X-Git-Url: https://git.saurik.com/apple/objc4.git/blobdiff_plain/5984afcec0d481527cfed40206070c7feb41f46f..31875a974789e6fabb418ee53dff5e8f10fd8119:/runtime/objc-runtime-new.h diff --git a/runtime/objc-runtime-new.h b/runtime/objc-runtime-new.h index 5825de7..cdea941 100644 --- a/runtime/objc-runtime-new.h +++ b/runtime/objc-runtime-new.h @@ -24,8 +24,6 @@ #ifndef _OBJC_RUNTIME_NEW_H #define _OBJC_RUNTIME_NEW_H -__BEGIN_DECLS - #if __LP64__ typedef uint32_t mask_t; // x86_64 & arm64 asm are less efficient with 16-bits #else @@ -62,9 +60,10 @@ public: mask_t occupied(); void incrementOccupied(); void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask); - void setEmpty(); + void initializeToEmpty(); mask_t capacity(); + bool isConstantEmptyCache(); bool canBeFreed(); static size_t bytesForCapacity(uint32_t cap); @@ -72,7 +71,7 @@ public: void expand(); void reallocate(mask_t oldCapacity, mask_t newCapacity); - struct bucket_t * find(cache_key_t key); + struct bucket_t * find(cache_key_t key, id receiver); static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn)); }; @@ -81,115 +80,143 @@ public: // classref_t is unremapped class_t* typedef struct classref * classref_t; -struct method_t { - SEL name; - const char *types; - IMP imp; - - struct SortBySELAddress : - public std::binary_function - { - bool operator() (const method_t& lhs, - const method_t& rhs) - { return lhs.name < rhs.name; } - }; -}; - -struct method_list_t { - uint32_t entsize_NEVER_USE; // high bits used for fixup markers +/*********************************************************************** +* entsize_list_tt +* Generic implementation of an array of non-fragile structs. +* +* Element is the struct type (e.g. method_t) +* List is the specialization of entsize_list_tt (e.g. method_list_t) +* FlagMask is used to stash extra bits in the entsize field +* (e.g. method list fixup markers) +**********************************************************************/ +template +struct entsize_list_tt { + uint32_t entsizeAndFlags; uint32_t count; - method_t first; + Element first; - uint32_t getEntsize() const { - return entsize_NEVER_USE & ~(uint32_t)3; + uint32_t entsize() const { + return entsizeAndFlags & ~FlagMask; } - uint32_t getCount() const { - return count; + uint32_t flags() const { + return entsizeAndFlags & FlagMask; } - method_t& getOrEnd(uint32_t i) const { + + Element& getOrEnd(uint32_t i) const { assert(i <= count); - return *(method_t *)((uint8_t *)&first + i*getEntsize()); + return *(Element *)((uint8_t *)&first + i*entsize()); } - method_t& get(uint32_t i) const { + Element& get(uint32_t i) const { assert(i < count); return getOrEnd(i); } - // iterate methods, taking entsize into account - // fixme need a proper const_iterator - struct method_iterator { + size_t byteSize() const { + return sizeof(*this) + (count-1)*entsize(); + } + + List *duplicate() const { + return (List *)memdup(this, this->byteSize()); + } + + struct iterator; + const iterator begin() const { + return iterator(*static_cast(this), 0); + } + iterator begin() { + return iterator(*static_cast(this), 0); + } + const iterator end() const { + return iterator(*static_cast(this), count); + } + iterator end() { + return iterator(*static_cast(this), count); + } + + struct iterator { uint32_t entsize; uint32_t index; // keeping track of this saves a divide in operator- - method_t* method; + Element* element; typedef std::random_access_iterator_tag iterator_category; - typedef method_t value_type; + typedef Element value_type; typedef ptrdiff_t difference_type; - typedef method_t* pointer; - typedef method_t& reference; + typedef Element* pointer; + typedef Element& reference; - method_iterator() { } + iterator() { } - method_iterator(const method_list_t& mlist, uint32_t start = 0) - : entsize(mlist.getEntsize()) + iterator(const List& list, uint32_t start = 0) + : entsize(list.entsize()) , index(start) - , method(&mlist.getOrEnd(start)) + , element(&list.getOrEnd(start)) { } - const method_iterator& operator += (ptrdiff_t delta) { - method = (method_t*)((uint8_t *)method + delta*entsize); + const iterator& operator += (ptrdiff_t delta) { + element = (Element*)((uint8_t *)element + delta*entsize); index += (int32_t)delta; return *this; } - const method_iterator& operator -= (ptrdiff_t delta) { - method = (method_t*)((uint8_t *)method - delta*entsize); + const iterator& operator -= (ptrdiff_t delta) { + element = (Element*)((uint8_t *)element - delta*entsize); index -= (int32_t)delta; return *this; } - const method_iterator operator + (ptrdiff_t delta) const { - return method_iterator(*this) += delta; + const iterator operator + (ptrdiff_t delta) const { + return iterator(*this) += delta; } - const method_iterator operator - (ptrdiff_t delta) const { - return method_iterator(*this) -= delta; + const iterator operator - (ptrdiff_t delta) const { + return 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; + iterator& operator ++ () { *this += 1; return *this; } + iterator& operator -- () { *this -= 1; return *this; } + iterator operator ++ (int) { + iterator result(*this); *this += 1; return result; } - method_iterator operator -- (int) { - method_iterator result(*this); *this -= 1; return result; + iterator operator -- (int) { + iterator result(*this); *this -= 1; return result; } - ptrdiff_t operator - (const method_iterator& rhs) const { + ptrdiff_t operator - (const iterator& rhs) const { return (ptrdiff_t)this->index - (ptrdiff_t)rhs.index; } - method_t& operator * () const { return *method; } - method_t* operator -> () const { return method; } + Element& operator * () const { return *element; } + Element* operator -> () const { return element; } - operator method_t& () const { return *method; } + operator Element& () const { return *element; } - bool operator == (const method_iterator& rhs) { - return this->method == rhs.method; + bool operator == (const iterator& rhs) const { + return this->element == rhs.element; } - bool operator != (const method_iterator& rhs) { - return this->method != rhs.method; + bool operator != (const iterator& rhs) const { + return this->element != rhs.element; } - bool operator < (const method_iterator& rhs) { - return this->method < rhs.method; + bool operator < (const iterator& rhs) const { + return this->element < rhs.element; } - bool operator > (const method_iterator& rhs) { - return this->method > rhs.method; + bool operator > (const iterator& rhs) const { + return this->element > rhs.element; } }; +}; - method_iterator begin() const { return method_iterator(*this, 0); } - method_iterator end() const { return method_iterator(*this, getCount()); } +struct method_t { + SEL name; + const char *types; + IMP imp; + + struct SortBySELAddress : + public std::binary_function + { + bool operator() (const method_t& lhs, + const method_t& rhs) + { return lhs.name < rhs.name; } + }; }; struct ivar_t { @@ -208,32 +235,44 @@ struct ivar_t { uint32_t alignment_raw; uint32_t size; - uint32_t alignment() { + uint32_t alignment() const { 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; +// Two bits of entsize are used for fixup markers. +struct method_list_t : entsize_list_tt { + bool isFixedUp() const; + void setFixedUp(); + + uint32_t indexOfMethod(const method_t *meth) const { + uint32_t i = + (uint32_t)(((uintptr_t)meth - (uintptr_t)this) / entsize()); + assert(i < count); + return i; + } +}; + +struct ivar_list_t : entsize_list_tt { }; +struct property_list_t : entsize_list_tt { +}; + + typedef uintptr_t protocol_ref_t; // protocol_t *, but unremapped -#define PROTOCOL_FIXED_UP (1<<31) // must never be set by compiler +// Values for protocol_t->flags +#define PROTOCOL_FIXED_UP_2 (1<<31) // must never be set by compiler +#define PROTOCOL_FIXED_UP_1 (1<<30) // must never be set by compiler + +#define PROTOCOL_FIXED_UP_MASK (PROTOCOL_FIXED_UP_1 | PROTOCOL_FIXED_UP_2) struct protocol_t : objc_object { const char *mangledName; @@ -245,10 +284,8 @@ struct protocol_t : objc_object { property_list_t *instanceProperties; uint32_t size; // sizeof(protocol_t) uint32_t flags; + // Fields below this point are not always present on disk. const char **extendedMethodTypes; - - // Fields below this point are allocated at runtime - // and are not present on disk. const char *_demangledName; const char *demangledName(); @@ -257,9 +294,8 @@ struct protocol_t : objc_object { return demangledName(); } - bool isFixedUp() const { - return flags & PROTOCOL_FIXED_UP; - } + bool isFixedUp() const; + void setFixedUp(); bool hasExtendedMethodTypesField() const { return size >= (offsetof(protocol_t, extendedMethodTypes) @@ -274,66 +310,43 @@ struct protocol_list_t { // count is 64-bit by accident. uintptr_t count; protocol_ref_t list[0]; // variable-size -}; - -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; // RW_METHOD_ARRAY == 1 - method_list_t *method_list; // RW_METHOD_ARRAY == 0 - }; - struct chained_property_list *properties; - const protocol_list_t ** protocols; + size_t byteSize() const { + return sizeof(*this) + count*sizeof(list[0]); + } - Class firstSubclass; - Class nextSiblingClass; + protocol_list_t *duplicate() const { + return (protocol_list_t *)memdup(this, this->byteSize()); + } - char *demangledName; + typedef protocol_ref_t* iterator; + typedef const protocol_ref_t* const_iterator; - void setFlags(uint32_t set) - { - OSAtomicOr32Barrier(set, &flags); + const_iterator begin() const { + return list; } - - void clearFlags(uint32_t clear) - { - OSAtomicXor32Barrier(clear, &flags); + iterator begin() { + return list; + } + const_iterator end() const { + return list + count; } + iterator end() { + return list + count; + } +}; - // set and clear must not overlap - void changeFlags(uint32_t set, uint32_t clear) - { - assert((set & clear) == 0); +struct locstamped_category_t { + category_t *cat; + struct header_info *hi; +}; - uint32_t oldf, newf; - do { - oldf = flags; - newf = (oldf | set) & ~clear; - } while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags)); - } +struct locstamped_category_list_t { + uint32_t count; +#if __LP64__ + uint32_t reserved; +#endif + locstamped_category_t list[0]; }; @@ -395,8 +408,8 @@ struct class_rw_t { #endif // class has instance-specific GC layout #define RW_HAS_INSTANCE_SPECIFIC_LAYOUT (1 << 21) -// class's method list is an array of method lists -#define RW_METHOD_ARRAY (1<<20) +// available for use +// #define RW_20 (1<<20) // class has started realizing but not yet completed it #define RW_REALIZING (1<<19) @@ -489,6 +502,318 @@ struct class_rw_t { #endif +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; + method_list_t * baseMethodList; + protocol_list_t * baseProtocols; + const ivar_list_t * ivars; + + const uint8_t * weakIvarLayout; + property_list_t *baseProperties; + + method_list_t *baseMethods() const { + return baseMethodList; + } +}; + + +/*********************************************************************** +* list_array_tt +* Generic implementation for metadata that can be augmented by categories. +* +* Element is the underlying metadata type (e.g. method_t) +* List is the metadata's list type (e.g. method_list_t) +* +* A list_array_tt has one of three values: +* - empty +* - a pointer to a single list +* - an array of pointers to lists +* +* countLists/beginLists/endLists iterate the metadata lists +* count/begin/end iterate the underlying metadata elements +**********************************************************************/ +template +class list_array_tt { + struct array_t { + uint32_t count; + List* lists[0]; + + static size_t byteSize(uint32_t count) { + return sizeof(array_t) + count*sizeof(lists[0]); + } + size_t byteSize() { + return byteSize(count); + } + }; + + protected: + class iterator { + List **lists; + List **listsEnd; + typename List::iterator m, mEnd; + + public: + iterator(List **begin, List **end) + : lists(begin), listsEnd(end) + { + if (begin != end) { + m = (*begin)->begin(); + mEnd = (*begin)->end(); + } + } + + const Element& operator * () const { + return *m; + } + Element& operator * () { + return *m; + } + + bool operator != (const iterator& rhs) const { + if (lists != rhs.lists) return true; + if (lists == listsEnd) return false; // m is undefined + if (m != rhs.m) return true; + return false; + } + + const iterator& operator ++ () { + assert(m != mEnd); + m++; + if (m == mEnd) { + assert(lists != listsEnd); + lists++; + if (lists != listsEnd) { + m = (*lists)->begin(); + mEnd = (*lists)->end(); + } + } + return *this; + } + }; + + private: + union { + List* list; + uintptr_t arrayAndFlag; + }; + + bool hasArray() const { + return arrayAndFlag & 1; + } + + array_t *array() { + return (array_t *)(arrayAndFlag & ~1); + } + + void setArray(array_t *array) { + arrayAndFlag = (uintptr_t)array | 1; + } + + public: + + uint32_t count() { + uint32_t result = 0; + for (auto lists = beginLists(), end = endLists(); + lists != end; + ++lists) + { + result += (*lists)->count; + } + return result; + } + + iterator begin() { + return iterator(beginLists(), endLists()); + } + + iterator end() { + List **e = endLists(); + return iterator(e, e); + } + + + uint32_t countLists() { + if (hasArray()) { + return array()->count; + } else if (list) { + return 1; + } else { + return 0; + } + } + + List** beginLists() { + if (hasArray()) { + return array()->lists; + } else { + return &list; + } + } + + List** endLists() { + if (hasArray()) { + return array()->lists + array()->count; + } else if (list) { + return &list + 1; + } else { + return &list; + } + } + + void attachLists(List* const * addedLists, uint32_t addedCount) { + if (addedCount == 0) return; + + if (hasArray()) { + // many lists -> many lists + uint32_t oldCount = array()->count; + uint32_t newCount = oldCount + addedCount; + setArray((array_t *)realloc(array(), array_t::byteSize(newCount))); + array()->count = newCount; + memmove(array()->lists + addedCount, array()->lists, + oldCount * sizeof(array()->lists[0])); + memcpy(array()->lists, addedLists, + addedCount * sizeof(array()->lists[0])); + } + else if (!list && addedCount == 1) { + // 0 lists -> 1 list + list = addedLists[0]; + } + else { + // 1 list -> many lists + List* oldList = list; + uint32_t oldCount = oldList ? 1 : 0; + uint32_t newCount = oldCount + addedCount; + setArray((array_t *)malloc(array_t::byteSize(newCount))); + array()->count = newCount; + if (oldList) array()->lists[addedCount] = oldList; + memcpy(array()->lists, addedLists, + addedCount * sizeof(array()->lists[0])); + } + } + + void tryFree() { + if (hasArray()) { + for (uint32_t i = 0; i < array()->count; i++) { + try_free(array()->lists[i]); + } + try_free(array()); + } + else if (list) { + try_free(list); + } + } + + template + Result duplicate() { + Result result; + + if (hasArray()) { + array_t *a = array(); + result.setArray((array_t *)memdup(a, a->byteSize())); + for (uint32_t i = 0; i < a->count; i++) { + result.array()->lists[i] = a->lists[i]->duplicate(); + } + } else if (list) { + result.list = list->duplicate(); + } else { + result.list = nil; + } + + return result; + } +}; + + +class method_array_t : + public list_array_tt +{ + typedef list_array_tt Super; + + public: + method_list_t **beginCategoryMethodLists() { + return beginLists(); + } + + method_list_t **endCategoryMethodLists(Class cls); + + method_array_t duplicate() { + return Super::duplicate(); + } +}; + + +class property_array_t : + public list_array_tt +{ + typedef list_array_tt Super; + + public: + property_array_t duplicate() { + return Super::duplicate(); + } +}; + + +class protocol_array_t : + public list_array_tt +{ + typedef list_array_tt Super; + + public: + protocol_array_t duplicate() { + return Super::duplicate(); + } +}; + + +struct class_rw_t { + uint32_t flags; + uint32_t version; + + const class_ro_t *ro; + + method_array_t methods; + property_array_t properties; + protocol_array_t protocols; + + Class firstSubclass; + Class nextSiblingClass; + + char *demangledName; + + void setFlags(uint32_t set) + { + OSAtomicOr32Barrier(set, &flags); + } + + void clearFlags(uint32_t clear) + { + OSAtomicXor32Barrier(clear, &flags); + } + + // set and clear must not overlap + 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)); + } +}; + + struct class_data_bits_t { // Values are the FAST_ flags above. @@ -741,9 +1066,11 @@ struct objc_class : objc_object { void printRequiresRawIsa(bool inherited); bool canAllocIndexed() { + assert(!isFuture()); return !requiresRawIsa(); } bool canAllocFast() { + assert(!isFuture()); return bits.canAllocFast(); } @@ -927,6 +1254,16 @@ struct category_t { struct method_list_t *classMethods; struct protocol_list_t *protocols; struct property_list_t *instanceProperties; + + method_list_t *methodsForMeta(bool isMeta) { + if (isMeta) return classMethods; + else return instanceMethods; + } + + property_list_t *propertiesForMeta(bool isMeta) { + if (isMeta) return nil; // classProperties; + else return instanceProperties; + } }; struct objc_super2 { @@ -945,7 +1282,7 @@ extern Method protocol_getMethod(protocol_t *p, SEL sel, bool isRequiredMethod, static inline void foreach_realized_class_and_subclass_2(Class top, bool (^code)(Class)) { - // rwlock_assert_writing(&runtimeLock); + // runtimeLock.assertWriting(); assert(top); Class cls = top; while (1) { @@ -971,6 +1308,4 @@ foreach_realized_class_and_subclass(Class top, void (^code)(Class)) }); } -__END_DECLS - #endif