iOS底层原理_08消息流程分析之快速查找(下)

第八节课 消息流程分析之快速查找(下)

上篇文章我们通过源码查看了方法底层调用的逻辑,但是只分析到了objc_msgSend
的主体逻辑,并没有深入了解,那么这篇文章我们就继续深入。

深入前,小小的回顾还是有必要的

主要的流程:
1.判断当前接收者是否存在cmp p0, #0

2.判断是不是SUPPORT_TAGGED_POINTERS类型。如果是,执行b.le LNilOrTagged,然后在里面执行 b.eq LReturnZero。如果不是SUPPORT_TAGGED_POINTERS类型,直接b.eq LReturnZero,此次objc_msgSend无效,结束本次消息发送。

3.如果p0存在,则将x0存入到p13,x0receiver,即类,即类的首地址,即isa,也就是说p13=isa。通过isa拿到class

GetClassFromIsa_p16 p13, 1, x0

4.查看GetClassFromIsa_p16源码,最终获取到p16=class

5.CacheLookup NORMAL

这篇文章我们就主要来分析这个CacheLookup NORMAL

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
    //
    
    mov x15, x16            // stash the original isa
LLookupStart\Function:
    // p1 = SEL, p16 = isa
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16_BIG_ADDRS
    ldr p10, [x16, #CACHE]              // p10 = mask|buckets
    lsr p11, p10, #48           // p11 = mask
    and p10, p10, #0xffffffffffff   // p10 = buckets
    and w12, w1, w11            // x12 = _cmd & mask
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16 //真机架构
    ldr p11, [x16, #CACHE]  //x16进行平移#CACHE大小,存储到p11。CACHE全局搜索赋值,是2 * __SIZEOF_POINTER__也就是2倍的指针大小,也就是16.平移后的位置就相当于cache_t的位置。p11 = cache_t
            // p11 = mask|buckets
    #if CONFIG_USE_PREOPT_CACHES
        #if __has_feature(ptrauth_calls)
    tbnz    p11, #0, LLookupPreopt\Function
    and p10, p11, #0x0000ffffffffffff   // p10 = buckets
        #else
    and p10, p11, #0x0000fffffffffffe   // p10 = buckets
    tbnz    p11, #0, LLookupPreopt\Function   //不为0就跳转LLookupPreopt
        #endif
    eor p12, p1, p1, LSR #7 
    and p12, p12, p11, LSR #48  //cache_t(_bucketsAndMaybeMask)右移48位,即清空了buckets,可以得到mask,最后将p12 & mask,得到了第一次查找bucket_t的index,即first_probed
        // x12 = (_cmd ^ (_cmd >> 7)) & mask
    #else

//  p11 cache -> p10 = buckets
//  p11, LSR #48 -> mask
//  p1(_cmd) & mask = index -> p12
    and p10, p11, #0x0000ffffffffffff   // p10 = buckets
    and p12, p1, p11, LSR #48       // x12 = _cmd & mask

#endif // CONFIG_USE_PREOPT_CACHES
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
    ldr p11, [x16, #CACHE]              // p11 = mask|buckets
    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


// objc - 源码调试 + 汇编
//  p11 cache -> p10 = buckets
//  p1(_cmd) & mask = index -> p12
//  (_cmd & mask) << 4  -> int 1 2 3 4 5   地址->int
//  buckets +  代表内存平移 (1 2 3 4)
//  b[i] -> b + I
//  p13 当前查找bucket
    add p13, p10, p12, LSL #(1+PTRSHIFT)
                        // p13 = buckets + ((_cmd & mask) << (1+PTRSHIFT))

                        // do {
//  *bucket--  p17, p9
//  bucket 里面的东西 imp (p17) sel (p9)
//  查到的 sel (p9) 和我们 say1
1:  ldp p17, p9, [x13], #-BUCKET_SIZE   //     {imp, sel} = *bucket--
    cmp p9, p1              //     if (sel != _cmd) {
    b.ne    3f              //         scan more
                        //     } else {
2:  CacheHit \Mode              // hit:    call or return imp
                        //     }
3:  cbz p9, \MissLabelDynamic       //     if (sel == 0) goto Miss;
    cmp p13, p10            // } while (bucket >= buckets)
    b.hs    1b

主要分为以下几步:
【第一步】通过cache首地址平移16字节(因为在objc_class中,cache正好距离首地址16字节,即isa首地址 占8字节,superClass占8字节),获取cache,cache中高16位存mask,低48位存buckets,即p11 = cache

【第二步】从cache中分别取出buckets和mask,并由mask根据哈希算法计算出哈希下标
通过cache和掩码(即0x0000fffffffffffe)的 & 运算,将高16位mask抹零,得到buckets指针地址,即p10 = buckets

cache右移48位,得到mask,即p11 = mask

objc_msgSend的参数p1(即第二个参数_cmd)& msak,通过哈希算法,得到需要查找存储sel-imp的bucket下标index,即p12 = index = _cmd & mask,为什么通过这种方式呢?因为在存储sel-imp时,也是通过同样哈希算法计算哈希下标进行存储,所以读取也需要通过同样的方式读取。

总结:

文字版流程

  1. 首先判断recevier是否存在
  2. recevier -> isa -> class(p16)
  3. class通过内存平移 -> cache(bucket mask)
  4. bucket掩码 -> bucket
  5. mask掩码 -> mask
  6. insert 哈希函数 (mask_t)(value & mask)
  7. 得到第一次查找的index
  8. bucket + index bucket平移获取整个缓存里面的第几个
  9. bucket{imp sel}
  10. 拿到sel_cmd 进行比较 sel == _cmd -> cacheHit -> imp^isa = imp(br)调用imp
  11. sel != _cmd bucket 再次平移
  12. 死循环 遍历
  13. 找不到 ->_objc_msgSend_uncached

图片版流程


08-objmsgSend主流程.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容