十 類的加載-前篇 (map_images)

前言

前篇 我們了解到 應(yīng)用的加載流程,在main 函數(shù)調(diào)用之前有許多系統(tǒng)的操作流程,但是在分析類的加載需要明確的是main 函數(shù)才是我們app程序的入口函數(shù),我們知道 在執(zhí)行main函數(shù)之前,系統(tǒng)會(huì)對(duì)runtime進(jìn)行初始化,在之前我們了解到dyld會(huì)調(diào)用 runtime的入口函數(shù),runtime的入口函數(shù) 就是 _objc_iinnit,它就是在 mian 函數(shù)之前就被dyld調(diào)用,而load方法就在 _objc_init中調(diào)用,所以 我們探究的起點(diǎn)就是 _objc_init函數(shù)

image.png

一 _objc_init 探究分析

我們?cè)趓untime的源碼中 可以了解到_objc_init 的源代碼

/***********************************************************************
* _objc_init
* Bootstrap initialization. Registers our image notifier with dyld.
* Called by libSystem BEFORE library initialization time
**********************************************************************/

void _objc_init(void)
{
    static bool initialized = false;
    if (initialized) return;
    initialized = true;
    
    // fixme defer initialization until an objc-using image is found?
    environ_init(); // 環(huán)境變量
    tls_init(); //線程 key 的綁定
    static_init(); //初始化系統(tǒng)內(nèi)置的 C++ 靜態(tài)構(gòu)造函數(shù)
    runtime_init(); //主要是運(yùn)行時(shí)的初始化,主要分為兩部分:分類初始化(unattachedCategories)和類的表初始化(allocatedClasses)
    exception_init(); // 初始化libobjc異常處理
    cache_init(); //緩存初始化
    _imp_implementationWithBlock_init(); //啟動(dòng)機(jī)制回調(diào)
    // 注冊(cè)回調(diào)通知
    _dyld_objc_notify_register(&map_images, load_images, unmap_image);

#if __OBJC2__
    didCallDyldNotifyRegister = true;
#endif
}·  

二 _dyld_objc_notify_register 解析

//
// Note: only for use by objc runtime
// Register handlers to be called when objc images are mapped, unmapped, and initialized.
// Dyld will call back the "mapped" function with an array of images that contain an objc-image-info section.
// Those images that are dylibs will have the ref-counts automatically bumped, so objc will no longer need to
// call dlopen() on them to keep them from being unloaded.  During the call to _dyld_objc_notify_register(),
// dyld will call the "mapped" function with already loaded objc images.  During any later dlopen() call,
// dyld will also call the "mapped" function.  Dyld will call the "init" function when dyld would be called
// initializers in that image.  This is when objc calls any +load methods in that image.
//
// 翻譯如下:
// 注意: 只能在objc runtime 中使用
// 注冊(cè)回調(diào)函數(shù), 當(dāng) objc 庫 映射,未映射,和初始化的時(shí)候調(diào)用
// dyld將要調(diào)用包含objc-image-info的鏡像數(shù)組回調(diào)的“mapped”函數(shù)。
// dyld 會(huì)為這些鏡像自動(dòng)增加引用技術(shù),所以objc 不需要使用dlopen函數(shù)保證它不被卸載。
// 在調(diào)用 `_dyld_objc_notify_register` 的過程中,dyld 會(huì)調(diào)用已經(jīng)加載的鏡像的 mapped 函數(shù)
// 在之后的任何dlopen()調(diào)用期間,dyld也將調(diào)用“映射”函數(shù)。
// 在dyld 調(diào)用鏡像的initializers 的時(shí)候,dyld 將調(diào)用 init
// 這是objc在這個(gè)鏡像中調(diào)用所有+ load方法的時(shí)候。
 void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
                                _dyld_objc_notify_init      init,
                                _dyld_objc_notify_unmapped  unmapped);

_dyld_objc_notify_register 實(shí)現(xiàn)

void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
                                _dyld_objc_notify_init      init,
                                _dyld_objc_notify_unmapped  unmapped)
{
    dyld::registerObjCNotifiers(mapped, init, unmapped);
}

