8.objc_msgSend下

230 阅读1分钟

一、问题回顾

当调用一次函数之后_maybeMask,按道理来说不应该是3吗?为什么_maybeMask=7? image.png 方式1:当插入函数的时候cache会调用insert函数,所以在insert函数中打印 image.png 重新调试 image.png 可以看到当调用saySomething函数时,系统自动调用了respondsToSelector和class函数

方式2:在insert函数中过滤打印 image.png 运行结果 image.png 第一个是空,第二个是respondsToSelector,第三个是class,第四个是什么呢? 最后一个的imp和第一个的buckets的地址是一样的,猜想最后一个就是buckets,buckets插入的时候是调用的set方法 image.png 那个函数会调用set呢,reallocate函数会 image.png allocateBuckets函数 image.png 最后从注释中可以看到,bucket会在最后一个位置插入一个并且值为1。。。最后一个是边界符号,也就解释了为什么mask=capacity-1

刚才是在lldb的环境下打印的,那代码直接调用还是一样吗?结果显而易见。。。 image.png

二、汇编objc_msgSend分析

首先判断receive是否是taggedPoint或者是nil image.png 获取isa完毕,执行

CacheLookup NORMAL, _objc_msgSend, __objc_msgSend_uncached image.png CACHE的定义(__SIZEOF_POINTER__指针的大小 8) CACHE = 16

#define CACHE (2 * SIZEOF_POINTER)

LLookupPreopt\Function: 定义 image.png LLookupStart\Function: 定义 image.png .macro CacheHit定义 image.png .macro TailCallCachedImp定义 image.png

总结:

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