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
This commit is contained in:
rfm 2008-06-30 05:29:19 +00:00
parent a12a537b6f
commit af084a115a
6 changed files with 123 additions and 10 deletions

View file

@ -1,3 +1,12 @@
2008-06-30 Richard Frith-Macdonald <rfm@gnu.org>
* 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 <rfm@gnu.org> 2008-06-28 Richard Frith-Macdonald <rfm@gnu.org>
* configure.ac: Check for sys/mman.h and mprotect * configure.ac: Check for sys/mman.h and mprotect

View file

@ -253,23 +253,28 @@ static IMP gs_objc_msg_forward (SEL sel)
frame: (cifframe_t *)frame frame: (cifframe_t *)frame
signature: (NSMethodSignature*)aSignature signature: (NSMethodSignature*)aSignature
{ {
int i;
_sig = RETAIN(aSignature); _sig = RETAIN(aSignature);
_numArgs = [aSignature numberOfArguments]; _numArgs = [aSignature numberOfArguments];
_info = [aSignature methodInfo]; _info = [aSignature methodInfo];
_cframe = frame; _cframe = frame;
((cifframe_t *)_cframe)->cif = *cif; ((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 #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++) for (i = 0; i < ((cifframe_t *)_cframe)->nargs; i++)
{ {
const char *t = _info[i+1].type; const char *t = _info[i+1].type;
if (*t == _C_STRUCT_B || *t == _C_UNION_B || *t == _C_ARY_B) 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], memcpy(((cifframe_t *)_cframe)->values[i], *(void **)vals[i],
((cifframe_t *)_cframe)->arg_types[i]->size); ((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); ((cifframe_t *)_cframe)->arg_types[i]->size);
} }
} }
}
#else #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 #endif
_retval = retp; _retval = retp;
return self; 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 * This is implemented as a function so it can be used by other
* routines (like the DO forwarding) * routines (like the DO forwarding)

View file

@ -43,6 +43,13 @@
#include <sys/mman.h> #include <sys/mman.h>
#endif #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 @implementation GSCodeBuffer
+ (GSCodeBuffer*) memoryWithSize: (unsigned)_size + (GSCodeBuffer*) memoryWithSize: (unsigned)_size
@ -1147,6 +1154,7 @@ _arg_addr(NSInvocation *inv, int index)
- (void) forwardInvocation: (NSInvocation*)anInvocation - (void) forwardInvocation: (NSInvocation*)anInvocation
{ {
invocation = anInvocation; invocation = anInvocation;
[invocation _storeRetval];
} }
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector - (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector
{ {
@ -1161,3 +1169,10 @@ _arg_addr(NSInvocation *inv, int index)
return invocation; return invocation;
} }
@end @end
@implementation NSInvocation (Private)
- (void) _storeRetval
{
return; // subclass should implemente where necessary
}
@end

View file

@ -52,6 +52,8 @@ typedef struct _cifframe_t {
extern cifframe_t *cifframe_from_info (NSArgumentInfo *info, int numargs, extern cifframe_t *cifframe_from_info (NSArgumentInfo *info, int numargs,
void **retval); void **retval);
extern unsigned retval_offset_from_info (NSArgumentInfo *info, int numargs);
extern void cifframe_set_arg(cifframe_t *cframe, int index, void *buffer, extern void cifframe_set_arg(cifframe_t *cframe, int index, void *buffer,
int size); int size);
extern void cifframe_get_arg(cifframe_t *cframe, int index, void *buffer, extern void cifframe_get_arg(cifframe_t *cframe, int index, void *buffer,

View file

@ -246,6 +246,75 @@ cifframe_from_info (NSArgumentInfo *info, int numargs, void **retval)
return cframe; 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 void
cifframe_set_arg(cifframe_t *cframe, int index, void *buffer, int size) cifframe_set_arg(cifframe_t *cframe, int index, void *buffer, int size)
{ {

View file

@ -14,6 +14,8 @@
#include <Foundation/NSAutoreleasePool.h> #include <Foundation/NSAutoreleasePool.h>
#include <Foundation/NSArchiver.h> #include <Foundation/NSArchiver.h>
static int loop_int_result;
typedef struct { typedef struct {
char c; char c;
int i; int i;
@ -78,6 +80,7 @@ typedef struct {
} }
- (int) loopInt: (int)v - (int) loopInt: (int)v
{ {
loop_int_result = v+1;
return v+1; return v+1;
} }
- (large) loopLarge: (large)v - (large) loopLarge: (large)v
@ -255,22 +258,24 @@ printf("Calling proxy\n");
printf("Testing NS_MESSAGE ... "); printf("Testing NS_MESSAGE ... ");
inv = NS_MESSAGE(t, loopInt: 5); inv = NS_MESSAGE(t, loopInt: 5);
loop_int_result = 0;
[inv invoke]; [inv invoke];
[inv getReturnValue: &i]; [inv getReturnValue: &i];
if (i == 6) if (i == 6 && loop_int_result == 6)
printf("OK\n"); printf("OK\n");
else 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 ... "); printf("Testing NS_INVOCATION ... ");
inv = NS_INVOCATION([Target class], loopInt: 7); inv = NS_INVOCATION([Target class], loopInt: 7);
[inv setTarget: t]; [inv setTarget: t];
loop_int_result = 0;
[inv invoke]; [inv invoke];
[inv getReturnValue: &i]; [inv getReturnValue: &i];
if (i == 8) if (i == 8 && loop_int_result == 8)
printf("OK\n"); printf("OK\n");
else 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) \ #define SETUP(X) \
sig = [t methodSignatureForSelector: @selector(X)]; \ sig = [t methodSignatureForSelector: @selector(X)]; \