preface

The nature of OC objects and the underlying structure of ISA and ISA classes are analyzed respectively in ISA and BITS. Class member variables also superclass and cache, today we will explore the underlying principle of cache.

The preparatory work

Objc4-818.2 – the source code

Cache structure analysis

Cache_t structure

The cache_t type is a structure

struct cache_t {
private:
    explicit_atomic<uintptr_t> _bucketsAndMaybeMask;
    union {
        struct {
            explicit_atomic<mask_t>    _maybeMask;
#if __LP64__
            uint16_t                   _flags;
#endif
            uint16_t                   _occupied;
        };
        explicit_atomic<preopt_cache_t *> _originalPreoptCache;
    };
   
    / * # if defined (__arm64__) && __LP64__ # if TARGET_OS_OSX | | TARGET_OS_SIMULATOR / / __arm64__ simulator # define CACHE_MASK_STORAGE CACHE_MASK_STORAGE_HIGH_16_BIG_ADDRS #else //__arm64__ true machine #define CACHE_MASK_STORAGE CACHE_MASK_STORAGE_HIGH_16 #endif #elif defined(__arm64__) && ! __LP64__ // 32-bit true machine #define CACHE_MASK_STORAGE CACHE_MASK_STORAGE_LOW_4 #else //macOS emulator #define CACHE_MASK_STORAGE CACHE_MASK_STORAGE_OUTLINED #endif ****** The middle is a mask judged mainly by different types of masks and buckets
    
    public:
    void incrementOccupied(a);
    void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
    void reallocate(mask_t oldCapacity, mask_t newCapacity, bool freeOld);
    unsigned capacity(a) const;
    struct bucket_t *buckets(a) const;
    Class cls(a) const;
    void insert(SEL sel, IMP imp, id receiver);
    // The following are methods that are basically all other methods
};
Copy the code
  • _bucketsAndMaybeMaskvariableuintptr_tLike bits in ISA_t, it isa pointer type that holds an address
  • A union has a structure and a structure pointer_originalPreoptCache
  • There are three member variables in the structure_maybeMask._flags._occupied
  • _originalPreoptCacheAnd the structure are mutually exclusive,_originalPreoptCacheThe initial cache, now exploring the cache in the class, this variable is almost never used
  • cache_tThere is a common way to get values, and to get masks and buckets based on different architectural systems

To explore the

  • When you need to cache methods that account for three quarters of the total capacity, you go directly to the cache process
  • Digging into some of the underlying source code will find that Apple’s design thinking, do what things will leave room. One might be for later optimization or scaling, another might be for security, as is memory alignment
  • If the capacity exceeds 3/4, the system expands the capacity twice. The maximum capacity to be expanded does not exceed 2^15 of the mask
  • During capacity expansion, an important operation will be performed to create new memory and free the old memory. In this case, freeOld = true

The cache method

  • A bucket() is neither an array nor a linked list, but a contiguous chunk of memory
  • The hash function computes the hash subscript based on the cache SEL and mask. Why do we need masks? The actual function of mask is to tell the system that you can only store the first three Spaces in capacity 1. For example, if capacity = 4, the cache method can only store the first three Spaces
  • Starts caching, caches the method if there is no data at the current location. If there is a method at that location and it is the same as yours, the method is already cached and returns. If there is a hash conflict and the subscripts are the same but the SEL is different, the hash will be performed again and the cache will continue to resolve the conflict

Insert call flow

  • callinsertMethod flow:[instance method]The underlying implementationobjc_msgSend --> _objc_msgSend_uncached --> lookUpImpOrForward --> log_and_fill_cache --> cache_t::insert

conclusion