美文网首页
Objc_msgSend流程(二)之方法慢速查找

Objc_msgSend流程(二)之方法慢速查找

作者: _涼城 | 来源:发表于2020-10-01 08:25 被阅读0次

    上篇文章Objc_msgSend流程 说到objc_msg_Send快速查找流程,最后调用_lookUpImpOrForward,但是_lookUpImpOrForward在哪里呢?

    查找_lookUpImpOrForward

    在objc源码工程调用一个方法并在该处新增一个断点,运行工程

    断点调试.png

    开启菜单栏Debug->Debug Workflow->Always Show Disassembly

    Always Show Disassembly.png

    objc_msgSend处新增一个断点,让程序运行至断点处

    objc_msgSend断点调试.png

    按住ctrl,点击step Into,进入objc_msgSend方法调试

    step Into.png

    objc_msgSend调试中找到_objc_msgSend_uncached,让程序运行至断点处,同样的按住ctrl,点击step Into;

    _objc_msgSend_uncached.png

    _objc_msgSend_uncached找到发现lookUpImpOrForward位于objc-runtime-new.mm文件

    lookUpImpOrForward.png
    探索 lookupImpOrForward

    找到lookupImpOrForward源码,lookupImpOrForward开始objc_msgSend的慢速查找

    if (fastpath(behavior & LOOKUP_CACHE)),增加断点,使代码运行到断点处,并输出参数的值

    调试lookupImpOrForward.png
    慢速查找流程

    查看lookupImpOrForward

    1. 首先查看当前cls是否有SEL的缓存

       if (fastpath(behavior & LOOKUP_CACHE)) {
              imp = cache_getImp(cls, sel);
              if (imp) goto done_nolock;
          }
      
    2. 继续查看是否当前类已知

      checkIsKnownClass(cls);
      //
      static void
      checkIsKnownClass(Class cls)
      {
          if (slowpath(!isKnownClass(cls))) {
              _objc_fatal("Attempt to use unknown class %p.", cls);
          }
      }
      
    3. 查看当前类是否已经实现,若未实现,则对class进行创建,并递归寻找父类及元类的继承链

      realizeClassMaybeSwiftAndLeaveLocked 调用realizeClassMaybeSwiftMaybeRelock调用

      realizeClassWithoutSwift

      if (slowpath(!cls->isRealized())) {
              cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
              // runtimeLock may have been dropped but is now locked again
      }
      
    4. 查看当前类是否已经初始化,若未初始化,则对class进行初始化,并递归寻找父类及元类的继承链;

      if (slowpath((behavior & LOOKUP_INITIALIZE) && !cls->isInitialized())) {
              cls = initializeAndLeaveLocked(cls, inst, runtimeLock);
              // runtimeLock may have been dropped but is now locked again
      
              // If sel == initialize, class_initialize will send +initialize and 
              // then the messenger will send +initialize again after this 
              // procedure finishes. Of course, if this is not being called 
              // from the messenger then it won't happen. 2778172
      }
      
    5. 进行查找

      for (unsigned attempts = unreasonableClassCount();;) {
             // curClass method list.
             Method meth = getMethodNoSuper_nolock(curClass, sel);
             if (meth) {
                 imp = meth->imp;
                 goto done;
             }
      
             if (slowpath((curClass = curClass->superclass) == nil)) {
                 // No implementation found, and method resolver didn't help.
                 // Use forwarding.
                 imp = forward_imp;
                 break;
             }
      
             // Halt if there is a cycle in the superclass chain.
             if (slowpath(--attempts == 0)) {
                 _objc_fatal("Memory corruption in class list.");
             }
      
             // Superclass cache.
             imp = cache_getImp(curClass, sel);
             if (slowpath(imp == forward_imp)) {
                 // Found a forward:: entry in a superclass.
                 // Stop searching, but don't cache yet; call method
                 // resolver for this class first.
                 break;
             }
             if (fastpath(imp)) {
                 // Found the method in a superclass. Cache it in this class.
                 goto done;
             }
         }
      
      • Method meth = getMethodNoSuper_nolock(curClass, sel);

        调用search_method_list_inline

        调用findMethodInSortedMethodList(SEL key, const method_list_t *list)进行折半查找。

        ALWAYS_INLINE static method_t *
        findMethodInSortedMethodList(SEL key, const method_list_t *list)
        {
           ASSERT(list);
        
           const method_t * const first = &list->first;
           const method_t *base = first;
           const method_t *probe;
           uintptr_t keyValue = (uintptr_t)key;
           uint32_t count;
        
           for (count = list->count; count != 0; count >>= 1) {
               probe = base + (count >> 1);
        
               uintptr_t probeValue = (uintptr_t)probe->name;
        
               if (keyValue == probeValue) {
                   // `probe` is a match.
                   // Rewind looking for the *first* occurrence of this value.
                   // This is required for correct category overrides.
                   while (probe > first && keyValue == (uintptr_t)probe[-1].name) {
                       probe--;
                   }
                   return (method_t *)probe;
               }
        
               if (keyValue > probeValue) {
                   base = probe + 1;
                   count--;
               }
           }
        
           return nil;
        }
        
        • 如果找到方法直接调用log_and_fill_cache,缓存该方法cache_fill(cls, sel, imp, receiver);方便下次直接在缓存中快速查找;
        • 如果未找到,则将superClass赋值给当前的class
      • 从父类中的缓存中查找,

        • 若找到该方法调用log_and_fill_cache,缓存该方法cache_fill(cls, sel, imp, receiver);方便下次直接在缓存中快速查找
        • 如果未找到,则会再次调用_lookupImpOrForward进行递归
      • 若根类未找到该方法,将forward_imp赋值给imp

        if (slowpath((curClass = curClass->superclass) == nil)) {
                   // No implementation found, and method resolver didn't help.
                   // Use forwarding.
                   imp = forward_imp;
                   break;
        }
        
      • imp等于forward_imp,则调用break退出循环

        if (slowpath(imp == forward_imp)) {
                   // Found a forward:: entry in a superclass.
                   // Stop searching, but don't cache yet; call method
                   // resolver for this class first.
                   break;
        }
        
    6. forward_imp_objc_msgForward_impcache返回的,那么forward_imp是什么呢?全局搜索找到__objc_msgForward_impcache,找到进入消息转发流程__objc_msgForward,消息转发__objc_forward_handler

      STATIC_ENTRY __objc_msgForward_impcache
      // No stret specialization.
      b    __objc_msgForward
      END_ENTRY __objc_msgForward_impcache
      
      ENTRY __objc_msgForward
      adrp x17, __objc_forward_handler@PAGE
      ldr  p17, [x17, __objc_forward_handler@PAGEOFF]
      TailCallFunctionPointer x17
      END_ENTRY __objc_msgForward
      
    7. 那么__objc_forward_handler是什么呢?我们找到__objc_forward_handlerobjc_defaultForwardHandler,而objc_defaultForwardHandler就是我们平常看到的未找到方法的提示语

      __attribute__((noreturn, cold)) void
      objc_defaultForwardHandler(id self, SEL sel)
      {
          _objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
                      "(no message forward handler is installed)", 
                      class_isMetaClass(object_getClass(self)) ? '+' : '-', 
                      object_getClassName(self), sel_getName(sel), self);
      }
      void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
      

    相关文章

      网友评论

          本文标题:Objc_msgSend流程(二)之方法慢速查找

          本文链接:https://www.haomeiwen.com/subject/oezgyktx.html