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
49 // An assert that's disabled for release builds but still ensures the expression compiles.
51 #define ASSERT(x) (void)sizeof(!(x))
53 #define ASSERT(x) assert(x)
60 typedef struct objc_class
*Class
;
61 typedef struct objc_object
*id
;
62 typedef struct classref
*classref_t
;
72 isa_t(uintptr_t value
) : bits(value
) { }
76 #if defined(ISA_BITFIELD)
78 ISA_BITFIELD
; // defined in isa.h
90 // ISA() assumes this is NOT a tagged pointer object
93 // rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
96 // getIsa() allows this to be a tagged pointer object
99 uintptr_t isaBits() const;
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
);
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
);
116 bool hasNonpointerIsa();
117 bool isTaggedPointer();
118 bool isBasicTaggedPointer();
119 bool isExtTaggedPointer();
122 // object may have associated objects?
123 bool hasAssociatedObjects();
124 void setHasAssociatedObjects();
126 // object may be weakly referenced?
127 bool isWeaklyReferenced();
128 void setWeaklyReferenced_nolock();
130 // object may have -.cxx_destruct implementation?
133 // Optimized calls to retain/release methods
138 // Implementations of retain/release methods
141 id
rootAutorelease();
142 bool rootTryRetain();
143 bool rootReleaseShouldDealloc();
144 uintptr_t rootRetainCount();
146 // Implementation of dealloc methods
147 bool rootIsDeallocating();
148 void clearDeallocating();
152 void initIsa(Class newCls
, bool nonpointer
, bool hasCxxDtor
);
154 // Slow paths for inline control
155 id
rootAutorelease2();
156 uintptr_t overrelease_error();
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
);
165 void clearDeallocating_slow();
167 // Side table retain count overflow for nonpointer isa
168 void sidetable_lock();
169 void sidetable_unlock();
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();
177 // Side-table-only retain count
178 bool sidetable_isDeallocating();
179 void sidetable_clearDeallocating();
181 bool sidetable_isWeaklyReferenced();
182 void sidetable_setWeaklyReferenced_nolock();
184 id
sidetable_retain();
185 id
sidetable_retain_slow(SideTable
& table
);
187 uintptr_t sidetable_release(bool performDealloc
= true);
188 uintptr_t sidetable_release_slow(SideTable
& table
, bool performDealloc
= true);
190 bool sidetable_tryRetain();
192 uintptr_t sidetable_retainCount();
194 bool sidetable_present();
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
;
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
;
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"
223 /* Do not include message.h here. */
224 /* #include "message.h" */
226 #define __APPLE_API_PRIVATE
227 #include "objc-gdb.h"
228 #undef __APPLE_API_PRIVATE
233 #include "objc-ptrauth.h"
236 #include "objc-runtime-new.h"
238 #include "objc-runtime-old.h"
241 #include "objc-references.h"
242 #include "objc-initialize.h"
243 #include "objc-loadmethod.h"
246 #define STRINGIFY(x) #x
247 #define STRINGIFY2(x) STRINGIFY(x)
259 inline bool contains(uintptr_t ptr
) const {
260 uintptr_t m_start
, m_end
;
262 // <rdar://problem/48304934> Force the compiler to use ldp
263 // we really don't want 2 loads and 2 jumps.
266 "ldp %x[one], %x[two], [%x[src]]"
268 "ldp %w[one], %w[two], [%x[src]]"
270 : [one
] "=r" (m_start
), [two
] "=r" (m_end
)
277 return m_start
<= ptr
&& ptr
< m_end
;
281 struct Range
*ranges
;
287 inline bool contains(uint16_t witness
, uintptr_t ptr
) const {
288 return witness
< count
&& ranges
[witness
].contains(ptr
);
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
);
296 extern struct SafeRanges dataSegmentsRanges
;
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
{
307 bool getLoaded() const {
311 void setLoaded(bool v
) {
315 bool getAllClassesRealized() const {
316 return allClassesRealized
;
319 void setAllClassesRealized(bool v
) {
320 allClassesRealized
= v
? 1: 0;
323 header_info
*getNext() const {
324 return (header_info
*)(next
<< 2);
327 void setNext(header_info
*v
) {
328 next
= ((uintptr_t)v
) >> 2;
333 uintptr_t isLoaded
: 1;
334 uintptr_t allClassesRealized
: 1;
337 uintptr_t isLoaded
: 1;
338 uintptr_t allClassesRealized
: 1;
343 struct header_info_rw
* getPreoptimizedHeaderRW(const struct header_info
*const hdr
);
345 typedef struct header_info
{
347 // Note, this is no longer a pointer, but instead an offset to a pointer
348 // from this location.
349 intptr_t mhdr_offset
;
351 // Note, this is no longer a pointer, but instead an offset to a pointer
352 // from this location.
353 intptr_t info_offset
;
355 // Offset from this location to the non-lazy class list
356 intptr_t nlclslist_offset
;
357 uintptr_t nlclslist_count
;
359 // Offset from this location to the non-lazy category list
360 intptr_t nlcatlist_offset
;
361 uintptr_t nlcatlist_count
;
363 // Offset from this location to the category list
364 intptr_t catlist_offset
;
365 uintptr_t catlist_count
;
367 // Offset from this location to the category list 2
368 intptr_t catlist2_offset
;
369 uintptr_t catlist2_count
;
371 // Do not add fields without editing ObjCModernAbstraction.hpp
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];
381 const headerType
*mhdr() const {
382 return (const headerType
*)(((intptr_t)&mhdr_offset
) + mhdr_offset
);
385 void setmhdr(const headerType
*mhdr
) {
386 mhdr_offset
= (intptr_t)mhdr
- (intptr_t)&mhdr_offset
;
389 const objc_image_info
*info() const {
390 return (const objc_image_info
*)(((intptr_t)&info_offset
) + info_offset
);
393 void setinfo(const objc_image_info
*info
) {
394 info_offset
= (intptr_t)info
- (intptr_t)&info_offset
;
397 const classref_t
*nlclslist(size_t *outCount
) const;
399 void set_nlclslist(const void *list
) {
400 nlclslist_offset
= (intptr_t)list
- (intptr_t)&nlclslist_offset
;
403 category_t
* const *nlcatlist(size_t *outCount
) const;
405 void set_nlcatlist(const void *list
) {
406 nlcatlist_offset
= (intptr_t)list
- (intptr_t)&nlcatlist_offset
;
409 category_t
* const *catlist(size_t *outCount
) const;
411 void set_catlist(const void *list
) {
412 catlist_offset
= (intptr_t)list
- (intptr_t)&catlist_offset
;
415 category_t
* const *catlist2(size_t *outCount
) const;
417 void set_catlist2(const void *list
) {
418 catlist2_offset
= (intptr_t)list
- (intptr_t)&catlist2_offset
;
422 return getHeaderInfoRW()->getLoaded();
425 void setLoaded(bool v
) {
426 getHeaderInfoRW()->setLoaded(v
);
429 bool areAllClassesRealized() {
430 return getHeaderInfoRW()->getAllClassesRealized();
433 void setAllClassesRealized(bool v
) {
434 getHeaderInfoRW()->setAllClassesRealized(v
);
437 header_info
*getNext() {
438 return getHeaderInfoRW()->getNext();
441 void setNext(header_info
*v
) {
442 getHeaderInfoRW()->setNext(v
);
446 return mhdr()->filetype
== MH_BUNDLE
;
449 const char *fname() const {
450 return dyld_image_path_containing_address(mhdr());
453 bool isPreoptimized() const;
455 bool hasPreoptimizedSelectors() const;
457 bool hasPreoptimizedClasses() const;
459 bool hasPreoptimizedProtocols() const;
461 bool hasPreoptimizedSectionLookups() const;
464 struct old_protocol
**proto_refs
;
465 struct objc_module
*mod_ptr
;
468 struct objc_module
**modules
;
470 struct old_protocol
**protocols
;
471 size_t protocolCount
;
473 size_t imageinfoBytes
;
476 struct objc_class
**clsrefs
;
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
[];
488 extern header_info
*FirstHeader
;
489 extern header_info
*LastHeader
;
491 extern void appendHeader(header_info
*hi
);
492 extern void removeHeader(header_info
*hi
);
494 extern objc_image_info
*_getObjcImageInfo(const headerType
*head
, size_t *size
);
495 extern bool _hasObjcContents(const header_info
*hi
);
498 // Mach-O segment and section names are 16 bytes and may be un-terminated.
500 static inline bool segnameEquals(const char *lhs
, const char *rhs
) {
501 return 0 == strncmp(lhs
, rhs
, 16);
504 static inline bool segnameStartsWith(const char *segname
, const char *prefix
) {
505 return 0 == strncmp(segname
, prefix
, strlen(prefix
));
508 static inline bool sectnameEquals(const char *lhs
, const char *rhs
) {
509 return segnameEquals(lhs
, rhs
);
512 static inline bool sectnameStartsWith(const char *sectname
, const char *prefix
){
513 return segnameStartsWith(sectname
, prefix
);
518 extern bool didCallDyldNotifyRegister
;
523 extern void sel_init(size_t selrefCount
);
524 extern SEL
sel_registerNameNoLock(const char *str
, bool copy
);
526 extern SEL SEL_cxx_construct
;
527 extern SEL SEL_cxx_destruct
;
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
);
536 extern Protocol
*getPreoptimizedProtocol(const char *name
);
537 extern Protocol
*getSharedCachePreoptimizedProtocol(const char *name
);
539 extern unsigned getPreoptimizedClassUnreasonableCount();
540 extern Class
getPreoptimizedClass(const char *name
);
541 extern Class
* copyPreoptimizedClasses(const char *name
, int *outCount
);
543 extern Class
_calloc_class(size_t size
);
547 LOOKUP_INITIALIZE
= 1,
552 extern IMP
lookUpImpOrForward(id obj
, SEL
, Class cls
, int behavior
);
555 lookUpImpOrNil(id obj
, SEL sel
, Class cls
, int behavior
= 0)
557 return lookUpImpOrForward(obj
, sel
, cls
, behavior
| LOOKUP_CACHE
| LOOKUP_NIL
);
560 extern IMP
lookupMethodInClassAndLoadCache(Class cls
, SEL sel
);
567 extern IMPAndSEL
_method_getImplementationAndName(Method m
);
569 extern BOOL
class_respondsToSelector_inst(id inst
, SEL sel
, Class cls
);
570 extern Class
class_initialize(Class cls
, id inst
);
572 extern bool objcMsgLogEnabled
;
573 extern bool logMessageSend(bool isClassMethod
,
574 const char *objectsClass
,
575 const char *implementingClass
,
578 /* message dispatcher */
580 #if !OBJC_OLD_DISPATCH_PROTOTYPES
581 extern void _objc_msgForward_impcache(void);
583 extern id
_objc_msgForward_impcache(id
, SEL
, ...);
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
);
597 extern Class
_objc_getFreedObjectClass (void);
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
);
603 /* hash table additions */
604 extern unsigned _NXHashCapacity(NXHashTable
*table
);
605 extern void _NXHashRehashToCapacity(NXHashTable
*table
, unsigned newCapacity
);
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
);
614 class monitor_locker_t
: nocopy_t
{
617 monitor_locker_t(monitor_t
& newLock
) : lock(newLock
) { lock
.enter(); }
618 ~monitor_locker_t() { lock
.leave(); }
621 class recursive_mutex_locker_t
: nocopy_t
{
622 recursive_mutex_t
& lock
;
624 recursive_mutex_locker_t(recursive_mutex_t
& newLock
)
625 : lock(newLock
) { lock
.lock(); }
626 ~recursive_mutex_locker_t() { lock
.unlock(); }
631 struct alt_handler_list
;
632 extern void exception_init(void);
633 extern void _destroyAltHandlerList(struct alt_handler_list
*list
);
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
));
644 // Settings from environment variables
645 #define OPTION(var, env, help) extern bool var;
646 #include "objc-env.h"
649 extern void environ_init(void);
650 extern void runtime_init(void);
652 extern void logReplacedMethod(const char *className
, SEL s
, bool isMeta
, const char *catName
, IMP oldImp
, IMP newImp
);
655 // objc per-thread storage
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
;
665 // If you add new fields here, don't forget to update
666 // _objc_pthread_destroyspecific()
668 } _objc_pthread_data
;
670 extern _objc_pthread_data
*_objc_fetch_pthread_data(bool create
);
671 extern void tls_init(void);
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
);
683 extern void _destroySyncCache(struct SyncCache
*cache
);
686 extern void arr_init(void);
687 extern id
objc_autoreleaseReturnValue(id obj
);
690 extern void _imp_implementationWithBlock_init(void);
691 extern IMP
_imp_implementationWithBlockNoCopy(id block
);
697 size_t bitsAllocated
;
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
);
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
);
729 extern const header_info
*_headerForClass(Class cls
);
731 extern Class
_class_remap(Class cls
);
732 extern Ivar
_class_getVariable(Class cls
, const char *name
);
734 extern unsigned _class_createInstancesFromZone(Class cls
, size_t extraBytes
, void *zone
, id
*results
, unsigned num_requested
);
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
);
742 OBJECT_CONSTRUCT_NONE
= 0,
743 OBJECT_CONSTRUCT_FREE_ONFAILURE
= 1,
744 OBJECT_CONSTRUCT_CALL_BADALLOC
= 2,
746 extern id
object_cxxConstructFromClass(id obj
, Class cls
, int flags
);
747 extern void object_cxxDestruct(id obj
);
749 extern void fixupCopiedIvars(id newObject
, id oldObject
);
750 extern Class
_class_getClassForIvar(Class cls
, Ivar ivar
);
753 #define OBJC_WARN_DEPRECATED \
755 static int warned = 0; \
758 _objc_inform_deprecated(__FUNCTION__, NULL); \
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) \
770 int _static_assert[(x) ? 0 : -1]; \
771 } _static_assert_ ## line __attribute__((unavailable))
774 #define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
777 static __inline
uint32_t _objc_strhash(const char *s
) {
782 hash
+= (hash
<< 8) + a
;
789 template <typename T
>
790 static inline T
log2u(T x
) {
791 return (x
<2) ? 0 : log2u(x
>>1)+1;
794 template <typename T
>
795 static inline T
exp2u(T x
) {
799 template <typename T
>
800 static T
exp2m1u(T x
) {
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
;
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.
820 #pragma clang diagnostic push
821 #pragma clang diagnostic ignored "-Winline-new-delete"
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
839 TimeLogger(bool record
= true)
840 : mStart(nanoseconds())
844 void log(const char *msg
) {
846 uint64_t end
= nanoseconds();
847 _objc_inform("%.2f ms: %s", (end
- mStart
) / 1000000.0, msg
);
848 mStart
= nanoseconds();
853 enum { CacheLineSize
= 64 };
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.
861 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
862 enum { StripeCount
= 8 };
864 enum { StripeCount
= 64 };
868 T value
alignas(CacheLineSize
);
871 PaddedT array
[StripeCount
];
873 static unsigned int indexForPointer(const void *p
) {
874 uintptr_t addr
= reinterpret_cast<uintptr_t>(p
);
875 return ((addr
>> 4) ^ (addr
>> 9)) % StripeCount
;
879 T
& operator[] (const void *p
) {
880 return array
[indexForPointer(p
)].value
;
882 const T
& operator[] (const void *p
) const {
883 return const_cast<StripedMap
<T
>>(this)[p
];
886 // Shortcuts for StripedMaps of locks.
888 for (unsigned int i
= 0; i
< StripeCount
; i
++) {
889 array
[i
].value
.lock();
894 for (unsigned int i
= 0; i
< StripeCount
; i
++) {
895 array
[i
].value
.unlock();
899 void forceResetAll() {
900 for (unsigned int i
= 0; i
< StripeCount
; i
++) {
901 array
[i
].value
.forceReset();
905 void defineLockOrder() {
906 for (unsigned int i
= 1; i
< StripeCount
; i
++) {
907 lockdebug_lock_precedes_lock(&array
[i
-1].value
, &array
[i
].value
);
911 void precedeLock(const void *newlock
) {
912 // assumes defineLockOrder is also called
913 lockdebug_lock_precedes_lock(&array
[StripeCount
-1].value
, newlock
);
916 void succeedLock(const void *oldlock
) {
917 // assumes defineLockOrder is also called
918 lockdebug_lock_precedes_lock(oldlock
, &array
[0].value
);
921 const void *getLock(int i
) {
922 if (i
< StripeCount
) return &array
[i
].value
;
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);
935 constexpr StripedMap() {}
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
>
949 static uintptr_t disguise(T
* ptr
) {
950 return -(uintptr_t)ptr
;
953 static T
* undisguise(uintptr_t val
) {
960 : value(disguise(ptr
)) { }
961 DisguisedPtr(const DisguisedPtr
<T
>& ptr
)
962 : value(ptr
.value
) { }
964 DisguisedPtr
<T
>& operator = (T
* rhs
) {
965 value
= disguise(rhs
);
968 DisguisedPtr
<T
>& operator = (const DisguisedPtr
<T
>& rhs
) {
973 operator T
* () const {
974 return undisguise(value
);
976 T
* operator -> () const {
977 return undisguise(value
);
979 T
& operator * () const {
980 return *undisguise(value
);
982 T
& operator [] (size_t i
) const {
983 return undisguise(value
)[i
];
986 // pointer arithmetic operators omitted
987 // because we don't currently use them anywhere
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
;
994 static inline bool operator != (DisguisedPtr
<objc_object
> lhs
, id rhs
) {
995 return lhs
!= (objc_object
*)rhs
;
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.
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
1010 template <typename Fn
>
1011 class ChainedHookFunction
{
1012 std::atomic
<Fn
> hook
{nil
};
1015 constexpr ChainedHookFunction(Fn f
) : hook
{f
} { };
1018 return hook
.load(std::memory_order_acquire
);
1021 void set(Fn newValue
, Fn
*oldVariable
)
1023 Fn oldValue
= hook
.load(std::memory_order_relaxed
);
1025 *oldVariable
= oldValue
;
1026 } while (!hook
.compare_exchange_weak(oldValue
, newValue
,
1027 std::memory_order_release
,
1028 std::memory_order_relaxed
));
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.
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.
1042 template <typename T
, unsigned InlineCount
>
1043 class GlobalSmallVector
{
1044 static_assert(std::is_pod
<T
>::value
, "SmallVector requires POD types");
1049 T inlineElements
[InlineCount
];
1050 T
*elements
{nullptr};
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
;
1065 // Resize the heap allocation and append.
1066 elements
= (T
*)realloc(elements
, (count
+ 1) * sizeof(T
));
1067 elements
[count
] = val
;
1072 const T
*begin() const {
1073 return count
<= InlineCount
? inlineElements
: elements
;
1076 const T
*end() const {
1077 return begin() + count
;
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
> {
1086 if (this->count
> InlineCount
)
1087 free(this->elements
);
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
));
1097 memcpy(this->inlineElements
, other
.begin(), this->count
* sizeof(T
));
1102 // Pointer hash function.
1103 // This is not a terrific hash, but it is fast
1104 // and not outrageously flawed for our purposes.
1106 // Based on principles from http://locklessinc.com/articles/fast_hash/
1107 // and evaluation ideas from http://floodyberry.com/noncryptohashzoo/
1109 static inline uint32_t ptr_hash(uint64_t key
)
1112 key
*= 0x8a970be7488fda55;
1113 key
^= __builtin_bswap64(key
);
1114 return (uint32_t)key
;
1117 static inline uint32_t ptr_hash(uint32_t key
)
1121 key
^= __builtin_bswap32(key
);
1127 Higher-quality hash function. This is measurably slower in some workloads.
1129 uint32_t ptr_hash(uint64_t key)
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;
1139 static uint32_t ptr_hash(uint32_t key)
1141 key -= __builtin_bswap32(key);
1143 key ^= __builtin_bswap32(key);
1145 key ^= __builtin_bswap32(key);
1153 // Lock declarations
1154 #include "objc-locks.h"
1156 // Inlined parts of objc_object's implementation
1157 #include "objc-object.h"
1159 #endif /* _OBJC_PRIVATE_H_ */