十 类的加载-前篇 (map_images)

前言

前篇 我们了解到 应用的加载流程,在main 函数调用之前有许多系统的操作流程,但是在分析类的加载需要明确的是main 函数才是我们app程序的入口函数,我们知道 在执行main函数之前,系统会对runtime进行初始化,在之前我们了解到dyld会调用 runtime的入口函数,runtime的入口函数 就是 _objc_iinnit,它就是在 mian 函数之前就被dyld调用,而load方法就在 _objc_init中调用,所以 我们探究的起点就是 _objc_init函数

image.png

一 _objc_init 探究分析

我们在runtime的源码中 可以了解到_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(); // 环境变量
    tls_init(); //线程 key 的绑定
    static_init(); //初始化系统内置的 C++ 静态构造函数
    runtime_init(); //主要是运行时的初始化,主要分为两部分:分类初始化(unattachedCategories)和类的表初始化(allocatedClasses)
    exception_init(); // 初始化libobjc异常处理
    cache_init(); //缓存初始化
    _imp_implementationWithBlock_init(); //启动机制回调
    // 注册回调通知
    _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 中使用
// 注册回调函数, 当 objc 库 映射,未映射,和初始化的时候调用
// dyld将要调用包含objc-image-info的镜像数组回调的“mapped”函数。
// dyld 会为这些镜像自动增加引用技术,所以objc 不需要使用dlopen函数保证它不被卸载。
// 在调用 `_dyld_objc_notify_register` 的过程中,dyld 会调用已经加载的镜像的 mapped 函数
// 在之后的任何dlopen()调用期间,dyld也将调用“映射”函数。
// 在dyld 调用镜像的initializers 的时候,dyld 将调用 init
// 这是objc在这个镜像中调用所有+ load方法的时候。
 void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
                                _dyld_objc_notify_init      init,
                                _dyld_objc_notify_unmapped  unmapped);

_dyld_objc_notify_register 实现

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

注册回调通知
参数介绍

  • _dyld_objc_notify_mapped : dyld 将 image 加载进内存时 , 会触发该函数.
  • _dyld_objc_notify_init : dyld 初始化 image 会触发该方法. ( 我们所熟知的 load 方法也是在此处调用 ) .
  • unmap__dyld_objc_notify_unmapped: dyld 将 image 移除时 , 会触发该函数 .

这三个回调函数 在runtime 中分别对应着 map_images, load_images, unmap_image

三 map_images 将image 加载进内存回调

  • 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 加载到内存的时候会触发该方法的调用

  • 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 读取镜像

主要内容是:条件控制只执行一次、处理编译阶段SEL混乱的问题、错误的类处理、加载协议、分类处理、类的读取、以及针对某些非懒加载的在直接进行实现。

我们现在分段进行解析,通过 ts.log进行分段分析

4.1 创建表

... 省略
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;
// 实例化存储类的哈希表
    gdb_objc_realized_classes =
        NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
        
    ts.log("IMAGE TIMES: first time tasks");
}
  • gdb_objc_realized_classes存储不在共享缓存且已命名的所有类,其容量是类数量的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混乱的问题

 // 修复预编译阶段的@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 强转为 char 类型
                const char *name = sel_cname(sels[i]);
                // 注册 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中的静态段__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并不是简单的字符串,是带地址的字符串 如下所示,sels[i]与sel字符串一致,但是地址不一致,所以需要调整为一致的。即fix up
    image.png

