首先从一张图开始说起,这样图是isa
和superclass
的走向图,那真的是这么走的吗?我们就通过代码,来看一下。
isa的走向
@interface LLPerson : NSObject
@end
@interface LLTeacher : LLPerson
@end
首先我们创建两个类,LLPerson
继承自NSObject
,LLTeacher
继承自LLPerson
。
LLPerson *p = [LLPerson new];
Class pClass1 = [p class];
Class pClass2 = [LLPerson class];
Class pClass3 = object_getClass(p); // runtime api
可以通过方法获取LLPerson
的类,我们打印出来:
三种方式都可以获取LLPerson
的类,那Class
是一种什么结构呢?我们通过源码搜索,来看一下Class
的结构。
typedef struct objc_class *Class;
// objc_runtime_new.h
// 继承自objc_object,说明它也是个对象
struct objc_class : objc_object {
......
// Class ISA; // 这个 ISA是继承自objc_object的
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数据
......
}
我们通过源码可以看出Class
是objc_class
的别名,并且objc_class
继承自objc_object
,也就是说objc_class
也是一个对象,我们叫做类对象。并且类对象这个结构体重包含:
isa
指针,指向元类,8
个字节
superclass
指针,指向父类,8
个字节
cache
,缓存,16
个字节
bits
,数据,这里面保存着类的相关数据
接下来,我们通过操作指针,来看一下objc_class
中的isa
是否是实例对象指向的。( x86
架构下的掩码 0x00007ffffffffff8ULL
)
我们通过指针的操作可以看到,实例对象的isa
指向类对象的地址,类对象的isa
指针指向元类对象,并且类对象的名称和元类对象是一致的。那么元类对象的isa
指向哪里呢?我们继续操作
通过打印,我们看出isa
的指向脉络,也就是开头提到的那张图。
实例对象
isa
--> 类对象isa
--> 元类对象isa
-->NSObject
根元类isa
--> 根元类自身
NSObject
类对象isa
-->NSObject
根元类
superclass的走向
下面我们看一下superclass
的走向,先从代码看起:
NSObject *object = [NSObject new];
Class class = object_getClass(object); // NSObejct 类对象
Class metaClass = object_getClass(class); // NSObject元类 根元类
NSLog(@"NSObject实例对象:%p", object);
NSLog(@"NSObject类对象:%p", class);
NSLog(@"NSObject元类对象:%p", metaClass);
// LLPerson
Class pMetaClass = objc_getMetaClass("LLPerson");
Class pSuperclass = class_getSuperclass(pMetaClass);
NSLog(@"LLPerson元类:%@ -- %p", pMetaClass, pMetaClass);
NSLog(@"LLPerson元类的父类:%@ -- %p", pSuperclass, pSuperclass);
我们看打印:
所以元类的父类就是父类的元类。
我们在引入LLTeacher
这个类,它继承自LLPerson
// LLTeacher 继承自LLPerson
Class tMetaClass = objc_getMetaClass("LLTeacher");
Class tSuperclass = class_getSuperclass(tMetaClass);
NSLog(@"LLTeacher元类:%@ -- %p", tMetaClass, tMetaClass);
NSLog(@"LLTeacher元类的父类:%@ -- %p", tSuperclass, tSuperclass);
再次印证了元类的父类就是父类的元类。
那么NSObject
和NSObject
根元类的父类呢?
Class nSuperclass = class_getSuperclass(NSObject.class);
NSLog(@"NSObject的父类:%@ -- %p", nSuperclass, nSuperclass);
Class rnSuperclass = class_getSuperclass(metaClass);
NSLog(@"NSObject根元类的父类:%@ -- %p", rnSuperclass, rnSuperclass);
那么我们的superclass
走向图就一目了然了:
子类
superclass
--> 父类superclass
-->NSObject
superclass
-->
nil
NSObject
根元类superclass
-->NSObject
类对象的存储 class_data_bits_t
接下来我们探索class_data_bits_t
中的数据。我们已经知道objc_class
的结构,那我们就可以通过内存平移来获取class_data_bits_t
中的数据。
首先,我们先在LLPerson
中添加成员变量、属性和方法:
@interface LLPerson : NSObject {
NSString *_hobby;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
- (void)instanceMethod;
+ (void)classMethod;
@end
@implementation LLPerson
- (void)instanceMethod {
NSLog(@"%s", __func__);
}
+ (void)classMethod {
NSLog(@"%s", __func__);
}
@end
添加完之后,我们已知的,LLPerson
类中有3
个成员变量(_hobby
、_name
(属性生成)、_age
(属性生成))、5
个 -
方法(instanceMethod
、setName:
(属性生成)、name
(属性生成)、setAge:
(属性生成)、age
(属性生成))、1
个 +
方法。
在源码中搜索可得class_data_bits_t
的结构:
// objc-runtime-new.h
struct class_data_bits_t {
friend objc_class; // 友元
// Values are the FAST_ flags above.// 值是在FAST_ flags上
uintptr_t bits;
private:
bool getBit(uintptr_t bit) const
{
return bits & bit;
}
// Atomically set the bits in `set` and clear the bits in `clear`.
// set and clear must not overlap. // 自动设置' set '中的位,清除' clear '中的位。Set和clear不得重叠。
void setAndClearBits(uintptr_t set, uintptr_t clear)
{
ASSERT((set & clear) == 0);
uintptr_t newBits, oldBits = LoadExclusive(&bits);
do {
newBits = (oldBits | set) & ~clear;
} while (slowpath(!StoreReleaseExclusive(&bits, &oldBits, newBits)));
}
void setBits(uintptr_t set) {
__c11_atomic_fetch_or((_Atomic(uintptr_t) *)&bits, set, __ATOMIC_RELAXED);
}
void clearBits(uintptr_t clear) {
__c11_atomic_fetch_and((_Atomic(uintptr_t) *)&bits, ~clear, __ATOMIC_RELAXED);
}
public:
// 真正的获取数据的地方 class_rw_t rw数据
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;
}
// Get the class's ro data, even in the presence of concurrent realization.
// fixme this isn't really safe without a compiler barrier at least
// and probably a memory barrier when realizeClass changes the data field
const class_ro_t *safe_ro() const {
class_rw_t *maybe_rw = data();
if (maybe_rw->flags & RW_REALIZED) {
// maybe_rw is rw
return maybe_rw->ro();
} else {
// maybe_rw is actually ro
return (class_ro_t *)maybe_rw;
}
}
#if SUPPORT_INDEXED_ISA
void setClassArrayIndex(unsigned Idx) {
// 0 is unused as then we can rely on zero-initialisation from calloc.
ASSERT(Idx > 0);
data()->index = Idx;
}
#else
void setClassArrayIndex(__unused unsigned Idx) {
}
#endif
unsigned classArrayIndex() {
#if SUPPORT_INDEXED_ISA
return data()->index;
#else
return 0;
#endif
}
bool isAnySwift() {
return isSwiftStable() || isSwiftLegacy();
}
bool isSwiftStable() {
return getBit(FAST_IS_SWIFT_STABLE);
}
void setIsSwiftStable() {
setAndClearBits(FAST_IS_SWIFT_STABLE, FAST_IS_SWIFT_LEGACY);
}
bool isSwiftLegacy() {
return getBit(FAST_IS_SWIFT_LEGACY);
}
void setIsSwiftLegacy() {
setAndClearBits(FAST_IS_SWIFT_LEGACY, FAST_IS_SWIFT_STABLE);
}
// fixme remove this once the Swift runtime uses the stable bits
bool isSwiftStable_ButAllowLegacyForNow() {
return isAnySwift();
}
_objc_swiftMetadataInitializer swiftMetadataInitializer() {
// This function is called on un-realized classes without
// holding any locks.
// Beware of races with other realizers.
return safe_ro()->swiftMetadataInitializer();
}
};
其中我们关注data()
这个方法,它可以得到class_rw_t
这个结构,也就是我们俗称的rw
:
// objc-runtime-new.h
// 真正的rw数据结构
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure. // 请注意,symbolation知道这个结构的布局。
uint32_t flags;
uint16_t witness;
#if SUPPORT_INDEXED_ISA
uint16_t index;
#endif
explicit_atomic<uintptr_t> ro_or_rw_ext;
Class firstSubclass;
Class nextSiblingClass;
private:
using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t, class_rw_ext_t, PTRAUTH_STR("class_ro_t"), PTRAUTH_STR("class_rw_ext_t")>;
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 readers
rwe->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);
public:
void setFlags(uint32_t set)
{
__c11_atomic_fetch_or((_Atomic(uint32_t) *)&flags, set, __ATOMIC_RELAXED);
}
void clearFlags(uint32_t clear)
{
__c11_atomic_fetch_and((_Atomic(uint32_t) *)&flags, ~clear, __ATOMIC_RELAXED);
}
// 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));
}
// 获取rwe的数据
class_rw_ext_t *ext() const {
return get_ro_or_rwe().dyn_cast<class_rw_ext_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<class_rw_ext_t *>(&ro_or_rw_ext);
} else {
return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext));
}
}
class_rw_ext_t *deepCopy(const class_ro_t *ro) {
return extAlloc(ro, true);
}
// 获取ro
const class_ro_t *ro() const {
auto v = get_ro_or_rwe();
if (slowpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
}
return v.get<const class_ro_t *>(&ro_or_rw_ext);
}
void set_ro(const class_ro_t *ro) {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro = ro;
} else {
set_ro_or_rwe(ro);
}
}
// 方法列表
const method_array_t methods() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
} else {
return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods};
}
}
// 属性列表
const property_array_t properties() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
} else {
return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
}
}
// 协议列表
const protocol_array_t protocols() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols;
} else {
return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
}
}
};
在这个结构中,我们就发现了methods()
、properties()
、protocols()
,也就是方法列表、属性列表、协议列表。
那我们先从方法列表开始,通过内存平移获取它:
通过一系列打印,我们获取了方法列表的结构,并且在源码中的形式是:
// objc-runtime-new.h
DECLARE_AUTHED_PTR_TEMPLATE(method_list_t)
// list_array_tt 容器结构
class method_array_t :
public list_array_tt<method_t, method_list_t, method_list_t_authed_ptr>
{
typedef list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> Super;
public:
method_array_t() : Super() { }
method_array_t(method_list_t *l) : Super(l) { }
const method_list_t_authed_ptr<method_list_t> *beginCategoryMethodLists() const {
return beginLists();
}
const method_list_t_authed_ptr<method_list_t> *endCategoryMethodLists(Class cls) const;
};
method_array_t
继承自list_array_tt
这个模板类:
// objc-runtime-new.h
/***********************************************************************
* list_array_tt<Element, List, Ptr>
* Generic implementation for metadata that can be augmented by categories. // 可以通过类别进行扩充的元数据的通用实现。
*
* Element is the underlying metadata type (e.g. method_t) // 元素是底层元数据类型(例如method_t)
* List is the metadata's list type (e.g. method_list_t) // List是元数据的列表类型(例如:method_list_t)
* List is a template applied to Element to make Element*. Useful for
* applying qualifiers to the pointer type. //List是一个应用于Element以生成Element*的模板。适用于对指针类型应用限定符。
*
* A list_array_tt has one of three values: //list_array_tt有以下三个值之一:
* - empty //空
* - a pointer to a single list //指向单个列表的指针
* - an array of pointers to lists //指向列表的指针数组
*
* countLists/beginLists/endLists iterate the metadata lists // countLists/beginLists/endLists迭代元数据列表
* count/begin/end iterate the underlying metadata elements // Count /begin/end对底层元数据元素进行迭代
**********************************************************************/
template <typename Element, typename List, template<typename> class Ptr>
class list_array_tt {
struct array_t {
uint32_t count;
Ptr<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:
template <bool authenticated>
class iteratorImpl {
const Ptr<List> *lists;
const Ptr<List> *listsEnd;
template<bool B>
struct ListIterator {
using Type = typename List::signedIterator;
static Type begin(Ptr<List> ptr) { return ptr->signedBegin(); }
static Type end(Ptr<List> ptr) { return ptr->signedEnd(); }
};
template<>
struct ListIterator<false> {
using Type = typename List::iterator;
static Type begin(Ptr<List> ptr) { return ptr->begin(); }
static Type end(Ptr<List> ptr) { return ptr->end(); }
};
typename ListIterator<authenticated>::Type m, mEnd;
public:
iteratorImpl(const Ptr<List> *begin, const Ptr<List> *end)
: lists(begin), listsEnd(end)
{
if (begin != end) {
m = ListIterator<authenticated>::begin(*begin);
mEnd = ListIterator<authenticated>::end(*begin);
}
}
const Element& operator * () const {
return *m;
}
Element& operator * () {
return *m;
}
bool operator != (const iteratorImpl& 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 iteratorImpl& operator ++ () {
ASSERT(m != mEnd);
m++;
if (m == mEnd) {
ASSERT(lists != listsEnd);
lists++;
if (lists != listsEnd) {
m = ListIterator<authenticated>::begin(*lists);
mEnd = ListIterator<authenticated>::end(*lists);
}
}
return *this;
}
};
using iterator = iteratorImpl<false>;
using signedIterator = iteratorImpl<true>;
private:
union {
Ptr<List> 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();
}
public:
list_array_tt() : list(nullptr) { }
list_array_tt(List *l) : list(l) { }
list_array_tt(const list_array_tt &other) {
*this = other;
}
list_array_tt &operator =(const list_array_tt &other) {
if (other.hasArray()) {
arrayAndFlag = other.arrayAndFlag;
} else {
list = other.list;
}
return *this;
}
uint32_t count() const {
uint32_t result = 0;
for (auto lists = beginLists(), end = endLists();
lists != end;
++lists)
{
result += (*lists)->count;
}
return result;
}
iterator begin() const {
return iterator(beginLists(), endLists());
}
iterator end() const {
auto e = endLists();
return iterator(e, e);
}
signedIterator signedBegin() const {
return signedIterator(beginLists(), endLists());
}
signedIterator signedEnd() const {
auto e = endLists();
return signedIterator(e, e);
}
inline uint32_t countLists(const std::function<const array_t * (const array_t *)> & peek) const {
if (hasArray()) {
return peek(array())->count;
} else if (list) {
return 1;
} else {
return 0;
}
}
uint32_t countLists() {
return countLists([](array_t *x) { return x; });
}
const Ptr<List>* beginLists() const {
if (hasArray()) {
return array()->lists;
} else {
return &list;
}
}
const Ptr<List>* endLists() const {
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;
array_t *newArray = (array_t *)malloc(array_t::byteSize(newCount));
newArray->count = newCount;
array()->count = newCount;
for (int i = oldCount - 1; i >= 0; i--)
newArray->lists[i + addedCount] = array()->lists[i];
for (unsigned i = 0; i < addedCount; i++)
newArray->lists[i] = addedLists[i];
free(array());
setArray(newArray);
validate();
}
else if (!list && addedCount == 1) {
// 0 lists -> 1 list
list = addedLists[0];
validate();
}
else {
// 1 list -> many lists
Ptr<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;
for (unsigned i = 0; i < addedCount; i++)
array()->lists[i] = addedLists[i];
validate();
}
}
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 Other>
void duplicateInto(Other &other) {
if (hasArray()) {
array_t *a = array();
other.setArray((array_t *)memdup(a, a->byteSize()));
for (uint32_t i = 0; i < a->count; i++) {
other.array()->lists[i] = a->lists[i]->duplicate();
}
} else if (list) {
other.list = list->duplicate();
} else {
other.list = nil;
}
}
};
我们通过list
、ptr
操作拿到真正的数据:
我们发现里面有6
个方法,正常情况下,-
方法是存放在类中的,我们已知了LLPerson
中有5
个-
方法,那么我们就通过数据来读取,看一下这6
个方法是什么。
// objc-runtime-new.h
// Two bits of entsize are used for fixup markers. // 两个entsize的比特用于固定标记。
// Reserve the top half of entsize for more flags. We never
// need entry sizes anywhere close to 64kB. //保留entsize的上半部分用于更多的标识。我们从来不需要接近64kB的条目大小。
//
// Currently there is one flag defined: the small method list flag, // 目前只定义了一个标志:小方法列表标志,method_t::smallMethodListFlag
// method_t::smallMethodListFlag. Other flags are currently ignored. //其他标志目前被忽略
// (NOTE: these bits are only ignored on runtimes that support small
// method lists. Older runtimes will treat them as part of the entry
// size!) //些位只在支持小方法列表的运行时被忽略。旧的运行时将把它们作为入口大小的一部分!
struct method_list_t : entsize_list_tt<method_t, method_list_t, 0xffff0003, method_t::pointer_modifier> {
bool isUniqued() const;
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;
}
bool isSmallList() const {
return flags() & method_t::smallMethodListFlag;
}
bool isExpectedSize() const {
if (isSmallList())
return entsize() == method_t::smallSize;
else
return entsize() == method_t::bigSize;
}
method_list_t *duplicate() const {
auto begin = signedBegin();
auto end = signedEnd();
method_list_t *dup;
if (isSmallList()) {
dup = (method_list_t *)calloc(byteSize(method_t::bigSize, count), 1);
dup->entsizeAndFlags = method_t::bigSize;
} else {
dup = (method_list_t *)calloc(this->byteSize(), 1);
dup->entsizeAndFlags = this->entsizeAndFlags;
}
dup->count = this->count;
std::copy(begin, end, dup->begin());
return dup;
}
struct Ptrauth {
static const uint16_t discriminator = 0xC310;
static_assert(std::is_same<
void * __ptrauth_objc_method_list_pointer *,
void * __ptrauth(ptrauth_key_method_list_pointer, 1, discriminator) *>::value,
"Method list pointer signing discriminator must match ptrauth.h");
ALWAYS_INLINE static method_list_t *sign (method_list_t *ptr, const void *address) {
return ptrauth_sign_unauthenticated(ptr,
ptrauth_key_method_list_pointer,
ptrauth_blend_discriminator(address,
discriminator));
}
ALWAYS_INLINE static method_list_t *auth(method_list_t *ptr, const void *address) {
(void)address;
#if __has_feature(ptrauth_calls)
if (ptr)
ptr = ptrauth_auth_data(ptr,
ptrauth_key_method_list_pointer,
ptrauth_blend_discriminator(address,
discriminator));
#endif
return ptr;
}
};
};
从method_list_t
这个结构我们可以看出,它继承自entsize_list_tt
,这也是一个模板类:
// objc-runtime-new.h
/***********************************************************************
* entsize_list_tt<Element, List, FlagMask, PointerModifier>
* Generic implementation of an array of non-fragile structs. // non-fragile结构数组的通用实现。
*
* Element is the struct type (e.g. method_t) // Element是结构类型(例如method_t)
* List is the specialization of entsize_list_tt (e.g. method_list_t) // List是entsize_list_tt的专门化(例如method_list_t)
* FlagMask is used to stash extra bits in the entsize field / /FlagMask用于在entsize字段中隐藏额外的位(e.g. method list fixup markers)
* (e.g. method list fixup markers)
* PointerModifier is applied to the element pointers retrieved from
* the array. //PointerModifier应用于从数组中检索到的元素指针。
**********************************************************************/
template <typename Element, typename List, uint32_t FlagMask, typename PointerModifier = PointerModifierNop>
struct entsize_list_tt {
uint32_t entsizeAndFlags;
uint32_t count; // 数据量
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;
}
template <bool authenticated>
struct iteratorImpl;
using iterator = iteratorImpl<false>;
using signedIterator = iteratorImpl<true>;
const iterator begin() const {
return iterator(*static_cast<const List*>(this), 0);
}
iterator begin() {
return iterator(*static_cast<const List*>(this), 0);
}
const iterator end() const {
return iterator(*static_cast<const List*>(this), count);
}
iterator end() {
return iterator(*static_cast<const List*>(this), count);
}
const signedIterator signedBegin() const {
return signedIterator(*static_cast<const List *>(this), 0);
}
const signedIterator signedEnd() const {
return signedIterator(*static_cast<const List*>(this), count);
}
template <bool authenticated>
struct iteratorImpl {
uint32_t entsize;
uint32_t index; // keeping track of this saves a divide in operator-
using ElementPtr = std::conditional_t<authenticated, Element * __ptrauth(ptrauth_key_process_dependent_data, 1, 0xdead), Element *>;
ElementPtr element;
typedef std::random_access_iterator_tag iterator_category;
typedef Element value_type;
typedef ptrdiff_t difference_type;
typedef Element* pointer;
typedef Element& reference;
iteratorImpl() { }
iteratorImpl(const List& list, uint32_t start = 0)
: entsize(list.entsize())
, index(start)
, element(&list.getOrEnd(start))
{ }
const iteratorImpl& operator += (ptrdiff_t delta) {
element = (Element*)((uint8_t *)element + delta*entsize);
index += (int32_t)delta;
return *this;
}
const iteratorImpl& operator -= (ptrdiff_t delta) {
element = (Element*)((uint8_t *)element - delta*entsize);
index -= (int32_t)delta;
return *this;
}
const iteratorImpl operator + (ptrdiff_t delta) const {
return iteratorImpl(*this) += delta;
}
const iteratorImpl operator - (ptrdiff_t delta) const {
return iteratorImpl(*this) -= delta;
}
iteratorImpl& operator ++ () { *this += 1; return *this; }
iteratorImpl& operator -- () { *this -= 1; return *this; }
iteratorImpl operator ++ (int) {
iteratorImpl result(*this); *this += 1; return result;
}
iteratorImpl operator -- (int) {
iteratorImpl result(*this); *this -= 1; return result;
}
ptrdiff_t operator - (const iteratorImpl& rhs) const {
return (ptrdiff_t)this->index - (ptrdiff_t)rhs.index;
}
Element& operator * () const { return *element; }
Element* operator -> () const { return element; }
operator Element& () const { return *element; }
bool operator == (const iteratorImpl& rhs) const {
return this->element == rhs.element;
}
bool operator != (const iteratorImpl& rhs) const {
return this->element != rhs.element;
}
bool operator < (const iteratorImpl& rhs) const {
return this->element < rhs.element;
}
bool operator > (const iteratorImpl& rhs) const {
return this->element > rhs.element;
}
};
};
在这个模板类中,我们只关注get
这个迭代器就可以,我们可以通过迭代器获取列表中的数据。
接下来就是method_t
这个结构了。
// objc-runtime-new.h
struct 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;
};
private:
bool isSmall() const { // 是否是小端模式
return ((uintptr_t)this & 1) == 1;
}
// The representation of a "small" method. This stores three
// relative offsets to the name, types, and implementation. // 小端方法的表示。这存储了名称、类型和实现的三个相对偏移量。
struct small { // ios是小端模式,这是我们关注的
// The name field either refers to a selector (in the shared
// cache) or a selref (everywhere else). // name字段要么引用一个选择器(在共享缓存中),要么引用一个selref(在其他任何地方)
RelativePointer<const void *> name;
RelativePointer<const char *> types;
RelativePointer<IMP, /*isNullable*/false> imp;
bool inSharedCache() const {
return (CONFIG_SHARED_CACHE_RELATIVE_DIRECT_SELECTORS &&
objc::inSharedCache((uintptr_t)this));
}
};
small &small() const {
ASSERT(isSmall());
return *(struct small *)((uintptr_t)this & ~(uintptr_t)1);
}
IMP remappedImp(bool needsLock) const;
void remapImp(IMP imp);
objc_method_description *getSmallDescription() const;
public:
static const auto bigSize = sizeof(struct big);
static const auto smallSize = sizeof(struct small);
// All shared cache relative method lists names are offsets from this selector. //所有共享缓存相对方法列表的名称都是这个选择器的偏移量。
static uintptr_t sharedCacheRelativeMethodBase() {
return (uintptr_t)@selector(🤯);
}
// The pointer modifier used with method lists. When the method
// list contains small methods, set the bottom bit of the pointer.
// We use that bottom bit elsewhere to distinguish between big
// and small methods. //方法列表中使用的指针修饰符。当方法列表包含小方法时,设置指针的底部位。我们在其他地方使用底部来区分大方法和小方法。
struct pointer_modifier {
template <typename ListType>
static method_t *modify(const ListType &list, method_t *ptr) {
if (list.flags() & smallMethodListFlag)
return (method_t *)((uintptr_t)ptr | 1);
return ptr;
}
};
big &big() const { // 大端模式获取数据
ASSERT(!isSmall());
return *(struct big *)this;
}
ALWAYS_INLINE SEL name() const {
if (isSmall()) {
if (small().inSharedCache()) {
return (SEL)small().name.get(sharedCacheRelativeMethodBase());
} else {
// Outside of the shared cache, relative methods point to a selRef //在共享缓存之外,相对方法指向一个selRef
return *(SEL *)small().name.get();
}
} else {
return big().name;
}
}
const char *types() const {
return isSmall() ? small().types.get() : big().types;
}
IMP imp(bool needsLock) const {
if (isSmall()) {
IMP smallIMP = ptrauth_sign_unauthenticated(small().imp.get(),
ptrauth_key_function_pointer, 0);
// We must sign the newly generated function pointer before calling
// out to remappedImp(). That call may spill `this` leaving it open
// to being overwritten while it's on the stack. By signing first,
// we'll spill the signed function pointer instead, which is
// resistant to being overwritten. //在调用remappedImp()之前,必须为新生成的函数指针签名。这个调用可能会泄露' this ',让它在堆栈上时被覆盖。通过先签名,我们将会泄漏已签名的函数指针,它是不会被覆盖的。
//
// The compiler REALLY wants to perform this signing operation after
// the call to remappedImp. This asm statement prevents it from
// doing that reordering. //编译器确实希望在调用remappedImp之后执行这个签名操作。asm语句阻止了这种重新排序。
asm ("": : "r" (smallIMP) :);
IMP remappedIMP = remappedImp(needsLock);
if (remappedIMP)
return remappedIMP;
return smallIMP;
}
return big().imp;
}
// Fetch the IMP as a `void *`. Avoid signing relative IMPs. This
// avoids signing oracles in cases where we're just logging the
// value. Runtime lock must be held. //以' void * '的形式获取IMP。避免签署相对imp。这避免了在只记录值的情况下为oracle签名。必须持有运行时锁。
void *impRaw() const {
if (isSmall()) {
IMP remappedIMP = remappedImp(false);
if (remappedIMP)
return (void *)remappedIMP;
return small().imp.getRaw();
}
return (void *)big().imp;
}
SEL getSmallNameAsSEL() const {
ASSERT(small().inSharedCache());
return (SEL)small().name.get(sharedCacheRelativeMethodBase());
}
SEL getSmallNameAsSELRef() const {
ASSERT(!small().inSharedCache());
return *(SEL *)small().name.get();
}
void setName(SEL name) {
if (isSmall()) {
ASSERT(!small().inSharedCache());
*(SEL *)small().name.get() = name;
} else {
big().name = name;
}
}
void setImp(IMP imp) {
if (isSmall()) {
remapImp(imp);
} else {
big().imp = imp;
}
}
objc_method_description *getDescription() const { // 通过这个可以打印整个信息
return isSmall() ? getSmallDescription() : (struct objc_method_description *)this;
}
struct SortBySELAddress :
public std::binary_function<const struct method_t::big&,
const struct method_t::big&, bool>
{
bool operator() (const struct method_t::big& lhs,
const struct method_t::big& rhs)
{ return lhs.name < rhs.name; }
};
method_t &operator=(const method_t &other) {
ASSERT(!isSmall());
big().imp = other.imp(false);
big().name = other.name();
big().types = other.types();
return *this;
}
};
通过读取method_t
的结构,我们可以看到,方法的数据都是在这个结构中的,并且可以通过getDescription
打印一下这个信息。
由于ios
是小端模式,所以打印的是small
这个结构。
我们可以看到列表中第一个方法时instanceMethod
这个方法,接着打印其他的:
通过打印我们可以看到,这6
个方法是我们已知的5
个-
方法,再加上一个c++
的析构函数。
至此,我们从rw
中就读取出了方法的信息。
下面,我们通过相同的方法打印一下properties
和protocols
。
// objc-runtime-new.h
class property_array_t :
public list_array_tt<property_t, property_list_t, RawPtr>
{
typedef list_array_tt<property_t, property_list_t, RawPtr> Super;
public:
property_array_t() : Super() { }
property_array_t(property_list_t *l) : Super(l) { }
};
protocol_array_t
同样也是继承自模板类list_array_tt
。
并且里面只有两个数据。
// objc-runtime-new.h
struct property_list_t : entsize_list_tt<property_t, property_list_t, 0> {
};
property_list_t
也是继承自模板类entsize_list_tt
,那我们就可以通过get
迭代器获取property_t
。
// objc-runtime-new.h
struct property_t {
const char *name;
const char *attributes;
};
property_t
这个结构就更简单了,我们直接打印就可以了。
里面就只有两个属性的信息,没有成员变量的信息,后期我们会探索成员变量的存储。
最后是protocols
:
// objc-runtime-new.h
class protocol_array_t :
public list_array_tt<protocol_ref_t, protocol_list_t, RawPtr>
{
typedef list_array_tt<protocol_ref_t, protocol_list_t, RawPtr> Super;
public:
protocol_array_t() : Super() { }
protocol_array_t(protocol_list_t *l) : Super(l) { }
};
同样的,继承自list_array_tt
模板类。
// objc-runtime-new.h
struct protocol_list_t {
// count is pointer-sized by accident.
uintptr_t count;
protocol_ref_t list[0]; // variable-size
size_t byteSize() const {
return sizeof(*this) + count*sizeof(list[0]);
}
protocol_list_t *duplicate() const {
return (protocol_list_t *)memdup(this, this->byteSize());
}
typedef protocol_ref_t* iterator;
typedef const protocol_ref_t* const_iterator;
const_iterator begin() const {
return list;
}
iterator begin() {
return list;
}
const_iterator end() const {
return list + count;
}
iterator end() {
return list + count;
}
};
这时候的protocol_list_t
就和上面的不一样了,它没有继承自entsize_list_tt
,所以也就没有的迭代器。我们可以尝试用protocol_ref_t list[0]
来读取它。
protocol_ref_t
这个结构我们可以看一下:
// // objc-runtime-new.h
typedef uintptr_t protocol_ref_t; // protocol_t *, but unremapped //protocol_t *指针
// 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_IS_CANONICAL (1<<29) // must never be set by compiler
// Bits 0..15 are reserved for Swift's use.
#define PROTOCOL_FIXED_UP_MASK (PROTOCOL_FIXED_UP_1 | PROTOCOL_FIXED_UP_2)
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; // sizeof(protocol_t)
uint32_t flags;
// Fields below this point are not always present on disk.
const char **_extendedMethodTypes;
const char *_demangledName;
property_list_t *_classProperties;
const char *demangledName();
const char *nameForLogging() {
return demangledName();
}
bool isFixedUp() const;
void setFixedUp();
bool isCanonical() const;
void clearIsCanonical();
# define HAS_FIELD(f) ((uintptr_t)(&f) < ((uintptr_t)this + size))
bool hasExtendedMethodTypesField() const {
return HAS_FIELD(_extendedMethodTypes);
}
bool hasDemangledNameField() const {
return HAS_FIELD(_demangledName);
}
bool hasClassPropertiesField() const {
return HAS_FIELD(_classProperties);
}
# undef HAS_FIELD
const char **extendedMethodTypes() const {
return hasExtendedMethodTypesField() ? _extendedMethodTypes : nil;
}
property_list_t *classProperties() const {
return hasClassPropertiesField() ? _classProperties : nil;
}
};
protocol_ref_t
就是protocol_t *
,那么我们就通过强转来获取一下数据:
至此我们就探索了methods
、properties
、protocols
,那么+
方法classMethod
在哪里呢?应该是在元类中,我们直接读取就可以:
至此,探索告一段落,我们在后续探索成员变量。