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
_bucketsAndMaybeMask
variableuintptr_t
Like 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
_originalPreoptCache
And the structure are mutually exclusive,_originalPreoptCache
The initial cache, now exploring the cache in the class, this variable is almost never usedcache_t
There 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
- call
insert
Method flow:[instance method]
The underlying implementationobjc_msgSend --> _objc_msgSend_uncached --> lookUpImpOrForward --> log_and_fill_cache --> cache_t::insert