Runtime 02 - Class(方法信息列表、方法緩存)

Runtime 02 - Class(方法信息列表、方法緩存)

Class 結(jié)構(gòu)圖

關(guān)于對(duì) objc_class、class_data_bits_t、class_rw_t、class_ro_t 的解讀,請(qǐng)參考這里Objective-C 對(duì)象的本質(zhì) 01 - 底層實(shí)現(xiàn))。

SEL、IMP

// 方法名(選擇器)
//
// 可以通過(guò) @selector() 或 sel_registerName() 獲取 SEL。
// 可以通過(guò) sel_getName() 或 NSStringFromSelector() 將 SEL 轉(zhuǎn)換為字符串。
// 不同類中的同名方法所對(duì)應(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);
};
// 方法緩存列表
// 
// 用散列表(哈希表)來(lái)緩存調(diào)用多的方法,可以提高查找方法的速度。
// 
// _mask 為什么是 _buckets 的長(zhǎng)度 -1 ?
// -1 能確保 (key & _mask) <= (_buckets 的長(zhǎng)度 - 1),用來(lái)作為 _buckets 的下標(biāo)來(lái)取值。
// 在 cache_t::find() 函數(shù)中可以看到計(jì)算下標(biāo)的代碼。
// 
// _buckets 的動(dòng)態(tài)擴(kuò)容:
// 向 _buckets 添加最后一個(gè)緩存時(shí)會(huì)進(jìn)行擴(kuò)容。
// 每次擴(kuò)容為原來(lái)的兩倍(2^n)。
// 擴(kuò)容時(shí)會(huì)將緩存清除,因?yàn)閿U(kuò)容后 _mask 發(fā)生了變化。
// 通過(guò) cache_t::expand() 函數(shù)中進(jìn)行擴(kuò)容。
struct cache_t {
    struct bucket_t *_buckets; // 散列表
    mask_t _mask;              // 散列表的長(zhǎng)度 -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)
};

// 擴(kuò)容列表
void cache_t::expand()
{
    cacheUpdateLock.assertLocked();
    
    // 計(jì)算新的長(zhǎng)度(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;
    }

    // 擴(kuò)容并清除舊的緩存
    reallocate(oldCapacity, newCapacity);
}
// 擴(kuò)容列表并清除舊的緩存
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();               // 取出散列表的長(zhǎng)度 -1 的值(_mask)
    mask_t begin = cache_hash(k, m); // 計(jì)算緩存的哈希值(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)計(jì)算下一個(gè)下標(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 |
// 例如一個(gè)沒(méi)有返回值且沒(méi)有參數(shù)的方法,它的 method_t 中的 *types 為 v16@:8
// | v16  | @0 | :8  |
// | void | id | SEL |
// 兩個(gè)參數(shù)為默認(rèn)參數(shù),id 對(duì)應(yīng) self,SEL 對(duì)應(yīng) _cmd
// 
// *types 中的數(shù)字:
// 第一個(gè)數(shù)字:所有參數(shù)一共占用多少字節(jié)
// 后面的數(shù)字:當(dāng)前參數(shù)從第幾個(gè)字節(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(通過(guò) @encode() 可以查看指定類型的字符串編碼)


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容