objc-runtime-new.h [plain text]
#ifndef _OBJC_RUNTIME_NEW_H
#define _OBJC_RUNTIME_NEW_H
__BEGIN_DECLS
#if __LP64__
typedef uint32_t mask_t; #else
typedef uint16_t mask_t;
#endif
typedef uintptr_t cache_key_t;
struct swift_class_t;
struct bucket_t {
private:
cache_key_t _key;
IMP _imp;
public:
inline cache_key_t key() const { return _key; }
inline IMP imp() const { return (IMP)_imp; }
inline void setKey(cache_key_t newKey) { _key = newKey; }
inline void setImp(IMP newImp) { _imp = newImp; }
void set(cache_key_t newKey, IMP newImp);
};
struct cache_t {
struct bucket_t *_buckets;
mask_t _mask;
mask_t _occupied;
public:
struct bucket_t *buckets();
mask_t mask();
mask_t occupied();
void incrementOccupied();
void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
void setEmpty();
mask_t capacity();
bool canBeFreed();
static size_t bytesForCapacity(uint32_t cap);
static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);
void expand();
void reallocate(mask_t oldCapacity, mask_t newCapacity);
struct bucket_t * find(cache_key_t key);
static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn));
};
typedef struct classref * classref_t;
struct method_t {
SEL name;
const char *types;
IMP imp;
struct SortBySELAddress :
public std::binary_function<const method_t&,
const method_t&, bool>
{
bool operator() (const method_t& lhs,
const method_t& rhs)
{ return lhs.name < rhs.name; }
};
};
struct method_list_t {
uint32_t entsize_NEVER_USE; uint32_t count;
method_t first;
uint32_t getEntsize() const {
return entsize_NEVER_USE & ~(uint32_t)3;
}
uint32_t getCount() const {
return count;
}
method_t& getOrEnd(uint32_t i) const {
assert(i <= count);
return *(method_t *)((uint8_t *)&first + i*getEntsize());
}
method_t& get(uint32_t i) const {
assert(i < count);
return getOrEnd(i);
}
struct method_iterator {
uint32_t entsize;
uint32_t index; method_t* method;
typedef std::random_access_iterator_tag iterator_category;
typedef method_t value_type;
typedef ptrdiff_t difference_type;
typedef method_t* pointer;
typedef method_t& reference;
method_iterator() { }
method_iterator(const method_list_t& mlist, uint32_t start = 0)
: entsize(mlist.getEntsize())
, index(start)
, method(&mlist.getOrEnd(start))
{ }
const method_iterator& operator += (ptrdiff_t delta) {
method = (method_t*)((uint8_t *)method + delta*entsize);
index += (int32_t)delta;
return *this;
}
const method_iterator& operator -= (ptrdiff_t delta) {
method = (method_t*)((uint8_t *)method - delta*entsize);
index -= (int32_t)delta;
return *this;
}
const method_iterator operator + (ptrdiff_t delta) const {
return method_iterator(*this) += delta;
}
const method_iterator operator - (ptrdiff_t delta) const {
return method_iterator(*this) -= delta;
}
method_iterator& operator ++ () { *this += 1; return *this; }
method_iterator& operator -- () { *this -= 1; return *this; }
method_iterator operator ++ (int) {
method_iterator result(*this); *this += 1; return result;
}
method_iterator operator -- (int) {
method_iterator result(*this); *this -= 1; return result;
}
ptrdiff_t operator - (const method_iterator& rhs) const {
return (ptrdiff_t)this->index - (ptrdiff_t)rhs.index;
}
method_t& operator * () const { return *method; }
method_t* operator -> () const { return method; }
operator method_t& () const { return *method; }
bool operator == (const method_iterator& rhs) {
return this->method == rhs.method;
}
bool operator != (const method_iterator& rhs) {
return this->method != rhs.method;
}
bool operator < (const method_iterator& rhs) {
return this->method < rhs.method;
}
bool operator > (const method_iterator& rhs) {
return this->method > rhs.method;
}
};
method_iterator begin() const { return method_iterator(*this, 0); }
method_iterator end() const { return method_iterator(*this, getCount()); }
};
struct ivar_t {
#if __x86_64__
#endif
int32_t *offset;
const char *name;
const char *type;
uint32_t alignment_raw;
uint32_t size;
uint32_t alignment() {
if (alignment_raw == ~(uint32_t)0) return 1U << WORD_SHIFT;
return 1 << alignment_raw;
}
};
struct ivar_list_t {
uint32_t entsize;
uint32_t count;
ivar_t first;
};
struct property_t {
const char *name;
const char *attributes;
};
struct property_list_t {
uint32_t entsize;
uint32_t count;
property_t first;
};
typedef uintptr_t protocol_ref_t;
#define PROTOCOL_FIXED_UP (1<<31) // must never be set by compiler
struct protocol_t : objc_object {
const char *mangledName;
struct protocol_list_t *protocols;
method_list_t *instanceMethods;
method_list_t *classMethods;
method_list_t *optionalInstanceMethods;
method_list_t *optionalClassMethods;
property_list_t *instanceProperties;
uint32_t size; uint32_t flags;
const char **extendedMethodTypes;
const char *_demangledName;
const char *demangledName();
const char *nameForLogging() {
return demangledName();
}
bool isFixedUp() const {
return flags & PROTOCOL_FIXED_UP;
}
bool hasExtendedMethodTypesField() const {
return size >= (offsetof(protocol_t, extendedMethodTypes)
+ sizeof(extendedMethodTypes));
}
bool hasExtendedMethodTypes() const {
return hasExtendedMethodTypesField() && extendedMethodTypes;
}
};
struct protocol_list_t {
uintptr_t count;
protocol_ref_t list[0]; };
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
const method_list_t * baseMethods;
const protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
const property_list_t *baseProperties;
};
struct class_rw_t {
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
union {
method_list_t **method_lists; method_list_t *method_list; };
struct chained_property_list *properties;
const protocol_list_t ** protocols;
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
void setFlags(uint32_t set)
{
OSAtomicOr32Barrier(set, &flags);
}
void clearFlags(uint32_t clear)
{
OSAtomicXor32Barrier(clear, &flags);
}
void changeFlags(uint32_t set, uint32_t clear)
{
assert((set & clear) == 0);
uint32_t oldf, newf;
do {
oldf = flags;
newf = (oldf | set) & ~clear;
} while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));
}
};
#define RO_META (1<<0)
#define RO_ROOT (1<<1)
#define RO_HAS_CXX_STRUCTORS (1<<2)
#define RO_HIDDEN (1<<4)
#define RO_EXCEPTION (1<<5)
#define RO_IS_ARR (1<<7)
#define RO_HAS_CXX_DTOR_ONLY (1<<8)
#define RO_FROM_BUNDLE (1<<29)
#define RO_FUTURE (1<<30)
#define RO_REALIZED (1<<31)
#define RW_REALIZED (1<<31)
#define RW_FUTURE (1<<30)
#define RW_INITIALIZED (1<<29)
#define RW_INITIALIZING (1<<28)
#define RW_COPIED_RO (1<<27)
#define RW_CONSTRUCTING (1<<26)
#define RW_CONSTRUCTED (1<<25)
#define RW_FINALIZE_ON_MAIN_THREAD (1<<24)
#define RW_LOADED (1<<23)
#if !SUPPORT_NONPOINTER_ISA
#define RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS (1<<22)
#endif
#define RW_HAS_INSTANCE_SPECIFIC_LAYOUT (1 << 21)
#define RW_METHOD_ARRAY (1<<20)
#define RW_REALIZING (1<<19)
#if !__LP64__
#define RW_HAS_CXX_CTOR (1<<18)
#define RW_HAS_CXX_DTOR (1<<17)
#define RW_HAS_DEFAULT_AWZ (1<<16)
#define FAST_IS_SWIFT (1UL<<0)
#define FAST_HAS_DEFAULT_RR (1UL<<1)
#define FAST_DATA_MASK 0xfffffffcUL
#elif 1
#define RW_HAS_CXX_CTOR (1<<18)
#define RW_HAS_CXX_DTOR (1<<17)
#define RW_HAS_DEFAULT_AWZ (1<<16)
#define FAST_IS_SWIFT (1UL<<0)
#define FAST_HAS_DEFAULT_RR (1UL<<1)
#define FAST_REQUIRES_RAW_ISA (1UL<<2)
#define FAST_DATA_MASK 0x00007ffffffffff8UL
#else
#define FAST_IS_SWIFT (1UL<<0)
#define FAST_REQUIRES_RAW_ISA (1UL<<1)
#define FAST_HAS_CXX_DTOR (1UL<<2)
#define FAST_DATA_MASK 0x00007ffffffffff8UL
#define FAST_HAS_CXX_CTOR (1UL<<47)
#define FAST_HAS_DEFAULT_AWZ (1UL<<48)
#define FAST_HAS_DEFAULT_RR (1UL<<49)
#define FAST_ALLOC (1UL<<50)
#define FAST_SHIFTED_SIZE_SHIFT 51
#define FAST_ALLOC_MASK (FAST_HAS_CXX_CTOR | FAST_REQUIRES_RAW_ISA)
#define FAST_ALLOC_VALUE (0)
#endif
struct class_data_bits_t {
uintptr_t bits;
private:
bool getBit(uintptr_t bit)
{
return bits & bit;
}
#if FAST_ALLOC
static uintptr_t updateFastAlloc(uintptr_t oldBits, uintptr_t change)
{
if (change & FAST_ALLOC_MASK) {
if (((oldBits & FAST_ALLOC_MASK) == FAST_ALLOC_VALUE) &&
((oldBits >> FAST_SHIFTED_SIZE_SHIFT) != 0))
{
oldBits |= FAST_ALLOC;
} else {
oldBits &= ~FAST_ALLOC;
}
}
return oldBits;
}
#else
static uintptr_t updateFastAlloc(uintptr_t oldBits, uintptr_t change) {
return oldBits;
}
#endif
void setBits(uintptr_t set)
{
uintptr_t oldBits;
uintptr_t newBits;
do {
oldBits = LoadExclusive(&bits);
newBits = updateFastAlloc(oldBits | set, set);
} while (!StoreReleaseExclusive(&bits, oldBits, newBits));
}
void clearBits(uintptr_t clear)
{
uintptr_t oldBits;
uintptr_t newBits;
do {
oldBits = LoadExclusive(&bits);
newBits = updateFastAlloc(oldBits & ~clear, clear);
} while (!StoreReleaseExclusive(&bits, oldBits, newBits));
}
public:
class_rw_t* data() {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
void setData(class_rw_t *newData)
{
assert(!data() || (newData->flags & (RW_REALIZING | RW_FUTURE)));
bits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
}
bool hasDefaultRR() {
return getBit(FAST_HAS_DEFAULT_RR);
}
void setHasDefaultRR() {
setBits(FAST_HAS_DEFAULT_RR);
}
void setHasCustomRR() {
clearBits(FAST_HAS_DEFAULT_RR);
}
#if FAST_HAS_DEFAULT_AWZ
bool hasDefaultAWZ() {
return getBit(FAST_HAS_DEFAULT_AWZ);
}
void setHasDefaultAWZ() {
setBits(FAST_HAS_DEFAULT_AWZ);
}
void setHasCustomAWZ() {
clearBits(FAST_HAS_DEFAULT_AWZ);
}
#else
bool hasDefaultAWZ() {
return data()->flags & RW_HAS_DEFAULT_AWZ;
}
void setHasDefaultAWZ() {
data()->setFlags(RW_HAS_DEFAULT_AWZ);
}
void setHasCustomAWZ() {
data()->clearFlags(RW_HAS_DEFAULT_AWZ);
}
#endif
#if FAST_HAS_CXX_CTOR
bool hasCxxCtor() {
return getBit(FAST_HAS_CXX_CTOR);
}
void setHasCxxCtor() {
setBits(FAST_HAS_CXX_CTOR);
}
#else
bool hasCxxCtor() {
return data()->flags & RW_HAS_CXX_CTOR;
}
void setHasCxxCtor() {
data()->setFlags(RW_HAS_CXX_CTOR);
}
#endif
#if FAST_HAS_CXX_DTOR
bool hasCxxDtor() {
return getBit(FAST_HAS_CXX_DTOR);
}
void setHasCxxDtor() {
setBits(FAST_HAS_CXX_DTOR);
}
#else
bool hasCxxDtor() {
return data()->flags & RW_HAS_CXX_DTOR;
}
void setHasCxxDtor() {
data()->setFlags(RW_HAS_CXX_DTOR);
}
#endif
#if FAST_REQUIRES_RAW_ISA
bool requiresRawIsa() {
return getBit(FAST_REQUIRES_RAW_ISA);
}
void setRequiresRawIsa() {
setBits(FAST_REQUIRES_RAW_ISA);
}
#else
# if SUPPORT_NONPOINTER_ISA
# error oops
# endif
bool requiresRawIsa() {
return true;
}
void setRequiresRawIsa() {
}
#endif
#if FAST_ALLOC
size_t fastInstanceSize()
{
assert(bits & FAST_ALLOC);
return (bits >> FAST_SHIFTED_SIZE_SHIFT) * 16;
}
void setFastInstanceSize(size_t newSize)
{
assert(data()->flags & RW_REALIZING);
newSize = ((newSize + 15) & ~15) / 16;
uintptr_t newBits = newSize << FAST_SHIFTED_SIZE_SHIFT;
if ((newBits >> FAST_SHIFTED_SIZE_SHIFT) == newSize) {
int shift = WORD_BITS - FAST_SHIFTED_SIZE_SHIFT;
uintptr_t oldBits = (bits << shift) >> shift;
if ((oldBits & FAST_ALLOC_MASK) == FAST_ALLOC_VALUE) {
newBits |= FAST_ALLOC;
}
bits = oldBits | newBits;
}
}
bool canAllocFast() {
return bits & FAST_ALLOC;
}
#else
size_t fastInstanceSize() {
abort();
}
void setFastInstanceSize(size_t) {
}
bool canAllocFast() {
return false;
}
#endif
bool isSwift() {
return getBit(FAST_IS_SWIFT);
}
void setIsSwift() {
setBits(FAST_IS_SWIFT);
}
};
struct objc_class : objc_object {
Class superclass;
cache_t cache; class_data_bits_t bits;
class_rw_t *data() {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
void setInfo(uint32_t set) {
assert(isFuture() || isRealized());
data()->setFlags(set);
}
void clearInfo(uint32_t clear) {
assert(isFuture() || isRealized());
data()->clearFlags(clear);
}
void changeInfo(uint32_t set, uint32_t clear) {
assert(isFuture() || isRealized());
assert((set & clear) == 0);
data()->changeFlags(set, clear);
}
bool hasCustomRR() {
return ! bits.hasDefaultRR();
}
void setHasDefaultRR() {
assert(isInitializing());
bits.setHasDefaultRR();
}
void setHasCustomRR(bool inherited = false);
void printCustomRR(bool inherited);
bool hasCustomAWZ() {
return ! bits.hasDefaultAWZ();
}
void setHasDefaultAWZ() {
assert(isInitializing());
bits.setHasDefaultAWZ();
}
void setHasCustomAWZ(bool inherited = false);
void printCustomAWZ(bool inherited);
bool requiresRawIsa() {
return bits.requiresRawIsa();
}
void setRequiresRawIsa(bool inherited = false);
void printRequiresRawIsa(bool inherited);
bool canAllocIndexed() {
return !requiresRawIsa();
}
bool canAllocFast() {
return bits.canAllocFast();
}
bool hasCxxCtor() {
assert(isRealized());
return bits.hasCxxCtor();
}
void setHasCxxCtor() {
bits.setHasCxxCtor();
}
bool hasCxxDtor() {
assert(isRealized());
return bits.hasCxxDtor();
}
void setHasCxxDtor() {
bits.setHasCxxDtor();
}
bool isSwift() {
return bits.isSwift();
}
#if SUPPORT_NONPOINTER_ISA
#else
bool instancesHaveAssociatedObjects() {
assert(isFuture() || isRealized());
return data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS;
}
void setInstancesHaveAssociatedObjects() {
assert(isFuture() || isRealized());
setInfo(RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
}
#endif
bool shouldGrowCache() {
return true;
}
void setShouldGrowCache(bool) {
}
bool shouldFinalizeOnMainThread() {
assert(isRealized());
return data()->flags & RW_FINALIZE_ON_MAIN_THREAD;
}
void setShouldFinalizeOnMainThread() {
assert(isRealized());
setInfo(RW_FINALIZE_ON_MAIN_THREAD);
}
bool isInitializing() {
return getMeta()->data()->flags & RW_INITIALIZING;
}
void setInitializing() {
assert(!isMetaClass());
ISA()->setInfo(RW_INITIALIZING);
}
bool isInitialized() {
return getMeta()->data()->flags & RW_INITIALIZED;
}
void setInitialized();
bool isLoadable() {
assert(isRealized());
return true; }
IMP getLoadMethod();
bool isRealized() {
return data()->flags & RW_REALIZED;
}
bool isFuture() {
return data()->flags & RW_FUTURE;
}
bool isMetaClass() {
assert(this);
assert(isRealized());
return data()->ro->flags & RO_META;
}
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
bool isRootClass() {
return superclass == nil;
}
bool isRootMetaclass() {
return ISA() == (Class)this;
}
const char *mangledName() {
assert(this);
if (isRealized() || isFuture()) {
return data()->ro->name;
} else {
return ((const class_ro_t *)data())->name;
}
}
const char *demangledName(bool realize = false);
const char *nameForLogging();
uint32_t unalignedInstanceSize() {
assert(isRealized());
return data()->ro->instanceSize;
}
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
if (size < 16) size = 16;
return size;
}
void setInstanceSize(uint32_t newSize) {
assert(isRealized());
if (newSize != data()->ro->instanceSize) {
assert(data()->flags & RW_COPIED_RO);
*const_cast<uint32_t *>(&data()->ro->instanceSize) = newSize;
}
bits.setFastInstanceSize(newSize);
}
};
struct swift_class_t : objc_class {
uint32_t flags;
uint32_t instanceAddressOffset;
uint32_t instanceSize;
uint16_t instanceAlignMask;
uint16_t reserved;
uint32_t classSize;
uint32_t classAddressOffset;
void *description;
void *baseAddress() {
return (void *)((uint8_t *)this - classAddressOffset);
}
};
struct category_t {
const char *name;
classref_t cls;
struct method_list_t *instanceMethods;
struct method_list_t *classMethods;
struct protocol_list_t *protocols;
struct property_list_t *instanceProperties;
};
struct objc_super2 {
id receiver;
Class current_class;
};
struct message_ref_t {
IMP imp;
SEL sel;
};
extern Method protocol_getMethod(protocol_t *p, SEL sel, bool isRequiredMethod, bool isInstanceMethod, bool recursive);
static inline void
foreach_realized_class_and_subclass_2(Class top, bool (^code)(Class))
{
assert(top);
Class cls = top;
while (1) {
if (!code(cls)) break;
if (cls->data()->firstSubclass) {
cls = cls->data()->firstSubclass;
} else {
while (!cls->data()->nextSiblingClass && cls != top) {
cls = cls->superclass;
}
if (cls == top) break;
cls = cls->data()->nextSiblingClass;
}
}
}
static inline void
foreach_realized_class_and_subclass(Class top, void (^code)(Class))
{
foreach_realized_class_and_subclass_2(top, ^bool(Class cls) {
code(cls); return true;
});
}
__END_DECLS
#endif