类的加载(中)

2021-08-03  本文已影响0人  冼同学

前言

上一篇文章中已经分析了_object_initread_images的底层原理,最后类的加载停留在了realizeClassWithoutSwift方法,这个也是我们这篇文章重点分析的点。

准备资料

realizeClassWithoutSwift

realizeClassWithoutSwift方法其实在类的加载中对rwro数据进行一系列的处理,在read_images方法中进入这个方法必须实现+load方法,使类变为非懒加载。其核心代码实现如下:

static Class realizeClassWithoutSwift(Class cls, Class previously)
{
    runtimeLock.assertLocked();
    class_rw_t *rw;      //rw数据
    Class supercls;      //父类
    Class metacls;       //元类
    //省略cls的初始化判断
    ......
    //省略生成rw数据的逻辑
    ......
    //初始化cache(缓存)
    ......
    cls->cache.initializeToEmptyOrPreoptimizedInDisguise();
   #if FAST_CACHE_META
    //判断是否为元类
    if (isMeta) cls->cache.setBit(FAST_CACHE_META);
#endif
    //为32位架构设计的,为isa是否纯指针做的处理。
    cls->chooseClassArrayIndex();
    ......
    //递归获取元类和父类(关联元类和父类)
    supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);
    metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
    ......
   //调整ivars
   if (supercls  &&  !isMeta) reconcileInstanceVariables(cls, supercls, ro);
    ......
   //同步flags标志位
   if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
        (supercls && supercls->forbidsAssociatedObjects()))
    {
        rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
    }
    ......
    //关联子类和相邻类
    if (supercls) {
        addSubclass(supercls, cls);
    } else {
        addRootClass(cls);
    }
    // Attach categories
    //分类处理
    methodizeClass(cls, previously);

    return cls;
}

realizeClassWithoutSwift主要做了以下的操作:

rw数据的生成

 auto ro = (const class_ro_t *)cls->data();
    auto isMeta = ro->flags & RO_META;
    if (ro->flags & RO_FUTURE) {
        // This was a future class. rw data is already allocated.
        rw = cls->data();
        ro = cls->data()->ro();
        ASSERT(!isMeta);
        cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
    } else {
        // Normal class. Allocate writeable class data.
        //开辟rw数据空间
        rw = objc::zalloc<class_rw_t>();
        //将ro数据写进rw数据中
        rw->set_ro(ro);
        //设置flag标志位
        rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
        //设置rw数据
        cls->setData(rw);
    }

注意:ro数据是在llvm编译期间已经生成。

cls关联元类与父类

//递归获取元类和父类
    supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);
    metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);

#if SUPPORT_NONPOINTER_ISA
    if (isMeta) {
        //元类的isa是纯isa
        cls->setInstancesRequireRawIsa();
    } else {
        bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
        bool rawIsaIsInherited = false;
        static bool hackedDispatch = false;

        if (DisableNonpointerIsa) {
            // Non-pointer isa disabled by environment or app SDK version
            //设置环境变量,此时isa为纯isa
            instancesRequireRawIsa = true;
        }
        //OS_object类时纯指针
        else if (!hackedDispatch  &&  0 == strcmp(ro->getName(), "OS_object"))
        {
            // hack for libdispatch et al - isa also acts as vtable pointer
            hackedDispatch = true;
            instancesRequireRawIsa = true;
        }
        //父类是纯指针,并且父类还有父类。那么自己也要是纯指针。
        //rawIsaIsInherited 表示继承的是纯指针
        else if (supercls  &&  supercls->getSuperclass()  &&
                 supercls->instancesRequireRawIsa())
        {
            instancesRequireRawIsa = true;
            rawIsaIsInherited = true;
        }
        //递归设置父类,子类为纯isa、指针
        if (instancesRequireRawIsa) {
            cls->setInstancesRequireRawIsaRecursively(rawIsaIsInherited);
        }
    }
// SUPPORT_NONPOINTER_ISA
#endif

    // Update superclass and metaclass in case of remapping
    //关联父类和元类,也是继承链与isa走位
    cls->setSuperclass(supercls);
    cls->initClassIsa(metacls);

