为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
天涯尽头无女友 2022-05-23 15:43:02
我想在 Go 中使用 WebAssembly 计算数组的总和:package mainimport (    "encoding/binary"    "encoding/hex"    "fmt"    wasm "github.com/wasmerio/go-ext-wasm/wasmer")const length int32 = 4func 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)    }}但是这段代码并没有给我预期的结果。我的代码的逻辑是计算数组的总和。数组的值在运行时给出。我需要做什么改变?我的 rust 代码看起来像这样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}谢谢
查看完整描述

1 回答

?
蛊毒传说

TA贡献1895条经验 获得超3个赞

将数据复制到 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))

    }

从 WebAssembly 实例中获取bar导出的函数:


    bar := instance.Exports["bar"]

使用 WebAssembly 内存地址和长度调用导出的函数:


    result, err := bar(0, 4)

    if err != nil {

        panic(err)

    }


    fmt.Println(result)

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)

}


输出(go run main.go):


it has memory: true

100

以下src/lib.rs文件具有相同的 wasm 二进制文件(因为 Rust 切片只有指针和长度):


#[no_mangle]

pub extern "C" fn bar(slice: &[i32]) -> i32 {

    slice.iter().sum()

}

转换为test.wasm:


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


输出转换为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)))


查看完整回答
反对 回复 2022-05-23
  • 1 回答
  • 0 关注
  • 115 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信