注冊(cè)回調(diào)通知
參數(shù)介紹

  • _dyld_objc_notify_mapped : dyld 將 image 加載進(jìn)內(nèi)存時(shí) , 會(huì)觸發(fā)該函數(shù).
  • _dyld_objc_notify_init : dyld 初始化 image 會(huì)觸發(fā)該方法. ( 我們所熟知的 load 方法也是在此處調(diào)用 ) .
  • unmap__dyld_objc_notify_unmapped: dyld 將 image 移除時(shí) , 會(huì)觸發(fā)該函數(shù) .

這三個(gè)回調(diào)函數(shù) 在runtime 中分別對(duì)應(yīng)著 map_images, load_images, unmap_image

三 map_images 將image 加載進(jìn)內(nèi)存回調(diào)

  • map_images
/***********************************************************************
* map_images
* Process the given images which are being mapped in by dyld.
* Calls ABI-agnostic code after taking ABI-specific locks.
*
* Locking: write-locks runtimeLock
**********************************************************************/
void
map_images(unsigned count, const
 char * const paths[],
           const struct mach_header * const mhdrs[])
{
    mutex_locker_t lock(runtimeLock);
    return map_images_nolock(count, paths, mhdrs);
}

map_images 方法在 image 加載到內(nèi)存的時(shí)候會(huì)觸發(fā)該方法的調(diào)用

  • map_images_nolock
void 
map_images_nolock(unsigned mhCount, const char * const mhPaths[],
                  const struct mach_header * const mhdrs[])
{
    ... 代碼省略

    if (hCount > 0) {
      // 讀取鏡像文件
        _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
    }

    firstTime = NO;
    
    // Call image load funcs after everything is set up.
    for (auto func : loadImageFuncs) {
        for (uint32_t i = 0; i < mhCount; i++) {
            func(mhdrs[i]);
        }
    }
}

四 _read_images 讀取鏡像

主要內(nèi)容是:條件控制只執(zhí)行一次、處理編譯階段SEL混亂的問題、錯(cuò)誤的類處理、加載協(xié)議、分類處理、類的讀取、以及針對(duì)某些非懶加載的在直接進(jìn)行實(shí)現(xiàn)。

我們現(xiàn)在分段進(jìn)行解析,通過 ts.log進(jìn)行分段分析

4.1 創(chuàng)建表

