-
Notifications
You must be signed in to change notification settings - Fork 745
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exposing GC in binaryen.js APIs #5921
Comments
No reason to hold off at this time: the GC spec is now very stable, as is Binaryen's implementation of it. So missing parts of the JS API are just that no one has gotten around to them yet, but it would be great to fill those out! |
@kripken Roger that. I discovered I can access them via the binaryen namespace directly e.g. |
@jayphelps I'm facing the exact same situation, but struggling to retrieve a usable type built using TypeBuilder. |
@ericvergnaud Because the APIs are not yet exposed/wrapped in the clean JS API you have to do things a bit more manually, like allocating/deallocating space in binaryen's memory space for arguments. Here's an example, though it may have mistakes: (anyone is free to correct my mistakes, especially use-after-frees) function allocU32Array(u32s: number[]): number {
const { length } = u32s;
const ptr = binaryen._malloc(length << 2);
let offset = ptr;
for (let i = 0; i < length; i++) {
const value = u32s[i];
binaryen.__i32_store(offset, value);
offset += 4;
}
return ptr;
}
const tempStructIndex = 0;
const typeBuilder = binaryen._TypeBuilderCreate(1);
// I always use temps so that I can potentially create recursive types.
const tempStructHeapType = binaryen._TypeBuilderGetTempHeapType(typeBuilder, tempStructIndex);
const fieldTypes = [binaryen.i32];
const cFieldTypes = allocU32Array(fieldTypes);
const cFieldPackedTypes = allocU32Array(fieldTypes.map(() => binaryen._BinaryenPackedTypeNotPacked()));
const cFieldMutables = allocU32Array(fieldTypes.map(() => 0));
binaryen._TypeBuilderSetStructType(
typeBuilder,
tempStructIndex,
cFieldTypes,
cFieldPackedTypes,
cFieldMutables,
fieldTypes.length
);
binaryen._free(cFieldTypes);
binaryen._free(cFieldPackedTypes);
binaryen._free(cFieldMutables);
const size = binaryen._TypeBuilderGetSize(typeBuilder);
const out = binaryen._malloc(Math.max(4 * size, 8));
if (!binaryen._TypeBuilderBuildAndDispose(typeBuilder, out, out, out + 4)) {
binaryen._free(out);
throw new Error('_TypeBuilderBuildAndDispose failed');
}
// const structHeapType = binaryen.__i32_load(out + 4 * tempStructIndex);
// const structBinaryenType = binaryen._BinaryenTypeFromHeapType(structHeapType, false);
// const signatureHeapType = binaryen.__i32_load(out + 4 * tempSignatureIndex);
binaryen._free(out);
const structNewArgs = allocU32Array([this.module.i32.const(1337)]);
const structNew = binaryen._BinaryenStructNew(this.module, structNewArgs, 1, tempStructHeapType);
binaryen._free(structNewArgs);
module.addFunction(
'_start',
binaryen.createType([]),
binaryen.i32,
[],
binaryen._BinaryenStructGet(this.module, 0, structNew, binaryen.i32, false)
);
module.addFunctionExport('_start', '_start'); I used AssemblyScript as a loose reference when I got stuck e.g. https://github.com/AssemblyScript/assemblyscript/blob/1e0466ef94fa5cacd0984e4f31a0087de51538a8/src/module.ts#L3689 I'm still unclear on when it's safe to free things, whether you have to free temp structs, etc. In some cases I'm just letting memory leak to be safe, since the compiler is short lived. |
@jayphelps Thanks for this. I thought I was missing something simple, the above makes sense when compared to c-api-kitchen-sink.c, but I didn't want to move that complexity up to the binaryen client.. |
@jayphelps see #6175 |
I am actually not certain whether #6192 and #6225 have a dependency between them (if there is, then the latter needs to be figured out first). @ericvergnaud ? |
@ericvergnaud thanks for the link! Yeah hopefully #6225 is resolved soon to allow #6192 to move forward. @kripken the example from @jayphelps above is forced to use heap |
@samestep Yes, opening small reasonable intermediate PRs for now sounds fine. And I don't see a problem with exposing those stack APIs specifically in the long term (in a project the size of Binaryen, doing so has very small cost). |
I have a compiler written in TypeScript to aid in potential community maintainability that uses binaryen.js. It's going to rely on the GC instructions, but since historically they were still very in flux I had implemented things using a simple bump allocator instead while I wait for stability. Now that the GC proposal is in implementation phase I wanted to try and adopt it. I was happy to find that it seems like Binaryen has good support for them, but it isn't yet fully exposed via the JS API. Is that just a matter of no one seemingly needing it yet, or did you all want to hold off still?
The text was updated successfully, but these errors were encountered: