类的底层探索(上)

在这里插入图片描述
首先从一张图开始说起,这样图是isasuperclass的走向图,那真的是这么走的吗?我们就通过代码,来看一下。

isa的走向

@interface LLPerson : NSObject

@end

@interface LLTeacher : LLPerson

@end

首先我们创建两个类,LLPerson继承自NSObjectLLTeacher继承自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数据
    
    ......
    
}

我们通过源码可以看出Classobjc_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);

在这里插入图片描述
再次印证了元类的父类就是父类的元类。
那么NSObjectNSObject根元类的父类呢?

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- 方法(instanceMethodsetName:(属性生成)、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;
        }
    }
};

我们通过listptr操作拿到真正的数据:
在这里插入图片描述
我们发现里面有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中就读取出了方法的信息。
下面,我们通过相同的方法打印一下propertiesprotocols

// 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 *,那么我们就通过强转来获取一下数据:
在这里插入图片描述
至此我们就探索了methodspropertiesprotocols,那么+方法classMethod在哪里呢?应该是在元类中,我们直接读取就可以:
在这里插入图片描述
至此,探索告一段落,我们在后续探索成员变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值