*/
#include <objc/objc.h>
+#include <objc/runtime.h>
#include <Availability.h>
#include <malloc/malloc.h>
+#include <mach-o/loader.h>
#include <dispatch/dispatch.h>
+// Include NSObject.h only if we're ObjC. Module imports get unhappy
+// otherwise.
+#if __OBJC__
+#include <objc/NSObject.h>
+#endif
+
+// Termination reasons in the OS_REASON_OBJC namespace.
+#define OBJC_EXIT_REASON_UNSPECIFIED 1
+#define OBJC_EXIT_REASON_GC_NOT_SUPPORTED 2
+
+// This is the allocation size required for each of the class and the metaclass
+// with objc_initializeClassPair() and objc_readClassPair().
+// The runtime's class structure will never grow beyond this.
+#define OBJC_MAX_CLASS_SIZE (32*sizeof(void*))
+
+// Private objc_setAssociatedObject policy modifier. When an object is
+// destroyed, associated objects attached to that object that are marked with
+// this will be released after all associated objects not so marked.
+//
+// In addition, such associations are not removed when calling
+// objc_removeAssociatedObjects.
+//
+// NOTE: This should be used sparingly. Performance will be poor when a single
+// object has more than a few (deliberately vague) associated objects marked
+// with this flag. If you're not sure if you should use this, you should not use
+// this!
+#define _OBJC_ASSOCIATION_SYSTEM_OBJECT (1 << 16)
+
__BEGIN_DECLS
-// In-place construction of an Objective-C instance.
-OBJC_EXPORT id objc_constructInstance(Class cls, void *bytes)
- __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0)
- OBJC_ARC_UNAVAILABLE;
-OBJC_EXPORT void *objc_destructInstance(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0)
- OBJC_ARC_UNAVAILABLE;
+// This symbol is exported only from debug builds of libobjc itself.
+#if defined(OBJC_IS_DEBUG_BUILD)
+OBJC_EXPORT void _objc_isDebugBuild(void);
+#endif
// In-place construction of an Objective-C class.
-OBJC_EXPORT Class objc_initializeClassPair(Class superclass_gen, const char *name, Class cls_gen, Class meta_gen)
- __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0);
-
-#if __OBJC2__ && __LP64__
-// Register a tagged pointer class.
-OBJC_EXPORT void _objc_insert_tagged_isa(unsigned char slotNumber, Class isa)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
+// cls and metacls must each be OBJC_MAX_CLASS_SIZE bytes.
+// Returns nil if a class with the same name already exists.
+// Returns nil if the superclass is under construction.
+// Call objc_registerClassPair() when you are done.
+OBJC_EXPORT Class _Nullable
+objc_initializeClassPair(Class _Nullable superclass, const char * _Nonnull name,
+ Class _Nonnull cls, Class _Nonnull metacls)
+ OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0, 2.0);
+
+// Class and metaclass construction from a compiler-generated memory image.
+// cls and cls->isa must each be OBJC_MAX_CLASS_SIZE bytes.
+// Extra bytes not used the the metadata must be zero.
+// info is the same objc_image_info that would be emitted by a static compiler.
+// Returns nil if a class with the same name already exists.
+// Returns nil if the superclass is nil and the class is not marked as a root.
+// Returns nil if the superclass is under construction.
+// Do not call objc_registerClassPair().
+#if __OBJC2__
+struct objc_image_info;
+OBJC_EXPORT Class _Nullable
+objc_readClassPair(Class _Nonnull cls,
+ const struct objc_image_info * _Nonnull info)
+ OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0, 2.0);
#endif
// Batch object allocation using malloc_zone_batch_malloc().
-OBJC_EXPORT unsigned class_createInstances(Class cls, size_t extraBytes,
- id *results, unsigned num_requested)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3)
+OBJC_EXPORT unsigned
+class_createInstances(Class _Nullable cls, size_t extraBytes,
+ id _Nonnull * _Nonnull results, unsigned num_requested)
+ OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0)
OBJC_ARC_UNAVAILABLE;
// Get the isa pointer written into objects just before being freed.
-OBJC_EXPORT Class _objc_getFreedObjectClass(void)
- __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
+OBJC_EXPORT Class _Nonnull
+_objc_getFreedObjectClass(void)
+ OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
+
+// env NSObjCMessageLoggingEnabled
+OBJC_EXPORT void
+instrumentObjcMessageSends(BOOL flag)
+ OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
+
+// Initializer called by libSystem
+OBJC_EXPORT void
+_objc_init(void)
+#if __OBJC2__
+ OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
+#else
+ OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
+#endif
+
+// fork() safety called by libSystem
+OBJC_EXPORT void
+_objc_atfork_prepare(void)
+ OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
-// Substitute receiver for messages to nil.
-// Not supported for all messages to nil.
-OBJC_EXPORT id _objc_setNilReceiver(id newNilReceiver)
- __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA);
-OBJC_EXPORT id _objc_getNilReceiver(void)
- __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA);
+OBJC_EXPORT void
+_objc_atfork_parent(void)
+ OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
-// Return NO if no instance of `cls` has ever owned an associative reference.
-OBJC_EXPORT BOOL class_instancesHaveAssociatedObjects(Class cls)
- __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0);
+OBJC_EXPORT void
+_objc_atfork_child(void)
+ OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
// Return YES if GC is on and `object` is a GC allocation.
-OBJC_EXPORT BOOL objc_isAuto(id object)
- __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_NA);
+OBJC_EXPORT BOOL
+objc_isAuto(id _Nullable object)
+ OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.8, "it always returns NO");
-// env NSObjCMessageLoggingEnabled
-OBJC_EXPORT void instrumentObjcMessageSends(BOOL flag)
- __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
+// GC debugging
+OBJC_EXPORT BOOL
+objc_dumpHeap(char * _Nonnull filename, unsigned long length)
+ OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.8, "it always returns NO");
// GC startup callback from Foundation
-OBJC_EXPORT malloc_zone_t *objc_collect_init(int (*callback)(void))
- __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_NA);
+OBJC_EXPORT malloc_zone_t * _Nullable
+objc_collect_init(int (* _Nonnull callback)(void))
+ OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.4, 10.8, "it does nothing");
+
+#if __OBJC2__
+// Copies the list of currently realized classes
+// intended for introspection only
+// most users will want objc_copyClassList instead.
+OBJC_EXPORT
+Class _Nonnull * _Nullable
+objc_copyRealizedClassList(unsigned int *_Nullable outCount)
+ OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
+
+typedef struct objc_imp_cache_entry {
+ SEL _Nonnull sel;
+ IMP _Nonnull imp;
+} objc_imp_cache_entry;
+
+OBJC_EXPORT
+objc_imp_cache_entry *_Nullable
+class_copyImpCache(Class _Nonnull cls, int * _Nullable outCount)
+ OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
+
+OBJC_EXPORT
+unsigned long
+sel_hash(SEL _Nullable sel)
+ OBJC_AVAILABLE(10.16, 14.0, 14.0, 7.0, 6.0);
+#endif
+
// Plainly-implemented GC barriers. Rosetta used to use these.
-OBJC_EXPORT id objc_assign_strongCast_generic(id value, id *dest)
+OBJC_EXPORT id _Nullable
+objc_assign_strongCast_generic(id _Nullable value, id _Nullable * _Nonnull dest)
UNAVAILABLE_ATTRIBUTE;
-OBJC_EXPORT id objc_assign_global_generic(id value, id *dest)
+
+OBJC_EXPORT id _Nullable
+objc_assign_global_generic(id _Nullable value, id _Nullable * _Nonnull dest)
UNAVAILABLE_ATTRIBUTE;
-OBJC_EXPORT id objc_assign_threadlocal_generic(id value, id *dest)
+
+OBJC_EXPORT id _Nullable
+objc_assign_threadlocal_generic(id _Nullable value,
+ id _Nullable * _Nonnull dest)
UNAVAILABLE_ATTRIBUTE;
-OBJC_EXPORT id objc_assign_ivar_generic(id value, id dest, ptrdiff_t offset)
+
+OBJC_EXPORT id _Nullable
+objc_assign_ivar_generic(id _Nullable value, id _Nonnull dest, ptrdiff_t offset)
UNAVAILABLE_ATTRIBUTE;
-// Install missing-class callback. Used by the late unlamented ZeroLink.
-OBJC_EXPORT void _objc_setClassLoader(BOOL (*newClassLoader)(const char *)) OBJC2_UNAVAILABLE;
+// GC preflight for an app executable.
+// 1: some slice requires GC
+// 0: no slice requires GC
+// -1: I/O or file format error
+OBJC_EXPORT int
+objc_appRequiresGC(int fd)
+ __OSX_AVAILABLE(10.11)
+ __IOS_UNAVAILABLE __TVOS_UNAVAILABLE
+ __WATCHOS_UNAVAILABLE
+#ifndef __APPLE_BLEACH_SDK__
+ __BRIDGEOS_UNAVAILABLE
+#endif
+;
-// This can go away when AppKit stops calling it (rdar://7811851)
-#if __OBJC2__
-OBJC_EXPORT void objc_setMultithreaded (BOOL flag)
- __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0,__MAC_10_5, __IPHONE_NA,__IPHONE_NA);
+// Install missing-class callback. Used by the late unlamented ZeroLink.
+OBJC_EXPORT void
+_objc_setClassLoader(BOOL (* _Nonnull newClassLoader)(const char * _Nonnull))
+ OBJC2_UNAVAILABLE;
+
+#if !(TARGET_OS_OSX && !TARGET_OS_MACCATALYST && __i386__)
+// Add a class copy fixup handler. The name is a misnomer, as
+// multiple calls will install multiple handlers. Older versions
+// of the Swift runtime call it by name, and it's only used by Swift
+// so it's not worth deprecating this name in favor of a better one.
+OBJC_EXPORT void
+_objc_setClassCopyFixupHandler(void (* _Nonnull newFixupHandler)
+ (Class _Nonnull oldClass, Class _Nonnull newClass))
+ OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
#endif
+// Install handler for allocation failures.
+// Handler may abort, or throw, or provide an object to return.
+OBJC_EXPORT void
+_objc_setBadAllocHandler(id _Nullable (* _Nonnull newHandler)
+ (Class _Nullable isa))
+ OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
+
// Used by ExceptionHandling.framework
#if !__OBJC2__
-OBJC_EXPORT void _objc_error(id rcv, const char *fmt, va_list args)
- __attribute__((noreturn))
- __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0,__MAC_10_5, __IPHONE_NA,__IPHONE_NA);
+OBJC_EXPORT void
+_objc_error(id _Nullable rcv, const char * _Nonnull fmt, va_list args)
+ __attribute__((noreturn, cold))
+ OBJC_OSX_DEPRECATED_OTHERS_UNAVAILABLE(10.0, 10.5, "use other logging facilities instead");
#endif
-// External Reference support. Used to support compaction.
-enum {
- OBJC_XREF_STRONG = 1,
- OBJC_XREF_WEAK = 2
+/**
+ * Returns the names of all the classes within a library.
+ *
+ * @param image The mach header for library or framework you are inquiring about.
+ * @param outCount The number of class names returned.
+ *
+ * @return An array of C strings representing the class names.
+ */
+OBJC_EXPORT const char * _Nonnull * _Nullable
+objc_copyClassNamesForImageHeader(const struct mach_header * _Nonnull mh,
+ unsigned int * _Nullable outCount)
+ OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
+
+/**
+ * Returns the all the classes within a library.
+ *
+ * @param image The mach header for library or framework you are inquiring about.
+ * @param outCount The number of class names returned.
+ *
+ * @return An array of Class objects
+ */
+
+OBJC_EXPORT Class _Nonnull * _Nullable
+objc_copyClassesForImage(const char * _Nonnull image,
+ unsigned int * _Nullable outCount)
+ OBJC_AVAILABLE(10.16, 14.0, 14.0, 7.0, 4.0);
+
+
+// Tagged pointer objects.
+
+#if __LP64__
+#define OBJC_HAVE_TAGGED_POINTERS 1
+#endif
+
+#if OBJC_HAVE_TAGGED_POINTERS
+
+// Tagged pointer layout and usage is subject to change on different OS versions.
+
+// Tag indexes 0..<7 have a 60-bit payload.
+// Tag index 7 is reserved.
+// Tag indexes 8..<264 have a 52-bit payload.
+// Tag index 264 is reserved.
+
+#if __has_feature(objc_fixed_enum) || __cplusplus >= 201103L
+enum objc_tag_index_t : uint16_t
+#else
+typedef uint16_t objc_tag_index_t;
+enum
+#endif
+{
+ // 60-bit payloads
+ OBJC_TAG_NSAtom = 0,
+ OBJC_TAG_1 = 1,
+ OBJC_TAG_NSString = 2,
+ OBJC_TAG_NSNumber = 3,
+ OBJC_TAG_NSIndexPath = 4,
+ OBJC_TAG_NSManagedObjectID = 5,
+ OBJC_TAG_NSDate = 6,
+
+ // 60-bit reserved
+ OBJC_TAG_RESERVED_7 = 7,
+
+ // 52-bit payloads
+ OBJC_TAG_Photos_1 = 8,
+ OBJC_TAG_Photos_2 = 9,
+ OBJC_TAG_Photos_3 = 10,
+ OBJC_TAG_Photos_4 = 11,
+ OBJC_TAG_XPC_1 = 12,
+ OBJC_TAG_XPC_2 = 13,
+ OBJC_TAG_XPC_3 = 14,
+ OBJC_TAG_XPC_4 = 15,
+ OBJC_TAG_NSColor = 16,
+ OBJC_TAG_UIColor = 17,
+ OBJC_TAG_CGColor = 18,
+ OBJC_TAG_NSIndexSet = 19,
+ OBJC_TAG_NSMethodSignature = 20,
+ OBJC_TAG_UTTypeRecord = 21,
+
+ // When using the split tagged pointer representation
+ // (OBJC_SPLIT_TAGGED_POINTERS), this is the first tag where
+ // the tag and payload are unobfuscated. All tags from here to
+ // OBJC_TAG_Last52BitPayload are unobfuscated. The shared cache
+ // builder is able to construct these as long as the low bit is
+ // not set (i.e. even-numbered tags).
+ OBJC_TAG_FirstUnobfuscatedSplitTag = 136, // 128 + 8, first ext tag with high bit set
+
+ OBJC_TAG_Constant_CFString = 136,
+
+ OBJC_TAG_First60BitPayload = 0,
+ OBJC_TAG_Last60BitPayload = 6,
+ OBJC_TAG_First52BitPayload = 8,
+ OBJC_TAG_Last52BitPayload = 263,
+
+ OBJC_TAG_RESERVED_264 = 264
};
-typedef uintptr_t objc_xref_type_t;
-typedef uintptr_t objc_xref_t;
+#if __has_feature(objc_fixed_enum) && !defined(__cplusplus)
+typedef enum objc_tag_index_t objc_tag_index_t;
+#endif
+
+
+// Returns true if tagged pointers are enabled.
+// The other functions below must not be called if tagged pointers are disabled.
+static inline bool
+_objc_taggedPointersEnabled(void);
+
+// Register a class for a tagged pointer tag.
+// Aborts if the tag is invalid or already in use.
+OBJC_EXPORT void
+_objc_registerTaggedPointerClass(objc_tag_index_t tag, Class _Nonnull cls)
+ OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
+
+// Returns the registered class for the given tag.
+// Returns nil if the tag is valid but has no registered class.
+// Aborts if the tag is invalid.
+OBJC_EXPORT Class _Nullable
+_objc_getClassForTag(objc_tag_index_t tag)
+ OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
+
+// Create a tagged pointer object with the given tag and payload.
+// Assumes the tag is valid.
+// Assumes tagged pointers are enabled.
+// The payload will be silently truncated to fit.
+static inline void * _Nonnull
+_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t payload);
+
+// Return true if ptr is a tagged pointer object.
+// Does not check the validity of ptr's class.
+static inline bool
+_objc_isTaggedPointer(const void * _Nullable ptr);
+
+// Extract the tag value from the given tagged pointer object.
+// Assumes ptr is a valid tagged pointer object.
+// Does not check the validity of ptr's tag.
+static inline objc_tag_index_t
+_objc_getTaggedPointerTag(const void * _Nullable ptr);
+
+// Extract the payload from the given tagged pointer object.
+// Assumes ptr is a valid tagged pointer object.
+// The payload value is zero-extended.
+static inline uintptr_t
+_objc_getTaggedPointerValue(const void * _Nullable ptr);
+
+// Extract the payload from the given tagged pointer object.
+// Assumes ptr is a valid tagged pointer object.
+// The payload value is sign-extended.
+static inline intptr_t
+_objc_getTaggedPointerSignedValue(const void * _Nullable ptr);
+
+// Don't use the values below. Use the declarations above.
+
+#if __arm64__
+// ARM64 uses a new tagged pointer scheme where normal tags are in
+// the low bits, extended tags are in the high bits, and half of the
+// extended tag space is reserved for unobfuscated payloads.
+# define OBJC_SPLIT_TAGGED_POINTERS 1
+#else
+# define OBJC_SPLIT_TAGGED_POINTERS 0
+#endif
+
+#if (TARGET_OS_OSX || TARGET_OS_MACCATALYST) && __x86_64__
+ // 64-bit Mac - tag bit is LSB
+# define OBJC_MSB_TAGGED_POINTERS 0
+#else
+ // Everything else - tag bit is MSB
+# define OBJC_MSB_TAGGED_POINTERS 1
+#endif
+
+#define _OBJC_TAG_INDEX_MASK 0x7UL
+
+#if OBJC_SPLIT_TAGGED_POINTERS
+#define _OBJC_TAG_SLOT_COUNT 8
+#define _OBJC_TAG_SLOT_MASK 0x7UL
+#else
+// array slot includes the tag bit itself
+#define _OBJC_TAG_SLOT_COUNT 16
+#define _OBJC_TAG_SLOT_MASK 0xfUL
+#endif
+
+#define _OBJC_TAG_EXT_INDEX_MASK 0xff
+// array slot has no extra bits
+#define _OBJC_TAG_EXT_SLOT_COUNT 256
+#define _OBJC_TAG_EXT_SLOT_MASK 0xff
+
+#if OBJC_SPLIT_TAGGED_POINTERS
+# define _OBJC_TAG_MASK (1UL<<63)
+# define _OBJC_TAG_INDEX_SHIFT 0
+# define _OBJC_TAG_SLOT_SHIFT 0
+# define _OBJC_TAG_PAYLOAD_LSHIFT 1
+# define _OBJC_TAG_PAYLOAD_RSHIFT 4
+# define _OBJC_TAG_EXT_MASK (_OBJC_TAG_MASK | 0x7UL)
+# define _OBJC_TAG_NO_OBFUSCATION_MASK ((1UL<<62) | _OBJC_TAG_EXT_MASK)
+# define _OBJC_TAG_CONSTANT_POINTER_MASK \
+ ~(_OBJC_TAG_EXT_MASK | ((uintptr_t)_OBJC_TAG_EXT_SLOT_MASK << _OBJC_TAG_EXT_SLOT_SHIFT))
+# define _OBJC_TAG_EXT_INDEX_SHIFT 55
+# define _OBJC_TAG_EXT_SLOT_SHIFT 55
+# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 9
+# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
+#elif OBJC_MSB_TAGGED_POINTERS
+# define _OBJC_TAG_MASK (1UL<<63)
+# define _OBJC_TAG_INDEX_SHIFT 60
+# define _OBJC_TAG_SLOT_SHIFT 60
+# define _OBJC_TAG_PAYLOAD_LSHIFT 4
+# define _OBJC_TAG_PAYLOAD_RSHIFT 4
+# define _OBJC_TAG_EXT_MASK (0xfUL<<60)
+# define _OBJC_TAG_EXT_INDEX_SHIFT 52
+# define _OBJC_TAG_EXT_SLOT_SHIFT 52
+# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 12
+# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
+#else
+# define _OBJC_TAG_MASK 1UL
+# define _OBJC_TAG_INDEX_SHIFT 1
+# define _OBJC_TAG_SLOT_SHIFT 0
+# define _OBJC_TAG_PAYLOAD_LSHIFT 0
+# define _OBJC_TAG_PAYLOAD_RSHIFT 4
+# define _OBJC_TAG_EXT_MASK 0xfUL
+# define _OBJC_TAG_EXT_INDEX_SHIFT 4
+# define _OBJC_TAG_EXT_SLOT_SHIFT 4
+# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 0
+# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
+#endif
+
+// Map of tags to obfuscated tags.
+extern uintptr_t objc_debug_taggedpointer_obfuscator;
+
+#if OBJC_SPLIT_TAGGED_POINTERS
+extern uint8_t objc_debug_tag60_permutations[8];
+
+static inline uintptr_t _objc_basicTagToObfuscatedTag(uintptr_t tag) {
+ return objc_debug_tag60_permutations[tag];
+}
+
+static inline uintptr_t _objc_obfuscatedTagToBasicTag(uintptr_t tag) {
+ for (unsigned i = 0; i < 7; i++)
+ if (objc_debug_tag60_permutations[i] == tag)
+ return i;
+ return 7;
+}
+#endif
+
+static inline void * _Nonnull
+_objc_encodeTaggedPointer(uintptr_t ptr)
+{
+ uintptr_t value = (objc_debug_taggedpointer_obfuscator ^ ptr);
+#if OBJC_SPLIT_TAGGED_POINTERS
+ if ((value & _OBJC_TAG_NO_OBFUSCATION_MASK) == _OBJC_TAG_NO_OBFUSCATION_MASK)
+ return (void *)ptr;
+ uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
+ uintptr_t permutedTag = _objc_basicTagToObfuscatedTag(basicTag);
+ value &= ~(_OBJC_TAG_INDEX_MASK << _OBJC_TAG_INDEX_SHIFT);
+ value |= permutedTag << _OBJC_TAG_INDEX_SHIFT;
+#endif
+ return (void *)value;
+}
+
+static inline uintptr_t
+_objc_decodeTaggedPointer_noPermute(const void * _Nullable ptr)
+{
+ uintptr_t value = (uintptr_t)ptr;
+#if OBJC_SPLIT_TAGGED_POINTERS
+ if ((value & _OBJC_TAG_NO_OBFUSCATION_MASK) == _OBJC_TAG_NO_OBFUSCATION_MASK)
+ return value;
+#endif
+ return value ^ objc_debug_taggedpointer_obfuscator;
+}
+
+static inline uintptr_t
+_objc_decodeTaggedPointer(const void * _Nullable ptr)
+{
+ uintptr_t value = _objc_decodeTaggedPointer_noPermute(ptr);
+#if OBJC_SPLIT_TAGGED_POINTERS
+ uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
+
+ value &= ~(_OBJC_TAG_INDEX_MASK << _OBJC_TAG_INDEX_SHIFT);
+ value |= _objc_obfuscatedTagToBasicTag(basicTag) << _OBJC_TAG_INDEX_SHIFT;
+#endif
+ return value;
+}
+
+static inline bool
+_objc_taggedPointersEnabled(void)
+{
+ extern uintptr_t objc_debug_taggedpointer_mask;
+ return (objc_debug_taggedpointer_mask != 0);
+}
+
+static inline void * _Nonnull
+_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t value)
+{
+ // PAYLOAD_LSHIFT and PAYLOAD_RSHIFT are the payload extraction shifts.
+ // They are reversed here for payload insertion.
+
+ // ASSERT(_objc_taggedPointersEnabled());
+ if (tag <= OBJC_TAG_Last60BitPayload) {
+ // ASSERT(((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT) == value);
+ uintptr_t result =
+ (_OBJC_TAG_MASK |
+ ((uintptr_t)tag << _OBJC_TAG_INDEX_SHIFT) |
+ ((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT));
+ return _objc_encodeTaggedPointer(result);
+ } else {
+ // ASSERT(tag >= OBJC_TAG_First52BitPayload);
+ // ASSERT(tag <= OBJC_TAG_Last52BitPayload);
+ // ASSERT(((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT) == value);
+ uintptr_t result =
+ (_OBJC_TAG_EXT_MASK |
+ ((uintptr_t)(tag - OBJC_TAG_First52BitPayload) << _OBJC_TAG_EXT_INDEX_SHIFT) |
+ ((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT));
+ return _objc_encodeTaggedPointer(result);
+ }
+}
+
+static inline bool
+_objc_isTaggedPointer(const void * _Nullable ptr)
+{
+ return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
+}
+
+static inline bool
+_objc_isTaggedPointerOrNil(const void * _Nullable ptr)
+{
+ // this function is here so that clang can turn this into
+ // a comparison with NULL when this is appropriate
+ // it turns out it's not able to in many cases without this
+ return !ptr || ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
+}
+
+static inline objc_tag_index_t
+_objc_getTaggedPointerTag(const void * _Nullable ptr)
+{
+ // ASSERT(_objc_isTaggedPointer(ptr));
+ uintptr_t value = _objc_decodeTaggedPointer(ptr);
+ uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
+ uintptr_t extTag = (value >> _OBJC_TAG_EXT_INDEX_SHIFT) & _OBJC_TAG_EXT_INDEX_MASK;
+ if (basicTag == _OBJC_TAG_INDEX_MASK) {
+ return (objc_tag_index_t)(extTag + OBJC_TAG_First52BitPayload);
+ } else {
+ return (objc_tag_index_t)basicTag;
+ }
+}
+
+static inline uintptr_t
+_objc_getTaggedPointerValue(const void * _Nullable ptr)
+{
+ // ASSERT(_objc_isTaggedPointer(ptr));
+ uintptr_t value = _objc_decodeTaggedPointer_noPermute(ptr);
+ uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
+ if (basicTag == _OBJC_TAG_INDEX_MASK) {
+ return (value << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
+ } else {
+ return (value << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
+ }
+}
+
+static inline intptr_t
+_objc_getTaggedPointerSignedValue(const void * _Nullable ptr)
+{
+ // ASSERT(_objc_isTaggedPointer(ptr));
+ uintptr_t value = _objc_decodeTaggedPointer_noPermute(ptr);
+ uintptr_t basicTag = (value >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
+ if (basicTag == _OBJC_TAG_INDEX_MASK) {
+ return ((intptr_t)value << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
+ } else {
+ return ((intptr_t)value << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
+ }
+}
-OBJC_EXPORT objc_xref_t _object_addExternalReference(id object, objc_xref_type_t type)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
-OBJC_EXPORT void _object_removeExternalReference(objc_xref_t xref)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
-OBJC_EXPORT id _object_readExternalReference(objc_xref_t xref)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
+# if OBJC_SPLIT_TAGGED_POINTERS
+static inline void * _Nullable
+_objc_getTaggedPointerRawPointerValue(const void * _Nullable ptr) {
+ return (void *)((uintptr_t)ptr & _OBJC_TAG_CONSTANT_POINTER_MASK);
+}
+# endif
-OBJC_EXPORT uintptr_t _object_getExternalHash(id object)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+// OBJC_HAVE_TAGGED_POINTERS
+#endif
+
+
+/**
+ * Returns the method implementation of an object.
+ *
+ * @param obj An Objective-C object.
+ * @param name An Objective-C selector.
+ *
+ * @return The IMP corresponding to the instance method implemented by
+ * the class of \e obj.
+ *
+ * @note Equivalent to:
+ *
+ * class_getMethodImplementation(object_getClass(obj), name);
+ */
+OBJC_EXPORT IMP _Nonnull
+object_getMethodImplementation(id _Nullable obj, SEL _Nonnull name)
+ OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
+
+OBJC_EXPORT IMP _Nonnull
+object_getMethodImplementation_stret(id _Nullable obj, SEL _Nonnull name)
+ OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0)
+ OBJC_ARM64_UNAVAILABLE;
+
+
+/**
+ * Adds multiple methods to a class in bulk. This amortizes overhead that can be
+ * expensive when adding methods one by one with class_addMethod.
+ *
+ * @param cls The class to which to add the methods.
+ * @param names An array of selectors for the methods to add.
+ * @param imps An array of functions which implement the new methods.
+ * @param types An array of strings that describe the types of each method's
+ * arguments.
+ * @param count The number of items in the names, imps, and types arrays.
+ * @param outFiledCount Upon return, contains the number of failed selectors in
+ * the returned array.
+ *
+ * @return A NULL-terminated C array of selectors which could not be added. A
+ * method cannot be added when a method of that name already exists on that
+ * class. When no failures occur, the return value is \c NULL. When a non-NULL
+ * value is returned, the caller must free the array with \c free().
+ *
+ */
+#if __OBJC2__
+OBJC_EXPORT _Nullable SEL * _Nullable
+class_addMethodsBulk(_Nullable Class cls, _Nonnull const SEL * _Nonnull names,
+ _Nonnull const IMP * _Nonnull imps,
+ const char * _Nonnull * _Nonnull types, uint32_t count,
+ uint32_t * _Nullable outFailedCount)
+ OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
+#endif
+
+/**
+ * Replaces multiple methods in a class in bulk. This amortizes overhead that
+ * can be expensive when adding methods one by one with class_replaceMethod.
+ *
+ * @param cls The class to modify.
+ * @param names An array of selectors for the methods to replace.
+ * @param imps An array of functions will be the new method implementantations.
+ * @param types An array of strings that describe the types of each method's
+ * arguments.
+ * @param count The number of items in the names, imps, and types arrays.
+ */
+#if __OBJC2__
+OBJC_EXPORT void
+class_replaceMethodsBulk(_Nullable Class cls,
+ _Nonnull const SEL * _Nonnull names,
+ _Nonnull const IMP * _Nonnull imps,
+ const char * _Nonnull * _Nonnull types,
+ uint32_t count)
+ OBJC_AVAILABLE(10.14, 12.0, 12.0, 5.0, 3.0);
+#endif
-// Instance-specific instance variable layout.
-OBJC_EXPORT void _class_setIvarLayoutAccessor(Class cls_gen, const uint8_t* (*accessor) (id object))
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
-OBJC_EXPORT const uint8_t *_object_getIvarLayout(Class cls_gen, id object)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
+// Instance-specific instance variable layout. This is no longer implemented.
+
+OBJC_EXPORT void
+_class_setIvarLayoutAccessor(Class _Nullable cls,
+ const uint8_t* _Nullable (* _Nonnull accessor)
+ (id _Nullable object))
+ UNAVAILABLE_ATTRIBUTE;
-OBJC_EXPORT BOOL _class_usesAutomaticRetainRelease(Class cls)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT const uint8_t * _Nullable
+_object_getIvarLayout(Class _Nullable cls, id _Nullable object)
+ UNAVAILABLE_ATTRIBUTE;
+
+
+/*
+ "Unknown" includes non-object ivars and non-ARC non-__weak ivars
+ "Strong" includes ARC __strong ivars
+ "Weak" includes ARC and new MRC __weak ivars
+ "Unretained" includes ARC __unsafe_unretained and old GC+MRC __weak ivars
+*/
+typedef enum {
+ objc_ivar_memoryUnknown, // unknown / unknown
+ objc_ivar_memoryStrong, // direct access / objc_storeStrong
+ objc_ivar_memoryWeak, // objc_loadWeak[Retained] / objc_storeWeak
+ objc_ivar_memoryUnretained // direct access / direct access
+} objc_ivar_memory_management_t;
+
+OBJC_EXPORT objc_ivar_memory_management_t
+_class_getIvarMemoryManagement(Class _Nullable cls, Ivar _Nonnull ivar)
+ OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0, 2.0);
+
+OBJC_EXPORT BOOL _class_isFutureClass(Class _Nullable cls)
+ OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
+
+/// Returns true if the class is an ABI stable Swift class. (Despite
+/// the name, this does NOT return true for Swift classes built with
+/// Swift versions prior to 5.0.)
+OBJC_EXPORT BOOL _class_isSwift(Class _Nullable cls)
+ OBJC_AVAILABLE(10.16, 14.0, 14.0, 7.0, 5.0);
// API to only be called by root classes like NSObject or NSProxy
OBJC_EXPORT
-id
-_objc_rootRetain(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+id _Nonnull
+_objc_rootRetain(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
void
-_objc_rootRelease(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+_objc_rootRelease(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
bool
-_objc_rootReleaseWasZero(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+_objc_rootReleaseWasZero(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
bool
-_objc_rootTryRetain(id obj)
-__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+_objc_rootTryRetain(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
bool
-_objc_rootIsDeallocating(id obj)
-__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+_objc_rootIsDeallocating(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
-id
-_objc_rootAutorelease(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+id _Nonnull
+_objc_rootAutorelease(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
uintptr_t
-_objc_rootRetainCount(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+_objc_rootRetainCount(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
-id
-_objc_rootInit(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+id _Nonnull
+_objc_rootInit(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
-id
-_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+id _Nullable
+_objc_rootAllocWithZone(Class _Nonnull cls, malloc_zone_t * _Nullable zone)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
-id
-_objc_rootAlloc(Class cls)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+id _Nullable
+_objc_rootAlloc(Class _Nonnull cls)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
void
-_objc_rootDealloc(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+_objc_rootDealloc(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
void
-_objc_rootFinalize(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+_objc_rootFinalize(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
-malloc_zone_t *
-_objc_rootZone(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+malloc_zone_t * _Nonnull
+_objc_rootZone(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
uintptr_t
-_objc_rootHash(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+_objc_rootHash(id _Nonnull obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
-void *
+void * _Nonnull
objc_autoreleasePoolPush(void)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
OBJC_EXPORT
void
-objc_autoreleasePoolPop(void *context)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+objc_autoreleasePoolPop(void * _Nonnull context)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
-OBJC_EXPORT id objc_retain(id obj)
- __asm__("_objc_retain")
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT id _Nullable
+objc_alloc(Class _Nullable cls)
+ OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
-OBJC_EXPORT void objc_release(id obj)
- __asm__("_objc_release")
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT id _Nullable
+objc_allocWithZone(Class _Nullable cls)
+ OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0, 2.0);
-OBJC_EXPORT id objc_autorelease(id obj)
- __asm__("_objc_autorelease")
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT id _Nullable
+objc_alloc_init(Class _Nullable cls)
+ OBJC_AVAILABLE(10.14.4, 12.2, 12.2, 5.2, 3.2);
-// wraps objc_autorelease(obj) in a useful way when used with return values
-OBJC_EXPORT
-id
-objc_autoreleaseReturnValue(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT id _Nullable
+objc_opt_new(Class _Nullable cls)
+ OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
-// wraps objc_autorelease(objc_retain(obj)) in a useful way when used with return values
-OBJC_EXPORT
-id
-objc_retainAutoreleaseReturnValue(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT id _Nullable
+objc_opt_self(id _Nullable obj)
+ OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
-// called ONLY by ARR by callers to undo the autorelease (if possible), otherwise objc_retain
-OBJC_EXPORT
-id
-objc_retainAutoreleasedReturnValue(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT Class _Nullable
+objc_opt_class(id _Nullable obj)
+ OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
-OBJC_EXPORT
-void
-objc_storeStrong(id *location, id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT BOOL
+objc_opt_respondsToSelector(id _Nullable obj, SEL _Nullable sel)
+ OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
-OBJC_EXPORT
-id
-objc_retainAutorelease(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT BOOL
+objc_opt_isKindOfClass(id _Nullable obj, Class _Nullable cls)
+ OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
-// obsolete.
-OBJC_EXPORT id objc_retain_autorelease(id obj)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
-OBJC_EXPORT
-id
-objc_loadWeakRetained(id *location)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT BOOL
+objc_sync_try_enter(id _Nonnull obj)
+ OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
-OBJC_EXPORT
-id
-objc_initWeak(id *addr, id val)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT id _Nullable
+objc_retain(id _Nullable obj)
+ __asm__("_objc_retain")
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
-OBJC_EXPORT
-void
-objc_destroyWeak(id *addr)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT void
+objc_release(id _Nullable obj)
+ __asm__("_objc_release")
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
-OBJC_EXPORT
-void
-objc_copyWeak(id *to, id *from)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT id _Nullable
+objc_autorelease(id _Nullable obj)
+ __asm__("_objc_autorelease")
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
-OBJC_EXPORT
-void
-objc_moveWeak(id *to, id *from)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+// Prepare a value at +1 for return through a +0 autoreleasing convention.
+OBJC_EXPORT id _Nullable
+objc_autoreleaseReturnValue(id _Nullable obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+// Prepare a value at +0 for return through a +0 autoreleasing convention.
+OBJC_EXPORT id _Nullable
+objc_retainAutoreleaseReturnValue(id _Nullable obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
-OBJC_EXPORT
-void
+// Accept a value returned through a +0 autoreleasing convention for use at +1.
+OBJC_EXPORT id _Nullable
+objc_retainAutoreleasedReturnValue(id _Nullable obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+// Accept a value returned through a +0 autoreleasing convention for use at +0.
+OBJC_EXPORT id _Nullable
+objc_unsafeClaimAutoreleasedReturnValue(id _Nullable obj)
+ OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);
+
+OBJC_EXPORT void
+objc_storeStrong(id _Nullable * _Nonnull location, id _Nullable obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+OBJC_EXPORT id _Nullable
+objc_retainAutorelease(id _Nullable obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+// obsolete.
+OBJC_EXPORT id _Nullable
+objc_retain_autorelease(id _Nullable obj)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+OBJC_EXPORT id _Nullable
+objc_loadWeakRetained(id _Nullable * _Nonnull location)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+OBJC_EXPORT id _Nullable
+objc_initWeak(id _Nullable * _Nonnull location, id _Nullable val)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+// Like objc_storeWeak, but stores nil if the new object is deallocating
+// or the new object's class does not support weak references.
+// Returns the value stored (either the new object or nil).
+OBJC_EXPORT id _Nullable
+objc_storeWeakOrNil(id _Nullable * _Nonnull location, id _Nullable obj)
+ OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);
+
+// Like objc_initWeak, but stores nil if the new object is deallocating
+// or the new object's class does not support weak references.
+// Returns the value stored (either the new object or nil).
+OBJC_EXPORT id _Nullable
+objc_initWeakOrNil(id _Nullable * _Nonnull location, id _Nullable val)
+ OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0, 2.0);
+
+OBJC_EXPORT void
+objc_destroyWeak(id _Nullable * _Nonnull location)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+OBJC_EXPORT void
+objc_copyWeak(id _Nullable * _Nonnull to, id _Nullable * _Nonnull from)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+OBJC_EXPORT void
+objc_moveWeak(id _Nullable * _Nonnull to, id _Nullable * _Nonnull from)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+
+OBJC_EXPORT void
_objc_autoreleasePoolPrint(void)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
-OBJC_EXPORT BOOL objc_should_deallocate(id object)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT BOOL
+objc_should_deallocate(id _Nonnull object)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
-OBJC_EXPORT void objc_clear_deallocating(id object)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT void
+objc_clear_deallocating(id _Nonnull object)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
// to make CF link for now
-OBJC_EXPORT
-void *
+OBJC_EXPORT void * _Nonnull
_objc_autoreleasePoolPush(void)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+OBJC_EXPORT void
+_objc_autoreleasePoolPop(void * _Nonnull context)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+
+/**
+ * Load a classref, which is a chunk of data containing a class
+ * pointer. May perform initialization and rewrite the classref to
+ * point to a new object, if needed. Returns the loaded Class.
+ *
+ * In particular, if the classref points to a stub class (indicated
+ * by setting the bottom bit of the class pointer to 1), then this
+ * will call the stub's initializer and then replace the classref
+ * value with the value returned by the initializer.
+ *
+ * @param clsref The classref to load.
+ * @return The loaded Class pointer.
+ */
+#if __OBJC2__
+OBJC_EXPORT _Nullable Class
+objc_loadClassref(_Nullable Class * _Nonnull clsref)
+ OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);
+#endif
-OBJC_EXPORT
-void
-_objc_autoreleasePoolPop(void *context)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+// Extra @encode data for XPC, or NULL
+OBJC_EXPORT const char * _Nullable
+_protocol_getMethodTypeEncoding(Protocol * _Nonnull proto, SEL _Nonnull sel,
+ BOOL isRequiredMethod, BOOL isInstanceMethod)
+ OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0, 2.0);
+
+
+/**
+ * Function type for a function that is called when a realized class
+ * is about to be initialized.
+ *
+ * @param context The context pointer the function was registered with.
+ * @param cls The class that's about to be initialized.
+ */
+struct mach_header;
+typedef void (*_objc_func_willInitializeClass)(void * _Nullable context, Class _Nonnull cls);
+
+/**
+ * Add a function to be called when a realized class is about to be
+ * initialized. The class can be queried and manipulated using runtime
+ * functions. Don't message it.
+ *
+ * When adding a new function, that function is immediately called with all
+ * realized classes that are already initialized or are in the process
+ * of initialization.
+ *
+ * @param func The function to add.
+ * @param context A context pointer that will be passed to the function when called.
+ */
+#define OBJC_WILLINITIALIZECLASSFUNC_DEFINED 1
+OBJC_EXPORT void _objc_addWillInitializeClassFunc(_objc_func_willInitializeClass _Nonnull func, void * _Nullable context)
+ OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 4.0);
+
+// Replicate the conditionals in objc-config.h for packed isa, indexed isa, and preopt caches
+#if __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__) || \
+ !(!__LP64__ || TARGET_OS_WIN32 || \
+ (TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST && !__arm64__))
+OBJC_EXPORT const uintptr_t _objc_has_weak_formation_callout;
+#define OBJC_WEAK_FORMATION_CALLOUT_DEFINED 1
+#else
+#define OBJC_WEAK_FORMATION_CALLOUT_DEFINED 0
+#endif
+
+#if defined(__arm64__) && TARGET_OS_IOS && !TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST
+#define CONFIG_USE_PREOPT_CACHES 1
+#else
+#define CONFIG_USE_PREOPT_CACHES 0
+#endif
+#if __OBJC2__
+// Helper function for objc4 tests only! Do not call this yourself
+// for any reason ever.
+OBJC_EXPORT void _method_setImplementationRawUnsafe(Method _Nonnull m, IMP _Nonnull imp)
+ OBJC_AVAILABLE(10.16, 14.0, 14.0, 7.0, 5.0);
+#endif
+
// API to only be called by classes that provide their own reference count storage
-OBJC_EXPORT
-void
-_objc_deallocOnMainThreadHelper(void *context)
- __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
+OBJC_EXPORT void
+_objc_deallocOnMainThreadHelper(void * _Nullable context)
+ OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0, 2.0);
+
+#if __OBJC__
+// Declarations for internal methods used for custom weak reference
+// implementations. These declarations ensure that the compiler knows
+// to exclude these methods from NS_DIRECT_MEMBERS. Do NOT implement
+// these methods unless you really know what you're doing.
+@interface NSObject ()
+- (BOOL)_tryRetain;
+- (BOOL)_isDeallocating;
+@end
+#endif
-#define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, _dealloc2main) \
- -(id)retain { \
- /* this will fail to compile if _rc_ivar is an unsigned type */ \
+// On async versus sync deallocation and the _dealloc2main flag
+//
+// Theory:
+//
+// If order matters, then code must always: [self dealloc].
+// If order doesn't matter, then always async should be safe.
+//
+// Practice:
+//
+// The _dealloc2main bit is set for GUI objects that may be retained by other
+// threads. Once deallocation begins on the main thread, doing more async
+// deallocation will at best cause extra UI latency and at worst cause
+// use-after-free bugs in unretained delegate style patterns. Yes, this is
+// extremely fragile. Yes, in the long run, developers should switch to weak
+// references.
+//
+// Note is NOT safe to do any equality check against the result of
+// dispatch_get_current_queue(). The main thread can and does drain more than
+// one dispatch queue. That is why we call pthread_main_np().
+//
+
+typedef enum {
+ _OBJC_RESURRECT_OBJECT = -1, /* _logicBlock has called -retain, and scheduled a -release for later. */
+ _OBJC_DEALLOC_OBJECT_NOW = 1, /* call [self dealloc] immediately. */
+ _OBJC_DEALLOC_OBJECT_LATER = 2 /* call [self dealloc] on the main queue. */
+} _objc_object_disposition_t;
+
+#define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, _logicBlock) \
+ -(id)retain { \
+ /* this will fail to compile if _rc_ivar is an unsigned type */ \
int _retain_count_ivar_must_not_be_unsigned[0L - (__typeof__(_rc_ivar))-1] __attribute__((unused)); \
- __typeof__(_rc_ivar) _prev = __sync_fetch_and_add(&_rc_ivar, 2); \
- if (_prev < 0) { \
- __builtin_trap(); /* BUG: retain of dealloc'ed ref */ \
- } \
- return self; \
- } \
- -(oneway void)release { \
- __typeof__(_rc_ivar) _prev = __sync_fetch_and_sub(&_rc_ivar, 2); \
- if (_prev == 0) { \
- if (__sync_bool_compare_and_swap(&_rc_ivar, -2, 1)) { \
- if (_dealloc2main) { \
- dispatch_barrier_async_f(dispatch_get_main_queue(), \
- self, _objc_deallocOnMainThreadHelper); \
- } else { \
- [self dealloc]; \
- } \
- } else { \
- __builtin_trap(); /* BUG: dangling ref did a retain */ \
- } \
- } else if (_prev < 0) { \
- __builtin_trap(); /* BUG: over-release */ \
- } \
- } \
- -(NSUInteger)retainCount { \
- return (_rc_ivar + 2) >> 1; \
- } \
- -(BOOL)_tryRetain { \
- __typeof__(_rc_ivar) _prev; \
- do { \
- _prev = _rc_ivar; \
- if (_prev & 1) { \
- return 0; \
- } else if (_prev == -2) { \
- return 0; \
- } else if (_prev < -2) { \
- __builtin_trap(); /* BUG: over-release elsewhere */ \
- } \
+ __typeof__(_rc_ivar) _prev = __sync_fetch_and_add(&_rc_ivar, 2); \
+ if (_prev < -2) { /* specifically allow resurrection from logical 0. */ \
+ __builtin_trap(); /* BUG: retain of over-released ref */ \
+ } \
+ return self; \
+ } \
+ -(oneway void)release { \
+ __typeof__(_rc_ivar) _prev = __sync_fetch_and_sub(&_rc_ivar, 2); \
+ if (_prev > 0) { \
+ return; \
+ } else if (_prev < 0) { \
+ __builtin_trap(); /* BUG: over-release */ \
+ } \
+ _objc_object_disposition_t fate = _logicBlock(self); \
+ if (fate == _OBJC_RESURRECT_OBJECT) { \
+ return; \
+ } \
+ /* mark the object as deallocating. */ \
+ if (!__sync_bool_compare_and_swap(&_rc_ivar, -2, 1)) { \
+ __builtin_trap(); /* BUG: dangling ref did a retain */ \
+ } \
+ if (fate == _OBJC_DEALLOC_OBJECT_NOW) { \
+ [self dealloc]; \
+ } else if (fate == _OBJC_DEALLOC_OBJECT_LATER) { \
+ dispatch_barrier_async_f(dispatch_get_main_queue(), self, \
+ _objc_deallocOnMainThreadHelper); \
+ } else { \
+ __builtin_trap(); /* BUG: bogus fate value */ \
+ } \
+ } \
+ -(NSUInteger)retainCount { \
+ return (NSUInteger)(_rc_ivar + 2) >> 1; \
+ } \
+ -(BOOL)_tryRetain { \
+ __typeof__(_rc_ivar) _prev; \
+ do { \
+ _prev = _rc_ivar; \
+ if (_prev & 1) { \
+ return 0; \
+ } else if (_prev == -2) { \
+ return 0; \
+ } else if (_prev < -2) { \
+ __builtin_trap(); /* BUG: over-release elsewhere */ \
+ } \
} while ( ! __sync_bool_compare_and_swap(&_rc_ivar, _prev, _prev + 2)); \
- return 1; \
- } \
- -(BOOL)_isDeallocating { \
- if (_rc_ivar == -2) { \
- return 1; \
- } else if (_rc_ivar < -2) { \
- __builtin_trap(); /* BUG: over-release elsewhere */ \
- } \
- return _rc_ivar & 1; \
+ return 1; \
+ } \
+ -(BOOL)_isDeallocating { \
+ if (_rc_ivar == -2) { \
+ return 1; \
+ } else if (_rc_ivar < -2) { \
+ __builtin_trap(); /* BUG: over-release elsewhere */ \
+ } \
+ return (_rc_ivar & 1) != 0; \
}
+#define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, _dealloc2main) \
+ _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, (^(id _self_ __attribute__((unused))) { \
+ if ((_dealloc2main) && !pthread_main_np()) { \
+ return _OBJC_DEALLOC_OBJECT_LATER; \
+ } else { \
+ return _OBJC_DEALLOC_OBJECT_NOW; \
+ } \
+ }))
+
#define _OBJC_SUPPORTED_INLINE_REFCNT(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 0)
#define _OBJC_SUPPORTED_INLINE_REFCNT_WITH_DEALLOC2MAIN(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 1)
+
+// C cache_t wrappers for objcdt and the IMP caches test tool
+struct cache_t;
+struct bucket_t;
+struct preopt_cache_t;
+OBJC_EXPORT struct bucket_t * _Nonnull objc_cache_buckets(const struct cache_t * _Nonnull cache);
+OBJC_EXPORT size_t objc_cache_bytesForCapacity(uint32_t cap);
+OBJC_EXPORT uint32_t objc_cache_occupied(const struct cache_t * _Nonnull cache);
+OBJC_EXPORT unsigned objc_cache_capacity(const struct cache_t * _Nonnull cache);
+
+#if CONFIG_USE_PREOPT_CACHES
+
+OBJC_EXPORT bool objc_cache_isConstantOptimizedCache(const struct cache_t * _Nonnull cache, bool strict, uintptr_t empty_addr);
+OBJC_EXPORT unsigned objc_cache_preoptCapacity(const struct cache_t * _Nonnull cache);
+OBJC_EXPORT Class _Nonnull objc_cache_preoptFallbackClass(const struct cache_t * _Nonnull cache);
+OBJC_EXPORT const struct preopt_cache_t * _Nonnull objc_cache_preoptCache(const struct cache_t * _Nonnull cache);
+
+#endif
+
__END_DECLS
#endif