@bytecodealliance/jco
Version:
JavaScript tooling for working with WebAssembly Components
1,795 lines (1,644 loc) • 157 kB
JavaScript
import { environment, exit as exit$1, stderr, stdin, stdout, terminalInput, terminalOutput, terminalStderr, terminalStdin, terminalStdout } from '@bytecodealliance/preview2-shim/cli';
import { preopens, types } from '@bytecodealliance/preview2-shim/filesystem';
import { error, streams } from '@bytecodealliance/preview2-shim/io';
import { random } from '@bytecodealliance/preview2-shim/random';
const { getEnvironment } = environment;
const { exit } = exit$1;
const { getStderr } = stderr;
const { getStdin } = stdin;
const { getStdout } = stdout;
const { TerminalInput } = terminalInput;
const { TerminalOutput } = terminalOutput;
const { getTerminalStderr } = terminalStderr;
const { getTerminalStdin } = terminalStdin;
const { getTerminalStdout } = terminalStdout;
const { getDirectories } = preopens;
const { Descriptor,
DirectoryEntryStream,
filesystemErrorCode } = types;
const { Error: Error$1 } = error;
const { InputStream,
OutputStream } = streams;
const { getRandomBytes } = random;
let dv = new DataView(new ArrayBuffer());
const dataView = mem => dv.buffer === mem.buffer ? dv : dv = new DataView(mem.buffer);
const toUint64 = val => BigInt.asUintN(64, BigInt(val));
function toUint32(val) {
return val >>> 0;
}
const utf8Decoder = new TextDecoder();
const utf8Encoder = new TextEncoder();
let utf8EncodedLen = 0;
function utf8Encode(s, realloc, memory) {
if (typeof s !== 'string') throw new TypeError('expected a string');
if (s.length === 0) {
utf8EncodedLen = 0;
return 1;
}
let buf = utf8Encoder.encode(s);
let ptr = realloc(0, 0, 1, buf.length);
new Uint8Array(memory.buffer).set(buf, ptr);
utf8EncodedLen = buf.length;
return ptr;
}
const T_FLAG = 1 << 30;
function rscTableCreateOwn (table, rep) {
const free = table[0] & ~T_FLAG;
if (free === 0) {
table.push(0);
table.push(rep | T_FLAG);
return (table.length >> 1) - 1;
}
table[0] = table[free << 1];
table[free << 1] = 0;
table[(free << 1) + 1] = rep | T_FLAG;
return free;
}
function rscTableRemove (table, handle) {
const scope = table[handle << 1];
const val = table[(handle << 1) + 1];
const own = (val & T_FLAG) !== 0;
const rep = val & ~T_FLAG;
if (val === 0 || (scope & T_FLAG) !== 0) throw new TypeError('Invalid handle');
table[handle << 1] = table[0] | T_FLAG;
table[0] = handle | T_FLAG;
return { rep, scope, own };
}
let curResourceBorrows = [];
let NEXT_TASK_ID = 0n;
function startCurrentTask(componentIdx, isAsync, entryFnName) {
_debugLog('[startCurrentTask()] args', { componentIdx, isAsync });
if (componentIdx === undefined || componentIdx === null) {
throw new Error('missing/invalid component instance index while starting task');
}
const tasks = ASYNC_TASKS_BY_COMPONENT_IDX.get(componentIdx);
const nextId = ++NEXT_TASK_ID;
const newTask = new AsyncTask({ id: nextId, componentIdx, isAsync, entryFnName });
const newTaskMeta = { id: nextId, componentIdx, task: newTask };
ASYNC_CURRENT_TASK_IDS.push(nextId);
ASYNC_CURRENT_COMPONENT_IDXS.push(componentIdx);
if (!tasks) {
ASYNC_TASKS_BY_COMPONENT_IDX.set(componentIdx, [newTaskMeta]);
return nextId;
} else {
tasks.push(newTaskMeta);
}
return nextId;
}
function endCurrentTask(componentIdx, taskId) {
_debugLog('[endCurrentTask()] args', { componentIdx });
componentIdx ??= ASYNC_CURRENT_COMPONENT_IDXS.at(-1);
taskId ??= ASYNC_CURRENT_TASK_IDS.at(-1);
if (componentIdx === undefined || componentIdx === null) {
throw new Error('missing/invalid component instance index while ending current task');
}
const tasks = ASYNC_TASKS_BY_COMPONENT_IDX.get(componentIdx);
if (!tasks || !Array.isArray(tasks)) {
throw new Error('missing/invalid tasks for component instance while ending task');
}
if (tasks.length == 0) {
throw new Error('no current task(s) for component instance while ending task');
}
if (taskId) {
const last = tasks[tasks.length - 1];
if (last.id !== taskId) {
throw new Error('current task does not match expected task ID');
}
}
ASYNC_CURRENT_TASK_IDS.pop();
ASYNC_CURRENT_COMPONENT_IDXS.pop();
return tasks.pop();
}
const ASYNC_TASKS_BY_COMPONENT_IDX = new Map();
let ASYNC_CURRENT_TASK_IDS = [];
let ASYNC_CURRENT_COMPONENT_IDXS = [];
class AsyncTask {
static State = {
INITIAL: 'initial',
CANCELLED: 'cancelled',
CANCEL_PENDING: 'cancel-pending',
CANCEL_DELIVERED: 'cancel-delivered',
RESOLVED: 'resolved',
}
static BlockResult = {
CANCELLED: 'block.cancelled',
NOT_CANCELLED: 'block.not-cancelled',
}
#id;
#componentIdx;
#state;
#isAsync;
#onResolve = null;
#returnedResults = null;
#entryFnName = null;
cancelled = false;
requested = false;
alwaysTaskReturn = false;
returnCalls = 0;
storage = [0, 0];
borrowedHandles = {};
awaitableResume = null;
awaitableCancel = null;
constructor(opts) {
if (opts?.id === undefined) { throw new TypeError('missing task ID during task creation'); }
this.#id = opts.id;
if (opts?.componentIdx === undefined) {
throw new TypeError('missing component id during task creation');
}
this.#componentIdx = opts.componentIdx;
this.#state = AsyncTask.State.INITIAL;
this.#isAsync = opts?.isAsync ?? false;
this.#entryFnName = opts.entryFnName;
this.#onResolve = (results) => {
this.#returnedResults = results;
}
}
taskState() { return this.#state.slice(); }
id() { return this.#id; }
componentIdx() { return this.#componentIdx; }
isAsync() { return this.#isAsync; }
getEntryFnName() { return this.#entryFnName; }
takeResults() {
const results = this.#returnedResults;
this.#returnedResults = null;
return results;
}
mayEnter(task) {
const cstate = getOrCreateAsyncState(this.#componentIdx);
if (!cstate.backpressure) {
_debugLog('[AsyncTask#mayEnter()] disallowed due to backpressure', { taskID: this.#id });
return false;
}
if (!cstate.callingSyncImport()) {
_debugLog('[AsyncTask#mayEnter()] disallowed due to sync import call', { taskID: this.#id });
return false;
}
const callingSyncExportWithSyncPending = cstate.callingSyncExport && !task.isAsync;
if (!callingSyncExportWithSyncPending) {
_debugLog('[AsyncTask#mayEnter()] disallowed due to sync export w/ sync pending', { taskID: this.#id });
return false;
}
return true;
}
async enter() {
_debugLog('[AsyncTask#enter()] args', { taskID: this.#id });
// TODO: assert scheduler locked
// TODO: trap if on the stack
const cstate = getOrCreateAsyncState(this.#componentIdx);
let mayNotEnter = !this.mayEnter(this);
const componentHasPendingTasks = cstate.pendingTasks > 0;
if (mayNotEnter || componentHasPendingTasks) {
throw new Error('in enter()'); // TODO: remove
cstate.pendingTasks.set(this.#id, new Awaitable(new Promise()));
const blockResult = await this.onBlock(awaitable);
if (blockResult) {
// TODO: find this pending task in the component
const pendingTask = cstate.pendingTasks.get(this.#id);
if (!pendingTask) {
throw new Error('pending task [' + this.#id + '] not found for component instance');
}
cstate.pendingTasks.remove(this.#id);
this.#onResolve([]);
return false;
}
mayNotEnter = !this.mayEnter(this);
if (!mayNotEnter || !cstate.startPendingTask) {
throw new Error('invalid component entrance/pending task resolution');
}
cstate.startPendingTask = false;
}
if (!this.isAsync) { cstate.callingSyncExport = true; }
return true;
}
async waitForEvent(opts) {
const { waitableSetRep, isAsync } = opts;
_debugLog('[AsyncTask#waitForEvent()] args', { taskID: this.#id, waitableSetRep, isAsync });
if (this.#isAsync !== isAsync) {
throw new Error('async waitForEvent called on non-async task');
}
if (this.status === AsyncTask.State.CANCEL_PENDING) {
this.#state = AsyncTask.State.CANCEL_DELIVERED;
return {
code: ASYNC_EVENT_CODE.TASK_CANCELLED,
something: 0,
something: 0,
};
}
const state = getOrCreateAsyncState(this.#componentIdx);
const waitableSet = state.waitableSets.get(waitableSetRep);
if (!waitableSet) { throw new Error('missing/invalid waitable set'); }
waitableSet.numWaiting += 1;
let event = null;
while (event == null) {
const awaitable = new Awaitable(waitableSet.getPendingEvent());
const waited = await this.blockOn({ awaitable, isAsync, isCancellable: true });
if (waited) {
if (this.#state !== AsyncTask.State.INITIAL) {
throw new Error('task should be in initial state found [' + this.#state + ']');
}
this.#state = AsyncTask.State.CANCELLED;
return {
code: ASYNC_EVENT_CODE.TASK_CANCELLED,
something: 0,
something: 0,
};
}
event = waitableSet.poll();
}
waitableSet.numWaiting -= 1;
return event;
}
waitForEventSync(opts) {
throw new Error('AsyncTask#yieldSync() not implemented')
}
async pollForEvent(opts) {
const { waitableSetRep, isAsync } = opts;
_debugLog('[AsyncTask#pollForEvent()] args', { taskID: this.#id, waitableSetRep, isAsync });
if (this.#isAsync !== isAsync) {
throw new Error('async pollForEvent called on non-async task');
}
throw new Error('AsyncTask#pollForEvent() not implemented');
}
pollForEventSync(opts) {
throw new Error('AsyncTask#yieldSync() not implemented')
}
async blockOn(opts) {
const { awaitable, isCancellable, forCallback } = opts;
_debugLog('[AsyncTask#blockOn()] args', { taskID: this.#id, awaitable, isCancellable, forCallback });
if (awaitable.resolved() && !ASYNC_DETERMINISM && _coinFlip()) {
return AsyncTask.BlockResult.NOT_CANCELLED;
}
const cstate = getOrCreateAsyncState(this.#componentIdx);
if (forCallback) { cstate.exclusiveRelease(); }
let cancelled = await this.onBlock(awaitable);
if (cancelled === AsyncTask.BlockResult.CANCELLED && !isCancellable) {
const secondCancel = await this.onBlock(awaitable);
if (secondCancel !== AsyncTask.BlockResult.NOT_CANCELLED) {
throw new Error('uncancellable task was canceled despite second onBlock()');
}
}
if (forCallback) {
const acquired = new Awaitable(cstate.exclusiveLock());
cancelled = await this.onBlock(acquired);
if (cancelled === AsyncTask.BlockResult.CANCELLED) {
const secondCancel = await this.onBlock(acquired);
if (secondCancel !== AsyncTask.BlockResult.NOT_CANCELLED) {
throw new Error('uncancellable callback task was canceled despite second onBlock()');
}
}
}
if (cancelled === AsyncTask.BlockResult.CANCELLED) {
if (this.#state !== AsyncTask.State.INITIAL) {
throw new Error('cancelled task is not at initial state');
}
if (isCancellable) {
this.#state = AsyncTask.State.CANCELLED;
return AsyncTask.BlockResult.CANCELLED;
} else {
this.#state = AsyncTask.State.CANCEL_PENDING;
return AsyncTask.BlockResult.NOT_CANCELLED;
}
}
return AsyncTask.BlockResult.NOT_CANCELLED;
}
async onBlock(awaitable) {
_debugLog('[AsyncTask#onBlock()] args', { taskID: this.#id, awaitable });
if (!(awaitable instanceof Awaitable)) {
throw new Error('invalid awaitable during onBlock');
}
// Build a promise that this task can await on which resolves when it is awoken
const { promise, resolve, reject } = Promise.withResolvers();
this.awaitableResume = () => {
_debugLog('[AsyncTask] resuming after onBlock', { taskID: this.#id });
resolve();
};
this.awaitableCancel = (err) => {
_debugLog('[AsyncTask] rejecting after onBlock', { taskID: this.#id, err });
reject(err);
};
// Park this task/execution to be handled later
const state = getOrCreateAsyncState(this.#componentIdx);
state.parkTaskOnAwaitable({ awaitable, task: this });
try {
await promise;
return AsyncTask.BlockResult.NOT_CANCELLED;
} catch (err) {
// rejection means task cancellation
return AsyncTask.BlockResult.CANCELLED;
}
}
// NOTE: this should likely be moved to a SubTask class
async asyncOnBlock(awaitable) {
_debugLog('[AsyncTask#asyncOnBlock()] args', { taskID: this.#id, awaitable });
if (!(awaitable instanceof Awaitable)) {
throw new Error('invalid awaitable during onBlock');
}
// TODO: watch for waitable AND cancellation
// TODO: if it WAS cancelled:
// - return true
// - only once per subtask
// - do not wait on the scheduler
// - control flow should go to the subtask (only once)
// - Once subtask blocks/resolves, reqlinquishControl() will tehn resolve request_cancel_end (without scheduler lock release)
// - control flow goes back to request_cancel
//
// Subtask cancellation should work similarly to an async import call -- runs sync up until
// the subtask blocks or resolves
//
throw new Error('AsyncTask#asyncOnBlock() not yet implemented');
}
async yield(opts) {
const { isCancellable, forCallback } = opts;
_debugLog('[AsyncTask#yield()] args', { taskID: this.#id, isCancellable, forCallback });
if (isCancellable && this.status === AsyncTask.State.CANCEL_PENDING) {
this.#state = AsyncTask.State.CANCELLED;
return {
code: ASYNC_EVENT_CODE.TASK_CANCELLED,
payload: [0, 0],
};
}
// TODO: Awaitables need to *always* trigger the parking mechanism when they're done...?
// TODO: Component async state should remember which awaitables are done and work to clear tasks waiting
const blockResult = await this.blockOn({
awaitable: new Awaitable(new Promise(resolve => setTimeout(resolve, 0))),
isCancellable,
forCallback,
});
if (blockResult === AsyncTask.BlockResult.CANCELLED) {
if (this.#state !== AsyncTask.State.INITIAL) {
throw new Error('task should be in initial state found [' + this.#state + ']');
}
this.#state = AsyncTask.State.CANCELLED;
return {
code: ASYNC_EVENT_CODE.TASK_CANCELLED,
payload: [0, 0],
};
}
return {
code: ASYNC_EVENT_CODE.NONE,
payload: [0, 0],
};
}
yieldSync(opts) {
throw new Error('AsyncTask#yieldSync() not implemented')
}
cancel() {
_debugLog('[AsyncTask#cancel()] args', { });
if (!this.taskState() !== AsyncTask.State.CANCEL_DELIVERED) {
throw new Error('invalid task state for cancellation');
}
if (this.borrowedHandles.length > 0) { throw new Error('task still has borrow handles'); }
this.#onResolve([]);
this.#state = AsyncTask.State.RESOLVED;
}
resolve(result) {
if (this.#state === AsyncTask.State.RESOLVED) {
throw new Error('task is already resolved');
}
if (this.borrowedHandles.length > 0) { throw new Error('task still has borrow handles'); }
this.#onResolve(result);
this.#state = AsyncTask.State.RESOLVED;
}
exit() {
// TODO: ensure there is only one task at a time (scheduler.lock() functionality)
if (this.#state !== AsyncTask.State.RESOLVED) {
throw new Error('task exited without resolution');
}
if (this.borrowedHandles > 0) {
throw new Error('task exited without clearing borrowed handles');
}
const state = getOrCreateAsyncState(this.#componentIdx);
if (!state) { throw new Error('missing async state for component [' + this.#componentIdx + ']'); }
if (!this.#isAsync && !state.inSyncExportCall) {
throw new Error('sync task must be run from components known to be in a sync export call');
}
state.inSyncExportCall = false;
this.startPendingTask();
}
startPendingTask(opts) {
// TODO: implement
}
}
function unpackCallbackResult(result) {
_debugLog('[unpackCallbackResult()] args', { result });
if (!(_typeCheckValidI32(result))) { throw new Error('invalid callback return value [' + result + '], not a valid i32'); }
const eventCode = result & 0xF;
if (eventCode < 0 || eventCode > 3) {
throw new Error('invalid async return value [' + eventCode + '], outside callback code range');
}
if (result < 0 || result >= 2**32) { throw new Error('invalid callback result'); }
// TODO: table max length check?
const waitableSetIdx = result >> 4;
return [eventCode, waitableSetIdx];
}
const ASYNC_STATE = new Map();
function getOrCreateAsyncState(componentIdx, init) {
if (!ASYNC_STATE.has(componentIdx)) {
ASYNC_STATE.set(componentIdx, new ComponentAsyncState());
}
return ASYNC_STATE.get(componentIdx);
}
class ComponentAsyncState {
#callingAsyncImport = false;
#syncImportWait = Promise.withResolvers();
#lock = null;
mayLeave = false;
waitableSets = new RepTable();
waitables = new RepTable();
#parkedTasks = new Map();
callingSyncImport(val) {
if (val === undefined) { return this.#callingAsyncImport; }
if (typeof val !== 'boolean') { throw new TypeError('invalid setting for async import'); }
const prev = this.#callingAsyncImport;
this.#callingAsyncImport = val;
if (prev === true && this.#callingAsyncImport === false) {
this.#notifySyncImportEnd();
}
}
#notifySyncImportEnd() {
const existing = this.#syncImportWait;
this.#syncImportWait = Promise.withResolvers();
existing.resolve();
}
async waitForSyncImportCallEnd() {
await this.#syncImportWait.promise;
}
parkTaskOnAwaitable(args) {
if (!args.awaitable) { throw new TypeError('missing awaitable when trying to park'); }
if (!args.task) { throw new TypeError('missing task when trying to park'); }
const { awaitable, task } = args;
let taskList = this.#parkedTasks.get(awaitable.id());
if (!taskList) {
taskList = [];
this.#parkedTasks.set(awaitable.id(), taskList);
}
taskList.push(task);
this.wakeNextTaskForAwaitable(awaitable);
}
wakeNextTaskForAwaitable(awaitable) {
if (!awaitable) { throw new TypeError('missing awaitable when waking next task'); }
const awaitableID = awaitable.id();
const taskList = this.#parkedTasks.get(awaitableID);
if (!taskList || taskList.length === 0) {
_debugLog('[ComponentAsyncState] no tasks waiting for awaitable', { awaitableID: awaitable.id() });
return;
}
let task = taskList.shift(); // todo(perf)
if (!task) { throw new Error('no task in parked list despite previous check'); }
if (!task.awaitableResume) {
throw new Error('task ready due to awaitable is missing resume', { taskID: task.id(), awaitableID });
}
task.awaitableResume();
}
async exclusiveLock() { // TODO: use atomics
if (this.#lock === null) {
this.#lock = { ticket: 0n };
}
// Take a ticket for the next valid usage
const ticket = ++this.#lock.ticket;
_debugLog('[ComponentAsyncState#exclusiveLock()] locking', {
currentTicket: ticket - 1n,
ticket
});
// If there is an active promise, then wait for it
let finishedTicket;
while (this.#lock.promise) {
finishedTicket = await this.#lock.promise;
if (finishedTicket === ticket - 1n) { break; }
}
const { promise, resolve } = Promise.withResolvers();
this.#lock = {
ticket,
promise,
resolve,
};
return this.#lock.promise;
}
exclusiveRelease() {
_debugLog('[ComponentAsyncState#exclusiveRelease()] releasing', {
currentTicket: this.#lock === null ? 'none' : this.#lock.ticket,
});
if (this.#lock === null) { return; }
const existingLock = this.#lock;
this.#lock = null;
existingLock.resolve(existingLock.ticket);
}
isExclusivelyLocked() { return this.#lock !== null; }
}
if (!Promise.withResolvers) {
Promise.withResolvers = () => {
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
};
}
const _debugLog = (...args) => {
if (!globalThis?.process?.env?.JCO_DEBUG) { return; }
console.debug(...args);
}
const ASYNC_DETERMINISM = 'random';
const _coinFlip = () => { return Math.random() > 0.5; };
const I32_MAX = 2_147_483_647;
const I32_MIN = -2_147_483_648;
const _typeCheckValidI32 = (n) => typeof n === 'number' && n >= I32_MIN && n <= I32_MAX;
const base64Compile = str => WebAssembly.compile(typeof Buffer !== 'undefined' ? Buffer.from(str, 'base64') : Uint8Array.from(atob(str), b => b.charCodeAt(0)));
const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
let _fs;
async function fetchCompile (url) {
if (isNode) {
_fs = _fs || await import('node:fs/promises');
return WebAssembly.compile(await _fs.readFile(url));
}
return fetch(url).then(WebAssembly.compileStreaming);
}
const symbolCabiDispose = Symbol.for('cabiDispose');
const symbolRscHandle = Symbol('handle');
const symbolRscRep = Symbol.for('cabiRep');
const symbolDispose = Symbol.dispose || Symbol.for('dispose');
const handleTables = [];
class ComponentError extends Error {
constructor (value) {
const enumerable = typeof value !== 'string';
super(enumerable ? `${String(value)} (see error.payload)` : value);
Object.defineProperty(this, 'payload', { value, enumerable });
}
}
function getErrorPayload(e) {
if (e && hasOwnProperty.call(e, 'payload')) return e.payload;
if (e instanceof Error) throw e;
return e;
}
class RepTable {
#data = [0, null];
insert(val) {
_debugLog('[RepTable#insert()] args', { val });
const freeIdx = this.#data[0];
if (freeIdx === 0) {
this.#data.push(val);
this.#data.push(null);
return (this.#data.length >> 1) - 1;
}
this.#data[0] = this.#data[freeIdx];
const newFreeIdx = freeIdx << 1;
this.#data[newFreeIdx] = val;
this.#data[newFreeIdx + 1] = null;
return free;
}
get(rep) {
_debugLog('[RepTable#insert()] args', { rep });
const baseIdx = idx << 1;
const val = this.#data[baseIdx];
return val;
}
contains(rep) {
_debugLog('[RepTable#insert()] args', { rep });
const baseIdx = idx << 1;
return !!this.#data[baseIdx];
}
remove(rep) {
_debugLog('[RepTable#insert()] args', { idx });
if (this.#data.length === 2) { throw new Error('invalid'); }
const baseIdx = idx << 1;
const val = this.#data[baseIdx];
if (val === 0) { throw new Error('invalid resource rep (cannot be 0)'); }
this.#data[baseIdx] = this.#data[0];
this.#data[0] = idx;
return val;
}
clear() {
this.#data = [0, null];
}
}
function throwUninitialized() {
throw new TypeError('Wasm uninitialized use `await $init` first');
}
const hasOwnProperty = Object.prototype.hasOwnProperty;
const instantiateCore = WebAssembly.instantiate;
let exports0;
let exports1;
const handleTable2 = [T_FLAG, 0];
const captureTable2= new Map();
let captureCnt2 = 0;
handleTables[2] = handleTable2;
function trampoline5() {
_debugLog('[iface="wasi:cli/stderr@0.2.3", function="get-stderr"] [Instruction::CallInterface] (async? sync, @ enter)');
const _interface_call_currentTaskID = startCurrentTask(0, false, 'get-stderr');
const ret = getStderr();
_debugLog('[iface="wasi:cli/stderr@0.2.3", function="get-stderr"] [Instruction::CallInterface] (sync, @ post-call)');
endCurrentTask(0);
if (!(ret instanceof OutputStream)) {
throw new TypeError('Resource error: Not a valid "OutputStream" resource.');
}
var handle0 = ret[symbolRscHandle];
if (!handle0) {
const rep = ret[symbolRscRep] || ++captureCnt2;
captureTable2.set(rep, ret);
handle0 = rscTableCreateOwn(handleTable2, rep);
}
_debugLog('[iface="wasi:cli/stderr@0.2.3", function="get-stderr"][Instruction::Return]', {
funcName: 'get-stderr',
paramCount: 1,
postReturn: false
});
return handle0;
}
const handleTable1 = [T_FLAG, 0];
const captureTable1= new Map();
let captureCnt1 = 0;
handleTables[1] = handleTable1;
function trampoline8() {
_debugLog('[iface="wasi:cli/stdin@0.2.3", function="get-stdin"] [Instruction::CallInterface] (async? sync, @ enter)');
const _interface_call_currentTaskID = startCurrentTask(0, false, 'get-stdin');
const ret = getStdin();
_debugLog('[iface="wasi:cli/stdin@0.2.3", function="get-stdin"] [Instruction::CallInterface] (sync, @ post-call)');
endCurrentTask(0);
if (!(ret instanceof InputStream)) {
throw new TypeError('Resource error: Not a valid "InputStream" resource.');
}
var handle0 = ret[symbolRscHandle];
if (!handle0) {
const rep = ret[symbolRscRep] || ++captureCnt1;
captureTable1.set(rep, ret);
handle0 = rscTableCreateOwn(handleTable1, rep);
}
_debugLog('[iface="wasi:cli/stdin@0.2.3", function="get-stdin"][Instruction::Return]', {
funcName: 'get-stdin',
paramCount: 1,
postReturn: false
});
return handle0;
}
function trampoline9() {
_debugLog('[iface="wasi:cli/stdout@0.2.3", function="get-stdout"] [Instruction::CallInterface] (async? sync, @ enter)');
const _interface_call_currentTaskID = startCurrentTask(0, false, 'get-stdout');
const ret = getStdout();
_debugLog('[iface="wasi:cli/stdout@0.2.3", function="get-stdout"] [Instruction::CallInterface] (sync, @ post-call)');
endCurrentTask(0);
if (!(ret instanceof OutputStream)) {
throw new TypeError('Resource error: Not a valid "OutputStream" resource.');
}
var handle0 = ret[symbolRscHandle];
if (!handle0) {
const rep = ret[symbolRscRep] || ++captureCnt2;
captureTable2.set(rep, ret);
handle0 = rscTableCreateOwn(handleTable2, rep);
}
_debugLog('[iface="wasi:cli/stdout@0.2.3", function="get-stdout"][Instruction::Return]', {
funcName: 'get-stdout',
paramCount: 1,
postReturn: false
});
return handle0;
}
function trampoline10(arg0) {
let variant0;
switch (arg0) {
case 0: {
variant0= {
tag: 'ok',
val: undefined
};
break;
}
case 1: {
variant0= {
tag: 'err',
val: undefined
};
break;
}
default: {
throw new TypeError('invalid variant discriminant for expected');
}
}
_debugLog('[iface="wasi:cli/exit@0.2.3", function="exit"] [Instruction::CallInterface] (async? sync, @ enter)');
const _interface_call_currentTaskID = startCurrentTask(0, false, 'exit');
exit(variant0);
_debugLog('[iface="wasi:cli/exit@0.2.3", function="exit"] [Instruction::CallInterface] (sync, @ post-call)');
endCurrentTask(0);
_debugLog('[iface="wasi:cli/exit@0.2.3", function="exit"][Instruction::Return]', {
funcName: 'exit',
paramCount: 0,
postReturn: false
});
}
let exports2;
let memory0;
let realloc0;
function trampoline11(arg0) {
_debugLog('[iface="wasi:cli/environment@0.2.3", function="get-environment"] [Instruction::CallInterface] (async? sync, @ enter)');
const _interface_call_currentTaskID = startCurrentTask(0, false, 'get-environment');
const ret = getEnvironment();
_debugLog('[iface="wasi:cli/environment@0.2.3", function="get-environment"] [Instruction::CallInterface] (sync, @ post-call)');
endCurrentTask(0);
var vec3 = ret;
var len3 = vec3.length;
var result3 = realloc0(0, 0, 4, len3 * 16);
for (let i = 0; i < vec3.length; i++) {
const e = vec3[i];
const base = result3 + i * 16;var [tuple0_0, tuple0_1] = e;
var ptr1 = utf8Encode(tuple0_0, realloc0, memory0);
var len1 = utf8EncodedLen;
dataView(memory0).setInt32(base + 4, len1, true);
dataView(memory0).setInt32(base + 0, ptr1, true);
var ptr2 = utf8Encode(tuple0_1, realloc0, memory0);
var len2 = utf8EncodedLen;
dataView(memory0).setInt32(base + 12, len2, true);
dataView(memory0).setInt32(base + 8, ptr2, true);
}
dataView(memory0).setInt32(arg0 + 4, len3, true);
dataView(memory0).setInt32(arg0 + 0, result3, true);
_debugLog('[iface="wasi:cli/environment@0.2.3", function="get-environment"][Instruction::Return]', {
funcName: 'get-environment',
paramCount: 0,
postReturn: false
});
}
const handleTable6 = [T_FLAG, 0];
const captureTable6= new Map();
let captureCnt6 = 0;
handleTables[6] = handleTable6;
function trampoline12(arg0, arg1) {
var handle1 = arg0;
var rep2 = handleTable6[(handle1 << 1) + 1] & ~T_FLAG;
var rsc0 = captureTable6.get(rep2);
if (!rsc0) {
rsc0 = Object.create(Descriptor.prototype);
Object.defineProperty(rsc0, symbolRscHandle, { writable: true, value: handle1});
Object.defineProperty(rsc0, symbolRscRep, { writable: true, value: rep2});
}
curResourceBorrows.push(rsc0);
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="[method]descriptor.get-type"] [Instruction::CallInterface] (async? sync, @ enter)');
const _interface_call_currentTaskID = startCurrentTask(0, false, '[method]descriptor.get-type');
let ret;
try {
ret = { tag: 'ok', val: rsc0.getType()};
} catch (e) {
ret = { tag: 'err', val: getErrorPayload(e) };
}
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="[method]descriptor.get-type"] [Instruction::CallInterface] (sync, @ post-call)');
for (const rsc of curResourceBorrows) {
rsc[symbolRscHandle] = undefined;
}
curResourceBorrows = [];
endCurrentTask(0);
var variant5 = ret;
switch (variant5.tag) {
case 'ok': {
const e = variant5.val;
dataView(memory0).setInt8(arg1 + 0, 0, true);
var val3 = e;
let enum3;
switch (val3) {
case 'unknown': {
enum3 = 0;
break;
}
case 'block-device': {
enum3 = 1;
break;
}
case 'character-device': {
enum3 = 2;
break;
}
case 'directory': {
enum3 = 3;
break;
}
case 'fifo': {
enum3 = 4;
break;
}
case 'symbolic-link': {
enum3 = 5;
break;
}
case 'regular-file': {
enum3 = 6;
break;
}
case 'socket': {
enum3 = 7;
break;
}
default: {
if ((e) instanceof Error) {
console.error(e);
}
throw new TypeError(`"${val3}" is not one of the cases of descriptor-type`);
}
}
dataView(memory0).setInt8(arg1 + 1, enum3, true);
break;
}
case 'err': {
const e = variant5.val;
dataView(memory0).setInt8(arg1 + 0, 1, true);
var val4 = e;
let enum4;
switch (val4) {
case 'access': {
enum4 = 0;
break;
}
case 'would-block': {
enum4 = 1;
break;
}
case 'already': {
enum4 = 2;
break;
}
case 'bad-descriptor': {
enum4 = 3;
break;
}
case 'busy': {
enum4 = 4;
break;
}
case 'deadlock': {
enum4 = 5;
break;
}
case 'quota': {
enum4 = 6;
break;
}
case 'exist': {
enum4 = 7;
break;
}
case 'file-too-large': {
enum4 = 8;
break;
}
case 'illegal-byte-sequence': {
enum4 = 9;
break;
}
case 'in-progress': {
enum4 = 10;
break;
}
case 'interrupted': {
enum4 = 11;
break;
}
case 'invalid': {
enum4 = 12;
break;
}
case 'io': {
enum4 = 13;
break;
}
case 'is-directory': {
enum4 = 14;
break;
}
case 'loop': {
enum4 = 15;
break;
}
case 'too-many-links': {
enum4 = 16;
break;
}
case 'message-size': {
enum4 = 17;
break;
}
case 'name-too-long': {
enum4 = 18;
break;
}
case 'no-device': {
enum4 = 19;
break;
}
case 'no-entry': {
enum4 = 20;
break;
}
case 'no-lock': {
enum4 = 21;
break;
}
case 'insufficient-memory': {
enum4 = 22;
break;
}
case 'insufficient-space': {
enum4 = 23;
break;
}
case 'not-directory': {
enum4 = 24;
break;
}
case 'not-empty': {
enum4 = 25;
break;
}
case 'not-recoverable': {
enum4 = 26;
break;
}
case 'unsupported': {
enum4 = 27;
break;
}
case 'no-tty': {
enum4 = 28;
break;
}
case 'no-such-device': {
enum4 = 29;
break;
}
case 'overflow': {
enum4 = 30;
break;
}
case 'not-permitted': {
enum4 = 31;
break;
}
case 'pipe': {
enum4 = 32;
break;
}
case 'read-only': {
enum4 = 33;
break;
}
case 'invalid-seek': {
enum4 = 34;
break;
}
case 'text-file-busy': {
enum4 = 35;
break;
}
case 'cross-device': {
enum4 = 36;
break;
}
default: {
if ((e) instanceof Error) {
console.error(e);
}
throw new TypeError(`"${val4}" is not one of the cases of error-code`);
}
}
dataView(memory0).setInt8(arg1 + 1, enum4, true);
break;
}
default: {
throw new TypeError('invalid variant specified for result');
}
}
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="[method]descriptor.get-type"][Instruction::Return]', {
funcName: '[method]descriptor.get-type',
paramCount: 0,
postReturn: false
});
}
function trampoline13(arg0, arg1) {
var handle1 = arg0;
var rep2 = handleTable6[(handle1 << 1) + 1] & ~T_FLAG;
var rsc0 = captureTable6.get(rep2);
if (!rsc0) {
rsc0 = Object.create(Descriptor.prototype);
Object.defineProperty(rsc0, symbolRscHandle, { writable: true, value: handle1});
Object.defineProperty(rsc0, symbolRscRep, { writable: true, value: rep2});
}
curResourceBorrows.push(rsc0);
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="[method]descriptor.metadata-hash"] [Instruction::CallInterface] (async? sync, @ enter)');
const _interface_call_currentTaskID = startCurrentTask(0, false, '[method]descriptor.metadata-hash');
let ret;
try {
ret = { tag: 'ok', val: rsc0.metadataHash()};
} catch (e) {
ret = { tag: 'err', val: getErrorPayload(e) };
}
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="[method]descriptor.metadata-hash"] [Instruction::CallInterface] (sync, @ post-call)');
for (const rsc of curResourceBorrows) {
rsc[symbolRscHandle] = undefined;
}
curResourceBorrows = [];
endCurrentTask(0);
var variant5 = ret;
switch (variant5.tag) {
case 'ok': {
const e = variant5.val;
dataView(memory0).setInt8(arg1 + 0, 0, true);
var {lower: v3_0, upper: v3_1 } = e;
dataView(memory0).setBigInt64(arg1 + 8, toUint64(v3_0), true);
dataView(memory0).setBigInt64(arg1 + 16, toUint64(v3_1), true);
break;
}
case 'err': {
const e = variant5.val;
dataView(memory0).setInt8(arg1 + 0, 1, true);
var val4 = e;
let enum4;
switch (val4) {
case 'access': {
enum4 = 0;
break;
}
case 'would-block': {
enum4 = 1;
break;
}
case 'already': {
enum4 = 2;
break;
}
case 'bad-descriptor': {
enum4 = 3;
break;
}
case 'busy': {
enum4 = 4;
break;
}
case 'deadlock': {
enum4 = 5;
break;
}
case 'quota': {
enum4 = 6;
break;
}
case 'exist': {
enum4 = 7;
break;
}
case 'file-too-large': {
enum4 = 8;
break;
}
case 'illegal-byte-sequence': {
enum4 = 9;
break;
}
case 'in-progress': {
enum4 = 10;
break;
}
case 'interrupted': {
enum4 = 11;
break;
}
case 'invalid': {
enum4 = 12;
break;
}
case 'io': {
enum4 = 13;
break;
}
case 'is-directory': {
enum4 = 14;
break;
}
case 'loop': {
enum4 = 15;
break;
}
case 'too-many-links': {
enum4 = 16;
break;
}
case 'message-size': {
enum4 = 17;
break;
}
case 'name-too-long': {
enum4 = 18;
break;
}
case 'no-device': {
enum4 = 19;
break;
}
case 'no-entry': {
enum4 = 20;
break;
}
case 'no-lock': {
enum4 = 21;
break;
}
case 'insufficient-memory': {
enum4 = 22;
break;
}
case 'insufficient-space': {
enum4 = 23;
break;
}
case 'not-directory': {
enum4 = 24;
break;
}
case 'not-empty': {
enum4 = 25;
break;
}
case 'not-recoverable': {
enum4 = 26;
break;
}
case 'unsupported': {
enum4 = 27;
break;
}
case 'no-tty': {
enum4 = 28;
break;
}
case 'no-such-device': {
enum4 = 29;
break;
}
case 'overflow': {
enum4 = 30;
break;
}
case 'not-permitted': {
enum4 = 31;
break;
}
case 'pipe': {
enum4 = 32;
break;
}
case 'read-only': {
enum4 = 33;
break;
}
case 'invalid-seek': {
enum4 = 34;
break;
}
case 'text-file-busy': {
enum4 = 35;
break;
}
case 'cross-device': {
enum4 = 36;
break;
}
default: {
if ((e) instanceof Error) {
console.error(e);
}
throw new TypeError(`"${val4}" is not one of the cases of error-code`);
}
}
dataView(memory0).setInt8(arg1 + 8, enum4, true);
break;
}
default: {
throw new TypeError('invalid variant specified for result');
}
}
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="[method]descriptor.metadata-hash"][Instruction::Return]', {
funcName: '[method]descriptor.metadata-hash',
paramCount: 0,
postReturn: false
});
}
const handleTable0 = [T_FLAG, 0];
const captureTable0= new Map();
let captureCnt0 = 0;
handleTables[0] = handleTable0;
function trampoline14(arg0, arg1) {
var handle1 = arg0;
var rep2 = handleTable0[(handle1 << 1) + 1] & ~T_FLAG;
var rsc0 = captureTable0.get(rep2);
if (!rsc0) {
rsc0 = Object.create(Error$1.prototype);
Object.defineProperty(rsc0, symbolRscHandle, { writable: true, value: handle1});
Object.defineProperty(rsc0, symbolRscRep, { writable: true, value: rep2});
}
curResourceBorrows.push(rsc0);
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="filesystem-error-code"] [Instruction::CallInterface] (async? sync, @ enter)');
const _interface_call_currentTaskID = startCurrentTask(0, false, 'filesystem-error-code');
const ret = filesystemErrorCode(rsc0);
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="filesystem-error-code"] [Instruction::CallInterface] (sync, @ post-call)');
for (const rsc of curResourceBorrows) {
rsc[symbolRscHandle] = undefined;
}
curResourceBorrows = [];
endCurrentTask(0);
var variant4 = ret;
if (variant4 === null || variant4=== undefined) {
dataView(memory0).setInt8(arg1 + 0, 0, true);
} else {
const e = variant4;
dataView(memory0).setInt8(arg1 + 0, 1, true);
var val3 = e;
let enum3;
switch (val3) {
case 'access': {
enum3 = 0;
break;
}
case 'would-block': {
enum3 = 1;
break;
}
case 'already': {
enum3 = 2;
break;
}
case 'bad-descriptor': {
enum3 = 3;
break;
}
case 'busy': {
enum3 = 4;
break;
}
case 'deadlock': {
enum3 = 5;
break;
}
case 'quota': {
enum3 = 6;
break;
}
case 'exist': {
enum3 = 7;
break;
}
case 'file-too-large': {
enum3 = 8;
break;
}
case 'illegal-byte-sequence': {
enum3 = 9;
break;
}
case 'in-progress': {
enum3 = 10;
break;
}
case 'interrupted': {
enum3 = 11;
break;
}
case 'invalid': {
enum3 = 12;
break;
}
case 'io': {
enum3 = 13;
break;
}
case 'is-directory': {
enum3 = 14;
break;
}
case 'loop': {
enum3 = 15;
break;
}
case 'too-many-links': {
enum3 = 16;
break;
}
case 'message-size': {
enum3 = 17;
break;
}
case 'name-too-long': {
enum3 = 18;
break;
}
case 'no-device': {
enum3 = 19;
break;
}
case 'no-entry': {
enum3 = 20;
break;
}
case 'no-lock': {
enum3 = 21;
break;
}
case 'insufficient-memory': {
enum3 = 22;
break;
}
case 'insufficient-space': {
enum3 = 23;
break;
}
case 'not-directory': {
enum3 = 24;
break;
}
case 'not-empty': {
enum3 = 25;
break;
}
case 'not-recoverable': {
enum3 = 26;
break;
}
case 'unsupported': {
enum3 = 27;
break;
}
case 'no-tty': {
enum3 = 28;
break;
}
case 'no-such-device': {
enum3 = 29;
break;
}
case 'overflow': {
enum3 = 30;
break;
}
case 'not-permitted': {
enum3 = 31;
break;
}
case 'pipe': {
enum3 = 32;
break;
}
case 'read-only': {
enum3 = 33;
break;
}
case 'invalid-seek': {
enum3 = 34;
break;
}
case 'text-file-busy': {
enum3 = 35;
break;
}
case 'cross-device': {
enum3 = 36;
break;
}
default: {
if ((e) instanceof Error) {
console.error(e);
}
throw new TypeError(`"${val3}" is not one of the cases of error-code`);
}
}
dataView(memory0).setInt8(arg1 + 1, enum3, true);
}
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="filesystem-error-code"][Instruction::Return]', {
funcName: 'filesystem-error-code',
paramCount: 0,
postReturn: false
});
}
function trampoline15(arg0, arg1, arg2, arg3, arg4) {
var handle1 = arg0;
var rep2 = handleTable6[(handle1 << 1) + 1] & ~T_FLAG;
var rsc0 = captureTable6.get(rep2);
if (!rsc0) {
rsc0 = Object.create(Descriptor.prototype);
Object.defineProperty(rsc0, symbolRscHandle, { writable: true, value: handle1});
Object.defineProperty(rsc0, symbolRscRep, { writable: true, value: rep2});
}
curResourceBorrows.push(rsc0);
if ((arg1 & 4294967294) !== 0) {
throw new TypeError('flags have extraneous bits set');
}
var flags3 = {
symlinkFollow: Boolean(arg1 & 1),
};
var ptr4 = arg2;
var len4 = arg3;
var result4 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr4, len4));
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="[method]descriptor.metadata-hash-at"] [Instruction::CallInterface] (async? sync, @ enter)');
const _interface_call_currentTaskID = startCurrentTask(0, false, '[method]descriptor.metadata-hash-at');
let ret;
try {
ret = { tag: 'ok', val: rsc0.metadataHashAt(flags3, result4)};
} catch (e) {
ret = { tag: 'err', val: getErrorPayload(e) };
}
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="[method]descriptor.metadata-hash-at"] [Instruction::CallInterface] (sync, @ post-call)');
for (const rsc of curResourceBorrows) {
rsc[symbolRscHandle] = undefined;
}
curResourceBorrows = [];
endCurrentTask(0);
var variant7 = ret;
switch (variant7.tag) {
case 'ok': {
const e = variant7.val;
dataView(memory0).setInt8(arg4 + 0, 0, true);
var {lower: v5_0, upper: v5_1 } = e;
dataView(memory0).setBigInt64(arg4 + 8, toUint64(v5_0), true);
dataView(memory0).setBigInt64(arg4 + 16, toUint64(v5_1), true);
break;
}
case 'err': {
const e = variant7.val;
dataView(memory0).setInt8(arg4 + 0, 1, true);
var val6 = e;
let enum6;
switch (val6) {
case 'access': {
enum6 = 0;
break;
}
case 'would-block': {
enum6 = 1;
break;
}
case 'already': {
enum6 = 2;
break;
}
case 'bad-descriptor': {
enum6 = 3;
break;
}
case 'busy': {
enum6 = 4;
break;
}
case 'deadlock': {
enum6 = 5;
break;
}
case 'quota': {
enum6 = 6;
break;
}
case 'exist': {
enum6 = 7;
break;
}
case 'file-too-large': {
enum6 = 8;
break;
}
case 'illegal-byte-sequence': {
enum6 = 9;
break;
}
case 'in-progress': {
enum6 = 10;
break;
}
case 'interrupted': {
enum6 = 11;
break;
}
case 'invalid': {
enum6 = 12;
break;
}
case 'io': {
enum6 = 13;
break;
}
case 'is-directory': {
enum6 = 14;
break;
}
case 'loop': {
enum6 = 15;
break;
}
case 'too-many-links': {
enum6 = 16;
break;
}
case 'message-size': {
enum6 = 17;
break;
}
case 'name-too-long': {
enum6 = 18;
break;
}
case 'no-device': {
enum6 = 19;
break;
}
case 'no-entry': {
enum6 = 20;
break;
}
case 'no-lock': {
enum6 = 21;
break;
}
case 'insufficient-memory': {
enum6 = 22;
break;
}
case 'insufficient-space': {
enum6 = 23;
break;
}
case 'not-directory': {
enum6 = 24;
break;
}
case 'not-empty': {
enum6 = 25;
break;
}
case 'not-recoverable': {
enum6 = 26;
break;
}
case 'unsupported': {
enum6 = 27;
break;
}
case 'no-tty': {
enum6 = 28;
break;
}
case 'no-such-device': {
enum6 = 29;
break;
}
case 'overflow': {
enum6 = 30;
break;
}
case 'not-permitted': {
enum6 = 31;
break;
}
case 'pipe': {
enum6 = 32;
break;
}
case 'read-only': {
enum6 = 33;
break;
}
case 'invalid-seek': {
enum6 = 34;
break;
}
case 'text-file-busy': {
enum6 = 35;
break;
}
case 'cross-device': {
enum6 = 36;
break;
}
default: {
if ((e) instanceof Error) {
console.error(e);
}
throw new TypeError(`"${val6}" is not one of the cases of error-code`);
}
}
dataView(memory0).setInt8(arg4 + 8, enum6, true);
break;
}
default: {
throw new TypeError('invalid variant specified for result');
}
}
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="[method]descriptor.metadata-hash-at"][Instruction::Return]', {
funcName: '[method]descriptor.metadata-hash-at',
paramCount: 0,
postReturn: false
});
}
function trampoline16(arg0, arg1, arg2) {
var handle1 = arg0;
var rep2 = handleTable6[(handle1 << 1) + 1] & ~T_FLAG;
var rsc0 = captureTable6.get(rep2);
if (!rsc0) {
rsc0 = Object.create(Descriptor.prototype);
Object.defineProperty(rsc0, symbolRscHandle, { writable: true, value: handle1});
Object.defineProperty(rsc0, symbolRscRep, { writable: true, value: rep2});
}
curResourceBorrows.push(rsc0);
_debugLog('[iface="wasi:filesystem/types@0.2.3", function="[method]descriptor.read-via-stream"] [Instruction::CallInterface] (async? sync, @ enter)');
const _interface_call_currentTaskID