调整ivar偏移(offset)

  //调整ivar 的offset 可能会重新创建`class_ro_t`来更新ivar
    if (supercls  &&  !isMeta) reconcileInstanceVariables(cls, supercls, ro);
    //设置ivar成员占用空间大小
    cls->setInstanceSize(ro->instanceSize);

同步flags标志位

    //拷贝ro的flags到rw中
    if (ro->flags & RO_HAS_CXX_STRUCTORS) {
        cls->setHasCxxDtor();
        if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
            cls->setHasCxxCtor();
        }
    }
    //是否禁止关联对象
    if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
        (supercls && supercls->forbidsAssociatedObjects()))
    {
        rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
    }

子类和根类的设置

  if (supercls) {
        // 关联子类
        addSubclass(supercls, cls);
    } else {
        //设置根类
        addRootClass(cls);
    }

addSubclass

static void addSubclass(Class supercls, Class subcls)
{
    runtimeLock.assertLocked();

    if (supercls  &&  subcls) {
        ASSERT(supercls->isRealized());
        ASSERT(subcls->isRealized());
        objc_debug_realized_class_generation_count++;
        //相邻的类
        subcls->data()->nextSiblingClass = supercls->data()->firstSubclass;
        //第一个子类
        supercls->data()->firstSubclass = subcls;
        //同步父类的c++析构和构造
        if (supercls->hasCxxCtor()) {
            subcls->setHasCxxCtor();
        }

        if (supercls->hasCxxDtor()) {
            subcls->setHasCxxDtor();
        }

        objc::AWZScanner::scanAddedSubClass(subcls, supercls);
        objc::RRScanner::scanAddedSubClass(subcls, supercls);
        objc::CoreScanner::scanAddedSubClass(subcls, supercls);

        if (!supercls->allowsPreoptCaches()) {
            subcls->setDisallowPreoptCachesRecursively(__func__);
        } else if (!supercls->allowsPreoptInlinedSels()) {
            subcls->setDisallowPreoptInlinedSelsRecursively(__func__);
        }
        //同步子类isa是否纯指针
        if (supercls->instancesRequireRawIsa()  &&  supercls->getSuperclass()) {
            subcls->setInstancesRequireRawIsaRecursively(true);
        }
    }
}

addRootClass

static void addRootClass(Class cls)
{
    runtimeLock.assertLocked();

    ASSERT(cls->isRealized());

    objc_debug_realized_class_generation_count++;
    
    //自己的相邻类设置为第一个初始化的类(nil)。第一个初始化的类设置为自己。
    cls->data()->nextSiblingClass = _firstRealizedClass;
    _firstRealizedClass = cls;
}

methodizeClass

上面分析的realizeClassWithoutSwift方法最后实现了methodizeClass方法,主要是添加分类的操作。代码如下:

  //添加分类
  methodizeClass(cls, previously);

在_read_image方法中调用:

realizeClassWithoutSwift(cls, nil);

methodizeClass核心代码如下:

