read_images

read_images

舊版本:對(duì)類(lèi) selector_references protocols objc_msgSend引用 進(jìn)行加載和修正,
其中獲取編譯好的類(lèi)加入一個(gè)全局管理的哈希表中,對(duì)非懶加載的(有+load實(shí)現(xiàn))的類(lèi)進(jìn)行識(shí)別,
最后分類(lèi)加載添加到對(duì)應(yīng)的宿主類(lèi)上去。
新版本:差別在于 在識(shí)別階段舊版本會(huì)methodizeClass 現(xiàn)在需要將ro(編譯好的內(nèi)容)中的方法列表、屬性、協(xié)議等加載到我們r(jià)w中去。
新版此時(shí)并不會(huì)將 ro這些內(nèi)容進(jìn)行處理 只會(huì)跟舊版本一樣把ro復(fù)制到rw->ro中去。?。?!如果這個(gè)類(lèi) 沒(méi)有分類(lèi) 是不會(huì)存在rwx(rw->ext())也就是跟舊版本區(qū)別點(diǎn) rw中沒(méi)有一份重復(fù)的 跟ro內(nèi)容一樣的,因?yàn)?rw中也有ro 所以他們做了優(yōu)化是 無(wú)分類(lèi) 到時(shí)候需要用到列表、屬性、協(xié)議直接去ro里面獲取(如果有處理 就是在 loadAllCategories 統(tǒng)一處理) (后面專(zhuān)門(mén)一篇文章進(jìn)行講述)

gdb_objc_realized_classes

int namedClassesSize = (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
gdb_objc_realized_classes = NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);

預(yù)先優(yōu)化過(guò)的類(lèi)不會(huì)加入到 gdb_objc_realized_classes 這個(gè)哈希表中來(lái),
gdb_objc_realized_classes 哈希表的裝載因子為 0.75,這是一個(gè)經(jīng)過(guò)驗(yàn)證的效率很高的擴(kuò)容臨界值。
除了 gdb_objc_realized_classes 表之外,還有一張表 allocatedClasses :
在新版的objc_已經(jīng)調(diào)整到objc_init runtime.init()處理 robjc::allocatedClasses.init();
其實(shí) gdb_objc_realized_classes 對(duì) allocatedClasses 是一種包含的關(guān)系,一張是類(lèi)的總表,一張是已經(jīng)開(kāi)辟了內(nèi)存的類(lèi)表,

Discover classes 流程

  1. 接著還是遍歷所有的 Mach-O 的 header 部分
  2. 然后通過(guò) mustReadClasses 來(lái)判斷哪些條件可以跳過(guò)讀取類(lèi)這一步驟(預(yù)檢)非必需readclass就跳過(guò)
  3. 遍歷 _getObjc2ClassList 取出的所有的類(lèi)
  4. 讀取 header 是否是 Bundle
  5. 讀取 header 是否開(kāi)啟了 預(yù)優(yōu)化
  6. 通過(guò) readClass 來(lái)讀取類(lèi)信息
  7. 判斷如果不相等并且 readClass 結(jié)果不為空,則需要重新為類(lèi)開(kāi)辟內(nèi)存

readClass

在_read_images里面的readClass missingWeakSuperclass popFutureNamedClass
是不會(huì)進(jìn)入 打斷點(diǎn)可知 至于何時(shí)處理會(huì)進(jìn)入 后期討論

其中涉及addNamedClass 把我們所有的Class 都存進(jìn)一個(gè)gdb_objc_realized_classes的map中

addClassTableEntry 已經(jīng)分配了才進(jìn)入 在所有類(lèi)的表中添加一個(gè)類(lèi)。如果addMeta為真,也自動(dòng)添加類(lèi)的元類(lèi)。這里是不會(huì)進(jìn)入的

**對(duì)于這個(gè)函數(shù)而言 封裝起來(lái)被多處調(diào)用 有部分內(nèi)容 并不是為readImages此方法所設(shè)立 **


Fix up remapped classes 流程

  1. 通過(guò) noClassesRemapped 方法判斷是否有類(lèi)引用(_objc_classrefs)需要進(jìn)行重映射
  2. 如果需要,則遍歷 EACH_HEADER
  3. 通過(guò) _getObjc2ClassRefs 和 _getObjc2SuperRefs 取出當(dāng)前遍歷到的 Mach-O 的類(lèi)引用和父類(lèi)引用,然后調(diào)用 remapClassRef 進(jìn)行重映射

Fix up @selector references 流程

  1. 遍歷 EACH_HEADER
  2. 如果開(kāi)啟了預(yù)優(yōu)化,contiue 到下一個(gè) Mach-O
  3. 通過(guò) _getObjc2SelectorRefs 拿到所有的 SEL 引用
  4. 然后對(duì)所有的 SEL 引用調(diào)用 sel_registerNameNoLock 進(jìn)行注冊(cè)
  5. 也就是說(shuō)這一流程最主要的目的就是注冊(cè) SEL ,我們注冊(cè)真正發(fā)生的地方: __sel_registerName

