// 仅供objc运行时使用 // Note: only for use by objc runtime // 当objc镜像在映射、取消映射、和初始化时注册的事件会被调 // Register handlers to be called when objc images are mapped, unmapped, and initialized. // Dyld会回调给将mapped函数一组包含objc-image-info段 // Dyld will call back the "mapped" function with an array of images that contain an objc-image-info section. // 这些dylibs 将自动引用计数,因此objc将不再需要调用dlopen()防止未加载 // 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_objc_notify_register()期间 dyld将调用 `mapped` 在已经加载好 images,稍后dlopen()。 // dyld will call the "mapped" function with already loaded objc images. During any later dlopen() call, // 在调动init的时候也会调用`mapped`,在dyld调用的时候,也会调用init函数 // dyld will also call the "mapped" function. Dyld will call the "init" function when dyld would be called // 在调用任何images +load方法时候 // 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);
for (i = 0; i < count; i++) { Class cls = (Class)classlist[i]; 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");
// 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 *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");
// 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++) { constchar *name = sel_cname(sels[i]); sels[i] = sel_registerNameNoLock(name, isBundle); } } }
ts.log("IMAGE TIMES: fix up selector references");
#if SUPPORT_FIXUP // 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++) { fixupMessageRef(refs+i); } }
ts.log("IMAGE TIMES: fix up objc_msgSend_fixup"); #endif
// Discover protocols. Fix up protocol refs. for (EACH_HEADER) { extern objc_class OBJC_CLASS_$_Protocol; Class cls = (Class)&OBJC_CLASS_$_Protocol; assert(cls); NXMapTable *protocol_map = protocols(); bool isPreoptimized = hi->isPreoptimized(); bool isBundle = hi->isBundle();
protocol_t **protolist = _getObjc2ProtocolList(hi, &count); for (i = 0; i < count; i++) { readProtocol(protolist[i], cls, protocol_map, isPreoptimized, isBundle); } }
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) { protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count); for (i = 0; i < count; i++) { remapProtocolRef(&protolist[i]); } }
ts.log("IMAGE TIMES: fix up @protocol references");
// Realize non-lazy classes (for +load methods and static instances) for (EACH_HEADER) { classref_t *classlist = _getObjc2NonlazyClassList(hi, &count); for (i = 0; i < count; i++) { Class cls = remapClass(classlist[i]); 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
addClassTableEntry(cls); realizeClass(cls); } }
ts.log("IMAGE TIMES: realize non-lazy classes");
// Realize newly-resolved future classes, in case CF manipulates them if (resolvedFutureClasses) { for (i = 0; i < resolvedFutureClassCount; i++) { realizeClass(resolvedFutureClasses[i]); resolvedFutureClasses[i]->setInstancesRequireRawIsa(false/*inherited*/); } free(resolvedFutureClasses); }
if (!cls) { // Category's target class is missing (probably weak-linked). // Disavow any knowledge of this category. catlist[i] = nil; if (PrintConnecting) { _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with " "missing weak-linked target class", cat->name, cat); } continue; }
// Process this category. // First, register the category with its target class. // Then, rebuild the class's method lists (etc) if // the class is realized.
if (cls->isRealized()) { remethodizeClass(cls); classExists = YES; } if (PrintConnecting) { _objc_inform("CLASS: found category -%s(%s) %s", cls->nameForLogging(), cat->name, classExists ? "on existing class" : ""); } }
if (cat->classMethods || cat->protocols || (hasClassProperties && cat->_classProperties)) { addUnattachedCategoryForClass(cat, cls->ISA(), hi); if (cls->ISA()->isRealized()) { remethodizeClass(cls->ISA()); } if (PrintConnecting) { _objc_inform("CLASS: found category +%s(%s)", cls->nameForLogging(), cat->name); } } } }
ts.log("IMAGE TIMES: discover categories");
// Category discovery MUST BE LAST to avoid potential races // when other threads call the new category code before // this thread finishes its fixups.
// +load handled by prepare_load_methods()
if (DebugNonFragileIvars) { realizeAllClasses(); }
// 遍历所有分类 for (i = 0; i < count; i++) { // 取出每一个分类 category_t *cat = catlist[i]; // 调用remapClass(cat->cls),并返回一个objc_class *对象cls。这一步的目的在于找到到category对应的类对象cls Class cls = remapClass(cat->cls);
if (!cls) { // Category's target class is missing (probably weak-linked). // Disavow any knowledge of this category. catlist[i] = nil; if (PrintConnecting) { _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with " "missing weak-linked target class", cat->name, cat); } continue; }
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) { /**< Specifies a weak reference to the associated object. */ OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a strong reference to the associated object. * The association is not made atomically. */ OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies that the associated object is copied. * The association is not made atomically. */ OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies a strong reference to the associated object. * The association is made atomically. */ OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies that the associated object is copied. * The association is made atomically. */ OBJC_ASSOCIATION_COPY = 01403 };
void load_images(constchar *path __unused, conststruct mach_header *mh) { // Return without taking locks if there are no +load methods here. if (!hasLoadMethods((const headerType *)mh)) return;