static void methodizeClass(Class cls, Class previously)
{
    runtimeLock.assertLocked();

    bool isMeta = cls->isMetaClass();
    auto rw = cls->data();  //获取rw数据
    auto ro = rw->ro();     //获取rw中的ro数据
    auto rwe = rw->ext();   //获取rw中的rwe数据(可扩展)

    // Methodizing for the first time
    //获取ro方法列表
    if (PrintConnecting) {
        _objc_inform("CLASS: methodizing class '%s' %s", 
                     cls->nameForLogging(), isMeta ? "(meta)" : "");
    }

    // Install methods and properties that the class implements itself.
    //ro方法列表获取
    method_list_t *list = ro->baseMethods();
    if (list) {
        prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls), nullptr);
        if (rwe) rwe->methods.attachLists(&list, 1);
    }
    //获取ro属性列表
    property_list_t *proplist = ro->baseProperties;
    if (rwe && proplist) {
        rwe->properties.attachLists(&proplist, 1);
    }
    //获取协议列表
    protocol_list_t *protolist = ro->baseProtocols;
    if (rwe && protolist) {
        rwe->protocols.attachLists(&protolist, 1);
    }

    // Root classes get bonus method implementations if they don't have 
    // them already. These apply before category replacements.
    //是否根元类,根元类加了initialize方法
    if (cls->isRootMetaclass()) {
        // root metaclass
        addMethod(cls, @selector(initialize), (IMP)&objc_noop_imp, "", NO);
    }

    // Attach categories.
    //分类的处理
    if (previously) {
        if (isMeta) {
            objc::unattachedCategories.attachToClass(cls, previously,
                                                     ATTACH_METACLASS);
        } else {
            // When a class relocates, categories with class methods
            // may be registered on the class itself rather than on
            // the metaclass. Tell attachToClass to look for those.
            objc::unattachedCategories.attachToClass(cls, previously,
                                                     ATTACH_CLASS_AND_METACLASS);
        }
    }
    objc::unattachedCategories.attachToClass(cls, cls,
                                             isMeta ? ATTACH_METACLASS : ATTACH_CLASS);
......(省略部分代码)

注意:attachCategories方法在attachToClass方法里面调用。

prepareMethodLists

方法入口:

prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls), nullptr);

此方法是获取ro的方法列表,核心代码如下:

//cls, &list, 1, YES, isBundleClass(cls), nullptr
static void 
prepareMethodLists(Class cls, method_list_t **addedLists, int addedCount,
                   bool baseMethods, bool methodsFromBundle, const char *why)
{
……省略一部分代码
    // Add method lists to array.
    // Reallocate un-fixed method lists.
    // The new methods are PREPENDED to the method list array.
    //addedCount 为 1
    for (int i = 0; i < addedCount; i++) {
        //addedLists 也就是list。
        method_list_t *mlist = addedLists[i];
        ASSERT(mlist);

        // Fixup selectors if necessary
        //是否已经排序,没有则进行排序。对ro methodlist 排序
        if (!mlist->isFixedUp()) {
            //修正并且排序methodList
            fixupMethodList(mlist, methodsFromBundle, true/*sort*/);
        }
    }
……省略一部分代码
}

mlist验证:

mlist验证
结论:listmlist是同一个地址,也就是他们是一样的。(通过地址偏移的方式找出list然后赋值给mlist)

fixupMethodList

static void 
fixupMethodList(method_list_t *mlist, bool bundleCopy, bool sort)
{
    //runtime的锁操作
    runtimeLock.assertLocked();
    ASSERT(!mlist->isFixedUp());

    // fixme lock less in attachMethodLists ?
    // dyld3 may have already uniqued, but not sorted, the list
    if (!mlist->isUniqued()) {
        mutex_locker_t lock(selLock);
    
        // Unique selectors in list.
        for (auto& meth : *mlist) {
            //SEL方法编号转字符型的name
            const char *name = sel_cname(meth.name());
            //将name和地址设置在meth中
            ///设置SEL,SEL有可能在 __sel_registerName 最终调用了_dyld_get_objc_selector的值,相当于修正到dyld中
//            printf("前面 -- name:%s -- address:%p\n",name,meth.name());
            meth.setName(sel_registerNameNoLock(name, bundleCopy));
//            printf("后面 -- name:%s -- address:%p\n",name,meth.name());
        }
    }
    //排序,通过SEL的地址排序。
    if (sort && !mlist->isSmallList() && mlist->entsize() == method_t::bigSize) {
        method_t::SortBySELAddress sorter;
        //二分法排序,类似与消息慢速查找
        std::stable_sort(&mlist->begin()->big(), &mlist->end()->big(), sorter);
    }
    
    // Mark method list as uniqued and sorted.
    // Can't mark small lists, since they're immutable.
    //设置排序的标志位
    if (!mlist->isSmallList()) {
        mlist->setFixedUp();
    }
}

注意:small list是不可变的,也不会进行排序。

修正前后的SEL验证:

SEL验证
结论:runeat的地址发生了变化,变成了dyld提供的地址了。

排序前后的验证:

分类的探索

