咱們知道cache是用來作緩存,經常使用的操做增刪改查。html
首先來看下緩存
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_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);
}
複製代碼
// 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便有了值, 此刻咱們能夠猜測一下,每當調用一次方法,便緩存一次。
嘗試一下:
再往下讀取** 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驗證一下