ios-runtime 初探 _objc_msgSend

运⾏时 就是代码跑起来了.被装载到内存中去了 . (你的代码保存在磁盘上没装⼊内存之前是个死家伙.只有跑到内存中才变成活的).⽽运⾏时类型检查就与前⾯讲的编译时类型检查(或者静态类型检查)不⼀样.不是简单的扫描代码.⽽是在内存中做些操作,做些判断.

即:编译器编译时会做一些操作和判断。

image.png

  • runtime 的三种使用方式

      1. Objective-C code @selector()
      1. NSObject 的方法 NSSelectorFromString()
      1. sel_registerName 函数 api

    image.png

  • clang -rewrite-objc main.m -o main.cpp

  • oc中的代码

image.png

  • c++中的转化

image.png

  • // 调用方法 = 消息发送 : objc_msgSend(消息的接受者,消息的主体(sel + 参数))

  • [LGPerson alloc]; 等价于

objc_msgSend)((id)objc_getClass("LGPerson"), sel_registerName("alloc"));

  • [person sayNB]; 等价于 objc_msgSend(person, @selector(sayNB));

等价于 objc_msgSend(person, sel_registerName("sayNB"));

  • 这里修改为NO才能通过编译

image.png

image.png

  • objc_super 结构体
    • receiver : 消息发送的接收者 如person 对象
    • super_class : 表示这个方法从哪个类中开始查找

image.png

  • 注意此时 person 继承自 teacher 最后调用到了父类的 sayHello 方法

image.png

_objc_msgSend 汇编源码分析

image.png

  • 汇编
  • cmp p0, #0 // nil check and tagged pointer check p0寄存器中存放了函数的第一个参数即如:person对象,p0与#0 比较,消息接收者是否为空。
  • b.le LNilOrTagged // (MSB tagged pointer looks negative) 判断是否为 tagged pointer 小对象类型 b 小于或等于 nil 或则 小对象 Yes: 进入 LNilOrTagged操作,NO:向下走
  • b.eq LReturnZero 判断是否为空 YES:则跳转至 LReturnZero 进行操作 NO:向下走
  • ldr p13, [x0] // p13 = isa load 将[x0]数据写入到寄存器中 即:p13寄存器保存了 对象的isa
  • GetClassFromIsa_p16 p13, 1, x0 // p16 = class isa & 掩码 找到 class 将类地址存入到p16寄存器中。
    .macro GetClassFromIsa_p16 src, needs_auth, auth_address /* note: auth_address is not required if !needs_auth */
    
    #if SUPPORT_INDEXED_ISA
            // Indexed isa
            mov	p16, \src			// optimistically set dst = src
            tbz	p16, #ISA_INDEX_IS_NPI_BIT, 1f	// done if not non-pointer isa
            // isa in p16 is indexed
            adrp	x10, _objc_indexed_classes@PAGE
            add	x10, x10, _objc_indexed_classes@PAGEOFF
            ubfx	p16, p16, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS  // extract index
            ldr	p16, [x10, p16, UXTP #PTRSHIFT]	// load class from array
    1:
    
    #elif __LP64__
    .if \needs_auth == 0 // _cache_getImp takes an authed class already
            mov	p16, \src   - 将p13寄存中的数据移动到p16寄存器中
    .else
            // 64-bit packed isa
            ExtractISA p16, \src, \auth_address --- //将p13 & 掩码 后存入到 p16寄存器中,即:p16 存放了 class
    .endif
    #else
            // 32-bit raw isa
            mov	p16, \src
    
    #endif
    
    .endmacro
    
    
    
    
    .macro ExtractISA
    and    $0, $1, #ISA_MASK  //将 $1 & 掩码 后存入到 $0 中
    .endmacro
    
    复制代码
    • 上面的操作 通过 receiver 获取了 class :因为cache是存入在 class 中的,因为先找缓存中的方法
  • CacheLookup NORMAL, _objc_msgSend, __objc_msgSend_uncached //开始查找缓存

上述流程

objc_msgSend查找缓存前操作.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享