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验证一下

相关文章
相关标签/搜索