阅读 500

iOS底层探险② 从LLVM源码分析为什么alloc、retain、isKindOfClass等AWZ、RR、CORE系列方法没有走自身的IMP

⭐ 表示「核心逻辑内容」

🐈 表示「分支知识扩展」

 表示「苹果官方文档或者源码」

本文分析用到的资源:

objc4-源码

可编译的 objc4 源码 (Cooci大神)

LLVM源码

LLVM 优化处理后的结果🌰

项目中最常用的初始化对象的几个方式 alloc init new ,但通过反汇编看出实际调用的并不是自身 NSObject.mm 方法的 IMP而实际调用的是 objc_alloc objc_alloc_init objc_opt_new _ (:з」∠) _ 年轻人不讲码德、、
alloc具体流程可参考:iOS底层探险① OC对象初始化流程

调试代码如下:

WX20210609-084515.png

clang (llvm的前端) 编译输出下编译后的cpp文件
步骤1:打开终端 cdmain.m 的文件夹
步骤2:输入指令 clang -rewrite-objc main.m -o main.cpp -o是输出的意思,后面紧接输出文件名 main.cpp. ( cpp是 c plus plus 的意思 c++的文件后缀)

可以看到 Clang 编译后的上述代码如下:

WX20210609-090654.png

⭐ 之前的 OC 方法都被转换成了 objc_msgSend , 而到这一步并不是最终执行的机器码, Clang 编译器前端生成的代码还行进行 LLVM IR 优化 优化之后针对目标CPU架构转汇编 通过汇编再换成最终执行的机器码, 所以 Clang 前端编译得出的代码并不一定是最终执行的代码,可能在中间 LLVM IR 优化 被处理过

汇编查看本质——最终执行代码:

WX20210609-085131.png

LLVM 中间到底做了什么

通过 VSCode 打开下载好的 LLVM源码 搜索刚才优化后调用的 objc_opt_new 很快就能找到:g_opt_dispatch_names

WX20210609-092102.png

g_opt_dispatch_names是个 C++ 全局 set 优化用的 方法符号 ,在上方 LLVM 也给除了注释说明:
目的是加速方法分发发送,提高效率。 原因是AWZ、RR、CORE系列方法很少被重写,编译器进行了替换,执行对应方法的时候一步到位(避免了OC继承链冗长的方法查找流程,这几个方法应该是方法查找链最长的了)。 当然也有条件检测,如果有哪个方法被重写会走原来的 objc_msgSend

优化函数调用流程:

WX20210609-100900@2x.png

核心方法在 CGObjC.cpptryGenerateSpecializedMessageSend() 函数, 函数声明及注释如下:

WX20210609-094543.png

注释的内容基本同上,目的为了让消息处理更快,如果有重写方法异常走原来的 objc_msgSend

WX20210609-101509.png

⭐ 分析源码可以看到,最终在 CGF.EmitObjcAlloc 方法里完成了 OC 方法 alloc 换成优化方法 objc_alloc 如下图:

WX20210609-101854.png

其他 LLVM IR 优化方法调用处理类似, 值得一提的是 OC [[MyClass alloc]init] 这样非单个函数的代码写法也是被优化的 优化方法在 tryEmitSpecializedAllocInit 源码进行了很多校验,包括了是否是同一个 Classalloc init 等等, 可以看出编译器级别的优化是非常非常细致的 ,在写项目、SDK做性能优化可以借鉴。

WX20210609-103052.png

补充 AWZ、RR、CORE系列方法是什么

AWZ 顾名思义是 allocWithZone 的缩写,包含alloc/allocWithZone方法
RRretain release 的缩写,主要包含 retain/release/autorelease方法
CORE 是OC对象核心的一些方法,包含new/self/class/respondsToSelector/isKindOfClass方法

可以在 objc4源码 objc-runtime-new.h 找到其定义

// class or superclass has default alloc/allocWithZone: implementation
// Note this is is stored in the metaclass.
#define FAST_CACHE_HAS_DEFAULT_AWZ    (1<<14)

// class or superclass has default retain/release/autorelease/retainCount/
//   _tryRetain/_isDeallocating/retainWeakReference/allowsWeakReference
#define FAST_HAS_DEFAULT_RR     (1UL<<2)

// class or superclass has default new/self/class/respondsToSelector/isKindOfClass
#define FAST_CACHE_HAS_DEFAULT_CORE   (1<<15)
复制代码

写在最后

文章的代码环境基于苹果 objc4-818.2 源码、Xcode12,内容尽量做到了结构化、精炼,以便节省读者阅读时间成本,如有哪里书写不对或者补充欢迎及时交流沟通~~

最后,感谢您的阅读 一切祝好哈 have a nice codding \(^o^)/~

文章分类
iOS
文章标签