mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
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:
parent
bb0482127b
commit
f07102c855
9 changed files with 630 additions and 788 deletions
20
ChangeLog
20
ChangeLog
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
302
Source/mframe.m
302
Source/mframe.m
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue