1/** Implementation of GSFFIInvocation for GNUStep 2 Copyright (C) 2000 Free Software Foundation, Inc. 3 4 Written: Adam Fedor <fedor@gnu.org> 5 Date: Apr 2002 6 7 This file is part of the GNUstep Base Library. 8 9 This library is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Lesser General Public 11 License as published by the Free Software Foundation; either 12 version 2 of the License, or (at your option) any later version. 13 14 This library is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Lesser General Public License for more details. 18 19 You should have received a copy of the GNU Lesser General Public 20 License along with this library; if not, write to the Free 21 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 Boston, MA 02110 USA. 23 */ 24 25#import "common.h" 26 27#if !defined (__GNU_LIBOBJC__) 28# include <objc/encoding.h> 29#endif 30 31#define EXPOSE_NSInvocation_IVARS 1 32#import "Foundation/NSException.h" 33#import "Foundation/NSCoder.h" 34#import "Foundation/NSDistantObject.h" 35#import "Foundation/NSData.h" 36#import "GSInvocation.h" 37#import "GNUstepBase/GSObjCRuntime.h" 38#import <pthread.h> 39#import "cifframe.h" 40#import "GSPrivate.h" 41 42#ifdef __GNUSTEP_RUNTIME__ 43#include <objc/hooks.h> 44#endif 45 46#ifdef __GNU_LIBOBJC__ 47#include <objc/message.h> 48#endif 49 50#ifndef GS_STATIC_INLINE 51#define GS_STATIC_INLINE static inline 52#endif 53 54/* Function that implements the actual forwarding */ 55typedef void (*ffi_closure_fun) (ffi_cif*,void*,void**,void*); 56 57typedef void (*f_fun) (); 58 59static void GSFFIInvocationCallback(ffi_cif*, void*, void **, void*); 60 61/* This routine should return a typed selector corresponding to the 62 name of the specified selector. If there is only one type, then we 63 can safely return that typed selector. If not, then we can not be 64 certain which one is expected, and to prevent a crash if we return 65 the wrong type, we return NULL. 66 67 Older runtimes do not have facilities in the API to check for 68 conflicting types, hence would return a random selector in that 69 case. */ 70GS_STATIC_INLINE SEL 71gs_find_best_typed_sel (SEL sel) 72#ifdef __GNUSTEP_RUNTIME__ 73{ 74 const char *selName = sel_getName(sel); 75 const char *types; 76 77 /* If there is not exactly one typed selector with this name 78 * registered with the runtime, then give up - we can't safely use 79 * this function. */ 80 if (1 != sel_copyTypes_np (selName, NULL, 0)) 81 return (SEL)0; 82 83 sel_copyTypes_np (selName, &types, 1); 84 return GSSelectorFromNameAndTypes(selName, types); 85} 86#elif defined (__GNU_LIBOBJC__) 87{ 88/* The sel_getTypedSelector() function returns a typed selector if there 89 * is only one, nul if there are zero or more tha one. 90 */ 91 return sel_getTypedSelector(sel_getName(sel)); 92} 93#elif defined(NeXTRUNTIME) 94{ 95 /* The NeXT runtime does not support typed selectors, so we simply 96 * return 0 here. */ 97 return (SEL)0; 98} 99#else 100{ 101 /* We can't iterate over the selectors with the same name, but we 102 * can ask the runtime for a typed selector with a certain name. 103 * Usually this works, but it may produce unexpected results 104 * (including a crash) if more than one selector are registered with 105 * the same name but different types. */ 106 if (!GSTypesFromSelector(sel)) 107 { 108 const char *name = sel_getName(sel); 109 if (name) 110 { 111 SEL tmp_sel = sel_get_any_typed_uid(name); 112 if (GSTypesFromSelector(tmp_sel)) 113 return tmp_sel; 114 } 115 } 116 return sel; 117} 118#endif 119 120 121@implementation GSFFIInvocation 122 123static IMP gs_objc_msg_forward2 (id receiver, SEL sel) 124{ 125 NSMethodSignature *sig = nil; 126 GSCodeBuffer *memory; 127 const char *types; 128 129 /* 130 * If we're called with a typed selector, then use this when deconstructing 131 * the stack frame. This deviates from OS X behaviour (where there are no 132 * typed selectors), but it always more reliable because the compiler will 133 * set the selector types to represent the layout of the call frame. This 134 * means that the invocation will always deconstruct the call frame 135 * correctly. 136 */ 137 138 if (NULL != (types = GSTypesFromSelector(sel))) 139 { 140 sig = [NSMethodSignature signatureWithObjCTypes: types]; 141 } 142 143 /* Take care here ... the receiver may be nil (old runtimes) or may be 144 * a proxy which implements a method by forwarding it (so calling the 145 * method might cause recursion). However, any sane proxy ought to at 146 * least implement -methodSignatureForSelector: in such a way that it 147 * won't cause infinite recursion, so we check for that method being 148 * implemented and call it. 149 * NB. object_getClass() and class_respondsToSelector() should both 150 * return NULL when given NULL arguments, so they are safe to use. 151 */ 152 if (nil == sig) 153 { 154 Class c = object_getClass(receiver); 155 156 if (class_respondsToSelector(c, @selector(methodSignatureForSelector:))) 157 { 158 sig = [receiver methodSignatureForSelector: sel]; 159 } 160 if (nil == sig 161 && (NULL != (types = GSTypesFromSelector(gs_find_best_typed_sel(sel))))) 162 { 163 sig = [NSMethodSignature signatureWithObjCTypes: types]; 164 } 165 if (nil == sig) 166 { 167 if (nil == receiver) 168 { 169 /* If we have a nil receiver, so the runtime is probably trying 170 * to check for forwarding ... return NULL to let it fall back 171 * on the standard forwarding mechanism. 172 */ 173 return NULL; 174 } 175 [NSException raise: NSInvalidArgumentException 176 format: @"%c[%s %s]: unrecognized selector sent to instance %p", 177 (class_isMetaClass(c) ? '+' : '-'), 178 class_getName(c), sel_getName(sel), receiver]; 179 } 180 } 181 182 memory = cifframe_closure(sig, GSFFIInvocationCallback); 183 184 return (IMP)[memory executable]; 185} 186 187static __attribute__ ((__unused__)) 188IMP gs_objc_msg_forward (SEL sel) 189{ 190 return gs_objc_msg_forward2 (nil, sel); 191} 192#ifdef __GNUSTEP_RUNTIME__ 193pthread_key_t thread_slot_key; 194static struct objc_slot * 195gs_objc_msg_forward3(id receiver, SEL op) 196{ 197 /* The slot has its version set to 0, so it can not be cached. This makes it 198 * safe to free it when the thread exits. */ 199 struct objc_slot *slot = pthread_getspecific(thread_slot_key); 200 201 if (NULL == slot) 202 { 203 slot = calloc(sizeof(struct objc_slot), 1); 204 pthread_setspecific(thread_slot_key, slot); 205 } 206 slot->method = gs_objc_msg_forward2(receiver, op); 207 return slot; 208} 209 210/** Hidden by legacy API define. Declare it locally */ 211BOOL class_isMetaClass(Class cls); 212BOOL class_respondsToSelector(Class cls, SEL sel); 213 214/** 215 * Runtime hook used to provide message redirections with libobjc2. 216 * If lookup fails but this function returns non-nil then the lookup 217 * will be retried with the returned value. 218 * 219 * Note: Every message sent by this function MUST be understood by the 220 * receiver. If this is not the case then there is a potential for infinite 221 * recursion. 222 */ 223static id gs_objc_proxy_lookup(id receiver, SEL op) 224{ 225 id cls = object_getClass(receiver); 226 BOOL resolved = NO; 227 228 /* Note that __GNU_LIBOBJC__ implements +resolveClassMethod: and 229 +resolveInstanceMethod: directly in the runtime instead. */ 230 231 /* Let the class try to add a method for this thing. */ 232 if (class_isMetaClass(cls)) 233 { 234 if (class_respondsToSelector(cls, @selector(resolveClassMethod:))) 235 { 236 resolved = [receiver resolveClassMethod: op]; 237 } 238 } 239 else 240 { 241 if (class_respondsToSelector(object_getClass(cls), 242 @selector(resolveInstanceMethod:))) 243 { 244 resolved = [cls resolveInstanceMethod: op]; 245 } 246 } 247 if (resolved) 248 { 249 return receiver; 250 } 251 if (class_respondsToSelector(cls, @selector(forwardingTargetForSelector:))) 252 { 253 return [receiver forwardingTargetForSelector: op]; 254 } 255 return nil; 256} 257#endif 258 259+ (void) load 260{ 261#ifdef __GNUSTEP_RUNTIME__ 262 pthread_key_create(&thread_slot_key, free); 263 __objc_msg_forward3 = gs_objc_msg_forward3; 264 __objc_msg_forward2 = gs_objc_msg_forward2; 265 objc_proxy_lookup = gs_objc_proxy_lookup; 266#else 267#if HAVE_FORWARD2 268 __objc_msg_forward2 = gs_objc_msg_forward2; 269#else 270 __objc_msg_forward = gs_objc_msg_forward; 271#endif 272#endif 273} 274 275 276/* 277 * This is the designated initialiser. 278 */ 279- (id) initWithMethodSignature: (NSMethodSignature*)aSignature 280{ 281 int i; 282 283 if (aSignature == nil) 284 { 285 DESTROY(self); 286 return nil; 287 } 288 _sig = RETAIN(aSignature); 289 _numArgs = [aSignature numberOfArguments]; 290 _info = [aSignature methodInfo]; 291 _frame = cifframe_from_signature(_sig); 292 [_frame retain]; 293 _cframe = [_frame mutableBytes]; 294 295 /* Make sure we have somewhere to store the return value if needed. 296 */ 297 _retval = _retptr = 0; 298 i = objc_sizeof_type (objc_skip_type_qualifiers ([_sig methodReturnType])); 299 if (i > 0) 300 { 301 if (i <= sizeof(_retbuf)) 302 { 303 _retval = _retbuf; 304 } 305 else 306 { 307 _retptr = NSAllocateCollectable(i, NSScannedOption); 308 _retval = _retptr; 309 } 310 } 311 return self; 312} 313 314/* Initializer used when we get a callback. uses the data provided by 315 the callback. The cifframe was allocated by the forwarding function, 316 but we own it now so we can free it */ 317- (id) initWithCallback: (ffi_cif *)cif 318 values: (void **)vals 319 frame: (void *)frame 320 signature: (NSMethodSignature*)aSignature 321{ 322 cifframe_t *f; 323 int i; 324 325 _sig = RETAIN(aSignature); 326 _numArgs = [aSignature numberOfArguments]; 327 _info = [aSignature methodInfo]; 328 _frame = (NSMutableData*)frame; 329 [_frame retain]; 330 _cframe = [_frame mutableBytes]; 331 f = (cifframe_t *)_cframe; 332 f->cif = *cif; 333 334 /* Copy the arguments into our frame so that they are preserved 335 * in the NSInvocation if the stack is changed before the 336 * invocation is used. 337 */ 338 for (i = 0; i < f->nargs; i++) 339 { 340 memcpy(f->values[i], vals[i], f->arg_types[i]->size); 341 } 342 343 /* Make sure we have somewhere to store the return value if needed. 344 */ 345 _retval = _retptr = 0; 346 i = objc_sizeof_type (objc_skip_type_qualifiers ([_sig methodReturnType])); 347 if (i > 0) 348 { 349 if (i <= sizeof(_retbuf)) 350 { 351 _retval = _retbuf; 352 } 353 else 354 { 355 _retptr = NSAllocateCollectable(i, NSScannedOption); 356 _retval = _retptr; 357 } 358 } 359 return self; 360} 361 362/* 363 * This is implemented as a function so it can be used by other 364 * routines (like the DO forwarding) 365 */ 366void 367GSFFIInvokeWithTargetAndImp(NSInvocation *inv, id anObject, IMP imp) 368{ 369 /* Do it */ 370 ffi_call(inv->_cframe, (f_fun)imp, (inv->_retval), 371 ((cifframe_t *)inv->_cframe)->values); 372 373 /* Don't decode the return value here (?) */ 374} 375 376- (void) invokeWithTarget: (id)anObject 377{ 378 id old_target; 379 const char *type; 380 IMP imp; 381 382 CLEAR_RETURN_VALUE_IF_OBJECT; 383 _validReturn = NO; 384 type = objc_skip_type_qualifiers([_sig methodReturnType]); 385 386 /* 387 * A message to a nil object returns nil. 388 */ 389 if (anObject == nil) 390 { 391 if (_retval) 392 { 393 memset(_retval, '\0', objc_sizeof_type (type)); 394 } 395 _validReturn = YES; 396 return; 397 } 398 399 /* Make sure we have a typed selector for forwarding. 400 */ 401 NSAssert(_selector != 0, @"you must set the selector before invoking"); 402 if (0 == GSTypesFromSelector(_selector)) 403 { 404 _selector = GSSelectorFromNameAndTypes(sel_getName(_selector), 405 [_sig methodType]); 406 } 407 408 /* 409 * Temporarily set new target and copy it (and the selector) into the 410 * _cframe. 411 */ 412 old_target = RETAIN(_target); 413 [self setTarget: anObject]; 414 415 cifframe_set_arg((cifframe_t *)_cframe, 0, &_target, sizeof(id)); 416 cifframe_set_arg((cifframe_t *)_cframe, 1, &_selector, sizeof(SEL)); 417 418 if (_sendToSuper == YES) 419 { 420 Class cls; 421 if (GSObjCIsInstance(_target)) 422 cls = class_getSuperclass(object_getClass(_target)); 423 else 424 cls = class_getSuperclass((Class)_target); 425 { 426 struct objc_super s = {_target, cls}; 427 imp = objc_msg_lookup_super(&s, _selector); 428 } 429 } 430 else 431 { 432 GSMethod method; 433 method = GSGetMethod((GSObjCIsInstance(_target) 434 ? (Class)object_getClass(_target) 435 : (Class)_target), 436 _selector, 437 GSObjCIsInstance(_target), 438 YES); 439 imp = method_getImplementation(method); 440 /* 441 * If fast lookup failed, we may be forwarding or something ... 442 */ 443 if (imp == 0) 444 { 445 imp = objc_msg_lookup(_target, _selector); 446 } 447 } 448 449 [self setTarget: old_target]; 450 RELEASE(old_target); 451 452 GSFFIInvokeWithTargetAndImp(self, anObject, imp); 453 454 /* Decode the return value */ 455 if (*type != _C_VOID) 456 { 457 cifframe_decode_arg(type, _retval); 458 } 459 460 RETAIN_RETURN_VALUE; 461 _validReturn = YES; 462} 463 464@end 465 466/* 467 * Return YES if the selector contains protocol qualifiers. 468 */ 469static BOOL 470gs_protocol_selector(const char *types) 471{ 472 if (types == 0) 473 { 474 return NO; 475 } 476 while (*types != '\0') 477 { 478 if (*types == '+' || *types == '-') 479 { 480 types++; 481 } 482 while (isdigit(*types)) 483 { 484 types++; 485 } 486 while (*types == _C_CONST || *types == _C_GCINVISIBLE) 487 { 488 types++; 489 } 490 if (*types == _C_IN 491 || *types == _C_INOUT 492 || *types == _C_OUT 493 || *types == _C_BYCOPY 494 || *types == _C_BYREF 495 || *types == _C_ONEWAY) 496 { 497 return YES; 498 } 499 if (*types == '\0') 500 { 501 return NO; 502 } 503 types = objc_skip_typespec(types); 504 } 505 return NO; 506} 507 508static void 509GSFFIInvocationCallback(ffi_cif *cif, void *retp, void **args, void *user) 510{ 511 id obj; 512 SEL selector; 513 GSFFIInvocation *invocation; 514 NSMethodSignature *sig; 515 516 obj = *(id *)args[0]; 517 selector = *(SEL *)args[1]; 518 519 if (!class_respondsToSelector(object_getClass(obj), 520 @selector(forwardInvocation:))) 521 { 522 [NSException raise: NSInvalidArgumentException 523 format: @"GSFFIInvocation: Class '%s'(%s) does not respond" 524 @" to forwardInvocation: for '%s'", 525 GSClassNameFromObject(obj), 526 GSObjCIsInstance(obj) ? "instance" : "class", 527 selector ? sel_getName(selector) : "(null)"]; 528 } 529 530 sig = nil; 531 if (gs_protocol_selector(GSTypesFromSelector(selector)) == YES) 532 { 533 sig = [NSMethodSignature signatureWithObjCTypes: 534 GSTypesFromSelector(selector)]; 535 } 536 if (sig == nil) 537 { 538 sig = [obj methodSignatureForSelector: selector]; 539 } 540 541 /* 542 * If we got a method signature from the receiving object, 543 * ensure that the selector we are using matches the types. 544 */ 545 if (sig != nil) 546 { 547 const char *receiverTypes = [sig methodType]; 548 const char *runtimeTypes = GSTypesFromSelector(selector); 549 550 if (NO == GSSelectorTypesMatch(receiverTypes, runtimeTypes)) 551 { 552 const char *runtimeName = sel_getName(selector); 553 554 selector = GSSelectorFromNameAndTypes(runtimeName, receiverTypes); 555 if (runtimeTypes != 0) 556 { 557 /* 558 * FIXME ... if we have a typed selector, it probably came 559 * from the compiler, and the types of the proxied method 560 * MUST match those that the compiler supplied on the stack 561 * and the type it expects to retrieve from the stack. 562 * We should therefore discriminate between signatures where 563 * type qalifiers and sizes differ, and those where the 564 * actual types differ. 565 */ 566 NSDebugFLog(@"Changed type signature '%s' to '%s' for '%s'", 567 runtimeTypes, receiverTypes, runtimeName); 568 } 569 } 570 } 571 572 if (sig == nil) 573 { 574 /* NB Don't overwrite selector prematurely, so we can show the untyped 575 * selector in the error message below if there is no best selector. */ 576 SEL typed_sel = gs_find_best_typed_sel (selector); 577 578 if (typed_sel != 0) 579 { 580 selector = typed_sel; 581 if (GSTypesFromSelector(selector) != 0) 582 { 583 sig = [NSMethodSignature signatureWithObjCTypes: 584 GSTypesFromSelector(selector)]; 585 } 586 } 587 } 588 589 if (sig == nil) 590 { 591 [NSException raise: NSInvalidArgumentException 592 format: @"Can not determine type information for %s[%s %s]", 593 GSObjCIsInstance(obj) ? "-" : "+", 594 GSClassNameFromObject(obj), 595 selector ? sel_getName(selector) : "(null)"]; 596 } 597 598 invocation = [[GSFFIInvocation alloc] initWithCallback: cif 599 values: args 600 frame: user 601 signature: sig]; 602 IF_NO_GC([invocation autorelease];) 603 [invocation setTarget: obj]; 604 [invocation setSelector: selector]; 605 606 [obj forwardInvocation: invocation]; 607 608 /* If we are returning a value, we must copy it from the invocation 609 * to the memory indicated by 'retp'. 610 */ 611 if (retp != 0 && invocation->_validReturn == YES) 612 { 613 [invocation getReturnValue: retp]; 614 } 615 616 /* We need to (re)encode the return type for it's trip back. */ 617 if (retp) 618 cifframe_encode_arg([sig methodReturnType], retp); 619} 620 621@implementation NSInvocation (DistantCoding) 622 623/* An internal method used to help NSConnections code invocations 624 to send over the wire */ 625- (BOOL) encodeWithDistantCoder: (NSCoder*)coder passPointers: (BOOL)passp 626{ 627 int i; 628 BOOL out_parameters = NO; 629 const char *type = [_sig methodType]; 630 631 [coder encodeValueOfObjCType: @encode(char*) at: &type]; 632 633 for (i = 0; i < _numArgs; i++) 634 { 635 int flags = _inf[i+1].qual; 636 const char *type = _inf[i+1].type; 637 void *datum; 638 639 if (i == 0) 640 { 641 datum = &_target; 642 } 643 else if (i == 1) 644 { 645 datum = &_selector; 646 } 647 else 648 { 649 datum = cifframe_arg_addr((cifframe_t *)_cframe, i); 650 } 651 652 /* 653 * Decide how, (or whether or not), to encode the argument 654 * depending on its FLAGS and TYPE. Only the first two cases 655 * involve parameters that may potentially be passed by 656 * reference, and thus only the first two may change the value 657 * of OUT_PARAMETERS. 658 */ 659 660 switch (*type) 661 { 662 case _C_ID: 663 if (flags & _F_BYCOPY) 664 { 665 [coder encodeBycopyObject: *(id*)datum]; 666 } 667#ifdef _F_BYREF 668 else if (flags & _F_BYREF) 669 { 670 [coder encodeByrefObject: *(id*)datum]; 671 } 672#endif 673 else 674 { 675 [coder encodeObject: *(id*)datum]; 676 } 677 break; 678 case _C_CHARPTR: 679 /* 680 * Handle a (char*) argument. 681 * If the char* is qualified as an OUT parameter, or if it 682 * not explicitly qualified as an IN parameter, then we will 683 * have to get this char* again after the method is run, 684 * because the method may have changed it. Set 685 * OUT_PARAMETERS accordingly. 686 */ 687 if ((flags & _F_OUT) || !(flags & _F_IN)) 688 { 689 out_parameters = YES; 690 } 691 /* 692 * If the char* is qualified as an IN parameter, or not 693 * explicity qualified as an OUT parameter, then encode 694 * it. 695 */ 696 if ((flags & _F_IN) || !(flags & _F_OUT)) 697 { 698 [coder encodeValueOfObjCType: type at: datum]; 699 } 700 break; 701 702 case _C_PTR: 703 /* 704 * If the pointer's value is qualified as an OUT parameter, 705 * or if it not explicitly qualified as an IN parameter, 706 * then we will have to get the value pointed to again after 707 * the method is run, because the method may have changed 708 * it. Set OUT_PARAMETERS accordingly. 709 */ 710 if ((flags & _F_OUT) || !(flags & _F_IN)) 711 { 712 out_parameters = YES; 713 } 714 if (passp) 715 { 716 if ((flags & _F_IN) || !(flags & _F_OUT)) 717 { 718 [coder encodeValueOfObjCType: type at: datum]; 719 } 720 } 721 else 722 { 723 /* 724 * Handle an argument that is a pointer to a non-char. But 725 * (void*) and (anything**) is not allowed. 726 * The argument is a pointer to something; increment TYPE 727 * so we can see what it is a pointer to. 728 */ 729 type++; 730 /* 731 * If the pointer's value is qualified as an IN parameter, 732 * or not explicity qualified as an OUT parameter, then 733 * encode it. 734 */ 735 if ((flags & _F_IN) || !(flags & _F_OUT)) 736 { 737 [coder encodeValueOfObjCType: type at: *(void**)datum]; 738 } 739 } 740 break; 741 742 case _C_STRUCT_B: 743 case _C_UNION_B: 744 case _C_ARY_B: 745 /* 746 * Handle struct and array arguments. 747 * Whether DATUM points to the data, or points to a pointer 748 * that points to the data, depends on the value of 749 * CALLFRAME_STRUCT_BYREF. Do the right thing 750 * so that ENCODER gets a pointer to directly to the data. 751 */ 752 [coder encodeValueOfObjCType: type at: datum]; 753 break; 754 755 default: 756 /* Handle arguments of all other types. */ 757 [coder encodeValueOfObjCType: type at: datum]; 758 } 759 } 760 761 /* 762 * Return a BOOL indicating whether or not there are parameters that 763 * were passed by reference; we will need to get those values again 764 * after the method has finished executing because the execution of 765 * the method may have changed them. 766 */ 767 return out_parameters; 768} 769 770@end 771