objc_msgSend(id self, SEL _cmd, ...) 中SEL找到IMP的流程
以下是苹果开源代码中Runtime底层的部分删减后的汇编代码
ENTRY _objc_msgSend
ldr x13, [x0] // x13 = isa
and x16, x13, #ISA_MASK // x16 = class
cmp x0, #0 // nil check and tagged pointer check
b.le LNilOrTagged // (MSB tagged pointer looks negative)
LGetIsaDone:
CacheLookup NORMAL // calls imp or objc_msgSend_uncached
LNilOrTagged:
b.eq LReturnZero // nil check
END_ENTRY _objc_msgSend
1.首先会进入汇编中 ENTRY _objc_msgSend
2.如果指针小于等于 LNilOrTagged 直接return返回
3.通过isa 找到相应类class
4.CacheLookup : NORMALCacheLookup源码中注释为:
Locate the implementation for a selector in a class method cache.
在类的方法缓存中 为 SEL 定位到 IMP。
5.此时全局搜索CacheLookup,在objc_msg_arm64.s中会找到其对应的宏CacheHit、CheckMiss、add。
.macro CacheLookup
1: CacheHit $0 // call or return imp
返回IMP,并执行
<1> MESSENGER_END_FAST 结束快速查找路径
<2> GETIMP 返回IMP
<3> LOOKUP
2: CheckMiss $0 // miss if bucket->sel == 0
执行
<1> GETIMP LGetImpMiss 没找到IMP
<2> __objc_msgSend_uncached
<3> __objc_msgLookup_uncached
3: add x12, x12, w11, UXTW #4 // x12 = buckets+(mask<<4)
执行
<1> CacheHit
<2> CheckMiss
<3> JumpMiss
6.当执行__objc_msgSend_uncached时,说明没有相应缓存。将会在__objc_msgSend_uncached中执行MethodTableLookup。
STATIC_ENTRY __objc_msgSend_uncached
MethodTableLookup
END_ENTRY __objc_msgSend_uncached
在MethodTableLookup的宏定义中会发现__class_lookupMethodAndLoadCache3
全局搜索__class_lookupMethodAndLoadCache3发现没有什么多余的东西可以看,尝试去掉前边的_后发现新大陆!
汇编通过_class_lookupMethodAndLoadCache3

本文详细阐述了在iOS Runtime中,如何通过SEL(选择子)找到IMP(实现)。从苹果开源的Runtime底层汇编代码开始,介绍了从方法缓存查找,到全局搜索,再到动态方法解析和消息转发的过程。在没有找到对应IMP时,系统会执行消息转发流程,最终确保消息的正确处理。同时,文章提到了通过特定途径查看方法调用堆栈信息,以便于调试和理解运行时机制。
最低0.47元/天 解锁文章
2842

被折叠的 条评论
为什么被折叠?



