Upgrade to WasmEdge-Go v0.10.0
Due to the WasmEdge-Go API breaking changes, this document shows the guideline of programming with WasmEdge-Go API to upgrade from the v0.9.2 to the v0.10.0 version.
Due to the v0.9.1 is retracted, we use the version v0.9.2 here.
Concepts
Merged the
ImportObjectinto theModule.The
ImportObjectstruct which is for the host functions is merged intoModule. Developers can use the related APIs to construct host modules.wasmedge.NewImportObject()is changed towasmedge.NewModule().(*wasmedge.ImportObject).Release()is changed to(*wasmedge.Module).Release().(*wasmedge.ImportObject).AddFunction()is changed to(*wasmedge.Module).AddFunction().(*wasmedge.ImportObject).AddTable()is changed to(*wasmedge.Module).AddTable().(*wasmedge.ImportObject).AddMemory()is changed to(*wasmedge.Module).AddMemory().(*wasmedge.ImportObject).AddGlobal()is changed to(*wasmedge.Module).AddGlobal().(*wasmedge.ImportObject).NewWasiImportObject()is changed to(*wasmedge.Module).NewWasiModule().(*wasmedge.ImportObject).NewWasmEdgeProcessImportObject()is changed to(*wasmedge.Module).NewWasmEdgeProcessModule().(*wasmedge.ImportObject).InitWASI()is changed to(*wasmedge.Module).InitWASI().(*wasmedge.ImportObject).InitWasmEdgeProcess()is changed to(*wasmedge.Module).InitWasmEdgeProcess().(*wasmedge.ImportObject).WasiGetExitCode()is changed to(*wasmedge.Module).WasiGetExitCode.(*wasmedge.VM).RegisterImport()is changed to(*wasmedge.VM).RegisterModule().(*wasmedge.VM).GetImportObject()is changed to(*wasmedge.VM).GetImportModule().
For the new host function examples, please refer to the example below.
Used the pointer to
Functioninstead of the index in theFuncRefvalue type.For the better performance and security, the
FuncRefrelated APIs used the*wasmedge.Functionfor the parameters and returns.wasmedge.NewFuncRef()is changed to use the*Functionas it's argument.- Added
(wasmedge.FuncRef).GetRef()to retrieve the*Function.
Supported multiple anonymous WASM module instantiation.
In the version before
v0.9.2, WasmEdge only supports 1 anonymous WASM module to be instantiated at one time. If developers instantiate a new WASM module, the old one will be replaced. After thev0.10.0version, developers can instantiate multiple anonymous WASM module byExecutorand get theModuleinstance. But for the source code using theVMAPIs, the behavior is not changed. For the new examples of instantiating multiple anonymous WASM modules, please refer to the example below.Behavior changed of
Store.The
Function,Table,Memory, andGlobalinstances retrievement from theStoreis moved to theModuleinstance. TheStoreonly manage the module linking when instantiation and the named module searching after thev0.10.0version.(*wasmedge.Store).ListFunction()and(*wasmedge.Store).ListFunctionRegistered()is replaced by(*wasmedge.Module).ListFunction().(*wasmedge.Store).ListTable()and(*wasmedge.Store).ListTableRegistered()is replaced by(*wasmedge.Module).ListTable().(*wasmedge.Store).ListMemory()and(*wasmedge.Store).ListMemoryRegistered()is replaced by(*wasmedge.Module).ListMemory().(*wasmedge.Store).ListGlobal()and(*wasmedge.Store).ListGlobalRegistered()is replaced by(*wasmedge.Module).ListGlobal().(*wasmedge.Store).FindFunction()and(*wasmedge.Store).FindFunctionRegistered()is replaced by(*wasmedge.Module).FindFunction().(*wasmedge.Store).FindTable()and(*wasmedge.Store).FindTableRegistered()is replaced by(*wasmedge.Module).FindTable().(*wasmedge.Store).FindMemory()and(*wasmedge.Store).FindMemoryRegistered()is replaced by(*wasmedge.Module).FindMemory().(*wasmedge.Store).FindGlobal()and(*wasmedge.Store).FindGlobalRegistered()is replaced by(*wasmedge.Module).FindGlobal().
For the new examples of retrieving instances, please refer to the example below.
The
Module-based resource management.Except the creation of
Moduleinstance for the host functions, theExecutorwill output aModuleinstance after instantiation. No matter the anonymous or named modules, developers have the responsibility to destroy them by(*wasmedge.Module).Release()API. TheStorewill link to the namedModuleinstance after registering. After the destroyment of aModuleinstance, theStorewill unlink to that automatically; after the destroyment of theStore, the allModuleinstances theStorelinked to will unlink to thatStoreautomatically.
WasmEdge-Go VM changes
The VM APIs are basically not changed, except the ImportObject related APIs.
The following is the example of WASI initialization in WasmEdge-Go v0.9.2:
conf := wasmedge.NewConfigure(wasmedge.WASI)
vm := wasmedge.NewVMWithConfig(conf)
// The following API can retrieve the pre-registration import objects from the VM object.
// This API will return `nil` if the corresponding pre-registration is not set into the configuration.
wasiobj := vm.GetImportObject(wasmedge.WASI)
// Initialize the WASI.
wasiobj.InitWasi(
os.Args[1:], // The args
os.Environ(), // The envs
[]string{".:."}, // The mapping preopens
)
// ...
vm.Release()
conf.Release()
Developers can change to use the WasmEdge-Go v0.10.0 as follows, with only replacing the ImportObject into Module:
conf := wasmedge.NewConfigure(wasmedge.WASI)
vm := wasmedge.NewVMWithConfig(conf)
// The following API can retrieve the pre-registration module instances from the VM object.
// This API will return `nil` if the corresponding pre-registration is not set into the configuration.
wasiobj := vm.GetImportModule(wasmedge.WASI)
// Initialize the WASI.
wasiobj.InitWasi(
os.Args[1:], // The args
os.Environ(), // The envs
[]string{".:."}, // The mapping preopens
)
// ...
vm.Release()
conf.Release()
The VM provides a new API for getting the current instantiated anonymous Module instance. For example, if developer want to get the exported Global instance:
// Assume that a WASM module is instantiated in `vm`, and exports the "global_i32".
store := vm.GetStore()
globinst := store.FindGlobal("global_i32")
After the WasmEdge-Go v0.10.0, developers can use the (*wasmedge.VM).GetActiveModule() to get the module instance:
// Assume that a WASM module is instantiated in `vm`, and exports the "global_i32".
mod := vm.GetActiveModule()
// The example of retrieving the global instance.
globinst := mod.FindGlobal("global_i32")
WasmEdge Executor changes
Executor helps to instantiate a WASM module, register a WASM module into Store with module name, register the host modules with host functions, or invoke functions.
WASM module instantiation
In WasmEdge-Go
v0.9.2version, developers can instantiate a WASM module by theExecutorAPI:var ast *wasmedge.AST
// Assume that `ast` is a loaded WASM from file or buffer and has passed the validation.
// Assume that `executor` is a `*wasmedge.Executor`.
// Assume that `store` is a `*wasmedge.Store`.
err := executor.Instantiate(store, ast)
if err != nil {
fmt.Println("Instantiation FAILED:", err.Error())
}Then the WASM module is instantiated into an anonymous module instance and handled by the
Store. If a new WASM module is instantiated by this API, the old instantiated module instance will be cleaned. After the WasmEdge-Gov0.10.0version, the instantiated anonymous module will be outputted and handled by caller, and not only 1 anonymous module instance can be instantiated. Developers have the responsibility to release the outputted module instances.var ast1 *wasmedge.AST
var ast2 *wasmedge.AST
// Assume that `ast1` and `ast2` are loaded WASMs from different files or buffers,
// and have both passed the validation.
// Assume that `executor` is a `*wasmedge.Executor`.
// Assume that `store` is a `*wasmedge.Store`.
mod1, err1 := executor.Instantiate(store, ast1)
if err1 != nil {
fmt.Println("Instantiation FAILED:", err1.Error())
}
mod2, err2 := executor.Instantiate(store, ast2)
if err2 != nil {
fmt.Println("Instantiation FAILED:", err2.Error())
}
mod1.Release()
mod2.Release()WASM module registration with module name
When instantiating and registering a WASM module with module name, developers can use the
(*wasmedge.Executor).RegisterModule()API before WasmEdge-Gov0.9.2.var ast *wasmedge.AST
// Assume that `ast` is a loaded WASM from file or buffer and has passed the validation.
// Assume that `executor` is a `*wasmedge.Executor`.
// Assume that `store` is a `*wasmedge.Store`.
// Register the WASM module into store with the export module name "mod".
err := executor.RegisterModule(store, ast, "mod")
if err != nil {
fmt.Println("WASM registration FAILED:", err.Error())
}The same feature is implemented in WasmEdge-Go
v0.10.0, but in different API(*wasmedge.Executor).Register():var ast *wasmedge.AST
// Assume that `ast` is a loaded WASM from file or buffer and has passed the validation.
// Assume that `executor` is a `*wasmedge.Executor`.
// Assume that `store` is a `*wasmedge.Store`.
// Register the WASM module into store with the export module name "mod".
mod, err := executor.Register(store, ast, "mod")
if err != nil {
fmt.Println("WASM registration FAILED:", err.Error())
}
mod.Release()Developers have the responsibility to release the outputted module instances.
Host module registration
In WasmEdge-Go
v0.9.2, developers can create anImportObjectand register intoStore.// Create the import object with the export module name.
impobj := wasmedge.NewImportObject("module")
// ...
// Add the host functions, tables, memories, and globals into the import object.
// The import object has already contained the export module name.
err := executor.RegisterImport(store, impobj)
if err != nil {
fmt.Println("Import object registration FAILED:", err.Error())
}After WasmEdge-Go
v0.10.0, developers should use theModuleinstance instead:// Create the module instance with the export module name.
impmod := wasmedge.NewModule("module")
// ...
// Add the host functions, tables, memories, and globals into the module instance.
// The module instance has already contained the export module name.
err := executor.RegisterImport(store, impmod)
if err != nil {
fmt.Println("Module instance registration FAILED:", err.Error())
}Developers have the responsibility to release the created module instances.
WASM function invocation
This example uses the WASM file
fibonacci.wasmconverted from the text format fibonacci.wat. In WasmEdge-Gov0.9.2version, developers can invoke a WASM function with the export function name:// Create the store object. The store object holds the instances.
store := wasmedge.NewStore()
// Error.
var err error
// AST object.
var ast *wasmedge.AST
// Return values.
var res []interface{}
// Create the loader object.
loader := wasmedge.NewLoader()
// Create the validator object.
validator := wasmedge.NewValidator()
// Create the executor object.
executor := wasmedge.NewExecutor()
// Load the WASM file or the compiled-WASM file and convert into the AST object.
ast, err = loader.LoadFile("fibonacci.wasm")
if err != nil {
fmt.Println("Load WASM from file FAILED:", err.Error())
return
}
// Validate the WASM module.
err = validator.Validate(ast)
if err != nil {
fmt.Println("Validation FAILED:", err.Error())
return
}
// Instantiate the WASM module into the Store object.
err = executor.Instantiate(store, ast)
if err != nil {
fmt.Println("Instantiation FAILED:", err.Error())
return
}
// Invoke the function which is exported with the function name "fib".
res, err = executor.Invoke(store, "fib", int32(30))
if err == nil {
fmt.Println("Get fibonacci[30]:", res[0].(int32))
} else {
fmt.Println("Run failed:", err.Error())
}
ast.Release()
loader.Release()
validator.Release()
executor.Release()
store.Release()After the WasmEdge-Go
v0.10.0, developers should retrieve theFunctioninstance by function name first.// ...
// Ignore the unchanged steps before validation. Please refer to the sample code above.
var mod *wasmedge.Module
// Instantiate the WASM module and get the output module instance.
mod, err = executor.Instantiate(store, ast)
if err != nil {
fmt.Println("Instantiation FAILED:", err.Error())
return
}
// Retrieve the function instance by name.
funcinst := mod.FindFunction("fib")
if funcinst == nil {
fmt.Println("Run FAILED: Function name `fib` not found")
return
}
res, err = executor.Invoke(store, funcinst, int32(30))
if err == nil {
fmt.Println("Get fibonacci[30]:", res[0].(int32))
} else {
fmt.Println("Run FAILED:", err.Error())
}
ast.Release()
mod.Release()
loader.Release()
validator.Release()
executor.Release()
store.Release()
Instances retrievement
This example uses the WASM file fibonacci.wasm converted from the text format fibonacci.wat.
Before the WasmEdge-Go v0.9.2 versions, developers can retrieve all exported instances of named or anonymous modules from Store:
// Create the store object. The store object holds the instances.
store := wasmedge.NewStore()
// Error.
var err error
// AST object.
var ast *wasmedge.AST
// Create the loader object.
loader := wasmedge.NewLoader()
// Create the validator object.
validator := wasmedge.NewValidator()
// Create the executor object.
executor := wasmedge.NewExecutor()
// Load the WASM file or the compiled-WASM file and convert into the AST object.
ast, err = loader.LoadFile("fibonacci.wasm")
if err != nil {
fmt.Println("Load WASM from file FAILED:", err.Error())
return
}
// Validate the WASM module.
err = validator.Validate(ast)
if err != nil {
fmt.Println("Validation FAILED:", err.Error())
return
}
// Example: register and instantiate the WASM module with the module name "module_fib".
err = executor.RegisterModule(store, ast, "module_fib")
if err != nil {
fmt.Println("Instantiation FAILED:", err.Error())
return
}
// Example: Instantiate the WASM module into the Store object.
err = executor.Instantiate(store, ast)
if err != nil {
fmt.Println("Instantiation FAILED:", err.Error())
return
}
// Now, developers can retrieve the exported instances from the store.
// Take the exported functions as example. This WASM exports the function "fib".
// Find the function "fib" from the instantiated anonymous module.
func1 := store.FindFunction("fib")
// Find the function "fib" from the registered module "module_fib".
func2 := store.FindFunctionRegistered("module_fib", "fib")
ast.Release()
store.Release()
loader.Release()
validator.Release()
executor.Release()
After the WasmEdge-Go v0.10.0, developers can instantiate several anonymous Module instances, and should retrieve the exported instances from named or anonymous Module instances:
// Create the store object. The store is the object to link the modules for imports and exports.
store := wasmedge.NewStore()
// Error.
var err error
// AST object.
var ast *wasmedge.AST
// Module instances.
var namedmod *wasmedge.Module
var anonymousmod *wasmedge.Module
// Create the loader object.
loader := wasmedge.NewLoader()
// Create the validator object.
validator := wasmedge.NewValidator()
// Create the executor object.
executor := wasmedge.NewExecutor()
// Load the WASM file or the compiled-WASM file and convert into the AST object.
ast, err = loader.LoadFile("fibonacci.wasm")
if err != nil {
fmt.Println("Load WASM from file FAILED:", err.Error())
return
}
// Validate the WASM module.
err = validator.Validate(ast)
if err != nil {
fmt.Println("Validation FAILED:", err.Error())
return
}
// Example: register and instantiate the WASM module with the module name "module_fib".
namedmod, err = executor.Register(store, ast, "module_fib")
if err != nil {
fmt.Println("Instantiation FAILED:", err.Error())
return
}
// Example: Instantiate the WASM module and get the output module instance.
anonymousmod, err = executor.Instantiate(store, ast)
if err != nil {
fmt.Println("Instantiation FAILED:", err.Error())
return
}
// Now, developers can retrieve the exported instances from the module instances.
// Take the exported functions as example. This WASM exports the function "fib".
// Find the function "fib" from the instantiated anonymous module.
func1 := anonymousmod.FindFunction("fib")
// Find the function "fib" from the registered module "module_fib".
func2 := namedmod.FindFunction("fib")
// Or developers can get the named module instance from the store:
gotmod := store.FindModule("module_fib")
func3 := gotmod.FindFunction("fib")
namedmod.Release()
anonymousmod.Release()
ast.Release()
store.Release()
loader.Release()
validator.Release()
executor.Release()
Host functions
The difference of host functions are the replacement of ImportObject struct.
// Host function body definition.
func host_add(data interface{}, mem *wasmedge.Memory, params []interface{}) ([]interface{}, wasmedge.Result) {
// add: i32, i32 -> i32
res := params[0].(int32) + params[1].(int32)
// Set the returns
returns := make([]interface{}, 1)
returns[0] = res
// Return
return returns, wasmedge.Result_Success
}
// ...
// Create an import object with the module name "module".
impobj := wasmedge.NewImportObject("module")
// Create and add a function instance into the import object with export name "add".
functype := wasmedge.NewFunctionType(
[]wasmedge.ValType{wasmedge.ValType_I32, wasmedge.ValType_I32},
[]wasmedge.ValType{wasmedge.ValType_I32},
)
hostfunc := wasmedge.NewFunction(functype, host_add, nil, 0)
// The third parameter is the pointer to the additional data object.
// Developers should guarantee the life cycle of the data, and it can be `nil`
// if the external data is not needed.
functype.Release()
impobj.AddFunction("add", hostfunc)
// The import object should be released.
// Developers should __NOT__ release the instances added into the import objects.
impobj.Release()
Developers can use the Module struct to upgrade to WasmEdge v0.10.0 easily.
// Host function body definition.
func host_add(data interface{}, mem *wasmedge.Memory, params []interface{}) ([]interface{}, wasmedge.Result) {
// add: i32, i32 -> i32
res := params[0].(int32) + params[1].(int32)
// Set the returns
returns := make([]interface{}, 1)
returns[0] = res
// Return
return returns, wasmedge.Result_Success
}
// ...
// Create a module instance with the module name "module".
mod := wasmedge.NewModule("module")
// Create and add a function instance into the module instance with export name "add".
functype := wasmedge.NewFunctionType(
[]wasmedge.ValType{wasmedge.ValType_I32, wasmedge.ValType_I32},
[]wasmedge.ValType{wasmedge.ValType_I32},
)
hostfunc := wasmedge.NewFunction(functype, host_add, nil, 0)
// The third parameter is the pointer to the additional data object.
// Developers should guarantee the life cycle of the data, and it can be `nil`
// if the external data is not needed.
functype.Release()
mod.AddFunction("add", hostfunc)
// The module instances should be released.
// Developers should __NOT__ release the instances added into the module instance objects.
mod.Release()