... 省略
if (!doneOnce) {
    doneOnce = YES;
    ...省略
    
    // namedClasses
    // Preoptimized classes don't go in this table.
    // 4/3 is NXMapTable's load factor
    int namedClassesSize = 
        (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
// 實(shí)例化存儲(chǔ)類的哈希表
    gdb_objc_realized_classes =
        NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
        
    ts.log("IMAGE TIMES: first time tasks");
}
  • gdb_objc_realized_classes存儲(chǔ)不在共享緩存且已命名的所有類,其容量是類數(shù)量的4/3
// This is a misnomer: gdb_objc_realized_classes is actually a list of 
// named classes not in the dyld shared cache, whether realized or not.
NXMapTable *gdb_objc_realized_classes;  // exported for debuggers in objc-gdb.h

4.2 sel_registerNameNoLock 處理編譯階段SEL混亂的問題

 // 修復(fù)預(yù)編譯階段的@selector的混亂問題
 static size_t UnfixedSelectors;
  {
        mutex_locker_t lock(selLock);
        for (EACH_HEADER) {
            if (hi->hasPreoptimizedSelectors()) continue;

            bool isBundle = hi->isBundle();
            // 從macho 文件中 獲取方法名稱
            SEL *sels = _getObjc2SelectorRefs(hi, &count);
            UnfixedSelectors += count;
            for (i = 0; i < count; i++) {
                // sel_cname 將 SEL 強(qiáng)轉(zhuǎn)為 char 類型
                const char *name = sel_cname(sels[i]);
                // 注冊(cè) SEL 的操作
                SEL sel = sel_registerNameNoLock(name, isBundle);
                if (sels[i] != sel) {
                    sels[i] = sel;
                }
            }
        }
    }
    ts.log("IMAGE TIMES: fix up selector references");
  • _getObjc2SelectorRefs:其中_getObjc2SelectorRefs的源碼如下,表示獲取Mach-O中的靜態(tài)段__objc_selrefs
//      function name                 content type     section name
GETSECT(_getObjc2SelectorRefs,        SEL,             "__objc_selrefs"); 
GETSECT(_getObjc2MessageRefs,         message_ref_t,   "__objc_msgrefs"); 
GETSECT(_getObjc2ClassRefs,           Class,           "__objc_classrefs");
GETSECT(_getObjc2SuperRefs,           Class,           "__objc_superrefs");
GETSECT(_getObjc2ClassList,           classref_t const,      "__objc_classlist");
GETSECT(_getObjc2NonlazyClassList,    classref_t const,      "__objc_nlclslist");
GETSECT(_getObjc2CategoryList,        category_t * const,    "__objc_catlist");
GETSECT(_getObjc2CategoryList2,       category_t * const,    "__objc_catlist2");
GETSECT(_getObjc2NonlazyCategoryList, category_t * const,    "__objc_nlcatlist");
GETSECT(_getObjc2ProtocolList,        protocol_t * const,    "__objc_protolist");
GETSECT(_getObjc2ProtocolRefs,        protocol_t *,    "__objc_protorefs");
GETSECT(getLibobjcInitializers,       UnsignedInitializer, "__objc_init_func");
  • sel_cname:其中SEL --> sel并不是簡(jiǎn)單的字符串,是帶地址的字符串 如下所示,sels[i]與sel字符串一致,但是地址不一致,所以需要調(diào)整為一致的。即fix up
    image.png

4.3 readClass 重點(diǎn)

    // Discover classes. Fix up unresolved future classes. Mark bundle classes.
    bool hasDyldRoots = dyld_shared_cache_some_image_overridden();
    // 從編譯后的類列表中取出所有類,獲取到的是一個(gè)classref_t類型的指針
    for (EACH_HEADER) {
        if (! mustReadClasses(hi, hasDyldRoots)) {
            // Image is sufficiently optimized that we need not call readClass()
            // 鏡像充分優(yōu)化,我們不需要調(diào)用 readClass()
            continue;
        }

        classref_t const *classlist = _getObjc2ClassList(hi, &count);

        bool headerIsBundle = hi->isBundle();
        bool headerIsPreoptimized = hi->hasPreoptimizedClasses();

        for (i = 0; i < count; i++) {
            //數(shù)組中會(huì)取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunloop等系統(tǒng)類,例如CF、Fundation、libdispatch中的類。以及自己創(chuàng)建的類
            Class cls = (Class)classlist[i];
            // 通過 readClass 函數(shù)獲取處理后的新類,內(nèi)部主要操作 ro 和 rw 結(jié)構(gòu)體
            Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
            // 初始化所有懶加載的類需要的內(nèi)存空間,并將所有的未來需要處理的類添加到一個(gè)數(shù)組中
            // 現(xiàn)在數(shù)據(jù)沒有加載到的,連類都沒有初始化
            if (newCls != cls  &&  newCls) {
                // Class was moved but not deleted. Currently this occurs 
                // only when the new class resolved a future class.
                // Non-lazily realize the class below.
                resolvedFutureClasses = (Class *)
                    realloc(resolvedFutureClasses, 
                            (resolvedFutureClassCount+1) * sizeof(Class));
                resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
            }
        }
    }

    ts.log("IMAGE TIMES: discover classes");
  • read_class

/***********************************************************************
* readClass
* Read a class and metaclass as written by a compiler.
* Returns the new class pointer. This could be: 
* - cls
* - nil  (cls has a missing weak-linked superclass)
* - something else (space for this class was reserved by a future class)
*
* Note that all work performed by this function is preflighted by 
* mustReadClasses(). Do not change this function without updating that one.
*
* Locking: runtimeLock acquired by map_images or objc_readClassPair
**********************************************************************/
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
{
    // 已經(jīng)實(shí)現(xiàn)類從內(nèi)存中讀取,未實(shí)現(xiàn)的類從 mach-o 中讀取
    const char *mangledName = cls->mangledName();
 // 測(cè)試代碼
    const char *LGPersonName = "LGPerson";
    if (strcmp(mangledName, LGPersonName) == 0) {
        printf("%s ---- %s",__func__ , mangledName);
    }
    // 如果某個(gè) cls 的 superclass 是 weak-linked 的并且丟失了,則返回YES。
    if (missingWeakSuperclass(cls)) {
        // No superclass (probably weak-linked). 
        // Disavow any knowledge of this subclass.
        if (PrintConnecting) {
            _objc_inform("CLASS: IGNORING class '%s' with "
                         "missing weak-linked superclass", 
                         cls->nameForLogging());
        }
        // 添加到重映射表里面,映射為 nil
        addRemappedClass(cls, nil);
        cls->superclass = nil;
        return nil;
    }
    
    cls->fixupBackwardDeployingStableSwift();

    Class replacing = nil;
    if (Class newCls = popFutureNamedClass(mangledName)) {
        // This name was previously allocated as a future class.
        // Copy objc_class to future class's struct.
        // Preserve future's rw data block.
        
        if (newCls->isAnySwift()) {
            _objc_fatal("Can't complete future class request for '%s' "
                        "because the real class is too big.", 
                        cls->nameForLogging());
        }
        
        class_rw_t *rw = newCls->data();
        const class_ro_t *old_ro = rw->ro();
        memcpy(newCls, cls, sizeof(objc_class));
        rw->set_ro((class_ro_t *)newCls->data());
        newCls->setData(rw);
        freeIfMutable((char *)old_ro->name);
        free((void *)old_ro);
        
        addRemappedClass(cls, newCls);
        
        replacing = cls;
        cls = newCls;
    }
    
    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 {
// 重點(diǎn):從mach-o 文件讀取插入到這兩個(gè)表里面,自此在內(nèi)存中就可以讀到這個(gè)類了
        // 將 cls 加入到 gdb_objc_realized_classes 表里面去
        addNamedClass(cls, mangledName, replacing);
        // 將 cls 插入到 allocatedClasses 表里面去
        addClassTableEntry(cls);
    }

    // for future reference: shared cache never contains MH_BUNDLEs
    if (headerIsBundle) {
        cls->data()->flags |= RO_FROM_BUNDLE;
        cls->ISA()->data()->flags |= RO_FROM_BUNDLE;
    }
    // 返回這個(gè)類
    return cls;
}
  • addNamedClass
    將當(dāng)前類添加到已創(chuàng)建好的gdb_objc_realized_classes哈希表(存放所有類)
/***********************************************************************
* addNamedClass
* Adds name => cls to the named non-meta class map.
* Warns about duplicate class names and keeps the old mapping.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static void addNamedClass(Class cls, const char *name, Class replacing = nil)
{
    runtimeLock.assertLocked();
    Class old;
    if ((old = getClassExceptSomeSwift(name))  &&  old != replacing) {
        inform_duplicate(name, old, cls);

        // getMaybeUnrealizedNonMetaClass uses name lookups.
        // Classes not found by name lookup must be in the
        // secondary meta->nonmeta table.
        addNonMetaClass(cls);
    } else {
      // 將類名插入類表中
        NXMapInsert(gdb_objc_realized_classes, name, cls);
    }
    ASSERT(!(cls->data()->flags & RO_META));

    // wrong: constructed classes are already realized when they get here
    // ASSERT(!cls->isRealized());
}
  • addClassTableEntry
    當(dāng)前類已經(jīng)初始化,所以要添加到allocatedClasses哈希表,并添加元類
/***********************************************************************
* addClassTableEntry
* Add a class to the table of all classes. If addMeta is true,
* automatically adds the metaclass of the class as well.
* Locking: runtimeLock must be held by the caller.
**********************************************************************/
static void
addClassTableEntry(Class cls, bool addMeta = true)
{
    runtimeLock.assertLocked();

    // This class is allowed to be a known class via the shared cache or via
    // data segments, but it is not allowed to be in the dynamic table already.
    // 將本類 和 元類添加到類表中
    auto &set = objc::allocatedClasses.get();

    ASSERT(set.find(cls) == set.end());
    // 未識(shí)別的類
    if (!isKnownClass(cls))
        set.insert(cls);
    if (addMeta)
        addClassTableEntry(cls->ISA(), false);
    // 開辟空間-元類遞歸-元類開辟空間-元類名稱插入類表
}
  • 注意: 第三步 類處理(readClass)中 內(nèi)部并沒有完成類的加載,只是將類名 和 類地址 記錄到了類表中

4.4 修復(fù)重映射

// 將未映射Class和Super Class重映射,被remap的類都是非懶加載的類

    // Fix up remapped classes
    // Class list and nonlazy class list remain unremapped.
    // Class refs and super refs are remapped for message dispatching.
    
    if (!noClassesRemapped()) {
        for (EACH_HEADER) {
            // 重映射Class,注意是從_getObjc2ClassRefs函數(shù)中取出類的引用
            Class *classrefs = _getObjc2ClassRefs(hi, &count);
            for (i = 0; i < count; i++) {
                remapClassRef(&classrefs[i]);
            }
            // fixme why doesn't test future1 catch the absence of this?
            classrefs = _getObjc2SuperRefs(hi, &count);
            for (i = 0; i < count; i++) {
                remapClassRef(&classrefs[i]);
            }
        }
    }

    ts.log("IMAGE TIMES: remap classes");

4.5 fixupMessageRef: 修復(fù)舊的函數(shù)指針調(diào)用遺留

    // Fix up old objc_msgSend_fixup call sites
    for (EACH_HEADER) {
        message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
        if (count == 0) continue;

        if (PrintVtables) {
            _objc_inform("VTABLES: repairing %zu unsupported vtable dispatch "
                         "call sites in %s", count, hi->fname());
        }
        for (i = 0; i < count; i++) {
         // 內(nèi)部將常用的alloc、objc_msgSend等函數(shù)指針進(jìn)行注冊(cè),并fix為新的函數(shù)指針
            fixupMessageRef(refs+i);
        }
    }

    ts.log("IMAGE TIMES: fix up objc_msgSend_fixup");

4.6 readProtocol :讀取并初始化Protocol


    bool cacheSupportsProtocolRoots = sharedCacheSupportsProtocolRoots();

    // Discover protocols. Fix up protocol refs.
// 遍歷所有協(xié)議列表,并且將協(xié)議列表加載到Protocol的哈希表中
    for (EACH_HEADER) {
        extern objc_class OBJC_CLASS_$_Protocol;
        // 獲取協(xié)議類 cls = Protocol類
        Class cls = (Class)&OBJC_CLASS_$_Protocol;
        ASSERT(cls);
    // 獲取protocol哈希表
        NXMapTable *protocol_map = protocols();
        bool isPreoptimized = hi->hasPreoptimizedProtocols();

        // Skip reading protocols if this is an image from the shared cache
        // and we support roots
        // Note, after launch we do need to walk the protocol as the protocol
        // in the shared cache is marked with isCanonical() and that may not
        // be true if some non-shared cache binary was chosen as the canonical
        // definition
        if (launchTime && isPreoptimized && cacheSupportsProtocolRoots) {
            if (PrintProtocols) {
                _objc_inform("PROTOCOLS: Skipping reading protocols in image: %s",
                             hi->fname());
            }
            continue;
        }

        bool isBundle = hi->isBundle();
        // 從編譯器中讀取并初始化Protocol
        protocol_t * const *protolist = _getObjc2ProtocolList(hi, &count);
        for (i = 0; i < count; i++) {
            readProtocol(protolist[i], cls, protocol_map, 
                         isPreoptimized, isBundle);
        }
 ts.log("IMAGE TIMES: discover protocols");

4.7 修復(fù)協(xié)議列表引用

// Fix up @protocol references
    // Preoptimized images may have the right 
    // answer already but we don't know for sure.
   // 修復(fù)協(xié)議列表引用,優(yōu)化后的images可能是正確的,但是并不確定
    for (EACH_HEADER) {
        // At launch time, we know preoptimized image refs are pointing at the
        // shared cache definition of a protocol.  We can skip the check on
        // launch, but have to visit @protocol refs for shared cache images
        // loaded later.
        if (launchTime && cacheSupportsProtocolRoots && hi->isPreoptimized())
            continue;
// 需要注意到是,下面的函數(shù)是_getObjc2ProtocolRefs,和上面的_getObjc2ProtocolList不一樣
        protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);
        for (i = 0; i < count; i++) {
            remapProtocolRef(&protolist[i]);
        }
    }

    ts.log("IMAGE TIMES: fix up @protocol references");

4.8 分類的加載

    // Discover categories. Only do this after the initial category
    // attachment has been done. For categories present at startup,
    // discovery is deferred until the first load_images call after
    // the call to _dyld_objc_notify_register completes. rdar://problem/53119145
    // 發(fā)現(xiàn)分類。僅在完成初始類別附件后才執(zhí)行此操作。 對(duì)于啟動(dòng)時(shí)出現(xiàn)的類別,發(fā)現(xiàn)將推遲到對(duì)_dyld_objc_notify_register的調(diào)用完成后的第一個(gè)load_images調(diào)用為止。
    if (didInitialAttachCategories) {
        for (EACH_HEADER) {
            load_categories_nolock(hi);
        }
    }

    ts.log("IMAGE TIMES: discover categories");

4.9 非懶加載的類

非懶加載類定義:實(shí)現(xiàn)了+load方法 和 靜態(tài)初始化的類是非懶加載類,否則就是懶加載類


    // Category discovery MUST BE Late to avoid potential races
    // when other threads call the new category code before
    // this thread finishes its fixups.

    // +load handled by prepare_load_methods()

    // Realize non-lazy classes (for +load methods and static instances)
    for (EACH_HEADER) {
        classref_t const *classlist = 
            _getObjc2NonlazyClassList(hi, &count);
        for (i = 0; i < count; i++) {
            Class cls = remapClass(classlist[i]);
            if (!cls) continue;

            addClassTableEntry(cls);

            if (cls->isSwiftStable()) {
                if (cls->swiftMetadataInitializer()) {
                    _objc_fatal("Swift class %s with a metadata initializer "
                                "is not allowed to be non-lazy",
                                cls->nameForLogging());
                }
                // fixme also disallow relocatable classes
                // We can't disallow all Swift classes because of
                // classes like Swift.__EmptyArrayStorage
            }
        // 實(shí)現(xiàn)所有非懶加載的類(實(shí)例化類對(duì)象的一些信息,例如rw)
            realizeClassWithoutSwift(cls, nil);
        }
    }

    ts.log("IMAGE TIMES: realize non-lazy classes");
  • _getObjc2NonlazyClassList獲取到__objc_nlclslist,取出非懶加載類

  • addClassTableEntry 再加載一遍——如果已添加就不會(huì)添加進(jìn)去,確保整個(gè)結(jié)構(gòu)都被添加

  • realizeClassWithoutSwift是接下來要關(guān)注的地方

  • realizeClassWithoutSwift 分析

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

    class_rw_t *rw;
    Class supercls;
    Class metacls;

    if (!cls) return nil;
    if (cls->isRealized()) return cls;
    // 判斷 cls 是否已經(jīng)初始化,里面是對(duì) data()->flags 的判斷
    ASSERT(cls == remapClass(cls));

    // fixme verify class is not in an un-dlopened part of the shared cache?
    // 驗(yàn)證類不在共享緩存的未刪除部分
    auto ro = (const class_ro_t *)cls->data();
    // 判斷類是否是未實(shí)現(xiàn)的未來類
    auto isMeta = ro->flags & RO_META;
    if (ro->flags & RO_FUTURE) {
        // 是未來的類. rw 已經(jīng)被初始化
        rw = cls->data();
        ro = cls->data()->ro();
        ASSERT(!isMeta);
        // 修改 flags
        cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
    } else {
        // Normal class. Allocate writeable class data.
        // 正常的類. 分配可寫的類數(shù)據(jù)。
        // 開辟 rw 內(nèi)存空間
        rw = objc::zalloc<class_rw_t>();
        rw->set_ro(ro);
        rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
        cls->setData(rw);
// 注: rw ro rwe
//
    }
    // 判斷是否是元類
#if FAST_CACHE_META
    if (isMeta) cls->cache.setBit(FAST_CACHE_META);
#endif

    // Choose an index for this class.
    // Sets cls->instancesRequireRawIsa if indexes no more indexes are available
    // 設(shè)置cls->instancesRequireRawIsa如果沒有更多的索引可用
    cls->chooseClassArrayIndex();

    if (PrintConnecting) {
        _objc_inform("CLASS: realizing class '%s'%s %p %p #%u %s%s",
                     cls->nameForLogging(), isMeta ? " (meta)" : "", 
                     (void*)cls, ro, cls->classArrayIndex(),
                     cls->isSwiftStable() ? "(swift)" : "",
                     cls->isSwiftLegacy() ? "(pre-stable swift)" : "");
    }
    // Realize superclass and metaclass, if they aren't already.
    // This needs to be done after RW_REALIZED is set above, for root classes.
    // This needs to be done after class index is chosen, for root metaclasses.
    // This assumes that none of those classes have Swift contents,
    //   or that Swift's initializers have already been called.
    //   fixme that assumption will be wrong if we add support
    //   for ObjC subclasses of Swift classes.
    // 遞歸調(diào)用,實(shí)現(xiàn)父類和元類
    supercls = realizeClassWithoutSwift(remapClass(cls->superclass), nil);
    metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);

