1/* 2 * Copyright (c) 2010-2012 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#include "objc-private.h" 25#include "NSObject.h" 26 27#include "objc-weak.h" 28#include "llvm-DenseMap.h" 29#include "NSObject.h" 30 31#include <malloc/malloc.h> 32#include <stdint.h> 33#include <stdbool.h> 34#include <mach/mach.h> 35#include <mach-o/dyld.h> 36#include <mach-o/nlist.h> 37#include <sys/types.h> 38#include <sys/mman.h> 39#include <libkern/OSAtomic.h> 40#include <Block.h> 41#include <map> 42#include <execinfo.h> 43 44@interface NSInvocation 45- (SEL)selector; 46@end 47 48 49#if TARGET_OS_MAC 50 51// NSObject used to be in Foundation/CoreFoundation. 52 53#define SYMBOL_ELSEWHERE_IN_3(sym, vers, n) \ 54 OBJC_EXPORT const char elsewhere_ ##n __asm__("$ld$hide$os" #vers "$" #sym); const char elsewhere_ ##n = 0 55#define SYMBOL_ELSEWHERE_IN_2(sym, vers, n) \ 56 SYMBOL_ELSEWHERE_IN_3(sym, vers, n) 57#define SYMBOL_ELSEWHERE_IN(sym, vers) \ 58 SYMBOL_ELSEWHERE_IN_2(sym, vers, __COUNTER__) 59 60#if __OBJC2__ 61# define NSOBJECT_ELSEWHERE_IN(vers) \ 62 SYMBOL_ELSEWHERE_IN(_OBJC_CLASS_$_NSObject, vers); \ 63 SYMBOL_ELSEWHERE_IN(_OBJC_METACLASS_$_NSObject, vers); \ 64 SYMBOL_ELSEWHERE_IN(_OBJC_IVAR_$_NSObject.isa, vers) 65#else 66# define NSOBJECT_ELSEWHERE_IN(vers) \ 67 SYMBOL_ELSEWHERE_IN(.objc_class_name_NSObject, vers) 68#endif 69 70#if TARGET_OS_IPHONE 71 NSOBJECT_ELSEWHERE_IN(5.1); 72 NSOBJECT_ELSEWHERE_IN(5.0); 73 NSOBJECT_ELSEWHERE_IN(4.3); 74 NSOBJECT_ELSEWHERE_IN(4.2); 75 NSOBJECT_ELSEWHERE_IN(4.1); 76 NSOBJECT_ELSEWHERE_IN(4.0); 77 NSOBJECT_ELSEWHERE_IN(3.2); 78 NSOBJECT_ELSEWHERE_IN(3.1); 79 NSOBJECT_ELSEWHERE_IN(3.0); 80 NSOBJECT_ELSEWHERE_IN(2.2); 81 NSOBJECT_ELSEWHERE_IN(2.1); 82 NSOBJECT_ELSEWHERE_IN(2.0); 83#else 84 NSOBJECT_ELSEWHERE_IN(10.7); 85 NSOBJECT_ELSEWHERE_IN(10.6); 86 NSOBJECT_ELSEWHERE_IN(10.5); 87 NSOBJECT_ELSEWHERE_IN(10.4); 88 NSOBJECT_ELSEWHERE_IN(10.3); 89 NSOBJECT_ELSEWHERE_IN(10.2); 90 NSOBJECT_ELSEWHERE_IN(10.1); 91 NSOBJECT_ELSEWHERE_IN(10.0); 92#endif 93 94// TARGET_OS_MAC 95#endif 96 97 98/*********************************************************************** 99* Weak ivar support 100**********************************************************************/ 101 102static id defaultBadAllocHandler(Class cls) 103{ 104 _objc_fatal("attempt to allocate object of class '%s' failed", 105 cls->nameForLogging()); 106} 107 108static id(*badAllocHandler)(Class) = &defaultBadAllocHandler; 109 110static id callBadAllocHandler(Class cls) 111{ 112 // fixme add re-entrancy protection in case allocation fails inside handler 113 return (*badAllocHandler)(cls); 114} 115 116void _objc_setBadAllocHandler(id(*newHandler)(Class)) 117{ 118 badAllocHandler = newHandler; 119} 120 121 122namespace { 123 124#if TARGET_OS_EMBEDDED 125# define SIDE_TABLE_STRIPE 8 126#else 127# define SIDE_TABLE_STRIPE 64 128#endif 129 130// should be a multiple of cache line size (64) 131#define SIDE_TABLE_SIZE 128 132 133// The order of these bits is important. 134#define SIDE_TABLE_WEAKLY_REFERENCED (1UL<<0) 135#define SIDE_TABLE_DEALLOCATING (1UL<<1) // MSB-ward of weak bit 136#define SIDE_TABLE_RC_ONE (1UL<<2) // MSB-ward of deallocating bit 137#define SIDE_TABLE_RC_PINNED (1UL<<(WORD_BITS-1)) 138 139#define SIDE_TABLE_RC_SHIFT 2 140#define SIDE_TABLE_FLAG_MASK (SIDE_TABLE_RC_ONE-1) 141 142// RefcountMap disguises its pointers because we 143// don't want the table to act as a root for `leaks`. 144typedef objc::DenseMap<DisguisedPtr<objc_object>,size_t,true> RefcountMap; 145 146class SideTable { 147private: 148 static uint8_t table_buf[SIDE_TABLE_STRIPE * SIDE_TABLE_SIZE]; 149 150public: 151 spinlock_t slock; 152 RefcountMap refcnts; 153 weak_table_t weak_table; 154 155 SideTable() : slock(SPINLOCK_INITIALIZER) 156 { 157 memset(&weak_table, 0, sizeof(weak_table)); 158 } 159 160 ~SideTable() 161 { 162 // never delete side_table in case other threads retain during exit 163 assert(0); 164 } 165 166 static SideTable *tableForPointer(const void *p) 167 { 168# if SIDE_TABLE_STRIPE == 1 169 return (SideTable *)table_buf; 170# else 171 uintptr_t a = (uintptr_t)p; 172 int index = ((a >> 4) ^ (a >> 9)) & (SIDE_TABLE_STRIPE - 1); 173 return (SideTable *)&table_buf[index * SIDE_TABLE_SIZE]; 174# endif 175 } 176 177 static void init() { 178 // use placement new instead of static ctor to avoid dtor at exit 179 for (int i = 0; i < SIDE_TABLE_STRIPE; i++) { 180 new (&table_buf[i * SIDE_TABLE_SIZE]) SideTable; 181 } 182 } 183}; 184 185STATIC_ASSERT(sizeof(SideTable) <= SIDE_TABLE_SIZE); 186__attribute__((aligned(SIDE_TABLE_SIZE))) uint8_t 187SideTable::table_buf[SIDE_TABLE_STRIPE * SIDE_TABLE_SIZE]; 188 189// anonymous namespace 190}; 191 192 193// 194// The -fobjc-arc flag causes the compiler to issue calls to objc_{retain/release/autorelease/retain_block} 195// 196 197id objc_retainBlock(id x) { 198 return (id)_Block_copy(x); 199} 200 201// 202// The following SHOULD be called by the compiler directly, but the request hasn't been made yet :-) 203// 204 205BOOL objc_should_deallocate(id object) { 206 return YES; 207} 208 209id 210objc_retain_autorelease(id obj) 211{ 212 return objc_autorelease(objc_retain(obj)); 213} 214 215 216void 217objc_storeStrong(id *location, id obj) 218{ 219 id prev = *location; 220 if (obj == prev) { 221 return; 222 } 223 objc_retain(obj); 224 *location = obj; 225 objc_release(prev); 226} 227 228 229/** 230 * This function stores a new value into a __weak variable. It would 231 * be used anywhere a __weak variable is the target of an assignment. 232 * 233 * @param location The address of the weak pointer itself 234 * @param newObj The new object this weak ptr should now point to 235 * 236 * @return \e newObj 237 */ 238id 239objc_storeWeak(id *location, id newObj) 240{ 241 id oldObj; 242 SideTable *oldTable; 243 SideTable *newTable; 244 spinlock_t *lock1; 245#if SIDE_TABLE_STRIPE > 1 246 spinlock_t *lock2; 247#endif 248 249 // Acquire locks for old and new values. 250 // Order by lock address to prevent lock ordering problems. 251 // Retry if the old value changes underneath us. 252 retry: 253 oldObj = *location; 254 255 oldTable = SideTable::tableForPointer(oldObj); 256 newTable = SideTable::tableForPointer(newObj); 257 258 lock1 = &newTable->slock; 259#if SIDE_TABLE_STRIPE > 1 260 lock2 = &oldTable->slock; 261 if (lock1 > lock2) { 262 spinlock_t *temp = lock1; 263 lock1 = lock2; 264 lock2 = temp; 265 } 266 if (lock1 != lock2) spinlock_lock(lock2); 267#endif 268 spinlock_lock(lock1); 269 270 if (*location != oldObj) { 271 spinlock_unlock(lock1); 272#if SIDE_TABLE_STRIPE > 1 273 if (lock1 != lock2) spinlock_unlock(lock2); 274#endif 275 goto retry; 276 } 277 278 weak_unregister_no_lock(&oldTable->weak_table, oldObj, location); 279 newObj = weak_register_no_lock(&newTable->weak_table, newObj, location); 280 // weak_register_no_lock returns nil if weak store should be rejected 281 282 // Set is-weakly-referenced bit in refcount table. 283 if (newObj && !newObj->isTaggedPointer()) { 284 newObj->setWeaklyReferenced_nolock(); 285 } 286 287 // Do not set *location anywhere else. That would introduce a race. 288 *location = newObj; 289 290 spinlock_unlock(lock1); 291#if SIDE_TABLE_STRIPE > 1 292 if (lock1 != lock2) spinlock_unlock(lock2); 293#endif 294 295 return newObj; 296} 297 298id 299objc_loadWeakRetained(id *location) 300{ 301 id result; 302 303 SideTable *table; 304 spinlock_t *lock; 305 306 retry: 307 result = *location; 308 if (!result) return nil; 309 310 table = SideTable::tableForPointer(result); 311 lock = &table->slock; 312 313 spinlock_lock(lock); 314 if (*location != result) { 315 spinlock_unlock(lock); 316 goto retry; 317 } 318 319 result = weak_read_no_lock(&table->weak_table, location); 320 321 spinlock_unlock(lock); 322 return result; 323} 324 325/** 326 * This loads the object referenced by a weak pointer and returns it, after 327 * retaining and autoreleasing the object to ensure that it stays alive 328 * long enough for the caller to use it. This function would be used 329 * anywhere a __weak variable is used in an expression. 330 * 331 * @param location The weak pointer address 332 * 333 * @return The object pointed to by \e location, or \c nil if \e location is \c nil. 334 */ 335id 336objc_loadWeak(id *location) 337{ 338 if (!*location) return nil; 339 return objc_autorelease(objc_loadWeakRetained(location)); 340} 341 342/** 343 * Initialize a fresh weak pointer to some object location. 344 * It would be used for code like: 345 * 346 * (The nil case) 347 * __weak id weakPtr; 348 * (The non-nil case) 349 * NSObject *o = ...; 350 * __weak id weakPtr = o; 351 * 352 * @param addr Address of __weak ptr. 353 * @param val Object ptr. 354 */ 355id 356objc_initWeak(id *addr, id val) 357{ 358 *addr = 0; 359 if (!val) return nil; 360 return objc_storeWeak(addr, val); 361} 362 363__attribute__((noinline, used)) void 364objc_destroyWeak_slow(id *addr) 365{ 366 SideTable *oldTable; 367 spinlock_t *lock; 368 id oldObj; 369 370 // No need to see weak refs, we are destroying 371 372 // Acquire lock for old value only 373 // retry if the old value changes underneath us 374 retry: 375 oldObj = *addr; 376 oldTable = SideTable::tableForPointer(oldObj); 377 378 lock = &oldTable->slock; 379 spinlock_lock(lock); 380 381 if (*addr != oldObj) { 382 spinlock_unlock(lock); 383 goto retry; 384 } 385 386 weak_unregister_no_lock(&oldTable->weak_table, oldObj, addr); 387 388 spinlock_unlock(lock); 389} 390 391/** 392 * Destroys the relationship between a weak pointer 393 * and the object it is referencing in the internal weak 394 * table. If the weak pointer is not referencing anything, 395 * there is no need to edit the weak table. 396 * 397 * @param addr The weak pointer address. 398 */ 399void 400objc_destroyWeak(id *addr) 401{ 402 if (!*addr) return; 403 return objc_destroyWeak_slow(addr); 404} 405 406/** 407 * This function copies a weak pointer from one location to another, 408 * when the destination doesn't already contain a weak pointer. It 409 * would be used for code like: 410 * 411 * __weak id weakPtr1 = ...; 412 * __weak id weakPtr2 = weakPtr1; 413 * 414 * @param to weakPtr2 in this ex 415 * @param from weakPtr1 416 */ 417void 418objc_copyWeak(id *to, id *from) 419{ 420 id val = objc_loadWeakRetained(from); 421 objc_initWeak(to, val); 422 objc_release(val); 423} 424 425/** 426 * Move a weak pointer from one location to another. 427 * Before the move, the destination must be uninitialized. 428 * After the move, the source is nil. 429 */ 430void 431objc_moveWeak(id *to, id *from) 432{ 433 objc_copyWeak(to, from); 434 objc_storeWeak(from, 0); 435} 436 437 438/*********************************************************************** 439 Autorelease pool implementation 440 441 A thread's autorelease pool is a stack of pointers. 442 Each pointer is either an object to release, or POOL_SENTINEL which is 443 an autorelease pool boundary. 444 A pool token is a pointer to the POOL_SENTINEL for that pool. When 445 the pool is popped, every object hotter than the sentinel is released. 446 The stack is divided into a doubly-linked list of pages. Pages are added 447 and deleted as necessary. 448 Thread-local storage points to the hot page, where newly autoreleased 449 objects are stored. 450**********************************************************************/ 451 452BREAKPOINT_FUNCTION(void objc_autoreleaseNoPool(id obj)); 453 454namespace { 455 456struct magic_t { 457 static const uint32_t M0 = 0xA1A1A1A1; 458# define M1 "AUTORELEASE!" 459 static const size_t M1_len = 12; 460 uint32_t m[4]; 461 462 magic_t() { 463 assert(M1_len == strlen(M1)); 464 assert(M1_len == 3 * sizeof(m[1])); 465 466 m[0] = M0; 467 strncpy((char *)&m[1], M1, M1_len); 468 } 469 470 ~magic_t() { 471 m[0] = m[1] = m[2] = m[3] = 0; 472 } 473 474 bool check() const { 475 return (m[0] == M0 && 0 == strncmp((char *)&m[1], M1, M1_len)); 476 } 477 478 bool fastcheck() const { 479#ifdef NDEBUG 480 return (m[0] == M0); 481#else 482 return check(); 483#endif 484 } 485 486# undef M1 487}; 488 489 490// Set this to 1 to mprotect() autorelease pool contents 491#define PROTECT_AUTORELEASEPOOL 0 492 493class AutoreleasePoolPage 494{ 495 496#define POOL_SENTINEL nil 497 static pthread_key_t const key = AUTORELEASE_POOL_KEY; 498 static uint8_t const SCRIBBLE = 0xA3; // 0xA3A3A3A3 after releasing 499 static size_t const SIZE = 500#if PROTECT_AUTORELEASEPOOL 501 PAGE_MAX_SIZE; // must be multiple of vm page size 502#else 503 PAGE_MAX_SIZE; // size and alignment, power of 2 504#endif 505 static size_t const COUNT = SIZE / sizeof(id); 506 507 magic_t const magic; 508 id *next; 509 pthread_t const thread; 510 AutoreleasePoolPage * const parent; 511 AutoreleasePoolPage *child; 512 uint32_t const depth; 513 uint32_t hiwat; 514 515 // SIZE-sizeof(*this) bytes of contents follow 516 517 static void * operator new(size_t size) { 518 return malloc_zone_memalign(malloc_default_zone(), SIZE, SIZE); 519 } 520 static void operator delete(void * p) { 521 return free(p); 522 } 523 524 inline void protect() { 525#if PROTECT_AUTORELEASEPOOL 526 mprotect(this, SIZE, PROT_READ); 527 check(); 528#endif 529 } 530 531 inline void unprotect() { 532#if PROTECT_AUTORELEASEPOOL 533 check(); 534 mprotect(this, SIZE, PROT_READ | PROT_WRITE); 535#endif 536 } 537 538 AutoreleasePoolPage(AutoreleasePoolPage *newParent) 539 : magic(), next(begin()), thread(pthread_self()), 540 parent(newParent), child(nil), 541 depth(parent ? 1+parent->depth : 0), 542 hiwat(parent ? parent->hiwat : 0) 543 { 544 if (parent) { 545 parent->check(); 546 assert(!parent->child); 547 parent->unprotect(); 548 parent->child = this; 549 parent->protect(); 550 } 551 protect(); 552 } 553 554 ~AutoreleasePoolPage() 555 { 556 check(); 557 unprotect(); 558 assert(empty()); 559 560 // Not recursive: we don't want to blow out the stack 561 // if a thread accumulates a stupendous amount of garbage 562 assert(!child); 563 } 564 565 566 void busted(bool die = true) 567 { 568 magic_t right; 569 (die ? _objc_fatal : _objc_inform) 570 ("autorelease pool page %p corrupted\n" 571 " magic 0x%08x 0x%08x 0x%08x 0x%08x\n" 572 " should be 0x%08x 0x%08x 0x%08x 0x%08x\n" 573 " pthread %p\n" 574 " should be %p\n", 575 this, 576 magic.m[0], magic.m[1], magic.m[2], magic.m[3], 577 right.m[0], right.m[1], right.m[2], right.m[3], 578 this->thread, pthread_self()); 579 } 580 581 void check(bool die = true) 582 { 583 if (!magic.check() || !pthread_equal(thread, pthread_self())) { 584 busted(die); 585 } 586 } 587 588 void fastcheck(bool die = true) 589 { 590 if (! magic.fastcheck()) { 591 busted(die); 592 } 593 } 594 595 596 id * begin() { 597 return (id *) ((uint8_t *)this+sizeof(*this)); 598 } 599 600 id * end() { 601 return (id *) ((uint8_t *)this+SIZE); 602 } 603 604 bool empty() { 605 return next == begin(); 606 } 607 608 bool full() { 609 return next == end(); 610 } 611 612 bool lessThanHalfFull() { 613 return (next - begin() < (end() - begin()) / 2); 614 } 615 616 id *add(id obj) 617 { 618 assert(!full()); 619 unprotect(); 620 id *ret = next; // faster than `return next-1` because of aliasing 621 *next++ = obj; 622 protect(); 623 return ret; 624 } 625 626 void releaseAll() 627 { 628 releaseUntil(begin()); 629 } 630 631 void releaseUntil(id *stop) 632 { 633 // Not recursive: we don't want to blow out the stack 634 // if a thread accumulates a stupendous amount of garbage 635 636 while (this->next != stop) { 637 // Restart from hotPage() every time, in case -release 638 // autoreleased more objects 639 AutoreleasePoolPage *page = hotPage(); 640 641 // fixme I think this `while` can be `if`, but I can't prove it 642 while (page->empty()) { 643 page = page->parent; 644 setHotPage(page); 645 } 646 647 page->unprotect(); 648 id obj = *--page->next; 649 memset((void*)page->next, SCRIBBLE, sizeof(*page->next)); 650 page->protect(); 651 652 if (obj != POOL_SENTINEL) { 653 objc_release(obj); 654 } 655 } 656 657 setHotPage(this); 658 659#ifndef NDEBUG 660 // we expect any children to be completely empty 661 for (AutoreleasePoolPage *page = child; page; page = page->child) { 662 assert(page->empty()); 663 } 664#endif 665 } 666 667 void kill() 668 { 669 // Not recursive: we don't want to blow out the stack 670 // if a thread accumulates a stupendous amount of garbage 671 AutoreleasePoolPage *page = this; 672 while (page->child) page = page->child; 673 674 AutoreleasePoolPage *deathptr; 675 do { 676 deathptr = page; 677 page = page->parent; 678 if (page) { 679 page->unprotect(); 680 page->child = nil; 681 page->protect(); 682 } 683 delete deathptr; 684 } while (deathptr != this); 685 } 686 687 static void tls_dealloc(void *p) 688 { 689 // reinstate TLS value while we work 690 setHotPage((AutoreleasePoolPage *)p); 691 pop(0); 692 setHotPage(nil); 693 } 694 695 static AutoreleasePoolPage *pageForPointer(const void *p) 696 { 697 return pageForPointer((uintptr_t)p); 698 } 699 700 static AutoreleasePoolPage *pageForPointer(uintptr_t p) 701 { 702 AutoreleasePoolPage *result; 703 uintptr_t offset = p % SIZE; 704 705 assert(offset >= sizeof(AutoreleasePoolPage)); 706 707 result = (AutoreleasePoolPage *)(p - offset); 708 result->fastcheck(); 709 710 return result; 711 } 712 713 714 static inline AutoreleasePoolPage *hotPage() 715 { 716 AutoreleasePoolPage *result = (AutoreleasePoolPage *) 717 tls_get_direct(key); 718 if (result) result->fastcheck(); 719 return result; 720 } 721 722 static inline void setHotPage(AutoreleasePoolPage *page) 723 { 724 if (page) page->fastcheck(); 725 tls_set_direct(key, (void *)page); 726 } 727 728 static inline AutoreleasePoolPage *coldPage() 729 { 730 AutoreleasePoolPage *result = hotPage(); 731 if (result) { 732 while (result->parent) { 733 result = result->parent; 734 result->fastcheck(); 735 } 736 } 737 return result; 738 } 739 740 741 static inline id *autoreleaseFast(id obj) 742 { 743 AutoreleasePoolPage *page = hotPage(); 744 if (page && !page->full()) { 745 return page->add(obj); 746 } else if (page) { 747 return autoreleaseFullPage(obj, page); 748 } else { 749 return autoreleaseNoPage(obj); 750 } 751 } 752 753 static __attribute__((noinline)) 754 id *autoreleaseFullPage(id obj, AutoreleasePoolPage *page) 755 { 756 // The hot page is full. 757 // Step to the next non-full page, adding a new page if necessary. 758 // Then add the object to that page. 759 assert(page == hotPage() && page->full()); 760 761 do { 762 if (page->child) page = page->child; 763 else page = new AutoreleasePoolPage(page); 764 } while (page->full()); 765 766 setHotPage(page); 767 return page->add(obj); 768 } 769 770 static __attribute__((noinline)) 771 id *autoreleaseNoPage(id obj) 772 { 773 // No pool in place. 774 assert(!hotPage()); 775 776 if (obj != POOL_SENTINEL && DebugMissingPools) { 777 // We are pushing an object with no pool in place, 778 // and no-pool debugging was requested by environment. 779 _objc_inform("MISSING POOLS: Object %p of class %s " 780 "autoreleased with no pool in place - " 781 "just leaking - break on " 782 "objc_autoreleaseNoPool() to debug", 783 (void*)obj, object_getClassName(obj)); 784 objc_autoreleaseNoPool(obj); 785 return nil; 786 } 787 788 // Install the first page. 789 AutoreleasePoolPage *page = new AutoreleasePoolPage(nil); 790 setHotPage(page); 791 792 // Push an autorelease pool boundary if it wasn't already requested. 793 if (obj != POOL_SENTINEL) { 794 page->add(POOL_SENTINEL); 795 } 796 797 // Push the requested object. 798 return page->add(obj); 799 } 800 801public: 802 static inline id autorelease(id obj) 803 { 804 assert(obj); 805 assert(!obj->isTaggedPointer()); 806 id *dest __unused = autoreleaseFast(obj); 807 assert(!dest || *dest == obj); 808 return obj; 809 } 810 811 812 static inline void *push() 813 { 814 id *dest = autoreleaseFast(POOL_SENTINEL); 815 assert(*dest == POOL_SENTINEL); 816 return dest; 817 } 818 819 static inline void pop(void *token) 820 { 821 AutoreleasePoolPage *page; 822 id *stop; 823 824 if (token) { 825 page = pageForPointer(token); 826 stop = (id *)token; 827 assert(*stop == POOL_SENTINEL); 828 } else { 829 // Token 0 is top-level pool 830 page = coldPage(); 831 assert(page); 832 stop = page->begin(); 833 } 834 835 if (PrintPoolHiwat) printHiwat(); 836 837 page->releaseUntil(stop); 838 839 // memory: delete empty children 840 // hysteresis: keep one empty child if this page is more than half full 841 // special case: delete everything for pop(0) 842 // special case: delete everything for pop(top) with DebugMissingPools 843 if (!token || 844 (DebugMissingPools && page->empty() && !page->parent)) 845 { 846 page->kill(); 847 setHotPage(nil); 848 } else if (page->child) { 849 if (page->lessThanHalfFull()) { 850 page->child->kill(); 851 } 852 else if (page->child->child) { 853 page->child->child->kill(); 854 } 855 } 856 } 857 858 static void init() 859 { 860 int r __unused = pthread_key_init_np(AutoreleasePoolPage::key, 861 AutoreleasePoolPage::tls_dealloc); 862 assert(r == 0); 863 } 864 865 void print() 866 { 867 _objc_inform("[%p] ................ PAGE %s %s %s", this, 868 full() ? "(full)" : "", 869 this == hotPage() ? "(hot)" : "", 870 this == coldPage() ? "(cold)" : ""); 871 check(false); 872 for (id *p = begin(); p < next; p++) { 873 if (*p == POOL_SENTINEL) { 874 _objc_inform("[%p] ################ POOL %p", p, p); 875 } else { 876 _objc_inform("[%p] %#16lx %s", 877 p, (unsigned long)*p, object_getClassName(*p)); 878 } 879 } 880 } 881 882 static void printAll() 883 { 884 _objc_inform("##############"); 885 _objc_inform("AUTORELEASE POOLS for thread %p", pthread_self()); 886 887 AutoreleasePoolPage *page; 888 ptrdiff_t objects = 0; 889 for (page = coldPage(); page; page = page->child) { 890 objects += page->next - page->begin(); 891 } 892 _objc_inform("%llu releases pending.", (unsigned long long)objects); 893 894 for (page = coldPage(); page; page = page->child) { 895 page->print(); 896 } 897 898 _objc_inform("##############"); 899 } 900 901 static void printHiwat() 902 { 903 // Check and propagate high water mark 904 // Ignore high water marks under 256 to suppress noise. 905 AutoreleasePoolPage *p = hotPage(); 906 uint32_t mark = p->depth*COUNT + (uint32_t)(p->next - p->begin()); 907 if (mark > p->hiwat && mark > 256) { 908 for( ; p; p = p->parent) { 909 p->unprotect(); 910 p->hiwat = mark; 911 p->protect(); 912 } 913 914 _objc_inform("POOL HIGHWATER: new high water mark of %u " 915 "pending autoreleases for thread %p:", 916 mark, pthread_self()); 917 918 void *stack[128]; 919 int count = backtrace(stack, sizeof(stack)/sizeof(stack[0])); 920 char **sym = backtrace_symbols(stack, count); 921 for (int i = 0; i < count; i++) { 922 _objc_inform("POOL HIGHWATER: %s", sym[i]); 923 } 924 free(sym); 925 } 926 } 927 928#undef POOL_SENTINEL 929}; 930 931// anonymous namespace 932}; 933 934 935/*********************************************************************** 936* Slow paths for inline control 937**********************************************************************/ 938 939#if SUPPORT_NONPOINTER_ISA 940 941NEVER_INLINE id 942objc_object::rootRetain_overflow(bool tryRetain) 943{ 944 return rootRetain(tryRetain, true); 945} 946 947 948NEVER_INLINE bool 949objc_object::rootRelease_underflow(bool performDealloc) 950{ 951 return rootRelease(performDealloc, true); 952} 953 954 955// Slow path of clearDeallocating() 956// for weakly-referenced objects with indexed isa 957NEVER_INLINE void 958objc_object::clearDeallocating_weak() 959{ 960 assert(isa.indexed && isa.weakly_referenced); 961 962 SideTable *table = SideTable::tableForPointer(this); 963 spinlock_lock(&table->slock); 964 weak_clear_no_lock(&table->weak_table, (id)this); 965 spinlock_unlock(&table->slock); 966} 967 968#endif 969 970__attribute__((noinline,used)) 971id 972objc_object::rootAutorelease2() 973{ 974 assert(!isTaggedPointer()); 975 return AutoreleasePoolPage::autorelease((id)this); 976} 977 978 979BREAKPOINT_FUNCTION( 980 void objc_overrelease_during_dealloc_error(void) 981); 982 983 984NEVER_INLINE 985bool 986objc_object::overrelease_error() 987{ 988 _objc_inform_now_and_on_crash("%s object %p overreleased while already deallocating; break on objc_overrelease_during_dealloc_error to debug", object_getClassName((id)this), this); 989 objc_overrelease_during_dealloc_error(); 990 return false; // allow rootRelease() to tail-call this 991} 992 993 994/*********************************************************************** 995* Retain count operations for side table. 996**********************************************************************/ 997 998 999#if !NDEBUG 1000// Used to assert that an object is not present in the side table. 1001bool 1002objc_object::sidetable_present() 1003{ 1004 bool result = false; 1005 SideTable *table = SideTable::tableForPointer(this); 1006 1007 spinlock_lock(&table->slock); 1008 1009 RefcountMap::iterator it = table->refcnts.find(this); 1010 if (it != table->refcnts.end()) result = true; 1011 1012 if (weak_is_registered_no_lock(&table->weak_table, (id)this)) result = true; 1013 1014 spinlock_unlock(&table->slock); 1015 1016 return result; 1017} 1018#endif 1019 1020#if SUPPORT_NONPOINTER_ISA 1021 1022void 1023objc_object::sidetable_lock() 1024{ 1025 SideTable *table = SideTable::tableForPointer(this); 1026 spinlock_lock(&table->slock); 1027} 1028 1029void 1030objc_object::sidetable_unlock() 1031{ 1032 SideTable *table = SideTable::tableForPointer(this); 1033 spinlock_unlock(&table->slock); 1034} 1035 1036 1037// Move the entire retain count to the side table, 1038// as well as isDeallocating and weaklyReferenced. 1039void 1040objc_object::sidetable_moveExtraRC_nolock(size_t extra_rc, 1041 bool isDeallocating, 1042 bool weaklyReferenced) 1043{ 1044 assert(!isa.indexed); // should already be changed to not-indexed 1045 SideTable *table = SideTable::tableForPointer(this); 1046 1047 size_t& refcntStorage = table->refcnts[this]; 1048 size_t oldRefcnt = refcntStorage; 1049 // not deallocating - that was in the isa 1050 assert((oldRefcnt & SIDE_TABLE_DEALLOCATING) == 0); 1051 assert((oldRefcnt & SIDE_TABLE_WEAKLY_REFERENCED) == 0); 1052 1053 uintptr_t carry; 1054 size_t refcnt = addc(oldRefcnt, extra_rc<<SIDE_TABLE_RC_SHIFT, 0, &carry); 1055 if (carry) refcnt = SIDE_TABLE_RC_PINNED; 1056 if (isDeallocating) refcnt |= SIDE_TABLE_DEALLOCATING; 1057 if (weaklyReferenced) refcnt |= SIDE_TABLE_WEAKLY_REFERENCED; 1058 1059 refcntStorage = refcnt; 1060} 1061 1062 1063// Move some retain counts to the side table from the isa field. 1064// Returns true if the object is now pinned. 1065bool 1066objc_object::sidetable_addExtraRC_nolock(size_t delta_rc) 1067{ 1068 assert(isa.indexed); 1069 SideTable *table = SideTable::tableForPointer(this); 1070 1071 size_t& refcntStorage = table->refcnts[this]; 1072 size_t oldRefcnt = refcntStorage; 1073 // not deallocating - that is in the isa 1074 assert((oldRefcnt & SIDE_TABLE_DEALLOCATING) == 0); 1075 assert((oldRefcnt & SIDE_TABLE_WEAKLY_REFERENCED) == 0); 1076 1077 if (oldRefcnt & SIDE_TABLE_RC_PINNED) return true; 1078 1079 uintptr_t carry; 1080 size_t newRefcnt = 1081 addc(oldRefcnt, delta_rc << SIDE_TABLE_RC_SHIFT, 0, &carry); 1082 if (carry) { 1083 refcntStorage = 1084 SIDE_TABLE_RC_PINNED | (oldRefcnt & SIDE_TABLE_FLAG_MASK); 1085 return true; 1086 } 1087 else { 1088 refcntStorage = newRefcnt; 1089 return false; 1090 } 1091} 1092 1093 1094// Move some retain counts from the side table to the isa field. 1095// Returns true if the sidetable retain count is now 0. 1096bool 1097objc_object::sidetable_subExtraRC_nolock(size_t delta_rc) 1098{ 1099 assert(isa.indexed); 1100 SideTable *table = SideTable::tableForPointer(this); 1101 1102 size_t& refcntStorage = table->refcnts[this]; 1103 size_t oldRefcnt = refcntStorage; 1104 // not deallocating - that is in the isa 1105 assert((oldRefcnt & SIDE_TABLE_DEALLOCATING) == 0); 1106 assert((oldRefcnt & SIDE_TABLE_WEAKLY_REFERENCED) == 0); 1107 1108 if (oldRefcnt < delta_rc) { 1109 _objc_inform_now_and_on_crash("refcount underflow error for object %p", 1110 this); 1111 _objc_fatal("refcount underflow error for %s %p", 1112 object_getClassName((id)this), this); 1113 } 1114 1115 size_t newRefcnt = oldRefcnt - (delta_rc << SIDE_TABLE_RC_SHIFT); 1116 if (newRefcnt == 0) { 1117 table->refcnts.erase(this); 1118 return true; 1119 } 1120 else { 1121 refcntStorage = newRefcnt; 1122 return false; 1123 } 1124} 1125 1126 1127size_t 1128objc_object::sidetable_getExtraRC_nolock() 1129{ 1130 assert(isa.indexed); 1131 SideTable *table = SideTable::tableForPointer(this); 1132 RefcountMap::iterator it = table->refcnts.find(this); 1133 assert(it != table->refcnts.end()); 1134 return it->second >> SIDE_TABLE_RC_SHIFT; 1135} 1136 1137 1138// SUPPORT_NONPOINTER_ISA 1139#endif 1140 1141 1142__attribute__((used,noinline,nothrow)) 1143id 1144objc_object::sidetable_retain_slow(SideTable *table) 1145{ 1146#if SUPPORT_NONPOINTER_ISA 1147 assert(!isa.indexed); 1148#endif 1149 1150 spinlock_lock(&table->slock); 1151 size_t& refcntStorage = table->refcnts[this]; 1152 if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) { 1153 refcntStorage += SIDE_TABLE_RC_ONE; 1154 } 1155 spinlock_unlock(&table->slock); 1156 1157 return (id)this; 1158} 1159 1160 1161id 1162objc_object::sidetable_retain() 1163{ 1164#if SUPPORT_NONPOINTER_ISA 1165 assert(!isa.indexed); 1166#endif 1167 SideTable *table = SideTable::tableForPointer(this); 1168 1169 if (spinlock_trylock(&table->slock)) { 1170 size_t& refcntStorage = table->refcnts[this]; 1171 if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) { 1172 refcntStorage += SIDE_TABLE_RC_ONE; 1173 } 1174 spinlock_unlock(&table->slock); 1175 return (id)this; 1176 } 1177 return sidetable_retain_slow(table); 1178} 1179 1180 1181bool 1182objc_object::sidetable_tryRetain() 1183{ 1184#if SUPPORT_NONPOINTER_ISA 1185 assert(!isa.indexed); 1186#endif 1187 SideTable *table = SideTable::tableForPointer(this); 1188 1189 // NO SPINLOCK HERE 1190 // _objc_rootTryRetain() is called exclusively by _objc_loadWeak(), 1191 // which already acquired the lock on our behalf. 1192 1193 // fixme can't do this efficiently with os_lock_handoff_s 1194 // if (table->slock == 0) { 1195 // _objc_fatal("Do not call -_tryRetain."); 1196 // } 1197 1198 bool result = true; 1199 RefcountMap::iterator it = table->refcnts.find(this); 1200 if (it == table->refcnts.end()) { 1201 table->refcnts[this] = SIDE_TABLE_RC_ONE; 1202 } else if (it->second & SIDE_TABLE_DEALLOCATING) { 1203 result = false; 1204 } else if (! (it->second & SIDE_TABLE_RC_PINNED)) { 1205 it->second += SIDE_TABLE_RC_ONE; 1206 } 1207 1208 return result; 1209} 1210 1211 1212uintptr_t 1213objc_object::sidetable_retainCount() 1214{ 1215 SideTable *table = SideTable::tableForPointer(this); 1216 1217 size_t refcnt_result = 1; 1218 1219 spinlock_lock(&table->slock); 1220 RefcountMap::iterator it = table->refcnts.find(this); 1221 if (it != table->refcnts.end()) { 1222 // this is valid for SIDE_TABLE_RC_PINNED too 1223 refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT; 1224 } 1225 spinlock_unlock(&table->slock); 1226 return refcnt_result; 1227} 1228 1229 1230bool 1231objc_object::sidetable_isDeallocating() 1232{ 1233 SideTable *table = SideTable::tableForPointer(this); 1234 1235 // NO SPINLOCK HERE 1236 // _objc_rootIsDeallocating() is called exclusively by _objc_storeWeak(), 1237 // which already acquired the lock on our behalf. 1238 1239 1240 // fixme can't do this efficiently with os_lock_handoff_s 1241 // if (table->slock == 0) { 1242 // _objc_fatal("Do not call -_isDeallocating."); 1243 // } 1244 1245 RefcountMap::iterator it = table->refcnts.find(this); 1246 return (it != table->refcnts.end()) && (it->second & SIDE_TABLE_DEALLOCATING); 1247} 1248 1249 1250bool 1251objc_object::sidetable_isWeaklyReferenced() 1252{ 1253 bool result = false; 1254 1255 SideTable *table = SideTable::tableForPointer(this); 1256 spinlock_lock(&table->slock); 1257 1258 RefcountMap::iterator it = table->refcnts.find(this); 1259 if (it != table->refcnts.end()) { 1260 result = it->second & SIDE_TABLE_WEAKLY_REFERENCED; 1261 } 1262 1263 spinlock_unlock(&table->slock); 1264 1265 return result; 1266} 1267 1268 1269void 1270objc_object::sidetable_setWeaklyReferenced_nolock() 1271{ 1272#if SUPPORT_NONPOINTER_ISA 1273 assert(!isa.indexed); 1274#endif 1275 1276 SideTable *table = SideTable::tableForPointer(this); 1277 1278 table->refcnts[this] |= SIDE_TABLE_WEAKLY_REFERENCED; 1279} 1280 1281 1282__attribute__((used,noinline,nothrow)) 1283bool 1284objc_object::sidetable_release_slow(SideTable *table, bool performDealloc) 1285{ 1286#if SUPPORT_NONPOINTER_ISA 1287 assert(!isa.indexed); 1288#endif 1289 bool do_dealloc = false; 1290 1291 spinlock_lock(&table->slock); 1292 RefcountMap::iterator it = table->refcnts.find(this); 1293 if (it == table->refcnts.end()) { 1294 do_dealloc = true; 1295 table->refcnts[this] = SIDE_TABLE_DEALLOCATING; 1296 } else if (it->second < SIDE_TABLE_DEALLOCATING) { 1297 // SIDE_TABLE_WEAKLY_REFERENCED may be set. Don't change it. 1298 do_dealloc = true; 1299 it->second |= SIDE_TABLE_DEALLOCATING; 1300 } else if (! (it->second & SIDE_TABLE_RC_PINNED)) { 1301 it->second -= SIDE_TABLE_RC_ONE; 1302 } 1303 spinlock_unlock(&table->slock); 1304 if (do_dealloc && performDealloc) { 1305 ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc); 1306 } 1307 return do_dealloc; 1308} 1309 1310 1311bool 1312objc_object::sidetable_release(bool performDealloc) 1313{ 1314#if SUPPORT_NONPOINTER_ISA 1315 assert(!isa.indexed); 1316#endif 1317 SideTable *table = SideTable::tableForPointer(this); 1318 1319 bool do_dealloc = false; 1320 1321 if (spinlock_trylock(&table->slock)) { 1322 RefcountMap::iterator it = table->refcnts.find(this); 1323 if (it == table->refcnts.end()) { 1324 do_dealloc = true; 1325 table->refcnts[this] = SIDE_TABLE_DEALLOCATING; 1326 } else if (it->second < SIDE_TABLE_DEALLOCATING) { 1327 // SIDE_TABLE_WEAKLY_REFERENCED may be set. Don't change it. 1328 do_dealloc = true; 1329 it->second |= SIDE_TABLE_DEALLOCATING; 1330 } else if (! (it->second & SIDE_TABLE_RC_PINNED)) { 1331 it->second -= SIDE_TABLE_RC_ONE; 1332 } 1333 spinlock_unlock(&table->slock); 1334 if (do_dealloc && performDealloc) { 1335 ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc); 1336 } 1337 return do_dealloc; 1338 } 1339 1340 return sidetable_release_slow(table, performDealloc); 1341} 1342 1343 1344void 1345objc_object::sidetable_clearDeallocating() 1346{ 1347 SideTable *table = SideTable::tableForPointer(this); 1348 1349 // clear any weak table items 1350 // clear extra retain count and deallocating bit 1351 // (fixme warn or abort if extra retain count == 0 ?) 1352 spinlock_lock(&table->slock); 1353 RefcountMap::iterator it = table->refcnts.find(this); 1354 if (it != table->refcnts.end()) { 1355 if (it->second & SIDE_TABLE_WEAKLY_REFERENCED) { 1356 weak_clear_no_lock(&table->weak_table, (id)this); 1357 } 1358 table->refcnts.erase(it); 1359 } 1360 spinlock_unlock(&table->slock); 1361} 1362 1363 1364/*********************************************************************** 1365* Optimized retain/release/autorelease entrypoints 1366**********************************************************************/ 1367 1368 1369#if __OBJC2__ 1370 1371__attribute__((aligned(16))) 1372id 1373objc_retain(id obj) 1374{ 1375 if (!obj) return obj; 1376 if (obj->isTaggedPointer()) return obj; 1377 return obj->retain(); 1378} 1379 1380 1381__attribute__((aligned(16))) 1382void 1383objc_release(id obj) 1384{ 1385 if (!obj) return; 1386 if (obj->isTaggedPointer()) return; 1387 return obj->release(); 1388} 1389 1390 1391__attribute__((aligned(16))) 1392id 1393objc_autorelease(id obj) 1394{ 1395 if (!obj) return obj; 1396 if (obj->isTaggedPointer()) return obj; 1397 return obj->autorelease(); 1398} 1399 1400 1401// OBJC2 1402#else 1403// not OBJC2 1404 1405 1406id objc_retain(id obj) { return [obj retain]; } 1407void objc_release(id obj) { [obj release]; } 1408id objc_autorelease(id obj) { return [obj autorelease]; } 1409 1410 1411#endif 1412 1413 1414/*********************************************************************** 1415* Basic operations for root class implementations a.k.a. _objc_root*() 1416**********************************************************************/ 1417 1418bool 1419_objc_rootTryRetain(id obj) 1420{ 1421 assert(obj); 1422 1423 return obj->rootTryRetain(); 1424} 1425 1426bool 1427_objc_rootIsDeallocating(id obj) 1428{ 1429 assert(obj); 1430 1431 return obj->rootIsDeallocating(); 1432} 1433 1434 1435void 1436objc_clear_deallocating(id obj) 1437{ 1438 assert(obj); 1439 assert(!UseGC); 1440 1441 if (obj->isTaggedPointer()) return; 1442 obj->clearDeallocating(); 1443} 1444 1445 1446bool 1447_objc_rootReleaseWasZero(id obj) 1448{ 1449 assert(obj); 1450 1451 return obj->rootReleaseShouldDealloc(); 1452} 1453 1454 1455id 1456_objc_rootAutorelease(id obj) 1457{ 1458 assert(obj); 1459 // assert(!UseGC); 1460 if (UseGC) return obj; // fixme CF calls this when GC is on 1461 1462 return obj->rootAutorelease(); 1463} 1464 1465uintptr_t 1466_objc_rootRetainCount(id obj) 1467{ 1468 assert(obj); 1469 1470 return obj->rootRetainCount(); 1471} 1472 1473 1474id 1475_objc_rootRetain(id obj) 1476{ 1477 assert(obj); 1478 1479 return obj->rootRetain(); 1480} 1481 1482void 1483_objc_rootRelease(id obj) 1484{ 1485 assert(obj); 1486 1487 obj->rootRelease(); 1488} 1489 1490 1491id 1492_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone) 1493{ 1494 id obj; 1495 1496#if __OBJC2__ 1497 // allocWithZone under __OBJC2__ ignores the zone parameter 1498 (void)zone; 1499 obj = class_createInstance(cls, 0); 1500#else 1501 if (!zone || UseGC) { 1502 obj = class_createInstance(cls, 0); 1503 } 1504 else { 1505 obj = class_createInstanceFromZone(cls, 0, zone); 1506 } 1507#endif 1508 1509 if (!obj) obj = callBadAllocHandler(cls); 1510 return obj; 1511} 1512 1513 1514// Call [cls alloc] or [cls allocWithZone:nil], with appropriate 1515// shortcutting optimizations. 1516static ALWAYS_INLINE id 1517callAlloc(Class cls, bool checkNil, bool allocWithZone=false) 1518{ 1519 if (checkNil && !cls) return nil; 1520 1521#if __OBJC2__ 1522 if (! cls->ISA()->hasCustomAWZ()) { 1523 // No alloc/allocWithZone implementation. Go straight to the allocator. 1524 // fixme store hasCustomAWZ in the non-meta class and 1525 // add it to canAllocFast's summary 1526 if (cls->canAllocFast()) { 1527 // No ctors, raw isa, etc. Go straight to the metal. 1528 bool dtor = cls->hasCxxDtor(); 1529 id obj = (id)calloc(1, cls->bits.fastInstanceSize()); 1530 if (!obj) return callBadAllocHandler(cls); 1531 obj->initInstanceIsa(cls, dtor); 1532 return obj; 1533 } 1534 else { 1535 // Has ctor or raw isa or something. Use the slower path. 1536 id obj = class_createInstance(cls, 0); 1537 if (!obj) return callBadAllocHandler(cls); 1538 return obj; 1539 } 1540 } 1541#endif 1542 1543 // No shortcuts available. 1544 if (allocWithZone) return [cls allocWithZone:nil]; 1545 return [cls alloc]; 1546} 1547 1548 1549// Base class implementation of +alloc. cls is not nil. 1550// Calls [cls allocWithZone:nil]. 1551id 1552_objc_rootAlloc(Class cls) 1553{ 1554 return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/); 1555} 1556 1557// Calls [cls alloc]. 1558id 1559objc_alloc(Class cls) 1560{ 1561 return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/); 1562} 1563 1564// Calls [cls allocWithZone:nil]. 1565id 1566objc_allocWithZone(Class cls) 1567{ 1568 return callAlloc(cls, true/*checkNil*/, true/*allocWithZone*/); 1569} 1570 1571 1572void 1573_objc_rootDealloc(id obj) 1574{ 1575 assert(obj); 1576 1577 obj->rootDealloc(); 1578} 1579 1580void 1581_objc_rootFinalize(id obj __unused) 1582{ 1583 assert(obj); 1584 assert(UseGC); 1585 1586 if (UseGC) { 1587 return; 1588 } 1589 _objc_fatal("_objc_rootFinalize called with garbage collection off"); 1590} 1591 1592 1593id 1594_objc_rootInit(id obj) 1595{ 1596 // In practice, it will be hard to rely on this function. 1597 // Many classes do not properly chain -init calls. 1598 return obj; 1599} 1600 1601 1602malloc_zone_t * 1603_objc_rootZone(id obj) 1604{ 1605 (void)obj; 1606 if (gc_zone) { 1607 return gc_zone; 1608 } 1609#if __OBJC2__ 1610 // allocWithZone under __OBJC2__ ignores the zone parameter 1611 return malloc_default_zone(); 1612#else 1613 malloc_zone_t *rval = malloc_zone_from_ptr(obj); 1614 return rval ? rval : malloc_default_zone(); 1615#endif 1616} 1617 1618uintptr_t 1619_objc_rootHash(id obj) 1620{ 1621 if (UseGC) { 1622 return _object_getExternalHash(obj); 1623 } 1624 return (uintptr_t)obj; 1625} 1626 1627void * 1628objc_autoreleasePoolPush(void) 1629{ 1630 if (UseGC) return nil; 1631 return AutoreleasePoolPage::push(); 1632} 1633 1634void 1635objc_autoreleasePoolPop(void *ctxt) 1636{ 1637 if (UseGC) return; 1638 1639 // fixme rdar://9167170 1640 if (!ctxt) return; 1641 1642 AutoreleasePoolPage::pop(ctxt); 1643} 1644 1645 1646void * 1647_objc_autoreleasePoolPush(void) 1648{ 1649 return objc_autoreleasePoolPush(); 1650} 1651 1652void 1653_objc_autoreleasePoolPop(void *ctxt) 1654{ 1655 objc_autoreleasePoolPop(ctxt); 1656} 1657 1658void 1659_objc_autoreleasePoolPrint(void) 1660{ 1661 if (UseGC) return; 1662 AutoreleasePoolPage::printAll(); 1663} 1664 1665id 1666objc_autoreleaseReturnValue(id obj) 1667{ 1668 if (fastAutoreleaseForReturn(obj)) return obj; 1669 1670 return objc_autorelease(obj); 1671} 1672 1673id 1674objc_retainAutoreleaseReturnValue(id obj) 1675{ 1676 return objc_autoreleaseReturnValue(objc_retain(obj)); 1677} 1678 1679id 1680objc_retainAutoreleasedReturnValue(id obj) 1681{ 1682 if (fastRetainFromReturn(obj)) return obj; 1683 1684 return objc_retain(obj); 1685} 1686 1687id 1688objc_retainAutorelease(id obj) 1689{ 1690 return objc_autorelease(objc_retain(obj)); 1691} 1692 1693void 1694_objc_deallocOnMainThreadHelper(void *context) 1695{ 1696 id obj = (id)context; 1697 [obj dealloc]; 1698} 1699 1700#undef objc_retainedObject 1701#undef objc_unretainedObject 1702#undef objc_unretainedPointer 1703 1704// convert objc_objectptr_t to id, callee must take ownership. 1705id objc_retainedObject(objc_objectptr_t pointer) { return (id)pointer; } 1706 1707// convert objc_objectptr_t to id, without ownership transfer. 1708id objc_unretainedObject(objc_objectptr_t pointer) { return (id)pointer; } 1709 1710// convert id to objc_objectptr_t, no ownership transfer. 1711objc_objectptr_t objc_unretainedPointer(id object) { return object; } 1712 1713 1714void arr_init(void) 1715{ 1716 AutoreleasePoolPage::init(); 1717 SideTable::init(); 1718} 1719 1720@implementation NSObject 1721 1722+ (void)load { 1723 if (UseGC) gc_init2(); 1724} 1725 1726+ (void)initialize { 1727} 1728 1729+ (id)self { 1730 return (id)self; 1731} 1732 1733- (id)self { 1734 return self; 1735} 1736 1737+ (Class)class { 1738 return self; 1739} 1740 1741- (Class)class { 1742 return object_getClass(self); 1743} 1744 1745+ (Class)superclass { 1746 return self->superclass; 1747} 1748 1749- (Class)superclass { 1750 return [self class]->superclass; 1751} 1752 1753+ (BOOL)isMemberOfClass:(Class)cls { 1754 return object_getClass((id)self) == cls; 1755} 1756 1757- (BOOL)isMemberOfClass:(Class)cls { 1758 return [self class] == cls; 1759} 1760 1761+ (BOOL)isKindOfClass:(Class)cls { 1762 for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) { 1763 if (tcls == cls) return YES; 1764 } 1765 return NO; 1766} 1767 1768- (BOOL)isKindOfClass:(Class)cls { 1769 for (Class tcls = [self class]; tcls; tcls = tcls->superclass) { 1770 if (tcls == cls) return YES; 1771 } 1772 return NO; 1773} 1774 1775+ (BOOL)isSubclassOfClass:(Class)cls { 1776 for (Class tcls = self; tcls; tcls = tcls->superclass) { 1777 if (tcls == cls) return YES; 1778 } 1779 return NO; 1780} 1781 1782+ (BOOL)isAncestorOfObject:(NSObject *)obj { 1783 for (Class tcls = [obj class]; tcls; tcls = tcls->superclass) { 1784 if (tcls == self) return YES; 1785 } 1786 return NO; 1787} 1788 1789+ (BOOL)instancesRespondToSelector:(SEL)sel { 1790 if (!sel) return NO; 1791 return class_respondsToSelector(self, sel); 1792} 1793 1794+ (BOOL)respondsToSelector:(SEL)sel { 1795 if (!sel) return NO; 1796 return class_respondsToSelector_inst(object_getClass(self), sel, self); 1797} 1798 1799- (BOOL)respondsToSelector:(SEL)sel { 1800 if (!sel) return NO; 1801 return class_respondsToSelector_inst([self class], sel, self); 1802} 1803 1804+ (BOOL)conformsToProtocol:(Protocol *)protocol { 1805 if (!protocol) return NO; 1806 for (Class tcls = self; tcls; tcls = tcls->superclass) { 1807 if (class_conformsToProtocol(tcls, protocol)) return YES; 1808 } 1809 return NO; 1810} 1811 1812- (BOOL)conformsToProtocol:(Protocol *)protocol { 1813 if (!protocol) return NO; 1814 for (Class tcls = [self class]; tcls; tcls = tcls->superclass) { 1815 if (class_conformsToProtocol(tcls, protocol)) return YES; 1816 } 1817 return NO; 1818} 1819 1820+ (NSUInteger)hash { 1821 return _objc_rootHash(self); 1822} 1823 1824- (NSUInteger)hash { 1825 return _objc_rootHash(self); 1826} 1827 1828+ (BOOL)isEqual:(id)obj { 1829 return obj == (id)self; 1830} 1831 1832- (BOOL)isEqual:(id)obj { 1833 return obj == self; 1834} 1835 1836 1837+ (BOOL)isFault { 1838 return NO; 1839} 1840 1841- (BOOL)isFault { 1842 return NO; 1843} 1844 1845+ (BOOL)isProxy { 1846 return NO; 1847} 1848 1849- (BOOL)isProxy { 1850 return NO; 1851} 1852 1853 1854+ (IMP)instanceMethodForSelector:(SEL)sel { 1855 if (!sel) [self doesNotRecognizeSelector:sel]; 1856 return class_getMethodImplementation(self, sel); 1857} 1858 1859+ (IMP)methodForSelector:(SEL)sel { 1860 if (!sel) [self doesNotRecognizeSelector:sel]; 1861 return object_getMethodImplementation((id)self, sel); 1862} 1863 1864- (IMP)methodForSelector:(SEL)sel { 1865 if (!sel) [self doesNotRecognizeSelector:sel]; 1866 return object_getMethodImplementation(self, sel); 1867} 1868 1869+ (BOOL)resolveClassMethod:(SEL)sel { 1870 return NO; 1871} 1872 1873+ (BOOL)resolveInstanceMethod:(SEL)sel { 1874 return NO; 1875} 1876 1877// Replaced by CF (throws an NSException) 1878+ (void)doesNotRecognizeSelector:(SEL)sel { 1879 _objc_fatal("+[%s %s]: unrecognized selector sent to instance %p", 1880 class_getName(self), sel_getName(sel), self); 1881} 1882 1883// Replaced by CF (throws an NSException) 1884- (void)doesNotRecognizeSelector:(SEL)sel { 1885 _objc_fatal("-[%s %s]: unrecognized selector sent to instance %p", 1886 object_getClassName(self), sel_getName(sel), self); 1887} 1888 1889 1890+ (id)performSelector:(SEL)sel { 1891 if (!sel) [self doesNotRecognizeSelector:sel]; 1892 return ((id(*)(id, SEL))objc_msgSend)((id)self, sel); 1893} 1894 1895+ (id)performSelector:(SEL)sel withObject:(id)obj { 1896 if (!sel) [self doesNotRecognizeSelector:sel]; 1897 return ((id(*)(id, SEL, id))objc_msgSend)((id)self, sel, obj); 1898} 1899 1900+ (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 { 1901 if (!sel) [self doesNotRecognizeSelector:sel]; 1902 return ((id(*)(id, SEL, id, id))objc_msgSend)((id)self, sel, obj1, obj2); 1903} 1904 1905- (id)performSelector:(SEL)sel { 1906 if (!sel) [self doesNotRecognizeSelector:sel]; 1907 return ((id(*)(id, SEL))objc_msgSend)(self, sel); 1908} 1909 1910- (id)performSelector:(SEL)sel withObject:(id)obj { 1911 if (!sel) [self doesNotRecognizeSelector:sel]; 1912 return ((id(*)(id, SEL, id))objc_msgSend)(self, sel, obj); 1913} 1914 1915- (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 { 1916 if (!sel) [self doesNotRecognizeSelector:sel]; 1917 return ((id(*)(id, SEL, id, id))objc_msgSend)(self, sel, obj1, obj2); 1918} 1919 1920 1921// Replaced by CF (returns an NSMethodSignature) 1922+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)sel { 1923 _objc_fatal("+[NSObject instanceMethodSignatureForSelector:] " 1924 "not available without CoreFoundation"); 1925} 1926 1927// Replaced by CF (returns an NSMethodSignature) 1928+ (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { 1929 _objc_fatal("+[NSObject methodSignatureForSelector:] " 1930 "not available without CoreFoundation"); 1931} 1932 1933// Replaced by CF (returns an NSMethodSignature) 1934- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { 1935 _objc_fatal("-[NSObject methodSignatureForSelector:] " 1936 "not available without CoreFoundation"); 1937} 1938 1939+ (void)forwardInvocation:(NSInvocation *)invocation { 1940 [self doesNotRecognizeSelector:(invocation ? [invocation selector] : 0)]; 1941} 1942 1943- (void)forwardInvocation:(NSInvocation *)invocation { 1944 [self doesNotRecognizeSelector:(invocation ? [invocation selector] : 0)]; 1945} 1946 1947+ (id)forwardingTargetForSelector:(SEL)sel { 1948 return nil; 1949} 1950 1951- (id)forwardingTargetForSelector:(SEL)sel { 1952 return nil; 1953} 1954 1955 1956// Replaced by CF (returns an NSString) 1957+ (NSString *)description { 1958 return nil; 1959} 1960 1961// Replaced by CF (returns an NSString) 1962- (NSString *)description { 1963 return nil; 1964} 1965 1966+ (NSString *)debugDescription { 1967 return [self description]; 1968} 1969 1970- (NSString *)debugDescription { 1971 return [self description]; 1972} 1973 1974 1975+ (id)new { 1976 return [callAlloc(self, false/*checkNil*/) init]; 1977} 1978 1979+ (id)retain { 1980 return (id)self; 1981} 1982 1983// Replaced by ObjectAlloc 1984- (id)retain { 1985 return ((id)self)->rootRetain(); 1986} 1987 1988 1989+ (BOOL)_tryRetain { 1990 return YES; 1991} 1992 1993// Replaced by ObjectAlloc 1994- (BOOL)_tryRetain { 1995 return ((id)self)->rootTryRetain(); 1996} 1997 1998+ (BOOL)_isDeallocating { 1999 return NO; 2000} 2001 2002- (BOOL)_isDeallocating { 2003 return ((id)self)->rootIsDeallocating(); 2004} 2005 2006+ (BOOL)allowsWeakReference { 2007 return YES; 2008} 2009 2010+ (BOOL)retainWeakReference { 2011 return YES; 2012} 2013 2014- (BOOL)allowsWeakReference { 2015 return ! [self _isDeallocating]; 2016} 2017 2018- (BOOL)retainWeakReference { 2019 return [self _tryRetain]; 2020} 2021 2022+ (oneway void)release { 2023} 2024 2025// Replaced by ObjectAlloc 2026- (oneway void)release { 2027 ((id)self)->rootRelease(); 2028} 2029 2030+ (id)autorelease { 2031 return (id)self; 2032} 2033 2034// Replaced by ObjectAlloc 2035- (id)autorelease { 2036 return ((id)self)->rootAutorelease(); 2037} 2038 2039+ (NSUInteger)retainCount { 2040 return ULONG_MAX; 2041} 2042 2043- (NSUInteger)retainCount { 2044 return ((id)self)->rootRetainCount(); 2045} 2046 2047+ (id)alloc { 2048 return _objc_rootAlloc(self); 2049} 2050 2051// Replaced by ObjectAlloc 2052+ (id)allocWithZone:(struct _NSZone *)zone { 2053 return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone); 2054} 2055 2056// Replaced by CF (throws an NSException) 2057+ (id)init { 2058 return (id)self; 2059} 2060 2061- (id)init { 2062 return _objc_rootInit(self); 2063} 2064 2065// Replaced by CF (throws an NSException) 2066+ (void)dealloc { 2067} 2068 2069 2070// Replaced by NSZombies 2071- (void)dealloc { 2072 _objc_rootDealloc(self); 2073} 2074 2075// Replaced by CF (throws an NSException) 2076+ (void)finalize { 2077} 2078 2079- (void)finalize { 2080 _objc_rootFinalize(self); 2081} 2082 2083+ (struct _NSZone *)zone { 2084 return (struct _NSZone *)_objc_rootZone(self); 2085} 2086 2087- (struct _NSZone *)zone { 2088 return (struct _NSZone *)_objc_rootZone(self); 2089} 2090 2091+ (id)copy { 2092 return (id)self; 2093} 2094 2095+ (id)copyWithZone:(struct _NSZone *)zone { 2096 return (id)self; 2097} 2098 2099- (id)copy { 2100 return [(id)self copyWithZone:nil]; 2101} 2102 2103+ (id)mutableCopy { 2104 return (id)self; 2105} 2106 2107+ (id)mutableCopyWithZone:(struct _NSZone *)zone { 2108 return (id)self; 2109} 2110 2111- (id)mutableCopy { 2112 return [(id)self mutableCopyWithZone:nil]; 2113} 2114 2115@end 2116 2117 2118