应用程序加载(三)-- 类的加载

2020-10-16  本文已影响0人  过气的程序员DZ

应用程序加载(一) -- dyld流程分析
应用程序加载(二) -- dyld&objc关联以及类的加载初探
应用程序加载(三)-- 类的加载
应用程序加载(四)-- 分类的加载
应用程序加载(五)-- 类扩展和关联对象


开场白

上篇文章研究到_read_images中调用了readClass函数。这篇继续开始我们的研究

readClass

Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
    const char *mangledName  = cls->mangledName();
    
    //省略不关心的代码
    ...
    
    
    if (headerIsPreoptimized  &&  !replacing) {
        // class list built in shared cache
        // fixme strict assert doesn't work because of duplicates
        // ASSERT(cls == getClass(name));
        ASSERT(getClassExceptSomeSwift(mangledName));
    } else {
        addNamedClass(cls, mangledName, replacing);
        addClassTableEntry(cls);
    }
    //省略不关心的代码
    ...
    
    return cls;
}

//获取类名

看看加入表的代码实现:

void *NXMapInsert(NXMapTable *table, const void *key, const void *value) {
    MapPair *pairs = (MapPair *)table->buckets;
    unsigned    index = bucketOf(table, key);
    MapPair *pair = pairs + index;
    if (key == NX_MAPNOTAKEY) {
    _objc_inform("*** NXMapInsert: invalid key: -1\n");
    return NULL;
    }

    unsigned numBuckets = table->nbBucketsMinusOne + 1;
    
    //哈希表中没有 直接加入
    if (pair->key == NX_MAPNOTAKEY) {
    pair->key = key; pair->value = value;
    table->count++;
    if (table->count * 4 > numBuckets * 3) _NXMapRehash(table);
    return NULL;
    }
    
    
    if (isEqual(table, pair->key, key)) {//表中有,并且key能匹配上,直接修改原来记录的value
    const void  *old = pair->value;
    if (old != value) pair->value = value;/* avoid writing unless needed! */
    return (void *)old;
    } else if (table->count == numBuckets) {
    /* no room: rehash and retry */
    _NXMapRehash(table);
    return NXMapInsert(table, key, value);
    } else {//key匹配不上,哈希冲突,重新计算哈希并加入到表
    unsigned    index2 = index;
    while ((index2 = nextIndex(table, index2)) != index) {
        pair = pairs + index2;
        if (pair->key == NX_MAPNOTAKEY) {
        pair->key = key; pair->value = value;
        table->count++;
        if (table->count * 4 > numBuckets * 3) _NXMapRehash(table);
        return NULL;
        }
        if (isEqual(table, pair->key, key)) {
        const void  *old = pair->value;
        if (old != value) pair->value = value;/* avoid writing unless needed! */
        return (void *)old;
        }
    }
    /* no room: can't happen! */
    _objc_inform("**** NXMapInsert: bug\n");
    return NULL;
    }
}

到此处,仅仅是将类名和类的总体信息保存到系统的一个表中。下面了解一下类中方法做了什么处理。

realizeClassWithoutSwift

_read_images中,会看到调用函数realizeClassWithoutSwift的地方

懒加载类和非懒加载类的函数调用栈,如图:


接下来看看realizeClassWithoutSwift的实现,代码比较长,通过多张图片的方式查看:

methodizeClass

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

    bool isMeta = cls->isMetaClass();
    auto rw = cls->data();
    auto ro = rw->ro();
    auto rwe = rw->ext();
    
    const char *mangledName  = cls->mangledName();

   //省略代码
   ...

    // Install methods and properties that the class implements itself.
    method_list_t *list = ro->baseMethods();
    if (list) {
        prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
        if (rwe) rwe->methods.attachLists(&list, 1);
    }

    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);
    }

   //省略代码
   ...
}
static void 
prepareMethodLists(Class cls, method_list_t **addedLists, int addedCount,
                   bool baseMethods, bool methodsFromBundle)
{
    runtimeLock.assertLocked();
    
    const char *mangledName  = cls->mangledName();

    if (addedCount == 0) return;

    //省略代码
   ...

    // Add method lists to array.
    // Reallocate un-fixed method lists.
    // The new methods are PREPENDED to the method list array.

    for (int i = 0; i < addedCount; i++) {
        method_list_t *mlist = addedLists[i];
        ASSERT(mlist);

        // Fixup selectors if necessary
        if (!mlist->isFixedUp()) {
            fixupMethodList(mlist, methodsFromBundle, true/*sort*/);
        }
    }

   //省略代码
   ...
}

static void 
fixupMethodList(method_list_t *mlist, bool bundleCopy, bool sort)
{
    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) {
            const char *name = sel_cname(meth.name);
            meth.name = sel_registerNameNoLock(name, bundleCopy);
        }
    }

    // Sort by selector address.
    if (sort) {
        method_t::SortBySELAddress sorter;
        std::stable_sort(mlist->begin(), mlist->end(), sorter);
    }
    
    // Mark method list as uniqued and sorted
    mlist->setFixedUp();
}

类加载流程图

上一篇 下一篇

猜你喜欢

热点阅读