cache_t底層探索

咱們知道cache是用來作緩存,經常使用的操做增刪改查。html

首先來看下緩存

cache_et底層源碼分析

struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
    explicit_atomic<struct bucket_t *> _buckets;
    explicit_atomic<mask_t> _mask;//此處模擬器會執行
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16//此處真機會執行
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;

    // How much the mask is shifted by.
    static constexpr uintptr_t maskShift = 48;

    // Additional bits after the mask which must be zero. msgSend
    // takes advantage of these additional bits to construct the value
    // `mask << 4` from `_maskAndBuckets` in a single instruction.
    static constexpr uintptr_t maskZeroBits = 4;

    // The largest mask value we can store.
    static constexpr uintptr_t maxMask = ((uintptr_t)1 << (64 - maskShift)) - 1;

    // The mask applied to `_maskAndBuckets` to retrieve the buckets pointer.
    static constexpr uintptr_t bucketsMask = ((uintptr_t)1 << (maskShift - maskZeroBits)) - 1;

    // Ensure we have enough bits for the buckets pointer.
    static_assert(bucketsMask >= MACH_VM_MAX_ADDRESS, "Bucket field doesn't have enough bits for arbitrary pointers.");
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
    //此處其他非64位會執行
    // _maskAndBuckets stores the mask shift in the low 4 bits, and
    // the buckets pointer in the remainder of the value. The mask
    // shift is the value where (0xffff >> shift) produces the correct
    // mask. This is equal to 16 - log2(cache_size).
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;

    static constexpr uintptr_t maskBits = 4;
    static constexpr uintptr_t maskMask = (1 << maskBits) - 1;
    static constexpr uintptr_t bucketsMask = ~maskMask;
#else
#error Unknown cache mask storage type.
#endif

#if __LP64__
    uint16_t _flags;
#endif
    uint16_t _occupied;
複製代碼

ps:第一行代碼作explicit_atomic(顯示原子性),其做用就是爲了安全安全

  • bucket_t下層markdown

    struct bucket_t { private: // IMP-first is better for arm64e ptrauth and no worse for arm64. // SEL-first is better for armv7* and i386 and x86_64. #if arm64 //真機 explicit_atomic<uintptr_t> _imp; explicit_atomic _sel; #else //非真機 explicit_atomic _sel; explicit_atomic<uintptr_t> _imp; #endifapp

    // Compute the ptrauth signing modifier from &_imp, newSel, and cls.
    uintptr_t modifierForSEL(SEL newSel, Class cls) const {
        return (uintptr_t)&_imp ^ (uintptr_t)newSel ^ (uintptr_t)cls;
    }
    
    // Sign newImp, with &_imp, newSel, and cls as modifiers.
    uintptr_t encodeImp(IMP newImp, SEL newSel, Class cls) const {
        if (!newImp) return 0;
    複製代碼

    #if CACHE_IMP_ENCODING == CACHE_IMP_ENCODING_PTRAUTH return (uintptr_t) ptrauth_auth_and_resign(newImp, ptrauth_key_function_pointer, 0, ptrauth_key_process_dependent_code, modifierForSEL(newSel, cls)); #elif CACHE_IMP_ENCODING == CACHE_IMP_ENCODING_ISA_XOR return (uintptr_t)newImp ^ (uintptr_t)cls; #elif CACHE_IMP_ENCODING == CACHE_IMP_ENCODING_NONE return (uintptr_t)newImp; #else #error Unknown method cache IMP encoding. #endif }源碼分析

cache_t結構

CACHE_MASK_STORAGE==CACHE_MASK_STORAGE_OUTLINEDui

CACHE_MASK_STORAGE==CACHE_MASK_STORAGE_HIGH_16atom

struct bucket_t *cache_t::buckets()
{
    uintptr_t maskAndBuckets = _maskAndBuckets.load(memory_order::memory_order_relaxed);
    return (bucket_t *)(maskAndBuckets & bucketsMask);
}
複製代碼

objc代碼舉例分析

// cache_t
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        CFPerson *person  = [CFPerson alloc];
        Class pClass = [CFPerson class];

        [person sayHello];
        [person sayCode];
        [person sayMaster];

        NSLog(@"%@",pClass);
    }
    return 0;
}

//CFPerson.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface CFPerson : NSObject

@property (nonatomic, copy) NSString *cgName;

@property (nonatomic, strong) NSString *nickName;

- (void)sayHello;

- (void)sayCode;

- (void)sayMaster;

- (void)sayNB;

+ (void)sayHappy;

@end
複製代碼

[person sayHello];斷點打印:spa

接着過一個斷點打印結果:3d

此時發現調用[person sayHello] _occupied便有了值, 此刻咱們能夠猜測一下,每當調用一次方法,便緩存一次。

嘗試一下:

再往下讀取** 3 . b u c k e t s 獲得 < s p a n > 3._buckets獲得**<span> 4

再繼續讀取$4打印發現打印了發現出問題了,出現一堆亂碼:

咋辦?靈機一動,再去看看cache_t源碼:

此刻關鍵代碼
public:
    static bucket_t *emptyBuckets();

    struct bucket_t *buckets();
    mask_t mask();
    mask_t occupied();
    void incrementOccupied();
    void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
    void initializeToEmpty();

    unsigned capacity();
    bool isConstantEmptyCache();
    bool canBeFreed();                                                                         
複製代碼

此刻讀取**$5.buckets()**

此刻便有了sel、_imp了,打印sel、_imp方法

打印sel()方法打能夠獲得定義的方法

直接用imp()打印卻出現錯誤:

去源碼看看發現imp須要帶一個參數:

inline SEL sel() const { return _sel.load(memory_order::memory_order_relaxed); }

    inline IMP imp(Class cls) const {
        uintptr_t imp = _imp.load(memory_order::memory_order_relaxed);
        if (!imp) return nil;
#if CACHE_IMP_ENCODING == CACHE_IMP_ENCODING_PTRAUTH
        SEL sel = _sel.load(memory_order::memory_order_relaxed);
        return (IMP)
            ptrauth_auth_and_resign((const void *)imp,
                                    ptrauth_key_process_dependent_code,
                                    modifierForSEL(sel, cls),
                                    ptrauth_key_function_pointer, 0);
#elif CACHE_IMP_ENCODING == CACHE_IMP_ENCODING_ISA_XOR
        return (IMP)(imp ^ (uintptr_t)cls);
#elif CACHE_IMP_ENCODING == CACHE_IMP_ENCODING_NONE
        return (IMP)imp;
#else
#error Unknown method cache IMP encoding.
#endif
    }

    template <Atomicity, IMPEncoding>
    void set(SEL newSel, IMP newImp, Class cls);
};
複製代碼

再試一下

經過MachOView驗證一下

相關文章
相關標籤/搜索