wasm-micro-runtime
wasm-micro-runtime copied to clipboard
Why do functions implemented in wasm require more than one parameter when calling CallFuncV?
- I have a
GetIntfunction in wasm:
// ...
//export GetInt
func GetInt() int32 {
fmt.Println("this is a test.")
return 15
}
// ...
- there is no error when I calling
CallFuncevent thoughGetIntdoes not require any parameters:
func main(){
// ...
err = instance.CallFunc("GetInt", 1, []uint32{0})
if err != nil {
fmt.Println(err)
return
}
// ...
}
- But it must be an error when I calling
CallFuncV: fatal error: "unexpected signal during runtime execution"
func main(){
// ...
results := make([]interface{}, 1)
err = instance.CallFuncV("GetInt", 1, results)
if err != nil {
fmt.Println(err)
return
}
// ...
}
- Of course, there is no error if the
GetIntis modified to:
// ...
//export GetInt
func GetInt(a int32) int32 {
fmt.Println("this is a test.")
return 15
}
// ...
- And calling
CallFuncVlike that:
func main(){
// ...
results := make([]interface{}, 1)
err = instance.CallFuncV("GetInt", 1, results, int32(1))
if err != nil {
fmt.Println(err)
return
}
// ...
}
- Finaly, I only want my function
GetIntdoes not require any parameters. What should I do?
@littetimo567 Do you use wamr go binding to call the wasm function which hasn't parameter? Maybe you can get the function first and then get its parameter count, and then decide what to do?
https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/language-bindings/go/wamr/instance.go#L167-L180
@wenyongh I'm sure the function in my wasm has no parameter and return one value. Ex. I using the wamr-sdk, it's panic when I call the function of instance.CallFuncV. My function is :
package main
import "fmt"
func main() {}
//export GetInt
func GetInt() int32 {
fmt.Println("this is a test.")
return 15
}
I implemented a Call function in the Instance.go file by referring to CallFunc and CallFuncV. The Call function ignoring how many input parameters and how many output parameters. And solved my issue.
func (_self *Instance) Call(fn string, args ...interface{}) ([]interface{}, error) {
f, err := _self.lookupFunction(fn)
if err != nil {
return nil, err
}
argc := uint32(C.wasm_func_get_param_count(f, _self._instance))
resultCount := uint32(C.wasm_func_get_result_count(f, _self._instance))
paramTypes := make([]C.uchar, argc)
resultType := make([]C.uchar, resultCount)
if argc > 0 {
C.wasm_func_get_param_types(f, _self._instance,
(*C.uchar)(unsafe.Pointer(¶mTypes[0])))
}
if resultCount > 0 {
C.wasm_func_get_result_types(f, _self._instance,
(*C.uchar)(unsafe.Pointer(&resultType[0])))
}
if len(args) != int(argc) {
str := "invalid param count, must be equal to %d"
return nil, fmt.Errorf(str, argc)
}
argvSize := argc * 2
if resultCount > argc {
argvSize = resultCount * 2
}
argv := make([]uint32, argvSize)
index := uint32(0)
for i, arg := range args {
switch val := arg.(type) {
case int32:
if paramTypes[i] != C.WASM_I32 &&
paramTypes[i] != C.WASM_FUNCREF &&
paramTypes[i] != C.WASM_EXTERNREF {
str := "invalid param type %d, " + "expect i32 but got other"
return nil, fmt.Errorf(str, paramTypes[i])
}
argv[index] = uint32(val)
index = index + 1
case int64:
if paramTypes[i] != C.WASM_I64 {
str := "invalid param type %d, " + "expect i64 but got other"
return nil, fmt.Errorf(str, paramTypes[i])
}
addr := (*C.uint32_t)(unsafe.Pointer(&argv[index]))
C.PUT_I64_TO_ADDR(addr, (C.int64_t)(val))
index += 2
case float32:
if paramTypes[i] != C.WASM_F32 {
str := "invalid param type %d, " + "expect f32 but got other"
return nil, fmt.Errorf(str, paramTypes[i])
}
*(*C.float)(unsafe.Pointer(&argv[index])) = (C.float)(val)
index++
case float64:
if paramTypes[i] != C.WASM_F64 {
str := "invalid param type %d, " + "expect f64 but got other"
return nil, fmt.Errorf(str, paramTypes[i])
}
addr := (*C.uint32_t)(unsafe.Pointer(&argv[index]))
C.PUT_F64_TO_ADDR(addr, (C.double)(val))
index += 2
default:
return nil, fmt.Errorf("unknown param type %d", paramTypes[i])
}
}
isThreadEnvInited := Runtime().ThreadEnvInited()
if !isThreadEnvInited {
Runtime().InitThreadEnv()
}
defer func() {
if !isThreadEnvInited {
Runtime().DestroyThreadEnv()
}
}()
var argv_C *C.uint32_t
if argc > 0 {
argv_C = (*C.uint32_t)(unsafe.Pointer(&argv[0]))
}
argc_C := (C.uint)(argc)
if !C.wasm_runtime_call_wasm(_self._exec_env, f, argc_C, argv_C) {
return nil, fmt.Errorf("error: %s", string(_self.GetException()))
}
index = 0
results := make([]interface{}, resultCount)
for i := 0; i < int(resultCount); i++ {
switch resultType[i] {
case C.WASM_I32, C.WASM_FUNCREF, C.WASM_EXTERNREF:
i32 := int32(argv[index])
results[i] = i32
index = index + 1
case C.WASM_I64:
addr := (*C.uint32_t)(unsafe.Pointer(&argv[index]))
results[i] = (int64)(C.GET_I64_FROM_ADDR(addr))
index = index + 2
case C.WASM_F32:
addr := (*C.float)(unsafe.Pointer(&argv[index]))
results[i] = (float32)(*addr)
index++
case C.WASM_F64:
addr := (*C.uint32_t)(unsafe.Pointer(&argv[index]))
results[i] = (float64)(C.GET_F64_FROM_ADDR(addr))
index += 2
}
}
return results, nil
}
func (_self *Instance) lookupFunction(fn string) (C.wasm_function_inst_t, error) {
_self._mutex.Lock()
defer _self._mutex.Unlock()
f := _self._exportsCache[fn]
if f == nil {
cfn := (C.CString)(fn)
defer C.free(unsafe.Pointer(cfn))
f = C.wasm_runtime_lookup_function(_self._instance, cfn)
if f == nil {
return nil, fmt.Errorf("lookup function failed")
}
_self._exportsCache[fn] = f
}
return f, nil
}
OK, thanks for update, how about renaming Call to CallFuncV2 and lookupFunction to LookupFunction? And could you submit a PR to upload the code?