博客 / 詳情

返回

嵌入 WebAssembly 運行時和實例化 WebAssembly 模塊的幾大要素

下面這段代碼忽略了錯誤處理機制,介紹瞭如何在 Go 語言開發的宿主程序中嵌入 WebAssembly.

func createWasmVM(code []byte) {
    engine := wasmtime.NewEngine()
    module, _ := wasmtime.NewModule(engine, code)
    store := wasmtime.NewStore(engine)
    linker := wasmtime.NewLinker(engine)
    inst, _ := linker.Instantiate(store, module)
    _ = inst
}

這段代碼涉及到幾個重要的 WebAssembly 的概念,簡單介紹如下:

  • 引擎(Engine):用於編譯和管理 wasm 模塊的全局上下文。
  • 模塊(Module):已編譯的 WebAssembly 模塊。 該結構表示實例化後準備執行的內存中 JIT 代碼。
  • 存儲(Store):所有 WebAssembly 對象和主機值都將“連接”到存儲。
  • 實例(Instance):一個實例化的 WebAssembly 模塊,您可以從中實際獲取一個函數,例如調用。實例化時,調用模塊的啓動函數。
  • 鏈接器(僅限 Wasmtime):將 wasm 模塊/實例鏈接在一起的輔助結構。

上面的代碼雖然創建了一個 WebAssembly 模塊的實例,但是根據 WebAssembly 規範,start 函數會被執行。 但由於安全限制,無法輸出執行結果,所以即使執行了也沒效果。 因此,我們需要實現宿主程序與 WebAssembly 程序的互操作,為WebAssembly 程序提供輸入/輸出接口。

假設我們的 WebAssembly 程序有一個名為 sum 的函數,它接收兩個整數變量作為參數並返回它們的和,宿主程序可以使用下面的代碼來調用這個函數:

fn := inst.GetExport(store, "sum").Func()
r, _ := fn.Call(store, 1, 2)
fmt.Println(r.(int32))

雖然具體的調用方式與宿主程序的編程語言和所使用的WebAssembly運行時不同,但是運行時的文檔一般都有相關的説明,按照文檔來做就好了。

這裏的難點在於如何從 WebAssembly 程序中導出 sum 函數,以便宿主程序可以找到並調用它。 前面説了,只要有編譯器,任何語言都可以編譯成WebAssembly,但是大部分語言在設計時都沒有考慮WebAssembly的需求,也沒有辦法在WebAssembly中導出函數。所以這個問題只能通過特定編譯器的非標準擴展來解決。也就是説,找到這個非標準擴展是解決問題最關鍵的一步。

user avatar ticktank 頭像
1 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.