From af084a115a865b08261e70bed6723d2bf0f5da77 Mon Sep 17 00:00:00 2001 From: rfm Date: Mon, 30 Jun 2008 05:29:19 +0000 Subject: [PATCH] Imprivemewnts to get NS_MESSAGE and NS_INVOCATION working for FFI. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@26733 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 9 ++++++ Source/GSFFIInvocation.m | 25 +++++++++++---- Source/NSInvocation.m | 15 +++++++++ Source/cifframe.h | 2 ++ Source/cifframe.m | 69 ++++++++++++++++++++++++++++++++++++++++ Testing/nsinvocation.m | 13 +++++--- 6 files changed, 123 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 24a098a73..301661399 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-06-30 Richard Frith-Macdonald + + * Source/GSFFIInvocation.m: + * Source/NSInvocation.m: + * Source/cifframe.h: + * Source/cifframe.m: + Tweaks to get NS_MESSAGE and NS_INVOCATION working on my 64bit + system. + 2008-06-28 Richard Frith-Macdonald * configure.ac: Check for sys/mman.h and mprotect diff --git a/Source/GSFFIInvocation.m b/Source/GSFFIInvocation.m index a211575f9..87ece6f9a 100644 --- a/Source/GSFFIInvocation.m +++ b/Source/GSFFIInvocation.m @@ -253,23 +253,28 @@ static IMP gs_objc_msg_forward (SEL sel) frame: (cifframe_t *)frame signature: (NSMethodSignature*)aSignature { + int i; + _sig = RETAIN(aSignature); _numArgs = [aSignature numberOfArguments]; _info = [aSignature methodInfo]; _cframe = frame; ((cifframe_t *)_cframe)->cif = *cif; + /* Copy the arguments into our frame so that they are preserved + * in the NSInvocation if the stack is changed before the + * invocation is used. + */ #if MFRAME_STRUCT_BYREF -{ - int i; - /* Fix up some of the values. Do this on all processors that pass - structs by reference. Is there an automatic way to determine this? */ for (i = 0; i < ((cifframe_t *)_cframe)->nargs; i++) { const char *t = _info[i+1].type; if (*t == _C_STRUCT_B || *t == _C_UNION_B || *t == _C_ARY_B) { + /* Fix up some of the values. Do this on all processors that pass + structs by reference. + Is there an automatic way to determine this? */ memcpy(((cifframe_t *)_cframe)->values[i], *(void **)vals[i], ((cifframe_t *)_cframe)->arg_types[i]->size); } @@ -279,14 +284,22 @@ static IMP gs_objc_msg_forward (SEL sel) ((cifframe_t *)_cframe)->arg_types[i]->size); } } -} #else - ((cifframe_t *)_cframe)->values = vals; + for (i = 0; i < ((cifframe_t *)_cframe)->nargs; i++) + { + memcpy(((cifframe_t *)_cframe)->values[i], vals[i], + ((cifframe_t *)_cframe)->arg_types[i]->size); + } #endif _retval = retp; return self; } +- (void) _storeRetval +{ + _retval = _cframe + retval_offset_from_info (_info, _numArgs); +} + /* * This is implemented as a function so it can be used by other * routines (like the DO forwarding) diff --git a/Source/NSInvocation.m b/Source/NSInvocation.m index e0ae96ac1..b5909c04f 100644 --- a/Source/NSInvocation.m +++ b/Source/NSInvocation.m @@ -43,6 +43,13 @@ #include #endif +@interface NSInvocation (Private) +/* Tell the invocation to store return values locally rather than writing + * themto the stack location specified when the invocation was produced + */ +- (void) _storeRetval; +@end + @implementation GSCodeBuffer + (GSCodeBuffer*) memoryWithSize: (unsigned)_size @@ -1147,6 +1154,7 @@ _arg_addr(NSInvocation *inv, int index) - (void) forwardInvocation: (NSInvocation*)anInvocation { invocation = anInvocation; + [invocation _storeRetval]; } - (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector { @@ -1161,3 +1169,10 @@ _arg_addr(NSInvocation *inv, int index) return invocation; } @end + +@implementation NSInvocation (Private) +- (void) _storeRetval +{ + return; // subclass should implemente where necessary +} +@end diff --git a/Source/cifframe.h b/Source/cifframe.h index 9a41412f9..aa31320d6 100644 --- a/Source/cifframe.h +++ b/Source/cifframe.h @@ -52,6 +52,8 @@ typedef struct _cifframe_t { extern cifframe_t *cifframe_from_info (NSArgumentInfo *info, int numargs, void **retval); +extern unsigned retval_offset_from_info (NSArgumentInfo *info, int numargs); + extern void cifframe_set_arg(cifframe_t *cframe, int index, void *buffer, int size); extern void cifframe_get_arg(cifframe_t *cframe, int index, void *buffer, diff --git a/Source/cifframe.m b/Source/cifframe.m index 03c0fa007..78e3a7596 100644 --- a/Source/cifframe.m +++ b/Source/cifframe.m @@ -246,6 +246,75 @@ cifframe_from_info (NSArgumentInfo *info, int numargs, void **retval) return cframe; } +/* NB. this must match the code in cifframe_from_info() so that it + * returns the offset for the returne value in the cframe. + */ +unsigned +retval_offset_from_info (NSArgumentInfo *info, int numargs) +{ + unsigned size = sizeof(cifframe_t); + unsigned align = __alignof(double); + unsigned type_offset = 0; + unsigned offset = 0; + int i; + ffi_type *arg_types[numargs]; + ffi_type *rtype; + + /* FIXME: in cifframe_type, return values/arguments that are structures + have custom ffi_types with are allocated separately. We should allocate + them in our cifframe so we don't leak memory. Or maybe we could + cache structure types? */ + rtype = cifframe_type(info[0].type, NULL); + if (rtype == 0 || (rtype->size == 0 && rtype->elements == NULL)) + { + return 0; + } + + for (i = 0; i < numargs; i++) + { + arg_types[i] = cifframe_type(info[i+1].type, NULL); + } + + if (numargs > 0) + { + if (size % align != 0) + { + size += align - (size % align); + } + type_offset = size; + /* Make room to copy the arg_types */ + size += sizeof(ffi_type *) * numargs; + if (size % align != 0) + { + size += align - (size % align); + } + offset = size; + size += numargs * sizeof(void*); + if (size % align != 0) + { + size += (align - (size % align)); + } + for (i = 0; i < numargs; i++) + { + if (arg_types[i]->elements) + size += cifframe_guess_struct_size(arg_types[i]); + else + size += arg_types[i]->size; + + if (size % align != 0) + { + size += (align - size % align); + } + } + } + + if (size % align != 0) + { + size += (align - size % align); + } + return size; +} + void cifframe_set_arg(cifframe_t *cframe, int index, void *buffer, int size) { diff --git a/Testing/nsinvocation.m b/Testing/nsinvocation.m index c0ec6349c..9061272b5 100644 --- a/Testing/nsinvocation.m +++ b/Testing/nsinvocation.m @@ -14,6 +14,8 @@ #include #include +static int loop_int_result; + typedef struct { char c; int i; @@ -78,6 +80,7 @@ typedef struct { } - (int) loopInt: (int)v { + loop_int_result = v+1; return v+1; } - (large) loopLarge: (large)v @@ -255,22 +258,24 @@ printf("Calling proxy\n"); printf("Testing NS_MESSAGE ... "); inv = NS_MESSAGE(t, loopInt: 5); + loop_int_result = 0; [inv invoke]; [inv getReturnValue: &i]; - if (i == 6) + if (i == 6 && loop_int_result == 6) printf("OK\n"); else - printf("ERROR ... expecting 6 and got %d\n", i); + printf("ERROR ... expecting 6,6 and got %d,%d\n", i, loop_int_result); printf("Testing NS_INVOCATION ... "); inv = NS_INVOCATION([Target class], loopInt: 7); [inv setTarget: t]; + loop_int_result = 0; [inv invoke]; [inv getReturnValue: &i]; - if (i == 8) + if (i == 8 && loop_int_result == 8) printf("OK\n"); else - printf("ERROR ... expecting 8 and got %d\n", i); + printf("ERROR ... expecting 8,8 and got %d,%d\n", i, loop_int_result); #define SETUP(X) \ sig = [t methodSignatureForSelector: @selector(X)]; \