__sel_registerName 方法的流程:

  1. 判斷是否要加鎖
  2. 如果 sel 為空,則返回一個(gè)空的 SEL
  3. 從 builtins 中搜索,看是否已經(jīng)注冊(cè)過(guò),如果找到,直接返回結(jié)果
  4. 從 namedSelectors 哈希表中查詢(xún),找到了就返回結(jié)果
  5. 如果 namedSelectors 未初始化,則創(chuàng)建一下這個(gè)哈希表
  6. 如果上面的流程都沒(méi)有找到,則需要調(diào)用 sel_alloc 來(lái)創(chuàng)建一下 SEL ,然后把新創(chuàng)建的 SEL 插入哈希表中進(jìn)行緩存的填充

Fix up old objc_msgSend_fixup call sites 流程

  1. 遍歷 EACH_HEADER
  2. 通過(guò) _getObjc2MessageRefs 方法來(lái)獲取當(dāng)前遍歷到的 Mach-O 鏡像的所有消息引用
  3. 遍歷這些消息引用,調(diào)用 fixupMessageRef 進(jìn)行修正

Discover protocols 流程

  1. 遍歷 EACH_HEADER
  2. 通過(guò) _getObjc2ProtocolList 方法來(lái)獲取當(dāng)前遍歷到的 Mach-O 鏡像的所有消息引用
  3. 遍歷這些消息引用,調(diào)用 readProtocol 進(jìn)行讀取

Fix up @protocol references 流程

對(duì)所有的協(xié)議做重映射

Realize non-lazy classes 流程

初始化非懶加載類(lèi)( +load 方法和靜態(tài)實(shí)例)

realizeClass 新版名realizeClassWithoutSwift

前部分

  1. 判斷是否被處理過(guò)了 assert 出去了
  2. 編譯器期間就確認(rèn)了cls ro 通過(guò)cls->data()取出 (內(nèi)部有個(gè)bits 維護(hù)著對(duì)象相關(guān)數(shù)據(jù))
  3. ro->flags & RO_FUTURE 根據(jù)該變量與不同的標(biāo)志位進(jìn)行 & 操作判斷 是否為元類(lèi),是否為根類(lèi),是否為ARC 是否為 future class
  4. 申請(qǐng)rw空間 rw中的ro設(shè)置為編譯期間確認(rèn)的ro
  5. 接下來(lái)標(biāo)識(shí)位和一些參數(shù)的設(shè)置

后部分

  1. 遞歸調(diào)用realizeClass 為什么?說(shuō)明下面的方法必須先父類(lèi) 元類(lèi) 先做 會(huì)對(duì)子類(lèi)有影響
  2. SUPPORT_NONPOINTER_ISA 關(guān)于這部分目前暫時(shí)跳過(guò)
  3. 設(shè)置父類(lèi)和元類(lèi)
  4. reconcileInstanceVariables 關(guān)于成員變量(reconcile 調(diào)節(jié)一致)
    取出父類(lèi)ro對(duì)比子類(lèi)的ro instanceStart是否大于等于父類(lèi)ro instanceSize
    運(yùn)行到 ManSuperClass ro start = 8 super_ro instanceSize = 8 相同
    默認(rèn)留有一定的空間也就是說(shuō) 偏移的start 就是8 如果父類(lèi)中 instanceSize
    需求空間大于了8 都必須 進(jìn)行偏移
  5. methodizeClass ro在上面步驟已經(jīng)處理好了 現(xiàn)在需要將ro(編譯好的內(nèi)容)中的方法列表、屬性、協(xié)議、分類(lèi)(需要加入了全局分類(lèi)map這里是未識(shí)別的才做處理 一開(kāi)始是空的)等加載到我們r(jià)w中去。(新版本 還要區(qū)分于 是否分類(lèi) 后面繼續(xù)分析) ?。?!在map_images階段不進(jìn)入分類(lèi) 打斷點(diǎn)可知 因?yàn)榉诸?lèi)map是空的此時(shí)

在新版本的objc中 mapimages中 rw->ext() 分配到才會(huì)有 估計(jì)時(shí)機(jī)延后 具體分析學(xué)習(xí)也進(jìn)行延后到對(duì)應(yīng)位置

Discover categories 流程

處理所有的分類(lèi),包括類(lèi)和元類(lèi)
Whether the initial attachment of categories present at startup has

在新版本之中加入了didInitialAttachCategories判斷

在此處的 map_images作用不大 暫時(shí)忽略深入 ===》load images 中分析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容