]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-private.h
69265c18a6c76a891ed10288c115790024728cc8
[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 union isa_t
60 {
61 isa_t() { }
62 isa_t(uintptr_t value) : bits(value) { }
63
64 Class cls;
65 uintptr_t bits;
66
67 #if SUPPORT_NONPOINTER_ISA
68
69 // extra_rc must be the MSB-most field (so it matches carry/overflow flags)
70 // indexed must be the LSB (fixme or get rid of it)
71 // shiftcls must occupy the same bits that a real class pointer would
72 // bits + RC_ONE is equivalent to extra_rc + 1
73 // RC_HALF is the high bit of extra_rc (i.e. half of its range)
74
75 // future expansion:
76 // uintptr_t fast_rr : 1; // no r/r overrides
77 // uintptr_t lock : 2; // lock for atomic property, @synch
78 // uintptr_t extraBytes : 1; // allocated with extra bytes
79
80 # if __arm64__
81 # define ISA_MASK 0x0000000ffffffff8ULL
82 # define ISA_MAGIC_MASK 0x000003f000000001ULL
83 # define ISA_MAGIC_VALUE 0x000001a000000001ULL
84 struct {
85 uintptr_t indexed : 1;
86 uintptr_t has_assoc : 1;
87 uintptr_t has_cxx_dtor : 1;
88 uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
89 uintptr_t magic : 6;
90 uintptr_t weakly_referenced : 1;
91 uintptr_t deallocating : 1;
92 uintptr_t has_sidetable_rc : 1;
93 uintptr_t extra_rc : 19;
94 # define RC_ONE (1ULL<<45)
95 # define RC_HALF (1ULL<<18)
96 };
97
98 # elif __x86_64__
99 # define ISA_MASK 0x00007ffffffffff8ULL
100 # define ISA_MAGIC_MASK 0x001f800000000001ULL
101 # define ISA_MAGIC_VALUE 0x001d800000000001ULL
102 struct {
103 uintptr_t indexed : 1;
104 uintptr_t has_assoc : 1;
105 uintptr_t has_cxx_dtor : 1;
106 uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
107 uintptr_t magic : 6;
108 uintptr_t weakly_referenced : 1;
109 uintptr_t deallocating : 1;
110 uintptr_t has_sidetable_rc : 1;
111 uintptr_t extra_rc : 8;
112 # define RC_ONE (1ULL<<56)
113 # define RC_HALF (1ULL<<7)
114 };
115
116 # else
117 // Available bits in isa field are architecture-specific.
118 # error unknown architecture
119 # endif
120
121 // SUPPORT_NONPOINTER_ISA
122 #endif
123
124 };
125
126
127 struct objc_object {
128 private:
129 isa_t isa;
130
131 public:
132
133 // ISA() assumes this is NOT a tagged pointer object
134 Class ISA();
135
136 // getIsa() allows this to be a tagged pointer object
137 Class getIsa();
138
139 // initIsa() should be used to init the isa of new objects only.
140 // If this object already has an isa, use changeIsa() for correctness.
141 // initInstanceIsa(): objects with no custom RR/AWZ
142 // initClassIsa(): class objects
143 // initProtocolIsa(): protocol objects
144 // initIsa(): other objects
145 void initIsa(Class cls /*indexed=false*/);
146 void initClassIsa(Class cls /*indexed=maybe*/);
147 void initProtocolIsa(Class cls /*indexed=maybe*/);
148 void initInstanceIsa(Class cls, bool hasCxxDtor);
149
150 // changeIsa() should be used to change the isa of existing objects.
151 // If this is a new object, use initIsa() for performance.
152 Class changeIsa(Class newCls);
153
154 bool hasIndexedIsa();
155 bool isTaggedPointer();
156 bool isClass();
157
158 // object may have associated objects?
159 bool hasAssociatedObjects();
160 void setHasAssociatedObjects();
161
162 // object may be weakly referenced?
163 bool isWeaklyReferenced();
164 void setWeaklyReferenced_nolock();
165
166 // object may have -.cxx_destruct implementation?
167 bool hasCxxDtor();
168
169 // Optimized calls to retain/release methods
170 id retain();
171 void release();
172 id autorelease();
173
174 // Implementations of retain/release methods
175 id rootRetain();
176 bool rootRelease();
177 id rootAutorelease();
178 bool rootTryRetain();
179 bool rootReleaseShouldDealloc();
180 uintptr_t rootRetainCount();
181
182 // Implementation of dealloc methods
183 bool rootIsDeallocating();
184 void clearDeallocating();
185 void rootDealloc();
186
187 private:
188 void initIsa(Class newCls, bool indexed, bool hasCxxDtor);
189
190 // Slow paths for inline control
191 id rootAutorelease2();
192 bool overrelease_error();
193
194 #if SUPPORT_NONPOINTER_ISA
195 // Unified retain count manipulation for nonpointer isa
196 id rootRetain(bool tryRetain, bool handleOverflow);
197 bool rootRelease(bool performDealloc, bool handleUnderflow);
198 id rootRetain_overflow(bool tryRetain);
199 bool rootRelease_underflow(bool performDealloc);
200
201 void clearDeallocating_slow();
202
203 // Side table retain count overflow for nonpointer isa
204 void sidetable_lock();
205 void sidetable_unlock();
206
207 void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
208 bool sidetable_addExtraRC_nolock(size_t delta_rc);
209 size_t sidetable_subExtraRC_nolock(size_t delta_rc);
210 size_t sidetable_getExtraRC_nolock();
211 #endif
212
213 // Side-table-only retain count
214 bool sidetable_isDeallocating();
215 void sidetable_clearDeallocating();
216
217 bool sidetable_isWeaklyReferenced();
218 void sidetable_setWeaklyReferenced_nolock();
219
220 id sidetable_retain();
221 id sidetable_retain_slow(SideTable& table);
222
223 uintptr_t sidetable_release(bool performDealloc = true);
224 uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);
225
226 bool sidetable_tryRetain();
227
228 uintptr_t sidetable_retainCount();
229 #if DEBUG
230 bool sidetable_present();
231 #endif
232 };
233
234
235 #if __OBJC2__
236 typedef struct method_t *Method;
237 typedef struct ivar_t *Ivar;
238 typedef struct category_t *Category;
239 typedef struct property_t *objc_property_t;
240 #else
241 typedef struct old_method *Method;
242 typedef struct old_ivar *Ivar;
243 typedef struct old_category *Category;
244 typedef struct old_property *objc_property_t;
245 #endif
246
247 // Public headers
248
249 #include "objc.h"
250 #include "runtime.h"
251 #include "objc-os.h"
252 #include "objc-abi.h"
253 #include "objc-api.h"
254 #include "objc-config.h"
255 #include "objc-internal.h"
256 #include "maptable.h"
257 #include "hashtable2.h"
258
259 #if SUPPORT_GC
260 #include "objc-auto.h"
261 #endif
262
263 /* Do not include message.h here. */
264 /* #include "message.h" */
265
266 #define __APPLE_API_PRIVATE
267 #include "objc-gdb.h"
268 #undef __APPLE_API_PRIVATE
269
270
271 // Private headers
272
273 #if __OBJC2__
274 #include "objc-runtime-new.h"
275 #else
276 #include "objc-runtime-old.h"
277 #endif
278
279 #include "objc-references.h"
280 #include "objc-initialize.h"
281 #include "objc-loadmethod.h"
282
283
284 #if SUPPORT_PREOPT && __cplusplus
285 #include <objc-shared-cache.h>
286 using objc_selopt_t = const objc_opt::objc_selopt_t;
287 #else
288 struct objc_selopt_t;
289 #endif
290
291
292 __BEGIN_DECLS
293
294
295 #if (defined(OBJC_NO_GC) && SUPPORT_GC) || \
296 (!defined(OBJC_NO_GC) && !SUPPORT_GC)
297 # error OBJC_NO_GC and SUPPORT_GC inconsistent
298 #endif
299
300 #if SUPPORT_GC
301 # include <auto_zone.h>
302 // PRIVATE_EXTERN is needed to help the compiler know "how" extern these are
303 PRIVATE_EXTERN extern int8_t UseGC; // equivalent to calling objc_collecting_enabled()
304 PRIVATE_EXTERN extern auto_zone_t *gc_zone; // the GC zone, or NULL if no GC
305 extern void objc_addRegisteredClass(Class c);
306 extern void objc_removeRegisteredClass(Class c);
307 #else
308 # define UseGC NO
309 # define gc_zone NULL
310 # define objc_addRegisteredClass(c) do {} while(0)
311 # define objc_removeRegisteredClass(c) do {} while(0)
312 /* Uses of the following must be protected with UseGC. */
313 extern id gc_unsupported_dont_call();
314 # define auto_zone_allocate_object gc_unsupported_dont_call
315 # define auto_zone_retain gc_unsupported_dont_call
316 # define auto_zone_release gc_unsupported_dont_call
317 # define auto_zone_is_valid_pointer gc_unsupported_dont_call
318 # define auto_zone_write_barrier_memmove gc_unsupported_dont_call
319 # define AUTO_OBJECT_SCANNED 0
320 #endif
321
322
323 #define _objcHeaderIsReplacement(h) ((h)->info && ((h)->info->flags & OBJC_IMAGE_IS_REPLACEMENT))
324
325 /* OBJC_IMAGE_IS_REPLACEMENT:
326 Don't load any classes
327 Don't load any categories
328 Do fix up selector refs (@selector points to them)
329 Do fix up class refs (@class and objc_msgSend points to them)
330 Do fix up protocols (@protocol points to them)
331 Do fix up superclass pointers in classes ([super ...] points to them)
332 Future: do load new classes?
333 Future: do load new categories?
334 Future: do insert new methods on existing classes?
335 Future: do insert new methods on existing categories?
336 */
337
338 #define _objcInfoSupportsGC(info) (((info)->flags & OBJC_IMAGE_SUPPORTS_GC) ? 1 : 0)
339 #define _objcInfoRequiresGC(info) (((info)->flags & OBJC_IMAGE_REQUIRES_GC) ? 1 : 0)
340 #define _objcHeaderSupportsGC(h) ((h)->info && _objcInfoSupportsGC((h)->info))
341 #define _objcHeaderRequiresGC(h) ((h)->info && _objcInfoRequiresGC((h)->info))
342
343 /* OBJC_IMAGE_SUPPORTS_GC:
344 was compiled with -fobjc-gc flag, regardless of whether write-barriers were issued
345 if executable image compiled this way, then all subsequent libraries etc. must also be this way
346 */
347
348 #define _objcHeaderOptimizedByDyld(h) ((h)->info && ((h)->info->flags & OBJC_IMAGE_OPTIMIZED_BY_DYLD))
349
350 /* OBJC_IMAGE_OPTIMIZED_BY_DYLD:
351 Assorted metadata precooked in the dyld shared cache.
352 Never set for images outside the shared cache file itself.
353 */
354
355
356 typedef struct header_info {
357 struct header_info *next;
358 const headerType *mhdr;
359 const objc_image_info *info;
360 const char *fname; // same as Dl_info.dli_fname
361 bool loaded;
362 bool inSharedCache;
363 bool allClassesRealized;
364
365 // Do not add fields without editing ObjCModernAbstraction.hpp
366
367 bool isLoaded() {
368 return loaded;
369 }
370
371 bool isBundle() {
372 return mhdr->filetype == MH_BUNDLE;
373 }
374
375 bool isPreoptimized() const;
376
377 #if !__OBJC2__
378 struct old_protocol **proto_refs;
379 struct objc_module *mod_ptr;
380 size_t mod_count;
381 # if TARGET_OS_WIN32
382 struct objc_module **modules;
383 size_t moduleCount;
384 struct old_protocol **protocols;
385 size_t protocolCount;
386 void *imageinfo;
387 size_t imageinfoBytes;
388 SEL *selrefs;
389 size_t selrefCount;
390 struct objc_class **clsrefs;
391 size_t clsrefCount;
392 TCHAR *moduleName;
393 # endif
394 #endif
395 } header_info;
396
397 extern header_info *FirstHeader;
398 extern header_info *LastHeader;
399 extern int HeaderCount;
400
401 extern void appendHeader(header_info *hi);
402 extern void removeHeader(header_info *hi);
403
404 extern objc_image_info *_getObjcImageInfo(const headerType *head, size_t *size);
405 extern bool _hasObjcContents(const header_info *hi);
406
407
408 /* selectors */
409 extern void sel_init(bool gc, size_t selrefCount);
410 extern SEL sel_registerNameNoLock(const char *str, bool copy);
411 extern void sel_lock(void);
412 extern void sel_unlock(void);
413
414 extern SEL SEL_load;
415 extern SEL SEL_initialize;
416 extern SEL SEL_resolveClassMethod;
417 extern SEL SEL_resolveInstanceMethod;
418 extern SEL SEL_cxx_construct;
419 extern SEL SEL_cxx_destruct;
420 extern SEL SEL_retain;
421 extern SEL SEL_release;
422 extern SEL SEL_autorelease;
423 extern SEL SEL_retainCount;
424 extern SEL SEL_alloc;
425 extern SEL SEL_allocWithZone;
426 extern SEL SEL_dealloc;
427 extern SEL SEL_copy;
428 extern SEL SEL_new;
429 extern SEL SEL_finalize;
430 extern SEL SEL_forwardInvocation;
431 extern SEL SEL_tryRetain;
432 extern SEL SEL_isDeallocating;
433 extern SEL SEL_retainWeakReference;
434 extern SEL SEL_allowsWeakReference;
435
436 /* preoptimization */
437 extern void preopt_init(void);
438 extern void disableSharedCacheOptimizations(void);
439 extern bool isPreoptimized(void);
440 extern header_info *preoptimizedHinfoForHeader(const headerType *mhdr);
441
442 extern objc_selopt_t *preoptimizedSelectors(void);
443
444 extern Protocol *getPreoptimizedProtocol(const char *name);
445
446 extern Class getPreoptimizedClass(const char *name);
447 extern Class* copyPreoptimizedClasses(const char *name, int *outCount);
448
449 extern Class _calloc_class(size_t size);
450
451 /* method lookup */
452 extern IMP lookUpImpOrNil(Class, SEL, id obj, bool initialize, bool cache, bool resolver);
453 extern IMP lookUpImpOrForward(Class, SEL, id obj, bool initialize, bool cache, bool resolver);
454
455 extern IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel);
456 extern bool class_respondsToSelector_inst(Class cls, SEL sel, id inst);
457
458 extern bool objcMsgLogEnabled;
459 extern bool logMessageSend(bool isClassMethod,
460 const char *objectsClass,
461 const char *implementingClass,
462 SEL selector);
463
464 /* message dispatcher */
465 extern IMP _class_lookupMethodAndLoadCache3(id, SEL, Class);
466
467 #if !OBJC_OLD_DISPATCH_PROTOTYPES
468 extern void _objc_msgForward_impcache(void);
469 extern void _objc_ignored_method(void);
470 extern void _objc_msgSend_uncached_impcache(void);
471 #else
472 extern id _objc_msgForward_impcache(id, SEL, ...);
473 extern id _objc_ignored_method(id, SEL, ...);
474 extern id _objc_msgSend_uncached_impcache(id, SEL, ...);
475 #endif
476
477 /* errors */
478 extern void __objc_error(id, const char *, ...) __attribute__((format (printf, 2, 3), noreturn));
479 extern void _objc_inform(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
480 extern void _objc_inform_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
481 extern void _objc_inform_now_and_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
482 extern void _objc_inform_deprecated(const char *oldname, const char *newname) __attribute__((noinline));
483 extern void inform_duplicate(const char *name, Class oldCls, Class cls);
484 extern bool crashlog_header_name(header_info *hi);
485 extern bool crashlog_header_name_string(const char *name);
486
487 /* magic */
488 extern Class _objc_getFreedObjectClass (void);
489
490 /* map table additions */
491 extern void *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value);
492 extern void *NXMapKeyFreeingRemove(NXMapTable *table, const void *key);
493
494 /* hash table additions */
495 extern unsigned _NXHashCapacity(NXHashTable *table);
496 extern void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity);
497
498 /* property attribute parsing */
499 extern const char *copyPropertyAttributeString(const objc_property_attribute_t *attrs, unsigned int count);
500 extern objc_property_attribute_t *copyPropertyAttributeList(const char *attrs, unsigned int *outCount);
501 extern char *copyPropertyAttributeValue(const char *attrs, const char *name);
502
503 /* locking */
504 extern void lock_init(void);
505 extern rwlock_t selLock;
506 extern mutex_t cacheUpdateLock;
507 extern recursive_mutex_t loadMethodLock;
508 #if __OBJC2__
509 extern rwlock_t runtimeLock;
510 #else
511 extern mutex_t classLock;
512 extern mutex_t methodListLock;
513 #endif
514
515 class monitor_locker_t : nocopy_t {
516 monitor_t& lock;
517 public:
518 monitor_locker_t(monitor_t& newLock) : lock(newLock) { lock.enter(); }
519 ~monitor_locker_t() { lock.leave(); }
520 };
521
522 class mutex_locker_t : nocopy_t {
523 mutex_t& lock;
524 public:
525 mutex_locker_t(mutex_t& newLock)
526 : lock(newLock) { lock.lock(); }
527 ~mutex_locker_t() { lock.unlock(); }
528 };
529
530 class recursive_mutex_locker_t : nocopy_t {
531 recursive_mutex_t& lock;
532 public:
533 recursive_mutex_locker_t(recursive_mutex_t& newLock)
534 : lock(newLock) { lock.lock(); }
535 ~recursive_mutex_locker_t() { lock.unlock(); }
536 };
537
538 class rwlock_reader_t : nocopy_t {
539 rwlock_t& lock;
540 public:
541 rwlock_reader_t(rwlock_t& newLock) : lock(newLock) { lock.read(); }
542 ~rwlock_reader_t() { lock.unlockRead(); }
543 };
544
545 class rwlock_writer_t : nocopy_t {
546 rwlock_t& lock;
547 public:
548 rwlock_writer_t(rwlock_t& newLock) : lock(newLock) { lock.write(); }
549 ~rwlock_writer_t() { lock.unlockWrite(); }
550 };
551
552 /* ignored selector support */
553
554 /* Non-GC: no ignored selectors
555 GC (i386 Mac): some selectors ignored, remapped to kIgnore
556 GC (others): some selectors ignored, but not remapped
557 */
558
559 static inline int ignoreSelector(SEL sel)
560 {
561 #if !SUPPORT_GC
562 return NO;
563 #elif SUPPORT_IGNORED_SELECTOR_CONSTANT
564 return UseGC && sel == (SEL)kIgnore;
565 #else
566 return UseGC &&
567 (sel == @selector(retain) ||
568 sel == @selector(release) ||
569 sel == @selector(autorelease) ||
570 sel == @selector(retainCount) ||
571 sel == @selector(dealloc));
572 #endif
573 }
574
575 static inline int ignoreSelectorNamed(const char *sel)
576 {
577 #if !SUPPORT_GC
578 return NO;
579 #else
580 // release retain retainCount dealloc autorelease
581 return (UseGC &&
582 ( (sel[0] == 'r' && sel[1] == 'e' &&
583 (strcmp(&sel[2], "lease") == 0 ||
584 strcmp(&sel[2], "tain") == 0 ||
585 strcmp(&sel[2], "tainCount") == 0 ))
586 ||
587 (strcmp(sel, "dealloc") == 0)
588 ||
589 (sel[0] == 'a' && sel[1] == 'u' &&
590 strcmp(&sel[2], "torelease") == 0)));
591 #endif
592 }
593
594 /* GC startup */
595 extern void gc_init(bool wantsGC);
596 extern void gc_init2(void);
597
598 /* Exceptions */
599 struct alt_handler_list;
600 extern void exception_init(void);
601 extern void _destroyAltHandlerList(struct alt_handler_list *list);
602
603 /* Class change notifications (gdb only for now) */
604 #define OBJC_CLASS_ADDED (1<<0)
605 #define OBJC_CLASS_REMOVED (1<<1)
606 #define OBJC_CLASS_IVARS_CHANGED (1<<2)
607 #define OBJC_CLASS_METHODS_CHANGED (1<<3)
608 extern void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)
609 __attribute__((noinline));
610
611 #if SUPPORT_GC
612
613 /* Write barrier implementations */
614 extern id objc_getAssociatedObject_non_gc(id object, const void *key);
615 extern void objc_setAssociatedObject_non_gc(id object, const void *key, id value, objc_AssociationPolicy policy);
616
617 extern id objc_getAssociatedObject_gc(id object, const void *key);
618 extern void objc_setAssociatedObject_gc(id object, const void *key, id value, objc_AssociationPolicy policy);
619
620 /* xrefs */
621 extern objc_xref_t _object_addExternalReference_non_gc(id obj, objc_xref_t type);
622 extern id _object_readExternalReference_non_gc(objc_xref_t ref);
623 extern void _object_removeExternalReference_non_gc(objc_xref_t ref);
624
625 extern objc_xref_t _object_addExternalReference_gc(id obj, objc_xref_t type);
626 extern id _object_readExternalReference_gc(objc_xref_t ref);
627 extern void _object_removeExternalReference_gc(objc_xref_t ref);
628
629 /* GC weak reference fixup. */
630 extern void gc_fixup_weakreferences(id newObject, id oldObject);
631
632 /* GC datasegment registration. */
633 extern void gc_register_datasegment(uintptr_t base, size_t size);
634 extern void gc_unregister_datasegment(uintptr_t base, size_t size);
635
636 /* objc_dumpHeap implementation */
637 extern bool _objc_dumpHeap(auto_zone_t *zone, const char *filename);
638
639 #endif
640
641
642 // Settings from environment variables
643 #define OPTION(var, env, help) extern bool var;
644 #include "objc-env.h"
645 #undef OPTION
646
647 extern void environ_init(void);
648
649 extern void logReplacedMethod(const char *className, SEL s, bool isMeta, const char *catName, IMP oldImp, IMP newImp);
650
651
652 // objc per-thread storage
653 typedef struct {
654 struct _objc_initializing_classes *initializingClasses; // for +initialize
655 struct SyncCache *syncCache; // for @synchronize
656 struct alt_handler_list *handlerList; // for exception alt handlers
657 char *printableNames[4]; // temporary demangled names for logging
658
659 // If you add new fields here, don't forget to update
660 // _objc_pthread_destroyspecific()
661
662 } _objc_pthread_data;
663
664 extern _objc_pthread_data *_objc_fetch_pthread_data(bool create);
665 extern void tls_init(void);
666
667 // encoding.h
668 extern unsigned int encoding_getNumberOfArguments(const char *typedesc);
669 extern unsigned int encoding_getSizeOfArguments(const char *typedesc);
670 extern unsigned int encoding_getArgumentInfo(const char *typedesc, unsigned int arg, const char **type, int *offset);
671 extern void encoding_getReturnType(const char *t, char *dst, size_t dst_len);
672 extern char * encoding_copyReturnType(const char *t);
673 extern void encoding_getArgumentType(const char *t, unsigned int index, char *dst, size_t dst_len);
674 extern char *encoding_copyArgumentType(const char *t, unsigned int index);
675
676 // sync.h
677 extern void _destroySyncCache(struct SyncCache *cache);
678
679 // arr
680 extern void arr_init(void);
681 extern id objc_autoreleaseReturnValue(id obj);
682
683 // block trampolines
684 extern IMP _imp_implementationWithBlockNoCopy(id block);
685
686 // layout.h
687 typedef struct {
688 uint8_t *bits;
689 size_t bitCount;
690 size_t bitsAllocated;
691 bool weak;
692 } layout_bitmap;
693 extern layout_bitmap layout_bitmap_create(const unsigned char *layout_string, size_t layoutStringInstanceSize, size_t instanceSize, bool weak);
694 extern layout_bitmap layout_bitmap_create_empty(size_t instanceSize, bool weak);
695 extern void layout_bitmap_free(layout_bitmap bits);
696 extern const unsigned char *layout_string_create(layout_bitmap bits);
697 extern void layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset);
698 extern void layout_bitmap_grow(layout_bitmap *bits, size_t newCount);
699 extern void layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos);
700 extern void layout_bitmap_slide_anywhere(layout_bitmap *bits, size_t oldPos, size_t newPos);
701 extern bool layout_bitmap_splat(layout_bitmap dst, layout_bitmap src,
702 size_t oldSrcInstanceSize);
703 extern bool layout_bitmap_or(layout_bitmap dst, layout_bitmap src, const char *msg);
704 extern bool layout_bitmap_clear(layout_bitmap dst, layout_bitmap src, const char *msg);
705 extern void layout_bitmap_print(layout_bitmap bits);
706
707
708 // fixme runtime
709 extern Class look_up_class(const char *aClassName, bool includeUnconnected, bool includeClassHandler);
710 extern "C" const char *map_2_images(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]);
711 extern const char *map_images_nolock(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]);
712 extern const char * load_images(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]);
713 extern bool load_images_nolock(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]);
714 extern void unmap_image(const struct mach_header *mh, intptr_t vmaddr_slide);
715 extern void unmap_image_nolock(const struct mach_header *mh);
716 extern void _read_images(header_info **hList, uint32_t hCount);
717 extern void prepare_load_methods(const headerType *mhdr);
718 extern bool hasLoadMethods(const headerType *mhdr);
719 extern void _unload_image(header_info *hi);
720 extern const char ** _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount);
721
722
723 extern const header_info *_headerForClass(Class cls);
724
725 extern Class _class_remap(Class cls);
726 extern Class _class_getNonMetaClass(Class cls, id obj);
727 extern Ivar _class_getVariable(Class cls, const char *name, Class *memberOf);
728 extern uint32_t _class_getInstanceStart(Class cls);
729
730 extern unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, id *results, unsigned num_requested);
731 extern id _objc_constructOrFree(id bytes, Class cls);
732
733 extern const char *_category_getName(Category cat);
734 extern const char *_category_getClassName(Category cat);
735 extern Class _category_getClass(Category cat);
736 extern IMP _category_getLoadMethod(Category cat);
737
738 extern id object_cxxConstructFromClass(id obj, Class cls);
739 extern void object_cxxDestruct(id obj);
740
741 extern void _class_resolveMethod(Class cls, SEL sel, id inst);
742
743 #define OBJC_WARN_DEPRECATED \
744 do { \
745 static int warned = 0; \
746 if (!warned) { \
747 warned = 1; \
748 _objc_inform_deprecated(__FUNCTION__, NULL); \
749 } \
750 } while (0) \
751
752 __END_DECLS
753
754
755 #ifndef STATIC_ASSERT
756 # define STATIC_ASSERT(x) _STATIC_ASSERT2(x, __LINE__)
757 # define _STATIC_ASSERT2(x, line) _STATIC_ASSERT3(x, line)
758 # define _STATIC_ASSERT3(x, line) \
759 typedef struct { \
760 int _static_assert[(x) ? 0 : -1]; \
761 } _static_assert_ ## line __attribute__((unavailable))
762 #endif
763
764 #define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
765
766
767 static __inline uint32_t _objc_strhash(const char *s) {
768 uint32_t hash = 0;
769 for (;;) {
770 int a = *s++;
771 if (0 == a) break;
772 hash += (hash << 8) + a;
773 }
774 return hash;
775 }
776
777 #if __cplusplus
778
779 template <typename T>
780 static inline T log2u(T x) {
781 return (x<2) ? 0 : log2u(x>>1)+1;
782 }
783
784 template <typename T>
785 static inline T exp2u(T x) {
786 return (1 << x);
787 }
788
789 template <typename T>
790 static T exp2m1u(T x) {
791 return (1 << x) - 1;
792 }
793
794 #endif
795
796
797 // Global operator new and delete. We must not use any app overrides.
798 // This ALSO REQUIRES each of these be in libobjc's unexported symbol list.
799 #if __cplusplus
800 #pragma clang diagnostic push
801 #pragma clang diagnostic ignored "-Winline-new-delete"
802 #include <new>
803 inline void* operator new(std::size_t size) throw (std::bad_alloc) { return malloc(size); }
804 inline void* operator new[](std::size_t size) throw (std::bad_alloc) { return malloc(size); }
805 inline void* operator new(std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }
806 inline void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }
807 inline void operator delete(void* p) throw() { free(p); }
808 inline void operator delete[](void* p) throw() { free(p); }
809 inline void operator delete(void* p, const std::nothrow_t&) throw() { free(p); }
810 inline void operator delete[](void* p, const std::nothrow_t&) throw() { free(p); }
811 #pragma clang diagnostic pop
812 #endif
813
814
815 class TimeLogger {
816 uint64_t mStart;
817 bool mRecord;
818 public:
819 TimeLogger(bool record = true)
820 : mStart(nanoseconds())
821 , mRecord(record)
822 { }
823
824 void log(const char *msg) {
825 if (mRecord) {
826 uint64_t end = nanoseconds();
827 _objc_inform("%.2f ms: %s", (end - mStart) / 1000000.0, msg);
828 mStart = nanoseconds();
829 }
830 }
831 };
832
833
834 // StripedMap<T> is a map of void* -> T, sized appropriately
835 // for cache-friendly lock striping.
836 // For example, this may be used as StripedMap<spinlock_t>
837 // or as StripedMap<SomeStruct> where SomeStruct stores a spin lock.
838 template<typename T>
839 class StripedMap {
840
841 enum { CacheLineSize = 64 };
842
843 #if TARGET_OS_EMBEDDED
844 enum { StripeCount = 8 };
845 #else
846 enum { StripeCount = 64 };
847 #endif
848
849 struct PaddedT {
850 T value alignas(CacheLineSize);
851 };
852
853 PaddedT array[StripeCount];
854
855 static unsigned int indexForPointer(const void *p) {
856 uintptr_t addr = reinterpret_cast<uintptr_t>(p);
857 return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
858 }
859
860 public:
861 T& operator[] (const void *p) {
862 return array[indexForPointer(p)].value;
863 }
864 const T& operator[] (const void *p) const {
865 return const_cast<StripedMap<T>>(this)[p];
866 }
867
868 #if DEBUG
869 StripedMap() {
870 // Verify alignment expectations.
871 uintptr_t base = (uintptr_t)&array[0].value;
872 uintptr_t delta = (uintptr_t)&array[1].value - base;
873 assert(delta % CacheLineSize == 0);
874 assert(base % CacheLineSize == 0);
875 }
876 #endif
877 };
878
879
880 // DisguisedPtr<T> acts like pointer type T*, except the
881 // stored value is disguised to hide it from tools like `leaks`.
882 // nil is disguised as itself so zero-filled memory works as expected,
883 // which means 0x80..00 is also diguised as itself but we don't care
884 template <typename T>
885 class DisguisedPtr {
886 uintptr_t value;
887
888 static uintptr_t disguise(T* ptr) {
889 return -(uintptr_t)ptr;
890 }
891
892 static T* undisguise(uintptr_t val) {
893 return (T*)-val;
894 }
895
896 public:
897 DisguisedPtr() { }
898 DisguisedPtr(T* ptr)
899 : value(disguise(ptr)) { }
900 DisguisedPtr(const DisguisedPtr<T>& ptr)
901 : value(ptr.value) { }
902
903 DisguisedPtr<T>& operator = (T* rhs) {
904 value = disguise(rhs);
905 return *this;
906 }
907 DisguisedPtr<T>& operator = (const DisguisedPtr<T>& rhs) {
908 value = rhs.value;
909 return *this;
910 }
911
912 operator T* () const {
913 return undisguise(value);
914 }
915 T* operator -> () const {
916 return undisguise(value);
917 }
918 T& operator * () const {
919 return *undisguise(value);
920 }
921 T& operator [] (size_t i) const {
922 return undisguise(value)[i];
923 }
924
925 // pointer arithmetic operators omitted
926 // because we don't currently use them anywhere
927 };
928
929 // fixme type id is weird and not identical to objc_object*
930 static inline bool operator == (DisguisedPtr<objc_object> lhs, id rhs) {
931 return lhs == (objc_object *)rhs;
932 }
933 static inline bool operator != (DisguisedPtr<objc_object> lhs, id rhs) {
934 return lhs != (objc_object *)rhs;
935 }
936
937
938 // Pointer hash function.
939 // This is not a terrific hash, but it is fast
940 // and not outrageously flawed for our purposes.
941
942 // Based on principles from http://locklessinc.com/articles/fast_hash/
943 // and evaluation ideas from http://floodyberry.com/noncryptohashzoo/
944 #if __LP64__
945 static inline uint32_t ptr_hash(uint64_t key)
946 {
947 key ^= key >> 4;
948 key *= 0x8a970be7488fda55;
949 key ^= __builtin_bswap64(key);
950 return (uint32_t)key;
951 }
952 #else
953 static inline uint32_t ptr_hash(uint32_t key)
954 {
955 key ^= key >> 4;
956 key *= 0x5052acdb;
957 key ^= __builtin_bswap32(key);
958 return key;
959 }
960 #endif
961
962 /*
963 Higher-quality hash function. This is measurably slower in some workloads.
964 #if __LP64__
965 uint32_t ptr_hash(uint64_t key)
966 {
967 key -= __builtin_bswap64(key);
968 key *= 0x8a970be7488fda55;
969 key ^= __builtin_bswap64(key);
970 key *= 0x8a970be7488fda55;
971 key ^= __builtin_bswap64(key);
972 return (uint32_t)key;
973 }
974 #else
975 static uint32_t ptr_hash(uint32_t key)
976 {
977 key -= __builtin_bswap32(key);
978 key *= 0x5052acdb;
979 key ^= __builtin_bswap32(key);
980 key *= 0x5052acdb;
981 key ^= __builtin_bswap32(key);
982 return key;
983 }
984 #endif
985 */
986
987
988 // Inlined parts of objc_object's implementation
989 #include "objc-object.h"
990
991 #endif /* _OBJC_PRIVATE_H_ */
992