美文网首页
方法查找流程 objc_msg_arm64.s

方法查找流程 objc_msg_arm64.s

作者: 答案不止一个 | 来源:发表于2020-09-19 15:30 被阅读0次
    常用汇编指令图片.png

    https://www.cnblogs.com/prayer521/p/5894198.html

    CacheHit
    1. NORMAL
    2. GETIMP
    3. LOOKUP
    // CacheHit: x17 = cached IMP, x12 = address of cached IMP, x1 = SEL, x16 = isa
    .macro CacheHit
    .if $0 == NORMAL
        TailCallCachedImp x17, x12, x1, x16 // authenticate and call imp
    .elseif $0 == GETIMP
        mov p0, p17
        cbz p0, 9f          // don't ptrauth a nil imp
        AuthAndResignAsIMP x0, x12, x1, x16 // authenticate imp and re-sign as IMP
    9:  ret             // return IMP
    .elseif $0 == LOOKUP
        // No nil check for ptrauth: the caller would crash anyway when they
        // jump to a nil IMP. We don't care if that jump also fails ptrauth.
        AuthAndResignAsIMP x17, x12, x1, x16    // authenticate imp and re-sign as IMP
        ret             // return imp via x17
    .else
    

    CheckMiss

    传入的 p9 为 计算出的bucket的imp;因为是hash的存储,在key出没有数据说明就没有sel的数据

    • 如果p9 为0,即选中的bucket的sel没有存储,说明sel不存在,则跳到__objc_msgSend_uncached / GETIMP / __objc_msgLookup_uncached
    • 否则返回原逻辑继续执行
    // 判断当前bucket
    // 根据之前的p1 进行判断,如果p9 (循环中的bucket的imp 是为0,这去跳转到 uncached)
    .macro CheckMiss
        // miss if bucket->sel == 0
    .if $0 == GETIMP
        cbz p9, LGetImpMiss
    .elseif $0 == NORMAL
        cbz p9, __objc_msgSend_uncached
    .elseif $0 == LOOKUP
        cbz p9, __objc_msgLookup_uncached
    .else
    
    
    .macro JumpMiss
    .if $0 == GETIMP
        b   LGetImpMiss
    .elseif $0 == NORMAL
        b   __objc_msgSend_uncached
    .elseif $0 == LOOKUP
        b   __objc_msgLookup_uncached
    .else
    .abort oops
    .endif
    .endmacro
    

    CacheLookup

    /.macro CacheLookup
        //
        // Restart protocol:
        //
        //   As soon as we're past the LLookupStart$1 label we may have loaded
        //   an invalid cache pointer or mask.
        //
        //   When task_restartable_ranges_synchronize() is called,
        //   (or when a signal hits us) before we're past LLookupEnd$1,
        //   then our PC will be reset to LLookupRecover$1 which forcefully
        //   jumps to the cache-miss codepath which have the following
        //   requirements:
        //
        //   GETIMP:
        //     The cache-miss is just returning NULL (setting x0 to 0)
        //
        //   NORMAL and LOOKUP:
        //   - x0 contains the receiver
        //   - x1 contains the selector
        //   - x16 contains the isa
        //   - other registers are set as per calling conventions
        //
    LLookupStart$1:
    
        // p1 = SEL, p16 = isa
        // #define CACHE            (2 * __SIZEOF_POINTER__)  ?? 16
        // [x16 #16] => isa  向右16字节 -》 cache的地址
        // 将cache的地址给到p11
        ldr p11, [x16, #CACHE]              // p11 = mask|buckets
    
    #if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
        // 根据 bucketMask  & p11    p10 等于 bucket的地址
        and p10, p11, #0x0000ffffffffffff   // p10 = buckets
        // 去获取 hashkey
        and p12, p1, p11, LSR #48       // x12 = _cmd & mask
    #elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
        and p10, p11, #~0xf         // p10 = buckets
        and p11, p11, #0xf          // p11 = maskShift
        mov p12, #0xffff
        lsr p11, p12, p11               // p11 = mask = 0xffff >> p11
        and p12, p1, p11                // x12 = _cmd & mask
    #else
    #error Unsupported cache mask storage for ARM64.
    #endif
    
        // PTRSHIFT 3 ; p12 是index hashkey
        // p12, LSL #(1+PTRSHIFT)  是  p12 << (1 + PTRSHIFT)
        // 所以这个操作就是 p12 = p10 + p12 << (1 + PTRSHIFT)
        // p12 存储着 hashkey 对应的bucket 地址
        // p10 时bucket 首地址
        add p12, p10, p12, LSL #(1+PTRSHIFT)
                         // p12 = buckets + ((_cmd & mask) << (1+PTRSHIFT))
        // ldp/stp 是 ldr/str 的衍生, 可以同时读/写两个寄存器, ldr/str只能读写一个
        // ldp x1 , x0, [sp, #0x10] ; 将sp偏移16个字节的值取出来,放入x1 和 x0
        ldp p17, p9, [x12]      // {imp, sel} = *bucket
        
        // p1 时cmd
    1:  cmp p9, p1          // if (bucket->sel != _cmd)
        b.ne    2f          //     scan more
        CacheHit $0         // call or return imp
        
    2:  // not hit: p12 = not-hit bucket
        // CheckMiss normal  -> 判断p9 是否是0
        // 即判断查找到的是不是为空,如果为空,跳转 去方法表查
        // 如果不为空,则是hash冲突,继续向前查找
        CheckMiss $0            // miss if bucket->sel == 0
        // 判断是否已经是第一个了。如果是首个,这去方法表查找
        cmp p12, p10        // wrap if bucket == buckets
        b.eq    3f // 则跳转到下面的3f
        
        // 还可以继续冲突向前查找
        ldp p17, p9, [x12, #-BUCKET_SIZE]!  // {imp, sel} = *--bucket
        b   1b          // loop 
    
    3:  // wrap: p12 = first bucket, w11 = mask
    #if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
        add p12, p12, p11, LSR #(48 - (1+PTRSHIFT))
                        // p12 = buckets + (mask << 1+PTRSHIFT)
    #elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
        add p12, p12, p11, LSL #(1+PTRSHIFT)
                        // p12 = buckets + (mask << 1+PTRSHIFT)
    #else
    #error Unsupported cache mask storage for ARM64.
    #endif
    
        // Clone scanning loop to miss instead of hang when cache is corrupt.
        // The slow path may detect any corruption and halt later.
    
        ldp p17, p9, [x12]      // {imp, sel} = *bucket
        
        // 如果不相等,
    1:  cmp p9, p1          // if (bucket->sel != _cmd)
        b.ne    2f          //     scan more
        CacheHit $0         // call or return imp
        
    2:  // not hit: p12 = not-hit bucket
        CheckMiss $0            // miss if bucket->sel == 0
        cmp p12, p10        // wrap if bucket == buckets
        b.eq    3f
        ldp p17, p9, [x12, #-BUCKET_SIZE]!  // {imp, sel} = *--bucket
        b   1b          // loop
    
    LLookupEnd$1:
    LLookupRecover$1:
    3:  // double wrap
        JumpMiss $0
    
    .endmacro
    

    在cache中查找imp的逻辑。

    1. 计算 bucket的地址和mask, 参考arm64下 bit的内存布局(0-48 是bucket的地址。其他的位置是 mask的数据)

    相关文章

      网友评论

          本文标题:方法查找流程 objc_msg_arm64.s

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