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
ImportObject
into theModule
.The
ImportObject
struct 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
Function
instead of the index in theFuncRef
value type.For the better performance and security, the
FuncRef
related APIs used the*wasmedge.Function
for the parameters and returns.wasmedge.NewFuncRef()
is changed to use the*Function
as 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.0
version, developers can instantiate multiple anonymous WASM module byExecutor
and get theModule
instance. But for the source code using theVM
APIs, 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
, andGlobal
instances retrievement from theStore
is moved to theModule
instance. TheStore
only manage the module linking when instantiation and the named module searching after thev0.10.0
version.(*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
Module
instance for the host functons, theExecutor
will output aModule
instance after instantiation. No matter the anonymous or named modules, developers have the responsibility to destroy them by(*wasmedge.Module).Release()
API. TheStore
will link to the namedModule
instance after registering. After the destroyment of aModule
instance, theStore
will unlink to that automatically; after the destroyment of theStore
, the allModule
instances theStore
linked to will unlink to thatStore
automatically.
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.2
version, developers can instantiate a WASM module by theExecutor
API: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.0
version, the instantiated anonymous module will be outputed and handled by caller, and not only 1 anonymous module instance can be instantiated. Developers have the responsibility to release the outputed 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 outputed module instances.
Host module registration
In WasmEdge-Go
v0.9.2
, developers can create anImportObject
and 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 theModule
instance 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 invokation
This example uses the fibonacci.wasm, and the corresponding WAT file is at fibonacci.wat. In WasmEdge-Go
v0.9.2
version, 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 theFunction
instance 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 fibonacci.wasm, and the corresponding WAT file is at 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 instaces.
// 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()