關(guān)于huatuo可行性的思維實(shí)驗(yàn)
在確定目標(biāo),動(dòng)手實(shí)現(xiàn)huatuo前,有一個(gè)必須考慮的問(wèn)題——我們?nèi)绾未_定huatuo的可行性?
il2cpp雖然不是一個(gè)極其完整的運(yùn)行時(shí),但代碼仍高達(dá)12w行,復(fù)雜度相當(dāng)高,想要短期內(nèi)深入了解它的實(shí)現(xiàn)是非常困難的。而且除了官方幾個(gè)介紹il2cpp的博客外,幾乎找不到其他文檔。 Hybrid mode execution 的實(shí)現(xiàn)復(fù)雜度也很高,如果不能確信能夠在il2cpp上實(shí)現(xiàn)這套機(jī)制,貿(mào)然投入開(kāi)發(fā),萬(wàn)一幾個(gè)月后發(fā)現(xiàn)此路不通,或者說(shuō)開(kāi)發(fā)完成后,突然發(fā)現(xiàn)有一個(gè)嚴(yán)重并且無(wú)解的系統(tǒng)性的缺陷導(dǎo)致這個(gè)方案完全不可用于商業(yè)項(xiàng)目,這會(huì)帶來(lái)巨大的資源浪費(fèi),以及對(duì)開(kāi)發(fā)者產(chǎn)生巨大的信心挫傷。 磨刀不誤砍柴工,在動(dòng)手前從理論上確信這套方案有極高可行性,是完全必要的。
?
以我們對(duì)CLR運(yùn)行時(shí)的認(rèn)識(shí),要實(shí)現(xiàn) hybrid mode execution 機(jī)制,至少要解決以下幾個(gè)問(wèn)題:
能夠動(dòng)態(tài)注冊(cè)元數(shù)據(jù),這些動(dòng)態(tài)注冊(cè)的元數(shù)據(jù)必須在運(yùn)行時(shí)中跟AOT元數(shù)據(jù)完全等價(jià)。
所有調(diào)用動(dòng)態(tài)加載的assembly中函數(shù)的路徑,都能定向到正確的解釋器實(shí)現(xiàn)。包括虛函數(shù)override、delegate回調(diào)、反射調(diào)用等等
解釋器中的gc,必須能夠與AOT部分的gc統(tǒng)一處理
多線程相關(guān)能正常工作。包括且不限于創(chuàng)建Thread、async、volatile、ThreadStatic等等
我們下面一一分析解決這些問(wèn)題
動(dòng)態(tài)注冊(cè)元數(shù)據(jù)
我們大略地分析了il2cpp元數(shù)據(jù)初始化相關(guān)代碼,得出以下結(jié)論。
首先,動(dòng)態(tài)修改globalmetadata.dat這個(gè)方式不可行。因?yàn)間lobalmetadata.dat保存了持久化的元數(shù)據(jù),元數(shù)據(jù)之間關(guān)系大量使用id來(lái)相互引用,添加新的數(shù)據(jù)很容易引入錯(cuò)誤,變成極難檢測(cè)的bug。另外,globalmetadata里有不少數(shù)據(jù)項(xiàng)由于沒(méi)有文檔,無(wú)法分析實(shí)際用途,也不得而知如何設(shè)置正確的值。另外,運(yùn)行時(shí)會(huì)動(dòng)態(tài)加載新的dll,重新計(jì)算globalmetadata.dat是成本高昂的事情。而且il2cpp中元數(shù)據(jù)管理并不支持二次加載,重復(fù)加載globalmetadata.dat會(huì)產(chǎn)生相當(dāng)大的代碼改動(dòng)。
一個(gè)較可行辦法,修改所有元數(shù)據(jù)訪問(wèn)的底層函數(shù),檢查被訪問(wèn)的元數(shù)據(jù)的類(lèi)型,如果是AOT元數(shù)據(jù),則保持之前的調(diào)用,如果來(lái)自動(dòng)態(tài)加載,則跳轉(zhuǎn)到huatuo的元數(shù)據(jù)管理模塊,返回一個(gè)恰當(dāng)?shù)闹?。但這兒又遇到一個(gè)問(wèn)題,其次globalmetadata為了優(yōu)化性能,所有dll中的元數(shù)據(jù)在統(tǒng)一的id命名空間下。很多元數(shù)據(jù)查詢(xún)操作僅僅使用一個(gè)id參數(shù),如何根據(jù)id區(qū)別出到底是AOT還是interpreter的元數(shù)據(jù)?
我們發(fā)現(xiàn)實(shí)際項(xiàng)目生成的globalmetadata.dat中這些元數(shù)據(jù)id的值都較小,最大也不過(guò)幾十萬(wàn)級(jí)別。思考后用一個(gè)技巧:我們將id分成兩部分: 高位為image id,低位為實(shí)際上的id,將image id=0保留給AOT元數(shù)據(jù)使用。我們?yōu)槊總€(gè)動(dòng)態(tài)加載的dll分配一個(gè)image id,這個(gè)image中解析出的所有元數(shù)據(jù)id的高位為相應(yīng)的image id。
我們通過(guò)這個(gè)技巧,hook了所有底層訪問(wèn)元數(shù)據(jù)的方法。大約修改了幾十處,基本都是如下這樣的代碼,盡量不修改原始邏輯,很容易保證正確性。



總結(jié)
我們通過(guò)少量的對(duì)實(shí)際il2cpp代碼的觀察,以及對(duì)CLR運(yùn)行時(shí)原理的了解,再配合思維實(shí)驗(yàn),可以99.9%以上確定,既然il2cpp生成的代碼都能在運(yùn)行時(shí)正確運(yùn)行,那huatuo解釋模式下執(zhí)行的代碼,也能正確運(yùn)行。
我們?cè)谕瓿伤季S實(shí)驗(yàn)的那一刻,難掩內(nèi)心激動(dòng)的心情。作為一名物理專(zhuān)業(yè)的IT人,腦海里第一時(shí)間浮現(xiàn)出愛(ài)因斯坦在思考廣義相對(duì)論時(shí)的,使用電梯思維實(shí)驗(yàn)得出引力使時(shí)空彎曲這一驚人結(jié)論。我們不敢比肩這種偉大的科學(xué)家,但我們確實(shí)在使用類(lèi)似的思維技巧??梢哉f(shuō),huatuo不是簡(jiǎn)單的經(jīng)驗(yàn)總結(jié),是深刻洞察力與分析能力孕育的結(jié)果。