mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-25 09:41:15 +00:00
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:
parent
a12a537b6f
commit
af084a115a
6 changed files with 123 additions and 10 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)]; \
|
||||||
|
|
Loading…
Reference in a new issue