
在alloc的底层源码探索过程中发现了callAlloc被调用了两次,带着疑惑,在初始化YDPerson时下了一个断点,并开启查看汇编模式


通过上图汇编发现在断点处调用的符号是objc_alloc,不应该是alloc吗?
于是在objc源码中在alloc和objc_alloc都下断点。



通过断点调试发现没有先执行alloc,而是先是来调用了objc_alloc执行了一次callAlloc,然后调用了alloc接着调用了_objc_rootAlloc然后又调用了一次callAlloc,虽然通过断点跟流程找到了两次执行的过程,但苹果为何要这样做呢?,于是开始在 objc4-818.2源码中疯狂查找objc_alloc,最后在objc-runtime-new.mm文件中找到了一些线索

通过上图可以发现函数fixupMessageRef对alloc做了处理,sel为alloc的imp重新指向到了objc_alloc,说明做了hook处理,接着在源码中查找fixupMessageRef的调用

最后在 _read_images函数中找到了fixupMessageRef函数的调用,在函数注释中提示了_read_images的调用函数是map_images_nolock

在函数map_images中调用了函数map_images_nolock

最终我们在_objc_init函数内的_dyld_objc_notify_register中查找到了map_images的调用

通过一系列的断点跟踪,最终反推出了调用的流程,发现最终执行是在_objc_init,然而_objc_init是在dyld动态链接后才执行的,得出结论fixupMessageRef消息的修复是在dyld之后,那么消息的绑定即sel和imp的绑定肯定是在dyld之前才行,就是在编译阶段了,接下来通过llvm源码继续查找objc_alloc



通过不停的搜索alloc,最终在tryGenerateSpecializedMessageSend函数中找到了case OMF_alloc:这里对消息类型的alloc和allocWithZone都做了特殊的处理,当消息为alloc时,直接对消息的接收者调用了objc_alloc,而tryGenerateSpecializedMessageSend又来至于GeneratePossiblySpecializedMessageSend,在这个函数里有两个判断,针对这个消息接收者首先会尝试发送一个特殊的消息,通过tryGenerateSpecializedMessageSend的实现可知,这个特殊的消息就是当消息为alloc时就发送一个特殊的objc_alloc消息,如果已经发送过了就直接走正常的消息发送即alloc消息,这也就验证了为什么alloc会走objc_alloc,原来苹果底层在编译阶段进行了llvm的优化。