Skip to content

Commit

Permalink
WASM progress point
Browse files Browse the repository at this point in the history
  • Loading branch information
TooTallNate committed Sep 23, 2023
1 parent ef8dcf1 commit 3e79c21
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 83 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"fs.h": "c",
"canvas.h": "c",
"font.h": "c",
"image.h": "c"
"image.h": "c",
"wasm3.h": "c"
},
"C_Cpp.default.compilerPath": "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc"
}
40 changes: 29 additions & 11 deletions apps/wasm/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
const importObject = {
imports: {
imported_func(arg: number) {
console.log(arg);
},
},
};

// `simple.wasm` exports a function named `exported_func()`,
// which invokes the imported function `imported_func()` with
// a single parameter containing the value 42.
// https://github.com/mdn/webassembly-examples/blob/main/js-api-examples/simple.wat
const wasm = Switch.readFileSync(new URL('simple.wasm', Switch.entrypoint));
WebAssembly.instantiate(wasm, importObject).then((results) => {
results.instance.exports.exported_func();
});
//const wasm = require('fs').readFileSync(__dirname + '/../romfs/simple.wasm');

const mod = new WebAssembly.Module(wasm);
console.log(WebAssembly.Module.exports(mod));
console.log(WebAssembly.Module.imports(mod));
//const importObject = {
// imports: {
// imported_func(arg /* @type any */) {
// console.log({ arg });
// },
// },
//};
//
//WebAssembly.instantiate(wasm, importObject)
// .then((results) => {
// console.log(WebAssembly.Module.exports(results.module));
// console.log(WebAssembly.Module.imports(results.module));
// //console.log(results.instance.exports.add);
// //console.log(results.instance.exports.add(1, 5));
// if (typeof results.instance.exports.exported_func === 'function') {
// console.log(results.instance.exports.exported_func());
// } else {
// throw new Error(`"exported_func" was not exported from WASM file`);
// }
// });
6 changes: 6 additions & 0 deletions packages/runtime/src/switch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type CanvasRenderingContext2DState =
Opaque<'CanvasRenderingContext2DState'>;
export type FontFaceState = Opaque<'FontFaceState'>;
export type ImageOpaque = Opaque<'ImageOpaque'>;
export type WasmModuleOpaque = Opaque<'WasmModuleOpaque'>;

export interface Vibration {
duration: number;
Expand Down Expand Up @@ -305,6 +306,11 @@ export interface Native {
connect(cb: Callback<number>, ip: string, port: number): void;
write(cb: Callback<number>, fd: number, data: ArrayBuffer): void;
read(cb: Callback<number>, fd: number, buffer: ArrayBuffer): void;

// wasm
wasmNewModule(b: ArrayBuffer): WasmModuleOpaque;
wasmModuleExports(m: WasmModuleOpaque): any[];
wasmModuleImports(m: WasmModuleOpaque): any[];
}

interface Internal {
Expand Down
94 changes: 69 additions & 25 deletions packages/runtime/src/wasm.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { SwitchClass } from './switch';
import type { SwitchClass, WasmModuleOpaque } from './switch';
import { bufferSourceToArrayBuffer } from './utils';

declare const Switch: SwitchClass;

Expand Down Expand Up @@ -54,27 +55,36 @@ export type Imports = Record<string, ModuleImports>;
export type ModuleImports = Record<string, ImportValue>;
export type ValueType = keyof ValueTypeMap;

export class CompileError extends Error implements WebAssembly.CompileError {}
export class RuntimeError extends Error implements WebAssembly.RuntimeError {}
export class LinkError extends Error implements WebAssembly.LinkError {}
export class CompileError extends Error implements WebAssembly.CompileError {
name = 'CompileError';
}
export class RuntimeError extends Error implements WebAssembly.RuntimeError {
name = 'RuntimeError';
}
export class LinkError extends Error implements WebAssembly.LinkError {
name = 'LinkError';
}

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Global) */
export class Global<T extends ValueType = ValueType>
implements WebAssembly.Global
{
value: any;
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Global/value) */
value: ValueTypeMap[T];

constructor(descriptor: GlobalDescriptor<T>, v?: ValueTypeMap[T]) {
throw new Error('Method not implemented.');
}

valueOf() {
throw new Error('Method not implemented.');
return this.value;
}
}

