一、问题回顾
当调用一次函数之后_maybeMask,按道理来说不应该是3吗?为什么_maybeMask=7?
方式1:当插入函数的时候cache会调用insert函数,所以在insert函数中打印
重新调试
可以看到当调用saySomething函数时,系统自动调用了respondsToSelector和class函数
方式2:在insert函数中过滤打印
运行结果
第一个是空,第二个是respondsToSelector,第三个是class,第四个是什么呢?
最后一个的imp和第一个的buckets的地址是一样的,猜想最后一个就是buckets,buckets插入的时候是调用的set方法
那个函数会调用set呢,reallocate函数会
allocateBuckets函数
最后从注释中可以看到,bucket会在最后一个位置插入一个并且值为1。。。最后一个是边界符号,也就解释了为什么mask=capacity-1
刚才是在lldb的环境下打印的,那代码直接调用还是一样吗?结果显而易见。。。
二、汇编objc_msgSend分析
首先判断receive是否是taggedPoint或者是nil
获取isa完毕,执行
CacheLookup NORMAL, _objc_msgSend, __objc_msgSend_uncached
CACHE的定义(__SIZEOF_POINTER__指针的大小 8) CACHE = 16
#define CACHE (2 * SIZEOF_POINTER)
LLookupPreopt\Function: 定义
LLookupStart\Function: 定义
.macro CacheHit定义
.macro TailCallCachedImp定义
总结:
1.判断receive是否存在
2.通过receive -> isa -> class(放在p16中)
3.class -> 内存平移 -> cache(bucket mask)
4.bucket掩码 -> bucket
5.mask掩码 -> mask
6.insert 哈希函数中 (mask_t)(value & mask)
7.第一次查找的index
8.bucket + index 整个缓存里面的第几个bucket
9.bucket{imp sel}
10.sel == _cmd -> cacheHit -> imp^isa = imp(br) 调用imp
11.如果找不到,bucket-- 再次平移
12.死循环遍历,直到找到
13.一直找不到 __objc_msgSend_uncached