DO fixes ... thread safety and get exceptions working properly again.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@10938 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2001-09-19 21:31:18 +00:00
parent bb0482127b
commit f07102c855
9 changed files with 630 additions and 788 deletions

View file

@ -1,3 +1,23 @@
2001-09-19 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSConnection.m: rewrite ethod call code.
* Source/callframe.h: ditto
* Source/callframe.m: ditto
* Source/cifframe.h: ditto
* Source/cifframe.m: ditto
* Source/mframe.m: ditto
* Source/mframe/mframe.head: ditto
* Headers/gnustep/base/DistributedObjects.h: Adde new DOContext struct.
Rewrite code for moving data to/from method call stackframes and
encoding/decoding it. The functions to encode/decode each data item
are no longer nested, and pass a context structure around which
provides for more information to be passed between the various layers
of the process so that the whole thing is thread-safe and we don't
get cases where code in one place tries to work with an object that
was released in another place.
Tested pretty extensively for libffcall stuff, with the simple test
programs for maframe, and not at all for libffi.
2001-09-19 Adam Fedor <fedor@gnu.org>
* configure.in: But CPPFLAGS in quotes

View file

@ -62,7 +62,7 @@ enum {
/*
* Catagory containing the methods by which the public interface to
* Category containing the methods by which the public interface to
* NSConnection must be extended in order to allow it's use by
* by NSDistantObject et al for implementation of Distributed objects.
*/
@ -74,4 +74,18 @@ enum {
- (void) retainTarget: (unsigned)target;
@end
/*
* A structure for passing context information using in encoding/decoding
* arguments for DO
*/
typedef struct {
const char *type; // The type of the data
int flags; // Type qualifier flags
void *datum; // Where to get/store data
NSConnection *connection; // The connection in use
NSPortCoder *decoder; // The coder to use
NSPortCoder *encoder; // The coder to use
unsigned seq; // Sequence number
} DOContext;
#endif /* __DistributedObjects_h */

View file

@ -27,12 +27,6 @@
#include <config.h>
#include <base/preface.h>
#include <mframe.h>
#if defined(USE_LIBFFI)
#include "cifframe.h"
#elif defined(USE_FFCALL)
#include "callframe.h"
#endif
/*
* Setup for inline operation of pointer map tables.
@ -50,6 +44,13 @@
#include <Foundation/NSConnection.h>
#undef _IN_CONNECTION_M
#include <mframe.h>
#if defined(USE_LIBFFI)
#include "cifframe.h"
#elif defined(USE_FFCALL)
#include "callframe.h"
#endif
#include <Foundation/NSPortCoder.h>
#include <Foundation/DistributedObjects.h>
@ -226,6 +227,7 @@ static unsigned local_object_counter = 0;
- (NSDistantObject*) localForObject: (id)object;
- (void) removeLocalObject: (id)anObj;
- (void) _doneInReply: (NSPortCoder*)c;
- (void) _doneInRmc: (NSPortCoder*)c;
- (void) _failInRmc: (NSPortCoder*)c;
- (void) _failOutRmc: (NSPortCoder*)c;
@ -1483,7 +1485,10 @@ static int seq_num;
[exc raise];
}
}
[ip decodeValueOfObjCType: type at: datum];
if (*type == _C_PTR)
else
[ip decodeValueOfObjCType: type+1 at: datum];
[ip decodeValueOfObjCType: type at: datum];
/* -decodeValueOfObjCType:at: malloc's new memory
for pointers. We need to make sure it gets freed eventually
so we don't have a memory leak. Request here that it be
@ -1498,6 +1503,73 @@ static int seq_num;
}
#endif
static void retDecoder(DOContext *ctxt)
{
NSPortCoder *coder = ctxt->decoder;
const char *type = ctxt->type;
if (type == 0)
{
if (coder != nil)
{
ctxt->decoder = nil;
[ctxt->connection _doneInReply: coder];
}
return;
}
/* If we didn't get the reply packet yet, get it now. */
if (coder == nil)
{
BOOL is_exception;
if ([ctxt->connection isValid] == NO)
{
[NSException raise: NSGenericException
format: @"connection waiting for request was shut down"];
}
ctxt->decoder = [ctxt->connection _getReplyRmc: ctxt->seq];
coder = ctxt->decoder;
/*
* Find out if the server is returning an exception instead
* of the return values.
*/
[coder decodeValueOfObjCType: @encode(BOOL) at: &is_exception];
if (is_exception == YES)
{
/* Decode the exception object, and raise it. */
id exc;
[coder decodeValueOfObjCType: @encode(id) at: &exc];
ctxt->decoder = nil;
[ctxt->connection _doneInRmc: coder];
[exc raise];
}
}
[coder decodeValueOfObjCType: type at: ctxt->datum];
if (*type == _C_ID)
{
AUTORELEASE(*(id*)ctxt->datum);
}
}
static void retEncoder (DOContext *ctxt)
{
switch (*ctxt->type)
{
case _C_ID:
if (ctxt->flags & _F_BYCOPY)
[ctxt->encoder encodeBycopyObject: *(id*)ctxt->datum];
#ifdef _F_BYREF
else if (ctxt->flags & _F_BYREF)
[ctxt->encoder encodeByrefObject: *(id*)ctxt->datum];
#endif
else
[ctxt->encoder encodeObject: *(id*)ctxt->datum];
break;
default:
[ctxt->encoder encodeValueOfObjCType: ctxt->type at: ctxt->datum];
}
}
/*
* NSDistantObject's -forward: : method calls this to send the message
* over the wire.
@ -1506,38 +1578,15 @@ static int seq_num;
selector: (SEL)sel
argFrame: (arglist_t)argframe
{
#ifndef BROKEN_NESTED_FUNCTIONS
NSPortCoder *op;
int seq_num;
#endif
BOOL outParams;
BOOL needsResponse;
const char *type;
retval_t retframe;
DOContext ctxt;
#ifndef BROKEN_NESTED_FUNCTIONS
/* The callback for encoding the args of the method call. */
void encoder (int argnum, void *datum, const char *type, int flags)
{
#define ENCODED_ARGNAME @"argument value"
switch (*type)
{
case _C_ID:
if (flags & _F_BYCOPY)
[op encodeBycopyObject: *(id*)datum];
#ifdef _F_BYREF
else if (flags & _F_BYREF)
[op encodeByrefObject: *(id*)datum];
#endif
else
[op encodeObject: *(id*)datum];
break;
default:
[op encodeValueOfObjCType: type at: datum];
}
}
#endif
memset(&ctxt, 0, sizeof(ctxt));
ctxt.connection = self;
/* Encode the method on an RMC, and send it. */
NSParameterAssert (_isValid);
@ -1562,23 +1611,23 @@ static int seq_num;
NSParameterAssert(type);
NSParameterAssert(*type);
op = [self _makeOutRmc: 0 generate: &seq_num reply: YES];
ctxt.encoder = [self _makeOutRmc: 0 generate: &ctxt.seq reply: YES];
if (debug_connection > 4)
NSLog(@"building packet seq %d", seq_num);
NSLog(@"building packet seq %d", ctxt.seq);
/* Send the types that we're using, so that the performer knows
exactly what qualifiers we're using.
If all selectors included qualifiers, and if I could make
sel_types_match() work the way I wanted, we wouldn't need to do
this. */
[op encodeValueOfObjCType: @encode(char*) at: &type];
[ctxt.encoder encodeValueOfObjCType: @encode(char*) at: &type];
/* xxx This doesn't work with proxies and the NeXT runtime because
type may be a method_type from a remote machine with a
different architecture, and its argframe layout specifiers
won't be right for this machine! */
outParams = mframe_dissect_call (argframe, type, encoder);
outParams = mframe_dissect_call (argframe, type, retEncoder, &ctxt);
if (outParams == YES)
{
@ -1605,7 +1654,8 @@ static int seq_num;
}
}
[self _sendOutRmc: op type: METHOD_REQUEST];
[self _sendOutRmc: ctxt.encoder type: METHOD_REQUEST];
ctxt.encoder = nil;
NSDebugMLLog(@"NSConnection", @"Sent message to 0x%x", (gsaddr)self);
if (needsResponse == NO)
@ -1618,7 +1668,7 @@ static int seq_num;
* a response, we must check for it and scrap it if necessary.
*/
M_LOCK(_refGate);
node = GSIMapNodeForKey(_replyMap, (GSIMapKey)seq_num);
node = GSIMapNodeForKey(_replyMap, (GSIMapKey)ctxt.seq);
if (node != 0 && node->value.obj != dummyObject)
{
BOOL is_exception = NO;
@ -1631,78 +1681,20 @@ static int seq_num;
NSLog(@"Got response with %@", NSStringFromSelector(sel));
[self _doneInRmc: node->value.obj];
}
GSIMapRemoveKey(_replyMap, (GSIMapKey)seq_num);
GSIMapRemoveKey(_replyMap, (GSIMapKey)ctxt.seq);
M_UNLOCK(_refGate);
retframe = alloca(sizeof(void*)); /* Dummy value for void return. */
}
else
{
#ifndef BROKEN_NESTED_FUNCTIONS
NSPortCoder *ip = nil;
BOOL is_exception = NO;
void decoder(int argnum, void *datum, const char *type, int flags)
{
if (type == 0)
{
if (ip != nil)
{
[self _doneInRmc: ip];
/* this must be here to avoid trashing alloca'ed retframe */
ip = (id)-1;
_repInCount++; /* received a reply */
}
return;
}
/* If we didn't get the reply packet yet, get it now. */
if (ip == nil)
{
if (_isValid == NO)
{
[NSException raise: NSGenericException
format: @"connection waiting for request was shut down"];
}
ip = [self _getReplyRmc: seq_num];
/*
* Find out if the server is returning an exception instead
* of the return values.
*/
[ip decodeValueOfObjCType: @encode(BOOL) at: &is_exception];
if (is_exception == YES)
{
/* Decode the exception object, and raise it. */
id exc;
[ip decodeValueOfObjCType: @encode(id) at: &exc];
[self _doneInRmc: ip];
ip = (id)-1;
/* xxx Is there anything else to clean up in
dissect_method_return()? */
[exc raise];
}
}
[ip decodeValueOfObjCType: type at: datum];
/* -decodeValueOfObjCType:at: malloc's new memory
for pointers. We need to make sure it gets freed eventually
so we don't have a memory leak. Request here that it be
autorelease'ed. Also autorelease created objects. */
if ((*type == _C_CHARPTR || *type == _C_PTR) && *(void**)datum != 0)
[NSData dataWithBytesNoCopy: *(void**)datum length: 1];
else if (*type == _C_ID)
AUTORELEASE(*(id*)datum);
}
#else
c_self = self;
second_decode = NO;
#endif /* not BROKEN_NESTED_FUNCTIONS */
retframe = mframe_build_return (argframe, type, outParams, decoder);
retframe = mframe_build_return (argframe, type, outParams,
retDecoder, &ctxt);
/* Make sure we processed all arguments, and dismissed the IP.
IP is always set to -1 after being dismissed; the only places
this is done is in this function DECODER(). IP will be nil
if mframe_build_return() never called DECODER(), i.e. when
we are just returning (void).*/
NSAssert(ip == (id)-1 || ip == nil, NSInternalInconsistencyException);
NSAssert(ctxt.decoder == nil, NSInternalInconsistencyException);
}
return retframe;
}
@ -1718,7 +1710,7 @@ static int seq_num;
BOOL outParams;
BOOL needsResponse;
const char *type;
int seq_num;
DOContext ctxt;
/* Encode the method on an RMC, and send it. */
@ -1737,12 +1729,15 @@ static int seq_num;
NSParameterAssert(type);
NSParameterAssert(*type);
op = [self _makeOutRmc: 0 generate: &seq_num reply: YES];
memset(&ctxt, 0, sizeof(ctxt));
ctxt.connection = self;
op = [self _makeOutRmc: 0 generate: &ctxt.seq reply: YES];
if (debug_connection > 4)
NSLog(@"building packet seq %d", seq_num);
NSLog(@"building packet seq %d", ctxt.seq);
outParams = [inv encodeWithDistantCoder: op passPointers: YES];
outParams = [inv encodeWithDistantCoder: op passPointers: NO];
if (outParams == YES)
{
@ -1782,7 +1777,7 @@ static int seq_num;
* a response, we must check for it and scrap it if necessary.
*/
M_LOCK(_refGate);
node = GSIMapNodeForKey(_replyMap, (GSIMapKey)seq_num);
node = GSIMapNodeForKey(_replyMap, (GSIMapKey)ctxt.seq);
if (node != 0 && node->value.obj != dummyObject)
{
BOOL is_exception = NO;
@ -1796,72 +1791,20 @@ static int seq_num;
NSLog(@"Got response with %@", NSStringFromSelector(sel));
[self _doneInRmc: node->value.obj];
}
GSIMapRemoveKey(_replyMap, (GSIMapKey)seq_num);
GSIMapRemoveKey(_replyMap, (GSIMapKey)ctxt.seq);
M_UNLOCK(_refGate);
}
else
{
#ifndef BROKEN_NESTED_FUNCTIONS
NSPortCoder *ip = nil;
BOOL is_exception = NO;
void decoder(int argnum, void *datum, const char *type, int flags)
{
if (type == 0)
{
if (ip != nil)
{
[self _doneInRmc: ip];
/* this must be here to avoid trashing alloca'ed retframe */
ip = (id)-1;
_repInCount++; /* received a reply */
}
return;
}
/* If we didn't get the reply packet yet, get it now. */
if (ip == nil)
{
if (_isValid == NO)
{
[NSException raise: NSGenericException
format: @"connection waiting for request was shut down"];
}
ip = [self _getReplyRmc: seq_num];
/*
* Find out if the server is returning an exception instead
* of the return values.
*/
[ip decodeValueOfObjCType: @encode(BOOL) at: &is_exception];
if (is_exception == YES)
{
/* Decode the exception object, and raise it. */
id exc;
[ip decodeValueOfObjCType: @encode(id) at: &exc];
[self _doneInRmc: ip];
ip = (id)-1;
/* xxx Is there anything else to clean up in
dissect_method_return()? */
[exc raise];
}
}
[ip decodeValueOfObjCType: type at: datum];
if (*type == _C_ID)
AUTORELEASE(*(id*)datum);
}
#else
c_self = self;
second_decode = YES;
#endif /* not BROKEN_NESTED_FUNCTIONS */
#ifdef USE_FFCALL
callframe_build_return (inv, type, outParams, decoder);
callframe_build_return (inv, type, outParams, retDecoder, &ctxt);
#endif
/* Make sure we processed all arguments, and dismissed the IP.
IP is always set to -1 after being dismissed; the only places
this is done is in this function DECODER(). IP will be nil
if mframe_build_return() never called DECODER(), i.e. when
we are just returning (void).*/
NSAssert(ip == (id)-1 || ip == nil, NSInternalInconsistencyException);
NSAssert(ctxt.decoder == nil, NSInternalInconsistencyException);
}
}
@ -2104,187 +2047,164 @@ static int seq_num;
debug_connection = val;
}
#ifdef BROKEN_NESTED_FUNCTIONS
#define decoder service_decoder
#define encoder service_encoder
static id op;
static int reply_sno;
static NSConnection *c_self;
static NSConnection_t *c_self_t;
static NSPortCoder *c_aRmc;
void service_decoder (int argnum, void *datum, const char *type)
static void callDecoder (DOContext *ctxt)
{
const char *type = ctxt->type;
void *datum = ctxt->datum;
NSPortCoder *coder = ctxt->decoder;
/*
* We need this "dismiss" to happen here and not later so that Coder
* "-awake..." methods will get sent before the method using the
* objects is invoked. We clear the 'decoder' field in the context to
* show that it is no longer valid.
*/
if (datum == 0 && type == 0)
{
/* We need this "dismiss" to happen here and not later so that Coder
"-awake..." methods will get sent before the __builtin_apply! */
if (argnum == -1 && datum == 0 && type == 0)
ctxt->decoder = nil;
[ctxt->connection _doneInRmc: coder];
return;
}
[coder decodeValueOfObjCType: type at: datum];
#ifdef USE_FFCALL
if (*type == _C_ID)
#else
/* -decodeValueOfObjCType: at: malloc's new memory
for char*'s. We need to make sure it gets freed eventually
so we don't have a memory leak. Request here that it be
autorelease'ed. Also autorelease created objects. */
if ((*type == _C_CHARPTR || *type == _C_PTR) && *(void**)datum != 0)
{
[NSData dataWithBytesNoCopy: *(void**)datum length: 1];
}
else if (*type == _C_ID)
#endif
{
AUTORELEASE(*(id*)datum);
}
}
static void callEncoder (DOContext *ctxt)
{
const char *type = ctxt->type;
void *datum = ctxt->datum;
int flags = ctxt->flags;
NSPortCoder *coder = ctxt->encoder;
if (coder == nil)
{
BOOL is_exception = NO;
/*
* It is possible that our connection died while the method was
* being called - in this case we mustn't try to send the result
* back to the remote application!
*/
if ([ctxt->connection isValid] == NO)
{
[c_self _doneInRmc: c_aRmc];
return;
}
[c_aRmc decodeValueOfObjCType: type at: datum];
#ifdef USE_FFCALL
if (*type == _C_ID)
#else
/* -decodeValueOfObjCType: at: malloc's new memory
for char*'s. We need to make sure it gets freed eventually
so we don't have a memory leak. Request here that it be
autorelease'ed. Also autorelease created objects. */
if ((*type == _C_CHARPTR || *type == _C_PTR) && *(void**)datum != 0)
[NSData dataWithBytesNoCopy: *(void**)datum length: 1];
else if (*type == _C_ID)
#endif
AUTORELEASE(*(id*)datum);
/*
* We create a new coder object and set it in the context for
* later use if/when we are called again. We encode a flag to
* say that this is not an exception.
*/
coder = [ctxt->connection _makeOutRmc: ctxt->seq
generate: 0
reply: NO];
ctxt->encoder = coder;
[coder encodeValueOfObjCType: @encode(BOOL) at: &is_exception];
}
void service_encoder (int argnum, void *datum, const char *type, int flags)
switch (*type)
{
c_self_t = (NSConnection_t *)c_self;
if (op == nil)
{
BOOL is_exception = NO;
/* It is possible that our connection died while the method was
being called - in this case we mustn't try to send the result
back to the remote application! */
if (c_self_t->_isValid == NO)
return;
op = [c_self _makeOutRmc: reply_sno generate: 0 reply: NO];
[op encodeValueOfObjCType: @encode(BOOL) at: &is_exception];
}
switch (*type)
{
case _C_ID:
if (flags & _F_BYCOPY)
[op encodeBycopyObject: *(id*)datum];
case _C_ID:
if (flags & _F_BYCOPY)
[coder encodeBycopyObject: *(id*)datum];
#ifdef _F_BYREF
else if (flags & _F_BYREF)
[op encodeByrefObject: *(id*)datum];
else if (flags & _F_BYREF)
[coder encodeByrefObject: *(id*)datum];
#endif
else
[op encodeObject: *(id*)datum];
break;
default:
[op encodeValueOfObjCType: type at: datum];
}
else
[coder encodeObject: *(id*)datum];
break;
default:
[coder encodeValueOfObjCType: type at: datum];
}
}
#endif
/* NSConnection calls this to service the incoming method request. */
- (void) _service_forwardForProxy: (NSPortCoder*)aRmc
{
char *forward_type = 0;
#ifndef BROKEN_NESTED_FUNCTIONS
id op = nil;
int reply_sno;
char *forward_type = 0;
DOContext ctxt;
void decoder (int argnum, void *datum, const char *type)
{
/* We need this "dismiss" to happen here and not later so that Coder
"-awake..." methods will get sent before the __builtin_apply! */
if (argnum == -1 && datum == 0 && type == 0)
{
[self _doneInRmc: aRmc];
return;
}
memset(&ctxt, 0, sizeof(ctxt));
ctxt.connection = self;
ctxt.decoder = aRmc;
[aRmc decodeValueOfObjCType: type at: datum];
#ifdef USE_FFCALL
if (*type == _C_ID)
#else
/* -decodeValueOfObjCType: at: malloc's new memory
for char*'s. We need to make sure it gets freed eventually
so we don't have a memory leak. Request here that it be
autorelease'ed. Also autorelease created objects. */
if ((*type == _C_CHARPTR || *type == _C_PTR) && *(void**)datum != 0)
[NSData dataWithBytesNoCopy: *(void**)datum length: 1];
else if (*type == _C_ID)
#endif
AUTORELEASE(*(id*)datum);
}
void encoder (int argnum, void *datum, const char *type, int flags)
{
if (op == nil)
{
BOOL is_exception = NO;
/* It is possible that our connection died while the method was
being called - in this case we mustn't try to send the result
back to the remote application! */
if (_isValid == NO)
return;
op = [self _makeOutRmc: reply_sno generate: 0 reply: NO];
[op encodeValueOfObjCType: @encode(BOOL) at: &is_exception];
}
switch (*type)
{
case _C_ID:
if (flags & _F_BYCOPY)
[op encodeBycopyObject: *(id*)datum];
#ifdef _F_BYREF
else if (flags & _F_BYREF)
[op encodeByrefObject: *(id*)datum];
#endif
else
[op encodeObject: *(id*)datum];
break;
default:
[op encodeValueOfObjCType: type at: datum];
}
}
#else
c_self = self;
c_aRmc = aRmc;
#endif /* not BROKEN_NESTED_FUNCTIONS */
/* Make sure don't let exceptions caused by servicing the client's
request cause us to crash. */
/*
* Make sure don't let exceptions caused by servicing the client's
* request cause us to crash.
*/
NS_DURING
{
NSParameterAssert (_isValid);
/* Save this for later */
[aRmc decodeValueOfObjCType: @encode(int) at: &reply_sno];
[aRmc decodeValueOfObjCType: @encode(int) at: &ctxt.seq];
/* Get the types that we're using, so that we know
exactly what qualifiers the forwarder used.
If all selectors included qualifiers and I could make
sel_types_match() work the way I wanted, we wouldn't need
to do this. */
/*
* Get the types that we're using, so that we know
* exactly what qualifiers the forwarder used.
* If all selectors included qualifiers and I could make
* sel_types_match() work the way I wanted, we wouldn't need
* to do this.
*/
[aRmc decodeValueOfObjCType: @encode(char*) at: &forward_type];
ctxt.type = forward_type;
if (debug_connection > 1)
NSLog(@"Handling message from 0x%x", (gsaddr)self);
_reqInCount++; /* Handling an incoming request. */
#if defined(USE_LIBFFI)
cifframe_do_call (forward_type, decoder, encoder);
#elif defined(USE_FFCALL)
callframe_do_call (forward_type, decoder, encoder);
#else
mframe_do_call (forward_type, decoder, encoder);
#endif
if (op != nil)
{
[self _sendOutRmc: op type: METHOD_REPLY];
NSLog(@"Handling message from 0x%x", (gsaddr)self);
}
_reqInCount++; /* Handling an incoming request. */
#if defined(USE_LIBFFI)
cifframe_do_call (&ctxt, callDecoder, callEncoder);
#elif defined(USE_FFCALL)
callframe_do_call (&ctxt, callDecoder, callEncoder);
#else
mframe_do_call (&ctxt, callDecoder, callEncoder);
#endif
if (ctxt.encoder != nil)
{
[self _sendOutRmc: ctxt.encoder type: METHOD_REPLY];
}
}
/* Make sure we pass all exceptions back to the requestor. */
NS_HANDLER
{
BOOL is_exception = YES;
[self _failInRmc: aRmc];
/* Send the exception back to the client. */
if (_isValid == YES)
{
BOOL is_exception = YES;
NS_DURING
{
if (op != nil)
NSPortCoder *op;
if (ctxt.decoder != nil)
{
[self _failOutRmc: op];
[self _failInRmc: ctxt.decoder];
}
op = [self _makeOutRmc: reply_sno generate: 0 reply: NO];
if (ctxt.encoder != nil)
{
[self _failOutRmc: ctxt.encoder];
}
op = [self _makeOutRmc: ctxt.seq generate: 0 reply: NO];
[op encodeValueOfObjCType: @encode(BOOL)
at: &is_exception];
[op encodeBycopyObject: localException];
@ -2603,6 +2523,12 @@ static NSPortCoder *c_aRmc;
return rmc;
}
- (void) _doneInReply: (NSPortCoder*)c
{
[self _doneInRmc: c];
_repInCount++;
}
- (void) _doneInRmc: (NSPortCoder*)c
{
M_LOCK(_refGate);

View file

@ -26,6 +26,7 @@
#define callframe_h_INCLUDE
#include <Foundation/NSMethodSignature.h>
#include <base/DistributedObjects.h>
@class NSInvocation;
@ -44,12 +45,13 @@ extern void callframe_get_arg(callframe_t *cframe, int index, void *buffer,
int size);
extern void *callframe_arg_addr(callframe_t *cframe, int index);
extern void callframe_do_call (const char *encoded_types,
void(*decoder)(int,void*,const char*),
void(*encoder)(int,void*,const char*,int));
extern void callframe_do_call (DOContext *ctxt,
void(*decoder)(DOContext*),
void(*encoder)(DOContext*));
extern void callframe_build_return (NSInvocation *inv,
const char *type,
BOOL out_parameters,
void(*decoder)(int,void*,const char*,int));
void(*decoder)(DOContext*),
DOContext* ctxt);
#endif

View file

@ -152,22 +152,21 @@ typedef struct _NSInvocation_t {
/* callframe_do_call()
This function decodes the arguments of method call, builds an
argframe of type arglist_t, and invokes the method using
__builtin_apply; then it encodes the return value and any
pass-by-reference arguments.
This function decodes the arguments of method call, builds a
callframe, and invokes the method using GSFFCallInvokeWithTargetAndImp
then it encodes the return value and any pass-by-reference arguments.
ENCODED_TYPES should be a string that describes the return value
An entry, ctxt->type should be a string that describes the return value
and arguments. It's argument types and argument type qualifiers
should match exactly those that were used when the arguments were
encoded with callframe_dissect_call()---callframe_do_call() uses
ENCODED_TYPES to determine which variable types it should decode.
encoded. callframe_do_call() uses this information to determine
which variable types it should decode.
ENCODED_TYPES is used to get the types and type qualifiers, but not
The type info is used to get the types and type qualifiers, but not
to get the register and stack locations---we get that information
from the selector type of the SEL that is decoded as the second
argument. In this way, the ENCODED_TYPES may come from a machine
of a different architecture. Having the original ENCODED_TYPES is
argument. In this way, the type info may come from a machine
of a different architecture. Having the original type info is
good, just in case the machine running callframe_do_call() has some
slightly different qualifiers. Using different qualifiers for
encoding and decoding could lead to massive confusion.
@ -176,17 +175,15 @@ typedef struct _NSInvocation_t {
DECODER should be a pointer to a function that obtains the method's
argument values. For example:
void my_decoder (int argnum, void *data, const char *type)
void my_decoder (DOContext *ctxt)
ARGNUM is the number of the argument, beginning at 0.
DATA is a pointer to the memory where the value should be placed.
TYPE is a pointer to the type string of this value.
CTXT contains the context information for the item to decode.
callframe_do_call() calls this function once for each of the methods
arguments. The DECODER function should place the ARGNUM'th
argument's value at the memory location DATA.
callframe_do_call() calls this function once with ARGNUM -1, DATA 0,
and TYPE 0 to denote completion of decoding.
argument's value at the memory location ctxt->datum.
callframe_do_call() calls this function once with ctxt->datum 0,
and ctxt->type 0 to denote completion of decoding.
If DECODER malloc's new memory in the course of doing its
@ -201,32 +198,22 @@ typedef struct _NSInvocation_t {
ENCODER should be a pointer to a function that records the method's
return value and pass-by-reference values. For example:
void my_encoder (int argnum, void *data, const char *type, int flags)
void my_encoder (DOContext *ctxt)
ARGNUM is the number of the argument; this will be -1 for the
return value, and the argument index for the pass-by-reference
values; the indices start at 0.
DATA is a pointer to the memory where the value can be found.
TYPE is a pointer to the type string of this value.
FLAGS is a copy of the type qualifier flags for this argument;
(see <objc/objc-api.h>).
CTXT contains the context information for the item to encode.
callframe_do_call() calls this function after the method has been
run---once for the return value, and once for each of the
pass-by-reference parameters. The ENCODER function should place
the value at memory location DATA wherever the user wants to
the value at memory location ctxt->datum wherever the user wants to
record the ARGNUM'th return value.
PASS_POINTERS is a flag saying whether pointers should be passed
as pointers (for local stuff) or should be assumed to point to a
single data item (for distributed objects).
*/
void
callframe_do_call_opts (const char *encoded_types,
void(*decoder)(int,void*,const char*),
void(*encoder)(int,void*,const char*,int),
BOOL pass_pointers)
callframe_do_call (DOContext *ctxt,
void(*decoder)(DOContext*),
void(*encoder)(DOContext*))
{
/* The method type string obtained from the target's OBJC_METHOD
structure for the selector we're sending. */
@ -241,8 +228,6 @@ callframe_do_call_opts (const char *encoded_types,
SEL selector;
/* The OBJECT's implementation of the SELECTOR. */
IMP method_implementation;
/* A pointer into the ARGFRAME; points at individual arguments. */
char *datum;
/* Type qualifier flags; see <objc/objc-api.h>. */
unsigned flags;
/* Which argument number are we processing now? */
@ -254,21 +239,25 @@ callframe_do_call_opts (const char *encoded_types,
/* Does the method have any arguments that are passed by reference?
If so, we need to encode them, since the method may have changed them. */
BOOL out_parameters = NO;
BOOL one_way = NO;
/* A dummy invocation to pass to the function that invokes our method */
NSInvocation_t *inv;
/* Signature information */
NSMethodSignature *sig;
const char *encoded_types = ctxt->type;
/* Decode the object, (which is always the first argument to a method),
into the local variable OBJECT. */
(*decoder) (0, &object, @encode(id));
ctxt->type = @encode(id);
ctxt->datum = &object;
(*decoder) (ctxt);
NSCParameterAssert (object);
/* Decode the selector, (which is always the second argument to a
method), into the local variable SELECTOR. */
/* xxx @encode(SEL) produces "^v" in gcc 2.5.8. It should be ":" */
(*decoder) (1, &selector, ":");
ctxt->type = @encode(SEL);
ctxt->datum = &selector;
(*decoder) (ctxt);
NSCParameterAssert (selector);
/* Get the "selector type" for this method. The "selector type" is
@ -343,7 +332,12 @@ callframe_do_call_opts (const char *encoded_types,
in <objc/objc-api.h> */
tmptype = objc_skip_type_qualifiers(tmptype);
datum = callframe_arg_addr(cframe, argnum);
/*
* Setup information in context.
*/
ctxt->datum = callframe_arg_addr(cframe, argnum);
ctxt->type = tmptype;
ctxt->flags = flags;
/* Decide how, (or whether or not), to decode the argument
depending on its FLAGS and TMPTYPE. Only the first two cases
@ -372,7 +366,7 @@ callframe_do_call_opts (const char *encoded_types,
the memory gets freed eventually, (usually through the
autorelease of NSData object). */
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (argnum, datum, tmptype);
(*decoder) (ctxt);
break;
@ -384,36 +378,24 @@ callframe_do_call_opts (const char *encoded_types,
it. Set OUT_PARAMETERS accordingly. */
if ((flags & _F_OUT) || !(flags & _F_IN))
out_parameters = YES;
if (pass_pointers)
{
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (argnum, datum, tmptype);
}
else
{
/* Handle an argument that is a pointer to a non-char. But
(void*) and (anything**) is not allowed. */
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
/* Allocate some memory to be pointed to, and to hold the
value. Note that it is allocated on the stack, and
methods that want to keep the data pointed to, will have
to make their own copies. */
*(void**)datum = alloca (objc_sizeof_type (tmptype));
/* If the pointer's value is qualified as an IN parameter,
or not explicity qualified as an OUT parameter, then
decode it. */
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (argnum, *(void**)datum, tmptype);
}
break;
case _C_STRUCT_B:
case _C_UNION_B:
case _C_ARY_B:
/* Handle struct and array arguments. */
(*decoder) (argnum, datum, tmptype);
/* Handle an argument that is a pointer to a non-char. But
(void*) and (anything**) is not allowed. */
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
ctxt->type = tmptype;
/* Allocate some memory to be pointed to, and to hold the
value. Note that it is allocated on the stack, and
methods that want to keep the data pointed to, will have
to make their own copies. */
*(void**)ctxt->datum = alloca (objc_sizeof_type (tmptype));
ctxt->datum = *(void**)ctxt->datum;
/* If the pointer's value is qualified as an IN parameter,
or not explicity qualified as an OUT parameter, then
decode it. */
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (ctxt);
break;
default:
@ -423,11 +405,13 @@ callframe_do_call_opts (const char *encoded_types,
object; the object may be autoreleased; if the method
wants to keep a reference to the object, it will have to
-retain it. */
(*decoder) (argnum, datum, tmptype);
(*decoder) (ctxt);
}
}
/* End of the for() loop that enumerates the method's arguments. */
(*decoder) (-1, 0, 0);
ctxt->type = 0;
ctxt->datum = 0;
(*decoder) (ctxt);
/* Invoke the method! */
@ -436,7 +420,7 @@ callframe_do_call_opts (const char *encoded_types,
method_implementation = objc_msg_lookup (object, selector);
NSCParameterAssert (method_implementation);
/* Do it! Send the message to the target, and get the return value
in retval. We need to rencode any pass-by-reference info */
in retval. We need to encode any pass-by-reference info */
inv = (NSInvocation_t *)NSAllocateObject([NSInvocation class], 0,
NSDefaultMallocZone());
inv->_retval = retval;
@ -464,76 +448,38 @@ callframe_do_call_opts (const char *encoded_types,
a non-oneway void return value, or if there are values that were
passed by reference. */
ctxt->flags = flags;
/* If there is a return value, encode it. */
switch (*tmptype)
if (*tmptype == _C_VOID)
{
case _C_VOID:
if ((flags & _F_ONEWAY) == 0)
{
int dummy = 0;
(*encoder) (-1, (void*)&dummy, @encode(int), 0);
}
else
{
one_way = YES;
int dummy = 0;
ctxt->type = @encode(int);
ctxt->datum = (void*)&dummy;
(*encoder) (ctxt);
}
/* No return value to encode; do nothing. */
break;
case _C_PTR:
if (pass_pointers)
{
(*encoder) (-1, retval, tmptype, flags);
}
else
}
else
{
if (*tmptype == _C_PTR)
{
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
/* Encode the value that was pointed to. */
(*encoder) (-1, *(void**)retval, tmptype, flags);
ctxt->type = tmptype;
ctxt->datum = *(void**)ctxt->datum;
}
break;
case _C_STRUCT_B:
case _C_UNION_B:
case _C_ARY_B:
/* The argument is a structure or array returned by value.
(In C, are array's allowed to be returned by value?) */
(*encoder)(-1, retval, tmptype, flags);
break;
case _C_FLT:
{
(*encoder) (-1, retval, tmptype, flags);
break;
}
case _C_DBL:
{
(*encoder) (-1, retval, tmptype, flags);
break;
}
case _C_SHT:
case _C_USHT:
{
(*encoder) (-1, retval, tmptype, flags);
break;
}
case _C_CHR:
case _C_UCHR:
{
(*encoder) (-1, retval, tmptype, flags);
break;
}
default:
/* case _C_INT: case _C_UINT: case _C_LNG: case _C_ULNG:
case _C_CHARPTR: case: _C_ID: */
/* xxx I think this assumes that sizeof(int)==sizeof(void*) */
(*encoder) (-1, retval, tmptype, flags);
else
{
ctxt->type = tmptype;
ctxt->datum = retval;
}
/* Encode the value that was pointed to. */
(*encoder) (ctxt);
}
@ -562,30 +508,30 @@ callframe_do_call_opts (const char *encoded_types,
/* Decide how, (or whether or not), to encode the argument
depending on its FLAGS and TMPTYPE. */
datum = callframe_arg_addr(cframe, argnum);
if (((flags & _F_OUT) || !(flags & _F_IN))
&& (*tmptype == _C_PTR || *tmptype == _C_CHARPTR))
{
ctxt->flags = flags;
ctxt->datum = callframe_arg_addr(cframe, argnum);
if ((*tmptype == _C_PTR)
&& ((flags & _F_OUT) || !(flags & _F_IN)))
{
/* The argument is a pointer (to a non-char), and the
pointer's value is qualified as an OUT parameter, or
it not explicitly qualified as an IN parameter, then
it is a pass-by-reference argument.*/
/* Encode it. */
(*encoder) (argnum, datum, tmptype, flags);
}
else if (*tmptype == _C_CHARPTR
&& ((flags & _F_OUT) || !(flags & _F_IN)))
{
/* The argument is a pointer char string, and the
pointer's value is qualified as an OUT parameter, or
it not explicitly qualified as an IN parameter, then
it is a pass-by-reference argument. Encode it.*/
/* xxx Perhaps we could save time and space by saving
a copy of the string before the method call, and then
comparing it to this string; if it didn't change, don't
bother to send it back again. */
(*encoder) (argnum, datum, tmptype, flags);
if (*tmptype == _C_PTR)
{
/* The argument is a pointer (to a non-char), and the
pointer's value is qualified as an OUT parameter, or
it not explicitly qualified as an IN parameter, then
it is a pass-by-reference argument.*/
ctxt->type = ++tmptype;
ctxt->datum = *(void**)ctxt->datum;
}
else if (*tmptype == _C_CHARPTR)
{
ctxt->type = tmptype;
/* The argument is a pointer char string, and the
pointer's value is qualified as an OUT parameter, or
it not explicitly qualified as an IN parameter, then
it is a pass-by-reference argument. */
}
(*encoder) (ctxt);
}
}
}
@ -597,14 +543,6 @@ callframe_do_call_opts (const char *encoded_types,
return;
}
void
callframe_do_call (const char *encoded_types,
void(*decoder)(int,void*,const char*),
void(*encoder)(int,void*,const char*,int))
{
callframe_do_call_opts(encoded_types, decoder, encoder, YES);
}
/* callframe_build_return()
This function decodes the values returned from a method call,
@ -616,14 +554,12 @@ callframe_do_call (const char *encoded_types,
dealt with. This permits the function to do any tidying up necessary. */
void
callframe_build_return_opts (NSInvocation *inv,
callframe_build_return (NSInvocation *inv,
const char *type,
BOOL out_parameters,
void(*decoder)(int,void*,const char*,int),
BOOL pass_pointers)
void(*decoder)(DOContext *ctxt),
DOContext *ctxt)
{
/* The size, in bytes, of memory pointed to by RETFRAME. */
int retsize;
/* Which argument number are we processing now? */
int argnum;
/* Type qualifier flags; see <objc/objc-api.h>. */
@ -664,74 +600,56 @@ callframe_build_return_opts (NSInvocation *inv,
/* If there is a return value, decode it, and put it in retval. */
if (*tmptype != _C_VOID || (flags & _F_ONEWAY) == 0)
{
ctxt->type = tmptype;
ctxt->datum = retval;
ctxt->flags = flags;
switch (*tmptype)
{
case _C_PTR:
if (pass_pointers)
{
(*decoder) (-1, retval, tmptype, flags);
}
else
{
unsigned retLength;
{
unsigned retLength;
/* We are returning a pointer to something. */
/* Increment TYPE so we can see what it is a pointer to. */
tmptype++;
retLength = objc_sizeof_type(tmptype);
/* Allocate memory to hold the value we're pointing to. */
*(void**)retval =
NSZoneMalloc(NSDefaultMallocZone(), retLength);
/* We are responsible for making sure this memory gets free'd
eventually. Ask NSData class to autorelease it. */
[NSData dataWithBytesNoCopy: *(void**)retval
length: retLength];
/* Decode the return value into the memory we allocated. */
(*decoder) (-1, *(void**)retval, tmptype, flags);
}
/* We are returning a pointer to something. */
/* Increment TYPE so we can see what it is a pointer to. */
tmptype++;
retLength = objc_sizeof_type(tmptype);
/* Allocate memory to hold the value we're pointing to. */
*(void**)retval =
NSZoneMalloc(NSDefaultMallocZone(), retLength);
/* We are responsible for making sure this memory gets free'd
eventually. Ask NSData class to autorelease it. */
[NSData dataWithBytesNoCopy: *(void**)retval
length: retLength];
ctxt->type = tmptype;
ctxt->datum = *(void**)retval;
/* Decode the return value into the memory we allocated. */
(*decoder) (ctxt);
}
break;
case _C_STRUCT_B:
case _C_UNION_B:
case _C_ARY_B:
/* Decode the return value into the memory we allocated. */
(*decoder) (-1, retval, tmptype, flags);
(*decoder) (ctxt);
break;
case _C_FLT:
case _C_DBL:
(*decoder) (-1, ((char*)retval), tmptype, flags);
(*decoder) (ctxt);
break;
case _C_VOID:
{
(*decoder) (-1, retval, @encode(int), 0);
ctxt->type = @encode(int);
ctxt->flags = 0;
(*decoder) (ctxt);
}
break;
default:
/* (Among other things, _C_CHARPTR is handled here). */
/* Special case BOOL (and other types smaller than int)
because retval doesn't actually point to the char */
/* xxx What about structures smaller than int's that
are passed by reference on true structure reference-
passing architectures? */
/* xxx Is this the right test? Use sizeof(int) instead? */
if (retsize < sizeof(void*))
{
#if 1
/* Frith-Macdonald said this worked better 21 Nov 96. */
(*decoder) (-1, retval, tmptype, flags);
#else
*(void**)retval = 0;
(*decoder) (-1, ((char*)retval)+sizeof(void*)-retsize,
tmptype, flags);
#endif
}
else
{
(*decoder) (-1, retval, tmptype, flags);
}
(*decoder) (ctxt);
}
}
[inv setReturnValue: retval];
@ -759,6 +677,10 @@ callframe_build_return_opts (NSInvocation *inv,
argument depending on its FLAGS and TMPTYPE. */
datum = callframe_arg_addr(cframe, argnum);
ctxt->type = tmptype;
ctxt->datum = datum;
ctxt->flags = flags;
if (*tmptype == _C_PTR
&& ((flags & _F_OUT) || !(flags & _F_IN)))
{
@ -768,14 +690,17 @@ callframe_build_return_opts (NSInvocation *inv,
parameter, or it not explicitly qualified as an
IN parameter, then it is a pass-by-reference
argument.*/
(*decoder) (argnum, datum, tmptype, flags);
tmptype++;
ctxt->type = tmptype;
(*decoder) (ctxt);
/* Copy the pointed-to data back to the original
pointer */
[inv getArgument: &ptr atIndex: argnum];
memcpy(ptr, *(void **)datum, objc_sizeof_type(tmptype+1));
memcpy(ptr, datum, objc_sizeof_type(tmptype));
}
else if (*tmptype == _C_CHARPTR
&& ((flags & _F_OUT) || !(flags & _F_IN)))
&& ((flags & _F_OUT) || !(flags & _F_IN)))
{
/* The argument is a pointer char string, and the
pointer's value is qualified as an OUT parameter,
@ -787,12 +712,14 @@ callframe_build_return_opts (NSInvocation *inv,
call, and then comparing it to this string; if it
didn't change, don't bother to send it back
again. */
(*decoder) (argnum, datum, tmptype, flags);
(*decoder) (ctxt);
[inv setArgument: datum atIndex: argnum];
}
}
}
(*decoder) (0, 0, 0, 0); /* Tell it we have finished. */
ctxt->type = 0;
ctxt->datum = 0;
(*decoder) (ctxt); /* Tell it we have finished. */
}
if (retval != 0)
@ -802,11 +729,3 @@ callframe_build_return_opts (NSInvocation *inv,
return;
}
void
callframe_build_return (NSInvocation *inv,
const char *type,
BOOL out_parameters,
void(*decoder)(int,void*,const char*,int))
{
callframe_build_return_opts(inv, type, out_parameters, decoder, YES);
}

View file

@ -43,8 +43,7 @@ extern void cifframe_get_arg(cifframe_t *cframe, int index, void *buffer);
extern void *cifframe_arg_addr(cifframe_t *cframe, int index);
extern BOOL cifframe_decode_return (const char *type, void* buffer);
extern void cifframe_do_call (const char *encoded_types,
void(*decoder)(int,void*,const char*),
void(*encoder)(int,void*,const char*,int));
extern void cifframe_do_call (DOContext *ctxt,
void(*decoder)(DOContext*),
void(*encoder)(DOContext*));
#endif

View file

@ -483,10 +483,9 @@ cifframe_decode_return (const char *type, void* buffer)
*/
void
cifframe_do_call_opts (const char *encoded_types,
void(*decoder)(int,void*,const char*),
void(*encoder)(int,void*,const char*,int),
BOOL pass_pointers)
cifframe_do_call_opts (DOContext *ctxt,
void(*decoder)(DOContext*),
void(*encoder)(DOContext*))
{
/* The method type string obtained from the target's OBJC_METHOD
structure for the selector we're sending. */
@ -501,8 +500,6 @@ cifframe_do_call_opts (const char *encoded_types,
SEL selector;
/* The OBJECT's implementation of the SELECTOR. */
IMP method_implementation;
/* A pointer into the ARGFRAME; points at individual arguments. */
char *datum;
/* Type qualifier flags; see <objc/objc-api.h>. */
unsigned flags;
/* Which argument number are we processing now? */
@ -514,16 +511,21 @@ cifframe_do_call_opts (const char *encoded_types,
/* Does the method have any arguments that are passed by reference?
If so, we need to encode them, since the method may have changed them. */
BOOL out_parameters = NO;
const char *encoded_types = ctxt->type;
/* Decode the object, (which is always the first argument to a method),
into the local variable OBJECT. */
(*decoder) (0, &object, @encode(id));
ctxt->type = @encode(id);
ctxt->datum = &object;
(*decoder) (ctxt);
NSCParameterAssert (object);
/* Decode the selector, (which is always the second argument to a
method), into the local variable SELECTOR. */
/* xxx @encode(SEL) produces "^v" in gcc 2.5.8. It should be ":" */
(*decoder) (1, &selector, ":");
ctxt->type = @encode(SEL);
ctxt->datum = &selector;
(*decoder) (ctxt);
NSCParameterAssert (selector);
/* Get the "selector type" for this method. The "selector type" is
@ -596,7 +598,9 @@ cifframe_do_call_opts (const char *encoded_types,
in <objc/objc-api.h> */
tmptype = objc_skip_type_qualifiers(tmptype);
datum = cifframe_arg_addr(cframe, argnum);
ctxt->flags = flags;
ctxt->type = tmptype;
ctxt->datum = cifframe_arg_addr(cframe, argnum);
/* Decide how, (or whether or not), to decode the argument
depending on its FLAGS and TMPTYPE. Only the first two cases
@ -625,7 +629,7 @@ cifframe_do_call_opts (const char *encoded_types,
the memory gets freed eventually, (usually through the
autorelease of NSData object). */
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (argnum, datum, tmptype);
(*decoder) (ctxt);
break;
@ -637,36 +641,30 @@ cifframe_do_call_opts (const char *encoded_types,
it. Set OUT_PARAMETERS accordingly. */
if ((flags & _F_OUT) || !(flags & _F_IN))
out_parameters = YES;
if (pass_pointers)
{
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (argnum, datum, tmptype);
}
else
{
/* Handle an argument that is a pointer to a non-char. But
(void*) and (anything**) is not allowed. */
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
/* Allocate some memory to be pointed to, and to hold the
value. Note that it is allocated on the stack, and
methods that want to keep the data pointed to, will have
to make their own copies. */
*(void**)datum = alloca (objc_sizeof_type (tmptype));
/* If the pointer's value is qualified as an IN parameter,
or not explicity qualified as an OUT parameter, then
decode it. */
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (argnum, *(void**)datum, tmptype);
}
/* Handle an argument that is a pointer to a non-char. But
(void*) and (anything**) is not allowed. */
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
ctxt->type = tmptype;
/* Allocate some memory to be pointed to, and to hold the
value. Note that it is allocated on the stack, and
methods that want to keep the data pointed to, will have
to make their own copies. */
*(void**)datum = alloca (objc_sizeof_type (tmptype));
ctxt->datum = *(void**)datum;
/* If the pointer's value is qualified as an IN parameter,
or not explicity qualified as an OUT parameter, then
decode it. */
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (ctxt);
break;
case _C_STRUCT_B:
case _C_UNION_B:
case _C_ARY_B:
/* Handle struct and array arguments. */
(*decoder) (argnum, datum, tmptype);
(*decoder) (ctxt);
break;
default:
@ -676,11 +674,13 @@ cifframe_do_call_opts (const char *encoded_types,
object; the object may be autoreleased; if the method
wants to keep a reference to the object, it will have to
-retain it. */
(*decoder) (argnum, datum, tmptype);
(*decoder) (ctxt);
}
}
/* End of the for() loop that enumerates the method's arguments. */
(*decoder) (-1, 0, 0);
ctxt->type = 0;
ctxt->datum = 0;
(*decoder) (ctxt);
/* Invoke the method! */
@ -711,30 +711,31 @@ cifframe_do_call_opts (const char *encoded_types,
/* If there is a return value, encode it. */
cifframe_decode_return(tmptype, retval);
ctxt->flags = flags;
ctxt->type = tmptype;
ctxt->datum = retval
switch (*tmptype)
{
case _C_VOID:
if ((flags & _F_ONEWAY) == 0)
{
int dummy = 0;
(*encoder) (-1, (void*)&dummy, @encode(int), 0);
ctxt->type = @encode(int);
ctxt->datum = &dummy;
(*encoder) (ctxt);
}
/* No return value to encode; do nothing. */
break;
case _C_PTR:
if (pass_pointers)
{
(*encoder) (-1, retval, tmptype, flags);
}
else
{
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
/* Encode the value that was pointed to. */
(*encoder) (-1, *(void**)retval, tmptype, flags);
}
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
ctxt->type = tmptype;
ctxt->datum = *(void**)retval;
/* Encode the value that was pointed to. */
(*encoder) (ctxt);
break;
case _C_STRUCT_B:
@ -742,32 +743,32 @@ cifframe_do_call_opts (const char *encoded_types,
case _C_ARY_B:
/* The argument is a structure or array returned by value.
(In C, are array's allowed to be returned by value?) */
(*encoder)(-1, retval, tmptype, flags);
(*encoder)(ctxt);
break;
case _C_FLT:
{
(*encoder) (-1, retval, tmptype, flags);
(*encoder) (ctxt);
break;
}
case _C_DBL:
{
(*encoder) (-1, retval, tmptype, flags);
(*encoder) (ctxt);
break;
}
case _C_SHT:
case _C_USHT:
{
(*encoder) (-1, retval, tmptype, flags);
(*encoder) (ctxt);
break;
}
case _C_CHR:
case _C_UCHR:
{
(*encoder) (-1, retval, tmptype, flags);
(*encoder) (ctxt);
break;
}
@ -775,7 +776,7 @@ cifframe_do_call_opts (const char *encoded_types,
/* case _C_INT: case _C_UINT: case _C_LNG: case _C_ULNG:
case _C_CHARPTR: case: _C_ID: */
/* xxx I think this assumes that sizeof(int)==sizeof(void*) */
(*encoder) (-1, retval, tmptype, flags);
(*encoder) (ctxt);
}
@ -806,8 +807,12 @@ cifframe_do_call_opts (const char *encoded_types,
depending on its FLAGS and TMPTYPE. */
datum = cifframe_arg_addr(cframe, argnum);
ctxt->flags = flags;
ctxt->type = tmptype;
ctxt->datum = datum;
if ((*tmptype == _C_PTR)
&& ((flags & _F_OUT) || !(flags & _F_IN)))
&& ((flags & _F_OUT) || !(flags & _F_IN)))
{
/* The argument is a pointer (to a non-char), and the
pointer's value is qualified as an OUT parameter, or
@ -816,11 +821,13 @@ cifframe_do_call_opts (const char *encoded_types,
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
ctxt->type = tmptype;
ctxt->datum = *(void**)ctxt->datum;
/* Encode it. */
(*encoder) (argnum, *(void**)datum, tmptype, flags);
(*encoder) (ctxt);
}
else if (*tmptype == _C_CHARPTR
&& ((flags & _F_OUT) || !(flags & _F_IN)))
&& ((flags & _F_OUT) || !(flags & _F_IN)))
{
/* The argument is a pointer char string, and the
pointer's value is qualified as an OUT parameter, or
@ -830,7 +837,7 @@ cifframe_do_call_opts (const char *encoded_types,
a copy of the string before the method call, and then
comparing it to this string; if it didn't change, don't
bother to send it back again. */
(*encoder) (argnum, datum, tmptype, flags);
(*encoder) (ctxt);
}
}
}
@ -838,10 +845,3 @@ cifframe_do_call_opts (const char *encoded_types,
return;
}
void
cifframe_do_call (const char *encoded_types,
void(*decoder)(int,void*,const char*),
void(*encoder)(int,void*,const char*,int))
{
cifframe_do_call_opts(encoded_types, decoder, encoder, NO);
}

View file

@ -609,9 +609,8 @@ method_types_get_sizeof_arguments (struct objc_method* mth)
e.g. an argument declared (out char*). */
BOOL
mframe_dissect_call_opts (arglist_t argframe, const char *type,
void (*encoder)(int,void*,const char*,int),
BOOL pass_pointers)
mframe_dissect_call (arglist_t argframe, const char *type,
void (*encoder)(DOContext *), DOContext *ctxt)
{
unsigned flags;
char *datum;
@ -645,6 +644,10 @@ mframe_dissect_call_opts (arglist_t argframe, const char *type,
reference, and thus only the first two may change the value
of OUT_PARAMETERS. */
ctxt->type = type;
ctxt->flags = flags;
ctxt->datum = datum;
switch (*type)
{
@ -661,7 +664,7 @@ mframe_dissect_call_opts (arglist_t argframe, const char *type,
explicity qualified as an OUT parameter, then encode
it. */
if ((flags & _F_IN) || !(flags & _F_OUT))
(*encoder) (argnum, datum, type, flags);
(*encoder) (ctxt);
break;
case _C_PTR:
@ -672,22 +675,18 @@ mframe_dissect_call_opts (arglist_t argframe, const char *type,
it. Set OUT_PARAMETERS accordingly. */
if ((flags & _F_OUT) || !(flags & _F_IN))
out_parameters = YES;
if (pass_pointers) {
if ((flags & _F_IN) || !(flags & _F_OUT))
(*encoder) (argnum, datum, type, flags);
}
else {
/* Handle an argument that is a pointer to a non-char. But
(void*) and (anything**) is not allowed. */
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
type++;
/* If the pointer's value is qualified as an IN parameter,
or not explicity qualified as an OUT parameter, then
encode it. */
if ((flags & _F_IN) || !(flags & _F_OUT))
(*encoder) (argnum, *(void**)datum, type, flags);
}
/* Handle an argument that is a pointer to a non-char. But
(void*) and (anything**) is not allowed. */
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
type++;
ctxt->type = type;
ctxt->datum = *(void**)datum;
/* If the pointer's value is qualified as an IN parameter,
or not explicity qualified as an OUT parameter, then
encode it. */
if ((flags & _F_IN) || !(flags & _F_OUT))
(*encoder) (ctxt);
break;
case _C_STRUCT_B:
@ -699,15 +698,14 @@ mframe_dissect_call_opts (arglist_t argframe, const char *type,
MFRAME_STRUCT_BYREF. Do the right thing
so that ENCODER gets a pointer to directly to the data. */
#if MFRAME_STRUCT_BYREF
(*encoder) (argnum, *(void**)datum, type, flags);
#else
(*encoder) (argnum, datum, type, flags);
ctxt->datum = *(void**)datum;
#endif
(*encoder) (ctxt);
break;
default:
/* Handle arguments of all other types. */
(*encoder) (argnum, datum, type, flags);
(*encoder) (ctxt);
}
}
@ -718,13 +716,6 @@ mframe_dissect_call_opts (arglist_t argframe, const char *type,
return out_parameters;
}
BOOL
mframe_dissect_call (arglist_t argframe, const char *type,
void (*encoder)(int,void*,const char*,int))
{
return mframe_dissect_call_opts(argframe, type, encoder, NO);
}
/* mframe_do_call()
@ -799,10 +790,9 @@ mframe_dissect_call (arglist_t argframe, const char *type,
*/
void
mframe_do_call_opts (const char *encoded_types,
void(*decoder)(int,void*,const char*),
void(*encoder)(int,void*,const char*,int),
BOOL pass_pointers)
mframe_do_call (DOContext *ctxt,
void(*decoder)(DOContext*),
void(*encoder)(DOContext*))
{
/* The method type string obtained from the target's OBJC_METHOD
structure for the selector we're sending. */
@ -834,6 +824,7 @@ mframe_do_call_opts (const char *encoded_types,
/* Does the method have any arguments that are passed by reference?
If so, we need to encode them, since the method may have changed them. */
BOOL out_parameters = NO;
const char *encoded_types = ctxt->type;
/* For extracting a return value of type `float' from RETFRAME. */
float retframe_float (void *rframe)
{
@ -857,13 +848,17 @@ mframe_do_call_opts (const char *encoded_types,
/* Decode the object, (which is always the first argument to a method),
into the local variable OBJECT. */
(*decoder) (0, &object, @encode(id));
ctxt->datum = &object;
ctxt->type = @encode(id);
(*decoder) (ctxt);
NSCParameterAssert (object);
/* Decode the selector, (which is always the second argument to a
method), into the local variable SELECTOR. */
/* xxx @encode(SEL) produces "^v" in gcc 2.5.8. It should be ":" */
(*decoder) (1, &selector, ":");
ctxt->datum = &selector;
ctxt->type = @encode(SEL);
(*decoder) (ctxt);
NSCParameterAssert (selector);
/* Get the "selector type" for this method. The "selector type" is
@ -981,6 +976,9 @@ mframe_do_call_opts (const char *encoded_types,
the code in mframe_dissect_call(); that function should
encode exactly what we decode here. *** */
ctxt->type = tmptype;
ctxt->datum = datum;
switch (*tmptype)
{
@ -1000,7 +998,7 @@ mframe_do_call_opts (const char *encoded_types,
the memory gets freed eventually, (usually through the
autorelease of NSData object). */
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (argnum, datum, tmptype);
(*decoder) (ctxt);
break;
@ -1012,29 +1010,23 @@ mframe_do_call_opts (const char *encoded_types,
it. Set OUT_PARAMETERS accordingly. */
if ((flags & _F_OUT) || !(flags & _F_IN))
out_parameters = YES;
if (pass_pointers)
{
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (argnum, datum, tmptype);
}
else
{
/* Handle an argument that is a pointer to a non-char. But
(void*) and (anything**) is not allowed. */
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
/* Allocate some memory to be pointed to, and to hold the
value. Note that it is allocated on the stack, and
methods that want to keep the data pointed to, will have
to make their own copies. */
*(void**)datum = alloca (objc_sizeof_type (tmptype));
/* If the pointer's value is qualified as an IN parameter,
or not explicity qualified as an OUT parameter, then
decode it. */
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (argnum, *(void**)datum, tmptype);
}
/* Handle an argument that is a pointer to a non-char. But
(void*) and (anything**) is not allowed. */
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
/* Allocate some memory to be pointed to, and to hold the
value. Note that it is allocated on the stack, and
methods that want to keep the data pointed to, will have
to make their own copies. */
*(void**)datum = alloca (objc_sizeof_type (tmptype));
/* If the pointer's value is qualified as an IN parameter,
or not explicity qualified as an OUT parameter, then
decode it. */
ctxt->type = tmptype;
ctxt->datum = *(void**)datum;
if ((flags & _F_IN) || !(flags & _F_OUT))
(*decoder) (ctxt);
break;
case _C_STRUCT_B:
@ -1051,10 +1043,9 @@ mframe_do_call_opts (const char *encoded_types,
methods that want to keep the data pointed to, will have
to make their own copies. */
*(void**)datum = alloca (objc_sizeof_type(tmptype));
(*decoder) (argnum, *(void**)datum, tmptype);
#else
(*decoder) (argnum, datum, tmptype);
ctxt->datum = datum;
#endif
(*decoder) (ctxt);
break;
default:
@ -1064,11 +1055,13 @@ mframe_do_call_opts (const char *encoded_types,
object; the object may be autoreleased; if the method
wants to keep a reference to the object, it will have to
-retain it. */
(*decoder) (argnum, datum, tmptype);
(*decoder) (ctxt);
}
}
/* End of the for() loop that enumerates the method's arguments. */
(*decoder) (-1, 0, 0);
ctxt->type = 0;
ctxt->datum = 0;
(*decoder) (ctxt);
/* Invoke the method! */
@ -1100,31 +1093,32 @@ mframe_do_call_opts (const char *encoded_types,
a non-oneway void return value, or if there are values that were
passed by reference. */
ctxt->type = tmptype;
ctxt->datum = retframe;
ctxt->flags = flags;
/* If there is a return value, encode it. */
switch (*tmptype)
{
case _C_VOID:
if ((flags & _F_ONEWAY) == 0)
{
int dummy = 0;
(*encoder) (-1, (void*)&dummy, @encode(int), 0);
int dummy = 0;
ctxt->datum = &dummy;
ctxt->type = @encode(int);
(*encoder) (ctxt);
}
/* No return value to encode; do nothing. */
break;
case _C_PTR:
if (pass_pointers)
{
(*encoder) (-1, retframe, tmptype, flags);
}
else
{
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
/* Encode the value that was pointed to. */
(*encoder) (-1, *(void**)retframe, tmptype, flags);
}
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
ctxt->type = tmptype;
ctxt->datum = *(void**)retframe;
/* Encode the value that was pointed to. */
(*encoder) (ctxt);
break;
case _C_STRUCT_B:
@ -1132,20 +1126,23 @@ mframe_do_call_opts (const char *encoded_types,
case _C_ARY_B:
/* The argument is a structure or array returned by value.
(In C, are array's allowed to be returned by value?) */
(*encoder)(-1, MFRAME_GET_STRUCT_ADDR(argframe, tmptype), tmptype, flags);
ctxt->datum = MFRAME_GET_STRUCT_ADDR(argframe, tmptype);
(*encoder)(ctxt);
break;
case _C_FLT:
{
float ret = retframe_float (retframe);
(*encoder) (-1, &ret, tmptype, flags);
ctxt->datum = &ret;
(*encoder) (ctxt);
break;
}
case _C_DBL:
{
double ret = retframe_double (retframe);
(*encoder) (-1, &ret, tmptype, flags);
ctxt->datum = &ret;
(*encoder) (ctxt);
break;
}
@ -1158,7 +1155,8 @@ mframe_do_call_opts (const char *encoded_types,
it. */
{
short ret = retframe_short (retframe);
(*encoder) (-1, &ret, tmptype, flags);
ctxt->datum = &ret;
(*encoder) (ctxt);
break;
}
@ -1171,7 +1169,8 @@ mframe_do_call_opts (const char *encoded_types,
it. */
{
char ret = retframe_char (retframe);
(*encoder) (-1, &ret, tmptype, flags);
ctxt->datum = &ret;
(*encoder) (ctxt);
break;
}
@ -1179,7 +1178,7 @@ mframe_do_call_opts (const char *encoded_types,
/* case _C_INT: case _C_UINT: case _C_LNG: case _C_ULNG:
case _C_CHARPTR: case: _C_ID: */
/* xxx I think this assumes that sizeof(int)==sizeof(void*) */
(*encoder) (-1, retframe, tmptype, flags);
(*encoder) (ctxt);
}
@ -1206,11 +1205,14 @@ mframe_do_call_opts (const char *encoded_types,
in <objc/objc-api.h> */
tmptype = objc_skip_type_qualifiers (tmptype);
ctxt->type = tmptype;
ctxt->datum = datum;
/* Decide how, (or whether or not), to encode the argument
depending on its FLAGS and TMPTYPE. */
if ((*tmptype == _C_PTR)
&& ((flags & _F_OUT) || !(flags & _F_IN)))
&& ((flags & _F_OUT) || !(flags & _F_IN)))
{
/* The argument is a pointer (to a non-char), and the
pointer's value is qualified as an OUT parameter, or
@ -1219,11 +1221,13 @@ mframe_do_call_opts (const char *encoded_types,
/* The argument is a pointer to something; increment TYPE
so we can see what it is a pointer to. */
tmptype++;
ctxt->type = tmptype;
ctxt->datum = *(void**)datum;
/* Encode it. */
(*encoder) (argnum, *(void**)datum, tmptype, flags);
(*encoder) (ctxt);
}
else if (*tmptype == _C_CHARPTR
&& ((flags & _F_OUT) || !(flags & _F_IN)))
&& ((flags & _F_OUT) || !(flags & _F_IN)))
{
/* The argument is a pointer char string, and the
pointer's value is qualified as an OUT parameter, or
@ -1233,7 +1237,7 @@ mframe_do_call_opts (const char *encoded_types,
a copy of the string before the method call, and then
comparing it to this string; if it didn't change, don't
bother to send it back again. */
(*encoder) (argnum, datum, tmptype, flags);
(*encoder) (ctxt);
}
}
}
@ -1241,15 +1245,7 @@ mframe_do_call_opts (const char *encoded_types,
return;
}
void
mframe_do_call (const char *encoded_types,
void(*decoder)(int,void*,const char*),
void(*encoder)(int,void*,const char*,int))
{
mframe_do_call_opts(encoded_types, decoder, encoder, NO);
}
/* For returning strucutres etc */
/* For returning structures etc */
typedef struct { id many[8];} __big;
static __big return_block (void* data)
{
@ -1319,11 +1315,11 @@ static retval_t apply_short(short data)
*/
retval_t
mframe_build_return_opts (arglist_t argframe,
mframe_build_return (arglist_t argframe,
const char *type,
BOOL out_parameters,
void(*decoder)(int,void*,const char*,int),
BOOL pass_pointers)
void(*decoder)(DOContext*),
DOContext *ctxt)
{
/* A pointer to the memory that will hold the return value. */
retval_t retframe = NULL;
@ -1357,9 +1353,6 @@ mframe_build_return_opts (arglist_t argframe,
/* xxx What happens with method declared "- (in char *) bar;" */
/* xxx Is this right? Do we also have to check _F_ONEWAY? */
{
/* ARGNUM == -1 signifies to DECODER() that this is the return
value, not an argument. */
/* If there is a return value, decode it, and put it in retframe. */
if (*tmptype != _C_VOID || (flags & _F_ONEWAY) == 0)
{
@ -1378,31 +1371,32 @@ mframe_build_return_opts (arglist_t argframe,
just always alloca(RETFRAME_SIZE == sizeof(void*)*4) */
retframe = alloca (MAX(retsize, sizeof(void*)*4));
ctxt->type = tmptype;
ctxt->datum = retframe;
ctxt->flags = flags;
switch (*tmptype)
{
case _C_PTR:
if (pass_pointers)
{
(*decoder) (-1, retframe, tmptype, flags);
}
else
{
unsigned retLength;
{
unsigned retLength;
/* We are returning a pointer to something. */
/* Increment TYPE so we can see what it is a pointer to. */
tmptype++;
retLength = objc_sizeof_type(tmptype);
/* Allocate memory to hold the value we're pointing to. */
*(void**)retframe =
NSZoneMalloc(NSDefaultMallocZone(), retLength);
/* We are responsible for making sure this memory gets free'd
eventually. Ask NSData class to autorelease it. */
[NSData dataWithBytesNoCopy: *(void**)retframe
length: retLength];
/* Decode the return value into the memory we allocated. */
(*decoder) (-1, *(void**)retframe, tmptype, flags);
}
/* We are returning a pointer to something. */
/* Increment TYPE so we can see what it is a pointer to. */
tmptype++;
retLength = objc_sizeof_type(tmptype);
/* Allocate memory to hold the value we're pointing to. */
*(void**)retframe =
NSZoneMalloc(NSDefaultMallocZone(), retLength);
/* We are responsible for making sure this memory gets free'd
eventually. Ask NSData class to autorelease it. */
[NSData dataWithBytesNoCopy: *(void**)retframe
length: retLength];
ctxt->type = tmptype;
ctxt->datum = *(void**)retframe;
/* Decode the return value into the memory we allocated. */
(*decoder) (ctxt);
}
break;
case _C_STRUCT_B:
@ -1412,43 +1406,24 @@ mframe_build_return_opts (arglist_t argframe,
(In C, are array's allowed to be returned by value?) */
*(void**)retframe = MFRAME_GET_STRUCT_ADDR(argframe, tmptype);
/* Decode the return value into the memory we allocated. */
(*decoder) (-1, *(void**)retframe, tmptype, flags);
ctxt->datum = *(void**)retframe;
(*decoder) (ctxt);
break;
case _C_FLT:
case _C_DBL:
(*decoder) (-1, ((char*)retframe), tmptype, flags);
(*decoder) (ctxt);
break;
case _C_VOID:
{
(*decoder) (-1, retframe, @encode(int), 0);
ctxt->type = @encode(int);
(*decoder) (ctxt);
}
break;
default:
/* (Among other things, _C_CHARPTR is handled here). */
/* Special case BOOL (and other types smaller than int)
because retframe doesn't actually point to the char */
/* xxx What about structures smaller than int's that
are passed by reference on true structure reference-
passing architectures? */
/* xxx Is this the right test? Use sizeof(int) instead? */
if (retsize < sizeof(void*))
{
#if 1
/* Frith-Macdonald said this worked better 21 Nov 96. */
(*decoder) (-1, retframe, tmptype, flags);
#else
*(void**)retframe = 0;
(*decoder) (-1, ((char*)retframe)+sizeof(void*)-retsize,
tmptype, flags);
#endif
}
else
{
(*decoder) (-1, retframe, tmptype, flags);
}
(*decoder) (ctxt);
}
}
@ -1487,16 +1462,19 @@ mframe_build_return_opts (arglist_t argframe,
/* The argument is a pointer to something; increment
TYPE so we can see what it is a pointer to. */
tmptype++;
ctxt->flags = flags;
ctxt->type = tmptype;
ctxt->datum = *(void**)datum;
/* xxx Note that a (char**) is malloc'ed anew here.
Yucky, or worse than yucky. If the returned string
is smaller than the original, we should just put it
there; if the returned string is bigger, I don't know
what to do. */
/* xxx __builtin_return can't return structures by value? */
(*decoder) (argnum, *(void**)datum, tmptype, flags);
(*decoder) (ctxt);
}
else if (*tmptype == _C_CHARPTR
&& ((flags & _F_OUT) || !(flags & _F_IN)))
&& ((flags & _F_OUT) || !(flags & _F_IN)))
{
/* The argument is a pointer char string, and the
pointer's value is qualified as an OUT parameter,
@ -1508,11 +1486,16 @@ mframe_build_return_opts (arglist_t argframe,
call, and then comparing it to this string; if it
didn't change, don't bother to send it back
again. */
(*decoder) (argnum, datum, tmptype, flags);
ctxt->flags = flags;
ctxt->type = tmptype;
ctxt->datum = datum;
(*decoder) (ctxt);
}
}
}
(*decoder) (0, 0, 0, 0); /* Tell it we have finished. */
ctxt->type = 0;
ctxt->datum = 0;
(*decoder) (ctxt); /* Tell it we have finished. */
}
else /* matches `if (out_parameters)' */
{
@ -1546,15 +1529,6 @@ mframe_build_return_opts (arglist_t argframe,
return retframe;
}
retval_t
mframe_build_return (arglist_t argframe,
const char *type,
BOOL out_parameters,
void(*decoder)(int,void*,const char*,int))
{
return mframe_build_return_opts(argframe,type,out_parameters,decoder,NO);
}
arglist_t

View file

@ -26,6 +26,8 @@
#include <base/preface.h>
#include <base/DistributedObjects.h>
/* For NSArgumentInfo we include NSMethodSignature.h */
#include <Foundation/NSMethodSignature.h>
@ -52,11 +54,7 @@ typedef union {
BOOL
mframe_dissect_call (arglist_t argframe, const char *types,
void (*encoder)(int,void*,const char*,int));
BOOL
mframe_dissect_call_opts (arglist_t argframe, const char *types,
void (*encoder)(int,void*,const char*,int),
BOOL pass_pointers);
void (*encoder)(DOContext*), DOContext *ctxt);
/* Decode the arguments to a method call by calling DECODER, knowing
what to decode by looking at type string ENCODED_TYPES. Build an
@ -64,14 +62,9 @@ mframe_dissect_call_opts (arglist_t argframe, const char *types,
return value and the pass-by-reference values using ENCODER. */
void
mframe_do_call (const char *encoded_types,
void(*decoder)(int,void*,const char*),
void(*encoder)(int,void*,const char*,int));
void
mframe_do_call_opts (const char *encoded_types,
void(*decoder)(int,void*,const char*),
void(*encoder)(int,void*,const char*,int),
BOOL pass_pointers);
mframe_do_call (DOContext *ctxt,
void(*decoder)(DOContext*),
void(*encoder)(DOContext*));
/* Decode the return value and pass-by-reference arguments using
DECODER, knowning what to decode by looking at type string TYPES
@ -81,12 +74,7 @@ mframe_do_call_opts (const char *encoded_types,
retval_t
mframe_build_return (arglist_t argframe, const char *types,
BOOL out_parameters,
void(*decoder)(int,void*,const char*,int));
retval_t
mframe_build_return_opts (arglist_t argframe, const char *types,
BOOL out_parameters,
void(*decoder)(int,void*,const char*,int),
BOOL pass_pointers);
void(*decoder)(DOContext*), DOContext *ctxt);
/*
* Copy the return value from retframe into the specified buffer.