4.3 readClass 重点

    // Discover classes. Fix up unresolved future classes. Mark bundle classes.
    bool hasDyldRoots = dyld_shared_cache_some_image_overridden();
    // 从编译后的类列表中取出所有类,获取到的是一个classref_t类型的指针
    for (EACH_HEADER) {
        if (! mustReadClasses(hi, hasDyldRoots)) {
            // Image is sufficiently optimized that we need not call readClass()
            // 镜像充分优化,我们不需要调用 readClass()
            continue;
        }

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

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

        for (i = 0; i < count; i++) {
            //数组中会取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunloop等系统类,例如CF、Fundation、libdispatch中的类。以及自己创建的类
            Class cls = (Class)classlist[i];
            // 通过 readClass 函数获取处理后的新类,内部主要操作 ro 和 rw 结构体
            Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
            // 初始化所有懒加载的类需要的内存空间,并将所有的未来需要处理的类添加到一个数组中
            // 现在数据没有加载到的,连类都没有初始化
            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)
{
    // 已经实现类从内存中读取,未实现的类从 mach-o 中读取
    const char *mangledName = cls->mangledName();
 // 测试代码
    const char *LGPersonName = "LGPerson";
    if (strcmp(mangledName, LGPersonName) == 0) {
        printf("%s ---- %s",__func__ , mangledName);
    }
    // 如果某个 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 {
// 重点:从mach-o 文件读取插入到这两个表里面,自此在内存中就可以读到这个类了
        // 将 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;
    }
    // 返回这个类
    return cls;
}
  • addNamedClass
    将当前类添加到已创建好的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
    当前类已经初始化,所以要添加到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());
    // 未识别的类
    if (!isKnownClass(cls))
        set.insert(cls);
    if (addMeta)
        addClassTableEntry(cls->ISA(), false);
    // 开辟空间-元类递归-元类开辟空间-元类名称插入类表
}
  • 注意: 第三步 类处理(readClass)中 内部并没有完成类的加载,只是将类名 和 类地址 记录到了类表中

4.4 修复重映射

// 将未映射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函数中取出类的引用
            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: 修复旧的函数指针调用遗留

    // 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++) {
         // 内部将常用的alloc、objc_msgSend等函数指针进行注册,并fix为新的函数指针
            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.
// 遍历所有协议列表,并且将协议列表加载到Protocol的哈希表中
    for (EACH_HEADER) {
        extern objc_class OBJC_CLASS_$_Protocol;
        // 获取协议类 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 修复协议列表引用

// Fix up @protocol references
    // Preoptimized images may have the right 
    // answer already but we don't know for sure.
   // 修复协议列表引用,优化后的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;
// 需要注意到是,下面的函数是_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
    // 发现分类。仅在完成初始类别附件后才执行此操作。 对于启动时出现的类别,发现将推迟到对_dyld_objc_notify_register的调用完成后的第一个load_images调用为止。
    if (didInitialAttachCategories) {
        for (EACH_HEADER) {
            load_categories_nolock(hi);
        }
    }

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

4.9 非懒加载的类

非懒加载类定义:实现了+load方法 和 静态初始化的类是非懒加载类,否则就是懒加载类


    // 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
            }
        // 实现所有非懒加载的类(实例化类对象的一些信息,例如rw)
            realizeClassWithoutSwift(cls, nil);
        }
    }

    ts.log("IMAGE TIMES: realize non-lazy classes");
  • _getObjc2NonlazyClassList获取到__objc_nlclslist,取出非懒加载类

  • addClassTableEntry 再加载一遍——如果已添加就不会添加进去,确保整个结构都被添加

  • realizeClassWithoutSwift是接下来要关注的地方

  • 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 是否已经初始化,里面是对 data()->flags 的判断
    ASSERT(cls == remapClass(cls));

    // fixme verify class is not in an un-dlopened part of the shared cache?
    // 验证类不在共享缓存的未删除部分
    auto ro = (const class_ro_t *)cls->data();
    // 判断类是否是未实现的未来类
    auto isMeta = ro->flags & RO_META;
    if (ro->flags & RO_FUTURE) {
        // 是未来的类. rw 已经被初始化
        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.
        // 正常的类. 分配可写的类数据。
        // 开辟 rw 内存空间
        rw = objc::zalloc();
        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
    // 设置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.
    // 递归调用,实现父类和元类
    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禁用的环境或应用程序SDK版本
            instancesRequireRawIsa = true;
        }
        else if (!hackedDispatch  &&  0 == strcmp(ro->name, "OS_object"))
        {
            // 在 hackedDispatch 里 isa 也充当虚表指针
            hackedDispatch = true;
            instancesRequireRawIsa = true;
        }
        else if (supercls  &&  supercls->superclass  &&
                 supercls->instancesRequireRawIsa())
        {
            // 从元类到根元类设置
            instancesRequireRawIsa = true;
            rawIsaIsInherited = true;
        }

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

    // 协调实例变量的偏移量/布局,可能会重新分配 class_ro_t,更新我们的 ro 变量。
    if (supercls  &&  !isMeta) reconcileInstanceVariables(cls, supercls, ro);

    // 如果还没有设置就开始设置 fastInstanceSize。
    cls->setInstanceSize(ro->instanceSize);

    // 将一些标志从 ro 复制到 rw
    if (ro->flags & RO_HAS_CXX_STRUCTORS) {
        cls->setHasCxxDtor();
        if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
            cls->setHasCxxCtor();
        }
    }
    
    
    // 从ro或父类中传播关联的对象禁止标志
    if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
        (supercls && supercls->forbidsAssociatedObjects()))
    {
        rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
    }

    // 将这个类连接到它的父类的子类列表,即双向绑定
    if (supercls) {
        addSubclass(supercls, cls);
    } else {
        addRootClass(cls);
    }

    // 整理 cls 的方法列表、协议列表和属性列表,以及附加任何未完成的类别
    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 里面的协议附加到 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.
    // 根类获得额外的方法实现,如果它们还没有。这些适用于类别替换之前。
    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 分析
