Reputation: 336
I'm following this code here, trying to share memory between my AssemblyScript code and my JS:
let aryPtr = instance.exports.allocateF32Array(3);
let ary = new Float32Array(instance.exports.memory.buffer, aryPtr, 3);
ary[0] = 1.0;
ary[1] = 2.0;
instance.exports.addArray(aryPtr);
And my index.ts:
export function allocateF32Array(length: i32): Float32Array {
return new Float32Array(length);
}
export function addArray(data: Float32Array): i32 {
data[2] = data[0] + data[1];
return data.length;
}
But this results in RuntimeError: memory access out of bounds
in addArray
. Have I misunderstood how this is supposed to work?
Upvotes: 2
Views: 1801
Reputation: 26161
A little late but this might be useful for people ending up here.
In my opinion AssemblyScript is a fantastic language to easily adopt WASM ability into your JS/TS code. The recent release 0.25.1 comes with bindings ready on many types. Yet still you can easily implement the bindings yourself.
Remember that you can only interchange i32
, i64
, f32
and f64
data directly inbetween your host and WASM module. Besides you can access the WASM memory from JS/TS (host) side.
Let us investigate the initial part of the code
let aryPtr = instance.exports.allocateF32Array(3);
let ary = new Float32Array(instance.exports.memory.buffer, aryPtr, 3);
ary[0] = 1.0;
ary[1] = 2.0;
instance.exports.addArray(aryPtr);
allocateF32Array(n)
is an exported function from WASM. When you invoke it with an integer argument n
it creates a Float32Array
of length n
at WASM side and passes it's pointer back to host side. The pointer is it's location in the module memory and gets assigned to aryPtr
.Float32Array
just to use as a view to access the WASM memory. So it passes the buffer to use, offset (pointer), and length) to the Float32Array
constructor. Now you can access the WASM memory's related part through ary
. Any modification you do on ary
will actually happen on the WASM side Float32Array
.addArray(ptr)
with the pointer of it.Now you should implement the allocateF32Array
and addArray
) functions to export.
TypedArray
is somewhat very similar to normal JS in AssemblyScript (AS).allocateF32Array(n)
:
export function allocateF32Array(length: i32): i32 {
const arr : Float32Array = new Float32Array(length);
return changetype<i32>(arr); // return the pointer
}
addArray(ptr)
:
export function addArray(ptr: usize): f32 {
const arr : Float32Array = changetype<Float32Array>(ptr); // obtain Float32Array from the pointer
return arr[0] + arr[1];
}
Finally, this is in fact the raw method and you don't really need to get this low. Nowadays the bindings are readily implemented in the .build/release.js
file from where you import the exported function just like ESM imports.
Upvotes: 1
Reputation: 361
I recommend to use the official loader for such purposes.
On the JavaScript side: (node.js for example)
const fs = require("fs");
const loader = require("@assemblyscript/loader");
const module = loader.instantiateSync(
fs.readFileSync("optimized.wasm"),
{}
);
var ptrArr = module.__retain(module.__allocArray(module.FLOAT32ARRAY, [1, 2, 0]));
console.log('length:', module.addArray(ptrArr));
const arr = module.__getFloat32Array(ptrArr);
console.log('result:', arr[2]);
// free array
module.__release(ptrArr);
On the AssemblyScript side:
export const FLOAT32ARRAY = idof<Float32Array>();
export function addArray(data: Float32Array): i32 {
data[2] = data[0] + data[1];
return data.length;
}
Upvotes: 1