#if SUPPORT_NONPOINTER_ISA
    if (isMeta) {
        // Metaclasses do not need any features from non pointer ISA
        // This allows for a faspath for classes in objc_retain/objc_release.
        cls->setInstancesRequireRawIsa();
    } else {
        // Disable non-pointer isa for some classes and/or platforms.
        // Set instancesRequireRawIsa.
        // 禁用一些類和非指針isa
        bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
        bool rawIsaIsInherited = false;
        static bool hackedDispatch = false;
        // 禁用非指針的 isa
        if (DisableNonpointerIsa) {
            // Non-pointer isa disabled by environment or app SDK version
            // 非指針isa禁用的環(huán)境或應(yīng)用程序SDK版本
            instancesRequireRawIsa = true;
        }
        else if (!hackedDispatch  &&  0 == strcmp(ro->name, "OS_object"))
        {
            // 在 hackedDispatch 里 isa 也充當(dāng)虛表指針
            hackedDispatch = true;
            instancesRequireRawIsa = true;
        }
        else if (supercls  &&  supercls->superclass  &&
                 supercls->instancesRequireRawIsa())
        {
            // 從元類到根元類設(shè)置
            instancesRequireRawIsa = true;
            rawIsaIsInherited = true;
        }

        if (instancesRequireRawIsa) {
            cls->setInstancesRequireRawIsaRecursively(rawIsaIsInherited);
        }
    }
