+#include "objc-config.h"
+
+/* Isolate ourselves from the definitions of id and Class in the compiler
+ * and public headers.
+ */
+
+#ifdef _OBJC_OBJC_H_
+#error include objc-private.h before other headers
+#endif
+
+#define OBJC_TYPES_DEFINED 1
+#undef OBJC_OLD_DISPATCH_PROTOTYPES
+#define OBJC_OLD_DISPATCH_PROTOTYPES 0
+
+#include <cstddef> // for nullptr_t
+#include <stdint.h>
+#include <assert.h>
+
+// An assert that's disabled for release builds but still ensures the expression compiles.
+#ifdef NDEBUG
+#define ASSERT(x) (void)sizeof(!(x))
+#else
+#define ASSERT(x) assert(x)
+#endif
+
+// `this` is never NULL in C++ unless we encounter UB, but checking for what's impossible
+// is the point of these asserts, so disable the corresponding warning, and let's hope
+// we will reach the assert despite the UB
+#define ASSERT_THIS_NOT_NULL \
+_Pragma("clang diagnostic push") \
+_Pragma("clang diagnostic ignored \"-Wundefined-bool-conversion\"") \
+ASSERT(this) \
+_Pragma("clang diagnostic pop")
+
+
+struct objc_class;
+struct objc_object;
+struct category_t;
+
+typedef struct objc_class *Class;
+typedef struct objc_object *id;
+typedef struct classref *classref_t;
+
+namespace {
+ struct SideTable;
+};
+
+#include "isa.h"
+
+union isa_t {
+ isa_t() { }
+ isa_t(uintptr_t value) : bits(value) { }
+
+ uintptr_t bits;
+
+private:
+ // Accessing the class requires custom ptrauth operations, so
+ // force clients to go through setClass/getClass by making this
+ // private.
+ Class cls;
+
+public:
+#if defined(ISA_BITFIELD)
+ struct {
+ ISA_BITFIELD; // defined in isa.h
+ };
+
+ bool isDeallocating() {
+ return extra_rc == 0 && has_sidetable_rc == 0;
+ }
+ void setDeallocating() {
+ extra_rc = 0;
+ has_sidetable_rc = 0;
+ }
+#endif
+
+ void setClass(Class cls, objc_object *obj);
+ Class getClass(bool authenticated);
+ Class getDecodedClass(bool authenticated);
+};
+
+
+struct objc_object {
+private:
+ isa_t isa;
+
+public:
+
+ // ISA() assumes this is NOT a tagged pointer object
+ Class ISA(bool authenticated = false);
+
+ // rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
+ Class rawISA();
+
+ // getIsa() allows this to be a tagged pointer object
+ Class getIsa();
+
+ uintptr_t isaBits() const;
+
+ // initIsa() should be used to init the isa of new objects only.
+ // If this object already has an isa, use changeIsa() for correctness.
+ // initInstanceIsa(): objects with no custom RR/AWZ
+ // initClassIsa(): class objects
+ // initProtocolIsa(): protocol objects
+ // initIsa(): other objects
+ void initIsa(Class cls /*nonpointer=false*/);
+ void initClassIsa(Class cls /*nonpointer=maybe*/);
+ void initProtocolIsa(Class cls /*nonpointer=maybe*/);
+ void initInstanceIsa(Class cls, bool hasCxxDtor);
+
+ // changeIsa() should be used to change the isa of existing objects.
+ // If this is a new object, use initIsa() for performance.
+ Class changeIsa(Class newCls);
+
+ bool hasNonpointerIsa();
+ bool isTaggedPointer();
+ bool isTaggedPointerOrNil();
+ bool isBasicTaggedPointer();
+ bool isExtTaggedPointer();
+ bool isClass();
+
+ // object may have associated objects?
+ bool hasAssociatedObjects();
+ void setHasAssociatedObjects();
+
+ // object may be weakly referenced?
+ bool isWeaklyReferenced();
+ void setWeaklyReferenced_nolock();
+
+ // object may have -.cxx_destruct implementation?
+ bool hasCxxDtor();
+
+ // Optimized calls to retain/release methods
+ id retain();
+ void release();
+ id autorelease();
+
+ // Implementations of retain/release methods
+ id rootRetain();
+ bool rootRelease();
+ id rootAutorelease();
+ bool rootTryRetain();
+ bool rootReleaseShouldDealloc();
+ uintptr_t rootRetainCount();
+
+ // Implementation of dealloc methods
+ bool rootIsDeallocating();
+ void clearDeallocating();
+ void rootDealloc();
+
+private:
+ void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);
+
+ // Slow paths for inline control
+ id rootAutorelease2();
+ uintptr_t overrelease_error();
+
+#if SUPPORT_NONPOINTER_ISA
+ // Controls what parts of root{Retain,Release} to emit/inline
+ // - Full means the full (slow) implementation
+ // - Fast means the fastpaths only
+ // - FastOrMsgSend means the fastpaths but checking whether we should call
+ // -retain/-release or Swift, for the usage of objc_{retain,release}
+ enum class RRVariant {
+ Full,
+ Fast,
+ FastOrMsgSend,
+ };
+
+ // Unified retain count manipulation for nonpointer isa
+ inline id rootRetain(bool tryRetain, RRVariant variant);
+ inline bool rootRelease(bool performDealloc, RRVariant variant);
+ id rootRetain_overflow(bool tryRetain);
+ uintptr_t rootRelease_underflow(bool performDealloc);
+
+ void clearDeallocating_slow();
+
+ // Side table retain count overflow for nonpointer isa
+ struct SidetableBorrow { size_t borrowed, remaining; };
+
+ void sidetable_lock();
+ void sidetable_unlock();
+
+ void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
+ bool sidetable_addExtraRC_nolock(size_t delta_rc);
+ SidetableBorrow sidetable_subExtraRC_nolock(size_t delta_rc);
+ size_t sidetable_getExtraRC_nolock();
+ void sidetable_clearExtraRC_nolock();
+#endif
+
+ // Side-table-only retain count
+ bool sidetable_isDeallocating();
+ void sidetable_clearDeallocating();
+
+ bool sidetable_isWeaklyReferenced();
+ void sidetable_setWeaklyReferenced_nolock();
+
+ id sidetable_retain(bool locked = false);
+ id sidetable_retain_slow(SideTable& table);
+
+ uintptr_t sidetable_release(bool locked = false, bool performDealloc = true);
+ uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);
+
+ bool sidetable_tryRetain();
+
+ uintptr_t sidetable_retainCount();
+#if DEBUG
+ bool sidetable_present();
+#endif
+};
+
+
+#if __OBJC2__
+typedef struct method_t *Method;
+typedef struct ivar_t *Ivar;
+typedef struct category_t *Category;
+typedef struct property_t *objc_property_t;
+#else
+typedef struct old_method *Method;
+typedef struct old_ivar *Ivar;
+typedef struct old_category *Category;
+typedef struct old_property *objc_property_t;
+#endif
+
+// Public headers