I have trouble handing over a double array to a WASM file, that is generated via emscripten. I have generated it as a .js output file with WASM=1, so I also have a wasm file.
This is my abbreviated C++ code:
#include <iostream>
using namespace std;
extern "C" {
int main(int argc, char** argv) {
return 0;
}
double *calculate(double *x, double *y, int array_length) {
std:cout << "Array Length: " << array_length << endl;
for (int i = 0; i < array_length; i++) {
std::cout << "Coords: " << x[i] << ", " << y[i] << endl;
}
return new double[7]{1,1,2,3,5,8,13};
}
}
It produces this output in the browser console:
Array Length: 4 average.js:8:16057
Coords: 2.36377e+232, 2.36377e+232 average.js:8:16057
Coords: 5.9419e-310, 5.9419e-310 average.js:8:16057
Coords: 4.28375e-319, 4.28375e-319 average.js:8:16057
Coords: 1.4854e-313, 1.4854e-313
I can see it does something.
This is the code calling it:
import { CalculationAdapterInterface, Coords, GraphData } from "../CalculationAdapterInterface";
import averageModule from "./average"
export default class CalculationWasmAdapter implements CalculationAdapterInterface {
async calculate(data: GraphData): Promise<Coords|void> {
const x = [ 5.0, 3.0, 2.0, 5.0];
const y = x.map(x => x/2);
const to_byte = (arr: number[]) => { return new Float64Array(arr).buffer}
const filePath = window.location.origin + "/average.wasm";
averageModule({locateFile: () => filePath}).then((module: any) => {
const calculate = module.cwrap('calculate', 'number', ['array', 'array', 'int'])
calculate(to_byte(x), to_byte(y), x.length);
})
}
}
I don't understand why the output in the browser is generated. When I change the input values in the array, it does not change the printed values (except for how many are printed). I strongly suspect that the c++ code does not receive the array and reads from some default allocated space. But why?
I've only ever done this once and I don't claim to be the expert but I had success passing an array of doubles from JavaScript to C++ using this technique.
The way I understand it, if you want to access memory from JavaScript, you have to be aware that JavaScript and WebAssembly have different memory layouts. You use HEAPF64.set
to copy data from a JavaScript array (with its own memory layout) to the Emscripten HEAP, where it can be accessed by the WebAssembly module.
Here's my example, which is node.js (sorry, that's how I was using it), but something similar should be possible in the browser platform.
const factory = require('./src/passarray.js');
factory().then(instance => {
const doubleArray = new Float64Array([1.0, 2.0, 3.0, 4.0, 5.0]);
const arrayPointer = instance._malloc(doubleArray.length * doubleArray.BYTES_PER_ELEMENT);
instance.HEAPF64.set(doubleArray, arrayPointer / doubleArray.BYTES_PER_ELEMENT);
instance._exampleFunction(arrayPointer);
instance._free(arrayPointer);
});
On the C++ side:
extern "C" {
EMSCRIPTEN_KEEPALIVE
void exampleFunction(double* elems) {
// [your code here]
}
}