根据以上的代码分析可知在prepareMethodLists执行完成后是没有rwe数据的,所以后续的attachLists相关操作都不会执行,那么我们添加一个分类如下:

#import "XJLPerson.h"

NS_ASSUME_NONNULL_BEGIN

@interface XJLPerson (test)
@property (nonatomic,strong) NSString *name_test;
@property (nonatomic,assign) NSInteger age_test;
-(void)test;
-(void)sayNB;

#import "XJLPerson+test.h"

@implementation XJLPerson (test)
-(void)test{
    NSLog(@"---xjl---%s",__func__);
}
-(void)sayNB{
    NSLog(@"---xjl---%s",__func__);
}
@end
@end

NS_ASSUME_NONNULL_END

编译项目使用Xrun导出底层代码(main.cpp)查看分类的实现:

static struct _category_t *L_OBJC_LABEL_CATEGORY_$ [1] __attribute__((used, section ("__DATA, __objc_catlist,regular,no_dead_strip")))= {
    &_OBJC_$_CATEGORY_XJLPerson_$_test,
};

可以看出_XJLPerson_$_test_category_t类型的。

查看_category_t结构体数据结构:

struct _category_t {
    const char *name;
    struct _class_t *cls;
    const struct _method_list_t *instance_methods;
    const struct _method_list_t *class_methods;
    const struct _protocol_list_t *protocols;
    const struct _prop_list_t *properties;
};

继续观察分类底层生成信息:

static struct _category_t _OBJC_$_CATEGORY_XJLPerson_$_test __attribute__ ((used, section ("__DATA,__objc_const"))) = 
{
    "XJLPerson",//名字
    0, // &OBJC_CLASS_$_XJLPerson,//cls
    (const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_XJLPerson_$_test,//实例方法
    (const struct _method_list_t *)&_OBJC_$_CATEGORY_CLASS_METHODS_XJLPerson_$_test,//类方法
    0,///协议
    (const struct _prop_list_t *)&_OBJC_$_PROP_LIST_XJLPerson_$_test,//属性
};

查看分类的属性情况:

static struct /*_prop_list_t*/ {
    unsigned int entsize;  // sizeof(struct _prop_t)
    unsigned int count_of_properties;
    struct _prop_t prop_list[2];
} _OBJC_$_PROP_LIST_XJLPeron_$_test __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_prop_t),
    2,
    {{"name_test","T@\"NSString\",C,N"},
    {"age_test","Ti,N"}}
};

此时属性已经有了,但是通过之后通过方法生成的地方查找不到属性的settergetter方法,这只能通过关联对象进行处理哦。

分类加载源码的探究

通过上面的分析,大概了解了分类的结构。分类本身是一个结构体,那么它是怎么加载的呢?通过类的加载源码的分析核心逻辑在attachListsattachToClass中。控制条件是rwe

auto rwe = rw->ext();

进入ext()方法查看核心代码:

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() {
    //获取rwe
    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 {
        //创建rwe
        return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext));
    }
}

extAllocIfNeeded中进行了rwe的创建。extAllocIfNeeded的调用分为以下情况(rwe创建情况):

extAllocIfNeeded调用位置

可以看到除了attachCategories,其它要么是对类进行动态处理要么是修复类的时候创建rwe。这与WWDC上的介绍就相吻合了。那么显然核心逻辑就在attachCategories了。

但是attachCategories的调用逻辑在attachToClassload_categories_nolock中。

那么我们就能得出分类的加载只有以下的两条线路:
1. methodizeClass -> attachToClass -> attachCategories
2. load_images -> loadAllCategories -> load_categories_nolock -> attachCategories

注意:分类的加载在下一篇文章会进行详细的分析哦。

总结

realizeClassWithoutSwift

methodizeClass
主要是对方法列表进行排序 &加载分类 & rwe 的处理。

rwe()方法

分类加载的两条线路:
1. methodizeClass -> attachToClass -> attachCategories
2. load_images -> loadAllCategories -> load_categories_nolock -> attachCategories

上一篇下一篇

猜你喜欢

热点阅读