当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《将JavaScript数组作为参数传递给WebAssembly函数》经验,为你挑选了2个好方法。

我想测试WebAssembly做一些复杂的数组计算.

所以我写了一个简单的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];
  }
}

}

并编译了这个:

emcc hello.cpp -s WASM=1 -s "MODULARIZE=1" -s "EXPORT_NAME='HELLO'" -s "BINARYEN_METHOD='native-wasm'" -s "EXPORTED_FUNCTIONS=['_array_add']" -o build/hello.js

其中包括a js和a wasm文件.我用以下html页面加载这些:



  
    
    
    
    
  
  

  

但不知何故,result阵列总是如此[0, 0, 0].

我已经尝试了各种各样的东西,包括调用函数ccall()(参见emscripten docs),似乎我不能将一个数组作为我的wasm编译函数的参数传递.

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

extern "C" {

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

}

在JavaScript中调用的结果是random-ish整数,而不是我作为参数传递的数组的期望值.

我错过了什么?

注意:我对C++几乎一无所知,所以如果这是一个与我的C++无知相关的初学者问题,那么所有道歉......



1> JF Bastien..:

您的问题与此问题非常相似:WebAssembly仅支持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将自身呈现为具有4GiB最大堆大小的ILP32,因此Just Works.

它确实对间接函数调用和函数指针有意义!我会留下另一个问题;-)

然而,这确实意味着JavaScript可以"谈论"指向WebAssembly的指针:a i32是一个i32.如果您知道某个值位于堆中的某个位置,那么您可以将其传递i32给JavaScript,JavaScript可以对其进行修改并将其传递回WebAssembly.如果JavaScript可以访问堆,ArrayBuffer那么i32可以让你知道堆中的位置,并像在C++中那样修改堆.

WebAssembly堆与大多数C++堆不同:它不能访问可执行页,也不能访问调用堆栈(或者更确切地说,大多数调用堆栈:LLVM之类的编译器可能会"溢出"某些地址-taken值到堆而不是使用WebAssembly的本地).这基本上就是哈佛架构所做的(而不是冯·诺伊曼).


那你hello._array_add(result, a, b)在做什么?使用强制转换ab数组ToInteger.这就变成了0,在WebAssembly中是一个有效的堆位置!您正在访问堆中非常意外的部分!



2> sebpiq..:

所以感谢其他类似的问题:

使用emscripten将数组传递给C函数

如何处理传递/返回emscripten编译代码的数组指针?

和API文档:

https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#getValue

我已经弄清楚了.为了举例说明如何将数组传递给wasm函数/获取数组,我在C++中实现了一个简单的数组副本:

#include 

extern "C" {

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

您可以这样编译:

emcc wasm_dsp.cpp -s WASM=1 -s "MODULARIZE=1" -s "EXPORT_NAME='WasmDsp'" -s "BINARYEN_METHOD='native-wasm'" -s "EXPORTED_FUNCTIONS=['_copy_array']" -o build/wasm_dsp.js

并在浏览器中运行如下:



  
    
    
    
    
  
  

  

注意这里的函数arrayToPtrptrToArray函数......它们是执行传递/返回数组的工作.

推荐阅读
重庆制造漫画社
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有