下面这段代码忽略了错误处理机制,介绍了如何在 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中导出函数。所以这个问题只能通过特定编译器的非标准扩展来解决。也就是说,找到这个非标准扩展是解决问题最关键的一步。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。