将JavaScript数组作为参数传递给WebAssembly函数 [英] Pass a JavaScript array as argument to a WebAssembly function

查看:517
本文介绍了将JavaScript数组作为参数传递给WebAssembly函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I would like to test WebAssembly for doing some complex array calculations.

所以我编写了一个简单的C ++函数,添加了两个 int 数组,每个数组包含3个元素:

So I've written a simple C++ function adding two int arrays containing 3 elements each :

// 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 -sMODULARIZE = 1-sEXPORT_NAME ='HELLO' - sBINARYEN_METHOD ='native-wasm' - sEXPORTED_FUNCTIONS = ['_ array_add'] - o build / hello.js

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

Which generates among others, a js and a wasm file. I load these with the following html page :

<!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/hello.js"></script>
    <script type="text/javascript">
      function reqListener () {
        // Loading wasm module
        var arrayBuffer = oReq.response
        HELLO['wasmBinary'] = arrayBuffer
        hello = HELLO({ wasmBinary: HELLO.wasmBinary })

        // Calling function
        var result = new Int32Array(3)
        var a = new Int32Array([1, 2, 3])
        var b = new Int32Array([4, 5, 2])
        hello._array_add(result, a, b)
        console.log('result', result)
      }

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

  </body>
</html>

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

But somehow, the result array is always [0, 0, 0].

我尝试过各种各样的事情,包括用 ccall()调用函数(参见 emscripten docs )似乎我不能将一个数组作为我的wasm编译函数的参数传递。

I have tried a variety of things, including calling the function with ccall() (see emscripten docs ) and it seems that I cannot get an array passed as argument of my wasm compiled function.

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

For example, with the following C++ function :

extern "C" {

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

}

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

Result when called in JavaScript is a random-ish integer, instead of the expected value from the array I passed as argument.

我缺少什么?

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

NB : I know pretty much nothing about C++, so all apologies if this is a beginner question related to my C++ ignorance ...

推荐答案

您的问题与此问题非常相似:WebAssembly仅支持 i32 / i64 / f32 / f64 价值类型以及 i8 / i16 用于存储。

Your question is very similar to this one: WebAssembly only supports i32 / i64 / f32 / f64 value types as well as i8 / i16 for storage.

这意味着你可以传递指针。当你从C ++的角度来看时,你所做的事情是完全理智的(不需要为无知而道歉!),但这并不是WebAssembly的边界是如何运作的。这对C ++专家来说也是令人惊讶的。

This means that you can't pass in pointers. What you're doing is totally sane when you're coming from a C++ point of view (no need to apologize for ignorance!), but it's just not how WebAssembly's boundary works. That surprising to C++ experts too.

在字符串问题中,您需要:

As in the string question, you need to either:


  • 通过每个条目调用一次导出(例如 set(size_t index,int value)),一次复制一个数组。

  • 将您的WebAssembly实例的堆作为 ArrayBuffer 暴露给JavaScript,并直接写入 ArrayBuffer 您想要的值。

  • Copy the array in one at a time by calling an export once per entry (such as set(size_t index, int value)).
  • Expose your WebAssembly instance's heap as an ArrayBuffer to JavaScript, and write directly into the ArrayBuffer the values you want.

您可以使用我在其他答案中提出的相同代码来执行后者:

You can do the latter with the same code I proposed in the other answer:

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,它只是工作。


Coming from C++ you're probably wondering: "but how do pointers work?". Above I explain that WebAssembly ↔ JavaScript you can't pass pointers around! Inside WebAssembly pointers are represented as simple i32 values. Empscripten relies on LLVM to do this, and since WebAssembly presents itself as ILP32 with a 4GiB maximum heap size it Just Works.

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

It does have interesting implications for indirect function calls and function pointers! I'll leave that for another question ;-)

但这意味着JavaScript可以谈论指向WebAssembly的指针: i32 i32 。如果你知道某个值在堆中的某个位置,那么你可以将 i32 传递给JavaScript,JavaScript可以修改它并将其传回WebAssembly。如果JavaScript可以访问堆的 ArrayBuffer ,那么拥有 i32 可以让你知道堆中的位置,以及像在C ++中一样修改堆。

This does however mean that JavaScript can "talk" about pointers to WebAssembly: an i32 is an i32. If you know a value is somewhere in the heap then you can pass that i32 out to JavaScript, and JavaScript can modify it and pass it back in to WebAssembly. If JavaScript has access to the heap's ArrayBuffer then having an i32 allows you to know where in the heap things are, and modify the heap as you would from C++.

WebAssembly堆与大多数C ++堆不同:它不能访问可执行页,也没有访问权限到调用堆栈(或者更确切地说,大多数调用堆栈:LLVM等编译器可能会将一些地址获取值溢出到堆而不是使用WebAssembly的本地)。这基本上就是哈佛架构所做的(而不是冯·诺伊曼)。

The WebAssembly heap is different from most C++ heaps though: it doesn't have access to executable pages, nor does it have access to the call stack (or rather, most of the call stack: compilers such as LLVM may "spill" some address-taken values to the heap instead of using WebAssembly's locals). This is basically what Harvard architectures do (as opposed to von Neumann).

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

So what is your hello._array_add(result, a, b) doing? Coercing a and b from arrays using ToInteger. That becomes 0, which in WebAssembly is a valid heap location! You're accessing a very unexpected part of your heap!

这篇关于将JavaScript数组作为参数传递给WebAssembly函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