preface
In the last section we explored objc_msgSend through assembly to get to the CacheLookup process. Now let’s look at CacheLookup
CacheLookup
NORMAL
,_objc_msgSend ,__objc_msgSend_uncached
,MissLabelDynamic,MissLabelConstant
Source code analysis: real machine for example.
eor p12,p1,p1,LSR #7
bitwiseMove 7 to the right
The diagram below:
- To obtain
_bucketsAndMaybeMask
The address is going to becache
Address:p16 = isa(class)
.p16 + 0x10 = _bucketsAndMaybeMask = p11
- To obtain
buckets
The address is the first address of the cache memory:Buckets = ((_bucketsAndMaybeMask >> 48) -1) BUCKETS = ((_bucketsAndMaybeMask >> 48) -1)
- To obtain
hash
The subscript:P = (CMD ^ (_cmd >> 7)
The purpose of this step is to obtainhash
The subscriptindex
- The process is as follows:
isa --> _bucketsAndMaybeMask --> buckets -->hash
The subscript
Traverse the cache
- According to the subscript
index
findindex
The correspondingbucket
.p13 = buckets + ((_cmd ^ (_cmd >> 7)) & mask) << (1+PTRSHIFT))
- So let’s get the corresponding
bucket
Then remove themimp
andsel
Deposit top17
andp9
And then*bucket
— Moving forward 1 process
:p9= sel
And the parameters passed in_cmd
Compare. If they go equally2 process
If they don’t go equallyThree processes
2 process
: Indicates a cache hitCacheHit
processThree processes
Judge:sel = 0
Whether the condition is true. If true, indicatebuckets
There are no arguments passed in_cmd
Cache, there is no need to go down directly jump__objc_msgSend_uncached
Process. ifSel! = 0
Illustrate thisbucket
It’s occupied by another method. I want you to find the next seat and see if it’s what you need. And then in judging the next positionbucket
andThe first bucket address size
If it is greater thanThe address of the first bucket
jump1 process
Loop lookup, if less than or equal to continue the process- If I loop to
In the first bucket
I didn’t find a match_cmd
. So it’s going to keep going down because of the subscriptindex
There may be more to comebucket
No query yet
CacheHit
process
CacheHit \Mode Mode = NORMAL
TailCallCachedImp
Is a macro. The macro is defined as follows
After the cache query, the IMP of the bucket is decoded directly. Imp = IMP ^ class, and then call the decoded IMP
mask
Traverse the cache forward
If no query is found in the cache through forward traversal, it will jump to the bucket corresponding to the mask to continue the search
- Find the last one
bucket
Location:p13 = buckets + (mask << 1+3)
Find the last onebucket
The location of the - So let’s get the corresponding
bucket
Then remove themimp
andsel
Deposit top17
andp9
And then*bucket--
To move forward p9= sel
And the parameters passed in_cmd
Compare. If they go equally2 process
- If not equal in the judgment (
Sel! = 0 && bucket > the first hash subscript bucket)
Then loop the cache lookup, if the entire process loop still no query or encounter emptybucket
. Indicates that there is no cache in the cache.sel = _cmd
Method to cache queries to end the jump__objc_msgSend_uncached
process - Mask forward traversal logic is basically the same as the previous loop traversal logic
Conclusion objc_msgSend (recevier, _cmd) sel – > imp
1. Check whether the Recevier exists
2.
recevier -> isa -> class (GetClassFromIsa_p16)
3. Class -> memory -> cache(bucket mask)
4. The bucket mask – > bucket
5. Mask Mask -> mask
6. Insert mask_t (value & mask);
7. Search index for the first time
8. Bucket +index Specifies the number of buckets in the entire cache
9.
bucket(imp sel)
10 Get sel == __cmd ->cacheHit-> IMP ^isa = IMP (br
Did not find
11 Get the bucket– shift it again
12 until it goes on forever
13. If __objc_msgsend_cached is not found