WebAssembly的一知半解
隨著互聯(lián)網(wǎng)的發(fā)展,網(wǎng)絡(luò)應用變得越來越復雜,如3d可視化、音視頻軟件以及大型網(wǎng)絡(luò)游戲。因此,代碼的效率和安全性變得更加重要。WebAssembly 是一個可移植的底層字節(jié)碼,它通過提供緊湊的表示、高效的驗證和編譯以及低開銷甚至零開銷的安全執(zhí)行來滿足這些需求。它不僅是一個特定的編程模型,而且是獨立于語言和平臺的一個現(xiàn)代硬件抽象。
1. 緣起
由于歷史的偶然性,JavaScript 是 Web 上唯一天生支持的編程語言。由于其在實現(xiàn)中的普遍性、快速的性能改進,或許由于純粹的需要,它已經(jīng)成為許多其他語言的編譯目標。然而,JavaScript 有不一致的性能和各種其他的問題。
WebAssembly (簡稱“ Wasm”)用底層代碼解決了 Web上的安全、快速和可移植問題。從 ActiveX 到 Native Client 再到 asm.js,都沒有達到這種代碼格式應該具有的屬性:
- 安全、快速、可移植性的語義:可以安全而快速地執(zhí)行,并且與語言、硬件和平臺無關(guān),具有確定性結(jié)果并易于推理,同時與 Web 平臺能夠簡單地互操作
- 安全有效的表達形式:機構(gòu)緊湊,很容易解碼,驗證和編譯,對開發(fā)者來說很容易生成,支持流式和并行處理。
為什么這些目標很重要呢? 為什么又很難呢?
安全性
代碼的安全性在 Web 上是至關(guān)重要的,因為代碼往往來自不可信的源。代碼的保護在傳統(tǒng)上是通過提供托管語言運行時來實現(xiàn)的,如瀏覽器的 JavaScript 虛擬機或語言插件。托管增強了內(nèi)存的安全性,防止程序損害用戶數(shù)據(jù)或系統(tǒng)狀態(tài)。然而,托管的運行時在傳統(tǒng)上并沒有為底層代碼提供更多的內(nèi)容,例如c/c++的程序。
快速
類似于c/c++的靜態(tài)語言,編譯器會對底層代碼提前進行優(yōu)化。本機代碼,無論是手寫的還是編譯器優(yōu)化后的輸出,都可以充分利用機器的性能。運行時托管和沙箱技術(shù)通常會給這些代碼帶來巨大的性能開銷。
統(tǒng)一性
除了不可避免的硬件限制之外,存在著大量的優(yōu)秀編程范例,這些范例都不應該受到代碼格式的限制。然而,大多數(shù)的運行時托管被設(shè)計成能很好地支持特定的語言或者編程范式,同時又給其他語言帶來了巨大的成本。
便于移植
Web 不僅跨越了許多設(shè)備,還跨越了不同的機器體系結(jié)構(gòu)、操作系統(tǒng)和瀏覽器。針對 Web 的代碼必須獨立于硬件和平臺,以允許應用程序以相同的確定性行為跨所有的瀏覽器和硬件類型運行。以前的低級別代碼解決方案都綁定在單一體系結(jié)構(gòu)上,或者存在著其他可移植性問題。
緊湊的機構(gòu)
通過網(wǎng)絡(luò)傳輸?shù)拇a應該很小,以減少負載、節(jié)省帶寬并提高整體的響應能力。Web 上的代碼通常以 JavaScript 源代碼的形式傳輸,即使對其進行了壓縮,也遠不如二進制格式緊湊。二進制代碼格式也并不總是針對大小進行優(yōu)化。
WebAssembly 是第一個針對 Web 的低級別代碼解決方案,它實現(xiàn)了上述所有設(shè)計目標,是所有主要瀏覽器供應商和在線社區(qū)為構(gòu)建高性能應用程序的通用解決方案進行協(xié)作的一個結(jié)果。
雖然 Web 是 WebAssembly 的緣起之地,但它的設(shè)計避免了對 Web 的任何依賴。它是一個開放標準,能夠在嵌入到各種各樣的環(huán)境中,也許是第一個從開始就用形式語義學來設(shè)計的工業(yè)級語言。
2. 語言概述
盡管 WebAssembly 是一種二進制代碼格式,本質(zhì)上仍然是一種具有語法和結(jié)構(gòu)的編程語言,這使得它更容易解釋和理解。
2.1. 基礎(chǔ)
以下是WebAssembly 中的一些基本概念。
模塊
WebAssembly 二進制文件采用了模塊的形式。它包含函數(shù)、全局變量、表和內(nèi)存的定義,這些定義可以通過導入、導出用于復用。
雖然模塊對應于程序的靜態(tài)表示,但模塊的動態(tài)表示是一個實例,具有完整的可變狀態(tài)。實例化一個模塊需要為所有導入提供定義,這些導入可能是從以前創(chuàng)建的實例導出的,通過調(diào)用導出函數(shù)來啟動計算。模塊提供了封裝和沙盒,客戶端只能訪問模塊的導出,其他內(nèi)部構(gòu)件受到保護而不被篡改; 同時,模塊只能通過客戶端提供的導入與其環(huán)境交互,因此客戶端對給定模塊的功能擁有完全的控制權(quán)。這兩個方面都是代碼安全的重要組成部分。
函數(shù)
模塊中的代碼被組織成單獨的函數(shù),獲取參數(shù)并返回由其函數(shù)類型定義的結(jié)果。函數(shù)可以相互調(diào)用,包括遞歸調(diào)用,運行中的 WebAssembly 程序不能直接訪問執(zhí)行調(diào)用的堆棧。
指令
WebAssembly 在概念上是基于堆棧的機器,函數(shù)的代碼由操作堆棧上值的指令序列組成。然而,類型系統(tǒng)的布局可以在代碼中的任何點靜態(tài)確定,因此可以直接編譯指令之間的數(shù)據(jù)流,而無需實現(xiàn)操作堆棧。堆棧的組織僅僅是實現(xiàn)緊湊表達的一種方式,它比基于寄存器的機器尺寸要小。
trap異常
某些指令可能會產(chǎn)生一個異常的trap,這會立即中止當前的計算。異常的trap可以不由 WebAssembly 代碼處理,一個嵌入器通常會提供處理這種情況的方法,例如,將它們具體化為 JavaScript 異常。
數(shù)值類型
WebAssembly 只有四個基本值類型可以計算。這些是整數(shù)和浮點數(shù),每個都有32位或64位之分,可以在普通硬件中使用。大多數(shù) WebAssembly 指令對這些數(shù)值類型提供了簡單的操作符,例如一元和二元運算符、比較和轉(zhuǎn)換。與硬件一樣,WebAssembly 不區(qū)分有/無符號整數(shù)類型。
變量
函數(shù)可以聲明可變局部變量,這實際上提供了一組零初始化的虛擬寄存器。模塊還可以聲明類型化的全局變量,這些變量可以是可變的,也可以是不可變的,并且需要顯式的初始值設(shè)定項。導入全局變量允許一種有限的可配置性,例如鏈接。像 WebAssembly 中的所有實體一樣,變量通過整數(shù)索引引用。
2.2 內(nèi)存
WebAssembly 的主要存儲器是大量的字節(jié)數(shù)組、線性存儲器或簡單存儲器。通過加載和存儲指令訪問內(nèi)存,其中地址只是無符號整數(shù)。
創(chuàng)建與擴展
每個模塊最多只能定義一塊內(nèi)存區(qū)域,可以通過導入/導出與其他實例共享。創(chuàng)建的內(nèi)存區(qū)域具有初始大小,但可以動態(tài)增長。增長單元是一個頁,它被定義為64kb,這將允許在硬件上重用虛擬內(nèi)存硬件進行邊界檢查。頁大小是固定的,而不是系統(tǒng)特定的,以防止可移植性的危險。
字節(jié)次序
由于大多數(shù)現(xiàn)代硬件都集中在 little endian 上,或者至少可以同樣很好地處理它,WebAssembly 的內(nèi)存區(qū)域同樣是little endian的字節(jié)順序。因此,內(nèi)存訪問的語義在所有引擎和平臺之間是完全確定和可移植的。
內(nèi)存安全
所有內(nèi)存訪問都是根據(jù)內(nèi)存大小動態(tài)檢查的,越界訪問將導致異常trap。線性內(nèi)存與代碼空間、執(zhí)行堆棧和引擎的數(shù)據(jù)結(jié)構(gòu)是分離的,因此,編譯后的程序不能破壞它們的執(zhí)行環(huán)境,不能跳轉(zhuǎn)到任意位置,或執(zhí)行其他未定義行為。要以高性能的方式與不受信任的 JavaScript 和各種 Web API進行交互,就必須實現(xiàn)快速的進程內(nèi)隔離。同時,WebAssembly 引擎安全地嵌入到其他托管語言運行時中。
2.3. 控制流
WebAssembly 表示的控制流與大多數(shù)基于堆棧的機器不同。它不提供任意跳轉(zhuǎn),而是提供更類似于編程語言的結(jié)構(gòu)化控制流。通過這種構(gòu)造確保了控制流不會形成不可約減的循環(huán),不會包含堆棧高度不對齊的塊分支,或者不會分支到多字節(jié)指令的中間。這些屬性允許在一次傳遞中驗證 WebAssembly 代碼,在一次傳遞中編譯。
控制結(jié)構(gòu)
塊、循環(huán)和 if 結(jié)構(gòu)必須由結(jié)束操作碼終止,并且必須正確嵌套才能被認為是格式良好的結(jié)構(gòu)。這些結(jié)構(gòu)中的內(nèi)部指令序列形成一個塊。注意,循環(huán)不會自動迭代,但允許使用顯式分支手動構(gòu)造循環(huán)。每個控件結(jié)構(gòu)都帶有一個函數(shù)的類型注釋,描述其對堆棧的影響、類型化的Pop/Push值。
分支
分支可以是無條件的、條件的或索引的。它們具有“標簽”的即時性,不表示指令流中的位置,而是通過相對嵌套深度引用外部控制結(jié)構(gòu)。因此,標簽有效地限定了作用域: 分支只能引用它們嵌套在其中的構(gòu)造。如果一個分支從該構(gòu)造的塊中斷開,切效果取決于目標的構(gòu)造: 對于一個塊,或者如果它是一個向前跳轉(zhuǎn)到它的結(jié)束(如 break 語句) ; 對于一個循環(huán),它是一個向后跳轉(zhuǎn)到它的開始(如 continue 語句)。分支通過隱式彈出所有未使用的操作符來解除對操作符堆棧的糾纏,類似于函數(shù)調(diào)用的返回。
表達式
結(jié)構(gòu)化控制流似乎是一個嚴格的限制,但大多數(shù)高級控制結(jié)構(gòu)都可以通過合適的塊嵌套輕松表達。例如,c 樣式 switch 語句,對于無序條件之間的失敗,需要更多的技巧。各種形式的循環(huán)同樣可以用分支組合來表示。
將非結(jié)構(gòu)化的控制流轉(zhuǎn)換為結(jié)構(gòu)化形式是開發(fā)者的責任。這是 Web 編譯的既定方法,其中 JavaScript 也被限制為結(jié)構(gòu)化控件。這種限制的好處是,引擎中的許多算法更簡單、更快速。
2.4. 函數(shù)調(diào)用和表
函數(shù)體是一個塊。執(zhí)行可以通過以函數(shù)在堆棧上的結(jié)果值到達塊的末尾來完成,也可以通過退出函數(shù)塊的分支來完成,返回指令只是后者的簡寫。
調(diào)用
函數(shù)可以使用調(diào)用指令直接調(diào)用,指令可以用函數(shù)指針來模擬,該指令將運行時索引引用到模塊定義的函數(shù)表中。表中的函數(shù)不需要具有相同的類型。相反,在不匹配的情況下,將根據(jù)提供的指令和trap的預期類型動態(tài)檢查函數(shù)的類型,保護了執(zhí)行環(huán)境的完整性。表的異構(gòu)性允許函數(shù)指針更準確地表示,并簡化了動態(tài)鏈接。為了進一步幫助動態(tài)鏈接的場景,可以通過外部API改變導出的表。
外部調(diào)用
函數(shù)可以導入到模塊中,直接和間接調(diào)用都可以調(diào)用導入的函數(shù),并且通過導出/導入,多個模塊實例可以通信。此外,導入機制作為一個安全的外部函數(shù)接口( , WebAssembly 程序通過它可以與其嵌入環(huán)境通信。例如,在 Web 上導入的函數(shù)可能是由 JavaScript 定義的宿主函數(shù)??缭秸Z言邊界的值將根據(jù) JavaScript 規(guī)則自動轉(zhuǎn)換。
2.5. 確定性結(jié)果
WebAssembly 試圖在不犧牲性能的情況下為低級代碼提供一個可移植的目標。硬件行為不同的地方通常包括整數(shù)除以零,溢出或浮點轉(zhuǎn)換以及對齊等。WebAssembly 的設(shè)計以最小的執(zhí)行開銷為所有這些硬件提供確定性語義。
然而,依賴于實現(xiàn)的行為仍然有三個來源可以被視為非確定性的:
NaN有效載荷:WebAssembly 遵循 IEEE 754標準進行浮點運算。但是,IEEE 并沒有在所有情況下為 NaN 值指定精確的位模式,cpu 之間存在顯著差異,而在每個數(shù)值操作之后進行規(guī)范化的開銷太大?;?JavaScript 引擎的經(jīng)驗,可以提供足夠的保證來支持像 NaN-tagging 這樣的技術(shù)。
資源耗盡:資源總是有限的,而且在設(shè)備之間差異很大。特別是,引擎可能會出現(xiàn)內(nèi)存不足,調(diào)用指令也可能由于堆棧溢出而產(chǎn)生異常trap,但是,WebAssembly 本身無法觀察到這些情況,只是中止了計算。
宿主函數(shù):WebAssembly 程序可以調(diào)用本身不確定或者更改 WebAssembly 狀態(tài)的宿主函數(shù)。當然,調(diào)用宿主函數(shù)的結(jié)果也超出了 WebAssembly 的語義范圍。
2.6. 二進制格式
WebAssembly 作為抽象語法的二進制編碼進行傳輸,這種編碼被設(shè)計為最小化尺寸大型和解碼時間。二進制文件表示一個單獨的模塊,并根據(jù)其中聲明的不同類型的實體被劃分為若干部分。函數(shù)體的代碼被推遲到所有聲明之后的一個單獨的部分,以便在函數(shù)體開始通過網(wǎng)絡(luò)到達時啟用流式編譯。引擎還可以并行編譯函數(shù)體。。該格式還允許用戶自定義的部分,這些部分可能會被引擎忽略。
3. 語義的感知
WebAssembly 語義由兩部分組成: 定義驗證的靜態(tài)語義和定義執(zhí)行的動態(tài)語義。在這兩種情況下,對于聲明性規(guī)范來說都是方便而有效的工具。最后,形式化能夠輕松地證明WebAssembly 規(guī)范,機器驗證結(jié)果的正確性,以及構(gòu)建一個可證明的正確解釋器。
執(zhí)行
執(zhí)行是根據(jù)一個標準的小步驟縮減關(guān)系來定義的,其中每個計算步驟都被描述為一系列指令的重寫規(guī)則。堆棧只是由一個指令序列中所有前導標識的指令組成,當指令序列被減少為與結(jié)果值堆棧相對應的常量時,執(zhí)行終止
為了處理控制構(gòu)造,使用少量輔助管理的指令擴展語法,這些輔助指令只在還原過程中臨時出現(xiàn),框架本質(zhì)上是函數(shù)調(diào)用的調(diào)用框架。
存儲區(qū)為程序的全局狀態(tài)建模,并記錄已分配的函數(shù)、全局、表和內(nèi)存實例的列表。存儲組件之一的索引稱為地址,模塊實例將指令中出現(xiàn)的靜態(tài)索引映射到存儲中各自的動態(tài)地址。為此,除了函數(shù)本地變量的狀態(tài)之外,每個幀還攜帶一個到它所在的模塊實例的鏈接,實現(xiàn)可以通過將生成的機器代碼專門化為模塊實例來消除這些閉包。
存儲、幀和指令序列的三元組一起構(gòu)成一個配置,表示 WebAssembly 抽象機器在給定時間點的完整狀態(tài)。一般的約簡規(guī)則是重寫配置,而不僅僅是指令序列。
驗證
在 Web 上,代碼是從不可信的來源獲取的,必須經(jīng)過驗證。Webasembly 的驗證規(guī)則簡潔地定義為類型系統(tǒng)。這種類型系統(tǒng),在設(shè)計成在一個單一的線性有效檢查。
指令的類型是指定其所需輸入堆棧和提供的輸出堆棧的函數(shù)類型。每條規(guī)則由一個結(jié)論和一個可能是空的前提列表組成。它可以被解讀為: 如果所有前提都成立,結(jié)論就成立。每個指令都有一個規(guī)則,定義何時類型良好。當且僅當規(guī)則能歸納地推導出它是類型良好的程序時,該程序才有效。
例如,常量和數(shù)值運算符的規(guī)則是公理,甚至不需要一個前提。控制構(gòu)造的規(guī)則要求它們的類型匹配顯式注釋,并且在檢查內(nèi)部塊時使用本地標簽擴展上下文。當鍵入分支指令時,會在上下文中查找標簽類型,這需要堆棧上的適當操作符來匹配連接點上的堆棧。
可靠性
WebAssembly 系統(tǒng)類型具有標準的可靠性屬性。約簡規(guī)則實際上涵蓋了有效程序可能出現(xiàn)的所有執(zhí)行狀態(tài)。這意味著沒有類型安全的違規(guī),如無效調(diào)用或非法訪問局部變量,它保證了內(nèi)存安全,并確保了代碼地址或調(diào)用堆棧的不可訪問性。它還意味著操作符堆棧的使用是結(jié)構(gòu)化的,其布局在所有程序點上都是靜態(tài)確定的,這對于在基于寄存器的機器上的高效編譯至關(guān)重要。此外,它還建立了內(nèi)存和狀態(tài)封裝,即模塊和函數(shù)邊界上的抽象屬性,這些屬性不會泄漏信息。
機械化證明
WebAssembly 中的引用解釋器包括了將形式規(guī)則直接轉(zhuǎn)譯為可執(zhí)行代碼。雖然這兩個任務(wù)基本上都很簡單,但它們總是容易出現(xiàn)測試沒有發(fā)現(xiàn)的細微錯誤。機器化語義驗證不僅在于驗證 WebAssembly 本身,還在于為其他形式化方法的應用程序提供了基礎(chǔ),例如驗證針對 WebAssembly 的編譯器或證明程序的性質(zhì)、程序等價性和安全性。
4. 標準化
WebAssembly 的形式化語義能夠促進標準化的形成。
核心語言
WebAssembly語言的定義遵循形式化,并指定抽象語法、類型規(guī)則、約簡規(guī)則和抽象存儲。二進制格式和文本格式作為屬性文法給出,準確地描述了它們產(chǎn)生的抽象語法。對于工業(yè)級語言來說,這種嚴謹和精確程度可能是前所未有的。
形式化:一個廣泛使用的標準不能假定所有讀者都熟悉語義的形式化符號,將正式規(guī)則集中放在標準文檔中,即使不直接閱讀這些規(guī)則的開發(fā)者也會從中受益。
引用解釋器:隨著瀏覽器對 WebAssembly 的產(chǎn)品化實現(xiàn),引用解釋器近似于“可執(zhí)行的規(guī)范”被用來開發(fā)測試套件,來測試具體的實現(xiàn)和形式規(guī)范,以及構(gòu)建新特性的原型。
顯然,形式化的語義并非在所有情況下都是直截了當?shù)?。WebAssembly 的實現(xiàn)包括了多階段提案流程。在提案的不同階段,維護者必須提供: (1)非正式的描述,(2)非正式規(guī)范,(3)原型實現(xiàn),(4)全面的測試套件,(5)形式規(guī)范,(6)引用解釋器中的實現(xiàn),(7)獨立生產(chǎn)系統(tǒng)中的實現(xiàn)。
嵌入執(zhí)行環(huán)境
WebAssembly 類似于虛擬指令集的程序架構(gòu),因為它不定義程序如何加載到執(zhí)行引擎,也不定義程序如何執(zhí)行 i/o。這種設(shè)計分離可以將 WebAssembly 實現(xiàn)嵌入到執(zhí)行環(huán)境中。嵌入機制定義了模塊如何加載、導入和導出如何解析、trap如何處理,并提供用于訪問環(huán)境的外部函數(shù)。
為了加強平臺獨立性,WebAssembly標準被分層為單獨的文檔: 核心規(guī)范只定義了虛擬指令集架構(gòu),單獨的嵌入規(guī)范定義了它與具體主機環(huán)境的交互。
在瀏覽器中,可以通過 JavaScript API 加載、編譯和調(diào)用 WebAssembly 模塊。粗略的方法是(1)從給定源獲取二進制模塊,例如,作為網(wǎng)絡(luò)資源,(2)實例化它,提供必要的導入,(3)調(diào)用所需的導出函數(shù)。由于編譯和實例化可能比較慢,因此它們作為異步方法提供,其結(jié)果包裝在承諾中。JavaScript API 還允許在外部創(chuàng)建和初始化內(nèi)存或表,或者作為導出訪問它們。
作為一種底層語言,WebAssembly 不提供任何內(nèi)置的對象模型,這種設(shè)計為開發(fā)者提供了最大的靈活性,并且不像以前的虛擬機那樣,不鎖定任何特定的編程范式/對象模型。生產(chǎn)者可以在 WebAssembly 之上定義通用的 ABI,這樣模塊就可以在不同的應用程序中進行互操作了。這個關(guān)注點的分離對于將 WebAssembly 作為一種通用的代碼格式至關(guān)重要。
5. 實現(xiàn)中的一些考量
WebAssembly 的主要設(shè)計目標是在不犧牲安全性和可移植性的情況下實現(xiàn)高性能。
V8(Chrome)、 SpiderMonkey (Firefox)和 JavaScriptCore (WebKit)重用其JS編譯器來提前編譯 WebAssembly 模塊。這樣可以獲得可預測的高性能,啟動速度更快,并且可能降低內(nèi)存消耗。在這些實現(xiàn)中,使用了相同的使用抽象控制和操作符堆棧的算法策略。在解碼過程中,對傳入字節(jié)碼進行一次驗證,不需要額外的中間表示。
SpiderMonkey 引擎包括了兩個 WebAssembly 編譯層。第一種是快速的基線 JIT,JIT 不創(chuàng)建中間表示(Intermediate Representation,IR) ,但是會跟蹤寄存器狀態(tài),并嘗試在前進傳遞中執(zhí)行簡單的寄存器分配?;€ JIT 僅用于快速啟動,而優(yōu)化 JIT 在后臺并行編譯模塊。V8在原型配置中包含類似的基線 JIT。優(yōu)化 JIT 可以獲得 JavaScript 的頂級執(zhí)行,并將其重用于 WebAssembly。V8和 SpiderMonkey 都使用基于SSA的中間表示。WebAssembly 的結(jié)構(gòu)化控制流對此有很大的幫助,使得解碼算法更簡單、更有效,并且避免了通常 JIT 的局限性。
通過設(shè)計,可以通過動態(tài)邊界檢查保證 WebAssembly 中的所有內(nèi)存訪問是安全的,這相當于根據(jù)內(nèi)存的當前大小檢查地址。引擎將從進程中的某個基址開始,在一個很大的連續(xù)范圍內(nèi)分配內(nèi)存。為了快速訪問,基址可以存儲在一個專用的機器寄存器中,一個更積極的策略是將每個實例的機器代碼專門化到一個特定的基地址,將它作為一個常量直接嵌入到代碼中。
在64位平臺上,引擎可以利用虛擬內(nèi)存來完全消除內(nèi)存訪問的邊界檢查。引擎只是保留8GB的虛擬地址空間,除了啟動附近的有效內(nèi)存部分,所有頁標記為不可訪問。由于 WebAssembly 內(nèi)存地址和偏移量是32位整數(shù)加上一個靜態(tài)常數(shù),任何訪問都不能超過8GB的地址空間。因此,JIT 可以簡單地發(fā)出普通的加載/存儲指令,并依靠硬件保護機制來捕獲越界訪問。
通過超前編譯, WebAssembly 模塊的編譯可以并行化,將各個函數(shù)分配到不同的線程,這樣做明顯地提高了性能。例如,v8和 SpiderMonkey 使用8個編譯線程,在編譯速度上都提高了5-6倍。此外,WebAssembly 二進制格式的設(shè)計支持流媒體,在加載完整的二進制文件之前,引擎可以開始編譯單個函數(shù)。當與并行化結(jié)合時,這最小化了冷啟動時間。
代碼緩存除了冷啟動時間之外,熱啟動時間也很重要,因為用戶可能會反復訪問相同的 Web 頁面。IndexedDB 數(shù)據(jù)庫的 JavaScript API 允許 JavaScript 操作和編譯 WebAssembly 模塊,并將其編譯后的表示作為一個不透明的 blob 存儲。這允許 JavaScript 應用程序在下載和編譯它之前,首先向 IndexedDB 查詢 WebAssembly 模塊的緩存版本。在 v8和 SpiderMonkey 中,這種機制可以使啟動時間提高數(shù)秒的數(shù)量級。字節(jié)碼驗證的速度和簡單性是獲得良好性能和高保證的關(guān)鍵,WebAssembly 不像 JVM 字節(jié)碼驗證那樣有150頁說明,而只是一頁形式化符號。
6. 小結(jié)
WebAssembly 側(cè)重于支持底層代碼,特別是從 c/c + + 編譯而來的代碼。通過包含相關(guān)的原語(如尾調(diào)用、堆棧切換或協(xié)同程序) ,WebAssembly 可能會發(fā)展成為高級語言,但是,一個非常重要的目標是提供對內(nèi)置在所有 Web 瀏覽器中的垃圾收集器的訪問,從而消除在編譯 Web 與 JavaScript 時候的相關(guān)缺陷。除了 Web 之外,WebAssembly 還可能在其他領(lǐng)域找到廣泛的用途,例如內(nèi)容傳輸網(wǎng)絡(luò)中的沙盒,智能合約或區(qū)塊鏈上的去中心化計算,作為移動設(shè)備的代碼格式,甚至僅僅作為提供便攜式運行時的單獨引擎。
【參考文獻與關(guān)聯(lián)閱讀】
https://webassembly.org/
https://webassembly.github.io/spec/.
http://asmjs.org
https://cacm.acm.org/magazines/2018/12/23288-bringing-the-web-up-to-speed-with-webassembly/fulltext