]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-private.h
objc4-750.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 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
466 extern bool objcMsgLogEnabled;
467 extern bool logMessageSend(bool isClassMethod,
468 const char *objectsClass,
469 const char *implementingClass,
470 SEL selector);
471
472 /* message dispatcher */
473 extern IMP _class_lookupMethodAndLoadCache3(id, SEL, Class);
474
475 #if !OBJC_OLD_DISPATCH_PROTOTYPES
476 extern void _objc_msgForward_impcache(void);
477 #else
478 extern id _objc_msgForward_impcache(id, SEL, ...);
479 #endif
480
481 /* errors */
482 extern void __objc_error(id, const char *, ...) __attribute__((format (printf, 2, 3), noreturn));
483 extern void _objc_inform(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
484 extern void _objc_inform_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
485 extern void _objc_inform_now_and_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
486 extern void _objc_inform_deprecated(const char *oldname, const char *newname) __attribute__((noinline));
487 extern void inform_duplicate(const char *name, Class oldCls, Class cls);
488
489 /* magic */
490 extern Class _objc_getFreedObjectClass (void);
491
492 /* map table additions */
493 extern void *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value);
494 extern void *NXMapKeyFreeingRemove(NXMapTable *table, const void *key);
495
496 /* hash table additions */
497 extern unsigned _NXHashCapacity(NXHashTable *table);
498 extern void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity);
499
500 /* property attribute parsing */
501 extern const char *copyPropertyAttributeString(const objc_property_attribute_t *attrs, unsigned int count);
502 extern objc_property_attribute_t *copyPropertyAttributeList(const char *attrs, unsigned int *outCount);
503 extern char *copyPropertyAttributeValue(const char *attrs, const char *name);
504
505 /* locking */
506 extern void lock_init(void);
507
508 class monitor_locker_t : nocopy_t {
509 monitor_t& lock;
510 public:
511 monitor_locker_t(monitor_t& newLock) : lock(newLock) { lock.enter(); }
512 ~monitor_locker_t() { lock.leave(); }
513 };
514
515 class recursive_mutex_locker_t : nocopy_t {
516 recursive_mutex_t& lock;
517 public:
518 recursive_mutex_locker_t(recursive_mutex_t& newLock)
519 : lock(newLock) { lock.lock(); }
520 ~recursive_mutex_locker_t() { lock.unlock(); }
521 };
522
523
524 /* Exceptions */
525 struct alt_handler_list;
526 extern void exception_init(void);
527 extern void _destroyAltHandlerList(struct alt_handler_list *list);
528
529 /* Class change notifications (gdb only for now) */
530 #define OBJC_CLASS_ADDED (1<<0)
531 #define OBJC_CLASS_REMOVED (1<<1)
532 #define OBJC_CLASS_IVARS_CHANGED (1<<2)
533 #define OBJC_CLASS_METHODS_CHANGED (1<<3)
534 extern void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)
535 __attribute__((noinline));
536
537
538 // Settings from environment variables
539 #define OPTION(var, env, help) extern bool var;
540 #include "objc-env.h"
541 #undef OPTION
542
543 extern void environ_init(void);
544
545 extern void logReplacedMethod(const char *className, SEL s, bool isMeta, const char *catName, IMP oldImp, IMP newImp);
546
547
548 // objc per-thread storage
549 typedef struct {
550 struct _objc_initializing_classes *initializingClasses; // for +initialize
551 struct SyncCache *syncCache; // for @synchronize
552 struct alt_handler_list *handlerList; // for exception alt handlers
553 char *printableNames[4]; // temporary demangled names for logging
554
555 // If you add new fields here, don't forget to update
556 // _objc_pthread_destroyspecific()
557
558 } _objc_pthread_data;
559
560 extern _objc_pthread_data *_objc_fetch_pthread_data(bool create);
561 extern void tls_init(void);
562
563 // encoding.h
564 extern unsigned int encoding_getNumberOfArguments(const char *typedesc);
565 extern unsigned int encoding_getSizeOfArguments(const char *typedesc);
566 extern unsigned int encoding_getArgumentInfo(const char *typedesc, unsigned int arg, const char **type, int *offset);
567 extern void encoding_getReturnType(const char *t, char *dst, size_t dst_len);
568 extern char * encoding_copyReturnType(const char *t);
569 extern void encoding_getArgumentType(const char *t, unsigned int index, char *dst, size_t dst_len);
570 extern char *encoding_copyArgumentType(const char *t, unsigned int index);
571
572 // sync.h
573 extern void _destroySyncCache(struct SyncCache *cache);
574
575 // arr
576 extern void arr_init(void);
577 extern id objc_autoreleaseReturnValue(id obj);
578
579 // block trampolines
580 extern IMP _imp_implementationWithBlockNoCopy(id block);
581
582 // layout.h
583 typedef struct {
584 uint8_t *bits;
585 size_t bitCount;
586 size_t bitsAllocated;
587 bool weak;
588 } layout_bitmap;
589 extern layout_bitmap layout_bitmap_create(const unsigned char *layout_string, size_t layoutStringInstanceSize, size_t instanceSize, bool weak);
590 extern layout_bitmap layout_bitmap_create_empty(size_t instanceSize, bool weak);
591 extern void layout_bitmap_free(layout_bitmap bits);
592 extern const unsigned char *layout_string_create(layout_bitmap bits);
593 extern void layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset);
594 extern void layout_bitmap_grow(layout_bitmap *bits, size_t newCount);
595 extern void layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos);
596 extern void layout_bitmap_slide_anywhere(layout_bitmap *bits, size_t oldPos, size_t newPos);
597 extern bool layout_bitmap_splat(layout_bitmap dst, layout_bitmap src,
598 size_t oldSrcInstanceSize);
599 extern bool layout_bitmap_or(layout_bitmap dst, layout_bitmap src, const char *msg);
600 extern bool layout_bitmap_clear(layout_bitmap dst, layout_bitmap src, const char *msg);
601 extern void layout_bitmap_print(layout_bitmap bits);
602
603
604 // fixme runtime
605 extern bool MultithreadedForkChild;
606 extern id objc_noop_imp(id self, SEL _cmd);
607 extern Class look_up_class(const char *aClassName, bool includeUnconnected, bool includeClassHandler);
608 extern "C" void map_images(unsigned count, const char * const paths[],
609 const struct mach_header * const mhdrs[]);
610 extern void map_images_nolock(unsigned count, const char * const paths[],
611 const struct mach_header * const mhdrs[]);
612 extern void load_images(const char *path, const struct mach_header *mh);
613 extern void unmap_image(const char *path, const struct mach_header *mh);
614 extern void unmap_image_nolock(const struct mach_header *mh);
615 extern void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClass);
616 extern void _unload_image(header_info *hi);
617
618 extern const header_info *_headerForClass(Class cls);
619
620 extern Class _class_remap(Class cls);
621 extern Class _class_getNonMetaClass(Class cls, id obj);
622 extern Ivar _class_getVariable(Class cls, const char *name);
623
624 extern unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, id *results, unsigned num_requested);
625 extern id _objc_constructOrFree(id bytes, Class cls);
626
627 extern const char *_category_getName(Category cat);
628 extern const char *_category_getClassName(Category cat);
629 extern Class _category_getClass(Category cat);
630 extern IMP _category_getLoadMethod(Category cat);
631
632 extern id object_cxxConstructFromClass(id obj, Class cls);
633 extern void object_cxxDestruct(id obj);
634
635 extern void _class_resolveMethod(Class cls, SEL sel, id inst);
636
637 extern void fixupCopiedIvars(id newObject, id oldObject);
638 extern Class _class_getClassForIvar(Class cls, Ivar ivar);
639
640
641 #define OBJC_WARN_DEPRECATED \
642 do { \
643 static int warned = 0; \
644 if (!warned) { \
645 warned = 1; \
646 _objc_inform_deprecated(__FUNCTION__, NULL); \
647 } \
648 } while (0) \
649
650 __END_DECLS
651
652
653 #ifndef STATIC_ASSERT
654 # define STATIC_ASSERT(x) _STATIC_ASSERT2(x, __LINE__)
655 # define _STATIC_ASSERT2(x, line) _STATIC_ASSERT3(x, line)
656 # define _STATIC_ASSERT3(x, line) \
657 typedef struct { \
658 int _static_assert[(x) ? 0 : -1]; \
659 } _static_assert_ ## line __attribute__((unavailable))
660 #endif
661
662 #define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
663
664
665 static __inline uint32_t _objc_strhash(const char *s) {
666 uint32_t hash = 0;
667 for (;;) {
668 int a = *s++;
669 if (0 == a) break;
670 hash += (hash << 8) + a;
671 }
672 return hash;
673 }
674
675 #if __cplusplus
676
677 template <typename T>
678 static inline T log2u(T x) {
679 return (x<2) ? 0 : log2u(x>>1)+1;
680 }
681
682 template <typename T>
683 static inline T exp2u(T x) {
684 return (1 << x);
685 }
686
687 template <typename T>
688 static T exp2m1u(T x) {
689 return (1 << x) - 1;
690 }
691
692 #endif
693
694 // Misalignment-safe integer types
695 __attribute__((aligned(1))) typedef uintptr_t unaligned_uintptr_t;
696 __attribute__((aligned(1))) typedef intptr_t unaligned_intptr_t;
697 __attribute__((aligned(1))) typedef uint64_t unaligned_uint64_t;
698 __attribute__((aligned(1))) typedef int64_t unaligned_int64_t;
699 __attribute__((aligned(1))) typedef uint32_t unaligned_uint32_t;
700 __attribute__((aligned(1))) typedef int32_t unaligned_int32_t;
701 __attribute__((aligned(1))) typedef uint16_t unaligned_uint16_t;
702 __attribute__((aligned(1))) typedef int16_t unaligned_int16_t;
703
704
705 // Global operator new and delete. We must not use any app overrides.
706 // This ALSO REQUIRES each of these be in libobjc's unexported symbol list.
707 #if __cplusplus
708 #pragma clang diagnostic push
709 #pragma clang diagnostic ignored "-Winline-new-delete"
710 #include <new>
711 inline void* operator new(std::size_t size) throw (std::bad_alloc) { return malloc(size); }
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, const std::nothrow_t&) throw() { return malloc(size); }
714 inline void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }
715 inline void operator delete(void* p) throw() { free(p); }
716 inline void operator delete[](void* p) throw() { free(p); }
717 inline void operator delete(void* p, const std::nothrow_t&) throw() { free(p); }
718 inline void operator delete[](void* p, const std::nothrow_t&) throw() { free(p); }
719 #pragma clang diagnostic pop
720 #endif
721
722
723 class TimeLogger {
724 uint64_t mStart;
725 bool mRecord;
726 public:
727 TimeLogger(bool record = true)
728 : mStart(nanoseconds())
729 , mRecord(record)
730 { }
731
732 void log(const char *msg) {
733 if (mRecord) {
734 uint64_t end = nanoseconds();
735 _objc_inform("%.2f ms: %s", (end - mStart) / 1000000.0, msg);
736 mStart = nanoseconds();
737 }
738 }
739 };
740
741 enum { CacheLineSize = 64 };
742
743 // StripedMap<T> is a map of void* -> T, sized appropriately
744 // for cache-friendly lock striping.
745 // For example, this may be used as StripedMap<spinlock_t>
746 // or as StripedMap<SomeStruct> where SomeStruct stores a spin lock.
747 template<typename T>
748 class StripedMap {
749 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
750 enum { StripeCount = 8 };
751 #else
752 enum { StripeCount = 64 };
753 #endif
754
755 struct PaddedT {
756 T value alignas(CacheLineSize);
757 };
758
759 PaddedT array[StripeCount];
760
761 static unsigned int indexForPointer(const void *p) {
762 uintptr_t addr = reinterpret_cast<uintptr_t>(p);
763 return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
764 }
765
766 public:
767 T& operator[] (const void *p) {
768 return array[indexForPointer(p)].value;
769 }
770 const T& operator[] (const void *p) const {
771 return const_cast<StripedMap<T>>(this)[p];
772 }
773
774 // Shortcuts for StripedMaps of locks.
775 void lockAll() {
776 for (unsigned int i = 0; i < StripeCount; i++) {
777 array[i].value.lock();
778 }
779 }
780
781 void unlockAll() {
782 for (unsigned int i = 0; i < StripeCount; i++) {
783 array[i].value.unlock();
784 }
785 }
786
787 void forceResetAll() {
788 for (unsigned int i = 0; i < StripeCount; i++) {
789 array[i].value.forceReset();
790 }
791 }
792
793 void defineLockOrder() {
794 for (unsigned int i = 1; i < StripeCount; i++) {
795 lockdebug_lock_precedes_lock(&array[i-1].value, &array[i].value);
796 }
797 }
798
799 void precedeLock(const void *newlock) {
800 // assumes defineLockOrder is also called
801 lockdebug_lock_precedes_lock(&array[StripeCount-1].value, newlock);
802 }
803
804 void succeedLock(const void *oldlock) {
805 // assumes defineLockOrder is also called
806 lockdebug_lock_precedes_lock(oldlock, &array[0].value);
807 }
808
809 const void *getLock(int i) {
810 if (i < StripeCount) return &array[i].value;
811 else return nil;
812 }
813
814 #if DEBUG
815 StripedMap() {
816 // Verify alignment expectations.
817 uintptr_t base = (uintptr_t)&array[0].value;
818 uintptr_t delta = (uintptr_t)&array[1].value - base;
819 assert(delta % CacheLineSize == 0);
820 assert(base % CacheLineSize == 0);
821 }
822 #else
823 constexpr StripedMap() {}
824 #endif
825 };
826
827
828 // DisguisedPtr<T> acts like pointer type T*, except the
829 // stored value is disguised to hide it from tools like `leaks`.
830 // nil is disguised as itself so zero-filled memory works as expected,
831 // which means 0x80..00 is also disguised as itself but we don't care.
832 // Note that weak_entry_t knows about this encoding.
833 template <typename T>
834 class DisguisedPtr {
835 uintptr_t value;
836
837 static uintptr_t disguise(T* ptr) {
838 return -(uintptr_t)ptr;
839 }
840
841 static T* undisguise(uintptr_t val) {
842 return (T*)-val;
843 }
844
845 public:
846 DisguisedPtr() { }
847 DisguisedPtr(T* ptr)
848 : value(disguise(ptr)) { }
849 DisguisedPtr(const DisguisedPtr<T>& ptr)
850 : value(ptr.value) { }
851
852 DisguisedPtr<T>& operator = (T* rhs) {
853 value = disguise(rhs);
854 return *this;
855 }
856 DisguisedPtr<T>& operator = (const DisguisedPtr<T>& rhs) {
857 value = rhs.value;
858 return *this;
859 }
860
861 operator T* () const {
862 return undisguise(value);
863 }
864 T* operator -> () const {
865 return undisguise(value);
866 }
867 T& operator * () const {
868 return *undisguise(value);
869 }
870 T& operator [] (size_t i) const {
871 return undisguise(value)[i];
872 }
873
874 // pointer arithmetic operators omitted
875 // because we don't currently use them anywhere
876 };
877
878 // fixme type id is weird and not identical to objc_object*
879 static inline bool operator == (DisguisedPtr<objc_object> lhs, id rhs) {
880 return lhs == (objc_object *)rhs;
881 }
882 static inline bool operator != (DisguisedPtr<objc_object> lhs, id rhs) {
883 return lhs != (objc_object *)rhs;
884 }
885
886
887 // Storage for a thread-safe chained hook function.
888 // get() returns the value for calling.
889 // set() installs a new function and returns the old one for chaining.
890 // More precisely, set() writes the old value to a variable supplied by
891 // the caller. get() and set() use appropriate barriers so that the
892 // old value is safely written to the variable before the new value is
893 // called to use it.
894 //
895 // T1: store to old variable; store-release to hook variable
896 // T2: load-acquire from hook variable; call it; called hook loads old variable
897
898 template <typename Fn>
899 class ChainedHookFunction {
900 std::atomic<Fn> hook{nil};
901
902 public:
903 ChainedHookFunction(Fn f) : hook{f} { };
904
905 Fn get() {
906 return hook.load(std::memory_order_acquire);
907 }
908
909 void set(Fn newValue, Fn *oldVariable)
910 {
911 Fn oldValue = hook.load(std::memory_order_relaxed);
912 do {
913 *oldVariable = oldValue;
914 } while (!hook.compare_exchange_weak(oldValue, newValue,
915 std::memory_order_release,
916 std::memory_order_relaxed));
917 }
918 };
919
920
921 // Pointer hash function.
922 // This is not a terrific hash, but it is fast
923 // and not outrageously flawed for our purposes.
924
925 // Based on principles from http://locklessinc.com/articles/fast_hash/
926 // and evaluation ideas from http://floodyberry.com/noncryptohashzoo/
927 #if __LP64__
928 static inline uint32_t ptr_hash(uint64_t key)
929 {
930 key ^= key >> 4;
931 key *= 0x8a970be7488fda55;
932 key ^= __builtin_bswap64(key);
933 return (uint32_t)key;
934 }
935 #else
936 static inline uint32_t ptr_hash(uint32_t key)
937 {
938 key ^= key >> 4;
939 key *= 0x5052acdb;
940 key ^= __builtin_bswap32(key);
941 return key;
942 }
943 #endif
944
945 /*
946 Higher-quality hash function. This is measurably slower in some workloads.
947 #if __LP64__
948 uint32_t ptr_hash(uint64_t key)
949 {
950 key -= __builtin_bswap64(key);
951 key *= 0x8a970be7488fda55;
952 key ^= __builtin_bswap64(key);
953 key *= 0x8a970be7488fda55;
954 key ^= __builtin_bswap64(key);
955 return (uint32_t)key;
956 }
957 #else
958 static uint32_t ptr_hash(uint32_t key)
959 {
960 key -= __builtin_bswap32(key);
961 key *= 0x5052acdb;
962 key ^= __builtin_bswap32(key);
963 key *= 0x5052acdb;
964 key ^= __builtin_bswap32(key);
965 return key;
966 }
967 #endif
968 */
969
970
971
972 // Lock declarations
973 #include "objc-locks.h"
974
975 // Inlined parts of objc_object's implementation
976 #include "objc-object.h"
977
978 #endif /* _OBJC_PRIVATE_H_ */
979