// SUPPORT_NONPOINTER_ISA
#endif
    // 在重新映射時(shí)更新父類和元類
    // Update superclass and metaclass in case of remapping
    cls->superclass = supercls;
    cls->initClassIsa(metacls);

    // 協(xié)調(diào)實(shí)例變量的偏移量/布局,可能會(huì)重新分配 class_ro_t,更新我們的 ro 變量。
    if (supercls  &&  !isMeta) reconcileInstanceVariables(cls, supercls, ro);

    // 如果還沒有設(shè)置就開始設(shè)置 fastInstanceSize。
    cls->setInstanceSize(ro->instanceSize);

    // 將一些標(biāo)志從 ro 復(fù)制到 rw
    if (ro->flags & RO_HAS_CXX_STRUCTORS) {
        cls->setHasCxxDtor();
        if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
            cls->setHasCxxCtor();
        }
    }
    
    
    // 從ro或父類中傳播關(guān)聯(lián)的對(duì)象禁止標(biāo)志
    if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
        (supercls && supercls->forbidsAssociatedObjects()))
    {
        rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
    }

    // 將這個(gè)類連接到它的父類的子類列表,即雙向綁定
    if (supercls) {
        addSubclass(supercls, cls);
    } else {
        addRootClass(cls);
    }

    // 整理 cls 的方法列表、協(xié)議列表和屬性列表,以及附加任何未完成的類別
    methodizeClass(cls, previously);

    return cls;
}

  • methodizeClass 分析

