2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Copyright 1988-1996, NeXT Software, Inc.
28 #ifndef _OBJC_PRIVATE_H_
29 #define _OBJC_PRIVATE_H_
31 #include "objc-config.h"
33 /* Isolate ourselves from the definitions of id and Class in the compiler
38 #error include objc-private.h before other headers
41 #define OBJC_TYPES_DEFINED 1
42 #undef OBJC_OLD_DISPATCH_PROTOTYPES
43 #define OBJC_OLD_DISPATCH_PROTOTYPES 0
45 #include <cstddef> // for nullptr_t
52 typedef struct objc_class
*Class
;
53 typedef struct objc_object
*id
;
63 isa_t(uintptr_t value
) : bits(value
) { }
67 #if defined(ISA_BITFIELD)
69 ISA_BITFIELD
; // defined in isa.h
81 // ISA() assumes this is NOT a tagged pointer object
84 // getIsa() allows this to be a tagged pointer object
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
);
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
);
102 bool hasNonpointerIsa();
103 bool isTaggedPointer();
104 bool isBasicTaggedPointer();
105 bool isExtTaggedPointer();
108 // object may have associated objects?
109 bool hasAssociatedObjects();
110 void setHasAssociatedObjects();
112 // object may be weakly referenced?
113 bool isWeaklyReferenced();
114 void setWeaklyReferenced_nolock();
116 // object may have -.cxx_destruct implementation?
119 // Optimized calls to retain/release methods
124 // Implementations of retain/release methods
127 id
rootAutorelease();
128 bool rootTryRetain();
129 bool rootReleaseShouldDealloc();
130 uintptr_t rootRetainCount();
132 // Implementation of dealloc methods
133 bool rootIsDeallocating();
134 void clearDeallocating();
138 void initIsa(Class newCls
, bool nonpointer
, bool hasCxxDtor
);
140 // Slow paths for inline control
141 id
rootAutorelease2();
142 bool overrelease_error();
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
);
151 void clearDeallocating_slow();
153 // Side table retain count overflow for nonpointer isa
154 void sidetable_lock();
155 void sidetable_unlock();
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();
163 // Side-table-only retain count
164 bool sidetable_isDeallocating();
165 void sidetable_clearDeallocating();
167 bool sidetable_isWeaklyReferenced();
168 void sidetable_setWeaklyReferenced_nolock();
170 id
sidetable_retain();
171 id
sidetable_retain_slow(SideTable
& table
);
173 uintptr_t sidetable_release(bool performDealloc
= true);
174 uintptr_t sidetable_release_slow(SideTable
& table
, bool performDealloc
= true);
176 bool sidetable_tryRetain();
178 uintptr_t sidetable_retainCount();
180 bool sidetable_present();
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
;
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
;
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"
209 /* Do not include message.h here. */
210 /* #include "message.h" */
212 #define __APPLE_API_PRIVATE
213 #include "objc-gdb.h"
214 #undef __APPLE_API_PRIVATE
219 #include "objc-ptrauth.h"
222 #include "objc-runtime-new.h"
224 #include "objc-runtime-old.h"
227 #include "objc-references.h"
228 #include "objc-initialize.h"
229 #include "objc-loadmethod.h"
232 #if SUPPORT_PREOPT && __cplusplus
233 #include <objc-shared-cache.h>
234 using objc_selopt_t
= const objc_opt::objc_selopt_t
;
236 struct objc_selopt_t
;
240 #define STRINGIFY(x) #x
241 #define STRINGIFY2(x) STRINGIFY(x)
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
{
252 bool getLoaded() const {
256 void setLoaded(bool v
) {
260 bool getAllClassesRealized() const {
261 return allClassesRealized
;
264 void setAllClassesRealized(bool v
) {
265 allClassesRealized
= v
? 1: 0;
268 header_info
*getNext() const {
269 return (header_info
*)(next
<< 2);
272 void setNext(header_info
*v
) {
273 next
= ((uintptr_t)v
) >> 2;
278 uintptr_t isLoaded
: 1;
279 uintptr_t allClassesRealized
: 1;
282 uintptr_t isLoaded
: 1;
283 uintptr_t allClassesRealized
: 1;
288 struct header_info_rw
* getPreoptimizedHeaderRW(const struct header_info
*const hdr
);
290 typedef struct header_info
{
292 // Note, this is no longer a pointer, but instead an offset to a pointer
293 // from this location.
294 intptr_t mhdr_offset
;
296 // Note, this is no longer a pointer, but instead an offset to a pointer
297 // from this location.
298 intptr_t info_offset
;
300 // Do not add fields without editing ObjCModernAbstraction.hpp
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];
310 const headerType
*mhdr() const {
311 return (const headerType
*)(((intptr_t)&mhdr_offset
) + mhdr_offset
);
314 void setmhdr(const headerType
*mhdr
) {
315 mhdr_offset
= (intptr_t)mhdr
- (intptr_t)&mhdr_offset
;
318 const objc_image_info
*info() const {
319 return (const objc_image_info
*)(((intptr_t)&info_offset
) + info_offset
);
322 void setinfo(const objc_image_info
*info
) {
323 info_offset
= (intptr_t)info
- (intptr_t)&info_offset
;
327 return getHeaderInfoRW()->getLoaded();
330 void setLoaded(bool v
) {
331 getHeaderInfoRW()->setLoaded(v
);
334 bool areAllClassesRealized() {
335 return getHeaderInfoRW()->getAllClassesRealized();
338 void setAllClassesRealized(bool v
) {
339 getHeaderInfoRW()->setAllClassesRealized(v
);
342 header_info
*getNext() {
343 return getHeaderInfoRW()->getNext();
346 void setNext(header_info
*v
) {
347 getHeaderInfoRW()->setNext(v
);
351 return mhdr()->filetype
== MH_BUNDLE
;
354 const char *fname() const {
355 return dyld_image_path_containing_address(mhdr());
358 bool isPreoptimized() const;
361 struct old_protocol
**proto_refs
;
362 struct objc_module
*mod_ptr
;
365 struct objc_module
**modules
;
367 struct old_protocol
**protocols
;
368 size_t protocolCount
;
370 size_t imageinfoBytes
;
373 struct objc_class
**clsrefs
;
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
[];
385 extern header_info
*FirstHeader
;
386 extern header_info
*LastHeader
;
387 extern int HeaderCount
;
389 extern void appendHeader(header_info
*hi
);
390 extern void removeHeader(header_info
*hi
);
392 extern objc_image_info
*_getObjcImageInfo(const headerType
*head
, size_t *size
);
393 extern bool _hasObjcContents(const header_info
*hi
);
396 // Mach-O segment and section names are 16 bytes and may be un-terminated.
398 static inline bool segnameEquals(const char *lhs
, const char *rhs
) {
399 return 0 == strncmp(lhs
, rhs
, 16);
402 static inline bool segnameStartsWith(const char *segname
, const char *prefix
) {
403 return 0 == strncmp(segname
, prefix
, strlen(prefix
));
406 static inline bool sectnameEquals(const char *lhs
, const char *rhs
) {
407 return segnameEquals(lhs
, rhs
);
410 static inline bool sectnameStartsWith(const char *sectname
, const char *prefix
){
411 return segnameStartsWith(sectname
, prefix
);
416 extern void sel_init(size_t selrefCount
);
417 extern SEL
sel_registerNameNoLock(const char *str
, bool copy
);
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
;
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
;
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
);
447 extern objc_selopt_t
*preoptimizedSelectors(void);
449 extern Protocol
*getPreoptimizedProtocol(const char *name
);
451 extern unsigned getPreoptimizedClassUnreasonableCount();
452 extern Class
getPreoptimizedClass(const char *name
);
453 extern Class
* copyPreoptimizedClasses(const char *name
, int *outCount
);
455 extern bool sharedRegionContains(const void *ptr
);
457 extern Class
_calloc_class(size_t size
);
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
);
463 extern IMP
lookupMethodInClassAndLoadCache(Class cls
, SEL sel
);
464 extern bool class_respondsToSelector_inst(Class cls
, SEL sel
, id inst
);
466 extern bool objcMsgLogEnabled
;
467 extern bool logMessageSend(bool isClassMethod
,
468 const char *objectsClass
,
469 const char *implementingClass
,
472 /* message dispatcher */
473 extern IMP
_class_lookupMethodAndLoadCache3(id
, SEL
, Class
);
475 #if !OBJC_OLD_DISPATCH_PROTOTYPES
476 extern void _objc_msgForward_impcache(void);
478 extern id
_objc_msgForward_impcache(id
, SEL
, ...);
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
);
490 extern Class
_objc_getFreedObjectClass (void);
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
);
496 /* hash table additions */
497 extern unsigned _NXHashCapacity(NXHashTable
*table
);
498 extern void _NXHashRehashToCapacity(NXHashTable
*table
, unsigned newCapacity
);
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
);
506 extern void lock_init(void);
508 class monitor_locker_t
: nocopy_t
{
511 monitor_locker_t(monitor_t
& newLock
) : lock(newLock
) { lock
.enter(); }
512 ~monitor_locker_t() { lock
.leave(); }
515 class recursive_mutex_locker_t
: nocopy_t
{
516 recursive_mutex_t
& lock
;
518 recursive_mutex_locker_t(recursive_mutex_t
& newLock
)
519 : lock(newLock
) { lock
.lock(); }
520 ~recursive_mutex_locker_t() { lock
.unlock(); }
525 struct alt_handler_list
;
526 extern void exception_init(void);
527 extern void _destroyAltHandlerList(struct alt_handler_list
*list
);
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
));
538 // Settings from environment variables
539 #define OPTION(var, env, help) extern bool var;
540 #include "objc-env.h"
543 extern void environ_init(void);
545 extern void logReplacedMethod(const char *className
, SEL s
, bool isMeta
, const char *catName
, IMP oldImp
, IMP newImp
);
548 // objc per-thread storage
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
555 // If you add new fields here, don't forget to update
556 // _objc_pthread_destroyspecific()
558 } _objc_pthread_data
;
560 extern _objc_pthread_data
*_objc_fetch_pthread_data(bool create
);
561 extern void tls_init(void);
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
);
573 extern void _destroySyncCache(struct SyncCache
*cache
);
576 extern void arr_init(void);
577 extern id
objc_autoreleaseReturnValue(id obj
);
580 extern IMP
_imp_implementationWithBlockNoCopy(id block
);
586 size_t bitsAllocated
;
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
);
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
);
618 extern const header_info
*_headerForClass(Class cls
);
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
);
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
);
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
);
632 extern id
object_cxxConstructFromClass(id obj
, Class cls
);
633 extern void object_cxxDestruct(id obj
);
635 extern void _class_resolveMethod(Class cls
, SEL sel
, id inst
);
637 extern void fixupCopiedIvars(id newObject
, id oldObject
);
638 extern Class
_class_getClassForIvar(Class cls
, Ivar ivar
);
641 #define OBJC_WARN_DEPRECATED \
643 static int warned = 0; \
646 _objc_inform_deprecated(__FUNCTION__, NULL); \
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) \
658 int _static_assert[(x) ? 0 : -1]; \
659 } _static_assert_ ## line __attribute__((unavailable))
662 #define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
665 static __inline
uint32_t _objc_strhash(const char *s
) {
670 hash
+= (hash
<< 8) + a
;
677 template <typename T
>
678 static inline T
log2u(T x
) {
679 return (x
<2) ? 0 : log2u(x
>>1)+1;
682 template <typename T
>
683 static inline T
exp2u(T x
) {
687 template <typename T
>
688 static T
exp2m1u(T x
) {
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
;
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.
708 #pragma clang diagnostic push
709 #pragma clang diagnostic ignored "-Winline-new-delete"
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
727 TimeLogger(bool record
= true)
728 : mStart(nanoseconds())
732 void log(const char *msg
) {
734 uint64_t end
= nanoseconds();
735 _objc_inform("%.2f ms: %s", (end
- mStart
) / 1000000.0, msg
);
736 mStart
= nanoseconds();
741 enum { CacheLineSize
= 64 };
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.
749 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
750 enum { StripeCount
= 8 };
752 enum { StripeCount
= 64 };
756 T value
alignas(CacheLineSize
);
759 PaddedT array
[StripeCount
];
761 static unsigned int indexForPointer(const void *p
) {
762 uintptr_t addr
= reinterpret_cast<uintptr_t>(p
);
763 return ((addr
>> 4) ^ (addr
>> 9)) % StripeCount
;
767 T
& operator[] (const void *p
) {
768 return array
[indexForPointer(p
)].value
;
770 const T
& operator[] (const void *p
) const {
771 return const_cast<StripedMap
<T
>>(this)[p
];
774 // Shortcuts for StripedMaps of locks.
776 for (unsigned int i
= 0; i
< StripeCount
; i
++) {
777 array
[i
].value
.lock();
782 for (unsigned int i
= 0; i
< StripeCount
; i
++) {
783 array
[i
].value
.unlock();
787 void forceResetAll() {
788 for (unsigned int i
= 0; i
< StripeCount
; i
++) {
789 array
[i
].value
.forceReset();
793 void defineLockOrder() {
794 for (unsigned int i
= 1; i
< StripeCount
; i
++) {
795 lockdebug_lock_precedes_lock(&array
[i
-1].value
, &array
[i
].value
);
799 void precedeLock(const void *newlock
) {
800 // assumes defineLockOrder is also called
801 lockdebug_lock_precedes_lock(&array
[StripeCount
-1].value
, newlock
);
804 void succeedLock(const void *oldlock
) {
805 // assumes defineLockOrder is also called
806 lockdebug_lock_precedes_lock(oldlock
, &array
[0].value
);
809 const void *getLock(int i
) {
810 if (i
< StripeCount
) return &array
[i
].value
;
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);
823 constexpr StripedMap() {}
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
>
837 static uintptr_t disguise(T
* ptr
) {
838 return -(uintptr_t)ptr
;
841 static T
* undisguise(uintptr_t val
) {
848 : value(disguise(ptr
)) { }
849 DisguisedPtr(const DisguisedPtr
<T
>& ptr
)
850 : value(ptr
.value
) { }
852 DisguisedPtr
<T
>& operator = (T
* rhs
) {
853 value
= disguise(rhs
);
856 DisguisedPtr
<T
>& operator = (const DisguisedPtr
<T
>& rhs
) {
861 operator T
* () const {
862 return undisguise(value
);
864 T
* operator -> () const {
865 return undisguise(value
);
867 T
& operator * () const {
868 return *undisguise(value
);
870 T
& operator [] (size_t i
) const {
871 return undisguise(value
)[i
];
874 // pointer arithmetic operators omitted
875 // because we don't currently use them anywhere
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
;
882 static inline bool operator != (DisguisedPtr
<objc_object
> lhs
, id rhs
) {
883 return lhs
!= (objc_object
*)rhs
;
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
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
898 template <typename Fn
>
899 class ChainedHookFunction
{
900 std::atomic
<Fn
> hook
{nil
};
903 ChainedHookFunction(Fn f
) : hook
{f
} { };
906 return hook
.load(std::memory_order_acquire
);
909 void set(Fn newValue
, Fn
*oldVariable
)
911 Fn oldValue
= hook
.load(std::memory_order_relaxed
);
913 *oldVariable
= oldValue
;
914 } while (!hook
.compare_exchange_weak(oldValue
, newValue
,
915 std::memory_order_release
,
916 std::memory_order_relaxed
));
921 // Pointer hash function.
922 // This is not a terrific hash, but it is fast
923 // and not outrageously flawed for our purposes.
925 // Based on principles from http://locklessinc.com/articles/fast_hash/
926 // and evaluation ideas from http://floodyberry.com/noncryptohashzoo/
928 static inline uint32_t ptr_hash(uint64_t key
)
931 key
*= 0x8a970be7488fda55;
932 key
^= __builtin_bswap64(key
);
933 return (uint32_t)key
;
936 static inline uint32_t ptr_hash(uint32_t key
)
940 key
^= __builtin_bswap32(key
);
946 Higher-quality hash function. This is measurably slower in some workloads.
948 uint32_t ptr_hash(uint64_t key)
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;
958 static uint32_t ptr_hash(uint32_t key)
960 key -= __builtin_bswap32(key);
962 key ^= __builtin_bswap32(key);
964 key ^= __builtin_bswap32(key);
973 #include "objc-locks.h"
975 // Inlined parts of objc_object's implementation
976 #include "objc-object.h"
978 #endif /* _OBJC_PRIVATE_H_ */