Skip to content

Commit

Permalink
WASM checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
TooTallNate committed Sep 18, 2023
1 parent 279d538 commit 6915756
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 25 deletions.
3 changes: 3 additions & 0 deletions apps/wasm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/*.nro
/node_modules
/romfs/main.js
1 change: 0 additions & 1 deletion apps/wasm/nxjs.env.d.ts

This file was deleted.

10 changes: 6 additions & 4 deletions apps/wasm/package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
{
"name": "nxjs-example-wasm",
"name": "wasm",
"version": "0.0.0",
"private": true,
"description": "nx.js example that loads a WASM binary",
"description": "nx.js app that loads a WASM binary",
"scripts": {
"build": "esbuild --bundle --target=es2020 src/main.ts --outfile=dist/main.js"
"build": "esbuild --bundle --target=es2020 src/main.ts --outfile=romfs/main.js",
"nro": "nxjs-pack"
},
"license": "MIT",
"devDependencies": {
"esbuild": "^0.17.19",
"nxjs-runtime": "^0.0.17"
"nxjs-pack": "workspace:^",
"nxjs-runtime": "workspace:^"
}
}
File renamed without changes.
2 changes: 1 addition & 1 deletion apps/wasm/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const importObject = {
},
};

const wasm = Switch.readFileSync('simple.wasm');
const wasm = Switch.readFileSync(new URL('simple.wasm', Switch.entrypoint));
WebAssembly.instantiate(wasm, importObject).then((results) => {
results.instance.exports.exported_func();
});
14 changes: 8 additions & 6 deletions apps/wasm/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
{
"compilerOptions": {
"target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"target": "es2020",
"moduleResolution": "node",
"noEmit": true, /* `esbuild` is used for bundling. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
"strict": true, /* Enable all strict type-checking options. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"types": [
"nxjs-runtime"
]
},
"include": [
"nxjs.env.d.ts",
"src/**/*.ts"
]
}
12 changes: 12 additions & 0 deletions packages/runtime/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,16 @@ output = output.replace(/\bHTMLCanvasElement\b/g, 'Canvas');
// hurt, but also isn't necessary. Clean that up.
output = output.trim().split('\n').slice(0, -1).join('\n');

let [output2] = generateDtsBundle(
[
{
filePath: './src/wasm.ts',
},
],
{
noBanner: true,
}
);
console.log({ output2 });

fs.writeFileSync(new URL('index.d.ts', distDir), output);
4 changes: 4 additions & 0 deletions packages/runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export type {
clearTimeout,
clearInterval,
} from './timers';
export type * as WebAssembly from './wasm';

/**
* The `Switch` global object contains native interfaces to interact with the Switch hardware.
Expand All @@ -72,6 +73,9 @@ def('setInterval', setInterval);
def('clearTimeout', clearTimeout);
def('clearInterval', clearInterval);

import * as WebAssembly from './wasm';
def('WebAssembly', WebAssembly);

function touchIsEqual(a: Touch, b: Touch) {
return (
a.screenX === b.screenX &&
Expand Down
153 changes: 140 additions & 13 deletions packages/runtime/src/wasm.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,177 @@
import type { Switch as _Switch } from './switch';
declare const Switch: _Switch;
import type { SwitchClass } from './switch';
import type { BufferSource } from './types';

declare const Switch: SwitchClass;

export interface GlobalDescriptor<T extends ValueType = ValueType> {
mutable?: boolean;
value: T;
}

export interface MemoryDescriptor {
initial: number;
maximum?: number;
shared?: boolean;
}

export interface ModuleExportDescriptor {
kind: ImportExportKind;
name: string;
}

export interface ModuleImportDescriptor {
kind: ImportExportKind;
module: string;
name: string;
}

export interface TableDescriptor {
element: TableKind;
initial: number;
maximum?: number;
}

export interface ValueTypeMap {
anyfunc: Function;
externref: any;
f32: number;
f64: number;
i32: number;
i64: bigint;
v128: never;
}

export interface WebAssemblyInstantiatedSource {
instance: Instance;
module: Module;
}

export type ImportExportKind = 'function' | 'global' | 'memory' | 'table';
export type TableKind = 'anyfunc' | 'externref';
export type ExportValue = Function | Global | Memory | Table;
export type Exports = Record<string, ExportValue>;
export type ImportValue = ExportValue | number;
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 Global<T extends ValueType = ValueType>
implements WebAssembly.Global
{
value: any;

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

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

export class Instance implements WebAssembly.Instance {
exports: WebAssembly.Exports;
exports: Exports;
constructor() {
this.exports = {};
}
}

/**
* [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) {
throw new Error('Method not implemented.');
}

/** [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.');
}
}

export class Module implements WebAssembly.Module {
constructor(bytes: BufferSource) {
throw new Error('Method not implemented.');
}

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module/customSections) */
static customSections(
moduleObject: Module,
sectionName: string
): ArrayBuffer[] {
throw new Error('Method not implemented.');
}
static exports(moduleObject: Module): WebAssembly.ModuleExportDescriptor[] {

/** [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.');
}

/** [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.');
}
}

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

constructor(descriptor: TableDescriptor, value?: any) {
throw new Error('Method not implemented.');
}
static imports(moduleObject: Module): WebAssembly.ModuleImportDescriptor[] {

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/get) */
get(index: number) {
throw new Error('Method not implemented.');
}

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

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/set) */
set(index: number, value?: any): void {
throw new Error('Method not implemented.');
}
}

export const compile: (typeof WebAssembly)['compile'] = async (bytes) => {
/**
* [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();
};
return new Module(buffer);
}

/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate) */
export function instantiate(
bytes: BufferSource,
importObject?: WebAssembly.Imports
): Promise<WebAssembly.WebAssemblyInstantiatedSource>;
importObject?: Imports
): Promise<WebAssemblyInstantiatedSource>;
export function instantiate(
moduleObject: Module,
importObject?: WebAssembly.Imports
): Promise<WebAssembly.Instance>;
importObject?: Imports
): Promise<Instance>;
export async function instantiate(
bytes: BufferSource | Module,
importObject?: WebAssembly.Imports
importObject?: Imports
) {
if (bytes instanceof Module) {
return new Instance();
Expand Down

0 comments on commit 6915756

Please sign in to comment.