mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 00:41:02 +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
7f1b63a68f
commit
1cc66c3501
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>
|
||||
|
||||
* 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
|
||||
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)
|
||||
|
|
|
@ -43,6 +43,13 @@
|
|||
#include <sys/mman.h>
|
||||
#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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <Foundation/NSAutoreleasePool.h>
|
||||
#include <Foundation/NSArchiver.h>
|
||||
|
||||
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)]; \
|
||||
|
|
Loading…
Reference in a new issue