1/* 2 * Copyright (c) 1999-2009 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/*********************************************************************** 25* objc-class-old.m 26* Support for old-ABI classes, methods, and categories. 27**********************************************************************/ 28 29#if !__OBJC2__ 30 31#include "objc-private.h" 32#include "objc-runtime-old.h" 33#include "objc-file-old.h" 34#include "objc-cache-old.h" 35 36static Method _class_getMethod(Class cls, SEL sel); 37static Method _class_getMethodNoSuper(Class cls, SEL sel); 38static Method _class_getMethodNoSuper_nolock(Class cls, SEL sel); 39static void flush_caches(Class cls, bool flush_meta); 40 41 42// Freed objects have their isa set to point to this dummy class. 43// This avoids the need to check for Nil classes in the messenger. 44static const void* freedObjectClass[12] = 45{ 46 Nil, // isa 47 Nil, // superclass 48 "FREED(id)", // name 49 0, // version 50 0, // info 51 0, // instance_size 52 nil, // ivars 53 nil, // methodLists 54 (Cache) &_objc_empty_cache, // cache 55 nil, // protocols 56 nil, // ivar_layout; 57 nil // ext 58}; 59 60 61/*********************************************************************** 62* _class_getFreedObjectClass. Return a pointer to the dummy freed 63* object class. Freed objects get their isa pointers replaced with 64* a pointer to the freedObjectClass, so that we can catch usages of 65* the freed object. 66**********************************************************************/ 67static Class _class_getFreedObjectClass(void) 68{ 69 return (Class)freedObjectClass; 70} 71 72 73/*********************************************************************** 74* _objc_getFreedObjectClass. Return a pointer to the dummy freed 75* object class. Freed objects get their isa pointers replaced with 76* a pointer to the freedObjectClass, so that we can catch usages of 77* the freed object. 78**********************************************************************/ 79Class _objc_getFreedObjectClass(void) 80{ 81 return _class_getFreedObjectClass(); 82} 83 84 85static void allocateExt(Class cls) 86{ 87 if (! (cls->info & CLS_EXT)) { 88 _objc_inform("class '%s' needs to be recompiled", cls->name); 89 return; 90 } 91 if (!cls->ext) { 92 uint32_t size = (uint32_t)sizeof(old_class_ext); 93 cls->ext = (old_class_ext *)_calloc_internal(size, 1); 94 cls->ext->size = size; 95 } 96} 97 98 99static inline old_method *_findNamedMethodInList(old_method_list * mlist, const char *meth_name) { 100 int i; 101 if (!mlist) return nil; 102 if (ignoreSelectorNamed(meth_name)) return nil; 103 for (i = 0; i < mlist->method_count; i++) { 104 old_method *m = &mlist->method_list[i]; 105 if (0 == strcmp((const char *)(m->method_name), meth_name)) { 106 return m; 107 } 108 } 109 return nil; 110} 111 112 113/*********************************************************************** 114* Method list fixup markers. 115* mlist->obsolete == fixed_up_method_list marks method lists with real SELs 116* versus method lists with un-uniqued char*. 117* PREOPTIMIZED VERSION: 118* Fixed-up method lists get mlist->obsolete == OBJC_FIXED_UP 119* dyld shared cache sets this for method lists it preoptimizes. 120* UN-PREOPTIMIZED VERSION 121* Fixed-up method lists get mlist->obsolete == OBJC_FIXED_UP_outside_dyld 122* dyld shared cache uses OBJC_FIXED_UP, but those aren't trusted. 123**********************************************************************/ 124#define OBJC_FIXED_UP ((void *)1771) 125#define OBJC_FIXED_UP_outside_dyld ((void *)1773) 126static void *fixed_up_method_list = OBJC_FIXED_UP; 127 128// sel_init() decided that selectors in the dyld shared cache are untrustworthy 129void disableSharedCacheOptimizations(void) 130{ 131 fixed_up_method_list = OBJC_FIXED_UP_outside_dyld; 132} 133 134/*********************************************************************** 135* fixupSelectorsInMethodList 136* Uniques selectors in the given method list. 137* Also replaces imps for GC-ignored selectors 138* The given method list must be non-nil and not already fixed-up. 139* If the class was loaded from a bundle: 140* fixes up the given list in place with heap-allocated selector strings 141* If the class was not from a bundle: 142* allocates a copy of the method list, fixes up the copy, and returns 143* the copy. The given list is unmodified. 144* 145* If cls is already in use, methodListLock must be held by the caller. 146**********************************************************************/ 147static old_method_list *fixupSelectorsInMethodList(Class cls, old_method_list *mlist) 148{ 149 int i; 150 size_t size; 151 old_method *method; 152 old_method_list *old_mlist; 153 154 if ( ! mlist ) return nil; 155 if ( mlist->obsolete == fixed_up_method_list ) { 156 // method list OK 157 } else { 158 BOOL isBundle = (cls->info & CLS_FROM_BUNDLE) ? YES : NO; 159 if (!isBundle) { 160 old_mlist = mlist; 161 size = sizeof(old_method_list) - sizeof(old_method) + old_mlist->method_count * sizeof(old_method); 162 mlist = (old_method_list *)_malloc_internal(size); 163 memmove(mlist, old_mlist, size); 164 } else { 165 // Mach-O bundles are fixed up in place. 166 // This prevents leaks when a bundle is unloaded. 167 } 168 sel_lock(); 169 for ( i = 0; i < mlist->method_count; i += 1 ) { 170 method = &mlist->method_list[i]; 171 method->method_name = 172 sel_registerNameNoLock((const char *)method->method_name, isBundle); // Always copy selector data from bundles. 173 174 if (ignoreSelector(method->method_name)) { 175 method->method_imp = (IMP)&_objc_ignored_method; 176 } 177 } 178 sel_unlock(); 179 mlist->obsolete = fixed_up_method_list; 180 } 181 return mlist; 182} 183 184 185/*********************************************************************** 186* nextMethodList 187* Returns successive method lists from the given class. 188* Method lists are returned in method search order (i.e. highest-priority 189* implementations first). 190* All necessary method list fixups are performed, so the 191* returned method list is fully-constructed. 192* 193* If cls is already in use, methodListLock must be held by the caller. 194* For full thread-safety, methodListLock must be continuously held by the 195* caller across all calls to nextMethodList(). If the lock is released, 196* the bad results listed in class_nextMethodList() may occur. 197* 198* void *iterator = nil; 199* old_method_list *mlist; 200* mutex_lock(&methodListLock); 201* while ((mlist = nextMethodList(cls, &iterator))) { 202* // do something with mlist 203* } 204* mutex_unlock(&methodListLock); 205**********************************************************************/ 206static old_method_list *nextMethodList(Class cls, 207 void **it) 208{ 209 uintptr_t index = *(uintptr_t *)it; 210 old_method_list **resultp; 211 212 if (index == 0) { 213 // First call to nextMethodList. 214 if (!cls->methodLists) { 215 resultp = nil; 216 } else if (cls->info & CLS_NO_METHOD_ARRAY) { 217 resultp = (old_method_list **)&cls->methodLists; 218 } else { 219 resultp = &cls->methodLists[0]; 220 if (!*resultp || *resultp == END_OF_METHODS_LIST) { 221 resultp = nil; 222 } 223 } 224 } else { 225 // Subsequent call to nextMethodList. 226 if (!cls->methodLists) { 227 resultp = nil; 228 } else if (cls->info & CLS_NO_METHOD_ARRAY) { 229 resultp = nil; 230 } else { 231 resultp = &cls->methodLists[index]; 232 if (!*resultp || *resultp == END_OF_METHODS_LIST) { 233 resultp = nil; 234 } 235 } 236 } 237 238 // resultp now is nil, meaning there are no more method lists, 239 // OR the address of the method list pointer to fix up and return. 240 241 if (resultp) { 242 if (*resultp) { 243 *resultp = fixupSelectorsInMethodList(cls, *resultp); 244 } 245 *it = (void *)(index + 1); 246 return *resultp; 247 } else { 248 *it = 0; 249 return nil; 250 } 251} 252 253 254/* These next three functions are the heart of ObjC method lookup. 255 * If the class is currently in use, methodListLock must be held by the caller. 256 */ 257static inline old_method *_findMethodInList(old_method_list * mlist, SEL sel) { 258 int i; 259 if (!mlist) return nil; 260 for (i = 0; i < mlist->method_count; i++) { 261 old_method *m = &mlist->method_list[i]; 262 if (m->method_name == sel) { 263 return m; 264 } 265 } 266 return nil; 267} 268 269static inline old_method * _findMethodInClass(Class cls, SEL sel) __attribute__((always_inline)); 270static inline old_method * _findMethodInClass(Class cls, SEL sel) { 271 // Flattened version of nextMethodList(). The optimizer doesn't 272 // do a good job with hoisting the conditionals out of the loop. 273 // Conceptually, this looks like: 274 // while ((mlist = nextMethodList(cls, &iterator))) { 275 // old_method *m = _findMethodInList(mlist, sel); 276 // if (m) return m; 277 // } 278 279 if (!cls->methodLists) { 280 // No method lists. 281 return nil; 282 } 283 else if (cls->info & CLS_NO_METHOD_ARRAY) { 284 // One method list. 285 old_method_list **mlistp; 286 mlistp = (old_method_list **)&cls->methodLists; 287 *mlistp = fixupSelectorsInMethodList(cls, *mlistp); 288 return _findMethodInList(*mlistp, sel); 289 } 290 else { 291 // Multiple method lists. 292 old_method_list **mlistp; 293 for (mlistp = cls->methodLists; 294 *mlistp != nil && *mlistp != END_OF_METHODS_LIST; 295 mlistp++) 296 { 297 old_method *m; 298 *mlistp = fixupSelectorsInMethodList(cls, *mlistp); 299 m = _findMethodInList(*mlistp, sel); 300 if (m) return m; 301 } 302 return nil; 303 } 304} 305 306static inline old_method * _getMethod(Class cls, SEL sel) { 307 for (; cls; cls = cls->superclass) { 308 old_method *m; 309 m = _findMethodInClass(cls, sel); 310 if (m) return m; 311 } 312 return nil; 313} 314 315 316// fixme for gc debugging temporary use 317IMP findIMPInClass(Class cls, SEL sel) 318{ 319 old_method *m = _findMethodInClass(cls, sel); 320 if (m) return m->method_imp; 321 else return nil; 322} 323 324 325/*********************************************************************** 326* _freedHandler. 327**********************************************************************/ 328static void _freedHandler(id obj, SEL sel) 329{ 330 __objc_error (obj, "message %s sent to freed object=%p", 331 sel_getName(sel), (void*)obj); 332} 333 334 335/*********************************************************************** 336* log_and_fill_cache 337* Log this method call. If the logger permits it, fill the method cache. 338* cls is the method whose cache should be filled. 339* implementer is the class that owns the implementation in question. 340**********************************************************************/ 341static void 342log_and_fill_cache(Class cls, Class implementer, Method meth, SEL sel) 343{ 344#if SUPPORT_MESSAGE_LOGGING 345 if (objcMsgLogEnabled) { 346 bool cacheIt = logMessageSend(implementer->isMetaClass(), 347 cls->nameForLogging(), 348 implementer->nameForLogging(), 349 sel); 350 if (!cacheIt) return; 351 } 352#endif 353 _cache_fill (cls, meth, sel); 354} 355 356 357/*********************************************************************** 358* _class_lookupMethodAndLoadCache. 359* Method lookup for dispatchers ONLY. OTHER CODE SHOULD USE lookUpImp(). 360* This lookup avoids optimistic cache scan because the dispatcher 361* already tried that. 362**********************************************************************/ 363IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls) 364{ 365 return lookUpImpOrForward(cls, sel, obj, 366 YES/*initialize*/, NO/*cache*/, YES/*resolver*/); 367} 368 369 370/*********************************************************************** 371* lookUpImpOrForward. 372* The standard IMP lookup. 373* initialize==NO tries to avoid +initialize (but sometimes fails) 374* cache==NO skips optimistic unlocked lookup (but uses cache elsewhere) 375* Most callers should use initialize==YES and cache==YES. 376* inst is an instance of cls or a subclass thereof, or nil if none is known. 377* If cls is an un-initialized metaclass then a non-nil inst is faster. 378* May return _objc_msgForward_impcache. IMPs destined for external use 379* must be converted to _objc_msgForward or _objc_msgForward_stret. 380* If you don't want forwarding at all, use lookUpImpOrNil() instead. 381**********************************************************************/ 382IMP lookUpImpOrForward(Class cls, SEL sel, id inst, 383 bool initialize, bool cache, bool resolver) 384{ 385 Class curClass; 386 IMP methodPC = nil; 387 Method meth; 388 bool triedResolver = NO; 389 390 mutex_assert_unlocked(&methodListLock); 391 392 // Optimistic cache lookup 393 if (cache) { 394 methodPC = _cache_getImp(cls, sel); 395 if (methodPC) return methodPC; 396 } 397 398 // Check for freed class 399 if (cls == _class_getFreedObjectClass()) 400 return (IMP) _freedHandler; 401 402 // Check for +initialize 403 if (initialize && !cls->isInitialized()) { 404 _class_initialize (_class_getNonMetaClass(cls, inst)); 405 // If sel == initialize, _class_initialize will send +initialize and 406 // then the messenger will send +initialize again after this 407 // procedure finishes. Of course, if this is not being called 408 // from the messenger then it won't happen. 2778172 409 } 410 411 // The lock is held to make method-lookup + cache-fill atomic 412 // with respect to method addition. Otherwise, a category could 413 // be added but ignored indefinitely because the cache was re-filled 414 // with the old value after the cache flush on behalf of the category. 415 retry: 416 mutex_lock(&methodListLock); 417 418 // Ignore GC selectors 419 if (ignoreSelector(sel)) { 420 methodPC = _cache_addIgnoredEntry(cls, sel); 421 goto done; 422 } 423 424 // Try this class's cache. 425 426 methodPC = _cache_getImp(cls, sel); 427 if (methodPC) goto done; 428 429 // Try this class's method lists. 430 431 meth = _class_getMethodNoSuper_nolock(cls, sel); 432 if (meth) { 433 log_and_fill_cache(cls, cls, meth, sel); 434 methodPC = method_getImplementation(meth); 435 goto done; 436 } 437 438 // Try superclass caches and method lists. 439 440 curClass = cls; 441 while ((curClass = curClass->superclass)) { 442 // Superclass cache. 443 meth = _cache_getMethod(curClass, sel, _objc_msgForward_impcache); 444 if (meth) { 445 if (meth != (Method)1) { 446 // Found the method in a superclass. Cache it in this class. 447 log_and_fill_cache(cls, curClass, meth, sel); 448 methodPC = method_getImplementation(meth); 449 goto done; 450 } 451 else { 452 // Found a forward:: entry in a superclass. 453 // Stop searching, but don't cache yet; call method 454 // resolver for this class first. 455 break; 456 } 457 } 458 459 // Superclass method list. 460 meth = _class_getMethodNoSuper_nolock(curClass, sel); 461 if (meth) { 462 log_and_fill_cache(cls, curClass, meth, sel); 463 methodPC = method_getImplementation(meth); 464 goto done; 465 } 466 } 467 468 // No implementation found. Try method resolver once. 469 470 if (resolver && !triedResolver) { 471 mutex_unlock(&methodListLock); 472 _class_resolveMethod(cls, sel, inst); 473 triedResolver = YES; 474 goto retry; 475 } 476 477 // No implementation found, and method resolver didn't help. 478 // Use forwarding. 479 480 _cache_addForwardEntry(cls, sel); 481 methodPC = _objc_msgForward_impcache; 482 483 done: 484 mutex_unlock(&methodListLock); 485 486 // paranoia: look for ignored selectors with non-ignored implementations 487 assert(!(ignoreSelector(sel) && methodPC != (IMP)&_objc_ignored_method)); 488 489 return methodPC; 490} 491 492 493/*********************************************************************** 494* lookUpImpOrNil. 495* Like lookUpImpOrForward, but returns nil instead of _objc_msgForward_impcache 496**********************************************************************/ 497IMP lookUpImpOrNil(Class cls, SEL sel, id inst, 498 bool initialize, bool cache, bool resolver) 499{ 500 IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver); 501 if (imp == _objc_msgForward_impcache) return nil; 502 else return imp; 503} 504 505 506/*********************************************************************** 507* lookupMethodInClassAndLoadCache. 508* Like _class_lookupMethodAndLoadCache, but does not search superclasses. 509* Caches and returns objc_msgForward if the method is not found in the class. 510**********************************************************************/ 511IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel) 512{ 513 Method meth; 514 IMP imp; 515 516 // fixme this still has the method list vs method cache race 517 // because it doesn't hold a lock across lookup+cache_fill, 518 // but it's only used for .cxx_construct/destruct and we assume 519 // categories don't change them. 520 521 // Search cache first. 522 imp = _cache_getImp(cls, sel); 523 if (imp) return imp; 524 525 // Cache miss. Search method list. 526 527 meth = _class_getMethodNoSuper(cls, sel); 528 529 if (meth) { 530 // Hit in method list. Cache it. 531 _cache_fill(cls, meth, sel); 532 return method_getImplementation(meth); 533 } else { 534 // Miss in method list. Cache objc_msgForward. 535 _cache_addForwardEntry(cls, sel); 536 return _objc_msgForward_impcache; 537 } 538} 539 540 541/*********************************************************************** 542* class_getVariable. Return the named instance variable. 543**********************************************************************/ 544 545Ivar _class_getVariable(Class cls, const char *name, Class *memberOf) 546{ 547 for (; cls != Nil; cls = cls->superclass) { 548 int i; 549 550 // Skip class having no ivars 551 if (!cls->ivars) continue; 552 553 for (i = 0; i < cls->ivars->ivar_count; i++) { 554 // Check this ivar's name. Be careful because the 555 // compiler generates ivar entries with nil ivar_name 556 // (e.g. for anonymous bit fields). 557 old_ivar *ivar = &cls->ivars->ivar_list[i]; 558 if (ivar->ivar_name && 0 == strcmp(name, ivar->ivar_name)) { 559 if (memberOf) *memberOf = cls; 560 return (Ivar)ivar; 561 } 562 } 563 } 564 565 // Not found 566 return nil; 567} 568 569 570old_property * 571property_list_nth(const old_property_list *plist, uint32_t i) 572{ 573 return (old_property *)(i*plist->entsize + (char *)&plist->first); 574} 575 576old_property ** 577copyPropertyList(old_property_list *plist, unsigned int *outCount) 578{ 579 old_property **result = nil; 580 unsigned int count = 0; 581 582 if (plist) { 583 count = plist->count; 584 } 585 586 if (count > 0) { 587 unsigned int i; 588 result = (old_property **)malloc((count+1) * sizeof(old_property *)); 589 590 for (i = 0; i < count; i++) { 591 result[i] = property_list_nth(plist, i); 592 } 593 result[i] = nil; 594 } 595 596 if (outCount) *outCount = count; 597 return result; 598} 599 600 601static old_property_list * 602nextPropertyList(Class cls, uintptr_t *indexp) 603{ 604 old_property_list *result = nil; 605 606 mutex_assert_locked(&classLock); 607 if (! ((cls->info & CLS_EXT) && cls->ext)) { 608 // No class ext 609 result = nil; 610 } else if (!cls->ext->propertyLists) { 611 // No property lists 612 result = nil; 613 } else if (cls->info & CLS_NO_PROPERTY_ARRAY) { 614 // Only one property list 615 if (*indexp == 0) { 616 result = (old_property_list *)cls->ext->propertyLists; 617 } else { 618 result = nil; 619 } 620 } else { 621 // More than one property list 622 result = cls->ext->propertyLists[*indexp]; 623 } 624 625 if (result) { 626 ++*indexp; 627 return result; 628 } else { 629 *indexp = 0; 630 return nil; 631 } 632} 633 634 635/*********************************************************************** 636* class_getIvarLayout 637* nil means all-scanned. "" means non-scanned. 638**********************************************************************/ 639const uint8_t * 640class_getIvarLayout(Class cls) 641{ 642 if (cls && (cls->info & CLS_EXT)) { 643 return cls->ivar_layout; 644 } else { 645 return nil; // conservative scan 646 } 647} 648 649 650/*********************************************************************** 651* class_getWeakIvarLayout 652* nil means no weak ivars. 653**********************************************************************/ 654const uint8_t * 655class_getWeakIvarLayout(Class cls) 656{ 657 if (cls && (cls->info & CLS_EXT) && cls->ext) { 658 return cls->ext->weak_ivar_layout; 659 } else { 660 return nil; // no weak ivars 661 } 662} 663 664 665/*********************************************************************** 666* class_setIvarLayout 667* nil means all-scanned. "" means non-scanned. 668**********************************************************************/ 669void class_setIvarLayout(Class cls, const uint8_t *layout) 670{ 671 if (!cls) return; 672 673 if (! (cls->info & CLS_EXT)) { 674 _objc_inform("class '%s' needs to be recompiled", cls->name); 675 return; 676 } 677 678 // fixme leak 679 cls->ivar_layout = _ustrdup_internal(layout); 680} 681 682// SPI: Instance-specific object layout. 683 684void _class_setIvarLayoutAccessor(Class cls, const uint8_t* (*accessor) (id object)) { 685 if (!cls) return; 686 687 if (! (cls->info & CLS_EXT)) { 688 _objc_inform("class '%s' needs to be recompiled", cls->name); 689 return; 690 } 691 692 // fixme leak 693 cls->ivar_layout = (const uint8_t *)accessor; 694 cls->setInfo(CLS_HAS_INSTANCE_SPECIFIC_LAYOUT); 695} 696 697const uint8_t *_object_getIvarLayout(Class cls, id object) { 698 if (cls && (cls->info & CLS_EXT)) { 699 const uint8_t* layout = cls->ivar_layout; 700 if (cls->info & CLS_HAS_INSTANCE_SPECIFIC_LAYOUT) { 701 const uint8_t* (*accessor) (id object) = (const uint8_t* (*)(id))layout; 702 layout = accessor(object); 703 } 704 return layout; 705 } else { 706 return nil; 707 } 708} 709 710/*********************************************************************** 711* class_setWeakIvarLayout 712* nil means no weak ivars. 713**********************************************************************/ 714void class_setWeakIvarLayout(Class cls, const uint8_t *layout) 715{ 716 if (!cls) return; 717 718 mutex_lock(&classLock); 719 720 allocateExt(cls); 721 722 // fixme leak 723 cls->ext->weak_ivar_layout = _ustrdup_internal(layout); 724 725 mutex_unlock(&classLock); 726} 727 728 729/*********************************************************************** 730* class_setVersion. Record the specified version with the class. 731**********************************************************************/ 732void class_setVersion(Class cls, int version) 733{ 734 if (!cls) return; 735 cls->version = version; 736} 737 738/*********************************************************************** 739* class_getVersion. Return the version recorded with the class. 740**********************************************************************/ 741int class_getVersion(Class cls) 742{ 743 if (!cls) return 0; 744 return (int)cls->version; 745} 746 747 748/*********************************************************************** 749* class_getName. 750**********************************************************************/ 751const char *class_getName(Class cls) 752{ 753 if (!cls) return "nil"; 754 else return cls->demangledName(); 755} 756 757 758/*********************************************************************** 759* _class_getNonMetaClass. 760* Return the ordinary class for this class or metaclass. 761* Used by +initialize. 762**********************************************************************/ 763Class _class_getNonMetaClass(Class cls, id obj __unused) 764{ 765 // fixme ick 766 if (cls->isMetaClass()) { 767 if (strncmp(cls->name, "_%", 2) == 0) { 768 // Posee's meta's name is smashed and isn't in the class_hash, 769 // so objc_getClass doesn't work. 770 const char *baseName = strchr(cls->name, '%'); // get posee's real name 771 cls = objc_getClass(baseName); 772 } else { 773 cls = objc_getClass(cls->name); 774 } 775 assert(cls); 776 } 777 778 return cls; 779} 780 781 782Cache _class_getCache(Class cls) 783{ 784 return cls->cache; 785} 786 787void _class_setCache(Class cls, Cache cache) 788{ 789 cls->cache = cache; 790} 791 792const char *_category_getName(Category cat) 793{ 794 return oldcategory(cat)->category_name; 795} 796 797const char *_category_getClassName(Category cat) 798{ 799 return oldcategory(cat)->class_name; 800} 801 802Class _category_getClass(Category cat) 803{ 804 return objc_getClass(oldcategory(cat)->class_name); 805} 806 807IMP _category_getLoadMethod(Category cat) 808{ 809 old_method_list *mlist = oldcategory(cat)->class_methods; 810 if (mlist) { 811 return lookupNamedMethodInMethodList(mlist, "load"); 812 } else { 813 return nil; 814 } 815} 816 817 818 819/*********************************************************************** 820* class_nextMethodList. 821* External version of nextMethodList(). 822* 823* This function is not fully thread-safe. A series of calls to 824* class_nextMethodList() may fail if methods are added to or removed 825* from the class between calls. 826* If methods are added between calls to class_nextMethodList(), it may 827* return previously-returned method lists again, and may fail to return 828* newly-added lists. 829* If methods are removed between calls to class_nextMethodList(), it may 830* omit surviving method lists or simply crash. 831**********************************************************************/ 832OBJC_EXPORT struct objc_method_list *class_nextMethodList(Class cls, void **it) 833{ 834 old_method_list *result; 835 836 OBJC_WARN_DEPRECATED; 837 838 mutex_lock(&methodListLock); 839 result = nextMethodList(cls, it); 840 mutex_unlock(&methodListLock); 841 return (struct objc_method_list *)result; 842} 843 844 845/*********************************************************************** 846* class_addMethods. 847* 848* Formerly class_addInstanceMethods () 849**********************************************************************/ 850OBJC_EXPORT void class_addMethods(Class cls, struct objc_method_list *meths) 851{ 852 OBJC_WARN_DEPRECATED; 853 854 // Add the methods. 855 mutex_lock(&methodListLock); 856 _objc_insertMethods(cls, (old_method_list *)meths, nil); 857 mutex_unlock(&methodListLock); 858 859 // Must flush when dynamically adding methods. No need to flush 860 // all the class method caches. If cls is a meta class, though, 861 // this will still flush it and any of its sub-meta classes. 862 flush_caches (cls, NO); 863} 864 865 866/*********************************************************************** 867* class_removeMethods. 868**********************************************************************/ 869OBJC_EXPORT void class_removeMethods(Class cls, struct objc_method_list *meths) 870{ 871 OBJC_WARN_DEPRECATED; 872 873 // Remove the methods 874 mutex_lock(&methodListLock); 875 _objc_removeMethods(cls, (old_method_list *)meths); 876 mutex_unlock(&methodListLock); 877 878 // Must flush when dynamically removing methods. No need to flush 879 // all the class method caches. If cls is a meta class, though, 880 // this will still flush it and any of its sub-meta classes. 881 flush_caches (cls, NO); 882} 883 884/*********************************************************************** 885* lookupNamedMethodInMethodList 886* Only called to find +load/-.cxx_construct/-.cxx_destruct methods, 887* without fixing up the entire method list. 888* The class is not yet in use, so methodListLock is not taken. 889**********************************************************************/ 890IMP lookupNamedMethodInMethodList(old_method_list *mlist, const char *meth_name) 891{ 892 old_method *m; 893 m = meth_name ? _findNamedMethodInList(mlist, meth_name) : nil; 894 return (m ? m->method_imp : nil); 895} 896 897static Method _class_getMethod(Class cls, SEL sel) 898{ 899 Method result; 900 901 mutex_lock(&methodListLock); 902 result = (Method)_getMethod(cls, sel); 903 mutex_unlock(&methodListLock); 904 905 return result; 906} 907 908static Method _class_getMethodNoSuper(Class cls, SEL sel) 909{ 910 Method result; 911 912 mutex_lock(&methodListLock); 913 result = (Method)_findMethodInClass(cls, sel); 914 mutex_unlock(&methodListLock); 915 916 return result; 917} 918 919static Method _class_getMethodNoSuper_nolock(Class cls, SEL sel) 920{ 921 mutex_assert_locked(&methodListLock); 922 return (Method)_findMethodInClass(cls, sel); 923} 924 925 926/*********************************************************************** 927* class_getInstanceMethod. Return the instance method for the 928* specified class and selector. 929**********************************************************************/ 930Method class_getInstanceMethod(Class cls, SEL sel) 931{ 932 if (!cls || !sel) return nil; 933 934 // This deliberately avoids +initialize because it historically did so. 935 936 // This implementation is a bit weird because it's the only place that 937 // wants a Method instead of an IMP. 938 939 Method meth; 940 meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache); 941 if (meth == (Method)1) { 942 // Cache contains forward:: . Stop searching. 943 return nil; 944 } else if (meth) { 945 return meth; 946 } 947 948 // Search method lists, try method resolver, etc. 949 lookUpImpOrNil(cls, sel, nil, 950 NO/*initialize*/, NO/*cache*/, YES/*resolver*/); 951 952 meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache); 953 if (meth == (Method)1) { 954 // Cache contains forward:: . Stop searching. 955 return nil; 956 } else if (meth) { 957 return meth; 958 } 959 960 return _class_getMethod(cls, sel); 961} 962 963 964BOOL class_conformsToProtocol(Class cls, Protocol *proto_gen) 965{ 966 old_protocol *proto = oldprotocol(proto_gen); 967 968 if (!cls) return NO; 969 if (!proto) return NO; 970 971 if (cls->ISA()->version >= 3) { 972 old_protocol_list *list; 973 for (list = cls->protocols; list != nil; list = list->next) { 974 int i; 975 for (i = 0; i < list->count; i++) { 976 if (list->list[i] == proto) return YES; 977 if (protocol_conformsToProtocol((Protocol *)list->list[i], proto_gen)) return YES; 978 } 979 if (cls->ISA()->version <= 4) break; 980 } 981 } 982 return NO; 983} 984 985 986static NXMapTable * posed_class_hash = nil; 987 988/*********************************************************************** 989* objc_getOrigClass. 990**********************************************************************/ 991extern "C" 992Class _objc_getOrigClass(const char *name) 993{ 994 Class ret; 995 996 // Look for class among the posers 997 ret = Nil; 998 mutex_lock(&classLock); 999 if (posed_class_hash) 1000 ret = (Class) NXMapGet (posed_class_hash, name); 1001 mutex_unlock(&classLock); 1002 if (ret) 1003 return ret; 1004 1005 // Not a poser. Do a normal lookup. 1006 ret = objc_getClass (name); 1007 if (!ret) 1008 _objc_inform ("class `%s' not linked into application", name); 1009 1010 return ret; 1011} 1012 1013Class objc_getOrigClass(const char *name) 1014{ 1015 OBJC_WARN_DEPRECATED; 1016 return _objc_getOrigClass(name); 1017} 1018 1019/*********************************************************************** 1020* _objc_addOrigClass. This function is only used from class_poseAs. 1021* Registers the original class names, before they get obscured by 1022* posing, so that [super ..] will work correctly from categories 1023* in posing classes and in categories in classes being posed for. 1024**********************************************************************/ 1025static void _objc_addOrigClass (Class origClass) 1026{ 1027 mutex_lock(&classLock); 1028 1029 // Create the poser's hash table on first use 1030 if (!posed_class_hash) 1031 { 1032 posed_class_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype, 1033 8, 1034 _objc_internal_zone ()); 1035 } 1036 1037 // Add the named class iff it is not already there (or collides?) 1038 if (NXMapGet (posed_class_hash, origClass->name) == 0) 1039 NXMapInsert (posed_class_hash, origClass->name, origClass); 1040 1041 mutex_unlock(&classLock); 1042} 1043 1044 1045/*********************************************************************** 1046* change_class_references 1047* Change classrefs and superclass pointers from original to imposter 1048* But if copy!=nil, don't change copy->superclass. 1049* If changeSuperRefs==YES, also change [super message] classrefs. 1050* Used by class_poseAs and objc_setFutureClass 1051* classLock must be locked. 1052**********************************************************************/ 1053void change_class_references(Class imposter, 1054 Class original, 1055 Class copy, 1056 BOOL changeSuperRefs) 1057{ 1058 header_info *hInfo; 1059 Class clsObject; 1060 NXHashState state; 1061 1062 // Change all subclasses of the original to point to the imposter. 1063 state = NXInitHashState (class_hash); 1064 while (NXNextHashState (class_hash, &state, (void **) &clsObject)) 1065 { 1066 while ((clsObject) && (clsObject != imposter) && 1067 (clsObject != copy)) 1068 { 1069 if (clsObject->superclass == original) 1070 { 1071 clsObject->superclass = imposter; 1072 clsObject->ISA()->superclass = imposter->ISA(); 1073 // We must flush caches here! 1074 break; 1075 } 1076 1077 clsObject = clsObject->superclass; 1078 } 1079 } 1080 1081 // Replace the original with the imposter in all class refs 1082 // Major loop - process all headers 1083 for (hInfo = FirstHeader; hInfo != nil; hInfo = hInfo->next) 1084 { 1085 Class *cls_refs; 1086 size_t refCount; 1087 unsigned int index; 1088 1089 // Fix class refs associated with this header 1090 cls_refs = _getObjcClassRefs(hInfo, &refCount); 1091 if (cls_refs) { 1092 for (index = 0; index < refCount; index += 1) { 1093 if (cls_refs[index] == original) { 1094 cls_refs[index] = imposter; 1095 } 1096 } 1097 } 1098 } 1099} 1100 1101 1102/*********************************************************************** 1103* class_poseAs. 1104* 1105* !!! class_poseAs () does not currently flush any caches. 1106**********************************************************************/ 1107Class class_poseAs(Class imposter, Class original) 1108{ 1109 char * imposterNamePtr; 1110 Class copy; 1111 1112 OBJC_WARN_DEPRECATED; 1113 1114 // Trivial case is easy 1115 if (imposter == original) 1116 return imposter; 1117 1118 // Imposter must be an immediate subclass of the original 1119 if (imposter->superclass != original) { 1120 __objc_error(imposter, 1121 "[%s poseAs:%s]: target not immediate superclass", 1122 imposter->name, original->name); 1123 } 1124 1125 // Can't pose when you have instance variables (how could it work?) 1126 if (imposter->ivars) { 1127 __objc_error(imposter, 1128 "[%s poseAs:%s]: %s defines new instance variables", 1129 imposter->name, original->name, imposter->name); 1130 } 1131 1132 // Build a string to use to replace the name of the original class. 1133#if TARGET_OS_WIN32 1134# define imposterNamePrefix "_%" 1135 imposterNamePtr = _malloc_internal(strlen(original->name) + strlen(imposterNamePrefix) + 1); 1136 strcpy(imposterNamePtr, imposterNamePrefix); 1137 strcat(imposterNamePtr, original->name); 1138# undef imposterNamePrefix 1139#else 1140 asprintf(&imposterNamePtr, "_%%%s", original->name); 1141#endif 1142 1143 // We lock the class hashtable, so we are thread safe with respect to 1144 // calls to objc_getClass (). However, the class names are not 1145 // changed atomically, nor are all of the subclasses updated 1146 // atomically. I have ordered the operations so that you will 1147 // never crash, but you may get inconsistent results.... 1148 1149 // Register the original class so that [super ..] knows 1150 // exactly which classes are the "original" classes. 1151 _objc_addOrigClass (original); 1152 _objc_addOrigClass (imposter); 1153 1154 // Copy the imposter, so that the imposter can continue 1155 // its normal life in addition to changing the behavior of 1156 // the original. As a hack we don't bother to copy the metaclass. 1157 // For some reason we modify the original rather than the copy. 1158 copy = (Class)_malloc_internal(sizeof(objc_class)); 1159 memmove(copy, imposter, sizeof(objc_class)); 1160 1161 mutex_lock(&classLock); 1162 1163 // Remove both the imposter and the original class. 1164 NXHashRemove (class_hash, imposter); 1165 NXHashRemove (class_hash, original); 1166 1167 NXHashInsert (class_hash, copy); 1168 objc_addRegisteredClass(copy); // imposter & original will rejoin later, just track the new guy 1169 1170 // Mark the imposter as such 1171 imposter->setInfo(CLS_POSING); 1172 imposter->ISA()->setInfo(CLS_POSING); 1173 1174 // Change the name of the imposter to that of the original class. 1175 imposter->name = original->name; 1176 imposter->ISA()->name = original->ISA()->name; 1177 1178 // Also copy the version field to avoid archiving problems. 1179 imposter->version = original->version; 1180 1181 // Change classrefs and superclass pointers 1182 // Don't change copy->superclass 1183 // Don't change [super ...] messages 1184 change_class_references(imposter, original, copy, NO); 1185 1186 // Change the name of the original class. 1187 original->name = imposterNamePtr + 1; 1188 original->ISA()->name = imposterNamePtr; 1189 1190 // Restore the imposter and the original class with their new names. 1191 NXHashInsert (class_hash, imposter); 1192 NXHashInsert (class_hash, original); 1193 1194 mutex_unlock(&classLock); 1195 1196 return imposter; 1197} 1198 1199 1200/*********************************************************************** 1201* _objc_flush_caches. Flush the instance and class method caches 1202* of cls and all its subclasses. 1203* 1204* Specifying Nil for the class "all classes." 1205**********************************************************************/ 1206static void flush_caches(Class target, bool flush_meta) 1207{ 1208 bool collectALot = (target == nil); 1209 NXHashState state; 1210 Class clsObject; 1211#ifdef OBJC_INSTRUMENTED 1212 unsigned int classesVisited; 1213 unsigned int subclassCount; 1214#endif 1215 1216 mutex_lock(&classLock); 1217 mutex_lock(&cacheUpdateLock); 1218 1219 // Leaf classes are fastest because there are no subclass caches to flush. 1220 // fixme instrument 1221 if (target && (target->info & CLS_LEAF)) { 1222 _cache_flush (target); 1223 1224 if (target->ISA() && (target->ISA()->info & CLS_LEAF)) { 1225 _cache_flush (target->ISA()); 1226 mutex_unlock(&cacheUpdateLock); 1227 mutex_unlock(&classLock); 1228 return; // done 1229 } else { 1230 // Reset target and handle it by one of the methods below. 1231 target = target->ISA(); 1232 flush_meta = NO; 1233 // NOT done 1234 } 1235 } 1236 1237 state = NXInitHashState(class_hash); 1238 1239 // Handle nil and root instance class specially: flush all 1240 // instance and class method caches. Nice that this 1241 // loop is linear vs the N-squared loop just below. 1242 if (!target || !target->superclass) 1243 { 1244#ifdef OBJC_INSTRUMENTED 1245 LinearFlushCachesCount += 1; 1246 classesVisited = 0; 1247 subclassCount = 0; 1248#endif 1249 // Traverse all classes in the hash table 1250 while (NXNextHashState(class_hash, &state, (void**)&clsObject)) 1251 { 1252 Class metaClsObject; 1253#ifdef OBJC_INSTRUMENTED 1254 classesVisited += 1; 1255#endif 1256 1257 // Skip class that is known not to be a subclass of this root 1258 // (the isa pointer of any meta class points to the meta class 1259 // of the root). 1260 // NOTE: When is an isa pointer of a hash tabled class ever nil? 1261 metaClsObject = clsObject->ISA(); 1262 if (target && metaClsObject && target->ISA() != metaClsObject->ISA()) { 1263 continue; 1264 } 1265 1266#ifdef OBJC_INSTRUMENTED 1267 subclassCount += 1; 1268#endif 1269 1270 _cache_flush (clsObject); 1271 if (flush_meta && metaClsObject != nil) { 1272 _cache_flush (metaClsObject); 1273 } 1274 } 1275#ifdef OBJC_INSTRUMENTED 1276 LinearFlushCachesVisitedCount += classesVisited; 1277 if (classesVisited > MaxLinearFlushCachesVisitedCount) 1278 MaxLinearFlushCachesVisitedCount = classesVisited; 1279 IdealFlushCachesCount += subclassCount; 1280 if (subclassCount > MaxIdealFlushCachesCount) 1281 MaxIdealFlushCachesCount = subclassCount; 1282#endif 1283 1284 goto done; 1285 } 1286 1287 // Outer loop - flush any cache that could now get a method from 1288 // cls (i.e. the cache associated with cls and any of its subclasses). 1289#ifdef OBJC_INSTRUMENTED 1290 NonlinearFlushCachesCount += 1; 1291 classesVisited = 0; 1292 subclassCount = 0; 1293#endif 1294 while (NXNextHashState(class_hash, &state, (void**)&clsObject)) 1295 { 1296 Class clsIter; 1297 1298#ifdef OBJC_INSTRUMENTED 1299 NonlinearFlushCachesClassCount += 1; 1300#endif 1301 1302 // Inner loop - Process a given class 1303 clsIter = clsObject; 1304 while (clsIter) 1305 { 1306 1307#ifdef OBJC_INSTRUMENTED 1308 classesVisited += 1; 1309#endif 1310 // Flush clsObject instance method cache if 1311 // clsObject is a subclass of cls, or is cls itself 1312 // Flush the class method cache if that was asked for 1313 if (clsIter == target) 1314 { 1315#ifdef OBJC_INSTRUMENTED 1316 subclassCount += 1; 1317#endif 1318 _cache_flush (clsObject); 1319 if (flush_meta) 1320 _cache_flush (clsObject->ISA()); 1321 1322 break; 1323 1324 } 1325 1326 // Flush clsObject class method cache if cls is 1327 // the meta class of clsObject or of one 1328 // of clsObject's superclasses 1329 else if (clsIter->ISA() == target) 1330 { 1331#ifdef OBJC_INSTRUMENTED 1332 subclassCount += 1; 1333#endif 1334 _cache_flush (clsObject->ISA()); 1335 break; 1336 } 1337 1338 // Move up superclass chain 1339 // else if (clsIter->isInitialized()) 1340 clsIter = clsIter->superclass; 1341 1342 // clsIter is not initialized, so its cache 1343 // must be empty. This happens only when 1344 // clsIter == clsObject, because 1345 // superclasses are initialized before 1346 // subclasses, and this loop traverses 1347 // from sub- to super- classes. 1348 // else 1349 // break; 1350 } 1351 } 1352#ifdef OBJC_INSTRUMENTED 1353 NonlinearFlushCachesVisitedCount += classesVisited; 1354 if (classesVisited > MaxNonlinearFlushCachesVisitedCount) 1355 MaxNonlinearFlushCachesVisitedCount = classesVisited; 1356 IdealFlushCachesCount += subclassCount; 1357 if (subclassCount > MaxIdealFlushCachesCount) 1358 MaxIdealFlushCachesCount = subclassCount; 1359#endif 1360 1361 1362 done: 1363 if (collectALot) { 1364 _cache_collect(true); 1365 } 1366 1367 mutex_unlock(&cacheUpdateLock); 1368 mutex_unlock(&classLock); 1369} 1370 1371 1372void _objc_flush_caches(Class target) 1373{ 1374 flush_caches(target, YES); 1375} 1376 1377 1378 1379/*********************************************************************** 1380* flush_marked_caches. Flush the method cache of any class marked 1381* CLS_FLUSH_CACHE (and all subclasses thereof) 1382* fixme instrument 1383**********************************************************************/ 1384void flush_marked_caches(void) 1385{ 1386 Class cls; 1387 Class supercls; 1388 NXHashState state; 1389 1390 mutex_lock(&classLock); 1391 mutex_lock(&cacheUpdateLock); 1392 1393 state = NXInitHashState(class_hash); 1394 while (NXNextHashState(class_hash, &state, (void**)&cls)) { 1395 for (supercls = cls; supercls; supercls = supercls->superclass) { 1396 if (supercls->info & CLS_FLUSH_CACHE) { 1397 _cache_flush(cls); 1398 break; 1399 } 1400 } 1401 1402 for (supercls = cls->ISA(); supercls; supercls = supercls->superclass) { 1403 if (supercls->info & CLS_FLUSH_CACHE) { 1404 _cache_flush(cls->ISA()); 1405 break; 1406 } 1407 } 1408 } 1409 1410 state = NXInitHashState(class_hash); 1411 while (NXNextHashState(class_hash, &state, (void**)&cls)) { 1412 if (cls->info & CLS_FLUSH_CACHE) { 1413 cls->clearInfo(CLS_FLUSH_CACHE); 1414 } 1415 if (cls->ISA()->info & CLS_FLUSH_CACHE) { 1416 cls->ISA()->clearInfo(CLS_FLUSH_CACHE); 1417 } 1418 } 1419 1420 mutex_unlock(&cacheUpdateLock); 1421 mutex_unlock(&classLock); 1422} 1423 1424 1425/*********************************************************************** 1426* get_base_method_list 1427* Returns the method list containing the class's own methods, 1428* ignoring any method lists added by categories or class_addMethods. 1429* Called only by add_class_to_loadable_list. 1430* Does not hold methodListLock because add_class_to_loadable_list 1431* does not manipulate in-use classes. 1432**********************************************************************/ 1433static old_method_list *get_base_method_list(Class cls) 1434{ 1435 old_method_list **ptr; 1436 1437 if (!cls->methodLists) return nil; 1438 if (cls->info & CLS_NO_METHOD_ARRAY) return (old_method_list *)cls->methodLists; 1439 ptr = cls->methodLists; 1440 if (!*ptr || *ptr == END_OF_METHODS_LIST) return nil; 1441 while ( *ptr != 0 && *ptr != END_OF_METHODS_LIST ) { ptr++; } 1442 --ptr; 1443 return *ptr; 1444} 1445 1446 1447static IMP _class_getLoadMethod_nocheck(Class cls) 1448{ 1449 old_method_list *mlist; 1450 mlist = get_base_method_list(cls->ISA()); 1451 if (mlist) { 1452 return lookupNamedMethodInMethodList (mlist, "load"); 1453 } 1454 return nil; 1455} 1456 1457 1458BOOL _class_hasLoadMethod(Class cls) 1459{ 1460 if (cls->ISA()->info & CLS_HAS_LOAD_METHOD) return YES; 1461 return (_class_getLoadMethod_nocheck(cls) ? YES : NO); 1462} 1463 1464 1465/*********************************************************************** 1466* objc_class::getLoadMethod 1467* Returns cls's +load implementation, or nil if it doesn't have one. 1468**********************************************************************/ 1469IMP objc_class::getLoadMethod() 1470{ 1471 if (ISA()->info & CLS_HAS_LOAD_METHOD) { 1472 return _class_getLoadMethod_nocheck((Class)this); 1473 } 1474 return nil; 1475} 1476 1477BOOL _class_usesAutomaticRetainRelease(Class cls) 1478{ 1479 return NO; 1480} 1481 1482uint32_t _class_getInstanceStart(Class cls) 1483{ 1484 _objc_fatal("_class_getInstanceStart() unimplemented for fragile instance variables"); 1485 return 0; // PCB: never used just provided for ARR consistency. 1486} 1487 1488ptrdiff_t ivar_getOffset(Ivar ivar) 1489{ 1490 return oldivar(ivar)->ivar_offset; 1491} 1492 1493const char *ivar_getName(Ivar ivar) 1494{ 1495 return oldivar(ivar)->ivar_name; 1496} 1497 1498const char *ivar_getTypeEncoding(Ivar ivar) 1499{ 1500 return oldivar(ivar)->ivar_type; 1501} 1502 1503 1504IMP method_getImplementation(Method m) 1505{ 1506 if (!m) return nil; 1507 return oldmethod(m)->method_imp; 1508} 1509 1510SEL method_getName(Method m) 1511{ 1512 if (!m) return nil; 1513 return oldmethod(m)->method_name; 1514} 1515 1516const char *method_getTypeEncoding(Method m) 1517{ 1518 if (!m) return nil; 1519 return oldmethod(m)->method_types; 1520} 1521 1522unsigned int method_getSizeOfArguments(Method m) 1523{ 1524 OBJC_WARN_DEPRECATED; 1525 if (!m) return 0; 1526 return encoding_getSizeOfArguments(method_getTypeEncoding(m)); 1527} 1528 1529unsigned int method_getArgumentInfo(Method m, int arg, 1530 const char **type, int *offset) 1531{ 1532 OBJC_WARN_DEPRECATED; 1533 if (!m) return 0; 1534 return encoding_getArgumentInfo(method_getTypeEncoding(m), 1535 arg, type, offset); 1536} 1537 1538 1539static spinlock_t impLock = SPINLOCK_INITIALIZER; 1540 1541IMP method_setImplementation(Method m_gen, IMP imp) 1542{ 1543 IMP old; 1544 old_method *m = oldmethod(m_gen); 1545 if (!m) return nil; 1546 if (!imp) return nil; 1547 1548 if (ignoreSelector(m->method_name)) { 1549 // Ignored methods stay ignored 1550 return m->method_imp; 1551 } 1552 1553 spinlock_lock(&impLock); 1554 old = m->method_imp; 1555 m->method_imp = imp; 1556 spinlock_unlock(&impLock); 1557 return old; 1558} 1559 1560 1561void method_exchangeImplementations(Method m1_gen, Method m2_gen) 1562{ 1563 IMP m1_imp; 1564 old_method *m1 = oldmethod(m1_gen); 1565 old_method *m2 = oldmethod(m2_gen); 1566 if (!m1 || !m2) return; 1567 1568 if (ignoreSelector(m1->method_name) || ignoreSelector(m2->method_name)) { 1569 // Ignored methods stay ignored. Now they're both ignored. 1570 m1->method_imp = (IMP)&_objc_ignored_method; 1571 m2->method_imp = (IMP)&_objc_ignored_method; 1572 return; 1573 } 1574 1575 spinlock_lock(&impLock); 1576 m1_imp = m1->method_imp; 1577 m1->method_imp = m2->method_imp; 1578 m2->method_imp = m1_imp; 1579 spinlock_unlock(&impLock); 1580} 1581 1582 1583struct objc_method_description * method_getDescription(Method m) 1584{ 1585 if (!m) return nil; 1586 return (struct objc_method_description *)oldmethod(m); 1587} 1588 1589 1590const char *property_getName(objc_property_t prop) 1591{ 1592 return oldproperty(prop)->name; 1593} 1594 1595const char *property_getAttributes(objc_property_t prop) 1596{ 1597 return oldproperty(prop)->attributes; 1598} 1599 1600objc_property_attribute_t *property_copyAttributeList(objc_property_t prop, 1601 unsigned int *outCount) 1602{ 1603 if (!prop) { 1604 if (outCount) *outCount = 0; 1605 return nil; 1606 } 1607 1608 objc_property_attribute_t *result; 1609 mutex_lock(&classLock); 1610 result = copyPropertyAttributeList(oldproperty(prop)->attributes,outCount); 1611 mutex_unlock(&classLock); 1612 return result; 1613} 1614 1615char * property_copyAttributeValue(objc_property_t prop, const char *name) 1616{ 1617 if (!prop || !name || *name == '\0') return nil; 1618 1619 char *result; 1620 mutex_lock(&classLock); 1621 result = copyPropertyAttributeValue(oldproperty(prop)->attributes, name); 1622 mutex_unlock(&classLock); 1623 return result; 1624} 1625 1626 1627/*********************************************************************** 1628* class_addMethod 1629**********************************************************************/ 1630static IMP _class_addMethod(Class cls, SEL name, IMP imp, 1631 const char *types, BOOL replace) 1632{ 1633 old_method *m; 1634 IMP result = nil; 1635 1636 if (!types) types = ""; 1637 1638 mutex_lock(&methodListLock); 1639 1640 if ((m = _findMethodInClass(cls, name))) { 1641 // already exists 1642 // fixme atomic 1643 result = method_getImplementation((Method)m); 1644 if (replace) { 1645 method_setImplementation((Method)m, imp); 1646 } 1647 } else { 1648 // fixme could be faster 1649 old_method_list *mlist = 1650 (old_method_list *)_calloc_internal(sizeof(old_method_list), 1); 1651 mlist->obsolete = fixed_up_method_list; 1652 mlist->method_count = 1; 1653 mlist->method_list[0].method_name = name; 1654 mlist->method_list[0].method_types = _strdup_internal(types); 1655 if (!ignoreSelector(name)) { 1656 mlist->method_list[0].method_imp = imp; 1657 } else { 1658 mlist->method_list[0].method_imp = (IMP)&_objc_ignored_method; 1659 } 1660 1661 _objc_insertMethods(cls, mlist, nil); 1662 if (!(cls->info & CLS_CONSTRUCTING)) { 1663 flush_caches(cls, NO); 1664 } else { 1665 // in-construction class has no subclasses 1666 flush_cache(cls); 1667 } 1668 result = nil; 1669 } 1670 1671 mutex_unlock(&methodListLock); 1672 1673 return result; 1674} 1675 1676 1677/*********************************************************************** 1678* class_addMethod 1679**********************************************************************/ 1680BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types) 1681{ 1682 IMP old; 1683 if (!cls) return NO; 1684 1685 old = _class_addMethod(cls, name, imp, types, NO); 1686 return old ? NO : YES; 1687} 1688 1689 1690/*********************************************************************** 1691* class_replaceMethod 1692**********************************************************************/ 1693IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) 1694{ 1695 if (!cls) return nil; 1696 1697 return _class_addMethod(cls, name, imp, types, YES); 1698} 1699 1700 1701/*********************************************************************** 1702* class_addIvar 1703**********************************************************************/ 1704BOOL class_addIvar(Class cls, const char *name, size_t size, 1705 uint8_t alignment, const char *type) 1706{ 1707 BOOL result = YES; 1708 1709 if (!cls) return NO; 1710 if (ISMETA(cls)) return NO; 1711 if (!(cls->info & CLS_CONSTRUCTING)) return NO; 1712 1713 if (!type) type = ""; 1714 if (name && 0 == strcmp(name, "")) name = nil; 1715 1716 mutex_lock(&classLock); 1717 1718 // Check for existing ivar with this name 1719 // fixme check superclasses? 1720 if (cls->ivars) { 1721 int i; 1722 for (i = 0; i < cls->ivars->ivar_count; i++) { 1723 if (0 == strcmp(cls->ivars->ivar_list[i].ivar_name, name)) { 1724 result = NO; 1725 break; 1726 } 1727 } 1728 } 1729 1730 if (result) { 1731 old_ivar_list *old = cls->ivars; 1732 size_t oldSize; 1733 int newCount; 1734 old_ivar *ivar; 1735 size_t alignBytes; 1736 size_t misalign; 1737 1738 if (old) { 1739 oldSize = sizeof(old_ivar_list) + 1740 (old->ivar_count - 1) * sizeof(old_ivar); 1741 newCount = 1 + old->ivar_count; 1742 } else { 1743 oldSize = sizeof(old_ivar_list) - sizeof(old_ivar); 1744 newCount = 1; 1745 } 1746 1747 // allocate new ivar list 1748 cls->ivars = (old_ivar_list *) 1749 _calloc_internal(oldSize+sizeof(old_ivar), 1); 1750 if (old) memcpy(cls->ivars, old, oldSize); 1751 if (old && malloc_size(old)) free(old); 1752 cls->ivars->ivar_count = newCount; 1753 ivar = &cls->ivars->ivar_list[newCount-1]; 1754 1755 // set ivar name and type 1756 ivar->ivar_name = _strdup_internal(name); 1757 ivar->ivar_type = _strdup_internal(type); 1758 1759 // align if necessary 1760 alignBytes = 1 << alignment; 1761 misalign = cls->instance_size % alignBytes; 1762 if (misalign) cls->instance_size += (long)(alignBytes - misalign); 1763 1764 // set ivar offset and increase instance size 1765 ivar->ivar_offset = (int)cls->instance_size; 1766 cls->instance_size += (long)size; 1767 } 1768 1769 mutex_unlock(&classLock); 1770 1771 return result; 1772} 1773 1774 1775/*********************************************************************** 1776* class_addProtocol 1777**********************************************************************/ 1778BOOL class_addProtocol(Class cls, Protocol *protocol_gen) 1779{ 1780 old_protocol *protocol = oldprotocol(protocol_gen); 1781 old_protocol_list *plist; 1782 1783 if (!cls) return NO; 1784 if (class_conformsToProtocol(cls, protocol_gen)) return NO; 1785 1786 mutex_lock(&classLock); 1787 1788 // fixme optimize - protocol list doesn't escape? 1789 plist = (old_protocol_list*)_calloc_internal(sizeof(old_protocol_list), 1); 1790 plist->count = 1; 1791 plist->list[0] = protocol; 1792 plist->next = cls->protocols; 1793 cls->protocols = plist; 1794 1795 // fixme metaclass? 1796 1797 mutex_unlock(&classLock); 1798 1799 return YES; 1800} 1801 1802 1803/*********************************************************************** 1804* _class_addProperties 1805* Internal helper to add properties to a class. 1806* Used by category attachment and class_addProperty() 1807* Locking: acquires classLock 1808**********************************************************************/ 1809BOOL 1810_class_addProperties(Class cls, 1811 old_property_list *additions) 1812{ 1813 old_property_list *newlist; 1814 1815 if (!(cls->info & CLS_EXT)) return NO; 1816 1817 newlist = (old_property_list *) 1818 _memdup_internal(additions, sizeof(*newlist) - sizeof(newlist->first) 1819 + (additions->entsize * additions->count)); 1820 1821 mutex_lock(&classLock); 1822 1823 allocateExt(cls); 1824 if (!cls->ext->propertyLists) { 1825 // cls has no properties - simply use this list 1826 cls->ext->propertyLists = (old_property_list **)newlist; 1827 cls->setInfo(CLS_NO_PROPERTY_ARRAY); 1828 } 1829 else if (cls->info & CLS_NO_PROPERTY_ARRAY) { 1830 // cls has one property list - make a new array 1831 old_property_list **newarray = (old_property_list **) 1832 _malloc_internal(3 * sizeof(*newarray)); 1833 newarray[0] = newlist; 1834 newarray[1] = (old_property_list *)cls->ext->propertyLists; 1835 newarray[2] = nil; 1836 cls->ext->propertyLists = newarray; 1837 cls->clearInfo(CLS_NO_PROPERTY_ARRAY); 1838 } 1839 else { 1840 // cls has a property array - make a bigger one 1841 old_property_list **newarray; 1842 int count = 0; 1843 while (cls->ext->propertyLists[count]) count++; 1844 newarray = (old_property_list **) 1845 _malloc_internal((count+2) * sizeof(*newarray)); 1846 newarray[0] = newlist; 1847 memcpy(&newarray[1], &cls->ext->propertyLists[0], 1848 count * sizeof(*newarray)); 1849 newarray[count+1] = nil; 1850 free(cls->ext->propertyLists); 1851 cls->ext->propertyLists = newarray; 1852 } 1853 1854 mutex_unlock(&classLock); 1855 1856 return YES; 1857} 1858 1859 1860/*********************************************************************** 1861* class_addProperty 1862* Adds a property to a class. Returns NO if the proeprty already exists. 1863* Locking: acquires classLock 1864**********************************************************************/ 1865static BOOL 1866_class_addProperty(Class cls, const char *name, 1867 const objc_property_attribute_t *attrs, unsigned int count, 1868 BOOL replace) 1869{ 1870 if (!cls) return NO; 1871 if (!name) return NO; 1872 1873 old_property *prop = oldproperty(class_getProperty(cls, name)); 1874 if (prop && !replace) { 1875 // already exists, refuse to replace 1876 return NO; 1877 } 1878 else if (prop) { 1879 // replace existing 1880 mutex_lock(&classLock); 1881 try_free(prop->attributes); 1882 prop->attributes = copyPropertyAttributeString(attrs, count); 1883 mutex_unlock(&classLock); 1884 return YES; 1885 } 1886 else { 1887 // add new 1888 old_property_list proplist; 1889 proplist.entsize = sizeof(old_property); 1890 proplist.count = 1; 1891 proplist.first.name = _strdup_internal(name); 1892 proplist.first.attributes = copyPropertyAttributeString(attrs, count); 1893 1894 return _class_addProperties(cls, &proplist); 1895 } 1896} 1897 1898BOOL 1899class_addProperty(Class cls, const char *name, 1900 const objc_property_attribute_t *attrs, unsigned int n) 1901{ 1902 return _class_addProperty(cls, name, attrs, n, NO); 1903} 1904 1905void 1906class_replaceProperty(Class cls, const char *name, 1907 const objc_property_attribute_t *attrs, unsigned int n) 1908{ 1909 _class_addProperty(cls, name, attrs, n, YES); 1910} 1911 1912 1913/*********************************************************************** 1914* class_copyProtocolList. Returns a heap block containing the 1915* protocols implemented by the class, or nil if the class 1916* implements no protocols. Caller must free the block. 1917* Does not copy any superclass's protocols. 1918**********************************************************************/ 1919Protocol * __unsafe_unretained * 1920class_copyProtocolList(Class cls, unsigned int *outCount) 1921{ 1922 old_protocol_list *plist; 1923 Protocol **result = nil; 1924 unsigned int count = 0; 1925 unsigned int p; 1926 1927 if (!cls) { 1928 if (outCount) *outCount = 0; 1929 return nil; 1930 } 1931 1932 mutex_lock(&classLock); 1933 1934 for (plist = cls->protocols; plist != nil; plist = plist->next) { 1935 count += (int)plist->count; 1936 } 1937 1938 if (count > 0) { 1939 result = (Protocol **)malloc((count+1) * sizeof(Protocol *)); 1940 1941 for (p = 0, plist = cls->protocols; 1942 plist != nil; 1943 plist = plist->next) 1944 { 1945 int i; 1946 for (i = 0; i < plist->count; i++) { 1947 result[p++] = (Protocol *)plist->list[i]; 1948 } 1949 } 1950 result[p] = nil; 1951 } 1952 1953 mutex_unlock(&classLock); 1954 1955 if (outCount) *outCount = count; 1956 return result; 1957} 1958 1959 1960/*********************************************************************** 1961* class_getProperty. Return the named property. 1962**********************************************************************/ 1963objc_property_t class_getProperty(Class cls, const char *name) 1964{ 1965 old_property *result; 1966 if (!cls || !name) return nil; 1967 1968 mutex_lock(&classLock); 1969 1970 for (result = nil; cls && !result; cls = cls->superclass) { 1971 uintptr_t iterator = 0; 1972 old_property_list *plist; 1973 while ((plist = nextPropertyList(cls, &iterator))) { 1974 uint32_t i; 1975 for (i = 0; i < plist->count; i++) { 1976 old_property *p = property_list_nth(plist, i); 1977 if (0 == strcmp(name, p->name)) { 1978 result = p; 1979 goto done; 1980 } 1981 } 1982 } 1983 } 1984 1985 done: 1986 mutex_unlock(&classLock); 1987 1988 return (objc_property_t)result; 1989} 1990 1991 1992/*********************************************************************** 1993* class_copyPropertyList. Returns a heap block containing the 1994* properties declared in the class, or nil if the class 1995* declares no properties. Caller must free the block. 1996* Does not copy any superclass's properties. 1997**********************************************************************/ 1998objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount) 1999{ 2000 old_property_list *plist; 2001 uintptr_t iterator = 0; 2002 old_property **result = nil; 2003 unsigned int count = 0; 2004 unsigned int p, i; 2005 2006 if (!cls) { 2007 if (outCount) *outCount = 0; 2008 return nil; 2009 } 2010 2011 mutex_lock(&classLock); 2012 2013 iterator = 0; 2014 while ((plist = nextPropertyList(cls, &iterator))) { 2015 count += plist->count; 2016 } 2017 2018 if (count > 0) { 2019 result = (old_property **)malloc((count+1) * sizeof(old_property *)); 2020 2021 p = 0; 2022 iterator = 0; 2023 while ((plist = nextPropertyList(cls, &iterator))) { 2024 for (i = 0; i < plist->count; i++) { 2025 result[p++] = property_list_nth(plist, i); 2026 } 2027 } 2028 result[p] = nil; 2029 } 2030 2031 mutex_unlock(&classLock); 2032 2033 if (outCount) *outCount = count; 2034 return (objc_property_t *)result; 2035} 2036 2037 2038/*********************************************************************** 2039* class_copyMethodList. Returns a heap block containing the 2040* methods implemented by the class, or nil if the class 2041* implements no methods. Caller must free the block. 2042* Does not copy any superclass's methods. 2043**********************************************************************/ 2044Method *class_copyMethodList(Class cls, unsigned int *outCount) 2045{ 2046 old_method_list *mlist; 2047 void *iterator = nil; 2048 Method *result = nil; 2049 unsigned int count = 0; 2050 unsigned int m; 2051 2052 if (!cls) { 2053 if (outCount) *outCount = 0; 2054 return nil; 2055 } 2056 2057 mutex_lock(&methodListLock); 2058 2059 iterator = nil; 2060 while ((mlist = nextMethodList(cls, &iterator))) { 2061 count += mlist->method_count; 2062 } 2063 2064 if (count > 0) { 2065 result = (Method *)malloc((count+1) * sizeof(Method)); 2066 2067 m = 0; 2068 iterator = nil; 2069 while ((mlist = nextMethodList(cls, &iterator))) { 2070 int i; 2071 for (i = 0; i < mlist->method_count; i++) { 2072 Method aMethod = (Method)&mlist->method_list[i]; 2073 if (ignoreSelector(method_getName(aMethod))) { 2074 count--; 2075 continue; 2076 } 2077 result[m++] = aMethod; 2078 } 2079 } 2080 result[m] = nil; 2081 } 2082 2083 mutex_unlock(&methodListLock); 2084 2085 if (outCount) *outCount = count; 2086 return result; 2087} 2088 2089 2090/*********************************************************************** 2091* class_copyIvarList. Returns a heap block containing the 2092* ivars declared in the class, or nil if the class 2093* declares no ivars. Caller must free the block. 2094* Does not copy any superclass's ivars. 2095**********************************************************************/ 2096Ivar *class_copyIvarList(Class cls, unsigned int *outCount) 2097{ 2098 Ivar *result = nil; 2099 unsigned int count = 0; 2100 int i; 2101 2102 if (!cls) { 2103 if (outCount) *outCount = 0; 2104 return nil; 2105 } 2106 2107 if (cls->ivars) { 2108 count = cls->ivars->ivar_count; 2109 } 2110 2111 if (count > 0) { 2112 result = (Ivar *)malloc((count+1) * sizeof(Ivar)); 2113 2114 for (i = 0; i < cls->ivars->ivar_count; i++) { 2115 result[i] = (Ivar)&cls->ivars->ivar_list[i]; 2116 } 2117 result[i] = nil; 2118 } 2119 2120 if (outCount) *outCount = count; 2121 return result; 2122} 2123 2124 2125/*********************************************************************** 2126* objc_allocateClass. 2127**********************************************************************/ 2128 2129void set_superclass(Class cls, Class supercls, BOOL cls_is_new) 2130{ 2131 Class meta = cls->ISA(); 2132 2133 if (supercls) { 2134 cls->superclass = supercls; 2135 meta->superclass = supercls->ISA(); 2136 meta->initIsa(supercls->ISA()->ISA()); 2137 2138 // Propagate C++ cdtors from superclass. 2139 if (supercls->info & CLS_HAS_CXX_STRUCTORS) { 2140 if (cls_is_new) cls->info |= CLS_HAS_CXX_STRUCTORS; 2141 else cls->setInfo(CLS_HAS_CXX_STRUCTORS); 2142 } 2143 2144 // Superclass is no longer a leaf for cache flushing 2145 if (supercls->info & CLS_LEAF) { 2146 supercls->clearInfo(CLS_LEAF); 2147 supercls->ISA()->clearInfo(CLS_LEAF); 2148 } 2149 } else { 2150 cls->superclass = Nil; // superclass of root class is nil 2151 meta->superclass = cls; // superclass of root metaclass is root class 2152 meta->initIsa(meta); // metaclass of root metaclass is root metaclass 2153 2154 // Root class is never a leaf for cache flushing, because the 2155 // root metaclass is a subclass. (This could be optimized, but 2156 // is too uncommon to bother.) 2157 cls->clearInfo(CLS_LEAF); 2158 meta->clearInfo(CLS_LEAF); 2159 } 2160} 2161 2162// &UnsetLayout is the default ivar layout during class construction 2163static const uint8_t UnsetLayout = 0; 2164 2165Class objc_initializeClassPair(Class supercls, const char *name, Class cls, Class meta) 2166{ 2167 // Connect to superclasses and metaclasses 2168 cls->initIsa(meta); 2169 set_superclass(cls, supercls, YES); 2170 2171 // Set basic info 2172 cls->name = _strdup_internal(name); 2173 meta->name = _strdup_internal(name); 2174 cls->version = 0; 2175 meta->version = 7; 2176 cls->info = CLS_CLASS | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF; 2177 meta->info = CLS_META | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF; 2178 2179 // Set instance size based on superclass. 2180 if (supercls) { 2181 cls->instance_size = supercls->instance_size; 2182 meta->instance_size = supercls->ISA()->instance_size; 2183 } else { 2184 cls->instance_size = sizeof(Class); // just an isa 2185 meta->instance_size = sizeof(objc_class); 2186 } 2187 2188 // No ivars. No methods. Empty cache. No protocols. No layout. Empty ext. 2189 cls->ivars = nil; 2190 cls->methodLists = nil; 2191 cls->cache = (Cache)&_objc_empty_cache; 2192 cls->protocols = nil; 2193 cls->ivar_layout = &UnsetLayout; 2194 cls->ext = nil; 2195 allocateExt(cls); 2196 cls->ext->weak_ivar_layout = &UnsetLayout; 2197 2198 meta->ivars = nil; 2199 meta->methodLists = nil; 2200 meta->cache = (Cache)&_objc_empty_cache; 2201 meta->protocols = nil; 2202 meta->ext = nil; 2203 2204 return cls; 2205} 2206 2207Class objc_allocateClassPair(Class supercls, const char *name, 2208 size_t extraBytes) 2209{ 2210 Class cls, meta; 2211 2212 if (objc_getClass(name)) return nil; 2213 // fixme reserve class name against simultaneous allocation 2214 2215 if (supercls && (supercls->info & CLS_CONSTRUCTING)) { 2216 // Can't make subclass of an in-construction class 2217 return nil; 2218 } 2219 2220 // Allocate new classes. 2221 if (supercls) { 2222 cls = _calloc_class(supercls->ISA()->alignedInstanceSize() + extraBytes); 2223 meta = _calloc_class(supercls->ISA()->ISA()->alignedInstanceSize() + extraBytes); 2224 } else { 2225 cls = _calloc_class(sizeof(objc_class) + extraBytes); 2226 meta = _calloc_class(sizeof(objc_class) + extraBytes); 2227 } 2228 2229 2230 objc_initializeClassPair(supercls, name, cls, meta); 2231 2232 return cls; 2233} 2234 2235 2236void objc_registerClassPair(Class cls) 2237{ 2238 if ((cls->info & CLS_CONSTRUCTED) || 2239 (cls->ISA()->info & CLS_CONSTRUCTED)) 2240 { 2241 _objc_inform("objc_registerClassPair: class '%s' was already " 2242 "registered!", cls->name); 2243 return; 2244 } 2245 2246 if (!(cls->info & CLS_CONSTRUCTING) || 2247 !(cls->ISA()->info & CLS_CONSTRUCTING)) 2248 { 2249 _objc_inform("objc_registerClassPair: class '%s' was not " 2250 "allocated with objc_allocateClassPair!", cls->name); 2251 return; 2252 } 2253 2254 if (ISMETA(cls)) { 2255 _objc_inform("objc_registerClassPair: class '%s' is a metaclass, " 2256 "not a class!", cls->name); 2257 return; 2258 } 2259 2260 mutex_lock(&classLock); 2261 2262 // Build ivar layouts 2263 if (UseGC) { 2264 if (cls->ivar_layout != &UnsetLayout) { 2265 // Class builder already called class_setIvarLayout. 2266 } 2267 else if (!cls->superclass) { 2268 // Root class. Scan conservatively (should be isa ivar only). 2269 cls->ivar_layout = nil; 2270 } 2271 else if (cls->ivars == nil) { 2272 // No local ivars. Use superclass's layout. 2273 cls->ivar_layout = 2274 _ustrdup_internal(cls->superclass->ivar_layout); 2275 } 2276 else { 2277 // Has local ivars. Build layout based on superclass. 2278 Class supercls = cls->superclass; 2279 const uint8_t *superlayout = 2280 class_getIvarLayout(supercls); 2281 layout_bitmap bitmap = 2282 layout_bitmap_create(superlayout, supercls->instance_size, 2283 cls->instance_size, NO); 2284 int i; 2285 for (i = 0; i < cls->ivars->ivar_count; i++) { 2286 old_ivar *iv = &cls->ivars->ivar_list[i]; 2287 layout_bitmap_set_ivar(bitmap, iv->ivar_type, iv->ivar_offset); 2288 } 2289 cls->ivar_layout = layout_string_create(bitmap); 2290 layout_bitmap_free(bitmap); 2291 } 2292 2293 if (cls->ext->weak_ivar_layout != &UnsetLayout) { 2294 // Class builder already called class_setWeakIvarLayout. 2295 } 2296 else if (!cls->superclass) { 2297 // Root class. No weak ivars (should be isa ivar only) 2298 cls->ext->weak_ivar_layout = nil; 2299 } 2300 else if (cls->ivars == nil) { 2301 // No local ivars. Use superclass's layout. 2302 const uint8_t *weak = 2303 class_getWeakIvarLayout(cls->superclass); 2304 if (weak) { 2305 cls->ext->weak_ivar_layout = _ustrdup_internal(weak); 2306 } else { 2307 cls->ext->weak_ivar_layout = nil; 2308 } 2309 } 2310 else { 2311 // Has local ivars. Build layout based on superclass. 2312 // No way to add weak ivars yet. 2313 const uint8_t *weak = 2314 class_getWeakIvarLayout(cls->superclass); 2315 if (weak) { 2316 cls->ext->weak_ivar_layout = _ustrdup_internal(weak); 2317 } else { 2318 cls->ext->weak_ivar_layout = nil; 2319 } 2320 } 2321 } 2322 2323 // Clear "under construction" bit, set "done constructing" bit 2324 cls->info &= ~CLS_CONSTRUCTING; 2325 cls->ISA()->info &= ~CLS_CONSTRUCTING; 2326 cls->info |= CLS_CONSTRUCTED; 2327 cls->ISA()->info |= CLS_CONSTRUCTED; 2328 2329 NXHashInsertIfAbsent(class_hash, cls); 2330 objc_addRegisteredClass(cls); 2331 //objc_addRegisteredClass(cls->ISA()); if we ever allocate classes from GC 2332 2333 mutex_unlock(&classLock); 2334} 2335 2336 2337Class objc_duplicateClass(Class original, const char *name, size_t extraBytes) 2338{ 2339 unsigned int count, i; 2340 old_method **originalMethods; 2341 old_method_list *duplicateMethods; 2342 // Don't use sizeof(objc_class) here because 2343 // instance_size has historically contained two extra words, 2344 // and instance_size is what objc_getIndexedIvars() actually uses. 2345 Class duplicate = 2346 _calloc_class(original->ISA()->alignedInstanceSize() + extraBytes); 2347 2348 duplicate->initIsa(original->ISA()); 2349 duplicate->superclass = original->superclass; 2350 duplicate->name = strdup(name); 2351 duplicate->version = original->version; 2352 duplicate->info = original->info & (CLS_CLASS|CLS_META|CLS_INITIALIZED|CLS_JAVA_HYBRID|CLS_JAVA_CLASS|CLS_HAS_CXX_STRUCTORS|CLS_HAS_LOAD_METHOD); 2353 duplicate->instance_size = original->instance_size; 2354 duplicate->ivars = original->ivars; 2355 // methodLists handled below 2356 duplicate->cache = (Cache)&_objc_empty_cache; 2357 duplicate->protocols = original->protocols; 2358 if (original->info & CLS_EXT) { 2359 duplicate->info |= original->info & (CLS_EXT|CLS_NO_PROPERTY_ARRAY); 2360 duplicate->ivar_layout = original->ivar_layout; 2361 if (original->ext) { 2362 duplicate->ext = (old_class_ext *)_malloc_internal(original->ext->size); 2363 memcpy(duplicate->ext, original->ext, original->ext->size); 2364 } else { 2365 duplicate->ext = nil; 2366 } 2367 } 2368 2369 // Method lists are deep-copied so they can be stomped. 2370 originalMethods = (old_method **)class_copyMethodList(original, &count); 2371 if (originalMethods) { 2372 duplicateMethods = (old_method_list *) 2373 calloc(sizeof(old_method_list) + 2374 (count-1)*sizeof(old_method), 1); 2375 duplicateMethods->obsolete = fixed_up_method_list; 2376 duplicateMethods->method_count = count; 2377 for (i = 0; i < count; i++) { 2378 duplicateMethods->method_list[i] = *(originalMethods[i]); 2379 } 2380 duplicate->methodLists = (old_method_list **)duplicateMethods; 2381 duplicate->info |= CLS_NO_METHOD_ARRAY; 2382 free(originalMethods); 2383 } 2384 2385 mutex_lock(&classLock); 2386 NXHashInsert(class_hash, duplicate); 2387 objc_addRegisteredClass(duplicate); 2388 mutex_unlock(&classLock); 2389 2390 return duplicate; 2391} 2392 2393 2394void objc_disposeClassPair(Class cls) 2395{ 2396 if (!(cls->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING)) || 2397 !(cls->ISA()->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING))) 2398 { 2399 // class not allocated with objc_allocateClassPair 2400 // disposing still-unregistered class is OK! 2401 _objc_inform("objc_disposeClassPair: class '%s' was not " 2402 "allocated with objc_allocateClassPair!", cls->name); 2403 return; 2404 } 2405 2406 if (ISMETA(cls)) { 2407 _objc_inform("objc_disposeClassPair: class '%s' is a metaclass, " 2408 "not a class!", cls->name); 2409 return; 2410 } 2411 2412 mutex_lock(&classLock); 2413 NXHashRemove(class_hash, cls); 2414 objc_removeRegisteredClass(cls); 2415 unload_class(cls->ISA()); 2416 unload_class(cls); 2417 mutex_unlock(&classLock); 2418} 2419 2420 2421/*********************************************************************** 2422* objc_constructInstance 2423* Creates an instance of `cls` at the location pointed to by `bytes`. 2424* `bytes` must point to at least class_getInstanceSize(cls) bytes of 2425* well-aligned zero-filled memory. 2426* The new object's isa is set. Any C++ constructors are called. 2427* Returns `bytes` if successful. Returns nil if `cls` or `bytes` is 2428* nil, or if C++ constructors fail. 2429**********************************************************************/ 2430id 2431objc_constructInstance(Class cls, void *bytes) 2432{ 2433 if (!cls || !bytes) return nil; 2434 2435 id obj = (id)bytes; 2436 2437 obj->initIsa(cls); 2438 2439 if (cls->hasCxxCtor()) { 2440 return object_cxxConstructFromClass(obj, cls); 2441 } else { 2442 return obj; 2443 } 2444} 2445 2446 2447/*********************************************************************** 2448* _class_createInstanceFromZone. Allocate an instance of the 2449* specified class with the specified number of bytes for indexed 2450* variables, in the specified zone. The isa field is set to the 2451* class, C++ default constructors are called, and all other fields are zeroed. 2452**********************************************************************/ 2453id 2454_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone) 2455{ 2456 void *bytes; 2457 size_t size; 2458 2459 // Can't create something for nothing 2460 if (!cls) return nil; 2461 2462 // Allocate and initialize 2463 size = cls->alignedInstanceSize() + extraBytes; 2464 2465 // CF requires all objects be at least 16 bytes. 2466 if (size < 16) size = 16; 2467 2468#if SUPPORT_GC 2469 if (UseGC) { 2470 bytes = auto_zone_allocate_object(gc_zone, size, 2471 AUTO_OBJECT_SCANNED, 0, 1); 2472 } else 2473#endif 2474 if (zone) { 2475 bytes = malloc_zone_calloc((malloc_zone_t *)zone, 1, size); 2476 } else { 2477 bytes = calloc(1, size); 2478 } 2479 2480 return objc_constructInstance(cls, bytes); 2481} 2482 2483 2484/*********************************************************************** 2485* _class_createInstance. Allocate an instance of the specified 2486* class with the specified number of bytes for indexed variables, in 2487* the default zone, using _class_createInstanceFromZone. 2488**********************************************************************/ 2489static id _class_createInstance(Class cls, size_t extraBytes) 2490{ 2491 return _class_createInstanceFromZone (cls, extraBytes, nil); 2492} 2493 2494 2495static id _object_copyFromZone(id oldObj, size_t extraBytes, void *zone) 2496{ 2497 id obj; 2498 size_t size; 2499 2500 if (!oldObj) return nil; 2501 2502 obj = (*_zoneAlloc)(oldObj->ISA(), extraBytes, zone); 2503 size = oldObj->ISA()->alignedInstanceSize() + extraBytes; 2504 2505 // fixme need C++ copy constructor 2506 objc_memmove_collectable(obj, oldObj, size); 2507 2508#if SUPPORT_GC 2509 if (UseGC) gc_fixup_weakreferences(obj, oldObj); 2510#endif 2511 2512 return obj; 2513} 2514 2515 2516/*********************************************************************** 2517* objc_destructInstance 2518* Destroys an instance without freeing memory. 2519* Calls C++ destructors. 2520* Removes associative references. 2521* Returns `obj`. Does nothing if `obj` is nil. 2522* Be warned that GC DOES NOT CALL THIS. If you edit this, also edit finalize. 2523* CoreFoundation and other clients do call this under GC. 2524**********************************************************************/ 2525void *objc_destructInstance(id obj) 2526{ 2527 if (obj) { 2528 Class isa = obj->getIsa(); 2529 2530 if (isa->hasCxxDtor()) { 2531 object_cxxDestruct(obj); 2532 } 2533 2534 if (isa->instancesHaveAssociatedObjects()) { 2535 _object_remove_assocations(obj); 2536 } 2537 2538 if (!UseGC) objc_clear_deallocating(obj); 2539 } 2540 2541 return obj; 2542} 2543 2544static id 2545_object_dispose(id anObject) 2546{ 2547 if (anObject==nil) return nil; 2548 2549 objc_destructInstance(anObject); 2550 2551#if SUPPORT_GC 2552 if (UseGC) { 2553 auto_zone_retain(gc_zone, anObject); // gc free expects rc==1 2554 } else 2555#endif 2556 { 2557 // only clobber isa for non-gc 2558 anObject->initIsa(_objc_getFreedObjectClass ()); 2559 } 2560 free(anObject); 2561 return nil; 2562} 2563 2564static id _object_copy(id oldObj, size_t extraBytes) 2565{ 2566 void *z = malloc_zone_from_ptr(oldObj); 2567 return _object_copyFromZone(oldObj, extraBytes, 2568 z ? z : malloc_default_zone()); 2569} 2570 2571static id _object_reallocFromZone(id anObject, size_t nBytes, void *zone) 2572{ 2573 id newObject; 2574 Class tmp; 2575 2576 if (anObject == nil) 2577 __objc_error(nil, "reallocating nil object"); 2578 2579 if (anObject->ISA() == _objc_getFreedObjectClass ()) 2580 __objc_error(anObject, "reallocating freed object"); 2581 2582 if (nBytes < anObject->ISA()->alignedInstanceSize()) 2583 __objc_error(anObject, "(%s, %zu) requested size too small", 2584 object_getClassName(anObject), nBytes); 2585 2586 // fixme need C++ copy constructor 2587 // fixme GC copy 2588 // Make sure not to modify space that has been declared free 2589 tmp = anObject->ISA(); 2590 anObject->initIsa(_objc_getFreedObjectClass ()); 2591 newObject = (id)malloc_zone_realloc((malloc_zone_t *)zone, anObject, nBytes); 2592 if (newObject) { 2593 newObject->initIsa(tmp); 2594 } else { 2595 // realloc failed, anObject is still alive 2596 anObject->initIsa(tmp); 2597 } 2598 return newObject; 2599} 2600 2601 2602static id _object_realloc(id anObject, size_t nBytes) 2603{ 2604 void *z = malloc_zone_from_ptr(anObject); 2605 return _object_reallocFromZone(anObject, 2606 nBytes, 2607 z ? z : malloc_default_zone()); 2608} 2609 2610id (*_alloc)(Class, size_t) = _class_createInstance; 2611id (*_copy)(id, size_t) = _object_copy; 2612id (*_realloc)(id, size_t) = _object_realloc; 2613id (*_dealloc)(id) = _object_dispose; 2614id (*_zoneAlloc)(Class, size_t, void *) = _class_createInstanceFromZone; 2615id (*_zoneCopy)(id, size_t, void *) = _object_copyFromZone; 2616id (*_zoneRealloc)(id, size_t, void *) = _object_reallocFromZone; 2617void (*_error)(id, const char *, va_list) = _objc_error; 2618 2619 2620id class_createInstance(Class cls, size_t extraBytes) 2621{ 2622 if (UseGC) { 2623 return _class_createInstance(cls, extraBytes); 2624 } else { 2625 return (*_alloc)(cls, extraBytes); 2626 } 2627} 2628 2629id class_createInstanceFromZone(Class cls, size_t extraBytes, void *z) 2630{ 2631 OBJC_WARN_DEPRECATED; 2632 if (UseGC) { 2633 return _class_createInstanceFromZone(cls, extraBytes, z); 2634 } else { 2635 return (*_zoneAlloc)(cls, extraBytes, z); 2636 } 2637} 2638 2639unsigned class_createInstances(Class cls, size_t extraBytes, 2640 id *results, unsigned num_requested) 2641{ 2642 if (UseGC || _alloc == &_class_createInstance) { 2643 return _class_createInstancesFromZone(cls, extraBytes, nil, 2644 results, num_requested); 2645 } else { 2646 // _alloc in use, which isn't understood by the batch allocator 2647 return 0; 2648 } 2649} 2650 2651id object_copy(id obj, size_t extraBytes) 2652{ 2653 if (UseGC) return _object_copy(obj, extraBytes); 2654 else return (*_copy)(obj, extraBytes); 2655} 2656 2657id object_copyFromZone(id obj, size_t extraBytes, void *z) 2658{ 2659 OBJC_WARN_DEPRECATED; 2660 if (UseGC) return _object_copyFromZone(obj, extraBytes, z); 2661 else return (*_zoneCopy)(obj, extraBytes, z); 2662} 2663 2664id object_dispose(id obj) 2665{ 2666 if (UseGC) return _object_dispose(obj); 2667 else return (*_dealloc)(obj); 2668} 2669 2670id object_realloc(id obj, size_t nBytes) 2671{ 2672 OBJC_WARN_DEPRECATED; 2673 if (UseGC) return _object_realloc(obj, nBytes); 2674 else return (*_realloc)(obj, nBytes); 2675} 2676 2677id object_reallocFromZone(id obj, size_t nBytes, void *z) 2678{ 2679 OBJC_WARN_DEPRECATED; 2680 if (UseGC) return _object_reallocFromZone(obj, nBytes, z); 2681 else return (*_zoneRealloc)(obj, nBytes, z); 2682} 2683 2684 2685/*********************************************************************** 2686* object_getIndexedIvars. 2687**********************************************************************/ 2688void *object_getIndexedIvars(id obj) 2689{ 2690 // ivars are tacked onto the end of the object 2691 if (!obj) return nil; 2692 if (obj->isTaggedPointer()) return nil; 2693 return ((char *) obj) + obj->ISA()->alignedInstanceSize(); 2694} 2695 2696 2697// ProKit SPI 2698Class class_setSuperclass(Class cls, Class newSuper) 2699{ 2700 Class oldSuper = cls->superclass; 2701 set_superclass(cls, newSuper, NO); 2702 flush_caches(cls, YES); 2703 return oldSuper; 2704} 2705#endif 2706