wasmerio / wasmer-go

🐹🕸️ WebAssembly runtime for Go
https://pkg.go.dev/github.com/wasmerio/wasmer-go
MIT License
2.84k stars 161 forks source link

Native or dynamic calls to function results in wrong signature error. #327

Open JamieSinn opened 2 years ago

JamieSinn commented 2 years ago

Describe the bug

Calling a function compiled into a WASM file by assemblyscript errors on attempting to call the function:

panic: Failed to call the `generateBucketedConfig` function natively: Dynamic function returned wrong signature. Expected [] but got [I32]

Function signature is generateBucketedConfig(i32, i32) : i32 - which is reflected in the WAT.

(func $src/index/generateBucketedConfig (param $0 i32) (param $1 i32) (result i32)

The source signature is two string input args and returns a string. But this is mapped to pointers in WASM.

Steps to reproduce

Go Code:


func ExampleFunction() {
    // Let's declare the Wasm module.
    //
    // We are using the text representation of the module here.
    file, err := os.Open("/Users/jamiesinn/git/js-sdks/lib/shared/bucketing-assembly-script/build/bucketing-lib-release.wasm")
    wasmBytes, err := ioutil.ReadAll(file)

    // Create an Engine
    engine := wasmer.NewEngine()
    // Create a Store
    store := wasmer.NewStore(engine)

    fmt.Println("Compiling module...")
    module, err := wasmer.NewModule(store, wasmBytes)
    if err != nil {
        fmt.Println("Failed to compile module:", err)
    }
    // Create an empty import object.
    importObject := wasmer.NewImportObject()

    if err != nil {
        fmt.Println("Failed to generate import object:", err)
    }
    importObject.Register("env", map[string]wasmer.IntoExtern{
        "abort": wasmer.NewFunction(
            store,
            wasmer.NewFunctionType(wasmer.NewValueTypes(wasmer.I32, wasmer.I32, wasmer.I32, wasmer.I32), wasmer.NewValueTypes()),
            func(args []wasmer.Value) ([]wasmer.Value, error) {
                return []wasmer.Value{wasmer.NewI32(42)}, nil
            },
        ),
        "generateBucketedConfig": wasmer.NewFunction(
            store,
            wasmer.NewFunctionType(wasmer.NewValueTypes(wasmer.I32, wasmer.I32), wasmer.NewValueTypes(wasmer.I32)),
            func(args []wasmer.Value) ([]wasmer.Value, error) {
                return []wasmer.Value{wasmer.NewI32(42)}, nil
            },
        ),
    })
    fmt.Println("Instantiating module...")
    // Let's instantiate the Wasm module.
    instance, err := wasmer.NewInstance(module, importObject)

    native, err := instance.Exports.GetFunction("generateBucketedConfig")

    if err != nil {
        panic(fmt.Sprintln("Failed to instantiate the module:", err))
    }

    memory, err := instance.Exports.GetMemory("memory")
    if err != nil {
        panic(fmt.Sprintln("Failed to get memory:", err))
    }

    fmt.Println("Memory size: ", memory.Size())
    memory.Grow(3)
    fmt.Println("Memory size: ", memory.Size())

    written := setStringAt("{\"project\":{\"_id\":\"_project\"},\"environment\":{\"_id\":\"environment\"}}", WASM_PAGE_SIZE*2, memory)
    setStringAt("{\"user_id\":\"test_id\"}" , WASM_PAGE_SIZE*2 + written, memory)

    //fmt.Println(string(memory.Data()[WASM_PAGE_SIZE*2:WASM_PAGE_SIZE*3]))

    gbc, err := instance.Exports.GetRawFunction("generateBucketedConfig")

    if err != nil || gbc == nil {
        panic(fmt.Sprintln("Failed to retrieve the `generateBucketedConfig` function:", err))
    }

    fmt.Println("Calling `generateBucketedConfig` function...")
    result, err := gbc.Call(WASM_PAGE_SIZE*2, WASM_PAGE_SIZE*2+written)

    if err != nil {
        fmt.Println("Failed to call the `generateBucketedConfig` function:", err)
    }
    fmt.Println("Result of the `generateBucketedConfig` function:", result)

    fmt.Println("Calling `generateBucketedConfig` function (natively)...")
    result, err = native(WASM_PAGE_SIZE*2, WASM_PAGE_SIZE*2+written)

    if err != nil {
        panic(fmt.Sprintln("Failed to call the `generateBucketedConfig` function natively:", err))
    }

    fmt.Println("Result of the `generateBucketedConfig` function:", result)
}

Can provide the WASM file if needed.

Expected behavior

Wasmer should understand from parsing the WASM file that the return type is i32 - why is it misunderstanding the return type?

Actual behavior

panic: Failed to call the `generateBucketedConfig` function natively: Dynamic function returned wrong signature. Expected [] but got [I32]

Additional context

Compiled using assemblyscript. We've been having issues with how assemblyscript handles some things in other languages - but haven't seen them in Go yet.