diff --git a/ChangeLog b/ChangeLog index b6ef9eb39..c0fc56027 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2009-10-04 Richard Frith-Macdonald + + * Source/cifframe.h: Remove unused code + * Source/cifframe.m: ditto + * Source/callframe.h: ditto + * Source/callframe.m: ditto + * Source/NSConnection.m: Use NSInvocation functionality directly + rather than duplicated versions of the code in ffi/ffcall/mframe + specific files. Should simplify things and make maintenance easier. + 2009-10-03 Richard Frith-Macdonald * Source/GSInvocation.h: diff --git a/Examples/nsconnection_client.m b/Examples/nsconnection_client.m index 0e20cea75..f33c69820 100644 --- a/Examples/nsconnection_client.m +++ b/Examples/nsconnection_client.m @@ -93,6 +93,7 @@ int con_data (id prx) id obj; small_struct small = {12}; foo ffoo = {'Z', 1234.5678, 99, "cow", 9876543}; + foo bck; printf("Testing data sending\n"); @@ -214,11 +215,13 @@ int con_data (id prx) #if 1 || !defined(__MINGW32__) pool = [NSAutoreleasePool new]; printf("Struct:\n"); + memcpy(&bck, &ffoo, sizeof(bck)); printf(" sending c='%c',d=%g,i=%d,s=%s,l=%ld", ffoo.c, ffoo.d, ffoo.i, ffoo.s, ffoo.l); ffoo = [prx sendStruct: ffoo]; printf(" got c='%c',d=%g,i=%d,s=%s,l=%ld\n", ffoo.c, ffoo.d, ffoo.i, ffoo.s, ffoo.l); + memcpy(&ffoo, &bck, sizeof(bck)); printf(" sending ptr to c='%c',d=%g,i=%d,s=%s,l=%ld", ffoo.c, ffoo.d, ffoo.i, ffoo.s, ffoo.l); [prx getStruct: &ffoo]; diff --git a/Examples/nsconnection_server.m b/Examples/nsconnection_server.m index 8d95fa194..ce45d2ac2 100644 --- a/Examples/nsconnection_server.m +++ b/Examples/nsconnection_server.m @@ -291,8 +291,11 @@ - (void) getObject: (id *)str { + static NSString *ret = @"hello"; printf ("(%s) got object (%s)\n", GSNameFromSelector(_cmd), GSClassNameFromObject(*str)); + *str = ret; + printf(" returning (%s)\n", [*str cString]); fflush(stdout); } @@ -307,8 +310,9 @@ - (void) getString: (char **)str { + static char *ret = "hello"; printf ("(%s) got string (%s)", GSNameFromSelector(_cmd), *str); - (*str)[0] = 'N'; + *str = ret; printf(" returning (%s)\n", *str); fflush(stdout); } diff --git a/Source/NSConnection.m b/Source/NSConnection.m index 598116104..446fdc331 100644 --- a/Source/NSConnection.m +++ b/Source/NSConnection.m @@ -1948,89 +1948,6 @@ static NSLock *cached_proxies_gate = nil; RELEASE(arp); } -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 decodeObject]; - - ctxt->decoder = nil; - [ctxt->connection _doneInReply: coder]; - if (ctxt->datToFree != 0) - { - NSZoneFree(NSDefaultMallocZone(), ctxt->datToFree); - ctxt->datToFree = 0; - } - [exc raise]; - } - } - if (*type == _C_ID) - { - *(id*)ctxt->datum = [coder decodeObject]; - } - else - { - [coder decodeValueOfObjCType: type at: ctxt->datum]; - } -} - -#if !defined(USE_FFCALL) && !defined(USE_LIBFFI) -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]; - } -} -#endif - /* * NSDistantObject's -forward:: method calls this to send the message * over the wire. @@ -2039,148 +1956,9 @@ static void retEncoder (DOContext *ctxt) selector: (SEL)sel argFrame: (arglist_t)argframe { -#if !defined(USE_FFCALL) && !defined(USE_LIBFFI) - BOOL outParams; - BOOL needsResponse; - const char *type; - retval_t retframe; - DOContext ctxt; - NSRunLoop *runLoop = GSRunLoopForThread(nil); - - memset(&ctxt, 0, sizeof(ctxt)); - ctxt.connection = self; - - /* Encode the method on an RMC, and send it. */ - - NSParameterAssert (IisValid); - - if ([IrunLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound) - { - if (ImultipleThreads == NO) - { - [NSException raise: NSObjectInaccessibleException - format: @"Forwarding message in wrong thread"]; - } - else - { - [self addRunLoop: runLoop]; - } - } - - /* get the method types from the selector */ -#if NeXT_RUNTIME - [NSException - raise: NSGenericException - format: @"Sorry, distributed objects does not work with NeXT runtime"]; - /* type = [object selectorTypeForProxy: sel]; */ -#else - type = sel_get_type(sel); - if (type == 0 || *type == '\0') - { - type = [[object methodSignatureForSelector: sel] methodType]; - if (type) - { - sel_register_typed_name(GSNameFromSelector(sel), type); - } - } -#endif - NSParameterAssert(type); - NSParameterAssert(*type); - - ctxt.encoder = [self _makeOutRmc: 0 generate: (int*)&ctxt.seq reply: YES]; - - if (debug_connection > 4) - 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. */ - [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, retEncoder, &ctxt); - - if (outParams == YES) - { - needsResponse = YES; - } - else - { - int flags; - - needsResponse = NO; - flags = objc_get_type_qualifiers(type); - if ((flags & _F_ONEWAY) == 0) - { - needsResponse = YES; - } - else - { - const char *tmptype = objc_skip_type_qualifiers(type); - - if (*tmptype != _C_VOID) - { - needsResponse = YES; - } - } - } - - [self _sendOutRmc: ctxt.encoder type: METHOD_REQUEST]; - ctxt.encoder = nil; - NSDebugMLLog(@"NSConnection", @"Sent message (%s) RMX %d to 0x%x", - GSNameFromSelector(sel), ctxt.seq, (uintptr_t)self); - - if (needsResponse == NO) - { - GSIMapNode node; - - /* - * Since we don't need a response, we can remove the placeholder from - * the IreplyMap. However, in case the other end has already sent us - * a response, we must check for it and scrap it if necessary. - */ - M_LOCK(IrefGate); - node = GSIMapNodeForKey(IreplyMap, (GSIMapKey)ctxt.seq); - if (node != 0 && node->value.obj != dummyObject) - { - BOOL is_exception = NO; - - [node->value.obj decodeValueOfObjCType: @encode(BOOL) - at: &is_exception]; - if (is_exception == YES) - NSLog(@"Got exception with %@", NSStringFromSelector(sel)); - else - NSLog(@"Got response with %@", NSStringFromSelector(sel)); - [self _doneInRmc: node->value.obj]; - } - GSIMapRemoveKey(IreplyMap, (GSIMapKey)ctxt.seq); - M_UNLOCK(IrefGate); - retframe = alloca(sizeof(void*)); /* Dummy value for void return. */ - } - else - { - 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(ctxt.decoder == nil, NSInternalInconsistencyException); - } - return retframe; -#else - /* If we've got to here then something has gone badly wrong. Most likely a - * mismatch between NSDistantObject and NSConnection implementations. - */ - NSAssert(NO, @"Legacy forwardForProxy:selector:argFrame: method called when compiled with fcall/ffi."); - return 0; // Not reached. -#endif //!defined(USE_FFCALL) && !defined(USE_LIBFFI) +[NSException raise: NSInternalInconsistencyException + format: @"Obsolete method called"]; + return 0; } /* @@ -2296,20 +2074,12 @@ static void retEncoder (DOContext *ctxt) } else { -#if 1 - /* Which argument number are we processing now? */ - int argnum; - /* Type qualifier flags; see . */ - int flags; - /* A pointer into the TYPE string. */ - const char *tmptype; - /* Points at individual arguments. */ - void *datum; - const char *rettype; - /* Signature information */ + int argnum; + int flags; + const char *tmptype; + void *datum; NSPortCoder *aRmc; - - BOOL is_exception; + BOOL is_exception; if ([self isValid] == NO) { @@ -2335,7 +2105,6 @@ static void retEncoder (DOContext *ctxt) /* Get the return type qualifier flags, and the return type. */ flags = objc_get_type_qualifiers(type); tmptype = objc_skip_type_qualifiers(type); - rettype = tmptype; /* Decode the return value and pass-by-reference values, if there are any. OUT_PARAMETERS should be the value returned by @@ -2345,9 +2114,6 @@ static void retEncoder (DOContext *ctxt) /* 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 datum. */ if (*tmptype != _C_VOID || (flags & _F_ONEWAY) == 0) { @@ -2394,33 +2160,23 @@ static void retEncoder (DOContext *ctxt) if (*tmptype == _C_PTR && ((flags & _F_OUT) || !(flags & _F_IN))) { + /* If the arg was myref, we obtain its address + * and decode the data directly to it. + */ tmptype++; - datum = alloca (objc_sizeof_type (tmptype)); - + [inv getArgument: &datum atIndex: argnum]; [aRmc decodeValueOfObjCType: tmptype at: datum]; - [inv setArgument: datum atIndex: argnum]; } else if (*tmptype == _C_CHARPTR && ((flags & _F_OUT) || !(flags & _F_IN))) { [aRmc decodeValueOfObjCType: tmptype at: &datum]; - [inv setArgument: &datum atIndex: argnum]; + [inv setArgument: datum atIndex: argnum]; } } } } [self _doneInReply: aRmc]; -#elif USE_LIBFFI - cifframe_build_return (inv, type, outParams, retDecoder, &ctxt); -#elif defined(USE_FFCALL) - 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(ctxt.decoder == nil, NSInternalInconsistencyException); } } @@ -2722,96 +2478,6 @@ static void retEncoder (DOContext *ctxt) } } -static void callDecoder (DOContext *ctxt) -{ - const char *type = ctxt->type; - - /* - * 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 (type == 0) - { - NSPortCoder *coder = ctxt->decoder; - - ctxt->decoder = nil; - [ctxt->connection _doneInRmc: coder]; - return; - } - - /* - * The coder may have an optimised method for decoding objects - * so we use that one if we are expecting an object, otherwise - * we use thegeneric method. - */ - if (*type == _C_ID) - { - *(id*)ctxt->datum = [ctxt->decoder decodeObject]; - } - else - { - [ctxt->decoder decodeValueOfObjCType: type at: ctxt->datum]; - } -} - -static void callEncoder (DOContext *ctxt) -{ - const char *type = ctxt->type; - 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) - { - return; - } - - /* - * 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. - */ - ctxt->encoder = [ctxt->connection _makeOutRmc: ctxt->seq - generate: 0 - reply: NO]; - coder = ctxt->encoder; - [coder encodeValueOfObjCType: @encode(BOOL) at: &is_exception]; - } - - if (*type == _C_ID) - { - int flags = ctxt->flags; - - if (flags & _F_BYCOPY) - { - [coder encodeBycopyObject: *(id*)ctxt->datum]; - } -#ifdef _F_BYREF - else if (flags & _F_BYREF) - { - [coder encodeByrefObject: *(id*)ctxt->datum]; - } -#endif - else - { - [coder encodeObject: *(id*)ctxt->datum]; - } - } - else - { - [coder encodeValueOfObjCType: type at: ctxt->datum]; - } -} - /* NSConnection calls this to service the incoming method request. */ - (void) _service_forwardForProxy: (NSPortCoder*)aRmc @@ -2864,331 +2530,319 @@ static void callEncoder (DOContext *ctxt) ctxt.type, ctxt.seq, (uintptr_t)self); IreqInCount++; /* Handling an incoming request. */ -#if 1 -{ - /* The method type string obtained from the target's OBJC_METHOD - structure for the selector we're sending. */ - const char *type; - /* A pointer into the local variable TYPE string. */ - const char *tmptype; - /* A pointer into the argument ENCODED_TYPES string. */ - const char *etmptype; - /* The target object that will receive the message. */ - id object; - /* The selector for the message we're sending to the TARGET. */ - SEL selector; - /* The OBJECT's Method(_t) pointer for the SELECTOR. */ - GSMethod meth = 0; - BOOL is_exception = NO; - /* Type qualifier flags; see . */ - unsigned flags; - /* Which argument number are we processing now? */ - int argnum; - /* 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; - NSInvocation *inv; - /* Signature information */ - NSMethodSignature *sig; - const char *encoded_types = forward_type; - - etmptype = encoded_types; - - ctxt.encoder = aRmc; - - /* Decode the object, (which is always the first argument to a method). */ - [aRmc decodeValueOfObjCType: @encode(id) at: &object]; - - /* Decode the selector, (which is always the second argument to a method). */ - /* xxx @encode(SEL) produces "^v" in gcc 2.5.8. It should be ":" */ - [aRmc decodeValueOfObjCType: @encode(SEL) at: &selector]; - - /* Get the "selector type" for this method. The "selector type" is - a string that lists the return and argument types, and also - indicates in which registers and where on the stack the arguments - should be placed before the method call. The selector type - string we get here should have the same argument and return types - as the ENCODED_TYPES string, but it will have different register - and stack locations if the ENCODED_TYPES came from a machine of a - different architecture. */ - if (GSObjCIsClass(object)) { - meth = GSGetMethod(object, selector, NO, YES); - } - else if (GSObjCIsInstance(object)) - { - meth = GSGetMethod(GSObjCClass(object), selector, YES, YES); - } - else - { - [NSException raise: NSInvalidArgumentException - format: @"decoded object %p is invalid", object]; - } - - if (meth != 0) - { - type = meth->method_types; - } - else - { - NSDebugLog(@"Local object <%p %s> doesn't implement: %s directly. " - @"Will search for arbitrary signature.", - object, - GSNameFromClass(GSObjCIsClass(object) - ? object : (id)GSObjCClass(object)), - GSNameFromSelector(selector)); - type = GSTypesFromSelector(selector); - } + /* The method type string obtained from the target's OBJC_METHOD + structure for the selector we're sending. */ + const char *type; + /* A pointer into the local variable TYPE string. */ + const char *tmptype; + /* A pointer into the argument ENCODED_TYPES string. */ + const char *etmptype; + /* The target object that will receive the message. */ + id object; + /* The selector for the message we're sending to the TARGET. */ + SEL selector; + /* The OBJECT's Method(_t) pointer for the SELECTOR. */ + GSMethod meth = 0; + BOOL is_exception = NO; + /* Type qualifier flags; see . */ + unsigned flags; + /* Which argument number are we processing now? */ + int argnum; + /* 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; + NSInvocation *inv; + /* Signature information */ + NSMethodSignature *sig; + const char *encoded_types = forward_type; - /* Make sure we successfully got the method type, and that its - types match the ENCODED_TYPES. */ - NSCParameterAssert (type); - if (GSSelectorTypesMatch(encoded_types, type) == NO) - { - [NSException raise: NSInvalidArgumentException - format: @"NSConection types (%s / %s) missmatch for %s", - encoded_types, type, GSNameFromSelector(selector)]; - } + etmptype = encoded_types; - sig = [NSMethodSignature signatureWithObjCTypes: type]; - inv = [[NSInvocation alloc] initWithMethodSignature: sig]; - ctxt.objToFree = inv; + ctxt.encoder = aRmc; - tmptype = objc_skip_argspec (type); - etmptype = objc_skip_argspec (etmptype); - [inv setTarget: object]; + /* Decode the object, (which is always the first argument to a method). */ + [aRmc decodeValueOfObjCType: @encode(id) at: &object]; - tmptype = objc_skip_argspec (tmptype); - etmptype = objc_skip_argspec (etmptype); - [inv setSelector: selector]; + /* Decode the selector, (which is always the second argument to a method). */ + /* xxx @encode(SEL) produces "^v" in gcc 2.5.8. It should be ":" */ + [aRmc decodeValueOfObjCType: @encode(SEL) at: &selector]; - - /* Step TMPTYPE and ETMPTYPE in lock-step through their - method type strings. */ - - for (tmptype = objc_skip_argspec (tmptype), - etmptype = objc_skip_argspec (etmptype), argnum = 2; - *tmptype != '\0'; - tmptype = objc_skip_argspec (tmptype), - etmptype = objc_skip_argspec (etmptype), argnum++) - { - void *datum; - - /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */ - flags = objc_get_type_qualifiers (etmptype); - /* Skip over the type qualifiers, so now TYPE is pointing directly - at the char corresponding to the argument's type, as defined - in */ - tmptype = objc_skip_type_qualifiers(tmptype); - - /* Decide how, (or whether or not), to decode the argument - depending on its FLAGS and TMPTYPE. Only the first two cases - involve parameters that may potentially be passed by - reference, and thus only the first two may change the value - of OUT_PARAMETERS. *** Note: This logic must match exactly - the code in cifframe_dissect_call(); that function should - encode exactly what we decode here. *** */ - - switch (*tmptype) + /* Get the "selector type" for this method. The "selector type" is + a string that lists the return and argument types, and also + indicates in which registers and where on the stack the arguments + should be placed before the method call. The selector type + string we get here should have the same argument and return types + as the ENCODED_TYPES string, but it will have different register + and stack locations if the ENCODED_TYPES came from a machine of a + different architecture. */ + if (GSObjCIsClass(object)) { - case _C_CHARPTR: - /* Handle a (char*) argument. */ - /* If the char* is qualified as an OUT parameter, or if it - not explicitly qualified as an IN parameter, then we will - have to get this char* again after the method is run, - because the method may have changed it. Set - OUT_PARAMETERS accordingly. */ - if ((flags & _F_OUT) || !(flags & _F_IN)) - out_parameters = YES; - /* If the char* is qualified as an IN parameter, or not - explicity qualified as an OUT parameter, then decode it. - Note: the decoder allocates memory for holding the - string, and it is also responsible for making sure that - the memory gets freed eventually, (usually through the - autorelease of NSData object). */ - if ((flags & _F_IN) || !(flags & _F_OUT)) - { - datum = alloca (sizeof(char*)); - [aRmc decodeValueOfObjCType: tmptype at: datum]; - [inv setArgument: datum atIndex: argnum]; - } - break; - - case _C_PTR: - /* If the pointer's value is qualified as an OUT parameter, - or if it not explicitly qualified as an IN parameter, - then we will have to get the value pointed to again after - the method is run, because the method may have changed - it. Set OUT_PARAMETERS accordingly. */ - if ((flags & _F_OUT) || !(flags & _F_IN)) - out_parameters = YES; - - /* 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++; - /* 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)) - { - datum = alloca (objc_sizeof_type (tmptype)); - [aRmc decodeValueOfObjCType: tmptype at: datum]; - [inv setArgument: &datum atIndex: argnum]; - } - break; - - default: - datum = alloca (objc_sizeof_type (tmptype)); - if (*tmptype == _C_ID) - { - *(id*)datum = [aRmc decodeObject]; - } - else - { - [aRmc decodeValueOfObjCType: tmptype at: datum]; - } - [inv setArgument: datum atIndex: argnum]; + meth = GSGetMethod(object, selector, NO, YES); } - } - - /* Stop using the decoder. - */ - [self _doneInRmc: aRmc]; - ctxt.decoder = nil; - - /* Invoke the method! */ - [inv invoke]; - - /* 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 ([self isValid] == NO) - { - return; - } - - /* 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. - */ - aRmc = [self _makeOutRmc: ctxt.seq generate: 0 reply: NO]; - ctxt.encoder = aRmc; - [aRmc encodeValueOfObjCType: @encode(BOOL) at: &is_exception]; - - /* Encode the return value and pass-by-reference values, if there - are any. This logic must match exactly that in - cifframe_build_return(). */ - /* OUT_PARAMETERS should be true here in exactly the same - situations as it was true in cifframe_dissect_call(). */ - - /* Get the qualifier type of the return value. */ - flags = objc_get_type_qualifiers (encoded_types); - /* Get the return type; store it our two temporary char*'s. */ - etmptype = objc_skip_type_qualifiers (encoded_types); - tmptype = objc_skip_type_qualifiers (type); - - /* Only encode return values if there is a non-void return value, - a non-oneway void return value, or if there are values that were - passed by reference. */ - - if (*tmptype == _C_VOID) - { - if ((flags & _F_ONEWAY) == 0) + else if (GSObjCIsInstance(object)) { - int dummy = 0; - - [aRmc encodeValueOfObjCType: @encode(int) at: (void*)&dummy]; - } - /* No return value to encode; do nothing. */ - } - else - { - void *datum; - - if (*tmptype == _C_PTR) - { - /* The argument is a pointer to something; increment TYPE - so we can see what it is a pointer to. */ - tmptype++; - datum = alloca (objc_sizeof_type (tmptype)); + meth = GSGetMethod(GSObjCClass(object), selector, YES, YES); } else { - datum = alloca (objc_sizeof_type (tmptype)); + [NSException raise: NSInvalidArgumentException + format: @"decoded object %p is invalid", object]; } - [inv getReturnValue: datum]; - [aRmc encodeValueOfObjCType: tmptype at: datum]; - } + + if (meth != 0) + { + type = meth->method_types; + } + else + { + NSDebugLog(@"Local object <%p %s> doesn't implement: %s directly. " + @"Will search for arbitrary signature.", + object, + GSNameFromClass(GSObjCIsClass(object) + ? object : (id)GSObjCClass(object)), + GSNameFromSelector(selector)); + type = GSTypesFromSelector(selector); + } + + /* Make sure we successfully got the method type, and that its + types match the ENCODED_TYPES. */ + NSCParameterAssert (type); + if (GSSelectorTypesMatch(encoded_types, type) == NO) + { + [NSException raise: NSInvalidArgumentException + format: @"NSConection types (%s / %s) missmatch for %s", + encoded_types, type, GSNameFromSelector(selector)]; + } + + sig = [NSMethodSignature signatureWithObjCTypes: type]; + inv = [[NSInvocation alloc] initWithMethodSignature: sig]; + ctxt.objToFree = inv; + + tmptype = objc_skip_argspec (type); + etmptype = objc_skip_argspec (etmptype); + [inv setTarget: object]; + + tmptype = objc_skip_argspec (tmptype); + etmptype = objc_skip_argspec (etmptype); + [inv setSelector: selector]; - /* Encode the values returned by reference. Note: this logic - must match exactly the code in cifframe_build_return(); that - function should decode exactly what we encode here. */ + /* Step TMPTYPE and ETMPTYPE in lock-step through their + method type strings. */ - if (out_parameters) - { - /* Step through all the arguments, finding the ones that were - passed by reference. */ for (tmptype = objc_skip_argspec (tmptype), - argnum = 0, - etmptype = objc_skip_argspec (etmptype); + etmptype = objc_skip_argspec (etmptype), argnum = 2; *tmptype != '\0'; tmptype = objc_skip_argspec (tmptype), - argnum++, - etmptype = objc_skip_argspec (etmptype)) + etmptype = objc_skip_argspec (etmptype), argnum++) { + void *datum; + /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */ - flags = objc_get_type_qualifiers(etmptype); + flags = objc_get_type_qualifiers (etmptype); /* Skip over the type qualifiers, so now TYPE is pointing directly at the char corresponding to the argument's type, as defined in */ - tmptype = objc_skip_type_qualifiers (tmptype); + tmptype = objc_skip_type_qualifiers(tmptype); - /* Decide how, (or whether or not), to encode the argument - depending on its FLAGS and TMPTYPE. */ - if (((flags & _F_OUT) || !(flags & _F_IN)) - && (*tmptype == _C_PTR || *tmptype == _C_CHARPTR)) + /* Decide how, (or whether or not), to decode the argument + depending on its FLAGS and TMPTYPE. Only the first two cases + involve parameters that may potentially be passed by + reference, and thus only the first two may change the value + of OUT_PARAMETERS. *** Note: This logic must match exactly + the code in cifframe_dissect_call(); that function should + encode exactly what we decode here. *** */ + + switch (*tmptype) { - void *datum; + case _C_CHARPTR: + /* Handle a (char*) argument. */ + /* If the char* is qualified as an OUT parameter, or if it + not explicitly qualified as an IN parameter, then we will + have to get this char* again after the method is run, + because the method may have changed it. Set + OUT_PARAMETERS accordingly. */ + if ((flags & _F_OUT) || !(flags & _F_IN)) + out_parameters = YES; + /* If the char* is qualified as an IN parameter, or not + explicity qualified as an OUT parameter, then decode it. + Note: the decoder allocates memory for holding the + string, and it is also responsible for making sure that + the memory gets freed eventually, (usually through the + autorelease of NSData object). */ + if ((flags & _F_IN) || !(flags & _F_OUT)) + { + datum = alloca (sizeof(char*)); + [aRmc decodeValueOfObjCType: tmptype at: datum]; + [inv setArgument: datum atIndex: argnum]; + } + break; - if (*tmptype == _C_PTR) + case _C_PTR: + /* If the pointer's value is qualified as an OUT parameter, + or if it not explicitly qualified as an IN parameter, + then we will have to get the value pointed to again after + the method is run, because the method may have changed + it. Set OUT_PARAMETERS accordingly. */ + if ((flags & _F_OUT) || !(flags & _F_IN)) + out_parameters = YES; + + /* 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++; + /* 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)) + { + datum = alloca (objc_sizeof_type (tmptype)); + [aRmc decodeValueOfObjCType: tmptype at: datum]; + [inv setArgument: &datum atIndex: argnum]; + } + break; + + default: + datum = alloca (objc_sizeof_type (tmptype)); + if (*tmptype == _C_ID) + { + *(id*)datum = [aRmc decodeObject]; + } + else + { + [aRmc decodeValueOfObjCType: tmptype at: datum]; + } + [inv setArgument: datum atIndex: argnum]; + } + } + + /* Stop using the decoder. + */ + [self _doneInRmc: aRmc]; + ctxt.decoder = nil; + + /* Invoke the method! */ + [inv invoke]; + + /* 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 ([self isValid] == NO) + { + return; + } + + /* 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. + */ + aRmc = [self _makeOutRmc: ctxt.seq generate: 0 reply: NO]; + ctxt.encoder = aRmc; + [aRmc encodeValueOfObjCType: @encode(BOOL) at: &is_exception]; + + /* Encode the return value and pass-by-reference values, if there + are any. This logic must match exactly that in + cifframe_build_return(). */ + /* OUT_PARAMETERS should be true here in exactly the same + situations as it was true in cifframe_dissect_call(). */ + + /* Get the qualifier type of the return value. */ + flags = objc_get_type_qualifiers (encoded_types); + /* Get the return type; store it our two temporary char*'s. */ + etmptype = objc_skip_type_qualifiers (encoded_types); + tmptype = objc_skip_type_qualifiers (type); + + /* Only encode return values if there is a non-void return value, + a non-oneway void return value, or if there are values that were + passed by reference. */ + + if (*tmptype == _C_VOID) + { + if ((flags & _F_ONEWAY) == 0) + { + int dummy = 0; + + [aRmc encodeValueOfObjCType: @encode(int) at: (void*)&dummy]; + } + /* No return value to encode; do nothing. */ + } + else + { + void *datum; + + if (*tmptype == _C_PTR) + { + /* The argument is a pointer to something; increment TYPE + so we can see what it is a pointer to. */ + tmptype++; + datum = alloca (objc_sizeof_type (tmptype)); + } + else + { + datum = alloca (objc_sizeof_type (tmptype)); + } + [inv getReturnValue: datum]; + [aRmc encodeValueOfObjCType: tmptype at: datum]; + } + + + /* Encode the values returned by reference. Note: this logic + must match exactly the code in cifframe_build_return(); that + function should decode exactly what we encode here. */ + + if (out_parameters) + { + /* Step through all the arguments, finding the ones that were + passed by reference. */ + for (tmptype = objc_skip_argspec (tmptype), + argnum = 0, + etmptype = objc_skip_argspec (etmptype); + *tmptype != '\0'; + tmptype = objc_skip_argspec (tmptype), + argnum++, + etmptype = objc_skip_argspec (etmptype)) + { + /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */ + flags = objc_get_type_qualifiers(etmptype); + /* Skip over the type qualifiers, so now TYPE is pointing directly + at the char corresponding to the argument's type, as defined + in */ + tmptype = objc_skip_type_qualifiers (tmptype); + + /* Decide how, (or whether or not), to encode the argument + depending on its FLAGS and TMPTYPE. */ + if (((flags & _F_OUT) || !(flags & _F_IN)) + && (*tmptype == _C_PTR || *tmptype == _C_CHARPTR)) { - /* 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.*/ - ++tmptype; - [inv getArgument: &datum atIndex: argnum]; - [aRmc encodeValueOfObjCType: tmptype at: datum]; - } - else if (*tmptype == _C_CHARPTR) - { - datum = alloca (sizeof (char*)); - [inv getArgument: datum atIndex: argnum]; - [aRmc encodeValueOfObjCType: tmptype at: datum]; + void *datum; + + 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.*/ + ++tmptype; + [inv getArgument: &datum atIndex: argnum]; + [aRmc encodeValueOfObjCType: tmptype at: datum]; + } + else if (*tmptype == _C_CHARPTR) + { + datum = alloca (sizeof (char*)); + [inv getArgument: datum atIndex: argnum]; + [aRmc encodeValueOfObjCType: tmptype at: datum]; + } } } } + ctxt.objToFree = nil; + [inv release]; + [self _sendOutRmc: aRmc type: METHOD_REPLY]; + ctxt.encoder = nil; } - ctxt.objToFree = nil; - [inv release]; - [self _sendOutRmc: aRmc type: METHOD_REPLY]; - ctxt.encoder = nil; -} -#elif 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]; - } } NS_HANDLER { diff --git a/Source/callframe.h b/Source/callframe.h index 17e76da3f..117e2b255 100644 --- a/Source/callframe.h +++ b/Source/callframe.h @@ -44,13 +44,5 @@ 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 (DOContext *ctxt, - void(*decoder)(DOContext*), - void(*encoder)(DOContext*)); -extern void callframe_build_return (NSInvocation *inv, - const char *type, - BOOL out_parameters, - void(*decoder)(DOContext*), - DOContext* ctxt); #endif diff --git a/Source/callframe.m b/Source/callframe.m index d56892de8..6e1091875 100644 --- a/Source/callframe.m +++ b/Source/callframe.m @@ -158,626 +158,3 @@ callframe_arg_addr(callframe_t *cframe, int index) return cframe->args[index]; } - - -/* Ugly hack to make it easier to invoke a method from outside - an NSInvocation class. Hopefully simplication of NSConnection - could remove this hack */ -typedef struct _NSInvocation_t { - @defs(NSInvocation) -} NSInvocation_t; - -/*-------------------------------------------------------------------------*/ -/* Functions for handling sending and receiving messages accross a - connection -*/ - -/* callframe_do_call() - - 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. - - 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. callframe_do_call() uses this information to determine - which variable types it should decode. - - 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 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. - - - DECODER should be a pointer to a function that obtains the method's - argument values. For example: - - void my_decoder (DOContext *ctxt) - - 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 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 - business, then DECODER is responsible for making sure that the - memory will get free eventually. For example, if DECODER uses - -decodeValueOfCType:at:withName: to decode a char* string, you - should remember that -decodeValueOfCType:at:withName: malloc's - new memory to hold the string, and DECODER should autorelease the - malloc'ed pointer, using the NSData class. - - - 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 (DOContext *ctxt) - - 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 ctxt->datum wherever the user wants to - record the ARGNUM'th return value. - -*/ - -void -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. */ - const char *type; - /* A pointer into the local variable TYPE string. */ - const char *tmptype; - /* A pointer into the argument ENCODED_TYPES string. */ - const char *etmptype; - /* The target object that will receive the message. */ - id object; - /* The selector for the message we're sending to the TARGET. */ - SEL selector; - /* The OBJECT's Method(_t) pointer for the SELECTOR. */ - GSMethod meth; - /* The OBJECT's implementation of the SELECTOR. */ - IMP method_implementation; - /* Type qualifier flags; see . */ - unsigned flags; - /* Which argument number are we processing now? */ - int argnum; - /* The cif information for calling the method */ - callframe_t *cframe; - /* 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; - /* A dummy invocation to pass to the function that invokes our method */ - NSInvocation_t *inv; - /* Signature information */ - NSMethodSignature *sig; - void *retval; - const char *encoded_types = ctxt->type; - - /* Decode the object, (which is always the first argument to a method), - into the local variable OBJECT. */ - 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 ":" */ - ctxt->type = @encode(SEL); - ctxt->datum = &selector; - (*decoder) (ctxt); - NSCParameterAssert (selector); - - /* Get the "selector type" for this method. The "selector type" is - a string that lists the return and argument types, and also - indicates in which registers and where on the stack the arguments - should be placed before the method call. The selector type - string we get here should have the same argument and return types - as the ENCODED_TYPES string, but it will have different register - and stack locations if the ENCODED_TYPES came from a machine of a - different architecture. */ - if (GSObjCIsClass(object)) - { - meth = GSGetMethod(object, selector, NO, YES); - } - else if (GSObjCIsInstance(object)) - { - meth = GSGetMethod(GSObjCClass(object), selector, YES, YES); - } - else - { - [NSException raise: NSInvalidArgumentException - format: @"decoded object %p is invalid", object]; - } - - if (meth != 0) - { - type = meth->method_types; - } - else - { - NSDebugLog(@"Local object <%p %s> doesn't implement: %s directly. " - @"Will search for arbitrary signature.", - object, - GSNameFromClass(GSObjCIsClass(object) - ? object : GSObjCClass(object)), - GSNameFromSelector(selector)); - type = GSTypesFromSelector(selector); - } - - /* Make sure we successfully got the method type, and that its - types match the ENCODED_TYPES. */ - NSCParameterAssert (type); - if (GSSelectorTypesMatch(encoded_types, type) == NO) - { - [NSException raise: NSInvalidArgumentException - format: @"callframe_do_call types (%s / %s) missmatch for %s", - encoded_types, type, GSNameFromSelector(selector)]; - } - - /* Build the cif frame */ - sig = [NSMethodSignature signatureWithObjCTypes: type]; - cframe = callframe_from_info([sig methodInfo], [sig numberOfArguments], - &retval); - ctxt->datToFree = cframe; - - /* Put OBJECT and SELECTOR into the ARGFRAME. */ - - /* Initialize our temporary pointers into the method type strings. */ - tmptype = objc_skip_argspec (type); - etmptype = objc_skip_argspec (encoded_types); - NSCParameterAssert (*tmptype == _C_ID); - /* Put the target object there. */ - callframe_set_arg(cframe, 0, &object, sizeof(id)); - /* Get a pointer into ARGFRAME, pointing to the location where the - second argument is to be stored. */ - tmptype = objc_skip_argspec (tmptype); - etmptype = objc_skip_argspec(etmptype); - NSCParameterAssert (*tmptype == _C_SEL); - /* Put the selector there. */ - callframe_set_arg(cframe, 1, &selector, sizeof(SEL)); - - - /* Decode arguments after OBJECT and SELECTOR, and put them into the - ARGFRAME. Step TMPTYPE and ETMPTYPE in lock-step through their - method type strings. */ - - for (tmptype = objc_skip_argspec (tmptype), - etmptype = objc_skip_argspec (etmptype), argnum = 2; - *tmptype != '\0'; - tmptype = objc_skip_argspec (tmptype), - etmptype = objc_skip_argspec (etmptype), argnum++) - { - /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */ - flags = objc_get_type_qualifiers (etmptype); - /* Skip over the type qualifiers, so now TYPE is pointing directly - at the char corresponding to the argument's type, as defined - in */ - tmptype = objc_skip_type_qualifiers(tmptype); - - /* - * 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 - involve parameters that may potentially be passed by - reference, and thus only the first two may change the value - of OUT_PARAMETERS. *** Note: This logic must match exactly - the code in callframe_dissect_call(); that function should - encode exactly what we decode here. *** */ - - switch (*tmptype) - { - - case _C_CHARPTR: - /* Handle a (char*) argument. */ - /* If the char* is qualified as an OUT parameter, or if it - not explicitly qualified as an IN parameter, then we will - have to get this char* again after the method is run, - because the method may have changed it. Set - OUT_PARAMETERS accordingly. */ - if ((flags & _F_OUT) || !(flags & _F_IN)) - out_parameters = YES; - /* If the char* is qualified as an IN parameter, or not - explicity qualified as an OUT parameter, then decode it. - Note: the decoder allocates memory for holding the - string, and it is also responsible for making sure that - the memory gets freed eventually, (usually through the - autorelease of NSData object). */ - if ((flags & _F_IN) || !(flags & _F_OUT)) - (*decoder) (ctxt); - - break; - - case _C_PTR: - /* If the pointer's value is qualified as an OUT parameter, - or if it not explicitly qualified as an IN parameter, - then we will have to get the value pointed to again after - the method is run, because the method may have changed - it. Set OUT_PARAMETERS accordingly. */ - if ((flags & _F_OUT) || !(flags & _F_IN)) - out_parameters = YES; - - /* 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: - /* Handle arguments of all other types. */ - /* NOTE FOR OBJECTS: Unlike [Decoder decodeObjectAt:..], - this function does not generate a reference to the - object; the object may be autoreleased; if the method - wants to keep a reference to the object, it will have to - -retain it. */ - (*decoder) (ctxt); - } - } - /* End of the for () loop that enumerates the method's arguments. */ - ctxt->type = 0; - ctxt->datum = 0; - (*decoder) (ctxt); - - - /* Invoke the method! */ - - /* Find the target object's implementation of this selector. */ - 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 encode any pass-by-reference info */ - inv = (NSInvocation_t *)NSAllocateObject([NSInvocation class], 0, - NSDefaultMallocZone()); - inv->_retval = retval; - inv->_selector = selector; - inv->_cframe = cframe; - inv->_info = [sig methodInfo]; - inv->_numArgs = [sig numberOfArguments]; - ctxt->objToFree = (id)inv; - GSFFCallInvokeWithTargetAndImp((NSInvocation *)inv, object, - method_implementation); - ctxt->objToFree = nil; - NSDeallocateObject((NSInvocation *)inv); - - /* Encode the return value and pass-by-reference values, if there - are any. This logic must match exactly that in - callframe_build_return(). */ - /* OUT_PARAMETERS should be true here in exactly the same - situations as it was true in callframe_dissect_call(). */ - - /* Get the qualifier type of the return value. */ - flags = objc_get_type_qualifiers (encoded_types); - /* Get the return type; store it our two temporary char*'s. */ - etmptype = objc_skip_type_qualifiers (encoded_types); - tmptype = objc_skip_type_qualifiers (type); - - /* Only encode return values if there is a non-void return value, - 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. */ - if (*tmptype == _C_VOID) - { - if ((flags & _F_ONEWAY) == 0) - { - int dummy = 0; - - ctxt->type = @encode(int); - ctxt->datum = (void*)&dummy; - (*encoder) (ctxt); - } - /* No return value to encode; do nothing. */ - } - 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++; - ctxt->type = tmptype; - ctxt->datum = *(void**)retval; - } - else - { - ctxt->type = tmptype; - ctxt->datum = retval; - } - /* Encode the value that was pointed to. */ - (*encoder) (ctxt); - } - - - /* Encode the values returned by reference. Note: this logic - must match exactly the code in callframe_build_return(); that - function should decode exactly what we encode here. */ - - if (out_parameters) - { - /* Step through all the arguments, finding the ones that were - passed by reference. */ - for (tmptype = objc_skip_argspec (tmptype), - argnum = 0, - etmptype = objc_skip_argspec (etmptype); - *tmptype != '\0'; - tmptype = objc_skip_argspec (tmptype), - argnum++, - etmptype = objc_skip_argspec (etmptype)) - { - /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */ - flags = objc_get_type_qualifiers(etmptype); - /* Skip over the type qualifiers, so now TYPE is pointing directly - at the char corresponding to the argument's type, as defined - in */ - tmptype = objc_skip_type_qualifiers (tmptype); - - /* Decide how, (or whether or not), to encode the argument - depending on its FLAGS and TMPTYPE. */ - 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) - { - /* 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); - } - } - } -#if !GS_WITH_GC - NSZoneFree(NSDefaultMallocZone(), ctxt->datToFree); -#endif - ctxt->datToFree = 0; - - return; -} - -/* callframe_build_return() - - This function decodes the values returned from a method call, - sets up the invocation with the return value, and updates the - pass-by-reference arguments. - - The callback function is finally called with the 'type' set to a null pointer - to tell it that the return value and all return parameters have been - dealt with. This permits the function to do any tidying up necessary. */ - -void -callframe_build_return (NSInvocation *inv, - const char *type, - BOOL out_parameters, - void(*decoder)(DOContext *ctxt), - DOContext *ctxt) -{ - /* Which argument number are we processing now? */ - int argnum; - /* Type qualifier flags; see . */ - int flags; - /* A pointer into the TYPE string. */ - const char *tmptype; - /* Points at individual arguments. */ - void *datum; - const char *rettype; - /* A pointer to the memory holding the return value of the method. */ - void *retval; - /* Storage for the argument information */ - callframe_t *cframe; - /* Signature information */ - NSMethodSignature *sig; - - /* Build the call frame */ - sig = [NSMethodSignature signatureWithObjCTypes: type]; - cframe = callframe_from_info([sig methodInfo], [sig numberOfArguments], - &retval); - ctxt->datToFree = cframe; - - /* Get the return type qualifier flags, and the return type. */ - flags = objc_get_type_qualifiers(type); - tmptype = objc_skip_type_qualifiers(type); - rettype = tmptype; - - /* Decode the return value and pass-by-reference values, if there - are any. OUT_PARAMETERS should be the value returned by - callframe_dissect_call(). */ - if (out_parameters || *tmptype != _C_VOID || (flags & _F_ONEWAY) == 0) - /* xxx What happens with method declared "- (oneway) foo: (out int*)ip;" */ - /* 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 retval. */ - if (*tmptype != _C_VOID || (flags & _F_ONEWAY) == 0) - { - ctxt->type = tmptype; - ctxt->datum = retval; - ctxt->flags = flags; - - switch (*tmptype) - { - case _C_PTR: - { - 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. */ -#if GS_WITH_GC - *(void**)retval = - NSAllocateCollectable(retLength, NSScannedOption); -#else - *(void**)retval = - NSZoneCalloc(NSDefaultMallocZone(), retLength, 1); - /* We are responsible for making sure this memory gets free'd - eventually. Ask NSData class to autorelease it. */ - [NSData dataWithBytesNoCopy: *(void**)retval - length: retLength]; -#endif - 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) (ctxt); - break; - - case _C_FLT: - case _C_DBL: - (*decoder) (ctxt); - break; - - case _C_VOID: - { - ctxt->type = @encode(int); - ctxt->flags = 0; - (*decoder) (ctxt); - } - break; - - default: - (*decoder) (ctxt); - } - } - [inv setReturnValue: retval]; - - /* Decode the values returned by reference. Note: this logic - must match exactly the code in callframe_do_call(); that - function should decode exactly what we encode here. */ - - if (out_parameters) - { - /* Step through all the arguments, finding the ones that were - passed by reference. */ - for (tmptype = objc_skip_argspec (tmptype), argnum = 0; - *tmptype != '\0'; - tmptype = objc_skip_argspec (tmptype), argnum++) - { - /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */ - flags = objc_get_type_qualifiers(tmptype); - /* Skip over the type qualifiers, so now TYPE is - pointing directly at the char corresponding to the - argument's type, as defined in */ - tmptype = objc_skip_type_qualifiers(tmptype); - - /* Decide how, (or whether or not), to encode the - 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))) - { - void *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.*/ - tmptype++; - ctxt->type = tmptype; - - /* Use the original pointer to find the buffer - * to store the returned data */ - [inv getArgument: &ptr atIndex: argnum]; - ctxt->datum = ptr; - - (*decoder) (ctxt); - } - 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. */ - (*decoder) (ctxt); - [inv setArgument: datum atIndex: argnum]; - } - } - } - ctxt->type = 0; - ctxt->datum = 0; - (*decoder) (ctxt); /* Tell it we have finished. */ - } - - if (ctxt->datToFree != 0) - { -#if !GS_WITH_GC - NSZoneFree(NSDefaultMallocZone(), ctxt->datToFree); -#endif - ctxt->datToFree = 0; - } - - return; -} - diff --git a/Source/cifframe.h b/Source/cifframe.h index 81ee4f790..02a8ef1ee 100644 --- a/Source/cifframe.h +++ b/Source/cifframe.h @@ -61,12 +61,4 @@ extern void *cifframe_arg_addr(cifframe_t *cframe, int index); extern BOOL cifframe_decode_arg (const char *type, void* buffer); extern BOOL cifframe_encode_arg (const char *type, void* buffer); -extern void cifframe_do_call (DOContext *ctxt, - void(*decoder)(DOContext*), - void(*encoder)(DOContext*)); -extern void cifframe_build_return (NSInvocation *inv, - const char *type, - BOOL out_parameters, - void(*decoder)(DOContext*), - DOContext* ctxt); #endif diff --git a/Source/cifframe.m b/Source/cifframe.m index 96429f8d1..2658cf544 100644 --- a/Source/cifframe.m +++ b/Source/cifframe.m @@ -504,14 +504,6 @@ cifframe_type(const char *typePtr, const char **advance) return ftype; } - -/* Ugly hack to make it easier to invoke a method from outside - an NSInvocation class. Hopefully simplication of NSConnection - could remove this hack */ -typedef struct _NSInvocation_t { - @defs(NSInvocation) -} NSInvocation_t; - /*-------------------------------------------------------------------------*/ /* Functions for handling sending and receiving messages accross a connection @@ -577,612 +569,3 @@ cifframe_encode_arg (const char *type, void* buffer) return YES; } -/* cifframe_do_call() - - This function decodes the arguments of method call, builds a - cifframe, and invokes the method using GSFFIInvokeWithTargetAndImp - then it encodes the return value and any pass-by-reference arguments. - - 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. cifframe_do_call() uses this information to determine - which variable types it should decode. - - 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 type info may come from a machine - of a different architecture. Having the original type info is - good, just in case the machine running cifframe_do_call() has some - slightly different qualifiers. Using different qualifiers for - encoding and decoding could lead to massive confusion. - - - DECODER should be a pointer to a function that obtains the method's - argument values. For example: - - void my_decoder (DOContext *ctxt) - - CTXT contains the context information for the item to decode. - - cifframe_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 ctxt->datum. - cifframe_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 - business, then DECODER is responsible for making sure that the - memory will get free eventually. For example, if DECODER uses - -decodeValueOfCType:at:withName: to decode a char* string, you - should remember that -decodeValueOfCType:at:withName: malloc's - new memory to hold the string, and DECODER should autorelease the - malloc'ed pointer, using the NSData class. - - - 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 (DOContext *ctxt) - - CTXT contains the context information for the item to encode. - - cifframe_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 ctxt->datum wherever the user wants to - record the ARGNUM'th return value. - -*/ - -void -cifframe_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. */ - const char *type; - /* A pointer into the local variable TYPE string. */ - const char *tmptype; - /* A pointer into the argument ENCODED_TYPES string. */ - const char *etmptype; - /* The target object that will receive the message. */ - id object; - /* The selector for the message we're sending to the TARGET. */ - SEL selector; - /* The OBJECT's Method(_t) pointer for the SELECTOR. */ - GSMethod meth = 0; - /* The OBJECT's implementation of the SELECTOR. */ - IMP method_implementation; - /* Type qualifier flags; see . */ - unsigned flags; - /* Which argument number are we processing now? */ - int argnum; - /* The cif information for calling the method */ - cifframe_t *cframe; - /* 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; - /* A dummy invocation to pass to the function that invokes our method */ - NSInvocation_t *inv; - /* Signature information */ - NSMethodSignature *sig; - void *retval; - const char *encoded_types = ctxt->type; - - /* Decode the object, (which is always the first argument to a method), - into the local variable OBJECT. */ - 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 ":" */ - ctxt->type = @encode(SEL); - ctxt->datum = &selector; - (*decoder) (ctxt); - NSCParameterAssert (selector); - - /* Get the "selector type" for this method. The "selector type" is - a string that lists the return and argument types, and also - indicates in which registers and where on the stack the arguments - should be placed before the method call. The selector type - string we get here should have the same argument and return types - as the ENCODED_TYPES string, but it will have different register - and stack locations if the ENCODED_TYPES came from a machine of a - different architecture. */ - if (GSObjCIsClass(object)) - { - meth = GSGetMethod(object, selector, NO, YES); - } - else if (GSObjCIsInstance(object)) - { - meth = GSGetMethod(GSObjCClass(object), selector, YES, YES); - } - else - { - [NSException raise: NSInvalidArgumentException - format: @"decoded object %p is invalid", object]; - } - - if (meth != 0) - { - type = meth->method_types; - } - else - { - NSDebugLog(@"Local object <%p %s> doesn't implement: %s directly. " - @"Will search for arbitrary signature.", - object, - GSNameFromClass(GSObjCIsClass(object) - ? object : (id)GSObjCClass(object)), - GSNameFromSelector(selector)); - type = GSTypesFromSelector(selector); - } - - /* Make sure we successfully got the method type, and that its - types match the ENCODED_TYPES. */ - NSCParameterAssert (type); - if (GSSelectorTypesMatch(encoded_types, type) == NO) - { - [NSException raise: NSInvalidArgumentException - format: @"cifframe_do_call types (%s / %s) missmatch for %s", - encoded_types, type, GSNameFromSelector(selector)]; - } - - /* Build the cif frame */ - sig = [NSMethodSignature signatureWithObjCTypes: type]; - cframe = cifframe_from_info([sig methodInfo], [sig numberOfArguments], - &retval); - ctxt->datToFree = cframe; - - /* Put OBJECT and SELECTOR into the ARGFRAME. */ - - /* Initialize our temporary pointers into the method type strings. */ - tmptype = objc_skip_argspec (type); - etmptype = objc_skip_argspec (encoded_types); - NSCParameterAssert (*tmptype == _C_ID); - /* Put the target object there. */ - cifframe_set_arg(cframe, 0, &object, sizeof(id)); - /* Get a pointer into ARGFRAME, pointing to the location where the - second argument is to be stored. */ - tmptype = objc_skip_argspec (tmptype); - etmptype = objc_skip_argspec(etmptype); - NSCParameterAssert (*tmptype == _C_SEL); - /* Put the selector there. */ - cifframe_set_arg(cframe, 1, &selector, sizeof(SEL)); - - - /* Decode arguments after OBJECT and SELECTOR, and put them into the - ARGFRAME. Step TMPTYPE and ETMPTYPE in lock-step through their - method type strings. */ - - for (tmptype = objc_skip_argspec (tmptype), - etmptype = objc_skip_argspec (etmptype), argnum = 2; - *tmptype != '\0'; - tmptype = objc_skip_argspec (tmptype), - etmptype = objc_skip_argspec (etmptype), argnum++) - { - /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */ - flags = objc_get_type_qualifiers (etmptype); - /* Skip over the type qualifiers, so now TYPE is pointing directly - at the char corresponding to the argument's type, as defined - in */ - tmptype = objc_skip_type_qualifiers(tmptype); - - /* - * Setup information in context. - */ - ctxt->datum = cifframe_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 - involve parameters that may potentially be passed by - reference, and thus only the first two may change the value - of OUT_PARAMETERS. *** Note: This logic must match exactly - the code in cifframe_dissect_call(); that function should - encode exactly what we decode here. *** */ - - switch (*tmptype) - { - - case _C_CHARPTR: - /* Handle a (char*) argument. */ - /* If the char* is qualified as an OUT parameter, or if it - not explicitly qualified as an IN parameter, then we will - have to get this char* again after the method is run, - because the method may have changed it. Set - OUT_PARAMETERS accordingly. */ - if ((flags & _F_OUT) || !(flags & _F_IN)) - out_parameters = YES; - /* If the char* is qualified as an IN parameter, or not - explicity qualified as an OUT parameter, then decode it. - Note: the decoder allocates memory for holding the - string, and it is also responsible for making sure that - the memory gets freed eventually, (usually through the - autorelease of NSData object). */ - if ((flags & _F_IN) || !(flags & _F_OUT)) - (*decoder) (ctxt); - - break; - - case _C_PTR: - /* If the pointer's value is qualified as an OUT parameter, - or if it not explicitly qualified as an IN parameter, - then we will have to get the value pointed to again after - the method is run, because the method may have changed - it. Set OUT_PARAMETERS accordingly. */ - if ((flags & _F_OUT) || !(flags & _F_IN)) - out_parameters = YES; - - /* 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: - /* Handle arguments of all other types. */ - /* NOTE FOR OBJECTS: Unlike [Decoder decodeObjectAt:..], - this function does not generate a reference to the - object; the object may be autoreleased; if the method - wants to keep a reference to the object, it will have to - -retain it. */ - (*decoder) (ctxt); - } - } - /* End of the for () loop that enumerates the method's arguments. */ - ctxt->type = 0; - ctxt->datum = 0; - (*decoder) (ctxt); - - - /* Invoke the method! */ - - /* Find the target object's implementation of this selector. */ - 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 encode any pass-by-reference info */ - inv = (NSInvocation_t *)NSAllocateObject([NSInvocation class], 0, - NSDefaultMallocZone()); - inv->_retval = retval; - inv->_selector = selector; - inv->_cframe = cframe; - inv->_info = [sig methodInfo]; - inv->_numArgs = [sig numberOfArguments]; - ctxt->objToFree = (id)inv; - GSFFIInvokeWithTargetAndImp((NSInvocation *)inv, object, - method_implementation); - ctxt->objToFree = nil; - NSDeallocateObject((NSInvocation *)inv); - - /* Encode the return value and pass-by-reference values, if there - are any. This logic must match exactly that in - cifframe_build_return(). */ - /* OUT_PARAMETERS should be true here in exactly the same - situations as it was true in cifframe_dissect_call(). */ - - /* Get the qualifier type of the return value. */ - flags = objc_get_type_qualifiers (encoded_types); - /* Get the return type; store it our two temporary char*'s. */ - etmptype = objc_skip_type_qualifiers (encoded_types); - tmptype = objc_skip_type_qualifiers (type); - - /* Only encode return values if there is a non-void return value, - 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. */ - if (*tmptype == _C_VOID) - { - if ((flags & _F_ONEWAY) == 0) - { - int dummy = 0; - - ctxt->type = @encode(int); - ctxt->datum = (void*)&dummy; - (*encoder) (ctxt); - } - /* No return value to encode; do nothing. */ - } - 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++; - ctxt->type = tmptype; - ctxt->datum = *(void**)retval; - } - else - { - cifframe_decode_arg(tmptype, retval); - ctxt->type = tmptype; - ctxt->datum = retval; - } - /* Encode the value that was pointed to. */ - (*encoder) (ctxt); - } - - - /* Encode the values returned by reference. Note: this logic - must match exactly the code in cifframe_build_return(); that - function should decode exactly what we encode here. */ - - if (out_parameters) - { - /* Step through all the arguments, finding the ones that were - passed by reference. */ - for (tmptype = objc_skip_argspec (tmptype), - argnum = 0, - etmptype = objc_skip_argspec (etmptype); - *tmptype != '\0'; - tmptype = objc_skip_argspec (tmptype), - argnum++, - etmptype = objc_skip_argspec (etmptype)) - { - /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */ - flags = objc_get_type_qualifiers(etmptype); - /* Skip over the type qualifiers, so now TYPE is pointing directly - at the char corresponding to the argument's type, as defined - in */ - tmptype = objc_skip_type_qualifiers (tmptype); - - /* Decide how, (or whether or not), to encode the argument - depending on its FLAGS and TMPTYPE. */ - if (((flags & _F_OUT) || !(flags & _F_IN)) - && (*tmptype == _C_PTR || *tmptype == _C_CHARPTR)) - { - ctxt->flags = flags; - ctxt->datum = cifframe_arg_addr(cframe, argnum); - - 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); - } - } - } -#if !GS_WITH_GC - NSZoneFree(NSDefaultMallocZone(), ctxt->datToFree); -#endif - ctxt->datToFree = 0; - - return; -} - -/* cifframe_build_return() - - This function decodes the values returned from a method call, - sets up the invocation with the return value, and updates the - pass-by-reference arguments. - - The callback function is finally called with the 'type' set to a null pointer - to tell it that the return value and all return parameters have been - dealt with. This permits the function to do any tidying up necessary. */ - -void -cifframe_build_return (NSInvocation *inv, - const char *type, - BOOL out_parameters, - void(*decoder)(DOContext *ctxt), - DOContext *ctxt) -{ - /* Which argument number are we processing now? */ - int argnum; - /* Type qualifier flags; see . */ - int flags; - /* A pointer into the TYPE string. */ - const char *tmptype; - /* Points at individual arguments. */ - void *datum; - const char *rettype; - /* A pointer to the memory holding the return value of the method. */ - void *retval; - /* Storage for the argument information */ - cifframe_t *cframe; - /* Signature information */ - NSMethodSignature *sig; - - /* Build the cif frame */ - sig = [NSMethodSignature signatureWithObjCTypes: type]; - cframe = cifframe_from_info([sig methodInfo], [sig numberOfArguments], - &retval); - ctxt->datToFree = cframe; - - /* Get the return type qualifier flags, and the return type. */ - flags = objc_get_type_qualifiers(type); - tmptype = objc_skip_type_qualifiers(type); - rettype = tmptype; - - /* Decode the return value and pass-by-reference values, if there - are any. OUT_PARAMETERS should be the value returned by - cifframe_dissect_call(). */ - if (out_parameters || *tmptype != _C_VOID || (flags & _F_ONEWAY) == 0) - /* xxx What happens with method declared "- (oneway) foo: (out int*)ip;" */ - /* 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 retval. */ - if (*tmptype != _C_VOID || (flags & _F_ONEWAY) == 0) - { - ctxt->type = tmptype; - ctxt->datum = retval; - ctxt->flags = flags; - - switch (*tmptype) - { - case _C_PTR: - { - 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. */ -#if GS_WITH_GC - *(void**)retval = - NSAllocateCollectable(retLength, NSScannedOption); -#else - *(void**)retval = - NSZoneCalloc(NSDefaultMallocZone(), retLength, 1); - /* We are responsible for making sure this memory gets free'd - eventually. Ask NSData class to autorelease it. */ - [NSData dataWithBytesNoCopy: *(void**)retval - length: retLength]; -#endif - 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) (ctxt); - break; - - case _C_FLT: - case _C_DBL: - (*decoder) (ctxt); - break; - - case _C_VOID: - { - ctxt->type = @encode(int); - ctxt->flags = 0; - (*decoder) (ctxt); - } - break; - - default: - (*decoder) (ctxt); - } - } - [inv setReturnValue: retval]; - - /* Decode the values returned by reference. Note: this logic - must match exactly the code in cifframe_do_call(); that - function should decode exactly what we encode here. */ - - if (out_parameters) - { - /* Step through all the arguments, finding the ones that were - passed by reference. */ - for (tmptype = objc_skip_argspec (tmptype), argnum = 0; - *tmptype != '\0'; - tmptype = objc_skip_argspec (tmptype), argnum++) - { - /* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */ - flags = objc_get_type_qualifiers(tmptype); - /* Skip over the type qualifiers, so now TYPE is - pointing directly at the char corresponding to the - argument's type, as defined in */ - tmptype = objc_skip_type_qualifiers(tmptype); - - /* Decide how, (or whether or not), to encode the - argument depending on its FLAGS and TMPTYPE. */ - datum = cifframe_arg_addr(cframe, argnum); - - ctxt->type = tmptype; - ctxt->datum = datum; - ctxt->flags = flags; - - if (*tmptype == _C_PTR - && ((flags & _F_OUT) || !(flags & _F_IN))) - { - void *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.*/ - tmptype++; - ctxt->type = tmptype; - - /* Use the original pointer to find the buffer - * to store the returned data */ - [inv getArgument: &ptr atIndex: argnum]; - ctxt->datum = ptr; - - (*decoder) (ctxt); - } - 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. */ - (*decoder) (ctxt); - [inv setArgument: datum atIndex: argnum]; - } - } - } - ctxt->type = 0; - ctxt->datum = 0; - (*decoder) (ctxt); /* Tell it we have finished. */ - } - - if (ctxt->datToFree != 0) - { -#if !GS_WITH_GC - NSZoneFree(NSDefaultMallocZone(), ctxt->datToFree); -#endif - ctxt->datToFree = 0; - } - - return; -} -