rework memory management for ffi

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@30611 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2010-06-07 20:38:19 +00:00
parent 23fb22bf40
commit 4e0ef853d3
6 changed files with 58 additions and 15 deletions

View file

@ -1,3 +1,16 @@
2010-06-07 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSInvocation.h:
* Source/GSFFIInvocation.m:
* Source/NSInvocation.m:
* Source/cifframe.h:
* Source/cifframe.m:
Rework memory management for frame used in FFI invocation so that
the memory has a retain count and multiple invocations can use the
same frame since it looks like the way FFI works, if you cache the
method implementation of a proxy, the same frame memory is re-used
in multiple invocations.
2010-06-07 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSFFIInvocation.m: Fix breakage caused by David's changes.

View file

@ -141,6 +141,7 @@ gs_find_by_receiver_best_typed_sel (id receiver, SEL sel)
static IMP gs_objc_msg_forward2 (id receiver, SEL sel)
{
void *frame;
cifframe_t *cframe;
ffi_closure *cclosure;
NSMethodSignature *sig;
@ -183,7 +184,6 @@ static IMP gs_objc_msg_forward2 (id receiver, SEL sel)
"receiver, or you must be using an old/faulty version of the "
"Objective-C runtime library.\n", sel_get_name(sel));
#endif
/*
* Default signature is for a method returning an object.
*/
@ -198,10 +198,15 @@ static IMP gs_objc_msg_forward2 (id receiver, SEL sel)
NSCAssert1(sig, @"No signature for selector %@", NSStringFromSelector(sel));
/* Construct the frame and closure. */
/* Note: We malloc cframe here, but it's passed to GSFFIInvocationCallback
/* Note: We obtain cframe here, but it's passed to GSFFIInvocationCallback
where it becomes owned by the callback invocation, so we don't have to
worry about freeing it */
cframe = cifframe_from_signature(sig);
worry about ownership */
frame = cifframe_from_signature(sig);
#if GS_WITH_GC
cframe = frame;
#else
cframe = [(NSMutableData*)frame mutableBytes];
#endif
/* Autorelease the closure through GSAutoreleasedBuffer */
memory = [GSCodeBuffer memoryWithSize: sizeof(ffi_closure)];
@ -211,7 +216,7 @@ static IMP gs_objc_msg_forward2 (id receiver, SEL sel)
[NSException raise: NSMallocException format: @"Allocating closure"];
}
if (ffi_prep_closure(cclosure, &(cframe->cif),
GSFFIInvocationCallback, cframe) != FFI_OK)
GSFFIInvocationCallback, frame) != FFI_OK)
{
[NSException raise: NSGenericException format: @"Preping closure"];
}
@ -328,7 +333,14 @@ static id gs_objc_proxy_lookup(id receiver, SEL op)
_sig = RETAIN(aSignature);
_numArgs = [aSignature numberOfArguments];
_info = [aSignature methodInfo];
#if GS_WITH_GC
_frame = nil;
_cframe = cifframe_from_signature(_sig);
#else
_frame = (NSMutableData*)cifframe_from_signature(_sig);
[_frame retain];
_cframe = [_frame mutableBytes];
#endif
/* Make sure we have somewhere to store the return value if needed.
*/
@ -354,7 +366,7 @@ static id gs_objc_proxy_lookup(id receiver, SEL op)
but we own it now so we can free it */
- (id) initWithCallback: (ffi_cif *)cif
values: (void **)vals
frame: (cifframe_t *)frame
frame: (void *)frame
signature: (NSMethodSignature*)aSignature
{
cifframe_t *f;
@ -363,7 +375,14 @@ static id gs_objc_proxy_lookup(id receiver, SEL op)
_sig = RETAIN(aSignature);
_numArgs = [aSignature numberOfArguments];
_info = [aSignature methodInfo];
#if GS_WITH_GC
_frame = nil;
_cframe = frame;
#else
_frame = (NSMutableData*)frame;
[_frame retain];
_cframe = [_frame mutableBytes];
#endif
f = (cifframe_t *)_cframe;
f->cif = *cif;
@ -548,7 +567,8 @@ GSFFIInvocationCallback(ffi_cif *cif, void *retp, void **args, void *user)
obj = *(id *)args[0];
selector = *(SEL *)args[1];
if (!class_respondsToSelector(obj->class_pointer, @selector(forwardInvocation:)))
if (!class_respondsToSelector(obj->class_pointer,
@selector(forwardInvocation:)))
{
[NSException raise: NSInvalidArgumentException
format: @"GSFFIInvocation: Class '%s'(%s) does not respond"

View file

@ -27,6 +27,8 @@
#include <Foundation/NSInvocation.h>
@class NSMutableData;
typedef struct {
int offset;
unsigned size;
@ -39,7 +41,9 @@ typedef struct {
@interface GSFFIInvocation : NSInvocation
{
@public
uint8_t _retbuf[32]; // Store return values of up to 32 bytes here.
NSMutableData *_frame;
}
@end

View file

@ -334,7 +334,11 @@ _arg_addr(NSInvocation *inv, int index)
#if defined(USE_LIBFFI)
if (_cframe)
{
NSZoneFree(NSDefaultMallocZone(), _cframe);
/* If we get here then we are not using GC, so the _frame instance
* variable points to a mutable data object containing _cframe and
* we can release it.
*/
[((GSFFIInvocation*)self)->_frame release];
}
#elif defined(USE_FFCALL)
if (_cframe)

View file

@ -50,7 +50,7 @@ typedef struct _cifframe_t {
void **values;
} cifframe_t;
extern cifframe_t *cifframe_from_signature (NSMethodSignature *info);
extern void *cifframe_from_signature (NSMethodSignature *info);
extern void cifframe_set_arg(cifframe_t *cframe, int index, void *buffer,
int size);

View file

@ -122,13 +122,14 @@ cifframe_guess_struct_size(ffi_type *stype)
}
cifframe_t *
void *
cifframe_from_signature (NSMethodSignature *info)
{
unsigned size = sizeof(cifframe_t);
unsigned align = __alignof(double);
unsigned type_offset = 0;
unsigned offset = 0;
void *result;
void *buf;
int i;
int numargs = [info numberOfArguments];
@ -180,9 +181,11 @@ cifframe_from_signature (NSMethodSignature *info)
}
#if GS_WITH_GC
cframe = buf = NSAllocateCollectable(size, NSScannedOption);
cframe = buf = result = NSAllocateCollectable(size, NSScannedOption);
#else
cframe = buf = NSZoneCalloc(NSDefaultMallocZone(), size, 1);
result = (void*)[NSMutableData dataWithCapacity: size];
[(NSMutableData*)result setLength: size];
cframe = buf = [(NSMutableData*)result mutableBytes];
#endif
if (cframe)
@ -196,8 +199,7 @@ cifframe_from_signature (NSMethodSignature *info)
if (ffi_prep_cif (&cframe->cif, FFI_DEFAULT_ABI, cframe->nargs,
rtype, cframe->arg_types) != FFI_OK)
{
objc_free(cframe);
cframe = NULL;
cframe = result = NULL;
}
if (cframe)
@ -222,7 +224,7 @@ cifframe_from_signature (NSMethodSignature *info)
}
}
return cframe;
return result;
}
void