Как использовать ломтик Go при вызове кода WebAssembly в Go? - PullRequest
0 голосов
/ 18 марта 2020

Я хочу вычислить сумму массива с помощью WebAssembly в Go:

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)

    }
}

Но этот код не дает ожидаемого результата. Logi c для моего кода заключается в расчете суммы массива. Значения для массива дают во время выполнения.
Какие изменения мне нужно сделать?

Мой код ржавчины выглядит следующим образом

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 Ответ

1 голос
/ 18 марта 2020

Копировать данные в память 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))
    }

Получить экспортированную функцию bar из экземпляра WebAssembly:

    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)))
...