]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-private.h
objc4-709.tar.gz
[apple/objc4.git] / runtime / objc-private.h
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * objc-private.h
25 * Copyright 1988-1996, NeXT Software, Inc.
26 */
27
28 #ifndef _OBJC_PRIVATE_H_
29 #define _OBJC_PRIVATE_H_
30
31 #include "objc-config.h"
32
33 /* Isolate ourselves from the definitions of id and Class in the compiler
34 * and public headers.
35 */
36
37 #ifdef _OBJC_OBJC_H_
38 #error include objc-private.h before other headers
39 #endif
40
41 #define OBJC_TYPES_DEFINED 1
42 #define OBJC_OLD_DISPATCH_PROTOTYPES 0
43
44 #include <cstddef> // for nullptr_t
45 #include <stdint.h>
46 #include <assert.h>
47
48 struct objc_class;
49 struct objc_object;
50
51 typedef struct objc_class *Class;
52 typedef struct objc_object *id;
53
54 namespace {
55 struct SideTable;
56 };
57
58
59 #if (!SUPPORT_NONPOINTER_ISA && !SUPPORT_PACKED_ISA && !SUPPORT_INDEXED_ISA) ||\
60 ( SUPPORT_NONPOINTER_ISA && SUPPORT_PACKED_ISA && !SUPPORT_INDEXED_ISA) ||\
61 ( SUPPORT_NONPOINTER_ISA && !SUPPORT_PACKED_ISA && SUPPORT_INDEXED_ISA)
62 // good config
63 #else
64 # error bad config
65 #endif
66
67
68 union isa_t
69 {
70 isa_t() { }
71 isa_t(uintptr_t value) : bits(value) { }
72
73 Class cls;
74 uintptr_t bits;
75
76 #if SUPPORT_PACKED_ISA
77
78 // extra_rc must be the MSB-most field (so it matches carry/overflow flags)
79 // nonpointer must be the LSB (fixme or get rid of it)
80 // shiftcls must occupy the same bits that a real class pointer would
81 // bits + RC_ONE is equivalent to extra_rc + 1
82 // RC_HALF is the high bit of extra_rc (i.e. half of its range)
83
84 // future expansion:
85 // uintptr_t fast_rr : 1; // no r/r overrides
86 // uintptr_t lock : 2; // lock for atomic property, @synch
87 // uintptr_t extraBytes : 1; // allocated with extra bytes
88
89 # if __arm64__
90 # define ISA_MASK 0x0000000ffffffff8ULL
91 # define ISA_MAGIC_MASK 0x000003f000000001ULL
92 # define ISA_MAGIC_VALUE 0x000001a000000001ULL
93 struct {
94 uintptr_t nonpointer : 1;
95 uintptr_t has_assoc : 1;
96 uintptr_t has_cxx_dtor : 1;
97 uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
98 uintptr_t magic : 6;
99 uintptr_t weakly_referenced : 1;
100 uintptr_t deallocating : 1;
101 uintptr_t has_sidetable_rc : 1;
102 uintptr_t extra_rc : 19;
103 # define RC_ONE (1ULL<<45)
104 # define RC_HALF (1ULL<<18)
105 };
106
107 # elif __x86_64__
108 # define ISA_MASK 0x00007ffffffffff8ULL
109 # define ISA_MAGIC_MASK 0x001f800000000001ULL
110 # define ISA_MAGIC_VALUE 0x001d800000000001ULL
111 struct {
112 uintptr_t nonpointer : 1;
113 uintptr_t has_assoc : 1;
114 uintptr_t has_cxx_dtor : 1;
115 uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
116 uintptr_t magic : 6;
117 uintptr_t weakly_referenced : 1;
118 uintptr_t deallocating : 1;
119 uintptr_t has_sidetable_rc : 1;
120 uintptr_t extra_rc : 8;
121 # define RC_ONE (1ULL<<56)
122 # define RC_HALF (1ULL<<7)
123 };
124
125 # else
126 # error unknown architecture for packed isa
127 # endif
128
129 // SUPPORT_PACKED_ISA
130 #endif
131
132
133 #if SUPPORT_INDEXED_ISA
134
135 # if __ARM_ARCH_7K__ >= 2
136
137 # define ISA_INDEX_IS_NPI 1
138 # define ISA_INDEX_MASK 0x0001FFFC
139 # define ISA_INDEX_SHIFT 2
140 # define ISA_INDEX_BITS 15
141 # define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)
142 # define ISA_INDEX_MAGIC_MASK 0x001E0001
143 # define ISA_INDEX_MAGIC_VALUE 0x001C0001
144 struct {
145 uintptr_t nonpointer : 1;
146 uintptr_t has_assoc : 1;
147 uintptr_t indexcls : 15;
148 uintptr_t magic : 4;
149 uintptr_t has_cxx_dtor : 1;
150 uintptr_t weakly_referenced : 1;
151 uintptr_t deallocating : 1;
152 uintptr_t has_sidetable_rc : 1;
153 uintptr_t extra_rc : 7;
154 # define RC_ONE (1ULL<<25)
155 # define RC_HALF (1ULL<<6)
156 };
157
158 # else
159 # error unknown architecture for indexed isa
160 # endif
161
162 // SUPPORT_INDEXED_ISA
163 #endif
164
165 };
166
167
168 struct objc_object {
169 private:
170 isa_t isa;
171
172 public:
173
174 // ISA() assumes this is NOT a tagged pointer object
175 Class ISA();
176
177 // getIsa() allows this to be a tagged pointer object
178 Class getIsa();
179
180 // initIsa() should be used to init the isa of new objects only.
181 // If this object already has an isa, use changeIsa() for correctness.
182 // initInstanceIsa(): objects with no custom RR/AWZ
183 // initClassIsa(): class objects
184 // initProtocolIsa(): protocol objects
185 // initIsa(): other objects
186 void initIsa(Class cls /*nonpointer=false*/);
187 void initClassIsa(Class cls /*nonpointer=maybe*/);
188 void initProtocolIsa(Class cls /*nonpointer=maybe*/);
189 void initInstanceIsa(Class cls, bool hasCxxDtor);
190
191 // changeIsa() should be used to change the isa of existing objects.
192 // If this is a new object, use initIsa() for performance.
193 Class changeIsa(Class newCls);
194
195 bool hasNonpointerIsa();
196 bool isTaggedPointer();
197 bool isBasicTaggedPointer();
198 bool isExtTaggedPointer();
199 bool isClass();
200
201 // object may have associated objects?
202 bool hasAssociatedObjects();
203 void setHasAssociatedObjects();
204
205 // object may be weakly referenced?
206 bool isWeaklyReferenced();
207 void setWeaklyReferenced_nolock();
208
209 // object may have -.cxx_destruct implementation?
210 bool hasCxxDtor();
211
212 // Optimized calls to retain/release methods
213 id retain();
214 void release();
215 id autorelease();
216
217 // Implementations of retain/release methods
218 id rootRetain();
219 bool rootRelease();
220 id rootAutorelease();
221 bool rootTryRetain();
222 bool rootReleaseShouldDealloc();
223 uintptr_t rootRetainCount();
224
225 // Implementation of dealloc methods
226 bool rootIsDeallocating();
227 void clearDeallocating();
228 void rootDealloc();
229
230 private:
231 void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);
232
233 // Slow paths for inline control
234 id rootAutorelease2();
235 bool overrelease_error();
236
237 #if SUPPORT_NONPOINTER_ISA
238 // Unified retain count manipulation for nonpointer isa
239 id rootRetain(bool tryRetain, bool handleOverflow);
240 bool rootRelease(bool performDealloc, bool handleUnderflow);
241 id rootRetain_overflow(bool tryRetain);
242 bool rootRelease_underflow(bool performDealloc);
243
244 void clearDeallocating_slow();
245
246 // Side table retain count overflow for nonpointer isa
247 void sidetable_lock();
248 void sidetable_unlock();
249
250 void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
251 bool sidetable_addExtraRC_nolock(size_t delta_rc);
252 size_t sidetable_subExtraRC_nolock(size_t delta_rc);
253 size_t sidetable_getExtraRC_nolock();
254 #endif
255
256 // Side-table-only retain count
257 bool sidetable_isDeallocating();
258 void sidetable_clearDeallocating();
259
260 bool sidetable_isWeaklyReferenced();
261 void sidetable_setWeaklyReferenced_nolock();
262
263 id sidetable_retain();
264 id sidetable_retain_slow(SideTable& table);
265
266 uintptr_t sidetable_release(bool performDealloc = true);
267 uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);
268
269 bool sidetable_tryRetain();
270
271 uintptr_t sidetable_retainCount();
272 #if DEBUG
273 bool sidetable_present();
274 #endif
275 };
276
277
278 #if __OBJC2__
279 typedef struct method_t *Method;
280 typedef struct ivar_t *Ivar;
281 typedef struct category_t *Category;
282 typedef struct property_t *objc_property_t;
283 #else
284 typedef struct old_method *Method;
285 typedef struct old_ivar *Ivar;
286 typedef struct old_category *Category;
287 typedef struct old_property *objc_property_t;
288 #endif
289
290 // Public headers
291
292 #include "objc.h"
293 #include "runtime.h"
294 #include "objc-os.h"
295 #include "objc-abi.h"
296 #include "objc-api.h"
297 #include "objc-config.h"
298 #include "objc-internal.h"
299 #include "maptable.h"
300 #include "hashtable2.h"
301
302 /* Do not include message.h here. */
303 /* #include "message.h" */
304
305 #define __APPLE_API_PRIVATE
306 #include "objc-gdb.h"
307 #undef __APPLE_API_PRIVATE
308
309
310 // Private headers
311
312 #if __OBJC2__
313 #include "objc-runtime-new.h"
314 #else
315 #include "objc-runtime-old.h"
316 #endif
317
318 #include "objc-references.h"
319 #include "objc-initialize.h"
320 #include "objc-loadmethod.h"
321
322
323 #if SUPPORT_PREOPT && __cplusplus
324 #include <objc-shared-cache.h>
325 using objc_selopt_t = const objc_opt::objc_selopt_t;
326 #else
327 struct objc_selopt_t;
328 #endif
329
330
331 #define STRINGIFY(x) #x
332 #define STRINGIFY2(x) STRINGIFY(x)
333
334 __BEGIN_DECLS
335
336 struct header_info;
337
338 // Split out the rw data from header info. For now put it in a huge array
339 // that more than exceeds the space needed. In future we'll just allocate
340 // this in the shared cache builder.
341 typedef struct header_info_rw {
342
343 bool getLoaded() const {
344 return isLoaded;
345 }
346
347 void setLoaded(bool v) {
348 isLoaded = v ? 1: 0;
349 }
350
351 bool getAllClassesRealized() const {
352 return allClassesRealized;
353 }
354
355 void setAllClassesRealized(bool v) {
356 allClassesRealized = v ? 1: 0;
357 }
358
359 header_info *getNext() const {
360 return (header_info *)(next << 2);
361 }
362
363 void setNext(header_info *v) {
364 next = ((uintptr_t)v) >> 2;
365 }
366
367 private:
368 #ifdef __LP64__
369 uintptr_t isLoaded : 1;
370 uintptr_t allClassesRealized : 1;
371 uintptr_t next : 62;
372 #else
373 uintptr_t isLoaded : 1;
374 uintptr_t allClassesRealized : 1;
375 uintptr_t next : 30;
376 #endif
377 } header_info_rw;
378
379 struct header_info_rw* getPreoptimizedHeaderRW(const struct header_info *const hdr);
380
381 typedef struct header_info {
382 private:
383 // Note, this is no longer a pointer, but instead an offset to a pointer
384 // from this location.
385 intptr_t mhdr_offset;
386
387 // Note, this is no longer a pointer, but instead an offset to a pointer
388 // from this location.
389 intptr_t info_offset;
390
391 // Do not add fields without editing ObjCModernAbstraction.hpp
392 public:
393
394 header_info_rw *getHeaderInfoRW() {
395 header_info_rw *preopt =
396 isPreoptimized() ? getPreoptimizedHeaderRW(this) : nil;
397 if (preopt) return preopt;
398 else return &rw_data[0];
399 }
400
401 const headerType *mhdr() const {
402 return (const headerType *)(((intptr_t)&mhdr_offset) + mhdr_offset);
403 }
404
405 void setmhdr(const headerType *mhdr) {
406 mhdr_offset = (intptr_t)mhdr - (intptr_t)&mhdr_offset;
407 }
408
409 const objc_image_info *info() const {
410 return (const objc_image_info *)(((intptr_t)&info_offset) + info_offset);
411 }
412
413 void setinfo(const objc_image_info *info) {
414 info_offset = (intptr_t)info - (intptr_t)&info_offset;
415 }
416
417 bool isLoaded() {
418 return getHeaderInfoRW()->getLoaded();
419 }
420
421 void setLoaded(bool v) {
422 getHeaderInfoRW()->setLoaded(v);
423 }
424
425 bool areAllClassesRealized() {
426 return getHeaderInfoRW()->getAllClassesRealized();
427 }
428
429 void setAllClassesRealized(bool v) {
430 getHeaderInfoRW()->setAllClassesRealized(v);
431 }
432
433 header_info *getNext() {
434 return getHeaderInfoRW()->getNext();
435 }
436
437 void setNext(header_info *v) {
438 getHeaderInfoRW()->setNext(v);
439 }
440
441 bool isBundle() {
442 return mhdr()->filetype == MH_BUNDLE;
443 }
444
445 const char *fname() const {
446 return dyld_image_path_containing_address(mhdr());
447 }
448
449 bool isPreoptimized() const;
450
451 #if !__OBJC2__
452 struct old_protocol **proto_refs;
453 struct objc_module *mod_ptr;
454 size_t mod_count;
455 # if TARGET_OS_WIN32
456 struct objc_module **modules;
457 size_t moduleCount;
458 struct old_protocol **protocols;
459 size_t protocolCount;
460 void *imageinfo;
461 size_t imageinfoBytes;
462 SEL *selrefs;
463 size_t selrefCount;
464 struct objc_class **clsrefs;
465 size_t clsrefCount;
466 TCHAR *moduleName;
467 # endif
468 #endif
469
470 private:
471 // Images in the shared cache will have an empty array here while those
472 // allocated at run time will allocate a single entry.
473 header_info_rw rw_data[];
474 } header_info;
475
476 extern header_info *FirstHeader;
477 extern header_info *LastHeader;
478 extern int HeaderCount;
479
480 extern void appendHeader(header_info *hi);
481 extern void removeHeader(header_info *hi);
482
483 extern objc_image_info *_getObjcImageInfo(const headerType *head, size_t *size);
484 extern bool _hasObjcContents(const header_info *hi);
485
486
487 // Mach-O segment and section names are 16 bytes and may be un-terminated.
488
489 static inline bool segnameEquals(const char *lhs, const char *rhs) {
490 return 0 == strncmp(lhs, rhs, 16);
491 }
492
493 static inline bool segnameStartsWith(const char *segname, const char *prefix) {
494 return 0 == strncmp(segname, prefix, strlen(prefix));
495 }
496
497 static inline bool sectnameEquals(const char *lhs, const char *rhs) {
498 return segnameEquals(lhs, rhs);
499 }
500
501 static inline bool sectnameStartsWith(const char *sectname, const char *prefix){
502 return segnameStartsWith(sectname, prefix);
503 }
504
505
506 /* selectors */
507 extern void sel_init(size_t selrefCount);
508 extern SEL sel_registerNameNoLock(const char *str, bool copy);
509 extern void sel_lock(void);
510 extern void sel_unlock(void);
511
512 extern SEL SEL_load;
513 extern SEL SEL_initialize;
514 extern SEL SEL_resolveClassMethod;
515 extern SEL SEL_resolveInstanceMethod;
516 extern SEL SEL_cxx_construct;
517 extern SEL SEL_cxx_destruct;
518 extern SEL SEL_retain;
519 extern SEL SEL_release;
520 extern SEL SEL_autorelease;
521 extern SEL SEL_retainCount;
522 extern SEL SEL_alloc;
523 extern SEL SEL_allocWithZone;
524 extern SEL SEL_dealloc;
525 extern SEL SEL_copy;
526 extern SEL SEL_new;
527 extern SEL SEL_forwardInvocation;
528 extern SEL SEL_tryRetain;
529 extern SEL SEL_isDeallocating;
530 extern SEL SEL_retainWeakReference;
531 extern SEL SEL_allowsWeakReference;
532
533 /* preoptimization */
534 extern void preopt_init(void);
535 extern void disableSharedCacheOptimizations(void);
536 extern bool isPreoptimized(void);
537 extern bool noMissingWeakSuperclasses(void);
538 extern header_info *preoptimizedHinfoForHeader(const headerType *mhdr);
539
540 extern objc_selopt_t *preoptimizedSelectors(void);
541
542 extern Protocol *getPreoptimizedProtocol(const char *name);
543
544 extern unsigned getPreoptimizedClassUnreasonableCount();
545 extern Class getPreoptimizedClass(const char *name);
546 extern Class* copyPreoptimizedClasses(const char *name, int *outCount);
547
548 extern Class _calloc_class(size_t size);
549
550 /* method lookup */
551 extern IMP lookUpImpOrNil(Class, SEL, id obj, bool initialize, bool cache, bool resolver);
552 extern IMP lookUpImpOrForward(Class, SEL, id obj, bool initialize, bool cache, bool resolver);
553
554 extern IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel);
555 extern bool class_respondsToSelector_inst(Class cls, SEL sel, id inst);
556
557 extern bool objcMsgLogEnabled;
558 extern bool logMessageSend(bool isClassMethod,
559 const char *objectsClass,
560 const char *implementingClass,
561 SEL selector);
562
563 /* message dispatcher */
564 extern IMP _class_lookupMethodAndLoadCache3(id, SEL, Class);
565
566 #if !OBJC_OLD_DISPATCH_PROTOTYPES
567 extern void _objc_msgForward_impcache(void);
568 #else
569 extern id _objc_msgForward_impcache(id, SEL, ...);
570 #endif
571
572 /* errors */
573 extern void __objc_error(id, const char *, ...) __attribute__((format (printf, 2, 3), noreturn));
574 extern void _objc_inform(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
575 extern void _objc_inform_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
576 extern void _objc_inform_now_and_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
577 extern void _objc_inform_deprecated(const char *oldname, const char *newname) __attribute__((noinline));
578 extern void inform_duplicate(const char *name, Class oldCls, Class cls);
579
580 /* magic */
581 extern Class _objc_getFreedObjectClass (void);
582
583 /* map table additions */
584 extern void *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value);
585 extern void *NXMapKeyFreeingRemove(NXMapTable *table, const void *key);
586
587 /* hash table additions */
588 extern unsigned _NXHashCapacity(NXHashTable *table);
589 extern void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity);
590
591 /* property attribute parsing */
592 extern const char *copyPropertyAttributeString(const objc_property_attribute_t *attrs, unsigned int count);
593 extern objc_property_attribute_t *copyPropertyAttributeList(const char *attrs, unsigned int *outCount);
594 extern char *copyPropertyAttributeValue(const char *attrs, const char *name);
595
596 /* locking */
597 extern void lock_init(void);
598
599 class monitor_locker_t : nocopy_t {
600 monitor_t& lock;
601 public:
602 monitor_locker_t(monitor_t& newLock) : lock(newLock) { lock.enter(); }
603 ~monitor_locker_t() { lock.leave(); }
604 };
605
606 class mutex_locker_t : nocopy_t {
607 mutex_t& lock;
608 public:
609 mutex_locker_t(mutex_t& newLock)
610 : lock(newLock) { lock.lock(); }
611 ~mutex_locker_t() { lock.unlock(); }
612 };
613
614 class recursive_mutex_locker_t : nocopy_t {
615 recursive_mutex_t& lock;
616 public:
617 recursive_mutex_locker_t(recursive_mutex_t& newLock)
618 : lock(newLock) { lock.lock(); }
619 ~recursive_mutex_locker_t() { lock.unlock(); }
620 };
621
622 class rwlock_reader_t : nocopy_t {
623 rwlock_t& lock;
624 public:
625 rwlock_reader_t(rwlock_t& newLock) : lock(newLock) { lock.read(); }
626 ~rwlock_reader_t() { lock.unlockRead(); }
627 };
628
629 class rwlock_writer_t : nocopy_t {
630 rwlock_t& lock;
631 public:
632 rwlock_writer_t(rwlock_t& newLock) : lock(newLock) { lock.write(); }
633 ~rwlock_writer_t() { lock.unlockWrite(); }
634 };
635
636
637 /* Exceptions */
638 struct alt_handler_list;
639 extern void exception_init(void);
640 extern void _destroyAltHandlerList(struct alt_handler_list *list);
641
642 /* Class change notifications (gdb only for now) */
643 #define OBJC_CLASS_ADDED (1<<0)
644 #define OBJC_CLASS_REMOVED (1<<1)
645 #define OBJC_CLASS_IVARS_CHANGED (1<<2)
646 #define OBJC_CLASS_METHODS_CHANGED (1<<3)
647 extern void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)
648 __attribute__((noinline));
649
650
651 // Settings from environment variables
652 #define OPTION(var, env, help) extern bool var;
653 #include "objc-env.h"
654 #undef OPTION
655
656 extern void environ_init(void);
657
658 extern void logReplacedMethod(const char *className, SEL s, bool isMeta, const char *catName, IMP oldImp, IMP newImp);
659
660
661 // objc per-thread storage
662 typedef struct {
663 struct _objc_initializing_classes *initializingClasses; // for +initialize
664 struct SyncCache *syncCache; // for @synchronize
665 struct alt_handler_list *handlerList; // for exception alt handlers
666 char *printableNames[4]; // temporary demangled names for logging
667
668 // If you add new fields here, don't forget to update
669 // _objc_pthread_destroyspecific()
670
671 } _objc_pthread_data;
672
673 extern _objc_pthread_data *_objc_fetch_pthread_data(bool create);
674 extern void tls_init(void);
675
676 // encoding.h
677 extern unsigned int encoding_getNumberOfArguments(const char *typedesc);
678 extern unsigned int encoding_getSizeOfArguments(const char *typedesc);
679 extern unsigned int encoding_getArgumentInfo(const char *typedesc, unsigned int arg, const char **type, int *offset);
680 extern void encoding_getReturnType(const char *t, char *dst, size_t dst_len);
681 extern char * encoding_copyReturnType(const char *t);
682 extern void encoding_getArgumentType(const char *t, unsigned int index, char *dst, size_t dst_len);
683 extern char *encoding_copyArgumentType(const char *t, unsigned int index);
684
685 // sync.h
686 extern void _destroySyncCache(struct SyncCache *cache);
687
688 // arr
689 extern void arr_init(void);
690 extern id objc_autoreleaseReturnValue(id obj);
691
692 // block trampolines
693 extern IMP _imp_implementationWithBlockNoCopy(id block);
694
695 // layout.h
696 typedef struct {
697 uint8_t *bits;
698 size_t bitCount;
699 size_t bitsAllocated;
700 bool weak;
701 } layout_bitmap;
702 extern layout_bitmap layout_bitmap_create(const unsigned char *layout_string, size_t layoutStringInstanceSize, size_t instanceSize, bool weak);
703 extern layout_bitmap layout_bitmap_create_empty(size_t instanceSize, bool weak);
704 extern void layout_bitmap_free(layout_bitmap bits);
705 extern const unsigned char *layout_string_create(layout_bitmap bits);
706 extern void layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset);
707 extern void layout_bitmap_grow(layout_bitmap *bits, size_t newCount);
708 extern void layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos);
709 extern void layout_bitmap_slide_anywhere(layout_bitmap *bits, size_t oldPos, size_t newPos);
710 extern bool layout_bitmap_splat(layout_bitmap dst, layout_bitmap src,
711 size_t oldSrcInstanceSize);
712 extern bool layout_bitmap_or(layout_bitmap dst, layout_bitmap src, const char *msg);
713 extern bool layout_bitmap_clear(layout_bitmap dst, layout_bitmap src, const char *msg);
714 extern void layout_bitmap_print(layout_bitmap bits);
715
716
717 // fixme runtime
718 extern Class look_up_class(const char *aClassName, bool includeUnconnected, bool includeClassHandler);
719 extern "C" void map_images(unsigned count, const char * const paths[],
720 const struct mach_header * const mhdrs[]);
721 extern void map_images_nolock(unsigned count, const char * const paths[],
722 const struct mach_header * const mhdrs[]);
723 extern void load_images(const char *path, const struct mach_header *mh);
724 extern void unmap_image(const char *path, const struct mach_header *mh);
725 extern void unmap_image_nolock(const struct mach_header *mh);
726 extern void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClass);
727 extern void _unload_image(header_info *hi);
728 extern const char ** _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount);
729
730
731 extern const header_info *_headerForClass(Class cls);
732
733 extern Class _class_remap(Class cls);
734 extern Class _class_getNonMetaClass(Class cls, id obj);
735 extern Ivar _class_getVariable(Class cls, const char *name);
736
737 extern unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, id *results, unsigned num_requested);
738 extern id _objc_constructOrFree(id bytes, Class cls);
739
740 extern const char *_category_getName(Category cat);
741 extern const char *_category_getClassName(Category cat);
742 extern Class _category_getClass(Category cat);
743 extern IMP _category_getLoadMethod(Category cat);
744
745 extern id object_cxxConstructFromClass(id obj, Class cls);
746 extern void object_cxxDestruct(id obj);
747
748 extern void _class_resolveMethod(Class cls, SEL sel, id inst);
749
750 extern void fixupCopiedIvars(id newObject, id oldObject);
751 extern Class _class_getClassForIvar(Class cls, Ivar ivar);
752
753
754 #define OBJC_WARN_DEPRECATED \
755 do { \
756 static int warned = 0; \
757 if (!warned) { \
758 warned = 1; \
759 _objc_inform_deprecated(__FUNCTION__, NULL); \
760 } \
761 } while (0) \
762
763 __END_DECLS
764
765
766 #ifndef STATIC_ASSERT
767 # define STATIC_ASSERT(x) _STATIC_ASSERT2(x, __LINE__)
768 # define _STATIC_ASSERT2(x, line) _STATIC_ASSERT3(x, line)
769 # define _STATIC_ASSERT3(x, line) \
770 typedef struct { \
771 int _static_assert[(x) ? 0 : -1]; \
772 } _static_assert_ ## line __attribute__((unavailable))
773 #endif
774
775 #define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
776
777
778 static __inline uint32_t _objc_strhash(const char *s) {
779 uint32_t hash = 0;
780 for (;;) {
781 int a = *s++;
782 if (0 == a) break;
783 hash += (hash << 8) + a;
784 }
785 return hash;
786 }
787
788 #if __cplusplus
789
790 template <typename T>
791 static inline T log2u(T x) {
792 return (x<2) ? 0 : log2u(x>>1)+1;
793 }
794
795 template <typename T>
796 static inline T exp2u(T x) {
797 return (1 << x);
798 }
799
800 template <typename T>
801 static T exp2m1u(T x) {
802 return (1 << x) - 1;
803 }
804
805 #endif
806
807 // Misalignment-safe integer types
808 __attribute__((aligned(1))) typedef uintptr_t unaligned_uintptr_t;
809 __attribute__((aligned(1))) typedef intptr_t unaligned_intptr_t;
810 __attribute__((aligned(1))) typedef uint64_t unaligned_uint64_t;
811 __attribute__((aligned(1))) typedef int64_t unaligned_int64_t;
812 __attribute__((aligned(1))) typedef uint32_t unaligned_uint32_t;
813 __attribute__((aligned(1))) typedef int32_t unaligned_int32_t;
814 __attribute__((aligned(1))) typedef uint16_t unaligned_uint16_t;
815 __attribute__((aligned(1))) typedef int16_t unaligned_int16_t;
816
817
818 // Global operator new and delete. We must not use any app overrides.
819 // This ALSO REQUIRES each of these be in libobjc's unexported symbol list.
820 #if __cplusplus
821 #pragma clang diagnostic push
822 #pragma clang diagnostic ignored "-Winline-new-delete"
823 #include <new>
824 inline void* operator new(std::size_t size) throw (std::bad_alloc) { return malloc(size); }
825 inline void* operator new[](std::size_t size) throw (std::bad_alloc) { return malloc(size); }
826 inline void* operator new(std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }
827 inline void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }
828 inline void operator delete(void* p) throw() { free(p); }
829 inline void operator delete[](void* p) throw() { free(p); }
830 inline void operator delete(void* p, const std::nothrow_t&) throw() { free(p); }
831 inline void operator delete[](void* p, const std::nothrow_t&) throw() { free(p); }
832 #pragma clang diagnostic pop
833 #endif
834
835
836 class TimeLogger {
837 uint64_t mStart;
838 bool mRecord;
839 public:
840 TimeLogger(bool record = true)
841 : mStart(nanoseconds())
842 , mRecord(record)
843 { }
844
845 void log(const char *msg) {
846 if (mRecord) {
847 uint64_t end = nanoseconds();
848 _objc_inform("%.2f ms: %s", (end - mStart) / 1000000.0, msg);
849 mStart = nanoseconds();
850 }
851 }
852 };
853
854
855 // StripedMap<T> is a map of void* -> T, sized appropriately
856 // for cache-friendly lock striping.
857 // For example, this may be used as StripedMap<spinlock_t>
858 // or as StripedMap<SomeStruct> where SomeStruct stores a spin lock.
859 template<typename T>
860 class StripedMap {
861
862 enum { CacheLineSize = 64 };
863
864 #if TARGET_OS_EMBEDDED
865 enum { StripeCount = 8 };
866 #else
867 enum { StripeCount = 64 };
868 #endif
869
870 struct PaddedT {
871 T value alignas(CacheLineSize);
872 };
873
874 PaddedT array[StripeCount];
875
876 static unsigned int indexForPointer(const void *p) {
877 uintptr_t addr = reinterpret_cast<uintptr_t>(p);
878 return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
879 }
880
881 public:
882 T& operator[] (const void *p) {
883 return array[indexForPointer(p)].value;
884 }
885 const T& operator[] (const void *p) const {
886 return const_cast<StripedMap<T>>(this)[p];
887 }
888
889 // Shortcuts for StripedMaps of locks.
890 void lockAll() {
891 for (unsigned int i = 0; i < StripeCount; i++) {
892 array[i].value.lock();
893 }
894 }
895
896 void unlockAll() {
897 for (unsigned int i = 0; i < StripeCount; i++) {
898 array[i].value.unlock();
899 }
900 }
901
902 void forceResetAll() {
903 for (unsigned int i = 0; i < StripeCount; i++) {
904 array[i].value.forceReset();
905 }
906 }
907
908 void defineLockOrder() {
909 for (unsigned int i = 1; i < StripeCount; i++) {
910 lockdebug_lock_precedes_lock(&array[i-1].value, &array[i].value);
911 }
912 }
913
914 void precedeLock(const void *newlock) {
915 // assumes defineLockOrder is also called
916 lockdebug_lock_precedes_lock(&array[StripeCount-1].value, newlock);
917 }
918
919 void succeedLock(const void *oldlock) {
920 // assumes defineLockOrder is also called
921 lockdebug_lock_precedes_lock(oldlock, &array[0].value);
922 }
923
924 #if DEBUG
925 StripedMap() {
926 // Verify alignment expectations.
927 uintptr_t base = (uintptr_t)&array[0].value;
928 uintptr_t delta = (uintptr_t)&array[1].value - base;
929 assert(delta % CacheLineSize == 0);
930 assert(base % CacheLineSize == 0);
931 }
932 #endif
933 };
934
935
936 // DisguisedPtr<T> acts like pointer type T*, except the
937 // stored value is disguised to hide it from tools like `leaks`.
938 // nil is disguised as itself so zero-filled memory works as expected,
939 // which means 0x80..00 is also disguised as itself but we don't care.
940 // Note that weak_entry_t knows about this encoding.
941 template <typename T>
942 class DisguisedPtr {
943 uintptr_t value;
944
945 static uintptr_t disguise(T* ptr) {
946 return -(uintptr_t)ptr;
947 }
948
949 static T* undisguise(uintptr_t val) {
950 return (T*)-val;
951 }
952
953 public:
954 DisguisedPtr() { }
955 DisguisedPtr(T* ptr)
956 : value(disguise(ptr)) { }
957 DisguisedPtr(const DisguisedPtr<T>& ptr)
958 : value(ptr.value) { }
959
960 DisguisedPtr<T>& operator = (T* rhs) {
961 value = disguise(rhs);
962 return *this;
963 }
964 DisguisedPtr<T>& operator = (const DisguisedPtr<T>& rhs) {
965 value = rhs.value;
966 return *this;
967 }
968
969 operator T* () const {
970 return undisguise(value);
971 }
972 T* operator -> () const {
973 return undisguise(value);
974 }
975 T& operator * () const {
976 return *undisguise(value);
977 }
978 T& operator [] (size_t i) const {
979 return undisguise(value)[i];
980 }
981
982 // pointer arithmetic operators omitted
983 // because we don't currently use them anywhere
984 };
985
986 // fixme type id is weird and not identical to objc_object*
987 static inline bool operator == (DisguisedPtr<objc_object> lhs, id rhs) {
988 return lhs == (objc_object *)rhs;
989 }
990 static inline bool operator != (DisguisedPtr<objc_object> lhs, id rhs) {
991 return lhs != (objc_object *)rhs;
992 }
993
994
995 // Pointer hash function.
996 // This is not a terrific hash, but it is fast
997 // and not outrageously flawed for our purposes.
998
999 // Based on principles from http://locklessinc.com/articles/fast_hash/
1000 // and evaluation ideas from http://floodyberry.com/noncryptohashzoo/
1001 #if __LP64__
1002 static inline uint32_t ptr_hash(uint64_t key)
1003 {
1004 key ^= key >> 4;
1005 key *= 0x8a970be7488fda55;
1006 key ^= __builtin_bswap64(key);
1007 return (uint32_t)key;
1008 }
1009 #else
1010 static inline uint32_t ptr_hash(uint32_t key)
1011 {
1012 key ^= key >> 4;
1013 key *= 0x5052acdb;
1014 key ^= __builtin_bswap32(key);
1015 return key;
1016 }
1017 #endif
1018
1019 /*
1020 Higher-quality hash function. This is measurably slower in some workloads.
1021 #if __LP64__
1022 uint32_t ptr_hash(uint64_t key)
1023 {
1024 key -= __builtin_bswap64(key);
1025 key *= 0x8a970be7488fda55;
1026 key ^= __builtin_bswap64(key);
1027 key *= 0x8a970be7488fda55;
1028 key ^= __builtin_bswap64(key);
1029 return (uint32_t)key;
1030 }
1031 #else
1032 static uint32_t ptr_hash(uint32_t key)
1033 {
1034 key -= __builtin_bswap32(key);
1035 key *= 0x5052acdb;
1036 key ^= __builtin_bswap32(key);
1037 key *= 0x5052acdb;
1038 key ^= __builtin_bswap32(key);
1039 return key;
1040 }
1041 #endif
1042 */
1043
1044
1045
1046 // Lock declarations
1047 #include "objc-locks.h"
1048
1049 // Inlined parts of objc_object's implementation
1050 #include "objc-object.h"
1051
1052 #endif /* _OBJC_PRIVATE_H_ */
1053