@@ -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); }