//objc-cache.mm(objc4) staticvoidcache_fill_nolock(Class cls, SEL sel, IMP imp, id receiver) { cacheUpdateLock.assertLocked();
// Never cache before +initialize is done if (!cls->isInitialized()) return; // 如果类还未初始化,直接返回
// Make sure the entry wasn't added to the cache by some other thread // before we grabbed the cacheUpdateLock. if (cache_getImp(cls, sel)) return; // 可能有其它线程抢先将该方法缓存了,所以要检查一次缓存,如果存在,直接返回
cache_t *cache = getCache(cls); // ️取出该 class 的 cache_t cache_key_t key = getKey(sel); // ️根据 sel 获得 _key
// Use the cache as-is if it is less than 3/4 full mask_t newOccupied = cache->occupied() + 1; // 将 cache_t 的 _occupied 即已经缓存的方法数量 + 1,这里只是为了判断 +1 后缓存容量是否满 mask_t capacity = cache->capacity(); // 获得缓存容量 = _mask + 1 if (cache->isConstantEmptyCache()) { // 如果缓存是只读的,重新申请缓存空间 // Cache is read-only. Replace it. cache->reallocate(capacity, capacity ?: INIT_CACHE_SIZE); // 申请新的缓存空间,并释放旧的 } elseif (newOccupied <= capacity / 4 * 3) { // ️如果当前已经缓存的方法数量 +1 <= 缓存容量的 3/4,就继续往下操作 // Cache is less than 3/4 full. Use it as-is. } else { // ️如果以上条件不满足,说明缓存已满,进行缓存扩容 // Cache is too full. Expand it. cache->expand(); }
// Scan for the first unused slot and insert there. // 扫描第一个未使用的插槽(bucket_t)并将其插入 // There is guaranteed to be an empty slot because the // 必然会有一个空的插槽(bucket_t) // minimum size is 4 and we resized at 3/4 full. // 因为最小大小是4,我们调整为3/4满 bucket_t *bucket = cache->find(key, receiver); // ️调用 find() 函数进行一次缓存查找,必然会得到一个空的 bucket_t if (bucket->key() == 0) cache->incrementOccupied(); // ️如果该 bucket_t 为空,将 _occupied 即已经缓存的方法数量 + 1 bucket->set(key, imp); // ️添加缓存 }
if ((uint32_t)(mask_t)newCapacity != newCapacity) { // mask overflow - can't grow further // fixme this wastes one bit of mask newCapacity = oldCapacity; }
// extra_rc must be the MSB-most field (so it matches carry/overflow flags) // nonpointer must be the LSB (fixme or get rid of it) // shiftcls must occupy the same bits that a real class pointer would // bits + RC_ONE is equivalent to extra_rc + 1 // RC_HALF is the high bit of extra_rc (i.e. half of its range)
// future expansion: // uintptr_t fast_rr : 1; // no r/r overrides // uintptr_t lock : 2; // lock for atomic property, @synch // uintptr_t extraBytes : 1; // allocated with extra bytes