1/* 2 * Copyright (c) 2005-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#ifndef _OBJC_RUNTIME_NEW_H 25#define _OBJC_RUNTIME_NEW_H 26 27__BEGIN_DECLS 28 29#if __LP64__ 30typedef uint32_t mask_t; // x86_64 & arm64 asm are less efficient with 16-bits 31#else 32typedef uint16_t mask_t; 33#endif 34typedef uintptr_t cache_key_t; 35 36struct swift_class_t; 37 38 39struct bucket_t { 40private: 41 cache_key_t _key; 42 IMP _imp; 43 44public: 45 inline cache_key_t key() const { return _key; } 46 inline IMP imp() const { return (IMP)_imp; } 47 inline void setKey(cache_key_t newKey) { _key = newKey; } 48 inline void setImp(IMP newImp) { _imp = newImp; } 49 50 void set(cache_key_t newKey, IMP newImp); 51}; 52 53 54struct cache_t { 55 struct bucket_t *_buckets; 56 mask_t _mask; 57 mask_t _occupied; 58 59public: 60 struct bucket_t *buckets(); 61 mask_t mask(); 62 mask_t occupied(); 63 void incrementOccupied(); 64 void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask); 65 void setEmpty(); 66 67 mask_t capacity(); 68 bool canBeFreed(); 69 70 static size_t bytesForCapacity(uint32_t cap); 71 static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap); 72 73 void expand(); 74 void reallocate(mask_t oldCapacity, mask_t newCapacity); 75 struct bucket_t * find(cache_key_t key); 76 77 static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn)); 78}; 79 80 81// classref_t is unremapped class_t* 82typedef struct classref * classref_t; 83 84struct method_t { 85 SEL name; 86 const char *types; 87 IMP imp; 88 89 struct SortBySELAddress : 90 public std::binary_function<const method_t&, 91 const method_t&, bool> 92 { 93 bool operator() (const method_t& lhs, 94 const method_t& rhs) 95 { return lhs.name < rhs.name; } 96 }; 97}; 98 99struct method_list_t { 100 uint32_t entsize_NEVER_USE; // high bits used for fixup markers 101 uint32_t count; 102 method_t first; 103 104 uint32_t getEntsize() const { 105 return entsize_NEVER_USE & ~(uint32_t)3; 106 } 107 uint32_t getCount() const { 108 return count; 109 } 110 method_t& getOrEnd(uint32_t i) const { 111 assert(i <= count); 112 return *(method_t *)((uint8_t *)&first + i*getEntsize()); 113 } 114 method_t& get(uint32_t i) const { 115 assert(i < count); 116 return getOrEnd(i); 117 } 118 119 // iterate methods, taking entsize into account 120 // fixme need a proper const_iterator 121 struct method_iterator { 122 uint32_t entsize; 123 uint32_t index; // keeping track of this saves a divide in operator- 124 method_t* method; 125 126 typedef std::random_access_iterator_tag iterator_category; 127 typedef method_t value_type; 128 typedef ptrdiff_t difference_type; 129 typedef method_t* pointer; 130 typedef method_t& reference; 131 132 method_iterator() { } 133 134 method_iterator(const method_list_t& mlist, uint32_t start = 0) 135 : entsize(mlist.getEntsize()) 136 , index(start) 137 , method(&mlist.getOrEnd(start)) 138 { } 139 140 const method_iterator& operator += (ptrdiff_t delta) { 141 method = (method_t*)((uint8_t *)method + delta*entsize); 142 index += (int32_t)delta; 143 return *this; 144 } 145 const method_iterator& operator -= (ptrdiff_t delta) { 146 method = (method_t*)((uint8_t *)method - delta*entsize); 147 index -= (int32_t)delta; 148 return *this; 149 } 150 const method_iterator operator + (ptrdiff_t delta) const { 151 return method_iterator(*this) += delta; 152 } 153 const method_iterator operator - (ptrdiff_t delta) const { 154 return method_iterator(*this) -= delta; 155 } 156 157 method_iterator& operator ++ () { *this += 1; return *this; } 158 method_iterator& operator -- () { *this -= 1; return *this; } 159 method_iterator operator ++ (int) { 160 method_iterator result(*this); *this += 1; return result; 161 } 162 method_iterator operator -- (int) { 163 method_iterator result(*this); *this -= 1; return result; 164 } 165 166 ptrdiff_t operator - (const method_iterator& rhs) const { 167 return (ptrdiff_t)this->index - (ptrdiff_t)rhs.index; 168 } 169 170 method_t& operator * () const { return *method; } 171 method_t* operator -> () const { return method; } 172 173 operator method_t& () const { return *method; } 174 175 bool operator == (const method_iterator& rhs) { 176 return this->method == rhs.method; 177 } 178 bool operator != (const method_iterator& rhs) { 179 return this->method != rhs.method; 180 } 181 182 bool operator < (const method_iterator& rhs) { 183 return this->method < rhs.method; 184 } 185 bool operator > (const method_iterator& rhs) { 186 return this->method > rhs.method; 187 } 188 }; 189 190 method_iterator begin() const { return method_iterator(*this, 0); } 191 method_iterator end() const { return method_iterator(*this, getCount()); } 192 193}; 194 195struct ivar_t { 196#if __x86_64__ 197 // *offset was originally 64-bit on some x86_64 platforms. 198 // We read and write only 32 bits of it. 199 // Some metadata provides all 64 bits. This is harmless for unsigned 200 // little-endian values. 201 // Some code uses all 64 bits. class_addIvar() over-allocates the 202 // offset for their benefit. 203#endif 204 int32_t *offset; 205 const char *name; 206 const char *type; 207 // alignment is sometimes -1; use alignment() instead 208 uint32_t alignment_raw; 209 uint32_t size; 210 211 uint32_t alignment() { 212 if (alignment_raw == ~(uint32_t)0) return 1U << WORD_SHIFT; 213 return 1 << alignment_raw; 214 } 215}; 216 217struct ivar_list_t { 218 uint32_t entsize; 219 uint32_t count; 220 ivar_t first; 221}; 222 223struct property_t { 224 const char *name; 225 const char *attributes; 226}; 227 228struct property_list_t { 229 uint32_t entsize; 230 uint32_t count; 231 property_t first; 232}; 233 234typedef uintptr_t protocol_ref_t; // protocol_t *, but unremapped 235 236#define PROTOCOL_FIXED_UP (1<<31) // must never be set by compiler 237 238struct protocol_t : objc_object { 239 const char *mangledName; 240 struct protocol_list_t *protocols; 241 method_list_t *instanceMethods; 242 method_list_t *classMethods; 243 method_list_t *optionalInstanceMethods; 244 method_list_t *optionalClassMethods; 245 property_list_t *instanceProperties; 246 uint32_t size; // sizeof(protocol_t) 247 uint32_t flags; 248 const char **extendedMethodTypes; 249 250 // Fields below this point are allocated at runtime 251 // and are not present on disk. 252 const char *_demangledName; 253 254 const char *demangledName(); 255 256 const char *nameForLogging() { 257 return demangledName(); 258 } 259 260 bool isFixedUp() const { 261 return flags & PROTOCOL_FIXED_UP; 262 } 263 264 bool hasExtendedMethodTypesField() const { 265 return size >= (offsetof(protocol_t, extendedMethodTypes) 266 + sizeof(extendedMethodTypes)); 267 } 268 bool hasExtendedMethodTypes() const { 269 return hasExtendedMethodTypesField() && extendedMethodTypes; 270 } 271}; 272 273struct protocol_list_t { 274 // count is 64-bit by accident. 275 uintptr_t count; 276 protocol_ref_t list[0]; // variable-size 277}; 278 279struct class_ro_t { 280 uint32_t flags; 281 uint32_t instanceStart; 282 uint32_t instanceSize; 283#ifdef __LP64__ 284 uint32_t reserved; 285#endif 286 287 const uint8_t * ivarLayout; 288 289 const char * name; 290 const method_list_t * baseMethods; 291 const protocol_list_t * baseProtocols; 292 const ivar_list_t * ivars; 293 294 const uint8_t * weakIvarLayout; 295 const property_list_t *baseProperties; 296}; 297 298struct class_rw_t { 299 uint32_t flags; 300 uint32_t version; 301 302 const class_ro_t *ro; 303 304 union { 305 method_list_t **method_lists; // RW_METHOD_ARRAY == 1 306 method_list_t *method_list; // RW_METHOD_ARRAY == 0 307 }; 308 struct chained_property_list *properties; 309 const protocol_list_t ** protocols; 310 311 Class firstSubclass; 312 Class nextSiblingClass; 313 314 char *demangledName; 315 316 void setFlags(uint32_t set) 317 { 318 OSAtomicOr32Barrier(set, &flags); 319 } 320 321 void clearFlags(uint32_t clear) 322 { 323 OSAtomicXor32Barrier(clear, &flags); 324 } 325 326 // set and clear must not overlap 327 void changeFlags(uint32_t set, uint32_t clear) 328 { 329 assert((set & clear) == 0); 330 331 uint32_t oldf, newf; 332 do { 333 oldf = flags; 334 newf = (oldf | set) & ~clear; 335 } while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags)); 336 } 337}; 338 339 340// class_data_bits_t is the class_t->data field (class_rw_t pointer plus flags) 341// The extra bits are optimized for the retain/release and alloc/dealloc paths. 342 343// Values for class_ro_t->flags 344// These are emitted by the compiler and are part of the ABI. 345// class is a metaclass 346#define RO_META (1<<0) 347// class is a root class 348#define RO_ROOT (1<<1) 349// class has .cxx_construct/destruct implementations 350#define RO_HAS_CXX_STRUCTORS (1<<2) 351// class has +load implementation 352// #define RO_HAS_LOAD_METHOD (1<<3) 353// class has visibility=hidden set 354#define RO_HIDDEN (1<<4) 355// class has attribute(objc_exception): OBJC_EHTYPE_$_ThisClass is non-weak 356#define RO_EXCEPTION (1<<5) 357// this bit is available for reassignment 358// #define RO_REUSE_ME (1<<6) 359// class compiled with -fobjc-arc (automatic retain/release) 360#define RO_IS_ARR (1<<7) 361// class has .cxx_destruct but no .cxx_construct (with RO_HAS_CXX_STRUCTORS) 362#define RO_HAS_CXX_DTOR_ONLY (1<<8) 363 364// class is in an unloadable bundle - must never be set by compiler 365#define RO_FROM_BUNDLE (1<<29) 366// class is unrealized future class - must never be set by compiler 367#define RO_FUTURE (1<<30) 368// class is realized - must never be set by compiler 369#define RO_REALIZED (1<<31) 370 371// Values for class_rw_t->flags 372// These are not emitted by the compiler and are never used in class_ro_t. 373// Their presence should be considered in future ABI versions. 374// class_t->data is class_rw_t, not class_ro_t 375#define RW_REALIZED (1<<31) 376// class is unresolved future class 377#define RW_FUTURE (1<<30) 378// class is initialized 379#define RW_INITIALIZED (1<<29) 380// class is initializing 381#define RW_INITIALIZING (1<<28) 382// class_rw_t->ro is heap copy of class_ro_t 383#define RW_COPIED_RO (1<<27) 384// class allocated but not yet registered 385#define RW_CONSTRUCTING (1<<26) 386// class allocated and registered 387#define RW_CONSTRUCTED (1<<25) 388// GC: class has unsafe finalize method 389#define RW_FINALIZE_ON_MAIN_THREAD (1<<24) 390// class +load has been called 391#define RW_LOADED (1<<23) 392#if !SUPPORT_NONPOINTER_ISA 393// class instances may have associative references 394#define RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS (1<<22) 395#endif 396// class has instance-specific GC layout 397#define RW_HAS_INSTANCE_SPECIFIC_LAYOUT (1 << 21) 398// class's method list is an array of method lists 399#define RW_METHOD_ARRAY (1<<20) 400// class has started realizing but not yet completed it 401#define RW_REALIZING (1<<19) 402 403// NOTE: MORE RW_ FLAGS DEFINED BELOW 404 405 406// Values for class_rw_t->flags or class_t->bits 407// These flags are optimized for retain/release and alloc/dealloc 408// 64-bit stores more of them in class_t->bits to reduce pointer indirection. 409 410#if !__LP64__ 411 412// class or superclass has .cxx_construct implementation 413#define RW_HAS_CXX_CTOR (1<<18) 414// class or superclass has .cxx_destruct implementation 415#define RW_HAS_CXX_DTOR (1<<17) 416// class or superclass has default alloc/allocWithZone: implementation 417// Note this is is stored in the metaclass. 418#define RW_HAS_DEFAULT_AWZ (1<<16) 419// class's instances requires raw isa 420// not tracked for 32-bit because it only applies to non-pointer isa 421// #define RW_REQUIRES_RAW_ISA 422 423// class is a Swift class 424#define FAST_IS_SWIFT (1UL<<0) 425// class or superclass has default retain/release/autorelease/retainCount/ 426// _tryRetain/_isDeallocating/retainWeakReference/allowsWeakReference 427#define FAST_HAS_DEFAULT_RR (1UL<<1) 428// data pointer 429#define FAST_DATA_MASK 0xfffffffcUL 430 431#elif 1 432// Leaks-compatible version that steals low bits only. 433 434// class or superclass has .cxx_construct implementation 435#define RW_HAS_CXX_CTOR (1<<18) 436// class or superclass has .cxx_destruct implementation 437#define RW_HAS_CXX_DTOR (1<<17) 438// class or superclass has default alloc/allocWithZone: implementation 439// Note this is is stored in the metaclass. 440#define RW_HAS_DEFAULT_AWZ (1<<16) 441 442// class is a Swift class 443#define FAST_IS_SWIFT (1UL<<0) 444// class or superclass has default retain/release/autorelease/retainCount/ 445// _tryRetain/_isDeallocating/retainWeakReference/allowsWeakReference 446#define FAST_HAS_DEFAULT_RR (1UL<<1) 447// class's instances requires raw isa 448#define FAST_REQUIRES_RAW_ISA (1UL<<2) 449// data pointer 450#define FAST_DATA_MASK 0x00007ffffffffff8UL 451 452#else 453// Leaks-incompatible version that steals lots of bits. 454 455// class is a Swift class 456#define FAST_IS_SWIFT (1UL<<0) 457// class's instances requires raw isa 458#define FAST_REQUIRES_RAW_ISA (1UL<<1) 459// class or superclass has .cxx_destruct implementation 460// This bit is aligned with isa_t->hasCxxDtor to save an instruction. 461#define FAST_HAS_CXX_DTOR (1UL<<2) 462// data pointer 463#define FAST_DATA_MASK 0x00007ffffffffff8UL 464// class or superclass has .cxx_construct implementation 465#define FAST_HAS_CXX_CTOR (1UL<<47) 466// class or superclass has default alloc/allocWithZone: implementation 467// Note this is is stored in the metaclass. 468#define FAST_HAS_DEFAULT_AWZ (1UL<<48) 469// class or superclass has default retain/release/autorelease/retainCount/ 470// _tryRetain/_isDeallocating/retainWeakReference/allowsWeakReference 471#define FAST_HAS_DEFAULT_RR (1UL<<49) 472// summary bit for fast alloc path: !hasCxxCtor and 473// !requiresRawIsa and instanceSize fits into shiftedSize 474#define FAST_ALLOC (1UL<<50) 475// instance size in units of 16 bytes 476// or 0 if the instance size is too big in this field 477// This field must be LAST 478#define FAST_SHIFTED_SIZE_SHIFT 51 479 480// FAST_ALLOC means 481// FAST_HAS_CXX_CTOR is set 482// FAST_REQUIRES_RAW_ISA is not set 483// FAST_SHIFTED_SIZE is not zero 484// FAST_ALLOC does NOT check FAST_HAS_DEFAULT_AWZ because that 485// bit is stored on the metaclass. 486#define FAST_ALLOC_MASK (FAST_HAS_CXX_CTOR | FAST_REQUIRES_RAW_ISA) 487#define FAST_ALLOC_VALUE (0) 488 489#endif 490 491 492struct class_data_bits_t { 493 494 // Values are the FAST_ flags above. 495 uintptr_t bits; 496private: 497 bool getBit(uintptr_t bit) 498 { 499 return bits & bit; 500 } 501 502#if FAST_ALLOC 503 static uintptr_t updateFastAlloc(uintptr_t oldBits, uintptr_t change) 504 { 505 if (change & FAST_ALLOC_MASK) { 506 if (((oldBits & FAST_ALLOC_MASK) == FAST_ALLOC_VALUE) && 507 ((oldBits >> FAST_SHIFTED_SIZE_SHIFT) != 0)) 508 { 509 oldBits |= FAST_ALLOC; 510 } else { 511 oldBits &= ~FAST_ALLOC; 512 } 513 } 514 return oldBits; 515 } 516#else 517 static uintptr_t updateFastAlloc(uintptr_t oldBits, uintptr_t change) { 518 return oldBits; 519 } 520#endif 521 522 void setBits(uintptr_t set) 523 { 524 uintptr_t oldBits; 525 uintptr_t newBits; 526 do { 527 oldBits = LoadExclusive(&bits); 528 newBits = updateFastAlloc(oldBits | set, set); 529 } while (!StoreReleaseExclusive(&bits, oldBits, newBits)); 530 } 531 532 void clearBits(uintptr_t clear) 533 { 534 uintptr_t oldBits; 535 uintptr_t newBits; 536 do { 537 oldBits = LoadExclusive(&bits); 538 newBits = updateFastAlloc(oldBits & ~clear, clear); 539 } while (!StoreReleaseExclusive(&bits, oldBits, newBits)); 540 } 541 542public: 543 544 class_rw_t* data() { 545 return (class_rw_t *)(bits & FAST_DATA_MASK); 546 } 547 void setData(class_rw_t *newData) 548 { 549 assert(!data() || (newData->flags & (RW_REALIZING | RW_FUTURE))); 550 // Set during realization or construction only. No locking needed. 551 bits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData; 552 } 553 554 bool hasDefaultRR() { 555 return getBit(FAST_HAS_DEFAULT_RR); 556 } 557 void setHasDefaultRR() { 558 setBits(FAST_HAS_DEFAULT_RR); 559 } 560 void setHasCustomRR() { 561 clearBits(FAST_HAS_DEFAULT_RR); 562 } 563 564#if FAST_HAS_DEFAULT_AWZ 565 bool hasDefaultAWZ() { 566 return getBit(FAST_HAS_DEFAULT_AWZ); 567 } 568 void setHasDefaultAWZ() { 569 setBits(FAST_HAS_DEFAULT_AWZ); 570 } 571 void setHasCustomAWZ() { 572 clearBits(FAST_HAS_DEFAULT_AWZ); 573 } 574#else 575 bool hasDefaultAWZ() { 576 return data()->flags & RW_HAS_DEFAULT_AWZ; 577 } 578 void setHasDefaultAWZ() { 579 data()->setFlags(RW_HAS_DEFAULT_AWZ); 580 } 581 void setHasCustomAWZ() { 582 data()->clearFlags(RW_HAS_DEFAULT_AWZ); 583 } 584#endif 585 586#if FAST_HAS_CXX_CTOR 587 bool hasCxxCtor() { 588 return getBit(FAST_HAS_CXX_CTOR); 589 } 590 void setHasCxxCtor() { 591 setBits(FAST_HAS_CXX_CTOR); 592 } 593#else 594 bool hasCxxCtor() { 595 return data()->flags & RW_HAS_CXX_CTOR; 596 } 597 void setHasCxxCtor() { 598 data()->setFlags(RW_HAS_CXX_CTOR); 599 } 600#endif 601 602#if FAST_HAS_CXX_DTOR 603 bool hasCxxDtor() { 604 return getBit(FAST_HAS_CXX_DTOR); 605 } 606 void setHasCxxDtor() { 607 setBits(FAST_HAS_CXX_DTOR); 608 } 609#else 610 bool hasCxxDtor() { 611 return data()->flags & RW_HAS_CXX_DTOR; 612 } 613 void setHasCxxDtor() { 614 data()->setFlags(RW_HAS_CXX_DTOR); 615 } 616#endif 617 618#if FAST_REQUIRES_RAW_ISA 619 bool requiresRawIsa() { 620 return getBit(FAST_REQUIRES_RAW_ISA); 621 } 622 void setRequiresRawIsa() { 623 setBits(FAST_REQUIRES_RAW_ISA); 624 } 625#else 626# if SUPPORT_NONPOINTER_ISA 627# error oops 628# endif 629 bool requiresRawIsa() { 630 return true; 631 } 632 void setRequiresRawIsa() { 633 // nothing 634 } 635#endif 636 637#if FAST_ALLOC 638 size_t fastInstanceSize() 639 { 640 assert(bits & FAST_ALLOC); 641 return (bits >> FAST_SHIFTED_SIZE_SHIFT) * 16; 642 } 643 void setFastInstanceSize(size_t newSize) 644 { 645 // Set during realization or construction only. No locking needed. 646 assert(data()->flags & RW_REALIZING); 647 648 // Round up to 16-byte boundary, then divide to get 16-byte units 649 newSize = ((newSize + 15) & ~15) / 16; 650 651 uintptr_t newBits = newSize << FAST_SHIFTED_SIZE_SHIFT; 652 if ((newBits >> FAST_SHIFTED_SIZE_SHIFT) == newSize) { 653 int shift = WORD_BITS - FAST_SHIFTED_SIZE_SHIFT; 654 uintptr_t oldBits = (bits << shift) >> shift; 655 if ((oldBits & FAST_ALLOC_MASK) == FAST_ALLOC_VALUE) { 656 newBits |= FAST_ALLOC; 657 } 658 bits = oldBits | newBits; 659 } 660 } 661 662 bool canAllocFast() { 663 return bits & FAST_ALLOC; 664 } 665#else 666 size_t fastInstanceSize() { 667 abort(); 668 } 669 void setFastInstanceSize(size_t) { 670 // nothing 671 } 672 bool canAllocFast() { 673 return false; 674 } 675#endif 676 677 bool isSwift() { 678 return getBit(FAST_IS_SWIFT); 679 } 680 681 void setIsSwift() { 682 setBits(FAST_IS_SWIFT); 683 } 684}; 685 686 687struct objc_class : objc_object { 688 // Class ISA; 689 Class superclass; 690 cache_t cache; // formerly cache pointer and vtable 691 class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags 692 693 class_rw_t *data() { 694 return bits.data(); 695 } 696 void setData(class_rw_t *newData) { 697 bits.setData(newData); 698 } 699 700 void setInfo(uint32_t set) { 701 assert(isFuture() || isRealized()); 702 data()->setFlags(set); 703 } 704 705 void clearInfo(uint32_t clear) { 706 assert(isFuture() || isRealized()); 707 data()->clearFlags(clear); 708 } 709 710 // set and clear must not overlap 711 void changeInfo(uint32_t set, uint32_t clear) { 712 assert(isFuture() || isRealized()); 713 assert((set & clear) == 0); 714 data()->changeFlags(set, clear); 715 } 716 717 bool hasCustomRR() { 718 return ! bits.hasDefaultRR(); 719 } 720 void setHasDefaultRR() { 721 assert(isInitializing()); 722 bits.setHasDefaultRR(); 723 } 724 void setHasCustomRR(bool inherited = false); 725 void printCustomRR(bool inherited); 726 727 bool hasCustomAWZ() { 728 return ! bits.hasDefaultAWZ(); 729 } 730 void setHasDefaultAWZ() { 731 assert(isInitializing()); 732 bits.setHasDefaultAWZ(); 733 } 734 void setHasCustomAWZ(bool inherited = false); 735 void printCustomAWZ(bool inherited); 736 737 bool requiresRawIsa() { 738 return bits.requiresRawIsa(); 739 } 740 void setRequiresRawIsa(bool inherited = false); 741 void printRequiresRawIsa(bool inherited); 742 743 bool canAllocIndexed() { 744 return !requiresRawIsa(); 745 } 746 bool canAllocFast() { 747 return bits.canAllocFast(); 748 } 749 750 751 bool hasCxxCtor() { 752 // addSubclass() propagates this flag from the superclass. 753 assert(isRealized()); 754 return bits.hasCxxCtor(); 755 } 756 void setHasCxxCtor() { 757 bits.setHasCxxCtor(); 758 } 759 760 bool hasCxxDtor() { 761 // addSubclass() propagates this flag from the superclass. 762 assert(isRealized()); 763 return bits.hasCxxDtor(); 764 } 765 void setHasCxxDtor() { 766 bits.setHasCxxDtor(); 767 } 768 769 770 bool isSwift() { 771 return bits.isSwift(); 772 } 773 774 775#if SUPPORT_NONPOINTER_ISA 776 // Tracked in non-pointer isas; not tracked otherwise 777#else 778 bool instancesHaveAssociatedObjects() { 779 // this may be an unrealized future class in the CF-bridged case 780 assert(isFuture() || isRealized()); 781 return data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS; 782 } 783 784 void setInstancesHaveAssociatedObjects() { 785 // this may be an unrealized future class in the CF-bridged case 786 assert(isFuture() || isRealized()); 787 setInfo(RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS); 788 } 789#endif 790 791 bool shouldGrowCache() { 792 return true; 793 } 794 795 void setShouldGrowCache(bool) { 796 // fixme good or bad for memory use? 797 } 798 799 bool shouldFinalizeOnMainThread() { 800 // finishInitializing() propagates this flag from the superclass. 801 assert(isRealized()); 802 return data()->flags & RW_FINALIZE_ON_MAIN_THREAD; 803 } 804 805 void setShouldFinalizeOnMainThread() { 806 assert(isRealized()); 807 setInfo(RW_FINALIZE_ON_MAIN_THREAD); 808 } 809 810 bool isInitializing() { 811 return getMeta()->data()->flags & RW_INITIALIZING; 812 } 813 814 void setInitializing() { 815 assert(!isMetaClass()); 816 ISA()->setInfo(RW_INITIALIZING); 817 } 818 819 bool isInitialized() { 820 return getMeta()->data()->flags & RW_INITIALIZED; 821 } 822 823 void setInitialized(); 824 825 bool isLoadable() { 826 assert(isRealized()); 827 return true; // any class registered for +load is definitely loadable 828 } 829 830 IMP getLoadMethod(); 831 832 // Locking: To prevent concurrent realization, hold runtimeLock. 833 bool isRealized() { 834 return data()->flags & RW_REALIZED; 835 } 836 837 // Returns true if this is an unrealized future class. 838 // Locking: To prevent concurrent realization, hold runtimeLock. 839 bool isFuture() { 840 return data()->flags & RW_FUTURE; 841 } 842 843 bool isMetaClass() { 844 assert(this); 845 assert(isRealized()); 846 return data()->ro->flags & RO_META; 847 } 848 849 // NOT identical to this->ISA when this is a metaclass 850 Class getMeta() { 851 if (isMetaClass()) return (Class)this; 852 else return this->ISA(); 853 } 854 855 bool isRootClass() { 856 return superclass == nil; 857 } 858 bool isRootMetaclass() { 859 return ISA() == (Class)this; 860 } 861 862 const char *mangledName() { 863 // fixme can't assert locks here 864 assert(this); 865 866 if (isRealized() || isFuture()) { 867 return data()->ro->name; 868 } else { 869 return ((const class_ro_t *)data())->name; 870 } 871 } 872 873 const char *demangledName(bool realize = false); 874 const char *nameForLogging(); 875 876 // May be unaligned depending on class's ivars. 877 uint32_t unalignedInstanceSize() { 878 assert(isRealized()); 879 return data()->ro->instanceSize; 880 } 881 882 // Class's ivar size rounded up to a pointer-size boundary. 883 uint32_t alignedInstanceSize() { 884 return word_align(unalignedInstanceSize()); 885 } 886 887 size_t instanceSize(size_t extraBytes) { 888 size_t size = alignedInstanceSize() + extraBytes; 889 // CF requires all objects be at least 16 bytes. 890 if (size < 16) size = 16; 891 return size; 892 } 893 894 void setInstanceSize(uint32_t newSize) { 895 assert(isRealized()); 896 if (newSize != data()->ro->instanceSize) { 897 assert(data()->flags & RW_COPIED_RO); 898 *const_cast<uint32_t *>(&data()->ro->instanceSize) = newSize; 899 } 900 bits.setFastInstanceSize(newSize); 901 } 902}; 903 904 905struct swift_class_t : objc_class { 906 uint32_t flags; 907 uint32_t instanceAddressOffset; 908 uint32_t instanceSize; 909 uint16_t instanceAlignMask; 910 uint16_t reserved; 911 912 uint32_t classSize; 913 uint32_t classAddressOffset; 914 void *description; 915 // ... 916 917 void *baseAddress() { 918 return (void *)((uint8_t *)this - classAddressOffset); 919 } 920}; 921 922 923struct category_t { 924 const char *name; 925 classref_t cls; 926 struct method_list_t *instanceMethods; 927 struct method_list_t *classMethods; 928 struct protocol_list_t *protocols; 929 struct property_list_t *instanceProperties; 930}; 931 932struct objc_super2 { 933 id receiver; 934 Class current_class; 935}; 936 937struct message_ref_t { 938 IMP imp; 939 SEL sel; 940}; 941 942 943extern Method protocol_getMethod(protocol_t *p, SEL sel, bool isRequiredMethod, bool isInstanceMethod, bool recursive); 944 945static inline void 946foreach_realized_class_and_subclass_2(Class top, bool (^code)(Class)) 947{ 948 // rwlock_assert_writing(&runtimeLock); 949 assert(top); 950 Class cls = top; 951 while (1) { 952 if (!code(cls)) break; 953 954 if (cls->data()->firstSubclass) { 955 cls = cls->data()->firstSubclass; 956 } else { 957 while (!cls->data()->nextSiblingClass && cls != top) { 958 cls = cls->superclass; 959 } 960 if (cls == top) break; 961 cls = cls->data()->nextSiblingClass; 962 } 963 } 964} 965 966static inline void 967foreach_realized_class_and_subclass(Class top, void (^code)(Class)) 968{ 969 foreach_realized_class_and_subclass_2(top, ^bool(Class cls) { 970 code(cls); return true; 971 }); 972} 973 974__END_DECLS 975 976#endif 977