1/* 2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/*********************************************************************** 24* objc-class.m 25* Copyright 1988-1997, Apple Computer, Inc. 26* Author: s. naroff 27**********************************************************************/ 28 29 30/*********************************************************************** 31 * Lazy method list arrays and method list locking (2004-10-19) 32 * 33 * cls->methodLists may be in one of three forms: 34 * 1. nil: The class has no methods. 35 * 2. non-nil, with CLS_NO_METHOD_ARRAY set: cls->methodLists points 36 * to a single method list, which is the class's only method list. 37 * 3. non-nil, with CLS_NO_METHOD_ARRAY clear: cls->methodLists points to 38 * an array of method list pointers. The end of the array's block 39 * is set to -1. If the actual number of method lists is smaller 40 * than that, the rest of the array is nil. 41 * 42 * Attaching categories and adding and removing classes may change 43 * the form of the class list. In addition, individual method lists 44 * may be reallocated when fixed up. 45 * 46 * Classes are initially read as #1 or #2. If a category is attached 47 * or other methods added, the class is changed to #3. Once in form #3, 48 * the class is never downgraded to #1 or #2, even if methods are removed. 49 * Classes added with objc_addClass are initially either #1 or #3. 50 * 51 * Accessing and manipulating a class's method lists are synchronized, 52 * to prevent races when one thread restructures the list. However, 53 * if the class is not yet in use (i.e. not in class_hash), then the 54 * thread loading the class may access its method lists without locking. 55 * 56 * The following functions acquire methodListLock: 57 * class_getInstanceMethod 58 * class_getClassMethod 59 * class_nextMethodList 60 * class_addMethods 61 * class_removeMethods 62 * class_respondsToMethod 63 * _class_lookupMethodAndLoadCache 64 * lookupMethodInClassAndLoadCache 65 * _objc_add_category_flush_caches 66 * 67 * The following functions don't acquire methodListLock because they 68 * only access method lists during class load and unload: 69 * _objc_register_category 70 * _resolve_categories_for_class (calls _objc_add_category) 71 * add_class_to_loadable_list 72 * _objc_addClass 73 * _objc_remove_classes_in_image 74 * 75 * The following functions use method lists without holding methodListLock. 76 * The caller must either hold methodListLock, or be loading the class. 77 * _getMethod (called by class_getInstanceMethod, class_getClassMethod, 78 * and class_respondsToMethod) 79 * _findMethodInClass (called by _class_lookupMethodAndLoadCache, 80 * lookupMethodInClassAndLoadCache, _getMethod) 81 * _findMethodInList (called by _findMethodInClass) 82 * nextMethodList (called by _findMethodInClass and class_nextMethodList 83 * fixupSelectorsInMethodList (called by nextMethodList) 84 * _objc_add_category (called by _objc_add_category_flush_caches, 85 * resolve_categories_for_class and _objc_register_category) 86 * _objc_insertMethods (called by class_addMethods and _objc_add_category) 87 * _objc_removeMethods (called by class_removeMethods) 88 * _objcTweakMethodListPointerForClass (called by _objc_insertMethods) 89 * get_base_method_list (called by add_class_to_loadable_list) 90 * lookupNamedMethodInMethodList (called by add_class_to_loadable_list) 91 ***********************************************************************/ 92 93/*********************************************************************** 94 * Thread-safety of class info bits (2004-10-19) 95 * 96 * Some class info bits are used to store mutable runtime state. 97 * Modifications of the info bits at particular times need to be 98 * synchronized to prevent races. 99 * 100 * Three thread-safe modification functions are provided: 101 * cls->setInfo() // atomically sets some bits 102 * cls->clearInfo() // atomically clears some bits 103 * cls->changeInfo() // atomically sets some bits and clears others 104 * These replace CLS_SETINFO() for the multithreaded cases. 105 * 106 * Three modification windows are defined: 107 * - compile time 108 * - class construction or image load (before +load) in one thread 109 * - multi-threaded messaging and method caches 110 * 111 * Info bit modification at compile time and class construction do not 112 * need to be locked, because only one thread is manipulating the class. 113 * Info bit modification during messaging needs to be locked, because 114 * there may be other threads simultaneously messaging or otherwise 115 * manipulating the class. 116 * 117 * Modification windows for each flag: 118 * 119 * CLS_CLASS: compile-time and class load 120 * CLS_META: compile-time and class load 121 * CLS_INITIALIZED: +initialize 122 * CLS_POSING: messaging 123 * CLS_MAPPED: compile-time 124 * CLS_FLUSH_CACHE: class load and messaging 125 * CLS_GROW_CACHE: messaging 126 * CLS_NEED_BIND: unused 127 * CLS_METHOD_ARRAY: unused 128 * CLS_JAVA_HYBRID: JavaBridge only 129 * CLS_JAVA_CLASS: JavaBridge only 130 * CLS_INITIALIZING: messaging 131 * CLS_FROM_BUNDLE: class load 132 * CLS_HAS_CXX_STRUCTORS: compile-time and class load 133 * CLS_NO_METHOD_ARRAY: class load and messaging 134 * CLS_HAS_LOAD_METHOD: class load 135 * 136 * CLS_INITIALIZED and CLS_INITIALIZING have additional thread-safety 137 * constraints to support thread-safe +initialize. See "Thread safety 138 * during class initialization" for details. 139 * 140 * CLS_JAVA_HYBRID and CLS_JAVA_CLASS are set immediately after JavaBridge 141 * calls objc_addClass(). The JavaBridge does not use an atomic update, 142 * but the modification counts as "class construction" unless some other 143 * thread quickly finds the class via the class list. This race is 144 * small and unlikely in well-behaved code. 145 * 146 * Most info bits that may be modified during messaging are also never 147 * read without a lock. There is no general read lock for the info bits. 148 * CLS_INITIALIZED: classInitLock 149 * CLS_FLUSH_CACHE: cacheUpdateLock 150 * CLS_GROW_CACHE: cacheUpdateLock 151 * CLS_NO_METHOD_ARRAY: methodListLock 152 * CLS_INITIALIZING: classInitLock 153 ***********************************************************************/ 154 155/*********************************************************************** 156* Imports. 157**********************************************************************/ 158 159#include "objc-private.h" 160#include "objc-abi.h" 161#include "objc-auto.h" 162#include <objc/message.h> 163 164 165/* overriding the default object allocation and error handling routines */ 166 167OBJC_EXPORT id (*_alloc)(Class, size_t); 168OBJC_EXPORT id (*_copy)(id, size_t); 169OBJC_EXPORT id (*_realloc)(id, size_t); 170OBJC_EXPORT id (*_dealloc)(id); 171OBJC_EXPORT id (*_zoneAlloc)(Class, size_t, void *); 172OBJC_EXPORT id (*_zoneRealloc)(id, size_t, void *); 173OBJC_EXPORT id (*_zoneCopy)(id, size_t, void *); 174 175 176/*********************************************************************** 177* Information about multi-thread support: 178* 179* Since we do not lock many operations which walk the superclass, method 180* and ivar chains, these chains must remain intact once a class is published 181* by inserting it into the class hashtable. All modifications must be 182* atomic so that someone walking these chains will always geta valid 183* result. 184***********************************************************************/ 185 186 187 188/*********************************************************************** 189* object_getClass. 190* Locking: None. If you add locking, tell gdb (rdar://7516456). 191**********************************************************************/ 192Class object_getClass(id obj) 193{ 194 if (obj) return obj->getIsa(); 195 else return Nil; 196} 197 198 199/*********************************************************************** 200* object_setClass. 201**********************************************************************/ 202Class object_setClass(id obj, Class cls) 203{ 204 if (obj) return obj->changeIsa(cls); 205 else return Nil; 206} 207 208 209/*********************************************************************** 210* object_getClassName. 211**********************************************************************/ 212const char *object_getClassName(id obj) 213{ 214 return class_getName(obj ? obj->getIsa() : nil); 215} 216 217 218/*********************************************************************** 219 * object_getMethodImplementation. 220 **********************************************************************/ 221IMP object_getMethodImplementation(id obj, SEL name) 222{ 223 Class cls = (obj ? obj->getIsa() : nil); 224 return class_getMethodImplementation(cls, name); 225} 226 227 228/*********************************************************************** 229 * object_getMethodImplementation_stret. 230 **********************************************************************/ 231IMP object_getMethodImplementation_stret(id obj, SEL name) 232{ 233 Class cls = (obj ? obj->getIsa() : nil); 234 return class_getMethodImplementation_stret(cls, name); 235} 236 237 238/*********************************************************************** 239* object_getIndexedIvars. 240**********************************************************************/ 241void *object_getIndexedIvars(id obj) 242{ 243 // ivars are tacked onto the end of the object 244 if (!obj) return nil; 245 if (obj->isTaggedPointer()) return nil; 246 return ((char *) obj) + obj->ISA()->alignedInstanceSize(); 247} 248 249 250Ivar object_setInstanceVariable(id obj, const char *name, void *value) 251{ 252 Ivar ivar = nil; 253 254 if (obj && name && !obj->isTaggedPointer()) { 255 if ((ivar = class_getInstanceVariable(obj->ISA(), name))) { 256 object_setIvar(obj, ivar, (id)value); 257 } 258 } 259 return ivar; 260} 261 262Ivar object_getInstanceVariable(id obj, const char *name, void **value) 263{ 264 if (obj && name && !obj->isTaggedPointer()) { 265 Ivar ivar; 266 if ((ivar = class_getInstanceVariable(obj->ISA(), name))) { 267 if (value) *value = (void *)object_getIvar(obj, ivar); 268 return ivar; 269 } 270 } 271 if (value) *value = nil; 272 return nil; 273} 274 275static BOOL is_scanned_offset(ptrdiff_t ivar_offset, const uint8_t *layout) { 276 ptrdiff_t index = 0, ivar_index = ivar_offset / sizeof(void*); 277 uint8_t byte; 278 while ((byte = *layout++)) { 279 unsigned skips = (byte >> 4); 280 unsigned scans = (byte & 0x0F); 281 index += skips; 282 while (scans--) { 283 if (index == ivar_index) return YES; 284 if (index > ivar_index) return NO; 285 ++index; 286 } 287 } 288 return NO; 289} 290 291// FIXME: this could be optimized. 292 293static Class _ivar_getClass(Class cls, Ivar ivar) { 294 Class ivar_class = nil; 295 const char *ivar_name = ivar_getName(ivar); 296 Ivar named_ivar = _class_getVariable(cls, ivar_name, &ivar_class); 297 if (named_ivar) { 298 // the same ivar name can appear multiple times along the superclass chain. 299 while (named_ivar != ivar && ivar_class != nil) { 300 ivar_class = ivar_class->superclass; 301 named_ivar = _class_getVariable(cls, ivar_getName(ivar), &ivar_class); 302 } 303 } 304 return ivar_class; 305} 306 307void object_setIvar(id obj, Ivar ivar, id value) 308{ 309 if (obj && ivar && !obj->isTaggedPointer()) { 310 Class cls = _ivar_getClass(obj->ISA(), ivar); 311 ptrdiff_t ivar_offset = ivar_getOffset(ivar); 312 id *location = (id *)((char *)obj + ivar_offset); 313 // if this ivar is a member of an ARR compiled class, then issue the correct barrier according to the layout. 314 if (_class_usesAutomaticRetainRelease(cls)) { 315 // for ARR, layout strings are relative to the instance start. 316 uint32_t instanceStart = _class_getInstanceStart(cls); 317 const uint8_t *weak_layout = class_getWeakIvarLayout(cls); 318 if (weak_layout && is_scanned_offset(ivar_offset - instanceStart, weak_layout)) { 319 // use the weak system to write to this variable. 320 objc_storeWeak(location, value); 321 return; 322 } 323 const uint8_t *strong_layout = class_getIvarLayout(cls); 324 if (strong_layout && is_scanned_offset(ivar_offset - instanceStart, strong_layout)) { 325 objc_storeStrong(location, value); 326 return; 327 } 328 } 329#if SUPPORT_GC 330 if (UseGC) { 331 // for GC, check for weak references. 332 const uint8_t *weak_layout = class_getWeakIvarLayout(cls); 333 if (weak_layout && is_scanned_offset(ivar_offset, weak_layout)) { 334 objc_assign_weak(value, location); 335 } 336 } 337 objc_assign_ivar(value, obj, ivar_offset); 338#else 339 *location = value; 340#endif 341 } 342} 343 344 345id object_getIvar(id obj, Ivar ivar) 346{ 347 if (obj && ivar && !obj->isTaggedPointer()) { 348 Class cls = obj->ISA(); 349 ptrdiff_t ivar_offset = ivar_getOffset(ivar); 350 if (_class_usesAutomaticRetainRelease(cls)) { 351 // for ARR, layout strings are relative to the instance start. 352 uint32_t instanceStart = _class_getInstanceStart(cls); 353 const uint8_t *weak_layout = class_getWeakIvarLayout(cls); 354 if (weak_layout && is_scanned_offset(ivar_offset - instanceStart, weak_layout)) { 355 // use the weak system to read this variable. 356 id *location = (id *)((char *)obj + ivar_offset); 357 return objc_loadWeak(location); 358 } 359 } 360 id *idx = (id *)((char *)obj + ivar_offset); 361#if SUPPORT_GC 362 if (UseGC) { 363 const uint8_t *weak_layout = class_getWeakIvarLayout(cls); 364 if (weak_layout && is_scanned_offset(ivar_offset, weak_layout)) { 365 return objc_read_weak(idx); 366 } 367 } 368#endif 369 return *idx; 370 } 371 return nil; 372} 373 374 375/*********************************************************************** 376* object_cxxDestructFromClass. 377* Call C++ destructors on obj, starting with cls's 378* dtor method (if any) followed by superclasses' dtors (if any), 379* stopping at cls's dtor (if any). 380* Uses methodListLock and cacheUpdateLock. The caller must hold neither. 381**********************************************************************/ 382static void object_cxxDestructFromClass(id obj, Class cls) 383{ 384 void (*dtor)(id); 385 386 // Call cls's dtor first, then superclasses's dtors. 387 388 for ( ; cls; cls = cls->superclass) { 389 if (!cls->hasCxxDtor()) return; 390 dtor = (void(*)(id)) 391 lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct); 392 if (dtor != (void(*)(id))_objc_msgForward_impcache) { 393 if (PrintCxxCtors) { 394 _objc_inform("CXX: calling C++ destructors for class %s", 395 cls->getName()); 396 } 397 (*dtor)(obj); 398 } 399 } 400} 401 402 403/*********************************************************************** 404* object_cxxDestruct. 405* Call C++ destructors on obj, if any. 406* Uses methodListLock and cacheUpdateLock. The caller must hold neither. 407**********************************************************************/ 408void object_cxxDestruct(id obj) 409{ 410 if (!obj) return; 411 if (obj->isTaggedPointer()) return; 412 object_cxxDestructFromClass(obj, obj->ISA()); 413} 414 415 416/*********************************************************************** 417* object_cxxConstructFromClass. 418* Recursively call C++ constructors on obj, starting with base class's 419* ctor method (if any) followed by subclasses' ctors (if any), stopping 420* at cls's ctor (if any). 421* Returns YES if construction succeeded. 422* Returns NO if some constructor threw an exception. The exception is 423* caught and discarded. Any partial construction is destructed. 424* Uses methodListLock and cacheUpdateLock. The caller must hold neither. 425* 426* .cxx_construct returns id. This really means: 427* return self: construction succeeded 428* return nil: construction failed because a C++ constructor threw an exception 429**********************************************************************/ 430static BOOL object_cxxConstructFromClass(id obj, Class cls) 431{ 432 id (*ctor)(id); 433 Class supercls; 434 435 // Stop if neither this class nor any superclass has ctors. 436 if (!cls->hasCxxCtor()) return YES; // no ctor - ok 437 438 supercls = cls->superclass; 439 440 // Call superclasses' ctors first, if any. 441 if (supercls) { 442 BOOL ok = object_cxxConstructFromClass(obj, supercls); 443 if (!ok) return NO; // some superclass's ctor failed - give up 444 } 445 446 // Find this class's ctor, if any. 447 ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, SEL_cxx_construct); 448 if (ctor == (id(*)(id))_objc_msgForward_impcache) return YES; // no ctor - ok 449 450 // Call this class's ctor. 451 if (PrintCxxCtors) { 452 _objc_inform("CXX: calling C++ constructors for class %s", cls->getName()); 453 } 454 if ((*ctor)(obj)) return YES; // ctor called and succeeded - ok 455 456 // This class's ctor was called and failed. 457 // Call superclasses's dtors to clean up. 458 if (supercls) object_cxxDestructFromClass(obj, supercls); 459 return NO; 460} 461 462 463/*********************************************************************** 464* object_cxxConstructFromClass. 465* Call C++ constructors on obj, if any. 466* Returns YES if construction succeeded. 467* Returns NO if some constructor threw an exception. The exception is 468* caught and discarded. Any partial construction is destructed. 469* Uses methodListLock and cacheUpdateLock. The caller must hold neither. 470**********************************************************************/ 471BOOL object_cxxConstruct(id obj) 472{ 473 if (!obj) return YES; 474 if (obj->isTaggedPointer()) return YES; 475 return object_cxxConstructFromClass(obj, obj->ISA()); 476} 477 478 479/*********************************************************************** 480* _class_resolveClassMethod 481* Call +resolveClassMethod, looking for a method to be added to class cls. 482* cls should be a metaclass. 483* Does not check if the method already exists. 484**********************************************************************/ 485static void _class_resolveClassMethod(Class cls, SEL sel, id inst) 486{ 487 assert(cls->isMetaClass()); 488 489 if (! lookUpImpOrNil(cls, SEL_resolveClassMethod, inst, 490 NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) 491 { 492 // Resolver not implemented. 493 return; 494 } 495 496 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend; 497 BOOL resolved = msg(_class_getNonMetaClass(cls, inst), 498 SEL_resolveClassMethod, sel); 499 500 // Cache the result (good or bad) so the resolver doesn't fire next time. 501 // +resolveClassMethod adds to self->ISA() a.k.a. cls 502 IMP imp = lookUpImpOrNil(cls, sel, inst, 503 NO/*initialize*/, YES/*cache*/, NO/*resolver*/); 504 505 if (resolved && PrintResolving) { 506 if (imp) { 507 _objc_inform("RESOLVE: method %c[%s %s] " 508 "dynamically resolved to %p", 509 cls->isMetaClass() ? '+' : '-', 510 cls->getName(), sel_getName(sel), imp); 511 } 512 else { 513 // Method resolver didn't add anything? 514 _objc_inform("RESOLVE: +[%s resolveClassMethod:%s] returned YES" 515 ", but no new implementation of %c[%s %s] was found", 516 cls->getName(), sel_getName(sel), 517 cls->isMetaClass() ? '+' : '-', 518 cls->getName(), sel_getName(sel)); 519 } 520 } 521} 522 523 524/*********************************************************************** 525* _class_resolveInstanceMethod 526* Call +resolveInstanceMethod, looking for a method to be added to class cls. 527* cls may be a metaclass or a non-meta class. 528* Does not check if the method already exists. 529**********************************************************************/ 530static void _class_resolveInstanceMethod(Class cls, SEL sel, id inst) 531{ 532 if (! lookUpImpOrNil(cls->ISA(), SEL_resolveInstanceMethod, cls, 533 NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) 534 { 535 // Resolver not implemented. 536 return; 537 } 538 539 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend; 540 BOOL resolved = msg(cls, SEL_resolveInstanceMethod, sel); 541 542 // Cache the result (good or bad) so the resolver doesn't fire next time. 543 // +resolveInstanceMethod adds to self a.k.a. cls 544 IMP imp = lookUpImpOrNil(cls, sel, inst, 545 NO/*initialize*/, YES/*cache*/, NO/*resolver*/); 546 547 if (resolved && PrintResolving) { 548 if (imp) { 549 _objc_inform("RESOLVE: method %c[%s %s] " 550 "dynamically resolved to %p", 551 cls->isMetaClass() ? '+' : '-', 552 cls->getName(), sel_getName(sel), imp); 553 } 554 else { 555 // Method resolver didn't add anything? 556 _objc_inform("RESOLVE: +[%s resolveInstanceMethod:%s] returned YES" 557 ", but no new implementation of %c[%s %s] was found", 558 cls->getName(), sel_getName(sel), 559 cls->isMetaClass() ? '+' : '-', 560 cls->getName(), sel_getName(sel)); 561 } 562 } 563} 564 565 566/*********************************************************************** 567* _class_resolveMethod 568* Call +resolveClassMethod or +resolveInstanceMethod. 569* Returns nothing; any result would be potentially out-of-date already. 570* Does not check if the method already exists. 571**********************************************************************/ 572void _class_resolveMethod(Class cls, SEL sel, id inst) 573{ 574 if (! cls->isMetaClass()) { 575 // try [cls resolveInstanceMethod:sel] 576 _class_resolveInstanceMethod(cls, sel, inst); 577 } 578 else { 579 // try [nonMetaClass resolveClassMethod:sel] 580 // and [cls resolveInstanceMethod:sel] 581 _class_resolveClassMethod(cls, sel, inst); 582 if (!lookUpImpOrNil(cls, sel, inst, 583 NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) 584 { 585 _class_resolveInstanceMethod(cls, sel, inst); 586 } 587 } 588} 589 590 591/*********************************************************************** 592* class_getClassMethod. Return the class method for the specified 593* class and selector. 594**********************************************************************/ 595Method class_getClassMethod(Class cls, SEL sel) 596{ 597 if (!cls || !sel) return nil; 598 599 return class_getInstanceMethod(cls->getMeta(), sel); 600} 601 602 603/*********************************************************************** 604* class_getInstanceVariable. Return the named instance variable. 605**********************************************************************/ 606Ivar class_getInstanceVariable(Class cls, const char *name) 607{ 608 if (!cls || !name) return nil; 609 610 return _class_getVariable(cls, name, nil); 611} 612 613 614/*********************************************************************** 615* class_getClassVariable. Return the named class variable. 616**********************************************************************/ 617Ivar class_getClassVariable(Class cls, const char *name) 618{ 619 if (!cls) return nil; 620 621 return class_getInstanceVariable(cls->ISA(), name); 622} 623 624 625/*********************************************************************** 626* gdb_objc_class_changed 627* Tell gdb that a class changed. Currently used for OBJC2 ivar layouts only 628* Does nothing; gdb sets a breakpoint on it. 629**********************************************************************/ 630BREAKPOINT_FUNCTION( 631 void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname) 632); 633 634 635/*********************************************************************** 636* class_respondsToSelector. 637**********************************************************************/ 638BOOL class_respondsToMethod(Class cls, SEL sel) 639{ 640 OBJC_WARN_DEPRECATED; 641 642 return class_respondsToSelector(cls, sel); 643} 644 645 646BOOL class_respondsToSelector(Class cls, SEL sel) 647{ 648 IMP imp; 649 650 if (!sel || !cls) return NO; 651 652 // Avoids +initialize because it historically did so. 653 // We're not returning a callable IMP anyway. 654 imp = lookUpImpOrNil(cls, sel, nil, 655 NO/*initialize*/, YES/*cache*/, YES/*resolver*/); 656 return imp ? YES : NO; 657} 658 659 660/*********************************************************************** 661* class_getMethodImplementation. 662* Returns the IMP that would be invoked if [obj sel] were sent, 663* where obj is an instance of class cls. 664**********************************************************************/ 665IMP class_lookupMethod(Class cls, SEL sel) 666{ 667 OBJC_WARN_DEPRECATED; 668 669 // No one responds to zero! 670 if (!sel) { 671 __objc_error(cls, "invalid selector (null)"); 672 } 673 674 return class_getMethodImplementation(cls, sel); 675} 676 677IMP class_getMethodImplementation(Class cls, SEL sel) 678{ 679 IMP imp; 680 681 if (!cls || !sel) return nil; 682 683 imp = lookUpImpOrNil(cls, sel, nil, 684 YES/*initialize*/, YES/*cache*/, YES/*resolver*/); 685 686 // Translate forwarding function to C-callable external version 687 if (!imp) { 688 return _objc_msgForward; 689 } 690 691 return imp; 692} 693 694 695IMP class_getMethodImplementation_stret(Class cls, SEL sel) 696{ 697 IMP imp = class_getMethodImplementation(cls, sel); 698 699 // Translate forwarding function to struct-returning version 700 if (imp == (IMP)&_objc_msgForward /* not _internal! */) { 701 return (IMP)&_objc_msgForward_stret; 702 } 703 return imp; 704} 705 706 707/*********************************************************************** 708* instrumentObjcMessageSends 709**********************************************************************/ 710#if !SUPPORT_MESSAGE_LOGGING 711 712void instrumentObjcMessageSends(BOOL flag) 713{ 714} 715 716#else 717 718bool objcMsgLogEnabled = false; 719static int objcMsgLogFD = -1; 720 721bool logMessageSend(bool isClassMethod, 722 const char *objectsClass, 723 const char *implementingClass, 724 SEL selector) 725{ 726 char buf[ 1024 ]; 727 728 // Create/open the log file 729 if (objcMsgLogFD == (-1)) 730 { 731 snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ()); 732 objcMsgLogFD = secure_open (buf, O_WRONLY | O_CREAT, geteuid()); 733 if (objcMsgLogFD < 0) { 734 // no log file - disable logging 735 objcMsgLogEnabled = false; 736 objcMsgLogFD = -1; 737 return true; 738 } 739 } 740 741 // Make the log entry 742 snprintf(buf, sizeof(buf), "%c %s %s %s\n", 743 isClassMethod ? '+' : '-', 744 objectsClass, 745 implementingClass, 746 sel_getName(selector)); 747 748 static spinlock_t lock = SPINLOCK_INITIALIZER; 749 spinlock_lock(&lock); 750 write (objcMsgLogFD, buf, strlen(buf)); 751 spinlock_unlock(&lock); 752 753 // Tell caller to not cache the method 754 return false; 755} 756 757void instrumentObjcMessageSends(BOOL flag) 758{ 759 bool enable = flag; 760 761 // Shortcut NOP 762 if (objcMsgLogEnabled == enable) 763 return; 764 765 // If enabling, flush all method caches so we get some traces 766 if (enable) 767 _objc_flush_caches(Nil); 768 769 // Sync our log file 770 if (objcMsgLogFD != -1) 771 fsync (objcMsgLogFD); 772 773 objcMsgLogEnabled = enable; 774} 775 776// SUPPORT_MESSAGE_LOGGING 777#endif 778 779 780/*********************************************************************** 781* _malloc_internal 782* _calloc_internal 783* _realloc_internal 784* _strdup_internal 785* _strdupcat_internal 786* _memdup_internal 787* _free_internal 788* Convenience functions for the internal malloc zone. 789**********************************************************************/ 790void *_malloc_internal(size_t size) 791{ 792 return malloc_zone_malloc(_objc_internal_zone(), size); 793} 794 795void *_calloc_internal(size_t count, size_t size) 796{ 797 return malloc_zone_calloc(_objc_internal_zone(), count, size); 798} 799 800void *_realloc_internal(void *ptr, size_t size) 801{ 802 return malloc_zone_realloc(_objc_internal_zone(), ptr, size); 803} 804 805char *_strdup_internal(const char *str) 806{ 807 size_t len; 808 char *dup; 809 if (!str) return nil; 810 len = strlen(str); 811 dup = (char *)malloc_zone_malloc(_objc_internal_zone(), len + 1); 812 memcpy(dup, str, len + 1); 813 return dup; 814} 815 816uint8_t *_ustrdup_internal(const uint8_t *str) 817{ 818 return (uint8_t *)_strdup_internal((char *)str); 819} 820 821// allocate a new string that concatenates s1+s2. 822char *_strdupcat_internal(const char *s1, const char *s2) 823{ 824 size_t len1 = strlen(s1); 825 size_t len2 = strlen(s2); 826 char *dup = (char *) 827 malloc_zone_malloc(_objc_internal_zone(), len1 + len2 + 1); 828 memcpy(dup, s1, len1); 829 memcpy(dup + len1, s2, len2 + 1); 830 return dup; 831} 832 833void *_memdup_internal(const void *mem, size_t len) 834{ 835 void *dup = malloc_zone_malloc(_objc_internal_zone(), len); 836 memcpy(dup, mem, len); 837 return dup; 838} 839 840void _free_internal(void *ptr) 841{ 842 malloc_zone_free(_objc_internal_zone(), ptr); 843} 844 845size_t _malloc_size_internal(void *ptr) 846{ 847 malloc_zone_t *zone = _objc_internal_zone(); 848 return zone->size(zone, ptr); 849} 850 851Class _calloc_class(size_t size) 852{ 853#if SUPPORT_GC 854 if (UseGC) return (Class) malloc_zone_calloc(gc_zone, 1, size); 855#endif 856 return (Class) _calloc_internal(1, size); 857} 858 859 860const char *class_getName(Class cls) 861{ 862 if (!cls) return "nil"; 863 else return cls->getName(); 864} 865 866Class class_getSuperclass(Class cls) 867{ 868 if (!cls) return nil; 869 return cls->superclass; 870} 871 872BOOL class_isMetaClass(Class cls) 873{ 874 if (!cls) return NO; 875 return cls->isMetaClass(); 876} 877 878 879size_t class_getInstanceSize(Class cls) 880{ 881 if (!cls) return 0; 882 return cls->alignedInstanceSize(); 883} 884 885 886/*********************************************************************** 887* method_getNumberOfArguments. 888**********************************************************************/ 889unsigned int method_getNumberOfArguments(Method m) 890{ 891 if (!m) return 0; 892 return encoding_getNumberOfArguments(method_getTypeEncoding(m)); 893} 894 895 896void method_getReturnType(Method m, char *dst, size_t dst_len) 897{ 898 encoding_getReturnType(method_getTypeEncoding(m), dst, dst_len); 899} 900 901 902char * method_copyReturnType(Method m) 903{ 904 return encoding_copyReturnType(method_getTypeEncoding(m)); 905} 906 907 908void method_getArgumentType(Method m, unsigned int index, 909 char *dst, size_t dst_len) 910{ 911 encoding_getArgumentType(method_getTypeEncoding(m), 912 index, dst, dst_len); 913} 914 915 916char * method_copyArgumentType(Method m, unsigned int index) 917{ 918 return encoding_copyArgumentType(method_getTypeEncoding(m), index); 919} 920 921 922/*********************************************************************** 923* objc_constructInstance 924* Creates an instance of `cls` at the location pointed to by `bytes`. 925* `bytes` must point to at least class_getInstanceSize(cls) bytes of 926* well-aligned zero-filled memory. 927* The new object's isa is set. Any C++ constructors are called. 928* Returns `bytes` if successful. Returns nil if `cls` or `bytes` is 929* nil, or if C++ constructors fail. 930* Note: class_createInstance() and class_createInstances() preflight this. 931**********************************************************************/ 932static id 933_objc_constructInstance(Class cls, void *bytes) 934{ 935 id obj = (id)bytes; 936 937 // Set the isa pointer 938 obj->initIsa(cls); 939 940 // Call C++ constructors, if any. 941 if (!object_cxxConstruct(obj)) { 942 // Some C++ constructor threw an exception. 943 return nil; 944 } 945 946 return obj; 947} 948 949 950id 951objc_constructInstance(Class cls, void *bytes) 952{ 953 if (!cls || !bytes) return nil; 954 return _objc_constructInstance(cls, bytes); 955} 956 957 958id 959_objc_constructOrFree(Class cls, void *bytes) 960{ 961 id obj = _objc_constructInstance(cls, bytes); 962 if (!obj) { 963#if SUPPORT_GC 964 if (UseGC) { 965 auto_zone_retain(gc_zone, bytes); // gc free expects rc==1 966 } 967#endif 968 free(bytes); 969 } 970 971 return obj; 972} 973 974 975/*********************************************************************** 976* _class_createInstancesFromZone 977* Batch-allocating version of _class_createInstanceFromZone. 978* Attempts to allocate num_requested objects, each with extraBytes. 979* Returns the number of allocated objects (possibly zero), with 980* the allocated pointers in *results. 981**********************************************************************/ 982unsigned 983_class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, 984 id *results, unsigned num_requested) 985{ 986 unsigned num_allocated; 987 if (!cls) return 0; 988 989 size_t size = cls->alignedInstanceSize() + extraBytes; 990 // CF requires all objects be at least 16 bytes. 991 if (size < 16) size = 16; 992 993#if SUPPORT_GC 994 if (UseGC) { 995 num_allocated = 996 auto_zone_batch_allocate(gc_zone, size, AUTO_OBJECT_SCANNED, 0, 1, 997 (void**)results, num_requested); 998 } else 999#endif 1000 { 1001 unsigned i; 1002 num_allocated = 1003 malloc_zone_batch_malloc((malloc_zone_t *)(zone ? zone : malloc_default_zone()), 1004 size, (void**)results, num_requested); 1005 for (i = 0; i < num_allocated; i++) { 1006 bzero(results[i], size); 1007 } 1008 } 1009 1010 // Construct each object, and delete any that fail construction. 1011 1012 unsigned shift = 0; 1013 unsigned i; 1014 bool ctor = cls->hasCxxCtor(); 1015 for (i = 0; i < num_allocated; i++) { 1016 id obj = results[i]; 1017 if (ctor) obj = _objc_constructOrFree(cls, obj); 1018 else if (obj) obj->initIsa(cls); 1019 1020 if (obj) { 1021 results[i-shift] = obj; 1022 } else { 1023 shift++; 1024 } 1025 } 1026 1027 return num_allocated - shift; 1028} 1029 1030 1031/*********************************************************************** 1032* inform_duplicate. Complain about duplicate class implementations. 1033**********************************************************************/ 1034void 1035inform_duplicate(const char *name, Class oldCls, Class cls) 1036{ 1037#if TARGET_OS_WIN32 1038 _objc_inform ("Class %s is implemented in two different images.", name); 1039#else 1040 const header_info *oldHeader = _headerForClass(oldCls); 1041 const header_info *newHeader = _headerForClass(cls); 1042 const char *oldName = oldHeader ? oldHeader->fname : "??"; 1043 const char *newName = newHeader ? newHeader->fname : "??"; 1044 1045 _objc_inform ("Class %s is implemented in both %s and %s. " 1046 "One of the two will be used. " 1047 "Which one is undefined.", 1048 name, oldName, newName); 1049#endif 1050} 1051 1052 1053const char * 1054copyPropertyAttributeString(const objc_property_attribute_t *attrs, 1055 unsigned int count) 1056{ 1057 char *result; 1058 unsigned int i; 1059 if (count == 0) return strdup(""); 1060 1061#ifndef NDEBUG 1062 // debug build: sanitize input 1063 for (i = 0; i < count; i++) { 1064 assert(attrs[i].name); 1065 assert(strlen(attrs[i].name) > 0); 1066 assert(! strchr(attrs[i].name, ',')); 1067 assert(! strchr(attrs[i].name, '"')); 1068 if (attrs[i].value) assert(! strchr(attrs[i].value, ',')); 1069 } 1070#endif 1071 1072 size_t len = 0; 1073 for (i = 0; i < count; i++) { 1074 if (attrs[i].value) { 1075 size_t namelen = strlen(attrs[i].name); 1076 if (namelen > 1) namelen += 2; // long names get quoted 1077 len += namelen + strlen(attrs[i].value) + 1; 1078 } 1079 } 1080 1081 result = (char *)malloc(len + 1); 1082 char *s = result; 1083 for (i = 0; i < count; i++) { 1084 if (attrs[i].value) { 1085 size_t namelen = strlen(attrs[i].name); 1086 if (namelen > 1) { 1087 s += sprintf(s, "\"%s\"%s,", attrs[i].name, attrs[i].value); 1088 } else { 1089 s += sprintf(s, "%s%s,", attrs[i].name, attrs[i].value); 1090 } 1091 } 1092 } 1093 1094 // remove trailing ',' if any 1095 if (s > result) s[-1] = '\0'; 1096 1097 return result; 1098} 1099 1100/* 1101 Property attribute string format: 1102 1103 - Comma-separated name-value pairs. 1104 - Name and value may not contain , 1105 - Name may not contain " 1106 - Value may be empty 1107 - Name is single char, value follows 1108 - OR Name is double-quoted string of 2+ chars, value follows 1109 1110 Grammar: 1111 attribute-string: \0 1112 attribute-string: name-value-pair (',' name-value-pair)* 1113 name-value-pair: unquoted-name optional-value 1114 name-value-pair: quoted-name optional-value 1115 unquoted-name: [^",] 1116 quoted-name: '"' [^",]{2,} '"' 1117 optional-value: [^,]* 1118 1119*/ 1120static unsigned int 1121iteratePropertyAttributes(const char *attrs, 1122 BOOL (*fn)(unsigned int index, 1123 void *ctx1, void *ctx2, 1124 const char *name, size_t nlen, 1125 const char *value, size_t vlen), 1126 void *ctx1, void *ctx2) 1127{ 1128 if (!attrs) return 0; 1129 1130#ifndef NDEBUG 1131 const char *attrsend = attrs + strlen(attrs); 1132#endif 1133 unsigned int attrcount = 0; 1134 1135 while (*attrs) { 1136 // Find the next comma-separated attribute 1137 const char *start = attrs; 1138 const char *end = start + strcspn(attrs, ","); 1139 1140 // Move attrs past this attribute and the comma (if any) 1141 attrs = *end ? end+1 : end; 1142 1143 assert(attrs <= attrsend); 1144 assert(start <= attrsend); 1145 assert(end <= attrsend); 1146 1147 // Skip empty attribute 1148 if (start == end) continue; 1149 1150 // Process one non-empty comma-free attribute [start,end) 1151 const char *nameStart; 1152 const char *nameEnd; 1153 1154 assert(start < end); 1155 assert(*start); 1156 if (*start != '\"') { 1157 // single-char short name 1158 nameStart = start; 1159 nameEnd = start+1; 1160 start++; 1161 } 1162 else { 1163 // double-quoted long name 1164 nameStart = start+1; 1165 nameEnd = nameStart + strcspn(nameStart, "\","); 1166 start++; // leading quote 1167 start += nameEnd - nameStart; // name 1168 if (*start == '\"') start++; // trailing quote, if any 1169 } 1170 1171 // Process one possibly-empty comma-free attribute value [start,end) 1172 const char *valueStart; 1173 const char *valueEnd; 1174 1175 assert(start <= end); 1176 1177 valueStart = start; 1178 valueEnd = end; 1179 1180 BOOL more = (*fn)(attrcount, ctx1, ctx2, 1181 nameStart, nameEnd-nameStart, 1182 valueStart, valueEnd-valueStart); 1183 attrcount++; 1184 if (!more) break; 1185 } 1186 1187 return attrcount; 1188} 1189 1190 1191static BOOL 1192copyOneAttribute(unsigned int index, void *ctxa, void *ctxs, 1193 const char *name, size_t nlen, const char *value, size_t vlen) 1194{ 1195 objc_property_attribute_t **ap = (objc_property_attribute_t**)ctxa; 1196 char **sp = (char **)ctxs; 1197 1198 objc_property_attribute_t *a = *ap; 1199 char *s = *sp; 1200 1201 a->name = s; 1202 memcpy(s, name, nlen); 1203 s += nlen; 1204 *s++ = '\0'; 1205 1206 a->value = s; 1207 memcpy(s, value, vlen); 1208 s += vlen; 1209 *s++ = '\0'; 1210 1211 a++; 1212 1213 *ap = a; 1214 *sp = s; 1215 1216 return YES; 1217} 1218 1219 1220objc_property_attribute_t * 1221copyPropertyAttributeList(const char *attrs, unsigned int *outCount) 1222{ 1223 if (!attrs) { 1224 if (outCount) *outCount = 0; 1225 return nil; 1226 } 1227 1228 // Result size: 1229 // number of commas plus 1 for the attributes (upper bound) 1230 // plus another attribute for the attribute array terminator 1231 // plus strlen(attrs) for name/value string data (upper bound) 1232 // plus count*2 for the name/value string terminators (upper bound) 1233 unsigned int attrcount = 1; 1234 const char *s; 1235 for (s = attrs; s && *s; s++) { 1236 if (*s == ',') attrcount++; 1237 } 1238 1239 size_t size = 1240 attrcount * sizeof(objc_property_attribute_t) + 1241 sizeof(objc_property_attribute_t) + 1242 strlen(attrs) + 1243 attrcount * 2; 1244 objc_property_attribute_t *result = (objc_property_attribute_t *) 1245 calloc(size, 1); 1246 1247 objc_property_attribute_t *ra = result; 1248 char *rs = (char *)(ra+attrcount+1); 1249 1250 attrcount = iteratePropertyAttributes(attrs, copyOneAttribute, &ra, &rs); 1251 1252 assert((uint8_t *)(ra+1) <= (uint8_t *)result+size); 1253 assert((uint8_t *)rs <= (uint8_t *)result+size); 1254 1255 if (attrcount == 0) { 1256 free(result); 1257 result = nil; 1258 } 1259 1260 if (outCount) *outCount = attrcount; 1261 return result; 1262} 1263 1264 1265static BOOL 1266findOneAttribute(unsigned int index, void *ctxa, void *ctxs, 1267 const char *name, size_t nlen, const char *value, size_t vlen) 1268{ 1269 const char *query = (char *)ctxa; 1270 char **resultp = (char **)ctxs; 1271 1272 if (strlen(query) == nlen && 0 == strncmp(name, query, nlen)) { 1273 char *result = (char *)calloc(vlen+1, 1); 1274 memcpy(result, value, vlen); 1275 result[vlen] = '\0'; 1276 *resultp = result; 1277 return NO; 1278 } 1279 1280 return YES; 1281} 1282 1283char *copyPropertyAttributeValue(const char *attrs, const char *name) 1284{ 1285 char *result = nil; 1286 1287 iteratePropertyAttributes(attrs, findOneAttribute, (void*)name, &result); 1288 1289 return result; 1290} 1291