OC class principle exploration series articles

  1. OC class principle exploration: Class structure analysis
  2. OC class principle exploration: Class structure analysis supplement
  3. OC class principles exploration: the underlying principles of attributes
  4. OC class principle Exploration: Structural analysis of cache_t
  5. OC class principle exploration: Cache structure analysis supplement

preface

OC class principle exploration: Cache_t structure analysis of the structure of the cache has been introduced, with insert function as the starting point to analyze the use of member variables in the cache, today the cache structure to do some additions and extensions.

The preparatory work

  • Objc4-818.2 – the source code
  • LLVM source

1. _bucketsAndMaybeMask authentication

As stated in cache_T, _bucketsAndMaybeMask stores the first address of buckets. We use LLDB to verify this:

  • _bucketsAndMaybeMasktheValueIn order to16Print in base form, the result is0x00000001006444a0;
  • buckets()the16The same is true for typing in base form0x00000001006444a0;
  • According to the printed results, you can prove that_bucketsAndMaybeMaskWhat is stored isbucketsThe initial address of.

B) buckets C) buckets D) buckets

Debug source breakpoints when adding methods:

  • The values of addr and buckets() are equal at 0x00000001003623A0.

  • buckets()againaddr & bucketsMaskThe result, the descriptionbucketsMaskTakes the following values:Expressed in binary:

  • The value of bucketsMask varies according to the architecture:

3. Imp algorithm

The imp function in bucket_t has such a code return (IMP)(imp ^ (uintPtr_t) CLS); As follows:

  • Here’s what’s involvedcodinganddecodingIn the process;
  • Storage ofimpIs auintptr_t(long integer), is not aA function pointer;
  • through^The (xor) operation gets the address of the true pointer, but the reason it does this is because it does the same thing when storing (encoding). Let’s move on.

Encoding and decoding algorithm

Look at the set function and its encodeImp encoding function:

  • ^(XOR) algorithm
    • c = a ^ b ;
    • a = c ^ b .
  • impThe codec
    • setWhen,Imp = function pointer ^ CLS;
    • When I take it,Function pointer = IMP ^ CLS;
    • clsIt’s the salt of the algorithm.

LLDB encoding and decoding

Debug imp function at breakpoint:

To debug LLDB:

The say1 method was finally obtained through LLDB, which verified the above conclusion.

4, LLDB call method mask defaults to 7

  • inOC class principle Exploration: Structural analysis of cache_tWe call with normal codesay1Method,_maybeMaskThe value is3And here it becomes7Why is that?
  • _maybeMaskThe value is7“Indicates that there was an expansion. This expansion should be an insertsay1Method or insertsay1Method, because there’s no need to insert those methods later on, so we’re insertingsay1Method to do some printing to analyze.

Insert the following code into the insert function:

Run the program, LLDB debug:

  • As shown above in insertsay1Method, insert firstrespondsToSelectorandclassIn the insertsay1When we expand, we clear out the previous method, so eventually_maybeMaskThe value is7._occupiedThe value is1;
  • We also found thatbucketsOf the fourth storage unitimpIt stores the first address0x101906760And that explains why jean Valjean_maybeMask = capacity - 1, also can be inobjcFind the corresponding method in the source code.

Why insert response to Selector and class in advance

As to why the respondsToSelector and class are inserted in advance, the LLVM source code is also described;

Buckets the last storage unit

The IMP of the last storage unit of Buckets, which stores the first address of buckets, is also found in the OBJC source code.

Real environment for cache_NEXT

See the related source code for cache_next:

  • armThe environment is our real environment, and in the real environment,cache_nextIs constantly looking for null values in the previous position;
  • In a non-real machine environment,cache_nextIt’s going to keep looking for a null in the last position.

What did you do before the insert() function

Now that we know a bit about insert(), what did we do before insert()? Let’s do a search on ->insert to see where it was called.

We did not find the cache-related insert() function, so we can make a breakpoint to see the stack information.

Search log_and_fill_cache to find the call to lookUpImpOrForward().

In addition to this method, we can see the following comment in objc-cache.mm:

We see that objc_msgSend is called before insert. Objc_msgSend is a very important method and will be explored in the next article.