ro_or_rw_ext 会有两种类型,class_rw_ext_t或者class_ro_t类型?objc_class类的定义,本篇文章研究bits到底存储了哪些信息struct objc_class : objc_object {// 初始化方法// Class ISA;Class superclass;cache_t cache; // formerly cache pointer and vtableclass_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags// 其他方法
}
class_data_bits_t结构中struct class_data_bits_t {friend objc_class;uintptr_t bits;// 省略方法
}
public方法class_rw_t* data() const {return (class_rw_t *)(bits & FAST_DATA_MASK);
}
void setData(class_rw_t *newData)
{ASSERT(!data() || (newData->flags & (RW_REALIZING | RW_FUTURE)));// Set during realization or construction only. No locking needed.// Use a store-release fence because there may be concurrent// readers of data and data's contents.uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;atomic_thread_fence(memory_order_release);bits = newBits;
}
data()的方法,这里面应该存储了某些数据,进入返回的类型class_rw_tstruct class_rw_t {// Be warned that Symbolication knows the layout of this structure.uint32_t flags;uint16_t witness;
#if SUPPORT_INDEXED_ISAuint16_t index;
#endif// ro_or_rw_ext 会有两种情况:// 1. 编译时值是 class_ro_t *// 2. class_rw_ext_t *,编译时的 class_ro_t * 作为 class_rw_ext_t 的 const class_ro_t *ro 成员变量保存explicit_atomic ro_or_rw_ext;Class firstSubclass;Class nextSiblingClass;private:// 省略私有方法public:// 省略部分方法const method_array_t methods() const {auto v = get_ro_or_rwe();if (v.is()) {return v.get(&ro_or_rw_ext)->methods;} else {return method_array_t{v.get(&ro_or_rw_ext)->baseMethods()};}}const property_array_t properties() const {auto v = get_ro_or_rwe();if (v.is()) {return v.get(&ro_or_rw_ext)->properties;} else {return property_array_t{v.get(&ro_or_rw_ext)->baseProperties};}}const protocol_array_t protocols() const {auto v = get_ro_or_rwe();if (v.is()) {return v.get(&ro_or_rw_ext)->protocols;} else {return protocol_array_t{v.get(&ro_or_rw_ext)->baseProtocols};}}
};
class_rw_t是一个结构体,提供了获取属性列表、方法列表、协议列表的方法。private里面的内容:private:using ro_or_rw_ext_t = objc::PointerUnion;const ro_or_rw_ext_t get_ro_or_rwe() const {return ro_or_rw_ext_t{ro_or_rw_ext};}void set_ro_or_rwe(const class_ro_t *ro) {ro_or_rw_ext_t{ro, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_relaxed);}void set_ro_or_rwe(class_rw_ext_t *rwe, const class_ro_t *ro) {// the release barrier is so that the class_rw_ext_t::ro initialization// is visible to lockless readersrwe->ro = ro;ro_or_rw_ext_t{rwe, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_release);}class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false);
使用 using 关键字声明一个 ro_or_rw_ext_t 类型为: objc::PointerUnion<**const** class_ro_t, class_rw_ext_t)>;
这里可以简单理解为一个指针联合体,系统只为其分配一个指针的内存空间,一次只能保存 class_ro_t 指针或者 class_rw_ext_t 指针
接着我们看一下public里面的主要方法,它大致分为下面几类
class_rw_ext_t或者class_ro_tusing关键字申明了ro_or_rw_ext_t类型,它的具体类型是一个PointerUnion模版类template
class PointerUnion {// 仅有一个成员变量 _valueuintptr_t _value;static_assert(alignof(T1) >= 2, "alignment requirement");static_assert(alignof(T2) >= 2, "alignment requirement");struct IsPT1 {static const uintptr_t Num = 0;};struct IsPT2 {static const uintptr_t Num = 1;};template struct UNION_DOESNT_CONTAIN_TYPE {};uintptr_t getPointer() const {return _value & ~1;}uintptr_t getTag() const {return _value & 1;}public:explicit PointerUnion(const std::atomic &raw): _value(raw.load(std::memory_order_relaxed)){ }PointerUnion(T1 *t, const void *address) {_value = (uintptr_t)Auth1::sign(t, address);}PointerUnion(T2 *t, const void *address) {_value = (uintptr_t)Auth2::sign(t, address) | 1;}void storeAt(std::atomic &raw, std::memory_order order) const {raw.store(_value, order);}template bool is() const {using Ty = typename PointerUnionTypeSelector>>::Return;return getTag() == Ty::Num;}template T get(const void *address) const {ASSERT(is() && "Invalid accessor called");using AuthT = typename PointerUnionTypeSelector>>::Return;return AuthT::auth((T)getPointer(), address);}template T dyn_cast(const void *address) const {if (is())return get(address);return T();}
};
using ro_or_rw_ext_t = objc::PointerUnion; 对应到模版类中T1:const class_ro_t类型,T2:class_rw_ext_t类型_valueconst class_ro_t 或 class_rw_ext_texplicit PointerUnion(const std::atomic &raw): _value(raw.load(std::memory_order_relaxed)){ }// 初始化T1
PointerUnion(T1 *t, const void *address) {_value = (uintptr_t)Auth1::sign(t, address);
}
// 初始化T2,把_value最后一位设置为1
PointerUnion(T2 *t, const void *address) {_value = (uintptr_t)Auth2::sign(t, address) | 1;
}
// 根据指定的 order 以原子方式把 raw 保存到 _value 中
void storeAt(std::atomic &raw, std::memory_order order) const {raw.store(_value, order);
}// 获取指针 class_ro_t 或者 class_rw_ext_t 指针
template T get(const void *address) const {ASSERT(is() && "Invalid accessor called");using AuthT = typename PointerUnionTypeSelector>>::Return;return AuthT::auth((T)getPointer(), address);
}// get 函数中如果当前 _value 类型和 T 不匹配的话,强制转换会返回错误类型的指针
// dyn_cast 则始终都返回 T 类型的指针
template T dyn_cast(const void *address) const {if (is())return get(address);return T();
}
// 定义结构体 IsPT1,内部仅有一个静态不可变 uintptr_t 类型的值为 0 的 Num。
//(用于 _value 的类型判断, 表示此时是 class_ro_t *)
struct IsPT1 {static const uintptr_t Num = 0;
};// 定义结构体 IsPT2,内部仅有一个静态不可变 uintptr_t 类型的值为 1 的 Num。
//(用于 _value 的类型判断,表示此时是 class_rw_ext_t *)
struct IsPT2 {static const uintptr_t Num = 1;
};// 来判断_value类型
template
bool is() const {using Ty = typename PointerUnionTypeSelector>>::Return;return getTag() == Ty::Num;
}
is()方法来判断,ro_or_rw_ext 当前是 class_rw_ext_t 还是 class_ro_t// 从 ro_or_rw_ext 中取得 class_rw_ext_t 指针
class_rw_ext_t *ext() const {return get_ro_or_rwe().dyn_cast(&ro_or_rw_ext);
}/*
由 class_ro_t 构建一个 class_rw_ext_t。如果 ro_or_rw_ext 已经是 class_rw_ext_t 指针了,则直接返回,如果 ro_or_rw_ext 是 class_ro_t 指针的话,根据 class_ro_t 的值构建 class_rw_ext_t 并把它的地址赋值给 class_rw_t 的 ro_or_rw_ext,
*/
class_rw_ext_t *extAllocIfNeeded() {auto v = get_ro_or_rwe();if (fastpath(v.is())) {// 直接返回 class_rw_ext_t 指针return v.get(&ro_or_rw_ext);} else {// 构建 class_rw_ext_t return extAlloc(v.get(&ro_or_rw_ext));}
}class_rw_ext_t *deepCopy(const class_ro_t *ro) {return extAlloc(ro, true);
}
// 从 ro_or_rw_ext 中取得 class_ro_t 指针,
const class_ro_t *ro() const {auto v = get_ro_or_rwe();if (slowpath(v.is())) {// 如果此时是 class_rw_ext_t 指针,则返回它的 roreturn v.get(&ro_or_rw_ext)->ro;}// 如果此时是 class_ro_t,则直接返回return v.get(&ro_or_rw_ext);
}// 设置ro
void set_ro(const class_ro_t *ro) {auto v = get_ro_or_rwe();if (v.is()) {// 如果 ro_or_rw_ext 中保存的是 class_rw_ext_t 指针,则把 ro 赋值给 class_rw_ext_t 的 const class_ro_t *ro。v.get(&ro_or_rw_ext)->ro = ro;} else {// 如果 ro_or_rw_ext 中保存的是 class_ro_t *ro 的话,直接入参 ro 保存到 ro_or_rw_ext 中。set_ro_or_rwe(ro);}
}
/*
方法列表获取1. class_rw_ext_t 的 method_array_t methods2. class_ro_t 的 method_list_t * baseMethodList 构建的 method_array_t
*/
const method_array_t methods() const {auto v = get_ro_or_rwe();if (v.is()) {return v.get(&ro_or_rw_ext)->methods;} else {return method_array_t{v.get(&ro_or_rw_ext)->baseMethods()};}
}// 属性列表获取(同上)
const property_array_t properties() const {auto v = get_ro_or_rwe();if (v.is()) {return v.get(&ro_or_rw_ext)->properties;} else {return property_array_t{v.get(&ro_or_rw_ext)->baseProperties};}
}// 协议列表获取(同上)
const protocol_array_t protocols() const {auto v = get_ro_or_rwe();if (v.is()) {return v.get(&ro_or_rw_ext)->protocols;} else {return protocol_array_t{v.get(&ro_or_rw_ext)->baseProtocols};}
}
class_rw_t结构中有一个ro_or_rw_ext变量,它可以是class_rw_ext_t类型指针。我们具体看一下它的结构struct class_rw_ext_t {DECLARE_AUTHED_PTR_TEMPLATE(class_ro_t)// 指向class_ro_t的指针class_ro_t_authed_ptr ro;// 方法列表method_array_t methods;// 属性列表property_array_t properties;// 协议列表protocol_array_t protocols;// 所属的类名char *demangledName;// 版本号uint32_t version;
};
class_ro_t的指针class_ro_t结构struct class_ro_t {uint32_t flags;uint32_t instanceStart;uint32_t instanceSize;
#ifdef __LP64__uint32_t reserved;
#endifunion {const uint8_t * ivarLayout;Class nonMetaclass;};// 类名explicit_atomic name;// 实例方法列表WrappedPtr baseMethods;// 协议列表protocol_list_t * baseProtocols;// 成员变量列表const ivar_list_t * ivars;const uint8_t * weakIvarLayout;// 属性列表property_list_t *baseProperties;// 省略方法
};
class_rw_ext_t中看完上面内容是不是有一下疑惑?
ro_or_rw_ext 会有两种类型,class_rw_ext_t或者class_ro_t类型?class_rw_ext_t和class_ro_t都有方法、属性、协议列表,那为什么还需要两个结构存储?有什么区别下面我们一一解答一下上面问题
ro_or_rw_ext 会有两种类型,class_rw_ext_t或者class_ro_t类型?ro_or_rw_ext是class_ro_t指针。class_ro_t是在编译期确定的。
class_rw_t中成员变量ro_or_rw_ext直接指向class_ro_t,省去class_rw_ext_t结构体的数据,减少内存消耗。ro_or_rw_ext是class_rw_ext_t指针。
class_rw_t中成员变量ro_or_rw_ext直接指向class_rw_ext_t,class_rw_ext_t的成员变量ro指向class_ro_tclass_rw_ext_t中存储列表使用是一个继承自list_array_tt的结构,可以理解为一个二维数组,数组中存的是列表。class_ro_t中存储列表使用的是一个普通数组。list_array_tt类型的二维数组中,把整个分类列表插入进去。class_rw_t最主要的作用就是存储了方法、属性、协议列表,以及提供了如何获取相关列表。
下面我们主要研究一下如何获取相关列表,在开始之前,我们需要了解它们的存储方式是如何?
以方法列表为例
const method_array_t methods() const {auto v = get_ro_or_rwe();if (v.is()) {return v.get(&ro_or_rw_ext)->methods;} else {return method_array_t{v.get(&ro_or_rw_ext)->baseMethods()};}
}
method_array_t类型结构class method_array_t : public list_array_tt
list_array_tt结构,所以我们首先看看这个结构,它是如何存储的。template class Ptr>
class list_array_tt {struct array_t {...};
protected:class iterator {...};
private:union {Ptr list;uintptr_t arrayAndFlag;};bool hasArray() const {return arrayAndFlag & 1;}array_t *array() const {return (array_t *)(arrayAndFlag & ~1);}void setArray(array_t *array) {arrayAndFlag = (uintptr_t)array | 1;}void validate() {for (auto cursor = beginLists(), end = endLists(); cursor != end; cursor++)cursor->validate();}
}
list_array_tt是一个模版类 typename Element:基础元数据类型(例如: method_t)typename List:元数据的列表类型(例如: method_list_t)struct array_t {uint32_t count; // count 是 lists 数组中 List * 的数量Ptr lists[0]; // 指针数组,每个元素指向一个列表static size_t byteSize(uint32_t count) {return sizeof(array_t) + count*sizeof(lists[0]);}size_t byteSize() {return byteSize(count);}
};
array_t是一个二维数据结构,里面含有基本的一些数据元素。array_t结构中的二维数组class method_array_t : public list_array_tt
method_list_t类型,进入它的结构struct method_list_t : entsize_list_tt
entsize_list_tt结构,我们看一下这个结构有何作用。template
struct entsize_list_tt {uint32_t entsizeAndFlags;// entsize_list_tt 的容量uint32_t count;// 元素的大小(entry 的大小)uint32_t entsize() const {return entsizeAndFlags & ~FlagMask;}uint32_t flags() const {return entsizeAndFlags & FlagMask;}// 获取对应下标元素Element& getOrEnd(uint32_t i) const { ASSERT(i <= count);return *PointerModifier::modify(*this, (Element *)((uint8_t *)this + sizeof(*this) + i*entsize()));}Element& get(uint32_t i) const { ASSERT(i < count);return getOrEnd(i);}size_t byteSize() const {return byteSize(entsize(), count);}static size_t byteSize(uint32_t entsize, uint32_t count) {return sizeof(entsize_list_tt) + count*entsize;}// 迭代器,用来遍历数组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 {...};
}
entsize_list_tt其实就是一个数组,用来存储编译完成后类的属性,提供了遍历和访问方法。list_array_tt。class method_array_t : public list_array_tt
{typedef list_array_tt Super;public:method_array_t() : Super() { }method_array_t(method_list_t *l) : Super(l) { }const method_list_t_authed_ptr *beginCategoryMethodLists() const {return beginLists();}const method_list_t_authed_ptr *endCategoryMethodLists(Class cls) const;
};
list_array_tt结构,可能是一维数组或者二维数组,所以method_array_t也是按照如下结构存储。method_tstruct method_t {static const uint32_t smallMethodListFlag = 0x80000000;method_t(const method_t &other) = delete;// The representation of a "big" method. This is the traditional// representation of three pointers storing the selector, types// and implementation.struct big {SEL name;const char *types;MethodListIMP imp;};// 省略方法
}
big结构体,里面包含了方法的SEL和impmethod_t结构拿到big,就可以获取到里面的方法。list_array_ttclass property_array_t : public list_array_tt
{typedef list_array_tt Super;public:property_array_t() : Super() { }property_array_t(property_list_t *l) : Super(l) { }
};
property_tstruct property_t {const char *name;const char *attributes;
};
list_array_ttclass protocol_array_t : public list_array_tt
{typedef list_array_tt Super;public:protocol_array_t() : Super() { }protocol_array_t(protocol_list_t *l) : Super(l) { }
};
protocol_ref_ttypedef uintptr_t protocol_ref_t;
bits中存储了属性、方法、协议、成员变量。成员变量只存储在class_ro_t中,它是编译器就决定好的,不可修改。
bits中这些信息,是通过class_rw_t结构存储,它有一个ro_or_rw_ext_t变量,它可以是ro类型,也可能是rw_ext类型。
ro类型rw_ext类型,然后它内部会包含ro。ro是干净内存,类的加载时类本身的数据存放在ro中,编译期决定。
rwe是脏内存,运行时动态创建成员或分类中的成员都在rwe。