Wasm 執行環境(Wasm runtime)
一個 .wasm 檔只是一堆位元組;總得有東西真正去執行它。Wasm 執行環境就是那個東西:它是一個引擎,負責載入 Wasm 模組、檢查格式是否正確、把它的位元組碼轉成你所在 CPU 的真正機器碼、給它一塊受沙箱保護的記憶體,並讓它執行。瀏覽器在其 JavaScript 引擎裡內建了一個(Chrome 用 V8,Firefox 用 SpiderMonkey);在瀏覽器之外,最有名的獨立執行環境是 Wasmtime 與 Wasmer。
具體而言,執行環境依序做好幾件事。首先它驗證模組——這是一個真實的處理階段,會證明每條指令的堆疊型別都對得上、流程控制是結構化的,因此格式錯誤或惡意的模組會在執行前就被拒絕。接著它編譯:許多執行環境使用預先(ahead-of-time)或即時(just-in-time)編譯來產生原生程式碼(所以跑得快),有些則使用簡單的直譯器(較慢,但啟動快且體積小)。它設定模組的線性記憶體與表格,接上模組要求的匯入(這是程式碼觸及外部世界的唯一途徑),並執行沙箱:客體無法讀寫自己線性記憶體以外的地方、無法發出你未授予的系統呼叫,只能受限於你交給它的那些主機函式。
執行環境之所以重要,是因為安全性與速度兩者都住在這裡,而不在 .wasm 檔裡。同一個模組在不同引擎下表現不同,取決於引擎的編譯器品質、它支援的功能(執行緒、SIMD、組件模型、WASI 版本),以及主機接上能力時有多嚴格。要老實說:不同執行環境支援不同的功能集合、推進速度也不一樣,所以實務上「能在 Wasm 上跑」其實是指「能在支援這個模組所需功能的執行環境上跑」——可攜性是真的,但並非無條件。
$ wasmtime run --dir=. app.wasm # 載入、驗證、JIT 編譯、沙箱化、執行 # 客體只能讀取 '.' 底下的檔案,因為主機正好只授予了那一個目錄
Wasmtime 執行一個模組。除非主機明確授予,否則沙箱之外的東西都碰不到(此處是一個目錄)。
沙箱是由執行環境強制執行的,並非單靠 .wasm 格式——有臭蟲或太寬鬆的執行環境,或一個授予了廣泛能力的主機,都會削弱它。「Wasm 很安全」是「一個正確的執行環境會把客體侷限在它的線性記憶體與你選擇暴露的匯入之內」的簡略說法。