Skip to content

Commit

Permalink
Handle WebAssembly.Memory buffer growing
Browse files Browse the repository at this point in the history
  • Loading branch information
TooTallNate committed Oct 7, 2023
1 parent 11288bf commit b950962
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 57 deletions.
5 changes: 5 additions & 0 deletions .changeset/fair-eyes-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'nxjs-runtime': patch
---

Handle `WebAssembly.Memory` buffer growing
39 changes: 19 additions & 20 deletions packages/runtime/src/wasm.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { $ } from './$';
import { bufferSourceToArrayBuffer } from './utils';
import type {
SwitchClass,
Expand Down Expand Up @@ -145,8 +146,11 @@ function unwrapImports(importObject: Imports = {}) {
kind = 'global';
i = v.value;
val = bindGlobal(v);
} else if (v instanceof Memory) {
kind = 'memory';
val = v;
} else {
// TODO: Handle "memory" / "table" types
// TODO: Handle "table" type
throw new Error(`Unsupported import type`);
}
return {
Expand All @@ -170,9 +174,8 @@ function wrapExports(op: WasmInstanceOpaque, ex: any[]): Exports {
bindGlobal(g, v.val);
e[v.name] = g;
} else if (v.kind === 'memory') {
const m = Object.create(Memory.prototype);
m.buffer = v.val;
e[v.name] = m;
Object.setPrototypeOf(v.val, Memory.prototype);
e[v.name] = v.val;
}
}
return Object.freeze(e);
Expand Down Expand Up @@ -214,34 +217,25 @@ function callFunc(
}
}

const BYTES_PER_PAGE = 65536;

interface MemoryInternals {
descriptor: MemoryDescriptor;
}

const memoryInternalsMap = new WeakMap<Memory, MemoryInternals>();

/**
* [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory)
*/
export class Memory implements WebAssembly.Memory {
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/buffer) */
readonly buffer: ArrayBuffer;

constructor(descriptor: MemoryDescriptor) {
const bytes = descriptor.initial * BYTES_PER_PAGE;
this.buffer = descriptor.shared
? new SharedArrayBuffer(bytes)
: new ArrayBuffer(bytes);
memoryInternalsMap.set(this, { descriptor });
const that = $.wasmMemNew(descriptor);
Object.setPrototypeOf(that, Memory.prototype);
return that;
}

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/buffer) */
declare readonly buffer: ArrayBuffer;

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/grow) */
grow(delta: number): number {
throw new Error('Method not implemented.');
}
}
$.wasmMemProto(Memory);

interface ModuleInternals {
buffer: ArrayBuffer;
Expand Down Expand Up @@ -313,6 +307,7 @@ export class Table implements WebAssembly.Table {
* [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/compile)
*/
export async function compile(bytes: BufferSource): Promise<Module> {
// TODO: run this on the thread pool?
return new Module(bytes);
}

Expand Down Expand Up @@ -345,7 +340,11 @@ export async function instantiate(
return new Instance(bytes, importObject);
}
const m = await compile(bytes);

// TODO: run this on the thread pool?
// maybe not, because we need to interact with JS here?
const instance = new Instance(m, importObject);

return { module: m, instance };
}

Expand Down
18 changes: 12 additions & 6 deletions source/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,12 @@ int main(int argc, char *argv[])
pthread_mutex_init(&(nx_ctx->async_done_mutex), NULL);
JS_SetContextOpaque(ctx, nx_ctx);

/* The internal `$` object contains native functions that are wrapped in the JS runtime */
JSValue global_obj = JS_GetGlobalObject(ctx);
JSValue init_obj = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, global_obj, "$", init_obj);
nx_init_wasm(ctx, init_obj);

// First try the `main.js` file on the RomFS
size_t user_code_size;
int js_path_needs_free = 0;
Expand Down Expand Up @@ -499,10 +505,9 @@ int main(int argc, char *argv[])
goto wait_error;
}

JSValue global_obj = JS_GetGlobalObject(ctx);
JSValue switch_obj = JS_GetPropertyStr(ctx, global_obj, "Switch");
JSValue native_obj = JS_GetPropertyStr(ctx, switch_obj, "native");
JSValue switch_dispatch_func = JS_GetPropertyStr(ctx, switch_obj, "dispatchEvent");
JSValue dispatch_event_func = JS_GetPropertyStr(ctx, switch_obj, "dispatchEvent");

JSValue version_obj = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, version_obj, "cairo", JS_NewString(ctx, cairo_version_string()));
Expand All @@ -525,7 +530,7 @@ int main(int argc, char *argv[])
nx_init_fs(ctx, native_obj);
nx_init_image(ctx, native_obj);
nx_init_tcp(ctx, native_obj);
nx_init_wasm(ctx, native_obj);
nx_init_wasm_(ctx, native_obj);

JS_SetPropertyStr(ctx, switch_obj, "exit", JS_NewCFunction(ctx, js_exit, "exit", 0));

Expand Down Expand Up @@ -610,7 +615,7 @@ int main(int argc, char *argv[])
JS_SetPropertyStr(ctx, event_obj, "type", JS_NewString(ctx, "frame"));
JS_SetPropertyStr(ctx, event_obj, "detail", JS_NewUint32(ctx, kDown));
JSValueConst args[] = {event_obj};
JSValue ret_val = JS_Call(ctx, switch_dispatch_func, switch_obj, 1, args);
JSValue ret_val = JS_Call(ctx, dispatch_event_func, switch_obj, 1, args);
JS_FreeValue(ctx, event_obj);

if (!is_running)
Expand Down Expand Up @@ -651,7 +656,7 @@ int main(int argc, char *argv[])
JSValue event_type = JS_NewString(ctx, "exit");
JS_SetPropertyStr(ctx, event_obj, "type", event_type);
JSValue args[] = {event_obj};
JSValue ret_val = JS_Call(ctx, switch_dispatch_func, switch_obj, 1, args);
JSValue ret_val = JS_Call(ctx, dispatch_event_func, switch_obj, 1, args);
JS_FreeValue(ctx, event_obj);
JS_FreeValue(ctx, ret_val);

Expand All @@ -673,9 +678,10 @@ int main(int argc, char *argv[])

FILE *leaks_fd = freopen("leaks.txt", "w", stdout);

JS_FreeValue(ctx, switch_dispatch_func);
JS_FreeValue(ctx, dispatch_event_func);
JS_FreeValue(ctx, native_obj);
JS_FreeValue(ctx, switch_obj);
JS_FreeValue(ctx, init_obj);
JS_FreeValue(ctx, global_obj);

JS_FreeContext(ctx);
Expand Down
Loading

0 comments on commit b950962

Please sign in to comment.