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