/***********************************************************************
* methodizeClass
* Fixes up cls's method list, protocol list, and property list.
* Attaches any outstanding categories.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
//方法的序列化
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();

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

    // Install methods and properties that the class implements itself.
    // 將 ro 里面的方法附加到 rw 里面去
    method_list_t *list = ro->baseMethods();
    if (list) {
        prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
        if (rwe) rwe->methods.attachLists(&list, 1);
    }
 // 將 ro 里面的屬性附加到 rw 里面去
    property_list_t *proplist = ro->baseProperties;
    if (rwe && proplist) {
        rwe->properties.attachLists(&proplist, 1);
    }
    // 將 ro 里面的協(xié)議附加到 rw 里面去
    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.
    // 根類獲得額外的方法實(shí)現(xiàn),如果它們還沒有。這些適用于類別替換之前。
    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);

#if DEBUG
    // Debug: sanity-check all SELs; log method list contents
    for (const auto& meth : rw->methods()) {
        if (PrintConnecting) {
            _objc_inform("METHOD %c[%s %s]", isMeta ? '+' : '-', 
                         cls->nameForLogging(), sel_getName(meth.name));
        }
        ASSERT(sel_registerName(sel_getName(meth.name)) == meth.name); 
    }
#endif
}
  • attachLists 分析
// 基本上方法、協(xié)議、屬性都是通過 attachLists 函數(shù)附加到對(duì)應(yīng)的列表上的
void attachLists(List* const * addedLists, uint32_t addedCount) {
    if (addedCount == 0) return;

    if (hasArray()) {
        // many lists -> many lists
        //計(jì)算數(shù)組中舊lists的大小
        uint32_t oldCount = array()->count;
        //計(jì)算新的容量大小 = 舊數(shù)據(jù)大小+新數(shù)據(jù)大小
        uint32_t newCount = oldCount + addedCount;
        //根據(jù)新的容量大小,開辟一個(gè)數(shù)組,類型是 array_t,通過array()獲取
        setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
        //設(shè)置數(shù)組大小
        array()->count = newCount;
        //舊的數(shù)據(jù)從 addedCount 數(shù)組下標(biāo)開始 存放舊的lists,大小為 舊數(shù)據(jù)大小 * 單個(gè)舊list大小
        memmove(array()->lists + addedCount, array()->lists, 
                oldCount * sizeof(array()->lists[0]));
        //新數(shù)據(jù)從數(shù)組 首位置開始存儲(chǔ),存放新的lists,大小為 新數(shù)據(jù)大小 * 單個(gè)list大小
        memcpy(
               array()->lists, addedLists, 
               addedCount * sizeof(array()->lists[0]));
    }
    else if (!list  &&  addedCount == 1) {
        // 0 lists -> 1 list
        list = addedLists[0];//將list加入mlists的第一個(gè)元素,此時(shí)的list是一個(gè)一維數(shù)組
    } 
    else {
        // 1 list -> many lists 有了一個(gè)list,有往里加很多l(xiāng)ist
        //新的list就是分類,來自LRU的算法思維,即最近最少使用
        //獲取舊的list
        List* oldList = list;
        uint32_t oldCount = oldList ? 1 : 0;
        //計(jì)算容量和 = 舊list個(gè)數(shù)+新lists的個(gè)數(shù)
        uint32_t newCount = oldCount + addedCount;
        //開辟一個(gè)容量和大小的集合,類型是 array_t,即創(chuàng)建一個(gè)數(shù)組,放到array中,通過array()獲取
        setArray((array_t *)malloc(array_t::byteSize(newCount)));
        //設(shè)置數(shù)組的大小
        array()->count = newCount;
        //判斷old是否存在,old肯定是存在的,將舊的list放入到數(shù)組的末尾
        if (oldList) array()->lists[addedCount] = oldList;
        // memcpy(開始位置,放什么,放多大) 是內(nèi)存平移,從數(shù)組起始位置存入新的list
        //其中array()->lists 表示首位元素位置
        memcpy(array()->lists, addedLists, 
               addedCount * sizeof(array()->lists[0]));
    }
}

map_images.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容