wai/wai-int-module is one WebAssembly module with the interface of waism §5 and nothing else: no import, one memory with a declared maximum, and every allocation trapping where memory cannot grow (R13). It decodes the integer payloads (WIV1, WIH1, WIA1, WIS1), int_synth, int_mlicpp, opus.dred.int and avatar.face through wai-rs's integer decoders, whose networks run on wai-ops/1; networks and weights arrive as each capability's set. - record/: the scalar and SIMD128 builds (7,099 vector instructions), named by SHA-256 in manifest.json, each held at the integer level by the Rust checker and check-module.mjs. build.sh builds both with the machine's paths remapped and checks both with both checkers. A build on another host has other bytes (the compiler's crate hashes take in each path dependency's absolute path and the host) and gives every case the same outcome. - corpus.json (corpus.py): every committed vector and refusal fixture of those capabilities, 120 cases, from the committed corpora. - host/ (wasmtime 50.0.1 Cranelift and Winch, Wasmi 2.0.0 with floats off), run-node.mjs and browser/run-browser.mjs run every case as a sink does and print one run digest; every run, on Linux x86_64, Linux arm64 and macOS arm64, gives the same. - plant.py plants a float or a relaxed vector instruction in a module, for the checkers. - waism §5, The set: one file as its bytes, several as their file sequence. avatars §6 names generator.wfg and identity.wfi; avatars §7.8, opus-dred §4.8 and determinism-tiers §5 state the module as a fabric. Co-Authored-By: Claude Opus 5.5 <[email protected]>
74 lines
3.2 KiB
JavaScript
74 lines
3.2 KiB
JavaScript
// sink.mjs: one object decoded through a WAISM module, as waism §5 and §6 checks 11 to 13
|
|
// state, in any JavaScript engine: Node, or a browser's page or worker. No dependency.
|
|
//
|
|
// decode(module, cap, payload, set) → { output } | { refused } | { sink, detail }
|
|
//
|
|
// `module` is a compiled WebAssembly.Module; `cap` the capability's term (a string),
|
|
// `payload` and `set` Uint8Arrays. The module is instantiated with an empty import object
|
|
// for this one object and discarded after it. `output` is the module's output (a
|
|
// Uint8Array) where wai_run returned 0; `refused` its refusal code where it returned 1;
|
|
// `sink` the sink's own refusal of the run (waism §8): module_resources, module_trap or
|
|
// module_result_invalid. The wall-clock bound of waism §7 is the caller's: a worker that
|
|
// runs this, ended from outside when a run passes its limit (module_timeout).
|
|
|
|
const ENCODER = new TextEncoder();
|
|
const DECODER = new TextDecoder();
|
|
|
|
function sinkRefusal(sink, detail) {
|
|
return { sink, detail: String(detail) };
|
|
}
|
|
|
|
/** A refusal code a module returns: ASCII lowercase letters, digits and `_`. */
|
|
function isCode(b) {
|
|
if (b.length === 0) return false;
|
|
for (const c of b) {
|
|
if (!((c >= 0x61 && c <= 0x7a) || (c >= 0x30 && c <= 0x39) || c === 0x5f)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
export async function decode(module, cap, payload, set) {
|
|
let inst;
|
|
try {
|
|
inst = await WebAssembly.instantiate(module, {});
|
|
} catch (e) {
|
|
return sinkRefusal('module_resources', e);
|
|
}
|
|
const x = inst.exports;
|
|
const call = (name, ...args) => x[name](...args);
|
|
const view = () => new Uint8Array(x.memory.buffer);
|
|
try {
|
|
// 1. The interface's version.
|
|
if (call('wai_abi') !== 1) return sinkRefusal('module_result_invalid', 'wai_abi is not 1');
|
|
// 2. The capability, the payload and the set, each at an offset from wai_alloc. An empty
|
|
// input passes 0, 0, with no call.
|
|
const args = [0, 0, 0, 0, 0, 0];
|
|
const inputs = [ENCODER.encode(cap), payload, set];
|
|
for (let i = 0; i < 3; i++) {
|
|
const b = inputs[i];
|
|
if (b.length === 0) continue;
|
|
const at = call('wai_alloc', b.length) >>> 0;
|
|
if (at === 0) return sinkRefusal('module_resources', 'wai_alloc gave 0');
|
|
const mem = view();
|
|
if (at + b.length > mem.length) return sinkRefusal('module_result_invalid', 'wai_alloc gave a region outside the memory');
|
|
mem.set(b, at);
|
|
args[2 * i] = at;
|
|
args[2 * i + 1] = b.length;
|
|
}
|
|
// 3. The run.
|
|
const status = call('wai_run', ...args);
|
|
// 4. The output.
|
|
const ptr = call('wai_out_ptr') >>> 0;
|
|
const len = call('wai_out_len') >>> 0;
|
|
const mem = view();
|
|
if (ptr + len > mem.length) return sinkRefusal('module_result_invalid', 'the output lies outside the memory');
|
|
const out = mem.slice(ptr, ptr + len);
|
|
// 5. What it is.
|
|
if (status === 0) return { output: out };
|
|
if (status === 1) return isCode(out) ? { refused: DECODER.decode(out) } : sinkRefusal('module_result_invalid', 'a refusal that is not a code');
|
|
return sinkRefusal('module_result_invalid', `wai_run gave ${status}`);
|
|
} catch (e) {
|
|
if (e instanceof WebAssembly.RuntimeError) return sinkRefusal('module_trap', e.message);
|
|
return sinkRefusal('module_trap', e);
|
|
}
|
|
}
|