// 基本上方法、协议、属性都是通过 attachLists 函数附加到对应的列表上的
void attachLists(List* const * addedLists, uint32_t addedCount) {
    if (addedCount == 0) return;

    if (hasArray()) {
        // many lists -> many lists
        //计算数组中旧lists的大小
        uint32_t oldCount = array()->count;
        //计算新的容量大小 = 旧数据大小+新数据大小
        uint32_t newCount = oldCount + addedCount;
        //根据新的容量大小,开辟一个数组,类型是 array_t,通过array()获取
        setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
        //设置数组大小
        array()->count = newCount;
        //旧的数据从 addedCount 数组下标开始 存放旧的lists,大小为 旧数据大小 * 单个旧list大小
        memmove(array()->lists + addedCount, array()->lists, 
                oldCount * sizeof(array()->lists[0]));
        //新数据从数组 首位置开始存储,存放新的lists,大小为 新数据大小 * 单个list大小
        memcpy(
               array()->lists, addedLists, 
               addedCount * sizeof(array()->lists[0]));
    }
    else if (!list  &&  addedCount == 1) {
        // 0 lists -> 1 list
        list = addedLists[0];//将list加入mlists的第一个元素,此时的list是一个一维数组
    } 
    else {
        // 1 list -> many lists 有了一个list,有往里加很多list
        //新的list就是分类,来自LRU的算法思维,即最近最少使用
        //获取旧的list
        List* oldList = list;
        uint32_t oldCount = oldList ? 1 : 0;
        //计算容量和 = 旧list个数+新lists的个数
        uint32_t newCount = oldCount + addedCount;
        //开辟一个容量和大小的集合,类型是 array_t,即创建一个数组,放到array中,通过array()获取
        setArray((array_t *)malloc(array_t::byteSize(newCount)));
        //设置数组的大小
        array()->count = newCount;
        //判断old是否存在,old肯定是存在的,将旧的list放入到数组的末尾
        if (oldList) array()->lists[addedCount] = oldList;
        // memcpy(开始位置,放什么,放多大) 是内存平移,从数组起始位置存入新的list
        //其中array()->lists 表示首位元素位置
        memcpy(array()->lists, addedLists, 
               addedCount * sizeof(array()->lists[0]));
    }
}

map_images.png

你可能感兴趣的:(十 类的加载-前篇 (map_images))