Table of contents
class structure
- A class
Class
is aobjc_class *
type of structure pointer,typedef struct objc_class *Class
- Struct
objc_class
inherits from Structobjc_object
strcut objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
return bits.data()
}
// 省略...
}
objc_object
Contains oneisa
, so each class contains oneisa
, it can be said that everything is an object
strcut objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
}
- Structure
cache_t
part code
struct cache_t {
struct buckrt_t *_buckets;
mask_t _mask;
mask_t _occupied;
// 省略...
}
Attributes, instance methods, protocols, and class method storage
Property list, instance method list, and protocol list are all stored bits
internally
- The way to get the storage location of the attribute list: <similar to instance method/protocol>
bits
Step 1: Calculate the obtained address according to the first address and offset of the class- The second step: through
bits.data()
the obtainedclass_rw_t *
pointera
- Step 3:
a
You can getclass_ro_t *
the pointer of the type through the pointerro
- Step 4:
ro.baseProperties
You can get aproperty_list_t *
type of pointer throughb
- Step 5: Print the pointer
b
, you can see the attribute (property
) list
- In addition,
ro.ivars
you can get aivar_list_t *
type of pointerc
by printing the pointerc
, and we can see the list of variables - By comparing the printed pointer
b
with the pointer , it can be found that the attribute will compile a variable with a variablec
in the variable list_
- The class method is stored in the metaclass, you can get the class object first, then
isa
read the metaclass, and then search the method list in the metaclass according to the above method, you can get the class method list
Relevant structure code implementation
class_rw_t
Code
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;
#if SUPPORT_INDEXED_ISA
uint32_t index;
#elseif
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));
}
};
class_ro_t
Code
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;
}
};
method_array_t
Code
class method_array_t :
public list_array_tt<method_t, method_list_t>
{
typedef list_array_tt<method_t, method_list_t> Super;
public:
method_list_t **beginCategoryMethodLists() {
return beginLists();
}
method_list_t **endCategoryMethodLists(Class cls);
method_array_t duplicate() {
return Super::duplicate<method_array_t>();
}
};
property_array_t
Code
class property_array_t :
public list_array_tt<property_t, property_list_t>
{
typedef list_array_tt<property_t, property_list_t> Super;
public:
property_array_t duplicate() {
return Super::duplicate<property_array_t>();
}
};
protocol_array_t
Code
class protocol_array_t :
public list_array_tt<protocol_ref_t, protocol_list_t>
{
typedef list_array_tt<protocol_ref_t, protocol_list_t> Super;
public:
protocol_array_t duplicate() {
return Super::duplicate<protocol_array_t>();
}
};
list_array_tt
Code
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<typename Result>
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;
}
};