Pass a JavaScript array as argument to a WebAssembly function

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

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:

  • 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);

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 😉

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

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


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!

Leave a Comment