小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
快速查找流程:
- 将类对象地址,内存平移
16字节,取地址,得到cache首地址,即:_bucketsAndMaybeMask _bucketsAndMaybeMask & bucketsMask,获取buckets首地址- 判断
_bucketsAndMaybeMask的0号位不为0,进入LLookupPreopt流程,查找共享缓存 - 否则,通过
_bucketsAndMaybeMask >> 48,得到mask (_cmd ^ (_cmd >> 7)) & mask,得到下标i。源码中的cache_hash函数- 通过
i * 16得到偏移值,buckets首地址+偏移值,得到指定下标的bucket 流程1:- 读取
bucket_t中的imp和sel - 通过
bucket_t - 16字节,读取上一个bucket
- 读取
流程2:- 如果
sel存在,并且等于_cmd,进入CacheHit缓存命中流程 -CacheHit流程:使用imp = imp ^ cls解码 - 跳转到指定
imp函数地址
- 如果
流程3:- 如果
sel不存在,进入__objc_msgSend_uncached流程 - 上一个
bucket地址和buckets首地址比较,如果>=,进入流程1 - 否则,
<首地址,获取mask下标的bucket,进入流程4
- 如果
流程4:- 读取
bucket_t中的imp和sel - 通过
bucket_t - 16字节,读取上一个bucket - 如果
sel等于_cmd,进入流程2 - 如果
sel存在,并且上一个bucket地址>指定下标bucket地址,进入流程4 - 否则,进入
__objc_msgSend_uncached流程
- 读取
消息快速查找流程中,如果无法命中缓存,进入MissLabelDynamic流程。而MissLabelDynamic即是调用CacheLookup时传入的__objc_msgSend_uncached
流程探索:
- 核心流程:
__objc_msgSend_uncached→MethodTableLookup→_lookUpImpOrForward lookUpImpOrForward函数,并且不是汇编代码实现,而是C/C++函数- 汇编和C/C++的相互调用:
C/C++中调用汇编,在汇编代码中查找时,在方法名称最前面加一个下划线- 汇编中调用
C/C++函数,在C/C++代码中查找时,去掉方法名称最前面的一个下划线