简体   繁体   English

在 Go 中调用 WebAssembly 代码时如何使用 Go 切片?

[英]How to use Go slice when calling WebAssembly code in Go?

I want to calculate the sum of an array using WebAssembly in Go:我想在 Go 中使用 WebAssembly 计算数组的总和:

package main

import (
    "encoding/binary"
    "encoding/hex"
    "fmt"

    wasm "github.com/wasmerio/go-ext-wasm/wasmer"
)

const length int32 = 4

func main() {
    // Instantiate the module.
    wasmbyte, _ := wasm.ReadBytes("test.wasm")
    instance, _ := wasm.NewInstance(wasmbyte)
    defer instance.Close()
    hasmemory := instance.HasMemory()
    fmt.Println("it has memory:", (hasmemory))

    a := []int32{1, 2, 3, 4}
    var i int32
    var ptr [length]*int32

    for i = 0; i < length; i++ {
        ptr[i] = &a[i]
        fmt.Printf("Value of a[%d] = %d\n", i, *ptr[i])

        // pass int value
        // lengths := binary.LittleEndian.Uint32(a)
        // fmt.Printf("customLen=%d\n", int32(lengths))
        // result := int32(lengths)

        allocateResult, err := instance.Exports["bar"](*ptr[i], length)
        if err != nil {
            fmt.Println("error is here", err)
        }

        binary.LittleEndian.PutUint32(instance.Memory.Data()[0:4], uint32(length))

        inputPointer := allocateResult.ToI32()

        //  Write the subject into the memory.
        memory := instance.Memory.Data()[inputPointer:]
        binary.LittleEndian.Uint32(memory)

        resp := hex.EncodeToString(memory)
        fmt.Println("resp:", resp)

    }
}

But this code is not giving me the expected result.但是这段代码没有给我预期的结果。 Logic for my code is to calculate the sum of an array.我的代码的逻辑是计算数组的总和。 Values to the array is giving during runtime.数组的值在运行时给出。
What changes I need to do?我需要做哪些改变?

My rust code looks like this我的锈代码看起来像这样

use std::os::raw::c_int;

#[no_mangle]
pub extern fn bar(my_array: *const c_int, length: c_int) -> *mut c_int{
    let slice = unsafe { std::slice::from_raw_parts(my_array, length as usize) };
    let resp: i32 = slice.iter().sum();

    resp as *mut c_int
}

Thanks谢谢

Copy data to WebAssembly memory (for example WebAssembly memory address 0):将数据复制到 WebAssembly 内存(例如 WebAssembly 内存地址 0):

    a := []int32{10, 20, 30, 40}
    // Copy data to wasm memory:
    bytes := instance.Memory.Data()
    for i, v := range a {
        binary.LittleEndian.PutUint32(bytes[4*i:], uint32(v))
    }

Get the bar exported function from the WebAssembly instance:从 WebAssembly 实例获取bar导出函数:

    bar := instance.Exports["bar"]

Call that exported function with WebAssembly memory address and length:使用 WebAssembly 内存地址和长度调用导出的函数:

    result, err := bar(0, 4)
    if err != nil {
        panic(err)
    }

    fmt.Println(result)

The main.go file: main.go文件:

package main

import (
    "encoding/binary"
    "fmt"

    wasm "github.com/wasmerio/go-ext-wasm/wasmer"
)

func main() {
    // Instantiate the module.
    wasmbyte, err := wasm.ReadBytes("test.wasm")
    if err != nil {
        panic(err)
    }

    instance, err := wasm.NewInstance(wasmbyte)
    if err != nil {
        panic(err)
    }

    defer instance.Close()
    hasmemory := instance.HasMemory()
    fmt.Println("it has memory:", hasmemory)

    a := []int32{10, 20, 30, 40}
    // Copy data to wasm memory:
    bytes := instance.Memory.Data()
    for i, v := range a {
        binary.LittleEndian.PutUint32(bytes[4*i:], uint32(v))
    }

    bar := instance.Exports["bar"]

    result, err := bar(0, 4)
    if err != nil {
        panic(err)
    }

    fmt.Println(result)
}

Output ( go run main.go ):输出( go run main.go ):

it has memory: true
100

And the following src/lib.rs file has the same wasm binary (since Rust slice has only pointer and length):并且以下src/lib.rs文件具有相同的 wasm 二进制文件(因为 Rust 切片只有指针和长度):

#[no_mangle]
pub extern "C" fn bar(slice: &[i32]) -> i32 {
    slice.iter().sum()
}

Convert to test.wasm :转换为test.wasm

rustc --target wasm32-unknown-unknown -O --crate-type=cdylib src/lib.rs  -o test.wasm

Output converted to test.wat ( wasm2wat test.wasm -o test.wat ) to see the function $bar arguments ( param i32 i32 ):输出转换为test.wat ( wasm2wat test.wasm -o test.wat ) 以查看函数$bar参数 ( param i32 i32 ):

(module
  (type (;0;) (func (param i32 i32) (result i32)))
  (func $bar (type 0) (param i32 i32) (result i32)
    (local i32)
    block  ;; label = @1
      local.get 1
      br_if 0 (;@1;)
      i32.const 0
      return
    end
    local.get 1
    i32.const 2
    i32.shl
    local.set 2
    i32.const 0
    local.set 1
    loop  ;; label = @1
      local.get 0
      i32.load
      local.get 1
      i32.add
      local.set 1
      local.get 0
      i32.const 4
      i32.add
      local.set 0
      local.get 2
      i32.const -4
      i32.add
      local.tee 2
      br_if 0 (;@1;)
    end
    local.get 1)
  (table (;0;) 1 1 funcref)
  (memory (;0;) 16)
  (global (;0;) (mut i32) (i32.const 1048576))
  (global (;1;) i32 (i32.const 1048576))
  (global (;2;) i32 (i32.const 1048576))
  (export "memory" (memory 0))
  (export "bar" (func $bar))
  (export "__data_end" (global 1))
  (export "__heap_base" (global 2)))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM