Index: src/invocation/apple-call-x86_64.S ================================================================== --- src/invocation/apple-call-x86_64.S +++ src/invocation/apple-call-x86_64.S @@ -22,13 +22,31 @@ _of_invocation_call: pushq %rbp movq %rsp, %rbp subq $16, %rsp + andq $-16, %rsp movq %rdi, -8(%rbp) - movb 177(%rdi), %al + leaq 208(%rdi), %rdx + movq 200(%rdi), %rcx + + testq $1, %rcx + jnz .fix_align + +.fill_stack: + testq %rcx, %rcx + jz .stack_filled + + decq %rcx + movq (%rdx,%rcx,8), %r11 + pushq %r11 + + jmp .fill_stack + +.stack_filled: + movb 192(%rdi), %al movdqa 176(%rdi), %xmm7 movdqa 160(%rdi), %xmm6 movdqa 144(%rdi), %xmm5 movdqa 128(%rdi), %xmm4 @@ -54,5 +72,10 @@ movq %rbp, %rsp popq %rbp ret + +.fix_align: + xorq %r11, %r11 + pushq %r11 + jmp .fill_stack Index: src/invocation/invoke-x86_64.m ================================================================== --- src/invocation/invoke-x86_64.m +++ src/invocation/invoke-x86_64.m @@ -15,40 +15,45 @@ */ #include "config.h" #include +#include #include #import "OFInvocation.h" #import "OFMethodSignature.h" #import "OFInvalidFormatException.h" +#import "OFOutOfMemoryException.h" #define NUM_GPR_IN 6 #define NUM_GPR_OUT 2 #define NUM_SSE_IN 8 #define NUM_SSE_OUT 2 -struct registers { +struct call_context { uint64_t gpr[NUM_GPR_IN + NUM_GPR_OUT]; __m128 sse[NUM_SSE_IN]; - uint8_t num_sse; + uint8_t num_sse_used; + uint64_t stack_size; + uint64_t stack[]; }; -extern void of_invocation_call(struct registers *); +extern void of_invocation_call(struct call_context *); void of_invocation_invoke(OFInvocation *invocation) { OFMethodSignature *methodSignature = [invocation methodSignature]; size_t numberOfArguments = [methodSignature numberOfArguments]; + struct call_context *context; const char *typeEncoding; - struct registers registers; size_t currentGPR = 0, currentSSE = 0; - memset(®isters, '\0', sizeof(registers)); + if ((context = calloc(sizeof(*context), 1)) == NULL) + @throw [OFOutOfMemoryException exception]; for (size_t i = 0; i < numberOfArguments; i++) { union { uint64_t gpr; __m128 sse; @@ -118,44 +123,79 @@ CASE_GPR('^', uintptr_t) #ifndef __STDC_NO_COMPLEX__ /* TODO: 'j' */ #endif default: + free(context); @throw [OFInvalidFormatException exception]; #undef CASE_GPR } if (valueType == VALUE_GPR) { if (currentGPR < NUM_GPR_IN) - registers.gpr[currentGPR++] = value.gpr; - else - /* TODO */ - abort(); + context->gpr[currentGPR++] = value.gpr; + else { + struct call_context *newContext; + + context->stack_size++; + + newContext = realloc(context, + sizeof(*context) + context->stack_size * 8); + if (newContext == NULL) { + free(context); + @throw [OFOutOfMemoryException + exceptionWithRequestedSize: + sizeof(*context) + + context->stack_size * 8]; + } + + context = newContext; + context->stack[context->stack_size - 1] = + value.gpr; + } } else if (valueType == VALUE_SSE) { if (currentSSE < NUM_SSE_IN) { - registers.sse[currentSSE++] = value.sse; - registers.num_sse++; - } else - /* TODO */ - abort(); + context->sse[currentSSE++] = value.sse; + context->num_sse_used++; + } else { + struct call_context *newContext; + double tmp; + + context->stack_size++; + + newContext = realloc(context, + sizeof(*context) + context->stack_size * 8); + if (newContext == NULL) { + free(context); + @throw [OFOutOfMemoryException + exceptionWithRequestedSize: + sizeof(*context) + + context->stack_size * 8]; + } + + context = newContext; + _mm_store_sd(&tmp, value.sse); + memcpy(&context->stack[context->stack_size - 1], + &tmp, 8); + } } } - of_invocation_call(®isters); + of_invocation_call(context); typeEncoding = [methodSignature methodReturnType]; if (*typeEncoding == 'r') typeEncoding++; switch (*typeEncoding) { -#define CASE_GPR(encoding, type) \ - case encoding: \ - { \ - type tmp = (type)registers.gpr[NUM_GPR_IN]; \ - [invocation setReturnValue: &tmp]; \ - } \ +#define CASE_GPR(encoding, type) \ + case encoding: \ + { \ + type tmp = (type)context->gpr[NUM_GPR_IN]; \ + [invocation setReturnValue: &tmp]; \ + } \ break; CASE_GPR('c', char) CASE_GPR('C', unsigned char) CASE_GPR('i', int) CASE_GPR('I', unsigned int) @@ -170,18 +210,18 @@ /* TODO: 'T' */ #endif case 'f': { float tmp; - _mm_store_ss(&tmp, registers.sse[0]); + _mm_store_ss(&tmp, context->sse[0]); [invocation setReturnValue: &tmp]; } break; case 'd': { double tmp; - _mm_store_sd(&tmp, registers.sse[0]); + _mm_store_sd(&tmp, context->sse[0]); [invocation setReturnValue: &tmp]; } break; /* TODO: 'D' */ CASE_GPR('B', _Bool) @@ -195,9 +235,12 @@ CASE_GPR('^', uintptr_t) #ifndef __STDC_NO_COMPLEX__ /* TODO: 'j' */ #endif default: + free(context); @throw [OFInvalidFormatException exception]; #undef CASE_GPR } + + free(context); } Index: tests/OFInvocationTests.m ================================================================== --- tests/OFInvocationTests.m +++ tests/OFInvocationTests.m @@ -30,23 +30,65 @@ unsigned char c; unsigned int i; }; @implementation TestsAppDelegate (OFInvocationTests) -- (struct test_struct)invocationTestMethod: (unsigned char)c - : (unsigned int)i - : (struct test_struct *)ptr - : (struct test_struct)st +- (struct test_struct)invocationTestMethod1: (unsigned char)c + : (unsigned int)i + : (struct test_struct *)ptr + : (struct test_struct)st { return st; } + +- (int)invocationTestMethod2: (int)i1 + : (int)i2 + : (int)i3 + : (int)i4 + : (int)i5 + : (int)i6 + : (int)i7 + : (int)i8 + : (int)i9 + : (int)i10 + : (int)i11 + : (int)i12 + : (int)i13 + : (int)i14 + : (int)i15 + : (int)i16 +{ + return (i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + + i12 + i13 + i14 + i15 + i16) / 16; +} + +- (double)invocationTestMethod3: (double)d1 + : (double)d2 + : (double)d3 + : (double)d4 + : (double)d5 + : (double)d6 + : (double)d7 + : (double)d8 + : (double)d9 + : (double)d10 + : (double)d11 + : (double)d12 + : (double)d13 + : (double)d14 + : (double)d15 + : (double)d16 +{ + return (d1 + d2 + d3 + d4 + d5 + d6 + d7 + d8 + d9 + d10 + d11 + + d12 + d13 + d14 + d15 + d16) / 16; +} - (void)invocationTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFMethodSignature *sig = [self methodSignatureForSelector: - @selector(invocationTestMethod::::)]; + SEL selector = @selector(invocationTestMethod1::::); + OFMethodSignature *sig = [self methodSignatureForSelector: selector]; OFInvocation *invocation; struct test_struct st, st2, *stp = &st, *stp2; unsigned const char c = 0xAA; unsigned char c2; const unsigned int i = 0x55555555; @@ -91,9 +133,50 @@ stp == stp2) TEST(@"-[getArgument:atIndex:] #4", R([invocation getArgument: &st2 atIndex: 5]) && memcmp(&st, &st2, sizeof(st)) == 0) + +#ifdef OF_INVOCATION_CAN_INVOKE + /* -[invoke] #1 */ + selector = @selector(invocationTestMethod2::::::::::::::::); + invocation = [OFInvocation invocationWithMethodSignature: + [self methodSignatureForSelector: selector]]; + + [invocation setArgument: &self + atIndex: 0]; + [invocation setArgument: &selector + atIndex: 1]; + + for (int i = 1; i <= 16; i++) + [invocation setArgument: &i + atIndex: i + 1]; + + int intResult; + TEST(@"-[invoke] #1", R([invocation invoke]) && + R([invocation getReturnValue: &intResult]) && intResult == 8) + + /* -[invoke] #2 */ + selector = @selector(invocationTestMethod3::::::::::::::::); + invocation = [OFInvocation invocationWithMethodSignature: + [self methodSignatureForSelector: selector]]; + + [invocation setArgument: &self + atIndex: 0]; + [invocation setArgument: &selector + atIndex: 1]; + + for (int i = 1; i <= 16; i++) { + double d = i; + [invocation setArgument: &d + atIndex: i + 1]; + } + + double doubleResult; + TEST(@"-[invoke] #2", R([invocation invoke]) && + R([invocation getReturnValue: &doubleResult]) && + doubleResult == 8.5) +#endif [pool drain]; } @end