系统层知识OC 底层

iOS底层原理之类的加载处理

2020-01-10  本文已影响0人  尘舒

1. _objc_init

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();
    static_init();
    lock_init();
    exception_init();

    _dyld_objc_notify_register(&map_images, load_images, unmap_image);
}

1.1 environ_init

objc[3206]: Objective-C runtime debugging. Set variable=YES to enable.
objc[3206]: OBJC_HELP: describe available environment variables
objc[3206]: OBJC_PRINT_OPTIONS: list which options are set
objc[3206]: OBJC_PRINT_IMAGES: log image and library names as they are loaded
objc[3206]: OBJC_PRINT_IMAGE_TIMES: measure duration of image loading steps
objc[3206]: OBJC_PRINT_LOAD_METHODS: log calls to class and category +load methods
objc[3206]: OBJC_PRINT_INITIALIZE_METHODS: log calls to class +initialize methods
objc[3206]: OBJC_PRINT_RESOLVED_METHODS: log methods created by +resolveClassMethod: and +resolveInstanceMethod:
objc[3206]: OBJC_PRINT_CLASS_SETUP: log progress of class and category setup
objc[3206]: OBJC_PRINT_PROTOCOL_SETUP: log progress of protocol setup
objc[3206]: OBJC_PRINT_IVAR_SETUP: log processing of non-fragile ivars
objc[3206]: OBJC_PRINT_VTABLE_SETUP: log processing of class vtables
objc[3206]: OBJC_PRINT_VTABLE_IMAGES: print vtable images showing overridden methods
objc[3206]: OBJC_PRINT_CACHE_SETUP: log processing of method caches

1.2 tls_init

1.3 static_init

1.4 lock_init

1.5 exception_init

1.6 小结

//
// 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.
//
void _dyld_objc_notify_register(_dyld_objc_notify_mapped    mapped,
                                _dyld_objc_notify_init      init,
                                _dyld_objc_notify_unmapped  unmapped);

2. 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);
}
    if (hCount > 0) {
        _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
    }

2.1 read_images

// 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);
        
        allocatedClasses = NXCreateHashTable(NXPtrPrototype, 0, nil);
    // 1. 初次进入,创建两张表
    if (!doneOnce) {
        doneOnce = YES;
        /** ... */
    }

    // 2. 类处理
    // Discover classes. Fix up unresolved future classes. Mark bundle classes.
    for (EACH_HEADER) {...}
    ts.log("IMAGE TIMES: discover classes");

    // 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) {...}
    }

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

    
    // 3. 方法编号处理
    // Fix up @selector references
    for (EACH_HEADER) {...}
    ts.log("IMAGE TIMES: fix up selector references");

    
    // 修复处理,一般不会走
#if SUPPORT_FIXUP
    // Fix up old objc_msgSend_fixup call sites
    for (EACH_HEADER) {...}
    ts.log("IMAGE TIMES: fix up objc_msgSend_fixup");
#endif

    // 4. 协议处理
    // Discover protocols. Fix up protocol refs.
    for (EACH_HEADER) {...}
    ts.log("IMAGE TIMES: discover protocols");

    // 修复处理,忽略
    // Fix up @protocol references
    // Preoptimized images may have the right 
    // answer already but we don't know for sure.
    for (EACH_HEADER) {...}
    ts.log("IMAGE TIMES: fix up @protocol references");

    // 5. 非懒加载类的处理
    // Realize non-lazy classes (for +load methods and static instances)
    for (EACH_HEADER) {...}
    ts.log("IMAGE TIMES: realize non-lazy classes");

    // 6. 将来需要处理的类
    // Realize newly-resolved future classes, in case CF manipulates them
    if (resolvedFutureClasses) {...}
    ts.log("IMAGE TIMES: realize future classes");

    // 7. 分类处理
    // Discover categories. 
    for (EACH_HEADER) {...}
    ts.log("IMAGE TIMES: discover categories");

2.2 类的处理

