The opening

Study hard, not anxious not impatient.

In the previous article, we mainly studied the message sending process of objc_msgSend, mainly in the case that msgSend is sent smoothly and cache hits. How does the message sending process execute in the case of a cache miss? Today we’re going to explore it;

Methods the cache

When the objc_msgSend message is sent, if the sel to be searched is the same as the queried SEL, the cache is hit and the CacheHit function is executed. If the cache misses, the MissLabelDynamic function logic is executed.

We can see the corresponding function from the value passed in CacheLookup:

Mode              —-> NORAML;

Function          —-> _objc_msgSend;

MissLabelDynamic  —-> _objc_msgSend_uncached;

Since the MissLabelDynamic function executes the _objC_msgsend_cached process, the next step is to analyze the _objc_msgSend_uncached process

The msgSend cache is not hit. Procedure

.endmacro
STATIC_ENTRY __objc_msgSend_uncached
UNWIND __objc_msgSend_uncached, FrameWithNoSaves

MethodTableLookup

TailCallFunctionPointer x17

......

Copy the code

In the source code, the two important functions are MethodTableLookup and TailCallFunctionPointer X17.

The TailCallFunctionPointer function, which returns the data, also means that the data has been fetched before it, so we’ll focus on the tablelookup function;

Through layer by layer analysis, it is concluded that _lookUpImpOrForward function is the key of everything.

lookUpImpOrForward

A global search for _lookUpImpOrForward failed to find _lookUpImpOrForward in the assembly source code, indicating that _lookUpImpOrForward does not use the assembly source process. Attempts to search for lookUpImpOrForward but finds that the lookUpImpOrForward process exists as C++ source code;

So the question is, why do we use assembly mode when the cache hits, but C++ mode when the cache misses? What are the benefits of using assembly?

Assembly is machine recognition language, for the equipment, the recognition of assembly language execution is very efficient, and is very safe;

So in the case of a cache hit, a direct lookup through the cache is very fast, which is what we call a quick lookup process;

When the cache does not hit, it needs to go through all the methods to find, which is slow, so it is a slow search process. The system will put the process in C/C ++;

Slow to find

Slow search process:

Select * from sel; select * from SEL; select * from SEL; select * from SEL;

Select method (s) from method (s) where method (s) is listed.

NSObject method list NSObject method list

4, finally go to nil, out of the search process;


In the lookUpImpOrForward method, our goal is to acquire the IMP, so we read the core code;

Method dichotomy

Take a closer look at how the getMethodNoSuper_nolock method performs a dichotomy lookup.

There is no binary search in getMethodNoSuper_nolock, because the method list can be a two-dimensional array, as we explained in the previous article on class method fetching; Since the method list may be a two-dimensional array, there is no dichotomy here;

Search_method_list_inline obtained is method_t and search_method_list_inline internal basis for judgment conditions, perform findMethodInSortedMethodList function, So let’s focus on this function;

findMethodInSortedMethodListfunction

Source dichotomy is very subtle, through two right shift and subtraction operation, can accurately locate dichotomy subscript, but also reduce the cycle operation, improve efficiency;

Here’s an example of the dichotomy:

After the end of the method search, through the method can obtain IMP, and then execute the goto done method, proceed to the next step;

Inside the done method, there will be a cache write to prevent the next time the binary lookup is performed again, which will consume memory. Storing in the cache also improves efficiency.

At this point, the sending, searching and inserting of messages form a closed loop;

Message slow search process, will continue to search through the inheritance chain, no subclass, query the parent class, the query process of the parent class, also exist fast search and slow search;

conclusion