@@ -23,10 +23,12 @@ #import "OFInvocation.h" #import "OFMethodSignature.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" + +#import "macros.h" #define NUM_GPR_IN 6 #define NUM_GPR_OUT 2 #define NUM_SSE_IN 8 #define NUM_X87_OUT 2 @@ -50,11 +52,11 @@ }; extern void of_invocation_call(struct call_context *); static void -pushGPR(struct call_context **context, size_t *currentGPR, uint64_t value) +pushGPR(struct call_context **context, uint_fast8_t *currentGPR, uint64_t value) { struct call_context *newContext; if (*currentGPR < NUM_GPR_IN) { (*context)->gpr[(*currentGPR)++] = value; @@ -72,11 +74,12 @@ newContext->stack_size++; *context = newContext; } static void -pushDouble(struct call_context **context, size_t *currentSSE, double value) +pushDouble(struct call_context **context, uint_fast8_t *currentSSE, + double value) { struct call_context *newContext; if (*currentSSE < NUM_SSE_IN) { (*context)->sse[(*currentSSE)++] = (__m128)_mm_set_sd(value); @@ -111,21 +114,25 @@ memcpy(&newContext->stack[newContext->stack_size], &value, 16); newContext->stack_size += 2; *context = newContext; } -#ifndef __clang__ +#if defined(__SIZEOF_INT128__) && !defined(__clang__) static void -alignStack(struct call_context **context, size_t alignment) +pushInt128(struct call_context **context, uint_fast8_t *currentGPR, + uint64_t low, uint64_t high) { - size_t stackSize = (*context)->stack_size; struct call_context *newContext; + size_t stackSize; - if (stackSize % alignment == 0) + if (*currentGPR + 1 < NUM_GPR_IN) { + (*context)->gpr[(*currentGPR)++] = low; + (*context)->gpr[(*currentGPR)++] = high; return; + } - stackSize += alignment - stackSize % alignment; + stackSize = OF_ROUND_UP_POW2(2, (*context)->stack_size) + 2; if ((newContext = realloc(*context, sizeof(**context) + stackSize * 8)) == NULL) { free(*context); @throw [OFOutOfMemoryException exceptionWithRequestedSize: @@ -132,10 +139,12 @@ sizeof(**context) + stackSize * 8]; } memset(&newContext->stack[newContext->stack_size], '\0', (stackSize - newContext->stack_size) * 8); + newContext->stack[stackSize - 2] = low; + newContext->stack[stackSize - 1] = high; newContext->stack_size = stackSize; *context = newContext; } #endif @@ -144,11 +153,11 @@ { OFMethodSignature *methodSignature = [invocation methodSignature]; size_t numberOfArguments = [methodSignature numberOfArguments]; struct call_context *context; const char *typeEncoding; - size_t currentGPR = 0, currentSSE = 0; + uint_fast8_t currentGPR = 0, currentSSE = 0; if ((context = calloc(sizeof(*context), 1)) == NULL) @throw [OFOutOfMemoryException exception]; for (size_t i = 0; i < numberOfArguments; i++) { @@ -178,22 +187,22 @@ CASE_GPR('q', long long) CASE_GPR('Q', unsigned long long) #ifdef __SIZEOF_INT128__ case 't': case 'T':; - uint64_t int128Tmp[2]; - [invocation getArgument: int128Tmp + struct { + uint64_t low, high; + } int128Tmp; + [invocation getArgument: &int128Tmp atIndex: i]; # ifndef __clang__ - /* - * Clang violates the x86_64 ABI and does not properly - * align __int128 on the stack. - */ - alignStack(&context, 2); + pushInt128(&context, ¤tGPR, + int128Tmp.low, int128Tmp.high); +# else + pushGPR(&context, ¤tGPR, int128Tmp.low); + pushGPR(&context, ¤tGPR, int128Tmp.high); # endif - pushGPR(&context, ¤tGPR, int128Tmp[0]); - pushGPR(&context, ¤tGPR, int128Tmp[1]); break; #endif case 'f':; float floatTmp; [invocation getArgument: &floatTmp