Read_images -> readClass -> realizeClassWithoutSwift(ro.rw.supcls.isa)-> methodizeClass -> realizeClassWithoutSwift(ro.rw.supcls.isa)-> methodizeClass -> PrepareMethodLists (Write the method name in the class. Sort)

read_images

As we know from the readClass test code in the previous article,mangleName can get the name of the class, so we can plug in the read_images test code in several places to verify each one.


    const char *mangledName = cls->nonlazyMangledName(a);// Test the code
    const char *PersonName = "Person";
    if (strcmp(mangledName, PersonName) == 0) {
        printf("%s - %s\n",__func__,mangledName);
    }
Copy the code

Let’s add the above code validation in log9 and log10 respectivelyThe two breakpoints are not stuck. Look at the note above yellow box 1Realize non-lazy classes (for +load methods and static instances)Meaning, there areloadThis is where they would have gone. So at this point we implement it in the Person classload()Method, and then run it again. Step over to therealizeClassWithoutSwiftThis method

realizeClassWithoutSwift

Does this look familiar? Yes, we’ve been here before when we were exploring the slow search of methods, method linkslookUpImpOrForward -> realizeAndInitializeIfNeeded_locked -> initializeAndLeaveLocked -> realizeClassMaybeSwiftAndLeaveLocked -> realizeClassMaybeSwiftMaybeRelock -> realizeClassWithoutSwiftSo anyway, let’s go ahead and find out if we implemented methodList ro rw rwe in this methodSo we can get, we just have the address of the Person, but we don’t have any assignment in the method list, ro, rw, rwe, etc.,

auto ro = (const class_ro_t *)cls->data(a);Copy the code

CLS ->data() is of type class_rw_t*, which is strongly converted to class_ro_t *

      // Normal class. Allocate writeable class data. ro -> rw
        rw = objc::zalloc<class_rw_t> (); rw->set_ro(ro);
        rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
        cls->setData(rw);
Copy the code

And then it goes over here, where it assigns ro clean memory to RW. The following two lines of code also map the isa inheritance chain and superCls

supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
Copy the code

methodizeClass

realizeClassWithoutSwift -> methodizeClassInsert the same debug code in this method to intercept the Person information. Continue printing ro as described abovebaseMethodListOr is emptyMoving on, we find that the system is also calledbaseMethods()

prepareMethodLists

Go to prepareMethodLists and fix the selector fixupMethodList

  for (auto& meth : *mlist) {
            const char *name = sel_cname(meth.name());
            printf("Before sorting: %s - %p\n",name, meth.name());
            meth.setName(sel_registerNameNoLock(name, bundleCopy));
   }
Copy the code

Now the sort here also corresponds to the slow search binary search. So after I’ve sorted it, I go back to the originalmethodizeClassSo let’s go ahead and do a little bit of ro and find out that there’s still no content and all of that exploration was done in the Person classloadUnder the premise that then not implementedloadSo where is our method ro, rw assigned

Lazy load class condition (not implementedloadMethods)

Let’s take the PersonloadMethod, and we know that we’re going to do this methodrealizeClassWithoutSwiftWe’re going to cut a break point here and go backwards inrealizeClassWithoutSwiftBreakpoint view call stackAt this point we can draw a conclusion

Lazy load class case: data loading is delayed until the first message Non-lazy class loading: all class information is recorded when map_images is used
lookUpImpOrForward readClass
realizeClassMaybeSwiftMaybeRelock _getObjc2NonlazyClassList
realizeClassWithoutSwift realizeClassWithoutSwift
methodizeClass methodizeClass

MethodizeClass looks at comments related to categorization, so add a categorization to main and look at main.cpp

struct _category_t {
	const char *name; / / class name
	struct _class_t *cls; / / class
	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;
};
Copy the code

Instance_methods: The class has no metaclass, so all current methods are in there.

static struct/ * _method_list_t* / {
	unsigned int entsize;  // sizeof(struct _objc_method)
	unsigned int method_count;
	struct _objc_method method_list[2].
} _OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_LG __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	sizeof(_objc_method),
	2,
	{{(struct objc_selector *)"cate_instanceMethod1"."v16@0:8", (void *)_I_Person_LG_cate_instanceMethod1},
	{(struct objc_selector *)"cate_instanceMethod2"."v16@0:8", (void *)_I_Person_LG_cate_instanceMethod2}}
};
Copy the code

Notice also that the set and GET methods are not included in the list of methods in the category

When is RWE assigned

Going back to the methodizeClass method, we know that the method of classification exists in RWE,

