手撕 iOS 底层03 -- NSObject的alloc分析

661 阅读2分钟

手撕 iOS 底层03 -- NSObject的alloc分析


本章要点主要探索NSObjectalloc源码?为什么要探索NSObject的源码呢, 上一篇手撕iOS底层02 -- 分析alloc&init&new不是分析过alloc的源码了嘛, 通过实践得知, NSObject *objc = [NSObject alloc];这行代码是不会直接走alloc方法里的, 这也就和我们之前探索的自定义类alloc流程有区别?所以这一章分析下NSObjectalloc和自定义类的alloc有什么区别?


0x00 -- objc_alloc

01

在断点处,点击Debug --> Debug Workflow --> Always Show Disassembly

02

通过汇编调试得知:

  • NSObjectalloc之前会调用objc_alloc,自定义类Test也会先调用objc_alloc;

系统级别就把NSObject的初始化做了,所以NSObjectalloc的调用关系是:

alloc --> objc_alloc --> calloc --> _objc_rootAllocWithZone

而自定义类的调用关系是:

alloc --> objc_alloc --> calloc --> objc_msgSend(cls,alloc) --> alloc -- > calloc --> _objc_rootAllocWithZone


0x01 -- 分析自定义类调用俩次alloc

首先探究下,为什么自定义的类调用alloc会直接走到objc_alloc的方法内?

究其原因, 基于alloc的特殊性,应该是LLVM编译器帮我们做了函数指针跳转,所以找一份苹果开源的llvm-project,看看其中是否可以找到一些蛛丝马迹👩‍❤️‍👩

  1. 搜索objc_alloc,找到如下所示,在当前文件由很多objc_alloc关键字;一点一点往下捋;

LLVM-1

  1. 再往下看,shouldUseRuntimeFunctionForCombinedAllocInit这个方法表示版本控制;

LLVM-2

  1. 然后查找什么地方使用了版本控制。找到特殊消息发送tryEmitSpecializedAllocInit

LLVM-3

  1. 遇到不好查找的关键代码时,开启上帝视觉,当前查找关键字omf-aloc

LLVM-4

在下边会调用这个方法特殊消息发送方法tryGenerateSpecializedMessageSend 第一次会调用objc_alloc,然后条件不成立,走GenerateMessageSend普通消息发送,走到alloc流程;So

自定义类的流程alloc会走俩次,第一次发送alloc会走到objc_alloc,通过objc_alloc走到callAlloc消息发送,会再次走到alloc源码里;

LLVM-5

CodeGen::RValue CGObjCRuntime::GeneratePossiblySpecializedMessageSend(
    CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType,
    Selector Sel, llvm::Value *Receiver, const CallArgList &Args,
    const ObjCInterfaceDecl *OID, const ObjCMethodDecl *Method,
    bool isClassMessage) {
  if (Optional<llvm::Value *> SpecializedResult =
          tryGenerateSpecializedMessageSend(CGF, ResultType, Receiver, Args,
                                            Sel, Method, isClassMessage)) {
    return RValue::get(SpecializedResult.getValue());
  }
  return GenerateMessageSend(CGF, Return, ResultType, Sel, Receiver, Args, OID,
                             Method);
}

这段代码是解释为什么走俩次alloc的, 在if条件里的tryGenerateSpecializedMessageSend这个函数一定会走, 从上可知,这个函数里有一个case判断,如果是alloc,会调用objc_alloc,然后这个if条件不成立, 会执行下边GenerateMessageSend函数,执行普通的消息发送 ,走alloc流程。


0x02 -- 附上流程图

NSObject流程

  • NSObject alloc流程图

自定义类alloc流程

  • 自定义类alloc流程图