arrays - 在 Go 中调用 WebAssembly 代码时如何使用 Go slice?
问题描述
我想在 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)
}
}
但是这段代码并没有给我预期的结果。我的代码的逻辑是计算数组的总和。数组的值在运行时给出。
我需要做什么改变?
我的 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
}
谢谢
解决方案
将数据复制到 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)))
推荐阅读
- visual-studio-code - VSCode + 调试器控制台。如何更改调试器中文本的颜色?
- javascript - 在循环中显示带有延迟的随机 div
- java - 并行处理传入数据的最佳方法?(Java/Groovy)
- flutter - 状态更改时 AppWidget 主页不会更改
- javascript - Javascript - 使用表单字段值来确定要使用的电子邮件地址
- python - Python中基于三角形的3D点的旋转和平移
- git - 一个分支中特定文件的更改会反映在另一个分支中的相同文件上
- html - 在选择标签之后定位下一个输入字段
- java - java.security.properties - 未应用更改
- c# - 我应该如何修复我的 runTime 方法以从我的 timeLeft 变量中减去/返回剩余时间?