auto rwe = rw->ext(a)Copy the code

Ext () is related to get_ro_or_rwe(), while get_ro_or_rwe() is related to extAllocIfNeeded()

    class_rw_ext_t *ext(a) const {
        return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>(&ro_or_rw_ext);
    }

    class_rw_ext_t *extAllocIfNeeded(a) {
        auto v = get_ro_or_rwe(a);if (fastpath(v.is<class_rw_ext_t* > ())) {return v.get<class_rw_ext_t *>(&ro_or_rw_ext);
        } else {
            return extAlloc(v.get<const class_ro_t*>(&ro_or_rw_ext)); }}Copy the code

The global search for extAllocIfNeeded locates this method attachCategories Look at the comment attaching the list of methods, properties, and protocols in the Categories category to the class to show that we are looking right

attachCategories

Found to call the method 1. There are two realizeClassWithoutSwift – > methodizeClass – > attachToClass – > 2 attachCategories load_categories_nolock ->attachCategories -> extAllocIfNeeded In attachCategories we found an algorithm for inserting categories attachLists where the calculation is to insert the categories in front of the ordered list, followed by the methods of the main class. This also explains why when a method with the same name is called, the method lookup will first locate the method with the same name of the class.

    void attachLists(List* const * addedLists, uint32_t addedCount) {
        if (addedCount == 0) return;

        if (hasArray()) {
            // many lists -> many lists
            uint32_t oldCount = array()->count;
            uint32_t newCount = oldCount + addedCount;
            array_t *newArray = (array_t *)malloc(array_t: :byteSize(newCount));
            newArray->count = newCount;
            array()->count = newCount;

            for (int i = oldCount - 1; i >= 0; i--)
                newArray->lists[i + addedCount] = array()->lists[i];
            for (unsigned i = 0; i < addedCount; i++)
                newArray->lists[i] = addedLists[i];
            free(array());
            setArray(newArray);
            validate(a); }else if(! list && addedCount ==1) {
            // 0 lists -> 1 list
            list = addedLists[0];
            validate(a); }else {
            // 1 list -> many lists
            Ptr<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;
            for (unsigned i = 0; i < addedCount; i++)
                array()->lists[i] = addedLists[i];
            validate();
        }
    }
Copy the code

We know that the loading of a class is related to load, so is the loading of a class related to load

Category + class collocation loading

List all four scenarios below

The classification load method is implemented Main class load method implementation Load order
There are There are _read_images ->realizeClassWithoutSwift->methodizeClass->load_categories_nolock ->attachCategories
There is no There are _read_images ->realizeClassWithoutSwift->methodizeClass(noattachCategories)
There are (1) There is no _read_images ->realizeClassWithoutSwift->methodizeClass(noattachCategories)
There are (> 1) There is no load_images -> prepare_load_methods -> realizeClassWithoutSwift -> methodizeClass -> attachCategories
There is no There is no Nothing

According to the above four cases, we analyze when the data of the classification is loaded in. At the same time, if the classification has no content, it will not be loaded into memory.

Timing of classification data loading

  1. In both cases: in**realizeClassWithoutSwift**Method console print

Print one by one and find that there are no classified methods, all methods of the main class. We know we’re coming**attachCategories**, where the print validation continuesIt is found that the classification method has been added here. Moving on, we see the classification insertion algorithm written aboveattachList

 rwe->methods.attachLists(mlists + ATTACH_BUFSIZ - mcount, mcount);
Copy the code

We know from the above that the first argument is a pointer to a pointer, which is a two-dimensional pointer

  1. There is no**attachCategories**How to load categories

Whether it’s the class or the main class there’s only one place to implement the load method, or it’s in theread_imagesThe non-lazy load inside, describes the main class in some cases the classification is forced to business. Now we come to**realizeClassWithoutSwift**If count=13, the class has already been loaded into the main class. Count is the number of classes read directly from Mach-o.**_read_images** ->**realizeClassWithoutSwift**->**methodizeClass**load_images->loadAllCategories -> load_categories_nolock -> attachCategories

  1. It’s the same thing as 2

  2. Main class implementation, in the case of multiple categories (more than 1 implementation load), the process is found to be a little different

_read_images ->realizeClassWithoutSwift-> methodizeClass -> load_images -> prepare_load_methods -> realizeClassWithoutSwift -> methodizeClass -> attachCategorie

  1. In the absence of either implementation, the loading of the classification is delayed until the first message is sentlookUpImpOrForwardInitialize data when the