UNPKG

@bytecodealliance/jco

Version:

JavaScript tooling for working with WebAssembly Components

1,795 lines (1,644 loc) 157 kB
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