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 rightThe diagram below:

  • To obtain_bucketsAndMaybeMaskThe address is going to becacheAddress:p16 = isa(class).p16 + 0x10 = _bucketsAndMaybeMask = p11
  • To obtainbucketsThe address is the first address of the cache memory:Buckets = ((_bucketsAndMaybeMask >> 48) -1) BUCKETS = ((_bucketsAndMaybeMask >> 48) -1)
  • To obtainhashThe subscript:P = (CMD ^ (_cmd >> 7)The purpose of this step is to obtainhashThe subscriptindex
  • The process is as follows:isa --> _bucketsAndMaybeMask --> buckets -->hashThe subscript

Traverse the cache

  • According to the subscriptindexfindindexThe correspondingbucket.p13 = buckets + ((_cmd ^ (_cmd >> 7)) & mask) << (1+PTRSHIFT))
  • So let’s get the correspondingbucketThen remove themimpandselDeposit top17andp9And then*bucket— Moving forward
  • 1 process:p9= selAnd the parameters passed in_cmdCompare. If they go equally2 processIf they don’t go equallyThree processes
  • 2 process: Indicates a cache hitCacheHitprocess
  • Three processesJudge:sel = 0Whether the condition is true. If true, indicatebucketsThere are no arguments passed in_cmdCache, there is no need to go down directly jump__objc_msgSend_uncachedProcess. ifSel! = 0Illustrate thisbucketIt’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 positionbucketandThe first bucket address sizeIf it is greater thanThe address of the first bucketjump1 processLoop lookup, if less than or equal to continue the process
  • If I loop toIn the first bucketI didn’t find a match_cmd. So it’s going to keep going down because of the subscriptindexThere may be more to comebucketNo query yet

CacheHitprocess

CacheHit \Mode Mode = NORMAL

TailCallCachedImpIs 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

maskTraverse 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 onebucketLocation:p13 = buckets + (mask << 1+3)Find the last onebucketThe location of the
  • So let’s get the correspondingbucketThen remove themimpandselDeposit top17andp9And then*bucket--To move forward
  • p9= selAnd the parameters passed in_cmdCompare. 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 = _cmdMethod to cache queries to end the jump__objc_msgSend_uncachedprocess
  • 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