Skip to content

Commit

Permalink
Avoid returning a promise from run if possible.
Browse files Browse the repository at this point in the history
This commit switches JCO instantiation type to sync (which is a breaking
change), and ensures that `run` only returns a promise if it has to
download resources.
  • Loading branch information
whitequark committed Feb 13, 2024
1 parent f1ffbe3 commit dc432bc
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 22 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
YoWASP JavaScript runtime
=========================

This package is an internal support package for the [YoWASP project][yowasp]. It handles interfacing with the [WebAssembly][] runtime and the supported execution environments (Node.js and the browser). Do not depend on this package in your own code.
This package is an internal support package for the [YoWASP project][yowasp]. It handles interfacing with the [WebAssembly][] runtime and the supported execution environments (Node.js and the browser). If you are writing code that is not part of the YoWASP project, you should only use functions from the `@yowasp/runtime/util` module.

[webassembly]: https://webassembly.org/
[yowasp]: https://yowasp.github.io/
Expand All @@ -10,7 +10,7 @@ This package is an internal support package for the [YoWASP project][yowasp]. It
Application API reference
-------------------------

All of the other JavaScript YoWASP packages re-export the API of the package. They export the function `runX` where `X` is the name of the application, which can be called as:
All of the other JavaScript YoWASP packages use the common runtime functionality implemented here. They export the function `runX` where `X` is the name of the application, which can be called as:

```js
const filesOut = await runX(args, filesIn, { stdout, stderr, decodeASCII: true });
Expand All @@ -29,6 +29,8 @@ If the application returns a non-zero exit code, the exception `Exit` (exported
- The `code` property indicates the exit code. (Currently this is always 1 due to WebAssembly peculiarities.)
- The `files` property represents the state of the virtual filesystem after the application terminated. This property can be used to retrieve log files or other data aiding in diagnosing the error.

While in general the `runX` function returns a promise, there are two special cases. Calling `runX()` (with no arguments) does not run the application, but preloads and caches, in memory, all of the necessary resources. Calling `runX([...])` (with arguments) after that executes the application synchronously instead of returning a promise.

[Uint8Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array


Expand Down
24 changes: 15 additions & 9 deletions lib/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@ export type Tree = {
export type OutputStream =
(bytes: Uint8Array | null) => void;

export class Exit extends Error {
code: number;
files: Tree;
}
export type RunOptions = {
stdout?: OutputStream | null,
stderr?: OutputStream | null,
decodeASCII?: boolean
};

export class Application {
constructor(resources: () => Promise<any>, instantiate: any, argv0: string);

run(args?: string[], files?: Tree, options?: {
stdout?: OutputStream | null,
stderr?: OutputStream | null,
decodeASCII?: boolean
}): Promise<Tree>;
preload(): Promise;

execute(args: string[], files?: Tree, options?: RunOptions): Tree;

run(args?: string[], files?: Tree, options?: RunOptions): Tree | Promise<Tree> | undefined;
}

export class Exit extends Error {
code: number;
files: Tree;
}
25 changes: 18 additions & 7 deletions lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,13 @@ export class Application {
this.argv0 = argv0;
}

// The `printLine` option is deprecated and not documented but still accepted for compatibility.
async run(args = null, files = {}, { stdout, stderr, decodeASCII = true, printLine } = {}) {
async preload() {
if (this.resourceData === null)
this.resourceData = await this.resources().then(fetchResources);
}

if (args === null)
return; // prefetch resources, but do not run

// The `printLine` option is deprecated and not documented but still accepted for compatibility.
execute(args, files = {}, { stdout, stderr, decodeASCII = true, printLine } = {}) {
const environment = new Environment();
environment.args = [this.argv0].concat(args);
environment.root = directoryFromTree(files);
Expand All @@ -64,9 +63,11 @@ export class Application {
environment.stdout = stdout === undefined ? lineBufferedConsole : stdout;
environment.stderr = stderr === undefined ? lineBufferedConsole : stderr;

const wasmCommand = await this.instantiate(
const wasmCommand = this.instantiate(
(filename) => this.resourceData.modules[filename],
{ runtime: environment.exports });
{ runtime: environment.exports },
// workaround for bytecodealliance/jco#374
(module, imports) => new WebAssembly.Instance(module, imports));
let error = null;
try {
wasmCommand.run.run();
Expand All @@ -87,4 +88,14 @@ export class Application {
return files;
}
}

run(args = null, files = {}, options = {}) {
if (this.resourceData === null)
return this.preload().then(_ => this.run(args, files, options));

if (args === null)
return; // prefetch resources, but do not actually run

return this.execute(args, files, options);
}
}
2 changes: 1 addition & 1 deletion package-in.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yowasp/runtime",
"version": "7.0",
"version": "8.0",
"description": "Common runtime for YoWASP packages",
"author": "Catherine <whitequark@whitequark.org>",
"license": "ISC",
Expand Down
7 changes: 6 additions & 1 deletion test/yowasp_runtime_test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,9 @@ if (files6['sp.txt'] !== '\r\n\t')

let files7 = await yowaspRuntimeTest.run([]);
if (typeof files7['share'] !== 'undefined')
throw 'test 7';
throw 'test 7';

await yowaspRuntimeTest.preload();

if ((yowaspRuntimeTest.execute(['share/foo.txt', 'foo.txt'], {}))['foo.txt'] !== 'contents of foo')
throw 'test 8 failed';
4 changes: 2 additions & 2 deletions test/yowasp_runtime_test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
"@yowasp/runtime": "file:../../"
},
"devDependencies": {
"@bytecodealliance/jco": "0.14.2"
"@bytecodealliance/jco": "1.0.0"
},
"scripts": {
"pack": "yowasp-pack-resources gen/resources.js gen share",
"transpile": "jco new ../copy.wasm --wasi-command --output copy.wasm && jco transpile copy.wasm --instantiation async --no-typescript --no-namespaced-exports --map 'wasi:io/*=runtime#io' --map 'wasi:cli/*=runtime#cli' --map 'wasi:clocks/*=runtime#*' --map 'wasi:filesystem/*=runtime#fs' --out-dir gen/",
"transpile": "jco new ../copy.wasm --wasi-command --output copy.wasm && jco transpile copy.wasm --instantiation sync --no-typescript --no-namespaced-exports --map 'wasi:io/*=runtime#io' --map 'wasi:cli/*=runtime#cli' --map 'wasi:clocks/*=runtime#*' --map 'wasi:filesystem/*=runtime#fs' --out-dir gen/",
"build": "./build.sh",
"test": "node ./index.js"
}
Expand Down

0 comments on commit dc432bc

Please sign in to comment.