]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-private.h
objc4-787.1.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 #undef OBJC_OLD_DISPATCH_PROTOTYPES
43 #define OBJC_OLD_DISPATCH_PROTOTYPES 0
44
45 #include <cstddef> // for nullptr_t
46 #include <stdint.h>
47 #include <assert.h>
48
49 // An assert that's disabled for release builds but still ensures the expression compiles.
50 #ifdef NDEBUG
51 #define ASSERT(x) (void)sizeof(!(x))
52 #else
53 #define ASSERT(x) assert(x)
54 #endif
55
56 struct objc_class;
57 struct objc_object;
58 struct category_t;
59
60 typedef struct objc_class *Class;
61 typedef struct objc_object *id;
62 typedef struct classref *classref_t;
63
64 namespace {
65 struct SideTable;
66 };
67
68 #include "isa.h"
69
70 union isa_t {
71 isa_t() { }
72 isa_t(uintptr_t value) : bits(value) { }
73
74 Class cls;
75 uintptr_t bits;
76 #if defined(ISA_BITFIELD)
77 struct {
78 ISA_BITFIELD; // defined in isa.h
79 };
80 #endif
81 };
82
83
84 struct objc_object {
85 private:
86 isa_t isa;
87
88 public:
89
90 // ISA() assumes this is NOT a tagged pointer object
91 Class ISA();
92
93 // rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
94 Class rawISA();
95
96 // getIsa() allows this to be a tagged pointer object
97 Class getIsa();
98
99 uintptr_t isaBits() const;
100
101 // initIsa() should be used to init the isa of new objects only.
102 // If this object already has an isa, use changeIsa() for correctness.
103 // initInstanceIsa(): objects with no custom RR/AWZ
104 // initClassIsa(): class objects
105 // initProtocolIsa(): protocol objects
106 // initIsa(): other objects
107 void initIsa(Class cls /*nonpointer=false*/);
108 void initClassIsa(Class cls /*nonpointer=maybe*/);
109 void initProtocolIsa(Class cls /*nonpointer=maybe*/);
110 void initInstanceIsa(Class cls, bool hasCxxDtor);
111
112 // changeIsa() should be used to change the isa of existing objects.
113 // If this is a new object, use initIsa() for performance.
114 Class changeIsa(Class newCls);
115
116 bool hasNonpointerIsa();
117 bool isTaggedPointer();
118 bool isBasicTaggedPointer();
119 bool isExtTaggedPointer();
120 bool isClass();
121
122 // object may have associated objects?
123 bool hasAssociatedObjects();
124 void setHasAssociatedObjects();
125
126 // object may be weakly referenced?
127 bool isWeaklyReferenced();
128 void setWeaklyReferenced_nolock();
129
130 // object may have -.cxx_destruct implementation?
131 bool hasCxxDtor();
132
133 // Optimized calls to retain/release methods
134 id retain();
135 void release();
136 id autorelease();
137
138 // Implementations of retain/release methods
139 id rootRetain();
140 bool rootRelease();
141 id rootAutorelease();
142 bool rootTryRetain();
143 bool rootReleaseShouldDealloc();
144 uintptr_t rootRetainCount();
145
146 // Implementation of dealloc methods
147 bool rootIsDeallocating();
148 void clearDeallocating();
149 void rootDealloc();
150
151 private:
152 void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);
153
154 // Slow paths for inline control
155 id rootAutorelease2();
156 uintptr_t overrelease_error();
157
158 #if SUPPORT_NONPOINTER_ISA
159 // Unified retain count manipulation for nonpointer isa
160 id rootRetain(bool tryRetain, bool handleOverflow);
161 bool rootRelease(bool performDealloc, bool handleUnderflow);
162 id rootRetain_overflow(bool tryRetain);
163 uintptr_t rootRelease_underflow(bool performDealloc);
164
165 void clearDeallocating_slow();
166
167 // Side table retain count overflow for nonpointer isa
168 void sidetable_lock();
169 void sidetable_unlock();
170
171 void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
172 bool sidetable_addExtraRC_nolock(size_t delta_rc);
173 size_t sidetable_subExtraRC_nolock(size_t delta_rc);
174 size_t sidetable_getExtraRC_nolock();
175 #endif
176
177 // Side-table-only retain count
178 bool sidetable_isDeallocating();
179 void sidetable_clearDeallocating();
180
181 bool sidetable_isWeaklyReferenced();
182 void sidetable_setWeaklyReferenced_nolock();
183
184 id sidetable_retain();
185 id sidetable_retain_slow(SideTable& table);
186
187 uintptr_t sidetable_release(bool performDealloc = true);
188 uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);
189
190 bool sidetable_tryRetain();
191
192 uintptr_t sidetable_retainCount();
193 #if DEBUG
194 bool sidetable_present();
195 #endif
196 };
197
198
199 #if __OBJC2__
200 typedef struct method_t *Method;
201 typedef struct ivar_t *Ivar;
202 typedef struct category_t *Category;
203 typedef struct property_t *objc_property_t;
204 #else
205 typedef struct old_method *Method;
206 typedef struct old_ivar *Ivar;
207 typedef struct old_category *Category;
208 typedef struct old_property *objc_property_t;
209 #endif
210
211 // Public headers
212
213 #include "objc.h"
214 #include "runtime.h"
215 #include "objc-os.h"
216 #include "objc-abi.h"
217 #include "objc-api.h"
218 #include "objc-config.h"
219 #include "objc-internal.h"
220 #include "maptable.h"
221 #include "hashtable2.h"
222
223 /* Do not include message.h here. */
224 /* #include "message.h" */
225
226 #define __APPLE_API_PRIVATE
227 #include "objc-gdb.h"
228 #undef __APPLE_API_PRIVATE
229
230
231 // Private headers
232
233 #include "objc-ptrauth.h"
234
235 #if __OBJC2__
236 #include "objc-runtime-new.h"
237 #else
238 #include "objc-runtime-old.h"
239 #endif
240
241 #include "objc-references.h"
242 #include "objc-initialize.h"
243 #include "objc-loadmethod.h"
244
245
246 #define STRINGIFY(x) #x
247 #define STRINGIFY2(x) STRINGIFY(x)
248
249 __BEGIN_DECLS
250
251 namespace objc {
252
253 struct SafeRanges {
254 private:
255 struct Range {
256 uintptr_t start;
257 uintptr_t end;
258
259 inline bool contains(uintptr_t ptr) const {
260 uintptr_t m_start, m_end;
261 #if __arm64__
262 // <rdar://problem/48304934> Force the compiler to use ldp
263 // we really don't want 2 loads and 2 jumps.
264 __asm__(
265 # if __LP64__
266 "ldp %x[one], %x[two], [%x[src]]"
267 # else
268 "ldp %w[one], %w[two], [%x[src]]"
269 # endif
270 : [one] "=r" (m_start), [two] "=r" (m_end)
271 : [src] "r" (this)
272 );
273 #else
274 m_start = start;
275 m_end = end;
276 #endif
277 return m_start <= ptr && ptr < m_end;
278 }
279 };
280
281 struct Range *ranges;
282 uint32_t count;
283 uint32_t size : 31;
284 uint32_t sorted : 1;
285
286 public:
287 inline bool contains(uint16_t witness, uintptr_t ptr) const {
288 return witness < count && ranges[witness].contains(ptr);
289 }
290
291 bool find(uintptr_t ptr, uint32_t &pos);
292 void add(uintptr_t start, uintptr_t end);
293 void remove(uintptr_t start, uintptr_t end);
294 };
295
296 extern struct SafeRanges dataSegmentsRanges;
297
298 } // objc
299
300 struct header_info;
301
302 // Split out the rw data from header info. For now put it in a huge array
303 // that more than exceeds the space needed. In future we'll just allocate
304 // this in the shared cache builder.
305 typedef struct header_info_rw {
306
307 bool getLoaded() const {
308 return isLoaded;
309 }
310
311 void setLoaded(bool v) {
312 isLoaded = v ? 1: 0;
313 }
314
315 bool getAllClassesRealized() const {
316 return allClassesRealized;
317 }
318
319 void setAllClassesRealized(bool v) {
320 allClassesRealized = v ? 1: 0;
321 }
322
323 header_info *getNext() const {
324 return (header_info *)(next << 2);
325 }
326
327 void setNext(header_info *v) {
328 next = ((uintptr_t)v) >> 2;
329 }
330
331 private:
332 #ifdef __LP64__
333 uintptr_t isLoaded : 1;
334 uintptr_t allClassesRealized : 1;
335 uintptr_t next : 62;
336 #else
337 uintptr_t isLoaded : 1;
338 uintptr_t allClassesRealized : 1;
339 uintptr_t next : 30;
340 #endif
341 } header_info_rw;
342
343 struct header_info_rw* getPreoptimizedHeaderRW(const struct header_info *const hdr);
344
345 typedef struct header_info {
346 private:
347 // Note, this is no longer a pointer, but instead an offset to a pointer
348 // from this location.
349 intptr_t mhdr_offset;
350
351 // Note, this is no longer a pointer, but instead an offset to a pointer
352 // from this location.
353 intptr_t info_offset;
354
355 // Offset from this location to the non-lazy class list
356 intptr_t nlclslist_offset;
357 uintptr_t nlclslist_count;
358
359 // Offset from this location to the non-lazy category list
360 intptr_t nlcatlist_offset;
361 uintptr_t nlcatlist_count;
362
363 // Offset from this location to the category list
364 intptr_t catlist_offset;
365 uintptr_t catlist_count;
366
367 // Offset from this location to the category list 2
368 intptr_t catlist2_offset;
369 uintptr_t catlist2_count;
370
371 // Do not add fields without editing ObjCModernAbstraction.hpp
372 public:
373
374 header_info_rw *getHeaderInfoRW() {
375 header_info_rw *preopt =
376 isPreoptimized() ? getPreoptimizedHeaderRW(this) : nil;
377 if (preopt) return preopt;
378 else return &rw_data[0];
379 }
380
381 const headerType *mhdr() const {
382 return (const headerType *)(((intptr_t)&mhdr_offset) + mhdr_offset);
383 }
384
385 void setmhdr(const headerType *mhdr) {
386 mhdr_offset = (intptr_t)mhdr - (intptr_t)&mhdr_offset;
387 }
388
389 const objc_image_info *info() const {
390 return (const objc_image_info *)(((intptr_t)&info_offset) + info_offset);
391 }
392
393 void setinfo(const objc_image_info *info) {
394 info_offset = (intptr_t)info - (intptr_t)&info_offset;
395 }
396
397 const classref_t *nlclslist(size_t *outCount) const;
398
399 void set_nlclslist(const void *list) {
400 nlclslist_offset = (intptr_t)list - (intptr_t)&nlclslist_offset;
401 }
402
403 category_t * const *nlcatlist(size_t *outCount) const;
404
405 void set_nlcatlist(const void *list) {
406 nlcatlist_offset = (intptr_t)list - (intptr_t)&nlcatlist_offset;
407 }
408
409 category_t * const *catlist(size_t *outCount) const;
410
411 void set_catlist(const void *list) {
412 catlist_offset = (intptr_t)list - (intptr_t)&catlist_offset;
413 }
414
415 category_t * const *catlist2(size_t *outCount) const;
416
417 void set_catlist2(const void *list) {
418 catlist2_offset = (intptr_t)list - (intptr_t)&catlist2_offset;
419 }
420
421 bool isLoaded() {
422 return getHeaderInfoRW()->getLoaded();
423 }
424
425 void setLoaded(bool v) {
426 getHeaderInfoRW()->setLoaded(v);
427 }
428
429 bool areAllClassesRealized() {
430 return getHeaderInfoRW()->getAllClassesRealized();
431 }
432
433 void setAllClassesRealized(bool v) {
434 getHeaderInfoRW()->setAllClassesRealized(v);
435 }
436
437 header_info *getNext() {
438 return getHeaderInfoRW()->getNext();
439 }
440
441 void setNext(header_info *v) {
442 getHeaderInfoRW()->setNext(v);
443 }
444
445 bool isBundle() {
446 return mhdr()->filetype == MH_BUNDLE;
447 }
448
449 const char *fname() const {
450 return dyld_image_path_containing_address(mhdr());
451 }
452
453 bool isPreoptimized() const;
454
455 bool hasPreoptimizedSelectors() const;
456
457 bool hasPreoptimizedClasses() const;
458
459 bool hasPreoptimizedProtocols() const;
460
461 bool hasPreoptimizedSectionLookups() const;
462
463 #if !__OBJC2__
464 struct old_protocol **proto_refs;
465 struct objc_module *mod_ptr;
466 size_t mod_count;
467 # if TARGET_OS_WIN32
468 struct objc_module **modules;
469 size_t moduleCount;
470 struct old_protocol **protocols;
471 size_t protocolCount;
472 void *imageinfo;
473 size_t imageinfoBytes;
474 SEL *selrefs;
475 size_t selrefCount;
476 struct objc_class **clsrefs;
477 size_t clsrefCount;
478 TCHAR *moduleName;
479 # endif
480 #endif
481
482 private:
483 // Images in the shared cache will have an empty array here while those
484 // allocated at run time will allocate a single entry.
485 header_info_rw rw_data[];
486 } header_info;
487
488 extern header_info *FirstHeader;
489 extern header_info *LastHeader;
490
491 extern void appendHeader(header_info *hi);
492 extern void removeHeader(header_info *hi);
493
494 extern objc_image_info *_getObjcImageInfo(const headerType *head, size_t *size);
495 extern bool _hasObjcContents(const header_info *hi);
496
497
498 // Mach-O segment and section names are 16 bytes and may be un-terminated.
499
500 static inline bool segnameEquals(const char *lhs, const char *rhs) {
501 return 0 == strncmp(lhs, rhs, 16);
502 }
503
504 static inline bool segnameStartsWith(const char *segname, const char *prefix) {
505 return 0 == strncmp(segname, prefix, strlen(prefix));
506 }
507
508 static inline bool sectnameEquals(const char *lhs, const char *rhs) {
509 return segnameEquals(lhs, rhs);
510 }
511
512 static inline bool sectnameStartsWith(const char *sectname, const char *prefix){
513 return segnameStartsWith(sectname, prefix);
514 }
515
516
517 #if __OBJC2__
518 extern bool didCallDyldNotifyRegister;
519 #endif
520
521
522 /* selectors */
523 extern void sel_init(size_t selrefCount);
524 extern SEL sel_registerNameNoLock(const char *str, bool copy);
525
526 extern SEL SEL_cxx_construct;
527 extern SEL SEL_cxx_destruct;
528
529 /* preoptimization */
530 extern void preopt_init(void);
531 extern void disableSharedCacheOptimizations(void);
532 extern bool isPreoptimized(void);
533 extern bool noMissingWeakSuperclasses(void);
534 extern header_info *preoptimizedHinfoForHeader(const headerType *mhdr);
535
536 extern Protocol *getPreoptimizedProtocol(const char *name);
537 extern Protocol *getSharedCachePreoptimizedProtocol(const char *name);
538
539 extern unsigned getPreoptimizedClassUnreasonableCount();
540 extern Class getPreoptimizedClass(const char *name);
541 extern Class* copyPreoptimizedClasses(const char *name, int *outCount);
542
543 extern Class _calloc_class(size_t size);
544
545 /* method lookup */
546 enum {
547 LOOKUP_INITIALIZE = 1,
548 LOOKUP_RESOLVER = 2,
549 LOOKUP_CACHE = 4,
550 LOOKUP_NIL = 8,
551 };
552 extern IMP lookUpImpOrForward(id obj, SEL, Class cls, int behavior);
553
554 static inline IMP
555 lookUpImpOrNil(id obj, SEL sel, Class cls, int behavior = 0)
556 {
557 return lookUpImpOrForward(obj, sel, cls, behavior | LOOKUP_CACHE | LOOKUP_NIL);
558 }
559
560 extern IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel);
561
562 struct IMPAndSEL {
563 IMP imp;
564 SEL sel;
565 };
566
567 extern IMPAndSEL _method_getImplementationAndName(Method m);
568
569 extern BOOL class_respondsToSelector_inst(id inst, SEL sel, Class cls);
570 extern Class class_initialize(Class cls, id inst);
571
572 extern bool objcMsgLogEnabled;
573 extern bool logMessageSend(bool isClassMethod,
574 const char *objectsClass,
575 const char *implementingClass,
576 SEL selector);
577
578 /* message dispatcher */
579
580 #if !OBJC_OLD_DISPATCH_PROTOTYPES
581 extern void _objc_msgForward_impcache(void);
582 #else
583 extern id _objc_msgForward_impcache(id, SEL, ...);
584 #endif
585
586 /* errors */
587 extern id(*badAllocHandler)(Class);
588 extern id _objc_callBadAllocHandler(Class cls) __attribute__((cold, noinline));
589 extern void __objc_error(id, const char *, ...) __attribute__((cold, format (printf, 2, 3), noreturn));
590 extern void _objc_inform(const char *fmt, ...) __attribute__((cold, format(printf, 1, 2)));
591 extern void _objc_inform_on_crash(const char *fmt, ...) __attribute__((cold, format (printf, 1, 2)));
592 extern void _objc_inform_now_and_on_crash(const char *fmt, ...) __attribute__((cold, format (printf, 1, 2)));
593 extern void _objc_inform_deprecated(const char *oldname, const char *newname) __attribute__((cold, noinline));
594 extern void inform_duplicate(const char *name, Class oldCls, Class cls);
595
596 /* magic */
597 extern Class _objc_getFreedObjectClass (void);
598
599 /* map table additions */
600 extern void *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value);
601 extern void *NXMapKeyFreeingRemove(NXMapTable *table, const void *key);
602
603 /* hash table additions */
604 extern unsigned _NXHashCapacity(NXHashTable *table);
605 extern void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity);
606
607 /* property attribute parsing */
608 extern const char *copyPropertyAttributeString(const objc_property_attribute_t *attrs, unsigned int count);
609 extern objc_property_attribute_t *copyPropertyAttributeList(const char *attrs, unsigned int *outCount);
610 extern char *copyPropertyAttributeValue(const char *attrs, const char *name);
611
612 /* locking */
613
614 class monitor_locker_t : nocopy_t {
615 monitor_t& lock;
616 public:
617 monitor_locker_t(monitor_t& newLock) : lock(newLock) { lock.enter(); }
618 ~monitor_locker_t() { lock.leave(); }
619 };
620
621 class recursive_mutex_locker_t : nocopy_t {
622 recursive_mutex_t& lock;
623 public:
624 recursive_mutex_locker_t(recursive_mutex_t& newLock)
625 : lock(newLock) { lock.lock(); }
626 ~recursive_mutex_locker_t() { lock.unlock(); }
627 };
628
629
630 /* Exceptions */
631 struct alt_handler_list;
632 extern void exception_init(void);
633 extern void _destroyAltHandlerList(struct alt_handler_list *list);
634
635 /* Class change notifications (gdb only for now) */
636 #define OBJC_CLASS_ADDED (1<<0)
637 #define OBJC_CLASS_REMOVED (1<<1)
638 #define OBJC_CLASS_IVARS_CHANGED (1<<2)
639 #define OBJC_CLASS_METHODS_CHANGED (1<<3)
640 extern void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)
641 __attribute__((noinline));
642
643
644 // Settings from environment variables
645 #define OPTION(var, env, help) extern bool var;
646 #include "objc-env.h"
647 #undef OPTION
648
649 extern void environ_init(void);
650 extern void runtime_init(void);
651
652 extern void logReplacedMethod(const char *className, SEL s, bool isMeta, const char *catName, IMP oldImp, IMP newImp);
653
654
655 // objc per-thread storage
656 typedef struct {
657 struct _objc_initializing_classes *initializingClasses; // for +initialize
658 struct SyncCache *syncCache; // for @synchronize
659 struct alt_handler_list *handlerList; // for exception alt handlers
660 char *printableNames[4]; // temporary demangled names for logging
661 const char **classNameLookups; // for objc_getClass() hooks
662 unsigned classNameLookupsAllocated;
663 unsigned classNameLookupsUsed;
664
665 // If you add new fields here, don't forget to update
666 // _objc_pthread_destroyspecific()
667
668 } _objc_pthread_data;
669
670 extern _objc_pthread_data *_objc_fetch_pthread_data(bool create);
671 extern void tls_init(void);
672
673 // encoding.h
674 extern unsigned int encoding_getNumberOfArguments(const char *typedesc);
675 extern unsigned int encoding_getSizeOfArguments(const char *typedesc);
676 extern unsigned int encoding_getArgumentInfo(const char *typedesc, unsigned int arg, const char **type, int *offset);
677 extern void encoding_getReturnType(const char *t, char *dst, size_t dst_len);
678 extern char * encoding_copyReturnType(const char *t);
679 extern void encoding_getArgumentType(const char *t, unsigned int index, char *dst, size_t dst_len);
680 extern char *encoding_copyArgumentType(const char *t, unsigned int index);
681
682 // sync.h
683 extern void _destroySyncCache(struct SyncCache *cache);
684
685 // arr
686 extern void arr_init(void);
687 extern id objc_autoreleaseReturnValue(id obj);
688
689 // block trampolines
690 extern void _imp_implementationWithBlock_init(void);
691 extern IMP _imp_implementationWithBlockNoCopy(id block);
692
693 // layout.h
694 typedef struct {
695 uint8_t *bits;
696 size_t bitCount;
697 size_t bitsAllocated;
698 bool weak;
699 } layout_bitmap;
700 extern layout_bitmap layout_bitmap_create(const unsigned char *layout_string, size_t layoutStringInstanceSize, size_t instanceSize, bool weak);
701 extern layout_bitmap layout_bitmap_create_empty(size_t instanceSize, bool weak);
702 extern void layout_bitmap_free(layout_bitmap bits);
703 extern const unsigned char *layout_string_create(layout_bitmap bits);
704 extern void layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset);
705 extern void layout_bitmap_grow(layout_bitmap *bits, size_t newCount);
706 extern void layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos);
707 extern void layout_bitmap_slide_anywhere(layout_bitmap *bits, size_t oldPos, size_t newPos);
708 extern bool layout_bitmap_splat(layout_bitmap dst, layout_bitmap src,
709 size_t oldSrcInstanceSize);
710 extern bool layout_bitmap_or(layout_bitmap dst, layout_bitmap src, const char *msg);
711 extern bool layout_bitmap_clear(layout_bitmap dst, layout_bitmap src, const char *msg);
712 extern void layout_bitmap_print(layout_bitmap bits);
713
714
715 // fixme runtime
716 extern bool MultithreadedForkChild;
717 extern id objc_noop_imp(id self, SEL _cmd);
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
729 extern const header_info *_headerForClass(Class cls);
730
731 extern Class _class_remap(Class cls);
732 extern Ivar _class_getVariable(Class cls, const char *name);
733
734 extern unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, id *results, unsigned num_requested);
735
736 extern const char *_category_getName(Category cat);
737 extern const char *_category_getClassName(Category cat);
738 extern Class _category_getClass(Category cat);
739 extern IMP _category_getLoadMethod(Category cat);
740
741 enum {
742 OBJECT_CONSTRUCT_NONE = 0,
743 OBJECT_CONSTRUCT_FREE_ONFAILURE = 1,
744 OBJECT_CONSTRUCT_CALL_BADALLOC = 2,
745 };
746 extern id object_cxxConstructFromClass(id obj, Class cls, int flags);
747 extern void object_cxxDestruct(id obj);
748
749 extern void fixupCopiedIvars(id newObject, id oldObject);
750 extern Class _class_getClassForIvar(Class cls, Ivar ivar);
751
752
753 #define OBJC_WARN_DEPRECATED \
754 do { \
755 static int warned = 0; \
756 if (!warned) { \
757 warned = 1; \
758 _objc_inform_deprecated(__FUNCTION__, NULL); \
759 } \
760 } while (0) \
761
762 __END_DECLS
763
764
765 #ifndef STATIC_ASSERT
766 # define STATIC_ASSERT(x) _STATIC_ASSERT2(x, __LINE__)
767 # define _STATIC_ASSERT2(x, line) _STATIC_ASSERT3(x, line)
768 # define _STATIC_ASSERT3(x, line) \
769 typedef struct { \
770 int _static_assert[(x) ? 0 : -1]; \
771 } _static_assert_ ## line __attribute__((unavailable))
772 #endif
773
774 #define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
775
776
777 static __inline uint32_t _objc_strhash(const char *s) {
778 uint32_t hash = 0;
779 for (;;) {
780 int a = *s++;
781 if (0 == a) break;
782 hash += (hash << 8) + a;
783 }
784 return hash;
785 }
786
787 #if __cplusplus
788
789 template <typename T>
790 static inline T log2u(T x) {
791 return (x<2) ? 0 : log2u(x>>1)+1;
792 }
793
794 template <typename T>
795 static inline T exp2u(T x) {
796 return (1 << x);
797 }
798
799 template <typename T>
800 static T exp2m1u(T x) {
801 return (1 << x) - 1;
802 }
803
804 #endif
805
806 // Misalignment-safe integer types
807 __attribute__((aligned(1))) typedef uintptr_t unaligned_uintptr_t;
808 __attribute__((aligned(1))) typedef intptr_t unaligned_intptr_t;
809 __attribute__((aligned(1))) typedef uint64_t unaligned_uint64_t;
810 __attribute__((aligned(1))) typedef int64_t unaligned_int64_t;
811 __attribute__((aligned(1))) typedef uint32_t unaligned_uint32_t;
812 __attribute__((aligned(1))) typedef int32_t unaligned_int32_t;
813 __attribute__((aligned(1))) typedef uint16_t unaligned_uint16_t;
814 __attribute__((aligned(1))) typedef int16_t unaligned_int16_t;
815
816
817 // Global operator new and delete. We must not use any app overrides.
818 // This ALSO REQUIRES each of these be in libobjc's unexported symbol list.
819 #if __cplusplus
820 #pragma clang diagnostic push
821 #pragma clang diagnostic ignored "-Winline-new-delete"
822 #include <new>
823 inline void* operator new(std::size_t size) throw (std::bad_alloc) { return malloc(size); }
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, const std::nothrow_t&) throw() { return malloc(size); }
826 inline void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }
827 inline void operator delete(void* p) throw() { free(p); }
828 inline void operator delete[](void* p) throw() { free(p); }
829 inline void operator delete(void* p, const std::nothrow_t&) throw() { free(p); }
830 inline void operator delete[](void* p, const std::nothrow_t&) throw() { free(p); }
831 #pragma clang diagnostic pop
832 #endif
833
834
835 class TimeLogger {
836 uint64_t mStart;
837 bool mRecord;
838 public:
839 TimeLogger(bool record = true)
840 : mStart(nanoseconds())
841 , mRecord(record)
842 { }
843
844 void log(const char *msg) {
845 if (mRecord) {
846 uint64_t end = nanoseconds();
847 _objc_inform("%.2f ms: %s", (end - mStart) / 1000000.0, msg);
848 mStart = nanoseconds();
849 }
850 }
851 };
852
853 enum { CacheLineSize = 64 };
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 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
862 enum { StripeCount = 8 };
863 #else
864 enum { StripeCount = 64 };
865 #endif
866
867 struct PaddedT {
868 T value alignas(CacheLineSize);
869 };
870
871 PaddedT array[StripeCount];
872
873 static unsigned int indexForPointer(const void *p) {
874 uintptr_t addr = reinterpret_cast<uintptr_t>(p);
875 return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
876 }
877
878 public:
879 T& operator[] (const void *p) {
880 return array[indexForPointer(p)].value;
881 }
882 const T& operator[] (const void *p) const {
883 return const_cast<StripedMap<T>>(this)[p];
884 }
885
886 // Shortcuts for StripedMaps of locks.
887 void lockAll() {
888 for (unsigned int i = 0; i < StripeCount; i++) {
889 array[i].value.lock();
890 }
891 }
892
893 void unlockAll() {
894 for (unsigned int i = 0; i < StripeCount; i++) {
895 array[i].value.unlock();
896 }
897 }
898
899 void forceResetAll() {
900 for (unsigned int i = 0; i < StripeCount; i++) {
901 array[i].value.forceReset();
902 }
903 }
904
905 void defineLockOrder() {
906 for (unsigned int i = 1; i < StripeCount; i++) {
907 lockdebug_lock_precedes_lock(&array[i-1].value, &array[i].value);
908 }
909 }
910
911 void precedeLock(const void *newlock) {
912 // assumes defineLockOrder is also called
913 lockdebug_lock_precedes_lock(&array[StripeCount-1].value, newlock);
914 }
915
916 void succeedLock(const void *oldlock) {
917 // assumes defineLockOrder is also called
918 lockdebug_lock_precedes_lock(oldlock, &array[0].value);
919 }
920
921 const void *getLock(int i) {
922 if (i < StripeCount) return &array[i].value;
923 else return nil;
924 }
925
926 #if DEBUG
927 StripedMap() {
928 // Verify alignment expectations.
929 uintptr_t base = (uintptr_t)&array[0].value;
930 uintptr_t delta = (uintptr_t)&array[1].value - base;
931 ASSERT(delta % CacheLineSize == 0);
932 ASSERT(base % CacheLineSize == 0);
933 }
934 #else
935 constexpr StripedMap() {}
936 #endif
937 };
938
939
940 // DisguisedPtr<T> acts like pointer type T*, except the
941 // stored value is disguised to hide it from tools like `leaks`.
942 // nil is disguised as itself so zero-filled memory works as expected,
943 // which means 0x80..00 is also disguised as itself but we don't care.
944 // Note that weak_entry_t knows about this encoding.
945 template <typename T>
946 class DisguisedPtr {
947 uintptr_t value;
948
949 static uintptr_t disguise(T* ptr) {
950 return -(uintptr_t)ptr;
951 }
952
953 static T* undisguise(uintptr_t val) {
954 return (T*)-val;
955 }
956
957 public:
958 DisguisedPtr() { }
959 DisguisedPtr(T* ptr)
960 : value(disguise(ptr)) { }
961 DisguisedPtr(const DisguisedPtr<T>& ptr)
962 : value(ptr.value) { }
963
964 DisguisedPtr<T>& operator = (T* rhs) {
965 value = disguise(rhs);
966 return *this;
967 }
968 DisguisedPtr<T>& operator = (const DisguisedPtr<T>& rhs) {
969 value = rhs.value;
970 return *this;
971 }
972
973 operator T* () const {
974 return undisguise(value);
975 }
976 T* operator -> () const {
977 return undisguise(value);
978 }
979 T& operator * () const {
980 return *undisguise(value);
981 }
982 T& operator [] (size_t i) const {
983 return undisguise(value)[i];
984 }
985
986 // pointer arithmetic operators omitted
987 // because we don't currently use them anywhere
988 };
989
990 // fixme type id is weird and not identical to objc_object*
991 static inline bool operator == (DisguisedPtr<objc_object> lhs, id rhs) {
992 return lhs == (objc_object *)rhs;
993 }
994 static inline bool operator != (DisguisedPtr<objc_object> lhs, id rhs) {
995 return lhs != (objc_object *)rhs;
996 }
997
998
999 // Storage for a thread-safe chained hook function.
1000 // get() returns the value for calling.
1001 // set() installs a new function and returns the old one for chaining.
1002 // More precisely, set() writes the old value to a variable supplied by
1003 // the caller. get() and set() use appropriate barriers so that the
1004 // old value is safely written to the variable before the new value is
1005 // called to use it.
1006 //
1007 // T1: store to old variable; store-release to hook variable
1008 // T2: load-acquire from hook variable; call it; called hook loads old variable
1009
1010 template <typename Fn>
1011 class ChainedHookFunction {
1012 std::atomic<Fn> hook{nil};
1013
1014 public:
1015 constexpr ChainedHookFunction(Fn f) : hook{f} { };
1016
1017 Fn get() {
1018 return hook.load(std::memory_order_acquire);
1019 }
1020
1021 void set(Fn newValue, Fn *oldVariable)
1022 {
1023 Fn oldValue = hook.load(std::memory_order_relaxed);
1024 do {
1025 *oldVariable = oldValue;
1026 } while (!hook.compare_exchange_weak(oldValue, newValue,
1027 std::memory_order_release,
1028 std::memory_order_relaxed));
1029 }
1030 };
1031
1032
1033 // A small vector for use as a global variable. Only supports appending and
1034 // iteration. Stores up to N elements inline, and multiple elements in a heap
1035 // allocation. There is no attempt to amortize reallocation cost; this is
1036 // intended to be used in situation where a small number of elements is
1037 // common, more might happen, and significantly more is very rare.
1038 //
1039 // This does not clean up its allocation, and thus cannot be used as a local
1040 // variable or member of something with limited lifetime.
1041
1042 template <typename T, unsigned InlineCount>
1043 class GlobalSmallVector {
1044 static_assert(std::is_pod<T>::value, "SmallVector requires POD types");
1045
1046 protected:
1047 unsigned count{0};
1048 union {
1049 T inlineElements[InlineCount];
1050 T *elements{nullptr};
1051 };
1052
1053 public:
1054 void append(const T &val) {
1055 if (count < InlineCount) {
1056 // We have space. Store the new value inline.
1057 inlineElements[count] = val;
1058 } else if (count == InlineCount) {
1059 // Inline storage is full. Switch to a heap allocation.
1060 T *newElements = (T *)malloc((count + 1) * sizeof(T));
1061 memcpy(newElements, inlineElements, count * sizeof(T));
1062 newElements[count] = val;
1063 elements = newElements;
1064 } else {
1065 // Resize the heap allocation and append.
1066 elements = (T *)realloc(elements, (count + 1) * sizeof(T));
1067 elements[count] = val;
1068 }
1069 count++;
1070 }
1071
1072 const T *begin() const {
1073 return count <= InlineCount ? inlineElements : elements;
1074 }
1075
1076 const T *end() const {
1077 return begin() + count;
1078 }
1079 };
1080
1081 // A small vector that cleans up its internal memory allocation when destroyed.
1082 template <typename T, unsigned InlineCount>
1083 class SmallVector: public GlobalSmallVector<T, InlineCount> {
1084 public:
1085 ~SmallVector() {
1086 if (this->count > InlineCount)
1087 free(this->elements);
1088 }
1089
1090 template <unsigned OtherCount>
1091 void initFrom(const GlobalSmallVector<T, OtherCount> &other) {
1092 ASSERT(this->count == 0);
1093 this->count = (unsigned)(other.end() - other.begin());
1094 if (this->count > InlineCount) {
1095 this->elements = (T *)memdup(other.begin(), this->count * sizeof(T));
1096 } else {
1097 memcpy(this->inlineElements, other.begin(), this->count * sizeof(T));
1098 }
1099 }
1100 };
1101
1102 // Pointer hash function.
1103 // This is not a terrific hash, but it is fast
1104 // and not outrageously flawed for our purposes.
1105
1106 // Based on principles from http://locklessinc.com/articles/fast_hash/
1107 // and evaluation ideas from http://floodyberry.com/noncryptohashzoo/
1108 #if __LP64__
1109 static inline uint32_t ptr_hash(uint64_t key)
1110 {
1111 key ^= key >> 4;
1112 key *= 0x8a970be7488fda55;
1113 key ^= __builtin_bswap64(key);
1114 return (uint32_t)key;
1115 }
1116 #else
1117 static inline uint32_t ptr_hash(uint32_t key)
1118 {
1119 key ^= key >> 4;
1120 key *= 0x5052acdb;
1121 key ^= __builtin_bswap32(key);
1122 return key;
1123 }
1124 #endif
1125
1126 /*
1127 Higher-quality hash function. This is measurably slower in some workloads.
1128 #if __LP64__
1129 uint32_t ptr_hash(uint64_t key)
1130 {
1131 key -= __builtin_bswap64(key);
1132 key *= 0x8a970be7488fda55;
1133 key ^= __builtin_bswap64(key);
1134 key *= 0x8a970be7488fda55;
1135 key ^= __builtin_bswap64(key);
1136 return (uint32_t)key;
1137 }
1138 #else
1139 static uint32_t ptr_hash(uint32_t key)
1140 {
1141 key -= __builtin_bswap32(key);
1142 key *= 0x5052acdb;
1143 key ^= __builtin_bswap32(key);
1144 key *= 0x5052acdb;
1145 key ^= __builtin_bswap32(key);
1146 return key;
1147 }
1148 #endif
1149 */
1150
1151
1152
1153 // Lock declarations
1154 #include "objc-locks.h"
1155
1156 // Inlined parts of objc_object's implementation
1157 #include "objc-object.h"
1158
1159 #endif /* _OBJC_PRIVATE_H_ */
1160