2.2.1 分析
        for (i = 0; i < count; i++) {
            //数组中会取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunloop等系统类,例如CF、Fundation、libdispatch中的类。 以及自己创建的类,
            //此时只有地址,还没有获取到具体的类名,类的信息在下一步获取
            Class cls = (Class)classlist[i];
            
            // 通过readClass函数获取处理后的新类,
            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;
            }
        }
2.2.2 readClass初步分析
 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.
        printf("******** popFutureNamedClass \n");
        
        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->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;
    }
printf("******** popFutureNamedClass \n");
// 验证方式, 这段代码放在上面那段 上面执行
    const class_ro_t *lgro = (const class_ro_t *)cls->data();
    const char *lgname     = lgro->name;
    const char *lgnameTest = "LGPerson";
    if (strcmp(lgname, lgnameTest) == 0) {
        printf("******** LGPerson\n");
    }
******** LGPerson
2020-01-09 23:16:22.008399+0800 objc-debug[4032:140200] +[LGTeacher load]
2020-01-09 23:16:22.008904+0800 objc-debug[4032:140200] +[LGStudent load]
2.2.3 readClass进一步探索
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);
    }
/***********************************************************************
* 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
* 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.
    assert(!NXHashMember(allocatedClasses, cls));

    if (!isKnownClass(cls))
        NXHashInsert(allocatedClasses, cls);
    if (addMeta)
        addClassTableEntry(cls->ISA(), false);
}
2.2.4 readClass延伸
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;
}       

2.3 方法编号和协议处理

// 将所有SEL都注册到哈希表中,是另外一张哈希表
    // Fix up @selector references
    static size_t UnfixedSelectors;
    {
        mutex_locker_t lock(selLock);
        for (EACH_HEADER) {
            if (hi->isPreoptimized()) continue;
            
            bool isBundle = hi->isBundle();
            SEL *sels = _getObjc2SelectorRefs(hi, &count);
            UnfixedSelectors += count;
            for (i = 0; i < count; i++) {
                const char *name = sel_cname(sels[i]);
                // 注册SEL的操作
                sels[i] = sel_registerNameNoLock(name, isBundle);
            }
        }
    }
// Discover protocols. Fix up protocol refs.
    // 遍历所有协议列表,并且将协议列表加载到Protocol的哈希表中
    for (EACH_HEADER) {
        extern objc_class OBJC_CLASS_$_Protocol;
        // cls = Protocol类,所有协议和对象的结构体都类似,isa都对应Protocol类
        Class cls = (Class)&OBJC_CLASS_$_Protocol;
        assert(cls);
        // 获取protocol哈希表
        NXMapTable *protocol_map = protocols();
        bool isPreoptimized = hi->isPreoptimized();
        bool isBundle = hi->isBundle();

        // 从编译器中读取并初始化Protocol
        protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
        for (i = 0; i < count; i++) {
            readProtocol(protolist[i], cls, protocol_map, 
                         isPreoptimized, isBundle);
        }
    }

2.4 非懒加载类的处理

    // 实现非懒加载的类,对于load方法和静态实例变量
    for (EACH_HEADER) {
        classref_t *classlist = 
            _getObjc2NonlazyClassList(hi, &count);
        for (i = 0; i < count; i++) {
            // 从镜像列表中映射出来
            Class cls = remapClass(classlist[i]);
            // printf("non-lazy Class:%s\n",cls->mangledName());
            if (!cls) continue;

            // hack for class __ARCLite__, which didn't get this above
#if TARGET_OS_SIMULATOR
            if (cls->cache._buckets == (void*)&_objc_empty_cache  &&  
                (cls->cache._mask  ||  cls->cache._occupied)) 
            {
                cls->cache._mask = 0;
                cls->cache._occupied = 0;
            }
            if (cls->ISA()->cache._buckets == (void*)&_objc_empty_cache  &&  
                (cls->ISA()->cache._mask  ||  cls->ISA()->cache._occupied)) 
            {
                cls->ISA()->cache._mask = 0;
                cls->ISA()->cache._occupied = 0;
            }
#endif
            // 再次插入到表allocatedClasses中
            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);
        }
    }
2.4.1 realizeClassWithoutSwift
    ro = (const class_ro_t *)cls->data();
    if (ro->flags & RO_FUTURE) {
        // 针对未来的类的特殊处理,不在主线流程中
        // This was a future class. rw data is already allocated.
        rw = cls->data();
        ro = cls->data()->ro;
        cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
    } else {
        // Normal class. Allocate writeable class data.
        // 一般的普通类都走这里,
        rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
        rw->ro = ro;
        rw->flags = RW_REALIZED|RW_REALIZING;
        cls->setData(rw);
    }
if (!cls) return nil;
...
supercls = realizeClassWithoutSwift(remapClass(cls->superclass));
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()));

cls->superclass = supercls;
cls->initClassIsa(metacls);
2.4.2 methodizeClass
static Class realizeClassWithoutSwift(Class cls)
{
  // 都是代码

    // Attach categories
    methodizeClass(cls);
    return cls;
}

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

    property_list_t *proplist = ro->baseProperties;
    if (proplist) {
        rw->properties.attachLists(&proplist, 1);
    }

    protocol_list_t *protolist = ro->baseProtocols;
    if (protolist) {
        rw->protocols.attachLists(&protolist, 1);
    }
    void attachLists(List* const * addedLists, uint32_t addedCount) {
        if (addedCount == 0) return;

        if (hasArray()) {
            // many lists -> many lists
            uint32_t oldCount = array()->count;//10
            uint32_t newCount = oldCount + addedCount;//4
            setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
            array()->count = newCount;// 10+4
   
            memmove(array()->lists + addedCount, array()->lists,
                    oldCount * sizeof(array()->lists[0]));
            
            memcpy(array()->lists, addedLists, 
                   addedCount * sizeof(array()->lists[0]));
        }
        else if (!list  &&  addedCount == 1) {
            // 0 lists -> 1 list
            list = addedLists[0];
        } 
        else {
            // 1 list -> many lists
            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;
            memcpy(array()->lists, addedLists, 
                   addedCount * sizeof(array()->lists[0]));
        }
    }

2.5 懒加载类的处理

if (!cls->isRealized()) {
        cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
        // runtimeLock may have been dropped but is now locked again
}
static Class
realizeClassMaybeSwiftAndLeaveLocked(Class cls, mutex_t& lock)
{
    return realizeClassMaybeSwiftMaybeRelock(cls, lock, true);
}

static Class
realizeClassMaybeSwiftMaybeRelock(Class cls, mutex_t& lock, bool leaveLocked)
{
    lock.assertLocked();

    if (!cls->isSwiftStable_ButAllowLegacyForNow()) {
        // Non-Swift class. Realize it now with the lock still held.
        // fixme wrong in the future for objc subclasses of swift classes
        realizeClassWithoutSwift(cls);
        if (!leaveLocked) lock.unlock();
    } else {
        // Swift class. We need to drop locks and call the Swift
        // runtime to initialize it.
        lock.unlock();
        cls = realizeSwiftClass(cls);
        assert(cls->isRealized());    // callback must have provoked realization
        if (leaveLocked) lock.lock();
    }

    return cls;
}

2.6 分类的处理

2.6.1 分类的定义
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;
};
struct category_t {
    const char *name;
    classref_t cls;
    struct method_list_t *instanceMethods;
    struct method_list_t *classMethods;
    struct protocol_list_t *protocols;
    struct property_list_t *instanceProperties;
    // Fields below this point are not always present on disk.
    struct property_list_t *_classProperties;

    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }

    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};
2.6.2 分类的加载
2.6.2.1 非懒加载主类+非懒加载分类
2.6.2.2 非懒加载主类+懒加载分类
2.6.2.3 懒加载主类+懒加载分类
2.6.2.4 懒加载主类+非懒加载分类

3. 总结

上一篇下一篇

猜你喜欢

热点阅读