将JavaScript数组作为参数传递给WebAssembly函数

将JavaScript数组作为参数传递给WebAssembly函数,javascript,c++,browser,emscripten,webassembly,Javascript,C++,Browser,Emscripten,Webassembly,我想测试WebAssembly以进行一些复杂的数组计算 p>我编写了一个简单的C++函数,添加了两个代码> int 数组,每个数组包含3个元素: // hello.cpp extern "C" { void array_add(int * summed, int* a, int* b) { for (int i=0; i < 3; i++) { summed[i] = a[i] + b[i]; } } } 但不知何故,结果数组总是[0,0,0] 我尝试了很多方法,包

我想测试WebAssembly以进行一些复杂的数组计算

<> p>我编写了一个简单的C++函数,添加了两个代码> int <代码>数组,每个数组包含3个元素:

// hello.cpp
extern "C" {

void array_add(int * summed, int* a, int* b) {
  for (int i=0; i < 3; i++) {
    summed[i] = a[i] + b[i];
  }
}

}
但不知何故,
结果
数组总是
[0,0,0]

我尝试了很多方法,包括使用
ccall()
(请参阅)调用函数,但似乎无法将数组作为wasm编译函数的参数传递

例如,使用以下C++函数:

extern "C" {

int first(int * arr) {
  return arr[0];
}

}
在JavaScript中调用时,结果是一个随机整数,而不是作为参数传递的数组中的预期值

我错过了什么


关于C++的问题,我知道的很清楚,所以如果这是一个与我的C++无知有关的初学者问题,那么所有的道歉……< /p> < p>你的问题非常类似:WebSalm只支持<代码> i32 < /> >代码> i64 < /代码> />代码> f32 < /> >代码> f64 < /> >以及<>代码> i8>代码> /<代码> i16<代码>存储。 这意味着您不能传入指针。当你来自C++的观点时,你所做的一切都是理智的(不需要为无知道歉),但这并不是WebAssembly的边界如何运作。这对于C++专家来说也是令人惊讶的。 与字符串问题一样,您需要:

  • 通过对每个条目调用一次导出,一次复制一个数组(例如
    set(size\t index,int-value)
  • 将WebAssembly实例的堆作为
    ArrayBuffer
    公开给JavaScript,并将所需的值直接写入
    ArrayBuffer
您可以使用我在另一个答案中提出的相同代码执行后者:

const bin = ...; // WebAssembly binary, I assume below that it imports a memory from module "imports", field "memory".
const module = new WebAssembly.Module(bin);
const memory = new WebAssembly.Memory({ initial: 2 }); // Size is in pages.
const instance = new WebAssembly.Instance(module, { imports: { memory: memory } });
const arrayBuffer = memory.buffer;
const buffer = new Uint8Array(arrayBuffer);

< C++ >你可能会想:“指针怎么工作?”上面我解释了WebAssembly↔ JavaScript你不能到处传递指针!内部WebAssembly指针表示为简单的
i32
值。Empscripten依赖LLVM来完成这项工作,由于WebAssembly以ILP32的形式出现,最大堆大小为4GiB,所以它可以正常工作

它确实对间接函数调用和函数指针有着有趣的含义!我把这个留给另一个问题;-)

然而,这确实意味着JavaScript可以“谈论”指向WebAssembly的指针:
i32
i32
。如果知道某个值在堆中的某个位置,那么可以将该值传递给JavaScript,JavaScript可以修改该值并将其传递回WebAssembly。如果JavaScript访问堆的代码< ArrayBuffer < /Cord>,那么有一个<代码> i32 允许你知道堆中的什么地方,并像C++那样修改堆。

WebSaseBead堆与大多数C++堆不同:它没有访问可执行页的能力,也没有访问调用栈的权限(或者更确切地说,大多数调用堆栈):编译器(例如LLVM)可能“将某些地址取值溢出到堆中,而不是使用WebSasppLISH本地语言”。这基本上就是哈佛体系结构所做的(与冯·诺依曼相反)



那么你的
你好。_array\u add(result,a,b)
在做什么?使用
ToInteger
从数组强制执行
a
b
。这将成为
0
,它在WebAssembly中是一个有效的堆位置!您正在访问堆中非常意外的部分

多亏了其他类似的问题:

和API文件:

我已经弄明白了。为了举例说明如何将数组传递给WASM函数/获取数组,我在C++中实现了一个简单的数组复制:

#include <stdint.h>

extern "C" {

int* copy_array(int* in_array, int length) {
  int out_array[length];
  for (int i=0; i<length; i++) {
    out_array[i] = in_array[i];
  }
  return out_array;
}

}

请注意此处的
arrayToPtr
ptrToArray
函数。。。他们正在做传递/返回数组的工作。

我尝试了一种基于MessagePack的解决方案,将任意对象序列化到WASM内存数组中。这似乎相当灵活,允许我在JavaScript和C++之间来回传递对象。以下是一篇包含更多详细信息的博文:
#include <stdint.h>

extern "C" {

int* copy_array(int* in_array, int length) {
  int out_array[length];
  for (int i=0; i<length; i++) {
    out_array[i] = in_array[i];
  }
  return out_array;
}

}
<!doctype html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <script type="text/javascript" src="build/wasm_dsp.js"></script>
    <script type="text/javascript">
      function reqListener () {
        // Loading wasm module
        var arrayBuffer = oReq.response
        WasmDsp['wasmBinary'] = arrayBuffer
        wasmDsp = WasmDsp({ wasmBinary: WasmDsp.wasmBinary })

        var inArray = new Int32Array([22, 44, 66, 999])
        var nByte = 4
        copyArray = wasmDsp.cwrap('copy_array', null, ['number', 'number']);

        // Takes an Int32Array, copies it to the heap and returns a pointer
        function arrayToPtr(array) {
          var ptr = wasmDsp._malloc(array.length * nByte)
          wasmDsp.HEAP32.set(array, ptr / nByte)
          return ptr
        }

        // Takes a pointer and  array length, and returns a Int32Array from the heap
        function ptrToArray(ptr, length) {
          var array = new Int32Array(length)
          var pos = ptr / nByte
          array.set(wasmDsp.HEAP32.subarray(pos, pos + length))
          return array
        }

        var copiedArray = ptrToArray(
          copyArray(arrayToPtr(inArray), inArray.length)
        , inArray.length)

        console.log(copiedArray)
      }

      var oReq = new XMLHttpRequest();
      oReq.responseType = "arraybuffer";
      oReq.addEventListener("load", reqListener);
      oReq.open("GET", "build/wasm_dsp.wasm");
      oReq.send();
    </script>
  </head>
  <body>

  </body>
</html>