Runtime 02 - Class(方法信息列表、方法緩存)
Class 結(jié)構(gòu)圖
關(guān)于對 objc_class凉袱、class_data_bits_t芥吟、class_rw_t侦铜、class_ro_t 的解讀,請參考這里Objective-C 對象的本質(zhì) 01 - 底層實現(xiàn))钟鸵。
SEL钉稍、IMP
// 方法名(選擇器)
//
// 可以通過 @selector() 或 sel_registerName() 獲取 SEL。
// 可以通過 sel_getName() 或 NSStringFromSelector() 將 SEL 轉(zhuǎn)換為字符串棺耍。
// 不同類中的同名方法所對應(yīng)的 SEL 是相同的贡未。
//
/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;
// 函數(shù)指針
//
/// A pointer to the function of a method implementation.
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
#endif
bucket_t、cache_t
typedef unsigned long uintptr_t;
// 方法緩存中的 Key
#if __LP64__
typedef uint32_t mask_t; // x86_64 & arm64 asm are less efficient with 16-bits
#else
typedef uint16_t mask_t;
#endif
typedef uintptr_t cache_key_t;
// 方法緩存
struct bucket_t {
private:
cache_key_t _key; // key 是方法的 SEL
IMP _imp; // 函數(shù)指針
public:
inline cache_key_t key() const { return _key; }
inline IMP imp() const { return (IMP)_imp; }
inline void setKey(cache_key_t newKey) { _key = newKey; }
inline void setImp(IMP newImp) { _imp = newImp; }
void set(cache_key_t newKey, IMP newImp);
};
// 方法緩存列表
//
// 用散列表(哈希表)來緩存調(diào)用多的方法烈掠,可以提高查找方法的速度羞秤。
//
// _mask 為什么是 _buckets 的長度 -1 ?
// -1 能確保 (key & _mask) <= (_buckets 的長度 - 1)缸托,用來作為 _buckets 的下標(biāo)來取值左敌。
// 在 cache_t::find() 函數(shù)中可以看到計算下標(biāo)的代碼。
//
// _buckets 的動態(tài)擴容:
// 向 _buckets 添加最后一個緩存時會進(jìn)行擴容俐镐。
// 每次擴容為原來的兩倍(2^n)矫限。
// 擴容時會將緩存清除,因為擴容后 _mask 發(fā)生了變化佩抹。
// 通過 cache_t::expand() 函數(shù)中進(jìn)行擴容叼风。
struct cache_t {
struct bucket_t *_buckets; // 散列表
mask_t _mask; // 散列表的長度 -1
mask_t _occupied; // 已經(jīng)緩存的方法數(shù)量(<= _mask)
public:
struct bucket_t *buckets();
mask_t mask();
mask_t occupied();
void incrementOccupied();
void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
void initializeToEmpty();
mask_t capacity();
bool isConstantEmptyCache();
bool canBeFreed();
static size_t bytesForCapacity(uint32_t cap);
static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);
void expand();
void reallocate(mask_t oldCapacity, mask_t newCapacity);
struct bucket_t * find(cache_key_t key, id receiver);
static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn));
};
/* Initial cache bucket count. INIT_CACHE_SIZE must be a power of two. */
enum {
INIT_CACHE_SIZE_LOG2 = 2,
INIT_CACHE_SIZE = (1 << INIT_CACHE_SIZE_LOG2)
};
// 擴容列表
void cache_t::expand()
{
cacheUpdateLock.assertLocked();
// 計算新的長度(oldCapacity * 2),初始值為 4(INIT_CACHE_SIZE)
uint32_t oldCapacity = capacity();
uint32_t newCapacity = oldCapacity ? oldCapacity*2 : INIT_CACHE_SIZE;
if ((uint32_t)(mask_t)newCapacity != newCapacity) {
// mask overflow - can't grow further
// fixme this wastes one bit of mask
newCapacity = oldCapacity;
}
// 擴容并清除舊的緩存
reallocate(oldCapacity, newCapacity);
}
// 擴容列表并清除舊的緩存
void cache_t::reallocate(mask_t oldCapacity, mask_t newCapacity)
{
bool freeOld = canBeFreed();
bucket_t *oldBuckets = buckets();
bucket_t *newBuckets = allocateBuckets(newCapacity);
// Cache's old contents are not propagated.
// This is thought to save cache memory at the cost of extra cache fills.
// fixme re-measure this
assert(newCapacity > 0);
assert((uintptr_t)(mask_t)(newCapacity-1) == newCapacity-1);
setBucketsAndMask(newBuckets, newCapacity - 1);
if (freeOld) {
cache_collect_free(oldBuckets, oldCapacity);
cache_collect(false);
}
}
// 從散列表中查找方法緩存
bucket_t * cache_t::find(cache_key_t k, id receiver)
{
assert(k != 0);
bucket_t *b = buckets(); // 取出散列表(_buckets)
mask_t m = mask(); // 取出散列表的長度 -1 的值(_mask)
mask_t begin = cache_hash(k, m); // 計算緩存的哈希值(k & m)
mask_t i = begin;
do {
if (b[i].key() == 0 || b[i].key() == k) {
return &b[i];
}
} while ((i = cache_next(i, m)) != begin);
// hack
Class cls = (Class)((uintptr_t)this - offsetof(objc_class, cache));
cache_t::bad_cache(receiver, (SEL)k, cls);
}
// 根據(jù)當(dāng)前下標(biāo)(i)計算下一個下標(biāo)(arm64 架構(gòu)中是 i - 1 或 mask)
#if __arm__ || __x86_64__ || __i386__
// objc_msgSend has few registers available.
// Cache scan increments and wraps at special end-marking bucket.
#define CACHE_END_MARKER 1
static inline mask_t cache_next(mask_t i, mask_t mask) {
return (i+1) & mask;
}
#elif __arm64__
// objc_msgSend has lots of registers available.
// Cache scan decrements. No end marker needed.
#define CACHE_END_MARKER 0
static inline mask_t cache_next(mask_t i, mask_t mask) {
return i ? i-1 : mask;
}
#else
#error unknown architecture
#endif
method_t棍苹、method_list_t无宿、method_array_t
// 方法信息
//
// *types 示意:| 返回值 | 參數(shù)1 | 參數(shù)2 | ... | 參數(shù)n |
// 例如一個沒有返回值且沒有參數(shù)的方法,它的 method_t 中的 *types 為 v16@:8
// | v16 | @0 | :8 |
// | void | id | SEL |
// 兩個參數(shù)為默認(rèn)參數(shù)枢里,id 對應(yīng) self孽鸡,SEL 對應(yīng) _cmd
//
// *types 中的數(shù)字:
// 第一個數(shù)字:所有參數(shù)一共占用多少字節(jié)
// 后面的數(shù)字:當(dāng)前參數(shù)從第幾個字節(jié)開始
struct method_t {
SEL name; // 方法名
const char *types; // 包含了返回值類型、參數(shù)類型的編碼字符串
IMP imp; // 函數(shù)指針
};
// 方法信息列表(一維數(shù)組)
// Two bits of entsize are used for fixup markers.
struct method_list_t : entsize_list_tt<method_t, method_list_t, 0x3> {
bool isFixedUp() const;
void setFixedUp();
uint32_t indexOfMethod(const method_t *meth) const {
uint32_t i = (uint32_t)(((uintptr_t)meth - (uintptr_t)this) / entsize());
assert(i < count);
return i;
}
};
// 方法信息列表(二維數(shù)組)
class method_array_t : public list_array_tt<method_t, method_list_t> {
typedef list_array_tt<method_t, method_list_t> Super;
public:
method_list_t **beginCategoryMethodLists() {
return beginLists();
}
method_list_t **endCategoryMethodLists(Class cls);
method_array_t duplicate() {
return Super::duplicate<method_array_t>();
}
};
Type Encoding(通過 @encode() 可以查看指定類型的字符串編碼)