export class Instance implements WebAssembly.Instance {
exports: Exports;
constructor() {
readonly exports: Exports;

constructor(module: Module, importObject?: Imports) {
this.exports = {};
}
}
Expand All @@ -96,9 +106,21 @@ export class Memory implements WebAssembly.Memory {
}
}

interface ModuleInternals {
buffer: ArrayBuffer;
opaque: WasmModuleOpaque;
}

const moduleInternalsMap = new WeakMap<Module, ModuleInternals>();

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module) */
export class Module implements WebAssembly.Module {
constructor(bytes: BufferSource) {
throw new Error('Method not implemented.');
const buffer = bufferSourceToArrayBuffer(bytes);
moduleInternalsMap.set(this, {
buffer,
opaque: Switch.native.wasmNewModule(buffer),
});
}

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module/customSections) */
Expand All @@ -111,12 +133,16 @@ export class Module implements WebAssembly.Module {

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module/exports) */
static exports(moduleObject: Module): ModuleExportDescriptor[] {
throw new Error('Method not implemented.');
const i = moduleInternalsMap.get(moduleObject);
if (!i) throw new Error(`No internal state for Module`);
return Switch.native.wasmModuleExports(i.opaque);
}

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module/imports) */
static imports(moduleObject: Module): ModuleImportDescriptor[] {
throw new Error('Method not implemented.');
const i = moduleInternalsMap.get(moduleObject);
if (!i) throw new Error(`No internal state for Module`);
return Switch.native.wasmModuleImports(i.opaque);
}
}

Expand Down Expand Up @@ -149,14 +175,19 @@ 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> {
const buffer =
bytes instanceof ArrayBuffer
? bytes
: bytes.buffer.slice(
bytes.byteOffset,
bytes.byteOffset + bytes.byteLength
);
return new Module(buffer);
return new Module(bytes);
}

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/compileStreaming) */
export async function compileStreaming(
source: Response | PromiseLike<Response>
): Promise<Module> {
const res = await source;
if (!res.ok) {
// TODO: throw error?
}
const buf = await res.arrayBuffer();
return compile(buf);
}

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate) */
Expand All @@ -173,11 +204,24 @@ export async function instantiate(
importObject?: Imports
) {
if (bytes instanceof Module) {
return new Instance();
return new Instance(bytes, importObject);
}
const module = await compile(bytes);
return {
instance: new Instance(),
module,
};
const m = await compile(bytes);
const instance = new Instance(m, importObject);
return { module: m, instance };
}

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming) */
export async function instantiateStreaming(
source: Response | PromiseLike<Response>,
importObject?: Imports
): Promise<WebAssemblyInstantiatedSource> {
const m = await compileStreaming(source);
const instance = await instantiate(m, importObject);
return { module: m, instance };
}

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/validate) */
export function validate(bytes: BufferSource): boolean {
throw new Error('Method not implemented.');
}
3 changes: 1 addition & 2 deletions source/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,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);

JSValue exit_func = JS_NewCFunction(ctx, js_exit, "exit", 0);
JS_SetPropertyStr(ctx, switch_obj, "exit", exit_func);
Expand Down Expand Up @@ -527,8 +528,6 @@ int main(int argc, char *argv[])
JS_CFUNC_DEF("resolveDns", 0, js_dns_resolve)};
JS_SetPropertyFunctionList(ctx, native_obj, function_list, countof(function_list));

js_wasm_init(ctx, native_obj);

// `Switch.entrypoint`
JS_SetPropertyStr(ctx, switch_obj, "entrypoint", JS_NewString(ctx, js_path));

Expand Down
Loading

0 comments on commit 3e79c21

Please sign in to comment.