From 78184a98697183b73691e921fac920d54201be02 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sun, 18 Oct 2026 19:43:06 -0700 Subject: [PATCH 01/39] =?UTF-8?q?WebAssembly=20W3=E2=80=93W4:=20translate?= =?UTF-8?q?=20modules=20to=20native=20code=20at=20build=20time,=20the=20Ja?= =?UTF-8?q?vaScript=20API=20over=20them,=20and=20Module=20transfer=20to=20?= =?UTF-8?q?workers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A build now translates every WebAssembly module whose bytes it can see (W2's discovery) into LLVM IR with a TypeScript translator (packages/compiler/src/wasm/module.ts, translate.ts) and appends it to the program module, so the existing LLVM helper optimizes, partitions and caches it with the program. The program also emits scr_wasm_registry, a portable table of module descriptors (scr_wasm_abi.h). At run time, WebAssembly.compile, instantiate, validate, new Module and new Instance find the translated module by the SHA-256 of its bytes; bytes the build did not see reject with a CompileError. There is no interpreter and no JIT. The runtime (scr_wasm.c, link-gated by the new `wasm` feature, handle tags inside W0's headroom) implements the JavaScript API once, over descriptors, with Node's semantics and messages: exports (functions, memories, tables, globals), imports (functions, immutable globals, and memories, tables and globals other instances export), every trap as WebAssembly.RuntimeError, the CompileError, LinkError and RuntimeError classes, compile and instantiate settling on a later turn, and globalThis.WebAssembly as a value. On 64-bit Linux and macOS, memories sit in 8 GiB guard reservations and a SIGSEGV/SIGBUS handler turns faults into traps or stack exhaustion; async fibers get a guard page on first use. Sanitizer builds and Windows check bounds and the stack explicitly. A WebAssembly.Module crosses to workers through W0's transfer hook (W4). W1's refusals become lowerings; the Memory, Table and Global constructors, Module.imports/exports/customSections and the streaming functions still refuse with SC2020. The globals: WebAssembly compatibility row moves to partial. Evidence: differential corpus programs for the API, TypeScript use and the codemode worker shape, plus five programs executing about 9,300 commands of the WebAssembly 2.0 spec suite; all match Node in the plain and sanitized lanes. quickjs-wasi runs through its own glue, matching Node (apart from a pre-existing non-wasm fence) and on par with or faster than V8. The zero-cost gate leaves every non-wasm program byte-identical. Co-Authored-By: Claude Opus 5.5 --- docs/content/docs/cli.mdx | 2 +- .../limitations/webassembly-modules.mdx | 18 +- .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 10 +- .../generated/node-v24-backlog.json | 23 +- .../generated/node-v24-internal.json | 26 +- internal/compatibility/static-support.json | 1 + .../src/backend/executable-features.ts | 1 + packages/compiler/src/backend/llvm/emitter.ts | 15 + .../compiler/src/backend/llvm/lib-dispatch.ts | 1 + .../compiler/src/backend/llvm/lib-shared.ts | 10 + .../compiler/src/backend/llvm/wasm-modules.ts | 74 + .../src/backend/native-link-info-core.ts | 3 + .../compiler/src/backend/native/contracts.ts | 2 + .../compiler/src/backend/native/executable.ts | 1 + .../compiler/src/backend/runtime-pack-core.ts | 2 + .../src/backend/target-diagnostics.ts | 8 + packages/compiler/src/coverage/report.ts | 8 +- .../compiler/src/coverage/surface-manifest.ts | 9 +- .../compiler/src/diagnostics/diagnostic.ts | 14 +- .../src/executable/executable-cache.ts | 1 + .../frontend/lowering/builtins/webassembly.ts | 193 +- .../src/frontend/lowering/lower-exprs.ts | 14 +- .../compiler/src/frontend/lowering/lowerer.ts | 65 +- packages/compiler/src/frontend/type-mapper.ts | 12 + packages/compiler/src/index.ts | 3 + packages/compiler/src/ir/builtin-effects.ts | 6 + .../compiler/src/ir/builtin-signatures.ts | 21 + .../src/ir/function-references.test.ts | 2 + packages/compiler/src/ir/ir.ts | 14 + packages/compiler/src/ir/runtime-features.ts | 10 + .../compiler/src/native/sanitizer.test.ts | 1 + packages/compiler/src/wasm/base64.ts | 61 + packages/compiler/src/wasm/discover.ts | 41 +- packages/compiler/src/wasm/module.ts | 659 +++++ packages/compiler/src/wasm/translate.test.ts | 145 ++ packages/compiler/src/wasm/translate.ts | 2173 +++++++++++++++++ packages/compiler/surface-manifest.json | 5 +- .../tests/corpus/webassembly-api.mjs.json | 6 + .../webassembly-spec-control/main.mjs.json | 8 + .../webassembly-spec-float/main.mjs.json | 8 + .../corpus/webassembly-spec-int/main.mjs.json | 8 + .../webassembly-spec-memory/main.mjs.json | 8 + .../webassembly-spec-table/main.mjs.json | 8 + .../tests/corpus/webassembly-typed.ts.json | 6 + .../tests/corpus/webassembly-worker.ts.json | 6 + .../runtime-pack-matrix.mjs | 1 + .../runtime-pack-matrix.mjs | 1 + .../runtime-wasm32-wasi/scripts/build.mjs | 1 + packages/runtime/src/scr_async.c | 8 - packages/runtime/src/scr_async.h | 14 + packages/runtime/src/scr_dyn.h | 5 + packages/runtime/src/scr_wasm.c | 1990 +++++++++++++++ packages/runtime/src/scr_wasm_abi.h | 191 ++ tests/corpus/webassembly-api.mjs | 179 ++ tests/corpus/webassembly-feature-probe.js | 5 +- .../corpus/webassembly-spec-control/data.mjs | 48 + .../corpus/webassembly-spec-control/main.mjs | 5 + tests/corpus/webassembly-spec-float/data.mjs | 113 + tests/corpus/webassembly-spec-float/main.mjs | 5 + tests/corpus/webassembly-spec-int/data.mjs | 33 + tests/corpus/webassembly-spec-int/main.mjs | 5 + tests/corpus/webassembly-spec-memory/data.mjs | 161 ++ tests/corpus/webassembly-spec-memory/main.mjs | 5 + tests/corpus/webassembly-spec-table/data.mjs | 193 ++ tests/corpus/webassembly-spec-table/main.mjs | 5 + tests/corpus/webassembly-typed.ts | 51 + tests/corpus/webassembly-worker.ts | 68 + tests/diagnostics/webassembly-fences.ts | 38 +- tests/harness/__snapshots__/coverage-wasm.txt | 12 +- .../__snapshots__/webassembly-fences.ts.txt | 129 +- tests/wasm-spec/corpus/api.wat | 52 + tests/wasm-spec/corpus/linked.wat | 12 + tests/wasm-spec/corpus/refs.wat | 10 + tests/wasm-spec/gen.mjs | 272 +++ tests/wasm-spec/runner.mjs | 145 ++ 76 files changed, 7252 insertions(+), 219 deletions(-) create mode 100644 packages/compiler/src/backend/llvm/wasm-modules.ts create mode 100644 packages/compiler/src/wasm/base64.ts create mode 100644 packages/compiler/src/wasm/module.ts create mode 100644 packages/compiler/src/wasm/translate.test.ts create mode 100644 packages/compiler/src/wasm/translate.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-api.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-control/main.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-float/main.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-int/main.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-memory/main.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-table/main.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-typed.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-worker.ts.json create mode 100644 packages/runtime/src/scr_wasm.c create mode 100644 packages/runtime/src/scr_wasm_abi.h create mode 100644 tests/corpus/webassembly-api.mjs create mode 100644 tests/corpus/webassembly-spec-control/data.mjs create mode 100644 tests/corpus/webassembly-spec-control/main.mjs create mode 100644 tests/corpus/webassembly-spec-float/data.mjs create mode 100644 tests/corpus/webassembly-spec-float/main.mjs create mode 100644 tests/corpus/webassembly-spec-int/data.mjs create mode 100644 tests/corpus/webassembly-spec-int/main.mjs create mode 100644 tests/corpus/webassembly-spec-memory/data.mjs create mode 100644 tests/corpus/webassembly-spec-memory/main.mjs create mode 100644 tests/corpus/webassembly-spec-table/data.mjs create mode 100644 tests/corpus/webassembly-spec-table/main.mjs create mode 100644 tests/corpus/webassembly-typed.ts create mode 100644 tests/corpus/webassembly-worker.ts create mode 100644 tests/wasm-spec/corpus/api.wat create mode 100644 tests/wasm-spec/corpus/linked.wat create mode 100644 tests/wasm-spec/corpus/refs.wat create mode 100644 tests/wasm-spec/gen.mjs create mode 100644 tests/wasm-spec/runner.mjs diff --git a/docs/content/docs/cli.mdx b/docs/content/docs/cli.mdx index c4fdf7876..37b4c2942 100644 --- a/docs/content/docs/cli.mdx +++ b/docs/content/docs/cli.mdx @@ -134,7 +134,7 @@ Verifies and loads the installed precompiled runtime objects and vendored librar
Coverage only. After the report, list the functions that already operate on values typed only at runtime and the bindings, fields, functions, classes and modules that unsupported constructs would move to the dynamic tier, each with the diagnostic behind it. With a name such as x, Point, or Point.x, show only the matching units. See Dynamic tier.
--wasm <file.wasm>
-
Coverage only. Report a WebAssembly module the program loads from a path its sources do not spell out. The report already lists modules whose paths the compiler resolves, modules inlined as base64 literals, and .wasm files shipped by packages that use WebAssembly; a scriptc.wasm array in package.json adds files the same way as this flag. Each module is listed with its size, whether it validates, and the WebAssembly proposals it uses. scriptc does not compile WebAssembly modules to native code yet. Repeatable.
+
Coverage only. Report a WebAssembly module the program loads from a path its sources do not spell out. The report already lists modules whose paths the compiler resolves, modules inlined as base64 literals, and .wasm files shipped by packages that use WebAssembly; a scriptc.wasm array in package.json adds files the same way as this flag. Each module is listed with its size, whether it validates, and the WebAssembly proposals it uses. Builds translate the modules they find to native code; a build reads the scriptc.wasm array but not this flag. Repeatable.
--sanitize
Build an executable with AddressSanitizer and a reference-count audit at exit, the same checks scriptc's own test suite uses. Requires a C compiler and is available only for host builds. Not supported with --emit=asm or --emit=obj.
diff --git a/docs/content/limitations/webassembly-modules.mdx b/docs/content/limitations/webassembly-modules.mdx index 492b2fc1a..e768b4ef0 100644 --- a/docs/content/limitations/webassembly-modules.mdx +++ b/docs/content/limitations/webassembly-modules.mdx @@ -1,3 +1,17 @@ -Compiled programs can't load WebAssembly modules yet. Code that only mentions the `WebAssembly` types type-checks, including packages whose declarations name them, and `typeof WebAssembly` answers as it does in Node.js. Every use of the API itself is rejected: `WebAssembly.compile`, `instantiate` and `validate`, `new WebAssembly.Module` and the other constructors, `instanceof` checks, and reads of `globalThis.WebAssembly`. TypeScript sources fail to build with SC2020 at each use, and JavaScript sources throw that diagnostic when the statement runs. +scriptc translates WebAssembly modules to native code when it builds the program; there is no interpreter or JIT in the executable. A build translates every module whose bytes it can see: files at paths the compiler resolves (`require.resolve`, `createRequire(...).resolve`, `import.meta.resolve`, `new URL("./x.wasm", import.meta.url)`, `path.join(__dirname, ...)`), modules inlined as base64 or byte-array literals, `.wasm` files shipped by packages whose code uses WebAssembly, and files listed in a `scriptc.wasm` array in `package.json`. At run time `WebAssembly.compile`, `instantiate`, `validate` and `new WebAssembly.Module` find the translated module by the SHA-256 of the bytes they are given. Bytes the build did not see, including bytes produced at run time, reject with a `CompileError` that says the module was not translated, and `WebAssembly.validate` answers `false` for them. `scriptc coverage` lists the modules a build finds, with their size, whether they validate, and the WebAssembly proposals they use. -`scriptc coverage` lists the modules a program would load, with their size, whether they validate, and the WebAssembly proposals they use. It finds modules at paths the compiler resolves, modules inlined as base64 literals, `.wasm` files shipped by packages that use WebAssembly, and files named with [`--wasm`](/docs/cli) or a `scriptc.wasm` array in `package.json`. +Translated modules can use the WebAssembly 2.0 feature set: the MVP plus sign-extension operators, non-trapping float-to-int conversions, bulk memory, multi-value, mutable globals, reference types, and extended constant expressions. Modules that use SIMD, threads, exception handling, tail calls, typed function references or GC, memory64, or multiple memories are not translated, so loading them rejects with the `CompileError` above; packages that fall back to a scalar build when that happens, such as undici and es-module-lexer, take their fallback. + +Supported: `WebAssembly.compile`, `instantiate` (with bytes or a `Module`), `validate`, `new WebAssembly.Module`, `new WebAssembly.Instance`, and `instanceof` for every class; the error classes `CompileError`, `LinkError` and `RuntimeError`, constructed with or without `new`; `globalThis.WebAssembly` and its `compile`, `instantiate` and `validate` functions as values. Instances expose exported functions, memories (`buffer`, `grow`), tables (`get`, `set`, `grow`, `length`) and globals (`value`). Imports can be functions, numbers or BigInts for immutable globals, and memories, tables and globals exported by other instances. Traps throw `WebAssembly.RuntimeError` with Node.js's messages, unbounded recursion throws `RangeError`, and an exception thrown by an imported function propagates through the WebAssembly frames unchanged. A `WebAssembly.Module` can be sent to a worker through `workerData` or `postMessage`. + +Not supported yet: the `Memory`, `Table`, `Global`, `Tag` and `Exception` constructors, `WebAssembly.Module.imports`, `exports` and `customSections`, `compileStreaming` and `instantiateStreaming`, and the classes used as values other than with `new` and `instanceof`. TypeScript sources fail to build with SC2020 at each such use, and JavaScript sources throw that diagnostic when the statement runs. Programs built for `wasm32-wasi` can't use the WebAssembly API. + +Differences from Node.js: + +- `Memory.prototype.grow` does not detach the previous `ArrayBuffer`. The memory never moves, so views created before the growth stay valid but keep their old length. +- Instances are never freed, together with their memories, imports and exports. +- A function reference (`funcref`) can reach JavaScript only as a function the module exports; other function references throw a `TypeError`. +- A load whose result the module never uses may be removed instead of trapping when its address is out of bounds. Loads whose result is dropped explicitly still trap. +- NaN payloads may differ, for example when a signaling NaN passes through arithmetic or a JavaScript number. +- `WebAssembly.compile` and `instantiate` with bytes settle after the current microtasks, as in Node.js, but can settle after `setImmediate` callbacks that Node.js would run later. +- The executable reads `.wasm` files at run time from the paths they had when it was built. diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index 1cf76d3e4..7a3e609ee 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "efc18bcd8a7a03fd8622", + "artifactVersion": "96f4a5b419510481a80b", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 0e6387ea9..2055d4acf 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -329,8 +329,8 @@ "apiEntries": 92, "static": { "supported": 0, - "partial": 12, - "refused": 1, + "partial": 13, + "refused": 0, "not-implemented": 79, "by-design": 0, "unreviewed": 0, @@ -36590,9 +36590,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 7d0fcf75c..4df2c983f 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,9 +7,9 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1162, + "audit-partial": 1163, "verify-gap": 2166, - "replace-refusal": 41, + "replace-refusal": 40, "classify": 2, "implement": 85 } @@ -34202,12 +34202,21 @@ "priority": "high", "tiers": { "static": { - "status": "refused", - "action": "replace-refusal", - "verification": "explicit-refusal", + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", "confidence": "high", - "source": "surface-manifest:unsupported:stdlib.webassembly", - "tests": [] + "source": "surface-manifest:stdlib.webassembly", + "tests": [ + "tests/corpus/webassembly-api.mjs", + "tests/corpus/webassembly-typed.ts", + "tests/corpus/webassembly-worker.ts", + "tests/corpus/webassembly-spec-int/main.mjs", + "tests/corpus/webassembly-spec-float/main.mjs", + "tests/corpus/webassembly-spec-control/main.mjs", + "tests/corpus/webassembly-spec-memory/main.mjs", + "tests/corpus/webassembly-spec-table/main.mjs" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index c87f98fec..f036d0ac3 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -341,8 +341,8 @@ "apiEntries": 92, "static": { "supported": 0, - "partial": 12, - "refused": 1, + "partial": 13, + "refused": 0, "not-implemented": 79, "by-design": 0, "unreviewed": 0, @@ -52218,6 +52218,14 @@ "tests/corpus/5290-blob-dynamic.js", "tests/corpus/5830-timers-promises-signal.ts", "tests/corpus/text-codec-values/main.ts", + "tests/corpus/webassembly-api.mjs", + "tests/corpus/webassembly-spec-control/main.mjs", + "tests/corpus/webassembly-spec-float/main.mjs", + "tests/corpus/webassembly-spec-int/main.mjs", + "tests/corpus/webassembly-spec-memory/main.mjs", + "tests/corpus/webassembly-spec-table/main.mjs", + "tests/corpus/webassembly-typed.ts", + "tests/corpus/webassembly-worker.ts", "tests/harness/fetch-conformance.test.ts" ] }, @@ -53553,8 +53561,18 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:stdlib.webassembly" + "status": "partial", + "evidence": "surface-manifest:stdlib.webassembly", + "tests": [ + "tests/corpus/webassembly-api.mjs", + "tests/corpus/webassembly-typed.ts", + "tests/corpus/webassembly-worker.ts", + "tests/corpus/webassembly-spec-int/main.mjs", + "tests/corpus/webassembly-spec-float/main.mjs", + "tests/corpus/webassembly-spec-control/main.mjs", + "tests/corpus/webassembly-spec-memory/main.mjs", + "tests/corpus/webassembly-spec-table/main.mjs" + ] }, "anchorSource": "exact" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index 584492bf1..96c41bcd1 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -28,6 +28,7 @@ "webstreams": "unreviewed" }, "evidenceByManifestPrefix": { + "stdlib.webassembly": ["tests/corpus/webassembly-api.mjs", "tests/corpus/webassembly-typed.ts", "tests/corpus/webassembly-worker.ts", "tests/corpus/webassembly-spec-int/main.mjs", "tests/corpus/webassembly-spec-float/main.mjs", "tests/corpus/webassembly-spec-control/main.mjs", "tests/corpus/webassembly-spec-memory/main.mjs", "tests/corpus/webassembly-spec-table/main.mjs"], "node-builtin.fs.readFileSync": ["tests/corpus/1403-buffer-fs.ts", "tests/corpus/2595-fs-arg-ladders.cjs", "tests/corpus/2919-fs-function-values.ts", "tests/corpus/2920-fs-promises-function-values.ts", "tests/corpus/fs-read-encodings.ts"], "syntax.using-declarations": ["tests/corpus/2841-using-sync.ts"], "syntax.await-using-declarations": ["tests/corpus/2842-await-using.ts"], diff --git a/packages/compiler/src/backend/executable-features.ts b/packages/compiler/src/backend/executable-features.ts index 553643470..aa6a9c490 100644 --- a/packages/compiler/src/backend/executable-features.ts +++ b/packages/compiler/src/backend/executable-features.ts @@ -14,6 +14,7 @@ export function executableLinkFeatures(mod: IrModule): NativeLinkFeatures { fileHandle: features.fileHandle, fetch: features.fetch, ...(features.eventTarget ? { eventTarget: true } : {}), + ...(features.wasm ? { wasm: true } : {}), zlib: features.zlib, assert: features.assert, inspect: features.inspect, diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index ede7a476e..9a1862cbe 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -1,3 +1,4 @@ +import { emitWasmModules, wasmBoundsChecks } from "./wasm-modules.js"; import { type ArraySearchKind, emitArraySearchHelpers } from "./array-search.js"; import { emitStringInputs } from "./string-lifetimes.js"; import { emitLlvmLayouts } from "./layouts.js"; @@ -500,6 +501,9 @@ export interface LlvmTargetOptions { * teardown after `process.exit` to a helper process (`--detached-exit`). * Executables only; the runtime's weak default keeps it off. */ detachedExit?: boolean; + /** Translated WebAssembly memories check bounds explicitly instead of + * relying on guard pages (wasm-modules.ts wasmBoundsChecks). */ + wasmBoundsChecks?: boolean; } export function emitLlvmModule(input: IrModule, options: LlvmTargetOptions = {}): string { @@ -775,6 +779,7 @@ export class LlEmitter { private readonly emitLibraryIdentity: boolean; private readonly runtimeAbiMarker: boolean; private readonly detachedExit: boolean; + private readonly wasmBoundsChecks: boolean; /** Interned string literals: UTF-8 text → { symbol, byte length } — * first-use order, the runtime ABI’s determinism discipline. */ private readonly literals = new Map(); @@ -1247,6 +1252,13 @@ export class LlEmitter { this.emitLibraryIdentity = options.emitLibraryIdentity !== false; this.runtimeAbiMarker = options.runtimeAbiMarker === true; this.detachedExit = options.detachedExit === true; + this.wasmBoundsChecks = + options.wasmBoundsChecks === true || + wasmBoundsChecks({ + sanitize: false, + pointerBits: options.pointerBits ?? 64, + targetTriple: options.targetTriple ?? "", + }); this.rcHelpers = options.inlineRc !== undefined ? new Set() : null; this.rcMode = options.inlineRc; this.rcHelpersNoinline = options.rcHelpersNoinline === true; @@ -2686,6 +2698,9 @@ export class LlEmitter { out.push(fnDefs[0] ?? ""); for (let i = 1; i < fnDefs.length; i++) out.push("", fnDefs[i]!); out.push(""); + // WebAssembly modules translated into this program, and the registry. + for (const line of emitWasmModules(this.mod, flushedDecls, this.wasmBoundsChecks)) + out.push(line); // main(): scr_init, the program-dependent error-vt interval stamps, // scr_lib_init(argc, argv), then the entry function. An uncaught diff --git a/packages/compiler/src/backend/llvm/lib-dispatch.ts b/packages/compiler/src/backend/llvm/lib-dispatch.ts index f21ded106..f740e19e2 100644 --- a/packages/compiler/src/backend/llvm/lib-dispatch.ts +++ b/packages/compiler/src/backend/llvm/lib-dispatch.ts @@ -832,6 +832,7 @@ export function emitLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue { case "event": case "events": case "blob": + case "wasm": case "record": case "disposable": case "punycode": diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 67cb77047..10e3ddd8d 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -836,6 +836,16 @@ export const LIB_FN_SYMS: Record = { "event.get": "scr_event_obj_get", "event.set": "scr_event_obj_set", "blob.new": "scr_blob_new", + "wasm.compile": "scr_wasm_compile", + "wasm.validate": "scr_wasm_validate", + "wasm.instantiate": "scr_wasm_instantiate", + "wasm.moduleNew": "scr_wasm_module_new", + "wasm.instanceNew": "scr_wasm_instance_new", + "wasm.is": "scr_wasm_is", + "wasm.errorNew": "scr_wasm_error_new", + "wasm.function": "scr_wasm_function", + "wasm.namespace": "scr_wasm_namespace", + "wasm.globalView": "scr_wasm_global_view", "blob.fileNew": "scr_file_new", "blob.slice": "scr_blob_slice", "blob.text": "scr_blob_text", diff --git a/packages/compiler/src/backend/llvm/wasm-modules.ts b/packages/compiler/src/backend/llvm/wasm-modules.ts new file mode 100644 index 000000000..c37dc36c4 --- /dev/null +++ b/packages/compiler/src/backend/llvm/wasm-modules.ts @@ -0,0 +1,74 @@ +/* The WebAssembly modules translated into a program (IrModule.wasmModules): + * each module's translation (wasm/translate.ts) and the registry the + * runtime looks modules up in (scr_wasm_registry, scr_wasm_abi.h). The + * translations join the program module, so the native helper optimizes, + * partitions and caches them with it. Programs that do not use the + * WebAssembly API carry no wasmModules and emit nothing here. */ +import type { IrModule } from "../../ir/ir.js"; +import { decodeBase64 } from "../../wasm/base64.js"; +import { translateWasmModule, WasmTranslateError } from "../../wasm/translate.js"; + +function hexBytes(hex: string): Uint8Array { + const out = new Uint8Array(hex.length / 2); + for (let i = 0; i < out.length; i++) out[i] = parseInt(hex.slice(2 * i, 2 * i + 2), 16); + return out; +} + +/** Whether translated memories check bounds explicitly instead of relying + * on guard pages and the runtime's fault handler: sanitizer builds (whose + * runtime owns SIGSEGV), 32-bit targets, and Windows, which has no + * fault handler yet. */ +export function wasmBoundsChecks(options: { + sanitize: boolean; + pointerBits: 32 | 64; + targetTriple: string; +}): boolean { + if (options.sanitize || options.pointerBits === 32) return true; + const target = options.targetTriple || process.platform; + return /windows|mingw|cygwin|win32|msvc/.test(target); +} + +/** The top-level lines of every translated module plus the registry. + * `declared` holds the declarations the module already carries; runtime + * entry points it lacks are declared here. A module the translator + * cannot translate is left out of the registry, so loading it at run + * time rejects with the CompileError for untranslated bytes. */ +export function emitWasmModules( + mod: IrModule, + declared: ReadonlySet, + boundsChecks: boolean, +): string[] { + const modules = mod.wasmModules; + if (modules === undefined) return []; + const out: string[] = []; + const decls = new Set(declared); + const descriptors: string[] = []; + for (const module of modules) { + const bytes = decodeBase64(module.bytes); + if (bytes === null) continue; + let translation; + try { + translation = translateWasmModule(bytes, hexBytes(module.sha256), { boundsChecks }); + } catch (error) { + if (error instanceof WasmTranslateError) continue; + throw error; + } + for (const decl of translation.decls) { + if (decls.has(decl)) continue; + decls.add(decl); + out.push(decl); + } + for (const part of translation.text) out.push(part); + descriptors.push(translation.descriptor); + } + if (descriptors.length === 0) { + out.push(`@scr_wasm_registry = constant { i64, ptr } { i64 0, ptr null }`); + } else { + out.push( + `@scr_wasm_registry_modules = private constant [${descriptors.length} x ptr] [${descriptors.map((d) => `ptr ${d}`).join(", ")}]`, + `@scr_wasm_registry = constant { i64, ptr } { i64 ${descriptors.length}, ptr @scr_wasm_registry_modules }`, + ); + } + out.push(""); + return out; +} diff --git a/packages/compiler/src/backend/native-link-info-core.ts b/packages/compiler/src/backend/native-link-info-core.ts index 8f69cea57..ba36a8ddb 100644 --- a/packages/compiler/src/backend/native-link-info-core.ts +++ b/packages/compiler/src/backend/native-link-info-core.ts @@ -22,6 +22,9 @@ export interface NativeLinkFeatures { fileHandle: boolean; fetch: boolean; eventTarget?: boolean; + /** The WebAssembly API (scr_wasm.c). Absent when unused, so programs + * without it keep their link identity. */ + wasm?: boolean; zlib: boolean; assert: boolean; inspect: boolean; diff --git a/packages/compiler/src/backend/native/contracts.ts b/packages/compiler/src/backend/native/contracts.ts index 5e981fe44..6708c5bae 100644 --- a/packages/compiler/src/backend/native/contracts.ts +++ b/packages/compiler/src/backend/native/contracts.ts @@ -112,6 +112,8 @@ export interface CcOptions { * native fetch AbortSignal built on the same engine: compiles * scr_event_target.c. */ eventTarget?: boolean; + /** The WebAssembly API: compiles scr_wasm.c. */ + wasm?: boolean; /** The program uses the process-events surface (signal/exit listeners, * stdin events, for-await over stdin — moduleUsesProcessEvents on the * IR): compiles scr_events.c into the binary. Event-free binaries keep diff --git a/packages/compiler/src/backend/native/executable.ts b/packages/compiler/src/backend/native/executable.ts index 549e9ebbf..dd7369138 100644 --- a/packages/compiler/src/backend/native/executable.ts +++ b/packages/compiler/src/backend/native/executable.ts @@ -503,6 +503,7 @@ export async function compileCInternal( ...(opts.dynInvoke || opts.workers || nativeFetch ? [rt(join(rtDir, "scr_dyn_invoke.c"))] : []), ...(opts.dc ? [rt(join(rtDir, "scr_dc.c"))] : []), ...(opts.eventTarget || nativeFetch ? [rt(join(rtDir, "scr_event_target.c"))] : []), + ...(opts.wasm ? [rt(join(rtDir, "scr_wasm.c"))] : []), ...(opts.dynAsync || opts.dynInvoke || opts.workers || opts.dc || opts.fileHandle || nativeFetch ? [rt(join(rtDir, "scr_async_dyn.c"))] : []), diff --git a/packages/compiler/src/backend/runtime-pack-core.ts b/packages/compiler/src/backend/runtime-pack-core.ts index 039ecc209..a34df80bb 100644 --- a/packages/compiler/src/backend/runtime-pack-core.ts +++ b/packages/compiler/src/backend/runtime-pack-core.ts @@ -81,6 +81,7 @@ export interface RuntimePackManifest { export interface RuntimeFeatureSet extends NativeLinkFeatures { workers: boolean; eventTarget: boolean; + wasm: boolean; nativeFetch: boolean; netEffective: boolean; httpEffective: boolean; @@ -267,6 +268,7 @@ export function effectiveRuntimeFeatures( ...features, workers: features.workers === true, eventTarget: features.eventTarget === true, + wasm: features.wasm === true, nativeFetch, netEffective, httpEffective, diff --git a/packages/compiler/src/backend/target-diagnostics.ts b/packages/compiler/src/backend/target-diagnostics.ts index 365d5e913..d130ce95e 100644 --- a/packages/compiler/src/backend/target-diagnostics.ts +++ b/packages/compiler/src/backend/target-diagnostics.ts @@ -192,6 +192,14 @@ export function moduleWasiUnavailableSurface( found = { surface: "OS signals (WASI Preview 1 has no signal API)", loc }; return false; } + if (node.fn.startsWith("wasm.")) { + found = { + surface: + "the WebAssembly API (a wasm32-wasi program cannot load translated modules into its own linear memory yet)", + loc, + }; + return false; + } if (node.fn === "crypto.cipherNew") { found = { surface: diff --git a/packages/compiler/src/coverage/report.ts b/packages/compiler/src/coverage/report.ts index 6570f23d1..89733e255 100644 --- a/packages/compiler/src/coverage/report.ts +++ b/packages/compiler/src/coverage/report.ts @@ -221,13 +221,13 @@ export function renderCoverage(input: CoverageInput, opts: CoverageRenderOptions out.push(""); } - // The WebAssembly modules the build can see: what translating them would - // take (wasm/discover.ts). No module compiles to native code yet; the - // sites that load one are blockers or deferred fences above. + // The WebAssembly modules the build can see (wasm/discover.ts). A build + // translates the valid ones to native code (wasm/translate.ts) when the + // program uses the WebAssembly API; the others fail to load at run time. const wasm = input.wasmModules ?? []; if (wasm.length > 0) { out.push( - ` ${c(DIM, "WebAssembly modules:")} ${c(DIM, "(found at build time; none compile to native code yet)")}`, + ` ${c(DIM, "WebAssembly modules:")} ${c(DIM, "(found at build time; valid ones compile to native code)")}`, ); for (const m of wasm) { const name = m.path !== undefined ? displayPath(m.path, opts.root) : "inline module"; diff --git a/packages/compiler/src/coverage/surface-manifest.ts b/packages/compiler/src/coverage/surface-manifest.ts index d82367611..824790bd9 100644 --- a/packages/compiler/src/coverage/surface-manifest.ts +++ b/packages/compiler/src/coverage/surface-manifest.ts @@ -444,16 +444,17 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes } } - // ── the WebAssembly global: every reached use refuses (webAssemblyDiag) ─ + // ── the WebAssembly global (builtins/webassembly.ts, wasm/translate.ts): + // the core API lowers over modules translated at build time; the rest + // refuses at each use (webAssemblyDiag) ─ { const refusal = webAssemblyDiag("WebAssembly", { file: "", start: 0, end: 0 }); add({ id: "stdlib.webassembly", kind: "stdlib", name: "globalThis.WebAssembly", - status: "unsupported", - code: refusal.code, - ...(refusal.hint !== undefined ? { note: refusal.hint } : {}), + status: "static", + note: `compile, instantiate, validate, Module, Instance, instanceof, the error classes, exports, memories, tables, globals and Module transfer to workers, over the modules translated at build time; the rest refuses with ${refusal.code} (${refusal.hint ?? ""})`, }); } diff --git a/packages/compiler/src/diagnostics/diagnostic.ts b/packages/compiler/src/diagnostics/diagnostic.ts index 4acd6bc50..0359dbf6b 100644 --- a/packages/compiler/src/diagnostics/diagnostic.ts +++ b/packages/compiler/src/diagnostics/diagnostic.ts @@ -751,17 +751,19 @@ export function noLoweringDiag( }; } -/** A REACHED use of the WebAssembly API (SC2020): scriptc.d.ts declares - * its types so packages that mention them typecheck, but no module - * compiles to native code yet. `surface` names what was used - * ('WebAssembly.compile', 'new WebAssembly.Module', 'globalThis.WebAssembly'). */ +/** A REACHED use of a part of the WebAssembly API scriptc does not + * implement yet (SC2020): the Memory, Table and Global constructors, + * Module.imports/exports/customSections, the streaming functions, the + * classes as values. compile, instantiate, validate, Module, Instance and + * the error classes lower (builtins/webassembly.ts). `surface` names what + * was used ('new WebAssembly.Memory', 'WebAssembly.Module.imports'). */ export function webAssemblyDiag(surface: string, loc: SrcLoc): ScrDiagnostic { return { code: "SC2020", - message: `'${surface}' is not supported yet: scriptc does not compile WebAssembly modules to native code yet`, + message: `'${surface}' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API`, loc, milestone: "later", - hint: "WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations)", + hint: "the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations)", }; } diff --git a/packages/compiler/src/executable/executable-cache.ts b/packages/compiler/src/executable/executable-cache.ts index fbd7e4edd..c8b00adc7 100644 --- a/packages/compiler/src/executable/executable-cache.ts +++ b/packages/compiler/src/executable/executable-cache.ts @@ -55,6 +55,7 @@ export interface EarlyExecutableNativeFeatures { fileHandle: boolean; fetch: boolean; eventTarget?: boolean; + wasm?: boolean; zlib: boolean; assert: boolean; inspect: boolean; diff --git a/packages/compiler/src/frontend/lowering/builtins/webassembly.ts b/packages/compiler/src/frontend/lowering/builtins/webassembly.ts index dc61853f8..3a0a00508 100644 --- a/packages/compiler/src/frontend/lowering/builtins/webassembly.ts +++ b/packages/compiler/src/frontend/lowering/builtins/webassembly.ts @@ -2,17 +2,41 @@ import * as ts from "../../ts7/adapter.js"; import { type Lowerer, PoisonError } from "../lowerer.js"; import { locOf } from "../../program.js"; import { webAssemblyDiag } from "../../../diagnostics/diagnostic.js"; -import { STRING, type IrExpr } from "../../../ir/ir.js"; +import { BOOL, DYN, F64, STRING, type IrExpr } from "../../../ir/ir.js"; +import { dynUndefinedExpr } from "../../../ir/build.js"; +import { lowerDynObjectLiteral } from "../expressions/object-literals.js"; import { stdlibGlobalNameOf } from "../surfaces.js"; /* The WebAssembly API. scriptc.d.ts declares its types (lib.dom's - * namespace) so that packages whose declarations mention them typecheck, - * and the type mapper gives those types the checked-dynamic representation. - * No module compiles to native code yet, so every reached use of the API - * value fences at its expression with webAssemblyDiag: a build error in - * TypeScript sources, a located runtime fence in JavaScript ones. typeof - * needs no value and folds to Node's answer. */ + * namespace) and the type mapper gives them the checked-dynamic + * representation. Modules whose bytes the build sees are translated to + * native code (wasm/translate.ts) and found at run time by the SHA-256 of + * their bytes (scr_wasm.c): + * - WebAssembly.compile, instantiate and validate calls, new + * WebAssembly.Module and new WebAssembly.Instance lower to wasm.* + * libCalls; members of the values they produce (exports, memory + * buffers, globals, tables) dispatch through the native handles; + * - `v instanceof WebAssembly.` lowers to wasm.is; + * - the error classes construct with or without `new` (wasm.errorNew). + * Every other reached use of the API value (the bare namespace, the + * Memory, Table and Global constructors, Module.imports and friends, the + * streaming functions) still fences at its expression with + * webAssemblyDiag: a build error in TypeScript sources, a located runtime + * fence in JavaScript ones. typeof needs no value and folds to Node's + * answer. A lowering marks the lowerer, so the build translates the + * modules it discovers (lowerToIr). */ +/** The classes `wasm.is` answers, by kind. */ +const WASM_CLASSES = [ + "Module", + "Instance", + "Memory", + "Table", + "Global", + "CompileError", + "LinkError", + "RuntimeError", +] as const; /** Strips the spellings that leave a value unchanged: parentheses, type * assertions, `satisfies` and non-null assertions. */ function bare(expr: ts.Expression): ts.Expression { @@ -130,3 +154,158 @@ export function lowerWebAssemblyTypeof(lowerer: Lowerer, operand: ts.Expression) } return null; } + +/** The member `WebAssembly.` names (any spelling of the namespace), + * or null. */ +function webAssemblyMember(lowerer: Lowerer, expr: ts.Expression): string | null { + const surface = webAssemblySurface(lowerer, expr); + if (surface === null || !surface.startsWith("WebAssembly.")) return null; + const member = surface.slice("WebAssembly.".length); + return member.includes(".") ? null : member; +} + +function lowerArg(lowerer: Lowerer, arg: ts.Expression): IrExpr { + return ts.isObjectLiteralExpression(arg) + ? lowerDynObjectLiteral(lowerer, arg) + : lowerer.lowerExprExpecting(arg, DYN); +} + +/** The arguments, padded with undefined to `count`; null for spreads or + * extra arguments (they stay refused). */ +function lowerArgs( + lowerer: Lowerer, + args: readonly ts.Expression[], + count: number, + loc: IrExpr["loc"], +): IrExpr[] | null { + if (args.length > count || args.some(ts.isSpreadElement)) return null; + const out = args.map((arg) => lowerArg(lowerer, arg)); + while (out.length < count) out.push(dynUndefinedExpr(loc)); + return out; +} + +function errorNew(member: string, args: IrExpr[], loc: IrExpr["loc"]): IrExpr { + const kind = (WASM_CLASSES as readonly string[]).indexOf(member); + return { + kind: "libCall", + fn: "wasm.errorNew", + args: [{ kind: "numLit", value: kind, type: F64, loc }, args[0]!, args[1]!], + type: DYN, + loc, + }; +} + +/** `WebAssembly.compile(bytes)`, `WebAssembly.instantiate(source, + * imports?)`, `WebAssembly.validate(bytes)`, and the error classes called + * without `new`. Null for anything else. */ +export function lowerWebAssemblyCall(lowerer: Lowerer, call: ts.CallExpression): IrExpr | null { + if (call.questionDotToken) return null; + const member = webAssemblyMember(lowerer, call.expression); + if (member === null) return null; + const loc = locOf(call); + const isError = member === "CompileError" || member === "LinkError" || member === "RuntimeError"; + if (member !== "compile" && member !== "instantiate" && member !== "validate" && !isError) + return null; + const used = member === "instantiate" || isError ? 2 : 1; + const args = lowerArgs(lowerer, call.arguments, used, loc); + if (args === null) return null; + lowerer.usesWebAssembly = true; + let result: IrExpr; + if (isError) result = errorNew(member, args, loc); + else if (member === "validate") + result = { kind: "libCall", fn: "wasm.validate", args: [args[0]!], type: BOOL, loc }; + else if (member === "compile") + result = { + kind: "libCall", + fn: "wasm.compile", + args: [args[0]!], + type: { kind: "promise", inner: DYN }, + loc, + }; + else + result = { + kind: "libCall", + fn: "wasm.instantiate", + args: [args[0]!, args[1]!], + type: { kind: "promise", inner: DYN }, + loc, + }; + return result; +} + +/** `new WebAssembly.Module(bytes)`, `new WebAssembly.Instance(module, + * imports?)` and the error classes. Null for anything else. */ +export function lowerWebAssemblyNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr | null { + const member = webAssemblyMember(lowerer, expr.expression); + if (member === null) return null; + const isError = member === "CompileError" || member === "LinkError" || member === "RuntimeError"; + if (member !== "Module" && member !== "Instance" && !isError) return null; + const loc = locOf(expr); + const used = member === "Module" ? 1 : 2; + const args = lowerArgs(lowerer, expr.arguments ?? [], used, loc); + if (args === null) return null; + lowerer.usesWebAssembly = true; + let result: IrExpr; + if (isError) result = errorNew(member, args, loc); + else if (member === "Module") + result = { kind: "libCall", fn: "wasm.moduleNew", args: [args[0]!], type: DYN, loc }; + else + result = { + kind: "libCall", + fn: "wasm.instanceNew", + args: [args[0]!, args[1]!], + type: DYN, + loc, + }; + return result; +} + +/** `v instanceof WebAssembly.`. Null for anything else. */ +export function lowerWebAssemblyInstanceof( + lowerer: Lowerer, + expr: ts.BinaryExpression, +): IrExpr | null { + const member = webAssemblyMember(lowerer, expr.right); + if (member === null) return null; + const kind = (WASM_CLASSES as readonly string[]).indexOf(member); + if (kind < 0) return null; + const loc = locOf(expr); + lowerer.usesWebAssembly = true; + const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN); + return { + kind: "libCall", + fn: "wasm.is", + args: [value, { kind: "numLit", value: kind, type: F64, loc }], + type: BOOL, + loc, + }; +} + +/** WebAssembly API values: `WebAssembly.compile`, `instantiate` and + * `validate` read as functions, the namespace itself (`WebAssembly`, + * `globalThis.WebAssembly`), and the global object cast to a type with a + * `WebAssembly` member (pi codemode's spelling). Null for anything else, + * which refuseWebAssemblyUse then fences. */ +export function lowerWebAssemblyValue(lowerer: Lowerer, expr: ts.Expression): IrExpr | null { + const surface = webAssemblySurface(lowerer, expr); + if (surface === null) return null; + const loc = locOf(expr); + const node = bare(expr); + const fn = (name: string, args: IrExpr[]): IrExpr => { + lowerer.usesWebAssembly = true; + return { kind: "libCall", fn: name as "wasm.namespace", args, type: DYN, loc }; + }; + if (surface === "globalThis.WebAssembly") { + // The cast spelling names the global object, not its member. + const cast = + (ts.isAsExpression(expr) || ts.isTypeAssertion(expr)) && + isGlobalThis(lowerer, expr.expression); + return cast ? fn("wasm.globalView", []) : fn("wasm.namespace", []); + } + if (surface === "WebAssembly") return fn("wasm.namespace", []); + const index = ["WebAssembly.compile", "WebAssembly.instantiate", "WebAssembly.validate"].indexOf( + surface, + ); + if (index < 0 || !ts.isPropertyAccessExpression(node)) return null; + return fn("wasm.function", [{ kind: "numLit", value: index, type: F64, loc }]); +} diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index d72faa936..1800601e7 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -11,7 +11,12 @@ import { lowerWorkerMetadata } from "./builtins/workers.js"; import { esmImportBindingKind } from "./builtins/module-bindings.js"; import { lowerReadlineProperty } from "./builtins/readline.js"; import { lowerBlobInstanceof } from "./builtins/blob.js"; -import { lowerWebAssemblyTypeof, refuseWebAssemblyUse } from "./builtins/webassembly.js"; +import { + lowerWebAssemblyInstanceof, + lowerWebAssemblyTypeof, + lowerWebAssemblyValue, + refuseWebAssemblyUse, +} from "./builtins/webassembly.js"; import { lowerKeyObjectInstanceof } from "./builtins/key-object.js"; import { lowerNetAddressInstanceof, lowerNetAddressStaticRead } from "./builtins/net-address.js"; import { isExecExceptionType, refuseExecExceptionCode } from "./builtins/errors.js"; @@ -464,7 +469,10 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { if (externalTypeSpecifier !== null) { lowerer.externalHostFence(externalTypeSpecifier, expr); } - // Every reached use of the WebAssembly API fences at its expression. + // WebAssembly API values lower; every other reached use of the API + // fences at its expression. + const webAssemblyValue = lowerWebAssemblyValue(lowerer, expr); + if (webAssemblyValue !== null) return webAssemblyValue; refuseWebAssemblyUse(lowerer, expr); if (ts.isNumericLiteral(expr)) { @@ -12514,6 +12522,8 @@ export function caughtLocalOf(lowerer: Lowerer, node: ts.Expression): IrLocal | * Folding is limited to side-effect-free operands — dropping a computed * operand would skip its effects, so those are rejected instead. */ export function lowerInstanceOf(lowerer: Lowerer, expr: ts.BinaryExpression, loc: SrcLoc): IrExpr { + const webAssembly = lowerWebAssemblyInstanceof(lowerer, expr); + if (webAssembly !== null) return webAssembly; refuseWebAssemblyUse(lowerer, expr.right); // `x instanceof net.Socket` over a union with a netSocket arm — the // h2 compat 'connect' narrowing (lower-server.ts): a union tag test. diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 4b17af697..9cc8015e8 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -26,8 +26,13 @@ import { isSettledIteratorValueRead } from "./lower-generators.js"; import { concreteCollectionNarrow } from "./collection-narrowing.js"; import { lowerWorkerMetadata } from "./builtins/workers.js"; import { fenceStaticBlobMember, lowerBlobNew, lowerStaticBlobCall } from "./builtins/blob.js"; -import { refuseWebAssemblyUse } from "./builtins/webassembly.js"; +import { + lowerWebAssemblyCall, + lowerWebAssemblyNew, + refuseWebAssemblyUse, +} from "./builtins/webassembly.js"; import { discoverWasmModules, type WasmModuleReport } from "../../wasm/discover.js"; +import { encodeBase64 } from "../../wasm/base64.js"; import { resolveRequireRuntime } from "../runtime-resolve.js"; import { lowerKeyObjectCall } from "./builtins/key-object.js"; import { hashStreamOf } from "./builtins/hash-stream.js"; @@ -176,6 +181,7 @@ import type { IrGlobal, IrLocal, IrModule, + IrWasmModule, IrParam, IrRecordShape, IrStmt, @@ -1084,6 +1090,40 @@ export function lowerToIr( diagnostics: [...result.diagnostics, ...contracts.diagnostics], }; else if (contracts.count > 0) result = { ...result, contracts }; + const discoverModules = ( + onModule?: (sha256: string, bytes: Uint8Array) => void, + ): WasmModuleReport[] => + discoverWasmModules({ + files: moduleOrder.includes(entry) ? moduleOrder : [...moduleOrder, entry], + entry: entry.fileName, + configured: options.wasmFiles ?? [], + resolveRequest: (fromFile, specifier) => { + const resolved = resolveRequireRuntime( + fromFile, + specifier, + targetPlatform, + undefined, + options.frontendServices, + ); + return resolved.ok ? resolved.value : null; + }, + ...(onModule === undefined ? {} : { onModule }), + }); + // A program that uses the WebAssembly API carries every module the build + // can see and translate (wasm/translate.ts); the rest fail at run time + // with the CompileError for untranslated bytes. + if (result.module !== null && resultLowerer.usesWebAssembly) { + const bytesByHash = new Map(); + const reports = discoverModules((sha256, bytes) => bytesByHash.set(sha256, bytes)); + const wasmModules: IrWasmModule[] = []; + for (const report of reports) { + const bytes = bytesByHash.get(report.sha256); + if (report.status !== "valid" || bytes === undefined) continue; + wasmModules.push({ sha256: report.sha256, bytes: encodeBase64(bytes) }); + } + result.module.wasmModules = wasmModules; + timing("wasm-discovery", { modules: wasmModules.length }); + } if (options.coverage !== true) return result; const remainder = new Lowerer(program, entry, moduleOrder, { frontendServices: options.frontendServices, @@ -1137,21 +1177,7 @@ export function lowerToIr( }, }; if (tiers !== undefined) covered.tiers = tiers; - const wasmModules = discoverWasmModules({ - files: moduleOrder.includes(entry) ? moduleOrder : [...moduleOrder, entry], - entry: entry.fileName, - configured: options.wasmFiles ?? [], - resolveRequest: (fromFile, specifier) => { - const resolved = resolveRequireRuntime( - fromFile, - specifier, - targetPlatform, - undefined, - options.frontendServices, - ); - return resolved.ok ? resolved.value : null; - }, - }); + const wasmModules = discoverModules(); timing("wasm-discovery", { modules: wasmModules.length }); if (wasmModules.length > 0) covered.wasmModules = wasmModules; return covered; @@ -2652,6 +2678,9 @@ export class Lowerer { readonly workerTargets: readonly ts.SourceFile[]; readonly workerTargetIdByPath = new Map(); usesWorkers = false; + /** The program uses the WebAssembly API (builtins/webassembly.ts): the + * build translates the modules it discovers. */ + usesWebAssembly = false; /** The program constructs a LifetimeRegion (lifetime-regions.ts). */ usesLifetimeRegions = false; /** Per-directory answers of experimental-import.ts's declaration-file test. */ @@ -11509,6 +11538,8 @@ export class Lowerer { // dispatch. The general identifier-call paths have no lowering for a // promise-returning ambient global, and `import` is a keyword callee no // identifier path matches. + const webAssembly = lowerWebAssemblyCall(this, expr); + if (webAssembly !== null) return webAssembly; refuseWebAssemblyUse(this, expr.expression); return ( lowerLifetimeRegionCall(this, expr) ?? @@ -11735,6 +11766,8 @@ export class Lowerer { } lowerNew(expr: ts.NewExpression): IrExpr { + const webAssembly = lowerWebAssemblyNew(this, expr); + if (webAssembly !== null) return webAssembly; refuseWebAssemblyUse(this, expr.expression, "new "); const builtin = lowerLifetimeRegionNew(this, expr) ?? diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 1aa5b1d1b..c8f8ee55a 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -1446,6 +1446,18 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { // option) holds that dynamic value too, so the whole union is dynamic. if (type.isUnionType() && ts.constituentTypes(type).some((t) => isWebAssemblyType(t, ctx))) return DYN; + // JavaScript inference merges WebAssembly.instantiate's overloads into + // `Promise & Promise`: a promise + // of a WebAssembly value either way. + if ( + type.isIntersectionType() && + ts.constituentTypes(type).every((t) => { + if (t.getSymbol()?.name !== "Promise") return false; + const arg = ctx.checker.getTypeArguments(t as ts.TypeReference)[0]; + return arg !== undefined && isWebAssemblyType(arg, ctx); + }) + ) + return { kind: "promise", inner: DYN }; // Immutable (@scriptc/types) is a deep-readonly view: the value is // still the T it maps. const immutableSource = immutableSourceType(type, ctx); diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index 56b787e18..8fa53029b 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -527,6 +527,7 @@ async function compileExecutableNative( fileHandle: features.fileHandle, fetch: features.fetch, ...(features.eventTarget ? { eventTarget: true } : {}), + ...(features.wasm ? { wasm: true } : {}), zlib: features.zlib, assert: features.assert, inspect: features.inspect, @@ -716,6 +717,7 @@ async function prepareExecutableInput( wasi: buildPlatform === "wasi", runtimeAbiMarker: outputKind === "obj", objectAudit: opts.sanitize === true, + ...(opts.sanitize === true ? { wasmBoundsChecks: true } : {}), ...inlineRcOption(opts.optimization, opts.sanitize === true), }); } catch (err) { @@ -781,6 +783,7 @@ async function prepareExecutableInput( wasi: buildPlatform === "wasi", runtimeAbiMarker: useRuntimePack, objectAudit: opts.sanitize === true, + ...(opts.sanitize === true ? { wasmBoundsChecks: true } : {}), ...inlineRcOption(opts.optimization, opts.sanitize === true), ...(opts.detachedExit === true ? { detachedExit: true } : {}), }); diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index a62046565..c6e93c268 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -132,6 +132,12 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "blob.new", "blob.fileNew", "blob.slice", + "wasm.compile", + "wasm.validate", + "wasm.instantiate", + "wasm.moduleNew", + "wasm.instanceNew", + "wasm.errorNew", "events.addAbortListener", "fetch.streamNew", "fetch.streamFrom", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index e61bb2594..1ec915409 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -106,6 +106,27 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "blob.bytes": { argTypes: [DYN], result: { kind: "promise", inner: BYTES_U8 } }, "blob.arrayBuffer": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, "blob.is": { argTypes: [DYN, F64], result: BOOL }, + /** WebAssembly (scr_wasm.c): modules translated at build time + * (wasm/translate.ts), found at run time by the SHA-256 of their bytes. + * compile and instantiate over bytes settle on a later loop turn; + * instantiate over a Module settles now, as in Node. `wasm.is` answers + * instanceof for Module, Instance, Memory, Table and Global (kinds 0-4) + * and CompileError, LinkError and RuntimeError (5-7); `wasm.errorNew` + * constructs one of the error classes (kind 5-7, message, options). */ + "wasm.compile": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "wasm.validate": { argTypes: [DYN], result: BOOL }, + "wasm.instantiate": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "wasm.moduleNew": { argTypes: [DYN], result: DYN }, + "wasm.instanceNew": { argTypes: [DYN, DYN], result: DYN }, + "wasm.is": { argTypes: [DYN, F64], result: BOOL }, + "wasm.errorNew": { argTypes: [F64, DYN, DYN], result: DYN }, + /** WebAssembly.compile (0), instantiate (1) and validate (2) as function + * values, and the namespace object holding them. */ + "wasm.function": { argTypes: [F64], result: DYN }, + "wasm.namespace": { argTypes: [], result: DYN }, + /** The global object viewed through a cast to a type with a WebAssembly + * member: an object holding the namespace. */ + "wasm.globalView": { argTypes: [], result: DYN }, "abort.timeout": { argTypes: [DYN], result: DYN }, "abort.now": { argTypes: [DYN], result: DYN }, "abort.any": { argTypes: [DYN], result: DYN }, diff --git a/packages/compiler/src/ir/function-references.test.ts b/packages/compiler/src/ir/function-references.test.ts index 0b1f9fb49..9d1e192bd 100644 --- a/packages/compiler/src/ir/function-references.test.ts +++ b/packages/compiler/src/ir/function-references.test.ts @@ -209,6 +209,8 @@ const MODULE_FIELDS: Record>, Role> = { "contracts.acyclic[]": "other", "contracts.immortalGlobals[]": "other", "contracts.programLifetime[]": "other", + "wasmModules[].sha256": "other", + "wasmModules[].bytes": "other", }; const loc = { file: "references.ts", start: 0, end: 0 }; diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 90a98a491..145038748 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -998,6 +998,20 @@ export interface IrModule { * write in the program (ir/contract-check.ts). Backends may rely on them * unconditionally. Absent when the program writes no contract. */ contracts?: IrContracts; + /** The WebAssembly modules translated into this program (wasm/ + * translate.ts), present exactly when the program uses the WebAssembly + * API (possibly empty). The backend appends each module's translation + * and emits the registry the runtime looks modules up in. */ + wasmModules?: IrWasmModule[]; +} + +/** A WebAssembly module whose bytes the build saw, validated within the + * translatable feature level. */ +export interface IrWasmModule { + /** Hex SHA-256 of the bytes. */ + sha256: string; + /** The bytes, base64. */ + bytes: string; } /** Verified contract facts, keyed by IR names. */ diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 7df85c738..125d30cec 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -43,6 +43,8 @@ export interface RuntimeFeatures { tls: boolean; tlsCa: boolean; cipher: boolean; + /** The WebAssembly API (scr_wasm.c). */ + wasm: boolean; } const DYN_ASYNC_LIB_FNS: ReadonlySet = new Set([ @@ -217,6 +219,7 @@ function scanRuntimeFeatures(mod: IrModule, stopAt?: keyof RuntimeFeatures): Run tls: false, tlsCa: false, cipher: false, + wasm: false, }; const keepGoing = (): boolean => stopAt === undefined || !features[stopAt]; let tables: TypeTables | undefined; @@ -427,6 +430,13 @@ function scanRuntimeFeatures(mod: IrModule, stopAt?: keyof RuntimeFeatures): Run // scr_cipher.c over the mbedTLS archive; DEP0182 reports through the // process-warning unit, and unknown output encodings render through // the inspect unit. + // scr_wasm.c boxes its handles and promises through the dyn-async + // unit and converts i64 values through BigInt. + if (fn.startsWith("wasm.")) { + features.wasm = true; + features.dynAsync = true; + features.bigint = true; + } if (fn === "crypto.cipherNew") { features.cipher = true; features.dynAsync = true; diff --git a/packages/compiler/src/native/sanitizer.test.ts b/packages/compiler/src/native/sanitizer.test.ts index 9047f3376..52cebcaf6 100644 --- a/packages/compiler/src/native/sanitizer.test.ts +++ b/packages/compiler/src/native/sanitizer.test.ts @@ -74,6 +74,7 @@ test.skipIf(process.platform !== "linux" && process.platform !== "darwin")( features: { workers: false, eventTarget: false, + wasm: false, regex: true, copying: false, textDecoderLegacy: false, diff --git a/packages/compiler/src/wasm/base64.ts b/packages/compiler/src/wasm/base64.ts new file mode 100644 index 000000000..122bcd4ef --- /dev/null +++ b/packages/compiler/src/wasm/base64.ts @@ -0,0 +1,61 @@ +/* Base64 for WebAssembly module bytes: decoding inline modules found in + * source text (discover.ts) and carrying translated modules on the IR + * (IrModule.wasmModules). Plain TypeScript, so the native compiler + * compiles it too. */ + +const BASE64_VALUES = (() => { + const table = new Int16Array(128).fill(-1); + const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + for (let i = 0; i < alphabet.length; i++) table[alphabet.charCodeAt(i)] = i; + // base64url spellings + table["-".charCodeAt(0)] = 62; + table["_".charCodeAt(0)] = 63; + return table; +})(); + +/** Decodes standard or URL-safe base64 (padding optional); null when the + * text is not base64. */ +export function decodeBase64(text: string): Uint8Array | null { + let end = text.length; + while (end > 0 && text.charCodeAt(end - 1) === 61) end--; + if (text.length - end > 2 || end % 4 === 1) return null; + const out = new Uint8Array(Math.floor((end * 3) / 4)); + let acc = 0; + let bits = 0; + let j = 0; + for (let i = 0; i < end; i++) { + const c = text.charCodeAt(i); + const v = c < 128 ? BASE64_VALUES[c]! : -1; + if (v < 0) return null; + acc = ((acc << 6) | v) & 0xffffff; + bits += 6; + if (bits >= 8) { + bits -= 8; + out[j++] = (acc >> bits) & 0xff; + } + } + return j === out.length ? out : out.subarray(0, j); +} + +const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** Standard base64 with padding. */ +export function encodeBase64(bytes: Uint8Array): string { + const parts: string[] = []; + let chunk = ""; + for (let i = 0; i < bytes.length; i += 3) { + const a = bytes[i]!; + const b = i + 1 < bytes.length ? bytes[i + 1]! : 0; + const c = i + 2 < bytes.length ? bytes[i + 2]! : 0; + const n = (a << 16) | (b << 8) | c; + chunk += BASE64_ALPHABET[(n >> 18) & 63]! + BASE64_ALPHABET[(n >> 12) & 63]!; + chunk += i + 1 < bytes.length ? BASE64_ALPHABET[(n >> 6) & 63]! : "="; + chunk += i + 2 < bytes.length ? BASE64_ALPHABET[n & 63]! : "="; + if (chunk.length >= 65536) { + parts.push(chunk); + chunk = ""; + } + } + parts.push(chunk); + return parts.join(""); +} diff --git a/packages/compiler/src/wasm/discover.ts b/packages/compiler/src/wasm/discover.ts index 610a389f1..856f0752f 100644 --- a/packages/compiler/src/wasm/discover.ts +++ b/packages/compiler/src/wasm/discover.ts @@ -28,6 +28,9 @@ import { trackedReadFile, } from "../frontend/input-tracker.js"; import { analyzeWasm, isWasmHeader, type WasmModuleSummary } from "./binary.js"; +import { decodeBase64 } from "./base64.js"; + +export { decodeBase64 }; export type WasmSourceKind = "path" | "inline" | "package" | "config"; @@ -56,6 +59,9 @@ export interface WasmDiscoveryInput { configured: readonly string[]; /** require.resolve from `fromFile`, or null when it does not resolve. */ resolveRequest: (fromFile: string, specifier: string) => string | null; + /** Receives each distinct module's bytes once, when it is first found + * (builds translate them). */ + onModule?: (sha256: string, bytes: Uint8Array) => void; } const SCAN_KINDS: ReadonlySet = new Set([ @@ -110,6 +116,7 @@ class Discovery { }; this.byHash.set(sha256, report); this.order.push(sha256); + this.input.onModule?.(sha256, bytes); } if (report.path === undefined && path !== undefined) report.path = path; addSource(report, source); @@ -351,40 +358,6 @@ function byteArrayLiteral(node: ts.ArrayLiteralExpression): Uint8Array | null { return out; } -const BASE64_VALUES = (() => { - const table = new Int16Array(128).fill(-1); - const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - for (let i = 0; i < alphabet.length; i++) table[alphabet.charCodeAt(i)] = i; - // base64url spellings - table["-".charCodeAt(0)] = 62; - table["_".charCodeAt(0)] = 63; - return table; -})(); - -/** Decodes standard or URL-safe base64 (padding optional); null when the - * text is not base64. */ -export function decodeBase64(text: string): Uint8Array | null { - let end = text.length; - while (end > 0 && text.charCodeAt(end - 1) === 61) end--; - if (text.length - end > 2 || end % 4 === 1) return null; - const out = new Uint8Array(Math.floor((end * 3) / 4)); - let acc = 0; - let bits = 0; - let j = 0; - for (let i = 0; i < end; i++) { - const c = text.charCodeAt(i); - const v = c < 128 ? BASE64_VALUES[c]! : -1; - if (v < 0) return null; - acc = ((acc << 6) | v) & 0xffffff; - bits += 6; - if (bits >= 8) { - bits -= 8; - out[j++] = (acc >> bits) & 0xff; - } - } - return j === out.length ? out : out.subarray(0, j); -} - /** The root directory of the npm package that contains `file` (the * directory below its innermost node_modules), or null outside one. */ export function packageRootOf(file: string): string | null { diff --git a/packages/compiler/src/wasm/module.ts b/packages/compiler/src/wasm/module.ts new file mode 100644 index 000000000..3b0dd54c0 --- /dev/null +++ b/packages/compiler/src/wasm/module.ts @@ -0,0 +1,659 @@ +/* The structure of a WebAssembly module, for the translator. + * + * binary.ts validates a module and keeps nothing but counts. This parser + * reads the parts translation needs (types, imports, functions, tables, + * memories, globals, exports, the start function, element and data + * segments, function bodies and custom sections) from bytes that binary.ts + * already accepted, so it checks nothing beyond what it must to stay in + * bounds. Constant expressions and function bodies are kept as byte ranges + * that the translator reads itself. + * + * i64 values never become JavaScript numbers: the translator reads their + * LEB128 encodings into two 32-bit halves. Plain TypeScript, so the native + * compiler compiles it too. */ + +export const VAL_I32 = 0x7f; +export const VAL_I64 = 0x7e; +export const VAL_F32 = 0x7d; +export const VAL_F64 = 0x7c; +export const VAL_FUNCREF = 0x70; +export const VAL_EXTERNREF = 0x6f; + +export const KIND_FUNC = 0; +export const KIND_TABLE = 1; +export const KIND_MEMORY = 2; +export const KIND_GLOBAL = 3; + +export interface WasmFuncType { + params: number[]; + results: number[]; +} + +/** A byte range of the module: a constant expression (through its `end` + * opcode) or a payload. */ +export interface WasmRange { + start: number; + end: number; +} + +export interface WasmImport { + module: string; + name: string; + kind: number; + /** Functions: the type index. Tables and globals: the value type. */ + type: number; + min: number; + max: number | null; + mutable: boolean; +} + +export interface WasmTable { + elemType: number; + min: number; + max: number | null; + imported: boolean; + /** A defined table's initializer (reference-types table with an init + * expression), or null for the null reference. */ + init: WasmRange | null; +} + +export interface WasmMemory { + min: number; + max: number | null; + imported: boolean; +} + +export interface WasmGlobal { + type: number; + mutable: boolean; + imported: boolean; + init: WasmRange | null; +} + +export interface WasmExport { + name: string; + kind: number; + index: number; +} + +export interface WasmElem { + mode: "active" | "passive" | "declarative"; + table: number; + offset: WasmRange | null; + elemType: number; + /** One initializer per element: a function index (>= 0), or -1 when the + * element is a constant expression in `exprs`. */ + funcs: number[]; + exprs: (WasmRange | null)[]; +} + +export interface WasmData { + mode: "active" | "passive"; + memory: number; + offset: WasmRange | null; + payload: WasmRange; +} + +export interface WasmCode { + /** Declared locals, expanded (not including parameters). */ + locals: number[]; + body: WasmRange; +} + +export interface WasmCustom { + name: string; + payload: WasmRange; +} + +export interface WasmModule { + bytes: Uint8Array; + types: WasmFuncType[]; + imports: WasmImport[]; + /** The type index of every function, imported functions first. */ + funcTypes: number[]; + importedFuncs: number; + tables: WasmTable[]; + memories: WasmMemory[]; + globals: WasmGlobal[]; + exports: WasmExport[]; + start: number | null; + elems: WasmElem[]; + datas: WasmData[]; + codes: WasmCode[]; + customs: WasmCustom[]; + /** Functions referenced outside a body (exports, element segments, + * ref.func in constant expressions): only these need a function + * reference record. Bodies add their own ref.func targets, which a valid + * module also declares in one of these places. */ + declaredRefs: Set; +} + +/** A byte cursor over a module that binary.ts validated. */ +export class WasmCursor { + bytes: Uint8Array; + pos: number; + constructor(bytes: Uint8Array, pos: number) { + this.bytes = bytes; + this.pos = pos; + } + + u8(): number { + const b = this.bytes[this.pos]; + if (b === undefined) throw new Error("wasm: unexpected end of module"); + this.pos++; + return b; + } + + u32(): number { + let result = 0; + let scale = 1; + for (;;) { + const b = this.u8(); + result += (b & 0x7f) * scale; + if ((b & 0x80) === 0) return result; + scale *= 128; + } + } + + /** A signed LEB128 of at most 33 bits. */ + s33(): number { + let result = 0; + let scale = 1; + for (;;) { + const b = this.u8(); + result += (b & 0x7f) * scale; + scale *= 128; + if ((b & 0x80) === 0) { + if (b & 0x40) result -= scale; + return result; + } + } + } + + /** A signed 32-bit LEB128 as a signed 32-bit number. */ + s32(): number { + return this.s33() | 0; + } + + /** A signed 64-bit LEB128 as its two's-complement halves [lo, hi], each + * an unsigned 32-bit number. */ + s64(): [number, number] { + let lo = 0; + let hi = 0; + let shift = 0; + let b = 0; + do { + b = this.u8(); + const bits = b & 0x7f; + if (shift < 32) { + lo = (lo | (bits << shift)) >>> 0; + if (shift > 25) hi = (hi | (bits >>> (32 - shift))) >>> 0; + } else if (shift < 64) { + hi = (hi | (bits << (shift - 32))) >>> 0; + } + shift += 7; + } while (b & 0x80); + if (shift < 64 && b & 0x40) { + // Sign-extend from bit `shift`. + if (shift < 32) { + lo = (lo | (~0 << shift)) >>> 0; + hi = 0xffffffff; + } else { + hi = (hi | (~0 << (shift - 32))) >>> 0; + } + } + return [lo, hi]; + } + + u32le(): number { + const b = this.bytes; + const p = this.pos; + this.pos += 4; + return (b[p]! | (b[p + 1]! << 8) | (b[p + 2]! << 16) | (b[p + 3]! << 24)) >>> 0; + } + + name(): string { + const length = this.u32(); + const start = this.pos; + this.pos += length; + return decodeUtf8(this.bytes, start, this.pos); + } + + /** Skips a constant expression through its `end` and answers its range. */ + constExpr(): WasmRange { + const start = this.pos; + for (;;) { + const op = this.u8(); + if (op === 0x0b) break; + skipImmediates(this, op); + } + return { start, end: this.pos }; + } + + valType(): number { + return this.u8(); + } + + /** A block type: -1 for the empty type, a value type, or a type index. */ + blockType(): + | { kind: "empty" } + | { kind: "value"; type: number } + | { kind: "index"; index: number } { + const b = this.bytes[this.pos]!; + if (b === 0x40) { + this.pos++; + return { kind: "empty" }; + } + if ( + b === VAL_I32 || + b === VAL_I64 || + b === VAL_F32 || + b === VAL_F64 || + b === VAL_FUNCREF || + b === VAL_EXTERNREF + ) { + this.pos++; + return { kind: "value", type: b }; + } + return { kind: "index", index: this.s33() }; + } +} + +function decodeUtf8(bytes: Uint8Array, start: number, end: number): string { + let out = ""; + let i = start; + while (i < end) { + const b = bytes[i]!; + let cp = b; + let need = 0; + if (b >= 0xf0) { + cp = b & 0x07; + need = 3; + } else if (b >= 0xe0) { + cp = b & 0x0f; + need = 2; + } else if (b >= 0xc0) { + cp = b & 0x1f; + need = 1; + } + for (let k = 1; k <= need; k++) cp = cp * 64 + (bytes[i + k]! & 0x3f); + out += String.fromCodePoint(cp); + i += need + 1; + } + return out; +} + +/** Reads the immediates of opcode `op` (already consumed). Covers the + * translatable feature level; anything else was refused before + * translation. */ +export function skipImmediates(c: WasmCursor, op: number): void { + switch (op) { + case 0x02: + case 0x03: + case 0x04: + c.blockType(); + return; + case 0x0c: + case 0x0d: + case 0x10: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0xd2: + c.u32(); + return; + case 0x0e: { + const n = c.u32(); + for (let i = 0; i <= n; i++) c.u32(); + return; + } + case 0x11: + c.u32(); + c.u32(); + return; + case 0x1c: { + const n = c.u32(); + for (let i = 0; i < n; i++) c.valType(); + return; + } + case 0x3f: + case 0x40: + // The memory index (a LEB128 zero; V8 accepts long encodings). + c.u32(); + return; + case 0x41: + c.s32(); + return; + case 0x42: + c.s64(); + return; + case 0x43: + c.pos += 4; + return; + case 0x44: + c.pos += 8; + return; + case 0xd0: + c.valType(); + return; + case 0xfc: { + const sub = c.u32(); + switch (sub) { + case 8: + c.u32(); + c.u32(); + return; + case 9: + case 13: + case 15: + case 16: + case 17: + c.u32(); + return; + case 10: + c.u32(); + c.u32(); + return; + case 11: + c.u32(); + return; + case 12: + case 14: + c.u32(); + c.u32(); + return; + default: + return; + } + } + default: + if (op >= 0x28 && op <= 0x3e) { + c.u32(); + c.u32(); + } + return; + } +} + +function limits(c: WasmCursor): { min: number; max: number | null } { + const flags = c.u8(); + const min = c.u32(); + const max = flags & 0x01 ? c.u32() : null; + return { min, max }; +} + +/** Parses a module binary.ts reported as valid within the translatable + * feature level. */ +export function parseWasmModule(bytes: Uint8Array): WasmModule { + const m: WasmModule = { + bytes, + types: [], + imports: [], + funcTypes: [], + importedFuncs: 0, + tables: [], + memories: [], + globals: [], + exports: [], + start: null, + elems: [], + datas: [], + codes: [], + customs: [], + declaredRefs: new Set(), + }; + const c = new WasmCursor(bytes, 8); + while (c.pos < bytes.length) { + const id = c.u8(); + const size = c.u32(); + const end = c.pos + size; + switch (id) { + case 0: { + const name = c.name(); + m.customs.push({ name, payload: { start: c.pos, end } }); + break; + } + case 1: { + const n = c.u32(); + for (let i = 0; i < n; i++) { + c.u8(); // 0x60 + const params: number[] = []; + const np = c.u32(); + for (let k = 0; k < np; k++) params.push(c.valType()); + const results: number[] = []; + const nr = c.u32(); + for (let k = 0; k < nr; k++) results.push(c.valType()); + m.types.push({ params, results }); + } + break; + } + case 2: { + const n = c.u32(); + for (let i = 0; i < n; i++) { + const module = c.name(); + const name = c.name(); + const kind = c.u8(); + const imp: WasmImport = { + module, + name, + kind, + type: 0, + min: 0, + max: null, + mutable: false, + }; + if (kind === KIND_FUNC) { + imp.type = c.u32(); + m.funcTypes.push(imp.type); + m.importedFuncs++; + } else if (kind === KIND_TABLE) { + imp.type = c.valType(); + const l = limits(c); + imp.min = l.min; + imp.max = l.max; + m.tables.push({ + elemType: imp.type, + min: l.min, + max: l.max, + imported: true, + init: null, + }); + } else if (kind === KIND_MEMORY) { + const l = limits(c); + imp.min = l.min; + imp.max = l.max; + m.memories.push({ min: l.min, max: l.max, imported: true }); + } else { + imp.type = c.valType(); + imp.mutable = c.u8() === 1; + m.globals.push({ type: imp.type, mutable: imp.mutable, imported: true, init: null }); + } + m.imports.push(imp); + } + break; + } + case 3: { + const n = c.u32(); + for (let i = 0; i < n; i++) m.funcTypes.push(c.u32()); + break; + } + case 4: { + const n = c.u32(); + for (let i = 0; i < n; i++) { + let init: WasmRange | null = null; + if (c.bytes[c.pos] === 0x40) { + // table with an initializer: 0x40 0x00 tabletype expr + c.pos += 2; + const elemType = c.valType(); + const l = limits(c); + init = c.constExpr(); + m.tables.push({ elemType, min: l.min, max: l.max, imported: false, init }); + continue; + } + const elemType = c.valType(); + const l = limits(c); + m.tables.push({ elemType, min: l.min, max: l.max, imported: false, init }); + } + break; + } + case 5: { + const n = c.u32(); + for (let i = 0; i < n; i++) { + const l = limits(c); + m.memories.push({ min: l.min, max: l.max, imported: false }); + } + break; + } + case 6: { + const n = c.u32(); + for (let i = 0; i < n; i++) { + const type = c.valType(); + const mutable = c.u8() === 1; + const init = c.constExpr(); + noteConstRefs(m, init); + m.globals.push({ type, mutable, imported: false, init }); + } + break; + } + case 7: { + const n = c.u32(); + for (let i = 0; i < n; i++) { + const name = c.name(); + const kind = c.u8(); + const index = c.u32(); + m.exports.push({ name, kind, index }); + if (kind === KIND_FUNC) m.declaredRefs.add(index); + } + break; + } + case 8: + m.start = c.u32(); + break; + case 9: { + const n = c.u32(); + for (let i = 0; i < n; i++) m.elems.push(elemSegment(m, c)); + break; + } + case 10: { + const n = c.u32(); + for (let i = 0; i < n; i++) { + const size = c.u32(); + const bodyEnd = c.pos + size; + const locals: number[] = []; + const groups = c.u32(); + for (let g = 0; g < groups; g++) { + const count = c.u32(); + const type = c.valType(); + for (let k = 0; k < count; k++) locals.push(type); + } + m.codes.push({ locals, body: { start: c.pos, end: bodyEnd } }); + c.pos = bodyEnd; + } + break; + } + case 11: { + const n = c.u32(); + for (let i = 0; i < n; i++) { + const flags = c.u32(); + if (flags === 1) { + const size = c.u32(); + m.datas.push({ + mode: "passive", + memory: 0, + offset: null, + payload: { start: c.pos, end: c.pos + size }, + }); + c.pos += size; + continue; + } + const memory = flags === 2 ? c.u32() : 0; + const offset = c.constExpr(); + const size = c.u32(); + m.datas.push({ + mode: "active", + memory, + offset, + payload: { start: c.pos, end: c.pos + size }, + }); + c.pos += size; + } + break; + } + default: + // 12 (data count) and anything binary.ts accepted without content + // translation needs. + break; + } + c.pos = end; + } + return m; +} + +function elemSegment(m: WasmModule, c: WasmCursor): WasmElem { + const flags = c.u32(); + const passiveOrDeclarative = (flags & 1) !== 0; + const explicitTable = (flags & 2) !== 0; + const usesExprs = (flags & 4) !== 0; + let mode: WasmElem["mode"] = "active"; + if (passiveOrDeclarative) mode = explicitTable ? "declarative" : "passive"; + let table = 0; + let offset: WasmRange | null = null; + if (!passiveOrDeclarative) { + if (explicitTable) table = c.u32(); + offset = c.constExpr(); + } + let elemType = VAL_FUNCREF; + if (passiveOrDeclarative || explicitTable) { + // elemkind (0x00 = funcref) or a reference type + const b = c.u8(); + elemType = usesExprs ? b : VAL_FUNCREF; + } + const n = c.u32(); + const funcs: number[] = []; + const exprs: (WasmRange | null)[] = []; + for (let i = 0; i < n; i++) { + if (usesExprs) { + const expr = c.constExpr(); + const direct = refFuncOf(m.bytes, expr); + if (direct !== null) { + funcs.push(direct); + exprs.push(null); + m.declaredRefs.add(direct); + } else { + noteConstRefs(m, expr); + funcs.push(-1); + exprs.push(expr); + } + } else { + const f = c.u32(); + funcs.push(f); + exprs.push(null); + m.declaredRefs.add(f); + } + } + return { mode, table, offset, elemType, funcs, exprs }; +} + +/** The function of a `ref.func f; end` expression, or null. */ +function refFuncOf(bytes: Uint8Array, expr: WasmRange): number | null { + if (bytes[expr.start] !== 0xd2) return null; + const c = new WasmCursor(bytes, expr.start + 1); + const f = c.u32(); + return c.pos === expr.end - 1 && bytes[c.pos] === 0x0b ? f : null; +} + +function noteConstRefs(m: WasmModule, expr: WasmRange): void { + const c = new WasmCursor(m.bytes, expr.start); + while (c.pos < expr.end) { + const op = c.u8(); + if (op === 0xd2) { + m.declaredRefs.add(c.u32()); + continue; + } + skipImmediates(c, op); + } +} diff --git a/packages/compiler/src/wasm/translate.test.ts b/packages/compiler/src/wasm/translate.test.ts new file mode 100644 index 000000000..a9ef58248 --- /dev/null +++ b/packages/compiler/src/wasm/translate.test.ts @@ -0,0 +1,145 @@ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { describe, expect, test } from "vitest"; +import { analyzeWasm } from "./binary.js"; +import { decodeBase64, encodeBase64 } from "./base64.js"; +import { WasmCursor, parseWasmModule } from "./module.js"; +import { + signatureHash, + stackCheckedFunctions, + translateWasmModule, + wasmSymbolPrefix, +} from "./translate.js"; + +const SHA = new Uint8Array(32).fill(0xab); + +/** (module (func (export "add") (param i32 i32) (result i32) local.get 0 local.get 1 i32.add) + * (memory (export "mem") 1) (data (i32.const 8) "hi")) */ +const ADD = new Uint8Array([ + 0, 97, 115, 109, 1, 0, 0, 0, 1, 7, 1, 96, 2, 127, 127, 1, 127, 3, 2, 1, 0, 5, 3, 1, 0, 1, 7, 13, + 2, 3, 97, 100, 100, 0, 0, 3, 109, 101, 109, 2, 0, 10, 9, 1, 7, 0, 32, 0, 32, 1, 106, 11, 11, 8, 1, + 0, 65, 8, 11, 2, 104, 105, +]); + +/** Every top-level line must be one the native helper's text partitioner + * accepts (native/llvm-codegen/src/partition.cpp), so translated modules + * keep the program on its concurrent parsing path. */ +function topLevelLines(text: string[]): string[] { + const lines: string[] = []; + for (const part of text) { + let inFunction = false; + for (const line of part.split("\n")) { + if (inFunction) { + if (line === "}") inFunction = false; + continue; + } + if (line.startsWith("define ")) inFunction = true; + lines.push(line); + } + } + return lines; +} + +describe("translateWasmModule", () => { + test("emits functions, thunks, data and the descriptor in the helper's grammar", () => { + const out = translateWasmModule(ADD, SHA, { boundsChecks: false }); + const prefix = wasmSymbolPrefix(SHA); + expect(prefix).toBe("scr_wasm_abababababababab"); + expect(out.descriptor).toBe(`@${prefix}_desc`); + const text = out.text.join("\n"); + expect(text).toContain(`define internal i32 @${prefix}_f0(ptr %inst, i32 %p0, i32 %p1)`); + expect(text).toContain(`define internal void @${prefix}_x0(ptr %inst, ptr %a, ptr %r)`); + expect(text).toContain(`c"hi"`); + expect(text).toContain(`"disable-tail-calls"="true"`); + for (const line of topLevelLines(out.text)) { + expect( + line === "" || /^(define internal |@[\w.$-]+ = (private|internal) )/.test(line), + line, + ).toBe(true); + } + for (const decl of out.decls) expect(decl).toMatch(/^declare /); + }); + + test("checks memory accesses explicitly only when asked", () => { + const guarded = translateWasmModule(ADD, SHA, { boundsChecks: false }).text.join("\n"); + const checked = translateWasmModule(ADD, SHA, { boundsChecks: true }).text.join("\n"); + expect(guarded).not.toContain("%msize"); + expect(checked).toContain("%msize"); + }); + + test("translates every valid module of the WebAssembly spec test suite", () => { + const cases = readFileSync(join(import.meta.dirname, "../../test/wasm-spec-cases.txt"), "utf8") + .split("\n") + .filter((line) => line !== "" && !line.startsWith("#")); + let translated = 0; + for (const line of cases) { + const [, , where, b64] = line.split(" "); + const bytes = decodeBase64(b64!)!; + if (analyzeWasm(bytes).status !== "valid") continue; + try { + translateWasmModule(bytes, SHA, { boundsChecks: false }); + } catch (error) { + throw new Error(`${where}: ${error instanceof Error ? error.message : String(error)}`); + } + translated++; + } + expect(translated).toBeGreaterThan(800); + }); +}); + +describe("module parsing", () => { + test("reads the parts translation needs", () => { + const m = parseWasmModule(ADD); + expect(m.types).toEqual([{ params: [0x7f, 0x7f], results: [0x7f] }]); + expect(m.exports.map((e) => e.name)).toEqual(["add", "mem"]); + expect(m.memories).toEqual([{ min: 1, max: null, imported: false }]); + expect(m.datas[0]!.mode).toBe("active"); + expect([...m.declaredRefs]).toEqual([0]); + }); + + test("decodes signed 64-bit LEB128 into two's-complement halves", () => { + const halves = (bytes: number[]): [number, number] => + new WasmCursor(new Uint8Array(bytes), 0).s64(); + expect(halves([0x7f])).toEqual([0xffffffff, 0xffffffff]); + expect(halves([0x80, 0x80, 0x80, 0x80, 0x10])).toEqual([0, 1]); + expect(halves([0xff, 0xff, 0xff, 0xff, 0x0f])).toEqual([0xffffffff, 0]); + expect(halves([0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f])).toEqual([ + 0, 0x80000000, + ]); + expect(halves([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00])).toEqual([ + 0xffffffff, 0x7fffffff, + ]); + }); +}); + +describe("stack checks", () => { + test("only functions through which the stack can grow without bound check it", () => { + // f0 <-> f1 recurse mutually, f2 recurses on itself, f3 calls f0 once. + const calls = new Uint8Array([ + 0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 3, 5, 4, 0, 0, 0, 0, 10, 21, 4, 4, 0, 16, 1, + 11, 4, 0, 16, 0, 11, 4, 0, 16, 2, 11, 4, 0, 16, 0, 11, + ]); + expect([...stackCheckedFunctions(parseWasmModule(calls))].sort()).toEqual([0, 1, 2]); + expect(stackCheckedFunctions(parseWasmModule(ADD)).size).toBe(0); + // Only code without the fault handler checks explicitly. + const checked = translateWasmModule(calls, SHA, { boundsChecks: true }).text.join("\n"); + expect(checked.split("@scr_wasm_stack_limit").length - 1).toBe(3); + const guarded = translateWasmModule(calls, SHA, { boundsChecks: false }).text.join("\n"); + expect(guarded).not.toContain("@scr_wasm_stack_limit"); + }); +}); + +describe("helpers", () => { + test("equal signatures share their identity across modules", () => { + expect(signatureHash("ii:i")).toBe(signatureHash("ii:i")); + expect(signatureHash("ii:i")).not.toBe(signatureHash("i:i")); + expect(signatureHash(":")).toMatch(/^u0x[0-9a-f]{16}$/); + }); + + test("base64 round-trips module bytes", () => { + expect(encodeBase64(ADD)).toBe(Buffer.from(ADD).toString("base64")); + expect(decodeBase64(encodeBase64(ADD))).toEqual(ADD); + expect(encodeBase64(new Uint8Array([1]))).toBe("AQ=="); + expect(encodeBase64(new Uint8Array([1, 2]))).toBe("AQI="); + }); +}); diff --git a/packages/compiler/src/wasm/translate.ts b/packages/compiler/src/wasm/translate.ts new file mode 100644 index 000000000..e0ce27be5 --- /dev/null +++ b/packages/compiler/src/wasm/translate.ts @@ -0,0 +1,2173 @@ +/* WebAssembly to LLVM IR. + * + * Translates one validated module (binary.ts accepted it within the + * translatable feature level) to LLVM assembly that the program's emitter + * appends to its own module, so the native helper optimizes, partitions and + * caches it with the program. The runtime (scr_wasm.c) implements the + * JavaScript API over the descriptor this emits; scr_wasm_abi.h is the + * contract both sides follow. + * + * Shape of the output: + * - one internal function per wasm function, taking the instance as its + * first parameter (`ptr %inst`) and the wasm values directly (i32, i64, + * float, double; references are pointers). Several results return as a + * literal struct. An imported function is a stub that packs its + * arguments and calls scr_wasm_import_call. + * - one thunk per exported function, `void (ptr inst, ptr args, ptr + * results)` over 64-bit slots, which the runtime calls under its trap + * guard; + * - an init function (globals, table initializers, active element and + * data segments); the descriptor names the start function; + * - constant data (segments, names, signatures) and the descriptor. + * + * The instance layout (scr_wasm_abi.h): host at 0, memory base at 8, + * memory object at 16, function reference records at 24, then one pointer + * per table and one cell pointer per global. + * + * Memory accesses compute `base + zext(address) + offset` in 64 bits. With + * guard pages (64-bit hosts) the runtime reserves enough address space that + * every such address past the memory faults, so accesses are unchecked and + * the base is loaded once per function (the memory never moves). With + * explicit bounds checks (sanitizer builds and hosts without the fault + * handler) the base and byte length live in function-local slots that are + * reloaded after every call and memory.grow. + * + * Locals, block results and loop parameters are allocas; LLVM promotes them + * to SSA values. Traps call scr_wasm_trap, which never returns. Plain + * TypeScript without bigint, so the native compiler compiles it too. */ +import { + KIND_FUNC, + KIND_GLOBAL, + KIND_MEMORY, + KIND_TABLE, + VAL_EXTERNREF, + VAL_F32, + VAL_F64, + VAL_FUNCREF, + VAL_I32, + VAL_I64, + WasmCursor, + parseWasmModule, + skipImmediates, + type WasmFuncType, + type WasmModule, + type WasmRange, +} from "./module.js"; + +/** Trap codes (scr_wasm_abi.h SCR_WASM_TRAP_*). */ +export const TRAP_UNREACHABLE = 1; +export const TRAP_MEMORY_OOB = 2; +export const TRAP_DIV_BY_ZERO = 3; +export const TRAP_DIV_UNREPRESENTABLE = 4; +export const TRAP_REM_BY_ZERO = 5; +export const TRAP_FLOAT_UNREPRESENTABLE = 6; +export const TRAP_TABLE_OOB = 7; +export const TRAP_SIGNATURE = 8; +export const TRAP_NULL = 9; +/** scr_wasm_abi.h SCR_WASM_TRAP_EXHAUSTION. */ +export const TRAP_EXHAUSTION = 100; + +/** The descriptor ABI version both sides agree on. */ +export const WASM_ABI_VERSION = 1; + +/** Instance slot offsets (bytes). */ +const OFF_MEMBASE = 8; +const OFF_MEMORY = 16; +const OFF_FUNCREFS = 24; +const OFF_TABLES = 32; +/** sizeof(ScrWasmFuncRef). */ +const FUNCREF_SIZE = 24; + +export interface WasmTranslateOptions { + /** Explicit bounds checks instead of guard pages. */ + boundsChecks: boolean; +} + +export interface WasmTranslation { + /** External declarations, one line each. */ + decls: string[]; + /** Definitions in the emitter's top-level grammar. */ + text: string[]; + /** The descriptor's symbol (internal). */ + descriptor: string; +} + +/** A construct the translator does not support in an otherwise valid module. */ +export class WasmTranslateError extends Error {} + +/** Attributes of translated functions. Recursion must exhaust the stack + * as it does in V8, so LLVM may not turn self-recursion into loops (tail + * recursion elimination, including its accumulator form, which would make + * `f(x) + 1` recursion loop forever) or calls into jumps. */ +const FUNC_ATTRS = `nounwind "disable-tail-calls"="true"`; + +const RUNTIME_DECLS = [ + "declare void @scr_wasm_trap(i32) noreturn nounwind cold", + "declare void @scr_wasm_import_call(ptr, i32, ptr, ptr)", + "declare i32 @scr_wasm_memory_grow(ptr, i32)", + "declare void @scr_wasm_memory_fill(ptr, i32, i32, i32)", + "declare void @scr_wasm_memory_copy(ptr, i32, i32, i32)", + "declare void @scr_wasm_memory_init(ptr, i32, i32, i32, i32)", + "declare void @scr_wasm_data_drop(ptr, i32)", + "declare ptr @scr_wasm_table_get(ptr, i32, i32)", + "declare void @scr_wasm_table_set(ptr, i32, i32, ptr)", + "declare i32 @scr_wasm_table_grow(ptr, i32, ptr, i32)", + "declare void @scr_wasm_table_fill(ptr, i32, i32, ptr, i32)", + "declare void @scr_wasm_table_copy(ptr, i32, i32, i32, i32, i32)", + "declare void @scr_wasm_table_init(ptr, i32, i32, i32, i32, i32)", + "declare void @scr_wasm_elem_drop(ptr, i32)", + "declare void @scr_wasm_global_set_ref(ptr, ptr)", +]; + +function llType(t: number): string { + switch (t) { + case VAL_I32: + return "i32"; + case VAL_I64: + return "i64"; + case VAL_F32: + return "float"; + case VAL_F64: + return "double"; + case VAL_FUNCREF: + case VAL_EXTERNREF: + return "ptr"; + default: + throw new WasmTranslateError(`value type 0x${t.toString(16)} is not supported`); + } +} + +function zeroOf(t: number): string { + switch (t) { + case VAL_I32: + case VAL_I64: + return "0"; + case VAL_F32: + case VAL_F64: + return "0.0"; + default: + return "null"; + } +} + +/** The runtime's signature letter of a value type. */ +function sigChar(t: number): string { + switch (t) { + case VAL_I32: + return "i"; + case VAL_I64: + return "I"; + case VAL_F32: + return "f"; + case VAL_F64: + return "F"; + case VAL_FUNCREF: + return "r"; + case VAL_EXTERNREF: + return "x"; + default: + throw new WasmTranslateError(`value type 0x${t.toString(16)} is not supported`); + } +} + +function sigString(ft: WasmFuncType): string { + let s = ""; + for (const p of ft.params) s += sigChar(p); + s += ":"; + for (const r of ft.results) s += sigChar(r); + return s; +} + +function retType(results: readonly number[]): string { + if (results.length === 0) return "void"; + if (results.length === 1) return llType(results[0]!); + return `{ ${results.map(llType).join(", ")} }`; +} + +function hex8(n: number): string { + return (n >>> 0).toString(16).padStart(8, "0"); +} + +/** An i64 constant from its halves, in LLVM's unsigned hexadecimal form. */ +function i64Lit(lo: number, hi: number): string { + return `u0x${hex8(hi)}${hex8(lo)}`; +} + +/** The canonical signature identity call_indirect compares: two + * independent 32-bit FNV-1a hashes of the signature text. Equal signatures + * in different modules get the same identity. */ +export function signatureHash(sig: string): string { + let a = 0x811c9dc5; + let b = 0x01000193 ^ 0x5bd1e995; + for (let i = 0; i < sig.length; i++) { + const c = sig.charCodeAt(i); + a = Math.imul(a ^ c, 0x01000193); + b = Math.imul(b ^ c, 0x01000193) ^ (b >>> 13); + } + return i64Lit(a >>> 0, b >>> 0); +} + +/** UTF-8 bytes of a string. */ +function utf8Bytes(text: string): number[] { + const out: number[] = []; + for (let i = 0; i < text.length; i++) { + const cp = text.codePointAt(i)!; + if (cp > 0xffff) i++; + if (cp < 0x80) out.push(cp); + else if (cp < 0x800) out.push(0xc0 | (cp >> 6), 0x80 | (cp & 0x3f)); + else if (cp < 0x10000) + out.push(0xe0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f)); + else { + out.push( + 0xf0 | (cp >> 18), + 0x80 | ((cp >> 12) & 0x3f), + 0x80 | ((cp >> 6) & 0x3f), + 0x80 | (cp & 0x3f), + ); + } + } + return out; +} + +/** An LLVM c"..." string body for bytes. */ +function cBytes(bytes: Uint8Array, start: number, end: number): string { + let s = ""; + for (let i = start; i < end; i++) { + const b = bytes[i]!; + if (b >= 0x20 && b < 0x7f && b !== 0x22 && b !== 0x5c) s += String.fromCharCode(b); + else s += "\\" + (b < 16 ? "0" : "") + b.toString(16).toUpperCase(); + } + return s; +} + +interface StackValue { + v: string; + t: number; + /** The line of the load that produced the value (this.lines). */ + load?: number; +} + +interface Frame { + kind: "block" | "loop" | "if" | "func"; + params: number[]; + results: number[]; + /** Branch target: the loop header, or the end label. */ + target: string; + end: string; + /** Allocas the values of a branch to this frame are stored in: the loop + * parameters for a loop, the results otherwise. */ + branchSlots: string[]; + /** Allocas of the results at the frame's end (loops: their own). */ + resultSlots: string[]; + height: number; + /** An if whose else branch has not started. */ + elseLabel: string | null; + /** The parameter values of an if, for its implicit else. */ + ifParams: StackValue[]; + /** The start of the frame was reachable. */ + live: boolean; +} + +class Lines { + lines: string[] = []; + add(line: string): void { + this.lines.push(line); + } +} + +/** One module's translation. */ +class ModuleTranslator { + m: WasmModule; + p: string; + opts: WasmTranslateOptions; + text: string[] = []; + /** Functions that need a reference record. */ + refs: Set; + /** Functions whose entry checks the stack (stackCheckedFunctions). */ + stackChecked: Set; + typeHashes: string[]; + memoryCount: number; + + constructor(m: WasmModule, prefix: string, opts: WasmTranslateOptions) { + this.m = m; + this.p = prefix; + this.opts = opts; + this.refs = new Set(m.declaredRefs); + this.typeHashes = m.types.map((t) => signatureHash(sigString(t))); + this.memoryCount = m.memories.length; + if (m.memories.length > 1) throw new WasmTranslateError("multiple memories are not supported"); + this.stackChecked = stackCheckedFunctions(m); + } + + fn(index: number): string { + return `@${this.p}_f${index}`; + } + + funcType(index: number): WasmFuncType { + return this.m.types[this.m.funcTypes[index]!]!; + } + + globalSlot(index: number): number { + return OFF_TABLES + 8 * (this.m.tables.length + index); + } + + tableSlot(index: number): number { + return OFF_TABLES + 8 * index; + } + + signature(ft: WasmFuncType, name: string): string { + const params = ["ptr %inst"]; + for (let i = 0; i < ft.params.length; i++) params.push(`${llType(ft.params[i]!)} %p${i}`); + return `${retType(ft.results)} ${name}(${params.join(", ")})`; + } + + translate(): void { + const m = this.m; + for (let i = 0; i < m.importedFuncs; i++) this.importStub(i); + for (let i = 0; i < m.codes.length; i++) { + const index = m.importedFuncs + i; + const f = new FunctionTranslator(this, index); + this.text.push(...f.translate()); + } + } + + importStub(index: number): void { + const ft = this.funcType(index); + const out: string[] = []; + out.push(`define internal ${this.signature(ft, this.fn(index))} nounwind {`); + out.push(`entry:`); + const np = Math.max(1, ft.params.length); + const nr = Math.max(1, ft.results.length); + out.push(` %args = alloca [${np} x i64], align 8`); + out.push(` %res = alloca [${nr} x i64], align 8`); + for (let i = 0; i < ft.params.length; i++) { + const slot = toSlot(out, ft.params[i]!, `%p${i}`, `a${i}`); + out.push(` %ap${i} = getelementptr i64, ptr %args, i64 ${i}`); + out.push(` store i64 ${slot}, ptr %ap${i}`); + } + out.push(` %host = load ptr, ptr %inst`); + out.push(` call void @scr_wasm_import_call(ptr %host, i32 ${index}, ptr %args, ptr %res)`); + emitSlotReturn(out, ft.results, "%res"); + out.push(`}`); + this.text.push(out.join("\n")); + } + + /** The thunk the runtime calls for exported function `index`. */ + exportThunk(index: number): string { + const name = `@${this.p}_x${index}`; + const ft = this.funcType(index); + const out: string[] = []; + out.push(`define internal void ${name}(ptr %inst, ptr %a, ptr %r) nounwind {`); + out.push(`entry:`); + const args: string[] = ["ptr %inst"]; + for (let i = 0; i < ft.params.length; i++) { + out.push(` %ap${i} = getelementptr i64, ptr %a, i64 ${i}`); + out.push(` %as${i} = load i64, ptr %ap${i}`); + args.push(`${llType(ft.params[i]!)} ${fromSlot(out, ft.params[i]!, `%as${i}`, `a${i}`)}`); + } + const ret = retType(ft.results); + if (ft.results.length === 0) { + out.push(` call void ${this.fn(index)}(${args.join(", ")})`); + } else { + out.push(` %res = call ${ret} ${this.fn(index)}(${args.join(", ")})`); + for (let i = 0; i < ft.results.length; i++) { + let v = "%res"; + if (ft.results.length > 1) { + out.push(` %rv${i} = extractvalue ${ret} %res, ${i}`); + v = `%rv${i}`; + } + const slot = toSlot(out, ft.results[i]!, v, `r${i}`); + out.push(` %rp${i} = getelementptr i64, ptr %r, i64 ${i}`); + out.push(` store i64 ${slot}, ptr %rp${i}`); + } + } + out.push(` ret void`); + out.push(`}`); + this.text.push(out.join("\n")); + return name; + } + + /** Emits the init function: globals, table initializers and segments, + * in the specification's order. The runtime calls the start function + * (which takes and returns nothing) separately. */ + initFunction(): string { + const m = this.m; + const name = `@${this.p}_init`; + const f = new FunctionTranslator(this, -1); + const body = f.lines; + // Globals. + for (let g = 0; g < m.globals.length; g++) { + const global = m.globals[g]!; + if (global.imported || global.init === null) continue; + const v = f.constExpr(global.init); + const cell = f.loadPtrSlot(this.globalSlot(g)); + if (global.type === VAL_EXTERNREF) { + // A defined externref global starts as null or another global's + // value; the runtime's setter retains it. + body.add(` call void @scr_wasm_global_set_ref(ptr ${cell}, ptr ${v})`); + } else { + body.add(` store ${llType(global.type)} ${v}, ptr ${cell}`); + } + } + // Defined tables with an initializer. + for (let t = 0; t < m.tables.length; t++) { + const table = m.tables[t]!; + if (table.imported || table.init === null) continue; + const v = f.constExpr(table.init); + body.add( + ` call void @scr_wasm_table_fill(ptr %inst, i32 ${t}, i32 0, ptr ${v}, i32 ${table.min})`, + ); + } + // Element segments: active ones initialize their table and drop; + // declarative ones only drop. + for (let s = 0; s < m.elems.length; s++) { + const seg = m.elems[s]!; + if (seg.mode === "active") { + const offset = f.constExpr(seg.offset!); + body.add( + ` call void @scr_wasm_table_init(ptr %inst, i32 ${seg.table}, i32 ${s}, i32 ${offset}, i32 0, i32 ${seg.funcs.length})`, + ); + } + if (seg.mode !== "passive") body.add(` call void @scr_wasm_elem_drop(ptr %inst, i32 ${s})`); + } + for (let s = 0; s < m.datas.length; s++) { + const seg = m.datas[s]!; + if (seg.mode !== "active") continue; + const offset = f.constExpr(seg.offset!); + const length = seg.payload.end - seg.payload.start; + body.add( + ` call void @scr_wasm_memory_init(ptr %inst, i32 ${s}, i32 ${offset}, i32 0, i32 ${length})`, + ); + body.add(` call void @scr_wasm_data_drop(ptr %inst, i32 ${s})`); + } + body.add(` ret void`); + const out = [`define internal void ${name}(ptr %inst) nounwind {`, `entry:`]; + out.push(...f.entry.lines); + out.push(...body.lines); + out.push(`}`); + this.text.push(out.join("\n")); + return name; + } + + /** Constant data and the descriptor. */ + descriptor(sha256: Uint8Array): string { + const m = this.m; + const p = this.p; + const lines: string[] = []; + // First, so that every function its constant expressions reference has + // a record in the tables below. + const init = this.initFunction(); + let strings = 0; + const cstr = (text: readonly number[]): string => { + const sym = `@${p}_s${strings++}`; + const bytes = new Uint8Array(text); + lines.push( + `${sym} = private unnamed_addr constant [${bytes.length + 1} x i8] c"${cBytes(bytes, 0, bytes.length)}\\00"`, + ); + return sym; + }; + const textStr = (text: string): { sym: string; len: number } => { + const bytes = utf8Bytes(text); + return { sym: cstr(bytes), len: bytes.length }; + }; + // Imports. + const importRows: string[] = []; + let funcImport = 0; + let tableImport = 0; + let memoryImport = 0; + let globalImport = 0; + for (const imp of m.imports) { + const mod = textStr(imp.module); + const name = textStr(imp.name); + let index = 0; + let type = ""; + if (imp.kind === KIND_FUNC) { + index = funcImport++; + type = sigString(m.types[imp.type]!); + } else if (imp.kind === KIND_TABLE) { + index = tableImport++; + type = sigChar(imp.type); + } else if (imp.kind === KIND_MEMORY) { + index = memoryImport++; + } else { + index = globalImport++; + type = sigChar(imp.type); + } + const typeSym = cstr(utf8Bytes(type)); + importRows.push( + `{ ptr, i64, ptr, i64, i64, i64, ptr } { ptr ${mod.sym}, i64 ${mod.len}, ptr ${name.sym}, i64 ${name.len}, i64 ${imp.kind}, i64 ${index}, ptr ${typeSym} }`, + ); + } + const importType = "{ ptr, i64, ptr, i64, i64, i64, ptr }"; + const importsSym = `@${p}_imports`; + lines.push( + `${importsSym} = private constant [${importRows.length} x ${importType}] [${importRows.join(", ")}]`, + ); + // Exports. + const thunks = new Map(); + const exportRows: string[] = []; + for (const ex of m.exports) { + const name = textStr(ex.name); + let type = ""; + let call = "null"; + if (ex.kind === KIND_FUNC) { + type = sigString(this.funcType(ex.index)); + let thunk = thunks.get(ex.index); + if (thunk === undefined) { + thunk = this.exportThunk(ex.index); + thunks.set(ex.index, thunk); + } + call = thunk; + } else if (ex.kind === KIND_TABLE) { + type = sigChar(m.tables[ex.index]!.elemType); + } else if (ex.kind === KIND_GLOBAL) { + type = sigChar(m.globals[ex.index]!.type); + } + const typeSym = cstr(utf8Bytes(type)); + exportRows.push( + `{ ptr, i64, i64, i64, ptr, ptr } { ptr ${name.sym}, i64 ${name.len}, i64 ${ex.kind}, i64 ${ex.index}, ptr ${typeSym}, ptr ${call} }`, + ); + } + const exportType = "{ ptr, i64, i64, i64, ptr, ptr }"; + const exportsSym = `@${p}_exports`; + lines.push( + `${exportsSym} = private constant [${exportRows.length} x ${exportType}] [${exportRows.join(", ")}]`, + ); + // Function references: code, signature identity and signature text for + // every function a reference can name. + const nf = m.funcTypes.length; + const codes: string[] = []; + const types: string[] = []; + const sigs: string[] = []; + const sigSyms = new Map(); + for (let f = 0; f < nf; f++) { + const referenced = this.refs.has(f); + codes.push(referenced ? `ptr ${this.fn(f)}` : "ptr null"); + types.push(`i64 ${this.typeHashes[m.funcTypes[f]!]!}`); + const sig = sigString(this.funcType(f)); + let sym = sigSyms.get(sig); + if (sym === undefined) { + sym = cstr(utf8Bytes(sig)); + sigSyms.set(sig, sym); + } + sigs.push(`ptr ${sym}`); + } + const codesSym = `@${p}_codes`; + const typesSym = `@${p}_types`; + const sigsSym = `@${p}_sigs`; + lines.push(`${codesSym} = private constant [${nf} x ptr] [${codes.join(", ")}]`); + lines.push(`${typesSym} = private constant [${nf} x i64] [${types.join(", ")}]`); + lines.push(`${sigsSym} = private constant [${nf} x ptr] [${sigs.join(", ")}]`); + // Tables. + const tableRows = m.tables.map( + (t) => + `{ i64, i64, i64, i64 } { i64 ${sigChar(t.elemType).charCodeAt(0)}, i64 ${t.min}, i64 ${t.max === null ? -1 : t.max}, i64 ${t.imported ? 1 : 0} }`, + ); + const tablesSym = `@${p}_tables`; + lines.push( + `${tablesSym} = private constant [${tableRows.length} x { i64, i64, i64, i64 }] [${tableRows.join(", ")}]`, + ); + // Globals. + const globalRows = m.globals.map( + (g) => + `{ i64, i64, i64 } { i64 ${sigChar(g.type).charCodeAt(0)}, i64 ${g.mutable ? 1 : 0}, i64 ${g.imported ? 1 : 0} }`, + ); + const globalsSym = `@${p}_globals`; + lines.push( + `${globalsSym} = private constant [${globalRows.length} x { i64, i64, i64 }] [${globalRows.join(", ")}]`, + ); + // Data segments. + const dataRows: string[] = []; + for (let s = 0; s < m.datas.length; s++) { + const seg = m.datas[s]!; + const len = seg.payload.end - seg.payload.start; + if (len === 0) { + dataRows.push(`{ ptr, i64 } { ptr null, i64 0 }`); + continue; + } + const sym = `@${p}_d${s}`; + lines.push( + `${sym} = private unnamed_addr constant [${len} x i8] c"${cBytes(m.bytes, seg.payload.start, seg.payload.end)}", align 1`, + ); + dataRows.push(`{ ptr, i64 } { ptr ${sym}, i64 ${len} }`); + } + const datasSym = `@${p}_datas`; + lines.push( + `${datasSym} = private constant [${dataRows.length} x { ptr, i64 }] [${dataRows.join(", ")}]`, + ); + // Element segments: a function index, -1 for null, or -(2 + g) for the + // value of global g. + const elemRows: string[] = []; + for (let s = 0; s < m.elems.length; s++) { + const seg = m.elems[s]!; + const items: string[] = []; + for (let k = 0; k < seg.funcs.length; k++) { + const f = seg.funcs[k]!; + if (f >= 0) { + items.push(`i64 ${f}`); + continue; + } + items.push(`i64 ${this.elemExprCode(seg.exprs[k]!)}`); + } + let itemsRef = "ptr null"; + if (items.length > 0) { + const sym = `@${p}_e${s}`; + lines.push(`${sym} = private constant [${items.length} x i64] [${items.join(", ")}]`); + itemsRef = `ptr ${sym}`; + } + elemRows.push( + `{ i64, i64, ptr } { i64 ${sigChar(seg.elemType).charCodeAt(0)}, i64 ${items.length}, ${itemsRef} }`, + ); + } + const elemsSym = `@${p}_elems`; + lines.push( + `${elemsSym} = private constant [${elemRows.length} x { i64, i64, ptr }] [${elemRows.join(", ")}]`, + ); + const memory = m.memories[0]; + const sha: string[] = []; + for (let i = 0; i < 32; i++) sha.push(`i8 ${sha256[i]!}`); + const desc = `@${p}_desc`; + const fields = [ + `[32 x i8] [${sha.join(", ")}]`, + `i64 ${m.bytes.length}`, + `i64 ${WASM_ABI_VERSION}`, + `i64 ${this.opts.boundsChecks ? 1 : 0}`, + `i64 ${m.imports.length}`, + `ptr ${importsSym}`, + `i64 ${m.exports.length}`, + `ptr ${exportsSym}`, + `i64 ${nf}`, + `i64 ${m.importedFuncs}`, + `ptr ${codesSym}`, + `ptr ${typesSym}`, + `ptr ${sigsSym}`, + `i64 ${m.tables.length}`, + `ptr ${tablesSym}`, + `i64 ${this.memoryCount}`, + `i64 ${memory === undefined ? 0 : memory.min}`, + `i64 ${memory === undefined || memory.max === null ? -1 : memory.max}`, + `i64 ${m.globals.length}`, + `ptr ${globalsSym}`, + `i64 ${m.datas.length}`, + `ptr ${datasSym}`, + `i64 ${m.elems.length}`, + `ptr ${elemsSym}`, + `ptr ${init}`, + `ptr ${m.start === null ? "null" : this.fn(m.start)}`, + ]; + const descType = + "{ [32 x i8], i64, i64, i64, i64, ptr, i64, ptr, i64, i64, ptr, ptr, ptr, i64, ptr, i64, i64, i64, i64, ptr, i64, ptr, i64, ptr, ptr, ptr }"; + lines.push(`${desc} = internal constant ${descType} { ${fields.join(", ")} }`); + this.text.push(lines.join("\n")); + return desc; + } + + /** The element-segment code of a non-ref.func constant expression. */ + elemExprCode(expr: WasmRange): number { + const c = new WasmCursor(this.m.bytes, expr.start); + const op = c.u8(); + if (op === 0xd0) { + c.valType(); + if (c.u8() === 0x0b) return -1; + } else if (op === 0x23) { + const g = c.u32(); + if (c.u8() === 0x0b) return -(2 + g); + } + throw new WasmTranslateError( + "element segment initializers other than ref.null, ref.func and global.get are not supported", + ); + } +} + +/** Store a value as a 64-bit slot; answers the slot operand. */ +function toSlot(out: string[], t: number, v: string, tag: string): string { + switch (t) { + case VAL_I32: + out.push(` %${tag}z = zext i32 ${v} to i64`); + return `%${tag}z`; + case VAL_I64: + return v; + case VAL_F32: + out.push(` %${tag}b = bitcast float ${v} to i32`); + out.push(` %${tag}z = zext i32 %${tag}b to i64`); + return `%${tag}z`; + case VAL_F64: + out.push(` %${tag}z = bitcast double ${v} to i64`); + return `%${tag}z`; + default: + out.push(` %${tag}z = ptrtoint ptr ${v} to i64`); + return `%${tag}z`; + } +} + +function fromSlot(out: string[], t: number, slot: string, tag: string): string { + switch (t) { + case VAL_I32: + out.push(` %${tag}v = trunc i64 ${slot} to i32`); + return `%${tag}v`; + case VAL_I64: + return slot; + case VAL_F32: + out.push(` %${tag}t = trunc i64 ${slot} to i32`); + out.push(` %${tag}v = bitcast i32 %${tag}t to float`); + return `%${tag}v`; + case VAL_F64: + out.push(` %${tag}v = bitcast i64 ${slot} to double`); + return `%${tag}v`; + default: + out.push(` %${tag}v = inttoptr i64 ${slot} to ptr`); + return `%${tag}v`; + } +} + +function emitSlotReturn(out: string[], results: readonly number[], buffer: string): void { + if (results.length === 0) { + out.push(` ret void`); + return; + } + const vals: string[] = []; + for (let i = 0; i < results.length; i++) { + out.push(` %rp${i} = getelementptr i64, ptr ${buffer}, i64 ${i}`); + out.push(` %rs${i} = load i64, ptr %rp${i}`); + vals.push(fromSlot(out, results[i]!, `%rs${i}`, `r${i}`)); + } + if (results.length === 1) { + out.push(` ret ${llType(results[0]!)} ${vals[0]}`); + return; + } + const ret = retType(results); + let agg = "undef"; + for (let i = 0; i < results.length; i++) { + out.push(` %agg${i} = insertvalue ${ret} ${agg}, ${llType(results[i]!)} ${vals[i]}, ${i}`); + agg = `%agg${i}`; + } + out.push(` ret ${ret} ${agg}`); +} + +const LOAD_INFO: Record = { + // opcode: [result type, memory type, bytes, extension] + 0x28: [VAL_I32, "i32", 4, ""], + 0x29: [VAL_I64, "i64", 8, ""], + 0x2a: [VAL_F32, "float", 4, ""], + 0x2b: [VAL_F64, "double", 8, ""], + 0x2c: [VAL_I32, "i8", 1, "sext"], + 0x2d: [VAL_I32, "i8", 1, "zext"], + 0x2e: [VAL_I32, "i16", 2, "sext"], + 0x2f: [VAL_I32, "i16", 2, "zext"], + 0x30: [VAL_I64, "i8", 1, "sext"], + 0x31: [VAL_I64, "i8", 1, "zext"], + 0x32: [VAL_I64, "i16", 2, "sext"], + 0x33: [VAL_I64, "i16", 2, "zext"], + 0x34: [VAL_I64, "i32", 4, "sext"], + 0x35: [VAL_I64, "i32", 4, "zext"], +}; + +const STORE_INFO: Record = { + 0x36: [VAL_I32, "i32", 4], + 0x37: [VAL_I64, "i64", 8], + 0x38: [VAL_F32, "float", 4], + 0x39: [VAL_F64, "double", 8], + 0x3a: [VAL_I32, "i8", 1], + 0x3b: [VAL_I32, "i16", 2], + 0x3c: [VAL_I64, "i8", 1], + 0x3d: [VAL_I64, "i16", 2], + 0x3e: [VAL_I64, "i32", 4], +}; + +/** Translates one function body (index >= 0) or hosts the init function's + * constant expressions (index -1). */ +class FunctionTranslator { + mt: ModuleTranslator; + m: WasmModule; + index: number; + ft: WasmFuncType; + entry = new Lines(); + lines = new Lines(); + stack: StackValue[] = []; + frames: Frame[] = []; + localTypes: number[] = []; + next = 0; + labels = 0; + live = true; + trapLabels = new Map(); + /** Guard mode: the memory base, loaded once in the entry block. */ + baseValue: string | null = null; + checked: boolean; + + constructor(mt: ModuleTranslator, index: number) { + this.mt = mt; + this.m = mt.m; + this.index = index; + this.ft = index >= 0 ? mt.funcType(index) : { params: [], results: [] }; + this.checked = mt.opts.boundsChecks; + } + + tmp(): string { + return `%v${this.next++}`; + } + + label(hint: string): string { + return `${hint}${this.labels++}`; + } + + add(line: string): void { + this.lines.add(line); + } + + emit(expr: string): string { + const v = this.tmp(); + this.add(` ${v} = ${expr}`); + return v; + } + + push(v: string, t: number): void { + this.stack.push({ v, t }); + } + + pop(): StackValue { + const v = this.stack.pop(); + if (v === undefined) throw new Error("wasm translator: operand stack underflow"); + return v; + } + + popN(n: number): StackValue[] { + const out = this.stack.splice(this.stack.length - n, n); + if (out.length !== n) throw new Error("wasm translator: operand stack underflow"); + return out; + } + + /** Starts a new basic block. */ + startBlock(label: string): void { + this.add(`${label}:`); + } + + alloca(type: string): string { + const v = `%s${this.next++}`; + this.entry.add(` ${v} = alloca ${type}`); + return v; + } + + slotPtr(offset: number): string { + if (offset === 0) return "%inst"; + return this.emit(`getelementptr inbounds i8, ptr %inst, i64 ${offset}`); + } + + loadPtrSlot(offset: number): string { + return this.emit(`load ptr, ptr ${this.slotPtr(offset)}, align 8`); + } + + trap(code: number): string { + let label = this.trapLabels.get(code); + if (label === undefined) { + label = `trap${code}`; + this.trapLabels.set(code, label); + } + return label; + } + + // ── memory ────────────────────────────────────────────────────────── + + /** Checked mode: the slots holding the base and byte length. */ + memSlots: { base: string; size: string } | null = null; + + refreshMemory(): void { + if (!this.checked || this.memSlots === null) return; + // From the memory object, not the instance: a memory another instance + // (or JavaScript) grew may have moved. + const mem = this.loadPtrSlot(OFF_MEMORY); + const base = this.emit(`load ptr, ptr ${mem}, align 8`); + this.add(` store ptr ${base}, ptr ${this.memSlots.base}`); + const sizePtr = this.emit(`getelementptr inbounds i8, ptr ${mem}, i64 8`); + const size = this.emit(`load i64, ptr ${sizePtr}, align 8`); + this.add(` store i64 ${size}, ptr ${this.memSlots.size}`); + } + + base(): string { + if (this.checked) { + return this.emit(`load ptr, ptr ${this.memSlots!.base}`); + } + if (this.baseValue === null) { + this.baseValue = "%membase"; + } + return this.baseValue; + } + + /** The address of an access of `bytes` bytes at `addr + offset`. */ + address(addr: string, offset: number, bytes: number): string { + const wide = this.emit(`zext i32 ${addr} to i64`); + const ea = offset === 0 ? wide : this.emit(`add i64 ${wide}, ${offset}`); + if (this.checked) { + const size = this.emit(`load i64, ptr ${this.memSlots!.size}`); + const endAddr = this.emit(`add i64 ${ea}, ${bytes}`); + const oob = this.emit(`icmp ugt i64 ${endAddr}, ${size}`); + const ok = this.label("ok"); + this.add(` br i1 ${oob}, label %${this.trap(TRAP_MEMORY_OOB)}, label %${ok}`); + this.startBlock(ok); + } + return this.emit(`getelementptr i8, ptr ${this.base()}, i64 ${ea}`); + } + + // ── constant expressions ──────────────────────────────────────────── + + constExpr(range: WasmRange): string { + const c = new WasmCursor(this.m.bytes, range.start); + const stack: string[] = []; + for (;;) { + const op = c.u8(); + if (op === 0x0b) break; + switch (op) { + case 0x41: + stack.push(String(c.s32())); + break; + case 0x42: { + const [lo, hi] = c.s64(); + stack.push(i64Lit(lo, hi)); + break; + } + case 0x43: + stack.push(this.emit(`bitcast i32 ${c.u32le() | 0} to float`)); + break; + case 0x44: { + const lo = c.u32le(); + const hi = c.u32le(); + stack.push(this.emit(`bitcast i64 ${i64Lit(lo, hi)} to double`)); + break; + } + case 0x23: { + const g = c.u32(); + const cell = this.loadPtrSlot(this.mt.globalSlot(g)); + stack.push(this.emit(`load ${llType(this.m.globals[g]!.type)}, ptr ${cell}`)); + break; + } + case 0xd0: + c.valType(); + stack.push("null"); + break; + case 0xd2: + stack.push(this.funcRef(c.u32())); + break; + case 0x6a: + case 0x6b: + case 0x6c: + case 0x7c: + case 0x7d: + case 0x7e: { + const b = stack.pop()!; + const a = stack.pop()!; + const t = op < 0x70 ? "i32" : "i64"; + const name = + op === 0x6a || op === 0x7c ? "add" : op === 0x6b || op === 0x7d ? "sub" : "mul"; + stack.push(this.emit(`${name} ${t} ${a}, ${b}`)); + break; + } + default: + throw new WasmTranslateError( + `constant expression opcode 0x${op.toString(16)} is not supported`, + ); + } + } + return stack[stack.length - 1]!; + } + + funcRef(f: number): string { + this.mt.refs.add(f); + const records = this.loadPtrSlot(OFF_FUNCREFS); + return this.emit(`getelementptr inbounds i8, ptr ${records}, i64 ${f * FUNCREF_SIZE}`); + } + + // ── control ───────────────────────────────────────────────────────── + + blockSig(c: WasmCursor): { params: number[]; results: number[] } { + const bt = c.blockType(); + if (bt.kind === "empty") return { params: [], results: [] }; + if (bt.kind === "value") return { params: [], results: [bt.type] }; + const t = this.m.types[bt.index]!; + return { params: t.params.slice(), results: t.results.slice() }; + } + + slotsFor(types: readonly number[]): string[] { + return types.map((t) => this.alloca(llType(t))); + } + + storeTo(slots: readonly string[], values: readonly StackValue[]): void { + for (let i = 0; i < slots.length; i++) { + const v = values[i]!; + this.add(` store ${llType(v.t)} ${v.v}, ptr ${slots[i]}`); + } + } + + loadFrom(slots: readonly string[], types: readonly number[]): void { + for (let i = 0; i < slots.length; i++) { + const t = types[i]!; + this.push(this.emit(`load ${llType(t)}, ptr ${slots[i]}`), t); + } + } + + /** Branch to the frame `depth` levels out (the stack keeps its values). */ + branch(depth: number): void { + const f = this.frames[this.frames.length - 1 - depth]!; + const n = f.branchSlots.length; + if (n > 0) this.storeTo(f.branchSlots, this.stack.slice(this.stack.length - n)); + this.add(` br label %${f.target}`); + } + + /** The label of a block that branches to `depth`, for conditional + * branches and tables: the target itself when no values travel. */ + branchEdge(depth: number, pending: string[]): string { + const f = this.frames[this.frames.length - 1 - depth]!; + if (f.branchSlots.length === 0) return f.target; + const edge = this.label("edge"); + const saved = this.lines; + const edgeLines = new Lines(); + this.lines = edgeLines; + this.startBlock(edge); + this.branch(depth); + this.lines = saved; + pending.push(...edgeLines.lines); + return edge; + } + + goDead(): void { + this.live = false; + } + + pushFrame(kind: Frame["kind"], sig: { params: number[]; results: number[] }): Frame { + const end = this.label("end"); + const frame: Frame = { + kind, + params: sig.params, + results: sig.results, + target: end, + end, + branchSlots: [], + resultSlots: this.slotsFor(sig.results), + height: this.stack.length - sig.params.length, + elseLabel: null, + ifParams: [], + live: true, + }; + frame.branchSlots = frame.resultSlots; + this.frames.push(frame); + return frame; + } + + /** Skips dead code from just after a terminator to the `else` or `end` + * of the current frame; answers the opcode it stopped at (consumed). */ + skipDead(c: WasmCursor): number { + let depth = 0; + for (;;) { + const op = c.u8(); + if (op === 0x02 || op === 0x03 || op === 0x04) { + c.blockType(); + depth++; + continue; + } + if (op === 0x0b) { + if (depth === 0) return op; + depth--; + continue; + } + if (op === 0x05 && depth === 0) return op; + skipImmediates(c, op); + } + } + + translate(): string[] { + const ft = this.ft; + const code = this.m.codes[this.index - this.m.importedFuncs]!; + // Locals. + const localSlots: string[] = []; + this.localTypes = ft.params.concat(code.locals); + for (let i = 0; i < this.localTypes.length; i++) { + const t = this.localTypes[i]!; + const slot = `%l${i}`; + localSlots.push(slot); + this.entry.add(` ${slot} = alloca ${llType(t)}`); + } + for (let i = 0; i < ft.params.length; i++) { + this.entry.add(` store ${llType(ft.params[i]!)} %p${i}, ptr %l${i}`); + } + for (let i = ft.params.length; i < this.localTypes.length; i++) { + const t = this.localTypes[i]!; + this.entry.add(` store ${llType(t)} ${zeroOf(t)}, ptr %l${i}`); + } + if (this.checked && this.mt.memoryCount > 0) { + this.memSlots = { base: "%mbase", size: "%msize" }; + this.entry.add(` %mbase = alloca ptr`); + this.entry.add(` %msize = alloca i64`); + } + // The function frame: branches to it return. + const ret = this.label("ret"); + const fnFrame: Frame = { + kind: "func", + params: [], + results: ft.results, + target: ret, + end: ret, + branchSlots: [], + resultSlots: this.slotsFor(ft.results), + height: 0, + elseLabel: null, + ifParams: [], + live: true, + }; + fnFrame.branchSlots = fnFrame.resultSlots; + this.frames.push(fnFrame); + if (this.memSlots !== null) this.refreshMemory(); + const c = new WasmCursor(this.m.bytes, code.body.start); + this.body(c, code.body.end); + // Epilogue. + const out: string[] = []; + out.push(`define internal ${this.mt.signature(ft, this.mt.fn(this.index))} ${FUNC_ATTRS} {`); + out.push(`entry:`); + out.push(...this.entry.lines); + if (!this.checked && this.baseValue !== null) { + out.push(` %membase.p = getelementptr inbounds i8, ptr %inst, i64 ${OFF_MEMBASE}`); + out.push(` %membase = load ptr, ptr %membase.p, align 8`); + } + if (this.checked && this.mt.stackChecked.has(this.index)) { + // Without the fault handler, stack exhaustion is an explicit check of + // the stack pointer against the runtime's guard for the running stack + // (thread or async fiber), in the functions through which the stack + // can grow without bound (stackCheckedFunctions). + // The address of a frame slot stands for the stack pointer; unlike + // llvm.stacksave it constrains no other code. + out.push(` %sp = alloca i8, align 1`); + out.push(` %sp.i = ptrtoint ptr %sp to i64`); + out.push(` %limit.p = call ptr @llvm.threadlocal.address.p0(ptr @scr_wasm_stack_limit)`); + out.push(` %limit = load i64, ptr %limit.p, align 8`); + out.push(` %exhausted = icmp ult i64 %sp.i, %limit`); + out.push(` br i1 %exhausted, label %exhausted.trap, label %body`); + out.push(`exhausted.trap:`); + out.push(` call void @scr_wasm_trap(i32 ${TRAP_EXHAUSTION})`); + out.push(` unreachable`); + } else { + out.push(` br label %body`); + } + out.push(`body:`); + out.push(...this.lines.lines); + for (const [code2, label] of this.trapLabels) { + out.push(`${label}:`); + out.push(` call void @scr_wasm_trap(i32 ${code2})`); + out.push(` unreachable`); + } + out.push(`}`); + return [out.join("\n")]; + } + + /** The function body; returns at the function's final `end`. */ + body(c: WasmCursor, end: number): void { + while (c.pos < end) { + if (!this.live) { + const op = this.skipDead(c); + if (op === 0x05) this.opElse(); + else if (this.opEnd()) return; + continue; + } + const op = c.u8(); + if (op === 0x0b) { + if (this.opEnd()) return; + continue; + } + this.instruction(c, op); + } + } + + /** `end`: closes the innermost frame; true when that was the function. */ + opEnd(): boolean { + const f = this.frames[this.frames.length - 1]!; + if (this.live) { + const n = f.results.length; + this.storeTo(f.resultSlots, this.stack.slice(this.stack.length - n)); + this.add(` br label %${f.end}`); + } + if (f.elseLabel !== null) { + // An if without else: the implicit else passes its parameters on. + this.startBlock(f.elseLabel); + if (f.live) { + this.storeTo(f.resultSlots, f.ifParams); + } + this.add(` br label %${f.end}`); + f.elseLabel = null; + } + this.frames.pop(); + this.stack.length = f.height; + this.startBlock(f.end); + if (f.kind === "func") { + if (f.results.length === 0) this.add(` ret void`); + else { + this.loadFrom(f.resultSlots, f.results); + const vals = this.popN(f.results.length); + if (vals.length === 1) this.add(` ret ${llType(vals[0]!.t)} ${vals[0]!.v}`); + else { + const rt = retType(f.results); + let agg = "undef"; + for (let i = 0; i < vals.length; i++) { + agg = this.emit(`insertvalue ${rt} ${agg}, ${llType(vals[i]!.t)} ${vals[i]!.v}, ${i}`); + } + this.add(` ret ${rt} ${agg}`); + } + } + return true; + } + this.loadFrom(f.resultSlots, f.results); + this.live = true; + return false; + } + + opElse(): void { + const f = this.frames[this.frames.length - 1]!; + if (this.live) { + const n = f.results.length; + this.storeTo(f.resultSlots, this.stack.slice(this.stack.length - n)); + this.add(` br label %${f.end}`); + } + this.stack.length = f.height; + this.startBlock(f.elseLabel!); + f.elseLabel = null; + for (const v of f.ifParams) this.stack.push(v); + this.live = f.live; + if (!f.live) { + // The if itself was dead: its else branch is too. + this.add(` unreachable`); + } + } + + call(index: number): void { + const ft = this.mt.funcType(index); + const args = this.popN(ft.params.length); + const argText = ["ptr %inst", ...args.map((a) => `${llType(a.t)} ${a.v}`)].join(", "); + this.callWith(this.mt.fn(index), ft, argText); + } + + callWith(callee: string, ft: WasmFuncType, argText: string): void { + const rt = retType(ft.results); + if (ft.results.length === 0) { + this.add(` call void ${callee}(${argText})`); + } else { + const r = this.emit(`call ${rt} ${callee}(${argText})`); + if (ft.results.length === 1) this.push(r, ft.results[0]!); + else + for (let i = 0; i < ft.results.length; i++) + this.push(this.emit(`extractvalue ${rt} ${r}, ${i}`), ft.results[i]!); + } + this.refreshMemory(); + } + + callIndirect(typeIndex: number, table: number): void { + const ft = this.m.types[typeIndex]!; + const idx = this.pop(); + const args = this.popN(ft.params.length); + const t = this.loadPtrSlot(this.mt.tableSlot(table)); + const sizePtr = this.emit(`getelementptr inbounds i8, ptr ${t}, i64 8`); + const size = this.emit(`load i32, ptr ${sizePtr}, align 8`); + const inRange = this.emit(`icmp ult i32 ${idx.v}, ${size}`); + const ok = this.label("ci"); + this.add(` br i1 ${inRange}, label %${ok}, label %${this.trap(TRAP_TABLE_OOB)}`); + this.startBlock(ok); + const elems = this.emit(`load ptr, ptr ${t}, align 8`); + const wide = this.emit(`zext i32 ${idx.v} to i64`); + const slot = this.emit(`getelementptr inbounds ptr, ptr ${elems}, i64 ${wide}`); + const rec = this.emit(`load ptr, ptr ${slot}, align 8`); + const isNull = this.emit(`icmp eq ptr ${rec}, null`); + const nn = this.label("cn"); + this.add(` br i1 ${isNull}, label %${this.trap(TRAP_SIGNATURE)}, label %${nn}`); + this.startBlock(nn); + const typePtr = this.emit(`getelementptr inbounds i8, ptr ${rec}, i64 8`); + const type = this.emit(`load i64, ptr ${typePtr}, align 8`); + const same = this.emit(`icmp eq i64 ${type}, ${this.mt.typeHashes[typeIndex]}`); + const go = this.label("cg"); + this.add(` br i1 ${same}, label %${go}, label %${this.trap(TRAP_SIGNATURE)}`); + this.startBlock(go); + const codePtr = this.emit(`load ptr, ptr ${rec}, align 8`); + const instPtr = this.emit(`getelementptr inbounds i8, ptr ${rec}, i64 16`); + const inst = this.emit(`load ptr, ptr ${instPtr}, align 8`); + const argText = [`ptr ${inst}`, ...args.map((a) => `${llType(a.t)} ${a.v}`)].join(", "); + this.callWith(codePtr, ft, argText); + } + + /** Integer division and remainder with wasm's traps. */ + divRem(op: number, t: string): void { + const b = this.pop(); + const a = this.pop(); + const ty = b.t; + const zero = this.emit(`icmp eq ${t} ${b.v}, 0`); + const signed = op === 0x6d || op === 0x6f || op === 0x7f || op === 0x81; + const rem = op === 0x6f || op === 0x70 || op === 0x81 || op === 0x82; + const nz = this.label("nz"); + this.add( + ` br i1 ${zero}, label %${this.trap(rem ? TRAP_REM_BY_ZERO : TRAP_DIV_BY_ZERO)}, label %${nz}`, + ); + this.startBlock(nz); + const min = t === "i32" ? "-2147483648" : "-9223372036854775808"; + if (signed && !rem) { + const isMin = this.emit(`icmp eq ${t} ${a.v}, ${min}`); + const isNeg1 = this.emit(`icmp eq ${t} ${b.v}, -1`); + const ovf = this.emit(`and i1 ${isMin}, ${isNeg1}`); + const okl = this.label("dv"); + this.add(` br i1 ${ovf}, label %${this.trap(TRAP_DIV_UNREPRESENTABLE)}, label %${okl}`); + this.startBlock(okl); + this.push(this.emit(`sdiv ${t} ${a.v}, ${b.v}`), ty); + return; + } + if (signed && rem) { + // INT_MIN % -1 is 0 in wasm (LLVM's srem would be undefined). + const isNeg1 = this.emit(`icmp eq ${t} ${b.v}, -1`); + const divisor = this.emit(`select i1 ${isNeg1}, ${t} 1, ${t} ${b.v}`); + this.push(this.emit(`srem ${t} ${a.v}, ${divisor}`), ty); + return; + } + this.push(this.emit(`${rem ? "urem" : "udiv"} ${t} ${a.v}, ${b.v}`), ty); + } + + /** Trapping float-to-int conversion. */ + truncTrap(op: number): void { + const x = this.pop(); + const from = x.t === VAL_F32 ? "float" : "double"; + // [lower bound exclusive?, lower, upper (exclusive)] as exact doubles. + let lo = ""; + let loInclusive = false; + let hi = ""; + let to = "i32"; + let signed = true; + switch (op) { + case 0xa8: // i32.trunc_f32_s + case 0xaa: // i32.trunc_f64_s + lo = op === 0xa8 ? "-2147483648.0" : "-2147483649.0"; + loInclusive = op === 0xa8; + hi = "2147483648.0"; + break; + case 0xa9: + case 0xab: + lo = "-1.0"; + hi = "4294967296.0"; + signed = false; + break; + case 0xae: + case 0xb0: + lo = "-9223372036854775808.0"; + loInclusive = true; + hi = "9223372036854775808.0"; + to = "i64"; + break; + default: + lo = "-1.0"; + hi = "18446744073709551616.0"; + to = "i64"; + signed = false; + break; + } + const d = from === "double" ? x.v : this.emit(`fpext float ${x.v} to double`); + const above = this.emit(`fcmp ${loInclusive ? "oge" : "ogt"} double ${d}, ${hexDouble(lo)}`); + const below = this.emit(`fcmp olt double ${d}, ${hexDouble(hi)}`); + const ok = this.emit(`and i1 ${above}, ${below}`); + const okl = this.label("cv"); + this.add(` br i1 ${ok}, label %${okl}, label %${this.trap(TRAP_FLOAT_UNREPRESENTABLE)}`); + this.startBlock(okl); + this.push( + this.emit(`${signed ? "fptosi" : "fptoui"} ${from} ${x.v} to ${to}`), + to === "i32" ? VAL_I32 : VAL_I64, + ); + } + + unaryIntrinsic(name: string, t: string, vt: number, extra = ""): void { + const a = this.pop(); + this.push(this.emit(`call ${t} @llvm.${name}(${t} ${a.v}${extra})`), vt); + } + + binaryIntrinsic(name: string, t: string, vt: number): void { + const b = this.pop(); + const a = this.pop(); + this.push(this.emit(`call ${t} @llvm.${name}(${t} ${a.v}, ${t} ${b.v})`), vt); + } + + binary(instr: string, t: string, vt: number): void { + const b = this.pop(); + const a = this.pop(); + this.push(this.emit(`${instr} ${t} ${a.v}, ${b.v}`), vt); + } + + compare(pred: string, t: string, float: boolean): void { + const b = this.pop(); + const a = this.pop(); + const r = this.emit(`${float ? "fcmp" : "icmp"} ${pred} ${t} ${a.v}, ${b.v}`); + this.push(this.emit(`zext i1 ${r} to i32`), VAL_I32); + } + + eqz(t: string): void { + const a = this.pop(); + const r = this.emit(`icmp eq ${t} ${a.v}, 0`); + this.push(this.emit(`zext i1 ${r} to i32`), VAL_I32); + } + + shift(instr: string, t: string, vt: number): void { + const b = this.pop(); + const a = this.pop(); + const masked = this.emit(`and ${t} ${b.v}, ${t === "i32" ? 31 : 63}`); + this.push(this.emit(`${instr} ${t} ${a.v}, ${masked}`), vt); + } + + rotate(name: string, t: string, vt: number): void { + const b = this.pop(); + const a = this.pop(); + this.push(this.emit(`call ${t} @llvm.${name}.${t}(${t} ${a.v}, ${t} ${a.v}, ${t} ${b.v})`), vt); + } + + convert(instr: string, from: string, to: string, vt: number): void { + const a = this.pop(); + this.push(this.emit(`${instr} ${from} ${a.v} to ${to}`), vt); + } + + instruction(c: WasmCursor, op: number): void { + switch (op) { + case 0x00: // unreachable + this.add(` br label %${this.trap(TRAP_UNREACHABLE)}`); + this.goDead(); + return; + case 0x01: + return; + case 0x02: { + // block + const sig = this.blockSig(c); + this.pushFrame("block", sig); + return; + } + case 0x03: { + // loop + const sig = this.blockSig(c); + const f = this.pushFrame("loop", sig); + f.target = this.label("loop"); + f.branchSlots = this.slotsFor(sig.params); + const params = this.popN(sig.params.length); + this.storeTo(f.branchSlots, params); + this.add(` br label %${f.target}`); + this.startBlock(f.target); + this.loadFrom(f.branchSlots, sig.params); + return; + } + case 0x04: { + // if + const sig = this.blockSig(c); + const cond = this.pop(); + const f = this.pushFrame("if", sig); + f.ifParams = this.stack.slice(this.stack.length - sig.params.length); + const then = this.label("then"); + f.elseLabel = this.label("else"); + const test = this.emit(`icmp ne i32 ${cond.v}, 0`); + this.add(` br i1 ${test}, label %${then}, label %${f.elseLabel}`); + this.startBlock(then); + return; + } + case 0x05: + this.opElse(); + return; + case 0x0c: { + const depth = c.u32(); + this.branch(depth); + this.goDead(); + return; + } + case 0x0d: { + const depth = c.u32(); + const cond = this.pop(); + const test = this.emit(`icmp ne i32 ${cond.v}, 0`); + const pending: string[] = []; + const target = this.branchEdge(depth, pending); + const cont = this.label("br"); + this.add(` br i1 ${test}, label %${target}, label %${cont}`); + for (const line of pending) this.add(line); + this.startBlock(cont); + return; + } + case 0x0e: { + const n = c.u32(); + const depths: number[] = []; + for (let i = 0; i < n; i++) depths.push(c.u32()); + const def = c.u32(); + const idx = this.pop(); + const pending: string[] = []; + const edges = new Map(); + const edgeOf = (d: number): string => { + let e = edges.get(d); + if (e === undefined) { + e = this.branchEdge(d, pending); + edges.set(d, e); + } + return e; + }; + const cases = depths.map((d, i) => `i32 ${i}, label %${edgeOf(d)}`); + this.add(` switch i32 ${idx.v}, label %${edgeOf(def)} [${cases.join(" ")}]`); + for (const line of pending) this.add(line); + this.goDead(); + return; + } + case 0x0f: // return + this.branch(this.frames.length - 1); + this.goDead(); + return; + case 0x10: + this.call(c.u32()); + return; + case 0x11: { + const type = c.u32(); + const table = c.u32(); + this.callIndirect(type, table); + return; + } + case 0x1a: { + // A dropped load must still fault when it is out of bounds: LLVM + // would delete an unused ordinary load. + const v = this.pop(); + if (v.load !== undefined) { + const line = this.lines.lines[v.load]!; + this.lines.lines[v.load] = line.replace(" = load ", " = load volatile "); + } + return; + } + case 0x1b: + case 0x1c: { + if (op === 0x1c) { + const n = c.u32(); + for (let i = 0; i < n; i++) c.valType(); + } + const cond = this.pop(); + const b = this.pop(); + const a = this.pop(); + const test = this.emit(`icmp ne i32 ${cond.v}, 0`); + const t = llType(a.t); + this.push(this.emit(`select i1 ${test}, ${t} ${a.v}, ${t} ${b.v}`), a.t); + return; + } + case 0x20: { + const i = c.u32(); + const t = this.localTypes[i]!; + this.push(this.emit(`load ${llType(t)}, ptr %l${i}`), t); + return; + } + case 0x21: { + const i = c.u32(); + const v = this.pop(); + this.add(` store ${llType(v.t)} ${v.v}, ptr %l${i}`); + return; + } + case 0x22: { + const i = c.u32(); + const v = this.stack[this.stack.length - 1]!; + this.add(` store ${llType(v.t)} ${v.v}, ptr %l${i}`); + return; + } + case 0x23: { + const g = c.u32(); + const t = this.m.globals[g]!.type; + const cell = this.loadPtrSlot(this.mt.globalSlot(g)); + this.push(this.emit(`load ${llType(t)}, ptr ${cell}, align 8`), t); + return; + } + case 0x24: { + const g = c.u32(); + const v = this.pop(); + const cell = this.loadPtrSlot(this.mt.globalSlot(g)); + if (v.t === VAL_EXTERNREF) + this.add(` call void @scr_wasm_global_set_ref(ptr ${cell}, ptr ${v.v})`); + else this.add(` store ${llType(v.t)} ${v.v}, ptr ${cell}, align 8`); + return; + } + case 0x25: { + const t = c.u32(); + const i = this.pop(); + this.push( + this.emit(`call ptr @scr_wasm_table_get(ptr %inst, i32 ${t}, i32 ${i.v})`), + this.m.tables[t]!.elemType, + ); + return; + } + case 0x26: { + const t = c.u32(); + const v = this.pop(); + const i = this.pop(); + this.add(` call void @scr_wasm_table_set(ptr %inst, i32 ${t}, i32 ${i.v}, ptr ${v.v})`); + return; + } + case 0x3f: { + c.u32(); + const mem = this.loadPtrSlot(OFF_MEMORY); + const sizePtr = this.emit(`getelementptr inbounds i8, ptr ${mem}, i64 8`); + const size = this.emit(`load i64, ptr ${sizePtr}, align 8`); + const pages = this.emit(`lshr i64 ${size}, 16`); + this.push(this.emit(`trunc i64 ${pages} to i32`), VAL_I32); + return; + } + case 0x40: { + c.u32(); + const delta = this.pop(); + this.push(this.emit(`call i32 @scr_wasm_memory_grow(ptr %inst, i32 ${delta.v})`), VAL_I32); + this.refreshMemory(); + return; + } + case 0x41: + this.push(String(c.s32()), VAL_I32); + return; + case 0x42: { + const [lo, hi] = c.s64(); + this.push(i64Lit(lo, hi), VAL_I64); + return; + } + case 0x43: + this.push(this.emit(`bitcast i32 ${c.u32le() | 0} to float`), VAL_F32); + return; + case 0x44: { + const lo = c.u32le(); + const hi = c.u32le(); + this.push(this.emit(`bitcast i64 ${i64Lit(lo, hi)} to double`), VAL_F64); + return; + } + case 0xd0: + c.valType(); + this.push("null", c.bytes[c.pos - 1]!); + return; + case 0xd1: { + const a = this.pop(); + const r = this.emit(`icmp eq ptr ${a.v}, null`); + this.push(this.emit(`zext i1 ${r} to i32`), VAL_I32); + return; + } + case 0xd2: + this.push(this.funcRef(c.u32()), VAL_FUNCREF); + return; + case 0xfc: + this.prefixed(c); + return; + default: + break; + } + if (op >= 0x28 && op <= 0x35) { + c.u32(); + const offset = c.u32(); + const [vt, mt, bytes, ext] = LOAD_INFO[op]!; + const addr = this.pop(); + const p = this.address(addr.v, offset, bytes); + const line = this.lines.lines.length; + const loaded = this.emit(`load ${mt}, ptr ${p}, align 1`); + if (ext === "") this.stack.push({ v: loaded, t: vt, load: line }); + else { + const extended = this.emit(`${ext} ${mt} ${loaded} to ${llType(vt)}`); + this.stack.push({ v: extended, t: vt, load: line }); + } + return; + } + if (op >= 0x36 && op <= 0x3e) { + c.u32(); + const offset = c.u32(); + const [, mt, bytes] = STORE_INFO[op]!; + const v = this.pop(); + const addr = this.pop(); + const p = this.address(addr.v, offset, bytes); + let value = v.v; + if (mt === "i8" || mt === "i16" || (mt === "i32" && v.t === VAL_I64)) { + value = this.emit(`trunc ${llType(v.t)} ${v.v} to ${mt}`); + } + this.add(` store ${mt} ${value}, ptr ${p}, align 1`); + return; + } + this.numeric(op); + } + + numeric(op: number): void { + const I32 = VAL_I32; + const I64 = VAL_I64; + const F32 = VAL_F32; + const F64 = VAL_F64; + switch (op) { + case 0x45: + return this.eqz("i32"); + case 0x46: + return this.compare("eq", "i32", false); + case 0x47: + return this.compare("ne", "i32", false); + case 0x48: + return this.compare("slt", "i32", false); + case 0x49: + return this.compare("ult", "i32", false); + case 0x4a: + return this.compare("sgt", "i32", false); + case 0x4b: + return this.compare("ugt", "i32", false); + case 0x4c: + return this.compare("sle", "i32", false); + case 0x4d: + return this.compare("ule", "i32", false); + case 0x4e: + return this.compare("sge", "i32", false); + case 0x4f: + return this.compare("uge", "i32", false); + case 0x50: + return this.eqz("i64"); + case 0x51: + return this.compare("eq", "i64", false); + case 0x52: + return this.compare("ne", "i64", false); + case 0x53: + return this.compare("slt", "i64", false); + case 0x54: + return this.compare("ult", "i64", false); + case 0x55: + return this.compare("sgt", "i64", false); + case 0x56: + return this.compare("ugt", "i64", false); + case 0x57: + return this.compare("sle", "i64", false); + case 0x58: + return this.compare("ule", "i64", false); + case 0x59: + return this.compare("sge", "i64", false); + case 0x5a: + return this.compare("uge", "i64", false); + case 0x5b: + return this.compare("oeq", "float", true); + case 0x5c: + return this.compare("une", "float", true); + case 0x5d: + return this.compare("olt", "float", true); + case 0x5e: + return this.compare("ogt", "float", true); + case 0x5f: + return this.compare("ole", "float", true); + case 0x60: + return this.compare("oge", "float", true); + case 0x61: + return this.compare("oeq", "double", true); + case 0x62: + return this.compare("une", "double", true); + case 0x63: + return this.compare("olt", "double", true); + case 0x64: + return this.compare("ogt", "double", true); + case 0x65: + return this.compare("ole", "double", true); + case 0x66: + return this.compare("oge", "double", true); + case 0x67: + return this.unaryIntrinsic("ctlz.i32", "i32", I32, ", i1 false"); + case 0x68: + return this.unaryIntrinsic("cttz.i32", "i32", I32, ", i1 false"); + case 0x69: + return this.unaryIntrinsic("ctpop.i32", "i32", I32); + case 0x6a: + return this.binary("add", "i32", I32); + case 0x6b: + return this.binary("sub", "i32", I32); + case 0x6c: + return this.binary("mul", "i32", I32); + case 0x6d: + case 0x6e: + case 0x6f: + case 0x70: + return this.divRem(op, "i32"); + case 0x71: + return this.binary("and", "i32", I32); + case 0x72: + return this.binary("or", "i32", I32); + case 0x73: + return this.binary("xor", "i32", I32); + case 0x74: + return this.shift("shl", "i32", I32); + case 0x75: + return this.shift("ashr", "i32", I32); + case 0x76: + return this.shift("lshr", "i32", I32); + case 0x77: + return this.rotate("fshl", "i32", I32); + case 0x78: + return this.rotate("fshr", "i32", I32); + case 0x79: + return this.unaryIntrinsic("ctlz.i64", "i64", I64, ", i1 false"); + case 0x7a: + return this.unaryIntrinsic("cttz.i64", "i64", I64, ", i1 false"); + case 0x7b: + return this.unaryIntrinsic("ctpop.i64", "i64", I64); + case 0x7c: + return this.binary("add", "i64", I64); + case 0x7d: + return this.binary("sub", "i64", I64); + case 0x7e: + return this.binary("mul", "i64", I64); + case 0x7f: + case 0x80: + case 0x81: + case 0x82: + return this.divRem(op, "i64"); + case 0x83: + return this.binary("and", "i64", I64); + case 0x84: + return this.binary("or", "i64", I64); + case 0x85: + return this.binary("xor", "i64", I64); + case 0x86: + return this.shift("shl", "i64", I64); + case 0x87: + return this.shift("ashr", "i64", I64); + case 0x88: + return this.shift("lshr", "i64", I64); + case 0x89: + return this.rotate("fshl", "i64", I64); + case 0x8a: + return this.rotate("fshr", "i64", I64); + case 0x8b: + return this.unaryIntrinsic("fabs.f32", "float", F32); + case 0x8c: { + const a = this.pop(); + this.push(this.emit(`fneg float ${a.v}`), F32); + return; + } + case 0x8d: + return this.unaryIntrinsic("ceil.f32", "float", F32); + case 0x8e: + return this.unaryIntrinsic("floor.f32", "float", F32); + case 0x8f: + return this.unaryIntrinsic("trunc.f32", "float", F32); + case 0x90: + return this.unaryIntrinsic("roundeven.f32", "float", F32); + case 0x91: + return this.unaryIntrinsic("sqrt.f32", "float", F32); + case 0x92: + return this.binary("fadd", "float", F32); + case 0x93: + return this.binary("fsub", "float", F32); + case 0x94: + return this.binary("fmul", "float", F32); + case 0x95: + return this.binary("fdiv", "float", F32); + case 0x96: + return this.binaryIntrinsic("minimum.f32", "float", F32); + case 0x97: + return this.binaryIntrinsic("maximum.f32", "float", F32); + case 0x98: + return this.binaryIntrinsic("copysign.f32", "float", F32); + case 0x99: + return this.unaryIntrinsic("fabs.f64", "double", F64); + case 0x9a: { + const a = this.pop(); + this.push(this.emit(`fneg double ${a.v}`), F64); + return; + } + case 0x9b: + return this.unaryIntrinsic("ceil.f64", "double", F64); + case 0x9c: + return this.unaryIntrinsic("floor.f64", "double", F64); + case 0x9d: + return this.unaryIntrinsic("trunc.f64", "double", F64); + case 0x9e: + return this.unaryIntrinsic("roundeven.f64", "double", F64); + case 0x9f: + return this.unaryIntrinsic("sqrt.f64", "double", F64); + case 0xa0: + return this.binary("fadd", "double", F64); + case 0xa1: + return this.binary("fsub", "double", F64); + case 0xa2: + return this.binary("fmul", "double", F64); + case 0xa3: + return this.binary("fdiv", "double", F64); + case 0xa4: + return this.binaryIntrinsic("minimum.f64", "double", F64); + case 0xa5: + return this.binaryIntrinsic("maximum.f64", "double", F64); + case 0xa6: + return this.binaryIntrinsic("copysign.f64", "double", F64); + case 0xa7: + return this.convert("trunc", "i64", "i32", I32); + case 0xa8: + case 0xa9: + case 0xaa: + case 0xab: + case 0xae: + case 0xaf: + case 0xb0: + case 0xb1: + return this.truncTrap(op); + case 0xac: + return this.convert("sext", "i32", "i64", I64); + case 0xad: + return this.convert("zext", "i32", "i64", I64); + case 0xb2: + return this.convert("sitofp", "i32", "float", F32); + case 0xb3: + return this.convert("uitofp", "i32", "float", F32); + case 0xb4: + return this.convert("sitofp", "i64", "float", F32); + case 0xb5: + return this.convert("uitofp", "i64", "float", F32); + case 0xb6: + return this.convert("fptrunc", "double", "float", F32); + case 0xb7: + return this.convert("sitofp", "i32", "double", F64); + case 0xb8: + return this.convert("uitofp", "i32", "double", F64); + case 0xb9: + return this.convert("sitofp", "i64", "double", F64); + case 0xba: + return this.convert("uitofp", "i64", "double", F64); + case 0xbb: + return this.convert("fpext", "float", "double", F64); + case 0xbc: + return this.convert("bitcast", "float", "i32", I32); + case 0xbd: + return this.convert("bitcast", "double", "i64", I64); + case 0xbe: + return this.convert("bitcast", "i32", "float", F32); + case 0xbf: + return this.convert("bitcast", "i64", "double", F64); + case 0xc0: + case 0xc1: { + const a = this.pop(); + const n = op === 0xc0 ? "i8" : "i16"; + const narrow = this.emit(`trunc i32 ${a.v} to ${n}`); + this.push(this.emit(`sext ${n} ${narrow} to i32`), I32); + return; + } + case 0xc2: + case 0xc3: + case 0xc4: { + const a = this.pop(); + const n = op === 0xc2 ? "i8" : op === 0xc3 ? "i16" : "i32"; + const narrow = this.emit(`trunc i64 ${a.v} to ${n}`); + this.push(this.emit(`sext ${n} ${narrow} to i64`), I64); + return; + } + default: + throw new WasmTranslateError(`opcode 0x${op.toString(16)} is not supported`); + } + } + + prefixed(c: WasmCursor): void { + const sub = c.u32(); + if (sub <= 7) { + // Saturating float-to-int conversions. + const a = this.pop(); + const from = a.t === VAL_F32 ? "f32" : "f64"; + const fromTy = a.t === VAL_F32 ? "float" : "double"; + const to = sub < 4 ? "i32" : "i64"; + const signed = (sub & 1) === 0; + this.push( + this.emit( + `call ${to} @llvm.${signed ? "fptosi" : "fptoui"}.sat.${to}.${from}(${fromTy} ${a.v})`, + ), + to === "i32" ? VAL_I32 : VAL_I64, + ); + return; + } + switch (sub) { + case 8: { + // memory.init + const seg = c.u32(); + c.u32(); + const n = this.pop(); + const s = this.pop(); + const d = this.pop(); + this.add( + ` call void @scr_wasm_memory_init(ptr %inst, i32 ${seg}, i32 ${d.v}, i32 ${s.v}, i32 ${n.v})`, + ); + return; + } + case 9: + this.add(` call void @scr_wasm_data_drop(ptr %inst, i32 ${c.u32()})`); + return; + case 10: { + c.u32(); + c.u32(); + const n = this.pop(); + const s = this.pop(); + const d = this.pop(); + this.add( + ` call void @scr_wasm_memory_copy(ptr %inst, i32 ${d.v}, i32 ${s.v}, i32 ${n.v})`, + ); + return; + } + case 11: { + c.u32(); + const n = this.pop(); + const v = this.pop(); + const d = this.pop(); + this.add( + ` call void @scr_wasm_memory_fill(ptr %inst, i32 ${d.v}, i32 ${v.v}, i32 ${n.v})`, + ); + return; + } + case 12: { + const seg = c.u32(); + const t = c.u32(); + const n = this.pop(); + const s = this.pop(); + const d = this.pop(); + this.add( + ` call void @scr_wasm_table_init(ptr %inst, i32 ${t}, i32 ${seg}, i32 ${d.v}, i32 ${s.v}, i32 ${n.v})`, + ); + return; + } + case 13: + this.add(` call void @scr_wasm_elem_drop(ptr %inst, i32 ${c.u32()})`); + return; + case 14: { + const dt = c.u32(); + const st = c.u32(); + const n = this.pop(); + const s = this.pop(); + const d = this.pop(); + this.add( + ` call void @scr_wasm_table_copy(ptr %inst, i32 ${dt}, i32 ${st}, i32 ${d.v}, i32 ${s.v}, i32 ${n.v})`, + ); + return; + } + case 15: { + const t = c.u32(); + const n = this.pop(); + const v = this.pop(); + this.push( + this.emit(`call i32 @scr_wasm_table_grow(ptr %inst, i32 ${t}, ptr ${v.v}, i32 ${n.v})`), + VAL_I32, + ); + return; + } + case 16: { + const t = c.u32(); + const tab = this.loadPtrSlot(this.mt.tableSlot(t)); + const sizePtr = this.emit(`getelementptr inbounds i8, ptr ${tab}, i64 8`); + this.push(this.emit(`load i32, ptr ${sizePtr}, align 8`), VAL_I32); + return; + } + case 17: { + const t = c.u32(); + const n = this.pop(); + const v = this.pop(); + const d = this.pop(); + this.add( + ` call void @scr_wasm_table_fill(ptr %inst, i32 ${t}, i32 ${d.v}, ptr ${v.v}, i32 ${n.v})`, + ); + return; + } + default: + throw new WasmTranslateError(`opcode 0xfc ${sub} is not supported`); + } + } +} + +/** The functions through which the stack can grow without bound, which + * check the stack pointer on entry: members of a cycle of direct calls + * (including self-recursion), and functions that call through a table or + * call an import (an indirect call can reach any function, and an import + * can call back into an export). Every other call chain is finite, so its + * depth is bounded by the module and the guard's reserve absorbs it. */ +export function stackCheckedFunctions(m: WasmModule): Set { + const n = m.funcTypes.length; + const callees: number[][] = []; + const checked = new Set(); + for (let f = 0; f < n; f++) callees.push([]); + for (let i = 0; i < m.codes.length; i++) { + const f = m.importedFuncs + i; + const body = m.codes[i]!.body; + const c = new WasmCursor(m.bytes, body.start); + while (c.pos < body.end) { + const op = c.u8(); + if (op === 0x10) { + const callee = c.u32(); + if (callee < m.importedFuncs) checked.add(f); + else callees[f]!.push(callee); + } else if (op === 0x11) { + c.u32(); + c.u32(); + checked.add(f); + } else { + skipImmediates(c, op); + } + } + } + // Tarjan's strongly connected components, iteratively. + const index = new Int32Array(n).fill(-1); + const low = new Int32Array(n); + const onStack = new Uint8Array(n); + const stack: number[] = []; + let next = 0; + for (let root = m.importedFuncs; root < n; root++) { + if (index[root] !== -1) continue; + const workNode: number[] = [root]; + const workEdge: number[] = [0]; + index[root] = low[root] = next++; + stack.push(root); + onStack[root] = 1; + while (workNode.length > 0) { + const top = workNode.length - 1; + const v = workNode[top]!; + const edges = callees[v]!; + const e = workEdge[top]!; + if (e < edges.length) { + workEdge[top] = e + 1; + const w = edges[e]!; + if (index[w] === -1) { + index[w] = low[w] = next++; + stack.push(w); + onStack[w] = 1; + workNode.push(w); + workEdge.push(0); + } else if (onStack[w]) { + low[v] = Math.min(low[v]!, index[w]!); + } + continue; + } + workNode.pop(); + workEdge.pop(); + if (workNode.length > 0) { + const parent = workNode[workNode.length - 1]!; + low[parent] = Math.min(low[parent]!, low[v]!); + } + if (low[v] === index[v]) { + const component: number[] = []; + for (;;) { + const w = stack.pop()!; + onStack[w] = 0; + component.push(w); + if (w === v) break; + } + if (component.length > 1 || edges.includes(v)) for (const w of component) checked.add(w); + } + } + } + return checked; +} + +/** A decimal double literal as LLVM's exact hexadecimal form. */ +function hexDouble(text: string): string { + const view = new DataView(new ArrayBuffer(8)); + view.setFloat64(0, Number(text)); + return `0x${hex8(view.getUint32(0))}${hex8(view.getUint32(4))}`.toUpperCase().replace("0X", "0x"); +} + +function hexOf(bytes: Uint8Array): string { + let s = ""; + for (let i = 0; i < bytes.length; i++) s += bytes[i]!.toString(16).padStart(2, "0"); + return s; +} + +/** The symbol prefix of a module's translation. */ +export function wasmSymbolPrefix(sha256: Uint8Array): string { + return `scr_wasm_${hexOf(sha256).slice(0, 16)}`; +} + +/** Translates a module that binary.ts validated within the translatable + * feature level. Throws WasmTranslateError for constructs outside it. */ +export function translateWasmModule( + bytes: Uint8Array, + sha256: Uint8Array, + opts: WasmTranslateOptions, +): WasmTranslation { + const m = parseWasmModule(bytes); + for (const t of m.tables) llType(t.elemType); + const mt = new ModuleTranslator(m, wasmSymbolPrefix(sha256), opts); + mt.translate(); + const descriptor = mt.descriptor(sha256); + const decls = RUNTIME_DECLS.slice(); + // Initial-exec: executables and their static runtime define it, so the + // check is one thread-pointer-relative load, not a TLS lookup call. + if (opts.boundsChecks) + decls.push("@scr_wasm_stack_limit = external thread_local(initialexec) global i64"); + return { decls, text: mt.text, descriptor }; +} diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index a167254c2..5d82b6719 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -5634,9 +5634,8 @@ "id": "stdlib.webassembly", "kind": "stdlib", "name": "globalThis.WebAssembly", - "status": "unsupported", - "code": "SC2020", - "note": "WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations)" + "status": "static", + "note": "compile, instantiate, validate, Module, Instance, instanceof, the error classes, exports, memories, tables, globals and Module transfer to workers, over the modules translated at build time; the rest refuses with SC2020 (the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations))" }, { "id": "syntax.async-generators", diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-api.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-api.mjs.json new file mode 100644 index 000000000..f3e1a711b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-api.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/webassembly-api.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-control/main.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-control/main.mjs.json new file mode 100644 index 000000000..58a263265 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-control/main.mjs.json @@ -0,0 +1,8 @@ +{ + "order": [ + "/tests/wasm-spec/runner.mjs", + "/tests/corpus/webassembly-spec-control/data.mjs", + "/tests/corpus/webassembly-spec-control/main.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-float/main.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-float/main.mjs.json new file mode 100644 index 000000000..e871d3b1d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-float/main.mjs.json @@ -0,0 +1,8 @@ +{ + "order": [ + "/tests/wasm-spec/runner.mjs", + "/tests/corpus/webassembly-spec-float/data.mjs", + "/tests/corpus/webassembly-spec-float/main.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-int/main.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-int/main.mjs.json new file mode 100644 index 000000000..d19226a63 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-int/main.mjs.json @@ -0,0 +1,8 @@ +{ + "order": [ + "/tests/wasm-spec/runner.mjs", + "/tests/corpus/webassembly-spec-int/data.mjs", + "/tests/corpus/webassembly-spec-int/main.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-memory/main.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-memory/main.mjs.json new file mode 100644 index 000000000..4510ade3a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-memory/main.mjs.json @@ -0,0 +1,8 @@ +{ + "order": [ + "/tests/wasm-spec/runner.mjs", + "/tests/corpus/webassembly-spec-memory/data.mjs", + "/tests/corpus/webassembly-spec-memory/main.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-table/main.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-table/main.mjs.json new file mode 100644 index 000000000..50409b1d0 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-table/main.mjs.json @@ -0,0 +1,8 @@ +{ + "order": [ + "/tests/wasm-spec/runner.mjs", + "/tests/corpus/webassembly-spec-table/data.mjs", + "/tests/corpus/webassembly-spec-table/main.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-typed.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-typed.ts.json new file mode 100644 index 000000000..7a3adb475 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-typed.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/webassembly-typed.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-worker.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-worker.ts.json new file mode 100644 index 000000000..2b4ffd4ba --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-worker.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/webassembly-worker.ts" + ], + "diags": [] +} diff --git a/packages/runtime-darwin-arm64/runtime-pack-matrix.mjs b/packages/runtime-darwin-arm64/runtime-pack-matrix.mjs index 54e789624..5ded1866c 100644 --- a/packages/runtime-darwin-arm64/runtime-pack-matrix.mjs +++ b/packages/runtime-darwin-arm64/runtime-pack-matrix.mjs @@ -112,6 +112,7 @@ const optional = [ ["scr_tls_ca.c", "tlsCaEffective"], ["scr_tls.c", "tlsEffective"], ["scr_cipher.c", "cipher"], + ["scr_wasm.c", "wasm"], ["scr_fetch.c", "nativeFetch"], ]; diff --git a/packages/runtime-pack-common/runtime-pack-matrix.mjs b/packages/runtime-pack-common/runtime-pack-matrix.mjs index 6b5052482..604e5dd07 100644 --- a/packages/runtime-pack-common/runtime-pack-matrix.mjs +++ b/packages/runtime-pack-common/runtime-pack-matrix.mjs @@ -102,6 +102,7 @@ const OPTIONAL = [ ["scr_tls_ca.c", "tlsCaEffective"], ["scr_tls.c", "tlsEffective"], ["scr_cipher.c", "cipher"], + ["scr_wasm.c", "wasm"], ["scr_fetch.c", "nativeFetch"], ]; diff --git a/packages/runtime-wasm32-wasi/scripts/build.mjs b/packages/runtime-wasm32-wasi/scripts/build.mjs index ca0786607..42808aaa5 100644 --- a/packages/runtime-wasm32-wasi/scripts/build.mjs +++ b/packages/runtime-wasm32-wasi/scripts/build.mjs @@ -20,6 +20,7 @@ process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ "scr_tls_ca.c", "scr_tls.c", "scr_cipher.c", + "scr_wasm.c", "scr_fetch.c", ], omitArchives: ["mbedtls"], diff --git a/packages/runtime/src/scr_async.c b/packages/runtime/src/scr_async.c index f630ee5f9..ce0e93814 100644 --- a/packages/runtime/src/scr_async.c +++ b/packages/runtime/src/scr_async.c @@ -88,14 +88,6 @@ void __lsan_unregister_root_region(const void *p, size_t size) __attribute__((we #endif #endif -#ifdef SCR_ASAN_FIBERS -#define SCR_FIBER_STACK (8 * 1024 * 1024) -#else -/* Deep enough for ordinary recursion inside async bodies and generators - * once the overflow guard's reserve is taken off; idle and shallow fibers - * only touch the pages they use. */ -#define SCR_FIBER_STACK (512 * 1024) -#endif #if !defined(_WIN32) && !defined(__wasi__) /* Keep stacks out of malloc's size classes. Reuse a bounded number during diff --git a/packages/runtime/src/scr_async.h b/packages/runtime/src/scr_async.h index efa98e942..9ff38ed88 100644 --- a/packages/runtime/src/scr_async.h +++ b/packages/runtime/src/scr_async.h @@ -29,6 +29,20 @@ void *scr_promise_retain_v(void *p); void scr_promise_release_v(void *p); typedef struct ScrFiber ScrFiber; +/* Bytes of each async fiber's native stack (scr_async.c), mapped without a + * guard page: compiled code checks scr_stack_guard instead, which sits + * scr_stack_guard_for's reserve above the mapping's start. Deep enough for + * ordinary recursion inside async bodies and generators once that reserve + * is taken off; idle and shallow fibers only touch the pages they use. + * AddressSanitizer's larger frames get more. */ +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define SCR_FIBER_STACK (8 * 1024 * 1024) +#endif +#endif +#ifndef SCR_FIBER_STACK +#define SCR_FIBER_STACK (512 * 1024) +#endif /* Spawn + run eagerly to the first suspension; returns the promise, +1. */ ScrPromise *scr_async_spawn(void (*entry)(ScrFiber *, void *), void *argpack); /* `await f(...)` of a fiber-backed async f: spawn and await in one call, diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index ca21a0685..b7960ba12 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -173,6 +173,11 @@ typedef enum { SCR_DYNH_BROADCAST_CHANNEL, /* worker_threads BroadcastChannel (scr_worker_events.c) */ SCR_DYNH_HASH, /* node:crypto Hash (scr_lib.c) */ SCR_DYNH_HMAC, /* node:crypto Hmac (scr_lib.c) */ + SCR_DYNH_WASM_MODULE, /* WebAssembly.Module (scr_wasm.c) */ + SCR_DYNH_WASM_INSTANCE, /* WebAssembly.Instance */ + SCR_DYNH_WASM_MEMORY, /* WebAssembly.Memory */ + SCR_DYNH_WASM_TABLE, /* WebAssembly.Table */ + SCR_DYNH_WASM_GLOBAL, /* WebAssembly.Global */ SCR_DYNH_COUNT, } ScrDynHandleTag; diff --git a/packages/runtime/src/scr_wasm.c b/packages/runtime/src/scr_wasm.c new file mode 100644 index 000000000..03d59604f --- /dev/null +++ b/packages/runtime/src/scr_wasm.c @@ -0,0 +1,1990 @@ +/* The JavaScript WebAssembly API over modules translated to native code + * when the program was built (scr_wasm_abi.h is the contract with the + * translator). + * + * WebAssembly.compile, instantiate, validate and new Module hash the bytes + * they are given and look the module up by SHA-256 and length in + * scr_wasm_registry, which the compiler emits; bytes that were not + * translated at build time reject with a CompileError that says so. + * Nothing is interpreted or compiled at run time, and a translated + * module's bytes were validated when the program was built. + * + * Values: Module, Instance, Memory, Table and Global are native handles in + * the checked-dynamic representation (the SCR_DYNH_WASM_* tags, installed + * per thread on first use). An instance's exports object is a frozen + * null-prototype object whose functions call the translated code through + * its thunks under a trap guard; imports are checked-dynamic callables + * called with `this` undefined, ToJSValue arguments and ToWebAssemblyValue + * results. + * + * Traps. Translated code calls scr_wasm_trap, which siglongjmps to the + * innermost export entry (scr_wasm_enter); the entry throws Node's + * WebAssembly.RuntimeError. With guard pages, an out-of-bounds access + * faults inside the memory's reservation and stack exhaustion faults near + * the stack pointer: the SIGSEGV/SIGBUS handler (installed when the first + * guarded instance is created, on a per-thread alternate stack, chaining + * to the previous handler for every other fault) moves the interrupted + * context to a trampoline that traps the same way, so the handler itself + * returns normally. Async fibers' stacks have no guard page of their own, + * so the first export call on one protects the lowest page of its mapping + * (scr_wasm_guard_fiber). An exception thrown by an import unwinds the + * translated frames the same way and propagates unchanged. Translated + * frames own nothing, so abandoning them leaks nothing; the module's own + * shadow stack pointer is not restored, exactly as in V8. + * + * The error classes are Errors whose inherited name is CompileError, + * LinkError or RuntimeError (not an own property, as in Node), which is + * the brand instanceof tests. + * + * Gaps (results/opt-wasm-design/DESIGN.md, stages W5-W7): no Memory, + * Table or Global constructors; Memory.grow does not detach the previous + * ArrayBuffer (the memory never moves, so old views stay valid with their + * old length); instances, their imports and exports are never freed (the + * cycle collector does not trace them yet); funcref values cross to + * JavaScript only as exported functions. */ +#if !defined(_GNU_SOURCE) && defined(__linux__) +#define _GNU_SOURCE /* REG_RIP and friends in */ +#endif +#include "scr_runtime.h" +#include "scr_wasm_abi.h" + +#include +#include +#include +#include +#include + +#if !defined(_WIN32) +#define SCR_WASM_SIGNALS 1 +#include +#include +#include +#include +#if defined(__APPLE__) +#include +#else +#include +#endif +#endif + +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define SCR_WASM_ASAN 1 +#endif +#endif +#if !defined(SCR_WASM_ASAN) && defined(__SANITIZE_ADDRESS__) +#define SCR_WASM_ASAN 1 +#endif + +ScrPromise *scr_wasm_compile(ScrDyn *bytes); +bool scr_wasm_validate(ScrDyn *bytes); +ScrPromise *scr_wasm_instantiate(ScrDyn *source, ScrDyn *imports); +ScrDyn *scr_wasm_module_new(ScrDyn *bytes); +ScrDyn *scr_wasm_instance_new(ScrDyn *module, ScrDyn *imports); +bool scr_wasm_is(const ScrDyn *value, double kind); +ScrDyn *scr_wasm_error_new(double kind, ScrDyn *message, ScrDyn *options); +ScrDyn *scr_wasm_function(double kind); +ScrDyn *scr_wasm_namespace(void); +ScrDyn *scr_wasm_global_view(void); + +/* Entry points of translated code. */ +/* Sanitized builds do not declare it noreturn: AddressSanitizer would + * call __asan_handle_no_return before every call, which warns on the + * runtime's async fibers. */ +#ifdef SCR_WASM_ASAN +void scr_wasm_trap(int32_t code); +#else +_Noreturn void scr_wasm_trap(int32_t code); +#endif +void scr_wasm_import_call(void *host, int32_t index, const uint64_t *args, uint64_t *results); +int32_t scr_wasm_memory_grow(void *inst, int32_t delta); +void scr_wasm_memory_fill(void *inst, int32_t d, int32_t value, int32_t n); +void scr_wasm_memory_copy(void *inst, int32_t d, int32_t s, int32_t n); +void scr_wasm_memory_init(void *inst, int32_t seg, int32_t d, int32_t s, int32_t n); +void scr_wasm_data_drop(void *inst, int32_t seg); +void *scr_wasm_table_get(void *inst, int32_t t, int32_t i); +void scr_wasm_table_set(void *inst, int32_t t, int32_t i, void *value); +int32_t scr_wasm_table_grow(void *inst, int32_t t, void *init, int32_t n); +void scr_wasm_table_fill(void *inst, int32_t t, int32_t i, void *value, int32_t n); +void scr_wasm_table_copy(void *inst, int32_t dt, int32_t st, int32_t d, int32_t s, int32_t n); +void scr_wasm_table_init(void *inst, int32_t t, int32_t seg, int32_t d, int32_t s, int32_t n); +void scr_wasm_elem_drop(void *inst, int32_t seg); +void scr_wasm_global_set_ref(void *cell, void *value); + +#define SCR_WASM_PAGE 65536u +#define SCR_WASM_MAX_PAGES 65536u +#define SCR_WASM_MAX_TABLE 10000000u +/* Every `base + zext(i32) + offset(u32) + size` the translated code can + * form stays inside this reservation, so an access past the memory faults + * on a PROT_NONE page instead of reaching other mappings. */ +#define SCR_WASM_GUARD_RESERVATION ((uint64_t)8 << 30 | (uint64_t)SCR_WASM_PAGE) + +/* ── instance state ──────────────────────────────────────────────────── */ + +typedef struct ScrWasmInst { + size_t rc; + const ScrWasmModuleDesc *desc; + void **inst; /* the translated code's instance (layout in scr_wasm_abi.h) */ + ScrDyn **funcs; /* imported function values, by function index */ + ScrWasmMemory *memory; + ScrWasmTable **tables; + ScrWasmGlobal **globals; + ScrWasmFuncRef *funcrefs; + ScrDyn **export_fns; /* exported function values, by function index (lazy) */ + char **export_names; + bool *data_dropped; + bool *elem_dropped; + ScrDyn *exports; +} ScrWasmInst; + +static ScrWasmInst *scr_wasm_host_of(void *inst) { return ((ScrWasmInst **)inst)[0]; } + +#ifdef SCR_RC_AUDIT +/* Instances are never freed yet (stage W6), so the sanitized lane's RC + * audit would report everything they hold. Audited builds tear every + * instance down at exit instead. */ +static SCR_TL ScrWasmInst **scr_wasm_hosts; +static SCR_TL size_t scr_wasm_host_count, scr_wasm_host_cap; +static void scr_wasm_teardown(void); + +static void scr_wasm_note_host(ScrWasmInst *host) { + if (scr_wasm_host_count == 0 && scr_wasm_host_cap == 0) scr_atexit(scr_wasm_teardown); + if (scr_wasm_host_count == scr_wasm_host_cap) { + size_t cap = scr_wasm_host_cap ? scr_wasm_host_cap * 2 : 8; + ScrWasmInst **grown = realloc(scr_wasm_hosts, cap * sizeof *grown); + if (!grown) scr_trap("scriptc: out of memory\n"); + scr_wasm_hosts = grown; + scr_wasm_host_cap = cap; + } + scr_wasm_hosts[scr_wasm_host_count++] = host; +} +#endif + +/* ── SHA-256 (FIPS 180-4) ────────────────────────────────────────────── */ + +typedef struct { + uint32_t h[8]; +} ScrWasmSha; + +static const uint32_t scr_wasm_sha_k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +static uint32_t scr_wasm_rotr(uint32_t x, unsigned n) { return (x >> n) | (x << (32 - n)); } + +static void scr_wasm_sha_block(ScrWasmSha *s, const uint8_t *p) { + uint32_t w[64]; + for (int i = 0; i < 16; i++) + w[i] = (uint32_t)p[4 * i] << 24 | (uint32_t)p[4 * i + 1] << 16 | (uint32_t)p[4 * i + 2] << 8 | p[4 * i + 3]; + for (int i = 16; i < 64; i++) { + uint32_t s0 = scr_wasm_rotr(w[i - 15], 7) ^ scr_wasm_rotr(w[i - 15], 18) ^ (w[i - 15] >> 3); + uint32_t s1 = scr_wasm_rotr(w[i - 2], 17) ^ scr_wasm_rotr(w[i - 2], 19) ^ (w[i - 2] >> 10); + w[i] = w[i - 16] + s0 + w[i - 7] + s1; + } + uint32_t a = s->h[0], b = s->h[1], c = s->h[2], d = s->h[3], e = s->h[4], f = s->h[5], g = s->h[6], h = s->h[7]; + for (int i = 0; i < 64; i++) { + uint32_t t1 = h + (scr_wasm_rotr(e, 6) ^ scr_wasm_rotr(e, 11) ^ scr_wasm_rotr(e, 25)) + ((e & f) ^ (~e & g)) + + scr_wasm_sha_k[i] + w[i]; + uint32_t t2 = (scr_wasm_rotr(a, 2) ^ scr_wasm_rotr(a, 13) ^ scr_wasm_rotr(a, 22)) + ((a & b) ^ (a & c) ^ (b & c)); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + s->h[0] += a; + s->h[1] += b; + s->h[2] += c; + s->h[3] += d; + s->h[4] += e; + s->h[5] += f; + s->h[6] += g; + s->h[7] += h; +} + +static void scr_wasm_sha256(const uint8_t *data, size_t len, uint8_t out[32]) { + ScrWasmSha s = {{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}}; + size_t i = 0; + for (; i + 64 <= len; i += 64) scr_wasm_sha_block(&s, data + i); + uint8_t tail[128] = {0}; + size_t rest = len - i; + if (rest) memcpy(tail, data + i, rest); + tail[rest] = 0x80; + size_t total = rest + 1 + 8 <= 64 ? 64 : 128; + uint64_t bits = (uint64_t)len * 8; + for (int k = 0; k < 8; k++) tail[total - 1 - k] = (uint8_t)(bits >> (8 * k)); + scr_wasm_sha_block(&s, tail); + if (total == 128) scr_wasm_sha_block(&s, tail + 64); + for (int k = 0; k < 8; k++) { + out[4 * k] = (uint8_t)(s.h[k] >> 24); + out[4 * k + 1] = (uint8_t)(s.h[k] >> 16); + out[4 * k + 2] = (uint8_t)(s.h[k] >> 8); + out[4 * k + 3] = (uint8_t)s.h[k]; + } +} + +/* ── errors ──────────────────────────────────────────────────────────── */ + +enum { SCR_WASM_COMPILE_ERROR, SCR_WASM_LINK_ERROR, SCR_WASM_RUNTIME_ERROR }; +static const char *const scr_wasm_error_names[] = {"CompileError", "LinkError", "RuntimeError"}; + +/* A WebAssembly error: an Error whose inherited (not own) name is the + * class's. Borrows message. +1. */ +static ScrError *scr_wasm_error_make(int which, ScrStr *message) { + ScrError *e = scr_error_new(SCR_ERR_ERROR, message); + scr_str_release(e->name); + const char *name = scr_wasm_error_names[which]; + e->name = scr_str_new(name, strlen(name)); + e->name_present = false; + return e; +} + +static void scr_wasm_throw_kind(int which, const char *msg) { + ScrStr *s = scr_str_new(msg, strlen(msg)); + ScrError *e = scr_wasm_error_make(which, s); + scr_str_release(s); + scr_throw_obj(e, &scr_error_retain_v, &scr_error_release_v, scr_error_trace_arg()); +} + +static int scr_wasm_error_brand(const ScrError *e) { + if (!e || e->vt != &scr_error_vts[SCR_ERR_ERROR] || e->name_present || !e->name) return -1; + for (int i = 0; i < 3; i++) { + size_t n = strlen(scr_wasm_error_names[i]); + if (e->name->len == n && !memcmp(e->name->data, scr_wasm_error_names[i], n)) return i; + } + return -1; +} + +static void scr_wasm_type_error(const char *msg) { scr_throw_error_msg(SCR_ERR_TYPE, msg, strlen(msg)); } +static void scr_wasm_range_error(const char *msg) { scr_throw_error_msg(SCR_ERR_RANGE, msg, strlen(msg)); } + +static const char *scr_wasm_trap_message(int code) { + switch (code) { + case SCR_WASM_TRAP_MEMORY_OOB: return "memory access out of bounds"; + case SCR_WASM_TRAP_DIV_BY_ZERO: return "divide by zero"; + case SCR_WASM_TRAP_DIV_UNREPRESENTABLE: return "divide result unrepresentable"; + case SCR_WASM_TRAP_REM_BY_ZERO: return "remainder by zero"; + case SCR_WASM_TRAP_FLOAT_UNREPRESENTABLE: return "float unrepresentable in integer range"; + case SCR_WASM_TRAP_TABLE_OOB: return "table index is out of bounds"; + case SCR_WASM_TRAP_SIGNATURE: return "null function or function signature mismatch"; + case SCR_WASM_TRAP_NULL: return "dereferencing a null pointer"; + case SCR_WASM_TRAP_ELEM_SEGMENT: return "element segment out of bounds"; + default: return "unreachable"; + } +} + +/* Throws the JavaScript error for a trap code (nothing for HOST: its + * exception is already pending). */ +static void scr_wasm_throw_trap(int code) { + if (code == SCR_WASM_TRAP_HOST) return; + if (code == SCR_WASM_TRAP_EXHAUSTION) { + scr_wasm_range_error("Maximum call stack size exceeded"); + return; + } + scr_wasm_throw_kind(SCR_WASM_RUNTIME_ERROR, scr_wasm_trap_message(code)); +} + +/* ── the trap guard ──────────────────────────────────────────────────── */ + +/* AddressSanitizer intercepts siglongjmp and warns when it cannot tell the + * extent of the running stack, as on the runtime's async fibers. Sanitized + * builds therefore jump with the compiler's builtin pair, which no runtime + * intercepts, and unpoison the abandoned frames themselves. */ +#ifdef SCR_WASM_ASAN +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +typedef void *ScrWasmJmp[5]; +#define SCR_WASM_SETJMP(buf) __builtin_setjmp(buf) +#define SCR_WASM_LONGJMP(buf) __builtin_longjmp(buf, 1) +#elif defined(_WIN32) +typedef jmp_buf ScrWasmJmp; +#define SCR_WASM_SETJMP(buf) setjmp(buf) +#define SCR_WASM_LONGJMP(buf) longjmp(buf, 1) +#else +typedef sigjmp_buf ScrWasmJmp; +#define SCR_WASM_SETJMP(buf) sigsetjmp(buf, 0) +#define SCR_WASM_LONGJMP(buf) siglongjmp(buf, 1) +#endif + +typedef struct ScrWasmEntry { + ScrWasmJmp jmp; + struct ScrWasmEntry *prev; + uintptr_t frame; /* the entry's frame address: exhaustion resumes below it */ +} ScrWasmEntry; + +/* Thread-local in every build: each thread runs its own instances, and + * the fault handler reads them. */ +static _Thread_local ScrWasmEntry *scr_wasm_top; +static _Thread_local bool scr_wasm_running; /* translated code (not an import) is on top */ +static _Thread_local int scr_wasm_trap_code; + +/* Externref values an import returned: translated code holds them without + * a reference, so they stay alive until the outermost export call + * returns. */ +static _Thread_local ScrDyn **scr_wasm_kept; +static _Thread_local size_t scr_wasm_kept_count, scr_wasm_kept_cap; + +static void scr_wasm_keep(ScrDyn *d) { + if (scr_wasm_kept_count == scr_wasm_kept_cap) { + size_t cap = scr_wasm_kept_cap ? scr_wasm_kept_cap * 2 : 16; + ScrDyn **grown = realloc(scr_wasm_kept, cap * sizeof *grown); + if (!grown) scr_trap("scriptc: out of memory\n"); + scr_wasm_kept = grown; + scr_wasm_kept_cap = cap; + } + scr_wasm_kept[scr_wasm_kept_count++] = scr_dyn_retain(d); +} + +static void scr_wasm_release_kept(void) { + while (scr_wasm_kept_count) scr_dyn_release(scr_wasm_kept[--scr_wasm_kept_count]); +} + +#ifdef SCR_WASM_ASAN +/* Uninstrumented, so the sanitizer inserts no __asan_handle_no_return + * before the jump; the abandoned frames are unpoisoned below. */ +__attribute__((no_sanitize("address"))) +#else +_Noreturn +#endif +void scr_wasm_trap(int32_t code) { + ScrWasmEntry *top = scr_wasm_top; + if (!top) scr_trap("scriptc: WebAssembly trap outside an export call\n"); + scr_wasm_running = false; + scr_wasm_trap_code = code; +#ifdef SCR_WASM_ASAN + /* The real frame address: a local's address may be on the sanitizer's + * fake stack. */ + uintptr_t low = ((uintptr_t)__builtin_frame_address(0) & ~(uintptr_t)15) - 256; + if (top->frame > low && top->frame - low < ((uintptr_t)256 << 20)) + __asan_unpoison_memory_region((void *)low, top->frame - low); +#endif + SCR_WASM_LONGJMP(top->jmp); +} + +#if SCR_WASM_SIGNALS +static void scr_wasm_thread_init(void); +static void scr_wasm_guard_fiber(uintptr_t frame); +#endif + +/* Code with explicit bounds checks: the lowest stack address translated + * code may use before it traps with stack exhaustion (translate.ts checks + * it in the entry of every function through which the stack can grow + * without bound): the runtime's own stack guard for the running stack + * (thread or async fiber), read at each outermost export call. */ +_Thread_local uint64_t scr_wasm_stack_limit; + +static void scr_wasm_set_stack_limit(void) { +#if !defined(_WIN32) && !defined(__wasi__) + if (!scr_stack_guard) scr_stack_guard_init(); + scr_wasm_stack_limit = scr_stack_guard; +#endif +} + +/* Calls a thunk with traps caught; answers a SCR_WASM_TRAP_* code. */ +static __attribute__((noinline)) int scr_wasm_enter(ScrWasmThunk fn, void *inst, const uint64_t *args, + uint64_t *results) { +#if SCR_WASM_SIGNALS + scr_wasm_thread_init(); +#endif + ScrWasmEntry entry; + entry.prev = scr_wasm_top; + entry.frame = (uintptr_t)__builtin_frame_address(0); + if (!entry.prev) { + scr_wasm_set_stack_limit(); +#if SCR_WASM_SIGNALS + scr_wasm_guard_fiber(entry.frame); +#endif + } + bool was_running = scr_wasm_running; + scr_wasm_top = &entry; + int code = 0; + if (SCR_WASM_SETJMP(entry.jmp) == 0) { + scr_wasm_running = true; + fn(inst, args, results); + } else { + code = scr_wasm_trap_code; + } + scr_wasm_running = was_running; + scr_wasm_top = entry.prev; + if (!entry.prev && scr_wasm_kept_count) scr_wasm_release_kept(); + return code; +} + +static void scr_wasm_init_thunk(void *inst, const uint64_t *args, uint64_t *results) { + (void)args; + (void)results; + scr_wasm_host_of(inst)->desc->init(inst); +} + +static void scr_wasm_start_thunk(void *inst, const uint64_t *args, uint64_t *results) { + (void)args; + (void)results; + scr_wasm_host_of(inst)->desc->start(inst); +} + +/* ── memories and the fault handler ──────────────────────────────────── */ + +#if SCR_WASM_SIGNALS +/* Reservations of this thread's guarded memories, read by the fault + * handler (faults are synchronous, so nothing changes under it). */ +typedef struct { + uintptr_t start, end; +} ScrWasmRange; +static _Thread_local ScrWasmRange *scr_wasm_ranges; +static _Thread_local size_t scr_wasm_range_count, scr_wasm_range_cap; +static _Thread_local bool scr_wasm_altstack_ready; + +static struct sigaction scr_wasm_prev_segv, scr_wasm_prev_bus; +static pthread_once_t scr_wasm_handler_once = PTHREAD_ONCE_INIT; +static bool scr_wasm_handler_installed; + +static void scr_wasm_range_add(uint8_t *base, uint64_t len) { + if (scr_wasm_range_count == scr_wasm_range_cap) { + size_t cap = scr_wasm_range_cap ? scr_wasm_range_cap * 2 : 8; + ScrWasmRange *grown = realloc(scr_wasm_ranges, cap * sizeof *grown); + if (!grown) scr_trap("scriptc: out of memory\n"); + scr_wasm_ranges = grown; + scr_wasm_range_cap = cap; + } + scr_wasm_ranges[scr_wasm_range_count++] = (ScrWasmRange){(uintptr_t)base, (uintptr_t)base + len}; +} + +static void scr_wasm_range_remove(uint8_t *base) { + for (size_t i = 0; i < scr_wasm_range_count; i++) { + if (scr_wasm_ranges[i].start == (uintptr_t)base) { + scr_wasm_ranges[i] = scr_wasm_ranges[--scr_wasm_range_count]; + return; + } + } +} + +static _Noreturn __attribute__((noinline, used)) void scr_wasm_fault_trampoline(int32_t code) { + scr_wasm_trap(code); + __builtin_unreachable(); +} + +/* Moves the interrupted context to scr_wasm_fault_trampoline(code). With + * `stack` nonzero the trampoline runs at that stack address (exhaustion); + * otherwise below the interrupted stack pointer. */ +static bool scr_wasm_redirect(void *context, int32_t code, uintptr_t stack) { + ucontext_t *uc = context; + uintptr_t target = (uintptr_t)&scr_wasm_fault_trampoline; +#if defined(__APPLE__) && defined(__x86_64__) + uintptr_t sp = stack ? stack : (uintptr_t)uc->uc_mcontext->__ss.__rsp - 256; + sp = (sp & ~(uintptr_t)15) - 8; /* as after a call */ + uc->uc_mcontext->__ss.__rsp = sp; + uc->uc_mcontext->__ss.__rdi = (uint64_t)(uint32_t)code; + uc->uc_mcontext->__ss.__rip = target; + return true; +#elif defined(__APPLE__) && defined(__aarch64__) + uintptr_t sp = stack ? stack : (uintptr_t)__darwin_arm_thread_state64_get_sp(uc->uc_mcontext->__ss) - 256; + sp &= ~(uintptr_t)15; + __darwin_arm_thread_state64_set_sp(uc->uc_mcontext->__ss, sp); + uc->uc_mcontext->__ss.__x[0] = (uint64_t)(uint32_t)code; + __darwin_arm_thread_state64_set_lr_fptr(uc->uc_mcontext->__ss, (void *)target); + __darwin_arm_thread_state64_set_pc_fptr(uc->uc_mcontext->__ss, (void *)target); + return true; +#elif defined(__linux__) && defined(__x86_64__) + uintptr_t sp = stack ? stack : (uintptr_t)uc->uc_mcontext.gregs[REG_RSP] - 256; + sp = (sp & ~(uintptr_t)15) - 8; + uc->uc_mcontext.gregs[REG_RSP] = (greg_t)sp; + uc->uc_mcontext.gregs[REG_RDI] = (greg_t)(uint32_t)code; + uc->uc_mcontext.gregs[REG_RIP] = (greg_t)target; + return true; +#elif defined(__linux__) && defined(__aarch64__) + uintptr_t sp = stack ? stack : (uintptr_t)uc->uc_mcontext.sp - 256; + sp &= ~(uintptr_t)15; + uc->uc_mcontext.sp = sp; + uc->uc_mcontext.regs[0] = (uint64_t)(uint32_t)code; + uc->uc_mcontext.regs[30] = target; + uc->uc_mcontext.pc = target; + return true; +#else + (void)uc; + (void)target; + (void)code; + (void)stack; + return false; +#endif +} + +static uintptr_t scr_wasm_context_sp(void *context) { + ucontext_t *uc = context; +#if defined(__APPLE__) && defined(__x86_64__) + return (uintptr_t)uc->uc_mcontext->__ss.__rsp; +#elif defined(__APPLE__) && defined(__aarch64__) + return (uintptr_t)__darwin_arm_thread_state64_get_sp(uc->uc_mcontext->__ss); +#elif defined(__linux__) && defined(__x86_64__) + return (uintptr_t)uc->uc_mcontext.gregs[REG_RSP]; +#elif defined(__linux__) && defined(__aarch64__) + return (uintptr_t)uc->uc_mcontext.sp; +#else + (void)uc; + return 0; +#endif +} + +static void scr_wasm_chain(int sig, siginfo_t *info, void *context) { + struct sigaction *prev = sig == SIGBUS ? &scr_wasm_prev_bus : &scr_wasm_prev_segv; + if (prev->sa_flags & SA_SIGINFO) { + if (prev->sa_sigaction) { + prev->sa_sigaction(sig, info, context); + return; + } + } else if (prev->sa_handler != SIG_DFL && prev->sa_handler != SIG_IGN) { + prev->sa_handler(sig); + return; + } + /* The default action: restore it and let the faulting instruction run + * again, so the process dies of the original signal. */ + sigaction(sig, prev, NULL); +} + +static void scr_wasm_fault(int sig, siginfo_t *info, void *context) { + if (scr_wasm_running && scr_wasm_top) { + uintptr_t addr = (uintptr_t)info->si_addr; + for (size_t i = 0; i < scr_wasm_range_count; i++) { + if (addr >= scr_wasm_ranges[i].start && addr < scr_wasm_ranges[i].end) { + if (scr_wasm_redirect(context, SCR_WASM_TRAP_MEMORY_OOB, 0)) return; + } + } + uintptr_t sp = scr_wasm_context_sp(context); + if (sp && addr + 65536 >= sp && addr <= sp + 65536) { + /* Stack exhaustion: resume below the export entry's frame, over the + * abandoned translated frames. */ + uintptr_t below = scr_wasm_top->frame - 4096; + if (scr_wasm_redirect(context, SCR_WASM_TRAP_EXHAUSTION, below)) return; + } + } + scr_wasm_chain(sig, info, context); +} + +static void scr_wasm_install_handler(void) { + struct sigaction sa; + memset(&sa, 0, sizeof sa); + sa.sa_sigaction = scr_wasm_fault; + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGSEGV, &sa, &scr_wasm_prev_segv) == 0 && sigaction(SIGBUS, &sa, &scr_wasm_prev_bus) == 0) + scr_wasm_handler_installed = true; +} + +/* The thread's own stack, which the system ends with a guard page. */ +static _Thread_local uintptr_t scr_wasm_thread_low, scr_wasm_thread_high; +/* The stack guard of the last stack an outermost export call ran on. */ +static _Thread_local uintptr_t scr_wasm_guarded_stack; + +/* Async fibers run on SCR_FIBER_STACK-byte mappings without a guard page + * (compiled code checks scr_stack_guard instead), so recursion in + * translated code there would run past the mapping. The first export call + * on a fiber therefore protects the lowest page of its mapping, which the + * fault handler then reports as stack exhaustion; scr_stack_guard, which + * sits scr_stack_guard_for's reserve above that page, locates it. The + * page stays protected while the runtime reuses the stack. A stack that + * does not match the fiber layout is left alone. */ +static void scr_wasm_guard_fiber(uintptr_t frame) { + if (!scr_wasm_handler_installed) return; + uintptr_t guard = scr_stack_guard; + if (!guard || guard == scr_wasm_guarded_stack) return; + scr_wasm_guarded_stack = guard; + if (!scr_wasm_thread_high) { +#if defined(__APPLE__) + pthread_t self = pthread_self(); + scr_wasm_thread_high = (uintptr_t)pthread_get_stackaddr_np(self); + scr_wasm_thread_low = scr_wasm_thread_high - pthread_get_stacksize_np(self); +#else + pthread_attr_t attr; + if (pthread_getattr_np(pthread_self(), &attr) == 0) { + void *addr; + size_t size; + if (pthread_attr_getstack(&attr, &addr, &size) == 0) { + scr_wasm_thread_low = (uintptr_t)addr; + scr_wasm_thread_high = (uintptr_t)addr + size; + } + pthread_attr_destroy(&attr); + } +#endif + } + if (frame >= scr_wasm_thread_low && frame < scr_wasm_thread_high) return; + uintptr_t low = guard - (scr_stack_guard_for(0, SCR_FIBER_STACK)); + long page = sysconf(_SC_PAGESIZE); + if (page <= 0 || (low & ((uintptr_t)page - 1)) != 0) return; + if (frame <= low + (uintptr_t)page || frame >= low + SCR_FIBER_STACK) return; + (void)mprotect((void *)low, (size_t)page, PROT_NONE); +} + +/* Per thread: an alternate signal stack, so exhaustion faults can be + * handled. A thread that already has one keeps it. */ +static void scr_wasm_thread_init(void) { + if (scr_wasm_altstack_ready || !scr_wasm_handler_installed) return; + scr_wasm_altstack_ready = true; + stack_t current; + if (sigaltstack(NULL, ¤t) == 0 && !(current.ss_flags & SS_DISABLE) && current.ss_size >= 32768) return; + size_t size = 65536; + void *mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + if (mem == MAP_FAILED) return; + stack_t ss = {.ss_sp = mem, .ss_size = size, .ss_flags = 0}; + sigaltstack(&ss, NULL); +} +#endif + +static ScrWasmMemory *scr_wasm_memory_retain(ScrWasmMemory *m) { + m->rc++; + return m; +} + +static void scr_wasm_memory_release(ScrWasmMemory *m) { + if (!m || --m->rc) return; + scr_dyn_release(m->buffer); +#if SCR_WASM_SIGNALS + if (m->guarded) { + scr_wasm_range_remove(m->base); + munmap(m->base, m->reserved); + } else +#endif + free(m->base); + free(m); +} + +/* A memory of `min` pages growing to at most `max` pages; NULL with + * Node's RangeError pending when the address space or memory is short. */ +static ScrWasmMemory *scr_wasm_memory_new(uint64_t min, uint64_t max, bool guarded, const char *what) { + if (max > SCR_WASM_MAX_PAGES) max = SCR_WASM_MAX_PAGES; + ScrWasmMemory *m = calloc(1, sizeof *m); + if (!m) scr_trap("scriptc: out of memory\n"); + m->rc = 1; + m->max_pages = max; + m->size = min * SCR_WASM_PAGE; +#if SCR_WASM_SIGNALS + if (guarded) { +#if !defined(MAP_NORESERVE) +#define MAP_NORESERVE 0 +#endif + void *base = mmap(NULL, SCR_WASM_GUARD_RESERVATION, PROT_NONE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); + if (base == MAP_FAILED || + (m->size && mprotect(base, m->size, PROT_READ | PROT_WRITE) != 0)) { + if (base != MAP_FAILED) munmap(base, SCR_WASM_GUARD_RESERVATION); + free(m); + char msg[200]; + snprintf(msg, sizeof msg, "%s: Out of memory: Cannot allocate Wasm memory for new instance", what); + scr_wasm_range_error(msg); + return NULL; + } + m->base = base; + m->reserved = SCR_WASM_GUARD_RESERVATION; + m->guarded = true; + scr_wasm_range_add(m->base, m->reserved); + return m; + } +#else + (void)guarded; +#endif + m->base = m->size ? calloc(1, m->size) : NULL; + if (m->size && !m->base) { + free(m); + char msg[200]; + snprintf(msg, sizeof msg, "%s: Out of memory: Cannot allocate Wasm memory for new instance", what); + scr_wasm_range_error(msg); + return NULL; + } + m->reserved = m->size; + return m; +} + +/* Grows by `delta` pages; answers the previous page count or -1. */ +static int64_t scr_wasm_memory_grow_by(ScrWasmMemory *m, uint64_t delta) { + uint64_t old = m->size / SCR_WASM_PAGE; + if (delta > m->max_pages || old + delta > m->max_pages) return -1; + if (delta == 0) return (int64_t)old; + uint64_t size = (old + delta) * SCR_WASM_PAGE; +#if SCR_WASM_SIGNALS + if (m->guarded) { + if (mprotect(m->base + m->size, size - m->size, PROT_READ | PROT_WRITE) != 0) return -1; + m->size = size; + return (int64_t)old; + } +#endif + uint8_t *grown = realloc(m->base, size); + if (!grown) return -1; + memset(grown + m->size, 0, size - m->size); + m->base = grown; + m->reserved = size; + m->size = size; + return (int64_t)old; +} + +static ScrWasmMemory *scr_wasm_inst_memory(void *inst) { return ((ScrWasmMemory **)inst)[2]; } + +int32_t scr_wasm_memory_grow(void *inst, int32_t delta) { + ScrWasmMemory *m = scr_wasm_inst_memory(inst); + int64_t old = scr_wasm_memory_grow_by(m, (uint32_t)delta); + ((void **)inst)[1] = m->base; + return (int32_t)old; +} + +static void scr_wasm_check_memory(ScrWasmMemory *m, uint32_t at, uint32_t n) { + if ((uint64_t)at + n > m->size) scr_wasm_trap(SCR_WASM_TRAP_MEMORY_OOB); +} + +void scr_wasm_memory_fill(void *inst, int32_t d, int32_t value, int32_t n) { + ScrWasmMemory *m = scr_wasm_inst_memory(inst); + scr_wasm_check_memory(m, (uint32_t)d, (uint32_t)n); + if (n) memset(m->base + (uint32_t)d, value & 0xff, (uint32_t)n); +} + +void scr_wasm_memory_copy(void *inst, int32_t d, int32_t s, int32_t n) { + ScrWasmMemory *m = scr_wasm_inst_memory(inst); + scr_wasm_check_memory(m, (uint32_t)d, (uint32_t)n); + scr_wasm_check_memory(m, (uint32_t)s, (uint32_t)n); + if (n) memmove(m->base + (uint32_t)d, m->base + (uint32_t)s, (uint32_t)n); +} + +/* Instantiation reports an active data segment's failure with its + * details (V8's "data segment N is out of bounds (offset ...)"). */ +static _Thread_local bool scr_wasm_instantiating; +static _Thread_local struct { + uint32_t seg, offset, length; + uint64_t size; +} scr_wasm_segment_failure; + +void scr_wasm_memory_init(void *inst, int32_t seg, int32_t d, int32_t s, int32_t n) { + ScrWasmInst *host = scr_wasm_host_of(inst); + const ScrWasmDataDesc *data = &host->desc->datas[seg]; + uint64_t len = host->data_dropped[seg] ? 0 : data->len; + ScrWasmMemory *m = scr_wasm_inst_memory(inst); + if ((uint64_t)(uint32_t)s + (uint32_t)n > len || (uint64_t)(uint32_t)d + (uint32_t)n > m->size) { + if (scr_wasm_instantiating) { + scr_wasm_segment_failure.seg = (uint32_t)seg; + scr_wasm_segment_failure.offset = (uint32_t)d; + scr_wasm_segment_failure.length = (uint32_t)n; + scr_wasm_segment_failure.size = m->size; + scr_wasm_trap(SCR_WASM_TRAP_DATA_SEGMENT); + } + scr_wasm_trap(SCR_WASM_TRAP_MEMORY_OOB); + } + if (n) memcpy(m->base + (uint32_t)d, data->data + (uint32_t)s, (uint32_t)n); +} + +void scr_wasm_data_drop(void *inst, int32_t seg) { scr_wasm_host_of(inst)->data_dropped[seg] = true; } + +/* ── tables ──────────────────────────────────────────────────────────── */ + +static ScrWasmTable *scr_wasm_table_new(char elem, uint64_t min, uint64_t max) { + ScrWasmTable *t = calloc(1, sizeof *t); + if (!t) scr_trap("scriptc: out of memory\n"); + t->rc = 1; + t->elem = elem; + t->size = (uint32_t)min; + t->max = max > SCR_WASM_MAX_TABLE ? SCR_WASM_MAX_TABLE : (uint32_t)max; + t->elems = calloc(min ? min : 1, sizeof *t->elems); + if (!t->elems) scr_trap("scriptc: out of memory\n"); + return t; +} + +static ScrWasmTable *scr_wasm_table_retain(ScrWasmTable *t) { + t->rc++; + return t; +} + +static void scr_wasm_table_release(ScrWasmTable *t) { + if (!t || --t->rc) return; + if (t->elem == 'x') + for (uint32_t i = 0; i < t->size; i++) scr_dyn_release(t->elems[i]); + free(t->elems); + free(t); +} + +static void *scr_wasm_ref_retain(char elem, void *v) { + if (elem == 'x' && v) scr_dyn_retain(v); + return v; +} + +static void scr_wasm_table_store(ScrWasmTable *t, uint32_t i, void *v) { + void *old = t->elems[i]; + t->elems[i] = scr_wasm_ref_retain(t->elem, v); + if (t->elem == 'x') scr_dyn_release(old); +} + +static ScrWasmTable *scr_wasm_inst_table(void *inst, int32_t t) { return ((ScrWasmTable **)inst)[4 + t]; } + +void *scr_wasm_table_get(void *inst, int32_t ti, int32_t i) { + ScrWasmTable *t = scr_wasm_inst_table(inst, ti); + if ((uint32_t)i >= t->size) scr_wasm_trap(SCR_WASM_TRAP_TABLE_OOB); + return t->elems[(uint32_t)i]; +} + +void scr_wasm_table_set(void *inst, int32_t ti, int32_t i, void *value) { + ScrWasmTable *t = scr_wasm_inst_table(inst, ti); + if ((uint32_t)i >= t->size) scr_wasm_trap(SCR_WASM_TRAP_TABLE_OOB); + scr_wasm_table_store(t, (uint32_t)i, value); +} + +static int64_t scr_wasm_table_grow_by(ScrWasmTable *t, uint32_t n, void *init) { + uint32_t old = t->size; + if ((uint64_t)old + n > t->max) return -1; + if (n == 0) return old; + void **grown = realloc(t->elems, ((size_t)old + n) * sizeof *grown); + if (!grown) return -1; + t->elems = grown; + for (uint32_t i = 0; i < n; i++) grown[old + i] = scr_wasm_ref_retain(t->elem, init); + t->size = old + n; + return old; +} + +int32_t scr_wasm_table_grow(void *inst, int32_t ti, void *init, int32_t n) { + return (int32_t)scr_wasm_table_grow_by(scr_wasm_inst_table(inst, ti), (uint32_t)n, init); +} + +void scr_wasm_table_fill(void *inst, int32_t ti, int32_t i, void *value, int32_t n) { + ScrWasmTable *t = scr_wasm_inst_table(inst, ti); + if ((uint64_t)(uint32_t)i + (uint32_t)n > t->size) scr_wasm_trap(SCR_WASM_TRAP_TABLE_OOB); + for (uint32_t k = 0; k < (uint32_t)n; k++) scr_wasm_table_store(t, (uint32_t)i + k, value); +} + +void scr_wasm_table_copy(void *inst, int32_t dti, int32_t sti, int32_t d, int32_t s, int32_t n) { + ScrWasmTable *dt = scr_wasm_inst_table(inst, dti), *st = scr_wasm_inst_table(inst, sti); + uint32_t ud = (uint32_t)d, us = (uint32_t)s, un = (uint32_t)n; + if ((uint64_t)ud + un > dt->size || (uint64_t)us + un > st->size) scr_wasm_trap(SCR_WASM_TRAP_TABLE_OOB); + if (ud <= us) { + for (uint32_t k = 0; k < un; k++) scr_wasm_table_store(dt, ud + k, st->elems[us + k]); + } else { + for (uint32_t k = un; k-- > 0;) scr_wasm_table_store(dt, ud + k, st->elems[us + k]); + } +} + +static void *scr_wasm_elem_item(ScrWasmInst *host, int64_t item) { + if (item >= 0) return &host->funcrefs[item]; + if (item == -1) return NULL; + return (void *)(uintptr_t)host->globals[-(item + 2)]->value; +} + +void scr_wasm_table_init(void *inst, int32_t ti, int32_t seg, int32_t d, int32_t s, int32_t n) { + ScrWasmInst *host = scr_wasm_host_of(inst); + ScrWasmTable *t = scr_wasm_inst_table(inst, ti); + const ScrWasmElemDesc *e = &host->desc->elems[seg]; + uint64_t len = host->elem_dropped[seg] ? 0 : e->count; + uint32_t ud = (uint32_t)d, us = (uint32_t)s, un = (uint32_t)n; + if ((uint64_t)ud + un > t->size) scr_wasm_trap(SCR_WASM_TRAP_TABLE_OOB); + if ((uint64_t)us + un > len) scr_wasm_trap(SCR_WASM_TRAP_ELEM_SEGMENT); + for (uint32_t k = 0; k < un; k++) scr_wasm_table_store(t, ud + k, scr_wasm_elem_item(host, e->items[us + k])); +} + +void scr_wasm_elem_drop(void *inst, int32_t seg) { scr_wasm_host_of(inst)->elem_dropped[seg] = true; } + +/* ── globals ─────────────────────────────────────────────────────────── */ + +static ScrWasmGlobal *scr_wasm_global_new(char type, bool mutable_) { + ScrWasmGlobal *g = calloc(1, sizeof *g); + if (!g) scr_trap("scriptc: out of memory\n"); + g->rc = 1; + g->type = type; + g->mutable_ = mutable_; + return g; +} + +static ScrWasmGlobal *scr_wasm_global_retain(ScrWasmGlobal *g) { + g->rc++; + return g; +} + +static void scr_wasm_global_release(ScrWasmGlobal *g) { + if (!g || --g->rc) return; + if (g->type == 'x') scr_dyn_release((ScrDyn *)(uintptr_t)g->value); + free(g); +} + +void scr_wasm_global_set_ref(void *cell, void *value) { + ScrWasmGlobal *g = cell; + ScrDyn *old = (ScrDyn *)(uintptr_t)g->value; + if (value) scr_dyn_retain(value); + g->value = (uint64_t)(uintptr_t)value; + scr_dyn_release(old); +} + +/* ── handles ─────────────────────────────────────────────────────────── */ + +enum { SCR_WASM_K_MODULE, SCR_WASM_K_INSTANCE, SCR_WASM_K_MEMORY, SCR_WASM_K_TABLE, SCR_WASM_K_GLOBAL }; + +typedef struct ScrWasmObj { + size_t rc; + int kind; + const ScrWasmModuleDesc *desc; /* Module */ + ScrWasmInst *inst; /* Instance; the owner of exported objects */ + ScrWasmMemory *memory; + ScrWasmTable *table; + ScrWasmGlobal *global; +} ScrWasmObj; + +/* Instances are never freed yet (stage W6 traces them for the cycle + * collector), so the references their handles and exported functions hold + * are not counted. */ +static void *scr_wasm_inst_retain(void *p) { return p; } + +static void scr_wasm_inst_release(void *p) { (void)p; } + +static void *scr_wasm_obj_retain(void *p) { + ((ScrWasmObj *)p)->rc++; + return p; +} + +static void scr_wasm_obj_release(void *p) { + ScrWasmObj *o = p; + if (--o->rc) return; + if (o->inst) scr_wasm_inst_release(o->inst); + scr_wasm_memory_release(o->memory); + scr_wasm_table_release(o->table); + scr_wasm_global_release(o->global); + free(o); +} + +static ScrWasmObj *scr_wasm_obj_new(int kind) { + ScrWasmObj *o = calloc(1, sizeof *o); + if (!o) scr_trap("scriptc: out of memory\n"); + o->rc = 1; + o->kind = kind; + return o; +} + +static ScrDyn *scr_wasm_empty_view(void *h) { + (void)h; + return scr_dyn_new_obj(); +} + +static const ScrDynHandleTag scr_wasm_tags[] = {SCR_DYNH_WASM_MODULE, SCR_DYNH_WASM_INSTANCE, SCR_DYNH_WASM_MEMORY, + SCR_DYNH_WASM_TABLE, SCR_DYNH_WASM_GLOBAL}; + +static void scr_wasm_install(void); + +static ScrDyn *scr_wasm_box(ScrWasmObj *o) { + scr_wasm_install(); + ScrDyn *d = scr_dyn_new_handle(o, scr_wasm_tags[o->kind]); + scr_wasm_obj_release(o); + return d; +} + +static ScrWasmObj *scr_wasm_unbox(const ScrDyn *v, int kind) { + if (!v || v->kind != SCR_DYN_HANDLE || v->v.handle.tag != scr_wasm_tags[kind]) return NULL; + return v->v.handle.ptr; +} + +/* ── values ──────────────────────────────────────────────────────────── */ + +static ScrDyn *scr_wasm_function_value(ScrWasmInst *host, uint32_t func); + +/* ToJSValue (+1; NULL with an exception pending). */ +static ScrDyn *scr_wasm_to_js(char t, uint64_t v) { + switch (t) { + case 'i': return scr_dyn_new_num((double)(int32_t)(uint32_t)v); + case 'I': { + ScrBigInt *b = scr_bigint_from_i64((int64_t)v); + ScrDyn *d = scr_dyn_new_bigint(b); + scr_bigint_release(b); + return d; + } + case 'f': { + uint32_t bits = (uint32_t)v; + float f; + memcpy(&f, &bits, 4); + return scr_dyn_new_num((double)f); + } + case 'F': { + double d; + memcpy(&d, &v, 8); + return scr_dyn_new_num(d); + } + case 'r': { + ScrWasmFuncRef *ref = (ScrWasmFuncRef *)(uintptr_t)v; + if (!ref) return scr_dyn_new_null(); + ScrWasmInst *host = scr_wasm_host_of(ref->inst); + return scr_wasm_function_value(host, (uint32_t)(ref - host->funcrefs)); + } + default: { + ScrDyn *d = (ScrDyn *)(uintptr_t)v; + return d ? scr_dyn_retain(d) : scr_dyn_new_null(); + } + } +} + +static uint32_t scr_wasm_to_int32(double n) { + if (!isfinite(n)) return 0; + double t = trunc(n); + double m = fmod(t, 4294967296.0); + if (m < 0) m += 4294967296.0; + return (uint32_t)m; +} + +static ScrWasmFuncRef *scr_wasm_funcref_of(const ScrDyn *v); + +/* ToWebAssemblyValue: false with an exception pending. References are + * borrowed from `v`. */ +static bool scr_wasm_from_js(char t, const ScrDyn *v, uint64_t *out) { + if (!v) v = scr_dyn_undefined(); + switch (t) { + case 'i': { + double n; + if (!scr_dyn_number_coerce_js(v, &n)) return false; + *out = scr_wasm_to_int32(n); + return true; + } + case 'f': { + double n; + if (!scr_dyn_number_coerce_js(v, &n)) return false; + float f = (float)n; + uint32_t b; + memcpy(&b, &f, 4); + *out = b; + return true; + } + case 'F': { + double n; + if (!scr_dyn_number_coerce_js(v, &n)) return false; + memcpy(out, &n, 8); + return true; + } + case 'I': { + ScrBigInt *b = scr_dyn_bigint_coerce(v); + if (!b) return false; + *out = (uint64_t)scr_bigint_to_i64(b); + scr_bigint_release(b); + return true; + } + case 'r': { + if (v->kind == SCR_DYN_NULL) { + *out = 0; + return true; + } + ScrWasmFuncRef *ref = scr_wasm_funcref_of(v); + if (!ref) { + scr_wasm_type_error("type incompatibility when transforming from/to JS"); + return false; + } + *out = (uint64_t)(uintptr_t)ref; + return true; + } + default: + if (v->kind == SCR_DYN_NULL) { + *out = 0; + return true; + } + *out = (uint64_t)(uintptr_t)v; + return true; + } +} + +static size_t scr_wasm_params(const char *sig) { + size_t n = 0; + while (sig[n] && sig[n] != ':') n++; + return n; +} + +/* ── exported functions ──────────────────────────────────────────────── */ + +typedef struct { + ScrWasmInst *host; + uint32_t func; + ScrWasmThunk thunk; +} ScrWasmExportCtx; + +static ScrDyn *scr_wasm_export_call(ScrClosure *clo, ScrDyn *const *args, size_t argc) { + ScrWasmInst *host = scr_box_get_ref(clo->caps[0]); + uint32_t func = (uint32_t)scr_box_get_f64(clo->caps[1]); + const char *sig = host->desc->func_sigs[func]; + ScrWasmThunk thunk = NULL; + for (uint64_t i = 0; i < host->desc->export_count; i++) { + const ScrWasmExportDesc *ex = &host->desc->exports[i]; + if (ex->kind == SCR_WASM_FUNC && ex->index == func) { + thunk = ex->call; + break; + } + } + size_t np = scr_wasm_params(sig); + const char *res = sig[np] == ':' ? sig + np + 1 : ""; + size_t nr = strlen(res); + uint64_t stack_args[16], stack_res[8] = {0}; + uint64_t *a = np <= 16 ? stack_args : malloc(np * sizeof *a); + uint64_t *r = nr <= 8 ? stack_res : calloc(nr, sizeof *r); + if (!a || !r) scr_trap("scriptc: out of memory\n"); + ScrDyn *result = NULL; + bool ok = true; + for (size_t i = 0; i < np && ok; i++) ok = scr_wasm_from_js(sig[i], i < argc ? args[i] : NULL, &a[i]); + if (ok) { + int trap = scr_wasm_enter(thunk, host->inst, a, r); + if (trap) { + scr_wasm_throw_trap(trap); + } else if (nr == 0) { + result = scr_dyn_retain(scr_dyn_undefined()); + } else if (nr == 1) { + result = scr_wasm_to_js(res[0], r[0]); + } else { + result = scr_dyn_new_arr(); + for (size_t i = 0; i < nr; i++) scr_dyn_arr_push(result, scr_wasm_to_js(res[i], r[i])); + } + } + if (a != stack_args) free(a); + if (r != stack_res) free(r); + scr_wasm_inst_release(host); + return result; +} + +/* The function value of exported function `func` (+1), created once per + * instance and function; NULL with a TypeError pending for a function the + * module does not export (funcref values of other functions are stage W5). */ +static ScrDyn *scr_wasm_function_value(ScrWasmInst *host, uint32_t func) { + if (host->export_fns[func]) return scr_dyn_retain(host->export_fns[func]); + bool exported = false; + for (uint64_t i = 0; i < host->desc->export_count; i++) { + const ScrWasmExportDesc *ex = &host->desc->exports[i]; + if (ex->kind == SCR_WASM_FUNC && ex->index == func) exported = true; + } + if (!exported) { + scr_wasm_type_error("WebAssembly function references to functions a module does not export are not supported yet"); + return NULL; + } + char name[24]; + snprintf(name, sizeof name, "%u", func); + size_t name_len = strlen(name) + 1; + host->export_names[func] = malloc(name_len); + if (!host->export_names[func]) scr_trap("scriptc: out of memory\n"); + memcpy(host->export_names[func], name, name_len); + ScrClosure *closure = scr_closure_new(NULL, 2); + closure->caps[0] = scr_box_new_obj(scr_wasm_inst_retain, scr_wasm_inst_release, NULL); + scr_box_set_ref(closure->caps[0], scr_wasm_inst_retain(host)); + closure->caps[1] = scr_box_new(SCR_BOX_F64); + scr_box_set_f64(closure->caps[1], (double)func); + uint32_t arity = (uint32_t)scr_wasm_params(host->desc->func_sigs[func]); + host->export_fns[func] = scr_dyn_new_func(closure, scr_wasm_export_call, arity, "", host->export_names[func]); + return scr_dyn_retain(host->export_fns[func]); +} + +static ScrWasmFuncRef *scr_wasm_funcref_of(const ScrDyn *v) { + if (!v || v->kind != SCR_DYN_FUNC || v->v.fn.thunk != scr_wasm_export_call) return NULL; + ScrClosure *clo = v->v.fn.clo; + ScrWasmInst *host = scr_box_get_ref(clo->caps[0]); + uint32_t func = (uint32_t)scr_box_get_f64(clo->caps[1]); + scr_wasm_inst_release(host); + return &host->funcrefs[func]; +} + +/* ── imported functions ──────────────────────────────────────────────── */ + +void scr_wasm_import_call(void *hostp, int32_t index, const uint64_t *args, uint64_t *results) { + ScrWasmInst *host = hostp; + const char *sig = host->desc->func_sigs[index]; + size_t np = scr_wasm_params(sig); + ScrDyn *stack_argv[16]; + ScrDyn **argv = np <= 16 ? stack_argv : malloc(np * sizeof *argv); + if (!argv) scr_trap("scriptc: out of memory\n"); + bool ok = true; + size_t made = 0; + for (; made < np; made++) { + argv[made] = scr_wasm_to_js(sig[made], args[made]); + if (!argv[made]) { + ok = false; + break; + } + } + scr_wasm_running = false; + ScrDyn *res = NULL; + if (ok) { + scr_dyn_this_push_dyn(scr_dyn_undefined()); + res = scr_dyn_call(host->funcs[index], argv, np, "WebAssembly import"); + scr_dyn_this_pop(); + } + for (size_t i = 0; i < made; i++) scr_dyn_release(argv[i]); + if (argv != stack_argv) free(argv); + if (res) { + const char *want = sig[np] == ':' ? sig + np + 1 : ""; + size_t nr = strlen(want); + if (nr == 1) { + ok = scr_wasm_from_js(want[0], res, &results[0]); + if (ok && want[0] == 'x' && results[0]) scr_wasm_keep((ScrDyn *)(uintptr_t)results[0]); + } else if (nr > 1) { + for (size_t i = 0; ok && i < nr; i++) { + ScrDyn *item = scr_dyn_index_get(res, (double)i); + ok = item && scr_wasm_from_js(want[i], item, &results[i]); + if (ok && want[i] == 'x' && results[i]) scr_wasm_keep((ScrDyn *)(uintptr_t)results[i]); + scr_dyn_release(item); + } + } + scr_dyn_release(res); + } else { + ok = false; + } + if (!ok) scr_wasm_trap(SCR_WASM_TRAP_HOST); + scr_wasm_running = true; +} + +/* ── handle members ──────────────────────────────────────────────────── */ + +static ScrDyn *scr_wasm_memory_buffer(ScrWasmMemory *m) { + /* memory.grow in translated code changes the size without telling the + * cached buffer. */ + if (m->buffer && m->buffer_size != m->size) { + scr_dyn_release(m->buffer); + m->buffer = NULL; + } + if (!m->buffer) { + m->buffer_size = m->size; + ScrBytes *bytes = scr_bytes_from_external(m->base, (size_t)m->size); + m->buffer = scr_array_buffer_from_bytes(bytes); + scr_bytes_release(bytes); + } + return scr_dyn_retain(m->buffer); +} + +static ScrDyn *scr_wasm_global_value(ScrWasmGlobal *g) { return scr_wasm_to_js(g->type, g->value); } + +static ScrDyn *scr_wasm_get(void *h, const char *key, size_t len) { + ScrWasmObj *o = h; + switch (o->kind) { + case SCR_WASM_K_INSTANCE: + if (len == 7 && !memcmp(key, "exports", 7)) return scr_dyn_retain(o->inst->exports); + return NULL; + case SCR_WASM_K_MEMORY: + if (len == 6 && !memcmp(key, "buffer", 6)) return scr_wasm_memory_buffer(o->memory); + return NULL; + case SCR_WASM_K_TABLE: + if (len == 6 && !memcmp(key, "length", 6)) return scr_dyn_new_num(o->table->size); + return NULL; + case SCR_WASM_K_GLOBAL: + if (len == 5 && !memcmp(key, "value", 5)) return scr_wasm_global_value(o->global); + return NULL; + default: + return NULL; + } +} + +static bool scr_wasm_global_assign(ScrWasmGlobal *g, const ScrDyn *value) { + if (!g->mutable_) { + scr_wasm_type_error("set WebAssembly.Global.value): Can't set the value of an immutable global."); + return false; + } + uint64_t v; + if (!scr_wasm_from_js(g->type, value, &v)) return false; + if (g->type == 'x') scr_wasm_global_set_ref(g, (void *)(uintptr_t)v); + else g->value = v; + return true; +} + +static bool scr_wasm_set(void *h, const char *key, size_t len, const ScrDyn *value) { + ScrWasmObj *o = h; + if (o->kind == SCR_WASM_K_GLOBAL && len == 5 && !memcmp(key, "value", 5)) { + scr_wasm_global_assign(o->global, value); + return true; + } + return false; +} + +static bool scr_wasm_u32_arg(const ScrDyn *v, const char *what, uint32_t *out) { + double n; + if (!scr_dyn_number_coerce_js(v ? v : scr_dyn_undefined(), &n)) return false; + if (!isfinite(n) || n < 0 || trunc(n) > 4294967295.0) { + char msg[200]; + snprintf(msg, sizeof msg, "%s must be convertible to a valid number", what); + scr_wasm_type_error(msg); + return false; + } + *out = (uint32_t)trunc(n); + return true; +} + +static ScrDyn *scr_wasm_invoke(void *h, ScrDyn *self, const char *method, ScrDyn *const *args, size_t argc, + const char *what) { + (void)self; + ScrWasmObj *o = h; + if (o->kind == SCR_WASM_K_MEMORY && !strcmp(method, "grow")) { + uint32_t delta; + if (!scr_wasm_u32_arg(argc ? args[0] : NULL, "WebAssembly.Memory.grow(): Argument 0", &delta)) return NULL; + int64_t old = scr_wasm_memory_grow_by(o->memory, delta); + if (old < 0) { + scr_wasm_range_error("WebAssembly.Memory.grow(): Maximum memory size exceeded"); + return NULL; + } + if (o->inst && o->inst->memory == o->memory) o->inst->inst[1] = o->memory->base; + /* The previous buffer keeps its length (no detachment yet, W5). */ + scr_dyn_release(o->memory->buffer); + o->memory->buffer = NULL; + return scr_dyn_new_num((double)old); + } + if (o->kind == SCR_WASM_K_TABLE) { + ScrWasmTable *t = o->table; + uint32_t index = 0; + uint64_t value = 0; + if (!strcmp(method, "get")) { + if (!scr_wasm_u32_arg(argc ? args[0] : NULL, "WebAssembly.Table.get(): Argument 0", &index)) return NULL; + if (index >= t->size) { + char msg[160]; + snprintf(msg, sizeof msg, "WebAssembly.Table.get(): invalid address %u in %s table of size %u", index, + t->elem == 'x' ? "externref" : "funcref", t->size); + scr_wasm_range_error(msg); + return NULL; + } + return scr_wasm_to_js(t->elem, (uint64_t)(uintptr_t)t->elems[index]); + } + if (!strcmp(method, "set")) { + if (!scr_wasm_u32_arg(argc ? args[0] : NULL, "WebAssembly.Table.set(): Argument 0", &index)) return NULL; + if (index >= t->size) { + char msg[160]; + snprintf(msg, sizeof msg, "WebAssembly.Table.set(): invalid address %u in %s table of size %u", index, + t->elem == 'x' ? "externref" : "funcref", t->size); + scr_wasm_range_error(msg); + return NULL; + } + const ScrDyn *v = argc > 1 ? args[1] : (t->elem == 'x' ? scr_dyn_undefined() : scr_dyn_new_null()); + if (!scr_wasm_from_js(t->elem, v, &value)) return NULL; + scr_wasm_table_store(t, index, (void *)(uintptr_t)value); + return scr_dyn_retain(scr_dyn_undefined()); + } + if (!strcmp(method, "grow")) { + uint32_t delta; + if (!scr_wasm_u32_arg(argc ? args[0] : NULL, "WebAssembly.Table.grow(): Argument 0", &delta)) return NULL; + if (argc > 1 && !scr_wasm_from_js(t->elem, args[1], &value)) return NULL; + int64_t old = scr_wasm_table_grow_by(t, delta, (void *)(uintptr_t)value); + if (old < 0) { + char msg[160]; + snprintf(msg, sizeof msg, "WebAssembly.Table.grow(): failed to grow table by %u", delta); + scr_wasm_range_error(msg); + return NULL; + } + return scr_dyn_new_num((double)old); + } + } + if (o->kind == SCR_WASM_K_GLOBAL && !strcmp(method, "valueOf")) return scr_wasm_global_value(o->global); + char msg[200]; + snprintf(msg, sizeof msg, "%s is not a function", what ? what : method); + scr_wasm_type_error(msg); + return NULL; +} + +/* Module transfer between threads (postMessage, workerData): a module is + * immutable code plus its descriptor, so the payload is the descriptor + * itself, which every thread of the executable shares. */ +static void *scr_wasm_module_share(void *h) { return (void *)((ScrWasmObj *)h)->desc; } + +static ScrDyn *scr_wasm_module_adopt(void *payload) { + ScrWasmObj *o = scr_wasm_obj_new(SCR_WASM_K_MODULE); + o->desc = payload; + return scr_wasm_box(o); +} + +static void scr_wasm_module_drop(void *payload) { (void)payload; } + +static const ScrDynHandleTransfer scr_wasm_module_transfer = { + .share = scr_wasm_module_share, .adopt = scr_wasm_module_adopt, .drop = scr_wasm_module_drop}; + +#define SCR_WASM_OPS(name, tag, xfer) \ + static const ScrDynHandleOps scr_wasm_ops_##name = { \ + .cls = #name, .retain = scr_wasm_obj_retain, .release = scr_wasm_obj_release, \ + .invoke = scr_wasm_invoke, .get = scr_wasm_get, .set = scr_wasm_set, \ + .inspect_view = scr_wasm_empty_view, .json_empty_object = true, \ + .to_string_tag = tag, .inspect_view_empty = true, .transfer = xfer, \ + }; +SCR_WASM_OPS(Module, "WebAssembly.Module", &scr_wasm_module_transfer) +SCR_WASM_OPS(Instance, "WebAssembly.Instance", NULL) +SCR_WASM_OPS(Memory, "WebAssembly.Memory", NULL) +SCR_WASM_OPS(Table, "WebAssembly.Table", NULL) +SCR_WASM_OPS(Global, "WebAssembly.Global", NULL) + +static void scr_wasm_install(void) { + static SCR_TL bool installed; + if (installed) return; + installed = true; + scr_dyn_handle_install(SCR_DYNH_WASM_MODULE, &scr_wasm_ops_Module); + scr_dyn_handle_install(SCR_DYNH_WASM_INSTANCE, &scr_wasm_ops_Instance); + scr_dyn_handle_install(SCR_DYNH_WASM_MEMORY, &scr_wasm_ops_Memory); + scr_dyn_handle_install(SCR_DYNH_WASM_TABLE, &scr_wasm_ops_Table); + scr_dyn_handle_install(SCR_DYNH_WASM_GLOBAL, &scr_wasm_ops_Global); +} + +/* ── modules ─────────────────────────────────────────────────────────── */ + +/* The bytes of a BufferSource, or false with Node's TypeError pending. */ +static bool scr_wasm_bytes_of(const ScrDyn *v, const char *what, const char *expected, const uint8_t **data, + size_t *len) { + if (v && v->kind == SCR_DYN_BYTES) { + *data = v->v.bytes->data; + *len = (size_t)scr_bytes_byte_len(v->v.bytes); + return true; + } + if (v && v->kind == SCR_DYN_HANDLE && scr_array_buffer_is(v)) { + ScrBytes *b = v->v.handle.ptr; + *data = b->data; + *len = (size_t)scr_bytes_byte_len(b); + return true; + } + char msg[200]; + snprintf(msg, sizeof msg, "%s: Argument 0 must be %s", what, expected); + scr_wasm_type_error(msg); + return false; +} + +static const ScrWasmModuleDesc *scr_wasm_lookup(const uint8_t *data, size_t len) { + uint8_t digest[32]; + bool hashed = false; + for (uint64_t i = 0; i < scr_wasm_registry.count; i++) { + const ScrWasmModuleDesc *d = scr_wasm_registry.modules[i]; + if (d->byte_length != len || d->abi_version != SCR_WASM_ABI_VERSION) continue; + if (!hashed) { + scr_wasm_sha256(data, len, digest); + hashed = true; + } + if (!memcmp(d->sha256, digest, 32)) return d; + } + return NULL; +} + +static void scr_wasm_not_translated(const char *what) { + char msg[400]; + snprintf(msg, sizeof msg, + "%s: this module was not translated when the program was built (scriptc compiles WebAssembly ahead of " + "time and cannot compile modules whose bytes it did not see; see https://scriptc.dev/limitations)", + what); + scr_wasm_throw_kind(SCR_WASM_COMPILE_ERROR, msg); +} + +static ScrDyn *scr_wasm_module_from(ScrDyn *bytes, const char *what, const char *expected) { + const uint8_t *data; + size_t len; + if (!scr_wasm_bytes_of(bytes, what, expected, &data, &len)) return NULL; + const ScrWasmModuleDesc *desc = scr_wasm_lookup(data, len); + if (!desc) { + scr_wasm_not_translated(what); + return NULL; + } + ScrWasmObj *o = scr_wasm_obj_new(SCR_WASM_K_MODULE); + o->desc = desc; + return scr_wasm_box(o); +} + +ScrDyn *scr_wasm_module_new(ScrDyn *bytes) { + return scr_wasm_module_from(bytes, "WebAssembly.Module()", "a buffer source"); +} + +bool scr_wasm_validate(ScrDyn *bytes) { + const uint8_t *data; + size_t len; + if (!scr_wasm_bytes_of(bytes, "WebAssembly.validate()", "a buffer source", &data, &len)) return false; + return scr_wasm_lookup(data, len) != NULL; +} + +/* ── instances ───────────────────────────────────────────────────────── */ + +/* A member of an import object (+1, NULL when absent or undefined, or with + * an exception pending from a getter). */ +static ScrDyn *scr_wasm_member(const ScrDyn *obj, const char *key, size_t len) { + ScrDyn *v = NULL; + switch (obj->kind) { + case SCR_DYN_OBJ: + case SCR_DYN_FUNC: + case SCR_DYN_ARR: + case SCR_DYN_PROXY: + v = scr_dyn_obj_read(obj, key, len); + break; + case SCR_DYN_TYPED_REF: { + ScrStr *k = scr_str_new(key, len); + v = scr_dyn_typed_ref_key_get(obj, k); + scr_str_release(k); + break; + } + case SCR_DYN_HANDLE: { + ScrStr *k = scr_str_new(key, len); + v = scr_dyn_handle_key_get(obj, k); + scr_str_release(k); + break; + } + default: + break; + } + if (v && v->kind == SCR_DYN_UNDEF) { + scr_dyn_release(v); + v = NULL; + } + return v; +} + +static bool scr_wasm_is_object(const ScrDyn *v) { + return v && (v->kind == SCR_DYN_OBJ || v->kind == SCR_DYN_TYPED_REF || v->kind == SCR_DYN_HANDLE || + v->kind == SCR_DYN_PROXY || v->kind == SCR_DYN_FUNC || v->kind == SCR_DYN_ARR); +} + +static void scr_wasm_link_error(const char *what, uint64_t i, const ScrWasmImportDesc *im, const char *reason) { + char msg[600]; + snprintf(msg, sizeof msg, "%s: Import #%llu \"%.*s\" \"%.*s\": %s", what, (unsigned long long)i, + (int)im->module_len, im->module, (int)im->name_len, im->name, reason); + scr_wasm_throw_kind(SCR_WASM_LINK_ERROR, msg); +} + +static bool scr_wasm_guarded(const ScrWasmModuleDesc *desc) { +#if SCR_WASM_SIGNALS + return !(desc->flags & SCR_WASM_DESC_BOUNDS_CHECKS); +#else + (void)desc; + return false; +#endif +} + +static ScrDyn *scr_wasm_instance_from(const ScrWasmModuleDesc *desc, ScrDyn *imports, const char *what) { + scr_wasm_install(); + char msg[400]; + bool have_imports = imports && imports->kind != SCR_DYN_UNDEF; + if (have_imports && !scr_wasm_is_object(imports)) { + snprintf(msg, sizeof msg, "%s: Argument 1 must be an object", what); + scr_wasm_type_error(msg); + return NULL; + } + if (desc->import_count && !have_imports) { + snprintf(msg, sizeof msg, "%s: Imports argument must be present and must be an object", what); + scr_wasm_type_error(msg); + return NULL; + } + /* Read every import value first (V8's order), then check memories, then + * the rest in order. */ + uint64_t n = desc->import_count; + ScrDyn **values = calloc(n ? n : 1, sizeof *values); + if (!values) scr_trap("scriptc: out of memory\n"); + bool ok = true; + for (uint64_t i = 0; ok && i < n; i++) { + const ScrWasmImportDesc *im = &desc->imports[i]; + ScrDyn *ns = scr_wasm_member(imports, im->module, (size_t)im->module_len); + if (scr_exc_pending()) { + ok = false; + } else if (!scr_wasm_is_object(ns)) { + snprintf(msg, sizeof msg, "%s: Import #%llu \"%.*s\": module is not an object or function", what, + (unsigned long long)i, (int)im->module_len, im->module); + scr_wasm_type_error(msg); + ok = false; + } else { + values[i] = scr_wasm_member(ns, im->name, (size_t)im->name_len); + if (scr_exc_pending()) ok = false; + } + scr_dyn_release(ns); + } + for (uint64_t i = 0; ok && i < n; i++) { + const ScrWasmImportDesc *im = &desc->imports[i]; + if (im->kind == SCR_WASM_MEMORY && !scr_wasm_unbox(values[i], SCR_WASM_K_MEMORY)) { + scr_wasm_link_error(what, i, im, "memory import must be a WebAssembly.Memory object"); + ok = false; + } + } + for (uint64_t i = 0; ok && i < n; i++) { + const ScrWasmImportDesc *im = &desc->imports[i]; + const ScrDyn *v = values[i]; + if (im->kind == SCR_WASM_FUNC && !(v && scr_dyn_is_callable(v))) { + scr_wasm_link_error(what, i, im, "function import requires a callable"); + ok = false; + } else if (im->kind == SCR_WASM_FUNC && scr_wasm_funcref_of(v) && + scr_wasm_funcref_of(v)->type != desc->func_types[im->index]) { + /* An exported WebAssembly function keeps its signature. */ + scr_wasm_link_error(what, i, im, "imported function does not match the expected type"); + ok = false; + } else if (im->kind == SCR_WASM_TABLE) { + ScrWasmObj *t = scr_wasm_unbox(v, SCR_WASM_K_TABLE); + if (!t) { + scr_wasm_link_error(what, i, im, "table import requires a WebAssembly.Table"); + ok = false; + } else if (t->table->elem != im->type[0]) { + scr_wasm_link_error(what, i, im, "imported table does not match the expected type"); + ok = false; + } + } else if (im->kind == SCR_WASM_GLOBAL) { + ScrWasmObj *g = scr_wasm_unbox(v, SCR_WASM_K_GLOBAL); + bool mutable_ = desc->globals[im->index].mutable_ != 0; + char type = im->type[0]; + if (g) { + if (g->global->type != type || g->global->mutable_ != mutable_) { + scr_wasm_link_error(what, i, im, "imported global does not match the expected type"); + ok = false; + } + } else if (mutable_) { + scr_wasm_link_error(what, i, im, "imported mutable global must be a WebAssembly.Global object"); + ok = false; + } else if (type == 'I' ? !(v && v->kind == SCR_DYN_BIGINT) + : type == 'x' || type == 'r' ? false + : !(v && v->kind == SCR_DYN_NUM)) { + scr_wasm_link_error(what, i, im, + "global import must be a number, valid Wasm reference, or WebAssembly.Global object"); + ok = false; + } + } + } + if (!ok) { + for (uint64_t k = 0; k < n; k++) scr_dyn_release(values[k]); + free(values); + return NULL; + } + + ScrWasmInst *host = calloc(1, sizeof *host); + if (!host) scr_trap("scriptc: out of memory\n"); + host->rc = 1; + host->desc = desc; + size_t nf = (size_t)desc->func_count; + size_t slots = 4 + (size_t)desc->table_count + (size_t)desc->global_count; + host->inst = calloc(slots, sizeof(void *)); + host->funcs = calloc(nf ? nf : 1, sizeof *host->funcs); + host->funcrefs = calloc(nf ? nf : 1, sizeof *host->funcrefs); + host->export_fns = calloc(nf ? nf : 1, sizeof *host->export_fns); + host->export_names = calloc(nf ? nf : 1, sizeof *host->export_names); + host->tables = calloc(desc->table_count ? desc->table_count : 1, sizeof *host->tables); + host->globals = calloc(desc->global_count ? desc->global_count : 1, sizeof *host->globals); + host->data_dropped = calloc(desc->data_count ? desc->data_count : 1, 1); + host->elem_dropped = calloc(desc->elem_count ? desc->elem_count : 1, 1); + if (!host->inst || !host->funcs || !host->funcrefs || !host->export_fns || !host->export_names || + !host->tables || !host->globals || !host->data_dropped || !host->elem_dropped) + scr_trap("scriptc: out of memory\n"); + void **inst = host->inst; + inst[0] = host; +#ifdef SCR_RC_AUDIT + scr_wasm_note_host(host); +#endif + for (size_t f = 0; f < nf; f++) { + host->funcrefs[f].code = desc->func_codes[f]; + host->funcrefs[f].type = desc->func_types[f]; + host->funcrefs[f].inst = inst; + } + inst[3] = host->funcrefs; + for (uint64_t i = 0; i < n; i++) { + const ScrWasmImportDesc *im = &desc->imports[i]; + ScrDyn *v = values[i]; + switch (im->kind) { + case SCR_WASM_FUNC: + host->funcs[im->index] = v; + values[i] = NULL; + break; + case SCR_WASM_MEMORY: + host->memory = scr_wasm_memory_retain(scr_wasm_unbox(v, SCR_WASM_K_MEMORY)->memory); + break; + case SCR_WASM_TABLE: + host->tables[im->index] = scr_wasm_table_retain(scr_wasm_unbox(v, SCR_WASM_K_TABLE)->table); + break; + default: { + ScrWasmObj *g = scr_wasm_unbox(v, SCR_WASM_K_GLOBAL); + if (g) { + host->globals[im->index] = scr_wasm_global_retain(g->global); + } else { + char type = im->type[0]; + ScrWasmGlobal *cell = scr_wasm_global_new(type, false); + uint64_t value = 0; + scr_wasm_from_js(type, v, &value); + if (type == 'x') scr_wasm_global_set_ref(cell, (void *)(uintptr_t)value); + else cell->value = value; + host->globals[im->index] = cell; + } + break; + } + } + scr_dyn_release(values[i]); + } + free(values); + if (desc->memory_count && !host->memory) { + host->memory = scr_wasm_memory_new(desc->memory_min, desc->memory_max == UINT64_MAX ? SCR_WASM_MAX_PAGES + : desc->memory_max, + scr_wasm_guarded(desc), what); + if (!host->memory) return NULL; + } + if (host->memory) { + inst[1] = host->memory->base; + inst[2] = host->memory; + } + for (uint64_t t = 0; t < desc->table_count; t++) { + const ScrWasmTableDesc *td = &desc->tables[t]; + if (!host->tables[t]) host->tables[t] = scr_wasm_table_new((char)td->elem, td->min, td->max); + inst[4 + t] = host->tables[t]; + } + for (uint64_t g = 0; g < desc->global_count; g++) { + const ScrWasmGlobalDesc *gd = &desc->globals[g]; + if (!host->globals[g]) host->globals[g] = scr_wasm_global_new((char)gd->type, gd->mutable_ != 0); + inst[4 + desc->table_count + g] = host->globals[g]; + } +#if SCR_WASM_SIGNALS + if (scr_wasm_guarded(desc)) pthread_once(&scr_wasm_handler_once, scr_wasm_install_handler); +#endif + /* Globals and segments, then the start function. */ + bool was = scr_wasm_instantiating; + scr_wasm_instantiating = true; + int trap = scr_wasm_enter(scr_wasm_init_thunk, inst, NULL, NULL); + scr_wasm_instantiating = was; + if (trap) { + if (trap == SCR_WASM_TRAP_DATA_SEGMENT) { + snprintf(msg, sizeof msg, "%s: data segment %u is out of bounds (offset %u, length %u, memory size %llu)", what, + scr_wasm_segment_failure.seg, scr_wasm_segment_failure.offset, scr_wasm_segment_failure.length, + (unsigned long long)scr_wasm_segment_failure.size); + scr_wasm_throw_kind(SCR_WASM_RUNTIME_ERROR, msg); + } else if (trap == SCR_WASM_TRAP_TABLE_OOB) { + snprintf(msg, sizeof msg, "%s: table index is out of bounds", what); + scr_wasm_throw_kind(SCR_WASM_RUNTIME_ERROR, msg); + } else { + scr_wasm_throw_trap(trap); + } + return NULL; + } + if (desc->start) { + trap = scr_wasm_enter(scr_wasm_start_thunk, inst, NULL, NULL); + if (trap) { + scr_wasm_throw_trap(trap); + return NULL; + } + } + + ScrDyn *exports = scr_dyn_new_obj_null_proto(); + for (uint64_t i = 0; i < desc->export_count; i++) { + const ScrWasmExportDesc *ex = &desc->exports[i]; + ScrDyn *value; + if (ex->kind == SCR_WASM_FUNC) { + value = scr_wasm_function_value(host, (uint32_t)ex->index); + } else { + int kind = ex->kind == SCR_WASM_MEMORY ? SCR_WASM_K_MEMORY + : ex->kind == SCR_WASM_TABLE ? SCR_WASM_K_TABLE + : SCR_WASM_K_GLOBAL; + ScrWasmObj *o = scr_wasm_obj_new(kind); + o->inst = scr_wasm_inst_retain(host); + if (kind == SCR_WASM_K_MEMORY) o->memory = scr_wasm_memory_retain(host->memory); + else if (kind == SCR_WASM_K_TABLE) o->table = scr_wasm_table_retain(host->tables[ex->index]); + else o->global = scr_wasm_global_retain(host->globals[ex->index]); + value = scr_wasm_box(o); + } + scr_dyn_obj_set(exports, ex->name, (size_t)ex->name_len, value); + } + ScrDyn *frozen = scr_dyn_freeze(exports); + scr_dyn_release(frozen); + host->exports = exports; + ScrWasmObj *o = scr_wasm_obj_new(SCR_WASM_K_INSTANCE); + o->inst = host; /* takes the creation reference */ + return scr_wasm_box(o); +} + +ScrDyn *scr_wasm_instance_new(ScrDyn *module, ScrDyn *imports) { + scr_wasm_install(); + ScrWasmObj *m = scr_wasm_unbox(module, SCR_WASM_K_MODULE); + if (!m) { + scr_wasm_type_error("WebAssembly.Instance(): Argument 0 must be a WebAssembly.Module"); + return NULL; + } + return scr_wasm_instance_from(m->desc, imports, "WebAssembly.Instance()"); +} + +/* ── promises ────────────────────────────────────────────────────────── */ + +/* A promise settled now: fulfilled with value, or rejected with the + * pending exception. */ +static ScrPromise *scr_wasm_settled(ScrDyn *value) { + if (value) { + ScrPromise *p = scr_promise_settled_ref(value, &scr_dyn_retain_v, &scr_dyn_release_v, &scr_dyn_trace_v); + return p; + } + ScrPromise *p = scr_promise_new(); + scr_promise_reject_pending(p); + return p; +} + +/* compile and instantiate over bytes settle on a later loop turn, after + * the current microtasks, as V8's compile task does. */ +enum { SCR_WASM_JOB_COMPILE, SCR_WASM_JOB_INSTANTIATE }; + +static void scr_wasm_job_fire(ScrClosure *clo) { + ScrPromise *p = scr_box_get_ref(clo->caps[0]); + ScrDyn *source = scr_box_get_ref(clo->caps[1]); + ScrDyn *imports = scr_box_get_ref(clo->caps[2]); + int job = (int)scr_box_get_f64(clo->caps[3]); + const char *what = job == SCR_WASM_JOB_COMPILE ? "WebAssembly.compile()" : "WebAssembly.instantiate()"; + ScrDyn *module = scr_wasm_module_from(source, what, "a buffer source"); + ScrDyn *result = module; + if (module && job == SCR_WASM_JOB_INSTANTIATE) { + ScrDyn *instance = scr_wasm_instance_from(scr_wasm_unbox(module, SCR_WASM_K_MODULE)->desc, imports, what); + if (instance) { + result = scr_dyn_new_obj(); + scr_dyn_obj_set(result, "module", 6, module); + scr_dyn_obj_set(result, "instance", 8, instance); + } else { + scr_dyn_release(module); + result = NULL; + } + } + if (result) { + scr_promise_resolve_dyn(p, result); /* moves result in */ + } else { + scr_promise_reject_pending(p); + } + scr_dyn_release(source); + scr_dyn_release(imports); + scr_promise_release(p); +} + +static ScrPromise *scr_wasm_defer(int job, ScrDyn *source, ScrDyn *imports) { + ScrPromise *p = scr_promise_new(); + ScrClosure *clo = scr_closure_new((void *)scr_wasm_job_fire, 4); + clo->caps[0] = scr_box_new_obj(scr_promise_retain_v, scr_promise_release_v, NULL); + scr_box_set_ref(clo->caps[0], scr_promise_retain(p)); + clo->caps[1] = scr_box_new_obj(scr_dyn_retain_v, scr_dyn_release_v, scr_dyn_trace_v); + scr_box_set_ref(clo->caps[1], scr_dyn_retain(source ? source : scr_dyn_undefined())); + clo->caps[2] = scr_box_new_obj(scr_dyn_retain_v, scr_dyn_release_v, scr_dyn_trace_v); + scr_box_set_ref(clo->caps[2], scr_dyn_retain(imports ? imports : scr_dyn_undefined())); + clo->caps[3] = scr_box_new(SCR_BOX_F64); + scr_box_set_f64(clo->caps[3], (double)job); + scr_loop_defer(clo); + return p; +} + +static bool scr_wasm_is_buffer_source(const ScrDyn *v) { + return v && (v->kind == SCR_DYN_BYTES || (v->kind == SCR_DYN_HANDLE && scr_array_buffer_is(v))); +} + +ScrPromise *scr_wasm_compile(ScrDyn *bytes) { + scr_wasm_install(); + if (!scr_wasm_is_buffer_source(bytes)) { + scr_wasm_type_error("WebAssembly.compile(): Argument 0 must be a buffer source"); + return scr_wasm_settled(NULL); + } + return scr_wasm_defer(SCR_WASM_JOB_COMPILE, bytes, NULL); +} + +ScrPromise *scr_wasm_instantiate(ScrDyn *source, ScrDyn *imports) { + scr_wasm_install(); + ScrWasmObj *m = scr_wasm_unbox(source, SCR_WASM_K_MODULE); + if (m) return scr_wasm_settled(scr_wasm_instance_from(m->desc, imports, "WebAssembly.instantiate()")); + if (!scr_wasm_is_buffer_source(source)) { + scr_wasm_type_error("WebAssembly.instantiate(): Argument 0 must be a buffer source or a WebAssembly.Module object"); + return scr_wasm_settled(NULL); + } + if (imports && imports->kind != SCR_DYN_UNDEF && !scr_wasm_is_object(imports)) { + scr_wasm_type_error("WebAssembly.instantiate(): Argument 1 must be an object"); + return scr_wasm_settled(NULL); + } + return scr_wasm_defer(SCR_WASM_JOB_INSTANTIATE, source, imports); +} + +/* ── instanceof and the error constructors ───────────────────────────── */ + +bool scr_wasm_is(const ScrDyn *value, double kind) { + int k = (int)kind; + if (k <= SCR_WASM_K_GLOBAL) return scr_wasm_unbox(value, k) != NULL; + ScrError *e = value ? scr_errdyn_err_of(value) : NULL; + if (!e) return false; + int brand = scr_wasm_error_brand(e); + scr_error_release(e); + return brand == k - 5; +} + +ScrDyn *scr_wasm_error_new(double kind, ScrDyn *message, ScrDyn *options) { + ScrStr *text = NULL; + if (message && message->kind != SCR_DYN_UNDEF) { + text = scr_dyn_string_coerce_js(message); + if (!text) return NULL; + } + ScrError *e = scr_wasm_error_make((int)kind - 5, text); + if (!text) e->message_present = false; + scr_str_release(text); + if (options && scr_wasm_is_object(options)) { + ScrDyn *cause = scr_wasm_member(options, "cause", 5); + if (cause) { + scr_error_define_cause(e, cause); + scr_dyn_release(cause); + } + } + ScrDyn *d = scr_dyn_from_error(e); + scr_error_release(e); + return d; +} + +/* ── the namespace and its functions as values ───────────────────────── */ + +enum { SCR_WASM_FN_COMPILE, SCR_WASM_FN_INSTANTIATE, SCR_WASM_FN_VALIDATE }; +static const char *const scr_wasm_fn_names[] = {"compile", "instantiate", "validate"}; + +static ScrDyn *scr_wasm_fn_call(ScrClosure *clo, ScrDyn *const *args, size_t argc) { + int kind = (int)scr_box_get_f64(clo->caps[0]); + ScrDyn *a0 = argc > 0 ? args[0] : scr_dyn_undefined(); + ScrDyn *a1 = argc > 1 ? args[1] : scr_dyn_undefined(); + if (kind == SCR_WASM_FN_VALIDATE) { + bool ok = scr_wasm_validate(a0); + if (scr_exc_pending()) return NULL; + return scr_dyn_new_bool(ok); + } + ScrPromise *p = kind == SCR_WASM_FN_COMPILE ? scr_wasm_compile(a0) : scr_wasm_instantiate(a0, a1); + ScrDyn *boxed = scr_dyn_new_promise(p); + scr_promise_release(p); + return boxed; +} + +/* WebAssembly.compile, instantiate and validate as function values (+1), + * one per thread and function, as in Node. */ +static SCR_TL ScrDyn *scr_wasm_fns[3]; +static SCR_TL ScrDyn *scr_wasm_ns; + +ScrDyn *scr_wasm_function(double kind) { + ScrDyn **fns = scr_wasm_fns; + int k = (int)kind; + if (!fns[k]) { + ScrClosure *closure = scr_closure_new(NULL, 1); + closure->caps[0] = scr_box_new(SCR_BOX_F64); + scr_box_set_f64(closure->caps[0], (double)k); + fns[k] = scr_dyn_new_func(closure, scr_wasm_fn_call, k == SCR_WASM_FN_INSTANTIATE ? 1 : 1, "", + scr_wasm_fn_names[k]); + } + return scr_dyn_retain(fns[k]); +} + +/* globalThis.WebAssembly as a value (+1): an object with the namespace's + * functions. The classes are not values yet: their constructors and + * instanceof lower at their use sites. */ +ScrDyn *scr_wasm_namespace(void) { + if (!scr_wasm_ns) { + scr_wasm_ns = scr_dyn_new_obj(); + for (int k = 0; k < 3; k++) + scr_dyn_obj_set(scr_wasm_ns, scr_wasm_fn_names[k], strlen(scr_wasm_fn_names[k]), scr_wasm_function(k)); + } + return scr_dyn_retain(scr_wasm_ns); +} + +/* The global object seen through a cast to a type with a `WebAssembly` + * member (`globalThis as unknown as { WebAssembly: ... }`): an object + * whose WebAssembly member is the namespace (+1). */ +ScrDyn *scr_wasm_global_view(void) { + ScrDyn *view = scr_dyn_new_obj(); + scr_dyn_obj_set(view, "WebAssembly", 11, scr_wasm_namespace()); + return view; +} + +#ifdef SCR_RC_AUDIT +static void scr_wasm_teardown(void) { + for (size_t i = 0; i < scr_wasm_host_count; i++) { + ScrWasmInst *host = scr_wasm_hosts[i]; + const ScrWasmModuleDesc *desc = host->desc; + scr_dyn_release(host->exports); + for (uint64_t f = 0; f < desc->func_count; f++) { + scr_dyn_release(host->export_fns[f]); + scr_dyn_release(host->funcs[f]); + free(host->export_names[f]); + } + scr_wasm_memory_release(host->memory); + for (uint64_t t = 0; t < desc->table_count; t++) scr_wasm_table_release(host->tables[t]); + for (uint64_t g = 0; g < desc->global_count; g++) scr_wasm_global_release(host->globals[g]); + free(host->funcs); + free(host->funcrefs); + free(host->export_fns); + free(host->export_names); + free(host->tables); + free(host->globals); + free(host->data_dropped); + free(host->elem_dropped); + free(host->inst); + free(host); + } + free(scr_wasm_hosts); + scr_wasm_hosts = NULL; + scr_wasm_host_count = scr_wasm_host_cap = 0; + for (int k = 0; k < 3; k++) { + scr_dyn_release(scr_wasm_fns[k]); + scr_wasm_fns[k] = NULL; + } + scr_dyn_release(scr_wasm_ns); + scr_wasm_ns = NULL; +} +#endif diff --git a/packages/runtime/src/scr_wasm_abi.h b/packages/runtime/src/scr_wasm_abi.h new file mode 100644 index 000000000..bd2a1e3bd --- /dev/null +++ b/packages/runtime/src/scr_wasm_abi.h @@ -0,0 +1,191 @@ +/* The contract between translated WebAssembly modules and the runtime + * (scr_wasm.c). The compiler's translator (packages/compiler/src/wasm/ + * translate.ts) emits each module's code, an init function and one + * ScrWasmModuleDesc as LLVM IR in the program module, plus the registry + * scr_wasm_registry listing every translated module. The runtime + * implements the JavaScript API once, generically, over these + * descriptors; it never sees the translator's own data structures, and + * the translator never sees the runtime's. + * + * Every descriptor field is pointer- or 64-bit sized so the emitted LLVM + * structs and these C structs have the same layout without padding rules. + * Signatures are strings "params:results" over the letters i (i32), + * I (i64), f (f32), F (f64), r (funcref) and x (externref). Values travel + * in uint64_t slots: f32 and f64 as their bit patterns, references as + * pointers (externref: a borrowed ScrDyn *, NULL for null; funcref: a + * ScrWasmFuncRef *, NULL for null). + * + * Instance layout (the first argument of every translated function): + * 0 ScrWasmInst *host runtime state + * 8 uint8_t *memory_base memory 0's data + * 16 ScrWasmMemory *memory memory 0, or NULL + * 24 ScrWasmFuncRef *funcrefs one record per function + * 32 ScrWasmTable *tables[table_count] + * .. uint64_t *globals[global_count] one cell per global + * With guard pages (no SCR_WASM_DESC_BOUNDS_CHECKS) memory_base never + * changes: the memory is reserved once at its largest size plus a guard + * region, and grow only commits pages. With explicit bounds checks the + * translated code reloads memory_base and the byte length after every + * call. */ +#ifndef SCR_WASM_ABI_H +#define SCR_WASM_ABI_H +#include +#include +#include + +#define SCR_WASM_ABI_VERSION 1 + +enum { SCR_WASM_FUNC = 0, SCR_WASM_TABLE = 1, SCR_WASM_MEMORY = 2, SCR_WASM_GLOBAL = 3 }; + +/* Trap codes the translated code passes to scr_wasm_trap (translate.ts + * TRAP_*), plus the runtime's own. */ +enum { + SCR_WASM_TRAP_NONE = 0, + SCR_WASM_TRAP_UNREACHABLE = 1, + SCR_WASM_TRAP_MEMORY_OOB = 2, + SCR_WASM_TRAP_DIV_BY_ZERO = 3, + SCR_WASM_TRAP_DIV_UNREPRESENTABLE = 4, + SCR_WASM_TRAP_REM_BY_ZERO = 5, + SCR_WASM_TRAP_FLOAT_UNREPRESENTABLE = 6, + SCR_WASM_TRAP_TABLE_OOB = 7, + SCR_WASM_TRAP_SIGNATURE = 8, + SCR_WASM_TRAP_NULL = 9, + SCR_WASM_TRAP_ELEM_SEGMENT = 10, + /* Runtime-only codes. */ + SCR_WASM_TRAP_EXHAUSTION = 100, /* RangeError: Maximum call stack size exceeded */ + SCR_WASM_TRAP_HOST = 101, /* a JavaScript exception is pending */ + SCR_WASM_TRAP_DATA_SEGMENT = 102, /* instantiation: active data segment out of bounds */ +}; + +/* Descriptor flags. */ +#define SCR_WASM_DESC_BOUNDS_CHECKS 1u + +typedef void (*ScrWasmThunk)(void *inst, const uint64_t *args, uint64_t *results); + +typedef struct { + const char *module; + uint64_t module_len; + const char *name; + uint64_t name_len; + uint64_t kind; + /* The index among imports of this kind (function imports: the function + * index). */ + uint64_t index; + /* Functions: the signature; tables: the element letter; globals: the + * value letter; memories: "". */ + const char *type; +} ScrWasmImportDesc; + +typedef struct { + const char *name; + uint64_t name_len; + uint64_t kind; + uint64_t index; /* function, table, memory or global index */ + const char *type; + ScrWasmThunk call; /* functions */ +} ScrWasmExportDesc; + +typedef struct { + uint64_t elem; /* 'r' or 'x' */ + uint64_t min; + uint64_t max; /* UINT64_MAX when absent */ + uint64_t imported; +} ScrWasmTableDesc; + +typedef struct { + uint64_t type; /* signature letter */ + uint64_t mutable_; + uint64_t imported; +} ScrWasmGlobalDesc; + +typedef struct { + const uint8_t *data; + uint64_t len; +} ScrWasmDataDesc; + +/* An element segment: per item a function index, -1 for null, or + * -(2 + g) for the value of global g. */ +typedef struct { + uint64_t elem; + uint64_t count; + const int64_t *items; +} ScrWasmElemDesc; + +typedef struct ScrWasmModuleDesc { + uint8_t sha256[32]; + uint64_t byte_length; + uint64_t abi_version; + uint64_t flags; + uint64_t import_count; + const ScrWasmImportDesc *imports; + uint64_t export_count; + const ScrWasmExportDesc *exports; + uint64_t func_count; /* imported + defined */ + uint64_t imported_func_count; + /* Per function: the native code `(inst, params...) -> results` for + * functions a reference can name (NULL otherwise), the canonical + * signature identity call_indirect compares, and the signature text. */ + void *const *func_codes; + const uint64_t *func_types; + const char *const *func_sigs; + uint64_t table_count; + const ScrWasmTableDesc *tables; + uint64_t memory_count; /* 0 or 1 */ + uint64_t memory_min; /* pages */ + uint64_t memory_max; /* pages, UINT64_MAX when absent */ + uint64_t global_count; + const ScrWasmGlobalDesc *globals; + uint64_t data_count; + const ScrWasmDataDesc *datas; + uint64_t elem_count; + const ScrWasmElemDesc *elems; + /* Globals, table initializers and active segments, under the trap + * guard; then the start function `void (inst)`, or NULL. */ + void (*init)(void *inst); + void (*start)(void *inst); +} ScrWasmModuleDesc; + +/* The registry the compiler emits in the program module of every program + * that uses the WebAssembly API (count may be 0). */ +typedef struct { + uint64_t count; + const ScrWasmModuleDesc *const *modules; +} ScrWasmRegistry; +extern const ScrWasmRegistry scr_wasm_registry; + +/* Runtime objects the translated code reads at fixed offsets. */ +typedef struct ScrWasmMemory { + uint8_t *base; /* 0 */ + uint64_t size; /* 8: bytes */ + uint64_t max_pages; /* 16 */ + uint64_t reserved; /* 24: bytes of address space reserved at base */ + size_t rc; + bool guarded; + struct ScrDyn *buffer; /* the cached ArrayBuffer */ + uint64_t buffer_size; /* the size it was created at */ +} ScrWasmMemory; + +typedef struct ScrWasmFuncRef { + void *code; /* 0 */ + uint64_t type; /* 8 */ + void *inst; /* 16: the instance the code expects; its host and the + * record's position in its funcrefs name the function */ +} ScrWasmFuncRef; + +typedef struct ScrWasmTable { + void **elems; /* 0: ScrWasmFuncRef * or ScrDyn * (retained) */ + uint32_t size; /* 8 */ + uint32_t max; + size_t rc; + char elem; /* 'r' or 'x' */ +} ScrWasmTable; + +/* A global's cell: the value in the low bytes of `value`. */ +typedef struct ScrWasmGlobal { + uint64_t value; /* 0 */ + size_t rc; + char type; + bool mutable_; +} ScrWasmGlobal; + +#endif diff --git a/tests/corpus/webassembly-api.mjs b/tests/corpus/webassembly-api.mjs new file mode 100644 index 000000000..5215cd3a2 --- /dev/null +++ b/tests/corpus/webassembly-api.mjs @@ -0,0 +1,179 @@ +// The WebAssembly JavaScript API over modules translated to native code when +// the program is built: compile, instantiate, validate, Module, Instance, +// exported functions, memories, tables and globals, imports, linking two +// instances, every trap, link errors, the error classes, externref values +// and the asynchronous entry points. The modules are inline base64 literals +// (their text is in tests/wasm-spec/corpus/*.wat). +const api = Buffer.from("AGFzbQEAAAABLwlgAX8Bf2ACf38Bf2ABfwBgAABgAAF/YAJ+fgF+YAJ/fwJ/f2ABfQF9YAN/f38AAi0EA2VudgNsb2cAAgNlbnYEZmFpbAAAA2VudgRiYXNlA38AA2VudgNiaWcDfgADEhEAAAMBAQQFBgcAAAQAAAAICAQFAXABAggFBAEBAQQGFwN/AUEAC3wARAAAAAAAAApAC34AIwELB5kBEwZtZW1vcnkCAAV0YWJsZQEAB2NvdW50ZXIDAgJwaQMDBGJpZzIDBANhZGQABQVhcHBseQAGBGJ1bXAABwVtdWw2NAAIBmRpdm1vZAAJBm5hcnJvdwAKBnN0cmxlbgALBGdyb3cADAVwYWdlcwANCGNhbGxGYWlsAA4EdHJhcAAPB3JlY3Vyc2UAEARmaWxsABEEY29weQASCAEECQgBAEEACwICAwqHAhEHACAAQQJsCwcAIAAgAGwLBgAjABAACwcAIAAgAWoLCQAgASAAEQAACwsAIwJBAWokAiMCCwcAIAAgAX4LDAAgACABbSAAIAFvCwQAIAALIAEBfwJAA0AgACABai0AAEUNASABQQFqIQEMAAsLIAELBgAgAEAACwQAPwALCQAgABABQQFqC1kAAkACQAJAAkACQAJAAkAgAA4GAAECAwQFBgsAC0EBQQBuDwtB/////wcoAgAPC0EBQQJBABEBAA8LQQFBBxEAAA8LRAAAAAAAAPh/qg8LQYCAgIB4QX9tCwwAIABBAWoQEEEBagsLACAAIAEgAvwLAAsMACAAIAEgAvwKAAALCw4BAEEQCwhzY3JpcHRjAA==", "base64"); +const linked = Buffer.from("AGFzbQEAAAABFwRgAn9/AX9gAX8Bf2ABfwBgA39/fwF/AjYEA2FwaQZtZW1vcnkCAAEDYXBpBXRhYmxlAXAAAgNhcGkHY291bnRlcgN/AQNhcGkDYWRkAAADBQQBAAIDBycEBHJlYWQAAQh1c2VUYWJsZQACCnNldENvdW50ZXIAAwRhZGQzAAQKJwQHACAALQAACwkAIAEgABEBAAsGACAAJAALDAAgACABEAAgAhAACw==", "base64"); +const refs = Buffer.from("AGFzbQEAAAABHwZgAW8Bb2ACf28AYAF/AW9gAW8Bf2ACb38Bf2AAAX8DBwYAAQIDBAUEBQFvAQEKBgYBbwHQbwsHPAgEcmVmcwEABHNsb3QDAARrZWVwAAAFc3RvcmUAAQRsb2FkAAIGaXNOdWxsAAMEZ3JvdwAEBHNpemUABQosBgQAIAALCAAgACABJgALBgAgACUACwUAIADRCwkAIAAgAfwPAAsFAPwQAAs=", "base64"); + +const show = (v) => { + if (typeof v === "bigint") return `${v}n`; + if (Array.isArray(v)) return `[${v.map(show).join(", ")}]`; + return String(v); +}; +const attempt = (label, f) => { + try { + console.log(label, show(f())); + } catch (e) { + console.log(label, e instanceof Error ? `${e.name}: ${e.message}` : `threw ${show(e)}`); + } +}; + +console.log(WebAssembly.validate(api), WebAssembly.validate(new Uint8Array([1, 2, 3]))); +attempt("validate(5)", () => WebAssembly.validate(5)); +const module = new WebAssembly.Module(api); +console.log(module instanceof WebAssembly.Module, module instanceof WebAssembly.Instance, String(module)); +console.log(module); + +const logged = []; +const env = { + log: (v) => logged.push(`log ${v}`), + fail(v) { + if (v < 0) throw new RangeError(`negative ${v}`); + return v * 10; + }, + base: 41, + big: 9007199254740993n, +}; +const instance = new WebAssembly.Instance(module, { env }); +console.log(logged.join(","), instance instanceof WebAssembly.Instance); +const x = instance.exports; +console.log(Object.keys(x).join(","), Object.isFrozen(x), Object.getPrototypeOf(x)); +console.log(x.add.name, x.add.length, typeof x.add, x.add === instance.exports.add); + +attempt("add", () => x.add(2, 3)); +attempt("add coerced", () => x.add("40", { valueOf: () => 2 })); +attempt("add wraps", () => x.add(0x7fffffff, 1)); +attempt("add missing", () => x.add(5)); +attempt("apply double", () => x.apply(0, 21)); +attempt("apply square", () => x.apply(1, 12)); +attempt("bump", () => [x.bump(), x.bump(), x.counter.value]); +x.counter.value = 100; +attempt("bump after set", () => x.bump()); +attempt("pi", () => x.pi.value); +attempt("set pi", () => { + x.pi.value = 1; +}); +attempt("big2", () => x.big2.value); +attempt("mul64", () => x.mul64(123456789n, 1000000007n)); +attempt("mul64 wraps", () => x.mul64(-1n, 2n ** 63n)); +attempt("mul64 number", () => x.mul64(1, 2)); +attempt("divmod", () => x.divmod(-17, 5)); +attempt("narrow", () => x.narrow(0.1)); +attempt("strlen", () => x.strlen(16)); + +const bytes = new Uint8Array(x.memory.buffer); +console.log(bytes.length, String.fromCharCode(...bytes.subarray(16, 23))); +console.log(x.memory instanceof WebAssembly.Memory, x.table instanceof WebAssembly.Table, x.counter instanceof WebAssembly.Global); +attempt("grow", () => x.grow(1)); +attempt("pages", () => x.pages()); +console.log(x.memory.buffer.byteLength); +attempt("memory.grow", () => x.memory.grow(1)); +attempt("memory.grow too far", () => x.memory.grow(2)); +console.log(x.memory.buffer.byteLength, x.pages()); +attempt("grow too far in wasm", () => x.grow(5)); +x.fill(100, 0x41, 5); +x.copy(200, 100, 5); +console.log(String.fromCharCode(...new Uint8Array(x.memory.buffer, 200, 5))); +attempt("fill out of bounds", () => x.fill(x.memory.buffer.byteLength - 2, 0, 5)); + +attempt("callFail", () => x.callFail(4)); +attempt("callFail throws", () => x.callFail(-1)); +for (let k = 0; k <= 6; k++) attempt(`trap ${k}`, () => x.trap(k)); +attempt("recurse", () => x.recurse(0)); +try { + x.trap(0); +} catch (e) { + console.log( + e instanceof WebAssembly.RuntimeError, + e instanceof Error, + e instanceof WebAssembly.LinkError, + Object.keys(e).length, + Object.prototype.hasOwnProperty.call(e, "name"), + ); +} +attempt("after traps", () => x.add(1, 1)); + +console.log(x.table.length); +attempt("table.get out of range", () => x.table.get(5)); +attempt("table.grow", () => x.table.grow(1)); +console.log(x.table.length); +x.table.set(2, x.add); +console.log(x.table.get(2) === x.add, x.table.length); +attempt("table.get past the end", () => x.table.get(3)); + +const linkedInstance = new WebAssembly.Instance(new WebAssembly.Module(linked), { api: x }); +const y = linkedInstance.exports; +attempt("read", () => y.read(16)); +attempt("useTable", () => y.useTable(1, 9)); +attempt("useTable signature", () => y.useTable(2, 9)); +attempt("useTable null", () => y.useTable(3, 9)); +y.setCounter(7); +attempt("shared counter", () => x.counter.value); +attempt("add3", () => y.add3(1, 2, 3)); + +attempt("no imports", () => new WebAssembly.Instance(module)); +attempt("missing module", () => new WebAssembly.Instance(module, {})); +attempt("imports not an object", () => new WebAssembly.Instance(module, 5)); +attempt("not callable", () => new WebAssembly.Instance(module, { env: { ...env, log: 1 } })); +attempt("global type", () => new WebAssembly.Instance(module, { env: { ...env, base: "x" } })); +attempt("bigint global", () => new WebAssembly.Instance(module, { env: { ...env, big: 1 } })); +attempt("memory import", () => + new WebAssembly.Instance(new WebAssembly.Module(linked), { + api: { memory: {}, table: x.table, counter: x.counter, add: x.add }, + }), +); +attempt("mutable global as number", () => + new WebAssembly.Instance(new WebAssembly.Module(linked), { + api: { memory: x.memory, table: x.table, counter: 1, add: x.add }, + }), +); +attempt("signature mismatch", () => + new WebAssembly.Instance(new WebAssembly.Module(linked), { + api: { memory: x.memory, table: x.table, counter: x.counter, add: x.bump }, + }), +); +attempt("Instance(5)", () => new WebAssembly.Instance(5)); +attempt("Module(5)", () => new WebAssembly.Module(5)); +try { + new WebAssembly.Module(new Uint8Array([0, 97, 115, 109, 2, 0, 0, 0])); +} catch (e) { + console.log(e.name, e instanceof WebAssembly.CompileError, e instanceof Error); +} + +const custom = new WebAssembly.RuntimeError("custom", { cause: 5 }); +console.log(String(custom), custom.name, custom.message, custom.cause); +console.log(custom instanceof WebAssembly.RuntimeError, custom instanceof WebAssembly.CompileError, custom instanceof Error); +console.log(String(WebAssembly.LinkError("called")), String(new WebAssembly.CompileError())); + +const z = new WebAssembly.Instance(new WebAssembly.Module(refs)).exports; +const token = { id: 1 }; +console.log(z.keep(token) === token, z.keep(null), z.keep(undefined), z.isNull(null), z.isNull(undefined), z.isNull(0)); +z.store(0, token); +console.log(z.load(0) === token, z.refs.get(0) === token); +attempt("grow refs", () => z.grow("filler", 3)); +console.log(z.size(), z.load(2), z.refs.length); +z.slot.value = token; +console.log(z.slot.value === token); +attempt("store out of range", () => z.store(10, token)); + +const order = []; +const compiled = WebAssembly.compile(api) + .then((m) => { + order.push(`compiled ${m instanceof WebAssembly.Module}`); + return WebAssembly.instantiate(m, { env }); + }) + .then((i) => { + order.push(`instance ${i instanceof WebAssembly.Instance} ${i.exports.add(1, 1)}`); + }); +const pair = WebAssembly.instantiate(api, { env }).then((result) => { + order.push(`pair ${Object.keys(result).join(",")} ${result.instance.exports.add(2, 2)}`); +}); +const rejected = WebAssembly.compile(new Uint8Array([1])).catch((e) => order.push(`rejected ${e.name}`)); +const typeError = WebAssembly.instantiate(5).catch((e) => order.push(`${e.name}: ${e.message}`)); +const linkError = WebAssembly.instantiate(api, {}).catch((e) => order.push(`${e.name}: ${e.message}`)); +await Promise.all([compiled, pair, rejected, typeError, linkError]); +console.log(order.sort().join("\n")); +console.log(logged.length); diff --git a/tests/corpus/webassembly-feature-probe.js b/tests/corpus/webassembly-feature-probe.js index 7a164fd90..053e5c0c6 100644 --- a/tests/corpus/webassembly-feature-probe.js +++ b/tests/corpus/webassembly-feature-probe.js @@ -1,7 +1,6 @@ -// @deferred-fences: 2 // A JavaScript dependency's WebAssembly glue: the feature probe answers as -// in Node, and the loader that would instantiate a module is never reached -// (reaching it would throw scriptc's located WebAssembly fence). +// in Node, and the loader that would instantiate a module compiles (it is +// not reached here). function supportsWasm() { return typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function"; } diff --git a/tests/corpus/webassembly-spec-control/data.mjs b/tests/corpus/webassembly-spec-control/data.mjs new file mode 100644 index 000000000..0be8faedb --- /dev/null +++ b/tests/corpus/webassembly-spec-control/data.mjs @@ -0,0 +1,48 @@ +/* Generated by tests/wasm-spec/gen.mjs from the WebAssembly 2.0 core test + * suite (WebAssembly/spec wg-2.0, Apache-2.0) with wabt 1.0.37 wast2json: + * block.wast, br.wast, br_if.wast, br_table.wast, call.wast, call_indirect.wast, fac.wast, forward.wast, func.wast, func_ptrs.wast, if.wast, labels.wast, loop.wast, local_get.wast, local_set.wast, local_tee.wast, nop.wast, return.wast, select.wast, stack.wast, switch.wast, unreachable.wast, unwind.wast, left-to-right.wast, global.wast, start.wast. Do not edit. */ +export const modules = [ + "AGFzbQEAAAABPQtgAn9/AX9gAABgAAF/YAF/AGADf3x/A398f2AAA39+f2ABfwF/YAACf39gAAJ9fWAAA39/fmACf38Cf38DODcBAQICAgICAgICAgIBAgICAgICAAICAgEBAgYCAgECAgICAgICAgICAgICAgkCAgICAgICAgIBBAUBcAEBAQUDAQABBgYBfwFBCgsH0AY0BWVtcHR5AAEIc2luZ3VsYXIAAgVtdWx0aQADBm5lc3RlZAAEBGRlZXAABQ9hcy1zZWxlY3QtZmlyc3QABg1hcy1zZWxlY3QtbWlkAAcOYXMtc2VsZWN0LWxhc3QACA1hcy1sb29wLWZpcnN0AAkLYXMtbG9vcC1taWQACgxhcy1sb29wLWxhc3QACw9hcy1pZi1jb25kaXRpb24ADAphcy1pZi10aGVuAA0KYXMtaWYtZWxzZQAODmFzLWJyX2lmLWZpcnN0AA8NYXMtYnJfaWYtbGFzdAAQEWFzLWJyX3RhYmxlLWZpcnN0ABEQYXMtYnJfdGFibGUtbGFzdAASFmFzLWNhbGxfaW5kaXJlY3QtZmlyc3QAFBRhcy1jYWxsX2luZGlyZWN0LW1pZAAVFWFzLWNhbGxfaW5kaXJlY3QtbGFzdAAWDmFzLXN0b3JlLWZpcnN0ABcNYXMtc3RvcmUtbGFzdAAYFGFzLW1lbW9yeS5ncm93LXZhbHVlABkNYXMtY2FsbC12YWx1ZQAbD2FzLXJldHVybi12YWx1ZQAcD2FzLWRyb3Atb3BlcmFuZAAdC2FzLWJyLXZhbHVlAB4SYXMtbG9jYWwuc2V0LXZhbHVlAB8SYXMtbG9jYWwudGVlLXZhbHVlACATYXMtZ2xvYmFsLnNldC12YWx1ZQAhD2FzLWxvYWQtb3BlcmFuZAAiEGFzLXVuYXJ5LW9wZXJhbmQAIxFhcy1iaW5hcnktb3BlcmFuZAAkD2FzLXRlc3Qtb3BlcmFuZAAlEmFzLWNvbXBhcmUtb3BlcmFuZAAmEmFzLWJpbmFyeS1vcGVyYW5kcwAnE2FzLWNvbXBhcmUtb3BlcmFuZHMAKBFhcy1taXhlZC1vcGVyYW5kcwApCmJyZWFrLWJhcmUAKgticmVhay12YWx1ZQArEWJyZWFrLW11bHRpLXZhbHVlACwOYnJlYWstcmVwZWF0ZWQALQticmVhay1pbm5lcgAuBXBhcmFtAC8GcGFyYW1zADAJcGFyYW1zLWlkADELcGFyYW0tYnJlYWsAMgxwYXJhbXMtYnJlYWsAMw9wYXJhbXMtaWQtYnJlYWsANAdlZmZlY3RzADUIdHlwZS11c2UANgkHAQBBAAsBEwrSCDcCAAsIAAJACwJACwsLAAJAAQsCf0EHCws+AAJAEAAQABAAEAALAn8QABAAEABBBxAACxoCBRAAEAAQAEEIEAAQABAAEABCBxAAEAAQABAAQQkQAAsaGgsVAAJ/AkAQAAJACwELAn8QAEEJCwsLeQACfwJ/An8CfwJ/An8CfwJ/An8CfwJ/An8CfwJ/An8CfwJ/An8CfwJ/An8CfwJ/An8CfwJ/An8CfwJ/An8CfwJ/An8CfwJ/An8CfwJ/EABBlgELCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsMAAJ/QQELQQJBAxsLDABBAgJ/QQELQQMbCwwAQQJBAwJ/QQELGwsOAAN/An9BAQsQABAACwsOAAN/EAACf0EBCxAACwsOAAN/EAAQAAJ/QQELCwsMAAJ/QQELBEAQAAsLDwBBAQR/An9BAQsFQQILCw8AQQEEf0ECBQJ/QQELCwsOAAJ/An9BAQtBAg0ACwsOAAJ/QQICf0EBCw0ACwsQAAJ/An9BAQtBAg4BAAALCxAAAn9BAgJ/QQELDgEAAAsLBAAgAAsRAAJ/An9BAQtBAkEAEQAACwsRAAJ/QQICf0EBC0EAEQAACwsRAAJ/QQFBAgJ/QQALEQAACwsMAAJ/QQELQQE2AgALDABBCgJ/QQELNgIACwkAAn9BAQtAAAsEACAACwkAAn9BAQsQGgsIAAJ/QQELDwsIAAJ/QQELGgsMAAJ/An9BAQsMAAsLDQEBfwJ/QQELIQAgAAsLAQF/An9BAQsiAAsLAAJ/QQELJAAjAAsKAAJ/QQELKAIACwoAAn8QAEENC2gLEQACfxAAQQMLAn8QAEEEC2wLCgACfxAAQQ0LRQsXAAJ9EABDAABAQAsCfRAAQwAAQEALXgsOAAIHEABBAxAAQQQLbAsUAAIIEABDAABAQBAAQwAAQEALXgsRAAIHEABBAxAAQQQLQQVqbAsmAAJADAAACwJAQQENAAALAkBBAA4AAAALAkBBAQ4CAAAAAAtBEwsLAAJ/QRIMAEETCwsTAAIJQRJBbkISDABBE0FtQhMLCzEAAn9BEgwAQRMMAEEUQQANABpBFEEBDQAaQRUMAEEWQQQOAABBF0EBDgIAAABBFQsLRQEBf0EAIQAgAAJ/An9BAQwBCwtqIQAgAAJ/AkAMAAtBAgtqIQAgAAJ/QQQMAGgLaiEAIAACfwJ/QQgMAQtoC2ohACAACwoAQQECBkECagsLCgBBAUECAgBqCwsKAEEBQQICCgtqCwwAQQECBkECagwACwsMAEEBQQICAGoMAAsLDABBAUECAgoMAAtqCy8BAX8CQEEBIQAgAEEDbCEAIABBBWshACAAQQdsIQAMACAAQeQAbCEACyAAQXJGCz0AAkALAn9BAAsCAxoLQQBEAAAAAAAAAABBAAIECxoaGgJ/QQALAgMaC0EARAAAAAAAAAAAQQACBAsaGhoL", + "AGFzbQEAAAABKwlgA39/fwF/YAAAYAABf2AAAX5gAAF9YAABfGAAAnx8YAACf35gAn9/AX8DS0oBAQEBAQEBAQECAwQFBgEBAQICAgICAQICAQICAwcCCAgICAICAAICAgICAgICAgICAgQDAgICAgICBAIDAgICAgICAgICAgICAgQFAXABAQEFAwEAAQYGAX8BQQoLB5IKSAh0eXBlLWkzMgABCHR5cGUtaTY0AAIIdHlwZS1mMzIAAwh0eXBlLWY2NAAEDHR5cGUtaTMyLWkzMgAFDHR5cGUtaTY0LWk2NAAGDHR5cGUtZjMyLWYzMgAHDHR5cGUtZjY0LWY2NAAIDnR5cGUtaTMyLXZhbHVlAAkOdHlwZS1pNjQtdmFsdWUACg50eXBlLWYzMi12YWx1ZQALDnR5cGUtZjY0LXZhbHVlAAwSdHlwZS1mNjQtZjY0LXZhbHVlAA0OYXMtYmxvY2stZmlyc3QADgxhcy1ibG9jay1taWQADw1hcy1ibG9jay1sYXN0ABAOYXMtYmxvY2stdmFsdWUAEQ1hcy1sb29wLWZpcnN0ABILYXMtbG9vcC1taWQAEwxhcy1sb29wLWxhc3QAFAthcy1ici12YWx1ZQAVDWFzLWJyX2lmLWNvbmQAFg5hcy1icl9pZi12YWx1ZQAXE2FzLWJyX2lmLXZhbHVlLWNvbmQAGBFhcy1icl90YWJsZS1pbmRleAAZEWFzLWJyX3RhYmxlLXZhbHVlABoXYXMtYnJfdGFibGUtdmFsdWUtaW5kZXgAGw9hcy1yZXR1cm4tdmFsdWUAHBBhcy1yZXR1cm4tdmFsdWVzAB0KYXMtaWYtY29uZAAeCmFzLWlmLXRoZW4AHwphcy1pZi1lbHNlACAPYXMtc2VsZWN0LWZpcnN0ACEQYXMtc2VsZWN0LXNlY29uZAAiDmFzLXNlbGVjdC1jb25kACMNYXMtc2VsZWN0LWFsbAAkDWFzLWNhbGwtZmlyc3QAJgthcy1jYWxsLW1pZAAnDGFzLWNhbGwtbGFzdAAoC2FzLWNhbGwtYWxsACkVYXMtY2FsbF9pbmRpcmVjdC1mdW5jACoWYXMtY2FsbF9pbmRpcmVjdC1maXJzdAArFGFzLWNhbGxfaW5kaXJlY3QtbWlkACwVYXMtY2FsbF9pbmRpcmVjdC1sYXN0AC0UYXMtY2FsbF9pbmRpcmVjdC1hbGwALhJhcy1sb2NhbC5zZXQtdmFsdWUALxJhcy1sb2NhbC50ZWUtdmFsdWUAMBNhcy1nbG9iYWwuc2V0LXZhbHVlADEPYXMtbG9hZC1hZGRyZXNzADIQYXMtbG9hZE4tYWRkcmVzcwAzEGFzLXN0b3JlLWFkZHJlc3MANA5hcy1zdG9yZS12YWx1ZQA1DWFzLXN0b3JlLWJvdGgANhFhcy1zdG9yZU4tYWRkcmVzcwA3D2FzLXN0b3JlTi12YWx1ZQA4DmFzLXN0b3JlTi1ib3RoADkQYXMtdW5hcnktb3BlcmFuZAA6DmFzLWJpbmFyeS1sZWZ0ADsPYXMtYmluYXJ5LXJpZ2h0ADwOYXMtYmluYXJ5LWJvdGgAPQ9hcy10ZXN0LW9wZXJhbmQAPg9hcy1jb21wYXJlLWxlZnQAPxBhcy1jb21wYXJlLXJpZ2h0AEAPYXMtY29tcGFyZS1ib3RoAEESYXMtY29udmVydC1vcGVyYW5kAEITYXMtbWVtb3J5Lmdyb3ctc2l6ZQBDEm5lc3RlZC1ibG9jay12YWx1ZQBED25lc3RlZC1ici12YWx1ZQBFEm5lc3RlZC1icl9pZi12YWx1ZQBGF25lc3RlZC1icl9pZi12YWx1ZS1jb25kAEcVbmVzdGVkLWJyX3RhYmxlLXZhbHVlAEgbbmVzdGVkLWJyX3RhYmxlLXZhbHVlLWluZGV4AEkJBwEAQQALASUK5QhKAgALCQACQAwAaBoLCwkAAkAMAHoaCwsJAAJADACMGgsLCQACQAwAmhoLCwkAAkAMAGoaCwsJAAJADAB8GgsLCQACQAwAkhoLCwkAAkAMAKAaCwsKAAJ/QQEMAGgLCwoAAn5CAgwAegsLDQACfUMAAEBADACMCwsRAAJ8RAAAAAAAABBADACaCwsjAAIGRAAAAAAAABBARAAAAAAAABRADACgRAAAAAAAABhACwsJAAJADAAQAAsLCwACQBAADAAQAAsLCgACQAEQAAwACwsMAAJ/ARAAQQIMAAsLDgACfwN/QQMMAUECCwsLEAACfwN/EABBBAwBQQILCwsPAAJ/A38BEABBBQwBCwsLCwACf0EJDAAMAAsLCQACQAwADQALCxAAAn9BCAwAQQENABpBBwsLEAACf0EGQQkMAA0AGkEHCwsMAAJADAAOAgAAAAsLEgACf0EKDABBAQ4CAAAAQQcLCxEAAn9BBkELDAAOAQAAQQcLCwoAAn5CBwwADwsLDgBBAgJ+QQFCBwwADwsLEQACf0ECDAAEf0EABUEBCwsLEQACfyAABH9BAwwBBSABCwsLEQACfyAABH8gAQVBBAwBCwsLDgACf0EFDAAgACABGwsLDgACfyAAQQYMACABGwsLDgACf0EAQQFBBwwAGwsLCgACf0EIDAAbCwsEAEF/Cw8AAn9BDAwAQQJBAxAlCwsPAAJ/QQFBDQwAQQMQJQsLDwACf0EBQQJBDgwAECULCwsAAn9BDwwAECULCxIAAn9BFAwAQQFBAkEDEQAACwsSAAJ/QQBBFQwAQQJBAxEAAAsLEgACf0EAQQFBFgwAQQMRAAALCxIAAn9BAEEBQQJBFwwAEQAACwsMAAJ/QRgMABEAAAsLDwEBfQJ/QREMACEAQX8LCw0BAX8Cf0EBDAAiAAsLCwACf0EBDAAkAAsLDwACfUOamdk/DAAqAgALCwwAAn5CHgwAMAAACwsXAAJ/QR4MAEQAAAAAAAAcQDkDAEF/CwsQAAJ/QQJBHwwANwMAQX8LCw4AAn9BIAwANwMAQX8LCxAAAn9BIAwAQQc6AABBfwsLEAACf0ECQSEMAD0BAEF/CwsOAAJ/QSIMAD0BAEF/CwsNAAJ9Q5qZWUAMAIwLCwwAAn9BAwwAQQpqCwsMAAJ+QgpCLQwAfQsLCgACf0EuDABqCwsKAAJ/QSwMAEULCxMAAn9BKwwARAAAAAAAACRAZQsLDwACf0MAACBBQSoMAFwLCwoAAn9BLAwAZQsLCgACf0EpDACnCwsLAAJ/QSgMAEAACwsRAEEBAn8QAEEEQQgMAGoLagsaAEEBAn9BAhoCf0EEGkEIDAEMAAsaQRALagsfAEEBAn9BAhoCf0EEGkEIDAFBAQ0AGkEgCxpBEAtqCxYAQQECf0ECGkEEQQgMAA0AGkEQC2oLHQBBAQJ/QQIaAn9BBBpBCAwBQQEOAAALGkEQC2oLFgBBAQJ/QQIaQQRBCAwADgAAQRALags=", + "AGFzbQEAAAABKQlgA39/fwF/YAAAYAABf2AAAX5gAAF9YAABfGABfwF/YAF/AGACf38AA0A/AQEBAQECAwQFBgYHBgYGBgYHAgECBgECAgMGCAgGBgIAAgICAAICAgIGBgYCAgICAgIFAgICAgICBgYGBgYGBAUBcAEBAQUDAQABBgYBfwFBCgsH0Qg8CHR5cGUtaTMyAAEIdHlwZS1pNjQAAgh0eXBlLWYzMgADCHR5cGUtZjY0AAQOdHlwZS1pMzItdmFsdWUABQ50eXBlLWk2NC12YWx1ZQAGDnR5cGUtZjMyLXZhbHVlAAcOdHlwZS1mNjQtdmFsdWUACA5hcy1ibG9jay1maXJzdAAJDGFzLWJsb2NrLW1pZAAKDWFzLWJsb2NrLWxhc3QACxRhcy1ibG9jay1maXJzdC12YWx1ZQAMEmFzLWJsb2NrLW1pZC12YWx1ZQANE2FzLWJsb2NrLWxhc3QtdmFsdWUADg1hcy1sb29wLWZpcnN0AA8LYXMtbG9vcC1taWQAEAxhcy1sb29wLWxhc3QAEQthcy1ici12YWx1ZQASDWFzLWJyX2lmLWNvbmQAEw5hcy1icl9pZi12YWx1ZQAUE2FzLWJyX2lmLXZhbHVlLWNvbmQAFRFhcy1icl90YWJsZS1pbmRleAAWEWFzLWJyX3RhYmxlLXZhbHVlABcXYXMtYnJfdGFibGUtdmFsdWUtaW5kZXgAGA9hcy1yZXR1cm4tdmFsdWUAGQphcy1pZi1jb25kABoKYXMtaWYtdGhlbgAbCmFzLWlmLWVsc2UAHA9hcy1zZWxlY3QtZmlyc3QAHRBhcy1zZWxlY3Qtc2Vjb25kAB4OYXMtc2VsZWN0LWNvbmQAHw1hcy1jYWxsLWZpcnN0ACELYXMtY2FsbC1taWQAIgxhcy1jYWxsLWxhc3QAIxVhcy1jYWxsX2luZGlyZWN0LWZ1bmMAJRZhcy1jYWxsX2luZGlyZWN0LWZpcnN0ACYUYXMtY2FsbF9pbmRpcmVjdC1taWQAJxVhcy1jYWxsX2luZGlyZWN0LWxhc3QAKBJhcy1sb2NhbC5zZXQtdmFsdWUAKRJhcy1sb2NhbC50ZWUtdmFsdWUAKhNhcy1nbG9iYWwuc2V0LXZhbHVlACsPYXMtbG9hZC1hZGRyZXNzACwQYXMtbG9hZE4tYWRkcmVzcwAtEGFzLXN0b3JlLWFkZHJlc3MALg5hcy1zdG9yZS12YWx1ZQAvEWFzLXN0b3JlTi1hZGRyZXNzADAPYXMtc3RvcmVOLXZhbHVlADEQYXMtdW5hcnktb3BlcmFuZAAyDmFzLWJpbmFyeS1sZWZ0ADMPYXMtYmluYXJ5LXJpZ2h0ADQPYXMtdGVzdC1vcGVyYW5kADUPYXMtY29tcGFyZS1sZWZ0ADYQYXMtY29tcGFyZS1yaWdodAA3E2FzLW1lbW9yeS5ncm93LXNpemUAOBJuZXN0ZWQtYmxvY2stdmFsdWUAOQ9uZXN0ZWQtYnItdmFsdWUAOhJuZXN0ZWQtYnJfaWYtdmFsdWUAOxduZXN0ZWQtYnJfaWYtdmFsdWUtY29uZAA8FW5lc3RlZC1icl90YWJsZS12YWx1ZQA9G25lc3RlZC1icl90YWJsZS12YWx1ZS1pbmRleAA+CQcBAEEACwEkCtoIPwIACw0AAkBBAEEBDQBoGgsLDQACQEIAQQENAHoaCwsQAAJAQwAAAABBAQ0AjBoLCxQAAkBEAAAAAAAAAABBAQ0AmhoLCwwAAn9BAUEBDQBoCwsMAAJ+QgJBAQ0AegsLDwACfUMAAEBAQQENAIwLCxMAAnxEAAAAAAAAEEBBAQ0AmgsLDgACQCAADQBBAg8LQQMLEAACQBAAIAANAEECDwtBAwsNAAJAEAAQACAADQALCw8AAn9BCiAADQAaQQsPCwsRAAJ/EABBFCAADQAaQRUPCwsPAAJ/EAAQAEELIAANAAsLEQACQANAIAANAUECDwsLQQMLEwACQANAEAAgAA0BQQIPCwtBBAsLAANAEAAgAA0BCwsNAAJ/QQFBAg0ADAALCw0AAkBBAUEBDQANAAsLEgACf0EBQQINAEEDDQAaQQQLCxIAAn9BAkEBIAANAA0AGkEECwsQAAJAQQFBAg0ADgIAAAALCxQAAn9BAUECDQBBAw4CAAAAQQQLCxMAAn9BAkEBQQMNAA4BAABBBAsLDAACfkIBQQINAA8LCxMAAn9BASAADQAEf0ECBUEDCwsLEQACQCAABEAgAQ0BBRAACwsLEQACQCAABEAQAAUgAQ0BCwsLEAACf0EDQQoNAEECIAAbCwsQAAJ/QQFBA0EKDQAgABsLCxAAAn9BAUECQQNBCg0AGwsLBABBfwsRAAJ/QQxBAQ0AQQJBAxAgCwsRAAJ/QQFBDUEBDQBBAxAgCwsRAAJ/QQFBAkEOQQENABAgCwsEACAACxQAAn9BBEEKDQBBAUECQQARAAALCxQAAn9BAUEEQQoNAEECQQARAAALCxQAAn9BAUECQQRBCg0AQQARAAALCxQAAn9BAUECQQNBBEEKDQARAAALCxEBAX8Cf0ERIAANACEAQX8LCxAAAn9BASAADQAiAEF/DwsLEAACf0EBIAANACQAQX8PCwsOAAJ/QQFBAQ0AKAIACwsOAAJ/QR5BAQ0ALAAACwsSAAJ/QR5BAQ0AQQc2AgBBfwsLEgACf0ECQR9BAQ0ANgIAQX8LCxIAAn9BIEEBDQBBBzoAAEF/CwsSAAJ/QQJBIUEBDQA7AQBBfwsLEwACfEQAAAAAAADwP0EBDQCaCwsOAAJ/QQFBAQ0AQQpqCwsOAAJ/QQpBAUEBDQBrCwsMAAJ/QQBBAQ0ARQsLDgACf0EBQQENAEEKTQsLDgACf0EKQQFBKg0ARwsLDQACf0EBQQENAEAACwsaAEEBAn9BAhpBBAJ/QQggAA0BGkEQC2oLagsbAEEBAn9BAhoCf0EIIAANARpBBAsMAEEQC2oLHgBBAQJ/QQIaAn9BCCAADQEaQQQLQQENABpBEAtqCx4AQQECf0ECGkEEAn9BCCAADQEaQQELDQAaQRALagseAEEBAn9BAhoCf0EIIAANARpBBAtBAQ4AAEEQC2oLHgBBAQJ/QQIaQQQCf0EIIAANARpBAQsOAABBEAtqCw==", + "AGFzbQEAAAABLAlgA39/fwF/YAAAYAABf2AAAX5gAAF9YAABfGABfwF/YAJ/fwF/YAJ/bwFvA0dGAQEBAQECAwQFBgYGBgYGBgEBAQICAgICAQICAQICAwIHBwcHAgACAgICAgICAgICBAMCAgICBAIDAgICAgIGBgYGBgYGCAQFAXABAQEFAwEAAQYGAX8BQQoLB7sJRAh0eXBlLWkzMgABCHR5cGUtaTY0AAIIdHlwZS1mMzIAAwh0eXBlLWY2NAAEDnR5cGUtaTMyLXZhbHVlAAUOdHlwZS1pNjQtdmFsdWUABg50eXBlLWYzMi12YWx1ZQAHDnR5cGUtZjY0LXZhbHVlAAgFZW1wdHkACQtlbXB0eS12YWx1ZQAKCXNpbmdsZXRvbgALD3NpbmdsZXRvbi12YWx1ZQAMCG11bHRpcGxlAA0ObXVsdGlwbGUtdmFsdWUADgVsYXJnZQAPDmFzLWJsb2NrLWZpcnN0ABAMYXMtYmxvY2stbWlkABENYXMtYmxvY2stbGFzdAASDmFzLWJsb2NrLXZhbHVlABMNYXMtbG9vcC1maXJzdAAUC2FzLWxvb3AtbWlkABUMYXMtbG9vcC1sYXN0ABYLYXMtYnItdmFsdWUAFw1hcy1icl9pZi1jb25kABgOYXMtYnJfaWYtdmFsdWUAGRNhcy1icl9pZi12YWx1ZS1jb25kABoRYXMtYnJfdGFibGUtaW5kZXgAGxFhcy1icl90YWJsZS12YWx1ZQAcF2FzLWJyX3RhYmxlLXZhbHVlLWluZGV4AB0PYXMtcmV0dXJuLXZhbHVlAB4KYXMtaWYtY29uZAAfCmFzLWlmLXRoZW4AIAphcy1pZi1lbHNlACEPYXMtc2VsZWN0LWZpcnN0ACIQYXMtc2VsZWN0LXNlY29uZAAjDmFzLXNlbGVjdC1jb25kACQNYXMtY2FsbC1maXJzdAAmC2FzLWNhbGwtbWlkACcMYXMtY2FsbC1sYXN0ACgWYXMtY2FsbF9pbmRpcmVjdC1maXJzdAApFGFzLWNhbGxfaW5kaXJlY3QtbWlkACoVYXMtY2FsbF9pbmRpcmVjdC1sYXN0ACsVYXMtY2FsbF9pbmRpcmVjdC1mdW5jACwSYXMtbG9jYWwuc2V0LXZhbHVlAC0SYXMtbG9jYWwudGVlLXZhbHVlAC4TYXMtZ2xvYmFsLnNldC12YWx1ZQAvD2FzLWxvYWQtYWRkcmVzcwAwEGFzLWxvYWROLWFkZHJlc3MAMRBhcy1zdG9yZS1hZGRyZXNzADIOYXMtc3RvcmUtdmFsdWUAMxFhcy1zdG9yZU4tYWRkcmVzcwA0D2FzLXN0b3JlTi12YWx1ZQA1EGFzLXVuYXJ5LW9wZXJhbmQANg5hcy1iaW5hcnktbGVmdAA3D2FzLWJpbmFyeS1yaWdodAA4D2FzLXRlc3Qtb3BlcmFuZAA5D2FzLWNvbXBhcmUtbGVmdAA6EGFzLWNvbXBhcmUtcmlnaHQAOxJhcy1jb252ZXJ0LW9wZXJhbmQAPBNhcy1tZW1vcnkuZ3Jvdy1zaXplAD0SbmVzdGVkLWJsb2NrLXZhbHVlAD4PbmVzdGVkLWJyLXZhbHVlAD8SbmVzdGVkLWJyX2lmLXZhbHVlAEAXbmVzdGVkLWJyX2lmLXZhbHVlLWNvbmQAQRVuZXN0ZWQtYnJfdGFibGUtdmFsdWUAQhtuZXN0ZWQtYnJfdGFibGUtdmFsdWUtaW5kZXgAQxpuZXN0ZWQtYnJfdGFibGUtbG9vcC1ibG9jawBEDm1lZXQtZXh0ZXJucmVmAEUJBwEAQQALASUK04kBRgIACw0AAkBBAA4BAABoGgsLDQACQEEADgEAAHoaCwsNAAJAQQAOAQAAjBoLCw0AAkBBAA4BAACaGgsLDgACf0EBQQAOAQAAaAsLDgACfkICQQAOAQAAegsLEQACfUMAAEBAQQAOAQAAjAsLFQACfEQAAAAAAAAQQEEADgEAAJoLCw8AAkAgAA4AAEEVDwtBFgsOAAJ/QSEgAA4AAEEfCwsWAAJAAkAgAA4BAQBBFQ8LQRQPC0EWCxYAAn8Cf0EhIAAOAQABQR8PCxpBIAsLMQACQAJAAkACQAJAIAAOBAMCAQAEQeMADwtB5AAPC0HlAA8LQeYADwtB5wAPC0HoAAtNAQF/An8CfwJ/An8Cf0HIASAADgQDAgEABCABQeMAag8LIQEgAUEKag8LIQEgAUELag8LIQEgAUEMag8LIQEgAUENag8LIQEgAUEOagusfgACQAJAIAAOlX4AAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABQX8PC0EADwtBAQ8LDgACQEEADgIAAAAQAAsLEAACQBAAQQAOAgAAABAACwsPAAJAARAAQQAOAgAAAAsLEQACfwEQAEECQQAOAgAAAAsLDwADf0EDQQAOAQEBQQELCxIAA38QAEEEQX8OAgEBAUECCwsRAAN/ARAAQQVBAQ4CAQEBCwsOAAJ/QQlBAA4AAAwACwsOAAJAQQEOAgAAAA0ACwsTAAJ/QQhBAA4AAEEBDQAaQQcLCxQAAn9BBkEJQQAOAQAADQAaQQcLCw8AAkBBAQ4AAA4CAAAACwsVAAJ/QQpBAA4AAEEBDgIAAABBBwsLFAACf0EGQQtBAQ4AAA4BAABBBwsLDQACfkIHQQAOAAAPCwsUAAJ/QQJBAA4AAAR/QQAFQQELCwsUAAJ/IAAEf0EDQQAOAAEFIAELCwsVAAJ/IAAEfyABBUEEQQAOAQEACwsLEQACf0EFQQAOAAAgACABGwsLEQACfyAAQQZBAQ4AACABGwsLEQACf0EAQQFBB0EBDgAAGwsLBABBfwsSAAJ/QQxBAQ4AAEECQQMQJQsLEgACf0EBQQ1BAQ4AAEEDECULCxIAAn9BAUECQQ5BAQ4AABAlCwsVAAJ/QRRBAQ4AAEEBQQJBAxEAAAsLFQACf0EAQRVBAQ4AAEECQQMRAAALCxUAAn9BAEEBQRZBAQ4AAEEDEQAACwsVAAJ/QQBBAUECQRdBAQ4AABEAAAsLEgEBfQJ/QRFBAQ4AACEAQX8LCxIBAX8Cf0EBQQEOAAAhAEF/CwsQAAJ/QQFBAQ4AACQAQX8LCxIAAn1DmpnZP0EBDgAAKgIACwsPAAJ+Qh5BAQ4AADAAAAsLGgACf0EeQQEOAABEAAAAAAAAHEA5AwBBfwsLEwACf0ECQR9BAQ4AADcDAEF/CwsTAAJ/QSBBAA4AAEEHOgAAQX8LCxMAAn9BAkEhQQAOAAA9AQBBfwsLEAACfUOamVlAQQAOAACMCwsQAAJ/QQNBAA4BAABBCmoLCw8AAn5CCkItQQAOAAB9CwsNAAJ/QSxBAA4AAEULCxcAAn9BK0EADgEAAEQAAAAAAAAkQGULCxIAAn9DAAAgQUEqQQAOAABcCwsNAAJ/QSlBAA4AAKcLCw4AAn9BKEEADgAAQAALCyMAAn9BfxpBAQJ/QQICf0EEGkEIQRAgAA4CAAECagtqC2oLCyIAAn9BAQJ/QQIaAn9BBBpBCCAADgICAQAMAAsaQRALagsLJwACf0EBAn9BAhoCf0EEGkEIIAAOAgABAkEBDQAaQSALGkEQC2oLCx4AAn9BAQJ/QQIaQQRBCCAADgIAAQANABpBEAtqCwsnAAJ/QQECf0ECGgJ/QQQaQQggAA4CAAECQQEOAABBIAsaQRALagsLHgACf0EBAn9BAhpBBEEIIAAOAgABAA4AAEEQC2oLCyIAA38CQCAADgIBAAALQQALIQADfwJAIAAOAgABAQtBAwsLEQACbwJvIAEgAA4CAQABCwsL", + "AGFzbQEAAAAB6QEZYAJ/fwF/YAABf2AAAX5gAAF9YAABfGAAAn9+YAF/AX9gAX4BfmABfQF9YAF8AXxgAn98An98YAJ/fwJ/f2ACfXwCfH1gAnx/An98YAJ9fwF/YAJ/fgF+YAJ8fQF9YAJ+fAF8YAACf3xgAAJ/f2AAAnx9YAJ+fgF+YAF+AX9gAABgZH1/f3x9fX18fX9/fXx+fn9+fn1+fn5/fX19fH1/fn18fH1/fX18fnx/fn18f39/fnx/fn58fHx8fHx/fXx8f359fX1/fHx8fHx9fn5/f399fH9+fX19f399fH59fH19fX99fn8BfwNPTgECAwQFBgcICQoLDA0ODxARAQIDBAUBAgMEAQIDBBITFBIBARMHFQcWFhcXFwEBAQEBAQEBAAEBARcXAQEXAQEBAQEGCAMBAQEBAQIYBgQFAXABAQEFAwEAAQYGAX8BQQoLB8oHOAh0eXBlLWkzMgARCHR5cGUtaTY0ABIIdHlwZS1mMzIAEwh0eXBlLWY2NAAUDHR5cGUtaTMyLWk2NAAVDnR5cGUtZmlyc3QtaTMyABYOdHlwZS1maXJzdC1pNjQAFw50eXBlLWZpcnN0LWYzMgAYDnR5cGUtZmlyc3QtZjY0ABkPdHlwZS1zZWNvbmQtaTMyABoPdHlwZS1zZWNvbmQtaTY0ABsPdHlwZS1zZWNvbmQtZjMyABwPdHlwZS1zZWNvbmQtZjY0AB0QdHlwZS1hbGwtaTMyLWY2NAAeEHR5cGUtYWxsLWkzMi1pMzIAHxB0eXBlLWFsbC1mMzItZjY0ACAQdHlwZS1hbGwtZjY0LWkzMgAhFmFzLWJpbmFyeS1hbGwtb3BlcmFuZHMAIhFhcy1taXhlZC1vcGVyYW5kcwAjFGFzLWNhbGwtYWxsLW9wZXJhbmRzACQDZmFjACUHZmFjLWFjYwAmA2ZpYgAnBGV2ZW4AKANvZGQAKQdydW5hd2F5ACoObXV0dWFsLXJ1bmF3YXkAKw9hcy1zZWxlY3QtZmlyc3QALQ1hcy1zZWxlY3QtbWlkAC4OYXMtc2VsZWN0LWxhc3QALw9hcy1pZi1jb25kaXRpb24AMA5hcy1icl9pZi1maXJzdAAxDWFzLWJyX2lmLWxhc3QAMhFhcy1icl90YWJsZS1maXJzdAAzEGFzLWJyX3RhYmxlLWxhc3QANBZhcy1jYWxsX2luZGlyZWN0LWZpcnN0ADYUYXMtY2FsbF9pbmRpcmVjdC1taWQANxVhcy1jYWxsX2luZGlyZWN0LWxhc3QAOA5hcy1zdG9yZS1maXJzdAA5DWFzLXN0b3JlLWxhc3QAOhRhcy1tZW1vcnkuZ3Jvdy12YWx1ZQA7D2FzLXJldHVybi12YWx1ZQA8D2FzLWRyb3Atb3BlcmFuZAA9C2FzLWJyLXZhbHVlAD4SYXMtbG9jYWwuc2V0LXZhbHVlAD8SYXMtbG9jYWwudGVlLXZhbHVlAEATYXMtZ2xvYmFsLnNldC12YWx1ZQBBD2FzLWxvYWQtb3BlcmFuZABCEGFzLXVuYXJ5LW9wZXJhbmQARQ5hcy1iaW5hcnktbGVmdABGD2FzLWJpbmFyeS1yaWdodABHD2FzLXRlc3Qtb3BlcmFuZABID2FzLWNvbXBhcmUtbGVmdABJEGFzLWNvbXBhcmUtcmlnaHQAShJhcy1jb252ZXJ0LW9wZXJhbmQASx5yZXR1cm4tZnJvbS1sb25nLWFyZ3VtZW50LWxpc3QATQkHAQBBAAsBNQr2CU4FAEGyAgsFAELkAgsHAEMAIHNFCwsARAAAAAAAyK5ACwgAQbICQuQCCwQAIAALBAAgAAsEACAACwQAIAALBgAgACABCwYAIAEgAAsGACABIAALBgAgASAACwQAIAELBAAgAQsEACABCwQAIAELBAAQAAsEABABCwQAEAILBAAQAwsEABAECwYAQSAQBQsHAELAABAGCwkAQ8P1qD8QBwsNAEQ9CtejcD36PxAICwsAQ2ZmAEJBIBANCwkAQSBCwAAQDgsSAEQAAAAAAABQQEMAAABCEA8LEABCwABEZmZmZmYGUEAQEAsPAEEgRD0K16NwPfo/EAkLCABBAUECEAoLEgBDAACAP0QAAAAAAAAAQBALCw8ARAAAAAAAAPA/QQIQDAsJAEEDQQQQCmoLDABBA0EEEApBBWpsCwoAQQNBBBAKEAoLFQAgAFAEfkIBBSAAIABCAX0QJX4LCxcAIABQBH4gAQUgAEIBfSAAIAF+ECYLCxwAIABCAVgEfkIBBSAAQgJ9ECcgAEIBfRAnfAsLEgAgAFAEf0EsBSAAQgF9ECkLCxMAIABQBH9B4wAFIABCAX0QKAsLBAAQKgsEABAsCwQAECsLCQAQAEECQQMbCwkAQQIQAEEDGwsJAEECQQMQABsLDAAQAAR/QQEFQQILCwsAAn8QAEECDQALCwsAAn9BAhAADQALCw0AAn8QAEECDgEAAAsLDQACf0ECEAAOAQAACwsEACAACw4AAn8QAEECQQARAAALCw4AAn9BAhAAQQARAAALCw4AAn9BAUECEAARAAALCwkAEABBATYCAAsJAEEKEAA2AgALBgAQAEAACwUAEAAPCwUAEAAaCwkAAn8QAAwACwsKAQF/EAAhACAACwgBAX8QACIACwgAEAAkACMACwcAEAAoAgALBAAgAAsEACAACw0AAn1DAAAAABBEkQsLDAACf0EBEENBCmoLCwwAAn9BCkEBEENrCwsKAAJ/QQEQQ0ULCwwAAn9BARBDQQpNCwsMAAJ/QQpBARBDRwsLCgACfkEBEEOsCwsEACBjC98DAEMAAAAAQQBBAEQAAAAAAAAAAEMAAAAAQwAAAABDAAAAAEQAAAAAAAAAAEMAAAAAQQBBAEMAAAAARAAAAAAAAAAAQgBCAEEAQgBCAEMAAAAAQgBCAEIAQQBDAAAAAEMAAAAAQwAAAABEAAAAAAAAAABDAAAAAEEAQgBDAAAAAEQAAAAAAAAAAEQAAAAAAAAAAEMAAAAAQQBDAAAAAEMAAAAARAAAAAAAAAAAQgBEAAAAAAAAAABBAEIAQwAAAABEAAAAAAAAAABBAEEAQQBCAEQAAAAAAAAAAEEAQgBCAEQAAAAAAAAAAEQAAAAAAAAAAEQAAAAAAAAAAEQAAAAAAAAAAEQAAAAAAAAAAEQAAAAAAAAAAEEAQwAAAABEAAAAAAAAAABEAAAAAAAAAABBAEIAQwAAAABDAAAAAEMAAAAAQQBEAAAAAAAAAABEAAAAAAAAAABEAAAAAAAAAABEAAAAAAAAAABEAAAAAAAAAABDAAAAAEIAQgBBAEEAQQBDAAAAAEQAAAAAAAAAAEEAQgBDAAAAAEMAAAAAQwAAAABBAEEAQwAAAABEAAAAAAAAAABCAEMAAAAARAAAAAAAAAAAQwAAAABDAAAAAEMAAAAAQQBDAAAAAEIAIAAQTAs=", + "AGFzbQEAAAABmAEdYAAAYAABf2AAAX5gAAF9YAABfGAAAnx/YAF/AX9gAX4BfmABfQF9YAF8AXxgAn98An98YAJ/fgJ+f2ACfX8Bf2ACf34BfmACfH0BfWACfnwBfGABfwF/YAF+AX5gAX0BfWABfAF8YAF+AGAEfnx/fgBgAX4Bf2AEfnx/fgF/YAACf3xgAAJ+f2ABfwF+YAF/AX1gAX8BfANRUAECAwQFBgcICQoLDQ8MDhAREhMAAQIDBAUCAQIDBAECAwQFGBkNGgYbHAcHBggJBggJBgYAAAABAQEBAgEDAQAAAQEAAwQEBAEDAQEBAQECBAUBcAEgIAUDAQABBg0BfAFEAAAAAAAAJEALB8QHOwh0eXBlLWkzMgAUCHR5cGUtaTY0ABUIdHlwZS1mMzIAFgh0eXBlLWY2NAAXDHR5cGUtZjY0LWkzMgAYCnR5cGUtaW5kZXgAGQ50eXBlLWZpcnN0LWkzMgAaDnR5cGUtZmlyc3QtaTY0ABsOdHlwZS1maXJzdC1mMzIAHA50eXBlLWZpcnN0LWY2NAAdD3R5cGUtc2Vjb25kLWkzMgAeD3R5cGUtc2Vjb25kLWk2NAAfD3R5cGUtc2Vjb25kLWYzMgAgD3R5cGUtc2Vjb25kLWY2NAAhEHR5cGUtYWxsLWY2NC1pMzIAIhB0eXBlLWFsbC1pMzItZjY0ACMQdHlwZS1hbGwtaTMyLWk2NAAkCGRpc3BhdGNoACUXZGlzcGF0Y2gtc3RydWN0dXJhbC1pNjQAJhdkaXNwYXRjaC1zdHJ1Y3R1cmFsLWkzMgAnF2Rpc3BhdGNoLXN0cnVjdHVyYWwtZjMyACgXZGlzcGF0Y2gtc3RydWN0dXJhbC1mNjQAKQdmYWMtaTY0ACoHZmliLWk2NAArB2ZhYy1pMzIALAdmYWMtZjMyAC0HZmFjLWY2NAAuB2ZpYi1pMzIALwdmaWItZjMyADAHZmliLWY2NAAxBGV2ZW4AMgNvZGQAMwdydW5hd2F5ADQObXV0dWFsLXJ1bmF3YXkANQ9hcy1zZWxlY3QtZmlyc3QANw1hcy1zZWxlY3QtbWlkADgOYXMtc2VsZWN0LWxhc3QAOQ9hcy1pZi1jb25kaXRpb24AOg5hcy1icl9pZi1maXJzdAA7DWFzLWJyX2lmLWxhc3QAPBFhcy1icl90YWJsZS1maXJzdAA9EGFzLWJyX3RhYmxlLWxhc3QAPg5hcy1zdG9yZS1maXJzdAA/DWFzLXN0b3JlLWxhc3QAQBRhcy1tZW1vcnkuZ3Jvdy12YWx1ZQBBD2FzLXJldHVybi12YWx1ZQBCD2FzLWRyb3Atb3BlcmFuZABDC2FzLWJyLXZhbHVlAEQSYXMtbG9jYWwuc2V0LXZhbHVlAEUSYXMtbG9jYWwudGVlLXZhbHVlAEYTYXMtZ2xvYmFsLnNldC12YWx1ZQBHD2FzLWxvYWQtb3BlcmFuZABIEGFzLXVuYXJ5LW9wZXJhbmQASQ5hcy1iaW5hcnktbGVmdABKD2FzLWJpbmFyeS1yaWdodABLD2FzLXRlc3Qtb3BlcmFuZABMD2FzLWNvbXBhcmUtbGVmdABNEGFzLWNvbXBhcmUtcmlnaHQAThJhcy1jb252ZXJ0LW9wZXJhbmQATwkmAQBBAAsgAAECAwUGBwgNCw4MKisyMzQ1Ng8QERIsLS4vMDEECQoK4QlQBQBBsgILBQBC5AILBwBDACBzRQsLAEQAAAAAAMiuQAsNAEQAAAAAAMiuQEEgCwQAIAALBAAgAAsEACAACwQAIAALBgAgACABCwYAIAEgAAsEACABCwQAIAELBAAgAQsEACABCwQAIAALBAAgAAsEACAACwQAIAALXQBBABEAAEIAQQARFABCAEQAAAAAAAAAAEEAQgBBABEVAEEAEQAAQQARAQBFGkEAEQEARRpCAEEAERYARRpCAEQAAAAAAAAAAEEAQgBBABEXAEUaQgBBABEHAFAaCwcAQQARAQALBwBBARECAAsHAEECEQMACwcAQQMRBAALBwBBHREFAAsKAELkAEEFEQcACwkAQSBBBBEGAAsKAELAAEEFEQcACwwAQ8P1qD9BBhEIAAsQAEQ9CtejcD36P0EHEQkACw4AQ2ZmAEJBIEEIEQwACwwAQSBCwABBCRENAAsVAEQAAAAAAABQQEMAAABCQQoRDgALEwBCwABEZmZmZmYGUEBBCxEPAAsHAEEdEQUACxIAQQFEAAAAAAAAAEBBHhEKAAsLAEEBQgJBHxELAAsJACABIAARBwALCQBCCSAAEREACwkAQQkgABEQAAsMAEMAABBBIAAREgALEABEAAAAAAAAIkAgABETAAsYACAAUAR+QgEFIAAgAEIBfUEMEQcAfgsLIgAgAEIBWAR+QgEFIABCAn1BDREHACAAQgF9QQ0RBwB8CwsYACAARQR/QQEFIAAgAEEBa0EXEQYAbAsLIwAgAEMAAAAAWwR9QwAAgD8FIAAgAEMAAIA/k0EYEQgAlAsLLwAgAEQAAAAAAAAAAGEEfEQAAAAAAADwPwUgACAARAAAAAAAAPA/oUEZEQkAogsLIgAgAEEBTQR/QQEFIABBAmtBGhEGACAAQQFrQRoRBgBqCwsuACAAQwAAgD9fBH1DAACAPwUgAEMAAABAk0EbEQgAIABDAACAP5NBGxEIAJILCz4AIABEAAAAAAAA8D9lBHxEAAAAAAAA8D8FIABEAAAAAAAAAEChQRwRCQAgAEQAAAAAAADwP6FBHBEJAKALCxUAIABFBH9BLAUgAEEBa0EPEQYACwsWACAARQR/QeMABSAAQQFrQQ4RBgALCwcAQRARAAALBwBBEhEAAAsHAEEREQAACwwAQQARAQBBAkEDGwsMAEECQQARAQBBAxsLDABBAkEDQQARAQAbCw8AQQARAQAEf0EBBUECCwsOAAJ+QQERAgBBAg0ACwsOAAJ/QQJBABEBAA0ACwsQAAJ9QQIRAwBBAg4BAAALCxAAAn9BAkEAEQEADgEAAAsLDABBABEBAEEBNgIACwwAQQpBAxEEADkDAAsJAEEAEQEAQAALCgBBAUEEEQYADwsKAEIBQQURBwAaCxEAAn1DAACAP0EGEQgADAALCxYBAXxEAAAAAAAA8D9BBxEJACEAIAALFAEBfEQAAAAAAADwP0EHEQkAIgALFABEAAAAAAAA8D9BBxEJACQAIwALCgBBABEBACgCAAsQAAJ9QwAAAABBBhEIAJELCw8AAn9BAUEEEQYAQQpqCwsPAAJ/QQpBAUEEEQYAawsLDQACf0EBQQQRBgBFCwsPAAJ/QQFBBBEGAEEKTQsLDwACf0EKQQFBBBEGAEcLCw0AAn5BAUEEEQYArAsL", + "AGFzbQEAAAABEQNgAn9/AX9gAABgA39/fwF/AwoJAAAAAAABAgICBAwDcAECAnABAwNwAAQHHAMGY2FsbC0xAAYGY2FsbC0yAAcGY2FsbC0zAAgJIwQAQQALAgABAgFBAAsAAwIDBAICQQALAAIBAgICQQMLAAEFClAJBwAgACABagsHACAAIAFrCwcAIAAgAWwLBwAgACABbgsHACAAIAFwCwIACwsAIAAgASACEQAACwsAIAAgASACEQABCwsAIAAgASACEQACCw==", + "AGFzbQEAAAABCAJgAABgAAF/AwwLAAAAAAAAAAAAAQEEBAFwAAEKZgsGAAARAAALBwAAEQAAAQsJAAARAAARAAALCQAAEQAAEQAACwwAABEAABEAABEAAAsGAAARAAALBgAAEQAACwkAABEAABEAAAsJAAARAAARAAALBwAAEQAAGwsKAAARAAAbEQAACw==", + "AGFzbQEAAAABGgRgAX4BfmABfgJ+fmACfn4Dfn5+YAJ+fgF+AwkIAAAAAAABAgAHSwYHZmFjLXJlYwAADWZhYy1yZWMtbmFtZWQAAQhmYWMtaXRlcgACDmZhYy1pdGVyLW5hbWVkAAMHZmFjLW9wdAAEB2ZhYy1zc2EABwrrAQgXACAAQgBRBH5CAQUgACAAQgF9EAB+CwsXACAAQgBRBH5CAQUgACAAQgF9EAF+CwsvAQJ+IAAhAUIBIQICQANAIAFCAFEEQAwCBSABIAJ+IQIgAUIBfSEBCwwACwsgAgsvAQJ+IAAhAUIBIQICQANAIAFCAFEEQAwCBSABIAJ+IQIgAUIBfSEBCwwACwsgAgssAQF+QgEhAQJAIABCAlMNAANAIAEgAH4hASAAQn98IQAgAEIBVQ0ACwsgAQsGACAAIAALCAAgACABIAALHABCASAAAwMQBhAGfhAGQgF9EAVCAFYNABoPCws=", + "AGFzbQEAAAABBgFgAX8BfwMDAgAABw4CBGV2ZW4AAANvZGQAAQorAhQAIABBAEYEf0EBBSAAQQFrEAELCxQAIABBAEYEf0EABSAAQQFrEAALCw==", + "AGFzbQEAAAABvAEcYAAAYAAAYAABf2ABfwBgA398fwF/YAAAYAN/fH4AYAJ/fABgBX99fn98AGAAA398fWAAAn98YAAFf31+f3xgBH99fn8Df35/YAABfmAAAX1gAAF8YAJ/fwF/YAJ+fgF+YAJ9fQF9YAJ8fAF8YAZ9f35/fH8BfGAAA39/f2AAAn9+YAF/AX9gAX8Cf35gAX8Cf39gAAJ/f2ARf359fX98fX9/f318fHx/f30QfH1/f39+fX9/fXx8f31/fANiYQAAAAAAAAAAAAAAAAAAAwMGBwgAAAIJCgsBAgMEAgMEAAUMAAINDg8CDQ4PDxAREhMQERITFAAAAg0ODwoVAAIWAAINDg8KFQIWAAINDg8KFQIWAxcYAxcYAxcZGwINDg8HlAlGAWYAAgFnAAQKdHlwZS11c2UtMQAZCnR5cGUtdXNlLTIAGgp0eXBlLXVzZS0zABsKdHlwZS11c2UtNAAcCnR5cGUtdXNlLTUAHQp0eXBlLXVzZS02AB4KdHlwZS11c2UtNwAfD2xvY2FsLWZpcnN0LWkzMgAkD2xvY2FsLWZpcnN0LWk2NAAlD2xvY2FsLWZpcnN0LWYzMgAmD2xvY2FsLWZpcnN0LWY2NAAnEGxvY2FsLXNlY29uZC1pMzIAKBBsb2NhbC1zZWNvbmQtaTY0ACkQbG9jYWwtc2Vjb25kLWYzMgAqEGxvY2FsLXNlY29uZC1mNjQAKwtsb2NhbC1taXhlZAAsD3BhcmFtLWZpcnN0LWkzMgAtD3BhcmFtLWZpcnN0LWk2NAAuD3BhcmFtLWZpcnN0LWYzMgAvD3BhcmFtLWZpcnN0LWY2NAAwEHBhcmFtLXNlY29uZC1pMzIAMRBwYXJhbS1zZWNvbmQtaTY0ADIQcGFyYW0tc2Vjb25kLWYzMgAzEHBhcmFtLXNlY29uZC1mNjQANAtwYXJhbS1taXhlZAA1BWVtcHR5ADYKdmFsdWUtdm9pZAA3CXZhbHVlLWkzMgA4CXZhbHVlLWk2NAA5CXZhbHVlLWYzMgA6CXZhbHVlLWY2NAA7DXZhbHVlLWkzMi1mNjQAPBF2YWx1ZS1pMzItaTMyLWkzMgA9EHZhbHVlLWJsb2NrLXZvaWQAPg92YWx1ZS1ibG9jay1pMzIAPxN2YWx1ZS1ibG9jay1pMzItaTY0AEAMcmV0dXJuLWVtcHR5AEEKcmV0dXJuLWkzMgBCCnJldHVybi1pNjQAQwpyZXR1cm4tZjMyAEQKcmV0dXJuLWY2NABFDnJldHVybi1pMzItZjY0AEYScmV0dXJuLWkzMi1pMzItaTMyAEcQcmV0dXJuLWJsb2NrLWkzMgBIFHJldHVybi1ibG9jay1pMzItaTY0AEkLYnJlYWstZW1wdHkASglicmVhay1pMzIASwlicmVhay1pNjQATAlicmVhay1mMzIATQlicmVhay1mNjQATg1icmVhay1pMzItZjY0AE8RYnJlYWstaTMyLWkzMi1pMzIAUA9icmVhay1ibG9jay1pMzIAURNicmVhay1ibG9jay1pMzItaTY0AFIRYnJlYWstYnJfaWYtZW1wdHkAUw9icmVhay1icl9pZi1udW0AVBNicmVhay1icl9pZi1udW0tbnVtAFUUYnJlYWstYnJfdGFibGUtZW1wdHkAVhJicmVhay1icl90YWJsZS1udW0AVxZicmVhay1icl90YWJsZS1udW0tbnVtAFgbYnJlYWstYnJfdGFibGUtbmVzdGVkLWVtcHR5AFkZYnJlYWstYnJfdGFibGUtbmVzdGVkLW51bQBaHWJyZWFrLWJyX3RhYmxlLW5lc3RlZC1udW0tbnVtAFsJbGFyZ2Utc2lnAFwOaW5pdC1sb2NhbC1pMzIAXQ5pbml0LWxvY2FsLWk2NABeDmluaXQtbG9jYWwtZjMyAF8OaW5pdC1sb2NhbC1mNjQAYAq3BmECAAsCAAsCAAsCAAsCAAsCAAsCAAsEAQF/CwQBAX8LCAMBfwF8AX4LBgIBfwF8CwwFAX8BfQF+AX8BfAsCAAsCAAsCAAsCAAsCAAsCAAsCAAsCAAsCAAsDAAALAwAACwMAAAsDAAALAgALBABBAAsCAAsEAEEACwQAQQALAgALBABBAAsCAAsCAAsQBgF9AX8BfgF/AXwBfwAACxAGAX0BfwF+AX8BfAF/AAALBgECfyAACwYBAn4gAAsGAQJ9IAALBgECfCAACwYBAn8gAQsGAQJ+IAELBgECfSABCwYBAnwgAQsoBgF9AX8BfgF/AXwBfyAAjBogAUUaIAJQGiADRRogBJoaIAVFGiAECwQAIAALBAAgAAsEACAACwQAIAALBAAgAQsEACABCwQAIAELBAAgAQscACAAjBogAUUaIAJQGiADRRogBJoaIAVFGiAECwIACwQAEAALBQBBzQALBQBC4TwLBwBDZmabQgsLAEThehSuR3FTQAsOAEHNAEQAAAAAAAAcQAsIAEEBQQJBAwsJAAJAEAAQAAsLCgACfxAAQc0ACwsLAAIWEABBAUICCwsDAA8LBgBBzgAPCwYAQsY9DwsIAENmZp1CDwsMAERSuB6F67FTQA8LDwBBzgBEUrgeheuxU0APCwkAQQFBAkEDDwsLAAJ/EABBzQALDwsMAAIWEABBAUICCw8LBAAMAAsHAEHPAAwACwcAQqs+DAALCQBDzcyfQgwACw0ARMP1KFyP8lNADAALEABBzwBEw/UoXI/yU0AMAAsKAEEBQQJBAwwACwwAAn8QAEHNAAsMAAsNAAIWEABBAUICCwwACwYAIAANAAsLAEEyIAANABpBMwsQAEEyQjMgAA0AGhpBM0I0CwkAIAAOAgAAAAsMAEEyIAAOAQAAQTMLEABBMkIzIAAOAQAAQTNCNAsMAAJAIAAOAgABAAsLEwACf0EyIAAOAgABAEEzC0ECagsXAAIaQTJBMyAADgIAAQBBM0F9C2pBNAsiACAFIAIgACAIIAcgASADIAkgBCAGIA0gCyAPIBAgDiAMCwYBAX8gAAsGAQF+IAALBgEBfSAACwYBAXwgAAs=", + "AGFzbQEAAAABDANgAX8AYAABfGAAAAMGBQEAAAECCikFCwBEAAAAAAAAAAALAgALAgALCwBEAAAAAAAAAAALCQBBABACEAMaCw==", + "AGFzbQEAAAABCgJgAAF/YAF/AX8DBQQBAQEABw0DAWYAAAFnAAIBcAADCiEEBgEBfyABCwYBAX8gAQsGACAAEAELCgEBf0EqIQAgAAs=", + "AGFzbQEAAAABHQRgAABgAABgCH5+fH58fn1/AGAIfH58fnx+fX8AAwwLAAMAAwMCAgAAAAAEBQFwAQcHB3cEGXNpZ25hdHVyZS1leHBsaWNpdC1yZXVzZWQABxlzaWduYXR1cmUtaW1wbGljaXQtcmV1c2VkAAgcc2lnbmF0dXJlLWV4cGxpY2l0LWR1cGxpY2F0ZQAJHHNpZ25hdHVyZS1pbXBsaWNpdC1kdXBsaWNhdGUACgkNAQBBAAsHBAIBBAAFBgqFAgsCAAsCAAsCAAsCAAsCAAsCAAsCAAsMAEEBEQAAQQQRAAALiQEARAAAAAAAAAAAQgBEAAAAAAAAAABCAEQAAAAAAAAAAEIAQwAAAABBAEEAEQMARAAAAAAAAAAAQgBEAAAAAAAAAABCAEQAAAAAAAAAAEIAQwAAAABBAEECEQMARAAAAAAAAAAAQgBEAAAAAAAAAABCAEQAAAAAAAAAAEIAQwAAAABBAEEDEQMACwcAQQERAQALTgBCAEIARAAAAAAAAAAAQgBEAAAAAAAAAABCAEMAAAAAQQBBBRECAEIAQgBEAAAAAAAAAABCAEQAAAAAAAAAAEIAQwAAAABBAEEGEQIACw==", + "AGFzbQEAAAABGwdgAABgAABgAABgAAF/YAABf2ABfwF/YAF/AAIWAQhzcGVjdGVzdAlwcmludF9pMzIABgMHBgABBAUFBgccBANvbmUAAwN0d28ABAV0aHJlZQAFBGZvdXIABgojBgIACwIACwQAQQ0LBwAgAEEBagsHACAAQQJrCwYAIAAQAAs=", + "AGFzbQEAAAABDgNgAAF/YAABf2ABfwF/AwgHAAAAAQECAgQFAXABBwcHEQIFY2FsbHQABQVjYWxsdQAGCQ0BAEEACwcAAQIDBAACCioHBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwcAIAARAAALBwAgABEBAAs=", + "AGFzbQEAAAABCgJgAAF/YAF/AX8DBAMAAAEEBQFwAQICBwkBBWNhbGx0AAIJCAEAQQALAgABChMDBABBAQsEAEECCwcAIAARAAAL", + "AGFzbQEAAAABXRBgAn9/AX9gAABgAAF/YAF/AGADf3x/A398f2ABfwF/YAF/An9/YAADf35/YAACf39gAAJ9fWABfwN/f35gAAN/f35gAn9/An9/YAN+fn8Cfn9gAn5+AX5gAX4BfgM2NQEDBQYABQUFBQUFBQUFBQUABQUFAwMFBQUFAwUFBQUFBQAFAAUFBQIFCgUFBQUFBQUNDgEBBAUBcAEBAQUDAQABBgYBfwFBCgsHzgYyBWVtcHR5AAEIc2luZ3VsYXIAAgVtdWx0aQADBm5lc3RlZAAED2FzLXNlbGVjdC1maXJzdAAFDWFzLXNlbGVjdC1taWQABg5hcy1zZWxlY3QtbGFzdAAHDWFzLWxvb3AtZmlyc3QACAthcy1sb29wLW1pZAAJDGFzLWxvb3AtbGFzdAAKD2FzLWlmLWNvbmRpdGlvbgALDmFzLWJyX2lmLWZpcnN0AAwNYXMtYnJfaWYtbGFzdAANEWFzLWJyX3RhYmxlLWZpcnN0AA4QYXMtYnJfdGFibGUtbGFzdAAPFmFzLWNhbGxfaW5kaXJlY3QtZmlyc3QAERRhcy1jYWxsX2luZGlyZWN0LW1pZAASFWFzLWNhbGxfaW5kaXJlY3QtbGFzdAATDmFzLXN0b3JlLWZpcnN0ABQNYXMtc3RvcmUtbGFzdAAVFGFzLW1lbW9yeS5ncm93LXZhbHVlABYNYXMtY2FsbC12YWx1ZQAYD2FzLXJldHVybi12YWx1ZQAZD2FzLWRyb3Atb3BlcmFuZAAaC2FzLWJyLXZhbHVlABsSYXMtbG9jYWwuc2V0LXZhbHVlABwSYXMtbG9jYWwudGVlLXZhbHVlAB0TYXMtZ2xvYmFsLnNldC12YWx1ZQAeD2FzLWxvYWQtb3BlcmFuZAAfEGFzLXVuYXJ5LW9wZXJhbmQAIBFhcy1iaW5hcnktb3BlcmFuZAAhD2FzLXRlc3Qtb3BlcmFuZAAiEmFzLWNvbXBhcmUtb3BlcmFuZAAjEmFzLWJpbmFyeS1vcGVyYW5kcwAkE2FzLWNvbXBhcmUtb3BlcmFuZHMAJRFhcy1taXhlZC1vcGVyYW5kcwAmCmJyZWFrLWJhcmUAJwticmVhay12YWx1ZQAoEWJyZWFrLW11bHRpLXZhbHVlACkFcGFyYW0AKgZwYXJhbXMAKwlwYXJhbXMtaWQALAtwYXJhbS1icmVhawAtDHBhcmFtcy1icmVhawAuD3BhcmFtcy1pZC1icmVhawAvB2VmZmVjdHMAMBJhZGQ2NF91X3dpdGhfY2FycnkAMRFhZGQ2NF91X3NhdHVyYXRlZAAyCHR5cGUtdXNlADMSYXR5cGljYWwtY29uZGl0aW9uADQJBwEAQQALARAKxgs1AgALFgAgAARACyAABEALIAAEQAsgAARACwsaACAABEABCyAABEABBQELIAAEf0EHBUEICwtnACAABEAQABAAEAALIAAEQAUQABAAEAALIAAEfxAAEABBCBAABRAAEABBCRAACyAABAcQABAAQQEQABAAEABCAhAAEAAQAEEDEAAFEAAQAEF/EAAQABAAQn4QABAAEABBfRAACxoaC1IAIAAEfyABBEAQAAJACwELIAEEQAUQAAJACwELIAEEfxAAQQkFEABBCgsFIAEEQBAAAkALAQsgAQRABRAAAkALAQsgAQR/EABBCgUQAEELCwsLFQAgAAR/EABBAQUQAEEAC0ECQQMbCxUAQQIgAAR/EABBAQUQAEEAC0EDGwsVAEECQQMgAAR/EABBAQUQAEEACxsLFwADfyAABH8QAEEBBRAAQQALEAAQAAsLFwADfxAAIAAEfxAAQQEFEABBAAsQAAsLFwADfxAAEAAgAAR/EABBAQUQAEEACwsLGAAgAAR/QQEFQQALBH8QAEECBRAAQQMLCxoAAn8gAAR/EABBAQUQAEEAC0ECDQBBAw8LCxoAAn9BAiAABH8QAEEBBRAAQQALDQBBAw8LCxkAAn8gAAR/EABBAQUQAEEAC0ECDgEAAAsLGQACf0ECIAAEfxAAQQEFEABBAAsOAQAACwsEACAACxoAAn8gAAR/EABBAQUQAEEAC0ECQQARAAALCxoAAn9BAiAABH8QAEEBBRAAQQALQQARAAALCxoAAn9BAkEAIAAEfxAAQQEFEABBAAsRAAALCxUAIAAEfxAAQQEFEABBAAtBAjYCAAsVAEECIAAEfxAAQQEFEABBAAs2AgALDgAgAAR/QQEFQQALQAALBAAgAAsOACAABH9BAQVBAAsQFwsNACAABH9BAQVBAAsPCw0AIAAEf0EBBUEACxoLEQACfyAABH9BAQVBAAsMAAsLEgEBfyAABH9BAQVBAAshACAACw4AIAAEf0EBBUEACyIACxAAIAAEf0EBBUEACyQAIwALDwAgAAR/QQsFQQoLKAIACxEAIAAEfxAAQQ0FEABBcwtoCx8AIAAEfxAAQQMFEABBfQsgAQR/EABBBAUQAEF7C2wLEQAgAAR/EABBDQUQAEEAC0ULKwAgAAR9EABDAABAQAUQAEMAAEDACyABBH0QAEMAAIBABRAAQwAAgMALXgsZACAABAgQAEEDEABBBAUQAEEDEABBfAtsCyUAIAAECRAAQwAAQEAQAEMAAEBABRAAQwAAAMAQAEMAAEDAC14LHAAgAAQIEABBAxAAQQQFEABBfRAAQXwLQQVqbAtnAEEBBEAMAAALQQEEQAwAAAUAC0EABEAABQwAAAtBAQRAQQENAAALQQEEQEEBDQAABQALQQAEQAAFQQENAAALQQEEQEEADgAAAAtBAQRAQQAOAAAABQALQQAEQAAFQQAOAAAAC0ETCxQAIAAEf0ESDABBEwVBFQwAQRQLCyQAIAAEC0ESQW5CEgwAQRNBbUITBUFuQRJCbgwAQW1BE0JtCwsQAEEBIAAEBUECagVBfmoLCw4AQQFBAiAABABqBWsLCwwAQQFBAiAABAwLagsUAEEBIAAEBUECagwABUF+agwACwsSAEEBQQIgAAQAagwABWsMAAsLDgBBAUECIAAEDAwAC2oLUQEBfwJ/QQEhASAACwRAIAFBA2whASABQQVrIQEgAUEHbCEBDAAgAUHkAGwhAQUgAUEFbCEBIAFBB2shASABQQNsIQEMACABQegHbCEBCyABCxcBAX4gACABfCACrXwhAyADIAMgAFQPCxAAIAAgAUEAEDEEDxpCfwsLVQBBAQRAC0EBBH9BAAVBAgtBAQQDGgUaC0EARAAAAAAAAAAAQQBBAQQECxoaGkEBBH9BAAVBAgtBAQQDGgUaC0EARAAAAAAAAAAAQQBBAQQECxoaGgsNAEEABEALQQFFBEALCw==", + "AGFzbQEAAAABCgJgAAF/YAF/AX8DExIAAAAAAQAAAAABAQAAAAAAAAAHmgESBWJsb2NrAAAFbG9vcDEAAQVsb29wMgACBWxvb3AzAAMFbG9vcDQABAVsb29wNQAFBWxvb3A2AAYCaWYABwNpZjIACAZzd2l0Y2gACQZyZXR1cm4ACgZicl9pZjAACwZicl9pZjEADAZicl9pZjIADQZicl9pZjMADgJicgAPCXNoYWRvd2luZwAQDHJlZGVmaW5pdGlvbgARCoMGEgsAAn9BAQwAQQALCyMBAX9BACEAAn8DfyAAQQFqIQAgAEEFRgRAIAAMAgsMAAsLCzQBAX9BACEAAn8DfyAAQQFqIQAgAEEFRgRADAELIABBCEYEQCAADAILIABBAWohAAwACwsLIwEBf0EAIQACfwN/IABBAWohACAAQQVGBEAgAAwCCyAACwsLIwEBf0EBIQECfwN/IAEgAWohASABIABLBEAgAQwCCwwACwsLCgADf0EBC0EBagsLAAN/QQANAEEDCwuEAQEBf0EAIQACQEEBBEAMAEGaBSEACyAAQQFqIQBBAQRADABBmgUhAAVB+AYhAAsgAEEBaiEAQQEEQAwAQZoFIQAFQfgGIQALIABBAWohAEEABEBB+AYhAAUMAEGaBSEACyAAQQFqIQBBAARAQfgGIQAFDABBmgUhAAsgAEEBaiEACyAAC4QBAQF/QQAhAAJAQQEEQAwAQZoFIQALIABBAWohAEEBBEAMAEGaBSEABUH4BiEACyAAQQFqIQBBAQRADABBmgUhAAVB+AYhAAsgAEEBaiEAQQAEQEH4BiEABQwAQZoFIQALIABBAWohAEEABEBB+AYhAAUMAEGaBSEACyAAQQFqIQALIAALLQACf0EKAn8CQAJAAkACQAJAIAAOBAQAAQIDCwtBAgwDC0EDDAMLC0EFC2wLCxgAAkACQAJAIAAOAQABDAILQQAPCwtBAgtWAQF/QQAhAAJ/AkBBAA0AIABBAXIhAEEBDQAgAEECciEACwJ/IABBBHIhACAAC0EADQAaIABBCHIhAAJ/IABBEHIhACAAC0EBDQAaIABBIHIhACAACwsTAAJ/An9BAQwAC0EBDQAaQQALCxgAAn9BAQRAAn9BAQwAC0EBDQEaC0EACwskAQF/An8Cf0EBIQAgAAsCf0ECIQAgAAsNABpBAAtBAGoaIAALIQACf0EBBEACf0EBDAALDAEFAkACf0EBDAALGgsLQQELCwwAAn9BAQwAQQJzCwsSAAJ/An9BAgsCf0EDDAALagsL", + "AGFzbQEAAAABTg5gAn9/AX9gAABgAAF/YAF/AGADf3x/A398f2AAA39+f2ABfwF/YAACf39gAAJ9fWAAA39/fmADf39+AGACf38Cf39gAX4BfmACfX0BfQM5OAEBAgICAgICAgECAgICAgIAAgICAQECBgICAQICAgICAgICAgICAgICCQICAgICAgICAgIMDA0BBAUBcAEBAQUDAQABBgYBfwFBAAsHyAY1BWVtcHR5AAEIc2luZ3VsYXIAAgVtdWx0aQADBm5lc3RlZAAEBGRlZXAABQ9hcy1zZWxlY3QtZmlyc3QABg1hcy1zZWxlY3QtbWlkAAcOYXMtc2VsZWN0LWxhc3QACA9hcy1pZi1jb25kaXRpb24ACQphcy1pZi10aGVuAAoKYXMtaWYtZWxzZQALDmFzLWJyX2lmLWZpcnN0AAwNYXMtYnJfaWYtbGFzdAANEWFzLWJyX3RhYmxlLWZpcnN0AA4QYXMtYnJfdGFibGUtbGFzdAAPFmFzLWNhbGxfaW5kaXJlY3QtZmlyc3QAERRhcy1jYWxsX2luZGlyZWN0LW1pZAASFWFzLWNhbGxfaW5kaXJlY3QtbGFzdAATDmFzLXN0b3JlLWZpcnN0ABQNYXMtc3RvcmUtbGFzdAAVFGFzLW1lbW9yeS5ncm93LXZhbHVlABYNYXMtY2FsbC12YWx1ZQAYD2FzLXJldHVybi12YWx1ZQAZD2FzLWRyb3Atb3BlcmFuZAAaC2FzLWJyLXZhbHVlABsSYXMtbG9jYWwuc2V0LXZhbHVlABwSYXMtbG9jYWwudGVlLXZhbHVlAB0TYXMtZ2xvYmFsLnNldC12YWx1ZQAeD2FzLWxvYWQtb3BlcmFuZAAfEGFzLXVuYXJ5LW9wZXJhbmQAIBFhcy1iaW5hcnktb3BlcmFuZAAhD2FzLXRlc3Qtb3BlcmFuZAAiEmFzLWNvbXBhcmUtb3BlcmFuZAAjEmFzLWJpbmFyeS1vcGVyYW5kcwAkE2FzLWNvbXBhcmUtb3BlcmFuZHMAJRFhcy1taXhlZC1vcGVyYW5kcwAmCmJyZWFrLWJhcmUAJwticmVhay12YWx1ZQAoEWJyZWFrLW11bHRpLXZhbHVlACkOYnJlYWstcmVwZWF0ZWQAKgticmVhay1pbm5lcgArCmNvbnQtaW5uZXIALAVwYXJhbQAtBnBhcmFtcwAuCXBhcmFtcy1pZAAvC3BhcmFtLWJyZWFrADAMcGFyYW1zLWJyZWFrADEPcGFyYW1zLWlkLWJyZWFrADIHZWZmZWN0cwAzBXdoaWxlADQDZm9yADUHbmVzdGluZwA2CHR5cGUtdXNlADcJBwEAQQALARAKgws4AgALCAADQAsDQAsLCwADQAELA39BBwsLPAADQBAAEAAQABAACwN/EAAQAEEIEAALGgMFEAAQABAAQQgQABAAEAAQAEIHEAAQABAAEABBCRAACxoaCxUAA38DQBAAAkALAQsDfxAAQQkLCwt/AAN/An8DfwJ/A38CfwN/An8DfwJ/A38CfwN/An8DfwJ/A38CfwN/An8DfwJ/A38CfwN/An8DfwJ/A38CfwN/An8DfwJ/A38CfwN/An8DfwJ/EABBlgELCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwwAA39BAQtBAkEDGwsMAEECA39BAQtBAxsLDABBAkEDA39BAQsbCwwAA39BAQsEQBAACwsPAEEBBH8Df0EBCwVBAgsLDwBBAQR/QQIFA39BAQsLCw4AAn8Df0EBC0ECDQALCw4AAn9BAgN/QQELDQALCxAAAn8Df0EBC0ECDgEAAAsLEAACf0ECA39BAQsOAQAACwsEACAACxEAAn8Df0EBC0ECQQARAAALCxEAAn9BAgN/QQELQQARAAALCxEAAn9BAUECA39BAAsRAAALCwwAA39BAQtBATYCAAsMAEEKA39BAQs2AgALCQADf0EBC0AACwQAIAALCQADf0EBCxAXCwgAA39BAQsPCwgAA39BAQsaCwwAAn8Df0EBCwwACwsNAQF/A39BAQshACAACwsBAX8Df0EBCyIACwsAA39BAQskACMACwoAA39BAQsoAgALCgADfxAAQQ0LaAsRAAN/EABBAwsDfxAAQQQLbAsKAAN/EABBDQtFCxcAA30QAEMAAEBACwN9EABDAABAQAteCw4AAwcQAEEDEABBBAtsCxQAAwgQAEMAAEBAEABDAABAQAteCxEAAwcQAEEDEABBBAtBBWpsCzQAAkADQAwBDAAACwsCQANAQQENAQALCwJAA0BBAA4AAQALCwJAA0BBAQ4CAQEBAAsLQRMLFwACf0EAAwMCQEESDAILQRQMAAtBEwsLJwACCUEAQQBCAAMKAkBBEkFuQhIMAgtBFEFsQhQMAAtBE0FtQhMLCzQAAn8Df0ESDAFBEwwBQRRBAA0BGkEUQQENARpBFQwBQRZBAA4AAUEXQQEOAgEBAUEVCwsLZgEBf0EAIQAgAAJ/A38Cf0EBDAILCwtqIQAgAAJ/A38Df0ECDAILCwtqIQAgAAJ/A38CfwN/QQQMAQsLCwtqIQAgAAJ/A39BCAwBaAsLaiEAIAACfwN/A39BEAwCC2gLC2ohACAACzABAX9BACEAIAADfwN/DAELC2ohACAAA38MAGgLaiEAIAADfwN/DAELaAtqIQAgAAsKAEEBAwZBAmoLCwoAQQFBAgMAagsLCgBBAUECAwsLagsVAQF/QQEDBkEEaiIAIABBCkkNAAsLGAEBf0EBQQIDAGoiAEEDIABBCkkNABoLCx4BAX9BACEAQQFBAgMLIABBAWohACAAQQpJDQALagsyAQF/AkADQEEBIQAgAEEDbCEAIABBBWshACAAQQdsIQAMASAAQeQAbCEACwsgAEFyRgslAQF+QgEhAQJAA0AgAFANASAAIAF+IQEgAEIBfSEADAALCyABCysBAn5CASEBQgIhAgJAA0AgAiAAVg0BIAEgAn4hASACQgF8IQIMAAsLIAELWgECfQJAA0AgAEMAAAAAWw0BIAEhAgJAA0AgAkMAAAAAWw0BIAJDAAAAAF0NAyADIAKSIQMgAkMAAABAkyECDAALCyADIACVIQMgAEMAAIA/kyEADAALCyADCz0AA0ALA39BAAsDAxoLQQBEAAAAAAAAAABBAAMECxoaGgN/QQALAwMaC0EARAAAAAAAAAAAQQADBAsaGhoL", + "AGFzbQEAAAABNgpgAAF/YAABfmAAAX1gAAF8YAF/AX9gAX4BfmABfQF9YAF8AXxgBX59fH9/AGAFfn18f38BfAMUEwABAgMEBQYHCAkEBAQEBAQEBAQHswITDnR5cGUtbG9jYWwtaTMyAAAOdHlwZS1sb2NhbC1pNjQAAQ50eXBlLWxvY2FsLWYzMgACDnR5cGUtbG9jYWwtZjY0AAMOdHlwZS1wYXJhbS1pMzIABA50eXBlLXBhcmFtLWk2NAAFDnR5cGUtcGFyYW0tZjMyAAYOdHlwZS1wYXJhbS1mNjQABwp0eXBlLW1peGVkAAgEcmVhZAAJDmFzLWJsb2NrLXZhbHVlAAoNYXMtbG9vcC12YWx1ZQALC2FzLWJyLXZhbHVlAAwOYXMtYnJfaWYtdmFsdWUADRNhcy1icl9pZi12YWx1ZS1jb25kAA4RYXMtYnJfdGFibGUtdmFsdWUADw9hcy1yZXR1cm4tdmFsdWUAEAphcy1pZi10aGVuABEKYXMtaWYtZWxzZQASCo4CEwYBAX8gAAsGAQF+IAALBgEBfSAACwYBAXwgAAsEACAACwQAIAALBAAgAAsEACAACywDAX0CfgF8IABQGiABjBogApoaIANFGiAERRogBYwaIAZQGiAHUBogCJoaCz8DAX0CfgF8QwAAsEAhBUIGIQZEAAAAAAAAIEAhCCAAuiABuyACIAO4IAS3IAW7IAa6IAe6IAigoKCgoKCgoAsHAAJ/IAALCwcAA38gAAsLCQACfyAADAALCwsAAn8gAEEBDQALCwsAAn8gACAADQALCx0AAkACQAJAIAAOAgABAkEADwtBAQ8LQQIPC0EDCwUAIAAPCwwAIAAEfyAABUEACwsMACAABH9BAQUgAAsL", + "AGFzbQEAAAABJQdgAABgAX8AYAF+AGABfQBgAXwAYAV+fXx/fwBgBX59fH9/AX4DFBMAAAAAAQIDBAUGAQEBAQEBAQEBB7QCEw50eXBlLWxvY2FsLWkzMgAADnR5cGUtbG9jYWwtaTY0AAEOdHlwZS1sb2NhbC1mMzIAAg50eXBlLWxvY2FsLWY2NAADDnR5cGUtcGFyYW0taTMyAAQOdHlwZS1wYXJhbS1pNjQABQ50eXBlLXBhcmFtLWYzMgAGDnR5cGUtcGFyYW0tZjY0AAcKdHlwZS1taXhlZAAIBXdyaXRlAAkOYXMtYmxvY2stdmFsdWUACg1hcy1sb29wLXZhbHVlAAsLYXMtYnItdmFsdWUADA5hcy1icl9pZi12YWx1ZQANE2FzLWJyX2lmLXZhbHVlLWNvbmQADhFhcy1icl90YWJsZS12YWx1ZQAPD2FzLXJldHVybi12YWx1ZQAQCmFzLWlmLXRoZW4AEQphcy1pZi1lbHNlABIK0gITCAEBf0EAIQALCAEBfkIAIQALCwEBfUMAAAAAIQALDwEBfEQAAAAAAAAAACEACwYAQQohAAsGAEILIQALCQBDmpkxQSEACw0ARGZmZmZmZihAIQALQAMBfQJ+AXxCACEAQwAAAAAhAUQAAAAAAAAAACECQQAhA0EAIQRDAAAAACEFQgAhBkIAIQdEAAAAAAAAAAAhCAtPAwF9An4BfEOamZm+IQFBKCEDQXkhBEMAALBAIQVCBiEGRAAAAAAAACBAIQggALogAbsgAiADuCAEtyAFuyAGuiAHuiAIoKCgoKCgoKCwCwkAAkBBASEACwsJAANAQQMhAAsLCwACQEEJIQAMAAsLDQACQEEIIQBBAQ0ACwsNAAJAQQZBCSEADQALCw4AAkBBCiEAQQEOAAALCwcAQQchAA8LCwAgAARAQQMhAAsLDAAgAARABUEBIQALCw==", + "AGFzbQEAAAABWBBgA39/fwF/YAABf2AAAX5gAAF9YAABfGABfwF/YAF+AX5gAX0BfWABfAF8YAV+fXx/fwBgBX59fH9/AX5gBX59fH9/AXxgAABgAX8AYAJ/fwF/YAF+AX8DOjkBAgMEBQYHCAkKCwwFBQUFBQUFDQUFDQUFBQUFBQ4OBQAFBQUFBQUFDAUMBQUNDQ0NBwUFBQUFDwUEBQFwAQEBBQMBAAEGBgF/AUEACwfPBzcOdHlwZS1sb2NhbC1pMzIAAA50eXBlLWxvY2FsLWk2NAABDnR5cGUtbG9jYWwtZjMyAAIOdHlwZS1sb2NhbC1mNjQAAw50eXBlLXBhcmFtLWkzMgAEDnR5cGUtcGFyYW0taTY0AAUOdHlwZS1wYXJhbS1mMzIABg50eXBlLXBhcmFtLWY2NAAHCnR5cGUtbWl4ZWQACAV3cml0ZQAJBnJlc3VsdAAKDmFzLWJsb2NrLWZpcnN0AAwMYXMtYmxvY2stbWlkAA0NYXMtYmxvY2stbGFzdAAODWFzLWxvb3AtZmlyc3QADwthcy1sb29wLW1pZAAQDGFzLWxvb3AtbGFzdAARC2FzLWJyLXZhbHVlABINYXMtYnJfaWYtY29uZAATDmFzLWJyX2lmLXZhbHVlABQTYXMtYnJfaWYtdmFsdWUtY29uZAAVEWFzLWJyX3RhYmxlLWluZGV4ABYRYXMtYnJfdGFibGUtdmFsdWUAFxdhcy1icl90YWJsZS12YWx1ZS1pbmRleAAYD2FzLXJldHVybi12YWx1ZQAZCmFzLWlmLWNvbmQAGgphcy1pZi10aGVuABsKYXMtaWYtZWxzZQAcD2FzLXNlbGVjdC1maXJzdAAdEGFzLXNlbGVjdC1zZWNvbmQAHg5hcy1zZWxlY3QtY29uZAAfDWFzLWNhbGwtZmlyc3QAIQthcy1jYWxsLW1pZAAiDGFzLWNhbGwtbGFzdAAjFmFzLWNhbGxfaW5kaXJlY3QtZmlyc3QAJBRhcy1jYWxsX2luZGlyZWN0LW1pZAAlFWFzLWNhbGxfaW5kaXJlY3QtbGFzdAAmFmFzLWNhbGxfaW5kaXJlY3QtaW5kZXgAJxJhcy1sb2NhbC5zZXQtdmFsdWUAKBJhcy1sb2NhbC50ZWUtdmFsdWUAKRNhcy1nbG9iYWwuc2V0LXZhbHVlACoPYXMtbG9hZC1hZGRyZXNzACsQYXMtbG9hZE4tYWRkcmVzcwAsEGFzLXN0b3JlLWFkZHJlc3MALQ5hcy1zdG9yZS12YWx1ZQAuEWFzLXN0b3JlTi1hZGRyZXNzAC8PYXMtc3RvcmVOLXZhbHVlADAQYXMtdW5hcnktb3BlcmFuZAAxDmFzLWJpbmFyeS1sZWZ0ADIPYXMtYmluYXJ5LXJpZ2h0ADMPYXMtdGVzdC1vcGVyYW5kADQPYXMtY29tcGFyZS1sZWZ0ADUQYXMtY29tcGFyZS1yaWdodAA2EmFzLWNvbnZlcnQtb3BlcmFuZAA3E2FzLW1lbW9yeS5ncm93LXNpemUAOAkHAQBBAAsBIAqDBzkIAQF/QQAiAAsIAQF+QgAiAAsLAQF9QwAAAAAiAAsPAQF8RAAAAAAAAAAAIgALBgBBCiIACwYAQgsiAAsJAEOamTFBIgALDQBEZmZmZmZmKEAiAAtSAwF9An4BfEIAIgBQGkMAAAAAIgGMGkQAAAAAAAAAACICmhpBACIDRRpBACIERRpDAAAAACIFjBpCACIGUBpCACIHUBpEAAAAAAAAAAAiCJoaC1UDAX0CfgF8Q5qZmb4iARpBKCIDGkF5IgQaQwAAsEAiBRpCBiIGGkQAAAAAAAAgQCIIGiAAuiABuyACIAO4IAS3IAW7IAa6IAe6IAigoKCgoKCgoLALTwMBfQJ+AXxCASIAukMAAABAIgG7RGZmZmZmZgpAIgJBBCIDuEEFIgS3QwAAsEAiBbtCBiIGukIAIge6RAAAAAAAACBAIgigoKCgoKCgoAsCAAsLAAJ/QQEiABALCwsNAAJ/EAtBASIAEAsLCw0AAn8QCxALQQEiAAsLCwADf0EDIgAQCwsLDQADfxALQQQiABALCwsNAAN/EAsQC0EFIgALCwsAAn9BCSIADAALCwsAAkBBASIADQALCxAAAn9BCCIAQQENABpBBwsLEAACf0EGQQkiAA0AGkEHCwsOAAJAQQAiAA4CAAAACwsSAAJ/QQoiAEEBDgIAAABBBwsLEQACf0EGQQsiAA4BAABBBwsLBwBBByIADwsOAEECIgAEf0EABUEBCwsOACAABH9BAyIABSAACwsOACAABH8gAAVBBCIACwsLAEEFIgAgACABGwsLACAAQQYiACABGwsLAEEAQQFBByIAGwsEAEF/CwwAQQwiAEECQQMQIAsMAEEBQQ0iAEEDECALDABBAUECQQ4iABAgCw8AQQEiAEECQQNBABEAAAsPAEEBQQIiAEEDQQARAAALDwBBAUECQQMiAEEAEQAACw8AQQFBAkEDQQAiABEAAAsKAQF/QQEiACEACwgAQQEiACIACwoBAX9BASIAJAALCQBBASIAKAIACwkAQQMiACwAAAsLAEEeIgBBBzYCAAsLAEECQQEiADYCAAsLAEEBIgBBBzoAAAsLAEECQQEiADsBAAsKAEPi8YB/IgCMCwkAQQMiAEEKagsJAEEKQQQiAGsLBwBBACIARQsJAEErIgBBCkwLCQBBCkEqIgBHCwcAQikiAKcLCABBKCIAQAAL", + "AGFzbQEAAAABIwdgAn9/AX9gAABgA39/fwF/YAABf2ABfwBgAX8Bf2ACf38AA1RTAQIDAwMDBAQEBQUFBQUDAwMDAwMDAwQEBAUFBQUFBQUFBQUFBQUFAgICAgIFBQUFBQUFBQUFBQUFBQUFBQADAwMDAwUFBQUFBQMDAwUFBQYGBgYEBQFwAQEBBQMBAAEGBgF/AUEACwfqC1ANYXMtZnVuYy1maXJzdAACC2FzLWZ1bmMtbWlkAAMMYXMtZnVuYy1sYXN0AAQSYXMtZnVuYy1ldmVyeXdoZXJlAAUNYXMtZHJvcC1maXJzdAAGDGFzLWRyb3AtbGFzdAAHEmFzLWRyb3AtZXZlcnl3aGVyZQAID2FzLXNlbGVjdC1maXJzdAAJDmFzLXNlbGVjdC1taWQxAAoOYXMtc2VsZWN0LW1pZDIACw5hcy1zZWxlY3QtbGFzdAAMFGFzLXNlbGVjdC1ldmVyeXdoZXJlAA0OYXMtYmxvY2stZmlyc3QADgxhcy1ibG9jay1taWQADw1hcy1ibG9jay1sYXN0ABATYXMtYmxvY2stZXZlcnl3aGVyZQARDWFzLWxvb3AtZmlyc3QAEgthcy1sb29wLW1pZAATDGFzLWxvb3AtbGFzdAAUEmFzLWxvb3AtZXZlcnl3aGVyZQAVD2FzLWlmLWNvbmRpdGlvbgAWCmFzLWlmLXRoZW4AFwphcy1pZi1lbHNlABgLYXMtYnItZmlyc3QAGQphcy1ici1sYXN0ABoQYXMtYnItZXZlcnl3aGVyZQAbDmFzLWJyX2lmLWZpcnN0ABwMYXMtYnJfaWYtbWlkAB0NYXMtYnJfaWYtbGFzdAAeE2FzLWJyX2lmLWV2ZXJ5d2hlcmUAHxFhcy1icl90YWJsZS1maXJzdAAgD2FzLWJyX3RhYmxlLW1pZAAhEGFzLWJyX3RhYmxlLWxhc3QAIhZhcy1icl90YWJsZS1ldmVyeXdoZXJlACMPYXMtcmV0dXJuLWZpcnN0ACQOYXMtcmV0dXJuLWxhc3QAJRRhcy1yZXR1cm4tZXZlcnl3aGVyZQAmDWFzLWNhbGwtZmlyc3QAJwxhcy1jYWxsLW1pZDEAKAxhcy1jYWxsLW1pZDIAKQxhcy1jYWxsLWxhc3QAKhJhcy1jYWxsLWV2ZXJ5d2hlcmUAKw5hcy11bmFyeS1maXJzdAAsDWFzLXVuYXJ5LWxhc3QALRNhcy11bmFyeS1ldmVyeXdoZXJlAC4PYXMtYmluYXJ5LWZpcnN0AC8NYXMtYmluYXJ5LW1pZAAwDmFzLWJpbmFyeS1sYXN0ADEUYXMtYmluYXJ5LWV2ZXJ5d2hlcmUAMg1hcy10ZXN0LWZpcnN0ADMMYXMtdGVzdC1sYXN0ADQSYXMtdGVzdC1ldmVyeXdoZXJlADUQYXMtY29tcGFyZS1maXJzdAA2DmFzLWNvbXBhcmUtbWlkADcPYXMtY29tcGFyZS1sYXN0ADgVYXMtY29tcGFyZS1ldmVyeXdoZXJlADkUYXMtbWVtb3J5Lmdyb3ctZmlyc3QAOhNhcy1tZW1vcnkuZ3Jvdy1sYXN0ADsZYXMtbWVtb3J5Lmdyb3ctZXZlcnl3aGVyZQA8FmFzLWNhbGxfaW5kaXJlY3QtZmlyc3QAPhVhcy1jYWxsX2luZGlyZWN0LW1pZDEAPxVhcy1jYWxsX2luZGlyZWN0LW1pZDIAQBVhcy1jYWxsX2luZGlyZWN0LWxhc3QAQRthcy1jYWxsX2luZGlyZWN0LWV2ZXJ5d2hlcmUAQhJhcy1sb2NhbC5zZXQtZmlyc3QAQxFhcy1sb2NhbC5zZXQtbGFzdABEF2FzLWxvY2FsLnNldC1ldmVyeXdoZXJlAEUSYXMtbG9jYWwudGVlLWZpcnN0AEYRYXMtbG9jYWwudGVlLWxhc3QARxdhcy1sb2NhbC50ZWUtZXZlcnl3aGVyZQBIE2FzLWdsb2JhbC5zZXQtZmlyc3QASRJhcy1nbG9iYWwuc2V0LWxhc3QAShhhcy1nbG9iYWwuc2V0LWV2ZXJ5d2hlcmUASw1hcy1sb2FkLWZpcnN0AEwMYXMtbG9hZC1sYXN0AE0SYXMtbG9hZC1ldmVyeXdoZXJlAE4OYXMtc3RvcmUtZmlyc3QATwxhcy1zdG9yZS1taWQAUA1hcy1zdG9yZS1sYXN0AFETYXMtc3RvcmUtZXZlcnl3aGVyZQBSCQcBAEEACwE9CqIHUwIACwoAIAAgASACa2oLBQABQQELBwAQAAFBAgsHABAAQQMBCwsAAQEQAAFBBAEBCwYAASAAGgsGACAAARoLCQABASAAAQEaCwoAASAAIAAgABsLCgAgAAEgACAAGwsKACAAIAABIAAbCwoAIAAgACAAARsLEAABIAABASAAAQEgAAEBGwsIAAJ/AUECCwsKAAJ/EAABQQILCwsAAn8BEABBAwELCw4AAn8BARAAAUEEAQELCwgAA38BQQILCwoAA38QAAFBAgsLCgADfxAAQQMBCwsOAAN/AQEQAAFBBAEBCwsKACAAAQRAEAALCwsAIAAEQAEFEAALCwsAIAAEQBAABQELCwoAAn8BIAAMAAsLCgACfyAAAQwACwsNAAJ/AQEgAAEBDAALCwwAAn8BIAAgAA0ACwsMAAJ/IAABIAANAAsLDAACfyAAIAABDQALCxEAAn8BASAAAQEgAAEBDQALCw4AAn8BIAAgAA4BAAALCw4AAn8gAAEgAA4BAAALCw4AAn8gACAAAQ4BAAALCxMAAn8BASAAAQEgAAEBDgEAAAsLBgABIAAPCwYAIAABDwsJAAEBIAABAQ8LCwABIAAgASACEAELCwAgAAEgASACEAELCwAgACABASACEAELCwAgACABIAIBEAELEgABASAAAQEgAQEBIAIBARABCwYAASAAaAsGACAAAWgLCQABASAAAQFoCwgAASAAIABqCwgAIAABIABqCwgAIAAgAAFqCwwAASAAAQEgAAEBagsGAAEgAEULBgAgAAFFCwkAAQEgAAEBRQsIAAEgACAARwsIACAAASAARwsIACAAIAABSQsMAAEgAAEBIAABAUwLBwABIABAAAsHACAAAUAACwoAAQEgAAEBQAALBAAgAAsPAAJ/AUEBQQJBABEAAAsLDwACf0EBAUECQQARAAALCw8AAn9BAUECAUEAEQAACwsPAAJ/QQFBAkEAAREAAAsLFgACfwEBQQEBAUECAQFBAAEBEQAACwsJAAFBAiEAIAALCQBBAgEhACAACwwAAQFBAgEBIQAgAAsHAAFBAiIACwcAQQIBIgALCgABAUECAQEiAAsJAAFBAiQAIwALCQBBAgEkACMACwwAAQFBAgEBJAAjAAsIAAEgACgCAAsIACAAASgCAAsLAAEBIAABASgCAAsKAAEgACABNgIACwoAIAABIAE2AgALCgAgACABATYCAAsPAAEBIAABASABAQE2AgAL", + "AGFzbQEAAAABIQdgA39/fwF/YAAAYAABf2AAAX5gAAF9YAABfGACf38BfwM+PQEBAQEBAgMEBQEFAgIBAgEBAQICAgICAQICAwICAwIGBgYGAgACAgICAgICAgICBAMCAgICBAIDAgICAgIEBQFwAQEBBQMBAAEGBgF/AUEACwf4BzsIdHlwZS1pMzIAAQh0eXBlLWk2NAACCHR5cGUtZjMyAAMIdHlwZS1mNjQABA50eXBlLWkzMi12YWx1ZQAFDnR5cGUtaTY0LXZhbHVlAAYOdHlwZS1mMzItdmFsdWUABw50eXBlLWY2NC12YWx1ZQAIB251bGxhcnkACQV1bmFyeQAKDWFzLWZ1bmMtZmlyc3QACwthcy1mdW5jLW1pZAAMDGFzLWZ1bmMtbGFzdAANDWFzLWZ1bmMtdmFsdWUADg5hcy1ibG9jay1maXJzdAAPDGFzLWJsb2NrLW1pZAAQDWFzLWJsb2NrLWxhc3QAEQ5hcy1ibG9jay12YWx1ZQASDWFzLWxvb3AtZmlyc3QAEwthcy1sb29wLW1pZAAUDGFzLWxvb3AtbGFzdAAVC2FzLWJyLXZhbHVlABYNYXMtYnJfaWYtY29uZAAXDmFzLWJyX2lmLXZhbHVlABgTYXMtYnJfaWYtdmFsdWUtY29uZAAZEWFzLWJyX3RhYmxlLWluZGV4ABoRYXMtYnJfdGFibGUtdmFsdWUAGxdhcy1icl90YWJsZS12YWx1ZS1pbmRleAAcD2FzLXJldHVybi12YWx1ZQAdCmFzLWlmLWNvbmQAHgphcy1pZi10aGVuAB8KYXMtaWYtZWxzZQAgD2FzLXNlbGVjdC1maXJzdAAhEGFzLXNlbGVjdC1zZWNvbmQAIg5hcy1zZWxlY3QtY29uZAAjDWFzLWNhbGwtZmlyc3QAJQthcy1jYWxsLW1pZAAmDGFzLWNhbGwtbGFzdAAnFWFzLWNhbGxfaW5kaXJlY3QtZnVuYwAoFmFzLWNhbGxfaW5kaXJlY3QtZmlyc3QAKRRhcy1jYWxsX2luZGlyZWN0LW1pZAAqFWFzLWNhbGxfaW5kaXJlY3QtbGFzdAArEmFzLWxvY2FsLnNldC12YWx1ZQAsEmFzLWxvY2FsLnRlZS12YWx1ZQAtE2FzLWdsb2JhbC5zZXQtdmFsdWUALg9hcy1sb2FkLWFkZHJlc3MALxBhcy1sb2FkTi1hZGRyZXNzADAQYXMtc3RvcmUtYWRkcmVzcwAxDmFzLXN0b3JlLXZhbHVlADIRYXMtc3RvcmVOLWFkZHJlc3MAMw9hcy1zdG9yZU4tdmFsdWUANBBhcy11bmFyeS1vcGVyYW5kADUOYXMtYmluYXJ5LWxlZnQANg9hcy1iaW5hcnktcmlnaHQANw9hcy10ZXN0LW9wZXJhbmQAOA9hcy1jb21wYXJlLWxlZnQAORBhcy1jb21wYXJlLXJpZ2h0ADoSYXMtY29udmVydC1vcGVyYW5kADsTYXMtbWVtb3J5Lmdyb3ctc2l6ZQA8CQcBAEEACwEkCqkFPQIACwUAD2gaCwUAD3oaCwUAD4waCwUAD5oaCwkAAn9BAQ9oCwsJAAJ+QgIPegsLDAACfUMAAEBAD4wLCxAAAnxEAAAAAAAAEEAPmgsLAwAPCwwARAAAAAAAAAhADwsHAEEBD0ECCwkAEABBAg9BAwsGAAEQAA8LCAABEABBAw8LCAACQA8QAAsLCgACQBAADxAACwsJAAJAARAADwsLCwACfwEQAEECDwsLCgADf0EDD0ECCwsMAAN/EABBBA9BAgsLCwADfwEQAEEFDwsLCgACf0EJDwwACwsIAAJADw0ACwsPAAJ/QQgPQQENABpBBwsLDwACf0EGQQkPDQAaQQcLCw8AAkBCCQ8OAgAAAAtCfwsRAAJ/QQoPQQEOAgAAAEEHCwsQAAJ/QQZBCw8OAQAAQQcLCwYAQgcPDwsNAEECDwR/QQAFQQELCw0AIAAEf0EDDwUgAQsLDQAgAAR/IAEFQQQPCwsKAEEFDyAAIAEbCwoAIABBBg8gARsLCgBBAEEBQQcPGwsEAEF/CwsAQQwPQQJBAxAkCwsAQQFBDQ9BAxAkCwsAQQFBAkEODxAkCw4AQRQPQQFBAkEDEQAACw4AQQBBFQ9BAkEDEQAACw4AQQBBAUEWD0EDEQAACw4AQQBBAUECQRcPEQAACwsBAX1BEQ8hAEF/CwkBAX9BAQ8iAAsHAEEBDyQACwsAQ5qZ2T8PKgIACwgAQh4PMAAACxMAQR4PRAAAAAAAABxAOQMAQX8LDABBAkEfDzcDAEF/CwwAQSAPQQc6AABBfwsMAEECQSEPPQEAQX8LCQBDmplZQA+MCwgAQQMPQQpqCwgAQgpCLQ99CwYAQSwPRQsPAEErD0QAAAAAAAAkQGULCwBDAAAgQUEqD1wLBgBBKQ+nCwcAQSgPQAAL", + "AGFzbQEAAAABPQpgAn9/AX9gAABgA39/fwF/YAN+fn8BfmADfX1/AX1gA3x8fwF8YANwcH8BcGADb29/AW9gAX8Bf2ABfwADLy4BAgMEBQIDBAUGBwgICAgICAkICAgICAgACAgICQkICAgICQgICAgICAgICAgIBAkCcAEBAXABAQEFAwEAAQYGAX8BQQoLB/AFKwpzZWxlY3QtaTMyAAEKc2VsZWN0LWk2NAACCnNlbGVjdC1mMzIAAwpzZWxlY3QtZjY0AAQMc2VsZWN0LWkzMi10AAUMc2VsZWN0LWk2NC10AAYMc2VsZWN0LWYzMi10AAcMc2VsZWN0LWY2NC10AAgOc2VsZWN0LWZ1bmNyZWYACRBzZWxlY3QtZXh0ZXJucmVmAAoPYXMtc2VsZWN0LWZpcnN0AAsNYXMtc2VsZWN0LW1pZAAMDmFzLXNlbGVjdC1sYXN0AA0NYXMtbG9vcC1maXJzdAAOC2FzLWxvb3AtbWlkAA8MYXMtbG9vcC1sYXN0ABAPYXMtaWYtY29uZGl0aW9uABEKYXMtaWYtdGhlbgASCmFzLWlmLWVsc2UAEw5hcy1icl9pZi1maXJzdAAUDWFzLWJyX2lmLWxhc3QAFRFhcy1icl90YWJsZS1maXJzdAAWEGFzLWJyX3RhYmxlLWxhc3QAFxZhcy1jYWxsX2luZGlyZWN0LWZpcnN0ABkUYXMtY2FsbF9pbmRpcmVjdC1taWQAGhVhcy1jYWxsX2luZGlyZWN0LWxhc3QAGw5hcy1zdG9yZS1maXJzdAAcDWFzLXN0b3JlLWxhc3QAHRRhcy1tZW1vcnkuZ3Jvdy12YWx1ZQAeDWFzLWNhbGwtdmFsdWUAIA9hcy1yZXR1cm4tdmFsdWUAIQ9hcy1kcm9wLW9wZXJhbmQAIgthcy1ici12YWx1ZQAjEmFzLWxvY2FsLnNldC12YWx1ZQAkEmFzLWxvY2FsLnRlZS12YWx1ZQAlE2FzLWdsb2JhbC5zZXQtdmFsdWUAJg9hcy1sb2FkLW9wZXJhbmQAJxBhcy11bmFyeS1vcGVyYW5kACgRYXMtYmluYXJ5LW9wZXJhbmQAKQ9hcy10ZXN0LW9wZXJhbmQAKg9hcy1jb21wYXJlLWxlZnQAKxBhcy1jb21wYXJlLXJpZ2h0ACwSYXMtY29udmVydC1vcGVyYW5kAC0JDwIAQQALAQACAUEACwABGAqABS4CAAsJACAAIAEgAhsLCQAgACABIAIbCwkAIAAgASACGwsJACAAIAEgAhsLCwAgACABIAIcAX8LCwAgACABIAIcAX4LCwAgACABIAIcAX0LCwAgACABIAIcAXwLCwAgACABIAIcAXALCwAgACABIAIcAW8LDgBBAEEBIAAbQQJBAxsLDgBBAkEAQQEgABtBAxsLDgBBAkEDQQBBASAAGxsLEAADf0ECQQMgABsQABAACwsQAAN/EABBAkEDIAAbEAALCxAAA38QABAAQQJBAyAAGwsLDgBBAkEDIAAbBEAQAAsLEQBBAQR/QQJBAyAAGwVBBAsLEQBBAAR/QQIFQQJBAyAAGwsLEAACf0ECQQMgABtBBA0ACwsQAAJ/QQJBAkEDIAAbDQALCxIAAn9BAkEDIAAbQQIOAQAACwsSAAJ/QQJBAkEDIAAbDgEAAAsLBAAgAAsTAAJ/QQJBAyAAG0EBQQARAAELCxMAAn9BAUECQQMgABtBABEAAQsLEwACf0EBQQRBAkEDIAAbEQABCwsOAEEAQQQgABtBATYCAAsOAEEIQQFBAiAAGzYCAAsLAEEBQQIgABtAAAsEACAACwsAQQFBAiAAGxAfCwoAQQFBAiAAGw8LCgBBAUECIAAbGgsOAAJ/QQFBAiAAGwwACwsPAQF/QQFBAiAAGyEAIAALCwBBAUECIAAbIgALDQBBAUECIAAbJAAjAAsMAEEAQQQgABsoAgALCgBBAEEBIAAbRQsRAEEBQQIgABtBAUECIAAbbAsNAAJ/QQBBASAAG0ULCw8AAn9BAUECIAAbQQFMCwsPAAJ/QQFBAEEBIAAbRwsLDQACf0IBQgAgABunCws=", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAAEBAFwAAEKUAsEAAAbCwUAABsBCwUAABsbCwUAABsbCwYAABsbGwsGAAAcAX8LBgAAHAF/CwcAABwBfxsLCQAAHAF/HAF/CwcAABsRAQALCAAAGxEBABsL", + "AGFzbQEAAAABDQNgAX4BfmAAAX9gAAADCQgAAAAAAAECAQYGAX8BQQALB1cGCGZhYy1leHByAAAJZmFjLXN0YWNrAAENZmFjLXN0YWNrLXJhdwACCWZhYy1taXhlZAADDWZhYy1taXhlZC1yYXcABBBub3QtcXVpdGUtYS10cmVlAAcKjwIILwECfiAAIQFCASECAkADQCABQgBRBEAMAgUgASACfiECIAFCAX0hAQsMAAsLIAILLwECfiAAIQFCASECAkADQCABQgBRBEAMAgUgASACfiECIAFCAX0hAQsMAAsLIAILLwECfiAAIQFCASECAkADQCABQgBRBEAMAgUgASACfiECIAFCAX0hAQsMAAsLIAILLwECfiAAIQFCASECAkADQCABQgBRBEAMAgUgASACfiECIAFCAX0hAQsMAAsLIAILLwECfiAAIQFCASECAkADQCABQgBRBEAMAgUgASACfiECIAFCAX0hAQsMAAsLIAILDQEBf0EBIwBqJAAjAAsFABAFGgsJABAFEAUQBmoL", + "AGFzbQEAAAABDANgAABgAX8AYAABfwMCAQAEBAFwAAEKtAMBsQMAAkBBABEAAAsDQEEAEQAAC0EABEBBABEAAAtBAARAQQARAAAFQQARAAALAkBBABEAAAsDQEEAEQAAC0EABEBBABEAAAtBAARAQQARAAAFQQARAAALAkBBAEEAEQEACwNAQQBBABEBAAtBAARAQQBBABEBAAtBAARAQQBBABEBAAVBAEEAEQEACwJ/QQARAgALGgN/QQARAgALGkEABH9BABECAAVBABECAAsaAkBBABEAAAsDQEEAEQAAC0EABEBBABEAAAtBAARAQQARAAAFQQARAAALAkBBABEAAAsDQEEAEQAAC0EABEBBABEAAAtBAARAQQARAAAFQQARAAALAkBBABEAAAsDQEEAEQAAC0EABEBBABEAAAtBAARAQQARAAAFQQARAAALAkBBAEEAEQEACwNAQQBBABEBAAtBAARAQQBBABEBAAtBAARAQQBBABEBAAVBAEEAEQEACwJ/QQARAgALGgN/QQARAgALGkEABH9BABECAAVBABECAAsaAkBBABEAAAsDQEEAEQAAC0EABEBBABEAAAtBAARAQQARAAAFQQARAAALQQARAAAL", + "AGFzbQEAAAABDwNgAX8Bf2ABfgF+YAABfwMFBAABAAIHHgQEc3RtdAAABGV4cHIAAQNhcmcAAgZjb3JuZXIAAwreAQRXAQF/QeQAIQECQAJAAkACQAJAAkACQAJAAkACQCAADggAAQIDBAUGCAcLIAAPCwELC0EAIABrIQEMBQsMBAtB5QAhAQwDC0HlACEBC0HmACEBCwsgAQ8LTAEBfkLkACEBAn4CQAJAAkACQAJAAkACQAJAAkAgAKcOCAABAgMGBQQIBwsgAA8LAQsLQgAgAH0MBQtC5QAhAQsLCyABDAELQnsLDwsqAAJ/QQoCf0HkAAJ/QegHAn9BAiAAbEEDIABxDgMBAgMAC2oLagtqCw8LDAACQEEADgAAC0EBCw==", + "AGFzbQEAAAABIAdgA39/fwBgAABgAAF/YAABfmAAAX1gAAF8YAJ/fwF/Az08AQACAwQFAgIBAgICAQICAgIBAgIBAgIBAgICAgMCBgYGBgYCAQEBAQEBAQEEBAQDAQEBAQQCAwICAgICBAUBcAEBAQUDAQABBgkBfQFDAAAAAAsHjAg6CHR5cGUtaTMyAAIIdHlwZS1pNjQAAwh0eXBlLWYzMgAECHR5cGUtZjY0AAUNYXMtZnVuYy1maXJzdAAGC2FzLWZ1bmMtbWlkAAcMYXMtZnVuYy1sYXN0AAgNYXMtZnVuYy12YWx1ZQAJDmFzLWJsb2NrLWZpcnN0AAoMYXMtYmxvY2stbWlkAAsNYXMtYmxvY2stbGFzdAAMDmFzLWJsb2NrLXZhbHVlAA0OYXMtYmxvY2stYnJva2UADg1hcy1sb29wLWZpcnN0AA8LYXMtbG9vcC1taWQAEAxhcy1sb29wLWxhc3QAEQ1hcy1sb29wLWJyb2tlABILYXMtYnItdmFsdWUAEw1hcy1icl9pZi1jb25kABQOYXMtYnJfaWYtdmFsdWUAFRNhcy1icl9pZi12YWx1ZS1jb25kABYRYXMtYnJfdGFibGUtaW5kZXgAFxFhcy1icl90YWJsZS12YWx1ZQAYE2FzLWJyX3RhYmxlLXZhbHVlLTIAGRdhcy1icl90YWJsZS12YWx1ZS1pbmRleAAaG2FzLWJyX3RhYmxlLXZhbHVlLWFuZC1pbmRleAAbD2FzLXJldHVybi12YWx1ZQAcCmFzLWlmLWNvbmQAHQphcy1pZi10aGVuAB4KYXMtaWYtZWxzZQAfEmFzLWlmLXRoZW4tbm8tZWxzZQAgD2FzLXNlbGVjdC1maXJzdAAhEGFzLXNlbGVjdC1zZWNvbmQAIg5hcy1zZWxlY3QtY29uZAAjDWFzLWNhbGwtZmlyc3QAJAthcy1jYWxsLW1pZAAlDGFzLWNhbGwtbGFzdAAmFWFzLWNhbGxfaW5kaXJlY3QtZnVuYwAnFmFzLWNhbGxfaW5kaXJlY3QtZmlyc3QAKBRhcy1jYWxsX2luZGlyZWN0LW1pZAApFWFzLWNhbGxfaW5kaXJlY3QtbGFzdAAqEmFzLWxvY2FsLnNldC12YWx1ZQArEmFzLWxvY2FsLnRlZS12YWx1ZQAsE2FzLWdsb2JhbC5zZXQtdmFsdWUALQ9hcy1sb2FkLWFkZHJlc3MALhBhcy1sb2FkTi1hZGRyZXNzAC8QYXMtc3RvcmUtYWRkcmVzcwAwDmFzLXN0b3JlLXZhbHVlADERYXMtc3RvcmVOLWFkZHJlc3MAMg9hcy1zdG9yZU4tdmFsdWUAMxBhcy11bmFyeS1vcGVyYW5kADQOYXMtYmluYXJ5LWxlZnQANQ9hcy1iaW5hcnktcmlnaHQANg9hcy10ZXN0LW9wZXJhbmQANw9hcy1jb21wYXJlLWxlZnQAOBBhcy1jb21wYXJlLXJpZ2h0ADkSYXMtY29udmVydC1vcGVyYW5kADoTYXMtbWVtb3J5Lmdyb3ctc2l6ZQA7CQcBAEEACwEBCrUEPAIACwIACwMAAAsDAAALAwAACwMAAAsFAABBfwsHABAAAEF/CwUAEAAACwUAEAAACwgAAn8AQQILCwoAAn8QAABBAgsLCQACQAEQAAALCwkAAn8BEAAACwsMAAJ/EABBAQwAAAsLCAADfwBBAgsLCgADfxAAAEECCwsJAANAARAAAAsLDwACfwN/EABBAQwBAAsLCwgAAn8ADAALCwgAAkAADQALCw0AAn8AQQENABpBBwsLDQACf0EGAA0AGkEHCwsLAAJAAA4CAAAACwsPAAJ/AEEBDgIAAABBBwsLDwACfwJ/AEEBDgEAAQsLCw4AAn9BBgAOAQAAQQcLCwwAAn8ADgEAAEEICwsEAAAPCwsAAAR/QQAFQQELCwsAIAAEfwAFIAELCwsAIAAEfyABBQALCwoAIAAEQAALIAELCAAAIAAgARsLCAAgAAAgARsLCABBAEEBABsLCQAAQQJBAxABCwkAQQEAQQMQAQsJAEEBQQIAEAELDAAAQQFBAkEDEQAACwwAQQAAQQJBAxEAAAsMAEEAQQEAQQMRAAALDABBAEEBQQIAEQAACwcBAX0AIQALBwEBfQAiAAsFAAAkAAsGAAAqAgALBgAAMAAACw8AAEQAAAAAAAAcQDkDAAsIAEECADcDAAsIAABBBzoAAAsIAEECAD0BAAsEAACMCwYAAEEKagsGAEIKAH0LBAAARQsNAABEAAAAAAAAJEBlCwkAQwAAIEEAXAsEAACnCwUAAEAACw==", + "AGFzbQEAAAABCAJgAABgAAF/AzIxAAABAAEAAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQeUCjEaZnVuYy11bndpbmQtYnktdW5yZWFjaGFibGUAABFmdW5jLXVud2luZC1ieS1icgABF2Z1bmMtdW53aW5kLWJ5LWJyLXZhbHVlAAIUZnVuYy11bndpbmQtYnktYnJfaWYAAxpmdW5jLXVud2luZC1ieS1icl9pZi12YWx1ZQAEF2Z1bmMtdW53aW5kLWJ5LWJyX3RhYmxlAAUdZnVuYy11bndpbmQtYnktYnJfdGFibGUtdmFsdWUABhVmdW5jLXVud2luZC1ieS1yZXR1cm4ABxtibG9jay11bndpbmQtYnktdW5yZWFjaGFibGUACBJibG9jay11bndpbmQtYnktYnIACRhibG9jay11bndpbmQtYnktYnItdmFsdWUAChVibG9jay11bndpbmQtYnktYnJfaWYACxtibG9jay11bndpbmQtYnktYnJfaWYtdmFsdWUADBhibG9jay11bndpbmQtYnktYnJfdGFibGUADR5ibG9jay11bndpbmQtYnktYnJfdGFibGUtdmFsdWUADhZibG9jay11bndpbmQtYnktcmV0dXJuAA8iYmxvY2stbmVzdGVkLXVud2luZC1ieS11bnJlYWNoYWJsZQAQGWJsb2NrLW5lc3RlZC11bndpbmQtYnktYnIAER9ibG9jay1uZXN0ZWQtdW53aW5kLWJ5LWJyLXZhbHVlABIcYmxvY2stbmVzdGVkLXVud2luZC1ieS1icl9pZgATImJsb2NrLW5lc3RlZC11bndpbmQtYnktYnJfaWYtdmFsdWUAFB9ibG9jay1uZXN0ZWQtdW53aW5kLWJ5LWJyX3RhYmxlABUlYmxvY2stbmVzdGVkLXVud2luZC1ieS1icl90YWJsZS12YWx1ZQAWHWJsb2NrLW5lc3RlZC11bndpbmQtYnktcmV0dXJuABcXdW5hcnktYWZ0ZXItdW5yZWFjaGFibGUAGA51bmFyeS1hZnRlci1icgAZEXVuYXJ5LWFmdGVyLWJyX2lmABoUdW5hcnktYWZ0ZXItYnJfdGFibGUAGxJ1bmFyeS1hZnRlci1yZXR1cm4AHBhiaW5hcnktYWZ0ZXItdW5yZWFjaGFibGUAHQ9iaW5hcnktYWZ0ZXItYnIAHhJiaW5hcnktYWZ0ZXItYnJfaWYAHxViaW5hcnktYWZ0ZXItYnJfdGFibGUAIBNiaW5hcnktYWZ0ZXItcmV0dXJuACEYc2VsZWN0LWFmdGVyLXVucmVhY2hhYmxlACIPc2VsZWN0LWFmdGVyLWJyACMSc2VsZWN0LWFmdGVyLWJyX2lmACQVc2VsZWN0LWFmdGVyLWJyX3RhYmxlACUTc2VsZWN0LWFmdGVyLXJldHVybgAmHWJsb2NrLXZhbHVlLWFmdGVyLXVucmVhY2hhYmxlACcUYmxvY2stdmFsdWUtYWZ0ZXItYnIAKBdibG9jay12YWx1ZS1hZnRlci1icl9pZgApGmJsb2NrLXZhbHVlLWFmdGVyLWJyX3RhYmxlACoYYmxvY2stdmFsdWUtYWZ0ZXItcmV0dXJuACscbG9vcC12YWx1ZS1hZnRlci11bnJlYWNoYWJsZQAsE2xvb3AtdmFsdWUtYWZ0ZXItYnIALRZsb29wLXZhbHVlLWFmdGVyLWJyX2lmAC4ZbG9vcC12YWx1ZS1hZnRlci1icl90YWJsZQAvF2xvb3AtdmFsdWUtYWZ0ZXItcmV0dXJuADAKvAYxBwBBA0IBAAsIAEEDQgEMAAsKAEEDQgFBCQwACwwAQQNCAUEBDQAaGgsOAEEDQgFBCUEBDQAaGgsLAEEDQgFBAA4AAAsNAEEDQgFBCUEADgAACwkAQQNCAUEJDwsKAAJAQQNCAQALCw0AAkBBA0IBDAALQQkLDQACf0EDQgFBCQwACwsRAAJAQQNCAUEBDQAaGgtBCQsRAAJ/QQNCAUEJQQENABoaCwsQAAJAQQNCAUEADgAAC0EJCxAAAn9BA0IBQQlBAA4AAAsLDAACf0EDQgFBCQ8LCw0AAn9BAwJAQgEACwsLEQACQEEDAkBCAQwBCxoLQQkLEAACf0EDAkBCAUEJDAELCwsUAAJAQQMCQEIBQQENARoLGgtBCQsUAAJ/QQMCQEIBQQlBAQ0BGhoLCwsUAAJAQQMCQEIBQQEOAAELGgtBCQsTAAJ/QQMCQEIBQQlBAQ4AAQsLCw8AAn9BAwJAQgFBCQ8LCwsJAEMAAAAAAFALDwACf0MAAAAAQQkMAFALCw8AAn9CAEEJQQENABpQCwsTAAJ/QwAAAABBCUEADgEAAFALCwsAQwAAAABBCQ9QCxIAQwAAAABEAAAAAAAA8D8AUQsYAAJ/QwAAAABEAAAAAAAA8D9BCQwAUQsLEQACf0IAQgFBCUEBDQAaUQsLGwACf0MAAAAARAAAAAAAAPA/QQlBAA4AAFELCxQAQwAAAABEAAAAAAAA8D9BCQ9RCxQAQwAAAABEAAAAAAAA8D9CAAAbCxoAAn9DAAAAAEQAAAAAAADwP0IAQQkMABsLCxMAAn9BAEEBQQBBCUEBDQAaGwsLHQACf0MAAAAARAAAAAAAAPA/QgBBCUEADgAAGwsLFgBDAAAAAEQAAAAAAADwP0IBQQkPGwsLAAJ/QwAAAAAACwsOAAJ/QwAAAABBCQwACwsOAAJ/QQBBCUEBDQAaCwsSAAJ/QwAAAABBCUEADgEAAAsLDQACf0MAAAAAQQkPCwsLAAN/QwAAAAAACwsRAAJ/A39DAAAAAEEJDAELCwsRAAJ/A39BAEEJQQENARoLCwsVAAJ/A39DAAAAAEEJQQAOAQEBCwsLDQADf0MAAAAAQQkPCws=", + "AGFzbQEAAAABQA1gAn9/AX9gAn5+AX9gAn19AX9gAnx8AX9gAABgAAF/YAABfmAAAX1gAAF8YAJ/fwBgAn5+AGACfX0AYAJ8fAADhAGCAQAAAQECAgMDBAQFBQUFBQUGBgYFBQcHBwUFCAgIBQUJCgsMBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEBQFwAQgIBQMBAAEHqghfB2kzMl9hZGQAIwdpMzJfc3ViACQHaTMyX211bAAlCWkzMl9kaXZfcwAmCWkzMl9kaXZfdQAnCWkzMl9yZW1fcwAoCWkzMl9yZW1fdQApB2kzMl9hbmQAKgZpMzJfb3IAKwdpMzJfeG9yACwHaTMyX3NobAAtCWkzMl9zaHJfdQAuCWkzMl9zaHJfcwAvBmkzMl9lcQAwBmkzMl9uZQAxCGkzMl9sdF9zADIIaTMyX2xlX3MAMwhpMzJfbHRfdQA0CGkzMl9sZV91ADUIaTMyX2d0X3MANghpMzJfZ2VfcwA3CGkzMl9ndF91ADgIaTMyX2dlX3UAOQlpMzJfc3RvcmUAOgppMzJfc3RvcmU4ADsLaTMyX3N0b3JlMTYAPAhpMzJfY2FsbAA9EWkzMl9jYWxsX2luZGlyZWN0AD4KaTMyX3NlbGVjdAA/B2k2NF9hZGQAQAdpNjRfc3ViAEEHaTY0X211bABCCWk2NF9kaXZfcwBDCWk2NF9kaXZfdQBECWk2NF9yZW1fcwBFCWk2NF9yZW1fdQBGB2k2NF9hbmQARwZpNjRfb3IASAdpNjRfeG9yAEkHaTY0X3NobABKCWk2NF9zaHJfdQBLCWk2NF9zaHJfcwBMBmk2NF9lcQBNBmk2NF9uZQBOCGk2NF9sdF9zAE8IaTY0X2xlX3MAUAhpNjRfbHRfdQBRCGk2NF9sZV91AFIIaTY0X2d0X3MAUwhpNjRfZ2VfcwBUCGk2NF9ndF91AFUIaTY0X2dlX3UAVglpNjRfc3RvcmUAVwppNjRfc3RvcmU4AFgLaTY0X3N0b3JlMTYAWQtpNjRfc3RvcmUzMgBaCGk2NF9jYWxsAFsRaTY0X2NhbGxfaW5kaXJlY3QAXAppNjRfc2VsZWN0AF0HZjMyX2FkZABeB2YzMl9zdWIAXwdmMzJfbXVsAGAHZjMyX2RpdgBhDGYzMl9jb3B5c2lnbgBiBmYzMl9lcQBjBmYzMl9uZQBkBmYzMl9sdABlBmYzMl9sZQBmBmYzMl9ndABnBmYzMl9nZQBoB2YzMl9taW4AaQdmMzJfbWF4AGoJZjMyX3N0b3JlAGsIZjMyX2NhbGwAbBFmMzJfY2FsbF9pbmRpcmVjdABtCmYzMl9zZWxlY3QAbgdmNjRfYWRkAG8HZjY0X3N1YgBwB2Y2NF9tdWwAcQdmNjRfZGl2AHIMZjY0X2NvcHlzaWduAHMGZjY0X2VxAHQGZjY0X25lAHUGZjY0X2x0AHYGZjY0X2xlAHcGZjY0X2d0AHgGZjY0X2dlAHkHZjY0X21pbgB6B2Y2NF9tYXgAewlmNjRfc3RvcmUAfAhmNjRfY2FsbAB9EWY2NF9jYWxsX2luZGlyZWN0AH4KZjY0X3NlbGVjdAB/BWJyX2lmAIABCGJyX3RhYmxlAIEBCQ4BAEEACwgAAQIDBAUGBwqqDYIBBABBfwsEAEF+CwQAQX8LBABBfgsEAEF/CwQAQX4LBABBfwsEAEF+CwkAQQhBADYCAAsnAEELQQotAAA6AABBCkEJLQAAOgAAQQlBCC0AADoAAEEIQX06AAALBwBBCCgCAAsNABAJQQhBAToAAEEACw0AEAlBCEECOgAAQQELDQAQCUEIQQM6AABBAQsNABAJQQhBBDoAAEEACw0AEAlBCEEFOgAAQQALDQAQCUEIQQE6AABCAAsNABAJQQhBAjoAAEIBCw0AEAlBCEEDOgAAQgELDQAQCUEIQQQ6AABBAgsNABAJQQhBBToAAEEACxAAEAlBCEEBOgAAQwAAAAALEAAQCUEIQQI6AABDAACAPwsQABAJQQhBAzoAAEMAAIA/Cw0AEAlBCEEEOgAAQQQLDQAQCUEIQQU6AABBAAsUABAJQQhBAToAAEQAAAAAAAAAAAsUABAJQQhBAjoAAEQAAAAAAADwPwsUABAJQQhBAzoAAEQAAAAAAADwPwsNABAJQQhBBDoAAEEGCw0AEAlBCEEFOgAAQQALAgALAgALAgALAgALDAAQCBALEAxqGhAKCwwAEAgQCxAMaxoQCgsMABAIEAsQDGwaEAoLDAAQCBALEAxtGhAKCwwAEAgQCxAMbhoQCgsMABAIEAsQDG8aEAoLDAAQCBALEAxwGhAKCwwAEAgQCxAMcRoQCgsMABAIEAsQDHIaEAoLDAAQCBALEAxzGhAKCwwAEAgQCxAMdBoQCgsMABAIEAsQDHYaEAoLDAAQCBALEAx1GhAKCwwAEAgQCxAMRhoQCgsMABAIEAsQDEcaEAoLDAAQCBALEAxIGhAKCwwAEAgQCxAMTBoQCgsMABAIEAsQDEkaEAoLDAAQCBALEAxNGhAKCwwAEAgQCxAMShoQCgsMABAIEAsQDE4aEAoLDAAQCBALEAxLGhAKCwwAEAgQCxAMTxoQCgsNABAIEAsQDDYCABAKCw0AEAgQCxAMOgAAEAoLDQAQCBALEAw7AQAQCgsMABAIEAsQDBAfEAoLEAAQCBALEAwQDhEAABoQCgsOABAIEAsQDBAPGxoQCgsMABAIEBAQEXwaEAoLDAAQCBAQEBF9GhAKCwwAEAgQEBARfhoQCgsMABAIEBAQEX8aEAoLDAAQCBAQEBGAGhAKCwwAEAgQEBARgRoQCgsMABAIEBAQEYIaEAoLDAAQCBAQEBGDGhAKCwwAEAgQEBARhBoQCgsMABAIEBAQEYUaEAoLDAAQCBAQEBGGGhAKCwwAEAgQEBARiBoQCgsMABAIEBAQEYcaEAoLDAAQCBAQEBFRGhAKCwwAEAgQEBARUhoQCgsMABAIEBAQEVMaEAoLDAAQCBAQEBFXGhAKCwwAEAgQEBARVBoQCgsMABAIEBAQEVgaEAoLDAAQCBAQEBFVGhAKCwwAEAgQEBARWRoQCgsMABAIEBAQEVYaEAoLDAAQCBAQEBFaGhAKCw0AEAgQCxARNwMAEAoLDQAQCBALEBE8AAAQCgsNABAIEAsQET0BABAKCw0AEAgQCxARPgIAEAoLDAAQCBAQEBEQIBAKCxAAEAgQEBAREBMRAQAaEAoLDgAQCBAQEBEQFBsaEAoLDAAQCBAVEBaSGhAKCwwAEAgQFRAWkxoQCgsMABAIEBUQFpQaEAoLDAAQCBAVEBaVGhAKCwwAEAgQFRAWmBoQCgsMABAIEBUQFlsaEAoLDAAQCBAVEBZcGhAKCwwAEAgQFRAWXRoQCgsMABAIEBUQFl8aEAoLDAAQCBAVEBZeGhAKCwwAEAgQFRAWYBoQCgsMABAIEBUQFpYaEAoLDAAQCBAVEBaXGhAKCw0AEAgQCxAWOAIAEAoLDAAQCBAVEBYQIRAKCxAAEAgQFRAWEBgRAgAaEAoLDgAQCBAVEBYQGRsaEAoLDAAQCBAaEBugGhAKCwwAEAgQGhAboRoQCgsMABAIEBoQG6IaEAoLDAAQCBAaEBujGhAKCwwAEAgQGhAbphoQCgsMABAIEBoQG2EaEAoLDAAQCBAaEBtiGhAKCwwAEAgQGhAbYxoQCgsMABAIEBoQG2UaEAoLDAAQCBAaEBtkGhAKCwwAEAgQGhAbZhoQCgsMABAIEBoQG6QaEAoLDAAQCBAaEBulGhAKCw0AEAgQCxAbOQMAEAoLDAAQCBAaEBsQIhAKCxAAEAgQGhAbEB0RAwAaEAoLDgAQCBAaEBsQHhsaEAoLEwACfxAIEAsQDEEAcQ0AGhAKCwsVAAJ/EAgCfxALEAwOAQEACxoQCgsL", + "AGFzbQEAAAABNw1gAn9/AX9gAAF/YAABfmAAAW9gAX8AYAF+AGABbwBgAAF9YAABfGABfQBgAXwAYAAAYAF/AX8CLwIIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AAhzcGVjdGVzdApnbG9iYWxfaTY0A34AAzMyAQIDAwECAQIEBQYHCAcICQoLAQEBAQEBAQEBAQEBAQABAQELCwEBDAEBCwEMDAEBAQEEBQFwAQEBBQMBAAEGVg1/AEF+C30AQwAAQMALfABEAAAAAAAAEMALfgBCewt/AUF0C30BQwAAUMELfAFEAAAAAAAALMALfgFCcQt/ACMAC34AIwELbwDQbwtvAdBvC3AA0HALB7EFLwVnZXQtYQAABWdldC1iAAEFZ2V0LXIAAgZnZXQtbXIAAwVnZXQteAAEBWdldC15AAUGZ2V0LXoxAAYGZ2V0LXoyAAcFc2V0LXgACAVzZXQteQAJBnNldC1tcgAKBWdldC0zAAsFZ2V0LTQADAVnZXQtNwANBWdldC04AA4Fc2V0LTcADwVzZXQtOAAQD2FzLXNlbGVjdC1maXJzdAASDWFzLXNlbGVjdC1taWQAEw5hcy1zZWxlY3QtbGFzdAAUDWFzLWxvb3AtZmlyc3QAFQthcy1sb29wLW1pZAAWDGFzLWxvb3AtbGFzdAAXD2FzLWlmLWNvbmRpdGlvbgAYCmFzLWlmLXRoZW4AGQphcy1pZi1lbHNlABoOYXMtYnJfaWYtZmlyc3QAGw1hcy1icl9pZi1sYXN0ABwRYXMtYnJfdGFibGUtZmlyc3QAHRBhcy1icl90YWJsZS1sYXN0AB4WYXMtY2FsbF9pbmRpcmVjdC1maXJzdAAgFGFzLWNhbGxfaW5kaXJlY3QtbWlkACEVYXMtY2FsbF9pbmRpcmVjdC1sYXN0ACIOYXMtc3RvcmUtZmlyc3QAIw1hcy1zdG9yZS1sYXN0ACQPYXMtbG9hZC1vcGVyYW5kACUUYXMtbWVtb3J5Lmdyb3ctdmFsdWUAJg1hcy1jYWxsLXZhbHVlACgPYXMtcmV0dXJuLXZhbHVlACkPYXMtZHJvcC1vcGVyYW5kACoLYXMtYnItdmFsdWUAKxJhcy1sb2NhbC5zZXQtdmFsdWUALBJhcy1sb2NhbC50ZWUtdmFsdWUALRNhcy1nbG9iYWwuc2V0LXZhbHVlAC4QYXMtdW5hcnktb3BlcmFuZAAvEWFzLWJpbmFyeS1vcGVyYW5kADASYXMtY29tcGFyZS1vcGVyYW5kADEJBwEAQQALAR8KsAMyBAAjAgsEACMFCwQAIwwLBAAjDQsEACMGCwQAIwkLBAAjCgsEACMLCwYAIAAkBgsGACAAJAkLBgAgACQNCwQAIwMLBAAjBAsEACMHCwQAIwgLBgAgACQHCwYAIAAkCAsCAAsJACMGQQJBAxsLCQBBAiMGQQMbCwkAQQJBAyMGGwsLAAN/IwYQERARCwsLAAN/EBEjBhARCwsLAAN/EBEQESMGCwsQACMGBH8QEUECBRARQQMLCwwAQQEEfyMGBUECCwsMAEEABH9BAgUjBgsLDgACfyMGQQINAEEDDwsLDgACf0ECIwYNAEEDDwsLDQACfyMGQQIOAQAACwsNAAJ/QQIjBg4BAAALCwQAIAALDgACfyMGQQJBABEAAAsLDgACf0ECIwZBABEAAAsLDgACf0ECQQAjBhEAAAsLCQAjBkEBNgIACwkAQQAjBjYCAAsHACMGKAIACwYAIwZAAAsEACAACwYAIwYQJwsFACMGDwsFACMGGgsJAAJ/IwYMAAsLCAAjBiEAIAALBgAjBiIACwgAIwYkBiMGCwUAIwZFCwcAIwYjBmwLBwAjAEEBSws=", + "AGFzbQEAAAAGCQF9AUMAAAAACwcFAQFhAwA=", + "AGFzbQEAAAACGAEIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AA==", + "AGFzbQEAAAAGBgF/AEEACw==", + "AGFzbQEAAAABCAJgAABgAAF/AwQDAAEABQQBAQEBBw0CA2luYwAAA2dldAABCAECCiMDDwBBAEEALQAAQQFqOgAACwgAQQAtAAAPCwgAEAAQABAACwsHAQBBAAsBQQ==", + "AGFzbQEAAAABCAJgAX8AYAAAAhYBCHNwZWN0ZXN0CXByaW50X2kzMgAAAwIBAQgBAQoIAQYAQQEQAAs=", + "AGFzbQEAAAABCAJgAX8AYAAAAhYBCHNwZWN0ZXN0CXByaW50X2kzMgAAAwIBAQgBAQoIAQYAQQIQAAs=", + "AGFzbQEAAAABBAFgAAACEgEIc3BlY3Rlc3QFcHJpbnQAAAgBAA==", + "AGFzbQEAAAABBAFgAAADAgEACAEACgUBAwAACw==", +]; +export const script = "[[\"file\",\"block.wast\"],[\"module\",3,0],[\"invoke\",353,0,\"empty\",[]],[\"invoke\",354,0,\"singular\",[]],[\"invoke\",355,0,\"multi\",[]],[\"invoke\",356,0,\"nested\",[]],[\"invoke\",357,0,\"deep\",[]],[\"invoke\",359,0,\"as-select-first\",[]],[\"invoke\",360,0,\"as-select-mid\",[]],[\"invoke\",361,0,\"as-select-last\",[]],[\"invoke\",363,0,\"as-loop-first\",[]],[\"invoke\",364,0,\"as-loop-mid\",[]],[\"invoke\",365,0,\"as-loop-last\",[]],[\"invoke\",367,0,\"as-if-condition\",[]],[\"invoke\",368,0,\"as-if-then\",[]],[\"invoke\",369,0,\"as-if-else\",[]],[\"invoke\",371,0,\"as-br_if-first\",[]],[\"invoke\",372,0,\"as-br_if-last\",[]],[\"invoke\",374,0,\"as-br_table-first\",[]],[\"invoke\",375,0,\"as-br_table-last\",[]],[\"invoke\",377,0,\"as-call_indirect-first\",[]],[\"invoke\",378,0,\"as-call_indirect-mid\",[]],[\"invoke\",379,0,\"as-call_indirect-last\",[]],[\"invoke\",381,0,\"as-store-first\",[]],[\"invoke\",382,0,\"as-store-last\",[]],[\"invoke\",384,0,\"as-memory.grow-value\",[]],[\"invoke\",385,0,\"as-call-value\",[]],[\"invoke\",386,0,\"as-return-value\",[]],[\"invoke\",387,0,\"as-drop-operand\",[]],[\"invoke\",388,0,\"as-br-value\",[]],[\"invoke\",389,0,\"as-local.set-value\",[]],[\"invoke\",390,0,\"as-local.tee-value\",[]],[\"invoke\",391,0,\"as-global.set-value\",[]],[\"invoke\",392,0,\"as-load-operand\",[]],[\"invoke\",394,0,\"as-unary-operand\",[]],[\"invoke\",395,0,\"as-binary-operand\",[]],[\"invoke\",396,0,\"as-test-operand\",[]],[\"invoke\",397,0,\"as-compare-operand\",[]],[\"invoke\",398,0,\"as-binary-operands\",[]],[\"invoke\",399,0,\"as-compare-operands\",[]],[\"invoke\",400,0,\"as-mixed-operands\",[]],[\"invoke\",402,0,\"break-bare\",[]],[\"invoke\",403,0,\"break-value\",[]],[\"invoke\",404,0,\"break-multi-value\",[]],[\"invoke\",407,0,\"break-repeated\",[]],[\"invoke\",408,0,\"break-inner\",[]],[\"invoke\",410,0,\"param\",[]],[\"invoke\",411,0,\"params\",[]],[\"invoke\",412,0,\"params-id\",[]],[\"invoke\",413,0,\"param-break\",[]],[\"invoke\",414,0,\"params-break\",[]],[\"invoke\",415,0,\"params-id-break\",[]],[\"invoke\",417,0,\"effects\",[]],[\"invoke\",419,0,\"type-use\",[]],[\"file\",\"br.wast\"],[\"module\",3,1],[\"invoke\",372,0,\"type-i32\",[]],[\"invoke\",373,0,\"type-i64\",[]],[\"invoke\",374,0,\"type-f32\",[]],[\"invoke\",375,0,\"type-f64\",[]],[\"invoke\",376,0,\"type-i32-i32\",[]],[\"invoke\",377,0,\"type-i64-i64\",[]],[\"invoke\",378,0,\"type-f32-f32\",[]],[\"invoke\",379,0,\"type-f64-f64\",[]],[\"invoke\",381,0,\"type-i32-value\",[]],[\"invoke\",382,0,\"type-i64-value\",[]],[\"invoke\",383,0,\"type-f32-value\",[]],[\"invoke\",384,0,\"type-f64-value\",[]],[\"invoke\",385,0,\"type-f64-f64-value\",[]],[\"invoke\",387,0,\"as-block-first\",[]],[\"invoke\",388,0,\"as-block-mid\",[]],[\"invoke\",389,0,\"as-block-last\",[]],[\"invoke\",390,0,\"as-block-value\",[]],[\"invoke\",392,0,\"as-loop-first\",[]],[\"invoke\",393,0,\"as-loop-mid\",[]],[\"invoke\",394,0,\"as-loop-last\",[]],[\"invoke\",396,0,\"as-br-value\",[]],[\"invoke\",398,0,\"as-br_if-cond\",[]],[\"invoke\",399,0,\"as-br_if-value\",[]],[\"invoke\",400,0,\"as-br_if-value-cond\",[]],[\"invoke\",402,0,\"as-br_table-index\",[]],[\"invoke\",403,0,\"as-br_table-value\",[]],[\"invoke\",404,0,\"as-br_table-value-index\",[]],[\"invoke\",406,0,\"as-return-value\",[]],[\"invoke\",407,0,\"as-return-values\",[]],[\"invoke\",409,0,\"as-if-cond\",[]],[\"invoke\",410,0,\"as-if-then\",[\"i32:1\",\"i32:6\"]],[\"invoke\",411,0,\"as-if-then\",[\"i32:0\",\"i32:6\"]],[\"invoke\",412,0,\"as-if-else\",[\"i32:0\",\"i32:6\"]],[\"invoke\",413,0,\"as-if-else\",[\"i32:1\",\"i32:6\"]],[\"invoke\",415,0,\"as-select-first\",[\"i32:0\",\"i32:6\"]],[\"invoke\",416,0,\"as-select-first\",[\"i32:1\",\"i32:6\"]],[\"invoke\",417,0,\"as-select-second\",[\"i32:0\",\"i32:6\"]],[\"invoke\",418,0,\"as-select-second\",[\"i32:1\",\"i32:6\"]],[\"invoke\",419,0,\"as-select-cond\",[]],[\"invoke\",420,0,\"as-select-all\",[]],[\"invoke\",422,0,\"as-call-first\",[]],[\"invoke\",423,0,\"as-call-mid\",[]],[\"invoke\",424,0,\"as-call-last\",[]],[\"invoke\",425,0,\"as-call-all\",[]],[\"invoke\",427,0,\"as-call_indirect-func\",[]],[\"invoke\",428,0,\"as-call_indirect-first\",[]],[\"invoke\",429,0,\"as-call_indirect-mid\",[]],[\"invoke\",430,0,\"as-call_indirect-last\",[]],[\"invoke\",431,0,\"as-call_indirect-all\",[]],[\"invoke\",433,0,\"as-local.set-value\",[]],[\"invoke\",434,0,\"as-local.tee-value\",[]],[\"invoke\",435,0,\"as-global.set-value\",[]],[\"invoke\",437,0,\"as-load-address\",[]],[\"invoke\",438,0,\"as-loadN-address\",[]],[\"invoke\",440,0,\"as-store-address\",[]],[\"invoke\",441,0,\"as-store-value\",[]],[\"invoke\",442,0,\"as-store-both\",[]],[\"invoke\",443,0,\"as-storeN-address\",[]],[\"invoke\",444,0,\"as-storeN-value\",[]],[\"invoke\",445,0,\"as-storeN-both\",[]],[\"invoke\",447,0,\"as-unary-operand\",[]],[\"invoke\",449,0,\"as-binary-left\",[]],[\"invoke\",450,0,\"as-binary-right\",[]],[\"invoke\",451,0,\"as-binary-both\",[]],[\"invoke\",453,0,\"as-test-operand\",[]],[\"invoke\",455,0,\"as-compare-left\",[]],[\"invoke\",456,0,\"as-compare-right\",[]],[\"invoke\",457,0,\"as-compare-both\",[]],[\"invoke\",459,0,\"as-convert-operand\",[]],[\"invoke\",461,0,\"as-memory.grow-size\",[]],[\"invoke\",463,0,\"nested-block-value\",[]],[\"invoke\",464,0,\"nested-br-value\",[]],[\"invoke\",465,0,\"nested-br_if-value\",[]],[\"invoke\",466,0,\"nested-br_if-value-cond\",[]],[\"invoke\",467,0,\"nested-br_table-value\",[]],[\"invoke\",468,0,\"nested-br_table-value-index\",[]],[\"file\",\"br_if.wast\"],[\"module\",3,2],[\"invoke\",372,0,\"type-i32\",[]],[\"invoke\",373,0,\"type-i64\",[]],[\"invoke\",374,0,\"type-f32\",[]],[\"invoke\",375,0,\"type-f64\",[]],[\"invoke\",377,0,\"type-i32-value\",[]],[\"invoke\",378,0,\"type-i64-value\",[]],[\"invoke\",379,0,\"type-f32-value\",[]],[\"invoke\",380,0,\"type-f64-value\",[]],[\"invoke\",382,0,\"as-block-first\",[\"i32:0\"]],[\"invoke\",383,0,\"as-block-first\",[\"i32:1\"]],[\"invoke\",384,0,\"as-block-mid\",[\"i32:0\"]],[\"invoke\",385,0,\"as-block-mid\",[\"i32:1\"]],[\"invoke\",386,0,\"as-block-last\",[\"i32:0\"]],[\"invoke\",387,0,\"as-block-last\",[\"i32:1\"]],[\"invoke\",389,0,\"as-block-first-value\",[\"i32:0\"]],[\"invoke\",390,0,\"as-block-first-value\",[\"i32:1\"]],[\"invoke\",391,0,\"as-block-mid-value\",[\"i32:0\"]],[\"invoke\",392,0,\"as-block-mid-value\",[\"i32:1\"]],[\"invoke\",393,0,\"as-block-last-value\",[\"i32:0\"]],[\"invoke\",394,0,\"as-block-last-value\",[\"i32:1\"]],[\"invoke\",396,0,\"as-loop-first\",[\"i32:0\"]],[\"invoke\",397,0,\"as-loop-first\",[\"i32:1\"]],[\"invoke\",398,0,\"as-loop-mid\",[\"i32:0\"]],[\"invoke\",399,0,\"as-loop-mid\",[\"i32:1\"]],[\"invoke\",400,0,\"as-loop-last\",[\"i32:0\"]],[\"invoke\",401,0,\"as-loop-last\",[\"i32:1\"]],[\"invoke\",403,0,\"as-br-value\",[]],[\"invoke\",405,0,\"as-br_if-cond\",[]],[\"invoke\",406,0,\"as-br_if-value\",[]],[\"invoke\",407,0,\"as-br_if-value-cond\",[\"i32:0\"]],[\"invoke\",408,0,\"as-br_if-value-cond\",[\"i32:1\"]],[\"invoke\",410,0,\"as-br_table-index\",[]],[\"invoke\",411,0,\"as-br_table-value\",[]],[\"invoke\",412,0,\"as-br_table-value-index\",[]],[\"invoke\",414,0,\"as-return-value\",[]],[\"invoke\",416,0,\"as-if-cond\",[\"i32:0\"]],[\"invoke\",417,0,\"as-if-cond\",[\"i32:1\"]],[\"invoke\",418,0,\"as-if-then\",[\"i32:0\",\"i32:0\"]],[\"invoke\",419,0,\"as-if-then\",[\"i32:4\",\"i32:0\"]],[\"invoke\",420,0,\"as-if-then\",[\"i32:0\",\"i32:1\"]],[\"invoke\",421,0,\"as-if-then\",[\"i32:4\",\"i32:1\"]],[\"invoke\",422,0,\"as-if-else\",[\"i32:0\",\"i32:0\"]],[\"invoke\",423,0,\"as-if-else\",[\"i32:3\",\"i32:0\"]],[\"invoke\",424,0,\"as-if-else\",[\"i32:0\",\"i32:1\"]],[\"invoke\",425,0,\"as-if-else\",[\"i32:3\",\"i32:1\"]],[\"invoke\",427,0,\"as-select-first\",[\"i32:0\"]],[\"invoke\",428,0,\"as-select-first\",[\"i32:1\"]],[\"invoke\",429,0,\"as-select-second\",[\"i32:0\"]],[\"invoke\",430,0,\"as-select-second\",[\"i32:1\"]],[\"invoke\",431,0,\"as-select-cond\",[]],[\"invoke\",433,0,\"as-call-first\",[]],[\"invoke\",434,0,\"as-call-mid\",[]],[\"invoke\",435,0,\"as-call-last\",[]],[\"invoke\",437,0,\"as-call_indirect-func\",[]],[\"invoke\",438,0,\"as-call_indirect-first\",[]],[\"invoke\",439,0,\"as-call_indirect-mid\",[]],[\"invoke\",440,0,\"as-call_indirect-last\",[]],[\"invoke\",442,0,\"as-local.set-value\",[\"i32:0\"]],[\"invoke\",443,0,\"as-local.set-value\",[\"i32:1\"]],[\"invoke\",445,0,\"as-local.tee-value\",[\"i32:0\"]],[\"invoke\",446,0,\"as-local.tee-value\",[\"i32:1\"]],[\"invoke\",448,0,\"as-global.set-value\",[\"i32:0\"]],[\"invoke\",449,0,\"as-global.set-value\",[\"i32:1\"]],[\"invoke\",451,0,\"as-load-address\",[]],[\"invoke\",452,0,\"as-loadN-address\",[]],[\"invoke\",454,0,\"as-store-address\",[]],[\"invoke\",455,0,\"as-store-value\",[]],[\"invoke\",456,0,\"as-storeN-address\",[]],[\"invoke\",457,0,\"as-storeN-value\",[]],[\"invoke\",459,0,\"as-unary-operand\",[]],[\"invoke\",460,0,\"as-binary-left\",[]],[\"invoke\",461,0,\"as-binary-right\",[]],[\"invoke\",462,0,\"as-test-operand\",[]],[\"invoke\",463,0,\"as-compare-left\",[]],[\"invoke\",464,0,\"as-compare-right\",[]],[\"invoke\",465,0,\"as-memory.grow-size\",[]],[\"invoke\",467,0,\"nested-block-value\",[\"i32:0\"]],[\"invoke\",468,0,\"nested-block-value\",[\"i32:1\"]],[\"invoke\",469,0,\"nested-br-value\",[\"i32:0\"]],[\"invoke\",470,0,\"nested-br-value\",[\"i32:1\"]],[\"invoke\",471,0,\"nested-br_if-value\",[\"i32:0\"]],[\"invoke\",472,0,\"nested-br_if-value\",[\"i32:1\"]],[\"invoke\",473,0,\"nested-br_if-value-cond\",[\"i32:0\"]],[\"invoke\",474,0,\"nested-br_if-value-cond\",[\"i32:1\"]],[\"invoke\",475,0,\"nested-br_table-value\",[\"i32:0\"]],[\"invoke\",476,0,\"nested-br_table-value\",[\"i32:1\"]],[\"invoke\",477,0,\"nested-br_table-value-index\",[\"i32:0\"]],[\"invoke\",478,0,\"nested-br_table-value-index\",[\"i32:1\"]],[\"file\",\"br_table.wast\"],[\"module\",3,3],[\"invoke\",1007,0,\"type-i32\",[]],[\"invoke\",1008,0,\"type-i64\",[]],[\"invoke\",1009,0,\"type-f32\",[]],[\"invoke\",1010,0,\"type-f64\",[]],[\"invoke\",1012,0,\"type-i32-value\",[]],[\"invoke\",1013,0,\"type-i64-value\",[]],[\"invoke\",1014,0,\"type-f32-value\",[]],[\"invoke\",1015,0,\"type-f64-value\",[]],[\"invoke\",1017,0,\"empty\",[\"i32:0\"]],[\"invoke\",1018,0,\"empty\",[\"i32:1\"]],[\"invoke\",1019,0,\"empty\",[\"i32:11\"]],[\"invoke\",1020,0,\"empty\",[\"i32:4294967295\"]],[\"invoke\",1021,0,\"empty\",[\"i32:4294967196\"]],[\"invoke\",1022,0,\"empty\",[\"i32:4294967295\"]],[\"invoke\",1024,0,\"empty-value\",[\"i32:0\"]],[\"invoke\",1025,0,\"empty-value\",[\"i32:1\"]],[\"invoke\",1026,0,\"empty-value\",[\"i32:11\"]],[\"invoke\",1027,0,\"empty-value\",[\"i32:4294967295\"]],[\"invoke\",1028,0,\"empty-value\",[\"i32:4294967196\"]],[\"invoke\",1029,0,\"empty-value\",[\"i32:4294967295\"]],[\"invoke\",1031,0,\"singleton\",[\"i32:0\"]],[\"invoke\",1032,0,\"singleton\",[\"i32:1\"]],[\"invoke\",1033,0,\"singleton\",[\"i32:11\"]],[\"invoke\",1034,0,\"singleton\",[\"i32:4294967295\"]],[\"invoke\",1035,0,\"singleton\",[\"i32:4294967196\"]],[\"invoke\",1036,0,\"singleton\",[\"i32:4294967295\"]],[\"invoke\",1038,0,\"singleton-value\",[\"i32:0\"]],[\"invoke\",1039,0,\"singleton-value\",[\"i32:1\"]],[\"invoke\",1040,0,\"singleton-value\",[\"i32:11\"]],[\"invoke\",1041,0,\"singleton-value\",[\"i32:4294967295\"]],[\"invoke\",1042,0,\"singleton-value\",[\"i32:4294967196\"]],[\"invoke\",1043,0,\"singleton-value\",[\"i32:4294967295\"]],[\"invoke\",1045,0,\"multiple\",[\"i32:0\"]],[\"invoke\",1046,0,\"multiple\",[\"i32:1\"]],[\"invoke\",1047,0,\"multiple\",[\"i32:2\"]],[\"invoke\",1048,0,\"multiple\",[\"i32:3\"]],[\"invoke\",1049,0,\"multiple\",[\"i32:4\"]],[\"invoke\",1050,0,\"multiple\",[\"i32:5\"]],[\"invoke\",1051,0,\"multiple\",[\"i32:6\"]],[\"invoke\",1052,0,\"multiple\",[\"i32:10\"]],[\"invoke\",1053,0,\"multiple\",[\"i32:4294967295\"]],[\"invoke\",1054,0,\"multiple\",[\"i32:4294967295\"]],[\"invoke\",1056,0,\"multiple-value\",[\"i32:0\"]],[\"invoke\",1057,0,\"multiple-value\",[\"i32:1\"]],[\"invoke\",1058,0,\"multiple-value\",[\"i32:2\"]],[\"invoke\",1059,0,\"multiple-value\",[\"i32:3\"]],[\"invoke\",1060,0,\"multiple-value\",[\"i32:4\"]],[\"invoke\",1061,0,\"multiple-value\",[\"i32:5\"]],[\"invoke\",1062,0,\"multiple-value\",[\"i32:6\"]],[\"invoke\",1063,0,\"multiple-value\",[\"i32:10\"]],[\"invoke\",1064,0,\"multiple-value\",[\"i32:4294967295\"]],[\"invoke\",1065,0,\"multiple-value\",[\"i32:4294967295\"]],[\"invoke\",1067,0,\"large\",[\"i32:0\"]],[\"invoke\",1068,0,\"large\",[\"i32:1\"]],[\"invoke\",1069,0,\"large\",[\"i32:100\"]],[\"invoke\",1070,0,\"large\",[\"i32:101\"]],[\"invoke\",1071,0,\"large\",[\"i32:10000\"]],[\"invoke\",1072,0,\"large\",[\"i32:10001\"]],[\"invoke\",1073,0,\"large\",[\"i32:1000000\"]],[\"invoke\",1074,0,\"large\",[\"i32:1000001\"]],[\"invoke\",1076,0,\"as-block-first\",[]],[\"invoke\",1077,0,\"as-block-mid\",[]],[\"invoke\",1078,0,\"as-block-last\",[]],[\"invoke\",1079,0,\"as-block-value\",[]],[\"invoke\",1081,0,\"as-loop-first\",[]],[\"invoke\",1082,0,\"as-loop-mid\",[]],[\"invoke\",1083,0,\"as-loop-last\",[]],[\"invoke\",1085,0,\"as-br-value\",[]],[\"invoke\",1087,0,\"as-br_if-cond\",[]],[\"invoke\",1088,0,\"as-br_if-value\",[]],[\"invoke\",1089,0,\"as-br_if-value-cond\",[]],[\"invoke\",1091,0,\"as-br_table-index\",[]],[\"invoke\",1092,0,\"as-br_table-value\",[]],[\"invoke\",1093,0,\"as-br_table-value-index\",[]],[\"invoke\",1095,0,\"as-return-value\",[]],[\"invoke\",1097,0,\"as-if-cond\",[]],[\"invoke\",1098,0,\"as-if-then\",[\"i32:1\",\"i32:6\"]],[\"invoke\",1099,0,\"as-if-then\",[\"i32:0\",\"i32:6\"]],[\"invoke\",1100,0,\"as-if-else\",[\"i32:0\",\"i32:6\"]],[\"invoke\",1101,0,\"as-if-else\",[\"i32:1\",\"i32:6\"]],[\"invoke\",1103,0,\"as-select-first\",[\"i32:0\",\"i32:6\"]],[\"invoke\",1104,0,\"as-select-first\",[\"i32:1\",\"i32:6\"]],[\"invoke\",1105,0,\"as-select-second\",[\"i32:0\",\"i32:6\"]],[\"invoke\",1106,0,\"as-select-second\",[\"i32:1\",\"i32:6\"]],[\"invoke\",1107,0,\"as-select-cond\",[]],[\"invoke\",1109,0,\"as-call-first\",[]],[\"invoke\",1110,0,\"as-call-mid\",[]],[\"invoke\",1111,0,\"as-call-last\",[]],[\"invoke\",1113,0,\"as-call_indirect-first\",[]],[\"invoke\",1114,0,\"as-call_indirect-mid\",[]],[\"invoke\",1115,0,\"as-call_indirect-last\",[]],[\"invoke\",1116,0,\"as-call_indirect-func\",[]],[\"invoke\",1118,0,\"as-local.set-value\",[]],[\"invoke\",1119,0,\"as-local.tee-value\",[]],[\"invoke\",1120,0,\"as-global.set-value\",[]],[\"invoke\",1122,0,\"as-load-address\",[]],[\"invoke\",1123,0,\"as-loadN-address\",[]],[\"invoke\",1125,0,\"as-store-address\",[]],[\"invoke\",1126,0,\"as-store-value\",[]],[\"invoke\",1127,0,\"as-storeN-address\",[]],[\"invoke\",1128,0,\"as-storeN-value\",[]],[\"invoke\",1130,0,\"as-unary-operand\",[]],[\"invoke\",1132,0,\"as-binary-left\",[]],[\"invoke\",1133,0,\"as-binary-right\",[]],[\"invoke\",1135,0,\"as-test-operand\",[]],[\"invoke\",1137,0,\"as-compare-left\",[]],[\"invoke\",1138,0,\"as-compare-right\",[]],[\"invoke\",1140,0,\"as-convert-operand\",[]],[\"invoke\",1142,0,\"as-memory.grow-size\",[]],[\"invoke\",1144,0,\"nested-block-value\",[\"i32:0\"]],[\"invoke\",1145,0,\"nested-block-value\",[\"i32:1\"]],[\"invoke\",1146,0,\"nested-block-value\",[\"i32:2\"]],[\"invoke\",1147,0,\"nested-block-value\",[\"i32:10\"]],[\"invoke\",1148,0,\"nested-block-value\",[\"i32:4294967295\"]],[\"invoke\",1149,0,\"nested-block-value\",[\"i32:100000\"]],[\"invoke\",1151,0,\"nested-br-value\",[\"i32:0\"]],[\"invoke\",1152,0,\"nested-br-value\",[\"i32:1\"]],[\"invoke\",1153,0,\"nested-br-value\",[\"i32:2\"]],[\"invoke\",1154,0,\"nested-br-value\",[\"i32:11\"]],[\"invoke\",1155,0,\"nested-br-value\",[\"i32:4294967292\"]],[\"invoke\",1156,0,\"nested-br-value\",[\"i32:10213210\"]],[\"invoke\",1158,0,\"nested-br_if-value\",[\"i32:0\"]],[\"invoke\",1159,0,\"nested-br_if-value\",[\"i32:1\"]],[\"invoke\",1160,0,\"nested-br_if-value\",[\"i32:2\"]],[\"invoke\",1161,0,\"nested-br_if-value\",[\"i32:9\"]],[\"invoke\",1162,0,\"nested-br_if-value\",[\"i32:4294967287\"]],[\"invoke\",1163,0,\"nested-br_if-value\",[\"i32:999999\"]],[\"invoke\",1165,0,\"nested-br_if-value-cond\",[\"i32:0\"]],[\"invoke\",1166,0,\"nested-br_if-value-cond\",[\"i32:1\"]],[\"invoke\",1167,0,\"nested-br_if-value-cond\",[\"i32:2\"]],[\"invoke\",1168,0,\"nested-br_if-value-cond\",[\"i32:3\"]],[\"invoke\",1169,0,\"nested-br_if-value-cond\",[\"i32:4293967296\"]],[\"invoke\",1170,0,\"nested-br_if-value-cond\",[\"i32:9423975\"]],[\"invoke\",1172,0,\"nested-br_table-value\",[\"i32:0\"]],[\"invoke\",1173,0,\"nested-br_table-value\",[\"i32:1\"]],[\"invoke\",1174,0,\"nested-br_table-value\",[\"i32:2\"]],[\"invoke\",1175,0,\"nested-br_table-value\",[\"i32:9\"]],[\"invoke\",1176,0,\"nested-br_table-value\",[\"i32:4294967287\"]],[\"invoke\",1177,0,\"nested-br_table-value\",[\"i32:999999\"]],[\"invoke\",1179,0,\"nested-br_table-value-index\",[\"i32:0\"]],[\"invoke\",1180,0,\"nested-br_table-value-index\",[\"i32:1\"]],[\"invoke\",1181,0,\"nested-br_table-value-index\",[\"i32:2\"]],[\"invoke\",1182,0,\"nested-br_table-value-index\",[\"i32:3\"]],[\"invoke\",1183,0,\"nested-br_table-value-index\",[\"i32:4293967296\"]],[\"invoke\",1184,0,\"nested-br_table-value-index\",[\"i32:9423975\"]],[\"invoke\",1186,0,\"nested-br_table-loop-block\",[\"i32:1\"]],[\"invoke\",1188,0,\"meet-externref\",[\"i32:0\",\"externref:1\"]],[\"invoke\",1189,0,\"meet-externref\",[\"i32:1\",\"externref:1\"]],[\"invoke\",1190,0,\"meet-externref\",[\"i32:2\",\"externref:1\"]],[\"file\",\"call.wast\"],[\"module\",3,4],[\"invoke\",285,0,\"type-i32\",[]],[\"invoke\",286,0,\"type-i64\",[]],[\"invoke\",287,0,\"type-f32\",[]],[\"invoke\",288,0,\"type-f64\",[]],[\"invoke\",289,0,\"type-i32-i64\",[]],[\"invoke\",291,0,\"type-first-i32\",[]],[\"invoke\",292,0,\"type-first-i64\",[]],[\"invoke\",293,0,\"type-first-f32\",[]],[\"invoke\",294,0,\"type-first-f64\",[]],[\"invoke\",296,0,\"type-second-i32\",[]],[\"invoke\",297,0,\"type-second-i64\",[]],[\"invoke\",298,0,\"type-second-f32\",[]],[\"invoke\",299,0,\"type-second-f64\",[]],[\"invoke\",301,0,\"type-all-i32-f64\",[]],[\"invoke\",302,0,\"type-all-i32-i32\",[]],[\"invoke\",303,0,\"type-all-f32-f64\",[]],[\"invoke\",304,0,\"type-all-f64-i32\",[]],[\"invoke\",306,0,\"as-binary-all-operands\",[]],[\"invoke\",307,0,\"as-mixed-operands\",[]],[\"invoke\",308,0,\"as-call-all-operands\",[]],[\"invoke\",310,0,\"fac\",[\"i64:0\"]],[\"invoke\",311,0,\"fac\",[\"i64:1\"]],[\"invoke\",312,0,\"fac\",[\"i64:5\"]],[\"invoke\",313,0,\"fac\",[\"i64:25\"]],[\"invoke\",314,0,\"fac-acc\",[\"i64:0\",\"i64:1\"]],[\"invoke\",315,0,\"fac-acc\",[\"i64:1\",\"i64:1\"]],[\"invoke\",316,0,\"fac-acc\",[\"i64:5\",\"i64:1\"]],[\"invoke\",318,0,\"fac-acc\",[\"i64:25\",\"i64:1\"]],[\"invoke\",322,0,\"fib\",[\"i64:0\"]],[\"invoke\",323,0,\"fib\",[\"i64:1\"]],[\"invoke\",324,0,\"fib\",[\"i64:2\"]],[\"invoke\",325,0,\"fib\",[\"i64:5\"]],[\"invoke\",326,0,\"fib\",[\"i64:20\"]],[\"invoke\",328,0,\"even\",[\"i64:0\"]],[\"invoke\",329,0,\"even\",[\"i64:1\"]],[\"invoke\",330,0,\"even\",[\"i64:100\"]],[\"invoke\",331,0,\"even\",[\"i64:77\"]],[\"invoke\",332,0,\"odd\",[\"i64:0\"]],[\"invoke\",333,0,\"odd\",[\"i64:1\"]],[\"invoke\",334,0,\"odd\",[\"i64:200\"]],[\"invoke\",335,0,\"odd\",[\"i64:77\"]],[\"invoke\",337,0,\"runaway\",[]],[\"invoke\",338,0,\"mutual-runaway\",[]],[\"invoke\",340,0,\"as-select-first\",[]],[\"invoke\",341,0,\"as-select-mid\",[]],[\"invoke\",342,0,\"as-select-last\",[]],[\"invoke\",344,0,\"as-if-condition\",[]],[\"invoke\",346,0,\"as-br_if-first\",[]],[\"invoke\",347,0,\"as-br_if-last\",[]],[\"invoke\",349,0,\"as-br_table-first\",[]],[\"invoke\",350,0,\"as-br_table-last\",[]],[\"invoke\",352,0,\"as-call_indirect-first\",[]],[\"invoke\",353,0,\"as-call_indirect-mid\",[]],[\"invoke\",354,0,\"as-call_indirect-last\",[]],[\"invoke\",356,0,\"as-store-first\",[]],[\"invoke\",357,0,\"as-store-last\",[]],[\"invoke\",359,0,\"as-memory.grow-value\",[]],[\"invoke\",360,0,\"as-return-value\",[]],[\"invoke\",361,0,\"as-drop-operand\",[]],[\"invoke\",362,0,\"as-br-value\",[]],[\"invoke\",363,0,\"as-local.set-value\",[]],[\"invoke\",364,0,\"as-local.tee-value\",[]],[\"invoke\",365,0,\"as-global.set-value\",[]],[\"invoke\",366,0,\"as-load-operand\",[]],[\"invoke\",368,0,\"as-unary-operand\",[]],[\"invoke\",369,0,\"as-binary-left\",[]],[\"invoke\",370,0,\"as-binary-right\",[]],[\"invoke\",371,0,\"as-test-operand\",[]],[\"invoke\",372,0,\"as-compare-left\",[]],[\"invoke\",373,0,\"as-compare-right\",[]],[\"invoke\",374,0,\"as-convert-operand\",[]],[\"invoke\",376,0,\"return-from-long-argument-list\",[\"i32:42\"]],[\"file\",\"call_indirect.wast\"],[\"module\",3,5],[\"invoke\",471,0,\"type-i32\",[]],[\"invoke\",472,0,\"type-i64\",[]],[\"invoke\",473,0,\"type-f32\",[]],[\"invoke\",474,0,\"type-f64\",[]],[\"invoke\",475,0,\"type-f64-i32\",[]],[\"invoke\",477,0,\"type-index\",[]],[\"invoke\",479,0,\"type-first-i32\",[]],[\"invoke\",480,0,\"type-first-i64\",[]],[\"invoke\",481,0,\"type-first-f32\",[]],[\"invoke\",482,0,\"type-first-f64\",[]],[\"invoke\",484,0,\"type-second-i32\",[]],[\"invoke\",485,0,\"type-second-i64\",[]],[\"invoke\",486,0,\"type-second-f32\",[]],[\"invoke\",487,0,\"type-second-f64\",[]],[\"invoke\",489,0,\"type-all-f64-i32\",[]],[\"invoke\",490,0,\"type-all-i32-f64\",[]],[\"invoke\",491,0,\"type-all-i32-i64\",[]],[\"invoke\",493,0,\"dispatch\",[\"i32:5\",\"i64:2\"]],[\"invoke\",494,0,\"dispatch\",[\"i32:5\",\"i64:5\"]],[\"invoke\",495,0,\"dispatch\",[\"i32:12\",\"i64:5\"]],[\"invoke\",496,0,\"dispatch\",[\"i32:13\",\"i64:5\"]],[\"invoke\",497,0,\"dispatch\",[\"i32:20\",\"i64:2\"]],[\"invoke\",498,0,\"dispatch\",[\"i32:0\",\"i64:2\"]],[\"invoke\",499,0,\"dispatch\",[\"i32:15\",\"i64:2\"]],[\"invoke\",500,0,\"dispatch\",[\"i32:32\",\"i64:2\"]],[\"invoke\",501,0,\"dispatch\",[\"i32:4294967295\",\"i64:2\"]],[\"invoke\",502,0,\"dispatch\",[\"i32:1213432423\",\"i64:2\"]],[\"invoke\",504,0,\"dispatch-structural-i64\",[\"i32:5\"]],[\"invoke\",505,0,\"dispatch-structural-i64\",[\"i32:12\"]],[\"invoke\",506,0,\"dispatch-structural-i64\",[\"i32:13\"]],[\"invoke\",507,0,\"dispatch-structural-i64\",[\"i32:20\"]],[\"invoke\",508,0,\"dispatch-structural-i64\",[\"i32:11\"]],[\"invoke\",509,0,\"dispatch-structural-i64\",[\"i32:22\"]],[\"invoke\",511,0,\"dispatch-structural-i32\",[\"i32:4\"]],[\"invoke\",512,0,\"dispatch-structural-i32\",[\"i32:23\"]],[\"invoke\",513,0,\"dispatch-structural-i32\",[\"i32:26\"]],[\"invoke\",514,0,\"dispatch-structural-i32\",[\"i32:19\"]],[\"invoke\",515,0,\"dispatch-structural-i32\",[\"i32:9\"]],[\"invoke\",516,0,\"dispatch-structural-i32\",[\"i32:21\"]],[\"invoke\",518,0,\"dispatch-structural-f32\",[\"i32:6\"]],[\"invoke\",519,0,\"dispatch-structural-f32\",[\"i32:24\"]],[\"invoke\",520,0,\"dispatch-structural-f32\",[\"i32:27\"]],[\"invoke\",521,0,\"dispatch-structural-f32\",[\"i32:21\"]],[\"invoke\",522,0,\"dispatch-structural-f32\",[\"i32:8\"]],[\"invoke\",523,0,\"dispatch-structural-f32\",[\"i32:19\"]],[\"invoke\",525,0,\"dispatch-structural-f64\",[\"i32:7\"]],[\"invoke\",526,0,\"dispatch-structural-f64\",[\"i32:25\"]],[\"invoke\",527,0,\"dispatch-structural-f64\",[\"i32:28\"]],[\"invoke\",528,0,\"dispatch-structural-f64\",[\"i32:22\"]],[\"invoke\",529,0,\"dispatch-structural-f64\",[\"i32:10\"]],[\"invoke\",530,0,\"dispatch-structural-f64\",[\"i32:18\"]],[\"invoke\",532,0,\"fac-i64\",[\"i64:0\"]],[\"invoke\",533,0,\"fac-i64\",[\"i64:1\"]],[\"invoke\",534,0,\"fac-i64\",[\"i64:5\"]],[\"invoke\",535,0,\"fac-i64\",[\"i64:25\"]],[\"invoke\",537,0,\"fac-i32\",[\"i32:0\"]],[\"invoke\",538,0,\"fac-i32\",[\"i32:1\"]],[\"invoke\",539,0,\"fac-i32\",[\"i32:5\"]],[\"invoke\",540,0,\"fac-i32\",[\"i32:10\"]],[\"invoke\",542,0,\"fac-f32\",[\"f32:0\"]],[\"invoke\",543,0,\"fac-f32\",[\"f32:1065353216\"]],[\"invoke\",544,0,\"fac-f32\",[\"f32:1084227584\"]],[\"invoke\",545,0,\"fac-f32\",[\"f32:1092616192\"]],[\"invoke\",547,0,\"fac-f64\",[\"f64:0\"]],[\"invoke\",548,0,\"fac-f64\",[\"f64:4607182418800017408\"]],[\"invoke\",549,0,\"fac-f64\",[\"f64:4617315517961601024\"]],[\"invoke\",550,0,\"fac-f64\",[\"f64:4621819117588971520\"]],[\"invoke\",552,0,\"fib-i64\",[\"i64:0\"]],[\"invoke\",553,0,\"fib-i64\",[\"i64:1\"]],[\"invoke\",554,0,\"fib-i64\",[\"i64:2\"]],[\"invoke\",555,0,\"fib-i64\",[\"i64:5\"]],[\"invoke\",556,0,\"fib-i64\",[\"i64:20\"]],[\"invoke\",558,0,\"fib-i32\",[\"i32:0\"]],[\"invoke\",559,0,\"fib-i32\",[\"i32:1\"]],[\"invoke\",560,0,\"fib-i32\",[\"i32:2\"]],[\"invoke\",561,0,\"fib-i32\",[\"i32:5\"]],[\"invoke\",562,0,\"fib-i32\",[\"i32:20\"]],[\"invoke\",564,0,\"fib-f32\",[\"f32:0\"]],[\"invoke\",565,0,\"fib-f32\",[\"f32:1065353216\"]],[\"invoke\",566,0,\"fib-f32\",[\"f32:1073741824\"]],[\"invoke\",567,0,\"fib-f32\",[\"f32:1084227584\"]],[\"invoke\",568,0,\"fib-f32\",[\"f32:1101004800\"]],[\"invoke\",570,0,\"fib-f64\",[\"f64:0\"]],[\"invoke\",571,0,\"fib-f64\",[\"f64:4607182418800017408\"]],[\"invoke\",572,0,\"fib-f64\",[\"f64:4611686018427387904\"]],[\"invoke\",573,0,\"fib-f64\",[\"f64:4617315517961601024\"]],[\"invoke\",574,0,\"fib-f64\",[\"f64:4626322717216342016\"]],[\"invoke\",576,0,\"even\",[\"i32:0\"]],[\"invoke\",577,0,\"even\",[\"i32:1\"]],[\"invoke\",578,0,\"even\",[\"i32:100\"]],[\"invoke\",579,0,\"even\",[\"i32:77\"]],[\"invoke\",580,0,\"odd\",[\"i32:0\"]],[\"invoke\",581,0,\"odd\",[\"i32:1\"]],[\"invoke\",582,0,\"odd\",[\"i32:200\"]],[\"invoke\",583,0,\"odd\",[\"i32:77\"]],[\"invoke\",585,0,\"runaway\",[]],[\"invoke\",586,0,\"mutual-runaway\",[]],[\"invoke\",588,0,\"as-select-first\",[]],[\"invoke\",589,0,\"as-select-mid\",[]],[\"invoke\",590,0,\"as-select-last\",[]],[\"invoke\",592,0,\"as-if-condition\",[]],[\"invoke\",594,0,\"as-br_if-first\",[]],[\"invoke\",595,0,\"as-br_if-last\",[]],[\"invoke\",597,0,\"as-br_table-first\",[]],[\"invoke\",598,0,\"as-br_table-last\",[]],[\"invoke\",600,0,\"as-store-first\",[]],[\"invoke\",601,0,\"as-store-last\",[]],[\"invoke\",603,0,\"as-memory.grow-value\",[]],[\"invoke\",604,0,\"as-return-value\",[]],[\"invoke\",605,0,\"as-drop-operand\",[]],[\"invoke\",606,0,\"as-br-value\",[]],[\"invoke\",607,0,\"as-local.set-value\",[]],[\"invoke\",608,0,\"as-local.tee-value\",[]],[\"invoke\",609,0,\"as-global.set-value\",[]],[\"invoke\",610,0,\"as-load-operand\",[]],[\"invoke\",612,0,\"as-unary-operand\",[]],[\"invoke\",613,0,\"as-binary-left\",[]],[\"invoke\",614,0,\"as-binary-right\",[]],[\"invoke\",615,0,\"as-test-operand\",[]],[\"invoke\",616,0,\"as-compare-left\",[]],[\"invoke\",617,0,\"as-compare-right\",[]],[\"invoke\",618,0,\"as-convert-operand\",[]],[\"module\",623,6],[\"invoke\",650,0,\"call-1\",[\"i32:2\",\"i32:3\",\"i32:0\"]],[\"invoke\",651,0,\"call-1\",[\"i32:2\",\"i32:3\",\"i32:1\"]],[\"invoke\",652,0,\"call-1\",[\"i32:2\",\"i32:3\",\"i32:2\"]],[\"invoke\",654,0,\"call-2\",[\"i32:2\",\"i32:3\",\"i32:0\"]],[\"invoke\",655,0,\"call-2\",[\"i32:2\",\"i32:3\",\"i32:1\"]],[\"invoke\",656,0,\"call-2\",[\"i32:2\",\"i32:3\",\"i32:2\"]],[\"invoke\",657,0,\"call-2\",[\"i32:2\",\"i32:3\",\"i32:3\"]],[\"invoke\",659,0,\"call-3\",[\"i32:2\",\"i32:3\",\"i32:0\"]],[\"invoke\",660,0,\"call-3\",[\"i32:2\",\"i32:3\",\"i32:1\"]],[\"invoke\",661,0,\"call-3\",[\"i32:2\",\"i32:3\",\"i32:2\"]],[\"invoke\",662,0,\"call-3\",[\"i32:2\",\"i32:3\",\"i32:3\"]],[\"invoke\",663,0,\"call-3\",[\"i32:2\",\"i32:3\",\"i32:4\"]],[\"module\",1047,7],[\"file\",\"fac.wast\"],[\"module\",1,8],[\"invoke\",102,0,\"fac-rec\",[\"i64:25\"]],[\"invoke\",103,0,\"fac-iter\",[\"i64:25\"]],[\"invoke\",104,0,\"fac-rec-named\",[\"i64:25\"]],[\"invoke\",105,0,\"fac-iter-named\",[\"i64:25\"]],[\"invoke\",106,0,\"fac-opt\",[\"i64:25\"]],[\"invoke\",107,0,\"fac-ssa\",[\"i64:25\"]],[\"invoke\",109,0,\"fac-rec\",[\"i64:1073741824\"]],[\"file\",\"forward.wast\"],[\"module\",1,9],[\"invoke\",17,0,\"even\",[\"i32:13\"]],[\"invoke\",18,0,\"even\",[\"i32:20\"]],[\"invoke\",19,0,\"odd\",[\"i32:13\"]],[\"invoke\",20,0,\"odd\",[\"i32:20\"]],[\"file\",\"func.wast\"],[\"module\",3,10],[\"invoke\",241,0,\"type-use-1\",[]],[\"invoke\",242,0,\"type-use-2\",[]],[\"invoke\",243,0,\"type-use-3\",[\"i32:1\"]],[\"invoke\",245,0,\"type-use-4\",[\"i32:1\",\"f64:4607182418800017408\",\"i32:1\"]],[\"invoke\",248,0,\"type-use-5\",[]],[\"invoke\",249,0,\"type-use-6\",[\"i32:1\"]],[\"invoke\",251,0,\"type-use-7\",[\"i32:1\",\"f64:4607182418800017408\",\"i32:1\"]],[\"invoke\",255,0,\"local-first-i32\",[]],[\"invoke\",256,0,\"local-first-i64\",[]],[\"invoke\",257,0,\"local-first-f32\",[]],[\"invoke\",258,0,\"local-first-f64\",[]],[\"invoke\",259,0,\"local-second-i32\",[]],[\"invoke\",260,0,\"local-second-i64\",[]],[\"invoke\",261,0,\"local-second-f32\",[]],[\"invoke\",262,0,\"local-second-f64\",[]],[\"invoke\",263,0,\"local-mixed\",[]],[\"invoke\",266,0,\"param-first-i32\",[\"i32:2\",\"i32:3\"]],[\"invoke\",269,0,\"param-first-i64\",[\"i64:2\",\"i64:3\"]],[\"invoke\",272,0,\"param-first-f32\",[\"f32:1073741824\",\"f32:1077936128\"]],[\"invoke\",275,0,\"param-first-f64\",[\"f64:4611686018427387904\",\"f64:4613937818241073152\"]],[\"invoke\",278,0,\"param-second-i32\",[\"i32:2\",\"i32:3\"]],[\"invoke\",281,0,\"param-second-i64\",[\"i64:2\",\"i64:3\"]],[\"invoke\",284,0,\"param-second-f32\",[\"f32:1073741824\",\"f32:1077936128\"]],[\"invoke\",287,0,\"param-second-f64\",[\"f64:4611686018427387904\",\"f64:4613937818241073152\"]],[\"invoke\",291,0,\"param-mixed\",[\"f32:1065353216\",\"i32:2\",\"i64:3\",\"i32:4\",\"f64:4617878467915022336\",\"i32:6\"]],[\"invoke\",298,0,\"empty\",[]],[\"invoke\",299,0,\"value-void\",[]],[\"invoke\",300,0,\"value-i32\",[]],[\"invoke\",301,0,\"value-i64\",[]],[\"invoke\",302,0,\"value-f32\",[]],[\"invoke\",303,0,\"value-f64\",[]],[\"invoke\",304,0,\"value-i32-f64\",[]],[\"invoke\",305,0,\"value-i32-i32-i32\",[]],[\"invoke\",308,0,\"value-block-void\",[]],[\"invoke\",309,0,\"value-block-i32\",[]],[\"invoke\",310,0,\"value-block-i32-i64\",[]],[\"invoke\",312,0,\"return-empty\",[]],[\"invoke\",313,0,\"return-i32\",[]],[\"invoke\",314,0,\"return-i64\",[]],[\"invoke\",315,0,\"return-f32\",[]],[\"invoke\",316,0,\"return-f64\",[]],[\"invoke\",317,0,\"return-i32-f64\",[]],[\"invoke\",318,0,\"return-i32-i32-i32\",[]],[\"invoke\",321,0,\"return-block-i32\",[]],[\"invoke\",322,0,\"return-block-i32-i64\",[]],[\"invoke\",324,0,\"break-empty\",[]],[\"invoke\",325,0,\"break-i32\",[]],[\"invoke\",326,0,\"break-i64\",[]],[\"invoke\",327,0,\"break-f32\",[]],[\"invoke\",328,0,\"break-f64\",[]],[\"invoke\",329,0,\"break-i32-f64\",[]],[\"invoke\",330,0,\"break-i32-i32-i32\",[]],[\"invoke\",333,0,\"break-block-i32\",[]],[\"invoke\",334,0,\"break-block-i32-i64\",[]],[\"invoke\",336,0,\"break-br_if-empty\",[\"i32:0\"]],[\"invoke\",337,0,\"break-br_if-empty\",[\"i32:2\"]],[\"invoke\",338,0,\"break-br_if-num\",[\"i32:0\"]],[\"invoke\",339,0,\"break-br_if-num\",[\"i32:1\"]],[\"invoke\",340,0,\"break-br_if-num-num\",[\"i32:0\"]],[\"invoke\",343,0,\"break-br_if-num-num\",[\"i32:1\"]],[\"invoke\",347,0,\"break-br_table-empty\",[\"i32:0\"]],[\"invoke\",348,0,\"break-br_table-empty\",[\"i32:1\"]],[\"invoke\",349,0,\"break-br_table-empty\",[\"i32:5\"]],[\"invoke\",350,0,\"break-br_table-empty\",[\"i32:4294967295\"]],[\"invoke\",351,0,\"break-br_table-num\",[\"i32:0\"]],[\"invoke\",352,0,\"break-br_table-num\",[\"i32:1\"]],[\"invoke\",353,0,\"break-br_table-num\",[\"i32:10\"]],[\"invoke\",354,0,\"break-br_table-num\",[\"i32:4294967196\"]],[\"invoke\",355,0,\"break-br_table-num-num\",[\"i32:0\"]],[\"invoke\",358,0,\"break-br_table-num-num\",[\"i32:1\"]],[\"invoke\",361,0,\"break-br_table-num-num\",[\"i32:10\"]],[\"invoke\",364,0,\"break-br_table-num-num\",[\"i32:4294967196\"]],[\"invoke\",367,0,\"break-br_table-nested-empty\",[\"i32:0\"]],[\"invoke\",368,0,\"break-br_table-nested-empty\",[\"i32:1\"]],[\"invoke\",369,0,\"break-br_table-nested-empty\",[\"i32:3\"]],[\"invoke\",370,0,\"break-br_table-nested-empty\",[\"i32:4294967294\"]],[\"invoke\",372,0,\"break-br_table-nested-num\",[\"i32:0\"]],[\"invoke\",375,0,\"break-br_table-nested-num\",[\"i32:1\"]],[\"invoke\",378,0,\"break-br_table-nested-num\",[\"i32:2\"]],[\"invoke\",381,0,\"break-br_table-nested-num\",[\"i32:4294967293\"]],[\"invoke\",384,0,\"break-br_table-nested-num-num\",[\"i32:0\"]],[\"invoke\",388,0,\"break-br_table-nested-num-num\",[\"i32:1\"]],[\"invoke\",392,0,\"break-br_table-nested-num-num\",[\"i32:2\"]],[\"invoke\",396,0,\"break-br_table-nested-num-num\",[\"i32:4294967293\"]],[\"invoke\",401,0,\"large-sig\",[\"i32:0\",\"i64:1\",\"f32:1073741824\",\"f32:1077936128\",\"i32:4\",\"f64:4617315517961601024\",\"f32:1086324736\",\"i32:7\",\"i32:8\",\"i32:9\",\"f32:1092616192\",\"f64:4622382067542392832\",\"f64:4622945017495814144\",\"f64:4623507967449235456\",\"i32:14\",\"i32:15\",\"f32:1098907648\"]],[\"invoke\",414,0,\"init-local-i32\",[]],[\"invoke\",415,0,\"init-local-i64\",[]],[\"invoke\",416,0,\"init-local-f32\",[]],[\"invoke\",417,0,\"init-local-f64\",[]],[\"module\",422,11],[\"module\",459,12],[\"invoke\",483,0,\"f\",[\"i32:42\"]],[\"invoke\",484,0,\"g\",[\"i32:42\"]],[\"invoke\",485,0,\"p\",[]],[\"module\",488,13],[\"invoke\",551,0,\"signature-explicit-reused\",[]],[\"invoke\",552,0,\"signature-implicit-reused\",[]],[\"invoke\",553,0,\"signature-explicit-duplicate\",[]],[\"invoke\",554,0,\"signature-implicit-duplicate\",[]],[\"file\",\"func_ptrs.wast\"],[\"module\",1,14],[\"invoke\",27,0,\"one\",[]],[\"invoke\",28,0,\"two\",[\"i32:13\"]],[\"invoke\",29,0,\"three\",[\"i32:13\"]],[\"invoke\",30,0,\"four\",[\"i32:83\"]],[\"module\",51,15],[\"invoke\",71,0,\"callt\",[\"i32:0\"]],[\"invoke\",72,0,\"callt\",[\"i32:1\"]],[\"invoke\",73,0,\"callt\",[\"i32:2\"]],[\"invoke\",74,0,\"callt\",[\"i32:3\"]],[\"invoke\",75,0,\"callt\",[\"i32:4\"]],[\"invoke\",76,0,\"callt\",[\"i32:5\"]],[\"invoke\",77,0,\"callt\",[\"i32:6\"]],[\"invoke\",78,0,\"callt\",[\"i32:7\"]],[\"invoke\",79,0,\"callt\",[\"i32:100\"]],[\"invoke\",80,0,\"callt\",[\"i32:4294967295\"]],[\"invoke\",82,0,\"callu\",[\"i32:0\"]],[\"invoke\",83,0,\"callu\",[\"i32:1\"]],[\"invoke\",84,0,\"callu\",[\"i32:2\"]],[\"invoke\",85,0,\"callu\",[\"i32:3\"]],[\"invoke\",86,0,\"callu\",[\"i32:4\"]],[\"invoke\",87,0,\"callu\",[\"i32:5\"]],[\"invoke\",88,0,\"callu\",[\"i32:6\"]],[\"invoke\",89,0,\"callu\",[\"i32:7\"]],[\"invoke\",90,0,\"callu\",[\"i32:100\"]],[\"invoke\",91,0,\"callu\",[\"i32:4294967295\"]],[\"module\",93,16],[\"invoke\",105,0,\"callt\",[\"i32:0\"]],[\"invoke\",106,0,\"callt\",[\"i32:1\"]],[\"file\",\"if.wast\"],[\"module\",3,17],[\"invoke\",537,0,\"empty\",[\"i32:0\"]],[\"invoke\",538,0,\"empty\",[\"i32:1\"]],[\"invoke\",539,0,\"empty\",[\"i32:100\"]],[\"invoke\",540,0,\"empty\",[\"i32:4294967294\"]],[\"invoke\",542,0,\"singular\",[\"i32:0\"]],[\"invoke\",543,0,\"singular\",[\"i32:1\"]],[\"invoke\",544,0,\"singular\",[\"i32:10\"]],[\"invoke\",545,0,\"singular\",[\"i32:4294967286\"]],[\"invoke\",547,0,\"multi\",[\"i32:0\"]],[\"invoke\",548,0,\"multi\",[\"i32:1\"]],[\"invoke\",549,0,\"multi\",[\"i32:13\"]],[\"invoke\",550,0,\"multi\",[\"i32:4294967291\"]],[\"invoke\",552,0,\"nested\",[\"i32:0\",\"i32:0\"]],[\"invoke\",553,0,\"nested\",[\"i32:1\",\"i32:0\"]],[\"invoke\",554,0,\"nested\",[\"i32:0\",\"i32:1\"]],[\"invoke\",555,0,\"nested\",[\"i32:3\",\"i32:2\"]],[\"invoke\",556,0,\"nested\",[\"i32:0\",\"i32:4294967196\"]],[\"invoke\",557,0,\"nested\",[\"i32:10\",\"i32:10\"]],[\"invoke\",558,0,\"nested\",[\"i32:0\",\"i32:4294967295\"]],[\"invoke\",559,0,\"nested\",[\"i32:4294967185\",\"i32:4294967294\"]],[\"invoke\",561,0,\"as-select-first\",[\"i32:0\"]],[\"invoke\",562,0,\"as-select-first\",[\"i32:1\"]],[\"invoke\",563,0,\"as-select-mid\",[\"i32:0\"]],[\"invoke\",564,0,\"as-select-mid\",[\"i32:1\"]],[\"invoke\",565,0,\"as-select-last\",[\"i32:0\"]],[\"invoke\",566,0,\"as-select-last\",[\"i32:1\"]],[\"invoke\",568,0,\"as-loop-first\",[\"i32:0\"]],[\"invoke\",569,0,\"as-loop-first\",[\"i32:1\"]],[\"invoke\",570,0,\"as-loop-mid\",[\"i32:0\"]],[\"invoke\",571,0,\"as-loop-mid\",[\"i32:1\"]],[\"invoke\",572,0,\"as-loop-last\",[\"i32:0\"]],[\"invoke\",573,0,\"as-loop-last\",[\"i32:1\"]],[\"invoke\",575,0,\"as-if-condition\",[\"i32:0\"]],[\"invoke\",576,0,\"as-if-condition\",[\"i32:1\"]],[\"invoke\",578,0,\"as-br_if-first\",[\"i32:0\"]],[\"invoke\",579,0,\"as-br_if-first\",[\"i32:1\"]],[\"invoke\",580,0,\"as-br_if-last\",[\"i32:0\"]],[\"invoke\",581,0,\"as-br_if-last\",[\"i32:1\"]],[\"invoke\",583,0,\"as-br_table-first\",[\"i32:0\"]],[\"invoke\",584,0,\"as-br_table-first\",[\"i32:1\"]],[\"invoke\",585,0,\"as-br_table-last\",[\"i32:0\"]],[\"invoke\",586,0,\"as-br_table-last\",[\"i32:1\"]],[\"invoke\",588,0,\"as-call_indirect-first\",[\"i32:0\"]],[\"invoke\",589,0,\"as-call_indirect-first\",[\"i32:1\"]],[\"invoke\",590,0,\"as-call_indirect-mid\",[\"i32:0\"]],[\"invoke\",591,0,\"as-call_indirect-mid\",[\"i32:1\"]],[\"invoke\",592,0,\"as-call_indirect-last\",[\"i32:0\"]],[\"invoke\",593,0,\"as-call_indirect-last\",[\"i32:1\"]],[\"invoke\",595,0,\"as-store-first\",[\"i32:0\"]],[\"invoke\",596,0,\"as-store-first\",[\"i32:1\"]],[\"invoke\",597,0,\"as-store-last\",[\"i32:0\"]],[\"invoke\",598,0,\"as-store-last\",[\"i32:1\"]],[\"invoke\",600,0,\"as-memory.grow-value\",[\"i32:0\"]],[\"invoke\",601,0,\"as-memory.grow-value\",[\"i32:1\"]],[\"invoke\",603,0,\"as-call-value\",[\"i32:0\"]],[\"invoke\",604,0,\"as-call-value\",[\"i32:1\"]],[\"invoke\",606,0,\"as-return-value\",[\"i32:0\"]],[\"invoke\",607,0,\"as-return-value\",[\"i32:1\"]],[\"invoke\",609,0,\"as-drop-operand\",[\"i32:0\"]],[\"invoke\",610,0,\"as-drop-operand\",[\"i32:1\"]],[\"invoke\",612,0,\"as-br-value\",[\"i32:0\"]],[\"invoke\",613,0,\"as-br-value\",[\"i32:1\"]],[\"invoke\",615,0,\"as-local.set-value\",[\"i32:0\"]],[\"invoke\",616,0,\"as-local.set-value\",[\"i32:1\"]],[\"invoke\",618,0,\"as-local.tee-value\",[\"i32:0\"]],[\"invoke\",619,0,\"as-local.tee-value\",[\"i32:1\"]],[\"invoke\",621,0,\"as-global.set-value\",[\"i32:0\"]],[\"invoke\",622,0,\"as-global.set-value\",[\"i32:1\"]],[\"invoke\",624,0,\"as-load-operand\",[\"i32:0\"]],[\"invoke\",625,0,\"as-load-operand\",[\"i32:1\"]],[\"invoke\",627,0,\"as-unary-operand\",[\"i32:0\"]],[\"invoke\",628,0,\"as-unary-operand\",[\"i32:1\"]],[\"invoke\",629,0,\"as-unary-operand\",[\"i32:4294967295\"]],[\"invoke\",631,0,\"as-binary-operand\",[\"i32:0\",\"i32:0\"]],[\"invoke\",632,0,\"as-binary-operand\",[\"i32:0\",\"i32:1\"]],[\"invoke\",633,0,\"as-binary-operand\",[\"i32:1\",\"i32:0\"]],[\"invoke\",634,0,\"as-binary-operand\",[\"i32:1\",\"i32:1\"]],[\"invoke\",636,0,\"as-test-operand\",[\"i32:0\"]],[\"invoke\",637,0,\"as-test-operand\",[\"i32:1\"]],[\"invoke\",639,0,\"as-compare-operand\",[\"i32:0\",\"i32:0\"]],[\"invoke\",640,0,\"as-compare-operand\",[\"i32:0\",\"i32:1\"]],[\"invoke\",641,0,\"as-compare-operand\",[\"i32:1\",\"i32:0\"]],[\"invoke\",642,0,\"as-compare-operand\",[\"i32:1\",\"i32:1\"]],[\"invoke\",644,0,\"as-binary-operands\",[\"i32:0\"]],[\"invoke\",645,0,\"as-binary-operands\",[\"i32:1\"]],[\"invoke\",647,0,\"as-compare-operands\",[\"i32:0\"]],[\"invoke\",648,0,\"as-compare-operands\",[\"i32:1\"]],[\"invoke\",650,0,\"as-mixed-operands\",[\"i32:0\"]],[\"invoke\",651,0,\"as-mixed-operands\",[\"i32:1\"]],[\"invoke\",653,0,\"break-bare\",[]],[\"invoke\",654,0,\"break-value\",[\"i32:1\"]],[\"invoke\",655,0,\"break-value\",[\"i32:0\"]],[\"invoke\",656,0,\"break-multi-value\",[\"i32:0\"]],[\"invoke\",659,0,\"break-multi-value\",[\"i32:1\"]],[\"invoke\",663,0,\"param\",[\"i32:0\"]],[\"invoke\",664,0,\"param\",[\"i32:1\"]],[\"invoke\",665,0,\"params\",[\"i32:0\"]],[\"invoke\",666,0,\"params\",[\"i32:1\"]],[\"invoke\",667,0,\"params-id\",[\"i32:0\"]],[\"invoke\",668,0,\"params-id\",[\"i32:1\"]],[\"invoke\",669,0,\"param-break\",[\"i32:0\"]],[\"invoke\",670,0,\"param-break\",[\"i32:1\"]],[\"invoke\",671,0,\"params-break\",[\"i32:0\"]],[\"invoke\",672,0,\"params-break\",[\"i32:1\"]],[\"invoke\",673,0,\"params-id-break\",[\"i32:0\"]],[\"invoke\",674,0,\"params-id-break\",[\"i32:1\"]],[\"invoke\",676,0,\"effects\",[\"i32:1\"]],[\"invoke\",677,0,\"effects\",[\"i32:0\"]],[\"invoke\",680,0,\"add64_u_with_carry\",[\"i64:0\",\"i64:0\",\"i32:0\"]],[\"invoke\",684,0,\"add64_u_with_carry\",[\"i64:100\",\"i64:124\",\"i32:0\"]],[\"invoke\",688,0,\"add64_u_with_carry\",[\"i64:18446744073709551615\",\"i64:0\",\"i32:0\"]],[\"invoke\",692,0,\"add64_u_with_carry\",[\"i64:18446744073709551615\",\"i64:1\",\"i32:0\"]],[\"invoke\",696,0,\"add64_u_with_carry\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\",\"i32:0\"]],[\"invoke\",700,0,\"add64_u_with_carry\",[\"i64:18446744073709551615\",\"i64:0\",\"i32:1\"]],[\"invoke\",704,0,\"add64_u_with_carry\",[\"i64:18446744073709551615\",\"i64:1\",\"i32:1\"]],[\"invoke\",708,0,\"add64_u_with_carry\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\",\"i32:0\"]],[\"invoke\",713,0,\"add64_u_saturated\",[\"i64:0\",\"i64:0\"]],[\"invoke\",716,0,\"add64_u_saturated\",[\"i64:1230\",\"i64:23\"]],[\"invoke\",719,0,\"add64_u_saturated\",[\"i64:18446744073709551615\",\"i64:0\"]],[\"invoke\",722,0,\"add64_u_saturated\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",725,0,\"add64_u_saturated\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",728,0,\"add64_u_saturated\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",731,0,\"type-use\",[]],[\"invoke\",733,0,\"atypical-condition\",[]],[\"file\",\"labels.wast\"],[\"module\",1,18],[\"invoke\",291,0,\"block\",[]],[\"invoke\",292,0,\"loop1\",[]],[\"invoke\",293,0,\"loop2\",[]],[\"invoke\",294,0,\"loop3\",[]],[\"invoke\",295,0,\"loop4\",[\"i32:8\"]],[\"invoke\",296,0,\"loop5\",[]],[\"invoke\",297,0,\"loop6\",[]],[\"invoke\",298,0,\"if\",[]],[\"invoke\",299,0,\"if2\",[]],[\"invoke\",300,0,\"switch\",[\"i32:0\"]],[\"invoke\",301,0,\"switch\",[\"i32:1\"]],[\"invoke\",302,0,\"switch\",[\"i32:2\"]],[\"invoke\",303,0,\"switch\",[\"i32:3\"]],[\"invoke\",304,0,\"switch\",[\"i32:4\"]],[\"invoke\",305,0,\"switch\",[\"i32:5\"]],[\"invoke\",306,0,\"return\",[\"i32:0\"]],[\"invoke\",307,0,\"return\",[\"i32:1\"]],[\"invoke\",308,0,\"return\",[\"i32:2\"]],[\"invoke\",309,0,\"br_if0\",[]],[\"invoke\",310,0,\"br_if1\",[]],[\"invoke\",311,0,\"br_if2\",[]],[\"invoke\",312,0,\"br_if3\",[]],[\"invoke\",313,0,\"br\",[]],[\"invoke\",314,0,\"shadowing\",[]],[\"invoke\",315,0,\"redefinition\",[]],[\"file\",\"loop.wast\"],[\"module\",3,19],[\"invoke\",430,0,\"empty\",[]],[\"invoke\",431,0,\"singular\",[]],[\"invoke\",432,0,\"multi\",[]],[\"invoke\",433,0,\"nested\",[]],[\"invoke\",434,0,\"deep\",[]],[\"invoke\",436,0,\"as-select-first\",[]],[\"invoke\",437,0,\"as-select-mid\",[]],[\"invoke\",438,0,\"as-select-last\",[]],[\"invoke\",440,0,\"as-if-condition\",[]],[\"invoke\",441,0,\"as-if-then\",[]],[\"invoke\",442,0,\"as-if-else\",[]],[\"invoke\",444,0,\"as-br_if-first\",[]],[\"invoke\",445,0,\"as-br_if-last\",[]],[\"invoke\",447,0,\"as-br_table-first\",[]],[\"invoke\",448,0,\"as-br_table-last\",[]],[\"invoke\",450,0,\"as-call_indirect-first\",[]],[\"invoke\",451,0,\"as-call_indirect-mid\",[]],[\"invoke\",452,0,\"as-call_indirect-last\",[]],[\"invoke\",454,0,\"as-store-first\",[]],[\"invoke\",455,0,\"as-store-last\",[]],[\"invoke\",457,0,\"as-memory.grow-value\",[]],[\"invoke\",458,0,\"as-call-value\",[]],[\"invoke\",459,0,\"as-return-value\",[]],[\"invoke\",460,0,\"as-drop-operand\",[]],[\"invoke\",461,0,\"as-br-value\",[]],[\"invoke\",462,0,\"as-local.set-value\",[]],[\"invoke\",463,0,\"as-local.tee-value\",[]],[\"invoke\",464,0,\"as-global.set-value\",[]],[\"invoke\",465,0,\"as-load-operand\",[]],[\"invoke\",467,0,\"as-unary-operand\",[]],[\"invoke\",468,0,\"as-binary-operand\",[]],[\"invoke\",469,0,\"as-test-operand\",[]],[\"invoke\",470,0,\"as-compare-operand\",[]],[\"invoke\",471,0,\"as-binary-operands\",[]],[\"invoke\",472,0,\"as-compare-operands\",[]],[\"invoke\",473,0,\"as-mixed-operands\",[]],[\"invoke\",475,0,\"break-bare\",[]],[\"invoke\",476,0,\"break-value\",[]],[\"invoke\",477,0,\"break-multi-value\",[]],[\"invoke\",480,0,\"break-repeated\",[]],[\"invoke\",481,0,\"break-inner\",[]],[\"invoke\",483,0,\"param\",[]],[\"invoke\",484,0,\"params\",[]],[\"invoke\",485,0,\"params-id\",[]],[\"invoke\",486,0,\"param-break\",[]],[\"invoke\",487,0,\"params-break\",[]],[\"invoke\",488,0,\"params-id-break\",[]],[\"invoke\",490,0,\"effects\",[]],[\"invoke\",492,0,\"while\",[\"i64:0\"]],[\"invoke\",493,0,\"while\",[\"i64:1\"]],[\"invoke\",494,0,\"while\",[\"i64:2\"]],[\"invoke\",495,0,\"while\",[\"i64:3\"]],[\"invoke\",496,0,\"while\",[\"i64:5\"]],[\"invoke\",497,0,\"while\",[\"i64:20\"]],[\"invoke\",499,0,\"for\",[\"i64:0\"]],[\"invoke\",500,0,\"for\",[\"i64:1\"]],[\"invoke\",501,0,\"for\",[\"i64:2\"]],[\"invoke\",502,0,\"for\",[\"i64:3\"]],[\"invoke\",503,0,\"for\",[\"i64:5\"]],[\"invoke\",504,0,\"for\",[\"i64:20\"]],[\"invoke\",506,0,\"nesting\",[\"f32:0\",\"f32:1088421888\"]],[\"invoke\",507,0,\"nesting\",[\"f32:1088421888\",\"f32:0\"]],[\"invoke\",508,0,\"nesting\",[\"f32:1065353216\",\"f32:1065353216\"]],[\"invoke\",509,0,\"nesting\",[\"f32:1065353216\",\"f32:1073741824\"]],[\"invoke\",510,0,\"nesting\",[\"f32:1065353216\",\"f32:1077936128\"]],[\"invoke\",511,0,\"nesting\",[\"f32:1065353216\",\"f32:1082130432\"]],[\"invoke\",512,0,\"nesting\",[\"f32:1065353216\",\"f32:1120403456\"]],[\"invoke\",513,0,\"nesting\",[\"f32:1065353216\",\"f32:1120534528\"]],[\"invoke\",514,0,\"nesting\",[\"f32:1073741824\",\"f32:1065353216\"]],[\"invoke\",515,0,\"nesting\",[\"f32:1077936128\",\"f32:1065353216\"]],[\"invoke\",516,0,\"nesting\",[\"f32:1092616192\",\"f32:1065353216\"]],[\"invoke\",517,0,\"nesting\",[\"f32:1073741824\",\"f32:1073741824\"]],[\"invoke\",518,0,\"nesting\",[\"f32:1073741824\",\"f32:1077936128\"]],[\"invoke\",519,0,\"nesting\",[\"f32:1088421888\",\"f32:1082130432\"]],[\"invoke\",520,0,\"nesting\",[\"f32:1088421888\",\"f32:1120403456\"]],[\"invoke\",521,0,\"nesting\",[\"f32:1088421888\",\"f32:1120534528\"]],[\"invoke\",523,0,\"type-use\",[]],[\"file\",\"local_get.wast\"],[\"module\",3,20],[\"invoke\",109,0,\"type-local-i32\",[]],[\"invoke\",110,0,\"type-local-i64\",[]],[\"invoke\",111,0,\"type-local-f32\",[]],[\"invoke\",112,0,\"type-local-f64\",[]],[\"invoke\",114,0,\"type-param-i32\",[\"i32:2\"]],[\"invoke\",115,0,\"type-param-i64\",[\"i64:3\"]],[\"invoke\",116,0,\"type-param-f32\",[\"f32:1082969293\"]],[\"invoke\",117,0,\"type-param-f64\",[\"f64:4617878467915022336\"]],[\"invoke\",119,0,\"as-block-value\",[\"i32:6\"]],[\"invoke\",120,0,\"as-loop-value\",[\"i32:7\"]],[\"invoke\",122,0,\"as-br-value\",[\"i32:8\"]],[\"invoke\",123,0,\"as-br_if-value\",[\"i32:9\"]],[\"invoke\",124,0,\"as-br_if-value-cond\",[\"i32:10\"]],[\"invoke\",125,0,\"as-br_table-value\",[\"i32:1\"]],[\"invoke\",127,0,\"as-return-value\",[\"i32:0\"]],[\"invoke\",129,0,\"as-if-then\",[\"i32:1\"]],[\"invoke\",130,0,\"as-if-else\",[\"i32:0\"]],[\"invoke\",133,0,\"type-mixed\",[\"i64:1\",\"f32:1074580685\",\"f64:4614613358185178726\",\"i32:4\",\"i32:5\"]],[\"invoke\",139,0,\"read\",[\"i64:1\",\"f32:1073741824\",\"f64:4614613358185178726\",\"i32:4\",\"i32:5\"]],[\"file\",\"local_set.wast\"],[\"module\",3,21],[\"invoke\",107,0,\"type-local-i32\",[]],[\"invoke\",108,0,\"type-local-i64\",[]],[\"invoke\",109,0,\"type-local-f32\",[]],[\"invoke\",110,0,\"type-local-f64\",[]],[\"invoke\",112,0,\"type-param-i32\",[\"i32:2\"]],[\"invoke\",113,0,\"type-param-i64\",[\"i64:3\"]],[\"invoke\",114,0,\"type-param-f32\",[\"f32:1082969293\"]],[\"invoke\",115,0,\"type-param-f64\",[\"f64:4617878467915022336\"]],[\"invoke\",117,0,\"as-block-value\",[\"i32:0\"]],[\"invoke\",118,0,\"as-loop-value\",[\"i32:0\"]],[\"invoke\",120,0,\"as-br-value\",[\"i32:0\"]],[\"invoke\",121,0,\"as-br_if-value\",[\"i32:0\"]],[\"invoke\",122,0,\"as-br_if-value-cond\",[\"i32:0\"]],[\"invoke\",123,0,\"as-br_table-value\",[\"i32:0\"]],[\"invoke\",125,0,\"as-return-value\",[\"i32:0\"]],[\"invoke\",127,0,\"as-if-then\",[\"i32:1\"]],[\"invoke\",128,0,\"as-if-else\",[\"i32:0\"]],[\"invoke\",131,0,\"type-mixed\",[\"i64:1\",\"f32:1074580685\",\"f64:4614613358185178726\",\"i32:4\",\"i32:5\"]],[\"invoke\",137,0,\"write\",[\"i64:1\",\"f32:1073741824\",\"f64:4614613358185178726\",\"i32:4\",\"i32:5\"]],[\"file\",\"local_tee.wast\"],[\"module\",3,22],[\"invoke\",280,0,\"type-local-i32\",[]],[\"invoke\",281,0,\"type-local-i64\",[]],[\"invoke\",282,0,\"type-local-f32\",[]],[\"invoke\",283,0,\"type-local-f64\",[]],[\"invoke\",285,0,\"type-param-i32\",[\"i32:2\"]],[\"invoke\",286,0,\"type-param-i64\",[\"i64:3\"]],[\"invoke\",287,0,\"type-param-f32\",[\"f32:1082969293\"]],[\"invoke\",288,0,\"type-param-f64\",[\"f64:4617878467915022336\"]],[\"invoke\",290,0,\"as-block-first\",[\"i32:0\"]],[\"invoke\",291,0,\"as-block-mid\",[\"i32:0\"]],[\"invoke\",292,0,\"as-block-last\",[\"i32:0\"]],[\"invoke\",294,0,\"as-loop-first\",[\"i32:0\"]],[\"invoke\",295,0,\"as-loop-mid\",[\"i32:0\"]],[\"invoke\",296,0,\"as-loop-last\",[\"i32:0\"]],[\"invoke\",298,0,\"as-br-value\",[\"i32:0\"]],[\"invoke\",300,0,\"as-br_if-cond\",[\"i32:0\"]],[\"invoke\",301,0,\"as-br_if-value\",[\"i32:0\"]],[\"invoke\",302,0,\"as-br_if-value-cond\",[\"i32:0\"]],[\"invoke\",304,0,\"as-br_table-index\",[\"i32:0\"]],[\"invoke\",305,0,\"as-br_table-value\",[\"i32:0\"]],[\"invoke\",306,0,\"as-br_table-value-index\",[\"i32:0\"]],[\"invoke\",308,0,\"as-return-value\",[\"i32:0\"]],[\"invoke\",310,0,\"as-if-cond\",[\"i32:0\"]],[\"invoke\",311,0,\"as-if-then\",[\"i32:1\"]],[\"invoke\",312,0,\"as-if-else\",[\"i32:0\"]],[\"invoke\",314,0,\"as-select-first\",[\"i32:0\",\"i32:1\"]],[\"invoke\",315,0,\"as-select-second\",[\"i32:0\",\"i32:0\"]],[\"invoke\",316,0,\"as-select-cond\",[\"i32:0\"]],[\"invoke\",318,0,\"as-call-first\",[\"i32:0\"]],[\"invoke\",319,0,\"as-call-mid\",[\"i32:0\"]],[\"invoke\",320,0,\"as-call-last\",[\"i32:0\"]],[\"invoke\",322,0,\"as-call_indirect-first\",[\"i32:0\"]],[\"invoke\",323,0,\"as-call_indirect-mid\",[\"i32:0\"]],[\"invoke\",324,0,\"as-call_indirect-last\",[\"i32:0\"]],[\"invoke\",325,0,\"as-call_indirect-index\",[\"i32:0\"]],[\"invoke\",327,0,\"as-local.set-value\",[]],[\"invoke\",328,0,\"as-local.tee-value\",[\"i32:0\"]],[\"invoke\",329,0,\"as-global.set-value\",[]],[\"invoke\",331,0,\"as-load-address\",[\"i32:0\"]],[\"invoke\",332,0,\"as-loadN-address\",[\"i32:0\"]],[\"invoke\",333,0,\"as-store-address\",[\"i32:0\"]],[\"invoke\",334,0,\"as-store-value\",[\"i32:0\"]],[\"invoke\",335,0,\"as-storeN-address\",[\"i32:0\"]],[\"invoke\",336,0,\"as-storeN-value\",[\"i32:0\"]],[\"invoke\",338,0,\"as-unary-operand\",[\"f32:0\"]],[\"invoke\",339,0,\"as-binary-left\",[\"i32:0\"]],[\"invoke\",340,0,\"as-binary-right\",[\"i32:0\"]],[\"invoke\",341,0,\"as-test-operand\",[\"i32:0\"]],[\"invoke\",342,0,\"as-compare-left\",[\"i32:0\"]],[\"invoke\",343,0,\"as-compare-right\",[\"i32:0\"]],[\"invoke\",344,0,\"as-convert-operand\",[\"i64:0\"]],[\"invoke\",345,0,\"as-memory.grow-size\",[\"i32:0\"]],[\"invoke\",348,0,\"type-mixed\",[\"i64:1\",\"f32:1074580685\",\"f64:4614613358185178726\",\"i32:4\",\"i32:5\"]],[\"invoke\",354,0,\"write\",[\"i64:1\",\"f32:1073741824\",\"f64:4614613358185178726\",\"i32:4\",\"i32:5\"]],[\"invoke\",361,0,\"result\",[\"i64:18446744073709551615\",\"f32:3221225472\",\"f64:13837985395039954534\",\"i32:4294967292\",\"i32:4294967291\"]],[\"file\",\"nop.wast\"],[\"module\",3,23],[\"invoke\",306,0,\"as-func-first\",[]],[\"invoke\",307,0,\"as-func-mid\",[]],[\"invoke\",308,0,\"as-func-last\",[]],[\"invoke\",309,0,\"as-func-everywhere\",[]],[\"invoke\",311,0,\"as-drop-first\",[\"i32:0\"]],[\"invoke\",312,0,\"as-drop-last\",[\"i32:0\"]],[\"invoke\",313,0,\"as-drop-everywhere\",[\"i32:0\"]],[\"invoke\",315,0,\"as-select-first\",[\"i32:3\"]],[\"invoke\",316,0,\"as-select-mid1\",[\"i32:3\"]],[\"invoke\",317,0,\"as-select-mid2\",[\"i32:3\"]],[\"invoke\",318,0,\"as-select-last\",[\"i32:3\"]],[\"invoke\",319,0,\"as-select-everywhere\",[\"i32:3\"]],[\"invoke\",321,0,\"as-block-first\",[]],[\"invoke\",322,0,\"as-block-mid\",[]],[\"invoke\",323,0,\"as-block-last\",[]],[\"invoke\",324,0,\"as-block-everywhere\",[]],[\"invoke\",326,0,\"as-loop-first\",[]],[\"invoke\",327,0,\"as-loop-mid\",[]],[\"invoke\",328,0,\"as-loop-last\",[]],[\"invoke\",329,0,\"as-loop-everywhere\",[]],[\"invoke\",331,0,\"as-if-condition\",[\"i32:0\"]],[\"invoke\",332,0,\"as-if-condition\",[\"i32:4294967295\"]],[\"invoke\",333,0,\"as-if-then\",[\"i32:0\"]],[\"invoke\",334,0,\"as-if-then\",[\"i32:4\"]],[\"invoke\",335,0,\"as-if-else\",[\"i32:0\"]],[\"invoke\",336,0,\"as-if-else\",[\"i32:3\"]],[\"invoke\",338,0,\"as-br-first\",[\"i32:5\"]],[\"invoke\",339,0,\"as-br-last\",[\"i32:6\"]],[\"invoke\",340,0,\"as-br-everywhere\",[\"i32:7\"]],[\"invoke\",342,0,\"as-br_if-first\",[\"i32:4\"]],[\"invoke\",343,0,\"as-br_if-mid\",[\"i32:5\"]],[\"invoke\",344,0,\"as-br_if-last\",[\"i32:6\"]],[\"invoke\",345,0,\"as-br_if-everywhere\",[\"i32:7\"]],[\"invoke\",347,0,\"as-br_table-first\",[\"i32:4\"]],[\"invoke\",348,0,\"as-br_table-mid\",[\"i32:5\"]],[\"invoke\",349,0,\"as-br_table-last\",[\"i32:6\"]],[\"invoke\",350,0,\"as-br_table-everywhere\",[\"i32:7\"]],[\"invoke\",352,0,\"as-return-first\",[\"i32:5\"]],[\"invoke\",353,0,\"as-return-last\",[\"i32:6\"]],[\"invoke\",354,0,\"as-return-everywhere\",[\"i32:7\"]],[\"invoke\",356,0,\"as-call-first\",[\"i32:3\",\"i32:1\",\"i32:2\"]],[\"invoke\",357,0,\"as-call-mid1\",[\"i32:3\",\"i32:1\",\"i32:2\"]],[\"invoke\",358,0,\"as-call-mid2\",[\"i32:0\",\"i32:3\",\"i32:1\"]],[\"invoke\",359,0,\"as-call-last\",[\"i32:10\",\"i32:9\",\"i32:4294967295\"]],[\"invoke\",360,0,\"as-call-everywhere\",[\"i32:2\",\"i32:1\",\"i32:5\"]],[\"invoke\",362,0,\"as-unary-first\",[\"i32:30\"]],[\"invoke\",363,0,\"as-unary-last\",[\"i32:30\"]],[\"invoke\",364,0,\"as-unary-everywhere\",[\"i32:12\"]],[\"invoke\",366,0,\"as-binary-first\",[\"i32:3\"]],[\"invoke\",367,0,\"as-binary-mid\",[\"i32:3\"]],[\"invoke\",368,0,\"as-binary-last\",[\"i32:3\"]],[\"invoke\",369,0,\"as-binary-everywhere\",[\"i32:3\"]],[\"invoke\",371,0,\"as-test-first\",[\"i32:0\"]],[\"invoke\",372,0,\"as-test-last\",[\"i32:0\"]],[\"invoke\",373,0,\"as-test-everywhere\",[\"i32:0\"]],[\"invoke\",375,0,\"as-compare-first\",[\"i32:3\"]],[\"invoke\",376,0,\"as-compare-mid\",[\"i32:3\"]],[\"invoke\",377,0,\"as-compare-last\",[\"i32:3\"]],[\"invoke\",378,0,\"as-compare-everywhere\",[\"i32:3\"]],[\"invoke\",380,0,\"as-memory.grow-first\",[\"i32:0\"]],[\"invoke\",381,0,\"as-memory.grow-last\",[\"i32:2\"]],[\"invoke\",382,0,\"as-memory.grow-everywhere\",[\"i32:12\"]],[\"invoke\",384,0,\"as-call_indirect-first\",[]],[\"invoke\",385,0,\"as-call_indirect-mid1\",[]],[\"invoke\",386,0,\"as-call_indirect-mid2\",[]],[\"invoke\",387,0,\"as-call_indirect-last\",[]],[\"invoke\",388,0,\"as-call_indirect-everywhere\",[]],[\"invoke\",390,0,\"as-local.set-first\",[\"i32:1\"]],[\"invoke\",391,0,\"as-local.set-last\",[\"i32:1\"]],[\"invoke\",392,0,\"as-local.set-everywhere\",[\"i32:1\"]],[\"invoke\",394,0,\"as-local.tee-first\",[\"i32:1\"]],[\"invoke\",395,0,\"as-local.tee-last\",[\"i32:1\"]],[\"invoke\",396,0,\"as-local.tee-everywhere\",[\"i32:1\"]],[\"invoke\",398,0,\"as-global.set-first\",[]],[\"invoke\",399,0,\"as-global.set-last\",[]],[\"invoke\",400,0,\"as-global.set-everywhere\",[]],[\"invoke\",402,0,\"as-load-first\",[\"i32:100\"]],[\"invoke\",403,0,\"as-load-last\",[\"i32:100\"]],[\"invoke\",404,0,\"as-load-everywhere\",[\"i32:100\"]],[\"invoke\",406,0,\"as-store-first\",[\"i32:0\",\"i32:1\"]],[\"invoke\",407,0,\"as-store-mid\",[\"i32:0\",\"i32:2\"]],[\"invoke\",408,0,\"as-store-last\",[\"i32:0\",\"i32:3\"]],[\"invoke\",409,0,\"as-store-everywhere\",[\"i32:0\",\"i32:4\"]],[\"file\",\"return.wast\"],[\"module\",3,24],[\"invoke\",224,0,\"type-i32\",[]],[\"invoke\",225,0,\"type-i64\",[]],[\"invoke\",226,0,\"type-f32\",[]],[\"invoke\",227,0,\"type-f64\",[]],[\"invoke\",229,0,\"type-i32-value\",[]],[\"invoke\",230,0,\"type-i64-value\",[]],[\"invoke\",231,0,\"type-f32-value\",[]],[\"invoke\",232,0,\"type-f64-value\",[]],[\"invoke\",234,0,\"nullary\",[]],[\"invoke\",235,0,\"unary\",[]],[\"invoke\",237,0,\"as-func-first\",[]],[\"invoke\",238,0,\"as-func-mid\",[]],[\"invoke\",239,0,\"as-func-last\",[]],[\"invoke\",240,0,\"as-func-value\",[]],[\"invoke\",242,0,\"as-block-first\",[]],[\"invoke\",243,0,\"as-block-mid\",[]],[\"invoke\",244,0,\"as-block-last\",[]],[\"invoke\",245,0,\"as-block-value\",[]],[\"invoke\",247,0,\"as-loop-first\",[]],[\"invoke\",248,0,\"as-loop-mid\",[]],[\"invoke\",249,0,\"as-loop-last\",[]],[\"invoke\",251,0,\"as-br-value\",[]],[\"invoke\",253,0,\"as-br_if-cond\",[]],[\"invoke\",254,0,\"as-br_if-value\",[]],[\"invoke\",255,0,\"as-br_if-value-cond\",[]],[\"invoke\",257,0,\"as-br_table-index\",[]],[\"invoke\",258,0,\"as-br_table-value\",[]],[\"invoke\",259,0,\"as-br_table-value-index\",[]],[\"invoke\",261,0,\"as-return-value\",[]],[\"invoke\",263,0,\"as-if-cond\",[]],[\"invoke\",264,0,\"as-if-then\",[\"i32:1\",\"i32:6\"]],[\"invoke\",265,0,\"as-if-then\",[\"i32:0\",\"i32:6\"]],[\"invoke\",266,0,\"as-if-else\",[\"i32:0\",\"i32:6\"]],[\"invoke\",267,0,\"as-if-else\",[\"i32:1\",\"i32:6\"]],[\"invoke\",269,0,\"as-select-first\",[\"i32:0\",\"i32:6\"]],[\"invoke\",270,0,\"as-select-first\",[\"i32:1\",\"i32:6\"]],[\"invoke\",271,0,\"as-select-second\",[\"i32:0\",\"i32:6\"]],[\"invoke\",272,0,\"as-select-second\",[\"i32:1\",\"i32:6\"]],[\"invoke\",273,0,\"as-select-cond\",[]],[\"invoke\",275,0,\"as-call-first\",[]],[\"invoke\",276,0,\"as-call-mid\",[]],[\"invoke\",277,0,\"as-call-last\",[]],[\"invoke\",279,0,\"as-call_indirect-func\",[]],[\"invoke\",280,0,\"as-call_indirect-first\",[]],[\"invoke\",281,0,\"as-call_indirect-mid\",[]],[\"invoke\",282,0,\"as-call_indirect-last\",[]],[\"invoke\",284,0,\"as-local.set-value\",[]],[\"invoke\",285,0,\"as-local.tee-value\",[]],[\"invoke\",286,0,\"as-global.set-value\",[]],[\"invoke\",288,0,\"as-load-address\",[]],[\"invoke\",289,0,\"as-loadN-address\",[]],[\"invoke\",291,0,\"as-store-address\",[]],[\"invoke\",292,0,\"as-store-value\",[]],[\"invoke\",293,0,\"as-storeN-address\",[]],[\"invoke\",294,0,\"as-storeN-value\",[]],[\"invoke\",296,0,\"as-unary-operand\",[]],[\"invoke\",298,0,\"as-binary-left\",[]],[\"invoke\",299,0,\"as-binary-right\",[]],[\"invoke\",301,0,\"as-test-operand\",[]],[\"invoke\",303,0,\"as-compare-left\",[]],[\"invoke\",304,0,\"as-compare-right\",[]],[\"invoke\",306,0,\"as-convert-operand\",[]],[\"invoke\",308,0,\"as-memory.grow-size\",[]],[\"file\",\"select.wast\"],[\"module\",1,25],[\"invoke\",183,0,\"select-i32\",[\"i32:1\",\"i32:2\",\"i32:1\"]],[\"invoke\",184,0,\"select-i64\",[\"i64:2\",\"i64:1\",\"i32:1\"]],[\"invoke\",185,0,\"select-f32\",[\"f32:1065353216\",\"f32:1073741824\",\"i32:1\"]],[\"invoke\",186,0,\"select-f64\",[\"f64:4607182418800017408\",\"f64:4611686018427387904\",\"i32:1\"]],[\"invoke\",188,0,\"select-i32\",[\"i32:1\",\"i32:2\",\"i32:0\"]],[\"invoke\",189,0,\"select-i32\",[\"i32:2\",\"i32:1\",\"i32:0\"]],[\"invoke\",190,0,\"select-i64\",[\"i64:2\",\"i64:1\",\"i32:4294967295\"]],[\"invoke\",191,0,\"select-i64\",[\"i64:2\",\"i64:1\",\"i32:4042322160\"]],[\"invoke\",193,0,\"select-f32\",[\"f32:2143289344\",\"f32:1065353216\",\"i32:1\"]],[\"invoke\",195,0,\"select-f32\",[\"f32:2143289344\",\"f32:1065353216\",\"i32:0\"]],[\"invoke\",197,0,\"select-f32\",[\"f32:1073741824\",\"f32:2143289344\",\"i32:1\"]],[\"invoke\",199,0,\"select-f32\",[\"f32:1073741824\",\"f32:2143289344\",\"i32:0\"]],[\"invoke\",202,0,\"select-f64\",[\"f64:9221120237041090560\",\"f64:4607182418800017408\",\"i32:1\"]],[\"invoke\",204,0,\"select-f64\",[\"f64:9221120237041090560\",\"f64:4607182418800017408\",\"i32:0\"]],[\"invoke\",206,0,\"select-f64\",[\"f64:4611686018427387904\",\"f64:9221120237041090560\",\"i32:1\"]],[\"invoke\",208,0,\"select-f64\",[\"f64:4611686018427387904\",\"f64:9221120237041090560\",\"i32:0\"]],[\"invoke\",211,0,\"select-i32-t\",[\"i32:1\",\"i32:2\",\"i32:1\"]],[\"invoke\",212,0,\"select-i64-t\",[\"i64:2\",\"i64:1\",\"i32:1\"]],[\"invoke\",213,0,\"select-f32-t\",[\"f32:1065353216\",\"f32:1073741824\",\"i32:1\"]],[\"invoke\",214,0,\"select-f64-t\",[\"f64:4607182418800017408\",\"f64:4611686018427387904\",\"i32:1\"]],[\"invoke\",215,0,\"select-funcref\",[\"funcref:null\",\"funcref:null\",\"i32:1\"]],[\"invoke\",216,0,\"select-externref\",[\"externref:1\",\"externref:2\",\"i32:1\"]],[\"invoke\",218,0,\"select-i32-t\",[\"i32:1\",\"i32:2\",\"i32:0\"]],[\"invoke\",219,0,\"select-i32-t\",[\"i32:2\",\"i32:1\",\"i32:0\"]],[\"invoke\",220,0,\"select-i64-t\",[\"i64:2\",\"i64:1\",\"i32:4294967295\"]],[\"invoke\",221,0,\"select-i64-t\",[\"i64:2\",\"i64:1\",\"i32:4042322160\"]],[\"invoke\",222,0,\"select-externref\",[\"externref:1\",\"externref:2\",\"i32:0\"]],[\"invoke\",223,0,\"select-externref\",[\"externref:2\",\"externref:1\",\"i32:0\"]],[\"invoke\",225,0,\"select-f32-t\",[\"f32:2143289344\",\"f32:1065353216\",\"i32:1\"]],[\"invoke\",227,0,\"select-f32-t\",[\"f32:2143289344\",\"f32:1065353216\",\"i32:0\"]],[\"invoke\",229,0,\"select-f32-t\",[\"f32:1073741824\",\"f32:2143289344\",\"i32:1\"]],[\"invoke\",231,0,\"select-f32-t\",[\"f32:1073741824\",\"f32:2143289344\",\"i32:0\"]],[\"invoke\",234,0,\"select-f64-t\",[\"f64:9221120237041090560\",\"f64:4607182418800017408\",\"i32:1\"]],[\"invoke\",236,0,\"select-f64-t\",[\"f64:9221120237041090560\",\"f64:4607182418800017408\",\"i32:0\"]],[\"invoke\",238,0,\"select-f64-t\",[\"f64:4611686018427387904\",\"f64:9221120237041090560\",\"i32:1\"]],[\"invoke\",240,0,\"select-f64-t\",[\"f64:4611686018427387904\",\"f64:9221120237041090560\",\"i32:0\"]],[\"invoke\",243,0,\"as-select-first\",[\"i32:0\"]],[\"invoke\",244,0,\"as-select-first\",[\"i32:1\"]],[\"invoke\",245,0,\"as-select-mid\",[\"i32:0\"]],[\"invoke\",246,0,\"as-select-mid\",[\"i32:1\"]],[\"invoke\",247,0,\"as-select-last\",[\"i32:0\"]],[\"invoke\",248,0,\"as-select-last\",[\"i32:1\"]],[\"invoke\",250,0,\"as-loop-first\",[\"i32:0\"]],[\"invoke\",251,0,\"as-loop-first\",[\"i32:1\"]],[\"invoke\",252,0,\"as-loop-mid\",[\"i32:0\"]],[\"invoke\",253,0,\"as-loop-mid\",[\"i32:1\"]],[\"invoke\",254,0,\"as-loop-last\",[\"i32:0\"]],[\"invoke\",255,0,\"as-loop-last\",[\"i32:1\"]],[\"invoke\",257,0,\"as-if-condition\",[\"i32:0\"]],[\"invoke\",258,0,\"as-if-condition\",[\"i32:1\"]],[\"invoke\",259,0,\"as-if-then\",[\"i32:0\"]],[\"invoke\",260,0,\"as-if-then\",[\"i32:1\"]],[\"invoke\",261,0,\"as-if-else\",[\"i32:0\"]],[\"invoke\",262,0,\"as-if-else\",[\"i32:1\"]],[\"invoke\",264,0,\"as-br_if-first\",[\"i32:0\"]],[\"invoke\",265,0,\"as-br_if-first\",[\"i32:1\"]],[\"invoke\",266,0,\"as-br_if-last\",[\"i32:0\"]],[\"invoke\",267,0,\"as-br_if-last\",[\"i32:1\"]],[\"invoke\",269,0,\"as-br_table-first\",[\"i32:0\"]],[\"invoke\",270,0,\"as-br_table-first\",[\"i32:1\"]],[\"invoke\",271,0,\"as-br_table-last\",[\"i32:0\"]],[\"invoke\",272,0,\"as-br_table-last\",[\"i32:1\"]],[\"invoke\",274,0,\"as-call_indirect-first\",[\"i32:0\"]],[\"invoke\",275,0,\"as-call_indirect-first\",[\"i32:1\"]],[\"invoke\",276,0,\"as-call_indirect-mid\",[\"i32:0\"]],[\"invoke\",277,0,\"as-call_indirect-mid\",[\"i32:1\"]],[\"invoke\",278,0,\"as-call_indirect-last\",[\"i32:0\"]],[\"invoke\",279,0,\"as-call_indirect-last\",[\"i32:1\"]],[\"invoke\",281,0,\"as-store-first\",[\"i32:0\"]],[\"invoke\",282,0,\"as-store-first\",[\"i32:1\"]],[\"invoke\",283,0,\"as-store-last\",[\"i32:0\"]],[\"invoke\",284,0,\"as-store-last\",[\"i32:1\"]],[\"invoke\",286,0,\"as-memory.grow-value\",[\"i32:0\"]],[\"invoke\",287,0,\"as-memory.grow-value\",[\"i32:1\"]],[\"invoke\",289,0,\"as-call-value\",[\"i32:0\"]],[\"invoke\",290,0,\"as-call-value\",[\"i32:1\"]],[\"invoke\",291,0,\"as-return-value\",[\"i32:0\"]],[\"invoke\",292,0,\"as-return-value\",[\"i32:1\"]],[\"invoke\",293,0,\"as-drop-operand\",[\"i32:0\"]],[\"invoke\",294,0,\"as-drop-operand\",[\"i32:1\"]],[\"invoke\",295,0,\"as-br-value\",[\"i32:0\"]],[\"invoke\",296,0,\"as-br-value\",[\"i32:1\"]],[\"invoke\",297,0,\"as-local.set-value\",[\"i32:0\"]],[\"invoke\",298,0,\"as-local.set-value\",[\"i32:1\"]],[\"invoke\",299,0,\"as-local.tee-value\",[\"i32:0\"]],[\"invoke\",300,0,\"as-local.tee-value\",[\"i32:1\"]],[\"invoke\",301,0,\"as-global.set-value\",[\"i32:0\"]],[\"invoke\",302,0,\"as-global.set-value\",[\"i32:1\"]],[\"invoke\",303,0,\"as-load-operand\",[\"i32:0\"]],[\"invoke\",304,0,\"as-load-operand\",[\"i32:1\"]],[\"invoke\",306,0,\"as-unary-operand\",[\"i32:0\"]],[\"invoke\",307,0,\"as-unary-operand\",[\"i32:1\"]],[\"invoke\",308,0,\"as-binary-operand\",[\"i32:0\"]],[\"invoke\",309,0,\"as-binary-operand\",[\"i32:1\"]],[\"invoke\",310,0,\"as-test-operand\",[\"i32:0\"]],[\"invoke\",311,0,\"as-test-operand\",[\"i32:1\"]],[\"invoke\",312,0,\"as-compare-left\",[\"i32:0\"]],[\"invoke\",313,0,\"as-compare-left\",[\"i32:1\"]],[\"invoke\",314,0,\"as-compare-right\",[\"i32:0\"]],[\"invoke\",315,0,\"as-compare-right\",[\"i32:1\"]],[\"invoke\",316,0,\"as-convert-operand\",[\"i32:0\"]],[\"invoke\",317,0,\"as-convert-operand\",[\"i32:1\"]],[\"module\",518,26],[\"file\",\"stack.wast\"],[\"module\",1,27],[\"invoke\",146,0,\"fac-expr\",[\"i64:25\"]],[\"invoke\",147,0,\"fac-stack\",[\"i64:25\"]],[\"invoke\",148,0,\"fac-mixed\",[\"i64:25\"]],[\"invoke\",150,0,\"not-quite-a-tree\",[]],[\"invoke\",151,0,\"not-quite-a-tree\",[]],[\"module\",156,28],[\"file\",\"switch.wast\"],[\"module\",1,29],[\"invoke\",120,0,\"stmt\",[\"i32:0\"]],[\"invoke\",121,0,\"stmt\",[\"i32:1\"]],[\"invoke\",122,0,\"stmt\",[\"i32:2\"]],[\"invoke\",123,0,\"stmt\",[\"i32:3\"]],[\"invoke\",124,0,\"stmt\",[\"i32:4\"]],[\"invoke\",125,0,\"stmt\",[\"i32:5\"]],[\"invoke\",126,0,\"stmt\",[\"i32:6\"]],[\"invoke\",127,0,\"stmt\",[\"i32:7\"]],[\"invoke\",128,0,\"stmt\",[\"i32:4294967286\"]],[\"invoke\",130,0,\"expr\",[\"i64:0\"]],[\"invoke\",131,0,\"expr\",[\"i64:1\"]],[\"invoke\",132,0,\"expr\",[\"i64:2\"]],[\"invoke\",133,0,\"expr\",[\"i64:3\"]],[\"invoke\",134,0,\"expr\",[\"i64:6\"]],[\"invoke\",135,0,\"expr\",[\"i64:7\"]],[\"invoke\",136,0,\"expr\",[\"i64:18446744073709551606\"]],[\"invoke\",138,0,\"arg\",[\"i32:0\"]],[\"invoke\",139,0,\"arg\",[\"i32:1\"]],[\"invoke\",140,0,\"arg\",[\"i32:2\"]],[\"invoke\",141,0,\"arg\",[\"i32:3\"]],[\"invoke\",142,0,\"arg\",[\"i32:4\"]],[\"invoke\",143,0,\"arg\",[\"i32:5\"]],[\"invoke\",144,0,\"arg\",[\"i32:6\"]],[\"invoke\",145,0,\"arg\",[\"i32:7\"]],[\"invoke\",146,0,\"arg\",[\"i32:8\"]],[\"invoke\",148,0,\"corner\",[]],[\"file\",\"unreachable.wast\"],[\"module\",3,30],[\"invoke\",221,0,\"type-i32\",[]],[\"invoke\",222,0,\"type-i64\",[]],[\"invoke\",223,0,\"type-f32\",[]],[\"invoke\",224,0,\"type-f64\",[]],[\"invoke\",226,0,\"as-func-first\",[]],[\"invoke\",227,0,\"as-func-mid\",[]],[\"invoke\",228,0,\"as-func-last\",[]],[\"invoke\",229,0,\"as-func-value\",[]],[\"invoke\",231,0,\"as-block-first\",[]],[\"invoke\",232,0,\"as-block-mid\",[]],[\"invoke\",233,0,\"as-block-last\",[]],[\"invoke\",234,0,\"as-block-value\",[]],[\"invoke\",235,0,\"as-block-broke\",[]],[\"invoke\",237,0,\"as-loop-first\",[]],[\"invoke\",238,0,\"as-loop-mid\",[]],[\"invoke\",239,0,\"as-loop-last\",[]],[\"invoke\",240,0,\"as-loop-broke\",[]],[\"invoke\",242,0,\"as-br-value\",[]],[\"invoke\",244,0,\"as-br_if-cond\",[]],[\"invoke\",245,0,\"as-br_if-value\",[]],[\"invoke\",246,0,\"as-br_if-value-cond\",[]],[\"invoke\",248,0,\"as-br_table-index\",[]],[\"invoke\",249,0,\"as-br_table-value\",[]],[\"invoke\",250,0,\"as-br_table-value-2\",[]],[\"invoke\",251,0,\"as-br_table-value-index\",[]],[\"invoke\",252,0,\"as-br_table-value-and-index\",[]],[\"invoke\",254,0,\"as-return-value\",[]],[\"invoke\",256,0,\"as-if-cond\",[]],[\"invoke\",257,0,\"as-if-then\",[\"i32:1\",\"i32:6\"]],[\"invoke\",258,0,\"as-if-then\",[\"i32:0\",\"i32:6\"]],[\"invoke\",259,0,\"as-if-else\",[\"i32:0\",\"i32:6\"]],[\"invoke\",260,0,\"as-if-else\",[\"i32:1\",\"i32:6\"]],[\"invoke\",261,0,\"as-if-then-no-else\",[\"i32:1\",\"i32:6\"]],[\"invoke\",262,0,\"as-if-then-no-else\",[\"i32:0\",\"i32:6\"]],[\"invoke\",264,0,\"as-select-first\",[\"i32:0\",\"i32:6\"]],[\"invoke\",265,0,\"as-select-first\",[\"i32:1\",\"i32:6\"]],[\"invoke\",266,0,\"as-select-second\",[\"i32:0\",\"i32:6\"]],[\"invoke\",267,0,\"as-select-second\",[\"i32:1\",\"i32:6\"]],[\"invoke\",268,0,\"as-select-cond\",[]],[\"invoke\",270,0,\"as-call-first\",[]],[\"invoke\",271,0,\"as-call-mid\",[]],[\"invoke\",272,0,\"as-call-last\",[]],[\"invoke\",274,0,\"as-call_indirect-func\",[]],[\"invoke\",275,0,\"as-call_indirect-first\",[]],[\"invoke\",276,0,\"as-call_indirect-mid\",[]],[\"invoke\",277,0,\"as-call_indirect-last\",[]],[\"invoke\",279,0,\"as-local.set-value\",[]],[\"invoke\",280,0,\"as-local.tee-value\",[]],[\"invoke\",281,0,\"as-global.set-value\",[]],[\"invoke\",283,0,\"as-load-address\",[]],[\"invoke\",284,0,\"as-loadN-address\",[]],[\"invoke\",286,0,\"as-store-address\",[]],[\"invoke\",287,0,\"as-store-value\",[]],[\"invoke\",288,0,\"as-storeN-address\",[]],[\"invoke\",289,0,\"as-storeN-value\",[]],[\"invoke\",291,0,\"as-unary-operand\",[]],[\"invoke\",293,0,\"as-binary-left\",[]],[\"invoke\",294,0,\"as-binary-right\",[]],[\"invoke\",296,0,\"as-test-operand\",[]],[\"invoke\",298,0,\"as-compare-left\",[]],[\"invoke\",299,0,\"as-compare-right\",[]],[\"invoke\",301,0,\"as-convert-operand\",[]],[\"invoke\",303,0,\"as-memory.grow-size\",[]],[\"file\",\"unwind.wast\"],[\"module\",3,31],[\"invoke\",212,0,\"func-unwind-by-unreachable\",[]],[\"invoke\",213,0,\"func-unwind-by-br\",[]],[\"invoke\",214,0,\"func-unwind-by-br-value\",[]],[\"invoke\",215,0,\"func-unwind-by-br_if\",[]],[\"invoke\",216,0,\"func-unwind-by-br_if-value\",[]],[\"invoke\",217,0,\"func-unwind-by-br_table\",[]],[\"invoke\",218,0,\"func-unwind-by-br_table-value\",[]],[\"invoke\",219,0,\"func-unwind-by-return\",[]],[\"invoke\",221,0,\"block-unwind-by-unreachable\",[]],[\"invoke\",222,0,\"block-unwind-by-br\",[]],[\"invoke\",223,0,\"block-unwind-by-br-value\",[]],[\"invoke\",224,0,\"block-unwind-by-br_if\",[]],[\"invoke\",225,0,\"block-unwind-by-br_if-value\",[]],[\"invoke\",226,0,\"block-unwind-by-br_table\",[]],[\"invoke\",227,0,\"block-unwind-by-br_table-value\",[]],[\"invoke\",228,0,\"block-unwind-by-return\",[]],[\"invoke\",230,0,\"block-nested-unwind-by-unreachable\",[]],[\"invoke\",231,0,\"block-nested-unwind-by-br\",[]],[\"invoke\",232,0,\"block-nested-unwind-by-br-value\",[]],[\"invoke\",233,0,\"block-nested-unwind-by-br_if\",[]],[\"invoke\",234,0,\"block-nested-unwind-by-br_if-value\",[]],[\"invoke\",235,0,\"block-nested-unwind-by-br_table\",[]],[\"invoke\",236,0,\"block-nested-unwind-by-br_table-value\",[]],[\"invoke\",237,0,\"block-nested-unwind-by-return\",[]],[\"invoke\",239,0,\"unary-after-unreachable\",[]],[\"invoke\",240,0,\"unary-after-br\",[]],[\"invoke\",241,0,\"unary-after-br_if\",[]],[\"invoke\",242,0,\"unary-after-br_table\",[]],[\"invoke\",243,0,\"unary-after-return\",[]],[\"invoke\",245,0,\"binary-after-unreachable\",[]],[\"invoke\",246,0,\"binary-after-br\",[]],[\"invoke\",247,0,\"binary-after-br_if\",[]],[\"invoke\",248,0,\"binary-after-br_table\",[]],[\"invoke\",249,0,\"binary-after-return\",[]],[\"invoke\",251,0,\"select-after-unreachable\",[]],[\"invoke\",252,0,\"select-after-br\",[]],[\"invoke\",253,0,\"select-after-br_if\",[]],[\"invoke\",254,0,\"select-after-br_table\",[]],[\"invoke\",255,0,\"select-after-return\",[]],[\"invoke\",257,0,\"block-value-after-unreachable\",[]],[\"invoke\",258,0,\"block-value-after-br\",[]],[\"invoke\",259,0,\"block-value-after-br_if\",[]],[\"invoke\",260,0,\"block-value-after-br_table\",[]],[\"invoke\",261,0,\"block-value-after-return\",[]],[\"invoke\",263,0,\"loop-value-after-unreachable\",[]],[\"invoke\",264,0,\"loop-value-after-br\",[]],[\"invoke\",265,0,\"loop-value-after-br_if\",[]],[\"invoke\",266,0,\"loop-value-after-br_table\",[]],[\"invoke\",267,0,\"loop-value-after-return\",[]],[\"file\",\"left-to-right.wast\"],[\"module\",1,32],[\"invoke\",181,0,\"i32_add\",[]],[\"invoke\",181,0,\"i64_add\",[]],[\"invoke\",182,0,\"i32_sub\",[]],[\"invoke\",182,0,\"i64_sub\",[]],[\"invoke\",183,0,\"i32_mul\",[]],[\"invoke\",183,0,\"i64_mul\",[]],[\"invoke\",184,0,\"i32_div_s\",[]],[\"invoke\",184,0,\"i64_div_s\",[]],[\"invoke\",185,0,\"i32_div_u\",[]],[\"invoke\",185,0,\"i64_div_u\",[]],[\"invoke\",186,0,\"i32_rem_s\",[]],[\"invoke\",186,0,\"i64_rem_s\",[]],[\"invoke\",187,0,\"i32_rem_u\",[]],[\"invoke\",187,0,\"i64_rem_u\",[]],[\"invoke\",188,0,\"i32_and\",[]],[\"invoke\",188,0,\"i64_and\",[]],[\"invoke\",189,0,\"i32_or\",[]],[\"invoke\",189,0,\"i64_or\",[]],[\"invoke\",190,0,\"i32_xor\",[]],[\"invoke\",190,0,\"i64_xor\",[]],[\"invoke\",191,0,\"i32_shl\",[]],[\"invoke\",191,0,\"i64_shl\",[]],[\"invoke\",192,0,\"i32_shr_u\",[]],[\"invoke\",192,0,\"i64_shr_u\",[]],[\"invoke\",193,0,\"i32_shr_s\",[]],[\"invoke\",193,0,\"i64_shr_s\",[]],[\"invoke\",194,0,\"i32_eq\",[]],[\"invoke\",194,0,\"i64_eq\",[]],[\"invoke\",195,0,\"i32_ne\",[]],[\"invoke\",195,0,\"i64_ne\",[]],[\"invoke\",196,0,\"i32_lt_s\",[]],[\"invoke\",196,0,\"i64_lt_s\",[]],[\"invoke\",197,0,\"i32_le_s\",[]],[\"invoke\",197,0,\"i64_le_s\",[]],[\"invoke\",198,0,\"i32_lt_u\",[]],[\"invoke\",198,0,\"i64_lt_u\",[]],[\"invoke\",199,0,\"i32_le_u\",[]],[\"invoke\",199,0,\"i64_le_u\",[]],[\"invoke\",200,0,\"i32_gt_s\",[]],[\"invoke\",200,0,\"i64_gt_s\",[]],[\"invoke\",201,0,\"i32_ge_s\",[]],[\"invoke\",201,0,\"i64_ge_s\",[]],[\"invoke\",202,0,\"i32_gt_u\",[]],[\"invoke\",202,0,\"i64_gt_u\",[]],[\"invoke\",203,0,\"i32_ge_u\",[]],[\"invoke\",203,0,\"i64_ge_u\",[]],[\"invoke\",204,0,\"i32_store\",[]],[\"invoke\",204,0,\"i64_store\",[]],[\"invoke\",205,0,\"i32_store8\",[]],[\"invoke\",205,0,\"i64_store8\",[]],[\"invoke\",206,0,\"i32_store16\",[]],[\"invoke\",206,0,\"i64_store16\",[]],[\"invoke\",207,0,\"i64_store32\",[]],[\"invoke\",208,0,\"i32_call\",[]],[\"invoke\",208,0,\"i64_call\",[]],[\"invoke\",209,0,\"i32_call_indirect\",[]],[\"invoke\",210,0,\"i64_call_indirect\",[]],[\"invoke\",211,0,\"i32_select\",[]],[\"invoke\",211,0,\"i64_select\",[]],[\"invoke\",213,0,\"f32_add\",[]],[\"invoke\",213,0,\"f64_add\",[]],[\"invoke\",214,0,\"f32_sub\",[]],[\"invoke\",214,0,\"f64_sub\",[]],[\"invoke\",215,0,\"f32_mul\",[]],[\"invoke\",215,0,\"f64_mul\",[]],[\"invoke\",216,0,\"f32_div\",[]],[\"invoke\",216,0,\"f64_div\",[]],[\"invoke\",217,0,\"f32_copysign\",[]],[\"invoke\",217,0,\"f64_copysign\",[]],[\"invoke\",218,0,\"f32_eq\",[]],[\"invoke\",218,0,\"f64_eq\",[]],[\"invoke\",219,0,\"f32_ne\",[]],[\"invoke\",219,0,\"f64_ne\",[]],[\"invoke\",220,0,\"f32_lt\",[]],[\"invoke\",220,0,\"f64_lt\",[]],[\"invoke\",221,0,\"f32_le\",[]],[\"invoke\",221,0,\"f64_le\",[]],[\"invoke\",222,0,\"f32_gt\",[]],[\"invoke\",222,0,\"f64_gt\",[]],[\"invoke\",223,0,\"f32_ge\",[]],[\"invoke\",223,0,\"f64_ge\",[]],[\"invoke\",224,0,\"f32_min\",[]],[\"invoke\",224,0,\"f64_min\",[]],[\"invoke\",225,0,\"f32_max\",[]],[\"invoke\",225,0,\"f64_max\",[]],[\"invoke\",226,0,\"f32_store\",[]],[\"invoke\",226,0,\"f64_store\",[]],[\"invoke\",227,0,\"f32_call\",[]],[\"invoke\",227,0,\"f64_call\",[]],[\"invoke\",228,0,\"f32_call_indirect\",[]],[\"invoke\",229,0,\"f64_call_indirect\",[]],[\"invoke\",230,0,\"f32_select\",[]],[\"invoke\",230,0,\"f64_select\",[]],[\"invoke\",232,0,\"br_if\",[]],[\"invoke\",233,0,\"br_table\",[]],[\"file\",\"global.wast\"],[\"module\",3,33],[\"invoke\",196,0,\"get-a\",[]],[\"invoke\",197,0,\"get-b\",[]],[\"invoke\",198,0,\"get-r\",[]],[\"invoke\",199,0,\"get-mr\",[]],[\"invoke\",200,0,\"get-x\",[]],[\"invoke\",201,0,\"get-y\",[]],[\"invoke\",202,0,\"get-z1\",[]],[\"invoke\",203,0,\"get-z2\",[]],[\"invoke\",205,0,\"get-3\",[]],[\"invoke\",206,0,\"get-4\",[]],[\"invoke\",207,0,\"get-7\",[]],[\"invoke\",208,0,\"get-8\",[]],[\"invoke\",210,0,\"set-x\",[\"i32:6\"]],[\"invoke\",211,0,\"set-y\",[\"i64:7\"]],[\"invoke\",213,0,\"set-7\",[\"f32:1090519040\"]],[\"invoke\",214,0,\"set-8\",[\"f64:4621256167635550208\"]],[\"invoke\",216,0,\"get-x\",[]],[\"invoke\",217,0,\"get-y\",[]],[\"invoke\",218,0,\"get-7\",[]],[\"invoke\",219,0,\"get-8\",[]],[\"invoke\",221,0,\"set-7\",[\"f32:1090519040\"]],[\"invoke\",222,0,\"set-8\",[\"f64:4621256167635550208\"]],[\"invoke\",223,0,\"set-mr\",[\"externref:10\"]],[\"invoke\",225,0,\"get-x\",[]],[\"invoke\",226,0,\"get-y\",[]],[\"invoke\",227,0,\"get-7\",[]],[\"invoke\",228,0,\"get-8\",[]],[\"invoke\",229,0,\"get-mr\",[]],[\"invoke\",231,0,\"as-select-first\",[]],[\"invoke\",232,0,\"as-select-mid\",[]],[\"invoke\",233,0,\"as-select-last\",[]],[\"invoke\",235,0,\"as-loop-first\",[]],[\"invoke\",236,0,\"as-loop-mid\",[]],[\"invoke\",237,0,\"as-loop-last\",[]],[\"invoke\",239,0,\"as-if-condition\",[]],[\"invoke\",240,0,\"as-if-then\",[]],[\"invoke\",241,0,\"as-if-else\",[]],[\"invoke\",243,0,\"as-br_if-first\",[]],[\"invoke\",244,0,\"as-br_if-last\",[]],[\"invoke\",246,0,\"as-br_table-first\",[]],[\"invoke\",247,0,\"as-br_table-last\",[]],[\"invoke\",249,0,\"as-call_indirect-first\",[]],[\"invoke\",250,0,\"as-call_indirect-mid\",[]],[\"invoke\",251,0,\"as-call_indirect-last\",[]],[\"invoke\",253,0,\"as-store-first\",[]],[\"invoke\",254,0,\"as-store-last\",[]],[\"invoke\",255,0,\"as-load-operand\",[]],[\"invoke\",256,0,\"as-memory.grow-value\",[]],[\"invoke\",258,0,\"as-call-value\",[]],[\"invoke\",260,0,\"as-return-value\",[]],[\"invoke\",261,0,\"as-drop-operand\",[]],[\"invoke\",262,0,\"as-br-value\",[]],[\"invoke\",264,0,\"as-local.set-value\",[\"i32:1\"]],[\"invoke\",265,0,\"as-local.tee-value\",[\"i32:1\"]],[\"invoke\",266,0,\"as-global.set-value\",[]],[\"invoke\",268,0,\"as-unary-operand\",[]],[\"invoke\",269,0,\"as-binary-operand\",[]],[\"invoke\",270,0,\"as-compare-operand\",[]],[\"module\",283,34],[\"module\",284,34],[\"module\",375,35],[\"module\",405,36],[\"file\",\"start.wast\"],[\"module\",21,37],[\"invoke\",45,0,\"get\",[]],[\"invoke\",46,0,\"inc\",[]],[\"invoke\",47,0,\"get\",[]],[\"invoke\",48,0,\"inc\",[]],[\"invoke\",49,0,\"get\",[]],[\"module\",51,37],[\"invoke\",74,0,\"get\",[]],[\"invoke\",75,0,\"inc\",[]],[\"invoke\",76,0,\"get\",[]],[\"invoke\",77,0,\"inc\",[]],[\"invoke\",78,0,\"get\",[]],[\"module\",80,38],[\"module\",86,39],[\"module\",92,40],[\"instantiate\",98,41]]"; diff --git a/tests/corpus/webassembly-spec-control/main.mjs b/tests/corpus/webassembly-spec-control/main.mjs new file mode 100644 index 000000000..2451a5a1c --- /dev/null +++ b/tests/corpus/webassembly-spec-control/main.mjs @@ -0,0 +1,5 @@ +// Executes WebAssembly spec tests (26 files); see tests/wasm-spec/runner.mjs. +import { run } from "../../wasm-spec/runner.mjs"; +import { modules, script } from "./data.mjs"; + +run(modules, script); diff --git a/tests/corpus/webassembly-spec-float/data.mjs b/tests/corpus/webassembly-spec-float/data.mjs new file mode 100644 index 000000000..814d702e3 --- /dev/null +++ b/tests/corpus/webassembly-spec-float/data.mjs @@ -0,0 +1,113 @@ +/* Generated by tests/wasm-spec/gen.mjs from the WebAssembly 2.0 core test + * suite (WebAssembly/spec wg-2.0, Apache-2.0) with wabt 1.0.37 wast2json: + * f32.wast, f64.wast, f32_cmp.wast, f64_cmp.wast, f32_bitwise.wast, f64_bitwise.wast, float_exprs.wast, float_literals.wast, float_misc.wast. Do not edit. */ +export const modules = [ + "AGFzbQEAAAABDAJgAn19AX1gAX0BfQMMCwAAAAABAAABAQEBB00LA2FkZAAAA3N1YgABA211bAACA2RpdgADBHNxcnQABANtaW4ABQNtYXgABgRjZWlsAAcFZmxvb3IACAV0cnVuYwAJB25lYXJlc3QACgpPCwcAIAAgAZILBwAgACABkwsHACAAIAGUCwcAIAAgAZULBQAgAJELBwAgACABlgsHACAAIAGXCwUAIACNCwUAIACOCwUAIACPCwUAIACQCw==", + "AGFzbQEAAAABDAJgAnx8AXxgAXwBfAMMCwAAAAABAAABAQEBB00LA2FkZAAAA3N1YgABA211bAACA2RpdgADBHNxcnQABANtaW4ABQNtYXgABgRjZWlsAAcFZmxvb3IACAV0cnVuYwAJB25lYXJlc3QACgpPCwcAIAAgAaALBwAgACABoQsHACAAIAGiCwcAIAAgAaMLBQAgAJ8LBwAgACABpAsHACAAIAGlCwUAIACbCwUAIACcCwUAIACdCwUAIACeCw==", + "AGFzbQEAAAABBwFgAn19AX8DBwYAAAAAAAAHHwYCZXEAAAJuZQABAmx0AAICbGUAAwJndAAEAmdlAAUKMQYHACAAIAFbCwcAIAAgAVwLBwAgACABXQsHACAAIAFfCwcAIAAgAV4LBwAgACABYAs=", + "AGFzbQEAAAABBwFgAnx8AX8DBwYAAAAAAAAHHwYCZXEAAAJuZQABAmx0AAICbGUAAwJndAAEAmdlAAUKMQYHACAAIAFhCwcAIAAgAWILBwAgACABYwsHACAAIAFlCwcAIAAgAWQLBwAgACABZgs=", + "AGFzbQEAAAABDAJgAX0BfWACfX0BfQMEAwAAAQcYAwNhYnMAAANuZWcAAQhjb3B5c2lnbgACChUDBQAgAIsLBQAgAIwLBwAgACABmAs=", + "AGFzbQEAAAABDAJgAXwBfGACfHwBfAMEAwAAAQcYAwNhYnMAAANuZWcAAQhjb3B5c2lnbgACChUDBQAgAJkLBQAgAJoLBwAgACABpgs=", + "AGFzbQEAAAABCAFgA3x8fAF8AwIBAAcWARJmNjQubm9fY29udHJhY3Rpb24AAAoMAQoAIAAgAaIgAqAL", + "AGFzbQEAAAABDwJgA319fQF9YAN8fHwBfAMDAgABBxsCCmYzMi5ub19mbWEAAApmNjQubm9fZm1hAAEKFwIKACAAIAGUIAKSCwoAIAAgAaIgAqAL", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfYWRkX3plcm8AABRmNjQubm9fZm9sZF9hZGRfemVybwABChsCCgAgAEMAAAAAkgsOACAARAAAAAAAAAAAoAs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfemVyb19zdWIAABRmNjQubm9fZm9sZF96ZXJvX3N1YgABChsCCgBDAAAAACAAkwsOAEQAAAAAAAAAACAAoQs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfc3ViX3plcm8AABRmNjQubm9fZm9sZF9zdWJfemVybwABChsCCgAgAEMAAAAAkwsOACAARAAAAAAAAAAAoQs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfbXVsX3plcm8AABRmNjQubm9fZm9sZF9tdWxfemVybwABChsCCgAgAEMAAAAAlAsOACAARAAAAAAAAAAAogs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLQITZjMyLm5vX2ZvbGRfbXVsX29uZQAAE2Y2NC5ub19mb2xkX211bF9vbmUAAQobAgoAIABDAACAP5QLDgAgAEQAAAAAAADwP6IL", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfemVyb19kaXYAABRmNjQubm9fZm9sZF96ZXJvX2RpdgABChsCCgBDAAAAACAAlQsOAEQAAAAAAAAAACAAows=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLQITZjMyLm5vX2ZvbGRfZGl2X29uZQAAE2Y2NC5ub19mb2xkX2Rpdl9vbmUAAQobAgoAIABDAACAP5ULDgAgAEQAAAAAAADwP6ML", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfZGl2X25lZzEAABRmNjQubm9fZm9sZF9kaXZfbmVnMQABChsCCgAgAEMAAIC/lQsOACAARAAAAAAAAPC/ows=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfbmVnMF9zdWIAABRmNjQubm9fZm9sZF9uZWcwX3N1YgABChsCCgBDAAAAgCAAkwsOAEQAAAAAAAAAgCAAoQs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfbmVnMV9tdWwAABRmNjQubm9fZm9sZF9uZWcxX211bAABChsCCgBDAACAvyAAlAsOAEQAAAAAAADwvyAAogs=", + "AGFzbQEAAAABCwJgAX0Bf2ABfAF/AwMCAAEHLQITZjMyLm5vX2ZvbGRfZXFfc2VsZgAAE2Y2NC5ub19mb2xkX2VxX3NlbGYAAQoRAgcAIAAgAFsLBwAgACAAYQs=", + "AGFzbQEAAAABCwJgAX0Bf2ABfAF/AwMCAAEHLQITZjMyLm5vX2ZvbGRfbmVfc2VsZgAAE2Y2NC5ub19mb2xkX25lX3NlbGYAAQoRAgcAIAAgAFwLBwAgACAAYgs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfc3ViX3NlbGYAABRmNjQubm9fZm9sZF9zdWJfc2VsZgABChECBwAgACAAkwsHACAAIAChCw==", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfZGl2X3NlbGYAABRmNjQubm9fZm9sZF9kaXZfc2VsZgABChECBwAgACAAlQsHACAAIACjCw==", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHKQIRZjMyLm5vX2ZvbGRfZGl2XzMAABFmNjQubm9fZm9sZF9kaXZfMwABChsCCgAgAEMAAEBAlQsOACAARAAAAAAAAAhAows=", + "AGFzbQEAAAABDwJgA319fQF9YAN8fHwBfAMDAgABByECDWYzMi5ub19mYWN0b3IAAA1mNjQubm9fZmFjdG9yAAEKHQINACAAIAKUIAEgApSSCw0AIAAgAqIgASACoqAL", + "AGFzbQEAAAABDwJgA319fQF9YAN8fHwBfAMDAgABBykCEWYzMi5ub19kaXN0cmlidXRlAAARZjY0Lm5vX2Rpc3RyaWJ1dGUAAQoXAgoAIAAgAZIgApQLCgAgACABoCACogs=", + "AGFzbQEAAAABDwJgA319fQF9YAN8fHwBfAMDAgABBzMCFmYzMi5ub19yZWdyb3VwX2Rpdl9tdWwAABZmNjQubm9fcmVncm91cF9kaXZfbXVsAAEKFwIKACAAIAEgApWUCwoAIAAgASACo6IL", + "AGFzbQEAAAABDwJgA319fQF9YAN8fHwBfAMDAgABBzMCFmYzMi5ub19yZWdyb3VwX211bF9kaXYAABZmNjQubm9fcmVncm91cF9tdWxfZGl2AAEKFwIKACAAIAGUIAKVCwoAIAAgAaIgAqML", + "AGFzbQEAAAABEQJgBH19fX0BfWAEfHx8fAF8AwMCAAEHMwIWZjMyLm5vX3JlYXNzb2NpYXRlX2FkZAAAFmY2NC5ub19yZWFzc29jaWF0ZV9hZGQAAQodAg0AIAAgAZIgApIgA5ILDQAgACABoCACoCADoAs=", + "AGFzbQEAAAABEQJgBH19fX0BfWAEfHx8fAF8AwMCAAEHMwIWZjMyLm5vX3JlYXNzb2NpYXRlX211bAAAFmY2NC5ub19yZWFzc29jaWF0ZV9tdWwAAQodAg0AIAAgAZQgApQgA5QLDQAgACABoiACoiADogs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHKQIRZjMyLm5vX2ZvbGRfZGl2XzAAABFmNjQubm9fZm9sZF9kaXZfMAABChsCCgAgAEMAAAAAlQsOACAARAAAAAAAAAAAows=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfZGl2X25lZzAAABRmNjQubm9fZm9sZF9kaXZfbmVnMAABChsCCgAgAEMAAACAlQsOACAARAAAAAAAAACAows=", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQcvAhRmMzIubm9fZm9sZF90b19oeXBvdAAAFGY2NC5ub19mb2xkX3RvX2h5cG90AAEKHwIOACAAIACUIAEgAZSSkQsOACAAIACiIAEgAaKgnws=", + "AGFzbQEAAAABBgFgAX0BfQMCAQAHIQEdZjMyLm5vX2FwcHJveGltYXRlX3JlY2lwcm9jYWwAAAoMAQoAQwAAgD8gAJUL", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHRAIiZjMyLm5vX2FwcHJveGltYXRlX3JlY2lwcm9jYWxfc3FydAAAG2Y2NC5ub19mdXNlX3JlY2lwcm9jYWxfc3FydAABCh0CCwBDAACAPyAAkZULDwBEAAAAAAAA8D8gAJ+jCw==", + "AGFzbQEAAAABBgFgAX0BfQMCAQAHJgEiZjMyLm5vX2FwcHJveGltYXRlX3NxcnRfcmVjaXByb2NhbAAACg0BCwBDAACAPyAAlZEL", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQdRBBFpMzIubm9fZm9sZF9mMzJfcwAAEWkzMi5ub19mb2xkX2YzMl91AAERaTY0Lm5vX2ZvbGRfZjY0X3MAAhFpNjQubm9fZm9sZF9mNjRfdQADCh0EBgAgALKoCwYAIACzqQsGACAAubALBgAgALqxCw==", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQctAhNmMzIubm9fZm9sZF9hZGRfc3ViAAATZjY0Lm5vX2ZvbGRfYWRkX3N1YgABChcCCgAgACABkiABkwsKACAAIAGgIAGhCw==", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQctAhNmMzIubm9fZm9sZF9zdWJfYWRkAAATZjY0Lm5vX2ZvbGRfc3ViX2FkZAABChcCCgAgACABkyABkgsKACAAIAGhIAGgCw==", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQctAhNmMzIubm9fZm9sZF9tdWxfZGl2AAATZjY0Lm5vX2ZvbGRfbXVsX2RpdgABChcCCgAgACABlCABlQsKACAAIAGiIAGjCw==", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQctAhNmMzIubm9fZm9sZF9kaXZfbXVsAAATZjY0Lm5vX2ZvbGRfZGl2X211bAABChcCCgAgACABlSABlAsKACAAIAGjIAGiCw==", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHMQIVZjMyLm5vX2ZvbGRfZGl2Ml9tdWwyAAAVZjY0Lm5vX2ZvbGRfZGl2Ml9tdWwyAAEKKwIQACAAQwAAAECVQwAAAECUCxgAIABEAAAAAAAAAECjRAAAAAAAAABAogs=", + "AGFzbQEAAAABBgFgAXwBfAMCAQAHGgEWbm9fZm9sZF9kZW1vdGVfcHJvbW90ZQAACggBBgAgALa7Cw==", + "AGFzbQEAAAABBgFgAX0BfQMCAQAHGgEWbm9fZm9sZF9wcm9tb3RlX2RlbW90ZQAACggBBgAgALu2Cw==", + "AGFzbQEAAAABDQJgAnx9AX1gAn18AX0DAwIAAQc2AhNub19kZW1vdGVfbWl4ZWRfYWRkAAAcbm9fZGVtb3RlX21peGVkX2FkZF9jb21tdXRlZAABChUCCQAgACABu6C2CwkAIAC7IAGgtgs=", + "AGFzbQEAAAABDQJgAnx9AX1gAn18AX0DAwIAAQc2AhNub19kZW1vdGVfbWl4ZWRfc3ViAAAcbm9fZGVtb3RlX21peGVkX3N1Yl9jb21tdXRlZAABChUCCQAgACABu6G2CwkAIAC7IAGhtgs=", + "AGFzbQEAAAABDQJgAnx9AX1gAn18AX0DAwIAAQc2AhNub19kZW1vdGVfbWl4ZWRfbXVsAAAcbm9fZGVtb3RlX21peGVkX211bF9jb21tdXRlZAABChUCCQAgACABu6K2CwkAIAC7IAGitgs=", + "AGFzbQEAAAABDQJgAnx9AX1gAn18AX0DAwIAAQc2AhNub19kZW1vdGVfbWl4ZWRfZGl2AAAcbm9fZGVtb3RlX21peGVkX2Rpdl9jb21tdXRlZAABChUCCQAgACABu6O2CwkAIAC7IAGjtgs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AxEQAAAAAAEBAQEAAAAAAQEBAQfBBBAhZjMyLmkzMi5ub19mb2xkX3RydW5jX3NfY29udmVydF9zAAAhZjMyLmkzMi5ub19mb2xkX3RydW5jX3VfY29udmVydF9zAAEhZjMyLmkzMi5ub19mb2xkX3RydW5jX3NfY29udmVydF91AAIhZjMyLmkzMi5ub19mb2xkX3RydW5jX3VfY29udmVydF91AAMhZjY0LmkzMi5ub19mb2xkX3RydW5jX3NfY29udmVydF9zAAQhZjY0LmkzMi5ub19mb2xkX3RydW5jX3VfY29udmVydF9zAAUhZjY0LmkzMi5ub19mb2xkX3RydW5jX3NfY29udmVydF91AAYhZjY0LmkzMi5ub19mb2xkX3RydW5jX3VfY29udmVydF91AAchZjMyLmk2NC5ub19mb2xkX3RydW5jX3NfY29udmVydF9zAAghZjMyLmk2NC5ub19mb2xkX3RydW5jX3VfY29udmVydF9zAAkhZjMyLmk2NC5ub19mb2xkX3RydW5jX3NfY29udmVydF91AAohZjMyLmk2NC5ub19mb2xkX3RydW5jX3VfY29udmVydF91AAshZjY0Lmk2NC5ub19mb2xkX3RydW5jX3NfY29udmVydF9zAAwhZjY0Lmk2NC5ub19mb2xkX3RydW5jX3VfY29udmVydF9zAA0hZjY0Lmk2NC5ub19mb2xkX3RydW5jX3NfY29udmVydF91AA4hZjY0Lmk2NC5ub19mb2xkX3RydW5jX3VfY29udmVydF91AA8KcRAGACAAqLILBgAgAKmyCwYAIACoswsGACAAqbMLBgAgAKq3CwYAIACrtwsGACAAqrgLBgAgAKu4CwYAIACutAsGACAAr7QLBgAgAK61CwYAIACvtQsGACAAsLkLBgAgALG5CwYAIACwugsGACAAsboL", + "AGFzbQEAAAABCwJgAn99AGABfwF9AwQDAAABBQQBAQEBBxYDBGluaXQAAANydW4AAQVjaGVjawACCjkDCQAgACABOAIACyUBAX8CQANAIAIgAioCACABlTgCACACQQRqIQIgAiAASQ0ACwsLBwAgACoCAAs=", + "AGFzbQEAAAABCwJgAn98AGABfwF8AwQDAAABBQQBAQEBBxYDBGluaXQAAANydW4AAQVjaGVjawACCjkDCQAgACABOQMACyUBAX8CQANAIAIgAisDACABozkDACACQQhqIQIgAiAASQ0ACwsLBwAgACsDAAs=", + "AGFzbQEAAAABDQJgAn19AX9gAnx8AX8DCQgAAAAAAQEBAQdRCAdmMzIudWx0AAAHZjMyLnVsZQABB2YzMi51Z3QAAgdmMzIudWdlAAMHZjY0LnVsdAAEB2Y2NC51bGUABQdmNjQudWd0AAYHZjY0LnVnZQAHCkkICAAgACABYEULCAAgACABXkULCAAgACABX0ULCAAgACABXUULCAAgACABZkULCAAgACABZEULCAAgACABZUULCAAgACABY0UL", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDCQgAAAAAAQEBAQfBAQgVZjMyLm5vX2ZvbGRfbHRfc2VsZWN0AAAVZjMyLm5vX2ZvbGRfbGVfc2VsZWN0AAEVZjMyLm5vX2ZvbGRfZ3Rfc2VsZWN0AAIVZjMyLm5vX2ZvbGRfZ2Vfc2VsZWN0AAMVZjY0Lm5vX2ZvbGRfbHRfc2VsZWN0AAQVZjY0Lm5vX2ZvbGRfbGVfc2VsZWN0AAUVZjY0Lm5vX2ZvbGRfZ3Rfc2VsZWN0AAYVZjY0Lm5vX2ZvbGRfZ2Vfc2VsZWN0AAcKaQgMACAAIAEgACABXRsLDAAgACABIAAgAV8bCwwAIAAgASAAIAFeGwsMACAAIAEgACABYBsLDAAgACABIAAgAWMbCwwAIAAgASAAIAFlGwsMACAAIAEgACABZBsLDAAgACABIAAgAWYbCw==", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDCQgAAAAAAQEBAQehAQgRZjMyLm5vX2ZvbGRfbHRfaWYAABFmMzIubm9fZm9sZF9sZV9pZgABEWYzMi5ub19mb2xkX2d0X2lmAAIRZjMyLm5vX2ZvbGRfZ2VfaWYAAxFmNjQubm9fZm9sZF9sdF9pZgAEEWY2NC5ub19mb2xkX2xlX2lmAAURZjY0Lm5vX2ZvbGRfZ3RfaWYABhFmNjQubm9fZm9sZF9nZV9pZgAHCoEBCA8AIAAgAV0EfSAABSABCwsPACAAIAFfBH0gAAUgAQsLDwAgACABXgR9IAAFIAELCw8AIAAgAWAEfSAABSABCwsPACAAIAFjBHwgAAUgAQsLDwAgACABZQR8IAAFIAELCw8AIAAgAWQEfCAABSABCwsPACAAIAFmBHwgAAUgAQsL", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwkIAAAAAAEBAQEH+QEIHGYzMi5ub19mb2xkX2x0X3NlbGVjdF90b19hYnMAABxmMzIubm9fZm9sZF9sZV9zZWxlY3RfdG9fYWJzAAEcZjMyLm5vX2ZvbGRfZ3Rfc2VsZWN0X3RvX2FicwACHGYzMi5ub19mb2xkX2dlX3NlbGVjdF90b19hYnMAAxxmNjQubm9fZm9sZF9sdF9zZWxlY3RfdG9fYWJzAAQcZjY0Lm5vX2ZvbGRfbGVfc2VsZWN0X3RvX2FicwAFHGY2NC5ub19mb2xkX2d0X3NlbGVjdF90b19hYnMABhxmNjQubm9fZm9sZF9nZV9zZWxlY3RfdG9fYWJzAAcKmQEIEAAgAIwgACAAQwAAAABdGwsQACAAjCAAIABDAAAAgF8bCxAAIAAgAIwgAEMAAACAXhsLEAAgACAAjCAAQwAAAABgGwsUACAAmiAAIABEAAAAAAAAAABjGwsUACAAmiAAIABEAAAAAAAAAIBlGwsUACAAIACaIABEAAAAAAAAAIBkGwsUACAAIACaIABEAAAAAAAAAABmGws=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwkIAAAAAAEBAQEH2QEIGGYzMi5ub19mb2xkX2x0X2lmX3RvX2FicwAAGGYzMi5ub19mb2xkX2xlX2lmX3RvX2FicwABGGYzMi5ub19mb2xkX2d0X2lmX3RvX2FicwACGGYzMi5ub19mb2xkX2dlX2lmX3RvX2FicwADGGY2NC5ub19mb2xkX2x0X2lmX3RvX2FicwAEGGY2NC5ub19mb2xkX2xlX2lmX3RvX2FicwAFGGY2NC5ub19mb2xkX2d0X2lmX3RvX2FicwAGGGY2NC5ub19mb2xkX2dlX2lmX3RvX2FicwAHCrEBCBMAIABDAAAAAF0EfSAAjAUgAAsLEwAgAEMAAACAXwR9IACMBSAACwsTACAAQwAAAIBeBH0gAAUgAIwLCxMAIABDAAAAAGAEfSAABSAAjAsLFwAgAEQAAAAAAAAAAGMEfCAAmgUgAAsLFwAgAEQAAAAAAAAAgGUEfCAAmgUgAAsLFwAgAEQAAAAAAAAAgGQEfCAABSAAmgsLFwAgAEQAAAAAAAAAAGYEfCAABSAAmgsL", + "AGFzbQEAAAABCQJgAAF9YAABfAMDAgABBzcCGGYzMi5pbmNvcnJlY3RfY29ycmVjdGlvbgAAGGY2NC5pbmNvcnJlY3RfY29ycmVjdGlvbgABCkUCGQBDvp+qP0PNzJw/kkO+n6o/k0PNzJw/kwspAESHFtnO91P1P0SamZmZmZnzP6BEhxbZzvdT9T+hRJqZmZmZmfM/oQs=", + "AGFzbQEAAAABBQFgAAF9AwIBAAcNAQljYWxjdWxhdGUAAApKAUgBBX1DAEAcQyEAQ1VVUEMhAUMVx+M/IQIgAYwgAJQgACAClCABk5UhAyABjCAAlCAAIAKUIAGTlSEEAkAgAyAEWw0AAAsgBAs=", + "AGFzbQEAAAABBQFgAAF8AwIBAAcNAQljYWxjdWxhdGUAAApWAVQBBXxEAAAAAACIY0AhAERLBquqqgpqQCEBRJbQ46riePw/IQIgAZogAKIgACACoiABoaMhAyABmiAAoiAAIAKiIAGhoyEEAkAgAyAEYQ0AAAsgBAs=", + "AGFzbQEAAAABBgFgAX0BfQMCAQAHEAEMbGx2bV9wcjI2NzQ2AAAKEgEQAEMAAAAAQwAAAIAgAJOTCw==", + "AGFzbQEAAAABBgFgAX8BfQMCAQAHEAEMbGx2bV9wcjI3MTUzAAAKFAESACAAQf////8AcbJDAAAAy5IL", + "AGFzbQEAAAABBwFgAn9/AX0DAgEABxABDGxsdm1fcHIyNzAzNgAAChcBFQAgAEHL/4d0crIgAUGAgJAHcbKSCw==", + "AGFzbQEAAAABFwNgBHx8fHwBfGADfHx8AXxgA319fQF9AwQDAAECByIDCHRoZXBhc3QwAAAIdGhlcGFzdDEAAQh0aGVwYXN0MgACCiUDDQAgACABoiACIAOiowsKACAAIAGiIAKhCwoAIAAgAZQgApQL", + "AGFzbQEAAAABBgFgAX0BfQMCAQAHCwEHaW52ZXJzZQAACgwBCgBDAACAPyAAlQs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHJwIQZjMyX3NxcnRfbWludXNfMgAAEGY2NF9zcXJ0X21pbnVzXzIAAQodAgsAIACRQwAAAECTCw8AIACfRAAAAAAAAABAoQs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHNQIXZjMyLm5vX2ZvbGRfcmVjaXBfcmVjaXAAABdmNjQubm9fZm9sZF9yZWNpcF9yZWNpcAABCisCEABDAACAP0MAAIA/IACVlQsYAEQAAAAAAADwP0QAAAAAAADwPyAAo6ML", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQc7AhpmMzIubm9fYWxnZWJyYWljX2ZhY3RvcmluZwAAGmY2NC5ub19hbGdlYnJhaWNfZmFjdG9yaW5nAAEKHQINACAAIAGSIAAgAZOUCw0AIAAgAaAgACABoaIL", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQc7AhpmMzIubm9fYWxnZWJyYWljX2ZhY3RvcmluZwAAGmY2NC5ub19hbGdlYnJhaWNfZmFjdG9yaW5nAAEKHQINACAAIACUIAEgAZSTCw0AIAAgAKIgASABoqEL", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfQMDAgABBQQBAQEBByACEWYzMi5zaW1wbGVfeDRfc3VtAAAIZjMyLmxvYWQAAQpuAmQBCH0gACoCACEDIAAqAgQhBCAAKgIIIQUgACoCDCEGIAEqAgAhByABKgIEIQggASoCCCEJIAEqAgwhCiACIAMgB5I4AgAgAiAEIAiSOAIEIAIgBSAJkjgCCCACIAYgCpI4AgwLBwAgACoCAAsLNgEAQQALMAEAAAABAACAAQAAAAEAAIABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfAMDAgABBQQBAQEBByACEWY2NC5zaW1wbGVfeDRfc3VtAAAIZjY0LmxvYWQAAQpuAmQBCHwgACsDACEDIAArAwghBCAAKwMQIQUgACsDGCEGIAErAwAhByABKwMIIQggASsDECEJIAErAxghCiACIAMgB6A5AwAgAiAEIAigOQMIIAIgBSAJoDkDECACIAYgCqA5AxgLBwAgACsDAAsLZgEAQQALYAEAAAAAAAAAAQAAAAAAAIABAAAAAAAAAAEAAAAAAACAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "AGFzbQEAAAABBwFgAn9/AX0DAwIAAAUEAQEBAQchAg1mMzIua2FoYW5fc3VtAAANZjMyLnBsYWluX3N1bQABCmICNwEDfQJAA0AgAyAAKgIAIASTIgSSIgIgA5MgBJMhBCAAQQRqIQAgAiEDIAFBf2oiAQ0ACwsgAgsoAQF9AkADQCACIAAqAgCSIQIgAEEEaiEAIAFBf2ohASABDQALCyACCwuHCAEAQQALgAjExVckpYTIC224Sy7ydhccykpWHhtucSJdFx5uv80UXMchVVE5nB+yUfCjk9fBLK5+qCg6ASH0CliT+EJ3n4M5al+69wrYUWo0yq3GNA7YJtxMMxztKZCoeA/RznYxI4O4NejyRLDTofy7MuGwumlECdbZff8uwFo2FDMUPqn6h22LvM6dp/3E6YU/3dfhGKZQJnJuP3MP+BKTIzRhdhJIwJsFk+usht6UPlXojOjd5PyVR75WAyEgTOa/e/Z/1bpzHMEUj8QnlrO9M/94QV/AWs72Z25zmhdmcAP4ziejUrKfO7/7ru3TWvg3V/D1bu+xTXA9VKcBmoUISJH1nQxgh1vZVB5RbYiOCIylcTpWCGdGj48TKizsLB+0YitvQQrEZUKiMWssfT67dayGlzDZSM2aH1bExuQSwJ377gKMzhzyHqF4I9vEHkkD03HMCFDF2Fzt1bVlrLXJIdLJKXbe8DAaWzzyO9s6OYI6FghvqPG+aWmZcaYF0xSTKhbyLxHHfiC7kUTu+OQBU8C5f/C/8AOcbbHfokQBbWtxK1yzIRlGXo/bkdN8eGu3EgCP672K9dQuxMEe33NjWUdJAwq3zyTPnA5Eep4U+0K/nTkwnqCrL9GunmqDQ+NVfYW/Y4r4lhAf/m3nIhvhaUaKRMjI+QwrGQelAj7yMBCahYpf74FFoHexAxBzS66YnUe/mi061Q8DZuM9U9lAzh9vMi8hKyMhbGLUpz6ozigxLQA9Z16voM8u0rlrhOtpCDxiNr4S/TZ/iD6tvAvAQcRQtuNQMejO4pZlVZwWRuawLTrogQWwvzT3vBAc+8w88YWXQp/rFI08v9cXiEmdiyuyOoPRTwSeoQ+tCJ1Ur9GCw+wyLwKPBSEtorfk9G8ugSsLnPzL/nQC+dv08+oAqOzRmXQm3dY01SWxRt2cqnH1YLCIyOALWVolTylm+eMu/una5RhPJ2L0zqQhlXTHV2Qnmkz9VH1hzsOsh0ac+v8JynmXZyR0ytQhgyYlGRI3ZBnlZeB0dY7dyO90x9ghK3kEUUZlYANd+tj0ZaSeXSPa14qSgKTeeDzxV0Jtzckv1aSeq0D0yxvXo8r866cBspppTkabGE7deaeqplI5Hu8wzJu9W+5MIW0wAHKwRl8Iz8W54D7CswzcjmTeGUJ5z0PqQ12OiPerFdw/yGcg27hksUcf3vLLP1mf2EaQ3K4vIvniMYnZnBxM06lKV4Scn+osPK48wx6L5U4XASXbNEZfFeoFDHzZRYwZ0HOKlhbdRPkFt1txsOYhNl91iZFzdat9rtNz7DfG6lV17+qri3sR3G0asmrEJc+q459JSYnLN5sKpwFgcNy3yIPhQvW+rWKUrY2h", + "AGFzbQEAAAABBwFgAn9/AXwDAwIAAAUEAQEBAQchAg1mNjQua2FoYW5fc3VtAAANZjY0LnBsYWluX3N1bQABCmICNwEDfAJAA0AgAyAAKwMAIAShIgSgIgIgA6EgBKEhBCAAQQhqIQAgAiEDIAFBf2oiAQ0ACwsgAgsoAQF8AkADQCACIAArAwCgIQIgAEEIaiEAIAFBf2ohASABDQALCyACCwuHEAEAQQALgBATBYRCXaIsxkPbVanN2lXjc/xY1rrVAP2DNUKIixNdOEpHDXJzoRrvxEUXV9jJRuCNbOE3cMiDW1VeWi1zHlbI4W1pFHgKilpkOgnHqIfF8NNd5gP8k74mytapkWC9sO2u9zB+kjpvp1mOqn2/Z1gqVPhO/u01WKZRv0LlS2YnJG1/Qi0okhjsCK7nVdqxpmWlclBHG7ipVNemBlsPQliDiheCxhBDoMAubbxahVNyf61EvDA8VbIkmnQ6nuHYD3D8qTrNk0vs437dXSfN+KCdHBHAVy79yBMyzDoafaNBVe3DgkkqBB7vc7kuLuNf9N/msjMMOT9vRGoDwUK5+rHI7aVYmX/ttHKeeev7Q4JFqruV0v8onvahrZXWVZUNb2ARx3g+SfJ+SPSicdATjrPemVLjRXTqdg4bKsjuFAHEUFs2PO+6cqKmCPh7Np357wvHVi1c8J1d3vy4rQ9kDpcVMibCMeYFHu/LFxttFQt0XdMu+GuGtLpzUlOZqXYgRclAgGsU7aH6gEbmJtLmmMRXv8QcpJB6NpQUuhWJbuacN4z03hIiXaF5UGcNPXrp1Koufyp6MD3qXRJI/uEYzaRXooc+tpqL29qdeJzPjbFPkLQ04J32yv5MO3htClwYn2G53bTgD3bgG2kNXlhzcF4OLaF9/yDrkTSSrDhyKh+OcS5q8a/HJ3DZxFf30jwduPDwZM/crr6jzD4ifU5pIWMX7QMCVJoPUE4TWjWhIqTfhsJ0eRa4aWmgUl0RZL1bk/xpoPQT0IFR3foMFcN6yWJ6qR3J5lqzW5cCPGQiEjwikGQtMFRMtKEiCVciXo44KwKorva+DSvyA636EAFxdyowApX2AD7QxI00GVAhCrxQ2jww1joxlI06/u8UV51LkwCWJAxv/bwjdgJs61JygBF+gDoTEjgdOEmVQCeKRHvo3G2MjI48tbMYDvYIGoRBNf+LuJNA6uFRHYmljUJoKeovwXpS65BdTdaA49d1SM7t0wEcjVullA14z/EGEy+YAqRtLmzy1XQpiUz5A/XHGK168Gj4XNZZh27WPwa+hiDjQZEi826L8GgcV6f8sHyemQuWGolf5g18CFGgomeaRwCTa/ko8GjbYvHgZSxTM+CnyhFCMPavAcFlPTIBb6suvtOLvhTD/+z78PnFDAVvAQlr4zQxDB9mpkK8GodJFhaMsJANNIwK4QleEKRrVszwybvcuFzO9syNdX6zB4gEL7ReyeNKI3MZYmyaA3ZEhpxg/Ntyjyeg3bPF2v/57Gqxe9PPUDfJengM5Dq29eb0mG5CfTVzi0XAVpfNbc7PrTGzw1T679XA9GpfVOdJPjMKMDj92QX/pT9XRhS1kRfKa5gjemWzbAK0zHldWNiz1ZSu9G11ZfeSv35HTDzu26zxMl37b0EcNMiDT8JYAb4FPmYWpgRtXU+GCSeCJRLNOs3Oa7zKrCib7molhp5FcMbSvTt9QuUnr8cd9IHIs3aKqDajrirmGOE2Iq32JXKwOYsBmiJ7hMMtX3KkmKwVcOfUGOJ90jB8MwjNysQihYh1gcZKdFiN4Oisxat1WvQoEvAYRVLyl7KTQW+Nf9tw+6NdH6eNmCArIp86AbWLG9LLFAMOFBTSGVofzl7NgXkVAcrec3SMViCfdy0lFvZhUR2kjpuYpcbsqEVXgll4DZC031Gww4KUzLNTCRVtlmw6QEe3SnoFL6EejJ2gIIj7Uref8/O7X+eKYachsaz6CaqkbLwkgLoq6WX/cP/M+mWHdvPFFc7L6EIxAAyRV9ngnTVUJK2k2PkIZ2PIz4HdkKLXxAdK5hBvZ+cn1CNZGPKonV/YlDCqVIZPh52CtSbKppa/z1X5nTcBGUhDxZRs83SXWEw8nQjoBMJYMHbhoPjq6cWuz3ieqQyss0RC4LxdG5xJWEocGUnBOur16zuBqUtwDMyeGtMvt1IvIDvrZFEdoC2yPr4ThUiSMi7bXKHnjEWRNQEKk8LrCc7z0iIk0IzMHZ04yE3jgsxkFQYt5wEvq7u1BEySHHrWP+hfMRUM3OQxtMQlPiqqAJ7I5SF6fynxwK8dXuhjOa34fmzIxX/CqJcnCtn0IWrqAwn795Y7g3lffEswn1Y13rRz1JXwFMN0Lw2jHU6NMSSzGoSFYlp7PBQ5F+Zt6zfCAFhbC+M8imLh+DVLVuKHYIu+pziRd1SpWiQlkJ+lQnfzXDnf/3QHdqHNH2ILgYForwXBwH8m7sCRo2p9KWFFJ+VXiNwNlwQaM6lEitoCEEU/jlWmdoxN4/GJg8jQ+JtQd59H30ycZg2qGLhfT8QBztyErEaeaeF2RWthieRdlLsRg5942ArS9X5dQ+q8EPE6yeJk+1Nl0Me0p/vUBVMl0M0piABWJSR9XbTzQZ/ptfeuZCzjyW3VhDpyErh62RsJ6DjaJk8EzgNxbopEe1yBWZzS5MO6WablKKePmuTVTrnKf8t1uCtDPrMVRrGlvJ2eOBXxvRshqvGCAJX8p3dHOaczQ5LXUkBLBoGKoL3xa5mEQlviO8VeElwoTbYOTshc6AGKxefknULuXZzE6+toCSeSlZoRVHPEEoD7ff7FCGB/NkHgELrWK2zxtBf+JjTjS/io45G+Tyr82oG45/7VJlBH8xplMoHgBbhPMjEmAEpTl8LDDi6hJlSrBY5WL32vIoRopYuX9qT9qMx1QZaG/Sc9KYaNf0zUjnNB9B7i3Vgnl86clM96BC/c7Q==", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQctAhNmMzIubm9fZm9sZF9uZWdfc3ViAAATZjY0Lm5vX2ZvbGRfbmVnX3N1YgABChMCCAAgACABk4wLCAAgACABoZoL", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQctAhNmMzIubm9fZm9sZF9uZWdfYWRkAAATZjY0Lm5vX2ZvbGRfbmVnX2FkZAABChMCCAAgACABkowLCAAgACABoJoL", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQc1AhdmMzIubm9fZm9sZF9hZGRfbmVnX25lZwAAF2Y2NC5ub19mb2xkX2FkZF9uZWdfbmVnAAEKFQIJACAAjCABjJILCQAgAJogAZqgCw==", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHLQITZjMyLm5vX2ZvbGRfYWRkX25lZwAAE2Y2NC5ub19mb2xkX2FkZF9uZWcAAQoTAggAIACMIACSCwgAIACaIACgCw==", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHMwIWZjMyLm5vX2ZvbGRfNnhfdmlhX2FkZAAAFmY2NC5ub19mb2xkXzZ4X3ZpYV9hZGQAAQopAhMAIAAgAJIgAJIgAJIgAJIgAJILEwAgACAAoCAAoCAAoCAAoCAAoAs=", + "AGFzbQEAAAABDwJgA319fQF9YAN8fHwBfAMDAgABBy0CE2YzMi5ub19mb2xkX2Rpdl9kaXYAABNmNjQubm9fZm9sZF9kaXZfZGl2AAEKFwIKACAAIAGVIAKVCwoAIAAgAaMgAqML", + "AGFzbQEAAAABEQJgBH19fX0BfWAEfHx8fAF8AwMCAAEHLwIUZjMyLm5vX2ZvbGRfbXVsX2RpdnMAABRmNjQubm9fZm9sZF9tdWxfZGl2cwABCh0CDQAgACABlSACIAOVlAsNACAAIAGjIAIgA6OiCw==", + "AGFzbQEAAAABDwJgA319fQF9YAN8fHwBfAMDAgABBy8CFGYzMi5ub19mb2xkX2FkZF9kaXZzAAAUZjY0Lm5vX2ZvbGRfYWRkX2RpdnMAAQodAg0AIAAgApUgASAClZILDQAgACACoyABIAKjoAs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHNQIXZjMyLm5vX2ZvbGRfc3FydF9zcXVhcmUAABdmNjQubm9fZm9sZF9zcXJ0X3NxdWFyZQABChMCCAAgACAAlJELCAAgACAAop8L", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQcxAhVmMzIubm9fZm9sZF9tdWxfc3FydHMAABVmNjQubm9fZm9sZF9tdWxfc3FydHMAAQoVAgkAIACRIAGRlAsJACAAnyABn6IL", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQcxAhVmMzIubm9fZm9sZF9kaXZfc3FydHMAABVmNjQubm9fZm9sZF9kaXZfc3FydHMAAQoVAgkAIACRIAGRlQsJACAAnyABn6ML", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQc3AhhmMzIubm9fZm9sZF9tdWxfc3FydF9kaXYAABhmNjQubm9fZm9sZF9tdWxfc3FydF9kaXYAAQoZAgsAIAAgAZGUIAGVCwsAIAAgAZ+iIAGjCw==", + "AGFzbQEAAAABDwJgA319fQF9YAN8fHwBfAMDAgABB00CI2YzMi5ub19mbHVzaF9pbnRlcm1lZGlhdGVfc3Vibm9ybWFsAAAjZjY0Lm5vX2ZsdXNoX2ludGVybWVkaWF0ZV9zdWJub3JtYWwAAQoXAgoAIAAgAZQgApQLCgAgACABoiACogs=", + "AGFzbQEAAAABEwNgAn19AX9gAnx8AX9gAnx9AX0DCAcAAAABAQECB38HD2YzMi5yZWNvZGluZ19lcQAAD2YzMi5yZWNvZGluZ19sZQABD2YzMi5yZWNvZGluZ19sdAACD2Y2NC5yZWNvZGluZ19lcQADD2Y2NC5yZWNvZGluZ19sZQAED2Y2NC5yZWNvZGluZ19sdAAFD3JlY29kaW5nX2RlbW90ZQAGCkwHCgAgACABlCAAWwsKACAAIAGUIABfCwoAIAAgAZQgAF0LCgAgACABoiAAYQsKACAAIAGiIABlCwoAIAAgAaIgAGMLCAAgALYgAZQL", + "AGFzbQEAAAABDwJgA319fQF/YAN8fHwBfwMDAgABB0ECHWYzMi5ub19leHRlbmRlZF9wcmVjaXNpb25fZGl2AAAdZjY0Lm5vX2V4dGVuZGVkX3ByZWNpc2lvbl9kaXYAAQoXAgoAIAAgAZUgAlsLCgAgACABoyACYQs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHNQIXZjMyLm5vX2Rpc3RyaWJ1dGVfZXhhY3QAABdmNjQubm9fZGlzdHJpYnV0ZV9leGFjdAABCjECEwBDAAAAwSAAlEMAAABBIACUkgsbAEQAAAAAAAAgwCAAokQAAAAAAAAgQCAAoqAL", + "AGFzbQEAAAABKQZgAX0BfWAEfX19fQF9YAN9fX0BfWABfAF8YAR8fHx8AXxgA3x8fAF8AwsKAAECAgEDBAUFBAe1AQoIZjMyLnNxcnQAAA9mMzIueGtjZF9zcXJ0XzIAAQ9mMzIueGtjZF9zcXJ0XzMAAg9mMzIueGtjZF9zcXJ0XzUAAxZmMzIueGtjZF9iZXR0ZXJfc3FydF81AAQIZjY0LnNxcnQABQ9mNjQueGtjZF9zcXJ0XzIABg9mNjQueGtjZF9zcXJ0XzMABw9mNjQueGtjZF9zcXJ0XzUACBZmNjQueGtjZF9iZXR0ZXJfc3FydF81AAkKiQEKBQAgAJELEAAgACABlSACIAMgApOVkgsKACAAIAGUIAKVCw0AIAAgAZUgAiAAlZILEwAgACABIAKUkiADIAEgApSTlQsFACAAnwsQACAAIAGjIAIgAyACoaOgCwoAIAAgAaIgAqMLDQAgACABoyACIACjoAsTACAAIAEgAqKgIAMgASACoqGjCw==", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQcpAhFmMzIuY29tcHV0ZV9yYWRpeAAAEWY2NC5jb21wdXRlX3JhZGl4AAEKnQECQwADQCAAIACSIgBDAACAP5IgAJNDAACAv5JDAAAAAFsNAAsDQCAAIAFDAACAP5IiAZIgAJMgAZNDAAAAAFwNAAsgAQtXAANAIAAgAKAiAEQAAAAAAADwP6AgAKFEAAAAAAAA8L+gRAAAAAAAAAAAYQ0ACwNAIAAgAUQAAAAAAADwP6AiAaAgAKEgAaFEAAAAAAAAAABiDQALIAEL", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQc3AhhmMzIubm9fZm9sZF9zdWIxX211bF9hZGQAABhmNjQubm9fZm9sZF9zdWIxX211bF9hZGQAAQonAhAAIABDAACAP5MgAZQgAZILFAAgAEQAAAAAAADwP6EgAaIgAaAL", + "AGFzbQEAAAABDwJgA319fQF/YAN8fHwBfwMFBAAAAQEHiQEEH2YzMi5ub19mb2xkX2FkZF9sZV9tb25vdG9uaWNpdHkAAB9mMzIubm9fZm9sZF9hZGRfZ2VfbW9ub3RvbmljaXR5AAEfZjY0Lm5vX2ZvbGRfYWRkX2xlX21vbm90b25pY2l0eQACH2Y2NC5ub19mb2xkX2FkZF9nZV9tb25vdG9uaWNpdHkAAwo5BA0AIAAgApIgASACkl8LDQAgACACkiABIAKSYAsNACAAIAKgIAEgAqBlCw0AIAAgAqAgASACoGYL", + "AGFzbQEAAAABDQJgAn19AX9gAnx8AX8DCQgAAAAAAQEBAQdpCApmMzIubm90X2x0AAAKZjMyLm5vdF9sZQABCmYzMi5ub3RfZ3QAAgpmMzIubm90X2dlAAMKZjY0Lm5vdF9sdAAECmY2NC5ub3RfbGUABQpmNjQubm90X2d0AAYKZjY0Lm5vdF9nZQAHCkkICAAgACABXUULCAAgACABX0ULCAAgACABXkULCAAgACABYEULCAAgACABY0ULCAAgACABZUULCAAgACABZEULCAAgACABZkUL", + "AGFzbQEAAAABCQJgAAF9YAABfAMDAgABBx0CC2YzMi5lcHNpbG9uAAALZjY0LmVwc2lsb24AAQpVAh8AQwAAgD9DAABAQEMAAIBAQwAAQECVQwAAgD+TlJMLMwBEAAAAAAAA8D9EAAAAAAAACEBEAAAAAAAAEEBEAAAAAAAACECjRAAAAAAAAPA/oaKhCw==", + "AGFzbQEAAAABCQJgAAF9YAABfAMDAgABBx0CC2YzMi5lcHNpbG9uAAALZjY0LmVwc2lsb24AAQpnAioBAn1DAACAPyEAA0AgACIBQwAAAD+UIgBDAACAP5JDAACAP14NAAsgAQs6AQJ8RAAAAAAAAPA/IQADQCAAIgFEAAAAAAAA4D+iIgBEAAAAAAAA8D+gRAAAAAAAAPA/ZA0ACyABCw==", + "AGFzbQEAAAABDQJgAn19AX9gAnx8AX8DCQgAAAAAAQEBAQe5AQgUZjMyLm5vX3RyaWNob3RvbXlfbHQAABRmMzIubm9fdHJpY2hvdG9teV9sZQABFGYzMi5ub190cmljaG90b215X2d0AAIUZjMyLm5vX3RyaWNob3RvbXlfZ2UAAxRmNjQubm9fdHJpY2hvdG9teV9sdAAEFGY2NC5ub190cmljaG90b215X2xlAAUUZjY0Lm5vX3RyaWNob3RvbXlfZ3QABhRmNjQubm9fdHJpY2hvdG9teV9nZQAHCnEIDQAgACABXSAAIAFgcgsNACAAIAFfIAAgAV5yCw0AIAAgAV4gACABX3ILDQAgACABYCAAIAFdcgsNACAAIAFjIAAgAWZyCw0AIAAgAWUgACABZHILDQAgACABZCAAIAFlcgsNACAAIAFmIAAgAWNyCw==", + "AGFzbQEAAAABFwRgAn9/AX9gAX8Bf2ACfn4BfmABfgF+AxQTAAABAgIDAQEBAQEBAwMDAwMDAQfuAxMdZjMyLmFyaXRobWV0aWNfbmFuX2JpdHBhdHRlcm4AABxmMzIuY2Fub25pY2FsX25hbl9iaXRwYXR0ZXJuAAEgZjMyLm5vbmFyaXRobWV0aWNfbmFuX2JpdHBhdHRlcm4AAh1mNjQuYXJpdGhtZXRpY19uYW5fYml0cGF0dGVybgADHGY2NC5jYW5vbmljYWxfbmFuX2JpdHBhdHRlcm4ABCBmNjQubm9uYXJpdGhtZXRpY19uYW5fYml0cGF0dGVybgAFFGYzMi5ub19mb2xkX3N1Yl96ZXJvAAYUZjMyLm5vX2ZvbGRfbmVnMF9zdWIABxNmMzIubm9fZm9sZF9tdWxfb25lAAgUZjMyLm5vX2ZvbGRfbmVnMV9tdWwACRNmMzIubm9fZm9sZF9kaXZfb25lAAoUZjMyLm5vX2ZvbGRfZGl2X25lZzEACxRmNjQubm9fZm9sZF9zdWJfemVybwAMFGY2NC5ub19mb2xkX25lZzBfc3ViAA0TZjY0Lm5vX2ZvbGRfbXVsX29uZQAOFGY2NC5ub19mb2xkX25lZzFfbXVsAA8TZjY0Lm5vX2ZvbGRfZGl2X29uZQAQFGY2NC5ub19mb2xkX2Rpdl9uZWcxABEWbm9fZm9sZF9wcm9tb3RlX2RlbW90ZQASCpkDExEAIAC+IAG+lbxBgICA/gdxCxEAIAC+IAG+lbxB/////wdxCwcAIAC+jLwLFgAgAL8gAb+jvUKAgICAgICA/P8AgwsWACAAvyABv6O9Qv///////////wCDCwcAIAC/mr0LEwAgAL5DAAAAAJO8QYCAgP4HcQsTAEMAAACAIAC+k7xBgICA/gdxCxMAIAC+QwAAgD+UvEGAgID+B3ELEwBDAACAvyAAvpS8QYCAgP4HcQsTACAAvkMAAIA/lbxBgICA/gdxCxMAIAC+QwAAgL+VvEGAgID+B3ELHAAgAL9EAAAAAAAAAAChvUKAgICAgICA/P8AgwscAEQAAAAAAAAAgCAAv6G9QoCAgICAgID8/wCDCxwAIAC/RAAAAAAAAPA/or1CgICAgICAgPz/AIMLHABEAAAAAAAA8L8gAL+ivUKAgICAgICA/P8AgwscACAAv0QAAAAAAADwP6O9QoCAgICAgID8/wCDCxwAIAC/RAAAAAAAAPC/o71CgICAgICAgPz/AIMLDwAgAL67trxBgICA/gdxCw==", + "AGFzbQEAAAABDQFgCHx8fHx8fHx8AXwDAwIAAAcyAhNkb3RfcHJvZHVjdF9leGFtcGxlAAAYd2l0aF9iaW5hcnlfc3VtX2NvbGxhcHNlAAEKNQIZACAAIASiIAEgBaKgIAIgBqKgIAMgB6KgCxkAIAAgBKIgASAFoqAgAiAGoiADIAeioKAL", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQcnAhBmMzIuY29udHJhY3QyZm1hAAAQZjY0LmNvbnRyYWN0MmZtYQABCh8CDgAgACAAlCABIAGUk5ELDgAgACAAoiABIAGioZ8L", + "AGFzbQEAAAABDwJgA319fQF9YAN8fHwBfAMDAgABBz8CHGYzMi5kaXZpc2lvbl9ieV9zbWFsbF9udW1iZXIAABxmNjQuZGl2aXNpb25fYnlfc21hbGxfbnVtYmVyAAEKFwIKACAAIAEgApWTCwoAIAAgASACo6EL", + "AGFzbQEAAAABDwJgA319fQF9YAN8fHwBfAMDAgABBycCEGYzMi5nb2xkZW5fcmF0aW8AABBmNjQuZ29sZGVuX3JhdGlvAAEKGQILACAAIAEgApGSlAsLACAAIAEgAp+gogs=", + "AGFzbQEAAAABCwJgAX0BfWABfAF8AwMCAAEHJwIQZjMyLnNpbHZlcl9tZWFucwAAEGY2NC5zaWx2ZXJfbWVhbnMAAQo5AhcAQwAAAD8gACAAIACUQwAAgECSkZKUCx8ARAAAAAAAAOA/IAAgACAAokQAAAAAAAAQQKCfoKIL", + "AGFzbQEAAAABBwFgAnx8AX8DAgEABw4BCnBvaW50X2ZvdXIAAAoTAREAIAAgAaNEmpmZmZmZ2T9jCw==", + "AGFzbQEAAAABBgFgAX8BfAMCAQAHBwEDdGF1AAAKywEByAEBBHxEAAAAAAAAAAAhAQJAIABBAUgNAEQAAAAAAADwPyECRAAAAAAAAAAAIQMDQCABIAJEAAAAAAAAIEAgA0QAAAAAAAAgQKIiBEQAAAAAAADwP6CjRAAAAAAAABBAIAREAAAAAAAAEECgo6FEAAAAAAAAAEAgBEQAAAAAAAAUQKCjoUQAAAAAAAAAQCAERAAAAAAAABhAoKOhoqAhASADRAAAAAAAAPA/oCEDIAJEAAAAAAAAsD+iIQIgAEF/aiIADQALCyABCw==", + "AGFzbQEAAAABDQJgAn19AX1gAnx8AXwDAwIAAQc9AhtmMzIubm9fZm9sZF9jb25kaXRpb25hbF9pbmMAABtmNjQubm9fZm9sZF9jb25kaXRpb25hbF9pbmMAAQo1AhUAIAAgAEMAAIA/kiABQwAAAABdGwsdACAAIABEAAAAAAAA8D+gIAFEAAAAAAAAAABjGws=", + "AGFzbQEAAAABEQRgAAF/YAABfmAAAX1gAAF8A2NiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgMDAwMDAwMDAwMHmQ5iB2YzMi5uYW4AABBmMzIucG9zaXRpdmVfbmFuAAEQZjMyLm5lZ2F0aXZlX25hbgACDWYzMi5wbGFpbl9uYW4AAyJmMzIuaW5mb3JtYWxseV9rbm93bl9hc19wbGFpbl9zbmFuAAQQZjMyLmFsbF9vbmVzX25hbgAFDGYzMi5taXNjX25hbgAGFWYzMi5taXNjX3Bvc2l0aXZlX25hbgAHFWYzMi5taXNjX25lZ2F0aXZlX25hbgAIDGYzMi5pbmZpbml0eQAJFWYzMi5wb3NpdGl2ZV9pbmZpbml0eQAKFWYzMi5uZWdhdGl2ZV9pbmZpbml0eQALCGYzMi56ZXJvAAwRZjMyLnBvc2l0aXZlX3plcm8ADRFmMzIubmVnYXRpdmVfemVybwAOCGYzMi5taXNjAA8QZjMyLm1pbl9wb3NpdGl2ZQAQDmYzMi5taW5fbm9ybWFsABEOZjMyLm1heF9maW5pdGUAEhFmMzIubWF4X3N1Ym5vcm1hbAATEGYzMi50cmFpbGluZ19kb3QAFAxmMzIubWlzY19pbnQAFQ1mMzIubGFyZ2VfaW50ABYNZjMyLm1pbl9pbnQzMgAXDWYzMi5taW5faW50NjQAGAxmMzJfZGVjLnplcm8AGRVmMzJfZGVjLnBvc2l0aXZlX3plcm8AGhVmMzJfZGVjLm5lZ2F0aXZlX3plcm8AGwxmMzJfZGVjLm1pc2MAHBRmMzJfZGVjLm1pbl9wb3NpdGl2ZQAdEmYzMl9kZWMubWluX25vcm1hbAAeFWYzMl9kZWMubWF4X3N1Ym5vcm1hbAAfEmYzMl9kZWMubWF4X2Zpbml0ZQAgFGYzMl9kZWMudHJhaWxpbmdfZG90ACEQZjMyX2RlYy5taXNjX2ludAAiEWYzMl9kZWMubGFyZ2VfaW50ACMRZjMyX2RlYy5taW5faW50MzIAJBFmMzJfZGVjLm1pbl9pbnQ2NAAlF2YzMl9kZWMucm9vdF9iZWVyX2Zsb2F0ACYHZjY0Lm5hbgAnEGY2NC5wb3NpdGl2ZV9uYW4AKBBmNjQubmVnYXRpdmVfbmFuACkNZjY0LnBsYWluX25hbgAqImY2NC5pbmZvcm1hbGx5X2tub3duX2FzX3BsYWluX3NuYW4AKxBmNjQuYWxsX29uZXNfbmFuACwMZjY0Lm1pc2NfbmFuAC0VZjY0Lm1pc2NfcG9zaXRpdmVfbmFuAC4VZjY0Lm1pc2NfbmVnYXRpdmVfbmFuAC8MZjY0LmluZmluaXR5ADAVZjY0LnBvc2l0aXZlX2luZmluaXR5ADEVZjY0Lm5lZ2F0aXZlX2luZmluaXR5ADIIZjY0Lnplcm8AMxFmNjQucG9zaXRpdmVfemVybwA0EWY2NC5uZWdhdGl2ZV96ZXJvADUIZjY0Lm1pc2MANhBmNjQubWluX3Bvc2l0aXZlADcOZjY0Lm1pbl9ub3JtYWwAOBFmNjQubWF4X3N1Ym5vcm1hbAA5DmY2NC5tYXhfZmluaXRlADoQZjY0LnRyYWlsaW5nX2RvdAA7DGY2NC5taXNjX2ludAA8DWY2NC5sYXJnZV9pbnQAPQ1mNjQubWluX2ludDMyAD4NZjY0Lm1pbl9pbnQ2NAA/DGY2NF9kZWMuemVybwBAFWY2NF9kZWMucG9zaXRpdmVfemVybwBBFWY2NF9kZWMubmVnYXRpdmVfemVybwBCDGY2NF9kZWMubWlzYwBDFGY2NF9kZWMubWluX3Bvc2l0aXZlAEQSZjY0X2RlYy5taW5fbm9ybWFsAEUVZjY0X2RlYy5tYXhfc3Vibm9ybWFsAEYSZjY0X2RlYy5tYXhfZmluaXRlAEcUZjY0X2RlYy50cmFpbGluZ19kb3QASBBmNjRfZGVjLm1pc2NfaW50AEkRZjY0X2RlYy5sYXJnZV9pbnQAShFmNjRfZGVjLm1pbl9pbnQzMgBLEWY2NF9kZWMubWluX2ludDY0AEwXZjY0X2RlYy5yb290X2JlZXJfZmxvYXQATQxmMzItZGVjLXNlcDEATgxmMzItZGVjLXNlcDIATwxmMzItZGVjLXNlcDMAUAxmMzItZGVjLXNlcDQAUQxmMzItZGVjLXNlcDUAUgxmMzItaGV4LXNlcDEAUwxmMzItaGV4LXNlcDIAVAxmMzItaGV4LXNlcDMAVQxmMzItaGV4LXNlcDQAVgxmMzItaGV4LXNlcDUAVwxmNjQtZGVjLXNlcDEAWAxmNjQtZGVjLXNlcDIAWQxmNjQtZGVjLXNlcDMAWgxmNjQtZGVjLXNlcDQAWwxmNjQtZGVjLXNlcDUAXAxmNjQtaGV4LXNlcDEAXQxmNjQtaGV4LXNlcDIAXgxmNjQtaGV4LXNlcDMAXwxmNjQtaGV4LXNlcDQAYAxmNjQtaGV4LXNlcDUAYQqjCGIIAEMAAMB/vAsIAEMAAMB/vAsIAEMAAMD/vAsIAEMAAMB/vAsIAEMAAKB/vAsIAEP/////vAsIAENFI4F/vAsIAENQQLB/vAsIAEPevKr/vAsIAEMAAIB/vAsIAEMAAIB/vAsIAEMAAID/vAsIAEMAAAAAvAsIAEMAAAAAvAsIAEMAAACAvAsIAEPbD8lAvAsIAEMBAAAAvAsIAEMAAIAAvAsIAEP//39/vAsIAEP//38AvAsIAEMAAIBEvAsIAEOAopFHvAsIAEMAAIBnvAsIAEMAAADPvAsIAEMAAADfvAsIAEMAAAAAvAsIAEMAAAAAvAsIAEMAAACAvAsIAEPbD8lAvAsIAEMBAAAAvAsIAEMAAIAAvAsIAEP//38AvAsIAEP//39/vAsIAEP5AhVQvAsIAEMA5EBGvAsIAEPseK1gvAsIAEMAAADPvAsIAEMAAADfvAsIAEMBAIA/vAsMAEQAAAAAAAD4f70LDABEAAAAAAAA+H+9CwwARAAAAAAAAPj/vQsMAEQAAAAAAAD4f70LDABEAAAAAAAA9H+9CwwARP//////////vQsMAES8mnhWNBLwf70LDABECQgHBgUE83+9CwwAREUjAe/Nq/L/vQsMAEQAAAAAAADwf70LDABEAAAAAAAA8H+9CwwARAAAAAAAAPD/vQsMAEQAAAAAAAAAAL0LDABEAAAAAAAAAAC9CwwARAAAAAAAAACAvQsMAEQYLURU+yEZQL0LDABEAQAAAAAAAAC9CwwARAAAAAAAABAAvQsMAET///////8PAL0LDABE////////73+9CwwARAAAAAAAADBGvQsMAEQAAAAAUDTyQL0LDABEAAAAAAAA8ES9CwwARAAAAAAAAODBvQsMAEQAAAAAAADgw70LDABEAAAAAAAAAAC9CwwARAAAAAAAAAAAvQsMAEQAAAAAAAAAgL0LDABEGC1EVPshGUC9CwwARAEAAAAAAAAAvQsMAEQAAAAAAAAQAL0LDABE////////DwC9CwwARP///////+9/vQsMAER9w5QlrUmyVL0LDABEAAAAAIAcyEC9CwwARECMtXgdrxVEvQsMAEQAAAAAAADgwb0LDABEAAAAAAAA4MO9CwwARCSe8R8AAPA/vQsHAEMAJHRJCwcAQwAAekQLBwBDEMl6RAsHAEOWGWFYCwcAQ3SuHW4LBwBDCvAgTQsHAEOAB9VHCwcAQ/H/IEcLBwBDAADwSQsHAEMowKtVCwsARAAAAACAhC5BCwsARAAAAAAAQI9ACwsARACL/PohWY9ACwsAREXMt1tzXNAmCwsARJzeW3LOtcNFCwsARDIzAQAe4CVDCwsARAAAAADwoPpACwsARECzNCj+H+RACwsARAAAAAAAAD5BCwsARABwnw8FeLVCCw==", + "AGFzbQEAAAABhYCAgAABYAABfAOCgICAAAEAB46AgIAAAQo0Mjk0OTY3MjQ5AAAKkYCAgAABi4CAgAAARAAAIPr//+9BCw==", + "AGFzbQEAAAABFwRgAn19AX1gAX0BfWACfHwBfGABfAF8Ax0cAAAAAAEBAQABAQEBAAACAgICAwMDAgMDAwMCAge3AhwHZjMyLmFkZAAAB2YzMi5zdWIAAQdmMzIubXVsAAIHZjMyLmRpdgADCGYzMi5zcXJ0AAQHZjMyLmFicwAFB2YzMi5uZWcABgxmMzIuY29weXNpZ24ABwhmMzIuY2VpbAAICWYzMi5mbG9vcgAJCWYzMi50cnVuYwAKC2YzMi5uZWFyZXN0AAsHZjMyLm1pbgAMB2YzMi5tYXgADQdmNjQuYWRkAA4HZjY0LnN1YgAPB2Y2NC5tdWwAEAdmNjQuZGl2ABEIZjY0LnNxcnQAEgdmNjQuYWJzABMHZjY0Lm5lZwAUDGY2NC5jb3B5c2lnbgAVCGY2NC5jZWlsABYJZjY0LmZsb29yABcJZjY0LnRydW5jABgLZjY0Lm5lYXJlc3QAGQdmNjQubWluABoHZjY0Lm1heAAbCsUBHAcAIAAgAZILBwAgACABkwsHACAAIAGUCwcAIAAgAZULBQAgAJELBQAgAIsLBQAgAIwLBwAgACABmAsFACAAjQsFACAAjgsFACAAjwsFACAAkAsHACAAIAGWCwcAIAAgAZcLBwAgACABoAsHACAAIAGhCwcAIAAgAaILBwAgACABowsFACAAnwsFACAAmQsFACAAmgsHACAAIAGmCwUAIACbCwUAIACcCwUAIACdCwUAIACeCwcAIAAgAaQLBwAgACABpQs=", +]; +export const script = "[[\"file\",\"f32.wast\"],[\"module\",5,0],[\"invoke\",19,0,\"add\",[\"f32:2147483648\",\"f32:2147483648\"]],[\"invoke\",25,0,\"add\",[\"f32:0\",\"f32:2147483649\"]],[\"invoke\",30,0,\"add\",[\"f32:0\",\"f32:8388608\"]],[\"invoke\",35,0,\"add\",[\"f32:2147483648\",\"f32:3212836864\"]],[\"invoke\",40,0,\"add\",[\"f32:2147483648\",\"f32:1086918619\"]],[\"invoke\",45,0,\"add\",[\"f32:0\",\"f32:4286578687\"]],[\"invoke\",50,0,\"add\",[\"f32:0\",\"f32:2139095040\"]],[\"invoke\",59,0,\"add\",[\"f32:2147483649\",\"f32:2147483648\"]],[\"invoke\",64,0,\"add\",[\"f32:2147483649\",\"f32:1\"]],[\"invoke\",69,0,\"add\",[\"f32:1\",\"f32:2155872256\"]],[\"invoke\",74,0,\"add\",[\"f32:1\",\"f32:1056964608\"]],[\"invoke\",79,0,\"add\",[\"f32:2147483649\",\"f32:3234402267\"]],[\"invoke\",85,0,\"add\",[\"f32:1\",\"f32:4286578687\"]],[\"invoke\",90,0,\"add\",[\"f32:1\",\"f32:2139095040\"]],[\"invoke\",99,0,\"add\",[\"f32:2155872256\",\"f32:2147483648\"]],[\"invoke\",104,0,\"add\",[\"f32:2155872256\",\"f32:1\"]],[\"invoke\",109,0,\"add\",[\"f32:8388608\",\"f32:2155872256\"]],[\"invoke\",114,0,\"add\",[\"f32:8388608\",\"f32:1056964608\"]],[\"invoke\",119,0,\"add\",[\"f32:2155872256\",\"f32:3234402267\"]],[\"invoke\",124,0,\"add\",[\"f32:2155872256\",\"f32:2139095039\"]],[\"invoke\",129,0,\"add\",[\"f32:8388608\",\"f32:4286578688\"]],[\"invoke\",137,0,\"add\",[\"f32:8388608\",\"f32:2143289344\"]],[\"invoke\",143,0,\"add\",[\"f32:3204448256\",\"f32:2147483649\"]],[\"invoke\",148,0,\"add\",[\"f32:3204448256\",\"f32:8388608\"]],[\"invoke\",154,0,\"add\",[\"f32:1056964608\",\"f32:1056964608\"]],[\"invoke\",159,0,\"add\",[\"f32:3204448256\",\"f32:3234402267\"]],[\"invoke\",164,0,\"add\",[\"f32:3204448256\",\"f32:2139095039\"]],[\"invoke\",169,0,\"add\",[\"f32:1056964608\",\"f32:4286578688\"]],[\"invoke\",177,0,\"add\",[\"f32:1056964608\",\"f32:2143289344\"]],[\"invoke\",183,0,\"add\",[\"f32:3212836864\",\"f32:2147483649\"]],[\"invoke\",188,0,\"add\",[\"f32:3212836864\",\"f32:8388608\"]],[\"invoke\",193,0,\"add\",[\"f32:1065353216\",\"f32:3204448256\"]],[\"invoke\",198,0,\"add\",[\"f32:1065353216\",\"f32:1065353216\"]],[\"invoke\",203,0,\"add\",[\"f32:3212836864\",\"f32:4286578687\"]],[\"invoke\",208,0,\"add\",[\"f32:3212836864\",\"f32:2139095040\"]],[\"invoke\",215,0,\"add\",[\"f32:1065353216\",\"f32:4290772992\"]],[\"invoke\",223,0,\"add\",[\"f32:3234402267\",\"f32:2147483649\"]],[\"invoke\",228,0,\"add\",[\"f32:3234402267\",\"f32:8388608\"]],[\"invoke\",233,0,\"add\",[\"f32:1086918619\",\"f32:3204448256\"]],[\"invoke\",238,0,\"add\",[\"f32:1086918619\",\"f32:1065353216\"]],[\"invoke\",243,0,\"add\",[\"f32:3234402267\",\"f32:4286578687\"]],[\"invoke\",248,0,\"add\",[\"f32:3234402267\",\"f32:2139095040\"]],[\"invoke\",255,0,\"add\",[\"f32:1086918619\",\"f32:4290772992\"]],[\"invoke\",262,0,\"add\",[\"f32:2139095039\",\"f32:0\"]],[\"invoke\",267,0,\"add\",[\"f32:4286578687\",\"f32:2155872256\"]],[\"invoke\",272,0,\"add\",[\"f32:4286578687\",\"f32:1056964608\"]],[\"invoke\",277,0,\"add\",[\"f32:2139095039\",\"f32:3212836864\"]],[\"invoke\",282,0,\"add\",[\"f32:2139095039\",\"f32:1086918619\"]],[\"invoke\",288,0,\"add\",[\"f32:4286578687\",\"f32:2139095040\"]],[\"invoke\",295,0,\"add\",[\"f32:2139095039\",\"f32:4290772992\"]],[\"invoke\",302,0,\"add\",[\"f32:2139095040\",\"f32:0\"]],[\"invoke\",307,0,\"add\",[\"f32:4286578688\",\"f32:2155872256\"]],[\"invoke\",312,0,\"add\",[\"f32:4286578688\",\"f32:1056964608\"]],[\"invoke\",317,0,\"add\",[\"f32:2139095040\",\"f32:3212836864\"]],[\"invoke\",322,0,\"add\",[\"f32:2139095040\",\"f32:1086918619\"]],[\"invoke\",327,0,\"add\",[\"f32:4286578688\",\"f32:4286578688\"]],[\"invoke\",333,0,\"add\",[\"f32:4286578688\",\"f32:2143289344\"]],[\"invoke\",343,0,\"add\",[\"f32:2143289344\",\"f32:2147483648\"]],[\"invoke\",353,0,\"add\",[\"f32:2143289344\",\"f32:1\"]],[\"invoke\",365,0,\"add\",[\"f32:4290772992\",\"f32:1056964608\"]],[\"invoke\",375,0,\"add\",[\"f32:2143289344\",\"f32:3212836864\"]],[\"invoke\",385,0,\"add\",[\"f32:2143289344\",\"f32:1086918619\"]],[\"invoke\",395,0,\"add\",[\"f32:4290772992\",\"f32:4286578688\"]],[\"invoke\",407,0,\"add\",[\"f32:4290772992\",\"f32:2143289344\"]],[\"invoke\",421,0,\"sub\",[\"f32:0\",\"f32:2147483648\"]],[\"invoke\",426,0,\"sub\",[\"f32:0\",\"f32:1\"]],[\"invoke\",431,0,\"sub\",[\"f32:2147483648\",\"f32:3204448256\"]],[\"invoke\",436,0,\"sub\",[\"f32:2147483648\",\"f32:1065353216\"]],[\"invoke\",441,0,\"sub\",[\"f32:0\",\"f32:3234402267\"]],[\"invoke\",446,0,\"sub\",[\"f32:0\",\"f32:2139095039\"]],[\"invoke\",451,0,\"sub\",[\"f32:2147483648\",\"f32:4290772992\"]],[\"invoke\",461,0,\"sub\",[\"f32:1\",\"f32:2147483648\"]],[\"invoke\",466,0,\"sub\",[\"f32:1\",\"f32:1\"]],[\"invoke\",471,0,\"sub\",[\"f32:2147483649\",\"f32:3204448256\"]],[\"invoke\",476,0,\"sub\",[\"f32:2147483649\",\"f32:1065353216\"]],[\"invoke\",481,0,\"sub\",[\"f32:1\",\"f32:3234402267\"]],[\"invoke\",486,0,\"sub\",[\"f32:1\",\"f32:2139095039\"]],[\"invoke\",491,0,\"sub\",[\"f32:2147483649\",\"f32:4290772992\"]],[\"invoke\",500,0,\"sub\",[\"f32:2155872256\",\"f32:0\"]],[\"invoke\",505,0,\"sub\",[\"f32:8388608\",\"f32:2147483649\"]],[\"invoke\",510,0,\"sub\",[\"f32:8388608\",\"f32:8388608\"]],[\"invoke\",515,0,\"sub\",[\"f32:2155872256\",\"f32:3212836864\"]],[\"invoke\",520,0,\"sub\",[\"f32:2155872256\",\"f32:1086918619\"]],[\"invoke\",526,0,\"sub\",[\"f32:8388608\",\"f32:2139095039\"]],[\"invoke\",531,0,\"sub\",[\"f32:2155872256\",\"f32:4290772992\"]],[\"invoke\",540,0,\"sub\",[\"f32:3204448256\",\"f32:0\"]],[\"invoke\",545,0,\"sub\",[\"f32:1056964608\",\"f32:2147483649\"]],[\"invoke\",550,0,\"sub\",[\"f32:1056964608\",\"f32:8388608\"]],[\"invoke\",555,0,\"sub\",[\"f32:3204448256\",\"f32:3212836864\"]],[\"invoke\",560,0,\"sub\",[\"f32:3204448256\",\"f32:1086918619\"]],[\"invoke\",565,0,\"sub\",[\"f32:1056964608\",\"f32:4286578687\"]],[\"invoke\",570,0,\"sub\",[\"f32:1056964608\",\"f32:2139095040\"]],[\"invoke\",579,0,\"sub\",[\"f32:3212836864\",\"f32:2147483648\"]],[\"invoke\",584,0,\"sub\",[\"f32:3212836864\",\"f32:1\"]],[\"invoke\",589,0,\"sub\",[\"f32:1065353216\",\"f32:2155872256\"]],[\"invoke\",595,0,\"sub\",[\"f32:3212836864\",\"f32:3212836864\"]],[\"invoke\",600,0,\"sub\",[\"f32:3212836864\",\"f32:1086918619\"]],[\"invoke\",605,0,\"sub\",[\"f32:1065353216\",\"f32:4286578687\"]],[\"invoke\",610,0,\"sub\",[\"f32:1065353216\",\"f32:2139095040\"]],[\"invoke\",619,0,\"sub\",[\"f32:3234402267\",\"f32:2147483648\"]],[\"invoke\",624,0,\"sub\",[\"f32:3234402267\",\"f32:1\"]],[\"invoke\",629,0,\"sub\",[\"f32:1086918619\",\"f32:2155872256\"]],[\"invoke\",634,0,\"sub\",[\"f32:1086918619\",\"f32:1056964608\"]],[\"invoke\",639,0,\"sub\",[\"f32:3234402267\",\"f32:3234402267\"]],[\"invoke\",644,0,\"sub\",[\"f32:3234402267\",\"f32:2139095039\"]],[\"invoke\",649,0,\"sub\",[\"f32:1086918619\",\"f32:4286578688\"]],[\"invoke\",659,0,\"sub\",[\"f32:4286578687\",\"f32:2147483648\"]],[\"invoke\",664,0,\"sub\",[\"f32:4286578687\",\"f32:1\"]],[\"invoke\",669,0,\"sub\",[\"f32:2139095039\",\"f32:2155872256\"]],[\"invoke\",674,0,\"sub\",[\"f32:2139095039\",\"f32:1056964608\"]],[\"invoke\",679,0,\"sub\",[\"f32:4286578687\",\"f32:3234402267\"]],[\"invoke\",684,0,\"sub\",[\"f32:4286578687\",\"f32:2139095039\"]],[\"invoke\",689,0,\"sub\",[\"f32:2139095039\",\"f32:4286578688\"]],[\"invoke\",697,0,\"sub\",[\"f32:2139095039\",\"f32:2143289344\"]],[\"invoke\",703,0,\"sub\",[\"f32:4286578688\",\"f32:2147483649\"]],[\"invoke\",708,0,\"sub\",[\"f32:4286578688\",\"f32:8388608\"]],[\"invoke\",713,0,\"sub\",[\"f32:2139095040\",\"f32:3204448256\"]],[\"invoke\",718,0,\"sub\",[\"f32:2139095040\",\"f32:1065353216\"]],[\"invoke\",724,0,\"sub\",[\"f32:4286578688\",\"f32:2139095039\"]],[\"invoke\",729,0,\"sub\",[\"f32:2139095040\",\"f32:4286578688\"]],[\"invoke\",737,0,\"sub\",[\"f32:2139095040\",\"f32:2143289344\"]],[\"invoke\",747,0,\"sub\",[\"f32:4290772992\",\"f32:2147483649\"]],[\"invoke\",757,0,\"sub\",[\"f32:4290772992\",\"f32:8388608\"]],[\"invoke\",767,0,\"sub\",[\"f32:2143289344\",\"f32:3204448256\"]],[\"invoke\",777,0,\"sub\",[\"f32:2143289344\",\"f32:1065353216\"]],[\"invoke\",787,0,\"sub\",[\"f32:4290772992\",\"f32:4286578687\"]],[\"invoke\",797,0,\"sub\",[\"f32:4290772992\",\"f32:2139095040\"]],[\"invoke\",811,0,\"sub\",[\"f32:2143289344\",\"f32:4290772992\"]],[\"invoke\",822,0,\"mul\",[\"f32:0\",\"f32:0\"]],[\"invoke\",827,0,\"mul\",[\"f32:2147483648\",\"f32:2155872256\"]],[\"invoke\",833,0,\"mul\",[\"f32:0\",\"f32:3204448256\"]],[\"invoke\",838,0,\"mul\",[\"f32:0\",\"f32:1065353216\"]],[\"invoke\",843,0,\"mul\",[\"f32:2147483648\",\"f32:4286578687\"]],[\"invoke\",848,0,\"mul\",[\"f32:2147483648\",\"f32:2139095040\"]],[\"invoke\",855,0,\"mul\",[\"f32:0\",\"f32:4290772992\"]],[\"invoke\",862,0,\"mul\",[\"f32:1\",\"f32:0\"]],[\"invoke\",867,0,\"mul\",[\"f32:2147483649\",\"f32:2155872256\"]],[\"invoke\",872,0,\"mul\",[\"f32:2147483649\",\"f32:1056964608\"]],[\"invoke\",877,0,\"mul\",[\"f32:1\",\"f32:3212836864\"]],[\"invoke\",882,0,\"mul\",[\"f32:1\",\"f32:1086918619\"]],[\"invoke\",887,0,\"mul\",[\"f32:2147483649\",\"f32:4286578688\"]],[\"invoke\",893,0,\"mul\",[\"f32:2147483649\",\"f32:2143289344\"]],[\"invoke\",902,0,\"mul\",[\"f32:8388608\",\"f32:0\"]],[\"invoke\",907,0,\"mul\",[\"f32:2155872256\",\"f32:2155872256\"]],[\"invoke\",912,0,\"mul\",[\"f32:2155872256\",\"f32:1056964608\"]],[\"invoke\",917,0,\"mul\",[\"f32:8388608\",\"f32:3212836864\"]],[\"invoke\",922,0,\"mul\",[\"f32:8388608\",\"f32:1086918619\"]],[\"invoke\",927,0,\"mul\",[\"f32:2155872256\",\"f32:4286578688\"]],[\"invoke\",933,0,\"mul\",[\"f32:2155872256\",\"f32:2143289344\"]],[\"invoke\",941,0,\"mul\",[\"f32:1056964608\",\"f32:2147483648\"]],[\"invoke\",946,0,\"mul\",[\"f32:1056964608\",\"f32:1\"]],[\"invoke\",951,0,\"mul\",[\"f32:3204448256\",\"f32:3204448256\"]],[\"invoke\",956,0,\"mul\",[\"f32:3204448256\",\"f32:1065353216\"]],[\"invoke\",962,0,\"mul\",[\"f32:1056964608\",\"f32:1086918619\"]],[\"invoke\",967,0,\"mul\",[\"f32:3204448256\",\"f32:4286578688\"]],[\"invoke\",973,0,\"mul\",[\"f32:3204448256\",\"f32:2143289344\"]],[\"invoke\",981,0,\"mul\",[\"f32:1065353216\",\"f32:2147483648\"]],[\"invoke\",986,0,\"mul\",[\"f32:1065353216\",\"f32:1\"]],[\"invoke\",991,0,\"mul\",[\"f32:3212836864\",\"f32:3204448256\"]],[\"invoke\",996,0,\"mul\",[\"f32:3212836864\",\"f32:1065353216\"]],[\"invoke\",1001,0,\"mul\",[\"f32:1065353216\",\"f32:3234402267\"]],[\"invoke\",1006,0,\"mul\",[\"f32:1065353216\",\"f32:2139095039\"]],[\"invoke\",1011,0,\"mul\",[\"f32:3212836864\",\"f32:4290772992\"]],[\"invoke\",1020,0,\"mul\",[\"f32:3234402267\",\"f32:0\"]],[\"invoke\",1025,0,\"mul\",[\"f32:1086918619\",\"f32:2147483649\"]],[\"invoke\",1031,0,\"mul\",[\"f32:3234402267\",\"f32:3204448256\"]],[\"invoke\",1036,0,\"mul\",[\"f32:3234402267\",\"f32:1065353216\"]],[\"invoke\",1041,0,\"mul\",[\"f32:1086918619\",\"f32:3234402267\"]],[\"invoke\",1046,0,\"mul\",[\"f32:1086918619\",\"f32:2139095039\"]],[\"invoke\",1051,0,\"mul\",[\"f32:3234402267\",\"f32:4290772992\"]],[\"invoke\",1060,0,\"mul\",[\"f32:4286578687\",\"f32:0\"]],[\"invoke\",1065,0,\"mul\",[\"f32:2139095039\",\"f32:2147483649\"]],[\"invoke\",1070,0,\"mul\",[\"f32:2139095039\",\"f32:8388608\"]],[\"invoke\",1075,0,\"mul\",[\"f32:4286578687\",\"f32:3212836864\"]],[\"invoke\",1080,0,\"mul\",[\"f32:4286578687\",\"f32:1086918619\"]],[\"invoke\",1085,0,\"mul\",[\"f32:2139095039\",\"f32:4286578687\"]],[\"invoke\",1090,0,\"mul\",[\"f32:2139095039\",\"f32:2139095040\"]],[\"invoke\",1100,0,\"mul\",[\"f32:4286578688\",\"f32:0\"]],[\"invoke\",1105,0,\"mul\",[\"f32:2139095040\",\"f32:2147483649\"]],[\"invoke\",1110,0,\"mul\",[\"f32:2139095040\",\"f32:8388608\"]],[\"invoke\",1115,0,\"mul\",[\"f32:4286578688\",\"f32:3212836864\"]],[\"invoke\",1120,0,\"mul\",[\"f32:4286578688\",\"f32:1086918619\"]],[\"invoke\",1125,0,\"mul\",[\"f32:2139095040\",\"f32:4286578687\"]],[\"invoke\",1130,0,\"mul\",[\"f32:2139095040\",\"f32:2139095040\"]],[\"invoke\",1139,0,\"mul\",[\"f32:4290772992\",\"f32:2147483648\"]],[\"invoke\",1149,0,\"mul\",[\"f32:4290772992\",\"f32:1\"]],[\"invoke\",1159,0,\"mul\",[\"f32:2143289344\",\"f32:2155872256\"]],[\"invoke\",1169,0,\"mul\",[\"f32:2143289344\",\"f32:1056964608\"]],[\"invoke\",1179,0,\"mul\",[\"f32:4290772992\",\"f32:3234402267\"]],[\"invoke\",1191,0,\"mul\",[\"f32:2143289344\",\"f32:4286578687\"]],[\"invoke\",1201,0,\"mul\",[\"f32:2143289344\",\"f32:2139095040\"]],[\"invoke\",1219,0,\"div\",[\"f32:2147483648\",\"f32:2147483648\"]],[\"invoke\",1224,0,\"div\",[\"f32:2147483648\",\"f32:1\"]],[\"invoke\",1229,0,\"div\",[\"f32:0\",\"f32:2155872256\"]],[\"invoke\",1234,0,\"div\",[\"f32:0\",\"f32:1056964608\"]],[\"invoke\",1239,0,\"div\",[\"f32:2147483648\",\"f32:3234402267\"]],[\"invoke\",1244,0,\"div\",[\"f32:2147483648\",\"f32:2139095039\"]],[\"invoke\",1249,0,\"div\",[\"f32:0\",\"f32:4286578688\"]],[\"invoke\",1257,0,\"div\",[\"f32:0\",\"f32:2143289344\"]],[\"invoke\",1263,0,\"div\",[\"f32:2147483649\",\"f32:2147483649\"]],[\"invoke\",1269,0,\"div\",[\"f32:1\",\"f32:2155872256\"]],[\"invoke\",1274,0,\"div\",[\"f32:1\",\"f32:1056964608\"]],[\"invoke\",1279,0,\"div\",[\"f32:2147483649\",\"f32:3234402267\"]],[\"invoke\",1284,0,\"div\",[\"f32:2147483649\",\"f32:2139095039\"]],[\"invoke\",1289,0,\"div\",[\"f32:1\",\"f32:4286578688\"]],[\"invoke\",1297,0,\"div\",[\"f32:1\",\"f32:2143289344\"]],[\"invoke\",1303,0,\"div\",[\"f32:2155872256\",\"f32:2147483649\"]],[\"invoke\",1308,0,\"div\",[\"f32:2155872256\",\"f32:8388608\"]],[\"invoke\",1313,0,\"div\",[\"f32:8388608\",\"f32:3204448256\"]],[\"invoke\",1318,0,\"div\",[\"f32:8388608\",\"f32:1065353216\"]],[\"invoke\",1323,0,\"div\",[\"f32:2155872256\",\"f32:4286578687\"]],[\"invoke\",1328,0,\"div\",[\"f32:2155872256\",\"f32:2139095040\"]],[\"invoke\",1337,0,\"div\",[\"f32:8388608\",\"f32:2143289344\"]],[\"invoke\",1343,0,\"div\",[\"f32:3204448256\",\"f32:2147483649\"]],[\"invoke\",1348,0,\"div\",[\"f32:3204448256\",\"f32:8388608\"]],[\"invoke\",1353,0,\"div\",[\"f32:1056964608\",\"f32:3204448256\"]],[\"invoke\",1358,0,\"div\",[\"f32:1056964608\",\"f32:1065353216\"]],[\"invoke\",1363,0,\"div\",[\"f32:3204448256\",\"f32:4286578687\"]],[\"invoke\",1368,0,\"div\",[\"f32:3204448256\",\"f32:2139095040\"]],[\"invoke\",1375,0,\"div\",[\"f32:1056964608\",\"f32:4290772992\"]],[\"invoke\",1382,0,\"div\",[\"f32:1065353216\",\"f32:0\"]],[\"invoke\",1387,0,\"div\",[\"f32:3212836864\",\"f32:2155872256\"]],[\"invoke\",1392,0,\"div\",[\"f32:3212836864\",\"f32:1056964608\"]],[\"invoke\",1397,0,\"div\",[\"f32:1065353216\",\"f32:3212836864\"]],[\"invoke\",1403,0,\"div\",[\"f32:3212836864\",\"f32:4286578687\"]],[\"invoke\",1408,0,\"div\",[\"f32:3212836864\",\"f32:2139095040\"]],[\"invoke\",1415,0,\"div\",[\"f32:1065353216\",\"f32:4290772992\"]],[\"invoke\",1422,0,\"div\",[\"f32:1086918619\",\"f32:0\"]],[\"invoke\",1427,0,\"div\",[\"f32:3234402267\",\"f32:2155872256\"]],[\"invoke\",1432,0,\"div\",[\"f32:3234402267\",\"f32:1056964608\"]],[\"invoke\",1437,0,\"div\",[\"f32:1086918619\",\"f32:3212836864\"]],[\"invoke\",1442,0,\"div\",[\"f32:1086918619\",\"f32:1086918619\"]],[\"invoke\",1447,0,\"div\",[\"f32:3234402267\",\"f32:4286578688\"]],[\"invoke\",1453,0,\"div\",[\"f32:3234402267\",\"f32:2143289344\"]],[\"invoke\",1461,0,\"div\",[\"f32:2139095039\",\"f32:2147483648\"]],[\"invoke\",1466,0,\"div\",[\"f32:2139095039\",\"f32:1\"]],[\"invoke\",1472,0,\"div\",[\"f32:4286578687\",\"f32:1056964608\"]],[\"invoke\",1477,0,\"div\",[\"f32:2139095039\",\"f32:3212836864\"]],[\"invoke\",1482,0,\"div\",[\"f32:2139095039\",\"f32:1086918619\"]],[\"invoke\",1487,0,\"div\",[\"f32:4286578687\",\"f32:4286578688\"]],[\"invoke\",1493,0,\"div\",[\"f32:4286578687\",\"f32:2143289344\"]],[\"invoke\",1501,0,\"div\",[\"f32:2139095040\",\"f32:2147483648\"]],[\"invoke\",1506,0,\"div\",[\"f32:2139095040\",\"f32:1\"]],[\"invoke\",1511,0,\"div\",[\"f32:4286578688\",\"f32:3204448256\"]],[\"invoke\",1516,0,\"div\",[\"f32:4286578688\",\"f32:1065353216\"]],[\"invoke\",1521,0,\"div\",[\"f32:2139095040\",\"f32:3234402267\"]],[\"invoke\",1526,0,\"div\",[\"f32:2139095040\",\"f32:2139095039\"]],[\"invoke\",1531,0,\"div\",[\"f32:4286578688\",\"f32:4290772992\"]],[\"invoke\",1543,0,\"div\",[\"f32:2143289344\",\"f32:2147483648\"]],[\"invoke\",1553,0,\"div\",[\"f32:2143289344\",\"f32:1\"]],[\"invoke\",1563,0,\"div\",[\"f32:4290772992\",\"f32:3204448256\"]],[\"invoke\",1573,0,\"div\",[\"f32:4290772992\",\"f32:1065353216\"]],[\"invoke\",1583,0,\"div\",[\"f32:2143289344\",\"f32:3234402267\"]],[\"invoke\",1593,0,\"div\",[\"f32:2143289344\",\"f32:2139095039\"]],[\"invoke\",1603,0,\"div\",[\"f32:4290772992\",\"f32:4290772992\"]],[\"invoke\",1620,0,\"min\",[\"f32:2147483648\",\"f32:0\"]],[\"invoke\",1625,0,\"min\",[\"f32:0\",\"f32:2147483649\"]],[\"invoke\",1630,0,\"min\",[\"f32:0\",\"f32:8388608\"]],[\"invoke\",1635,0,\"min\",[\"f32:2147483648\",\"f32:3212836864\"]],[\"invoke\",1641,0,\"min\",[\"f32:0\",\"f32:3234402267\"]],[\"invoke\",1646,0,\"min\",[\"f32:0\",\"f32:2139095039\"]],[\"invoke\",1651,0,\"min\",[\"f32:2147483648\",\"f32:4290772992\"]],[\"invoke\",1660,0,\"min\",[\"f32:2147483649\",\"f32:0\"]],[\"invoke\",1665,0,\"min\",[\"f32:1\",\"f32:2147483649\"]],[\"invoke\",1670,0,\"min\",[\"f32:1\",\"f32:8388608\"]],[\"invoke\",1675,0,\"min\",[\"f32:2147483649\",\"f32:3212836864\"]],[\"invoke\",1680,0,\"min\",[\"f32:2147483649\",\"f32:1086918619\"]],[\"invoke\",1685,0,\"min\",[\"f32:1\",\"f32:4286578687\"]],[\"invoke\",1690,0,\"min\",[\"f32:1\",\"f32:2139095040\"]],[\"invoke\",1699,0,\"min\",[\"f32:2155872256\",\"f32:2147483648\"]],[\"invoke\",1704,0,\"min\",[\"f32:2155872256\",\"f32:1\"]],[\"invoke\",1710,0,\"min\",[\"f32:8388608\",\"f32:8388608\"]],[\"invoke\",1715,0,\"min\",[\"f32:2155872256\",\"f32:3212836864\"]],[\"invoke\",1720,0,\"min\",[\"f32:2155872256\",\"f32:1086918619\"]],[\"invoke\",1725,0,\"min\",[\"f32:8388608\",\"f32:4286578687\"]],[\"invoke\",1730,0,\"min\",[\"f32:8388608\",\"f32:2139095040\"]],[\"invoke\",1739,0,\"min\",[\"f32:3204448256\",\"f32:2147483648\"]],[\"invoke\",1744,0,\"min\",[\"f32:3204448256\",\"f32:1\"]],[\"invoke\",1749,0,\"min\",[\"f32:1056964608\",\"f32:2155872256\"]],[\"invoke\",1754,0,\"min\",[\"f32:1056964608\",\"f32:1056964608\"]],[\"invoke\",1759,0,\"min\",[\"f32:3204448256\",\"f32:3234402267\"]],[\"invoke\",1764,0,\"min\",[\"f32:3204448256\",\"f32:2139095039\"]],[\"invoke\",1769,0,\"min\",[\"f32:1056964608\",\"f32:4286578688\"]],[\"invoke\",1779,0,\"min\",[\"f32:3212836864\",\"f32:2147483648\"]],[\"invoke\",1784,0,\"min\",[\"f32:3212836864\",\"f32:1\"]],[\"invoke\",1789,0,\"min\",[\"f32:1065353216\",\"f32:2155872256\"]],[\"invoke\",1794,0,\"min\",[\"f32:1065353216\",\"f32:1056964608\"]],[\"invoke\",1799,0,\"min\",[\"f32:3212836864\",\"f32:3234402267\"]],[\"invoke\",1804,0,\"min\",[\"f32:3212836864\",\"f32:2139095039\"]],[\"invoke\",1809,0,\"min\",[\"f32:1065353216\",\"f32:4286578688\"]],[\"invoke\",1817,0,\"min\",[\"f32:1065353216\",\"f32:2143289344\"]],[\"invoke\",1823,0,\"min\",[\"f32:3234402267\",\"f32:2147483649\"]],[\"invoke\",1828,0,\"min\",[\"f32:3234402267\",\"f32:8388608\"]],[\"invoke\",1833,0,\"min\",[\"f32:1086918619\",\"f32:3204448256\"]],[\"invoke\",1838,0,\"min\",[\"f32:1086918619\",\"f32:1065353216\"]],[\"invoke\",1844,0,\"min\",[\"f32:3234402267\",\"f32:2139095039\"]],[\"invoke\",1849,0,\"min\",[\"f32:1086918619\",\"f32:4286578688\"]],[\"invoke\",1857,0,\"min\",[\"f32:1086918619\",\"f32:2143289344\"]],[\"invoke\",1863,0,\"min\",[\"f32:4286578687\",\"f32:2147483649\"]],[\"invoke\",1868,0,\"min\",[\"f32:4286578687\",\"f32:8388608\"]],[\"invoke\",1873,0,\"min\",[\"f32:2139095039\",\"f32:3204448256\"]],[\"invoke\",1878,0,\"min\",[\"f32:2139095039\",\"f32:1065353216\"]],[\"invoke\",1883,0,\"min\",[\"f32:4286578687\",\"f32:4286578687\"]],[\"invoke\",1888,0,\"min\",[\"f32:4286578687\",\"f32:2139095040\"]],[\"invoke\",1895,0,\"min\",[\"f32:2139095039\",\"f32:4290772992\"]],[\"invoke\",1902,0,\"min\",[\"f32:2139095040\",\"f32:0\"]],[\"invoke\",1908,0,\"min\",[\"f32:4286578688\",\"f32:8388608\"]],[\"invoke\",1913,0,\"min\",[\"f32:2139095040\",\"f32:3204448256\"]],[\"invoke\",1918,0,\"min\",[\"f32:2139095040\",\"f32:1065353216\"]],[\"invoke\",1923,0,\"min\",[\"f32:4286578688\",\"f32:4286578687\"]],[\"invoke\",1928,0,\"min\",[\"f32:4286578688\",\"f32:2139095040\"]],[\"invoke\",1935,0,\"min\",[\"f32:2139095040\",\"f32:4290772992\"]],[\"invoke\",1945,0,\"min\",[\"f32:2143289344\",\"f32:0\"]],[\"invoke\",1955,0,\"min\",[\"f32:4290772992\",\"f32:2155872256\"]],[\"invoke\",1965,0,\"min\",[\"f32:4290772992\",\"f32:1056964608\"]],[\"invoke\",1975,0,\"min\",[\"f32:2143289344\",\"f32:3212836864\"]],[\"invoke\",1985,0,\"min\",[\"f32:2143289344\",\"f32:1086918619\"]],[\"invoke\",1995,0,\"min\",[\"f32:4290772992\",\"f32:4286578688\"]],[\"invoke\",2011,0,\"min\",[\"f32:2143289344\",\"f32:4290772992\"]],[\"invoke\",2022,0,\"max\",[\"f32:0\",\"f32:0\"]],[\"invoke\",2027,0,\"max\",[\"f32:2147483648\",\"f32:2155872256\"]],[\"invoke\",2032,0,\"max\",[\"f32:2147483648\",\"f32:1056964608\"]],[\"invoke\",2037,0,\"max\",[\"f32:0\",\"f32:3212836864\"]],[\"invoke\",2042,0,\"max\",[\"f32:0\",\"f32:1086918619\"]],[\"invoke\",2047,0,\"max\",[\"f32:2147483648\",\"f32:4286578688\"]],[\"invoke\",2053,0,\"max\",[\"f32:2147483648\",\"f32:2143289344\"]],[\"invoke\",2061,0,\"max\",[\"f32:1\",\"f32:2147483648\"]],[\"invoke\",2066,0,\"max\",[\"f32:1\",\"f32:1\"]],[\"invoke\",2071,0,\"max\",[\"f32:2147483649\",\"f32:3204448256\"]],[\"invoke\",2076,0,\"max\",[\"f32:2147483649\",\"f32:1065353216\"]],[\"invoke\",2082,0,\"max\",[\"f32:1\",\"f32:1086918619\"]],[\"invoke\",2087,0,\"max\",[\"f32:2147483649\",\"f32:4286578688\"]],[\"invoke\",2093,0,\"max\",[\"f32:2147483649\",\"f32:2143289344\"]],[\"invoke\",2101,0,\"max\",[\"f32:8388608\",\"f32:2147483648\"]],[\"invoke\",2106,0,\"max\",[\"f32:8388608\",\"f32:1\"]],[\"invoke\",2111,0,\"max\",[\"f32:2155872256\",\"f32:3204448256\"]],[\"invoke\",2116,0,\"max\",[\"f32:2155872256\",\"f32:1065353216\"]],[\"invoke\",2121,0,\"max\",[\"f32:8388608\",\"f32:3234402267\"]],[\"invoke\",2126,0,\"max\",[\"f32:8388608\",\"f32:2139095039\"]],[\"invoke\",2131,0,\"max\",[\"f32:2155872256\",\"f32:4290772992\"]],[\"invoke\",2140,0,\"max\",[\"f32:3204448256\",\"f32:0\"]],[\"invoke\",2145,0,\"max\",[\"f32:1056964608\",\"f32:2147483649\"]],[\"invoke\",2151,0,\"max\",[\"f32:3204448256\",\"f32:3204448256\"]],[\"invoke\",2156,0,\"max\",[\"f32:3204448256\",\"f32:1065353216\"]],[\"invoke\",2161,0,\"max\",[\"f32:1056964608\",\"f32:3234402267\"]],[\"invoke\",2166,0,\"max\",[\"f32:1056964608\",\"f32:2139095039\"]],[\"invoke\",2171,0,\"max\",[\"f32:3204448256\",\"f32:4290772992\"]],[\"invoke\",2180,0,\"max\",[\"f32:3212836864\",\"f32:0\"]],[\"invoke\",2185,0,\"max\",[\"f32:1065353216\",\"f32:2147483649\"]],[\"invoke\",2190,0,\"max\",[\"f32:1065353216\",\"f32:8388608\"]],[\"invoke\",2195,0,\"max\",[\"f32:3212836864\",\"f32:3212836864\"]],[\"invoke\",2200,0,\"max\",[\"f32:3212836864\",\"f32:1086918619\"]],[\"invoke\",2205,0,\"max\",[\"f32:1065353216\",\"f32:4286578687\"]],[\"invoke\",2211,0,\"max\",[\"f32:3212836864\",\"f32:4290772992\"]],[\"invoke\",2220,0,\"max\",[\"f32:3234402267\",\"f32:0\"]],[\"invoke\",2225,0,\"max\",[\"f32:1086918619\",\"f32:2147483649\"]],[\"invoke\",2230,0,\"max\",[\"f32:1086918619\",\"f32:8388608\"]],[\"invoke\",2235,0,\"max\",[\"f32:3234402267\",\"f32:3212836864\"]],[\"invoke\",2240,0,\"max\",[\"f32:3234402267\",\"f32:1086918619\"]],[\"invoke\",2245,0,\"max\",[\"f32:1086918619\",\"f32:4286578687\"]],[\"invoke\",2250,0,\"max\",[\"f32:1086918619\",\"f32:2139095040\"]],[\"invoke\",2259,0,\"max\",[\"f32:4286578687\",\"f32:2147483648\"]],[\"invoke\",2264,0,\"max\",[\"f32:4286578687\",\"f32:1\"]],[\"invoke\",2269,0,\"max\",[\"f32:2139095039\",\"f32:2155872256\"]],[\"invoke\",2274,0,\"max\",[\"f32:2139095039\",\"f32:1056964608\"]],[\"invoke\",2280,0,\"max\",[\"f32:4286578687\",\"f32:1086918619\"]],[\"invoke\",2285,0,\"max\",[\"f32:2139095039\",\"f32:4286578687\"]],[\"invoke\",2290,0,\"max\",[\"f32:2139095039\",\"f32:2139095040\"]],[\"invoke\",2299,0,\"max\",[\"f32:4286578688\",\"f32:2147483648\"]],[\"invoke\",2304,0,\"max\",[\"f32:4286578688\",\"f32:1\"]],[\"invoke\",2309,0,\"max\",[\"f32:2139095040\",\"f32:2155872256\"]],[\"invoke\",2314,0,\"max\",[\"f32:2139095040\",\"f32:1056964608\"]],[\"invoke\",2319,0,\"max\",[\"f32:4286578688\",\"f32:3234402267\"]],[\"invoke\",2324,0,\"max\",[\"f32:4286578688\",\"f32:2139095039\"]],[\"invoke\",2329,0,\"max\",[\"f32:2139095040\",\"f32:4286578688\"]],[\"invoke\",2337,0,\"max\",[\"f32:2139095040\",\"f32:2143289344\"]],[\"invoke\",2347,0,\"max\",[\"f32:4290772992\",\"f32:2147483649\"]],[\"invoke\",2359,0,\"max\",[\"f32:2143289344\",\"f32:2155872256\"]],[\"invoke\",2369,0,\"max\",[\"f32:2143289344\",\"f32:1056964608\"]],[\"invoke\",2379,0,\"max\",[\"f32:4290772992\",\"f32:3234402267\"]],[\"invoke\",2389,0,\"max\",[\"f32:4290772992\",\"f32:2139095039\"]],[\"invoke\",2399,0,\"max\",[\"f32:2143289344\",\"f32:4286578688\"]],[\"invoke\",2415,0,\"max\",[\"f32:2143289344\",\"f32:2143289344\"]],[\"invoke\",2423,0,\"sqrt\",[\"f32:2155872256\"]],[\"invoke\",2428,0,\"sqrt\",[\"f32:1065353216\"]],[\"invoke\",2433,0,\"sqrt\",[\"f32:4286578688\"]],[\"invoke\",2440,0,\"floor\",[\"f32:0\"]],[\"invoke\",2445,0,\"floor\",[\"f32:3204448256\"]],[\"invoke\",2450,0,\"floor\",[\"f32:1086918619\"]],[\"invoke\",2457,0,\"floor\",[\"f32:2143289344\"]],[\"invoke\",2463,0,\"ceil\",[\"f32:2155872256\"]],[\"invoke\",2468,0,\"ceil\",[\"f32:1065353216\"]],[\"invoke\",2473,0,\"ceil\",[\"f32:4286578688\"]],[\"invoke\",2480,0,\"trunc\",[\"f32:0\"]],[\"invoke\",2485,0,\"trunc\",[\"f32:3204448256\"]],[\"invoke\",2490,0,\"trunc\",[\"f32:1086918619\"]],[\"invoke\",2495,0,\"trunc\",[\"f32:4290772992\"]],[\"invoke\",2502,0,\"nearest\",[\"f32:1\"]],[\"invoke\",2507,0,\"nearest\",[\"f32:3212836864\"]],[\"invoke\",2512,0,\"nearest\",[\"f32:2139095039\"]],[\"file\",\"f64.wast\"],[\"module\",5,1],[\"invoke\",19,0,\"add\",[\"f64:9223372036854775808\",\"f64:9223372036854775808\"]],[\"invoke\",25,0,\"add\",[\"f64:0\",\"f64:9223372036854775809\"]],[\"invoke\",30,0,\"add\",[\"f64:0\",\"f64:4503599627370496\"]],[\"invoke\",35,0,\"add\",[\"f64:9223372036854775808\",\"f64:13830554455654793216\"]],[\"invoke\",40,0,\"add\",[\"f64:9223372036854775808\",\"f64:4618760256179416344\"]],[\"invoke\",45,0,\"add\",[\"f64:0\",\"f64:18442240474082181119\"]],[\"invoke\",50,0,\"add\",[\"f64:0\",\"f64:9218868437227405312\"]],[\"invoke\",59,0,\"add\",[\"f64:9223372036854775809\",\"f64:9223372036854775808\"]],[\"invoke\",64,0,\"add\",[\"f64:9223372036854775809\",\"f64:1\"]],[\"invoke\",69,0,\"add\",[\"f64:1\",\"f64:9227875636482146304\"]],[\"invoke\",74,0,\"add\",[\"f64:1\",\"f64:4602678819172646912\"]],[\"invoke\",79,0,\"add\",[\"f64:9223372036854775809\",\"f64:13842132293034192152\"]],[\"invoke\",85,0,\"add\",[\"f64:1\",\"f64:18442240474082181119\"]],[\"invoke\",90,0,\"add\",[\"f64:1\",\"f64:9218868437227405312\"]],[\"invoke\",99,0,\"add\",[\"f64:9227875636482146304\",\"f64:9223372036854775808\"]],[\"invoke\",104,0,\"add\",[\"f64:9227875636482146304\",\"f64:1\"]],[\"invoke\",109,0,\"add\",[\"f64:4503599627370496\",\"f64:9227875636482146304\"]],[\"invoke\",114,0,\"add\",[\"f64:4503599627370496\",\"f64:4602678819172646912\"]],[\"invoke\",119,0,\"add\",[\"f64:9227875636482146304\",\"f64:13842132293034192152\"]],[\"invoke\",124,0,\"add\",[\"f64:9227875636482146304\",\"f64:9218868437227405311\"]],[\"invoke\",129,0,\"add\",[\"f64:4503599627370496\",\"f64:18442240474082181120\"]],[\"invoke\",137,0,\"add\",[\"f64:4503599627370496\",\"f64:9221120237041090560\"]],[\"invoke\",143,0,\"add\",[\"f64:13826050856027422720\",\"f64:9223372036854775809\"]],[\"invoke\",148,0,\"add\",[\"f64:13826050856027422720\",\"f64:4503599627370496\"]],[\"invoke\",154,0,\"add\",[\"f64:4602678819172646912\",\"f64:4602678819172646912\"]],[\"invoke\",159,0,\"add\",[\"f64:13826050856027422720\",\"f64:13842132293034192152\"]],[\"invoke\",164,0,\"add\",[\"f64:13826050856027422720\",\"f64:9218868437227405311\"]],[\"invoke\",169,0,\"add\",[\"f64:4602678819172646912\",\"f64:18442240474082181120\"]],[\"invoke\",177,0,\"add\",[\"f64:4602678819172646912\",\"f64:9221120237041090560\"]],[\"invoke\",183,0,\"add\",[\"f64:13830554455654793216\",\"f64:9223372036854775809\"]],[\"invoke\",188,0,\"add\",[\"f64:13830554455654793216\",\"f64:4503599627370496\"]],[\"invoke\",193,0,\"add\",[\"f64:4607182418800017408\",\"f64:13826050856027422720\"]],[\"invoke\",198,0,\"add\",[\"f64:4607182418800017408\",\"f64:4607182418800017408\"]],[\"invoke\",203,0,\"add\",[\"f64:13830554455654793216\",\"f64:18442240474082181119\"]],[\"invoke\",208,0,\"add\",[\"f64:13830554455654793216\",\"f64:9218868437227405312\"]],[\"invoke\",215,0,\"add\",[\"f64:4607182418800017408\",\"f64:18444492273895866368\"]],[\"invoke\",223,0,\"add\",[\"f64:13842132293034192152\",\"f64:9223372036854775809\"]],[\"invoke\",228,0,\"add\",[\"f64:13842132293034192152\",\"f64:4503599627370496\"]],[\"invoke\",233,0,\"add\",[\"f64:4618760256179416344\",\"f64:13826050856027422720\"]],[\"invoke\",238,0,\"add\",[\"f64:4618760256179416344\",\"f64:4607182418800017408\"]],[\"invoke\",243,0,\"add\",[\"f64:13842132293034192152\",\"f64:18442240474082181119\"]],[\"invoke\",248,0,\"add\",[\"f64:13842132293034192152\",\"f64:9218868437227405312\"]],[\"invoke\",255,0,\"add\",[\"f64:4618760256179416344\",\"f64:18444492273895866368\"]],[\"invoke\",262,0,\"add\",[\"f64:9218868437227405311\",\"f64:0\"]],[\"invoke\",267,0,\"add\",[\"f64:18442240474082181119\",\"f64:9227875636482146304\"]],[\"invoke\",272,0,\"add\",[\"f64:18442240474082181119\",\"f64:4602678819172646912\"]],[\"invoke\",277,0,\"add\",[\"f64:9218868437227405311\",\"f64:13830554455654793216\"]],[\"invoke\",282,0,\"add\",[\"f64:9218868437227405311\",\"f64:4618760256179416344\"]],[\"invoke\",288,0,\"add\",[\"f64:18442240474082181119\",\"f64:9218868437227405312\"]],[\"invoke\",295,0,\"add\",[\"f64:9218868437227405311\",\"f64:18444492273895866368\"]],[\"invoke\",302,0,\"add\",[\"f64:9218868437227405312\",\"f64:0\"]],[\"invoke\",307,0,\"add\",[\"f64:18442240474082181120\",\"f64:9227875636482146304\"]],[\"invoke\",312,0,\"add\",[\"f64:18442240474082181120\",\"f64:4602678819172646912\"]],[\"invoke\",317,0,\"add\",[\"f64:9218868437227405312\",\"f64:13830554455654793216\"]],[\"invoke\",322,0,\"add\",[\"f64:9218868437227405312\",\"f64:4618760256179416344\"]],[\"invoke\",327,0,\"add\",[\"f64:18442240474082181120\",\"f64:18442240474082181120\"]],[\"invoke\",333,0,\"add\",[\"f64:18442240474082181120\",\"f64:9221120237041090560\"]],[\"invoke\",343,0,\"add\",[\"f64:9221120237041090560\",\"f64:9223372036854775808\"]],[\"invoke\",353,0,\"add\",[\"f64:9221120237041090560\",\"f64:1\"]],[\"invoke\",365,0,\"add\",[\"f64:18444492273895866368\",\"f64:4602678819172646912\"]],[\"invoke\",375,0,\"add\",[\"f64:9221120237041090560\",\"f64:13830554455654793216\"]],[\"invoke\",385,0,\"add\",[\"f64:9221120237041090560\",\"f64:4618760256179416344\"]],[\"invoke\",395,0,\"add\",[\"f64:18444492273895866368\",\"f64:18442240474082181120\"]],[\"invoke\",407,0,\"add\",[\"f64:18444492273895866368\",\"f64:9221120237041090560\"]],[\"invoke\",421,0,\"sub\",[\"f64:0\",\"f64:9223372036854775808\"]],[\"invoke\",426,0,\"sub\",[\"f64:0\",\"f64:1\"]],[\"invoke\",431,0,\"sub\",[\"f64:9223372036854775808\",\"f64:13826050856027422720\"]],[\"invoke\",436,0,\"sub\",[\"f64:9223372036854775808\",\"f64:4607182418800017408\"]],[\"invoke\",441,0,\"sub\",[\"f64:0\",\"f64:13842132293034192152\"]],[\"invoke\",446,0,\"sub\",[\"f64:0\",\"f64:9218868437227405311\"]],[\"invoke\",451,0,\"sub\",[\"f64:9223372036854775808\",\"f64:18444492273895866368\"]],[\"invoke\",461,0,\"sub\",[\"f64:1\",\"f64:9223372036854775808\"]],[\"invoke\",466,0,\"sub\",[\"f64:1\",\"f64:1\"]],[\"invoke\",471,0,\"sub\",[\"f64:9223372036854775809\",\"f64:13826050856027422720\"]],[\"invoke\",476,0,\"sub\",[\"f64:9223372036854775809\",\"f64:4607182418800017408\"]],[\"invoke\",481,0,\"sub\",[\"f64:1\",\"f64:13842132293034192152\"]],[\"invoke\",486,0,\"sub\",[\"f64:1\",\"f64:9218868437227405311\"]],[\"invoke\",491,0,\"sub\",[\"f64:9223372036854775809\",\"f64:18444492273895866368\"]],[\"invoke\",500,0,\"sub\",[\"f64:9227875636482146304\",\"f64:0\"]],[\"invoke\",505,0,\"sub\",[\"f64:4503599627370496\",\"f64:9223372036854775809\"]],[\"invoke\",510,0,\"sub\",[\"f64:4503599627370496\",\"f64:4503599627370496\"]],[\"invoke\",515,0,\"sub\",[\"f64:9227875636482146304\",\"f64:13830554455654793216\"]],[\"invoke\",520,0,\"sub\",[\"f64:9227875636482146304\",\"f64:4618760256179416344\"]],[\"invoke\",526,0,\"sub\",[\"f64:4503599627370496\",\"f64:9218868437227405311\"]],[\"invoke\",531,0,\"sub\",[\"f64:9227875636482146304\",\"f64:18444492273895866368\"]],[\"invoke\",540,0,\"sub\",[\"f64:13826050856027422720\",\"f64:0\"]],[\"invoke\",545,0,\"sub\",[\"f64:4602678819172646912\",\"f64:9223372036854775809\"]],[\"invoke\",550,0,\"sub\",[\"f64:4602678819172646912\",\"f64:4503599627370496\"]],[\"invoke\",555,0,\"sub\",[\"f64:13826050856027422720\",\"f64:13830554455654793216\"]],[\"invoke\",560,0,\"sub\",[\"f64:13826050856027422720\",\"f64:4618760256179416344\"]],[\"invoke\",565,0,\"sub\",[\"f64:4602678819172646912\",\"f64:18442240474082181119\"]],[\"invoke\",570,0,\"sub\",[\"f64:4602678819172646912\",\"f64:9218868437227405312\"]],[\"invoke\",579,0,\"sub\",[\"f64:13830554455654793216\",\"f64:9223372036854775808\"]],[\"invoke\",584,0,\"sub\",[\"f64:13830554455654793216\",\"f64:1\"]],[\"invoke\",589,0,\"sub\",[\"f64:4607182418800017408\",\"f64:9227875636482146304\"]],[\"invoke\",595,0,\"sub\",[\"f64:13830554455654793216\",\"f64:13830554455654793216\"]],[\"invoke\",600,0,\"sub\",[\"f64:13830554455654793216\",\"f64:4618760256179416344\"]],[\"invoke\",605,0,\"sub\",[\"f64:4607182418800017408\",\"f64:18442240474082181119\"]],[\"invoke\",610,0,\"sub\",[\"f64:4607182418800017408\",\"f64:9218868437227405312\"]],[\"invoke\",619,0,\"sub\",[\"f64:13842132293034192152\",\"f64:9223372036854775808\"]],[\"invoke\",624,0,\"sub\",[\"f64:13842132293034192152\",\"f64:1\"]],[\"invoke\",629,0,\"sub\",[\"f64:4618760256179416344\",\"f64:9227875636482146304\"]],[\"invoke\",634,0,\"sub\",[\"f64:4618760256179416344\",\"f64:4602678819172646912\"]],[\"invoke\",639,0,\"sub\",[\"f64:13842132293034192152\",\"f64:13842132293034192152\"]],[\"invoke\",644,0,\"sub\",[\"f64:13842132293034192152\",\"f64:9218868437227405311\"]],[\"invoke\",649,0,\"sub\",[\"f64:4618760256179416344\",\"f64:18442240474082181120\"]],[\"invoke\",659,0,\"sub\",[\"f64:18442240474082181119\",\"f64:9223372036854775808\"]],[\"invoke\",664,0,\"sub\",[\"f64:18442240474082181119\",\"f64:1\"]],[\"invoke\",669,0,\"sub\",[\"f64:9218868437227405311\",\"f64:9227875636482146304\"]],[\"invoke\",674,0,\"sub\",[\"f64:9218868437227405311\",\"f64:4602678819172646912\"]],[\"invoke\",679,0,\"sub\",[\"f64:18442240474082181119\",\"f64:13842132293034192152\"]],[\"invoke\",684,0,\"sub\",[\"f64:18442240474082181119\",\"f64:9218868437227405311\"]],[\"invoke\",689,0,\"sub\",[\"f64:9218868437227405311\",\"f64:18442240474082181120\"]],[\"invoke\",697,0,\"sub\",[\"f64:9218868437227405311\",\"f64:9221120237041090560\"]],[\"invoke\",703,0,\"sub\",[\"f64:18442240474082181120\",\"f64:9223372036854775809\"]],[\"invoke\",708,0,\"sub\",[\"f64:18442240474082181120\",\"f64:4503599627370496\"]],[\"invoke\",713,0,\"sub\",[\"f64:9218868437227405312\",\"f64:13826050856027422720\"]],[\"invoke\",718,0,\"sub\",[\"f64:9218868437227405312\",\"f64:4607182418800017408\"]],[\"invoke\",724,0,\"sub\",[\"f64:18442240474082181120\",\"f64:9218868437227405311\"]],[\"invoke\",729,0,\"sub\",[\"f64:9218868437227405312\",\"f64:18442240474082181120\"]],[\"invoke\",737,0,\"sub\",[\"f64:9218868437227405312\",\"f64:9221120237041090560\"]],[\"invoke\",747,0,\"sub\",[\"f64:18444492273895866368\",\"f64:9223372036854775809\"]],[\"invoke\",757,0,\"sub\",[\"f64:18444492273895866368\",\"f64:4503599627370496\"]],[\"invoke\",767,0,\"sub\",[\"f64:9221120237041090560\",\"f64:13826050856027422720\"]],[\"invoke\",777,0,\"sub\",[\"f64:9221120237041090560\",\"f64:4607182418800017408\"]],[\"invoke\",787,0,\"sub\",[\"f64:18444492273895866368\",\"f64:18442240474082181119\"]],[\"invoke\",797,0,\"sub\",[\"f64:18444492273895866368\",\"f64:9218868437227405312\"]],[\"invoke\",811,0,\"sub\",[\"f64:9221120237041090560\",\"f64:18444492273895866368\"]],[\"invoke\",822,0,\"mul\",[\"f64:0\",\"f64:0\"]],[\"invoke\",827,0,\"mul\",[\"f64:9223372036854775808\",\"f64:9227875636482146304\"]],[\"invoke\",833,0,\"mul\",[\"f64:0\",\"f64:13826050856027422720\"]],[\"invoke\",838,0,\"mul\",[\"f64:0\",\"f64:4607182418800017408\"]],[\"invoke\",843,0,\"mul\",[\"f64:9223372036854775808\",\"f64:18442240474082181119\"]],[\"invoke\",848,0,\"mul\",[\"f64:9223372036854775808\",\"f64:9218868437227405312\"]],[\"invoke\",855,0,\"mul\",[\"f64:0\",\"f64:18444492273895866368\"]],[\"invoke\",862,0,\"mul\",[\"f64:1\",\"f64:0\"]],[\"invoke\",867,0,\"mul\",[\"f64:9223372036854775809\",\"f64:9227875636482146304\"]],[\"invoke\",872,0,\"mul\",[\"f64:9223372036854775809\",\"f64:4602678819172646912\"]],[\"invoke\",877,0,\"mul\",[\"f64:1\",\"f64:13830554455654793216\"]],[\"invoke\",882,0,\"mul\",[\"f64:1\",\"f64:4618760256179416344\"]],[\"invoke\",887,0,\"mul\",[\"f64:9223372036854775809\",\"f64:18442240474082181120\"]],[\"invoke\",893,0,\"mul\",[\"f64:9223372036854775809\",\"f64:9221120237041090560\"]],[\"invoke\",902,0,\"mul\",[\"f64:4503599627370496\",\"f64:0\"]],[\"invoke\",907,0,\"mul\",[\"f64:9227875636482146304\",\"f64:9227875636482146304\"]],[\"invoke\",912,0,\"mul\",[\"f64:9227875636482146304\",\"f64:4602678819172646912\"]],[\"invoke\",917,0,\"mul\",[\"f64:4503599627370496\",\"f64:13830554455654793216\"]],[\"invoke\",922,0,\"mul\",[\"f64:4503599627370496\",\"f64:4618760256179416344\"]],[\"invoke\",927,0,\"mul\",[\"f64:9227875636482146304\",\"f64:18442240474082181120\"]],[\"invoke\",933,0,\"mul\",[\"f64:9227875636482146304\",\"f64:9221120237041090560\"]],[\"invoke\",941,0,\"mul\",[\"f64:4602678819172646912\",\"f64:9223372036854775808\"]],[\"invoke\",946,0,\"mul\",[\"f64:4602678819172646912\",\"f64:1\"]],[\"invoke\",951,0,\"mul\",[\"f64:13826050856027422720\",\"f64:13826050856027422720\"]],[\"invoke\",956,0,\"mul\",[\"f64:13826050856027422720\",\"f64:4607182418800017408\"]],[\"invoke\",962,0,\"mul\",[\"f64:4602678819172646912\",\"f64:4618760256179416344\"]],[\"invoke\",967,0,\"mul\",[\"f64:13826050856027422720\",\"f64:18442240474082181120\"]],[\"invoke\",973,0,\"mul\",[\"f64:13826050856027422720\",\"f64:9221120237041090560\"]],[\"invoke\",981,0,\"mul\",[\"f64:4607182418800017408\",\"f64:9223372036854775808\"]],[\"invoke\",986,0,\"mul\",[\"f64:4607182418800017408\",\"f64:1\"]],[\"invoke\",991,0,\"mul\",[\"f64:13830554455654793216\",\"f64:13826050856027422720\"]],[\"invoke\",996,0,\"mul\",[\"f64:13830554455654793216\",\"f64:4607182418800017408\"]],[\"invoke\",1001,0,\"mul\",[\"f64:4607182418800017408\",\"f64:13842132293034192152\"]],[\"invoke\",1006,0,\"mul\",[\"f64:4607182418800017408\",\"f64:9218868437227405311\"]],[\"invoke\",1011,0,\"mul\",[\"f64:13830554455654793216\",\"f64:18444492273895866368\"]],[\"invoke\",1020,0,\"mul\",[\"f64:13842132293034192152\",\"f64:0\"]],[\"invoke\",1025,0,\"mul\",[\"f64:4618760256179416344\",\"f64:9223372036854775809\"]],[\"invoke\",1031,0,\"mul\",[\"f64:13842132293034192152\",\"f64:13826050856027422720\"]],[\"invoke\",1036,0,\"mul\",[\"f64:13842132293034192152\",\"f64:4607182418800017408\"]],[\"invoke\",1041,0,\"mul\",[\"f64:4618760256179416344\",\"f64:13842132293034192152\"]],[\"invoke\",1046,0,\"mul\",[\"f64:4618760256179416344\",\"f64:9218868437227405311\"]],[\"invoke\",1051,0,\"mul\",[\"f64:13842132293034192152\",\"f64:18444492273895866368\"]],[\"invoke\",1060,0,\"mul\",[\"f64:18442240474082181119\",\"f64:0\"]],[\"invoke\",1065,0,\"mul\",[\"f64:9218868437227405311\",\"f64:9223372036854775809\"]],[\"invoke\",1070,0,\"mul\",[\"f64:9218868437227405311\",\"f64:4503599627370496\"]],[\"invoke\",1075,0,\"mul\",[\"f64:18442240474082181119\",\"f64:13830554455654793216\"]],[\"invoke\",1080,0,\"mul\",[\"f64:18442240474082181119\",\"f64:4618760256179416344\"]],[\"invoke\",1085,0,\"mul\",[\"f64:9218868437227405311\",\"f64:18442240474082181119\"]],[\"invoke\",1090,0,\"mul\",[\"f64:9218868437227405311\",\"f64:9218868437227405312\"]],[\"invoke\",1100,0,\"mul\",[\"f64:18442240474082181120\",\"f64:0\"]],[\"invoke\",1105,0,\"mul\",[\"f64:9218868437227405312\",\"f64:9223372036854775809\"]],[\"invoke\",1110,0,\"mul\",[\"f64:9218868437227405312\",\"f64:4503599627370496\"]],[\"invoke\",1115,0,\"mul\",[\"f64:18442240474082181120\",\"f64:13830554455654793216\"]],[\"invoke\",1120,0,\"mul\",[\"f64:18442240474082181120\",\"f64:4618760256179416344\"]],[\"invoke\",1125,0,\"mul\",[\"f64:9218868437227405312\",\"f64:18442240474082181119\"]],[\"invoke\",1130,0,\"mul\",[\"f64:9218868437227405312\",\"f64:9218868437227405312\"]],[\"invoke\",1139,0,\"mul\",[\"f64:18444492273895866368\",\"f64:9223372036854775808\"]],[\"invoke\",1149,0,\"mul\",[\"f64:18444492273895866368\",\"f64:1\"]],[\"invoke\",1159,0,\"mul\",[\"f64:9221120237041090560\",\"f64:9227875636482146304\"]],[\"invoke\",1169,0,\"mul\",[\"f64:9221120237041090560\",\"f64:4602678819172646912\"]],[\"invoke\",1179,0,\"mul\",[\"f64:18444492273895866368\",\"f64:13842132293034192152\"]],[\"invoke\",1191,0,\"mul\",[\"f64:9221120237041090560\",\"f64:18442240474082181119\"]],[\"invoke\",1201,0,\"mul\",[\"f64:9221120237041090560\",\"f64:9218868437227405312\"]],[\"invoke\",1219,0,\"div\",[\"f64:9223372036854775808\",\"f64:9223372036854775808\"]],[\"invoke\",1224,0,\"div\",[\"f64:9223372036854775808\",\"f64:1\"]],[\"invoke\",1229,0,\"div\",[\"f64:0\",\"f64:9227875636482146304\"]],[\"invoke\",1234,0,\"div\",[\"f64:0\",\"f64:4602678819172646912\"]],[\"invoke\",1239,0,\"div\",[\"f64:9223372036854775808\",\"f64:13842132293034192152\"]],[\"invoke\",1244,0,\"div\",[\"f64:9223372036854775808\",\"f64:9218868437227405311\"]],[\"invoke\",1249,0,\"div\",[\"f64:0\",\"f64:18442240474082181120\"]],[\"invoke\",1257,0,\"div\",[\"f64:0\",\"f64:9221120237041090560\"]],[\"invoke\",1263,0,\"div\",[\"f64:9223372036854775809\",\"f64:9223372036854775809\"]],[\"invoke\",1269,0,\"div\",[\"f64:1\",\"f64:9227875636482146304\"]],[\"invoke\",1274,0,\"div\",[\"f64:1\",\"f64:4602678819172646912\"]],[\"invoke\",1279,0,\"div\",[\"f64:9223372036854775809\",\"f64:13842132293034192152\"]],[\"invoke\",1284,0,\"div\",[\"f64:9223372036854775809\",\"f64:9218868437227405311\"]],[\"invoke\",1289,0,\"div\",[\"f64:1\",\"f64:18442240474082181120\"]],[\"invoke\",1297,0,\"div\",[\"f64:1\",\"f64:9221120237041090560\"]],[\"invoke\",1303,0,\"div\",[\"f64:9227875636482146304\",\"f64:9223372036854775809\"]],[\"invoke\",1308,0,\"div\",[\"f64:9227875636482146304\",\"f64:4503599627370496\"]],[\"invoke\",1313,0,\"div\",[\"f64:4503599627370496\",\"f64:13826050856027422720\"]],[\"invoke\",1318,0,\"div\",[\"f64:4503599627370496\",\"f64:4607182418800017408\"]],[\"invoke\",1323,0,\"div\",[\"f64:9227875636482146304\",\"f64:18442240474082181119\"]],[\"invoke\",1328,0,\"div\",[\"f64:9227875636482146304\",\"f64:9218868437227405312\"]],[\"invoke\",1337,0,\"div\",[\"f64:4503599627370496\",\"f64:9221120237041090560\"]],[\"invoke\",1343,0,\"div\",[\"f64:13826050856027422720\",\"f64:9223372036854775809\"]],[\"invoke\",1348,0,\"div\",[\"f64:13826050856027422720\",\"f64:4503599627370496\"]],[\"invoke\",1353,0,\"div\",[\"f64:4602678819172646912\",\"f64:13826050856027422720\"]],[\"invoke\",1358,0,\"div\",[\"f64:4602678819172646912\",\"f64:4607182418800017408\"]],[\"invoke\",1363,0,\"div\",[\"f64:13826050856027422720\",\"f64:18442240474082181119\"]],[\"invoke\",1368,0,\"div\",[\"f64:13826050856027422720\",\"f64:9218868437227405312\"]],[\"invoke\",1375,0,\"div\",[\"f64:4602678819172646912\",\"f64:18444492273895866368\"]],[\"invoke\",1382,0,\"div\",[\"f64:4607182418800017408\",\"f64:0\"]],[\"invoke\",1387,0,\"div\",[\"f64:13830554455654793216\",\"f64:9227875636482146304\"]],[\"invoke\",1392,0,\"div\",[\"f64:13830554455654793216\",\"f64:4602678819172646912\"]],[\"invoke\",1397,0,\"div\",[\"f64:4607182418800017408\",\"f64:13830554455654793216\"]],[\"invoke\",1403,0,\"div\",[\"f64:13830554455654793216\",\"f64:18442240474082181119\"]],[\"invoke\",1408,0,\"div\",[\"f64:13830554455654793216\",\"f64:9218868437227405312\"]],[\"invoke\",1415,0,\"div\",[\"f64:4607182418800017408\",\"f64:18444492273895866368\"]],[\"invoke\",1422,0,\"div\",[\"f64:4618760256179416344\",\"f64:0\"]],[\"invoke\",1427,0,\"div\",[\"f64:13842132293034192152\",\"f64:9227875636482146304\"]],[\"invoke\",1432,0,\"div\",[\"f64:13842132293034192152\",\"f64:4602678819172646912\"]],[\"invoke\",1437,0,\"div\",[\"f64:4618760256179416344\",\"f64:13830554455654793216\"]],[\"invoke\",1442,0,\"div\",[\"f64:4618760256179416344\",\"f64:4618760256179416344\"]],[\"invoke\",1447,0,\"div\",[\"f64:13842132293034192152\",\"f64:18442240474082181120\"]],[\"invoke\",1453,0,\"div\",[\"f64:13842132293034192152\",\"f64:9221120237041090560\"]],[\"invoke\",1461,0,\"div\",[\"f64:9218868437227405311\",\"f64:9223372036854775808\"]],[\"invoke\",1466,0,\"div\",[\"f64:9218868437227405311\",\"f64:1\"]],[\"invoke\",1472,0,\"div\",[\"f64:18442240474082181119\",\"f64:4602678819172646912\"]],[\"invoke\",1477,0,\"div\",[\"f64:9218868437227405311\",\"f64:13830554455654793216\"]],[\"invoke\",1482,0,\"div\",[\"f64:9218868437227405311\",\"f64:4618760256179416344\"]],[\"invoke\",1487,0,\"div\",[\"f64:18442240474082181119\",\"f64:18442240474082181120\"]],[\"invoke\",1493,0,\"div\",[\"f64:18442240474082181119\",\"f64:9221120237041090560\"]],[\"invoke\",1501,0,\"div\",[\"f64:9218868437227405312\",\"f64:9223372036854775808\"]],[\"invoke\",1506,0,\"div\",[\"f64:9218868437227405312\",\"f64:1\"]],[\"invoke\",1511,0,\"div\",[\"f64:18442240474082181120\",\"f64:13826050856027422720\"]],[\"invoke\",1516,0,\"div\",[\"f64:18442240474082181120\",\"f64:4607182418800017408\"]],[\"invoke\",1521,0,\"div\",[\"f64:9218868437227405312\",\"f64:13842132293034192152\"]],[\"invoke\",1526,0,\"div\",[\"f64:9218868437227405312\",\"f64:9218868437227405311\"]],[\"invoke\",1531,0,\"div\",[\"f64:18442240474082181120\",\"f64:18444492273895866368\"]],[\"invoke\",1543,0,\"div\",[\"f64:9221120237041090560\",\"f64:9223372036854775808\"]],[\"invoke\",1553,0,\"div\",[\"f64:9221120237041090560\",\"f64:1\"]],[\"invoke\",1563,0,\"div\",[\"f64:18444492273895866368\",\"f64:13826050856027422720\"]],[\"invoke\",1573,0,\"div\",[\"f64:18444492273895866368\",\"f64:4607182418800017408\"]],[\"invoke\",1583,0,\"div\",[\"f64:9221120237041090560\",\"f64:13842132293034192152\"]],[\"invoke\",1593,0,\"div\",[\"f64:9221120237041090560\",\"f64:9218868437227405311\"]],[\"invoke\",1603,0,\"div\",[\"f64:18444492273895866368\",\"f64:18444492273895866368\"]],[\"invoke\",1620,0,\"min\",[\"f64:9223372036854775808\",\"f64:0\"]],[\"invoke\",1625,0,\"min\",[\"f64:0\",\"f64:9223372036854775809\"]],[\"invoke\",1630,0,\"min\",[\"f64:0\",\"f64:4503599627370496\"]],[\"invoke\",1635,0,\"min\",[\"f64:9223372036854775808\",\"f64:13830554455654793216\"]],[\"invoke\",1641,0,\"min\",[\"f64:0\",\"f64:13842132293034192152\"]],[\"invoke\",1646,0,\"min\",[\"f64:0\",\"f64:9218868437227405311\"]],[\"invoke\",1651,0,\"min\",[\"f64:9223372036854775808\",\"f64:18444492273895866368\"]],[\"invoke\",1660,0,\"min\",[\"f64:9223372036854775809\",\"f64:0\"]],[\"invoke\",1665,0,\"min\",[\"f64:1\",\"f64:9223372036854775809\"]],[\"invoke\",1670,0,\"min\",[\"f64:1\",\"f64:4503599627370496\"]],[\"invoke\",1675,0,\"min\",[\"f64:9223372036854775809\",\"f64:13830554455654793216\"]],[\"invoke\",1680,0,\"min\",[\"f64:9223372036854775809\",\"f64:4618760256179416344\"]],[\"invoke\",1685,0,\"min\",[\"f64:1\",\"f64:18442240474082181119\"]],[\"invoke\",1690,0,\"min\",[\"f64:1\",\"f64:9218868437227405312\"]],[\"invoke\",1699,0,\"min\",[\"f64:9227875636482146304\",\"f64:9223372036854775808\"]],[\"invoke\",1704,0,\"min\",[\"f64:9227875636482146304\",\"f64:1\"]],[\"invoke\",1710,0,\"min\",[\"f64:4503599627370496\",\"f64:4503599627370496\"]],[\"invoke\",1715,0,\"min\",[\"f64:9227875636482146304\",\"f64:13830554455654793216\"]],[\"invoke\",1720,0,\"min\",[\"f64:9227875636482146304\",\"f64:4618760256179416344\"]],[\"invoke\",1725,0,\"min\",[\"f64:4503599627370496\",\"f64:18442240474082181119\"]],[\"invoke\",1730,0,\"min\",[\"f64:4503599627370496\",\"f64:9218868437227405312\"]],[\"invoke\",1739,0,\"min\",[\"f64:13826050856027422720\",\"f64:9223372036854775808\"]],[\"invoke\",1744,0,\"min\",[\"f64:13826050856027422720\",\"f64:1\"]],[\"invoke\",1749,0,\"min\",[\"f64:4602678819172646912\",\"f64:9227875636482146304\"]],[\"invoke\",1754,0,\"min\",[\"f64:4602678819172646912\",\"f64:4602678819172646912\"]],[\"invoke\",1759,0,\"min\",[\"f64:13826050856027422720\",\"f64:13842132293034192152\"]],[\"invoke\",1764,0,\"min\",[\"f64:13826050856027422720\",\"f64:9218868437227405311\"]],[\"invoke\",1769,0,\"min\",[\"f64:4602678819172646912\",\"f64:18442240474082181120\"]],[\"invoke\",1779,0,\"min\",[\"f64:13830554455654793216\",\"f64:9223372036854775808\"]],[\"invoke\",1784,0,\"min\",[\"f64:13830554455654793216\",\"f64:1\"]],[\"invoke\",1789,0,\"min\",[\"f64:4607182418800017408\",\"f64:9227875636482146304\"]],[\"invoke\",1794,0,\"min\",[\"f64:4607182418800017408\",\"f64:4602678819172646912\"]],[\"invoke\",1799,0,\"min\",[\"f64:13830554455654793216\",\"f64:13842132293034192152\"]],[\"invoke\",1804,0,\"min\",[\"f64:13830554455654793216\",\"f64:9218868437227405311\"]],[\"invoke\",1809,0,\"min\",[\"f64:4607182418800017408\",\"f64:18442240474082181120\"]],[\"invoke\",1817,0,\"min\",[\"f64:4607182418800017408\",\"f64:9221120237041090560\"]],[\"invoke\",1823,0,\"min\",[\"f64:13842132293034192152\",\"f64:9223372036854775809\"]],[\"invoke\",1828,0,\"min\",[\"f64:13842132293034192152\",\"f64:4503599627370496\"]],[\"invoke\",1833,0,\"min\",[\"f64:4618760256179416344\",\"f64:13826050856027422720\"]],[\"invoke\",1838,0,\"min\",[\"f64:4618760256179416344\",\"f64:4607182418800017408\"]],[\"invoke\",1844,0,\"min\",[\"f64:13842132293034192152\",\"f64:9218868437227405311\"]],[\"invoke\",1849,0,\"min\",[\"f64:4618760256179416344\",\"f64:18442240474082181120\"]],[\"invoke\",1857,0,\"min\",[\"f64:4618760256179416344\",\"f64:9221120237041090560\"]],[\"invoke\",1863,0,\"min\",[\"f64:18442240474082181119\",\"f64:9223372036854775809\"]],[\"invoke\",1868,0,\"min\",[\"f64:18442240474082181119\",\"f64:4503599627370496\"]],[\"invoke\",1873,0,\"min\",[\"f64:9218868437227405311\",\"f64:13826050856027422720\"]],[\"invoke\",1878,0,\"min\",[\"f64:9218868437227405311\",\"f64:4607182418800017408\"]],[\"invoke\",1883,0,\"min\",[\"f64:18442240474082181119\",\"f64:18442240474082181119\"]],[\"invoke\",1888,0,\"min\",[\"f64:18442240474082181119\",\"f64:9218868437227405312\"]],[\"invoke\",1895,0,\"min\",[\"f64:9218868437227405311\",\"f64:18444492273895866368\"]],[\"invoke\",1902,0,\"min\",[\"f64:9218868437227405312\",\"f64:0\"]],[\"invoke\",1908,0,\"min\",[\"f64:18442240474082181120\",\"f64:4503599627370496\"]],[\"invoke\",1913,0,\"min\",[\"f64:9218868437227405312\",\"f64:13826050856027422720\"]],[\"invoke\",1918,0,\"min\",[\"f64:9218868437227405312\",\"f64:4607182418800017408\"]],[\"invoke\",1923,0,\"min\",[\"f64:18442240474082181120\",\"f64:18442240474082181119\"]],[\"invoke\",1928,0,\"min\",[\"f64:18442240474082181120\",\"f64:9218868437227405312\"]],[\"invoke\",1935,0,\"min\",[\"f64:9218868437227405312\",\"f64:18444492273895866368\"]],[\"invoke\",1945,0,\"min\",[\"f64:9221120237041090560\",\"f64:0\"]],[\"invoke\",1955,0,\"min\",[\"f64:18444492273895866368\",\"f64:9227875636482146304\"]],[\"invoke\",1965,0,\"min\",[\"f64:18444492273895866368\",\"f64:4602678819172646912\"]],[\"invoke\",1975,0,\"min\",[\"f64:9221120237041090560\",\"f64:13830554455654793216\"]],[\"invoke\",1985,0,\"min\",[\"f64:9221120237041090560\",\"f64:4618760256179416344\"]],[\"invoke\",1995,0,\"min\",[\"f64:18444492273895866368\",\"f64:18442240474082181120\"]],[\"invoke\",2011,0,\"min\",[\"f64:9221120237041090560\",\"f64:18444492273895866368\"]],[\"invoke\",2022,0,\"max\",[\"f64:0\",\"f64:0\"]],[\"invoke\",2027,0,\"max\",[\"f64:9223372036854775808\",\"f64:9227875636482146304\"]],[\"invoke\",2032,0,\"max\",[\"f64:9223372036854775808\",\"f64:4602678819172646912\"]],[\"invoke\",2037,0,\"max\",[\"f64:0\",\"f64:13830554455654793216\"]],[\"invoke\",2042,0,\"max\",[\"f64:0\",\"f64:4618760256179416344\"]],[\"invoke\",2047,0,\"max\",[\"f64:9223372036854775808\",\"f64:18442240474082181120\"]],[\"invoke\",2053,0,\"max\",[\"f64:9223372036854775808\",\"f64:9221120237041090560\"]],[\"invoke\",2061,0,\"max\",[\"f64:1\",\"f64:9223372036854775808\"]],[\"invoke\",2066,0,\"max\",[\"f64:1\",\"f64:1\"]],[\"invoke\",2071,0,\"max\",[\"f64:9223372036854775809\",\"f64:13826050856027422720\"]],[\"invoke\",2076,0,\"max\",[\"f64:9223372036854775809\",\"f64:4607182418800017408\"]],[\"invoke\",2082,0,\"max\",[\"f64:1\",\"f64:4618760256179416344\"]],[\"invoke\",2087,0,\"max\",[\"f64:9223372036854775809\",\"f64:18442240474082181120\"]],[\"invoke\",2093,0,\"max\",[\"f64:9223372036854775809\",\"f64:9221120237041090560\"]],[\"invoke\",2101,0,\"max\",[\"f64:4503599627370496\",\"f64:9223372036854775808\"]],[\"invoke\",2106,0,\"max\",[\"f64:4503599627370496\",\"f64:1\"]],[\"invoke\",2111,0,\"max\",[\"f64:9227875636482146304\",\"f64:13826050856027422720\"]],[\"invoke\",2116,0,\"max\",[\"f64:9227875636482146304\",\"f64:4607182418800017408\"]],[\"invoke\",2121,0,\"max\",[\"f64:4503599627370496\",\"f64:13842132293034192152\"]],[\"invoke\",2126,0,\"max\",[\"f64:4503599627370496\",\"f64:9218868437227405311\"]],[\"invoke\",2131,0,\"max\",[\"f64:9227875636482146304\",\"f64:18444492273895866368\"]],[\"invoke\",2140,0,\"max\",[\"f64:13826050856027422720\",\"f64:0\"]],[\"invoke\",2145,0,\"max\",[\"f64:4602678819172646912\",\"f64:9223372036854775809\"]],[\"invoke\",2151,0,\"max\",[\"f64:13826050856027422720\",\"f64:13826050856027422720\"]],[\"invoke\",2156,0,\"max\",[\"f64:13826050856027422720\",\"f64:4607182418800017408\"]],[\"invoke\",2161,0,\"max\",[\"f64:4602678819172646912\",\"f64:13842132293034192152\"]],[\"invoke\",2166,0,\"max\",[\"f64:4602678819172646912\",\"f64:9218868437227405311\"]],[\"invoke\",2171,0,\"max\",[\"f64:13826050856027422720\",\"f64:18444492273895866368\"]],[\"invoke\",2180,0,\"max\",[\"f64:13830554455654793216\",\"f64:0\"]],[\"invoke\",2185,0,\"max\",[\"f64:4607182418800017408\",\"f64:9223372036854775809\"]],[\"invoke\",2190,0,\"max\",[\"f64:4607182418800017408\",\"f64:4503599627370496\"]],[\"invoke\",2195,0,\"max\",[\"f64:13830554455654793216\",\"f64:13830554455654793216\"]],[\"invoke\",2200,0,\"max\",[\"f64:13830554455654793216\",\"f64:4618760256179416344\"]],[\"invoke\",2205,0,\"max\",[\"f64:4607182418800017408\",\"f64:18442240474082181119\"]],[\"invoke\",2211,0,\"max\",[\"f64:13830554455654793216\",\"f64:18444492273895866368\"]],[\"invoke\",2220,0,\"max\",[\"f64:13842132293034192152\",\"f64:0\"]],[\"invoke\",2225,0,\"max\",[\"f64:4618760256179416344\",\"f64:9223372036854775809\"]],[\"invoke\",2230,0,\"max\",[\"f64:4618760256179416344\",\"f64:4503599627370496\"]],[\"invoke\",2235,0,\"max\",[\"f64:13842132293034192152\",\"f64:13830554455654793216\"]],[\"invoke\",2240,0,\"max\",[\"f64:13842132293034192152\",\"f64:4618760256179416344\"]],[\"invoke\",2245,0,\"max\",[\"f64:4618760256179416344\",\"f64:18442240474082181119\"]],[\"invoke\",2250,0,\"max\",[\"f64:4618760256179416344\",\"f64:9218868437227405312\"]],[\"invoke\",2259,0,\"max\",[\"f64:18442240474082181119\",\"f64:9223372036854775808\"]],[\"invoke\",2264,0,\"max\",[\"f64:18442240474082181119\",\"f64:1\"]],[\"invoke\",2269,0,\"max\",[\"f64:9218868437227405311\",\"f64:9227875636482146304\"]],[\"invoke\",2274,0,\"max\",[\"f64:9218868437227405311\",\"f64:4602678819172646912\"]],[\"invoke\",2280,0,\"max\",[\"f64:18442240474082181119\",\"f64:4618760256179416344\"]],[\"invoke\",2285,0,\"max\",[\"f64:9218868437227405311\",\"f64:18442240474082181119\"]],[\"invoke\",2290,0,\"max\",[\"f64:9218868437227405311\",\"f64:9218868437227405312\"]],[\"invoke\",2299,0,\"max\",[\"f64:18442240474082181120\",\"f64:9223372036854775808\"]],[\"invoke\",2304,0,\"max\",[\"f64:18442240474082181120\",\"f64:1\"]],[\"invoke\",2309,0,\"max\",[\"f64:9218868437227405312\",\"f64:9227875636482146304\"]],[\"invoke\",2314,0,\"max\",[\"f64:9218868437227405312\",\"f64:4602678819172646912\"]],[\"invoke\",2319,0,\"max\",[\"f64:18442240474082181120\",\"f64:13842132293034192152\"]],[\"invoke\",2324,0,\"max\",[\"f64:18442240474082181120\",\"f64:9218868437227405311\"]],[\"invoke\",2329,0,\"max\",[\"f64:9218868437227405312\",\"f64:18442240474082181120\"]],[\"invoke\",2337,0,\"max\",[\"f64:9218868437227405312\",\"f64:9221120237041090560\"]],[\"invoke\",2347,0,\"max\",[\"f64:18444492273895866368\",\"f64:9223372036854775809\"]],[\"invoke\",2359,0,\"max\",[\"f64:9221120237041090560\",\"f64:9227875636482146304\"]],[\"invoke\",2369,0,\"max\",[\"f64:9221120237041090560\",\"f64:4602678819172646912\"]],[\"invoke\",2379,0,\"max\",[\"f64:18444492273895866368\",\"f64:13842132293034192152\"]],[\"invoke\",2389,0,\"max\",[\"f64:18444492273895866368\",\"f64:9218868437227405311\"]],[\"invoke\",2399,0,\"max\",[\"f64:9221120237041090560\",\"f64:18442240474082181120\"]],[\"invoke\",2415,0,\"max\",[\"f64:9221120237041090560\",\"f64:9221120237041090560\"]],[\"invoke\",2423,0,\"sqrt\",[\"f64:9227875636482146304\"]],[\"invoke\",2428,0,\"sqrt\",[\"f64:4607182418800017408\"]],[\"invoke\",2433,0,\"sqrt\",[\"f64:18442240474082181120\"]],[\"invoke\",2440,0,\"floor\",[\"f64:0\"]],[\"invoke\",2445,0,\"floor\",[\"f64:13826050856027422720\"]],[\"invoke\",2450,0,\"floor\",[\"f64:4618760256179416344\"]],[\"invoke\",2457,0,\"floor\",[\"f64:9221120237041090560\"]],[\"invoke\",2463,0,\"ceil\",[\"f64:9227875636482146304\"]],[\"invoke\",2468,0,\"ceil\",[\"f64:4607182418800017408\"]],[\"invoke\",2473,0,\"ceil\",[\"f64:18442240474082181120\"]],[\"invoke\",2480,0,\"trunc\",[\"f64:0\"]],[\"invoke\",2485,0,\"trunc\",[\"f64:13826050856027422720\"]],[\"invoke\",2490,0,\"trunc\",[\"f64:4618760256179416344\"]],[\"invoke\",2495,0,\"trunc\",[\"f64:18444492273895866368\"]],[\"invoke\",2502,0,\"nearest\",[\"f64:1\"]],[\"invoke\",2507,0,\"nearest\",[\"f64:13830554455654793216\"]],[\"invoke\",2512,0,\"nearest\",[\"f64:9218868437227405311\"]],[\"file\",\"f32_cmp.wast\"],[\"module\",4,2],[\"invoke\",13,0,\"eq\",[\"f32:2147483648\",\"f32:2147483648\"]],[\"invoke\",18,0,\"eq\",[\"f32:2147483648\",\"f32:1\"]],[\"invoke\",23,0,\"eq\",[\"f32:0\",\"f32:2155872256\"]],[\"invoke\",28,0,\"eq\",[\"f32:0\",\"f32:1056964608\"]],[\"invoke\",33,0,\"eq\",[\"f32:2147483648\",\"f32:3234402267\"]],[\"invoke\",38,0,\"eq\",[\"f32:2147483648\",\"f32:2139095039\"]],[\"invoke\",43,0,\"eq\",[\"f32:0\",\"f32:4286578688\"]],[\"invoke\",51,0,\"eq\",[\"f32:0\",\"f32:2143289344\"]],[\"invoke\",56,0,\"eq\",[\"f32:1\",\"f32:0\"]],[\"invoke\",61,0,\"eq\",[\"f32:2147483649\",\"f32:2155872256\"]],[\"invoke\",66,0,\"eq\",[\"f32:2147483649\",\"f32:1056964608\"]],[\"invoke\",71,0,\"eq\",[\"f32:1\",\"f32:3212836864\"]],[\"invoke\",76,0,\"eq\",[\"f32:1\",\"f32:1086918619\"]],[\"invoke\",81,0,\"eq\",[\"f32:2147483649\",\"f32:4286578688\"]],[\"invoke\",87,0,\"eq\",[\"f32:2147483649\",\"f32:2143289344\"]],[\"invoke\",94,0,\"eq\",[\"f32:2155872256\",\"f32:0\"]],[\"invoke\",99,0,\"eq\",[\"f32:8388608\",\"f32:2147483649\"]],[\"invoke\",104,0,\"eq\",[\"f32:8388608\",\"f32:8388608\"]],[\"invoke\",109,0,\"eq\",[\"f32:2155872256\",\"f32:3212836864\"]],[\"invoke\",114,0,\"eq\",[\"f32:2155872256\",\"f32:1086918619\"]],[\"invoke\",119,0,\"eq\",[\"f32:8388608\",\"f32:4286578687\"]],[\"invoke\",124,0,\"eq\",[\"f32:8388608\",\"f32:2139095040\"]],[\"invoke\",131,0,\"eq\",[\"f32:8388608\",\"f32:2143289344\"]],[\"invoke\",137,0,\"eq\",[\"f32:3204448256\",\"f32:2147483649\"]],[\"invoke\",142,0,\"eq\",[\"f32:3204448256\",\"f32:8388608\"]],[\"invoke\",147,0,\"eq\",[\"f32:1056964608\",\"f32:3204448256\"]],[\"invoke\",152,0,\"eq\",[\"f32:1056964608\",\"f32:1065353216\"]],[\"invoke\",157,0,\"eq\",[\"f32:3204448256\",\"f32:4286578687\"]],[\"invoke\",162,0,\"eq\",[\"f32:3204448256\",\"f32:2139095040\"]],[\"invoke\",167,0,\"eq\",[\"f32:3204448256\",\"f32:2143289344\"]],[\"invoke\",175,0,\"eq\",[\"f32:1065353216\",\"f32:2147483648\"]],[\"invoke\",180,0,\"eq\",[\"f32:1065353216\",\"f32:1\"]],[\"invoke\",185,0,\"eq\",[\"f32:3212836864\",\"f32:3204448256\"]],[\"invoke\",190,0,\"eq\",[\"f32:3212836864\",\"f32:1065353216\"]],[\"invoke\",195,0,\"eq\",[\"f32:1065353216\",\"f32:3234402267\"]],[\"invoke\",200,0,\"eq\",[\"f32:1065353216\",\"f32:2139095039\"]],[\"invoke\",204,0,\"eq\",[\"f32:1065353216\",\"f32:2139095040\"]],[\"invoke\",213,0,\"eq\",[\"f32:3234402267\",\"f32:2147483648\"]],[\"invoke\",218,0,\"eq\",[\"f32:3234402267\",\"f32:1\"]],[\"invoke\",223,0,\"eq\",[\"f32:1086918619\",\"f32:2155872256\"]],[\"invoke\",228,0,\"eq\",[\"f32:1086918619\",\"f32:1056964608\"]],[\"invoke\",233,0,\"eq\",[\"f32:3234402267\",\"f32:3234402267\"]],[\"invoke\",238,0,\"eq\",[\"f32:3234402267\",\"f32:2139095039\"]],[\"invoke\",242,0,\"eq\",[\"f32:3234402267\",\"f32:2139095040\"]],[\"invoke\",249,0,\"eq\",[\"f32:1086918619\",\"f32:4290772992\"]],[\"invoke\",256,0,\"eq\",[\"f32:2139095039\",\"f32:0\"]],[\"invoke\",261,0,\"eq\",[\"f32:4286578687\",\"f32:2155872256\"]],[\"invoke\",266,0,\"eq\",[\"f32:4286578687\",\"f32:1056964608\"]],[\"invoke\",271,0,\"eq\",[\"f32:2139095039\",\"f32:3212836864\"]],[\"invoke\",276,0,\"eq\",[\"f32:2139095039\",\"f32:1086918619\"]],[\"invoke\",281,0,\"eq\",[\"f32:4286578687\",\"f32:4286578688\"]],[\"invoke\",285,0,\"eq\",[\"f32:4286578687\",\"f32:4290772992\"]],[\"invoke\",294,0,\"eq\",[\"f32:4286578688\",\"f32:0\"]],[\"invoke\",299,0,\"eq\",[\"f32:2139095040\",\"f32:2147483649\"]],[\"invoke\",304,0,\"eq\",[\"f32:2139095040\",\"f32:8388608\"]],[\"invoke\",309,0,\"eq\",[\"f32:4286578688\",\"f32:3212836864\"]],[\"invoke\",314,0,\"eq\",[\"f32:4286578688\",\"f32:1086918619\"]],[\"invoke\",319,0,\"eq\",[\"f32:2139095040\",\"f32:4286578687\"]],[\"invoke\",323,0,\"eq\",[\"f32:2139095040\",\"f32:4286578688\"]],[\"invoke\",331,0,\"eq\",[\"f32:2139095040\",\"f32:2143289344\"]],[\"invoke\",341,0,\"eq\",[\"f32:4290772992\",\"f32:2147483649\"]],[\"invoke\",351,0,\"eq\",[\"f32:4290772992\",\"f32:8388608\"]],[\"invoke\",361,0,\"eq\",[\"f32:2143289344\",\"f32:3204448256\"]],[\"invoke\",371,0,\"eq\",[\"f32:2143289344\",\"f32:1065353216\"]],[\"invoke\",381,0,\"eq\",[\"f32:4290772992\",\"f32:4286578687\"]],[\"invoke\",389,0,\"eq\",[\"f32:4290772992\",\"f32:4286578688\"]],[\"invoke\",401,0,\"eq\",[\"f32:4290772992\",\"f32:2143289344\"]],[\"invoke\",415,0,\"ne\",[\"f32:0\",\"f32:2147483648\"]],[\"invoke\",420,0,\"ne\",[\"f32:0\",\"f32:1\"]],[\"invoke\",425,0,\"ne\",[\"f32:2147483648\",\"f32:3204448256\"]],[\"invoke\",430,0,\"ne\",[\"f32:2147483648\",\"f32:1065353216\"]],[\"invoke\",435,0,\"ne\",[\"f32:0\",\"f32:3234402267\"]],[\"invoke\",439,0,\"ne\",[\"f32:0\",\"f32:4286578687\"]],[\"invoke\",444,0,\"ne\",[\"f32:0\",\"f32:2139095040\"]],[\"invoke\",453,0,\"ne\",[\"f32:2147483649\",\"f32:2147483648\"]],[\"invoke\",458,0,\"ne\",[\"f32:2147483649\",\"f32:1\"]],[\"invoke\",463,0,\"ne\",[\"f32:1\",\"f32:2155872256\"]],[\"invoke\",468,0,\"ne\",[\"f32:1\",\"f32:1056964608\"]],[\"invoke\",473,0,\"ne\",[\"f32:2147483649\",\"f32:3234402267\"]],[\"invoke\",477,0,\"ne\",[\"f32:2147483649\",\"f32:4286578687\"]],[\"invoke\",482,0,\"ne\",[\"f32:2147483649\",\"f32:2139095040\"]],[\"invoke\",489,0,\"ne\",[\"f32:1\",\"f32:4290772992\"]],[\"invoke\",496,0,\"ne\",[\"f32:8388608\",\"f32:0\"]],[\"invoke\",501,0,\"ne\",[\"f32:2155872256\",\"f32:2155872256\"]],[\"invoke\",506,0,\"ne\",[\"f32:2155872256\",\"f32:1056964608\"]],[\"invoke\",511,0,\"ne\",[\"f32:8388608\",\"f32:3212836864\"]],[\"invoke\",515,0,\"ne\",[\"f32:8388608\",\"f32:3234402267\"]],[\"invoke\",520,0,\"ne\",[\"f32:8388608\",\"f32:2139095039\"]],[\"invoke\",525,0,\"ne\",[\"f32:2155872256\",\"f32:4290772992\"]],[\"invoke\",534,0,\"ne\",[\"f32:3204448256\",\"f32:0\"]],[\"invoke\",539,0,\"ne\",[\"f32:1056964608\",\"f32:2147483649\"]],[\"invoke\",544,0,\"ne\",[\"f32:1056964608\",\"f32:8388608\"]],[\"invoke\",549,0,\"ne\",[\"f32:3204448256\",\"f32:3212836864\"]],[\"invoke\",553,0,\"ne\",[\"f32:3204448256\",\"f32:3234402267\"]],[\"invoke\",558,0,\"ne\",[\"f32:3204448256\",\"f32:2139095039\"]],[\"invoke\",563,0,\"ne\",[\"f32:1056964608\",\"f32:4286578688\"]],[\"invoke\",571,0,\"ne\",[\"f32:1056964608\",\"f32:2143289344\"]],[\"invoke\",577,0,\"ne\",[\"f32:3212836864\",\"f32:2147483649\"]],[\"invoke\",582,0,\"ne\",[\"f32:3212836864\",\"f32:8388608\"]],[\"invoke\",587,0,\"ne\",[\"f32:1065353216\",\"f32:3204448256\"]],[\"invoke\",592,0,\"ne\",[\"f32:1065353216\",\"f32:1065353216\"]],[\"invoke\",596,0,\"ne\",[\"f32:1065353216\",\"f32:1086918619\"]],[\"invoke\",601,0,\"ne\",[\"f32:3212836864\",\"f32:4286578688\"]],[\"invoke\",607,0,\"ne\",[\"f32:3212836864\",\"f32:2143289344\"]],[\"invoke\",615,0,\"ne\",[\"f32:1086918619\",\"f32:2147483648\"]],[\"invoke\",620,0,\"ne\",[\"f32:1086918619\",\"f32:1\"]],[\"invoke\",625,0,\"ne\",[\"f32:3234402267\",\"f32:3204448256\"]],[\"invoke\",630,0,\"ne\",[\"f32:3234402267\",\"f32:1065353216\"]],[\"invoke\",634,0,\"ne\",[\"f32:3234402267\",\"f32:1086918619\"]],[\"invoke\",639,0,\"ne\",[\"f32:1086918619\",\"f32:4286578687\"]],[\"invoke\",644,0,\"ne\",[\"f32:1086918619\",\"f32:2139095040\"]],[\"invoke\",653,0,\"ne\",[\"f32:4286578687\",\"f32:2147483648\"]],[\"invoke\",658,0,\"ne\",[\"f32:4286578687\",\"f32:1\"]],[\"invoke\",663,0,\"ne\",[\"f32:2139095039\",\"f32:2155872256\"]],[\"invoke\",668,0,\"ne\",[\"f32:2139095039\",\"f32:1056964608\"]],[\"invoke\",672,0,\"ne\",[\"f32:2139095039\",\"f32:1065353216\"]],[\"invoke\",677,0,\"ne\",[\"f32:4286578687\",\"f32:4286578687\"]],[\"invoke\",682,0,\"ne\",[\"f32:4286578687\",\"f32:2139095040\"]],[\"invoke\",689,0,\"ne\",[\"f32:2139095039\",\"f32:4290772992\"]],[\"invoke\",696,0,\"ne\",[\"f32:2139095040\",\"f32:0\"]],[\"invoke\",701,0,\"ne\",[\"f32:4286578688\",\"f32:2155872256\"]],[\"invoke\",706,0,\"ne\",[\"f32:4286578688\",\"f32:1056964608\"]],[\"invoke\",710,0,\"ne\",[\"f32:4286578688\",\"f32:1065353216\"]],[\"invoke\",715,0,\"ne\",[\"f32:2139095040\",\"f32:3234402267\"]],[\"invoke\",720,0,\"ne\",[\"f32:2139095040\",\"f32:2139095039\"]],[\"invoke\",725,0,\"ne\",[\"f32:4286578688\",\"f32:4290772992\"]],[\"invoke\",735,0,\"ne\",[\"f32:4290772992\",\"f32:0\"]],[\"invoke\",745,0,\"ne\",[\"f32:2143289344\",\"f32:2147483649\"]],[\"invoke\",755,0,\"ne\",[\"f32:2143289344\",\"f32:8388608\"]],[\"invoke\",763,0,\"ne\",[\"f32:2143289344\",\"f32:1056964608\"]],[\"invoke\",773,0,\"ne\",[\"f32:4290772992\",\"f32:3234402267\"]],[\"invoke\",783,0,\"ne\",[\"f32:4290772992\",\"f32:2139095039\"]],[\"invoke\",793,0,\"ne\",[\"f32:2143289344\",\"f32:4286578688\"]],[\"invoke\",809,0,\"ne\",[\"f32:2143289344\",\"f32:2143289344\"]],[\"invoke\",817,0,\"lt\",[\"f32:2147483648\",\"f32:2147483649\"]],[\"invoke\",822,0,\"lt\",[\"f32:2147483648\",\"f32:8388608\"]],[\"invoke\",826,0,\"lt\",[\"f32:2147483648\",\"f32:1056964608\"]],[\"invoke\",831,0,\"lt\",[\"f32:0\",\"f32:3212836864\"]],[\"invoke\",836,0,\"lt\",[\"f32:0\",\"f32:1086918619\"]],[\"invoke\",841,0,\"lt\",[\"f32:2147483648\",\"f32:4286578688\"]],[\"invoke\",847,0,\"lt\",[\"f32:2147483648\",\"f32:2143289344\"]],[\"invoke\",855,0,\"lt\",[\"f32:1\",\"f32:2147483648\"]],[\"invoke\",860,0,\"lt\",[\"f32:1\",\"f32:1\"]],[\"invoke\",864,0,\"lt\",[\"f32:1\",\"f32:8388608\"]],[\"invoke\",869,0,\"lt\",[\"f32:2147483649\",\"f32:3212836864\"]],[\"invoke\",874,0,\"lt\",[\"f32:2147483649\",\"f32:1086918619\"]],[\"invoke\",879,0,\"lt\",[\"f32:1\",\"f32:4286578687\"]],[\"invoke\",884,0,\"lt\",[\"f32:1\",\"f32:2139095040\"]],[\"invoke\",893,0,\"lt\",[\"f32:2155872256\",\"f32:2147483648\"]],[\"invoke\",898,0,\"lt\",[\"f32:2155872256\",\"f32:1\"]],[\"invoke\",903,0,\"lt\",[\"f32:8388608\",\"f32:2155872256\"]],[\"invoke\",907,0,\"lt\",[\"f32:8388608\",\"f32:3204448256\"]],[\"invoke\",912,0,\"lt\",[\"f32:8388608\",\"f32:1065353216\"]],[\"invoke\",917,0,\"lt\",[\"f32:2155872256\",\"f32:4286578687\"]],[\"invoke\",922,0,\"lt\",[\"f32:2155872256\",\"f32:2139095040\"]],[\"invoke\",929,0,\"lt\",[\"f32:8388608\",\"f32:4290772992\"]],[\"invoke\",936,0,\"lt\",[\"f32:1056964608\",\"f32:0\"]],[\"invoke\",941,0,\"lt\",[\"f32:3204448256\",\"f32:2155872256\"]],[\"invoke\",945,0,\"lt\",[\"f32:3204448256\",\"f32:3204448256\"]],[\"invoke\",950,0,\"lt\",[\"f32:3204448256\",\"f32:1065353216\"]],[\"invoke\",955,0,\"lt\",[\"f32:1056964608\",\"f32:3234402267\"]],[\"invoke\",960,0,\"lt\",[\"f32:1056964608\",\"f32:2139095039\"]],[\"invoke\",965,0,\"lt\",[\"f32:3204448256\",\"f32:4290772992\"]],[\"invoke\",974,0,\"lt\",[\"f32:3212836864\",\"f32:0\"]],[\"invoke\",979,0,\"lt\",[\"f32:1065353216\",\"f32:2147483649\"]],[\"invoke\",983,0,\"lt\",[\"f32:1065353216\",\"f32:2155872256\"]],[\"invoke\",988,0,\"lt\",[\"f32:1065353216\",\"f32:1056964608\"]],[\"invoke\",993,0,\"lt\",[\"f32:3212836864\",\"f32:3234402267\"]],[\"invoke\",998,0,\"lt\",[\"f32:3212836864\",\"f32:2139095039\"]],[\"invoke\",1003,0,\"lt\",[\"f32:1065353216\",\"f32:4286578688\"]],[\"invoke\",1011,0,\"lt\",[\"f32:1065353216\",\"f32:2143289344\"]],[\"invoke\",1017,0,\"lt\",[\"f32:3234402267\",\"f32:2147483649\"]],[\"invoke\",1021,0,\"lt\",[\"f32:3234402267\",\"f32:2155872256\"]],[\"invoke\",1026,0,\"lt\",[\"f32:3234402267\",\"f32:1056964608\"]],[\"invoke\",1031,0,\"lt\",[\"f32:1086918619\",\"f32:3212836864\"]],[\"invoke\",1036,0,\"lt\",[\"f32:1086918619\",\"f32:1086918619\"]],[\"invoke\",1041,0,\"lt\",[\"f32:3234402267\",\"f32:4286578688\"]],[\"invoke\",1047,0,\"lt\",[\"f32:3234402267\",\"f32:2143289344\"]],[\"invoke\",1055,0,\"lt\",[\"f32:2139095039\",\"f32:2147483648\"]],[\"invoke\",1059,0,\"lt\",[\"f32:2139095039\",\"f32:2147483649\"]],[\"invoke\",1064,0,\"lt\",[\"f32:2139095039\",\"f32:8388608\"]],[\"invoke\",1069,0,\"lt\",[\"f32:4286578687\",\"f32:3212836864\"]],[\"invoke\",1074,0,\"lt\",[\"f32:4286578687\",\"f32:1086918619\"]],[\"invoke\",1079,0,\"lt\",[\"f32:2139095039\",\"f32:4286578687\"]],[\"invoke\",1084,0,\"lt\",[\"f32:2139095039\",\"f32:2139095040\"]],[\"invoke\",1093,0,\"lt\",[\"f32:4286578688\",\"f32:2147483648\"]],[\"invoke\",1097,0,\"lt\",[\"f32:4286578688\",\"f32:2147483649\"]],[\"invoke\",1102,0,\"lt\",[\"f32:4286578688\",\"f32:8388608\"]],[\"invoke\",1107,0,\"lt\",[\"f32:2139095040\",\"f32:3204448256\"]],[\"invoke\",1112,0,\"lt\",[\"f32:2139095040\",\"f32:1065353216\"]],[\"invoke\",1117,0,\"lt\",[\"f32:4286578688\",\"f32:4286578687\"]],[\"invoke\",1122,0,\"lt\",[\"f32:4286578688\",\"f32:2139095040\"]],[\"invoke\",1129,0,\"lt\",[\"f32:2139095040\",\"f32:4290772992\"]],[\"invoke\",1137,0,\"lt\",[\"f32:2143289344\",\"f32:2147483648\"]],[\"invoke\",1147,0,\"lt\",[\"f32:2143289344\",\"f32:1\"]],[\"invoke\",1157,0,\"lt\",[\"f32:4290772992\",\"f32:3204448256\"]],[\"invoke\",1167,0,\"lt\",[\"f32:4290772992\",\"f32:1065353216\"]],[\"invoke\",1177,0,\"lt\",[\"f32:2143289344\",\"f32:3234402267\"]],[\"invoke\",1187,0,\"lt\",[\"f32:2143289344\",\"f32:2139095039\"]],[\"invoke\",1197,0,\"lt\",[\"f32:4290772992\",\"f32:4290772992\"]],[\"invoke\",1214,0,\"le\",[\"f32:2147483648\",\"f32:0\"]],[\"invoke\",1218,0,\"le\",[\"f32:2147483648\",\"f32:1\"]],[\"invoke\",1223,0,\"le\",[\"f32:0\",\"f32:2155872256\"]],[\"invoke\",1228,0,\"le\",[\"f32:0\",\"f32:1056964608\"]],[\"invoke\",1233,0,\"le\",[\"f32:2147483648\",\"f32:3234402267\"]],[\"invoke\",1238,0,\"le\",[\"f32:2147483648\",\"f32:2139095039\"]],[\"invoke\",1243,0,\"le\",[\"f32:0\",\"f32:4286578688\"]],[\"invoke\",1251,0,\"le\",[\"f32:0\",\"f32:2143289344\"]],[\"invoke\",1256,0,\"le\",[\"f32:1\",\"f32:0\"]],[\"invoke\",1261,0,\"le\",[\"f32:2147483649\",\"f32:2155872256\"]],[\"invoke\",1266,0,\"le\",[\"f32:2147483649\",\"f32:1056964608\"]],[\"invoke\",1271,0,\"le\",[\"f32:1\",\"f32:3212836864\"]],[\"invoke\",1276,0,\"le\",[\"f32:1\",\"f32:1086918619\"]],[\"invoke\",1281,0,\"le\",[\"f32:2147483649\",\"f32:4286578688\"]],[\"invoke\",1287,0,\"le\",[\"f32:2147483649\",\"f32:2143289344\"]],[\"invoke\",1294,0,\"le\",[\"f32:2155872256\",\"f32:0\"]],[\"invoke\",1299,0,\"le\",[\"f32:8388608\",\"f32:2147483649\"]],[\"invoke\",1304,0,\"le\",[\"f32:8388608\",\"f32:8388608\"]],[\"invoke\",1309,0,\"le\",[\"f32:2155872256\",\"f32:3212836864\"]],[\"invoke\",1314,0,\"le\",[\"f32:2155872256\",\"f32:1086918619\"]],[\"invoke\",1319,0,\"le\",[\"f32:8388608\",\"f32:4286578687\"]],[\"invoke\",1324,0,\"le\",[\"f32:8388608\",\"f32:2139095040\"]],[\"invoke\",1331,0,\"le\",[\"f32:8388608\",\"f32:2143289344\"]],[\"invoke\",1337,0,\"le\",[\"f32:3204448256\",\"f32:2147483649\"]],[\"invoke\",1342,0,\"le\",[\"f32:3204448256\",\"f32:8388608\"]],[\"invoke\",1347,0,\"le\",[\"f32:1056964608\",\"f32:3204448256\"]],[\"invoke\",1352,0,\"le\",[\"f32:1056964608\",\"f32:1065353216\"]],[\"invoke\",1357,0,\"le\",[\"f32:3204448256\",\"f32:4286578687\"]],[\"invoke\",1362,0,\"le\",[\"f32:3204448256\",\"f32:2139095040\"]],[\"invoke\",1367,0,\"le\",[\"f32:3204448256\",\"f32:2143289344\"]],[\"invoke\",1375,0,\"le\",[\"f32:1065353216\",\"f32:2147483648\"]],[\"invoke\",1380,0,\"le\",[\"f32:1065353216\",\"f32:1\"]],[\"invoke\",1385,0,\"le\",[\"f32:3212836864\",\"f32:3204448256\"]],[\"invoke\",1390,0,\"le\",[\"f32:3212836864\",\"f32:1065353216\"]],[\"invoke\",1395,0,\"le\",[\"f32:1065353216\",\"f32:3234402267\"]],[\"invoke\",1400,0,\"le\",[\"f32:1065353216\",\"f32:2139095039\"]],[\"invoke\",1404,0,\"le\",[\"f32:1065353216\",\"f32:2139095040\"]],[\"invoke\",1413,0,\"le\",[\"f32:3234402267\",\"f32:2147483648\"]],[\"invoke\",1418,0,\"le\",[\"f32:3234402267\",\"f32:1\"]],[\"invoke\",1423,0,\"le\",[\"f32:1086918619\",\"f32:2155872256\"]],[\"invoke\",1428,0,\"le\",[\"f32:1086918619\",\"f32:1056964608\"]],[\"invoke\",1433,0,\"le\",[\"f32:3234402267\",\"f32:3234402267\"]],[\"invoke\",1438,0,\"le\",[\"f32:3234402267\",\"f32:2139095039\"]],[\"invoke\",1442,0,\"le\",[\"f32:3234402267\",\"f32:2139095040\"]],[\"invoke\",1449,0,\"le\",[\"f32:1086918619\",\"f32:4290772992\"]],[\"invoke\",1456,0,\"le\",[\"f32:2139095039\",\"f32:0\"]],[\"invoke\",1461,0,\"le\",[\"f32:4286578687\",\"f32:2155872256\"]],[\"invoke\",1466,0,\"le\",[\"f32:4286578687\",\"f32:1056964608\"]],[\"invoke\",1471,0,\"le\",[\"f32:2139095039\",\"f32:3212836864\"]],[\"invoke\",1476,0,\"le\",[\"f32:2139095039\",\"f32:1086918619\"]],[\"invoke\",1480,0,\"le\",[\"f32:2139095039\",\"f32:2139095039\"]],[\"invoke\",1485,0,\"le\",[\"f32:4286578687\",\"f32:4290772992\"]],[\"invoke\",1494,0,\"le\",[\"f32:4286578688\",\"f32:0\"]],[\"invoke\",1499,0,\"le\",[\"f32:2139095040\",\"f32:2147483649\"]],[\"invoke\",1504,0,\"le\",[\"f32:2139095040\",\"f32:8388608\"]],[\"invoke\",1509,0,\"le\",[\"f32:4286578688\",\"f32:3212836864\"]],[\"invoke\",1514,0,\"le\",[\"f32:4286578688\",\"f32:1086918619\"]],[\"invoke\",1519,0,\"le\",[\"f32:2139095040\",\"f32:4286578687\"]],[\"invoke\",1523,0,\"le\",[\"f32:2139095040\",\"f32:4286578688\"]],[\"invoke\",1531,0,\"le\",[\"f32:2139095040\",\"f32:2143289344\"]],[\"invoke\",1541,0,\"le\",[\"f32:4290772992\",\"f32:2147483649\"]],[\"invoke\",1551,0,\"le\",[\"f32:4290772992\",\"f32:8388608\"]],[\"invoke\",1561,0,\"le\",[\"f32:2143289344\",\"f32:3204448256\"]],[\"invoke\",1571,0,\"le\",[\"f32:2143289344\",\"f32:1065353216\"]],[\"invoke\",1581,0,\"le\",[\"f32:4290772992\",\"f32:4286578687\"]],[\"invoke\",1589,0,\"le\",[\"f32:4290772992\",\"f32:4286578688\"]],[\"invoke\",1601,0,\"le\",[\"f32:4290772992\",\"f32:2143289344\"]],[\"invoke\",1615,0,\"gt\",[\"f32:0\",\"f32:2147483648\"]],[\"invoke\",1620,0,\"gt\",[\"f32:0\",\"f32:1\"]],[\"invoke\",1625,0,\"gt\",[\"f32:2147483648\",\"f32:3204448256\"]],[\"invoke\",1630,0,\"gt\",[\"f32:2147483648\",\"f32:1065353216\"]],[\"invoke\",1635,0,\"gt\",[\"f32:0\",\"f32:3234402267\"]],[\"invoke\",1639,0,\"gt\",[\"f32:0\",\"f32:4286578687\"]],[\"invoke\",1644,0,\"gt\",[\"f32:0\",\"f32:2139095040\"]],[\"invoke\",1653,0,\"gt\",[\"f32:2147483649\",\"f32:2147483648\"]],[\"invoke\",1658,0,\"gt\",[\"f32:2147483649\",\"f32:1\"]],[\"invoke\",1663,0,\"gt\",[\"f32:1\",\"f32:2155872256\"]],[\"invoke\",1668,0,\"gt\",[\"f32:1\",\"f32:1056964608\"]],[\"invoke\",1673,0,\"gt\",[\"f32:2147483649\",\"f32:3234402267\"]],[\"invoke\",1677,0,\"gt\",[\"f32:2147483649\",\"f32:4286578687\"]],[\"invoke\",1682,0,\"gt\",[\"f32:2147483649\",\"f32:2139095040\"]],[\"invoke\",1689,0,\"gt\",[\"f32:1\",\"f32:4290772992\"]],[\"invoke\",1696,0,\"gt\",[\"f32:8388608\",\"f32:0\"]],[\"invoke\",1701,0,\"gt\",[\"f32:2155872256\",\"f32:2155872256\"]],[\"invoke\",1706,0,\"gt\",[\"f32:2155872256\",\"f32:1056964608\"]],[\"invoke\",1711,0,\"gt\",[\"f32:8388608\",\"f32:3212836864\"]],[\"invoke\",1715,0,\"gt\",[\"f32:8388608\",\"f32:3234402267\"]],[\"invoke\",1720,0,\"gt\",[\"f32:8388608\",\"f32:2139095039\"]],[\"invoke\",1725,0,\"gt\",[\"f32:2155872256\",\"f32:4290772992\"]],[\"invoke\",1734,0,\"gt\",[\"f32:3204448256\",\"f32:0\"]],[\"invoke\",1739,0,\"gt\",[\"f32:1056964608\",\"f32:2147483649\"]],[\"invoke\",1744,0,\"gt\",[\"f32:1056964608\",\"f32:8388608\"]],[\"invoke\",1749,0,\"gt\",[\"f32:3204448256\",\"f32:3212836864\"]],[\"invoke\",1753,0,\"gt\",[\"f32:3204448256\",\"f32:3234402267\"]],[\"invoke\",1758,0,\"gt\",[\"f32:3204448256\",\"f32:2139095039\"]],[\"invoke\",1763,0,\"gt\",[\"f32:1056964608\",\"f32:4286578688\"]],[\"invoke\",1771,0,\"gt\",[\"f32:1056964608\",\"f32:2143289344\"]],[\"invoke\",1777,0,\"gt\",[\"f32:3212836864\",\"f32:2147483649\"]],[\"invoke\",1782,0,\"gt\",[\"f32:3212836864\",\"f32:8388608\"]],[\"invoke\",1787,0,\"gt\",[\"f32:1065353216\",\"f32:3204448256\"]],[\"invoke\",1791,0,\"gt\",[\"f32:1065353216\",\"f32:3212836864\"]],[\"invoke\",1796,0,\"gt\",[\"f32:1065353216\",\"f32:1086918619\"]],[\"invoke\",1801,0,\"gt\",[\"f32:3212836864\",\"f32:4286578688\"]],[\"invoke\",1807,0,\"gt\",[\"f32:3212836864\",\"f32:2143289344\"]],[\"invoke\",1815,0,\"gt\",[\"f32:1086918619\",\"f32:2147483648\"]],[\"invoke\",1820,0,\"gt\",[\"f32:1086918619\",\"f32:1\"]],[\"invoke\",1825,0,\"gt\",[\"f32:3234402267\",\"f32:3204448256\"]],[\"invoke\",1830,0,\"gt\",[\"f32:3234402267\",\"f32:1065353216\"]],[\"invoke\",1834,0,\"gt\",[\"f32:3234402267\",\"f32:1086918619\"]],[\"invoke\",1839,0,\"gt\",[\"f32:1086918619\",\"f32:4286578687\"]],[\"invoke\",1844,0,\"gt\",[\"f32:1086918619\",\"f32:2139095040\"]],[\"invoke\",1853,0,\"gt\",[\"f32:4286578687\",\"f32:2147483648\"]],[\"invoke\",1858,0,\"gt\",[\"f32:4286578687\",\"f32:1\"]],[\"invoke\",1863,0,\"gt\",[\"f32:2139095039\",\"f32:2155872256\"]],[\"invoke\",1868,0,\"gt\",[\"f32:2139095039\",\"f32:1056964608\"]],[\"invoke\",1872,0,\"gt\",[\"f32:2139095039\",\"f32:1065353216\"]],[\"invoke\",1877,0,\"gt\",[\"f32:4286578687\",\"f32:4286578687\"]],[\"invoke\",1882,0,\"gt\",[\"f32:4286578687\",\"f32:2139095040\"]],[\"invoke\",1889,0,\"gt\",[\"f32:2139095039\",\"f32:4290772992\"]],[\"invoke\",1896,0,\"gt\",[\"f32:2139095040\",\"f32:0\"]],[\"invoke\",1901,0,\"gt\",[\"f32:4286578688\",\"f32:2155872256\"]],[\"invoke\",1906,0,\"gt\",[\"f32:4286578688\",\"f32:1056964608\"]],[\"invoke\",1910,0,\"gt\",[\"f32:4286578688\",\"f32:1065353216\"]],[\"invoke\",1915,0,\"gt\",[\"f32:2139095040\",\"f32:3234402267\"]],[\"invoke\",1920,0,\"gt\",[\"f32:2139095040\",\"f32:2139095039\"]],[\"invoke\",1925,0,\"gt\",[\"f32:4286578688\",\"f32:4290772992\"]],[\"invoke\",1935,0,\"gt\",[\"f32:4290772992\",\"f32:0\"]],[\"invoke\",1945,0,\"gt\",[\"f32:2143289344\",\"f32:2147483649\"]],[\"invoke\",1955,0,\"gt\",[\"f32:2143289344\",\"f32:8388608\"]],[\"invoke\",1963,0,\"gt\",[\"f32:2143289344\",\"f32:1056964608\"]],[\"invoke\",1973,0,\"gt\",[\"f32:4290772992\",\"f32:3234402267\"]],[\"invoke\",1983,0,\"gt\",[\"f32:4290772992\",\"f32:2139095039\"]],[\"invoke\",1993,0,\"gt\",[\"f32:2143289344\",\"f32:4286578688\"]],[\"invoke\",2009,0,\"gt\",[\"f32:2143289344\",\"f32:2143289344\"]],[\"invoke\",2017,0,\"ge\",[\"f32:2147483648\",\"f32:2147483649\"]],[\"invoke\",2022,0,\"ge\",[\"f32:2147483648\",\"f32:8388608\"]],[\"invoke\",2026,0,\"ge\",[\"f32:2147483648\",\"f32:1056964608\"]],[\"invoke\",2031,0,\"ge\",[\"f32:0\",\"f32:3212836864\"]],[\"invoke\",2036,0,\"ge\",[\"f32:0\",\"f32:1086918619\"]],[\"invoke\",2041,0,\"ge\",[\"f32:2147483648\",\"f32:4286578688\"]],[\"invoke\",2047,0,\"ge\",[\"f32:2147483648\",\"f32:2143289344\"]],[\"invoke\",2055,0,\"ge\",[\"f32:1\",\"f32:2147483648\"]],[\"invoke\",2060,0,\"ge\",[\"f32:1\",\"f32:1\"]],[\"invoke\",2064,0,\"ge\",[\"f32:1\",\"f32:8388608\"]],[\"invoke\",2069,0,\"ge\",[\"f32:2147483649\",\"f32:3212836864\"]],[\"invoke\",2074,0,\"ge\",[\"f32:2147483649\",\"f32:1086918619\"]],[\"invoke\",2079,0,\"ge\",[\"f32:1\",\"f32:4286578687\"]],[\"invoke\",2084,0,\"ge\",[\"f32:1\",\"f32:2139095040\"]],[\"invoke\",2093,0,\"ge\",[\"f32:2155872256\",\"f32:2147483648\"]],[\"invoke\",2098,0,\"ge\",[\"f32:2155872256\",\"f32:1\"]],[\"invoke\",2102,0,\"ge\",[\"f32:2155872256\",\"f32:8388608\"]],[\"invoke\",2107,0,\"ge\",[\"f32:8388608\",\"f32:3204448256\"]],[\"invoke\",2112,0,\"ge\",[\"f32:8388608\",\"f32:1065353216\"]],[\"invoke\",2117,0,\"ge\",[\"f32:2155872256\",\"f32:4286578687\"]],[\"invoke\",2122,0,\"ge\",[\"f32:2155872256\",\"f32:2139095040\"]],[\"invoke\",2129,0,\"ge\",[\"f32:8388608\",\"f32:4290772992\"]],[\"invoke\",2136,0,\"ge\",[\"f32:1056964608\",\"f32:0\"]],[\"invoke\",2141,0,\"ge\",[\"f32:3204448256\",\"f32:2155872256\"]],[\"invoke\",2145,0,\"ge\",[\"f32:3204448256\",\"f32:3204448256\"]],[\"invoke\",2150,0,\"ge\",[\"f32:3204448256\",\"f32:1065353216\"]],[\"invoke\",2155,0,\"ge\",[\"f32:1056964608\",\"f32:3234402267\"]],[\"invoke\",2160,0,\"ge\",[\"f32:1056964608\",\"f32:2139095039\"]],[\"invoke\",2165,0,\"ge\",[\"f32:3204448256\",\"f32:4290772992\"]],[\"invoke\",2174,0,\"ge\",[\"f32:3212836864\",\"f32:0\"]],[\"invoke\",2179,0,\"ge\",[\"f32:1065353216\",\"f32:2147483649\"]],[\"invoke\",2183,0,\"ge\",[\"f32:1065353216\",\"f32:2155872256\"]],[\"invoke\",2188,0,\"ge\",[\"f32:1065353216\",\"f32:1056964608\"]],[\"invoke\",2193,0,\"ge\",[\"f32:3212836864\",\"f32:3234402267\"]],[\"invoke\",2198,0,\"ge\",[\"f32:3212836864\",\"f32:2139095039\"]],[\"invoke\",2203,0,\"ge\",[\"f32:1065353216\",\"f32:4286578688\"]],[\"invoke\",2211,0,\"ge\",[\"f32:1065353216\",\"f32:2143289344\"]],[\"invoke\",2217,0,\"ge\",[\"f32:3234402267\",\"f32:2147483649\"]],[\"invoke\",2221,0,\"ge\",[\"f32:3234402267\",\"f32:2155872256\"]],[\"invoke\",2226,0,\"ge\",[\"f32:3234402267\",\"f32:1056964608\"]],[\"invoke\",2231,0,\"ge\",[\"f32:1086918619\",\"f32:3212836864\"]],[\"invoke\",2236,0,\"ge\",[\"f32:1086918619\",\"f32:1086918619\"]],[\"invoke\",2241,0,\"ge\",[\"f32:3234402267\",\"f32:4286578688\"]],[\"invoke\",2247,0,\"ge\",[\"f32:3234402267\",\"f32:2143289344\"]],[\"invoke\",2255,0,\"ge\",[\"f32:2139095039\",\"f32:2147483648\"]],[\"invoke\",2259,0,\"ge\",[\"f32:2139095039\",\"f32:2147483649\"]],[\"invoke\",2264,0,\"ge\",[\"f32:2139095039\",\"f32:8388608\"]],[\"invoke\",2269,0,\"ge\",[\"f32:4286578687\",\"f32:3212836864\"]],[\"invoke\",2274,0,\"ge\",[\"f32:4286578687\",\"f32:1086918619\"]],[\"invoke\",2279,0,\"ge\",[\"f32:2139095039\",\"f32:4286578687\"]],[\"invoke\",2284,0,\"ge\",[\"f32:2139095039\",\"f32:2139095040\"]],[\"invoke\",2293,0,\"ge\",[\"f32:4286578688\",\"f32:2147483648\"]],[\"invoke\",2297,0,\"ge\",[\"f32:4286578688\",\"f32:2147483649\"]],[\"invoke\",2302,0,\"ge\",[\"f32:4286578688\",\"f32:8388608\"]],[\"invoke\",2307,0,\"ge\",[\"f32:2139095040\",\"f32:3204448256\"]],[\"invoke\",2312,0,\"ge\",[\"f32:2139095040\",\"f32:1065353216\"]],[\"invoke\",2317,0,\"ge\",[\"f32:4286578688\",\"f32:4286578687\"]],[\"invoke\",2322,0,\"ge\",[\"f32:4286578688\",\"f32:2139095040\"]],[\"invoke\",2329,0,\"ge\",[\"f32:2139095040\",\"f32:4290772992\"]],[\"invoke\",2337,0,\"ge\",[\"f32:2143289344\",\"f32:2147483648\"]],[\"invoke\",2347,0,\"ge\",[\"f32:2143289344\",\"f32:1\"]],[\"invoke\",2357,0,\"ge\",[\"f32:4290772992\",\"f32:3204448256\"]],[\"invoke\",2367,0,\"ge\",[\"f32:4290772992\",\"f32:1065353216\"]],[\"invoke\",2377,0,\"ge\",[\"f32:2143289344\",\"f32:3234402267\"]],[\"invoke\",2387,0,\"ge\",[\"f32:2143289344\",\"f32:2139095039\"]],[\"invoke\",2397,0,\"ge\",[\"f32:4290772992\",\"f32:4290772992\"]],[\"file\",\"f64_cmp.wast\"],[\"module\",4,3],[\"invoke\",13,0,\"eq\",[\"f64:9223372036854775808\",\"f64:9223372036854775808\"]],[\"invoke\",18,0,\"eq\",[\"f64:9223372036854775808\",\"f64:1\"]],[\"invoke\",23,0,\"eq\",[\"f64:0\",\"f64:9227875636482146304\"]],[\"invoke\",28,0,\"eq\",[\"f64:0\",\"f64:4602678819172646912\"]],[\"invoke\",33,0,\"eq\",[\"f64:9223372036854775808\",\"f64:13842132293034192152\"]],[\"invoke\",38,0,\"eq\",[\"f64:9223372036854775808\",\"f64:9218868437227405311\"]],[\"invoke\",43,0,\"eq\",[\"f64:0\",\"f64:18442240474082181120\"]],[\"invoke\",51,0,\"eq\",[\"f64:0\",\"f64:9221120237041090560\"]],[\"invoke\",56,0,\"eq\",[\"f64:1\",\"f64:0\"]],[\"invoke\",61,0,\"eq\",[\"f64:9223372036854775809\",\"f64:9227875636482146304\"]],[\"invoke\",66,0,\"eq\",[\"f64:9223372036854775809\",\"f64:4602678819172646912\"]],[\"invoke\",71,0,\"eq\",[\"f64:1\",\"f64:13830554455654793216\"]],[\"invoke\",76,0,\"eq\",[\"f64:1\",\"f64:4618760256179416344\"]],[\"invoke\",81,0,\"eq\",[\"f64:9223372036854775809\",\"f64:18442240474082181120\"]],[\"invoke\",87,0,\"eq\",[\"f64:9223372036854775809\",\"f64:9221120237041090560\"]],[\"invoke\",94,0,\"eq\",[\"f64:9227875636482146304\",\"f64:0\"]],[\"invoke\",99,0,\"eq\",[\"f64:4503599627370496\",\"f64:9223372036854775809\"]],[\"invoke\",104,0,\"eq\",[\"f64:4503599627370496\",\"f64:4503599627370496\"]],[\"invoke\",109,0,\"eq\",[\"f64:9227875636482146304\",\"f64:13830554455654793216\"]],[\"invoke\",114,0,\"eq\",[\"f64:9227875636482146304\",\"f64:4618760256179416344\"]],[\"invoke\",119,0,\"eq\",[\"f64:4503599627370496\",\"f64:18442240474082181119\"]],[\"invoke\",124,0,\"eq\",[\"f64:4503599627370496\",\"f64:9218868437227405312\"]],[\"invoke\",131,0,\"eq\",[\"f64:4503599627370496\",\"f64:9221120237041090560\"]],[\"invoke\",137,0,\"eq\",[\"f64:13826050856027422720\",\"f64:9223372036854775809\"]],[\"invoke\",142,0,\"eq\",[\"f64:13826050856027422720\",\"f64:4503599627370496\"]],[\"invoke\",147,0,\"eq\",[\"f64:4602678819172646912\",\"f64:13826050856027422720\"]],[\"invoke\",152,0,\"eq\",[\"f64:4602678819172646912\",\"f64:4607182418800017408\"]],[\"invoke\",157,0,\"eq\",[\"f64:13826050856027422720\",\"f64:18442240474082181119\"]],[\"invoke\",162,0,\"eq\",[\"f64:13826050856027422720\",\"f64:9218868437227405312\"]],[\"invoke\",167,0,\"eq\",[\"f64:13826050856027422720\",\"f64:9221120237041090560\"]],[\"invoke\",175,0,\"eq\",[\"f64:4607182418800017408\",\"f64:9223372036854775808\"]],[\"invoke\",180,0,\"eq\",[\"f64:4607182418800017408\",\"f64:1\"]],[\"invoke\",185,0,\"eq\",[\"f64:13830554455654793216\",\"f64:13826050856027422720\"]],[\"invoke\",190,0,\"eq\",[\"f64:13830554455654793216\",\"f64:4607182418800017408\"]],[\"invoke\",195,0,\"eq\",[\"f64:4607182418800017408\",\"f64:13842132293034192152\"]],[\"invoke\",200,0,\"eq\",[\"f64:4607182418800017408\",\"f64:9218868437227405311\"]],[\"invoke\",204,0,\"eq\",[\"f64:4607182418800017408\",\"f64:9218868437227405312\"]],[\"invoke\",213,0,\"eq\",[\"f64:13842132293034192152\",\"f64:9223372036854775808\"]],[\"invoke\",218,0,\"eq\",[\"f64:13842132293034192152\",\"f64:1\"]],[\"invoke\",223,0,\"eq\",[\"f64:4618760256179416344\",\"f64:9227875636482146304\"]],[\"invoke\",228,0,\"eq\",[\"f64:4618760256179416344\",\"f64:4602678819172646912\"]],[\"invoke\",233,0,\"eq\",[\"f64:13842132293034192152\",\"f64:13842132293034192152\"]],[\"invoke\",238,0,\"eq\",[\"f64:13842132293034192152\",\"f64:9218868437227405311\"]],[\"invoke\",242,0,\"eq\",[\"f64:13842132293034192152\",\"f64:9218868437227405312\"]],[\"invoke\",249,0,\"eq\",[\"f64:4618760256179416344\",\"f64:18444492273895866368\"]],[\"invoke\",256,0,\"eq\",[\"f64:9218868437227405311\",\"f64:0\"]],[\"invoke\",261,0,\"eq\",[\"f64:18442240474082181119\",\"f64:9227875636482146304\"]],[\"invoke\",266,0,\"eq\",[\"f64:18442240474082181119\",\"f64:4602678819172646912\"]],[\"invoke\",271,0,\"eq\",[\"f64:9218868437227405311\",\"f64:13830554455654793216\"]],[\"invoke\",276,0,\"eq\",[\"f64:9218868437227405311\",\"f64:4618760256179416344\"]],[\"invoke\",281,0,\"eq\",[\"f64:18442240474082181119\",\"f64:18442240474082181120\"]],[\"invoke\",285,0,\"eq\",[\"f64:18442240474082181119\",\"f64:18444492273895866368\"]],[\"invoke\",294,0,\"eq\",[\"f64:18442240474082181120\",\"f64:0\"]],[\"invoke\",299,0,\"eq\",[\"f64:9218868437227405312\",\"f64:9223372036854775809\"]],[\"invoke\",304,0,\"eq\",[\"f64:9218868437227405312\",\"f64:4503599627370496\"]],[\"invoke\",309,0,\"eq\",[\"f64:18442240474082181120\",\"f64:13830554455654793216\"]],[\"invoke\",314,0,\"eq\",[\"f64:18442240474082181120\",\"f64:4618760256179416344\"]],[\"invoke\",319,0,\"eq\",[\"f64:9218868437227405312\",\"f64:18442240474082181119\"]],[\"invoke\",323,0,\"eq\",[\"f64:9218868437227405312\",\"f64:18442240474082181120\"]],[\"invoke\",331,0,\"eq\",[\"f64:9218868437227405312\",\"f64:9221120237041090560\"]],[\"invoke\",341,0,\"eq\",[\"f64:18444492273895866368\",\"f64:9223372036854775809\"]],[\"invoke\",351,0,\"eq\",[\"f64:18444492273895866368\",\"f64:4503599627370496\"]],[\"invoke\",361,0,\"eq\",[\"f64:9221120237041090560\",\"f64:13826050856027422720\"]],[\"invoke\",371,0,\"eq\",[\"f64:9221120237041090560\",\"f64:4607182418800017408\"]],[\"invoke\",381,0,\"eq\",[\"f64:18444492273895866368\",\"f64:18442240474082181119\"]],[\"invoke\",389,0,\"eq\",[\"f64:18444492273895866368\",\"f64:18442240474082181120\"]],[\"invoke\",401,0,\"eq\",[\"f64:18444492273895866368\",\"f64:9221120237041090560\"]],[\"invoke\",415,0,\"ne\",[\"f64:0\",\"f64:9223372036854775808\"]],[\"invoke\",420,0,\"ne\",[\"f64:0\",\"f64:1\"]],[\"invoke\",425,0,\"ne\",[\"f64:9223372036854775808\",\"f64:13826050856027422720\"]],[\"invoke\",430,0,\"ne\",[\"f64:9223372036854775808\",\"f64:4607182418800017408\"]],[\"invoke\",435,0,\"ne\",[\"f64:0\",\"f64:13842132293034192152\"]],[\"invoke\",439,0,\"ne\",[\"f64:0\",\"f64:18442240474082181119\"]],[\"invoke\",444,0,\"ne\",[\"f64:0\",\"f64:9218868437227405312\"]],[\"invoke\",453,0,\"ne\",[\"f64:9223372036854775809\",\"f64:9223372036854775808\"]],[\"invoke\",458,0,\"ne\",[\"f64:9223372036854775809\",\"f64:1\"]],[\"invoke\",463,0,\"ne\",[\"f64:1\",\"f64:9227875636482146304\"]],[\"invoke\",468,0,\"ne\",[\"f64:1\",\"f64:4602678819172646912\"]],[\"invoke\",473,0,\"ne\",[\"f64:9223372036854775809\",\"f64:13842132293034192152\"]],[\"invoke\",477,0,\"ne\",[\"f64:9223372036854775809\",\"f64:18442240474082181119\"]],[\"invoke\",482,0,\"ne\",[\"f64:9223372036854775809\",\"f64:9218868437227405312\"]],[\"invoke\",489,0,\"ne\",[\"f64:1\",\"f64:18444492273895866368\"]],[\"invoke\",496,0,\"ne\",[\"f64:4503599627370496\",\"f64:0\"]],[\"invoke\",501,0,\"ne\",[\"f64:9227875636482146304\",\"f64:9227875636482146304\"]],[\"invoke\",506,0,\"ne\",[\"f64:9227875636482146304\",\"f64:4602678819172646912\"]],[\"invoke\",511,0,\"ne\",[\"f64:4503599627370496\",\"f64:13830554455654793216\"]],[\"invoke\",515,0,\"ne\",[\"f64:4503599627370496\",\"f64:13842132293034192152\"]],[\"invoke\",520,0,\"ne\",[\"f64:4503599627370496\",\"f64:9218868437227405311\"]],[\"invoke\",525,0,\"ne\",[\"f64:9227875636482146304\",\"f64:18444492273895866368\"]],[\"invoke\",534,0,\"ne\",[\"f64:13826050856027422720\",\"f64:0\"]],[\"invoke\",539,0,\"ne\",[\"f64:4602678819172646912\",\"f64:9223372036854775809\"]],[\"invoke\",544,0,\"ne\",[\"f64:4602678819172646912\",\"f64:4503599627370496\"]],[\"invoke\",549,0,\"ne\",[\"f64:13826050856027422720\",\"f64:13830554455654793216\"]],[\"invoke\",553,0,\"ne\",[\"f64:13826050856027422720\",\"f64:13842132293034192152\"]],[\"invoke\",558,0,\"ne\",[\"f64:13826050856027422720\",\"f64:9218868437227405311\"]],[\"invoke\",563,0,\"ne\",[\"f64:4602678819172646912\",\"f64:18442240474082181120\"]],[\"invoke\",571,0,\"ne\",[\"f64:4602678819172646912\",\"f64:9221120237041090560\"]],[\"invoke\",577,0,\"ne\",[\"f64:13830554455654793216\",\"f64:9223372036854775809\"]],[\"invoke\",582,0,\"ne\",[\"f64:13830554455654793216\",\"f64:4503599627370496\"]],[\"invoke\",587,0,\"ne\",[\"f64:4607182418800017408\",\"f64:13826050856027422720\"]],[\"invoke\",592,0,\"ne\",[\"f64:4607182418800017408\",\"f64:4607182418800017408\"]],[\"invoke\",596,0,\"ne\",[\"f64:4607182418800017408\",\"f64:4618760256179416344\"]],[\"invoke\",601,0,\"ne\",[\"f64:13830554455654793216\",\"f64:18442240474082181120\"]],[\"invoke\",607,0,\"ne\",[\"f64:13830554455654793216\",\"f64:9221120237041090560\"]],[\"invoke\",615,0,\"ne\",[\"f64:4618760256179416344\",\"f64:9223372036854775808\"]],[\"invoke\",620,0,\"ne\",[\"f64:4618760256179416344\",\"f64:1\"]],[\"invoke\",625,0,\"ne\",[\"f64:13842132293034192152\",\"f64:13826050856027422720\"]],[\"invoke\",630,0,\"ne\",[\"f64:13842132293034192152\",\"f64:4607182418800017408\"]],[\"invoke\",634,0,\"ne\",[\"f64:13842132293034192152\",\"f64:4618760256179416344\"]],[\"invoke\",639,0,\"ne\",[\"f64:4618760256179416344\",\"f64:18442240474082181119\"]],[\"invoke\",644,0,\"ne\",[\"f64:4618760256179416344\",\"f64:9218868437227405312\"]],[\"invoke\",653,0,\"ne\",[\"f64:18442240474082181119\",\"f64:9223372036854775808\"]],[\"invoke\",658,0,\"ne\",[\"f64:18442240474082181119\",\"f64:1\"]],[\"invoke\",663,0,\"ne\",[\"f64:9218868437227405311\",\"f64:9227875636482146304\"]],[\"invoke\",668,0,\"ne\",[\"f64:9218868437227405311\",\"f64:4602678819172646912\"]],[\"invoke\",672,0,\"ne\",[\"f64:9218868437227405311\",\"f64:4607182418800017408\"]],[\"invoke\",677,0,\"ne\",[\"f64:18442240474082181119\",\"f64:18442240474082181119\"]],[\"invoke\",682,0,\"ne\",[\"f64:18442240474082181119\",\"f64:9218868437227405312\"]],[\"invoke\",689,0,\"ne\",[\"f64:9218868437227405311\",\"f64:18444492273895866368\"]],[\"invoke\",696,0,\"ne\",[\"f64:9218868437227405312\",\"f64:0\"]],[\"invoke\",701,0,\"ne\",[\"f64:18442240474082181120\",\"f64:9227875636482146304\"]],[\"invoke\",706,0,\"ne\",[\"f64:18442240474082181120\",\"f64:4602678819172646912\"]],[\"invoke\",710,0,\"ne\",[\"f64:18442240474082181120\",\"f64:4607182418800017408\"]],[\"invoke\",715,0,\"ne\",[\"f64:9218868437227405312\",\"f64:13842132293034192152\"]],[\"invoke\",720,0,\"ne\",[\"f64:9218868437227405312\",\"f64:9218868437227405311\"]],[\"invoke\",725,0,\"ne\",[\"f64:18442240474082181120\",\"f64:18444492273895866368\"]],[\"invoke\",735,0,\"ne\",[\"f64:18444492273895866368\",\"f64:0\"]],[\"invoke\",745,0,\"ne\",[\"f64:9221120237041090560\",\"f64:9223372036854775809\"]],[\"invoke\",755,0,\"ne\",[\"f64:9221120237041090560\",\"f64:4503599627370496\"]],[\"invoke\",763,0,\"ne\",[\"f64:9221120237041090560\",\"f64:4602678819172646912\"]],[\"invoke\",773,0,\"ne\",[\"f64:18444492273895866368\",\"f64:13842132293034192152\"]],[\"invoke\",783,0,\"ne\",[\"f64:18444492273895866368\",\"f64:9218868437227405311\"]],[\"invoke\",793,0,\"ne\",[\"f64:9221120237041090560\",\"f64:18442240474082181120\"]],[\"invoke\",809,0,\"ne\",[\"f64:9221120237041090560\",\"f64:9221120237041090560\"]],[\"invoke\",817,0,\"lt\",[\"f64:9223372036854775808\",\"f64:9223372036854775809\"]],[\"invoke\",822,0,\"lt\",[\"f64:9223372036854775808\",\"f64:4503599627370496\"]],[\"invoke\",826,0,\"lt\",[\"f64:9223372036854775808\",\"f64:4602678819172646912\"]],[\"invoke\",831,0,\"lt\",[\"f64:0\",\"f64:13830554455654793216\"]],[\"invoke\",836,0,\"lt\",[\"f64:0\",\"f64:4618760256179416344\"]],[\"invoke\",841,0,\"lt\",[\"f64:9223372036854775808\",\"f64:18442240474082181120\"]],[\"invoke\",847,0,\"lt\",[\"f64:9223372036854775808\",\"f64:9221120237041090560\"]],[\"invoke\",855,0,\"lt\",[\"f64:1\",\"f64:9223372036854775808\"]],[\"invoke\",860,0,\"lt\",[\"f64:1\",\"f64:1\"]],[\"invoke\",864,0,\"lt\",[\"f64:1\",\"f64:4503599627370496\"]],[\"invoke\",869,0,\"lt\",[\"f64:9223372036854775809\",\"f64:13830554455654793216\"]],[\"invoke\",874,0,\"lt\",[\"f64:9223372036854775809\",\"f64:4618760256179416344\"]],[\"invoke\",879,0,\"lt\",[\"f64:1\",\"f64:18442240474082181119\"]],[\"invoke\",884,0,\"lt\",[\"f64:1\",\"f64:9218868437227405312\"]],[\"invoke\",893,0,\"lt\",[\"f64:9227875636482146304\",\"f64:9223372036854775808\"]],[\"invoke\",898,0,\"lt\",[\"f64:9227875636482146304\",\"f64:1\"]],[\"invoke\",903,0,\"lt\",[\"f64:4503599627370496\",\"f64:9227875636482146304\"]],[\"invoke\",907,0,\"lt\",[\"f64:4503599627370496\",\"f64:13826050856027422720\"]],[\"invoke\",912,0,\"lt\",[\"f64:4503599627370496\",\"f64:4607182418800017408\"]],[\"invoke\",917,0,\"lt\",[\"f64:9227875636482146304\",\"f64:18442240474082181119\"]],[\"invoke\",922,0,\"lt\",[\"f64:9227875636482146304\",\"f64:9218868437227405312\"]],[\"invoke\",929,0,\"lt\",[\"f64:4503599627370496\",\"f64:18444492273895866368\"]],[\"invoke\",936,0,\"lt\",[\"f64:4602678819172646912\",\"f64:0\"]],[\"invoke\",941,0,\"lt\",[\"f64:13826050856027422720\",\"f64:9227875636482146304\"]],[\"invoke\",945,0,\"lt\",[\"f64:13826050856027422720\",\"f64:13826050856027422720\"]],[\"invoke\",950,0,\"lt\",[\"f64:13826050856027422720\",\"f64:4607182418800017408\"]],[\"invoke\",955,0,\"lt\",[\"f64:4602678819172646912\",\"f64:13842132293034192152\"]],[\"invoke\",960,0,\"lt\",[\"f64:4602678819172646912\",\"f64:9218868437227405311\"]],[\"invoke\",965,0,\"lt\",[\"f64:13826050856027422720\",\"f64:18444492273895866368\"]],[\"invoke\",974,0,\"lt\",[\"f64:13830554455654793216\",\"f64:0\"]],[\"invoke\",979,0,\"lt\",[\"f64:4607182418800017408\",\"f64:9223372036854775809\"]],[\"invoke\",983,0,\"lt\",[\"f64:4607182418800017408\",\"f64:9227875636482146304\"]],[\"invoke\",988,0,\"lt\",[\"f64:4607182418800017408\",\"f64:4602678819172646912\"]],[\"invoke\",993,0,\"lt\",[\"f64:13830554455654793216\",\"f64:13842132293034192152\"]],[\"invoke\",998,0,\"lt\",[\"f64:13830554455654793216\",\"f64:9218868437227405311\"]],[\"invoke\",1003,0,\"lt\",[\"f64:4607182418800017408\",\"f64:18442240474082181120\"]],[\"invoke\",1011,0,\"lt\",[\"f64:4607182418800017408\",\"f64:9221120237041090560\"]],[\"invoke\",1017,0,\"lt\",[\"f64:13842132293034192152\",\"f64:9223372036854775809\"]],[\"invoke\",1021,0,\"lt\",[\"f64:13842132293034192152\",\"f64:9227875636482146304\"]],[\"invoke\",1026,0,\"lt\",[\"f64:13842132293034192152\",\"f64:4602678819172646912\"]],[\"invoke\",1031,0,\"lt\",[\"f64:4618760256179416344\",\"f64:13830554455654793216\"]],[\"invoke\",1036,0,\"lt\",[\"f64:4618760256179416344\",\"f64:4618760256179416344\"]],[\"invoke\",1041,0,\"lt\",[\"f64:13842132293034192152\",\"f64:18442240474082181120\"]],[\"invoke\",1047,0,\"lt\",[\"f64:13842132293034192152\",\"f64:9221120237041090560\"]],[\"invoke\",1055,0,\"lt\",[\"f64:9218868437227405311\",\"f64:9223372036854775808\"]],[\"invoke\",1059,0,\"lt\",[\"f64:9218868437227405311\",\"f64:9223372036854775809\"]],[\"invoke\",1064,0,\"lt\",[\"f64:9218868437227405311\",\"f64:4503599627370496\"]],[\"invoke\",1069,0,\"lt\",[\"f64:18442240474082181119\",\"f64:13830554455654793216\"]],[\"invoke\",1074,0,\"lt\",[\"f64:18442240474082181119\",\"f64:4618760256179416344\"]],[\"invoke\",1079,0,\"lt\",[\"f64:9218868437227405311\",\"f64:18442240474082181119\"]],[\"invoke\",1084,0,\"lt\",[\"f64:9218868437227405311\",\"f64:9218868437227405312\"]],[\"invoke\",1093,0,\"lt\",[\"f64:18442240474082181120\",\"f64:9223372036854775808\"]],[\"invoke\",1097,0,\"lt\",[\"f64:18442240474082181120\",\"f64:9223372036854775809\"]],[\"invoke\",1102,0,\"lt\",[\"f64:18442240474082181120\",\"f64:4503599627370496\"]],[\"invoke\",1107,0,\"lt\",[\"f64:9218868437227405312\",\"f64:13826050856027422720\"]],[\"invoke\",1112,0,\"lt\",[\"f64:9218868437227405312\",\"f64:4607182418800017408\"]],[\"invoke\",1117,0,\"lt\",[\"f64:18442240474082181120\",\"f64:18442240474082181119\"]],[\"invoke\",1122,0,\"lt\",[\"f64:18442240474082181120\",\"f64:9218868437227405312\"]],[\"invoke\",1129,0,\"lt\",[\"f64:9218868437227405312\",\"f64:18444492273895866368\"]],[\"invoke\",1137,0,\"lt\",[\"f64:9221120237041090560\",\"f64:9223372036854775808\"]],[\"invoke\",1147,0,\"lt\",[\"f64:9221120237041090560\",\"f64:1\"]],[\"invoke\",1157,0,\"lt\",[\"f64:18444492273895866368\",\"f64:13826050856027422720\"]],[\"invoke\",1167,0,\"lt\",[\"f64:18444492273895866368\",\"f64:4607182418800017408\"]],[\"invoke\",1177,0,\"lt\",[\"f64:9221120237041090560\",\"f64:13842132293034192152\"]],[\"invoke\",1187,0,\"lt\",[\"f64:9221120237041090560\",\"f64:9218868437227405311\"]],[\"invoke\",1197,0,\"lt\",[\"f64:18444492273895866368\",\"f64:18444492273895866368\"]],[\"invoke\",1214,0,\"le\",[\"f64:9223372036854775808\",\"f64:0\"]],[\"invoke\",1218,0,\"le\",[\"f64:9223372036854775808\",\"f64:1\"]],[\"invoke\",1223,0,\"le\",[\"f64:0\",\"f64:9227875636482146304\"]],[\"invoke\",1228,0,\"le\",[\"f64:0\",\"f64:4602678819172646912\"]],[\"invoke\",1233,0,\"le\",[\"f64:9223372036854775808\",\"f64:13842132293034192152\"]],[\"invoke\",1238,0,\"le\",[\"f64:9223372036854775808\",\"f64:9218868437227405311\"]],[\"invoke\",1243,0,\"le\",[\"f64:0\",\"f64:18442240474082181120\"]],[\"invoke\",1251,0,\"le\",[\"f64:0\",\"f64:9221120237041090560\"]],[\"invoke\",1256,0,\"le\",[\"f64:1\",\"f64:0\"]],[\"invoke\",1261,0,\"le\",[\"f64:9223372036854775809\",\"f64:9227875636482146304\"]],[\"invoke\",1266,0,\"le\",[\"f64:9223372036854775809\",\"f64:4602678819172646912\"]],[\"invoke\",1271,0,\"le\",[\"f64:1\",\"f64:13830554455654793216\"]],[\"invoke\",1276,0,\"le\",[\"f64:1\",\"f64:4618760256179416344\"]],[\"invoke\",1281,0,\"le\",[\"f64:9223372036854775809\",\"f64:18442240474082181120\"]],[\"invoke\",1287,0,\"le\",[\"f64:9223372036854775809\",\"f64:9221120237041090560\"]],[\"invoke\",1294,0,\"le\",[\"f64:9227875636482146304\",\"f64:0\"]],[\"invoke\",1299,0,\"le\",[\"f64:4503599627370496\",\"f64:9223372036854775809\"]],[\"invoke\",1304,0,\"le\",[\"f64:4503599627370496\",\"f64:4503599627370496\"]],[\"invoke\",1309,0,\"le\",[\"f64:9227875636482146304\",\"f64:13830554455654793216\"]],[\"invoke\",1314,0,\"le\",[\"f64:9227875636482146304\",\"f64:4618760256179416344\"]],[\"invoke\",1319,0,\"le\",[\"f64:4503599627370496\",\"f64:18442240474082181119\"]],[\"invoke\",1324,0,\"le\",[\"f64:4503599627370496\",\"f64:9218868437227405312\"]],[\"invoke\",1331,0,\"le\",[\"f64:4503599627370496\",\"f64:9221120237041090560\"]],[\"invoke\",1337,0,\"le\",[\"f64:13826050856027422720\",\"f64:9223372036854775809\"]],[\"invoke\",1342,0,\"le\",[\"f64:13826050856027422720\",\"f64:4503599627370496\"]],[\"invoke\",1347,0,\"le\",[\"f64:4602678819172646912\",\"f64:13826050856027422720\"]],[\"invoke\",1352,0,\"le\",[\"f64:4602678819172646912\",\"f64:4607182418800017408\"]],[\"invoke\",1357,0,\"le\",[\"f64:13826050856027422720\",\"f64:18442240474082181119\"]],[\"invoke\",1362,0,\"le\",[\"f64:13826050856027422720\",\"f64:9218868437227405312\"]],[\"invoke\",1367,0,\"le\",[\"f64:13826050856027422720\",\"f64:9221120237041090560\"]],[\"invoke\",1375,0,\"le\",[\"f64:4607182418800017408\",\"f64:9223372036854775808\"]],[\"invoke\",1380,0,\"le\",[\"f64:4607182418800017408\",\"f64:1\"]],[\"invoke\",1385,0,\"le\",[\"f64:13830554455654793216\",\"f64:13826050856027422720\"]],[\"invoke\",1390,0,\"le\",[\"f64:13830554455654793216\",\"f64:4607182418800017408\"]],[\"invoke\",1395,0,\"le\",[\"f64:4607182418800017408\",\"f64:13842132293034192152\"]],[\"invoke\",1400,0,\"le\",[\"f64:4607182418800017408\",\"f64:9218868437227405311\"]],[\"invoke\",1404,0,\"le\",[\"f64:4607182418800017408\",\"f64:9218868437227405312\"]],[\"invoke\",1413,0,\"le\",[\"f64:13842132293034192152\",\"f64:9223372036854775808\"]],[\"invoke\",1418,0,\"le\",[\"f64:13842132293034192152\",\"f64:1\"]],[\"invoke\",1423,0,\"le\",[\"f64:4618760256179416344\",\"f64:9227875636482146304\"]],[\"invoke\",1428,0,\"le\",[\"f64:4618760256179416344\",\"f64:4602678819172646912\"]],[\"invoke\",1433,0,\"le\",[\"f64:13842132293034192152\",\"f64:13842132293034192152\"]],[\"invoke\",1438,0,\"le\",[\"f64:13842132293034192152\",\"f64:9218868437227405311\"]],[\"invoke\",1442,0,\"le\",[\"f64:13842132293034192152\",\"f64:9218868437227405312\"]],[\"invoke\",1449,0,\"le\",[\"f64:4618760256179416344\",\"f64:18444492273895866368\"]],[\"invoke\",1456,0,\"le\",[\"f64:9218868437227405311\",\"f64:0\"]],[\"invoke\",1461,0,\"le\",[\"f64:18442240474082181119\",\"f64:9227875636482146304\"]],[\"invoke\",1466,0,\"le\",[\"f64:18442240474082181119\",\"f64:4602678819172646912\"]],[\"invoke\",1471,0,\"le\",[\"f64:9218868437227405311\",\"f64:13830554455654793216\"]],[\"invoke\",1476,0,\"le\",[\"f64:9218868437227405311\",\"f64:4618760256179416344\"]],[\"invoke\",1480,0,\"le\",[\"f64:9218868437227405311\",\"f64:9218868437227405311\"]],[\"invoke\",1485,0,\"le\",[\"f64:18442240474082181119\",\"f64:18444492273895866368\"]],[\"invoke\",1494,0,\"le\",[\"f64:18442240474082181120\",\"f64:0\"]],[\"invoke\",1499,0,\"le\",[\"f64:9218868437227405312\",\"f64:9223372036854775809\"]],[\"invoke\",1504,0,\"le\",[\"f64:9218868437227405312\",\"f64:4503599627370496\"]],[\"invoke\",1509,0,\"le\",[\"f64:18442240474082181120\",\"f64:13830554455654793216\"]],[\"invoke\",1514,0,\"le\",[\"f64:18442240474082181120\",\"f64:4618760256179416344\"]],[\"invoke\",1519,0,\"le\",[\"f64:9218868437227405312\",\"f64:18442240474082181119\"]],[\"invoke\",1523,0,\"le\",[\"f64:9218868437227405312\",\"f64:18442240474082181120\"]],[\"invoke\",1531,0,\"le\",[\"f64:9218868437227405312\",\"f64:9221120237041090560\"]],[\"invoke\",1541,0,\"le\",[\"f64:18444492273895866368\",\"f64:9223372036854775809\"]],[\"invoke\",1551,0,\"le\",[\"f64:18444492273895866368\",\"f64:4503599627370496\"]],[\"invoke\",1561,0,\"le\",[\"f64:9221120237041090560\",\"f64:13826050856027422720\"]],[\"invoke\",1571,0,\"le\",[\"f64:9221120237041090560\",\"f64:4607182418800017408\"]],[\"invoke\",1581,0,\"le\",[\"f64:18444492273895866368\",\"f64:18442240474082181119\"]],[\"invoke\",1589,0,\"le\",[\"f64:18444492273895866368\",\"f64:18442240474082181120\"]],[\"invoke\",1601,0,\"le\",[\"f64:18444492273895866368\",\"f64:9221120237041090560\"]],[\"invoke\",1615,0,\"gt\",[\"f64:0\",\"f64:9223372036854775808\"]],[\"invoke\",1620,0,\"gt\",[\"f64:0\",\"f64:1\"]],[\"invoke\",1625,0,\"gt\",[\"f64:9223372036854775808\",\"f64:13826050856027422720\"]],[\"invoke\",1630,0,\"gt\",[\"f64:9223372036854775808\",\"f64:4607182418800017408\"]],[\"invoke\",1635,0,\"gt\",[\"f64:0\",\"f64:13842132293034192152\"]],[\"invoke\",1639,0,\"gt\",[\"f64:0\",\"f64:18442240474082181119\"]],[\"invoke\",1644,0,\"gt\",[\"f64:0\",\"f64:9218868437227405312\"]],[\"invoke\",1653,0,\"gt\",[\"f64:9223372036854775809\",\"f64:9223372036854775808\"]],[\"invoke\",1658,0,\"gt\",[\"f64:9223372036854775809\",\"f64:1\"]],[\"invoke\",1663,0,\"gt\",[\"f64:1\",\"f64:9227875636482146304\"]],[\"invoke\",1668,0,\"gt\",[\"f64:1\",\"f64:4602678819172646912\"]],[\"invoke\",1673,0,\"gt\",[\"f64:9223372036854775809\",\"f64:13842132293034192152\"]],[\"invoke\",1677,0,\"gt\",[\"f64:9223372036854775809\",\"f64:18442240474082181119\"]],[\"invoke\",1682,0,\"gt\",[\"f64:9223372036854775809\",\"f64:9218868437227405312\"]],[\"invoke\",1689,0,\"gt\",[\"f64:1\",\"f64:18444492273895866368\"]],[\"invoke\",1696,0,\"gt\",[\"f64:4503599627370496\",\"f64:0\"]],[\"invoke\",1701,0,\"gt\",[\"f64:9227875636482146304\",\"f64:9227875636482146304\"]],[\"invoke\",1706,0,\"gt\",[\"f64:9227875636482146304\",\"f64:4602678819172646912\"]],[\"invoke\",1711,0,\"gt\",[\"f64:4503599627370496\",\"f64:13830554455654793216\"]],[\"invoke\",1715,0,\"gt\",[\"f64:4503599627370496\",\"f64:13842132293034192152\"]],[\"invoke\",1720,0,\"gt\",[\"f64:4503599627370496\",\"f64:9218868437227405311\"]],[\"invoke\",1725,0,\"gt\",[\"f64:9227875636482146304\",\"f64:18444492273895866368\"]],[\"invoke\",1734,0,\"gt\",[\"f64:13826050856027422720\",\"f64:0\"]],[\"invoke\",1739,0,\"gt\",[\"f64:4602678819172646912\",\"f64:9223372036854775809\"]],[\"invoke\",1744,0,\"gt\",[\"f64:4602678819172646912\",\"f64:4503599627370496\"]],[\"invoke\",1749,0,\"gt\",[\"f64:13826050856027422720\",\"f64:13830554455654793216\"]],[\"invoke\",1753,0,\"gt\",[\"f64:13826050856027422720\",\"f64:13842132293034192152\"]],[\"invoke\",1758,0,\"gt\",[\"f64:13826050856027422720\",\"f64:9218868437227405311\"]],[\"invoke\",1763,0,\"gt\",[\"f64:4602678819172646912\",\"f64:18442240474082181120\"]],[\"invoke\",1771,0,\"gt\",[\"f64:4602678819172646912\",\"f64:9221120237041090560\"]],[\"invoke\",1777,0,\"gt\",[\"f64:13830554455654793216\",\"f64:9223372036854775809\"]],[\"invoke\",1782,0,\"gt\",[\"f64:13830554455654793216\",\"f64:4503599627370496\"]],[\"invoke\",1787,0,\"gt\",[\"f64:4607182418800017408\",\"f64:13826050856027422720\"]],[\"invoke\",1791,0,\"gt\",[\"f64:4607182418800017408\",\"f64:13830554455654793216\"]],[\"invoke\",1796,0,\"gt\",[\"f64:4607182418800017408\",\"f64:4618760256179416344\"]],[\"invoke\",1801,0,\"gt\",[\"f64:13830554455654793216\",\"f64:18442240474082181120\"]],[\"invoke\",1807,0,\"gt\",[\"f64:13830554455654793216\",\"f64:9221120237041090560\"]],[\"invoke\",1815,0,\"gt\",[\"f64:4618760256179416344\",\"f64:9223372036854775808\"]],[\"invoke\",1820,0,\"gt\",[\"f64:4618760256179416344\",\"f64:1\"]],[\"invoke\",1825,0,\"gt\",[\"f64:13842132293034192152\",\"f64:13826050856027422720\"]],[\"invoke\",1830,0,\"gt\",[\"f64:13842132293034192152\",\"f64:4607182418800017408\"]],[\"invoke\",1834,0,\"gt\",[\"f64:13842132293034192152\",\"f64:4618760256179416344\"]],[\"invoke\",1839,0,\"gt\",[\"f64:4618760256179416344\",\"f64:18442240474082181119\"]],[\"invoke\",1844,0,\"gt\",[\"f64:4618760256179416344\",\"f64:9218868437227405312\"]],[\"invoke\",1853,0,\"gt\",[\"f64:18442240474082181119\",\"f64:9223372036854775808\"]],[\"invoke\",1858,0,\"gt\",[\"f64:18442240474082181119\",\"f64:1\"]],[\"invoke\",1863,0,\"gt\",[\"f64:9218868437227405311\",\"f64:9227875636482146304\"]],[\"invoke\",1868,0,\"gt\",[\"f64:9218868437227405311\",\"f64:4602678819172646912\"]],[\"invoke\",1872,0,\"gt\",[\"f64:9218868437227405311\",\"f64:4607182418800017408\"]],[\"invoke\",1877,0,\"gt\",[\"f64:18442240474082181119\",\"f64:18442240474082181119\"]],[\"invoke\",1882,0,\"gt\",[\"f64:18442240474082181119\",\"f64:9218868437227405312\"]],[\"invoke\",1889,0,\"gt\",[\"f64:9218868437227405311\",\"f64:18444492273895866368\"]],[\"invoke\",1896,0,\"gt\",[\"f64:9218868437227405312\",\"f64:0\"]],[\"invoke\",1901,0,\"gt\",[\"f64:18442240474082181120\",\"f64:9227875636482146304\"]],[\"invoke\",1906,0,\"gt\",[\"f64:18442240474082181120\",\"f64:4602678819172646912\"]],[\"invoke\",1910,0,\"gt\",[\"f64:18442240474082181120\",\"f64:4607182418800017408\"]],[\"invoke\",1915,0,\"gt\",[\"f64:9218868437227405312\",\"f64:13842132293034192152\"]],[\"invoke\",1920,0,\"gt\",[\"f64:9218868437227405312\",\"f64:9218868437227405311\"]],[\"invoke\",1925,0,\"gt\",[\"f64:18442240474082181120\",\"f64:18444492273895866368\"]],[\"invoke\",1935,0,\"gt\",[\"f64:18444492273895866368\",\"f64:0\"]],[\"invoke\",1945,0,\"gt\",[\"f64:9221120237041090560\",\"f64:9223372036854775809\"]],[\"invoke\",1955,0,\"gt\",[\"f64:9221120237041090560\",\"f64:4503599627370496\"]],[\"invoke\",1963,0,\"gt\",[\"f64:9221120237041090560\",\"f64:4602678819172646912\"]],[\"invoke\",1973,0,\"gt\",[\"f64:18444492273895866368\",\"f64:13842132293034192152\"]],[\"invoke\",1983,0,\"gt\",[\"f64:18444492273895866368\",\"f64:9218868437227405311\"]],[\"invoke\",1993,0,\"gt\",[\"f64:9221120237041090560\",\"f64:18442240474082181120\"]],[\"invoke\",2009,0,\"gt\",[\"f64:9221120237041090560\",\"f64:9221120237041090560\"]],[\"invoke\",2017,0,\"ge\",[\"f64:9223372036854775808\",\"f64:9223372036854775809\"]],[\"invoke\",2022,0,\"ge\",[\"f64:9223372036854775808\",\"f64:4503599627370496\"]],[\"invoke\",2026,0,\"ge\",[\"f64:9223372036854775808\",\"f64:4602678819172646912\"]],[\"invoke\",2031,0,\"ge\",[\"f64:0\",\"f64:13830554455654793216\"]],[\"invoke\",2036,0,\"ge\",[\"f64:0\",\"f64:4618760256179416344\"]],[\"invoke\",2041,0,\"ge\",[\"f64:9223372036854775808\",\"f64:18442240474082181120\"]],[\"invoke\",2047,0,\"ge\",[\"f64:9223372036854775808\",\"f64:9221120237041090560\"]],[\"invoke\",2055,0,\"ge\",[\"f64:1\",\"f64:9223372036854775808\"]],[\"invoke\",2060,0,\"ge\",[\"f64:1\",\"f64:1\"]],[\"invoke\",2064,0,\"ge\",[\"f64:1\",\"f64:4503599627370496\"]],[\"invoke\",2069,0,\"ge\",[\"f64:9223372036854775809\",\"f64:13830554455654793216\"]],[\"invoke\",2074,0,\"ge\",[\"f64:9223372036854775809\",\"f64:4618760256179416344\"]],[\"invoke\",2079,0,\"ge\",[\"f64:1\",\"f64:18442240474082181119\"]],[\"invoke\",2084,0,\"ge\",[\"f64:1\",\"f64:9218868437227405312\"]],[\"invoke\",2093,0,\"ge\",[\"f64:9227875636482146304\",\"f64:9223372036854775808\"]],[\"invoke\",2098,0,\"ge\",[\"f64:9227875636482146304\",\"f64:1\"]],[\"invoke\",2102,0,\"ge\",[\"f64:9227875636482146304\",\"f64:4503599627370496\"]],[\"invoke\",2107,0,\"ge\",[\"f64:4503599627370496\",\"f64:13826050856027422720\"]],[\"invoke\",2112,0,\"ge\",[\"f64:4503599627370496\",\"f64:4607182418800017408\"]],[\"invoke\",2117,0,\"ge\",[\"f64:9227875636482146304\",\"f64:18442240474082181119\"]],[\"invoke\",2122,0,\"ge\",[\"f64:9227875636482146304\",\"f64:9218868437227405312\"]],[\"invoke\",2129,0,\"ge\",[\"f64:4503599627370496\",\"f64:18444492273895866368\"]],[\"invoke\",2136,0,\"ge\",[\"f64:4602678819172646912\",\"f64:0\"]],[\"invoke\",2141,0,\"ge\",[\"f64:13826050856027422720\",\"f64:9227875636482146304\"]],[\"invoke\",2145,0,\"ge\",[\"f64:13826050856027422720\",\"f64:13826050856027422720\"]],[\"invoke\",2150,0,\"ge\",[\"f64:13826050856027422720\",\"f64:4607182418800017408\"]],[\"invoke\",2155,0,\"ge\",[\"f64:4602678819172646912\",\"f64:13842132293034192152\"]],[\"invoke\",2160,0,\"ge\",[\"f64:4602678819172646912\",\"f64:9218868437227405311\"]],[\"invoke\",2165,0,\"ge\",[\"f64:13826050856027422720\",\"f64:18444492273895866368\"]],[\"invoke\",2174,0,\"ge\",[\"f64:13830554455654793216\",\"f64:0\"]],[\"invoke\",2179,0,\"ge\",[\"f64:4607182418800017408\",\"f64:9223372036854775809\"]],[\"invoke\",2183,0,\"ge\",[\"f64:4607182418800017408\",\"f64:9227875636482146304\"]],[\"invoke\",2188,0,\"ge\",[\"f64:4607182418800017408\",\"f64:4602678819172646912\"]],[\"invoke\",2193,0,\"ge\",[\"f64:13830554455654793216\",\"f64:13842132293034192152\"]],[\"invoke\",2198,0,\"ge\",[\"f64:13830554455654793216\",\"f64:9218868437227405311\"]],[\"invoke\",2203,0,\"ge\",[\"f64:4607182418800017408\",\"f64:18442240474082181120\"]],[\"invoke\",2211,0,\"ge\",[\"f64:4607182418800017408\",\"f64:9221120237041090560\"]],[\"invoke\",2217,0,\"ge\",[\"f64:13842132293034192152\",\"f64:9223372036854775809\"]],[\"invoke\",2221,0,\"ge\",[\"f64:13842132293034192152\",\"f64:9227875636482146304\"]],[\"invoke\",2226,0,\"ge\",[\"f64:13842132293034192152\",\"f64:4602678819172646912\"]],[\"invoke\",2231,0,\"ge\",[\"f64:4618760256179416344\",\"f64:13830554455654793216\"]],[\"invoke\",2236,0,\"ge\",[\"f64:4618760256179416344\",\"f64:4618760256179416344\"]],[\"invoke\",2241,0,\"ge\",[\"f64:13842132293034192152\",\"f64:18442240474082181120\"]],[\"invoke\",2247,0,\"ge\",[\"f64:13842132293034192152\",\"f64:9221120237041090560\"]],[\"invoke\",2255,0,\"ge\",[\"f64:9218868437227405311\",\"f64:9223372036854775808\"]],[\"invoke\",2259,0,\"ge\",[\"f64:9218868437227405311\",\"f64:9223372036854775809\"]],[\"invoke\",2264,0,\"ge\",[\"f64:9218868437227405311\",\"f64:4503599627370496\"]],[\"invoke\",2269,0,\"ge\",[\"f64:18442240474082181119\",\"f64:13830554455654793216\"]],[\"invoke\",2274,0,\"ge\",[\"f64:18442240474082181119\",\"f64:4618760256179416344\"]],[\"invoke\",2279,0,\"ge\",[\"f64:9218868437227405311\",\"f64:18442240474082181119\"]],[\"invoke\",2284,0,\"ge\",[\"f64:9218868437227405311\",\"f64:9218868437227405312\"]],[\"invoke\",2293,0,\"ge\",[\"f64:18442240474082181120\",\"f64:9223372036854775808\"]],[\"invoke\",2297,0,\"ge\",[\"f64:18442240474082181120\",\"f64:9223372036854775809\"]],[\"invoke\",2302,0,\"ge\",[\"f64:18442240474082181120\",\"f64:4503599627370496\"]],[\"invoke\",2307,0,\"ge\",[\"f64:9218868437227405312\",\"f64:13826050856027422720\"]],[\"invoke\",2312,0,\"ge\",[\"f64:9218868437227405312\",\"f64:4607182418800017408\"]],[\"invoke\",2317,0,\"ge\",[\"f64:18442240474082181120\",\"f64:18442240474082181119\"]],[\"invoke\",2322,0,\"ge\",[\"f64:18442240474082181120\",\"f64:9218868437227405312\"]],[\"invoke\",2329,0,\"ge\",[\"f64:9218868437227405312\",\"f64:18444492273895866368\"]],[\"invoke\",2337,0,\"ge\",[\"f64:9221120237041090560\",\"f64:9223372036854775808\"]],[\"invoke\",2347,0,\"ge\",[\"f64:9221120237041090560\",\"f64:1\"]],[\"invoke\",2357,0,\"ge\",[\"f64:18444492273895866368\",\"f64:13826050856027422720\"]],[\"invoke\",2367,0,\"ge\",[\"f64:18444492273895866368\",\"f64:4607182418800017408\"]],[\"invoke\",2377,0,\"ge\",[\"f64:9221120237041090560\",\"f64:13842132293034192152\"]],[\"invoke\",2387,0,\"ge\",[\"f64:9221120237041090560\",\"f64:9218868437227405311\"]],[\"invoke\",2397,0,\"ge\",[\"f64:18444492273895866368\",\"f64:18444492273895866368\"]],[\"file\",\"f32_bitwise.wast\"],[\"module\",4,4],[\"invoke\",10,0,\"copysign\",[\"f32:2147483648\",\"f32:2147483648\"]],[\"invoke\",11,0,\"copysign\",[\"f32:2147483648\",\"f32:0\"]],[\"invoke\",12,0,\"copysign\",[\"f32:0\",\"f32:2147483648\"]],[\"invoke\",13,0,\"copysign\",[\"f32:0\",\"f32:0\"]],[\"invoke\",14,0,\"copysign\",[\"f32:2147483648\",\"f32:2147483649\"]],[\"invoke\",15,0,\"copysign\",[\"f32:2147483648\",\"f32:1\"]],[\"invoke\",16,0,\"copysign\",[\"f32:0\",\"f32:2147483649\"]],[\"invoke\",17,0,\"copysign\",[\"f32:0\",\"f32:1\"]],[\"invoke\",18,0,\"copysign\",[\"f32:2147483648\",\"f32:2155872256\"]],[\"invoke\",19,0,\"copysign\",[\"f32:2147483648\",\"f32:8388608\"]],[\"invoke\",20,0,\"copysign\",[\"f32:0\",\"f32:2155872256\"]],[\"invoke\",21,0,\"copysign\",[\"f32:0\",\"f32:8388608\"]],[\"invoke\",22,0,\"copysign\",[\"f32:2147483648\",\"f32:3204448256\"]],[\"invoke\",23,0,\"copysign\",[\"f32:2147483648\",\"f32:1056964608\"]],[\"invoke\",24,0,\"copysign\",[\"f32:0\",\"f32:3204448256\"]],[\"invoke\",25,0,\"copysign\",[\"f32:0\",\"f32:1056964608\"]],[\"invoke\",26,0,\"copysign\",[\"f32:2147483648\",\"f32:3212836864\"]],[\"invoke\",27,0,\"copysign\",[\"f32:2147483648\",\"f32:1065353216\"]],[\"invoke\",28,0,\"copysign\",[\"f32:0\",\"f32:3212836864\"]],[\"invoke\",29,0,\"copysign\",[\"f32:0\",\"f32:1065353216\"]],[\"invoke\",30,0,\"copysign\",[\"f32:2147483648\",\"f32:3234402267\"]],[\"invoke\",31,0,\"copysign\",[\"f32:2147483648\",\"f32:1086918619\"]],[\"invoke\",32,0,\"copysign\",[\"f32:0\",\"f32:3234402267\"]],[\"invoke\",33,0,\"copysign\",[\"f32:0\",\"f32:1086918619\"]],[\"invoke\",34,0,\"copysign\",[\"f32:2147483648\",\"f32:4286578687\"]],[\"invoke\",35,0,\"copysign\",[\"f32:2147483648\",\"f32:2139095039\"]],[\"invoke\",36,0,\"copysign\",[\"f32:0\",\"f32:4286578687\"]],[\"invoke\",37,0,\"copysign\",[\"f32:0\",\"f32:2139095039\"]],[\"invoke\",38,0,\"copysign\",[\"f32:2147483648\",\"f32:4286578688\"]],[\"invoke\",39,0,\"copysign\",[\"f32:2147483648\",\"f32:2139095040\"]],[\"invoke\",40,0,\"copysign\",[\"f32:0\",\"f32:4286578688\"]],[\"invoke\",41,0,\"copysign\",[\"f32:0\",\"f32:2139095040\"]],[\"invoke\",42,0,\"copysign\",[\"f32:2147483648\",\"f32:4290772992\"]],[\"invoke\",43,0,\"copysign\",[\"f32:2147483648\",\"f32:2143289344\"]],[\"invoke\",44,0,\"copysign\",[\"f32:0\",\"f32:4290772992\"]],[\"invoke\",45,0,\"copysign\",[\"f32:0\",\"f32:2143289344\"]],[\"invoke\",46,0,\"copysign\",[\"f32:2147483649\",\"f32:2147483648\"]],[\"invoke\",47,0,\"copysign\",[\"f32:2147483649\",\"f32:0\"]],[\"invoke\",48,0,\"copysign\",[\"f32:1\",\"f32:2147483648\"]],[\"invoke\",49,0,\"copysign\",[\"f32:1\",\"f32:0\"]],[\"invoke\",50,0,\"copysign\",[\"f32:2147483649\",\"f32:2147483649\"]],[\"invoke\",51,0,\"copysign\",[\"f32:2147483649\",\"f32:1\"]],[\"invoke\",52,0,\"copysign\",[\"f32:1\",\"f32:2147483649\"]],[\"invoke\",53,0,\"copysign\",[\"f32:1\",\"f32:1\"]],[\"invoke\",54,0,\"copysign\",[\"f32:2147483649\",\"f32:2155872256\"]],[\"invoke\",55,0,\"copysign\",[\"f32:2147483649\",\"f32:8388608\"]],[\"invoke\",56,0,\"copysign\",[\"f32:1\",\"f32:2155872256\"]],[\"invoke\",57,0,\"copysign\",[\"f32:1\",\"f32:8388608\"]],[\"invoke\",58,0,\"copysign\",[\"f32:2147483649\",\"f32:3204448256\"]],[\"invoke\",59,0,\"copysign\",[\"f32:2147483649\",\"f32:1056964608\"]],[\"invoke\",60,0,\"copysign\",[\"f32:1\",\"f32:3204448256\"]],[\"invoke\",61,0,\"copysign\",[\"f32:1\",\"f32:1056964608\"]],[\"invoke\",62,0,\"copysign\",[\"f32:2147483649\",\"f32:3212836864\"]],[\"invoke\",63,0,\"copysign\",[\"f32:2147483649\",\"f32:1065353216\"]],[\"invoke\",64,0,\"copysign\",[\"f32:1\",\"f32:3212836864\"]],[\"invoke\",65,0,\"copysign\",[\"f32:1\",\"f32:1065353216\"]],[\"invoke\",66,0,\"copysign\",[\"f32:2147483649\",\"f32:3234402267\"]],[\"invoke\",67,0,\"copysign\",[\"f32:2147483649\",\"f32:1086918619\"]],[\"invoke\",68,0,\"copysign\",[\"f32:1\",\"f32:3234402267\"]],[\"invoke\",69,0,\"copysign\",[\"f32:1\",\"f32:1086918619\"]],[\"invoke\",70,0,\"copysign\",[\"f32:2147483649\",\"f32:4286578687\"]],[\"invoke\",71,0,\"copysign\",[\"f32:2147483649\",\"f32:2139095039\"]],[\"invoke\",72,0,\"copysign\",[\"f32:1\",\"f32:4286578687\"]],[\"invoke\",73,0,\"copysign\",[\"f32:1\",\"f32:2139095039\"]],[\"invoke\",74,0,\"copysign\",[\"f32:2147483649\",\"f32:4286578688\"]],[\"invoke\",75,0,\"copysign\",[\"f32:2147483649\",\"f32:2139095040\"]],[\"invoke\",76,0,\"copysign\",[\"f32:1\",\"f32:4286578688\"]],[\"invoke\",77,0,\"copysign\",[\"f32:1\",\"f32:2139095040\"]],[\"invoke\",78,0,\"copysign\",[\"f32:2147483649\",\"f32:4290772992\"]],[\"invoke\",79,0,\"copysign\",[\"f32:2147483649\",\"f32:2143289344\"]],[\"invoke\",80,0,\"copysign\",[\"f32:1\",\"f32:4290772992\"]],[\"invoke\",81,0,\"copysign\",[\"f32:1\",\"f32:2143289344\"]],[\"invoke\",82,0,\"copysign\",[\"f32:2155872256\",\"f32:2147483648\"]],[\"invoke\",83,0,\"copysign\",[\"f32:2155872256\",\"f32:0\"]],[\"invoke\",84,0,\"copysign\",[\"f32:8388608\",\"f32:2147483648\"]],[\"invoke\",85,0,\"copysign\",[\"f32:8388608\",\"f32:0\"]],[\"invoke\",86,0,\"copysign\",[\"f32:2155872256\",\"f32:2147483649\"]],[\"invoke\",87,0,\"copysign\",[\"f32:2155872256\",\"f32:1\"]],[\"invoke\",88,0,\"copysign\",[\"f32:8388608\",\"f32:2147483649\"]],[\"invoke\",89,0,\"copysign\",[\"f32:8388608\",\"f32:1\"]],[\"invoke\",90,0,\"copysign\",[\"f32:2155872256\",\"f32:2155872256\"]],[\"invoke\",91,0,\"copysign\",[\"f32:2155872256\",\"f32:8388608\"]],[\"invoke\",92,0,\"copysign\",[\"f32:8388608\",\"f32:2155872256\"]],[\"invoke\",93,0,\"copysign\",[\"f32:8388608\",\"f32:8388608\"]],[\"invoke\",94,0,\"copysign\",[\"f32:2155872256\",\"f32:3204448256\"]],[\"invoke\",95,0,\"copysign\",[\"f32:2155872256\",\"f32:1056964608\"]],[\"invoke\",96,0,\"copysign\",[\"f32:8388608\",\"f32:3204448256\"]],[\"invoke\",97,0,\"copysign\",[\"f32:8388608\",\"f32:1056964608\"]],[\"invoke\",98,0,\"copysign\",[\"f32:2155872256\",\"f32:3212836864\"]],[\"invoke\",99,0,\"copysign\",[\"f32:2155872256\",\"f32:1065353216\"]],[\"invoke\",100,0,\"copysign\",[\"f32:8388608\",\"f32:3212836864\"]],[\"invoke\",101,0,\"copysign\",[\"f32:8388608\",\"f32:1065353216\"]],[\"invoke\",102,0,\"copysign\",[\"f32:2155872256\",\"f32:3234402267\"]],[\"invoke\",103,0,\"copysign\",[\"f32:2155872256\",\"f32:1086918619\"]],[\"invoke\",104,0,\"copysign\",[\"f32:8388608\",\"f32:3234402267\"]],[\"invoke\",105,0,\"copysign\",[\"f32:8388608\",\"f32:1086918619\"]],[\"invoke\",106,0,\"copysign\",[\"f32:2155872256\",\"f32:4286578687\"]],[\"invoke\",107,0,\"copysign\",[\"f32:2155872256\",\"f32:2139095039\"]],[\"invoke\",108,0,\"copysign\",[\"f32:8388608\",\"f32:4286578687\"]],[\"invoke\",109,0,\"copysign\",[\"f32:8388608\",\"f32:2139095039\"]],[\"invoke\",110,0,\"copysign\",[\"f32:2155872256\",\"f32:4286578688\"]],[\"invoke\",111,0,\"copysign\",[\"f32:2155872256\",\"f32:2139095040\"]],[\"invoke\",112,0,\"copysign\",[\"f32:8388608\",\"f32:4286578688\"]],[\"invoke\",113,0,\"copysign\",[\"f32:8388608\",\"f32:2139095040\"]],[\"invoke\",114,0,\"copysign\",[\"f32:2155872256\",\"f32:4290772992\"]],[\"invoke\",115,0,\"copysign\",[\"f32:2155872256\",\"f32:2143289344\"]],[\"invoke\",116,0,\"copysign\",[\"f32:8388608\",\"f32:4290772992\"]],[\"invoke\",117,0,\"copysign\",[\"f32:8388608\",\"f32:2143289344\"]],[\"invoke\",118,0,\"copysign\",[\"f32:3204448256\",\"f32:2147483648\"]],[\"invoke\",119,0,\"copysign\",[\"f32:3204448256\",\"f32:0\"]],[\"invoke\",120,0,\"copysign\",[\"f32:1056964608\",\"f32:2147483648\"]],[\"invoke\",121,0,\"copysign\",[\"f32:1056964608\",\"f32:0\"]],[\"invoke\",122,0,\"copysign\",[\"f32:3204448256\",\"f32:2147483649\"]],[\"invoke\",123,0,\"copysign\",[\"f32:3204448256\",\"f32:1\"]],[\"invoke\",124,0,\"copysign\",[\"f32:1056964608\",\"f32:2147483649\"]],[\"invoke\",125,0,\"copysign\",[\"f32:1056964608\",\"f32:1\"]],[\"invoke\",126,0,\"copysign\",[\"f32:3204448256\",\"f32:2155872256\"]],[\"invoke\",127,0,\"copysign\",[\"f32:3204448256\",\"f32:8388608\"]],[\"invoke\",128,0,\"copysign\",[\"f32:1056964608\",\"f32:2155872256\"]],[\"invoke\",129,0,\"copysign\",[\"f32:1056964608\",\"f32:8388608\"]],[\"invoke\",130,0,\"copysign\",[\"f32:3204448256\",\"f32:3204448256\"]],[\"invoke\",131,0,\"copysign\",[\"f32:3204448256\",\"f32:1056964608\"]],[\"invoke\",132,0,\"copysign\",[\"f32:1056964608\",\"f32:3204448256\"]],[\"invoke\",133,0,\"copysign\",[\"f32:1056964608\",\"f32:1056964608\"]],[\"invoke\",134,0,\"copysign\",[\"f32:3204448256\",\"f32:3212836864\"]],[\"invoke\",135,0,\"copysign\",[\"f32:3204448256\",\"f32:1065353216\"]],[\"invoke\",136,0,\"copysign\",[\"f32:1056964608\",\"f32:3212836864\"]],[\"invoke\",137,0,\"copysign\",[\"f32:1056964608\",\"f32:1065353216\"]],[\"invoke\",138,0,\"copysign\",[\"f32:3204448256\",\"f32:3234402267\"]],[\"invoke\",139,0,\"copysign\",[\"f32:3204448256\",\"f32:1086918619\"]],[\"invoke\",140,0,\"copysign\",[\"f32:1056964608\",\"f32:3234402267\"]],[\"invoke\",141,0,\"copysign\",[\"f32:1056964608\",\"f32:1086918619\"]],[\"invoke\",142,0,\"copysign\",[\"f32:3204448256\",\"f32:4286578687\"]],[\"invoke\",143,0,\"copysign\",[\"f32:3204448256\",\"f32:2139095039\"]],[\"invoke\",144,0,\"copysign\",[\"f32:1056964608\",\"f32:4286578687\"]],[\"invoke\",145,0,\"copysign\",[\"f32:1056964608\",\"f32:2139095039\"]],[\"invoke\",146,0,\"copysign\",[\"f32:3204448256\",\"f32:4286578688\"]],[\"invoke\",147,0,\"copysign\",[\"f32:3204448256\",\"f32:2139095040\"]],[\"invoke\",148,0,\"copysign\",[\"f32:1056964608\",\"f32:4286578688\"]],[\"invoke\",149,0,\"copysign\",[\"f32:1056964608\",\"f32:2139095040\"]],[\"invoke\",150,0,\"copysign\",[\"f32:3204448256\",\"f32:4290772992\"]],[\"invoke\",151,0,\"copysign\",[\"f32:3204448256\",\"f32:2143289344\"]],[\"invoke\",152,0,\"copysign\",[\"f32:1056964608\",\"f32:4290772992\"]],[\"invoke\",153,0,\"copysign\",[\"f32:1056964608\",\"f32:2143289344\"]],[\"invoke\",154,0,\"copysign\",[\"f32:3212836864\",\"f32:2147483648\"]],[\"invoke\",155,0,\"copysign\",[\"f32:3212836864\",\"f32:0\"]],[\"invoke\",156,0,\"copysign\",[\"f32:1065353216\",\"f32:2147483648\"]],[\"invoke\",157,0,\"copysign\",[\"f32:1065353216\",\"f32:0\"]],[\"invoke\",158,0,\"copysign\",[\"f32:3212836864\",\"f32:2147483649\"]],[\"invoke\",159,0,\"copysign\",[\"f32:3212836864\",\"f32:1\"]],[\"invoke\",160,0,\"copysign\",[\"f32:1065353216\",\"f32:2147483649\"]],[\"invoke\",161,0,\"copysign\",[\"f32:1065353216\",\"f32:1\"]],[\"invoke\",162,0,\"copysign\",[\"f32:3212836864\",\"f32:2155872256\"]],[\"invoke\",163,0,\"copysign\",[\"f32:3212836864\",\"f32:8388608\"]],[\"invoke\",164,0,\"copysign\",[\"f32:1065353216\",\"f32:2155872256\"]],[\"invoke\",165,0,\"copysign\",[\"f32:1065353216\",\"f32:8388608\"]],[\"invoke\",166,0,\"copysign\",[\"f32:3212836864\",\"f32:3204448256\"]],[\"invoke\",167,0,\"copysign\",[\"f32:3212836864\",\"f32:1056964608\"]],[\"invoke\",168,0,\"copysign\",[\"f32:1065353216\",\"f32:3204448256\"]],[\"invoke\",169,0,\"copysign\",[\"f32:1065353216\",\"f32:1056964608\"]],[\"invoke\",170,0,\"copysign\",[\"f32:3212836864\",\"f32:3212836864\"]],[\"invoke\",171,0,\"copysign\",[\"f32:3212836864\",\"f32:1065353216\"]],[\"invoke\",172,0,\"copysign\",[\"f32:1065353216\",\"f32:3212836864\"]],[\"invoke\",173,0,\"copysign\",[\"f32:1065353216\",\"f32:1065353216\"]],[\"invoke\",174,0,\"copysign\",[\"f32:3212836864\",\"f32:3234402267\"]],[\"invoke\",175,0,\"copysign\",[\"f32:3212836864\",\"f32:1086918619\"]],[\"invoke\",176,0,\"copysign\",[\"f32:1065353216\",\"f32:3234402267\"]],[\"invoke\",177,0,\"copysign\",[\"f32:1065353216\",\"f32:1086918619\"]],[\"invoke\",178,0,\"copysign\",[\"f32:3212836864\",\"f32:4286578687\"]],[\"invoke\",179,0,\"copysign\",[\"f32:3212836864\",\"f32:2139095039\"]],[\"invoke\",180,0,\"copysign\",[\"f32:1065353216\",\"f32:4286578687\"]],[\"invoke\",181,0,\"copysign\",[\"f32:1065353216\",\"f32:2139095039\"]],[\"invoke\",182,0,\"copysign\",[\"f32:3212836864\",\"f32:4286578688\"]],[\"invoke\",183,0,\"copysign\",[\"f32:3212836864\",\"f32:2139095040\"]],[\"invoke\",184,0,\"copysign\",[\"f32:1065353216\",\"f32:4286578688\"]],[\"invoke\",185,0,\"copysign\",[\"f32:1065353216\",\"f32:2139095040\"]],[\"invoke\",186,0,\"copysign\",[\"f32:3212836864\",\"f32:4290772992\"]],[\"invoke\",187,0,\"copysign\",[\"f32:3212836864\",\"f32:2143289344\"]],[\"invoke\",188,0,\"copysign\",[\"f32:1065353216\",\"f32:4290772992\"]],[\"invoke\",189,0,\"copysign\",[\"f32:1065353216\",\"f32:2143289344\"]],[\"invoke\",190,0,\"copysign\",[\"f32:3234402267\",\"f32:2147483648\"]],[\"invoke\",191,0,\"copysign\",[\"f32:3234402267\",\"f32:0\"]],[\"invoke\",192,0,\"copysign\",[\"f32:1086918619\",\"f32:2147483648\"]],[\"invoke\",193,0,\"copysign\",[\"f32:1086918619\",\"f32:0\"]],[\"invoke\",194,0,\"copysign\",[\"f32:3234402267\",\"f32:2147483649\"]],[\"invoke\",195,0,\"copysign\",[\"f32:3234402267\",\"f32:1\"]],[\"invoke\",196,0,\"copysign\",[\"f32:1086918619\",\"f32:2147483649\"]],[\"invoke\",197,0,\"copysign\",[\"f32:1086918619\",\"f32:1\"]],[\"invoke\",198,0,\"copysign\",[\"f32:3234402267\",\"f32:2155872256\"]],[\"invoke\",199,0,\"copysign\",[\"f32:3234402267\",\"f32:8388608\"]],[\"invoke\",200,0,\"copysign\",[\"f32:1086918619\",\"f32:2155872256\"]],[\"invoke\",201,0,\"copysign\",[\"f32:1086918619\",\"f32:8388608\"]],[\"invoke\",202,0,\"copysign\",[\"f32:3234402267\",\"f32:3204448256\"]],[\"invoke\",203,0,\"copysign\",[\"f32:3234402267\",\"f32:1056964608\"]],[\"invoke\",204,0,\"copysign\",[\"f32:1086918619\",\"f32:3204448256\"]],[\"invoke\",205,0,\"copysign\",[\"f32:1086918619\",\"f32:1056964608\"]],[\"invoke\",206,0,\"copysign\",[\"f32:3234402267\",\"f32:3212836864\"]],[\"invoke\",207,0,\"copysign\",[\"f32:3234402267\",\"f32:1065353216\"]],[\"invoke\",208,0,\"copysign\",[\"f32:1086918619\",\"f32:3212836864\"]],[\"invoke\",209,0,\"copysign\",[\"f32:1086918619\",\"f32:1065353216\"]],[\"invoke\",210,0,\"copysign\",[\"f32:3234402267\",\"f32:3234402267\"]],[\"invoke\",211,0,\"copysign\",[\"f32:3234402267\",\"f32:1086918619\"]],[\"invoke\",212,0,\"copysign\",[\"f32:1086918619\",\"f32:3234402267\"]],[\"invoke\",213,0,\"copysign\",[\"f32:1086918619\",\"f32:1086918619\"]],[\"invoke\",214,0,\"copysign\",[\"f32:3234402267\",\"f32:4286578687\"]],[\"invoke\",215,0,\"copysign\",[\"f32:3234402267\",\"f32:2139095039\"]],[\"invoke\",216,0,\"copysign\",[\"f32:1086918619\",\"f32:4286578687\"]],[\"invoke\",217,0,\"copysign\",[\"f32:1086918619\",\"f32:2139095039\"]],[\"invoke\",218,0,\"copysign\",[\"f32:3234402267\",\"f32:4286578688\"]],[\"invoke\",219,0,\"copysign\",[\"f32:3234402267\",\"f32:2139095040\"]],[\"invoke\",220,0,\"copysign\",[\"f32:1086918619\",\"f32:4286578688\"]],[\"invoke\",221,0,\"copysign\",[\"f32:1086918619\",\"f32:2139095040\"]],[\"invoke\",222,0,\"copysign\",[\"f32:3234402267\",\"f32:4290772992\"]],[\"invoke\",223,0,\"copysign\",[\"f32:3234402267\",\"f32:2143289344\"]],[\"invoke\",224,0,\"copysign\",[\"f32:1086918619\",\"f32:4290772992\"]],[\"invoke\",225,0,\"copysign\",[\"f32:1086918619\",\"f32:2143289344\"]],[\"invoke\",226,0,\"copysign\",[\"f32:4286578687\",\"f32:2147483648\"]],[\"invoke\",227,0,\"copysign\",[\"f32:4286578687\",\"f32:0\"]],[\"invoke\",228,0,\"copysign\",[\"f32:2139095039\",\"f32:2147483648\"]],[\"invoke\",229,0,\"copysign\",[\"f32:2139095039\",\"f32:0\"]],[\"invoke\",230,0,\"copysign\",[\"f32:4286578687\",\"f32:2147483649\"]],[\"invoke\",231,0,\"copysign\",[\"f32:4286578687\",\"f32:1\"]],[\"invoke\",232,0,\"copysign\",[\"f32:2139095039\",\"f32:2147483649\"]],[\"invoke\",233,0,\"copysign\",[\"f32:2139095039\",\"f32:1\"]],[\"invoke\",234,0,\"copysign\",[\"f32:4286578687\",\"f32:2155872256\"]],[\"invoke\",235,0,\"copysign\",[\"f32:4286578687\",\"f32:8388608\"]],[\"invoke\",236,0,\"copysign\",[\"f32:2139095039\",\"f32:2155872256\"]],[\"invoke\",237,0,\"copysign\",[\"f32:2139095039\",\"f32:8388608\"]],[\"invoke\",238,0,\"copysign\",[\"f32:4286578687\",\"f32:3204448256\"]],[\"invoke\",239,0,\"copysign\",[\"f32:4286578687\",\"f32:1056964608\"]],[\"invoke\",240,0,\"copysign\",[\"f32:2139095039\",\"f32:3204448256\"]],[\"invoke\",241,0,\"copysign\",[\"f32:2139095039\",\"f32:1056964608\"]],[\"invoke\",242,0,\"copysign\",[\"f32:4286578687\",\"f32:3212836864\"]],[\"invoke\",243,0,\"copysign\",[\"f32:4286578687\",\"f32:1065353216\"]],[\"invoke\",244,0,\"copysign\",[\"f32:2139095039\",\"f32:3212836864\"]],[\"invoke\",245,0,\"copysign\",[\"f32:2139095039\",\"f32:1065353216\"]],[\"invoke\",246,0,\"copysign\",[\"f32:4286578687\",\"f32:3234402267\"]],[\"invoke\",247,0,\"copysign\",[\"f32:4286578687\",\"f32:1086918619\"]],[\"invoke\",248,0,\"copysign\",[\"f32:2139095039\",\"f32:3234402267\"]],[\"invoke\",249,0,\"copysign\",[\"f32:2139095039\",\"f32:1086918619\"]],[\"invoke\",250,0,\"copysign\",[\"f32:4286578687\",\"f32:4286578687\"]],[\"invoke\",251,0,\"copysign\",[\"f32:4286578687\",\"f32:2139095039\"]],[\"invoke\",252,0,\"copysign\",[\"f32:2139095039\",\"f32:4286578687\"]],[\"invoke\",253,0,\"copysign\",[\"f32:2139095039\",\"f32:2139095039\"]],[\"invoke\",254,0,\"copysign\",[\"f32:4286578687\",\"f32:4286578688\"]],[\"invoke\",255,0,\"copysign\",[\"f32:4286578687\",\"f32:2139095040\"]],[\"invoke\",256,0,\"copysign\",[\"f32:2139095039\",\"f32:4286578688\"]],[\"invoke\",257,0,\"copysign\",[\"f32:2139095039\",\"f32:2139095040\"]],[\"invoke\",258,0,\"copysign\",[\"f32:4286578687\",\"f32:4290772992\"]],[\"invoke\",259,0,\"copysign\",[\"f32:4286578687\",\"f32:2143289344\"]],[\"invoke\",260,0,\"copysign\",[\"f32:2139095039\",\"f32:4290772992\"]],[\"invoke\",261,0,\"copysign\",[\"f32:2139095039\",\"f32:2143289344\"]],[\"invoke\",262,0,\"copysign\",[\"f32:4286578688\",\"f32:2147483648\"]],[\"invoke\",263,0,\"copysign\",[\"f32:4286578688\",\"f32:0\"]],[\"invoke\",264,0,\"copysign\",[\"f32:2139095040\",\"f32:2147483648\"]],[\"invoke\",265,0,\"copysign\",[\"f32:2139095040\",\"f32:0\"]],[\"invoke\",266,0,\"copysign\",[\"f32:4286578688\",\"f32:2147483649\"]],[\"invoke\",267,0,\"copysign\",[\"f32:4286578688\",\"f32:1\"]],[\"invoke\",268,0,\"copysign\",[\"f32:2139095040\",\"f32:2147483649\"]],[\"invoke\",269,0,\"copysign\",[\"f32:2139095040\",\"f32:1\"]],[\"invoke\",270,0,\"copysign\",[\"f32:4286578688\",\"f32:2155872256\"]],[\"invoke\",271,0,\"copysign\",[\"f32:4286578688\",\"f32:8388608\"]],[\"invoke\",272,0,\"copysign\",[\"f32:2139095040\",\"f32:2155872256\"]],[\"invoke\",273,0,\"copysign\",[\"f32:2139095040\",\"f32:8388608\"]],[\"invoke\",274,0,\"copysign\",[\"f32:4286578688\",\"f32:3204448256\"]],[\"invoke\",275,0,\"copysign\",[\"f32:4286578688\",\"f32:1056964608\"]],[\"invoke\",276,0,\"copysign\",[\"f32:2139095040\",\"f32:3204448256\"]],[\"invoke\",277,0,\"copysign\",[\"f32:2139095040\",\"f32:1056964608\"]],[\"invoke\",278,0,\"copysign\",[\"f32:4286578688\",\"f32:3212836864\"]],[\"invoke\",279,0,\"copysign\",[\"f32:4286578688\",\"f32:1065353216\"]],[\"invoke\",280,0,\"copysign\",[\"f32:2139095040\",\"f32:3212836864\"]],[\"invoke\",281,0,\"copysign\",[\"f32:2139095040\",\"f32:1065353216\"]],[\"invoke\",282,0,\"copysign\",[\"f32:4286578688\",\"f32:3234402267\"]],[\"invoke\",283,0,\"copysign\",[\"f32:4286578688\",\"f32:1086918619\"]],[\"invoke\",284,0,\"copysign\",[\"f32:2139095040\",\"f32:3234402267\"]],[\"invoke\",285,0,\"copysign\",[\"f32:2139095040\",\"f32:1086918619\"]],[\"invoke\",286,0,\"copysign\",[\"f32:4286578688\",\"f32:4286578687\"]],[\"invoke\",287,0,\"copysign\",[\"f32:4286578688\",\"f32:2139095039\"]],[\"invoke\",288,0,\"copysign\",[\"f32:2139095040\",\"f32:4286578687\"]],[\"invoke\",289,0,\"copysign\",[\"f32:2139095040\",\"f32:2139095039\"]],[\"invoke\",290,0,\"copysign\",[\"f32:4286578688\",\"f32:4286578688\"]],[\"invoke\",291,0,\"copysign\",[\"f32:4286578688\",\"f32:2139095040\"]],[\"invoke\",292,0,\"copysign\",[\"f32:2139095040\",\"f32:4286578688\"]],[\"invoke\",293,0,\"copysign\",[\"f32:2139095040\",\"f32:2139095040\"]],[\"invoke\",294,0,\"copysign\",[\"f32:4286578688\",\"f32:4290772992\"]],[\"invoke\",295,0,\"copysign\",[\"f32:4286578688\",\"f32:2143289344\"]],[\"invoke\",296,0,\"copysign\",[\"f32:2139095040\",\"f32:4290772992\"]],[\"invoke\",297,0,\"copysign\",[\"f32:2139095040\",\"f32:2143289344\"]],[\"invoke\",298,0,\"copysign\",[\"f32:4290772992\",\"f32:2147483648\"]],[\"invoke\",299,0,\"copysign\",[\"f32:4290772992\",\"f32:0\"]],[\"invoke\",300,0,\"copysign\",[\"f32:2143289344\",\"f32:2147483648\"]],[\"invoke\",301,0,\"copysign\",[\"f32:2143289344\",\"f32:0\"]],[\"invoke\",302,0,\"copysign\",[\"f32:4290772992\",\"f32:2147483649\"]],[\"invoke\",303,0,\"copysign\",[\"f32:4290772992\",\"f32:1\"]],[\"invoke\",304,0,\"copysign\",[\"f32:2143289344\",\"f32:2147483649\"]],[\"invoke\",305,0,\"copysign\",[\"f32:2143289344\",\"f32:1\"]],[\"invoke\",306,0,\"copysign\",[\"f32:4290772992\",\"f32:2155872256\"]],[\"invoke\",307,0,\"copysign\",[\"f32:4290772992\",\"f32:8388608\"]],[\"invoke\",308,0,\"copysign\",[\"f32:2143289344\",\"f32:2155872256\"]],[\"invoke\",309,0,\"copysign\",[\"f32:2143289344\",\"f32:8388608\"]],[\"invoke\",310,0,\"copysign\",[\"f32:4290772992\",\"f32:3204448256\"]],[\"invoke\",311,0,\"copysign\",[\"f32:4290772992\",\"f32:1056964608\"]],[\"invoke\",312,0,\"copysign\",[\"f32:2143289344\",\"f32:3204448256\"]],[\"invoke\",313,0,\"copysign\",[\"f32:2143289344\",\"f32:1056964608\"]],[\"invoke\",314,0,\"copysign\",[\"f32:4290772992\",\"f32:3212836864\"]],[\"invoke\",315,0,\"copysign\",[\"f32:4290772992\",\"f32:1065353216\"]],[\"invoke\",316,0,\"copysign\",[\"f32:2143289344\",\"f32:3212836864\"]],[\"invoke\",317,0,\"copysign\",[\"f32:2143289344\",\"f32:1065353216\"]],[\"invoke\",318,0,\"copysign\",[\"f32:4290772992\",\"f32:3234402267\"]],[\"invoke\",319,0,\"copysign\",[\"f32:4290772992\",\"f32:1086918619\"]],[\"invoke\",320,0,\"copysign\",[\"f32:2143289344\",\"f32:3234402267\"]],[\"invoke\",321,0,\"copysign\",[\"f32:2143289344\",\"f32:1086918619\"]],[\"invoke\",322,0,\"copysign\",[\"f32:4290772992\",\"f32:4286578687\"]],[\"invoke\",323,0,\"copysign\",[\"f32:4290772992\",\"f32:2139095039\"]],[\"invoke\",324,0,\"copysign\",[\"f32:2143289344\",\"f32:4286578687\"]],[\"invoke\",325,0,\"copysign\",[\"f32:2143289344\",\"f32:2139095039\"]],[\"invoke\",326,0,\"copysign\",[\"f32:4290772992\",\"f32:4286578688\"]],[\"invoke\",327,0,\"copysign\",[\"f32:4290772992\",\"f32:2139095040\"]],[\"invoke\",328,0,\"copysign\",[\"f32:2143289344\",\"f32:4286578688\"]],[\"invoke\",329,0,\"copysign\",[\"f32:2143289344\",\"f32:2139095040\"]],[\"invoke\",330,0,\"copysign\",[\"f32:4290772992\",\"f32:4290772992\"]],[\"invoke\",331,0,\"copysign\",[\"f32:4290772992\",\"f32:2143289344\"]],[\"invoke\",332,0,\"copysign\",[\"f32:2143289344\",\"f32:4290772992\"]],[\"invoke\",333,0,\"copysign\",[\"f32:2143289344\",\"f32:2143289344\"]],[\"invoke\",334,0,\"abs\",[\"f32:2147483648\"]],[\"invoke\",335,0,\"abs\",[\"f32:0\"]],[\"invoke\",336,0,\"abs\",[\"f32:2147483649\"]],[\"invoke\",337,0,\"abs\",[\"f32:1\"]],[\"invoke\",338,0,\"abs\",[\"f32:2155872256\"]],[\"invoke\",339,0,\"abs\",[\"f32:8388608\"]],[\"invoke\",340,0,\"abs\",[\"f32:3204448256\"]],[\"invoke\",341,0,\"abs\",[\"f32:1056964608\"]],[\"invoke\",342,0,\"abs\",[\"f32:3212836864\"]],[\"invoke\",343,0,\"abs\",[\"f32:1065353216\"]],[\"invoke\",344,0,\"abs\",[\"f32:3234402267\"]],[\"invoke\",345,0,\"abs\",[\"f32:1086918619\"]],[\"invoke\",346,0,\"abs\",[\"f32:4286578687\"]],[\"invoke\",347,0,\"abs\",[\"f32:2139095039\"]],[\"invoke\",348,0,\"abs\",[\"f32:4286578688\"]],[\"invoke\",349,0,\"abs\",[\"f32:2139095040\"]],[\"invoke\",350,0,\"abs\",[\"f32:4290772992\"]],[\"invoke\",351,0,\"abs\",[\"f32:2143289344\"]],[\"invoke\",352,0,\"neg\",[\"f32:2147483648\"]],[\"invoke\",353,0,\"neg\",[\"f32:0\"]],[\"invoke\",354,0,\"neg\",[\"f32:2147483649\"]],[\"invoke\",355,0,\"neg\",[\"f32:1\"]],[\"invoke\",356,0,\"neg\",[\"f32:2155872256\"]],[\"invoke\",357,0,\"neg\",[\"f32:8388608\"]],[\"invoke\",358,0,\"neg\",[\"f32:3204448256\"]],[\"invoke\",359,0,\"neg\",[\"f32:1056964608\"]],[\"invoke\",360,0,\"neg\",[\"f32:3212836864\"]],[\"invoke\",361,0,\"neg\",[\"f32:1065353216\"]],[\"invoke\",362,0,\"neg\",[\"f32:3234402267\"]],[\"invoke\",363,0,\"neg\",[\"f32:1086918619\"]],[\"invoke\",364,0,\"neg\",[\"f32:4286578687\"]],[\"invoke\",365,0,\"neg\",[\"f32:2139095039\"]],[\"invoke\",366,0,\"neg\",[\"f32:4286578688\"]],[\"invoke\",367,0,\"neg\",[\"f32:2139095040\"]],[\"invoke\",368,0,\"neg\",[\"f32:4290772992\"]],[\"invoke\",369,0,\"neg\",[\"f32:2143289344\"]],[\"file\",\"f64_bitwise.wast\"],[\"module\",4,5],[\"invoke\",10,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:9223372036854775808\"]],[\"invoke\",11,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:0\"]],[\"invoke\",12,0,\"copysign\",[\"f64:0\",\"f64:9223372036854775808\"]],[\"invoke\",13,0,\"copysign\",[\"f64:0\",\"f64:0\"]],[\"invoke\",14,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:9223372036854775809\"]],[\"invoke\",15,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:1\"]],[\"invoke\",16,0,\"copysign\",[\"f64:0\",\"f64:9223372036854775809\"]],[\"invoke\",17,0,\"copysign\",[\"f64:0\",\"f64:1\"]],[\"invoke\",18,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:9227875636482146304\"]],[\"invoke\",19,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:4503599627370496\"]],[\"invoke\",20,0,\"copysign\",[\"f64:0\",\"f64:9227875636482146304\"]],[\"invoke\",21,0,\"copysign\",[\"f64:0\",\"f64:4503599627370496\"]],[\"invoke\",22,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:13826050856027422720\"]],[\"invoke\",23,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:4602678819172646912\"]],[\"invoke\",24,0,\"copysign\",[\"f64:0\",\"f64:13826050856027422720\"]],[\"invoke\",25,0,\"copysign\",[\"f64:0\",\"f64:4602678819172646912\"]],[\"invoke\",26,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:13830554455654793216\"]],[\"invoke\",27,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:4607182418800017408\"]],[\"invoke\",28,0,\"copysign\",[\"f64:0\",\"f64:13830554455654793216\"]],[\"invoke\",29,0,\"copysign\",[\"f64:0\",\"f64:4607182418800017408\"]],[\"invoke\",30,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:13842132293034192152\"]],[\"invoke\",31,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:4618760256179416344\"]],[\"invoke\",32,0,\"copysign\",[\"f64:0\",\"f64:13842132293034192152\"]],[\"invoke\",33,0,\"copysign\",[\"f64:0\",\"f64:4618760256179416344\"]],[\"invoke\",34,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:18442240474082181119\"]],[\"invoke\",35,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:9218868437227405311\"]],[\"invoke\",36,0,\"copysign\",[\"f64:0\",\"f64:18442240474082181119\"]],[\"invoke\",37,0,\"copysign\",[\"f64:0\",\"f64:9218868437227405311\"]],[\"invoke\",38,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:18442240474082181120\"]],[\"invoke\",39,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:9218868437227405312\"]],[\"invoke\",40,0,\"copysign\",[\"f64:0\",\"f64:18442240474082181120\"]],[\"invoke\",41,0,\"copysign\",[\"f64:0\",\"f64:9218868437227405312\"]],[\"invoke\",42,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:18444492273895866368\"]],[\"invoke\",43,0,\"copysign\",[\"f64:9223372036854775808\",\"f64:9221120237041090560\"]],[\"invoke\",44,0,\"copysign\",[\"f64:0\",\"f64:18444492273895866368\"]],[\"invoke\",45,0,\"copysign\",[\"f64:0\",\"f64:9221120237041090560\"]],[\"invoke\",46,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:9223372036854775808\"]],[\"invoke\",47,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:0\"]],[\"invoke\",48,0,\"copysign\",[\"f64:1\",\"f64:9223372036854775808\"]],[\"invoke\",49,0,\"copysign\",[\"f64:1\",\"f64:0\"]],[\"invoke\",50,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:9223372036854775809\"]],[\"invoke\",51,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:1\"]],[\"invoke\",52,0,\"copysign\",[\"f64:1\",\"f64:9223372036854775809\"]],[\"invoke\",53,0,\"copysign\",[\"f64:1\",\"f64:1\"]],[\"invoke\",54,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:9227875636482146304\"]],[\"invoke\",55,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:4503599627370496\"]],[\"invoke\",56,0,\"copysign\",[\"f64:1\",\"f64:9227875636482146304\"]],[\"invoke\",57,0,\"copysign\",[\"f64:1\",\"f64:4503599627370496\"]],[\"invoke\",58,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:13826050856027422720\"]],[\"invoke\",59,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:4602678819172646912\"]],[\"invoke\",60,0,\"copysign\",[\"f64:1\",\"f64:13826050856027422720\"]],[\"invoke\",61,0,\"copysign\",[\"f64:1\",\"f64:4602678819172646912\"]],[\"invoke\",62,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:13830554455654793216\"]],[\"invoke\",63,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:4607182418800017408\"]],[\"invoke\",64,0,\"copysign\",[\"f64:1\",\"f64:13830554455654793216\"]],[\"invoke\",65,0,\"copysign\",[\"f64:1\",\"f64:4607182418800017408\"]],[\"invoke\",66,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:13842132293034192152\"]],[\"invoke\",67,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:4618760256179416344\"]],[\"invoke\",68,0,\"copysign\",[\"f64:1\",\"f64:13842132293034192152\"]],[\"invoke\",69,0,\"copysign\",[\"f64:1\",\"f64:4618760256179416344\"]],[\"invoke\",70,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:18442240474082181119\"]],[\"invoke\",71,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:9218868437227405311\"]],[\"invoke\",72,0,\"copysign\",[\"f64:1\",\"f64:18442240474082181119\"]],[\"invoke\",73,0,\"copysign\",[\"f64:1\",\"f64:9218868437227405311\"]],[\"invoke\",74,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:18442240474082181120\"]],[\"invoke\",75,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:9218868437227405312\"]],[\"invoke\",76,0,\"copysign\",[\"f64:1\",\"f64:18442240474082181120\"]],[\"invoke\",77,0,\"copysign\",[\"f64:1\",\"f64:9218868437227405312\"]],[\"invoke\",78,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:18444492273895866368\"]],[\"invoke\",79,0,\"copysign\",[\"f64:9223372036854775809\",\"f64:9221120237041090560\"]],[\"invoke\",80,0,\"copysign\",[\"f64:1\",\"f64:18444492273895866368\"]],[\"invoke\",81,0,\"copysign\",[\"f64:1\",\"f64:9221120237041090560\"]],[\"invoke\",82,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:9223372036854775808\"]],[\"invoke\",83,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:0\"]],[\"invoke\",84,0,\"copysign\",[\"f64:4503599627370496\",\"f64:9223372036854775808\"]],[\"invoke\",85,0,\"copysign\",[\"f64:4503599627370496\",\"f64:0\"]],[\"invoke\",86,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:9223372036854775809\"]],[\"invoke\",87,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:1\"]],[\"invoke\",88,0,\"copysign\",[\"f64:4503599627370496\",\"f64:9223372036854775809\"]],[\"invoke\",89,0,\"copysign\",[\"f64:4503599627370496\",\"f64:1\"]],[\"invoke\",90,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:9227875636482146304\"]],[\"invoke\",91,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:4503599627370496\"]],[\"invoke\",92,0,\"copysign\",[\"f64:4503599627370496\",\"f64:9227875636482146304\"]],[\"invoke\",93,0,\"copysign\",[\"f64:4503599627370496\",\"f64:4503599627370496\"]],[\"invoke\",94,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:13826050856027422720\"]],[\"invoke\",95,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:4602678819172646912\"]],[\"invoke\",96,0,\"copysign\",[\"f64:4503599627370496\",\"f64:13826050856027422720\"]],[\"invoke\",97,0,\"copysign\",[\"f64:4503599627370496\",\"f64:4602678819172646912\"]],[\"invoke\",98,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:13830554455654793216\"]],[\"invoke\",99,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:4607182418800017408\"]],[\"invoke\",100,0,\"copysign\",[\"f64:4503599627370496\",\"f64:13830554455654793216\"]],[\"invoke\",101,0,\"copysign\",[\"f64:4503599627370496\",\"f64:4607182418800017408\"]],[\"invoke\",102,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:13842132293034192152\"]],[\"invoke\",103,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:4618760256179416344\"]],[\"invoke\",104,0,\"copysign\",[\"f64:4503599627370496\",\"f64:13842132293034192152\"]],[\"invoke\",105,0,\"copysign\",[\"f64:4503599627370496\",\"f64:4618760256179416344\"]],[\"invoke\",106,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:18442240474082181119\"]],[\"invoke\",107,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:9218868437227405311\"]],[\"invoke\",108,0,\"copysign\",[\"f64:4503599627370496\",\"f64:18442240474082181119\"]],[\"invoke\",109,0,\"copysign\",[\"f64:4503599627370496\",\"f64:9218868437227405311\"]],[\"invoke\",110,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:18442240474082181120\"]],[\"invoke\",111,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:9218868437227405312\"]],[\"invoke\",112,0,\"copysign\",[\"f64:4503599627370496\",\"f64:18442240474082181120\"]],[\"invoke\",113,0,\"copysign\",[\"f64:4503599627370496\",\"f64:9218868437227405312\"]],[\"invoke\",114,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:18444492273895866368\"]],[\"invoke\",115,0,\"copysign\",[\"f64:9227875636482146304\",\"f64:9221120237041090560\"]],[\"invoke\",116,0,\"copysign\",[\"f64:4503599627370496\",\"f64:18444492273895866368\"]],[\"invoke\",117,0,\"copysign\",[\"f64:4503599627370496\",\"f64:9221120237041090560\"]],[\"invoke\",118,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:9223372036854775808\"]],[\"invoke\",119,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:0\"]],[\"invoke\",120,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:9223372036854775808\"]],[\"invoke\",121,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:0\"]],[\"invoke\",122,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:9223372036854775809\"]],[\"invoke\",123,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:1\"]],[\"invoke\",124,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:9223372036854775809\"]],[\"invoke\",125,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:1\"]],[\"invoke\",126,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:9227875636482146304\"]],[\"invoke\",127,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:4503599627370496\"]],[\"invoke\",128,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:9227875636482146304\"]],[\"invoke\",129,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:4503599627370496\"]],[\"invoke\",130,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:13826050856027422720\"]],[\"invoke\",131,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:4602678819172646912\"]],[\"invoke\",132,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:13826050856027422720\"]],[\"invoke\",133,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:4602678819172646912\"]],[\"invoke\",134,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:13830554455654793216\"]],[\"invoke\",135,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:4607182418800017408\"]],[\"invoke\",136,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:13830554455654793216\"]],[\"invoke\",137,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:4607182418800017408\"]],[\"invoke\",138,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:13842132293034192152\"]],[\"invoke\",139,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:4618760256179416344\"]],[\"invoke\",140,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:13842132293034192152\"]],[\"invoke\",141,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:4618760256179416344\"]],[\"invoke\",142,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:18442240474082181119\"]],[\"invoke\",143,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:9218868437227405311\"]],[\"invoke\",144,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:18442240474082181119\"]],[\"invoke\",145,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:9218868437227405311\"]],[\"invoke\",146,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:18442240474082181120\"]],[\"invoke\",147,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:9218868437227405312\"]],[\"invoke\",148,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:18442240474082181120\"]],[\"invoke\",149,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:9218868437227405312\"]],[\"invoke\",150,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:18444492273895866368\"]],[\"invoke\",151,0,\"copysign\",[\"f64:13826050856027422720\",\"f64:9221120237041090560\"]],[\"invoke\",152,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:18444492273895866368\"]],[\"invoke\",153,0,\"copysign\",[\"f64:4602678819172646912\",\"f64:9221120237041090560\"]],[\"invoke\",154,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:9223372036854775808\"]],[\"invoke\",155,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:0\"]],[\"invoke\",156,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:9223372036854775808\"]],[\"invoke\",157,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:0\"]],[\"invoke\",158,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:9223372036854775809\"]],[\"invoke\",159,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:1\"]],[\"invoke\",160,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:9223372036854775809\"]],[\"invoke\",161,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:1\"]],[\"invoke\",162,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:9227875636482146304\"]],[\"invoke\",163,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:4503599627370496\"]],[\"invoke\",164,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:9227875636482146304\"]],[\"invoke\",165,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:4503599627370496\"]],[\"invoke\",166,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:13826050856027422720\"]],[\"invoke\",167,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:4602678819172646912\"]],[\"invoke\",168,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:13826050856027422720\"]],[\"invoke\",169,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:4602678819172646912\"]],[\"invoke\",170,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:13830554455654793216\"]],[\"invoke\",171,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:4607182418800017408\"]],[\"invoke\",172,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:13830554455654793216\"]],[\"invoke\",173,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:4607182418800017408\"]],[\"invoke\",174,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:13842132293034192152\"]],[\"invoke\",175,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:4618760256179416344\"]],[\"invoke\",176,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:13842132293034192152\"]],[\"invoke\",177,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:4618760256179416344\"]],[\"invoke\",178,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:18442240474082181119\"]],[\"invoke\",179,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:9218868437227405311\"]],[\"invoke\",180,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:18442240474082181119\"]],[\"invoke\",181,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:9218868437227405311\"]],[\"invoke\",182,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:18442240474082181120\"]],[\"invoke\",183,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:9218868437227405312\"]],[\"invoke\",184,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:18442240474082181120\"]],[\"invoke\",185,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:9218868437227405312\"]],[\"invoke\",186,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:18444492273895866368\"]],[\"invoke\",187,0,\"copysign\",[\"f64:13830554455654793216\",\"f64:9221120237041090560\"]],[\"invoke\",188,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:18444492273895866368\"]],[\"invoke\",189,0,\"copysign\",[\"f64:4607182418800017408\",\"f64:9221120237041090560\"]],[\"invoke\",190,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:9223372036854775808\"]],[\"invoke\",191,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:0\"]],[\"invoke\",192,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:9223372036854775808\"]],[\"invoke\",193,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:0\"]],[\"invoke\",194,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:9223372036854775809\"]],[\"invoke\",195,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:1\"]],[\"invoke\",196,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:9223372036854775809\"]],[\"invoke\",197,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:1\"]],[\"invoke\",198,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:9227875636482146304\"]],[\"invoke\",199,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:4503599627370496\"]],[\"invoke\",200,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:9227875636482146304\"]],[\"invoke\",201,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:4503599627370496\"]],[\"invoke\",202,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:13826050856027422720\"]],[\"invoke\",203,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:4602678819172646912\"]],[\"invoke\",204,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:13826050856027422720\"]],[\"invoke\",205,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:4602678819172646912\"]],[\"invoke\",206,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:13830554455654793216\"]],[\"invoke\",207,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:4607182418800017408\"]],[\"invoke\",208,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:13830554455654793216\"]],[\"invoke\",209,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:4607182418800017408\"]],[\"invoke\",210,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:13842132293034192152\"]],[\"invoke\",211,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:4618760256179416344\"]],[\"invoke\",212,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:13842132293034192152\"]],[\"invoke\",213,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:4618760256179416344\"]],[\"invoke\",214,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:18442240474082181119\"]],[\"invoke\",215,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:9218868437227405311\"]],[\"invoke\",216,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:18442240474082181119\"]],[\"invoke\",217,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:9218868437227405311\"]],[\"invoke\",218,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:18442240474082181120\"]],[\"invoke\",219,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:9218868437227405312\"]],[\"invoke\",220,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:18442240474082181120\"]],[\"invoke\",221,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:9218868437227405312\"]],[\"invoke\",222,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:18444492273895866368\"]],[\"invoke\",223,0,\"copysign\",[\"f64:13842132293034192152\",\"f64:9221120237041090560\"]],[\"invoke\",224,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:18444492273895866368\"]],[\"invoke\",225,0,\"copysign\",[\"f64:4618760256179416344\",\"f64:9221120237041090560\"]],[\"invoke\",226,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:9223372036854775808\"]],[\"invoke\",227,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:0\"]],[\"invoke\",228,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:9223372036854775808\"]],[\"invoke\",229,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:0\"]],[\"invoke\",230,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:9223372036854775809\"]],[\"invoke\",231,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:1\"]],[\"invoke\",232,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:9223372036854775809\"]],[\"invoke\",233,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:1\"]],[\"invoke\",234,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:9227875636482146304\"]],[\"invoke\",235,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:4503599627370496\"]],[\"invoke\",236,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:9227875636482146304\"]],[\"invoke\",237,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:4503599627370496\"]],[\"invoke\",238,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:13826050856027422720\"]],[\"invoke\",239,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:4602678819172646912\"]],[\"invoke\",240,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:13826050856027422720\"]],[\"invoke\",241,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:4602678819172646912\"]],[\"invoke\",242,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:13830554455654793216\"]],[\"invoke\",243,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:4607182418800017408\"]],[\"invoke\",244,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:13830554455654793216\"]],[\"invoke\",245,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:4607182418800017408\"]],[\"invoke\",246,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:13842132293034192152\"]],[\"invoke\",247,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:4618760256179416344\"]],[\"invoke\",248,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:13842132293034192152\"]],[\"invoke\",249,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:4618760256179416344\"]],[\"invoke\",250,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:18442240474082181119\"]],[\"invoke\",251,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:9218868437227405311\"]],[\"invoke\",252,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:18442240474082181119\"]],[\"invoke\",253,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:9218868437227405311\"]],[\"invoke\",254,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:18442240474082181120\"]],[\"invoke\",255,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:9218868437227405312\"]],[\"invoke\",256,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:18442240474082181120\"]],[\"invoke\",257,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:9218868437227405312\"]],[\"invoke\",258,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:18444492273895866368\"]],[\"invoke\",259,0,\"copysign\",[\"f64:18442240474082181119\",\"f64:9221120237041090560\"]],[\"invoke\",260,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:18444492273895866368\"]],[\"invoke\",261,0,\"copysign\",[\"f64:9218868437227405311\",\"f64:9221120237041090560\"]],[\"invoke\",262,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:9223372036854775808\"]],[\"invoke\",263,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:0\"]],[\"invoke\",264,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:9223372036854775808\"]],[\"invoke\",265,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:0\"]],[\"invoke\",266,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:9223372036854775809\"]],[\"invoke\",267,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:1\"]],[\"invoke\",268,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:9223372036854775809\"]],[\"invoke\",269,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:1\"]],[\"invoke\",270,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:9227875636482146304\"]],[\"invoke\",271,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:4503599627370496\"]],[\"invoke\",272,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:9227875636482146304\"]],[\"invoke\",273,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:4503599627370496\"]],[\"invoke\",274,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:13826050856027422720\"]],[\"invoke\",275,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:4602678819172646912\"]],[\"invoke\",276,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:13826050856027422720\"]],[\"invoke\",277,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:4602678819172646912\"]],[\"invoke\",278,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:13830554455654793216\"]],[\"invoke\",279,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:4607182418800017408\"]],[\"invoke\",280,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:13830554455654793216\"]],[\"invoke\",281,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:4607182418800017408\"]],[\"invoke\",282,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:13842132293034192152\"]],[\"invoke\",283,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:4618760256179416344\"]],[\"invoke\",284,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:13842132293034192152\"]],[\"invoke\",285,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:4618760256179416344\"]],[\"invoke\",286,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:18442240474082181119\"]],[\"invoke\",287,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:9218868437227405311\"]],[\"invoke\",288,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:18442240474082181119\"]],[\"invoke\",289,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:9218868437227405311\"]],[\"invoke\",290,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:18442240474082181120\"]],[\"invoke\",291,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:9218868437227405312\"]],[\"invoke\",292,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:18442240474082181120\"]],[\"invoke\",293,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:9218868437227405312\"]],[\"invoke\",294,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:18444492273895866368\"]],[\"invoke\",295,0,\"copysign\",[\"f64:18442240474082181120\",\"f64:9221120237041090560\"]],[\"invoke\",296,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:18444492273895866368\"]],[\"invoke\",297,0,\"copysign\",[\"f64:9218868437227405312\",\"f64:9221120237041090560\"]],[\"invoke\",298,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:9223372036854775808\"]],[\"invoke\",299,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:0\"]],[\"invoke\",300,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:9223372036854775808\"]],[\"invoke\",301,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:0\"]],[\"invoke\",302,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:9223372036854775809\"]],[\"invoke\",303,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:1\"]],[\"invoke\",304,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:9223372036854775809\"]],[\"invoke\",305,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:1\"]],[\"invoke\",306,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:9227875636482146304\"]],[\"invoke\",307,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:4503599627370496\"]],[\"invoke\",308,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:9227875636482146304\"]],[\"invoke\",309,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:4503599627370496\"]],[\"invoke\",310,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:13826050856027422720\"]],[\"invoke\",311,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:4602678819172646912\"]],[\"invoke\",312,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:13826050856027422720\"]],[\"invoke\",313,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:4602678819172646912\"]],[\"invoke\",314,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:13830554455654793216\"]],[\"invoke\",315,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:4607182418800017408\"]],[\"invoke\",316,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:13830554455654793216\"]],[\"invoke\",317,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:4607182418800017408\"]],[\"invoke\",318,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:13842132293034192152\"]],[\"invoke\",319,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:4618760256179416344\"]],[\"invoke\",320,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:13842132293034192152\"]],[\"invoke\",321,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:4618760256179416344\"]],[\"invoke\",322,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:18442240474082181119\"]],[\"invoke\",323,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:9218868437227405311\"]],[\"invoke\",324,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:18442240474082181119\"]],[\"invoke\",325,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:9218868437227405311\"]],[\"invoke\",326,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:18442240474082181120\"]],[\"invoke\",327,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:9218868437227405312\"]],[\"invoke\",328,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:18442240474082181120\"]],[\"invoke\",329,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:9218868437227405312\"]],[\"invoke\",330,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:18444492273895866368\"]],[\"invoke\",331,0,\"copysign\",[\"f64:18444492273895866368\",\"f64:9221120237041090560\"]],[\"invoke\",332,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:18444492273895866368\"]],[\"invoke\",333,0,\"copysign\",[\"f64:9221120237041090560\",\"f64:9221120237041090560\"]],[\"invoke\",334,0,\"abs\",[\"f64:9223372036854775808\"]],[\"invoke\",335,0,\"abs\",[\"f64:0\"]],[\"invoke\",336,0,\"abs\",[\"f64:9223372036854775809\"]],[\"invoke\",337,0,\"abs\",[\"f64:1\"]],[\"invoke\",338,0,\"abs\",[\"f64:9227875636482146304\"]],[\"invoke\",339,0,\"abs\",[\"f64:4503599627370496\"]],[\"invoke\",340,0,\"abs\",[\"f64:13826050856027422720\"]],[\"invoke\",341,0,\"abs\",[\"f64:4602678819172646912\"]],[\"invoke\",342,0,\"abs\",[\"f64:13830554455654793216\"]],[\"invoke\",343,0,\"abs\",[\"f64:4607182418800017408\"]],[\"invoke\",344,0,\"abs\",[\"f64:13842132293034192152\"]],[\"invoke\",345,0,\"abs\",[\"f64:4618760256179416344\"]],[\"invoke\",346,0,\"abs\",[\"f64:18442240474082181119\"]],[\"invoke\",347,0,\"abs\",[\"f64:9218868437227405311\"]],[\"invoke\",348,0,\"abs\",[\"f64:18442240474082181120\"]],[\"invoke\",349,0,\"abs\",[\"f64:9218868437227405312\"]],[\"invoke\",350,0,\"abs\",[\"f64:18444492273895866368\"]],[\"invoke\",351,0,\"abs\",[\"f64:9221120237041090560\"]],[\"invoke\",352,0,\"neg\",[\"f64:9223372036854775808\"]],[\"invoke\",353,0,\"neg\",[\"f64:0\"]],[\"invoke\",354,0,\"neg\",[\"f64:9223372036854775809\"]],[\"invoke\",355,0,\"neg\",[\"f64:1\"]],[\"invoke\",356,0,\"neg\",[\"f64:9227875636482146304\"]],[\"invoke\",357,0,\"neg\",[\"f64:4503599627370496\"]],[\"invoke\",358,0,\"neg\",[\"f64:13826050856027422720\"]],[\"invoke\",359,0,\"neg\",[\"f64:4602678819172646912\"]],[\"invoke\",360,0,\"neg\",[\"f64:13830554455654793216\"]],[\"invoke\",361,0,\"neg\",[\"f64:4607182418800017408\"]],[\"invoke\",362,0,\"neg\",[\"f64:13842132293034192152\"]],[\"invoke\",363,0,\"neg\",[\"f64:4618760256179416344\"]],[\"invoke\",364,0,\"neg\",[\"f64:18442240474082181119\"]],[\"invoke\",365,0,\"neg\",[\"f64:9218868437227405311\"]],[\"invoke\",366,0,\"neg\",[\"f64:18442240474082181120\"]],[\"invoke\",367,0,\"neg\",[\"f64:9218868437227405312\"]],[\"invoke\",368,0,\"neg\",[\"f64:18444492273895866368\"]],[\"invoke\",369,0,\"neg\",[\"f64:9221120237041090560\"]],[\"file\",\"float_exprs.wast\"],[\"module\",6,6],[\"invoke\",11,0,\"f64.no_contraction\",[\"f64:13369472591878845359\",\"f64:7598224971858294334\",\"f64:7009968021366006149\"]],[\"invoke\",13,0,\"f64.no_contraction\",[\"f64:11159707324127586240\",\"f64:7011538096610110295\",\"f64:4140382893275160737\"]],[\"invoke\",15,0,\"f64.no_contraction\",[\"f64:9554523352352050493\",\"f64:18042841594766434431\",\"f64:4368037109959396445\"]],[\"module\",19,7],[\"invoke\",27,0,\"f32.no_fma\",[\"f32:838240978\",\"f32:2796592697\",\"f32:329493464\"]],[\"invoke\",29,0,\"f32.no_fma\",[\"f32:999635965\",\"f32:3403528619\",\"f32:3222888213\"]],[\"invoke\",31,0,\"f64.no_fma\",[\"f64:7118716943724900052\",\"f64:6546073043412611735\",\"f64:18275705786238687882\"]],[\"invoke\",33,0,\"f64.no_fma\",[\"f64:1362668175782178275\",\"f64:18385570095786966502\",\"f64:5677031731722859914\"]],[\"invoke\",35,0,\"f64.no_fma\",[\"f64:4843589256781277081\",\"f64:7695653093478086834\",\"f64:16938438850771988744\"]],[\"module\",40,8],[\"invoke\",48,0,\"f64.no_fold_add_zero\",[\"f64:9223372036854775808\"]],[\"module\",54,9],[\"invoke\",62,0,\"f64.no_fold_zero_sub\",[\"f64:0\"]],[\"module\",68,10],[\"module\",80,11],[\"invoke\",88,0,\"f32.no_fold_mul_zero\",[\"f32:3212836864\"]],[\"invoke\",91,0,\"f64.no_fold_mul_zero\",[\"f64:9223372036854775808\"]],[\"invoke\",93,0,\"f64.no_fold_mul_zero\",[\"f64:13835058055282163712\"]],[\"module\",99,12],[\"module\",111,13],[\"invoke\",118,0,\"f32.no_fold_zero_div\",[\"f32:0\"]],[\"invoke\",120,0,\"f32.no_fold_zero_div\",[\"f32:2143289344\"]],[\"invoke\",123,0,\"f64.no_fold_zero_div\",[\"f64:9223372036854775808\"]],[\"module\",129,14],[\"module\",141,15],[\"module\",153,16],[\"module\",165,17],[\"module\",177,18],[\"invoke\",184,0,\"f32.no_fold_eq_self\",[\"f32:2143289344\"]],[\"module\",189,19],[\"invoke\",196,0,\"f32.no_fold_ne_self\",[\"f32:2143289344\"]],[\"module\",201,20],[\"invoke\",208,0,\"f32.no_fold_sub_self\",[\"f32:2139095040\"]],[\"invoke\",210,0,\"f64.no_fold_sub_self\",[\"f64:9218868437227405312\"]],[\"module\",215,21],[\"invoke\",222,0,\"f32.no_fold_div_self\",[\"f32:2139095040\"]],[\"invoke\",224,0,\"f32.no_fold_div_self\",[\"f32:0\"]],[\"invoke\",226,0,\"f64.no_fold_div_self\",[\"f64:9218868437227405312\"]],[\"invoke\",228,0,\"f64.no_fold_div_self\",[\"f64:0\"]],[\"module\",233,22],[\"invoke\",240,0,\"f32.no_fold_div_3\",[\"f32:3634023955\"]],[\"invoke\",242,0,\"f32.no_fold_div_3\",[\"f32:2517965963\"]],[\"invoke\",243,0,\"f32.no_fold_div_3\",[\"f32:2173683100\"]],[\"invoke\",245,0,\"f64.no_fold_div_3\",[\"f64:16679796490173820099\"]],[\"invoke\",247,0,\"f64.no_fold_div_3\",[\"f64:674365394458900388\"]],[\"invoke\",249,0,\"f64.no_fold_div_3\",[\"f64:6476267216527259981\"]],[\"module\",253,23],[\"invoke\",261,0,\"f32.no_factor\",[\"f32:3168433147\",\"f32:1028017286\",\"f32:3141035521\"]],[\"invoke\",263,0,\"f32.no_factor\",[\"f32:2684117842\",\"f32:369386499\",\"f32:2061166438\"]],[\"invoke\",265,0,\"f64.no_factor\",[\"f64:2698691837980592503\",\"f64:2529920934327896545\",\"f64:12819783413251458936\"]],[\"invoke\",267,0,\"f64.no_factor\",[\"f64:12326480769054961745\",\"f64:12563546453737163926\",\"f64:15990519985875741037\"]],[\"invoke\",269,0,\"f64.no_factor\",[\"f64:1871759566187673434\",\"f64:2002968319587025494\",\"f64:16033202089880281080\"]],[\"module\",273,24],[\"invoke\",281,0,\"f32.no_distribute\",[\"f32:3168433147\",\"f32:1028017286\",\"f32:3141035521\"]],[\"invoke\",283,0,\"f32.no_distribute\",[\"f32:2684117842\",\"f32:369386499\",\"f32:2061166438\"]],[\"invoke\",285,0,\"f64.no_distribute\",[\"f64:2698691837980592503\",\"f64:2529920934327896545\",\"f64:12819783413251458936\"]],[\"invoke\",287,0,\"f64.no_distribute\",[\"f64:12326480769054961745\",\"f64:12563546453737163926\",\"f64:15990519985875741037\"]],[\"invoke\",288,0,\"f64.no_distribute\",[\"f64:12532477544855171977\",\"f64:3439526350000314825\",\"f64:12694541248380731909\"]],[\"module\",293,25],[\"invoke\",300,0,\"f32.no_regroup_div_mul\",[\"f32:2249624147\",\"f32:2678828342\",\"f32:95319815\"]],[\"invoke\",302,0,\"f32.no_regroup_div_mul\",[\"f32:3350590135\",\"f32:3042588643\",\"f32:2186448635\"]],[\"invoke\",304,0,\"f32.no_regroup_div_mul\",[\"f32:2011387707\",\"f32:1274956446\",\"f32:3811596788\"]],[\"invoke\",306,0,\"f64.no_regroup_div_mul\",[\"f64:6126139291059848917\",\"f64:2596039250849921421\",\"f64:17423258659719899654\"]],[\"invoke\",308,0,\"f64.no_regroup_div_mul\",[\"f64:15994259208199847538\",\"f64:16584156163346075677\",\"f64:17596923907238870430\"]],[\"module\",313,26],[\"invoke\",320,0,\"f32.no_regroup_mul_div\",[\"f32:2249624147\",\"f32:2678828342\",\"f32:95319815\"]],[\"invoke\",322,0,\"f32.no_regroup_mul_div\",[\"f32:3350590135\",\"f32:3042588643\",\"f32:2186448635\"]],[\"invoke\",324,0,\"f32.no_regroup_mul_div\",[\"f32:2011387707\",\"f32:1274956446\",\"f32:3811596788\"]],[\"invoke\",326,0,\"f64.no_regroup_mul_div\",[\"f64:6126139291059848917\",\"f64:2596039250849921421\",\"f64:17423258659719899654\"]],[\"invoke\",328,0,\"f64.no_regroup_mul_div\",[\"f64:15994259208199847538\",\"f64:16584156163346075677\",\"f64:17596923907238870430\"]],[\"module\",333,27],[\"invoke\",340,0,\"f32.no_reassociate_add\",[\"f32:3585064686\",\"f32:1354934024\",\"f32:3612934982\",\"f32:3557837641\"]],[\"invoke\",342,0,\"f32.no_reassociate_add\",[\"f32:3506363549\",\"f32:3562765939\",\"f32:1440782572\",\"f32:1388583643\"]],[\"invoke\",343,0,\"f32.no_reassociate_add\",[\"f32:1460378878\",\"f32:1481791683\",\"f32:3506843934\",\"f32:1493913729\"]],[\"invoke\",345,0,\"f64.no_reassociate_add\",[\"f64:17619937326421449126\",\"f64:8424880666975634327\",\"f64:8461713040394112626\",\"f64:17692076622886930107\"]],[\"invoke\",347,0,\"f64.no_reassociate_add\",[\"f64:15816220208145029204\",\"f64:6443786499090728432\",\"f64:15798639273395365185\",\"f64:6395820899158300605\"]],[\"invoke\",349,0,\"f64.no_reassociate_add\",[\"f64:16720963389015391005\",\"f64:16597092572968550980\",\"f64:7518944085377596897\",\"f64:16733407756820198530\"]],[\"module\",353,28],[\"invoke\",361,0,\"f32.no_reassociate_mul\",[\"f32:598526039\",\"f32:4072603010\",\"f32:2166864805\",\"f32:3802968051\"]],[\"invoke\",363,0,\"f32.no_reassociate_mul\",[\"f32:191948150\",\"f32:1717012201\",\"f32:3682645872\",\"f32:3713382507\"]],[\"invoke\",365,0,\"f64.no_reassociate_mul\",[\"f64:10830726381612138752\",\"f64:18293529276079591087\",\"f64:12137662286027993114\",\"f64:16821646709291069775\"]],[\"invoke\",367,0,\"f64.no_reassociate_mul\",[\"f64:2352911459797566465\",\"f64:17379873157362463143\",\"f64:1179129869275935356\",\"f64:14228398113747850351\"]],[\"invoke\",369,0,\"f64.no_reassociate_mul\",[\"f64:3553622953022765407\",\"f64:1044040287824900408\",\"f64:17112762794520509437\",\"f64:11134095486440145773\"]],[\"module\",373,29],[\"invoke\",381,0,\"f32.no_fold_div_0\",[\"f32:3212836864\"]],[\"invoke\",383,0,\"f32.no_fold_div_0\",[\"f32:4286578688\"]],[\"invoke\",385,0,\"f32.no_fold_div_0\",[\"f32:2147483648\"]],[\"invoke\",388,0,\"f64.no_fold_div_0\",[\"f64:4607182418800017408\"]],[\"invoke\",389,0,\"f64.no_fold_div_0\",[\"f64:13830554455654793216\"]],[\"invoke\",391,0,\"f64.no_fold_div_0\",[\"f64:18442240474082181120\"]],[\"invoke\",393,0,\"f64.no_fold_div_0\",[\"f64:9223372036854775808\"]],[\"module\",399,30],[\"invoke\",406,0,\"f32.no_fold_div_neg0\",[\"f32:1065353216\"]],[\"invoke\",408,0,\"f32.no_fold_div_neg0\",[\"f32:2139095040\"]],[\"invoke\",410,0,\"f32.no_fold_div_neg0\",[\"f32:0\"]],[\"invoke\",413,0,\"f32.no_fold_div_neg0\",[\"f32:2143289344\"]],[\"invoke\",415,0,\"f64.no_fold_div_neg0\",[\"f64:13830554455654793216\"]],[\"invoke\",417,0,\"f64.no_fold_div_neg0\",[\"f64:18442240474082181120\"]],[\"invoke\",419,0,\"f64.no_fold_div_neg0\",[\"f64:9223372036854775808\"]],[\"module\",425,31],[\"invoke\",434,0,\"f32.no_fold_to_hypot\",[\"f32:392264092\",\"f32:497028527\"]],[\"invoke\",436,0,\"f32.no_fold_to_hypot\",[\"f32:2261577829\",\"f32:2641790518\"]],[\"invoke\",438,0,\"f32.no_fold_to_hypot\",[\"f32:432505039\",\"f32:2618036612\"]],[\"invoke\",439,0,\"f64.no_fold_to_hypot\",[\"f64:1743351192697472785\",\"f64:2202602366606243153\"]],[\"invoke\",441,0,\"f64.no_fold_to_hypot\",[\"f64:2195337108264055819\",\"f64:10384237061545402288\"]],[\"invoke\",443,0,\"f64.no_fold_to_hypot\",[\"f64:1591440107418864392\",\"f64:11515806374387309036\"]],[\"module\",447,32],[\"invoke\",453,0,\"f32.no_approximate_reciprocal\",[\"f32:2138280080\"]],[\"invoke\",455,0,\"f32.no_approximate_reciprocal\",[\"f32:1705936409\"]],[\"module\",460,33],[\"invoke\",467,0,\"f32.no_approximate_reciprocal_sqrt\",[\"f32:708147349\"]],[\"invoke\",469,0,\"f32.no_approximate_reciprocal_sqrt\",[\"f32:517799246\"]],[\"invoke\",471,0,\"f32.no_approximate_reciprocal_sqrt\",[\"f32:347001813\"]],[\"invoke\",474,0,\"f64.no_fuse_reciprocal_sqrt\",[\"f64:6008428610859539631\"]],[\"invoke\",476,0,\"f64.no_fuse_reciprocal_sqrt\",[\"f64:7616219057857077123\"]],[\"module\",481,34],[\"invoke\",486,0,\"f32.no_approximate_sqrt_reciprocal\",[\"f32:1574069443\"]],[\"invoke\",488,0,\"f32.no_approximate_sqrt_reciprocal\",[\"f32:1644769121\"]],[\"invoke\",490,0,\"f32.no_approximate_sqrt_reciprocal\",[\"f32:1940205041\"]],[\"module\",494,35],[\"invoke\",505,0,\"i32.no_fold_f32_s\",[\"i32:16777216\"]],[\"invoke\",507,0,\"i32.no_fold_f32_s\",[\"i32:4026531856\"]],[\"invoke\",510,0,\"i32.no_fold_f32_u\",[\"i32:16777217\"]],[\"invoke\",513,0,\"i64.no_fold_f64_s\",[\"i64:9007199254740992\"]],[\"invoke\",515,0,\"i64.no_fold_f64_s\",[\"i64:17293822569102705664\"]],[\"invoke\",518,0,\"i64.no_fold_f64_u\",[\"i64:9007199254740993\"]],[\"module\",523,36],[\"invoke\",530,0,\"f32.no_fold_add_sub\",[\"f32:677030386\",\"f32:2998136214\"]],[\"invoke\",532,0,\"f32.no_fold_add_sub\",[\"f32:3908960888\",\"f32:4063404061\"]],[\"invoke\",534,0,\"f32.no_fold_add_sub\",[\"f32:2307650739\",\"f32:2511328013\"]],[\"invoke\",537,0,\"f64.no_fold_add_sub\",[\"f64:2152218683357821298\",\"f64:2238360073507307376\"]],[\"invoke\",539,0,\"f64.no_fold_add_sub\",[\"f64:12298280617237492384\",\"f64:3233965342858558382\"]],[\"module\",544,37],[\"invoke\",551,0,\"f32.no_fold_sub_add\",[\"f32:3291029084\",\"f32:1137280182\"]],[\"invoke\",553,0,\"f32.no_fold_sub_add\",[\"f32:1285466516\",\"f32:1361849144\"]],[\"invoke\",554,0,\"f32.no_fold_sub_add\",[\"f32:740009747\",\"f32:2989707904\"]],[\"invoke\",557,0,\"f64.no_fold_sub_add\",[\"f64:5758126085282503565\",\"f64:14997141603873875659\"]],[\"invoke\",559,0,\"f64.no_fold_sub_add\",[\"f64:5738179408840599949\",\"f64:15186085143903012996\"]],[\"invoke\",561,0,\"f64.no_fold_sub_add\",[\"f64:2955729038738127538\",\"f64:12208627806665035010\"]],[\"module\",565,38],[\"invoke\",573,0,\"f32.no_fold_mul_div\",[\"f32:2995104604\",\"f32:178524966\"]],[\"invoke\",575,0,\"f32.no_fold_mul_div\",[\"f32:1507152519\",\"f32:3723483599\"]],[\"invoke\",578,0,\"f64.no_fold_mul_div\",[\"f64:10062123074470382106\",\"f64:12910565991996555404\"]],[\"invoke\",580,0,\"f64.no_fold_mul_div\",[\"f64:14905228263410157971\",\"f64:11346251643264732732\"]],[\"invoke\",582,0,\"f64.no_fold_mul_div\",[\"f64:16807035693954817236\",\"f64:12360222454864961326\"]],[\"module\",586,39],[\"invoke\",594,0,\"f32.no_fold_div_mul\",[\"f32:2777664539\",\"f32:3062588018\"]],[\"invoke\",596,0,\"f32.no_fold_div_mul\",[\"f32:2593594703\",\"f32:3709508810\"]],[\"invoke\",599,0,\"f64.no_fold_div_mul\",[\"f64:665690489208775809\",\"f64:14660005164454413124\"]],[\"invoke\",601,0,\"f64.no_fold_div_mul\",[\"f64:13179336828827425934\",\"f64:6536345148565138764\"]],[\"invoke\",602,0,\"f64.no_fold_div_mul\",[\"f64:12582623625647949669\",\"f64:15106746174896642041\"]],[\"module\",607,40],[\"invoke\",614,0,\"f32.no_fold_div2_mul2\",[\"f32:16777215\"]],[\"module\",619,41],[\"invoke\",624,0,\"no_fold_demote_promote\",[\"f64:13235495337234861917\"]],[\"invoke\",626,0,\"no_fold_demote_promote\",[\"f64:5090364081358261697\"]],[\"invoke\",628,0,\"no_fold_demote_promote\",[\"f64:5076240020598306430\"]],[\"module\",633,42],[\"invoke\",640,0,\"no_fold_promote_demote\",[\"f32:2147483648\"]],[\"invoke\",642,0,\"no_fold_promote_demote\",[\"f32:2147483649\"]],[\"invoke\",644,0,\"no_fold_promote_demote\",[\"f32:2155872255\"]],[\"invoke\",646,0,\"no_fold_promote_demote\",[\"f32:2155872256\"]],[\"invoke\",648,0,\"no_fold_promote_demote\",[\"f32:4286578687\"]],[\"invoke\",650,0,\"no_fold_promote_demote\",[\"f32:4286578688\"]],[\"module\",655,43],[\"invoke\",663,0,\"no_demote_mixed_add\",[\"f64:4773927428111915216\",\"f32:1387972204\"]],[\"invoke\",665,0,\"no_demote_mixed_add\",[\"f64:13740716732336801211\",\"f32:822392741\"]],[\"invoke\",666,0,\"no_demote_mixed_add\",[\"f64:13742514716462174325\",\"f32:2870112826\"]],[\"invoke\",669,0,\"no_demote_mixed_add_commuted\",[\"f32:1387972204\",\"f64:4773927428111915216\"]],[\"invoke\",671,0,\"no_demote_mixed_add_commuted\",[\"f32:822392741\",\"f64:13740716732336801211\"]],[\"module\",677,44],[\"invoke\",684,0,\"no_demote_mixed_sub\",[\"f64:4979303437048015281\",\"f32:1583535740\"]],[\"invoke\",686,0,\"no_demote_mixed_sub\",[\"f64:13860263758943608426\",\"f32:969848030\"]],[\"invoke\",688,0,\"no_demote_mixed_sub\",[\"f64:4673175763235896759\",\"f32:1198952676\"]],[\"invoke\",691,0,\"no_demote_mixed_sub_commuted\",[\"f32:1214924370\",\"f64:13967600632962086462\"]],[\"invoke\",693,0,\"no_demote_mixed_sub_commuted\",[\"f32:472962692\",\"f64:4364064588997139903\"]],[\"module\",699,45],[\"invoke\",706,0,\"no_demote_mixed_mul\",[\"f64:3700298049681794165\",\"f32:2017642079\"]],[\"invoke\",708,0,\"no_demote_mixed_mul\",[\"f64:5404042108537284972\",\"f32:592745128\"]],[\"invoke\",710,0,\"no_demote_mixed_mul\",[\"f64:3845043516226476604\",\"f32:1468885281\"]],[\"invoke\",713,0,\"no_demote_mixed_mul_commuted\",[\"f32:169311251\",\"f64:5240203039857786645\"]],[\"invoke\",714,0,\"no_demote_mixed_mul_commuted\",[\"f32:592745128\",\"f64:5404042108537284972\"]],[\"invoke\",716,0,\"no_demote_mixed_mul_commuted\",[\"f32:1468885281\",\"f64:3845043516226476604\"]],[\"module\",721,46],[\"invoke\",729,0,\"no_demote_mixed_div\",[\"f64:3919260277508722072\",\"f32:379509872\"]],[\"invoke\",731,0,\"no_demote_mixed_div\",[\"f64:3987118416164120709\",\"f32:327692725\"]],[\"invoke\",734,0,\"no_demote_mixed_div_commuted\",[\"f32:451659502\",\"f64:4418811329667688930\"]],[\"invoke\",736,0,\"no_demote_mixed_div_commuted\",[\"f32:737399826\",\"f64:3994494799108309244\"]],[\"invoke\",738,0,\"no_demote_mixed_div_commuted\",[\"f32:456887038\",\"f64:3717438582804640027\"]],[\"module\",742,47],[\"invoke\",778,0,\"f32.i32.no_fold_trunc_s_convert_s\",[\"f32:3217031168\"]],[\"invoke\",780,0,\"f32.i32.no_fold_trunc_u_convert_s\",[\"f32:3204448256\"]],[\"invoke\",782,0,\"f32.i32.no_fold_trunc_s_convert_u\",[\"f32:3217031168\"]],[\"invoke\",784,0,\"f32.i32.no_fold_trunc_u_convert_u\",[\"f32:3204448256\"]],[\"invoke\",787,0,\"f64.i32.no_fold_trunc_s_convert_s\",[\"f64:13832806255468478464\"]],[\"invoke\",789,0,\"f64.i32.no_fold_trunc_u_convert_s\",[\"f64:13826050856027422720\"]],[\"invoke\",790,0,\"f64.i32.no_fold_trunc_s_convert_u\",[\"f64:4609434218613702656\"]],[\"invoke\",792,0,\"f64.i32.no_fold_trunc_u_convert_u\",[\"f64:4609434218613702656\"]],[\"invoke\",795,0,\"f32.i64.no_fold_trunc_s_convert_s\",[\"f32:1069547520\"]],[\"invoke\",797,0,\"f32.i64.no_fold_trunc_u_convert_s\",[\"f32:1069547520\"]],[\"invoke\",799,0,\"f32.i64.no_fold_trunc_s_convert_u\",[\"f32:1069547520\"]],[\"invoke\",801,0,\"f32.i64.no_fold_trunc_u_convert_u\",[\"f32:1069547520\"]],[\"invoke\",804,0,\"f64.i64.no_fold_trunc_s_convert_s\",[\"f64:4609434218613702656\"]],[\"invoke\",806,0,\"f64.i64.no_fold_trunc_u_convert_s\",[\"f64:4609434218613702656\"]],[\"invoke\",808,0,\"f64.i64.no_fold_trunc_s_convert_u\",[\"f64:4609434218613702656\"]],[\"invoke\",810,0,\"f64.i64.no_fold_trunc_u_convert_u\",[\"f64:4609434218613702656\"]],[\"module\",817,48],[\"invoke\",838,0,\"init\",[\"i32:0\",\"f32:1097963930\"]],[\"invoke\",840,0,\"init\",[\"i32:8\",\"f32:1098173645\"]],[\"invoke\",842,0,\"check\",[\"i32:0\"]],[\"invoke\",843,0,\"check\",[\"i32:4\"]],[\"invoke\",845,0,\"check\",[\"i32:12\"]],[\"invoke\",847,0,\"check\",[\"i32:0\"]],[\"invoke\",849,0,\"check\",[\"i32:8\"]],[\"module\",852,49],[\"invoke\",873,0,\"init\",[\"i32:0\",\"f64:4624690162351420211\"]],[\"invoke\",875,0,\"init\",[\"i32:16\",\"f64:4624802752342104474\"]],[\"invoke\",877,0,\"check\",[\"i32:0\"]],[\"invoke\",879,0,\"check\",[\"i32:16\"]],[\"invoke\",881,0,\"run\",[\"i32:32\",\"f64:4613937818241073152\"]],[\"invoke\",883,0,\"check\",[\"i32:8\"]],[\"invoke\",885,0,\"check\",[\"i32:24\"]],[\"module\",889,50],[\"invoke\",902,0,\"f32.ult\",[\"f32:1073741824\",\"f32:1073741824\"]],[\"invoke\",904,0,\"f32.ult\",[\"f32:1073741824\",\"f32:2143289344\"]],[\"invoke\",905,0,\"f32.ule\",[\"f32:1077936128\",\"f32:1073741824\"]],[\"invoke\",907,0,\"f32.ule\",[\"f32:1073741824\",\"f32:1077936128\"]],[\"invoke\",909,0,\"f32.ugt\",[\"f32:1077936128\",\"f32:1073741824\"]],[\"invoke\",911,0,\"f32.ugt\",[\"f32:1073741824\",\"f32:1077936128\"]],[\"invoke\",913,0,\"f32.uge\",[\"f32:1077936128\",\"f32:1073741824\"]],[\"invoke\",915,0,\"f32.uge\",[\"f32:1073741824\",\"f32:1077936128\"]],[\"invoke\",917,0,\"f64.ult\",[\"f64:4613937818241073152\",\"f64:4611686018427387904\"]],[\"invoke\",919,0,\"f64.ult\",[\"f64:4611686018427387904\",\"f64:4613937818241073152\"]],[\"invoke\",921,0,\"f64.ule\",[\"f64:4613937818241073152\",\"f64:4611686018427387904\"]],[\"invoke\",923,0,\"f64.ule\",[\"f64:4611686018427387904\",\"f64:4613937818241073152\"]],[\"invoke\",925,0,\"f64.ugt\",[\"f64:4613937818241073152\",\"f64:4611686018427387904\"]],[\"invoke\",927,0,\"f64.ugt\",[\"f64:4611686018427387904\",\"f64:4613937818241073152\"]],[\"invoke\",929,0,\"f64.uge\",[\"f64:4613937818241073152\",\"f64:4611686018427387904\"]],[\"invoke\",930,0,\"f64.uge\",[\"f64:4611686018427387904\",\"f64:4611686018427387904\"]],[\"invoke\",932,0,\"f64.uge\",[\"f64:4611686018427387904\",\"f64:9221120237041090560\"]],[\"module\",936,51],[\"invoke\",949,0,\"f32.no_fold_lt_select\",[\"f32:2143289344\",\"f32:0\"]],[\"invoke\",951,0,\"f32.no_fold_lt_select\",[\"f32:2147483648\",\"f32:0\"]],[\"invoke\",953,0,\"f32.no_fold_le_select\",[\"f32:2143289344\",\"f32:0\"]],[\"invoke\",955,0,\"f32.no_fold_le_select\",[\"f32:2147483648\",\"f32:0\"]],[\"invoke\",957,0,\"f32.no_fold_gt_select\",[\"f32:2143289344\",\"f32:0\"]],[\"invoke\",959,0,\"f32.no_fold_gt_select\",[\"f32:2147483648\",\"f32:0\"]],[\"invoke\",961,0,\"f32.no_fold_ge_select\",[\"f32:2143289344\",\"f32:0\"]],[\"invoke\",963,0,\"f32.no_fold_ge_select\",[\"f32:2147483648\",\"f32:0\"]],[\"invoke\",965,0,\"f64.no_fold_lt_select\",[\"f64:9221120237041090560\",\"f64:0\"]],[\"invoke\",967,0,\"f64.no_fold_lt_select\",[\"f64:9223372036854775808\",\"f64:0\"]],[\"invoke\",969,0,\"f64.no_fold_le_select\",[\"f64:9221120237041090560\",\"f64:0\"]],[\"invoke\",970,0,\"f64.no_fold_le_select\",[\"f64:0\",\"f64:9223372036854775808\"]],[\"invoke\",972,0,\"f64.no_fold_gt_select\",[\"f64:0\",\"f64:9221120237041090560\"]],[\"invoke\",974,0,\"f64.no_fold_gt_select\",[\"f64:0\",\"f64:9223372036854775808\"]],[\"invoke\",976,0,\"f64.no_fold_ge_select\",[\"f64:0\",\"f64:9221120237041090560\"]],[\"invoke\",978,0,\"f64.no_fold_ge_select\",[\"f64:0\",\"f64:9223372036854775808\"]],[\"module\",983,52],[\"invoke\",1027,0,\"f32.no_fold_lt_if\",[\"f32:0\",\"f32:2143289344\"]],[\"invoke\",1029,0,\"f32.no_fold_lt_if\",[\"f32:0\",\"f32:2147483648\"]],[\"invoke\",1031,0,\"f32.no_fold_le_if\",[\"f32:0\",\"f32:2143289344\"]],[\"invoke\",1033,0,\"f32.no_fold_le_if\",[\"f32:0\",\"f32:2147483648\"]],[\"invoke\",1035,0,\"f32.no_fold_gt_if\",[\"f32:0\",\"f32:2143289344\"]],[\"invoke\",1037,0,\"f32.no_fold_gt_if\",[\"f32:0\",\"f32:2147483648\"]],[\"invoke\",1039,0,\"f32.no_fold_ge_if\",[\"f32:0\",\"f32:2143289344\"]],[\"invoke\",1041,0,\"f32.no_fold_ge_if\",[\"f32:0\",\"f32:2147483648\"]],[\"invoke\",1042,0,\"f32.no_fold_ge_if\",[\"f32:2147483648\",\"f32:0\"]],[\"invoke\",1044,0,\"f64.no_fold_lt_if\",[\"f64:9221120237041090560\",\"f64:0\"]],[\"invoke\",1046,0,\"f64.no_fold_lt_if\",[\"f64:9223372036854775808\",\"f64:0\"]],[\"invoke\",1048,0,\"f64.no_fold_le_if\",[\"f64:9221120237041090560\",\"f64:0\"]],[\"invoke\",1050,0,\"f64.no_fold_le_if\",[\"f64:9223372036854775808\",\"f64:0\"]],[\"invoke\",1052,0,\"f64.no_fold_gt_if\",[\"f64:9221120237041090560\",\"f64:0\"]],[\"invoke\",1054,0,\"f64.no_fold_gt_if\",[\"f64:9223372036854775808\",\"f64:0\"]],[\"invoke\",1056,0,\"f64.no_fold_ge_if\",[\"f64:9221120237041090560\",\"f64:0\"]],[\"invoke\",1058,0,\"f64.no_fold_ge_if\",[\"f64:9223372036854775808\",\"f64:0\"]],[\"module\",1062,53],[\"invoke\",1076,0,\"f32.no_fold_lt_select_to_abs\",[\"f32:0\"]],[\"invoke\",1079,0,\"f32.no_fold_le_select_to_abs\",[\"f32:4290772992\"]],[\"invoke\",1081,0,\"f32.no_fold_le_select_to_abs\",[\"f32:2147483648\"]],[\"invoke\",1084,0,\"f32.no_fold_gt_select_to_abs\",[\"f32:0\"]],[\"invoke\",1085,0,\"f32.no_fold_gt_select_to_abs\",[\"f32:2147483648\"]],[\"invoke\",1088,0,\"f32.no_fold_ge_select_to_abs\",[\"f32:0\"]],[\"invoke\",1091,0,\"f64.no_fold_lt_select_to_abs\",[\"f64:18444492273895866368\"]],[\"invoke\",1093,0,\"f64.no_fold_lt_select_to_abs\",[\"f64:9223372036854775808\"]],[\"invoke\",1096,0,\"f64.no_fold_le_select_to_abs\",[\"f64:0\"]],[\"invoke\",1099,0,\"f64.no_fold_gt_select_to_abs\",[\"f64:18444492273895866368\"]],[\"invoke\",1101,0,\"f64.no_fold_gt_select_to_abs\",[\"f64:9223372036854775808\"]],[\"invoke\",1104,0,\"f64.no_fold_ge_select_to_abs\",[\"f64:0\"]],[\"module\",1109,54],[\"invoke\",1154,0,\"f32.no_fold_lt_if_to_abs\",[\"f32:4290772992\"]],[\"invoke\",1156,0,\"f32.no_fold_lt_if_to_abs\",[\"f32:2147483648\"]],[\"invoke\",1159,0,\"f32.no_fold_le_if_to_abs\",[\"f32:0\"]],[\"invoke\",1162,0,\"f32.no_fold_gt_if_to_abs\",[\"f32:4290772992\"]],[\"invoke\",1164,0,\"f32.no_fold_gt_if_to_abs\",[\"f32:2147483648\"]],[\"invoke\",1166,0,\"f32.no_fold_ge_if_to_abs\",[\"f32:4290772992\"]],[\"invoke\",1168,0,\"f32.no_fold_ge_if_to_abs\",[\"f32:2147483648\"]],[\"invoke\",1171,0,\"f64.no_fold_lt_if_to_abs\",[\"f64:0\"]],[\"invoke\",1174,0,\"f64.no_fold_le_if_to_abs\",[\"f64:18444492273895866368\"]],[\"invoke\",1176,0,\"f64.no_fold_le_if_to_abs\",[\"f64:9223372036854775808\"]],[\"invoke\",1179,0,\"f64.no_fold_gt_if_to_abs\",[\"f64:0\"]],[\"invoke\",1182,0,\"f64.no_fold_ge_if_to_abs\",[\"f64:18444492273895866368\"]],[\"invoke\",1184,0,\"f64.no_fold_ge_if_to_abs\",[\"f64:9223372036854775808\"]],[\"module\",1189,55],[\"invoke\",1199,0,\"f64.incorrect_correction\",[]],[\"module\",1204,56],[\"module\",1223,57],[\"invoke\",1240,0,\"calculate\",[]],[\"module\",1245,58],[\"module\",1256,59],[\"invoke\",1262,0,\"llvm_pr27153\",[\"i32:33554434\"]],[\"module\",1267,60],[\"module\",1284,61],[\"invoke\",1298,0,\"thepast0\",[\"f64:9007199254740992\",\"f64:4607182418800017407\",\"f64:4611686018427387904\",\"f64:4602678819172646912\"]],[\"invoke\",1300,0,\"thepast2\",[\"f32:16777216\",\"f32:1056964608\",\"f32:1065353216\"]],[\"module\",1305,62],[\"invoke\",1311,0,\"inverse\",[\"f32:1119879168\"]],[\"module\",1316,63],[\"invoke\",1327,0,\"f64_sqrt_minus_2\",[\"f64:4616189618054758400\"]],[\"module\",1331,64],[\"invoke\",1340,0,\"f32.no_fold_recip_recip\",[\"f32:426844452\"]],[\"invoke\",1342,0,\"f32.no_fold_recip_recip\",[\"f32:3253941441\"]],[\"invoke\",1345,0,\"f32.no_fold_recip_recip\",[\"f32:2147483648\"]],[\"invoke\",1347,0,\"f32.no_fold_recip_recip\",[\"f32:4286578688\"]],[\"invoke\",1350,0,\"f64.no_fold_recip_recip\",[\"f64:14500888369201570768\"]],[\"invoke\",1352,0,\"f64.no_fold_recip_recip\",[\"f64:5359183527603521526\"]],[\"invoke\",1354,0,\"f64.no_fold_recip_recip\",[\"f64:8671785631545870379\"]],[\"invoke\",1357,0,\"f64.no_fold_recip_recip\",[\"f64:0\"]],[\"invoke\",1359,0,\"f64.no_fold_recip_recip\",[\"f64:9218868437227405312\"]],[\"module\",1363,65],[\"invoke\",1374,0,\"f32.no_algebraic_factoring\",[\"f32:3415653214\",\"f32:1274676302\"]],[\"invoke\",1375,0,\"f32.no_algebraic_factoring\",[\"f32:1446924633\",\"f32:3607373982\"]],[\"invoke\",1377,0,\"f32.no_algebraic_factoring\",[\"f32:3278732464\",\"f32:3379389272\"]],[\"invoke\",1380,0,\"f64.no_algebraic_factoring\",[\"f64:2911983657790464931\",\"f64:2814431682419759911\"]],[\"invoke\",1382,0,\"f64.no_algebraic_factoring\",[\"f64:14639789466354372633\",\"f64:5456963169336729236\"]],[\"module\",1387,66],[\"invoke\",1397,0,\"f32.no_algebraic_factoring\",[\"f32:684135946\",\"f32:744319693\"]],[\"invoke\",1399,0,\"f32.no_algebraic_factoring\",[\"f32:968841772\",\"f32:3106497100\"]],[\"invoke\",1401,0,\"f32.no_algebraic_factoring\",[\"f32:1498230729\",\"f32:3650453580\"]],[\"invoke\",1404,0,\"f64.no_algebraic_factoring\",[\"f64:15222970140370015722\",\"f64:15325207139996136125\"]],[\"invoke\",1406,0,\"f64.no_algebraic_factoring\",[\"f64:14653559129294038194\",\"f64:14581996260169223461\"]],[\"module\",1412,67],[\"invoke\",1445,0,\"f32.simple_x4_sum\",[\"i32:0\",\"i32:16\",\"i32:32\"]],[\"invoke\",1447,0,\"f32.load\",[\"i32:36\"]],[\"invoke\",1449,0,\"f32.load\",[\"i32:44\"]],[\"module\",1451,68],[\"invoke\",1485,0,\"f64.load\",[\"i32:64\"]],[\"invoke\",1486,0,\"f64.load\",[\"i32:72\"]],[\"invoke\",1488,0,\"f64.load\",[\"i32:88\"]],[\"module\",1493,69],[\"invoke\",1585,0,\"f32.plain_sum\",[\"i32:0\",\"i32:256\"]],[\"module\",1587,70],[\"invoke\",1636,0,\"f64.plain_sum\",[\"i32:0\",\"i32:256\"]],[\"module\",1640,71],[\"invoke\",1649,0,\"f32.no_fold_neg_sub\",[\"f32:0\",\"f32:2147483648\"]],[\"invoke\",1651,0,\"f32.no_fold_neg_sub\",[\"f32:0\",\"f32:0\"]],[\"invoke\",1654,0,\"f64.no_fold_neg_sub\",[\"f64:0\",\"f64:9223372036854775808\"]],[\"invoke\",1656,0,\"f64.no_fold_neg_sub\",[\"f64:0\",\"f64:0\"]],[\"module\",1660,72],[\"invoke\",1669,0,\"f32.no_fold_neg_add\",[\"f32:0\",\"f32:2147483648\"]],[\"invoke\",1671,0,\"f32.no_fold_neg_add\",[\"f32:0\",\"f32:0\"]],[\"invoke\",1674,0,\"f64.no_fold_neg_add\",[\"f64:0\",\"f64:9223372036854775808\"]],[\"invoke\",1676,0,\"f64.no_fold_neg_add\",[\"f64:0\",\"f64:0\"]],[\"module\",1680,73],[\"invoke\",1689,0,\"f32.no_fold_add_neg_neg\",[\"f32:0\",\"f32:2147483648\"]],[\"invoke\",1690,0,\"f32.no_fold_add_neg_neg\",[\"f32:2147483648\",\"f32:0\"]],[\"invoke\",1693,0,\"f64.no_fold_add_neg_neg\",[\"f64:9223372036854775808\",\"f64:9223372036854775808\"]],[\"invoke\",1695,0,\"f64.no_fold_add_neg_neg\",[\"f64:9223372036854775808\",\"f64:0\"]],[\"module\",1700,74],[\"invoke\",1708,0,\"f32.no_fold_add_neg\",[\"f32:0\"]],[\"invoke\",1710,0,\"f32.no_fold_add_neg\",[\"f32:2139095040\"]],[\"invoke\",1713,0,\"f64.no_fold_add_neg\",[\"f64:0\"]],[\"invoke\",1715,0,\"f64.no_fold_add_neg\",[\"f64:9218868437227405312\"]],[\"module\",1720,75],[\"invoke\",1734,0,\"f32.no_fold_6x_via_add\",[\"f32:4046243078\"]],[\"invoke\",1736,0,\"f32.no_fold_6x_via_add\",[\"f32:419462401\"]],[\"invoke\",1738,0,\"f32.no_fold_6x_via_add\",[\"f32:3883931973\"]],[\"invoke\",1741,0,\"f64.no_fold_6x_via_add\",[\"f64:11424134044545165748\"]],[\"invoke\",1743,0,\"f64.no_fold_6x_via_add\",[\"f64:7991451501228919438\"]],[\"module\",1749,76],[\"invoke\",1757,0,\"f32.no_fold_div_div\",[\"f32:3875242260\",\"f32:3086869257\",\"f32:3301317576\"]],[\"invoke\",1758,0,\"f32.no_fold_div_div\",[\"f32:485052055\",\"f32:1996083391\",\"f32:2276616712\"]],[\"invoke\",1760,0,\"f32.no_fold_div_div\",[\"f32:3101818893\",\"f32:4258133430\",\"f32:2855958950\"]],[\"invoke\",1763,0,\"f64.no_fold_div_div\",[\"f64:6128077243319875447\",\"f64:7240092044185667120\",\"f64:10312472494987686942\"]],[\"invoke\",1765,0,\"f64.no_fold_div_div\",[\"f64:13843263185226986279\",\"f64:17796742619038211051\",\"f64:5375701731263473827\"]],[\"invoke\",1767,0,\"f64.no_fold_div_div\",[\"f64:9835707468114203513\",\"f64:1924400690116523912\",\"f64:13208934041167870811\"]],[\"module\",1773,77],[\"invoke\",1782,0,\"f32.no_fold_mul_divs\",[\"f32:4068974897\",\"f32:1276265036\",\"f32:930821438\",\"f32:1044692964\"]],[\"invoke\",1784,0,\"f32.no_fold_mul_divs\",[\"f32:4135236702\",\"f32:787270424\",\"f32:932959293\",\"f32:1724950821\"]],[\"invoke\",1787,0,\"f64.no_fold_mul_divs\",[\"f64:10143060558527560466\",\"f64:11745059379675007839\",\"f64:16295837305232663584\",\"f64:5444961058358534642\"]],[\"invoke\",1789,0,\"f64.no_fold_mul_divs\",[\"f64:15220380342429201729\",\"f64:14697937818549468616\",\"f64:13203624158275174657\",\"f64:17131104131485469546\"]],[\"invoke\",1791,0,\"f64.no_fold_mul_divs\",[\"f64:4529089342618677929\",\"f64:3361245300043094097\",\"f64:1815899012046749567\",\"f64:15418396504351552390\"]],[\"module\",1795,78],[\"invoke\",1804,0,\"f32.no_fold_add_divs\",[\"f32:2690073844\",\"f32:2809448479\",\"f32:3608905030\"]],[\"invoke\",1806,0,\"f32.no_fold_add_divs\",[\"f32:2365787800\",\"f32:245111369\",\"f32:3952003433\"]],[\"invoke\",1809,0,\"f64.no_fold_add_divs\",[\"f64:15770585325769044278\",\"f64:6564157675451289455\",\"f64:8712254759989822359\"]],[\"invoke\",1810,0,\"f64.no_fold_add_divs\",[\"f64:14069844870254671283\",\"f64:4634122757084803708\",\"f64:9524897388132352235\"]],[\"invoke\",1812,0,\"f64.no_fold_add_divs\",[\"f64:6019502660029506228\",\"f64:15316513033818836241\",\"f64:4039967192182502935\"]],[\"module\",1817,79],[\"invoke\",1825,0,\"f32.no_fold_sqrt_square\",[\"f32:2662226315\"]],[\"invoke\",1827,0,\"f32.no_fold_sqrt_square\",[\"f32:2624528574\"]],[\"invoke\",1829,0,\"f32.no_fold_sqrt_square\",[\"f32:1978715378\"]],[\"invoke\",1832,0,\"f64.no_fold_sqrt_square\",[\"f64:11517048459773840771\"]],[\"invoke\",1834,0,\"f64.no_fold_sqrt_square\",[\"f64:11056484744549647728\"]],[\"module\",1839,80],[\"invoke\",1847,0,\"f32.no_fold_mul_sqrts\",[\"f32:24047316\",\"f32:2517821717\"]],[\"invoke\",1849,0,\"f32.no_fold_mul_sqrts\",[\"f32:329708528\",\"f32:1120042892\"]],[\"invoke\",1851,0,\"f32.no_fold_mul_sqrts\",[\"f32:598482176\",\"f32:990534933\"]],[\"invoke\",1854,0,\"f64.no_fold_mul_sqrts\",[\"f64:1712959863583927241\",\"f64:2792003944717853898\"]],[\"invoke\",1856,0,\"f64.no_fold_mul_sqrts\",[\"f64:2976792199849816182\",\"f64:2030444188042608984\"]],[\"module\",1861,81],[\"invoke\",1869,0,\"f32.no_fold_div_sqrts\",[\"f32:3428799709\",\"f32:2733489079\"]],[\"invoke\",1870,0,\"f32.no_fold_div_sqrts\",[\"f32:1339867611\",\"f32:1296568207\"]],[\"invoke\",1872,0,\"f32.no_fold_div_sqrts\",[\"f32:1566143010\",\"f32:816694667\"]],[\"invoke\",1875,0,\"f64.no_fold_div_sqrts\",[\"f64:10629913473787695463\",\"f64:12991130264919696663\"]],[\"invoke\",1877,0,\"f64.no_fold_div_sqrts\",[\"f64:6965599900716272009\",\"f64:4118781927977980600\"]],[\"invoke\",1879,0,\"f64.no_fold_div_sqrts\",[\"f64:1056821405580891413\",\"f64:8865548665903786673\"]],[\"module\",1883,82],[\"invoke\",1892,0,\"f32.no_fold_mul_sqrt_div\",[\"f32:2210946958\",\"f32:256302916\"]],[\"invoke\",1894,0,\"f32.no_fold_mul_sqrt_div\",[\"f32:3576537897\",\"f32:2010442638\"]],[\"invoke\",1897,0,\"f64.no_fold_mul_sqrt_div\",[\"f64:7751219282814906463\",\"f64:8023732701704228537\"]],[\"invoke\",1899,0,\"f64.no_fold_mul_sqrt_div\",[\"f64:2695209648295623224\",\"f64:7133480874314061811\"]],[\"invoke\",1901,0,\"f64.no_fold_mul_sqrt_div\",[\"f64:5076901024782455083\",\"f64:8399438310541178654\"]],[\"module\",1906,83],[\"invoke\",1915,0,\"f64.no_flush_intermediate_subnormal\",[\"f64:4503599627370496\",\"f64:4372995238176751616\",\"f64:4841369599423283200\"]],[\"module\",1920,84],[\"invoke\",1944,0,\"f32.recoding_le\",[\"f32:4286578688\",\"f32:1077936128\"]],[\"invoke\",1947,0,\"f32.recoding_eq\",[\"f32:0\",\"f32:1065353216\"]],[\"invoke\",1948,0,\"f32.recoding_le\",[\"f32:0\",\"f32:1065353216\"]],[\"invoke\",1951,0,\"f64.recoding_eq\",[\"f64:18442240474082181120\",\"f64:4613937818241073152\"]],[\"invoke\",1953,0,\"f64.recoding_lt\",[\"f64:18442240474082181120\",\"f64:4613937818241073152\"]],[\"invoke\",1956,0,\"f64.recoding_le\",[\"f64:0\",\"f64:4607182418800017408\"]],[\"invoke\",1959,0,\"recoding_demote\",[\"f64:4014054135371399168\",\"f32:1150853120\"]],[\"module\",1964,85],[\"invoke\",1973,0,\"f64.no_extended_precision_div\",[\"f64:4613937818241073152\",\"f64:4619567317775286272\",\"f64:4601392076421969627\"]],[\"module\",1980,86],[\"invoke\",1989,0,\"f64.no_distribute_exact\",[\"f64:9223372036854775808\"]],[\"module\",1994,87],[\"invoke\",2027,0,\"f32.xkcd_sqrt_2\",[\"f32:1077936128\",\"f32:1084227584\",\"f32:1078530011\",\"f32:1088421888\"]],[\"invoke\",2029,0,\"f32.xkcd_sqrt_3\",[\"f32:1073741824\",\"f32:1076754516\",\"f32:1078530011\"]],[\"invoke\",2031,0,\"f32.xkcd_sqrt_5\",[\"f32:1073741824\",\"f32:1076754516\",\"f32:1077936128\"]],[\"invoke\",2034,0,\"f64.sqrt\",[\"f64:4611686018427387904\"]],[\"invoke\",2036,0,\"f64.sqrt\",[\"f64:4613937818241073152\"]],[\"invoke\",2038,0,\"f64.sqrt\",[\"f64:4617315517961601024\"]],[\"invoke\",2039,0,\"f64.xkcd_sqrt_5\",[\"f64:4611686018427387904\",\"f64:4613303445314885481\",\"f64:4613937818241073152\"]],[\"module\",2045,88],[\"invoke\",2123,0,\"f32.compute_radix\",[\"f32:1065353216\",\"f32:1065353216\"]],[\"module\",2129,89],[\"invoke\",2137,0,\"f32.no_fold_sub1_mul_add\",[\"f32:796917760\",\"f32:1065353216\"]],[\"module\",2143,90],[\"invoke\",2157,0,\"f32.no_fold_add_le_monotonicity\",[\"f32:0\",\"f32:0\",\"f32:2143289344\"]],[\"invoke\",2159,0,\"f64.no_fold_add_le_monotonicity\",[\"f64:0\",\"f64:0\",\"f64:9221120237041090560\"]],[\"module\",2164,91],[\"invoke\",2190,0,\"f32.not_lt\",[\"f32:2143289344\",\"f32:0\"]],[\"invoke\",2192,0,\"f32.not_gt\",[\"f32:2143289344\",\"f32:0\"]],[\"invoke\",2194,0,\"f64.not_lt\",[\"f64:9221120237041090560\",\"f64:0\"]],[\"invoke\",2196,0,\"f64.not_gt\",[\"f64:9221120237041090560\",\"f64:0\"]],[\"module\",2203,92],[\"invoke\",2211,0,\"f32.epsilon\",[]],[\"module\",2218,93],[\"invoke\",2266,0,\"f32.epsilon\",[]],[\"module\",2272,94],[\"invoke\",2292,0,\"f32.no_trichotomy_lt\",[\"f32:0\",\"f32:2143289344\"]],[\"invoke\",2294,0,\"f32.no_trichotomy_gt\",[\"f32:0\",\"f32:2143289344\"]],[\"invoke\",2295,0,\"f32.no_trichotomy_ge\",[\"f32:0\",\"f32:2143289344\"]],[\"invoke\",2297,0,\"f64.no_trichotomy_le\",[\"f64:0\",\"f64:9221120237041090560\"]],[\"invoke\",2299,0,\"f64.no_trichotomy_ge\",[\"f64:0\",\"f64:9221120237041090560\"]],[\"module\",2304,95],[\"invoke\",2385,0,\"f32.canonical_nan_bitpattern\",[\"i32:2143289344\",\"i32:2143289344\"]],[\"invoke\",2387,0,\"f32.canonical_nan_bitpattern\",[\"i32:2143289344\",\"i32:4290772992\"]],[\"invoke\",2389,0,\"f32.nonarithmetic_nan_bitpattern\",[\"i32:2143302160\"]],[\"invoke\",2394,0,\"f64.canonical_nan_bitpattern\",[\"i64:0\",\"i64:0\"]],[\"invoke\",2396,0,\"f64.canonical_nan_bitpattern\",[\"i64:18444492273895866368\",\"i64:9221120237041090560\"]],[\"invoke\",2398,0,\"f64.canonical_nan_bitpattern\",[\"i64:18444492273895866368\",\"i64:18444492273895866368\"]],[\"invoke\",2400,0,\"f64.nonarithmetic_nan_bitpattern\",[\"i64:18444492273895879184\"]],[\"module\",2420,96],[\"invoke\",2447,0,\"with_binary_sum_collapse\",[\"f64:4719355144821538816\",\"f64:4607182418800017408\",\"f64:13830554455654793216\",\"f64:4725141118604279808\",\"f64:4720637518976909312\",\"f64:4607182418800017408\",\"f64:13830554455654793216\",\"f64:13938223582048944128\"]],[\"module\",2454,97],[\"invoke\",2466,0,\"f32.contract2fma\",[\"f32:1066192077\",\"f32:1066192077\"]],[\"invoke\",2468,0,\"f64.contract2fma\",[\"f64:4607182418800017408\",\"f64:4607182418800017408\"]],[\"invoke\",2469,0,\"f64.contract2fma\",[\"f64:4607632778762754458\",\"f64:4607632778762754458\"]],[\"module\",2475,98],[\"invoke\",2484,0,\"f32.division_by_small_number\",[\"f32:1289068416\",\"f32:1203982336\",\"f32:980151802\"]],[\"module\",2490,99],[\"invoke\",2497,0,\"f32.golden_ratio\",[\"f32:1056964608\",\"f32:1065353216\",\"f32:1084227584\"]],[\"module\",2503,100],[\"invoke\",2516,0,\"f32.silver_means\",[\"f32:0\"]],[\"invoke\",2518,0,\"f32.silver_means\",[\"f32:1073741824\"]],[\"invoke\",2520,0,\"f32.silver_means\",[\"f32:1082130432\"]],[\"invoke\",2522,0,\"f64.silver_means\",[\"f64:0\"]],[\"invoke\",2524,0,\"f64.silver_means\",[\"f64:4611686018427387904\"]],[\"invoke\",2526,0,\"f64.silver_means\",[\"f64:4616189618054758400\"]],[\"module\",2532,101],[\"invoke\",2537,0,\"point_four\",[\"f64:4616189618054758400\",\"f64:4621819117588971520\"]],[\"module\",2542,102],[\"invoke\",2608,0,\"tau\",[\"i32:11\"]],[\"module\",2612,103],[\"invoke\",2624,0,\"f64.no_fold_conditional_inc\",[\"f64:9223372036854775808\",\"f64:13830554455654793216\"]],[\"file\",\"float_literals.wast\"],[\"module\",3,104],[\"invoke\",121,0,\"f32.nan\",[]],[\"invoke\",122,0,\"f32.positive_nan\",[]],[\"invoke\",123,0,\"f32.negative_nan\",[]],[\"invoke\",124,0,\"f32.plain_nan\",[]],[\"invoke\",125,0,\"f32.informally_known_as_plain_snan\",[]],[\"invoke\",126,0,\"f32.all_ones_nan\",[]],[\"invoke\",127,0,\"f32.misc_nan\",[]],[\"invoke\",128,0,\"f32.misc_positive_nan\",[]],[\"invoke\",129,0,\"f32.misc_negative_nan\",[]],[\"invoke\",130,0,\"f32.infinity\",[]],[\"invoke\",131,0,\"f32.positive_infinity\",[]],[\"invoke\",132,0,\"f32.negative_infinity\",[]],[\"invoke\",133,0,\"f32.zero\",[]],[\"invoke\",134,0,\"f32.positive_zero\",[]],[\"invoke\",135,0,\"f32.negative_zero\",[]],[\"invoke\",136,0,\"f32.misc\",[]],[\"invoke\",137,0,\"f32.min_positive\",[]],[\"invoke\",138,0,\"f32.min_normal\",[]],[\"invoke\",139,0,\"f32.max_subnormal\",[]],[\"invoke\",140,0,\"f32.max_finite\",[]],[\"invoke\",141,0,\"f32.trailing_dot\",[]],[\"invoke\",142,0,\"f32.misc_int\",[]],[\"invoke\",143,0,\"f32.large_int\",[]],[\"invoke\",144,0,\"f32.min_int32\",[]],[\"invoke\",145,0,\"f32.min_int64\",[]],[\"invoke\",146,0,\"f32_dec.zero\",[]],[\"invoke\",147,0,\"f32_dec.positive_zero\",[]],[\"invoke\",148,0,\"f32_dec.negative_zero\",[]],[\"invoke\",149,0,\"f32_dec.misc\",[]],[\"invoke\",150,0,\"f32_dec.min_positive\",[]],[\"invoke\",151,0,\"f32_dec.min_normal\",[]],[\"invoke\",152,0,\"f32_dec.max_subnormal\",[]],[\"invoke\",153,0,\"f32_dec.max_finite\",[]],[\"invoke\",154,0,\"f32_dec.trailing_dot\",[]],[\"invoke\",155,0,\"f32_dec.root_beer_float\",[]],[\"invoke\",156,0,\"f32_dec.misc_int\",[]],[\"invoke\",157,0,\"f32_dec.large_int\",[]],[\"invoke\",158,0,\"f32_dec.min_int32\",[]],[\"invoke\",159,0,\"f32_dec.min_int64\",[]],[\"invoke\",161,0,\"f64.nan\",[]],[\"invoke\",162,0,\"f64.positive_nan\",[]],[\"invoke\",163,0,\"f64.negative_nan\",[]],[\"invoke\",164,0,\"f64.plain_nan\",[]],[\"invoke\",165,0,\"f64.informally_known_as_plain_snan\",[]],[\"invoke\",166,0,\"f64.all_ones_nan\",[]],[\"invoke\",167,0,\"f64.misc_nan\",[]],[\"invoke\",168,0,\"f64.misc_positive_nan\",[]],[\"invoke\",169,0,\"f64.misc_negative_nan\",[]],[\"invoke\",170,0,\"f64.infinity\",[]],[\"invoke\",171,0,\"f64.positive_infinity\",[]],[\"invoke\",172,0,\"f64.negative_infinity\",[]],[\"invoke\",173,0,\"f64.zero\",[]],[\"invoke\",174,0,\"f64.positive_zero\",[]],[\"invoke\",175,0,\"f64.negative_zero\",[]],[\"invoke\",176,0,\"f64.misc\",[]],[\"invoke\",177,0,\"f64.min_positive\",[]],[\"invoke\",178,0,\"f64.min_normal\",[]],[\"invoke\",179,0,\"f64.max_subnormal\",[]],[\"invoke\",180,0,\"f64.max_finite\",[]],[\"invoke\",181,0,\"f64.trailing_dot\",[]],[\"invoke\",182,0,\"f64.misc_int\",[]],[\"invoke\",183,0,\"f64.large_int\",[]],[\"invoke\",184,0,\"f64.min_int32\",[]],[\"invoke\",185,0,\"f64.min_int64\",[]],[\"invoke\",186,0,\"f64_dec.zero\",[]],[\"invoke\",187,0,\"f64_dec.positive_zero\",[]],[\"invoke\",188,0,\"f64_dec.negative_zero\",[]],[\"invoke\",189,0,\"f64_dec.misc\",[]],[\"invoke\",190,0,\"f64_dec.min_positive\",[]],[\"invoke\",191,0,\"f64_dec.min_normal\",[]],[\"invoke\",192,0,\"f64_dec.max_subnormal\",[]],[\"invoke\",193,0,\"f64_dec.max_finite\",[]],[\"invoke\",194,0,\"f64_dec.trailing_dot\",[]],[\"invoke\",195,0,\"f64_dec.root_beer_float\",[]],[\"invoke\",196,0,\"f64_dec.misc_int\",[]],[\"invoke\",197,0,\"f64_dec.large_int\",[]],[\"invoke\",198,0,\"f64_dec.min_int32\",[]],[\"invoke\",199,0,\"f64_dec.min_int64\",[]],[\"invoke\",201,0,\"f32-dec-sep1\",[]],[\"invoke\",202,0,\"f32-dec-sep2\",[]],[\"invoke\",203,0,\"f32-dec-sep3\",[]],[\"invoke\",204,0,\"f32-dec-sep4\",[]],[\"invoke\",205,0,\"f32-dec-sep5\",[]],[\"invoke\",206,0,\"f32-hex-sep1\",[]],[\"invoke\",207,0,\"f32-hex-sep2\",[]],[\"invoke\",208,0,\"f32-hex-sep3\",[]],[\"invoke\",209,0,\"f32-hex-sep4\",[]],[\"invoke\",210,0,\"f32-hex-sep5\",[]],[\"invoke\",212,0,\"f64-dec-sep1\",[]],[\"invoke\",213,0,\"f64-dec-sep2\",[]],[\"invoke\",214,0,\"f64-dec-sep3\",[]],[\"invoke\",215,0,\"f64-dec-sep4\",[]],[\"invoke\",216,0,\"f64-dec-sep5\",[]],[\"invoke\",217,0,\"f64-hex-sep1\",[]],[\"invoke\",218,0,\"f64-hex-sep2\",[]],[\"invoke\",219,0,\"f64-hex-sep3\",[]],[\"invoke\",220,0,\"f64-hex-sep4\",[]],[\"invoke\",221,0,\"f64-hex-sep5\",[]],[\"module\",224,105],[\"invoke\",233,0,\"4294967249\",[]],[\"file\",\"float_misc.wast\"],[\"module\",17,106],[\"invoke\",50,0,\"f32.add\",[\"f32:1066388847\",\"f32:789036054\"]],[\"invoke\",55,0,\"f32.add\",[\"f32:1065353216\",\"f32:864026624\"]],[\"invoke\",56,0,\"f32.add\",[\"f32:1065353216\",\"f32:864026625\"]],[\"invoke\",57,0,\"f64.add\",[\"f64:4607182418800017408\",\"f64:4368491638549381120\"]],[\"invoke\",58,0,\"f64.add\",[\"f64:4607182418800017408\",\"f64:4368491638549381121\"]],[\"invoke\",61,0,\"f32.add\",[\"f32:1\",\"f32:8388607\"]],[\"invoke\",62,0,\"f64.add\",[\"f64:1\",\"f64:4503599627370495\"]],[\"invoke\",67,0,\"f32.add\",[\"f32:1325400064\",\"f32:1149241344\"]],[\"invoke\",72,0,\"f64.add\",[\"f64:9290926031265333248\",\"f64:5910\"]],[\"invoke\",75,0,\"f64.add\",[\"f64:4845873199050653696\",\"f64:4607182463836013682\"]],[\"invoke\",78,0,\"f64.add\",[\"f64:4845873199050653697\",\"f64:4607182281361063936\"]],[\"invoke\",81,0,\"f32.add\",[\"f32:1258291200\",\"f32:1056964608\"]],[\"invoke\",82,0,\"f32.add\",[\"f32:1258291201\",\"f32:1056964608\"]],[\"invoke\",83,0,\"f64.add\",[\"f64:4841369599423283200\",\"f64:4602678819172646912\"]],[\"invoke\",84,0,\"f64.add\",[\"f64:4841369599423283201\",\"f64:4602678819172646912\"]],[\"invoke\",88,0,\"f32.add\",[\"f32:1630930834\",\"f32:3650472296\"]],[\"invoke\",89,0,\"f32.add\",[\"f32:376639884\",\"f32:24880479\"]],[\"invoke\",90,0,\"f32.add\",[\"f32:1393899754\",\"f32:3680827526\"]],[\"invoke\",91,0,\"f32.add\",[\"f32:947682203\",\"f32:1958603311\"]],[\"invoke\",92,0,\"f64.add\",[\"f64:2751474943031650218\",\"f64:14953834855654151696\"]],[\"invoke\",93,0,\"f64.add\",[\"f64:14174076479053295281\",\"f64:3779173703388472492\"]],[\"invoke\",94,0,\"f64.add\",[\"f64:3940735352412940081\",\"f64:13776826739676942972\"]],[\"invoke\",95,0,\"f64.add\",[\"f64:6845567588107709194\",\"f64:4904758653169279867\"]],[\"invoke\",99,0,\"f32.add\",[\"f32:1670249659\",\"f32:3384781876\"]],[\"invoke\",100,0,\"f32.add\",[\"f32:692047414\",\"f32:2564611463\"]],[\"invoke\",101,0,\"f32.add\",[\"f32:2862180574\",\"f32:2122049802\"]],[\"invoke\",102,0,\"f32.add\",[\"f32:2848402951\",\"f32:2325576998\"]],[\"invoke\",103,0,\"f32.add\",[\"f32:982116028\",\"f32:2317187467\"]],[\"invoke\",104,0,\"f64.add\",[\"f64:5417704807092288842\",\"f64:11458115339210975423\"]],[\"invoke\",105,0,\"f64.add\",[\"f64:5306888566943064716\",\"f64:13560253914302152139\"]],[\"invoke\",107,0,\"f64.add\",[\"f64:14493512931660601393\",\"f64:14459238760182946131\"]],[\"invoke\",108,0,\"f64.add\",[\"f64:13847269089137787654\",\"f64:5913400236268010570\"]],[\"invoke\",111,0,\"f32.add\",[\"f32:2231979500\",\"f32:711174153\"]],[\"invoke\",112,0,\"f32.add\",[\"f32:3084976721\",\"f32:843077785\"]],[\"invoke\",113,0,\"f32.add\",[\"f32:3522127374\",\"f32:157500525\"]],[\"invoke\",114,0,\"f32.add\",[\"f32:78702389\",\"f32:3468399689\"]],[\"invoke\",115,0,\"f32.add\",[\"f32:2208228371\",\"f32:1870536627\"]],[\"invoke\",116,0,\"f64.add\",[\"f64:1111252809067936271\",\"f64:18353849863141451174\"]],[\"invoke\",118,0,\"f64.add\",[\"f64:9478779231447112314\",\"f64:3336259491488022866\"]],[\"invoke\",119,0,\"f64.add\",[\"f64:11541137186853127278\",\"f64:735421354967021004\"]],[\"invoke\",120,0,\"f64.add\",[\"f64:18181384676953296798\",\"f64:8211214354507491487\"]],[\"invoke\",123,0,\"f64.add\",[\"f64:17455847474217352892\",\"f64:8328504330151758329\"]],[\"invoke\",124,0,\"f64.add\",[\"f64:8138029755241725240\",\"f64:7967841770626914860\"]],[\"invoke\",125,0,\"f64.add\",[\"f64:16644741111433920314\",\"f64:7647005019700459394\"]],[\"invoke\",126,0,\"f64.add\",[\"f64:6696851869641768443\",\"f64:6935821972358342665\"]],[\"invoke\",130,0,\"f64.add\",[\"f64:17221080860858566255\",\"f64:18119355194379769652\"]],[\"invoke\",131,0,\"f64.add\",[\"f64:5479469458864399218\",\"f64:15063363222154738502\"]],[\"invoke\",132,0,\"f64.add\",[\"f64:15191393426281101490\",\"f64:2705322087145917275\"]],[\"invoke\",133,0,\"f64.add\",[\"f64:12404517211283155052\",\"f64:15933096090325362723\"]],[\"invoke\",134,0,\"f64.add\",[\"f64:12941874353187635000\",\"f64:149235811938438489\"]],[\"invoke\",137,0,\"f32.add\",[\"f32:2039859408\",\"f32:2137384617\"]],[\"invoke\",138,0,\"f32.add\",[\"f32:2135652809\",\"f32:4113932278\"]],[\"invoke\",140,0,\"f32.add\",[\"f32:4220448050\",\"f32:4286022000\"]],[\"invoke\",141,0,\"f32.add\",[\"f32:4280642669\",\"f32:4269109313\"]],[\"invoke\",142,0,\"f64.add\",[\"f64:9214390167692528523\",\"f64:9025765862177526868\"]],[\"invoke\",143,0,\"f64.add\",[\"f64:9218174330906182895\",\"f64:9066655639269665468\"]],[\"invoke\",144,0,\"f64.add\",[\"f64:18440065048487386960\",\"f64:9166530475417861020\"]],[\"invoke\",145,0,\"f64.add\",[\"f64:18341378616977760125\",\"f64:9218376305633483958\"]],[\"invoke\",146,0,\"f64.add\",[\"f64:9214484525044672441\",\"f64:18297568705700624757\"]],[\"invoke\",149,0,\"f32.add\",[\"f32:5932680\",\"f32:623\"]],[\"invoke\",151,0,\"f32.add\",[\"f32:2147483656\",\"f32:3701056\"]],[\"invoke\",152,0,\"f32.add\",[\"f32:2147483668\",\"f32:44113961\"]],[\"invoke\",153,0,\"f32.add\",[\"f32:453\",\"f32:2147507390\"]],[\"invoke\",154,0,\"f64.add\",[\"f64:5760669582171681\",\"f64:9233067416817195210\"]],[\"invoke\",155,0,\"f64.add\",[\"f64:9301019945277718\",\"f64:9236877899492518055\"]],[\"invoke\",156,0,\"f64.add\",[\"f64:9225260466475370890\",\"f64:9229416573822848190\"]],[\"invoke\",157,0,\"f64.add\",[\"f64:16303139584665809\",\"f64:9240639734747285230\"]],[\"invoke\",162,0,\"f32.add\",[\"f32:2139095038\",\"f32:1937768448\"]],[\"invoke\",163,0,\"f64.add\",[\"f64:9218868437227405310\",\"f64:8980177656976769024\"]],[\"invoke\",166,0,\"f32.add\",[\"f32:1073741824\",\"f32:1073741824\"]],[\"invoke\",167,0,\"f64.add\",[\"f64:4611686018427387904\",\"f64:4611686018427387904\"]],[\"invoke\",170,0,\"f32.add\",[\"f32:2139095039\",\"f32:1929379839\"]],[\"invoke\",171,0,\"f32.add\",[\"f32:2139095039\",\"f32:1929379840\"]],[\"invoke\",172,0,\"f64.add\",[\"f64:9218868437227405311\",\"f64:8975674057349398527\"]],[\"invoke\",173,0,\"f64.add\",[\"f64:9218868437227405311\",\"f64:8975674057349398528\"]],[\"invoke\",178,0,\"f64.sub\",[\"f64:4679240012837945344\",\"f64:4440549232587309056\"]],[\"invoke\",182,0,\"f32.sub\",[\"f32:1065353216\",\"f32:855638016\"]],[\"invoke\",183,0,\"f32.sub\",[\"f32:1065353216\",\"f32:855638017\"]],[\"invoke\",184,0,\"f64.sub\",[\"f64:4607182418800017408\",\"f64:4363988038922010624\"]],[\"invoke\",185,0,\"f64.sub\",[\"f64:4607182418800017408\",\"f64:4363988038922010625\"]],[\"invoke\",188,0,\"f32.sub\",[\"f32:183964211\",\"f32:4211807167\"]],[\"invoke\",189,0,\"f32.sub\",[\"f32:4213323727\",\"f32:3575761746\"]],[\"invoke\",191,0,\"f32.sub\",[\"f32:88711906\",\"f32:431212897\"]],[\"invoke\",192,0,\"f32.sub\",[\"f32:919562194\",\"f32:2319656354\"]],[\"invoke\",193,0,\"f64.sub\",[\"f64:12332465020357998661\",\"f64:9766989582560416510\"]],[\"invoke\",194,0,\"f64.sub\",[\"f64:16318450733361321773\",\"f64:13120762196173477233\"]],[\"invoke\",195,0,\"f64.sub\",[\"f64:2534186520144737456\",\"f64:10065159679028096147\"]],[\"invoke\",196,0,\"f64.sub\",[\"f64:81253721542311597\",\"f64:14524181566355681001\"]],[\"invoke\",197,0,\"f64.sub\",[\"f64:13189545483472981053\",\"f64:11407195172005604952\"]],[\"invoke\",201,0,\"f32.sub\",[\"f32:4130431355\",\"f32:1119299749\"]],[\"invoke\",202,0,\"f32.sub\",[\"f32:2517909066\",\"f32:864524238\"]],[\"invoke\",203,0,\"f32.sub\",[\"f32:2573484334\",\"f32:3114628459\"]],[\"invoke\",204,0,\"f32.sub\",[\"f32:4044667730\",\"f32:576942556\"]],[\"invoke\",205,0,\"f64.sub\",[\"f64:14742371419310964805\",\"f64:17888404506408184249\"]],[\"invoke\",206,0,\"f64.sub\",[\"f64:2953146626865245854\",\"f64:2577681730975527916\"]],[\"invoke\",207,0,\"f64.sub\",[\"f64:12932364735331397407\",\"f64:2320782934320318207\"]],[\"invoke\",208,0,\"f64.sub\",[\"f64:9365060414983047910\",\"f64:12353777816259046974\"]],[\"invoke\",212,0,\"f32.sub\",[\"f32:1869943590\",\"f32:943887556\"]],[\"invoke\",213,0,\"f32.sub\",[\"f32:3372906046\",\"f32:2919590399\"]],[\"invoke\",214,0,\"f32.sub\",[\"f32:2912495853\",\"f32:2745492671\"]],[\"invoke\",215,0,\"f32.sub\",[\"f32:3096029999\",\"f32:957859028\"]],[\"invoke\",216,0,\"f32.sub\",[\"f32:2939165019\",\"f32:2346559691\"]],[\"invoke\",217,0,\"f64.sub\",[\"f64:13126685627069188368\",\"f64:17084005755352353256\"]],[\"invoke\",218,0,\"f64.sub\",[\"f64:17250804263238954355\",\"f64:17897322818375888829\"]],[\"invoke\",220,0,\"f64.sub\",[\"f64:11250563508203208480\",\"f64:2160870138446053709\"]],[\"invoke\",221,0,\"f64.sub\",[\"f64:11315355526970152728\",\"f64:13767999508795332779\"]],[\"invoke\",224,0,\"f64.sub\",[\"f64:4259315722107263852\",\"f64:4089445689175118070\"]],[\"invoke\",225,0,\"f64.sub\",[\"f64:188121565440651108\",\"f64:62416789530785743\"]],[\"invoke\",226,0,\"f64.sub\",[\"f64:3467770562990504390\",\"f64:3710644584044210353\"]],[\"invoke\",227,0,\"f64.sub\",[\"f64:13655868372788825570\",\"f64:13522732182992332383\"]],[\"invoke\",228,0,\"f64.sub\",[\"f64:4496158230847685281\",\"f64:4595312328816348364\"]],[\"invoke\",231,0,\"f64.sub\",[\"f64:10165048318361601487\",\"f64:10384658282813060399\"]],[\"invoke\",233,0,\"f64.sub\",[\"f64:5124509539958121241\",\"f64:1953255029772502995\"]],[\"invoke\",234,0,\"f64.sub\",[\"f64:2408125051325635052\",\"f64:10707017964771367822\"]],[\"invoke\",235,0,\"f64.sub\",[\"f64:4352135458168599028\",\"f64:1826599214642193119\"]],[\"invoke\",239,0,\"f32.sub\",[\"f32:1102651427\",\"f32:1078530011\"]],[\"invoke\",240,0,\"f64.sub\",[\"f64:4627206743602008890\",\"f64:4614256656552045848\"]],[\"invoke\",243,0,\"f32.sub\",[\"f32:1245125372\",\"f32:1245125368\"]],[\"invoke\",244,0,\"f32.sub\",[\"f32:1240736760\",\"f32:1240736728\"]],[\"invoke\",246,0,\"f32.sub\",[\"f32:1220759616\",\"f32:1220759584\"]],[\"invoke\",247,0,\"f32.sub\",[\"f32:1220759616\",\"f32:1220759552\"]],[\"invoke\",248,0,\"f64.sub\",[\"f64:4838362400168542206\",\"f64:4838362400168542204\"]],[\"invoke\",249,0,\"f64.sub\",[\"f64:4835858800541171708\",\"f64:4835858800541171692\"]],[\"invoke\",250,0,\"f64.sub\",[\"f64:4835858800541171708\",\"f64:4835858800541171684\"]],[\"invoke\",251,0,\"f64.sub\",[\"f64:4825251601286430752\",\"f64:4825251601286430736\"]],[\"invoke\",252,0,\"f64.sub\",[\"f64:4825251601286430752\",\"f64:4825251601286430720\"]],[\"invoke\",256,0,\"f64.sub\",[\"f64:4503599627370496\",\"f64:4503599627370495\"]],[\"invoke\",259,0,\"f32.sub\",[\"f32:1065353217\",\"f32:1065353215\"]],[\"invoke\",260,0,\"f32.sub\",[\"f32:1065353217\",\"f32:1065353216\"]],[\"invoke\",261,0,\"f32.sub\",[\"f32:1065353216\",\"f32:1065353215\"]],[\"invoke\",262,0,\"f64.sub\",[\"f64:4607182418800017409\",\"f64:4607182418800017407\"]],[\"invoke\",263,0,\"f64.sub\",[\"f64:4607182418800017409\",\"f64:4607182418800017408\"]],[\"invoke\",264,0,\"f64.sub\",[\"f64:4607182418800017408\",\"f64:4607182418800017407\"]],[\"invoke\",268,0,\"f32.sub\",[\"f32:2139095039\",\"f32:1929379839\"]],[\"invoke\",270,0,\"f64.sub\",[\"f64:9218868437227405311\",\"f64:8975674057349398527\"]],[\"invoke\",271,0,\"f64.sub\",[\"f64:9218868437227405311\",\"f64:8975674057349398528\"]],[\"invoke\",274,0,\"f32.mul\",[\"f32:1482907561\",\"f32:1482907561\"]],[\"invoke\",275,0,\"f32.mul\",[\"f32:1621981420\",\"f32:1621981420\"]],[\"invoke\",276,0,\"f32.mul\",[\"f32:1761892689\",\"f32:1761892689\"]],[\"invoke\",277,0,\"f64.mul\",[\"f64:4831355200913801216\",\"f64:4831355200913801216\"]],[\"invoke\",278,0,\"f64.mul\",[\"f64:4906019910204099648\",\"f64:4906019910204099648\"]],[\"invoke\",284,0,\"f32.mul\",[\"f32:1323067183\",\"f32:1351920719\"]],[\"invoke\",285,0,\"f64.mul\",[\"f64:4745541551160033280\",\"f64:4761032175258435584\"]],[\"invoke\",289,0,\"f32.mul\",[\"f32:1117401907\",\"f32:1146388480\"]],[\"invoke\",290,0,\"f64.mul\",[\"f64:4635125847112967782\",\"f64:4650687894887858176\"]],[\"invoke\",293,0,\"f32.mul\",[\"f32:3725225879\",\"f32:767181884\"]],[\"invoke\",294,0,\"f32.mul\",[\"f32:4071298289\",\"f32:2363594761\"]],[\"invoke\",295,0,\"f32.mul\",[\"f32:3990403914\",\"f32:2406636213\"]],[\"invoke\",296,0,\"f32.mul\",[\"f32:3876262739\",\"f32:2590162616\"]],[\"invoke\",298,0,\"f64.mul\",[\"f64:15745248579468343268\",\"f64:8867411559652116184\"]],[\"invoke\",299,0,\"f64.mul\",[\"f64:9393595877903301723\",\"f64:12847704090045979814\"]],[\"invoke\",300,0,\"f64.mul\",[\"f64:7339743909496900438\",\"f64:14312273837817528234\"]],[\"invoke\",301,0,\"f64.mul\",[\"f64:12422633289194844785\",\"f64:7233496047441461849\"]],[\"invoke\",302,0,\"f64.mul\",[\"f64:8188526721198436258\",\"f64:745378815681991665\"]],[\"invoke\",305,0,\"f32.mul\",[\"f32:2468326353\",\"f32:3984723636\"]],[\"invoke\",306,0,\"f32.mul\",[\"f32:1680245441\",\"f32:1228341789\"]],[\"invoke\",308,0,\"f32.mul\",[\"f32:1631446143\",\"f32:3340593865\"]],[\"invoke\",309,0,\"f32.mul\",[\"f32:1321841569\",\"f32:3771977928\"]],[\"invoke\",310,0,\"f64.mul\",[\"f64:10956034376207055635\",\"f64:3195464683520095288\"]],[\"invoke\",311,0,\"f64.mul\",[\"f64:3366372084365197849\",\"f64:10971437597834234015\"]],[\"invoke\",312,0,\"f64.mul\",[\"f64:15316253934569525376\",\"f64:17593766689751523793\"]],[\"invoke\",313,0,\"f64.mul\",[\"f64:8873430008942894499\",\"f64:2630310872370005737\"]],[\"invoke\",314,0,\"f64.mul\",[\"f64:6138390736122864607\",\"f64:14591737303103877464\"]],[\"invoke\",318,0,\"f32.mul\",[\"f32:3192278970\",\"f32:242309673\"]],[\"invoke\",319,0,\"f32.mul\",[\"f32:3060150317\",\"f32:1953896717\"]],[\"invoke\",320,0,\"f32.mul\",[\"f32:3685735869\",\"f32:265571119\"]],[\"invoke\",321,0,\"f32.mul\",[\"f32:3355295625\",\"f32:69023757\"]],[\"invoke\",322,0,\"f64.mul\",[\"f64:11598370094301102699\",\"f64:15783697741936198553\"]],[\"invoke\",323,0,\"f64.mul\",[\"f64:6760137556672200005\",\"f64:10390971429121674926\"]],[\"invoke\",324,0,\"f64.mul\",[\"f64:14608361260346079328\",\"f64:6227029768418337647\"]],[\"invoke\",325,0,\"f64.mul\",[\"f64:8069908676175581646\",\"f64:15517844864458283108\"]],[\"invoke\",329,0,\"f64.mul\",[\"f64:3075846375446710711\",\"f64:2019524319895558702\"]],[\"invoke\",330,0,\"f64.mul\",[\"f64:13792389967993824121\",\"f64:7865224186729676301\"]],[\"invoke\",331,0,\"f64.mul\",[\"f64:15483491341737357200\",\"f64:10898188329492193507\"]],[\"invoke\",332,0,\"f64.mul\",[\"f64:8100886621587996114\",\"f64:4881220253517731398\"]],[\"invoke\",333,0,\"f64.mul\",[\"f64:12589892576446671178\",\"f64:8646729507413822745\"]],[\"invoke\",336,0,\"f64.mul\",[\"f64:1913383041739811140\",\"f64:2696786534754768330\"]],[\"invoke\",337,0,\"f64.mul\",[\"f64:13576886274997223712\",\"f64:9480836654241272360\"]],[\"invoke\",339,0,\"f64.mul\",[\"f64:10357270161024523488\",\"f64:3460198093814186274\"]],[\"invoke\",340,0,\"f64.mul\",[\"f64:11506848031881565957\",\"f64:11547514064126512393\"]],[\"invoke\",343,0,\"f64.mul\",[\"f64:8446730755803745435\",\"f64:640105622936255012\"]],[\"invoke\",344,0,\"f64.mul\",[\"f64:4578331547514318947\",\"f64:3937894457345907544\"]],[\"invoke\",345,0,\"f64.mul\",[\"f64:13839181621982597923\",\"f64:4426983905639375259\"]],[\"invoke\",346,0,\"f64.mul\",[\"f64:2931365221683549507\",\"f64:3687257801017498184\"]],[\"invoke\",347,0,\"f64.mul\",[\"f64:14180592859625794472\",\"f64:3043918530412552819\"]],[\"invoke\",350,0,\"f32.mul\",[\"f32:436207616\",\"f32:436207616\"]],[\"invoke\",352,0,\"f64.mul\",[\"f64:2186111271319845836\",\"f64:2186111271319845836\"]],[\"invoke\",353,0,\"f64.mul\",[\"f64:2186111271319845837\",\"f64:2186111271319845837\"]],[\"invoke\",356,0,\"f32.mul\",[\"f32:1602224127\",\"f32:1602224127\"]],[\"invoke\",357,0,\"f32.mul\",[\"f32:1602224128\",\"f32:1602224128\"]],[\"invoke\",358,0,\"f64.mul\",[\"f64:6913025428013711359\",\"f64:6913025428013711359\"]],[\"invoke\",359,0,\"f64.mul\",[\"f64:6913025428013711360\",\"f64:6913025428013711360\"]],[\"invoke\",362,0,\"f32.mul\",[\"f32:1065353217\",\"f32:1065353217\"]],[\"invoke\",364,0,\"f64.mul\",[\"f64:4607182418800017409\",\"f64:4607182418800017409\"]],[\"invoke\",365,0,\"f64.mul\",[\"f64:4607182418800017407\",\"f64:4607182418800017407\"]],[\"invoke\",368,0,\"f32.mul\",[\"f32:1065353217\",\"f32:1065353215\"]],[\"invoke\",369,0,\"f32.mul\",[\"f32:1065353218\",\"f32:1065353214\"]],[\"invoke\",370,0,\"f64.mul\",[\"f64:4607182418800017409\",\"f64:4607182418800017407\"]],[\"invoke\",371,0,\"f64.mul\",[\"f64:4607182418800017410\",\"f64:4607182418800017406\"]],[\"invoke\",375,0,\"f32.mul\",[\"f32:8388608\",\"f32:872415232\"]],[\"invoke\",376,0,\"f64.mul\",[\"f64:4503599627370496\",\"f64:4372995238176751616\"]],[\"invoke\",382,0,\"f32.div\",[\"f32:1066388847\",\"f32:1120403456\"]],[\"invoke\",383,0,\"f32.div\",[\"f32:1258294259\",\"f32:1262485497\"]],[\"invoke\",384,0,\"f32.div\",[\"f32:1199570944\",\"f32:754974720\"]],[\"invoke\",385,0,\"f32.div\",[\"f32:1072586677\",\"f32:2139095039\"]],[\"invoke\",386,0,\"f32.div\",[\"f32:1082130432\",\"f32:1077936128\"]],[\"invoke\",387,0,\"f64.div\",[\"f64:4607738418748954166\",\"f64:4636737291354636288\"]],[\"invoke\",388,0,\"f64.div\",[\"f64:4710766852517658624\",\"f64:4713017006285127680\"]],[\"invoke\",390,0,\"f64.div\",[\"f64:4611065853604003840\",\"f64:9218868437227405311\"]],[\"invoke\",391,0,\"f64.div\",[\"f64:4616189618054758400\",\"f64:4613937818241073152\"]],[\"invoke\",395,0,\"f32.div\",[\"f32:1249905654\",\"f32:1245708284\"]],[\"invoke\",396,0,\"f64.div\",[\"f64:4706263254500900864\",\"f64:4704009808640999424\"]],[\"invoke\",399,0,\"f32.div\",[\"f32:666187309\",\"f32:2138899896\"]],[\"invoke\",400,0,\"f32.div\",[\"f32:338737113\",\"f32:1637454009\"]],[\"invoke\",401,0,\"f32.div\",[\"f32:3351999420\",\"f32:401966635\"]],[\"invoke\",403,0,\"f32.div\",[\"f32:3564182439\",\"f32:397999726\"]],[\"invoke\",404,0,\"f64.div\",[\"f64:5269602717919885505\",\"f64:5615431061534361830\"]],[\"invoke\",405,0,\"f64.div\",[\"f64:1791703022234099881\",\"f64:230587289790163684\"]],[\"invoke\",406,0,\"f64.div\",[\"f64:15176390632865983384\",\"f64:7489729865403831125\"]],[\"invoke\",407,0,\"f64.div\",[\"f64:16945752639368638170\",\"f64:5718505335991307775\"]],[\"invoke\",408,0,\"f64.div\",[\"f64:16263708435887736913\",\"f64:6648866667391375614\"]],[\"invoke\",411,0,\"f32.div\",[\"f32:3798033061\",\"f32:2491443361\"]],[\"invoke\",412,0,\"f32.div\",[\"f32:686927199\",\"f32:1440960248\"]],[\"invoke\",414,0,\"f32.div\",[\"f32:642177221\",\"f32:2685135\"]],[\"invoke\",415,0,\"f32.div\",[\"f32:1824271560\",\"f32:1797890210\"]],[\"invoke\",416,0,\"f64.div\",[\"f64:4278321332874065\",\"f64:15464375907975098426\"]],[\"invoke\",417,0,\"f64.div\",[\"f64:9385779280320516508\",\"f64:2195352144435258723\"]],[\"invoke\",418,0,\"f64.div\",[\"f64:12019785500442997560\",\"f64:14033717547286793792\"]],[\"invoke\",419,0,\"f64.div\",[\"f64:14192622858179995755\",\"f64:1048270709368415171\"]],[\"invoke\",420,0,\"f64.div\",[\"f64:14895971708944847415\",\"f64:14082502105592202184\"]],[\"invoke\",424,0,\"f32.div\",[\"f32:3861505243\",\"f32:1298875600\"]],[\"invoke\",425,0,\"f32.div\",[\"f32:1387472197\",\"f32:4021087697\"]],[\"invoke\",426,0,\"f32.div\",[\"f32:4149014653\",\"f32:3294714580\"]],[\"invoke\",427,0,\"f32.div\",[\"f32:3987554477\",\"f32:3327836421\"]],[\"invoke\",428,0,\"f64.div\",[\"f64:10882983485852580843\",\"f64:1499380901194126188\"]],[\"invoke\",429,0,\"f64.div\",[\"f64:17353632673902705731\",\"f64:11343375610449883809\"]],[\"invoke\",430,0,\"f64.div\",[\"f64:10471640091267549911\",\"f64:4317563730789156718\"]],[\"invoke\",431,0,\"f64.div\",[\"f64:15262578458239868670\",\"f64:11184694400998603321\"]],[\"invoke\",435,0,\"f64.div\",[\"f64:16467910284400317286\",\"f64:14710955777971283471\"]],[\"invoke\",436,0,\"f64.div\",[\"f64:16290965053652735591\",\"f64:15317706837775392625\"]],[\"invoke\",437,0,\"f64.div\",[\"f64:5440366292977110369\",\"f64:18177315027663270891\"]],[\"invoke\",438,0,\"f64.div\",[\"f64:5586144947709395659\",\"f64:6532436425888624877\"]],[\"invoke\",439,0,\"f64.div\",[\"f64:17550005606375580620\",\"f64:6180045224129992598\"]],[\"invoke\",442,0,\"f64.div\",[\"f64:4611065853588275309\",\"f64:9218868437227405311\"]],[\"invoke\",443,0,\"f64.div\",[\"f64:58005932411648970\",\"f64:4662638783615926141\"]],[\"invoke\",445,0,\"f64.div\",[\"f64:12062544014359965409\",\"f64:16674780236028867992\"]],[\"invoke\",446,0,\"f64.div\",[\"f64:752499975442349235\",\"f64:5356690663768240614\"]],[\"invoke\",447,0,\"f64.div\",[\"f64:83041154348962762\",\"f64:13934889252531101931\"]],[\"invoke\",450,0,\"f32.div\",[\"f32:1817629909\",\"f32:1421132838\"]],[\"invoke\",451,0,\"f32.div\",[\"f32:1824604388\",\"f32:4105258014\"]],[\"invoke\",452,0,\"f32.div\",[\"f32:1747858929\",\"f32:1063784191\"]],[\"invoke\",453,0,\"f32.div\",[\"f32:3378374953\",\"f32:3497907368\"]],[\"invoke\",455,0,\"f64.div\",[\"f64:4885037015672297625\",\"f64:9954263091431620051\"]],[\"invoke\",456,0,\"f64.div\",[\"f64:4022347395424227722\",\"f64:11486191764643320419\"]],[\"invoke\",457,0,\"f64.div\",[\"f64:7623973190248181230\",\"f64:7481900282945497881\"]],[\"invoke\",458,0,\"f64.div\",[\"f64:14650287530633645126\",\"f64:8091500841285620267\"]],[\"invoke\",459,0,\"f64.div\",[\"f64:9910334119372230161\",\"f64:10921408834055405722\"]],[\"invoke\",462,0,\"f64.div\",[\"f64:4352764235752579571\",\"f64:4610853254537913145\"]],[\"invoke\",463,0,\"f64.div\",[\"f64:4148344307949876337\",\"f64:13642564096968604240\"]],[\"invoke\",464,0,\"f64.div\",[\"f64:4425554483259831683\",\"f64:4103199251532205583\"]],[\"invoke\",466,0,\"f64.div\",[\"f64:4558988817252519457\",\"f64:14066629987516208597\"]],[\"invoke\",469,0,\"f32.div\",[\"f32:8388608\",\"f32:8388607\"]],[\"invoke\",470,0,\"f32.div\",[\"f32:8388607\",\"f32:8388608\"]],[\"invoke\",471,0,\"f64.div\",[\"f64:4503599627370496\",\"f64:4503599627370495\"]],[\"invoke\",472,0,\"f64.div\",[\"f64:4503599627370495\",\"f64:4503599627370496\"]],[\"invoke\",475,0,\"f32.div\",[\"f32:880803839\",\"f32:2139095039\"]],[\"invoke\",476,0,\"f32.div\",[\"f32:880803840\",\"f32:2139095039\"]],[\"invoke\",478,0,\"f64.div\",[\"f64:4377498837804122112\",\"f64:9218868437227405311\"]],[\"invoke\",481,0,\"f32.div\",[\"f32:1065353216\",\"f32:2097152\"]],[\"invoke\",482,0,\"f32.div\",[\"f32:1065353216\",\"f32:2097153\"]],[\"invoke\",483,0,\"f64.div\",[\"f64:4607182418800017408\",\"f64:1125899906842624\"]],[\"invoke\",484,0,\"f64.div\",[\"f64:4607182418800017408\",\"f64:1125899906842625\"]],[\"invoke\",487,0,\"f32.div\",[\"f32:1065353216\",\"f32:2122317825\"]],[\"invoke\",488,0,\"f32.div\",[\"f32:1065353216\",\"f32:2122317824\"]],[\"invoke\",489,0,\"f64.div\",[\"f64:4607182418800017408\",\"f64:9209861237972664321\"]],[\"invoke\",500,0,\"f32.div\",[\"f32:1065353216\",\"f32:1077936128\"]],[\"invoke\",501,0,\"f32.div\",[\"f32:1077936128\",\"f32:1091567616\"]],[\"invoke\",502,0,\"f32.div\",[\"f32:1091567616\",\"f32:1104674816\"]],[\"invoke\",503,0,\"f64.div\",[\"f64:4607182418800017408\",\"f64:4613937818241073152\"]],[\"invoke\",504,0,\"f64.div\",[\"f64:4613937818241073152\",\"f64:4621256167635550208\"]],[\"invoke\",505,0,\"f64.div\",[\"f64:4621256167635550208\",\"f64:4628293042053316608\"]],[\"invoke\",508,0,\"f32.div\",[\"f32:1065353217\",\"f32:1065353215\"]],[\"invoke\",510,0,\"f32.div\",[\"f32:1065353216\",\"f32:1065353215\"]],[\"invoke\",511,0,\"f32.div\",[\"f32:1065353216\",\"f32:1065353217\"]],[\"invoke\",512,0,\"f64.div\",[\"f64:4607182418800017409\",\"f64:4607182418800017407\"]],[\"invoke\",513,0,\"f64.div\",[\"f64:4607182418800017407\",\"f64:4607182418800017409\"]],[\"invoke\",514,0,\"f64.div\",[\"f64:4607182418800017408\",\"f64:4607182418800017407\"]],[\"invoke\",515,0,\"f64.div\",[\"f64:4607182418800017408\",\"f64:4607182418800017409\"]],[\"invoke\",519,0,\"f32.sqrt\",[\"f32:1126891520\"]],[\"invoke\",521,0,\"f64.sqrt\",[\"f64:4640220544191430656\"]],[\"invoke\",522,0,\"f64.sqrt\",[\"f64:4505170691092029701\"]],[\"invoke\",525,0,\"f64.sqrt\",[\"f64:3868634135368364633\"]],[\"invoke\",526,0,\"f64.sqrt\",[\"f64:6130334638238385213\"]],[\"invoke\",527,0,\"f64.sqrt\",[\"f64:6420749722515481850\"]],[\"invoke\",528,0,\"f64.sqrt\",[\"f64:4441983858611369811\"]],[\"invoke\",529,0,\"f64.sqrt\",[\"f64:2943222801950574478\"]],[\"invoke\",533,0,\"f64.sqrt\",[\"f64:4607182418800017407\"]],[\"invoke\",537,0,\"f32.sqrt\",[\"f32:1911349112\"]],[\"invoke\",538,0,\"f32.sqrt\",[\"f32:1033984731\"]],[\"invoke\",539,0,\"f32.sqrt\",[\"f32:471548520\"]],[\"invoke\",540,0,\"f32.sqrt\",[\"f32:980180519\"]],[\"invoke\",541,0,\"f64.sqrt\",[\"f64:447478826231748356\"]],[\"invoke\",542,0,\"f64.sqrt\",[\"f64:7882765141420635228\"]],[\"invoke\",543,0,\"f64.sqrt\",[\"f64:6345006020483303032\"]],[\"invoke\",545,0,\"f64.sqrt\",[\"f64:9108179429173493573\"]],[\"invoke\",548,0,\"f32.sqrt\",[\"f32:1293112087\"]],[\"invoke\",549,0,\"f32.sqrt\",[\"f32:118173697\"]],[\"invoke\",550,0,\"f32.sqrt\",[\"f32:941555112\"]],[\"invoke\",551,0,\"f32.sqrt\",[\"f32:60323222\"]],[\"invoke\",552,0,\"f32.sqrt\",[\"f32:40220718\"]],[\"invoke\",553,0,\"f64.sqrt\",[\"f64:7741365502393472048\"]],[\"invoke\",554,0,\"f64.sqrt\",[\"f64:1175297548666390979\"]],[\"invoke\",556,0,\"f64.sqrt\",[\"f64:3521792205891300764\"]],[\"invoke\",557,0,\"f64.sqrt\",[\"f64:8798159938601760820\"]],[\"invoke\",560,0,\"f32.sqrt\",[\"f32:2058533950\"]],[\"invoke\",561,0,\"f32.sqrt\",[\"f32:1194962978\"]],[\"invoke\",562,0,\"f32.sqrt\",[\"f32:1062209384\"]],[\"invoke\",563,0,\"f32.sqrt\",[\"f32:339551808\"]],[\"invoke\",564,0,\"f32.sqrt\",[\"f32:279876202\"]],[\"invoke\",566,0,\"f64.sqrt\",[\"f64:2893298197477532149\"]],[\"invoke\",567,0,\"f64.sqrt\",[\"f64:8954101765007123282\"]],[\"invoke\",568,0,\"f64.sqrt\",[\"f64:4405641787023763989\"]],[\"invoke\",569,0,\"f64.sqrt\",[\"f64:2394824404681191749\"]],[\"invoke\",572,0,\"f64.sqrt\",[\"f64:9494538992465685200\"]],[\"invoke\",573,0,\"f64.sqrt\",[\"f64:5074882158241187075\"]],[\"invoke\",574,0,\"f64.sqrt\",[\"f64:1187437724299488295\"]],[\"invoke\",576,0,\"f64.sqrt\",[\"f64:7161993531047854177\"]],[\"invoke\",579,0,\"f32.sqrt\",[\"f32:1065353217\"]],[\"invoke\",580,0,\"f32.sqrt\",[\"f32:1065353218\"]],[\"invoke\",581,0,\"f64.sqrt\",[\"f64:4607182418800017409\"]],[\"invoke\",582,0,\"f64.sqrt\",[\"f64:4607182418800017410\"]],[\"invoke\",585,0,\"f32.sqrt\",[\"f32:1065353214\"]],[\"invoke\",586,0,\"f32.sqrt\",[\"f32:1065353213\"]],[\"invoke\",587,0,\"f64.sqrt\",[\"f64:4607182418800017406\"]],[\"invoke\",591,0,\"f32.sqrt\",[\"f32:1048575999\"]],[\"invoke\",592,0,\"f32.sqrt\",[\"f32:1048576000\"]],[\"invoke\",593,0,\"f32.sqrt\",[\"f32:1048576001\"]],[\"invoke\",594,0,\"f32.sqrt\",[\"f32:1048576002\"]],[\"invoke\",595,0,\"f64.sqrt\",[\"f64:4598175219545276415\"]],[\"invoke\",596,0,\"f64.sqrt\",[\"f64:4598175219545276416\"]],[\"invoke\",597,0,\"f64.sqrt\",[\"f64:4598175219545276417\"]],[\"invoke\",602,0,\"f32.sqrt\",[\"f32:1383964906\"]],[\"invoke\",603,0,\"f64.sqrt\",[\"f64:4778235767454362395\"]],[\"invoke\",607,0,\"f32.sqrt\",[\"f32:1344155865\"]],[\"invoke\",608,0,\"f32.sqrt\",[\"f32:1496014503\"]],[\"invoke\",609,0,\"f32.sqrt\",[\"f32:1437792278\"]],[\"invoke\",610,0,\"f32.sqrt\",[\"f32:1318267910\"]],[\"invoke\",611,0,\"f64.sqrt\",[\"f64:4756863450987102208\"]],[\"invoke\",612,0,\"f64.sqrt\",[\"f64:4838391936821527880\"]],[\"invoke\",614,0,\"f64.sqrt\",[\"f64:4742964961037254656\"]],[\"invoke\",618,0,\"f32.sqrt\",[\"f32:1057229822\"]],[\"invoke\",619,0,\"f32.sqrt\",[\"f32:1057013196\"]],[\"invoke\",620,0,\"f64.sqrt\",[\"f64:4602821204854702080\"]],[\"invoke\",621,0,\"f64.sqrt\",[\"f64:4602704904656519168\"]],[\"invoke\",625,0,\"f32.sqrt\",[\"f32:1091567616\"]],[\"invoke\",626,0,\"f32.sqrt\",[\"f32:1124663296\"]],[\"invoke\",628,0,\"f32.sqrt\",[\"f32:1148846080\"]],[\"invoke\",629,0,\"f64.sqrt\",[\"f64:4621256167635550208\"]],[\"invoke\",630,0,\"f64.sqrt\",[\"f64:4639024275540410368\"]],[\"invoke\",631,0,\"f64.sqrt\",[\"f64:4610667174614947795\"]],[\"invoke\",632,0,\"f64.sqrt\",[\"f64:4652007308841189376\"]],[\"invoke\",656,0,\"f32.ceil\",[\"f32:1065353215\"]],[\"invoke\",657,0,\"f32.ceil\",[\"f32:1065353217\"]],[\"invoke\",659,0,\"f64.ceil\",[\"f64:4607182418800017409\"]],[\"invoke\",662,0,\"f32.ceil\",[\"f32:1258291199\"]],[\"invoke\",663,0,\"f32.ceil\",[\"f32:3405774847\"]],[\"invoke\",664,0,\"f64.ceil\",[\"f64:4841369599423283199\"]],[\"invoke\",665,0,\"f64.ceil\",[\"f64:14064741636278059007\"]],[\"invoke\",669,0,\"f32.ceil\",[\"f32:1266679807\"]],[\"invoke\",670,0,\"f32.ceil\",[\"f32:3414163455\"]],[\"invoke\",671,0,\"f64.ceil\",[\"f64:4845873199050653695\"]],[\"invoke\",675,0,\"f32.floor\",[\"f32:3212836863\"]],[\"invoke\",676,0,\"f32.floor\",[\"f32:3212836865\"]],[\"invoke\",677,0,\"f64.floor\",[\"f64:13830554455654793215\"]],[\"invoke\",678,0,\"f64.floor\",[\"f64:13830554455654793217\"]],[\"invoke\",681,0,\"f32.floor\",[\"f32:3405774847\"]],[\"invoke\",682,0,\"f32.floor\",[\"f32:1258291199\"]],[\"invoke\",683,0,\"f64.floor\",[\"f64:14064741636278059007\"]],[\"invoke\",688,0,\"f32.floor\",[\"f32:1202524032\"]],[\"invoke\",689,0,\"f64.floor\",[\"f64:4680825439885721600\"]],[\"invoke\",692,0,\"f32.trunc\",[\"f32:3405774847\"]],[\"invoke\",693,0,\"f32.trunc\",[\"f32:1258291199\"]],[\"invoke\",694,0,\"f64.trunc\",[\"f64:14064741636278059007\"]],[\"invoke\",695,0,\"f64.trunc\",[\"f64:4841369599423283199\"]],[\"invoke\",700,0,\"f32.nearest\",[\"f32:1258291201\"]],[\"invoke\",701,0,\"f32.nearest\",[\"f32:1258291202\"]],[\"invoke\",703,0,\"f32.nearest\",[\"f32:1468006399\"]],[\"invoke\",704,0,\"f64.nearest\",[\"f64:4841369599423283201\"]],[\"invoke\",705,0,\"f64.nearest\",[\"f64:4841369599423283202\"]],[\"invoke\",706,0,\"f64.nearest\",[\"f64:4602678819172646911\"]],[\"invoke\",707,0,\"f64.nearest\",[\"f64:5084563979301289983\"]],[\"invoke\",711,0,\"f32.nearest\",[\"f32:1083179008\"]],[\"invoke\",712,0,\"f32.nearest\",[\"f32:3230662656\"]],[\"invoke\",714,0,\"f64.nearest\",[\"f64:4616752568008179712\"]],[\"invoke\",715,0,\"f64.nearest\",[\"f64:13840124604862955520\"]],[\"invoke\",716,0,\"f64.nearest\",[\"f64:13838435755002691584\"]],[\"invoke\",719,0,\"f32.nearest\",[\"f32:3405774847\"]],[\"invoke\",720,0,\"f32.nearest\",[\"f32:1258291199\"]],[\"invoke\",721,0,\"f64.nearest\",[\"f64:14064741636278059007\"]],[\"invoke\",722,0,\"f64.nearest\",[\"f64:4841369599423283199\"]]]"; diff --git a/tests/corpus/webassembly-spec-float/main.mjs b/tests/corpus/webassembly-spec-float/main.mjs new file mode 100644 index 000000000..289dad212 --- /dev/null +++ b/tests/corpus/webassembly-spec-float/main.mjs @@ -0,0 +1,5 @@ +// Executes WebAssembly spec tests (9 files); see tests/wasm-spec/runner.mjs. +import { run } from "../../wasm-spec/runner.mjs"; +import { modules, script } from "./data.mjs"; + +run(modules, script); diff --git a/tests/corpus/webassembly-spec-int/data.mjs b/tests/corpus/webassembly-spec-int/data.mjs new file mode 100644 index 000000000..08a72be2f --- /dev/null +++ b/tests/corpus/webassembly-spec-int/data.mjs @@ -0,0 +1,33 @@ +/* Generated by tests/wasm-spec/gen.mjs from the WebAssembly 2.0 core test + * suite (WebAssembly/spec wg-2.0, Apache-2.0) with wabt 1.0.37 wast2json: + * i32.wast, i64.wast, int_exprs.wast, int_literals.wast, conversions.wast, traps.wast. Do not edit. */ +export const modules = [ + "AGFzbQEAAAABDAJgAn9/AX9gAX8BfwMgHwAAAAAAAAAAAAAAAAAAAAEBAQEBAQAAAAAAAAAAAAAH3gEfA2FkZAAAA3N1YgABA211bAACBWRpdl9zAAMFZGl2X3UABAVyZW1fcwAFBXJlbV91AAYDYW5kAAcCb3IACAN4b3IACQNzaGwACgVzaHJfcwALBXNocl91AAwEcm90bAANBHJvdHIADgNjbHoADwNjdHoAEAZwb3BjbnQAEQlleHRlbmQ4X3MAEgpleHRlbmQxNl9zABMDZXF6ABQCZXEAFQJuZQAWBGx0X3MAFwRsdF91ABgEbGVfcwAZBGxlX3UAGgRndF9zABsEZ3RfdQAcBGdlX3MAHQRnZV91AB4K7QEfBwAgACABagsHACAAIAFrCwcAIAAgAWwLBwAgACABbQsHACAAIAFuCwcAIAAgAW8LBwAgACABcAsHACAAIAFxCwcAIAAgAXILBwAgACABcwsHACAAIAF0CwcAIAAgAXULBwAgACABdgsHACAAIAF3CwcAIAAgAXgLBQAgAGcLBQAgAGgLBQAgAGkLBQAgAMALBQAgAMELBQAgAEULBwAgACABRgsHACAAIAFHCwcAIAAgAUgLBwAgACABSQsHACAAIAFMCwcAIAAgAU0LBwAgACABSgsHACAAIAFLCwcAIAAgAU4LBwAgACABTws=", + "AGFzbQEAAAABFwRgAn5+AX5gAX4BfmABfgF/YAJ+fgF/AyEgAAAAAAAAAAAAAAAAAAAAAQEBAQEBAgMDAwMDAwMDAwMH6wEgA2FkZAAAA3N1YgABA211bAACBWRpdl9zAAMFZGl2X3UABAVyZW1fcwAFBXJlbV91AAYDYW5kAAcCb3IACAN4b3IACQNzaGwACgVzaHJfcwALBXNocl91AAwEcm90bAANBHJvdHIADgNjbHoADwNjdHoAEAZwb3BjbnQAEQlleHRlbmQ4X3MAEgpleHRlbmQxNl9zABMKZXh0ZW5kMzJfcwAUA2VxegAVAmVxABYCbmUAFwRsdF9zABgEbHRfdQAZBGxlX3MAGgRsZV91ABsEZ3RfcwAcBGd0X3UAHQRnZV9zAB4EZ2VfdQAfCvMBIAcAIAAgAXwLBwAgACABfQsHACAAIAF+CwcAIAAgAX8LBwAgACABgAsHACAAIAGBCwcAIAAgAYILBwAgACABgwsHACAAIAGECwcAIAAgAYULBwAgACABhgsHACAAIAGHCwcAIAAgAYgLBwAgACABiQsHACAAIAGKCwUAIAB5CwUAIAB6CwUAIAB7CwUAIADCCwUAIADDCwUAIADECwUAIABQCwcAIAAgAVELBwAgACABUgsHACAAIAFTCwcAIAAgAVQLBwAgACABVwsHACAAIAFYCwcAIAAgAVULBwAgACABVgsHACAAIAFZCwcAIAAgAVoL", + "AGFzbQEAAAABDQJgAn9/AX9gAn5+AX8DBQQAAAEBB20EGGkzMi5ub19mb2xkX2NtcF9zX29mZnNldAAAGGkzMi5ub19mb2xkX2NtcF91X29mZnNldAABGGk2NC5ub19mb2xkX2NtcF9zX29mZnNldAACGGk2NC5ub19mb2xkX2NtcF91X29mZnNldAADCjkEDQAgAEEBaiABQQFqSAsNACAAQQFqIAFBAWpJCw0AIABCAXwgAUIBfFMLDQAgAEIBfCABQgF8VAs=", + "AGFzbQEAAAABBgFgAX4BfgMCAQAHHQEZaTY0Lm5vX2ZvbGRfd3JhcF9leHRlbmRfcwAACggBBgAgAKesCw==", + "AGFzbQEAAAABBgFgAX4BfgMCAQAHHQEZaTY0Lm5vX2ZvbGRfd3JhcF9leHRlbmRfdQAACggBBgAgAKetCw==", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQdhBBVpMzIubm9fZm9sZF9zaGxfc2hyX3MAABVpMzIubm9fZm9sZF9zaGxfc2hyX3UAARVpNjQubm9fZm9sZF9zaGxfc2hyX3MAAhVpNjQubm9fZm9sZF9zaGxfc2hyX3UAAwotBAoAIABBAXRBAXULCgAgAEEBdEEBdgsKACAAQgGGQgGHCwoAIABCAYZCAYgL", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQdhBBVpMzIubm9fZm9sZF9zaHJfc19zaGwAABVpMzIubm9fZm9sZF9zaHJfdV9zaGwAARVpNjQubm9fZm9sZF9zaHJfc19zaGwAAhVpNjQubm9fZm9sZF9zaHJfdV9zaGwAAwotBAoAIABBAXVBAXQLCgAgAEEBdkEBdAsKACAAQgGHQgGGCwoAIABCAYhCAYYL", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQdhBBVpMzIubm9fZm9sZF9kaXZfc19tdWwAABVpMzIubm9fZm9sZF9kaXZfdV9tdWwAARVpNjQubm9fZm9sZF9kaXZfc19tdWwAAhVpNjQubm9fZm9sZF9kaXZfdV9tdWwAAwotBAoAIABBBm1BBmwLCgAgAEEGbkEGbAsKACAAQgZ/QgZ+CwoAIABCBoBCBn4L", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQdlBBZpMzIubm9fZm9sZF9kaXZfc19zZWxmAAAWaTMyLm5vX2ZvbGRfZGl2X3Vfc2VsZgABFmk2NC5ub19mb2xkX2Rpdl9zX3NlbGYAAhZpNjQubm9fZm9sZF9kaXZfdV9zZWxmAAMKIQQHACAAIABtCwcAIAAgAG4LBwAgACAAfwsHACAAIACACw==", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQdlBBZpMzIubm9fZm9sZF9yZW1fc19zZWxmAAAWaTMyLm5vX2ZvbGRfcmVtX3Vfc2VsZgABFmk2NC5ub19mb2xkX3JlbV9zX3NlbGYAAhZpNjQubm9fZm9sZF9yZW1fdV9zZWxmAAMKIQQHACAAIABvCwcAIAAgAHALBwAgACAAgQsHACAAIACCCw==", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQdhBBVpMzIubm9fZm9sZF9tdWxfZGl2X3MAABVpMzIubm9fZm9sZF9tdWxfZGl2X3UAARVpNjQubm9fZm9sZF9tdWxfZGl2X3MAAhVpNjQubm9fZm9sZF9tdWxfZGl2X3UAAwotBAoAIABBBmxBBm0LCgAgAEEGbEEGbgsKACAAQgZ+QgZ/CwoAIABCBn5CBoAL", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwMCAAEHLQITaTMyLm5vX2ZvbGRfZGl2X3NfMgAAE2k2NC5ub19mb2xkX2Rpdl9zXzIAAQoRAgcAIABBAm0LBwAgAEICfws=", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwMCAAEHLQITaTMyLm5vX2ZvbGRfcmVtX3NfMgAAE2k2NC5ub19mb2xkX3JlbV9zXzIAAQoRAgcAIABBAm8LBwAgAEICgQs=", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQc5BAtpMzIuZGl2X3NfMAAAC2kzMi5kaXZfdV8wAAELaTY0LmRpdl9zXzAAAgtpNjQuZGl2X3VfMAADCiEEBwAgAEEAbQsHACAAQQBuCwcAIABCAH8LBwAgAEIAgAs=", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQc5BAtpMzIuZGl2X3NfMwAAC2kzMi5kaXZfdV8zAAELaTY0LmRpdl9zXzMAAgtpNjQuZGl2X3VfMwADCiEEBwAgAEEDbQsHACAAQQNuCwcAIABCA38LBwAgAEIDgAs=", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQc5BAtpMzIuZGl2X3NfNQAAC2kzMi5kaXZfdV81AAELaTY0LmRpdl9zXzUAAgtpNjQuZGl2X3VfNQADCiEEBwAgAEEFbQsHACAAQQVuCwcAIABCBX8LBwAgAEIFgAs=", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQc5BAtpMzIuZGl2X3NfNwAAC2kzMi5kaXZfdV83AAELaTY0LmRpdl9zXzcAAgtpNjQuZGl2X3VfNwADCiEEBwAgAEEHbQsHACAAQQduCwcAIABCB38LBwAgAEIHgAs=", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQc5BAtpMzIucmVtX3NfMwAAC2kzMi5yZW1fdV8zAAELaTY0LnJlbV9zXzMAAgtpNjQucmVtX3VfMwADCiEEBwAgAEEDbwsHACAAQQNwCwcAIABCA4ELBwAgAEIDggs=", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQc5BAtpMzIucmVtX3NfNQAAC2kzMi5yZW1fdV81AAELaTY0LnJlbV9zXzUAAgtpNjQucmVtX3VfNQADCiEEBwAgAEEFbwsHACAAQQVwCwcAIABCBYELBwAgAEIFggs=", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwUEAAABAQc5BAtpMzIucmVtX3NfNwAAC2kzMi5yZW1fdV83AAELaTY0LnJlbV9zXzcAAgtpNjQucmVtX3VfNwADCiEEBwAgAEEHbwsHACAAQQdwCwcAIABCB4ELBwAgAEIHggs=", + "AGFzbQEAAAABCwJgAX8Bf2ABfgF+AwMCAAEHLwIUaTMyLm5vX2ZvbGRfZGl2X25lZzEAABRpNjQubm9fZm9sZF9kaXZfbmVnMQABChECBwAgAEF/bQsHACAAQn9/Cw==", + "AGFzbQEAAAABCQJgAAF/YAABfgMfHgAAAAAAAAAAAAAAAQEBAQEBAQEBAQEAAAAAAQEBAQe3Ax4IaTMyLnRlc3QAAAhpMzIudW1heAABCGkzMi5zbWF4AAIMaTMyLm5lZ19zbWF4AAMIaTMyLnNtaW4ABAxpMzIuYWx0X3NtaW4ABQxpMzIuaW5jX3NtaW4ABgxpMzIubmVnX3plcm8ABw1pMzIubm90X29jdGFsAAgUaTMyLnVuc2lnbmVkX2RlY2ltYWwACQ1pMzIucGx1c19zaWduAAoIaTY0LnRlc3QACwhpNjQudW1heAAMCGk2NC5zbWF4AA0MaTY0Lm5lZ19zbWF4AA4IaTY0LnNtaW4ADwxpNjQuYWx0X3NtaW4AEAxpNjQuaW5jX3NtaW4AEQxpNjQubmVnX3plcm8AEg1pNjQubm90X29jdGFsABMUaTY0LnVuc2lnbmVkX2RlY2ltYWwAFA1pNjQucGx1c19zaWduABUMaTMyLWRlYy1zZXAxABYMaTMyLWRlYy1zZXAyABcMaTMyLWhleC1zZXAxABgMaTMyLWhleC1zZXAyABkMaTY0LWRlYy1zZXAxABoMaTY0LWRlYy1zZXAyABsMaTY0LWhleC1zZXAxABwMaTY0LWhleC1zZXAyAB0KlQIeCQBBjaC33QAPCwUAQX8PCwkAQf////8HDwsJAEGBgICAeA8LCQBBgICAgHgPCwkAQYCAgIB4DwsMAEGAgICAeEEBag8LBQBBAA8LBQBBCg8LBQBBfw8LBQBBKg8LDQBC7tSZ3eDN7tUMDwsFAEJ/DwsOAEL///////////8ADwsOAEKBgICAgICAgIB/DwsOAEKAgICAgICAgIB/DwsOAEKAgICAgICAgIB/DwsRAEKAgICAgICAgIB/QgF8DwsFAEIADwsFAEIKDwsFAEJ/DwsFAEIqDwsGAEHAhD0LBQBB6AcLCABBmYG80AALBgBBj9QGCwYAQsCEPQsFAELoBwsLAEKZs4KA8IG8BQsGAEKP1AYL", + "AGFzbQEAAAABPQxgAX8BfmABfgF/YAF9AX9gAXwBf2ABfQF+YAF8AX5gAX8BfWABfgF9YAF/AXxgAX4BfGABfQF8YAF8AX0DIiEAAAECAgMDBAQFBQICAwMEBAUFBgcICQYHCAkKCwYJAgUHkQUhEGk2NC5leHRlbmRfaTMyX3MAABBpNjQuZXh0ZW5kX2kzMl91AAEMaTMyLndyYXBfaTY0AAIPaTMyLnRydW5jX2YzMl9zAAMPaTMyLnRydW5jX2YzMl91AAQPaTMyLnRydW5jX2Y2NF9zAAUPaTMyLnRydW5jX2Y2NF91AAYPaTY0LnRydW5jX2YzMl9zAAcPaTY0LnRydW5jX2YzMl91AAgPaTY0LnRydW5jX2Y2NF9zAAkPaTY0LnRydW5jX2Y2NF91AAoTaTMyLnRydW5jX3NhdF9mMzJfcwALE2kzMi50cnVuY19zYXRfZjMyX3UADBNpMzIudHJ1bmNfc2F0X2Y2NF9zAA0TaTMyLnRydW5jX3NhdF9mNjRfdQAOE2k2NC50cnVuY19zYXRfZjMyX3MADxNpNjQudHJ1bmNfc2F0X2YzMl91ABATaTY0LnRydW5jX3NhdF9mNjRfcwARE2k2NC50cnVuY19zYXRfZjY0X3UAEhFmMzIuY29udmVydF9pMzJfcwATEWYzMi5jb252ZXJ0X2k2NF9zABQRZjY0LmNvbnZlcnRfaTMyX3MAFRFmNjQuY29udmVydF9pNjRfcwAWEWYzMi5jb252ZXJ0X2kzMl91ABcRZjMyLmNvbnZlcnRfaTY0X3UAGBFmNjQuY29udmVydF9pMzJfdQAZEWY2NC5jb252ZXJ0X2k2NF91ABoPZjY0LnByb21vdGVfZjMyABsOZjMyLmRlbW90ZV9mNjQAHBNmMzIucmVpbnRlcnByZXRfaTMyAB0TZjY0LnJlaW50ZXJwcmV0X2k2NAAeE2kzMi5yZWludGVycHJldF9mMzIAHxNpNjQucmVpbnRlcnByZXRfZjY0ACAKzwEhBQAgAKwLBQAgAK0LBQAgAKcLBQAgAKgLBQAgAKkLBQAgAKoLBQAgAKsLBQAgAK4LBQAgAK8LBQAgALALBQAgALELBgAgAPwACwYAIAD8AQsGACAA/AILBgAgAPwDCwYAIAD8BAsGACAA/AULBgAgAPwGCwYAIAD8BwsFACAAsgsFACAAtAsFACAAtwsFACAAuQsFACAAswsFACAAtQsFACAAuAsFACAAugsFACAAuwsFACAAtgsFACAAvgsFACAAvwsFACAAvAsFACAAvQs=", + "AGFzbQEAAAABCwJgAn9/AGACfn4AAwUEAAABAQdNBBBub19kY2UuaTMyLmRpdl9zAAAQbm9fZGNlLmkzMi5kaXZfdQABEG5vX2RjZS5pNjQuZGl2X3MAAhBub19kY2UuaTY0LmRpdl91AAMKJQQIACAAIAFtGgsIACAAIAFuGgsIACAAIAF/GgsIACAAIAGAGgs=", + "AGFzbQEAAAABCwJgAn9/AGACfn4AAwUEAAABAQdNBBBub19kY2UuaTMyLnJlbV9zAAAQbm9fZGNlLmkzMi5yZW1fdQABEG5vX2RjZS5pNjQucmVtX3MAAhBub19kY2UuaTY0LnJlbV91AAMKJQQIACAAIAFvGgsIACAAIAFwGgsIACAAIAGBGgsIACAAIAGCGgs=", + "AGFzbQEAAAABCQJgAX0AYAF8AAMJCAAAAQEAAAEBB8kBCBZub19kY2UuaTMyLnRydW5jX2YzMl9zAAAWbm9fZGNlLmkzMi50cnVuY19mMzJfdQABFm5vX2RjZS5pMzIudHJ1bmNfZjY0X3MAAhZub19kY2UuaTMyLnRydW5jX2Y2NF91AAMWbm9fZGNlLmk2NC50cnVuY19mMzJfcwAEFm5vX2RjZS5pNjQudHJ1bmNfZjMyX3UABRZub19kY2UuaTY0LnRydW5jX2Y2NF9zAAYWbm9fZGNlLmk2NC50cnVuY19mNjRfdQAHCjkIBgAgAKgaCwYAIACpGgsGACAAqhoLBgAgAKsaCwYAIACuGgsGACAArxoLBgAgALAaCwYAIACxGgs=", + "AGFzbQEAAAABBQFgAX8AAw8OAAAAAAAAAAAAAAAAAAAFAwEAAQehAg4Pbm9fZGNlLmkzMi5sb2FkAAATbm9fZGNlLmkzMi5sb2FkMTZfcwABE25vX2RjZS5pMzIubG9hZDE2X3UAAhJub19kY2UuaTMyLmxvYWQ4X3MAAxJub19kY2UuaTMyLmxvYWQ4X3UABA9ub19kY2UuaTY0LmxvYWQABRNub19kY2UuaTY0LmxvYWQzMl9zAAYTbm9fZGNlLmk2NC5sb2FkMzJfdQAHE25vX2RjZS5pNjQubG9hZDE2X3MACBNub19kY2UuaTY0LmxvYWQxNl91AAkSbm9fZGNlLmk2NC5sb2FkOF9zAAoSbm9fZGNlLmk2NC5sb2FkOF91AAsPbm9fZGNlLmYzMi5sb2FkAAwPbm9fZGNlLmY2NC5sb2FkAA0Kfw4IACAAKAIAGgsIACAALgEAGgsIACAALwEAGgsIACAALAAAGgsIACAALQAAGgsIACAAKQMAGgsIACAANAIAGgsIACAANQIAGgsIACAAMgEAGgsIACAAMwEAGgsIACAAMAAAGgsIACAAMQAAGgsIACAAKgIAGgsIACAAKwMAGgs=", +]; +export const script = "[[\"file\",\"i32.wast\"],[\"module\",3,0],[\"invoke\",37,0,\"add\",[\"i32:1\",\"i32:1\"]],[\"invoke\",38,0,\"add\",[\"i32:1\",\"i32:0\"]],[\"invoke\",39,0,\"add\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",40,0,\"add\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",41,0,\"add\",[\"i32:2147483647\",\"i32:1\"]],[\"invoke\",42,0,\"add\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",43,0,\"add\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",44,0,\"add\",[\"i32:1073741823\",\"i32:1\"]],[\"invoke\",46,0,\"sub\",[\"i32:1\",\"i32:1\"]],[\"invoke\",47,0,\"sub\",[\"i32:1\",\"i32:0\"]],[\"invoke\",48,0,\"sub\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",49,0,\"sub\",[\"i32:2147483647\",\"i32:4294967295\"]],[\"invoke\",50,0,\"sub\",[\"i32:2147483648\",\"i32:1\"]],[\"invoke\",51,0,\"sub\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",52,0,\"sub\",[\"i32:1073741823\",\"i32:4294967295\"]],[\"invoke\",54,0,\"mul\",[\"i32:1\",\"i32:1\"]],[\"invoke\",55,0,\"mul\",[\"i32:1\",\"i32:0\"]],[\"invoke\",56,0,\"mul\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",57,0,\"mul\",[\"i32:268435456\",\"i32:4096\"]],[\"invoke\",58,0,\"mul\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",59,0,\"mul\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",60,0,\"mul\",[\"i32:2147483647\",\"i32:4294967295\"]],[\"invoke\",61,0,\"mul\",[\"i32:19088743\",\"i32:1985229328\"]],[\"invoke\",62,0,\"mul\",[\"i32:2147483647\",\"i32:2147483647\"]],[\"invoke\",64,0,\"div_s\",[\"i32:1\",\"i32:0\"]],[\"invoke\",65,0,\"div_s\",[\"i32:0\",\"i32:0\"]],[\"invoke\",66,0,\"div_s\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",67,0,\"div_s\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",68,0,\"div_s\",[\"i32:1\",\"i32:1\"]],[\"invoke\",69,0,\"div_s\",[\"i32:0\",\"i32:1\"]],[\"invoke\",70,0,\"div_s\",[\"i32:0\",\"i32:4294967295\"]],[\"invoke\",71,0,\"div_s\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",72,0,\"div_s\",[\"i32:2147483648\",\"i32:2\"]],[\"invoke\",73,0,\"div_s\",[\"i32:2147483649\",\"i32:1000\"]],[\"invoke\",74,0,\"div_s\",[\"i32:5\",\"i32:2\"]],[\"invoke\",75,0,\"div_s\",[\"i32:4294967291\",\"i32:2\"]],[\"invoke\",76,0,\"div_s\",[\"i32:5\",\"i32:4294967294\"]],[\"invoke\",77,0,\"div_s\",[\"i32:4294967291\",\"i32:4294967294\"]],[\"invoke\",78,0,\"div_s\",[\"i32:7\",\"i32:3\"]],[\"invoke\",79,0,\"div_s\",[\"i32:4294967289\",\"i32:3\"]],[\"invoke\",80,0,\"div_s\",[\"i32:7\",\"i32:4294967293\"]],[\"invoke\",81,0,\"div_s\",[\"i32:4294967289\",\"i32:4294967293\"]],[\"invoke\",82,0,\"div_s\",[\"i32:11\",\"i32:5\"]],[\"invoke\",83,0,\"div_s\",[\"i32:17\",\"i32:7\"]],[\"invoke\",85,0,\"div_u\",[\"i32:1\",\"i32:0\"]],[\"invoke\",86,0,\"div_u\",[\"i32:0\",\"i32:0\"]],[\"invoke\",87,0,\"div_u\",[\"i32:1\",\"i32:1\"]],[\"invoke\",88,0,\"div_u\",[\"i32:0\",\"i32:1\"]],[\"invoke\",89,0,\"div_u\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",90,0,\"div_u\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",91,0,\"div_u\",[\"i32:2147483648\",\"i32:2\"]],[\"invoke\",92,0,\"div_u\",[\"i32:2414874608\",\"i32:65537\"]],[\"invoke\",93,0,\"div_u\",[\"i32:2147483649\",\"i32:1000\"]],[\"invoke\",94,0,\"div_u\",[\"i32:5\",\"i32:2\"]],[\"invoke\",95,0,\"div_u\",[\"i32:4294967291\",\"i32:2\"]],[\"invoke\",96,0,\"div_u\",[\"i32:5\",\"i32:4294967294\"]],[\"invoke\",97,0,\"div_u\",[\"i32:4294967291\",\"i32:4294967294\"]],[\"invoke\",98,0,\"div_u\",[\"i32:7\",\"i32:3\"]],[\"invoke\",99,0,\"div_u\",[\"i32:11\",\"i32:5\"]],[\"invoke\",100,0,\"div_u\",[\"i32:17\",\"i32:7\"]],[\"invoke\",102,0,\"rem_s\",[\"i32:1\",\"i32:0\"]],[\"invoke\",103,0,\"rem_s\",[\"i32:0\",\"i32:0\"]],[\"invoke\",104,0,\"rem_s\",[\"i32:2147483647\",\"i32:4294967295\"]],[\"invoke\",105,0,\"rem_s\",[\"i32:1\",\"i32:1\"]],[\"invoke\",106,0,\"rem_s\",[\"i32:0\",\"i32:1\"]],[\"invoke\",107,0,\"rem_s\",[\"i32:0\",\"i32:4294967295\"]],[\"invoke\",108,0,\"rem_s\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",109,0,\"rem_s\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",110,0,\"rem_s\",[\"i32:2147483648\",\"i32:2\"]],[\"invoke\",111,0,\"rem_s\",[\"i32:2147483649\",\"i32:1000\"]],[\"invoke\",112,0,\"rem_s\",[\"i32:5\",\"i32:2\"]],[\"invoke\",113,0,\"rem_s\",[\"i32:4294967291\",\"i32:2\"]],[\"invoke\",114,0,\"rem_s\",[\"i32:5\",\"i32:4294967294\"]],[\"invoke\",115,0,\"rem_s\",[\"i32:4294967291\",\"i32:4294967294\"]],[\"invoke\",116,0,\"rem_s\",[\"i32:7\",\"i32:3\"]],[\"invoke\",117,0,\"rem_s\",[\"i32:4294967289\",\"i32:3\"]],[\"invoke\",118,0,\"rem_s\",[\"i32:7\",\"i32:4294967293\"]],[\"invoke\",119,0,\"rem_s\",[\"i32:4294967289\",\"i32:4294967293\"]],[\"invoke\",120,0,\"rem_s\",[\"i32:11\",\"i32:5\"]],[\"invoke\",121,0,\"rem_s\",[\"i32:17\",\"i32:7\"]],[\"invoke\",123,0,\"rem_u\",[\"i32:1\",\"i32:0\"]],[\"invoke\",124,0,\"rem_u\",[\"i32:0\",\"i32:0\"]],[\"invoke\",125,0,\"rem_u\",[\"i32:1\",\"i32:1\"]],[\"invoke\",126,0,\"rem_u\",[\"i32:0\",\"i32:1\"]],[\"invoke\",127,0,\"rem_u\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",128,0,\"rem_u\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",129,0,\"rem_u\",[\"i32:2147483648\",\"i32:2\"]],[\"invoke\",130,0,\"rem_u\",[\"i32:2414874608\",\"i32:65537\"]],[\"invoke\",131,0,\"rem_u\",[\"i32:2147483649\",\"i32:1000\"]],[\"invoke\",132,0,\"rem_u\",[\"i32:5\",\"i32:2\"]],[\"invoke\",133,0,\"rem_u\",[\"i32:4294967291\",\"i32:2\"]],[\"invoke\",134,0,\"rem_u\",[\"i32:5\",\"i32:4294967294\"]],[\"invoke\",135,0,\"rem_u\",[\"i32:4294967291\",\"i32:4294967294\"]],[\"invoke\",136,0,\"rem_u\",[\"i32:7\",\"i32:3\"]],[\"invoke\",137,0,\"rem_u\",[\"i32:11\",\"i32:5\"]],[\"invoke\",138,0,\"rem_u\",[\"i32:17\",\"i32:7\"]],[\"invoke\",140,0,\"and\",[\"i32:1\",\"i32:0\"]],[\"invoke\",141,0,\"and\",[\"i32:0\",\"i32:1\"]],[\"invoke\",142,0,\"and\",[\"i32:1\",\"i32:1\"]],[\"invoke\",143,0,\"and\",[\"i32:0\",\"i32:0\"]],[\"invoke\",144,0,\"and\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",145,0,\"and\",[\"i32:2147483647\",\"i32:4294967295\"]],[\"invoke\",146,0,\"and\",[\"i32:4042326015\",\"i32:4294963440\"]],[\"invoke\",147,0,\"and\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",149,0,\"or\",[\"i32:1\",\"i32:0\"]],[\"invoke\",150,0,\"or\",[\"i32:0\",\"i32:1\"]],[\"invoke\",151,0,\"or\",[\"i32:1\",\"i32:1\"]],[\"invoke\",152,0,\"or\",[\"i32:0\",\"i32:0\"]],[\"invoke\",153,0,\"or\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",154,0,\"or\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",155,0,\"or\",[\"i32:4042326015\",\"i32:4294963440\"]],[\"invoke\",156,0,\"or\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",158,0,\"xor\",[\"i32:1\",\"i32:0\"]],[\"invoke\",159,0,\"xor\",[\"i32:0\",\"i32:1\"]],[\"invoke\",160,0,\"xor\",[\"i32:1\",\"i32:1\"]],[\"invoke\",161,0,\"xor\",[\"i32:0\",\"i32:0\"]],[\"invoke\",162,0,\"xor\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",163,0,\"xor\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",164,0,\"xor\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",165,0,\"xor\",[\"i32:4294967295\",\"i32:2147483647\"]],[\"invoke\",166,0,\"xor\",[\"i32:4042326015\",\"i32:4294963440\"]],[\"invoke\",167,0,\"xor\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",169,0,\"shl\",[\"i32:1\",\"i32:1\"]],[\"invoke\",170,0,\"shl\",[\"i32:1\",\"i32:0\"]],[\"invoke\",171,0,\"shl\",[\"i32:2147483647\",\"i32:1\"]],[\"invoke\",172,0,\"shl\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",173,0,\"shl\",[\"i32:2147483648\",\"i32:1\"]],[\"invoke\",174,0,\"shl\",[\"i32:1073741824\",\"i32:1\"]],[\"invoke\",175,0,\"shl\",[\"i32:1\",\"i32:31\"]],[\"invoke\",176,0,\"shl\",[\"i32:1\",\"i32:32\"]],[\"invoke\",177,0,\"shl\",[\"i32:1\",\"i32:33\"]],[\"invoke\",178,0,\"shl\",[\"i32:1\",\"i32:4294967295\"]],[\"invoke\",179,0,\"shl\",[\"i32:1\",\"i32:2147483647\"]],[\"invoke\",181,0,\"shr_s\",[\"i32:1\",\"i32:1\"]],[\"invoke\",182,0,\"shr_s\",[\"i32:1\",\"i32:0\"]],[\"invoke\",183,0,\"shr_s\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",184,0,\"shr_s\",[\"i32:2147483647\",\"i32:1\"]],[\"invoke\",185,0,\"shr_s\",[\"i32:2147483648\",\"i32:1\"]],[\"invoke\",186,0,\"shr_s\",[\"i32:1073741824\",\"i32:1\"]],[\"invoke\",187,0,\"shr_s\",[\"i32:1\",\"i32:32\"]],[\"invoke\",188,0,\"shr_s\",[\"i32:1\",\"i32:33\"]],[\"invoke\",189,0,\"shr_s\",[\"i32:1\",\"i32:4294967295\"]],[\"invoke\",190,0,\"shr_s\",[\"i32:1\",\"i32:2147483647\"]],[\"invoke\",191,0,\"shr_s\",[\"i32:1\",\"i32:2147483648\"]],[\"invoke\",192,0,\"shr_s\",[\"i32:2147483648\",\"i32:31\"]],[\"invoke\",193,0,\"shr_s\",[\"i32:4294967295\",\"i32:32\"]],[\"invoke\",194,0,\"shr_s\",[\"i32:4294967295\",\"i32:33\"]],[\"invoke\",195,0,\"shr_s\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",196,0,\"shr_s\",[\"i32:4294967295\",\"i32:2147483647\"]],[\"invoke\",197,0,\"shr_s\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",199,0,\"shr_u\",[\"i32:1\",\"i32:1\"]],[\"invoke\",200,0,\"shr_u\",[\"i32:1\",\"i32:0\"]],[\"invoke\",201,0,\"shr_u\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",202,0,\"shr_u\",[\"i32:2147483647\",\"i32:1\"]],[\"invoke\",203,0,\"shr_u\",[\"i32:2147483648\",\"i32:1\"]],[\"invoke\",204,0,\"shr_u\",[\"i32:1073741824\",\"i32:1\"]],[\"invoke\",205,0,\"shr_u\",[\"i32:1\",\"i32:32\"]],[\"invoke\",206,0,\"shr_u\",[\"i32:1\",\"i32:33\"]],[\"invoke\",207,0,\"shr_u\",[\"i32:1\",\"i32:4294967295\"]],[\"invoke\",208,0,\"shr_u\",[\"i32:1\",\"i32:2147483647\"]],[\"invoke\",209,0,\"shr_u\",[\"i32:1\",\"i32:2147483648\"]],[\"invoke\",210,0,\"shr_u\",[\"i32:2147483648\",\"i32:31\"]],[\"invoke\",211,0,\"shr_u\",[\"i32:4294967295\",\"i32:32\"]],[\"invoke\",212,0,\"shr_u\",[\"i32:4294967295\",\"i32:33\"]],[\"invoke\",213,0,\"shr_u\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",214,0,\"shr_u\",[\"i32:4294967295\",\"i32:2147483647\"]],[\"invoke\",215,0,\"shr_u\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",217,0,\"rotl\",[\"i32:1\",\"i32:1\"]],[\"invoke\",218,0,\"rotl\",[\"i32:1\",\"i32:0\"]],[\"invoke\",219,0,\"rotl\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",220,0,\"rotl\",[\"i32:1\",\"i32:32\"]],[\"invoke\",221,0,\"rotl\",[\"i32:2882377846\",\"i32:1\"]],[\"invoke\",222,0,\"rotl\",[\"i32:4261469184\",\"i32:4\"]],[\"invoke\",223,0,\"rotl\",[\"i32:2965492451\",\"i32:5\"]],[\"invoke\",224,0,\"rotl\",[\"i32:32768\",\"i32:37\"]],[\"invoke\",225,0,\"rotl\",[\"i32:2965492451\",\"i32:65285\"]],[\"invoke\",226,0,\"rotl\",[\"i32:1989852383\",\"i32:4294967277\"]],[\"invoke\",227,0,\"rotl\",[\"i32:1989852383\",\"i32:2147483661\"]],[\"invoke\",228,0,\"rotl\",[\"i32:1\",\"i32:31\"]],[\"invoke\",229,0,\"rotl\",[\"i32:2147483648\",\"i32:1\"]],[\"invoke\",231,0,\"rotr\",[\"i32:1\",\"i32:1\"]],[\"invoke\",232,0,\"rotr\",[\"i32:1\",\"i32:0\"]],[\"invoke\",233,0,\"rotr\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",234,0,\"rotr\",[\"i32:1\",\"i32:32\"]],[\"invoke\",235,0,\"rotr\",[\"i32:4278242304\",\"i32:1\"]],[\"invoke\",236,0,\"rotr\",[\"i32:524288\",\"i32:4\"]],[\"invoke\",237,0,\"rotr\",[\"i32:2965492451\",\"i32:5\"]],[\"invoke\",238,0,\"rotr\",[\"i32:32768\",\"i32:37\"]],[\"invoke\",239,0,\"rotr\",[\"i32:2965492451\",\"i32:65285\"]],[\"invoke\",240,0,\"rotr\",[\"i32:1989852383\",\"i32:4294967277\"]],[\"invoke\",241,0,\"rotr\",[\"i32:1989852383\",\"i32:2147483661\"]],[\"invoke\",242,0,\"rotr\",[\"i32:1\",\"i32:31\"]],[\"invoke\",243,0,\"rotr\",[\"i32:2147483648\",\"i32:31\"]],[\"invoke\",245,0,\"clz\",[\"i32:4294967295\"]],[\"invoke\",246,0,\"clz\",[\"i32:0\"]],[\"invoke\",247,0,\"clz\",[\"i32:32768\"]],[\"invoke\",248,0,\"clz\",[\"i32:255\"]],[\"invoke\",249,0,\"clz\",[\"i32:2147483648\"]],[\"invoke\",250,0,\"clz\",[\"i32:1\"]],[\"invoke\",251,0,\"clz\",[\"i32:2\"]],[\"invoke\",252,0,\"clz\",[\"i32:2147483647\"]],[\"invoke\",254,0,\"ctz\",[\"i32:4294967295\"]],[\"invoke\",255,0,\"ctz\",[\"i32:0\"]],[\"invoke\",256,0,\"ctz\",[\"i32:32768\"]],[\"invoke\",257,0,\"ctz\",[\"i32:65536\"]],[\"invoke\",258,0,\"ctz\",[\"i32:2147483648\"]],[\"invoke\",259,0,\"ctz\",[\"i32:2147483647\"]],[\"invoke\",261,0,\"popcnt\",[\"i32:4294967295\"]],[\"invoke\",262,0,\"popcnt\",[\"i32:0\"]],[\"invoke\",263,0,\"popcnt\",[\"i32:32768\"]],[\"invoke\",264,0,\"popcnt\",[\"i32:2147516416\"]],[\"invoke\",265,0,\"popcnt\",[\"i32:2147483647\"]],[\"invoke\",266,0,\"popcnt\",[\"i32:2863311530\"]],[\"invoke\",267,0,\"popcnt\",[\"i32:1431655765\"]],[\"invoke\",268,0,\"popcnt\",[\"i32:3735928559\"]],[\"invoke\",270,0,\"extend8_s\",[\"i32:0\"]],[\"invoke\",271,0,\"extend8_s\",[\"i32:127\"]],[\"invoke\",272,0,\"extend8_s\",[\"i32:128\"]],[\"invoke\",273,0,\"extend8_s\",[\"i32:255\"]],[\"invoke\",274,0,\"extend8_s\",[\"i32:19088640\"]],[\"invoke\",275,0,\"extend8_s\",[\"i32:4275878528\"]],[\"invoke\",276,0,\"extend8_s\",[\"i32:4294967295\"]],[\"invoke\",278,0,\"extend16_s\",[\"i32:0\"]],[\"invoke\",279,0,\"extend16_s\",[\"i32:32767\"]],[\"invoke\",280,0,\"extend16_s\",[\"i32:32768\"]],[\"invoke\",281,0,\"extend16_s\",[\"i32:65535\"]],[\"invoke\",282,0,\"extend16_s\",[\"i32:19070976\"]],[\"invoke\",283,0,\"extend16_s\",[\"i32:4275863552\"]],[\"invoke\",284,0,\"extend16_s\",[\"i32:4294967295\"]],[\"invoke\",286,0,\"eqz\",[\"i32:0\"]],[\"invoke\",287,0,\"eqz\",[\"i32:1\"]],[\"invoke\",288,0,\"eqz\",[\"i32:2147483648\"]],[\"invoke\",289,0,\"eqz\",[\"i32:2147483647\"]],[\"invoke\",290,0,\"eqz\",[\"i32:4294967295\"]],[\"invoke\",292,0,\"eq\",[\"i32:0\",\"i32:0\"]],[\"invoke\",293,0,\"eq\",[\"i32:1\",\"i32:1\"]],[\"invoke\",294,0,\"eq\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",295,0,\"eq\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",296,0,\"eq\",[\"i32:2147483647\",\"i32:2147483647\"]],[\"invoke\",297,0,\"eq\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",298,0,\"eq\",[\"i32:1\",\"i32:0\"]],[\"invoke\",299,0,\"eq\",[\"i32:0\",\"i32:1\"]],[\"invoke\",300,0,\"eq\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",301,0,\"eq\",[\"i32:0\",\"i32:2147483648\"]],[\"invoke\",302,0,\"eq\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",303,0,\"eq\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",304,0,\"eq\",[\"i32:2147483648\",\"i32:2147483647\"]],[\"invoke\",305,0,\"eq\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",307,0,\"ne\",[\"i32:0\",\"i32:0\"]],[\"invoke\",308,0,\"ne\",[\"i32:1\",\"i32:1\"]],[\"invoke\",309,0,\"ne\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",310,0,\"ne\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",311,0,\"ne\",[\"i32:2147483647\",\"i32:2147483647\"]],[\"invoke\",312,0,\"ne\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",313,0,\"ne\",[\"i32:1\",\"i32:0\"]],[\"invoke\",314,0,\"ne\",[\"i32:0\",\"i32:1\"]],[\"invoke\",315,0,\"ne\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",316,0,\"ne\",[\"i32:0\",\"i32:2147483648\"]],[\"invoke\",317,0,\"ne\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",318,0,\"ne\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",319,0,\"ne\",[\"i32:2147483648\",\"i32:2147483647\"]],[\"invoke\",320,0,\"ne\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",322,0,\"lt_s\",[\"i32:0\",\"i32:0\"]],[\"invoke\",323,0,\"lt_s\",[\"i32:1\",\"i32:1\"]],[\"invoke\",324,0,\"lt_s\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",325,0,\"lt_s\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",326,0,\"lt_s\",[\"i32:2147483647\",\"i32:2147483647\"]],[\"invoke\",327,0,\"lt_s\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",328,0,\"lt_s\",[\"i32:1\",\"i32:0\"]],[\"invoke\",329,0,\"lt_s\",[\"i32:0\",\"i32:1\"]],[\"invoke\",330,0,\"lt_s\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",331,0,\"lt_s\",[\"i32:0\",\"i32:2147483648\"]],[\"invoke\",332,0,\"lt_s\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",333,0,\"lt_s\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",334,0,\"lt_s\",[\"i32:2147483648\",\"i32:2147483647\"]],[\"invoke\",335,0,\"lt_s\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",337,0,\"lt_u\",[\"i32:0\",\"i32:0\"]],[\"invoke\",338,0,\"lt_u\",[\"i32:1\",\"i32:1\"]],[\"invoke\",339,0,\"lt_u\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",340,0,\"lt_u\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",341,0,\"lt_u\",[\"i32:2147483647\",\"i32:2147483647\"]],[\"invoke\",342,0,\"lt_u\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",343,0,\"lt_u\",[\"i32:1\",\"i32:0\"]],[\"invoke\",344,0,\"lt_u\",[\"i32:0\",\"i32:1\"]],[\"invoke\",345,0,\"lt_u\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",346,0,\"lt_u\",[\"i32:0\",\"i32:2147483648\"]],[\"invoke\",347,0,\"lt_u\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",348,0,\"lt_u\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",349,0,\"lt_u\",[\"i32:2147483648\",\"i32:2147483647\"]],[\"invoke\",350,0,\"lt_u\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",352,0,\"le_s\",[\"i32:0\",\"i32:0\"]],[\"invoke\",353,0,\"le_s\",[\"i32:1\",\"i32:1\"]],[\"invoke\",354,0,\"le_s\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",355,0,\"le_s\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",356,0,\"le_s\",[\"i32:2147483647\",\"i32:2147483647\"]],[\"invoke\",357,0,\"le_s\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",358,0,\"le_s\",[\"i32:1\",\"i32:0\"]],[\"invoke\",359,0,\"le_s\",[\"i32:0\",\"i32:1\"]],[\"invoke\",360,0,\"le_s\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",361,0,\"le_s\",[\"i32:0\",\"i32:2147483648\"]],[\"invoke\",362,0,\"le_s\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",363,0,\"le_s\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",364,0,\"le_s\",[\"i32:2147483648\",\"i32:2147483647\"]],[\"invoke\",365,0,\"le_s\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",367,0,\"le_u\",[\"i32:0\",\"i32:0\"]],[\"invoke\",368,0,\"le_u\",[\"i32:1\",\"i32:1\"]],[\"invoke\",369,0,\"le_u\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",370,0,\"le_u\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",371,0,\"le_u\",[\"i32:2147483647\",\"i32:2147483647\"]],[\"invoke\",372,0,\"le_u\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",373,0,\"le_u\",[\"i32:1\",\"i32:0\"]],[\"invoke\",374,0,\"le_u\",[\"i32:0\",\"i32:1\"]],[\"invoke\",375,0,\"le_u\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",376,0,\"le_u\",[\"i32:0\",\"i32:2147483648\"]],[\"invoke\",377,0,\"le_u\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",378,0,\"le_u\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",379,0,\"le_u\",[\"i32:2147483648\",\"i32:2147483647\"]],[\"invoke\",380,0,\"le_u\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",382,0,\"gt_s\",[\"i32:0\",\"i32:0\"]],[\"invoke\",383,0,\"gt_s\",[\"i32:1\",\"i32:1\"]],[\"invoke\",384,0,\"gt_s\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",385,0,\"gt_s\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",386,0,\"gt_s\",[\"i32:2147483647\",\"i32:2147483647\"]],[\"invoke\",387,0,\"gt_s\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",388,0,\"gt_s\",[\"i32:1\",\"i32:0\"]],[\"invoke\",389,0,\"gt_s\",[\"i32:0\",\"i32:1\"]],[\"invoke\",390,0,\"gt_s\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",391,0,\"gt_s\",[\"i32:0\",\"i32:2147483648\"]],[\"invoke\",392,0,\"gt_s\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",393,0,\"gt_s\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",394,0,\"gt_s\",[\"i32:2147483648\",\"i32:2147483647\"]],[\"invoke\",395,0,\"gt_s\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",397,0,\"gt_u\",[\"i32:0\",\"i32:0\"]],[\"invoke\",398,0,\"gt_u\",[\"i32:1\",\"i32:1\"]],[\"invoke\",399,0,\"gt_u\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",400,0,\"gt_u\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",401,0,\"gt_u\",[\"i32:2147483647\",\"i32:2147483647\"]],[\"invoke\",402,0,\"gt_u\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",403,0,\"gt_u\",[\"i32:1\",\"i32:0\"]],[\"invoke\",404,0,\"gt_u\",[\"i32:0\",\"i32:1\"]],[\"invoke\",405,0,\"gt_u\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",406,0,\"gt_u\",[\"i32:0\",\"i32:2147483648\"]],[\"invoke\",407,0,\"gt_u\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",408,0,\"gt_u\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",409,0,\"gt_u\",[\"i32:2147483648\",\"i32:2147483647\"]],[\"invoke\",410,0,\"gt_u\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",412,0,\"ge_s\",[\"i32:0\",\"i32:0\"]],[\"invoke\",413,0,\"ge_s\",[\"i32:1\",\"i32:1\"]],[\"invoke\",414,0,\"ge_s\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",415,0,\"ge_s\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",416,0,\"ge_s\",[\"i32:2147483647\",\"i32:2147483647\"]],[\"invoke\",417,0,\"ge_s\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",418,0,\"ge_s\",[\"i32:1\",\"i32:0\"]],[\"invoke\",419,0,\"ge_s\",[\"i32:0\",\"i32:1\"]],[\"invoke\",420,0,\"ge_s\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",421,0,\"ge_s\",[\"i32:0\",\"i32:2147483648\"]],[\"invoke\",422,0,\"ge_s\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",423,0,\"ge_s\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",424,0,\"ge_s\",[\"i32:2147483648\",\"i32:2147483647\"]],[\"invoke\",425,0,\"ge_s\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"invoke\",427,0,\"ge_u\",[\"i32:0\",\"i32:0\"]],[\"invoke\",428,0,\"ge_u\",[\"i32:1\",\"i32:1\"]],[\"invoke\",429,0,\"ge_u\",[\"i32:4294967295\",\"i32:1\"]],[\"invoke\",430,0,\"ge_u\",[\"i32:2147483648\",\"i32:2147483648\"]],[\"invoke\",431,0,\"ge_u\",[\"i32:2147483647\",\"i32:2147483647\"]],[\"invoke\",432,0,\"ge_u\",[\"i32:4294967295\",\"i32:4294967295\"]],[\"invoke\",433,0,\"ge_u\",[\"i32:1\",\"i32:0\"]],[\"invoke\",434,0,\"ge_u\",[\"i32:0\",\"i32:1\"]],[\"invoke\",435,0,\"ge_u\",[\"i32:2147483648\",\"i32:0\"]],[\"invoke\",436,0,\"ge_u\",[\"i32:0\",\"i32:2147483648\"]],[\"invoke\",437,0,\"ge_u\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",438,0,\"ge_u\",[\"i32:4294967295\",\"i32:2147483648\"]],[\"invoke\",439,0,\"ge_u\",[\"i32:2147483648\",\"i32:2147483647\"]],[\"invoke\",440,0,\"ge_u\",[\"i32:2147483647\",\"i32:2147483648\"]],[\"file\",\"i64.wast\"],[\"module\",3,1],[\"invoke\",38,0,\"add\",[\"i64:1\",\"i64:1\"]],[\"invoke\",39,0,\"add\",[\"i64:1\",\"i64:0\"]],[\"invoke\",40,0,\"add\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",41,0,\"add\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",42,0,\"add\",[\"i64:9223372036854775807\",\"i64:1\"]],[\"invoke\",43,0,\"add\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",44,0,\"add\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",45,0,\"add\",[\"i64:1073741823\",\"i64:1\"]],[\"invoke\",47,0,\"sub\",[\"i64:1\",\"i64:1\"]],[\"invoke\",48,0,\"sub\",[\"i64:1\",\"i64:0\"]],[\"invoke\",49,0,\"sub\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",50,0,\"sub\",[\"i64:9223372036854775807\",\"i64:18446744073709551615\"]],[\"invoke\",51,0,\"sub\",[\"i64:9223372036854775808\",\"i64:1\"]],[\"invoke\",52,0,\"sub\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",53,0,\"sub\",[\"i64:1073741823\",\"i64:18446744073709551615\"]],[\"invoke\",55,0,\"mul\",[\"i64:1\",\"i64:1\"]],[\"invoke\",56,0,\"mul\",[\"i64:1\",\"i64:0\"]],[\"invoke\",57,0,\"mul\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",58,0,\"mul\",[\"i64:1152921504606846976\",\"i64:4096\"]],[\"invoke\",59,0,\"mul\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",60,0,\"mul\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",61,0,\"mul\",[\"i64:9223372036854775807\",\"i64:18446744073709551615\"]],[\"invoke\",62,0,\"mul\",[\"i64:81985529216486895\",\"i64:18364758544493064720\"]],[\"invoke\",63,0,\"mul\",[\"i64:9223372036854775807\",\"i64:9223372036854775807\"]],[\"invoke\",65,0,\"div_s\",[\"i64:1\",\"i64:0\"]],[\"invoke\",66,0,\"div_s\",[\"i64:0\",\"i64:0\"]],[\"invoke\",67,0,\"div_s\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",68,0,\"div_s\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",69,0,\"div_s\",[\"i64:1\",\"i64:1\"]],[\"invoke\",70,0,\"div_s\",[\"i64:0\",\"i64:1\"]],[\"invoke\",71,0,\"div_s\",[\"i64:0\",\"i64:18446744073709551615\"]],[\"invoke\",72,0,\"div_s\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",73,0,\"div_s\",[\"i64:9223372036854775808\",\"i64:2\"]],[\"invoke\",74,0,\"div_s\",[\"i64:9223372036854775809\",\"i64:1000\"]],[\"invoke\",75,0,\"div_s\",[\"i64:5\",\"i64:2\"]],[\"invoke\",76,0,\"div_s\",[\"i64:18446744073709551611\",\"i64:2\"]],[\"invoke\",77,0,\"div_s\",[\"i64:5\",\"i64:18446744073709551614\"]],[\"invoke\",78,0,\"div_s\",[\"i64:18446744073709551611\",\"i64:18446744073709551614\"]],[\"invoke\",79,0,\"div_s\",[\"i64:7\",\"i64:3\"]],[\"invoke\",80,0,\"div_s\",[\"i64:18446744073709551609\",\"i64:3\"]],[\"invoke\",81,0,\"div_s\",[\"i64:7\",\"i64:18446744073709551613\"]],[\"invoke\",82,0,\"div_s\",[\"i64:18446744073709551609\",\"i64:18446744073709551613\"]],[\"invoke\",83,0,\"div_s\",[\"i64:11\",\"i64:5\"]],[\"invoke\",84,0,\"div_s\",[\"i64:17\",\"i64:7\"]],[\"invoke\",86,0,\"div_u\",[\"i64:1\",\"i64:0\"]],[\"invoke\",87,0,\"div_u\",[\"i64:0\",\"i64:0\"]],[\"invoke\",88,0,\"div_u\",[\"i64:1\",\"i64:1\"]],[\"invoke\",89,0,\"div_u\",[\"i64:0\",\"i64:1\"]],[\"invoke\",90,0,\"div_u\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",91,0,\"div_u\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",92,0,\"div_u\",[\"i64:9223372036854775808\",\"i64:2\"]],[\"invoke\",93,0,\"div_u\",[\"i64:10371807465568210928\",\"i64:4294967297\"]],[\"invoke\",94,0,\"div_u\",[\"i64:9223372036854775809\",\"i64:1000\"]],[\"invoke\",95,0,\"div_u\",[\"i64:5\",\"i64:2\"]],[\"invoke\",96,0,\"div_u\",[\"i64:18446744073709551611\",\"i64:2\"]],[\"invoke\",97,0,\"div_u\",[\"i64:5\",\"i64:18446744073709551614\"]],[\"invoke\",98,0,\"div_u\",[\"i64:18446744073709551611\",\"i64:18446744073709551614\"]],[\"invoke\",99,0,\"div_u\",[\"i64:7\",\"i64:3\"]],[\"invoke\",100,0,\"div_u\",[\"i64:11\",\"i64:5\"]],[\"invoke\",101,0,\"div_u\",[\"i64:17\",\"i64:7\"]],[\"invoke\",103,0,\"rem_s\",[\"i64:1\",\"i64:0\"]],[\"invoke\",104,0,\"rem_s\",[\"i64:0\",\"i64:0\"]],[\"invoke\",105,0,\"rem_s\",[\"i64:9223372036854775807\",\"i64:18446744073709551615\"]],[\"invoke\",106,0,\"rem_s\",[\"i64:1\",\"i64:1\"]],[\"invoke\",107,0,\"rem_s\",[\"i64:0\",\"i64:1\"]],[\"invoke\",108,0,\"rem_s\",[\"i64:0\",\"i64:18446744073709551615\"]],[\"invoke\",109,0,\"rem_s\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",110,0,\"rem_s\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",111,0,\"rem_s\",[\"i64:9223372036854775808\",\"i64:2\"]],[\"invoke\",112,0,\"rem_s\",[\"i64:9223372036854775809\",\"i64:1000\"]],[\"invoke\",113,0,\"rem_s\",[\"i64:5\",\"i64:2\"]],[\"invoke\",114,0,\"rem_s\",[\"i64:18446744073709551611\",\"i64:2\"]],[\"invoke\",115,0,\"rem_s\",[\"i64:5\",\"i64:18446744073709551614\"]],[\"invoke\",116,0,\"rem_s\",[\"i64:18446744073709551611\",\"i64:18446744073709551614\"]],[\"invoke\",117,0,\"rem_s\",[\"i64:7\",\"i64:3\"]],[\"invoke\",118,0,\"rem_s\",[\"i64:18446744073709551609\",\"i64:3\"]],[\"invoke\",119,0,\"rem_s\",[\"i64:7\",\"i64:18446744073709551613\"]],[\"invoke\",120,0,\"rem_s\",[\"i64:18446744073709551609\",\"i64:18446744073709551613\"]],[\"invoke\",121,0,\"rem_s\",[\"i64:11\",\"i64:5\"]],[\"invoke\",122,0,\"rem_s\",[\"i64:17\",\"i64:7\"]],[\"invoke\",124,0,\"rem_u\",[\"i64:1\",\"i64:0\"]],[\"invoke\",125,0,\"rem_u\",[\"i64:0\",\"i64:0\"]],[\"invoke\",126,0,\"rem_u\",[\"i64:1\",\"i64:1\"]],[\"invoke\",127,0,\"rem_u\",[\"i64:0\",\"i64:1\"]],[\"invoke\",128,0,\"rem_u\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",129,0,\"rem_u\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",130,0,\"rem_u\",[\"i64:9223372036854775808\",\"i64:2\"]],[\"invoke\",131,0,\"rem_u\",[\"i64:10371807465568210928\",\"i64:4294967297\"]],[\"invoke\",132,0,\"rem_u\",[\"i64:9223372036854775809\",\"i64:1000\"]],[\"invoke\",133,0,\"rem_u\",[\"i64:5\",\"i64:2\"]],[\"invoke\",134,0,\"rem_u\",[\"i64:18446744073709551611\",\"i64:2\"]],[\"invoke\",135,0,\"rem_u\",[\"i64:5\",\"i64:18446744073709551614\"]],[\"invoke\",136,0,\"rem_u\",[\"i64:18446744073709551611\",\"i64:18446744073709551614\"]],[\"invoke\",137,0,\"rem_u\",[\"i64:7\",\"i64:3\"]],[\"invoke\",138,0,\"rem_u\",[\"i64:11\",\"i64:5\"]],[\"invoke\",139,0,\"rem_u\",[\"i64:17\",\"i64:7\"]],[\"invoke\",141,0,\"and\",[\"i64:1\",\"i64:0\"]],[\"invoke\",142,0,\"and\",[\"i64:0\",\"i64:1\"]],[\"invoke\",143,0,\"and\",[\"i64:1\",\"i64:1\"]],[\"invoke\",144,0,\"and\",[\"i64:0\",\"i64:0\"]],[\"invoke\",145,0,\"and\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",146,0,\"and\",[\"i64:9223372036854775807\",\"i64:18446744073709551615\"]],[\"invoke\",147,0,\"and\",[\"i64:4042326015\",\"i64:4294963440\"]],[\"invoke\",148,0,\"and\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",150,0,\"or\",[\"i64:1\",\"i64:0\"]],[\"invoke\",151,0,\"or\",[\"i64:0\",\"i64:1\"]],[\"invoke\",152,0,\"or\",[\"i64:1\",\"i64:1\"]],[\"invoke\",153,0,\"or\",[\"i64:0\",\"i64:0\"]],[\"invoke\",154,0,\"or\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",155,0,\"or\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",156,0,\"or\",[\"i64:4042326015\",\"i64:4294963440\"]],[\"invoke\",157,0,\"or\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",159,0,\"xor\",[\"i64:1\",\"i64:0\"]],[\"invoke\",160,0,\"xor\",[\"i64:0\",\"i64:1\"]],[\"invoke\",161,0,\"xor\",[\"i64:1\",\"i64:1\"]],[\"invoke\",162,0,\"xor\",[\"i64:0\",\"i64:0\"]],[\"invoke\",163,0,\"xor\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",164,0,\"xor\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",165,0,\"xor\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",166,0,\"xor\",[\"i64:18446744073709551615\",\"i64:9223372036854775807\"]],[\"invoke\",167,0,\"xor\",[\"i64:4042326015\",\"i64:4294963440\"]],[\"invoke\",168,0,\"xor\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",170,0,\"shl\",[\"i64:1\",\"i64:1\"]],[\"invoke\",171,0,\"shl\",[\"i64:1\",\"i64:0\"]],[\"invoke\",172,0,\"shl\",[\"i64:9223372036854775807\",\"i64:1\"]],[\"invoke\",173,0,\"shl\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",174,0,\"shl\",[\"i64:9223372036854775808\",\"i64:1\"]],[\"invoke\",175,0,\"shl\",[\"i64:4611686018427387904\",\"i64:1\"]],[\"invoke\",176,0,\"shl\",[\"i64:1\",\"i64:63\"]],[\"invoke\",177,0,\"shl\",[\"i64:1\",\"i64:64\"]],[\"invoke\",178,0,\"shl\",[\"i64:1\",\"i64:65\"]],[\"invoke\",179,0,\"shl\",[\"i64:1\",\"i64:18446744073709551615\"]],[\"invoke\",180,0,\"shl\",[\"i64:1\",\"i64:9223372036854775807\"]],[\"invoke\",182,0,\"shr_s\",[\"i64:1\",\"i64:1\"]],[\"invoke\",183,0,\"shr_s\",[\"i64:1\",\"i64:0\"]],[\"invoke\",184,0,\"shr_s\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",185,0,\"shr_s\",[\"i64:9223372036854775807\",\"i64:1\"]],[\"invoke\",186,0,\"shr_s\",[\"i64:9223372036854775808\",\"i64:1\"]],[\"invoke\",187,0,\"shr_s\",[\"i64:4611686018427387904\",\"i64:1\"]],[\"invoke\",188,0,\"shr_s\",[\"i64:1\",\"i64:64\"]],[\"invoke\",189,0,\"shr_s\",[\"i64:1\",\"i64:65\"]],[\"invoke\",190,0,\"shr_s\",[\"i64:1\",\"i64:18446744073709551615\"]],[\"invoke\",191,0,\"shr_s\",[\"i64:1\",\"i64:9223372036854775807\"]],[\"invoke\",192,0,\"shr_s\",[\"i64:1\",\"i64:9223372036854775808\"]],[\"invoke\",193,0,\"shr_s\",[\"i64:9223372036854775808\",\"i64:63\"]],[\"invoke\",194,0,\"shr_s\",[\"i64:18446744073709551615\",\"i64:64\"]],[\"invoke\",195,0,\"shr_s\",[\"i64:18446744073709551615\",\"i64:65\"]],[\"invoke\",196,0,\"shr_s\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",197,0,\"shr_s\",[\"i64:18446744073709551615\",\"i64:9223372036854775807\"]],[\"invoke\",198,0,\"shr_s\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",200,0,\"shr_u\",[\"i64:1\",\"i64:1\"]],[\"invoke\",201,0,\"shr_u\",[\"i64:1\",\"i64:0\"]],[\"invoke\",202,0,\"shr_u\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",203,0,\"shr_u\",[\"i64:9223372036854775807\",\"i64:1\"]],[\"invoke\",204,0,\"shr_u\",[\"i64:9223372036854775808\",\"i64:1\"]],[\"invoke\",205,0,\"shr_u\",[\"i64:4611686018427387904\",\"i64:1\"]],[\"invoke\",206,0,\"shr_u\",[\"i64:1\",\"i64:64\"]],[\"invoke\",207,0,\"shr_u\",[\"i64:1\",\"i64:65\"]],[\"invoke\",208,0,\"shr_u\",[\"i64:1\",\"i64:18446744073709551615\"]],[\"invoke\",209,0,\"shr_u\",[\"i64:1\",\"i64:9223372036854775807\"]],[\"invoke\",210,0,\"shr_u\",[\"i64:1\",\"i64:9223372036854775808\"]],[\"invoke\",211,0,\"shr_u\",[\"i64:9223372036854775808\",\"i64:63\"]],[\"invoke\",212,0,\"shr_u\",[\"i64:18446744073709551615\",\"i64:64\"]],[\"invoke\",213,0,\"shr_u\",[\"i64:18446744073709551615\",\"i64:65\"]],[\"invoke\",214,0,\"shr_u\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",215,0,\"shr_u\",[\"i64:18446744073709551615\",\"i64:9223372036854775807\"]],[\"invoke\",216,0,\"shr_u\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",218,0,\"rotl\",[\"i64:1\",\"i64:1\"]],[\"invoke\",219,0,\"rotl\",[\"i64:1\",\"i64:0\"]],[\"invoke\",220,0,\"rotl\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",221,0,\"rotl\",[\"i64:1\",\"i64:64\"]],[\"invoke\",222,0,\"rotl\",[\"i64:12379718583323101902\",\"i64:1\"]],[\"invoke\",223,0,\"rotl\",[\"i64:18302628889324683264\",\"i64:4\"]],[\"invoke\",224,0,\"rotl\",[\"i64:12379570969274382345\",\"i64:53\"]],[\"invoke\",225,0,\"rotl\",[\"i64:12380715672649826460\",\"i64:63\"]],[\"invoke\",226,0,\"rotl\",[\"i64:12379570969274382345\",\"i64:245\"]],[\"invoke\",227,0,\"rotl\",[\"i64:12379676934707509257\",\"i64:18446744073709551597\"]],[\"invoke\",228,0,\"rotl\",[\"i64:12380715672649826460\",\"i64:9223372036854775871\"]],[\"invoke\",229,0,\"rotl\",[\"i64:1\",\"i64:63\"]],[\"invoke\",230,0,\"rotl\",[\"i64:9223372036854775808\",\"i64:1\"]],[\"invoke\",232,0,\"rotr\",[\"i64:1\",\"i64:1\"]],[\"invoke\",233,0,\"rotr\",[\"i64:1\",\"i64:0\"]],[\"invoke\",234,0,\"rotr\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",235,0,\"rotr\",[\"i64:1\",\"i64:64\"]],[\"invoke\",236,0,\"rotr\",[\"i64:12379718583323101902\",\"i64:1\"]],[\"invoke\",237,0,\"rotr\",[\"i64:18302628889324683264\",\"i64:4\"]],[\"invoke\",238,0,\"rotr\",[\"i64:12379570969274382345\",\"i64:53\"]],[\"invoke\",239,0,\"rotr\",[\"i64:12380715672649826460\",\"i64:63\"]],[\"invoke\",240,0,\"rotr\",[\"i64:12379570969274382345\",\"i64:245\"]],[\"invoke\",241,0,\"rotr\",[\"i64:12379676934707509257\",\"i64:18446744073709551597\"]],[\"invoke\",242,0,\"rotr\",[\"i64:12380715672649826460\",\"i64:9223372036854775871\"]],[\"invoke\",243,0,\"rotr\",[\"i64:1\",\"i64:63\"]],[\"invoke\",244,0,\"rotr\",[\"i64:9223372036854775808\",\"i64:63\"]],[\"invoke\",246,0,\"clz\",[\"i64:18446744073709551615\"]],[\"invoke\",247,0,\"clz\",[\"i64:0\"]],[\"invoke\",248,0,\"clz\",[\"i64:32768\"]],[\"invoke\",249,0,\"clz\",[\"i64:255\"]],[\"invoke\",250,0,\"clz\",[\"i64:9223372036854775808\"]],[\"invoke\",251,0,\"clz\",[\"i64:1\"]],[\"invoke\",252,0,\"clz\",[\"i64:2\"]],[\"invoke\",253,0,\"clz\",[\"i64:9223372036854775807\"]],[\"invoke\",255,0,\"ctz\",[\"i64:18446744073709551615\"]],[\"invoke\",256,0,\"ctz\",[\"i64:0\"]],[\"invoke\",257,0,\"ctz\",[\"i64:32768\"]],[\"invoke\",258,0,\"ctz\",[\"i64:65536\"]],[\"invoke\",259,0,\"ctz\",[\"i64:9223372036854775808\"]],[\"invoke\",260,0,\"ctz\",[\"i64:9223372036854775807\"]],[\"invoke\",262,0,\"popcnt\",[\"i64:18446744073709551615\"]],[\"invoke\",263,0,\"popcnt\",[\"i64:0\"]],[\"invoke\",264,0,\"popcnt\",[\"i64:32768\"]],[\"invoke\",265,0,\"popcnt\",[\"i64:9223512776490647552\"]],[\"invoke\",266,0,\"popcnt\",[\"i64:9223372036854775807\"]],[\"invoke\",267,0,\"popcnt\",[\"i64:12297829381041378645\"]],[\"invoke\",268,0,\"popcnt\",[\"i64:11068046444512062122\"]],[\"invoke\",269,0,\"popcnt\",[\"i64:16045690984833335023\"]],[\"invoke\",271,0,\"extend8_s\",[\"i64:0\"]],[\"invoke\",272,0,\"extend8_s\",[\"i64:127\"]],[\"invoke\",273,0,\"extend8_s\",[\"i64:128\"]],[\"invoke\",274,0,\"extend8_s\",[\"i64:255\"]],[\"invoke\",275,0,\"extend8_s\",[\"i64:81985529216486656\"]],[\"invoke\",276,0,\"extend8_s\",[\"i64:18364758544493064832\"]],[\"invoke\",277,0,\"extend8_s\",[\"i64:18446744073709551615\"]],[\"invoke\",279,0,\"extend16_s\",[\"i64:0\"]],[\"invoke\",280,0,\"extend16_s\",[\"i64:32767\"]],[\"invoke\",281,0,\"extend16_s\",[\"i64:32768\"]],[\"invoke\",282,0,\"extend16_s\",[\"i64:65535\"]],[\"invoke\",283,0,\"extend16_s\",[\"i64:1311768467463733248\"]],[\"invoke\",284,0,\"extend16_s\",[\"i64:18364758544493084672\"]],[\"invoke\",285,0,\"extend16_s\",[\"i64:18446744073709551615\"]],[\"invoke\",287,0,\"extend32_s\",[\"i64:0\"]],[\"invoke\",288,0,\"extend32_s\",[\"i64:32767\"]],[\"invoke\",289,0,\"extend32_s\",[\"i64:32768\"]],[\"invoke\",290,0,\"extend32_s\",[\"i64:65535\"]],[\"invoke\",291,0,\"extend32_s\",[\"i64:2147483647\"]],[\"invoke\",292,0,\"extend32_s\",[\"i64:2147483648\"]],[\"invoke\",293,0,\"extend32_s\",[\"i64:4294967295\"]],[\"invoke\",294,0,\"extend32_s\",[\"i64:81985526906748928\"]],[\"invoke\",295,0,\"extend32_s\",[\"i64:18364758544655319040\"]],[\"invoke\",296,0,\"extend32_s\",[\"i64:18446744073709551615\"]],[\"invoke\",298,0,\"eqz\",[\"i64:0\"]],[\"invoke\",299,0,\"eqz\",[\"i64:1\"]],[\"invoke\",300,0,\"eqz\",[\"i64:9223372036854775808\"]],[\"invoke\",301,0,\"eqz\",[\"i64:9223372036854775807\"]],[\"invoke\",302,0,\"eqz\",[\"i64:18446744073709551615\"]],[\"invoke\",304,0,\"eq\",[\"i64:0\",\"i64:0\"]],[\"invoke\",305,0,\"eq\",[\"i64:1\",\"i64:1\"]],[\"invoke\",306,0,\"eq\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",307,0,\"eq\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",308,0,\"eq\",[\"i64:9223372036854775807\",\"i64:9223372036854775807\"]],[\"invoke\",309,0,\"eq\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",310,0,\"eq\",[\"i64:1\",\"i64:0\"]],[\"invoke\",311,0,\"eq\",[\"i64:0\",\"i64:1\"]],[\"invoke\",312,0,\"eq\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",313,0,\"eq\",[\"i64:0\",\"i64:9223372036854775808\"]],[\"invoke\",314,0,\"eq\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",315,0,\"eq\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",316,0,\"eq\",[\"i64:9223372036854775808\",\"i64:9223372036854775807\"]],[\"invoke\",317,0,\"eq\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",319,0,\"ne\",[\"i64:0\",\"i64:0\"]],[\"invoke\",320,0,\"ne\",[\"i64:1\",\"i64:1\"]],[\"invoke\",321,0,\"ne\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",322,0,\"ne\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",323,0,\"ne\",[\"i64:9223372036854775807\",\"i64:9223372036854775807\"]],[\"invoke\",324,0,\"ne\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",325,0,\"ne\",[\"i64:1\",\"i64:0\"]],[\"invoke\",326,0,\"ne\",[\"i64:0\",\"i64:1\"]],[\"invoke\",327,0,\"ne\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",328,0,\"ne\",[\"i64:0\",\"i64:9223372036854775808\"]],[\"invoke\",329,0,\"ne\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",330,0,\"ne\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",331,0,\"ne\",[\"i64:9223372036854775808\",\"i64:9223372036854775807\"]],[\"invoke\",332,0,\"ne\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",334,0,\"lt_s\",[\"i64:0\",\"i64:0\"]],[\"invoke\",335,0,\"lt_s\",[\"i64:1\",\"i64:1\"]],[\"invoke\",336,0,\"lt_s\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",337,0,\"lt_s\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",338,0,\"lt_s\",[\"i64:9223372036854775807\",\"i64:9223372036854775807\"]],[\"invoke\",339,0,\"lt_s\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",340,0,\"lt_s\",[\"i64:1\",\"i64:0\"]],[\"invoke\",341,0,\"lt_s\",[\"i64:0\",\"i64:1\"]],[\"invoke\",342,0,\"lt_s\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",343,0,\"lt_s\",[\"i64:0\",\"i64:9223372036854775808\"]],[\"invoke\",344,0,\"lt_s\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",345,0,\"lt_s\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",346,0,\"lt_s\",[\"i64:9223372036854775808\",\"i64:9223372036854775807\"]],[\"invoke\",347,0,\"lt_s\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",349,0,\"lt_u\",[\"i64:0\",\"i64:0\"]],[\"invoke\",350,0,\"lt_u\",[\"i64:1\",\"i64:1\"]],[\"invoke\",351,0,\"lt_u\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",352,0,\"lt_u\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",353,0,\"lt_u\",[\"i64:9223372036854775807\",\"i64:9223372036854775807\"]],[\"invoke\",354,0,\"lt_u\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",355,0,\"lt_u\",[\"i64:1\",\"i64:0\"]],[\"invoke\",356,0,\"lt_u\",[\"i64:0\",\"i64:1\"]],[\"invoke\",357,0,\"lt_u\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",358,0,\"lt_u\",[\"i64:0\",\"i64:9223372036854775808\"]],[\"invoke\",359,0,\"lt_u\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",360,0,\"lt_u\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",361,0,\"lt_u\",[\"i64:9223372036854775808\",\"i64:9223372036854775807\"]],[\"invoke\",362,0,\"lt_u\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",364,0,\"le_s\",[\"i64:0\",\"i64:0\"]],[\"invoke\",365,0,\"le_s\",[\"i64:1\",\"i64:1\"]],[\"invoke\",366,0,\"le_s\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",367,0,\"le_s\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",368,0,\"le_s\",[\"i64:9223372036854775807\",\"i64:9223372036854775807\"]],[\"invoke\",369,0,\"le_s\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",370,0,\"le_s\",[\"i64:1\",\"i64:0\"]],[\"invoke\",371,0,\"le_s\",[\"i64:0\",\"i64:1\"]],[\"invoke\",372,0,\"le_s\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",373,0,\"le_s\",[\"i64:0\",\"i64:9223372036854775808\"]],[\"invoke\",374,0,\"le_s\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",375,0,\"le_s\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",376,0,\"le_s\",[\"i64:9223372036854775808\",\"i64:9223372036854775807\"]],[\"invoke\",377,0,\"le_s\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",379,0,\"le_u\",[\"i64:0\",\"i64:0\"]],[\"invoke\",380,0,\"le_u\",[\"i64:1\",\"i64:1\"]],[\"invoke\",381,0,\"le_u\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",382,0,\"le_u\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",383,0,\"le_u\",[\"i64:9223372036854775807\",\"i64:9223372036854775807\"]],[\"invoke\",384,0,\"le_u\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",385,0,\"le_u\",[\"i64:1\",\"i64:0\"]],[\"invoke\",386,0,\"le_u\",[\"i64:0\",\"i64:1\"]],[\"invoke\",387,0,\"le_u\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",388,0,\"le_u\",[\"i64:0\",\"i64:9223372036854775808\"]],[\"invoke\",389,0,\"le_u\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",390,0,\"le_u\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",391,0,\"le_u\",[\"i64:9223372036854775808\",\"i64:9223372036854775807\"]],[\"invoke\",392,0,\"le_u\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",394,0,\"gt_s\",[\"i64:0\",\"i64:0\"]],[\"invoke\",395,0,\"gt_s\",[\"i64:1\",\"i64:1\"]],[\"invoke\",396,0,\"gt_s\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",397,0,\"gt_s\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",398,0,\"gt_s\",[\"i64:9223372036854775807\",\"i64:9223372036854775807\"]],[\"invoke\",399,0,\"gt_s\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",400,0,\"gt_s\",[\"i64:1\",\"i64:0\"]],[\"invoke\",401,0,\"gt_s\",[\"i64:0\",\"i64:1\"]],[\"invoke\",402,0,\"gt_s\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",403,0,\"gt_s\",[\"i64:0\",\"i64:9223372036854775808\"]],[\"invoke\",404,0,\"gt_s\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",405,0,\"gt_s\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",406,0,\"gt_s\",[\"i64:9223372036854775808\",\"i64:9223372036854775807\"]],[\"invoke\",407,0,\"gt_s\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",409,0,\"gt_u\",[\"i64:0\",\"i64:0\"]],[\"invoke\",410,0,\"gt_u\",[\"i64:1\",\"i64:1\"]],[\"invoke\",411,0,\"gt_u\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",412,0,\"gt_u\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",413,0,\"gt_u\",[\"i64:9223372036854775807\",\"i64:9223372036854775807\"]],[\"invoke\",414,0,\"gt_u\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",415,0,\"gt_u\",[\"i64:1\",\"i64:0\"]],[\"invoke\",416,0,\"gt_u\",[\"i64:0\",\"i64:1\"]],[\"invoke\",417,0,\"gt_u\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",418,0,\"gt_u\",[\"i64:0\",\"i64:9223372036854775808\"]],[\"invoke\",419,0,\"gt_u\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",420,0,\"gt_u\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",421,0,\"gt_u\",[\"i64:9223372036854775808\",\"i64:9223372036854775807\"]],[\"invoke\",422,0,\"gt_u\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",424,0,\"ge_s\",[\"i64:0\",\"i64:0\"]],[\"invoke\",425,0,\"ge_s\",[\"i64:1\",\"i64:1\"]],[\"invoke\",426,0,\"ge_s\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",427,0,\"ge_s\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",428,0,\"ge_s\",[\"i64:9223372036854775807\",\"i64:9223372036854775807\"]],[\"invoke\",429,0,\"ge_s\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",430,0,\"ge_s\",[\"i64:1\",\"i64:0\"]],[\"invoke\",431,0,\"ge_s\",[\"i64:0\",\"i64:1\"]],[\"invoke\",432,0,\"ge_s\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",433,0,\"ge_s\",[\"i64:0\",\"i64:9223372036854775808\"]],[\"invoke\",434,0,\"ge_s\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",435,0,\"ge_s\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",436,0,\"ge_s\",[\"i64:9223372036854775808\",\"i64:9223372036854775807\"]],[\"invoke\",437,0,\"ge_s\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"invoke\",439,0,\"ge_u\",[\"i64:0\",\"i64:0\"]],[\"invoke\",440,0,\"ge_u\",[\"i64:1\",\"i64:1\"]],[\"invoke\",441,0,\"ge_u\",[\"i64:18446744073709551615\",\"i64:1\"]],[\"invoke\",442,0,\"ge_u\",[\"i64:9223372036854775808\",\"i64:9223372036854775808\"]],[\"invoke\",443,0,\"ge_u\",[\"i64:9223372036854775807\",\"i64:9223372036854775807\"]],[\"invoke\",444,0,\"ge_u\",[\"i64:18446744073709551615\",\"i64:18446744073709551615\"]],[\"invoke\",445,0,\"ge_u\",[\"i64:1\",\"i64:0\"]],[\"invoke\",446,0,\"ge_u\",[\"i64:0\",\"i64:1\"]],[\"invoke\",447,0,\"ge_u\",[\"i64:9223372036854775808\",\"i64:0\"]],[\"invoke\",448,0,\"ge_u\",[\"i64:0\",\"i64:9223372036854775808\"]],[\"invoke\",449,0,\"ge_u\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"invoke\",450,0,\"ge_u\",[\"i64:18446744073709551615\",\"i64:9223372036854775808\"]],[\"invoke\",451,0,\"ge_u\",[\"i64:9223372036854775808\",\"i64:9223372036854775807\"]],[\"invoke\",452,0,\"ge_u\",[\"i64:9223372036854775807\",\"i64:9223372036854775808\"]],[\"file\",\"int_exprs.wast\"],[\"module\",6,2],[\"invoke\",18,0,\"i32.no_fold_cmp_s_offset\",[\"i32:2147483647\",\"i32:0\"]],[\"invoke\",19,0,\"i32.no_fold_cmp_u_offset\",[\"i32:4294967295\",\"i32:0\"]],[\"invoke\",20,0,\"i64.no_fold_cmp_s_offset\",[\"i64:9223372036854775807\",\"i64:0\"]],[\"invoke\",21,0,\"i64.no_fold_cmp_u_offset\",[\"i64:18446744073709551615\",\"i64:0\"]],[\"module\",25,3],[\"invoke\",30,0,\"i64.no_fold_wrap_extend_s\",[\"i64:4538991236898928\"]],[\"invoke\",31,0,\"i64.no_fold_wrap_extend_s\",[\"i64:45230338458316960\"]],[\"module\",35,4],[\"invoke\",40,0,\"i64.no_fold_wrap_extend_u\",[\"i64:4538991236898928\"]],[\"module\",44,5],[\"invoke\",56,0,\"i32.no_fold_shl_shr_s\",[\"i32:2147483648\"]],[\"invoke\",57,0,\"i32.no_fold_shl_shr_u\",[\"i32:2147483648\"]],[\"invoke\",58,0,\"i64.no_fold_shl_shr_s\",[\"i64:9223372036854775808\"]],[\"invoke\",59,0,\"i64.no_fold_shl_shr_u\",[\"i64:9223372036854775808\"]],[\"module\",63,6],[\"invoke\",75,0,\"i32.no_fold_shr_s_shl\",[\"i32:1\"]],[\"invoke\",76,0,\"i32.no_fold_shr_u_shl\",[\"i32:1\"]],[\"invoke\",77,0,\"i64.no_fold_shr_s_shl\",[\"i64:1\"]],[\"invoke\",78,0,\"i64.no_fold_shr_u_shl\",[\"i64:1\"]],[\"module\",82,7],[\"invoke\",94,0,\"i32.no_fold_div_s_mul\",[\"i32:1\"]],[\"invoke\",95,0,\"i32.no_fold_div_u_mul\",[\"i32:1\"]],[\"invoke\",96,0,\"i64.no_fold_div_s_mul\",[\"i64:1\"]],[\"invoke\",97,0,\"i64.no_fold_div_u_mul\",[\"i64:1\"]],[\"module\",101,8],[\"invoke\",113,0,\"i32.no_fold_div_s_self\",[\"i32:0\"]],[\"invoke\",114,0,\"i32.no_fold_div_u_self\",[\"i32:0\"]],[\"invoke\",115,0,\"i64.no_fold_div_s_self\",[\"i64:0\"]],[\"invoke\",116,0,\"i64.no_fold_div_u_self\",[\"i64:0\"]],[\"module\",120,9],[\"invoke\",132,0,\"i32.no_fold_rem_s_self\",[\"i32:0\"]],[\"invoke\",133,0,\"i32.no_fold_rem_u_self\",[\"i32:0\"]],[\"invoke\",134,0,\"i64.no_fold_rem_s_self\",[\"i64:0\"]],[\"invoke\",135,0,\"i64.no_fold_rem_u_self\",[\"i64:0\"]],[\"module\",139,10],[\"invoke\",151,0,\"i32.no_fold_mul_div_s\",[\"i32:2147483648\"]],[\"invoke\",152,0,\"i32.no_fold_mul_div_u\",[\"i32:2147483648\"]],[\"invoke\",153,0,\"i64.no_fold_mul_div_s\",[\"i64:9223372036854775808\"]],[\"invoke\",154,0,\"i64.no_fold_mul_div_u\",[\"i64:9223372036854775808\"]],[\"module\",158,11],[\"invoke\",166,0,\"i32.no_fold_div_s_2\",[\"i32:4294967285\"]],[\"invoke\",167,0,\"i64.no_fold_div_s_2\",[\"i64:18446744073709551605\"]],[\"module\",171,12],[\"invoke\",179,0,\"i32.no_fold_rem_s_2\",[\"i32:4294967285\"]],[\"invoke\",180,0,\"i64.no_fold_rem_s_2\",[\"i64:18446744073709551605\"]],[\"module\",184,13],[\"invoke\",196,0,\"i32.div_s_0\",[\"i32:71\"]],[\"invoke\",197,0,\"i32.div_u_0\",[\"i32:71\"]],[\"invoke\",198,0,\"i64.div_s_0\",[\"i64:71\"]],[\"invoke\",199,0,\"i64.div_u_0\",[\"i64:71\"]],[\"module\",203,14],[\"invoke\",215,0,\"i32.div_s_3\",[\"i32:71\"]],[\"invoke\",216,0,\"i32.div_s_3\",[\"i32:1610612736\"]],[\"invoke\",217,0,\"i32.div_u_3\",[\"i32:71\"]],[\"invoke\",218,0,\"i32.div_u_3\",[\"i32:3221225472\"]],[\"invoke\",219,0,\"i64.div_s_3\",[\"i64:71\"]],[\"invoke\",220,0,\"i64.div_s_3\",[\"i64:3458764513820540928\"]],[\"invoke\",221,0,\"i64.div_u_3\",[\"i64:71\"]],[\"invoke\",222,0,\"i64.div_u_3\",[\"i64:13835058055282163712\"]],[\"module\",226,15],[\"invoke\",238,0,\"i32.div_s_5\",[\"i32:71\"]],[\"invoke\",239,0,\"i32.div_s_5\",[\"i32:1342177280\"]],[\"invoke\",240,0,\"i32.div_u_5\",[\"i32:71\"]],[\"invoke\",241,0,\"i32.div_u_5\",[\"i32:2684354560\"]],[\"invoke\",242,0,\"i64.div_s_5\",[\"i64:71\"]],[\"invoke\",243,0,\"i64.div_s_5\",[\"i64:5764607523034234880\"]],[\"invoke\",244,0,\"i64.div_u_5\",[\"i64:71\"]],[\"invoke\",245,0,\"i64.div_u_5\",[\"i64:11529215046068469760\"]],[\"module\",249,16],[\"invoke\",261,0,\"i32.div_s_7\",[\"i32:71\"]],[\"invoke\",262,0,\"i32.div_s_7\",[\"i32:1879048192\"]],[\"invoke\",263,0,\"i32.div_u_7\",[\"i32:71\"]],[\"invoke\",264,0,\"i32.div_u_7\",[\"i32:3758096384\"]],[\"invoke\",265,0,\"i64.div_s_7\",[\"i64:71\"]],[\"invoke\",266,0,\"i64.div_s_7\",[\"i64:8070450532247928832\"]],[\"invoke\",267,0,\"i64.div_u_7\",[\"i64:71\"]],[\"invoke\",268,0,\"i64.div_u_7\",[\"i64:16140901064495857664\"]],[\"module\",272,17],[\"invoke\",284,0,\"i32.rem_s_3\",[\"i32:71\"]],[\"invoke\",285,0,\"i32.rem_s_3\",[\"i32:1610612736\"]],[\"invoke\",286,0,\"i32.rem_u_3\",[\"i32:71\"]],[\"invoke\",287,0,\"i32.rem_u_3\",[\"i32:3221225472\"]],[\"invoke\",288,0,\"i64.rem_s_3\",[\"i64:71\"]],[\"invoke\",289,0,\"i64.rem_s_3\",[\"i64:3458764513820540928\"]],[\"invoke\",290,0,\"i64.rem_u_3\",[\"i64:71\"]],[\"invoke\",291,0,\"i64.rem_u_3\",[\"i64:13835058055282163712\"]],[\"module\",295,18],[\"invoke\",307,0,\"i32.rem_s_5\",[\"i32:71\"]],[\"invoke\",308,0,\"i32.rem_s_5\",[\"i32:1342177280\"]],[\"invoke\",309,0,\"i32.rem_u_5\",[\"i32:71\"]],[\"invoke\",310,0,\"i32.rem_u_5\",[\"i32:2684354560\"]],[\"invoke\",311,0,\"i64.rem_s_5\",[\"i64:71\"]],[\"invoke\",312,0,\"i64.rem_s_5\",[\"i64:5764607523034234880\"]],[\"invoke\",313,0,\"i64.rem_u_5\",[\"i64:71\"]],[\"invoke\",314,0,\"i64.rem_u_5\",[\"i64:11529215046068469760\"]],[\"module\",318,19],[\"invoke\",330,0,\"i32.rem_s_7\",[\"i32:71\"]],[\"invoke\",331,0,\"i32.rem_s_7\",[\"i32:1879048192\"]],[\"invoke\",332,0,\"i32.rem_u_7\",[\"i32:71\"]],[\"invoke\",333,0,\"i32.rem_u_7\",[\"i32:3758096384\"]],[\"invoke\",334,0,\"i64.rem_s_7\",[\"i64:71\"]],[\"invoke\",335,0,\"i64.rem_s_7\",[\"i64:8070450532247928832\"]],[\"invoke\",336,0,\"i64.rem_u_7\",[\"i64:71\"]],[\"invoke\",337,0,\"i64.rem_u_7\",[\"i64:16140901064495857664\"]],[\"module\",341,20],[\"invoke\",349,0,\"i32.no_fold_div_neg1\",[\"i32:2147483648\"]],[\"invoke\",350,0,\"i64.no_fold_div_neg1\",[\"i64:9223372036854775808\"]],[\"file\",\"int_literals.wast\"],[\"module\",1,21],[\"invoke\",37,0,\"i32.test\",[]],[\"invoke\",38,0,\"i32.umax\",[]],[\"invoke\",39,0,\"i32.smax\",[]],[\"invoke\",40,0,\"i32.neg_smax\",[]],[\"invoke\",41,0,\"i32.smin\",[]],[\"invoke\",42,0,\"i32.alt_smin\",[]],[\"invoke\",43,0,\"i32.inc_smin\",[]],[\"invoke\",44,0,\"i32.neg_zero\",[]],[\"invoke\",45,0,\"i32.not_octal\",[]],[\"invoke\",46,0,\"i32.unsigned_decimal\",[]],[\"invoke\",47,0,\"i32.plus_sign\",[]],[\"invoke\",49,0,\"i64.test\",[]],[\"invoke\",50,0,\"i64.umax\",[]],[\"invoke\",51,0,\"i64.smax\",[]],[\"invoke\",52,0,\"i64.neg_smax\",[]],[\"invoke\",53,0,\"i64.smin\",[]],[\"invoke\",54,0,\"i64.alt_smin\",[]],[\"invoke\",55,0,\"i64.inc_smin\",[]],[\"invoke\",56,0,\"i64.neg_zero\",[]],[\"invoke\",57,0,\"i64.not_octal\",[]],[\"invoke\",58,0,\"i64.unsigned_decimal\",[]],[\"invoke\",59,0,\"i64.plus_sign\",[]],[\"invoke\",61,0,\"i32-dec-sep1\",[]],[\"invoke\",62,0,\"i32-dec-sep2\",[]],[\"invoke\",63,0,\"i32-hex-sep1\",[]],[\"invoke\",64,0,\"i32-hex-sep2\",[]],[\"invoke\",66,0,\"i64-dec-sep1\",[]],[\"invoke\",67,0,\"i64-dec-sep2\",[]],[\"invoke\",68,0,\"i64-hex-sep1\",[]],[\"invoke\",69,0,\"i64-hex-sep2\",[]],[\"file\",\"conversions.wast\"],[\"module\",1,22],[\"invoke\",37,0,\"i64.extend_i32_s\",[\"i32:0\"]],[\"invoke\",39,0,\"i64.extend_i32_s\",[\"i32:4294957296\"]],[\"invoke\",40,0,\"i64.extend_i32_s\",[\"i32:4294967295\"]],[\"invoke\",42,0,\"i64.extend_i32_s\",[\"i32:2147483648\"]],[\"invoke\",44,0,\"i64.extend_i32_u\",[\"i32:0\"]],[\"invoke\",45,0,\"i64.extend_i32_u\",[\"i32:10000\"]],[\"invoke\",47,0,\"i64.extend_i32_u\",[\"i32:4294967295\"]],[\"invoke\",48,0,\"i64.extend_i32_u\",[\"i32:2147483647\"]],[\"invoke\",51,0,\"i32.wrap_i64\",[\"i64:18446744073709551615\"]],[\"invoke\",52,0,\"i32.wrap_i64\",[\"i64:18446744073709451616\"]],[\"invoke\",53,0,\"i32.wrap_i64\",[\"i64:2147483648\"]],[\"invoke\",55,0,\"i32.wrap_i64\",[\"i64:18446744069414584320\"]],[\"invoke\",56,0,\"i32.wrap_i64\",[\"i64:18446744069414584319\"]],[\"invoke\",57,0,\"i32.wrap_i64\",[\"i64:18446744069414584321\"]],[\"invoke\",59,0,\"i32.wrap_i64\",[\"i64:1311768467463790320\"]],[\"invoke\",60,0,\"i32.wrap_i64\",[\"i64:4294967295\"]],[\"invoke\",62,0,\"i32.wrap_i64\",[\"i64:4294967297\"]],[\"invoke\",64,0,\"i32.trunc_f32_s\",[\"f32:0\"]],[\"invoke\",65,0,\"i32.trunc_f32_s\",[\"f32:2147483648\"]],[\"invoke\",67,0,\"i32.trunc_f32_s\",[\"f32:2147483649\"]],[\"invoke\",68,0,\"i32.trunc_f32_s\",[\"f32:1065353216\"]],[\"invoke\",69,0,\"i32.trunc_f32_s\",[\"f32:1066192077\"]],[\"invoke\",71,0,\"i32.trunc_f32_s\",[\"f32:3212836864\"]],[\"invoke\",72,0,\"i32.trunc_f32_s\",[\"f32:3213675725\"]],[\"invoke\",74,0,\"i32.trunc_f32_s\",[\"f32:3220386611\"]],[\"invoke\",75,0,\"i32.trunc_f32_s\",[\"f32:3221225472\"]],[\"invoke\",76,0,\"i32.trunc_f32_s\",[\"f32:1325400063\"]],[\"invoke\",78,0,\"i32.trunc_f32_s\",[\"f32:1325400064\"]],[\"invoke\",79,0,\"i32.trunc_f32_s\",[\"f32:3472883713\"]],[\"invoke\",80,0,\"i32.trunc_f32_s\",[\"f32:2139095040\"]],[\"invoke\",82,0,\"i32.trunc_f32_s\",[\"f32:2143289344\"]],[\"invoke\",84,0,\"i32.trunc_f32_s\",[\"f32:4290772992\"]],[\"invoke\",88,0,\"i32.trunc_f32_u\",[\"f32:2147483648\"]],[\"invoke\",89,0,\"i32.trunc_f32_u\",[\"f32:1\"]],[\"invoke\",90,0,\"i32.trunc_f32_u\",[\"f32:2147483649\"]],[\"invoke\",92,0,\"i32.trunc_f32_u\",[\"f32:1066192077\"]],[\"invoke\",93,0,\"i32.trunc_f32_u\",[\"f32:1069547520\"]],[\"invoke\",94,0,\"i32.trunc_f32_u\",[\"f32:1072902963\"]],[\"invoke\",96,0,\"i32.trunc_f32_u\",[\"f32:1325400064\"]],[\"invoke\",97,0,\"i32.trunc_f32_u\",[\"f32:1333788671\"]],[\"invoke\",99,0,\"i32.trunc_f32_u\",[\"f32:3212836863\"]],[\"invoke\",100,0,\"i32.trunc_f32_u\",[\"f32:1333788672\"]],[\"invoke\",101,0,\"i32.trunc_f32_u\",[\"f32:3212836864\"]],[\"invoke\",103,0,\"i32.trunc_f32_u\",[\"f32:4286578688\"]],[\"invoke\",104,0,\"i32.trunc_f32_u\",[\"f32:2143289344\"]],[\"invoke\",106,0,\"i32.trunc_f32_u\",[\"f32:4290772992\"]],[\"invoke\",110,0,\"i32.trunc_f64_s\",[\"f64:9223372036854775808\"]],[\"invoke\",111,0,\"i32.trunc_f64_s\",[\"f64:1\"]],[\"invoke\",113,0,\"i32.trunc_f64_s\",[\"f64:4607182418800017408\"]],[\"invoke\",114,0,\"i32.trunc_f64_s\",[\"f64:4607632778762754458\"]],[\"invoke\",115,0,\"i32.trunc_f64_s\",[\"f64:4609434218613702656\"]],[\"invoke\",117,0,\"i32.trunc_f64_s\",[\"f64:13831004815617530266\"]],[\"invoke\",118,0,\"i32.trunc_f64_s\",[\"f64:13832806255468478464\"]],[\"invoke\",120,0,\"i32.trunc_f64_s\",[\"f64:13835058055282163712\"]],[\"invoke\",121,0,\"i32.trunc_f64_s\",[\"f64:4746794007244308480\"]],[\"invoke\",122,0,\"i32.trunc_f64_s\",[\"f64:13970166044103278592\"]],[\"invoke\",124,0,\"i32.trunc_f64_s\",[\"f64:4746794007248083354\"]],[\"invoke\",125,0,\"i32.trunc_f64_s\",[\"f64:4746794007248502784\"]],[\"invoke\",126,0,\"i32.trunc_f64_s\",[\"f64:13970166044105375744\"]],[\"invoke\",128,0,\"i32.trunc_f64_s\",[\"f64:18442240474082181120\"]],[\"invoke\",129,0,\"i32.trunc_f64_s\",[\"f64:9221120237041090560\"]],[\"invoke\",134,0,\"i32.trunc_f64_u\",[\"f64:0\"]],[\"invoke\",135,0,\"i32.trunc_f64_u\",[\"f64:9223372036854775808\"]],[\"invoke\",136,0,\"i32.trunc_f64_u\",[\"f64:1\"]],[\"invoke\",138,0,\"i32.trunc_f64_u\",[\"f64:4607182418800017408\"]],[\"invoke\",139,0,\"i32.trunc_f64_u\",[\"f64:4607632778762754458\"]],[\"invoke\",140,0,\"i32.trunc_f64_u\",[\"f64:4609434218613702656\"]],[\"invoke\",142,0,\"i32.trunc_f64_u\",[\"f64:4611686018427387904\"]],[\"invoke\",143,0,\"i32.trunc_f64_u\",[\"f64:4746794007248502784\"]],[\"invoke\",145,0,\"i32.trunc_f64_u\",[\"f64:13829653735729319117\"]],[\"invoke\",146,0,\"i32.trunc_f64_u\",[\"f64:13830554455654793215\"]],[\"invoke\",147,0,\"i32.trunc_f64_u\",[\"f64:4726483295884279808\"]],[\"invoke\",149,0,\"i32.trunc_f64_u\",[\"f64:4751297606875663565\"]],[\"invoke\",150,0,\"i32.trunc_f64_u\",[\"f64:4751297606875873280\"]],[\"invoke\",151,0,\"i32.trunc_f64_u\",[\"f64:13830554455654793216\"]],[\"invoke\",153,0,\"i32.trunc_f64_u\",[\"f64:5055640609639927018\"]],[\"invoke\",154,0,\"i32.trunc_f64_u\",[\"f64:4890909195324358656\"]],[\"invoke\",156,0,\"i32.trunc_f64_u\",[\"f64:18442240474082181120\"]],[\"invoke\",157,0,\"i32.trunc_f64_u\",[\"f64:9221120237041090560\"]],[\"invoke\",159,0,\"i32.trunc_f64_u\",[\"f64:18444492273895866368\"]],[\"invoke\",163,0,\"i64.trunc_f32_s\",[\"f32:2147483648\"]],[\"invoke\",164,0,\"i64.trunc_f32_s\",[\"f32:1\"]],[\"invoke\",165,0,\"i64.trunc_f32_s\",[\"f32:2147483649\"]],[\"invoke\",167,0,\"i64.trunc_f32_s\",[\"f32:1066192077\"]],[\"invoke\",168,0,\"i64.trunc_f32_s\",[\"f32:1069547520\"]],[\"invoke\",170,0,\"i64.trunc_f32_s\",[\"f32:3213675725\"]],[\"invoke\",171,0,\"i64.trunc_f32_s\",[\"f32:3217031168\"]],[\"invoke\",172,0,\"i64.trunc_f32_s\",[\"f32:3220386611\"]],[\"invoke\",174,0,\"i64.trunc_f32_s\",[\"f32:1333788672\"]],[\"invoke\",175,0,\"i64.trunc_f32_s\",[\"f32:3481272320\"]],[\"invoke\",176,0,\"i64.trunc_f32_s\",[\"f32:1593835519\"]],[\"invoke\",178,0,\"i64.trunc_f32_s\",[\"f32:1593835520\"]],[\"invoke\",179,0,\"i64.trunc_f32_s\",[\"f32:3741319169\"]],[\"invoke\",181,0,\"i64.trunc_f32_s\",[\"f32:4286578688\"]],[\"invoke\",182,0,\"i64.trunc_f32_s\",[\"f32:2143289344\"]],[\"invoke\",184,0,\"i64.trunc_f32_s\",[\"f32:4290772992\"]],[\"invoke\",188,0,\"i64.trunc_f32_u\",[\"f32:2147483648\"]],[\"invoke\",189,0,\"i64.trunc_f32_u\",[\"f32:1\"]],[\"invoke\",190,0,\"i64.trunc_f32_u\",[\"f32:2147483649\"]],[\"invoke\",192,0,\"i64.trunc_f32_u\",[\"f32:1066192077\"]],[\"invoke\",193,0,\"i64.trunc_f32_u\",[\"f32:1069547520\"]],[\"invoke\",195,0,\"i64.trunc_f32_u\",[\"f32:1602224127\"]],[\"invoke\",196,0,\"i64.trunc_f32_u\",[\"f32:3211159142\"]],[\"invoke\",197,0,\"i64.trunc_f32_u\",[\"f32:3212836863\"]],[\"invoke\",199,0,\"i64.trunc_f32_u\",[\"f32:3212836864\"]],[\"invoke\",200,0,\"i64.trunc_f32_u\",[\"f32:2139095040\"]],[\"invoke\",202,0,\"i64.trunc_f32_u\",[\"f32:2143289344\"]],[\"invoke\",204,0,\"i64.trunc_f32_u\",[\"f32:4290772992\"]],[\"invoke\",207,0,\"i64.trunc_f64_s\",[\"f64:0\"]],[\"invoke\",209,0,\"i64.trunc_f64_s\",[\"f64:1\"]],[\"invoke\",210,0,\"i64.trunc_f64_s\",[\"f64:9223372036854775809\"]],[\"invoke\",211,0,\"i64.trunc_f64_s\",[\"f64:4607182418800017408\"]],[\"invoke\",213,0,\"i64.trunc_f64_s\",[\"f64:4609434218613702656\"]],[\"invoke\",214,0,\"i64.trunc_f64_s\",[\"f64:13830554455654793216\"]],[\"invoke\",216,0,\"i64.trunc_f64_s\",[\"f64:13832806255468478464\"]],[\"invoke\",217,0,\"i64.trunc_f64_s\",[\"f64:13834607695319426662\"]],[\"invoke\",218,0,\"i64.trunc_f64_s\",[\"f64:13835058055282163712\"]],[\"invoke\",220,0,\"i64.trunc_f64_s\",[\"f64:13974669643730649088\"]],[\"invoke\",221,0,\"i64.trunc_f64_s\",[\"f64:4890909195324358655\"]],[\"invoke\",222,0,\"i64.trunc_f64_s\",[\"f64:14114281232179134464\"]],[\"invoke\",224,0,\"i64.trunc_f64_s\",[\"f64:14114281232179134465\"]],[\"invoke\",225,0,\"i64.trunc_f64_s\",[\"f64:9218868437227405312\"]],[\"invoke\",227,0,\"i64.trunc_f64_s\",[\"f64:9221120237041090560\"]],[\"invoke\",229,0,\"i64.trunc_f64_s\",[\"f64:18444492273895866368\"]],[\"invoke\",232,0,\"i64.trunc_f64_u\",[\"f64:0\"]],[\"invoke\",234,0,\"i64.trunc_f64_u\",[\"f64:1\"]],[\"invoke\",235,0,\"i64.trunc_f64_u\",[\"f64:9223372036854775809\"]],[\"invoke\",236,0,\"i64.trunc_f64_u\",[\"f64:4607182418800017408\"]],[\"invoke\",238,0,\"i64.trunc_f64_u\",[\"f64:4609434218613702656\"]],[\"invoke\",239,0,\"i64.trunc_f64_u\",[\"f64:4751297606873776128\"]],[\"invoke\",241,0,\"i64.trunc_f64_u\",[\"f64:4895412794951729151\"]],[\"invoke\",242,0,\"i64.trunc_f64_u\",[\"f64:13829653735729319117\"]],[\"invoke\",243,0,\"i64.trunc_f64_u\",[\"f64:13830554455654793215\"]],[\"invoke\",245,0,\"i64.trunc_f64_u\",[\"f64:4846369599423283200\"]],[\"invoke\",246,0,\"i64.trunc_f64_u\",[\"f64:4890909195324358656\"]],[\"invoke\",247,0,\"i64.trunc_f64_u\",[\"f64:4895412794951729152\"]],[\"invoke\",249,0,\"i64.trunc_f64_u\",[\"f64:9218868437227405312\"]],[\"invoke\",250,0,\"i64.trunc_f64_u\",[\"f64:18442240474082181120\"]],[\"invoke\",253,0,\"i64.trunc_f64_u\",[\"f64:18444492273895866368\"]],[\"invoke\",256,0,\"f32.convert_i32_s\",[\"i32:1\"]],[\"invoke\",257,0,\"f32.convert_i32_s\",[\"i32:4294967295\"]],[\"invoke\",259,0,\"f32.convert_i32_s\",[\"i32:2147483647\"]],[\"invoke\",260,0,\"f32.convert_i32_s\",[\"i32:2147483648\"]],[\"invoke\",261,0,\"f32.convert_i32_s\",[\"i32:1234567890\"]],[\"invoke\",266,0,\"i32.trunc_sat_f32_s\",[\"f32:2147483648\"]],[\"invoke\",267,0,\"i32.trunc_sat_f32_s\",[\"f32:1\"]],[\"invoke\",269,0,\"i32.trunc_sat_f32_s\",[\"f32:1065353216\"]],[\"invoke\",270,0,\"i32.trunc_sat_f32_s\",[\"f32:1066192077\"]],[\"invoke\",271,0,\"i32.trunc_sat_f32_s\",[\"f32:1069547520\"]],[\"invoke\",273,0,\"i32.trunc_sat_f32_s\",[\"f32:3213675725\"]],[\"invoke\",274,0,\"i32.trunc_sat_f32_s\",[\"f32:3217031168\"]],[\"invoke\",276,0,\"i32.trunc_sat_f32_s\",[\"f32:3221225472\"]],[\"invoke\",277,0,\"i32.trunc_sat_f32_s\",[\"f32:1325400063\"]],[\"invoke\",278,0,\"i32.trunc_sat_f32_s\",[\"f32:3472883712\"]],[\"invoke\",280,0,\"i32.trunc_sat_f32_s\",[\"f32:3472883713\"]],[\"invoke\",281,0,\"i32.trunc_sat_f32_s\",[\"f32:2139095040\"]],[\"invoke\",282,0,\"i32.trunc_sat_f32_s\",[\"f32:4286578688\"]],[\"invoke\",285,0,\"i32.trunc_sat_f32_s\",[\"f32:4290772992\"]],[\"invoke\",288,0,\"i32.trunc_sat_f32_u\",[\"f32:0\"]],[\"invoke\",290,0,\"i32.trunc_sat_f32_u\",[\"f32:1\"]],[\"invoke\",291,0,\"i32.trunc_sat_f32_u\",[\"f32:2147483649\"]],[\"invoke\",292,0,\"i32.trunc_sat_f32_u\",[\"f32:1065353216\"]],[\"invoke\",294,0,\"i32.trunc_sat_f32_u\",[\"f32:1069547520\"]],[\"invoke\",295,0,\"i32.trunc_sat_f32_u\",[\"f32:1072902963\"]],[\"invoke\",296,0,\"i32.trunc_sat_f32_u\",[\"f32:1073741824\"]],[\"invoke\",298,0,\"i32.trunc_sat_f32_u\",[\"f32:1333788671\"]],[\"invoke\",299,0,\"i32.trunc_sat_f32_u\",[\"f32:3211159142\"]],[\"invoke\",301,0,\"i32.trunc_sat_f32_u\",[\"f32:1333788672\"]],[\"invoke\",302,0,\"i32.trunc_sat_f32_u\",[\"f32:3212836864\"]],[\"invoke\",303,0,\"i32.trunc_sat_f32_u\",[\"f32:2139095040\"]],[\"invoke\",305,0,\"i32.trunc_sat_f32_u\",[\"f32:2143289344\"]],[\"invoke\",307,0,\"i32.trunc_sat_f32_u\",[\"f32:4290772992\"]],[\"invoke\",310,0,\"i32.trunc_sat_f64_s\",[\"f64:0\"]],[\"invoke\",312,0,\"i32.trunc_sat_f64_s\",[\"f64:1\"]],[\"invoke\",313,0,\"i32.trunc_sat_f64_s\",[\"f64:9223372036854775809\"]],[\"invoke\",315,0,\"i32.trunc_sat_f64_s\",[\"f64:4607632778762754458\"]],[\"invoke\",316,0,\"i32.trunc_sat_f64_s\",[\"f64:4609434218613702656\"]],[\"invoke\",317,0,\"i32.trunc_sat_f64_s\",[\"f64:13830554455654793216\"]],[\"invoke\",319,0,\"i32.trunc_sat_f64_s\",[\"f64:13832806255468478464\"]],[\"invoke\",320,0,\"i32.trunc_sat_f64_s\",[\"f64:13834607695319426662\"]],[\"invoke\",321,0,\"i32.trunc_sat_f64_s\",[\"f64:13835058055282163712\"]],[\"invoke\",323,0,\"i32.trunc_sat_f64_s\",[\"f64:13970166044103278592\"]],[\"invoke\",324,0,\"i32.trunc_sat_f64_s\",[\"f64:4746794007248502784\"]],[\"invoke\",326,0,\"i32.trunc_sat_f64_s\",[\"f64:9218868437227405312\"]],[\"invoke\",327,0,\"i32.trunc_sat_f64_s\",[\"f64:18442240474082181120\"]],[\"invoke\",328,0,\"i32.trunc_sat_f64_s\",[\"f64:9221120237041090560\"]],[\"invoke\",333,0,\"i32.trunc_sat_f64_u\",[\"f64:0\"]],[\"invoke\",334,0,\"i32.trunc_sat_f64_u\",[\"f64:9223372036854775808\"]],[\"invoke\",335,0,\"i32.trunc_sat_f64_u\",[\"f64:1\"]],[\"invoke\",337,0,\"i32.trunc_sat_f64_u\",[\"f64:4607182418800017408\"]],[\"invoke\",338,0,\"i32.trunc_sat_f64_u\",[\"f64:4607632778762754458\"]],[\"invoke\",340,0,\"i32.trunc_sat_f64_u\",[\"f64:4611235658464650854\"]],[\"invoke\",341,0,\"i32.trunc_sat_f64_u\",[\"f64:4611686018427387904\"]],[\"invoke\",342,0,\"i32.trunc_sat_f64_u\",[\"f64:4746794007248502784\"]],[\"invoke\",344,0,\"i32.trunc_sat_f64_u\",[\"f64:13829653735729319117\"]],[\"invoke\",345,0,\"i32.trunc_sat_f64_u\",[\"f64:13830554455654793215\"]],[\"invoke\",346,0,\"i32.trunc_sat_f64_u\",[\"f64:4726483295884279808\"]],[\"invoke\",348,0,\"i32.trunc_sat_f64_u\",[\"f64:13830554455654793216\"]],[\"invoke\",349,0,\"i32.trunc_sat_f64_u\",[\"f64:4846369599423283200\"]],[\"invoke\",351,0,\"i32.trunc_sat_f64_u\",[\"f64:4890909195324358656\"]],[\"invoke\",352,0,\"i32.trunc_sat_f64_u\",[\"f64:9218868437227405312\"]],[\"invoke\",353,0,\"i32.trunc_sat_f64_u\",[\"f64:18442240474082181120\"]],[\"invoke\",356,0,\"i32.trunc_sat_f64_u\",[\"f64:18444492273895866368\"]],[\"invoke\",359,0,\"i64.trunc_sat_f32_s\",[\"f32:0\"]],[\"invoke\",361,0,\"i64.trunc_sat_f32_s\",[\"f32:1\"]],[\"invoke\",362,0,\"i64.trunc_sat_f32_s\",[\"f32:2147483649\"]],[\"invoke\",363,0,\"i64.trunc_sat_f32_s\",[\"f32:1065353216\"]],[\"invoke\",365,0,\"i64.trunc_sat_f32_s\",[\"f32:1069547520\"]],[\"invoke\",366,0,\"i64.trunc_sat_f32_s\",[\"f32:3212836864\"]],[\"invoke\",367,0,\"i64.trunc_sat_f32_s\",[\"f32:3213675725\"]],[\"invoke\",369,0,\"i64.trunc_sat_f32_s\",[\"f32:3220386611\"]],[\"invoke\",370,0,\"i64.trunc_sat_f32_s\",[\"f32:3221225472\"]],[\"invoke\",372,0,\"i64.trunc_sat_f32_s\",[\"f32:3481272320\"]],[\"invoke\",373,0,\"i64.trunc_sat_f32_s\",[\"f32:1593835519\"]],[\"invoke\",374,0,\"i64.trunc_sat_f32_s\",[\"f32:3741319168\"]],[\"invoke\",376,0,\"i64.trunc_sat_f32_s\",[\"f32:3741319169\"]],[\"invoke\",377,0,\"i64.trunc_sat_f32_s\",[\"f32:2139095040\"]],[\"invoke\",378,0,\"i64.trunc_sat_f32_s\",[\"f32:4286578688\"]],[\"invoke\",381,0,\"i64.trunc_sat_f32_s\",[\"f32:4290772992\"]],[\"invoke\",384,0,\"i64.trunc_sat_f32_u\",[\"f32:0\"]],[\"invoke\",386,0,\"i64.trunc_sat_f32_u\",[\"f32:1\"]],[\"invoke\",387,0,\"i64.trunc_sat_f32_u\",[\"f32:2147483649\"]],[\"invoke\",388,0,\"i64.trunc_sat_f32_u\",[\"f32:1065353216\"]],[\"invoke\",390,0,\"i64.trunc_sat_f32_u\",[\"f32:1069547520\"]],[\"invoke\",391,0,\"i64.trunc_sat_f32_u\",[\"f32:1333788672\"]],[\"invoke\",392,0,\"i64.trunc_sat_f32_u\",[\"f32:1602224127\"]],[\"invoke\",394,0,\"i64.trunc_sat_f32_u\",[\"f32:3212836863\"]],[\"invoke\",395,0,\"i64.trunc_sat_f32_u\",[\"f32:1602224128\"]],[\"invoke\",397,0,\"i64.trunc_sat_f32_u\",[\"f32:2139095040\"]],[\"invoke\",398,0,\"i64.trunc_sat_f32_u\",[\"f32:4286578688\"]],[\"invoke\",399,0,\"i64.trunc_sat_f32_u\",[\"f32:2143289344\"]],[\"invoke\",404,0,\"i64.trunc_sat_f64_s\",[\"f64:0\"]],[\"invoke\",405,0,\"i64.trunc_sat_f64_s\",[\"f64:9223372036854775808\"]],[\"invoke\",406,0,\"i64.trunc_sat_f64_s\",[\"f64:1\"]],[\"invoke\",408,0,\"i64.trunc_sat_f64_s\",[\"f64:4607182418800017408\"]],[\"invoke\",409,0,\"i64.trunc_sat_f64_s\",[\"f64:4607632778762754458\"]],[\"invoke\",411,0,\"i64.trunc_sat_f64_s\",[\"f64:13830554455654793216\"]],[\"invoke\",412,0,\"i64.trunc_sat_f64_s\",[\"f64:13831004815617530266\"]],[\"invoke\",413,0,\"i64.trunc_sat_f64_s\",[\"f64:13832806255468478464\"]],[\"invoke\",415,0,\"i64.trunc_sat_f64_s\",[\"f64:13835058055282163712\"]],[\"invoke\",416,0,\"i64.trunc_sat_f64_s\",[\"f64:4751297606875873280\"]],[\"invoke\",417,0,\"i64.trunc_sat_f64_s\",[\"f64:13974669643730649088\"]],[\"invoke\",419,0,\"i64.trunc_sat_f64_s\",[\"f64:14114281232179134464\"]],[\"invoke\",420,0,\"i64.trunc_sat_f64_s\",[\"f64:4890909195324358656\"]],[\"invoke\",422,0,\"i64.trunc_sat_f64_s\",[\"f64:9218868437227405312\"]],[\"invoke\",423,0,\"i64.trunc_sat_f64_s\",[\"f64:18442240474082181120\"]],[\"invoke\",424,0,\"i64.trunc_sat_f64_s\",[\"f64:9221120237041090560\"]],[\"invoke\",429,0,\"i64.trunc_sat_f64_u\",[\"f64:0\"]],[\"invoke\",430,0,\"i64.trunc_sat_f64_u\",[\"f64:9223372036854775808\"]],[\"invoke\",431,0,\"i64.trunc_sat_f64_u\",[\"f64:1\"]],[\"invoke\",433,0,\"i64.trunc_sat_f64_u\",[\"f64:4607182418800017408\"]],[\"invoke\",434,0,\"i64.trunc_sat_f64_u\",[\"f64:4607632778762754458\"]],[\"invoke\",436,0,\"i64.trunc_sat_f64_u\",[\"f64:4751297606873776128\"]],[\"invoke\",437,0,\"i64.trunc_sat_f64_u\",[\"f64:4751297606875873280\"]],[\"invoke\",438,0,\"i64.trunc_sat_f64_u\",[\"f64:4895412794951729151\"]],[\"invoke\",440,0,\"i64.trunc_sat_f64_u\",[\"f64:13830554455654793215\"]],[\"invoke\",441,0,\"i64.trunc_sat_f64_u\",[\"f64:4726483295884279808\"]],[\"invoke\",443,0,\"i64.trunc_sat_f64_u\",[\"f64:4890909195324358656\"]],[\"invoke\",444,0,\"i64.trunc_sat_f64_u\",[\"f64:4895412794951729152\"]],[\"invoke\",445,0,\"i64.trunc_sat_f64_u\",[\"f64:13830554455654793216\"]],[\"invoke\",447,0,\"i64.trunc_sat_f64_u\",[\"f64:18442240474082181120\"]],[\"invoke\",448,0,\"i64.trunc_sat_f64_u\",[\"f64:9221120237041090560\"]],[\"invoke\",450,0,\"i64.trunc_sat_f64_u\",[\"f64:18444492273895866368\"]],[\"invoke\",455,0,\"f32.convert_i32_s\",[\"i32:4278190079\"]],[\"invoke\",456,0,\"f32.convert_i32_s\",[\"i32:16777219\"]],[\"invoke\",459,0,\"f32.convert_i64_s\",[\"i64:1\"]],[\"invoke\",460,0,\"f32.convert_i64_s\",[\"i64:18446744073709551615\"]],[\"invoke\",461,0,\"f32.convert_i64_s\",[\"i64:0\"]],[\"invoke\",463,0,\"f32.convert_i64_s\",[\"i64:9223372036854775808\"]],[\"invoke\",464,0,\"f32.convert_i64_s\",[\"i64:314159265358979\"]],[\"invoke\",466,0,\"f32.convert_i64_s\",[\"i64:16777217\"]],[\"invoke\",468,0,\"f32.convert_i64_s\",[\"i64:16777219\"]],[\"invoke\",469,0,\"f32.convert_i64_s\",[\"i64:18446744073692774397\"]],[\"invoke\",472,0,\"f32.convert_i64_s\",[\"i64:9223372311732682753\"]],[\"invoke\",473,0,\"f32.convert_i64_s\",[\"i64:9007199791611905\"]],[\"invoke\",474,0,\"f32.convert_i64_s\",[\"i64:18437736873917939711\"]],[\"invoke\",477,0,\"f64.convert_i32_s\",[\"i32:4294967295\"]],[\"invoke\",478,0,\"f64.convert_i32_s\",[\"i32:0\"]],[\"invoke\",479,0,\"f64.convert_i32_s\",[\"i32:2147483647\"]],[\"invoke\",481,0,\"f64.convert_i32_s\",[\"i32:987654321\"]],[\"invoke\",483,0,\"f64.convert_i64_s\",[\"i64:1\"]],[\"invoke\",485,0,\"f64.convert_i64_s\",[\"i64:0\"]],[\"invoke\",486,0,\"f64.convert_i64_s\",[\"i64:9223372036854775807\"]],[\"invoke\",487,0,\"f64.convert_i64_s\",[\"i64:9223372036854775808\"]],[\"invoke\",490,0,\"f64.convert_i64_s\",[\"i64:9007199254740993\"]],[\"invoke\",491,0,\"f64.convert_i64_s\",[\"i64:18437736874454810623\"]],[\"invoke\",492,0,\"f64.convert_i64_s\",[\"i64:9007199254740995\"]],[\"invoke\",495,0,\"f32.convert_i32_u\",[\"i32:1\"]],[\"invoke\",496,0,\"f32.convert_i32_u\",[\"i32:0\"]],[\"invoke\",498,0,\"f32.convert_i32_u\",[\"i32:2147483648\"]],[\"invoke\",499,0,\"f32.convert_i32_u\",[\"i32:305419896\"]],[\"invoke\",500,0,\"f32.convert_i32_u\",[\"i32:4294967295\"]],[\"invoke\",502,0,\"f32.convert_i32_u\",[\"i32:2147483777\"]],[\"invoke\",503,0,\"f32.convert_i32_u\",[\"i32:2147483778\"]],[\"invoke\",504,0,\"f32.convert_i32_u\",[\"i32:4294966912\"]],[\"invoke\",506,0,\"f32.convert_i32_u\",[\"i32:4294966914\"]],[\"invoke\",508,0,\"f32.convert_i32_u\",[\"i32:16777217\"]],[\"invoke\",511,0,\"f32.convert_i64_u\",[\"i64:1\"]],[\"invoke\",512,0,\"f32.convert_i64_u\",[\"i64:0\"]],[\"invoke\",513,0,\"f32.convert_i64_u\",[\"i64:9223372036854775807\"]],[\"invoke\",515,0,\"f32.convert_i64_u\",[\"i64:18446744073709551615\"]],[\"invoke\",517,0,\"f32.convert_i64_u\",[\"i64:16777217\"]],[\"invoke\",520,0,\"f32.convert_i64_u\",[\"i64:9007199791611905\"]],[\"invoke\",521,0,\"f32.convert_i64_u\",[\"i64:9223371761976868863\"]],[\"invoke\",522,0,\"f32.convert_i64_u\",[\"i64:9223372586610589697\"]],[\"invoke\",525,0,\"f64.convert_i32_u\",[\"i32:1\"]],[\"invoke\",526,0,\"f64.convert_i32_u\",[\"i32:0\"]],[\"invoke\",527,0,\"f64.convert_i32_u\",[\"i32:2147483647\"]],[\"invoke\",529,0,\"f64.convert_i32_u\",[\"i32:4294967295\"]],[\"invoke\",531,0,\"f64.convert_i64_u\",[\"i64:1\"]],[\"invoke\",533,0,\"f64.convert_i64_u\",[\"i64:9223372036854775807\"]],[\"invoke\",534,0,\"f64.convert_i64_u\",[\"i64:9223372036854775808\"]],[\"invoke\",535,0,\"f64.convert_i64_u\",[\"i64:18446744073709551615\"]],[\"invoke\",537,0,\"f64.convert_i64_u\",[\"i64:9223372036854776833\"]],[\"invoke\",538,0,\"f64.convert_i64_u\",[\"i64:9223372036854776834\"]],[\"invoke\",539,0,\"f64.convert_i64_u\",[\"i64:18446744073709548544\"]],[\"invoke\",541,0,\"f64.convert_i64_u\",[\"i64:18446744073709548546\"]],[\"invoke\",543,0,\"f64.convert_i64_u\",[\"i64:9007199254740993\"]],[\"invoke\",546,0,\"f64.promote_f32\",[\"f32:0\"]],[\"invoke\",547,0,\"f64.promote_f32\",[\"f32:2147483648\"]],[\"invoke\",548,0,\"f64.promote_f32\",[\"f32:1\"]],[\"invoke\",550,0,\"f64.promote_f32\",[\"f32:1065353216\"]],[\"invoke\",551,0,\"f64.promote_f32\",[\"f32:3212836864\"]],[\"invoke\",552,0,\"f64.promote_f32\",[\"f32:4286578687\"]],[\"invoke\",555,0,\"f64.promote_f32\",[\"f32:67108864\"]],[\"invoke\",557,0,\"f64.promote_f32\",[\"f32:2118632255\"]],[\"invoke\",559,0,\"f64.promote_f32\",[\"f32:4286578688\"]],[\"invoke\",560,0,\"f64.promote_f32\",[\"f32:2143289344\"]],[\"invoke\",562,0,\"f64.promote_f32\",[\"f32:4290772992\"]],[\"invoke\",566,0,\"f32.demote_f64\",[\"f64:9223372036854775808\"]],[\"invoke\",567,0,\"f32.demote_f64\",[\"f64:1\"]],[\"invoke\",568,0,\"f32.demote_f64\",[\"f64:9223372036854775809\"]],[\"invoke\",570,0,\"f32.demote_f64\",[\"f64:13830554455654793216\"]],[\"invoke\",571,0,\"f32.demote_f64\",[\"f64:4039728865214464000\"]],[\"invoke\",573,0,\"f32.demote_f64\",[\"f64:4039728865214463999\"]],[\"invoke\",574,0,\"f32.demote_f64\",[\"f64:13263100902069239807\"]],[\"invoke\",575,0,\"f32.demote_f64\",[\"f64:3936146074321813504\"]],[\"invoke\",577,0,\"f32.demote_f64\",[\"f64:5183643170298134528\"]],[\"invoke\",578,0,\"f32.demote_f64\",[\"f64:14407015207152910336\"]],[\"invoke\",579,0,\"f32.demote_f64\",[\"f64:5183643170298134529\"]],[\"invoke\",581,0,\"f32.demote_f64\",[\"f64:5183643170566569984\"]],[\"invoke\",582,0,\"f32.demote_f64\",[\"f64:14407015207421345792\"]],[\"invoke\",584,0,\"f32.demote_f64\",[\"f64:14407015207689781247\"]],[\"invoke\",585,0,\"f32.demote_f64\",[\"f64:5183643170835005440\"]],[\"invoke\",586,0,\"f32.demote_f64\",[\"f64:14407015207689781248\"]],[\"invoke\",588,0,\"f32.demote_f64\",[\"f64:5172657297058430976\"]],[\"invoke\",589,0,\"f32.demote_f64\",[\"f64:9218868437227405312\"]],[\"invoke\",590,0,\"f32.demote_f64\",[\"f64:18442240474082181120\"]],[\"invoke\",592,0,\"f32.demote_f64\",[\"f64:4607182418800017407\"]],[\"invoke\",593,0,\"f32.demote_f64\",[\"f64:4607182419068452864\"]],[\"invoke\",595,0,\"f32.demote_f64\",[\"f64:4607182419605323775\"]],[\"invoke\",596,0,\"f32.demote_f64\",[\"f64:4607182419605323776\"]],[\"invoke\",597,0,\"f32.demote_f64\",[\"f64:4607182420142194688\"]],[\"invoke\",599,0,\"f32.demote_f64\",[\"f64:4715268810125344769\"]],[\"invoke\",600,0,\"f32.demote_f64\",[\"f64:4715268810662215679\"]],[\"invoke\",602,0,\"f32.demote_f64\",[\"f64:5094955347580439664\"]],[\"invoke\",603,0,\"f32.demote_f64\",[\"f64:4101111194527827589\"]],[\"invoke\",604,0,\"f32.demote_f64\",[\"f64:4038806939559600639\"]],[\"invoke\",606,0,\"f32.demote_f64\",[\"f64:14338315240173327556\"]],[\"invoke\",607,0,\"f32.demote_f64\",[\"f64:9221120237041090560\"]],[\"invoke\",609,0,\"f32.demote_f64\",[\"f64:18444492273895866368\"]],[\"invoke\",612,0,\"f32.demote_f64\",[\"f64:9227875636482146304\"]],[\"invoke\",613,0,\"f32.demote_f64\",[\"f64:3931642474694443008\"]],[\"invoke\",615,0,\"f32.demote_f64\",[\"f64:3931642474694443009\"]],[\"invoke\",616,0,\"f32.demote_f64\",[\"f64:13155014511549218817\"]],[\"invoke\",618,0,\"f32.reinterpret_i32\",[\"i32:0\"]],[\"invoke\",620,0,\"f32.reinterpret_i32\",[\"i32:1\"]],[\"invoke\",621,0,\"f32.reinterpret_i32\",[\"i32:4294967295\"]],[\"invoke\",622,0,\"f32.reinterpret_i32\",[\"i32:123456789\"]],[\"invoke\",624,0,\"f32.reinterpret_i32\",[\"i32:2139095040\"]],[\"invoke\",625,0,\"f32.reinterpret_i32\",[\"i32:4286578688\"]],[\"invoke\",627,0,\"f32.reinterpret_i32\",[\"i32:4290772992\"]],[\"invoke\",628,0,\"f32.reinterpret_i32\",[\"i32:2141192192\"]],[\"invoke\",629,0,\"f32.reinterpret_i32\",[\"i32:4288675840\"]],[\"invoke\",632,0,\"f64.reinterpret_i64\",[\"i64:1\"]],[\"invoke\",633,0,\"f64.reinterpret_i64\",[\"i64:18446744073709551615\"]],[\"invoke\",634,0,\"f64.reinterpret_i64\",[\"i64:9223372036854775808\"]],[\"invoke\",636,0,\"f64.reinterpret_i64\",[\"i64:9223372036854775809\"]],[\"invoke\",637,0,\"f64.reinterpret_i64\",[\"i64:9218868437227405312\"]],[\"invoke\",639,0,\"f64.reinterpret_i64\",[\"i64:9221120237041090560\"]],[\"invoke\",640,0,\"f64.reinterpret_i64\",[\"i64:18444492273895866368\"]],[\"invoke\",641,0,\"f64.reinterpret_i64\",[\"i64:9219994337134247936\"]],[\"invoke\",644,0,\"i32.reinterpret_f32\",[\"f32:0\"]],[\"invoke\",645,0,\"i32.reinterpret_f32\",[\"f32:2147483648\"]],[\"invoke\",646,0,\"i32.reinterpret_f32\",[\"f32:1\"]],[\"invoke\",649,0,\"i32.reinterpret_f32\",[\"f32:1065353216\"]],[\"invoke\",650,0,\"i32.reinterpret_f32\",[\"f32:1078530010\"]],[\"invoke\",652,0,\"i32.reinterpret_f32\",[\"f32:4286578687\"]],[\"invoke\",653,0,\"i32.reinterpret_f32\",[\"f32:2139095040\"]],[\"invoke\",654,0,\"i32.reinterpret_f32\",[\"f32:4286578688\"]],[\"invoke\",656,0,\"i32.reinterpret_f32\",[\"f32:4290772992\"]],[\"invoke\",660,0,\"i64.reinterpret_f64\",[\"f64:0\"]],[\"invoke\",661,0,\"i64.reinterpret_f64\",[\"f64:9223372036854775808\"]],[\"invoke\",664,0,\"i64.reinterpret_f64\",[\"f64:9223372036854775809\"]],[\"invoke\",665,0,\"i64.reinterpret_f64\",[\"f64:4607182418800017408\"]],[\"invoke\",667,0,\"i64.reinterpret_f64\",[\"f64:9218868437227405311\"]],[\"invoke\",668,0,\"i64.reinterpret_f64\",[\"f64:18442240474082181119\"]],[\"invoke\",669,0,\"i64.reinterpret_f64\",[\"f64:9218868437227405312\"]],[\"invoke\",671,0,\"i64.reinterpret_f64\",[\"f64:9221120237041090560\"]],[\"invoke\",672,0,\"i64.reinterpret_f64\",[\"f64:18444492273895866368\"]],[\"file\",\"traps.wast\"],[\"module\",5,23],[\"invoke\",16,0,\"no_dce.i32.div_s\",[\"i32:1\",\"i32:0\"]],[\"invoke\",17,0,\"no_dce.i32.div_u\",[\"i32:1\",\"i32:0\"]],[\"invoke\",18,0,\"no_dce.i64.div_s\",[\"i64:1\",\"i64:0\"]],[\"invoke\",19,0,\"no_dce.i64.div_u\",[\"i64:1\",\"i64:0\"]],[\"invoke\",20,0,\"no_dce.i32.div_s\",[\"i32:2147483648\",\"i32:4294967295\"]],[\"invoke\",21,0,\"no_dce.i64.div_s\",[\"i64:9223372036854775808\",\"i64:18446744073709551615\"]],[\"module\",23,24],[\"invoke\",34,0,\"no_dce.i32.rem_s\",[\"i32:1\",\"i32:0\"]],[\"invoke\",35,0,\"no_dce.i32.rem_u\",[\"i32:1\",\"i32:0\"]],[\"invoke\",36,0,\"no_dce.i64.rem_s\",[\"i64:1\",\"i64:0\"]],[\"invoke\",37,0,\"no_dce.i64.rem_u\",[\"i64:1\",\"i64:0\"]],[\"module\",39,25],[\"invoke\",50,0,\"no_dce.i32.trunc_f32_s\",[\"f32:2143289344\"]],[\"invoke\",51,0,\"no_dce.i32.trunc_f32_u\",[\"f32:2143289344\"]],[\"invoke\",52,0,\"no_dce.i32.trunc_f64_s\",[\"f64:9221120237041090560\"]],[\"invoke\",53,0,\"no_dce.i32.trunc_f64_u\",[\"f64:9221120237041090560\"]],[\"invoke\",54,0,\"no_dce.i64.trunc_f32_s\",[\"f32:2143289344\"]],[\"invoke\",55,0,\"no_dce.i64.trunc_f32_u\",[\"f32:2143289344\"]],[\"invoke\",56,0,\"no_dce.i64.trunc_f64_s\",[\"f64:9221120237041090560\"]],[\"invoke\",57,0,\"no_dce.i64.trunc_f64_u\",[\"f64:9221120237041090560\"]],[\"module\",59,26],[\"invoke\",78,0,\"no_dce.i32.load\",[\"i32:65536\"]],[\"invoke\",79,0,\"no_dce.i32.load16_s\",[\"i32:65536\"]],[\"invoke\",80,0,\"no_dce.i32.load16_u\",[\"i32:65536\"]],[\"invoke\",81,0,\"no_dce.i32.load8_s\",[\"i32:65536\"]],[\"invoke\",82,0,\"no_dce.i32.load8_u\",[\"i32:65536\"]],[\"invoke\",83,0,\"no_dce.i64.load\",[\"i32:65536\"]],[\"invoke\",84,0,\"no_dce.i64.load32_s\",[\"i32:65536\"]],[\"invoke\",85,0,\"no_dce.i64.load32_u\",[\"i32:65536\"]],[\"invoke\",86,0,\"no_dce.i64.load16_s\",[\"i32:65536\"]],[\"invoke\",87,0,\"no_dce.i64.load16_u\",[\"i32:65536\"]],[\"invoke\",88,0,\"no_dce.i64.load8_s\",[\"i32:65536\"]],[\"invoke\",89,0,\"no_dce.i64.load8_u\",[\"i32:65536\"]],[\"invoke\",90,0,\"no_dce.f32.load\",[\"i32:65536\"]],[\"invoke\",91,0,\"no_dce.f64.load\",[\"i32:65536\"]]]"; diff --git a/tests/corpus/webassembly-spec-int/main.mjs b/tests/corpus/webassembly-spec-int/main.mjs new file mode 100644 index 000000000..3f5bef066 --- /dev/null +++ b/tests/corpus/webassembly-spec-int/main.mjs @@ -0,0 +1,5 @@ +// Executes WebAssembly spec tests (6 files); see tests/wasm-spec/runner.mjs. +import { run } from "../../wasm-spec/runner.mjs"; +import { modules, script } from "./data.mjs"; + +run(modules, script); diff --git a/tests/corpus/webassembly-spec-memory/data.mjs b/tests/corpus/webassembly-spec-memory/data.mjs new file mode 100644 index 000000000..9b2ec91d7 --- /dev/null +++ b/tests/corpus/webassembly-spec-memory/data.mjs @@ -0,0 +1,161 @@ +/* Generated by tests/wasm-spec/gen.mjs from the WebAssembly 2.0 core test + * suite (WebAssembly/spec wg-2.0, Apache-2.0) with wabt 1.0.37 wast2json: + * address.wast, align.wast, endianness.wast, float_memory.wast, load.wast, store.wast, memory.wast, memory_grow.wast, memory_redundancy.wast, memory_size.wast, memory_trap.wast, bulk.wast, memory_copy.wast, memory_fill.wast, memory_init.wast, data.wast. Do not edit. */ +export const modules = [ + "AGFzbQEAAAABCgJgAX8Bf2ABfwADHx4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEFAwEAAQfNAh4IOHVfZ29vZDEAAAg4dV9nb29kMgABCDh1X2dvb2QzAAIIOHVfZ29vZDQAAwg4dV9nb29kNQAECDhzX2dvb2QxAAUIOHNfZ29vZDIABgg4c19nb29kMwAHCDhzX2dvb2Q0AAgIOHNfZ29vZDUACQkxNnVfZ29vZDEACgkxNnVfZ29vZDIACwkxNnVfZ29vZDMADAkxNnVfZ29vZDQADQkxNnVfZ29vZDUADgkxNnNfZ29vZDEADwkxNnNfZ29vZDIAEAkxNnNfZ29vZDMAEQkxNnNfZ29vZDQAEgkxNnNfZ29vZDUAEwgzMl9nb29kMQAUCDMyX2dvb2QyABUIMzJfZ29vZDMAFggzMl9nb29kNAAXCDMyX2dvb2Q1ABgGOHVfYmFkABkGOHNfYmFkABoHMTZ1X2JhZAAbBzE2c19iYWQAHAYzMl9iYWQAHQqKAh4HACAALQAACwcAIAAtAAALBwAgAC0AAQsHACAALQACCwcAIAAtABkLBwAgACwAAAsHACAALAAACwcAIAAsAAELBwAgACwAAgsHACAALAAZCwcAIAAvAQALBwAgAC8AAAsHACAALwABCwcAIAAvAQILBwAgAC8BGQsHACAALgEACwcAIAAuAAALBwAgAC4AAQsHACAALgECCwcAIAAuARkLBwAgACgCAAsHACAAKAAACwcAIAAoAAELBwAgACgBAgsHACAAKAIZCwwAIAAtAP////8PGgsMACAALAD/////DxoLDAAgAC8B/////w8aCwwAIAAuAf////8PGgsMACAAKAL/////DxoLCyABAEEACxphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eg==", + "AGFzbQEAAAABCgJgAX8BfmABfwADKyoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEFAwEAAQfZAyoIOHVfZ29vZDEAAAg4dV9nb29kMgABCDh1X2dvb2QzAAIIOHVfZ29vZDQAAwg4dV9nb29kNQAECDhzX2dvb2QxAAUIOHNfZ29vZDIABgg4c19nb29kMwAHCDhzX2dvb2Q0AAgIOHNfZ29vZDUACQkxNnVfZ29vZDEACgkxNnVfZ29vZDIACwkxNnVfZ29vZDMADAkxNnVfZ29vZDQADQkxNnVfZ29vZDUADgkxNnNfZ29vZDEADwkxNnNfZ29vZDIAEAkxNnNfZ29vZDMAEQkxNnNfZ29vZDQAEgkxNnNfZ29vZDUAEwkzMnVfZ29vZDEAFAkzMnVfZ29vZDIAFQkzMnVfZ29vZDMAFgkzMnVfZ29vZDQAFwkzMnVfZ29vZDUAGAkzMnNfZ29vZDEAGQkzMnNfZ29vZDIAGgkzMnNfZ29vZDMAGwkzMnNfZ29vZDQAHAkzMnNfZ29vZDUAHQg2NF9nb29kMQAeCDY0X2dvb2QyAB8INjRfZ29vZDMAIAg2NF9nb29kNAAhCDY0X2dvb2Q1ACIGOHVfYmFkACMGOHNfYmFkACQHMTZ1X2JhZAAlBzE2c19iYWQAJgczMnVfYmFkACcHMzJzX2JhZAAoBjY0X2JhZAApCvQCKgcAIAAxAAALBwAgADEAAAsHACAAMQABCwcAIAAxAAILBwAgADEAGQsHACAAMAAACwcAIAAwAAALBwAgADAAAQsHACAAMAACCwcAIAAwABkLBwAgADMBAAsHACAAMwAACwcAIAAzAAELBwAgADMBAgsHACAAMwEZCwcAIAAyAQALBwAgADIAAAsHACAAMgABCwcAIAAyAQILBwAgADIBGQsHACAANQIACwcAIAA1AAALBwAgADUAAQsHACAANQECCwcAIAA1AhkLBwAgADQCAAsHACAANAAACwcAIAA0AAELBwAgADQBAgsHACAANAIZCwcAIAApAwALBwAgACkAAAsHACAAKQABCwcAIAApAQILBwAgACkDGQsMACAAMQD/////DxoLDAAgADAA/////w8aCwwAIAAzAf////8PGgsMACAAMgH/////DxoLDAAgADUC/////w8aCwwAIAA0Av////8PGgsMACAAKQP/////DxoLCyABAEEACxphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eg==", + "AGFzbQEAAAABCgJgAX8BfWABfwADBwYAAAAAAAEFAwEAAQdBBggzMl9nb29kMQAACDMyX2dvb2QyAAEIMzJfZ29vZDMAAggzMl9nb29kNAADCDMyX2dvb2Q1AAQGMzJfYmFkAAUKNgYHACAAKgIACwcAIAAqAAALBwAgACoAAQsHACAAKgECCwcAIAAqAggLDAAgACoC/////w8aCwsSAQBBAAsMAAAAAAAAoH8BANB/", + "AGFzbQEAAAABCgJgAX8BfGABfwADBwYAAAAAAAEFAwEAAQdBBgg2NF9nb29kMQAACDY0X2dvb2QyAAEINjRfZ29vZDMAAgg2NF9nb29kNAADCDY0X2dvb2Q1AAQGNjRfYmFkAAUKNgYHACAAKwMACwcAIAArAAALBwAgACsAAQsHACAAKwECCwcAIAArAxILDAAgACsD/////w8aCwsgAQBBAAsaAAAAAAAAAAAAAAAAAAAAAPR/AQAAAAAA/H8=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEALAAAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEALQAAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEALgEAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEALwEAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEAKAIAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEAMAAAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEAMQAAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEAMgEAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEAMwEAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEANAIAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEANQIAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEAKQMAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEAKgIAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCgEIAEEAKwMAGgs=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCwEJAEEAQQE6AAAL", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCwEJAEEAQQE7AQAL", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCwEJAEEAQQE2AgAL", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCwEJAEEAQgE8AAAL", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCwEJAEEAQgE9AQAL", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCwEJAEEAQgE+AgAL", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKCwEJAEEAQgE3AwAL", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKDgEMAEEAQwAAgD84AgAL", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAAKEgEQAEEARAAAAAAAAPA/OQMACw==", + "AGFzbQEAAAABFwRgAX8BfWABfwF8YAJ/fwF/YAJ/fwF+AwUEAAECAwUDAQABB00EEGYzMl9hbGlnbl9zd2l0Y2gAABBmNjRfYWxpZ25fc3dpdGNoAAEQaTMyX2FsaWduX3N3aXRjaAACEGk2NF9hbGlnbl9zd2l0Y2gAAwr7CARjAQJ9QwAAIEEhAQJAAkACQAJAAkAgAA4EAAECAwQLQQAgATgCAEEAKgIAIQIMAwtBACABOAAAQQAqAAAhAgwCC0EAIAE4AQBBACoBACECDAELQQAgATgCAEEAKgIAIQILIAILewECfEQAAAAAAAAkQCEBAkACQAJAAkACQAJAIAAOBQABAgMEBQtBACABOQMAQQArAwAhAgwEC0EAIAE5AABBACsAACECDAMLQQAgATkBAEEAKwEAIQIMAgtBACABOQIAQQArAgAhAgwBC0EAIAE5AwBBACsDACECCyACC+ICAQJ/QQohAgJAAkACQAJAAkACQCAADgUAAQIDBAULIAFBAEYEQEEAIAI6AABBACwAACEDCyABQQFGBEBBACACOgAAQQAsAAAhAwsMBAsgAUEARgRAQQAgAjoAAEEALQAAIQMLIAFBAUYEQEEAIAI6AABBAC0AACEDCwwDCyABQQBGBEBBACACOwEAQQAuAQAhAwsgAUEBRgRAQQAgAjsAAEEALgAAIQMLIAFBAkYEQEEAIAI7AQBBAC4BACEDCwwCCyABQQBGBEBBACACOwEAQQAvAQAhAwsgAUEBRgRAQQAgAjsAAEEALwAAIQMLIAFBAkYEQEEAIAI7AQBBAC8BACEDCwwBCyABQQBGBEBBACACNgIAQQAoAgAhAwsgAUEBRgRAQQAgAjYAAEEAKAAAIQMLIAFBAkYEQEEAIAI2AQBBACgBACEDCyABQQRGBEBBACACNgIAQQAoAgAhAwsLIAMLtAQBAn5CCiECAkACQAJAAkACQAJAAkACQCAADgcAAQIDBAUGBwsgAUEARgRAQQAgAjwAAEEAMAAAIQMLIAFBAUYEQEEAIAI8AABBADAAACEDCwwGCyABQQBGBEBBACACPAAAQQAxAAAhAwsgAUEBRgRAQQAgAjwAAEEAMQAAIQMLDAULIAFBAEYEQEEAIAI9AQBBADIBACEDCyABQQFGBEBBACACPQAAQQAyAAAhAwsgAUECRgRAQQAgAj0BAEEAMgEAIQMLDAQLIAFBAEYEQEEAIAI9AQBBADMBACEDCyABQQFGBEBBACACPQAAQQAzAAAhAwsgAUECRgRAQQAgAj0BAEEAMwEAIQMLDAMLIAFBAEYEQEEAIAI+AgBBADQCACEDCyABQQFGBEBBACACPgAAQQA0AAAhAwsgAUECRgRAQQAgAj4BAEEANAEAIQMLIAFBBEYEQEEAIAI+AgBBADQCACEDCwwCCyABQQBGBEBBACACPgIAQQA1AgAhAwsgAUEBRgRAQQAgAj4AAEEANQAAIQMLIAFBAkYEQEEAIAI+AQBBADUBACEDCyABQQRGBEBBACACPgIAQQA1AgAhAwsMAQsgAUEARgRAQQAgAjcDAEEAKQMAIQMLIAFBAUYEQEEAIAI3AABBACkAACEDCyABQQJGBEBBACACNwEAQQApAQAhAwsgAUEERgRAQQAgAjcCAEEAKQIAIQMLIAFBCEYEQEEAIAI3AwBBACkDACEDCwsgAws=", + "AGFzbQEAAAABCwJgAn9+AGABfwF/AwMCAAEFAwEAAQcQAgVzdG9yZQAABGxvYWQAAQoTAgkAIAAgATcCAAsHACAAKAIACw==", + "AGFzbQEAAAABJAdgAn9/AGACf34AYAF/AX9gAX8BfmABfgF+YAF9AX1gAXwBfAMYFwAAAQICAwICAgQEBAQEBQYCAgQEBAUGBQMBAAEH4QERDGkzMl9sb2FkMTZfcwAGDGkzMl9sb2FkMTZfdQAHCGkzMl9sb2FkAAgMaTY0X2xvYWQxNl9zAAkMaTY0X2xvYWQxNl91AAoMaTY0X2xvYWQzMl9zAAsMaTY0X2xvYWQzMl91AAwIaTY0X2xvYWQADQhmMzJfbG9hZAAOCGY2NF9sb2FkAA8LaTMyX3N0b3JlMTYAEAlpMzJfc3RvcmUAEQtpNjRfc3RvcmUxNgASC2k2NF9zdG9yZTMyABMJaTY0X3N0b3JlABQJZjMyX3N0b3JlABUJZjY0X3N0b3JlABYK9gIXFgAgACABOgAAIABBAWogAUEIdjoAAAsUACAAIAEQACAAQQJqIAFBEHYQAAsWACAAIAGnEAEgAEEEaiABQiCIpxABCxMAIAAtAAAgAEEBai0AAEEIdHILEQAgABADIABBAmoQA0EQdHILEwAgABAErSAAQQRqEAStQiCGhAsNAEEAIAAQAEEALgEACw0AQQAgABAAQQAvAQALDQBBACAAEAFBACgCAAsOAEEAIACnEABBADIBAAsOAEEAIACnEABBADMBAAsOAEEAIACnEAFBADQCAAsOAEEAIACnEAFBADUCAAsNAEEAIAAQAkEAKQMACw4AQQAgALwQAUEAKgIACw4AQQAgAL0QAkEAKwMACw0AQQAgADsBAEEAEAMLDQBBACAANgIAQQAQBAsOAEEAIAA9AQBBABADrQsOAEEAIAA+AgBBABAErQsNAEEAIAA3AwBBABAFCw4AQQAgADgCAEEAEAS+Cw4AQQAgADkDAEEAEAW/Cw==", + "AGFzbQEAAAABDANgAAF9YAABf2AAAAMGBQABAgICBQQBAQEBBzcFCGYzMi5sb2FkAAAIaTMyLmxvYWQAAQlmMzIuc3RvcmUAAglpMzIuc3RvcmUAAwVyZXNldAAECjYFBwBBACoCAAsHAEEAKAIACwwAQQBDAACgfzgCAAsNAEEAQYCAgP0HNgIACwkAQQBBADYCAAsLCgEAQQALBAAAoH8=", + "AGFzbQEAAAABDANgAAF8YAABfmAAAAMGBQABAgICBQQBAQEBBzcFCGY2NC5sb2FkAAAIaTY0LmxvYWQAAQlmNjQuc3RvcmUAAglpNjQuc3RvcmUAAwVyZXNldAAECj8FBwBBACsDAAsHAEEAKQMACxAAQQBEAAAAAAAA9H85AwALEgBBAEKAgICAgICA+v8ANwMACwkAQQBCADcDAAsLDgEAQQALCAAAAAAAAPR/", + "AGFzbQEAAAABDANgAAF9YAABf2AAAAMGBQABAgICBQQBAQEBBzcFCGYzMi5sb2FkAAAIaTMyLmxvYWQAAQlmMzIuc3RvcmUAAglpMzIuc3RvcmUAAwVyZXNldAAECjYFBwBBASoCAAsHAEEBKAIACwwAQQFDAACgfzgCAAsNAEEBQYCAgP0HNgIACwkAQQFBADYCAAsLCwEAQQALBQAAAKB/", + "AGFzbQEAAAABDANgAAF8YAABfmAAAAMGBQABAgICBQQBAQEBBzcFCGY2NC5sb2FkAAAIaTY0LmxvYWQAAQlmNjQuc3RvcmUAAglpNjQuc3RvcmUAAwVyZXNldAAECj8FBwBBASsDAAsHAEEBKQMACxAAQQFEAAAAAAAA9H85AwALEgBBAUKAgICAgICA+v8ANwMACwkAQQFCADcDAAsLDwEAQQALCQAAAAAAAAD0fw==", + "AGFzbQEAAAABDANgAAF9YAABf2AAAAMGBQABAgICBQQBAQEBBzcFCGYzMi5sb2FkAAAIaTMyLmxvYWQAAQlmMzIuc3RvcmUAAglpMzIuc3RvcmUAAwVyZXNldAAECjYFBwBBACoCAAsHAEEAKAIACwwAQQBDAQDQfzgCAAsNAEEAQYGAwP4HNgIACwkAQQBBADYCAAsLCgEAQQALBAEA0H8=", + "AGFzbQEAAAABDANgAAF8YAABfmAAAAMGBQABAgICBQQBAQEBBzcFCGY2NC5sb2FkAAAIaTY0LmxvYWQAAQlmNjQuc3RvcmUAAglpNjQuc3RvcmUAAwVyZXNldAAECj8FBwBBACsDAAsHAEEAKQMACxAAQQBEAQAAAAAA/H85AwALEgBBAEKBgICAgICA/v8ANwMACwkAQQBCADcDAAsLDgEAQQALCAEAAAAAAPx/", + "AGFzbQEAAAABFQRgA39/fwF/YAABf2AAAGACf38BfwMnJgECAQECAQEBAQEBAwMBAAEBAQEBAQECAQIBAQICAgIBAQEBAQEBBAUBcAEBAQUDAQABBgYBfwFBAAsHtwUlC2FzLWJyLXZhbHVlAAANYXMtYnJfaWYtY29uZAABDmFzLWJyX2lmLXZhbHVlAAITYXMtYnJfaWYtdmFsdWUtY29uZAADEWFzLWJyX3RhYmxlLWluZGV4AAQRYXMtYnJfdGFibGUtdmFsdWUABRdhcy1icl90YWJsZS12YWx1ZS1pbmRleAAGD2FzLXJldHVybi12YWx1ZQAHCmFzLWlmLWNvbmQACAphcy1pZi10aGVuAAkKYXMtaWYtZWxzZQAKD2FzLXNlbGVjdC1maXJzdAALEGFzLXNlbGVjdC1zZWNvbmQADA5hcy1zZWxlY3QtY29uZAANDWFzLWNhbGwtZmlyc3QADwthcy1jYWxsLW1pZAAQDGFzLWNhbGwtbGFzdAARFmFzLWNhbGxfaW5kaXJlY3QtZmlyc3QAEhRhcy1jYWxsX2luZGlyZWN0LW1pZAATFWFzLWNhbGxfaW5kaXJlY3QtbGFzdAAUFmFzLWNhbGxfaW5kaXJlY3QtaW5kZXgAFRJhcy1sb2NhbC5zZXQtdmFsdWUAFhJhcy1sb2NhbC50ZWUtdmFsdWUAFxNhcy1nbG9iYWwuc2V0LXZhbHVlABgPYXMtbG9hZC1hZGRyZXNzABkQYXMtbG9hZE4tYWRkcmVzcwAaEGFzLXN0b3JlLWFkZHJlc3MAGw5hcy1zdG9yZS12YWx1ZQAcEWFzLXN0b3JlTi1hZGRyZXNzAB0PYXMtc3RvcmVOLXZhbHVlAB4QYXMtdW5hcnktb3BlcmFuZAAfDmFzLWJpbmFyeS1sZWZ0ACAPYXMtYmluYXJ5LXJpZ2h0ACEPYXMtdGVzdC1vcGVyYW5kACIPYXMtY29tcGFyZS1sZWZ0ACMQYXMtY29tcGFyZS1yaWdodAAkE2FzLW1lbW9yeS5ncm93LXNpemUAJQkHAQBBAAsBDgqGBCYMAAJ/QQAoAgAMAAsLDAACQEEAKAIADQALCxEAAn9BACgCAEEBDQAaQQcLCxEAAn9BBkEAKAIADQAaQQcLCw8AAkBBACgCAA4CAAAACwsTAAJ/QQAoAgBBAQ4CAAAAQQcLCxIAAn9BBkEAKAIADgEAAEEHCwsIAEEAKAIADwsPAEEAKAIABH9BAAVBAQsLDwBBAQR/QQAoAgAFQQALCw8AQQAEf0EABUEAKAIACwsMAEEAKAIAIAAgARsLDAAgAEEAKAIAIAEbCwwAQQBBAUEAKAIAGwsEAEF/Cw0AQQAoAgBBAkEDEA4LDQBBAUEAKAIAQQMQDgsNAEEBQQJBACgCABAOCxAAQQAoAgBBAkEDQQARAAALEABBAUEAKAIAQQNBABEAAAsQAEEBQQJBACgCAEEAEQAACxAAQQFBAkEDQQAoAgARAAALCwEBf0EAKAIAIQALCwEBf0EAKAIAIgALCwEBf0EAKAIAJAALCgBBACgCACgCAAsKAEEAKAIALAAACwwAQQAoAgBBBzYCAAsMAEECQQAoAgA2AgALDABBACwAAEEHOgAACwwAQQJBACgCADsBAAsJAEHkACgCAGcLCwBB5AAoAgBBCmoLCwBBCkHkACgCAGsLCQBB5AAoAgBFCwsAQeQAKAIAQQpMCwsAQQpB5AAoAgBHCwoAQeQAKAIAQAAL", + "AGFzbQEAAAABBAFgAAADCgkAAAAAAAAAAAAFAwEAAQeXAQkOYXMtYmxvY2stdmFsdWUAAA1hcy1sb29wLXZhbHVlAAELYXMtYnItdmFsdWUAAg5hcy1icl9pZi12YWx1ZQADE2FzLWJyX2lmLXZhbHVlLWNvbmQABBFhcy1icl90YWJsZS12YWx1ZQAFD2FzLXJldHVybi12YWx1ZQAGCmFzLWlmLXRoZW4ABwphcy1pZi1lbHNlAAgKiAEJDAACQEEAQQE2AgALCwwAA0BBAEEBNgIACwsOAAJAQQBBATYCAAwACwsQAAJAQQBBATYCAEEBDQALCxAAAkBBBkEAQQE2AgANAAsLEQACQEEAQQE2AgBBAQ4AAAsLCgBBAEEBNgIADwsOAEEBBEBBAEEBNgIACwsPAEEABEAFQQBBATYCAAsL", + "AGFzbQEAAAAFAwEAAA==", + "AGFzbQEAAAAFAwEAAQ==", + "AGFzbQEAAAAFBAEBAAA=", + "AGFzbQEAAAAFBAEBAAE=", + "AGFzbQEAAAAFBQEBAYAC", + "AGFzbQEAAAAFBgEBAICABA==", + "AGFzbQEAAAABBQFgAAF/AwIBAAUEAQEAAAcLAQdtZW1zaXplAAAKBgEEAD8ACwsGAQBBAAsA", + "AGFzbQEAAAABBQFgAAF/AwIBAAUEAQEBAQcLAQdtZW1zaXplAAAKBgEEAD8ACwsHAQBBAAsBeA==", + "AGFzbQEAAAABEwRgAAF/YAABfGABfwF/YAF+AX4DDQwAAQICAgIDAwMDAwMFAwEAAQehAQwEZGF0YQAABGNhc3QAAQtpMzJfbG9hZDhfcwACC2kzMl9sb2FkOF91AAMMaTMyX2xvYWQxNl9zAAQMaTMyX2xvYWQxNl91AAULaTY0X2xvYWQ4X3MABgtpNjRfbG9hZDhfdQAHDGk2NF9sb2FkMTZfcwAIDGk2NF9sb2FkMTZfdQAJDGk2NF9sb2FkMzJfcwAKDGk2NF9sb2FkMzJfdQALCp8CDE4AQQAtAABBwQBGQQMtAABBpwFGcUEGLQAAQQBGQRMtAABBAEZxcUEULQAAQdcARkEXLQAAQc0ARnFBGC0AAEEARkH/By0AAEEARnFxcQs4AEEIQseffzcDAEEIKwMAQseff79hBEBEAAAAAAAAAAAPC0EJQgA3AABBD0HFgAE7AABBCSsAAAsOAEEIIAA6AABBCCwAAAsOAEEIIAA6AABBCC0AAAsOAEEIIAA7AQBBCC4BAAsOAEEIIAA7AQBBCC8BAAsOAEEIIAA8AABBCDAAAAsOAEEIIAA8AABBCDEAAAsOAEEIIAA9AQBBCDIBAAsOAEEIIAA9AQBBCDMBAAsOAEEIIAA+AgBBCDQCAAsOAEEIIAA+AgBBCDUCAAsLFAIAQQALBUFCQ6dEAEEUCwRXQVNN", + "AGFzbQEAAAABBgFgAX8BfwMCAQAFBAEBAQEGFgN/AEGQzgALfwBBkM4AC38AQZDOAAsHOgUGbWVtb3J5AgAKX19kYXRhX2VuZAMAC19fc3RhY2tfdG9wAwELX19oZWFwX2Jhc2UDAgRsb2FkAAAKCQEHACAALQAACw==", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8DBwYAAQABAgAFAwEAAAdXBgxsb2FkX2F0X3plcm8AAA1zdG9yZV9hdF96ZXJvAAERbG9hZF9hdF9wYWdlX3NpemUAAhJzdG9yZV9hdF9wYWdlX3NpemUAAwRncm93AAQEc2l6ZQAFCjUGBwBBACgCAAsJAEEAQQI2AgALCQBBgIAEKAIACwsAQYCABEEDNgIACwYAIABAAAsEAD8ACw==", + "AGFzbQEAAAABBgFgAX8BfwMCAQAFAwEAAAcIAQRncm93AAAKCAEGACAAQAAL", + "AGFzbQEAAAABBgFgAX8BfwMCAQAFBAEBAAoHCAEEZ3JvdwAACggBBgAgAEAACw==", + "AGFzbQEAAAABDAJgAX8Bf2ACf38BfwMDAgABBQMBAAEHHAIEZ3JvdwAAEWNoZWNrLW1lbW9yeS16ZXJvAAEKPAIGACAAQAALMwEBf0EBIQICQANAIAAtAAAhAiACQQBHDQEgACABTw0BIABBAWohACAAIAFNDQALCyACCw==", + "AGFzbQEAAAABFQRgA39/fwF/YAABf2AAAGACf38BfwMnJgECAQECAQEBAQEBAwMBAAEBAQEBAQECAQIBAQICAgIBAQEBAQEBBAUBcAEBAQUDAQABBgYBfwFBAAsHtwUlC2FzLWJyLXZhbHVlAAANYXMtYnJfaWYtY29uZAABDmFzLWJyX2lmLXZhbHVlAAITYXMtYnJfaWYtdmFsdWUtY29uZAADEWFzLWJyX3RhYmxlLWluZGV4AAQRYXMtYnJfdGFibGUtdmFsdWUABRdhcy1icl90YWJsZS12YWx1ZS1pbmRleAAGD2FzLXJldHVybi12YWx1ZQAHCmFzLWlmLWNvbmQACAphcy1pZi10aGVuAAkKYXMtaWYtZWxzZQAKD2FzLXNlbGVjdC1maXJzdAALEGFzLXNlbGVjdC1zZWNvbmQADA5hcy1zZWxlY3QtY29uZAANDWFzLWNhbGwtZmlyc3QADwthcy1jYWxsLW1pZAAQDGFzLWNhbGwtbGFzdAARFmFzLWNhbGxfaW5kaXJlY3QtZmlyc3QAEhRhcy1jYWxsX2luZGlyZWN0LW1pZAATFWFzLWNhbGxfaW5kaXJlY3QtbGFzdAAUFmFzLWNhbGxfaW5kaXJlY3QtaW5kZXgAFRJhcy1sb2NhbC5zZXQtdmFsdWUAFhJhcy1sb2NhbC50ZWUtdmFsdWUAFxNhcy1nbG9iYWwuc2V0LXZhbHVlABgPYXMtbG9hZC1hZGRyZXNzABkQYXMtbG9hZE4tYWRkcmVzcwAaEGFzLXN0b3JlLWFkZHJlc3MAGw5hcy1zdG9yZS12YWx1ZQAcEWFzLXN0b3JlTi1hZGRyZXNzAB0PYXMtc3RvcmVOLXZhbHVlAB4QYXMtdW5hcnktb3BlcmFuZAAfDmFzLWJpbmFyeS1sZWZ0ACAPYXMtYmluYXJ5LXJpZ2h0ACEPYXMtdGVzdC1vcGVyYW5kACIPYXMtY29tcGFyZS1sZWZ0ACMQYXMtY29tcGFyZS1yaWdodAAkE2FzLW1lbW9yeS5ncm93LXNpemUAJQkHAQBBAAsBDgraAyYLAAJ/QQBAAAwACwsLAAJAQQBAAA0ACwsQAAJ/QQBAAEEBDQAaQQcLCxAAAn9BBkEAQAANABpBBwsLDgACQEEAQAAOAgAAAAsLEgACf0EAQABBAQ4CAAAAQQcLCxEAAn9BBkEAQAAOAQAAQQcLCwcAQQBAAA8LDgBBAEAABH9BAAVBAQsLDgBBAQR/QQBAAAVBAAsLDgBBAAR/QQAFQQBAAAsLCwBBAEAAIAAgARsLCwAgAEEAQAAgARsLCwBBAEEBQQBAABsLBABBfwsMAEEAQABBAkEDEA4LDABBAUEAQABBAxAOCwwAQQFBAkEAQAAQDgsPAEEAQABBAkEDQQARAAALDwBBAUEAQABBA0EAEQAACw8AQQFBAkEAQABBABEAAAsPAEEBQQJBA0EAQAARAAALCgEBf0EAQAAhAAsKAQF/QQBAACIACwoBAX9BAEAAJAALCQBBAEAAKAIACwkAQQBAACwAAAsLAEEAQABBBzYCAAsLAEECQQBAADYCAAsLAEEAQABBBzoAAAsLAEECQQBAADsBAAsHAEEAQABnCwkAQQBAAEEKagsJAEEKQQBAAGsLBwBBAEAARQsJAEEAQABBCkwLCQBBCkEAQABHCwgAQQBAAEAACw==", + "AGFzbQEAAAABBQFgAAF/AwIBAAUDAQABBxECBm1lbW9yeQIABGdyb3cAAAoIAQYAQQFAAAs=", + "AGFzbQEAAAABBQFgAAF/AhgBDGdyb3duLW1lbW9yeQZtZW1vcnkCAAIDAgEABxECBm1lbW9yeQIABGdyb3cAAAoIAQYAQQFAAAs=", + "AGFzbQEAAAABBQFgAAF/AiEBFWdyb3duLWltcG9ydGVkLW1lbW9yeQZtZW1vcnkCAAMDAgEABwgBBHNpemUAAAoGAQQAPwAL", + "AGFzbQEAAAABEQRgAABgAAF/YAABfWABfwF/AwcGAAEBAgMBBQQBAQEBB2sGD3plcm9fZXZlcnl0aGluZwAAEnRlc3Rfc3RvcmVfdG9fbG9hZAABE3Rlc3RfcmVkdW5kYW50X2xvYWQAAg90ZXN0X2RlYWRfc3RvcmUAAwZtYWxsb2MABA9tYWxsb2NfYWxpYXNpbmcABQqlAQYeAEEAQQA2AgBBBEEANgIAQQhBADYCAEEMQQA2AgALGABBCEEANgIAQQVDAAAAgDgCAEEIKAIACyIBAn9BCCgCACEAQQVBgICAgHg2AgBBCCgCACEBIAAgAWoLHwEBfUEIQaPGjJkCNgIAQQsqAgAhAEEIQQA2AgAgAAsEAEEQCyMBAn9BBBAEIQBBBBAEIQEgAEEqNgIAIAFBKzYCACAAKAIACw==", + "AGFzbQEAAAABCQJgAAF/YAF/AAMDAgABBQMBAAAHDwIEc2l6ZQAABGdyb3cAAQoOAgQAPwALBwAgAEAAGgs=", + "AGFzbQEAAAABCQJgAAF/YAF/AAMDAgABBQMBAAEHDwIEc2l6ZQAABGdyb3cAAQoOAgQAPwALBwAgAEAAGgs=", + "AGFzbQEAAAABCQJgAAF/YAF/AAMDAgABBQQBAQACBw8CBHNpemUAAARncm93AAEKDgIEAD8ACwcAIABAABoL", + "AGFzbQEAAAABCQJgAAF/YAF/AAMDAgABBQQBAQMIBw8CBHNpemUAAARncm93AAEKDgIEAD8ACwcAIABAABoL", + "AGFzbQEAAAABDwNgAAF/YAJ/fwBgAX8BfwMFBAABAgIFAwEAAQceAwVzdG9yZQABBGxvYWQAAgttZW1vcnkuZ3JvdwADCioECQA/AEGAgARsCwwAEAAgAGogATYCAAsKABAAIABqKAIACwYAIABAAAs=", + "AGFzbQEAAAABKQhgAX8Bf2ABfwF+YAF/AX1gAX8BfGACf38AYAJ/fgBgAn99AGACf3wAAxgXAAECAwAAAAABAQEBAQEEBQYHBAQFBQUFAwEAAQezAhcIaTMyLmxvYWQAAAhpNjQubG9hZAABCGYzMi5sb2FkAAIIZjY0LmxvYWQAAwtpMzIubG9hZDhfcwAEC2kzMi5sb2FkOF91AAUMaTMyLmxvYWQxNl9zAAYMaTMyLmxvYWQxNl91AAcLaTY0LmxvYWQ4X3MACAtpNjQubG9hZDhfdQAJDGk2NC5sb2FkMTZfcwAKDGk2NC5sb2FkMTZfdQALDGk2NC5sb2FkMzJfcwAMDGk2NC5sb2FkMzJfdQANCWkzMi5zdG9yZQAOCWk2NC5zdG9yZQAPCWYzMi5zdG9yZQAQCWY2NC5zdG9yZQARCmkzMi5zdG9yZTgAEgtpMzIuc3RvcmUxNgATCmk2NC5zdG9yZTgAFAtpNjQuc3RvcmUxNgAVC2k2NC5zdG9yZTMyABYKywEXBwAgACgCAAsHACAAKQMACwcAIAAqAgALBwAgACsDAAsHACAALAAACwcAIAAtAAALBwAgAC4BAAsHACAALwEACwcAIAAwAAALBwAgADEAAAsHACAAMgEACwcAIAAzAQALBwAgADQCAAsHACAANQIACwkAIAAgATYCAAsJACAAIAE3AwALCQAgACABOAIACwkAIAAgATkDAAsJACAAIAE6AAALCQAgACABOwEACwkAIAAgATwAAAsJACAAIAE9AQALCQAgACABPgIACwsdAgBBAAsIYWJjZGVmZ2gAQfj/AwsIYWJjZGVmZ2g=", + "AGFzbQEAAAAFAwEAAQsGAQEDZm9v", + "AGFzbQEAAAABBAFgAAADAwIAAAQEAXAAAwkNAQVwA9IAC9BwC9IBCwoHAgIACwIACw==", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfwMDAgABBQMBAAEHEgIEZmlsbAAAB2xvYWQ4X3UAAQoVAgsAIAAgASAC/AsACwcAIAAtAAAL", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfwMDAgABBQQBAQEBBxICBGNvcHkAAAdsb2FkOF91AAEKFgIMACAAIAEgAvwKAAALBwAgAC0AAAsLCgEAQQALBKq7zN0=", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfwMDAgABBQMBAAEHEgIEaW5pdAAAB2xvYWQ4X3UAAQwBAQoWAgwAIAAgASAC/AgAAAsHACAALQAACwsHAQEEqrvM3Q==", + "AGFzbQEAAAABCAJgAABgAX8AAwUEAAEAAQUDAQABBzsEDGRyb3BfcGFzc2l2ZQAADGluaXRfcGFzc2l2ZQABC2Ryb3BfYWN0aXZlAAILaW5pdF9hY3RpdmUAAwwBAgonBAUA/AkACwwAQQBBACAA/AgAAAsFAPwJAQsMAEEAQQAgAPwIAQALCwoCAQF4AEEACwF4", + "AGFzbQEAAAABBAFgAAADAgEADAFBCgcBBQD8CUALC4MBQQEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQA=", + "AGFzbQEAAAABBAFgAAADAgEADAEBCgcBBQD8CQALCwoBAQdnb29kYnll", + "AGFzbQEAAAABEANgAAF/YAN/f38AYAF/AX8DBQQAAAECBAQBcAADBw8CBGluaXQAAgRjYWxsAAMJCAEBAAQAAQABCiAEBABBAAsEAEEBCwwAIAAgASAC/AwAAAsHACAAEQAACw==", + "AGFzbQEAAAABCAJgAABgAX8AAwYFAAABAAEEBAFwAAEHOwQMZHJvcF9wYXNzaXZlAAEMaW5pdF9wYXNzaXZlAAILZHJvcF9hY3RpdmUAAwtpbml0X2FjdGl2ZQAECQsCAQABAABBAAsBAAoqBQIACwUA/A0ACwwAQQBBACAA/AwAAAsFAPwNAQsMAEEAQQAgAPwMAQAL", + "AGFzbQEAAAABBAFgAAADAgEACcQBQQEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAoHAQUA/A1ACw==", + "AGFzbQEAAAABBAFgAAADAgEACQUBAQABAAoHAQUA/A0ACw==", + "AGFzbQEAAAABEANgAAF/YAN/f38AYAF/AX8DBgUAAAABAgQEAXAACgcPAgRjb3B5AAMEY2FsbAAECQkBAEEACwMAAQIKJQUEAEEACwQAQQELBABBAgsMACAAIAEgAvwOAAALBwAgABEAAAs=", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABCg0CAwABCwcAIAAtAAALCxQCAEECCwQDAQQBAEEMCwUHBQIDBg==", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABChYCDABBDUECQQP8CgAACwcAIAAtAAALCxQCAEECCwQDAQQBAEEMCwUHBQIDBg==", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABChYCDABBGUEPQQL8CgAACwcAIAAtAAALCxQCAEECCwQDAQQBAEEMCwUHBQIDBg==", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABChYCDABBDUEZQQP8CgAACwcAIAAtAAALCxQCAEECCwQDAQQBAEEMCwUHBQIDBg==", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABChYCDABBFEEWQQT8CgAACwcAIAAtAAALCxQCAEECCwQDAQQBAEEMCwUHBQIDBg==", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABChYCDABBGUEBQQP8CgAACwcAIAAtAAALCxQCAEECCwQDAQQBAEEMCwUHBQIDBg==", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABChYCDABBCkEMQQf8CgAACwcAIAAtAAALCxQCAEECCwQDAQQBAEEMCwUHBQIDBg==", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABChYCDABBDEEKQQf8CgAACwcAIAAtAAALCxQCAEECCwQDAQQBAEEMCwUHBQIDBg==", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfwMDAgABBQQBAQEBBxcDA21lbQIAA3J1bgAAB2xvYWQ4X3UAAQoWAgwAIAAgASAC/AoAAAsHACAALQAACwsaAQBBAAsUAAECAwQFBgcICQoLDA0ODxAREhM=", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfwMDAgABBQQBAQEBBxcDA21lbQIAA3J1bgAAB2xvYWQ4X3UAAQoWAgwAIAAgASAC/AoAAAsHACAALQAACwsbAQBBAAsVAAECAwQFBgcICQoLDA0ODxAREhMU", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfwMDAgABBQQBAQEBBxcDA21lbQIAA3J1bgAAB2xvYWQ4X3UAAQoWAgwAIAAgASAC/AoAAAsHACAALQAACwscAQBB7P8DCxQAAQIDBAUGBwgJCgsMDQ4PEBESEw==", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfwMDAgABBQQBAQEBBxcDA21lbQIAA3J1bgAAB2xvYWQ4X3UAAQoWAgwAIAAgASAC/AoAAAsHACAALQAACwsdAQBB6/8DCxUAAQIDBAUGBwgJCgsMDQ4PEBESExQ=", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfwMDAgABBQQBAQEBBxcDA21lbQIAA3J1bgAAB2xvYWQ4X3UAAQoWAgwAIAAgASAC/AoAAAsHACAALQAACwscAQBBzv8DCxQAAQIDBAUGBwgJCgsMDQ4PEBESEw==", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfwMDAgABBQQBAQEBBxcDA21lbQIAA3J1bgAAB2xvYWQ4X3UAAQoWAgwAIAAgASAC/AoAAAsHACAALQAACwscAQBB4v8DCxQAAQIDBAUGBwgJCgsMDQ4PEBESEw==", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfwMDAgABBQMBAAEHFwMDbWVtAgADcnVuAAAHbG9hZDhfdQABChYCDAAgACABIAL8CgAACwcAIAAtAAALCxwBAEHs/wMLFAABAgMEBQYHCAkKCwwNDg8QERIT", + "AGFzbQEAAAABDAJgA39/fwBgAX8BfwMDAgABBQQBAQEBBxcDA21lbQIAA3J1bgAAB2xvYWQ4X3UAAQoWAgwAIAAgASAC/AoAAAsHACAALQAACwscAQBBgOADCxQAAQIDBAUGBwgJCgsMDQ4PEBESEw==", + "AGFzbQEAAAABCwJgAABgA39/fwF/AwMCAAEFBAEBAQEHFQIEdGVzdAAACmNoZWNrUmFuZ2UAAQpAAhYAQQpB1QBBCvwLAEEJQQpBBfwKAAALJwADQCAAIAFGBEBBfw8LIAAtAAAgAkYEQCAAQQFqIQAMAQsLIAAPCw==", + "AGFzbQEAAAABCwJgAABgA39/fwF/AwMCAAEFBAEBAQEHFQIEdGVzdAAACmNoZWNrUmFuZ2UAAQpAAhYAQQpB1QBBCvwLAEEQQQ9BBfwKAAALJwADQCAAIAFGBEBBfw8LIAAtAAAgAkYEQCAAQQFqIQAMAQsLIAAPCw==", + "AGFzbQEAAAABBAFgAAADAgEABQQBAQEBBwgBBHRlc3QAAAoTAREAQYD+A0GAgAJBgQL8CgAACw==", + "AGFzbQEAAAABBAFgAAADAgEABQQBAQEBBwgBBHRlc3QAAAoSARAAQYB+QYCAAUGBAvwKAAAL", + "AGFzbQEAAAABBAFgAAADAgEABQQBAQEBBwgBBHRlc3QAAAoTAREAQYCAAkGA/gNBgQL8CgAACw==", + "AGFzbQEAAAABBAFgAAADAgEABQQBAQEBBwgBBHRlc3QAAAoSARAAQYCAAUGAfkGBAvwKAAAL", + "AGFzbQEAAAABCwJgAABgA39/fwF/AwMCAAEFBAEBAQEHFQIEdGVzdAAACmNoZWNrUmFuZ2UAAQpUAioAQQBB1QBBgIAC/AsAQYCAAkGqAUGAgAL8CwBBgKACQYDgAUEA/AoAAAsnAANAIAAgAUYEQEF/DwsgAC0AACACRgRAIABBAWohAAwBCwsgAA8L", + "AGFzbQEAAAABBAFgAAADAgEABQQBAQEBBwgBBHRlc3QAAAoSARAAQYCABEGA4AFBAPwKAAAL", + "AGFzbQEAAAABBAFgAAADAgEABQQBAQEBBwgBBHRlc3QAAAoSARAAQYCACEGA4AFBAPwKAAAL", + "AGFzbQEAAAABBAFgAAADAgEABQQBAQEBBwgBBHRlc3QAAAoSARAAQYCgAkGAgARBAPwKAAAL", + "AGFzbQEAAAABBAFgAAADAgEABQQBAQEBBwgBBHRlc3QAAAoSARAAQYCgAkGAgAhBAPwKAAAL", + "AGFzbQEAAAABBAFgAAADAgEABQQBAQEBBwgBBHRlc3QAAAoSARAAQYCABEGAgARBAPwKAAAL", + "AGFzbQEAAAABBAFgAAADAgEABQQBAQEBBwgBBHRlc3QAAAoSARAAQYCACEGAgAhBAPwKAAAL", + "AGFzbQEAAAABCwJgAABgA39/fwF/AwMCAAEFBAEBAQEHFQIEdGVzdAAACmNoZWNrUmFuZ2UAAQq3FQKMFQBB54oBQQFBwAr8CwBB6bACQQJBnwj8CwBB0bgDQQNB3Af8CwBByqgCQQRBwgL8CwBBqT5BBUHKD/wLAEG6sQFBBkHcF/wLAEHygwFBB0HEEvwLAEHj0wJBCEHDBvwLAEH8AEEJQfEK/AsAQdQQQQpBxhX8CwBBm8YAQQtBmhj8CwBB55sDQQxB5QX8CwBB9h5BDUGHFvwLAEGzhANBDkGACvwLAEHJiQNBD0G6C/wLAEGNoAFBEEHWGPwLAEGx9AJBEUGgBPwLAEGj4QBBEkHtFPwLAEGlwgFBE0HbFPwLAEGF4gJBFEGiDPwLAEHY0AJBFUGbDfwLAEHeiAJBFkGGBfwLAEGr+wJBF0HCDvwLAEHNoQNBGEHhFPwLAEGb7QFBGUHVB/wLAEHUyABBGkGPDvwLAEGOiANBG0HnA/wLAEGh6gNBHEGSBPwLAEHcmwJBHUGvB/wLAEHwNEEeQf0C/AsAQb6QA0EfQZEY/AsAQcGEA0EgQZIF/AsAQfzbAkEhQaYN/AsAQb6EAkEiQcQI/AsAQf6MA0EjQYIL/AsAQerzAkEkQZwR/AsAQeumA0ElQdoS/AsAQY+vA0EmQfoB/AsAQdywAUEnQbEQ/AsAQeyFAUEoQcAZ/AsAQbuoA0EpQeMZ/AsAQbK0AkEqQewV/AsAQbyaAkErQZYQ/AsAQeyTAkEsQcsV/AsAQdv/AUEtQbgC/AsAQYLyA0EuQcAB/AsAQf7xAUEvQdQE/AsAQfuBAUEwQfUD/AsAQaq9A0ExQa4F/AsAQfuLAkEyQYED/AsAQdHbA0EzQYcH/AsAQYXgA0E0QdYS/AsAQfzuAkE1QaEL/AsAQfXKAUE2QdoY/AsAQb4rQTdB1xD8CwBBiZkCQThBhwT8CwBB3N4CQTlB0Bn8CwBBqO0CQTpBjg38CwBBj+wCQTtB4Bj8CwBBsa8BQTxBoQv8CwBB8ckDQT1BlwX8CwBBhfwBQT5Bhw38CwBB9xdBP0HRBfwLAEHpiQJBwABB1AD8CwBBuoQCQcEAQe0P/AsAQcqfAkHCAEEd/AsAQcuVAUHDAEHaF/wLAEHI4gBBxABBkwj8CwBB5I4BQcUAQfwZ/AsAQZ8kQcYAQcMI/AsAQZ7+AEHHAEHND/wLAEGcjgFByABB0xH8CwBB5IoDQckAQfUY/AsAQZTWAEHKAEGwD/wLAEHa/ABBywBBrwv8CwBB3uICQcwAQZkJ/AsAQfmmA0HNAEGgDPwLAEG7ggJBzgBB6gz8CwBB5NwDQc8AQdQZ/AsAQZGUA0HQAEHfAfwLAEGJIkHRAEH7EPwLAEGqwQNB0gBBqgr8CwBBrLMDQdMAQdgU/AsAQZu8AUHUAEGVCPwLAEGv0QJB1QBBmRj8CwBBs/wBQdYAQewV/AsAQeMdQdcAQdoP/AsAQcisA0HYAEEA/AsAQZWGA0HZAEGVEPwLAEG7nwFB2gBB0Bb8CwBBoogCQdsAQcAB/AsAQbrJAEHcAEGTEfwLAEH94ABB3QBBGPwLAEGL7gBB3gBBwQT8CwBBmtgCQd8AQakQ/AsAQf+eAkHgAEHsGvwLAEH4tQFB4QBBzRX8CwBB+DFB4gBBvgb8CwBBm4QCQeMAQZIP/AsAQbWrAUHkAEG+FfwLAEHOzgNB6KcDQbIQ/AoAAEGy7ANBuLICQeYB/AoAAEH5lANBzbgBQfwR/AoAAEG0NEG8uwFB/wT8CgAAQc42QfeEAkHJCPwKAABBy5cBQezQAEH9GPwKAABBrNUBQYapA0HkAPwKAABB1dQBQaLVAkG1DfwKAABB8NgDQbXDAEH3APwKAABBuy5BhBJBkgX8CgAAQbMlQa+TA0HdEfwKAABByeIAQf2VAUHBBvwKAABBztwAQanrAkHkGfwKAABB8NgAQdTfAkHpEfwKAABBiosCQak0QYwU/AoAAEHIJkGaDUGwCvwKAABBvO0DQdU7QYYN/AoAAEGY3AJBqI8BQSH8CgAAQY7XAkHMrgFBkwv8CgAAQa3sAkGbhQNBmgv8CgAAQcTxA0GzxABBwgb8CgAAQc2FAkGjnQFB9Rn8CgAAQf+8AkGtqANBgRn8CgAAQdTJAUH2zgNBlBP8CgAAQd6ZAUGyvANB2gL8CgAAQez7AEHKmAJB/hL8CgAAQbDcAEH2lQJBrAL8CgAAQaPQA0GF7QBB0Rj8CgAAQfuLAkGy2QNBgQr8CgAAQYTGAEH03wBBrwf8CgAAQYsWQbnRAEHfDvwKAABButECQYbXAkHiBfwKAABBvuwDQYWUAUH6APwKAABB7LsBQdndAkHbDfwKAABB0LABQaPzAEG+BfwKAABBlNgAQdPPAUGmDvwKAABBtLQBQfefAUGoCPwKAABBoL8DQfKrA0HHFPwKAABBlMcBQYEIQakY/AoAAEG0gwNBvNkCQc8H/AoAAEH43AFB+sUCQaAS/AoAAEHp3gNB5gFBuBb8CgAAQdCvAUGamgNBlRH8CgAAQem8AkHqygBBpg/8CgAAQcziAUH+ogFBihH8CgAAQaWeA0Gz1wJBjQj8CgAAQYTHAUHTlgJB8gz8CgAAQZTJA0H75QJBwg/8CgAAQZmrAkGQLUGjD/wKAABB194BQcSwA0HAEvwKAABBm+kDQbyNAUHMCvwKAABB5YcDQaXsAEH+AvwKAABBiIQBQfWbAkHsDvwKAABB4vcCQd7YAEH3FfwKAABB4N4BQaq7AkHDAvwKAABBspUCQdDZAUGGDfwKAABB+usDQdSgA0G9CvwKAABBte4AQejpAkGEBfwKAABB5uIBQYKVAUHwA/wKAABBmN8CQdnzAkHgFfwKAABBh7UCQfXcAkHGCvwKAABB8NAAQdrkAUHDC/wKAABBv+4CQeLoAkG7C/wKAABBqSZBxOABQecO/AoAAEH8qAJBpb8DQdcN/AoAAEHOzgFB19QBQecI/AoAAEHTywNB0cABQacI/AoAAEGs3wNBhq8CQf4F/AoAAEGA2QJB7BFB8Av8CgAAQeT/AUGF8QJBxhf8CgAAQYzXAEGMpgFB8wf8CgAAQfE7Qfz2AUHaF/wKAABB/IwBQbvlAEH4GfwKAABB2r8DQeG0A0G0AvwKAABB48ABQa+DAUGDCfwKAABBvJsBQYPPAEHSBfwKAABB6RZBry5BwhL8CgAAQf/7AUGvhwNB7hb8CgAAQZb2AEGThwFBrxT8CgAAQYfkAkGf3gFB/Q/8CgAAQe2uA0GRmgJBpBT8CgAAQa3eAUGNpwNBkAn8CgAAQc/2AkGJoQNBwRj8CgAAQbbvAUHj4AJB2RT8CgAAQcEnQcchQTT8CgAAQaQ0QYO9AUG5A/wKAABB2IECQe3TAUH1GvwKAABBkv4BQezPA0HhFfwKAABBuYwCQYLGAEHmEvwKAABB5YsBQYqqA0G1GvwKAABBnbEBQffYAkGIAfwKAABB0c0DQaU3QZUI/AoAAEHBzwJB9K0DQdUS/AoAAEGV3QJBqp0BQe0G/AoAAEHKnwJB7MQBQfca/AoAAEGu5QJBkPkBQdYG/AoAAEGsvQFB+vgBQeEK/AoAAEHyhwJBtAVBugz8CgAAQcrZA0GZkQFBqxf8CgAAQcKJA0G3wgJB/gr8CgAACycAA0AgACABRgRAQX8PCyAALQAAIAJGBEAgAEEBaiEADAELCyAADws=", + "AGFzbQEAAAABCwJgA39/fwF/YAAAAwMCAAEFBAEBAQEHFQIKY2hlY2tSYW5nZQAABHRlc3QAAQo5AicAA0AgACABRgRAQX8PCyAALQAAIAJGBEAgAEEBaiEADAELCyAADwsPAEGA/gNB1QBBgAL8CwAL", + "AGFzbQEAAAABCwJgA39/fwF/YAAAAwMCAAEFBAEBAQEHFQIKY2hlY2tSYW5nZQAABHRlc3QAAQo5AicAA0AgACABRgRAQX8PCyAALQAAIAJGBEAgAEEBaiEADAELCyAADwsPAEGA/gNB1QBBgQL8CwAL", + "AGFzbQEAAAABCwJgA39/fwF/YAAAAwMCAAEFBAEBAQEHFQIKY2hlY2tSYW5nZQAABHRlc3QAAQo4AicAA0AgACABRgRAQX8PCyAALQAAIAJGBEAgAEEBaiEADAELCyAADwsOAEGAfkHVAEGBAvwLAAs=", + "AGFzbQEAAAABCwJgA39/fwF/YAAAAwMCAAEFBAEBAQEHFQIKY2hlY2tSYW5nZQAABHRlc3QAAQo2AicAA0AgACABRgRAQX8PCyAALQAAIAJGBEAgAEEBaiEADAELCyAADwsMAEESQdUAQQD8CwAL", + "AGFzbQEAAAABCwJgA39/fwF/YAAAAwMCAAEFBAEBAQEHFQIKY2hlY2tSYW5nZQAABHRlc3QAAQo4AicAA0AgACABRgRAQX8PCyAALQAAIAJGBEAgAEEBaiEADAELCyAADwsOAEGAgARB1QBBAPwLAAs=", + "AGFzbQEAAAABCwJgA39/fwF/YAAAAwMCAAEFBAEBAQEHFQIKY2hlY2tSYW5nZQAABHRlc3QAAQo4AicAA0AgACABRgRAQX8PCyAALQAAIAJGBEAgAEEBaiEADAELCyAADwsOAEGAgAhB1QBBAPwLAAs=", + "AGFzbQEAAAABCwJgA39/fwF/YAAAAwMCAAEFBAEBAQEHFQIKY2hlY2tSYW5nZQAABHRlc3QAAQo4AicAA0AgACABRgRAQX8PCyAALQAAIAJGBEAgAEEBaiEADAELCyAADwsOAEEBQaoBQf7/A/wLAAs=", + "AGFzbQEAAAABCwJgA39/fwF/YAAAAwMCAAEFBAEBAQEHFQIKY2hlY2tSYW5nZQAABHRlc3QAAQpAAicAA0AgACABRgRAQX8PCyAALQAAIAJGBEAgAEEBaiEADAELCyAADwsWAEESQdUAQQr8CwBBFUGqAUEE/AsACw==", + "AGFzbQEAAAABDgJgA39/fwF/YAN/f38AAwMCAAEFBAEBAQEHFAIKY2hlY2tSYW5nZQAAA3J1bgABCjUCJwADQCAAIAFGBEBBfw8LIAAtAAAgAkYEQCAAQQFqIQAMAQsLIAAPCwsAIAAgASAC/AsACw==", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABCg0CAwABCwcAIAAtAAALCyEEAEECCwQDAQQBAQQCBwEIAEEMCwUHBQIDBgEFBQkCBwY=", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABDAEEChYCDABBB0EAQQT8CAEACwcAIAAtAAALCyEEAEECCwQDAQQBAQQCBwEIAEEMCwUHBQIDBgEFBQkCBwY=", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABDAEEChYCDABBD0EBQQP8CAMACwcAIAAtAAALCyEEAEECCwQDAQQBAQQCBwEIAEEMCwUHBQIDBgEFBQkCBwY=", + "AGFzbQEAAAABCQJgAABgAX8BfwMDAgABBQQBAQEBBxwDB21lbW9yeTACAAR0ZXN0AAAHbG9hZDhfdQABDAEEClgCTgBBB0EAQQT8CAEA/AkBQQ9BAUED/AgDAPwJA0EUQQ9BBfwKAABBFUEdQQH8CgAAQRhBCkEB/AoAAEENQQtBBPwKAABBE0EUQQX8CgAACwcAIAAtAAALCyEEAEECCwQDAQQBAQQCBwEIAEEMCwUHBQIDBgEFBQkCBwY=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBCgoBCAD8CQD8CQALCwQBAQE3", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBChIBEAD8CQBB0glBAUEB/AgAAAsLBAEBATc=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBCg8BDQBB0glBAUEB/AgAAAsLBwEAQQALATc=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBChgBFgBBAUEAQQH8CAAAQQFBAEEB/AgAAAsLBAEBATc=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBCg8BDQBB0glBAEEF/AgAAAsLBAEBATc=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBCg8BDQBB0glBAkED/AgAAAsLBAEBATc=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBChABDgBB/v8DQQFBA/wIAAALCwQBAQE3", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBCg8BDQBB0glBBEEA/AgAAAsLBAEBATc=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBCg8BDQBB0glBAUEA/AgAAAsLBAEBATc=", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBChABDgBBgYAEQQBBAPwIAAALCwQBAQE3", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBChABDgBBgIAEQQBBAPwIAAALCwQBAQE3", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBChABDgBBgIAEQQFBAPwIAAALCwQBAQE3", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEHCAEEdGVzdAAADAEBChABDgBBgYAEQQRBAPwIAAALCwQBAQE3", + "AGFzbQEAAAABDQJgA39/fwF/YAJ/fwADAwIAAQUEAQEBAQcUAgpjaGVja1JhbmdlAAADcnVuAAEMAQEKNgInAANAIAAgAUYEQEF/DwsgAC0AACACRgRAIABBAWohAAwBCwsgAA8LDAAgAEEAIAH8CAAACwsTAQEQQkJCQkJCQkJCQkJCQkJCQg==", + "AGFzbQEAAAABDQJgA39/fwF/YAJ/fwADAwIAAQUDAQABBxQCCmNoZWNrUmFuZ2UAAANydW4AAQwBAQo2AicAA0AgACABRgRAQX8PCyAALQAAIAJGBEAgAEEBaiEADAELCyAADwsMACAAQQAgAfwIAAALCxMBARBCQkJCQkJCQkJCQkJCQkJC", + "AGFzbQEAAAABBAFgAAADAgEABQMBAAEMAUEKDgEMAEEAQQBBAPwIQAALC4MBQQEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQA=", + "AGFzbQEAAAAFAwEAAQuzARwAQQALAABBAQsEYWJjZABBAAsAAEEACwNhYmMAQQALAABBAQsEYWJjZABBAAsAAEEACwNhYmMAQQALAABBAQsEYWJjZABBAAsAAEEACwNhYmMBAAEEYWJjZABBAAsAAEEBCwRhYmNkAEEACwAAQQALA2FiYwBBAAsAAEEBCwRhYmNkAEEACwAAQQALA2FiYwBBAAsAAEEBCwRhYmNkAEEACwAAQQALA2FiYwEAAQRhYmNk", + "AGFzbQEAAAAFAwEAAQsHAQBBAAsBYQ==", + "AGFzbQEAAAAFAwEAAQsiBQBBAAsBYQBBAwsBYgBB5AALA2NkZQBBBQsBeABBAwsBYw==", + "AGFzbQEAAAACGAEIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AAUDAQABCwcBACMACwFh", + "AGFzbQEAAAAFAwEAAQsPAgBBAAsBYQBB//8DCwFi", + "AGFzbQEAAAAFAwEAAgsJAQBB//8HCwFh", + "AGFzbQEAAAAFAwEAAAsGAQBBAAsA", + "AGFzbQEAAAAFBAEBAAALBgEAQQALAA==", + "AGFzbQEAAAAFAwEAAQsIAQBBgIAECwA=", + "AGFzbQEAAAAFAwEAAAsHAQBBAAsBYQ==", + "AGFzbQEAAAAFBAEBAAALBwEAQQALAWE=", + "AGFzbQEAAAAFBAEBAAELBwEAQQALAWE=", + "AGFzbQEAAAAFAwEAAAsGAQBBAQsA", + "AGFzbQEAAAAFBAEBAAELBgEAQQELAA==", + "AGFzbQEAAAACGAEIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AAUDAQAACwcBACMACwFh", + "AGFzbQEAAAAFBAEBAQILCQEAQYCABAsBYQ==", + "AGFzbQEAAAAFAwEAAgsJAQBBgIAICwFh", + "AGFzbQEAAAAFBAEBAgMLCQEAQYCACAsBYQ==", + "AGFzbQEAAAAFAwEAAQsHAQBBfwsBYQ==", + "AGFzbQEAAAAFAwEAAgsIAQBBnH8LAWE=", +]; +export const script = "[[\"file\",\"address.wast\"],[\"module\",3,0],[\"invoke\",104,0,\"8u_good1\",[\"i32:0\"]],[\"invoke\",105,0,\"8u_good2\",[\"i32:0\"]],[\"invoke\",106,0,\"8u_good3\",[\"i32:0\"]],[\"invoke\",107,0,\"8u_good4\",[\"i32:0\"]],[\"invoke\",108,0,\"8u_good5\",[\"i32:0\"]],[\"invoke\",110,0,\"8s_good1\",[\"i32:0\"]],[\"invoke\",111,0,\"8s_good2\",[\"i32:0\"]],[\"invoke\",112,0,\"8s_good3\",[\"i32:0\"]],[\"invoke\",113,0,\"8s_good4\",[\"i32:0\"]],[\"invoke\",114,0,\"8s_good5\",[\"i32:0\"]],[\"invoke\",116,0,\"16u_good1\",[\"i32:0\"]],[\"invoke\",117,0,\"16u_good2\",[\"i32:0\"]],[\"invoke\",118,0,\"16u_good3\",[\"i32:0\"]],[\"invoke\",119,0,\"16u_good4\",[\"i32:0\"]],[\"invoke\",120,0,\"16u_good5\",[\"i32:0\"]],[\"invoke\",122,0,\"16s_good1\",[\"i32:0\"]],[\"invoke\",123,0,\"16s_good2\",[\"i32:0\"]],[\"invoke\",124,0,\"16s_good3\",[\"i32:0\"]],[\"invoke\",125,0,\"16s_good4\",[\"i32:0\"]],[\"invoke\",126,0,\"16s_good5\",[\"i32:0\"]],[\"invoke\",128,0,\"32_good1\",[\"i32:0\"]],[\"invoke\",129,0,\"32_good2\",[\"i32:0\"]],[\"invoke\",130,0,\"32_good3\",[\"i32:0\"]],[\"invoke\",131,0,\"32_good4\",[\"i32:0\"]],[\"invoke\",132,0,\"32_good5\",[\"i32:0\"]],[\"invoke\",134,0,\"8u_good1\",[\"i32:65507\"]],[\"invoke\",135,0,\"8u_good2\",[\"i32:65507\"]],[\"invoke\",136,0,\"8u_good3\",[\"i32:65507\"]],[\"invoke\",137,0,\"8u_good4\",[\"i32:65507\"]],[\"invoke\",138,0,\"8u_good5\",[\"i32:65507\"]],[\"invoke\",140,0,\"8s_good1\",[\"i32:65507\"]],[\"invoke\",141,0,\"8s_good2\",[\"i32:65507\"]],[\"invoke\",142,0,\"8s_good3\",[\"i32:65507\"]],[\"invoke\",143,0,\"8s_good4\",[\"i32:65507\"]],[\"invoke\",144,0,\"8s_good5\",[\"i32:65507\"]],[\"invoke\",146,0,\"16u_good1\",[\"i32:65507\"]],[\"invoke\",147,0,\"16u_good2\",[\"i32:65507\"]],[\"invoke\",148,0,\"16u_good3\",[\"i32:65507\"]],[\"invoke\",149,0,\"16u_good4\",[\"i32:65507\"]],[\"invoke\",150,0,\"16u_good5\",[\"i32:65507\"]],[\"invoke\",152,0,\"16s_good1\",[\"i32:65507\"]],[\"invoke\",153,0,\"16s_good2\",[\"i32:65507\"]],[\"invoke\",154,0,\"16s_good3\",[\"i32:65507\"]],[\"invoke\",155,0,\"16s_good4\",[\"i32:65507\"]],[\"invoke\",156,0,\"16s_good5\",[\"i32:65507\"]],[\"invoke\",158,0,\"32_good1\",[\"i32:65507\"]],[\"invoke\",159,0,\"32_good2\",[\"i32:65507\"]],[\"invoke\",160,0,\"32_good3\",[\"i32:65507\"]],[\"invoke\",161,0,\"32_good4\",[\"i32:65507\"]],[\"invoke\",162,0,\"32_good5\",[\"i32:65507\"]],[\"invoke\",164,0,\"8u_good1\",[\"i32:65508\"]],[\"invoke\",165,0,\"8u_good2\",[\"i32:65508\"]],[\"invoke\",166,0,\"8u_good3\",[\"i32:65508\"]],[\"invoke\",167,0,\"8u_good4\",[\"i32:65508\"]],[\"invoke\",168,0,\"8u_good5\",[\"i32:65508\"]],[\"invoke\",170,0,\"8s_good1\",[\"i32:65508\"]],[\"invoke\",171,0,\"8s_good2\",[\"i32:65508\"]],[\"invoke\",172,0,\"8s_good3\",[\"i32:65508\"]],[\"invoke\",173,0,\"8s_good4\",[\"i32:65508\"]],[\"invoke\",174,0,\"8s_good5\",[\"i32:65508\"]],[\"invoke\",176,0,\"16u_good1\",[\"i32:65508\"]],[\"invoke\",177,0,\"16u_good2\",[\"i32:65508\"]],[\"invoke\",178,0,\"16u_good3\",[\"i32:65508\"]],[\"invoke\",179,0,\"16u_good4\",[\"i32:65508\"]],[\"invoke\",180,0,\"16u_good5\",[\"i32:65508\"]],[\"invoke\",182,0,\"16s_good1\",[\"i32:65508\"]],[\"invoke\",183,0,\"16s_good2\",[\"i32:65508\"]],[\"invoke\",184,0,\"16s_good3\",[\"i32:65508\"]],[\"invoke\",185,0,\"16s_good4\",[\"i32:65508\"]],[\"invoke\",186,0,\"16s_good5\",[\"i32:65508\"]],[\"invoke\",188,0,\"32_good1\",[\"i32:65508\"]],[\"invoke\",189,0,\"32_good2\",[\"i32:65508\"]],[\"invoke\",190,0,\"32_good3\",[\"i32:65508\"]],[\"invoke\",191,0,\"32_good4\",[\"i32:65508\"]],[\"invoke\",192,0,\"32_good5\",[\"i32:65508\"]],[\"invoke\",194,0,\"8u_good3\",[\"i32:4294967295\"]],[\"invoke\",195,0,\"8s_good3\",[\"i32:4294967295\"]],[\"invoke\",196,0,\"16u_good3\",[\"i32:4294967295\"]],[\"invoke\",197,0,\"16s_good3\",[\"i32:4294967295\"]],[\"invoke\",198,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",199,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",201,0,\"8u_bad\",[\"i32:0\"]],[\"invoke\",202,0,\"8s_bad\",[\"i32:0\"]],[\"invoke\",203,0,\"16u_bad\",[\"i32:0\"]],[\"invoke\",204,0,\"16s_bad\",[\"i32:0\"]],[\"invoke\",205,0,\"32_bad\",[\"i32:0\"]],[\"invoke\",207,0,\"8u_bad\",[\"i32:1\"]],[\"invoke\",208,0,\"8s_bad\",[\"i32:1\"]],[\"invoke\",209,0,\"16u_bad\",[\"i32:1\"]],[\"invoke\",210,0,\"16s_bad\",[\"i32:1\"]],[\"invoke\",211,0,\"32_bad\",[\"i32:1\"]],[\"module\",223,1],[\"invoke\",362,0,\"8u_good1\",[\"i32:0\"]],[\"invoke\",363,0,\"8u_good2\",[\"i32:0\"]],[\"invoke\",364,0,\"8u_good3\",[\"i32:0\"]],[\"invoke\",365,0,\"8u_good4\",[\"i32:0\"]],[\"invoke\",366,0,\"8u_good5\",[\"i32:0\"]],[\"invoke\",368,0,\"8s_good1\",[\"i32:0\"]],[\"invoke\",369,0,\"8s_good2\",[\"i32:0\"]],[\"invoke\",370,0,\"8s_good3\",[\"i32:0\"]],[\"invoke\",371,0,\"8s_good4\",[\"i32:0\"]],[\"invoke\",372,0,\"8s_good5\",[\"i32:0\"]],[\"invoke\",374,0,\"16u_good1\",[\"i32:0\"]],[\"invoke\",375,0,\"16u_good2\",[\"i32:0\"]],[\"invoke\",376,0,\"16u_good3\",[\"i32:0\"]],[\"invoke\",377,0,\"16u_good4\",[\"i32:0\"]],[\"invoke\",378,0,\"16u_good5\",[\"i32:0\"]],[\"invoke\",380,0,\"16s_good1\",[\"i32:0\"]],[\"invoke\",381,0,\"16s_good2\",[\"i32:0\"]],[\"invoke\",382,0,\"16s_good3\",[\"i32:0\"]],[\"invoke\",383,0,\"16s_good4\",[\"i32:0\"]],[\"invoke\",384,0,\"16s_good5\",[\"i32:0\"]],[\"invoke\",386,0,\"32u_good1\",[\"i32:0\"]],[\"invoke\",387,0,\"32u_good2\",[\"i32:0\"]],[\"invoke\",388,0,\"32u_good3\",[\"i32:0\"]],[\"invoke\",389,0,\"32u_good4\",[\"i32:0\"]],[\"invoke\",390,0,\"32u_good5\",[\"i32:0\"]],[\"invoke\",392,0,\"32s_good1\",[\"i32:0\"]],[\"invoke\",393,0,\"32s_good2\",[\"i32:0\"]],[\"invoke\",394,0,\"32s_good3\",[\"i32:0\"]],[\"invoke\",395,0,\"32s_good4\",[\"i32:0\"]],[\"invoke\",396,0,\"32s_good5\",[\"i32:0\"]],[\"invoke\",398,0,\"64_good1\",[\"i32:0\"]],[\"invoke\",399,0,\"64_good2\",[\"i32:0\"]],[\"invoke\",400,0,\"64_good3\",[\"i32:0\"]],[\"invoke\",401,0,\"64_good4\",[\"i32:0\"]],[\"invoke\",402,0,\"64_good5\",[\"i32:0\"]],[\"invoke\",404,0,\"8u_good1\",[\"i32:65503\"]],[\"invoke\",405,0,\"8u_good2\",[\"i32:65503\"]],[\"invoke\",406,0,\"8u_good3\",[\"i32:65503\"]],[\"invoke\",407,0,\"8u_good4\",[\"i32:65503\"]],[\"invoke\",408,0,\"8u_good5\",[\"i32:65503\"]],[\"invoke\",410,0,\"8s_good1\",[\"i32:65503\"]],[\"invoke\",411,0,\"8s_good2\",[\"i32:65503\"]],[\"invoke\",412,0,\"8s_good3\",[\"i32:65503\"]],[\"invoke\",413,0,\"8s_good4\",[\"i32:65503\"]],[\"invoke\",414,0,\"8s_good5\",[\"i32:65503\"]],[\"invoke\",416,0,\"16u_good1\",[\"i32:65503\"]],[\"invoke\",417,0,\"16u_good2\",[\"i32:65503\"]],[\"invoke\",418,0,\"16u_good3\",[\"i32:65503\"]],[\"invoke\",419,0,\"16u_good4\",[\"i32:65503\"]],[\"invoke\",420,0,\"16u_good5\",[\"i32:65503\"]],[\"invoke\",422,0,\"16s_good1\",[\"i32:65503\"]],[\"invoke\",423,0,\"16s_good2\",[\"i32:65503\"]],[\"invoke\",424,0,\"16s_good3\",[\"i32:65503\"]],[\"invoke\",425,0,\"16s_good4\",[\"i32:65503\"]],[\"invoke\",426,0,\"16s_good5\",[\"i32:65503\"]],[\"invoke\",428,0,\"32u_good1\",[\"i32:65503\"]],[\"invoke\",429,0,\"32u_good2\",[\"i32:65503\"]],[\"invoke\",430,0,\"32u_good3\",[\"i32:65503\"]],[\"invoke\",431,0,\"32u_good4\",[\"i32:65503\"]],[\"invoke\",432,0,\"32u_good5\",[\"i32:65503\"]],[\"invoke\",434,0,\"32s_good1\",[\"i32:65503\"]],[\"invoke\",435,0,\"32s_good2\",[\"i32:65503\"]],[\"invoke\",436,0,\"32s_good3\",[\"i32:65503\"]],[\"invoke\",437,0,\"32s_good4\",[\"i32:65503\"]],[\"invoke\",438,0,\"32s_good5\",[\"i32:65503\"]],[\"invoke\",440,0,\"64_good1\",[\"i32:65503\"]],[\"invoke\",441,0,\"64_good2\",[\"i32:65503\"]],[\"invoke\",442,0,\"64_good3\",[\"i32:65503\"]],[\"invoke\",443,0,\"64_good4\",[\"i32:65503\"]],[\"invoke\",444,0,\"64_good5\",[\"i32:65503\"]],[\"invoke\",446,0,\"8u_good1\",[\"i32:65504\"]],[\"invoke\",447,0,\"8u_good2\",[\"i32:65504\"]],[\"invoke\",448,0,\"8u_good3\",[\"i32:65504\"]],[\"invoke\",449,0,\"8u_good4\",[\"i32:65504\"]],[\"invoke\",450,0,\"8u_good5\",[\"i32:65504\"]],[\"invoke\",452,0,\"8s_good1\",[\"i32:65504\"]],[\"invoke\",453,0,\"8s_good2\",[\"i32:65504\"]],[\"invoke\",454,0,\"8s_good3\",[\"i32:65504\"]],[\"invoke\",455,0,\"8s_good4\",[\"i32:65504\"]],[\"invoke\",456,0,\"8s_good5\",[\"i32:65504\"]],[\"invoke\",458,0,\"16u_good1\",[\"i32:65504\"]],[\"invoke\",459,0,\"16u_good2\",[\"i32:65504\"]],[\"invoke\",460,0,\"16u_good3\",[\"i32:65504\"]],[\"invoke\",461,0,\"16u_good4\",[\"i32:65504\"]],[\"invoke\",462,0,\"16u_good5\",[\"i32:65504\"]],[\"invoke\",464,0,\"16s_good1\",[\"i32:65504\"]],[\"invoke\",465,0,\"16s_good2\",[\"i32:65504\"]],[\"invoke\",466,0,\"16s_good3\",[\"i32:65504\"]],[\"invoke\",467,0,\"16s_good4\",[\"i32:65504\"]],[\"invoke\",468,0,\"16s_good5\",[\"i32:65504\"]],[\"invoke\",470,0,\"32u_good1\",[\"i32:65504\"]],[\"invoke\",471,0,\"32u_good2\",[\"i32:65504\"]],[\"invoke\",472,0,\"32u_good3\",[\"i32:65504\"]],[\"invoke\",473,0,\"32u_good4\",[\"i32:65504\"]],[\"invoke\",474,0,\"32u_good5\",[\"i32:65504\"]],[\"invoke\",476,0,\"32s_good1\",[\"i32:65504\"]],[\"invoke\",477,0,\"32s_good2\",[\"i32:65504\"]],[\"invoke\",478,0,\"32s_good3\",[\"i32:65504\"]],[\"invoke\",479,0,\"32s_good4\",[\"i32:65504\"]],[\"invoke\",480,0,\"32s_good5\",[\"i32:65504\"]],[\"invoke\",482,0,\"64_good1\",[\"i32:65504\"]],[\"invoke\",483,0,\"64_good2\",[\"i32:65504\"]],[\"invoke\",484,0,\"64_good3\",[\"i32:65504\"]],[\"invoke\",485,0,\"64_good4\",[\"i32:65504\"]],[\"invoke\",486,0,\"64_good5\",[\"i32:65504\"]],[\"invoke\",488,0,\"8u_good3\",[\"i32:4294967295\"]],[\"invoke\",489,0,\"8s_good3\",[\"i32:4294967295\"]],[\"invoke\",490,0,\"16u_good3\",[\"i32:4294967295\"]],[\"invoke\",491,0,\"16s_good3\",[\"i32:4294967295\"]],[\"invoke\",492,0,\"32u_good3\",[\"i32:4294967295\"]],[\"invoke\",493,0,\"32s_good3\",[\"i32:4294967295\"]],[\"invoke\",494,0,\"64_good3\",[\"i32:4294967295\"]],[\"invoke\",496,0,\"8u_bad\",[\"i32:0\"]],[\"invoke\",497,0,\"8s_bad\",[\"i32:0\"]],[\"invoke\",498,0,\"16u_bad\",[\"i32:0\"]],[\"invoke\",499,0,\"16s_bad\",[\"i32:0\"]],[\"invoke\",500,0,\"32u_bad\",[\"i32:0\"]],[\"invoke\",501,0,\"32s_bad\",[\"i32:0\"]],[\"invoke\",502,0,\"64_bad\",[\"i32:0\"]],[\"invoke\",504,0,\"8u_bad\",[\"i32:1\"]],[\"invoke\",505,0,\"8s_bad\",[\"i32:1\"]],[\"invoke\",506,0,\"16u_bad\",[\"i32:1\"]],[\"invoke\",507,0,\"16s_bad\",[\"i32:1\"]],[\"invoke\",508,0,\"32u_bad\",[\"i32:0\"]],[\"invoke\",509,0,\"32s_bad\",[\"i32:0\"]],[\"invoke\",510,0,\"64_bad\",[\"i32:1\"]],[\"module\",514,2],[\"invoke\",538,0,\"32_good1\",[\"i32:0\"]],[\"invoke\",539,0,\"32_good2\",[\"i32:0\"]],[\"invoke\",540,0,\"32_good3\",[\"i32:0\"]],[\"invoke\",541,0,\"32_good4\",[\"i32:0\"]],[\"invoke\",542,0,\"32_good5\",[\"i32:0\"]],[\"invoke\",544,0,\"32_good1\",[\"i32:65524\"]],[\"invoke\",545,0,\"32_good2\",[\"i32:65524\"]],[\"invoke\",546,0,\"32_good3\",[\"i32:65524\"]],[\"invoke\",547,0,\"32_good4\",[\"i32:65524\"]],[\"invoke\",548,0,\"32_good5\",[\"i32:65524\"]],[\"invoke\",550,0,\"32_good1\",[\"i32:65525\"]],[\"invoke\",551,0,\"32_good2\",[\"i32:65525\"]],[\"invoke\",552,0,\"32_good3\",[\"i32:65525\"]],[\"invoke\",553,0,\"32_good4\",[\"i32:65525\"]],[\"invoke\",554,0,\"32_good5\",[\"i32:65525\"]],[\"invoke\",556,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",557,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",559,0,\"32_bad\",[\"i32:0\"]],[\"invoke\",560,0,\"32_bad\",[\"i32:1\"]],[\"module\",564,3],[\"invoke\",588,0,\"64_good1\",[\"i32:0\"]],[\"invoke\",589,0,\"64_good2\",[\"i32:0\"]],[\"invoke\",590,0,\"64_good3\",[\"i32:0\"]],[\"invoke\",591,0,\"64_good4\",[\"i32:0\"]],[\"invoke\",592,0,\"64_good5\",[\"i32:0\"]],[\"invoke\",594,0,\"64_good1\",[\"i32:65510\"]],[\"invoke\",595,0,\"64_good2\",[\"i32:65510\"]],[\"invoke\",596,0,\"64_good3\",[\"i32:65510\"]],[\"invoke\",597,0,\"64_good4\",[\"i32:65510\"]],[\"invoke\",598,0,\"64_good5\",[\"i32:65510\"]],[\"invoke\",600,0,\"64_good1\",[\"i32:65511\"]],[\"invoke\",601,0,\"64_good2\",[\"i32:65511\"]],[\"invoke\",602,0,\"64_good3\",[\"i32:65511\"]],[\"invoke\",603,0,\"64_good4\",[\"i32:65511\"]],[\"invoke\",604,0,\"64_good5\",[\"i32:65511\"]],[\"invoke\",606,0,\"64_good3\",[\"i32:4294967295\"]],[\"invoke\",607,0,\"64_good3\",[\"i32:4294967295\"]],[\"invoke\",609,0,\"64_bad\",[\"i32:0\"]],[\"invoke\",610,0,\"64_bad\",[\"i32:1\"]],[\"file\",\"align.wast\"],[\"module\",3,4],[\"module\",4,5],[\"module\",5,6],[\"module\",6,7],[\"module\",7,8],[\"module\",8,9],[\"module\",9,10],[\"module\",10,11],[\"module\",11,12],[\"module\",12,13],[\"module\",13,14],[\"module\",14,15],[\"module\",15,16],[\"module\",16,17],[\"module\",17,18],[\"module\",18,19],[\"module\",19,20],[\"module\",20,21],[\"module\",21,22],[\"module\",22,23],[\"module\",23,24],[\"module\",24,25],[\"module\",25,26],[\"module\",458,27],[\"invoke\",802,0,\"f32_align_switch\",[\"i32:0\"]],[\"invoke\",803,0,\"f32_align_switch\",[\"i32:1\"]],[\"invoke\",804,0,\"f32_align_switch\",[\"i32:2\"]],[\"invoke\",805,0,\"f32_align_switch\",[\"i32:3\"]],[\"invoke\",807,0,\"f64_align_switch\",[\"i32:0\"]],[\"invoke\",808,0,\"f64_align_switch\",[\"i32:1\"]],[\"invoke\",809,0,\"f64_align_switch\",[\"i32:2\"]],[\"invoke\",810,0,\"f64_align_switch\",[\"i32:3\"]],[\"invoke\",811,0,\"f64_align_switch\",[\"i32:4\"]],[\"invoke\",813,0,\"i32_align_switch\",[\"i32:0\",\"i32:0\"]],[\"invoke\",814,0,\"i32_align_switch\",[\"i32:0\",\"i32:1\"]],[\"invoke\",815,0,\"i32_align_switch\",[\"i32:1\",\"i32:0\"]],[\"invoke\",816,0,\"i32_align_switch\",[\"i32:1\",\"i32:1\"]],[\"invoke\",817,0,\"i32_align_switch\",[\"i32:2\",\"i32:0\"]],[\"invoke\",818,0,\"i32_align_switch\",[\"i32:2\",\"i32:1\"]],[\"invoke\",819,0,\"i32_align_switch\",[\"i32:2\",\"i32:2\"]],[\"invoke\",820,0,\"i32_align_switch\",[\"i32:3\",\"i32:0\"]],[\"invoke\",821,0,\"i32_align_switch\",[\"i32:3\",\"i32:1\"]],[\"invoke\",822,0,\"i32_align_switch\",[\"i32:3\",\"i32:2\"]],[\"invoke\",823,0,\"i32_align_switch\",[\"i32:4\",\"i32:0\"]],[\"invoke\",824,0,\"i32_align_switch\",[\"i32:4\",\"i32:1\"]],[\"invoke\",825,0,\"i32_align_switch\",[\"i32:4\",\"i32:2\"]],[\"invoke\",826,0,\"i32_align_switch\",[\"i32:4\",\"i32:4\"]],[\"invoke\",828,0,\"i64_align_switch\",[\"i32:0\",\"i32:0\"]],[\"invoke\",829,0,\"i64_align_switch\",[\"i32:0\",\"i32:1\"]],[\"invoke\",830,0,\"i64_align_switch\",[\"i32:1\",\"i32:0\"]],[\"invoke\",831,0,\"i64_align_switch\",[\"i32:1\",\"i32:1\"]],[\"invoke\",832,0,\"i64_align_switch\",[\"i32:2\",\"i32:0\"]],[\"invoke\",833,0,\"i64_align_switch\",[\"i32:2\",\"i32:1\"]],[\"invoke\",834,0,\"i64_align_switch\",[\"i32:2\",\"i32:2\"]],[\"invoke\",835,0,\"i64_align_switch\",[\"i32:3\",\"i32:0\"]],[\"invoke\",836,0,\"i64_align_switch\",[\"i32:3\",\"i32:1\"]],[\"invoke\",837,0,\"i64_align_switch\",[\"i32:3\",\"i32:2\"]],[\"invoke\",838,0,\"i64_align_switch\",[\"i32:4\",\"i32:0\"]],[\"invoke\",839,0,\"i64_align_switch\",[\"i32:4\",\"i32:1\"]],[\"invoke\",840,0,\"i64_align_switch\",[\"i32:4\",\"i32:2\"]],[\"invoke\",841,0,\"i64_align_switch\",[\"i32:4\",\"i32:4\"]],[\"invoke\",842,0,\"i64_align_switch\",[\"i32:5\",\"i32:0\"]],[\"invoke\",843,0,\"i64_align_switch\",[\"i32:5\",\"i32:1\"]],[\"invoke\",844,0,\"i64_align_switch\",[\"i32:5\",\"i32:2\"]],[\"invoke\",845,0,\"i64_align_switch\",[\"i32:5\",\"i32:4\"]],[\"invoke\",846,0,\"i64_align_switch\",[\"i32:6\",\"i32:0\"]],[\"invoke\",847,0,\"i64_align_switch\",[\"i32:6\",\"i32:1\"]],[\"invoke\",848,0,\"i64_align_switch\",[\"i32:6\",\"i32:2\"]],[\"invoke\",849,0,\"i64_align_switch\",[\"i32:6\",\"i32:4\"]],[\"invoke\",850,0,\"i64_align_switch\",[\"i32:6\",\"i32:8\"]],[\"module\",854,28],[\"invoke\",864,0,\"store\",[\"i32:65532\",\"i64:18446744073709551615\"]],[\"invoke\",866,0,\"load\",[\"i32:65532\"]],[\"file\",\"endianness.wast\"],[\"module\",1,29],[\"invoke\",133,0,\"i32_load16_s\",[\"i32:4294967295\"]],[\"invoke\",134,0,\"i32_load16_s\",[\"i32:4294963054\"]],[\"invoke\",135,0,\"i32_load16_s\",[\"i32:42\"]],[\"invoke\",136,0,\"i32_load16_s\",[\"i32:12816\"]],[\"invoke\",138,0,\"i32_load16_u\",[\"i32:4294967295\"]],[\"invoke\",139,0,\"i32_load16_u\",[\"i32:4294963054\"]],[\"invoke\",140,0,\"i32_load16_u\",[\"i32:42\"]],[\"invoke\",141,0,\"i32_load16_u\",[\"i32:51966\"]],[\"invoke\",143,0,\"i32_load\",[\"i32:4294967295\"]],[\"invoke\",144,0,\"i32_load\",[\"i32:4252543054\"]],[\"invoke\",145,0,\"i32_load\",[\"i32:42424242\"]],[\"invoke\",146,0,\"i32_load\",[\"i32:2880249322\"]],[\"invoke\",148,0,\"i64_load16_s\",[\"i64:18446744073709551615\"]],[\"invoke\",149,0,\"i64_load16_s\",[\"i64:18446744073709547374\"]],[\"invoke\",150,0,\"i64_load16_s\",[\"i64:42\"]],[\"invoke\",151,0,\"i64_load16_s\",[\"i64:12816\"]],[\"invoke\",153,0,\"i64_load16_u\",[\"i64:18446744073709551615\"]],[\"invoke\",154,0,\"i64_load16_u\",[\"i64:18446744073709547374\"]],[\"invoke\",155,0,\"i64_load16_u\",[\"i64:42\"]],[\"invoke\",156,0,\"i64_load16_u\",[\"i64:51966\"]],[\"invoke\",158,0,\"i64_load32_s\",[\"i64:18446744073709551615\"]],[\"invoke\",159,0,\"i64_load32_s\",[\"i64:18446744073667127374\"]],[\"invoke\",160,0,\"i64_load32_s\",[\"i64:42424242\"]],[\"invoke\",161,0,\"i64_load32_s\",[\"i64:305419896\"]],[\"invoke\",163,0,\"i64_load32_u\",[\"i64:18446744073709551615\"]],[\"invoke\",164,0,\"i64_load32_u\",[\"i64:18446744073667127374\"]],[\"invoke\",165,0,\"i64_load32_u\",[\"i64:42424242\"]],[\"invoke\",166,0,\"i64_load32_u\",[\"i64:2880249322\"]],[\"invoke\",168,0,\"i64_load\",[\"i64:18446744073709551615\"]],[\"invoke\",169,0,\"i64_load\",[\"i64:18446744073667127374\"]],[\"invoke\",170,0,\"i64_load\",[\"i64:2880249322\"]],[\"invoke\",171,0,\"i64_load\",[\"i64:12370766947463011818\"]],[\"invoke\",173,0,\"f32_load\",[\"f32:3212836864\"]],[\"invoke\",174,0,\"f32_load\",[\"f32:1011494326\"]],[\"invoke\",175,0,\"f32_load\",[\"f32:1166316389\"]],[\"invoke\",176,0,\"f32_load\",[\"f32:2139095039\"]],[\"invoke\",178,0,\"f64_load\",[\"f64:13830554455654793216\"]],[\"invoke\",179,0,\"f64_load\",[\"f64:4653144502447687399\"]],[\"invoke\",180,0,\"f64_load\",[\"f64:4691032041816096430\"]],[\"invoke\",181,0,\"f64_load\",[\"f64:9218868437227405311\"]],[\"invoke\",184,0,\"i32_store16\",[\"i32:4294967295\"]],[\"invoke\",185,0,\"i32_store16\",[\"i32:4294963054\"]],[\"invoke\",186,0,\"i32_store16\",[\"i32:42\"]],[\"invoke\",187,0,\"i32_store16\",[\"i32:51966\"]],[\"invoke\",189,0,\"i32_store\",[\"i32:4294967295\"]],[\"invoke\",190,0,\"i32_store\",[\"i32:4294963054\"]],[\"invoke\",191,0,\"i32_store\",[\"i32:42424242\"]],[\"invoke\",192,0,\"i32_store\",[\"i32:3735931646\"]],[\"invoke\",194,0,\"i64_store16\",[\"i64:18446744073709551615\"]],[\"invoke\",195,0,\"i64_store16\",[\"i64:18446744073709547374\"]],[\"invoke\",196,0,\"i64_store16\",[\"i64:42\"]],[\"invoke\",197,0,\"i64_store16\",[\"i64:51966\"]],[\"invoke\",199,0,\"i64_store32\",[\"i64:18446744073709551615\"]],[\"invoke\",200,0,\"i64_store32\",[\"i64:18446744073709547374\"]],[\"invoke\",201,0,\"i64_store32\",[\"i64:42424242\"]],[\"invoke\",202,0,\"i64_store32\",[\"i64:3735931646\"]],[\"invoke\",204,0,\"i64_store\",[\"i64:18446744073709551615\"]],[\"invoke\",205,0,\"i64_store\",[\"i64:18446744073667127374\"]],[\"invoke\",206,0,\"i64_store\",[\"i64:2880249322\"]],[\"invoke\",207,0,\"i64_store\",[\"i64:12370766947463011818\"]],[\"invoke\",209,0,\"f32_store\",[\"f32:3212836864\"]],[\"invoke\",210,0,\"f32_store\",[\"f32:1011494326\"]],[\"invoke\",211,0,\"f32_store\",[\"f32:1166316389\"]],[\"invoke\",212,0,\"f32_store\",[\"f32:2139095039\"]],[\"invoke\",214,0,\"f64_store\",[\"f64:13830554455654793216\"]],[\"invoke\",215,0,\"f64_store\",[\"f64:4653144502447687399\"]],[\"invoke\",216,0,\"f64_store\",[\"f64:4691032041816096430\"]],[\"invoke\",217,0,\"f64_store\",[\"f64:9218868437227405311\"]],[\"file\",\"float_memory.wast\"],[\"module\",5,30],[\"invoke\",15,0,\"i32.load\",[]],[\"invoke\",16,0,\"f32.load\",[]],[\"invoke\",17,0,\"reset\",[]],[\"invoke\",18,0,\"i32.load\",[]],[\"invoke\",19,0,\"f32.load\",[]],[\"invoke\",20,0,\"f32.store\",[]],[\"invoke\",21,0,\"i32.load\",[]],[\"invoke\",22,0,\"f32.load\",[]],[\"invoke\",23,0,\"reset\",[]],[\"invoke\",24,0,\"i32.load\",[]],[\"invoke\",25,0,\"f32.load\",[]],[\"invoke\",26,0,\"i32.store\",[]],[\"invoke\",27,0,\"i32.load\",[]],[\"invoke\",28,0,\"f32.load\",[]],[\"module\",30,31],[\"invoke\",40,0,\"i64.load\",[]],[\"invoke\",41,0,\"f64.load\",[]],[\"invoke\",42,0,\"reset\",[]],[\"invoke\",43,0,\"i64.load\",[]],[\"invoke\",44,0,\"f64.load\",[]],[\"invoke\",45,0,\"f64.store\",[]],[\"invoke\",46,0,\"i64.load\",[]],[\"invoke\",47,0,\"f64.load\",[]],[\"invoke\",48,0,\"reset\",[]],[\"invoke\",49,0,\"i64.load\",[]],[\"invoke\",50,0,\"f64.load\",[]],[\"invoke\",51,0,\"i64.store\",[]],[\"invoke\",52,0,\"i64.load\",[]],[\"invoke\",53,0,\"f64.load\",[]],[\"module\",57,32],[\"invoke\",67,0,\"i32.load\",[]],[\"invoke\",68,0,\"f32.load\",[]],[\"invoke\",69,0,\"reset\",[]],[\"invoke\",70,0,\"i32.load\",[]],[\"invoke\",71,0,\"f32.load\",[]],[\"invoke\",72,0,\"f32.store\",[]],[\"invoke\",73,0,\"i32.load\",[]],[\"invoke\",74,0,\"f32.load\",[]],[\"invoke\",75,0,\"reset\",[]],[\"invoke\",76,0,\"i32.load\",[]],[\"invoke\",77,0,\"f32.load\",[]],[\"invoke\",78,0,\"i32.store\",[]],[\"invoke\",79,0,\"i32.load\",[]],[\"invoke\",80,0,\"f32.load\",[]],[\"module\",82,33],[\"invoke\",92,0,\"i64.load\",[]],[\"invoke\",93,0,\"f64.load\",[]],[\"invoke\",94,0,\"reset\",[]],[\"invoke\",95,0,\"i64.load\",[]],[\"invoke\",96,0,\"f64.load\",[]],[\"invoke\",97,0,\"f64.store\",[]],[\"invoke\",98,0,\"i64.load\",[]],[\"invoke\",99,0,\"f64.load\",[]],[\"invoke\",100,0,\"reset\",[]],[\"invoke\",101,0,\"i64.load\",[]],[\"invoke\",102,0,\"f64.load\",[]],[\"invoke\",103,0,\"i64.store\",[]],[\"invoke\",104,0,\"i64.load\",[]],[\"invoke\",105,0,\"f64.load\",[]],[\"module\",109,34],[\"invoke\",119,0,\"i32.load\",[]],[\"invoke\",120,0,\"f32.load\",[]],[\"invoke\",121,0,\"reset\",[]],[\"invoke\",122,0,\"i32.load\",[]],[\"invoke\",123,0,\"f32.load\",[]],[\"invoke\",124,0,\"f32.store\",[]],[\"invoke\",125,0,\"i32.load\",[]],[\"invoke\",126,0,\"f32.load\",[]],[\"invoke\",127,0,\"reset\",[]],[\"invoke\",128,0,\"i32.load\",[]],[\"invoke\",129,0,\"f32.load\",[]],[\"invoke\",130,0,\"i32.store\",[]],[\"invoke\",131,0,\"i32.load\",[]],[\"invoke\",132,0,\"f32.load\",[]],[\"module\",134,35],[\"invoke\",144,0,\"i64.load\",[]],[\"invoke\",145,0,\"f64.load\",[]],[\"invoke\",146,0,\"reset\",[]],[\"invoke\",147,0,\"i64.load\",[]],[\"invoke\",148,0,\"f64.load\",[]],[\"invoke\",149,0,\"f64.store\",[]],[\"invoke\",150,0,\"i64.load\",[]],[\"invoke\",151,0,\"f64.load\",[]],[\"invoke\",152,0,\"reset\",[]],[\"invoke\",153,0,\"i64.load\",[]],[\"invoke\",154,0,\"f64.load\",[]],[\"invoke\",155,0,\"i64.store\",[]],[\"invoke\",156,0,\"i64.load\",[]],[\"invoke\",157,0,\"f64.load\",[]],[\"file\",\"load.wast\"],[\"module\",3,36],[\"invoke\",161,0,\"as-br-value\",[]],[\"invoke\",163,0,\"as-br_if-cond\",[]],[\"invoke\",164,0,\"as-br_if-value\",[]],[\"invoke\",165,0,\"as-br_if-value-cond\",[]],[\"invoke\",167,0,\"as-br_table-index\",[]],[\"invoke\",168,0,\"as-br_table-value\",[]],[\"invoke\",169,0,\"as-br_table-value-index\",[]],[\"invoke\",171,0,\"as-return-value\",[]],[\"invoke\",173,0,\"as-if-cond\",[]],[\"invoke\",174,0,\"as-if-then\",[]],[\"invoke\",175,0,\"as-if-else\",[]],[\"invoke\",177,0,\"as-select-first\",[\"i32:0\",\"i32:1\"]],[\"invoke\",178,0,\"as-select-second\",[\"i32:0\",\"i32:0\"]],[\"invoke\",179,0,\"as-select-cond\",[]],[\"invoke\",181,0,\"as-call-first\",[]],[\"invoke\",182,0,\"as-call-mid\",[]],[\"invoke\",183,0,\"as-call-last\",[]],[\"invoke\",185,0,\"as-call_indirect-first\",[]],[\"invoke\",186,0,\"as-call_indirect-mid\",[]],[\"invoke\",187,0,\"as-call_indirect-last\",[]],[\"invoke\",188,0,\"as-call_indirect-index\",[]],[\"invoke\",190,0,\"as-local.set-value\",[]],[\"invoke\",191,0,\"as-local.tee-value\",[]],[\"invoke\",192,0,\"as-global.set-value\",[]],[\"invoke\",194,0,\"as-load-address\",[]],[\"invoke\",195,0,\"as-loadN-address\",[]],[\"invoke\",196,0,\"as-store-address\",[]],[\"invoke\",197,0,\"as-store-value\",[]],[\"invoke\",198,0,\"as-storeN-address\",[]],[\"invoke\",199,0,\"as-storeN-value\",[]],[\"invoke\",201,0,\"as-unary-operand\",[]],[\"invoke\",203,0,\"as-binary-left\",[]],[\"invoke\",204,0,\"as-binary-right\",[]],[\"invoke\",206,0,\"as-test-operand\",[]],[\"invoke\",208,0,\"as-compare-left\",[]],[\"invoke\",209,0,\"as-compare-right\",[]],[\"invoke\",211,0,\"as-memory.grow-size\",[]],[\"file\",\"store.wast\"],[\"module\",3,37],[\"invoke\",44,0,\"as-block-value\",[]],[\"invoke\",45,0,\"as-loop-value\",[]],[\"invoke\",47,0,\"as-br-value\",[]],[\"invoke\",48,0,\"as-br_if-value\",[]],[\"invoke\",49,0,\"as-br_if-value-cond\",[]],[\"invoke\",50,0,\"as-br_table-value\",[]],[\"invoke\",52,0,\"as-return-value\",[]],[\"invoke\",54,0,\"as-if-then\",[]],[\"invoke\",55,0,\"as-if-else\",[]],[\"file\",\"memory.wast\"],[\"module\",3,38],[\"module\",4,39],[\"module\",5,40],[\"module\",6,41],[\"module\",7,42],[\"module\",8,43],[\"module\",13,44],[\"invoke\",14,0,\"memsize\",[]],[\"module\",15,44],[\"invoke\",16,0,\"memsize\",[]],[\"module\",17,45],[\"invoke\",18,0,\"memsize\",[]],[\"module\",92,46],[\"invoke\",180,0,\"data\",[]],[\"invoke\",181,0,\"cast\",[]],[\"invoke\",183,0,\"i32_load8_s\",[\"i32:4294967295\"]],[\"invoke\",184,0,\"i32_load8_u\",[\"i32:4294967295\"]],[\"invoke\",185,0,\"i32_load16_s\",[\"i32:4294967295\"]],[\"invoke\",186,0,\"i32_load16_u\",[\"i32:4294967295\"]],[\"invoke\",188,0,\"i32_load8_s\",[\"i32:100\"]],[\"invoke\",189,0,\"i32_load8_u\",[\"i32:200\"]],[\"invoke\",190,0,\"i32_load16_s\",[\"i32:20000\"]],[\"invoke\",191,0,\"i32_load16_u\",[\"i32:40000\"]],[\"invoke\",193,0,\"i32_load8_s\",[\"i32:4275856707\"]],[\"invoke\",194,0,\"i32_load8_s\",[\"i32:878104047\"]],[\"invoke\",195,0,\"i32_load8_u\",[\"i32:4275856707\"]],[\"invoke\",196,0,\"i32_load8_u\",[\"i32:878104047\"]],[\"invoke\",197,0,\"i32_load16_s\",[\"i32:4275856707\"]],[\"invoke\",198,0,\"i32_load16_s\",[\"i32:878104047\"]],[\"invoke\",199,0,\"i32_load16_u\",[\"i32:4275856707\"]],[\"invoke\",200,0,\"i32_load16_u\",[\"i32:878104047\"]],[\"invoke\",202,0,\"i64_load8_s\",[\"i64:18446744073709551615\"]],[\"invoke\",203,0,\"i64_load8_u\",[\"i64:18446744073709551615\"]],[\"invoke\",204,0,\"i64_load16_s\",[\"i64:18446744073709551615\"]],[\"invoke\",205,0,\"i64_load16_u\",[\"i64:18446744073709551615\"]],[\"invoke\",206,0,\"i64_load32_s\",[\"i64:18446744073709551615\"]],[\"invoke\",207,0,\"i64_load32_u\",[\"i64:18446744073709551615\"]],[\"invoke\",209,0,\"i64_load8_s\",[\"i64:100\"]],[\"invoke\",210,0,\"i64_load8_u\",[\"i64:200\"]],[\"invoke\",211,0,\"i64_load16_s\",[\"i64:20000\"]],[\"invoke\",212,0,\"i64_load16_u\",[\"i64:40000\"]],[\"invoke\",213,0,\"i64_load32_s\",[\"i64:20000\"]],[\"invoke\",214,0,\"i64_load32_u\",[\"i64:40000\"]],[\"invoke\",216,0,\"i64_load8_s\",[\"i64:18364758543954109763\"]],[\"invoke\",217,0,\"i64_load8_s\",[\"i64:3771275841602506223\"]],[\"invoke\",218,0,\"i64_load8_u\",[\"i64:18364758543954109763\"]],[\"invoke\",219,0,\"i64_load8_u\",[\"i64:3771275841602506223\"]],[\"invoke\",220,0,\"i64_load16_s\",[\"i64:18364758543954109763\"]],[\"invoke\",221,0,\"i64_load16_s\",[\"i64:3771275841602506223\"]],[\"invoke\",222,0,\"i64_load16_u\",[\"i64:18364758543954109763\"]],[\"invoke\",223,0,\"i64_load16_u\",[\"i64:3771275841602506223\"]],[\"invoke\",224,0,\"i64_load32_s\",[\"i64:18364758543954109763\"]],[\"invoke\",225,0,\"i64_load32_s\",[\"i64:3771275841602506223\"]],[\"invoke\",226,0,\"i64_load32_u\",[\"i64:18364758543954109763\"]],[\"invoke\",227,0,\"i64_load32_u\",[\"i64:3771275841602506223\"]],[\"module\",246,47],[\"invoke\",260,0,\"load\",[\"i32:0\"]],[\"invoke\",261,0,\"load\",[\"i32:10000\"]],[\"invoke\",262,0,\"load\",[\"i32:20000\"]],[\"invoke\",263,0,\"load\",[\"i32:30000\"]],[\"invoke\",264,0,\"load\",[\"i32:40000\"]],[\"invoke\",265,0,\"load\",[\"i32:50000\"]],[\"invoke\",266,0,\"load\",[\"i32:60000\"]],[\"invoke\",267,0,\"load\",[\"i32:65535\"]],[\"file\",\"memory_grow.wast\"],[\"module\",1,48],[\"invoke\",14,0,\"size\",[]],[\"invoke\",15,0,\"store_at_zero\",[]],[\"invoke\",16,0,\"load_at_zero\",[]],[\"invoke\",17,0,\"store_at_page_size\",[]],[\"invoke\",18,0,\"load_at_page_size\",[]],[\"invoke\",19,0,\"grow\",[\"i32:1\"]],[\"invoke\",20,0,\"size\",[]],[\"invoke\",21,0,\"load_at_zero\",[]],[\"invoke\",22,0,\"store_at_zero\",[]],[\"invoke\",23,0,\"load_at_zero\",[]],[\"invoke\",24,0,\"store_at_page_size\",[]],[\"invoke\",25,0,\"load_at_page_size\",[]],[\"invoke\",26,0,\"grow\",[\"i32:4\"]],[\"invoke\",27,0,\"size\",[]],[\"invoke\",28,0,\"load_at_zero\",[]],[\"invoke\",29,0,\"store_at_zero\",[]],[\"invoke\",30,0,\"load_at_zero\",[]],[\"invoke\",31,0,\"load_at_page_size\",[]],[\"invoke\",32,0,\"store_at_page_size\",[]],[\"invoke\",33,0,\"load_at_page_size\",[]],[\"module\",36,49],[\"invoke\",41,0,\"grow\",[\"i32:0\"]],[\"invoke\",42,0,\"grow\",[\"i32:1\"]],[\"invoke\",43,0,\"grow\",[\"i32:0\"]],[\"invoke\",44,0,\"grow\",[\"i32:2\"]],[\"invoke\",45,0,\"grow\",[\"i32:800\"]],[\"invoke\",46,0,\"grow\",[\"i32:65536\"]],[\"invoke\",47,0,\"grow\",[\"i32:64736\"]],[\"invoke\",48,0,\"grow\",[\"i32:1\"]],[\"module\",50,50],[\"invoke\",55,0,\"grow\",[\"i32:0\"]],[\"invoke\",56,0,\"grow\",[\"i32:1\"]],[\"invoke\",57,0,\"grow\",[\"i32:1\"]],[\"invoke\",58,0,\"grow\",[\"i32:2\"]],[\"invoke\",59,0,\"grow\",[\"i32:6\"]],[\"invoke\",60,0,\"grow\",[\"i32:0\"]],[\"invoke\",61,0,\"grow\",[\"i32:1\"]],[\"invoke\",62,0,\"grow\",[\"i32:65536\"]],[\"module\",66,51],[\"invoke\",87,0,\"check-memory-zero\",[\"i32:0\",\"i32:65535\"]],[\"invoke\",88,0,\"grow\",[\"i32:1\"]],[\"invoke\",89,0,\"check-memory-zero\",[\"i32:65536\",\"i32:131071\"]],[\"invoke\",90,0,\"grow\",[\"i32:1\"]],[\"invoke\",91,0,\"check-memory-zero\",[\"i32:131072\",\"i32:196607\"]],[\"invoke\",92,0,\"grow\",[\"i32:1\"]],[\"invoke\",93,0,\"check-memory-zero\",[\"i32:196608\",\"i32:262143\"]],[\"invoke\",94,0,\"grow\",[\"i32:1\"]],[\"invoke\",95,0,\"check-memory-zero\",[\"i32:262144\",\"i32:327679\"]],[\"invoke\",96,0,\"grow\",[\"i32:1\"]],[\"invoke\",97,0,\"check-memory-zero\",[\"i32:327680\",\"i32:393215\"]],[\"module\",101,52],[\"invoke\",259,0,\"as-br-value\",[]],[\"invoke\",261,0,\"as-br_if-cond\",[]],[\"invoke\",262,0,\"as-br_if-value\",[]],[\"invoke\",263,0,\"as-br_if-value-cond\",[]],[\"invoke\",265,0,\"as-br_table-index\",[]],[\"invoke\",266,0,\"as-br_table-value\",[]],[\"invoke\",267,0,\"as-br_table-value-index\",[]],[\"invoke\",269,0,\"as-return-value\",[]],[\"invoke\",271,0,\"as-if-cond\",[]],[\"invoke\",272,0,\"as-if-then\",[]],[\"invoke\",273,0,\"as-if-else\",[]],[\"invoke\",275,0,\"as-select-first\",[\"i32:0\",\"i32:1\"]],[\"invoke\",276,0,\"as-select-second\",[\"i32:0\",\"i32:0\"]],[\"invoke\",277,0,\"as-select-cond\",[]],[\"invoke\",279,0,\"as-call-first\",[]],[\"invoke\",280,0,\"as-call-mid\",[]],[\"invoke\",281,0,\"as-call-last\",[]],[\"invoke\",283,0,\"as-call_indirect-first\",[]],[\"invoke\",284,0,\"as-call_indirect-mid\",[]],[\"invoke\",285,0,\"as-call_indirect-last\",[]],[\"invoke\",286,0,\"as-call_indirect-index\",[]],[\"invoke\",288,0,\"as-local.set-value\",[]],[\"invoke\",289,0,\"as-local.tee-value\",[]],[\"invoke\",290,0,\"as-global.set-value\",[]],[\"invoke\",292,0,\"as-load-address\",[]],[\"invoke\",293,0,\"as-loadN-address\",[]],[\"invoke\",294,0,\"as-store-address\",[]],[\"invoke\",295,0,\"as-store-value\",[]],[\"invoke\",296,0,\"as-storeN-address\",[]],[\"invoke\",297,0,\"as-storeN-value\",[]],[\"invoke\",299,0,\"as-unary-operand\",[]],[\"invoke\",301,0,\"as-binary-left\",[]],[\"invoke\",302,0,\"as-binary-right\",[]],[\"invoke\",304,0,\"as-test-operand\",[]],[\"invoke\",306,0,\"as-compare-left\",[]],[\"invoke\",307,0,\"as-compare-right\",[]],[\"invoke\",309,0,\"as-memory.grow-size\",[]],[\"module\",312,53,\"$Mgm\"],[\"register\",\"grown-memory\",\"$Mgm\"],[\"invoke\",317,\"$Mgm\",\"grow\",[]],[\"module\",318,54,\"$Mgim1\"],[\"register\",\"grown-imported-memory\",\"$Mgim1\"],[\"invoke\",324,\"$Mgim1\",\"grow\",[]],[\"module\",325,55,\"$Mgim2\"],[\"invoke\",330,\"$Mgim2\",\"size\",[]],[\"file\",\"memory_redundancy.wast\"],[\"module\",5,56],[\"invoke\",59,0,\"test_store_to_load\",[]],[\"invoke\",60,0,\"zero_everything\",[]],[\"invoke\",61,0,\"test_redundant_load\",[]],[\"invoke\",62,0,\"zero_everything\",[]],[\"invoke\",63,0,\"test_dead_store\",[]],[\"invoke\",64,0,\"zero_everything\",[]],[\"invoke\",65,0,\"malloc_aliasing\",[]],[\"file\",\"memory_size.wast\"],[\"module\",1,57],[\"invoke\",7,0,\"size\",[]],[\"invoke\",8,0,\"grow\",[\"i32:1\"]],[\"invoke\",9,0,\"size\",[]],[\"invoke\",10,0,\"grow\",[\"i32:4\"]],[\"invoke\",11,0,\"size\",[]],[\"invoke\",12,0,\"grow\",[\"i32:0\"]],[\"invoke\",13,0,\"size\",[]],[\"module\",15,58],[\"invoke\",21,0,\"size\",[]],[\"invoke\",22,0,\"grow\",[\"i32:1\"]],[\"invoke\",23,0,\"size\",[]],[\"invoke\",24,0,\"grow\",[\"i32:4\"]],[\"invoke\",25,0,\"size\",[]],[\"invoke\",26,0,\"grow\",[\"i32:0\"]],[\"invoke\",27,0,\"size\",[]],[\"module\",29,59],[\"invoke\",35,0,\"size\",[]],[\"invoke\",36,0,\"grow\",[\"i32:3\"]],[\"invoke\",37,0,\"size\",[]],[\"invoke\",38,0,\"grow\",[\"i32:1\"]],[\"invoke\",39,0,\"size\",[]],[\"invoke\",40,0,\"grow\",[\"i32:0\"]],[\"invoke\",41,0,\"size\",[]],[\"invoke\",42,0,\"grow\",[\"i32:4\"]],[\"invoke\",43,0,\"size\",[]],[\"invoke\",44,0,\"grow\",[\"i32:1\"]],[\"invoke\",45,0,\"size\",[]],[\"module\",47,60],[\"invoke\",53,0,\"size\",[]],[\"invoke\",54,0,\"grow\",[\"i32:1\"]],[\"invoke\",55,0,\"size\",[]],[\"invoke\",56,0,\"grow\",[\"i32:3\"]],[\"invoke\",57,0,\"size\",[]],[\"invoke\",58,0,\"grow\",[\"i32:0\"]],[\"invoke\",59,0,\"size\",[]],[\"invoke\",60,0,\"grow\",[\"i32:2\"]],[\"invoke\",61,0,\"size\",[]],[\"invoke\",62,0,\"grow\",[\"i32:1\"]],[\"invoke\",63,0,\"size\",[]],[\"file\",\"memory_trap.wast\"],[\"module\",1,61],[\"invoke\",21,0,\"store\",[\"i32:4294967292\",\"i32:42\"]],[\"invoke\",22,0,\"load\",[\"i32:4294967292\"]],[\"invoke\",23,0,\"store\",[\"i32:4294967293\",\"i32:305419896\"]],[\"invoke\",24,0,\"load\",[\"i32:4294967293\"]],[\"invoke\",25,0,\"store\",[\"i32:4294967294\",\"i32:13\"]],[\"invoke\",26,0,\"load\",[\"i32:4294967294\"]],[\"invoke\",27,0,\"store\",[\"i32:4294967295\",\"i32:13\"]],[\"invoke\",28,0,\"load\",[\"i32:4294967295\"]],[\"invoke\",29,0,\"store\",[\"i32:0\",\"i32:13\"]],[\"invoke\",30,0,\"load\",[\"i32:0\"]],[\"invoke\",31,0,\"store\",[\"i32:2147483648\",\"i32:13\"]],[\"invoke\",32,0,\"load\",[\"i32:2147483648\"]],[\"invoke\",33,0,\"memory.grow\",[\"i32:65537\"]],[\"module\",35,62],[\"invoke\",111,0,\"i32.store\",[\"i32:65536\",\"i32:0\"]],[\"invoke\",112,0,\"i32.store\",[\"i32:65535\",\"i32:0\"]],[\"invoke\",113,0,\"i32.store\",[\"i32:65534\",\"i32:0\"]],[\"invoke\",114,0,\"i32.store\",[\"i32:65533\",\"i32:0\"]],[\"invoke\",115,0,\"i32.store\",[\"i32:4294967295\",\"i32:0\"]],[\"invoke\",116,0,\"i32.store\",[\"i32:4294967294\",\"i32:0\"]],[\"invoke\",117,0,\"i32.store\",[\"i32:4294967293\",\"i32:0\"]],[\"invoke\",118,0,\"i32.store\",[\"i32:4294967292\",\"i32:0\"]],[\"invoke\",119,0,\"i64.store\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",120,0,\"i64.store\",[\"i32:65535\",\"i64:0\"]],[\"invoke\",121,0,\"i64.store\",[\"i32:65534\",\"i64:0\"]],[\"invoke\",122,0,\"i64.store\",[\"i32:65533\",\"i64:0\"]],[\"invoke\",123,0,\"i64.store\",[\"i32:65532\",\"i64:0\"]],[\"invoke\",124,0,\"i64.store\",[\"i32:65531\",\"i64:0\"]],[\"invoke\",125,0,\"i64.store\",[\"i32:65530\",\"i64:0\"]],[\"invoke\",126,0,\"i64.store\",[\"i32:65529\",\"i64:0\"]],[\"invoke\",127,0,\"i64.store\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",128,0,\"i64.store\",[\"i32:4294967294\",\"i64:0\"]],[\"invoke\",129,0,\"i64.store\",[\"i32:4294967293\",\"i64:0\"]],[\"invoke\",130,0,\"i64.store\",[\"i32:4294967292\",\"i64:0\"]],[\"invoke\",131,0,\"i64.store\",[\"i32:4294967291\",\"i64:0\"]],[\"invoke\",132,0,\"i64.store\",[\"i32:4294967290\",\"i64:0\"]],[\"invoke\",133,0,\"i64.store\",[\"i32:4294967289\",\"i64:0\"]],[\"invoke\",134,0,\"i64.store\",[\"i32:4294967288\",\"i64:0\"]],[\"invoke\",135,0,\"f32.store\",[\"i32:65536\",\"f32:0\"]],[\"invoke\",136,0,\"f32.store\",[\"i32:65535\",\"f32:0\"]],[\"invoke\",137,0,\"f32.store\",[\"i32:65534\",\"f32:0\"]],[\"invoke\",138,0,\"f32.store\",[\"i32:65533\",\"f32:0\"]],[\"invoke\",139,0,\"f32.store\",[\"i32:4294967295\",\"f32:0\"]],[\"invoke\",140,0,\"f32.store\",[\"i32:4294967294\",\"f32:0\"]],[\"invoke\",141,0,\"f32.store\",[\"i32:4294967293\",\"f32:0\"]],[\"invoke\",142,0,\"f32.store\",[\"i32:4294967292\",\"f32:0\"]],[\"invoke\",143,0,\"f64.store\",[\"i32:65536\",\"f64:0\"]],[\"invoke\",144,0,\"f64.store\",[\"i32:65535\",\"f64:0\"]],[\"invoke\",145,0,\"f64.store\",[\"i32:65534\",\"f64:0\"]],[\"invoke\",146,0,\"f64.store\",[\"i32:65533\",\"f64:0\"]],[\"invoke\",147,0,\"f64.store\",[\"i32:65532\",\"f64:0\"]],[\"invoke\",148,0,\"f64.store\",[\"i32:65531\",\"f64:0\"]],[\"invoke\",149,0,\"f64.store\",[\"i32:65530\",\"f64:0\"]],[\"invoke\",150,0,\"f64.store\",[\"i32:65529\",\"f64:0\"]],[\"invoke\",151,0,\"f64.store\",[\"i32:4294967295\",\"f64:0\"]],[\"invoke\",152,0,\"f64.store\",[\"i32:4294967294\",\"f64:0\"]],[\"invoke\",153,0,\"f64.store\",[\"i32:4294967293\",\"f64:0\"]],[\"invoke\",154,0,\"f64.store\",[\"i32:4294967292\",\"f64:0\"]],[\"invoke\",155,0,\"f64.store\",[\"i32:4294967291\",\"f64:0\"]],[\"invoke\",156,0,\"f64.store\",[\"i32:4294967290\",\"f64:0\"]],[\"invoke\",157,0,\"f64.store\",[\"i32:4294967289\",\"f64:0\"]],[\"invoke\",158,0,\"f64.store\",[\"i32:4294967288\",\"f64:0\"]],[\"invoke\",159,0,\"i32.store8\",[\"i32:65536\",\"i32:0\"]],[\"invoke\",160,0,\"i32.store8\",[\"i32:4294967295\",\"i32:0\"]],[\"invoke\",161,0,\"i32.store16\",[\"i32:65536\",\"i32:0\"]],[\"invoke\",162,0,\"i32.store16\",[\"i32:65535\",\"i32:0\"]],[\"invoke\",163,0,\"i32.store16\",[\"i32:4294967295\",\"i32:0\"]],[\"invoke\",164,0,\"i32.store16\",[\"i32:4294967294\",\"i32:0\"]],[\"invoke\",165,0,\"i64.store8\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",166,0,\"i64.store8\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",167,0,\"i64.store16\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",168,0,\"i64.store16\",[\"i32:65535\",\"i64:0\"]],[\"invoke\",169,0,\"i64.store16\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",170,0,\"i64.store16\",[\"i32:4294967294\",\"i64:0\"]],[\"invoke\",171,0,\"i64.store32\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",172,0,\"i64.store32\",[\"i32:65535\",\"i64:0\"]],[\"invoke\",173,0,\"i64.store32\",[\"i32:65534\",\"i64:0\"]],[\"invoke\",174,0,\"i64.store32\",[\"i32:65533\",\"i64:0\"]],[\"invoke\",175,0,\"i64.store32\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",176,0,\"i64.store32\",[\"i32:4294967294\",\"i64:0\"]],[\"invoke\",177,0,\"i64.store32\",[\"i32:4294967293\",\"i64:0\"]],[\"invoke\",178,0,\"i64.store32\",[\"i32:4294967292\",\"i64:0\"]],[\"invoke\",179,0,\"i32.load\",[\"i32:65536\"]],[\"invoke\",180,0,\"i32.load\",[\"i32:65535\"]],[\"invoke\",181,0,\"i32.load\",[\"i32:65534\"]],[\"invoke\",182,0,\"i32.load\",[\"i32:65533\"]],[\"invoke\",183,0,\"i32.load\",[\"i32:4294967295\"]],[\"invoke\",184,0,\"i32.load\",[\"i32:4294967294\"]],[\"invoke\",185,0,\"i32.load\",[\"i32:4294967293\"]],[\"invoke\",186,0,\"i32.load\",[\"i32:4294967292\"]],[\"invoke\",187,0,\"i64.load\",[\"i32:65536\"]],[\"invoke\",188,0,\"i64.load\",[\"i32:65535\"]],[\"invoke\",189,0,\"i64.load\",[\"i32:65534\"]],[\"invoke\",190,0,\"i64.load\",[\"i32:65533\"]],[\"invoke\",191,0,\"i64.load\",[\"i32:65532\"]],[\"invoke\",192,0,\"i64.load\",[\"i32:65531\"]],[\"invoke\",193,0,\"i64.load\",[\"i32:65530\"]],[\"invoke\",194,0,\"i64.load\",[\"i32:65529\"]],[\"invoke\",195,0,\"i64.load\",[\"i32:4294967295\"]],[\"invoke\",196,0,\"i64.load\",[\"i32:4294967294\"]],[\"invoke\",197,0,\"i64.load\",[\"i32:4294967293\"]],[\"invoke\",198,0,\"i64.load\",[\"i32:4294967292\"]],[\"invoke\",199,0,\"i64.load\",[\"i32:4294967291\"]],[\"invoke\",200,0,\"i64.load\",[\"i32:4294967290\"]],[\"invoke\",201,0,\"i64.load\",[\"i32:4294967289\"]],[\"invoke\",202,0,\"i64.load\",[\"i32:4294967288\"]],[\"invoke\",203,0,\"f32.load\",[\"i32:65536\"]],[\"invoke\",204,0,\"f32.load\",[\"i32:65535\"]],[\"invoke\",205,0,\"f32.load\",[\"i32:65534\"]],[\"invoke\",206,0,\"f32.load\",[\"i32:65533\"]],[\"invoke\",207,0,\"f32.load\",[\"i32:4294967295\"]],[\"invoke\",208,0,\"f32.load\",[\"i32:4294967294\"]],[\"invoke\",209,0,\"f32.load\",[\"i32:4294967293\"]],[\"invoke\",210,0,\"f32.load\",[\"i32:4294967292\"]],[\"invoke\",211,0,\"f64.load\",[\"i32:65536\"]],[\"invoke\",212,0,\"f64.load\",[\"i32:65535\"]],[\"invoke\",213,0,\"f64.load\",[\"i32:65534\"]],[\"invoke\",214,0,\"f64.load\",[\"i32:65533\"]],[\"invoke\",215,0,\"f64.load\",[\"i32:65532\"]],[\"invoke\",216,0,\"f64.load\",[\"i32:65531\"]],[\"invoke\",217,0,\"f64.load\",[\"i32:65530\"]],[\"invoke\",218,0,\"f64.load\",[\"i32:65529\"]],[\"invoke\",219,0,\"f64.load\",[\"i32:4294967295\"]],[\"invoke\",220,0,\"f64.load\",[\"i32:4294967294\"]],[\"invoke\",221,0,\"f64.load\",[\"i32:4294967293\"]],[\"invoke\",222,0,\"f64.load\",[\"i32:4294967292\"]],[\"invoke\",223,0,\"f64.load\",[\"i32:4294967291\"]],[\"invoke\",224,0,\"f64.load\",[\"i32:4294967290\"]],[\"invoke\",225,0,\"f64.load\",[\"i32:4294967289\"]],[\"invoke\",226,0,\"f64.load\",[\"i32:4294967288\"]],[\"invoke\",227,0,\"i32.load8_s\",[\"i32:65536\"]],[\"invoke\",228,0,\"i32.load8_s\",[\"i32:4294967295\"]],[\"invoke\",229,0,\"i32.load8_u\",[\"i32:65536\"]],[\"invoke\",230,0,\"i32.load8_u\",[\"i32:4294967295\"]],[\"invoke\",231,0,\"i32.load16_s\",[\"i32:65536\"]],[\"invoke\",232,0,\"i32.load16_s\",[\"i32:65535\"]],[\"invoke\",233,0,\"i32.load16_s\",[\"i32:4294967295\"]],[\"invoke\",234,0,\"i32.load16_s\",[\"i32:4294967294\"]],[\"invoke\",235,0,\"i32.load16_u\",[\"i32:65536\"]],[\"invoke\",236,0,\"i32.load16_u\",[\"i32:65535\"]],[\"invoke\",237,0,\"i32.load16_u\",[\"i32:4294967295\"]],[\"invoke\",238,0,\"i32.load16_u\",[\"i32:4294967294\"]],[\"invoke\",239,0,\"i64.load8_s\",[\"i32:65536\"]],[\"invoke\",240,0,\"i64.load8_s\",[\"i32:4294967295\"]],[\"invoke\",241,0,\"i64.load8_u\",[\"i32:65536\"]],[\"invoke\",242,0,\"i64.load8_u\",[\"i32:4294967295\"]],[\"invoke\",243,0,\"i64.load16_s\",[\"i32:65536\"]],[\"invoke\",244,0,\"i64.load16_s\",[\"i32:65535\"]],[\"invoke\",245,0,\"i64.load16_s\",[\"i32:4294967295\"]],[\"invoke\",246,0,\"i64.load16_s\",[\"i32:4294967294\"]],[\"invoke\",247,0,\"i64.load16_u\",[\"i32:65536\"]],[\"invoke\",248,0,\"i64.load16_u\",[\"i32:65535\"]],[\"invoke\",249,0,\"i64.load16_u\",[\"i32:4294967295\"]],[\"invoke\",250,0,\"i64.load16_u\",[\"i32:4294967294\"]],[\"invoke\",251,0,\"i64.load32_s\",[\"i32:65536\"]],[\"invoke\",252,0,\"i64.load32_s\",[\"i32:65535\"]],[\"invoke\",253,0,\"i64.load32_s\",[\"i32:65534\"]],[\"invoke\",254,0,\"i64.load32_s\",[\"i32:65533\"]],[\"invoke\",255,0,\"i64.load32_s\",[\"i32:4294967295\"]],[\"invoke\",256,0,\"i64.load32_s\",[\"i32:4294967294\"]],[\"invoke\",257,0,\"i64.load32_s\",[\"i32:4294967293\"]],[\"invoke\",258,0,\"i64.load32_s\",[\"i32:4294967292\"]],[\"invoke\",259,0,\"i64.load32_u\",[\"i32:65536\"]],[\"invoke\",260,0,\"i64.load32_u\",[\"i32:65535\"]],[\"invoke\",261,0,\"i64.load32_u\",[\"i32:65534\"]],[\"invoke\",262,0,\"i64.load32_u\",[\"i32:65533\"]],[\"invoke\",263,0,\"i64.load32_u\",[\"i32:4294967295\"]],[\"invoke\",264,0,\"i64.load32_u\",[\"i32:4294967294\"]],[\"invoke\",265,0,\"i64.load32_u\",[\"i32:4294967293\"]],[\"invoke\",266,0,\"i64.load32_u\",[\"i32:4294967292\"]],[\"invoke\",269,0,\"i64.load\",[\"i32:65528\"]],[\"invoke\",270,0,\"i64.load\",[\"i32:0\"]],[\"invoke\",274,0,\"i64.store\",[\"i32:65528\",\"i64:0\"]],[\"invoke\",275,0,\"i32.store\",[\"i32:65533\",\"i32:305419896\"]],[\"invoke\",276,0,\"i32.load\",[\"i32:65532\"]],[\"invoke\",277,0,\"i64.store\",[\"i32:65529\",\"i64:1311768467294899695\"]],[\"invoke\",278,0,\"i64.load\",[\"i32:65528\"]],[\"invoke\",279,0,\"f32.store\",[\"i32:65533\",\"f32:1301390004\"]],[\"invoke\",280,0,\"f32.load\",[\"i32:65532\"]],[\"invoke\",281,0,\"f64.store\",[\"i32:65529\",\"f64:4878018892390247374\"]],[\"invoke\",282,0,\"f64.load\",[\"i32:65528\"]],[\"file\",\"bulk.wast\"],[\"module\",2,63],[\"module\",6,64],[\"module\",13,65],[\"invoke\",27,0,\"fill\",[\"i32:1\",\"i32:255\",\"i32:3\"]],[\"invoke\",28,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",29,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",30,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",31,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",32,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",35,0,\"fill\",[\"i32:0\",\"i32:48042\",\"i32:2\"]],[\"invoke\",36,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",37,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",40,0,\"fill\",[\"i32:0\",\"i32:0\",\"i32:65536\"]],[\"invoke\",43,0,\"fill\",[\"i32:65280\",\"i32:1\",\"i32:257\"]],[\"invoke\",45,0,\"load8_u\",[\"i32:65280\"]],[\"invoke\",46,0,\"load8_u\",[\"i32:65535\"]],[\"invoke\",49,0,\"fill\",[\"i32:65536\",\"i32:0\",\"i32:0\"]],[\"invoke\",52,0,\"fill\",[\"i32:65537\",\"i32:0\",\"i32:0\"]],[\"module\",57,66],[\"invoke\",71,0,\"copy\",[\"i32:10\",\"i32:0\",\"i32:4\"]],[\"invoke\",73,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",74,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",75,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",76,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",77,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",78,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",81,0,\"copy\",[\"i32:8\",\"i32:10\",\"i32:4\"]],[\"invoke\",82,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",83,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",84,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",85,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",86,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",87,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",90,0,\"copy\",[\"i32:10\",\"i32:7\",\"i32:6\"]],[\"invoke\",91,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",92,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",93,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",94,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",95,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",96,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",97,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",100,0,\"copy\",[\"i32:65280\",\"i32:0\",\"i32:256\"]],[\"invoke\",101,0,\"copy\",[\"i32:65024\",\"i32:65280\",\"i32:256\"]],[\"invoke\",104,0,\"copy\",[\"i32:65536\",\"i32:0\",\"i32:0\"]],[\"invoke\",105,0,\"copy\",[\"i32:0\",\"i32:65536\",\"i32:0\"]],[\"invoke\",108,0,\"copy\",[\"i32:65537\",\"i32:0\",\"i32:0\"]],[\"invoke\",110,0,\"copy\",[\"i32:0\",\"i32:65537\",\"i32:0\"]],[\"module\",115,67],[\"invoke\",129,0,\"init\",[\"i32:0\",\"i32:1\",\"i32:2\"]],[\"invoke\",130,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",131,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",132,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",135,0,\"init\",[\"i32:65532\",\"i32:0\",\"i32:4\"]],[\"invoke\",138,0,\"init\",[\"i32:65534\",\"i32:0\",\"i32:3\"]],[\"invoke\",140,0,\"load8_u\",[\"i32:65534\"]],[\"invoke\",141,0,\"load8_u\",[\"i32:65535\"]],[\"invoke\",144,0,\"init\",[\"i32:65536\",\"i32:0\",\"i32:0\"]],[\"invoke\",145,0,\"init\",[\"i32:0\",\"i32:4\",\"i32:0\"]],[\"invoke\",148,0,\"init\",[\"i32:65537\",\"i32:0\",\"i32:0\"]],[\"invoke\",150,0,\"init\",[\"i32:0\",\"i32:5\",\"i32:0\"]],[\"module\",154,68],[\"invoke\",168,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",169,0,\"drop_passive\",[]],[\"invoke\",170,0,\"drop_passive\",[]],[\"invoke\",171,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",172,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",173,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",174,0,\"drop_active\",[]],[\"invoke\",175,0,\"init_active\",[\"i32:0\"]],[\"invoke\",176,0,\"init_active\",[\"i32:1\"]],[\"invoke\",177,0,\"init_active\",[\"i32:0\"]],[\"module\",181,69],[\"module\",196,70],[\"module\",199,71],[\"invoke\",219,0,\"init\",[\"i32:2\",\"i32:0\",\"i32:2\"]],[\"invoke\",221,0,\"call\",[\"i32:2\"]],[\"invoke\",224,0,\"init\",[\"i32:0\",\"i32:1\",\"i32:2\"]],[\"invoke\",225,0,\"call\",[\"i32:0\"]],[\"invoke\",226,0,\"call\",[\"i32:1\"]],[\"invoke\",227,0,\"call\",[\"i32:2\"]],[\"invoke\",230,0,\"init\",[\"i32:1\",\"i32:2\",\"i32:2\"]],[\"invoke\",233,0,\"init\",[\"i32:3\",\"i32:0\",\"i32:0\"]],[\"invoke\",234,0,\"init\",[\"i32:0\",\"i32:4\",\"i32:0\"]],[\"invoke\",237,0,\"init\",[\"i32:4\",\"i32:0\",\"i32:0\"]],[\"invoke\",239,0,\"init\",[\"i32:0\",\"i32:5\",\"i32:0\"]],[\"module\",244,72],[\"invoke\",261,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",262,0,\"drop_passive\",[]],[\"invoke\",263,0,\"drop_passive\",[]],[\"invoke\",264,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",265,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",266,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",267,0,\"drop_active\",[]],[\"invoke\",268,0,\"init_active\",[\"i32:0\"]],[\"invoke\",269,0,\"init_active\",[\"i32:1\"]],[\"invoke\",270,0,\"init_active\",[\"i32:0\"]],[\"module\",274,73],[\"module\",297,74],[\"module\",300,75],[\"invoke\",319,0,\"copy\",[\"i32:3\",\"i32:0\",\"i32:3\"]],[\"invoke\",321,0,\"call\",[\"i32:3\"]],[\"invoke\",322,0,\"call\",[\"i32:4\"]],[\"invoke\",323,0,\"call\",[\"i32:5\"]],[\"invoke\",326,0,\"copy\",[\"i32:0\",\"i32:1\",\"i32:3\"]],[\"invoke\",328,0,\"call\",[\"i32:0\"]],[\"invoke\",329,0,\"call\",[\"i32:1\"]],[\"invoke\",330,0,\"call\",[\"i32:2\"]],[\"invoke\",333,0,\"copy\",[\"i32:2\",\"i32:0\",\"i32:3\"]],[\"invoke\",335,0,\"call\",[\"i32:2\"]],[\"invoke\",336,0,\"call\",[\"i32:3\"]],[\"invoke\",337,0,\"call\",[\"i32:4\"]],[\"invoke\",340,0,\"copy\",[\"i32:6\",\"i32:8\",\"i32:2\"]],[\"invoke\",341,0,\"copy\",[\"i32:8\",\"i32:6\",\"i32:2\"]],[\"invoke\",344,0,\"copy\",[\"i32:10\",\"i32:0\",\"i32:0\"]],[\"invoke\",345,0,\"copy\",[\"i32:0\",\"i32:10\",\"i32:0\"]],[\"invoke\",348,0,\"copy\",[\"i32:11\",\"i32:0\",\"i32:0\"]],[\"invoke\",350,0,\"copy\",[\"i32:0\",\"i32:11\",\"i32:0\"]],[\"file\",\"memory_copy.wast\"],[\"module\",6,76],[\"invoke\",15,0,\"test\",[]],[\"invoke\",27,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",38,0,\"load8_u\",[\"i32:21\"]],[\"module\",48,77],[\"invoke\",60,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",71,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",82,0,\"load8_u\",[\"i32:23\"]],[\"module\",90,78],[\"invoke\",104,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",115,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",126,0,\"load8_u\",[\"i32:25\"]],[\"module\",132,79],[\"invoke\",147,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",158,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",169,0,\"load8_u\",[\"i32:26\"]],[\"module\",174,80],[\"invoke\",191,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",202,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",213,0,\"load8_u\",[\"i32:28\"]],[\"module\",216,81],[\"invoke\",235,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",246,0,\"load8_u\",[\"i32:19\"]],[\"module\",258,82],[\"invoke\",267,0,\"test\",[]],[\"invoke\",278,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",289,0,\"load8_u\",[\"i32:20\"]],[\"module\",300,83],[\"invoke\",311,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",322,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",333,0,\"load8_u\",[\"i32:22\"]],[\"module\",342,84],[\"invoke\",355,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",366,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",377,0,\"load8_u\",[\"i32:1014\"]],[\"invoke\",387,0,\"load8_u\",[\"i32:3004\"]],[\"invoke\",398,0,\"load8_u\",[\"i32:5193\"]],[\"invoke\",409,0,\"load8_u\",[\"i32:7382\"]],[\"invoke\",420,0,\"load8_u\",[\"i32:9571\"]],[\"invoke\",431,0,\"load8_u\",[\"i32:11760\"]],[\"invoke\",442,0,\"load8_u\",[\"i32:13949\"]],[\"invoke\",453,0,\"load8_u\",[\"i32:16138\"]],[\"invoke\",464,0,\"load8_u\",[\"i32:18327\"]],[\"invoke\",475,0,\"load8_u\",[\"i32:20516\"]],[\"invoke\",485,0,\"load8_u\",[\"i32:22506\"]],[\"invoke\",496,0,\"load8_u\",[\"i32:24695\"]],[\"invoke\",507,0,\"load8_u\",[\"i32:26884\"]],[\"invoke\",518,0,\"load8_u\",[\"i32:29073\"]],[\"invoke\",529,0,\"load8_u\",[\"i32:31262\"]],[\"invoke\",540,0,\"load8_u\",[\"i32:33451\"]],[\"invoke\",551,0,\"load8_u\",[\"i32:35640\"]],[\"invoke\",562,0,\"load8_u\",[\"i32:37829\"]],[\"invoke\",572,0,\"load8_u\",[\"i32:39819\"]],[\"invoke\",583,0,\"load8_u\",[\"i32:42008\"]],[\"invoke\",594,0,\"load8_u\",[\"i32:44197\"]],[\"invoke\",605,0,\"load8_u\",[\"i32:46386\"]],[\"invoke\",616,0,\"load8_u\",[\"i32:48575\"]],[\"invoke\",627,0,\"load8_u\",[\"i32:50764\"]],[\"invoke\",638,0,\"load8_u\",[\"i32:52953\"]],[\"invoke\",649,0,\"load8_u\",[\"i32:55142\"]],[\"invoke\",660,0,\"load8_u\",[\"i32:57331\"]],[\"invoke\",670,0,\"load8_u\",[\"i32:59321\"]],[\"invoke\",681,0,\"load8_u\",[\"i32:61510\"]],[\"invoke\",692,0,\"load8_u\",[\"i32:63699\"]],[\"module\",703,85],[\"invoke\",714,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",725,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",736,0,\"load8_u\",[\"i32:418\"]],[\"invoke\",747,0,\"load8_u\",[\"i32:2607\"]],[\"invoke\",758,0,\"load8_u\",[\"i32:4796\"]],[\"invoke\",768,0,\"load8_u\",[\"i32:6786\"]],[\"invoke\",779,0,\"load8_u\",[\"i32:8975\"]],[\"invoke\",790,0,\"load8_u\",[\"i32:11164\"]],[\"invoke\",801,0,\"load8_u\",[\"i32:13353\"]],[\"invoke\",812,0,\"load8_u\",[\"i32:15542\"]],[\"invoke\",823,0,\"load8_u\",[\"i32:17731\"]],[\"invoke\",834,0,\"load8_u\",[\"i32:19920\"]],[\"invoke\",845,0,\"load8_u\",[\"i32:22109\"]],[\"invoke\",856,0,\"load8_u\",[\"i32:24298\"]],[\"invoke\",866,0,\"load8_u\",[\"i32:26288\"]],[\"invoke\",877,0,\"load8_u\",[\"i32:28477\"]],[\"invoke\",888,0,\"load8_u\",[\"i32:30666\"]],[\"invoke\",899,0,\"load8_u\",[\"i32:32855\"]],[\"invoke\",910,0,\"load8_u\",[\"i32:35044\"]],[\"invoke\",921,0,\"load8_u\",[\"i32:37233\"]],[\"invoke\",932,0,\"load8_u\",[\"i32:39422\"]],[\"invoke\",943,0,\"load8_u\",[\"i32:41611\"]],[\"invoke\",953,0,\"load8_u\",[\"i32:43601\"]],[\"invoke\",964,0,\"load8_u\",[\"i32:45790\"]],[\"invoke\",975,0,\"load8_u\",[\"i32:47979\"]],[\"invoke\",986,0,\"load8_u\",[\"i32:50168\"]],[\"invoke\",997,0,\"load8_u\",[\"i32:52357\"]],[\"invoke\",1008,0,\"load8_u\",[\"i32:54546\"]],[\"invoke\",1019,0,\"load8_u\",[\"i32:56735\"]],[\"invoke\",1030,0,\"load8_u\",[\"i32:58924\"]],[\"invoke\",1041,0,\"load8_u\",[\"i32:61113\"]],[\"invoke\",1051,0,\"load8_u\",[\"i32:63103\"]],[\"invoke\",1062,0,\"load8_u\",[\"i32:65292\"]],[\"module\",1065,86],[\"invoke\",1084,0,\"load8_u\",[\"i32:1790\"]],[\"invoke\",1095,0,\"load8_u\",[\"i32:3979\"]],[\"invoke\",1106,0,\"load8_u\",[\"i32:6168\"]],[\"invoke\",1117,0,\"load8_u\",[\"i32:8357\"]],[\"invoke\",1128,0,\"load8_u\",[\"i32:10546\"]],[\"invoke\",1139,0,\"load8_u\",[\"i32:12735\"]],[\"invoke\",1149,0,\"load8_u\",[\"i32:14725\"]],[\"invoke\",1160,0,\"load8_u\",[\"i32:16914\"]],[\"invoke\",1171,0,\"load8_u\",[\"i32:19103\"]],[\"invoke\",1182,0,\"load8_u\",[\"i32:21292\"]],[\"invoke\",1193,0,\"load8_u\",[\"i32:23481\"]],[\"invoke\",1204,0,\"load8_u\",[\"i32:25670\"]],[\"invoke\",1215,0,\"load8_u\",[\"i32:27859\"]],[\"invoke\",1226,0,\"load8_u\",[\"i32:30048\"]],[\"invoke\",1237,0,\"load8_u\",[\"i32:32237\"]],[\"invoke\",1247,0,\"load8_u\",[\"i32:34227\"]],[\"invoke\",1258,0,\"load8_u\",[\"i32:36416\"]],[\"invoke\",1269,0,\"load8_u\",[\"i32:38605\"]],[\"invoke\",1280,0,\"load8_u\",[\"i32:40794\"]],[\"invoke\",1291,0,\"load8_u\",[\"i32:42983\"]],[\"invoke\",1302,0,\"load8_u\",[\"i32:45172\"]],[\"invoke\",1313,0,\"load8_u\",[\"i32:47361\"]],[\"invoke\",1324,0,\"load8_u\",[\"i32:49550\"]],[\"invoke\",1334,0,\"load8_u\",[\"i32:51540\"]],[\"invoke\",1345,0,\"load8_u\",[\"i32:53729\"]],[\"invoke\",1356,0,\"load8_u\",[\"i32:55918\"]],[\"invoke\",1367,0,\"load8_u\",[\"i32:58107\"]],[\"invoke\",1378,0,\"load8_u\",[\"i32:60296\"]],[\"invoke\",1389,0,\"load8_u\",[\"i32:62485\"]],[\"invoke\",1400,0,\"load8_u\",[\"i32:64674\"]],[\"invoke\",1411,0,\"load8_u\",[\"i32:65522\"]],[\"invoke\",1422,0,\"load8_u\",[\"i32:65533\"]],[\"module\",1426,87],[\"invoke\",1443,0,\"load8_u\",[\"i32:1392\"]],[\"invoke\",1454,0,\"load8_u\",[\"i32:3581\"]],[\"invoke\",1465,0,\"load8_u\",[\"i32:5770\"]],[\"invoke\",1476,0,\"load8_u\",[\"i32:7959\"]],[\"invoke\",1487,0,\"load8_u\",[\"i32:10148\"]],[\"invoke\",1498,0,\"load8_u\",[\"i32:12337\"]],[\"invoke\",1509,0,\"load8_u\",[\"i32:14526\"]],[\"invoke\",1520,0,\"load8_u\",[\"i32:16715\"]],[\"invoke\",1530,0,\"load8_u\",[\"i32:18705\"]],[\"invoke\",1541,0,\"load8_u\",[\"i32:20894\"]],[\"invoke\",1552,0,\"load8_u\",[\"i32:23083\"]],[\"invoke\",1563,0,\"load8_u\",[\"i32:25272\"]],[\"invoke\",1574,0,\"load8_u\",[\"i32:27461\"]],[\"invoke\",1585,0,\"load8_u\",[\"i32:29650\"]],[\"invoke\",1596,0,\"load8_u\",[\"i32:31839\"]],[\"invoke\",1607,0,\"load8_u\",[\"i32:34028\"]],[\"invoke\",1618,0,\"load8_u\",[\"i32:36217\"]],[\"invoke\",1628,0,\"load8_u\",[\"i32:38207\"]],[\"invoke\",1639,0,\"load8_u\",[\"i32:40396\"]],[\"invoke\",1650,0,\"load8_u\",[\"i32:42585\"]],[\"invoke\",1661,0,\"load8_u\",[\"i32:44774\"]],[\"invoke\",1672,0,\"load8_u\",[\"i32:46963\"]],[\"invoke\",1683,0,\"load8_u\",[\"i32:49152\"]],[\"invoke\",1694,0,\"load8_u\",[\"i32:51341\"]],[\"invoke\",1705,0,\"load8_u\",[\"i32:53530\"]],[\"invoke\",1715,0,\"load8_u\",[\"i32:55520\"]],[\"invoke\",1726,0,\"load8_u\",[\"i32:57709\"]],[\"invoke\",1737,0,\"load8_u\",[\"i32:59898\"]],[\"invoke\",1748,0,\"load8_u\",[\"i32:62087\"]],[\"invoke\",1759,0,\"load8_u\",[\"i32:64276\"]],[\"invoke\",1770,0,\"load8_u\",[\"i32:65519\"]],[\"invoke\",1781,0,\"load8_u\",[\"i32:65530\"]],[\"module\",1788,88],[\"invoke\",1803,0,\"load8_u\",[\"i32:994\"]],[\"invoke\",1814,0,\"load8_u\",[\"i32:3183\"]],[\"invoke\",1824,0,\"load8_u\",[\"i32:5173\"]],[\"invoke\",1835,0,\"load8_u\",[\"i32:7362\"]],[\"invoke\",1846,0,\"load8_u\",[\"i32:9551\"]],[\"invoke\",1857,0,\"load8_u\",[\"i32:11740\"]],[\"invoke\",1868,0,\"load8_u\",[\"i32:13929\"]],[\"invoke\",1879,0,\"load8_u\",[\"i32:16118\"]],[\"invoke\",1890,0,\"load8_u\",[\"i32:18307\"]],[\"invoke\",1901,0,\"load8_u\",[\"i32:20496\"]],[\"invoke\",1911,0,\"load8_u\",[\"i32:22486\"]],[\"invoke\",1922,0,\"load8_u\",[\"i32:24675\"]],[\"invoke\",1933,0,\"load8_u\",[\"i32:26864\"]],[\"invoke\",1944,0,\"load8_u\",[\"i32:29053\"]],[\"invoke\",1955,0,\"load8_u\",[\"i32:31242\"]],[\"invoke\",1966,0,\"load8_u\",[\"i32:33431\"]],[\"invoke\",1977,0,\"load8_u\",[\"i32:35620\"]],[\"invoke\",1988,0,\"load8_u\",[\"i32:37809\"]],[\"invoke\",1999,0,\"load8_u\",[\"i32:39998\"]],[\"invoke\",2009,0,\"load8_u\",[\"i32:41988\"]],[\"invoke\",2020,0,\"load8_u\",[\"i32:44177\"]],[\"invoke\",2031,0,\"load8_u\",[\"i32:46366\"]],[\"invoke\",2042,0,\"load8_u\",[\"i32:48555\"]],[\"invoke\",2053,0,\"load8_u\",[\"i32:50744\"]],[\"invoke\",2064,0,\"load8_u\",[\"i32:52933\"]],[\"invoke\",2075,0,\"load8_u\",[\"i32:55122\"]],[\"invoke\",2086,0,\"load8_u\",[\"i32:57311\"]],[\"invoke\",2096,0,\"load8_u\",[\"i32:59301\"]],[\"invoke\",2107,0,\"load8_u\",[\"i32:61490\"]],[\"invoke\",2118,0,\"load8_u\",[\"i32:63679\"]],[\"invoke\",2129,0,\"load8_u\",[\"i32:65487\"]],[\"invoke\",2140,0,\"load8_u\",[\"i32:65498\"]],[\"module\",2149,86],[\"invoke\",2162,0,\"load8_u\",[\"i32:596\"]],[\"invoke\",2173,0,\"load8_u\",[\"i32:2785\"]],[\"invoke\",2184,0,\"load8_u\",[\"i32:4974\"]],[\"invoke\",2195,0,\"load8_u\",[\"i32:7163\"]],[\"invoke\",2205,0,\"load8_u\",[\"i32:9153\"]],[\"invoke\",2216,0,\"load8_u\",[\"i32:11342\"]],[\"invoke\",2227,0,\"load8_u\",[\"i32:13531\"]],[\"invoke\",2238,0,\"load8_u\",[\"i32:15720\"]],[\"invoke\",2249,0,\"load8_u\",[\"i32:17909\"]],[\"invoke\",2260,0,\"load8_u\",[\"i32:20098\"]],[\"invoke\",2271,0,\"load8_u\",[\"i32:22287\"]],[\"invoke\",2282,0,\"load8_u\",[\"i32:24476\"]],[\"invoke\",2292,0,\"load8_u\",[\"i32:26466\"]],[\"invoke\",2303,0,\"load8_u\",[\"i32:28655\"]],[\"invoke\",2314,0,\"load8_u\",[\"i32:30844\"]],[\"invoke\",2325,0,\"load8_u\",[\"i32:33033\"]],[\"invoke\",2336,0,\"load8_u\",[\"i32:35222\"]],[\"invoke\",2347,0,\"load8_u\",[\"i32:37411\"]],[\"invoke\",2358,0,\"load8_u\",[\"i32:39600\"]],[\"invoke\",2369,0,\"load8_u\",[\"i32:41789\"]],[\"invoke\",2380,0,\"load8_u\",[\"i32:43978\"]],[\"invoke\",2390,0,\"load8_u\",[\"i32:45968\"]],[\"invoke\",2401,0,\"load8_u\",[\"i32:48157\"]],[\"invoke\",2412,0,\"load8_u\",[\"i32:50346\"]],[\"invoke\",2423,0,\"load8_u\",[\"i32:52535\"]],[\"invoke\",2434,0,\"load8_u\",[\"i32:54724\"]],[\"invoke\",2445,0,\"load8_u\",[\"i32:56913\"]],[\"invoke\",2456,0,\"load8_u\",[\"i32:59102\"]],[\"invoke\",2467,0,\"load8_u\",[\"i32:61291\"]],[\"invoke\",2477,0,\"load8_u\",[\"i32:63281\"]],[\"invoke\",2488,0,\"load8_u\",[\"i32:65470\"]],[\"invoke\",2499,0,\"load8_u\",[\"i32:65526\"]],[\"module\",2510,89],[\"invoke\",2521,0,\"load8_u\",[\"i32:198\"]],[\"invoke\",2532,0,\"load8_u\",[\"i32:2387\"]],[\"invoke\",2543,0,\"load8_u\",[\"i32:4576\"]],[\"invoke\",2554,0,\"load8_u\",[\"i32:6765\"]],[\"invoke\",2565,0,\"load8_u\",[\"i32:8954\"]],[\"invoke\",2576,0,\"load8_u\",[\"i32:11143\"]],[\"invoke\",2586,0,\"load8_u\",[\"i32:13133\"]],[\"invoke\",2597,0,\"load8_u\",[\"i32:15322\"]],[\"invoke\",2608,0,\"load8_u\",[\"i32:17511\"]],[\"invoke\",2619,0,\"load8_u\",[\"i32:19700\"]],[\"invoke\",2630,0,\"load8_u\",[\"i32:21889\"]],[\"invoke\",2641,0,\"load8_u\",[\"i32:24078\"]],[\"invoke\",2652,0,\"load8_u\",[\"i32:26267\"]],[\"invoke\",2663,0,\"load8_u\",[\"i32:28456\"]],[\"invoke\",2673,0,\"load8_u\",[\"i32:30446\"]],[\"invoke\",2684,0,\"load8_u\",[\"i32:32635\"]],[\"invoke\",2695,0,\"load8_u\",[\"i32:34824\"]],[\"invoke\",2706,0,\"load8_u\",[\"i32:37013\"]],[\"invoke\",2717,0,\"load8_u\",[\"i32:39202\"]],[\"invoke\",2728,0,\"load8_u\",[\"i32:41391\"]],[\"invoke\",2739,0,\"load8_u\",[\"i32:43580\"]],[\"invoke\",2750,0,\"load8_u\",[\"i32:45769\"]],[\"invoke\",2761,0,\"load8_u\",[\"i32:47958\"]],[\"invoke\",2771,0,\"load8_u\",[\"i32:49948\"]],[\"invoke\",2782,0,\"load8_u\",[\"i32:52137\"]],[\"invoke\",2793,0,\"load8_u\",[\"i32:54326\"]],[\"invoke\",2804,0,\"load8_u\",[\"i32:56515\"]],[\"invoke\",2815,0,\"load8_u\",[\"i32:58704\"]],[\"invoke\",2826,0,\"load8_u\",[\"i32:60893\"]],[\"invoke\",2837,0,\"load8_u\",[\"i32:63082\"]],[\"invoke\",2848,0,\"load8_u\",[\"i32:65271\"]],[\"invoke\",2858,0,\"load8_u\",[\"i32:65514\"]],[\"invoke\",2869,0,\"load8_u\",[\"i32:65525\"]],[\"module\",2871,86],[\"invoke\",2891,0,\"load8_u\",[\"i32:1989\"]],[\"invoke\",2902,0,\"load8_u\",[\"i32:4178\"]],[\"invoke\",2913,0,\"load8_u\",[\"i32:6367\"]],[\"invoke\",2924,0,\"load8_u\",[\"i32:8556\"]],[\"invoke\",2935,0,\"load8_u\",[\"i32:10745\"]],[\"invoke\",2946,0,\"load8_u\",[\"i32:12934\"]],[\"invoke\",2957,0,\"load8_u\",[\"i32:15123\"]],[\"invoke\",2967,0,\"load8_u\",[\"i32:17113\"]],[\"invoke\",2978,0,\"load8_u\",[\"i32:19302\"]],[\"invoke\",2989,0,\"load8_u\",[\"i32:21491\"]],[\"invoke\",3000,0,\"load8_u\",[\"i32:23680\"]],[\"invoke\",3011,0,\"load8_u\",[\"i32:25869\"]],[\"invoke\",3022,0,\"load8_u\",[\"i32:28058\"]],[\"invoke\",3033,0,\"load8_u\",[\"i32:30247\"]],[\"invoke\",3044,0,\"load8_u\",[\"i32:32436\"]],[\"invoke\",3054,0,\"load8_u\",[\"i32:34426\"]],[\"invoke\",3065,0,\"load8_u\",[\"i32:36615\"]],[\"invoke\",3076,0,\"load8_u\",[\"i32:38804\"]],[\"invoke\",3087,0,\"load8_u\",[\"i32:40993\"]],[\"invoke\",3098,0,\"load8_u\",[\"i32:43182\"]],[\"invoke\",3109,0,\"load8_u\",[\"i32:45371\"]],[\"invoke\",3120,0,\"load8_u\",[\"i32:47560\"]],[\"invoke\",3131,0,\"load8_u\",[\"i32:49749\"]],[\"invoke\",3142,0,\"load8_u\",[\"i32:51938\"]],[\"invoke\",3152,0,\"load8_u\",[\"i32:53928\"]],[\"invoke\",3163,0,\"load8_u\",[\"i32:56117\"]],[\"invoke\",3174,0,\"load8_u\",[\"i32:58306\"]],[\"invoke\",3185,0,\"load8_u\",[\"i32:60495\"]],[\"invoke\",3196,0,\"load8_u\",[\"i32:62684\"]],[\"invoke\",3207,0,\"load8_u\",[\"i32:64873\"]],[\"invoke\",3218,0,\"load8_u\",[\"i32:65523\"]],[\"invoke\",3229,0,\"load8_u\",[\"i32:65534\"]],[\"module\",3232,86],[\"invoke\",3250,0,\"load8_u\",[\"i32:1591\"]],[\"invoke\",3261,0,\"load8_u\",[\"i32:3780\"]],[\"invoke\",3272,0,\"load8_u\",[\"i32:5969\"]],[\"invoke\",3283,0,\"load8_u\",[\"i32:8158\"]],[\"invoke\",3294,0,\"load8_u\",[\"i32:10347\"]],[\"invoke\",3305,0,\"load8_u\",[\"i32:12536\"]],[\"invoke\",3316,0,\"load8_u\",[\"i32:14725\"]],[\"invoke\",3327,0,\"load8_u\",[\"i32:16914\"]],[\"invoke\",3338,0,\"load8_u\",[\"i32:19103\"]],[\"invoke\",3348,0,\"load8_u\",[\"i32:21093\"]],[\"invoke\",3359,0,\"load8_u\",[\"i32:23282\"]],[\"invoke\",3370,0,\"load8_u\",[\"i32:25471\"]],[\"invoke\",3381,0,\"load8_u\",[\"i32:27660\"]],[\"invoke\",3392,0,\"load8_u\",[\"i32:29849\"]],[\"invoke\",3403,0,\"load8_u\",[\"i32:32038\"]],[\"invoke\",3414,0,\"load8_u\",[\"i32:34227\"]],[\"invoke\",3425,0,\"load8_u\",[\"i32:36416\"]],[\"invoke\",3435,0,\"load8_u\",[\"i32:38406\"]],[\"invoke\",3446,0,\"load8_u\",[\"i32:40595\"]],[\"invoke\",3457,0,\"load8_u\",[\"i32:42784\"]],[\"invoke\",3468,0,\"load8_u\",[\"i32:44973\"]],[\"invoke\",3479,0,\"load8_u\",[\"i32:47162\"]],[\"invoke\",3490,0,\"load8_u\",[\"i32:49351\"]],[\"invoke\",3501,0,\"load8_u\",[\"i32:51540\"]],[\"invoke\",3512,0,\"load8_u\",[\"i32:53729\"]],[\"invoke\",3523,0,\"load8_u\",[\"i32:55918\"]],[\"invoke\",3533,0,\"load8_u\",[\"i32:57908\"]],[\"invoke\",3544,0,\"load8_u\",[\"i32:60097\"]],[\"invoke\",3555,0,\"load8_u\",[\"i32:62286\"]],[\"invoke\",3566,0,\"load8_u\",[\"i32:64475\"]],[\"invoke\",3577,0,\"load8_u\",[\"i32:65521\"]],[\"invoke\",3588,0,\"load8_u\",[\"i32:65532\"]],[\"module\",3593,90],[\"invoke\",3610,0,\"load8_u\",[\"i32:1392\"]],[\"invoke\",3621,0,\"load8_u\",[\"i32:3581\"]],[\"invoke\",3631,0,\"load8_u\",[\"i32:5571\"]],[\"invoke\",3642,0,\"load8_u\",[\"i32:7760\"]],[\"invoke\",3653,0,\"load8_u\",[\"i32:9949\"]],[\"invoke\",3664,0,\"load8_u\",[\"i32:12138\"]],[\"invoke\",3675,0,\"load8_u\",[\"i32:14327\"]],[\"invoke\",3686,0,\"load8_u\",[\"i32:16516\"]],[\"invoke\",3697,0,\"load8_u\",[\"i32:18705\"]],[\"invoke\",3708,0,\"load8_u\",[\"i32:20894\"]],[\"invoke\",3719,0,\"load8_u\",[\"i32:23083\"]],[\"invoke\",3729,0,\"load8_u\",[\"i32:25073\"]],[\"invoke\",3740,0,\"load8_u\",[\"i32:27262\"]],[\"invoke\",3751,0,\"load8_u\",[\"i32:29451\"]],[\"invoke\",3762,0,\"load8_u\",[\"i32:31640\"]],[\"invoke\",3773,0,\"load8_u\",[\"i32:33829\"]],[\"invoke\",3784,0,\"load8_u\",[\"i32:36018\"]],[\"invoke\",3795,0,\"load8_u\",[\"i32:38207\"]],[\"invoke\",3806,0,\"load8_u\",[\"i32:40396\"]],[\"invoke\",3816,0,\"load8_u\",[\"i32:42386\"]],[\"invoke\",3827,0,\"load8_u\",[\"i32:44575\"]],[\"invoke\",3838,0,\"load8_u\",[\"i32:46764\"]],[\"invoke\",3849,0,\"load8_u\",[\"i32:48953\"]],[\"invoke\",3860,0,\"load8_u\",[\"i32:51142\"]],[\"invoke\",3871,0,\"load8_u\",[\"i32:53331\"]],[\"invoke\",3882,0,\"load8_u\",[\"i32:55520\"]],[\"invoke\",3893,0,\"load8_u\",[\"i32:57709\"]],[\"invoke\",3904,0,\"load8_u\",[\"i32:59898\"]],[\"invoke\",3914,0,\"load8_u\",[\"i32:61888\"]],[\"invoke\",3925,0,\"load8_u\",[\"i32:64077\"]],[\"invoke\",3936,0,\"load8_u\",[\"i32:65519\"]],[\"invoke\",3947,0,\"load8_u\",[\"i32:65530\"]],[\"module\",3954,91],[\"invoke\",3969,0,\"load8_u\",[\"i32:994\"]],[\"invoke\",3980,0,\"load8_u\",[\"i32:3183\"]],[\"invoke\",3991,0,\"load8_u\",[\"i32:5372\"]],[\"invoke\",4002,0,\"load8_u\",[\"i32:7561\"]],[\"invoke\",4012,0,\"load8_u\",[\"i32:9551\"]],[\"invoke\",4023,0,\"load8_u\",[\"i32:11740\"]],[\"invoke\",4034,0,\"load8_u\",[\"i32:13929\"]],[\"invoke\",4045,0,\"load8_u\",[\"i32:16118\"]],[\"invoke\",4056,0,\"load8_u\",[\"i32:18307\"]],[\"invoke\",4067,0,\"load8_u\",[\"i32:20496\"]],[\"invoke\",4078,0,\"load8_u\",[\"i32:22685\"]],[\"invoke\",4089,0,\"load8_u\",[\"i32:24874\"]],[\"invoke\",4100,0,\"load8_u\",[\"i32:27063\"]],[\"invoke\",4110,0,\"load8_u\",[\"i32:29053\"]],[\"invoke\",4121,0,\"load8_u\",[\"i32:31242\"]],[\"invoke\",4132,0,\"load8_u\",[\"i32:33431\"]],[\"invoke\",4143,0,\"load8_u\",[\"i32:35620\"]],[\"invoke\",4154,0,\"load8_u\",[\"i32:37809\"]],[\"invoke\",4165,0,\"load8_u\",[\"i32:39998\"]],[\"invoke\",4176,0,\"load8_u\",[\"i32:42187\"]],[\"invoke\",4187,0,\"load8_u\",[\"i32:44376\"]],[\"invoke\",4197,0,\"load8_u\",[\"i32:46366\"]],[\"invoke\",4208,0,\"load8_u\",[\"i32:48555\"]],[\"invoke\",4219,0,\"load8_u\",[\"i32:50744\"]],[\"invoke\",4230,0,\"load8_u\",[\"i32:52933\"]],[\"invoke\",4241,0,\"load8_u\",[\"i32:55122\"]],[\"invoke\",4252,0,\"load8_u\",[\"i32:57311\"]],[\"invoke\",4263,0,\"load8_u\",[\"i32:59500\"]],[\"invoke\",4274,0,\"load8_u\",[\"i32:61441\"]],[\"invoke\",4285,0,\"load8_u\",[\"i32:61452\"]],[\"invoke\",4295,0,\"load8_u\",[\"i32:61908\"]],[\"invoke\",4306,0,\"load8_u\",[\"i32:64097\"]],[\"module\",4763,92],[\"invoke\",4786,0,\"checkRange\",[\"i32:20\",\"i32:65536\",\"i32:0\"]],[\"module\",4789,93],[\"module\",4815,94],[\"module\",4821,95],[\"module\",4827,96],[\"module\",4833,97],[\"module\",4839,98],[\"invoke\",4861,0,\"checkRange\",[\"i32:32768\",\"i32:65536\",\"i32:170\"]],[\"module\",4863,99],[\"module\",4869,100],[\"module\",4875,101],[\"module\",4881,102],[\"module\",4887,103],[\"module\",4893,104],[\"module\",4899,105],[\"invoke\",5123,0,\"checkRange\",[\"i32:2132\",\"i32:2827\",\"i32:10\"]],[\"invoke\",5145,0,\"checkRange\",[\"i32:5691\",\"i32:6552\",\"i32:83\"]],[\"invoke\",5167,0,\"checkRange\",[\"i32:10087\",\"i32:10206\",\"i32:5\"]],[\"invoke\",5189,0,\"checkRange\",[\"i32:13114\",\"i32:14133\",\"i32:59\"]],[\"invoke\",5209,0,\"checkRange\",[\"i32:15871\",\"i32:15998\",\"i32:95\"]],[\"invoke\",5231,0,\"checkRange\",[\"i32:18553\",\"i32:18744\",\"i32:42\"]],[\"invoke\",5253,0,\"checkRange\",[\"i32:21468\",\"i32:21492\",\"i32:93\"]],[\"invoke\",5275,0,\"checkRange\",[\"i32:24348\",\"i32:24515\",\"i32:92\"]],[\"invoke\",5297,0,\"checkRange\",[\"i32:27503\",\"i32:27573\",\"i32:77\"]],[\"invoke\",5319,0,\"checkRange\",[\"i32:31379\",\"i32:31403\",\"i32:57\"]],[\"invoke\",5341,0,\"checkRange\",[\"i32:33056\",\"i32:33660\",\"i32:89\"]],[\"invoke\",5363,0,\"checkRange\",[\"i32:35648\",\"i32:36547\",\"i32:83\"]],[\"invoke\",5385,0,\"checkRange\",[\"i32:39187\",\"i32:39859\",\"i32:92\"]],[\"invoke\",5405,0,\"checkRange\",[\"i32:42945\",\"i32:43115\",\"i32:77\"]],[\"invoke\",5427,0,\"checkRange\",[\"i32:45575\",\"i32:45640\",\"i32:77\"]],[\"invoke\",5449,0,\"checkRange\",[\"i32:47951\",\"i32:48632\",\"i32:100\"]],[\"invoke\",5471,0,\"checkRange\",[\"i32:50370\",\"i32:51358\",\"i32:92\"]],[\"invoke\",5493,0,\"checkRange\",[\"i32:55198\",\"i32:55389\",\"i32:42\"]],[\"invoke\",5515,0,\"checkRange\",[\"i32:58516\",\"i32:58835\",\"i32:95\"]],[\"invoke\",5537,0,\"checkRange\",[\"i32:60777\",\"i32:60834\",\"i32:76\"]],[\"invoke\",5559,0,\"checkRange\",[\"i32:63525\",\"i32:63605\",\"i32:74\"]],[\"file\",\"memory_fill.wast\"],[\"module\",6,106],[\"invoke\",22,0,\"test\",[]],[\"invoke\",24,0,\"checkRange\",[\"i32:0\",\"i32:65280\",\"i32:0\"]],[\"invoke\",26,0,\"checkRange\",[\"i32:65280\",\"i32:65536\",\"i32:85\"]],[\"module\",28,107],[\"invoke\",44,0,\"test\",[]],[\"module\",46,108],[\"invoke\",62,0,\"test\",[]],[\"module\",64,109],[\"invoke\",80,0,\"test\",[]],[\"invoke\",82,0,\"checkRange\",[\"i32:0\",\"i32:65536\",\"i32:0\"]],[\"module\",84,110],[\"invoke\",100,0,\"test\",[]],[\"module\",102,111],[\"invoke\",118,0,\"test\",[]],[\"module\",120,112],[\"invoke\",136,0,\"test\",[]],[\"invoke\",138,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"invoke\",140,0,\"checkRange\",[\"i32:1\",\"i32:65535\",\"i32:170\"]],[\"invoke\",142,0,\"checkRange\",[\"i32:65535\",\"i32:65536\",\"i32:0\"]],[\"module\",145,113],[\"invoke\",162,0,\"test\",[]],[\"invoke\",164,0,\"checkRange\",[\"i32:0\",\"i32:18\",\"i32:0\"]],[\"invoke\",166,0,\"checkRange\",[\"i32:18\",\"i32:21\",\"i32:85\"]],[\"invoke\",168,0,\"checkRange\",[\"i32:21\",\"i32:25\",\"i32:170\"]],[\"invoke\",170,0,\"checkRange\",[\"i32:25\",\"i32:28\",\"i32:85\"]],[\"invoke\",172,0,\"checkRange\",[\"i32:28\",\"i32:65536\",\"i32:0\"]],[\"module\",621,114],[\"invoke\",638,0,\"run\",[\"i32:65280\",\"i32:37\",\"i32:512\"]],[\"invoke\",641,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",643,114],[\"invoke\",660,0,\"run\",[\"i32:65279\",\"i32:37\",\"i32:514\"]],[\"invoke\",663,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",665,114],[\"invoke\",682,0,\"run\",[\"i32:65279\",\"i32:37\",\"i32:4294967295\"]],[\"invoke\",685,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"file\",\"memory_init.wast\"],[\"module\",6,115],[\"invoke\",17,0,\"test\",[]],[\"invoke\",19,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",20,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",21,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",22,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",23,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",24,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",25,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",26,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",27,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",28,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",29,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",30,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",31,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",32,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",33,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",34,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",35,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",36,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",37,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",38,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",39,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",40,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",41,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",42,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",43,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",44,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",45,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",46,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",47,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",48,0,\"load8_u\",[\"i32:29\"]],[\"module\",50,116],[\"invoke\",61,0,\"test\",[]],[\"invoke\",63,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",64,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",65,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",66,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",67,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",68,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",69,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",70,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",71,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",72,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",73,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",74,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",75,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",76,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",77,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",78,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",79,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",80,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",81,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",82,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",83,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",84,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",85,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",86,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",87,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",88,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",89,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",90,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",91,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",92,0,\"load8_u\",[\"i32:29\"]],[\"module\",94,117],[\"invoke\",105,0,\"test\",[]],[\"invoke\",107,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",108,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",109,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",110,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",111,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",112,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",113,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",114,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",115,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",116,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",117,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",118,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",119,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",120,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",121,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",122,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",123,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",124,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",125,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",126,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",127,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",128,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",129,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",130,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",131,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",132,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",133,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",134,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",135,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",136,0,\"load8_u\",[\"i32:29\"]],[\"module\",138,118],[\"invoke\",157,0,\"test\",[]],[\"invoke\",159,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",160,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",161,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",162,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",163,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",164,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",165,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",166,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",167,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",168,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",169,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",170,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",171,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",172,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",173,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",174,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",175,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",176,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",177,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",178,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",179,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",180,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",181,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",182,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",183,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",184,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",185,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",186,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",187,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",188,0,\"load8_u\",[\"i32:29\"]],[\"module\",203,119],[\"invoke\",209,0,\"test\",[]],[\"module\",211,120],[\"invoke\",217,0,\"test\",[]],[\"module\",219,121],[\"invoke\",224,0,\"test\",[]],[\"module\",240,122],[\"invoke\",246,0,\"test\",[]],[\"module\",248,123],[\"invoke\",253,0,\"test\",[]],[\"module\",255,124],[\"invoke\",260,0,\"test\",[]],[\"module\",262,125],[\"invoke\",267,0,\"test\",[]],[\"module\",269,126],[\"invoke\",274,0,\"test\",[]],[\"module\",276,127],[\"invoke\",281,0,\"test\",[]],[\"module\",283,128],[\"invoke\",288,0,\"test\",[]],[\"module\",290,129],[\"invoke\",295,0,\"test\",[]],[\"module\",297,130],[\"invoke\",302,0,\"test\",[]],[\"module\",304,131],[\"invoke\",309,0,\"test\",[]],[\"module\",815,132],[\"invoke\",833,0,\"run\",[\"i32:65528\",\"i32:16\"]],[\"invoke\",836,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",838,132],[\"invoke\",856,0,\"run\",[\"i32:65527\",\"i32:16\"]],[\"invoke\",859,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",861,132],[\"invoke\",879,0,\"run\",[\"i32:65472\",\"i32:30\"]],[\"invoke\",882,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",884,132],[\"invoke\",902,0,\"run\",[\"i32:65473\",\"i32:31\"]],[\"invoke\",905,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",907,133],[\"invoke\",925,0,\"run\",[\"i32:65528\",\"i32:4294967040\"]],[\"invoke\",928,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",930,133],[\"invoke\",948,0,\"run\",[\"i32:0\",\"i32:4294967292\"]],[\"invoke\",951,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",954,134],[\"file\",\"data.wast\"],[\"module\",5,135],[\"module\",39,136],[\"module\",48,137],[\"module\",66,138],[\"module\",77,138],[\"module\",100,139],[\"module\",111,140],[\"module\",116,141],[\"module\",125,142],[\"module\",130,143],[\"module\",135,141],[\"module\",144,142],[\"instantiate\",184,144],[\"instantiate\",192,145],[\"instantiate\",200,146],[\"instantiate\",207,147],[\"instantiate\",214,148],[\"instantiate\",231,149],[\"instantiate\",240,150],[\"instantiate\",255,151],[\"instantiate\",263,152],[\"instantiate\",271,153],[\"instantiate\",286,154]]"; diff --git a/tests/corpus/webassembly-spec-memory/main.mjs b/tests/corpus/webassembly-spec-memory/main.mjs new file mode 100644 index 000000000..f45ccc584 --- /dev/null +++ b/tests/corpus/webassembly-spec-memory/main.mjs @@ -0,0 +1,5 @@ +// Executes WebAssembly spec tests (16 files); see tests/wasm-spec/runner.mjs. +import { run } from "../../wasm-spec/runner.mjs"; +import { modules, script } from "./data.mjs"; + +run(modules, script); diff --git a/tests/corpus/webassembly-spec-table/data.mjs b/tests/corpus/webassembly-spec-table/data.mjs new file mode 100644 index 000000000..15dbf08aa --- /dev/null +++ b/tests/corpus/webassembly-spec-table/data.mjs @@ -0,0 +1,193 @@ +/* Generated by tests/wasm-spec/gen.mjs from the WebAssembly 2.0 core test + * suite (WebAssembly/spec wg-2.0, Apache-2.0) with wabt 1.0.37 wast2json: + * table_copy.wast, table_fill.wast, table_get.wast, table_grow.wast, table_init.wast, table_set.wast, table_size.wast, elem.wast, ref_func.wast, ref_is_null.wast, ref_null.wast, exports.wast, linking.wast. Do not edit. */ +export const modules = [ + "AGFzbQEAAAABBQFgAAF/AwYFAAAAAAAHHwUDZWYwAAADZWYxAAEDZWYyAAIDZWYzAAMDZWY0AAQKGgUEAEEACwQAQQELBABBAgsEAEEDCwQAQQQL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgIBQQMLAAQBAwEEAgFBCwsABQYDAgUHCi4IBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwMAAQsHACAAEQAACwcAIAARAAEL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgIBQQMLAAQBAwEEAgFBCwsABQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQQ1BAkED/A4AAAsHACAAEQAACwcAIAARAAEL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgIBQQMLAAQBAwEEAgFBCwsABQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQRlBD0EC/A4AAAsHACAAEQAACwcAIAARAAEL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgIBQQMLAAQBAwEEAgFBCwsABQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQQ1BGUED/A4AAAsHACAAEQAACwcAIAARAAEL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgIBQQMLAAQBAwEEAgFBCwsABQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQRRBFkEE/A4AAAsHACAAEQAACwcAIAARAAEL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgIBQQMLAAQBAwEEAgFBCwsABQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQRlBAUED/A4AAAsHACAAEQAACwcAIAARAAEL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgIBQQMLAAQBAwEEAgFBCwsABQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQQpBDEEH/A4AAAsHACAAEQAACwcAIAARAAEL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgIBQQMLAAQBAwEEAgFBCwsABQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQQxBCkEH/A4AAAsHACAAEQAACwcAIAARAAEL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgIBQQMLAAQBAwEEAgFBCwsABQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQQpBAEEU/A4BAAsHACAAEQAACwcAIAARAAEL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYAQQMLBAEDAQQAQQsLBQYDAgUHCi4IBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwMAAQsHACAAEQABCwcAIAARAAAL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYAQQMLBAEDAQQAQQsLBQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQQ1BAkED/A4BAQsHACAAEQABCwcAIAARAAAL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYAQQMLBAEDAQQAQQsLBQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQRlBD0EC/A4BAQsHACAAEQABCwcAIAARAAAL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYAQQMLBAEDAQQAQQsLBQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQQ1BGUED/A4BAQsHACAAEQABCwcAIAARAAAL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYAQQMLBAEDAQQAQQsLBQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQRRBFkEE/A4BAQsHACAAEQABCwcAIAARAAAL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYAQQMLBAEDAQQAQQsLBQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQRlBAUED/A4BAQsHACAAEQABCwcAIAARAAAL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYAQQMLBAEDAQQAQQsLBQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQQpBDEEH/A4BAQsHACAAEQABCwcAIAARAAAL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYAQQMLBAEDAQQAQQsLBQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQQxBCkEH/A4BAQsHACAAEQABCwcAIAARAAAL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwkIAAAAAAABAgIECQJwAR4ecAEeHgceAwR0ZXN0AAoIY2hlY2tfdDAACwhjaGVja190MQAMCToGAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYAQQMLBAEDAQQAQQsLBQYDAgUHCjcIBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwwAQQpBAEEU/A4AAQsHACAAEQABCwcAIAARAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEcQQFBA/wOAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEF+QQFBAvwOAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEPQRlBBvwOAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEPQX5BAvwOAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEPQRlBAPwOAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEeQQ9BAPwOAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEfQQ9BAPwOAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEPQR5BAPwOAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEPQR9BAPwOAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEeQR5BAPwOAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEfQR9BAPwOAAAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEcQQFBA/wOAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEF+QQFBAvwOAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEPQRlBBvwOAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEPQX5BAvwOAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEPQRlBAPwOAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEeQQ9BAPwOAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEfQQ9BAPwOAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEPQR5BAPwOAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEPQR9BAPwOAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEeQR5BAPwOAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEeHgcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEfQR9BAPwOAQAL", + "AGFzbQEAAAABEANgAAF/YAF/AX9gA39/fwADExIAAAAAAAAAAAAAAAAAAAAAAQIEBQFwASBAB2QSAmYwAAACZjEAAQJmMgACAmYzAAMCZjQABAJmNQAFAmY2AAYCZjcABwJmOAAIAmY5AAkDZjEwAAoDZjExAAsDZjEyAAwDZjEzAA0DZjE0AA4DZjE1AA8EdGVzdAAQA3J1bgARCQ4BAEEACwgAAQIDBAUGBwpmEgQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLBABBCgsEAEELCwQAQQwLBABBDQsEAEEOCwQAQQ8LBwAgABEAAAsMACAAIAEgAvwOAAAL", + "AGFzbQEAAAABEANgAAF/YAF/AX9gA39/fwADExIAAAAAAAAAAAAAAAAAAAAAAQIEBQFwASBAB2QSAmYwAAACZjEAAQJmMgACAmYzAAMCZjQABAJmNQAFAmY2AAYCZjcABwJmOAAIAmY5AAkDZjEwAAoDZjExAAsDZjEyAAwDZjEzAA0DZjE0AA4DZjE1AA8EdGVzdAAQA3J1bgARCQ8BAEEACwkAAQIDBAUGBwgKZhIEAEEACwQAQQELBABBAgsEAEEDCwQAQQQLBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwQAQQoLBABBCwsEAEEMCwQAQQ0LBABBDgsEAEEPCwcAIAARAAALDAAgACABIAL8DgAACw==", + "AGFzbQEAAAABEANgAAF/YAF/AX9gA39/fwADExIAAAAAAAAAAAAAAAAAAAAAAQIEBQFwASBAB2QSAmYwAAACZjEAAQJmMgACAmYzAAMCZjQABAJmNQAFAmY2AAYCZjcABwJmOAAIAmY5AAkDZjEwAAoDZjExAAsDZjEyAAwDZjEzAA0DZjE0AA4DZjE1AA8EdGVzdAAQA3J1bgARCQ4BAEEYCwgAAQIDBAUGBwpmEgQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLBABBCgsEAEELCwQAQQwLBABBDQsEAEEOCwQAQQ8LBwAgABEAAAsMACAAIAEgAvwOAAAL", + "AGFzbQEAAAABEANgAAF/YAF/AX9gA39/fwADExIAAAAAAAAAAAAAAAAAAAAAAQIEBQFwASBAB2QSAmYwAAACZjEAAQJmMgACAmYzAAMCZjQABAJmNQAFAmY2AAYCZjcABwJmOAAIAmY5AAkDZjEwAAoDZjExAAsDZjEyAAwDZjEzAA0DZjE0AA4DZjE1AA8EdGVzdAAQA3J1bgARCQ8BAEEXCwkAAQIDBAUGBwgKZhIEAEEACwQAQQELBABBAgsEAEEDCwQAQQQLBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwQAQQoLBABBCwsEAEEMCwQAQQ0LBABBDgsEAEEPCwcAIAARAAALDAAgACABIAL8DgAACw==", + "AGFzbQEAAAABEANgAAF/YAF/AX9gA39/fwADExIAAAAAAAAAAAAAAAAAAAAAAQIEBQFwASBAB2QSAmYwAAACZjEAAQJmMgACAmYzAAMCZjQABAJmNQAFAmY2AAYCZjcABwJmOAAIAmY5AAkDZjEwAAoDZjExAAsDZjEyAAwDZjEzAA0DZjE0AA4DZjE1AA8EdGVzdAAQA3J1bgARCQ4BAEELCwgAAQIDBAUGBwpmEgQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLBABBCgsEAEELCwQAQQwLBABBDQsEAEEOCwQAQQ8LBwAgABEAAAsMACAAIAEgAvwOAAAL", + "AGFzbQEAAAABEANgAAF/YAF/AX9gA39/fwADExIAAAAAAAAAAAAAAAAAAAAAAQIEBQFwASBAB2QSAmYwAAACZjEAAQJmMgACAmYzAAMCZjQABAJmNQAFAmY2AAYCZjcABwJmOAAIAmY5AAkDZjEwAAoDZjExAAsDZjEyAAwDZjEzAA0DZjE0AA4DZjE1AA8EdGVzdAAQA3J1bgARCQ4BAEEVCwgAAQIDBAUGBwpmEgQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLBABBCgsEAEELCwQAQQwLBABBDQsEAEEOCwQAQQ8LBwAgABEAAAsMACAAIAEgAvwOAAAL", + "AGFzbQEAAAABEANgAAF/YAF/AX9gA39/fwADExIAAAAAAAAAAAAAAAAAAAAAAQIEBQFwASBAB2QSAmYwAAACZjEAAQJmMgACAmYzAAMCZjQABAJmNQAFAmY2AAYCZjcABwJmOAAIAmY5AAkDZjEwAAoDZjExAAsDZjEyAAwDZjEzAA0DZjE0AA4DZjE1AA8EdGVzdAAQA3J1bgARCREBAEEVCwsAAQIDBAUGBwgJCgpmEgQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLBABBCgsEAEELCwQAQQwLBABBDQsEAEEOCwQAQQ8LBwAgABEAAAsMACAAIAEgAvwOAAAL", + "AGFzbQEAAAABEANgAAF/YAF/AX9gA39/fwADExIAAAAAAAAAAAAAAAAAAAAAAQIEBwFwAYABgAEHZBICZjAAAAJmMQABAmYyAAICZjMAAwJmNAAEAmY1AAUCZjYABgJmNwAHAmY4AAgCZjkACQNmMTAACgNmMTEACwNmMTIADANmMTMADQNmMTQADgNmMTUADwR0ZXN0ABADcnVuABEJFwEAQfAACxAAAQIDBAUGBwgJCgsMDQ4PCmYSBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsEAEEKCwQAQQsLBABBDAsEAEENCwQAQQ4LBABBDwsHACAAEQAACwwAIAAgASAC/A4AAAs=", + "AGFzbQEAAAABEANgAAF/YAF/AX9gA39/fwADExIAAAAAAAAAAAAAAAAAAAAAAQIEBwFwAYABgAEHZBICZjAAAAJmMQABAmYyAAICZjMAAwJmNAAEAmY1AAUCZjYABgJmNwAHAmY4AAgCZjkACQNmMTAACgNmMTEACwNmMTIADANmMTMADQNmMTQADgNmMTUADwR0ZXN0ABADcnVuABEJFgEAQQALEAABAgMEBQYHCAkKCwwNDg8KZhIEAEEACwQAQQELBABBAgsEAEEDCwQAQQQLBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwQAQQoLBABBCwsEAEEMCwQAQQ0LBABBDgsEAEEPCwcAIAARAAALDAAgACABIAL8DgAACw==", + "AGFzbQEAAAABDAJgA39vfwBgAX8BbwMEAwAAAQQEAW8ACgccAwRmaWxsAAALZmlsbC1hYmJyZXYAAQNnZXQAAgogAwsAIAAgASAC/BEACwsAIAAgASAC/BEACwYAIAAlAAs=", + "AGFzbQEAAAABFwVgAABgAW8AYAF/AW9gAX8BcGABfwF/AwYFAAECAwQEBwJvAAJwAAMHOAQEaW5pdAABDWdldC1leHRlcm5yZWYAAgtnZXQtZnVuY3JlZgADD2lzX251bGwtZnVuY3JlZgAECQkBAgFBAQsAAQAKKwUCAAsQAEEBIAAmAEECQQElASYBCwYAIAAlAAsGACAAJQELBwAgABAD0Qs=", + "AGFzbQEAAAABFQRgAX8Bb2ACf28AYAJ/bwF/YAABfwMGBQABAgIDBAQBbwAABykFA2dldAAAA3NldAABBGdyb3cAAgtncm93LWFiYnJldgADBHNpemUABAorBQYAIAAlAAsIACAAIAEmAAsJACABIAD8DwALCQAgASAA/A8ACwUA/BAACw==", + "AGFzbQEAAAABBQFgAAF/AwIBAAQEAXAAEAcIAQRncm93AAAJBQEDAAEACgsBCQDSAEFw/A8ACw==", + "AGFzbQEAAAABBgFgAX8BfwMCAQAEBAFvAAAHCAEEZ3JvdwAACgsBCQDQbyAA/A8ACw==", + "AGFzbQEAAAABBgFgAX8BfwMCAQAEBQFvAQAKBwgBBGdyb3cAAAoLAQkA0G8gAPwPAAs=", + "AGFzbQEAAAABDAJgAX8Bf2ACf38BcAMDAgABBAQBcAAKBxsCBGdyb3cAABBjaGVjay10YWJsZS1udWxsAAEJBQEDAAEBCj0CCQDQcCAA/A8ACzEBAXDSASECAkADQCAAJQAhAiAC0UUNASAAIAFPDQEgAEEBaiEAIAAgAU0NAAsLIAIL", + "AGFzbQEAAAABBQFgAAF/AwIBAAQEAXAAAQcQAgV0YWJsZQEABGdyb3cAAAoLAQkA0HBBAfwPAAs=", + "AGFzbQEAAAABBQFgAAF/AhcBC2dyb3duLXRhYmxlBXRhYmxlAXAAAgMCAQAHEAIFdGFibGUBAARncm93AAAKCwEJANBwQQH8DwAL", + "AGFzbQEAAAABBQFgAAF/AiABFGdyb3duLWltcG9ydGVkLXRhYmxlBXRhYmxlAXAAAwMCAQAHCAEEc2l6ZQAACgcBBQD8EAAL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwgHAAAAAAABAgQJAnABHh5wAR4eBxACBHRlc3QACgVjaGVjawALCSMEAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgovBwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEHQQBBBPwMAQALBwAgABEAAAs=", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwgHAAAAAAABAgQJAnABHh5wAR4eBxACBHRlc3QACgVjaGVjawALCSMEAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgovBwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEPQQFBA/wMAwALBwAgABEAAAs=", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwgHAAAAAAABAgQJAnABHh5wAR4eBxACBHRlc3QACgVjaGVjawALCSMEAEECCwQDAQQBAQAEAgcBCABBDAsFBwUCAwYBAAUFCQIHBgpxBwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQtOAEEHQQBBBPwMAQD8DQFBD0EBQQP8DAMA/A0DQRRBD0EF/A4AAEEVQR1BAfwOAABBGEEKQQH8DgAAQQ1BC0EE/A4AAEETQRRBBfwOAAALBwAgABEAAAs=", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwgHAAAAAAABAgQJAnABHh5wAR4eBxACBHRlc3QACgVjaGVjawALCScEAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYKLwcEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLDABBB0EAQQT8DAEBCwcAIAARAAEL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwgHAAAAAAABAgQJAnABHh5wAR4eBxACBHRlc3QACgVjaGVjawALCScEAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYKLwcEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLDABBD0EBQQP8DAMBCwcAIAARAAEL", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8CKQUBYQNlZjAAAAFhA2VmMQAAAWEDZWYyAAABYQNlZjMAAAFhA2VmNAAAAwgHAAAAAAABAgQJAnABHh5wAR4eBxACBHRlc3QACgVjaGVjawALCScEAgFBAgsABAMBBAEBAAQCBwEIAgFBDAsABQcFAgMGAQAFBQkCBwYKcQcEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLTgBBB0EAQQT8DAEB/A0BQQ9BAUED/AwDAfwNA0EUQQ9BBfwOAQFBFUEdQQH8DgEBQRhBCkEB/A4BAUENQQtBBPwOAQFBE0EUQQX8DgEBCwcAIAARAAEL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCjkLBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsFAPwNAgs=", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEMQQFBAfwMAgAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkoLBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsWAEEMQQFBAfwMAQBBFUEBQQH8DAEACw==", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCjwLBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsIAPwNAfwNAQs=", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkMLBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsPAPwNAUEMQQFBAfwMAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEMQQBBBfwMAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEMQQJBA/wMAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEcQQFBA/wMAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEMQQRBAPwMAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEMQQVBAPwMAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEeQQJBAPwMAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEfQQJBAPwMAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEeQQRBAPwMAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJIwQAQQILBAMBBAEBAAQCBwEIAEEMCwUHBQIDBgEABQUJAgcGCkALBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsMAEEfQQVBAPwMAQAL", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJJwQCAUECCwAEAwEEAQEABAIHAQgCAUEMCwAFBwUCAwYBAAUFCQIHBgpACwQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLDABBGkEBQQP8DAEBCw==", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJJwQCAUECCwAEAwEEAQEABAIHAQgCAUEMCwAFBwUCAwYBAAUFCQIHBgpACwQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLDABBDEEEQQD8DAEBCw==", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJJwQCAUECCwAEAwEEAQEABAIHAQgCAUEMCwAFBwUCAwYBAAUFCQIHBgpACwQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLDABBDEEFQQD8DAEBCw==", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJJwQCAUECCwAEAwEEAQEABAIHAQgCAUEMCwAFBwUCAwYBAAUFCQIHBgpACwQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLDABBHEECQQD8DAEBCw==", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJJwQCAUECCwAEAwEEAQEABAIHAQgCAUEMCwAFBwUCAwYBAAUFCQIHBgpACwQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLDABBHUECQQD8DAEBCw==", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJJwQCAUECCwAEAwEEAQEABAIHAQgCAUEMCwAFBwUCAwYBAAUFCQIHBgpACwQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLDABBHEEEQQD8DAEBCw==", + "AGFzbQEAAAABCAJgAAF/YAAAAwwLAAAAAAAAAAAAAAEECQJwAR4ecAEcHAcIAQR0ZXN0AAoJJwQCAUECCwAEAwEEAQEABAIHAQgCAUEMCwAFBwUCAwYBAAUFCQIHBgpACwQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLDABBHUEFQQD8DAEBCw==", + "AGFzbQEAAAABDwNgAAF/YAF/AX9gAn9/AAMTEgAAAAAAAAAAAAAAAAAAAAABAgQFAXABIEAHZBICZjAAAAJmMQABAmYyAAICZjMAAwJmNAAEAmY1AAUCZjYABgJmNwAHAmY4AAgCZjkACQNmMTAACgNmMTEACwNmMTIADANmMTMADQNmMTQADgNmMTUADwR0ZXN0ABADcnVuABEJFAEBABAAAQIDBAUGBwgJCgsMDQ4PCmYSBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsEAEEKCwQAQQsLBABBDAsEAEENCwQAQQ4LBABBDwsHACAAEQAACwwAIABBACAB/AwAAAs=", + "AGFzbQEAAAABDwNgAAF/YAF/AX9gAn9/AAMTEgAAAAAAAAAAAAAAAAAAAAABAgQHAXABoAHAAgdkEgJmMAAAAmYxAAECZjIAAgJmMwADAmY0AAQCZjUABQJmNgAGAmY3AAcCZjgACAJmOQAJA2YxMAAKA2YxMQALA2YxMgAMA2YxMwANA2YxNAAOA2YxNQAPBHRlc3QAEANydW4AEQkUAQEAEAABAgMEBQYHCAkKCwwNDg8KZhIEAEEACwQAQQELBABBAgsEAEEDCwQAQQQLBABBBQsEAEEGCwQAQQcLBABBCAsEAEEJCwQAQQoLBABBCwsEAEEMCwQAQQ0LBABBDgsEAEEPCwcAIAARAAALDAAgAEEAIAH8DAAACw==", + "AGFzbQEAAAABDwNgAAF/YAF/AX9gAn9/AAMTEgAAAAAAAAAAAAAAAAAAAAABAgQFAXABQEAHZBICZjAAAAJmMQABAmYyAAICZjMAAwJmNAAEAmY1AAUCZjYABgJmNwAHAmY4AAgCZjkACQNmMTAACgNmMTEACwNmMTIADANmMTMADQNmMTQADgNmMTUADwR0ZXN0ABADcnVuABEJFAEBABAAAQIDBAUGBwgJCgsMDQ4PCmYSBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsEAEEKCwQAQQsLBABBDAsEAEENCwQAQQ4LBABBDwsHACAAEQAACwwAIABBACAB/AwAAAs=", + "AGFzbQEAAAABDwNgAAF/YAF/AX9gAn9/AAMTEgAAAAAAAAAAAAAAAAAAAAABAgQFAXABEBAHZBICZjAAAAJmMQABAmYyAAICZjMAAwJmNAAEAmY1AAUCZjYABgJmNwAHAmY4AAgCZjkACQNmMTAACgNmMTEACwNmMTIADANmMTMADQNmMTQADgNmMTUADwR0ZXN0ABADcnVuABEJFAEBABAAAQIDBAUGBwgJCgsMDQ4PCmYSBABBAAsEAEEBCwQAQQILBABBAwsEAEEECwQAQQULBABBBgsEAEEHCwQAQQgLBABBCQsEAEEKCwQAQQsLBABBDAsEAEENCwQAQQ4LBABBDwsHACAAEQAACwwAIABBCCAB/AwAAAs=", + "AGFzbQEAAAABBAFgAAADAgEABAQBcAABCcQBQQEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAoOAQwAQQBBAEEA/AxAAAs=", + "AGFzbQEAAAABIgdgAABgAX8Bb2ABfwFwYAJ/bwBgAn9wAGACf38AYAF/AX8DCAcAAQIDBAUGBAcCbwABcAACB2IGDWdldC1leHRlcm5yZWYAAQtnZXQtZnVuY3JlZgACDXNldC1leHRlcm5yZWYAAwtzZXQtZnVuY3JlZgAEEHNldC1mdW5jcmVmLWZyb20ABQ9pc19udWxsLWZ1bmNyZWYABgkJAQIBQQELAAEACjcHAgALBgAgACUACwYAIAAlAQsIACAAIAEmAAsIACAAIAEmAQsKACAAIAElASYBCwcAIAAQAtEL", + "AGFzbQEAAAABCQJgAAF/YAF/AAMJCAAAAAABAQEBBA8EbwAAbwABbwEAAm8BAwgHUQgHc2l6ZS10MAAAB3NpemUtdDEAAQdzaXplLXQyAAIHc2l6ZS10MwADB2dyb3ctdDAABAdncm93LXQxAAUHZ3Jvdy10MgAGB2dyb3ctdDMABwpFCAUA/BAACwUA/BABCwUA/BACCwUA/BADCwoA0G8gAPwPABoLCgDQbyAA/A8BGgsKANBvIAD8DwIaCwoA0G8gAPwPAxoL", + "AGFzbQEAAAABBAFgAAADAwIAAAQEAXAACgmkAz0BAAAFcATSAAvSAAvQcAvSAQsBAAABAAQAAAEBAQAABXAE0gAL0gAL0HAL0gELAQAAAQAEAAABAQBBAAsABEEACwLSAAvQcAsAQQALAABBAAsCAAEAQQALAABBAAsCAAEAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAARBAAsC0gAL0HALAEEACwIAAABBAAsCAAAAQQALAARBAAsC0gAL0HALAEEACwIAAABBAAsCAAAEQQALAtIAC9BwCwBBAAsABEEACwLSAAvQcAsAQQALAABBAAsCAAEAQQALAABBAAsCAAEAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAARBAAsC0gAL0HALAEEACwIAAABBAAsCAAAAQQALAARBAAsC0gAL0HALAEEACwIAAABBAAsCAAADAAAHcATSAAvSAAvQcAvSAQsDAAADAAQAAAEBAwAAB3AE0gAL0gAL0HAL0gELAwAAAwAEAAABAQoHAgIACwIACw==", + "AGFzbQEAAAABBAFgAAADAwIAAAQFAXABAwMJDwEEQQALA9IAC9BwC9IBCwoHAgIACwIACw==", + "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCQcBAEEACwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCR8FAEEACwEAAEEDCwEAAEEHCwEAAEEFCwEAAEEDCwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAACGAEIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AAMCAQAEBQFwAOgHCQcBACMACwEACgQBAgAL", + "AGFzbQEAAAABBQFgAAF/AwUEAAAAAAQEAXAACgcTAgZjYWxsLTcAAgZjYWxsLTkAAwkNAgBBBwsBAABBCQsBAQodBAUAQcEACwUAQcIACwcAQQcRAAALBwBBCREAAAs=", + "AGFzbQEAAAABBQFgAAF/AwUEAAAAAAQEAXAACwcTAgZjYWxsLTcAAgZjYWxsLTkAAwkXAgRBBgsC0HAL0gALBEEJCwLSAQvQcAsKHQQFAEHBAAsFAEHCAAsHAEEHEQAACwcAQQkRAAAL", + "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCQcBAEEJCwEACgQBAgAL", + "AGFzbQEAAAAEBAFwAAAJBgEAQQALAA==", + "AGFzbQEAAAAEBQFwAQAACQYBAEEACwA=", + "AGFzbQEAAAAEBAFwABQJBgEAQRQLAA==", + "AGFzbQEAAAABBAFgAAADAgEABAQBcAAACQcBAEEACwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAADAgEABAUBcAEAAAkHAQBBAAsBAAoEAQIACw==", + "AGFzbQEAAAABBAFgAAADAgEABAUBcAEAAQkHAQBBAAsBAAoEAQIACw==", + "AGFzbQEAAAAEBAFwAAAJBgEAQQELAA==", + "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCQcBAEEKCwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAADAgEABAUBcAEKFAkHAQBBCgsBAAoEAQIACw==", + "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCQcBAEF/CwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCQcBAEF2CwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAADAwIAAAQEAXAACgcIAQRpbml0AAEJBwEAQQALAQAKEQICAAsMAEEAQQBBAfwMAAAL", + "AGFzbQEAAAABBAFgAAADAwIAAAQEAXAACgcIAQRpbml0AAEJBQEDAAEAChECAgALDABBAEEAQQH8DAAACw==", + "AGFzbQEAAAABBQFgAAF/AwQDAAAABAQBcAAKBxQBEGNhbGwtb3ZlcndyaXR0ZW4AAgkNAgBBCQsBAABBCQsBAQoVAwUAQcEACwUAQcIACwcAQQkRAAAL", + "AGFzbQEAAAABBQFgAAF/AwYFAAAAAAAEBAFwAAoHKwQMc2hhcmVkLXRhYmxlAQAGY2FsbC03AAIGY2FsbC04AAMGY2FsbC05AAQJDQIAQQgLAQAAQQkLAQEKJQUFAEHBAAsFAEHCAAsHAEEHEQAACwcAQQgRAAALBwBBCREAAAs=", + "AGFzbQEAAAABBQFgAAF/AhoBB21vZHVsZTEMc2hhcmVkLXRhYmxlAXAACgMDAgAACQ0CAEEHCwEAAEEICwEBCg0CBQBBwwALBQBBxAAL", + "AGFzbQEAAAABBQFgAAF/AhoBB21vZHVsZTEMc2hhcmVkLXRhYmxlAXAACgMDAgAACQ0CAEEICwEAAEEJCwEBCg0CBQBBxQALBQBBxgAL", + "AGFzbQEAAAABCwJgAX8Bb2ACf28AAwMCAAEEBAFvAAIHFQMFdGFibGUBAANnZXQAAANzZXQAAQoRAgYAIAAlAAsIACAAIAEmAAs=", + "AGFzbQEAAAACFAEIZXhwb3J0ZXIFdGFibGUBbwACCQsBBgBBAAtvAdBvCw==", + "AGFzbQEAAAABBQFgAAF/AwIBAAYGAXAA0gALBwUBAWYDAAoGAQQAQSoL", + "AGFzbQEAAAABBQFgAAF/Ag4BB21vZHVsZTQBZgNwAAMCAQAEBAFwAAoHFgESY2FsbF9pbXBvcnRlZF9lbGVtAAAJCQEEQQALASMACwoJAQcAQQARAAAL", + "AGFzbQEAAAABBgFgAX8BfwMCAQAHBQEBZgAACgYBBAAgAAs=", + "AGFzbQEAAAABDQNgAX8Bf2AAAGAAAX8CBwEBTQFmAAADDw4AAQEBAQECAgIBAQAAAAQEAXAAAQYaBXAA0gALcADSAQtwAdIAC3AA0gMLcADSBAsHUAgJaXNfbnVsbC1mAAcJaXNfbnVsbC1nAAgJaXNfbnVsbC12AAkFc2V0LWYACgVzZXQtZwALBmNhbGwtZgAMBmNhbGwtZwANBmNhbGwtdgAOCRADAwACAwUDAAIEBgMAAgABCm4OBwAgAEEBagsIANIFGtIGGgsCAAsCAAsCAAsCAAsFANIA0QsFANIB0QsFACMC0QsGANIAJAILBgDSASQCCw8AQQDSACYAIABBABEAAAsPAEEA0gEmACAAQQARAAALDwBBACMCJgAgAEEAEQAACw==", + "AGFzbQEAAAABBAFgAAADCAcAAAAAAAAABAQBcAABBgYBcADSAAsHBQEBZgABCRUEAEEACwECAEEACwEDAQABBAEAAQUKIwcCAAsCAAsCAAsCAAsCAAsCAAsPANIA0gHSAtID0gTSBQ8L", + "AGFzbQEAAAABFwVgAXABf2ABbwF/YAAAYAFvAGABfwF/AwgHAAECAwIEBAQHAnAAAm8AAgdHBgdmdW5jcmVmAAAJZXh0ZXJucmVmAAEEaW5pdAADBmRlaW5pdAAEDGZ1bmNyZWYtZWxlbQAFDmV4dGVybnJlZi1lbGVtAAYJBwEAQQELAQIKOgcFACAA0QsFACAA0QsCAAsIAEEBIAAmAQsOAEEB0HAmAEEB0G8mAQsIACAAJQAQAAsIACAAJQEQAQs=", + "AGFzbQEAAAABCQJgAAFvYAABcAMDAgABBgsCbwDQbwtwANBwCwcXAglleHRlcm5yZWYAAAdmdW5jcmVmAAEKCwIEANBvCwQA0HAL", + "AGFzbQEAAAABBAFgAAADAgEABwUBAWEAAAoEAQIACw==", + "AGFzbQEAAAABBAFgAAADAgEABwkCAWEAAAFiAAAKBAECAAs=", + "AGFzbQEAAAABBAFgAAADAwIAAAcJAgFhAAABYgABCgcCAgALAgAL", + "AGFzbQEAAAABBAFgAAADAgEABw0DAWEAAAFiAAABYwAACgQBAgAL", + "AGFzbQEAAAABBQFgAX8AAwIBAAcJAgFhAAABYgAACgQBAgAL", + "AGFzbQEAAAABBgFgAX8BfwMCAQAHBQEBZQAACgoBCAAgAEEBag8L", + "AGFzbQEAAAA=", + "AGFzbQEAAAABBQFgAAF/AwIBAAcNAwFhAAABYgAAAWMAAAoGAQQAQSoL", + "AGFzbQEAAAAGBgF/AEEACwcFAQFhAwA=", + "AGFzbQEAAAAGBgF/AEEACwcJAgFhAwABYgMA", + "AGFzbQEAAAAGCwJ/AEEAC38AQQALBwkCAWEDAAFiAwE=", + "AGFzbQEAAAAGBgF/AEEqCwcFAQFlAwA=", + "AGFzbQEAAAAEBAFwAAAHBQEBYQEA", + "AGFzbQEAAAAEBAFwAAAHCQIBYQEAAWIBAA==", + "AGFzbQEAAAAEBwJwAABwAAAHCQIBYQEAAWIBAQ==", + "AGFzbQEAAAAEBQFwAQABBwUBAWEBAA==", + "AGFzbQEAAAAFAwEAAAcFAQFhAgA=", + "AGFzbQEAAAAFAwEAAAcJAgFhAgABYgIA", + "AGFzbQEAAAAFBAEBAAEHBQEBYQIA", + "AGFzbQEAAAABBQFgAAF/AwMCAAAHCAEEY2FsbAAACgsCBAAQAQsEAEECCw==", + "AGFzbQEAAAABBQFgAAF/AgsBAk1mBGNhbGwAAAMEAwAAAAchAwdNZi5jYWxsAAAMY2FsbCBNZi5jYWxsAAEEY2FsbAACChADBAAQAAsEABADCwQAQQML", + "AGFzbQEAAAABBQFgAX8AAhYBCHNwZWN0ZXN0CXByaW50X2kzMgAABwkBBXByaW50AAA=", + "AGFzbQEAAAABBQFgAX4AAhQBCnJlZXhwb3J0X2YFcHJpbnQAAA==", + "AGFzbQEAAAABBgFgAX8BfwIUAQpyZWV4cG9ydF9mBXByaW50AAA=", + "AGFzbQEAAAABCQJgAAF/YAF/AAMEAwAAAQYMAn8AQSoLfwFBjgELBy0FBGdsb2IDAANnZXQAAAhtdXRfZ2xvYgMBB2dldF9tdXQAAQdzZXRfbXV0AAIKEgMEACMACwQAIwELBgAgACQBCw==", + "AGFzbQEAAAABCQJgAAF/YAF/AAI+BQJNZwRnbG9iA38AAk1nCG11dF9nbG9iA38BAk1nA2dldAAAAk1nB2dldF9tdXQAAAJNZwdzZXRfbXV0AAEDAgEABgYBfwBBKwsHSQcHTWcuZ2xvYgMABk1nLmdldAAABGdsb2IDAgNnZXQAAwtNZy5tdXRfZ2xvYgMBCk1nLmdldF9tdXQAAQpNZy5zZXRfbXV0AAIKBgEEACMCCw==", + "AGFzbQEAAAACEAECTWcIbXV0X2dsb2IDfwA=", + "AGFzbQEAAAACDAECTWcEZ2xvYgN/AQ==", + "AGFzbQEAAAAGFQRwANBwC3AB0HALbwDQbwtvAdBvCwc9BAxnLWNvbnN0LWZ1bmMDAApnLXZhci1mdW5jAwEOZy1jb25zdC1leHRlcm4DAgxnLXZhci1leHRlcm4DAw==", + "AGFzbQEAAAACYQQHTXJlZl9leAxnLWNvbnN0LWZ1bmMDcAAHTXJlZl9leA5nLWNvbnN0LWV4dGVybgNvAAdNcmVmX2V4CmctdmFyLWZ1bmMDcAEHTXJlZl9leAxnLXZhci1leHRlcm4DbwE=", + "AGFzbQEAAAACGwEHTXJlZl9leA5nLWNvbnN0LWV4dGVybgNwAA==", + "AGFzbQEAAAACGQEHTXJlZl9leAxnLWNvbnN0LWZ1bmMDbwA=", + "AGFzbQEAAAACFwEHTXJlZl9leApnLXZhci1mdW5jA28B", + "AGFzbQEAAAACGQEHTXJlZl9leAxnLXZhci1leHRlcm4DcAE=", + "AGFzbQEAAAABDQNgAAF/YAAAYAF/AX8DBAMAAAIEBAFwAAoHEgMDdGFiAQABaAABBGNhbGwAAgkKAQBBAgsEAAAAAAoTAwQAQQQLBABBfAsHACAAEQAACw==", + "AGFzbQEAAAABDQNgAABgAAF/YAF/AX8CEgICTXQEY2FsbAACAk10AWgAAQMEAwECAgQFAXABBQUHIQMHTXQuY2FsbAAADGNhbGwgTXQuY2FsbAADBGNhbGwABAkLAQBBAAsFAgICAQAKFQMEAEEFCwYAIAAQAAsHACAAEQEACw==", + "AGFzbQEAAAABCgJgAAF/YAF/AX8CEwICTXQBaAAAAk10A3RhYgFwAAUDAwIAAQcIAQRjYWxsAAIJCAEAQQELAgEACg4CBABBBgsHACAAEQAACw==", + "AGFzbQEAAAABBAFgAAACDAECTXQDdGFiAXAAAAMCAQAJBwEAQQkLAQAKBAECAAs=", + "AGFzbQEAAAAGBgF/AEEFCwcFAQFnAwA=", + "AGFzbQEAAAACCQECRzEBZwN/AAYGAX8AIwALBwUBAWcDAQ==", + "AGFzbQEAAAABBAFgAAACDAECTXQDdGFiAXAAAAMCAQAJBwEAQQoLAQAKBAECAAs=", + "AGFzbQEAAAABBQFgAAF/AhYCAk10A3RhYgFwAAoCTXQDbWVtAgABAwIBAAkNAgBBBwsBAABBCQsBAAoGAQQAQQAL", + "AGFzbQEAAAABBQFgAAF/AgwBAk10A3RhYgFwAAoDAgEACRECAEEHCwEAAEEICwUAAAAAAAoGAQQAQQAL", + "AGFzbQEAAAABBQFgAAF/AgwBAk10A3RhYgFwAAoDAgEABQMBAAEJBwEAQQcLAQAKBgEEAEEACwsJAQBBgIAECwFk", + "AGFzbQEAAAAEBwJwAAFvAAEHFQIGdC1mdW5jAQAIdC1leHRlcm4BAQ==", + "AGFzbQEAAAACLQIJTXRhYmxlX2V4BnQtZnVuYwFwAAEJTXRhYmxlX2V4CHQtZXh0ZXJuAW8AAQ==", + "AGFzbQEAAAACFgEJTXRhYmxlX2V4BnQtZnVuYwFvAAE=", + "AGFzbQEAAAACGAEJTXRhYmxlX2V4CHQtZXh0ZXJuAXAAAQ==", + "AGFzbQEAAAABBgFgAX8BfwMCAQAFBAEBAQUHDgIDbWVtAgAEbG9hZAAACgkBBwAgAC0AAAsLEAEAQQoLCgABAgMEBQYHCAk=", + "AGFzbQEAAAABBgFgAX8BfwILAQJNbQRsb2FkAAADAgEABQMBAAEHEgIHTW0ubG9hZAAABGxvYWQAAQoJAQcAIAAtAAALCwwBAEEKCwbw8fLz9PU=", + "AGFzbQEAAAABBgFgAX8BfwILAQJNbQNtZW0CAAEDAgEABwgBBGxvYWQAAAoJAQcAIAAtAAALCw4BAEEFCwigoaKjpKWmpw==", + "AGFzbQEAAAACCwECTW0DbWVtAgAACwkBAEH//wMLAWE=", + "AGFzbQEAAAACCwECTW0DbWVtAgAACwkBAEGAgAQLAWE=", + "AGFzbQEAAAABBgFgAX8BfwIMAQJNbQNtZW0CAQEIAwIBAAcIAQRncm93AAAKCAEGACAAQAAL", + "AGFzbQEAAAABBAFgAAACJwMIc3BlY3Rlc3QFcHJpbnQAAAJNbQNtZW0CAAECTW0DdGFiAXAAAAsJAQBBAAsDYWJj", + "AGFzbQEAAAACCwECTW0DbWVtAgABCyICAEEACwNhYmMAQfb/EwsSenp6enp6enp6enp6enp6enp6", + "AGFzbQEAAAABBAFgAAACCwECTW0DbWVtAgABAwIBAAQEAXAAAAkHAQBBAAsBAAoEAQIACwsJAQBBAAsDYWJj", + "AGFzbQEAAAABBQFgAAF/AwMCAAAEBAFwAAEFAwEAAQcxBAZtZW1vcnkCAAV0YWJsZQEADWdldCBtZW1vcnlbMF0AAAxnZXQgdGFibGVbMF0AAQoRAgcAQQAtAAALBwBBABEAAAs=", + "AGFzbQEAAAABCAJgAAF/YAAAAhsCAk1zBm1lbW9yeQIAAQJNcwV0YWJsZQFwAAEDAwIAAQgBAQkHAQBBAAsBAAoMAgYAQa29AwsDAAALCwsBAEEACwVoZWxsbw==", +]; +export const script = "[[\"file\",\"table_copy.wast\"],[\"module\",6,0],[\"register\",\"a\"],[\"module\",15,1],[\"invoke\",45,0,\"test\",[]],[\"invoke\",50,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",54,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",58,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",62,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",66,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",71,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",75,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",79,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",83,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",87,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",92,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",96,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",100,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",104,0,\"check_t1\",[\"i32:28\"]],[\"module\",107,2],[\"invoke\",139,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",143,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",148,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",152,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",156,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",160,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",164,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",169,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",173,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",177,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",181,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",185,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",190,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",194,0,\"check_t1\",[\"i32:26\"]],[\"module\",199,3],[\"invoke\",229,0,\"test\",[]],[\"invoke\",233,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",237,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",241,0,\"check_t0\",[\"i32:11\"]],[\"invoke\",246,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",250,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",254,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",258,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",262,0,\"check_t1\",[\"i32:2\"]],[\"invoke\",267,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",271,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",275,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",279,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",283,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",288,0,\"check_t1\",[\"i32:28\"]],[\"module\",291,4],[\"invoke\",323,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",327,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",331,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",335,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",339,0,\"check_t0\",[\"i32:17\"]],[\"invoke\",344,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",348,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",352,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",356,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",360,0,\"check_t1\",[\"i32:8\"]],[\"invoke\",365,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",369,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",373,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",377,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",381,0,\"check_t1\",[\"i32:29\"]],[\"module\",383,5],[\"invoke\",417,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",421,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",425,0,\"check_t0\",[\"i32:11\"]],[\"invoke\",429,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",433,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",437,0,\"check_t0\",[\"i32:23\"]],[\"invoke\",442,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",446,0,\"check_t1\",[\"i32:2\"]],[\"invoke\",450,0,\"check_t1\",[\"i32:6\"]],[\"invoke\",454,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",458,0,\"check_t1\",[\"i32:14\"]],[\"invoke\",463,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",467,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",471,0,\"check_t1\",[\"i32:27\"]],[\"module\",475,6],[\"invoke\",506,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",510,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",515,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",519,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",523,0,\"check_t0\",[\"i32:17\"]],[\"invoke\",527,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",531,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",535,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",540,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",544,0,\"check_t1\",[\"i32:8\"]],[\"invoke\",548,0,\"check_t1\",[\"i32:12\"]],[\"invoke\",552,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",556,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",561,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",565,0,\"check_t1\",[\"i32:29\"]],[\"module\",567,7],[\"invoke\",600,0,\"check_t0\",[\"i32:2\"]],[\"invoke\",604,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",608,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",613,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",617,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",621,0,\"check_t0\",[\"i32:23\"]],[\"invoke\",625,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",629,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",633,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",638,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",642,0,\"check_t1\",[\"i32:14\"]],[\"invoke\",646,0,\"check_t1\",[\"i32:18\"]],[\"invoke\",650,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",654,0,\"check_t1\",[\"i32:26\"]],[\"module\",659,8],[\"invoke\",690,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",694,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",698,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",702,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",706,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",711,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",715,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",719,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",723,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",727,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",731,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",736,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",740,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",744,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",748,0,\"check_t1\",[\"i32:28\"]],[\"module\",751,9],[\"invoke\",783,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",788,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",792,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",796,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",800,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",804,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",809,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",813,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",817,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",821,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",825,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",829,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",834,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",838,0,\"check_t1\",[\"i32:26\"]],[\"module\",843,10],[\"invoke\",873,0,\"test\",[]],[\"invoke\",877,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",881,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",886,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",890,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",894,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",898,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",902,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",907,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",911,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",915,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",919,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",923,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",927,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",932,0,\"check_t1\",[\"i32:28\"]],[\"module\",935,11],[\"invoke\",967,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",971,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",975,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",979,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",984,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",988,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",992,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",996,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",1000,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",1005,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",1009,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",1013,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",1017,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",1021,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",1025,0,\"check_t1\",[\"i32:29\"]],[\"module\",1027,12],[\"invoke\",1061,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",1065,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",1069,0,\"check_t0\",[\"i32:11\"]],[\"invoke\",1073,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",1077,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",1082,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",1086,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",1090,0,\"check_t1\",[\"i32:2\"]],[\"invoke\",1094,0,\"check_t1\",[\"i32:6\"]],[\"invoke\",1098,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",1103,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",1107,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",1111,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",1115,0,\"check_t1\",[\"i32:27\"]],[\"module\",1119,13],[\"invoke\",1150,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",1154,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",1159,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",1163,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",1167,0,\"check_t0\",[\"i32:17\"]],[\"invoke\",1171,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",1175,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",1180,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",1184,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",1188,0,\"check_t1\",[\"i32:8\"]],[\"invoke\",1192,0,\"check_t1\",[\"i32:12\"]],[\"invoke\",1196,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",1201,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",1205,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",1209,0,\"check_t1\",[\"i32:29\"]],[\"module\",1211,14],[\"invoke\",1244,0,\"check_t0\",[\"i32:2\"]],[\"invoke\",1248,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",1252,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",1257,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",1261,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",1265,0,\"check_t0\",[\"i32:23\"]],[\"invoke\",1269,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",1273,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",1278,0,\"check_t1\",[\"i32:6\"]],[\"invoke\",1282,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",1286,0,\"check_t1\",[\"i32:14\"]],[\"invoke\",1290,0,\"check_t1\",[\"i32:18\"]],[\"invoke\",1294,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",1299,0,\"check_t1\",[\"i32:27\"]],[\"module\",1303,15],[\"invoke\",1334,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",1338,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",1342,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",1346,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",1350,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",1355,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",1359,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",1363,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",1367,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",1371,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",1376,0,\"check_t1\",[\"i32:12\"]],[\"invoke\",1380,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",1384,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",1388,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",1392,0,\"check_t1\",[\"i32:28\"]],[\"module\",1395,16],[\"invoke\",1428,0,\"check_t0\",[\"i32:2\"]],[\"invoke\",1432,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",1436,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",1440,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",1444,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",1448,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",1453,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",1457,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",1461,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",1465,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",1469,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",1474,0,\"check_t1\",[\"i32:18\"]],[\"invoke\",1478,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",1482,0,\"check_t1\",[\"i32:26\"]],[\"module\",1487,17],[\"invoke\",1517,0,\"test\",[]],[\"invoke\",1521,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",1526,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",1530,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",1534,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",1538,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",1542,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",1546,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",1551,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",1555,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",1559,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",1563,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",1567,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",1572,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",1576,0,\"check_t1\",[\"i32:28\"]],[\"module\",1579,18],[\"invoke\",1611,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",1615,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",1619,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",1624,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",1628,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",1632,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",1636,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",1640,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",1644,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",1649,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",1653,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",1657,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",1661,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",1665,0,\"check_t1\",[\"i32:25\"]],[\"module\",1671,19],[\"invoke\",1694,0,\"test\",[]],[\"module\",1696,20],[\"module\",1721,21],[\"module\",1746,22],[\"module\",1771,23],[\"invoke\",1794,0,\"test\",[]],[\"module\",1796,24],[\"module\",1821,25],[\"module\",1846,26],[\"module\",1871,27],[\"invoke\",1894,0,\"test\",[]],[\"module\",1896,28],[\"module\",1921,29],[\"module\",1946,30],[\"module\",1971,31],[\"invoke\",1994,0,\"test\",[]],[\"module\",1996,32],[\"module\",2021,33],[\"module\",2046,34],[\"module\",2071,35],[\"invoke\",2094,0,\"test\",[]],[\"module\",2096,36],[\"module\",2121,37],[\"module\",2146,38],[\"module\",2171,39],[\"module\",2196,40],[\"invoke\",2219,0,\"test\",[]],[\"module\",2221,41],[\"invoke\",2251,0,\"test\",[\"i32:2\"]],[\"invoke\",2255,0,\"test\",[\"i32:6\"]],[\"invoke\",2259,0,\"test\",[\"i32:10\"]],[\"invoke\",2263,0,\"test\",[\"i32:14\"]],[\"invoke\",2267,0,\"test\",[\"i32:18\"]],[\"invoke\",2272,0,\"test\",[\"i32:23\"]],[\"invoke\",2276,0,\"test\",[\"i32:27\"]],[\"invoke\",2280,0,\"test\",[\"i32:31\"]],[\"module\",2282,42],[\"invoke\",2312,0,\"test\",[\"i32:2\"]],[\"invoke\",2316,0,\"test\",[\"i32:6\"]],[\"invoke\",2321,0,\"test\",[\"i32:11\"]],[\"invoke\",2325,0,\"test\",[\"i32:15\"]],[\"invoke\",2329,0,\"test\",[\"i32:19\"]],[\"invoke\",2333,0,\"test\",[\"i32:23\"]],[\"invoke\",2337,0,\"test\",[\"i32:27\"]],[\"module\",2343,43],[\"invoke\",2369,0,\"run\",[\"i32:0\",\"i32:24\",\"i32:16\"]],[\"invoke\",2374,0,\"test\",[\"i32:3\"]],[\"invoke\",2378,0,\"test\",[\"i32:7\"]],[\"invoke\",2382,0,\"test\",[\"i32:11\"]],[\"invoke\",2386,0,\"test\",[\"i32:15\"]],[\"invoke\",2390,0,\"test\",[\"i32:19\"]],[\"invoke\",2395,0,\"test\",[\"i32:24\"]],[\"invoke\",2399,0,\"test\",[\"i32:28\"]],[\"module\",2404,44],[\"invoke\",2430,0,\"run\",[\"i32:0\",\"i32:23\",\"i32:15\"]],[\"invoke\",2435,0,\"test\",[\"i32:3\"]],[\"invoke\",2439,0,\"test\",[\"i32:7\"]],[\"invoke\",2444,0,\"test\",[\"i32:12\"]],[\"invoke\",2448,0,\"test\",[\"i32:16\"]],[\"invoke\",2452,0,\"test\",[\"i32:20\"]],[\"invoke\",2456,0,\"test\",[\"i32:24\"]],[\"invoke\",2460,0,\"test\",[\"i32:28\"]],[\"module\",2465,45],[\"invoke\",2493,0,\"test\",[\"i32:0\"]],[\"invoke\",2497,0,\"test\",[\"i32:4\"]],[\"invoke\",2501,0,\"test\",[\"i32:8\"]],[\"invoke\",2505,0,\"test\",[\"i32:12\"]],[\"invoke\",2509,0,\"test\",[\"i32:16\"]],[\"invoke\",2513,0,\"test\",[\"i32:20\"]],[\"invoke\",2518,0,\"test\",[\"i32:25\"]],[\"invoke\",2522,0,\"test\",[\"i32:29\"]],[\"module\",2526,43],[\"invoke\",2554,0,\"test\",[\"i32:0\"]],[\"invoke\",2558,0,\"test\",[\"i32:4\"]],[\"invoke\",2562,0,\"test\",[\"i32:8\"]],[\"invoke\",2567,0,\"test\",[\"i32:13\"]],[\"invoke\",2571,0,\"test\",[\"i32:17\"]],[\"invoke\",2575,0,\"test\",[\"i32:21\"]],[\"invoke\",2579,0,\"test\",[\"i32:25\"]],[\"invoke\",2583,0,\"test\",[\"i32:29\"]],[\"module\",2587,46],[\"invoke\",2616,0,\"test\",[\"i32:1\"]],[\"invoke\",2620,0,\"test\",[\"i32:5\"]],[\"invoke\",2624,0,\"test\",[\"i32:9\"]],[\"invoke\",2628,0,\"test\",[\"i32:13\"]],[\"invoke\",2632,0,\"test\",[\"i32:17\"]],[\"invoke\",2636,0,\"test\",[\"i32:21\"]],[\"invoke\",2641,0,\"test\",[\"i32:26\"]],[\"invoke\",2645,0,\"test\",[\"i32:30\"]],[\"module\",2648,43],[\"invoke\",2677,0,\"test\",[\"i32:1\"]],[\"invoke\",2681,0,\"test\",[\"i32:5\"]],[\"invoke\",2685,0,\"test\",[\"i32:9\"]],[\"invoke\",2690,0,\"test\",[\"i32:14\"]],[\"invoke\",2694,0,\"test\",[\"i32:18\"]],[\"invoke\",2698,0,\"test\",[\"i32:22\"]],[\"invoke\",2702,0,\"test\",[\"i32:26\"]],[\"invoke\",2706,0,\"test\",[\"i32:30\"]],[\"module\",2709,47],[\"invoke\",2739,0,\"test\",[\"i32:2\"]],[\"invoke\",2743,0,\"test\",[\"i32:6\"]],[\"invoke\",2747,0,\"test\",[\"i32:10\"]],[\"invoke\",2751,0,\"test\",[\"i32:14\"]],[\"invoke\",2755,0,\"test\",[\"i32:18\"]],[\"invoke\",2759,0,\"test\",[\"i32:22\"]],[\"invoke\",2764,0,\"test\",[\"i32:27\"]],[\"invoke\",2768,0,\"test\",[\"i32:31\"]],[\"module\",2770,48],[\"invoke\",2800,0,\"test\",[\"i32:2\"]],[\"invoke\",2804,0,\"test\",[\"i32:6\"]],[\"invoke\",2808,0,\"test\",[\"i32:10\"]],[\"invoke\",2813,0,\"test\",[\"i32:15\"]],[\"invoke\",2817,0,\"test\",[\"i32:19\"]],[\"invoke\",2821,0,\"test\",[\"i32:23\"]],[\"invoke\",2825,0,\"test\",[\"i32:27\"]],[\"invoke\",2829,0,\"test\",[\"i32:31\"]],[\"invoke\",2834,0,\"test\",[\"i32:36\"]],[\"invoke\",2838,0,\"test\",[\"i32:40\"]],[\"invoke\",2842,0,\"test\",[\"i32:44\"]],[\"invoke\",2846,0,\"test\",[\"i32:48\"]],[\"invoke\",2850,0,\"test\",[\"i32:52\"]],[\"invoke\",2854,0,\"test\",[\"i32:56\"]],[\"invoke\",2859,0,\"test\",[\"i32:61\"]],[\"invoke\",2863,0,\"test\",[\"i32:65\"]],[\"invoke\",2867,0,\"test\",[\"i32:69\"]],[\"invoke\",2871,0,\"test\",[\"i32:73\"]],[\"invoke\",2875,0,\"test\",[\"i32:77\"]],[\"invoke\",2880,0,\"test\",[\"i32:82\"]],[\"invoke\",2884,0,\"test\",[\"i32:86\"]],[\"invoke\",2888,0,\"test\",[\"i32:90\"]],[\"invoke\",2892,0,\"test\",[\"i32:94\"]],[\"invoke\",2896,0,\"test\",[\"i32:98\"]],[\"invoke\",2901,0,\"test\",[\"i32:103\"]],[\"invoke\",2905,0,\"test\",[\"i32:107\"]],[\"invoke\",2909,0,\"test\",[\"i32:111\"]],[\"invoke\",2913,0,\"test\",[\"i32:115\"]],[\"invoke\",2917,0,\"test\",[\"i32:119\"]],[\"invoke\",2921,0,\"test\",[\"i32:123\"]],[\"module\",2927,49],[\"invoke\",2953,0,\"run\",[\"i32:112\",\"i32:0\",\"i32:4294967264\"]],[\"invoke\",2958,0,\"test\",[\"i32:3\"]],[\"invoke\",2962,0,\"test\",[\"i32:7\"]],[\"invoke\",2966,0,\"test\",[\"i32:11\"]],[\"invoke\",2970,0,\"test\",[\"i32:15\"]],[\"invoke\",2975,0,\"test\",[\"i32:20\"]],[\"invoke\",2979,0,\"test\",[\"i32:24\"]],[\"invoke\",2983,0,\"test\",[\"i32:28\"]],[\"invoke\",2987,0,\"test\",[\"i32:32\"]],[\"invoke\",2991,0,\"test\",[\"i32:36\"]],[\"invoke\",2996,0,\"test\",[\"i32:41\"]],[\"invoke\",3000,0,\"test\",[\"i32:45\"]],[\"invoke\",3004,0,\"test\",[\"i32:49\"]],[\"invoke\",3008,0,\"test\",[\"i32:53\"]],[\"invoke\",3012,0,\"test\",[\"i32:57\"]],[\"invoke\",3016,0,\"test\",[\"i32:61\"]],[\"invoke\",3021,0,\"test\",[\"i32:66\"]],[\"invoke\",3025,0,\"test\",[\"i32:70\"]],[\"invoke\",3029,0,\"test\",[\"i32:74\"]],[\"invoke\",3033,0,\"test\",[\"i32:78\"]],[\"invoke\",3037,0,\"test\",[\"i32:82\"]],[\"invoke\",3042,0,\"test\",[\"i32:87\"]],[\"invoke\",3046,0,\"test\",[\"i32:91\"]],[\"invoke\",3050,0,\"test\",[\"i32:95\"]],[\"invoke\",3054,0,\"test\",[\"i32:99\"]],[\"invoke\",3058,0,\"test\",[\"i32:103\"]],[\"invoke\",3063,0,\"test\",[\"i32:108\"]],[\"invoke\",3067,0,\"test\",[\"i32:112\"]],[\"invoke\",3071,0,\"test\",[\"i32:116\"]],[\"invoke\",3075,0,\"test\",[\"i32:120\"]],[\"invoke\",3079,0,\"test\",[\"i32:124\"]],[\"file\",\"table_fill.wast\"],[\"module\",1,50],[\"invoke\",17,0,\"get\",[\"i32:1\"]],[\"invoke\",18,0,\"get\",[\"i32:2\"]],[\"invoke\",19,0,\"get\",[\"i32:3\"]],[\"invoke\",20,0,\"get\",[\"i32:4\"]],[\"invoke\",21,0,\"get\",[\"i32:5\"]],[\"invoke\",23,0,\"fill\",[\"i32:2\",\"externref:1\",\"i32:3\"]],[\"invoke\",24,0,\"get\",[\"i32:1\"]],[\"invoke\",25,0,\"get\",[\"i32:2\"]],[\"invoke\",26,0,\"get\",[\"i32:3\"]],[\"invoke\",27,0,\"get\",[\"i32:4\"]],[\"invoke\",28,0,\"get\",[\"i32:5\"]],[\"invoke\",30,0,\"fill\",[\"i32:4\",\"externref:2\",\"i32:2\"]],[\"invoke\",31,0,\"get\",[\"i32:3\"]],[\"invoke\",32,0,\"get\",[\"i32:4\"]],[\"invoke\",33,0,\"get\",[\"i32:5\"]],[\"invoke\",34,0,\"get\",[\"i32:6\"]],[\"invoke\",36,0,\"fill\",[\"i32:4\",\"externref:3\",\"i32:0\"]],[\"invoke\",37,0,\"get\",[\"i32:3\"]],[\"invoke\",38,0,\"get\",[\"i32:4\"]],[\"invoke\",39,0,\"get\",[\"i32:5\"]],[\"invoke\",41,0,\"fill\",[\"i32:8\",\"externref:4\",\"i32:2\"]],[\"invoke\",42,0,\"get\",[\"i32:7\"]],[\"invoke\",43,0,\"get\",[\"i32:8\"]],[\"invoke\",44,0,\"get\",[\"i32:9\"]],[\"invoke\",46,0,\"fill-abbrev\",[\"i32:9\",\"externref:null\",\"i32:1\"]],[\"invoke\",47,0,\"get\",[\"i32:8\"]],[\"invoke\",48,0,\"get\",[\"i32:9\"]],[\"invoke\",50,0,\"fill\",[\"i32:10\",\"externref:5\",\"i32:0\"]],[\"invoke\",51,0,\"get\",[\"i32:9\"]],[\"invoke\",54,0,\"fill\",[\"i32:8\",\"externref:6\",\"i32:3\"]],[\"invoke\",57,0,\"get\",[\"i32:7\"]],[\"invoke\",58,0,\"get\",[\"i32:8\"]],[\"invoke\",59,0,\"get\",[\"i32:9\"]],[\"invoke\",62,0,\"fill\",[\"i32:11\",\"externref:null\",\"i32:0\"]],[\"invoke\",67,0,\"fill\",[\"i32:11\",\"externref:null\",\"i32:10\"]],[\"file\",\"table_get.wast\"],[\"module\",1,51],[\"invoke\",24,0,\"init\",[\"externref:1\"]],[\"invoke\",26,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",27,0,\"get-externref\",[\"i32:1\"]],[\"invoke\",29,0,\"get-funcref\",[\"i32:0\"]],[\"invoke\",30,0,\"is_null-funcref\",[\"i32:1\"]],[\"invoke\",31,0,\"is_null-funcref\",[\"i32:2\"]],[\"invoke\",33,0,\"get-externref\",[\"i32:2\"]],[\"invoke\",34,0,\"get-funcref\",[\"i32:3\"]],[\"invoke\",35,0,\"get-externref\",[\"i32:4294967295\"]],[\"invoke\",36,0,\"get-funcref\",[\"i32:4294967295\"]],[\"file\",\"table_grow.wast\"],[\"module\",1,52],[\"invoke\",16,0,\"size\",[]],[\"invoke\",17,0,\"set\",[\"i32:0\",\"externref:2\"]],[\"invoke\",18,0,\"get\",[\"i32:0\"]],[\"invoke\",20,0,\"grow\",[\"i32:1\",\"externref:null\"]],[\"invoke\",21,0,\"size\",[]],[\"invoke\",22,0,\"get\",[\"i32:0\"]],[\"invoke\",23,0,\"set\",[\"i32:0\",\"externref:2\"]],[\"invoke\",24,0,\"get\",[\"i32:0\"]],[\"invoke\",25,0,\"set\",[\"i32:1\",\"externref:2\"]],[\"invoke\",26,0,\"get\",[\"i32:1\"]],[\"invoke\",28,0,\"grow-abbrev\",[\"i32:4\",\"externref:3\"]],[\"invoke\",29,0,\"size\",[]],[\"invoke\",30,0,\"get\",[\"i32:0\"]],[\"invoke\",31,0,\"set\",[\"i32:0\",\"externref:2\"]],[\"invoke\",32,0,\"get\",[\"i32:0\"]],[\"invoke\",33,0,\"get\",[\"i32:1\"]],[\"invoke\",34,0,\"get\",[\"i32:4\"]],[\"invoke\",35,0,\"set\",[\"i32:4\",\"externref:4\"]],[\"invoke\",36,0,\"get\",[\"i32:4\"]],[\"invoke\",37,0,\"set\",[\"i32:5\",\"externref:2\"]],[\"invoke\",38,0,\"get\",[\"i32:5\"]],[\"module\",42,53],[\"invoke\",50,0,\"grow\",[]],[\"module\",53,54],[\"invoke\",60,0,\"grow\",[\"i32:0\"]],[\"invoke\",61,0,\"grow\",[\"i32:1\"]],[\"invoke\",62,0,\"grow\",[\"i32:0\"]],[\"invoke\",63,0,\"grow\",[\"i32:2\"]],[\"invoke\",64,0,\"grow\",[\"i32:800\"]],[\"module\",67,55],[\"invoke\",74,0,\"grow\",[\"i32:0\"]],[\"invoke\",75,0,\"grow\",[\"i32:1\"]],[\"invoke\",76,0,\"grow\",[\"i32:1\"]],[\"invoke\",77,0,\"grow\",[\"i32:2\"]],[\"invoke\",78,0,\"grow\",[\"i32:6\"]],[\"invoke\",79,0,\"grow\",[\"i32:0\"]],[\"invoke\",80,0,\"grow\",[\"i32:1\"]],[\"invoke\",81,0,\"grow\",[\"i32:65536\"]],[\"module\",84,56],[\"invoke\",106,0,\"check-table-null\",[\"i32:0\",\"i32:9\"]],[\"invoke\",107,0,\"grow\",[\"i32:10\"]],[\"invoke\",108,0,\"check-table-null\",[\"i32:0\",\"i32:19\"]],[\"module\",111,57,\"$Tgt\"],[\"register\",\"grown-table\",\"$Tgt\"],[\"invoke\",116,\"$Tgt\",\"grow\",[]],[\"module\",117,58,\"$Tgit1\"],[\"register\",\"grown-imported-table\",\"$Tgit1\"],[\"invoke\",123,\"$Tgit1\",\"grow\",[]],[\"module\",124,59,\"$Tgit2\"],[\"invoke\",129,\"$Tgit2\",\"size\",[]],[\"file\",\"table_init.wast\"],[\"module\",6,0],[\"register\",\"a\"],[\"module\",15,60],[\"invoke\",41,0,\"test\",[]],[\"invoke\",43,0,\"check\",[\"i32:1\"]],[\"invoke\",45,0,\"check\",[\"i32:3\"]],[\"invoke\",47,0,\"check\",[\"i32:5\"]],[\"invoke\",48,0,\"check\",[\"i32:6\"]],[\"invoke\",50,0,\"check\",[\"i32:8\"]],[\"invoke\",52,0,\"check\",[\"i32:10\"]],[\"invoke\",53,0,\"check\",[\"i32:11\"]],[\"invoke\",55,0,\"check\",[\"i32:13\"]],[\"invoke\",57,0,\"check\",[\"i32:15\"]],[\"invoke\",58,0,\"check\",[\"i32:16\"]],[\"invoke\",60,0,\"check\",[\"i32:18\"]],[\"invoke\",62,0,\"check\",[\"i32:20\"]],[\"invoke\",64,0,\"check\",[\"i32:22\"]],[\"invoke\",65,0,\"check\",[\"i32:23\"]],[\"invoke\",67,0,\"check\",[\"i32:25\"]],[\"invoke\",69,0,\"check\",[\"i32:27\"]],[\"invoke\",70,0,\"check\",[\"i32:28\"]],[\"module\",73,61],[\"invoke\",99,0,\"test\",[]],[\"invoke\",101,0,\"check\",[\"i32:1\"]],[\"invoke\",102,0,\"check\",[\"i32:2\"]],[\"invoke\",104,0,\"check\",[\"i32:4\"]],[\"invoke\",106,0,\"check\",[\"i32:6\"]],[\"invoke\",107,0,\"check\",[\"i32:7\"]],[\"invoke\",109,0,\"check\",[\"i32:9\"]],[\"invoke\",111,0,\"check\",[\"i32:11\"]],[\"invoke\",113,0,\"check\",[\"i32:13\"]],[\"invoke\",114,0,\"check\",[\"i32:14\"]],[\"invoke\",116,0,\"check\",[\"i32:16\"]],[\"invoke\",118,0,\"check\",[\"i32:18\"]],[\"invoke\",119,0,\"check\",[\"i32:19\"]],[\"invoke\",121,0,\"check\",[\"i32:21\"]],[\"invoke\",123,0,\"check\",[\"i32:23\"]],[\"invoke\",124,0,\"check\",[\"i32:24\"]],[\"invoke\",126,0,\"check\",[\"i32:26\"]],[\"invoke\",128,0,\"check\",[\"i32:28\"]],[\"invoke\",129,0,\"check\",[\"i32:29\"]],[\"module\",131,62],[\"invoke\",166,0,\"check\",[\"i32:0\"]],[\"invoke\",168,0,\"check\",[\"i32:2\"]],[\"invoke\",170,0,\"check\",[\"i32:4\"]],[\"invoke\",171,0,\"check\",[\"i32:5\"]],[\"invoke\",173,0,\"check\",[\"i32:7\"]],[\"invoke\",175,0,\"check\",[\"i32:9\"]],[\"invoke\",176,0,\"check\",[\"i32:10\"]],[\"invoke\",178,0,\"check\",[\"i32:12\"]],[\"invoke\",180,0,\"check\",[\"i32:14\"]],[\"invoke\",181,0,\"check\",[\"i32:15\"]],[\"invoke\",183,0,\"check\",[\"i32:17\"]],[\"invoke\",185,0,\"check\",[\"i32:19\"]],[\"invoke\",186,0,\"check\",[\"i32:20\"]],[\"invoke\",188,0,\"check\",[\"i32:22\"]],[\"invoke\",190,0,\"check\",[\"i32:24\"]],[\"invoke\",192,0,\"check\",[\"i32:26\"]],[\"invoke\",193,0,\"check\",[\"i32:27\"]],[\"invoke\",195,0,\"check\",[\"i32:29\"]],[\"module\",197,63],[\"invoke\",224,0,\"check\",[\"i32:0\"]],[\"invoke\",225,0,\"check\",[\"i32:1\"]],[\"invoke\",227,0,\"check\",[\"i32:3\"]],[\"invoke\",229,0,\"check\",[\"i32:5\"]],[\"invoke\",230,0,\"check\",[\"i32:6\"]],[\"invoke\",232,0,\"check\",[\"i32:8\"]],[\"invoke\",234,0,\"check\",[\"i32:10\"]],[\"invoke\",235,0,\"check\",[\"i32:11\"]],[\"invoke\",237,0,\"check\",[\"i32:13\"]],[\"invoke\",239,0,\"check\",[\"i32:15\"]],[\"invoke\",241,0,\"check\",[\"i32:17\"]],[\"invoke\",242,0,\"check\",[\"i32:18\"]],[\"invoke\",244,0,\"check\",[\"i32:20\"]],[\"invoke\",246,0,\"check\",[\"i32:22\"]],[\"invoke\",247,0,\"check\",[\"i32:23\"]],[\"invoke\",249,0,\"check\",[\"i32:25\"]],[\"invoke\",251,0,\"check\",[\"i32:27\"]],[\"invoke\",252,0,\"check\",[\"i32:28\"]],[\"module\",255,64],[\"invoke\",281,0,\"test\",[]],[\"invoke\",283,0,\"check\",[\"i32:1\"]],[\"invoke\",284,0,\"check\",[\"i32:2\"]],[\"invoke\",286,0,\"check\",[\"i32:4\"]],[\"invoke\",288,0,\"check\",[\"i32:6\"]],[\"invoke\",290,0,\"check\",[\"i32:8\"]],[\"invoke\",291,0,\"check\",[\"i32:9\"]],[\"invoke\",293,0,\"check\",[\"i32:11\"]],[\"invoke\",295,0,\"check\",[\"i32:13\"]],[\"invoke\",296,0,\"check\",[\"i32:14\"]],[\"invoke\",298,0,\"check\",[\"i32:16\"]],[\"invoke\",300,0,\"check\",[\"i32:18\"]],[\"invoke\",301,0,\"check\",[\"i32:19\"]],[\"invoke\",303,0,\"check\",[\"i32:21\"]],[\"invoke\",305,0,\"check\",[\"i32:23\"]],[\"invoke\",306,0,\"check\",[\"i32:24\"]],[\"invoke\",308,0,\"check\",[\"i32:26\"]],[\"invoke\",310,0,\"check\",[\"i32:28\"]],[\"module\",313,65],[\"invoke\",347,0,\"test\",[]],[\"invoke\",348,0,\"check\",[\"i32:0\"]],[\"invoke\",350,0,\"check\",[\"i32:2\"]],[\"invoke\",352,0,\"check\",[\"i32:4\"]],[\"invoke\",353,0,\"check\",[\"i32:5\"]],[\"invoke\",355,0,\"check\",[\"i32:7\"]],[\"invoke\",357,0,\"check\",[\"i32:9\"]],[\"invoke\",358,0,\"check\",[\"i32:10\"]],[\"invoke\",360,0,\"check\",[\"i32:12\"]],[\"invoke\",362,0,\"check\",[\"i32:14\"]],[\"invoke\",363,0,\"check\",[\"i32:15\"]],[\"invoke\",365,0,\"check\",[\"i32:17\"]],[\"invoke\",367,0,\"check\",[\"i32:19\"]],[\"invoke\",369,0,\"check\",[\"i32:21\"]],[\"invoke\",370,0,\"check\",[\"i32:22\"]],[\"invoke\",372,0,\"check\",[\"i32:24\"]],[\"invoke\",374,0,\"check\",[\"i32:26\"]],[\"invoke\",375,0,\"check\",[\"i32:27\"]],[\"invoke\",377,0,\"check\",[\"i32:29\"]],[\"module\",407,66],[\"module\",431,67],[\"invoke\",453,0,\"test\",[]],[\"module\",455,68],[\"invoke\",477,0,\"test\",[]],[\"module\",479,69],[\"module\",503,70],[\"invoke\",525,0,\"test\",[]],[\"module\",527,71],[\"module\",551,72],[\"invoke\",573,0,\"test\",[]],[\"module\",575,73],[\"invoke\",597,0,\"test\",[]],[\"module\",599,74],[\"module\",623,75],[\"invoke\",645,0,\"test\",[]],[\"module\",647,76],[\"module\",671,77],[\"invoke\",693,0,\"test\",[]],[\"module\",695,78],[\"module\",719,79],[\"invoke\",741,0,\"test\",[]],[\"module\",743,80],[\"invoke\",765,0,\"test\",[]],[\"module\",767,81],[\"module\",791,82],[\"invoke\",813,0,\"test\",[]],[\"module\",815,83],[\"module\",839,84],[\"invoke\",861,0,\"test\",[]],[\"module\",863,85],[\"invoke\",885,0,\"test\",[]],[\"module\",887,86],[\"module\",1478,87],[\"invoke\",1506,0,\"run\",[\"i32:24\",\"i32:16\"]],[\"invoke\",1508,0,\"test\",[\"i32:1\"]],[\"invoke\",1509,0,\"test\",[\"i32:2\"]],[\"invoke\",1511,0,\"test\",[\"i32:4\"]],[\"invoke\",1513,0,\"test\",[\"i32:6\"]],[\"invoke\",1514,0,\"test\",[\"i32:7\"]],[\"invoke\",1516,0,\"test\",[\"i32:9\"]],[\"invoke\",1518,0,\"test\",[\"i32:11\"]],[\"invoke\",1520,0,\"test\",[\"i32:13\"]],[\"invoke\",1521,0,\"test\",[\"i32:14\"]],[\"invoke\",1523,0,\"test\",[\"i32:16\"]],[\"invoke\",1525,0,\"test\",[\"i32:18\"]],[\"invoke\",1526,0,\"test\",[\"i32:19\"]],[\"invoke\",1528,0,\"test\",[\"i32:21\"]],[\"invoke\",1530,0,\"test\",[\"i32:23\"]],[\"invoke\",1531,0,\"test\",[\"i32:24\"]],[\"invoke\",1533,0,\"test\",[\"i32:26\"]],[\"invoke\",1535,0,\"test\",[\"i32:28\"]],[\"invoke\",1536,0,\"test\",[\"i32:29\"]],[\"invoke\",1538,0,\"test\",[\"i32:31\"]],[\"module\",1540,87],[\"invoke\",1569,0,\"test\",[\"i32:0\"]],[\"invoke\",1571,0,\"test\",[\"i32:2\"]],[\"invoke\",1572,0,\"test\",[\"i32:3\"]],[\"invoke\",1574,0,\"test\",[\"i32:5\"]],[\"invoke\",1576,0,\"test\",[\"i32:7\"]],[\"invoke\",1577,0,\"test\",[\"i32:8\"]],[\"invoke\",1579,0,\"test\",[\"i32:10\"]],[\"invoke\",1581,0,\"test\",[\"i32:12\"]],[\"invoke\",1582,0,\"test\",[\"i32:13\"]],[\"invoke\",1584,0,\"test\",[\"i32:15\"]],[\"invoke\",1586,0,\"test\",[\"i32:17\"]],[\"invoke\",1587,0,\"test\",[\"i32:18\"]],[\"invoke\",1589,0,\"test\",[\"i32:20\"]],[\"invoke\",1591,0,\"test\",[\"i32:22\"]],[\"invoke\",1593,0,\"test\",[\"i32:24\"]],[\"invoke\",1594,0,\"test\",[\"i32:25\"]],[\"invoke\",1596,0,\"test\",[\"i32:27\"]],[\"invoke\",1598,0,\"test\",[\"i32:29\"]],[\"invoke\",1599,0,\"test\",[\"i32:30\"]],[\"module\",1602,88],[\"invoke\",1630,0,\"run\",[\"i32:96\",\"i32:32\"]],[\"invoke\",1632,0,\"test\",[\"i32:1\"]],[\"invoke\",1633,0,\"test\",[\"i32:2\"]],[\"invoke\",1635,0,\"test\",[\"i32:4\"]],[\"invoke\",1637,0,\"test\",[\"i32:6\"]],[\"invoke\",1638,0,\"test\",[\"i32:7\"]],[\"invoke\",1640,0,\"test\",[\"i32:9\"]],[\"invoke\",1642,0,\"test\",[\"i32:11\"]],[\"invoke\",1644,0,\"test\",[\"i32:13\"]],[\"invoke\",1645,0,\"test\",[\"i32:14\"]],[\"invoke\",1647,0,\"test\",[\"i32:16\"]],[\"invoke\",1649,0,\"test\",[\"i32:18\"]],[\"invoke\",1650,0,\"test\",[\"i32:19\"]],[\"invoke\",1652,0,\"test\",[\"i32:21\"]],[\"invoke\",1654,0,\"test\",[\"i32:23\"]],[\"invoke\",1655,0,\"test\",[\"i32:24\"]],[\"invoke\",1657,0,\"test\",[\"i32:26\"]],[\"invoke\",1659,0,\"test\",[\"i32:28\"]],[\"invoke\",1660,0,\"test\",[\"i32:29\"]],[\"invoke\",1662,0,\"test\",[\"i32:31\"]],[\"invoke\",1664,0,\"test\",[\"i32:33\"]],[\"invoke\",1666,0,\"test\",[\"i32:35\"]],[\"invoke\",1667,0,\"test\",[\"i32:36\"]],[\"invoke\",1669,0,\"test\",[\"i32:38\"]],[\"invoke\",1671,0,\"test\",[\"i32:40\"]],[\"invoke\",1672,0,\"test\",[\"i32:41\"]],[\"invoke\",1674,0,\"test\",[\"i32:43\"]],[\"invoke\",1676,0,\"test\",[\"i32:45\"]],[\"invoke\",1677,0,\"test\",[\"i32:46\"]],[\"invoke\",1679,0,\"test\",[\"i32:48\"]],[\"invoke\",1681,0,\"test\",[\"i32:50\"]],[\"invoke\",1682,0,\"test\",[\"i32:51\"]],[\"invoke\",1684,0,\"test\",[\"i32:53\"]],[\"invoke\",1686,0,\"test\",[\"i32:55\"]],[\"invoke\",1688,0,\"test\",[\"i32:57\"]],[\"invoke\",1689,0,\"test\",[\"i32:58\"]],[\"invoke\",1691,0,\"test\",[\"i32:60\"]],[\"invoke\",1693,0,\"test\",[\"i32:62\"]],[\"invoke\",1694,0,\"test\",[\"i32:63\"]],[\"invoke\",1696,0,\"test\",[\"i32:65\"]],[\"invoke\",1698,0,\"test\",[\"i32:67\"]],[\"invoke\",1699,0,\"test\",[\"i32:68\"]],[\"invoke\",1701,0,\"test\",[\"i32:70\"]],[\"invoke\",1703,0,\"test\",[\"i32:72\"]],[\"invoke\",1704,0,\"test\",[\"i32:73\"]],[\"invoke\",1706,0,\"test\",[\"i32:75\"]],[\"invoke\",1708,0,\"test\",[\"i32:77\"]],[\"invoke\",1710,0,\"test\",[\"i32:79\"]],[\"invoke\",1711,0,\"test\",[\"i32:80\"]],[\"invoke\",1713,0,\"test\",[\"i32:82\"]],[\"invoke\",1715,0,\"test\",[\"i32:84\"]],[\"invoke\",1716,0,\"test\",[\"i32:85\"]],[\"invoke\",1718,0,\"test\",[\"i32:87\"]],[\"invoke\",1720,0,\"test\",[\"i32:89\"]],[\"invoke\",1721,0,\"test\",[\"i32:90\"]],[\"invoke\",1723,0,\"test\",[\"i32:92\"]],[\"invoke\",1725,0,\"test\",[\"i32:94\"]],[\"invoke\",1726,0,\"test\",[\"i32:95\"]],[\"invoke\",1728,0,\"test\",[\"i32:97\"]],[\"invoke\",1730,0,\"test\",[\"i32:99\"]],[\"invoke\",1732,0,\"test\",[\"i32:101\"]],[\"invoke\",1733,0,\"test\",[\"i32:102\"]],[\"invoke\",1735,0,\"test\",[\"i32:104\"]],[\"invoke\",1737,0,\"test\",[\"i32:106\"]],[\"invoke\",1738,0,\"test\",[\"i32:107\"]],[\"invoke\",1740,0,\"test\",[\"i32:109\"]],[\"invoke\",1742,0,\"test\",[\"i32:111\"]],[\"invoke\",1743,0,\"test\",[\"i32:112\"]],[\"invoke\",1745,0,\"test\",[\"i32:114\"]],[\"invoke\",1747,0,\"test\",[\"i32:116\"]],[\"invoke\",1748,0,\"test\",[\"i32:117\"]],[\"invoke\",1750,0,\"test\",[\"i32:119\"]],[\"invoke\",1752,0,\"test\",[\"i32:121\"]],[\"invoke\",1754,0,\"test\",[\"i32:123\"]],[\"invoke\",1755,0,\"test\",[\"i32:124\"]],[\"invoke\",1757,0,\"test\",[\"i32:126\"]],[\"invoke\",1759,0,\"test\",[\"i32:128\"]],[\"invoke\",1760,0,\"test\",[\"i32:129\"]],[\"invoke\",1762,0,\"test\",[\"i32:131\"]],[\"invoke\",1764,0,\"test\",[\"i32:133\"]],[\"invoke\",1765,0,\"test\",[\"i32:134\"]],[\"invoke\",1767,0,\"test\",[\"i32:136\"]],[\"invoke\",1769,0,\"test\",[\"i32:138\"]],[\"invoke\",1770,0,\"test\",[\"i32:139\"]],[\"invoke\",1772,0,\"test\",[\"i32:141\"]],[\"invoke\",1774,0,\"test\",[\"i32:143\"]],[\"invoke\",1776,0,\"test\",[\"i32:145\"]],[\"invoke\",1777,0,\"test\",[\"i32:146\"]],[\"invoke\",1779,0,\"test\",[\"i32:148\"]],[\"invoke\",1781,0,\"test\",[\"i32:150\"]],[\"invoke\",1782,0,\"test\",[\"i32:151\"]],[\"invoke\",1784,0,\"test\",[\"i32:153\"]],[\"invoke\",1786,0,\"test\",[\"i32:155\"]],[\"invoke\",1787,0,\"test\",[\"i32:156\"]],[\"invoke\",1789,0,\"test\",[\"i32:158\"]],[\"module\",1792,88],[\"invoke\",1820,0,\"run\",[\"i32:97\",\"i32:31\"]],[\"invoke\",1821,0,\"test\",[\"i32:0\"]],[\"invoke\",1823,0,\"test\",[\"i32:2\"]],[\"invoke\",1825,0,\"test\",[\"i32:4\"]],[\"invoke\",1827,0,\"test\",[\"i32:6\"]],[\"invoke\",1828,0,\"test\",[\"i32:7\"]],[\"invoke\",1830,0,\"test\",[\"i32:9\"]],[\"invoke\",1832,0,\"test\",[\"i32:11\"]],[\"invoke\",1833,0,\"test\",[\"i32:12\"]],[\"invoke\",1835,0,\"test\",[\"i32:14\"]],[\"invoke\",1837,0,\"test\",[\"i32:16\"]],[\"invoke\",1838,0,\"test\",[\"i32:17\"]],[\"invoke\",1840,0,\"test\",[\"i32:19\"]],[\"invoke\",1842,0,\"test\",[\"i32:21\"]],[\"invoke\",1843,0,\"test\",[\"i32:22\"]],[\"invoke\",1845,0,\"test\",[\"i32:24\"]],[\"invoke\",1847,0,\"test\",[\"i32:26\"]],[\"invoke\",1849,0,\"test\",[\"i32:28\"]],[\"invoke\",1850,0,\"test\",[\"i32:29\"]],[\"invoke\",1852,0,\"test\",[\"i32:31\"]],[\"invoke\",1854,0,\"test\",[\"i32:33\"]],[\"invoke\",1855,0,\"test\",[\"i32:34\"]],[\"invoke\",1857,0,\"test\",[\"i32:36\"]],[\"invoke\",1859,0,\"test\",[\"i32:38\"]],[\"invoke\",1860,0,\"test\",[\"i32:39\"]],[\"invoke\",1862,0,\"test\",[\"i32:41\"]],[\"invoke\",1864,0,\"test\",[\"i32:43\"]],[\"invoke\",1865,0,\"test\",[\"i32:44\"]],[\"invoke\",1867,0,\"test\",[\"i32:46\"]],[\"invoke\",1869,0,\"test\",[\"i32:48\"]],[\"invoke\",1871,0,\"test\",[\"i32:50\"]],[\"invoke\",1872,0,\"test\",[\"i32:51\"]],[\"invoke\",1874,0,\"test\",[\"i32:53\"]],[\"invoke\",1876,0,\"test\",[\"i32:55\"]],[\"invoke\",1877,0,\"test\",[\"i32:56\"]],[\"invoke\",1879,0,\"test\",[\"i32:58\"]],[\"invoke\",1881,0,\"test\",[\"i32:60\"]],[\"invoke\",1882,0,\"test\",[\"i32:61\"]],[\"invoke\",1884,0,\"test\",[\"i32:63\"]],[\"invoke\",1886,0,\"test\",[\"i32:65\"]],[\"invoke\",1887,0,\"test\",[\"i32:66\"]],[\"invoke\",1889,0,\"test\",[\"i32:68\"]],[\"invoke\",1891,0,\"test\",[\"i32:70\"]],[\"invoke\",1893,0,\"test\",[\"i32:72\"]],[\"invoke\",1894,0,\"test\",[\"i32:73\"]],[\"invoke\",1896,0,\"test\",[\"i32:75\"]],[\"invoke\",1898,0,\"test\",[\"i32:77\"]],[\"invoke\",1899,0,\"test\",[\"i32:78\"]],[\"invoke\",1901,0,\"test\",[\"i32:80\"]],[\"invoke\",1903,0,\"test\",[\"i32:82\"]],[\"invoke\",1904,0,\"test\",[\"i32:83\"]],[\"invoke\",1906,0,\"test\",[\"i32:85\"]],[\"invoke\",1908,0,\"test\",[\"i32:87\"]],[\"invoke\",1909,0,\"test\",[\"i32:88\"]],[\"invoke\",1911,0,\"test\",[\"i32:90\"]],[\"invoke\",1913,0,\"test\",[\"i32:92\"]],[\"invoke\",1915,0,\"test\",[\"i32:94\"]],[\"invoke\",1916,0,\"test\",[\"i32:95\"]],[\"invoke\",1918,0,\"test\",[\"i32:97\"]],[\"invoke\",1920,0,\"test\",[\"i32:99\"]],[\"invoke\",1921,0,\"test\",[\"i32:100\"]],[\"invoke\",1923,0,\"test\",[\"i32:102\"]],[\"invoke\",1925,0,\"test\",[\"i32:104\"]],[\"invoke\",1926,0,\"test\",[\"i32:105\"]],[\"invoke\",1928,0,\"test\",[\"i32:107\"]],[\"invoke\",1930,0,\"test\",[\"i32:109\"]],[\"invoke\",1931,0,\"test\",[\"i32:110\"]],[\"invoke\",1933,0,\"test\",[\"i32:112\"]],[\"invoke\",1935,0,\"test\",[\"i32:114\"]],[\"invoke\",1937,0,\"test\",[\"i32:116\"]],[\"invoke\",1938,0,\"test\",[\"i32:117\"]],[\"invoke\",1940,0,\"test\",[\"i32:119\"]],[\"invoke\",1942,0,\"test\",[\"i32:121\"]],[\"invoke\",1943,0,\"test\",[\"i32:122\"]],[\"invoke\",1945,0,\"test\",[\"i32:124\"]],[\"invoke\",1947,0,\"test\",[\"i32:126\"]],[\"invoke\",1948,0,\"test\",[\"i32:127\"]],[\"invoke\",1950,0,\"test\",[\"i32:129\"]],[\"invoke\",1952,0,\"test\",[\"i32:131\"]],[\"invoke\",1953,0,\"test\",[\"i32:132\"]],[\"invoke\",1955,0,\"test\",[\"i32:134\"]],[\"invoke\",1957,0,\"test\",[\"i32:136\"]],[\"invoke\",1959,0,\"test\",[\"i32:138\"]],[\"invoke\",1960,0,\"test\",[\"i32:139\"]],[\"invoke\",1962,0,\"test\",[\"i32:141\"]],[\"invoke\",1964,0,\"test\",[\"i32:143\"]],[\"invoke\",1965,0,\"test\",[\"i32:144\"]],[\"invoke\",1967,0,\"test\",[\"i32:146\"]],[\"invoke\",1969,0,\"test\",[\"i32:148\"]],[\"invoke\",1970,0,\"test\",[\"i32:149\"]],[\"invoke\",1972,0,\"test\",[\"i32:151\"]],[\"invoke\",1974,0,\"test\",[\"i32:153\"]],[\"invoke\",1975,0,\"test\",[\"i32:154\"]],[\"invoke\",1977,0,\"test\",[\"i32:156\"]],[\"invoke\",1979,0,\"test\",[\"i32:158\"]],[\"module\",1982,89],[\"invoke\",2010,0,\"run\",[\"i32:48\",\"i32:4294967280\"]],[\"invoke\",2011,0,\"test\",[\"i32:0\"]],[\"invoke\",2013,0,\"test\",[\"i32:2\"]],[\"invoke\",2015,0,\"test\",[\"i32:4\"]],[\"invoke\",2016,0,\"test\",[\"i32:5\"]],[\"invoke\",2018,0,\"test\",[\"i32:7\"]],[\"invoke\",2020,0,\"test\",[\"i32:9\"]],[\"invoke\",2021,0,\"test\",[\"i32:10\"]],[\"invoke\",2023,0,\"test\",[\"i32:12\"]],[\"invoke\",2025,0,\"test\",[\"i32:14\"]],[\"invoke\",2026,0,\"test\",[\"i32:15\"]],[\"invoke\",2028,0,\"test\",[\"i32:17\"]],[\"invoke\",2030,0,\"test\",[\"i32:19\"]],[\"invoke\",2032,0,\"test\",[\"i32:21\"]],[\"invoke\",2033,0,\"test\",[\"i32:22\"]],[\"invoke\",2035,0,\"test\",[\"i32:24\"]],[\"invoke\",2037,0,\"test\",[\"i32:26\"]],[\"invoke\",2038,0,\"test\",[\"i32:27\"]],[\"invoke\",2040,0,\"test\",[\"i32:29\"]],[\"invoke\",2042,0,\"test\",[\"i32:31\"]],[\"invoke\",2043,0,\"test\",[\"i32:32\"]],[\"invoke\",2045,0,\"test\",[\"i32:34\"]],[\"invoke\",2047,0,\"test\",[\"i32:36\"]],[\"invoke\",2048,0,\"test\",[\"i32:37\"]],[\"invoke\",2050,0,\"test\",[\"i32:39\"]],[\"invoke\",2052,0,\"test\",[\"i32:41\"]],[\"invoke\",2054,0,\"test\",[\"i32:43\"]],[\"invoke\",2055,0,\"test\",[\"i32:44\"]],[\"invoke\",2057,0,\"test\",[\"i32:46\"]],[\"invoke\",2059,0,\"test\",[\"i32:48\"]],[\"invoke\",2060,0,\"test\",[\"i32:49\"]],[\"invoke\",2062,0,\"test\",[\"i32:51\"]],[\"invoke\",2064,0,\"test\",[\"i32:53\"]],[\"invoke\",2065,0,\"test\",[\"i32:54\"]],[\"invoke\",2067,0,\"test\",[\"i32:56\"]],[\"invoke\",2069,0,\"test\",[\"i32:58\"]],[\"invoke\",2070,0,\"test\",[\"i32:59\"]],[\"invoke\",2072,0,\"test\",[\"i32:61\"]],[\"invoke\",2074,0,\"test\",[\"i32:63\"]],[\"module\",2076,90],[\"invoke\",2105,0,\"test\",[\"i32:0\"]],[\"invoke\",2106,0,\"test\",[\"i32:1\"]],[\"invoke\",2108,0,\"test\",[\"i32:3\"]],[\"invoke\",2110,0,\"test\",[\"i32:5\"]],[\"invoke\",2111,0,\"test\",[\"i32:6\"]],[\"invoke\",2113,0,\"test\",[\"i32:8\"]],[\"invoke\",2115,0,\"test\",[\"i32:10\"]],[\"invoke\",2116,0,\"test\",[\"i32:11\"]],[\"invoke\",2118,0,\"test\",[\"i32:13\"]],[\"invoke\",2120,0,\"test\",[\"i32:15\"]],[\"module\",2122,91],[\"file\",\"table_set.wast\"],[\"module\",1,92],[\"invoke\",29,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",30,0,\"set-externref\",[\"i32:0\",\"externref:1\"]],[\"invoke\",31,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",32,0,\"set-externref\",[\"i32:0\",\"externref:null\"]],[\"invoke\",33,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",35,0,\"get-funcref\",[\"i32:0\"]],[\"invoke\",36,0,\"set-funcref-from\",[\"i32:0\",\"i32:1\"]],[\"invoke\",37,0,\"is_null-funcref\",[\"i32:0\"]],[\"invoke\",38,0,\"set-funcref\",[\"i32:0\",\"funcref:null\"]],[\"invoke\",39,0,\"get-funcref\",[\"i32:0\"]],[\"invoke\",41,0,\"set-externref\",[\"i32:2\",\"externref:null\"]],[\"invoke\",42,0,\"set-funcref\",[\"i32:3\",\"funcref:null\"]],[\"invoke\",43,0,\"set-externref\",[\"i32:4294967295\",\"externref:null\"]],[\"invoke\",44,0,\"set-funcref\",[\"i32:4294967295\",\"funcref:null\"]],[\"invoke\",46,0,\"set-externref\",[\"i32:2\",\"externref:0\"]],[\"invoke\",47,0,\"set-funcref-from\",[\"i32:3\",\"i32:1\"]],[\"invoke\",48,0,\"set-externref\",[\"i32:4294967295\",\"externref:0\"]],[\"invoke\",49,0,\"set-funcref-from\",[\"i32:4294967295\",\"i32:1\"]],[\"file\",\"table_size.wast\"],[\"module\",1,93],[\"invoke\",26,0,\"size-t0\",[]],[\"invoke\",27,0,\"grow-t0\",[\"i32:1\"]],[\"invoke\",28,0,\"size-t0\",[]],[\"invoke\",29,0,\"grow-t0\",[\"i32:4\"]],[\"invoke\",30,0,\"size-t0\",[]],[\"invoke\",31,0,\"grow-t0\",[\"i32:0\"]],[\"invoke\",32,0,\"size-t0\",[]],[\"invoke\",34,0,\"size-t1\",[]],[\"invoke\",35,0,\"grow-t1\",[\"i32:1\"]],[\"invoke\",36,0,\"size-t1\",[]],[\"invoke\",37,0,\"grow-t1\",[\"i32:4\"]],[\"invoke\",38,0,\"size-t1\",[]],[\"invoke\",39,0,\"grow-t1\",[\"i32:0\"]],[\"invoke\",40,0,\"size-t1\",[]],[\"invoke\",42,0,\"size-t2\",[]],[\"invoke\",43,0,\"grow-t2\",[\"i32:3\"]],[\"invoke\",44,0,\"size-t2\",[]],[\"invoke\",45,0,\"grow-t2\",[\"i32:1\"]],[\"invoke\",46,0,\"size-t2\",[]],[\"invoke\",47,0,\"grow-t2\",[\"i32:0\"]],[\"invoke\",48,0,\"size-t2\",[]],[\"invoke\",49,0,\"grow-t2\",[\"i32:4\"]],[\"invoke\",50,0,\"size-t2\",[]],[\"invoke\",51,0,\"grow-t2\",[\"i32:1\"]],[\"invoke\",52,0,\"size-t2\",[]],[\"invoke\",54,0,\"size-t3\",[]],[\"invoke\",55,0,\"grow-t3\",[\"i32:1\"]],[\"invoke\",56,0,\"size-t3\",[]],[\"invoke\",57,0,\"grow-t3\",[\"i32:3\"]],[\"invoke\",58,0,\"size-t3\",[]],[\"invoke\",59,0,\"grow-t3\",[\"i32:0\"]],[\"invoke\",60,0,\"size-t3\",[]],[\"invoke\",61,0,\"grow-t3\",[\"i32:2\"]],[\"invoke\",62,0,\"size-t3\",[]],[\"invoke\",63,0,\"grow-t3\",[\"i32:1\"]],[\"invoke\",64,0,\"size-t3\",[]],[\"file\",\"elem.wast\"],[\"module\",4,94],[\"module\",80,95],[\"module\",90,96],[\"module\",101,97],[\"module\",120,98],[\"module\",127,98],[\"module\",134,99],[\"invoke\",148,0,\"call-7\",[]],[\"invoke\",149,0,\"call-9\",[]],[\"module\",153,100],[\"invoke\",167,0,\"call-7\",[]],[\"invoke\",168,0,\"call-9\",[]],[\"module\",182,101],[\"module\",193,102],[\"module\",202,103],[\"module\",207,104],[\"instantiate\",239,105],[\"instantiate\",248,106],[\"instantiate\",257,107],[\"instantiate\",266,108],[\"instantiate\",273,109],[\"instantiate\",290,110],[\"instantiate\",307,111],[\"instantiate\",324,112],[\"module\",342,113],[\"invoke\",350,0,\"init\",[]],[\"module\",352,114],[\"invoke\",360,0,\"init\",[]],[\"module\",537,115],[\"invoke\",548,0,\"call-overwritten\",[]],[\"module\",565,116,\"$module1\"],[\"register\",\"module1\",\"$module1\"],[\"invoke\",585,\"$module1\",\"call-7\",[]],[\"invoke\",586,\"$module1\",\"call-8\",[]],[\"invoke\",587,\"$module1\",\"call-9\",[]],[\"module\",589,117,\"$module2\"],[\"invoke\",598,\"$module1\",\"call-7\",[]],[\"invoke\",599,\"$module1\",\"call-8\",[]],[\"invoke\",600,\"$module1\",\"call-9\",[]],[\"module\",602,118,\"$module3\"],[\"invoke\",611,\"$module1\",\"call-7\",[]],[\"invoke\",612,\"$module1\",\"call-8\",[]],[\"invoke\",613,\"$module1\",\"call-9\",[]],[\"module\",646,119,\"$m\"],[\"register\",\"exporter\",\"$m\"],[\"invoke\",655,\"$m\",\"get\",[\"i32:0\"]],[\"invoke\",656,\"$m\",\"get\",[\"i32:1\"]],[\"invoke\",658,\"$m\",\"set\",[\"i32:0\",\"externref:42\"]],[\"invoke\",659,\"$m\",\"set\",[\"i32:1\",\"externref:137\"]],[\"invoke\",661,\"$m\",\"get\",[\"i32:0\"]],[\"invoke\",662,\"$m\",\"get\",[\"i32:1\"]],[\"module\",664,120],[\"invoke\",668,\"$m\",\"get\",[\"i32:0\"]],[\"invoke\",669,\"$m\",\"get\",[\"i32:1\"]],[\"module\",673,121,\"$module4\"],[\"register\",\"module4\",\"$module4\"],[\"module\",682,122],[\"invoke\",692,0,\"call_imported_elem\",[]],[\"file\",\"ref_func.wast\"],[\"module\",1,123],[\"register\",\"M\"],[\"module\",6,124],[\"invoke\",56,0,\"is_null-f\",[]],[\"invoke\",57,0,\"is_null-g\",[]],[\"invoke\",58,0,\"is_null-v\",[]],[\"invoke\",60,0,\"call-f\",[\"i32:4\"]],[\"invoke\",61,0,\"call-g\",[\"i32:4\"]],[\"invoke\",62,0,\"call-v\",[\"i32:4\"]],[\"invoke\",63,0,\"set-g\",[]],[\"invoke\",64,0,\"call-v\",[\"i32:4\"]],[\"invoke\",65,0,\"set-f\",[]],[\"invoke\",66,0,\"call-v\",[\"i32:4\"]],[\"module\",80,125],[\"file\",\"ref_is_null.wast\"],[\"module\",1,126],[\"invoke\",30,0,\"funcref\",[\"funcref:null\"]],[\"invoke\",31,0,\"externref\",[\"externref:null\"]],[\"invoke\",33,0,\"externref\",[\"externref:1\"]],[\"invoke\",35,0,\"init\",[\"externref:0\"]],[\"invoke\",37,0,\"funcref-elem\",[\"i32:0\"]],[\"invoke\",38,0,\"externref-elem\",[\"i32:0\"]],[\"invoke\",40,0,\"funcref-elem\",[\"i32:1\"]],[\"invoke\",41,0,\"externref-elem\",[\"i32:1\"]],[\"invoke\",43,0,\"deinit\",[]],[\"invoke\",45,0,\"funcref-elem\",[\"i32:0\"]],[\"invoke\",46,0,\"externref-elem\",[\"i32:0\"]],[\"invoke\",48,0,\"funcref-elem\",[\"i32:1\"]],[\"invoke\",49,0,\"externref-elem\",[\"i32:1\"]],[\"file\",\"ref_null.wast\"],[\"module\",1,127],[\"invoke\",9,0,\"externref\",[]],[\"invoke\",10,0,\"funcref\",[]],[\"file\",\"exports.wast\"],[\"module\",3,128],[\"module\",4,129],[\"module\",5,130],[\"module\",7,128],[\"module\",8,131],[\"module\",9,132],[\"module\",10,128],[\"module\",11,128],[\"module\",12,128],[\"module\",13,128],[\"module\",14,128],[\"module\",16,133,\"$Func\"],[\"invoke\",22,0,\"e\",[\"i32:42\"]],[\"invoke\",23,\"$Func\",\"e\",[\"i32:42\"]],[\"module\",24,134],[\"module\",25,134,\"$Other1\"],[\"invoke\",26,\"$Func\",\"e\",[\"i32:42\"]],[\"module\",28,135],[\"invoke\",34,0,\"a\",[]],[\"invoke\",35,0,\"b\",[]],[\"invoke\",36,0,\"c\",[]],[\"module\",74,136],[\"module\",75,137],[\"module\",76,138],[\"module\",78,136],[\"module\",79,136],[\"module\",80,136],[\"module\",81,136],[\"module\",82,136],[\"module\",83,136],[\"module\",85,139,\"$Global\"],[\"get\",89,0,\"e\",[]],[\"get\",90,\"$Global\",\"e\",[]],[\"module\",91,134],[\"module\",92,134,\"$Other2\"],[\"get\",93,\"$Global\",\"e\",[]],[\"module\",131,140],[\"module\",132,141],[\"module\",133,142],[\"module\",135,140],[\"module\",136,143],[\"module\",137,140],[\"module\",138,143],[\"module\",139,140],[\"module\",140,143],[\"module\",141,140],[\"module\",142,143],[\"module\",143,140],[\"module\",144,143],[\"module\",145,140],[\"module\",146,143],[\"module\",186,144],[\"module\",187,145],[\"module\",191,144],[\"module\",192,146],[\"module\",193,144],[\"module\",194,146],[\"module\",195,144],[\"module\",196,146],[\"module\",197,144],[\"module\",198,146],[\"module\",199,144],[\"module\",200,146],[\"module\",201,144],[\"module\",202,146],[\"file\",\"linking.wast\"],[\"module\",3,147,\"$Mf\"],[\"register\",\"Mf\",\"$Mf\"],[\"module\",9,148,\"$Nf\"],[\"invoke\",17,\"$Mf\",\"call\",[]],[\"invoke\",18,\"$Nf\",\"Mf.call\",[]],[\"invoke\",19,\"$Nf\",\"call\",[]],[\"invoke\",20,\"$Nf\",\"call Mf.call\",[]],[\"module\",22,149],[\"register\",\"reexport_f\"],[\"instantiate\",28,150],[\"instantiate\",32,151],[\"module\",39,152,\"$Mg\"],[\"register\",\"Mg\",\"$Mg\"],[\"module\",50,153,\"$Ng\"],[\"get\",67,\"$Mg\",\"glob\",[]],[\"get\",68,\"$Ng\",\"Mg.glob\",[]],[\"get\",69,\"$Ng\",\"glob\",[]],[\"invoke\",70,\"$Mg\",\"get\",[]],[\"invoke\",71,\"$Ng\",\"Mg.get\",[]],[\"invoke\",72,\"$Ng\",\"get\",[]],[\"get\",74,\"$Mg\",\"mut_glob\",[]],[\"get\",75,\"$Ng\",\"Mg.mut_glob\",[]],[\"invoke\",76,\"$Mg\",\"get_mut\",[]],[\"invoke\",77,\"$Ng\",\"Mg.get_mut\",[]],[\"invoke\",79,\"$Mg\",\"set_mut\",[\"i32:241\"]],[\"get\",80,\"$Mg\",\"mut_glob\",[]],[\"get\",81,\"$Ng\",\"Mg.mut_glob\",[]],[\"invoke\",82,\"$Mg\",\"get_mut\",[]],[\"invoke\",83,\"$Ng\",\"Mg.get_mut\",[]],[\"instantiate\",87,154],[\"instantiate\",91,155],[\"module\",96,156,\"$Mref_ex\"],[\"register\",\"Mref_ex\",\"$Mref_ex\"],[\"module\",104,157,\"$Mref_im\"],[\"instantiate\",113,158],[\"instantiate\",117,159],[\"instantiate\",123,160],[\"instantiate\",127,161],[\"module\",134,162,\"$Mt\"],[\"register\",\"Mt\",\"$Mt\"],[\"module\",149,163,\"$Nt\"],[\"invoke\",168,\"$Mt\",\"call\",[\"i32:2\"]],[\"invoke\",169,\"$Nt\",\"Mt.call\",[\"i32:2\"]],[\"invoke\",170,\"$Nt\",\"call\",[\"i32:2\"]],[\"invoke\",171,\"$Nt\",\"call Mt.call\",[\"i32:2\"]],[\"invoke\",173,\"$Mt\",\"call\",[\"i32:1\"]],[\"invoke\",174,\"$Nt\",\"Mt.call\",[\"i32:1\"]],[\"invoke\",175,\"$Nt\",\"call\",[\"i32:1\"]],[\"invoke\",176,\"$Nt\",\"call Mt.call\",[\"i32:1\"]],[\"invoke\",178,\"$Mt\",\"call\",[\"i32:0\"]],[\"invoke\",179,\"$Nt\",\"Mt.call\",[\"i32:0\"]],[\"invoke\",180,\"$Nt\",\"call\",[\"i32:0\"]],[\"invoke\",181,\"$Nt\",\"call Mt.call\",[\"i32:0\"]],[\"invoke\",183,\"$Mt\",\"call\",[\"i32:20\"]],[\"invoke\",184,\"$Nt\",\"Mt.call\",[\"i32:20\"]],[\"invoke\",185,\"$Nt\",\"call\",[\"i32:7\"]],[\"invoke\",186,\"$Nt\",\"call Mt.call\",[\"i32:20\"]],[\"invoke\",188,\"$Nt\",\"call\",[\"i32:3\"]],[\"invoke\",189,\"$Nt\",\"call\",[\"i32:4\"]],[\"module\",191,164,\"$Ot\"],[\"invoke\",204,\"$Mt\",\"call\",[\"i32:3\"]],[\"invoke\",205,\"$Nt\",\"Mt.call\",[\"i32:3\"]],[\"invoke\",206,\"$Nt\",\"call Mt.call\",[\"i32:3\"]],[\"invoke\",207,\"$Ot\",\"call\",[\"i32:3\"]],[\"invoke\",209,\"$Mt\",\"call\",[\"i32:2\"]],[\"invoke\",210,\"$Nt\",\"Mt.call\",[\"i32:2\"]],[\"invoke\",211,\"$Nt\",\"call\",[\"i32:2\"]],[\"invoke\",212,\"$Nt\",\"call Mt.call\",[\"i32:2\"]],[\"invoke\",213,\"$Ot\",\"call\",[\"i32:2\"]],[\"invoke\",215,\"$Mt\",\"call\",[\"i32:1\"]],[\"invoke\",216,\"$Nt\",\"Mt.call\",[\"i32:1\"]],[\"invoke\",217,\"$Nt\",\"call\",[\"i32:1\"]],[\"invoke\",218,\"$Nt\",\"call Mt.call\",[\"i32:1\"]],[\"invoke\",219,\"$Ot\",\"call\",[\"i32:1\"]],[\"invoke\",221,\"$Mt\",\"call\",[\"i32:0\"]],[\"invoke\",222,\"$Nt\",\"Mt.call\",[\"i32:0\"]],[\"invoke\",223,\"$Nt\",\"call\",[\"i32:0\"]],[\"invoke\",224,\"$Nt\",\"call Mt.call\",[\"i32:0\"]],[\"invoke\",225,\"$Ot\",\"call\",[\"i32:0\"]],[\"invoke\",227,\"$Ot\",\"call\",[\"i32:20\"]],[\"module\",229,165],[\"module\",235,166,\"$G1\"],[\"register\",\"G1\",\"$G1\"],[\"module\",237,167,\"$G2\"],[\"get\",241,\"$G2\",\"g\",[]],[\"instantiate\",244,168],[\"instantiate\",253,169],[\"invoke\",262,\"$Mt\",\"call\",[\"i32:7\"]],[\"instantiate\",267,170],[\"invoke\",275,\"$Mt\",\"call\",[\"i32:7\"]],[\"invoke\",276,\"$Mt\",\"call\",[\"i32:8\"]],[\"instantiate\",279,171],[\"invoke\",288,\"$Mt\",\"call\",[\"i32:7\"]],[\"module\",291,172,\"$Mtable_ex\"],[\"register\",\"Mtable_ex\",\"$Mtable_ex\"],[\"module\",297,173],[\"instantiate\",303,174],[\"instantiate\",307,175],[\"module\",314,176,\"$Mm\"],[\"register\",\"Mm\",\"$Mm\"],[\"module\",324,177,\"$Nm\"],[\"invoke\",336,\"$Mm\",\"load\",[\"i32:12\"]],[\"invoke\",337,\"$Nm\",\"Mm.load\",[\"i32:12\"]],[\"invoke\",338,\"$Nm\",\"load\",[\"i32:12\"]],[\"module\",340,178,\"$Om\"],[\"invoke\",349,\"$Mm\",\"load\",[\"i32:12\"]],[\"invoke\",350,\"$Nm\",\"Mm.load\",[\"i32:12\"]],[\"invoke\",351,\"$Nm\",\"load\",[\"i32:12\"]],[\"invoke\",352,\"$Om\",\"load\",[\"i32:12\"]],[\"module\",354,179],[\"instantiate\",360,180],[\"module\",367,181,\"$Pm\"],[\"invoke\",375,\"$Pm\",\"grow\",[\"i32:0\"]],[\"invoke\",376,\"$Pm\",\"grow\",[\"i32:2\"]],[\"invoke\",377,\"$Pm\",\"grow\",[\"i32:0\"]],[\"invoke\",378,\"$Pm\",\"grow\",[\"i32:1\"]],[\"invoke\",379,\"$Pm\",\"grow\",[\"i32:1\"]],[\"invoke\",380,\"$Pm\",\"grow\",[\"i32:0\"]],[\"invoke\",381,\"$Pm\",\"grow\",[\"i32:1\"]],[\"invoke\",382,\"$Pm\",\"grow\",[\"i32:0\"]],[\"instantiate\",385,182],[\"invoke\",393,\"$Mm\",\"load\",[\"i32:0\"]],[\"instantiate\",398,183],[\"invoke\",406,\"$Mm\",\"load\",[\"i32:0\"]],[\"invoke\",407,\"$Mm\",\"load\",[\"i32:327670\"]],[\"instantiate\",410,184],[\"invoke\",419,\"$Mm\",\"load\",[\"i32:0\"]],[\"module\",422,185,\"$Ms\"],[\"register\",\"Ms\",\"$Ms\"],[\"instantiate\",436,186],[\"invoke\",452,\"$Ms\",\"get memory[0]\",[]],[\"invoke\",453,\"$Ms\",\"get table[0]\",[]]]"; diff --git a/tests/corpus/webassembly-spec-table/main.mjs b/tests/corpus/webassembly-spec-table/main.mjs new file mode 100644 index 000000000..38c7c67d5 --- /dev/null +++ b/tests/corpus/webassembly-spec-table/main.mjs @@ -0,0 +1,5 @@ +// Executes WebAssembly spec tests (13 files); see tests/wasm-spec/runner.mjs. +import { run } from "../../wasm-spec/runner.mjs"; +import { modules, script } from "./data.mjs"; + +run(modules, script); diff --git a/tests/corpus/webassembly-typed.ts b/tests/corpus/webassembly-typed.ts new file mode 100644 index 000000000..967996135 --- /dev/null +++ b/tests/corpus/webassembly-typed.ts @@ -0,0 +1,51 @@ +// The WebAssembly API from TypeScript: lib.dom's types (declared by +// scriptc.d.ts), exports read through casts, and the error classes in +// catch clauses. The module text is tests/wasm-spec/corpus/api.wat. +const bytes: Uint8Array = Buffer.from("AGFzbQEAAAABLwlgAX8Bf2ACf38Bf2ABfwBgAABgAAF/YAJ+fgF+YAJ/fwJ/f2ABfQF9YAN/f38AAi0EA2VudgNsb2cAAgNlbnYEZmFpbAAAA2VudgRiYXNlA38AA2VudgNiaWcDfgADEhEAAAMBAQQFBgcAAAQAAAAICAQFAXABAggFBAEBAQQGFwN/AUEAC3wARAAAAAAAAApAC34AIwELB5kBEwZtZW1vcnkCAAV0YWJsZQEAB2NvdW50ZXIDAgJwaQMDBGJpZzIDBANhZGQABQVhcHBseQAGBGJ1bXAABwVtdWw2NAAIBmRpdm1vZAAJBm5hcnJvdwAKBnN0cmxlbgALBGdyb3cADAVwYWdlcwANCGNhbGxGYWlsAA4EdHJhcAAPB3JlY3Vyc2UAEARmaWxsABEEY29weQASCAEECQgBAEEACwICAwqHAhEHACAAQQJsCwcAIAAgAGwLBgAjABAACwcAIAAgAWoLCQAgASAAEQAACwsAIwJBAWokAiMCCwcAIAAgAX4LDAAgACABbSAAIAFvCwQAIAALIAEBfwJAA0AgACABai0AAEUNASABQQFqIQEMAAsLIAELBgAgAEAACwQAPwALCQAgABABQQFqC1kAAkACQAJAAkACQAJAAkAgAA4GAAECAwQFBgsAC0EBQQBuDwtB/////wcoAgAPC0EBQQJBABEBAA8LQQFBBxEAAA8LRAAAAAAAAPh/qg8LQYCAgIB4QX9tCwwAIABBAWoQEEEBagsLACAAIAEgAvwLAAsMACAAIAEgAvwKAAALCw4BAEEQCwhzY3JpcHRjAA==", "base64"); + +const logs: string[] = []; +// lib.dom's ImportValue has no bigint; Node accepts one for an i64 global. +const imports = { + env: { + log: (v: number): void => { + logs.push(`start ${v}`); + }, + fail: (v: number): number => v + 1, + base: 7, + big: 1n, + }, +} as unknown as WebAssembly.Imports; + +async function main(): Promise { + const { module, instance } = await WebAssembly.instantiate(bytes, imports); + console.log(logs.join(","), module instanceof WebAssembly.Module); + const exports = instance.exports; + const add = exports.add as (a: number, b: number) => number; + const mul64 = exports.mul64 as (a: bigint, b: bigint) => bigint; + const strlen = exports.strlen as (p: number) => number; + const trap = exports.trap as (kind: number) => number; + console.log(add(20, 22), mul64(3n, 4n), strlen(16)); + const memory = exports.memory as WebAssembly.Memory; + const text = new Uint8Array(memory.buffer, 16, strlen(16)); + console.log(new TextDecoder().decode(text), memory.buffer.byteLength); + const counter = exports.counter as WebAssembly.Global; + counter.value = 41; + console.log((exports.bump as () => number)(), counter.value); + for (let kind = 0; kind < 3; kind++) { + try { + trap(kind); + } catch (e) { + if (e instanceof WebAssembly.RuntimeError) console.log(`RuntimeError: ${e.message}`); + else throw e; + } + } + const second = new WebAssembly.Instance(module, imports); + console.log((second.exports.add as (a: number, b: number) => number)(1, 2), WebAssembly.validate(bytes)); + try { + await WebAssembly.compile(new Uint8Array([0, 97, 115, 109])); + } catch (e) { + console.log(e instanceof WebAssembly.CompileError); + } +} + +await main(); diff --git a/tests/corpus/webassembly-worker.ts b/tests/corpus/webassembly-worker.ts new file mode 100644 index 000000000..02bdf22c6 --- /dev/null +++ b/tests/corpus/webassembly-worker.ts @@ -0,0 +1,68 @@ +import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads"; + +// The codemode shape: the main thread compiles a module once and sends the +// WebAssembly.Module to a fresh Worker per job, through workerData and +// through postMessage; each worker instantiates it with its own imports, +// runs it, and reports back. Traps in a worker (out-of-bounds memory and +// stack exhaustion, both caught by the per-thread fault handling) stay in +// that worker. The module text is tests/wasm-spec/corpus/api.wat. +const bytes = Buffer.from("AGFzbQEAAAABLwlgAX8Bf2ACf38Bf2ABfwBgAABgAAF/YAJ+fgF+YAJ/fwJ/f2ABfQF9YAN/f38AAi0EA2VudgNsb2cAAgNlbnYEZmFpbAAAA2VudgRiYXNlA38AA2VudgNiaWcDfgADEhEAAAMBAQQFBgcAAAQAAAAICAQFAXABAggFBAEBAQQGFwN/AUEAC3wARAAAAAAAAApAC34AIwELB5kBEwZtZW1vcnkCAAV0YWJsZQEAB2NvdW50ZXIDAgJwaQMDBGJpZzIDBANhZGQABQVhcHBseQAGBGJ1bXAABwVtdWw2NAAIBmRpdm1vZAAJBm5hcnJvdwAKBnN0cmxlbgALBGdyb3cADAVwYWdlcwANCGNhbGxGYWlsAA4EdHJhcAAPB3JlY3Vyc2UAEARmaWxsABEEY29weQASCAEECQgBAEEACwICAwqHAhEHACAAQQJsCwcAIAAgAGwLBgAjABAACwcAIAAgAWoLCQAgASAAEQAACwsAIwJBAWokAiMCCwcAIAAgAX4LDAAgACABbSAAIAFvCwQAIAALIAEBfwJAA0AgACABai0AAEUNASABQQFqIQEMAAsLIAELBgAgAEAACwQAPwALCQAgABABQQFqC1kAAkACQAJAAkACQAJAAkAgAA4GAAECAwQFBgsAC0EBQQBuDwtB/////wcoAgAPC0EBQQJBABEBAA8LQQFBBxEAAA8LRAAAAAAAAPh/qg8LQYCAgIB4QX9tCwwAIABBAWoQEEEBagsLACAAIAEgAvwLAAsMACAAIAEgAvwKAAALCw4BAEEQCwhzY3JpcHRjAA==", "base64"); + +interface Job { + module: WebAssembly.Module; + input: number; +} + +function run(module: WebAssembly.Module, input: number): string { + const seen: number[] = []; + const imports = { + env: { + log: (v: number): void => { + seen.push(v); + }, + fail: (v: number): number => v * 2, + base: input, + big: BigInt(input), + }, + } as unknown as WebAssembly.Imports; + const instance = new WebAssembly.Instance(module, imports); + const exports = instance.exports; + const apply = exports.apply as (fn: number, v: number) => number; + const callFail = exports.callFail as (v: number) => number; + const trap = exports.trap as (kind: number) => number; + const recurse = exports.recurse as (v: number) => number; + const traps: string[] = []; + for (const attempt of [() => trap(2), () => recurse(0), () => trap(1)]) { + try { + attempt(); + } catch (e) { + traps.push(e instanceof Error ? `${e.name}: ${e.message}` : String(e)); + } + } + return `job ${input}: start ${seen.join(",")} apply ${apply(1, input + 3)} callFail ${callFail(input)} traps ${traps.join(" | ")}`; +} + +if (isMainThread) { + const module = await WebAssembly.compile(bytes); + console.log(run(module, 0)); + for (let input = 1; input <= 3; input++) { + const line = await new Promise((resolve, reject) => { + const worker = new Worker(new URL(import.meta.url), { workerData: { module, input } satisfies Job }); + worker.once("message", (message: string) => resolve(message)); + worker.once("error", reject); + }); + console.log(line); + } + const worker = new Worker(new URL(import.meta.url), { workerData: null }); + const reply = new Promise((resolve) => worker.once("message", (message: string) => resolve(message))); + worker.postMessage({ module, input: 9 } satisfies Job); + console.log(await reply); + console.log("main still works:", run(module, 4).slice(0, 18)); +} else if (workerData !== null) { + const job = workerData as Job; + parentPort!.postMessage(`${job.module instanceof WebAssembly.Module} ${run(job.module, job.input)}`); +} else { + parentPort!.once("message", (job: Job) => { + parentPort!.postMessage(run(job.module, job.input)); + }); +} diff --git a/tests/diagnostics/webassembly-fences.ts b/tests/diagnostics/webassembly-fences.ts index 56b2991de..ffa2f96e3 100644 --- a/tests/diagnostics/webassembly-fences.ts +++ b/tests/diagnostics/webassembly-fences.ts @@ -1,30 +1,18 @@ -// No WebAssembly module compiles to native code yet: every reached use of -// the API refuses at its site, in each spelling, while declarations that -// only mention its types compile. -interface LoaderOptions { - wasm?: BufferSource | WebAssembly.Module; - imports?: WebAssembly.Imports; -} - -async function load(options: LoaderOptions, bytes: Uint8Array): Promise { - console.log(WebAssembly.validate(bytes)); +// The parts of the WebAssembly API scriptc does not implement yet refuse at +// each reached use, in each spelling. compile, instantiate, validate, +// Module, Instance and the error classes compile (tests/corpus/webassembly-*). +async function load(bytes: Uint8Array): Promise { const module = await WebAssembly.compile(bytes); - const { instance } = await WebAssembly.instantiate(bytes, options.imports); - console.log(instance instanceof WebAssembly.Instance, module); - const direct = new WebAssembly.Instance(new WebAssembly.Module(bytes)); - console.log(direct.exports); const memory = new WebAssembly.Memory({ initial: 1 }); - console.log(memory.buffer.byteLength); - const api = globalThis.WebAssembly; - console.log(api); + const table = new WebAssembly.Table({ initial: 1, element: "anyfunc" }); + const global = new WebAssembly.Global({ value: "i32", mutable: true }, 1); + console.log(memory.buffer.byteLength, table.length, global.value); console.log(WebAssembly.Module.imports(module).length); + console.log(WebAssembly.Module.customSections(module, "name").length); + const streamed = await WebAssembly.instantiateStreaming(fetch("https://example.com/x.wasm")); + console.log(streamed.instance); + const Ctor = WebAssembly.Module; + console.log(Ctor); } -// pi's codemode spelling: the global object viewed through a cast. -interface WebAssemblyGlobal { - compile(bytes: Uint8Array): Promise; -} -const { WebAssembly: viewed } = globalThis as unknown as { WebAssembly: WebAssemblyGlobal }; -console.log(typeof viewed.compile); - -await load({}, new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0])); +await load(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0])); diff --git a/tests/harness/__snapshots__/coverage-wasm.txt b/tests/harness/__snapshots__/coverage-wasm.txt index 5b5bea36a..0a56ccd1d 100644 --- a/tests/harness/__snapshots__/coverage-wasm.txt +++ b/tests/harness/__snapshots__/coverage-wasm.txt @@ -1,13 +1,13 @@ scriptc coverage tests/coverage-fixtures/wasm/main.ts statements analyzed 8 - compile statically 6 (75%) + compile statically 8 (100%) in dynamic tier 2 (operate on values typed only at runtime; --explain-dynamic lists them) npm package compilation: wasm-fixture-pkg static - WebAssembly modules: (found at build time; none compile to native code yet) + WebAssembly modules: (found at build time; valid ones compile to native code) inline module 39 bytes valid 1 function, 0 imports, 1 export found: inline at tests/coverage-fixtures/wasm/glue.js:5 @@ -22,10 +22,4 @@ scriptc coverage tests/coverage-fixtures/wasm/main.ts features: simd found: configured by tests/coverage-fixtures/wasm/package.json - in unreached code (never lowered — cannot fail a build) - ×1 SC2004 uses of 'instance' inherit the blocker on its declaration - at tests/coverage-fixtures/wasm/glue.js:17:10 - hint: the declaration of 'instance' did not compile — fix the diagnostic reported there and these sites clear with it - ×1 SC2020 'WebAssembly.instantiate' is not supported yet: scriptc does not compile WebAssembly modules to native code yet - at tests/coverage-fixtures/wasm/glue.js:16:30 - hint: WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations) \ No newline at end of file + fully static — all analyzed statements compile to native code. \ No newline at end of file diff --git a/tests/harness/__snapshots__/webassembly-fences.ts.txt b/tests/harness/__snapshots__/webassembly-fences.ts.txt index da38a2c57..f4a1eeae1 100644 --- a/tests/harness/__snapshots__/webassembly-fences.ts.txt +++ b/tests/harness/__snapshots__/webassembly-fences.ts.txt @@ -1,98 +1,71 @@ -webassembly-fences.ts:10:15 - error SC2020: 'WebAssembly.validate' is not supported yet: scriptc does not compile WebAssembly modules to native code yet +webassembly-fences.ts:6:22 - error SC2020: 'new WebAssembly.Memory' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API - 9 | async function load(options: LoaderOptions, bytes: Uint8Array): Promise { - 10 | console.log(WebAssembly.validate(bytes)); - | ^~~~~~~~~~~~~~~~~~~~ - 11 | const module = await WebAssembly.compile(bytes); + 5 | const module = await WebAssembly.compile(bytes); + 6 | const memory = new WebAssembly.Memory({ initial: 1 }); + | ^~~~~~~~~~~~~~~~~~ + 7 | const table = new WebAssembly.Table({ initial: 1, element: "anyfunc" }); - hint: WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations) + hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) -webassembly-fences.ts:11:24 - error SC2020: 'WebAssembly.compile' is not supported yet: scriptc does not compile WebAssembly modules to native code yet +webassembly-fences.ts:7:21 - error SC2020: 'new WebAssembly.Table' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API - 10 | console.log(WebAssembly.validate(bytes)); - 11 | const module = await WebAssembly.compile(bytes); - | ^~~~~~~~~~~~~~~~~~~ - 12 | const { instance } = await WebAssembly.instantiate(bytes, options.imports); + 6 | const memory = new WebAssembly.Memory({ initial: 1 }); + 7 | const table = new WebAssembly.Table({ initial: 1, element: "anyfunc" }); + | ^~~~~~~~~~~~~~~~~ + 8 | const global = new WebAssembly.Global({ value: "i32", mutable: true }, 1); - hint: WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations) + hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) -webassembly-fences.ts:12:30 - error SC2020: 'WebAssembly.instantiate' is not supported yet: scriptc does not compile WebAssembly modules to native code yet +webassembly-fences.ts:8:22 - error SC2020: 'new WebAssembly.Global' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API - 11 | const module = await WebAssembly.compile(bytes); - 12 | const { instance } = await WebAssembly.instantiate(bytes, options.imports); - | ^~~~~~~~~~~~~~~~~~~~~~~ - 13 | console.log(instance instanceof WebAssembly.Instance, module); + 7 | const table = new WebAssembly.Table({ initial: 1, element: "anyfunc" }); + 8 | const global = new WebAssembly.Global({ value: "i32", mutable: true }, 1); + | ^~~~~~~~~~~~~~~~~~ + 9 | console.log(memory.buffer.byteLength, table.length, global.value); - hint: WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations) + hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) -webassembly-fences.ts:13:35 - error SC2020: 'WebAssembly.Instance' is not supported yet: scriptc does not compile WebAssembly modules to native code yet +webassembly-fences.ts:9:15 - error SC2004: uses of 'memory' inherit the blocker on its declaration - 12 | const { instance } = await WebAssembly.instantiate(bytes, options.imports); - 13 | console.log(instance instanceof WebAssembly.Instance, module); - | ^~~~~~~~~~~~~~~~~~~~ - 14 | const direct = new WebAssembly.Instance(new WebAssembly.Module(bytes)); - - hint: WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations) - -webassembly-fences.ts:14:22 - error SC2020: 'new WebAssembly.Instance' is not supported yet: scriptc does not compile WebAssembly modules to native code yet - - 13 | console.log(instance instanceof WebAssembly.Instance, module); - 14 | const direct = new WebAssembly.Instance(new WebAssembly.Module(bytes)); - | ^~~~~~~~~~~~~~~~~~~~ - 15 | console.log(direct.exports); - - hint: WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations) - -webassembly-fences.ts:16:22 - error SC2020: 'new WebAssembly.Memory' is not supported yet: scriptc does not compile WebAssembly modules to native code yet - - 15 | console.log(direct.exports); - 16 | const memory = new WebAssembly.Memory({ initial: 1 }); - | ^~~~~~~~~~~~~~~~~~ - 17 | console.log(memory.buffer.byteLength); - - hint: WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations) - -webassembly-fences.ts:17:15 - error SC2004: uses of 'memory' inherit the blocker on its declaration - - 16 | const memory = new WebAssembly.Memory({ initial: 1 }); - 17 | console.log(memory.buffer.byteLength); + 8 | const global = new WebAssembly.Global({ value: "i32", mutable: true }, 1); + 9 | console.log(memory.buffer.byteLength, table.length, global.value); | ^~~~~~~~~~~~~~~~~~~~~~~~ - 18 | const api = globalThis.WebAssembly; + 10 | console.log(WebAssembly.Module.imports(module).length); hint: the declaration of 'memory' did not compile — fix the diagnostic reported there and these sites clear with it -webassembly-fences.ts:18:15 - error SC2020: 'globalThis.WebAssembly' is not supported yet: scriptc does not compile WebAssembly modules to native code yet +webassembly-fences.ts:10:15 - error SC2020: 'WebAssembly.Module.imports' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API - 17 | console.log(memory.buffer.byteLength); - 18 | const api = globalThis.WebAssembly; - | ^~~~~~~~~~~~~~~~~~~~~~ - 19 | console.log(api); - - hint: WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations) - -webassembly-fences.ts:19:15 - error SC2004: uses of 'api' inherit the blocker on its declaration - - 18 | const api = globalThis.WebAssembly; - 19 | console.log(api); - | ^~~ - 20 | console.log(WebAssembly.Module.imports(module).length); - - hint: the declaration of 'api' did not compile — fix the diagnostic reported there and these sites clear with it - -webassembly-fences.ts:20:15 - error SC2020: 'WebAssembly.Module.imports' is not supported yet: scriptc does not compile WebAssembly modules to native code yet - - 19 | console.log(api); - 20 | console.log(WebAssembly.Module.imports(module).length); + 9 | console.log(memory.buffer.byteLength, table.length, global.value); + 10 | console.log(WebAssembly.Module.imports(module).length); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ - 21 | } + 11 | console.log(WebAssembly.Module.customSections(module, "name").length); - hint: WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations) + hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) -webassembly-fences.ts:27:33 - error SC2020: 'globalThis.WebAssembly' is not supported yet: scriptc does not compile WebAssembly modules to native code yet +webassembly-fences.ts:11:15 - error SC2020: 'WebAssembly.Module.customSections' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API - 26 | } - 27 | const { WebAssembly: viewed } = globalThis as unknown as { WebAssembly: WebAssemblyGlobal }; - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 28 | console.log(typeof viewed.compile); + 10 | console.log(WebAssembly.Module.imports(module).length); + 11 | console.log(WebAssembly.Module.customSections(module, "name").length); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 12 | const streamed = await WebAssembly.instantiateStreaming(fetch("https://example.com/x.wasm")); - hint: WebAssembly support is planned as translation of each module whose bytes the build can see (an inline literal, or a file read from a path the compiler resolves) into native code; 'scriptc coverage' lists the modules this program would load (https://scriptc.dev/limitations) \ No newline at end of file + hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) + +webassembly-fences.ts:12:26 - error SC2020: 'WebAssembly.instantiateStreaming' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API + + 11 | console.log(WebAssembly.Module.customSections(module, "name").length); + 12 | const streamed = await WebAssembly.instantiateStreaming(fetch("https://example.com/x.wasm")); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 13 | console.log(streamed.instance); + + hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) + +webassembly-fences.ts:14:16 - error SC2020: 'WebAssembly.Module' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API + + 13 | console.log(streamed.instance); + 14 | const Ctor = WebAssembly.Module; + | ^~~~~~~~~~~~~~~~~~ + 15 | console.log(Ctor); + + hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) \ No newline at end of file diff --git a/tests/wasm-spec/corpus/api.wat b/tests/wasm-spec/corpus/api.wat new file mode 100644 index 000000000..353a8421c --- /dev/null +++ b/tests/wasm-spec/corpus/api.wat @@ -0,0 +1,52 @@ +(module + (import "env" "log" (func $log (param i32))) + (import "env" "fail" (func $fail (param i32) (result i32))) + (import "env" "base" (global $base i32)) + (import "env" "big" (global $big i64)) + (memory (export "memory") 1 4) + (table (export "table") 2 8 funcref) + (global $counter (export "counter") (mut i32) (i32.const 0)) + (global (export "pi") f64 (f64.const 3.25)) + (global (export "big2") i64 (global.get $big)) + (data (i32.const 16) "scriptc\00") + (elem (i32.const 0) $double $square) + (type $unop (func (param i32) (result i32))) + (type $binop (func (param i32 i32) (result i32))) + (func $double (type $unop) (i32.mul (local.get 0) (i32.const 2))) + (func $square (type $unop) (i32.mul (local.get 0) (local.get 0))) + (start $init) + (func $init (call $log (global.get $base))) + (func (export "add") (type $binop) (i32.add (local.get 0) (local.get 1))) + (func (export "apply") (param i32 i32) (result i32) + (call_indirect (type $unop) (local.get 1) (local.get 0))) + (func (export "bump") (result i32) + (global.set $counter (i32.add (global.get $counter) (i32.const 1))) + (global.get $counter)) + (func (export "mul64") (param i64 i64) (result i64) (i64.mul (local.get 0) (local.get 1))) + (func (export "divmod") (param i32 i32) (result i32 i32) + (i32.div_s (local.get 0) (local.get 1)) (i32.rem_s (local.get 0) (local.get 1))) + (func (export "narrow") (param f32) (result f32) (local.get 0)) + (func (export "strlen") (param $p i32) (result i32) (local $n i32) + (block $done (loop $next + (br_if $done (i32.eqz (i32.load8_u (i32.add (local.get $p) (local.get $n))))) + (local.set $n (i32.add (local.get $n) (i32.const 1))) + (br $next))) + (local.get $n)) + (func (export "grow") (param i32) (result i32) (memory.grow (local.get 0))) + (func (export "pages") (result i32) (memory.size)) + (func (export "callFail") (param i32) (result i32) (i32.add (call $fail (local.get 0)) (i32.const 1))) + (func (export "trap") (param i32) (result i32) + (block $b6 (block $b5 (block $b4 (block $b3 (block $b2 (block $b1 (block $b0 + (br_table $b0 $b1 $b2 $b3 $b4 $b5 $b6 (local.get 0))) + unreachable) + (return (i32.div_u (i32.const 1) (i32.const 0)))) + (return (i32.load (i32.const 0x7fffffff)))) + (return (call_indirect (type $binop) (i32.const 1) (i32.const 2) (i32.const 0)))) + (return (call_indirect (type $unop) (i32.const 1) (i32.const 7)))) + (return (i32.trunc_f64_s (f64.const nan)))) + (i32.div_s (i32.const 0x80000000) (i32.const -1))) + (func $rec (export "recurse") (param i32) (result i32) + (i32.add (call $rec (i32.add (local.get 0) (i32.const 1))) (i32.const 1))) + (func (export "fill") (param i32 i32 i32) (memory.fill (local.get 0) (local.get 1) (local.get 2))) + (func (export "copy") (param i32 i32 i32) (memory.copy (local.get 0) (local.get 1) (local.get 2))) +) diff --git a/tests/wasm-spec/corpus/linked.wat b/tests/wasm-spec/corpus/linked.wat new file mode 100644 index 000000000..28834b006 --- /dev/null +++ b/tests/wasm-spec/corpus/linked.wat @@ -0,0 +1,12 @@ +(module + (import "api" "memory" (memory 1)) + (import "api" "table" (table 2 funcref)) + (import "api" "counter" (global $c (mut i32))) + (import "api" "add" (func $add (param i32 i32) (result i32))) + (func (export "read") (param i32) (result i32) (i32.load8_u (local.get 0))) + (func (export "useTable") (param i32 i32) (result i32) + (call_indirect (param i32) (result i32) (local.get 1) (local.get 0))) + (func (export "setCounter") (param i32) (global.set $c (local.get 0))) + (func (export "add3") (param i32 i32 i32) (result i32) + (call $add (call $add (local.get 0) (local.get 1)) (local.get 2))) +) diff --git a/tests/wasm-spec/corpus/refs.wat b/tests/wasm-spec/corpus/refs.wat new file mode 100644 index 000000000..52516fa30 --- /dev/null +++ b/tests/wasm-spec/corpus/refs.wat @@ -0,0 +1,10 @@ +(module + (table $t (export "refs") 1 10 externref) + (global (export "slot") (mut externref) (ref.null extern)) + (func (export "keep") (param externref) (result externref) (local.get 0)) + (func (export "store") (param i32 externref) (table.set $t (local.get 0) (local.get 1))) + (func (export "load") (param i32) (result externref) (table.get $t (local.get 0))) + (func (export "isNull") (param externref) (result i32) (ref.is_null (local.get 0))) + (func (export "grow") (param externref i32) (result i32) (table.grow $t (local.get 0) (local.get 1))) + (func (export "size") (result i32) (table.size $t)) +) diff --git a/tests/wasm-spec/gen.mjs b/tests/wasm-spec/gen.mjs new file mode 100644 index 000000000..3019c56f5 --- /dev/null +++ b/tests/wasm-spec/gen.mjs @@ -0,0 +1,272 @@ +/* Regenerates the executed WebAssembly spec-test corpus programs + * (tests/corpus/webassembly-spec-/data.mjs): the binary modules and + * the commands of selected .wast files of the WebAssembly 2.0 core suite, + * which runner.mjs instantiates and invokes under Node and as a compiled + * binary. The differential harness compares the two outputs, so V8 is the + * oracle; the modules are inline base64 literals, which the build + * discovers and translates. + * + * node tests/wasm-spec/gen.mjs --wast2json /bin/wast2json \ + * --spec /test/core + * + * Left out: modules given as text, modules the decoder does not accept + * within the translatable feature level, modules that import a spectest + * memory or table (the Memory and Table constructors are not supported + * yet) and every command that targets them, and commands with v128 + * values. Also left out, because they test NaN payloads, which neither + * side preserves the way the other does: actions whose f32 or f64 + * arguments are NaNs other than the canonical quiet NaN (V8 and scriptc + * carry NaN payloads through JavaScript numbers differently), and + * float_exprs.wast's actions that pass a signaling NaN's bit pattern to + * arithmetic that must quiet it (LLVM may fold `x - 0.0` to `x`, leaving + * the payload; WebAssembly requires a quiet NaN). Files with more than + * MAX_ACTIONS actions keep an evenly spaced + * sample of them (every module and register command stays), which keeps + * the generated programs small. + * + * Commands are compact tuples (runner.mjs reads them): + * ["file", name] + * ["module", line, moduleIndex, name?] instantiate, make current + * ["instantiate", line, moduleIndex] assert_un{linkable,instantiable} + * ["register", as, name?] + * ["invoke" | "get", line, name | 0, field, args] args: "type:value" + * The suite's tests are Apache-2.0 licensed (WebAssembly Community + * Group). */ +import { execFileSync } from "node:child_process"; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { dirname, join } from "node:path"; +import { parseArgs } from "node:util"; +import { analyzeWasm } from "../../packages/compiler/dist/wasm/binary.js"; + +export const GROUPS = { + int: ["i32", "i64", "int_exprs", "int_literals", "conversions", "traps"], + float: [ + "f32", + "f64", + "f32_cmp", + "f64_cmp", + "f32_bitwise", + "f64_bitwise", + "float_exprs", + "float_literals", + "float_misc", + ], + control: [ + "block", + "br", + "br_if", + "br_table", + "call", + "call_indirect", + "fac", + "forward", + "func", + "func_ptrs", + "if", + "labels", + "loop", + "local_get", + "local_set", + "local_tee", + "nop", + "return", + "select", + "stack", + "switch", + "unreachable", + "unwind", + "left-to-right", + "global", + "start", + ], + memory: [ + "address", + "align", + "endianness", + "float_memory", + "load", + "store", + "memory", + "memory_grow", + "memory_redundancy", + "memory_size", + "memory_trap", + "bulk", + "memory_copy", + "memory_fill", + "memory_init", + "data", + ], + table: [ + "table_copy", + "table_fill", + "table_get", + "table_grow", + "table_init", + "table_set", + "table_size", + "elem", + "ref_func", + "ref_is_null", + "ref_null", + "exports", + "linking", + ], +}; + +const MAX_ACTIONS = 400; + +const { values } = parseArgs({ + options: { wast2json: { type: "string" }, spec: { type: "string" } }, +}); +const repo = join(dirname(new URL(import.meta.url).pathname), "../.."); + +function value(v) { + if (v.type === "v128") return null; + return `${v.type}:${v.value}`; +} + +/** Whether a "type:value" argument is a NaN other than the canonical + * quiet one. */ +function oddNaN(arg) { + const [type, text] = arg.split(":"); + if (type === "f32") { + const bits = Number(text); + return (bits & 0x7f800000) === 0x7f800000 && (bits & 0x7fffff) !== 0 && (bits & 0x7fffffff) !== 0x7fc00000; + } + if (type === "f64") { + const bits = BigInt(text); + const exp = 0x7ff0000000000000n; + const mantissa = bits & 0xfffffffffffffn; + return (bits & exp) === exp && mantissa !== 0n && (bits & 0x7fffffffffffffffn) !== 0x7ff8000000000000n; + } + return false; +} + +/** Whether a "type:value" integer argument is the bit pattern of a + * signaling NaN. */ +function signalingPattern(arg) { + const [type, text] = arg.split(":"); + if (type === "i32") { + const bits = Number(text) >>> 0; + return (bits & 0x7fc00000) === 0x7f800000 && (bits & 0x3fffff) !== 0; + } + if (type === "i64") { + const bits = BigInt.asUintN(64, BigInt(text)); + return (bits & 0x7ff8000000000000n) === 0x7ff0000000000000n && (bits & 0x7ffffffffffffn) !== 0n; + } + return false; +} + +/** Keeps every structural command and an evenly spaced sample of at most + * MAX_ACTIONS actions. */ +function sample(commands) { + const actions = commands.filter((c) => c[0] === "invoke" || c[0] === "get").length; + if (actions <= MAX_ACTIONS) return commands; + const step = actions / MAX_ACTIONS; + let seen = 0; + let next = 0; + return commands.filter((c) => { + if (c[0] !== "invoke" && c[0] !== "get") return true; + const keep = seen >= next; + seen++; + if (keep) next += step; + return keep; + }); +} + +for (const [group, names] of Object.entries(GROUPS)) { + const modules = []; + const moduleIndex = new Map(); + const commands = []; + for (const name of names) { + const dir = mkdtempSync(join(tmpdir(), "wasm-spec-")); + try { + execFileSync(values.wast2json, [join(values.spec, `${name}.wast`), "-o", join(dir, "x.json")], { + stdio: "pipe", + }); + const json = JSON.parse(readFileSync(join(dir, "x.json"), "utf8")); + const fileCommands = [["file", `${name}.wast`]]; + // Module names that refer to a module left out: their commands go too. + const skipped = new Set(); + let current = null; + let currentSkipped = false; + for (const c of json.commands) { + const where = c.line; + if (c.type === "module" || c.type === "assert_uninstantiable" || c.type === "assert_unlinkable") { + if (c.module_type === "text" || !c.filename?.endsWith(".wasm")) { + if (c.type === "module") { + currentSkipped = true; + if (c.name) skipped.add(c.name); + } + continue; + } + const bytes = readFileSync(join(dir, c.filename)); + const summary = analyzeWasm(new Uint8Array(bytes)); + const imports = WebAssembly.Module.imports(new WebAssembly.Module(bytes)); + const usable = + summary.status === "valid" && + !imports.some( + (i) => i.module === "spectest" && (i.kind === "memory" || i.kind === "table"), + ); + if (!usable) { + if (c.type === "module") { + currentSkipped = true; + if (c.name) skipped.add(c.name); + } + continue; + } + const b64 = bytes.toString("base64"); + let index = moduleIndex.get(b64); + if (index === undefined) { + index = modules.length; + modules.push(b64); + moduleIndex.set(b64, index); + } + if (c.type === "module") { + current = c.name ?? null; + currentSkipped = false; + fileCommands.push(["module", where, index, ...(c.name ? [c.name] : [])]); + } else { + fileCommands.push(["instantiate", where, index]); + } + continue; + } + if (c.type === "register") { + const target = c.name ?? current; + if ((c.name ? skipped.has(c.name) : currentSkipped)) continue; + fileCommands.push(["register", c.as, ...(target ? [target] : [])]); + continue; + } + if (!c.action) continue; + const a = c.action; + const target = a.module ?? null; + if (target ? skipped.has(target) : currentSkipped) continue; + const args = (a.args ?? []).map(value); + const expected = (c.expected ?? []).map(value); + if (args.includes(null) || expected.includes(null)) continue; + if (args.some(oddNaN)) continue; + if (name === "float_exprs" && args.some(signalingPattern)) continue; + fileCommands.push([a.type === "get" ? "get" : "invoke", where, target ?? 0, a.field, args]); + } + commands.push(...sample(fileCommands)); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + } + const out = join(repo, `tests/corpus/webassembly-spec-${group}`); + mkdirSync(out, { recursive: true }); + const header = `/* Generated by tests/wasm-spec/gen.mjs from the WebAssembly 2.0 core test + * suite (WebAssembly/spec wg-2.0, Apache-2.0) with wabt 1.0.37 wast2json: + * ${names.map((n) => `${n}.wast`).join(", ")}. Do not edit. */\n`; + const body = + `export const modules = [\n${modules.map((m) => ` "${m}",`).join("\n")}\n];\n` + + `export const script = ${JSON.stringify(JSON.stringify(commands))};\n`; + writeFileSync(join(out, "data.mjs"), header + body); + writeFileSync( + join(out, "main.mjs"), + `// Executes WebAssembly spec tests (${names.length} files); see tests/wasm-spec/runner.mjs.\nimport { run } from "../../wasm-spec/runner.mjs";\nimport { modules, script } from "./data.mjs";\n\nrun(modules, script);\n`, + ); + console.log(`${group}: ${modules.length} modules, ${commands.length} commands`); +} diff --git a/tests/wasm-spec/runner.mjs b/tests/wasm-spec/runner.mjs new file mode 100644 index 000000000..5c1b8b6b4 --- /dev/null +++ b/tests/wasm-spec/runner.mjs @@ -0,0 +1,145 @@ +/* Executes WebAssembly spec-test commands (generated by gen.mjs) and prints + * one line per command. The webassembly-spec-* corpus programs call it; + * the differential harness runs them under Node and as compiled binaries + * and compares the output, so V8 decides every expected value, trap and + * error. Module bytes are inline base64 literals in each program's + * data.mjs, which the build translates. */ + +/** The spec harness's `spectest` module, without its memory and table. */ +function spectestImports(log) { + return { + print() { + log("print"); + }, + print_i32(a) { + log(`print_i32 ${a}`); + }, + print_i64(a) { + log(`print_i64 ${a}`); + }, + print_f32(a) { + log(`print_f32 ${show(a)}`); + }, + print_f64(a) { + log(`print_f64 ${show(a)}`); + }, + print_i32_f32(a, b) { + log(`print_i32_f32 ${a} ${show(b)}`); + }, + print_f64_f64(a, b) { + log(`print_f64_f64 ${show(a)} ${show(b)}`); + }, + global_i32: 666, + global_i64: 666n, + global_f32: 666.6, + global_f64: 666.6, + }; +} + +function show(v) { + if (typeof v === "bigint") return `${v}n`; + if (typeof v === "number") return Object.is(v, -0) ? "-0" : String(v); + if (v === null) return "null"; + if (v === undefined) return "undefined"; + if (typeof v === "function") return "function"; + if (Array.isArray(v)) return `[${v.map(show).join(",")}]`; + if (typeof v === "object" && typeof v.ref === "number") return `ref ${v.ref}`; + return typeof v; +} + +const refs = new Map(); + +function decode(arg) { + const colon = arg.indexOf(":"); + const type = arg.slice(0, colon); + const text = arg.slice(colon + 1); + if (type === "i32") return Number(text) | 0; + if (type === "i64") return BigInt.asIntN(64, BigInt(text)); + if (type === "f32") { + const view = new DataView(new ArrayBuffer(4)); + view.setUint32(0, Number(text)); + return view.getFloat32(0); + } + if (type === "f64") { + const view = new DataView(new ArrayBuffer(8)); + view.setBigUint64(0, BigInt(text)); + return view.getFloat64(0); + } + if (text === "null") return null; + const n = Number(text); + let ref = refs.get(n); + if (ref === undefined) { + ref = { ref: n }; + refs.set(n, ref); + } + return ref; +} + +function failure(e) { + return e instanceof Error ? `${e.name}: ${e.message}` : `threw ${show(e)}`; +} + +export function run(modules, script) { + const commands = JSON.parse(script); + const lines = []; + const log = (line) => { + lines.push(line); + }; + const imports = { spectest: spectestImports(log) }; + const named = new Map(); + let current = null; + const instantiate = (index) => + new WebAssembly.Instance(new WebAssembly.Module(Buffer.from(modules[index], "base64")), imports); + let file = ""; + for (const c of commands) { + const op = c[0]; + if (op === "file") { + file = c[1]; + log(`# ${file}`); + continue; + } + if (op === "register") { + const instance = c.length > 2 ? named.get(c[2]) : current; + if (instance) imports[c[1]] = instance.exports; + continue; + } + const at = `${file}:${c[1]}`; + if (op === "module") { + try { + current = instantiate(c[2]); + if (c.length > 3) named.set(c[3], current); + log(`${at} module`); + } catch (e) { + current = null; + log(`${at} module ${failure(e)}`); + } + continue; + } + if (op === "instantiate") { + try { + instantiate(c[2]); + log(`${at} instantiated`); + } catch (e) { + log(`${at} ${e instanceof Error ? e.name : "threw"}`); + } + continue; + } + const instance = c[2] !== 0 ? named.get(c[2]) : current; + if (!instance) { + log(`${at} no instance`); + continue; + } + try { + const target = instance.exports[c[3]]; + if (op === "get") { + log(`${at} ${show(target.value)}`); + continue; + } + const args = c[4].map(decode); + log(`${at} ${show(target(...args))}`); + } catch (e) { + log(`${at} ${failure(e)}`); + } + } + console.log(lines.join("\n")); +} From 6e68a811f10777e00fd9c61922ec0dba06cbecab Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 12:27:45 -0700 Subject: [PATCH 02/39] WebAssembly W5: the Memory, Table and Global constructors, Module.imports/exports/customSections, and function references from tables new WebAssembly.Memory, Table and Global construct the runtime objects an instance exports, with Node 24's descriptor order, defaults, conversions and messages (V8's EnforceUint32 errors, the v128 and shared-memory errors; a valid shared memory is refused with a TypeError until threads), so either kind can be imported. Imports of memories, tables and globals now check limits, types and mutability with V8's LinkError messages, and exports keep V8's identity (imported objects re-export as themselves, one object per memory and table). The classes called without new throw Node's TypeError. WebAssembly.Module.imports, exports and customSections read the descriptor (ABI v2). Custom sections are carried only by programs that call customSections. Every function a module references reaches JavaScript as a callable function: the translator emits one call thunk per signature, so table.get and funcref globals return the module's unexported functions too, and exported functions can be stored in tables and globals from any instance. Discovery also finds .so WebAssembly shared libraries at resolved paths. Fixes to W3/W4 found on the way: externref Table.grow fills with undefined; Memory.grow/Table index errors and funcref messages match V8; an invalid funcref global import is a LinkError; global.valueOf() on a WebAssembly.Global-typed receiver answers the value; explicit-bounds memories keep the blocks grow replaced, so old ArrayBuffers never dangle. This unblocks quickjs-wasi's extension loader: quickjs-wasi with its url, encoding, headers and structured-clone extensions runs through its own glue identically to Node, and pi codemode's static coverage goes from 83% to 84% with no WebAssembly blocker left. Evidence: differential corpus programs for the API (webassembly-jsapi), a 261-test port of WPT wasm/jsapi (webassembly-wpt-jsapi), quickjs-wasi's dist/extensions.js run unmodified against dylink-shaped modules (webassembly-dylink), and the 2.0 spec suite's modules that import the spectest memory and table (new webassembly-spec-imports group plus the memory and table groups); all match Node in the plain and sanitized lanes. The zero-cost gate leaves every non-WebAssembly program byte-identical. Co-Authored-By: Claude Opus 5.5 --- .../limitations/webassembly-modules.mdx | 10 +- .../generated/node-v24-backlog.json | 6 +- .../generated/node-v24-internal.json | 10 +- internal/compatibility/static-support.json | 2 +- .../compiler/src/backend/llvm/lib-shared.ts | 8 + .../compiler/src/backend/llvm/wasm-modules.ts | 5 +- .../compiler/src/coverage/surface-manifest.ts | 2 +- .../compiler/src/diagnostics/diagnostic.ts | 15 +- .../frontend/lowering/builtins/webassembly.ts | 125 +- .../src/frontend/lowering/lower-calls.ts | 3 + .../compiler/src/frontend/lowering/lowerer.ts | 4 + packages/compiler/src/ir/builtin-effects.ts | 8 + .../compiler/src/ir/builtin-signatures.ts | 18 + packages/compiler/src/ir/ir.ts | 4 + packages/compiler/src/wasm/discover.ts | 24 +- packages/compiler/src/wasm/translate.test.ts | 31 + packages/compiler/src/wasm/translate.ts | 88 +- packages/compiler/surface-manifest.json | 2 +- .../corpus/webassembly-dylink/main.mjs.json | 7 + .../tests/corpus/webassembly-jsapi.mjs.json | 6 + .../webassembly-spec-imports/main.mjs.json | 8 + .../corpus/webassembly-wpt-jsapi.mjs.json | 6 + packages/runtime/src/scr_wasm.c | 511 +++++++- packages/runtime/src/scr_wasm_abi.h | 28 +- .../webassembly-dylink/LICENSE.quickjs-wasi | 21 + tests/corpus/webassembly-dylink/extensions.js | 372 ++++++ tests/corpus/webassembly-dylink/main.mjs | 101 ++ tests/corpus/webassembly-jsapi.mjs | 356 ++++++ .../corpus/webassembly-spec-imports/data.mjs | 137 ++ .../corpus/webassembly-spec-imports/main.mjs | 5 + tests/corpus/webassembly-spec-memory/data.mjs | 16 +- tests/corpus/webassembly-spec-table/data.mjs | 14 +- tests/corpus/webassembly-wpt-jsapi.mjs | 1117 +++++++++++++++++ tests/coverage-fixtures/wasm/ext.so | Bin 0 -> 36 bytes tests/coverage-fixtures/wasm/glue.js | 9 + tests/coverage-fixtures/wasm/main.ts | 13 +- tests/coverage-fixtures/wasm/native.so | Bin 0 -> 25 bytes tests/diagnostics/webassembly-fences.ts | 13 +- tests/harness/__snapshots__/coverage-wasm.txt | 9 +- .../__snapshots__/webassembly-fences.ts.txt | 83 +- tests/harness/coverage.test.ts | 8 +- tests/wasm-spec/corpus/dylink-ext.wat | 42 + tests/wasm-spec/corpus/dylink-main.wat | 33 + tests/wasm-spec/corpus/jsapi-own.wat | 11 + tests/wasm-spec/corpus/jsapi.wat | 37 + tests/wasm-spec/gen.mjs | 17 +- tests/wasm-spec/runner.mjs | 5 +- 47 files changed, 3162 insertions(+), 188 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-dylink/main.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-jsapi.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-imports/main.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-wpt-jsapi.mjs.json create mode 100644 tests/corpus/webassembly-dylink/LICENSE.quickjs-wasi create mode 100644 tests/corpus/webassembly-dylink/extensions.js create mode 100644 tests/corpus/webassembly-dylink/main.mjs create mode 100644 tests/corpus/webassembly-jsapi.mjs create mode 100644 tests/corpus/webassembly-spec-imports/data.mjs create mode 100644 tests/corpus/webassembly-spec-imports/main.mjs create mode 100644 tests/corpus/webassembly-wpt-jsapi.mjs create mode 100644 tests/coverage-fixtures/wasm/ext.so create mode 100644 tests/coverage-fixtures/wasm/native.so create mode 100644 tests/wasm-spec/corpus/dylink-ext.wat create mode 100644 tests/wasm-spec/corpus/dylink-main.wat create mode 100644 tests/wasm-spec/corpus/jsapi-own.wat create mode 100644 tests/wasm-spec/corpus/jsapi.wat diff --git a/docs/content/limitations/webassembly-modules.mdx b/docs/content/limitations/webassembly-modules.mdx index e768b4ef0..8c8f8645c 100644 --- a/docs/content/limitations/webassembly-modules.mdx +++ b/docs/content/limitations/webassembly-modules.mdx @@ -1,16 +1,16 @@ -scriptc translates WebAssembly modules to native code when it builds the program; there is no interpreter or JIT in the executable. A build translates every module whose bytes it can see: files at paths the compiler resolves (`require.resolve`, `createRequire(...).resolve`, `import.meta.resolve`, `new URL("./x.wasm", import.meta.url)`, `path.join(__dirname, ...)`), modules inlined as base64 or byte-array literals, `.wasm` files shipped by packages whose code uses WebAssembly, and files listed in a `scriptc.wasm` array in `package.json`. At run time `WebAssembly.compile`, `instantiate`, `validate` and `new WebAssembly.Module` find the translated module by the SHA-256 of the bytes they are given. Bytes the build did not see, including bytes produced at run time, reject with a `CompileError` that says the module was not translated, and `WebAssembly.validate` answers `false` for them. `scriptc coverage` lists the modules a build finds, with their size, whether they validate, and the WebAssembly proposals they use. +scriptc translates WebAssembly modules to native code when it builds the program; there is no interpreter or JIT in the executable. A build translates every module whose bytes it can see: files at paths the compiler resolves (`require.resolve`, `createRequire(...).resolve`, `import.meta.resolve`, `new URL("./x.wasm", import.meta.url)`, `path.join(__dirname, ...)`), including `.so` WebAssembly shared libraries such as quickjs-wasi's extensions, modules inlined as base64 or byte-array literals, `.wasm` files shipped by packages whose code uses WebAssembly, and files listed in a `scriptc.wasm` array in `package.json`. At run time `WebAssembly.compile`, `instantiate`, `validate` and `new WebAssembly.Module` find the translated module by the SHA-256 of the bytes they are given. Bytes the build did not see, including bytes produced at run time, reject with a `CompileError` that says the module was not translated, and `WebAssembly.validate` answers `false` for them. `scriptc coverage` lists the modules a build finds, with their size, whether they validate, and the WebAssembly proposals they use. Translated modules can use the WebAssembly 2.0 feature set: the MVP plus sign-extension operators, non-trapping float-to-int conversions, bulk memory, multi-value, mutable globals, reference types, and extended constant expressions. Modules that use SIMD, threads, exception handling, tail calls, typed function references or GC, memory64, or multiple memories are not translated, so loading them rejects with the `CompileError` above; packages that fall back to a scalar build when that happens, such as undici and es-module-lexer, take their fallback. -Supported: `WebAssembly.compile`, `instantiate` (with bytes or a `Module`), `validate`, `new WebAssembly.Module`, `new WebAssembly.Instance`, and `instanceof` for every class; the error classes `CompileError`, `LinkError` and `RuntimeError`, constructed with or without `new`; `globalThis.WebAssembly` and its `compile`, `instantiate` and `validate` functions as values. Instances expose exported functions, memories (`buffer`, `grow`), tables (`get`, `set`, `grow`, `length`) and globals (`value`). Imports can be functions, numbers or BigInts for immutable globals, and memories, tables and globals exported by other instances. Traps throw `WebAssembly.RuntimeError` with Node.js's messages, unbounded recursion throws `RangeError`, and an exception thrown by an imported function propagates through the WebAssembly frames unchanged. A `WebAssembly.Module` can be sent to a worker through `workerData` or `postMessage`. +Supported: `WebAssembly.compile`, `instantiate` (with bytes or a `Module`), `validate`, `new WebAssembly.Module`, `new WebAssembly.Instance`, `new WebAssembly.Memory`, `new WebAssembly.Table`, `new WebAssembly.Global`, `WebAssembly.Module.imports`, `exports` and `customSections`, and `instanceof` for every class; the error classes `CompileError`, `LinkError` and `RuntimeError`, constructed with or without `new`; `globalThis.WebAssembly` and its `compile`, `instantiate` and `validate` functions as values. Instances expose exported functions, memories (`buffer`, `grow`), tables (`get`, `set`, `grow`, `length`) and globals (`value`, `valueOf`). Imports can be functions, numbers or BigInts for immutable globals, and memories, tables and globals that the program constructs or other instances export; their limits, types and mutability are checked with Node.js's `LinkError` messages. Function references from a table or global reach JavaScript as callable functions, and exported functions can be stored in tables and globals, which is what dynamic linkers such as quickjs-wasi's extension loader do. Traps throw `WebAssembly.RuntimeError` with Node.js's messages, unbounded recursion throws `RangeError`, and an exception thrown by an imported function propagates through the WebAssembly frames unchanged. A `WebAssembly.Module` can be sent to a worker through `workerData` or `postMessage`. -Not supported yet: the `Memory`, `Table`, `Global`, `Tag` and `Exception` constructors, `WebAssembly.Module.imports`, `exports` and `customSections`, `compileStreaming` and `instantiateStreaming`, and the classes used as values other than with `new` and `instanceof`. TypeScript sources fail to build with SC2020 at each such use, and JavaScript sources throw that diagnostic when the statement runs. Programs built for `wasm32-wasi` can't use the WebAssembly API. +Not supported yet: the `Tag` and `Exception` constructors, shared memories (`new WebAssembly.Memory({ shared: true, ... })` throws a `TypeError`), `compileStreaming` and `instantiateStreaming`, and the classes used as values other than with `new`, `instanceof` and `WebAssembly.Module`'s static functions. TypeScript sources fail to build with SC2020 at each such use, and JavaScript sources throw that diagnostic when the statement runs. Programs built for `wasm32-wasi` can't use the WebAssembly API. Differences from Node.js: -- `Memory.prototype.grow` does not detach the previous `ArrayBuffer`. The memory never moves, so views created before the growth stay valid but keep their old length. +- Growing a memory, from JavaScript or inside the module, does not detach the previous `ArrayBuffer`. Its contents stay readable, so views created before the growth stay valid but keep their old length; code that reads `memory.buffer` again after growing, as WebAssembly glue code does, behaves as in Node.js. +- `valueOf()` answers a `WebAssembly.Global`'s value only when the receiver's static type is `WebAssembly.Global`; through an untyped value it answers the object, and converting a `Global` to a primitive uses the object rather than its value. - Instances are never freed, together with their memories, imports and exports. -- A function reference (`funcref`) can reach JavaScript only as a function the module exports; other function references throw a `TypeError`. - A load whose result the module never uses may be removed instead of trapping when its address is out of bounds. Loads whose result is dropped explicitly still trap. - NaN payloads may differ, for example when a signaling NaN passes through arithmetic or a JavaScript number. - `WebAssembly.compile` and `instantiate` with bytes settle after the current microtasks, as in Node.js, but can settle after `setImmediate` callbacks that Node.js would run later. diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 4df2c983f..236255be9 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -34215,7 +34215,11 @@ "tests/corpus/webassembly-spec-float/main.mjs", "tests/corpus/webassembly-spec-control/main.mjs", "tests/corpus/webassembly-spec-memory/main.mjs", - "tests/corpus/webassembly-spec-table/main.mjs" + "tests/corpus/webassembly-spec-table/main.mjs", + "tests/corpus/webassembly-spec-imports/main.mjs", + "tests/corpus/webassembly-jsapi.mjs", + "tests/corpus/webassembly-wpt-jsapi.mjs", + "tests/corpus/webassembly-dylink/main.mjs" ] } } diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index f036d0ac3..4f78842aa 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -52219,13 +52219,17 @@ "tests/corpus/5830-timers-promises-signal.ts", "tests/corpus/text-codec-values/main.ts", "tests/corpus/webassembly-api.mjs", + "tests/corpus/webassembly-dylink/main.mjs", + "tests/corpus/webassembly-jsapi.mjs", "tests/corpus/webassembly-spec-control/main.mjs", "tests/corpus/webassembly-spec-float/main.mjs", + "tests/corpus/webassembly-spec-imports/main.mjs", "tests/corpus/webassembly-spec-int/main.mjs", "tests/corpus/webassembly-spec-memory/main.mjs", "tests/corpus/webassembly-spec-table/main.mjs", "tests/corpus/webassembly-typed.ts", "tests/corpus/webassembly-worker.ts", + "tests/corpus/webassembly-wpt-jsapi.mjs", "tests/harness/fetch-conformance.test.ts" ] }, @@ -53571,7 +53575,11 @@ "tests/corpus/webassembly-spec-float/main.mjs", "tests/corpus/webassembly-spec-control/main.mjs", "tests/corpus/webassembly-spec-memory/main.mjs", - "tests/corpus/webassembly-spec-table/main.mjs" + "tests/corpus/webassembly-spec-table/main.mjs", + "tests/corpus/webassembly-spec-imports/main.mjs", + "tests/corpus/webassembly-jsapi.mjs", + "tests/corpus/webassembly-wpt-jsapi.mjs", + "tests/corpus/webassembly-dylink/main.mjs" ] }, "anchorSource": "exact" diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index 96c41bcd1..703be5f11 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -28,7 +28,7 @@ "webstreams": "unreviewed" }, "evidenceByManifestPrefix": { - "stdlib.webassembly": ["tests/corpus/webassembly-api.mjs", "tests/corpus/webassembly-typed.ts", "tests/corpus/webassembly-worker.ts", "tests/corpus/webassembly-spec-int/main.mjs", "tests/corpus/webassembly-spec-float/main.mjs", "tests/corpus/webassembly-spec-control/main.mjs", "tests/corpus/webassembly-spec-memory/main.mjs", "tests/corpus/webassembly-spec-table/main.mjs"], + "stdlib.webassembly": ["tests/corpus/webassembly-api.mjs", "tests/corpus/webassembly-typed.ts", "tests/corpus/webassembly-worker.ts", "tests/corpus/webassembly-spec-int/main.mjs", "tests/corpus/webassembly-spec-float/main.mjs", "tests/corpus/webassembly-spec-control/main.mjs", "tests/corpus/webassembly-spec-memory/main.mjs", "tests/corpus/webassembly-spec-table/main.mjs", "tests/corpus/webassembly-spec-imports/main.mjs", "tests/corpus/webassembly-jsapi.mjs", "tests/corpus/webassembly-wpt-jsapi.mjs", "tests/corpus/webassembly-dylink/main.mjs"], "node-builtin.fs.readFileSync": ["tests/corpus/1403-buffer-fs.ts", "tests/corpus/2595-fs-arg-ladders.cjs", "tests/corpus/2919-fs-function-values.ts", "tests/corpus/2920-fs-promises-function-values.ts", "tests/corpus/fs-read-encodings.ts"], "syntax.using-declarations": ["tests/corpus/2841-using-sync.ts"], "syntax.await-using-declarations": ["tests/corpus/2842-await-using.ts"], diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 10e3ddd8d..2b0c70dee 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -843,6 +843,14 @@ export const LIB_FN_SYMS: Record = { "wasm.instanceNew": "scr_wasm_instance_new", "wasm.is": "scr_wasm_is", "wasm.errorNew": "scr_wasm_error_new", + "wasm.memoryNew": "scr_wasm_memory_construct", + "wasm.tableNew": "scr_wasm_table_construct", + "wasm.globalNew": "scr_wasm_global_construct", + "wasm.withoutNew": "scr_wasm_construct_without_new", + "wasm.moduleImports": "scr_wasm_module_imports", + "wasm.moduleExports": "scr_wasm_module_exports", + "wasm.moduleCustomSections": "scr_wasm_module_custom_sections", + "wasm.valueOf": "scr_wasm_value_of", "wasm.function": "scr_wasm_function", "wasm.namespace": "scr_wasm_namespace", "wasm.globalView": "scr_wasm_global_view", diff --git a/packages/compiler/src/backend/llvm/wasm-modules.ts b/packages/compiler/src/backend/llvm/wasm-modules.ts index c37dc36c4..8b8479bc8 100644 --- a/packages/compiler/src/backend/llvm/wasm-modules.ts +++ b/packages/compiler/src/backend/llvm/wasm-modules.ts @@ -48,7 +48,10 @@ export function emitWasmModules( if (bytes === null) continue; let translation; try { - translation = translateWasmModule(bytes, hexBytes(module.sha256), { boundsChecks }); + translation = translateWasmModule(bytes, hexBytes(module.sha256), { + boundsChecks, + customSections: mod.wasmCustomSections === true, + }); } catch (error) { if (error instanceof WasmTranslateError) continue; throw error; diff --git a/packages/compiler/src/coverage/surface-manifest.ts b/packages/compiler/src/coverage/surface-manifest.ts index 824790bd9..9867a5617 100644 --- a/packages/compiler/src/coverage/surface-manifest.ts +++ b/packages/compiler/src/coverage/surface-manifest.ts @@ -454,7 +454,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes kind: "stdlib", name: "globalThis.WebAssembly", status: "static", - note: `compile, instantiate, validate, Module, Instance, instanceof, the error classes, exports, memories, tables, globals and Module transfer to workers, over the modules translated at build time; the rest refuses with ${refusal.code} (${refusal.hint ?? ""})`, + note: `compile, instantiate, validate, the Module, Instance, Memory, Table and Global constructors, Module.imports, exports and customSections, instanceof, the error classes, exports, imports and Module transfer to workers, over the modules translated at build time; the rest refuses with ${refusal.code} (${refusal.hint ?? ""})`, }); } diff --git a/packages/compiler/src/diagnostics/diagnostic.ts b/packages/compiler/src/diagnostics/diagnostic.ts index 0359dbf6b..56c288605 100644 --- a/packages/compiler/src/diagnostics/diagnostic.ts +++ b/packages/compiler/src/diagnostics/diagnostic.ts @@ -752,18 +752,19 @@ export function noLoweringDiag( } /** A REACHED use of a part of the WebAssembly API scriptc does not - * implement yet (SC2020): the Memory, Table and Global constructors, - * Module.imports/exports/customSections, the streaming functions, the - * classes as values. compile, instantiate, validate, Module, Instance and - * the error classes lower (builtins/webassembly.ts). `surface` names what - * was used ('new WebAssembly.Memory', 'WebAssembly.Module.imports'). */ + * implement yet (SC2020): the streaming functions, Tag and Exception, the + * classes as values. compile, instantiate, validate, the Module, Instance, + * Memory, Table and Global constructors, Module.imports/exports/ + * customSections and the error classes lower (builtins/webassembly.ts). + * `surface` names what was used ('WebAssembly.compileStreaming', + * 'WebAssembly.Memory'). */ export function webAssemblyDiag(surface: string, loc: SrcLoc): ScrDiagnostic { return { code: "SC2020", - message: `'${surface}' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API`, + message: `'${surface}' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, the Module, Instance, Memory, Table and Global constructors, Module.imports, exports and customSections, and the error classes over modules translated at build time, but not this part of the API`, loc, milestone: "later", - hint: "the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations)", + hint: "the streaming functions, Tag and Exception, and the classes used as values other than with new and instanceof are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations)", }; } diff --git a/packages/compiler/src/frontend/lowering/builtins/webassembly.ts b/packages/compiler/src/frontend/lowering/builtins/webassembly.ts index 3a0a00508..2d5c5f17e 100644 --- a/packages/compiler/src/frontend/lowering/builtins/webassembly.ts +++ b/packages/compiler/src/frontend/lowering/builtins/webassembly.ts @@ -6,6 +6,7 @@ import { BOOL, DYN, F64, STRING, type IrExpr } from "../../../ir/ir.js"; import { dynUndefinedExpr } from "../../../ir/build.js"; import { lowerDynObjectLiteral } from "../expressions/object-literals.js"; import { stdlibGlobalNameOf } from "../surfaces.js"; +import { isWebAssemblyType } from "../../type-mapper.js"; /* The WebAssembly API. scriptc.d.ts declares its types (lib.dom's * namespace) and the type mapper gives them the checked-dynamic @@ -13,16 +14,18 @@ import { stdlibGlobalNameOf } from "../surfaces.js"; * native code (wasm/translate.ts) and found at run time by the SHA-256 of * their bytes (scr_wasm.c): * - WebAssembly.compile, instantiate and validate calls, new - * WebAssembly.Module and new WebAssembly.Instance lower to wasm.* - * libCalls; members of the values they produce (exports, memory + * WebAssembly.Module, Instance, Memory, Table and Global, and + * WebAssembly.Module.imports, exports and customSections lower to + * wasm.* libCalls; members of the values they produce (exports, memory * buffers, globals, tables) dispatch through the native handles; + * - the classes called without `new` throw Node's TypeError + * (wasm.withoutNew); * - `v instanceof WebAssembly.` lowers to wasm.is; * - the error classes construct with or without `new` (wasm.errorNew). - * Every other reached use of the API value (the bare namespace, the - * Memory, Table and Global constructors, Module.imports and friends, the - * streaming functions) still fences at its expression with - * webAssemblyDiag: a build error in TypeScript sources, a located runtime - * fence in JavaScript ones. typeof needs no value and folds to Node's + * Every other reached use of the API value (the classes as values, the + * streaming functions, Tag and Exception) still fences at its expression + * with webAssemblyDiag: a build error in TypeScript sources, a located + * runtime fence in JavaScript ones. typeof needs no value and folds to Node's * answer. A lowering marks the lowerer, so the build translates the * modules it discovers (lowerToIr). */ @@ -170,15 +173,38 @@ function lowerArg(lowerer: Lowerer, arg: ts.Expression): IrExpr { : lowerer.lowerExprExpecting(arg, DYN); } -/** The arguments, padded with undefined to `count`; null for spreads or - * extra arguments (they stay refused). */ +/** An argument whose evaluation has no effect: a literal, a plain + * identifier, or an empty object or array literal. */ +function isInert(arg: ts.Expression): boolean { + const node = bare(arg); + if (ts.isObjectLiteralExpression(node)) return node.properties.length === 0; + if (ts.isArrayLiteralExpression(node)) return node.elements.length === 0; + return ( + ts.isIdentifier(node) || + ts.isNumericLiteral(node) || + node.kind === ts.SyntaxKind.BigIntLiteral || + ts.isStringLiteral(node) || + ts.isNoSubstitutionTemplateLiteral(node) || + node.kind === ts.SyntaxKind.NullKeyword || + node.kind === ts.SyntaxKind.TrueKeyword || + node.kind === ts.SyntaxKind.FalseKeyword + ); +} + +/** The arguments, padded with undefined to `count`. Extra arguments are + * ignored, as the API ignores them, when evaluating them has no effect; + * null for spreads or other extra arguments (they stay refused). */ function lowerArgs( lowerer: Lowerer, args: readonly ts.Expression[], count: number, loc: IrExpr["loc"], ): IrExpr[] | null { - if (args.length > count || args.some(ts.isSpreadElement)) return null; + if (args.some(ts.isSpreadElement)) return null; + if (args.length > count) { + if (!args.slice(count).every(isInert)) return null; + args = args.slice(0, count); + } const out = args.map((arg) => lowerArg(lowerer, arg)); while (out.length < count) out.push(dynUndefinedExpr(loc)); return out; @@ -195,14 +221,57 @@ function errorNew(member: string, args: IrExpr[], loc: IrExpr["loc"]): IrExpr { }; } +/** The classes that require `new`, in wasm.withoutNew's numbering. */ +const NEW_ONLY = ["Module", "Instance", "Memory", "Table", "Global"]; + +/** `WebAssembly.Module.imports(module)`, `exports(module)` and + * `customSections(module, name)`. Their results are arrays of descriptors + * or ArrayBuffers built as checked-dynamic values, then taken into the + * call's own type. Null for anything else. */ +function lowerModuleStatic(lowerer: Lowerer, call: ts.CallExpression): IrExpr | null { + const surface = webAssemblySurface(lowerer, call.expression); + const name = surface?.startsWith("WebAssembly.Module.") + ? surface.slice("WebAssembly.Module.".length) + : null; + if (name !== "imports" && name !== "exports" && name !== "customSections") return null; + const loc = locOf(call); + const args = lowerArgs(lowerer, call.arguments, name === "customSections" ? 2 : 1, loc); + if (args === null) return null; + lowerer.usesWebAssembly = true; + if (name === "customSections") lowerer.usesWasmCustomSections = true; + const fn = + name === "imports" + ? "wasm.moduleImports" + : name === "exports" + ? "wasm.moduleExports" + : "wasm.moduleCustomSections"; + const result: IrExpr = { kind: "libCall", fn, args, type: DYN, loc }; + return lowerer.coerceInto(call, result, lowerer.irTypeOf(call)); +} + /** `WebAssembly.compile(bytes)`, `WebAssembly.instantiate(source, - * imports?)`, `WebAssembly.validate(bytes)`, and the error classes called - * without `new`. Null for anything else. */ + * imports?)`, `WebAssembly.validate(bytes)`, the error classes called + * without `new`, the other classes called without `new` (a TypeError), and + * Module's static functions. Null for anything else. */ export function lowerWebAssemblyCall(lowerer: Lowerer, call: ts.CallExpression): IrExpr | null { if (call.questionDotToken) return null; const member = webAssemblyMember(lowerer, call.expression); - if (member === null) return null; + if (member === null) return lowerModuleStatic(lowerer, call); const loc = locOf(call); + const newOnly = NEW_ONLY.indexOf(member); + if (newOnly >= 0) { + // The arguments evaluate, then the call throws. + const args = lowerArgs(lowerer, call.arguments, 2, loc); + if (args === null) return null; + lowerer.usesWebAssembly = true; + return { + kind: "libCall", + fn: "wasm.withoutNew", + args: [{ kind: "numLit", value: newOnly, type: F64, loc }, args[0]!, args[1]!], + type: DYN, + loc, + }; + } const isError = member === "CompileError" || member === "LinkError" || member === "RuntimeError"; if (member !== "compile" && member !== "instantiate" && member !== "validate" && !isError) return null; @@ -234,14 +303,17 @@ export function lowerWebAssemblyCall(lowerer: Lowerer, call: ts.CallExpression): } /** `new WebAssembly.Module(bytes)`, `new WebAssembly.Instance(module, - * imports?)` and the error classes. Null for anything else. */ + * imports?)`, `new WebAssembly.Memory(descriptor)`, `new + * WebAssembly.Table(descriptor, value?)`, `new + * WebAssembly.Global(descriptor, value?)` and the error classes. Null for + * anything else. */ export function lowerWebAssemblyNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr | null { const member = webAssemblyMember(lowerer, expr.expression); if (member === null) return null; const isError = member === "CompileError" || member === "LinkError" || member === "RuntimeError"; - if (member !== "Module" && member !== "Instance" && !isError) return null; + if (!NEW_ONLY.includes(member) && !isError) return null; const loc = locOf(expr); - const used = member === "Module" ? 1 : 2; + const used = member === "Module" || member === "Memory" ? 1 : 2; const args = lowerArgs(lowerer, expr.arguments ?? [], used, loc); if (args === null) return null; lowerer.usesWebAssembly = true; @@ -249,6 +321,12 @@ export function lowerWebAssemblyNew(lowerer: Lowerer, expr: ts.NewExpression): I if (isError) result = errorNew(member, args, loc); else if (member === "Module") result = { kind: "libCall", fn: "wasm.moduleNew", args: [args[0]!], type: DYN, loc }; + else if (member === "Memory") + result = { kind: "libCall", fn: "wasm.memoryNew", args: [args[0]!], type: DYN, loc }; + else if (member === "Table") + result = { kind: "libCall", fn: "wasm.tableNew", args: [args[0]!, args[1]!], type: DYN, loc }; + else if (member === "Global") + result = { kind: "libCall", fn: "wasm.globalNew", args: [args[0]!, args[1]!], type: DYN, loc }; else result = { kind: "libCall", @@ -309,3 +387,18 @@ export function lowerWebAssemblyValue(lowerer: Lowerer, expr: ts.Expression): Ir if (index < 0 || !ts.isPropertyAccessExpression(node)) return null; return fn("wasm.function", [{ kind: "numLit", value: index, type: F64, loc }]); } + +/** `global.valueOf()` on a receiver typed as a WebAssembly value: a + * Global answers its value (the generic dyn.valueOf answers the object + * itself for native handles other than Date). Null for other receivers. */ +export function lowerWebAssemblyValueOf( + lowerer: Lowerer, + receiver: ts.Expression, + recv: IrExpr, + loc: IrExpr["loc"], +): IrExpr | null { + const ctx = { checker: lowerer.checker, isStdlibFile: lowerer.isStdlibFile }; + if (!isWebAssemblyType(lowerer.typeOf(receiver), ctx)) return null; + lowerer.usesWebAssembly = true; + return { kind: "libCall", fn: "wasm.valueOf", args: [recv], type: DYN, loc }; +} diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 303bdf517..37a96b1d8 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -1,6 +1,7 @@ import { guardNullProto, nullProtoRecordShape } from "./null-prototype.js"; import { lowerUnionEquality, tagEqualityMayMissAlias } from "./strict-equality.js"; import { lowerHashStreamCall } from "./builtins/hash-stream.js"; +import { lowerWebAssemblyValueOf } from "./builtins/webassembly.js"; import { lowerArrayCallbackCall } from "./containers/array-callback-call.js"; /** Dispatch source calls, builtin members and receiver-specific operations. * Signature collection, argument completion and function bodies have their @@ -3497,6 +3498,8 @@ function lowerDynReceiverMethodCall( // answers each kind's own: primitives and plain objects themselves, a // Date its time value, an own or inherited valueOf member its result. if (access.name.text === "valueOf" && call.arguments.length === 0) { + const webAssembly = lowerWebAssemblyValueOf(lowerer, access.expression, recv, locOf(call)); + if (webAssembly !== null) return webAssembly; return { kind: "libCall", fn: "dyn.valueOf", diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 9cc8015e8..83fe9e4bd 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1122,6 +1122,7 @@ export function lowerToIr( wasmModules.push({ sha256: report.sha256, bytes: encodeBase64(bytes) }); } result.module.wasmModules = wasmModules; + if (resultLowerer.usesWasmCustomSections) result.module.wasmCustomSections = true; timing("wasm-discovery", { modules: wasmModules.length }); } if (options.coverage !== true) return result; @@ -2681,6 +2682,9 @@ export class Lowerer { /** The program uses the WebAssembly API (builtins/webassembly.ts): the * build translates the modules it discovers. */ usesWebAssembly = false; + /** The program calls WebAssembly.Module.customSections: translated + * modules keep their custom sections. */ + usesWasmCustomSections = false; /** The program constructs a LifetimeRegion (lifetime-regions.ts). */ usesLifetimeRegions = false; /** Per-directory answers of experimental-import.ts's declaration-file test. */ diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index c6e93c268..e1ccf7dfd 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -138,6 +138,14 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "wasm.moduleNew", "wasm.instanceNew", "wasm.errorNew", + "wasm.memoryNew", + "wasm.tableNew", + "wasm.globalNew", + "wasm.withoutNew", + "wasm.moduleImports", + "wasm.moduleExports", + "wasm.moduleCustomSections", + "wasm.valueOf", "events.addAbortListener", "fetch.streamNew", "fetch.streamFrom", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 1ec915409..fb6e264d4 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -120,6 +120,24 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "wasm.instanceNew": { argTypes: [DYN, DYN], result: DYN }, "wasm.is": { argTypes: [DYN, F64], result: BOOL }, "wasm.errorNew": { argTypes: [F64, DYN, DYN], result: DYN }, + /** new WebAssembly.Memory(descriptor), Table(descriptor, value) and + * Global(descriptor, value) (an undefined value is the type's default); + * `wasm.withoutNew` throws the TypeError for Module, Instance, Memory, + * Table or Global (kinds 0-4) called without new, after its arguments + * evaluate. */ + "wasm.memoryNew": { argTypes: [DYN], result: DYN }, + "wasm.tableNew": { argTypes: [DYN, DYN], result: DYN }, + "wasm.globalNew": { argTypes: [DYN, DYN], result: DYN }, + "wasm.withoutNew": { argTypes: [F64, DYN, DYN], result: DYN }, + /** WebAssembly.Module.imports(module), exports(module) and + * customSections(module, name): checked-dynamic arrays of descriptor + * objects and ArrayBuffers. */ + "wasm.moduleImports": { argTypes: [DYN], result: DYN }, + "wasm.moduleExports": { argTypes: [DYN], result: DYN }, + "wasm.moduleCustomSections": { argTypes: [DYN, DYN], result: DYN }, + /** `v.valueOf()` on a WebAssembly-typed receiver: a Global's value, + * dyn.valueOf's answer for anything else. */ + "wasm.valueOf": { argTypes: [DYN], result: DYN }, /** WebAssembly.compile (0), instantiate (1) and validate (2) as function * values, and the namespace object holding them. */ "wasm.function": { argTypes: [F64], result: DYN }, diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 145038748..0135c8f73 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -1003,6 +1003,10 @@ export interface IrModule { * API (possibly empty). The backend appends each module's translation * and emits the registry the runtime looks modules up in. */ wasmModules?: IrWasmModule[]; + /** The program calls WebAssembly.Module.customSections, so translated + * modules keep their custom sections (otherwise they carry none, and + * debug sections cost nothing). */ + wasmCustomSections?: boolean; } /** A WebAssembly module whose bytes the build saw, validated within the diff --git a/packages/compiler/src/wasm/discover.ts b/packages/compiler/src/wasm/discover.ts index 856f0752f..cd6cb1ff9 100644 --- a/packages/compiler/src/wasm/discover.ts +++ b/packages/compiler/src/wasm/discover.ts @@ -6,7 +6,9 @@ * 1. path: a `.wasm` path the compiler resolves from the source text * (`require.resolve`, `createRequire(...).resolve`, `import.meta.resolve`, * `new URL("./x.wasm", import.meta.url)`, and `path.join(__dirname, ...)` - * or `__dirname + "/x.wasm"`); + * or `__dirname + "/x.wasm"`), or a `.so` path spelled the same ways + * whose file is a module (WebAssembly shared libraries, such as + * quickjs-wasi's extensions); * 2. inline: a string literal that decodes as base64 to a module, or an * array literal of its bytes; * 3. package: every `.wasm` file shipped by a reached npm package whose @@ -78,6 +80,9 @@ const BASE64_MAGIC = "AGFzbQ"; const BYTES_MAGIC = /\[\s*(?:0|0x0+)\s*,\s*(?:97|0x61)\s*,\s*(?:115|0x73)\s*,\s*(?:109|0x6d)\s*,/i; /** Package directories deeper than this are not searched for modules. */ const PACKAGE_SCAN_DEPTH = 6; +/** A `.so` path in a string literal: the cheap test before a file with no + * `.wasm` mention is walked for shared-library paths. */ +const SHARED_LIBRARY_PATH = /\.so["'`]/; /** Larger files are reported by size but not read. */ const MAX_MODULE_BYTES = 256 * 1024 * 1024; @@ -139,6 +144,8 @@ class Discovery { return; } if (bytes.length > MAX_MODULE_BYTES) return; + // A shared-library path names a module only when the file is one. + if (source.kind === "path" && !path.endsWith(".wasm") && !isWasmHeader(bytes)) return; this.byPath.set(path, this.addBytes(bytes, path, source)); } @@ -146,7 +153,7 @@ class Discovery { scanFile(sf: ts.SourceFile): void { const text = sf.text; - const paths = text.includes(".wasm"); + const paths = text.includes(".wasm") || SHARED_LIBRARY_PATH.test(text); const base64 = text.includes(BASE64_MAGIC); const bytes = BYTES_MAGIC.test(text); if (!paths && !base64 && !bytes) return; @@ -184,7 +191,8 @@ class Discovery { ); } - /** The module path a resolution expression names, when it ends in .wasm. */ + /** The module path a resolution expression names, when it ends in .wasm + * (or .so). */ resolvedPath(sf: ts.SourceFile, node: ts.Node): string | null { const dir = dirname(sf.fileName); if (ts.isCallExpression(node)) { @@ -245,7 +253,7 @@ class Discovery { if (!ts.isStringLiteral(arg) && !ts.isNoSubstitutionTemplateLiteral(arg)) return null; parts.push(arg.text); } - if (!parts[parts.length - 1]!.endsWith(".wasm")) return null; + if (!isModulePath(parts[parts.length - 1]!)) return null; let path = parts[0]!; for (let i = 1; i < parts.length; i++) path = resolve(path, parts[i]!); return path; @@ -314,9 +322,15 @@ function addSource(report: WasmModuleReport, source: WasmSource): void { report.sources.push(source); } +/** A path that may name a module: `.wasm`, or `.so` for WebAssembly shared + * libraries (addFile keeps those only when the file is a module). */ +function isModulePath(text: string): boolean { + return text.endsWith(".wasm") || text.endsWith(".so"); +} + function wasmLiteral(node: ts.Expression): string | null { if (!ts.isStringLiteral(node) && !ts.isNoSubstitutionTemplateLiteral(node)) return null; - return node.text.endsWith(".wasm") ? node.text : null; + return isModulePath(node.text) ? node.text : null; } function isDirname(node: ts.Expression): boolean { diff --git a/packages/compiler/src/wasm/translate.test.ts b/packages/compiler/src/wasm/translate.test.ts index a9ef58248..07b0cbb9c 100644 --- a/packages/compiler/src/wasm/translate.test.ts +++ b/packages/compiler/src/wasm/translate.test.ts @@ -60,6 +60,37 @@ describe("translateWasmModule", () => { for (const decl of out.decls) expect(decl).toMatch(/^declare /); }); + test("keeps custom sections only when asked, and gives unexported table functions call thunks", () => { + // (module (type $t (func (param i32) (result i32))) (table 2 funcref) + // (elem (i32.const 0) $hidden $shown) (func $hidden (type $t) local.get 0) + // (func $shown (export "shown") (type $t) local.get 0)), plus a custom + // section "meta" with "hi". + const refs = new Uint8Array([ + 0, 97, 115, 109, 1, 0, 0, 0, 1, 6, 1, 96, 1, 127, 1, 127, 3, 3, 2, 0, 0, 4, 4, 1, 112, 0, 2, 7, 9, + 1, 5, 115, 104, 111, 119, 110, 0, 1, 9, 8, 1, 0, 65, 0, 11, 2, 0, 1, 10, 11, 2, 4, 0, 32, 0, 11, 4, + 0, 32, 0, 11, 0, 7, 4, 109, 101, 116, 97, 104, 105, + ]); + const prefix = wasmSymbolPrefix(SHA); + const plain = translateWasmModule(refs, SHA, { boundsChecks: false }).text.join("\n"); + expect(plain).toContain(`@${prefix}_customs = private constant [0 x { ptr, i64, ptr, i64 }] []`); + expect(plain).not.toContain(`c"hi"`); + const kept = translateWasmModule(refs, SHA, { boundsChecks: false, customSections: true }); + const text = kept.text.join("\n"); + expect(text).toContain(`@${prefix}_c0 = private unnamed_addr constant [2 x i8] c"hi", align 1`); + expect(text).toContain(`@${prefix}_customs = private constant [1 x { ptr, i64, ptr, i64 }]`); + // One call thunk for the signature, used by the unexported function + // only (the exported one has its export thunk). + expect(text).toContain(`define internal void @${prefix}_k0(ptr %code, ptr %inst, ptr %a, ptr %r)`); + expect(text).toContain(`%res = call i32 %code(ptr %inst, i32 `); + expect(text).toContain(`@${prefix}_calls = private constant [2 x ptr] [ptr @${prefix}_k0, ptr null]`); + for (const line of topLevelLines(kept.text)) { + expect( + line === "" || /^(define internal |@[\w.$-]+ = (private|internal) )/.test(line), + line, + ).toBe(true); + } + }); + test("checks memory accesses explicitly only when asked", () => { const guarded = translateWasmModule(ADD, SHA, { boundsChecks: false }).text.join("\n"); const checked = translateWasmModule(ADD, SHA, { boundsChecks: true }).text.join("\n"); diff --git a/packages/compiler/src/wasm/translate.ts b/packages/compiler/src/wasm/translate.ts index e0ce27be5..ddfbe1225 100644 --- a/packages/compiler/src/wasm/translate.ts +++ b/packages/compiler/src/wasm/translate.ts @@ -68,7 +68,7 @@ export const TRAP_NULL = 9; export const TRAP_EXHAUSTION = 100; /** The descriptor ABI version both sides agree on. */ -export const WASM_ABI_VERSION = 1; +export const WASM_ABI_VERSION = 2; /** Instance slot offsets (bytes). */ const OFF_MEMBASE = 8; @@ -81,6 +81,8 @@ const FUNCREF_SIZE = 24; export interface WasmTranslateOptions { /** Explicit bounds checks instead of guard pages. */ boundsChecks: boolean; + /** Keep the custom sections, for WebAssembly.Module.customSections. */ + customSections?: boolean; } export interface WasmTranslation { @@ -387,6 +389,44 @@ class ModuleTranslator { return name; } + /** A call thunk for signature `type`: `(code, inst, args, results)` + * calls `code` (a function of that signature) with the arguments in + * 64-bit slots. The runtime calls a function reference that reaches + * JavaScript through it when the module does not export the function. */ + callThunk(type: number): string { + const name = `@${this.p}_k${type}`; + const ft = this.m.types[type]!; + const out: string[] = []; + out.push(`define internal void ${name}(ptr %code, ptr %inst, ptr %a, ptr %r) nounwind {`); + out.push(`entry:`); + const args: string[] = ["ptr %inst"]; + for (let i = 0; i < ft.params.length; i++) { + out.push(` %ap${i} = getelementptr i64, ptr %a, i64 ${i}`); + out.push(` %as${i} = load i64, ptr %ap${i}`); + args.push(`${llType(ft.params[i]!)} ${fromSlot(out, ft.params[i]!, `%as${i}`, `a${i}`)}`); + } + const ret = retType(ft.results); + if (ft.results.length === 0) { + out.push(` call void %code(${args.join(", ")})`); + } else { + out.push(` %res = call ${ret} %code(${args.join(", ")})`); + for (let i = 0; i < ft.results.length; i++) { + let v = "%res"; + if (ft.results.length > 1) { + out.push(` %rv${i} = extractvalue ${ret} %res, ${i}`); + v = `%rv${i}`; + } + const slot = toSlot(out, ft.results[i]!, v, `r${i}`); + out.push(` %rp${i} = getelementptr i64, ptr %r, i64 ${i}`); + out.push(` store i64 ${slot}, ptr %rp${i}`); + } + } + out.push(` ret void`); + out.push(`}`); + this.text.push(out.join("\n")); + return name; + } + /** Emits the init function: globals, table initializers and segments, * in the specification's order. The runtime calls the start function * (which takes and returns nothing) separately. */ @@ -537,12 +577,27 @@ class ModuleTranslator { // every function a reference can name. const nf = m.funcTypes.length; const codes: string[] = []; + const callThunks: string[] = []; + const callThunkSyms = new Map(); const types: string[] = []; const sigs: string[] = []; const sigSyms = new Map(); for (let f = 0; f < nf; f++) { const referenced = this.refs.has(f); codes.push(referenced ? `ptr ${this.fn(f)}` : "ptr null"); + // Referenced functions the module does not export reach JavaScript + // through their signature's call thunk. + if (referenced && !thunks.has(f)) { + const type = m.funcTypes[f]!; + let thunk = callThunkSyms.get(type); + if (thunk === undefined) { + thunk = this.callThunk(type); + callThunkSyms.set(type, thunk); + } + callThunks.push(`ptr ${thunk}`); + } else { + callThunks.push("ptr null"); + } types.push(`i64 ${this.typeHashes[m.funcTypes[f]!]!}`); const sig = sigString(this.funcType(f)); let sym = sigSyms.get(sig); @@ -555,7 +610,9 @@ class ModuleTranslator { const codesSym = `@${p}_codes`; const typesSym = `@${p}_types`; const sigsSym = `@${p}_sigs`; + const callThunksSym = `@${p}_calls`; lines.push(`${codesSym} = private constant [${nf} x ptr] [${codes.join(", ")}]`); + lines.push(`${callThunksSym} = private constant [${nf} x ptr] [${callThunks.join(", ")}]`); lines.push(`${typesSym} = private constant [${nf} x i64] [${types.join(", ")}]`); lines.push(`${sigsSym} = private constant [${nf} x ptr] [${sigs.join(", ")}]`); // Tables. @@ -623,6 +680,30 @@ class ModuleTranslator { lines.push( `${elemsSym} = private constant [${elemRows.length} x { i64, i64, ptr }] [${elemRows.join(", ")}]`, ); + // Custom sections, when the program reads them. + const customRows: string[] = []; + if (this.opts.customSections === true) { + for (let s = 0; s < m.customs.length; s++) { + const custom = m.customs[s]!; + const name = textStr(custom.name); + const len = custom.payload.end - custom.payload.start; + let data = "ptr null"; + if (len > 0) { + const sym = `@${p}_c${s}`; + lines.push( + `${sym} = private unnamed_addr constant [${len} x i8] c"${cBytes(m.bytes, custom.payload.start, custom.payload.end)}", align 1`, + ); + data = `ptr ${sym}`; + } + customRows.push( + `{ ptr, i64, ptr, i64 } { ptr ${name.sym}, i64 ${name.len}, ${data}, i64 ${len} }`, + ); + } + } + const customsSym = `@${p}_customs`; + lines.push( + `${customsSym} = private constant [${customRows.length} x { ptr, i64, ptr, i64 }] [${customRows.join(", ")}]`, + ); const memory = m.memories[0]; const sha: string[] = []; for (let i = 0; i < 32; i++) sha.push(`i8 ${sha256[i]!}`); @@ -654,9 +735,12 @@ class ModuleTranslator { `ptr ${elemsSym}`, `ptr ${init}`, `ptr ${m.start === null ? "null" : this.fn(m.start)}`, + `i64 ${customRows.length}`, + `ptr ${customsSym}`, + `ptr ${callThunksSym}`, ]; const descType = - "{ [32 x i8], i64, i64, i64, i64, ptr, i64, ptr, i64, i64, ptr, ptr, ptr, i64, ptr, i64, i64, i64, i64, ptr, i64, ptr, i64, ptr, ptr, ptr }"; + "{ [32 x i8], i64, i64, i64, i64, ptr, i64, ptr, i64, i64, ptr, ptr, ptr, i64, ptr, i64, i64, i64, i64, ptr, i64, ptr, i64, ptr, ptr, ptr, i64, ptr, ptr }"; lines.push(`${desc} = internal constant ${descType} { ${fields.join(", ")} }`); this.text.push(lines.join("\n")); return desc; diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 5d82b6719..571234953 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -5635,7 +5635,7 @@ "kind": "stdlib", "name": "globalThis.WebAssembly", "status": "static", - "note": "compile, instantiate, validate, Module, Instance, instanceof, the error classes, exports, memories, tables, globals and Module transfer to workers, over the modules translated at build time; the rest refuses with SC2020 (the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations))" + "note": "compile, instantiate, validate, the Module, Instance, Memory, Table and Global constructors, Module.imports, exports and customSections, instanceof, the error classes, exports, imports and Module transfer to workers, over the modules translated at build time; the rest refuses with SC2020 (the streaming functions, Tag and Exception, and the classes used as values other than with new and instanceof are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations))" }, { "id": "syntax.async-generators", diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-dylink/main.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-dylink/main.mjs.json new file mode 100644 index 000000000..14b064864 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-dylink/main.mjs.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/webassembly-dylink/extensions.js", + "/tests/corpus/webassembly-dylink/main.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-jsapi.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-jsapi.mjs.json new file mode 100644 index 000000000..4f8ee17cf --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-jsapi.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/webassembly-jsapi.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-imports/main.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-imports/main.mjs.json new file mode 100644 index 000000000..a23646c06 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-spec-imports/main.mjs.json @@ -0,0 +1,8 @@ +{ + "order": [ + "/tests/wasm-spec/runner.mjs", + "/tests/corpus/webassembly-spec-imports/data.mjs", + "/tests/corpus/webassembly-spec-imports/main.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-wpt-jsapi.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-wpt-jsapi.mjs.json new file mode 100644 index 000000000..dd80857d8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/webassembly-wpt-jsapi.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/webassembly-wpt-jsapi.mjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_wasm.c b/packages/runtime/src/scr_wasm.c index 03d59604f..3110a9aa4 100644 --- a/packages/runtime/src/scr_wasm.c +++ b/packages/runtime/src/scr_wasm.c @@ -36,12 +36,16 @@ * LinkError or RuntimeError (not an own property, as in Node), which is * the brand instanceof tests. * - * Gaps (results/opt-wasm-design/DESIGN.md, stages W5-W7): no Memory, - * Table or Global constructors; Memory.grow does not detach the previous - * ArrayBuffer (the memory never moves, so old views stay valid with their - * old length); instances, their imports and exports are never freed (the - * cycle collector does not trace them yet); funcref values cross to - * JavaScript only as exported functions. */ + * The Memory, Table and Global constructors build the same objects an + * instance exports, so either kind can be imported; WebAssembly.Module. + * imports, exports and customSections read the descriptor. + * + * Gaps (results/opt-wasm-design/DESIGN.md, stages W6-W9): Memory.grow + * does not detach the previous ArrayBuffer (the memory never moves with + * guard pages, and explicit-bounds memories keep their previous blocks, so + * old views stay valid with their old length); shared memories are not + * constructed; instances, their imports and exports are never freed (the + * cycle collector does not trace them yet). */ #if !defined(_GNU_SOURCE) && defined(__linux__) #define _GNU_SOURCE /* REG_RIP and friends in */ #endif @@ -86,6 +90,14 @@ ScrDyn *scr_wasm_error_new(double kind, ScrDyn *message, ScrDyn *options); ScrDyn *scr_wasm_function(double kind); ScrDyn *scr_wasm_namespace(void); ScrDyn *scr_wasm_global_view(void); +ScrDyn *scr_wasm_memory_construct(ScrDyn *descriptor); +ScrDyn *scr_wasm_table_construct(ScrDyn *descriptor, ScrDyn *value); +ScrDyn *scr_wasm_global_construct(ScrDyn *descriptor, ScrDyn *value); +ScrDyn *scr_wasm_construct_without_new(double kind, ScrDyn *arg0, ScrDyn *arg1); +ScrDyn *scr_wasm_module_imports(ScrDyn *module); +ScrDyn *scr_wasm_module_exports(ScrDyn *module); +ScrDyn *scr_wasm_module_custom_sections(ScrDyn *module, ScrDyn *name); +ScrDyn *scr_wasm_value_of(ScrDyn *value); /* Entry points of translated code. */ /* Sanitized builds do not declare it noreturn: AddressSanitizer would @@ -135,6 +147,12 @@ typedef struct ScrWasmInst { bool *data_dropped; bool *elem_dropped; ScrDyn *exports; + /* The Memory, Table and Global objects of the instance, by index: the + * imported object itself, or the one created when the module exports it, + * so every export of the same index is the same object, as in V8. */ + ScrDyn *memory_obj; + ScrDyn **table_objs; + ScrDyn **global_objs; } ScrWasmInst; static ScrWasmInst *scr_wasm_host_of(void *inst) { return ((ScrWasmInst **)inst)[0]; } @@ -388,9 +406,10 @@ static void scr_wasm_set_stack_limit(void) { #endif } -/* Calls a thunk with traps caught; answers a SCR_WASM_TRAP_* code. */ -static __attribute__((noinline)) int scr_wasm_enter(ScrWasmThunk fn, void *inst, const uint64_t *args, - uint64_t *results) { +/* Calls a thunk (or `call` on `code`, a function reference's code) with + * traps caught; answers a SCR_WASM_TRAP_* code. */ +static __attribute__((noinline)) int scr_wasm_enter_ref(ScrWasmThunk fn, ScrWasmCallThunk call, void *ref_code, + void *inst, const uint64_t *args, uint64_t *results) { #if SCR_WASM_SIGNALS scr_wasm_thread_init(); #endif @@ -408,7 +427,8 @@ static __attribute__((noinline)) int scr_wasm_enter(ScrWasmThunk fn, void *inst, int code = 0; if (SCR_WASM_SETJMP(entry.jmp) == 0) { scr_wasm_running = true; - fn(inst, args, results); + if (call) call(ref_code, inst, args, results); + else fn(inst, args, results); } else { code = scr_wasm_trap_code; } @@ -418,6 +438,10 @@ static __attribute__((noinline)) int scr_wasm_enter(ScrWasmThunk fn, void *inst, return code; } +static int scr_wasm_enter(ScrWasmThunk fn, void *inst, const uint64_t *args, uint64_t *results) { + return scr_wasm_enter_ref(fn, NULL, NULL, inst, args, results); +} + static void scr_wasm_init_thunk(void *inst, const uint64_t *args, uint64_t *results) { (void)args; (void)results; @@ -644,6 +668,8 @@ static ScrWasmMemory *scr_wasm_memory_retain(ScrWasmMemory *m) { static void scr_wasm_memory_release(ScrWasmMemory *m) { if (!m || --m->rc) return; scr_dyn_release(m->buffer); + for (size_t i = 0; i < m->retired_count; i++) free(m->retired[i]); + free(m->retired); #if SCR_WASM_SIGNALS if (m->guarded) { scr_wasm_range_remove(m->base); @@ -654,14 +680,15 @@ static void scr_wasm_memory_release(ScrWasmMemory *m) { free(m); } -/* A memory of `min` pages growing to at most `max` pages; NULL with - * Node's RangeError pending when the address space or memory is short. */ +/* A memory of `min` pages growing to at most `max` pages (UINT64_MAX: + * no declared maximum); NULL with Node's RangeError pending when the + * address space or memory is short. */ static ScrWasmMemory *scr_wasm_memory_new(uint64_t min, uint64_t max, bool guarded, const char *what) { - if (max > SCR_WASM_MAX_PAGES) max = SCR_WASM_MAX_PAGES; ScrWasmMemory *m = calloc(1, sizeof *m); if (!m) scr_trap("scriptc: out of memory\n"); m->rc = 1; - m->max_pages = max; + m->declared_max = max; + m->max_pages = max > SCR_WASM_MAX_PAGES ? SCR_WASM_MAX_PAGES : max; m->size = min * SCR_WASM_PAGE; #if SCR_WASM_SIGNALS if (guarded) { @@ -712,9 +739,20 @@ static int64_t scr_wasm_memory_grow_by(ScrWasmMemory *m, uint64_t delta) { return (int64_t)old; } #endif - uint8_t *grown = realloc(m->base, size); + /* A new block, not realloc: ArrayBuffers created before the growth keep + * pointing into the old one, which stays alive with the memory. */ + uint8_t *grown = calloc(1, size); if (!grown) return -1; - memset(grown + m->size, 0, size - m->size); + if (m->base) { + uint8_t **retired = realloc(m->retired, (m->retired_count + 1) * sizeof *retired); + if (!retired) { + free(grown); + return -1; + } + memcpy(grown, m->base, m->size); + m->retired = retired; + m->retired[m->retired_count++] = m->base; + } m->base = grown; m->reserved = size; m->size = size; @@ -783,6 +821,7 @@ static ScrWasmTable *scr_wasm_table_new(char elem, uint64_t min, uint64_t max) { t->rc = 1; t->elem = elem; t->size = (uint32_t)min; + t->declared_max = max; t->max = max > SCR_WASM_MAX_TABLE ? SCR_WASM_MAX_TABLE : (uint32_t)max; t->elems = calloc(min ? min : 1, sizeof *t->elems); if (!t->elems) scr_trap("scriptc: out of memory\n"); @@ -1023,9 +1062,15 @@ static uint32_t scr_wasm_to_int32(double n) { static ScrWasmFuncRef *scr_wasm_funcref_of(const ScrDyn *v); +/* V8's message for a value that is neither null nor an exported + * WebAssembly function where a funcref is expected (behind a prefix that + * names the operation). */ +#define SCR_WASM_FUNCREF_EXPECTED "function-typed object must be null (if nullable) or a Wasm function object" + /* ToWebAssemblyValue: false with an exception pending. References are - * borrowed from `v`. */ -static bool scr_wasm_from_js(char t, const ScrDyn *v, uint64_t *out) { + * borrowed from `v`. A funcref mismatch throws a TypeError with + * `funcref_error` (the export-call message when NULL). */ +static bool scr_wasm_from_js_as(char t, const ScrDyn *v, uint64_t *out, const char *funcref_error) { if (!v) v = scr_dyn_undefined(); switch (t) { case 'i': { @@ -1063,7 +1108,7 @@ static bool scr_wasm_from_js(char t, const ScrDyn *v, uint64_t *out) { } ScrWasmFuncRef *ref = scr_wasm_funcref_of(v); if (!ref) { - scr_wasm_type_error("type incompatibility when transforming from/to JS"); + scr_wasm_type_error(funcref_error ? funcref_error : "type incompatibility when transforming from/to JS"); return false; } *out = (uint64_t)(uintptr_t)ref; @@ -1079,6 +1124,14 @@ static bool scr_wasm_from_js(char t, const ScrDyn *v, uint64_t *out) { } } +static bool scr_wasm_from_js(char t, const ScrDyn *v, uint64_t *out) { return scr_wasm_from_js_as(t, v, out, NULL); } + +/* DefaultValue(type): what a missing initial value of a constructed + * global or table, or a missing table.grow/set value, stands for. */ +static uint64_t scr_wasm_default_value(char t) { + return t == 'x' ? (uint64_t)(uintptr_t)scr_dyn_undefined() : 0; +} + static size_t scr_wasm_params(const char *sig) { size_t n = 0; while (sig[n] && sig[n] != ':') n++; @@ -1116,7 +1169,11 @@ static ScrDyn *scr_wasm_export_call(ScrClosure *clo, ScrDyn *const *args, size_t bool ok = true; for (size_t i = 0; i < np && ok; i++) ok = scr_wasm_from_js(sig[i], i < argc ? args[i] : NULL, &a[i]); if (ok) { - int trap = scr_wasm_enter(thunk, host->inst, a, r); + /* A function the module does not export runs through its signature's + * call thunk, on the code its reference record names. */ + int trap = thunk ? scr_wasm_enter(thunk, host->inst, a, r) + : scr_wasm_enter_ref(NULL, host->desc->func_call_thunks[func], host->funcrefs[func].code, + host->inst, a, r); if (trap) { scr_wasm_throw_trap(trap); } else if (nr == 0) { @@ -1134,18 +1191,20 @@ static ScrDyn *scr_wasm_export_call(ScrClosure *clo, ScrDyn *const *args, size_t return result; } -/* The function value of exported function `func` (+1), created once per - * instance and function; NULL with a TypeError pending for a function the - * module does not export (funcref values of other functions are stage W5). */ +/* The function value of function `func` (+1), created once per instance + * and function: exported functions call through their export thunk, other + * referenced functions through their signature's call thunk. */ static ScrDyn *scr_wasm_function_value(ScrWasmInst *host, uint32_t func) { if (host->export_fns[func]) return scr_dyn_retain(host->export_fns[func]); - bool exported = false; - for (uint64_t i = 0; i < host->desc->export_count; i++) { + bool callable = host->desc->func_call_thunks[func] != NULL && host->funcrefs[func].code != NULL; + for (uint64_t i = 0; i < host->desc->export_count && !callable; i++) { const ScrWasmExportDesc *ex = &host->desc->exports[i]; - if (ex->kind == SCR_WASM_FUNC && ex->index == func) exported = true; + if (ex->kind == SCR_WASM_FUNC && ex->index == func) callable = true; } - if (!exported) { - scr_wasm_type_error("WebAssembly function references to functions a module does not export are not supported yet"); + if (!callable) { + /* Unreachable for valid modules: every function a reference can name + * is exported or has a call thunk. */ + scr_wasm_type_error("type incompatibility when transforming from/to JS"); return NULL; } char name[24]; @@ -1268,7 +1327,8 @@ static bool scr_wasm_global_assign(ScrWasmGlobal *g, const ScrDyn *value) { return false; } uint64_t v; - if (!scr_wasm_from_js(g->type, value, &v)) return false; + if (!scr_wasm_from_js_as(g->type, value, &v, "set WebAssembly.Global.value): " SCR_WASM_FUNCREF_EXPECTED)) + return false; if (g->type == 'x') scr_wasm_global_set_ref(g, (void *)(uintptr_t)v); else g->value = v; return true; @@ -1283,12 +1343,20 @@ static bool scr_wasm_set(void *h, const char *key, size_t len, const ScrDyn *val return false; } +/* V8's EnforceUint32: ToNumber (its own TypeError for symbols and + * BigInts), then finite, non-negative and at most 2^32-1, truncated. + * `what` names the value ("WebAssembly.Memory.grow(): Argument 0", + * "WebAssembly.Memory(): Property 'initial'"). */ static bool scr_wasm_u32_arg(const ScrDyn *v, const char *what, uint32_t *out) { double n; if (!scr_dyn_number_coerce_js(v ? v : scr_dyn_undefined(), &n)) return false; - if (!isfinite(n) || n < 0 || trunc(n) > 4294967295.0) { + const char *problem = !isfinite(n) ? "must be convertible to a valid number" + : n < 0 ? "must be non-negative" + : trunc(n) > 4294967295.0 ? "must be in the unsigned long range" + : NULL; + if (problem) { char msg[200]; - snprintf(msg, sizeof msg, "%s must be convertible to a valid number", what); + snprintf(msg, sizeof msg, "%s %s", what, problem); scr_wasm_type_error(msg); return false; } @@ -1309,7 +1377,7 @@ static ScrDyn *scr_wasm_invoke(void *h, ScrDyn *self, const char *method, ScrDyn return NULL; } if (o->inst && o->inst->memory == o->memory) o->inst->inst[1] = o->memory->base; - /* The previous buffer keeps its length (no detachment yet, W5). */ + /* The previous buffer keeps its length (no detachment). */ scr_dyn_release(o->memory->buffer); o->memory->buffer = NULL; return scr_dyn_new_num((double)old); @@ -1338,15 +1406,26 @@ static ScrDyn *scr_wasm_invoke(void *h, ScrDyn *self, const char *method, ScrDyn scr_wasm_range_error(msg); return NULL; } - const ScrDyn *v = argc > 1 ? args[1] : (t->elem == 'x' ? scr_dyn_undefined() : scr_dyn_new_null()); - if (!scr_wasm_from_js(t->elem, v, &value)) return NULL; + if (argc > 1) { + if (!scr_wasm_from_js_as(t->elem, args[1], &value, + "WebAssembly.Table.set(): Argument 1 is invalid for table: " SCR_WASM_FUNCREF_EXPECTED)) + return NULL; + } else { + value = scr_wasm_default_value(t->elem); + } scr_wasm_table_store(t, index, (void *)(uintptr_t)value); return scr_dyn_retain(scr_dyn_undefined()); } if (!strcmp(method, "grow")) { uint32_t delta; if (!scr_wasm_u32_arg(argc ? args[0] : NULL, "WebAssembly.Table.grow(): Argument 0", &delta)) return NULL; - if (argc > 1 && !scr_wasm_from_js(t->elem, args[1], &value)) return NULL; + if (argc > 1) { + if (!scr_wasm_from_js_as(t->elem, args[1], &value, + "WebAssembly.Table.grow(): Argument 1 is invalid: " SCR_WASM_FUNCREF_EXPECTED)) + return NULL; + } else { + value = scr_wasm_default_value(t->elem); + } int64_t old = scr_wasm_table_grow_by(t, delta, (void *)(uintptr_t)value); if (old < 0) { char msg[160]; @@ -1569,10 +1648,30 @@ static ScrDyn *scr_wasm_instance_from(const ScrWasmModuleDesc *desc, ScrDyn *imp } for (uint64_t i = 0; ok && i < n; i++) { const ScrWasmImportDesc *im = &desc->imports[i]; - if (im->kind == SCR_WASM_MEMORY && !scr_wasm_unbox(values[i], SCR_WASM_K_MEMORY)) { + if (im->kind != SCR_WASM_MEMORY) continue; + ScrWasmObj *mo = scr_wasm_unbox(values[i], SCR_WASM_K_MEMORY); + if (!mo) { scr_wasm_link_error(what, i, im, "memory import must be a WebAssembly.Memory object"); ok = false; + break; } + /* V8's limit checks, with its messages (a missing maximum prints as + * the unsigned -1). */ + char reason[200]; + uint64_t pages = mo->memory->size / SCR_WASM_PAGE; + if (pages < desc->memory_min) { + snprintf(reason, sizeof reason, "memory import has %llu pages which is smaller than the declared initial of %llu", + (unsigned long long)pages, (unsigned long long)desc->memory_min); + } else if (desc->memory_max != UINT64_MAX && mo->memory->declared_max == UINT64_MAX) { + snprintf(reason, sizeof reason, "memory import has no maximum limit, expected at most 4294967295"); + } else if (desc->memory_max != UINT64_MAX && mo->memory->declared_max > desc->memory_max) { + snprintf(reason, sizeof reason, "memory import has a larger maximum size %llu than the module's declared maximum %llu", + (unsigned long long)mo->memory->declared_max, (unsigned long long)desc->memory_max); + } else { + continue; + } + scr_wasm_link_error(what, i, im, reason); + ok = false; } for (uint64_t i = 0; ok && i < n; i++) { const ScrWasmImportDesc *im = &desc->imports[i]; @@ -1587,9 +1686,26 @@ static ScrDyn *scr_wasm_instance_from(const ScrWasmModuleDesc *desc, ScrDyn *imp ok = false; } else if (im->kind == SCR_WASM_TABLE) { ScrWasmObj *t = scr_wasm_unbox(v, SCR_WASM_K_TABLE); + const ScrWasmTableDesc *td = &desc->tables[im->index]; if (!t) { scr_wasm_link_error(what, i, im, "table import requires a WebAssembly.Table"); ok = false; + } else if (t->table->size < td->min || (td->max != UINT64_MAX && t->table->declared_max > td->max)) { + /* V8's size checks name the import by number only; the imported + * maximum prints in hexadecimal. */ + char msg[300]; + if (t->table->size < td->min) + snprintf(msg, sizeof msg, "%s: table import %llu is smaller than initial %llu, got %u", what, + (unsigned long long)i, (unsigned long long)td->min, t->table->size); + else if (t->table->declared_max == UINT64_MAX) + snprintf(msg, sizeof msg, "%s: table import %llu has no maximum length; required: %llu", what, + (unsigned long long)i, (unsigned long long)td->max); + else + snprintf(msg, sizeof msg, "%s: table import %llu has a larger maximum size %llx than the module's declared maximum %llu", + what, (unsigned long long)i, (unsigned long long)t->table->declared_max, + (unsigned long long)td->max); + scr_wasm_throw_kind(SCR_WASM_LINK_ERROR, msg); + ok = false; } else if (t->table->elem != im->type[0]) { scr_wasm_link_error(what, i, im, "imported table does not match the expected type"); ok = false; @@ -1599,16 +1715,24 @@ static ScrDyn *scr_wasm_instance_from(const ScrWasmModuleDesc *desc, ScrDyn *imp bool mutable_ = desc->globals[im->index].mutable_ != 0; char type = im->type[0]; if (g) { - if (g->global->type != type || g->global->mutable_ != mutable_) { + if (g->global->mutable_ != mutable_) { + scr_wasm_link_error(what, i, im, "imported global does not match the expected mutability"); + ok = false; + } else if (g->global->type != type) { scr_wasm_link_error(what, i, im, "imported global does not match the expected type"); ok = false; } } else if (mutable_) { scr_wasm_link_error(what, i, im, "imported mutable global must be a WebAssembly.Global object"); ok = false; + } else if (type == 'r') { + if (!v || (v->kind != SCR_DYN_NULL && !scr_wasm_funcref_of(v))) { + scr_wasm_link_error(what, i, im, SCR_WASM_FUNCREF_EXPECTED); + ok = false; + } } else if (type == 'I' ? !(v && v->kind == SCR_DYN_BIGINT) - : type == 'x' || type == 'r' ? false - : !(v && v->kind == SCR_DYN_NUM)) { + : type == 'x' ? false + : !(v && v->kind == SCR_DYN_NUM)) { scr_wasm_link_error(what, i, im, "global import must be a number, valid Wasm reference, or WebAssembly.Global object"); ok = false; @@ -1636,8 +1760,11 @@ static ScrDyn *scr_wasm_instance_from(const ScrWasmModuleDesc *desc, ScrDyn *imp host->globals = calloc(desc->global_count ? desc->global_count : 1, sizeof *host->globals); host->data_dropped = calloc(desc->data_count ? desc->data_count : 1, 1); host->elem_dropped = calloc(desc->elem_count ? desc->elem_count : 1, 1); + host->table_objs = calloc(desc->table_count ? desc->table_count : 1, sizeof *host->table_objs); + host->global_objs = calloc(desc->global_count ? desc->global_count : 1, sizeof *host->global_objs); if (!host->inst || !host->funcs || !host->funcrefs || !host->export_fns || !host->export_names || - !host->tables || !host->globals || !host->data_dropped || !host->elem_dropped) + !host->tables || !host->globals || !host->data_dropped || !host->elem_dropped || !host->table_objs || + !host->global_objs) scr_trap("scriptc: out of memory\n"); void **inst = host->inst; inst[0] = host; @@ -1660,14 +1787,20 @@ static ScrDyn *scr_wasm_instance_from(const ScrWasmModuleDesc *desc, ScrDyn *imp break; case SCR_WASM_MEMORY: host->memory = scr_wasm_memory_retain(scr_wasm_unbox(v, SCR_WASM_K_MEMORY)->memory); + host->memory_obj = v; + values[i] = NULL; break; case SCR_WASM_TABLE: host->tables[im->index] = scr_wasm_table_retain(scr_wasm_unbox(v, SCR_WASM_K_TABLE)->table); + host->table_objs[im->index] = v; + values[i] = NULL; break; default: { ScrWasmObj *g = scr_wasm_unbox(v, SCR_WASM_K_GLOBAL); if (g) { host->globals[im->index] = scr_wasm_global_retain(g->global); + host->global_objs[im->index] = v; + values[i] = NULL; } else { char type = im->type[0]; ScrWasmGlobal *cell = scr_wasm_global_new(type, false); @@ -1684,9 +1817,7 @@ static ScrDyn *scr_wasm_instance_from(const ScrWasmModuleDesc *desc, ScrDyn *imp } free(values); if (desc->memory_count && !host->memory) { - host->memory = scr_wasm_memory_new(desc->memory_min, desc->memory_max == UINT64_MAX ? SCR_WASM_MAX_PAGES - : desc->memory_max, - scr_wasm_guarded(desc), what); + host->memory = scr_wasm_memory_new(desc->memory_min, desc->memory_max, scr_wasm_guarded(desc), what); if (!host->memory) return NULL; } if (host->memory) { @@ -1743,12 +1874,22 @@ static ScrDyn *scr_wasm_instance_from(const ScrWasmModuleDesc *desc, ScrDyn *imp int kind = ex->kind == SCR_WASM_MEMORY ? SCR_WASM_K_MEMORY : ex->kind == SCR_WASM_TABLE ? SCR_WASM_K_TABLE : SCR_WASM_K_GLOBAL; - ScrWasmObj *o = scr_wasm_obj_new(kind); - o->inst = scr_wasm_inst_retain(host); - if (kind == SCR_WASM_K_MEMORY) o->memory = scr_wasm_memory_retain(host->memory); - else if (kind == SCR_WASM_K_TABLE) o->table = scr_wasm_table_retain(host->tables[ex->index]); - else o->global = scr_wasm_global_retain(host->globals[ex->index]); - value = scr_wasm_box(o); + /* V8 exports an imported object itself, and one object per memory + * and table; a defined global gets a new object per export. */ + ScrDyn **slot = kind == SCR_WASM_K_MEMORY ? &host->memory_obj + : kind == SCR_WASM_K_TABLE ? &host->table_objs[ex->index] + : &host->global_objs[ex->index]; + if (*slot) { + value = scr_dyn_retain(*slot); + } else { + ScrWasmObj *o = scr_wasm_obj_new(kind); + o->inst = scr_wasm_inst_retain(host); + if (kind == SCR_WASM_K_MEMORY) o->memory = scr_wasm_memory_retain(host->memory); + else if (kind == SCR_WASM_K_TABLE) o->table = scr_wasm_table_retain(host->tables[ex->index]); + else o->global = scr_wasm_global_retain(host->globals[ex->index]); + value = scr_wasm_box(o); + if (kind != SCR_WASM_K_GLOBAL) *slot = scr_dyn_retain(value); + } } scr_dyn_obj_set(exports, ex->name, (size_t)ex->name_len, value); } @@ -1770,6 +1911,273 @@ ScrDyn *scr_wasm_instance_new(ScrDyn *module, ScrDyn *imports) { return scr_wasm_instance_from(m->desc, imports, "WebAssembly.Instance()"); } +/* ── constructors and Module's static functions ────────────────────── */ + +/* Memories the program constructs are guarded exactly when the translated + * modules are (every module of a build shares the mode), so any of them + * can import one. */ +static bool scr_wasm_build_guarded(void) { +#if SCR_WASM_SIGNALS + return scr_wasm_registry.count > 0 && !(scr_wasm_registry.modules[0]->flags & SCR_WASM_DESC_BOUNDS_CHECKS); +#else + return false; +#endif +} + +/* V8's GetOptionalIntegerProperty: the descriptor's `name` property as an + * unsigned 32-bit integer within [lower, upper]. An absent or undefined + * property leaves *out unchanged, or throws "is required" when + * `required`. False with an exception pending. */ +static bool scr_wasm_limit(const ScrDyn *descriptor, const char *name, bool required, const char *what, + uint64_t lower, uint64_t upper, uint64_t *out) { + ScrDyn *v = scr_wasm_member(descriptor, name, strlen(name)); + if (scr_exc_pending()) return false; + char msg[240]; + if (!v) { + if (!required) return true; + snprintf(msg, sizeof msg, "%s: Property '%s' is required", what, name); + scr_wasm_type_error(msg); + return false; + } + char label[120]; + snprintf(label, sizeof label, "%s: Property '%s'", what, name); + uint32_t n; + bool ok = scr_wasm_u32_arg(v, label, &n); + scr_dyn_release(v); + if (!ok) return false; + /* V8 prints the lower bound in hexadecimal. */ + if (n < lower) { + snprintf(msg, sizeof msg, "%s: Property '%s': value %u is below the lower bound %llx", what, name, n, + (unsigned long long)lower); + scr_wasm_range_error(msg); + return false; + } + if (n > upper) { + snprintf(msg, sizeof msg, "%s: Property '%s': value %u is above the upper bound %llu", what, name, n, + (unsigned long long)upper); + scr_wasm_range_error(msg); + return false; + } + *out = n; + return true; +} + +/* ToString of a descriptor's type property (+1; NULL with an exception + * pending). An absent property reads as "undefined". */ +static ScrStr *scr_wasm_type_name(const ScrDyn *descriptor, const char *name) { + ScrDyn *v = scr_wasm_member(descriptor, name, strlen(name)); + if (scr_exc_pending()) return NULL; + if (!v) return scr_str_new("undefined", 9); + ScrStr *s = scr_dyn_string_coerce_js(v); + scr_dyn_release(v); + return s; +} + +static bool scr_wasm_str_is(const ScrStr *s, const char *text) { + size_t n = strlen(text); + return s->len == n && !memcmp(s->data, text, n); +} + +/* A descriptor's boolean property (ToBoolean; false when absent). */ +static bool scr_wasm_flag(const ScrDyn *descriptor, const char *name, bool *out) { + ScrDyn *v = scr_wasm_member(descriptor, name, strlen(name)); + if (scr_exc_pending()) return false; + *out = v && scr_dyn_truthy(v); + scr_dyn_release(v); + return true; +} + +static bool scr_wasm_absent(const ScrDyn *v) { return !v || v->kind == SCR_DYN_UNDEF; } + +ScrDyn *scr_wasm_memory_construct(ScrDyn *descriptor) { + scr_wasm_install(); + const char *what = "WebAssembly.Memory()"; + if (!scr_wasm_is_object(descriptor)) { + scr_wasm_type_error("WebAssembly.Memory(): Argument 0 must be a memory descriptor"); + return NULL; + } + uint64_t initial = 0, maximum = UINT64_MAX; + bool shared; + if (!scr_wasm_limit(descriptor, "initial", true, what, 0, SCR_WASM_MAX_PAGES, &initial) || + !scr_wasm_limit(descriptor, "maximum", false, what, initial, SCR_WASM_MAX_PAGES, &maximum) || + !scr_wasm_flag(descriptor, "shared", &shared)) + return NULL; + if (shared && maximum == UINT64_MAX) { + scr_wasm_type_error("WebAssembly.Memory(): If shared is true, maximum property should be defined."); + return NULL; + } + if (shared) { + scr_wasm_type_error("WebAssembly.Memory(): shared memories are not supported yet (scriptc does not translate " + "WebAssembly threads; see https://scriptc.dev/limitations)"); + return NULL; + } + ScrWasmMemory *m = scr_wasm_memory_new(initial, maximum, scr_wasm_build_guarded(), what); + if (!m) return NULL; + ScrWasmObj *o = scr_wasm_obj_new(SCR_WASM_K_MEMORY); + o->memory = m; + return scr_wasm_box(o); +} + +ScrDyn *scr_wasm_table_construct(ScrDyn *descriptor, ScrDyn *value) { + scr_wasm_install(); + const char *what = "WebAssembly.Table()"; + if (!scr_wasm_is_object(descriptor)) { + scr_wasm_type_error("WebAssembly.Table(): Argument 0 must be a table descriptor"); + return NULL; + } + ScrStr *type = scr_wasm_type_name(descriptor, "element"); + if (!type) return NULL; + char elem = scr_wasm_str_is(type, "anyfunc") ? 'r' : scr_wasm_str_is(type, "externref") ? 'x' : 0; + scr_str_release(type); + if (!elem) { + scr_wasm_type_error("WebAssembly.Table(): Descriptor property 'element' must be a WebAssembly reference type"); + return NULL; + } + uint64_t initial = 0, maximum = UINT64_MAX; + if (!scr_wasm_limit(descriptor, "initial", true, what, 0, SCR_WASM_MAX_TABLE, &initial) || + !scr_wasm_limit(descriptor, "maximum", false, what, initial, 4294967295u, &maximum)) + return NULL; + uint64_t init = scr_wasm_default_value(elem); + if (!scr_wasm_absent(value) && + !scr_wasm_from_js_as(elem, value, &init, + "WebAssembly.Table(): Argument 2 must be undefined or a value of type compatible with the " + "type of the new table: " SCR_WASM_FUNCREF_EXPECTED ".")) + return NULL; + ScrWasmTable *t = scr_wasm_table_new(elem, initial, maximum); + for (uint32_t i = 0; i < t->size; i++) t->elems[i] = scr_wasm_ref_retain(elem, (void *)(uintptr_t)init); + ScrWasmObj *o = scr_wasm_obj_new(SCR_WASM_K_TABLE); + o->table = t; + return scr_wasm_box(o); +} + +ScrDyn *scr_wasm_global_construct(ScrDyn *descriptor, ScrDyn *value) { + scr_wasm_install(); + if (!scr_wasm_is_object(descriptor)) { + scr_wasm_type_error("WebAssembly.Global(): Argument 0 must be a global descriptor"); + return NULL; + } + bool mutable_; + if (!scr_wasm_flag(descriptor, "mutable", &mutable_)) return NULL; + ScrStr *name = scr_wasm_type_name(descriptor, "value"); + if (!name) return NULL; + static const char *const names[] = {"i32", "i64", "f32", "f64", "externref", "anyfunc"}; + static const char letters[] = {'i', 'I', 'f', 'F', 'x', 'r'}; + char type = 0; + for (size_t i = 0; i < sizeof letters; i++) + if (scr_wasm_str_is(name, names[i])) type = letters[i]; + bool v128 = scr_wasm_str_is(name, "v128"); + scr_str_release(name); + if (v128) { + scr_wasm_type_error("WebAssembly.Global(): A global of type 'v128' cannot be created in JavaScript"); + return NULL; + } + if (!type) { + scr_wasm_type_error("WebAssembly.Global(): Descriptor property 'value' must be a WebAssembly type"); + return NULL; + } + uint64_t v = scr_wasm_default_value(type); + if (!scr_wasm_absent(value) && + !scr_wasm_from_js_as(type, value, &v, "WebAssembly.Global(): " SCR_WASM_FUNCREF_EXPECTED)) + return NULL; + ScrWasmGlobal *g = scr_wasm_global_new(type, mutable_); + if (type == 'x') scr_wasm_global_set_ref(g, (void *)(uintptr_t)v); + else g->value = v; + ScrWasmObj *o = scr_wasm_obj_new(SCR_WASM_K_GLOBAL); + o->global = g; + return scr_wasm_box(o); +} + +/* `WebAssembly.Module(...)` and the other classes called without new. */ +ScrDyn *scr_wasm_construct_without_new(double kind, ScrDyn *arg0, ScrDyn *arg1) { + (void)arg0; + (void)arg1; + static const char *const names[] = {"Module", "Instance", "Memory", "Table", "Global"}; + const char *name = names[(int)kind]; + char msg[160]; + snprintf(msg, sizeof msg, "WebAssembly.%s(): WebAssembly.%s must be invoked with 'new'", name, name); + scr_wasm_type_error(msg); + return NULL; +} + +static const ScrWasmModuleDesc *scr_wasm_module_arg(const ScrDyn *v, const char *what) { + ScrWasmObj *m = scr_wasm_unbox(v, SCR_WASM_K_MODULE); + if (m) return m->desc; + char msg[160]; + snprintf(msg, sizeof msg, "%s: Argument 0 must be a WebAssembly.Module", what); + scr_wasm_type_error(msg); + return NULL; +} + +static void scr_wasm_set_text(ScrDyn *obj, const char *key, const char *text, size_t len) { + ScrStr *s = scr_str_new(text, len); + scr_dyn_obj_set(obj, key, strlen(key), scr_dyn_new_str(s)); + scr_str_release(s); +} + +static const char *const scr_wasm_kind_names[] = {"function", "table", "memory", "global"}; + +ScrDyn *scr_wasm_module_imports(ScrDyn *module) { + const ScrWasmModuleDesc *desc = scr_wasm_module_arg(module, "WebAssembly.Module.imports()"); + if (!desc) return NULL; + ScrDyn *out = scr_dyn_new_arr(); + for (uint64_t i = 0; i < desc->import_count; i++) { + const ScrWasmImportDesc *im = &desc->imports[i]; + ScrDyn *row = scr_dyn_new_obj(); + scr_wasm_set_text(row, "module", im->module, (size_t)im->module_len); + scr_wasm_set_text(row, "name", im->name, (size_t)im->name_len); + scr_wasm_set_text(row, "kind", scr_wasm_kind_names[im->kind], strlen(scr_wasm_kind_names[im->kind])); + scr_dyn_arr_push(out, row); + } + return out; +} + +ScrDyn *scr_wasm_module_exports(ScrDyn *module) { + const ScrWasmModuleDesc *desc = scr_wasm_module_arg(module, "WebAssembly.Module.exports()"); + if (!desc) return NULL; + ScrDyn *out = scr_dyn_new_arr(); + for (uint64_t i = 0; i < desc->export_count; i++) { + const ScrWasmExportDesc *ex = &desc->exports[i]; + ScrDyn *row = scr_dyn_new_obj(); + scr_wasm_set_text(row, "name", ex->name, (size_t)ex->name_len); + scr_wasm_set_text(row, "kind", scr_wasm_kind_names[ex->kind], strlen(scr_wasm_kind_names[ex->kind])); + scr_dyn_arr_push(out, row); + } + return out; +} + +/* A fresh ArrayBuffer per matching custom section, in module order. */ +ScrDyn *scr_wasm_module_custom_sections(ScrDyn *module, ScrDyn *name) { + const ScrWasmModuleDesc *desc = scr_wasm_module_arg(module, "WebAssembly.Module.customSections()"); + if (!desc) return NULL; + if (scr_wasm_absent(name)) { + scr_wasm_type_error("WebAssembly.Module.customSections(): Argument 1 is required"); + return NULL; + } + ScrStr *wanted = scr_dyn_string_coerce_js(name); + if (!wanted) return NULL; + ScrDyn *out = scr_dyn_new_arr(); + for (uint64_t i = 0; i < desc->custom_count; i++) { + const ScrWasmCustomDesc *c = &desc->customs[i]; + if (c->name_len != wanted->len || memcmp(c->name, wanted->data, wanted->len) != 0) continue; + ScrBytes *bytes = scr_bytes_from_data(c->data, (size_t)c->len); + scr_dyn_arr_push(out, scr_array_buffer_from_bytes(bytes)); + scr_bytes_release(bytes); + } + scr_str_release(wanted); + return out; +} + +/* `v.valueOf()` on a WebAssembly-typed receiver: a Global's value; any + * other value answers what the generic valueOf answers. */ +ScrDyn *scr_wasm_value_of(ScrDyn *value) { + ScrWasmObj *g = scr_wasm_unbox(value, SCR_WASM_K_GLOBAL); + if (g) return scr_wasm_global_value(g->global); + ScrStr *what = scr_str_new("valueOf", 7); + ScrDyn *out = scr_dyn_value_of(value, what); + scr_str_release(what); + return out; +} + /* ── promises ────────────────────────────────────────────────────────── */ /* A promise settled now: fulfilled with value, or rejected with the @@ -1958,6 +2366,11 @@ static void scr_wasm_teardown(void) { ScrWasmInst *host = scr_wasm_hosts[i]; const ScrWasmModuleDesc *desc = host->desc; scr_dyn_release(host->exports); + scr_dyn_release(host->memory_obj); + for (uint64_t t = 0; t < desc->table_count; t++) scr_dyn_release(host->table_objs[t]); + for (uint64_t g = 0; g < desc->global_count; g++) scr_dyn_release(host->global_objs[g]); + free(host->table_objs); + free(host->global_objs); for (uint64_t f = 0; f < desc->func_count; f++) { scr_dyn_release(host->export_fns[f]); scr_dyn_release(host->funcs[f]); diff --git a/packages/runtime/src/scr_wasm_abi.h b/packages/runtime/src/scr_wasm_abi.h index bd2a1e3bd..140fa7648 100644 --- a/packages/runtime/src/scr_wasm_abi.h +++ b/packages/runtime/src/scr_wasm_abi.h @@ -33,7 +33,7 @@ #include #include -#define SCR_WASM_ABI_VERSION 1 +#define SCR_WASM_ABI_VERSION 2 enum { SCR_WASM_FUNC = 0, SCR_WASM_TABLE = 1, SCR_WASM_MEMORY = 2, SCR_WASM_GLOBAL = 3 }; @@ -61,6 +61,9 @@ enum { #define SCR_WASM_DESC_BOUNDS_CHECKS 1u typedef void (*ScrWasmThunk)(void *inst, const uint64_t *args, uint64_t *results); +/* A signature's call thunk: calls `code` (a function of that signature, + * `(inst, params...) -> results`) with the arguments in slots. */ +typedef void (*ScrWasmCallThunk)(void *code, void *inst, const uint64_t *args, uint64_t *results); typedef struct { const char *module; @@ -111,6 +114,16 @@ typedef struct { const int64_t *items; } ScrWasmElemDesc; +/* A custom section: its name and payload, in module order. Only programs + * that call WebAssembly.Module.customSections carry them (the translator + * emits none otherwise, so debug sections cost nothing). */ +typedef struct { + const char *name; + uint64_t name_len; + const uint8_t *data; + uint64_t len; +} ScrWasmCustomDesc; + typedef struct ScrWasmModuleDesc { uint8_t sha256[32]; uint64_t byte_length; @@ -143,6 +156,12 @@ typedef struct ScrWasmModuleDesc { * guard; then the start function `void (inst)`, or NULL. */ void (*init)(void *inst); void (*start)(void *inst); + uint64_t custom_count; + const ScrWasmCustomDesc *customs; + /* Per function: the call thunk of its signature for referenced + * functions the module does not export (NULL otherwise), so any + * function reference can be called from JavaScript. */ + const ScrWasmCallThunk *func_call_thunks; } ScrWasmModuleDesc; /* The registry the compiler emits in the program module of every program @@ -163,6 +182,12 @@ typedef struct ScrWasmMemory { bool guarded; struct ScrDyn *buffer; /* the cached ArrayBuffer */ uint64_t buffer_size; /* the size it was created at */ + uint64_t declared_max; /* pages; UINT64_MAX when the memory has no maximum */ + /* Explicit-bounds memories (not guarded): the blocks grow replaced. + * ArrayBuffers created before a growth still point into them, so they + * live as long as the memory. */ + uint8_t **retired; + size_t retired_count; } ScrWasmMemory; typedef struct ScrWasmFuncRef { @@ -178,6 +203,7 @@ typedef struct ScrWasmTable { uint32_t max; size_t rc; char elem; /* 'r' or 'x' */ + uint64_t declared_max; /* UINT64_MAX when the table has no maximum */ } ScrWasmTable; /* A global's cell: the value in the low bytes of `value`. */ diff --git a/tests/corpus/webassembly-dylink/LICENSE.quickjs-wasi b/tests/corpus/webassembly-dylink/LICENSE.quickjs-wasi new file mode 100644 index 000000000..5a2e99d85 --- /dev/null +++ b/tests/corpus/webassembly-dylink/LICENSE.quickjs-wasi @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Vercel, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/tests/corpus/webassembly-dylink/extensions.js b/tests/corpus/webassembly-dylink/extensions.js new file mode 100644 index 000000000..8c6b26feb --- /dev/null +++ b/tests/corpus/webassembly-dylink/extensions.js @@ -0,0 +1,372 @@ +/** + * WASM Dynamic Linking - Extension Loader + * + * Loads WASM shared libraries (.so) compiled with wasi-sdk as extensions + * for the QuickJS WASM runtime. Extensions can call QuickJS C API functions + * directly through dynamic linking (shared memory + symbol resolution). + * + * Key concepts: + * - Extensions are WASM shared libraries with a `dylink.0` custom section + * - They share linear memory and the indirect function table with the main module + * - Symbol imports (env.*) are resolved against the main module's exports + * - Each extension gets a unique __memory_base and __table_base + * - Extensions export an init function (e.g., `qjs_ext_url_init`) + */ +const decoder = new TextDecoder(); +/** + * Parse a null-terminated "key=value\nkey=value" string from WASM memory + * into a Record. Used to read version info from extensions. + */ +function parseVersionString(memory, ptr) { + const mem = new Uint8Array(memory.buffer); + let end = ptr; + while (mem[end] !== 0) + end++; + if (end === ptr) + return {}; + const str = decoder.decode(mem.slice(ptr, end)); + const result = {}; + for (const line of str.split('\n')) { + const eq = line.indexOf('='); + if (eq > 0) { + result[line.slice(0, eq)] = line.slice(eq + 1); + } + } + return result; +} +/** + * Check if an extension exports a versions function and parse the result. + */ +function extractExtensionVersions(ext, memory) { + const versionsFnName = `qjs_ext_${ext.name.replace(/-/g, '_')}_versions`; + const versionsFn = ext.instance.exports[versionsFnName]; + if (typeof versionsFn !== 'function') + return undefined; + const ptr = versionsFn(); + if (ptr === 0) + return undefined; + return parseVersionString(memory, ptr); +} +// ---- dylink.0 parser ---- +/** Read a ULEB128-encoded integer from a byte array */ +function readULEB128(bytes, offset) { + let result = 0; + let shift = 0; + while (offset.value < bytes.length) { + const byte = bytes[offset.value++]; + result |= (byte & 0x7f) << shift; + if ((byte & 0x80) === 0) + break; + shift += 7; + } + return result; +} +/** Parse the dylink.0 custom section from a WASM module */ +export function parseDylink(module) { + const sections = WebAssembly.Module.customSections(module, 'dylink.0'); + if (sections.length === 0) + return null; + const bytes = new Uint8Array(sections[0]); + const offset = { value: 0 }; + const info = { + memorySize: 0, + memoryAlignment: 0, + tableSize: 0, + tableAlignment: 0, + needed: [], + }; + while (offset.value < bytes.length) { + const subsectionType = readULEB128(bytes, offset); + const subsectionSize = readULEB128(bytes, offset); + const subsectionEnd = offset.value + subsectionSize; + if (subsectionType === 1) { + // WASM_DYLINK_MEM_INFO + info.memorySize = readULEB128(bytes, offset); + info.memoryAlignment = readULEB128(bytes, offset); + info.tableSize = readULEB128(bytes, offset); + info.tableAlignment = readULEB128(bytes, offset); + } + else if (subsectionType === 2) { + // WASM_DYLINK_NEEDED + const count = readULEB128(bytes, offset); + for (let i = 0; i < count; i++) { + const len = readULEB128(bytes, offset); + const name = new TextDecoder().decode(bytes.slice(offset.value, offset.value + len)); + offset.value += len; + info.needed.push(name); + } + } + offset.value = subsectionEnd; + } + return info; +} +// ---- Alignment helper ---- +/** Align a value up to 2^align */ +function alignUp(value, align) { + if (align <= 0) + return value; + const mask = (1 << align) - 1; + return (value + mask) & ~mask; +} +// ---- Extension Loader ---- +/** + * Load a WASM shared library extension and link it against the main module. + * + * @param descriptor - Extension description (name, wasm bytes, init function) + * @param mainExports - The main QuickJS WASM module's exports + * @param wasiBuiltins - Built-in WASI implementations (lowest priority) + * @param wasiUserOverrides - User-provided WASI overrides (highest priority) + * @param memoryProxy - A memory proxy for extension WASI factories + * @param allocBase - Optional fixed memory/table bases (for snapshot restore) + */ +export async function loadExtension(descriptor, mainExports, wasiBuiltins, wasiUserOverrides, memoryProxy, allocBase) { + // Compile the extension module + let module; + if (descriptor.wasm instanceof WebAssembly.Module) { + module = descriptor.wasm; + } + else { + module = await WebAssembly.compile(descriptor.wasm); + } + // Parse dylink.0 section + const dylink = parseDylink(module); + if (!dylink) { + throw new Error(`Extension "${descriptor.name}" is not a WASM shared library (missing dylink.0 section)`); + } + const memory = mainExports.memory; + const table = mainExports.__indirect_function_table; + const stackPointer = mainExports.__stack_pointer; + const mallocFn = mainExports.malloc; + if (!memory) + throw new Error('Main module does not export memory'); + if (!table) + throw new Error('Main module does not export __indirect_function_table'); + if (!mallocFn) + throw new Error('Main module does not export malloc'); + // Allocate memory region for the extension's static data + let memoryBase; + let tableBase; + if (allocBase) { + // Restore mode: use the exact same bases as before + memoryBase = allocBase.memoryBase; + tableBase = allocBase.tableBase; + } + else { + // Fresh allocation + if (dylink.memorySize > 0) { + // Use malloc from the main module to allocate in the shared heap + memoryBase = mallocFn(dylink.memorySize); + if (memoryBase === 0) { + throw new Error(`Failed to allocate ${dylink.memorySize} bytes for extension "${descriptor.name}"`); + } + // Zero-initialize the region + new Uint8Array(memory.buffer, memoryBase, dylink.memorySize).fill(0); + } + else { + memoryBase = 0; + } + } + // Grow the function table if needed + if (allocBase) { + tableBase = allocBase.tableBase; + // Ensure table is large enough + if (tableBase + dylink.tableSize > table.length) { + table.grow(tableBase + dylink.tableSize - table.length); + } + } + else { + tableBase = table.length; + if (dylink.tableSize > 0) { + table.grow(dylink.tableSize); + } + } + // Build the import object + const extImports = WebAssembly.Module.imports(module); + const importObj = { + env: {}, + 'GOT.mem': {}, + 'GOT.func': {}, + }; + // Provide wasi_snapshot_preview1 imports to extensions that need them. + // Layered merge: builtins → extension-provided → user overrides. + const needsWasi = extImports.some((imp) => imp.module === 'wasi_snapshot_preview1'); + if (needsWasi) { + const extWasi = (descriptor.wasi && memoryProxy) ? descriptor.wasi(memoryProxy) : undefined; + importObj['wasi_snapshot_preview1'] = { + ...wasiBuiltins, // 1. Built-in defaults (lowest priority) + ...extWasi, // 2. Extension-provided + ...wasiUserOverrides // 3. User overrides (highest priority) + }; + } + // Collect names of functions the extension exports (for self-resolution) + const extExportNames = new Set(WebAssembly.Module.exports(module) + .filter((e) => e.kind === 'function') + .map((e) => e.name)); + const unresolvedFuncs = new Set(); + for (const imp of extImports) { + if (imp.module === 'env') { + if (imp.name === 'memory' && imp.kind === 'memory') { + importObj.env.memory = memory; + } + else if (imp.name === '__indirect_function_table' && + imp.kind === 'table') { + importObj.env.__indirect_function_table = table; + } + else if (imp.name === '__memory_base' && imp.kind === 'global') { + importObj.env.__memory_base = new WebAssembly.Global({ value: 'i32', mutable: false }, memoryBase); + } + else if (imp.name === '__table_base' && imp.kind === 'global') { + importObj.env.__table_base = new WebAssembly.Global({ value: 'i32', mutable: false }, tableBase); + } + else if (imp.name === '__stack_pointer' && imp.kind === 'global') { + importObj.env.__stack_pointer = stackPointer; + } + else if (imp.kind === 'function') { + // Resolve function imports from the main module's exports + const resolved = mainExports[imp.name]; + if (resolved && typeof resolved === 'function') { + importObj.env[imp.name] = resolved; + } + else { + // Provide a trap stub for unresolved symbols (e.g., C++ runtime + // functions like wstring methods that are imported but never called). + // If actually called at runtime, this will throw. + unresolvedFuncs.add(imp.name); + importObj.env[imp.name] = () => { + throw new Error(`Extension "${descriptor.name}" called unresolved symbol: env.${imp.name}`); + }; + } + } + else if (imp.kind === 'global') { + // Other globals - try to resolve from main exports + const resolved = mainExports[imp.name]; + if (resolved instanceof WebAssembly.Global) { + importObj.env[imp.name] = resolved; + } + else { + // Create a zero-initialized mutable global as fallback + importObj.env[imp.name] = new WebAssembly.Global({ value: 'i32', mutable: true }, 0); + } + } + } + else if (imp.module === 'GOT.mem' && imp.kind === 'global') { + // GOT.mem entries are mutable globals containing memory addresses of symbols + // Try to resolve the symbol's address - for now, create mutable globals + // that can be patched by __wasm_apply_data_relocs + importObj['GOT.mem'][imp.name] = new WebAssembly.Global({ value: 'i32', mutable: true }, 0); + } + else if (imp.module === 'GOT.func' && imp.kind === 'global') { + // GOT.func entries are mutable globals containing table indices of functions. + // We resolve these by finding the function in the main module's exports, + // adding it to the indirect function table, and providing the table index. + const resolved = mainExports[imp.name]; + if (resolved && typeof resolved === 'function') { + const idx = table.length; + table.grow(1); + table.set(idx, resolved); + importObj['GOT.func'][imp.name] = new WebAssembly.Global({ value: 'i32', mutable: true }, idx); + } + else { + importObj['GOT.func'][imp.name] = new WebAssembly.Global({ value: 'i32', mutable: true }, 0); + } + } + } + // Self-resolve: in WASM shared libraries, the linker with --allow-undefined + // may leave symbols as both imports and exports (e.g., C++ weak symbols from + // libc++ string.cpp.o that satisfy references from ada.o). We use indirection + // through mutable wrapper functions: first create wrappers that initially trap, + // then instantiate, then patch the wrappers to forward to the instance's own exports. + // This way all internal calls go through the wrappers which point to the final exports. + const selfResolvable = [...unresolvedFuncs].filter((name) => extExportNames.has(name)); + // For self-resolvable symbols, create mutable wrappers + const wrappers = {}; + for (const name of selfResolvable) { + const wrapper = { target: null }; + wrappers[name] = wrapper; + // Replace the trap stub with a wrapper that forwards to the target + importObj.env[name] = (...args) => { + if (!wrapper.target) { + throw new Error(`Extension "${descriptor.name}" called unresolved symbol during init: env.${name}`); + } + return wrapper.target(...args); + }; + } + const instance = await WebAssembly.instantiate(module, importObj); + const extExports = instance.exports; + // Patch wrappers to point to the instance's own exports + for (const name of selfResolvable) { + const selfExport = extExports[name]; + if (typeof selfExport === 'function') { + wrappers[name].target = selfExport; + } + } + // Apply data relocations if the extension has them + if (typeof extExports.__wasm_apply_data_relocs === 'function') { + extExports.__wasm_apply_data_relocs(); + } + // Call constructors if present + if (typeof extExports.__wasm_call_ctors === 'function') { + extExports.__wasm_call_ctors(); + } + const initFn = descriptor.initFn ?? `qjs_ext_${descriptor.name.replace(/-/g, '_')}_init`; + const ext = { + name: descriptor.name, + module, + instance, + dylink, + memoryBase, + tableBase, + initFn, + }; + // Check for version reporting + ext.versions = extractExtensionVersions(ext, memory); + return ext; +} +/** + * Call the extension's init function, passing the JSContext and JSRuntime + * pointers from the main module. + */ +export function initExtension(ext, mainExports) { + const initFunc = ext.instance.exports[ext.initFn]; + if (typeof initFunc !== 'function') { + throw new Error(`Extension "${ext.name}" does not export init function "${ext.initFn}"`); + } + // Get the JSContext and JSRuntime pointers from the main module + const ctxPtr = mainExports.qjs_get_context_ptr(); + const rtPtr = mainExports.qjs_get_runtime_ptr(); + // Call the extension's init function: qjs_ext_xxx_init(ctx, rt) + const result = initFunc(ctxPtr, rtPtr); + if (result !== 0) { + throw new Error(`Extension "${ext.name}" init function returned error code ${result}`); + } +} +/** + * Re-instantiate extensions for snapshot restore. + * + * During restore, we need to: + * 1. Instantiate extension modules with the same memory/table bases + * 2. Let them populate the function table (via elem segments and __wasm_apply_data_relocs) + * 3. Do NOT call the init function (the state is already in the snapshot memory) + * + * This reconstructs the function table entries that extensions need, without + * modifying linear memory (which will be overwritten by the snapshot). + */ +export async function restoreExtensions(descriptors, extensionMeta, mainExports, wasiBuiltins, wasiUserOverrides, memoryProxy) { + const loaded = []; + for (const meta of extensionMeta) { + // Find the descriptor for this extension + const descriptor = descriptors.find((d) => d.name === meta.name); + if (!descriptor) { + throw new Error(`Extension "${meta.name}" required by snapshot but not provided`); + } + // Load with fixed bases + const ext = await loadExtension(descriptor, mainExports, wasiBuiltins, wasiUserOverrides, memoryProxy, { + memoryBase: meta.memoryBase, + tableBase: meta.tableBase, + }); + ext.initFn = meta.initFn; + loaded.push(ext); + } + return loaded; +} +//# sourceMappingURL=extensions.js.map \ No newline at end of file diff --git a/tests/corpus/webassembly-dylink/main.mjs b/tests/corpus/webassembly-dylink/main.mjs new file mode 100644 index 000000000..42237b1f1 --- /dev/null +++ b/tests/corpus/webassembly-dylink/main.mjs @@ -0,0 +1,101 @@ +// quickjs-wasi's WebAssembly extension loader, run through its own code: +// extensions.js is dist/extensions.js of quickjs-wasi 3.6.2, unmodified +// (MIT, LICENSE.quickjs-wasi). It parses the dylink.0 custom section +// (WebAssembly.Module.customSections), reads the extension's imports and +// exports (Module.imports, Module.exports), allocates the extension's data +// in the main module's memory, grows the shared function table and stores +// main-module functions in it (table.grow, table.set), creates +// __memory_base, __table_base and GOT globals (new WebAssembly.Global), and +// instantiates the extension against the main module's memory, table and +// stack pointer. The two modules stand in for quickjs.wasm and an +// extension .so; their text is in tests/wasm-spec/corpus/dylink-*.wat. +import { initExtension, loadExtension, parseDylink } from "./extensions.js"; + +const mainBytes = Buffer.from( + "AGFzbQEAAAABEANgAX8Bf2AAAX9gAn9/AX8DBwYAAQECAgAEBAFwAAQFAwEAAgYTA38BQYCABAt/AUGACAt/AUEACweOAQkGbWVtb3J5AgAZX19pbmRpcmVjdF9mdW5jdGlvbl90YWJsZQEAD19fc3RhY2tfcG9pbnRlcgMABm1hbGxvYwAAE3Fqc19nZXRfY29udGV4dF9wdHIAARNxanNfZ2V0X3J1bnRpbWVfcHRyAAILanNfcmVnaXN0ZXIAAwdqc19jYWxsAAQGaGVscGVyAAUKXAYXAQF/IwEhASMBIABqQQ9qQXBxJAEgAQsFAEHkAAsFAEHIAQsZAEGABCMCQQRsaiABNgIAIwJBAWokAiMCCxMAIAFBgAQgAEEEbGooAgARAAALCAAgAEHoB2oL", + "base64", +); +const extBytes = Buffer.from( + "AGFzbQEAAAABEwRgAX8Bf2ACf38Bf2AAAGAAAX8C0AEKA2VudgZtZW1vcnkCAAEDZW52GV9faW5kaXJlY3RfZnVuY3Rpb25fdGFibGUBcAAAA2Vudg9fX3N0YWNrX3BvaW50ZXIDfwEDZW52DV9fbWVtb3J5X2Jhc2UDfwADZW52DF9fdGFibGVfYmFzZQN/AAdHT1QubWVtB2NvdW50ZXIDfwEIR09ULmZ1bmMGaGVscGVyA38BA2Vudgtqc19yZWdpc3RlcgABA2Vudg5taXNzaW5nX3N5bWJvbAAAA2VudgtzZWxmX3N5bWJvbAAAAwwLAAACAgEDAAAAAwMHogEJGF9fd2FzbV9hcHBseV9kYXRhX3JlbG9jcwAFEV9fd2FzbV9jYWxsX2N0b3JzAAYRcWpzX2V4dF9kZW1vX2luaXQABxVxanNfZXh0X2RlbW9fdmVyc2lvbnMACAtzZWxmX3N5bWJvbAAJCHVzZV9zZWxmAAoLdXNlX21pc3NpbmcACw1zdGFja19wb2ludGVyAAwMYnVtcF9jb3VudGVyAA0JCAEAIwILAgMECnYLBwAgAEEDbAsJACAAIwQRAAALCQAjAUEgaiQDCwkAIwNBBTYCAAsZACAAIwIQABogACMCQQFqEAAaIAFByAFrCwQAIwELBwAgAEEBagsGACAAEAILBgAgABABCwQAIwALFAAjAyMDKAIAQQFqNgIAIwMoAgALCxwBACMBCxZuYW1lPWRlbW8KdmVyc2lvbj0xLjIAABoIZHlsaW5rLjABBDACAgACCQEHbGliYy5zbw==", + "base64", +); +// A module without a dylink.0 section (tests/wasm-spec/corpus/jsapi-own.wat). +const plainBytes = Buffer.from( + "AGFzbQEAAAABBgFgAX8BfwMCAQAEBQFwAQIIBQQBAQEEBhICfwFBBwt8AEQAAAAAAAD4PwsHKgcDbWVtAgAEbWVtMgIAA3RhYgEAAWcDAAJnMgMABWZpeGVkAwECaWQAAAkHAQBBAQsBAAoGAQQAIAAL", + "base64", +); + +const failure = (e) => (e instanceof Error ? `${e.name}: ${e.message}` : `threw ${String(e)}`); + +const { instance } = await WebAssembly.instantiate(mainBytes, {}); +const mainExports = instance.exports; +const table = mainExports.__indirect_function_table; + +console.log("dylink", JSON.stringify(parseDylink(new WebAssembly.Module(extBytes)))); +console.log("plain dylink", parseDylink(new WebAssembly.Module(plainBytes))); + +const ext = await loadExtension({ name: "demo", wasm: extBytes }, mainExports, {}, {}, null); +console.log("loaded", ext.name, ext.memoryBase, ext.tableBase, ext.initFn); +console.log("versions", JSON.stringify(ext.versions)); +console.log("dylink", JSON.stringify(ext.dylink)); +console.log("table length", table.length, table.get(6) === mainExports.helper); +// The extension's own functions in the shared table, called from here. +const triple = table.get(4); +console.log("table functions", triple(14), table.get(5) === table.get(5), triple.name, triple.length); +console.log("module", ext.module instanceof WebAssembly.Module, ext.instance instanceof WebAssembly.Instance); + +initExtension(ext, mainExports); +console.log("js_call", mainExports.js_call(0, 7), mainExports.js_call(1, 5)); +const x = ext.instance.exports; +console.log("self symbol", x.use_self(41)); +try { + x.use_missing(1); +} catch (e) { + console.log("missing symbol", failure(e)); +} +console.log("stack pointer", x.stack_pointer(), mainExports.__stack_pointer.value); +mainExports.__stack_pointer.value = 60000; +console.log("shared stack pointer", x.stack_pointer()); +console.log("counter", x.bump_counter(), x.bump_counter()); +console.log("memory", new Uint32Array(mainExports.memory.buffer, ext.memoryBase + 32, 1)[0]); + +// Snapshot restore (what restoreExtensions does per extension): the same +// bases, from a compiled Module, without init. +const restored = await loadExtension( + { name: "demo", wasm: new WebAssembly.Module(extBytes) }, + mainExports, + {}, + {}, + null, + { memoryBase: ext.memoryBase, tableBase: ext.tableBase }, +); +console.log("restored", restored.memoryBase, restored.tableBase, table.length); +console.log("restored counter", restored.instance.exports.bump_counter()); + +// A second extension instance gets its own bases. +const second = await loadExtension({ name: "demo", wasm: extBytes }, mainExports, {}, {}, null); +console.log("second", second.memoryBase, second.tableBase, table.length); +initExtension(second, mainExports); +console.log("js_call", mainExports.js_call(2, 10), mainExports.js_call(3, 10)); + +async function tryLoad(label, wasm, exports) { + try { + await loadExtension({ name: label, wasm }, exports, {}, {}, null); + console.log(label, "loaded"); + } catch (e) { + console.log(label, failure(e)); + } +} +await tryLoad("plain", plainBytes, mainExports); +await tryLoad("no memory", extBytes, { ...mainExports, memory: undefined }); +await tryLoad("no table", extBytes, { ...mainExports, __indirect_function_table: undefined }); +try { + initExtension({ ...ext, initFn: "qjs_ext_none_init" }, mainExports); +} catch (e) { + console.log("init", failure(e)); +} +try { + initExtension(ext, { ...mainExports, qjs_get_runtime_ptr: () => 201 }); +} catch (e) { + console.log("init", failure(e)); +} diff --git a/tests/corpus/webassembly-jsapi.mjs b/tests/corpus/webassembly-jsapi.mjs new file mode 100644 index 000000000..ad9739972 --- /dev/null +++ b/tests/corpus/webassembly-jsapi.mjs @@ -0,0 +1,356 @@ +// The WebAssembly JavaScript API's constructors and reflection: new +// WebAssembly.Memory, Table and Global (descriptors, defaults, conversions +// and every error), using them as imports (limits, types and mutability +// checked with Node's LinkError messages), the identity of exported +// objects, WebAssembly.Module.imports, exports and customSections, and the +// classes called without new. The modules are inline base64 literals +// (their text is in tests/wasm-spec/corpus/jsapi.wat and jsapi-own.wat). +const jsapi = Buffer.from("AGFzbQEAAAABKglgAX8Bf2ABfwBgAAF/YAF8AXxgAX4AYAABb2ABbwBgAn9/AX9gAn9/AAJbBwNlbnYDbG9nAAEDZW52Bm1lbW9yeQIBAQQDZW52BXRhYmxlAXABAggDZW52B2NvdW50ZXIDfwEDZW52BXNjYWxlA3wAA2VudgNiaWcDfgEDZW52A3JlZgNvAQMPDgAAAgMEBQYHCAACAAIBB5UBEQRidW1wAAMGc2NhbGVkAAQGYmlnQWRkAAUGZ2V0UmVmAAYGc2V0UmVmAAcFYXBwbHkACAVzdG9yZQAJBGxvYWQACgRzaXplAAsEZ3JvdwAMCXRhYmxlU2l6ZQANA3NheQAOBm1lbW9yeQIABXRhYmxlAQAHY291bnRlcgMAC2Fsc29Db3VudGVyAwAGZG91YmxlAAEJCAEAQQALAgECCnAOBwAgAEECbAsHACAAIABsCwsAIwBBAWokACMACwcAIAAjAaILCQAjAiAAfCQCCwQAIwMLBgAgACQDCwkAIAEgABEAAAsJACAAIAE6AAALBwAgAC0AAAsEAD8ACwYAIABAAAsFAPwQAAsGACAAEAALAAwIZHlsaW5rLjABAgMACgRtZXRhaGVsbG8ACwhkeWxpbmsuMAQFAAEA", "base64"); +const own = Buffer.from("AGFzbQEAAAABBgFgAX8BfwMCAQAEBQFwAQIIBQQBAQEEBhICfwFBBwt8AEQAAAAAAAD4PwsHKgcDbWVtAgAEbWVtMgIAA3RhYgEAAWcDAAJnMgMABWZpeGVkAwECaWQAAAkHAQBBAQsBAAoGAQQAIAAL", "base64"); + +const show = (v) => { + if (typeof v === "bigint") return `${v}n`; + if (typeof v === "number") return Object.is(v, -0) ? "-0" : String(v); + if (typeof v === "function") return "function"; + if (Array.isArray(v)) return `[${v.map(show).join(", ")}]`; + if (v instanceof WebAssembly.Memory) return "Memory"; + if (v instanceof WebAssembly.Table) return "Table"; + if (v instanceof WebAssembly.Global) return "Global"; + if (v instanceof ArrayBuffer) return `ArrayBuffer(${v.byteLength})`; + if (v !== null && typeof v === "object") return JSON.stringify(v); + return String(v); +}; +const attempt = (label, f) => { + try { + console.log(label, show(f())); + } catch (e) { + console.log(label, e instanceof Error ? `${e.name}: ${e.message}` : `threw ${show(e)}`); + } +}; + +// ── WebAssembly.Global ──────────────────────────────────────────────────── +console.log("Global"); +attempt("i32 default", () => new WebAssembly.Global({ value: "i32" }).value); +attempt("i64 default", () => new WebAssembly.Global({ value: "i64" }).value); +attempt("f32", () => new WebAssembly.Global({ value: "f32" }, 1.1).value); +attempt("f64", () => new WebAssembly.Global({ value: "f64" }, 1.1).value); +attempt("f64 undefined", () => new WebAssembly.Global({ value: "f64" }, undefined).value); +attempt("f64 null", () => new WebAssembly.Global({ value: "f64" }, null).value); +attempt("i32 string", () => new WebAssembly.Global({ value: "i32" }, "7").value); +attempt("i32 wraps", () => new WebAssembly.Global({ value: "i32" }, 2 ** 32 + 3).value); +attempt("i32 object", () => new WebAssembly.Global({ value: "i32" }, { valueOf: () => 9 }).value); +attempt("i64 bigint", () => new WebAssembly.Global({ value: "i64" }, 2n ** 63n).value); +attempt("i64 string", () => new WebAssembly.Global({ value: "i64" }, "12").value); +attempt("i64 number", () => new WebAssembly.Global({ value: "i64" }, 5).value); +attempt("i64 null", () => new WebAssembly.Global({ value: "i64" }, null).value); +attempt("i32 bigint", () => new WebAssembly.Global({ value: "i32" }, 5n).value); +attempt("externref default", () => new WebAssembly.Global({ value: "externref" }).value); +attempt("externref object", () => new WebAssembly.Global({ value: "externref" }, { a: 1 }).value); +attempt("anyfunc default", () => new WebAssembly.Global({ value: "anyfunc" }).value); +attempt("anyfunc arrow", () => new WebAssembly.Global({ value: "anyfunc" }, () => 1)); +attempt("anyfunc number", () => new WebAssembly.Global({ value: "anyfunc" }, 1)); +attempt("funcref name", () => new WebAssembly.Global({ value: "funcref" })); +attempt("v128", () => new WebAssembly.Global({ value: "v128" })); +attempt("bad type", () => new WebAssembly.Global({ value: "i16" })); +attempt("no value", () => new WebAssembly.Global({})); +attempt("no descriptor", () => new WebAssembly.Global()); +attempt("number descriptor", () => new WebAssembly.Global(1)); +attempt("toString type", () => new WebAssembly.Global({ value: { toString: () => "f64" } }, 2.5).value); +const order = []; +new WebAssembly.Global( + { + get value() { + order.push("value"); + return { toString: () => (order.push("value toString"), "f64") }; + }, + get mutable() { + order.push("mutable"); + return false; + }, + }, + { valueOf: () => (order.push("valueOf"), 1) }, +); +console.log("order", order.join(",")); +const immutable = new WebAssembly.Global({ value: "i32" }, 4); +attempt("immutable set", () => { + immutable.value = 5; +}); +console.log("immutable after", immutable.value, immutable.valueOf()); +const mutable = new WebAssembly.Global({ value: "i32", mutable: 1 }, 4); +mutable.value = 2.9; +console.log("mutable", mutable.value, mutable.valueOf()); +mutable.value = "x"; +console.log("mutable NaN", mutable.value); +const mutable64 = new WebAssembly.Global({ value: "i64", mutable: true }); +mutable64.value = true; +console.log("mutable64", show(mutable64.value)); +attempt("i64 set number", () => { + mutable64.value = 3; +}); +const mutableF32 = new WebAssembly.Global({ value: "f32", mutable: true }, 1); +mutableF32.value = undefined; +console.log("f32 set undefined", mutableF32.value); +const mutableRef = new WebAssembly.Global({ value: "externref", mutable: true }, "start"); +mutableRef.value = undefined; +console.log("externref set undefined", mutableRef.value); +const mutableFunc = new WebAssembly.Global({ value: "anyfunc", mutable: true }); +attempt("anyfunc set arrow", () => { + mutableFunc.value = () => 2; +}); +console.log(String(immutable), Object.prototype.toString.call(immutable), immutable instanceof WebAssembly.Global); +console.log(immutable); +// @ts-ignore: called without new, as Node reports +attempt("Global()", () => WebAssembly.Global({ value: "i32" })); + +// ── WebAssembly.Memory ──────────────────────────────────────────────────── +console.log("Memory"); +attempt("bytes", () => new WebAssembly.Memory({ initial: 1 }).buffer.byteLength); +attempt("zero", () => new WebAssembly.Memory({ initial: 0 }).buffer.byteLength); +attempt("string initial", () => new WebAssembly.Memory({ initial: "2" }).buffer.byteLength); +attempt("fractional", () => new WebAssembly.Memory({ initial: 1.9 }).buffer.byteLength); +attempt("null initial", () => new WebAssembly.Memory({ initial: null }).buffer.byteLength); +attempt("missing", () => new WebAssembly.Memory({})); +attempt("minimum only", () => new WebAssembly.Memory({ minimum: 1 })); +attempt("undefined initial", () => new WebAssembly.Memory({ initial: undefined })); +attempt("negative", () => new WebAssembly.Memory({ initial: -1 })); +attempt("negative fraction", () => new WebAssembly.Memory({ initial: -0.5 })); +attempt("NaN", () => new WebAssembly.Memory({ initial: NaN })); +attempt("Infinity", () => new WebAssembly.Memory({ initial: Infinity })); +attempt("2^32", () => new WebAssembly.Memory({ initial: 2 ** 32 })); +attempt("too many pages", () => new WebAssembly.Memory({ initial: 65537 })); +attempt("max below initial", () => new WebAssembly.Memory({ initial: 20, maximum: 1 })); +attempt("max too large", () => new WebAssembly.Memory({ initial: 1, maximum: 65537 })); +attempt("max 2^32", () => new WebAssembly.Memory({ initial: 1, maximum: 2 ** 32 })); +attempt("max null", () => new WebAssembly.Memory({ initial: 1, maximum: null })); +attempt("bigint initial", () => new WebAssembly.Memory({ initial: 1n })); +attempt("throwing initial", () => + new WebAssembly.Memory({ + initial: { + valueOf() { + throw new Error("boom"); + }, + }, + }), +); +attempt("shared without maximum", () => new WebAssembly.Memory({ initial: 1, shared: true })); +attempt("no descriptor", () => new WebAssembly.Memory()); +attempt("string descriptor", () => new WebAssembly.Memory("x")); +const memoryOrder = []; +new WebAssembly.Memory({ + get initial() { + memoryOrder.push("initial"); + return { valueOf: () => (memoryOrder.push("initial valueOf"), 1) }; + }, + get maximum() { + memoryOrder.push("maximum"); + return { valueOf: () => (memoryOrder.push("maximum valueOf"), 3) }; + }, + get shared() { + memoryOrder.push("shared"); + return false; + }, +}); +console.log("order", memoryOrder.join(",")); +const grown = new WebAssembly.Memory({ initial: 1, maximum: 2 }); +const before = grown.buffer; +new Uint8Array(before)[5] = 7; +console.log("same buffer", grown.buffer === grown.buffer); +attempt("grow", () => grown.grow(1)); +console.log("after grow", grown.buffer.byteLength, new Uint8Array(grown.buffer)[5], before === grown.buffer); +attempt("grow past maximum", () => grown.grow(1)); +attempt("grow negative", () => grown.grow(-1)); +attempt("grow missing", () => grown.grow()); +attempt("grow NaN", () => grown.grow(NaN)); +attempt("grow 2^32", () => grown.grow(2 ** 32)); +attempt("grow zero", () => grown.grow(0)); +attempt("unbounded grow", () => new WebAssembly.Memory({ initial: 1, maximum: undefined }).grow(3)); +console.log(String(grown), grown instanceof WebAssembly.Memory); +console.log(grown); +// @ts-ignore: called without new, as Node reports +attempt("Memory()", () => WebAssembly.Memory({ initial: 1 })); + +// ── WebAssembly.Table ───────────────────────────────────────────────────── +console.log("Table"); +attempt("anyfunc", () => new WebAssembly.Table({ initial: 2, element: "anyfunc" }).get(1)); +attempt("externref", () => new WebAssembly.Table({ initial: 1, element: "externref" }).get(0)); +attempt("externref init", () => new WebAssembly.Table({ initial: 2, element: "externref" }, "hi").get(1)); +attempt("externref undefined", () => new WebAssembly.Table({ initial: 2, element: "externref" }, undefined).get(1)); +attempt("anyfunc null", () => new WebAssembly.Table({ initial: 2, element: "anyfunc" }, null).get(1)); +attempt("anyfunc arrow", () => new WebAssembly.Table({ initial: 2, element: "anyfunc" }, () => 1)); +attempt("anyfunc number", () => new WebAssembly.Table({ initial: 2, element: "anyfunc" }, 5)); +attempt("funcref name", () => new WebAssembly.Table({ initial: 1, element: "funcref" })); +attempt("i32 element", () => new WebAssembly.Table({ initial: 1, element: "i32" })); +attempt("no element", () => new WebAssembly.Table({ initial: 1 })); +attempt("no initial", () => new WebAssembly.Table({ element: "anyfunc" })); +// @ts-ignore: an incomplete descriptor +attempt("empty", () => new WebAssembly.Table({})); +attempt("no descriptor", () => new WebAssembly.Table()); +attempt("max below initial", () => new WebAssembly.Table({ initial: 2, maximum: 1, element: "anyfunc" })); +attempt("bad init and descriptor", () => new WebAssembly.Table({ initial: 3, maximum: 2, element: "anyfunc" }, 37)); +attempt("too large", () => new WebAssembly.Table({ initial: 10000001, element: "anyfunc" })); +attempt("large maximum", () => new WebAssembly.Table({ initial: 1, maximum: 10000001, element: "anyfunc" }).length); +attempt("max 2^32", () => new WebAssembly.Table({ initial: 1, maximum: 2 ** 32, element: "anyfunc" })); +attempt("toString element", () => new WebAssembly.Table({ element: { toString: () => "anyfunc" }, initial: 1 }).length); +const tableOrder = []; +new WebAssembly.Table({ + get element() { + tableOrder.push("element"); + return { toString: () => (tableOrder.push("element toString"), "anyfunc") }; + }, + get initial() { + tableOrder.push("initial"); + return { valueOf: () => (tableOrder.push("initial valueOf"), 1) }; + }, + get maximum() { + tableOrder.push("maximum"); + return { valueOf: () => (tableOrder.push("maximum valueOf"), 3) }; + }, +}); +console.log("order", tableOrder.join(",")); +const refs = new WebAssembly.Table({ initial: 1, maximum: 4, element: "externref" }, 3); +attempt("set default", () => { + refs.set(0); + return refs.get(0); +}); +attempt("grow default", () => [refs.grow(1), refs.get(1), refs.length]); +attempt("grow value", () => [refs.grow(1, "z"), refs.get(2), refs.length]); +attempt("grow past maximum", () => refs.grow(2)); +attempt("get negative", () => refs.get(-1)); +attempt("get missing", () => refs.get()); +attempt("get out of range", () => refs.get(5)); +attempt("set out of range", () => refs.set(9, 1)); +const funcs = new WebAssembly.Table({ initial: 1, element: "anyfunc" }); +attempt("set arrow", () => funcs.set(0, () => 1)); +attempt("set number", () => funcs.set(0, 7)); +attempt("grow arrow", () => funcs.grow(1, () => 1)); +attempt("grow negative", () => funcs.grow(-1)); +console.log(String(funcs), funcs instanceof WebAssembly.Table); +console.log(funcs); +// @ts-ignore: called without new, as Node reports +attempt("Table()", () => WebAssembly.Table({ initial: 1, element: "anyfunc" })); + +// ── WebAssembly.Module's static functions ──────────────────────────────── +console.log("Module"); +const module = new WebAssembly.Module(jsapi); +console.log(JSON.stringify(WebAssembly.Module.imports(module))); +console.log(JSON.stringify(WebAssembly.Module.exports(module))); +const firstImport = WebAssembly.Module.imports(module)[0]; +console.log(Object.keys(firstImport).join(","), Array.isArray(WebAssembly.Module.imports(module))); +firstImport.module = "changed"; +console.log("fresh", WebAssembly.Module.imports(module)[0].module); +const dylink = WebAssembly.Module.customSections(module, "dylink.0"); +console.log( + "dylink.0", + dylink.length, + dylink.map((b) => `${show(b)} ${[...new Uint8Array(b)].join(" ")}`).join(" | "), +); +console.log("meta", new TextDecoder().decode(WebAssembly.Module.customSections(module, "meta")[0])); +console.log("empty name", WebAssembly.Module.customSections(module, "").length); +console.log("missing", WebAssembly.Module.customSections(module, "nope").length); +console.log("toString", WebAssembly.Module.customSections(module, { toString: () => "meta" }).length); +console.log("null", WebAssembly.Module.customSections(module, null).length); +const copy = WebAssembly.Module.customSections(module, "meta")[0]; +new Uint8Array(copy)[0] = 0; +console.log( + "copies", + new Uint8Array(WebAssembly.Module.customSections(module, "meta")[0])[0], + copy === WebAssembly.Module.customSections(module, "meta")[0], +); +attempt("customSections missing name", () => WebAssembly.Module.customSections(module)); +attempt("customSections symbol", () => WebAssembly.Module.customSections(module, Symbol("x"))); +attempt("customSections number", () => WebAssembly.Module.customSections(1, "x")); +attempt("imports object", () => WebAssembly.Module.imports({})); +attempt("exports missing", () => WebAssembly.Module.exports()); +attempt("imports stray", () => WebAssembly.Module.imports(module, 1).length); +console.log("own", JSON.stringify(WebAssembly.Module.imports(new WebAssembly.Module(own)))); +console.log("own", JSON.stringify(WebAssembly.Module.exports(new WebAssembly.Module(own)))); +// @ts-ignore: called without new, as Node reports +attempt("Module()", () => WebAssembly.Module(jsapi)); +// @ts-ignore: called without new, as Node reports +attempt("Instance()", () => WebAssembly.Instance(module, {})); + +// ── constructed objects as imports ──────────────────────────────────────── +console.log("imports"); +const logged = []; +const memory = new WebAssembly.Memory({ initial: 1, maximum: 4 }); +const table = new WebAssembly.Table({ initial: 2, maximum: 8, element: "anyfunc" }); +const counter = new WebAssembly.Global({ value: "i32", mutable: true }, 10); +const big = new WebAssembly.Global({ value: "i64", mutable: true }, 1n); +const ref = new WebAssembly.Global({ value: "externref", mutable: true }, "first"); +const env = { log: (v) => logged.push(v), memory, table, counter, scale: 2.5, big, ref }; +const instance = new WebAssembly.Instance(module, { env }); +const x = instance.exports; +console.log( + "identity", + x.memory === memory, + x.table === table, + x.counter === counter, + x.alsoCounter === counter, +); +attempt("bump", () => [x.bump(), x.bump(), counter.value]); +counter.value = 100; +attempt("bump after set", () => x.bump()); +attempt("scaled", () => x.scaled(4)); +x.bigAdd(41n); +console.log("big", show(big.value)); +attempt("getRef", () => x.getRef()); +x.setRef({ hello: "world" }); +console.log("ref", JSON.stringify(ref.value)); +ref.value = 42; +attempt("getRef after set", () => x.getRef()); +attempt("apply double", () => x.apply(0, 21)); +attempt("apply square", () => x.apply(1, 12)); +console.log("table get", table.get(0) === x.double); +// A function the module does not export, reached through the table. +const square = table.get(1); +console.log("unexported", square(5), square === table.get(1), square.name, square.length, typeof square); +x.store(3, 99); +console.log("memory", new Uint8Array(memory.buffer)[3], x.load(3)); +new Uint8Array(memory.buffer)[4] = 55; +console.log("memory from js", x.load(4)); +attempt("grow in wasm", () => [x.grow(1), x.size(), memory.buffer.byteLength]); +attempt("grow from js", () => [memory.grow(1), x.size(), memory.buffer.byteLength]); +attempt("table grow", () => [table.grow(2), x.tableSize(), table.length]); +const global = new WebAssembly.Global({ value: "anyfunc", mutable: true }, x.double); +console.log("funcref global", global.value === x.double); +global.value = null; +console.log("funcref null", global.value); +table.set(1, x.double); +attempt("apply after set", () => x.apply(1, 8)); +x.say(5); +console.log("logged", logged.join(",")); + +// Another instance's exports as imports, and the same objects again. +const provider = new WebAssembly.Instance(new WebAssembly.Module(own)).exports; +console.log("own identity", provider.mem === provider.mem2, provider.g === provider.g2, provider.mem instanceof WebAssembly.Memory); +const second = new WebAssembly.Instance(module, { + env: { ...env, memory: provider.mem, table: provider.tab, counter: provider.g }, +}).exports; +console.log("re-exported", second.memory === provider.mem, second.table === provider.tab, second.counter === provider.g); +attempt("bump provider global", () => [second.bump(), provider.g.value]); +attempt("apply provider table", () => second.apply(1, 3)); + +// ── link errors ─────────────────────────────────────────────────────────── +console.log("link errors"); +const link = (label, overrides) => + attempt(label, () => new WebAssembly.Instance(module, { env: { ...env, ...overrides } }) && "linked"); +link("memory too small", { memory: new WebAssembly.Memory({ initial: 0, maximum: 4 }) }); +link("memory without maximum", { memory: new WebAssembly.Memory({ initial: 1 }) }); +link("memory maximum too large", { memory: new WebAssembly.Memory({ initial: 1, maximum: 5 }) }); +link("memory larger initial", { memory: new WebAssembly.Memory({ initial: 3, maximum: 4 }) }); +link("memory number", { memory: 5 }); +link("table too small", { table: new WebAssembly.Table({ initial: 1, maximum: 8, element: "anyfunc" }) }); +link("table without maximum", { table: new WebAssembly.Table({ initial: 2, element: "anyfunc" }) }); +link("table maximum too large", { table: new WebAssembly.Table({ initial: 2, maximum: 12, element: "anyfunc" }) }); +link("table externref", { table: new WebAssembly.Table({ initial: 2, maximum: 8, element: "externref" }) }); +link("table small externref", { table: new WebAssembly.Table({ initial: 1, maximum: 8, element: "externref" }) }); +link("table number", { table: 3 }); +link("global immutable", { counter: new WebAssembly.Global({ value: "i32" }, 1) }); +link("global type", { counter: new WebAssembly.Global({ value: "i64", mutable: true }, 1n) }); +link("global both", { counter: new WebAssembly.Global({ value: "f64" }, 1) }); +link("global number", { counter: 1 }); +link("immutable global object", { scale: new WebAssembly.Global({ value: "f64" }, 4) }); +link("immutable global mutable", { scale: new WebAssembly.Global({ value: "f64", mutable: true }, 4) }); +link("immutable global bigint", { scale: 4n }); +link("i64 number", { big: 4 }); +link("externref anything", { ref: new WebAssembly.Global({ value: "externref", mutable: true }, null) }); diff --git a/tests/corpus/webassembly-spec-imports/data.mjs b/tests/corpus/webassembly-spec-imports/data.mjs new file mode 100644 index 000000000..c082547b8 --- /dev/null +++ b/tests/corpus/webassembly-spec-imports/data.mjs @@ -0,0 +1,137 @@ +/* Generated by tests/wasm-spec/gen.mjs from the WebAssembly 2.0 core test + * suite (WebAssembly/spec wg-2.0, Apache-2.0) with wabt 1.0.37 wast2json: + * imports.wast, table.wast, names.wast. Do not edit. */ +export const modules = [ + "AGFzbQEAAAABHgdgAABgAX8AYAF9AGAAAX9gAAF9YAF/AX9gAX4BfgMIBwABAgMEBQYECAJwAApwAQoUBQMBAAIGFAN/AEE3C30AQwAAMEILfgFCwgALB60BDQRmdW5jAAAIZnVuYy1pMzIAAQhmdW5jLWYzMgACCWZ1bmMtPmkzMgADCWZ1bmMtPmYzMgAEDWZ1bmMtaTMyLT5pMzIABQ1mdW5jLWk2NC0+aTY0AAYKZ2xvYmFsLWkzMgMACmdsb2JhbC1mMzIDAQ5nbG9iYWwtbXV0LWk2NAMCDHRhYmxlLTEwLWluZgEAC3RhYmxlLTEwLTIwAQEMbWVtb3J5LTItaW5mAgAKIQcCAAsCAAsCAAsEAEEWCwcAQwAAMEELBAAgAAsEACAACw==", + "AGFzbQEAAAABJAhgAX8AYAF+AGABfQBgAXwAYAF/AGACf30AYAJ8fABgAX4BfgKDAxIIc3BlY3Rlc3QJcHJpbnRfaTMyAAAIc3BlY3Rlc3QJcHJpbnRfaTY0AAEIc3BlY3Rlc3QJcHJpbnRfaTMyAAAIc3BlY3Rlc3QJcHJpbnRfaTY0AAEIc3BlY3Rlc3QJcHJpbnRfZjMyAAIIc3BlY3Rlc3QJcHJpbnRfZjY0AAMIc3BlY3Rlc3QNcHJpbnRfaTMyX2YzMgAFCHNwZWN0ZXN0DXByaW50X2Y2NF9mNjQABghzcGVjdGVzdAlwcmludF9pMzIAAAhzcGVjdGVzdAlwcmludF9mNjQAAwR0ZXN0DWZ1bmMtaTY0LT5pNjQABwhzcGVjdGVzdAlwcmludF9pMzIAAAhzcGVjdGVzdAlwcmludF9pMzIAAAhzcGVjdGVzdAlwcmludF9pMzIAAAhzcGVjdGVzdAlwcmludF9pMzIAAAhzcGVjdGVzdAlwcmludF9pMzIAAAhzcGVjdGVzdAlwcmludF9pMzIABAhzcGVjdGVzdAlwcmludF9pMzIABAMDAgABBAUBcAECAgczCAJwMQALAnAyAAwCcDMADQJwNAANAnA1AA4CcDYADwdwcmludDMyABIHcHJpbnQ2NAATCQgBAEEACwICBQpoAiwBAX0gALIhASAAEAAgAEEBakMAAChCEAYgABACIAAQCCABEAQgAEEAEQAACzkBAXwgABAKuSEBIAAQASABRAAAAAAAAPA/oEQAAAAAAIBKQBAHIAAQAyABEAUgARAJIAFBAREDAAs=", + "AGFzbQEAAAABBQFgAX8AAhYBCHNwZWN0ZXN0CXByaW50X2kzMgAAAwIBAAcNAQlwcmludF9pMzIAAQoIAQYAIAAQAAs=", + "AGFzbQEAAAABCwJgAX8AYAJ/fwF/AhYBCHNwZWN0ZXN0CXByaW50X2kzMgAAAwIBAQcNAQlwcmludF9pMzIAAQoJAQcAIAAgAWoL", + "AGFzbQEAAAABBAFgAAACDQEEdGVzdARmdW5jAAA=", + "AGFzbQEAAAABBQFgAX8AAhEBBHRlc3QIZnVuYy1pMzIAAA==", + "AGFzbQEAAAABBQFgAX0AAhEBBHRlc3QIZnVuYy1mMzIAAA==", + "AGFzbQEAAAABBQFgAAF/AhIBBHRlc3QJZnVuYy0+aTMyAAA=", + "AGFzbQEAAAABBQFgAAF9AhIBBHRlc3QJZnVuYy0+ZjMyAAA=", + "AGFzbQEAAAABBgFgAX8BfwIWAQR0ZXN0DWZ1bmMtaTMyLT5pMzIAAA==", + "AGFzbQEAAAABBgFgAX4BfgIWAQR0ZXN0DWZ1bmMtaTY0LT5pNjQAAA==", + "AGFzbQEAAAABBAFgAAACEAEEdGVzdAd1bmtub3duAAA=", + "AGFzbQEAAAABBAFgAAACFAEIc3BlY3Rlc3QHdW5rbm93bgAA", + "AGFzbQEAAAABBQFgAX8AAg0BBHRlc3QEZnVuYwAA", + "AGFzbQEAAAABBQFgAAF/Ag0BBHRlc3QEZnVuYwAA", + "AGFzbQEAAAABBgFgAX8BfwINAQR0ZXN0BGZ1bmMAAA==", + "AGFzbQEAAAABBAFgAAACEQEEdGVzdAhmdW5jLWkzMgAA", + "AGFzbQEAAAABBQFgAAF/AhEBBHRlc3QIZnVuYy1pMzIAAA==", + "AGFzbQEAAAABBQFgAX0AAhEBBHRlc3QIZnVuYy1pMzIAAA==", + "AGFzbQEAAAABBQFgAX4AAhEBBHRlc3QIZnVuYy1pMzIAAA==", + "AGFzbQEAAAABBgFgAX8BfwIRAQR0ZXN0CGZ1bmMtaTMyAAA=", + "AGFzbQEAAAABBAFgAAACEgEEdGVzdAlmdW5jLT5pMzIAAA==", + "AGFzbQEAAAABBQFgAX8AAhIBBHRlc3QJZnVuYy0+aTMyAAA=", + "AGFzbQEAAAABBQFgAAF9AhIBBHRlc3QJZnVuYy0+aTMyAAA=", + "AGFzbQEAAAABBQFgAAF+AhIBBHRlc3QJZnVuYy0+aTMyAAA=", + "AGFzbQEAAAABBgFgAX8BfwISAQR0ZXN0CWZ1bmMtPmkzMgAA", + "AGFzbQEAAAABBAFgAAACFgEEdGVzdA1mdW5jLWkzMi0+aTMyAAA=", + "AGFzbQEAAAABBQFgAX8AAhYBBHRlc3QNZnVuYy1pMzItPmkzMgAA", + "AGFzbQEAAAABBQFgAAF/AhYBBHRlc3QNZnVuYy1pMzItPmkzMgAA", + "AGFzbQEAAAABBQFgAAF/AhMBBHRlc3QKZ2xvYmFsLWkzMgAA", + "AGFzbQEAAAABBAFgAAACFQEEdGVzdAx0YWJsZS0xMC1pbmYAAA==", + "AGFzbQEAAAABBAFgAAACFQEEdGVzdAxtZW1vcnktMi1pbmYAAA==", + "AGFzbQEAAAABBAFgAAACFwEIc3BlY3Rlc3QKZ2xvYmFsX2kzMgAA", + "AGFzbQEAAAABBAFgAAACEgEIc3BlY3Rlc3QFdGFibGUAAA==", + "AGFzbQEAAAABBAFgAAACEwEIc3BlY3Rlc3QGbWVtb3J5AAA=", + "AGFzbQEAAAABEQRgAAF/YAABfmAAAX1gAAF8AqIBBwhzcGVjdGVzdApnbG9iYWxfaTMyA38ACHNwZWN0ZXN0Cmdsb2JhbF9pMzIDfwAIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AAhzcGVjdGVzdApnbG9iYWxfaTMyA38ACHNwZWN0ZXN0Cmdsb2JhbF9pNjQDfgAIc3BlY3Rlc3QKZ2xvYmFsX2YzMgN9AAhzcGVjdGVzdApnbG9iYWxfZjY0A3wAAwgHAAAAAAECAwc5BwVnZXQtMAAABWdldC0xAAEFZ2V0LXgAAgVnZXQteQADBWdldC00AAQFZ2V0LTUABQVnZXQtNgAGCiQHBAAjAAsEACMBCwQAIwILBAAjAwsEACMECwQAIwULBAAjBgs=", + "AGFzbQEAAAACFAEEdGVzdApnbG9iYWwtaTMyA38A", + "AGFzbQEAAAACFAEEdGVzdApnbG9iYWwtZjMyA30A", + "AGFzbQEAAAACGAEEdGVzdA5nbG9iYWwtbXV0LWk2NAN+AQ==", + "AGFzbQEAAAACEQEEdGVzdAd1bmtub3duA38A", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QHdW5rbm93bgN/AA==", + "AGFzbQEAAAACFAEEdGVzdApnbG9iYWwtaTMyA34A", + "AGFzbQEAAAACFAEEdGVzdApnbG9iYWwtaTMyA30A", + "AGFzbQEAAAACFAEEdGVzdApnbG9iYWwtaTMyA3wA", + "AGFzbQEAAAACFAEEdGVzdApnbG9iYWwtaTMyA38B", + "AGFzbQEAAAACFAEEdGVzdApnbG9iYWwtZjMyA38A", + "AGFzbQEAAAACFAEEdGVzdApnbG9iYWwtZjMyA34A", + "AGFzbQEAAAACFAEEdGVzdApnbG9iYWwtZjMyA3wA", + "AGFzbQEAAAACFAEEdGVzdApnbG9iYWwtZjMyA30B", + "AGFzbQEAAAACGAEEdGVzdA5nbG9iYWwtbXV0LWk2NAN/AQ==", + "AGFzbQEAAAACGAEEdGVzdA5nbG9iYWwtbXV0LWk2NAN9AQ==", + "AGFzbQEAAAACGAEEdGVzdA5nbG9iYWwtbXV0LWk2NAN8AQ==", + "AGFzbQEAAAACGAEEdGVzdA5nbG9iYWwtbXV0LWk2NAN+AA==", + "AGFzbQEAAAACDgEEdGVzdARmdW5jA38A", + "AGFzbQEAAAACFgEEdGVzdAx0YWJsZS0xMC1pbmYDfwA=", + "AGFzbQEAAAACFgEEdGVzdAxtZW1vcnktMi1pbmYDfwA=", + "AGFzbQEAAAACFwEIc3BlY3Rlc3QJcHJpbnRfaTMyA38A", + "AGFzbQEAAAACEwEIc3BlY3Rlc3QFdGFibGUDfwA=", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5A38A", + "AGFzbQEAAAABCgJgAAF/YAF/AX8CFQEIc3BlY3Rlc3QFdGFibGUBcAEKFAMEAwEAAAcIAQRjYWxsAAAJCAEAQQELAgECChMDBwAgABEAAAsEAEELCwQAQRYL", + "AGFzbQEAAAACJwIIc3BlY3Rlc3QFdGFibGUBcAAACHNwZWN0ZXN0BXRhYmxlAXAAAAQHAnAACnAACg==", + "AGFzbQEAAAACFwEEdGVzdAx0YWJsZS0xMC1pbmYBcAAK", + "AGFzbQEAAAACFwEEdGVzdAx0YWJsZS0xMC1pbmYBcAAF", + "AGFzbQEAAAACFwEEdGVzdAx0YWJsZS0xMC1pbmYBcAAA", + "AGFzbQEAAAACFgEEdGVzdAt0YWJsZS0xMC0yMAFwAAo=", + "AGFzbQEAAAACFgEEdGVzdAt0YWJsZS0xMC0yMAFwAAU=", + "AGFzbQEAAAACFgEEdGVzdAt0YWJsZS0xMC0yMAFwAAA=", + "AGFzbQEAAAACFwEEdGVzdAt0YWJsZS0xMC0yMAFwAQoU", + "AGFzbQEAAAACFwEEdGVzdAt0YWJsZS0xMC0yMAFwAQUU", + "AGFzbQEAAAACFwEEdGVzdAt0YWJsZS0xMC0yMAFwAQAU", + "AGFzbQEAAAACFwEEdGVzdAt0YWJsZS0xMC0yMAFwAQoZ", + "AGFzbQEAAAACFwEEdGVzdAt0YWJsZS0xMC0yMAFwAQUZ", + "AGFzbQEAAAACFwEEdGVzdAt0YWJsZS0xMC0yMAFwAQAZ", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAK", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAF", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAA", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QFdGFibGUBcAEKFA==", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QFdGFibGUBcAEFFA==", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QFdGFibGUBcAEAFA==", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QFdGFibGUBcAEKGQ==", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QFdGFibGUBcAEFGQ==", + "AGFzbQEAAAACEgEEdGVzdAd1bmtub3duAXAACg==", + "AGFzbQEAAAACFgEIc3BlY3Rlc3QHdW5rbm93bgFwAAo=", + "AGFzbQEAAAACFwEEdGVzdAx0YWJsZS0xMC1pbmYBcAAM", + "AGFzbQEAAAACGAEEdGVzdAx0YWJsZS0xMC1pbmYBcAEKFA==", + "AGFzbQEAAAACFwEEdGVzdAt0YWJsZS0xMC0yMAFwAQwU", + "AGFzbQEAAAACFwEEdGVzdAt0YWJsZS0xMC0yMAFwAQoS", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAM", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QFdGFibGUBcAEKDw==", + "AGFzbQEAAAACDwEEdGVzdARmdW5jAXAACg==", + "AGFzbQEAAAACFQEEdGVzdApnbG9iYWwtaTMyAXAACg==", + "AGFzbQEAAAACFwEEdGVzdAxtZW1vcnktMi1pbmYBcAAK", + "AGFzbQEAAAACGAEIc3BlY3Rlc3QJcHJpbnRfaTMyAXAACg==", + "AGFzbQEAAAABBgFgAX8BfwIVAQhzcGVjdGVzdAZtZW1vcnkCAQECAwIBAAcIAQRsb2FkAAAKCQEHACAAKAIACwsHAQBBCgsBEA==", + "AGFzbQEAAAACFgEEdGVzdAxtZW1vcnktMi1pbmYCAAI=", + "AGFzbQEAAAACFgEEdGVzdAxtZW1vcnktMi1pbmYCAAE=", + "AGFzbQEAAAACFgEEdGVzdAxtZW1vcnktMi1pbmYCAAA=", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgAB", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgAA", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QGbWVtb3J5AgEBAg==", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QGbWVtb3J5AgEAAg==", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QGbWVtb3J5AgEBAw==", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QGbWVtb3J5AgEAAw==", + "AGFzbQEAAAACEQEEdGVzdAd1bmtub3duAgAB", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QHdW5rbm93bgIAAQ==", + "AGFzbQEAAAACFgEEdGVzdAxtZW1vcnktMi1pbmYCAAM=", + "AGFzbQEAAAACFwEEdGVzdAxtZW1vcnktMi1pbmYCAQID", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgAC", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QGbWVtb3J5AgEBAQ==", + "AGFzbQEAAAACEgEEdGVzdAhmdW5jLWkzMgIAAQ==", + "AGFzbQEAAAACFAEEdGVzdApnbG9iYWwtaTMyAgAB", + "AGFzbQEAAAACFgEEdGVzdAx0YWJsZS0xMC1pbmYCAAE=", + "AGFzbQEAAAACFwEIc3BlY3Rlc3QJcHJpbnRfaTMyAgAB", + "AGFzbQEAAAACGAEIc3BlY3Rlc3QKZ2xvYmFsX2kzMgIAAQ==", + "AGFzbQEAAAACEwEIc3BlY3Rlc3QFdGFibGUCAAE=", + "AGFzbQEAAAABBgFgAX8BfwIVAQhzcGVjdGVzdAZtZW1vcnkCAQADAwIBAAcIAQRncm93AAAKCAEGACAAQAAL", + "AGFzbQEAAAA=", + "AGFzbQEAAAABKQpgAABgAX8AYAJ/fwBgAX4AYAF9AGABfABgAAF/YAABfmAAAX1gAAF8AugCEAhub3Qgd2FzbQpvdmVybG9hZGVkAAAIbm90IHdhc20Kb3ZlcmxvYWRlZAABCG5vdCB3YXNtCm92ZXJsb2FkZWQAAghub3Qgd2FzbQpvdmVybG9hZGVkAAMIbm90IHdhc20Kb3ZlcmxvYWRlZAAECG5vdCB3YXNtCm92ZXJsb2FkZWQABQhub3Qgd2FzbQpvdmVybG9hZGVkAAYIbm90IHdhc20Kb3ZlcmxvYWRlZAAHCG5vdCB3YXNtCm92ZXJsb2FkZWQACAhub3Qgd2FzbQpvdmVybG9hZGVkAAkIbm90IHdhc20Kb3ZlcmxvYWRlZAN/AAhub3Qgd2FzbQpvdmVybG9hZGVkA34ACG5vdCB3YXNtCm92ZXJsb2FkZWQDfQAIbm90IHdhc20Kb3ZlcmxvYWRlZAN8AAhub3Qgd2FzbQpvdmVybG9hZGVkAXAAAAhub3Qgd2FzbQpvdmVybG9hZGVkAgAA", + "AGFzbQEAAAAEBAFwAAA=", + "AGFzbQEAAAAEBAFwAAE=", + "AGFzbQEAAAAEBQFwAQAA", + "AGFzbQEAAAAEBQFwAQAB", + "AGFzbQEAAAAEBgFwAQGAAg==", + "AGFzbQEAAAAEBwFwAQCAgAQ=", + "AGFzbQEAAAAECQFwAQD/////Dw==", + "AGFzbQEAAAAEBwJwAABwAAA=", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAABAQBcAAA", + "AGFzbQEAAAABBQFgAAF/AwIBAAcHAQNmb28AAAoGAQQAQQAL", + "AGFzbQEAAAABBQFgAAF/AwIBAAcHAQNmb28AAAoGAQQAQQEL", + "AGFzbQEAAAABBQFgAAF/A+ED3wMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAerId8DAAAAATAAAQItMAACAV8AAwEkAAQBQAAFIX4hQCMkJV4mKigpXytgLT17fXxbXVw6IjsnPD4/LC4vIAAGA05hTgAHCEluZmluaXR5AAgCaWYACQZtYWxsb2MACgdfbWFsbG9jAAsIX19tYWxsb2MADAFhAA0BQQAOA++7vwAPAsOFABADQcyKABED4oSrABID76yDABMEZu+sgQAUA2ZmaQAVEAABAgMEBQYHCAkKCwwNDg8AFhAQERITFBUWFxgZGhscHR4fABcCIH8AGCDCgMKBwoLCg8KEwoXChsKHwojCicKKwovCjMKNwo7CjwAZIMKQwpHCksKTwpTClcKWwpfCmMKZwprCm8Kcwp3CnsKfABoY77+w77+x77+y77+z77+077+177+277+3ABsY77+477+577+677+777+877+977++77+/ABww4pCA4pCB4pCC4pCD4pCE4pCF4pCG4pCH4pCI4pCJ4pCK4pCL4pCM4pCN4pCO4pCPAB0w4pCQ4pCR4pCS4pCT4pCU4pCV4pCW4pCX4pCY4pCZ4pCa4pCb4pCc4pCd4pCe4pCfAB4G4pCg4pChAB8q77+w77+x77+y77+z77+077+177+277+377+477+577+677+777+877+9ACAD4oCNACED4oCMACICzY8AIwPigaAAJAPitb8AJQTwkYG/ACYD4aCOACcW77+v4oCLwqDCreKBoOGagOKAruKArQAoJ+KAjuKAj+KAkeKAqOKAqeKAquKAq+KArOKAr+KBpuKBp+KBqOKBqQApEuKBquKBq+KBrOKBreKBruKBrwAqDOKBoeKBouKBo+KBpAArDPCQgIDzn7+/9I+/vwAsgQJazI/NhsyGzZvNjMy0zZjNns2HzKvMpcyqzZPNiM2UzY7Ml8yezLrMr8yxzJ7MmcyxzJzMlsygYc2XzajMjsyEzIbNl8y/zaHNn82AzLbNgcylzLDMs8ytzZnMssyxzLnMnc2OzLxszYTNisyazZfNps2EzavMh82BzLbMt82JzKnMucyrzJ3Nls2FzJnMssy8zYfNms2NzK7NjsylzYXMnmfNg8yQzIXNrsyUzJDMjsyCzI/Mvs2KzI3Ni82KzafMgcyGzabNnsy2zZXNlM2azKlvzYvMlM2QzarNqcyhzY/MosynzYHMq8yZzKTMrs2WzZnNk8y6zJzMqcy8zJjMoAAtDOGFn+GFoOOFpO++oAAuA++4gAAvA++4hAAwBPOghIAAMQTzoIevADICzIgAMwEKADQD4pCkADUD4oCoADYBDQA3Ag0KADgCCg0AOQEeADoBCwA7AQwAPALChQA9A+KAqQA+A+KApgA/A+KPjgBAAsKLAEECwowAQgLCjQBDA+KGtQBEA+KGqQBFA+KMpABGA+KktgBHA+KGsgBIA+KuqABJA+KusABKA++/vQBLA++3kABMA++3kQBNA++3kgBOA++3kwBPA++3lABQA++3lQBRA++3lgBSA++3lwBTA++3mABUA++3mQBVA++3mgBWA++3mwBXA++3nABYA++3nQBZA++3ngBaA++3nwBbA++3oABcA++3oQBdA++3ogBeA++3owBfA++3pABgA++3pQBhA++3pgBiA++3pwBjA++3qABkA++3qQBlA++3qgBmA++3qwBnA++3rABoA++3rQBpA++3rgBqA++3rwBrA++/vgBsA++/vwBtBPCfv74AbgTwn7+/AG8E8K+/vgBwBPCvv78AcQTwv7++AHIE8L+/vwBzBPGPv74AdATxj7+/AHUE8Z+/vgB2BPGfv78AdwTxr7++AHgE8a+/vwB5BPG/v74AegTxv7+/AHsE8o+/vgB8BPKPv78AfQTyn7++AH4E8p+/vwB/BPKvv74AgAEE8q+/vwCBAQTyv7++AIIBBPK/v78AgwEE84+/vgCEAQTzj7+/AIUBBPOfv74AhgEE85+/vwCHAQTzr7++AIgBBPOvv78AiQEE87+/vgCKAQTzv7+/AIsBBPSPv74AjAEE9I+/vwCNAQnMiOKAvcyIzIkAjgEDYWJjAI8BBuKArWFiYwCQAQbigK5jYmEAkQEJ4oCtYWJj4oCuAJIBCeKArmNiYeKArQCTAQTwnZGoAJQBBPCdkLQAlQEE8J2YiACWAQTwnZi8AJcBBPCdkIAAmAEE8J2TkACZAQTwnZWsAJoBBPCdl5QAmwEE8J2SnACcAQTwnZSEAJ0BBPCdlLgAngEE8J2WoACfAQTwnZmwAKABA+G0gAChAQPhtKwAogED4pK2AKMBA++8oQCkAQTwn4SQAKUBBPCfhLAApgEE86CBgQCnAQZVKzAwNDEAqAEEQeKAiwCpAQLQkACqAQPqmZYAqwED4re8AKwBA+K3tgCtAQPisa8ArgEE8J+FkACvAQTwn4WwALABA+KwrQCxAQTwkJCCALIBBPCQkIgAswEE8JCSsAC0AQLDgAC1AQLDgQC2AQLDggC3AQLDgwC4AQLDhAC5AQLEgAC6AQLEggC7AQLEhAC8AQLHjQC9AQLHngC+AQLHoAC/AQLHugDAAQLIgADBAQLIggDCAQLIpgDDAQLIugDEAQLTkADFAQLTkgDGAQLfigDHAQPgoKEAyAED4KCiAMkBA+CgowDKAQPgoKQAywED4KClAMwBA+CkhADNAQPgpIUAzgED4KWyAM8BA+CmhQDQAQPgqIUA0QED4KqFANIBA+CshQDTAQPgroUA1AED4LCFANUBA+CyhQDWAQPgtIUA1wED4LiwANgBA+C6sADZAQPgvIEA2gED4L2oANsBA+C+uADcAQPhgKEA3QED4YCiAN4BA+GCnADfAQPhhaEA4AED4YqgAOEBA+GLkADiAQPhjqAA4wED4ZCKAOQBA+GWswDlAQPhmqgA5gED4ZqqAOcBA+GbhgDoAQPhnIAA6QED4ZygAOoBA+GdgADrAQPhnaAA7AED4aCgAO0BA+GihwDuAQPhpKAA7wED4aWjAPABA+GolQDxAQPhqYsA8gED4amhAPMBA+GugwD0AQPhr4AA9QED4a+BAPYBA+GwowD3AQPhuIAA+AED4bqgAPkBA+G6ogD6AQPhuqQA+wED4bqmAPwBA+G6qAD9AQPhuqoA/gED4bqsAP8BA+G6rgCAAgPhurAAgQID4bqyAIICA+G6tACDAgPhurYAhAID44GCAIUCA+OCogCGAgPjhJoAhwID44WPAIgCA+OIjgCJAgPjiI8AigID44iQAIsCA+OIkQCMAgPjiJIAjQID44iTAI4CA+OIlACPAgPjiJUAkAID44iWAJECA+OIlwCSAgPjiJgAkwID44iZAJQCA+OImgCVAgPjiJsAlgID44muAJcCA+OJrwCYAgPjibAAmQID44mxAJoCA+OJsgCbAgPjibMAnAID44m0AJ0CA+OJtQCeAgPjibYAnwID44m3AKACA+OJuAChAgPjibkAogID44m6AKMCA+OJuwCkAgPji5AApQID6oCKAKYCA+qTrgCnAgPqlYkAqAID6pqgAKkCA+qggACqAgPqoKMAqwID6qGdAKwCA+qiggCtAgPqo6oArgID6qSiAK8CA+qlhgCwAgPqpoQAsQID6qiAALICA++9sQCzAgPvv4IAtAIE8JCAgAC1AgTwkIqAALYCBPCQiqAAtwIE8JCMgAC4AgTwkI6gALkCBPCQkpYAugIE8JCUgAC7AgTwkJ2AALwCBPCQoIAAvQIE8JCkoAC+AgTwkKaAAL8CBPCQpqAAwAIE8JCogADBAgTwkKyAAMICBPCQsIAAwwIE8JCwgQDEAgTwkLKAAMUCBPCRgIUAxgIE8JGCgwDHAgTwkYSnAMgCBPCRhZAAyQIE8JGGgwDKAgTwkYiAAMsCBPCRioAAzAIE8JGKsADNAgTwkYyFAM4CBPCRjbAAzwIE8JGQgADQAgTwkZKBANECBPCRloAA0gIE8JGYgADTAgTwkZqAANQCBPCRnJIA1QIE8JGcoADWAgTwkaKhANcCBPCRq5UA2AIE8JGwgADZAgTwkbKPANoCBPCRsq8A2wIE8JKAgADcAgTwlqeVAN0CBPCWqYYA3gIE8JarpwDfAgTwlr2UAOACBPCbsYEA4QIE8JuxpADiAgTwnqCjAOMCBPCfh6YA5AID4rGtAOUCAs6bAOYCA+KxsADnAgLCqgDoAgPiiIAA6QID4oKzAOoCBPCQpIAA6wID4rKAAOwCBPCQjLAA7QICzoYA7gICzpEA7wID4byIAPACA+G8iQDxAgPhvIoA8gID4byLAPMCA+G8jAD0AgPhvI0A9QID4byOAPYCA+G8jwD3AgPhvogA+AID4b6JAPkCA+G+igD6AgPhvosA+wID4b6MAPwCA+G+jQD9AgPhvo4A/gID4b6PAP8CA+G+uACAAwPhvrkAgQMD4b66AIIDA+G+uwCDAwPhvrwAhAME8J2aqACFAwTwnZuiAIYDBPCdnJwAhwME8J2dlgCIAwTwnZ6QAIkDA+KNtgCKAwPijboAiwMD4qmcAIwDA+GXhQCNAwPhjqoAjgOcASnLusu88JSXj/CdhbTwnYW28J2FuPCdhbrigb7igo7inaninavin6/vtL/vuLbvuZrvvInvvaDzoICp4p2z4p214p+n4p+p4p+r4p+t4qaI4qaK4qaW4rij4ril77iY77i477i677i877i+77mA77mC77mE77mI77mc77me77y9772d772j86CBnfOggb3Cu+KAmeKAneKAuuKdrwCPA5wBKMu5y7vwlJeO8J2Fs/CdhbXwnYW38J2FueKBveKCjeKdqOKdquKfru+0vu+4te+5me+8iO+9n/OggKjinbLinbTin6bin6jin6rin6zipofiponippXiuKLiuKTvuJfvuLfvuLnvuLvvuL3vuL/vuYHvuYPvuYfvuZvvuZ3vvLvvvZvvvaLzoIGb86CBu8Kr4oCY4oCc4oC54p2uAJADCPCdqovwnaqkAJEDBPCdqosAkgMCwr0AkwMFMeKBhDIAlAMDMS8yAJUDA+CtswCWAwPgtbQAlwMD4rO9AJgDA+qgsQCZAwTwkIWBAJoDBPCQhbUAmwME8JCFtgCcAwTwkKa9AJ0DBPCQubsAngMD77yCAJ8DAX8AoAMBCAChAwPijKsAogMD4oymAKMDA+KQiACkAwPikKEApQMD4be7AKYDAQ8ApwMD4oaQAKgDA+KMpwCpAwPijZIAqgMD4o2UAKsDA+KNogCsAwPijasArQMBGgCuAwPikKYArwMD4pCaALADA++/vACxAwE/ALIDAsK/ALMDA+GlhQC0AwLNvgC1AwLVngC2AwLYnwC3AwPhjacAuAMD4oGHALkDA+KNsAC6AwPinZMAuwMD4p2UALwDA+KzugC9AwPis7sAvgMD4riuAL8DA+OJhADAAwPqmI8AwQMD6pu3AMIDA++4lgDDAwPvuZYAxAMD77yfAMUDBPCRhYMAxgME8J6lnwDHAwTzoIC/AMgDBPCWoYQAyQMD4q+RAMoDAsK2AMsDA+KBiwDMAwLcgADNAwPhg7sAzgMD4Y2oAM8DA+OAtwDQAwPinaEA0QMD4riPANIDA+K4kADTAwPiuJEA1AMD4riOANUDARQA1gMD4piZANcDA+K4vwDYAwPjgIcA2QMD4LmbANoDA+qZrgDbAwLPkwDcAwLPlADdAwPhupsA3gMK/BXfAwQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLBABBCgsEAEELCwQAQQwLBABBDQsEAEEOCwQAQQ8LBABBEAsEAEERCwQAQRILBABBEwsEAEEUCwQAQRULBABBFgsEAEEXCwQAQRgLBABBGQsEAEEaCwQAQRsLBABBHAsEAEEdCwQAQR4LBABBHwsEAEEgCwQAQSELBABBIgsEAEEjCwQAQSQLBABBJQsEAEEmCwQAQScLBABBKAsEAEEpCwQAQSoLBABBKwsEAEEsCwQAQS0LBABBLgsEAEEvCwQAQTALBABBMQsEAEEyCwQAQTMLBABBNAsEAEE1CwQAQTYLBABBNwsEAEE4CwQAQTkLBABBOgsEAEE7CwQAQTwLBABBPQsEAEE+CwQAQT8LBQBBwAALBQBBwQALBQBBwgALBQBBwwALBQBBxAALBQBBxQALBQBBxgALBQBBxwALBQBByAALBQBByQALBQBBygALBQBBywALBQBBzAALBQBBzQALBQBBzgALBQBBzwALBQBB0AALBQBB0QALBQBB0gALBQBB0wALBQBB1AALBQBB1QALBQBB1gALBQBB1wALBQBB2AALBQBB2QALBQBB2gALBQBB2wALBQBB3AALBQBB3QALBQBB3gALBQBB3wALBQBB4AALBQBB4QALBQBB4gALBQBB4wALBQBB5AALBQBB5QALBQBB5gALBQBB5wALBQBB6AALBQBB6QALBQBB6gALBQBB6wALBQBB7AALBQBB7QALBQBB7gALBQBB7wALBQBB8AALBQBB8QALBQBB8gALBQBB8wALBQBB9AALBQBB9QALBQBB9gALBQBB9wALBQBB+AALBQBB+QALBQBB+gALBQBB+wALBQBB/AALBQBB/QALBQBB/gALBQBB/wALBQBBgAELBQBBgQELBQBBggELBQBBgwELBQBBhAELBQBBhQELBQBBhgELBQBBhwELBQBBiAELBQBBiQELBQBBigELBQBBiwELBQBBjAELBQBBjQELBQBBjgELBQBBjwELBQBBkAELBQBBkQELBQBBkgELBQBBkwELBQBBlAELBQBBlQELBQBBlgELBQBBlwELBQBBmAELBQBBmQELBQBBmgELBQBBmwELBQBBnAELBQBBnQELBQBBngELBQBBnwELBQBBoAELBQBBoQELBQBBogELBQBBowELBQBBpAELBQBBpQELBQBBpgELBQBBpwELBQBBqAELBQBBqQELBQBBqgELBQBBqwELBQBBrAELBQBBrQELBQBBrgELBQBBrwELBQBBsAELBQBBsQELBQBBsgELBQBBswELBQBBtAELBQBBtQELBQBBtgELBQBBtwELBQBBuAELBQBBuQELBQBBugELBQBBuwELBQBBvAELBQBBvQELBQBBvgELBQBBvwELBQBBwAELBQBBwQELBQBBwgELBQBBwwELBQBBxAELBQBBxQELBQBBxgELBQBBxwELBQBByAELBQBByQELBQBBygELBQBBywELBQBBzAELBQBBzQELBQBBzgELBQBBzwELBQBB0AELBQBB0QELBQBB0gELBQBB0wELBQBB1AELBQBB1QELBQBB1gELBQBB1wELBQBB2AELBQBB2QELBQBB2gELBQBB2wELBQBB3AELBQBB3QELBQBB3gELBQBB3wELBQBB4AELBQBB4QELBQBB4gELBQBB4wELBQBB5AELBQBB5QELBQBB5gELBQBB5wELBQBB6AELBQBB6QELBQBB6gELBQBB6wELBQBB7AELBQBB7QELBQBB7gELBQBB7wELBQBB8AELBQBB8QELBQBB8gELBQBB8wELBQBB9AELBQBB9QELBQBB9gELBQBB9wELBQBB+AELBQBB+QELBQBB+gELBQBB+wELBQBB/AELBQBB/QELBQBB/gELBQBB/wELBQBBgAILBQBBgQILBQBBggILBQBBgwILBQBBhAILBQBBhQILBQBBhgILBQBBhwILBQBBiAILBQBBiQILBQBBigILBQBBiwILBQBBjAILBQBBjQILBQBBjgILBQBBjwILBQBBkAILBQBBkQILBQBBkgILBQBBkwILBQBBlAILBQBBlQILBQBBlgILBQBBlwILBQBBmAILBQBBmQILBQBBmgILBQBBmwILBQBBnAILBQBBnQILBQBBngILBQBBnwILBQBBoAILBQBBoQILBQBBogILBQBBowILBQBBpAILBQBBpQILBQBBpgILBQBBpwILBQBBqAILBQBBqQILBQBBqgILBQBBqwILBQBBrAILBQBBrQILBQBBrgILBQBBrwILBQBBsAILBQBBsQILBQBBsgILBQBBswILBQBBtAILBQBBtQILBQBBtgILBQBBtwILBQBBuAILBQBBuQILBQBBugILBQBBuwILBQBBvAILBQBBvQILBQBBvgILBQBBvwILBQBBwAILBQBBwQILBQBBwgILBQBBwwILBQBBxAILBQBBxQILBQBBxgILBQBBxwILBQBByAILBQBByQILBQBBygILBQBBywILBQBBzAILBQBBzQILBQBBzgILBQBBzwILBQBB0AILBQBB0QILBQBB0gILBQBB0wILBQBB1AILBQBB1QILBQBB1gILBQBB1wILBQBB2AILBQBB2QILBQBB2gILBQBB2wILBQBB3AILBQBB3QILBQBB3gILBQBB3wILBQBB4AILBQBB4QILBQBB4gILBQBB4wILBQBB5AILBQBB5QILBQBB5gILBQBB5wILBQBB6AILBQBB6QILBQBB6gILBQBB6wILBQBB7AILBQBB7QILBQBB7gILBQBB7wILBQBB8AILBQBB8QILBQBB8gILBQBB8wILBQBB9AILBQBB9QILBQBB9gILBQBB9wILBQBB+AILBQBB+QILBQBB+gILBQBB+wILBQBB/AILBQBB/QILBQBB/gILBQBB/wILBQBBgAMLBQBBgQMLBQBBggMLBQBBgwMLBQBBhAMLBQBBhQMLBQBBhgMLBQBBhwMLBQBBiAMLBQBBiQMLBQBBigMLBQBBiwMLBQBBjAMLBQBBjQMLBQBBjgMLBQBBjwMLBQBBkAMLBQBBkQMLBQBBkgMLBQBBkwMLBQBBlAMLBQBBlQMLBQBBlgMLBQBBlwMLBQBBmAMLBQBBmQMLBQBBmgMLBQBBmwMLBQBBnAMLBQBBnQMLBQBBngMLBQBBnwMLBQBBoAMLBQBBoQMLBQBBogMLBQBBowMLBQBBpAMLBQBBpQMLBQBBpgMLBQBBpwMLBQBBqAMLBQBBqQMLBQBBqgMLBQBBqwMLBQBBrAMLBQBBrQMLBQBBrgMLBQBBrwMLBQBBsAMLBQBBsQMLBQBBsgMLBQBBswMLBQBBtAMLBQBBtQMLBQBBtgMLBQBBtwMLBQBBuAMLBQBBuQMLBQBBugMLBQBBuwMLBQBBvAMLBQBBvQMLBQBBvgMLBQBBvwMLBQBBwAMLBQBBwQMLBQBBwgMLBQBBwwMLBQBBxAMLBQBBxQMLBQBBxgMLBQBBxwMLBQBByAMLBQBByQMLBQBBygMLBQBBywMLBQBBzAMLBQBBzQMLBQBBzgMLBQBBzwMLBQBB0AMLBQBB0QMLBQBB0gMLBQBB0wMLBQBB1AMLBQBB1QMLBQBB1gMLBQBB1wMLBQBB2AMLBQBB2QMLBQBB2gMLBQBB2wMLBQBB3AMLBQBB3QMLBQBB3gML", + "AGFzbQEAAAABCgJgAX8AYAJ/fwACKwIIc3BlY3Rlc3QJcHJpbnRfaTMyAAAIc3BlY3Rlc3QJcHJpbnRfaTMyAAADAgEBBwsBB3ByaW50MzIAAgoMAQoAIAAQACABEAEL", +]; +export const script = "[[\"file\",\"imports.wast\"],[\"module\",3,0],[\"register\",\"test\"],[\"module\",26,1],[\"invoke\",85,0,\"print32\",[\"i32:13\"]],[\"invoke\",86,0,\"print64\",[\"i64:24\"]],[\"module\",97,2],[\"invoke\",104,0,\"print_i32\",[\"i32:13\"]],[\"module\",107,3],[\"invoke\",114,0,\"print_i32\",[\"i32:5\",\"i32:11\"]],[\"module\",116,4],[\"module\",117,5],[\"module\",118,6],[\"module\",119,7],[\"module\",120,8],[\"module\",121,9],[\"module\",122,10],[\"instantiate\",125,11],[\"instantiate\",129,12],[\"instantiate\",134,13],[\"instantiate\",138,14],[\"instantiate\",142,15],[\"instantiate\",146,16],[\"instantiate\",150,17],[\"instantiate\",154,18],[\"instantiate\",158,19],[\"instantiate\",162,20],[\"instantiate\",166,21],[\"instantiate\",170,22],[\"instantiate\",174,23],[\"instantiate\",178,24],[\"instantiate\",182,25],[\"instantiate\",186,26],[\"instantiate\",190,27],[\"instantiate\",194,28],[\"instantiate\",199,29],[\"instantiate\",203,30],[\"instantiate\",207,31],[\"instantiate\",211,32],[\"instantiate\",215,33],[\"instantiate\",219,34],[\"module\",226,35],[\"invoke\",246,0,\"get-0\",[]],[\"invoke\",247,0,\"get-1\",[]],[\"invoke\",248,0,\"get-x\",[]],[\"invoke\",249,0,\"get-y\",[]],[\"invoke\",250,0,\"get-4\",[]],[\"invoke\",251,0,\"get-5\",[]],[\"invoke\",252,0,\"get-6\",[]],[\"module\",254,36],[\"module\",255,37],[\"module\",256,38],[\"instantiate\",259,39],[\"instantiate\",263,40],[\"instantiate\",268,41],[\"instantiate\",272,42],[\"instantiate\",276,43],[\"instantiate\",280,44],[\"instantiate\",284,45],[\"instantiate\",288,46],[\"instantiate\",292,47],[\"instantiate\",296,48],[\"instantiate\",300,49],[\"instantiate\",304,50],[\"instantiate\",308,51],[\"instantiate\",312,52],[\"instantiate\",317,53],[\"instantiate\",321,54],[\"instantiate\",325,55],[\"instantiate\",329,56],[\"instantiate\",333,57],[\"instantiate\",337,58],[\"module\",344,59],[\"invoke\",356,0,\"call\",[\"i32:0\"]],[\"invoke\",357,0,\"call\",[\"i32:1\"]],[\"invoke\",358,0,\"call\",[\"i32:2\"]],[\"invoke\",359,0,\"call\",[\"i32:3\"]],[\"invoke\",360,0,\"call\",[\"i32:100\"]],[\"module\",363,59],[\"invoke\",375,0,\"call\",[\"i32:0\"]],[\"invoke\",376,0,\"call\",[\"i32:1\"]],[\"invoke\",377,0,\"call\",[\"i32:2\"]],[\"invoke\",378,0,\"call\",[\"i32:3\"]],[\"invoke\",379,0,\"call\",[\"i32:100\"]],[\"module\",381,60],[\"module\",388,61],[\"module\",389,62],[\"module\",390,63],[\"module\",391,64],[\"module\",392,65],[\"module\",393,66],[\"module\",394,67],[\"module\",395,68],[\"module\",396,69],[\"module\",397,70],[\"module\",398,71],[\"module\",399,72],[\"module\",400,73],[\"module\",401,74],[\"module\",402,75],[\"module\",403,76],[\"module\",404,77],[\"module\",405,78],[\"module\",406,79],[\"module\",407,80],[\"instantiate\",410,81],[\"instantiate\",414,82],[\"instantiate\",419,83],[\"instantiate\",423,84],[\"instantiate\",427,85],[\"instantiate\",431,86],[\"instantiate\",435,87],[\"instantiate\",439,88],[\"instantiate\",444,89],[\"instantiate\",448,90],[\"instantiate\",452,91],[\"instantiate\",456,92],[\"module\",464,93],[\"invoke\",471,0,\"load\",[\"i32:0\"]],[\"invoke\",472,0,\"load\",[\"i32:10\"]],[\"invoke\",473,0,\"load\",[\"i32:8\"]],[\"invoke\",474,0,\"load\",[\"i32:1000000\"]],[\"module\",476,93],[\"invoke\",482,0,\"load\",[\"i32:0\"]],[\"invoke\",483,0,\"load\",[\"i32:10\"]],[\"invoke\",484,0,\"load\",[\"i32:8\"]],[\"invoke\",485,0,\"load\",[\"i32:1000000\"]],[\"module\",500,94],[\"module\",501,95],[\"module\",502,96],[\"module\",503,97],[\"module\",504,98],[\"module\",505,99],[\"module\",506,100],[\"module\",507,101],[\"module\",508,102],[\"instantiate\",511,103],[\"instantiate\",515,104],[\"instantiate\",520,105],[\"instantiate\",524,106],[\"instantiate\",528,107],[\"instantiate\",532,108],[\"instantiate\",537,109],[\"instantiate\",541,110],[\"instantiate\",545,111],[\"instantiate\",549,112],[\"instantiate\",553,113],[\"instantiate\",557,114],[\"instantiate\",562,107],[\"instantiate\",566,108],[\"module\",570,115],[\"invoke\",574,0,\"grow\",[\"i32:0\"]],[\"invoke\",575,0,\"grow\",[\"i32:1\"]],[\"invoke\",576,0,\"grow\",[\"i32:0\"]],[\"invoke\",577,0,\"grow\",[\"i32:1\"]],[\"invoke\",578,0,\"grow\",[\"i32:0\"]],[\"module\",654,116],[\"register\",\"not wasm\"],[\"instantiate\",657,117],[\"file\",\"table.wast\"],[\"module\",3,118],[\"module\",4,119],[\"module\",5,120],[\"module\",6,121],[\"module\",7,122],[\"module\",8,123],[\"module\",9,124],[\"module\",11,125],[\"module\",12,126],[\"file\",\"names.wast\"],[\"module\",4,127],[\"invoke\",8,0,\"foo\",[]],[\"module\",12,128],[\"module\",19,129],[\"invoke\",615,0,\"\",[]],[\"invoke\",616,0,\"0\",[]],[\"invoke\",617,0,\"-0\",[]],[\"invoke\",618,0,\"_\",[]],[\"invoke\",620,0,\"@\",[]],[\"invoke\",621,0,\"~!@#$%^&*()_+`-={}|[]\\\\:\\\";'<>?,./ \",[]],[\"invoke\",622,0,\"NaN\",[]],[\"invoke\",623,0,\"Infinity\",[]],[\"invoke\",624,0,\"if\",[]],[\"invoke\",626,0,\"_malloc\",[]],[\"invoke\",627,0,\"__malloc\",[]],[\"invoke\",628,0,\"a\",[]],[\"invoke\",629,0,\"A\",[]],[\"invoke\",630,0,\"\",[]],[\"invoke\",632,0,\"Å\",[]],[\"invoke\",633,0,\"Å\",[]],[\"invoke\",634,0,\"ffi\",[]],[\"invoke\",635,0,\"ffi\",[]],[\"invoke\",636,0,\"ffi\",[]],[\"invoke\",638,0,\"\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\",[]],[\"invoke\",639,0,\" \",[]],[\"invoke\",640,0,\"€‚ƒ„…†‡ˆ‰Š‹ŒŽ\",[]],[\"invoke\",641,0,\"‘’“”•–—˜™š›œžŸ\",[]],[\"invoke\",642,0,\"￰￱￲￳￴￵￶￷\",[]],[\"invoke\",644,0,\"␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏\",[]],[\"invoke\",645,0,\"␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟\",[]],[\"invoke\",646,0,\"␠␡\",[]],[\"invoke\",647,0,\"￰￱￲￳￴￵￶￷￸�\",[]],[\"invoke\",648,0,\"‍\",[]],[\"invoke\",650,0,\"͏\",[]],[\"invoke\",651,0,\"⁠\",[]],[\"invoke\",652,0,\"⵿\",[]],[\"invoke\",653,0,\"𑁿\",[]],[\"invoke\",654,0,\"᠎\",[]],[\"invoke\",656,0,\"‎‏‑

‪‫‬ ⁦⁧⁨⁩\",[]],[\"invoke\",657,0,\"\",[]],[\"invoke\",658,0,\"⁡⁢⁣⁤\",[]],[\"invoke\",659,0,\"𐀀󟿿􏿿\",[]],[\"invoke\",660,0,\"Z̴͇̫̥̪͓͈͔͎̗̞̺̯̱̞̙̱̜̖̠̏͆̆͛͌͘͞ḁ̶̰̳̭͙̲̱̹̝͎̼͗ͨ̎̄̆͗̿̀́͟͡l̶̷͉̩̹̫̝͖̙̲̼͇͚͍̮͎̥̞̈́͊͗ͦ̈́ͫ̇́̚ͅͅg̶͕͔͚̩̓̐̅ͮ̔̐̎̂̏̾͊̍͋͊ͧ́̆ͦ͞o̡͋̔͐ͪͩ͏̢̧̫̙̤̮͖͙͓̺̜̩̼̘̠́\",[]],[\"invoke\",662,0,\"︀\",[]],[\"invoke\",663,0,\"︄\",[]],[\"invoke\",664,0,\"󠄀\",[]],[\"invoke\",665,0,\"󠇯\",[]],[\"invoke\",667,0,\"\\n\",[]],[\"invoke\",668,0,\"␤\",[]],[\"invoke\",669,0,\"
\",[]],[\"invoke\",670,0,\"\\r\",[]],[\"invoke\",671,0,\"\\r\\n\",[]],[\"invoke\",673,0,\"\\u001e\",[]],[\"invoke\",674,0,\"\\u000b\",[]],[\"invoke\",675,0,\"\\f\",[]],[\"invoke\",676,0,\"…\",[]],[\"invoke\",677,0,\"
\",[]],[\"invoke\",679,0,\"⏎\",[]],[\"invoke\",680,0,\"‹\",[]],[\"invoke\",681,0,\"Œ\",[]],[\"invoke\",682,0,\"\",[]],[\"invoke\",683,0,\"↵\",[]],[\"invoke\",685,0,\"⌤\",[]],[\"invoke\",686,0,\"⤶\",[]],[\"invoke\",687,0,\"↲\",[]],[\"invoke\",688,0,\"⮨\",[]],[\"invoke\",689,0,\"⮰\",[]],[\"invoke\",691,0,\"﷐\",[]],[\"invoke\",692,0,\"﷑\",[]],[\"invoke\",693,0,\"﷒\",[]],[\"invoke\",694,0,\"﷓\",[]],[\"invoke\",695,0,\"﷔\",[]],[\"invoke\",697,0,\"﷖\",[]],[\"invoke\",698,0,\"﷗\",[]],[\"invoke\",699,0,\"﷘\",[]],[\"invoke\",700,0,\"﷙\",[]],[\"invoke\",701,0,\"﷚\",[]],[\"invoke\",703,0,\"﷜\",[]],[\"invoke\",704,0,\"﷝\",[]],[\"invoke\",705,0,\"﷞\",[]],[\"invoke\",706,0,\"﷟\",[]],[\"invoke\",707,0,\"﷠\",[]],[\"invoke\",709,0,\"﷢\",[]],[\"invoke\",710,0,\"﷣\",[]],[\"invoke\",711,0,\"﷤\",[]],[\"invoke\",712,0,\"﷥\",[]],[\"invoke\",714,0,\"﷧\",[]],[\"invoke\",715,0,\"﷨\",[]],[\"invoke\",716,0,\"﷩\",[]],[\"invoke\",717,0,\"﷪\",[]],[\"invoke\",718,0,\"﷫\",[]],[\"invoke\",720,0,\"﷭\",[]],[\"invoke\",721,0,\"﷮\",[]],[\"invoke\",722,0,\"﷯\",[]],[\"invoke\",723,0,\"￾\",[]],[\"invoke\",724,0,\"￿\",[]],[\"invoke\",726,0,\"🿿\",[]],[\"invoke\",727,0,\"𯿾\",[]],[\"invoke\",728,0,\"𯿿\",[]],[\"invoke\",729,0,\"𿿾\",[]],[\"invoke\",730,0,\"𿿿\",[]],[\"invoke\",732,0,\"񏿿\",[]],[\"invoke\",733,0,\"񟿾\",[]],[\"invoke\",734,0,\"񟿿\",[]],[\"invoke\",735,0,\"񯿾\",[]],[\"invoke\",736,0,\"񯿿\",[]],[\"invoke\",738,0,\"񿿿\",[]],[\"invoke\",739,0,\"򏿾\",[]],[\"invoke\",740,0,\"򏿿\",[]],[\"invoke\",741,0,\"򟿾\",[]],[\"invoke\",742,0,\"򟿿\",[]],[\"invoke\",744,0,\"򯿿\",[]],[\"invoke\",745,0,\"򿿾\",[]],[\"invoke\",746,0,\"򿿿\",[]],[\"invoke\",747,0,\"󏿾\",[]],[\"invoke\",748,0,\"󏿿\",[]],[\"invoke\",750,0,\"󟿿\",[]],[\"invoke\",751,0,\"󯿾\",[]],[\"invoke\",752,0,\"󯿿\",[]],[\"invoke\",753,0,\"󿿾\",[]],[\"invoke\",754,0,\"󿿿\",[]],[\"invoke\",756,0,\"􏿿\",[]],[\"invoke\",757,0,\"̈‽̈̉\",[]],[\"invoke\",758,0,\"abc\",[]],[\"invoke\",759,0,\"‭abc\",[]],[\"invoke\",761,0,\"‭abc‮\",[]],[\"invoke\",762,0,\"‮cba‭\",[]],[\"invoke\",763,0,\"𝑨\",[]],[\"invoke\",764,0,\"𝐴\",[]],[\"invoke\",765,0,\"𝘈\",[]],[\"invoke\",767,0,\"𝐀\",[]],[\"invoke\",768,0,\"𝓐\",[]],[\"invoke\",769,0,\"𝕬\",[]],[\"invoke\",770,0,\"𝗔\",[]],[\"invoke\",771,0,\"𝒜\",[]],[\"invoke\",773,0,\"𝔸\",[]],[\"invoke\",774,0,\"𝖠\",[]],[\"invoke\",775,0,\"𝙰\",[]],[\"invoke\",776,0,\"ᴀ\",[]],[\"invoke\",777,0,\"ᴬ\",[]],[\"invoke\",779,0,\"A\",[]],[\"invoke\",780,0,\"🄐\",[]],[\"invoke\",781,0,\"🄰\",[]],[\"invoke\",782,0,\"󠁁\",[]],[\"invoke\",783,0,\"U+0041\",[]],[\"invoke\",785,0,\"А\",[]],[\"invoke\",786,0,\"Ꙗ\",[]],[\"invoke\",787,0,\"ⷼ\",[]],[\"invoke\",788,0,\"ⷶ\",[]],[\"invoke\",789,0,\"Ɐ\",[]],[\"invoke\",791,0,\"🅰\",[]],[\"invoke\",792,0,\"Ⱝ\",[]],[\"invoke\",793,0,\"𐐂\",[]],[\"invoke\",794,0,\"𐐈\",[]],[\"invoke\",795,0,\"𐒰\",[]],[\"invoke\",797,0,\"Á\",[]],[\"invoke\",798,0,\"Â\",[]],[\"invoke\",799,0,\"Ã\",[]],[\"invoke\",800,0,\"Ä\",[]],[\"invoke\",801,0,\"Ā\",[]],[\"invoke\",803,0,\"Ą\",[]],[\"invoke\",804,0,\"Ǎ\",[]],[\"invoke\",805,0,\"Ǟ\",[]],[\"invoke\",806,0,\"Ǡ\",[]],[\"invoke\",808,0,\"Ȁ\",[]],[\"invoke\",809,0,\"Ȃ\",[]],[\"invoke\",810,0,\"Ȧ\",[]],[\"invoke\",811,0,\"Ⱥ\",[]],[\"invoke\",812,0,\"Ӑ\",[]],[\"invoke\",814,0,\"ߊ\",[]],[\"invoke\",815,0,\"ࠡ\",[]],[\"invoke\",816,0,\"ࠢ\",[]],[\"invoke\",817,0,\"ࠣ\",[]],[\"invoke\",818,0,\"ࠤ\",[]],[\"invoke\",820,0,\"ऄ\",[]],[\"invoke\",821,0,\"अ\",[]],[\"invoke\",822,0,\"ॲ\",[]],[\"invoke\",823,0,\"অ\",[]],[\"invoke\",824,0,\"ਅ\",[]],[\"invoke\",826,0,\"ଅ\",[]],[\"invoke\",827,0,\"அ\",[]],[\"invoke\",828,0,\"అ\",[]],[\"invoke\",829,0,\"ಅ\",[]],[\"invoke\",830,0,\"അ\",[]],[\"invoke\",832,0,\"ະ\",[]],[\"invoke\",833,0,\"༁\",[]],[\"invoke\",834,0,\"ཨ\",[]],[\"invoke\",835,0,\"ྸ\",[]],[\"invoke\",836,0,\"အ\",[]],[\"invoke\",838,0,\"ႜ\",[]],[\"invoke\",839,0,\"ᅡ\",[]],[\"invoke\",840,0,\"አ\",[]],[\"invoke\",841,0,\"ዐ\",[]],[\"invoke\",842,0,\"Ꭰ\",[]],[\"invoke\",844,0,\"ᖳ\",[]],[\"invoke\",845,0,\"ᚨ\",[]],[\"invoke\",846,0,\"ᚪ\",[]],[\"invoke\",847,0,\"ᛆ\",[]],[\"invoke\",848,0,\"ᜀ\",[]],[\"invoke\",850,0,\"ᝀ\",[]],[\"invoke\",851,0,\"ᝠ\",[]],[\"invoke\",852,0,\"ᠠ\",[]],[\"invoke\",853,0,\"ᢇ\",[]],[\"invoke\",855,0,\"ᥣ\",[]],[\"invoke\",856,0,\"ᨕ\",[]],[\"invoke\",857,0,\"ᩋ\",[]],[\"invoke\",858,0,\"ᩡ\",[]],[\"invoke\",859,0,\"ᮃ\",[]],[\"invoke\",861,0,\"ᯁ\",[]],[\"invoke\",862,0,\"ᰣ\",[]],[\"invoke\",863,0,\"Ḁ\",[]],[\"invoke\",864,0,\"Ạ\",[]],[\"invoke\",865,0,\"Ả\",[]],[\"invoke\",867,0,\"Ầ\",[]],[\"invoke\",868,0,\"Ẩ\",[]],[\"invoke\",869,0,\"Ẫ\",[]],[\"invoke\",870,0,\"Ậ\",[]],[\"invoke\",871,0,\"Ắ\",[]],[\"invoke\",873,0,\"Ẳ\",[]],[\"invoke\",874,0,\"Ẵ\",[]],[\"invoke\",875,0,\"Ặ\",[]],[\"invoke\",876,0,\"あ\",[]],[\"invoke\",877,0,\"ア\",[]],[\"invoke\",879,0,\"ㅏ\",[]],[\"invoke\",880,0,\"㈎\",[]],[\"invoke\",881,0,\"㈏\",[]],[\"invoke\",882,0,\"㈐\",[]],[\"invoke\",883,0,\"㈑\",[]],[\"invoke\",885,0,\"㈓\",[]],[\"invoke\",886,0,\"㈔\",[]],[\"invoke\",887,0,\"㈕\",[]],[\"invoke\",888,0,\"㈖\",[]],[\"invoke\",889,0,\"㈗\",[]],[\"invoke\",891,0,\"㈙\",[]],[\"invoke\",892,0,\"㈚\",[]],[\"invoke\",893,0,\"㈛\",[]],[\"invoke\",894,0,\"㉮\",[]],[\"invoke\",895,0,\"㉯\",[]],[\"invoke\",897,0,\"㉱\",[]],[\"invoke\",898,0,\"㉲\",[]],[\"invoke\",899,0,\"㉳\",[]],[\"invoke\",900,0,\"㉴\",[]],[\"invoke\",901,0,\"㉵\",[]],[\"invoke\",903,0,\"㉷\",[]],[\"invoke\",904,0,\"㉸\",[]],[\"invoke\",905,0,\"㉹\",[]],[\"invoke\",906,0,\"㉺\",[]],[\"invoke\",908,0,\"㋐\",[]],[\"invoke\",909,0,\"ꀊ\",[]],[\"invoke\",910,0,\"ꓮ\",[]],[\"invoke\",911,0,\"ꕉ\",[]],[\"invoke\",912,0,\"ꚠ\",[]],[\"invoke\",914,0,\"ꠣ\",[]],[\"invoke\",915,0,\"ꡝ\",[]],[\"invoke\",916,0,\"ꢂ\",[]],[\"invoke\",917,0,\"꣪\",[]],[\"invoke\",918,0,\"ꤢ\",[]],[\"invoke\",920,0,\"ꦄ\",[]],[\"invoke\",921,0,\"ꨀ\",[]],[\"invoke\",922,0,\"ア\",[]],[\"invoke\",923,0,\"ᅡ\",[]],[\"invoke\",924,0,\"𐀀\",[]],[\"invoke\",926,0,\"𐊠\",[]],[\"invoke\",927,0,\"𐌀\",[]],[\"invoke\",928,0,\"𐎠\",[]],[\"invoke\",929,0,\"𐒖\",[]],[\"invoke\",930,0,\"𐔀\",[]],[\"invoke\",932,0,\"𐠀\",[]],[\"invoke\",933,0,\"𐤠\",[]],[\"invoke\",934,0,\"𐦀\",[]],[\"invoke\",935,0,\"𐦠\",[]],[\"invoke\",936,0,\"𐨀\",[]],[\"invoke\",938,0,\"𐰀\",[]],[\"invoke\",939,0,\"𐰁\",[]],[\"invoke\",940,0,\"𐲀\",[]],[\"invoke\",941,0,\"𑀅\",[]],[\"invoke\",942,0,\"𑂃\",[]],[\"invoke\",944,0,\"𑅐\",[]],[\"invoke\",945,0,\"𑆃\",[]],[\"invoke\",946,0,\"𑈀\",[]],[\"invoke\",947,0,\"𑊀\",[]],[\"invoke\",948,0,\"𑊰\",[]],[\"invoke\",950,0,\"𑍰\",[]],[\"invoke\",951,0,\"𑐀\",[]],[\"invoke\",952,0,\"𑒁\",[]],[\"invoke\",953,0,\"𑖀\",[]],[\"invoke\",955,0,\"𑚀\",[]],[\"invoke\",956,0,\"𑜒\",[]],[\"invoke\",957,0,\"𑜠\",[]],[\"invoke\",958,0,\"𑢡\",[]],[\"invoke\",959,0,\"𑫕\",[]],[\"invoke\",961,0,\"𑲏\",[]],[\"invoke\",962,0,\"𑲯\",[]],[\"invoke\",963,0,\"𒀀\",[]],[\"invoke\",964,0,\"𖧕\",[]],[\"invoke\",965,0,\"𖩆\",[]],[\"invoke\",967,0,\"𖽔\",[]],[\"invoke\",968,0,\"𛱁\",[]],[\"invoke\",969,0,\"𛱤\",[]],[\"invoke\",970,0,\"𞠣\",[]],[\"invoke\",971,0,\"🇦\",[]],[\"invoke\",973,0,\"Λ\",[]],[\"invoke\",974,0,\"Ɒ\",[]],[\"invoke\",975,0,\"ª\",[]],[\"invoke\",976,0,\"∀\",[]],[\"invoke\",977,0,\"₳\",[]],[\"invoke\",979,0,\"Ⲁ\",[]],[\"invoke\",980,0,\"𐌰\",[]],[\"invoke\",981,0,\"Ά\",[]],[\"invoke\",982,0,\"Α\",[]],[\"invoke\",983,0,\"Ἀ\",[]],[\"invoke\",985,0,\"Ἂ\",[]],[\"invoke\",986,0,\"Ἃ\",[]],[\"invoke\",987,0,\"Ἄ\",[]],[\"invoke\",988,0,\"Ἅ\",[]],[\"invoke\",989,0,\"Ἆ\",[]],[\"invoke\",991,0,\"ᾈ\",[]],[\"invoke\",992,0,\"ᾉ\",[]],[\"invoke\",993,0,\"ᾊ\",[]],[\"invoke\",994,0,\"ᾋ\",[]],[\"invoke\",995,0,\"ᾌ\",[]],[\"invoke\",997,0,\"ᾎ\",[]],[\"invoke\",998,0,\"ᾏ\",[]],[\"invoke\",999,0,\"Ᾰ\",[]],[\"invoke\",1000,0,\"Ᾱ\",[]],[\"invoke\",1002,0,\"Ά\",[]],[\"invoke\",1003,0,\"ᾼ\",[]],[\"invoke\",1004,0,\"𝚨\",[]],[\"invoke\",1005,0,\"𝛢\",[]],[\"invoke\",1006,0,\"𝜜\",[]],[\"invoke\",1008,0,\"𝞐\",[]],[\"invoke\",1009,0,\"⍶\",[]],[\"invoke\",1010,0,\"⍺\",[]],[\"invoke\",1011,0,\"⩜\",[]],[\"invoke\",1012,0,\"ᗅ\",[]],[\"invoke\",1014,0,\")˺˼𔗏𝅴𝅶𝅸𝅺⁾₎❩❫⟯﴿︶﹚)⦆󠀩❳❵⟧⟩⟫⟭⦈⦊⦖⸣⸥︘︸︺︼︾﹀﹂﹄﹈﹜﹞]}」󠁝󠁽»’”›❯\",[]],[\"invoke\",1015,0,\"(˹˻𔗎𝅳𝅵𝅷𝅹⁽₍❨❪⟮﴾︵﹙(⦅󠀨❲❴⟦⟨⟪⟬⦇⦉⦕⸢⸤︗︷︹︻︽︿﹁﹃﹇﹛﹝[{「󠁛󠁻«‘“‹❮\",[]],[\"invoke\",1016,0,\"𝪋𝪤\",[]],[\"invoke\",1017,0,\"𝪋\",[]],[\"invoke\",1018,0,\"½\",[]],[\"invoke\",1020,0,\"1/2\",[]],[\"invoke\",1021,0,\"୳\",[]],[\"invoke\",1022,0,\"൴\",[]],[\"invoke\",1023,0,\"⳽\",[]],[\"invoke\",1024,0,\"꠱\",[]],[\"invoke\",1026,0,\"𐅵\",[]],[\"invoke\",1027,0,\"𐅶\",[]],[\"invoke\",1028,0,\"𐦽\",[]],[\"invoke\",1029,0,\"𐹻\",[]],[\"invoke\",1030,0,\""\",[]],[\"invoke\",1032,0,\"\\b\",[]],[\"invoke\",1033,0,\"⌫\",[]],[\"invoke\",1034,0,\"⌦\",[]],[\"invoke\",1035,0,\"␈\",[]],[\"invoke\",1036,0,\"␡\",[]],[\"invoke\",1038,0,\"\\u000f\",[]],[\"invoke\",1039,0,\"←\",[]],[\"invoke\",1040,0,\"⌧\",[]],[\"invoke\",1041,0,\"⍒\",[]],[\"invoke\",1042,0,\"⍔\",[]],[\"invoke\",1044,0,\"⍫\",[]],[\"invoke\",1045,0,\"\\u001a\",[]],[\"invoke\",1046,0,\"␦\",[]],[\"invoke\",1047,0,\"␚\",[]],[\"invoke\",1049,0,\"?\",[]],[\"invoke\",1050,0,\"¿\",[]],[\"invoke\",1051,0,\"᥅\",[]],[\"invoke\",1052,0,\";\",[]],[\"invoke\",1053,0,\"՞\",[]],[\"invoke\",1055,0,\"፧\",[]],[\"invoke\",1056,0,\"⁇\",[]],[\"invoke\",1057,0,\"⍰\",[]],[\"invoke\",1058,0,\"❓\",[]],[\"invoke\",1059,0,\"❔\",[]],[\"invoke\",1061,0,\"⳻\",[]],[\"invoke\",1062,0,\"⸮\",[]],[\"invoke\",1063,0,\"㉄\",[]],[\"invoke\",1064,0,\"꘏\",[]],[\"invoke\",1065,0,\"꛷\",[]],[\"invoke\",1067,0,\"﹖\",[]],[\"invoke\",1068,0,\"?\",[]],[\"invoke\",1069,0,\"𑅃\",[]],[\"invoke\",1070,0,\"𞥟\",[]],[\"invoke\",1071,0,\"󠀿\",[]],[\"invoke\",1073,0,\"⯑\",[]],[\"invoke\",1074,0,\"¶\",[]],[\"invoke\",1075,0,\"⁋\",[]],[\"invoke\",1076,0,\"܀\",[]],[\"invoke\",1077,0,\"჻\",[]],[\"invoke\",1079,0,\"〷\",[]],[\"invoke\",1080,0,\"❡\",[]],[\"invoke\",1081,0,\"⸏\",[]],[\"invoke\",1082,0,\"⸐\",[]],[\"invoke\",1083,0,\"⸑\",[]],[\"invoke\",1085,0,\"\\u0014\",[]],[\"invoke\",1086,0,\"☙\",[]],[\"invoke\",1087,0,\"⸿\",[]],[\"invoke\",1088,0,\"〇\",[]],[\"invoke\",1089,0,\"๛\",[]],[\"invoke\",1091,0,\"ϓ\",[]],[\"invoke\",1092,0,\"ϔ\",[]],[\"invoke\",1093,0,\"ẛ\",[]],[\"module\",1095,130],[\"invoke\",1107,0,\"print32\",[\"i32:42\",\"i32:123\"]]]"; diff --git a/tests/corpus/webassembly-spec-imports/main.mjs b/tests/corpus/webassembly-spec-imports/main.mjs new file mode 100644 index 000000000..681908d64 --- /dev/null +++ b/tests/corpus/webassembly-spec-imports/main.mjs @@ -0,0 +1,5 @@ +// Executes WebAssembly spec tests (3 files); see tests/wasm-spec/runner.mjs. +import { run } from "../../wasm-spec/runner.mjs"; +import { modules, script } from "./data.mjs"; + +run(modules, script); diff --git a/tests/corpus/webassembly-spec-memory/data.mjs b/tests/corpus/webassembly-spec-memory/data.mjs index 9b2ec91d7..d62a7e491 100644 --- a/tests/corpus/webassembly-spec-memory/data.mjs +++ b/tests/corpus/webassembly-spec-memory/data.mjs @@ -139,13 +139,24 @@ export const modules = [ "AGFzbQEAAAABBAFgAAADAgEABQMBAAEMAUEKDgEMAEEAQQBBAPwIQAALC4MBQQEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQA=", "AGFzbQEAAAAFAwEAAQuzARwAQQALAABBAQsEYWJjZABBAAsAAEEACwNhYmMAQQALAABBAQsEYWJjZABBAAsAAEEACwNhYmMAQQALAABBAQsEYWJjZABBAAsAAEEACwNhYmMBAAEEYWJjZABBAAsAAEEBCwRhYmNkAEEACwAAQQALA2FiYwBBAAsAAEEBCwRhYmNkAEEACwAAQQALA2FiYwBBAAsAAEEBCwRhYmNkAEEACwAAQQALA2FiYwEAAQRhYmNk", "AGFzbQEAAAAFAwEAAQsHAQBBAAsBYQ==", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgABCwcBAEEACwFh", "AGFzbQEAAAAFAwEAAQsiBQBBAAsBYQBBAwsBYgBB5AALA2NkZQBBBQsBeABBAwsBYw==", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgABCycGAEEACwFhAEEBCwFiAEECCwNjZGUAQQMLAWYAQQILAWcAQQELAWg=", "AGFzbQEAAAACGAEIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AAUDAQABCwcBACMACwFh", + "AGFzbQEAAAACKwIIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AAhzcGVjdGVzdAZtZW1vcnkCAAELBwEAIwALAWE=", "AGFzbQEAAAAFAwEAAQsPAgBBAAsBYQBB//8DCwFi", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgABCw8CAEEACwFhAEH//wMLAWI=", "AGFzbQEAAAAFAwEAAgsJAQBB//8HCwFh", "AGFzbQEAAAAFAwEAAAsGAQBBAAsA", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgAACwYBAEEACwA=", "AGFzbQEAAAAFBAEBAAALBgEAQQALAA==", "AGFzbQEAAAAFAwEAAQsIAQBBgIAECwA=", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgAACwcBAEEACwFh", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QGbWVtb3J5AgEAAwsHAQBBAAsBYQ==", + "AGFzbQEAAAACKwIIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AAhzcGVjdGVzdAZtZW1vcnkCAAALBwEAIwALAWE=", + "AGFzbQEAAAACLAIIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AAhzcGVjdGVzdAZtZW1vcnkCAQADCwcBACMACwFh", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgAACwcBAEEBCwFh", + "AGFzbQEAAAACFQEIc3BlY3Rlc3QGbWVtb3J5AgEAAwsHAQBBAQsBYQ==", "AGFzbQEAAAAFAwEAAAsHAQBBAAsBYQ==", "AGFzbQEAAAAFBAEBAAALBwEAQQALAWE=", "AGFzbQEAAAAFBAEBAAELBwEAQQALAWE=", @@ -153,9 +164,12 @@ export const modules = [ "AGFzbQEAAAAFBAEBAAELBgEAQQELAA==", "AGFzbQEAAAACGAEIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AAUDAQAACwcBACMACwFh", "AGFzbQEAAAAFBAEBAQILCQEAQYCABAsBYQ==", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgABCwkBAEGAgAQLAWE=", "AGFzbQEAAAAFAwEAAgsJAQBBgIAICwFh", "AGFzbQEAAAAFBAEBAgMLCQEAQYCACAsBYQ==", "AGFzbQEAAAAFAwEAAQsHAQBBfwsBYQ==", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgABCwcBAEF/CwFh", "AGFzbQEAAAAFAwEAAgsIAQBBnH8LAWE=", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QGbWVtb3J5AgABCwgBAEGcfwsBYQ==", ]; -export const script = "[[\"file\",\"address.wast\"],[\"module\",3,0],[\"invoke\",104,0,\"8u_good1\",[\"i32:0\"]],[\"invoke\",105,0,\"8u_good2\",[\"i32:0\"]],[\"invoke\",106,0,\"8u_good3\",[\"i32:0\"]],[\"invoke\",107,0,\"8u_good4\",[\"i32:0\"]],[\"invoke\",108,0,\"8u_good5\",[\"i32:0\"]],[\"invoke\",110,0,\"8s_good1\",[\"i32:0\"]],[\"invoke\",111,0,\"8s_good2\",[\"i32:0\"]],[\"invoke\",112,0,\"8s_good3\",[\"i32:0\"]],[\"invoke\",113,0,\"8s_good4\",[\"i32:0\"]],[\"invoke\",114,0,\"8s_good5\",[\"i32:0\"]],[\"invoke\",116,0,\"16u_good1\",[\"i32:0\"]],[\"invoke\",117,0,\"16u_good2\",[\"i32:0\"]],[\"invoke\",118,0,\"16u_good3\",[\"i32:0\"]],[\"invoke\",119,0,\"16u_good4\",[\"i32:0\"]],[\"invoke\",120,0,\"16u_good5\",[\"i32:0\"]],[\"invoke\",122,0,\"16s_good1\",[\"i32:0\"]],[\"invoke\",123,0,\"16s_good2\",[\"i32:0\"]],[\"invoke\",124,0,\"16s_good3\",[\"i32:0\"]],[\"invoke\",125,0,\"16s_good4\",[\"i32:0\"]],[\"invoke\",126,0,\"16s_good5\",[\"i32:0\"]],[\"invoke\",128,0,\"32_good1\",[\"i32:0\"]],[\"invoke\",129,0,\"32_good2\",[\"i32:0\"]],[\"invoke\",130,0,\"32_good3\",[\"i32:0\"]],[\"invoke\",131,0,\"32_good4\",[\"i32:0\"]],[\"invoke\",132,0,\"32_good5\",[\"i32:0\"]],[\"invoke\",134,0,\"8u_good1\",[\"i32:65507\"]],[\"invoke\",135,0,\"8u_good2\",[\"i32:65507\"]],[\"invoke\",136,0,\"8u_good3\",[\"i32:65507\"]],[\"invoke\",137,0,\"8u_good4\",[\"i32:65507\"]],[\"invoke\",138,0,\"8u_good5\",[\"i32:65507\"]],[\"invoke\",140,0,\"8s_good1\",[\"i32:65507\"]],[\"invoke\",141,0,\"8s_good2\",[\"i32:65507\"]],[\"invoke\",142,0,\"8s_good3\",[\"i32:65507\"]],[\"invoke\",143,0,\"8s_good4\",[\"i32:65507\"]],[\"invoke\",144,0,\"8s_good5\",[\"i32:65507\"]],[\"invoke\",146,0,\"16u_good1\",[\"i32:65507\"]],[\"invoke\",147,0,\"16u_good2\",[\"i32:65507\"]],[\"invoke\",148,0,\"16u_good3\",[\"i32:65507\"]],[\"invoke\",149,0,\"16u_good4\",[\"i32:65507\"]],[\"invoke\",150,0,\"16u_good5\",[\"i32:65507\"]],[\"invoke\",152,0,\"16s_good1\",[\"i32:65507\"]],[\"invoke\",153,0,\"16s_good2\",[\"i32:65507\"]],[\"invoke\",154,0,\"16s_good3\",[\"i32:65507\"]],[\"invoke\",155,0,\"16s_good4\",[\"i32:65507\"]],[\"invoke\",156,0,\"16s_good5\",[\"i32:65507\"]],[\"invoke\",158,0,\"32_good1\",[\"i32:65507\"]],[\"invoke\",159,0,\"32_good2\",[\"i32:65507\"]],[\"invoke\",160,0,\"32_good3\",[\"i32:65507\"]],[\"invoke\",161,0,\"32_good4\",[\"i32:65507\"]],[\"invoke\",162,0,\"32_good5\",[\"i32:65507\"]],[\"invoke\",164,0,\"8u_good1\",[\"i32:65508\"]],[\"invoke\",165,0,\"8u_good2\",[\"i32:65508\"]],[\"invoke\",166,0,\"8u_good3\",[\"i32:65508\"]],[\"invoke\",167,0,\"8u_good4\",[\"i32:65508\"]],[\"invoke\",168,0,\"8u_good5\",[\"i32:65508\"]],[\"invoke\",170,0,\"8s_good1\",[\"i32:65508\"]],[\"invoke\",171,0,\"8s_good2\",[\"i32:65508\"]],[\"invoke\",172,0,\"8s_good3\",[\"i32:65508\"]],[\"invoke\",173,0,\"8s_good4\",[\"i32:65508\"]],[\"invoke\",174,0,\"8s_good5\",[\"i32:65508\"]],[\"invoke\",176,0,\"16u_good1\",[\"i32:65508\"]],[\"invoke\",177,0,\"16u_good2\",[\"i32:65508\"]],[\"invoke\",178,0,\"16u_good3\",[\"i32:65508\"]],[\"invoke\",179,0,\"16u_good4\",[\"i32:65508\"]],[\"invoke\",180,0,\"16u_good5\",[\"i32:65508\"]],[\"invoke\",182,0,\"16s_good1\",[\"i32:65508\"]],[\"invoke\",183,0,\"16s_good2\",[\"i32:65508\"]],[\"invoke\",184,0,\"16s_good3\",[\"i32:65508\"]],[\"invoke\",185,0,\"16s_good4\",[\"i32:65508\"]],[\"invoke\",186,0,\"16s_good5\",[\"i32:65508\"]],[\"invoke\",188,0,\"32_good1\",[\"i32:65508\"]],[\"invoke\",189,0,\"32_good2\",[\"i32:65508\"]],[\"invoke\",190,0,\"32_good3\",[\"i32:65508\"]],[\"invoke\",191,0,\"32_good4\",[\"i32:65508\"]],[\"invoke\",192,0,\"32_good5\",[\"i32:65508\"]],[\"invoke\",194,0,\"8u_good3\",[\"i32:4294967295\"]],[\"invoke\",195,0,\"8s_good3\",[\"i32:4294967295\"]],[\"invoke\",196,0,\"16u_good3\",[\"i32:4294967295\"]],[\"invoke\",197,0,\"16s_good3\",[\"i32:4294967295\"]],[\"invoke\",198,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",199,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",201,0,\"8u_bad\",[\"i32:0\"]],[\"invoke\",202,0,\"8s_bad\",[\"i32:0\"]],[\"invoke\",203,0,\"16u_bad\",[\"i32:0\"]],[\"invoke\",204,0,\"16s_bad\",[\"i32:0\"]],[\"invoke\",205,0,\"32_bad\",[\"i32:0\"]],[\"invoke\",207,0,\"8u_bad\",[\"i32:1\"]],[\"invoke\",208,0,\"8s_bad\",[\"i32:1\"]],[\"invoke\",209,0,\"16u_bad\",[\"i32:1\"]],[\"invoke\",210,0,\"16s_bad\",[\"i32:1\"]],[\"invoke\",211,0,\"32_bad\",[\"i32:1\"]],[\"module\",223,1],[\"invoke\",362,0,\"8u_good1\",[\"i32:0\"]],[\"invoke\",363,0,\"8u_good2\",[\"i32:0\"]],[\"invoke\",364,0,\"8u_good3\",[\"i32:0\"]],[\"invoke\",365,0,\"8u_good4\",[\"i32:0\"]],[\"invoke\",366,0,\"8u_good5\",[\"i32:0\"]],[\"invoke\",368,0,\"8s_good1\",[\"i32:0\"]],[\"invoke\",369,0,\"8s_good2\",[\"i32:0\"]],[\"invoke\",370,0,\"8s_good3\",[\"i32:0\"]],[\"invoke\",371,0,\"8s_good4\",[\"i32:0\"]],[\"invoke\",372,0,\"8s_good5\",[\"i32:0\"]],[\"invoke\",374,0,\"16u_good1\",[\"i32:0\"]],[\"invoke\",375,0,\"16u_good2\",[\"i32:0\"]],[\"invoke\",376,0,\"16u_good3\",[\"i32:0\"]],[\"invoke\",377,0,\"16u_good4\",[\"i32:0\"]],[\"invoke\",378,0,\"16u_good5\",[\"i32:0\"]],[\"invoke\",380,0,\"16s_good1\",[\"i32:0\"]],[\"invoke\",381,0,\"16s_good2\",[\"i32:0\"]],[\"invoke\",382,0,\"16s_good3\",[\"i32:0\"]],[\"invoke\",383,0,\"16s_good4\",[\"i32:0\"]],[\"invoke\",384,0,\"16s_good5\",[\"i32:0\"]],[\"invoke\",386,0,\"32u_good1\",[\"i32:0\"]],[\"invoke\",387,0,\"32u_good2\",[\"i32:0\"]],[\"invoke\",388,0,\"32u_good3\",[\"i32:0\"]],[\"invoke\",389,0,\"32u_good4\",[\"i32:0\"]],[\"invoke\",390,0,\"32u_good5\",[\"i32:0\"]],[\"invoke\",392,0,\"32s_good1\",[\"i32:0\"]],[\"invoke\",393,0,\"32s_good2\",[\"i32:0\"]],[\"invoke\",394,0,\"32s_good3\",[\"i32:0\"]],[\"invoke\",395,0,\"32s_good4\",[\"i32:0\"]],[\"invoke\",396,0,\"32s_good5\",[\"i32:0\"]],[\"invoke\",398,0,\"64_good1\",[\"i32:0\"]],[\"invoke\",399,0,\"64_good2\",[\"i32:0\"]],[\"invoke\",400,0,\"64_good3\",[\"i32:0\"]],[\"invoke\",401,0,\"64_good4\",[\"i32:0\"]],[\"invoke\",402,0,\"64_good5\",[\"i32:0\"]],[\"invoke\",404,0,\"8u_good1\",[\"i32:65503\"]],[\"invoke\",405,0,\"8u_good2\",[\"i32:65503\"]],[\"invoke\",406,0,\"8u_good3\",[\"i32:65503\"]],[\"invoke\",407,0,\"8u_good4\",[\"i32:65503\"]],[\"invoke\",408,0,\"8u_good5\",[\"i32:65503\"]],[\"invoke\",410,0,\"8s_good1\",[\"i32:65503\"]],[\"invoke\",411,0,\"8s_good2\",[\"i32:65503\"]],[\"invoke\",412,0,\"8s_good3\",[\"i32:65503\"]],[\"invoke\",413,0,\"8s_good4\",[\"i32:65503\"]],[\"invoke\",414,0,\"8s_good5\",[\"i32:65503\"]],[\"invoke\",416,0,\"16u_good1\",[\"i32:65503\"]],[\"invoke\",417,0,\"16u_good2\",[\"i32:65503\"]],[\"invoke\",418,0,\"16u_good3\",[\"i32:65503\"]],[\"invoke\",419,0,\"16u_good4\",[\"i32:65503\"]],[\"invoke\",420,0,\"16u_good5\",[\"i32:65503\"]],[\"invoke\",422,0,\"16s_good1\",[\"i32:65503\"]],[\"invoke\",423,0,\"16s_good2\",[\"i32:65503\"]],[\"invoke\",424,0,\"16s_good3\",[\"i32:65503\"]],[\"invoke\",425,0,\"16s_good4\",[\"i32:65503\"]],[\"invoke\",426,0,\"16s_good5\",[\"i32:65503\"]],[\"invoke\",428,0,\"32u_good1\",[\"i32:65503\"]],[\"invoke\",429,0,\"32u_good2\",[\"i32:65503\"]],[\"invoke\",430,0,\"32u_good3\",[\"i32:65503\"]],[\"invoke\",431,0,\"32u_good4\",[\"i32:65503\"]],[\"invoke\",432,0,\"32u_good5\",[\"i32:65503\"]],[\"invoke\",434,0,\"32s_good1\",[\"i32:65503\"]],[\"invoke\",435,0,\"32s_good2\",[\"i32:65503\"]],[\"invoke\",436,0,\"32s_good3\",[\"i32:65503\"]],[\"invoke\",437,0,\"32s_good4\",[\"i32:65503\"]],[\"invoke\",438,0,\"32s_good5\",[\"i32:65503\"]],[\"invoke\",440,0,\"64_good1\",[\"i32:65503\"]],[\"invoke\",441,0,\"64_good2\",[\"i32:65503\"]],[\"invoke\",442,0,\"64_good3\",[\"i32:65503\"]],[\"invoke\",443,0,\"64_good4\",[\"i32:65503\"]],[\"invoke\",444,0,\"64_good5\",[\"i32:65503\"]],[\"invoke\",446,0,\"8u_good1\",[\"i32:65504\"]],[\"invoke\",447,0,\"8u_good2\",[\"i32:65504\"]],[\"invoke\",448,0,\"8u_good3\",[\"i32:65504\"]],[\"invoke\",449,0,\"8u_good4\",[\"i32:65504\"]],[\"invoke\",450,0,\"8u_good5\",[\"i32:65504\"]],[\"invoke\",452,0,\"8s_good1\",[\"i32:65504\"]],[\"invoke\",453,0,\"8s_good2\",[\"i32:65504\"]],[\"invoke\",454,0,\"8s_good3\",[\"i32:65504\"]],[\"invoke\",455,0,\"8s_good4\",[\"i32:65504\"]],[\"invoke\",456,0,\"8s_good5\",[\"i32:65504\"]],[\"invoke\",458,0,\"16u_good1\",[\"i32:65504\"]],[\"invoke\",459,0,\"16u_good2\",[\"i32:65504\"]],[\"invoke\",460,0,\"16u_good3\",[\"i32:65504\"]],[\"invoke\",461,0,\"16u_good4\",[\"i32:65504\"]],[\"invoke\",462,0,\"16u_good5\",[\"i32:65504\"]],[\"invoke\",464,0,\"16s_good1\",[\"i32:65504\"]],[\"invoke\",465,0,\"16s_good2\",[\"i32:65504\"]],[\"invoke\",466,0,\"16s_good3\",[\"i32:65504\"]],[\"invoke\",467,0,\"16s_good4\",[\"i32:65504\"]],[\"invoke\",468,0,\"16s_good5\",[\"i32:65504\"]],[\"invoke\",470,0,\"32u_good1\",[\"i32:65504\"]],[\"invoke\",471,0,\"32u_good2\",[\"i32:65504\"]],[\"invoke\",472,0,\"32u_good3\",[\"i32:65504\"]],[\"invoke\",473,0,\"32u_good4\",[\"i32:65504\"]],[\"invoke\",474,0,\"32u_good5\",[\"i32:65504\"]],[\"invoke\",476,0,\"32s_good1\",[\"i32:65504\"]],[\"invoke\",477,0,\"32s_good2\",[\"i32:65504\"]],[\"invoke\",478,0,\"32s_good3\",[\"i32:65504\"]],[\"invoke\",479,0,\"32s_good4\",[\"i32:65504\"]],[\"invoke\",480,0,\"32s_good5\",[\"i32:65504\"]],[\"invoke\",482,0,\"64_good1\",[\"i32:65504\"]],[\"invoke\",483,0,\"64_good2\",[\"i32:65504\"]],[\"invoke\",484,0,\"64_good3\",[\"i32:65504\"]],[\"invoke\",485,0,\"64_good4\",[\"i32:65504\"]],[\"invoke\",486,0,\"64_good5\",[\"i32:65504\"]],[\"invoke\",488,0,\"8u_good3\",[\"i32:4294967295\"]],[\"invoke\",489,0,\"8s_good3\",[\"i32:4294967295\"]],[\"invoke\",490,0,\"16u_good3\",[\"i32:4294967295\"]],[\"invoke\",491,0,\"16s_good3\",[\"i32:4294967295\"]],[\"invoke\",492,0,\"32u_good3\",[\"i32:4294967295\"]],[\"invoke\",493,0,\"32s_good3\",[\"i32:4294967295\"]],[\"invoke\",494,0,\"64_good3\",[\"i32:4294967295\"]],[\"invoke\",496,0,\"8u_bad\",[\"i32:0\"]],[\"invoke\",497,0,\"8s_bad\",[\"i32:0\"]],[\"invoke\",498,0,\"16u_bad\",[\"i32:0\"]],[\"invoke\",499,0,\"16s_bad\",[\"i32:0\"]],[\"invoke\",500,0,\"32u_bad\",[\"i32:0\"]],[\"invoke\",501,0,\"32s_bad\",[\"i32:0\"]],[\"invoke\",502,0,\"64_bad\",[\"i32:0\"]],[\"invoke\",504,0,\"8u_bad\",[\"i32:1\"]],[\"invoke\",505,0,\"8s_bad\",[\"i32:1\"]],[\"invoke\",506,0,\"16u_bad\",[\"i32:1\"]],[\"invoke\",507,0,\"16s_bad\",[\"i32:1\"]],[\"invoke\",508,0,\"32u_bad\",[\"i32:0\"]],[\"invoke\",509,0,\"32s_bad\",[\"i32:0\"]],[\"invoke\",510,0,\"64_bad\",[\"i32:1\"]],[\"module\",514,2],[\"invoke\",538,0,\"32_good1\",[\"i32:0\"]],[\"invoke\",539,0,\"32_good2\",[\"i32:0\"]],[\"invoke\",540,0,\"32_good3\",[\"i32:0\"]],[\"invoke\",541,0,\"32_good4\",[\"i32:0\"]],[\"invoke\",542,0,\"32_good5\",[\"i32:0\"]],[\"invoke\",544,0,\"32_good1\",[\"i32:65524\"]],[\"invoke\",545,0,\"32_good2\",[\"i32:65524\"]],[\"invoke\",546,0,\"32_good3\",[\"i32:65524\"]],[\"invoke\",547,0,\"32_good4\",[\"i32:65524\"]],[\"invoke\",548,0,\"32_good5\",[\"i32:65524\"]],[\"invoke\",550,0,\"32_good1\",[\"i32:65525\"]],[\"invoke\",551,0,\"32_good2\",[\"i32:65525\"]],[\"invoke\",552,0,\"32_good3\",[\"i32:65525\"]],[\"invoke\",553,0,\"32_good4\",[\"i32:65525\"]],[\"invoke\",554,0,\"32_good5\",[\"i32:65525\"]],[\"invoke\",556,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",557,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",559,0,\"32_bad\",[\"i32:0\"]],[\"invoke\",560,0,\"32_bad\",[\"i32:1\"]],[\"module\",564,3],[\"invoke\",588,0,\"64_good1\",[\"i32:0\"]],[\"invoke\",589,0,\"64_good2\",[\"i32:0\"]],[\"invoke\",590,0,\"64_good3\",[\"i32:0\"]],[\"invoke\",591,0,\"64_good4\",[\"i32:0\"]],[\"invoke\",592,0,\"64_good5\",[\"i32:0\"]],[\"invoke\",594,0,\"64_good1\",[\"i32:65510\"]],[\"invoke\",595,0,\"64_good2\",[\"i32:65510\"]],[\"invoke\",596,0,\"64_good3\",[\"i32:65510\"]],[\"invoke\",597,0,\"64_good4\",[\"i32:65510\"]],[\"invoke\",598,0,\"64_good5\",[\"i32:65510\"]],[\"invoke\",600,0,\"64_good1\",[\"i32:65511\"]],[\"invoke\",601,0,\"64_good2\",[\"i32:65511\"]],[\"invoke\",602,0,\"64_good3\",[\"i32:65511\"]],[\"invoke\",603,0,\"64_good4\",[\"i32:65511\"]],[\"invoke\",604,0,\"64_good5\",[\"i32:65511\"]],[\"invoke\",606,0,\"64_good3\",[\"i32:4294967295\"]],[\"invoke\",607,0,\"64_good3\",[\"i32:4294967295\"]],[\"invoke\",609,0,\"64_bad\",[\"i32:0\"]],[\"invoke\",610,0,\"64_bad\",[\"i32:1\"]],[\"file\",\"align.wast\"],[\"module\",3,4],[\"module\",4,5],[\"module\",5,6],[\"module\",6,7],[\"module\",7,8],[\"module\",8,9],[\"module\",9,10],[\"module\",10,11],[\"module\",11,12],[\"module\",12,13],[\"module\",13,14],[\"module\",14,15],[\"module\",15,16],[\"module\",16,17],[\"module\",17,18],[\"module\",18,19],[\"module\",19,20],[\"module\",20,21],[\"module\",21,22],[\"module\",22,23],[\"module\",23,24],[\"module\",24,25],[\"module\",25,26],[\"module\",458,27],[\"invoke\",802,0,\"f32_align_switch\",[\"i32:0\"]],[\"invoke\",803,0,\"f32_align_switch\",[\"i32:1\"]],[\"invoke\",804,0,\"f32_align_switch\",[\"i32:2\"]],[\"invoke\",805,0,\"f32_align_switch\",[\"i32:3\"]],[\"invoke\",807,0,\"f64_align_switch\",[\"i32:0\"]],[\"invoke\",808,0,\"f64_align_switch\",[\"i32:1\"]],[\"invoke\",809,0,\"f64_align_switch\",[\"i32:2\"]],[\"invoke\",810,0,\"f64_align_switch\",[\"i32:3\"]],[\"invoke\",811,0,\"f64_align_switch\",[\"i32:4\"]],[\"invoke\",813,0,\"i32_align_switch\",[\"i32:0\",\"i32:0\"]],[\"invoke\",814,0,\"i32_align_switch\",[\"i32:0\",\"i32:1\"]],[\"invoke\",815,0,\"i32_align_switch\",[\"i32:1\",\"i32:0\"]],[\"invoke\",816,0,\"i32_align_switch\",[\"i32:1\",\"i32:1\"]],[\"invoke\",817,0,\"i32_align_switch\",[\"i32:2\",\"i32:0\"]],[\"invoke\",818,0,\"i32_align_switch\",[\"i32:2\",\"i32:1\"]],[\"invoke\",819,0,\"i32_align_switch\",[\"i32:2\",\"i32:2\"]],[\"invoke\",820,0,\"i32_align_switch\",[\"i32:3\",\"i32:0\"]],[\"invoke\",821,0,\"i32_align_switch\",[\"i32:3\",\"i32:1\"]],[\"invoke\",822,0,\"i32_align_switch\",[\"i32:3\",\"i32:2\"]],[\"invoke\",823,0,\"i32_align_switch\",[\"i32:4\",\"i32:0\"]],[\"invoke\",824,0,\"i32_align_switch\",[\"i32:4\",\"i32:1\"]],[\"invoke\",825,0,\"i32_align_switch\",[\"i32:4\",\"i32:2\"]],[\"invoke\",826,0,\"i32_align_switch\",[\"i32:4\",\"i32:4\"]],[\"invoke\",828,0,\"i64_align_switch\",[\"i32:0\",\"i32:0\"]],[\"invoke\",829,0,\"i64_align_switch\",[\"i32:0\",\"i32:1\"]],[\"invoke\",830,0,\"i64_align_switch\",[\"i32:1\",\"i32:0\"]],[\"invoke\",831,0,\"i64_align_switch\",[\"i32:1\",\"i32:1\"]],[\"invoke\",832,0,\"i64_align_switch\",[\"i32:2\",\"i32:0\"]],[\"invoke\",833,0,\"i64_align_switch\",[\"i32:2\",\"i32:1\"]],[\"invoke\",834,0,\"i64_align_switch\",[\"i32:2\",\"i32:2\"]],[\"invoke\",835,0,\"i64_align_switch\",[\"i32:3\",\"i32:0\"]],[\"invoke\",836,0,\"i64_align_switch\",[\"i32:3\",\"i32:1\"]],[\"invoke\",837,0,\"i64_align_switch\",[\"i32:3\",\"i32:2\"]],[\"invoke\",838,0,\"i64_align_switch\",[\"i32:4\",\"i32:0\"]],[\"invoke\",839,0,\"i64_align_switch\",[\"i32:4\",\"i32:1\"]],[\"invoke\",840,0,\"i64_align_switch\",[\"i32:4\",\"i32:2\"]],[\"invoke\",841,0,\"i64_align_switch\",[\"i32:4\",\"i32:4\"]],[\"invoke\",842,0,\"i64_align_switch\",[\"i32:5\",\"i32:0\"]],[\"invoke\",843,0,\"i64_align_switch\",[\"i32:5\",\"i32:1\"]],[\"invoke\",844,0,\"i64_align_switch\",[\"i32:5\",\"i32:2\"]],[\"invoke\",845,0,\"i64_align_switch\",[\"i32:5\",\"i32:4\"]],[\"invoke\",846,0,\"i64_align_switch\",[\"i32:6\",\"i32:0\"]],[\"invoke\",847,0,\"i64_align_switch\",[\"i32:6\",\"i32:1\"]],[\"invoke\",848,0,\"i64_align_switch\",[\"i32:6\",\"i32:2\"]],[\"invoke\",849,0,\"i64_align_switch\",[\"i32:6\",\"i32:4\"]],[\"invoke\",850,0,\"i64_align_switch\",[\"i32:6\",\"i32:8\"]],[\"module\",854,28],[\"invoke\",864,0,\"store\",[\"i32:65532\",\"i64:18446744073709551615\"]],[\"invoke\",866,0,\"load\",[\"i32:65532\"]],[\"file\",\"endianness.wast\"],[\"module\",1,29],[\"invoke\",133,0,\"i32_load16_s\",[\"i32:4294967295\"]],[\"invoke\",134,0,\"i32_load16_s\",[\"i32:4294963054\"]],[\"invoke\",135,0,\"i32_load16_s\",[\"i32:42\"]],[\"invoke\",136,0,\"i32_load16_s\",[\"i32:12816\"]],[\"invoke\",138,0,\"i32_load16_u\",[\"i32:4294967295\"]],[\"invoke\",139,0,\"i32_load16_u\",[\"i32:4294963054\"]],[\"invoke\",140,0,\"i32_load16_u\",[\"i32:42\"]],[\"invoke\",141,0,\"i32_load16_u\",[\"i32:51966\"]],[\"invoke\",143,0,\"i32_load\",[\"i32:4294967295\"]],[\"invoke\",144,0,\"i32_load\",[\"i32:4252543054\"]],[\"invoke\",145,0,\"i32_load\",[\"i32:42424242\"]],[\"invoke\",146,0,\"i32_load\",[\"i32:2880249322\"]],[\"invoke\",148,0,\"i64_load16_s\",[\"i64:18446744073709551615\"]],[\"invoke\",149,0,\"i64_load16_s\",[\"i64:18446744073709547374\"]],[\"invoke\",150,0,\"i64_load16_s\",[\"i64:42\"]],[\"invoke\",151,0,\"i64_load16_s\",[\"i64:12816\"]],[\"invoke\",153,0,\"i64_load16_u\",[\"i64:18446744073709551615\"]],[\"invoke\",154,0,\"i64_load16_u\",[\"i64:18446744073709547374\"]],[\"invoke\",155,0,\"i64_load16_u\",[\"i64:42\"]],[\"invoke\",156,0,\"i64_load16_u\",[\"i64:51966\"]],[\"invoke\",158,0,\"i64_load32_s\",[\"i64:18446744073709551615\"]],[\"invoke\",159,0,\"i64_load32_s\",[\"i64:18446744073667127374\"]],[\"invoke\",160,0,\"i64_load32_s\",[\"i64:42424242\"]],[\"invoke\",161,0,\"i64_load32_s\",[\"i64:305419896\"]],[\"invoke\",163,0,\"i64_load32_u\",[\"i64:18446744073709551615\"]],[\"invoke\",164,0,\"i64_load32_u\",[\"i64:18446744073667127374\"]],[\"invoke\",165,0,\"i64_load32_u\",[\"i64:42424242\"]],[\"invoke\",166,0,\"i64_load32_u\",[\"i64:2880249322\"]],[\"invoke\",168,0,\"i64_load\",[\"i64:18446744073709551615\"]],[\"invoke\",169,0,\"i64_load\",[\"i64:18446744073667127374\"]],[\"invoke\",170,0,\"i64_load\",[\"i64:2880249322\"]],[\"invoke\",171,0,\"i64_load\",[\"i64:12370766947463011818\"]],[\"invoke\",173,0,\"f32_load\",[\"f32:3212836864\"]],[\"invoke\",174,0,\"f32_load\",[\"f32:1011494326\"]],[\"invoke\",175,0,\"f32_load\",[\"f32:1166316389\"]],[\"invoke\",176,0,\"f32_load\",[\"f32:2139095039\"]],[\"invoke\",178,0,\"f64_load\",[\"f64:13830554455654793216\"]],[\"invoke\",179,0,\"f64_load\",[\"f64:4653144502447687399\"]],[\"invoke\",180,0,\"f64_load\",[\"f64:4691032041816096430\"]],[\"invoke\",181,0,\"f64_load\",[\"f64:9218868437227405311\"]],[\"invoke\",184,0,\"i32_store16\",[\"i32:4294967295\"]],[\"invoke\",185,0,\"i32_store16\",[\"i32:4294963054\"]],[\"invoke\",186,0,\"i32_store16\",[\"i32:42\"]],[\"invoke\",187,0,\"i32_store16\",[\"i32:51966\"]],[\"invoke\",189,0,\"i32_store\",[\"i32:4294967295\"]],[\"invoke\",190,0,\"i32_store\",[\"i32:4294963054\"]],[\"invoke\",191,0,\"i32_store\",[\"i32:42424242\"]],[\"invoke\",192,0,\"i32_store\",[\"i32:3735931646\"]],[\"invoke\",194,0,\"i64_store16\",[\"i64:18446744073709551615\"]],[\"invoke\",195,0,\"i64_store16\",[\"i64:18446744073709547374\"]],[\"invoke\",196,0,\"i64_store16\",[\"i64:42\"]],[\"invoke\",197,0,\"i64_store16\",[\"i64:51966\"]],[\"invoke\",199,0,\"i64_store32\",[\"i64:18446744073709551615\"]],[\"invoke\",200,0,\"i64_store32\",[\"i64:18446744073709547374\"]],[\"invoke\",201,0,\"i64_store32\",[\"i64:42424242\"]],[\"invoke\",202,0,\"i64_store32\",[\"i64:3735931646\"]],[\"invoke\",204,0,\"i64_store\",[\"i64:18446744073709551615\"]],[\"invoke\",205,0,\"i64_store\",[\"i64:18446744073667127374\"]],[\"invoke\",206,0,\"i64_store\",[\"i64:2880249322\"]],[\"invoke\",207,0,\"i64_store\",[\"i64:12370766947463011818\"]],[\"invoke\",209,0,\"f32_store\",[\"f32:3212836864\"]],[\"invoke\",210,0,\"f32_store\",[\"f32:1011494326\"]],[\"invoke\",211,0,\"f32_store\",[\"f32:1166316389\"]],[\"invoke\",212,0,\"f32_store\",[\"f32:2139095039\"]],[\"invoke\",214,0,\"f64_store\",[\"f64:13830554455654793216\"]],[\"invoke\",215,0,\"f64_store\",[\"f64:4653144502447687399\"]],[\"invoke\",216,0,\"f64_store\",[\"f64:4691032041816096430\"]],[\"invoke\",217,0,\"f64_store\",[\"f64:9218868437227405311\"]],[\"file\",\"float_memory.wast\"],[\"module\",5,30],[\"invoke\",15,0,\"i32.load\",[]],[\"invoke\",16,0,\"f32.load\",[]],[\"invoke\",17,0,\"reset\",[]],[\"invoke\",18,0,\"i32.load\",[]],[\"invoke\",19,0,\"f32.load\",[]],[\"invoke\",20,0,\"f32.store\",[]],[\"invoke\",21,0,\"i32.load\",[]],[\"invoke\",22,0,\"f32.load\",[]],[\"invoke\",23,0,\"reset\",[]],[\"invoke\",24,0,\"i32.load\",[]],[\"invoke\",25,0,\"f32.load\",[]],[\"invoke\",26,0,\"i32.store\",[]],[\"invoke\",27,0,\"i32.load\",[]],[\"invoke\",28,0,\"f32.load\",[]],[\"module\",30,31],[\"invoke\",40,0,\"i64.load\",[]],[\"invoke\",41,0,\"f64.load\",[]],[\"invoke\",42,0,\"reset\",[]],[\"invoke\",43,0,\"i64.load\",[]],[\"invoke\",44,0,\"f64.load\",[]],[\"invoke\",45,0,\"f64.store\",[]],[\"invoke\",46,0,\"i64.load\",[]],[\"invoke\",47,0,\"f64.load\",[]],[\"invoke\",48,0,\"reset\",[]],[\"invoke\",49,0,\"i64.load\",[]],[\"invoke\",50,0,\"f64.load\",[]],[\"invoke\",51,0,\"i64.store\",[]],[\"invoke\",52,0,\"i64.load\",[]],[\"invoke\",53,0,\"f64.load\",[]],[\"module\",57,32],[\"invoke\",67,0,\"i32.load\",[]],[\"invoke\",68,0,\"f32.load\",[]],[\"invoke\",69,0,\"reset\",[]],[\"invoke\",70,0,\"i32.load\",[]],[\"invoke\",71,0,\"f32.load\",[]],[\"invoke\",72,0,\"f32.store\",[]],[\"invoke\",73,0,\"i32.load\",[]],[\"invoke\",74,0,\"f32.load\",[]],[\"invoke\",75,0,\"reset\",[]],[\"invoke\",76,0,\"i32.load\",[]],[\"invoke\",77,0,\"f32.load\",[]],[\"invoke\",78,0,\"i32.store\",[]],[\"invoke\",79,0,\"i32.load\",[]],[\"invoke\",80,0,\"f32.load\",[]],[\"module\",82,33],[\"invoke\",92,0,\"i64.load\",[]],[\"invoke\",93,0,\"f64.load\",[]],[\"invoke\",94,0,\"reset\",[]],[\"invoke\",95,0,\"i64.load\",[]],[\"invoke\",96,0,\"f64.load\",[]],[\"invoke\",97,0,\"f64.store\",[]],[\"invoke\",98,0,\"i64.load\",[]],[\"invoke\",99,0,\"f64.load\",[]],[\"invoke\",100,0,\"reset\",[]],[\"invoke\",101,0,\"i64.load\",[]],[\"invoke\",102,0,\"f64.load\",[]],[\"invoke\",103,0,\"i64.store\",[]],[\"invoke\",104,0,\"i64.load\",[]],[\"invoke\",105,0,\"f64.load\",[]],[\"module\",109,34],[\"invoke\",119,0,\"i32.load\",[]],[\"invoke\",120,0,\"f32.load\",[]],[\"invoke\",121,0,\"reset\",[]],[\"invoke\",122,0,\"i32.load\",[]],[\"invoke\",123,0,\"f32.load\",[]],[\"invoke\",124,0,\"f32.store\",[]],[\"invoke\",125,0,\"i32.load\",[]],[\"invoke\",126,0,\"f32.load\",[]],[\"invoke\",127,0,\"reset\",[]],[\"invoke\",128,0,\"i32.load\",[]],[\"invoke\",129,0,\"f32.load\",[]],[\"invoke\",130,0,\"i32.store\",[]],[\"invoke\",131,0,\"i32.load\",[]],[\"invoke\",132,0,\"f32.load\",[]],[\"module\",134,35],[\"invoke\",144,0,\"i64.load\",[]],[\"invoke\",145,0,\"f64.load\",[]],[\"invoke\",146,0,\"reset\",[]],[\"invoke\",147,0,\"i64.load\",[]],[\"invoke\",148,0,\"f64.load\",[]],[\"invoke\",149,0,\"f64.store\",[]],[\"invoke\",150,0,\"i64.load\",[]],[\"invoke\",151,0,\"f64.load\",[]],[\"invoke\",152,0,\"reset\",[]],[\"invoke\",153,0,\"i64.load\",[]],[\"invoke\",154,0,\"f64.load\",[]],[\"invoke\",155,0,\"i64.store\",[]],[\"invoke\",156,0,\"i64.load\",[]],[\"invoke\",157,0,\"f64.load\",[]],[\"file\",\"load.wast\"],[\"module\",3,36],[\"invoke\",161,0,\"as-br-value\",[]],[\"invoke\",163,0,\"as-br_if-cond\",[]],[\"invoke\",164,0,\"as-br_if-value\",[]],[\"invoke\",165,0,\"as-br_if-value-cond\",[]],[\"invoke\",167,0,\"as-br_table-index\",[]],[\"invoke\",168,0,\"as-br_table-value\",[]],[\"invoke\",169,0,\"as-br_table-value-index\",[]],[\"invoke\",171,0,\"as-return-value\",[]],[\"invoke\",173,0,\"as-if-cond\",[]],[\"invoke\",174,0,\"as-if-then\",[]],[\"invoke\",175,0,\"as-if-else\",[]],[\"invoke\",177,0,\"as-select-first\",[\"i32:0\",\"i32:1\"]],[\"invoke\",178,0,\"as-select-second\",[\"i32:0\",\"i32:0\"]],[\"invoke\",179,0,\"as-select-cond\",[]],[\"invoke\",181,0,\"as-call-first\",[]],[\"invoke\",182,0,\"as-call-mid\",[]],[\"invoke\",183,0,\"as-call-last\",[]],[\"invoke\",185,0,\"as-call_indirect-first\",[]],[\"invoke\",186,0,\"as-call_indirect-mid\",[]],[\"invoke\",187,0,\"as-call_indirect-last\",[]],[\"invoke\",188,0,\"as-call_indirect-index\",[]],[\"invoke\",190,0,\"as-local.set-value\",[]],[\"invoke\",191,0,\"as-local.tee-value\",[]],[\"invoke\",192,0,\"as-global.set-value\",[]],[\"invoke\",194,0,\"as-load-address\",[]],[\"invoke\",195,0,\"as-loadN-address\",[]],[\"invoke\",196,0,\"as-store-address\",[]],[\"invoke\",197,0,\"as-store-value\",[]],[\"invoke\",198,0,\"as-storeN-address\",[]],[\"invoke\",199,0,\"as-storeN-value\",[]],[\"invoke\",201,0,\"as-unary-operand\",[]],[\"invoke\",203,0,\"as-binary-left\",[]],[\"invoke\",204,0,\"as-binary-right\",[]],[\"invoke\",206,0,\"as-test-operand\",[]],[\"invoke\",208,0,\"as-compare-left\",[]],[\"invoke\",209,0,\"as-compare-right\",[]],[\"invoke\",211,0,\"as-memory.grow-size\",[]],[\"file\",\"store.wast\"],[\"module\",3,37],[\"invoke\",44,0,\"as-block-value\",[]],[\"invoke\",45,0,\"as-loop-value\",[]],[\"invoke\",47,0,\"as-br-value\",[]],[\"invoke\",48,0,\"as-br_if-value\",[]],[\"invoke\",49,0,\"as-br_if-value-cond\",[]],[\"invoke\",50,0,\"as-br_table-value\",[]],[\"invoke\",52,0,\"as-return-value\",[]],[\"invoke\",54,0,\"as-if-then\",[]],[\"invoke\",55,0,\"as-if-else\",[]],[\"file\",\"memory.wast\"],[\"module\",3,38],[\"module\",4,39],[\"module\",5,40],[\"module\",6,41],[\"module\",7,42],[\"module\",8,43],[\"module\",13,44],[\"invoke\",14,0,\"memsize\",[]],[\"module\",15,44],[\"invoke\",16,0,\"memsize\",[]],[\"module\",17,45],[\"invoke\",18,0,\"memsize\",[]],[\"module\",92,46],[\"invoke\",180,0,\"data\",[]],[\"invoke\",181,0,\"cast\",[]],[\"invoke\",183,0,\"i32_load8_s\",[\"i32:4294967295\"]],[\"invoke\",184,0,\"i32_load8_u\",[\"i32:4294967295\"]],[\"invoke\",185,0,\"i32_load16_s\",[\"i32:4294967295\"]],[\"invoke\",186,0,\"i32_load16_u\",[\"i32:4294967295\"]],[\"invoke\",188,0,\"i32_load8_s\",[\"i32:100\"]],[\"invoke\",189,0,\"i32_load8_u\",[\"i32:200\"]],[\"invoke\",190,0,\"i32_load16_s\",[\"i32:20000\"]],[\"invoke\",191,0,\"i32_load16_u\",[\"i32:40000\"]],[\"invoke\",193,0,\"i32_load8_s\",[\"i32:4275856707\"]],[\"invoke\",194,0,\"i32_load8_s\",[\"i32:878104047\"]],[\"invoke\",195,0,\"i32_load8_u\",[\"i32:4275856707\"]],[\"invoke\",196,0,\"i32_load8_u\",[\"i32:878104047\"]],[\"invoke\",197,0,\"i32_load16_s\",[\"i32:4275856707\"]],[\"invoke\",198,0,\"i32_load16_s\",[\"i32:878104047\"]],[\"invoke\",199,0,\"i32_load16_u\",[\"i32:4275856707\"]],[\"invoke\",200,0,\"i32_load16_u\",[\"i32:878104047\"]],[\"invoke\",202,0,\"i64_load8_s\",[\"i64:18446744073709551615\"]],[\"invoke\",203,0,\"i64_load8_u\",[\"i64:18446744073709551615\"]],[\"invoke\",204,0,\"i64_load16_s\",[\"i64:18446744073709551615\"]],[\"invoke\",205,0,\"i64_load16_u\",[\"i64:18446744073709551615\"]],[\"invoke\",206,0,\"i64_load32_s\",[\"i64:18446744073709551615\"]],[\"invoke\",207,0,\"i64_load32_u\",[\"i64:18446744073709551615\"]],[\"invoke\",209,0,\"i64_load8_s\",[\"i64:100\"]],[\"invoke\",210,0,\"i64_load8_u\",[\"i64:200\"]],[\"invoke\",211,0,\"i64_load16_s\",[\"i64:20000\"]],[\"invoke\",212,0,\"i64_load16_u\",[\"i64:40000\"]],[\"invoke\",213,0,\"i64_load32_s\",[\"i64:20000\"]],[\"invoke\",214,0,\"i64_load32_u\",[\"i64:40000\"]],[\"invoke\",216,0,\"i64_load8_s\",[\"i64:18364758543954109763\"]],[\"invoke\",217,0,\"i64_load8_s\",[\"i64:3771275841602506223\"]],[\"invoke\",218,0,\"i64_load8_u\",[\"i64:18364758543954109763\"]],[\"invoke\",219,0,\"i64_load8_u\",[\"i64:3771275841602506223\"]],[\"invoke\",220,0,\"i64_load16_s\",[\"i64:18364758543954109763\"]],[\"invoke\",221,0,\"i64_load16_s\",[\"i64:3771275841602506223\"]],[\"invoke\",222,0,\"i64_load16_u\",[\"i64:18364758543954109763\"]],[\"invoke\",223,0,\"i64_load16_u\",[\"i64:3771275841602506223\"]],[\"invoke\",224,0,\"i64_load32_s\",[\"i64:18364758543954109763\"]],[\"invoke\",225,0,\"i64_load32_s\",[\"i64:3771275841602506223\"]],[\"invoke\",226,0,\"i64_load32_u\",[\"i64:18364758543954109763\"]],[\"invoke\",227,0,\"i64_load32_u\",[\"i64:3771275841602506223\"]],[\"module\",246,47],[\"invoke\",260,0,\"load\",[\"i32:0\"]],[\"invoke\",261,0,\"load\",[\"i32:10000\"]],[\"invoke\",262,0,\"load\",[\"i32:20000\"]],[\"invoke\",263,0,\"load\",[\"i32:30000\"]],[\"invoke\",264,0,\"load\",[\"i32:40000\"]],[\"invoke\",265,0,\"load\",[\"i32:50000\"]],[\"invoke\",266,0,\"load\",[\"i32:60000\"]],[\"invoke\",267,0,\"load\",[\"i32:65535\"]],[\"file\",\"memory_grow.wast\"],[\"module\",1,48],[\"invoke\",14,0,\"size\",[]],[\"invoke\",15,0,\"store_at_zero\",[]],[\"invoke\",16,0,\"load_at_zero\",[]],[\"invoke\",17,0,\"store_at_page_size\",[]],[\"invoke\",18,0,\"load_at_page_size\",[]],[\"invoke\",19,0,\"grow\",[\"i32:1\"]],[\"invoke\",20,0,\"size\",[]],[\"invoke\",21,0,\"load_at_zero\",[]],[\"invoke\",22,0,\"store_at_zero\",[]],[\"invoke\",23,0,\"load_at_zero\",[]],[\"invoke\",24,0,\"store_at_page_size\",[]],[\"invoke\",25,0,\"load_at_page_size\",[]],[\"invoke\",26,0,\"grow\",[\"i32:4\"]],[\"invoke\",27,0,\"size\",[]],[\"invoke\",28,0,\"load_at_zero\",[]],[\"invoke\",29,0,\"store_at_zero\",[]],[\"invoke\",30,0,\"load_at_zero\",[]],[\"invoke\",31,0,\"load_at_page_size\",[]],[\"invoke\",32,0,\"store_at_page_size\",[]],[\"invoke\",33,0,\"load_at_page_size\",[]],[\"module\",36,49],[\"invoke\",41,0,\"grow\",[\"i32:0\"]],[\"invoke\",42,0,\"grow\",[\"i32:1\"]],[\"invoke\",43,0,\"grow\",[\"i32:0\"]],[\"invoke\",44,0,\"grow\",[\"i32:2\"]],[\"invoke\",45,0,\"grow\",[\"i32:800\"]],[\"invoke\",46,0,\"grow\",[\"i32:65536\"]],[\"invoke\",47,0,\"grow\",[\"i32:64736\"]],[\"invoke\",48,0,\"grow\",[\"i32:1\"]],[\"module\",50,50],[\"invoke\",55,0,\"grow\",[\"i32:0\"]],[\"invoke\",56,0,\"grow\",[\"i32:1\"]],[\"invoke\",57,0,\"grow\",[\"i32:1\"]],[\"invoke\",58,0,\"grow\",[\"i32:2\"]],[\"invoke\",59,0,\"grow\",[\"i32:6\"]],[\"invoke\",60,0,\"grow\",[\"i32:0\"]],[\"invoke\",61,0,\"grow\",[\"i32:1\"]],[\"invoke\",62,0,\"grow\",[\"i32:65536\"]],[\"module\",66,51],[\"invoke\",87,0,\"check-memory-zero\",[\"i32:0\",\"i32:65535\"]],[\"invoke\",88,0,\"grow\",[\"i32:1\"]],[\"invoke\",89,0,\"check-memory-zero\",[\"i32:65536\",\"i32:131071\"]],[\"invoke\",90,0,\"grow\",[\"i32:1\"]],[\"invoke\",91,0,\"check-memory-zero\",[\"i32:131072\",\"i32:196607\"]],[\"invoke\",92,0,\"grow\",[\"i32:1\"]],[\"invoke\",93,0,\"check-memory-zero\",[\"i32:196608\",\"i32:262143\"]],[\"invoke\",94,0,\"grow\",[\"i32:1\"]],[\"invoke\",95,0,\"check-memory-zero\",[\"i32:262144\",\"i32:327679\"]],[\"invoke\",96,0,\"grow\",[\"i32:1\"]],[\"invoke\",97,0,\"check-memory-zero\",[\"i32:327680\",\"i32:393215\"]],[\"module\",101,52],[\"invoke\",259,0,\"as-br-value\",[]],[\"invoke\",261,0,\"as-br_if-cond\",[]],[\"invoke\",262,0,\"as-br_if-value\",[]],[\"invoke\",263,0,\"as-br_if-value-cond\",[]],[\"invoke\",265,0,\"as-br_table-index\",[]],[\"invoke\",266,0,\"as-br_table-value\",[]],[\"invoke\",267,0,\"as-br_table-value-index\",[]],[\"invoke\",269,0,\"as-return-value\",[]],[\"invoke\",271,0,\"as-if-cond\",[]],[\"invoke\",272,0,\"as-if-then\",[]],[\"invoke\",273,0,\"as-if-else\",[]],[\"invoke\",275,0,\"as-select-first\",[\"i32:0\",\"i32:1\"]],[\"invoke\",276,0,\"as-select-second\",[\"i32:0\",\"i32:0\"]],[\"invoke\",277,0,\"as-select-cond\",[]],[\"invoke\",279,0,\"as-call-first\",[]],[\"invoke\",280,0,\"as-call-mid\",[]],[\"invoke\",281,0,\"as-call-last\",[]],[\"invoke\",283,0,\"as-call_indirect-first\",[]],[\"invoke\",284,0,\"as-call_indirect-mid\",[]],[\"invoke\",285,0,\"as-call_indirect-last\",[]],[\"invoke\",286,0,\"as-call_indirect-index\",[]],[\"invoke\",288,0,\"as-local.set-value\",[]],[\"invoke\",289,0,\"as-local.tee-value\",[]],[\"invoke\",290,0,\"as-global.set-value\",[]],[\"invoke\",292,0,\"as-load-address\",[]],[\"invoke\",293,0,\"as-loadN-address\",[]],[\"invoke\",294,0,\"as-store-address\",[]],[\"invoke\",295,0,\"as-store-value\",[]],[\"invoke\",296,0,\"as-storeN-address\",[]],[\"invoke\",297,0,\"as-storeN-value\",[]],[\"invoke\",299,0,\"as-unary-operand\",[]],[\"invoke\",301,0,\"as-binary-left\",[]],[\"invoke\",302,0,\"as-binary-right\",[]],[\"invoke\",304,0,\"as-test-operand\",[]],[\"invoke\",306,0,\"as-compare-left\",[]],[\"invoke\",307,0,\"as-compare-right\",[]],[\"invoke\",309,0,\"as-memory.grow-size\",[]],[\"module\",312,53,\"$Mgm\"],[\"register\",\"grown-memory\",\"$Mgm\"],[\"invoke\",317,\"$Mgm\",\"grow\",[]],[\"module\",318,54,\"$Mgim1\"],[\"register\",\"grown-imported-memory\",\"$Mgim1\"],[\"invoke\",324,\"$Mgim1\",\"grow\",[]],[\"module\",325,55,\"$Mgim2\"],[\"invoke\",330,\"$Mgim2\",\"size\",[]],[\"file\",\"memory_redundancy.wast\"],[\"module\",5,56],[\"invoke\",59,0,\"test_store_to_load\",[]],[\"invoke\",60,0,\"zero_everything\",[]],[\"invoke\",61,0,\"test_redundant_load\",[]],[\"invoke\",62,0,\"zero_everything\",[]],[\"invoke\",63,0,\"test_dead_store\",[]],[\"invoke\",64,0,\"zero_everything\",[]],[\"invoke\",65,0,\"malloc_aliasing\",[]],[\"file\",\"memory_size.wast\"],[\"module\",1,57],[\"invoke\",7,0,\"size\",[]],[\"invoke\",8,0,\"grow\",[\"i32:1\"]],[\"invoke\",9,0,\"size\",[]],[\"invoke\",10,0,\"grow\",[\"i32:4\"]],[\"invoke\",11,0,\"size\",[]],[\"invoke\",12,0,\"grow\",[\"i32:0\"]],[\"invoke\",13,0,\"size\",[]],[\"module\",15,58],[\"invoke\",21,0,\"size\",[]],[\"invoke\",22,0,\"grow\",[\"i32:1\"]],[\"invoke\",23,0,\"size\",[]],[\"invoke\",24,0,\"grow\",[\"i32:4\"]],[\"invoke\",25,0,\"size\",[]],[\"invoke\",26,0,\"grow\",[\"i32:0\"]],[\"invoke\",27,0,\"size\",[]],[\"module\",29,59],[\"invoke\",35,0,\"size\",[]],[\"invoke\",36,0,\"grow\",[\"i32:3\"]],[\"invoke\",37,0,\"size\",[]],[\"invoke\",38,0,\"grow\",[\"i32:1\"]],[\"invoke\",39,0,\"size\",[]],[\"invoke\",40,0,\"grow\",[\"i32:0\"]],[\"invoke\",41,0,\"size\",[]],[\"invoke\",42,0,\"grow\",[\"i32:4\"]],[\"invoke\",43,0,\"size\",[]],[\"invoke\",44,0,\"grow\",[\"i32:1\"]],[\"invoke\",45,0,\"size\",[]],[\"module\",47,60],[\"invoke\",53,0,\"size\",[]],[\"invoke\",54,0,\"grow\",[\"i32:1\"]],[\"invoke\",55,0,\"size\",[]],[\"invoke\",56,0,\"grow\",[\"i32:3\"]],[\"invoke\",57,0,\"size\",[]],[\"invoke\",58,0,\"grow\",[\"i32:0\"]],[\"invoke\",59,0,\"size\",[]],[\"invoke\",60,0,\"grow\",[\"i32:2\"]],[\"invoke\",61,0,\"size\",[]],[\"invoke\",62,0,\"grow\",[\"i32:1\"]],[\"invoke\",63,0,\"size\",[]],[\"file\",\"memory_trap.wast\"],[\"module\",1,61],[\"invoke\",21,0,\"store\",[\"i32:4294967292\",\"i32:42\"]],[\"invoke\",22,0,\"load\",[\"i32:4294967292\"]],[\"invoke\",23,0,\"store\",[\"i32:4294967293\",\"i32:305419896\"]],[\"invoke\",24,0,\"load\",[\"i32:4294967293\"]],[\"invoke\",25,0,\"store\",[\"i32:4294967294\",\"i32:13\"]],[\"invoke\",26,0,\"load\",[\"i32:4294967294\"]],[\"invoke\",27,0,\"store\",[\"i32:4294967295\",\"i32:13\"]],[\"invoke\",28,0,\"load\",[\"i32:4294967295\"]],[\"invoke\",29,0,\"store\",[\"i32:0\",\"i32:13\"]],[\"invoke\",30,0,\"load\",[\"i32:0\"]],[\"invoke\",31,0,\"store\",[\"i32:2147483648\",\"i32:13\"]],[\"invoke\",32,0,\"load\",[\"i32:2147483648\"]],[\"invoke\",33,0,\"memory.grow\",[\"i32:65537\"]],[\"module\",35,62],[\"invoke\",111,0,\"i32.store\",[\"i32:65536\",\"i32:0\"]],[\"invoke\",112,0,\"i32.store\",[\"i32:65535\",\"i32:0\"]],[\"invoke\",113,0,\"i32.store\",[\"i32:65534\",\"i32:0\"]],[\"invoke\",114,0,\"i32.store\",[\"i32:65533\",\"i32:0\"]],[\"invoke\",115,0,\"i32.store\",[\"i32:4294967295\",\"i32:0\"]],[\"invoke\",116,0,\"i32.store\",[\"i32:4294967294\",\"i32:0\"]],[\"invoke\",117,0,\"i32.store\",[\"i32:4294967293\",\"i32:0\"]],[\"invoke\",118,0,\"i32.store\",[\"i32:4294967292\",\"i32:0\"]],[\"invoke\",119,0,\"i64.store\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",120,0,\"i64.store\",[\"i32:65535\",\"i64:0\"]],[\"invoke\",121,0,\"i64.store\",[\"i32:65534\",\"i64:0\"]],[\"invoke\",122,0,\"i64.store\",[\"i32:65533\",\"i64:0\"]],[\"invoke\",123,0,\"i64.store\",[\"i32:65532\",\"i64:0\"]],[\"invoke\",124,0,\"i64.store\",[\"i32:65531\",\"i64:0\"]],[\"invoke\",125,0,\"i64.store\",[\"i32:65530\",\"i64:0\"]],[\"invoke\",126,0,\"i64.store\",[\"i32:65529\",\"i64:0\"]],[\"invoke\",127,0,\"i64.store\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",128,0,\"i64.store\",[\"i32:4294967294\",\"i64:0\"]],[\"invoke\",129,0,\"i64.store\",[\"i32:4294967293\",\"i64:0\"]],[\"invoke\",130,0,\"i64.store\",[\"i32:4294967292\",\"i64:0\"]],[\"invoke\",131,0,\"i64.store\",[\"i32:4294967291\",\"i64:0\"]],[\"invoke\",132,0,\"i64.store\",[\"i32:4294967290\",\"i64:0\"]],[\"invoke\",133,0,\"i64.store\",[\"i32:4294967289\",\"i64:0\"]],[\"invoke\",134,0,\"i64.store\",[\"i32:4294967288\",\"i64:0\"]],[\"invoke\",135,0,\"f32.store\",[\"i32:65536\",\"f32:0\"]],[\"invoke\",136,0,\"f32.store\",[\"i32:65535\",\"f32:0\"]],[\"invoke\",137,0,\"f32.store\",[\"i32:65534\",\"f32:0\"]],[\"invoke\",138,0,\"f32.store\",[\"i32:65533\",\"f32:0\"]],[\"invoke\",139,0,\"f32.store\",[\"i32:4294967295\",\"f32:0\"]],[\"invoke\",140,0,\"f32.store\",[\"i32:4294967294\",\"f32:0\"]],[\"invoke\",141,0,\"f32.store\",[\"i32:4294967293\",\"f32:0\"]],[\"invoke\",142,0,\"f32.store\",[\"i32:4294967292\",\"f32:0\"]],[\"invoke\",143,0,\"f64.store\",[\"i32:65536\",\"f64:0\"]],[\"invoke\",144,0,\"f64.store\",[\"i32:65535\",\"f64:0\"]],[\"invoke\",145,0,\"f64.store\",[\"i32:65534\",\"f64:0\"]],[\"invoke\",146,0,\"f64.store\",[\"i32:65533\",\"f64:0\"]],[\"invoke\",147,0,\"f64.store\",[\"i32:65532\",\"f64:0\"]],[\"invoke\",148,0,\"f64.store\",[\"i32:65531\",\"f64:0\"]],[\"invoke\",149,0,\"f64.store\",[\"i32:65530\",\"f64:0\"]],[\"invoke\",150,0,\"f64.store\",[\"i32:65529\",\"f64:0\"]],[\"invoke\",151,0,\"f64.store\",[\"i32:4294967295\",\"f64:0\"]],[\"invoke\",152,0,\"f64.store\",[\"i32:4294967294\",\"f64:0\"]],[\"invoke\",153,0,\"f64.store\",[\"i32:4294967293\",\"f64:0\"]],[\"invoke\",154,0,\"f64.store\",[\"i32:4294967292\",\"f64:0\"]],[\"invoke\",155,0,\"f64.store\",[\"i32:4294967291\",\"f64:0\"]],[\"invoke\",156,0,\"f64.store\",[\"i32:4294967290\",\"f64:0\"]],[\"invoke\",157,0,\"f64.store\",[\"i32:4294967289\",\"f64:0\"]],[\"invoke\",158,0,\"f64.store\",[\"i32:4294967288\",\"f64:0\"]],[\"invoke\",159,0,\"i32.store8\",[\"i32:65536\",\"i32:0\"]],[\"invoke\",160,0,\"i32.store8\",[\"i32:4294967295\",\"i32:0\"]],[\"invoke\",161,0,\"i32.store16\",[\"i32:65536\",\"i32:0\"]],[\"invoke\",162,0,\"i32.store16\",[\"i32:65535\",\"i32:0\"]],[\"invoke\",163,0,\"i32.store16\",[\"i32:4294967295\",\"i32:0\"]],[\"invoke\",164,0,\"i32.store16\",[\"i32:4294967294\",\"i32:0\"]],[\"invoke\",165,0,\"i64.store8\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",166,0,\"i64.store8\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",167,0,\"i64.store16\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",168,0,\"i64.store16\",[\"i32:65535\",\"i64:0\"]],[\"invoke\",169,0,\"i64.store16\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",170,0,\"i64.store16\",[\"i32:4294967294\",\"i64:0\"]],[\"invoke\",171,0,\"i64.store32\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",172,0,\"i64.store32\",[\"i32:65535\",\"i64:0\"]],[\"invoke\",173,0,\"i64.store32\",[\"i32:65534\",\"i64:0\"]],[\"invoke\",174,0,\"i64.store32\",[\"i32:65533\",\"i64:0\"]],[\"invoke\",175,0,\"i64.store32\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",176,0,\"i64.store32\",[\"i32:4294967294\",\"i64:0\"]],[\"invoke\",177,0,\"i64.store32\",[\"i32:4294967293\",\"i64:0\"]],[\"invoke\",178,0,\"i64.store32\",[\"i32:4294967292\",\"i64:0\"]],[\"invoke\",179,0,\"i32.load\",[\"i32:65536\"]],[\"invoke\",180,0,\"i32.load\",[\"i32:65535\"]],[\"invoke\",181,0,\"i32.load\",[\"i32:65534\"]],[\"invoke\",182,0,\"i32.load\",[\"i32:65533\"]],[\"invoke\",183,0,\"i32.load\",[\"i32:4294967295\"]],[\"invoke\",184,0,\"i32.load\",[\"i32:4294967294\"]],[\"invoke\",185,0,\"i32.load\",[\"i32:4294967293\"]],[\"invoke\",186,0,\"i32.load\",[\"i32:4294967292\"]],[\"invoke\",187,0,\"i64.load\",[\"i32:65536\"]],[\"invoke\",188,0,\"i64.load\",[\"i32:65535\"]],[\"invoke\",189,0,\"i64.load\",[\"i32:65534\"]],[\"invoke\",190,0,\"i64.load\",[\"i32:65533\"]],[\"invoke\",191,0,\"i64.load\",[\"i32:65532\"]],[\"invoke\",192,0,\"i64.load\",[\"i32:65531\"]],[\"invoke\",193,0,\"i64.load\",[\"i32:65530\"]],[\"invoke\",194,0,\"i64.load\",[\"i32:65529\"]],[\"invoke\",195,0,\"i64.load\",[\"i32:4294967295\"]],[\"invoke\",196,0,\"i64.load\",[\"i32:4294967294\"]],[\"invoke\",197,0,\"i64.load\",[\"i32:4294967293\"]],[\"invoke\",198,0,\"i64.load\",[\"i32:4294967292\"]],[\"invoke\",199,0,\"i64.load\",[\"i32:4294967291\"]],[\"invoke\",200,0,\"i64.load\",[\"i32:4294967290\"]],[\"invoke\",201,0,\"i64.load\",[\"i32:4294967289\"]],[\"invoke\",202,0,\"i64.load\",[\"i32:4294967288\"]],[\"invoke\",203,0,\"f32.load\",[\"i32:65536\"]],[\"invoke\",204,0,\"f32.load\",[\"i32:65535\"]],[\"invoke\",205,0,\"f32.load\",[\"i32:65534\"]],[\"invoke\",206,0,\"f32.load\",[\"i32:65533\"]],[\"invoke\",207,0,\"f32.load\",[\"i32:4294967295\"]],[\"invoke\",208,0,\"f32.load\",[\"i32:4294967294\"]],[\"invoke\",209,0,\"f32.load\",[\"i32:4294967293\"]],[\"invoke\",210,0,\"f32.load\",[\"i32:4294967292\"]],[\"invoke\",211,0,\"f64.load\",[\"i32:65536\"]],[\"invoke\",212,0,\"f64.load\",[\"i32:65535\"]],[\"invoke\",213,0,\"f64.load\",[\"i32:65534\"]],[\"invoke\",214,0,\"f64.load\",[\"i32:65533\"]],[\"invoke\",215,0,\"f64.load\",[\"i32:65532\"]],[\"invoke\",216,0,\"f64.load\",[\"i32:65531\"]],[\"invoke\",217,0,\"f64.load\",[\"i32:65530\"]],[\"invoke\",218,0,\"f64.load\",[\"i32:65529\"]],[\"invoke\",219,0,\"f64.load\",[\"i32:4294967295\"]],[\"invoke\",220,0,\"f64.load\",[\"i32:4294967294\"]],[\"invoke\",221,0,\"f64.load\",[\"i32:4294967293\"]],[\"invoke\",222,0,\"f64.load\",[\"i32:4294967292\"]],[\"invoke\",223,0,\"f64.load\",[\"i32:4294967291\"]],[\"invoke\",224,0,\"f64.load\",[\"i32:4294967290\"]],[\"invoke\",225,0,\"f64.load\",[\"i32:4294967289\"]],[\"invoke\",226,0,\"f64.load\",[\"i32:4294967288\"]],[\"invoke\",227,0,\"i32.load8_s\",[\"i32:65536\"]],[\"invoke\",228,0,\"i32.load8_s\",[\"i32:4294967295\"]],[\"invoke\",229,0,\"i32.load8_u\",[\"i32:65536\"]],[\"invoke\",230,0,\"i32.load8_u\",[\"i32:4294967295\"]],[\"invoke\",231,0,\"i32.load16_s\",[\"i32:65536\"]],[\"invoke\",232,0,\"i32.load16_s\",[\"i32:65535\"]],[\"invoke\",233,0,\"i32.load16_s\",[\"i32:4294967295\"]],[\"invoke\",234,0,\"i32.load16_s\",[\"i32:4294967294\"]],[\"invoke\",235,0,\"i32.load16_u\",[\"i32:65536\"]],[\"invoke\",236,0,\"i32.load16_u\",[\"i32:65535\"]],[\"invoke\",237,0,\"i32.load16_u\",[\"i32:4294967295\"]],[\"invoke\",238,0,\"i32.load16_u\",[\"i32:4294967294\"]],[\"invoke\",239,0,\"i64.load8_s\",[\"i32:65536\"]],[\"invoke\",240,0,\"i64.load8_s\",[\"i32:4294967295\"]],[\"invoke\",241,0,\"i64.load8_u\",[\"i32:65536\"]],[\"invoke\",242,0,\"i64.load8_u\",[\"i32:4294967295\"]],[\"invoke\",243,0,\"i64.load16_s\",[\"i32:65536\"]],[\"invoke\",244,0,\"i64.load16_s\",[\"i32:65535\"]],[\"invoke\",245,0,\"i64.load16_s\",[\"i32:4294967295\"]],[\"invoke\",246,0,\"i64.load16_s\",[\"i32:4294967294\"]],[\"invoke\",247,0,\"i64.load16_u\",[\"i32:65536\"]],[\"invoke\",248,0,\"i64.load16_u\",[\"i32:65535\"]],[\"invoke\",249,0,\"i64.load16_u\",[\"i32:4294967295\"]],[\"invoke\",250,0,\"i64.load16_u\",[\"i32:4294967294\"]],[\"invoke\",251,0,\"i64.load32_s\",[\"i32:65536\"]],[\"invoke\",252,0,\"i64.load32_s\",[\"i32:65535\"]],[\"invoke\",253,0,\"i64.load32_s\",[\"i32:65534\"]],[\"invoke\",254,0,\"i64.load32_s\",[\"i32:65533\"]],[\"invoke\",255,0,\"i64.load32_s\",[\"i32:4294967295\"]],[\"invoke\",256,0,\"i64.load32_s\",[\"i32:4294967294\"]],[\"invoke\",257,0,\"i64.load32_s\",[\"i32:4294967293\"]],[\"invoke\",258,0,\"i64.load32_s\",[\"i32:4294967292\"]],[\"invoke\",259,0,\"i64.load32_u\",[\"i32:65536\"]],[\"invoke\",260,0,\"i64.load32_u\",[\"i32:65535\"]],[\"invoke\",261,0,\"i64.load32_u\",[\"i32:65534\"]],[\"invoke\",262,0,\"i64.load32_u\",[\"i32:65533\"]],[\"invoke\",263,0,\"i64.load32_u\",[\"i32:4294967295\"]],[\"invoke\",264,0,\"i64.load32_u\",[\"i32:4294967294\"]],[\"invoke\",265,0,\"i64.load32_u\",[\"i32:4294967293\"]],[\"invoke\",266,0,\"i64.load32_u\",[\"i32:4294967292\"]],[\"invoke\",269,0,\"i64.load\",[\"i32:65528\"]],[\"invoke\",270,0,\"i64.load\",[\"i32:0\"]],[\"invoke\",274,0,\"i64.store\",[\"i32:65528\",\"i64:0\"]],[\"invoke\",275,0,\"i32.store\",[\"i32:65533\",\"i32:305419896\"]],[\"invoke\",276,0,\"i32.load\",[\"i32:65532\"]],[\"invoke\",277,0,\"i64.store\",[\"i32:65529\",\"i64:1311768467294899695\"]],[\"invoke\",278,0,\"i64.load\",[\"i32:65528\"]],[\"invoke\",279,0,\"f32.store\",[\"i32:65533\",\"f32:1301390004\"]],[\"invoke\",280,0,\"f32.load\",[\"i32:65532\"]],[\"invoke\",281,0,\"f64.store\",[\"i32:65529\",\"f64:4878018892390247374\"]],[\"invoke\",282,0,\"f64.load\",[\"i32:65528\"]],[\"file\",\"bulk.wast\"],[\"module\",2,63],[\"module\",6,64],[\"module\",13,65],[\"invoke\",27,0,\"fill\",[\"i32:1\",\"i32:255\",\"i32:3\"]],[\"invoke\",28,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",29,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",30,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",31,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",32,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",35,0,\"fill\",[\"i32:0\",\"i32:48042\",\"i32:2\"]],[\"invoke\",36,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",37,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",40,0,\"fill\",[\"i32:0\",\"i32:0\",\"i32:65536\"]],[\"invoke\",43,0,\"fill\",[\"i32:65280\",\"i32:1\",\"i32:257\"]],[\"invoke\",45,0,\"load8_u\",[\"i32:65280\"]],[\"invoke\",46,0,\"load8_u\",[\"i32:65535\"]],[\"invoke\",49,0,\"fill\",[\"i32:65536\",\"i32:0\",\"i32:0\"]],[\"invoke\",52,0,\"fill\",[\"i32:65537\",\"i32:0\",\"i32:0\"]],[\"module\",57,66],[\"invoke\",71,0,\"copy\",[\"i32:10\",\"i32:0\",\"i32:4\"]],[\"invoke\",73,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",74,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",75,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",76,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",77,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",78,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",81,0,\"copy\",[\"i32:8\",\"i32:10\",\"i32:4\"]],[\"invoke\",82,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",83,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",84,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",85,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",86,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",87,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",90,0,\"copy\",[\"i32:10\",\"i32:7\",\"i32:6\"]],[\"invoke\",91,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",92,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",93,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",94,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",95,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",96,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",97,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",100,0,\"copy\",[\"i32:65280\",\"i32:0\",\"i32:256\"]],[\"invoke\",101,0,\"copy\",[\"i32:65024\",\"i32:65280\",\"i32:256\"]],[\"invoke\",104,0,\"copy\",[\"i32:65536\",\"i32:0\",\"i32:0\"]],[\"invoke\",105,0,\"copy\",[\"i32:0\",\"i32:65536\",\"i32:0\"]],[\"invoke\",108,0,\"copy\",[\"i32:65537\",\"i32:0\",\"i32:0\"]],[\"invoke\",110,0,\"copy\",[\"i32:0\",\"i32:65537\",\"i32:0\"]],[\"module\",115,67],[\"invoke\",129,0,\"init\",[\"i32:0\",\"i32:1\",\"i32:2\"]],[\"invoke\",130,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",131,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",132,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",135,0,\"init\",[\"i32:65532\",\"i32:0\",\"i32:4\"]],[\"invoke\",138,0,\"init\",[\"i32:65534\",\"i32:0\",\"i32:3\"]],[\"invoke\",140,0,\"load8_u\",[\"i32:65534\"]],[\"invoke\",141,0,\"load8_u\",[\"i32:65535\"]],[\"invoke\",144,0,\"init\",[\"i32:65536\",\"i32:0\",\"i32:0\"]],[\"invoke\",145,0,\"init\",[\"i32:0\",\"i32:4\",\"i32:0\"]],[\"invoke\",148,0,\"init\",[\"i32:65537\",\"i32:0\",\"i32:0\"]],[\"invoke\",150,0,\"init\",[\"i32:0\",\"i32:5\",\"i32:0\"]],[\"module\",154,68],[\"invoke\",168,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",169,0,\"drop_passive\",[]],[\"invoke\",170,0,\"drop_passive\",[]],[\"invoke\",171,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",172,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",173,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",174,0,\"drop_active\",[]],[\"invoke\",175,0,\"init_active\",[\"i32:0\"]],[\"invoke\",176,0,\"init_active\",[\"i32:1\"]],[\"invoke\",177,0,\"init_active\",[\"i32:0\"]],[\"module\",181,69],[\"module\",196,70],[\"module\",199,71],[\"invoke\",219,0,\"init\",[\"i32:2\",\"i32:0\",\"i32:2\"]],[\"invoke\",221,0,\"call\",[\"i32:2\"]],[\"invoke\",224,0,\"init\",[\"i32:0\",\"i32:1\",\"i32:2\"]],[\"invoke\",225,0,\"call\",[\"i32:0\"]],[\"invoke\",226,0,\"call\",[\"i32:1\"]],[\"invoke\",227,0,\"call\",[\"i32:2\"]],[\"invoke\",230,0,\"init\",[\"i32:1\",\"i32:2\",\"i32:2\"]],[\"invoke\",233,0,\"init\",[\"i32:3\",\"i32:0\",\"i32:0\"]],[\"invoke\",234,0,\"init\",[\"i32:0\",\"i32:4\",\"i32:0\"]],[\"invoke\",237,0,\"init\",[\"i32:4\",\"i32:0\",\"i32:0\"]],[\"invoke\",239,0,\"init\",[\"i32:0\",\"i32:5\",\"i32:0\"]],[\"module\",244,72],[\"invoke\",261,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",262,0,\"drop_passive\",[]],[\"invoke\",263,0,\"drop_passive\",[]],[\"invoke\",264,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",265,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",266,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",267,0,\"drop_active\",[]],[\"invoke\",268,0,\"init_active\",[\"i32:0\"]],[\"invoke\",269,0,\"init_active\",[\"i32:1\"]],[\"invoke\",270,0,\"init_active\",[\"i32:0\"]],[\"module\",274,73],[\"module\",297,74],[\"module\",300,75],[\"invoke\",319,0,\"copy\",[\"i32:3\",\"i32:0\",\"i32:3\"]],[\"invoke\",321,0,\"call\",[\"i32:3\"]],[\"invoke\",322,0,\"call\",[\"i32:4\"]],[\"invoke\",323,0,\"call\",[\"i32:5\"]],[\"invoke\",326,0,\"copy\",[\"i32:0\",\"i32:1\",\"i32:3\"]],[\"invoke\",328,0,\"call\",[\"i32:0\"]],[\"invoke\",329,0,\"call\",[\"i32:1\"]],[\"invoke\",330,0,\"call\",[\"i32:2\"]],[\"invoke\",333,0,\"copy\",[\"i32:2\",\"i32:0\",\"i32:3\"]],[\"invoke\",335,0,\"call\",[\"i32:2\"]],[\"invoke\",336,0,\"call\",[\"i32:3\"]],[\"invoke\",337,0,\"call\",[\"i32:4\"]],[\"invoke\",340,0,\"copy\",[\"i32:6\",\"i32:8\",\"i32:2\"]],[\"invoke\",341,0,\"copy\",[\"i32:8\",\"i32:6\",\"i32:2\"]],[\"invoke\",344,0,\"copy\",[\"i32:10\",\"i32:0\",\"i32:0\"]],[\"invoke\",345,0,\"copy\",[\"i32:0\",\"i32:10\",\"i32:0\"]],[\"invoke\",348,0,\"copy\",[\"i32:11\",\"i32:0\",\"i32:0\"]],[\"invoke\",350,0,\"copy\",[\"i32:0\",\"i32:11\",\"i32:0\"]],[\"file\",\"memory_copy.wast\"],[\"module\",6,76],[\"invoke\",15,0,\"test\",[]],[\"invoke\",27,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",38,0,\"load8_u\",[\"i32:21\"]],[\"module\",48,77],[\"invoke\",60,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",71,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",82,0,\"load8_u\",[\"i32:23\"]],[\"module\",90,78],[\"invoke\",104,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",115,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",126,0,\"load8_u\",[\"i32:25\"]],[\"module\",132,79],[\"invoke\",147,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",158,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",169,0,\"load8_u\",[\"i32:26\"]],[\"module\",174,80],[\"invoke\",191,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",202,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",213,0,\"load8_u\",[\"i32:28\"]],[\"module\",216,81],[\"invoke\",235,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",246,0,\"load8_u\",[\"i32:19\"]],[\"module\",258,82],[\"invoke\",267,0,\"test\",[]],[\"invoke\",278,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",289,0,\"load8_u\",[\"i32:20\"]],[\"module\",300,83],[\"invoke\",311,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",322,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",333,0,\"load8_u\",[\"i32:22\"]],[\"module\",342,84],[\"invoke\",355,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",366,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",377,0,\"load8_u\",[\"i32:1014\"]],[\"invoke\",387,0,\"load8_u\",[\"i32:3004\"]],[\"invoke\",398,0,\"load8_u\",[\"i32:5193\"]],[\"invoke\",409,0,\"load8_u\",[\"i32:7382\"]],[\"invoke\",420,0,\"load8_u\",[\"i32:9571\"]],[\"invoke\",431,0,\"load8_u\",[\"i32:11760\"]],[\"invoke\",442,0,\"load8_u\",[\"i32:13949\"]],[\"invoke\",453,0,\"load8_u\",[\"i32:16138\"]],[\"invoke\",464,0,\"load8_u\",[\"i32:18327\"]],[\"invoke\",475,0,\"load8_u\",[\"i32:20516\"]],[\"invoke\",485,0,\"load8_u\",[\"i32:22506\"]],[\"invoke\",496,0,\"load8_u\",[\"i32:24695\"]],[\"invoke\",507,0,\"load8_u\",[\"i32:26884\"]],[\"invoke\",518,0,\"load8_u\",[\"i32:29073\"]],[\"invoke\",529,0,\"load8_u\",[\"i32:31262\"]],[\"invoke\",540,0,\"load8_u\",[\"i32:33451\"]],[\"invoke\",551,0,\"load8_u\",[\"i32:35640\"]],[\"invoke\",562,0,\"load8_u\",[\"i32:37829\"]],[\"invoke\",572,0,\"load8_u\",[\"i32:39819\"]],[\"invoke\",583,0,\"load8_u\",[\"i32:42008\"]],[\"invoke\",594,0,\"load8_u\",[\"i32:44197\"]],[\"invoke\",605,0,\"load8_u\",[\"i32:46386\"]],[\"invoke\",616,0,\"load8_u\",[\"i32:48575\"]],[\"invoke\",627,0,\"load8_u\",[\"i32:50764\"]],[\"invoke\",638,0,\"load8_u\",[\"i32:52953\"]],[\"invoke\",649,0,\"load8_u\",[\"i32:55142\"]],[\"invoke\",660,0,\"load8_u\",[\"i32:57331\"]],[\"invoke\",670,0,\"load8_u\",[\"i32:59321\"]],[\"invoke\",681,0,\"load8_u\",[\"i32:61510\"]],[\"invoke\",692,0,\"load8_u\",[\"i32:63699\"]],[\"module\",703,85],[\"invoke\",714,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",725,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",736,0,\"load8_u\",[\"i32:418\"]],[\"invoke\",747,0,\"load8_u\",[\"i32:2607\"]],[\"invoke\",758,0,\"load8_u\",[\"i32:4796\"]],[\"invoke\",768,0,\"load8_u\",[\"i32:6786\"]],[\"invoke\",779,0,\"load8_u\",[\"i32:8975\"]],[\"invoke\",790,0,\"load8_u\",[\"i32:11164\"]],[\"invoke\",801,0,\"load8_u\",[\"i32:13353\"]],[\"invoke\",812,0,\"load8_u\",[\"i32:15542\"]],[\"invoke\",823,0,\"load8_u\",[\"i32:17731\"]],[\"invoke\",834,0,\"load8_u\",[\"i32:19920\"]],[\"invoke\",845,0,\"load8_u\",[\"i32:22109\"]],[\"invoke\",856,0,\"load8_u\",[\"i32:24298\"]],[\"invoke\",866,0,\"load8_u\",[\"i32:26288\"]],[\"invoke\",877,0,\"load8_u\",[\"i32:28477\"]],[\"invoke\",888,0,\"load8_u\",[\"i32:30666\"]],[\"invoke\",899,0,\"load8_u\",[\"i32:32855\"]],[\"invoke\",910,0,\"load8_u\",[\"i32:35044\"]],[\"invoke\",921,0,\"load8_u\",[\"i32:37233\"]],[\"invoke\",932,0,\"load8_u\",[\"i32:39422\"]],[\"invoke\",943,0,\"load8_u\",[\"i32:41611\"]],[\"invoke\",953,0,\"load8_u\",[\"i32:43601\"]],[\"invoke\",964,0,\"load8_u\",[\"i32:45790\"]],[\"invoke\",975,0,\"load8_u\",[\"i32:47979\"]],[\"invoke\",986,0,\"load8_u\",[\"i32:50168\"]],[\"invoke\",997,0,\"load8_u\",[\"i32:52357\"]],[\"invoke\",1008,0,\"load8_u\",[\"i32:54546\"]],[\"invoke\",1019,0,\"load8_u\",[\"i32:56735\"]],[\"invoke\",1030,0,\"load8_u\",[\"i32:58924\"]],[\"invoke\",1041,0,\"load8_u\",[\"i32:61113\"]],[\"invoke\",1051,0,\"load8_u\",[\"i32:63103\"]],[\"invoke\",1062,0,\"load8_u\",[\"i32:65292\"]],[\"module\",1065,86],[\"invoke\",1084,0,\"load8_u\",[\"i32:1790\"]],[\"invoke\",1095,0,\"load8_u\",[\"i32:3979\"]],[\"invoke\",1106,0,\"load8_u\",[\"i32:6168\"]],[\"invoke\",1117,0,\"load8_u\",[\"i32:8357\"]],[\"invoke\",1128,0,\"load8_u\",[\"i32:10546\"]],[\"invoke\",1139,0,\"load8_u\",[\"i32:12735\"]],[\"invoke\",1149,0,\"load8_u\",[\"i32:14725\"]],[\"invoke\",1160,0,\"load8_u\",[\"i32:16914\"]],[\"invoke\",1171,0,\"load8_u\",[\"i32:19103\"]],[\"invoke\",1182,0,\"load8_u\",[\"i32:21292\"]],[\"invoke\",1193,0,\"load8_u\",[\"i32:23481\"]],[\"invoke\",1204,0,\"load8_u\",[\"i32:25670\"]],[\"invoke\",1215,0,\"load8_u\",[\"i32:27859\"]],[\"invoke\",1226,0,\"load8_u\",[\"i32:30048\"]],[\"invoke\",1237,0,\"load8_u\",[\"i32:32237\"]],[\"invoke\",1247,0,\"load8_u\",[\"i32:34227\"]],[\"invoke\",1258,0,\"load8_u\",[\"i32:36416\"]],[\"invoke\",1269,0,\"load8_u\",[\"i32:38605\"]],[\"invoke\",1280,0,\"load8_u\",[\"i32:40794\"]],[\"invoke\",1291,0,\"load8_u\",[\"i32:42983\"]],[\"invoke\",1302,0,\"load8_u\",[\"i32:45172\"]],[\"invoke\",1313,0,\"load8_u\",[\"i32:47361\"]],[\"invoke\",1324,0,\"load8_u\",[\"i32:49550\"]],[\"invoke\",1334,0,\"load8_u\",[\"i32:51540\"]],[\"invoke\",1345,0,\"load8_u\",[\"i32:53729\"]],[\"invoke\",1356,0,\"load8_u\",[\"i32:55918\"]],[\"invoke\",1367,0,\"load8_u\",[\"i32:58107\"]],[\"invoke\",1378,0,\"load8_u\",[\"i32:60296\"]],[\"invoke\",1389,0,\"load8_u\",[\"i32:62485\"]],[\"invoke\",1400,0,\"load8_u\",[\"i32:64674\"]],[\"invoke\",1411,0,\"load8_u\",[\"i32:65522\"]],[\"invoke\",1422,0,\"load8_u\",[\"i32:65533\"]],[\"module\",1426,87],[\"invoke\",1443,0,\"load8_u\",[\"i32:1392\"]],[\"invoke\",1454,0,\"load8_u\",[\"i32:3581\"]],[\"invoke\",1465,0,\"load8_u\",[\"i32:5770\"]],[\"invoke\",1476,0,\"load8_u\",[\"i32:7959\"]],[\"invoke\",1487,0,\"load8_u\",[\"i32:10148\"]],[\"invoke\",1498,0,\"load8_u\",[\"i32:12337\"]],[\"invoke\",1509,0,\"load8_u\",[\"i32:14526\"]],[\"invoke\",1520,0,\"load8_u\",[\"i32:16715\"]],[\"invoke\",1530,0,\"load8_u\",[\"i32:18705\"]],[\"invoke\",1541,0,\"load8_u\",[\"i32:20894\"]],[\"invoke\",1552,0,\"load8_u\",[\"i32:23083\"]],[\"invoke\",1563,0,\"load8_u\",[\"i32:25272\"]],[\"invoke\",1574,0,\"load8_u\",[\"i32:27461\"]],[\"invoke\",1585,0,\"load8_u\",[\"i32:29650\"]],[\"invoke\",1596,0,\"load8_u\",[\"i32:31839\"]],[\"invoke\",1607,0,\"load8_u\",[\"i32:34028\"]],[\"invoke\",1618,0,\"load8_u\",[\"i32:36217\"]],[\"invoke\",1628,0,\"load8_u\",[\"i32:38207\"]],[\"invoke\",1639,0,\"load8_u\",[\"i32:40396\"]],[\"invoke\",1650,0,\"load8_u\",[\"i32:42585\"]],[\"invoke\",1661,0,\"load8_u\",[\"i32:44774\"]],[\"invoke\",1672,0,\"load8_u\",[\"i32:46963\"]],[\"invoke\",1683,0,\"load8_u\",[\"i32:49152\"]],[\"invoke\",1694,0,\"load8_u\",[\"i32:51341\"]],[\"invoke\",1705,0,\"load8_u\",[\"i32:53530\"]],[\"invoke\",1715,0,\"load8_u\",[\"i32:55520\"]],[\"invoke\",1726,0,\"load8_u\",[\"i32:57709\"]],[\"invoke\",1737,0,\"load8_u\",[\"i32:59898\"]],[\"invoke\",1748,0,\"load8_u\",[\"i32:62087\"]],[\"invoke\",1759,0,\"load8_u\",[\"i32:64276\"]],[\"invoke\",1770,0,\"load8_u\",[\"i32:65519\"]],[\"invoke\",1781,0,\"load8_u\",[\"i32:65530\"]],[\"module\",1788,88],[\"invoke\",1803,0,\"load8_u\",[\"i32:994\"]],[\"invoke\",1814,0,\"load8_u\",[\"i32:3183\"]],[\"invoke\",1824,0,\"load8_u\",[\"i32:5173\"]],[\"invoke\",1835,0,\"load8_u\",[\"i32:7362\"]],[\"invoke\",1846,0,\"load8_u\",[\"i32:9551\"]],[\"invoke\",1857,0,\"load8_u\",[\"i32:11740\"]],[\"invoke\",1868,0,\"load8_u\",[\"i32:13929\"]],[\"invoke\",1879,0,\"load8_u\",[\"i32:16118\"]],[\"invoke\",1890,0,\"load8_u\",[\"i32:18307\"]],[\"invoke\",1901,0,\"load8_u\",[\"i32:20496\"]],[\"invoke\",1911,0,\"load8_u\",[\"i32:22486\"]],[\"invoke\",1922,0,\"load8_u\",[\"i32:24675\"]],[\"invoke\",1933,0,\"load8_u\",[\"i32:26864\"]],[\"invoke\",1944,0,\"load8_u\",[\"i32:29053\"]],[\"invoke\",1955,0,\"load8_u\",[\"i32:31242\"]],[\"invoke\",1966,0,\"load8_u\",[\"i32:33431\"]],[\"invoke\",1977,0,\"load8_u\",[\"i32:35620\"]],[\"invoke\",1988,0,\"load8_u\",[\"i32:37809\"]],[\"invoke\",1999,0,\"load8_u\",[\"i32:39998\"]],[\"invoke\",2009,0,\"load8_u\",[\"i32:41988\"]],[\"invoke\",2020,0,\"load8_u\",[\"i32:44177\"]],[\"invoke\",2031,0,\"load8_u\",[\"i32:46366\"]],[\"invoke\",2042,0,\"load8_u\",[\"i32:48555\"]],[\"invoke\",2053,0,\"load8_u\",[\"i32:50744\"]],[\"invoke\",2064,0,\"load8_u\",[\"i32:52933\"]],[\"invoke\",2075,0,\"load8_u\",[\"i32:55122\"]],[\"invoke\",2086,0,\"load8_u\",[\"i32:57311\"]],[\"invoke\",2096,0,\"load8_u\",[\"i32:59301\"]],[\"invoke\",2107,0,\"load8_u\",[\"i32:61490\"]],[\"invoke\",2118,0,\"load8_u\",[\"i32:63679\"]],[\"invoke\",2129,0,\"load8_u\",[\"i32:65487\"]],[\"invoke\",2140,0,\"load8_u\",[\"i32:65498\"]],[\"module\",2149,86],[\"invoke\",2162,0,\"load8_u\",[\"i32:596\"]],[\"invoke\",2173,0,\"load8_u\",[\"i32:2785\"]],[\"invoke\",2184,0,\"load8_u\",[\"i32:4974\"]],[\"invoke\",2195,0,\"load8_u\",[\"i32:7163\"]],[\"invoke\",2205,0,\"load8_u\",[\"i32:9153\"]],[\"invoke\",2216,0,\"load8_u\",[\"i32:11342\"]],[\"invoke\",2227,0,\"load8_u\",[\"i32:13531\"]],[\"invoke\",2238,0,\"load8_u\",[\"i32:15720\"]],[\"invoke\",2249,0,\"load8_u\",[\"i32:17909\"]],[\"invoke\",2260,0,\"load8_u\",[\"i32:20098\"]],[\"invoke\",2271,0,\"load8_u\",[\"i32:22287\"]],[\"invoke\",2282,0,\"load8_u\",[\"i32:24476\"]],[\"invoke\",2292,0,\"load8_u\",[\"i32:26466\"]],[\"invoke\",2303,0,\"load8_u\",[\"i32:28655\"]],[\"invoke\",2314,0,\"load8_u\",[\"i32:30844\"]],[\"invoke\",2325,0,\"load8_u\",[\"i32:33033\"]],[\"invoke\",2336,0,\"load8_u\",[\"i32:35222\"]],[\"invoke\",2347,0,\"load8_u\",[\"i32:37411\"]],[\"invoke\",2358,0,\"load8_u\",[\"i32:39600\"]],[\"invoke\",2369,0,\"load8_u\",[\"i32:41789\"]],[\"invoke\",2380,0,\"load8_u\",[\"i32:43978\"]],[\"invoke\",2390,0,\"load8_u\",[\"i32:45968\"]],[\"invoke\",2401,0,\"load8_u\",[\"i32:48157\"]],[\"invoke\",2412,0,\"load8_u\",[\"i32:50346\"]],[\"invoke\",2423,0,\"load8_u\",[\"i32:52535\"]],[\"invoke\",2434,0,\"load8_u\",[\"i32:54724\"]],[\"invoke\",2445,0,\"load8_u\",[\"i32:56913\"]],[\"invoke\",2456,0,\"load8_u\",[\"i32:59102\"]],[\"invoke\",2467,0,\"load8_u\",[\"i32:61291\"]],[\"invoke\",2477,0,\"load8_u\",[\"i32:63281\"]],[\"invoke\",2488,0,\"load8_u\",[\"i32:65470\"]],[\"invoke\",2499,0,\"load8_u\",[\"i32:65526\"]],[\"module\",2510,89],[\"invoke\",2521,0,\"load8_u\",[\"i32:198\"]],[\"invoke\",2532,0,\"load8_u\",[\"i32:2387\"]],[\"invoke\",2543,0,\"load8_u\",[\"i32:4576\"]],[\"invoke\",2554,0,\"load8_u\",[\"i32:6765\"]],[\"invoke\",2565,0,\"load8_u\",[\"i32:8954\"]],[\"invoke\",2576,0,\"load8_u\",[\"i32:11143\"]],[\"invoke\",2586,0,\"load8_u\",[\"i32:13133\"]],[\"invoke\",2597,0,\"load8_u\",[\"i32:15322\"]],[\"invoke\",2608,0,\"load8_u\",[\"i32:17511\"]],[\"invoke\",2619,0,\"load8_u\",[\"i32:19700\"]],[\"invoke\",2630,0,\"load8_u\",[\"i32:21889\"]],[\"invoke\",2641,0,\"load8_u\",[\"i32:24078\"]],[\"invoke\",2652,0,\"load8_u\",[\"i32:26267\"]],[\"invoke\",2663,0,\"load8_u\",[\"i32:28456\"]],[\"invoke\",2673,0,\"load8_u\",[\"i32:30446\"]],[\"invoke\",2684,0,\"load8_u\",[\"i32:32635\"]],[\"invoke\",2695,0,\"load8_u\",[\"i32:34824\"]],[\"invoke\",2706,0,\"load8_u\",[\"i32:37013\"]],[\"invoke\",2717,0,\"load8_u\",[\"i32:39202\"]],[\"invoke\",2728,0,\"load8_u\",[\"i32:41391\"]],[\"invoke\",2739,0,\"load8_u\",[\"i32:43580\"]],[\"invoke\",2750,0,\"load8_u\",[\"i32:45769\"]],[\"invoke\",2761,0,\"load8_u\",[\"i32:47958\"]],[\"invoke\",2771,0,\"load8_u\",[\"i32:49948\"]],[\"invoke\",2782,0,\"load8_u\",[\"i32:52137\"]],[\"invoke\",2793,0,\"load8_u\",[\"i32:54326\"]],[\"invoke\",2804,0,\"load8_u\",[\"i32:56515\"]],[\"invoke\",2815,0,\"load8_u\",[\"i32:58704\"]],[\"invoke\",2826,0,\"load8_u\",[\"i32:60893\"]],[\"invoke\",2837,0,\"load8_u\",[\"i32:63082\"]],[\"invoke\",2848,0,\"load8_u\",[\"i32:65271\"]],[\"invoke\",2858,0,\"load8_u\",[\"i32:65514\"]],[\"invoke\",2869,0,\"load8_u\",[\"i32:65525\"]],[\"module\",2871,86],[\"invoke\",2891,0,\"load8_u\",[\"i32:1989\"]],[\"invoke\",2902,0,\"load8_u\",[\"i32:4178\"]],[\"invoke\",2913,0,\"load8_u\",[\"i32:6367\"]],[\"invoke\",2924,0,\"load8_u\",[\"i32:8556\"]],[\"invoke\",2935,0,\"load8_u\",[\"i32:10745\"]],[\"invoke\",2946,0,\"load8_u\",[\"i32:12934\"]],[\"invoke\",2957,0,\"load8_u\",[\"i32:15123\"]],[\"invoke\",2967,0,\"load8_u\",[\"i32:17113\"]],[\"invoke\",2978,0,\"load8_u\",[\"i32:19302\"]],[\"invoke\",2989,0,\"load8_u\",[\"i32:21491\"]],[\"invoke\",3000,0,\"load8_u\",[\"i32:23680\"]],[\"invoke\",3011,0,\"load8_u\",[\"i32:25869\"]],[\"invoke\",3022,0,\"load8_u\",[\"i32:28058\"]],[\"invoke\",3033,0,\"load8_u\",[\"i32:30247\"]],[\"invoke\",3044,0,\"load8_u\",[\"i32:32436\"]],[\"invoke\",3054,0,\"load8_u\",[\"i32:34426\"]],[\"invoke\",3065,0,\"load8_u\",[\"i32:36615\"]],[\"invoke\",3076,0,\"load8_u\",[\"i32:38804\"]],[\"invoke\",3087,0,\"load8_u\",[\"i32:40993\"]],[\"invoke\",3098,0,\"load8_u\",[\"i32:43182\"]],[\"invoke\",3109,0,\"load8_u\",[\"i32:45371\"]],[\"invoke\",3120,0,\"load8_u\",[\"i32:47560\"]],[\"invoke\",3131,0,\"load8_u\",[\"i32:49749\"]],[\"invoke\",3142,0,\"load8_u\",[\"i32:51938\"]],[\"invoke\",3152,0,\"load8_u\",[\"i32:53928\"]],[\"invoke\",3163,0,\"load8_u\",[\"i32:56117\"]],[\"invoke\",3174,0,\"load8_u\",[\"i32:58306\"]],[\"invoke\",3185,0,\"load8_u\",[\"i32:60495\"]],[\"invoke\",3196,0,\"load8_u\",[\"i32:62684\"]],[\"invoke\",3207,0,\"load8_u\",[\"i32:64873\"]],[\"invoke\",3218,0,\"load8_u\",[\"i32:65523\"]],[\"invoke\",3229,0,\"load8_u\",[\"i32:65534\"]],[\"module\",3232,86],[\"invoke\",3250,0,\"load8_u\",[\"i32:1591\"]],[\"invoke\",3261,0,\"load8_u\",[\"i32:3780\"]],[\"invoke\",3272,0,\"load8_u\",[\"i32:5969\"]],[\"invoke\",3283,0,\"load8_u\",[\"i32:8158\"]],[\"invoke\",3294,0,\"load8_u\",[\"i32:10347\"]],[\"invoke\",3305,0,\"load8_u\",[\"i32:12536\"]],[\"invoke\",3316,0,\"load8_u\",[\"i32:14725\"]],[\"invoke\",3327,0,\"load8_u\",[\"i32:16914\"]],[\"invoke\",3338,0,\"load8_u\",[\"i32:19103\"]],[\"invoke\",3348,0,\"load8_u\",[\"i32:21093\"]],[\"invoke\",3359,0,\"load8_u\",[\"i32:23282\"]],[\"invoke\",3370,0,\"load8_u\",[\"i32:25471\"]],[\"invoke\",3381,0,\"load8_u\",[\"i32:27660\"]],[\"invoke\",3392,0,\"load8_u\",[\"i32:29849\"]],[\"invoke\",3403,0,\"load8_u\",[\"i32:32038\"]],[\"invoke\",3414,0,\"load8_u\",[\"i32:34227\"]],[\"invoke\",3425,0,\"load8_u\",[\"i32:36416\"]],[\"invoke\",3435,0,\"load8_u\",[\"i32:38406\"]],[\"invoke\",3446,0,\"load8_u\",[\"i32:40595\"]],[\"invoke\",3457,0,\"load8_u\",[\"i32:42784\"]],[\"invoke\",3468,0,\"load8_u\",[\"i32:44973\"]],[\"invoke\",3479,0,\"load8_u\",[\"i32:47162\"]],[\"invoke\",3490,0,\"load8_u\",[\"i32:49351\"]],[\"invoke\",3501,0,\"load8_u\",[\"i32:51540\"]],[\"invoke\",3512,0,\"load8_u\",[\"i32:53729\"]],[\"invoke\",3523,0,\"load8_u\",[\"i32:55918\"]],[\"invoke\",3533,0,\"load8_u\",[\"i32:57908\"]],[\"invoke\",3544,0,\"load8_u\",[\"i32:60097\"]],[\"invoke\",3555,0,\"load8_u\",[\"i32:62286\"]],[\"invoke\",3566,0,\"load8_u\",[\"i32:64475\"]],[\"invoke\",3577,0,\"load8_u\",[\"i32:65521\"]],[\"invoke\",3588,0,\"load8_u\",[\"i32:65532\"]],[\"module\",3593,90],[\"invoke\",3610,0,\"load8_u\",[\"i32:1392\"]],[\"invoke\",3621,0,\"load8_u\",[\"i32:3581\"]],[\"invoke\",3631,0,\"load8_u\",[\"i32:5571\"]],[\"invoke\",3642,0,\"load8_u\",[\"i32:7760\"]],[\"invoke\",3653,0,\"load8_u\",[\"i32:9949\"]],[\"invoke\",3664,0,\"load8_u\",[\"i32:12138\"]],[\"invoke\",3675,0,\"load8_u\",[\"i32:14327\"]],[\"invoke\",3686,0,\"load8_u\",[\"i32:16516\"]],[\"invoke\",3697,0,\"load8_u\",[\"i32:18705\"]],[\"invoke\",3708,0,\"load8_u\",[\"i32:20894\"]],[\"invoke\",3719,0,\"load8_u\",[\"i32:23083\"]],[\"invoke\",3729,0,\"load8_u\",[\"i32:25073\"]],[\"invoke\",3740,0,\"load8_u\",[\"i32:27262\"]],[\"invoke\",3751,0,\"load8_u\",[\"i32:29451\"]],[\"invoke\",3762,0,\"load8_u\",[\"i32:31640\"]],[\"invoke\",3773,0,\"load8_u\",[\"i32:33829\"]],[\"invoke\",3784,0,\"load8_u\",[\"i32:36018\"]],[\"invoke\",3795,0,\"load8_u\",[\"i32:38207\"]],[\"invoke\",3806,0,\"load8_u\",[\"i32:40396\"]],[\"invoke\",3816,0,\"load8_u\",[\"i32:42386\"]],[\"invoke\",3827,0,\"load8_u\",[\"i32:44575\"]],[\"invoke\",3838,0,\"load8_u\",[\"i32:46764\"]],[\"invoke\",3849,0,\"load8_u\",[\"i32:48953\"]],[\"invoke\",3860,0,\"load8_u\",[\"i32:51142\"]],[\"invoke\",3871,0,\"load8_u\",[\"i32:53331\"]],[\"invoke\",3882,0,\"load8_u\",[\"i32:55520\"]],[\"invoke\",3893,0,\"load8_u\",[\"i32:57709\"]],[\"invoke\",3904,0,\"load8_u\",[\"i32:59898\"]],[\"invoke\",3914,0,\"load8_u\",[\"i32:61888\"]],[\"invoke\",3925,0,\"load8_u\",[\"i32:64077\"]],[\"invoke\",3936,0,\"load8_u\",[\"i32:65519\"]],[\"invoke\",3947,0,\"load8_u\",[\"i32:65530\"]],[\"module\",3954,91],[\"invoke\",3969,0,\"load8_u\",[\"i32:994\"]],[\"invoke\",3980,0,\"load8_u\",[\"i32:3183\"]],[\"invoke\",3991,0,\"load8_u\",[\"i32:5372\"]],[\"invoke\",4002,0,\"load8_u\",[\"i32:7561\"]],[\"invoke\",4012,0,\"load8_u\",[\"i32:9551\"]],[\"invoke\",4023,0,\"load8_u\",[\"i32:11740\"]],[\"invoke\",4034,0,\"load8_u\",[\"i32:13929\"]],[\"invoke\",4045,0,\"load8_u\",[\"i32:16118\"]],[\"invoke\",4056,0,\"load8_u\",[\"i32:18307\"]],[\"invoke\",4067,0,\"load8_u\",[\"i32:20496\"]],[\"invoke\",4078,0,\"load8_u\",[\"i32:22685\"]],[\"invoke\",4089,0,\"load8_u\",[\"i32:24874\"]],[\"invoke\",4100,0,\"load8_u\",[\"i32:27063\"]],[\"invoke\",4110,0,\"load8_u\",[\"i32:29053\"]],[\"invoke\",4121,0,\"load8_u\",[\"i32:31242\"]],[\"invoke\",4132,0,\"load8_u\",[\"i32:33431\"]],[\"invoke\",4143,0,\"load8_u\",[\"i32:35620\"]],[\"invoke\",4154,0,\"load8_u\",[\"i32:37809\"]],[\"invoke\",4165,0,\"load8_u\",[\"i32:39998\"]],[\"invoke\",4176,0,\"load8_u\",[\"i32:42187\"]],[\"invoke\",4187,0,\"load8_u\",[\"i32:44376\"]],[\"invoke\",4197,0,\"load8_u\",[\"i32:46366\"]],[\"invoke\",4208,0,\"load8_u\",[\"i32:48555\"]],[\"invoke\",4219,0,\"load8_u\",[\"i32:50744\"]],[\"invoke\",4230,0,\"load8_u\",[\"i32:52933\"]],[\"invoke\",4241,0,\"load8_u\",[\"i32:55122\"]],[\"invoke\",4252,0,\"load8_u\",[\"i32:57311\"]],[\"invoke\",4263,0,\"load8_u\",[\"i32:59500\"]],[\"invoke\",4274,0,\"load8_u\",[\"i32:61441\"]],[\"invoke\",4285,0,\"load8_u\",[\"i32:61452\"]],[\"invoke\",4295,0,\"load8_u\",[\"i32:61908\"]],[\"invoke\",4306,0,\"load8_u\",[\"i32:64097\"]],[\"module\",4763,92],[\"invoke\",4786,0,\"checkRange\",[\"i32:20\",\"i32:65536\",\"i32:0\"]],[\"module\",4789,93],[\"module\",4815,94],[\"module\",4821,95],[\"module\",4827,96],[\"module\",4833,97],[\"module\",4839,98],[\"invoke\",4861,0,\"checkRange\",[\"i32:32768\",\"i32:65536\",\"i32:170\"]],[\"module\",4863,99],[\"module\",4869,100],[\"module\",4875,101],[\"module\",4881,102],[\"module\",4887,103],[\"module\",4893,104],[\"module\",4899,105],[\"invoke\",5123,0,\"checkRange\",[\"i32:2132\",\"i32:2827\",\"i32:10\"]],[\"invoke\",5145,0,\"checkRange\",[\"i32:5691\",\"i32:6552\",\"i32:83\"]],[\"invoke\",5167,0,\"checkRange\",[\"i32:10087\",\"i32:10206\",\"i32:5\"]],[\"invoke\",5189,0,\"checkRange\",[\"i32:13114\",\"i32:14133\",\"i32:59\"]],[\"invoke\",5209,0,\"checkRange\",[\"i32:15871\",\"i32:15998\",\"i32:95\"]],[\"invoke\",5231,0,\"checkRange\",[\"i32:18553\",\"i32:18744\",\"i32:42\"]],[\"invoke\",5253,0,\"checkRange\",[\"i32:21468\",\"i32:21492\",\"i32:93\"]],[\"invoke\",5275,0,\"checkRange\",[\"i32:24348\",\"i32:24515\",\"i32:92\"]],[\"invoke\",5297,0,\"checkRange\",[\"i32:27503\",\"i32:27573\",\"i32:77\"]],[\"invoke\",5319,0,\"checkRange\",[\"i32:31379\",\"i32:31403\",\"i32:57\"]],[\"invoke\",5341,0,\"checkRange\",[\"i32:33056\",\"i32:33660\",\"i32:89\"]],[\"invoke\",5363,0,\"checkRange\",[\"i32:35648\",\"i32:36547\",\"i32:83\"]],[\"invoke\",5385,0,\"checkRange\",[\"i32:39187\",\"i32:39859\",\"i32:92\"]],[\"invoke\",5405,0,\"checkRange\",[\"i32:42945\",\"i32:43115\",\"i32:77\"]],[\"invoke\",5427,0,\"checkRange\",[\"i32:45575\",\"i32:45640\",\"i32:77\"]],[\"invoke\",5449,0,\"checkRange\",[\"i32:47951\",\"i32:48632\",\"i32:100\"]],[\"invoke\",5471,0,\"checkRange\",[\"i32:50370\",\"i32:51358\",\"i32:92\"]],[\"invoke\",5493,0,\"checkRange\",[\"i32:55198\",\"i32:55389\",\"i32:42\"]],[\"invoke\",5515,0,\"checkRange\",[\"i32:58516\",\"i32:58835\",\"i32:95\"]],[\"invoke\",5537,0,\"checkRange\",[\"i32:60777\",\"i32:60834\",\"i32:76\"]],[\"invoke\",5559,0,\"checkRange\",[\"i32:63525\",\"i32:63605\",\"i32:74\"]],[\"file\",\"memory_fill.wast\"],[\"module\",6,106],[\"invoke\",22,0,\"test\",[]],[\"invoke\",24,0,\"checkRange\",[\"i32:0\",\"i32:65280\",\"i32:0\"]],[\"invoke\",26,0,\"checkRange\",[\"i32:65280\",\"i32:65536\",\"i32:85\"]],[\"module\",28,107],[\"invoke\",44,0,\"test\",[]],[\"module\",46,108],[\"invoke\",62,0,\"test\",[]],[\"module\",64,109],[\"invoke\",80,0,\"test\",[]],[\"invoke\",82,0,\"checkRange\",[\"i32:0\",\"i32:65536\",\"i32:0\"]],[\"module\",84,110],[\"invoke\",100,0,\"test\",[]],[\"module\",102,111],[\"invoke\",118,0,\"test\",[]],[\"module\",120,112],[\"invoke\",136,0,\"test\",[]],[\"invoke\",138,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"invoke\",140,0,\"checkRange\",[\"i32:1\",\"i32:65535\",\"i32:170\"]],[\"invoke\",142,0,\"checkRange\",[\"i32:65535\",\"i32:65536\",\"i32:0\"]],[\"module\",145,113],[\"invoke\",162,0,\"test\",[]],[\"invoke\",164,0,\"checkRange\",[\"i32:0\",\"i32:18\",\"i32:0\"]],[\"invoke\",166,0,\"checkRange\",[\"i32:18\",\"i32:21\",\"i32:85\"]],[\"invoke\",168,0,\"checkRange\",[\"i32:21\",\"i32:25\",\"i32:170\"]],[\"invoke\",170,0,\"checkRange\",[\"i32:25\",\"i32:28\",\"i32:85\"]],[\"invoke\",172,0,\"checkRange\",[\"i32:28\",\"i32:65536\",\"i32:0\"]],[\"module\",621,114],[\"invoke\",638,0,\"run\",[\"i32:65280\",\"i32:37\",\"i32:512\"]],[\"invoke\",641,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",643,114],[\"invoke\",660,0,\"run\",[\"i32:65279\",\"i32:37\",\"i32:514\"]],[\"invoke\",663,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",665,114],[\"invoke\",682,0,\"run\",[\"i32:65279\",\"i32:37\",\"i32:4294967295\"]],[\"invoke\",685,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"file\",\"memory_init.wast\"],[\"module\",6,115],[\"invoke\",17,0,\"test\",[]],[\"invoke\",19,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",20,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",21,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",22,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",23,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",24,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",25,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",26,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",27,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",28,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",29,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",30,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",31,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",32,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",33,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",34,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",35,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",36,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",37,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",38,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",39,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",40,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",41,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",42,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",43,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",44,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",45,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",46,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",47,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",48,0,\"load8_u\",[\"i32:29\"]],[\"module\",50,116],[\"invoke\",61,0,\"test\",[]],[\"invoke\",63,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",64,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",65,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",66,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",67,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",68,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",69,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",70,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",71,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",72,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",73,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",74,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",75,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",76,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",77,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",78,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",79,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",80,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",81,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",82,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",83,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",84,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",85,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",86,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",87,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",88,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",89,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",90,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",91,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",92,0,\"load8_u\",[\"i32:29\"]],[\"module\",94,117],[\"invoke\",105,0,\"test\",[]],[\"invoke\",107,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",108,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",109,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",110,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",111,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",112,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",113,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",114,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",115,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",116,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",117,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",118,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",119,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",120,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",121,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",122,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",123,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",124,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",125,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",126,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",127,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",128,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",129,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",130,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",131,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",132,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",133,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",134,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",135,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",136,0,\"load8_u\",[\"i32:29\"]],[\"module\",138,118],[\"invoke\",157,0,\"test\",[]],[\"invoke\",159,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",160,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",161,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",162,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",163,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",164,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",165,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",166,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",167,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",168,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",169,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",170,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",171,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",172,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",173,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",174,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",175,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",176,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",177,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",178,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",179,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",180,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",181,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",182,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",183,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",184,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",185,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",186,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",187,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",188,0,\"load8_u\",[\"i32:29\"]],[\"module\",203,119],[\"invoke\",209,0,\"test\",[]],[\"module\",211,120],[\"invoke\",217,0,\"test\",[]],[\"module\",219,121],[\"invoke\",224,0,\"test\",[]],[\"module\",240,122],[\"invoke\",246,0,\"test\",[]],[\"module\",248,123],[\"invoke\",253,0,\"test\",[]],[\"module\",255,124],[\"invoke\",260,0,\"test\",[]],[\"module\",262,125],[\"invoke\",267,0,\"test\",[]],[\"module\",269,126],[\"invoke\",274,0,\"test\",[]],[\"module\",276,127],[\"invoke\",281,0,\"test\",[]],[\"module\",283,128],[\"invoke\",288,0,\"test\",[]],[\"module\",290,129],[\"invoke\",295,0,\"test\",[]],[\"module\",297,130],[\"invoke\",302,0,\"test\",[]],[\"module\",304,131],[\"invoke\",309,0,\"test\",[]],[\"module\",815,132],[\"invoke\",833,0,\"run\",[\"i32:65528\",\"i32:16\"]],[\"invoke\",836,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",838,132],[\"invoke\",856,0,\"run\",[\"i32:65527\",\"i32:16\"]],[\"invoke\",859,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",861,132],[\"invoke\",879,0,\"run\",[\"i32:65472\",\"i32:30\"]],[\"invoke\",882,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",884,132],[\"invoke\",902,0,\"run\",[\"i32:65473\",\"i32:31\"]],[\"invoke\",905,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",907,133],[\"invoke\",925,0,\"run\",[\"i32:65528\",\"i32:4294967040\"]],[\"invoke\",928,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",930,133],[\"invoke\",948,0,\"run\",[\"i32:0\",\"i32:4294967292\"]],[\"invoke\",951,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",954,134],[\"file\",\"data.wast\"],[\"module\",5,135],[\"module\",39,136],[\"module\",48,137],[\"module\",66,138],[\"module\",77,138],[\"module\",100,139],[\"module\",111,140],[\"module\",116,141],[\"module\",125,142],[\"module\",130,143],[\"module\",135,141],[\"module\",144,142],[\"instantiate\",184,144],[\"instantiate\",192,145],[\"instantiate\",200,146],[\"instantiate\",207,147],[\"instantiate\",214,148],[\"instantiate\",231,149],[\"instantiate\",240,150],[\"instantiate\",255,151],[\"instantiate\",263,152],[\"instantiate\",271,153],[\"instantiate\",286,154]]"; +export const script = "[[\"file\",\"address.wast\"],[\"module\",3,0],[\"invoke\",104,0,\"8u_good1\",[\"i32:0\"]],[\"invoke\",105,0,\"8u_good2\",[\"i32:0\"]],[\"invoke\",106,0,\"8u_good3\",[\"i32:0\"]],[\"invoke\",107,0,\"8u_good4\",[\"i32:0\"]],[\"invoke\",108,0,\"8u_good5\",[\"i32:0\"]],[\"invoke\",110,0,\"8s_good1\",[\"i32:0\"]],[\"invoke\",111,0,\"8s_good2\",[\"i32:0\"]],[\"invoke\",112,0,\"8s_good3\",[\"i32:0\"]],[\"invoke\",113,0,\"8s_good4\",[\"i32:0\"]],[\"invoke\",114,0,\"8s_good5\",[\"i32:0\"]],[\"invoke\",116,0,\"16u_good1\",[\"i32:0\"]],[\"invoke\",117,0,\"16u_good2\",[\"i32:0\"]],[\"invoke\",118,0,\"16u_good3\",[\"i32:0\"]],[\"invoke\",119,0,\"16u_good4\",[\"i32:0\"]],[\"invoke\",120,0,\"16u_good5\",[\"i32:0\"]],[\"invoke\",122,0,\"16s_good1\",[\"i32:0\"]],[\"invoke\",123,0,\"16s_good2\",[\"i32:0\"]],[\"invoke\",124,0,\"16s_good3\",[\"i32:0\"]],[\"invoke\",125,0,\"16s_good4\",[\"i32:0\"]],[\"invoke\",126,0,\"16s_good5\",[\"i32:0\"]],[\"invoke\",128,0,\"32_good1\",[\"i32:0\"]],[\"invoke\",129,0,\"32_good2\",[\"i32:0\"]],[\"invoke\",130,0,\"32_good3\",[\"i32:0\"]],[\"invoke\",131,0,\"32_good4\",[\"i32:0\"]],[\"invoke\",132,0,\"32_good5\",[\"i32:0\"]],[\"invoke\",134,0,\"8u_good1\",[\"i32:65507\"]],[\"invoke\",135,0,\"8u_good2\",[\"i32:65507\"]],[\"invoke\",136,0,\"8u_good3\",[\"i32:65507\"]],[\"invoke\",137,0,\"8u_good4\",[\"i32:65507\"]],[\"invoke\",138,0,\"8u_good5\",[\"i32:65507\"]],[\"invoke\",140,0,\"8s_good1\",[\"i32:65507\"]],[\"invoke\",141,0,\"8s_good2\",[\"i32:65507\"]],[\"invoke\",142,0,\"8s_good3\",[\"i32:65507\"]],[\"invoke\",143,0,\"8s_good4\",[\"i32:65507\"]],[\"invoke\",144,0,\"8s_good5\",[\"i32:65507\"]],[\"invoke\",146,0,\"16u_good1\",[\"i32:65507\"]],[\"invoke\",147,0,\"16u_good2\",[\"i32:65507\"]],[\"invoke\",148,0,\"16u_good3\",[\"i32:65507\"]],[\"invoke\",149,0,\"16u_good4\",[\"i32:65507\"]],[\"invoke\",150,0,\"16u_good5\",[\"i32:65507\"]],[\"invoke\",152,0,\"16s_good1\",[\"i32:65507\"]],[\"invoke\",153,0,\"16s_good2\",[\"i32:65507\"]],[\"invoke\",154,0,\"16s_good3\",[\"i32:65507\"]],[\"invoke\",155,0,\"16s_good4\",[\"i32:65507\"]],[\"invoke\",156,0,\"16s_good5\",[\"i32:65507\"]],[\"invoke\",158,0,\"32_good1\",[\"i32:65507\"]],[\"invoke\",159,0,\"32_good2\",[\"i32:65507\"]],[\"invoke\",160,0,\"32_good3\",[\"i32:65507\"]],[\"invoke\",161,0,\"32_good4\",[\"i32:65507\"]],[\"invoke\",162,0,\"32_good5\",[\"i32:65507\"]],[\"invoke\",164,0,\"8u_good1\",[\"i32:65508\"]],[\"invoke\",165,0,\"8u_good2\",[\"i32:65508\"]],[\"invoke\",166,0,\"8u_good3\",[\"i32:65508\"]],[\"invoke\",167,0,\"8u_good4\",[\"i32:65508\"]],[\"invoke\",168,0,\"8u_good5\",[\"i32:65508\"]],[\"invoke\",170,0,\"8s_good1\",[\"i32:65508\"]],[\"invoke\",171,0,\"8s_good2\",[\"i32:65508\"]],[\"invoke\",172,0,\"8s_good3\",[\"i32:65508\"]],[\"invoke\",173,0,\"8s_good4\",[\"i32:65508\"]],[\"invoke\",174,0,\"8s_good5\",[\"i32:65508\"]],[\"invoke\",176,0,\"16u_good1\",[\"i32:65508\"]],[\"invoke\",177,0,\"16u_good2\",[\"i32:65508\"]],[\"invoke\",178,0,\"16u_good3\",[\"i32:65508\"]],[\"invoke\",179,0,\"16u_good4\",[\"i32:65508\"]],[\"invoke\",180,0,\"16u_good5\",[\"i32:65508\"]],[\"invoke\",182,0,\"16s_good1\",[\"i32:65508\"]],[\"invoke\",183,0,\"16s_good2\",[\"i32:65508\"]],[\"invoke\",184,0,\"16s_good3\",[\"i32:65508\"]],[\"invoke\",185,0,\"16s_good4\",[\"i32:65508\"]],[\"invoke\",186,0,\"16s_good5\",[\"i32:65508\"]],[\"invoke\",188,0,\"32_good1\",[\"i32:65508\"]],[\"invoke\",189,0,\"32_good2\",[\"i32:65508\"]],[\"invoke\",190,0,\"32_good3\",[\"i32:65508\"]],[\"invoke\",191,0,\"32_good4\",[\"i32:65508\"]],[\"invoke\",192,0,\"32_good5\",[\"i32:65508\"]],[\"invoke\",194,0,\"8u_good3\",[\"i32:4294967295\"]],[\"invoke\",195,0,\"8s_good3\",[\"i32:4294967295\"]],[\"invoke\",196,0,\"16u_good3\",[\"i32:4294967295\"]],[\"invoke\",197,0,\"16s_good3\",[\"i32:4294967295\"]],[\"invoke\",198,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",199,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",201,0,\"8u_bad\",[\"i32:0\"]],[\"invoke\",202,0,\"8s_bad\",[\"i32:0\"]],[\"invoke\",203,0,\"16u_bad\",[\"i32:0\"]],[\"invoke\",204,0,\"16s_bad\",[\"i32:0\"]],[\"invoke\",205,0,\"32_bad\",[\"i32:0\"]],[\"invoke\",207,0,\"8u_bad\",[\"i32:1\"]],[\"invoke\",208,0,\"8s_bad\",[\"i32:1\"]],[\"invoke\",209,0,\"16u_bad\",[\"i32:1\"]],[\"invoke\",210,0,\"16s_bad\",[\"i32:1\"]],[\"invoke\",211,0,\"32_bad\",[\"i32:1\"]],[\"module\",223,1],[\"invoke\",362,0,\"8u_good1\",[\"i32:0\"]],[\"invoke\",363,0,\"8u_good2\",[\"i32:0\"]],[\"invoke\",364,0,\"8u_good3\",[\"i32:0\"]],[\"invoke\",365,0,\"8u_good4\",[\"i32:0\"]],[\"invoke\",366,0,\"8u_good5\",[\"i32:0\"]],[\"invoke\",368,0,\"8s_good1\",[\"i32:0\"]],[\"invoke\",369,0,\"8s_good2\",[\"i32:0\"]],[\"invoke\",370,0,\"8s_good3\",[\"i32:0\"]],[\"invoke\",371,0,\"8s_good4\",[\"i32:0\"]],[\"invoke\",372,0,\"8s_good5\",[\"i32:0\"]],[\"invoke\",374,0,\"16u_good1\",[\"i32:0\"]],[\"invoke\",375,0,\"16u_good2\",[\"i32:0\"]],[\"invoke\",376,0,\"16u_good3\",[\"i32:0\"]],[\"invoke\",377,0,\"16u_good4\",[\"i32:0\"]],[\"invoke\",378,0,\"16u_good5\",[\"i32:0\"]],[\"invoke\",380,0,\"16s_good1\",[\"i32:0\"]],[\"invoke\",381,0,\"16s_good2\",[\"i32:0\"]],[\"invoke\",382,0,\"16s_good3\",[\"i32:0\"]],[\"invoke\",383,0,\"16s_good4\",[\"i32:0\"]],[\"invoke\",384,0,\"16s_good5\",[\"i32:0\"]],[\"invoke\",386,0,\"32u_good1\",[\"i32:0\"]],[\"invoke\",387,0,\"32u_good2\",[\"i32:0\"]],[\"invoke\",388,0,\"32u_good3\",[\"i32:0\"]],[\"invoke\",389,0,\"32u_good4\",[\"i32:0\"]],[\"invoke\",390,0,\"32u_good5\",[\"i32:0\"]],[\"invoke\",392,0,\"32s_good1\",[\"i32:0\"]],[\"invoke\",393,0,\"32s_good2\",[\"i32:0\"]],[\"invoke\",394,0,\"32s_good3\",[\"i32:0\"]],[\"invoke\",395,0,\"32s_good4\",[\"i32:0\"]],[\"invoke\",396,0,\"32s_good5\",[\"i32:0\"]],[\"invoke\",398,0,\"64_good1\",[\"i32:0\"]],[\"invoke\",399,0,\"64_good2\",[\"i32:0\"]],[\"invoke\",400,0,\"64_good3\",[\"i32:0\"]],[\"invoke\",401,0,\"64_good4\",[\"i32:0\"]],[\"invoke\",402,0,\"64_good5\",[\"i32:0\"]],[\"invoke\",404,0,\"8u_good1\",[\"i32:65503\"]],[\"invoke\",405,0,\"8u_good2\",[\"i32:65503\"]],[\"invoke\",406,0,\"8u_good3\",[\"i32:65503\"]],[\"invoke\",407,0,\"8u_good4\",[\"i32:65503\"]],[\"invoke\",408,0,\"8u_good5\",[\"i32:65503\"]],[\"invoke\",410,0,\"8s_good1\",[\"i32:65503\"]],[\"invoke\",411,0,\"8s_good2\",[\"i32:65503\"]],[\"invoke\",412,0,\"8s_good3\",[\"i32:65503\"]],[\"invoke\",413,0,\"8s_good4\",[\"i32:65503\"]],[\"invoke\",414,0,\"8s_good5\",[\"i32:65503\"]],[\"invoke\",416,0,\"16u_good1\",[\"i32:65503\"]],[\"invoke\",417,0,\"16u_good2\",[\"i32:65503\"]],[\"invoke\",418,0,\"16u_good3\",[\"i32:65503\"]],[\"invoke\",419,0,\"16u_good4\",[\"i32:65503\"]],[\"invoke\",420,0,\"16u_good5\",[\"i32:65503\"]],[\"invoke\",422,0,\"16s_good1\",[\"i32:65503\"]],[\"invoke\",423,0,\"16s_good2\",[\"i32:65503\"]],[\"invoke\",424,0,\"16s_good3\",[\"i32:65503\"]],[\"invoke\",425,0,\"16s_good4\",[\"i32:65503\"]],[\"invoke\",426,0,\"16s_good5\",[\"i32:65503\"]],[\"invoke\",428,0,\"32u_good1\",[\"i32:65503\"]],[\"invoke\",429,0,\"32u_good2\",[\"i32:65503\"]],[\"invoke\",430,0,\"32u_good3\",[\"i32:65503\"]],[\"invoke\",431,0,\"32u_good4\",[\"i32:65503\"]],[\"invoke\",432,0,\"32u_good5\",[\"i32:65503\"]],[\"invoke\",434,0,\"32s_good1\",[\"i32:65503\"]],[\"invoke\",435,0,\"32s_good2\",[\"i32:65503\"]],[\"invoke\",436,0,\"32s_good3\",[\"i32:65503\"]],[\"invoke\",437,0,\"32s_good4\",[\"i32:65503\"]],[\"invoke\",438,0,\"32s_good5\",[\"i32:65503\"]],[\"invoke\",440,0,\"64_good1\",[\"i32:65503\"]],[\"invoke\",441,0,\"64_good2\",[\"i32:65503\"]],[\"invoke\",442,0,\"64_good3\",[\"i32:65503\"]],[\"invoke\",443,0,\"64_good4\",[\"i32:65503\"]],[\"invoke\",444,0,\"64_good5\",[\"i32:65503\"]],[\"invoke\",446,0,\"8u_good1\",[\"i32:65504\"]],[\"invoke\",447,0,\"8u_good2\",[\"i32:65504\"]],[\"invoke\",448,0,\"8u_good3\",[\"i32:65504\"]],[\"invoke\",449,0,\"8u_good4\",[\"i32:65504\"]],[\"invoke\",450,0,\"8u_good5\",[\"i32:65504\"]],[\"invoke\",452,0,\"8s_good1\",[\"i32:65504\"]],[\"invoke\",453,0,\"8s_good2\",[\"i32:65504\"]],[\"invoke\",454,0,\"8s_good3\",[\"i32:65504\"]],[\"invoke\",455,0,\"8s_good4\",[\"i32:65504\"]],[\"invoke\",456,0,\"8s_good5\",[\"i32:65504\"]],[\"invoke\",458,0,\"16u_good1\",[\"i32:65504\"]],[\"invoke\",459,0,\"16u_good2\",[\"i32:65504\"]],[\"invoke\",460,0,\"16u_good3\",[\"i32:65504\"]],[\"invoke\",461,0,\"16u_good4\",[\"i32:65504\"]],[\"invoke\",462,0,\"16u_good5\",[\"i32:65504\"]],[\"invoke\",464,0,\"16s_good1\",[\"i32:65504\"]],[\"invoke\",465,0,\"16s_good2\",[\"i32:65504\"]],[\"invoke\",466,0,\"16s_good3\",[\"i32:65504\"]],[\"invoke\",467,0,\"16s_good4\",[\"i32:65504\"]],[\"invoke\",468,0,\"16s_good5\",[\"i32:65504\"]],[\"invoke\",470,0,\"32u_good1\",[\"i32:65504\"]],[\"invoke\",471,0,\"32u_good2\",[\"i32:65504\"]],[\"invoke\",472,0,\"32u_good3\",[\"i32:65504\"]],[\"invoke\",473,0,\"32u_good4\",[\"i32:65504\"]],[\"invoke\",474,0,\"32u_good5\",[\"i32:65504\"]],[\"invoke\",476,0,\"32s_good1\",[\"i32:65504\"]],[\"invoke\",477,0,\"32s_good2\",[\"i32:65504\"]],[\"invoke\",478,0,\"32s_good3\",[\"i32:65504\"]],[\"invoke\",479,0,\"32s_good4\",[\"i32:65504\"]],[\"invoke\",480,0,\"32s_good5\",[\"i32:65504\"]],[\"invoke\",482,0,\"64_good1\",[\"i32:65504\"]],[\"invoke\",483,0,\"64_good2\",[\"i32:65504\"]],[\"invoke\",484,0,\"64_good3\",[\"i32:65504\"]],[\"invoke\",485,0,\"64_good4\",[\"i32:65504\"]],[\"invoke\",486,0,\"64_good5\",[\"i32:65504\"]],[\"invoke\",488,0,\"8u_good3\",[\"i32:4294967295\"]],[\"invoke\",489,0,\"8s_good3\",[\"i32:4294967295\"]],[\"invoke\",490,0,\"16u_good3\",[\"i32:4294967295\"]],[\"invoke\",491,0,\"16s_good3\",[\"i32:4294967295\"]],[\"invoke\",492,0,\"32u_good3\",[\"i32:4294967295\"]],[\"invoke\",493,0,\"32s_good3\",[\"i32:4294967295\"]],[\"invoke\",494,0,\"64_good3\",[\"i32:4294967295\"]],[\"invoke\",496,0,\"8u_bad\",[\"i32:0\"]],[\"invoke\",497,0,\"8s_bad\",[\"i32:0\"]],[\"invoke\",498,0,\"16u_bad\",[\"i32:0\"]],[\"invoke\",499,0,\"16s_bad\",[\"i32:0\"]],[\"invoke\",500,0,\"32u_bad\",[\"i32:0\"]],[\"invoke\",501,0,\"32s_bad\",[\"i32:0\"]],[\"invoke\",502,0,\"64_bad\",[\"i32:0\"]],[\"invoke\",504,0,\"8u_bad\",[\"i32:1\"]],[\"invoke\",505,0,\"8s_bad\",[\"i32:1\"]],[\"invoke\",506,0,\"16u_bad\",[\"i32:1\"]],[\"invoke\",507,0,\"16s_bad\",[\"i32:1\"]],[\"invoke\",508,0,\"32u_bad\",[\"i32:0\"]],[\"invoke\",509,0,\"32s_bad\",[\"i32:0\"]],[\"invoke\",510,0,\"64_bad\",[\"i32:1\"]],[\"module\",514,2],[\"invoke\",538,0,\"32_good1\",[\"i32:0\"]],[\"invoke\",539,0,\"32_good2\",[\"i32:0\"]],[\"invoke\",540,0,\"32_good3\",[\"i32:0\"]],[\"invoke\",541,0,\"32_good4\",[\"i32:0\"]],[\"invoke\",542,0,\"32_good5\",[\"i32:0\"]],[\"invoke\",544,0,\"32_good1\",[\"i32:65524\"]],[\"invoke\",545,0,\"32_good2\",[\"i32:65524\"]],[\"invoke\",546,0,\"32_good3\",[\"i32:65524\"]],[\"invoke\",547,0,\"32_good4\",[\"i32:65524\"]],[\"invoke\",548,0,\"32_good5\",[\"i32:65524\"]],[\"invoke\",550,0,\"32_good1\",[\"i32:65525\"]],[\"invoke\",551,0,\"32_good2\",[\"i32:65525\"]],[\"invoke\",552,0,\"32_good3\",[\"i32:65525\"]],[\"invoke\",553,0,\"32_good4\",[\"i32:65525\"]],[\"invoke\",554,0,\"32_good5\",[\"i32:65525\"]],[\"invoke\",556,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",557,0,\"32_good3\",[\"i32:4294967295\"]],[\"invoke\",559,0,\"32_bad\",[\"i32:0\"]],[\"invoke\",560,0,\"32_bad\",[\"i32:1\"]],[\"module\",564,3],[\"invoke\",588,0,\"64_good1\",[\"i32:0\"]],[\"invoke\",589,0,\"64_good2\",[\"i32:0\"]],[\"invoke\",590,0,\"64_good3\",[\"i32:0\"]],[\"invoke\",591,0,\"64_good4\",[\"i32:0\"]],[\"invoke\",592,0,\"64_good5\",[\"i32:0\"]],[\"invoke\",594,0,\"64_good1\",[\"i32:65510\"]],[\"invoke\",595,0,\"64_good2\",[\"i32:65510\"]],[\"invoke\",596,0,\"64_good3\",[\"i32:65510\"]],[\"invoke\",597,0,\"64_good4\",[\"i32:65510\"]],[\"invoke\",598,0,\"64_good5\",[\"i32:65510\"]],[\"invoke\",600,0,\"64_good1\",[\"i32:65511\"]],[\"invoke\",601,0,\"64_good2\",[\"i32:65511\"]],[\"invoke\",602,0,\"64_good3\",[\"i32:65511\"]],[\"invoke\",603,0,\"64_good4\",[\"i32:65511\"]],[\"invoke\",604,0,\"64_good5\",[\"i32:65511\"]],[\"invoke\",606,0,\"64_good3\",[\"i32:4294967295\"]],[\"invoke\",607,0,\"64_good3\",[\"i32:4294967295\"]],[\"invoke\",609,0,\"64_bad\",[\"i32:0\"]],[\"invoke\",610,0,\"64_bad\",[\"i32:1\"]],[\"file\",\"align.wast\"],[\"module\",3,4],[\"module\",4,5],[\"module\",5,6],[\"module\",6,7],[\"module\",7,8],[\"module\",8,9],[\"module\",9,10],[\"module\",10,11],[\"module\",11,12],[\"module\",12,13],[\"module\",13,14],[\"module\",14,15],[\"module\",15,16],[\"module\",16,17],[\"module\",17,18],[\"module\",18,19],[\"module\",19,20],[\"module\",20,21],[\"module\",21,22],[\"module\",22,23],[\"module\",23,24],[\"module\",24,25],[\"module\",25,26],[\"module\",458,27],[\"invoke\",802,0,\"f32_align_switch\",[\"i32:0\"]],[\"invoke\",803,0,\"f32_align_switch\",[\"i32:1\"]],[\"invoke\",804,0,\"f32_align_switch\",[\"i32:2\"]],[\"invoke\",805,0,\"f32_align_switch\",[\"i32:3\"]],[\"invoke\",807,0,\"f64_align_switch\",[\"i32:0\"]],[\"invoke\",808,0,\"f64_align_switch\",[\"i32:1\"]],[\"invoke\",809,0,\"f64_align_switch\",[\"i32:2\"]],[\"invoke\",810,0,\"f64_align_switch\",[\"i32:3\"]],[\"invoke\",811,0,\"f64_align_switch\",[\"i32:4\"]],[\"invoke\",813,0,\"i32_align_switch\",[\"i32:0\",\"i32:0\"]],[\"invoke\",814,0,\"i32_align_switch\",[\"i32:0\",\"i32:1\"]],[\"invoke\",815,0,\"i32_align_switch\",[\"i32:1\",\"i32:0\"]],[\"invoke\",816,0,\"i32_align_switch\",[\"i32:1\",\"i32:1\"]],[\"invoke\",817,0,\"i32_align_switch\",[\"i32:2\",\"i32:0\"]],[\"invoke\",818,0,\"i32_align_switch\",[\"i32:2\",\"i32:1\"]],[\"invoke\",819,0,\"i32_align_switch\",[\"i32:2\",\"i32:2\"]],[\"invoke\",820,0,\"i32_align_switch\",[\"i32:3\",\"i32:0\"]],[\"invoke\",821,0,\"i32_align_switch\",[\"i32:3\",\"i32:1\"]],[\"invoke\",822,0,\"i32_align_switch\",[\"i32:3\",\"i32:2\"]],[\"invoke\",823,0,\"i32_align_switch\",[\"i32:4\",\"i32:0\"]],[\"invoke\",824,0,\"i32_align_switch\",[\"i32:4\",\"i32:1\"]],[\"invoke\",825,0,\"i32_align_switch\",[\"i32:4\",\"i32:2\"]],[\"invoke\",826,0,\"i32_align_switch\",[\"i32:4\",\"i32:4\"]],[\"invoke\",828,0,\"i64_align_switch\",[\"i32:0\",\"i32:0\"]],[\"invoke\",829,0,\"i64_align_switch\",[\"i32:0\",\"i32:1\"]],[\"invoke\",830,0,\"i64_align_switch\",[\"i32:1\",\"i32:0\"]],[\"invoke\",831,0,\"i64_align_switch\",[\"i32:1\",\"i32:1\"]],[\"invoke\",832,0,\"i64_align_switch\",[\"i32:2\",\"i32:0\"]],[\"invoke\",833,0,\"i64_align_switch\",[\"i32:2\",\"i32:1\"]],[\"invoke\",834,0,\"i64_align_switch\",[\"i32:2\",\"i32:2\"]],[\"invoke\",835,0,\"i64_align_switch\",[\"i32:3\",\"i32:0\"]],[\"invoke\",836,0,\"i64_align_switch\",[\"i32:3\",\"i32:1\"]],[\"invoke\",837,0,\"i64_align_switch\",[\"i32:3\",\"i32:2\"]],[\"invoke\",838,0,\"i64_align_switch\",[\"i32:4\",\"i32:0\"]],[\"invoke\",839,0,\"i64_align_switch\",[\"i32:4\",\"i32:1\"]],[\"invoke\",840,0,\"i64_align_switch\",[\"i32:4\",\"i32:2\"]],[\"invoke\",841,0,\"i64_align_switch\",[\"i32:4\",\"i32:4\"]],[\"invoke\",842,0,\"i64_align_switch\",[\"i32:5\",\"i32:0\"]],[\"invoke\",843,0,\"i64_align_switch\",[\"i32:5\",\"i32:1\"]],[\"invoke\",844,0,\"i64_align_switch\",[\"i32:5\",\"i32:2\"]],[\"invoke\",845,0,\"i64_align_switch\",[\"i32:5\",\"i32:4\"]],[\"invoke\",846,0,\"i64_align_switch\",[\"i32:6\",\"i32:0\"]],[\"invoke\",847,0,\"i64_align_switch\",[\"i32:6\",\"i32:1\"]],[\"invoke\",848,0,\"i64_align_switch\",[\"i32:6\",\"i32:2\"]],[\"invoke\",849,0,\"i64_align_switch\",[\"i32:6\",\"i32:4\"]],[\"invoke\",850,0,\"i64_align_switch\",[\"i32:6\",\"i32:8\"]],[\"module\",854,28],[\"invoke\",864,0,\"store\",[\"i32:65532\",\"i64:18446744073709551615\"]],[\"invoke\",866,0,\"load\",[\"i32:65532\"]],[\"file\",\"endianness.wast\"],[\"module\",1,29],[\"invoke\",133,0,\"i32_load16_s\",[\"i32:4294967295\"]],[\"invoke\",134,0,\"i32_load16_s\",[\"i32:4294963054\"]],[\"invoke\",135,0,\"i32_load16_s\",[\"i32:42\"]],[\"invoke\",136,0,\"i32_load16_s\",[\"i32:12816\"]],[\"invoke\",138,0,\"i32_load16_u\",[\"i32:4294967295\"]],[\"invoke\",139,0,\"i32_load16_u\",[\"i32:4294963054\"]],[\"invoke\",140,0,\"i32_load16_u\",[\"i32:42\"]],[\"invoke\",141,0,\"i32_load16_u\",[\"i32:51966\"]],[\"invoke\",143,0,\"i32_load\",[\"i32:4294967295\"]],[\"invoke\",144,0,\"i32_load\",[\"i32:4252543054\"]],[\"invoke\",145,0,\"i32_load\",[\"i32:42424242\"]],[\"invoke\",146,0,\"i32_load\",[\"i32:2880249322\"]],[\"invoke\",148,0,\"i64_load16_s\",[\"i64:18446744073709551615\"]],[\"invoke\",149,0,\"i64_load16_s\",[\"i64:18446744073709547374\"]],[\"invoke\",150,0,\"i64_load16_s\",[\"i64:42\"]],[\"invoke\",151,0,\"i64_load16_s\",[\"i64:12816\"]],[\"invoke\",153,0,\"i64_load16_u\",[\"i64:18446744073709551615\"]],[\"invoke\",154,0,\"i64_load16_u\",[\"i64:18446744073709547374\"]],[\"invoke\",155,0,\"i64_load16_u\",[\"i64:42\"]],[\"invoke\",156,0,\"i64_load16_u\",[\"i64:51966\"]],[\"invoke\",158,0,\"i64_load32_s\",[\"i64:18446744073709551615\"]],[\"invoke\",159,0,\"i64_load32_s\",[\"i64:18446744073667127374\"]],[\"invoke\",160,0,\"i64_load32_s\",[\"i64:42424242\"]],[\"invoke\",161,0,\"i64_load32_s\",[\"i64:305419896\"]],[\"invoke\",163,0,\"i64_load32_u\",[\"i64:18446744073709551615\"]],[\"invoke\",164,0,\"i64_load32_u\",[\"i64:18446744073667127374\"]],[\"invoke\",165,0,\"i64_load32_u\",[\"i64:42424242\"]],[\"invoke\",166,0,\"i64_load32_u\",[\"i64:2880249322\"]],[\"invoke\",168,0,\"i64_load\",[\"i64:18446744073709551615\"]],[\"invoke\",169,0,\"i64_load\",[\"i64:18446744073667127374\"]],[\"invoke\",170,0,\"i64_load\",[\"i64:2880249322\"]],[\"invoke\",171,0,\"i64_load\",[\"i64:12370766947463011818\"]],[\"invoke\",173,0,\"f32_load\",[\"f32:3212836864\"]],[\"invoke\",174,0,\"f32_load\",[\"f32:1011494326\"]],[\"invoke\",175,0,\"f32_load\",[\"f32:1166316389\"]],[\"invoke\",176,0,\"f32_load\",[\"f32:2139095039\"]],[\"invoke\",178,0,\"f64_load\",[\"f64:13830554455654793216\"]],[\"invoke\",179,0,\"f64_load\",[\"f64:4653144502447687399\"]],[\"invoke\",180,0,\"f64_load\",[\"f64:4691032041816096430\"]],[\"invoke\",181,0,\"f64_load\",[\"f64:9218868437227405311\"]],[\"invoke\",184,0,\"i32_store16\",[\"i32:4294967295\"]],[\"invoke\",185,0,\"i32_store16\",[\"i32:4294963054\"]],[\"invoke\",186,0,\"i32_store16\",[\"i32:42\"]],[\"invoke\",187,0,\"i32_store16\",[\"i32:51966\"]],[\"invoke\",189,0,\"i32_store\",[\"i32:4294967295\"]],[\"invoke\",190,0,\"i32_store\",[\"i32:4294963054\"]],[\"invoke\",191,0,\"i32_store\",[\"i32:42424242\"]],[\"invoke\",192,0,\"i32_store\",[\"i32:3735931646\"]],[\"invoke\",194,0,\"i64_store16\",[\"i64:18446744073709551615\"]],[\"invoke\",195,0,\"i64_store16\",[\"i64:18446744073709547374\"]],[\"invoke\",196,0,\"i64_store16\",[\"i64:42\"]],[\"invoke\",197,0,\"i64_store16\",[\"i64:51966\"]],[\"invoke\",199,0,\"i64_store32\",[\"i64:18446744073709551615\"]],[\"invoke\",200,0,\"i64_store32\",[\"i64:18446744073709547374\"]],[\"invoke\",201,0,\"i64_store32\",[\"i64:42424242\"]],[\"invoke\",202,0,\"i64_store32\",[\"i64:3735931646\"]],[\"invoke\",204,0,\"i64_store\",[\"i64:18446744073709551615\"]],[\"invoke\",205,0,\"i64_store\",[\"i64:18446744073667127374\"]],[\"invoke\",206,0,\"i64_store\",[\"i64:2880249322\"]],[\"invoke\",207,0,\"i64_store\",[\"i64:12370766947463011818\"]],[\"invoke\",209,0,\"f32_store\",[\"f32:3212836864\"]],[\"invoke\",210,0,\"f32_store\",[\"f32:1011494326\"]],[\"invoke\",211,0,\"f32_store\",[\"f32:1166316389\"]],[\"invoke\",212,0,\"f32_store\",[\"f32:2139095039\"]],[\"invoke\",214,0,\"f64_store\",[\"f64:13830554455654793216\"]],[\"invoke\",215,0,\"f64_store\",[\"f64:4653144502447687399\"]],[\"invoke\",216,0,\"f64_store\",[\"f64:4691032041816096430\"]],[\"invoke\",217,0,\"f64_store\",[\"f64:9218868437227405311\"]],[\"file\",\"float_memory.wast\"],[\"module\",5,30],[\"invoke\",15,0,\"i32.load\",[]],[\"invoke\",16,0,\"f32.load\",[]],[\"invoke\",17,0,\"reset\",[]],[\"invoke\",18,0,\"i32.load\",[]],[\"invoke\",19,0,\"f32.load\",[]],[\"invoke\",20,0,\"f32.store\",[]],[\"invoke\",21,0,\"i32.load\",[]],[\"invoke\",22,0,\"f32.load\",[]],[\"invoke\",23,0,\"reset\",[]],[\"invoke\",24,0,\"i32.load\",[]],[\"invoke\",25,0,\"f32.load\",[]],[\"invoke\",26,0,\"i32.store\",[]],[\"invoke\",27,0,\"i32.load\",[]],[\"invoke\",28,0,\"f32.load\",[]],[\"module\",30,31],[\"invoke\",40,0,\"i64.load\",[]],[\"invoke\",41,0,\"f64.load\",[]],[\"invoke\",42,0,\"reset\",[]],[\"invoke\",43,0,\"i64.load\",[]],[\"invoke\",44,0,\"f64.load\",[]],[\"invoke\",45,0,\"f64.store\",[]],[\"invoke\",46,0,\"i64.load\",[]],[\"invoke\",47,0,\"f64.load\",[]],[\"invoke\",48,0,\"reset\",[]],[\"invoke\",49,0,\"i64.load\",[]],[\"invoke\",50,0,\"f64.load\",[]],[\"invoke\",51,0,\"i64.store\",[]],[\"invoke\",52,0,\"i64.load\",[]],[\"invoke\",53,0,\"f64.load\",[]],[\"module\",57,32],[\"invoke\",67,0,\"i32.load\",[]],[\"invoke\",68,0,\"f32.load\",[]],[\"invoke\",69,0,\"reset\",[]],[\"invoke\",70,0,\"i32.load\",[]],[\"invoke\",71,0,\"f32.load\",[]],[\"invoke\",72,0,\"f32.store\",[]],[\"invoke\",73,0,\"i32.load\",[]],[\"invoke\",74,0,\"f32.load\",[]],[\"invoke\",75,0,\"reset\",[]],[\"invoke\",76,0,\"i32.load\",[]],[\"invoke\",77,0,\"f32.load\",[]],[\"invoke\",78,0,\"i32.store\",[]],[\"invoke\",79,0,\"i32.load\",[]],[\"invoke\",80,0,\"f32.load\",[]],[\"module\",82,33],[\"invoke\",92,0,\"i64.load\",[]],[\"invoke\",93,0,\"f64.load\",[]],[\"invoke\",94,0,\"reset\",[]],[\"invoke\",95,0,\"i64.load\",[]],[\"invoke\",96,0,\"f64.load\",[]],[\"invoke\",97,0,\"f64.store\",[]],[\"invoke\",98,0,\"i64.load\",[]],[\"invoke\",99,0,\"f64.load\",[]],[\"invoke\",100,0,\"reset\",[]],[\"invoke\",101,0,\"i64.load\",[]],[\"invoke\",102,0,\"f64.load\",[]],[\"invoke\",103,0,\"i64.store\",[]],[\"invoke\",104,0,\"i64.load\",[]],[\"invoke\",105,0,\"f64.load\",[]],[\"module\",109,34],[\"invoke\",119,0,\"i32.load\",[]],[\"invoke\",120,0,\"f32.load\",[]],[\"invoke\",121,0,\"reset\",[]],[\"invoke\",122,0,\"i32.load\",[]],[\"invoke\",123,0,\"f32.load\",[]],[\"invoke\",124,0,\"f32.store\",[]],[\"invoke\",125,0,\"i32.load\",[]],[\"invoke\",126,0,\"f32.load\",[]],[\"invoke\",127,0,\"reset\",[]],[\"invoke\",128,0,\"i32.load\",[]],[\"invoke\",129,0,\"f32.load\",[]],[\"invoke\",130,0,\"i32.store\",[]],[\"invoke\",131,0,\"i32.load\",[]],[\"invoke\",132,0,\"f32.load\",[]],[\"module\",134,35],[\"invoke\",144,0,\"i64.load\",[]],[\"invoke\",145,0,\"f64.load\",[]],[\"invoke\",146,0,\"reset\",[]],[\"invoke\",147,0,\"i64.load\",[]],[\"invoke\",148,0,\"f64.load\",[]],[\"invoke\",149,0,\"f64.store\",[]],[\"invoke\",150,0,\"i64.load\",[]],[\"invoke\",151,0,\"f64.load\",[]],[\"invoke\",152,0,\"reset\",[]],[\"invoke\",153,0,\"i64.load\",[]],[\"invoke\",154,0,\"f64.load\",[]],[\"invoke\",155,0,\"i64.store\",[]],[\"invoke\",156,0,\"i64.load\",[]],[\"invoke\",157,0,\"f64.load\",[]],[\"file\",\"load.wast\"],[\"module\",3,36],[\"invoke\",161,0,\"as-br-value\",[]],[\"invoke\",163,0,\"as-br_if-cond\",[]],[\"invoke\",164,0,\"as-br_if-value\",[]],[\"invoke\",165,0,\"as-br_if-value-cond\",[]],[\"invoke\",167,0,\"as-br_table-index\",[]],[\"invoke\",168,0,\"as-br_table-value\",[]],[\"invoke\",169,0,\"as-br_table-value-index\",[]],[\"invoke\",171,0,\"as-return-value\",[]],[\"invoke\",173,0,\"as-if-cond\",[]],[\"invoke\",174,0,\"as-if-then\",[]],[\"invoke\",175,0,\"as-if-else\",[]],[\"invoke\",177,0,\"as-select-first\",[\"i32:0\",\"i32:1\"]],[\"invoke\",178,0,\"as-select-second\",[\"i32:0\",\"i32:0\"]],[\"invoke\",179,0,\"as-select-cond\",[]],[\"invoke\",181,0,\"as-call-first\",[]],[\"invoke\",182,0,\"as-call-mid\",[]],[\"invoke\",183,0,\"as-call-last\",[]],[\"invoke\",185,0,\"as-call_indirect-first\",[]],[\"invoke\",186,0,\"as-call_indirect-mid\",[]],[\"invoke\",187,0,\"as-call_indirect-last\",[]],[\"invoke\",188,0,\"as-call_indirect-index\",[]],[\"invoke\",190,0,\"as-local.set-value\",[]],[\"invoke\",191,0,\"as-local.tee-value\",[]],[\"invoke\",192,0,\"as-global.set-value\",[]],[\"invoke\",194,0,\"as-load-address\",[]],[\"invoke\",195,0,\"as-loadN-address\",[]],[\"invoke\",196,0,\"as-store-address\",[]],[\"invoke\",197,0,\"as-store-value\",[]],[\"invoke\",198,0,\"as-storeN-address\",[]],[\"invoke\",199,0,\"as-storeN-value\",[]],[\"invoke\",201,0,\"as-unary-operand\",[]],[\"invoke\",203,0,\"as-binary-left\",[]],[\"invoke\",204,0,\"as-binary-right\",[]],[\"invoke\",206,0,\"as-test-operand\",[]],[\"invoke\",208,0,\"as-compare-left\",[]],[\"invoke\",209,0,\"as-compare-right\",[]],[\"invoke\",211,0,\"as-memory.grow-size\",[]],[\"file\",\"store.wast\"],[\"module\",3,37],[\"invoke\",44,0,\"as-block-value\",[]],[\"invoke\",45,0,\"as-loop-value\",[]],[\"invoke\",47,0,\"as-br-value\",[]],[\"invoke\",48,0,\"as-br_if-value\",[]],[\"invoke\",49,0,\"as-br_if-value-cond\",[]],[\"invoke\",50,0,\"as-br_table-value\",[]],[\"invoke\",52,0,\"as-return-value\",[]],[\"invoke\",54,0,\"as-if-then\",[]],[\"invoke\",55,0,\"as-if-else\",[]],[\"file\",\"memory.wast\"],[\"module\",3,38],[\"module\",4,39],[\"module\",5,40],[\"module\",6,41],[\"module\",7,42],[\"module\",8,43],[\"module\",13,44],[\"invoke\",14,0,\"memsize\",[]],[\"module\",15,44],[\"invoke\",16,0,\"memsize\",[]],[\"module\",17,45],[\"invoke\",18,0,\"memsize\",[]],[\"module\",92,46],[\"invoke\",180,0,\"data\",[]],[\"invoke\",181,0,\"cast\",[]],[\"invoke\",183,0,\"i32_load8_s\",[\"i32:4294967295\"]],[\"invoke\",184,0,\"i32_load8_u\",[\"i32:4294967295\"]],[\"invoke\",185,0,\"i32_load16_s\",[\"i32:4294967295\"]],[\"invoke\",186,0,\"i32_load16_u\",[\"i32:4294967295\"]],[\"invoke\",188,0,\"i32_load8_s\",[\"i32:100\"]],[\"invoke\",189,0,\"i32_load8_u\",[\"i32:200\"]],[\"invoke\",190,0,\"i32_load16_s\",[\"i32:20000\"]],[\"invoke\",191,0,\"i32_load16_u\",[\"i32:40000\"]],[\"invoke\",193,0,\"i32_load8_s\",[\"i32:4275856707\"]],[\"invoke\",194,0,\"i32_load8_s\",[\"i32:878104047\"]],[\"invoke\",195,0,\"i32_load8_u\",[\"i32:4275856707\"]],[\"invoke\",196,0,\"i32_load8_u\",[\"i32:878104047\"]],[\"invoke\",197,0,\"i32_load16_s\",[\"i32:4275856707\"]],[\"invoke\",198,0,\"i32_load16_s\",[\"i32:878104047\"]],[\"invoke\",199,0,\"i32_load16_u\",[\"i32:4275856707\"]],[\"invoke\",200,0,\"i32_load16_u\",[\"i32:878104047\"]],[\"invoke\",202,0,\"i64_load8_s\",[\"i64:18446744073709551615\"]],[\"invoke\",203,0,\"i64_load8_u\",[\"i64:18446744073709551615\"]],[\"invoke\",204,0,\"i64_load16_s\",[\"i64:18446744073709551615\"]],[\"invoke\",205,0,\"i64_load16_u\",[\"i64:18446744073709551615\"]],[\"invoke\",206,0,\"i64_load32_s\",[\"i64:18446744073709551615\"]],[\"invoke\",207,0,\"i64_load32_u\",[\"i64:18446744073709551615\"]],[\"invoke\",209,0,\"i64_load8_s\",[\"i64:100\"]],[\"invoke\",210,0,\"i64_load8_u\",[\"i64:200\"]],[\"invoke\",211,0,\"i64_load16_s\",[\"i64:20000\"]],[\"invoke\",212,0,\"i64_load16_u\",[\"i64:40000\"]],[\"invoke\",213,0,\"i64_load32_s\",[\"i64:20000\"]],[\"invoke\",214,0,\"i64_load32_u\",[\"i64:40000\"]],[\"invoke\",216,0,\"i64_load8_s\",[\"i64:18364758543954109763\"]],[\"invoke\",217,0,\"i64_load8_s\",[\"i64:3771275841602506223\"]],[\"invoke\",218,0,\"i64_load8_u\",[\"i64:18364758543954109763\"]],[\"invoke\",219,0,\"i64_load8_u\",[\"i64:3771275841602506223\"]],[\"invoke\",220,0,\"i64_load16_s\",[\"i64:18364758543954109763\"]],[\"invoke\",221,0,\"i64_load16_s\",[\"i64:3771275841602506223\"]],[\"invoke\",222,0,\"i64_load16_u\",[\"i64:18364758543954109763\"]],[\"invoke\",223,0,\"i64_load16_u\",[\"i64:3771275841602506223\"]],[\"invoke\",224,0,\"i64_load32_s\",[\"i64:18364758543954109763\"]],[\"invoke\",225,0,\"i64_load32_s\",[\"i64:3771275841602506223\"]],[\"invoke\",226,0,\"i64_load32_u\",[\"i64:18364758543954109763\"]],[\"invoke\",227,0,\"i64_load32_u\",[\"i64:3771275841602506223\"]],[\"module\",246,47],[\"invoke\",260,0,\"load\",[\"i32:0\"]],[\"invoke\",261,0,\"load\",[\"i32:10000\"]],[\"invoke\",262,0,\"load\",[\"i32:20000\"]],[\"invoke\",263,0,\"load\",[\"i32:30000\"]],[\"invoke\",264,0,\"load\",[\"i32:40000\"]],[\"invoke\",265,0,\"load\",[\"i32:50000\"]],[\"invoke\",266,0,\"load\",[\"i32:60000\"]],[\"invoke\",267,0,\"load\",[\"i32:65535\"]],[\"file\",\"memory_grow.wast\"],[\"module\",1,48],[\"invoke\",14,0,\"size\",[]],[\"invoke\",15,0,\"store_at_zero\",[]],[\"invoke\",16,0,\"load_at_zero\",[]],[\"invoke\",17,0,\"store_at_page_size\",[]],[\"invoke\",18,0,\"load_at_page_size\",[]],[\"invoke\",19,0,\"grow\",[\"i32:1\"]],[\"invoke\",20,0,\"size\",[]],[\"invoke\",21,0,\"load_at_zero\",[]],[\"invoke\",22,0,\"store_at_zero\",[]],[\"invoke\",23,0,\"load_at_zero\",[]],[\"invoke\",24,0,\"store_at_page_size\",[]],[\"invoke\",25,0,\"load_at_page_size\",[]],[\"invoke\",26,0,\"grow\",[\"i32:4\"]],[\"invoke\",27,0,\"size\",[]],[\"invoke\",28,0,\"load_at_zero\",[]],[\"invoke\",29,0,\"store_at_zero\",[]],[\"invoke\",30,0,\"load_at_zero\",[]],[\"invoke\",31,0,\"load_at_page_size\",[]],[\"invoke\",32,0,\"store_at_page_size\",[]],[\"invoke\",33,0,\"load_at_page_size\",[]],[\"module\",36,49],[\"invoke\",41,0,\"grow\",[\"i32:0\"]],[\"invoke\",42,0,\"grow\",[\"i32:1\"]],[\"invoke\",43,0,\"grow\",[\"i32:0\"]],[\"invoke\",44,0,\"grow\",[\"i32:2\"]],[\"invoke\",45,0,\"grow\",[\"i32:800\"]],[\"invoke\",46,0,\"grow\",[\"i32:65536\"]],[\"invoke\",47,0,\"grow\",[\"i32:64736\"]],[\"invoke\",48,0,\"grow\",[\"i32:1\"]],[\"module\",50,50],[\"invoke\",55,0,\"grow\",[\"i32:0\"]],[\"invoke\",56,0,\"grow\",[\"i32:1\"]],[\"invoke\",57,0,\"grow\",[\"i32:1\"]],[\"invoke\",58,0,\"grow\",[\"i32:2\"]],[\"invoke\",59,0,\"grow\",[\"i32:6\"]],[\"invoke\",60,0,\"grow\",[\"i32:0\"]],[\"invoke\",61,0,\"grow\",[\"i32:1\"]],[\"invoke\",62,0,\"grow\",[\"i32:65536\"]],[\"module\",66,51],[\"invoke\",87,0,\"check-memory-zero\",[\"i32:0\",\"i32:65535\"]],[\"invoke\",88,0,\"grow\",[\"i32:1\"]],[\"invoke\",89,0,\"check-memory-zero\",[\"i32:65536\",\"i32:131071\"]],[\"invoke\",90,0,\"grow\",[\"i32:1\"]],[\"invoke\",91,0,\"check-memory-zero\",[\"i32:131072\",\"i32:196607\"]],[\"invoke\",92,0,\"grow\",[\"i32:1\"]],[\"invoke\",93,0,\"check-memory-zero\",[\"i32:196608\",\"i32:262143\"]],[\"invoke\",94,0,\"grow\",[\"i32:1\"]],[\"invoke\",95,0,\"check-memory-zero\",[\"i32:262144\",\"i32:327679\"]],[\"invoke\",96,0,\"grow\",[\"i32:1\"]],[\"invoke\",97,0,\"check-memory-zero\",[\"i32:327680\",\"i32:393215\"]],[\"module\",101,52],[\"invoke\",259,0,\"as-br-value\",[]],[\"invoke\",261,0,\"as-br_if-cond\",[]],[\"invoke\",262,0,\"as-br_if-value\",[]],[\"invoke\",263,0,\"as-br_if-value-cond\",[]],[\"invoke\",265,0,\"as-br_table-index\",[]],[\"invoke\",266,0,\"as-br_table-value\",[]],[\"invoke\",267,0,\"as-br_table-value-index\",[]],[\"invoke\",269,0,\"as-return-value\",[]],[\"invoke\",271,0,\"as-if-cond\",[]],[\"invoke\",272,0,\"as-if-then\",[]],[\"invoke\",273,0,\"as-if-else\",[]],[\"invoke\",275,0,\"as-select-first\",[\"i32:0\",\"i32:1\"]],[\"invoke\",276,0,\"as-select-second\",[\"i32:0\",\"i32:0\"]],[\"invoke\",277,0,\"as-select-cond\",[]],[\"invoke\",279,0,\"as-call-first\",[]],[\"invoke\",280,0,\"as-call-mid\",[]],[\"invoke\",281,0,\"as-call-last\",[]],[\"invoke\",283,0,\"as-call_indirect-first\",[]],[\"invoke\",284,0,\"as-call_indirect-mid\",[]],[\"invoke\",285,0,\"as-call_indirect-last\",[]],[\"invoke\",286,0,\"as-call_indirect-index\",[]],[\"invoke\",288,0,\"as-local.set-value\",[]],[\"invoke\",289,0,\"as-local.tee-value\",[]],[\"invoke\",290,0,\"as-global.set-value\",[]],[\"invoke\",292,0,\"as-load-address\",[]],[\"invoke\",293,0,\"as-loadN-address\",[]],[\"invoke\",294,0,\"as-store-address\",[]],[\"invoke\",295,0,\"as-store-value\",[]],[\"invoke\",296,0,\"as-storeN-address\",[]],[\"invoke\",297,0,\"as-storeN-value\",[]],[\"invoke\",299,0,\"as-unary-operand\",[]],[\"invoke\",301,0,\"as-binary-left\",[]],[\"invoke\",302,0,\"as-binary-right\",[]],[\"invoke\",304,0,\"as-test-operand\",[]],[\"invoke\",306,0,\"as-compare-left\",[]],[\"invoke\",307,0,\"as-compare-right\",[]],[\"invoke\",309,0,\"as-memory.grow-size\",[]],[\"module\",312,53,\"$Mgm\"],[\"register\",\"grown-memory\",\"$Mgm\"],[\"invoke\",317,\"$Mgm\",\"grow\",[]],[\"module\",318,54,\"$Mgim1\"],[\"register\",\"grown-imported-memory\",\"$Mgim1\"],[\"invoke\",324,\"$Mgim1\",\"grow\",[]],[\"module\",325,55,\"$Mgim2\"],[\"invoke\",330,\"$Mgim2\",\"size\",[]],[\"file\",\"memory_redundancy.wast\"],[\"module\",5,56],[\"invoke\",59,0,\"test_store_to_load\",[]],[\"invoke\",60,0,\"zero_everything\",[]],[\"invoke\",61,0,\"test_redundant_load\",[]],[\"invoke\",62,0,\"zero_everything\",[]],[\"invoke\",63,0,\"test_dead_store\",[]],[\"invoke\",64,0,\"zero_everything\",[]],[\"invoke\",65,0,\"malloc_aliasing\",[]],[\"file\",\"memory_size.wast\"],[\"module\",1,57],[\"invoke\",7,0,\"size\",[]],[\"invoke\",8,0,\"grow\",[\"i32:1\"]],[\"invoke\",9,0,\"size\",[]],[\"invoke\",10,0,\"grow\",[\"i32:4\"]],[\"invoke\",11,0,\"size\",[]],[\"invoke\",12,0,\"grow\",[\"i32:0\"]],[\"invoke\",13,0,\"size\",[]],[\"module\",15,58],[\"invoke\",21,0,\"size\",[]],[\"invoke\",22,0,\"grow\",[\"i32:1\"]],[\"invoke\",23,0,\"size\",[]],[\"invoke\",24,0,\"grow\",[\"i32:4\"]],[\"invoke\",25,0,\"size\",[]],[\"invoke\",26,0,\"grow\",[\"i32:0\"]],[\"invoke\",27,0,\"size\",[]],[\"module\",29,59],[\"invoke\",35,0,\"size\",[]],[\"invoke\",36,0,\"grow\",[\"i32:3\"]],[\"invoke\",37,0,\"size\",[]],[\"invoke\",38,0,\"grow\",[\"i32:1\"]],[\"invoke\",39,0,\"size\",[]],[\"invoke\",40,0,\"grow\",[\"i32:0\"]],[\"invoke\",41,0,\"size\",[]],[\"invoke\",42,0,\"grow\",[\"i32:4\"]],[\"invoke\",43,0,\"size\",[]],[\"invoke\",44,0,\"grow\",[\"i32:1\"]],[\"invoke\",45,0,\"size\",[]],[\"module\",47,60],[\"invoke\",53,0,\"size\",[]],[\"invoke\",54,0,\"grow\",[\"i32:1\"]],[\"invoke\",55,0,\"size\",[]],[\"invoke\",56,0,\"grow\",[\"i32:3\"]],[\"invoke\",57,0,\"size\",[]],[\"invoke\",58,0,\"grow\",[\"i32:0\"]],[\"invoke\",59,0,\"size\",[]],[\"invoke\",60,0,\"grow\",[\"i32:2\"]],[\"invoke\",61,0,\"size\",[]],[\"invoke\",62,0,\"grow\",[\"i32:1\"]],[\"invoke\",63,0,\"size\",[]],[\"file\",\"memory_trap.wast\"],[\"module\",1,61],[\"invoke\",21,0,\"store\",[\"i32:4294967292\",\"i32:42\"]],[\"invoke\",22,0,\"load\",[\"i32:4294967292\"]],[\"invoke\",23,0,\"store\",[\"i32:4294967293\",\"i32:305419896\"]],[\"invoke\",24,0,\"load\",[\"i32:4294967293\"]],[\"invoke\",25,0,\"store\",[\"i32:4294967294\",\"i32:13\"]],[\"invoke\",26,0,\"load\",[\"i32:4294967294\"]],[\"invoke\",27,0,\"store\",[\"i32:4294967295\",\"i32:13\"]],[\"invoke\",28,0,\"load\",[\"i32:4294967295\"]],[\"invoke\",29,0,\"store\",[\"i32:0\",\"i32:13\"]],[\"invoke\",30,0,\"load\",[\"i32:0\"]],[\"invoke\",31,0,\"store\",[\"i32:2147483648\",\"i32:13\"]],[\"invoke\",32,0,\"load\",[\"i32:2147483648\"]],[\"invoke\",33,0,\"memory.grow\",[\"i32:65537\"]],[\"module\",35,62],[\"invoke\",111,0,\"i32.store\",[\"i32:65536\",\"i32:0\"]],[\"invoke\",112,0,\"i32.store\",[\"i32:65535\",\"i32:0\"]],[\"invoke\",113,0,\"i32.store\",[\"i32:65534\",\"i32:0\"]],[\"invoke\",114,0,\"i32.store\",[\"i32:65533\",\"i32:0\"]],[\"invoke\",115,0,\"i32.store\",[\"i32:4294967295\",\"i32:0\"]],[\"invoke\",116,0,\"i32.store\",[\"i32:4294967294\",\"i32:0\"]],[\"invoke\",117,0,\"i32.store\",[\"i32:4294967293\",\"i32:0\"]],[\"invoke\",118,0,\"i32.store\",[\"i32:4294967292\",\"i32:0\"]],[\"invoke\",119,0,\"i64.store\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",120,0,\"i64.store\",[\"i32:65535\",\"i64:0\"]],[\"invoke\",121,0,\"i64.store\",[\"i32:65534\",\"i64:0\"]],[\"invoke\",122,0,\"i64.store\",[\"i32:65533\",\"i64:0\"]],[\"invoke\",123,0,\"i64.store\",[\"i32:65532\",\"i64:0\"]],[\"invoke\",124,0,\"i64.store\",[\"i32:65531\",\"i64:0\"]],[\"invoke\",125,0,\"i64.store\",[\"i32:65530\",\"i64:0\"]],[\"invoke\",126,0,\"i64.store\",[\"i32:65529\",\"i64:0\"]],[\"invoke\",127,0,\"i64.store\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",128,0,\"i64.store\",[\"i32:4294967294\",\"i64:0\"]],[\"invoke\",129,0,\"i64.store\",[\"i32:4294967293\",\"i64:0\"]],[\"invoke\",130,0,\"i64.store\",[\"i32:4294967292\",\"i64:0\"]],[\"invoke\",131,0,\"i64.store\",[\"i32:4294967291\",\"i64:0\"]],[\"invoke\",132,0,\"i64.store\",[\"i32:4294967290\",\"i64:0\"]],[\"invoke\",133,0,\"i64.store\",[\"i32:4294967289\",\"i64:0\"]],[\"invoke\",134,0,\"i64.store\",[\"i32:4294967288\",\"i64:0\"]],[\"invoke\",135,0,\"f32.store\",[\"i32:65536\",\"f32:0\"]],[\"invoke\",136,0,\"f32.store\",[\"i32:65535\",\"f32:0\"]],[\"invoke\",137,0,\"f32.store\",[\"i32:65534\",\"f32:0\"]],[\"invoke\",138,0,\"f32.store\",[\"i32:65533\",\"f32:0\"]],[\"invoke\",139,0,\"f32.store\",[\"i32:4294967295\",\"f32:0\"]],[\"invoke\",140,0,\"f32.store\",[\"i32:4294967294\",\"f32:0\"]],[\"invoke\",141,0,\"f32.store\",[\"i32:4294967293\",\"f32:0\"]],[\"invoke\",142,0,\"f32.store\",[\"i32:4294967292\",\"f32:0\"]],[\"invoke\",143,0,\"f64.store\",[\"i32:65536\",\"f64:0\"]],[\"invoke\",144,0,\"f64.store\",[\"i32:65535\",\"f64:0\"]],[\"invoke\",145,0,\"f64.store\",[\"i32:65534\",\"f64:0\"]],[\"invoke\",146,0,\"f64.store\",[\"i32:65533\",\"f64:0\"]],[\"invoke\",147,0,\"f64.store\",[\"i32:65532\",\"f64:0\"]],[\"invoke\",148,0,\"f64.store\",[\"i32:65531\",\"f64:0\"]],[\"invoke\",149,0,\"f64.store\",[\"i32:65530\",\"f64:0\"]],[\"invoke\",150,0,\"f64.store\",[\"i32:65529\",\"f64:0\"]],[\"invoke\",151,0,\"f64.store\",[\"i32:4294967295\",\"f64:0\"]],[\"invoke\",152,0,\"f64.store\",[\"i32:4294967294\",\"f64:0\"]],[\"invoke\",153,0,\"f64.store\",[\"i32:4294967293\",\"f64:0\"]],[\"invoke\",154,0,\"f64.store\",[\"i32:4294967292\",\"f64:0\"]],[\"invoke\",155,0,\"f64.store\",[\"i32:4294967291\",\"f64:0\"]],[\"invoke\",156,0,\"f64.store\",[\"i32:4294967290\",\"f64:0\"]],[\"invoke\",157,0,\"f64.store\",[\"i32:4294967289\",\"f64:0\"]],[\"invoke\",158,0,\"f64.store\",[\"i32:4294967288\",\"f64:0\"]],[\"invoke\",159,0,\"i32.store8\",[\"i32:65536\",\"i32:0\"]],[\"invoke\",160,0,\"i32.store8\",[\"i32:4294967295\",\"i32:0\"]],[\"invoke\",161,0,\"i32.store16\",[\"i32:65536\",\"i32:0\"]],[\"invoke\",162,0,\"i32.store16\",[\"i32:65535\",\"i32:0\"]],[\"invoke\",163,0,\"i32.store16\",[\"i32:4294967295\",\"i32:0\"]],[\"invoke\",164,0,\"i32.store16\",[\"i32:4294967294\",\"i32:0\"]],[\"invoke\",165,0,\"i64.store8\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",166,0,\"i64.store8\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",167,0,\"i64.store16\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",168,0,\"i64.store16\",[\"i32:65535\",\"i64:0\"]],[\"invoke\",169,0,\"i64.store16\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",170,0,\"i64.store16\",[\"i32:4294967294\",\"i64:0\"]],[\"invoke\",171,0,\"i64.store32\",[\"i32:65536\",\"i64:0\"]],[\"invoke\",172,0,\"i64.store32\",[\"i32:65535\",\"i64:0\"]],[\"invoke\",173,0,\"i64.store32\",[\"i32:65534\",\"i64:0\"]],[\"invoke\",174,0,\"i64.store32\",[\"i32:65533\",\"i64:0\"]],[\"invoke\",175,0,\"i64.store32\",[\"i32:4294967295\",\"i64:0\"]],[\"invoke\",176,0,\"i64.store32\",[\"i32:4294967294\",\"i64:0\"]],[\"invoke\",177,0,\"i64.store32\",[\"i32:4294967293\",\"i64:0\"]],[\"invoke\",178,0,\"i64.store32\",[\"i32:4294967292\",\"i64:0\"]],[\"invoke\",179,0,\"i32.load\",[\"i32:65536\"]],[\"invoke\",180,0,\"i32.load\",[\"i32:65535\"]],[\"invoke\",181,0,\"i32.load\",[\"i32:65534\"]],[\"invoke\",182,0,\"i32.load\",[\"i32:65533\"]],[\"invoke\",183,0,\"i32.load\",[\"i32:4294967295\"]],[\"invoke\",184,0,\"i32.load\",[\"i32:4294967294\"]],[\"invoke\",185,0,\"i32.load\",[\"i32:4294967293\"]],[\"invoke\",186,0,\"i32.load\",[\"i32:4294967292\"]],[\"invoke\",187,0,\"i64.load\",[\"i32:65536\"]],[\"invoke\",188,0,\"i64.load\",[\"i32:65535\"]],[\"invoke\",189,0,\"i64.load\",[\"i32:65534\"]],[\"invoke\",190,0,\"i64.load\",[\"i32:65533\"]],[\"invoke\",191,0,\"i64.load\",[\"i32:65532\"]],[\"invoke\",192,0,\"i64.load\",[\"i32:65531\"]],[\"invoke\",193,0,\"i64.load\",[\"i32:65530\"]],[\"invoke\",194,0,\"i64.load\",[\"i32:65529\"]],[\"invoke\",195,0,\"i64.load\",[\"i32:4294967295\"]],[\"invoke\",196,0,\"i64.load\",[\"i32:4294967294\"]],[\"invoke\",197,0,\"i64.load\",[\"i32:4294967293\"]],[\"invoke\",198,0,\"i64.load\",[\"i32:4294967292\"]],[\"invoke\",199,0,\"i64.load\",[\"i32:4294967291\"]],[\"invoke\",200,0,\"i64.load\",[\"i32:4294967290\"]],[\"invoke\",201,0,\"i64.load\",[\"i32:4294967289\"]],[\"invoke\",202,0,\"i64.load\",[\"i32:4294967288\"]],[\"invoke\",203,0,\"f32.load\",[\"i32:65536\"]],[\"invoke\",204,0,\"f32.load\",[\"i32:65535\"]],[\"invoke\",205,0,\"f32.load\",[\"i32:65534\"]],[\"invoke\",206,0,\"f32.load\",[\"i32:65533\"]],[\"invoke\",207,0,\"f32.load\",[\"i32:4294967295\"]],[\"invoke\",208,0,\"f32.load\",[\"i32:4294967294\"]],[\"invoke\",209,0,\"f32.load\",[\"i32:4294967293\"]],[\"invoke\",210,0,\"f32.load\",[\"i32:4294967292\"]],[\"invoke\",211,0,\"f64.load\",[\"i32:65536\"]],[\"invoke\",212,0,\"f64.load\",[\"i32:65535\"]],[\"invoke\",213,0,\"f64.load\",[\"i32:65534\"]],[\"invoke\",214,0,\"f64.load\",[\"i32:65533\"]],[\"invoke\",215,0,\"f64.load\",[\"i32:65532\"]],[\"invoke\",216,0,\"f64.load\",[\"i32:65531\"]],[\"invoke\",217,0,\"f64.load\",[\"i32:65530\"]],[\"invoke\",218,0,\"f64.load\",[\"i32:65529\"]],[\"invoke\",219,0,\"f64.load\",[\"i32:4294967295\"]],[\"invoke\",220,0,\"f64.load\",[\"i32:4294967294\"]],[\"invoke\",221,0,\"f64.load\",[\"i32:4294967293\"]],[\"invoke\",222,0,\"f64.load\",[\"i32:4294967292\"]],[\"invoke\",223,0,\"f64.load\",[\"i32:4294967291\"]],[\"invoke\",224,0,\"f64.load\",[\"i32:4294967290\"]],[\"invoke\",225,0,\"f64.load\",[\"i32:4294967289\"]],[\"invoke\",226,0,\"f64.load\",[\"i32:4294967288\"]],[\"invoke\",227,0,\"i32.load8_s\",[\"i32:65536\"]],[\"invoke\",228,0,\"i32.load8_s\",[\"i32:4294967295\"]],[\"invoke\",229,0,\"i32.load8_u\",[\"i32:65536\"]],[\"invoke\",230,0,\"i32.load8_u\",[\"i32:4294967295\"]],[\"invoke\",231,0,\"i32.load16_s\",[\"i32:65536\"]],[\"invoke\",232,0,\"i32.load16_s\",[\"i32:65535\"]],[\"invoke\",233,0,\"i32.load16_s\",[\"i32:4294967295\"]],[\"invoke\",234,0,\"i32.load16_s\",[\"i32:4294967294\"]],[\"invoke\",235,0,\"i32.load16_u\",[\"i32:65536\"]],[\"invoke\",236,0,\"i32.load16_u\",[\"i32:65535\"]],[\"invoke\",237,0,\"i32.load16_u\",[\"i32:4294967295\"]],[\"invoke\",238,0,\"i32.load16_u\",[\"i32:4294967294\"]],[\"invoke\",239,0,\"i64.load8_s\",[\"i32:65536\"]],[\"invoke\",240,0,\"i64.load8_s\",[\"i32:4294967295\"]],[\"invoke\",241,0,\"i64.load8_u\",[\"i32:65536\"]],[\"invoke\",242,0,\"i64.load8_u\",[\"i32:4294967295\"]],[\"invoke\",243,0,\"i64.load16_s\",[\"i32:65536\"]],[\"invoke\",244,0,\"i64.load16_s\",[\"i32:65535\"]],[\"invoke\",245,0,\"i64.load16_s\",[\"i32:4294967295\"]],[\"invoke\",246,0,\"i64.load16_s\",[\"i32:4294967294\"]],[\"invoke\",247,0,\"i64.load16_u\",[\"i32:65536\"]],[\"invoke\",248,0,\"i64.load16_u\",[\"i32:65535\"]],[\"invoke\",249,0,\"i64.load16_u\",[\"i32:4294967295\"]],[\"invoke\",250,0,\"i64.load16_u\",[\"i32:4294967294\"]],[\"invoke\",251,0,\"i64.load32_s\",[\"i32:65536\"]],[\"invoke\",252,0,\"i64.load32_s\",[\"i32:65535\"]],[\"invoke\",253,0,\"i64.load32_s\",[\"i32:65534\"]],[\"invoke\",254,0,\"i64.load32_s\",[\"i32:65533\"]],[\"invoke\",255,0,\"i64.load32_s\",[\"i32:4294967295\"]],[\"invoke\",256,0,\"i64.load32_s\",[\"i32:4294967294\"]],[\"invoke\",257,0,\"i64.load32_s\",[\"i32:4294967293\"]],[\"invoke\",258,0,\"i64.load32_s\",[\"i32:4294967292\"]],[\"invoke\",259,0,\"i64.load32_u\",[\"i32:65536\"]],[\"invoke\",260,0,\"i64.load32_u\",[\"i32:65535\"]],[\"invoke\",261,0,\"i64.load32_u\",[\"i32:65534\"]],[\"invoke\",262,0,\"i64.load32_u\",[\"i32:65533\"]],[\"invoke\",263,0,\"i64.load32_u\",[\"i32:4294967295\"]],[\"invoke\",264,0,\"i64.load32_u\",[\"i32:4294967294\"]],[\"invoke\",265,0,\"i64.load32_u\",[\"i32:4294967293\"]],[\"invoke\",266,0,\"i64.load32_u\",[\"i32:4294967292\"]],[\"invoke\",269,0,\"i64.load\",[\"i32:65528\"]],[\"invoke\",270,0,\"i64.load\",[\"i32:0\"]],[\"invoke\",274,0,\"i64.store\",[\"i32:65528\",\"i64:0\"]],[\"invoke\",275,0,\"i32.store\",[\"i32:65533\",\"i32:305419896\"]],[\"invoke\",276,0,\"i32.load\",[\"i32:65532\"]],[\"invoke\",277,0,\"i64.store\",[\"i32:65529\",\"i64:1311768467294899695\"]],[\"invoke\",278,0,\"i64.load\",[\"i32:65528\"]],[\"invoke\",279,0,\"f32.store\",[\"i32:65533\",\"f32:1301390004\"]],[\"invoke\",280,0,\"f32.load\",[\"i32:65532\"]],[\"invoke\",281,0,\"f64.store\",[\"i32:65529\",\"f64:4878018892390247374\"]],[\"invoke\",282,0,\"f64.load\",[\"i32:65528\"]],[\"file\",\"bulk.wast\"],[\"module\",2,63],[\"module\",6,64],[\"module\",13,65],[\"invoke\",27,0,\"fill\",[\"i32:1\",\"i32:255\",\"i32:3\"]],[\"invoke\",28,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",29,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",30,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",31,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",32,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",35,0,\"fill\",[\"i32:0\",\"i32:48042\",\"i32:2\"]],[\"invoke\",36,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",37,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",40,0,\"fill\",[\"i32:0\",\"i32:0\",\"i32:65536\"]],[\"invoke\",43,0,\"fill\",[\"i32:65280\",\"i32:1\",\"i32:257\"]],[\"invoke\",45,0,\"load8_u\",[\"i32:65280\"]],[\"invoke\",46,0,\"load8_u\",[\"i32:65535\"]],[\"invoke\",49,0,\"fill\",[\"i32:65536\",\"i32:0\",\"i32:0\"]],[\"invoke\",52,0,\"fill\",[\"i32:65537\",\"i32:0\",\"i32:0\"]],[\"module\",57,66],[\"invoke\",71,0,\"copy\",[\"i32:10\",\"i32:0\",\"i32:4\"]],[\"invoke\",73,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",74,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",75,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",76,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",77,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",78,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",81,0,\"copy\",[\"i32:8\",\"i32:10\",\"i32:4\"]],[\"invoke\",82,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",83,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",84,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",85,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",86,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",87,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",90,0,\"copy\",[\"i32:10\",\"i32:7\",\"i32:6\"]],[\"invoke\",91,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",92,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",93,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",94,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",95,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",96,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",97,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",100,0,\"copy\",[\"i32:65280\",\"i32:0\",\"i32:256\"]],[\"invoke\",101,0,\"copy\",[\"i32:65024\",\"i32:65280\",\"i32:256\"]],[\"invoke\",104,0,\"copy\",[\"i32:65536\",\"i32:0\",\"i32:0\"]],[\"invoke\",105,0,\"copy\",[\"i32:0\",\"i32:65536\",\"i32:0\"]],[\"invoke\",108,0,\"copy\",[\"i32:65537\",\"i32:0\",\"i32:0\"]],[\"invoke\",110,0,\"copy\",[\"i32:0\",\"i32:65537\",\"i32:0\"]],[\"module\",115,67],[\"invoke\",129,0,\"init\",[\"i32:0\",\"i32:1\",\"i32:2\"]],[\"invoke\",130,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",131,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",132,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",135,0,\"init\",[\"i32:65532\",\"i32:0\",\"i32:4\"]],[\"invoke\",138,0,\"init\",[\"i32:65534\",\"i32:0\",\"i32:3\"]],[\"invoke\",140,0,\"load8_u\",[\"i32:65534\"]],[\"invoke\",141,0,\"load8_u\",[\"i32:65535\"]],[\"invoke\",144,0,\"init\",[\"i32:65536\",\"i32:0\",\"i32:0\"]],[\"invoke\",145,0,\"init\",[\"i32:0\",\"i32:4\",\"i32:0\"]],[\"invoke\",148,0,\"init\",[\"i32:65537\",\"i32:0\",\"i32:0\"]],[\"invoke\",150,0,\"init\",[\"i32:0\",\"i32:5\",\"i32:0\"]],[\"module\",154,68],[\"invoke\",168,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",169,0,\"drop_passive\",[]],[\"invoke\",170,0,\"drop_passive\",[]],[\"invoke\",171,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",172,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",173,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",174,0,\"drop_active\",[]],[\"invoke\",175,0,\"init_active\",[\"i32:0\"]],[\"invoke\",176,0,\"init_active\",[\"i32:1\"]],[\"invoke\",177,0,\"init_active\",[\"i32:0\"]],[\"module\",181,69],[\"module\",196,70],[\"module\",199,71],[\"invoke\",219,0,\"init\",[\"i32:2\",\"i32:0\",\"i32:2\"]],[\"invoke\",221,0,\"call\",[\"i32:2\"]],[\"invoke\",224,0,\"init\",[\"i32:0\",\"i32:1\",\"i32:2\"]],[\"invoke\",225,0,\"call\",[\"i32:0\"]],[\"invoke\",226,0,\"call\",[\"i32:1\"]],[\"invoke\",227,0,\"call\",[\"i32:2\"]],[\"invoke\",230,0,\"init\",[\"i32:1\",\"i32:2\",\"i32:2\"]],[\"invoke\",233,0,\"init\",[\"i32:3\",\"i32:0\",\"i32:0\"]],[\"invoke\",234,0,\"init\",[\"i32:0\",\"i32:4\",\"i32:0\"]],[\"invoke\",237,0,\"init\",[\"i32:4\",\"i32:0\",\"i32:0\"]],[\"invoke\",239,0,\"init\",[\"i32:0\",\"i32:5\",\"i32:0\"]],[\"module\",244,72],[\"invoke\",261,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",262,0,\"drop_passive\",[]],[\"invoke\",263,0,\"drop_passive\",[]],[\"invoke\",264,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",265,0,\"init_passive\",[\"i32:1\"]],[\"invoke\",266,0,\"init_passive\",[\"i32:0\"]],[\"invoke\",267,0,\"drop_active\",[]],[\"invoke\",268,0,\"init_active\",[\"i32:0\"]],[\"invoke\",269,0,\"init_active\",[\"i32:1\"]],[\"invoke\",270,0,\"init_active\",[\"i32:0\"]],[\"module\",274,73],[\"module\",297,74],[\"module\",300,75],[\"invoke\",319,0,\"copy\",[\"i32:3\",\"i32:0\",\"i32:3\"]],[\"invoke\",321,0,\"call\",[\"i32:3\"]],[\"invoke\",322,0,\"call\",[\"i32:4\"]],[\"invoke\",323,0,\"call\",[\"i32:5\"]],[\"invoke\",326,0,\"copy\",[\"i32:0\",\"i32:1\",\"i32:3\"]],[\"invoke\",328,0,\"call\",[\"i32:0\"]],[\"invoke\",329,0,\"call\",[\"i32:1\"]],[\"invoke\",330,0,\"call\",[\"i32:2\"]],[\"invoke\",333,0,\"copy\",[\"i32:2\",\"i32:0\",\"i32:3\"]],[\"invoke\",335,0,\"call\",[\"i32:2\"]],[\"invoke\",336,0,\"call\",[\"i32:3\"]],[\"invoke\",337,0,\"call\",[\"i32:4\"]],[\"invoke\",340,0,\"copy\",[\"i32:6\",\"i32:8\",\"i32:2\"]],[\"invoke\",341,0,\"copy\",[\"i32:8\",\"i32:6\",\"i32:2\"]],[\"invoke\",344,0,\"copy\",[\"i32:10\",\"i32:0\",\"i32:0\"]],[\"invoke\",345,0,\"copy\",[\"i32:0\",\"i32:10\",\"i32:0\"]],[\"invoke\",348,0,\"copy\",[\"i32:11\",\"i32:0\",\"i32:0\"]],[\"invoke\",350,0,\"copy\",[\"i32:0\",\"i32:11\",\"i32:0\"]],[\"file\",\"memory_copy.wast\"],[\"module\",6,76],[\"invoke\",15,0,\"test\",[]],[\"invoke\",27,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",38,0,\"load8_u\",[\"i32:21\"]],[\"module\",48,77],[\"invoke\",60,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",71,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",82,0,\"load8_u\",[\"i32:23\"]],[\"module\",90,78],[\"invoke\",104,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",115,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",126,0,\"load8_u\",[\"i32:25\"]],[\"module\",132,79],[\"invoke\",147,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",158,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",169,0,\"load8_u\",[\"i32:26\"]],[\"module\",174,80],[\"invoke\",191,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",202,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",213,0,\"load8_u\",[\"i32:28\"]],[\"module\",216,81],[\"invoke\",235,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",246,0,\"load8_u\",[\"i32:19\"]],[\"module\",258,82],[\"invoke\",267,0,\"test\",[]],[\"invoke\",278,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",289,0,\"load8_u\",[\"i32:20\"]],[\"module\",300,83],[\"invoke\",311,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",322,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",333,0,\"load8_u\",[\"i32:22\"]],[\"module\",342,84],[\"invoke\",355,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",366,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",377,0,\"load8_u\",[\"i32:1014\"]],[\"invoke\",387,0,\"load8_u\",[\"i32:3004\"]],[\"invoke\",398,0,\"load8_u\",[\"i32:5193\"]],[\"invoke\",409,0,\"load8_u\",[\"i32:7382\"]],[\"invoke\",420,0,\"load8_u\",[\"i32:9571\"]],[\"invoke\",431,0,\"load8_u\",[\"i32:11760\"]],[\"invoke\",442,0,\"load8_u\",[\"i32:13949\"]],[\"invoke\",453,0,\"load8_u\",[\"i32:16138\"]],[\"invoke\",464,0,\"load8_u\",[\"i32:18327\"]],[\"invoke\",475,0,\"load8_u\",[\"i32:20516\"]],[\"invoke\",485,0,\"load8_u\",[\"i32:22506\"]],[\"invoke\",496,0,\"load8_u\",[\"i32:24695\"]],[\"invoke\",507,0,\"load8_u\",[\"i32:26884\"]],[\"invoke\",518,0,\"load8_u\",[\"i32:29073\"]],[\"invoke\",529,0,\"load8_u\",[\"i32:31262\"]],[\"invoke\",540,0,\"load8_u\",[\"i32:33451\"]],[\"invoke\",551,0,\"load8_u\",[\"i32:35640\"]],[\"invoke\",562,0,\"load8_u\",[\"i32:37829\"]],[\"invoke\",572,0,\"load8_u\",[\"i32:39819\"]],[\"invoke\",583,0,\"load8_u\",[\"i32:42008\"]],[\"invoke\",594,0,\"load8_u\",[\"i32:44197\"]],[\"invoke\",605,0,\"load8_u\",[\"i32:46386\"]],[\"invoke\",616,0,\"load8_u\",[\"i32:48575\"]],[\"invoke\",627,0,\"load8_u\",[\"i32:50764\"]],[\"invoke\",638,0,\"load8_u\",[\"i32:52953\"]],[\"invoke\",649,0,\"load8_u\",[\"i32:55142\"]],[\"invoke\",660,0,\"load8_u\",[\"i32:57331\"]],[\"invoke\",670,0,\"load8_u\",[\"i32:59321\"]],[\"invoke\",681,0,\"load8_u\",[\"i32:61510\"]],[\"invoke\",692,0,\"load8_u\",[\"i32:63699\"]],[\"module\",703,85],[\"invoke\",714,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",725,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",736,0,\"load8_u\",[\"i32:418\"]],[\"invoke\",747,0,\"load8_u\",[\"i32:2607\"]],[\"invoke\",758,0,\"load8_u\",[\"i32:4796\"]],[\"invoke\",768,0,\"load8_u\",[\"i32:6786\"]],[\"invoke\",779,0,\"load8_u\",[\"i32:8975\"]],[\"invoke\",790,0,\"load8_u\",[\"i32:11164\"]],[\"invoke\",801,0,\"load8_u\",[\"i32:13353\"]],[\"invoke\",812,0,\"load8_u\",[\"i32:15542\"]],[\"invoke\",823,0,\"load8_u\",[\"i32:17731\"]],[\"invoke\",834,0,\"load8_u\",[\"i32:19920\"]],[\"invoke\",845,0,\"load8_u\",[\"i32:22109\"]],[\"invoke\",856,0,\"load8_u\",[\"i32:24298\"]],[\"invoke\",866,0,\"load8_u\",[\"i32:26288\"]],[\"invoke\",877,0,\"load8_u\",[\"i32:28477\"]],[\"invoke\",888,0,\"load8_u\",[\"i32:30666\"]],[\"invoke\",899,0,\"load8_u\",[\"i32:32855\"]],[\"invoke\",910,0,\"load8_u\",[\"i32:35044\"]],[\"invoke\",921,0,\"load8_u\",[\"i32:37233\"]],[\"invoke\",932,0,\"load8_u\",[\"i32:39422\"]],[\"invoke\",943,0,\"load8_u\",[\"i32:41611\"]],[\"invoke\",953,0,\"load8_u\",[\"i32:43601\"]],[\"invoke\",964,0,\"load8_u\",[\"i32:45790\"]],[\"invoke\",975,0,\"load8_u\",[\"i32:47979\"]],[\"invoke\",986,0,\"load8_u\",[\"i32:50168\"]],[\"invoke\",997,0,\"load8_u\",[\"i32:52357\"]],[\"invoke\",1008,0,\"load8_u\",[\"i32:54546\"]],[\"invoke\",1019,0,\"load8_u\",[\"i32:56735\"]],[\"invoke\",1030,0,\"load8_u\",[\"i32:58924\"]],[\"invoke\",1041,0,\"load8_u\",[\"i32:61113\"]],[\"invoke\",1051,0,\"load8_u\",[\"i32:63103\"]],[\"invoke\",1062,0,\"load8_u\",[\"i32:65292\"]],[\"module\",1065,86],[\"invoke\",1084,0,\"load8_u\",[\"i32:1790\"]],[\"invoke\",1095,0,\"load8_u\",[\"i32:3979\"]],[\"invoke\",1106,0,\"load8_u\",[\"i32:6168\"]],[\"invoke\",1117,0,\"load8_u\",[\"i32:8357\"]],[\"invoke\",1128,0,\"load8_u\",[\"i32:10546\"]],[\"invoke\",1139,0,\"load8_u\",[\"i32:12735\"]],[\"invoke\",1149,0,\"load8_u\",[\"i32:14725\"]],[\"invoke\",1160,0,\"load8_u\",[\"i32:16914\"]],[\"invoke\",1171,0,\"load8_u\",[\"i32:19103\"]],[\"invoke\",1182,0,\"load8_u\",[\"i32:21292\"]],[\"invoke\",1193,0,\"load8_u\",[\"i32:23481\"]],[\"invoke\",1204,0,\"load8_u\",[\"i32:25670\"]],[\"invoke\",1215,0,\"load8_u\",[\"i32:27859\"]],[\"invoke\",1226,0,\"load8_u\",[\"i32:30048\"]],[\"invoke\",1237,0,\"load8_u\",[\"i32:32237\"]],[\"invoke\",1247,0,\"load8_u\",[\"i32:34227\"]],[\"invoke\",1258,0,\"load8_u\",[\"i32:36416\"]],[\"invoke\",1269,0,\"load8_u\",[\"i32:38605\"]],[\"invoke\",1280,0,\"load8_u\",[\"i32:40794\"]],[\"invoke\",1291,0,\"load8_u\",[\"i32:42983\"]],[\"invoke\",1302,0,\"load8_u\",[\"i32:45172\"]],[\"invoke\",1313,0,\"load8_u\",[\"i32:47361\"]],[\"invoke\",1324,0,\"load8_u\",[\"i32:49550\"]],[\"invoke\",1334,0,\"load8_u\",[\"i32:51540\"]],[\"invoke\",1345,0,\"load8_u\",[\"i32:53729\"]],[\"invoke\",1356,0,\"load8_u\",[\"i32:55918\"]],[\"invoke\",1367,0,\"load8_u\",[\"i32:58107\"]],[\"invoke\",1378,0,\"load8_u\",[\"i32:60296\"]],[\"invoke\",1389,0,\"load8_u\",[\"i32:62485\"]],[\"invoke\",1400,0,\"load8_u\",[\"i32:64674\"]],[\"invoke\",1411,0,\"load8_u\",[\"i32:65522\"]],[\"invoke\",1422,0,\"load8_u\",[\"i32:65533\"]],[\"module\",1426,87],[\"invoke\",1443,0,\"load8_u\",[\"i32:1392\"]],[\"invoke\",1454,0,\"load8_u\",[\"i32:3581\"]],[\"invoke\",1465,0,\"load8_u\",[\"i32:5770\"]],[\"invoke\",1476,0,\"load8_u\",[\"i32:7959\"]],[\"invoke\",1487,0,\"load8_u\",[\"i32:10148\"]],[\"invoke\",1498,0,\"load8_u\",[\"i32:12337\"]],[\"invoke\",1509,0,\"load8_u\",[\"i32:14526\"]],[\"invoke\",1520,0,\"load8_u\",[\"i32:16715\"]],[\"invoke\",1530,0,\"load8_u\",[\"i32:18705\"]],[\"invoke\",1541,0,\"load8_u\",[\"i32:20894\"]],[\"invoke\",1552,0,\"load8_u\",[\"i32:23083\"]],[\"invoke\",1563,0,\"load8_u\",[\"i32:25272\"]],[\"invoke\",1574,0,\"load8_u\",[\"i32:27461\"]],[\"invoke\",1585,0,\"load8_u\",[\"i32:29650\"]],[\"invoke\",1596,0,\"load8_u\",[\"i32:31839\"]],[\"invoke\",1607,0,\"load8_u\",[\"i32:34028\"]],[\"invoke\",1618,0,\"load8_u\",[\"i32:36217\"]],[\"invoke\",1628,0,\"load8_u\",[\"i32:38207\"]],[\"invoke\",1639,0,\"load8_u\",[\"i32:40396\"]],[\"invoke\",1650,0,\"load8_u\",[\"i32:42585\"]],[\"invoke\",1661,0,\"load8_u\",[\"i32:44774\"]],[\"invoke\",1672,0,\"load8_u\",[\"i32:46963\"]],[\"invoke\",1683,0,\"load8_u\",[\"i32:49152\"]],[\"invoke\",1694,0,\"load8_u\",[\"i32:51341\"]],[\"invoke\",1705,0,\"load8_u\",[\"i32:53530\"]],[\"invoke\",1715,0,\"load8_u\",[\"i32:55520\"]],[\"invoke\",1726,0,\"load8_u\",[\"i32:57709\"]],[\"invoke\",1737,0,\"load8_u\",[\"i32:59898\"]],[\"invoke\",1748,0,\"load8_u\",[\"i32:62087\"]],[\"invoke\",1759,0,\"load8_u\",[\"i32:64276\"]],[\"invoke\",1770,0,\"load8_u\",[\"i32:65519\"]],[\"invoke\",1781,0,\"load8_u\",[\"i32:65530\"]],[\"module\",1788,88],[\"invoke\",1803,0,\"load8_u\",[\"i32:994\"]],[\"invoke\",1814,0,\"load8_u\",[\"i32:3183\"]],[\"invoke\",1824,0,\"load8_u\",[\"i32:5173\"]],[\"invoke\",1835,0,\"load8_u\",[\"i32:7362\"]],[\"invoke\",1846,0,\"load8_u\",[\"i32:9551\"]],[\"invoke\",1857,0,\"load8_u\",[\"i32:11740\"]],[\"invoke\",1868,0,\"load8_u\",[\"i32:13929\"]],[\"invoke\",1879,0,\"load8_u\",[\"i32:16118\"]],[\"invoke\",1890,0,\"load8_u\",[\"i32:18307\"]],[\"invoke\",1901,0,\"load8_u\",[\"i32:20496\"]],[\"invoke\",1911,0,\"load8_u\",[\"i32:22486\"]],[\"invoke\",1922,0,\"load8_u\",[\"i32:24675\"]],[\"invoke\",1933,0,\"load8_u\",[\"i32:26864\"]],[\"invoke\",1944,0,\"load8_u\",[\"i32:29053\"]],[\"invoke\",1955,0,\"load8_u\",[\"i32:31242\"]],[\"invoke\",1966,0,\"load8_u\",[\"i32:33431\"]],[\"invoke\",1977,0,\"load8_u\",[\"i32:35620\"]],[\"invoke\",1988,0,\"load8_u\",[\"i32:37809\"]],[\"invoke\",1999,0,\"load8_u\",[\"i32:39998\"]],[\"invoke\",2009,0,\"load8_u\",[\"i32:41988\"]],[\"invoke\",2020,0,\"load8_u\",[\"i32:44177\"]],[\"invoke\",2031,0,\"load8_u\",[\"i32:46366\"]],[\"invoke\",2042,0,\"load8_u\",[\"i32:48555\"]],[\"invoke\",2053,0,\"load8_u\",[\"i32:50744\"]],[\"invoke\",2064,0,\"load8_u\",[\"i32:52933\"]],[\"invoke\",2075,0,\"load8_u\",[\"i32:55122\"]],[\"invoke\",2086,0,\"load8_u\",[\"i32:57311\"]],[\"invoke\",2096,0,\"load8_u\",[\"i32:59301\"]],[\"invoke\",2107,0,\"load8_u\",[\"i32:61490\"]],[\"invoke\",2118,0,\"load8_u\",[\"i32:63679\"]],[\"invoke\",2129,0,\"load8_u\",[\"i32:65487\"]],[\"invoke\",2140,0,\"load8_u\",[\"i32:65498\"]],[\"module\",2149,86],[\"invoke\",2162,0,\"load8_u\",[\"i32:596\"]],[\"invoke\",2173,0,\"load8_u\",[\"i32:2785\"]],[\"invoke\",2184,0,\"load8_u\",[\"i32:4974\"]],[\"invoke\",2195,0,\"load8_u\",[\"i32:7163\"]],[\"invoke\",2205,0,\"load8_u\",[\"i32:9153\"]],[\"invoke\",2216,0,\"load8_u\",[\"i32:11342\"]],[\"invoke\",2227,0,\"load8_u\",[\"i32:13531\"]],[\"invoke\",2238,0,\"load8_u\",[\"i32:15720\"]],[\"invoke\",2249,0,\"load8_u\",[\"i32:17909\"]],[\"invoke\",2260,0,\"load8_u\",[\"i32:20098\"]],[\"invoke\",2271,0,\"load8_u\",[\"i32:22287\"]],[\"invoke\",2282,0,\"load8_u\",[\"i32:24476\"]],[\"invoke\",2292,0,\"load8_u\",[\"i32:26466\"]],[\"invoke\",2303,0,\"load8_u\",[\"i32:28655\"]],[\"invoke\",2314,0,\"load8_u\",[\"i32:30844\"]],[\"invoke\",2325,0,\"load8_u\",[\"i32:33033\"]],[\"invoke\",2336,0,\"load8_u\",[\"i32:35222\"]],[\"invoke\",2347,0,\"load8_u\",[\"i32:37411\"]],[\"invoke\",2358,0,\"load8_u\",[\"i32:39600\"]],[\"invoke\",2369,0,\"load8_u\",[\"i32:41789\"]],[\"invoke\",2380,0,\"load8_u\",[\"i32:43978\"]],[\"invoke\",2390,0,\"load8_u\",[\"i32:45968\"]],[\"invoke\",2401,0,\"load8_u\",[\"i32:48157\"]],[\"invoke\",2412,0,\"load8_u\",[\"i32:50346\"]],[\"invoke\",2423,0,\"load8_u\",[\"i32:52535\"]],[\"invoke\",2434,0,\"load8_u\",[\"i32:54724\"]],[\"invoke\",2445,0,\"load8_u\",[\"i32:56913\"]],[\"invoke\",2456,0,\"load8_u\",[\"i32:59102\"]],[\"invoke\",2467,0,\"load8_u\",[\"i32:61291\"]],[\"invoke\",2477,0,\"load8_u\",[\"i32:63281\"]],[\"invoke\",2488,0,\"load8_u\",[\"i32:65470\"]],[\"invoke\",2499,0,\"load8_u\",[\"i32:65526\"]],[\"module\",2510,89],[\"invoke\",2521,0,\"load8_u\",[\"i32:198\"]],[\"invoke\",2532,0,\"load8_u\",[\"i32:2387\"]],[\"invoke\",2543,0,\"load8_u\",[\"i32:4576\"]],[\"invoke\",2554,0,\"load8_u\",[\"i32:6765\"]],[\"invoke\",2565,0,\"load8_u\",[\"i32:8954\"]],[\"invoke\",2576,0,\"load8_u\",[\"i32:11143\"]],[\"invoke\",2586,0,\"load8_u\",[\"i32:13133\"]],[\"invoke\",2597,0,\"load8_u\",[\"i32:15322\"]],[\"invoke\",2608,0,\"load8_u\",[\"i32:17511\"]],[\"invoke\",2619,0,\"load8_u\",[\"i32:19700\"]],[\"invoke\",2630,0,\"load8_u\",[\"i32:21889\"]],[\"invoke\",2641,0,\"load8_u\",[\"i32:24078\"]],[\"invoke\",2652,0,\"load8_u\",[\"i32:26267\"]],[\"invoke\",2663,0,\"load8_u\",[\"i32:28456\"]],[\"invoke\",2673,0,\"load8_u\",[\"i32:30446\"]],[\"invoke\",2684,0,\"load8_u\",[\"i32:32635\"]],[\"invoke\",2695,0,\"load8_u\",[\"i32:34824\"]],[\"invoke\",2706,0,\"load8_u\",[\"i32:37013\"]],[\"invoke\",2717,0,\"load8_u\",[\"i32:39202\"]],[\"invoke\",2728,0,\"load8_u\",[\"i32:41391\"]],[\"invoke\",2739,0,\"load8_u\",[\"i32:43580\"]],[\"invoke\",2750,0,\"load8_u\",[\"i32:45769\"]],[\"invoke\",2761,0,\"load8_u\",[\"i32:47958\"]],[\"invoke\",2771,0,\"load8_u\",[\"i32:49948\"]],[\"invoke\",2782,0,\"load8_u\",[\"i32:52137\"]],[\"invoke\",2793,0,\"load8_u\",[\"i32:54326\"]],[\"invoke\",2804,0,\"load8_u\",[\"i32:56515\"]],[\"invoke\",2815,0,\"load8_u\",[\"i32:58704\"]],[\"invoke\",2826,0,\"load8_u\",[\"i32:60893\"]],[\"invoke\",2837,0,\"load8_u\",[\"i32:63082\"]],[\"invoke\",2848,0,\"load8_u\",[\"i32:65271\"]],[\"invoke\",2858,0,\"load8_u\",[\"i32:65514\"]],[\"invoke\",2869,0,\"load8_u\",[\"i32:65525\"]],[\"module\",2871,86],[\"invoke\",2891,0,\"load8_u\",[\"i32:1989\"]],[\"invoke\",2902,0,\"load8_u\",[\"i32:4178\"]],[\"invoke\",2913,0,\"load8_u\",[\"i32:6367\"]],[\"invoke\",2924,0,\"load8_u\",[\"i32:8556\"]],[\"invoke\",2935,0,\"load8_u\",[\"i32:10745\"]],[\"invoke\",2946,0,\"load8_u\",[\"i32:12934\"]],[\"invoke\",2957,0,\"load8_u\",[\"i32:15123\"]],[\"invoke\",2967,0,\"load8_u\",[\"i32:17113\"]],[\"invoke\",2978,0,\"load8_u\",[\"i32:19302\"]],[\"invoke\",2989,0,\"load8_u\",[\"i32:21491\"]],[\"invoke\",3000,0,\"load8_u\",[\"i32:23680\"]],[\"invoke\",3011,0,\"load8_u\",[\"i32:25869\"]],[\"invoke\",3022,0,\"load8_u\",[\"i32:28058\"]],[\"invoke\",3033,0,\"load8_u\",[\"i32:30247\"]],[\"invoke\",3044,0,\"load8_u\",[\"i32:32436\"]],[\"invoke\",3054,0,\"load8_u\",[\"i32:34426\"]],[\"invoke\",3065,0,\"load8_u\",[\"i32:36615\"]],[\"invoke\",3076,0,\"load8_u\",[\"i32:38804\"]],[\"invoke\",3087,0,\"load8_u\",[\"i32:40993\"]],[\"invoke\",3098,0,\"load8_u\",[\"i32:43182\"]],[\"invoke\",3109,0,\"load8_u\",[\"i32:45371\"]],[\"invoke\",3120,0,\"load8_u\",[\"i32:47560\"]],[\"invoke\",3131,0,\"load8_u\",[\"i32:49749\"]],[\"invoke\",3142,0,\"load8_u\",[\"i32:51938\"]],[\"invoke\",3152,0,\"load8_u\",[\"i32:53928\"]],[\"invoke\",3163,0,\"load8_u\",[\"i32:56117\"]],[\"invoke\",3174,0,\"load8_u\",[\"i32:58306\"]],[\"invoke\",3185,0,\"load8_u\",[\"i32:60495\"]],[\"invoke\",3196,0,\"load8_u\",[\"i32:62684\"]],[\"invoke\",3207,0,\"load8_u\",[\"i32:64873\"]],[\"invoke\",3218,0,\"load8_u\",[\"i32:65523\"]],[\"invoke\",3229,0,\"load8_u\",[\"i32:65534\"]],[\"module\",3232,86],[\"invoke\",3250,0,\"load8_u\",[\"i32:1591\"]],[\"invoke\",3261,0,\"load8_u\",[\"i32:3780\"]],[\"invoke\",3272,0,\"load8_u\",[\"i32:5969\"]],[\"invoke\",3283,0,\"load8_u\",[\"i32:8158\"]],[\"invoke\",3294,0,\"load8_u\",[\"i32:10347\"]],[\"invoke\",3305,0,\"load8_u\",[\"i32:12536\"]],[\"invoke\",3316,0,\"load8_u\",[\"i32:14725\"]],[\"invoke\",3327,0,\"load8_u\",[\"i32:16914\"]],[\"invoke\",3338,0,\"load8_u\",[\"i32:19103\"]],[\"invoke\",3348,0,\"load8_u\",[\"i32:21093\"]],[\"invoke\",3359,0,\"load8_u\",[\"i32:23282\"]],[\"invoke\",3370,0,\"load8_u\",[\"i32:25471\"]],[\"invoke\",3381,0,\"load8_u\",[\"i32:27660\"]],[\"invoke\",3392,0,\"load8_u\",[\"i32:29849\"]],[\"invoke\",3403,0,\"load8_u\",[\"i32:32038\"]],[\"invoke\",3414,0,\"load8_u\",[\"i32:34227\"]],[\"invoke\",3425,0,\"load8_u\",[\"i32:36416\"]],[\"invoke\",3435,0,\"load8_u\",[\"i32:38406\"]],[\"invoke\",3446,0,\"load8_u\",[\"i32:40595\"]],[\"invoke\",3457,0,\"load8_u\",[\"i32:42784\"]],[\"invoke\",3468,0,\"load8_u\",[\"i32:44973\"]],[\"invoke\",3479,0,\"load8_u\",[\"i32:47162\"]],[\"invoke\",3490,0,\"load8_u\",[\"i32:49351\"]],[\"invoke\",3501,0,\"load8_u\",[\"i32:51540\"]],[\"invoke\",3512,0,\"load8_u\",[\"i32:53729\"]],[\"invoke\",3523,0,\"load8_u\",[\"i32:55918\"]],[\"invoke\",3533,0,\"load8_u\",[\"i32:57908\"]],[\"invoke\",3544,0,\"load8_u\",[\"i32:60097\"]],[\"invoke\",3555,0,\"load8_u\",[\"i32:62286\"]],[\"invoke\",3566,0,\"load8_u\",[\"i32:64475\"]],[\"invoke\",3577,0,\"load8_u\",[\"i32:65521\"]],[\"invoke\",3588,0,\"load8_u\",[\"i32:65532\"]],[\"module\",3593,90],[\"invoke\",3610,0,\"load8_u\",[\"i32:1392\"]],[\"invoke\",3621,0,\"load8_u\",[\"i32:3581\"]],[\"invoke\",3631,0,\"load8_u\",[\"i32:5571\"]],[\"invoke\",3642,0,\"load8_u\",[\"i32:7760\"]],[\"invoke\",3653,0,\"load8_u\",[\"i32:9949\"]],[\"invoke\",3664,0,\"load8_u\",[\"i32:12138\"]],[\"invoke\",3675,0,\"load8_u\",[\"i32:14327\"]],[\"invoke\",3686,0,\"load8_u\",[\"i32:16516\"]],[\"invoke\",3697,0,\"load8_u\",[\"i32:18705\"]],[\"invoke\",3708,0,\"load8_u\",[\"i32:20894\"]],[\"invoke\",3719,0,\"load8_u\",[\"i32:23083\"]],[\"invoke\",3729,0,\"load8_u\",[\"i32:25073\"]],[\"invoke\",3740,0,\"load8_u\",[\"i32:27262\"]],[\"invoke\",3751,0,\"load8_u\",[\"i32:29451\"]],[\"invoke\",3762,0,\"load8_u\",[\"i32:31640\"]],[\"invoke\",3773,0,\"load8_u\",[\"i32:33829\"]],[\"invoke\",3784,0,\"load8_u\",[\"i32:36018\"]],[\"invoke\",3795,0,\"load8_u\",[\"i32:38207\"]],[\"invoke\",3806,0,\"load8_u\",[\"i32:40396\"]],[\"invoke\",3816,0,\"load8_u\",[\"i32:42386\"]],[\"invoke\",3827,0,\"load8_u\",[\"i32:44575\"]],[\"invoke\",3838,0,\"load8_u\",[\"i32:46764\"]],[\"invoke\",3849,0,\"load8_u\",[\"i32:48953\"]],[\"invoke\",3860,0,\"load8_u\",[\"i32:51142\"]],[\"invoke\",3871,0,\"load8_u\",[\"i32:53331\"]],[\"invoke\",3882,0,\"load8_u\",[\"i32:55520\"]],[\"invoke\",3893,0,\"load8_u\",[\"i32:57709\"]],[\"invoke\",3904,0,\"load8_u\",[\"i32:59898\"]],[\"invoke\",3914,0,\"load8_u\",[\"i32:61888\"]],[\"invoke\",3925,0,\"load8_u\",[\"i32:64077\"]],[\"invoke\",3936,0,\"load8_u\",[\"i32:65519\"]],[\"invoke\",3947,0,\"load8_u\",[\"i32:65530\"]],[\"module\",3954,91],[\"invoke\",3969,0,\"load8_u\",[\"i32:994\"]],[\"invoke\",3980,0,\"load8_u\",[\"i32:3183\"]],[\"invoke\",3991,0,\"load8_u\",[\"i32:5372\"]],[\"invoke\",4002,0,\"load8_u\",[\"i32:7561\"]],[\"invoke\",4012,0,\"load8_u\",[\"i32:9551\"]],[\"invoke\",4023,0,\"load8_u\",[\"i32:11740\"]],[\"invoke\",4034,0,\"load8_u\",[\"i32:13929\"]],[\"invoke\",4045,0,\"load8_u\",[\"i32:16118\"]],[\"invoke\",4056,0,\"load8_u\",[\"i32:18307\"]],[\"invoke\",4067,0,\"load8_u\",[\"i32:20496\"]],[\"invoke\",4078,0,\"load8_u\",[\"i32:22685\"]],[\"invoke\",4089,0,\"load8_u\",[\"i32:24874\"]],[\"invoke\",4100,0,\"load8_u\",[\"i32:27063\"]],[\"invoke\",4110,0,\"load8_u\",[\"i32:29053\"]],[\"invoke\",4121,0,\"load8_u\",[\"i32:31242\"]],[\"invoke\",4132,0,\"load8_u\",[\"i32:33431\"]],[\"invoke\",4143,0,\"load8_u\",[\"i32:35620\"]],[\"invoke\",4154,0,\"load8_u\",[\"i32:37809\"]],[\"invoke\",4165,0,\"load8_u\",[\"i32:39998\"]],[\"invoke\",4176,0,\"load8_u\",[\"i32:42187\"]],[\"invoke\",4187,0,\"load8_u\",[\"i32:44376\"]],[\"invoke\",4197,0,\"load8_u\",[\"i32:46366\"]],[\"invoke\",4208,0,\"load8_u\",[\"i32:48555\"]],[\"invoke\",4219,0,\"load8_u\",[\"i32:50744\"]],[\"invoke\",4230,0,\"load8_u\",[\"i32:52933\"]],[\"invoke\",4241,0,\"load8_u\",[\"i32:55122\"]],[\"invoke\",4252,0,\"load8_u\",[\"i32:57311\"]],[\"invoke\",4263,0,\"load8_u\",[\"i32:59500\"]],[\"invoke\",4274,0,\"load8_u\",[\"i32:61441\"]],[\"invoke\",4285,0,\"load8_u\",[\"i32:61452\"]],[\"invoke\",4295,0,\"load8_u\",[\"i32:61908\"]],[\"invoke\",4306,0,\"load8_u\",[\"i32:64097\"]],[\"module\",4763,92],[\"invoke\",4786,0,\"checkRange\",[\"i32:20\",\"i32:65536\",\"i32:0\"]],[\"module\",4789,93],[\"module\",4815,94],[\"module\",4821,95],[\"module\",4827,96],[\"module\",4833,97],[\"module\",4839,98],[\"invoke\",4861,0,\"checkRange\",[\"i32:32768\",\"i32:65536\",\"i32:170\"]],[\"module\",4863,99],[\"module\",4869,100],[\"module\",4875,101],[\"module\",4881,102],[\"module\",4887,103],[\"module\",4893,104],[\"module\",4899,105],[\"invoke\",5123,0,\"checkRange\",[\"i32:2132\",\"i32:2827\",\"i32:10\"]],[\"invoke\",5145,0,\"checkRange\",[\"i32:5691\",\"i32:6552\",\"i32:83\"]],[\"invoke\",5167,0,\"checkRange\",[\"i32:10087\",\"i32:10206\",\"i32:5\"]],[\"invoke\",5189,0,\"checkRange\",[\"i32:13114\",\"i32:14133\",\"i32:59\"]],[\"invoke\",5209,0,\"checkRange\",[\"i32:15871\",\"i32:15998\",\"i32:95\"]],[\"invoke\",5231,0,\"checkRange\",[\"i32:18553\",\"i32:18744\",\"i32:42\"]],[\"invoke\",5253,0,\"checkRange\",[\"i32:21468\",\"i32:21492\",\"i32:93\"]],[\"invoke\",5275,0,\"checkRange\",[\"i32:24348\",\"i32:24515\",\"i32:92\"]],[\"invoke\",5297,0,\"checkRange\",[\"i32:27503\",\"i32:27573\",\"i32:77\"]],[\"invoke\",5319,0,\"checkRange\",[\"i32:31379\",\"i32:31403\",\"i32:57\"]],[\"invoke\",5341,0,\"checkRange\",[\"i32:33056\",\"i32:33660\",\"i32:89\"]],[\"invoke\",5363,0,\"checkRange\",[\"i32:35648\",\"i32:36547\",\"i32:83\"]],[\"invoke\",5385,0,\"checkRange\",[\"i32:39187\",\"i32:39859\",\"i32:92\"]],[\"invoke\",5405,0,\"checkRange\",[\"i32:42945\",\"i32:43115\",\"i32:77\"]],[\"invoke\",5427,0,\"checkRange\",[\"i32:45575\",\"i32:45640\",\"i32:77\"]],[\"invoke\",5449,0,\"checkRange\",[\"i32:47951\",\"i32:48632\",\"i32:100\"]],[\"invoke\",5471,0,\"checkRange\",[\"i32:50370\",\"i32:51358\",\"i32:92\"]],[\"invoke\",5493,0,\"checkRange\",[\"i32:55198\",\"i32:55389\",\"i32:42\"]],[\"invoke\",5515,0,\"checkRange\",[\"i32:58516\",\"i32:58835\",\"i32:95\"]],[\"invoke\",5537,0,\"checkRange\",[\"i32:60777\",\"i32:60834\",\"i32:76\"]],[\"invoke\",5559,0,\"checkRange\",[\"i32:63525\",\"i32:63605\",\"i32:74\"]],[\"file\",\"memory_fill.wast\"],[\"module\",6,106],[\"invoke\",22,0,\"test\",[]],[\"invoke\",24,0,\"checkRange\",[\"i32:0\",\"i32:65280\",\"i32:0\"]],[\"invoke\",26,0,\"checkRange\",[\"i32:65280\",\"i32:65536\",\"i32:85\"]],[\"module\",28,107],[\"invoke\",44,0,\"test\",[]],[\"module\",46,108],[\"invoke\",62,0,\"test\",[]],[\"module\",64,109],[\"invoke\",80,0,\"test\",[]],[\"invoke\",82,0,\"checkRange\",[\"i32:0\",\"i32:65536\",\"i32:0\"]],[\"module\",84,110],[\"invoke\",100,0,\"test\",[]],[\"module\",102,111],[\"invoke\",118,0,\"test\",[]],[\"module\",120,112],[\"invoke\",136,0,\"test\",[]],[\"invoke\",138,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"invoke\",140,0,\"checkRange\",[\"i32:1\",\"i32:65535\",\"i32:170\"]],[\"invoke\",142,0,\"checkRange\",[\"i32:65535\",\"i32:65536\",\"i32:0\"]],[\"module\",145,113],[\"invoke\",162,0,\"test\",[]],[\"invoke\",164,0,\"checkRange\",[\"i32:0\",\"i32:18\",\"i32:0\"]],[\"invoke\",166,0,\"checkRange\",[\"i32:18\",\"i32:21\",\"i32:85\"]],[\"invoke\",168,0,\"checkRange\",[\"i32:21\",\"i32:25\",\"i32:170\"]],[\"invoke\",170,0,\"checkRange\",[\"i32:25\",\"i32:28\",\"i32:85\"]],[\"invoke\",172,0,\"checkRange\",[\"i32:28\",\"i32:65536\",\"i32:0\"]],[\"module\",621,114],[\"invoke\",638,0,\"run\",[\"i32:65280\",\"i32:37\",\"i32:512\"]],[\"invoke\",641,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",643,114],[\"invoke\",660,0,\"run\",[\"i32:65279\",\"i32:37\",\"i32:514\"]],[\"invoke\",663,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",665,114],[\"invoke\",682,0,\"run\",[\"i32:65279\",\"i32:37\",\"i32:4294967295\"]],[\"invoke\",685,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"file\",\"memory_init.wast\"],[\"module\",6,115],[\"invoke\",17,0,\"test\",[]],[\"invoke\",19,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",20,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",21,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",22,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",23,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",24,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",25,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",26,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",27,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",28,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",29,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",30,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",31,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",32,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",33,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",34,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",35,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",36,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",37,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",38,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",39,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",40,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",41,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",42,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",43,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",44,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",45,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",46,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",47,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",48,0,\"load8_u\",[\"i32:29\"]],[\"module\",50,116],[\"invoke\",61,0,\"test\",[]],[\"invoke\",63,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",64,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",65,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",66,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",67,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",68,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",69,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",70,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",71,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",72,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",73,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",74,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",75,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",76,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",77,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",78,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",79,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",80,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",81,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",82,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",83,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",84,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",85,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",86,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",87,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",88,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",89,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",90,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",91,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",92,0,\"load8_u\",[\"i32:29\"]],[\"module\",94,117],[\"invoke\",105,0,\"test\",[]],[\"invoke\",107,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",108,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",109,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",110,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",111,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",112,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",113,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",114,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",115,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",116,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",117,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",118,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",119,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",120,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",121,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",122,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",123,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",124,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",125,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",126,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",127,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",128,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",129,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",130,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",131,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",132,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",133,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",134,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",135,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",136,0,\"load8_u\",[\"i32:29\"]],[\"module\",138,118],[\"invoke\",157,0,\"test\",[]],[\"invoke\",159,0,\"load8_u\",[\"i32:0\"]],[\"invoke\",160,0,\"load8_u\",[\"i32:1\"]],[\"invoke\",161,0,\"load8_u\",[\"i32:2\"]],[\"invoke\",162,0,\"load8_u\",[\"i32:3\"]],[\"invoke\",163,0,\"load8_u\",[\"i32:4\"]],[\"invoke\",164,0,\"load8_u\",[\"i32:5\"]],[\"invoke\",165,0,\"load8_u\",[\"i32:6\"]],[\"invoke\",166,0,\"load8_u\",[\"i32:7\"]],[\"invoke\",167,0,\"load8_u\",[\"i32:8\"]],[\"invoke\",168,0,\"load8_u\",[\"i32:9\"]],[\"invoke\",169,0,\"load8_u\",[\"i32:10\"]],[\"invoke\",170,0,\"load8_u\",[\"i32:11\"]],[\"invoke\",171,0,\"load8_u\",[\"i32:12\"]],[\"invoke\",172,0,\"load8_u\",[\"i32:13\"]],[\"invoke\",173,0,\"load8_u\",[\"i32:14\"]],[\"invoke\",174,0,\"load8_u\",[\"i32:15\"]],[\"invoke\",175,0,\"load8_u\",[\"i32:16\"]],[\"invoke\",176,0,\"load8_u\",[\"i32:17\"]],[\"invoke\",177,0,\"load8_u\",[\"i32:18\"]],[\"invoke\",178,0,\"load8_u\",[\"i32:19\"]],[\"invoke\",179,0,\"load8_u\",[\"i32:20\"]],[\"invoke\",180,0,\"load8_u\",[\"i32:21\"]],[\"invoke\",181,0,\"load8_u\",[\"i32:22\"]],[\"invoke\",182,0,\"load8_u\",[\"i32:23\"]],[\"invoke\",183,0,\"load8_u\",[\"i32:24\"]],[\"invoke\",184,0,\"load8_u\",[\"i32:25\"]],[\"invoke\",185,0,\"load8_u\",[\"i32:26\"]],[\"invoke\",186,0,\"load8_u\",[\"i32:27\"]],[\"invoke\",187,0,\"load8_u\",[\"i32:28\"]],[\"invoke\",188,0,\"load8_u\",[\"i32:29\"]],[\"module\",203,119],[\"invoke\",209,0,\"test\",[]],[\"module\",211,120],[\"invoke\",217,0,\"test\",[]],[\"module\",219,121],[\"invoke\",224,0,\"test\",[]],[\"module\",240,122],[\"invoke\",246,0,\"test\",[]],[\"module\",248,123],[\"invoke\",253,0,\"test\",[]],[\"module\",255,124],[\"invoke\",260,0,\"test\",[]],[\"module\",262,125],[\"invoke\",267,0,\"test\",[]],[\"module\",269,126],[\"invoke\",274,0,\"test\",[]],[\"module\",276,127],[\"invoke\",281,0,\"test\",[]],[\"module\",283,128],[\"invoke\",288,0,\"test\",[]],[\"module\",290,129],[\"invoke\",295,0,\"test\",[]],[\"module\",297,130],[\"invoke\",302,0,\"test\",[]],[\"module\",304,131],[\"invoke\",309,0,\"test\",[]],[\"module\",815,132],[\"invoke\",833,0,\"run\",[\"i32:65528\",\"i32:16\"]],[\"invoke\",836,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",838,132],[\"invoke\",856,0,\"run\",[\"i32:65527\",\"i32:16\"]],[\"invoke\",859,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",861,132],[\"invoke\",879,0,\"run\",[\"i32:65472\",\"i32:30\"]],[\"invoke\",882,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",884,132],[\"invoke\",902,0,\"run\",[\"i32:65473\",\"i32:31\"]],[\"invoke\",905,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",907,133],[\"invoke\",925,0,\"run\",[\"i32:65528\",\"i32:4294967040\"]],[\"invoke\",928,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",930,133],[\"invoke\",948,0,\"run\",[\"i32:0\",\"i32:4294967292\"]],[\"invoke\",951,0,\"checkRange\",[\"i32:0\",\"i32:1\",\"i32:0\"]],[\"module\",954,134],[\"file\",\"data.wast\"],[\"module\",5,135],[\"module\",39,136],[\"module\",43,137],[\"module\",48,138],[\"module\",56,139],[\"module\",66,140],[\"module\",71,141],[\"module\",77,140],[\"module\",82,141],[\"module\",100,142],[\"module\",105,143],[\"module\",111,144],[\"module\",116,145],[\"module\",120,146],[\"module\",125,147],[\"module\",130,148],[\"module\",135,145],[\"module\",139,146],[\"module\",144,147],[\"module\",149,149],[\"module\",154,150],[\"module\",159,151],[\"module\",165,152],[\"module\",171,153],[\"module\",176,154],[\"instantiate\",184,155],[\"instantiate\",192,156],[\"instantiate\",200,157],[\"instantiate\",207,158],[\"instantiate\",214,159],[\"instantiate\",231,160],[\"instantiate\",240,161],[\"instantiate\",247,162],[\"instantiate\",255,163],[\"instantiate\",263,164],[\"instantiate\",271,165],[\"instantiate\",278,166],[\"instantiate\",286,167],[\"instantiate\",293,168]]"; diff --git a/tests/corpus/webassembly-spec-table/data.mjs b/tests/corpus/webassembly-spec-table/data.mjs index 15dbf08aa..d6334cb9e 100644 --- a/tests/corpus/webassembly-spec-table/data.mjs +++ b/tests/corpus/webassembly-spec-table/data.mjs @@ -99,25 +99,37 @@ export const modules = [ "AGFzbQEAAAABBAFgAAADAwIAAAQEAXAACgmkAz0BAAAFcATSAAvSAAvQcAvSAQsBAAABAAQAAAEBAQAABXAE0gAL0gAL0HAL0gELAQAAAQAEAAABAQBBAAsABEEACwLSAAvQcAsAQQALAABBAAsCAAEAQQALAABBAAsCAAEAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAARBAAsC0gAL0HALAEEACwIAAABBAAsCAAAAQQALAARBAAsC0gAL0HALAEEACwIAAABBAAsCAAAEQQALAtIAC9BwCwBBAAsABEEACwLSAAvQcAsAQQALAABBAAsCAAEAQQALAABBAAsCAAEAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAABBAAsCAAAAQQALAARBAAsC0gAL0HALAEEACwIAAABBAAsCAAAAQQALAARBAAsC0gAL0HALAEEACwIAAABBAAsCAAADAAAHcATSAAvSAAvQcAvSAQsDAAADAAQAAAEBAwAAB3AE0gAL0gAL0HAL0gELAwAAAwAEAAABAQoHAgIACwIACw==", "AGFzbQEAAAABBAFgAAADAwIAAAQFAXABAwMJDwEEQQALA9IAC9BwC9IBCwoHAgIACwIACw==", "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCQcBAEEACwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAKAwIBAAkHAQBBAAsBAAoEAQIACw==", "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCR8FAEEACwEAAEEDCwEAAEEHCwEAAEEFCwEAAEEDCwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAKAwIBAAkfBQBBCQsBAABBAwsBAABBBwsBAABBAwsBAABBBQsBAAoEAQIACw==", "AGFzbQEAAAABBAFgAAACGAEIc3BlY3Rlc3QKZ2xvYmFsX2kzMgN/AAMCAQAEBQFwAOgHCQcBACMACwEACgQBAgAL", "AGFzbQEAAAABBQFgAAF/AwUEAAAAAAQEAXAACgcTAgZjYWxsLTcAAgZjYWxsLTkAAwkNAgBBBwsBAABBCQsBAQodBAUAQcEACwUAQcIACwcAQQcRAAALBwBBCREAAAs=", "AGFzbQEAAAABBQFgAAF/AwUEAAAAAAQEAXAACwcTAgZjYWxsLTcAAgZjYWxsLTkAAwkXAgRBBgsC0HAL0gALBEEJCwLSAQvQcAsKHQQFAEHBAAsFAEHCAAsHAEEHEQAACwcAQQkRAAAL", "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCQcBAEEJCwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAKAwIBAAkHAQBBCQsBAAoEAQIACw==", "AGFzbQEAAAAEBAFwAAAJBgEAQQALAA==", + "AGFzbQEAAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAACQYBAEEACwA=", "AGFzbQEAAAAEBQFwAQAACQYBAEEACwA=", "AGFzbQEAAAAEBAFwABQJBgEAQRQLAA==", + "AGFzbQEAAAABBAFgAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAAAwIBAAkHAQBBAAsBAAoEAQIACw==", + "AGFzbQEAAAABBAFgAAACFQEIc3BlY3Rlc3QFdGFibGUBcAEAZAMCAQAJBwEAQQALAQAKBAECAAs=", + "AGFzbQEAAAABBAFgAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAAAwIBAAkHAQBBAQsBAAoEAQIACw==", + "AGFzbQEAAAABBAFgAAACFQEIc3BlY3Rlc3QFdGFibGUBcAEAHgMCAQAJBwEAQQELAQAKBAECAAs=", "AGFzbQEAAAABBAFgAAADAgEABAQBcAAACQcBAEEACwEACgQBAgAL", "AGFzbQEAAAABBAFgAAADAgEABAUBcAEAAAkHAQBBAAsBAAoEAQIACw==", "AGFzbQEAAAABBAFgAAADAgEABAUBcAEAAQkHAQBBAAsBAAoEAQIACw==", "AGFzbQEAAAAEBAFwAAAJBgEAQQELAA==", "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCQcBAEEKCwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAKAwIBAAkHAQBBCgsBAAoEAQIACw==", "AGFzbQEAAAABBAFgAAADAgEABAUBcAEKFAkHAQBBCgsBAAoEAQIACw==", "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCQcBAEF/CwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAKAwIBAAkHAQBBfwsBAAoEAQIACw==", "AGFzbQEAAAABBAFgAAADAgEABAQBcAAKCQcBAEF2CwEACgQBAgAL", + "AGFzbQEAAAABBAFgAAACFAEIc3BlY3Rlc3QFdGFibGUBcAAKAwIBAAkHAQBBdgsBAAoEAQIACw==", "AGFzbQEAAAABBAFgAAADAwIAAAQEAXAACgcIAQRpbml0AAEJBwEAQQALAQAKEQICAAsMAEEAQQBBAfwMAAAL", "AGFzbQEAAAABBAFgAAADAwIAAAQEAXAACgcIAQRpbml0AAEJBQEDAAEAChECAgALDABBAEEAQQH8DAAACw==", "AGFzbQEAAAABBQFgAAF/AwQDAAAABAQBcAAKBxQBEGNhbGwtb3ZlcndyaXR0ZW4AAgkNAgBBCQsBAABBCQsBAQoVAwUAQcEACwUAQcIACwcAQQkRAAAL", + "AGFzbQEAAAABBQFgAAF/AhQBCHNwZWN0ZXN0BXRhYmxlAXAACgMEAwAAAAccARhjYWxsLW92ZXJ3cml0dGVuLWVsZW1lbnQAAgkNAgBBCQsBAABBCQsBAQoVAwUAQcEACwUAQcIACwcAQQkRAAAL", "AGFzbQEAAAABBQFgAAF/AwYFAAAAAAAEBAFwAAoHKwQMc2hhcmVkLXRhYmxlAQAGY2FsbC03AAIGY2FsbC04AAMGY2FsbC05AAQJDQIAQQgLAQAAQQkLAQEKJQUFAEHBAAsFAEHCAAsHAEEHEQAACwcAQQgRAAALBwBBCREAAAs=", "AGFzbQEAAAABBQFgAAF/AhoBB21vZHVsZTEMc2hhcmVkLXRhYmxlAXAACgMDAgAACQ0CAEEHCwEAAEEICwEBCg0CBQBBwwALBQBBxAAL", "AGFzbQEAAAABBQFgAAF/AhoBB21vZHVsZTEMc2hhcmVkLXRhYmxlAXAACgMDAgAACQ0CAEEICwEAAEEJCwEBCg0CBQBBxQALBQBBxgAL", @@ -190,4 +202,4 @@ export const modules = [ "AGFzbQEAAAABBQFgAAF/AwMCAAAEBAFwAAEFAwEAAQcxBAZtZW1vcnkCAAV0YWJsZQEADWdldCBtZW1vcnlbMF0AAAxnZXQgdGFibGVbMF0AAQoRAgcAQQAtAAALBwBBABEAAAs=", "AGFzbQEAAAABCAJgAAF/YAAAAhsCAk1zBm1lbW9yeQIAAQJNcwV0YWJsZQFwAAEDAwIAAQgBAQkHAQBBAAsBAAoMAgYAQa29AwsDAAALCwsBAEEACwVoZWxsbw==", ]; -export const script = "[[\"file\",\"table_copy.wast\"],[\"module\",6,0],[\"register\",\"a\"],[\"module\",15,1],[\"invoke\",45,0,\"test\",[]],[\"invoke\",50,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",54,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",58,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",62,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",66,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",71,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",75,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",79,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",83,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",87,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",92,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",96,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",100,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",104,0,\"check_t1\",[\"i32:28\"]],[\"module\",107,2],[\"invoke\",139,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",143,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",148,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",152,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",156,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",160,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",164,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",169,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",173,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",177,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",181,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",185,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",190,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",194,0,\"check_t1\",[\"i32:26\"]],[\"module\",199,3],[\"invoke\",229,0,\"test\",[]],[\"invoke\",233,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",237,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",241,0,\"check_t0\",[\"i32:11\"]],[\"invoke\",246,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",250,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",254,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",258,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",262,0,\"check_t1\",[\"i32:2\"]],[\"invoke\",267,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",271,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",275,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",279,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",283,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",288,0,\"check_t1\",[\"i32:28\"]],[\"module\",291,4],[\"invoke\",323,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",327,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",331,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",335,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",339,0,\"check_t0\",[\"i32:17\"]],[\"invoke\",344,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",348,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",352,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",356,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",360,0,\"check_t1\",[\"i32:8\"]],[\"invoke\",365,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",369,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",373,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",377,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",381,0,\"check_t1\",[\"i32:29\"]],[\"module\",383,5],[\"invoke\",417,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",421,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",425,0,\"check_t0\",[\"i32:11\"]],[\"invoke\",429,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",433,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",437,0,\"check_t0\",[\"i32:23\"]],[\"invoke\",442,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",446,0,\"check_t1\",[\"i32:2\"]],[\"invoke\",450,0,\"check_t1\",[\"i32:6\"]],[\"invoke\",454,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",458,0,\"check_t1\",[\"i32:14\"]],[\"invoke\",463,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",467,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",471,0,\"check_t1\",[\"i32:27\"]],[\"module\",475,6],[\"invoke\",506,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",510,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",515,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",519,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",523,0,\"check_t0\",[\"i32:17\"]],[\"invoke\",527,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",531,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",535,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",540,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",544,0,\"check_t1\",[\"i32:8\"]],[\"invoke\",548,0,\"check_t1\",[\"i32:12\"]],[\"invoke\",552,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",556,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",561,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",565,0,\"check_t1\",[\"i32:29\"]],[\"module\",567,7],[\"invoke\",600,0,\"check_t0\",[\"i32:2\"]],[\"invoke\",604,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",608,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",613,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",617,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",621,0,\"check_t0\",[\"i32:23\"]],[\"invoke\",625,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",629,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",633,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",638,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",642,0,\"check_t1\",[\"i32:14\"]],[\"invoke\",646,0,\"check_t1\",[\"i32:18\"]],[\"invoke\",650,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",654,0,\"check_t1\",[\"i32:26\"]],[\"module\",659,8],[\"invoke\",690,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",694,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",698,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",702,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",706,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",711,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",715,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",719,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",723,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",727,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",731,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",736,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",740,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",744,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",748,0,\"check_t1\",[\"i32:28\"]],[\"module\",751,9],[\"invoke\",783,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",788,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",792,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",796,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",800,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",804,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",809,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",813,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",817,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",821,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",825,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",829,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",834,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",838,0,\"check_t1\",[\"i32:26\"]],[\"module\",843,10],[\"invoke\",873,0,\"test\",[]],[\"invoke\",877,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",881,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",886,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",890,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",894,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",898,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",902,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",907,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",911,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",915,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",919,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",923,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",927,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",932,0,\"check_t1\",[\"i32:28\"]],[\"module\",935,11],[\"invoke\",967,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",971,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",975,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",979,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",984,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",988,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",992,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",996,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",1000,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",1005,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",1009,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",1013,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",1017,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",1021,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",1025,0,\"check_t1\",[\"i32:29\"]],[\"module\",1027,12],[\"invoke\",1061,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",1065,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",1069,0,\"check_t0\",[\"i32:11\"]],[\"invoke\",1073,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",1077,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",1082,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",1086,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",1090,0,\"check_t1\",[\"i32:2\"]],[\"invoke\",1094,0,\"check_t1\",[\"i32:6\"]],[\"invoke\",1098,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",1103,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",1107,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",1111,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",1115,0,\"check_t1\",[\"i32:27\"]],[\"module\",1119,13],[\"invoke\",1150,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",1154,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",1159,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",1163,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",1167,0,\"check_t0\",[\"i32:17\"]],[\"invoke\",1171,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",1175,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",1180,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",1184,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",1188,0,\"check_t1\",[\"i32:8\"]],[\"invoke\",1192,0,\"check_t1\",[\"i32:12\"]],[\"invoke\",1196,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",1201,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",1205,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",1209,0,\"check_t1\",[\"i32:29\"]],[\"module\",1211,14],[\"invoke\",1244,0,\"check_t0\",[\"i32:2\"]],[\"invoke\",1248,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",1252,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",1257,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",1261,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",1265,0,\"check_t0\",[\"i32:23\"]],[\"invoke\",1269,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",1273,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",1278,0,\"check_t1\",[\"i32:6\"]],[\"invoke\",1282,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",1286,0,\"check_t1\",[\"i32:14\"]],[\"invoke\",1290,0,\"check_t1\",[\"i32:18\"]],[\"invoke\",1294,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",1299,0,\"check_t1\",[\"i32:27\"]],[\"module\",1303,15],[\"invoke\",1334,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",1338,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",1342,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",1346,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",1350,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",1355,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",1359,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",1363,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",1367,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",1371,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",1376,0,\"check_t1\",[\"i32:12\"]],[\"invoke\",1380,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",1384,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",1388,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",1392,0,\"check_t1\",[\"i32:28\"]],[\"module\",1395,16],[\"invoke\",1428,0,\"check_t0\",[\"i32:2\"]],[\"invoke\",1432,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",1436,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",1440,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",1444,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",1448,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",1453,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",1457,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",1461,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",1465,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",1469,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",1474,0,\"check_t1\",[\"i32:18\"]],[\"invoke\",1478,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",1482,0,\"check_t1\",[\"i32:26\"]],[\"module\",1487,17],[\"invoke\",1517,0,\"test\",[]],[\"invoke\",1521,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",1526,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",1530,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",1534,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",1538,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",1542,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",1546,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",1551,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",1555,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",1559,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",1563,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",1567,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",1572,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",1576,0,\"check_t1\",[\"i32:28\"]],[\"module\",1579,18],[\"invoke\",1611,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",1615,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",1619,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",1624,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",1628,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",1632,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",1636,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",1640,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",1644,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",1649,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",1653,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",1657,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",1661,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",1665,0,\"check_t1\",[\"i32:25\"]],[\"module\",1671,19],[\"invoke\",1694,0,\"test\",[]],[\"module\",1696,20],[\"module\",1721,21],[\"module\",1746,22],[\"module\",1771,23],[\"invoke\",1794,0,\"test\",[]],[\"module\",1796,24],[\"module\",1821,25],[\"module\",1846,26],[\"module\",1871,27],[\"invoke\",1894,0,\"test\",[]],[\"module\",1896,28],[\"module\",1921,29],[\"module\",1946,30],[\"module\",1971,31],[\"invoke\",1994,0,\"test\",[]],[\"module\",1996,32],[\"module\",2021,33],[\"module\",2046,34],[\"module\",2071,35],[\"invoke\",2094,0,\"test\",[]],[\"module\",2096,36],[\"module\",2121,37],[\"module\",2146,38],[\"module\",2171,39],[\"module\",2196,40],[\"invoke\",2219,0,\"test\",[]],[\"module\",2221,41],[\"invoke\",2251,0,\"test\",[\"i32:2\"]],[\"invoke\",2255,0,\"test\",[\"i32:6\"]],[\"invoke\",2259,0,\"test\",[\"i32:10\"]],[\"invoke\",2263,0,\"test\",[\"i32:14\"]],[\"invoke\",2267,0,\"test\",[\"i32:18\"]],[\"invoke\",2272,0,\"test\",[\"i32:23\"]],[\"invoke\",2276,0,\"test\",[\"i32:27\"]],[\"invoke\",2280,0,\"test\",[\"i32:31\"]],[\"module\",2282,42],[\"invoke\",2312,0,\"test\",[\"i32:2\"]],[\"invoke\",2316,0,\"test\",[\"i32:6\"]],[\"invoke\",2321,0,\"test\",[\"i32:11\"]],[\"invoke\",2325,0,\"test\",[\"i32:15\"]],[\"invoke\",2329,0,\"test\",[\"i32:19\"]],[\"invoke\",2333,0,\"test\",[\"i32:23\"]],[\"invoke\",2337,0,\"test\",[\"i32:27\"]],[\"module\",2343,43],[\"invoke\",2369,0,\"run\",[\"i32:0\",\"i32:24\",\"i32:16\"]],[\"invoke\",2374,0,\"test\",[\"i32:3\"]],[\"invoke\",2378,0,\"test\",[\"i32:7\"]],[\"invoke\",2382,0,\"test\",[\"i32:11\"]],[\"invoke\",2386,0,\"test\",[\"i32:15\"]],[\"invoke\",2390,0,\"test\",[\"i32:19\"]],[\"invoke\",2395,0,\"test\",[\"i32:24\"]],[\"invoke\",2399,0,\"test\",[\"i32:28\"]],[\"module\",2404,44],[\"invoke\",2430,0,\"run\",[\"i32:0\",\"i32:23\",\"i32:15\"]],[\"invoke\",2435,0,\"test\",[\"i32:3\"]],[\"invoke\",2439,0,\"test\",[\"i32:7\"]],[\"invoke\",2444,0,\"test\",[\"i32:12\"]],[\"invoke\",2448,0,\"test\",[\"i32:16\"]],[\"invoke\",2452,0,\"test\",[\"i32:20\"]],[\"invoke\",2456,0,\"test\",[\"i32:24\"]],[\"invoke\",2460,0,\"test\",[\"i32:28\"]],[\"module\",2465,45],[\"invoke\",2493,0,\"test\",[\"i32:0\"]],[\"invoke\",2497,0,\"test\",[\"i32:4\"]],[\"invoke\",2501,0,\"test\",[\"i32:8\"]],[\"invoke\",2505,0,\"test\",[\"i32:12\"]],[\"invoke\",2509,0,\"test\",[\"i32:16\"]],[\"invoke\",2513,0,\"test\",[\"i32:20\"]],[\"invoke\",2518,0,\"test\",[\"i32:25\"]],[\"invoke\",2522,0,\"test\",[\"i32:29\"]],[\"module\",2526,43],[\"invoke\",2554,0,\"test\",[\"i32:0\"]],[\"invoke\",2558,0,\"test\",[\"i32:4\"]],[\"invoke\",2562,0,\"test\",[\"i32:8\"]],[\"invoke\",2567,0,\"test\",[\"i32:13\"]],[\"invoke\",2571,0,\"test\",[\"i32:17\"]],[\"invoke\",2575,0,\"test\",[\"i32:21\"]],[\"invoke\",2579,0,\"test\",[\"i32:25\"]],[\"invoke\",2583,0,\"test\",[\"i32:29\"]],[\"module\",2587,46],[\"invoke\",2616,0,\"test\",[\"i32:1\"]],[\"invoke\",2620,0,\"test\",[\"i32:5\"]],[\"invoke\",2624,0,\"test\",[\"i32:9\"]],[\"invoke\",2628,0,\"test\",[\"i32:13\"]],[\"invoke\",2632,0,\"test\",[\"i32:17\"]],[\"invoke\",2636,0,\"test\",[\"i32:21\"]],[\"invoke\",2641,0,\"test\",[\"i32:26\"]],[\"invoke\",2645,0,\"test\",[\"i32:30\"]],[\"module\",2648,43],[\"invoke\",2677,0,\"test\",[\"i32:1\"]],[\"invoke\",2681,0,\"test\",[\"i32:5\"]],[\"invoke\",2685,0,\"test\",[\"i32:9\"]],[\"invoke\",2690,0,\"test\",[\"i32:14\"]],[\"invoke\",2694,0,\"test\",[\"i32:18\"]],[\"invoke\",2698,0,\"test\",[\"i32:22\"]],[\"invoke\",2702,0,\"test\",[\"i32:26\"]],[\"invoke\",2706,0,\"test\",[\"i32:30\"]],[\"module\",2709,47],[\"invoke\",2739,0,\"test\",[\"i32:2\"]],[\"invoke\",2743,0,\"test\",[\"i32:6\"]],[\"invoke\",2747,0,\"test\",[\"i32:10\"]],[\"invoke\",2751,0,\"test\",[\"i32:14\"]],[\"invoke\",2755,0,\"test\",[\"i32:18\"]],[\"invoke\",2759,0,\"test\",[\"i32:22\"]],[\"invoke\",2764,0,\"test\",[\"i32:27\"]],[\"invoke\",2768,0,\"test\",[\"i32:31\"]],[\"module\",2770,48],[\"invoke\",2800,0,\"test\",[\"i32:2\"]],[\"invoke\",2804,0,\"test\",[\"i32:6\"]],[\"invoke\",2808,0,\"test\",[\"i32:10\"]],[\"invoke\",2813,0,\"test\",[\"i32:15\"]],[\"invoke\",2817,0,\"test\",[\"i32:19\"]],[\"invoke\",2821,0,\"test\",[\"i32:23\"]],[\"invoke\",2825,0,\"test\",[\"i32:27\"]],[\"invoke\",2829,0,\"test\",[\"i32:31\"]],[\"invoke\",2834,0,\"test\",[\"i32:36\"]],[\"invoke\",2838,0,\"test\",[\"i32:40\"]],[\"invoke\",2842,0,\"test\",[\"i32:44\"]],[\"invoke\",2846,0,\"test\",[\"i32:48\"]],[\"invoke\",2850,0,\"test\",[\"i32:52\"]],[\"invoke\",2854,0,\"test\",[\"i32:56\"]],[\"invoke\",2859,0,\"test\",[\"i32:61\"]],[\"invoke\",2863,0,\"test\",[\"i32:65\"]],[\"invoke\",2867,0,\"test\",[\"i32:69\"]],[\"invoke\",2871,0,\"test\",[\"i32:73\"]],[\"invoke\",2875,0,\"test\",[\"i32:77\"]],[\"invoke\",2880,0,\"test\",[\"i32:82\"]],[\"invoke\",2884,0,\"test\",[\"i32:86\"]],[\"invoke\",2888,0,\"test\",[\"i32:90\"]],[\"invoke\",2892,0,\"test\",[\"i32:94\"]],[\"invoke\",2896,0,\"test\",[\"i32:98\"]],[\"invoke\",2901,0,\"test\",[\"i32:103\"]],[\"invoke\",2905,0,\"test\",[\"i32:107\"]],[\"invoke\",2909,0,\"test\",[\"i32:111\"]],[\"invoke\",2913,0,\"test\",[\"i32:115\"]],[\"invoke\",2917,0,\"test\",[\"i32:119\"]],[\"invoke\",2921,0,\"test\",[\"i32:123\"]],[\"module\",2927,49],[\"invoke\",2953,0,\"run\",[\"i32:112\",\"i32:0\",\"i32:4294967264\"]],[\"invoke\",2958,0,\"test\",[\"i32:3\"]],[\"invoke\",2962,0,\"test\",[\"i32:7\"]],[\"invoke\",2966,0,\"test\",[\"i32:11\"]],[\"invoke\",2970,0,\"test\",[\"i32:15\"]],[\"invoke\",2975,0,\"test\",[\"i32:20\"]],[\"invoke\",2979,0,\"test\",[\"i32:24\"]],[\"invoke\",2983,0,\"test\",[\"i32:28\"]],[\"invoke\",2987,0,\"test\",[\"i32:32\"]],[\"invoke\",2991,0,\"test\",[\"i32:36\"]],[\"invoke\",2996,0,\"test\",[\"i32:41\"]],[\"invoke\",3000,0,\"test\",[\"i32:45\"]],[\"invoke\",3004,0,\"test\",[\"i32:49\"]],[\"invoke\",3008,0,\"test\",[\"i32:53\"]],[\"invoke\",3012,0,\"test\",[\"i32:57\"]],[\"invoke\",3016,0,\"test\",[\"i32:61\"]],[\"invoke\",3021,0,\"test\",[\"i32:66\"]],[\"invoke\",3025,0,\"test\",[\"i32:70\"]],[\"invoke\",3029,0,\"test\",[\"i32:74\"]],[\"invoke\",3033,0,\"test\",[\"i32:78\"]],[\"invoke\",3037,0,\"test\",[\"i32:82\"]],[\"invoke\",3042,0,\"test\",[\"i32:87\"]],[\"invoke\",3046,0,\"test\",[\"i32:91\"]],[\"invoke\",3050,0,\"test\",[\"i32:95\"]],[\"invoke\",3054,0,\"test\",[\"i32:99\"]],[\"invoke\",3058,0,\"test\",[\"i32:103\"]],[\"invoke\",3063,0,\"test\",[\"i32:108\"]],[\"invoke\",3067,0,\"test\",[\"i32:112\"]],[\"invoke\",3071,0,\"test\",[\"i32:116\"]],[\"invoke\",3075,0,\"test\",[\"i32:120\"]],[\"invoke\",3079,0,\"test\",[\"i32:124\"]],[\"file\",\"table_fill.wast\"],[\"module\",1,50],[\"invoke\",17,0,\"get\",[\"i32:1\"]],[\"invoke\",18,0,\"get\",[\"i32:2\"]],[\"invoke\",19,0,\"get\",[\"i32:3\"]],[\"invoke\",20,0,\"get\",[\"i32:4\"]],[\"invoke\",21,0,\"get\",[\"i32:5\"]],[\"invoke\",23,0,\"fill\",[\"i32:2\",\"externref:1\",\"i32:3\"]],[\"invoke\",24,0,\"get\",[\"i32:1\"]],[\"invoke\",25,0,\"get\",[\"i32:2\"]],[\"invoke\",26,0,\"get\",[\"i32:3\"]],[\"invoke\",27,0,\"get\",[\"i32:4\"]],[\"invoke\",28,0,\"get\",[\"i32:5\"]],[\"invoke\",30,0,\"fill\",[\"i32:4\",\"externref:2\",\"i32:2\"]],[\"invoke\",31,0,\"get\",[\"i32:3\"]],[\"invoke\",32,0,\"get\",[\"i32:4\"]],[\"invoke\",33,0,\"get\",[\"i32:5\"]],[\"invoke\",34,0,\"get\",[\"i32:6\"]],[\"invoke\",36,0,\"fill\",[\"i32:4\",\"externref:3\",\"i32:0\"]],[\"invoke\",37,0,\"get\",[\"i32:3\"]],[\"invoke\",38,0,\"get\",[\"i32:4\"]],[\"invoke\",39,0,\"get\",[\"i32:5\"]],[\"invoke\",41,0,\"fill\",[\"i32:8\",\"externref:4\",\"i32:2\"]],[\"invoke\",42,0,\"get\",[\"i32:7\"]],[\"invoke\",43,0,\"get\",[\"i32:8\"]],[\"invoke\",44,0,\"get\",[\"i32:9\"]],[\"invoke\",46,0,\"fill-abbrev\",[\"i32:9\",\"externref:null\",\"i32:1\"]],[\"invoke\",47,0,\"get\",[\"i32:8\"]],[\"invoke\",48,0,\"get\",[\"i32:9\"]],[\"invoke\",50,0,\"fill\",[\"i32:10\",\"externref:5\",\"i32:0\"]],[\"invoke\",51,0,\"get\",[\"i32:9\"]],[\"invoke\",54,0,\"fill\",[\"i32:8\",\"externref:6\",\"i32:3\"]],[\"invoke\",57,0,\"get\",[\"i32:7\"]],[\"invoke\",58,0,\"get\",[\"i32:8\"]],[\"invoke\",59,0,\"get\",[\"i32:9\"]],[\"invoke\",62,0,\"fill\",[\"i32:11\",\"externref:null\",\"i32:0\"]],[\"invoke\",67,0,\"fill\",[\"i32:11\",\"externref:null\",\"i32:10\"]],[\"file\",\"table_get.wast\"],[\"module\",1,51],[\"invoke\",24,0,\"init\",[\"externref:1\"]],[\"invoke\",26,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",27,0,\"get-externref\",[\"i32:1\"]],[\"invoke\",29,0,\"get-funcref\",[\"i32:0\"]],[\"invoke\",30,0,\"is_null-funcref\",[\"i32:1\"]],[\"invoke\",31,0,\"is_null-funcref\",[\"i32:2\"]],[\"invoke\",33,0,\"get-externref\",[\"i32:2\"]],[\"invoke\",34,0,\"get-funcref\",[\"i32:3\"]],[\"invoke\",35,0,\"get-externref\",[\"i32:4294967295\"]],[\"invoke\",36,0,\"get-funcref\",[\"i32:4294967295\"]],[\"file\",\"table_grow.wast\"],[\"module\",1,52],[\"invoke\",16,0,\"size\",[]],[\"invoke\",17,0,\"set\",[\"i32:0\",\"externref:2\"]],[\"invoke\",18,0,\"get\",[\"i32:0\"]],[\"invoke\",20,0,\"grow\",[\"i32:1\",\"externref:null\"]],[\"invoke\",21,0,\"size\",[]],[\"invoke\",22,0,\"get\",[\"i32:0\"]],[\"invoke\",23,0,\"set\",[\"i32:0\",\"externref:2\"]],[\"invoke\",24,0,\"get\",[\"i32:0\"]],[\"invoke\",25,0,\"set\",[\"i32:1\",\"externref:2\"]],[\"invoke\",26,0,\"get\",[\"i32:1\"]],[\"invoke\",28,0,\"grow-abbrev\",[\"i32:4\",\"externref:3\"]],[\"invoke\",29,0,\"size\",[]],[\"invoke\",30,0,\"get\",[\"i32:0\"]],[\"invoke\",31,0,\"set\",[\"i32:0\",\"externref:2\"]],[\"invoke\",32,0,\"get\",[\"i32:0\"]],[\"invoke\",33,0,\"get\",[\"i32:1\"]],[\"invoke\",34,0,\"get\",[\"i32:4\"]],[\"invoke\",35,0,\"set\",[\"i32:4\",\"externref:4\"]],[\"invoke\",36,0,\"get\",[\"i32:4\"]],[\"invoke\",37,0,\"set\",[\"i32:5\",\"externref:2\"]],[\"invoke\",38,0,\"get\",[\"i32:5\"]],[\"module\",42,53],[\"invoke\",50,0,\"grow\",[]],[\"module\",53,54],[\"invoke\",60,0,\"grow\",[\"i32:0\"]],[\"invoke\",61,0,\"grow\",[\"i32:1\"]],[\"invoke\",62,0,\"grow\",[\"i32:0\"]],[\"invoke\",63,0,\"grow\",[\"i32:2\"]],[\"invoke\",64,0,\"grow\",[\"i32:800\"]],[\"module\",67,55],[\"invoke\",74,0,\"grow\",[\"i32:0\"]],[\"invoke\",75,0,\"grow\",[\"i32:1\"]],[\"invoke\",76,0,\"grow\",[\"i32:1\"]],[\"invoke\",77,0,\"grow\",[\"i32:2\"]],[\"invoke\",78,0,\"grow\",[\"i32:6\"]],[\"invoke\",79,0,\"grow\",[\"i32:0\"]],[\"invoke\",80,0,\"grow\",[\"i32:1\"]],[\"invoke\",81,0,\"grow\",[\"i32:65536\"]],[\"module\",84,56],[\"invoke\",106,0,\"check-table-null\",[\"i32:0\",\"i32:9\"]],[\"invoke\",107,0,\"grow\",[\"i32:10\"]],[\"invoke\",108,0,\"check-table-null\",[\"i32:0\",\"i32:19\"]],[\"module\",111,57,\"$Tgt\"],[\"register\",\"grown-table\",\"$Tgt\"],[\"invoke\",116,\"$Tgt\",\"grow\",[]],[\"module\",117,58,\"$Tgit1\"],[\"register\",\"grown-imported-table\",\"$Tgit1\"],[\"invoke\",123,\"$Tgit1\",\"grow\",[]],[\"module\",124,59,\"$Tgit2\"],[\"invoke\",129,\"$Tgit2\",\"size\",[]],[\"file\",\"table_init.wast\"],[\"module\",6,0],[\"register\",\"a\"],[\"module\",15,60],[\"invoke\",41,0,\"test\",[]],[\"invoke\",43,0,\"check\",[\"i32:1\"]],[\"invoke\",45,0,\"check\",[\"i32:3\"]],[\"invoke\",47,0,\"check\",[\"i32:5\"]],[\"invoke\",48,0,\"check\",[\"i32:6\"]],[\"invoke\",50,0,\"check\",[\"i32:8\"]],[\"invoke\",52,0,\"check\",[\"i32:10\"]],[\"invoke\",53,0,\"check\",[\"i32:11\"]],[\"invoke\",55,0,\"check\",[\"i32:13\"]],[\"invoke\",57,0,\"check\",[\"i32:15\"]],[\"invoke\",58,0,\"check\",[\"i32:16\"]],[\"invoke\",60,0,\"check\",[\"i32:18\"]],[\"invoke\",62,0,\"check\",[\"i32:20\"]],[\"invoke\",64,0,\"check\",[\"i32:22\"]],[\"invoke\",65,0,\"check\",[\"i32:23\"]],[\"invoke\",67,0,\"check\",[\"i32:25\"]],[\"invoke\",69,0,\"check\",[\"i32:27\"]],[\"invoke\",70,0,\"check\",[\"i32:28\"]],[\"module\",73,61],[\"invoke\",99,0,\"test\",[]],[\"invoke\",101,0,\"check\",[\"i32:1\"]],[\"invoke\",102,0,\"check\",[\"i32:2\"]],[\"invoke\",104,0,\"check\",[\"i32:4\"]],[\"invoke\",106,0,\"check\",[\"i32:6\"]],[\"invoke\",107,0,\"check\",[\"i32:7\"]],[\"invoke\",109,0,\"check\",[\"i32:9\"]],[\"invoke\",111,0,\"check\",[\"i32:11\"]],[\"invoke\",113,0,\"check\",[\"i32:13\"]],[\"invoke\",114,0,\"check\",[\"i32:14\"]],[\"invoke\",116,0,\"check\",[\"i32:16\"]],[\"invoke\",118,0,\"check\",[\"i32:18\"]],[\"invoke\",119,0,\"check\",[\"i32:19\"]],[\"invoke\",121,0,\"check\",[\"i32:21\"]],[\"invoke\",123,0,\"check\",[\"i32:23\"]],[\"invoke\",124,0,\"check\",[\"i32:24\"]],[\"invoke\",126,0,\"check\",[\"i32:26\"]],[\"invoke\",128,0,\"check\",[\"i32:28\"]],[\"invoke\",129,0,\"check\",[\"i32:29\"]],[\"module\",131,62],[\"invoke\",166,0,\"check\",[\"i32:0\"]],[\"invoke\",168,0,\"check\",[\"i32:2\"]],[\"invoke\",170,0,\"check\",[\"i32:4\"]],[\"invoke\",171,0,\"check\",[\"i32:5\"]],[\"invoke\",173,0,\"check\",[\"i32:7\"]],[\"invoke\",175,0,\"check\",[\"i32:9\"]],[\"invoke\",176,0,\"check\",[\"i32:10\"]],[\"invoke\",178,0,\"check\",[\"i32:12\"]],[\"invoke\",180,0,\"check\",[\"i32:14\"]],[\"invoke\",181,0,\"check\",[\"i32:15\"]],[\"invoke\",183,0,\"check\",[\"i32:17\"]],[\"invoke\",185,0,\"check\",[\"i32:19\"]],[\"invoke\",186,0,\"check\",[\"i32:20\"]],[\"invoke\",188,0,\"check\",[\"i32:22\"]],[\"invoke\",190,0,\"check\",[\"i32:24\"]],[\"invoke\",192,0,\"check\",[\"i32:26\"]],[\"invoke\",193,0,\"check\",[\"i32:27\"]],[\"invoke\",195,0,\"check\",[\"i32:29\"]],[\"module\",197,63],[\"invoke\",224,0,\"check\",[\"i32:0\"]],[\"invoke\",225,0,\"check\",[\"i32:1\"]],[\"invoke\",227,0,\"check\",[\"i32:3\"]],[\"invoke\",229,0,\"check\",[\"i32:5\"]],[\"invoke\",230,0,\"check\",[\"i32:6\"]],[\"invoke\",232,0,\"check\",[\"i32:8\"]],[\"invoke\",234,0,\"check\",[\"i32:10\"]],[\"invoke\",235,0,\"check\",[\"i32:11\"]],[\"invoke\",237,0,\"check\",[\"i32:13\"]],[\"invoke\",239,0,\"check\",[\"i32:15\"]],[\"invoke\",241,0,\"check\",[\"i32:17\"]],[\"invoke\",242,0,\"check\",[\"i32:18\"]],[\"invoke\",244,0,\"check\",[\"i32:20\"]],[\"invoke\",246,0,\"check\",[\"i32:22\"]],[\"invoke\",247,0,\"check\",[\"i32:23\"]],[\"invoke\",249,0,\"check\",[\"i32:25\"]],[\"invoke\",251,0,\"check\",[\"i32:27\"]],[\"invoke\",252,0,\"check\",[\"i32:28\"]],[\"module\",255,64],[\"invoke\",281,0,\"test\",[]],[\"invoke\",283,0,\"check\",[\"i32:1\"]],[\"invoke\",284,0,\"check\",[\"i32:2\"]],[\"invoke\",286,0,\"check\",[\"i32:4\"]],[\"invoke\",288,0,\"check\",[\"i32:6\"]],[\"invoke\",290,0,\"check\",[\"i32:8\"]],[\"invoke\",291,0,\"check\",[\"i32:9\"]],[\"invoke\",293,0,\"check\",[\"i32:11\"]],[\"invoke\",295,0,\"check\",[\"i32:13\"]],[\"invoke\",296,0,\"check\",[\"i32:14\"]],[\"invoke\",298,0,\"check\",[\"i32:16\"]],[\"invoke\",300,0,\"check\",[\"i32:18\"]],[\"invoke\",301,0,\"check\",[\"i32:19\"]],[\"invoke\",303,0,\"check\",[\"i32:21\"]],[\"invoke\",305,0,\"check\",[\"i32:23\"]],[\"invoke\",306,0,\"check\",[\"i32:24\"]],[\"invoke\",308,0,\"check\",[\"i32:26\"]],[\"invoke\",310,0,\"check\",[\"i32:28\"]],[\"module\",313,65],[\"invoke\",347,0,\"test\",[]],[\"invoke\",348,0,\"check\",[\"i32:0\"]],[\"invoke\",350,0,\"check\",[\"i32:2\"]],[\"invoke\",352,0,\"check\",[\"i32:4\"]],[\"invoke\",353,0,\"check\",[\"i32:5\"]],[\"invoke\",355,0,\"check\",[\"i32:7\"]],[\"invoke\",357,0,\"check\",[\"i32:9\"]],[\"invoke\",358,0,\"check\",[\"i32:10\"]],[\"invoke\",360,0,\"check\",[\"i32:12\"]],[\"invoke\",362,0,\"check\",[\"i32:14\"]],[\"invoke\",363,0,\"check\",[\"i32:15\"]],[\"invoke\",365,0,\"check\",[\"i32:17\"]],[\"invoke\",367,0,\"check\",[\"i32:19\"]],[\"invoke\",369,0,\"check\",[\"i32:21\"]],[\"invoke\",370,0,\"check\",[\"i32:22\"]],[\"invoke\",372,0,\"check\",[\"i32:24\"]],[\"invoke\",374,0,\"check\",[\"i32:26\"]],[\"invoke\",375,0,\"check\",[\"i32:27\"]],[\"invoke\",377,0,\"check\",[\"i32:29\"]],[\"module\",407,66],[\"module\",431,67],[\"invoke\",453,0,\"test\",[]],[\"module\",455,68],[\"invoke\",477,0,\"test\",[]],[\"module\",479,69],[\"module\",503,70],[\"invoke\",525,0,\"test\",[]],[\"module\",527,71],[\"module\",551,72],[\"invoke\",573,0,\"test\",[]],[\"module\",575,73],[\"invoke\",597,0,\"test\",[]],[\"module\",599,74],[\"module\",623,75],[\"invoke\",645,0,\"test\",[]],[\"module\",647,76],[\"module\",671,77],[\"invoke\",693,0,\"test\",[]],[\"module\",695,78],[\"module\",719,79],[\"invoke\",741,0,\"test\",[]],[\"module\",743,80],[\"invoke\",765,0,\"test\",[]],[\"module\",767,81],[\"module\",791,82],[\"invoke\",813,0,\"test\",[]],[\"module\",815,83],[\"module\",839,84],[\"invoke\",861,0,\"test\",[]],[\"module\",863,85],[\"invoke\",885,0,\"test\",[]],[\"module\",887,86],[\"module\",1478,87],[\"invoke\",1506,0,\"run\",[\"i32:24\",\"i32:16\"]],[\"invoke\",1508,0,\"test\",[\"i32:1\"]],[\"invoke\",1509,0,\"test\",[\"i32:2\"]],[\"invoke\",1511,0,\"test\",[\"i32:4\"]],[\"invoke\",1513,0,\"test\",[\"i32:6\"]],[\"invoke\",1514,0,\"test\",[\"i32:7\"]],[\"invoke\",1516,0,\"test\",[\"i32:9\"]],[\"invoke\",1518,0,\"test\",[\"i32:11\"]],[\"invoke\",1520,0,\"test\",[\"i32:13\"]],[\"invoke\",1521,0,\"test\",[\"i32:14\"]],[\"invoke\",1523,0,\"test\",[\"i32:16\"]],[\"invoke\",1525,0,\"test\",[\"i32:18\"]],[\"invoke\",1526,0,\"test\",[\"i32:19\"]],[\"invoke\",1528,0,\"test\",[\"i32:21\"]],[\"invoke\",1530,0,\"test\",[\"i32:23\"]],[\"invoke\",1531,0,\"test\",[\"i32:24\"]],[\"invoke\",1533,0,\"test\",[\"i32:26\"]],[\"invoke\",1535,0,\"test\",[\"i32:28\"]],[\"invoke\",1536,0,\"test\",[\"i32:29\"]],[\"invoke\",1538,0,\"test\",[\"i32:31\"]],[\"module\",1540,87],[\"invoke\",1569,0,\"test\",[\"i32:0\"]],[\"invoke\",1571,0,\"test\",[\"i32:2\"]],[\"invoke\",1572,0,\"test\",[\"i32:3\"]],[\"invoke\",1574,0,\"test\",[\"i32:5\"]],[\"invoke\",1576,0,\"test\",[\"i32:7\"]],[\"invoke\",1577,0,\"test\",[\"i32:8\"]],[\"invoke\",1579,0,\"test\",[\"i32:10\"]],[\"invoke\",1581,0,\"test\",[\"i32:12\"]],[\"invoke\",1582,0,\"test\",[\"i32:13\"]],[\"invoke\",1584,0,\"test\",[\"i32:15\"]],[\"invoke\",1586,0,\"test\",[\"i32:17\"]],[\"invoke\",1587,0,\"test\",[\"i32:18\"]],[\"invoke\",1589,0,\"test\",[\"i32:20\"]],[\"invoke\",1591,0,\"test\",[\"i32:22\"]],[\"invoke\",1593,0,\"test\",[\"i32:24\"]],[\"invoke\",1594,0,\"test\",[\"i32:25\"]],[\"invoke\",1596,0,\"test\",[\"i32:27\"]],[\"invoke\",1598,0,\"test\",[\"i32:29\"]],[\"invoke\",1599,0,\"test\",[\"i32:30\"]],[\"module\",1602,88],[\"invoke\",1630,0,\"run\",[\"i32:96\",\"i32:32\"]],[\"invoke\",1632,0,\"test\",[\"i32:1\"]],[\"invoke\",1633,0,\"test\",[\"i32:2\"]],[\"invoke\",1635,0,\"test\",[\"i32:4\"]],[\"invoke\",1637,0,\"test\",[\"i32:6\"]],[\"invoke\",1638,0,\"test\",[\"i32:7\"]],[\"invoke\",1640,0,\"test\",[\"i32:9\"]],[\"invoke\",1642,0,\"test\",[\"i32:11\"]],[\"invoke\",1644,0,\"test\",[\"i32:13\"]],[\"invoke\",1645,0,\"test\",[\"i32:14\"]],[\"invoke\",1647,0,\"test\",[\"i32:16\"]],[\"invoke\",1649,0,\"test\",[\"i32:18\"]],[\"invoke\",1650,0,\"test\",[\"i32:19\"]],[\"invoke\",1652,0,\"test\",[\"i32:21\"]],[\"invoke\",1654,0,\"test\",[\"i32:23\"]],[\"invoke\",1655,0,\"test\",[\"i32:24\"]],[\"invoke\",1657,0,\"test\",[\"i32:26\"]],[\"invoke\",1659,0,\"test\",[\"i32:28\"]],[\"invoke\",1660,0,\"test\",[\"i32:29\"]],[\"invoke\",1662,0,\"test\",[\"i32:31\"]],[\"invoke\",1664,0,\"test\",[\"i32:33\"]],[\"invoke\",1666,0,\"test\",[\"i32:35\"]],[\"invoke\",1667,0,\"test\",[\"i32:36\"]],[\"invoke\",1669,0,\"test\",[\"i32:38\"]],[\"invoke\",1671,0,\"test\",[\"i32:40\"]],[\"invoke\",1672,0,\"test\",[\"i32:41\"]],[\"invoke\",1674,0,\"test\",[\"i32:43\"]],[\"invoke\",1676,0,\"test\",[\"i32:45\"]],[\"invoke\",1677,0,\"test\",[\"i32:46\"]],[\"invoke\",1679,0,\"test\",[\"i32:48\"]],[\"invoke\",1681,0,\"test\",[\"i32:50\"]],[\"invoke\",1682,0,\"test\",[\"i32:51\"]],[\"invoke\",1684,0,\"test\",[\"i32:53\"]],[\"invoke\",1686,0,\"test\",[\"i32:55\"]],[\"invoke\",1688,0,\"test\",[\"i32:57\"]],[\"invoke\",1689,0,\"test\",[\"i32:58\"]],[\"invoke\",1691,0,\"test\",[\"i32:60\"]],[\"invoke\",1693,0,\"test\",[\"i32:62\"]],[\"invoke\",1694,0,\"test\",[\"i32:63\"]],[\"invoke\",1696,0,\"test\",[\"i32:65\"]],[\"invoke\",1698,0,\"test\",[\"i32:67\"]],[\"invoke\",1699,0,\"test\",[\"i32:68\"]],[\"invoke\",1701,0,\"test\",[\"i32:70\"]],[\"invoke\",1703,0,\"test\",[\"i32:72\"]],[\"invoke\",1704,0,\"test\",[\"i32:73\"]],[\"invoke\",1706,0,\"test\",[\"i32:75\"]],[\"invoke\",1708,0,\"test\",[\"i32:77\"]],[\"invoke\",1710,0,\"test\",[\"i32:79\"]],[\"invoke\",1711,0,\"test\",[\"i32:80\"]],[\"invoke\",1713,0,\"test\",[\"i32:82\"]],[\"invoke\",1715,0,\"test\",[\"i32:84\"]],[\"invoke\",1716,0,\"test\",[\"i32:85\"]],[\"invoke\",1718,0,\"test\",[\"i32:87\"]],[\"invoke\",1720,0,\"test\",[\"i32:89\"]],[\"invoke\",1721,0,\"test\",[\"i32:90\"]],[\"invoke\",1723,0,\"test\",[\"i32:92\"]],[\"invoke\",1725,0,\"test\",[\"i32:94\"]],[\"invoke\",1726,0,\"test\",[\"i32:95\"]],[\"invoke\",1728,0,\"test\",[\"i32:97\"]],[\"invoke\",1730,0,\"test\",[\"i32:99\"]],[\"invoke\",1732,0,\"test\",[\"i32:101\"]],[\"invoke\",1733,0,\"test\",[\"i32:102\"]],[\"invoke\",1735,0,\"test\",[\"i32:104\"]],[\"invoke\",1737,0,\"test\",[\"i32:106\"]],[\"invoke\",1738,0,\"test\",[\"i32:107\"]],[\"invoke\",1740,0,\"test\",[\"i32:109\"]],[\"invoke\",1742,0,\"test\",[\"i32:111\"]],[\"invoke\",1743,0,\"test\",[\"i32:112\"]],[\"invoke\",1745,0,\"test\",[\"i32:114\"]],[\"invoke\",1747,0,\"test\",[\"i32:116\"]],[\"invoke\",1748,0,\"test\",[\"i32:117\"]],[\"invoke\",1750,0,\"test\",[\"i32:119\"]],[\"invoke\",1752,0,\"test\",[\"i32:121\"]],[\"invoke\",1754,0,\"test\",[\"i32:123\"]],[\"invoke\",1755,0,\"test\",[\"i32:124\"]],[\"invoke\",1757,0,\"test\",[\"i32:126\"]],[\"invoke\",1759,0,\"test\",[\"i32:128\"]],[\"invoke\",1760,0,\"test\",[\"i32:129\"]],[\"invoke\",1762,0,\"test\",[\"i32:131\"]],[\"invoke\",1764,0,\"test\",[\"i32:133\"]],[\"invoke\",1765,0,\"test\",[\"i32:134\"]],[\"invoke\",1767,0,\"test\",[\"i32:136\"]],[\"invoke\",1769,0,\"test\",[\"i32:138\"]],[\"invoke\",1770,0,\"test\",[\"i32:139\"]],[\"invoke\",1772,0,\"test\",[\"i32:141\"]],[\"invoke\",1774,0,\"test\",[\"i32:143\"]],[\"invoke\",1776,0,\"test\",[\"i32:145\"]],[\"invoke\",1777,0,\"test\",[\"i32:146\"]],[\"invoke\",1779,0,\"test\",[\"i32:148\"]],[\"invoke\",1781,0,\"test\",[\"i32:150\"]],[\"invoke\",1782,0,\"test\",[\"i32:151\"]],[\"invoke\",1784,0,\"test\",[\"i32:153\"]],[\"invoke\",1786,0,\"test\",[\"i32:155\"]],[\"invoke\",1787,0,\"test\",[\"i32:156\"]],[\"invoke\",1789,0,\"test\",[\"i32:158\"]],[\"module\",1792,88],[\"invoke\",1820,0,\"run\",[\"i32:97\",\"i32:31\"]],[\"invoke\",1821,0,\"test\",[\"i32:0\"]],[\"invoke\",1823,0,\"test\",[\"i32:2\"]],[\"invoke\",1825,0,\"test\",[\"i32:4\"]],[\"invoke\",1827,0,\"test\",[\"i32:6\"]],[\"invoke\",1828,0,\"test\",[\"i32:7\"]],[\"invoke\",1830,0,\"test\",[\"i32:9\"]],[\"invoke\",1832,0,\"test\",[\"i32:11\"]],[\"invoke\",1833,0,\"test\",[\"i32:12\"]],[\"invoke\",1835,0,\"test\",[\"i32:14\"]],[\"invoke\",1837,0,\"test\",[\"i32:16\"]],[\"invoke\",1838,0,\"test\",[\"i32:17\"]],[\"invoke\",1840,0,\"test\",[\"i32:19\"]],[\"invoke\",1842,0,\"test\",[\"i32:21\"]],[\"invoke\",1843,0,\"test\",[\"i32:22\"]],[\"invoke\",1845,0,\"test\",[\"i32:24\"]],[\"invoke\",1847,0,\"test\",[\"i32:26\"]],[\"invoke\",1849,0,\"test\",[\"i32:28\"]],[\"invoke\",1850,0,\"test\",[\"i32:29\"]],[\"invoke\",1852,0,\"test\",[\"i32:31\"]],[\"invoke\",1854,0,\"test\",[\"i32:33\"]],[\"invoke\",1855,0,\"test\",[\"i32:34\"]],[\"invoke\",1857,0,\"test\",[\"i32:36\"]],[\"invoke\",1859,0,\"test\",[\"i32:38\"]],[\"invoke\",1860,0,\"test\",[\"i32:39\"]],[\"invoke\",1862,0,\"test\",[\"i32:41\"]],[\"invoke\",1864,0,\"test\",[\"i32:43\"]],[\"invoke\",1865,0,\"test\",[\"i32:44\"]],[\"invoke\",1867,0,\"test\",[\"i32:46\"]],[\"invoke\",1869,0,\"test\",[\"i32:48\"]],[\"invoke\",1871,0,\"test\",[\"i32:50\"]],[\"invoke\",1872,0,\"test\",[\"i32:51\"]],[\"invoke\",1874,0,\"test\",[\"i32:53\"]],[\"invoke\",1876,0,\"test\",[\"i32:55\"]],[\"invoke\",1877,0,\"test\",[\"i32:56\"]],[\"invoke\",1879,0,\"test\",[\"i32:58\"]],[\"invoke\",1881,0,\"test\",[\"i32:60\"]],[\"invoke\",1882,0,\"test\",[\"i32:61\"]],[\"invoke\",1884,0,\"test\",[\"i32:63\"]],[\"invoke\",1886,0,\"test\",[\"i32:65\"]],[\"invoke\",1887,0,\"test\",[\"i32:66\"]],[\"invoke\",1889,0,\"test\",[\"i32:68\"]],[\"invoke\",1891,0,\"test\",[\"i32:70\"]],[\"invoke\",1893,0,\"test\",[\"i32:72\"]],[\"invoke\",1894,0,\"test\",[\"i32:73\"]],[\"invoke\",1896,0,\"test\",[\"i32:75\"]],[\"invoke\",1898,0,\"test\",[\"i32:77\"]],[\"invoke\",1899,0,\"test\",[\"i32:78\"]],[\"invoke\",1901,0,\"test\",[\"i32:80\"]],[\"invoke\",1903,0,\"test\",[\"i32:82\"]],[\"invoke\",1904,0,\"test\",[\"i32:83\"]],[\"invoke\",1906,0,\"test\",[\"i32:85\"]],[\"invoke\",1908,0,\"test\",[\"i32:87\"]],[\"invoke\",1909,0,\"test\",[\"i32:88\"]],[\"invoke\",1911,0,\"test\",[\"i32:90\"]],[\"invoke\",1913,0,\"test\",[\"i32:92\"]],[\"invoke\",1915,0,\"test\",[\"i32:94\"]],[\"invoke\",1916,0,\"test\",[\"i32:95\"]],[\"invoke\",1918,0,\"test\",[\"i32:97\"]],[\"invoke\",1920,0,\"test\",[\"i32:99\"]],[\"invoke\",1921,0,\"test\",[\"i32:100\"]],[\"invoke\",1923,0,\"test\",[\"i32:102\"]],[\"invoke\",1925,0,\"test\",[\"i32:104\"]],[\"invoke\",1926,0,\"test\",[\"i32:105\"]],[\"invoke\",1928,0,\"test\",[\"i32:107\"]],[\"invoke\",1930,0,\"test\",[\"i32:109\"]],[\"invoke\",1931,0,\"test\",[\"i32:110\"]],[\"invoke\",1933,0,\"test\",[\"i32:112\"]],[\"invoke\",1935,0,\"test\",[\"i32:114\"]],[\"invoke\",1937,0,\"test\",[\"i32:116\"]],[\"invoke\",1938,0,\"test\",[\"i32:117\"]],[\"invoke\",1940,0,\"test\",[\"i32:119\"]],[\"invoke\",1942,0,\"test\",[\"i32:121\"]],[\"invoke\",1943,0,\"test\",[\"i32:122\"]],[\"invoke\",1945,0,\"test\",[\"i32:124\"]],[\"invoke\",1947,0,\"test\",[\"i32:126\"]],[\"invoke\",1948,0,\"test\",[\"i32:127\"]],[\"invoke\",1950,0,\"test\",[\"i32:129\"]],[\"invoke\",1952,0,\"test\",[\"i32:131\"]],[\"invoke\",1953,0,\"test\",[\"i32:132\"]],[\"invoke\",1955,0,\"test\",[\"i32:134\"]],[\"invoke\",1957,0,\"test\",[\"i32:136\"]],[\"invoke\",1959,0,\"test\",[\"i32:138\"]],[\"invoke\",1960,0,\"test\",[\"i32:139\"]],[\"invoke\",1962,0,\"test\",[\"i32:141\"]],[\"invoke\",1964,0,\"test\",[\"i32:143\"]],[\"invoke\",1965,0,\"test\",[\"i32:144\"]],[\"invoke\",1967,0,\"test\",[\"i32:146\"]],[\"invoke\",1969,0,\"test\",[\"i32:148\"]],[\"invoke\",1970,0,\"test\",[\"i32:149\"]],[\"invoke\",1972,0,\"test\",[\"i32:151\"]],[\"invoke\",1974,0,\"test\",[\"i32:153\"]],[\"invoke\",1975,0,\"test\",[\"i32:154\"]],[\"invoke\",1977,0,\"test\",[\"i32:156\"]],[\"invoke\",1979,0,\"test\",[\"i32:158\"]],[\"module\",1982,89],[\"invoke\",2010,0,\"run\",[\"i32:48\",\"i32:4294967280\"]],[\"invoke\",2011,0,\"test\",[\"i32:0\"]],[\"invoke\",2013,0,\"test\",[\"i32:2\"]],[\"invoke\",2015,0,\"test\",[\"i32:4\"]],[\"invoke\",2016,0,\"test\",[\"i32:5\"]],[\"invoke\",2018,0,\"test\",[\"i32:7\"]],[\"invoke\",2020,0,\"test\",[\"i32:9\"]],[\"invoke\",2021,0,\"test\",[\"i32:10\"]],[\"invoke\",2023,0,\"test\",[\"i32:12\"]],[\"invoke\",2025,0,\"test\",[\"i32:14\"]],[\"invoke\",2026,0,\"test\",[\"i32:15\"]],[\"invoke\",2028,0,\"test\",[\"i32:17\"]],[\"invoke\",2030,0,\"test\",[\"i32:19\"]],[\"invoke\",2032,0,\"test\",[\"i32:21\"]],[\"invoke\",2033,0,\"test\",[\"i32:22\"]],[\"invoke\",2035,0,\"test\",[\"i32:24\"]],[\"invoke\",2037,0,\"test\",[\"i32:26\"]],[\"invoke\",2038,0,\"test\",[\"i32:27\"]],[\"invoke\",2040,0,\"test\",[\"i32:29\"]],[\"invoke\",2042,0,\"test\",[\"i32:31\"]],[\"invoke\",2043,0,\"test\",[\"i32:32\"]],[\"invoke\",2045,0,\"test\",[\"i32:34\"]],[\"invoke\",2047,0,\"test\",[\"i32:36\"]],[\"invoke\",2048,0,\"test\",[\"i32:37\"]],[\"invoke\",2050,0,\"test\",[\"i32:39\"]],[\"invoke\",2052,0,\"test\",[\"i32:41\"]],[\"invoke\",2054,0,\"test\",[\"i32:43\"]],[\"invoke\",2055,0,\"test\",[\"i32:44\"]],[\"invoke\",2057,0,\"test\",[\"i32:46\"]],[\"invoke\",2059,0,\"test\",[\"i32:48\"]],[\"invoke\",2060,0,\"test\",[\"i32:49\"]],[\"invoke\",2062,0,\"test\",[\"i32:51\"]],[\"invoke\",2064,0,\"test\",[\"i32:53\"]],[\"invoke\",2065,0,\"test\",[\"i32:54\"]],[\"invoke\",2067,0,\"test\",[\"i32:56\"]],[\"invoke\",2069,0,\"test\",[\"i32:58\"]],[\"invoke\",2070,0,\"test\",[\"i32:59\"]],[\"invoke\",2072,0,\"test\",[\"i32:61\"]],[\"invoke\",2074,0,\"test\",[\"i32:63\"]],[\"module\",2076,90],[\"invoke\",2105,0,\"test\",[\"i32:0\"]],[\"invoke\",2106,0,\"test\",[\"i32:1\"]],[\"invoke\",2108,0,\"test\",[\"i32:3\"]],[\"invoke\",2110,0,\"test\",[\"i32:5\"]],[\"invoke\",2111,0,\"test\",[\"i32:6\"]],[\"invoke\",2113,0,\"test\",[\"i32:8\"]],[\"invoke\",2115,0,\"test\",[\"i32:10\"]],[\"invoke\",2116,0,\"test\",[\"i32:11\"]],[\"invoke\",2118,0,\"test\",[\"i32:13\"]],[\"invoke\",2120,0,\"test\",[\"i32:15\"]],[\"module\",2122,91],[\"file\",\"table_set.wast\"],[\"module\",1,92],[\"invoke\",29,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",30,0,\"set-externref\",[\"i32:0\",\"externref:1\"]],[\"invoke\",31,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",32,0,\"set-externref\",[\"i32:0\",\"externref:null\"]],[\"invoke\",33,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",35,0,\"get-funcref\",[\"i32:0\"]],[\"invoke\",36,0,\"set-funcref-from\",[\"i32:0\",\"i32:1\"]],[\"invoke\",37,0,\"is_null-funcref\",[\"i32:0\"]],[\"invoke\",38,0,\"set-funcref\",[\"i32:0\",\"funcref:null\"]],[\"invoke\",39,0,\"get-funcref\",[\"i32:0\"]],[\"invoke\",41,0,\"set-externref\",[\"i32:2\",\"externref:null\"]],[\"invoke\",42,0,\"set-funcref\",[\"i32:3\",\"funcref:null\"]],[\"invoke\",43,0,\"set-externref\",[\"i32:4294967295\",\"externref:null\"]],[\"invoke\",44,0,\"set-funcref\",[\"i32:4294967295\",\"funcref:null\"]],[\"invoke\",46,0,\"set-externref\",[\"i32:2\",\"externref:0\"]],[\"invoke\",47,0,\"set-funcref-from\",[\"i32:3\",\"i32:1\"]],[\"invoke\",48,0,\"set-externref\",[\"i32:4294967295\",\"externref:0\"]],[\"invoke\",49,0,\"set-funcref-from\",[\"i32:4294967295\",\"i32:1\"]],[\"file\",\"table_size.wast\"],[\"module\",1,93],[\"invoke\",26,0,\"size-t0\",[]],[\"invoke\",27,0,\"grow-t0\",[\"i32:1\"]],[\"invoke\",28,0,\"size-t0\",[]],[\"invoke\",29,0,\"grow-t0\",[\"i32:4\"]],[\"invoke\",30,0,\"size-t0\",[]],[\"invoke\",31,0,\"grow-t0\",[\"i32:0\"]],[\"invoke\",32,0,\"size-t0\",[]],[\"invoke\",34,0,\"size-t1\",[]],[\"invoke\",35,0,\"grow-t1\",[\"i32:1\"]],[\"invoke\",36,0,\"size-t1\",[]],[\"invoke\",37,0,\"grow-t1\",[\"i32:4\"]],[\"invoke\",38,0,\"size-t1\",[]],[\"invoke\",39,0,\"grow-t1\",[\"i32:0\"]],[\"invoke\",40,0,\"size-t1\",[]],[\"invoke\",42,0,\"size-t2\",[]],[\"invoke\",43,0,\"grow-t2\",[\"i32:3\"]],[\"invoke\",44,0,\"size-t2\",[]],[\"invoke\",45,0,\"grow-t2\",[\"i32:1\"]],[\"invoke\",46,0,\"size-t2\",[]],[\"invoke\",47,0,\"grow-t2\",[\"i32:0\"]],[\"invoke\",48,0,\"size-t2\",[]],[\"invoke\",49,0,\"grow-t2\",[\"i32:4\"]],[\"invoke\",50,0,\"size-t2\",[]],[\"invoke\",51,0,\"grow-t2\",[\"i32:1\"]],[\"invoke\",52,0,\"size-t2\",[]],[\"invoke\",54,0,\"size-t3\",[]],[\"invoke\",55,0,\"grow-t3\",[\"i32:1\"]],[\"invoke\",56,0,\"size-t3\",[]],[\"invoke\",57,0,\"grow-t3\",[\"i32:3\"]],[\"invoke\",58,0,\"size-t3\",[]],[\"invoke\",59,0,\"grow-t3\",[\"i32:0\"]],[\"invoke\",60,0,\"size-t3\",[]],[\"invoke\",61,0,\"grow-t3\",[\"i32:2\"]],[\"invoke\",62,0,\"size-t3\",[]],[\"invoke\",63,0,\"grow-t3\",[\"i32:1\"]],[\"invoke\",64,0,\"size-t3\",[]],[\"file\",\"elem.wast\"],[\"module\",4,94],[\"module\",80,95],[\"module\",90,96],[\"module\",101,97],[\"module\",120,98],[\"module\",127,98],[\"module\",134,99],[\"invoke\",148,0,\"call-7\",[]],[\"invoke\",149,0,\"call-9\",[]],[\"module\",153,100],[\"invoke\",167,0,\"call-7\",[]],[\"invoke\",168,0,\"call-9\",[]],[\"module\",182,101],[\"module\",193,102],[\"module\",202,103],[\"module\",207,104],[\"instantiate\",239,105],[\"instantiate\",248,106],[\"instantiate\",257,107],[\"instantiate\",266,108],[\"instantiate\",273,109],[\"instantiate\",290,110],[\"instantiate\",307,111],[\"instantiate\",324,112],[\"module\",342,113],[\"invoke\",350,0,\"init\",[]],[\"module\",352,114],[\"invoke\",360,0,\"init\",[]],[\"module\",537,115],[\"invoke\",548,0,\"call-overwritten\",[]],[\"module\",565,116,\"$module1\"],[\"register\",\"module1\",\"$module1\"],[\"invoke\",585,\"$module1\",\"call-7\",[]],[\"invoke\",586,\"$module1\",\"call-8\",[]],[\"invoke\",587,\"$module1\",\"call-9\",[]],[\"module\",589,117,\"$module2\"],[\"invoke\",598,\"$module1\",\"call-7\",[]],[\"invoke\",599,\"$module1\",\"call-8\",[]],[\"invoke\",600,\"$module1\",\"call-9\",[]],[\"module\",602,118,\"$module3\"],[\"invoke\",611,\"$module1\",\"call-7\",[]],[\"invoke\",612,\"$module1\",\"call-8\",[]],[\"invoke\",613,\"$module1\",\"call-9\",[]],[\"module\",646,119,\"$m\"],[\"register\",\"exporter\",\"$m\"],[\"invoke\",655,\"$m\",\"get\",[\"i32:0\"]],[\"invoke\",656,\"$m\",\"get\",[\"i32:1\"]],[\"invoke\",658,\"$m\",\"set\",[\"i32:0\",\"externref:42\"]],[\"invoke\",659,\"$m\",\"set\",[\"i32:1\",\"externref:137\"]],[\"invoke\",661,\"$m\",\"get\",[\"i32:0\"]],[\"invoke\",662,\"$m\",\"get\",[\"i32:1\"]],[\"module\",664,120],[\"invoke\",668,\"$m\",\"get\",[\"i32:0\"]],[\"invoke\",669,\"$m\",\"get\",[\"i32:1\"]],[\"module\",673,121,\"$module4\"],[\"register\",\"module4\",\"$module4\"],[\"module\",682,122],[\"invoke\",692,0,\"call_imported_elem\",[]],[\"file\",\"ref_func.wast\"],[\"module\",1,123],[\"register\",\"M\"],[\"module\",6,124],[\"invoke\",56,0,\"is_null-f\",[]],[\"invoke\",57,0,\"is_null-g\",[]],[\"invoke\",58,0,\"is_null-v\",[]],[\"invoke\",60,0,\"call-f\",[\"i32:4\"]],[\"invoke\",61,0,\"call-g\",[\"i32:4\"]],[\"invoke\",62,0,\"call-v\",[\"i32:4\"]],[\"invoke\",63,0,\"set-g\",[]],[\"invoke\",64,0,\"call-v\",[\"i32:4\"]],[\"invoke\",65,0,\"set-f\",[]],[\"invoke\",66,0,\"call-v\",[\"i32:4\"]],[\"module\",80,125],[\"file\",\"ref_is_null.wast\"],[\"module\",1,126],[\"invoke\",30,0,\"funcref\",[\"funcref:null\"]],[\"invoke\",31,0,\"externref\",[\"externref:null\"]],[\"invoke\",33,0,\"externref\",[\"externref:1\"]],[\"invoke\",35,0,\"init\",[\"externref:0\"]],[\"invoke\",37,0,\"funcref-elem\",[\"i32:0\"]],[\"invoke\",38,0,\"externref-elem\",[\"i32:0\"]],[\"invoke\",40,0,\"funcref-elem\",[\"i32:1\"]],[\"invoke\",41,0,\"externref-elem\",[\"i32:1\"]],[\"invoke\",43,0,\"deinit\",[]],[\"invoke\",45,0,\"funcref-elem\",[\"i32:0\"]],[\"invoke\",46,0,\"externref-elem\",[\"i32:0\"]],[\"invoke\",48,0,\"funcref-elem\",[\"i32:1\"]],[\"invoke\",49,0,\"externref-elem\",[\"i32:1\"]],[\"file\",\"ref_null.wast\"],[\"module\",1,127],[\"invoke\",9,0,\"externref\",[]],[\"invoke\",10,0,\"funcref\",[]],[\"file\",\"exports.wast\"],[\"module\",3,128],[\"module\",4,129],[\"module\",5,130],[\"module\",7,128],[\"module\",8,131],[\"module\",9,132],[\"module\",10,128],[\"module\",11,128],[\"module\",12,128],[\"module\",13,128],[\"module\",14,128],[\"module\",16,133,\"$Func\"],[\"invoke\",22,0,\"e\",[\"i32:42\"]],[\"invoke\",23,\"$Func\",\"e\",[\"i32:42\"]],[\"module\",24,134],[\"module\",25,134,\"$Other1\"],[\"invoke\",26,\"$Func\",\"e\",[\"i32:42\"]],[\"module\",28,135],[\"invoke\",34,0,\"a\",[]],[\"invoke\",35,0,\"b\",[]],[\"invoke\",36,0,\"c\",[]],[\"module\",74,136],[\"module\",75,137],[\"module\",76,138],[\"module\",78,136],[\"module\",79,136],[\"module\",80,136],[\"module\",81,136],[\"module\",82,136],[\"module\",83,136],[\"module\",85,139,\"$Global\"],[\"get\",89,0,\"e\",[]],[\"get\",90,\"$Global\",\"e\",[]],[\"module\",91,134],[\"module\",92,134,\"$Other2\"],[\"get\",93,\"$Global\",\"e\",[]],[\"module\",131,140],[\"module\",132,141],[\"module\",133,142],[\"module\",135,140],[\"module\",136,143],[\"module\",137,140],[\"module\",138,143],[\"module\",139,140],[\"module\",140,143],[\"module\",141,140],[\"module\",142,143],[\"module\",143,140],[\"module\",144,143],[\"module\",145,140],[\"module\",146,143],[\"module\",186,144],[\"module\",187,145],[\"module\",191,144],[\"module\",192,146],[\"module\",193,144],[\"module\",194,146],[\"module\",195,144],[\"module\",196,146],[\"module\",197,144],[\"module\",198,146],[\"module\",199,144],[\"module\",200,146],[\"module\",201,144],[\"module\",202,146],[\"file\",\"linking.wast\"],[\"module\",3,147,\"$Mf\"],[\"register\",\"Mf\",\"$Mf\"],[\"module\",9,148,\"$Nf\"],[\"invoke\",17,\"$Mf\",\"call\",[]],[\"invoke\",18,\"$Nf\",\"Mf.call\",[]],[\"invoke\",19,\"$Nf\",\"call\",[]],[\"invoke\",20,\"$Nf\",\"call Mf.call\",[]],[\"module\",22,149],[\"register\",\"reexport_f\"],[\"instantiate\",28,150],[\"instantiate\",32,151],[\"module\",39,152,\"$Mg\"],[\"register\",\"Mg\",\"$Mg\"],[\"module\",50,153,\"$Ng\"],[\"get\",67,\"$Mg\",\"glob\",[]],[\"get\",68,\"$Ng\",\"Mg.glob\",[]],[\"get\",69,\"$Ng\",\"glob\",[]],[\"invoke\",70,\"$Mg\",\"get\",[]],[\"invoke\",71,\"$Ng\",\"Mg.get\",[]],[\"invoke\",72,\"$Ng\",\"get\",[]],[\"get\",74,\"$Mg\",\"mut_glob\",[]],[\"get\",75,\"$Ng\",\"Mg.mut_glob\",[]],[\"invoke\",76,\"$Mg\",\"get_mut\",[]],[\"invoke\",77,\"$Ng\",\"Mg.get_mut\",[]],[\"invoke\",79,\"$Mg\",\"set_mut\",[\"i32:241\"]],[\"get\",80,\"$Mg\",\"mut_glob\",[]],[\"get\",81,\"$Ng\",\"Mg.mut_glob\",[]],[\"invoke\",82,\"$Mg\",\"get_mut\",[]],[\"invoke\",83,\"$Ng\",\"Mg.get_mut\",[]],[\"instantiate\",87,154],[\"instantiate\",91,155],[\"module\",96,156,\"$Mref_ex\"],[\"register\",\"Mref_ex\",\"$Mref_ex\"],[\"module\",104,157,\"$Mref_im\"],[\"instantiate\",113,158],[\"instantiate\",117,159],[\"instantiate\",123,160],[\"instantiate\",127,161],[\"module\",134,162,\"$Mt\"],[\"register\",\"Mt\",\"$Mt\"],[\"module\",149,163,\"$Nt\"],[\"invoke\",168,\"$Mt\",\"call\",[\"i32:2\"]],[\"invoke\",169,\"$Nt\",\"Mt.call\",[\"i32:2\"]],[\"invoke\",170,\"$Nt\",\"call\",[\"i32:2\"]],[\"invoke\",171,\"$Nt\",\"call Mt.call\",[\"i32:2\"]],[\"invoke\",173,\"$Mt\",\"call\",[\"i32:1\"]],[\"invoke\",174,\"$Nt\",\"Mt.call\",[\"i32:1\"]],[\"invoke\",175,\"$Nt\",\"call\",[\"i32:1\"]],[\"invoke\",176,\"$Nt\",\"call Mt.call\",[\"i32:1\"]],[\"invoke\",178,\"$Mt\",\"call\",[\"i32:0\"]],[\"invoke\",179,\"$Nt\",\"Mt.call\",[\"i32:0\"]],[\"invoke\",180,\"$Nt\",\"call\",[\"i32:0\"]],[\"invoke\",181,\"$Nt\",\"call Mt.call\",[\"i32:0\"]],[\"invoke\",183,\"$Mt\",\"call\",[\"i32:20\"]],[\"invoke\",184,\"$Nt\",\"Mt.call\",[\"i32:20\"]],[\"invoke\",185,\"$Nt\",\"call\",[\"i32:7\"]],[\"invoke\",186,\"$Nt\",\"call Mt.call\",[\"i32:20\"]],[\"invoke\",188,\"$Nt\",\"call\",[\"i32:3\"]],[\"invoke\",189,\"$Nt\",\"call\",[\"i32:4\"]],[\"module\",191,164,\"$Ot\"],[\"invoke\",204,\"$Mt\",\"call\",[\"i32:3\"]],[\"invoke\",205,\"$Nt\",\"Mt.call\",[\"i32:3\"]],[\"invoke\",206,\"$Nt\",\"call Mt.call\",[\"i32:3\"]],[\"invoke\",207,\"$Ot\",\"call\",[\"i32:3\"]],[\"invoke\",209,\"$Mt\",\"call\",[\"i32:2\"]],[\"invoke\",210,\"$Nt\",\"Mt.call\",[\"i32:2\"]],[\"invoke\",211,\"$Nt\",\"call\",[\"i32:2\"]],[\"invoke\",212,\"$Nt\",\"call Mt.call\",[\"i32:2\"]],[\"invoke\",213,\"$Ot\",\"call\",[\"i32:2\"]],[\"invoke\",215,\"$Mt\",\"call\",[\"i32:1\"]],[\"invoke\",216,\"$Nt\",\"Mt.call\",[\"i32:1\"]],[\"invoke\",217,\"$Nt\",\"call\",[\"i32:1\"]],[\"invoke\",218,\"$Nt\",\"call Mt.call\",[\"i32:1\"]],[\"invoke\",219,\"$Ot\",\"call\",[\"i32:1\"]],[\"invoke\",221,\"$Mt\",\"call\",[\"i32:0\"]],[\"invoke\",222,\"$Nt\",\"Mt.call\",[\"i32:0\"]],[\"invoke\",223,\"$Nt\",\"call\",[\"i32:0\"]],[\"invoke\",224,\"$Nt\",\"call Mt.call\",[\"i32:0\"]],[\"invoke\",225,\"$Ot\",\"call\",[\"i32:0\"]],[\"invoke\",227,\"$Ot\",\"call\",[\"i32:20\"]],[\"module\",229,165],[\"module\",235,166,\"$G1\"],[\"register\",\"G1\",\"$G1\"],[\"module\",237,167,\"$G2\"],[\"get\",241,\"$G2\",\"g\",[]],[\"instantiate\",244,168],[\"instantiate\",253,169],[\"invoke\",262,\"$Mt\",\"call\",[\"i32:7\"]],[\"instantiate\",267,170],[\"invoke\",275,\"$Mt\",\"call\",[\"i32:7\"]],[\"invoke\",276,\"$Mt\",\"call\",[\"i32:8\"]],[\"instantiate\",279,171],[\"invoke\",288,\"$Mt\",\"call\",[\"i32:7\"]],[\"module\",291,172,\"$Mtable_ex\"],[\"register\",\"Mtable_ex\",\"$Mtable_ex\"],[\"module\",297,173],[\"instantiate\",303,174],[\"instantiate\",307,175],[\"module\",314,176,\"$Mm\"],[\"register\",\"Mm\",\"$Mm\"],[\"module\",324,177,\"$Nm\"],[\"invoke\",336,\"$Mm\",\"load\",[\"i32:12\"]],[\"invoke\",337,\"$Nm\",\"Mm.load\",[\"i32:12\"]],[\"invoke\",338,\"$Nm\",\"load\",[\"i32:12\"]],[\"module\",340,178,\"$Om\"],[\"invoke\",349,\"$Mm\",\"load\",[\"i32:12\"]],[\"invoke\",350,\"$Nm\",\"Mm.load\",[\"i32:12\"]],[\"invoke\",351,\"$Nm\",\"load\",[\"i32:12\"]],[\"invoke\",352,\"$Om\",\"load\",[\"i32:12\"]],[\"module\",354,179],[\"instantiate\",360,180],[\"module\",367,181,\"$Pm\"],[\"invoke\",375,\"$Pm\",\"grow\",[\"i32:0\"]],[\"invoke\",376,\"$Pm\",\"grow\",[\"i32:2\"]],[\"invoke\",377,\"$Pm\",\"grow\",[\"i32:0\"]],[\"invoke\",378,\"$Pm\",\"grow\",[\"i32:1\"]],[\"invoke\",379,\"$Pm\",\"grow\",[\"i32:1\"]],[\"invoke\",380,\"$Pm\",\"grow\",[\"i32:0\"]],[\"invoke\",381,\"$Pm\",\"grow\",[\"i32:1\"]],[\"invoke\",382,\"$Pm\",\"grow\",[\"i32:0\"]],[\"instantiate\",385,182],[\"invoke\",393,\"$Mm\",\"load\",[\"i32:0\"]],[\"instantiate\",398,183],[\"invoke\",406,\"$Mm\",\"load\",[\"i32:0\"]],[\"invoke\",407,\"$Mm\",\"load\",[\"i32:327670\"]],[\"instantiate\",410,184],[\"invoke\",419,\"$Mm\",\"load\",[\"i32:0\"]],[\"module\",422,185,\"$Ms\"],[\"register\",\"Ms\",\"$Ms\"],[\"instantiate\",436,186],[\"invoke\",452,\"$Ms\",\"get memory[0]\",[]],[\"invoke\",453,\"$Ms\",\"get table[0]\",[]]]"; +export const script = "[[\"file\",\"table_copy.wast\"],[\"module\",6,0],[\"register\",\"a\"],[\"module\",15,1],[\"invoke\",45,0,\"test\",[]],[\"invoke\",50,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",54,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",58,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",62,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",66,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",71,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",75,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",79,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",83,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",87,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",92,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",96,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",100,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",104,0,\"check_t1\",[\"i32:28\"]],[\"module\",107,2],[\"invoke\",139,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",143,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",148,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",152,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",156,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",160,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",164,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",169,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",173,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",177,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",181,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",185,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",190,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",194,0,\"check_t1\",[\"i32:26\"]],[\"module\",199,3],[\"invoke\",229,0,\"test\",[]],[\"invoke\",233,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",237,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",241,0,\"check_t0\",[\"i32:11\"]],[\"invoke\",246,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",250,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",254,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",258,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",262,0,\"check_t1\",[\"i32:2\"]],[\"invoke\",267,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",271,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",275,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",279,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",283,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",288,0,\"check_t1\",[\"i32:28\"]],[\"module\",291,4],[\"invoke\",323,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",327,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",331,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",335,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",339,0,\"check_t0\",[\"i32:17\"]],[\"invoke\",344,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",348,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",352,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",356,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",360,0,\"check_t1\",[\"i32:8\"]],[\"invoke\",365,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",369,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",373,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",377,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",381,0,\"check_t1\",[\"i32:29\"]],[\"module\",383,5],[\"invoke\",417,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",421,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",425,0,\"check_t0\",[\"i32:11\"]],[\"invoke\",429,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",433,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",437,0,\"check_t0\",[\"i32:23\"]],[\"invoke\",442,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",446,0,\"check_t1\",[\"i32:2\"]],[\"invoke\",450,0,\"check_t1\",[\"i32:6\"]],[\"invoke\",454,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",458,0,\"check_t1\",[\"i32:14\"]],[\"invoke\",463,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",467,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",471,0,\"check_t1\",[\"i32:27\"]],[\"module\",475,6],[\"invoke\",506,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",510,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",515,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",519,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",523,0,\"check_t0\",[\"i32:17\"]],[\"invoke\",527,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",531,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",535,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",540,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",544,0,\"check_t1\",[\"i32:8\"]],[\"invoke\",548,0,\"check_t1\",[\"i32:12\"]],[\"invoke\",552,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",556,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",561,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",565,0,\"check_t1\",[\"i32:29\"]],[\"module\",567,7],[\"invoke\",600,0,\"check_t0\",[\"i32:2\"]],[\"invoke\",604,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",608,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",613,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",617,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",621,0,\"check_t0\",[\"i32:23\"]],[\"invoke\",625,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",629,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",633,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",638,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",642,0,\"check_t1\",[\"i32:14\"]],[\"invoke\",646,0,\"check_t1\",[\"i32:18\"]],[\"invoke\",650,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",654,0,\"check_t1\",[\"i32:26\"]],[\"module\",659,8],[\"invoke\",690,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",694,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",698,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",702,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",706,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",711,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",715,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",719,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",723,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",727,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",731,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",736,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",740,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",744,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",748,0,\"check_t1\",[\"i32:28\"]],[\"module\",751,9],[\"invoke\",783,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",788,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",792,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",796,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",800,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",804,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",809,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",813,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",817,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",821,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",825,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",829,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",834,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",838,0,\"check_t1\",[\"i32:26\"]],[\"module\",843,10],[\"invoke\",873,0,\"test\",[]],[\"invoke\",877,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",881,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",886,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",890,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",894,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",898,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",902,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",907,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",911,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",915,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",919,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",923,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",927,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",932,0,\"check_t1\",[\"i32:28\"]],[\"module\",935,11],[\"invoke\",967,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",971,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",975,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",979,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",984,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",988,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",992,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",996,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",1000,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",1005,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",1009,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",1013,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",1017,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",1021,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",1025,0,\"check_t1\",[\"i32:29\"]],[\"module\",1027,12],[\"invoke\",1061,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",1065,0,\"check_t0\",[\"i32:7\"]],[\"invoke\",1069,0,\"check_t0\",[\"i32:11\"]],[\"invoke\",1073,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",1077,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",1082,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",1086,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",1090,0,\"check_t1\",[\"i32:2\"]],[\"invoke\",1094,0,\"check_t1\",[\"i32:6\"]],[\"invoke\",1098,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",1103,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",1107,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",1111,0,\"check_t1\",[\"i32:23\"]],[\"invoke\",1115,0,\"check_t1\",[\"i32:27\"]],[\"module\",1119,13],[\"invoke\",1150,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",1154,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",1159,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",1163,0,\"check_t0\",[\"i32:13\"]],[\"invoke\",1167,0,\"check_t0\",[\"i32:17\"]],[\"invoke\",1171,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",1175,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",1180,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",1184,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",1188,0,\"check_t1\",[\"i32:8\"]],[\"invoke\",1192,0,\"check_t1\",[\"i32:12\"]],[\"invoke\",1196,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",1201,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",1205,0,\"check_t1\",[\"i32:25\"]],[\"invoke\",1209,0,\"check_t1\",[\"i32:29\"]],[\"module\",1211,14],[\"invoke\",1244,0,\"check_t0\",[\"i32:2\"]],[\"invoke\",1248,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",1252,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",1257,0,\"check_t0\",[\"i32:15\"]],[\"invoke\",1261,0,\"check_t0\",[\"i32:19\"]],[\"invoke\",1265,0,\"check_t0\",[\"i32:23\"]],[\"invoke\",1269,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",1273,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",1278,0,\"check_t1\",[\"i32:6\"]],[\"invoke\",1282,0,\"check_t1\",[\"i32:10\"]],[\"invoke\",1286,0,\"check_t1\",[\"i32:14\"]],[\"invoke\",1290,0,\"check_t1\",[\"i32:18\"]],[\"invoke\",1294,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",1299,0,\"check_t1\",[\"i32:27\"]],[\"module\",1303,15],[\"invoke\",1334,0,\"check_t0\",[\"i32:0\"]],[\"invoke\",1338,0,\"check_t0\",[\"i32:4\"]],[\"invoke\",1342,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",1346,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",1350,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",1355,0,\"check_t0\",[\"i32:21\"]],[\"invoke\",1359,0,\"check_t0\",[\"i32:25\"]],[\"invoke\",1363,0,\"check_t0\",[\"i32:29\"]],[\"invoke\",1367,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",1371,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",1376,0,\"check_t1\",[\"i32:12\"]],[\"invoke\",1380,0,\"check_t1\",[\"i32:16\"]],[\"invoke\",1384,0,\"check_t1\",[\"i32:20\"]],[\"invoke\",1388,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",1392,0,\"check_t1\",[\"i32:28\"]],[\"module\",1395,16],[\"invoke\",1428,0,\"check_t0\",[\"i32:2\"]],[\"invoke\",1432,0,\"check_t0\",[\"i32:6\"]],[\"invoke\",1436,0,\"check_t0\",[\"i32:10\"]],[\"invoke\",1440,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",1444,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",1448,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",1453,0,\"check_t0\",[\"i32:27\"]],[\"invoke\",1457,0,\"check_t1\",[\"i32:1\"]],[\"invoke\",1461,0,\"check_t1\",[\"i32:5\"]],[\"invoke\",1465,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",1469,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",1474,0,\"check_t1\",[\"i32:18\"]],[\"invoke\",1478,0,\"check_t1\",[\"i32:22\"]],[\"invoke\",1482,0,\"check_t1\",[\"i32:26\"]],[\"module\",1487,17],[\"invoke\",1517,0,\"test\",[]],[\"invoke\",1521,0,\"check_t0\",[\"i32:3\"]],[\"invoke\",1526,0,\"check_t0\",[\"i32:8\"]],[\"invoke\",1530,0,\"check_t0\",[\"i32:12\"]],[\"invoke\",1534,0,\"check_t0\",[\"i32:16\"]],[\"invoke\",1538,0,\"check_t0\",[\"i32:20\"]],[\"invoke\",1542,0,\"check_t0\",[\"i32:24\"]],[\"invoke\",1546,0,\"check_t0\",[\"i32:28\"]],[\"invoke\",1551,0,\"check_t1\",[\"i32:3\"]],[\"invoke\",1555,0,\"check_t1\",[\"i32:7\"]],[\"invoke\",1559,0,\"check_t1\",[\"i32:11\"]],[\"invoke\",1563,0,\"check_t1\",[\"i32:15\"]],[\"invoke\",1567,0,\"check_t1\",[\"i32:19\"]],[\"invoke\",1572,0,\"check_t1\",[\"i32:24\"]],[\"invoke\",1576,0,\"check_t1\",[\"i32:28\"]],[\"module\",1579,18],[\"invoke\",1611,0,\"check_t0\",[\"i32:1\"]],[\"invoke\",1615,0,\"check_t0\",[\"i32:5\"]],[\"invoke\",1619,0,\"check_t0\",[\"i32:9\"]],[\"invoke\",1624,0,\"check_t0\",[\"i32:14\"]],[\"invoke\",1628,0,\"check_t0\",[\"i32:18\"]],[\"invoke\",1632,0,\"check_t0\",[\"i32:22\"]],[\"invoke\",1636,0,\"check_t0\",[\"i32:26\"]],[\"invoke\",1640,0,\"check_t1\",[\"i32:0\"]],[\"invoke\",1644,0,\"check_t1\",[\"i32:4\"]],[\"invoke\",1649,0,\"check_t1\",[\"i32:9\"]],[\"invoke\",1653,0,\"check_t1\",[\"i32:13\"]],[\"invoke\",1657,0,\"check_t1\",[\"i32:17\"]],[\"invoke\",1661,0,\"check_t1\",[\"i32:21\"]],[\"invoke\",1665,0,\"check_t1\",[\"i32:25\"]],[\"module\",1671,19],[\"invoke\",1694,0,\"test\",[]],[\"module\",1696,20],[\"module\",1721,21],[\"module\",1746,22],[\"module\",1771,23],[\"invoke\",1794,0,\"test\",[]],[\"module\",1796,24],[\"module\",1821,25],[\"module\",1846,26],[\"module\",1871,27],[\"invoke\",1894,0,\"test\",[]],[\"module\",1896,28],[\"module\",1921,29],[\"module\",1946,30],[\"module\",1971,31],[\"invoke\",1994,0,\"test\",[]],[\"module\",1996,32],[\"module\",2021,33],[\"module\",2046,34],[\"module\",2071,35],[\"invoke\",2094,0,\"test\",[]],[\"module\",2096,36],[\"module\",2121,37],[\"module\",2146,38],[\"module\",2171,39],[\"module\",2196,40],[\"invoke\",2219,0,\"test\",[]],[\"module\",2221,41],[\"invoke\",2251,0,\"test\",[\"i32:2\"]],[\"invoke\",2255,0,\"test\",[\"i32:6\"]],[\"invoke\",2259,0,\"test\",[\"i32:10\"]],[\"invoke\",2263,0,\"test\",[\"i32:14\"]],[\"invoke\",2267,0,\"test\",[\"i32:18\"]],[\"invoke\",2272,0,\"test\",[\"i32:23\"]],[\"invoke\",2276,0,\"test\",[\"i32:27\"]],[\"invoke\",2280,0,\"test\",[\"i32:31\"]],[\"module\",2282,42],[\"invoke\",2312,0,\"test\",[\"i32:2\"]],[\"invoke\",2316,0,\"test\",[\"i32:6\"]],[\"invoke\",2321,0,\"test\",[\"i32:11\"]],[\"invoke\",2325,0,\"test\",[\"i32:15\"]],[\"invoke\",2329,0,\"test\",[\"i32:19\"]],[\"invoke\",2333,0,\"test\",[\"i32:23\"]],[\"invoke\",2337,0,\"test\",[\"i32:27\"]],[\"module\",2343,43],[\"invoke\",2369,0,\"run\",[\"i32:0\",\"i32:24\",\"i32:16\"]],[\"invoke\",2374,0,\"test\",[\"i32:3\"]],[\"invoke\",2378,0,\"test\",[\"i32:7\"]],[\"invoke\",2382,0,\"test\",[\"i32:11\"]],[\"invoke\",2386,0,\"test\",[\"i32:15\"]],[\"invoke\",2390,0,\"test\",[\"i32:19\"]],[\"invoke\",2395,0,\"test\",[\"i32:24\"]],[\"invoke\",2399,0,\"test\",[\"i32:28\"]],[\"module\",2404,44],[\"invoke\",2430,0,\"run\",[\"i32:0\",\"i32:23\",\"i32:15\"]],[\"invoke\",2435,0,\"test\",[\"i32:3\"]],[\"invoke\",2439,0,\"test\",[\"i32:7\"]],[\"invoke\",2444,0,\"test\",[\"i32:12\"]],[\"invoke\",2448,0,\"test\",[\"i32:16\"]],[\"invoke\",2452,0,\"test\",[\"i32:20\"]],[\"invoke\",2456,0,\"test\",[\"i32:24\"]],[\"invoke\",2460,0,\"test\",[\"i32:28\"]],[\"module\",2465,45],[\"invoke\",2493,0,\"test\",[\"i32:0\"]],[\"invoke\",2497,0,\"test\",[\"i32:4\"]],[\"invoke\",2501,0,\"test\",[\"i32:8\"]],[\"invoke\",2505,0,\"test\",[\"i32:12\"]],[\"invoke\",2509,0,\"test\",[\"i32:16\"]],[\"invoke\",2513,0,\"test\",[\"i32:20\"]],[\"invoke\",2518,0,\"test\",[\"i32:25\"]],[\"invoke\",2522,0,\"test\",[\"i32:29\"]],[\"module\",2526,43],[\"invoke\",2554,0,\"test\",[\"i32:0\"]],[\"invoke\",2558,0,\"test\",[\"i32:4\"]],[\"invoke\",2562,0,\"test\",[\"i32:8\"]],[\"invoke\",2567,0,\"test\",[\"i32:13\"]],[\"invoke\",2571,0,\"test\",[\"i32:17\"]],[\"invoke\",2575,0,\"test\",[\"i32:21\"]],[\"invoke\",2579,0,\"test\",[\"i32:25\"]],[\"invoke\",2583,0,\"test\",[\"i32:29\"]],[\"module\",2587,46],[\"invoke\",2616,0,\"test\",[\"i32:1\"]],[\"invoke\",2620,0,\"test\",[\"i32:5\"]],[\"invoke\",2624,0,\"test\",[\"i32:9\"]],[\"invoke\",2628,0,\"test\",[\"i32:13\"]],[\"invoke\",2632,0,\"test\",[\"i32:17\"]],[\"invoke\",2636,0,\"test\",[\"i32:21\"]],[\"invoke\",2641,0,\"test\",[\"i32:26\"]],[\"invoke\",2645,0,\"test\",[\"i32:30\"]],[\"module\",2648,43],[\"invoke\",2677,0,\"test\",[\"i32:1\"]],[\"invoke\",2681,0,\"test\",[\"i32:5\"]],[\"invoke\",2685,0,\"test\",[\"i32:9\"]],[\"invoke\",2690,0,\"test\",[\"i32:14\"]],[\"invoke\",2694,0,\"test\",[\"i32:18\"]],[\"invoke\",2698,0,\"test\",[\"i32:22\"]],[\"invoke\",2702,0,\"test\",[\"i32:26\"]],[\"invoke\",2706,0,\"test\",[\"i32:30\"]],[\"module\",2709,47],[\"invoke\",2739,0,\"test\",[\"i32:2\"]],[\"invoke\",2743,0,\"test\",[\"i32:6\"]],[\"invoke\",2747,0,\"test\",[\"i32:10\"]],[\"invoke\",2751,0,\"test\",[\"i32:14\"]],[\"invoke\",2755,0,\"test\",[\"i32:18\"]],[\"invoke\",2759,0,\"test\",[\"i32:22\"]],[\"invoke\",2764,0,\"test\",[\"i32:27\"]],[\"invoke\",2768,0,\"test\",[\"i32:31\"]],[\"module\",2770,48],[\"invoke\",2800,0,\"test\",[\"i32:2\"]],[\"invoke\",2804,0,\"test\",[\"i32:6\"]],[\"invoke\",2808,0,\"test\",[\"i32:10\"]],[\"invoke\",2813,0,\"test\",[\"i32:15\"]],[\"invoke\",2817,0,\"test\",[\"i32:19\"]],[\"invoke\",2821,0,\"test\",[\"i32:23\"]],[\"invoke\",2825,0,\"test\",[\"i32:27\"]],[\"invoke\",2829,0,\"test\",[\"i32:31\"]],[\"invoke\",2834,0,\"test\",[\"i32:36\"]],[\"invoke\",2838,0,\"test\",[\"i32:40\"]],[\"invoke\",2842,0,\"test\",[\"i32:44\"]],[\"invoke\",2846,0,\"test\",[\"i32:48\"]],[\"invoke\",2850,0,\"test\",[\"i32:52\"]],[\"invoke\",2854,0,\"test\",[\"i32:56\"]],[\"invoke\",2859,0,\"test\",[\"i32:61\"]],[\"invoke\",2863,0,\"test\",[\"i32:65\"]],[\"invoke\",2867,0,\"test\",[\"i32:69\"]],[\"invoke\",2871,0,\"test\",[\"i32:73\"]],[\"invoke\",2875,0,\"test\",[\"i32:77\"]],[\"invoke\",2880,0,\"test\",[\"i32:82\"]],[\"invoke\",2884,0,\"test\",[\"i32:86\"]],[\"invoke\",2888,0,\"test\",[\"i32:90\"]],[\"invoke\",2892,0,\"test\",[\"i32:94\"]],[\"invoke\",2896,0,\"test\",[\"i32:98\"]],[\"invoke\",2901,0,\"test\",[\"i32:103\"]],[\"invoke\",2905,0,\"test\",[\"i32:107\"]],[\"invoke\",2909,0,\"test\",[\"i32:111\"]],[\"invoke\",2913,0,\"test\",[\"i32:115\"]],[\"invoke\",2917,0,\"test\",[\"i32:119\"]],[\"invoke\",2921,0,\"test\",[\"i32:123\"]],[\"module\",2927,49],[\"invoke\",2953,0,\"run\",[\"i32:112\",\"i32:0\",\"i32:4294967264\"]],[\"invoke\",2958,0,\"test\",[\"i32:3\"]],[\"invoke\",2962,0,\"test\",[\"i32:7\"]],[\"invoke\",2966,0,\"test\",[\"i32:11\"]],[\"invoke\",2970,0,\"test\",[\"i32:15\"]],[\"invoke\",2975,0,\"test\",[\"i32:20\"]],[\"invoke\",2979,0,\"test\",[\"i32:24\"]],[\"invoke\",2983,0,\"test\",[\"i32:28\"]],[\"invoke\",2987,0,\"test\",[\"i32:32\"]],[\"invoke\",2991,0,\"test\",[\"i32:36\"]],[\"invoke\",2996,0,\"test\",[\"i32:41\"]],[\"invoke\",3000,0,\"test\",[\"i32:45\"]],[\"invoke\",3004,0,\"test\",[\"i32:49\"]],[\"invoke\",3008,0,\"test\",[\"i32:53\"]],[\"invoke\",3012,0,\"test\",[\"i32:57\"]],[\"invoke\",3016,0,\"test\",[\"i32:61\"]],[\"invoke\",3021,0,\"test\",[\"i32:66\"]],[\"invoke\",3025,0,\"test\",[\"i32:70\"]],[\"invoke\",3029,0,\"test\",[\"i32:74\"]],[\"invoke\",3033,0,\"test\",[\"i32:78\"]],[\"invoke\",3037,0,\"test\",[\"i32:82\"]],[\"invoke\",3042,0,\"test\",[\"i32:87\"]],[\"invoke\",3046,0,\"test\",[\"i32:91\"]],[\"invoke\",3050,0,\"test\",[\"i32:95\"]],[\"invoke\",3054,0,\"test\",[\"i32:99\"]],[\"invoke\",3058,0,\"test\",[\"i32:103\"]],[\"invoke\",3063,0,\"test\",[\"i32:108\"]],[\"invoke\",3067,0,\"test\",[\"i32:112\"]],[\"invoke\",3071,0,\"test\",[\"i32:116\"]],[\"invoke\",3075,0,\"test\",[\"i32:120\"]],[\"invoke\",3079,0,\"test\",[\"i32:124\"]],[\"file\",\"table_fill.wast\"],[\"module\",1,50],[\"invoke\",17,0,\"get\",[\"i32:1\"]],[\"invoke\",18,0,\"get\",[\"i32:2\"]],[\"invoke\",19,0,\"get\",[\"i32:3\"]],[\"invoke\",20,0,\"get\",[\"i32:4\"]],[\"invoke\",21,0,\"get\",[\"i32:5\"]],[\"invoke\",23,0,\"fill\",[\"i32:2\",\"externref:1\",\"i32:3\"]],[\"invoke\",24,0,\"get\",[\"i32:1\"]],[\"invoke\",25,0,\"get\",[\"i32:2\"]],[\"invoke\",26,0,\"get\",[\"i32:3\"]],[\"invoke\",27,0,\"get\",[\"i32:4\"]],[\"invoke\",28,0,\"get\",[\"i32:5\"]],[\"invoke\",30,0,\"fill\",[\"i32:4\",\"externref:2\",\"i32:2\"]],[\"invoke\",31,0,\"get\",[\"i32:3\"]],[\"invoke\",32,0,\"get\",[\"i32:4\"]],[\"invoke\",33,0,\"get\",[\"i32:5\"]],[\"invoke\",34,0,\"get\",[\"i32:6\"]],[\"invoke\",36,0,\"fill\",[\"i32:4\",\"externref:3\",\"i32:0\"]],[\"invoke\",37,0,\"get\",[\"i32:3\"]],[\"invoke\",38,0,\"get\",[\"i32:4\"]],[\"invoke\",39,0,\"get\",[\"i32:5\"]],[\"invoke\",41,0,\"fill\",[\"i32:8\",\"externref:4\",\"i32:2\"]],[\"invoke\",42,0,\"get\",[\"i32:7\"]],[\"invoke\",43,0,\"get\",[\"i32:8\"]],[\"invoke\",44,0,\"get\",[\"i32:9\"]],[\"invoke\",46,0,\"fill-abbrev\",[\"i32:9\",\"externref:null\",\"i32:1\"]],[\"invoke\",47,0,\"get\",[\"i32:8\"]],[\"invoke\",48,0,\"get\",[\"i32:9\"]],[\"invoke\",50,0,\"fill\",[\"i32:10\",\"externref:5\",\"i32:0\"]],[\"invoke\",51,0,\"get\",[\"i32:9\"]],[\"invoke\",54,0,\"fill\",[\"i32:8\",\"externref:6\",\"i32:3\"]],[\"invoke\",57,0,\"get\",[\"i32:7\"]],[\"invoke\",58,0,\"get\",[\"i32:8\"]],[\"invoke\",59,0,\"get\",[\"i32:9\"]],[\"invoke\",62,0,\"fill\",[\"i32:11\",\"externref:null\",\"i32:0\"]],[\"invoke\",67,0,\"fill\",[\"i32:11\",\"externref:null\",\"i32:10\"]],[\"file\",\"table_get.wast\"],[\"module\",1,51],[\"invoke\",24,0,\"init\",[\"externref:1\"]],[\"invoke\",26,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",27,0,\"get-externref\",[\"i32:1\"]],[\"invoke\",29,0,\"get-funcref\",[\"i32:0\"]],[\"invoke\",30,0,\"is_null-funcref\",[\"i32:1\"]],[\"invoke\",31,0,\"is_null-funcref\",[\"i32:2\"]],[\"invoke\",33,0,\"get-externref\",[\"i32:2\"]],[\"invoke\",34,0,\"get-funcref\",[\"i32:3\"]],[\"invoke\",35,0,\"get-externref\",[\"i32:4294967295\"]],[\"invoke\",36,0,\"get-funcref\",[\"i32:4294967295\"]],[\"file\",\"table_grow.wast\"],[\"module\",1,52],[\"invoke\",16,0,\"size\",[]],[\"invoke\",17,0,\"set\",[\"i32:0\",\"externref:2\"]],[\"invoke\",18,0,\"get\",[\"i32:0\"]],[\"invoke\",20,0,\"grow\",[\"i32:1\",\"externref:null\"]],[\"invoke\",21,0,\"size\",[]],[\"invoke\",22,0,\"get\",[\"i32:0\"]],[\"invoke\",23,0,\"set\",[\"i32:0\",\"externref:2\"]],[\"invoke\",24,0,\"get\",[\"i32:0\"]],[\"invoke\",25,0,\"set\",[\"i32:1\",\"externref:2\"]],[\"invoke\",26,0,\"get\",[\"i32:1\"]],[\"invoke\",28,0,\"grow-abbrev\",[\"i32:4\",\"externref:3\"]],[\"invoke\",29,0,\"size\",[]],[\"invoke\",30,0,\"get\",[\"i32:0\"]],[\"invoke\",31,0,\"set\",[\"i32:0\",\"externref:2\"]],[\"invoke\",32,0,\"get\",[\"i32:0\"]],[\"invoke\",33,0,\"get\",[\"i32:1\"]],[\"invoke\",34,0,\"get\",[\"i32:4\"]],[\"invoke\",35,0,\"set\",[\"i32:4\",\"externref:4\"]],[\"invoke\",36,0,\"get\",[\"i32:4\"]],[\"invoke\",37,0,\"set\",[\"i32:5\",\"externref:2\"]],[\"invoke\",38,0,\"get\",[\"i32:5\"]],[\"module\",42,53],[\"invoke\",50,0,\"grow\",[]],[\"module\",53,54],[\"invoke\",60,0,\"grow\",[\"i32:0\"]],[\"invoke\",61,0,\"grow\",[\"i32:1\"]],[\"invoke\",62,0,\"grow\",[\"i32:0\"]],[\"invoke\",63,0,\"grow\",[\"i32:2\"]],[\"invoke\",64,0,\"grow\",[\"i32:800\"]],[\"module\",67,55],[\"invoke\",74,0,\"grow\",[\"i32:0\"]],[\"invoke\",75,0,\"grow\",[\"i32:1\"]],[\"invoke\",76,0,\"grow\",[\"i32:1\"]],[\"invoke\",77,0,\"grow\",[\"i32:2\"]],[\"invoke\",78,0,\"grow\",[\"i32:6\"]],[\"invoke\",79,0,\"grow\",[\"i32:0\"]],[\"invoke\",80,0,\"grow\",[\"i32:1\"]],[\"invoke\",81,0,\"grow\",[\"i32:65536\"]],[\"module\",84,56],[\"invoke\",106,0,\"check-table-null\",[\"i32:0\",\"i32:9\"]],[\"invoke\",107,0,\"grow\",[\"i32:10\"]],[\"invoke\",108,0,\"check-table-null\",[\"i32:0\",\"i32:19\"]],[\"module\",111,57,\"$Tgt\"],[\"register\",\"grown-table\",\"$Tgt\"],[\"invoke\",116,\"$Tgt\",\"grow\",[]],[\"module\",117,58,\"$Tgit1\"],[\"register\",\"grown-imported-table\",\"$Tgit1\"],[\"invoke\",123,\"$Tgit1\",\"grow\",[]],[\"module\",124,59,\"$Tgit2\"],[\"invoke\",129,\"$Tgit2\",\"size\",[]],[\"file\",\"table_init.wast\"],[\"module\",6,0],[\"register\",\"a\"],[\"module\",15,60],[\"invoke\",41,0,\"test\",[]],[\"invoke\",43,0,\"check\",[\"i32:1\"]],[\"invoke\",45,0,\"check\",[\"i32:3\"]],[\"invoke\",47,0,\"check\",[\"i32:5\"]],[\"invoke\",48,0,\"check\",[\"i32:6\"]],[\"invoke\",50,0,\"check\",[\"i32:8\"]],[\"invoke\",52,0,\"check\",[\"i32:10\"]],[\"invoke\",53,0,\"check\",[\"i32:11\"]],[\"invoke\",55,0,\"check\",[\"i32:13\"]],[\"invoke\",57,0,\"check\",[\"i32:15\"]],[\"invoke\",58,0,\"check\",[\"i32:16\"]],[\"invoke\",60,0,\"check\",[\"i32:18\"]],[\"invoke\",62,0,\"check\",[\"i32:20\"]],[\"invoke\",64,0,\"check\",[\"i32:22\"]],[\"invoke\",65,0,\"check\",[\"i32:23\"]],[\"invoke\",67,0,\"check\",[\"i32:25\"]],[\"invoke\",69,0,\"check\",[\"i32:27\"]],[\"invoke\",70,0,\"check\",[\"i32:28\"]],[\"module\",73,61],[\"invoke\",99,0,\"test\",[]],[\"invoke\",101,0,\"check\",[\"i32:1\"]],[\"invoke\",102,0,\"check\",[\"i32:2\"]],[\"invoke\",104,0,\"check\",[\"i32:4\"]],[\"invoke\",106,0,\"check\",[\"i32:6\"]],[\"invoke\",107,0,\"check\",[\"i32:7\"]],[\"invoke\",109,0,\"check\",[\"i32:9\"]],[\"invoke\",111,0,\"check\",[\"i32:11\"]],[\"invoke\",113,0,\"check\",[\"i32:13\"]],[\"invoke\",114,0,\"check\",[\"i32:14\"]],[\"invoke\",116,0,\"check\",[\"i32:16\"]],[\"invoke\",118,0,\"check\",[\"i32:18\"]],[\"invoke\",119,0,\"check\",[\"i32:19\"]],[\"invoke\",121,0,\"check\",[\"i32:21\"]],[\"invoke\",123,0,\"check\",[\"i32:23\"]],[\"invoke\",124,0,\"check\",[\"i32:24\"]],[\"invoke\",126,0,\"check\",[\"i32:26\"]],[\"invoke\",128,0,\"check\",[\"i32:28\"]],[\"invoke\",129,0,\"check\",[\"i32:29\"]],[\"module\",131,62],[\"invoke\",166,0,\"check\",[\"i32:0\"]],[\"invoke\",168,0,\"check\",[\"i32:2\"]],[\"invoke\",170,0,\"check\",[\"i32:4\"]],[\"invoke\",171,0,\"check\",[\"i32:5\"]],[\"invoke\",173,0,\"check\",[\"i32:7\"]],[\"invoke\",175,0,\"check\",[\"i32:9\"]],[\"invoke\",176,0,\"check\",[\"i32:10\"]],[\"invoke\",178,0,\"check\",[\"i32:12\"]],[\"invoke\",180,0,\"check\",[\"i32:14\"]],[\"invoke\",181,0,\"check\",[\"i32:15\"]],[\"invoke\",183,0,\"check\",[\"i32:17\"]],[\"invoke\",185,0,\"check\",[\"i32:19\"]],[\"invoke\",186,0,\"check\",[\"i32:20\"]],[\"invoke\",188,0,\"check\",[\"i32:22\"]],[\"invoke\",190,0,\"check\",[\"i32:24\"]],[\"invoke\",192,0,\"check\",[\"i32:26\"]],[\"invoke\",193,0,\"check\",[\"i32:27\"]],[\"invoke\",195,0,\"check\",[\"i32:29\"]],[\"module\",197,63],[\"invoke\",224,0,\"check\",[\"i32:0\"]],[\"invoke\",225,0,\"check\",[\"i32:1\"]],[\"invoke\",227,0,\"check\",[\"i32:3\"]],[\"invoke\",229,0,\"check\",[\"i32:5\"]],[\"invoke\",230,0,\"check\",[\"i32:6\"]],[\"invoke\",232,0,\"check\",[\"i32:8\"]],[\"invoke\",234,0,\"check\",[\"i32:10\"]],[\"invoke\",235,0,\"check\",[\"i32:11\"]],[\"invoke\",237,0,\"check\",[\"i32:13\"]],[\"invoke\",239,0,\"check\",[\"i32:15\"]],[\"invoke\",241,0,\"check\",[\"i32:17\"]],[\"invoke\",242,0,\"check\",[\"i32:18\"]],[\"invoke\",244,0,\"check\",[\"i32:20\"]],[\"invoke\",246,0,\"check\",[\"i32:22\"]],[\"invoke\",247,0,\"check\",[\"i32:23\"]],[\"invoke\",249,0,\"check\",[\"i32:25\"]],[\"invoke\",251,0,\"check\",[\"i32:27\"]],[\"invoke\",252,0,\"check\",[\"i32:28\"]],[\"module\",255,64],[\"invoke\",281,0,\"test\",[]],[\"invoke\",283,0,\"check\",[\"i32:1\"]],[\"invoke\",284,0,\"check\",[\"i32:2\"]],[\"invoke\",286,0,\"check\",[\"i32:4\"]],[\"invoke\",288,0,\"check\",[\"i32:6\"]],[\"invoke\",290,0,\"check\",[\"i32:8\"]],[\"invoke\",291,0,\"check\",[\"i32:9\"]],[\"invoke\",293,0,\"check\",[\"i32:11\"]],[\"invoke\",295,0,\"check\",[\"i32:13\"]],[\"invoke\",296,0,\"check\",[\"i32:14\"]],[\"invoke\",298,0,\"check\",[\"i32:16\"]],[\"invoke\",300,0,\"check\",[\"i32:18\"]],[\"invoke\",301,0,\"check\",[\"i32:19\"]],[\"invoke\",303,0,\"check\",[\"i32:21\"]],[\"invoke\",305,0,\"check\",[\"i32:23\"]],[\"invoke\",306,0,\"check\",[\"i32:24\"]],[\"invoke\",308,0,\"check\",[\"i32:26\"]],[\"invoke\",310,0,\"check\",[\"i32:28\"]],[\"module\",313,65],[\"invoke\",347,0,\"test\",[]],[\"invoke\",348,0,\"check\",[\"i32:0\"]],[\"invoke\",350,0,\"check\",[\"i32:2\"]],[\"invoke\",352,0,\"check\",[\"i32:4\"]],[\"invoke\",353,0,\"check\",[\"i32:5\"]],[\"invoke\",355,0,\"check\",[\"i32:7\"]],[\"invoke\",357,0,\"check\",[\"i32:9\"]],[\"invoke\",358,0,\"check\",[\"i32:10\"]],[\"invoke\",360,0,\"check\",[\"i32:12\"]],[\"invoke\",362,0,\"check\",[\"i32:14\"]],[\"invoke\",363,0,\"check\",[\"i32:15\"]],[\"invoke\",365,0,\"check\",[\"i32:17\"]],[\"invoke\",367,0,\"check\",[\"i32:19\"]],[\"invoke\",369,0,\"check\",[\"i32:21\"]],[\"invoke\",370,0,\"check\",[\"i32:22\"]],[\"invoke\",372,0,\"check\",[\"i32:24\"]],[\"invoke\",374,0,\"check\",[\"i32:26\"]],[\"invoke\",375,0,\"check\",[\"i32:27\"]],[\"invoke\",377,0,\"check\",[\"i32:29\"]],[\"module\",407,66],[\"module\",431,67],[\"invoke\",453,0,\"test\",[]],[\"module\",455,68],[\"invoke\",477,0,\"test\",[]],[\"module\",479,69],[\"module\",503,70],[\"invoke\",525,0,\"test\",[]],[\"module\",527,71],[\"module\",551,72],[\"invoke\",573,0,\"test\",[]],[\"module\",575,73],[\"invoke\",597,0,\"test\",[]],[\"module\",599,74],[\"module\",623,75],[\"invoke\",645,0,\"test\",[]],[\"module\",647,76],[\"module\",671,77],[\"invoke\",693,0,\"test\",[]],[\"module\",695,78],[\"module\",719,79],[\"invoke\",741,0,\"test\",[]],[\"module\",743,80],[\"invoke\",765,0,\"test\",[]],[\"module\",767,81],[\"module\",791,82],[\"invoke\",813,0,\"test\",[]],[\"module\",815,83],[\"module\",839,84],[\"invoke\",861,0,\"test\",[]],[\"module\",863,85],[\"invoke\",885,0,\"test\",[]],[\"module\",887,86],[\"module\",1478,87],[\"invoke\",1506,0,\"run\",[\"i32:24\",\"i32:16\"]],[\"invoke\",1508,0,\"test\",[\"i32:1\"]],[\"invoke\",1509,0,\"test\",[\"i32:2\"]],[\"invoke\",1511,0,\"test\",[\"i32:4\"]],[\"invoke\",1513,0,\"test\",[\"i32:6\"]],[\"invoke\",1514,0,\"test\",[\"i32:7\"]],[\"invoke\",1516,0,\"test\",[\"i32:9\"]],[\"invoke\",1518,0,\"test\",[\"i32:11\"]],[\"invoke\",1520,0,\"test\",[\"i32:13\"]],[\"invoke\",1521,0,\"test\",[\"i32:14\"]],[\"invoke\",1523,0,\"test\",[\"i32:16\"]],[\"invoke\",1525,0,\"test\",[\"i32:18\"]],[\"invoke\",1526,0,\"test\",[\"i32:19\"]],[\"invoke\",1528,0,\"test\",[\"i32:21\"]],[\"invoke\",1530,0,\"test\",[\"i32:23\"]],[\"invoke\",1531,0,\"test\",[\"i32:24\"]],[\"invoke\",1533,0,\"test\",[\"i32:26\"]],[\"invoke\",1535,0,\"test\",[\"i32:28\"]],[\"invoke\",1536,0,\"test\",[\"i32:29\"]],[\"invoke\",1538,0,\"test\",[\"i32:31\"]],[\"module\",1540,87],[\"invoke\",1569,0,\"test\",[\"i32:0\"]],[\"invoke\",1571,0,\"test\",[\"i32:2\"]],[\"invoke\",1572,0,\"test\",[\"i32:3\"]],[\"invoke\",1574,0,\"test\",[\"i32:5\"]],[\"invoke\",1576,0,\"test\",[\"i32:7\"]],[\"invoke\",1577,0,\"test\",[\"i32:8\"]],[\"invoke\",1579,0,\"test\",[\"i32:10\"]],[\"invoke\",1581,0,\"test\",[\"i32:12\"]],[\"invoke\",1582,0,\"test\",[\"i32:13\"]],[\"invoke\",1584,0,\"test\",[\"i32:15\"]],[\"invoke\",1586,0,\"test\",[\"i32:17\"]],[\"invoke\",1587,0,\"test\",[\"i32:18\"]],[\"invoke\",1589,0,\"test\",[\"i32:20\"]],[\"invoke\",1591,0,\"test\",[\"i32:22\"]],[\"invoke\",1593,0,\"test\",[\"i32:24\"]],[\"invoke\",1594,0,\"test\",[\"i32:25\"]],[\"invoke\",1596,0,\"test\",[\"i32:27\"]],[\"invoke\",1598,0,\"test\",[\"i32:29\"]],[\"invoke\",1599,0,\"test\",[\"i32:30\"]],[\"module\",1602,88],[\"invoke\",1630,0,\"run\",[\"i32:96\",\"i32:32\"]],[\"invoke\",1632,0,\"test\",[\"i32:1\"]],[\"invoke\",1633,0,\"test\",[\"i32:2\"]],[\"invoke\",1635,0,\"test\",[\"i32:4\"]],[\"invoke\",1637,0,\"test\",[\"i32:6\"]],[\"invoke\",1638,0,\"test\",[\"i32:7\"]],[\"invoke\",1640,0,\"test\",[\"i32:9\"]],[\"invoke\",1642,0,\"test\",[\"i32:11\"]],[\"invoke\",1644,0,\"test\",[\"i32:13\"]],[\"invoke\",1645,0,\"test\",[\"i32:14\"]],[\"invoke\",1647,0,\"test\",[\"i32:16\"]],[\"invoke\",1649,0,\"test\",[\"i32:18\"]],[\"invoke\",1650,0,\"test\",[\"i32:19\"]],[\"invoke\",1652,0,\"test\",[\"i32:21\"]],[\"invoke\",1654,0,\"test\",[\"i32:23\"]],[\"invoke\",1655,0,\"test\",[\"i32:24\"]],[\"invoke\",1657,0,\"test\",[\"i32:26\"]],[\"invoke\",1659,0,\"test\",[\"i32:28\"]],[\"invoke\",1660,0,\"test\",[\"i32:29\"]],[\"invoke\",1662,0,\"test\",[\"i32:31\"]],[\"invoke\",1664,0,\"test\",[\"i32:33\"]],[\"invoke\",1666,0,\"test\",[\"i32:35\"]],[\"invoke\",1667,0,\"test\",[\"i32:36\"]],[\"invoke\",1669,0,\"test\",[\"i32:38\"]],[\"invoke\",1671,0,\"test\",[\"i32:40\"]],[\"invoke\",1672,0,\"test\",[\"i32:41\"]],[\"invoke\",1674,0,\"test\",[\"i32:43\"]],[\"invoke\",1676,0,\"test\",[\"i32:45\"]],[\"invoke\",1677,0,\"test\",[\"i32:46\"]],[\"invoke\",1679,0,\"test\",[\"i32:48\"]],[\"invoke\",1681,0,\"test\",[\"i32:50\"]],[\"invoke\",1682,0,\"test\",[\"i32:51\"]],[\"invoke\",1684,0,\"test\",[\"i32:53\"]],[\"invoke\",1686,0,\"test\",[\"i32:55\"]],[\"invoke\",1688,0,\"test\",[\"i32:57\"]],[\"invoke\",1689,0,\"test\",[\"i32:58\"]],[\"invoke\",1691,0,\"test\",[\"i32:60\"]],[\"invoke\",1693,0,\"test\",[\"i32:62\"]],[\"invoke\",1694,0,\"test\",[\"i32:63\"]],[\"invoke\",1696,0,\"test\",[\"i32:65\"]],[\"invoke\",1698,0,\"test\",[\"i32:67\"]],[\"invoke\",1699,0,\"test\",[\"i32:68\"]],[\"invoke\",1701,0,\"test\",[\"i32:70\"]],[\"invoke\",1703,0,\"test\",[\"i32:72\"]],[\"invoke\",1704,0,\"test\",[\"i32:73\"]],[\"invoke\",1706,0,\"test\",[\"i32:75\"]],[\"invoke\",1708,0,\"test\",[\"i32:77\"]],[\"invoke\",1710,0,\"test\",[\"i32:79\"]],[\"invoke\",1711,0,\"test\",[\"i32:80\"]],[\"invoke\",1713,0,\"test\",[\"i32:82\"]],[\"invoke\",1715,0,\"test\",[\"i32:84\"]],[\"invoke\",1716,0,\"test\",[\"i32:85\"]],[\"invoke\",1718,0,\"test\",[\"i32:87\"]],[\"invoke\",1720,0,\"test\",[\"i32:89\"]],[\"invoke\",1721,0,\"test\",[\"i32:90\"]],[\"invoke\",1723,0,\"test\",[\"i32:92\"]],[\"invoke\",1725,0,\"test\",[\"i32:94\"]],[\"invoke\",1726,0,\"test\",[\"i32:95\"]],[\"invoke\",1728,0,\"test\",[\"i32:97\"]],[\"invoke\",1730,0,\"test\",[\"i32:99\"]],[\"invoke\",1732,0,\"test\",[\"i32:101\"]],[\"invoke\",1733,0,\"test\",[\"i32:102\"]],[\"invoke\",1735,0,\"test\",[\"i32:104\"]],[\"invoke\",1737,0,\"test\",[\"i32:106\"]],[\"invoke\",1738,0,\"test\",[\"i32:107\"]],[\"invoke\",1740,0,\"test\",[\"i32:109\"]],[\"invoke\",1742,0,\"test\",[\"i32:111\"]],[\"invoke\",1743,0,\"test\",[\"i32:112\"]],[\"invoke\",1745,0,\"test\",[\"i32:114\"]],[\"invoke\",1747,0,\"test\",[\"i32:116\"]],[\"invoke\",1748,0,\"test\",[\"i32:117\"]],[\"invoke\",1750,0,\"test\",[\"i32:119\"]],[\"invoke\",1752,0,\"test\",[\"i32:121\"]],[\"invoke\",1754,0,\"test\",[\"i32:123\"]],[\"invoke\",1755,0,\"test\",[\"i32:124\"]],[\"invoke\",1757,0,\"test\",[\"i32:126\"]],[\"invoke\",1759,0,\"test\",[\"i32:128\"]],[\"invoke\",1760,0,\"test\",[\"i32:129\"]],[\"invoke\",1762,0,\"test\",[\"i32:131\"]],[\"invoke\",1764,0,\"test\",[\"i32:133\"]],[\"invoke\",1765,0,\"test\",[\"i32:134\"]],[\"invoke\",1767,0,\"test\",[\"i32:136\"]],[\"invoke\",1769,0,\"test\",[\"i32:138\"]],[\"invoke\",1770,0,\"test\",[\"i32:139\"]],[\"invoke\",1772,0,\"test\",[\"i32:141\"]],[\"invoke\",1774,0,\"test\",[\"i32:143\"]],[\"invoke\",1776,0,\"test\",[\"i32:145\"]],[\"invoke\",1777,0,\"test\",[\"i32:146\"]],[\"invoke\",1779,0,\"test\",[\"i32:148\"]],[\"invoke\",1781,0,\"test\",[\"i32:150\"]],[\"invoke\",1782,0,\"test\",[\"i32:151\"]],[\"invoke\",1784,0,\"test\",[\"i32:153\"]],[\"invoke\",1786,0,\"test\",[\"i32:155\"]],[\"invoke\",1787,0,\"test\",[\"i32:156\"]],[\"invoke\",1789,0,\"test\",[\"i32:158\"]],[\"module\",1792,88],[\"invoke\",1820,0,\"run\",[\"i32:97\",\"i32:31\"]],[\"invoke\",1821,0,\"test\",[\"i32:0\"]],[\"invoke\",1823,0,\"test\",[\"i32:2\"]],[\"invoke\",1825,0,\"test\",[\"i32:4\"]],[\"invoke\",1827,0,\"test\",[\"i32:6\"]],[\"invoke\",1828,0,\"test\",[\"i32:7\"]],[\"invoke\",1830,0,\"test\",[\"i32:9\"]],[\"invoke\",1832,0,\"test\",[\"i32:11\"]],[\"invoke\",1833,0,\"test\",[\"i32:12\"]],[\"invoke\",1835,0,\"test\",[\"i32:14\"]],[\"invoke\",1837,0,\"test\",[\"i32:16\"]],[\"invoke\",1838,0,\"test\",[\"i32:17\"]],[\"invoke\",1840,0,\"test\",[\"i32:19\"]],[\"invoke\",1842,0,\"test\",[\"i32:21\"]],[\"invoke\",1843,0,\"test\",[\"i32:22\"]],[\"invoke\",1845,0,\"test\",[\"i32:24\"]],[\"invoke\",1847,0,\"test\",[\"i32:26\"]],[\"invoke\",1849,0,\"test\",[\"i32:28\"]],[\"invoke\",1850,0,\"test\",[\"i32:29\"]],[\"invoke\",1852,0,\"test\",[\"i32:31\"]],[\"invoke\",1854,0,\"test\",[\"i32:33\"]],[\"invoke\",1855,0,\"test\",[\"i32:34\"]],[\"invoke\",1857,0,\"test\",[\"i32:36\"]],[\"invoke\",1859,0,\"test\",[\"i32:38\"]],[\"invoke\",1860,0,\"test\",[\"i32:39\"]],[\"invoke\",1862,0,\"test\",[\"i32:41\"]],[\"invoke\",1864,0,\"test\",[\"i32:43\"]],[\"invoke\",1865,0,\"test\",[\"i32:44\"]],[\"invoke\",1867,0,\"test\",[\"i32:46\"]],[\"invoke\",1869,0,\"test\",[\"i32:48\"]],[\"invoke\",1871,0,\"test\",[\"i32:50\"]],[\"invoke\",1872,0,\"test\",[\"i32:51\"]],[\"invoke\",1874,0,\"test\",[\"i32:53\"]],[\"invoke\",1876,0,\"test\",[\"i32:55\"]],[\"invoke\",1877,0,\"test\",[\"i32:56\"]],[\"invoke\",1879,0,\"test\",[\"i32:58\"]],[\"invoke\",1881,0,\"test\",[\"i32:60\"]],[\"invoke\",1882,0,\"test\",[\"i32:61\"]],[\"invoke\",1884,0,\"test\",[\"i32:63\"]],[\"invoke\",1886,0,\"test\",[\"i32:65\"]],[\"invoke\",1887,0,\"test\",[\"i32:66\"]],[\"invoke\",1889,0,\"test\",[\"i32:68\"]],[\"invoke\",1891,0,\"test\",[\"i32:70\"]],[\"invoke\",1893,0,\"test\",[\"i32:72\"]],[\"invoke\",1894,0,\"test\",[\"i32:73\"]],[\"invoke\",1896,0,\"test\",[\"i32:75\"]],[\"invoke\",1898,0,\"test\",[\"i32:77\"]],[\"invoke\",1899,0,\"test\",[\"i32:78\"]],[\"invoke\",1901,0,\"test\",[\"i32:80\"]],[\"invoke\",1903,0,\"test\",[\"i32:82\"]],[\"invoke\",1904,0,\"test\",[\"i32:83\"]],[\"invoke\",1906,0,\"test\",[\"i32:85\"]],[\"invoke\",1908,0,\"test\",[\"i32:87\"]],[\"invoke\",1909,0,\"test\",[\"i32:88\"]],[\"invoke\",1911,0,\"test\",[\"i32:90\"]],[\"invoke\",1913,0,\"test\",[\"i32:92\"]],[\"invoke\",1915,0,\"test\",[\"i32:94\"]],[\"invoke\",1916,0,\"test\",[\"i32:95\"]],[\"invoke\",1918,0,\"test\",[\"i32:97\"]],[\"invoke\",1920,0,\"test\",[\"i32:99\"]],[\"invoke\",1921,0,\"test\",[\"i32:100\"]],[\"invoke\",1923,0,\"test\",[\"i32:102\"]],[\"invoke\",1925,0,\"test\",[\"i32:104\"]],[\"invoke\",1926,0,\"test\",[\"i32:105\"]],[\"invoke\",1928,0,\"test\",[\"i32:107\"]],[\"invoke\",1930,0,\"test\",[\"i32:109\"]],[\"invoke\",1931,0,\"test\",[\"i32:110\"]],[\"invoke\",1933,0,\"test\",[\"i32:112\"]],[\"invoke\",1935,0,\"test\",[\"i32:114\"]],[\"invoke\",1937,0,\"test\",[\"i32:116\"]],[\"invoke\",1938,0,\"test\",[\"i32:117\"]],[\"invoke\",1940,0,\"test\",[\"i32:119\"]],[\"invoke\",1942,0,\"test\",[\"i32:121\"]],[\"invoke\",1943,0,\"test\",[\"i32:122\"]],[\"invoke\",1945,0,\"test\",[\"i32:124\"]],[\"invoke\",1947,0,\"test\",[\"i32:126\"]],[\"invoke\",1948,0,\"test\",[\"i32:127\"]],[\"invoke\",1950,0,\"test\",[\"i32:129\"]],[\"invoke\",1952,0,\"test\",[\"i32:131\"]],[\"invoke\",1953,0,\"test\",[\"i32:132\"]],[\"invoke\",1955,0,\"test\",[\"i32:134\"]],[\"invoke\",1957,0,\"test\",[\"i32:136\"]],[\"invoke\",1959,0,\"test\",[\"i32:138\"]],[\"invoke\",1960,0,\"test\",[\"i32:139\"]],[\"invoke\",1962,0,\"test\",[\"i32:141\"]],[\"invoke\",1964,0,\"test\",[\"i32:143\"]],[\"invoke\",1965,0,\"test\",[\"i32:144\"]],[\"invoke\",1967,0,\"test\",[\"i32:146\"]],[\"invoke\",1969,0,\"test\",[\"i32:148\"]],[\"invoke\",1970,0,\"test\",[\"i32:149\"]],[\"invoke\",1972,0,\"test\",[\"i32:151\"]],[\"invoke\",1974,0,\"test\",[\"i32:153\"]],[\"invoke\",1975,0,\"test\",[\"i32:154\"]],[\"invoke\",1977,0,\"test\",[\"i32:156\"]],[\"invoke\",1979,0,\"test\",[\"i32:158\"]],[\"module\",1982,89],[\"invoke\",2010,0,\"run\",[\"i32:48\",\"i32:4294967280\"]],[\"invoke\",2011,0,\"test\",[\"i32:0\"]],[\"invoke\",2013,0,\"test\",[\"i32:2\"]],[\"invoke\",2015,0,\"test\",[\"i32:4\"]],[\"invoke\",2016,0,\"test\",[\"i32:5\"]],[\"invoke\",2018,0,\"test\",[\"i32:7\"]],[\"invoke\",2020,0,\"test\",[\"i32:9\"]],[\"invoke\",2021,0,\"test\",[\"i32:10\"]],[\"invoke\",2023,0,\"test\",[\"i32:12\"]],[\"invoke\",2025,0,\"test\",[\"i32:14\"]],[\"invoke\",2026,0,\"test\",[\"i32:15\"]],[\"invoke\",2028,0,\"test\",[\"i32:17\"]],[\"invoke\",2030,0,\"test\",[\"i32:19\"]],[\"invoke\",2032,0,\"test\",[\"i32:21\"]],[\"invoke\",2033,0,\"test\",[\"i32:22\"]],[\"invoke\",2035,0,\"test\",[\"i32:24\"]],[\"invoke\",2037,0,\"test\",[\"i32:26\"]],[\"invoke\",2038,0,\"test\",[\"i32:27\"]],[\"invoke\",2040,0,\"test\",[\"i32:29\"]],[\"invoke\",2042,0,\"test\",[\"i32:31\"]],[\"invoke\",2043,0,\"test\",[\"i32:32\"]],[\"invoke\",2045,0,\"test\",[\"i32:34\"]],[\"invoke\",2047,0,\"test\",[\"i32:36\"]],[\"invoke\",2048,0,\"test\",[\"i32:37\"]],[\"invoke\",2050,0,\"test\",[\"i32:39\"]],[\"invoke\",2052,0,\"test\",[\"i32:41\"]],[\"invoke\",2054,0,\"test\",[\"i32:43\"]],[\"invoke\",2055,0,\"test\",[\"i32:44\"]],[\"invoke\",2057,0,\"test\",[\"i32:46\"]],[\"invoke\",2059,0,\"test\",[\"i32:48\"]],[\"invoke\",2060,0,\"test\",[\"i32:49\"]],[\"invoke\",2062,0,\"test\",[\"i32:51\"]],[\"invoke\",2064,0,\"test\",[\"i32:53\"]],[\"invoke\",2065,0,\"test\",[\"i32:54\"]],[\"invoke\",2067,0,\"test\",[\"i32:56\"]],[\"invoke\",2069,0,\"test\",[\"i32:58\"]],[\"invoke\",2070,0,\"test\",[\"i32:59\"]],[\"invoke\",2072,0,\"test\",[\"i32:61\"]],[\"invoke\",2074,0,\"test\",[\"i32:63\"]],[\"module\",2076,90],[\"invoke\",2105,0,\"test\",[\"i32:0\"]],[\"invoke\",2106,0,\"test\",[\"i32:1\"]],[\"invoke\",2108,0,\"test\",[\"i32:3\"]],[\"invoke\",2110,0,\"test\",[\"i32:5\"]],[\"invoke\",2111,0,\"test\",[\"i32:6\"]],[\"invoke\",2113,0,\"test\",[\"i32:8\"]],[\"invoke\",2115,0,\"test\",[\"i32:10\"]],[\"invoke\",2116,0,\"test\",[\"i32:11\"]],[\"invoke\",2118,0,\"test\",[\"i32:13\"]],[\"invoke\",2120,0,\"test\",[\"i32:15\"]],[\"module\",2122,91],[\"file\",\"table_set.wast\"],[\"module\",1,92],[\"invoke\",29,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",30,0,\"set-externref\",[\"i32:0\",\"externref:1\"]],[\"invoke\",31,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",32,0,\"set-externref\",[\"i32:0\",\"externref:null\"]],[\"invoke\",33,0,\"get-externref\",[\"i32:0\"]],[\"invoke\",35,0,\"get-funcref\",[\"i32:0\"]],[\"invoke\",36,0,\"set-funcref-from\",[\"i32:0\",\"i32:1\"]],[\"invoke\",37,0,\"is_null-funcref\",[\"i32:0\"]],[\"invoke\",38,0,\"set-funcref\",[\"i32:0\",\"funcref:null\"]],[\"invoke\",39,0,\"get-funcref\",[\"i32:0\"]],[\"invoke\",41,0,\"set-externref\",[\"i32:2\",\"externref:null\"]],[\"invoke\",42,0,\"set-funcref\",[\"i32:3\",\"funcref:null\"]],[\"invoke\",43,0,\"set-externref\",[\"i32:4294967295\",\"externref:null\"]],[\"invoke\",44,0,\"set-funcref\",[\"i32:4294967295\",\"funcref:null\"]],[\"invoke\",46,0,\"set-externref\",[\"i32:2\",\"externref:0\"]],[\"invoke\",47,0,\"set-funcref-from\",[\"i32:3\",\"i32:1\"]],[\"invoke\",48,0,\"set-externref\",[\"i32:4294967295\",\"externref:0\"]],[\"invoke\",49,0,\"set-funcref-from\",[\"i32:4294967295\",\"i32:1\"]],[\"file\",\"table_size.wast\"],[\"module\",1,93],[\"invoke\",26,0,\"size-t0\",[]],[\"invoke\",27,0,\"grow-t0\",[\"i32:1\"]],[\"invoke\",28,0,\"size-t0\",[]],[\"invoke\",29,0,\"grow-t0\",[\"i32:4\"]],[\"invoke\",30,0,\"size-t0\",[]],[\"invoke\",31,0,\"grow-t0\",[\"i32:0\"]],[\"invoke\",32,0,\"size-t0\",[]],[\"invoke\",34,0,\"size-t1\",[]],[\"invoke\",35,0,\"grow-t1\",[\"i32:1\"]],[\"invoke\",36,0,\"size-t1\",[]],[\"invoke\",37,0,\"grow-t1\",[\"i32:4\"]],[\"invoke\",38,0,\"size-t1\",[]],[\"invoke\",39,0,\"grow-t1\",[\"i32:0\"]],[\"invoke\",40,0,\"size-t1\",[]],[\"invoke\",42,0,\"size-t2\",[]],[\"invoke\",43,0,\"grow-t2\",[\"i32:3\"]],[\"invoke\",44,0,\"size-t2\",[]],[\"invoke\",45,0,\"grow-t2\",[\"i32:1\"]],[\"invoke\",46,0,\"size-t2\",[]],[\"invoke\",47,0,\"grow-t2\",[\"i32:0\"]],[\"invoke\",48,0,\"size-t2\",[]],[\"invoke\",49,0,\"grow-t2\",[\"i32:4\"]],[\"invoke\",50,0,\"size-t2\",[]],[\"invoke\",51,0,\"grow-t2\",[\"i32:1\"]],[\"invoke\",52,0,\"size-t2\",[]],[\"invoke\",54,0,\"size-t3\",[]],[\"invoke\",55,0,\"grow-t3\",[\"i32:1\"]],[\"invoke\",56,0,\"size-t3\",[]],[\"invoke\",57,0,\"grow-t3\",[\"i32:3\"]],[\"invoke\",58,0,\"size-t3\",[]],[\"invoke\",59,0,\"grow-t3\",[\"i32:0\"]],[\"invoke\",60,0,\"size-t3\",[]],[\"invoke\",61,0,\"grow-t3\",[\"i32:2\"]],[\"invoke\",62,0,\"size-t3\",[]],[\"invoke\",63,0,\"grow-t3\",[\"i32:1\"]],[\"invoke\",64,0,\"size-t3\",[]],[\"file\",\"elem.wast\"],[\"module\",4,94],[\"module\",80,95],[\"module\",90,96],[\"module\",95,97],[\"module\",101,98],[\"module\",110,99],[\"module\",120,100],[\"module\",127,100],[\"module\",134,101],[\"invoke\",148,0,\"call-7\",[]],[\"invoke\",149,0,\"call-9\",[]],[\"module\",153,102],[\"invoke\",167,0,\"call-7\",[]],[\"invoke\",168,0,\"call-9\",[]],[\"module\",182,103],[\"module\",187,104],[\"module\",193,105],[\"module\",197,106],[\"module\",202,107],[\"module\",207,108],[\"module\",212,109],[\"module\",218,110],[\"module\",224,111],[\"module\",230,112],[\"instantiate\",239,113],[\"instantiate\",248,114],[\"instantiate\",257,115],[\"instantiate\",266,116],[\"instantiate\",273,117],[\"instantiate\",281,118],[\"instantiate\",290,119],[\"instantiate\",298,118],[\"instantiate\",307,120],[\"instantiate\",315,121],[\"instantiate\",324,122],[\"instantiate\",332,123],[\"module\",342,124],[\"invoke\",350,0,\"init\",[]],[\"module\",352,125],[\"invoke\",360,0,\"init\",[]],[\"module\",537,126],[\"invoke\",548,0,\"call-overwritten\",[]],[\"module\",550,127],[\"invoke\",561,0,\"call-overwritten-element\",[]],[\"module\",565,128,\"$module1\"],[\"register\",\"module1\",\"$module1\"],[\"invoke\",585,\"$module1\",\"call-7\",[]],[\"invoke\",586,\"$module1\",\"call-8\",[]],[\"invoke\",587,\"$module1\",\"call-9\",[]],[\"module\",589,129,\"$module2\"],[\"invoke\",598,\"$module1\",\"call-7\",[]],[\"invoke\",599,\"$module1\",\"call-8\",[]],[\"invoke\",600,\"$module1\",\"call-9\",[]],[\"module\",602,130,\"$module3\"],[\"invoke\",611,\"$module1\",\"call-7\",[]],[\"invoke\",612,\"$module1\",\"call-8\",[]],[\"invoke\",613,\"$module1\",\"call-9\",[]],[\"module\",646,131,\"$m\"],[\"register\",\"exporter\",\"$m\"],[\"invoke\",655,\"$m\",\"get\",[\"i32:0\"]],[\"invoke\",656,\"$m\",\"get\",[\"i32:1\"]],[\"invoke\",658,\"$m\",\"set\",[\"i32:0\",\"externref:42\"]],[\"invoke\",659,\"$m\",\"set\",[\"i32:1\",\"externref:137\"]],[\"invoke\",661,\"$m\",\"get\",[\"i32:0\"]],[\"invoke\",662,\"$m\",\"get\",[\"i32:1\"]],[\"module\",664,132],[\"invoke\",668,\"$m\",\"get\",[\"i32:0\"]],[\"invoke\",669,\"$m\",\"get\",[\"i32:1\"]],[\"module\",673,133,\"$module4\"],[\"register\",\"module4\",\"$module4\"],[\"module\",682,134],[\"invoke\",692,0,\"call_imported_elem\",[]],[\"file\",\"ref_func.wast\"],[\"module\",1,135],[\"register\",\"M\"],[\"module\",6,136],[\"invoke\",56,0,\"is_null-f\",[]],[\"invoke\",57,0,\"is_null-g\",[]],[\"invoke\",58,0,\"is_null-v\",[]],[\"invoke\",60,0,\"call-f\",[\"i32:4\"]],[\"invoke\",61,0,\"call-g\",[\"i32:4\"]],[\"invoke\",62,0,\"call-v\",[\"i32:4\"]],[\"invoke\",63,0,\"set-g\",[]],[\"invoke\",64,0,\"call-v\",[\"i32:4\"]],[\"invoke\",65,0,\"set-f\",[]],[\"invoke\",66,0,\"call-v\",[\"i32:4\"]],[\"module\",80,137],[\"file\",\"ref_is_null.wast\"],[\"module\",1,138],[\"invoke\",30,0,\"funcref\",[\"funcref:null\"]],[\"invoke\",31,0,\"externref\",[\"externref:null\"]],[\"invoke\",33,0,\"externref\",[\"externref:1\"]],[\"invoke\",35,0,\"init\",[\"externref:0\"]],[\"invoke\",37,0,\"funcref-elem\",[\"i32:0\"]],[\"invoke\",38,0,\"externref-elem\",[\"i32:0\"]],[\"invoke\",40,0,\"funcref-elem\",[\"i32:1\"]],[\"invoke\",41,0,\"externref-elem\",[\"i32:1\"]],[\"invoke\",43,0,\"deinit\",[]],[\"invoke\",45,0,\"funcref-elem\",[\"i32:0\"]],[\"invoke\",46,0,\"externref-elem\",[\"i32:0\"]],[\"invoke\",48,0,\"funcref-elem\",[\"i32:1\"]],[\"invoke\",49,0,\"externref-elem\",[\"i32:1\"]],[\"file\",\"ref_null.wast\"],[\"module\",1,139],[\"invoke\",9,0,\"externref\",[]],[\"invoke\",10,0,\"funcref\",[]],[\"file\",\"exports.wast\"],[\"module\",3,140],[\"module\",4,141],[\"module\",5,142],[\"module\",7,140],[\"module\",8,143],[\"module\",9,144],[\"module\",10,140],[\"module\",11,140],[\"module\",12,140],[\"module\",13,140],[\"module\",14,140],[\"module\",16,145,\"$Func\"],[\"invoke\",22,0,\"e\",[\"i32:42\"]],[\"invoke\",23,\"$Func\",\"e\",[\"i32:42\"]],[\"module\",24,146],[\"module\",25,146,\"$Other1\"],[\"invoke\",26,\"$Func\",\"e\",[\"i32:42\"]],[\"module\",28,147],[\"invoke\",34,0,\"a\",[]],[\"invoke\",35,0,\"b\",[]],[\"invoke\",36,0,\"c\",[]],[\"module\",74,148],[\"module\",75,149],[\"module\",76,150],[\"module\",78,148],[\"module\",79,148],[\"module\",80,148],[\"module\",81,148],[\"module\",82,148],[\"module\",83,148],[\"module\",85,151,\"$Global\"],[\"get\",89,0,\"e\",[]],[\"get\",90,\"$Global\",\"e\",[]],[\"module\",91,146],[\"module\",92,146,\"$Other2\"],[\"get\",93,\"$Global\",\"e\",[]],[\"module\",131,152],[\"module\",132,153],[\"module\",133,154],[\"module\",135,152],[\"module\",136,155],[\"module\",137,152],[\"module\",138,155],[\"module\",139,152],[\"module\",140,155],[\"module\",141,152],[\"module\",142,155],[\"module\",143,152],[\"module\",144,155],[\"module\",145,152],[\"module\",146,155],[\"module\",186,156],[\"module\",187,157],[\"module\",191,156],[\"module\",192,158],[\"module\",193,156],[\"module\",194,158],[\"module\",195,156],[\"module\",196,158],[\"module\",197,156],[\"module\",198,158],[\"module\",199,156],[\"module\",200,158],[\"module\",201,156],[\"module\",202,158],[\"file\",\"linking.wast\"],[\"module\",3,159,\"$Mf\"],[\"register\",\"Mf\",\"$Mf\"],[\"module\",9,160,\"$Nf\"],[\"invoke\",17,\"$Mf\",\"call\",[]],[\"invoke\",18,\"$Nf\",\"Mf.call\",[]],[\"invoke\",19,\"$Nf\",\"call\",[]],[\"invoke\",20,\"$Nf\",\"call Mf.call\",[]],[\"module\",22,161],[\"register\",\"reexport_f\"],[\"instantiate\",28,162],[\"instantiate\",32,163],[\"module\",39,164,\"$Mg\"],[\"register\",\"Mg\",\"$Mg\"],[\"module\",50,165,\"$Ng\"],[\"get\",67,\"$Mg\",\"glob\",[]],[\"get\",68,\"$Ng\",\"Mg.glob\",[]],[\"get\",69,\"$Ng\",\"glob\",[]],[\"invoke\",70,\"$Mg\",\"get\",[]],[\"invoke\",71,\"$Ng\",\"Mg.get\",[]],[\"invoke\",72,\"$Ng\",\"get\",[]],[\"get\",74,\"$Mg\",\"mut_glob\",[]],[\"get\",75,\"$Ng\",\"Mg.mut_glob\",[]],[\"invoke\",76,\"$Mg\",\"get_mut\",[]],[\"invoke\",77,\"$Ng\",\"Mg.get_mut\",[]],[\"invoke\",79,\"$Mg\",\"set_mut\",[\"i32:241\"]],[\"get\",80,\"$Mg\",\"mut_glob\",[]],[\"get\",81,\"$Ng\",\"Mg.mut_glob\",[]],[\"invoke\",82,\"$Mg\",\"get_mut\",[]],[\"invoke\",83,\"$Ng\",\"Mg.get_mut\",[]],[\"instantiate\",87,166],[\"instantiate\",91,167],[\"module\",96,168,\"$Mref_ex\"],[\"register\",\"Mref_ex\",\"$Mref_ex\"],[\"module\",104,169,\"$Mref_im\"],[\"instantiate\",113,170],[\"instantiate\",117,171],[\"instantiate\",123,172],[\"instantiate\",127,173],[\"module\",134,174,\"$Mt\"],[\"register\",\"Mt\",\"$Mt\"],[\"module\",149,175,\"$Nt\"],[\"invoke\",168,\"$Mt\",\"call\",[\"i32:2\"]],[\"invoke\",169,\"$Nt\",\"Mt.call\",[\"i32:2\"]],[\"invoke\",170,\"$Nt\",\"call\",[\"i32:2\"]],[\"invoke\",171,\"$Nt\",\"call Mt.call\",[\"i32:2\"]],[\"invoke\",173,\"$Mt\",\"call\",[\"i32:1\"]],[\"invoke\",174,\"$Nt\",\"Mt.call\",[\"i32:1\"]],[\"invoke\",175,\"$Nt\",\"call\",[\"i32:1\"]],[\"invoke\",176,\"$Nt\",\"call Mt.call\",[\"i32:1\"]],[\"invoke\",178,\"$Mt\",\"call\",[\"i32:0\"]],[\"invoke\",179,\"$Nt\",\"Mt.call\",[\"i32:0\"]],[\"invoke\",180,\"$Nt\",\"call\",[\"i32:0\"]],[\"invoke\",181,\"$Nt\",\"call Mt.call\",[\"i32:0\"]],[\"invoke\",183,\"$Mt\",\"call\",[\"i32:20\"]],[\"invoke\",184,\"$Nt\",\"Mt.call\",[\"i32:20\"]],[\"invoke\",185,\"$Nt\",\"call\",[\"i32:7\"]],[\"invoke\",186,\"$Nt\",\"call Mt.call\",[\"i32:20\"]],[\"invoke\",188,\"$Nt\",\"call\",[\"i32:3\"]],[\"invoke\",189,\"$Nt\",\"call\",[\"i32:4\"]],[\"module\",191,176,\"$Ot\"],[\"invoke\",204,\"$Mt\",\"call\",[\"i32:3\"]],[\"invoke\",205,\"$Nt\",\"Mt.call\",[\"i32:3\"]],[\"invoke\",206,\"$Nt\",\"call Mt.call\",[\"i32:3\"]],[\"invoke\",207,\"$Ot\",\"call\",[\"i32:3\"]],[\"invoke\",209,\"$Mt\",\"call\",[\"i32:2\"]],[\"invoke\",210,\"$Nt\",\"Mt.call\",[\"i32:2\"]],[\"invoke\",211,\"$Nt\",\"call\",[\"i32:2\"]],[\"invoke\",212,\"$Nt\",\"call Mt.call\",[\"i32:2\"]],[\"invoke\",213,\"$Ot\",\"call\",[\"i32:2\"]],[\"invoke\",215,\"$Mt\",\"call\",[\"i32:1\"]],[\"invoke\",216,\"$Nt\",\"Mt.call\",[\"i32:1\"]],[\"invoke\",217,\"$Nt\",\"call\",[\"i32:1\"]],[\"invoke\",218,\"$Nt\",\"call Mt.call\",[\"i32:1\"]],[\"invoke\",219,\"$Ot\",\"call\",[\"i32:1\"]],[\"invoke\",221,\"$Mt\",\"call\",[\"i32:0\"]],[\"invoke\",222,\"$Nt\",\"Mt.call\",[\"i32:0\"]],[\"invoke\",223,\"$Nt\",\"call\",[\"i32:0\"]],[\"invoke\",224,\"$Nt\",\"call Mt.call\",[\"i32:0\"]],[\"invoke\",225,\"$Ot\",\"call\",[\"i32:0\"]],[\"invoke\",227,\"$Ot\",\"call\",[\"i32:20\"]],[\"module\",229,177],[\"module\",235,178,\"$G1\"],[\"register\",\"G1\",\"$G1\"],[\"module\",237,179,\"$G2\"],[\"get\",241,\"$G2\",\"g\",[]],[\"instantiate\",244,180],[\"instantiate\",253,181],[\"invoke\",262,\"$Mt\",\"call\",[\"i32:7\"]],[\"instantiate\",267,182],[\"invoke\",275,\"$Mt\",\"call\",[\"i32:7\"]],[\"invoke\",276,\"$Mt\",\"call\",[\"i32:8\"]],[\"instantiate\",279,183],[\"invoke\",288,\"$Mt\",\"call\",[\"i32:7\"]],[\"module\",291,184,\"$Mtable_ex\"],[\"register\",\"Mtable_ex\",\"$Mtable_ex\"],[\"module\",297,185],[\"instantiate\",303,186],[\"instantiate\",307,187],[\"module\",314,188,\"$Mm\"],[\"register\",\"Mm\",\"$Mm\"],[\"module\",324,189,\"$Nm\"],[\"invoke\",336,\"$Mm\",\"load\",[\"i32:12\"]],[\"invoke\",337,\"$Nm\",\"Mm.load\",[\"i32:12\"]],[\"invoke\",338,\"$Nm\",\"load\",[\"i32:12\"]],[\"module\",340,190,\"$Om\"],[\"invoke\",349,\"$Mm\",\"load\",[\"i32:12\"]],[\"invoke\",350,\"$Nm\",\"Mm.load\",[\"i32:12\"]],[\"invoke\",351,\"$Nm\",\"load\",[\"i32:12\"]],[\"invoke\",352,\"$Om\",\"load\",[\"i32:12\"]],[\"module\",354,191],[\"instantiate\",360,192],[\"module\",367,193,\"$Pm\"],[\"invoke\",375,\"$Pm\",\"grow\",[\"i32:0\"]],[\"invoke\",376,\"$Pm\",\"grow\",[\"i32:2\"]],[\"invoke\",377,\"$Pm\",\"grow\",[\"i32:0\"]],[\"invoke\",378,\"$Pm\",\"grow\",[\"i32:1\"]],[\"invoke\",379,\"$Pm\",\"grow\",[\"i32:1\"]],[\"invoke\",380,\"$Pm\",\"grow\",[\"i32:0\"]],[\"invoke\",381,\"$Pm\",\"grow\",[\"i32:1\"]],[\"invoke\",382,\"$Pm\",\"grow\",[\"i32:0\"]],[\"instantiate\",385,194],[\"invoke\",393,\"$Mm\",\"load\",[\"i32:0\"]],[\"instantiate\",398,195],[\"invoke\",406,\"$Mm\",\"load\",[\"i32:0\"]],[\"invoke\",407,\"$Mm\",\"load\",[\"i32:327670\"]],[\"instantiate\",410,196],[\"invoke\",419,\"$Mm\",\"load\",[\"i32:0\"]],[\"module\",422,197,\"$Ms\"],[\"register\",\"Ms\",\"$Ms\"],[\"instantiate\",436,198],[\"invoke\",452,\"$Ms\",\"get memory[0]\",[]],[\"invoke\",453,\"$Ms\",\"get table[0]\",[]]]"; diff --git a/tests/corpus/webassembly-wpt-jsapi.mjs b/tests/corpus/webassembly-wpt-jsapi.mjs new file mode 100644 index 000000000..419e655ab --- /dev/null +++ b/tests/corpus/webassembly-wpt-jsapi.mjs @@ -0,0 +1,1117 @@ +// A port of web-platform-tests wasm/jsapi tests for the parts W5 adds: +// global/constructor, global/value-get-set, global/valueOf, +// memory/constructor, memory/grow, table/constructor, table/get-set, +// table/grow, module/imports, module/exports and module/customSections +// (WPT, 3-Clause BSD). Each test keeps its WPT name and body, with these +// changes: modules that WasmModuleBuilder builds at run time are inline +// base64 literals (built by the same builder), a minimal testharness prints +// one line per test, and the assertions the port cannot express are left +// out: the classes as values (prototypes, function name and length, +// property descriptors, branding through Function.prototype.call), +// Symbol arguments, Object.isFrozen and Object.isExtensible of +// ArrayBuffers (general scriptc gaps), and the old buffer's detachment +// after Memory.grow (a documented difference). assert_Global's parameter carries a JSDoc type: +// scriptc answers a Global's valueOf() only on receivers typed as one. +const modules = { + empty: "AGFzbQEAAAA=", + imports: "AGFzbQEAAAABBAFgAAACRAQGbW9kdWxlAmZuAAAGbW9kdWxlBmdsb2JhbAN/AAZtb2R1bGUGbWVtb3J5AgEAgAEGbW9kdWxlBXRhYmxlAXABAIAB", + importsEmptyModule: "AGFzbQEAAAABBAFgAAACLAQAAmZuAAAABmdsb2JhbAN/AAAGbWVtb3J5AgEAgAEABXRhYmxlAXABAIAB", + importsEmptyNames: "AGFzbQEAAAABBAFgAAACHQQBYQAAAAFiAAN/AAFjAAIBAIABAWQAAXABAIAB", + importsEmptyBoth: "AGFzbQEAAAABBAFgAAACGQQAAAAAAAADfwAAAAIBAIABAAABcAEAgAE=", + exports: "AGFzbQEAAAABBwJgAABgAAADAwIAAQQEAXAAAQUFAQEAgAIGEgJ/AUEHC3wBRDMzMzMzM/M/CwcwBgJmbgAAA2ZuMgABBXRhYmxlAQAGZ2xvYmFsAwAHZ2xvYmFsMgMBBm1lbW9yeQIACgcCAgALAgALABEEbmFtZQEKAgACZm4BA2ZuMg==", + exportsEmptyFunction: "AGFzbQEAAAABBAFgAAADAgEABwQBAAAACgQBAgALAAoEbmFtZQEDAQAA", + exportsEmptyTable: "AGFzbQEAAAAEBAFwAAEHBAEAAQA=", + exportsEmptyGlobal: "AGFzbQEAAAAGBgF/AUEHCwcEAQADAA==", + custom: "AGFzbQEAAAAAEARuYW1lV2ViQXNzZW1ibHkACgRuYW1lSlNBUEkADwNmb29XZWJBc3NlbWJseQ==", + customSurrogates: "AGFzbQEAAAAAFgp5ZWXwkJC3ZWV5V2ViQXNzZW1ibHk=", + customReplacement: "AGFzbQEAAAAAEwduYe+/vW1lV2ViQXNzZW1ibHk=", + customCopy: "AGFzbQEAAAAACARjb3B5ESIz", + fn: "AGFzbQEAAAABBAFgAAADAgEABwYBAmZuAAAKBAECAAsADARuYW1lAQUBAAJmbg==", + functions: "AGFzbQEAAAABCAJgAXwAYAAAAwMCAAEHDAICZm4AAANmbjIAAQoHAgIACwIACwARBG5hbWUBCgIAAmZuAQNmbjI=", +}; +const binary = (name) => Buffer.from(modules[name], "base64"); + +// ── a minimal testharness ───────────────────────────────────────────────── +class AssertionError extends Error {} +function fail(message) { + throw new AssertionError(message); +} +function same(a, b) { + return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b; +} +function format_value(v) { + if (typeof v === "string") return JSON.stringify(v); + if (typeof v === "bigint") return `${v}n`; + if (typeof v === "number") return same(v, -0) ? "-0" : String(v); + if (typeof v === "boolean") return String(v); + if (v === null) return "null"; + if (v === undefined) return "undefined"; + return typeof v; +} +function assert_equals(actual, expected, description = "") { + if (!same(actual, expected)) fail(`${description} expected ${format_value(expected)} but got ${format_value(actual)}`); +} +function assert_not_equals(actual, expected, description = "") { + if (same(actual, expected)) fail(`${description} got disallowed value ${format_value(actual)}`); +} +function assert_true(actual, description = "") { + if (actual !== true) fail(`${description} expected true got ${format_value(actual)}`); +} +function assert_false(actual, description = "") { + if (actual !== false) fail(`${description} expected false got ${format_value(actual)}`); +} +function assert_array_equals(actual, expected, description = "") { + if (actual.length !== expected.length) fail(`${description} lengths differ, expected ${expected.length} got ${actual.length}`); + for (let i = 0; i < expected.length; i++) { + if (!same(actual[i], expected[i])) fail(`${description} property ${i}, expected ${format_value(expected[i])} but got ${format_value(actual[i])}`); + } +} +function assert_throws_js(name, func, description = "") { + try { + func(); + } catch (e) { + if (e instanceof AssertionError) throw e; + if (!(e instanceof Error) || e.name !== name) fail(`${description} threw ${e instanceof Error ? e.name : format_value(e)}, expected ${name}`); + return; + } + fail(`${description} did not throw`); +} +let passed = 0; +let failed = 0; +function test(func, name) { + try { + func(); + passed++; + console.log(`PASS ${name}`); + } catch (e) { + failed++; + console.log(`FAIL ${name}: ${e instanceof Error ? e.message : format_value(e)}`); + } +} + +// ── global/constructor.any.js ───────────────────────────────────────────── +/** @param {WebAssembly.Global} actual (typed so that valueOf() reaches the Global) */ +function assert_Global(actual, expected) { + assert_equals(actual.value, expected, "value"); + assert_equals(actual.valueOf(), expected, "valueOf"); +} + +test(() => { + // @ts-ignore: no descriptor + assert_throws_js("TypeError", () => new WebAssembly.Global()); +}, "No arguments"); + +test(() => { + const argument = { value: "i32" }; + // @ts-ignore: called without new + assert_throws_js("TypeError", () => WebAssembly.Global(argument)); +}, "Calling"); + +test(() => { + const order = []; + new WebAssembly.Global( + { + get value() { + order.push("descriptor value"); + return { + toString() { + order.push("descriptor value toString"); + return "f64"; + }, + }; + }, + get mutable() { + order.push("descriptor mutable"); + return false; + }, + }, + { + valueOf() { + order.push("value valueOf()"); + }, + }, + ); + assert_array_equals(order, ["descriptor mutable", "descriptor value", "descriptor value toString", "value valueOf()"]); +}, "Order of evaluation"); + +test(() => { + const invalidArguments = [undefined, null, false, true, "", "test", 1, NaN, {}]; + for (const invalidArgument of invalidArguments) { + // @ts-ignore: an invalid descriptor + assert_throws_js("TypeError", () => new WebAssembly.Global(invalidArgument), `new Global(${format_value(invalidArgument)})`); + } +}, "Invalid descriptor argument"); + +test(() => { + const invalidTypes = ["i16", "i128", "f16", "f128", "u32", "u64", "i32\0"]; + for (const value of invalidTypes) { + const argument = { value }; + // @ts-ignore: an invalid type + assert_throws_js("TypeError", () => new WebAssembly.Global(argument)); + } +}, "Invalid type argument"); + +test(() => { + const argument = { value: "v128" }; + // @ts-ignore: v128 + assert_throws_js("TypeError", () => new WebAssembly.Global(argument)); +}, "Construct v128 global"); + +test(() => { + const argument = { value: "i64" }; + const global = new WebAssembly.Global(argument); + assert_Global(global, 0n); +}, "i64 with default"); + +for (const type of ["i32", "f32", "f64"]) { + test(() => { + const argument = { value: type }; + const global = new WebAssembly.Global(argument); + assert_Global(global, 0); + }, `Default value for type ${type}`); + + const valueArguments = [ + { value: undefined, expected: 0, name: "undefined" }, + { value: null, expected: 0, name: "null" }, + { value: true, expected: 1, name: "true" }, + { value: false, expected: 0, name: "false" }, + { value: 2, expected: 2, name: "2" }, + { value: "3", expected: 3, name: '"3"' }, + { value: { toString() { return "5"; } }, expected: 5, name: "object with toString returning string" }, + { value: { valueOf() { return "8"; } }, expected: 8, name: "object with valueOf returning string" }, + { value: { toString() { return 6; } }, expected: 6, name: "object with toString returning number" }, + { value: { valueOf() { return 9; } }, expected: 9, name: "object with valueOf returning number" }, + ]; + for (const { value, expected, name } of valueArguments) { + test(() => { + const argument = { value: type }; + const global = new WebAssembly.Global(argument, value); + assert_Global(global, expected); + }, `Explicit value ${name} for type ${type}`); + } + + test(() => { + const argument = { value: type }; + assert_throws_js("TypeError", () => new WebAssembly.Global(argument, 0n)); + }, `BigInt value for type ${type}`); +} + +const bigintArguments = [ + { value: undefined, expected: 0n, name: "undefined" }, + { value: true, expected: 1n, name: "true" }, + { value: false, expected: 0n, name: "false" }, + { value: "3", expected: 3n, name: '"3"' }, + { value: 123n, expected: 123n, name: "123n" }, + { value: { toString() { return "5"; } }, expected: 5n, name: "object with toString returning string" }, + { value: { valueOf() { return "8"; } }, expected: 8n, name: "object with valueOf returning string" }, + { value: { toString() { return 6n; } }, expected: 6n, name: "object with toString returning bigint" }, + { value: { valueOf() { return 9n; } }, expected: 9n, name: "object with valueOf returning bigint" }, +]; +for (const { value, expected, name } of bigintArguments) { + test(() => { + const argument = { value: "i64" }; + const global = new WebAssembly.Global(argument, value); + assert_Global(global, expected); + }, `Explicit value ${name} for type i64`); +} + +const invalidBigints = [ + { value: null, name: "null" }, + { value: 666, name: "666" }, + { value: { toString() { return 5; } }, name: "object" }, + { value: { valueOf() { return 8; } }, name: "object" }, +]; +for (const { value: invalidBigint, name } of invalidBigints) { + test(() => { + const argument = { value: "i64" }; + assert_throws_js("TypeError", () => new WebAssembly.Global(argument, invalidBigint)); + }, `Pass non-bigint as i64 Global value: ${name}`); +} + +test(() => { + const argument = { value: "i32" }; + const global = new WebAssembly.Global(argument, 0, {}); + assert_Global(global, 0); +}, "Stray argument"); + +// ── global/value-get-set.any.js and global/valueOf.any.js ──────────────── +for (const type of ["i32", "i64", "f32", "f64"]) { + const [initial, value, invalid] = type === "i64" ? [0n, 1n, 2] : [0, 1, 2n]; + const immutableOptions = [ + { opts: {}, name: "missing" }, + { opts: { mutable: undefined }, name: "undefined" }, + { opts: { mutable: null }, name: "null" }, + { opts: { mutable: false }, name: "false" }, + { opts: { mutable: "" }, name: "empty string" }, + { opts: { mutable: 0 }, name: "zero" }, + ]; + for (const { opts, name } of immutableOptions) { + test(() => { + const global = new WebAssembly.Global({ ...opts, value: type }); + assert_equals(global.value, initial, "initial value"); + assert_equals(global.valueOf(), initial, "initial valueOf"); + assert_throws_js("TypeError", () => { + global.value = value; + }); + assert_equals(global.value, initial, "post-set value"); + assert_equals(global.valueOf(), initial, "post-set valueOf"); + }, `Immutable ${type} (${name})`); + + test(() => { + const global = new WebAssembly.Global({ ...opts, value: type }); + let touched = false; + const value = { + valueOf() { + touched = true; + return 1; + }, + toString() { + touched = true; + return "1"; + }, + }; + assert_throws_js("TypeError", () => { + global.value = value; + }); + assert_false(touched, "should not call valueOf or toString"); + assert_equals(global.value, initial, "post-set value"); + assert_equals(global.valueOf(), initial, "post-set valueOf"); + }, `Immutable ${type} with ToNumber side-effects (${name})`); + } + + const mutableOptions = [ + { opts: { mutable: true }, name: "true" }, + { opts: { mutable: 1 }, name: "one" }, + { opts: { mutable: "x" }, name: "string" }, + ]; + for (const { opts, name } of mutableOptions) { + test(() => { + const global = new WebAssembly.Global({ ...opts, value: type }); + assert_equals(global.value, initial, "initial value"); + assert_equals(global.valueOf(), initial, "initial valueOf"); + global.value = value; + assert_throws_js("TypeError", () => { + global.value = invalid; + }); + assert_equals(global.value, value, "post-set value"); + assert_equals(global.valueOf(), value, "post-set valueOf"); + }, `Mutable ${type} (${name})`); + } +} + +test(() => { + const argument = { value: "i64", mutable: true }; + const global = new WebAssembly.Global(argument); + assert_equals(global.value, 0n, "initial value using ToJSValue"); + const valid = [ + { input: 123n, output: 123n }, + { input: 2n ** 63n, output: -(2n ** 63n) }, + { input: true, output: 1n }, + { input: false, output: 0n }, + { input: "456", output: 456n }, + ]; + for (const { input, output } of valid) { + global.value = input; + assert_equals(global.valueOf(), output, "post-set valueOf"); + } + const invalid = [undefined, null, 0, 1, 4.2]; + for (const input of invalid) { + assert_throws_js("TypeError", () => { + global.value = input; + }); + } +}, "i64 mutability"); + +test(() => { + const argument = { value: "i32" }; + const global = new WebAssembly.Global(argument, 0); + assert_equals(global.valueOf({}), 0); +}, "valueOf: Stray argument"); + +// ── memory/constructor.any.js ───────────────────────────────────────────── +function assert_ArrayBuffer(actual, { size = 0 }, message) { + assert_equals(actual.toString(), "[object ArrayBuffer]", `${message}: toString()`); + assert_equals(actual.byteLength, 0x10000 * size, `${message}: size`); + if (size > 0) { + const array = new Uint8Array(actual); + assert_equals(array[0], 0, `${message}: first element`); + assert_equals(array[array.byteLength - 1], 0, `${message}: last element`); + } +} + +function assert_Memory(memory, { size = 0 }) { + assert_equals(memory.buffer, memory.buffer, "buffer should be idempotent"); + assert_ArrayBuffer(memory.buffer, { size }); +} + +test(() => { + // @ts-ignore: no descriptor + assert_throws_js("TypeError", () => new WebAssembly.Memory()); +}, "Memory: No arguments"); + +test(() => { + const argument = { initial: 0 }; + // @ts-ignore: called without new + assert_throws_js("TypeError", () => WebAssembly.Memory(argument)); +}, "Memory: Calling"); + +test(() => { + const invalidArguments = [undefined, null, false, true, "", "test", 1, NaN, {}]; + for (const invalidArgument of invalidArguments) { + // @ts-ignore: an invalid descriptor + assert_throws_js("TypeError", () => new WebAssembly.Memory(invalidArgument), `new Memory(${format_value(invalidArgument)})`); + } +}, "Memory: Invalid descriptor argument"); + +test(() => { + assert_throws_js("TypeError", () => new WebAssembly.Memory({ initial: undefined })); +}, "Undefined initial value in descriptor"); + +const outOfRangeValues = [NaN, Infinity, -Infinity, -1, 0x100000000, 0x1000000000]; +for (const value of outOfRangeValues) { + test(() => { + assert_throws_js("TypeError", () => new WebAssembly.Memory({ initial: value })); + }, `Memory: Out-of-range initial value in descriptor: ${format_value(value)}`); + + test(() => { + assert_throws_js("TypeError", () => new WebAssembly.Memory({ initial: 0, maximum: value })); + }, `Memory: Out-of-range maximum value in descriptor: ${format_value(value)}`); +} + +test(() => { + assert_throws_js("RangeError", () => new WebAssembly.Memory({ initial: 10, maximum: 9 })); +}, "Memory: Initial value exceeds maximum"); + +test(() => { + const order = []; + new WebAssembly.Memory({ + get maximum() { + order.push("maximum"); + return { + valueOf() { + order.push("maximum valueOf"); + return 1; + }, + }; + }, + get initial() { + order.push("initial"); + return { + valueOf() { + order.push("initial valueOf"); + return 1; + }, + }; + }, + }); + assert_array_equals(order, ["initial", "initial valueOf", "maximum", "maximum valueOf"]); +}, "Memory: Order of evaluation for descriptor"); + +test(() => { + const argument = { initial: 0 }; + const memory = new WebAssembly.Memory(argument); + assert_Memory(memory, { size: 0 }); +}, "Zero initial"); + +test(() => { + const argument = { initial: 4 }; + const memory = new WebAssembly.Memory(argument); + assert_Memory(memory, { size: 4 }); +}, "Non-zero initial"); + +test(() => { + const argument = { initial: 0 }; + const memory = new WebAssembly.Memory(argument, {}); + assert_Memory(memory, { size: 0 }); +}, "Memory: Stray argument"); + +// ── memory/grow.any.js ──────────────────────────────────────────────────── +test(() => { + const argument = { initial: 0 }; + const memory = new WebAssembly.Memory(argument); + // @ts-ignore: no delta + assert_throws_js("TypeError", () => memory.grow()); +}, "grow: Missing arguments"); + +for (const { initial, delta, label } of [ + { initial: 0, delta: 2, label: "Zero initial" }, + { initial: { valueOf() { return 0; } }, delta: { valueOf() { return 2; } }, label: "Zero initial with valueOf" }, + { initial: 3, delta: 2, label: "Non-zero initial" }, +]) { + test(() => { + const memory = new WebAssembly.Memory({ initial }); + const before = Number(initial); + const oldMemory = memory.buffer; + assert_ArrayBuffer(oldMemory, { size: before }, "Buffer before growing"); + const result = memory.grow(delta); + assert_equals(result, before); + const newMemory = memory.buffer; + assert_not_equals(oldMemory, newMemory); + assert_ArrayBuffer(newMemory, { size: before + 2 }, "New buffer after growing"); + }, `grow: ${label}`); +} + +test(() => { + const argument = { initial: 0, maximum: 2 }; + const memory = new WebAssembly.Memory(argument); + const result = memory.grow(2); + assert_equals(result, 0); + assert_ArrayBuffer(memory.buffer, { size: 2 }, "New buffer after growing"); +}, "grow: Zero initial with respected maximum"); + +test(() => { + const argument = { initial: 0, maximum: 2 }; + const memory = new WebAssembly.Memory(argument); + assert_equals(memory.grow(1), 0); + assert_equals(memory.grow(1), 1); + assert_ArrayBuffer(memory.buffer, { size: 2 }, "Buffer after growing twice"); +}, "grow: Zero initial with respected maximum grown twice"); + +test(() => { + const argument = { initial: 1, maximum: 2 }; + const memory = new WebAssembly.Memory(argument); + const oldMemory = memory.buffer; + assert_throws_js("RangeError", () => memory.grow(2)); + assert_equals(memory.buffer, oldMemory); + assert_ArrayBuffer(memory.buffer, { size: 1 }, "Buffer after trying to grow"); +}, "grow: Zero initial growing too much"); + +const outOfRangeDeltas = [undefined, NaN, Infinity, -Infinity, -1, 0x100000000, 0x1000000000]; +for (const value of outOfRangeDeltas) { + test(() => { + const argument = { initial: 0 }; + const memory = new WebAssembly.Memory(argument); + assert_throws_js("TypeError", () => memory.grow(value)); + }, `grow: Out-of-range argument: ${format_value(value)}`); +} + +test(() => { + const argument = { initial: 0 }; + const memory = new WebAssembly.Memory(argument); + const result = memory.grow(2, {}); + assert_equals(result, 0); +}, "grow: Stray argument"); + +// ── table/constructor.any.js ────────────────────────────────────────────── +function assert_equal_to_array(table, expected, message = "") { + assert_equals(table.length, expected.length, `${message}: length`); + assert_throws_js("TypeError", () => table.get(-1), `${message}: table.get(-1)`); + for (let i = 0; i < expected.length; ++i) { + assert_equals(table.get(i), expected[i], `${message}: table.get(${i} of ${expected.length})`); + } + assert_throws_js("RangeError", () => table.get(expected.length), `${message}: table.get(${expected.length} of ${expected.length})`); + assert_throws_js("RangeError", () => table.get(expected.length + 1), `${message}: table.get(${expected.length + 1} of ${expected.length})`); +} + +function assert_Table(actual, expected) { + assert_equals(actual.length, expected.length, "length"); + for (let i = 0; i < expected.length; ++i) { + assert_equals(actual.get(i), null, `actual.get(${i})`); + } +} + +test(() => { + // @ts-ignore: no descriptor + assert_throws_js("TypeError", () => new WebAssembly.Table()); +}, "Table: No arguments"); + +test(() => { + const argument = { element: "anyfunc", initial: 0 }; + // @ts-ignore: called without new + assert_throws_js("TypeError", () => WebAssembly.Table(argument)); +}, "Table: Calling"); + +test(() => { + // @ts-ignore: an empty descriptor + assert_throws_js("TypeError", () => new WebAssembly.Table({})); +}, "Empty descriptor"); + +test(() => { + const invalidArguments = [undefined, null, false, true, "", "test", 1, NaN, {}]; + for (const invalidArgument of invalidArguments) { + // @ts-ignore: an invalid descriptor + assert_throws_js("TypeError", () => new WebAssembly.Table(invalidArgument), `new Table(${format_value(invalidArgument)})`); + } +}, "Table: Invalid descriptor argument"); + +test(() => { + assert_throws_js("TypeError", () => new WebAssembly.Table({ element: "anyfunc", initial: undefined })); +}, "Table: Undefined initial value in descriptor"); + +test(() => { + // @ts-ignore: an undefined element + assert_throws_js("TypeError", () => new WebAssembly.Table({ element: undefined, initial: 0 })); +}, "Undefined element value in descriptor"); + +for (const value of outOfRangeValues) { + test(() => { + assert_throws_js("TypeError", () => new WebAssembly.Table({ element: "anyfunc", initial: value })); + }, `Table: Out-of-range initial value in descriptor: ${format_value(value)}`); + + test(() => { + assert_throws_js("TypeError", () => new WebAssembly.Table({ element: "anyfunc", initial: 0, maximum: value })); + }, `Table: Out-of-range maximum value in descriptor: ${format_value(value)}`); +} + +test(() => { + assert_throws_js("RangeError", () => new WebAssembly.Table({ element: "anyfunc", initial: 10, maximum: 9 })); +}, "Table: Initial value exceeds maximum"); + +test(() => { + const argument = { element: "anyfunc", initial: 0 }; + const table = new WebAssembly.Table(argument); + assert_Table(table, { length: 0 }); +}, "Basic (zero)"); + +test(() => { + const argument = { element: "anyfunc", initial: 5 }; + const table = new WebAssembly.Table(argument); + assert_Table(table, { length: 5 }); +}, "Basic (non-zero)"); + +test(() => { + const argument = { element: "anyfunc", initial: 0 }; + const table = new WebAssembly.Table(argument, null, {}); + assert_Table(table, { length: 0 }); +}, "Table: Stray argument"); + +test(() => { + const table = new WebAssembly.Table({ + // @ts-ignore: an object element + element: { + toString() { + return "anyfunc"; + }, + }, + initial: 1, + }); + assert_Table(table, { length: 1 }); +}, "Type conversion for descriptor.element"); + +test(() => { + const order = []; + new WebAssembly.Table({ + get maximum() { + order.push("maximum"); + return { + valueOf() { + order.push("maximum valueOf"); + return 1; + }, + }; + }, + get initial() { + order.push("initial"); + return { + valueOf() { + order.push("initial valueOf"); + return 1; + }, + }; + }, + get element() { + order.push("element"); + return { + toString() { + order.push("element toString"); + return "anyfunc"; + }, + }; + }, + }); + assert_array_equals(order, ["element", "element toString", "initial", "initial valueOf", "maximum", "maximum valueOf"]); +}, "Table: Order of evaluation for descriptor"); + +test(() => { + const testObject = {}; + const argument = { element: "externref", initial: 3 }; + const table = new WebAssembly.Table(argument, testObject); + assert_equals(table.length, 3); + assert_equals(table.get(0), testObject); + assert_equals(table.get(1), testObject); + assert_equals(table.get(2), testObject); +}, "initialize externref table with default value"); + +test(() => { + const argument = { element: "i32", initial: 3 }; + // @ts-ignore: an invalid element + assert_throws_js("TypeError", () => new WebAssembly.Table(argument)); +}, "initialize table with a wrong element value"); + +test(() => { + const fn = new WebAssembly.Instance(new WebAssembly.Module(binary("fn"))).exports.fn; + const argument = { element: "anyfunc", initial: 3 }; + const table = new WebAssembly.Table(argument, fn); + assert_equals(table.length, 3); + assert_equals(table.get(0), fn); + assert_equals(table.get(1), fn); + assert_equals(table.get(2), fn); +}, "initialize anyfunc table with default value"); + +test(() => { + const argument = { element: "anyfunc", initial: 3 }; + assert_throws_js("TypeError", () => new WebAssembly.Table(argument, {})); + assert_throws_js("TypeError", () => new WebAssembly.Table(argument, "cannot be used as a wasm function")); + assert_throws_js("TypeError", () => new WebAssembly.Table(argument, 37)); +}, "initialize anyfunc table with a bad default value"); + +test(() => { + assert_throws_js("RangeError", () => new WebAssembly.Table({ element: "anyfunc", initial: 3, maximum: 2 }, 37)); +}, "initialize anyfunc table with a bad default value and a bad descriptor"); + +// ── table/get-set.any.js ────────────────────────────────────────────────── +const functions = new WebAssembly.Instance(new WebAssembly.Module(binary("functions")), {}).exports; + +test(() => { + const argument = { element: "anyfunc", initial: 5 }; + const table = new WebAssembly.Table(argument); + // @ts-ignore: no index + assert_throws_js("TypeError", () => table.get()); +}, "Missing arguments: get"); + +test(() => { + const argument = { element: "anyfunc", initial: 5 }; + const table = new WebAssembly.Table(argument); + // @ts-ignore: no index + assert_throws_js("TypeError", () => table.set()); +}, "Missing arguments: set"); + +test(() => { + const argument = { element: "anyfunc", initial: 5 }; + const table = new WebAssembly.Table(argument); + assert_equal_to_array(table, [null, null, null, null, null]); + const { fn, fn2 } = functions; + assert_equals(table.set(0, fn), undefined, "set() returns undefined."); + table.set(2, fn2); + table.set(4, fn); + assert_equal_to_array(table, [fn, null, fn2, null, fn]); + table.set(0, null); + assert_equal_to_array(table, [null, null, fn2, null, fn]); +}, "Basic"); + +test(() => { + const argument = { element: "anyfunc", initial: 5 }; + const table = new WebAssembly.Table(argument); + assert_equal_to_array(table, [null, null, null, null, null]); + const { fn, fn2 } = functions; + table.set(0, fn); + table.set(2, fn2); + table.set(4, fn); + assert_equal_to_array(table, [fn, null, fn2, null, fn]); + table.grow(4); + assert_equal_to_array(table, [fn, null, fn2, null, fn, null, null, null, null]); +}, "Growing"); + +test(() => { + const argument = { element: "anyfunc", initial: 5 }; + const table = new WebAssembly.Table(argument); + assert_equal_to_array(table, [null, null, null, null, null]); + const { fn } = functions; + assert_throws_js("TypeError", () => table.set(-1, fn)); + assert_throws_js("RangeError", () => table.set(5, fn)); + assert_equal_to_array(table, [null, null, null, null, null]); +}, "Setting out-of-bounds"); + +test(() => { + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument); + assert_equal_to_array(table, [null]); + const invalidArguments = [undefined, true, false, "test", 7, NaN, {}]; + for (const argument of invalidArguments) { + assert_throws_js("TypeError", () => table.set(0, argument), `set(${format_value(argument)})`); + } + assert_equal_to_array(table, [null]); +}, "Setting non-function"); + +test(() => { + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument); + assert_equal_to_array(table, [null]); + const fn = function () {}; + assert_throws_js("TypeError", () => table.set(0, fn)); + assert_equal_to_array(table, [null]); +}, "Setting non-wasm function"); + +test(() => { + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument); + assert_equal_to_array(table, [null]); + const fn = () => {}; + assert_throws_js("TypeError", () => table.set(0, fn)); + assert_equal_to_array(table, [null]); +}, "Setting non-wasm arrow function"); + +const outOfRangeIndices = [ + { value: undefined, name: "undefined" }, + { value: NaN, name: "NaN" }, + { value: Infinity, name: "Infinity" }, + { value: -Infinity, name: "-Infinity" }, + { value: -1, name: "-1" }, + { value: 0x100000000, name: "4294967296" }, + { value: 0x1000000000, name: "68719476736" }, + { value: "0x100000000", name: '"0x100000000"' }, + { value: { valueOf() { return 0x100000000; } }, name: "object" }, +]; +for (const { value, name } of outOfRangeIndices) { + test(() => { + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument); + assert_throws_js("TypeError", () => table.get(value)); + }, `Getting out-of-range argument: ${name}`); + + test(() => { + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument); + assert_throws_js("TypeError", () => table.set(value, null)); + }, `Setting out-of-range argument: ${name}`); +} + +test(() => { + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument); + let called = 0; + const value = { + valueOf() { + called++; + return 0; + }, + }; + assert_throws_js("TypeError", () => table.set(value, {})); + assert_equals(called, 1); +}, "Order of argument conversion"); + +test(() => { + const { fn } = functions; + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument); + assert_equals(table.get(0, {}), null); + assert_equals(table.set(0, fn, {}), undefined); +}, "get-set: Stray argument"); + +test(() => { + const fn = new WebAssembly.Instance(new WebAssembly.Module(binary("fn"))).exports.fn; + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument, fn); + assert_equals(table.get(0), fn); + table.set(0); + assert_equals(table.get(0), null); + table.set(0, fn); + assert_equals(table.get(0), fn); + assert_throws_js("TypeError", () => table.set(0, {})); + assert_throws_js("TypeError", () => table.set(0, 37)); +}, "Arguments for anyfunc table set"); + +test(() => { + const testObject = {}; + const argument = { element: "externref", initial: 1 }; + const table = new WebAssembly.Table(argument, testObject); + assert_equals(table.get(0), testObject); + table.set(0); + assert_equals(table.get(0), undefined); + table.set(0, testObject); + assert_equals(table.get(0), testObject); + table.set(0, 37); + assert_equals(table.get(0), 37); +}, "Arguments for externref table set"); + +// ── table/grow.any.js ───────────────────────────────────────────────────── +function nulls(n) { + return Array(n).fill(null); +} + +test(() => { + const argument = { element: "anyfunc", initial: 5 }; + const table = new WebAssembly.Table(argument); + // @ts-ignore: no delta + assert_throws_js("TypeError", () => table.grow()); +}, "Table grow: Missing arguments"); + +test(() => { + const argument = { element: "anyfunc", initial: 5 }; + const table = new WebAssembly.Table(argument); + assert_equal_to_array(table, nulls(5), "before"); + const result = table.grow(3); + assert_equals(result, 5); + assert_equal_to_array(table, nulls(8), "after"); +}, "Table grow: Basic"); + +test(() => { + const argument = { element: "anyfunc", initial: 3, maximum: 5 }; + const table = new WebAssembly.Table(argument); + assert_equal_to_array(table, nulls(3), "before"); + const result = table.grow(2); + assert_equals(result, 3); + assert_equal_to_array(table, nulls(5), "after"); +}, "Reached maximum"); + +test(() => { + const argument = { element: "anyfunc", initial: 2, maximum: 5 }; + const table = new WebAssembly.Table(argument); + assert_equal_to_array(table, nulls(2), "before"); + assert_throws_js("RangeError", () => table.grow(4)); + assert_equal_to_array(table, nulls(2), "after"); +}, "Exceeded maximum"); + +for (const { value, name } of outOfRangeIndices) { + test(() => { + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument); + assert_throws_js("TypeError", () => table.grow(value)); + }, `Table grow: Out-of-range argument: ${name}`); +} + +test(() => { + const argument = { element: "anyfunc", initial: 5 }; + const table = new WebAssembly.Table(argument); + assert_equal_to_array(table, nulls(5), "before"); + const result = table.grow(3, null, {}); + assert_equals(result, 5); + assert_equal_to_array(table, nulls(8), "after"); +}, "Table grow: Stray argument"); + +test(() => { + const fn = new WebAssembly.Instance(new WebAssembly.Module(binary("fn"))).exports.fn; + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument, fn); + assert_equal_to_array(table, [fn], "before"); + const result = table.grow(2, fn); + assert_equals(result, 1); + assert_equal_to_array(table, [fn, fn, fn], "after"); +}, "Grow with exported-function argument"); + +test(() => { + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument); + assert_throws_js("TypeError", () => table.grow(2, {})); +}, "Grow with non-function argument"); + +test(() => { + const argument = { element: "anyfunc", initial: 1 }; + const table = new WebAssembly.Table(argument); + assert_throws_js("TypeError", () => table.grow(2, () => true)); +}, "Grow with JS-function argument"); + +// ── module/imports.any.js and module/exports.any.js ────────────────────── +function assert_descriptors(actual, expected, keys) { + assert_true(Array.isArray(actual), "Should be array"); + assert_true(Object.isExtensible(actual), "isExtensible"); + assert_equals(actual.length, expected.length); + for (let i = 0; i < expected.length; ++i) { + assert_true(Object.isExtensible(actual[i]), "isExtensible"); + assert_array_equals(Object.keys(actual[i]), keys, "keys"); + for (const key of keys) assert_equals(actual[i][key], expected[i][key], key); + } +} +const assert_imports = (imports, expected) => assert_descriptors(imports, expected, ["module", "name", "kind"]); +const assert_exports = (exports, expected) => assert_descriptors(exports, expected, ["name", "kind"]); +const emptyModule = new WebAssembly.Module(binary("empty")); + +for (const which of ["imports", "exports"]) { + test(() => { + // @ts-ignore: no module + assert_throws_js("TypeError", () => (which === "imports" ? WebAssembly.Module.imports() : WebAssembly.Module.exports())); + }, `${which}: Missing arguments`); + + test(() => { + const invalidArguments = [undefined, null, true, "", 1, {}]; + for (const argument of invalidArguments) { + assert_throws_js( + "TypeError", + // @ts-ignore: not a module + () => (which === "imports" ? WebAssembly.Module.imports(argument) : WebAssembly.Module.exports(argument)), + `${which}(${format_value(argument)})`, + ); + } + }, `${which}: Non-Module arguments`); + + test(() => { + const result = which === "imports" ? WebAssembly.Module.imports(emptyModule) : WebAssembly.Module.exports(emptyModule); + assert_true(Array.isArray(result)); + }, `${which}: Return type`); + + test(() => { + if (which === "imports") assert_imports(WebAssembly.Module.imports(emptyModule), []); + else assert_exports(WebAssembly.Module.exports(emptyModule), []); + }, `${which}: Empty module`); + + test(() => { + if (which === "imports") + assert_not_equals(WebAssembly.Module.imports(emptyModule), WebAssembly.Module.imports(emptyModule)); + else assert_not_equals(WebAssembly.Module.exports(emptyModule), WebAssembly.Module.exports(emptyModule)); + }, `${which}: Empty module: array caching`); +} + +test(() => { + const module = new WebAssembly.Module(binary("imports")); + const imports = WebAssembly.Module.imports(module); + const expected = [ + { module: "module", kind: "function", name: "fn" }, + { module: "module", kind: "global", name: "global" }, + { module: "module", kind: "memory", name: "memory" }, + { module: "module", kind: "table", name: "table" }, + ]; + assert_imports(imports, expected); +}, "imports"); + +for (const { key, label, expected } of [ + { + key: "importsEmptyModule", + label: "imports with empty module name", + expected: [ + { module: "", kind: "function", name: "fn" }, + { module: "", kind: "global", name: "global" }, + { module: "", kind: "memory", name: "memory" }, + { module: "", kind: "table", name: "table" }, + ], + }, + { + key: "importsEmptyNames", + label: "imports with empty names", + expected: [ + { module: "a", kind: "function", name: "" }, + { module: "b", kind: "global", name: "" }, + { module: "c", kind: "memory", name: "" }, + { module: "d", kind: "table", name: "" }, + ], + }, + { + key: "importsEmptyBoth", + label: "imports with empty module names and names", + expected: [ + { module: "", kind: "function", name: "" }, + { module: "", kind: "global", name: "" }, + { module: "", kind: "memory", name: "" }, + { module: "", kind: "table", name: "" }, + ], + }, +]) { + test(() => { + const module = new WebAssembly.Module(binary(key)); + assert_imports(WebAssembly.Module.imports(module), expected); + }, label); +} + +test(() => { + assert_imports(WebAssembly.Module.imports(emptyModule, {}), []); +}, "imports: Stray argument"); + +test(() => { + const module = new WebAssembly.Module(binary("exports")); + const exports = WebAssembly.Module.exports(module); + const expected = [ + { kind: "function", name: "fn" }, + { kind: "function", name: "fn2" }, + { kind: "table", name: "table" }, + { kind: "global", name: "global" }, + { kind: "global", name: "global2" }, + { kind: "memory", name: "memory" }, + ]; + assert_exports(exports, expected); +}, "exports"); + +for (const { key, kind } of [ + { key: "exportsEmptyFunction", kind: "function" }, + { key: "exportsEmptyTable", kind: "table" }, + { key: "exportsEmptyGlobal", kind: "global" }, +]) { + test(() => { + const module = new WebAssembly.Module(binary(key)); + assert_exports(WebAssembly.Module.exports(module), [{ kind, name: "" }]); + }, `exports with empty name: ${kind}`); +} + +test(() => { + assert_exports(WebAssembly.Module.exports(emptyModule, {}), []); +}, "exports: Stray argument"); + +// ── module/customSections.any.js ────────────────────────────────────────── +function assert_sections(sections, expected) { + assert_true(Array.isArray(sections), "Should be array"); + assert_true(Object.isExtensible(sections), "isExtensible"); + assert_equals(sections.length, expected.length); + for (let i = 0; i < expected.length; ++i) { + assert_true(sections[i] instanceof ArrayBuffer, "ArrayBuffer"); + assert_array_equals(new Uint8Array(sections[i]), expected[i]); + } +} + +test(() => { + // @ts-ignore: no arguments + assert_throws_js("TypeError", () => WebAssembly.Module.customSections()); + // @ts-ignore: no name + assert_throws_js("TypeError", () => WebAssembly.Module.customSections(emptyModule)); +}, "customSections: Missing arguments"); + +test(() => { + const invalidArguments = [undefined, null, true, "", 1, {}]; + for (const argument of invalidArguments) { + // @ts-ignore: not a module + assert_throws_js("TypeError", () => WebAssembly.Module.customSections(argument, ""), `customSections(${format_value(argument)})`); + } +}, "customSections: Non-Module arguments"); + +test(() => { + assert_sections(WebAssembly.Module.customSections(emptyModule, ""), []); +}, "customSections: Empty module"); + +test(() => { + assert_not_equals(WebAssembly.Module.customSections(emptyModule, ""), WebAssembly.Module.customSections(emptyModule, "")); +}, "customSections: Empty module: array caching"); + +const bytes1 = [87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121]; +const bytes2 = [74, 83, 65, 80, 73]; + +test(() => { + const module = new WebAssembly.Module(binary("custom")); + assert_sections(WebAssembly.Module.customSections(module, "name"), [bytes1, bytes2]); + assert_sections(WebAssembly.Module.customSections(module, "foo"), [bytes1]); + assert_sections(WebAssembly.Module.customSections(module, ""), []); + assert_sections(WebAssembly.Module.customSections(module, "\0"), []); + assert_sections(WebAssembly.Module.customSections(module, "name\0"), []); + assert_sections(WebAssembly.Module.customSections(module, "foo\0"), []); +}, "Custom sections"); + +test(() => { + const name = "yee𐐷eey"; + const module = new WebAssembly.Module(binary("customSurrogates")); + assert_sections(WebAssembly.Module.customSections(module, name), [bytes1]); + assert_sections(WebAssembly.Module.customSections(module, "yee�eey"), []); + assert_sections(WebAssembly.Module.customSections(module, "yee��eey"), []); +}, "Custom sections with surrogate pairs"); + +test(() => { + const module = new WebAssembly.Module(binary("customReplacement")); + assert_sections(WebAssembly.Module.customSections(module, "name"), []); + assert_sections(WebAssembly.Module.customSections(module, "na�me"), [bytes1]); + assert_sections(WebAssembly.Module.customSections(module, "na\uDC01me"), []); +}, "Custom sections with U+FFFD"); + +test(() => { + assert_sections(WebAssembly.Module.customSections(emptyModule, "", {}), []); +}, "customSections: Stray argument"); + +test(() => { + const module = new WebAssembly.Module(binary("customCopy")); + const first = WebAssembly.Module.customSections(module, "copy"); + const second = WebAssembly.Module.customSections(module, "copy"); + assert_equals(first.length, 1); + assert_equals(second.length, 1); + assert_not_equals(first, second); + assert_not_equals(first[0], second[0]); +}, "Custom section buffers are independent copies"); + +test(() => { + const bytes = [0x11, 0x22, 0x33]; + const module = new WebAssembly.Module(binary("customCopy")); + const first = WebAssembly.Module.customSections(module, "copy"); + const second = WebAssembly.Module.customSections(module, "copy"); + const view = new Uint8Array(first[0]); + view[0] = 0xff; + view[1] = 0xee; + view[2] = 0xdd; + const again = WebAssembly.Module.customSections(module, "copy"); + assert_array_equals(new Uint8Array(again[0]), bytes); + assert_array_equals(new Uint8Array(second[0]), bytes); +}, "Mutating a custom section buffer does not change other copies"); + +console.log(`${passed} passed, ${failed} failed`); diff --git a/tests/coverage-fixtures/wasm/ext.so b/tests/coverage-fixtures/wasm/ext.so new file mode 100644 index 0000000000000000000000000000000000000000..d8b6461083bc0ee6db05933d542c24b1df7dea13 GIT binary patch literal 36 rcmZQbEY4+QU|?WmWlUgTtY>CoWMF4!WKOLpVPN25V`O1)WakC|QojTH literal 0 HcmV?d00001 diff --git a/tests/coverage-fixtures/wasm/glue.js b/tests/coverage-fixtures/wasm/glue.js index 631560632..4a18af315 100644 --- a/tests/coverage-fixtures/wasm/glue.js +++ b/tests/coverage-fixtures/wasm/glue.js @@ -8,6 +8,15 @@ export function hasModule() { return existsSync(new URL("./add.wasm", import.meta.url).pathname); } +// WebAssembly shared libraries (quickjs-wasi's extensions) use .so: ext.so +// is a module, native.so is not and is not reported. +export function sharedLibraries() { + return [ + existsSync(new URL("./ext.so", import.meta.url).pathname), + existsSync(new URL("./native.so", import.meta.url).pathname), + ]; +} + export function inlineModule() { return ANSWER; } diff --git a/tests/coverage-fixtures/wasm/main.ts b/tests/coverage-fixtures/wasm/main.ts index a2d80b6b3..4e54283e7 100644 --- a/tests/coverage-fixtures/wasm/main.ts +++ b/tests/coverage-fixtures/wasm/main.ts @@ -1,9 +1,10 @@ // The WebAssembly modules this program can load are visible to the build in -// four ways (wasm/discover.ts): a path the compiler resolves (glue.js), an -// inline base64 literal (glue.js), a .wasm file shipped by a package whose -// code mentions WebAssembly (wasm-fixture-pkg), and the scriptc.wasm list in -// package.json (build/generated.wasm). -import { hasModule, inlineModule } from "./glue.js"; +// four ways (wasm/discover.ts): a path the compiler resolves (glue.js, +// including a .so shared library), an inline base64 literal (glue.js), a +// .wasm file shipped by a package whose code mentions WebAssembly +// (wasm-fixture-pkg), and the scriptc.wasm list in package.json +// (build/generated.wasm). +import { hasModule, inlineModule, sharedLibraries } from "./glue.js"; import { describeModule } from "wasm-fixture-pkg"; -console.log(hasModule(), inlineModule().length, describeModule()); +console.log(hasModule(), inlineModule().length, describeModule(), sharedLibraries()); diff --git a/tests/coverage-fixtures/wasm/native.so b/tests/coverage-fixtures/wasm/native.so new file mode 100644 index 0000000000000000000000000000000000000000..66d7d9f629a698a934bba1fce8f776473cf19b07 GIT binary patch literal 25 gcmb<-^>JfjWMs(8FHuNTC{HZTRmjaxDa}a*09SVhs{jB1 literal 0 HcmV?d00001 diff --git a/tests/diagnostics/webassembly-fences.ts b/tests/diagnostics/webassembly-fences.ts index ffa2f96e3..fe90d41c9 100644 --- a/tests/diagnostics/webassembly-fences.ts +++ b/tests/diagnostics/webassembly-fences.ts @@ -1,18 +1,17 @@ // The parts of the WebAssembly API scriptc does not implement yet refuse at -// each reached use, in each spelling. compile, instantiate, validate, -// Module, Instance and the error classes compile (tests/corpus/webassembly-*). +// each reached use, in each spelling. compile, instantiate, validate, the +// Module, Instance, Memory, Table and Global constructors, Module.imports, +// exports and customSections, and the error classes compile +// (tests/corpus/webassembly-*). async function load(bytes: Uint8Array): Promise { const module = await WebAssembly.compile(bytes); - const memory = new WebAssembly.Memory({ initial: 1 }); - const table = new WebAssembly.Table({ initial: 1, element: "anyfunc" }); - const global = new WebAssembly.Global({ value: "i32", mutable: true }, 1); - console.log(memory.buffer.byteLength, table.length, global.value); console.log(WebAssembly.Module.imports(module).length); - console.log(WebAssembly.Module.customSections(module, "name").length); const streamed = await WebAssembly.instantiateStreaming(fetch("https://example.com/x.wasm")); console.log(streamed.instance); const Ctor = WebAssembly.Module; console.log(Ctor); + const Memory = WebAssembly.Memory; + console.log(new Memory({ initial: 1 })); } await load(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0])); diff --git a/tests/harness/__snapshots__/coverage-wasm.txt b/tests/harness/__snapshots__/coverage-wasm.txt index 0a56ccd1d..9d0ca414a 100644 --- a/tests/harness/__snapshots__/coverage-wasm.txt +++ b/tests/harness/__snapshots__/coverage-wasm.txt @@ -1,8 +1,8 @@ scriptc coverage tests/coverage-fixtures/wasm/main.ts - statements analyzed 8 - compile statically 8 (100%) - in dynamic tier 2 (operate on values typed only at runtime; --explain-dynamic lists them) + statements analyzed 9 + compile statically 9 (100%) + in dynamic tier 4 (operate on values typed only at runtime; --explain-dynamic lists them) npm package compilation: wasm-fixture-pkg static @@ -14,6 +14,9 @@ scriptc coverage tests/coverage-fixtures/wasm/main.ts tests/coverage-fixtures/wasm/add.wasm 41 bytes valid 1 function, 0 imports, 1 export found: path at tests/coverage-fixtures/wasm/glue.js:8 + tests/coverage-fixtures/wasm/ext.so 36 bytes valid + 1 function, 0 imports, 1 export + found: path at tests/coverage-fixtures/wasm/glue.js:15 tests/coverage-fixtures/wasm/node_modules/wasm-fixture-pkg/lib/core.wasm 27 bytes invalid: type mismatch (at byte 27) 1 function, 0 imports, 0 exports found: shipped by the package at tests/coverage-fixtures/wasm/node_modules/wasm-fixture-pkg diff --git a/tests/harness/__snapshots__/webassembly-fences.ts.txt b/tests/harness/__snapshots__/webassembly-fences.ts.txt index f4a1eeae1..49c423707 100644 --- a/tests/harness/__snapshots__/webassembly-fences.ts.txt +++ b/tests/harness/__snapshots__/webassembly-fences.ts.txt @@ -1,71 +1,26 @@ -webassembly-fences.ts:6:22 - error SC2020: 'new WebAssembly.Memory' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API +webassembly-fences.ts:9:26 - error SC2020: 'WebAssembly.instantiateStreaming' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, the Module, Instance, Memory, Table and Global constructors, Module.imports, exports and customSections, and the error classes over modules translated at build time, but not this part of the API - 5 | const module = await WebAssembly.compile(bytes); - 6 | const memory = new WebAssembly.Memory({ initial: 1 }); - | ^~~~~~~~~~~~~~~~~~ - 7 | const table = new WebAssembly.Table({ initial: 1, element: "anyfunc" }); - - hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) - -webassembly-fences.ts:7:21 - error SC2020: 'new WebAssembly.Table' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API - - 6 | const memory = new WebAssembly.Memory({ initial: 1 }); - 7 | const table = new WebAssembly.Table({ initial: 1, element: "anyfunc" }); - | ^~~~~~~~~~~~~~~~~ - 8 | const global = new WebAssembly.Global({ value: "i32", mutable: true }, 1); - - hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) - -webassembly-fences.ts:8:22 - error SC2020: 'new WebAssembly.Global' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API - - 7 | const table = new WebAssembly.Table({ initial: 1, element: "anyfunc" }); - 8 | const global = new WebAssembly.Global({ value: "i32", mutable: true }, 1); - | ^~~~~~~~~~~~~~~~~~ - 9 | console.log(memory.buffer.byteLength, table.length, global.value); - - hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) - -webassembly-fences.ts:9:15 - error SC2004: uses of 'memory' inherit the blocker on its declaration - - 8 | const global = new WebAssembly.Global({ value: "i32", mutable: true }, 1); - 9 | console.log(memory.buffer.byteLength, table.length, global.value); - | ^~~~~~~~~~~~~~~~~~~~~~~~ - 10 | console.log(WebAssembly.Module.imports(module).length); - - hint: the declaration of 'memory' did not compile — fix the diagnostic reported there and these sites clear with it - -webassembly-fences.ts:10:15 - error SC2020: 'WebAssembly.Module.imports' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API - - 9 | console.log(memory.buffer.byteLength, table.length, global.value); - 10 | console.log(WebAssembly.Module.imports(module).length); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~ - 11 | console.log(WebAssembly.Module.customSections(module, "name").length); - - hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) - -webassembly-fences.ts:11:15 - error SC2020: 'WebAssembly.Module.customSections' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API - - 10 | console.log(WebAssembly.Module.imports(module).length); - 11 | console.log(WebAssembly.Module.customSections(module, "name").length); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 12 | const streamed = await WebAssembly.instantiateStreaming(fetch("https://example.com/x.wasm")); - - hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) - -webassembly-fences.ts:12:26 - error SC2020: 'WebAssembly.instantiateStreaming' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API - - 11 | console.log(WebAssembly.Module.customSections(module, "name").length); - 12 | const streamed = await WebAssembly.instantiateStreaming(fetch("https://example.com/x.wasm")); + 8 | console.log(WebAssembly.Module.imports(module).length); + 9 | const streamed = await WebAssembly.instantiateStreaming(fetch("https://example.com/x.wasm")); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 13 | console.log(streamed.instance); + 10 | console.log(streamed.instance); - hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) + hint: the streaming functions, Tag and Exception, and the classes used as values other than with new and instanceof are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) -webassembly-fences.ts:14:16 - error SC2020: 'WebAssembly.Module' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, Module, Instance and the error classes over modules translated at build time, but not this part of the API +webassembly-fences.ts:11:16 - error SC2020: 'WebAssembly.Module' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, the Module, Instance, Memory, Table and Global constructors, Module.imports, exports and customSections, and the error classes over modules translated at build time, but not this part of the API - 13 | console.log(streamed.instance); - 14 | const Ctor = WebAssembly.Module; + 10 | console.log(streamed.instance); + 11 | const Ctor = WebAssembly.Module; | ^~~~~~~~~~~~~~~~~~ - 15 | console.log(Ctor); + 12 | console.log(Ctor); - hint: the Memory, Table and Global constructors, Module.imports, exports and customSections, and the streaming functions are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) \ No newline at end of file + hint: the streaming functions, Tag and Exception, and the classes used as values other than with new and instanceof are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) + +webassembly-fences.ts:13:18 - error SC2020: 'WebAssembly.Memory' is not supported yet: scriptc implements WebAssembly.compile, instantiate, validate, the Module, Instance, Memory, Table and Global constructors, Module.imports, exports and customSections, and the error classes over modules translated at build time, but not this part of the API + + 12 | console.log(Ctor); + 13 | const Memory = WebAssembly.Memory; + | ^~~~~~~~~~~~~~~~~~ + 14 | console.log(new Memory({ initial: 1 })); + + hint: the streaming functions, Tag and Exception, and the classes used as values other than with new and instanceof are planned; 'scriptc coverage' lists the modules this program loads (https://scriptc.dev/limitations) \ No newline at end of file diff --git a/tests/harness/coverage.test.ts b/tests/harness/coverage.test.ts index f1347bf23..9d67f39c1 100644 --- a/tests/harness/coverage.test.ts +++ b/tests/harness/coverage.test.ts @@ -44,8 +44,9 @@ test("unreached blockers report in their own group", async () => { }); test("WebAssembly modules the build can see report with their sources", async () => { - // A resolved path and an inline literal (glue.js), a packaged .wasm - // (wasm-fixture-pkg), and package.json's scriptc.wasm list. + // A resolved path, a resolved .so shared library and an inline literal + // (glue.js), a packaged .wasm (wasm-fixture-pkg), and package.json's + // scriptc.wasm list. A resolved .so that is not a module is not reported. await expect(report(fixture("wasm/main.ts"))).toMatchFileSnapshot( "__snapshots__/coverage-wasm.txt", ); @@ -61,6 +62,7 @@ test("WebAssembly modules the build can see report with their sources", async () ).toEqual([ ["inline", "valid", [], ["inline"]], ["tests/coverage-fixtures/wasm/add.wasm", "valid", [], ["path", "config"]], + ["tests/coverage-fixtures/wasm/ext.so", "valid", [], ["path"]], [ "tests/coverage-fixtures/wasm/node_modules/wasm-fixture-pkg/lib/core.wasm", "invalid", @@ -70,7 +72,7 @@ test("WebAssembly modules the build can see report with their sources", async () ["tests/coverage-fixtures/wasm/build/generated.wasm", "unsupported", ["simd"], ["config"]], ]); const envelope = coverageEnvelope(coverage, { compilerVersion: "test" }); - expect(envelope.wasmModules?.map((m) => m.sha256.length)).toEqual([64, 64, 64, 64]); + expect(envelope.wasmModules?.map((m) => m.sha256.length)).toEqual([64, 64, 64, 64, 64]); }); test("divergences report as warnings, never as blockers", async () => { diff --git a/tests/wasm-spec/corpus/dylink-ext.wat b/tests/wasm-spec/corpus/dylink-ext.wat new file mode 100644 index 000000000..87023c646 --- /dev/null +++ b/tests/wasm-spec/corpus/dylink-ext.wat @@ -0,0 +1,42 @@ +;; tests/corpus/webassembly-dylink: an extension shaped like quickjs-wasi's +;; WebAssembly shared libraries (wasi-sdk -shared): it shares the main +;; module's memory and table, places its data and functions at the +;; __memory_base and __table_base the loader assigns, reaches the main +;; module through GOT.mem and GOT.func globals and env imports, and leaves +;; one symbol unresolved and one resolved by its own export. The program's +;; base64 copy appends the dylink.0 section: memory size 48 (alignment 2^2), +;; table size 2, needed "libc.so". +(module + (type $i_i (func (param i32) (result i32))) + (import "env" "memory" (memory 1)) + (import "env" "__indirect_function_table" (table 0 funcref)) + (import "env" "__stack_pointer" (global $sp (mut i32))) + (import "env" "__memory_base" (global $mb i32)) + (import "env" "__table_base" (global $tb i32)) + (import "GOT.mem" "counter" (global $got_counter (mut i32))) + (import "GOT.func" "helper" (global $got_helper (mut i32))) + (import "env" "js_register" (func $js_register (param i32 i32) (result i32))) + (import "env" "missing_symbol" (func $missing (param i32) (result i32))) + (import "env" "self_symbol" (func $self (param i32) (result i32))) + (data (global.get $mb) "name=demo\0aversion=1.2\00") + (elem (global.get $tb) $triple $via_helper) + (func $triple (type $i_i) (i32.mul (local.get 0) (i32.const 3))) + (func $via_helper (type $i_i) + (call_indirect (type $i_i) (local.get 0) (global.get $got_helper))) + (func (export "__wasm_apply_data_relocs") + (global.set $got_counter (i32.add (global.get $mb) (i32.const 32)))) + (func (export "__wasm_call_ctors") + (i32.store (global.get $got_counter) (i32.const 5))) + (func (export "qjs_ext_demo_init") (param i32 i32) (result i32) + (drop (call $js_register (local.get 0) (global.get $tb))) + (drop (call $js_register (local.get 0) (i32.add (global.get $tb) (i32.const 1)))) + (i32.sub (local.get 1) (i32.const 200))) + (func (export "qjs_ext_demo_versions") (result i32) (global.get $mb)) + (func (export "self_symbol") (param i32) (result i32) (i32.add (local.get 0) (i32.const 1))) + (func (export "use_self") (param i32) (result i32) (call $self (local.get 0))) + (func (export "use_missing") (param i32) (result i32) (call $missing (local.get 0))) + (func (export "stack_pointer") (result i32) (global.get $sp)) + (func (export "bump_counter") (result i32) + (i32.store (global.get $got_counter) (i32.add (i32.load (global.get $got_counter)) (i32.const 1))) + (i32.load (global.get $got_counter))) +) diff --git a/tests/wasm-spec/corpus/dylink-main.wat b/tests/wasm-spec/corpus/dylink-main.wat new file mode 100644 index 000000000..0cba26bb3 --- /dev/null +++ b/tests/wasm-spec/corpus/dylink-main.wat @@ -0,0 +1,33 @@ +;; tests/corpus/webassembly-dylink: the main module of a dynamically linked +;; program, shaped like quickjs-wasi's quickjs.wasm: it exports its memory, +;; its function table, __stack_pointer, malloc and the entry points an +;; extension's init function calls. +(module + (type $i_i (func (param i32) (result i32))) + (memory (export "memory") 2) + (table (export "__indirect_function_table") 4 funcref) + (global $sp (export "__stack_pointer") (mut i32) (i32.const 65536)) + (global $heap (mut i32) (i32.const 1024)) + (global $registered (mut i32) (i32.const 0)) + (func (export "malloc") (param i32) (result i32) + (local i32) + (local.set 1 (global.get $heap)) + (global.set $heap + (i32.and (i32.add (i32.add (global.get $heap) (local.get 0)) (i32.const 15)) (i32.const -16))) + (local.get 1)) + (func (export "qjs_get_context_ptr") (result i32) (i32.const 100)) + (func (export "qjs_get_runtime_ptr") (result i32) (i32.const 200)) + ;; js_register(ctx, tableIndex): remembers a function an extension adds. + (func (export "js_register") (param i32 i32) (result i32) + (i32.store + (i32.add (i32.const 512) (i32.mul (global.get $registered) (i32.const 4))) + (local.get 1)) + (global.set $registered (i32.add (global.get $registered) (i32.const 1))) + (global.get $registered)) + ;; js_call(n, x): calls the n-th registered function through the table. + (func (export "js_call") (param i32 i32) (result i32) + (call_indirect (type $i_i) + (local.get 1) + (i32.load (i32.add (i32.const 512) (i32.mul (local.get 0) (i32.const 4)))))) + (func (export "helper") (param i32) (result i32) (i32.add (local.get 0) (i32.const 1000))) +) diff --git a/tests/wasm-spec/corpus/jsapi-own.wat b/tests/wasm-spec/corpus/jsapi-own.wat new file mode 100644 index 000000000..be2795793 --- /dev/null +++ b/tests/wasm-spec/corpus/jsapi-own.wat @@ -0,0 +1,11 @@ +;; tests/corpus/webassembly-jsapi.mjs: a module that defines and exports a +;; memory, a table and globals, exported twice each, for identity and for +;; importing what one instance exports into another. +(module + (memory (export "mem") (export "mem2") 1 4) + (table (export "tab") 2 8 funcref) + (global (export "g") (export "g2") (mut i32) (i32.const 7)) + (global (export "fixed") f64 (f64.const 1.5)) + (func (export "id") (param i32) (result i32) (local.get 0)) + (elem (i32.const 1) 0) +) diff --git a/tests/wasm-spec/corpus/jsapi.wat b/tests/wasm-spec/corpus/jsapi.wat new file mode 100644 index 000000000..63e2d4241 --- /dev/null +++ b/tests/wasm-spec/corpus/jsapi.wat @@ -0,0 +1,37 @@ +;; tests/corpus/webassembly-jsapi.mjs: imports of every kind, filled by the +;; Memory, Table and Global constructors. The program's base64 copy also +;; carries custom sections ("dylink.0" [1 2 3], "meta" "hello", "dylink.0" +;; [4 5] and "" []), appended after wat2wasm. +(module + (import "env" "log" (func $log (param i32))) + (import "env" "memory" (memory 1 4)) + (import "env" "table" (table 2 8 funcref)) + (import "env" "counter" (global $counter (mut i32))) + (import "env" "scale" (global $scale f64)) + (import "env" "big" (global $big (mut i64))) + (import "env" "ref" (global $ref (mut externref))) + (type $i_i (func (param i32) (result i32))) + (func $double (type $i_i) (i32.mul (local.get 0) (i32.const 2))) + (func $square (type $i_i) (i32.mul (local.get 0) (local.get 0))) + (elem (i32.const 0) $double $square) + (func (export "bump") (result i32) + (global.set $counter (i32.add (global.get $counter) (i32.const 1))) + (global.get $counter)) + (func (export "scaled") (param f64) (result f64) (f64.mul (local.get 0) (global.get $scale))) + (func (export "bigAdd") (param i64) (global.set $big (i64.add (global.get $big) (local.get 0)))) + (func (export "getRef") (result externref) (global.get $ref)) + (func (export "setRef") (param externref) (global.set $ref (local.get 0))) + (func (export "apply") (param i32 i32) (result i32) + (call_indirect (type $i_i) (local.get 1) (local.get 0))) + (func (export "store") (param i32 i32) (i32.store8 (local.get 0) (local.get 1))) + (func (export "load") (param i32) (result i32) (i32.load8_u (local.get 0))) + (func (export "size") (result i32) (memory.size)) + (func (export "grow") (param i32) (result i32) (memory.grow (local.get 0))) + (func (export "tableSize") (result i32) (table.size 0)) + (func (export "say") (param i32) (call $log (local.get 0))) + (export "memory" (memory 0)) + (export "table" (table 0)) + (export "counter" (global $counter)) + (export "alsoCounter" (global $counter)) + (export "double" (func $double)) +) diff --git a/tests/wasm-spec/gen.mjs b/tests/wasm-spec/gen.mjs index 3019c56f5..bfb6dd9ee 100644 --- a/tests/wasm-spec/gen.mjs +++ b/tests/wasm-spec/gen.mjs @@ -10,10 +10,10 @@ * --spec /test/core * * Left out: modules given as text, modules the decoder does not accept - * within the translatable feature level, modules that import a spectest - * memory or table (the Memory and Table constructors are not supported - * yet) and every command that targets them, and commands with v128 - * values. Also left out, because they test NaN payloads, which neither + * within the translatable feature level and every command that targets + * them, and commands with v128 values. The runner's spectest module + * provides the harness's memory and table (new WebAssembly.Memory and + * Table), so modules that import them run. Also left out, because they test NaN payloads, which neither * side preserves the way the other does: actions whose f32 or f64 * arguments are NaNs other than the canonical quiet NaN (V8 and scriptc * carry NaN payloads through JavaScript numbers differently), and @@ -113,6 +113,7 @@ export const GROUPS = { "exports", "linking", ], + imports: ["imports", "table", "names"], }; const MAX_ACTIONS = 400; @@ -204,13 +205,7 @@ for (const [group, names] of Object.entries(GROUPS)) { } const bytes = readFileSync(join(dir, c.filename)); const summary = analyzeWasm(new Uint8Array(bytes)); - const imports = WebAssembly.Module.imports(new WebAssembly.Module(bytes)); - const usable = - summary.status === "valid" && - !imports.some( - (i) => i.module === "spectest" && (i.kind === "memory" || i.kind === "table"), - ); - if (!usable) { + if (summary.status !== "valid") { if (c.type === "module") { currentSkipped = true; if (c.name) skipped.add(c.name); diff --git a/tests/wasm-spec/runner.mjs b/tests/wasm-spec/runner.mjs index 5c1b8b6b4..25e8ed393 100644 --- a/tests/wasm-spec/runner.mjs +++ b/tests/wasm-spec/runner.mjs @@ -5,7 +5,8 @@ * error. Module bytes are inline base64 literals in each program's * data.mjs, which the build translates. */ -/** The spec harness's `spectest` module, without its memory and table. */ +/** The spec harness's `spectest` module (the reference interpreter's JS + * harness), with its memory and table. */ function spectestImports(log) { return { print() { @@ -33,6 +34,8 @@ function spectestImports(log) { global_i64: 666n, global_f32: 666.6, global_f64: 666.6, + table: new WebAssembly.Table({ initial: 10, maximum: 20, element: "anyfunc" }), + memory: new WebAssembly.Memory({ initial: 1, maximum: 2 }), }; } From cfb50d16e288a4b6b7fb9581d0e3f5d7a306f315 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 14:03:44 -0700 Subject: [PATCH 03/39] Specialize variadic generic wrappers to the wrapped function's signature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Higher-order wrappers over `(...args: any) => any` that forward `arguments` with `fn.apply(this, arguments)` and type their options with `Parameters` / `ReturnType`, and their rest-tuple rewrite, did not compile. Generic calls already monomorphize per call site; these pieces now resolve to that site's concrete signature: - Rest parameters typed as fixed tuples (`...args: [A, B]`, `...args: A` bound to a tuple, `...args: Parameters`) flatten to positional parameters, so `(...args: [A, B]) => R` and `(a: A, b: B) => R` share one function type. Trailing optional positions become `T | undefined` slots. - `Parameters`, `ReturnType`, `Awaited>` and the `ReturnType extends PromiseLike ? U : …` spelling resolve through F's binding. - A parameterless function expression reading `arguments` lowers against the fixed signature its value is asserted to (or contextually typed as); `arguments` is that signature's tuple. - `f.apply(thisArg, args)` and `f(...args)` over a forwarded tuple call directly, passing `thisArg` as the receiver. A tuple that is only forwarded is never allocated. - `fn.name` on a function parameter folds to the call site's static name; the instantiation key carries it. Also: optional callback fields narrowed at the call (`o.cb ? o.cb(x) : …`) compile, effect-free surplus arguments to fixed-arity function values are dropped, and `arguments.length` no longer counts a `this` parameter. Co-Authored-By: Claude Opus 5.5 --- .../language-features/generics.mdx | 1 + .../src/frontend/lowering/call-arguments.ts | 64 ++- .../src/frontend/lowering/call-signatures.ts | 94 +++- .../lowering/expressions/optional-chains.ts | 17 + .../frontend/lowering/generic-functions.ts | 31 +- .../src/frontend/lowering/lower-calls.ts | 20 + .../src/frontend/lowering/lower-exprs.ts | 34 +- .../src/frontend/lowering/lower-functions.ts | 3 + .../src/frontend/lowering/lower-stmts.ts | 14 + .../compiler/src/frontend/lowering/lowerer.ts | 96 ++++ .../lowering/static-function-names.ts | 221 ++++++++ .../src/frontend/lowering/typed-arguments.ts | 511 ++++++++++++++++++ packages/compiler/src/frontend/type-mapper.ts | 283 +++++++++- ...0-variadic-wrapper-arguments-apply.ts.json | 6 + .../6381-variadic-wrapper-async.ts.json | 6 + ...6382-variadic-wrapper-methods-this.ts.json | 6 + .../6383-variadic-wrapper-rest-tuple.ts.json | 6 + .../6384-variadic-wrapper-nested.ts.json | 6 + .../variadic-wrapper-fences.ts.json | 6 + .../6380-variadic-wrapper-arguments-apply.ts | 77 +++ tests/corpus/6381-variadic-wrapper-async.ts | 81 +++ .../6382-variadic-wrapper-methods-this.ts | 46 ++ .../6383-variadic-wrapper-rest-tuple.ts | 54 ++ tests/corpus/6384-variadic-wrapper-nested.ts | 37 ++ tests/diagnostics/arrow-bind.ts | 3 +- tests/diagnostics/variadic-wrapper-fences.ts | 28 + tests/harness/__snapshots__/arrow-bind.ts.txt | 17 +- .../variadic-wrapper-fences.ts.txt | 29 + 28 files changed, 1763 insertions(+), 34 deletions(-) create mode 100644 packages/compiler/src/frontend/lowering/static-function-names.ts create mode 100644 packages/compiler/src/frontend/lowering/typed-arguments.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6380-variadic-wrapper-arguments-apply.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6381-variadic-wrapper-async.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6382-variadic-wrapper-methods-this.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6383-variadic-wrapper-rest-tuple.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6384-variadic-wrapper-nested.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/variadic-wrapper-fences.ts.json create mode 100644 tests/corpus/6380-variadic-wrapper-arguments-apply.ts create mode 100644 tests/corpus/6381-variadic-wrapper-async.ts create mode 100644 tests/corpus/6382-variadic-wrapper-methods-this.ts create mode 100644 tests/corpus/6383-variadic-wrapper-rest-tuple.ts create mode 100644 tests/corpus/6384-variadic-wrapper-nested.ts create mode 100644 tests/diagnostics/variadic-wrapper-fences.ts create mode 100644 tests/harness/__snapshots__/variadic-wrapper-fences.ts.txt diff --git a/docs/content/limitations/language-features/generics.mdx b/docs/content/limitations/language-features/generics.mdx index 7668e0d47..5b252ebf0 100644 --- a/docs/content/limitations/language-features/generics.mdx +++ b/docs/content/limitations/language-features/generics.mdx @@ -1 +1,2 @@ - **Generics:** Generic functions declared inside other functions, generic class expressions, and generic methods requiring dynamic dispatch are unsupported. Generic classes can extend generic bases when each specialization has a concrete layout. Independent concrete uses have no specialization-count limit; recursively expanding demands and type layouts produce diagnostics. Other generic calls compile when the target resolves statically. Generic function values require a concrete signature at use and a binding that is never reassigned. +- **Variadic wrappers:** A generic higher-order wrapper is specialized to each wrapped function's exact signature. `Parameters`, `ReturnType`, and rest parameters typed as fixed tuples become that signature's parameter list. A function expression with no parameters that reads `arguments` compiles only when its value is asserted to, or contextually typed as, one fixed-arity signature; `arguments` is then that signature's tuple. Forwarding it with `fn.apply(this, arguments)` passes `this` through. Reading `fn.name` on a wrapped function requires its name to be known where the wrapper is called, such as a function declaration or a `const`-bound function. `Parameters` over a signature with optional or array-typed rest parameters is unsupported, because that tuple has no fixed length. diff --git a/packages/compiler/src/frontend/lowering/call-arguments.ts b/packages/compiler/src/frontend/lowering/call-arguments.ts index f5600b033..db7691a1c 100644 --- a/packages/compiler/src/frontend/lowering/call-arguments.ts +++ b/packages/compiler/src/frontend/lowering/call-arguments.ts @@ -1,3 +1,4 @@ +import { forwardedTupleType, pureForwardedValues, stripTypeWrappers } from "./typed-arguments.js"; import { dynUndefinedExpr } from "../../ir/build.js"; import { InternalCompilerError } from "../../errors.js"; import * as ts from "../ts7/adapter.js"; @@ -26,13 +27,13 @@ import { checkedIterableSpread } from "./checked-iterable-spread.js"; import { type ParamShape } from "./call-signatures.js"; import { arrayValueRead, arrayValueType } from "./array-values.js"; import { buildArrayConversion } from "./coercions/builders.js"; -import { typeKey } from "../type-mapper.js"; +import { restTupleElementTypes, typeKey } from "../type-mapper.js"; function fixedTupleSpreadInfo( lowerer: Lowerer, node: ts.Expression, ): { type: IrType & { kind: "record" }; fields: { name: string; type: IrType }[] } | null { - const type = lowerer.mapTypeOf(lowerer.typeOf(node)); + const type = forwardedTupleType(lowerer, node) ?? lowerer.mapTypeOf(lowerer.typeOf(node)); if (type?.kind !== "record") return null; const shape = lowerer.shapes.get(type.shapeId); if (!shape?.tuple || shape.fields.length === 0) return null; @@ -42,6 +43,18 @@ function fixedTupleSpreadInfo( }; } +/** `...t` over a provably EMPTY tuple bound to a plain name (`[]`, a rest + * tuple whose type parameter or `Parameters` resolved to no positions): + * it contributes no arguments, and reading the name has no effect. */ +function emptyTupleSpread(lowerer: Lowerer, node: ts.Expression): boolean { + let operand = node; + while (ts.isParenthesizedExpression(operand)) operand = operand.expression; + if (!ts.isIdentifier(operand)) return false; + const forwarded = forwardedTupleType(lowerer, operand); + if (forwarded) return forwarded.kind === "array"; + return restTupleElementTypes(lowerer.typeOf(operand), lowerer.typeCtx)?.length === 0; +} + export function completeArgs( lowerer: Lowerer, argNodes: readonly ts.Expression[], @@ -59,7 +72,9 @@ export function completeArgs( // graph. Ordinary calls and fixed tuples never need that analysis. const runtimeSpreads = argNodes.filter( (arg): arg is ts.SpreadElement => - ts.isSpreadElement(arg) && !fixedTupleSpreadInfo(lowerer, arg.expression), + ts.isSpreadElement(arg) && + !fixedTupleSpreadInfo(lowerer, arg.expression) && + !emptyTupleSpread(lowerer, arg.expression), ); // Spread operands lowered while choosing the completion, each exactly once. const loweredSpreads = new Map(); @@ -190,6 +205,12 @@ export function completeArgs( sources.push(arg); continue; } + if (emptyTupleSpread(lowerer, arg.expression)) continue; + const pure = pureForwardedValues(lowerer, arg.expression); + if (pure) { + for (const value of pure) sources.push({ ir: value }); + continue; + } const tuple = fixedTupleSpreadInfo(lowerer, arg.expression); if (!tuple) { sources.push(arg); @@ -204,7 +225,13 @@ export function completeArgs( // values as separately written arguments while the saved tuple stays // alive through the call. const spreadLoc = locOf(arg); - const value = lowerer.coerceInto(arg.expression, lowerer.lowerExpr(arg.expression), tuple.type); + // A forwarded tuple seen through type assertions (`...(arguments as + // unknown as Parameters)`) spreads the tuple itself. + const operand = + forwardedTupleType(lowerer, arg.expression) !== null + ? stripTypeWrappers(arg.expression) + : arg.expression; + const value = lowerer.coerceInto(arg.expression, lowerer.lowerExpr(operand), tuple.type); const saved = lowerer.declareHiddenLocal("%callSpread", tuple.type); const savedRef = (): IrExpr => ({ kind: "varRef", @@ -506,9 +533,38 @@ export function completeFuncValueArgs( shapes.push({ type: rest, mode: "rest" }); return completeArgs(lowerer, call.arguments.nodes, shapes, loc, call); } + // A fixed-tuple spread (`fn(...args)` over a tuple-typed rest binding) + // has a compile-time arity: completion flattens it into the positional + // slots exactly like a direct call's. + if ( + funcType.rest !== true && + call.arguments.nodes.some(ts.isSpreadElement) && + call.arguments.nodes.every( + (arg) => + !ts.isSpreadElement(arg) || + fixedTupleSpreadInfo(lowerer, arg.expression) !== null || + emptyTupleSpread(lowerer, arg.expression), + ) + ) { + const shapes: ParamShape[] = funcType.params.map((type) => ({ + type, + mode: omittedArgFor(lowerer, type, loc) ? "omittable" : "required", + })); + return completeArgs(lowerer, call.arguments.nodes, shapes, loc, call); + } const args = call.arguments.nodes.map((arg, index) => lowerer.lowerExprExpecting(arg, funcType.params[index]), ); + // Effect-free surplus arguments of a fixed-arity value (`(r: void) => + // void` drops its void slot) evaluate to nothing observable: drop them, + // as the callee ignores them. + while ( + funcType.rest !== true && + args.length > funcType.params.length && + isSafeToDiscard(args[args.length - 1]!) + ) { + args.pop(); + } for (let i = args.length; i < funcType.params.length; i++) { const absent = omittedArgFor(lowerer, funcType.params[i]!, loc); if (!absent) { diff --git a/packages/compiler/src/frontend/lowering/call-signatures.ts b/packages/compiler/src/frontend/lowering/call-signatures.ts index 9d9c9668c..ef2900a7c 100644 --- a/packages/compiler/src/frontend/lowering/call-signatures.ts +++ b/packages/compiler/src/frontend/lowering/call-signatures.ts @@ -1,3 +1,8 @@ +import { + typedArgumentsCandidate, + typedArgumentsShapes, + typedArgumentsTarget, +} from "./typed-arguments.js"; import { InternalCompilerError } from "../../errors.js"; import * as ts from "../ts7/adapter.js"; import { bodyReadsArguments } from "../arguments-usage.js"; @@ -15,6 +20,7 @@ import { import { isJsSourceFile, isNodeEsmFile } from "../program.js"; import { genResultRecord, + restTupleParamTypes, isAnyArrayType, isUnitOnlyTsType, jsOpenObjectType, @@ -52,6 +58,10 @@ export interface ParamShape { mode: ParamMode; bodyType?: IrType; callDefault?: IrExpr; + /** One flattened position of a fixed-tuple rest parameter + * (restTupleShapes): the declaration's last parameter owns every shape + * from its index on, and the body binds the tuple (declareParams). */ + restTuple?: true; } export interface FnSig { @@ -369,6 +379,28 @@ export function isThisParameter(param: ts.ParameterDeclaration): boolean { return ts.isIdentifier(param.name) && param.name.text === "this"; } +/** A TypeScript rest parameter bound to a name whose type is a fixed tuple + * (`...args: [A, B]`, `...args: A` with A bound to a tuple, `...args: + * Parameters` with F bound): one required shape per position. Call + * sites and function values see the equivalent fixed signature; the body + * rebuilds the tuple (declareParams) unless it only forwards it. Null for + * every other parameter. */ +export function restTupleShapes( + lowerer: Lowerer, + param: ts.ParameterDeclaration, + tsType?: ts.Type, +): ParamShape[] | null { + if ( + param.dotDotDotToken === undefined || + !ts.isIdentifier(param.name) || + isJsSourceFile(param.getSourceFile()) + ) { + return null; + } + const elems = restTupleParamTypes(tsType ?? lowerer.typeOf(param.name), lowerer.typeCtx); + return elems ? elems.map((type) => ({ type, mode: "required", restTuple: true })) : null; +} + /** ParamShapes for a whole parameter list. */ export function paramShapes( lowerer: Lowerer, @@ -376,16 +408,37 @@ export function paramShapes( signature?: ts.Signature, blameOf?: (param: ts.ParameterDeclaration, index: number) => ts.Node, ): ParamShape[] { - if (!signature) - return params.filter((p) => !isThisParameter(p)).map((param) => lowerer.paramShape(param)); + const out: ParamShape[] = []; + if (!signature) { + for (const param of params) { + if (isThisParameter(param)) continue; + const flattened = restTupleShapes(lowerer, param); + if (flattened) out.push(...flattened); + else out.push(lowerer.paramShape(param)); + } + return out; + } const symbols = signature.getParameters(); - return params.map((declParam, i) => { + const shapeAt = (declParam: ts.ParameterDeclaration, i: number): ParamShape => { const stage = lowerer.stageSourceType(declParam.name); if (stage) return { type: stage, mode: "required" as const }; const symbol = symbols[i]; const tsType = symbol ? lowerer.checker.getTypeOfSymbol(symbol) : lowerer.typeOf(declParam.name); + // A call-site instantiation whose concrete argument type does not map + // is that argument's blocker: name it there, with its concrete type, + // rather than as the declaration's unbound type parameter. + if ( + blameOf !== undefined && + !isJsSourceFile(declParam.getSourceFile()) && + (tsType.flags & ts.TypeFlags.Any) === 0 && + declParam.type !== undefined && + mentionsTypeParameter(lowerer, lowerer.checker.getTypeFromTypeNode(declParam.type)) && + lowerer.mapTypeOf(tsType) === null + ) { + lowerer.badType(blameOf(declParam, i), tsType); + } let mapped = jsOpenObjectType( declParam, lowerer.runtimeOptionalBindingType( @@ -416,7 +469,32 @@ export function paramShapes( ); } return { type: mapped, mode: declParam.questionToken ? "omittable" : "required" }; + }; + params.forEach((declParam, i) => { + const symbol = symbols[i]; + const flattened = restTupleShapes( + lowerer, + declParam, + symbol ? lowerer.checker.getTypeOfSymbol(symbol) : undefined, + ); + if (flattened) out.push(...flattened); + else out.push(shapeAt(declParam, i)); }); + return out; +} + +/** A declared type that is (or is a union over) a bare type parameter + * or an instantiation of a generic alias/interface over type arguments. */ +function mentionsTypeParameter(lowerer: Lowerer, t: ts.Type): boolean { + if (t.flags & ts.TypeFlags.TypeParameter) return true; + const mentions = (part: ts.Type): boolean => mentionsTypeParameter(lowerer, part); + if (t.isUnionType()) return ts.constituentTypes(t).some(mentions); + if (t.getAliasTypeArguments().some(mentions)) return true; + return ( + (t.flags & ts.TypeFlags.Object) !== 0 && + ((t as ts.ObjectType).objectFlags & ts.ObjectFlags.Reference) !== 0 && + lowerer.checker.getTypeArguments(t as ts.TypeReference).some(mentions) + ); } /** A default expression may itself yield undefined. Keep that arm in the @@ -758,6 +836,16 @@ export function lambdaSignature( | ts.SetAccessorDeclaration, ): { shapes: ParamShape[]; funcType: IrType & { kind: "func" } } { if (!node.body) lowerer.unsupported("SC1090", node, "function overload signatures"); + // A parameterless function expression forwarding its `arguments`, + // asserted to a fixed signature: that signature is its ABI. + if (typedArgumentsCandidate(node) && !node.typeParameters?.nodes.length) { + const target = typedArgumentsTarget(lowerer, node); + if (target) { + const shapes = typedArgumentsShapes(target); + lowerer.typedArgumentsLambdas.add(node); + return { shapes, funcType: funcTypeFromParamShapes(shapes, target.ret) }; + } + } // A JS replacement of a native stream's write method receives the // actual call tuple, including overloads and omitted arguments. Node's // contextual overload signature cannot define this closure's ABI. diff --git a/packages/compiler/src/frontend/lowering/expressions/optional-chains.ts b/packages/compiler/src/frontend/lowering/expressions/optional-chains.ts index 930e1a7cb..995514a4d 100644 --- a/packages/compiler/src/frontend/lowering/expressions/optional-chains.ts +++ b/packages/compiler/src/frontend/lowering/expressions/optional-chains.ts @@ -1,3 +1,5 @@ +import { isSafeToDiscard } from "./evaluation-safety.js"; +import { completeFuncValueArgs } from "../call-arguments.js"; import { dynUndefinedExpr } from "../../../ir/build.js"; import * as ts from "../../ts7/adapter.js"; import { DYN, STRING, UNDEFINED_T, VOID, isUnitType, typeEquals } from "../../../ir/ir.js"; @@ -429,7 +431,22 @@ export function lowerOptionalChain( if (dotNode === expr && ts.isCallExpression(expr)) { if (narrowed.kind !== "func") lowerer.badType(recvNode, lowerer.typeOf(recvNode)); const params = narrowed.params; + // Forwarded fixed tuples (`f?.(...args)`) complete into the slots. + if (expr.arguments.nodes.some(ts.isSpreadElement)) { + const completed = completeFuncValueArgs(lowerer, expr, narrowed, loc); + const call: IrExpr = { + kind: "callValue", + callee: recvRef, + args: completed, + type: narrowed.ret, + loc, + }; + return lowerer.finishOptionalChain(expr, id, receiver, call, loc); + } const args = expr.arguments.nodes.map((a, i) => lowerer.lowerExprExpecting(a, params[i])); + // Effect-free surplus arguments (a dropped `void` slot) are ignored. + while (narrowed.rest !== true && args.length > params.length && isSafeToDiscard(args.at(-1)!)) + args.pop(); const body: IrExpr = { kind: "callValue", callee: recvRef, args, type: narrowed.ret, loc }; return lowerer.finishOptionalChain(expr, id, receiver, body, loc); } diff --git a/packages/compiler/src/frontend/lowering/generic-functions.ts b/packages/compiler/src/frontend/lowering/generic-functions.ts index bf5f2563d..e1fa5994d 100644 --- a/packages/compiler/src/frontend/lowering/generic-functions.ts +++ b/packages/compiler/src/frontend/lowering/generic-functions.ts @@ -1,3 +1,4 @@ +import { staticNameBindings } from "./static-function-names.js"; import * as ts from "../ts7/adapter.js"; import { bodyReadsArguments } from "../arguments-usage.js"; import type { Lowerer } from "./lowerer.js"; @@ -100,6 +101,9 @@ export interface GenericFnInfo { * names where the slot binds the call site's object type. Computed on * first use. */ implicitPatterns?: (ImplicitPattern | null)[]; + /** Parameter index → symbol for the function parameters whose `.name` + * the body reads (static-function-names.ts); computed on first use. */ + nameReadParams?: Map; } export interface GenericInstance { @@ -140,6 +144,9 @@ export interface GenericInstance { implicitInferReturn?: true; /** An erased instance (every type parameter bound to `unknown`). */ erased?: true; + /** Name-keyed instances: function parameter → its call site's static + * name (null when only known at run time), folded at `.name` reads. */ + staticFnNames?: Map; } /** Defaults bind during inference; collection only resolves symbols in @@ -317,6 +324,7 @@ export function genericCallInstance( // different fields). Non-literal bindings (a key union, plain string) // share one runtime-keyed instance per IR signature, exactly the // widened discipline. + const named = staticNameBindings(lowerer, expr, info); const keyofTps = keyofConstrainedTypeParams(info); if (keyofTps.size > 0) { const tsBindings = new Map(); @@ -333,12 +341,19 @@ export function genericCallInstance( }) .join(","); return internGenericInstance(lowerer, expr, info, params, returnType, () => bindings, { - extraKey: `@${litKey}`, + extraKey: `@${litKey}${named?.key ?? ""}`, tsBindings, + ...(named ? { staticFnNames: named.names } : {}), }); } - return internGenericInstance(lowerer, expr, info, params, returnType, (tsBindings) => - lowerer.inferTypeParamBindings(expr, info, rsig, tsBindings), + return internGenericInstance( + lowerer, + expr, + info, + params, + returnType, + (tsBindings) => lowerer.inferTypeParamBindings(expr, info, rsig, tsBindings), + named ? { extraKey: named.key, staticFnNames: named.names } : undefined, ); } @@ -498,7 +513,11 @@ function internGenericInstance( params: ParamShape[], returnType: IrType, makeBindings: (tsBindings: Map) => Map, - opts?: { extraKey?: string; tsBindings?: Map }, + opts?: { + extraKey?: string; + tsBindings?: Map; + staticFnNames?: Map; + }, ): GenericInstance { // keyof-constrained instantiations append their literal keys // (extraKey): the IR signature alone under-discriminates there — two @@ -541,6 +560,7 @@ function internGenericInstance( bindings, tsBindings, typeArgsText, + ...(opts?.staticFnNames ? { staticFnNames: opts.staticFnNames } : {}), }; info.instances.set(key, inst); lowerer.instantiationQueue.push({ info, inst }); @@ -824,6 +844,8 @@ export function lowerGenericInstance( const prevSuppress = lowerer.suppressStats; const prevClass = lowerer.currentClass; const prevImplicit = lowerer.implicitParamTypes; + const prevStaticFnNames = lowerer.staticFnNames; + lowerer.staticFnNames = inst.staticFnNames ?? null; // A generic METHOD of a generic-class INSTANTIATION lowers under BOTH // binding sets: the receiver instantiation's class type parameters // underneath, the method instantiation's own on top (disjoint symbol @@ -984,6 +1006,7 @@ export function lowerGenericInstance( lowerer.typeParamBindings = prevBindings; lowerer.typeParamTsBindings = prevTsBindings; lowerer.implicitParamTypes = prevImplicit; + lowerer.staticFnNames = prevStaticFnNames; lowerer.instantiationContext = prevContext; lowerer.localClassInstantiations.pop(); lowerer.suppressStats = prevSuppress; diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 67ca01b3f..3bebfd2af 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -1,3 +1,4 @@ +import { isForwardedTupleSpread, lowerForwardingApply } from "./typed-arguments.js"; import { guardNullProto, nullProtoRecordShape } from "./null-prototype.js"; import { lowerUnionEquality, tagEqualityMayMissAlias } from "./strict-equality.js"; import { lowerHashStreamCall } from "./builtins/hash-stream.js"; @@ -1364,6 +1365,9 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { if (ts.isPropertyAccessExpression(expr.expression)) { const intrinsic = fenceNodeModuleMutationCall(lowerer, expr, expr.expression) ?? + // `f.apply(thisArg, args)` forwarding a fixed argument tuple (typed + // `arguments`, a tuple rest parameter): a direct call. + lowerForwardingApply(lowerer, expr, expr.expression) ?? // Builtin namespace imports first (`fs.readFileSync(...)` where fs // is `import * as fs from "node:fs"`): the same tables and fences // as named builtin imports — before anything below tries to lower @@ -1854,6 +1858,19 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { // or marshals the callee and applies through a runtime-built argument // list (lowerSpreadArgsCall). Shapes outside its lanes fall through // to the historical fences. + // Forwarded fixed tuples (`fn(...args)` over a tuple rest parameter or a + // typed `arguments`) have a compile-time arity: complete them into the + // callee's positional slots directly, without the runtime-arity lane. + if ( + callee.type.rest !== true && + expr.arguments.nodes.some(ts.isSpreadElement) && + expr.arguments.nodes.every( + (a) => !ts.isSpreadElement(a) || isForwardedTupleSpread(lowerer, a.expression), + ) + ) { + const args = completeFuncValueArgs(lowerer, expr, callee.type, loc); + return { kind: "callValue", callee, args, type: callee.type.ret, loc }; + } if (expr.arguments.nodes.some((a) => ts.isSpreadElement(a))) { const spreadServed = lowerSpreadArgsCall(lowerer, expr, callee, loc); if (spreadServed) return spreadServed; @@ -8504,6 +8521,9 @@ export function lowerRecordFieldCall( }; return init ? { kind: "seqExpr", stmts: [init], result, type: result.type, loc } : result; } + // An optional callback field the checker narrowed at this call + // (`o.cb ? o.cb(x) : …`, `if (o.cb) o.cb(x)`): extract the func arm. + if (callee.type.kind === "union") callee = lowerer.maybeNarrow(callee, access); if (callee.type.kind !== "func") lowerer.badType(access, lowerer.typeOf(access)); // JavaScript passes the record as `this`. A record with no dynamic form // cannot be that receiver; the library's own function fields (the diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 09407f71f..bc970957d 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -1,3 +1,5 @@ +import { staticFunctionNameRead } from "./static-function-names.js"; +import { argumentsOwner, typedArgumentsArity, typedArgumentsCandidate } from "./typed-arguments.js"; import { dateJsonType, isDateJsonSource } from "./builtins/dates.js"; import { guardNullProto, nullProtoRecordShape, recordNullProtoTest } from "./null-prototype.js"; import { lowerProtocolPropertyRead } from "./class-protocol-dispatch.js"; @@ -191,7 +193,7 @@ import { } from "./lower-classes.js"; import { hasRuntimeStatics } from "./class-runtime-statics.js"; import { bindingNeverReassigned, nullishGenericBindingUnitOf } from "./binding-analysis.js"; -import { funcTypeFromParamShapes } from "./call-signatures.js"; +import { funcTypeFromParamShapes, isThisParameter } from "./call-signatures.js"; import { implicitMonoFile, objLitGenericFnInfoOf, @@ -906,7 +908,18 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { // type and lowerLambda declared the local. if (expr.text === "arguments") { const binding = captureContextArguments(lowerer.fnStack); - if (binding) return { kind: "varRef", localId: binding.id, type: DYN, loc }; + if (binding && lowerer.pureTuples.has(binding.id)) { + throw new InternalCompilerError("lowerer bug: forwarded-only 'arguments' read as a value"); + } + if (binding) return { kind: "varRef", localId: binding.id, type: binding.type, loc }; + const owner = argumentsOwner(expr); + if (owner && typedArgumentsCandidate(owner)) { + lowerer.unsupported( + "SC1090", + expr, + "'arguments' in a function expression whose value is not asserted to one fixed-arity signature (assert it, as in `function () { … } as F`, and the function lowers against that signature)", + ); + } } // A compiler-projected adapter as a VALUE: the adapter has no // runtime function object (its calls rewrite directly) — call it @@ -1929,6 +1942,18 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { if (ts.isConditionalExpression(expr)) return lowerTernary(lowerer, expr); if (ts.isPropertyAccessExpression(expr)) { + // `fn.name` on a function parameter of a generic instance keyed by + // its argument's static name (call-site specialization). + { + const staticName = staticFunctionNameRead(lowerer, expr); + if (staticName !== null) return { kind: "strLit", value: staticName, type: STRING, loc }; + } + // `.length` of a forwarded fixed tuple (a typed `arguments`, a tuple + // rest parameter, an alias of either): the signature's arity. + if (expr.name.text === "length" && !expr.questionDotToken) { + const arity = typedArgumentsArity(lowerer, expr.expression); + if (arity !== null) return { kind: "numLit", value: arity, type: F64, loc }; + } // `require("./x").member` over a program module's export table: the // module's %init at this position, then the member read exactly like // a `const m = require("./x")` binding's (cjs-inline-require.ts). @@ -2233,9 +2258,12 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { p.dotDotDotToken === undefined, ); if (fixedArity) { + // A `this` parameter is type-only: callers never pass it. return { kind: "numLit", - value: (fn as ts.FunctionLikeDeclaration).parameters.nodes.length, + value: (fn as ts.FunctionLikeDeclaration).parameters.nodes.filter( + (p) => !isThisParameter(p), + ).length, type: F64, loc, }; diff --git a/packages/compiler/src/frontend/lowering/lower-functions.ts b/packages/compiler/src/frontend/lowering/lower-functions.ts index 7cc448994..74dd362e5 100644 --- a/packages/compiler/src/frontend/lowering/lower-functions.ts +++ b/packages/compiler/src/frontend/lowering/lower-functions.ts @@ -1,3 +1,4 @@ +import { declareTypedArguments } from "./typed-arguments.js"; import { varRef } from "../../ir/build.js"; import { InternalCompilerError } from "../../errors.js"; import * as ts from "../ts7/adapter.js"; @@ -309,6 +310,8 @@ export function lowerLambda( : null; const { params, prologue } = lowerer.declareParams(node.parameters.nodes, shapes); if (receiver) prologue.unshift(receiver); + if (ts.isFunctionExpression(node) && lowerer.typedArgumentsLambdas.has(node)) + declareTypedArguments(lowerer, node, shapes, params, prologue); declareFunctionArguments( lowerer, node, diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 36abb9130..01ff5f5c1 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -1,3 +1,4 @@ +import { lowerTupleAliasDecl, stripTypeWrappers } from "./typed-arguments.js"; import { matchAllRowsReadByElements, storedMatchAllRowsReadByElements, @@ -4463,6 +4464,10 @@ export function lowerVarDecl( } } if (!ts.isIdentifier(decl.name)) lowerer.unsupported("SC1031", decl.name); + { + const alias = lowerTupleAliasDecl(lowerer, decl); + if (alias) return alias; + } // A NULLISH generic binding (`const i: I = null as any` — the // declared type has no mapping, the value is provably null/undefined @@ -4876,6 +4881,15 @@ export function lowerVarDecl( init.type.kind === "func" ) type = init.type; + // A typed-arguments function expression (typed-arguments.ts): the + // checker types the binding variadic, but its value has the fixed + // signature every use asserts. + if ( + !decl.type && + init.type.kind === "func" && + lowerer.typedArgumentsLambdas.has(stripTypeWrappers(decl.initializer)) + ) + type = init.type; // A TypeScript lambda whose closure returns the runtime result (a missing // read, a `??` default of another type) instead of the checker's bare // return type: the binding keeps the checker's parameters and takes the diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index d252af250..ccc140e9e 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1,3 +1,4 @@ +import { onlyForwarded } from "./typed-arguments.js"; import { jsDynamicDeclarations } from "./js-dynamic-objects.js"; import { lifetimeRegionType, @@ -1910,6 +1911,19 @@ export class Lowerer { * type parameters are bound to `unknown`, so lambdaSignature admits * them. */ readonly erasingLambdas = new Set(); + /** Function expressions lowered against a fixed target signature with a + * tuple-typed `arguments` (typed-arguments.ts). */ + readonly typedArgumentsLambdas = new Set(); + /** Const bindings holding a forwarded fixed tuple (`const args = + * arguments as any` in a typed-arguments function) → the tuple type. */ + readonly tupleAliasSymbols = new Map(); + /** Tuple bindings that are only forwarded (typed-arguments.ts + * onlyForwarded): binding local id → the native slots forwarding reads. + * Such a binding is never materialized. */ + readonly pureTuples = new Map(); + /** The static names of the current generic instance's name-keyed + * function parameters (static-function-names.ts). */ + staticFnNames: Map | null = null; /** Nesting depth of erased generic bodies being lowered (erased lambdas * and erased instances). */ erasingDepth = 0; @@ -10681,6 +10695,70 @@ export class Lowerer { return declareContextLocal(this.ctx, name, type, false, undefined, undefined); } + /** The body binding of a fixed-tuple rest parameter: one native slot per + * position (the flattened ABI), rebuilt into the tuple the source names. + * The empty tuple rides the empty-array representation. */ + declareRestTupleParam( + decl: ts.ParameterDeclaration, + nameNode: ts.Identifier, + elemShapes: readonly ParamShape[], + params: IrParam[], + prologue: IrStmt[], + ): void { + const loc = locOf(decl); + const name = nameNode.text; + const tupleType = this.irTypeOf(nameNode); + const slots = elemShapes.map((shape, i) => { + const slot = this.declareHiddenLocal(`%${name}.${i}`, shape.type); + params.push({ localId: slot.id, name: `%${name}.${i}`, type: shape.type }); + return slot; + }); + const body = this.declareLocal(nameNode, name, tupleType, true); + const fn = decl.parent; + const symbol = this.checker.getSymbolAtLocation(nameNode); + if ( + fn !== undefined && + symbol !== undefined && + onlyForwarded( + this, + fn, + (id) => id !== nameNode && this.checker.getSymbolAtLocation(id) === symbol, + ) + ) { + this.pureTuples.set(body.id, slots); + return; + } + const init = this.tupleOfSlots(slots, tupleType, nameNode, loc); + prologue.push({ kind: "varDecl", localId: body.id, init, loc }); + } + + /** A fresh tuple holding the given positional slots, typed `tupleType` + * (a tuple record, or the empty-array form of `[]`). */ + tupleOfSlots(slots: readonly IrLocal[], tupleType: IrType, blame: ts.Node, loc: SrcLoc): IrExpr { + if (slots.length === 0) { + if (tupleType.kind !== "array") this.badType(blame, this.typeOf(blame)); + return { kind: "arrayLit", elems: [], type: tupleType, loc }; + } + const shape = tupleType.kind === "record" ? this.shapes.get(tupleType.shapeId) : undefined; + if (!shape?.tuple || shape.fields.length !== slots.length) + this.badType(blame, this.typeOf(blame)); + return { + kind: "recordLit", + fields: slots.map((slot, i) => { + const field = shape.fields.find((f) => f.name === String(i))!; + return { + name: field.name, + value: this.coerceToExpected( + { kind: "varRef", localId: slot.id, type: slot.type, loc }, + field.type, + ), + }; + }), + type: tupleType, + loc, + }; + } + /** Declares a callee's parameter locals from its ParamShapes and builds * the DEFAULT-PARAM PROLOGUE. Required/optional/rest params bind their * symbol directly (one local of the ABI type). A defaulted param `x: T = e` @@ -10717,6 +10795,17 @@ export class Lowerer { return defaultAfterUndefined(undefinedValue, this.coerceInto(node, absent, expected)); }; decls.forEach((decl, i) => { + // A fixed-tuple rest parameter owns every remaining (flattened) + // shape, possibly none for `[]` (restTupleShapes). + if ( + decl.dotDotDotToken !== undefined && + ts.isIdentifier(decl.name) && + i === decls.length - 1 && + (shapes[i] === undefined ? shapes.length === i : shapes[i]!.restTuple === true) + ) { + this.declareRestTupleParam(decl, decl.name, shapes.slice(i), params, prologue); + return; + } const shape = shapes[i]!; if (ts.isArrayBindingPattern(decl.name) || ts.isObjectBindingPattern(decl.name)) { // Pattern parameter: one hidden ABI slot carries the source value; @@ -11033,6 +11122,13 @@ export class Lowerer { } if (!symbol) return null; const direct = this.resolveKey(symbol, ident); + if (direct && this.pureTuples.has(direct.id)) { + // onlyForwarded proved every read forwards; a plain read here means + // the analysis and the lowering disagree. + throw new InternalCompilerError( + `lowerer bug: forwarded-only tuple '${ident.text}' read as a value`, + ); + } if (direct) return direct; // A PARAMETER PROPERTY declares two symbols: references resolve to the // PARAMETER symbol, while the declaration's name binds the PROPERTY diff --git a/packages/compiler/src/frontend/lowering/static-function-names.ts b/packages/compiler/src/frontend/lowering/static-function-names.ts new file mode 100644 index 000000000..1fcab901b --- /dev/null +++ b/packages/compiler/src/frontend/lowering/static-function-names.ts @@ -0,0 +1,221 @@ +import * as ts from "../ts7/adapter.js"; +import { isJsSourceFile } from "../program.js"; +import type { Lowerer } from "./lowerer.js"; +import type { GenericFnInfo } from "./generic-functions.js"; +import { stripTypeWrappers } from "./typed-arguments.js"; + +/** `fn.name` inside generic higher-order functions. + * + * Native closures carry no name, but a generic wrapper is instantiated per + * call site anyway: when its body reads `.name` of a function parameter, + * the instantiation key also carries the static name of that call's + * argument (the function declaration's name, a const binding's inferred + * name, the name of the function a wrapper call returns), and the read + * folds to that string. A call whose argument's name is only known at run + * time keeps a precise refusal at the read. */ + +/** Parameter index → symbol for the parameters whose `.name` the generic + * body reads (and never reassigns). Computed once per generic. */ +export function nameReadParams(lowerer: Lowerer, info: GenericFnInfo): Map { + if (info.nameReadParams) return info.nameReadParams; + const out = new Map(); + // JavaScript generics read function names through the checked-value + // box, which carries the runtime name already. + if (isJsSourceFile(info.decl.getSourceFile())) { + info.nameReadParams = out; + return out; + } + const bySymbol = new Map(); + info.decl.parameters.nodes.forEach((param, i) => { + if (!ts.isIdentifier(param.name) || param.dotDotDotToken) return; + if (!functionTypedParameter(lowerer, param)) return; + const symbol = lowerer.checker.getSymbolAtLocation(param.name); + if (symbol) bySymbol.set(symbol, i); + }); + if (bySymbol.size > 0) { + const written = new Set(); + const read = new Set(); + ts.walkPreorder(info.decl, (node) => { + if (ts.isTypeNode(node)) return "skip"; + if ( + ts.isPropertyAccessExpression(node) && + node.name.text === "name" && + ts.isIdentifier(node.expression) + ) { + const symbol = lowerer.checker.getSymbolAtLocation(node.expression); + if (symbol && bySymbol.has(symbol)) read.add(symbol); + } + if ( + ts.isBinaryExpression(node) && + node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && + node.operatorToken.kind <= ts.SyntaxKind.LastAssignment && + ts.isIdentifier(node.left) + ) { + const symbol = lowerer.checker.getSymbolAtLocation(node.left); + if (symbol) written.add(symbol); + } + return undefined; + }); + for (const symbol of read) { + if (!written.has(symbol)) out.set(bySymbol.get(symbol)!, symbol); + } + } + info.nameReadParams = out; + return out; +} + +/** A parameter declared with a function type, or with a type parameter + * constrained to one (`fn: F` where `F extends (...args: any) => any`). */ +function functionTypedParameter(lowerer: Lowerer, param: ts.ParameterDeclaration): boolean { + const t = lowerer.typeOf(param.name); + if (lowerer.checker.getCallSignatures(t).length > 0) return true; + if (!(t.flags & ts.TypeFlags.TypeParameter)) return false; + const symbol = t.getSymbol(); + const decl = symbol + ? lowerer.checker.declarationsOf(symbol).find(ts.isTypeParameterDeclaration) + : undefined; + if (!decl?.constraint) return false; + const constraint = lowerer.checker.getTypeFromTypeNode(decl.constraint); + return lowerer.checker.getCallSignatures(constraint).length > 0; +} + +/** The instantiation key suffix and name bindings of one call of `info`, + * or null when the body reads no parameter's name. */ +export function staticNameBindings( + lowerer: Lowerer, + call: ts.CallExpression, + info: GenericFnInfo, +): { key: string; names: Map } | null { + const params = nameReadParams(lowerer, info); + if (params.size === 0) return null; + const names = new Map(); + const parts: string[] = []; + for (const [index, symbol] of params) { + const arg = call.arguments.nodes[index]; + const name = arg && !ts.isSpreadElement(arg) ? staticFunctionName(lowerer, arg) : null; + names.set(symbol, name); + parts.push(name === null ? "?" : JSON.stringify(name)); + } + return { key: `@name(${parts.join(",")})`, names }; +} + +/** The `name` JavaScript gives the function `expr` evaluates to, when it is + * statically known; null otherwise. */ +export function staticFunctionName(lowerer: Lowerer, expr: ts.Expression): string | null { + return staticNameOf(lowerer, expr, new Set()); +} + +function staticNameOf(lowerer: Lowerer, expr: ts.Expression, seen: Set): string | null { + const e = stripTypeWrappers(expr); + if (seen.has(e)) return null; + seen.add(e); + // An anonymous function as a call argument gets no inferred name. + if (ts.isFunctionExpression(e) || ts.isArrowFunction(e)) { + return !ts.isArrowFunction(e) && e.name ? e.name.text : ""; + } + if (ts.isIdentifier(e)) { + const symbol = lowerer.resolveValueSymbol(e); + if (!symbol) return null; + const bound = lowerer.staticFnNames?.get(symbol); + if (bound !== undefined) return bound; + const decl = lowerer.checker.valueDeclarationOf(symbol); + if (decl === undefined) return null; + if (ts.isFunctionDeclaration(decl)) return decl.name ? decl.name.text : "default"; + if ( + ts.isVariableDeclaration(decl) && + ts.isIdentifier(decl.name) && + decl.initializer !== undefined && + (ts.getCombinedNodeFlags(decl) & ts.NodeFlags.Const) !== 0 + ) { + const init = stripTypeWrappers(decl.initializer); + // `const f = () => …` / `const f = function () {}`: the binding names + // an anonymous function definition. + if (ts.isArrowFunction(init)) return decl.name.text; + if (ts.isFunctionExpression(init)) return init.name ? init.name.text : decl.name.text; + return staticNameOf(lowerer, init, seen); + } + return null; + } + if (ts.isCallExpression(e) && ts.isIdentifier(e.expression)) { + // A call of a generic higher-order function returns the function its + // body returns: every `return` names the same anonymous definition or + // the same local const binding. + const symbol = lowerer.resolveValueSymbol(e.expression); + const info = symbol ? lowerer.genericFnsBySymbol.get(symbol) : undefined; + if (!info) return null; + return returnedFunctionName(lowerer, info.decl, seen); + } + if (ts.isPropertyAccessExpression(e)) { + const symbol = lowerer.checker.getSymbolAtLocation(e.name); + const decl = symbol ? lowerer.checker.valueDeclarationOf(symbol) : undefined; + if (decl && ts.isMethodDeclaration(decl) && ts.isIdentifier(decl.name)) return decl.name.text; + return null; + } + return null; +} + +function returnedFunctionName( + lowerer: Lowerer, + decl: GenericFnInfo["decl"], + seen: Set, +): string | null { + const body = decl.body; + if (body === undefined) return null; + if (!ts.isBlock(body)) return functionValueName(lowerer, body, seen); + let name: string | null | undefined; + let ok = true; + ts.walkPreorder(body, (node) => { + if (!ok) return "stop"; + if (ts.isFunctionLike(node)) return "skip"; + if (!ts.isReturnStatement(node)) return undefined; + const here = node.expression ? functionValueName(lowerer, node.expression, seen) : null; + if (here === null || (name !== undefined && name !== here)) ok = false; + else name = here; + return undefined; + }); + return ok && name !== undefined ? name : null; +} + +/** The name of a returned function value: an anonymous definition returned + * directly is nameless; a local const binding names its definition. */ +function functionValueName( + lowerer: Lowerer, + expr: ts.Expression, + seen: Set, +): string | null { + const e = stripTypeWrappers(expr); + if (ts.isFunctionExpression(e) || ts.isArrowFunction(e)) { + return !ts.isArrowFunction(e) && e.name ? e.name.text : ""; + } + if (ts.isIdentifier(e)) return staticNameOf(lowerer, e, seen); + return null; +} + +/** `fn.name` where `fn` is a name-keyed parameter of the generic instance + * being lowered: the folded name, or a precise refusal when this call + * site's argument has no static name. Null for every other read. */ +export function staticFunctionNameRead( + lowerer: Lowerer, + expr: ts.PropertyAccessExpression, +): string | null { + const names = lowerer.staticFnNames; + if ( + names === null || + expr.name.text !== "name" || + expr.questionDotToken !== undefined || + !ts.isIdentifier(expr.expression) + ) { + return null; + } + const symbol = lowerer.checker.getSymbolAtLocation(expr.expression); + if (!symbol || !names.has(symbol)) return null; + const name = names.get(symbol); + if (name === null || name === undefined) { + lowerer.unsupported( + "SC1090", + expr, + `reading '${expr.expression.text}.name' when the call passes a function whose name is only known at run time (generic wrappers fold the name of a function declaration, a const-bound function, or a wrapper call's result)`, + ); + } + return name; +} diff --git a/packages/compiler/src/frontend/lowering/typed-arguments.ts b/packages/compiler/src/frontend/lowering/typed-arguments.ts new file mode 100644 index 000000000..751d0d6be --- /dev/null +++ b/packages/compiler/src/frontend/lowering/typed-arguments.ts @@ -0,0 +1,511 @@ +import * as ts from "../ts7/adapter.js"; +import { bodyReadsArguments } from "../arguments-usage.js"; +import { isJsSourceFile, locOf } from "../program.js"; +import { unitOnlyUnion } from "../type-mapper.js"; +import { + DYN, + type IrExpr, + type IrLocal, + type IrStmt, + type IrType, + arrayOf, + typeEquals, +} from "../../ir/ir.js"; +import type { Lowerer } from "./lowerer.js"; +import { captureContextArguments } from "./function-context.js"; +import { isThisParameter, type ParamShape } from "./call-signatures.js"; +import { tryLowerExpression } from "./expressions/try-lower-expression.js"; +import { omittedArgFor } from "./call-arguments.js"; + +/** Variadic forwarding through a FIXED signature. + * + * A TypeScript function expression that declares no parameters and reads + * `arguments` (`function (this: unknown) { return fn.apply(this, arguments) } + * as F`) is lowered against the fixed function type its value is asserted + * to: one native slot per position of that type, and `arguments` is the + * tuple of those slots. Inside a generic instantiation F is the call + * site's concrete signature, so a higher-order wrapper specializes to the + * wrapped function's exact ABI. Forwarding (`f.apply(thisArg, args)`, + * `f(...args)`) then calls with the tuple's positions directly. */ + +/** `e`, with the type-only wrappers that never change its value removed. */ +export function stripTypeWrappers(e: ts.Expression): ts.Expression { + let cur = e; + for (;;) { + if (ts.isParenthesizedExpression(cur)) cur = cur.expression; + else if (ts.isAsExpression(cur) || ts.isTypeAssertion(cur) || ts.isSatisfiesExpression(cur)) + cur = cur.expression; + else if (ts.isNonNullExpression(cur)) cur = cur.expression; + else return cur; + } +} + +/** The outermost type assertion around `node` (`node as unknown as F` → F), + * looking through parentheses; null when the value is not asserted. */ +function assertedTypeNode(node: ts.Node): ts.TypeNode | null { + let cur: ts.Node = node; + let found: ts.TypeNode | null = null; + for (let parent = cur.parent; parent !== undefined; parent = cur.parent) { + if (ts.isParenthesizedExpression(parent)) { + cur = parent; + continue; + } + if ((ts.isAsExpression(parent) || ts.isTypeAssertion(parent)) && parent.expression === cur) { + found = parent.type; + cur = parent; + continue; + } + break; + } + return found; +} + +/** The fixed function type a value is asserted to, or null. */ +function assertedFuncType(lowerer: Lowerer, node: ts.Node): (IrType & { kind: "func" }) | null { + const typeNode = assertedTypeNode(node); + if (!typeNode) return null; + const mapped = lowerer.mapTypeOf(lowerer.checker.getTypeFromTypeNode(typeNode)); + return mapped?.kind === "func" ? mapped : null; +} + +function sameFuncType(a: IrType & { kind: "func" }, b: IrType & { kind: "func" }): boolean { + return JSON.stringify(a) === JSON.stringify(b); +} + +/** A function expression whose `arguments` can be typed: TypeScript source, + * no runtime parameters (a `this` parameter is type-only), an ordinary + * (non-generator) function that reads its own `arguments`. */ +export function typedArgumentsCandidate(node: ts.Node): node is ts.FunctionExpression { + return ( + ts.isFunctionExpression(node) && + node.asteriskToken === undefined && + !isJsSourceFile(node.getSourceFile()) && + node.parameters.nodes.every(isThisParameter) && + bodyReadsArguments(node) + ); +} + +/** The fixed signature a typed-arguments function expression is lowered + * against: the type its value is asserted to (`function () {…} as F`), the + * one type every use of its const binding asserts it to (`const w = + * function () {…}; return w as unknown as F`), or its contextual function + * type. Null when none names one fixed-arity signature. */ +export function typedArgumentsTarget( + lowerer: Lowerer, + node: ts.FunctionExpression, +): (IrType & { kind: "func" }) | null { + const fixed = (t: (IrType & { kind: "func" }) | null) => (t && t.rest !== true ? t : null); + const direct = assertedFuncType(lowerer, node); + if (direct) return fixed(direct); + let top: ts.Node = node; + while (top.parent && ts.isParenthesizedExpression(top.parent)) top = top.parent; + const decl = top.parent; + if ( + decl && + ts.isVariableDeclaration(decl) && + decl.initializer === top && + decl.type === undefined && + ts.isIdentifier(decl.name) && + (ts.getCombinedNodeFlags(decl) & ts.NodeFlags.Const) !== 0 + ) { + const symbol = lowerer.checker.getSymbolAtLocation(decl.name); + const scope = enclosingScope(decl); + if (symbol && scope) { + let target: (IrType & { kind: "func" }) | null = null; + let ok = true; + let uses = 0; + ts.walkPreorder(scope, (n) => { + if (!ok) return "stop"; + if (n === decl.name || !ts.isIdentifier(n) || n.text !== decl.name.text) return undefined; + if (lowerer.checker.getSymbolAtLocation(n) !== symbol) return undefined; + uses++; + const asserted = assertedFuncType(lowerer, n); + if (!asserted || (target && !sameFuncType(target, asserted))) ok = false; + else target = asserted; + return undefined; + }); + if (ok && uses > 0) return fixed(target); + } + } + const ctxType = lowerer.checker.getContextualType(node); + if (!ctxType) return null; + const sigs = lowerer.checker.getCallSignatures(lowerer.checker.getNonNullableType(ctxType)); + if (sigs.length !== 1) return null; + const mapped = lowerer.mapTypeOf(lowerer.checker.getNonNullableType(ctxType)); + return mapped?.kind === "func" ? fixed(mapped) : null; +} + +function enclosingScope(node: ts.Node): ts.Node | null { + for (let cur = node.parent; cur !== undefined; cur = cur.parent) { + if (ts.isSourceFile(cur) || (ts.isFunctionLike(cur) && cur.body !== undefined)) return cur; + } + return null; +} + +/** The tuple type of a fixed parameter list, interned exactly as the + * spelled tuple (and `Parameters`) map: positional fields, or the + * empty-array form for no parameters. */ +export function tupleTypeOfParams(lowerer: Lowerer, params: readonly IrType[]): IrType { + if (params.length === 0) return arrayOf(unitOnlyUnion(lowerer.unions)); + const fields = params.map((type, i) => ({ name: String(i), type })); + fields.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)); + return { kind: "record", shapeId: lowerer.shapes.intern(fields, true) }; +} + +/** The ABI shapes of a typed-arguments function: one required slot per + * position of its target signature. */ +export function typedArgumentsShapes(target: IrType & { kind: "func" }): ParamShape[] { + return target.params.map((type) => ({ type, mode: "required" })); +} + +/** Declares the hidden positional slots of a typed-arguments function and + * binds its `arguments` to their tuple. */ +export function declareTypedArguments( + lowerer: Lowerer, + node: ts.FunctionExpression, + shapes: readonly ParamShape[], + params: { localId: string; name: string; type: IrType }[], + prologue: IrStmt[], +): void { + const loc = locOf(node); + const slots = shapes.map((shape, i) => { + const slot = lowerer.declareHiddenLocal(`%arguments.${i}`, shape.type); + params.push({ localId: slot.id, name: `%arguments.${i}`, type: shape.type }); + return slot; + }); + const tupleType = tupleTypeOfParams( + lowerer, + shapes.map((s) => s.type), + ); + const local = lowerer.declareHiddenLocal("%arguments", tupleType); + lowerer.ctx.argumentsLocal = local; + // Pure forwarding (every read is forwarded, counted, or aliased by a + // binding that is itself only forwarded): no tuple exists at all. + if ( + onlyForwarded(lowerer, node, (id) => id.text === "arguments" && argumentsOwner(id) === node) + ) { + lowerer.pureTuples.set(local.id, slots); + return; + } + prologue.push({ + kind: "varDecl", + localId: local.id, + init: lowerer.tupleOfSlots(slots, tupleType, node, loc), + loc, + }); +} + +/** Whether every read of a tuple binding in `fn` (identified by `isRoot`) + * only forwards it: `f.apply(t, x)`, `g(...x)` into a program function, + * `x.length`, or a const alias whose own reads only forward. Reads inside + * nested functions (arrows included) capture the binding and need the + * tuple. Type assertions around a read never matter. */ +export function onlyForwarded( + lowerer: Lowerer, + fn: ts.Node, + isRoot: (id: ts.Identifier) => boolean, +): boolean { + const body = (fn as ts.Node & { body?: ts.Node }).body; + if (body === undefined) return false; + const roots: ((id: ts.Identifier) => boolean)[] = [isRoot]; + let ok = true; + const visit = (scope: ts.Node, test: (id: ts.Identifier) => boolean): void => { + ts.walkPreorder(scope, (n) => { + if (!ok) return "stop"; + if (ts.isTypeNode(n)) return "skip"; + if (!ts.isIdentifier(n) || !test(n)) return undefined; + for (let cur = n.parent; cur !== undefined && cur !== fn; cur = cur.parent) { + if (ts.isFunctionLike(cur)) { + ok = false; + return "stop"; + } + } + let top: ts.Node = n; + while ( + top.parent && + (ts.isParenthesizedExpression(top.parent) || + ts.isAsExpression(top.parent) || + ts.isTypeAssertion(top.parent) || + ts.isSatisfiesExpression(top.parent) || + ts.isNonNullExpression(top.parent)) + ) + top = top.parent; + const p = top.parent; + if (!p) { + ok = false; + return "stop"; + } + if (ts.isPropertyAccessExpression(p) && p.expression === top && p.name.text === "length") + return undefined; + if ( + ts.isCallExpression(p) && + p.arguments.nodes.length === 2 && + p.arguments.nodes[1] === top && + ts.isPropertyAccessExpression(p.expression) && + p.expression.name.text === "apply" && + p.expression.questionDotToken === undefined + ) + return undefined; + if (ts.isSpreadElement(p) && p.parent && ts.isCallExpression(p.parent)) { + const sigs = lowerer.checker.getCallSignatures( + lowerer.checker.getNonNullableType(lowerer.typeOf(p.parent.expression)), + ); + const decl = sigs.length === 1 ? lowerer.checker.signatureDeclaration(sigs[0]!) : undefined; + if (decl && !decl.getSourceFile().isDeclarationFile) return undefined; + } + if ( + ts.isVariableDeclaration(p) && + p.initializer === top && + ts.isIdentifier(p.name) && + (ts.getCombinedNodeFlags(p) & ts.NodeFlags.Const) !== 0 + ) { + const alias = lowerer.checker.getSymbolAtLocation(p.name); + const aliasName = p.name; + if (alias) { + roots.push((id) => id !== aliasName && lowerer.checker.getSymbolAtLocation(id) === alias); + return undefined; + } + } + ok = false; + return "stop"; + }); + }; + for (let i = 0; i < roots.length && ok; i++) visit(body, roots[i]!); + return ok; +} + +/** The native slots of a pure-forwarded tuple binding read at `node` in + * the current function, or null when the tuple is materialized. */ +function pureSlotsOf(lowerer: Lowerer, node: ts.Expression): IrLocal[] | null { + const operand = stripTypeWrappers(node); + if (!ts.isIdentifier(operand)) return null; + const local = + operand.text === "arguments" ? lowerer.ctx.argumentsLocal : lowerer.peekLocal(operand); + return local ? (lowerer.pureTuples.get(local.id) ?? null) : null; +} + +/** The positional values `node` forwards when it is a pure-forwarded tuple + * (slot reads, in order), or null. */ +export function pureForwardedValues(lowerer: Lowerer, node: ts.Expression): IrExpr[] | null { + const slots = pureSlotsOf(lowerer, node); + if (!slots) return null; + const loc = locOf(node); + return slots.map((slot) => ({ kind: "varRef", localId: slot.id, type: slot.type, loc })); +} + +/** Whether `node` reads a tuple-typed `arguments` binding: the nearest + * ordinary function (arrows inherit it) is a typed-arguments function. + * Looks the binding up without allocating captures. */ +function isTypedArgumentsRead(lowerer: Lowerer, node: ts.Expression): boolean { + if (!ts.isIdentifier(node) || node.text !== "arguments") return false; + const stack = lowerer.fnStack; + let owner = stack.length - 1; + while (owner > 0 && stack[owner]!.inheritsArguments) owner--; + const own = owner >= 0 ? stack[owner]!.argumentsLocal : undefined; + return own !== undefined && own !== null && own.type.kind !== "dyn"; +} + +/** The fixed tuple `node` forwards, or null: the typed `arguments`, a + * fixed-tuple rest parameter, or a const alias of either — seen through + * type assertions, which never change the value. */ +export function forwardedTupleType(lowerer: Lowerer, node: ts.Expression): IrType | null { + const operand = stripTypeWrappers(node); + if (!ts.isIdentifier(operand)) return null; + if (operand.text === "arguments") { + if (!isTypedArgumentsRead(lowerer, operand)) return null; + return captureContextArguments(lowerer.fnStack)!.type; + } + const symbol = lowerer.resolveValueSymbol(operand); + if (!symbol) return null; + const alias = lowerer.tupleAliasSymbols.get(symbol); + if (alias) return alias; + const decl = lowerer.checker.valueDeclarationOf(symbol); + if ( + decl !== undefined && + ts.isParameter(decl) && + decl.dotDotDotToken !== undefined && + ts.isIdentifier(decl.name) && + !isJsSourceFile(decl.getSourceFile()) + ) { + const t = lowerer.mapTypeOf(lowerer.typeOf(operand)); + if (t && isTupleValueType(lowerer, t)) return t; + } + return null; +} + +function isTupleValueType(lowerer: Lowerer, t: IrType): boolean { + if (t.kind === "record") return lowerer.shapes.get(t.shapeId)?.tuple === true; + // The empty tuple's representation (mapType's `[]` rule). + return typeEquals(t, arrayOf(unitOnlyUnion(lowerer.unions))); +} + +/** The positional reads of a forwarded tuple value (already saved in a + * local), in order. */ +function tupleReads( + lowerer: Lowerer, + ref: () => IrExpr, + tupleType: IrType, + loc: IrExpr["loc"], +): IrExpr[] { + if (tupleType.kind !== "record") return []; + const shape = lowerer.shapes.get(tupleType.shapeId)!; + return [...shape.fields] + .sort((a, b) => Number(a.name) - Number(b.name)) + .map((field) => ({ + kind: "recordGet" as const, + obj: ref(), + shapeId: tupleType.shapeId, + field: field.name, + type: field.type, + loc, + })); +} + +/** `f.apply(thisArg, args)` where `args` forwards a fixed tuple and `f` is a + * fixed-arity function value: a direct call of `f` with the tuple's + * positions and `thisArg` as the call-time receiver. Null for every other + * form (the existing Function.prototype paths keep them). */ +export function lowerForwardingApply( + lowerer: Lowerer, + call: ts.CallExpression, + access: ts.PropertyAccessExpression, +): IrExpr | null { + if (access.name.text !== "apply" || access.questionDotToken !== undefined) return null; + const argNodes = call.arguments.nodes; + if (argNodes.length !== 2 || argNodes.some(ts.isSpreadElement)) return null; + const tupleType = forwardedTupleType(lowerer, argNodes[1]!); + if (!tupleType) return null; + const callee = tryLowerExpression(lowerer, access.expression); + if (callee?.type.kind !== "func") return null; + const fnType = callee.type; + const loc = locOf(call); + if (fnType.rest === true) { + lowerer.unsupported( + "SC1090", + call, + "forwarding a fixed argument tuple through 'apply' to a variadic function value", + ); + } + const savedFn = lowerer.declareHiddenLocal("%applyFn", fnType); + const savedThis = lowerer.declareHiddenLocal("%applyThis", DYN); + const stmts: IrStmt[] = [ + { kind: "varDecl", localId: savedFn.id, init: callee, loc }, + { + kind: "varDecl", + localId: savedThis.id, + init: lowerer.lowerExprExpecting(argNodes[0]!, DYN), + loc, + }, + ]; + let reads = pureForwardedValues(lowerer, argNodes[1]!); + if (!reads) { + const savedArgs = lowerer.declareHiddenLocal("%applyArgs", tupleType); + stmts.push({ + kind: "varDecl", + localId: savedArgs.id, + init: lowerer.lowerExpr(stripTypeWrappers(argNodes[1]!)), + loc, + }); + reads = tupleReads( + lowerer, + () => ({ kind: "varRef", localId: savedArgs.id, type: tupleType, loc }), + tupleType, + loc, + ); + } + // JS drops surplus positions and fills missing ones with undefined. + const args = fnType.params.map((param, i): IrExpr => { + const read = reads[i]; + if (read) return lowerer.coerceInto(call, read, param); + const absent = omittedArgFor(lowerer, param, loc); + if (!absent) { + lowerer.unsupported( + "SC1090", + call, + "forwarding fewer arguments through 'apply' than the callee's required parameters", + ); + } + return absent; + }); + const invoked: IrExpr = { + kind: "callValue", + callee: { kind: "varRef", localId: savedFn.id, type: fnType, loc }, + receiver: { kind: "varRef", localId: savedThis.id, type: DYN, loc }, + args, + type: fnType.ret, + loc, + }; + return { kind: "seqExpr", stmts, result: invoked, type: fnType.ret, loc }; +} + +/** `const args = arguments as …` (or an alias of a rest tuple) inside a + * typed-arguments function: the binding holds the tuple itself — the + * assertion only re-describes the value — and stays a forwarding source. */ +export function lowerTupleAliasDecl(lowerer: Lowerer, decl: ts.VariableDeclaration): IrStmt | null { + if ( + !decl.initializer || + !ts.isIdentifier(decl.name) || + (ts.getCombinedNodeFlags(decl) & ts.NodeFlags.Const) === 0 || + lowerer.fnStack.length === 0 + ) { + return null; + } + const tupleType = forwardedTupleType(lowerer, decl.initializer); + if (!tupleType) return null; + const symbol = lowerer.checker.getSymbolAtLocation(decl.name); + if (!symbol) return null; + const declared = lowerer.mapTypeOf(lowerer.typeOf(decl.name)); + if (declared && declared.kind !== "dyn" && JSON.stringify(declared) !== JSON.stringify(tupleType)) + return null; + lowerer.tupleAliasSymbols.set(symbol, tupleType); + const slots = pureSlotsOf(lowerer, decl.initializer); + if (slots) { + // An alias of a pure-forwarded tuple is itself only forwarded + // (onlyForwarded followed it): it names the same slots. + const local = lowerer.declareLocal(decl.name, decl.name.text, tupleType, false); + lowerer.pureTuples.set(local.id, slots); + return { kind: "block", body: [], loc: locOf(decl) }; + } + const init = lowerer.lowerExpr(stripTypeWrappers(decl.initializer)); + const local = lowerer.declareLocal(decl.name, decl.name.text, tupleType, false); + return { kind: "varDecl", localId: local.id, init, loc: locOf(decl) }; +} + +/** A spread operand forwarding a fixed tuple (forwardedTupleType), + * including one that resolved to no positions at all. */ +export function isForwardedTupleSpread(lowerer: Lowerer, node: ts.Expression): boolean { + return forwardedTupleType(lowerer, node) !== null; +} + +/** `arguments` read inside a typed-arguments function: its fixed arity. */ +export function typedArgumentsArity(lowerer: Lowerer, node: ts.Expression): number | null { + if (!ts.isIdentifier(node)) return null; + const t = forwardedTupleType(lowerer, node); + if (!t) return null; + if (t.kind !== "record") return 0; + const fields = lowerer.shapes.get(t.shapeId)?.fields ?? []; + // A position that may be undefined may also be absent at the call: the + // native signature always passes it, so the count is not static. + if ( + fields.some( + (f) => f.type.kind === "union" && lowerer.armTag(f.type.unionId, { kind: "undefinedT" }) >= 0, + ) + ) { + lowerer.unsupported( + "SC1090", + node.parent ?? node, + "'length' of an argument tuple whose positions may be omitted (the native signature always passes every position, so the count is not static)", + ); + } + return fields.length; +} + +/** The function whose `arguments` an identifier reads: the nearest + * enclosing non-arrow function. */ +export function argumentsOwner(node: ts.Node): ts.Node | null { + for (let cur = node.parent; cur !== undefined; cur = cur.parent) { + if (ts.isFunctionLike(cur) && !ts.isArrowFunction(cur)) return cur; + if (ts.isSourceFile(cur)) return null; + } + return null; +} diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 123a5d1a0..19e7775cc 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -1552,6 +1552,15 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { contextResolutions++; return viaIndexed; } + // `Parameters` / `ReturnType` over a bound function-typed + // parameter (variadic higher-order wrappers): the checker keeps both + // conditionals symbolic inside the body, and their `infer` positions + // match a call signature, which matchInferReference cannot decide. + const viaSignature = mapBoundSignatureAlias(type, ctx); + if (viaSignature !== null) { + contextResolutions++; + return viaSignature; + } // A conditional type over a bound parameter (`Infer`, a // mapped type's member): evaluate it against the bindings. if (type.isConditionalType()) { @@ -4324,6 +4333,16 @@ function mapCallSignature(sig: ts.Signature, ctx: TypeMapperCtx): IrType | null // declaration as a typed packed-array closure would bypass its boxed // spread/error semantics and change coverage classification. if (rest && decl !== undefined && isJsSourceFile(decl.getSourceFile())) return null; + // A fixed-tuple rest (`...args: [A, B]`, `...args: Parameters` over + // a bound F) flattens to its positional parameters. Pattern rests keep + // their packed-record ABI and stay unmapped as values. + if (rest && decl !== undefined && ts.isParameter(decl) && ts.isIdentifier(decl.name)) { + const elems = restTupleParamTypes(checker.getTypeOfSymbol(p), ctx); + if (elems) { + params.push(...elems); + continue; + } + } const optional = decl !== undefined && ts.isParameter(decl) && @@ -4814,6 +4833,167 @@ function mapBoundIndexedAccess(type: ts.Type, ctx: TypeMapperCtx): IrType | null return mapType(checker.getTypeOfSymbol(prop), ctx); } +/** The standard library's `Parameters` / `ReturnType` over a type + * parameter the current instantiation binds to a callable checker type: + * that type's one call signature. Concrete arguments never reach here (the + * checker evaluates those conditionals itself); generic bodies keep them + * symbolic because their `infer` sits in a call signature. */ +function boundSignatureAlias( + type: ts.Type, + ctx: TypeMapperCtx, +): { name: "Parameters" | "ReturnType"; sig: ts.Signature } | null { + const { checker, resolveTypeParamTs } = ctx; + if (!resolveTypeParamTs) return null; + const alias = type.getAliasSymbol(); + if (!alias || (alias.name !== "Parameters" && alias.name !== "ReturnType")) return null; + const aliasArgs = type.getAliasTypeArguments(); + const arg = aliasArgs[0]; + if (aliasArgs.length !== 1 || !arg || !(arg.flags & ts.TypeFlags.TypeParameter)) return null; + const isLibAlias = checker + .declarationsOf(alias) + .some((d) => ts.isTypeAliasDeclaration(d) && ctx.isStdlibFile(d.getSourceFile())); + if (!isLibAlias) return null; + const bound = resolveTypeParamTs(arg); + if (!bound || bound.flags & ts.TypeFlags.TypeParameter) return null; + const sigs = checker.getCallSignatures(bound); + const sig = sigs[0]; + if (sigs.length !== 1 || !sig || sig.getTypeParameters().length > 0) return null; + return { name: alias.name, sig }; +} + +/** One position of a fixed-arity parameter tuple. An optional position + * still has a native slot (the function type's `T | undefined` slot). */ +interface TupleElement { + type: ts.Type; + optional: boolean; +} + +/** The positional parameters of a signature as a fixed tuple: a trailing + * rest flattened when its own type is a fixed tuple. Null for a variadic + * position, which has no fixed native arity. */ +function signatureParameters(sig: ts.Signature, ctx: TypeMapperCtx): TupleElement[] | null { + const { checker } = ctx; + const out: TupleElement[] = []; + for (const p of sig.getParameters()) { + const decl = checker.valueDeclarationOf(p); + const type = checker.getTypeOfSymbol(p); + if (decl !== undefined && ts.isParameter(decl)) { + if (decl.dotDotDotToken !== undefined) { + const inner = restTupleElements(type, ctx); + if (!inner) return null; + out.push(...inner); + continue; + } + out.push({ + type, + optional: decl.questionToken !== undefined || decl.initializer !== undefined, + }); + continue; + } + out.push({ type, optional: (p.flags & ts.SymbolFlags.Optional) !== 0 }); + } + return out; +} + +/** The required-only positional parameter types of a signature (the + * value-level `Parameters` tuple), null when a position is optional + * or variadic: such a tuple's length varies per call. */ +function signatureParameterTypes(sig: ts.Signature, ctx: TypeMapperCtx): ts.Type[] | null { + const elems = signatureParameters(sig, ctx); + if (!elems || elems.some((e) => e.optional)) return null; + return elems.map((e) => e.type); +} + +/** The element types of a REST parameter's type when it is a fixed tuple: + * a tuple of required elements (`[number, string]`, the empty `[]`), a type + * parameter bound to one, or `Parameters` over a bound function type. + * Such a rest parameter has a compile-time arity, so its native ABI is the + * flattened positional list (exactly the equivalent fixed signature — + * TypeScript treats `(...a: [A, B]) => R` and `(a: A, b: B) => R` alike). */ +export function restTupleElementTypes(type: ts.Type, ctx: TypeMapperCtx): ts.Type[] | null { + return restTupleElements(type, ctx)?.map((e) => e.type) ?? null; +} + +/** restTupleElementTypes with each position's optionality: a rest tuple + * may end in optional positions (`[A, B?]`, `Parameters<(a: A, b?: B) => + * R>`), which flatten to `T | undefined` slots exactly as the function + * type's optional parameters do. */ +function restTupleElements(type: ts.Type, ctx: TypeMapperCtx): TupleElement[] | null { + const { checker } = ctx; + if (type.flags & ts.TypeFlags.TypeParameter) { + const bound = ctx.resolveTypeParamTs?.(type); + return bound && bound !== type ? restTupleElements(bound, ctx) : null; + } + const viaAlias = boundSignatureAlias(type, ctx); + if (viaAlias) { + return viaAlias.name === "Parameters" ? signatureParameters(viaAlias.sig, ctx) : null; + } + if (!checker.isTupleType(type)) return null; + const ref = type as ts.TupleTypeReference; + const tupleShape = + (ref.elementFlags as ts.ElementFlags[] | undefined) !== undefined + ? ref + : (ref.getTarget() as ts.TupleType | undefined); + const args = checker.getTypeArguments(ref); + if (args.length === 0) return []; + const flags = tupleShape?.elementFlags; + if (flags === undefined) return null; + if (flags.some((f) => !(f & (ts.ElementFlags.Required | ts.ElementFlags.Optional)))) return null; + return args.map((t, i) => ({ + type: t, + optional: (flags[i]! & ts.ElementFlags.Optional) !== 0, + })); +} + +/** One tuple element's IR type under the tuple mapping's rules. */ +function mapTupleElement(t: ts.Type, ctx: TypeMapperCtx): IrType | null { + let et = (t.flags & ts.TypeFlags.Any) !== 0 ? DYN : mapType(t, ctx); + if (et?.kind === "void" && isUnitOnlyTsType(t, ctx.resolveTypeParam)) + et = unitOnlyUnion(ctx.unions); + return !et || et.kind === "void" ? null : et; +} + +/** The mapped element types of a fixed-tuple rest parameter type + * (restTupleElementTypes), null when it is not one or an element does not + * map. */ +export function restTupleParamTypes(type: ts.Type, ctx: TypeMapperCtx): IrType[] | null { + const elems = restTupleElements(type, ctx); + if (!elems) return null; + const out: IrType[] = []; + for (const e of elems) { + let et = mapTupleElement(e.type, ctx); + // An optional position's slot holds undefined when the caller omits + // it, as an optional parameter's does (mapCallSignature). + if (et && e.optional && et.kind !== "dyn") et = withUndefinedArm(et, ctx.unions); + if (!et) return null; + out.push(et); + } + return out; +} + +/** `Parameters` (the fixed tuple of F's parameters, interned exactly as + * the spelled tuple maps) and `ReturnType` (F's mapped result) over a + * bound function-typed type parameter. */ +function mapBoundSignatureAlias(type: ts.Type, ctx: TypeMapperCtx): IrType | null { + const target = boundSignatureAlias(type, ctx); + if (!target) return null; + if (target.name === "ReturnType") { + const ret = ctx.checker.getReturnTypeOfSignature(target.sig); + return ret.flags & ts.TypeFlags.Any ? DYN : mapType(ret, ctx); + } + const elems = signatureParameterTypes(target.sig, ctx); + if (!elems) return null; + if (elems.length === 0) return arrayOf(unitOnlyUnion(ctx.unions)); + const fields: { name: string; type: IrType }[] = []; + for (let i = 0; i < elems.length; i++) { + const et = mapTupleElement(elems[i]!, ctx); + if (!et) return null; + fields.push({ name: String(i), type: et }); + } + fields.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)); + return { kind: "record", shapeId: ctx.shapes.intern(fields, true) }; +} + /** `Partial` / `Readonly` where T is a STILL-GENERIC type parameter — * the one mapped-type spelling a monomorphized body can contain that the * checker cannot resolve for us (`keyof T` is unknown inside the body, so @@ -4885,13 +5065,17 @@ function mapGenericAwaitedAlias(type: ts.Type, ctx: TypeMapperCtx): IrType | nul const aliasArgs = type.getAliasTypeArguments(); const arg = aliasArgs[0]; if (aliasArgs.length !== 1 || !arg) return null; - if (!(arg.flags & ts.TypeFlags.TypeParameter)) return null; + // `Awaited>` (an async wrapper's settled result) resolves + // through F's bound signature like a bare type parameter. + const viaSignature = + arg.flags & ts.TypeFlags.TypeParameter ? null : boundSignatureAlias(arg, ctx); + if (!(arg.flags & ts.TypeFlags.TypeParameter) && viaSignature?.name !== "ReturnType") return null; // Provenance: the STANDARD LIBRARY's alias, not a user's shadowing one. const isLibAlias = ctx.checker .declarationsOf(alias) .some((d) => ts.isTypeAliasDeclaration(d) && ctx.isStdlibFile(d.getSourceFile())); if (!isLibAlias) return null; - const bound = resolveTypeParam(arg); + const bound = viaSignature ? mapBoundSignatureAlias(arg, ctx) : resolveTypeParam(arg); if (!bound) return null; let r = bound; while (r.kind === "promise") r = r.inner; @@ -5083,10 +5267,13 @@ function matchInferReference( const target = (t: ts.Type): ts.Type | undefined => t.isTypeReference?.() ? (t as ts.TypeReference).getTarget?.() : undefined; const wantTarget = target(extendsType) ?? extendsType.getAliasSymbol(); - if (!wantTarget) return undefined; + if (!wantTarget) return matchInferSignature(checked, extendsType, ctx); const gotTarget = target(checked) ?? checked.getAliasSymbol(); - if (!gotTarget) return checked.flags & ts.TypeFlags.Object ? undefined : false; - if (gotTarget !== wantTarget) return undefined; + if (!gotTarget) + return checked.flags & ts.TypeFlags.Object + ? matchInferThenable(checked, extendsType, ctx) + : false; + if (gotTarget !== wantTarget) return matchInferThenable(checked, extendsType, ctx); const wantArgs = target(extendsType) ? checker.getTypeArguments(extendsType as ts.TypeReference) : extendsType.getAliasTypeArguments(); @@ -5109,6 +5296,78 @@ function matchInferReference( return inferred; } +/** The type parameter an `infer X` declares, when `t` is one. */ +function inferSymbolOf(t: ts.Type, ctx: TypeMapperCtx): ts.Symbol | undefined { + if (!(t.flags & ts.TypeFlags.TypeParameter)) return undefined; + const symbol = t.getSymbol(); + return symbol && + ctx.checker + .declarationsOf(symbol) + .some((d) => d.parent !== undefined && ts.isInferTypeNode(d.parent)) + ? symbol + : undefined; +} + +/** `checked extends (...args: any) => infer R` — the shape of the standard + * library's ReturnType, over a concrete function type: R binds to its + * result. Parameters must be `any` (they constrain nothing); anything else + * stays undecided. A primitive never matches a function type. */ +function matchInferSignature( + checked: ts.Type, + extendsType: ts.Type, + ctx: TypeMapperCtx, +): Map | false | undefined { + const { checker } = ctx; + const wantSigs = checker.getCallSignatures(extendsType); + const want = wantSigs[0]; + if (wantSigs.length !== 1 || !want || want.getTypeParameters().length > 0) return undefined; + const anyParams = want.getParameters().every((p) => { + const t = checker.getTypeOfSymbol(p); + return ( + (t.flags & ts.TypeFlags.Any) !== 0 || + (checker.isArrayType(t) && + (checker.getTypeArguments(t as ts.TypeReference)[0]!.flags & ts.TypeFlags.Any) !== 0) + ); + }); + if (!anyParams) return undefined; + if (!(checked.flags & ts.TypeFlags.Object)) return false; + const gotSigs = checker.getCallSignatures(checked); + const got = gotSigs[0]; + if (gotSigs.length !== 1 || !got || got.getTypeParameters().length > 0) return undefined; + const wantRet = checker.getReturnTypeOfSignature(want); + const infer = inferSymbolOf(wantRet, ctx); + if (infer) return new Map([[infer, checker.getReturnTypeOfSignature(got)]]); + return wantRet.flags & ts.TypeFlags.Any ? new Map() : undefined; +} + +/** `checked extends PromiseLike` (or `Promise`) over the + * standard library's Promise: U binds to the settled type. An object with + * no `then` member is no thenable. Everything else stays undecided. */ +function matchInferThenable( + checked: ts.Type, + extendsType: ts.Type, + ctx: TypeMapperCtx, +): Map | false | undefined { + const { checker } = ctx; + const stdlibNamed = (t: ts.Type, names: readonly string[]): boolean => { + const symbol = t.getSymbol(); + return ( + symbol !== undefined && + names.includes(symbol.name) && + checker.declarationsOf(symbol).some((d) => ctx.isStdlibFile(d.getSourceFile())) + ); + }; + if (!stdlibNamed(extendsType, ["PromiseLike", "Promise"])) return undefined; + const wantArgs = checker.getTypeArguments(extendsType as ts.TypeReference); + const infer = wantArgs.length === 1 ? inferSymbolOf(wantArgs[0]!, ctx) : undefined; + if (!infer) return undefined; + if (stdlibNamed(checked, ["Promise", "PromiseLike"])) { + const gotArgs = checker.getTypeArguments(checked as ts.TypeReference); + return gotArgs.length === 1 ? new Map([[infer, gotArgs[0]!]]) : undefined; + } + return checker.getPropertyOfType(checked, "then") === undefined ? false : undefined; +} + /** The type mentions a mapped key or bound alias parameter (a template * shape evalMappedTemplate does not reduce). */ function mentionsMappedParams( @@ -5259,10 +5518,22 @@ export function isUnitOnlyTsType(t: ts.Type, resolveTypeParam?: TypeParamResolve return parts.every( (p) => (p.flags & UNIT) !== 0 || - ((p.flags & ts.TypeFlags.TypeParameter) !== 0 && resolveTypeParam?.(p)?.kind === "void"), + ((p.flags & ts.TypeFlags.TypeParameter) !== 0 && resolveTypeParam?.(p)?.kind === "void") || + boundVoidReturnType(p, resolveTypeParam), ); } +/** `ReturnType` over a type parameter bound to a void-returning + * function (a variadic wrapper's result slot): a unit-only value. */ +function boundVoidReturnType(p: ts.Type, resolveTypeParam?: TypeParamResolver): boolean { + if (!resolveTypeParam || p.getAliasSymbol()?.name !== "ReturnType") return false; + const args = p.getAliasTypeArguments(); + const arg = args[0]; + if (args.length !== 1 || !arg || !(arg.flags & ts.TypeFlags.TypeParameter)) return false; + const bound = resolveTypeParam(arg); + return bound?.kind === "func" && bound.ret.kind === "void"; +} + /** IR-level `t | undefined`, canonicalized and fenced exactly like the * ts-union branch of mapType (typeKey-sorted arms, deduplicated; * Date/dyn/void arms unrepresentable; a func arm IS representable — the diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6380-variadic-wrapper-arguments-apply.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6380-variadic-wrapper-arguments-apply.ts.json new file mode 100644 index 000000000..df0124219 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6380-variadic-wrapper-arguments-apply.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6380-variadic-wrapper-arguments-apply.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6381-variadic-wrapper-async.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6381-variadic-wrapper-async.ts.json new file mode 100644 index 000000000..2138df43d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6381-variadic-wrapper-async.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6381-variadic-wrapper-async.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6382-variadic-wrapper-methods-this.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6382-variadic-wrapper-methods-this.ts.json new file mode 100644 index 000000000..2135f8b6f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6382-variadic-wrapper-methods-this.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6382-variadic-wrapper-methods-this.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6383-variadic-wrapper-rest-tuple.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6383-variadic-wrapper-rest-tuple.ts.json new file mode 100644 index 000000000..a2f7f32c4 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6383-variadic-wrapper-rest-tuple.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6383-variadic-wrapper-rest-tuple.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6384-variadic-wrapper-nested.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6384-variadic-wrapper-nested.ts.json new file mode 100644 index 000000000..d69618e3a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6384-variadic-wrapper-nested.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6384-variadic-wrapper-nested.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/variadic-wrapper-fences.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/variadic-wrapper-fences.ts.json new file mode 100644 index 000000000..c3e44b2e5 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/variadic-wrapper-fences.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/variadic-wrapper-fences.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6380-variadic-wrapper-arguments-apply.ts b/tests/corpus/6380-variadic-wrapper-arguments-apply.ts new file mode 100644 index 000000000..1a14b6e2f --- /dev/null +++ b/tests/corpus/6380-variadic-wrapper-arguments-apply.ts @@ -0,0 +1,77 @@ +// A generic higher-order wrapper over `(...args: any) => any` that forwards +// `arguments` with `fn.apply(this, arguments)`, and types its options with +// Parameters / ReturnType. Each call site specializes the wrapper to +// the wrapped function's exact signature. +type AnyFn = (...args: any) => any; + +interface TraceOptions { + name?: string; + tags?: (...args: Parameters) => Record; + onResult?: (result: ReturnType) => void; +} + +function trace(fn: F, opts: TraceOptions = {}): F { + return function (this: unknown) { + const args = arguments as unknown as Parameters; + const tags = opts.tags ? opts.tags(...args) : {}; + console.log("enter", opts.name ?? fn.name, JSON.stringify(tags)); + const result: ReturnType = fn.apply(this, arguments as any); + opts.onResult?.(result); + console.log("exit", opts.name ?? fn.name); + return result; + } as F; +} + +function add(a: number, b: number): number { + return a + b; +} +const tracedAdd = trace(add, { + tags: (a, b) => ({ a: String(a), b: String(b) }), + onResult: (r) => console.log("result", r), +}); +console.log(tracedAdd(2, 3)); +console.log(tracedAdd(10, -4)); + +// A wrapped function with an optional parameter: the omitted position +// arrives as undefined, in the wrapper and its tags callback alike. +function titled(name: string, title?: string): string { + return title ? `${title} ${name}` : name; +} +const tracedTitled = trace(titled, { tags: (name, title) => ({ name, title: title ?? "-" }) }); +console.log(tracedTitled("ada")); +console.log(tracedTitled("ada", "dr")); + +const greet = (who: string, punct: string): string => `hi ${who}${punct}`; +const tracedGreet = trace(greet); +console.log(tracedGreet("ada", "!")); + +const tick = trace(function tick(): number { + return 42; +}); +console.log(tick()); + +interface Point { + x: number; + y: number; +} +const norm = trace((p: Point, scale: number): Point => ({ x: p.x * scale, y: p.y * scale }), { + name: "norm", + tags: (p) => ({ x: String(p.x) }), +}); +console.log(JSON.stringify(norm({ x: 1, y: 2 }, 3))); + +// The arguments tuple spread straight into an optional callback. +function audit(fn: F, check?: (...args: Parameters) => boolean): F { + return function (this: unknown) { + console.log("audit", check?.(...(arguments as unknown as Parameters))); + return fn.apply(this, arguments as any); + } as F; +} +const audited = audit(add, (a, b) => a < b); +console.log(audited(1, 2), audited(5, 3)); +console.log(audit(add)(7, 8)); + +const logOnly = trace((msg: string): void => { + console.log("log:", msg); +}); +logOnly("done"); diff --git a/tests/corpus/6381-variadic-wrapper-async.ts b/tests/corpus/6381-variadic-wrapper-async.ts new file mode 100644 index 000000000..200454a5e --- /dev/null +++ b/tests/corpus/6381-variadic-wrapper-async.ts @@ -0,0 +1,81 @@ +// Variadic generic wrappers around async functions: the wrapper forwards +// `arguments`, awaits the wrapped promise and reports its settled value +// through an Awaited> callback; rejections propagate. +type AnyFn = (...args: any) => any; + +interface Opts { + name?: string; + tags?: (...args: Parameters) => Record; + onSettled?: (value: Awaited>) => void; +} + +function traceAsync Promise>(fn: F, opts: Opts = {}): F { + return async function (this: unknown) { + const args = arguments as unknown as Parameters; + const tags = opts.tags ? opts.tags(...args) : {}; + console.log("start", opts.name ?? fn.name, JSON.stringify(tags)); + try { + const value: Awaited> = await fn.apply(this, arguments as any); + opts.onSettled?.(value); + console.log("ok", opts.name ?? fn.name); + return value; + } catch (e) { + console.log("failed", opts.name ?? fn.name, (e as Error).message); + throw e; + } + } as F; +} + +// The settled result spelled as a conditional over ReturnType. +type Settled = ReturnType extends PromiseLike ? U : ReturnType; + +function summarized Promise>( + fn: F, + summarize: (value: Settled) => string, +): F { + return async function (this: unknown) { + const value: Settled = await fn.apply(this, arguments as any); + console.log("summary", summarize(value)); + return value; + } as F; +} + +async function fetchUser(id: number, prefix: string): Promise { + await Promise.resolve(); + if (id < 0) throw new Error(`bad id ${id}`); + return `${prefix}${id}`; +} + +const getUser = traceAsync(fetchUser, { + tags: (id) => ({ id: String(id) }), + onSettled: (v) => console.log("settled", v.toUpperCase()), +}); + +const sleepless = traceAsync(async (): Promise => 7, { name: "seven" }); + +interface Report { + ok: boolean; + items: string[]; +} +const report = summarized( + async (count: number): Promise => ({ ok: count > 0, items: ["a", "b"].slice(0, count) }), + (r) => `${r.ok}:${r.items.join("+")}`, +); +const counted = summarized(async (n: number): Promise => n * 2, (n) => `n=${n + 1}`); + +async function main(): Promise { + console.log(await getUser(1, "u-")); + console.log(await sleepless()); + console.log(JSON.stringify(await report(1))); + console.log(await counted(4)); + try { + await getUser(-2, "u-"); + } catch (e) { + console.log("caught", (e as Error).message); + } + const pending = getUser(3, "a-"); + const second = await getUser(4, "b-"); + console.log(second, await pending); +} + +main().then(() => console.log("main done")); diff --git a/tests/corpus/6382-variadic-wrapper-methods-this.ts b/tests/corpus/6382-variadic-wrapper-methods-this.ts new file mode 100644 index 000000000..54e043207 --- /dev/null +++ b/tests/corpus/6382-variadic-wrapper-methods-this.ts @@ -0,0 +1,46 @@ +// Variadic generic wrappers on methods: the wrapper passes its own `this` +// through `fn.apply(this, arguments)`, so a wrapped `function (this: C)` +// stored as a class property sees the receiver it was called on. +type AnyFn = (...args: any) => any; + +function logged(fn: F, label: string): F { + return function (this: unknown) { + console.log(`[${label}] call with ${arguments.length} args`); + return fn.apply(this, arguments as any); + } as F; +} + +class Counter { + count = 0; + step: number; + constructor(step: number) { + this.step = step; + } + bump = logged(function (this: Counter, times: number): number { + this.count += this.step * times; + return this.count; + }, "bump"); + reset = logged((): void => { + this.count = 0; + }, "reset"); +} + +const c = new Counter(5); +console.log(c.bump(1)); +console.log(c.bump(2)); +c.reset(); +console.log(c.count); + +class Repo { + base: string; + constructor(base: string) { + this.base = base; + } + load = logged(async function (this: Repo, id: string): Promise { + await Promise.resolve(); + return `${this.base}/${id}`; + }, "load"); +} + +const repo = new Repo("https://x.test"); +repo.load("7").then((url) => console.log("loaded", url)); diff --git a/tests/corpus/6383-variadic-wrapper-rest-tuple.ts b/tests/corpus/6383-variadic-wrapper-rest-tuple.ts new file mode 100644 index 000000000..64f1cbacc --- /dev/null +++ b/tests/corpus/6383-variadic-wrapper-rest-tuple.ts @@ -0,0 +1,54 @@ +// The type-safe variadic wrapper: rest tuples instead of `arguments`. +// `...args: A` with A bound to the wrapped function's parameter tuple +// flattens to that fixed signature; `fn.apply(this, args)`, `fn(...args)` +// and `opts.tags(...args)` forward the tuple's positions. +interface Opts { + name?: string; + tags?: (...args: A) => Record; + onResult?: (r: R) => void; +} + +function wrap(fn: (...args: A) => R, opts: Opts = {}): (...args: A) => R { + return function (this: unknown, ...args: A): R { + const tags = opts.tags ? opts.tags(...args) : {}; + console.log("enter", opts.name ?? fn.name, JSON.stringify(tags)); + const r = fn.apply(this, args); + opts.onResult?.(r); + return r; + }; +} + +function viaSpread(fn: (...args: A) => R): (...args: A) => R { + return (...args: A): R => { + console.log("spread", args.length); + return fn(...args); + }; +} + +function mul(a: number, b: number): number { + return a * b; +} +const m = wrap(mul, { tags: (a, b) => ({ a: String(a), b: String(b) }), onResult: (r) => console.log("r", r) }); +console.log(m(6, 7)); + +const concat = wrap((s: string, n: number, flag: boolean) => `${s}:${n}:${flag}`, { name: "concat" }); +console.log(concat("x", 1, true)); + +const opt = wrap((s: string, n?: number) => `${s}:${n ?? "none"}`, { tags: (s, n) => ({ s, n: String(n) }) }); +console.log(opt("a", undefined), opt("b", 2)); + +const zero = wrap(() => "nothing"); +console.log(zero()); + +const spreadMul = viaSpread(mul); +console.log(spreadMul(3, 3)); + +// A concrete tuple rest parameter has the same fixed signature. +function pair(...args: [string, number]): string { + return `${args[0]}=${args[1]}`; +} +console.log(pair("k", 9)); +const asValue: (k: string, v: number) => string = pair; +console.log(asValue("v", 1)); +const t: [string, number] = ["t", 2]; +console.log(pair(...t)); diff --git a/tests/corpus/6384-variadic-wrapper-nested.ts b/tests/corpus/6384-variadic-wrapper-nested.ts new file mode 100644 index 000000000..76f714402 --- /dev/null +++ b/tests/corpus/6384-variadic-wrapper-nested.ts @@ -0,0 +1,37 @@ +// Nested variadic wrappers: wrapping an already wrapped function, mixing +// the `arguments` form and the rest-tuple form. The inner wrapper's +// function binding gives the outer wrapper its `fn.name`. +type AnyFn = (...args: any) => any; + +function trace(fn: F, label?: string): F { + const wrapped = function (this: unknown) { + console.log("trace>", label ?? fn.name); + const out = fn.apply(this, arguments as any); + console.log("trace<", label ?? fn.name); + return out; + }; + return wrapped as unknown as F; +} + +function timed(fn: (...args: A) => R): (...args: A) => R { + return function (this: unknown, ...args: A): R { + console.log("timed>", fn.name, args.length); + return fn.apply(this, args); + }; +} + +function area(w: number, h: number): number { + return w * h; +} + +const twice = trace(trace(area)); +console.log(twice(2, 3)); + +const labelled = trace(trace(area, "inner"), "outer"); +console.log(labelled(4, 5)); + +const mixed = timed(trace(area)); +console.log(mixed(6, 7)); + +const mixed2 = trace(timed(area)); +console.log(mixed2(1, 9)); diff --git a/tests/diagnostics/arrow-bind.ts b/tests/diagnostics/arrow-bind.ts index c78db514b..0b677c5ef 100644 --- a/tests/diagnostics/arrow-bind.ts +++ b/tests/diagnostics/arrow-bind.ts @@ -1,4 +1,5 @@ -// Typed preset and rest signatures still exceed the callable adapter. +// Typed rest signatures still exceed the callable adapter. (A typed preset +// binds to a fixed signature and compiles.) const preset = ((value: number) => value).bind(null, 1); const rest = ((...values: number[]) => values.length).bind(null); export {}; diff --git a/tests/diagnostics/variadic-wrapper-fences.ts b/tests/diagnostics/variadic-wrapper-fences.ts new file mode 100644 index 000000000..d2ad65646 --- /dev/null +++ b/tests/diagnostics/variadic-wrapper-fences.ts @@ -0,0 +1,28 @@ +// Variadic generic wrappers specialize per call site; the forms that have +// no fixed signature or no static name keep precise refusals. +type AnyFn = (...args: any) => any; + +// `arguments` with no fixed signature to lower against. +const loose = function () { + return arguments[0]; +}; + +// `fn.name` where the argument's name is only known at run time. +function named(fn: F): string { + return fn.name; +} +function one(): number { + return 1; +} +function two(): number { + return 2; +} +const pick = (flag: boolean) => (flag ? one : two); +console.log(named(pick(true))); + +// Forwarding a fixed tuple to a variadic function value. +function forward(sink: (...xs: number[]) => number, ...args: A): number { + return sink.apply(null, args); +} +console.log(forward((...xs: number[]) => xs.length, 1, 2)); +export { loose }; diff --git a/tests/harness/__snapshots__/arrow-bind.ts.txt b/tests/harness/__snapshots__/arrow-bind.ts.txt index 4618bdfe2..d63201d59 100644 --- a/tests/harness/__snapshots__/arrow-bind.ts.txt +++ b/tests/harness/__snapshots__/arrow-bind.ts.txt @@ -1,17 +1,8 @@ -arrow-bind.ts:2:16 - error SC1100: passing 'unknown' values where '((null | undefined)[]) => number' is expected is not supported yet +arrow-bind.ts:4:14 - error SC1100: passing 'unknown' values where '(number[]) => number' is expected is not supported yet - 1 | // Typed preset and rest signatures still exceed the callable adapter. - 2 | const preset = ((value: number) => value).bind(null, 1); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 3 | const rest = ((...values: number[]) => values.length).bind(null); - - hint: validate with 'as ' first — the cast checks the dynamic value at runtime and throws on mismatch - -arrow-bind.ts:3:14 - error SC1100: passing 'unknown' values where '(number[]) => number' is expected is not supported yet - - 2 | const preset = ((value: number) => value).bind(null, 1); - 3 | const rest = ((...values: number[]) => values.length).bind(null); + 3 | const preset = ((value: number) => value).bind(null, 1); + 4 | const rest = ((...values: number[]) => values.length).bind(null); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 4 | export {}; + 5 | export {}; hint: validate with 'as ' first — the cast checks the dynamic value at runtime and throws on mismatch \ No newline at end of file diff --git a/tests/harness/__snapshots__/variadic-wrapper-fences.ts.txt b/tests/harness/__snapshots__/variadic-wrapper-fences.ts.txt new file mode 100644 index 000000000..0cb2774d2 --- /dev/null +++ b/tests/harness/__snapshots__/variadic-wrapper-fences.ts.txt @@ -0,0 +1,29 @@ +variadic-wrapper-fences.ts:6:7 - error SC2009: values of type '() => any' cannot be compiled: the function shape is supported, but its signature is variadic ('arguments'-reading), and a compiled signature is fixed-arity + + 5 | // `arguments` with no fixed signature to lower against. + 6 | const loose = function () { + | ^~~~~ + 7 | return arguments[0]; + + hint: the outer shape is supported — the named component is the blocker; restate it inside the compilable set (number, string, boolean, arrays, Maps, Sets, RegExp, functions, classes, records, unions of those, and 'unknown') + +variadic-wrapper-fences.ts:7:10 - error SC1090: 'arguments' in a function expression whose value is not asserted to one fixed-arity signature (assert it, as in `function () { … } as F`, and the function lowers against that signature) is not supported yet + + 6 | const loose = function () { + 7 | return arguments[0]; + | ^~~~~~~~~ + 8 | }; + +variadic-wrapper-fences.ts:12:10 - error SC1090: reading 'fn.name' when the call passes a function whose name is only known at run time (generic wrappers fold the name of a function declaration, a const-bound function, or a wrapper call's result) is not supported yet (instantiating 'named' with <() => number>) + + 11 | function named(fn: F): string { + 12 | return fn.name; + | ^~~~~~~ + 13 | } + +variadic-wrapper-fences.ts:25:10 - error SC1090: forwarding a fixed argument tuple through 'apply' to a variadic function value is not supported yet (instantiating 'forward' with <[number, number]>) + + 24 | function forward(sink: (...xs: number[]) => number, ...args: A): number { + 25 | return sink.apply(null, args); + | ^~~~~~~~~~~~~~~~~~~~~~ + 26 | } \ No newline at end of file From 1711c0110e1727323d17241eccf3275ef88c3e6e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Mon, 19 Oct 2026 17:05:27 -0500 Subject: [PATCH 04/39] Inspect WebAssembly objects as Node does and declare the wasm entry points in scr_runtime.h util.inspect prints a handle whose Symbol.toStringTag ends with "." and its class name in place of the name, as Node does: WebAssembly.Module {} rather than Module [WebAssembly.Module] {}. The same holds for Instance, Memory, Table and Global. The WebAssembly API entry points move to scr_wasm.h, which scr_runtime.h includes with scr_wasm_abi.h, so every scr_* symbol the backend can emit has a header declaration. The emitted registry array is renamed sc_wasm_registry_modules, following the compiler-emitted symbol prefix. --- .../compiler/src/backend/llvm/wasm-modules.ts | 4 ++-- packages/runtime/src/scr_dyn.h | 3 ++- packages/runtime/src/scr_inspect.c | 22 ++++++++++++++---- packages/runtime/src/scr_runtime.h | 2 ++ packages/runtime/src/scr_wasm.c | 11 --------- packages/runtime/src/scr_wasm.h | 23 +++++++++++++++++++ 6 files changed, 47 insertions(+), 18 deletions(-) create mode 100644 packages/runtime/src/scr_wasm.h diff --git a/packages/compiler/src/backend/llvm/wasm-modules.ts b/packages/compiler/src/backend/llvm/wasm-modules.ts index c37dc36c4..6a79ff5fe 100644 --- a/packages/compiler/src/backend/llvm/wasm-modules.ts +++ b/packages/compiler/src/backend/llvm/wasm-modules.ts @@ -65,8 +65,8 @@ export function emitWasmModules( out.push(`@scr_wasm_registry = constant { i64, ptr } { i64 0, ptr null }`); } else { out.push( - `@scr_wasm_registry_modules = private constant [${descriptors.length} x ptr] [${descriptors.map((d) => `ptr ${d}`).join(", ")}]`, - `@scr_wasm_registry = constant { i64, ptr } { i64 ${descriptors.length}, ptr @scr_wasm_registry_modules }`, + `@sc_wasm_registry_modules = private constant [${descriptors.length} x ptr] [${descriptors.map((d) => `ptr ${d}`).join(", ")}]`, + `@scr_wasm_registry = constant { i64, ptr } { i64 ${descriptors.length}, ptr @sc_wasm_registry_modules }`, ); } out.push(""); diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index b7960ba12..e46fb28d4 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -1171,7 +1171,8 @@ typedef struct ScrDynHandleOps { * inspector returns `this`) instead of the bare class name. */ bool inspect_bracketed_past_depth; /* The @@toStringTag when it differs from cls: String() answers - * "[object ]" and util.inspect prints ` [] `. */ + * "[object ]" and util.inspect prints ` [] `, or + * ` ` when the tag ends with "." and cls, as Node does. */ const char *to_string_tag; /* The view has no properties, so util.inspect prints it in full at any * depth, as Node prints `{}`. */ diff --git a/packages/runtime/src/scr_inspect.c b/packages/runtime/src/scr_inspect.c index 34438353f..eccd404fc 100644 --- a/packages/runtime/src/scr_inspect.c +++ b/packages/runtime/src/scr_inspect.c @@ -975,6 +975,16 @@ static ScrStr *scr_insp_class_tag(const char *cls, const char *tail) { return ib_take(&out); } +/* Node prints a @@toStringTag that ends with "." and the constructor name + * (WebAssembly.Module for Module) in place of the name, without the + * bracketed tag. */ +static bool insp_tag_names_class(const char *tag, const char *cls) { + if (!tag) return false; + size_t tag_len = strlen(tag), cls_len = strlen(cls); + return tag_len > cls_len + 1 && tag[tag_len - cls_len - 1] == '.' && + memcmp(tag + tag_len - cls_len, cls, cls_len) == 0; +} + /* A native Set or Map held as a checked-dynamic value: `Set(n) { a, b }`, * `Map(n) { k => v }`, at most 100 entries like Node's maxArrayLength. */ /* Node's formatWeakCollection: the entries of a WeakMap or WeakSet are not @@ -1261,11 +1271,15 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { ScrStr *body = scr_insp_dyn(view, recurse, depth); scr_dyn_release(view); InspBuf out = {0}; - ib_cstr(&out, ops->cls); - if (ops->to_string_tag) { - ib_cstr(&out, " ["); + if (insp_tag_names_class(ops->to_string_tag, ops->cls)) { ib_cstr(&out, ops->to_string_tag); - ib_char(&out, ']'); + } else { + ib_cstr(&out, ops->cls); + if (ops->to_string_tag) { + ib_cstr(&out, " ["); + ib_cstr(&out, ops->to_string_tag); + ib_char(&out, ']'); + } } ib_char(&out, ' '); ib_bytes(&out, body->data, body->len); diff --git a/packages/runtime/src/scr_runtime.h b/packages/runtime/src/scr_runtime.h index a66d1c554..f52e63088 100644 --- a/packages/runtime/src/scr_runtime.h +++ b/packages/runtime/src/scr_runtime.h @@ -74,5 +74,7 @@ #include "scr_assert.h" #include "scr_console.h" #include "scr_fs_cp.h" +#include "scr_wasm_abi.h" +#include "scr_wasm.h" #endif /* SCR_RUNTIME_H */ diff --git a/packages/runtime/src/scr_wasm.c b/packages/runtime/src/scr_wasm.c index 03d59604f..f9e96ab76 100644 --- a/packages/runtime/src/scr_wasm.c +++ b/packages/runtime/src/scr_wasm.c @@ -76,17 +76,6 @@ #define SCR_WASM_ASAN 1 #endif -ScrPromise *scr_wasm_compile(ScrDyn *bytes); -bool scr_wasm_validate(ScrDyn *bytes); -ScrPromise *scr_wasm_instantiate(ScrDyn *source, ScrDyn *imports); -ScrDyn *scr_wasm_module_new(ScrDyn *bytes); -ScrDyn *scr_wasm_instance_new(ScrDyn *module, ScrDyn *imports); -bool scr_wasm_is(const ScrDyn *value, double kind); -ScrDyn *scr_wasm_error_new(double kind, ScrDyn *message, ScrDyn *options); -ScrDyn *scr_wasm_function(double kind); -ScrDyn *scr_wasm_namespace(void); -ScrDyn *scr_wasm_global_view(void); - /* Entry points of translated code. */ /* Sanitized builds do not declare it noreturn: AddressSanitizer would * call __asan_handle_no_return before every call, which warns on the diff --git a/packages/runtime/src/scr_wasm.h b/packages/runtime/src/scr_wasm.h new file mode 100644 index 000000000..7b0a29689 --- /dev/null +++ b/packages/runtime/src/scr_wasm.h @@ -0,0 +1,23 @@ +/* scriptc runtime — the WebAssembly JavaScript API (scr_wasm.c): the entry + * points the LLVM backend calls for the wasm.* lib functions. Included by + * scr_runtime.h, which says where new declarations go. The contract with + * translated modules, including scr_wasm_registry, is in scr_wasm_abi.h. */ +#ifndef SCR_WASM_H +#define SCR_WASM_H + +#include "scr_async.h" +#include "scr_dyn.h" +#include "scr_wasm_abi.h" + +ScrPromise *scr_wasm_compile(ScrDyn *bytes); +bool scr_wasm_validate(ScrDyn *bytes); +ScrPromise *scr_wasm_instantiate(ScrDyn *source, ScrDyn *imports); +ScrDyn *scr_wasm_module_new(ScrDyn *bytes); +ScrDyn *scr_wasm_instance_new(ScrDyn *module, ScrDyn *imports); +bool scr_wasm_is(const ScrDyn *value, double kind); +ScrDyn *scr_wasm_error_new(double kind, ScrDyn *message, ScrDyn *options); +ScrDyn *scr_wasm_function(double kind); +ScrDyn *scr_wasm_namespace(void); +ScrDyn *scr_wasm_global_view(void); + +#endif /* SCR_WASM_H */ From 46d12eb1e1a1981a9bfcf9faf45a262fcc9a1bc9 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 15:15:02 -0700 Subject: [PATCH 05/39] Probe forwarded tuples without interning types Recognizing the empty-tuple representation interned the unit-only union, and a rest parameter's IR type was mapped before checking that it is a tuple at all. Both shifted union ids in programs with ordinary array rest parameters that read `.length`. Probe through the checker and registry lookups only. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/typed-arguments.ts | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/typed-arguments.ts b/packages/compiler/src/frontend/lowering/typed-arguments.ts index 751d0d6be..90fef0e86 100644 --- a/packages/compiler/src/frontend/lowering/typed-arguments.ts +++ b/packages/compiler/src/frontend/lowering/typed-arguments.ts @@ -1,16 +1,8 @@ import * as ts from "../ts7/adapter.js"; import { bodyReadsArguments } from "../arguments-usage.js"; import { isJsSourceFile, locOf } from "../program.js"; -import { unitOnlyUnion } from "../type-mapper.js"; -import { - DYN, - type IrExpr, - type IrLocal, - type IrStmt, - type IrType, - arrayOf, - typeEquals, -} from "../../ir/ir.js"; +import { restTupleElementTypes, unitOnlyUnion } from "../type-mapper.js"; +import { DYN, type IrExpr, type IrLocal, type IrStmt, type IrType, arrayOf } from "../../ir/ir.js"; import type { Lowerer } from "./lowerer.js"; import { captureContextArguments } from "./function-context.js"; import { isThisParameter, type ParamShape } from "./call-signatures.js"; @@ -325,7 +317,9 @@ export function forwardedTupleType(lowerer: Lowerer, node: ts.Expression): IrTyp ts.isParameter(decl) && decl.dotDotDotToken !== undefined && ts.isIdentifier(decl.name) && - !isJsSourceFile(decl.getSourceFile()) + !isJsSourceFile(decl.getSourceFile()) && + // Checker-only probe first: an ordinary array rest never maps here. + restTupleElementTypes(lowerer.typeOf(operand), lowerer.typeCtx) !== null ) { const t = lowerer.mapTypeOf(lowerer.typeOf(operand)); if (t && isTupleValueType(lowerer, t)) return t; @@ -335,8 +329,17 @@ export function forwardedTupleType(lowerer: Lowerer, node: ts.Expression): IrTyp function isTupleValueType(lowerer: Lowerer, t: IrType): boolean { if (t.kind === "record") return lowerer.shapes.get(t.shapeId)?.tuple === true; - // The empty tuple's representation (mapType's `[]` rule). - return typeEquals(t, arrayOf(unitOnlyUnion(lowerer.unions))); + // The empty tuple's representation (mapType's `[]` rule): an array over + // the unit-only union. Looked up, never interned, so probing a value + // leaves the registries untouched. + if (t.kind !== "array" || t.elem.kind !== "union") return false; + const arms = lowerer.unions.get(t.elem.unionId)?.arms; + return ( + arms !== undefined && + arms.length === 2 && + arms.some((a) => a.kind === "nullT") && + arms.some((a) => a.kind === "undefinedT") + ); } /** The positional reads of a forwarded tuple value (already saved in a From 44bd0a7b1427616f705425e423e529256bebc1db Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Mon, 19 Oct 2026 19:24:17 -0500 Subject: [PATCH 06/39] Keep forwarded-only tuple bindings per function The lowerer kept the tuple bindings that are only forwarded in one map for the whole program, keyed by local id. Local ids are unique within one function only: two wrappers that both bind `arguments` (or a `const args = arguments as any` alias) declare the same id, so a wrapper whose tuple exists found the other wrapper's entry, and reading an element of its `arguments` failed with "forwarded-only 'arguments' read as a value". Each function's context now keeps its own map. The corpus program wraps functions with a forwarding-only wrapper and with one that also reads an element of `arguments`, directly and through an alias, in both orders. --- .../src/frontend/lowering/function-context.ts | 7 +++ .../src/frontend/lowering/lower-exprs.ts | 2 +- .../compiler/src/frontend/lowering/lowerer.ts | 8 +-- .../src/frontend/lowering/typed-arguments.ts | 6 +- ...ariadic-wrapper-shared-local-names.ts.json | 6 ++ ...385-variadic-wrapper-shared-local-names.ts | 56 +++++++++++++++++++ ...ariadic-wrapper-shared-local-names.ts.json | 1 + 7 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6385-variadic-wrapper-shared-local-names.ts.json create mode 100644 tests/corpus/6385-variadic-wrapper-shared-local-names.ts create mode 100644 tests/harness/corpus-costs/6385-variadic-wrapper-shared-local-names.ts.json diff --git a/packages/compiler/src/frontend/lowering/function-context.ts b/packages/compiler/src/frontend/lowering/function-context.ts index e31e194c5..55d8ed0b0 100644 --- a/packages/compiler/src/frontend/lowering/function-context.ts +++ b/packages/compiler/src/frontend/lowering/function-context.ts @@ -48,6 +48,12 @@ export interface FnCtx { argumentsLocal?: IrLocal | null; /** Arrows inherit the nearest ordinary function's arguments binding. */ inheritsArguments?: boolean; + /** Tuple bindings of this function that are only forwarded + * (typed-arguments.ts onlyForwarded): binding local id → the native + * slots forwarding reads. Such a binding is never materialized. Local ids + * are unique within one function only, and nested functions never read + * these bindings (a read there needs the tuple). */ + pureTuples: Map; /** Declared return type — lets `return` detect record-shape mismatches * (SC2002) before the validator would ICE on them. */ returnType: IrType; @@ -81,6 +87,7 @@ export function newFnCtx( captures: lifted ? [] : null, captureSources: [], captureBySymbol: new Map(), + pureTuples: new Map(), selfSymbol, selfType, returnType, diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index bc970957d..80b5bb333 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -908,7 +908,7 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { // type and lowerLambda declared the local. if (expr.text === "arguments") { const binding = captureContextArguments(lowerer.fnStack); - if (binding && lowerer.pureTuples.has(binding.id)) { + if (binding && lowerer.ctx.pureTuples.has(binding.id)) { throw new InternalCompilerError("lowerer bug: forwarded-only 'arguments' read as a value"); } if (binding) return { kind: "varRef", localId: binding.id, type: binding.type, loc }; diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index ccc140e9e..26405865c 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1917,10 +1917,6 @@ export class Lowerer { /** Const bindings holding a forwarded fixed tuple (`const args = * arguments as any` in a typed-arguments function) → the tuple type. */ readonly tupleAliasSymbols = new Map(); - /** Tuple bindings that are only forwarded (typed-arguments.ts - * onlyForwarded): binding local id → the native slots forwarding reads. - * Such a binding is never materialized. */ - readonly pureTuples = new Map(); /** The static names of the current generic instance's name-keyed * function parameters (static-function-names.ts). */ staticFnNames: Map | null = null; @@ -10725,7 +10721,7 @@ export class Lowerer { (id) => id !== nameNode && this.checker.getSymbolAtLocation(id) === symbol, ) ) { - this.pureTuples.set(body.id, slots); + this.ctx.pureTuples.set(body.id, slots); return; } const init = this.tupleOfSlots(slots, tupleType, nameNode, loc); @@ -11122,7 +11118,7 @@ export class Lowerer { } if (!symbol) return null; const direct = this.resolveKey(symbol, ident); - if (direct && this.pureTuples.has(direct.id)) { + if (direct && this.ctx.pureTuples.has(direct.id)) { // onlyForwarded proved every read forwards; a plain read here means // the analysis and the lowering disagree. throw new InternalCompilerError( diff --git a/packages/compiler/src/frontend/lowering/typed-arguments.ts b/packages/compiler/src/frontend/lowering/typed-arguments.ts index 90fef0e86..82b7f23c3 100644 --- a/packages/compiler/src/frontend/lowering/typed-arguments.ts +++ b/packages/compiler/src/frontend/lowering/typed-arguments.ts @@ -176,7 +176,7 @@ export function declareTypedArguments( if ( onlyForwarded(lowerer, node, (id) => id.text === "arguments" && argumentsOwner(id) === node) ) { - lowerer.pureTuples.set(local.id, slots); + lowerer.ctx.pureTuples.set(local.id, slots); return; } prologue.push({ @@ -273,7 +273,7 @@ function pureSlotsOf(lowerer: Lowerer, node: ts.Expression): IrLocal[] | null { if (!ts.isIdentifier(operand)) return null; const local = operand.text === "arguments" ? lowerer.ctx.argumentsLocal : lowerer.peekLocal(operand); - return local ? (lowerer.pureTuples.get(local.id) ?? null) : null; + return local ? (lowerer.ctx.pureTuples.get(local.id) ?? null) : null; } /** The positional values `node` forwards when it is a pure-forwarded tuple @@ -466,7 +466,7 @@ export function lowerTupleAliasDecl(lowerer: Lowerer, decl: ts.VariableDeclarati // An alias of a pure-forwarded tuple is itself only forwarded // (onlyForwarded followed it): it names the same slots. const local = lowerer.declareLocal(decl.name, decl.name.text, tupleType, false); - lowerer.pureTuples.set(local.id, slots); + lowerer.ctx.pureTuples.set(local.id, slots); return { kind: "block", body: [], loc: locOf(decl) }; } const init = lowerer.lowerExpr(stripTypeWrappers(decl.initializer)); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6385-variadic-wrapper-shared-local-names.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6385-variadic-wrapper-shared-local-names.ts.json new file mode 100644 index 000000000..5791565f2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6385-variadic-wrapper-shared-local-names.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6385-variadic-wrapper-shared-local-names.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6385-variadic-wrapper-shared-local-names.ts b/tests/corpus/6385-variadic-wrapper-shared-local-names.ts new file mode 100644 index 000000000..2d4272b55 --- /dev/null +++ b/tests/corpus/6385-variadic-wrapper-shared-local-names.ts @@ -0,0 +1,56 @@ +// Variadic wrappers whose bodies declare the same local names: one only +// forwards its `arguments` (or its alias of them), the other also reads an +// element, so its tuple exists. Each wrapper forwards its own arguments. +type AnyFn = (...args: any) => any; + +function forward(fn: F): F { + return function (this: unknown) { + return fn.apply(this, arguments as any); + } as F; +} + +function logFirst(fn: F): F { + return function (this: unknown) { + console.log("first:", arguments[0], "of", arguments.length); + return fn.apply(this, arguments as any); + } as F; +} + +function forwardAlias(fn: F): F { + return function (this: unknown) { + const args = arguments as any; + return fn.apply(this, args); + } as F; +} + +function logFirstAlias(fn: F): F { + return function (this: unknown) { + const args = arguments as any; + console.log("alias first:", args[0]); + return fn.apply(this, args); + } as F; +} + +function add3(a: number, b: number, c: number): number { + return a + b + c; +} + +function greet(name: string): string { + return "hi " + name; +} + +const sum = forward(add3); +console.log(sum(1, 2, 3)); +const hello = logFirst(greet); +console.log(hello("ada")); + +const sumAlias = forwardAlias(add3); +console.log(sumAlias(4, 5, 6)); +const helloAlias = logFirstAlias(greet); +console.log(helloAlias("grace")); + +// The other order: the wrapper that reads an element first. +const hello2 = logFirst(greet); +console.log(hello2("linus")); +const sum2 = forward(add3); +console.log(sum2(7, 8, 9)); diff --git a/tests/harness/corpus-costs/6385-variadic-wrapper-shared-local-names.ts.json b/tests/harness/corpus-costs/6385-variadic-wrapper-shared-local-names.ts.json new file mode 100644 index 000000000..187f1764f --- /dev/null +++ b/tests/harness/corpus-costs/6385-variadic-wrapper-shared-local-names.ts.json @@ -0,0 +1 @@ +{ "plain": 2200, "san": 3300 } From c17eec0261ae43502a29e76ba57a3cde02299d86 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 19:03:28 -0700 Subject: [PATCH 07/39] Compile event-loop metrics, predicate-narrowed catch bindings and other wrapper-reachable gaps Once generic wrappers compile (#1413), the code behind them is reachable. This closes the general gaps found there: - performance.eventLoopUtilization() and monitorEventLoopDelay()'s IntervalHistogram (enable, disable, reset, percentile and the min, max, mean, stddev, count and exceeds readings), under the fallback declarations and @types/node. A new runtime unit, scr_perf_loop.c, links only for programs that read them (the perfLoop feature): an unref'd sampling interval records into HdrHistogram-shaped buckets, and utilization measures active time as the main thread's CPU time since the loop started. - Catch bindings narrowed by a user type predicate or an assertion read their members through the checked-dynamic value. - `??` with a function default of a different signature takes the optional callback's own function type and adapts the default. - Optional calls on interface-typed receivers dispatch like the plain protocol call. - `any` parameters of function declarations and spelled function types are checked-dynamic slots, and a generic instantiated at `any` takes `unknown` there. - `'key' in err` on Error receivers answers from the declaring subclasses. - Object.entries over a generic record resolves `keyof T extends never ? unknown : T[keyof T]` through the binding. Co-Authored-By: Claude Opus 5.5 --- .../builtin-apis/performance-entries.mdx | 1 + .../src/generated/node-v24-compatibility.json | 40 +-- .../generated/node-v24-backlog.json | 94 +++--- .../generated/node-v24-internal.json | 56 +++- internal/compatibility/static-support.json | 4 + .../ambient/scriptc-node-fallback.d.ts | 29 ++ .../src/backend/executable-features.ts | 1 + packages/compiler/src/backend/library-pack.ts | 1 + packages/compiler/src/backend/llvm/emitter.ts | 17 + .../compiler/src/backend/llvm/lib-shared.ts | 8 + .../src/backend/native-link-info-core.ts | 2 + .../compiler/src/backend/native/contracts.ts | 2 + .../compiler/src/backend/native/executable.ts | 2 + .../src/backend/runtime-pack-targets.test.ts | 1 + .../compiler/src/backend/runtime-pack.test.ts | 1 + packages/compiler/src/backend/warm-cache.ts | 1 + .../src/executable/executable-cache.test.ts | 1 + .../src/executable/executable-cache.ts | 2 + .../frontend/lowering/builtins/performance.ts | 313 +++++++++++++++++- .../src/frontend/lowering/call-signatures.ts | 7 +- .../lowering/class-protocol-dispatch.ts | 8 +- .../frontend/lowering/generic-functions.ts | 14 +- .../src/frontend/lowering/lower-calls.ts | 20 +- .../src/frontend/lowering/lower-exprs.ts | 66 ++++ .../src/frontend/lowering/lower-stmts.ts | 3 +- .../compiler/src/frontend/lowering/lowerer.ts | 3 + .../src/frontend/lowering/surfaces.ts | 21 ++ packages/compiler/src/frontend/type-mapper.ts | 86 ++++- packages/compiler/src/index.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 14 + packages/compiler/src/ir/runtime-features.ts | 6 + packages/compiler/src/native/cli.ts | 1 + packages/compiler/src/native/prepare.ts | 1 + .../compiler/src/native/sanitizer.test.ts | 1 + packages/compiler/surface-manifest.json | 14 + .../6390-catch-binding-predicate.ts.json | 6 + .../6391-nullish-function-default.ts.json | 6 + ...6392-optional-chain-protocol-calls.ts.json | 6 + .../6393-function-types-any-params.ts.json | 6 + .../6394-in-key-error-subclasses.ts.json | 6 + .../6395-generic-object-entries.ts.json | 6 + .../6396-generic-any-instantiation.ts.json | 6 + .../corpus/6397-event-loop-metrics.ts.json | 6 + .../node-types/event-loop-metrics.ts.json | 6 + .../fixtures/node-types/timeout-type.ts.json | 6 + .../runtime-pack-matrix.mjs | 2 + packages/runtime/src/scr_lib.h | 15 + packages/runtime/src/scr_perf_loop.c | 305 +++++++++++++++++ tests/corpus/6390-catch-binding-predicate.ts | 42 +++ tests/corpus/6391-nullish-function-default.ts | 13 + .../6392-optional-chain-protocol-calls.ts | 47 +++ .../corpus/6393-function-types-any-params.ts | 8 + tests/corpus/6394-in-key-error-subclasses.ts | 25 ++ tests/corpus/6395-generic-object-entries.ts | 7 + .../corpus/6396-generic-any-instantiation.ts | 18 + tests/corpus/6397-event-loop-metrics.ts | 49 +++ tests/fixtures/node-types/README.md | 1 + .../fixtures/node-types/event-loop-metrics.ts | 49 +++ tests/fixtures/node-types/timeout-type.ts | 30 ++ tests/harness/project-config.test.ts | 26 ++ .../self-hosting-native-toolchain.test.ts | 1 + .../harness/self-hosting-runtime-pack.test.ts | 1 + 62 files changed, 1457 insertions(+), 84 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6390-catch-binding-predicate.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6391-nullish-function-default.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6392-optional-chain-protocol-calls.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6393-function-types-any-params.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6394-in-key-error-subclasses.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6395-generic-object-entries.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6396-generic-any-instantiation.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6397-event-loop-metrics.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/event-loop-metrics.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/timeout-type.ts.json create mode 100644 packages/runtime/src/scr_perf_loop.c create mode 100644 tests/corpus/6390-catch-binding-predicate.ts create mode 100644 tests/corpus/6391-nullish-function-default.ts create mode 100644 tests/corpus/6392-optional-chain-protocol-calls.ts create mode 100644 tests/corpus/6393-function-types-any-params.ts create mode 100644 tests/corpus/6394-in-key-error-subclasses.ts create mode 100644 tests/corpus/6395-generic-object-entries.ts create mode 100644 tests/corpus/6396-generic-any-instantiation.ts create mode 100644 tests/corpus/6397-event-loop-metrics.ts create mode 100644 tests/fixtures/node-types/event-loop-metrics.ts create mode 100644 tests/fixtures/node-types/timeout-type.ts diff --git a/docs/content/limitations/builtin-apis/performance-entries.mdx b/docs/content/limitations/builtin-apis/performance-entries.mdx index 957781b06..f634bb342 100644 --- a/docs/content/limitations/builtin-apis/performance-entries.mdx +++ b/docs/content/limitations/builtin-apis/performance-entries.mdx @@ -1 +1,2 @@ - **Performance entries:** `performance.mark()`, `measure()`, and the `getEntries` methods return entries with Node's fields, `toJSON()`, inspection, and identity. `Object.keys`, `for...in`, object spread, and `hasOwnProperty` on an entry are unsupported, and an entry stored in an `unknown` slot prints as a plain object. +- **Event-loop metrics:** `performance.eventLoopUtilization()` counts the main thread's CPU time since the event loop started as active time, so blocking system calls count as idle where Node counts them as active. `monitorEventLoopDelay()` supports `enable()`, `disable()`, `reset()`, `percentile()`, and the `min`, `max`, `mean`, `stddev`, `count`, and `exceeds` readings; the BigInt readings, `percentiles`, and non-literal option objects are unsupported. diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index e2e4cdd19..b0f0f2450 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -539,9 +539,9 @@ "apiEntries": 131, "static": { "supported": 0, - "partial": 19, + "partial": 25, "refused": 0, - "not-implemented": 112, + "not-implemented": 106, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -54688,9 +54688,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -54803,9 +54803,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -55286,9 +55286,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -55309,9 +55309,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -55677,9 +55677,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { @@ -55815,9 +55815,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 0ad30b783..26a0302c0 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1163, - "verify-gap": 2165, + "audit-partial": 1169, + "verify-gap": 2159, "replace-refusal": 41, "classify": 2, "implement": 85 @@ -54259,12 +54259,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:perf_hooks", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:perf_hooks.histogram.percentile", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] } } }, @@ -54384,12 +54387,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:perf_hooks", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:perf_hooks.histogram.reset", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] } } }, @@ -54909,12 +54915,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:perf_hooks", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:perf_hooks.histogram.disable", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] } } }, @@ -54934,12 +54943,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:perf_hooks", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:perf_hooks.histogram.enable", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] } } }, @@ -55334,12 +55346,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:perf_hooks", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "surface-manifest:node-builtin.perf_hooks.monitorEventLoopDelay", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] } } }, @@ -55494,12 +55509,15 @@ "priority": "high", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:perf_hooks", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "compiler-feature:perf_hooks.performance.eventLoopUtilization", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 2f0565f84..9870f7c48 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -566,9 +566,9 @@ "apiEntries": 131, "static": { "supported": 0, - "partial": 19, + "partial": 25, "refused": 0, - "not-implemented": 112, + "not-implemented": 106, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -75524,7 +75524,9 @@ "tests/corpus/5212-perf-marks-measures.ts", "tests/corpus/5213-perf-timing-errors.ts", "tests/corpus/5214-perf-entry-inspect.ts", - "tests/corpus/5215-perf-timing-validation.js" + "tests/corpus/5215-perf-timing-validation.js", + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" ] }, "anchorSource": "chapter" @@ -77565,8 +77567,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:perf_hooks" + "status": "partial", + "evidence": "compiler-feature:perf_hooks.histogram.percentile", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] }, "anchorSource": "exact" }, @@ -77680,8 +77686,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:perf_hooks" + "status": "partial", + "evidence": "compiler-feature:perf_hooks.histogram.reset", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] }, "anchorSource": "exact" }, @@ -78163,8 +78173,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:perf_hooks" + "status": "partial", + "evidence": "compiler-feature:perf_hooks.histogram.disable", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] }, "anchorSource": "exact" }, @@ -78186,8 +78200,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:perf_hooks" + "status": "partial", + "evidence": "compiler-feature:perf_hooks.histogram.enable", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] }, "anchorSource": "exact" }, @@ -78554,8 +78572,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:perf_hooks" + "status": "partial", + "evidence": "surface-manifest:node-builtin.perf_hooks.monitorEventLoopDelay", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] }, "anchorSource": "exact" }, @@ -78704,8 +78726,12 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:perf_hooks" + "status": "partial", + "evidence": "compiler-feature:perf_hooks.performance.eventLoopUtilization", + "tests": [ + "tests/corpus/6397-event-loop-metrics.ts", + "tests/fixtures/node-types/event-loop-metrics.ts" + ] }, "anchorSource": "exact" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index 5807c1ae9..f1130f9b1 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -132,6 +132,8 @@ "node-builtin.perf_hooks.performance.getEntries": ["tests/corpus/5212-perf-marks-measures.ts", "tests/corpus/5214-perf-entry-inspect.ts", "tests/corpus/5215-perf-timing-validation.js"], "node-builtin.perf_hooks.performance.clearMarks": ["tests/corpus/5212-perf-marks-measures.ts", "tests/corpus/5213-perf-timing-errors.ts", "tests/corpus/5215-perf-timing-validation.js"], "node-builtin.perf_hooks.performance.clearMeasures": ["tests/corpus/5212-perf-marks-measures.ts"], + "node-builtin.perf_hooks.performance.eventLoopUtilization": ["tests/corpus/6397-event-loop-metrics.ts", "tests/fixtures/node-types/event-loop-metrics.ts"], + "node-builtin.perf_hooks.monitorEventLoopDelay": ["tests/corpus/6397-event-loop-metrics.ts", "tests/fixtures/node-types/event-loop-metrics.ts"], "node-builtin.process": ["tests/corpus/990-process-basics.ts", "tests/corpus/2314-process-introspection.ts"], "node-builtin.process.hrtime": ["tests/corpus/process-hrtime.js"], "node-builtin.process.memoryUsage": ["tests/corpus/5210-process-memory-usage.ts"], @@ -232,6 +234,8 @@ { "chapter": "util", "symbols": ["util.parseEnv"], "status": "partial", "evidence": ["tests/corpus/node24-env-parse.ts", "tests/corpus/node24-env-parse-errors.ts", "tests/corpus/node24-env-imports.cjs", "tests/fixtures/node-types/env-files.ts", "tests/harness/project-config.test.ts"] }, { "chapter": "process", "symbols": ["process.memoryUsage.rss"], "status": "partial", "evidence": ["tests/corpus/5210-process-memory-usage.ts"] }, { "chapter": "perf_hooks", "symbols": ["performance.now"], "status": "partial", "evidence": ["tests/corpus/2427-perf-hooks-now.ts", "tests/corpus/2446-performance-global.ts"] }, + { "chapter": "perf_hooks", "symbols": ["performance.eventLoopUtilization"], "status": "partial", "evidence": ["tests/corpus/6397-event-loop-metrics.ts", "tests/fixtures/node-types/event-loop-metrics.ts"] }, + { "chapter": "perf_hooks", "symbols": ["histogram.enable", "histogram.disable", "histogram.percentile", "histogram.reset"], "status": "partial", "evidence": ["tests/corpus/6397-event-loop-metrics.ts", "tests/fixtures/node-types/event-loop-metrics.ts"] }, { "chapter": "perf_hooks", "symbols": ["performance.mark", "performance.measure", "performance.getEntries", "performance.getEntriesByName", "performance.getEntriesByType", "performance.clearMarks", "performance.clearMeasures"], "status": "partial", "evidence": ["tests/corpus/5212-perf-marks-measures.ts", "tests/corpus/5213-perf-timing-errors.ts", "tests/corpus/5214-perf-entry-inspect.ts", "tests/corpus/5215-perf-timing-validation.js"] }, { "chapter": "perf_hooks", "symbols": ["PerformanceEntry", "PerformanceMark", "PerformanceMeasure"], "status": "partial", "evidence": ["tests/corpus/5212-perf-marks-measures.ts", "tests/corpus/5214-perf-entry-inspect.ts"] }, { "chapter": "perf_hooks", "parent": "Class: `PerformanceEntry`", "symbols": ["duration", "entryType", "name", "startTime"], "status": "partial", "evidence": ["tests/corpus/5212-perf-marks-measures.ts", "tests/corpus/5214-perf-entry-inspect.ts"] }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 0a0837389..dc9f2be2a 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -1166,8 +1166,37 @@ declare module "node:perf_hooks" { getEntriesByType(type: EntryType): PerformanceEntry[]; clearMarks(name?: string): void; clearMeasures(name?: string): void; + eventLoopUtilization( + utilization1?: EventLoopUtilization, + utilization2?: EventLoopUtilization, + ): EventLoopUtilization; } export const performance: Performance; + /* Event-loop metrics: utilization (idle/active ms since the loop started) + * and monitorEventLoopDelay's sampling histogram (nanoseconds). */ + export interface EventLoopUtilization { + idle: number; + active: number; + utilization: number; + } + export interface EventLoopMonitorOptions { + resolution?: number | undefined; + } + export interface Histogram { + readonly count: number; + readonly exceeds: number; + readonly max: number; + readonly mean: number; + readonly min: number; + readonly stddev: number; + percentile(percentile: number): number; + reset(): void; + } + export interface IntervalHistogram extends Histogram { + enable(): boolean; + disable(): boolean; + } + export function monitorEventLoopDelay(options?: EventLoopMonitorOptions): IntervalHistogram; } declare module "perf_hooks" { export * from "node:perf_hooks"; diff --git a/packages/compiler/src/backend/executable-features.ts b/packages/compiler/src/backend/executable-features.ts index a565965f1..141ee4962 100644 --- a/packages/compiler/src/backend/executable-features.ts +++ b/packages/compiler/src/backend/executable-features.ts @@ -40,5 +40,6 @@ export function executableLinkFeatures(mod: IrModule): NativeLinkFeatures { tls: features.tls, tlsCa: features.tlsCa, cipher: features.cipher, + perfLoop: features.perfLoop, }; } diff --git a/packages/compiler/src/backend/library-pack.ts b/packages/compiler/src/backend/library-pack.ts index 833ef93e7..e260430e3 100644 --- a/packages/compiler/src/backend/library-pack.ts +++ b/packages/compiler/src/backend/library-pack.ts @@ -52,6 +52,7 @@ export async function compilePackedLibrary( nodeTest: false, tls: false, cipher: false, + perfLoop: false, tlsCa: false, }; const selection = await loadRuntimePack({ diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 9e2d3524e..3981c5da0 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -2285,6 +2285,7 @@ export class LlEmitter { if (runsLoop) { this.declare(`declare zeroext i1 @scr_loop_run(ptr)`); if (this.mod.commonJsEntry === true) this.declare(`declare void @scr_loop_commonjs_entry()`); + if (this.readsLoopMetrics()) this.declare(`declare void @scr_perf_loop_mark()`); this.declare(`declare zeroext i1 @scr_report_unhandled_rejections()`); this.declare(`declare void @scr_discard_unhandled_rejections()`); } @@ -2843,6 +2844,8 @@ export class LlEmitter { ...(runsLoop ? [ ...(this.mod.commonJsEntry === true ? [` call void @scr_loop_commonjs_entry()`] : []), + // performance.eventLoopUtilization measures from here on. + ...(this.readsLoopMetrics() ? [` call void @scr_perf_loop_mark()`] : []), ` %loop_rejection = call zeroext i1 @scr_loop_run(ptr ${asyncEntry ? "%top" : "null"})`, ` %lexc = call zeroext i1 @scr_exc_pending()`, ` br i1 %lexc, label %luncaught, label %lok`, @@ -7858,6 +7861,20 @@ export class LlEmitter { /** Moves need plain slots that nothing else reads behind the binding's * back: no debugger view, no coroutine frame, no borrowed (+0) return. */ + /** Whether the program reads event-loop utilization (perf.loopStart / + * perf.idleTime): main then marks the loop's start before running it. */ + private loopMetricsRead: boolean | undefined; + private readsLoopMetrics(): boolean { + if (this.loopMetricsRead !== undefined) return this.loopMetricsRead; + const visitor = { + expr: (e: IrExpr): boolean => + !(e.kind === "libCall" && (e.fn === "perf.loopStart" || e.fn === "perf.idleTime")), + stmt: (): boolean => true, + }; + this.loopMetricsRead = !this.mod.functions.every((fn) => everyStmtList(fn.body, visitor)); + return this.loopMetricsRead; + } + private lastUseMovesAllowed(): boolean { return ( this.debug === null && diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index be67e1b67..8ab89bd22 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -273,6 +273,14 @@ export const LIB_FN_SYMS: Record = { "perf.entryDetail": "scr_perf_entry_detail", "perf.entryKeep": "scr_perf_entry_keep", "perf.entryRef": "scr_perf_entry_ref", + "perf.loopStart": "scr_perf_loop_start", + "perf.idleTime": "scr_perf_idle_time", + "perf.eldNew": "scr_eld_new", + "perf.eldEnable": "scr_eld_enable", + "perf.eldDisable": "scr_eld_disable", + "perf.eldReset": "scr_eld_reset", + "perf.eldPercentile": "scr_eld_percentile", + "perf.eldStat": "scr_eld_stat", "process.memoryUsageTake": "scr_process_memory_usage_take", "process.memoryUsageField": "scr_process_memory_usage_field", "process.rss": "scr_process_rss", diff --git a/packages/compiler/src/backend/native-link-info-core.ts b/packages/compiler/src/backend/native-link-info-core.ts index 3beb84a20..048deecb1 100644 --- a/packages/compiler/src/backend/native-link-info-core.ts +++ b/packages/compiler/src/backend/native-link-info-core.ts @@ -50,6 +50,8 @@ export interface NativeLinkFeatures { /** crypto.createCipheriv/createDecipheriv: scr_cipher.c plus the mbedTLS * archive. */ cipher: boolean; + /** perf_hooks event-loop metrics: scr_perf_loop.c. */ + perfLoop: boolean; tlsCa: boolean; } diff --git a/packages/compiler/src/backend/native/contracts.ts b/packages/compiler/src/backend/native/contracts.ts index 875a723bc..bc9df5618 100644 --- a/packages/compiler/src/backend/native/contracts.ts +++ b/packages/compiler/src/backend/native/contracts.ts @@ -199,6 +199,8 @@ export interface CcOptions { /** crypto.createCipheriv/createDecipheriv: compiles scr_cipher.c and links * the mbedTLS archive (shared with tls). */ cipher?: boolean; + /** perf_hooks event-loop metrics: compiles scr_perf_loop.c. */ + perfLoop?: boolean; /** Internal compiler hook: called only after a strict native artifact hit * or a successful stable build has installed `outPath`. The executable * frontend cache uses it to publish its stamp after native dependencies diff --git a/packages/compiler/src/backend/native/executable.ts b/packages/compiler/src/backend/native/executable.ts index 6c8673fe4..0b6ab945c 100644 --- a/packages/compiler/src/backend/native/executable.ts +++ b/packages/compiler/src/backend/native/executable.ts @@ -510,6 +510,8 @@ export async function compileCInternal( // The performance timeline (every perf_hooks user-timing call selects // dynAsync, whose unit carries the timeline's buffer warning). ...(opts.dynAsync ? [rt(join(rtDir, "scr_perf.c"))] : []), + // perf_hooks event-loop metrics, only for programs that read them. + ...(opts.perfLoop ? [rt(join(rtDir, "scr_perf_loop.c"))] : []), // Blob and File (every blob.* call selects dynAsync, whose unit boxes // their reads as dyn promises). ...(opts.dynAsync ? [rt(join(rtDir, "scr_blob.c"))] : []), diff --git a/packages/compiler/src/backend/runtime-pack-targets.test.ts b/packages/compiler/src/backend/runtime-pack-targets.test.ts index faa335e33..1d500957a 100644 --- a/packages/compiler/src/backend/runtime-pack-targets.test.ts +++ b/packages/compiler/src/backend/runtime-pack-targets.test.ts @@ -119,6 +119,7 @@ const features = { tls: false, tlsCa: false, cipher: false, + perfLoop: false, }; test.each([ diff --git a/packages/compiler/src/backend/runtime-pack.test.ts b/packages/compiler/src/backend/runtime-pack.test.ts index ffe581366..3521b47bd 100644 --- a/packages/compiler/src/backend/runtime-pack.test.ts +++ b/packages/compiler/src/backend/runtime-pack.test.ts @@ -56,6 +56,7 @@ const BASE: NativeLinkFeatures = { tls: false, tlsCa: false, cipher: false, + perfLoop: false, }; async function fixture(target: NativeTargetSpec = MACOS_ARM64_TARGET) { diff --git a/packages/compiler/src/backend/warm-cache.ts b/packages/compiler/src/backend/warm-cache.ts index 67e627c91..232701e6b 100644 --- a/packages/compiler/src/backend/warm-cache.ts +++ b/packages/compiler/src/backend/warm-cache.ts @@ -61,6 +61,7 @@ export async function warmNativeCaches( nodeTest: false, tls: false, cipher: false, + perfLoop: false, tlsCa: false, }, }); diff --git a/packages/compiler/src/executable/executable-cache.test.ts b/packages/compiler/src/executable/executable-cache.test.ts index e5887e855..b6bd90b06 100644 --- a/packages/compiler/src/executable/executable-cache.test.ts +++ b/packages/compiler/src/executable/executable-cache.test.ts @@ -57,6 +57,7 @@ const native: EarlyExecutableNativeFeatures = { tls: false, tlsCa: false, cipher: false, + perfLoop: false, }; async function fixture(): Promise<{ diff --git a/packages/compiler/src/executable/executable-cache.ts b/packages/compiler/src/executable/executable-cache.ts index ee9d84fcf..c020a1e1c 100644 --- a/packages/compiler/src/executable/executable-cache.ts +++ b/packages/compiler/src/executable/executable-cache.ts @@ -79,6 +79,7 @@ export interface EarlyExecutableNativeFeatures { nodeTest: boolean; tls: boolean; cipher: boolean; + perfLoop: boolean; tlsCa: boolean; } @@ -193,6 +194,7 @@ const BOOLEAN_NATIVE_KEYS = [ "tls", "tlsCa", "cipher", + "perfLoop", ] as const satisfies readonly (keyof EarlyExecutableNativeFeatures)[]; function validNativeFeatures(value: unknown): value is EarlyExecutableNativeFeatures { diff --git a/packages/compiler/src/frontend/lowering/builtins/performance.ts b/packages/compiler/src/frontend/lowering/builtins/performance.ts index 2a9962b0f..19b585e37 100644 --- a/packages/compiler/src/frontend/lowering/builtins/performance.ts +++ b/packages/compiler/src/frontend/lowering/builtins/performance.ts @@ -134,6 +134,12 @@ export function lowerPerfHooksCall( loc, }; } + if ( + access.name.text === "eventLoopUtilization" && + isPerfHooksPerformanceExpr(lowerer, access.expression) + ) { + return lowerEventLoopUtilization(lowerer, expr); + } const timeline = PERF_TIMELINE_CALLS.get(access.name.text); if (timeline && isPerfHooksPerformanceExpr(lowerer, access.expression)) { return lowerPerfTimelineCall(lowerer, expr, access.name.text, timeline, loc); @@ -142,7 +148,7 @@ export function lowerPerfHooksCall( lowerer.noLowering( `perf_hooks performance.${access.name.text}`, expr, - "performance.now() (and its .bind(performance) function value), mark, measure, the getEntries family, clearMarks and clearMeasures are the lowered surface", + "performance.now() (and its .bind(performance) function value), mark, measure, the getEntries family, clearMarks, clearMeasures and eventLoopUtilization are the lowered surface", ); } return null; @@ -513,3 +519,308 @@ export function fencePerfEntryKeyWalk( `${what} over performance entries (Node keeps their fields as prototype getters, so own-key walks see none; read the fields or call toJSON())`, ); } + +/* ── event-loop metrics: eventLoopUtilization and monitorEventLoopDelay ── */ + +/** The stdlib IntervalHistogram (monitorEventLoopDelay's result), by the + * receiver's checker type. Its value is the runtime histogram handle. */ +function isIntervalHistogram(lowerer: Lowerer, node: ts.Expression): boolean { + const symbol = lowerer.typeOf(node).getSymbol(); + return symbol?.name === "IntervalHistogram" && lowerer.isStdlibSymbol(symbol); +} + +/** IntervalHistogram's numeric members, as perf.eldStat selectors. */ +const HISTOGRAM_STATS: ReadonlyMap = new Map([ + ["min", 0], + ["max", 1], + ["mean", 2], + ["stddev", 3], + ["count", 4], + ["exceeds", 5], +]); + +/** `h.min`, `h.max`, … on an IntervalHistogram: the runtime's current + * statistic (Node's hdr_histogram values; nanoseconds). Null for every + * other read. */ +export function lowerHistogramProperty( + lowerer: Lowerer, + expr: ts.PropertyAccessExpression, +): IrExpr | null { + const which = HISTOGRAM_STATS.get(expr.name.text); + if ( + which === undefined || + expr.questionDotToken || + !isIntervalHistogram(lowerer, expr.expression) + ) + return null; + const loc = locOf(expr); + return { + kind: "libCall", + fn: "perf.eldStat", + args: [lowerer.lowerExprExpecting(expr.expression, F64), numLit(which, loc)], + type: F64, + loc, + }; +} + +/** enable(), disable(), reset() and percentile(p) on an IntervalHistogram. + * Other members (the BigInt twins, the percentiles Map) fence by name. */ +export function lowerHistogramMethodCall( + lowerer: Lowerer, + expr: ts.CallExpression, + access: ts.PropertyAccessExpression, +): IrExpr | null { + if (access.questionDotToken || !isIntervalHistogram(lowerer, access.expression)) return null; + const loc = locOf(expr); + const name = access.name.text; + const handle = (): IrExpr => lowerer.lowerExprExpecting(access.expression, F64); + const args = expr.arguments.nodes; + if ((name === "enable" || name === "disable" || name === "reset") && args.length === 0) { + const fn = + name === "enable" + ? "perf.eldEnable" + : name === "disable" + ? "perf.eldDisable" + : "perf.eldReset"; + return { kind: "libCall", fn, args: [handle()], type: name === "reset" ? VOID : BOOL, loc }; + } + if (name === "percentile" && args.length === 1 && !ts.isSpreadElement(args[0]!)) { + // Node validates first: NaN, p <= 0 and p > 100 throw ERR_OUT_OF_RANGE. + const h = lowerer.declareHiddenLocal("%histogram", F64); + const p = lowerer.declareHiddenLocal("%percentile", F64); + const pRef = (): IrExpr => varRef(p.id, F64, loc); + const cmp = (op: "!==" | "<=" | ">", left: IrExpr, right: IrExpr): IrExpr => ({ + kind: "bin", + op, + left, + right, + type: BOOL, + loc, + }); + const or = (left: IrExpr, right: IrExpr): IrExpr => ({ + kind: "logical", + op: "||", + left, + right, + type: BOOL, + loc, + }); + const outOfRange = or( + or(cmp("!==", pRef(), pRef()), cmp("<=", pRef(), numLit(0, loc))), + cmp(">", pRef(), numLit(100, loc)), + ); + const message: IrExpr = { + kind: "strConcat", + left: { + kind: "strLit", + value: 'The value of "percentile" is out of range. It must be > 0 && <= 100. Received ', + type: STRING, + loc, + }, + right: { kind: "toString", operand: pRef(), type: STRING, loc }, + type: STRING, + loc, + }; + const thrown: IrExpr = { + kind: "libCall", + fn: "error.nodeThrow", + args: [ + numLit(2, loc), + { kind: "strLit", value: "ERR_OUT_OF_RANGE", type: STRING, loc }, + message, + ], + type: F64, + loc, + }; + return { + kind: "seqExpr", + stmts: [ + { kind: "varDecl", localId: h.id, init: handle(), loc }, + { kind: "varDecl", localId: p.id, init: lowerer.lowerExprExpecting(args[0]!, F64), loc }, + ], + result: { + kind: "ternary", + cond: outOfRange, + then: thrown, + else_: { + kind: "libCall", + fn: "perf.eldPercentile", + args: [varRef(h.id, F64, loc), pRef()], + type: F64, + loc, + }, + type: F64, + loc, + }, + type: F64, + loc, + }; + } + lowerer.noLowering( + `IntervalHistogram.${name}`, + expr, + "enable(), disable(), reset(), percentile(p) and the min, max, mean, stddev, count and exceeds readings are the lowered surface", + ); +} + +/** `monitorEventLoopDelay(options?)` from node:perf_hooks (a named import + * or a namespace member): a new sampling histogram handle. The resolution + * must be a literal-free number expression or an object literal option. */ +export function lowerMonitorEventLoopDelayCall( + lowerer: Lowerer, + expr: ts.CallExpression, +): IrExpr | null { + const callee = expr.expression; + const bi = ts.isIdentifier(callee) + ? builtinImportOf(lowerer, callee) + : ts.isPropertyAccessExpression(callee) && !callee.questionDotToken + ? lowerer.builtinMemberOf(callee) + : null; + if (bi === null || bi.module !== "perf_hooks" || bi.member !== "monitorEventLoopDelay") + return null; + const loc = locOf(expr); + const args = expr.arguments.nodes; + let resolution: IrExpr = numLit(10, loc); + if (args.length > 1 || args.some(ts.isSpreadElement)) { + lowerer.noLowering( + "this monitorEventLoopDelay call form", + expr, + "pass at most one options object", + ); + } + if (args.length === 1) { + const options = args[0]!; + if (!ts.isObjectLiteralExpression(options)) { + lowerer.noLowering( + "monitorEventLoopDelay with a non-literal options object", + options, + "spell the options inline: monitorEventLoopDelay({ resolution: 20 })", + ); + } + for (const property of options.properties.nodes) { + if ( + !ts.isPropertyAssignment(property) || + !ts.isIdentifier(property.name) || + property.name.text !== "resolution" + ) { + lowerer.noLowering( + "monitorEventLoopDelay options other than resolution", + property, + "resolution is the one option", + ); + } + resolution = lowerer.lowerExprExpecting(property.initializer, F64); + } + } + return { kind: "libCall", fn: "perf.eldNew", args: [resolution], type: F64, loc }; +} + +/** performance.eventLoopUtilization(u1?, u2?) — Node's + * lib/internal/perf/event_loop_utilization.js over the runtime's loop + * start and idle time, one lifted helper per arity. */ +function lowerEventLoopUtilization(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { + const loc = locOf(expr); + const args = expr.arguments.nodes; + const resultT = lowerer.mapTypeOf(lowerer.typeOf(expr)); + if (resultT?.kind !== "record" || args.length > 2 || args.some(ts.isSpreadElement)) { + lowerer.noLowering("this performance.eventLoopUtilization call form", expr); + } + const helper = eluHelperOf(lowerer, args.length, resultT); + return { + kind: "call", + callee: helper, + args: args.map((arg) => lowerer.lowerExprExpecting(arg, resultT)), + type: resultT, + loc, + }; +} + +function eluHelperOf(lowerer: Lowerer, arity: number, recT: IrType & { kind: "record" }): string { + const name = `%perf.elu.${arity}`; + if (lowerer.liftedFns.some((f) => f.name === name)) return name; + const loc: SrcLoc = { file: "", start: 0, end: 0 }; + const f64Local = (id: string) => ({ id, name: id, type: F64, mutable: false }); + const params = Array.from({ length: arity }, (_, i) => ({ + localId: `u${i + 1}.0`, + name: `u${i + 1}`, + type: recT as IrType, + })); + const locals = [ + ...params.map((p) => ({ id: p.localId, name: p.name, type: recT as IrType, mutable: false })), + f64Local("ls.0"), + f64Local("idle.0"), + f64Local("active.0"), + ]; + const ref = (id: string): IrExpr => varRef(id, F64, loc); + const field = (param: string, f: string): IrExpr => ({ + kind: "recordGet", + obj: varRef(param, recT, loc), + shapeId: recT.shapeId, + field: f, + type: F64, + loc, + }); + const bin = (op: "+" | "-" | "/" | "<=", left: IrExpr, right: IrExpr): IrExpr => ({ + kind: "bin", + op, + left, + right, + type: op === "<=" ? BOOL : F64, + loc, + }); + const record = (idle: IrExpr, active: IrExpr, utilization: IrExpr): IrExpr => ({ + kind: "recordLit", + fields: [ + { name: "idle", value: idle }, + { name: "active", value: active }, + { name: "utilization", value: utilization }, + ], + type: recT, + loc, + }); + const result = (idle: IrExpr, active: IrExpr): IrStmt => ({ + kind: "return", + value: record(idle, active, bin("/", active, bin("+", idle, active))), + loc, + }); + const decl = (id: string, init: IrExpr): IrStmt => ({ kind: "varDecl", localId: id, init, loc }); + const body: IrStmt[] = [ + decl("ls.0", { kind: "libCall", fn: "perf.loopStart", args: [], type: F64, loc }), + { + kind: "if", + cond: bin("<=", ref("ls.0"), numLit(0, loc)), + then: [ + { kind: "return", value: record(numLit(0, loc), numLit(0, loc), numLit(0, loc)), loc }, + ], + else_: null, + loc, + }, + ]; + if (arity === 2) { + body.push( + decl("idle.0", bin("-", field("u1.0", "idle"), field("u2.0", "idle"))), + decl("active.0", bin("-", field("u1.0", "active"), field("u2.0", "active"))), + result(ref("idle.0"), ref("active.0")), + ); + } else { + body.push( + decl("idle.0", { kind: "libCall", fn: "perf.idleTime", args: [], type: F64, loc }), + decl( + "active.0", + bin( + "-", + bin("-", { kind: "libCall", fn: "perf.now", args: [], type: F64, loc }, ref("ls.0")), + ref("idle.0"), + ), + ), + arity === 0 + ? result(ref("idle.0"), ref("active.0")) + : result( + bin("-", ref("idle.0"), field("u1.0", "idle")), + bin("-", ref("active.0"), field("u1.0", "active")), + ), + ); + } + lowerer.liftedFns.push({ name, params, returnType: recT, locals, body, loc }); + return name; +} diff --git a/packages/compiler/src/frontend/lowering/call-signatures.ts b/packages/compiler/src/frontend/lowering/call-signatures.ts index ef2900a7c..533ff79b0 100644 --- a/packages/compiler/src/frontend/lowering/call-signatures.ts +++ b/packages/compiler/src/frontend/lowering/call-signatures.ts @@ -443,7 +443,12 @@ export function paramShapes( declParam, lowerer.runtimeOptionalBindingType( declParam.name, - lowerer.mapTypeOf(tsType) ?? lowerer.irTypeOf(declParam.name), + lowerer.mapTypeOf(tsType) ?? + // A TypeScript instantiation at `any` (a type argument inferred + // from an untyped value) takes the checked-dynamic slot. + ((tsType.flags & ts.TypeFlags.Any) !== 0 && !isJsSourceFile(declParam.getSourceFile()) + ? DYN + : lowerer.irTypeOf(declParam.name)), ), lowerer.shapes, lowerer.unions, diff --git a/packages/compiler/src/frontend/lowering/class-protocol-dispatch.ts b/packages/compiler/src/frontend/lowering/class-protocol-dispatch.ts index c8e56f3cc..1b881ed43 100644 --- a/packages/compiler/src/frontend/lowering/class-protocol-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-protocol-dispatch.ts @@ -188,7 +188,8 @@ function protocolSignature( call: ts.CallExpression, access: ts.PropertyAccessExpression, ): ProtocolSignature | null { - const recvTs = lowerer.typeOf(access.expression); + // A guarded optional step's receiver still carries its nullish arms. + const recvTs = lowerer.checker.getNonNullableType(lowerer.typeOf(access.expression)); const property = lowerer.checker.getPropertyOfType(recvTs, access.name.text); if (!property) return null; const declarations = lowerer.checker.declarationsOf(property); @@ -240,10 +241,11 @@ export function lowerProtocolMethodCall( access: ts.PropertyAccessExpression, recv: IrExpr, ): IrExpr | null { + // An optional chain that already guarded this step (`s?.m(x)`, the chain + // re-dispatching with the narrowed receiver) calls like a plain one. if ( recv.type.kind !== "dyn" || - call.questionDotToken || - access.questionDotToken || + lowerer.chainBlocked(call, access) || call.arguments.nodes.some(ts.isSpreadElement) ) return null; diff --git a/packages/compiler/src/frontend/lowering/generic-functions.ts b/packages/compiler/src/frontend/lowering/generic-functions.ts index e1fa5994d..ac611a7df 100644 --- a/packages/compiler/src/frontend/lowering/generic-functions.ts +++ b/packages/compiler/src/frontend/lowering/generic-functions.ts @@ -302,7 +302,13 @@ export function genericCallInstance( const retTs = lowerer.checker.getReturnTypeOfSignature(rsig); const local = localClassResultInstance(lowerer, expr, info, rsig, params, retTs); if (local) return local; - const mappedReturn = lowerer.mapTypeOf(retTs); + // A result instantiated at `any` (a type argument inferred from an + // untyped value, such as an untyped forwarding call) is checked-dynamic. + const mappedReturn = + lowerer.mapTypeOf(retTs) ?? + ((retTs.flags & ts.TypeFlags.Any) !== 0 && !isJsSourceFile(info.decl.getSourceFile()) + ? DYN + : null); if (!mappedReturn) { fenceGenericSignatureResult(lowerer, expr, retTs); lowerer.badType(expr, retTs); @@ -691,7 +697,11 @@ function unifySignatureBindings( tsBindings.set(sym, lowerer.typeParamTsResolver(inst) ?? inst); } if (!bindings.has(sym)) { - const mapped = lowerer.mapTypeOf(inst); + const mapped = + lowerer.mapTypeOf(inst) ?? + ((inst.flags & ts.TypeFlags.Any) !== 0 && !isJsSourceFile(info.decl.getSourceFile()) + ? DYN + : null); // A visitor's inferred T can be void. It still binds the // return convention of `(node) => T`; discarding it leaves // the callback's return type spuriously uninstantiated. diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 3bebfd2af..23629a7ba 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -143,6 +143,8 @@ import { import { fencePerfEntryKeyWalk, isPerfEntryType, + lowerHistogramMethodCall, + lowerMonitorEventLoopDelayCall, lowerPerfHooksCall, perfEntryTag, } from "./builtins/performance.js"; @@ -241,6 +243,15 @@ const ZLIB_STREAM_METHODS: ReadonlySet = new Set(["flush", "params", "cl export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { const loc = locOf(expr); + // node:perf_hooks monitorEventLoopDelay (named import or namespace member). + if ( + (ts.isIdentifier(expr.expression) && expr.expression.text === "monitorEventLoopDelay") || + (ts.isPropertyAccessExpression(expr.expression) && + expr.expression.name.text === "monitorEventLoopDelay") + ) { + const histogram = lowerMonitorEventLoopDelayCall(lowerer, expr); + if (histogram) return histogram; + } // Object's checker return type is `any`. Claim known object inputs // before generic checked-dynamic dispatch tries to load the constructor. @@ -1379,6 +1390,7 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { // .bind(performance) function value over the runtime's // process-start-anchored monotonic clock. lowerPerfHooksCall(lowerer, expr, expr.expression) ?? + lowerHistogramMethodCall(lowerer, expr, expr.expression) ?? // The composed crypto pattern (randomBytes(n).toString(enc)) // — its receiver is a Buffer-typed CALL no other lowering claims. lowerer.lowerCryptoComposedCall(expr, expr.expression) ?? @@ -3289,7 +3301,13 @@ function lowerDynReceiverMethodCall( // array — scalar narrowings bridge through maybeNarrow's dynCheck and // take the ordinary typed paths, but there is no static home for an // any-elemented array). Typed receivers keep their own lowerings. - const recvTs = lowerer.typeOf(access.expression); + // An optional step the chain already guarded (`s?.m(x)`) has a receiver + // proven non-nullish. + const rawRecvTs = lowerer.typeOf(access.expression); + const recvTs = + access.questionDotToken !== undefined && lowerer.chainHandled.has(access) + ? lowerer.checker.getNonNullableType(rawRecvTs) + : rawRecvTs; if (lowerer.classImplementedProtocol(recvTs)) { const property = lowerer.checker.getPropertyOfType(recvTs, access.name.text); if ( diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 80b5bb333..aa597d8a2 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -1,3 +1,5 @@ +import { lowerHistogramProperty } from "./builtins/performance.js"; +import { cleanFuncAdaptable } from "./coercions/function-adapters.js"; import { staticFunctionNameRead } from "./static-function-names.js"; import { argumentsOwner, typedArgumentsArity, typedArgumentsCandidate } from "./typed-arguments.js"; import { dateJsonType, isDateJsonSource } from "./builtins/dates.js"; @@ -1948,6 +1950,11 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { const staticName = staticFunctionNameRead(lowerer, expr); if (staticName !== null) return { kind: "strLit", value: staticName, type: STRING, loc }; } + // An IntervalHistogram's readings (min, max, mean, stddev, count, exceeds). + { + const reading = lowerHistogramProperty(lowerer, expr); + if (reading) return reading; + } // `.length` of a forwarded fixed tuple (a typed `arguments`, a tuple // rest parameter, an alias of either): the signature's arity. if (expr.name.text === "length" && !expr.questionDotToken) { @@ -4715,6 +4722,22 @@ function lowerNullishPair( ); } } + // An optional callback defaulted to a function of another signature + // (`o.tags ?? (() => ({}))`, fewer parameters or a narrower result): the + // result is the callback's own function type, and the default adapts into + // it (JavaScript ignores surplus arguments). The checker's merged union + // signature would lose the callback's result shape. + if (present?.kind === "func" && present.rest !== true) { + const raw = lowerer.lowerExpr(expr.right); + if ( + raw.type.kind === "func" && + (typeEquals(raw.type, present) || cleanFuncAdaptable(lowerer, raw.type, present)) + ) { + const right = lowerer.coerceInto(expr.right, raw, present); + lowerer.nullishFuncResults.add(expr); + return { kind: "nullish", left, right, type: present, loc }; + } + } lowerer.unsupported( "SC1090", expr, @@ -12688,6 +12711,19 @@ export function caughtRead( if (narrowed?.kind === "dyn") { return { kind: "caughtToDyn", value: ref, type: DYN, loc }; } + // A binding a user type predicate (or an assertion) narrowed to a + // structural type (`isErrorLike(e)` → `{ message: string; … }`, an + // intersection like `TypeError & { code: unknown }`): the thrown value is + // still whatever was thrown, so it crosses as a checked-dynamic value and + // each member read validates its own result, as JavaScript reads it. + const checked = lowerer.typeOf(node); + if ( + narrowed?.kind === "record" || + narrowed?.kind === "union" || + (narrowed === null && (checked.flags & (ts.TypeFlags.Object | ts.TypeFlags.Intersection)) !== 0) + ) { + return { kind: "caughtToDyn", value: ref, type: DYN, loc }; + } lowerer.unsupported("SC1063", node); } @@ -14000,6 +14036,36 @@ function lowerInExpression(lowerer: Lowerer, expr: ts.BinaryExpression, loc: Src ) { return { kind: "boolLit", value: true, type: BOOL, loc }; } + // Any other key: a member a program class declares. The receiver's + // runtime class is its static class or a descendant; the key is + // present exactly when that class (or an ancestor) declares it. + if (recv.kind === "varRef" || recv.kind === "caughtNarrow") { + const declares = (c: ClassInfo): boolean => + c.fields.has(key) || + lowerer.findMethodOn(c, key) !== null || + lowerer.findMethodOn(c, `get:${key}`) !== null || + lowerer.findMethodOn(c, `set:${key}`) !== null; + const staticName = recv.type.className; + const staticInfo = lowerer.classes.get(staticName); + if (staticInfo && declares(staticInfo)) + return { kind: "boolLit", value: true, type: BOOL, loc }; + const tests: IrExpr[] = []; + for (const c of lowerer.classes.values()) { + const name = c.def.name; + if (name === staticName || !lowerer.isSubclassOf(name, staticName) || !declares(c)) + continue; + // A declaring ancestor below the static class already covers it. + if (c.base && c.base.def.name !== staticName && declares(c.base)) continue; + tests.push({ kind: "instanceOf", value: recv, className: name, type: BOOL, loc }); + } + return tests.reduce( + (acc, test) => + acc.kind === "boolLit" + ? test + : { kind: "logical", op: "||", left: acc, right: test, type: BOOL, loc }, + { kind: "boolLit", value: false, type: BOOL, loc }, + ); + } lowerer.unsupported( "SC1090", expr, diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 01ff5f5c1..3af47f614 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -4887,7 +4887,8 @@ export function lowerVarDecl( if ( !decl.type && init.type.kind === "func" && - lowerer.typedArgumentsLambdas.has(stripTypeWrappers(decl.initializer)) + (lowerer.typedArgumentsLambdas.has(stripTypeWrappers(decl.initializer)) || + lowerer.nullishFuncResults.has(stripTypeWrappers(decl.initializer))) ) type = init.type; // A TypeScript lambda whose closure returns the runtime result (a missing diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 26405865c..8913b9eeb 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1917,6 +1917,9 @@ export class Lowerer { /** Const bindings holding a forwarded fixed tuple (`const args = * arguments as any` in a typed-arguments function) → the tuple type. */ readonly tupleAliasSymbols = new Map(); + /** `??` expressions whose result is the optional callback's own function + * type (an adapted function default); their bindings take that type. */ + readonly nullishFuncResults = new Set(); /** The static names of the current generic instance's name-keyed * function parameters (static-function-names.ts). */ staticFnNames: Map | null = null; diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index e43748b39..c819bf80c 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -2397,6 +2397,27 @@ export const AMBIENT_SURFACE_FNS: readonly AmbientSurfaceRow[] = [ name: "perf_hooks.performance.clearMeasures", fns: ["perf.clearMeasures"], }, + { + id: "node-builtin.perf_hooks.performance.eventLoopUtilization", + kind: "node-builtin", + name: "perf_hooks.performance.eventLoopUtilization", + fns: ["perf.loopStart", "perf.idleTime"], + note: "active time is the main thread's CPU time since the loop started; the one- and two-argument difference forms are supported", + }, + { + id: "node-builtin.perf_hooks.monitorEventLoopDelay", + kind: "node-builtin", + name: "perf_hooks.monitorEventLoopDelay", + fns: [ + "perf.eldNew", + "perf.eldEnable", + "perf.eldDisable", + "perf.eldReset", + "perf.eldPercentile", + "perf.eldStat", + ], + note: "an unref'd sampling interval records the delay histogram; enable, disable, reset, percentile and the min, max, mean, stddev, count and exceeds readings are supported", + }, // ── the process global's ambient reads and authority calls // (lowerProcessProperty/lowerProcessMethodCall — process is a // provenance-checked global here, not an importable module). diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 19e7775cc..1e3954586 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -1556,7 +1556,8 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { // parameter (variadic higher-order wrappers): the checker keeps both // conditionals symbolic inside the body, and their `infer` positions // match a call signature, which matchInferReference cannot decide. - const viaSignature = mapBoundSignatureAlias(type, ctx); + const viaSignature = + mapBoundSignatureAlias(type, ctx) ?? mapBoundKeyofNeverConditional(type, ctx); if (viaSignature !== null) { contextResolutions++; return viaSignature; @@ -3809,6 +3810,27 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { return { kind: "record", shapeId: perfEntryShape(ctx.shapes, ctx.unions) }; } // readline's getCursorPos() record, in Node's key order ({ cols, rows }). + // perf_hooks' EventLoopUtilization (performance.eventLoopUtilization's + // result): a plain data record in Node's key order. + if (isStdlibInterface("EventLoopUtilization")) { + return { + kind: "record", + shapeId: ctx.shapes.intern( + [ + { name: "active", type: F64 }, + { name: "idle", type: F64 }, + { name: "utilization", type: F64 }, + ], + false, + undefined, + ["idle", "active", "utilization"], + ), + }; + } + // monitorEventLoopDelay's IntervalHistogram: a numeric handle into the + // runtime's histogram table, like a timer handle. Its members lower over + // the handle (builtins/performance.ts). + if (isStdlibInterface("IntervalHistogram")) return F64; if (isStdlibInterface("CursorPos")) { return { kind: "record", @@ -4348,6 +4370,22 @@ function mapCallSignature(sig: ts.Signature, ctx: TypeMapperCtx): IrType | null ts.isParameter(decl) && (decl.questionToken !== undefined || decl.initializer !== undefined); let pt = mapType(checker.getTypeOfSymbol(p), ctx); + // A parameter a TypeScript program types `any` takes whatever the + // caller passes: the checked-dynamic slot, as an `any`-typed binding + // already is (dynFallbackType). Declaration files keep their paths. + // Only function declarations and spelled function types: lambdas and + // methods in object literals keep their existing checked-dynamic story. + if ( + !pt && + !rest && + decl !== undefined && + ts.isParameter(decl) && + decl.parent !== undefined && + (ts.isFunctionDeclaration(decl.parent) || ts.isFunctionTypeNode(decl.parent)) && + !decl.getSourceFile().isDeclarationFile && + (checker.getTypeOfSymbol(p).flags & ts.TypeFlags.Any) !== 0 + ) + pt = DYN; if ( decl && ts.isParameter(decl) && @@ -5122,7 +5160,51 @@ function mapGenericIndexedAccess(type: ts.Type, ctx: TypeMapperCtx): IrType | nu } if (!covered || covered.length === 0) return null; const first = covered[0]!; - return covered.every((t) => typeEquals(t, first)) ? first : null; + if (covered.every((t) => typeEquals(t, first))) return first; + // Only the `keyof T` index itself covers every field at once; a key + // parameter bound to string keeps its literal-key resolution below. + if (!(idx.isIndexType() && idx.getTarget() === obj)) return null; + // Fields of different scalar types (`Object.entries` over a bound record + // reads `T[keyof T]`): any one of them, the union of their types. + const arms: IrType[] = []; + for (const t of covered) { + const parts = t.kind === "union" ? (ctx.unions.get(t.unionId)?.arms ?? null) : [t]; + if (!parts) return null; + for (const part of parts) { + if ( + part.kind !== "f64" && + part.kind !== "string" && + part.kind !== "bool" && + part.kind !== "undefinedT" && + part.kind !== "nullT" + ) + return null; + if (!arms.some((a) => typeEquals(a, part))) arms.push(part); + } + } + if (arms.length === 1) return arms[0]!; + arms.sort((a, b) => (typeKey(a) < typeKey(b) ? -1 : 1)); + return { kind: "union", unionId: ctx.unions.intern(arms) }; +} + +/** `keyof T extends never ? A : B` over a bound record T (the lib's + * Object.entries element spelling): decided by whether the binding has any + * key. */ +function mapBoundKeyofNeverConditional(type: ts.Type, ctx: TypeMapperCtx): IrType | null { + const { resolveTypeParam, shapes } = ctx; + if (!resolveTypeParam || !type.isConditionalType()) return null; + const check = type.getCheckType(); + const ext = type.getExtendsType(); + if (!check || !ext || !(ext.flags & ts.TypeFlags.Never) || !check.isIndexType()) return null; + const target = check.getTarget(); + if (!target || !(target.flags & ts.TypeFlags.TypeParameter)) return null; + const bound = resolveTypeParam(target); + if (bound?.kind !== "record") return null; + const shape = shapes.get(bound.shapeId); + if (!shape || shape.tuple) return null; + const hasKeys = shape.fields.length > 0 || shape.indexValue !== undefined; + const branch = hasKeys ? type.getFalseType() : type.getTrueType(); + return branch ? mapType(branch, ctx) : null; } /** A mapped type over a type parameter of the instance being lowered (`{ diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index ca9dc4d18..92643c7b9 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -554,6 +554,7 @@ async function compileExecutableNative( tls: features.tls, tlsCa: features.tlsCa, cipher: features.cipher, + perfLoop: features.perfLoop, ...(onArtifactReady === undefined ? {} : { onArtifactReady }), ...(ffi === null ? {} diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index f3ad4db28..02943ae1b 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -361,6 +361,20 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "perf.entryDetail": { argTypes: [F64], result: DYN }, "perf.entryKeep": { argTypes: [DYN], result: VOID }, "perf.entryRef": { argTypes: [F64], result: DYN }, + /** perf_hooks event-loop metrics (scr_perf_loop.c): loopStart is the + * loop's start in performance.now() ms (0 before it), idleTime the idle + * ms since. eldNew(resolution ms) creates a monitorEventLoopDelay + * histogram handle; enable/disable answer whether the state changed; + * eldPercentile expects Node's validated range; eldStat(which) reads + * 0 min, 1 max, 2 mean, 3 stddev, 4 count, 5 exceeds. */ + "perf.loopStart": { argTypes: [], result: F64 }, + "perf.idleTime": { argTypes: [], result: F64 }, + "perf.eldNew": { argTypes: [F64], result: F64 }, + "perf.eldEnable": { argTypes: [F64], result: BOOL }, + "perf.eldDisable": { argTypes: [F64], result: BOOL }, + "perf.eldReset": { argTypes: [F64], result: VOID }, + "perf.eldPercentile": { argTypes: [F64, F64], result: F64 }, + "perf.eldStat": { argTypes: [F64, F64], result: F64 }, /** process.memoryUsage(): memoryUsageTake samples the resident set and * the runtime heap once (MAY THROW Node's uv_resident_set_memory error) * and memoryUsageField(k) reads that sample (0 rss, 1 heapTotal, 2 diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 6e71fe91c..b2628fa10 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -49,6 +49,9 @@ export interface RuntimeFeatures { tls: boolean; tlsCa: boolean; cipher: boolean; + /** perf_hooks event-loop metrics (eventLoopUtilization, + * monitorEventLoopDelay): scr_perf_loop.c. */ + perfLoop: boolean; } const DYN_ASYNC_LIB_FNS: ReadonlySet = new Set([ @@ -407,6 +410,7 @@ function scanRuntimeFeatures(mod: IrModule, stopAt?: keyof RuntimeFeatures): Run tls: false, tlsCa: false, cipher: false, + perfLoop: false, }; const keepGoing = (): boolean => stopAt === undefined || !features[stopAt]; let tables: TypeTables | undefined; @@ -505,6 +509,8 @@ function scanRuntimeFeatures(mod: IrModule, stopAt?: keyof RuntimeFeatures): Run // scr_cipher.c over the mbedTLS archive; DEP0182 reports through the // process-warning unit, and unknown output encodings render through // the inspect unit. + if (fn.startsWith("perf.loop") || fn === "perf.idleTime" || fn.startsWith("perf.eld")) + features.perfLoop = true; if (fn === "crypto.cipherNew") { features.cipher = true; features.dynAsync = true; diff --git a/packages/compiler/src/native/cli.ts b/packages/compiler/src/native/cli.ts index c0d89bbbf..cf0c32ee3 100644 --- a/packages/compiler/src/native/cli.ts +++ b/packages/compiler/src/native/cli.ts @@ -100,6 +100,7 @@ async function main(): Promise { nodeTest: false, tls: false, cipher: false, + perfLoop: false, tlsCa: false, }, options.optimization ?? "release", diff --git a/packages/compiler/src/native/prepare.ts b/packages/compiler/src/native/prepare.ts index bb901a674..90f4ca562 100644 --- a/packages/compiler/src/native/prepare.ts +++ b/packages/compiler/src/native/prepare.ts @@ -155,6 +155,7 @@ function validFeatures(value: unknown): value is NativeLinkFeatures { "tls", "tlsCa", "cipher", + "perfLoop", ].every((name) => typeof features[name] === "boolean"); } diff --git a/packages/compiler/src/native/sanitizer.test.ts b/packages/compiler/src/native/sanitizer.test.ts index 79984d6c5..3f7d96226 100644 --- a/packages/compiler/src/native/sanitizer.test.ts +++ b/packages/compiler/src/native/sanitizer.test.ts @@ -104,6 +104,7 @@ test.skipIf(process.platform !== "linux" && process.platform !== "darwin")( tls: false, tlsCa: false, cipher: false, + perfLoop: false, nativeFetch: false, netEffective: false, httpEffective: false, diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 5cea78586..dc8ff48f8 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -1847,6 +1847,13 @@ "status": "static", "note": "recognized module (bare and node:-prefixed specifiers)" }, + { + "id": "node-builtin.perf_hooks.monitorEventLoopDelay", + "kind": "node-builtin", + "name": "perf_hooks.monitorEventLoopDelay", + "status": "static", + "note": "an unref'd sampling interval records the delay histogram; enable, disable, reset, percentile and the min, max, mean, stddev, count and exceeds readings are supported" + }, { "id": "node-builtin.perf_hooks.performance.clearMarks", "kind": "node-builtin", @@ -1859,6 +1866,13 @@ "name": "perf_hooks.performance.clearMeasures", "status": "static" }, + { + "id": "node-builtin.perf_hooks.performance.eventLoopUtilization", + "kind": "node-builtin", + "name": "perf_hooks.performance.eventLoopUtilization", + "status": "static", + "note": "active time is the main thread's CPU time since the loop started; the one- and two-argument difference forms are supported" + }, { "id": "node-builtin.perf_hooks.performance.getEntries", "kind": "node-builtin", diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6390-catch-binding-predicate.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6390-catch-binding-predicate.ts.json new file mode 100644 index 000000000..fcfb2852f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6390-catch-binding-predicate.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6390-catch-binding-predicate.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6391-nullish-function-default.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6391-nullish-function-default.ts.json new file mode 100644 index 000000000..8200d301e --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6391-nullish-function-default.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6391-nullish-function-default.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6392-optional-chain-protocol-calls.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6392-optional-chain-protocol-calls.ts.json new file mode 100644 index 000000000..f2343714c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6392-optional-chain-protocol-calls.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6392-optional-chain-protocol-calls.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6393-function-types-any-params.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6393-function-types-any-params.ts.json new file mode 100644 index 000000000..af0a9abe7 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6393-function-types-any-params.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6393-function-types-any-params.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6394-in-key-error-subclasses.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6394-in-key-error-subclasses.ts.json new file mode 100644 index 000000000..9df1e1014 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6394-in-key-error-subclasses.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6394-in-key-error-subclasses.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6395-generic-object-entries.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6395-generic-object-entries.ts.json new file mode 100644 index 000000000..879a09388 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6395-generic-object-entries.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6395-generic-object-entries.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6396-generic-any-instantiation.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6396-generic-any-instantiation.ts.json new file mode 100644 index 000000000..da41452ad --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6396-generic-any-instantiation.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6396-generic-any-instantiation.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6397-event-loop-metrics.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6397-event-loop-metrics.ts.json new file mode 100644 index 000000000..0a74534b0 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6397-event-loop-metrics.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6397-event-loop-metrics.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/event-loop-metrics.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/event-loop-metrics.ts.json new file mode 100644 index 000000000..66246403d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/event-loop-metrics.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/event-loop-metrics.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/timeout-type.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/timeout-type.ts.json new file mode 100644 index 000000000..46f0b6e38 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/timeout-type.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/timeout-type.ts" + ], + "diags": [] +} diff --git a/packages/runtime-pack-common/runtime-pack-matrix.mjs b/packages/runtime-pack-common/runtime-pack-matrix.mjs index eab680a55..b603f37ee 100644 --- a/packages/runtime-pack-common/runtime-pack-matrix.mjs +++ b/packages/runtime-pack-common/runtime-pack-matrix.mjs @@ -62,6 +62,8 @@ const OPTIONAL = [ ["scr_async_dyn.c", any("dynAsync", "dynInvoke", "dc", "fileHandle", "nativeFetch")], // The performance timeline emits its buffer warning through scr_async_dyn.c. ["scr_perf.c", "dynAsync"], + // perf_hooks event-loop metrics, only for programs that read them. + ["scr_perf_loop.c", "perfLoop"], // Blob and File box their reads as dyn promises through scr_async_dyn.c. ["scr_blob.c", "dynAsync"], ["scr_zlib.c", "zlib"], diff --git a/packages/runtime/src/scr_lib.h b/packages/runtime/src/scr_lib.h index 4c973e3e5..4b1094d54 100644 --- a/packages/runtime/src/scr_lib.h +++ b/packages/runtime/src/scr_lib.h @@ -169,6 +169,21 @@ double scr_process_uptime(void); /* perf_hooks performance.now(): fractional ms since process start (the * uptime anchor — Node's timeOrigin for a compiled program). */ double scr_perf_now(void); +/* perf_hooks event-loop metrics (scr_perf_loop.c). loop_mark records the + * loop's start (the emitted main calls it before the loop runs, only in + * programs that read the metric); loop_start answers it (0 before) and + * idle_time the idle ms since. The eld_* family is monitorEventLoopDelay's + * IntervalHistogram over a handle; eld_percentile expects 0 < p <= 100; eld_stat which: 0 min, 1 max, 2 mean, 3 stddev, + * 4 count, 5 exceeds. */ +void scr_perf_loop_mark(void); +double scr_perf_loop_start(void); +double scr_perf_idle_time(void); +double scr_eld_new(double resolution); +bool scr_eld_enable(double handle); +bool scr_eld_disable(double handle); +void scr_eld_reset(double handle); +double scr_eld_percentile(double handle, double percentile); +double scr_eld_stat(double handle, double which); /* perf_hooks user timing (scr_perf.c): mark, measure, the getEntries * family and the clears take the call's dyn argument vector (borrowed) * and apply Node's validation and errors. mark and measure answer 1 and diff --git a/packages/runtime/src/scr_perf_loop.c b/packages/runtime/src/scr_perf_loop.c new file mode 100644 index 000000000..29d98ea29 --- /dev/null +++ b/packages/runtime/src/scr_perf_loop.c @@ -0,0 +1,305 @@ +/* node:perf_hooks event-loop metrics: performance.eventLoopUtilization() + * and monitorEventLoopDelay()'s IntervalHistogram. + * + * Event-loop utilization. Node measures idle time as the time its loop + * spends blocked in the poll phase. A compiled program's main thread is + * busy exactly while it runs on the CPU (or blocks in a synchronous call), + * so the thread's CPU time stands in for Node's active time: idle is the + * wall time since the loop started minus that CPU time. The loop start is + * marked by the emitted main just before the loop runs, and only in + * programs that ask for the metric; before it, utilization is all zeros, + * like Node during the main module's synchronous evaluation. + * + * Event-loop delay. Each histogram samples on an unref'd interval at its + * resolution and records the time between samples in nanoseconds, like + * Node's ELDHistogram (Histogram::RecordDelta). Values land in an + * HdrHistogram-shaped counts array (lowest 1, three significant figures: + * 2048 sub-buckets per power of two), so min, max, mean, stddev and + * percentiles answer the bucket values Node's hdr_histogram answers. */ + +#include "scr_runtime.h" + +#include +#include +#include +#include +#ifdef _WIN32 +#include +#endif + +/* ── event-loop utilization ─────────────────────────────────────────── */ + +static SCR_TL double scr_perf_loop_start_ms = 0; /* performance.now() at loop start */ +static SCR_TL double scr_perf_loop_cpu0_ms = 0; /* thread CPU time at loop start */ + +/* The calling thread's CPU time in milliseconds; 0 where unavailable. */ +static double scr_perf_thread_cpu_ms(void) { +#if defined(_WIN32) + FILETIME created, exited, kernel, user; + if (!GetThreadTimes(GetCurrentThread(), &created, &exited, &kernel, &user)) return 0; + ULARGE_INTEGER k, u; + k.LowPart = kernel.dwLowDateTime; + k.HighPart = kernel.dwHighDateTime; + u.LowPart = user.dwLowDateTime; + u.HighPart = user.dwHighDateTime; + return (double)(k.QuadPart + u.QuadPart) / 1e4; /* 100ns units */ +#elif defined(CLOCK_THREAD_CPUTIME_ID) && !defined(__wasi__) + struct timespec ts; + if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != 0) return 0; + return (double)ts.tv_sec * 1000.0 + (double)ts.tv_nsec / 1e6; +#else + return 0; +#endif +} + +void scr_perf_loop_mark(void) { + if (scr_perf_loop_start_ms > 0) return; + scr_perf_loop_cpu0_ms = scr_perf_thread_cpu_ms(); + double now = scr_perf_now(); + /* Node's loopStart is positive once set; a mark at the very first + * microsecond still counts as started. */ + scr_perf_loop_start_ms = now > 0 ? now : 1e-6; +} + +double scr_perf_loop_start(void) { return scr_perf_loop_start_ms; } + +double scr_perf_idle_time(void) { + if (scr_perf_loop_start_ms <= 0) return 0; + double wall = scr_perf_now() - scr_perf_loop_start_ms; + double busy = scr_perf_thread_cpu_ms() - scr_perf_loop_cpu0_ms; + double idle = wall - busy; + if (idle < 0) idle = 0; + if (idle > wall) idle = wall; + return idle; +} + +/* ── HdrHistogram-shaped counts (lowest 1, 3 significant figures) ───── */ + +#define SCR_HDR_SUB_BUCKET_HALF_MAG 10 +#define SCR_HDR_SUB_BUCKET_HALF (1 << SCR_HDR_SUB_BUCKET_HALF_MAG) /* 1024 */ +#define SCR_HDR_SUB_BUCKET_COUNT (SCR_HDR_SUB_BUCKET_HALF * 2) /* 2048 */ +#define SCR_HDR_SUB_BUCKET_MASK ((int64_t)SCR_HDR_SUB_BUCKET_COUNT - 1) + +typedef struct { + int64_t *counts; /* owned, grown on demand */ + size_t counts_len; + int64_t total; + int64_t min_value; /* INT64_MAX while empty */ + int64_t max_value; /* 0 while empty */ + double count; /* Node's count_ (successful records) */ + uint64_t prev_ns; /* RecordDelta's previous sample; 0 = none */ + double resolution; /* ms */ + double timer; /* the sampling interval's handle while enabled, else 0 */ + ScrClosure *tick; /* owned: the sampling callback, identifies this histogram */ + bool enabled; +} ScrEld; + +static int scr_hdr_bucket_index(int64_t value) { + int pow2ceiling = 64 - __builtin_clzll((uint64_t)(value | SCR_HDR_SUB_BUCKET_MASK)); + return pow2ceiling - (SCR_HDR_SUB_BUCKET_HALF_MAG + 1); +} + +static size_t scr_hdr_counts_index(int64_t value) { + int bucket = scr_hdr_bucket_index(value); + int64_t sub = value >> bucket; + return (size_t)(((int64_t)(bucket + 1) << SCR_HDR_SUB_BUCKET_HALF_MAG) + (sub - SCR_HDR_SUB_BUCKET_HALF)); +} + +static int64_t scr_hdr_value_at_index(size_t index) { + int bucket = (int)(index >> SCR_HDR_SUB_BUCKET_HALF_MAG) - 1; + int64_t sub = (int64_t)(index & (SCR_HDR_SUB_BUCKET_HALF - 1)) + SCR_HDR_SUB_BUCKET_HALF; + if (bucket < 0) { + sub -= SCR_HDR_SUB_BUCKET_HALF; + bucket = 0; + } + return sub << bucket; +} + +static int64_t scr_hdr_range_size(int64_t value) { + int bucket = scr_hdr_bucket_index(value); + int64_t sub = value >> bucket; + int adjusted = sub >= SCR_HDR_SUB_BUCKET_COUNT ? bucket + 1 : bucket; + return (int64_t)1 << adjusted; +} + +static int64_t scr_hdr_lowest_equivalent(int64_t value) { + int bucket = scr_hdr_bucket_index(value); + int64_t sub = value >> bucket; + return sub << bucket; +} + +static int64_t scr_hdr_highest_equivalent(int64_t value) { + return scr_hdr_lowest_equivalent(value) + scr_hdr_range_size(value) - 1; +} + +static int64_t scr_hdr_median_equivalent(int64_t value) { + return scr_hdr_lowest_equivalent(value) + (scr_hdr_range_size(value) >> 1); +} + +/* Newton's square root: keeps this unit free of a libm reference. */ +static double scr_eld_sqrt(double x) { + if (!(x > 0)) return x == 0 ? 0 : NAN; + double r = x >= 1 ? x : 1; + for (int i = 0; i < 64; i++) { + double next = 0.5 * (r + x / r); + if (next == r) break; + r = next; + } + return r; +} + +static void scr_eld_record(ScrEld *h, int64_t value) { + if (value < 0) return; + size_t index = scr_hdr_counts_index(value); + if (index >= h->counts_len) { + size_t len = h->counts_len ? h->counts_len : SCR_HDR_SUB_BUCKET_COUNT; + while (len <= index) len *= 2; + int64_t *grown = realloc(h->counts, len * sizeof(int64_t)); + if (grown == NULL) return; + for (size_t i = h->counts_len; i < len; i++) grown[i] = 0; + h->counts = grown; + h->counts_len = len; + } + h->counts[index]++; + h->total++; + if (value != 0 && value < h->min_value) h->min_value = value; + if (value > h->max_value) h->max_value = value; + h->count += 1; +} + +static void scr_eld_clear(ScrEld *h) { + for (size_t i = 0; i < h->counts_len; i++) h->counts[i] = 0; + h->total = 0; + h->min_value = INT64_MAX; + h->max_value = 0; + h->count = 0; + h->prev_ns = 0; +} + +/* ── monitorEventLoopDelay ──────────────────────────────────────────── */ + +static SCR_TL ScrEld **scr_elds; +static SCR_TL size_t scr_elds_len; + +static ScrEld *scr_eld_of(double handle) { + if (!(handle >= 1) || handle > (double)scr_elds_len) return NULL; + return scr_elds[(size_t)handle - 1]; +} + +static void scr_eld_tick(ScrClosure *self) { + for (size_t i = 0; i < scr_elds_len; i++) { + ScrEld *h = scr_elds[i]; + if (h->tick != self) continue; + uint64_t now = scr_hrtime_ns(); + if (h->prev_ns > 0 && now > h->prev_ns) scr_eld_record(h, (int64_t)(now - h->prev_ns)); + h->prev_ns = now; + return; + } +} + +/* Histograms live for the thread's lifetime (Node frees them with their + * JS object); release them when the script ends so their callbacks and + * counts do not outlive it. */ +static void scr_eld_cleanup(void) { + for (size_t i = 0; i < scr_elds_len; i++) { + ScrEld *h = scr_elds[i]; + scr_closure_release(h->tick); + free(h->counts); + free(h); + } + free(scr_elds); + scr_elds = NULL; + scr_elds_len = 0; +} + +double scr_eld_new(double resolution) { + if (scr_elds_len == 0 && scr_elds == NULL) scr_atexit(scr_eld_cleanup); + ScrEld *h = calloc(1, sizeof(ScrEld)); + ScrEld **grown = realloc(scr_elds, (scr_elds_len + 1) * sizeof(ScrEld *)); + if (h == NULL || grown == NULL) { + free(h); + if (grown != NULL) scr_elds = grown; + return 0; + } + scr_elds = grown; + h->min_value = INT64_MAX; + h->resolution = resolution >= 1 ? resolution : 10; + h->tick = scr_closure_new((void *)scr_eld_tick, 0); + scr_elds[scr_elds_len++] = h; + return (double)scr_elds_len; +} + +bool scr_eld_enable(double handle) { + ScrEld *h = scr_eld_of(handle); + if (h == NULL || h->enabled) return false; + h->enabled = true; + h->timer = scr_set_interval(scr_closure_retain(h->tick), h->resolution); + scr_timer_unref(h->timer); + return true; +} + +bool scr_eld_disable(double handle) { + ScrEld *h = scr_eld_of(handle); + if (h == NULL || !h->enabled) return false; + h->enabled = false; + scr_clear_interval(h->timer); + h->timer = 0; + return true; +} + +void scr_eld_reset(double handle) { + ScrEld *h = scr_eld_of(handle); + if (h != NULL) scr_eld_clear(h); +} + +/* hdr_value_at_percentile; the compiler checked Node's 0 < p <= 100 range. */ +double scr_eld_percentile(double handle, double percentile) { + ScrEld *h = scr_eld_of(handle); + if (h == NULL || h->total == 0) return 0; + double requested = percentile < 100.0 ? percentile : 100.0; + int64_t wanted = (int64_t)((requested / 100.0) * (double)h->total + 0.5); + if (wanted < 1) wanted = 1; + int64_t seen = 0; + for (size_t i = 0; i < h->counts_len; i++) { + seen += h->counts[i]; + if (seen >= wanted) return (double)scr_hdr_highest_equivalent(scr_hdr_value_at_index(i)); + } + return 0; +} + +/* which: 0 min, 1 max, 2 mean, 3 stddev, 4 count, 5 exceeds. */ +double scr_eld_stat(double handle, double which) { + ScrEld *h = scr_eld_of(handle); + int w = (int)which; + if (h == NULL) return w == 0 ? (double)INT64_MAX : w >= 2 && w <= 3 ? NAN : 0; + switch (w) { + case 0: + if (h->counts_len > 0 && h->counts[0] > 0) return 0; + return h->min_value == INT64_MAX ? (double)INT64_MAX + : (double)scr_hdr_lowest_equivalent(h->min_value); + case 1: + return h->max_value == 0 ? 0 : (double)scr_hdr_highest_equivalent(h->max_value); + case 2: + case 3: { + if (h->total == 0) return NAN; + double sum = 0; + for (size_t i = 0; i < h->counts_len; i++) { + if (h->counts[i] == 0) continue; + sum += (double)h->counts[i] * (double)scr_hdr_median_equivalent(scr_hdr_value_at_index(i)); + } + double mean = sum / (double)h->total; + if (w == 2) return mean; + double geo = 0; + for (size_t i = 0; i < h->counts_len; i++) { + if (h->counts[i] == 0) continue; + double dev = (double)scr_hdr_median_equivalent(scr_hdr_value_at_index(i)) - mean; + geo += dev * dev * (double)h->counts[i]; + } + return scr_eld_sqrt(geo / (double)h->total); + } + case 4: + return h->count; + default: + return 0; + } +} diff --git a/tests/corpus/6390-catch-binding-predicate.ts b/tests/corpus/6390-catch-binding-predicate.ts new file mode 100644 index 000000000..82c8797b5 --- /dev/null +++ b/tests/corpus/6390-catch-binding-predicate.ts @@ -0,0 +1,42 @@ +// A catch binding narrowed by a user type predicate reads its fields. +interface ErrorLike { + message: string; + name: string; + code?: string; +} +function isErrorLike(value: unknown): value is ErrorLike { + return typeof value === "object" && value !== null && "message" in value && "name" in value; +} +interface Coded { + code: string; +} +function isCoded(value: unknown): value is Coded { + return typeof value === "object" && value !== null && typeof (value as Coded).code === "string"; +} +function report(fn: () => void): void { + try { + fn(); + } catch (err) { + if (isErrorLike(err)) { + console.log("error", { message: err ? err.message : "none", name: err.name, code: err.code ?? "-" }); + if (err.message.includes("disk")) console.log("disk problem"); + } else { + console.log("not error-like", String(err)); + } + if (isCoded(err) && err.code === "ENOSPC") console.log("coded", err.code); + } +} +report(() => { + throw new Error("disk full"); +}); +report(() => { + const e = new Error("no space") as Error & { code?: string }; + e.code = "ENOSPC"; + throw e; +}); +report(() => { + throw "plain"; +}); +report(() => { + throw { message: "obj", name: "Custom", code: "ENOSPC" }; +}); diff --git a/tests/corpus/6391-nullish-function-default.ts b/tests/corpus/6391-nullish-function-default.ts new file mode 100644 index 000000000..6721d97bf --- /dev/null +++ b/tests/corpus/6391-nullish-function-default.ts @@ -0,0 +1,13 @@ +// `??` with a function fallback whose signature differs from the optional +// callback's (fewer parameters, narrower result). +interface Opts { + tags?: (a: number, b: number) => Record; + label?: (n: number) => string; +} +function run(o: Opts, x: number, y: number): string { + const tags = o.tags ?? (() => ({})); + const label = o.label ?? ((n: number) => `#${n}`); + return `${label(x)} ${JSON.stringify(tags(x, y))}`; +} +console.log(run({}, 1, 2)); +console.log(run({ tags: (a, b) => ({ a, b }), label: (n) => `n${n}` }, 3, 4)); diff --git a/tests/corpus/6392-optional-chain-protocol-calls.ts b/tests/corpus/6392-optional-chain-protocol-calls.ts new file mode 100644 index 000000000..a08a4ee85 --- /dev/null +++ b/tests/corpus/6392-optional-chain-protocol-calls.ts @@ -0,0 +1,47 @@ +// Optional calls on an interface-typed method chain (a do-nothing tracer). +interface Span { + addTags(tags: Record): Span; +} +interface Scope { + active(): Span | null; +} +interface Tracer { + scope(): Scope; +} +class NoopSpan implements Span { + addTags(tags: Record): Span { + console.log("tags", JSON.stringify(tags)); + return this; + } +} +class NoopScope implements Scope { + span: Span | null; + constructor(span: Span | null) { + this.span = span; + } + active(): Span | null { + return this.span; + } +} +class NoopTracer implements Tracer { + s: Scope; + constructor(s: Scope) { + this.s = s; + } + scope(): Scope { + return this.s; + } +} +const quiet: Tracer = new NoopTracer(new NoopScope(null)); +const loud: Tracer = new NoopTracer(new NoopScope(new NoopSpan())); +function tagActiveSpan(tracer: Tracer, tags: Record): void { + tracer.scope().active()?.addTags(tags); +} +tagActiveSpan(quiet, { a: 1 }); +tagActiveSpan(loud, { b: 2 }); + +// Narrowed locals and non-null assertions reach the same protocol calls. +const scope2: Scope = new NoopScope(new NoopSpan()); +const current = scope2.active(); +current?.addTags({ c: 3 }); +scope2.active()!.addTags({ d: 4 }); diff --git a/tests/corpus/6393-function-types-any-params.ts b/tests/corpus/6393-function-types-any-params.ts new file mode 100644 index 000000000..ec7799c9d --- /dev/null +++ b/tests/corpus/6393-function-types-any-params.ts @@ -0,0 +1,8 @@ +// Function values whose parameters are typed any (optional or not). +function build(limit?: any): string { + return `limit=${limit ?? "none"}`; +} +const fns: Array<(limit?: any) => string> = [build]; +console.log(fns[0]!(), fns[0]!(5)); +const take: (v: any) => number = (v) => (typeof v === "number" ? v : -1); +console.log(take(3), take("x")); diff --git a/tests/corpus/6394-in-key-error-subclasses.ts b/tests/corpus/6394-in-key-error-subclasses.ts new file mode 100644 index 000000000..cdb28a5a3 --- /dev/null +++ b/tests/corpus/6394-in-key-error-subclasses.ts @@ -0,0 +1,25 @@ +// `'key' in err` on Error receivers, including subclasses that declare it. +class HttpError extends Error { + status: number; + constructor(message: string, status: number) { + super(message); + this.status = status; + } +} +function describe(err: Error): string { + if ("status" in err) return `status ${(err as HttpError).status}`; + if ("code" in err) return "has code"; + return `plain ${err.message}`; +} +console.log(describe(new Error("x"))); +console.log(describe(new HttpError("nf", 404))); +class Timeout extends HttpError { + get retryable(): boolean { + return true; + } +} +function retryable(err: Error): boolean { + return "retryable" in err; +} +console.log(retryable(new Error("x")), retryable(new HttpError("a", 500)), retryable(new Timeout("t", 504))); +console.log(describe(new Timeout("t", 504))); diff --git a/tests/corpus/6395-generic-object-entries.ts b/tests/corpus/6395-generic-object-entries.ts new file mode 100644 index 000000000..772367a3a --- /dev/null +++ b/tests/corpus/6395-generic-object-entries.ts @@ -0,0 +1,7 @@ +// Object.entries over a generic record parameter. +function maskSecrets>(tags: T): Record { + return Object.fromEntries( + Object.entries(tags).map(([k, v]) => [k, k.includes("secret") ? "[redacted]" : v]), + ); +} +console.log(JSON.stringify(maskSecrets({ user: "ada", secretToken: "x", n: 1 }))); diff --git a/tests/corpus/6396-generic-any-instantiation.ts b/tests/corpus/6396-generic-any-instantiation.ts new file mode 100644 index 000000000..c3c9da060 --- /dev/null +++ b/tests/corpus/6396-generic-any-instantiation.ts @@ -0,0 +1,18 @@ +// A generic method instantiated at `any` from an untyped forwarding call. +type AnyFn = (...args: any) => any; +class Tracer { + trace(name: string, fn: () => T): T { + console.log("span", name); + return fn(); + } +} +const tracer = new Tracer(); +function traced(name: string, fn: F): F { + return function (this: unknown) { + const args = arguments; + const result = tracer.trace(name, () => fn.apply(this, args as any)); + return result; + } as F; +} +const add = traced("add", (a: number, b: number) => a + b); +console.log(add(1, 2)); diff --git a/tests/corpus/6397-event-loop-metrics.ts b/tests/corpus/6397-event-loop-metrics.ts new file mode 100644 index 000000000..e1c3829ac --- /dev/null +++ b/tests/corpus/6397-event-loop-metrics.ts @@ -0,0 +1,49 @@ +// Event-loop monitoring under @types/node: monitorEventLoopDelay's histogram, +// eventLoopUtilization deltas, and an unref'd interval typed NodeJS.Timeout. +import { monitorEventLoopDelay, performance } from "node:perf_hooks"; + +const histogram = monitorEventLoopDelay({ resolution: 10 }); +console.log("enable", histogram.enable(), histogram.enable()); +const first = performance.eventLoopUtilization(); +console.log("before loop", first.idle, first.active, first.utilization); + +let last = performance.eventLoopUtilization(); +let ticks = 0; +// The unref'd interval keeps nothing alive; this timer holds the loop open +// until the third sample. +const keepAlive = setTimeout(() => console.log("never"), 10_000); +const interval = setInterval(() => { + const now = performance.eventLoopUtilization(); + const delta = performance.eventLoopUtilization(now, last); + last = now; + ticks++; + const p50 = histogram.percentile(50); + const p99 = histogram.percentile(99); + console.log( + "tick", + ticks, + delta.utilization >= 0 && delta.utilization <= 1, + delta.idle >= 0, + p50 > 0, + p99 >= p50, + histogram.max >= p99, + histogram.min <= p50, + histogram.count > 0, + ); + histogram.reset(); + console.log("after reset", histogram.count, histogram.max, histogram.min, Number.isNaN(histogram.mean)); + if (ticks === 3) { + clearInterval(interval); + clearTimeout(keepAlive); + console.log("disable", histogram.disable(), histogram.disable()); + const since = performance.eventLoopUtilization(first); + console.log("since", since.utilization > 0 && since.utilization <= 1, since.idle > 0); + try { + histogram.percentile(0); + } catch (e) { + console.log((e as Error).message, (e as { code?: string }).code); + } + } +}, 50); +interval.unref(); +console.log("hasRef", interval.hasRef()); diff --git a/tests/fixtures/node-types/README.md b/tests/fixtures/node-types/README.md index 0784c57fe..243ce0b81 100644 --- a/tests/fixtures/node-types/README.md +++ b/tests/fixtures/node-types/README.md @@ -21,6 +21,7 @@ What the fixture pins (see tests/harness/project-config.test.ts): (process.uptime, Buffer.from, setInterval) reports the SC2020-family fence naming @types/node, instead of typechecking its way into a broken binary — and never a raw "Cannot find name" error. +- `event-loop-metrics.ts` and `timeout-type.ts` — performance.eventLoopUtilization, monitorEventLoopDelay's IntervalHistogram and NodeJS.Timeout as declared types lower under @types/node exactly as under the fallback declarations. - `source-import/` — an imported TypeScript source may use the `RequestInfo` global supplied by TypeScript's default DOM lib while scriptc adopts the project's @types/node declarations. Projects WITHOUT @types/node (every other fixture and the whole corpus) keep diff --git a/tests/fixtures/node-types/event-loop-metrics.ts b/tests/fixtures/node-types/event-loop-metrics.ts new file mode 100644 index 000000000..f5c97c41b --- /dev/null +++ b/tests/fixtures/node-types/event-loop-metrics.ts @@ -0,0 +1,49 @@ +// Event-loop monitoring under @types/node: monitorEventLoopDelay's histogram, +// eventLoopUtilization deltas, and an unref'd interval typed NodeJS.Timeout. +import { monitorEventLoopDelay, performance } from "node:perf_hooks"; + +const histogram = monitorEventLoopDelay({ resolution: 10 }); +console.log("enable", histogram.enable(), histogram.enable()); +const first = performance.eventLoopUtilization(); +console.log("before loop", first.idle, first.active, first.utilization); + +let last = performance.eventLoopUtilization(); +let ticks = 0; +// The unref'd interval keeps nothing alive; this timer holds the loop open +// until the third sample. +const keepAlive = setTimeout(() => console.log("never"), 10_000); +const interval: NodeJS.Timeout = setInterval(() => { + const now = performance.eventLoopUtilization(); + const delta = performance.eventLoopUtilization(now, last); + last = now; + ticks++; + const p50 = histogram.percentile(50); + const p99 = histogram.percentile(99); + console.log( + "tick", + ticks, + delta.utilization >= 0 && delta.utilization <= 1, + delta.idle >= 0, + p50 > 0, + p99 >= p50, + histogram.max >= p99, + histogram.min <= p50, + histogram.count > 0, + ); + histogram.reset(); + console.log("after reset", histogram.count, histogram.max, histogram.min, Number.isNaN(histogram.mean)); + if (ticks === 3) { + clearInterval(interval); + clearTimeout(keepAlive); + console.log("disable", histogram.disable(), histogram.disable()); + const since = performance.eventLoopUtilization(first); + console.log("since", since.utilization > 0 && since.utilization <= 1, since.idle > 0); + try { + histogram.percentile(0); + } catch (e) { + console.log((e as Error).message, (e as { code?: string }).code); + } + } +}, 50); +interval.unref(); +console.log("hasRef", interval.hasRef()); diff --git a/tests/fixtures/node-types/timeout-type.ts b/tests/fixtures/node-types/timeout-type.ts new file mode 100644 index 000000000..42daee86d --- /dev/null +++ b/tests/fixtures/node-types/timeout-type.ts @@ -0,0 +1,30 @@ +// NodeJS.Timeout as a declared type under @types/node: fields, clearTimeout, +// ref/unref/hasRef, refresh. +class Poller { + private timer: NodeJS.Timeout | undefined; + private count = 0; + start(): void { + this.timer = setInterval(() => { + this.count++; + console.log("poll", this.count); + if (this.count === 3) this.stop(); + }, 5); + } + stop(): void { + if (this.timer) { + clearInterval(this.timer); + this.timer = undefined; + console.log("stopped"); + } + } +} +new Poller().start(); +const t: NodeJS.Timeout = setTimeout(() => console.log("never"), 1000); +console.log(t.hasRef()); +t.unref(); +console.log(t.hasRef()); +t.ref(); +console.log(t.hasRef()); +clearTimeout(t); +const timers: NodeJS.Timeout[] = [setTimeout(() => console.log("a"), 30), setTimeout(() => console.log("b"), 31)]; +console.log(timers.length); diff --git a/tests/harness/project-config.test.ts b/tests/harness/project-config.test.ts index bf57a830a..4b307b1d9 100644 --- a/tests/harness/project-config.test.ts +++ b/tests/harness/project-config.test.ts @@ -52,6 +52,32 @@ test("node-types: filesystem capacity supports typed number and BigInt results u expect(comparableStderr(native.stderr)).toBe(node.stderr); }); +for (const [name, title] of [ + [ + "event-loop-metrics", + "eventLoopUtilization and monitorEventLoopDelay follow @types/node's types", + ], + ["timeout-type", "NodeJS.Timeout fields, ref/unref/hasRef and clearInterval under @types/node"], +] as const) { + test(`node-types: ${title}`, async () => { + const outDir = outDirFor(name); + const entry = join(nodeTypesDir, `${name}.ts`); + const result = await compile(entry, { + outPath: join(outDir, process.platform === "win32" ? `${name}.exe` : name), + outDir, + sanitize, + }); + expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true); + if (!result.ok) return; + const [native, node] = await Promise.all([ + execFileAsync(result.binaryPath), + execFileAsync(process.execPath, ["--disable-warning=MODULE_TYPELESS_PACKAGE_JSON", entry]), + ]); + expect(native.stdout).toBe(node.stdout); + expect(comparableStderr(native.stderr)).toBe(node.stderr); + }); +} + test("node-types: http header arrays and server.address() follow @types/node's types", async () => { const outDir = outDirFor("http-headers-address"); const entry = join(nodeTypesDir, "http-headers-address.ts"); diff --git a/tests/harness/self-hosting-native-toolchain.test.ts b/tests/harness/self-hosting-native-toolchain.test.ts index c22e8a839..39edd5567 100644 --- a/tests/harness/self-hosting-native-toolchain.test.ts +++ b/tests/harness/self-hosting-native-toolchain.test.ts @@ -42,6 +42,7 @@ const features: NativeLinkFeatures = { tls: false, tlsCa: false, cipher: false, + perfLoop: false, }; test("native toolchain configuration, staging and helper validation are static", async () => { diff --git a/tests/harness/self-hosting-runtime-pack.test.ts b/tests/harness/self-hosting-runtime-pack.test.ts index 08eb45754..7aee06559 100644 --- a/tests/harness/self-hosting-runtime-pack.test.ts +++ b/tests/harness/self-hosting-runtime-pack.test.ts @@ -43,6 +43,7 @@ const base: NativeLinkFeatures = { tls: false, tlsCa: false, cipher: false, + perfLoop: false, }; test("runtime manifest validation and selection are entirely static", async () => { From 33588981ae38c6a7d6380024e014dad5cc07abd0 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 19:59:40 -0700 Subject: [PATCH 08/39] Bake mixed JSON tables and destructure unions of arrays and tuples JSON documents whose rows mix strings and numbers (`(string | number)[][]`, `(string | number[])[][]`, the character-set and code-point tables of iconv-lite and tr46) now bake: comptime literals take union-typed elements and pick each value's arm from its JSON kind and contents. Array destructuring of a union of array and tuple types (`const [m, a, b] = re.exec(s) || ["", "", ""]`) reads each position from the arm the value holds: a tuple arm answers its field or undefined past its end, an array arm its element or undefined past its end. Unions of tuple types no longer pick the checker's `length` literal as a discriminant: tuple shapes have no such slot. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/array-values.ts | 60 ++++++++++++--- .../src/frontend/lowering/lower-comptime.ts | 73 ++++++++++++++++++- .../src/frontend/lowering/lower-stmts.ts | 12 ++- packages/compiler/src/frontend/type-mapper.ts | 3 + .../main.ts.json | 6 ++ ...11-union-array-tuple-destructuring.ts.json | 6 ++ .../6410-json-mixed-scalar-tables/extra.json | 1 + .../6410-json-mixed-scalar-tables/main.ts | 21 ++++++ .../node_modules/code-table/index.d.ts | 2 + .../node_modules/code-table/index.js | 10 +++ .../node_modules/code-table/package.json | 1 + .../node_modules/code-table/table.json | 1 + .../node_modules/range-map/index.d.ts | 2 + .../node_modules/range-map/index.js | 37 ++++++++++ .../node_modules/range-map/package.json | 1 + .../node_modules/range-map/table.json | 1 + .../6411-union-array-tuple-destructuring.ts | 34 +++++++++ 17 files changed, 255 insertions(+), 16 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6410-json-mixed-scalar-tables/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6411-union-array-tuple-destructuring.ts.json create mode 100644 tests/corpus/6410-json-mixed-scalar-tables/extra.json create mode 100644 tests/corpus/6410-json-mixed-scalar-tables/main.ts create mode 100644 tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/index.d.ts create mode 100644 tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/index.js create mode 100644 tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/package.json create mode 100644 tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/table.json create mode 100644 tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/index.d.ts create mode 100644 tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/index.js create mode 100644 tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/package.json create mode 100644 tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/table.json create mode 100644 tests/corpus/6411-union-array-tuple-destructuring.ts diff --git a/packages/compiler/src/frontend/lowering/array-values.ts b/packages/compiler/src/frontend/lowering/array-values.ts index 8f2b28a3f..e9148b244 100644 --- a/packages/compiler/src/frontend/lowering/array-values.ts +++ b/packages/compiler/src/frontend/lowering/array-values.ts @@ -84,8 +84,11 @@ export function arrayValueRead( }; } -/** Read a stabilized union of native arrays without copying either the - * receiver or its elements. Every arm contributes its missing-value case. */ +/** Read one position of a stabilized union of native arrays and tuples + * (`const [a, b] = re.exec(s) || ["", ""]`) without copying the receiver + * or its elements. Every array arm contributes its missing-value case; a + * tuple arm answers its field, or undefined past its end. Tuple arms need + * a constant position. */ export function unionArrayValueRead( lowerer: Lowerer, value: IrExpr, @@ -96,17 +99,32 @@ export function unionArrayValueRead( const unionId = value.type.unionId; const arms = lowerer.unions.get(unionId)?.arms; if (!arms?.length) return null; + const position = index.kind === "numLit" ? String(index.value) : null; + // A tuple arm's answer at the position: its field, or undefined past + // its end. Null when the arm is neither an array nor a tuple. + const tupleField = (arm: IrType): { name: string; type: IrType } | "past" | null => { + if (arm.kind !== "record" || position === null) return null; + const shape = lowerer.shapes.get(arm.shapeId); + if (!shape?.tuple) return null; + return shape.fields.find((f) => f.name === position) ?? "past"; + }; // Keep the collection's IrType union layout and narrow each element at // its use; an inferred array predicate changes the collection's ABI. - for (const arm of arms) if (arm.kind !== "array") return null; + for (const arm of arms) if (arm.kind !== "array" && tupleField(arm) === null) return null; const answers = new Map(); for (const arm of arms) { - if (arm.kind !== "array") return null; - const answer = arrayValueType(lowerer, arm.elem); + const field = arm.kind === "array" ? null : tupleField(arm); + const answer = + arm.kind === "array" + ? arrayValueType(lowerer, arm.elem) + : field === "past" + ? UNDEFINED_T + : field!.type; const parts = answer.kind === "union" ? lowerer.unions.get(answer.unionId)!.arms : [answer]; for (const part of parts) answers.set(typeKey(part), part); } const joined = [...answers.values()].sort((a, b) => (typeKey(a) < typeKey(b) ? -1 : 1)); + if (joined.length === 1 && joined[0]!.kind === "undefinedT") return null; if ( joined.length > 1 && (!unionContainerArmsOk(joined) || @@ -118,12 +136,34 @@ export function unionArrayValueRead( let result: IrExpr | null = null; for (let tag = arms.length - 1; tag >= 0; tag--) { const arm = arms[tag]!; - if (arm.kind !== "array") return null; const receiver: IrExpr = { kind: "unionNarrow", unionId, tag, value, type: arm, loc }; - const read = lowerer.coerceToExpected( - arrayValueRead(lowerer, receiver, index, arm.elem, loc), - type, - ); + let read: IrExpr; + if (arm.kind === "array") { + read = lowerer.coerceToExpected( + arrayValueRead(lowerer, receiver, index, arm.elem, loc), + type, + ); + } else { + const field = tupleField(arm); + if (field === null) return null; + if (field === "past") { + const missing = lowerer.wrappedUndefined(type, loc); + if (!missing) return null; + read = missing; + } else { + read = lowerer.coerceToExpected( + { + kind: "recordGet", + obj: receiver, + shapeId: (arm as IrType & { kind: "record" }).shapeId, + field: field.name, + type: field.type, + loc, + }, + type, + ); + } + } result = result === null ? read diff --git a/packages/compiler/src/frontend/lowering/lower-comptime.ts b/packages/compiler/src/frontend/lowering/lower-comptime.ts index 41c6704c5..31fa5afe0 100644 --- a/packages/compiler/src/frontend/lowering/lower-comptime.ts +++ b/packages/compiler/src/frontend/lowering/lower-comptime.ts @@ -4,7 +4,7 @@ import { InternalCompilerError } from "../../errors.js"; * literals — records/arrays/unions included, subject to comptimeBakeable. */ import * as ts from "../ts7/adapter.js"; import type { Lowerer } from "./lowerer.js"; -import { type IrExpr, type IrType } from "../../ir/ir.js"; +import { isUnitType, type IrExpr, type IrType } from "../../ir/ir.js"; import { comptimeFailedDiag } from "../../diagnostics/diagnostic.js"; import { locOf } from "../program.js"; import { PoisonError } from "./lowerer.js"; @@ -110,8 +110,9 @@ function comptimeFailureDetail(error: unknown): string { /** True when a comptime result of this type can be written as a literal * expression: number/string/boolean, arrays and record shapes of those, - * nested. Closures, class instances, unions, promises, dyn, and void - * cannot be baked. */ + * and unions of those with null or undefined (the mixed rows of a JSON + * table: `(string | number)[][]`), nested. Closures, class instances, + * promises, dyn, and void cannot be baked. */ export function comptimeBakeable(lowerer: Lowerer, t: IrType): boolean { switch (t.kind) { case "f64": @@ -124,6 +125,52 @@ export function comptimeBakeable(lowerer: Lowerer, t: IrType): boolean { const shape = lowerer.shapes.get(t.shapeId); return !!shape && shape.fields.every((f) => lowerer.comptimeBakeable(f.type)); } + case "union": { + const arms = lowerer.unions.get(t.unionId)?.arms; + return ( + arms !== undefined && + arms.every( + (arm) => isUnitType(arm) || (arm.kind !== "union" && comptimeBakeable(lowerer, arm)), + ) + ); + } + default: + return false; + } +} + +/** Whether `value` bakes into the bakeable type `t` without a mismatch: + * the arm choice of a union literal. Records are exact, as in + * comptimeValueToIr; an absent field reads as undefined. */ +function comptimeFits(lowerer: Lowerer, value: unknown, t: IrType): boolean { + switch (t.kind) { + case "f64": + return typeof value === "number" && Number.isFinite(value); + case "string": + return typeof value === "string"; + case "bool": + return typeof value === "boolean"; + case "nullT": + return value === null; + case "undefinedT": + return value === undefined; + case "array": + return Array.isArray(value) && value.every((el) => comptimeFits(lowerer, el, t.elem)); + case "record": { + if (typeof value !== "object" || value === null || Array.isArray(value)) return false; + const shape = lowerer.shapes.get(t.shapeId); + if (!shape) return false; + const obj = value as Record; + const declared = new Set(shape.fields.map((f) => f.name)); + return ( + Object.keys(obj).every((key) => declared.has(key)) && + shape.fields.every((f) => comptimeFits(lowerer, obj[f.name], f.type)) + ); + } + case "union": + return (lowerer.unions.get(t.unionId)?.arms ?? []).some((arm) => + comptimeFits(lowerer, value, arm), + ); default: return false; } @@ -265,6 +312,26 @@ export function comptimeValueToIr( })); return { kind: "recordLit", fields, type: expected, loc }; } + case "union": { + // The first arm the value fits, in the union's arm order: a JSON + // value fits exactly one scalar arm, and array or record arms are + // told apart by their contents. + const arms = lowerer.unions.get(expected.unionId)!.arms; // bakeable-checked + const tag = arms.findIndex((arm) => comptimeFits(lowerer, value, arm)); + if (tag < 0) fail(describeComptimeValue(value)); + const arm = arms[tag]!; + const payload: IrExpr = isUnitType(arm) + ? { kind: "unitLit", unit: arm.kind === "nullT" ? "null" : "undefined", type: arm, loc } + : lowerer.comptimeValueToIr(value, arm, path, blame); + return { + kind: "unionWrap", + unionId: expected.unionId, + tag, + value: payload, + type: expected, + loc, + }; + } default: // comptimeBakeable already fenced these off. throw new InternalCompilerError(`lowerer bug: unbakeable comptime target '${expected.kind}'`); diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 2c36e4973..444fb899c 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -2379,20 +2379,26 @@ export function lowerBindingPattern( lowerer.fenceStaticHeadersIteration(pattern); if ( srcType.kind === "union" && - lowerer.unions.get(srcType.unionId)?.arms.every((arm) => arm.kind === "array") + lowerer.unions + .get(srcType.unionId) + ?.arms.every( + (arm) => + arm.kind === "array" || + (arm.kind === "record" && lowerer.shapes.get(arm.shapeId)?.tuple === true), + ) ) { for (let i = 0; i < pattern.elements.nodes.length; i++) { const el = pattern.elements.nodes[i]!; if (ts.isOmittedExpression(el) || el.name === undefined) continue; if (el.dotDotDotToken) - lowerer.unsupported("SC1031", el, "rest elements over a union of array layouts"); + lowerer.unsupported("SC1031", el, "rest elements over a union of array or tuple layouts"); const loc = locOf(el); let value = unionArrayValueRead(lowerer, srcRef(), numLit(i, loc), loc); if (!value) lowerer.unsupported( "SC1031", el, - "array union elements without a common native representation", + "array or tuple union elements without a common native representation", ); if (el.initializer) value = applyBindingDefault(lowerer, el, value); lowerer.bindPatternTarget(el.name, value, isLet, out); diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 437aba2b8..eea7dd976 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -4411,6 +4411,9 @@ function unionDiscriminant( ): IrUnionDiscriminant | undefined { if (arms.filter((arm) => arm.kind === "record").length < 2 || parts.length < 2) return undefined; const { checker } = ctx; + // Tuple shapes keep positions only: their checker `length` literal has + // no slot to compare (discriminantField refuses tuple shapes too). + if (parts.some((part) => ctx.shapes.get(part.mapped.shapeId)?.tuple)) return undefined; for (const candidate of checker.getPropertiesOfType(parts[0]!.source)) { if (candidate.name.startsWith("__@")) continue; const byTag = new Map(); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6410-json-mixed-scalar-tables/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6410-json-mixed-scalar-tables/main.ts.json new file mode 100644 index 000000000..c7ec1ab56 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6410-json-mixed-scalar-tables/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6410-json-mixed-scalar-tables/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6411-union-array-tuple-destructuring.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6411-union-array-tuple-destructuring.ts.json new file mode 100644 index 000000000..94d8b78e7 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6411-union-array-tuple-destructuring.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6411-union-array-tuple-destructuring.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6410-json-mixed-scalar-tables/extra.json b/tests/corpus/6410-json-mixed-scalar-tables/extra.json new file mode 100644 index 000000000..927c5d968 --- /dev/null +++ b/tests/corpus/6410-json-mixed-scalar-tables/extra.json @@ -0,0 +1 @@ +[["x", 1, "two", 3], [4, "five"], ["six"]] diff --git a/tests/corpus/6410-json-mixed-scalar-tables/main.ts b/tests/corpus/6410-json-mixed-scalar-tables/main.ts new file mode 100644 index 000000000..54e337b02 --- /dev/null +++ b/tests/corpus/6410-json-mixed-scalar-tables/main.ts @@ -0,0 +1,21 @@ +// JSON tables whose rows mix strings and numbers, the shape of a +// character-set table (`[["8140", 12288, 65292], ...]`) and of a +// code-point range map (`[[[0, 44], "disallowed"], [[65, 65], "mapped", +// [97]], ...]`). A package requires them at load or inside a function, and +// an ES module imports one; each row keeps its strings and numbers. +import { lookup, rowCount } from "code-table"; +import { mapChars, status } from "range-map"; +import extra from "./extra.json" with { type: "json" }; + +console.log(lookup("8150"), lookup("a1"), lookup("zzzz"), rowCount()); +const mapped = mapChars("AB-c9"); +console.log(mapped.text, mapped.error); +console.log(JSON.stringify(mapChars("a,b")), JSON.stringify(mapChars("{"))); +console.log(status(10), status(46), status(66), status(1000)); + +for (const row of extra) { + const head = row[0]; + const rest = row.slice(1); + console.log(typeof head, head, rest.length, rest.map((v) => (typeof v === "number" ? v + 1 : v.toUpperCase())).join(",")); +} +console.log(JSON.stringify(extra)); diff --git a/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/index.d.ts b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/index.d.ts new file mode 100644 index 000000000..ae7db1d98 --- /dev/null +++ b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/index.d.ts @@ -0,0 +1,2 @@ +export declare function lookup(code: string): number | string; +export declare function rowCount(): number; diff --git a/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/index.js b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/index.js new file mode 100644 index 000000000..dc10bb817 --- /dev/null +++ b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/index.js @@ -0,0 +1,10 @@ +'use strict'; +const table = require('./table.json'); +exports.lookup = function (code) { + for (const row of table) if (row[0] === code) return row[1]; + return -1; +}; +exports.rowCount = function () { + // A second require of the same document answers the same rows. + return require('./table.json').length; +}; diff --git a/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/package.json b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/package.json new file mode 100644 index 000000000..e15622d87 --- /dev/null +++ b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/package.json @@ -0,0 +1 @@ +{ "name": "code-table", "version": "1.0.0", "main": "index.js", "types": "index.d.ts" } diff --git a/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/table.json b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/table.json new file mode 100644 index 000000000..5abaa6772 --- /dev/null +++ b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/code-table/table.json @@ -0,0 +1 @@ +[["8140", 12288, 65292], ["8150", 65507, 65340], ["a1", "。", 62]] diff --git a/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/index.d.ts b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/index.d.ts new file mode 100644 index 000000000..322bd20e1 --- /dev/null +++ b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/index.d.ts @@ -0,0 +1,2 @@ +export declare function mapChars(s: string): { text: string; error: boolean }; +export declare function status(cp: number): string; diff --git a/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/index.js b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/index.js new file mode 100644 index 000000000..481d93ad4 --- /dev/null +++ b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/index.js @@ -0,0 +1,37 @@ +'use strict'; +var table = require('./table.json'); +function findStatus(val) { + var start = 0; + var end = table.length - 1; + while (start <= end) { + var mid = Math.floor((start + end) / 2); + var target = table[mid]; + if (target[0][0] <= val && target[0][1] >= val) { + return target; + } else if (target[0][0] > val) { + end = mid - 1; + } else { + start = mid + 1; + } + } + return null; +} +exports.status = function (cp) { + var found = findStatus(cp); + return found === null ? 'unknown' : found[1]; +}; +exports.mapChars = function (s) { + var error = false; + var out = ''; + for (var i = 0; i < s.length; ++i) { + var cp = s.codePointAt(i); + var found = findStatus(cp); + if (found === null) { error = true; continue; } + switch (found[1]) { + case 'disallowed': error = true; out += String.fromCodePoint(cp); break; + case 'mapped': out += String.fromCodePoint.apply(String, found[2]); break; + case 'valid': out += String.fromCodePoint(cp); break; + } + } + return { text: out, error: error }; +}; diff --git a/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/package.json b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/package.json new file mode 100644 index 000000000..bc877e1e8 --- /dev/null +++ b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/package.json @@ -0,0 +1 @@ +{ "name": "range-map", "version": "1.0.0", "main": "index.js", "types": "index.d.ts" } diff --git a/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/table.json b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/table.json new file mode 100644 index 000000000..900f9e316 --- /dev/null +++ b/tests/corpus/6410-json-mixed-scalar-tables/node_modules/range-map/table.json @@ -0,0 +1 @@ +[[[0,44],"disallowed"],[[45,46],"valid"],[[47,47],"disallowed"],[[48,57],"valid"],[[65,65],"mapped",[97]],[[66,67],"mapped",[98,99]],[[97,122],"valid"]] diff --git a/tests/corpus/6411-union-array-tuple-destructuring.ts b/tests/corpus/6411-union-array-tuple-destructuring.ts new file mode 100644 index 000000000..1dd88fa92 --- /dev/null +++ b/tests/corpus/6411-union-array-tuple-destructuring.ts @@ -0,0 +1,34 @@ +// Array destructuring of a value whose type is a union of array and tuple +// types: a regex match or a default row (`re.exec(s) || ["", "", ""]`), and +// functions answering either a fixed tuple or a list. Each position reads +// the arm the value holds; positions past a tuple's end and past an array's +// end read undefined, and defaults fire exactly there. +function scan(text: string): string { + const [match, head, word] = /(\w*)-(\w+)/.exec(text) || ["", "", ""]; + return `${match}|${head}|${word.toUpperCase()}`; +} +console.log(scan("ab-cd"), scan("none"), scan("-x")); + +function pick(flag: boolean): [string, number] | string[] { + return flag ? ["a", 1] : ["b", "c"]; +} +const [p, q] = pick(true); +const [r, s = "dflt", t = "z"] = pick(false); +const [u, , w = "w"] = pick(true); +console.log(p, q, r, s, t, u, w); +console.log(typeof q, typeof s); + +function pair(n: number): number[] | [number, number] { + return n > 1 ? [n, n * 2] : [n]; +} +const [x, y] = pair(7); +const [x1, y1 = -1] = pair(1); +console.log(x, y, x1, y1); + +function row(kind: string): [string, boolean] | [string, boolean, number] { + return kind === "long" ? [kind, true, 3] : [kind, false]; +} +for (const k of ["long", "short"]) { + const [name, flag, count = 0] = row(k); + console.log(name, flag, count); +} From 52f9bf284f7174c3e0f0163aa676f57591ec25b4 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 20:40:56 -0700 Subject: [PATCH 09/39] Destructure a match-or-empty-string union by code point `const [hit] = re.exec(s) || ""` destructures `RegExpExecArray | string`: the string arm answers its code point at each position, or undefined past its end, as the string iterator does. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/array-values.ts | 25 ++++++++++++++----- .../src/frontend/lowering/lower-stmts.ts | 8 ++++-- .../6411-union-array-tuple-destructuring.ts | 8 ++++++ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/array-values.ts b/packages/compiler/src/frontend/lowering/array-values.ts index e9148b244..0ca8503df 100644 --- a/packages/compiler/src/frontend/lowering/array-values.ts +++ b/packages/compiler/src/frontend/lowering/array-values.ts @@ -8,6 +8,7 @@ import { type IrType, isIntegerBytesElem, type SrcLoc, + STRING, UNDEFINED_T, typeEquals, typeKey, @@ -88,12 +89,15 @@ export function arrayValueRead( * (`const [a, b] = re.exec(s) || ["", ""]`) without copying the receiver * or its elements. Every array arm contributes its missing-value case; a * tuple arm answers its field, or undefined past its end. Tuple arms need - * a constant position. */ + * a constant position. With `stringChars` (the string iterator's code + * points as a fresh string[]), a string arm (`re.exec(s) || ""`) answers + * its code point at the position, or undefined past its end. */ export function unionArrayValueRead( lowerer: Lowerer, value: IrExpr, index: IrExpr, loc: SrcLoc, + stringChars?: (text: IrExpr) => IrExpr, ): IrExpr | null { if (value.type.kind !== "union") return null; const unionId = value.type.unionId; @@ -110,16 +114,20 @@ export function unionArrayValueRead( }; // Keep the collection's IrType union layout and narrow each element at // its use; an inferred array predicate changes the collection's ABI. - for (const arm of arms) if (arm.kind !== "array" && tupleField(arm) === null) return null; + const stringArm = (arm: IrType): boolean => arm.kind === "string" && stringChars !== undefined; + for (const arm of arms) + if (arm.kind !== "array" && !stringArm(arm) && tupleField(arm) === null) return null; const answers = new Map(); for (const arm of arms) { - const field = arm.kind === "array" ? null : tupleField(arm); + const field = arm.kind === "array" || stringArm(arm) ? null : tupleField(arm); const answer = arm.kind === "array" ? arrayValueType(lowerer, arm.elem) - : field === "past" - ? UNDEFINED_T - : field!.type; + : stringArm(arm) + ? arrayValueType(lowerer, STRING) + : field === "past" + ? UNDEFINED_T + : field!.type; const parts = answer.kind === "union" ? lowerer.unions.get(answer.unionId)!.arms : [answer]; for (const part of parts) answers.set(typeKey(part), part); } @@ -143,6 +151,11 @@ export function unionArrayValueRead( arrayValueRead(lowerer, receiver, index, arm.elem, loc), type, ); + } else if (stringArm(arm)) { + read = lowerer.coerceToExpected( + arrayValueRead(lowerer, stringChars!(receiver), index, STRING, loc), + type, + ); } else { const field = tupleField(arm); if (field === null) return null; diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 444fb899c..737c2e9ae 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -2384,8 +2384,10 @@ export function lowerBindingPattern( ?.arms.every( (arm) => arm.kind === "array" || + arm.kind === "string" || (arm.kind === "record" && lowerer.shapes.get(arm.shapeId)?.tuple === true), - ) + ) && + lowerer.unions.get(srcType.unionId)!.arms.some((arm) => arm.kind !== "string") ) { for (let i = 0; i < pattern.elements.nodes.length; i++) { const el = pattern.elements.nodes[i]!; @@ -2393,7 +2395,9 @@ export function lowerBindingPattern( if (el.dotDotDotToken) lowerer.unsupported("SC1031", el, "rest elements over a union of array or tuple layouts"); const loc = locOf(el); - let value = unionArrayValueRead(lowerer, srcRef(), numLit(i, loc), loc); + let value = unionArrayValueRead(lowerer, srcRef(), numLit(i, loc), loc, (text) => + strCharsCall(lowerer, text, loc), + ); if (!value) lowerer.unsupported( "SC1031", diff --git a/tests/corpus/6411-union-array-tuple-destructuring.ts b/tests/corpus/6411-union-array-tuple-destructuring.ts index 1dd88fa92..f62eba996 100644 --- a/tests/corpus/6411-union-array-tuple-destructuring.ts +++ b/tests/corpus/6411-union-array-tuple-destructuring.ts @@ -32,3 +32,11 @@ for (const k of ["long", "short"]) { const [name, flag, count = 0] = row(k); console.log(name, flag, count); } + +// A match or an empty string (`re.exec(s) || ""`): a string destructures +// by code point, so the empty string binds undefined. +function firstHit(text: string): string { + const [hit] = /\d+/.exec(text) || ""; + return hit ? `hit ${hit}` : "none"; +} +console.log(firstHit("ab12"), firstHit("ab")); From c208973d752bd72c72b6497358e7e4f2a3860342 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 20:35:23 -0700 Subject: [PATCH 10/39] Read T[keyof T] as unknown for T bound to an unknown-valued record Inside a generic body Object.entries(t) over T extends Record types its values 'keyof T extends never ? unknown : T[keyof T]'. An instance whose T maps to the checked-dynamic value now reads both branches as unknown. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/src/frontend/type-mapper.ts | 19 +++++++++-- ...468-generic-unknown-record-entries.ts.json | 6 ++++ .../6468-generic-unknown-record-entries.ts | 33 +++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6468-generic-unknown-record-entries.ts.json create mode 100644 tests/corpus/6468-generic-unknown-record-entries.ts diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 1e3954586..7a40d4e24 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -5139,11 +5139,15 @@ function mapGenericIndexedAccess(type: ts.Type, ctx: TypeMapperCtx): IrType | nu const obj = type.getObjectType(); if (obj === undefined || !(obj.flags & ts.TypeFlags.TypeParameter)) return null; const bound = resolveTypeParam(obj); + const idx = type.getIndexType(); + if (idx === undefined) return null; + // `T[keyof T]` over a T bound to an unknown-valued record view + // (`Record` maps to the checked-dynamic value, see + // mapRecordType): every member reads as unknown. + if (bound?.kind === "dyn" && idx.isIndexType() && idx.getTarget() === obj) return DYN; if (!bound || bound.kind !== "record") return null; const shape = shapes.get(bound.shapeId); if (!shape || shape.tuple) return null; - const idx = type.getIndexType(); - if (idx === undefined) return null; let covered: IrType[] | null = null; if (idx.isStringLiteralType()) { const f = shape.fields.find((x) => x.name === idx.value); @@ -5199,6 +5203,17 @@ function mapBoundKeyofNeverConditional(type: ts.Type, ctx: TypeMapperCtx): IrTyp const target = check.getTarget(); if (!target || !(target.flags & ts.TypeFlags.TypeParameter)) return null; const bound = resolveTypeParam(target); + // A T bound to the checked-dynamic value (`Record`, an + // unknown-valued record view) has no static key set to decide the + // branch, but both branches of the lib's `keyof T extends never ? + // unknown : T[keyof T]` read as unknown there: one answer either way. + if (bound?.kind === "dyn") { + const whenEmpty = type.getTrueType(); + const otherwise = type.getFalseType(); + const a = whenEmpty ? mapType(whenEmpty, ctx) : null; + const b = otherwise ? mapType(otherwise, ctx) : null; + return a && b && typeEquals(a, b) ? a : null; + } if (bound?.kind !== "record") return null; const shape = shapes.get(bound.shapeId); if (!shape || shape.tuple) return null; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6468-generic-unknown-record-entries.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6468-generic-unknown-record-entries.ts.json new file mode 100644 index 000000000..0b4118c70 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6468-generic-unknown-record-entries.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6468-generic-unknown-record-entries.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6468-generic-unknown-record-entries.ts b/tests/corpus/6468-generic-unknown-record-entries.ts new file mode 100644 index 000000000..f0e57756a --- /dev/null +++ b/tests/corpus/6468-generic-unknown-record-entries.ts @@ -0,0 +1,33 @@ +// Inside a generic body, `Object.entries(tags)` over `T extends +// Record` reads `[string, T[keyof T]]` elements. An +// instance whose T is the unknown-valued record view reads every member +// as unknown; a record instance reads the union of its member types. +function upper(text: string): string { + return text.toUpperCase(); +} + +function scrub(text: string): string { + return text.replace(/secret/g, "***"); +} + +function describe>(tags: T): string[] { + return Object.entries(tags).map( + ([key, value]) => `${key}=${typeof value === "string" ? upper(value) : String(value)}`, + ); +} + +function redact>(tags: T): T { + return Object.fromEntries( + Object.entries(tags).map(([key, value]) => [key, typeof value === "string" ? scrub(value) : value]), + ) as T; +} + +function flatten(value: unknown): Record { + return typeof value === "object" && value !== null ? (value as Record) : { value }; +} + +console.log(describe(flatten({ b: 1, a: "x", c: true }))); +console.log(describe(flatten(5))); +console.log(describe({ name: "n", size: 3 })); +const cleaned = redact(flatten({ token: "secret", count: 2 })); +console.log(cleaned, Object.keys(cleaned)); From fe322ae901cbc4914f527c756d8f71235f2454f4 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 21:16:25 -0700 Subject: [PATCH 11/39] Keep the JSON-shape diagnostics fixture refused now that null fields bake A null-valued JSON field bakes as null, so the fixture's document now compiles. It keeps its purpose with a value no literal spells (1e400 parses to Infinity), and the mixed-table corpus program covers null elements. Co-Authored-By: Claude Opus 5.5 --- tests/corpus/6410-json-mixed-scalar-tables/extra.json | 2 +- tests/corpus/6410-json-mixed-scalar-tables/main.ts | 7 ++++++- tests/diagnostics/json-shape/main.ts | 8 ++++---- tests/diagnostics/json-shape/nulled.json | 2 +- tests/harness/__snapshots__/json-shape/main.ts.txt | 4 ++-- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/tests/corpus/6410-json-mixed-scalar-tables/extra.json b/tests/corpus/6410-json-mixed-scalar-tables/extra.json index 927c5d968..7af99c22f 100644 --- a/tests/corpus/6410-json-mixed-scalar-tables/extra.json +++ b/tests/corpus/6410-json-mixed-scalar-tables/extra.json @@ -1 +1 @@ -[["x", 1, "two", 3], [4, "five"], ["six"]] +[["x", 1, "two", 3], [4, "five", null], ["six"], [null]] diff --git a/tests/corpus/6410-json-mixed-scalar-tables/main.ts b/tests/corpus/6410-json-mixed-scalar-tables/main.ts index 54e337b02..c60f962dc 100644 --- a/tests/corpus/6410-json-mixed-scalar-tables/main.ts +++ b/tests/corpus/6410-json-mixed-scalar-tables/main.ts @@ -16,6 +16,11 @@ console.log(status(10), status(46), status(66), status(1000)); for (const row of extra) { const head = row[0]; const rest = row.slice(1); - console.log(typeof head, head, rest.length, rest.map((v) => (typeof v === "number" ? v + 1 : v.toUpperCase())).join(",")); + console.log( + typeof head, + head, + rest.length, + rest.map((v) => (v === null ? "null" : typeof v === "number" ? v + 1 : v.toUpperCase())).join(","), + ); } console.log(JSON.stringify(extra)); diff --git a/tests/diagnostics/json-shape/main.ts b/tests/diagnostics/json-shape/main.ts index 1d9552506..a46338d52 100644 --- a/tests/diagnostics/json-shape/main.ts +++ b/tests/diagnostics/json-shape/main.ts @@ -1,7 +1,7 @@ -/* A JSON document whose shape doesn't bake: a null-valued field has no - * standalone STATIC type, so the import reports the dynamic-family type - * diagnostic (SC2011 at the import site — the shape maps in the embedded - * engine) and uses of the binding poison. */ +/* A JSON document whose value doesn't bake: `1e400` parses to Infinity, + * which no number literal spells, so the import reports the bake failure + * at the import site and uses of the binding poison. (Its null-valued + * field bakes as null.) */ import bad from "./nulled.json" with { type: "json" }; console.log(bad.name); diff --git a/tests/diagnostics/json-shape/nulled.json b/tests/diagnostics/json-shape/nulled.json index fa4738449..5e506a6af 100644 --- a/tests/diagnostics/json-shape/nulled.json +++ b/tests/diagnostics/json-shape/nulled.json @@ -1 +1 @@ -{ "name": "x", "deprecated": null } +{ "name": "x", "deprecated": null, "limit": 1e400 } diff --git a/tests/harness/__snapshots__/json-shape/main.ts.txt b/tests/harness/__snapshots__/json-shape/main.ts.txt index b03f098a6..85f5d2917 100644 --- a/tests/harness/__snapshots__/json-shape/main.ts.txt +++ b/tests/harness/__snapshots__/json-shape/main.ts.txt @@ -1,6 +1,6 @@ -json-shape/main.ts:5:8 - error SC2001: values of type '{ name: string; deprecated: null; }' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +json-shape/main.ts:5:8 - error SC1110: comptime evaluation failed: expected 'number' at $.limit, got Infinity (only finite numbers can be written as literals) - 4 | * engine) and uses of the binding poison. */ + 4 | * field bakes as null.) */ 5 | import bad from "./nulled.json" with { type: "json" }; | ^~~ 6 | From 85a2567ecdcacfcbf1004af9cc248b7fc04b8ffc Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 20:35:22 -0700 Subject: [PATCH 12/39] Treat optional members an index signature covers as keys, erase 'as never', and keep fromEntries objects asserted to records A record type whose declared members are all optional and typed as its index signature's slot (ProcessEnv's TZ?, '{ CI?: string } & Dictionary') interns as the pure index-signature record, its slot admitting undefined: spread, delete and enumeration then follow one insertion order. 'value as never' erases, so the consuming slot checks an unknown value like any other. 'Object.fromEntries(...) as T' for a declared record T goes through the checked-dynamic bridge, which keeps the entries' keys and order. Co-Authored-By: Claude Opus 5.5 --- .../lowering/expressions/narrowing.ts | 52 +++++++++++++ packages/compiler/src/frontend/type-mapper.ts | 47 ++++++++++++ ...ional-members-over-index-signature.ts.json | 6 ++ .../6466-never-assertion-argument.ts.json | 6 ++ .../6467-fromentries-record-assertion.ts.json | 6 ++ ...5-optional-members-over-index-signature.ts | 73 +++++++++++++++++++ tests/corpus/6466-never-assertion-argument.ts | 31 ++++++++ .../6467-fromentries-record-assertion.ts | 29 ++++++++ 8 files changed, 250 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6465-optional-members-over-index-signature.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6466-never-assertion-argument.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6467-fromentries-record-assertion.ts.json create mode 100644 tests/corpus/6465-optional-members-over-index-signature.ts create mode 100644 tests/corpus/6466-never-assertion-argument.ts create mode 100644 tests/corpus/6467-fromentries-record-assertion.ts diff --git a/packages/compiler/src/frontend/lowering/expressions/narrowing.ts b/packages/compiler/src/frontend/lowering/expressions/narrowing.ts index 207000717..09bb4b4d1 100644 --- a/packages/compiler/src/frontend/lowering/expressions/narrowing.ts +++ b/packages/compiler/src/frontend/lowering/expressions/narrowing.ts @@ -1151,6 +1151,50 @@ export function withRuntimeOptionalNarrowed( * memory); * - dyn → anything else (closures, class instances, void) is rejected: * those types cannot be found inside a JSON dyn. */ +/** `Object.fromEntries(...) as T` with T a declared record (the generic + * `transform>(t: T): T` idiom): the + * entries build a pure index-signature record, which has no layout in + * common with T's struct. Node keeps the object itself, with exactly the + * keys and the order the entries gave it. The result of fromEntries is a + * fresh object nothing else references, so the checked-dynamic bridge, + * which keeps keys and their order the same way `JSON.parse(text) as T` + * does, cannot be told apart from the original object; a value outside + * T throws the catchable TypeError of every checked cast. Other sources + * may be aliased, where a rebuilt object would sever mutation, so they + * keep the exact-shape fence. */ +function freshEntriesRecordAssertion( + lowerer: Lowerer, + expr: ts.AsExpression | ts.TypeAssertion, + inner: IrExpr, + target: IrType | null, +): IrExpr | null { + if (inner.type.kind !== "record" || target?.kind !== "record") return null; + const source = lowerer.shapes.get(inner.type.shapeId); + const dest = lowerer.shapes.get(target.shapeId); + if (!source?.indexValue || source.tuple || source.fields.length > 0) return null; + if (!dest || dest.tuple || dest.indexValue || shapeHasAccessorSlots(dest)) return null; + let operand: ts.Expression = expr.expression; + while (ts.isParenthesizedExpression(operand)) operand = operand.expression; + if ( + !ts.isCallExpression(operand) || + !ts.isPropertyAccessExpression(operand.expression) || + operand.expression.name.text !== "fromEntries" || + !lowerer.isStdlibGlobal(operand.expression.expression, "Object") + ) + return null; + if (!lowerer.dynConvertible(inner.type)) return null; + if ( + !canDynCheckTo( + target, + (id) => lowerer.shapes.get(id), + (id) => lowerer.unions.get(id), + ) + ) + return null; + const loc = locOf(expr); + return { kind: "dynCheck", value: lowerer.coerceToExpected(inner, DYN), type: target, loc }; +} + /** `e as T` and the old-style assertion `e` — one node shape (both * carry `.type` and `.expression`), one lowering. */ export function lowerAsExpression( @@ -1286,6 +1330,8 @@ export function lowerAsExpression( ) { return lowerer.coerceInto(expr, inner, target); } + const rebuilt = freshEntriesRecordAssertion(lowerer, expr, inner, target); + if (rebuilt) return rebuilt; // Static assertions normally erase, but record layouts are // monomorphic: a consumer selected from the asserted shape must see // that shape physically. Reuse the ordinary slot coercion so plain @@ -1327,6 +1373,12 @@ export function lowerAsExpression( return inner; // erasure, unchanged } + // `value as never` is the escape hatch that makes an unknown value fit + // any slot (`tagSuccess(value as never)`). No value has type never, so + // checking against its placeholder layout would reject every value. + // Erase it instead: the consuming slot applies the same validated + // extraction an unknown value gets wherever the checker admits it. + if (expr.type.kind === ts.SyntaxKind.NeverKeyword) return inner; const targetTs = lowerer.checker.getTypeFromTypeNode(expr.type); const target = lowerer.mapTypeOf(targetTs) ?? dynFallbackType(lowerer, expr.type, targetTs); if (!target) lowerer.badType(expr.type, targetTs); diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 437aba2b8..2b47c8ff3 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -5860,6 +5860,8 @@ function mapRecordType(widened: ts.Type, ctx: TypeMapperCtx): IrType | null { (inner.indexValue === undefined || inner.indexValue.kind === "dyn") ) return DYN; + const covered = coveredOptionalFieldsShape(widened, inner, ctx); + if (covered !== null) return { kind: "record", shapeId: covered }; const refined = refinedConstituentShape(widened, inner, ctx); if (refined !== null) return { kind: "record", shapeId: refined }; return { @@ -5871,6 +5873,51 @@ function mapRecordType(widened: ts.Type, ctx: TypeMapperCtx): IrType | null { } } +/** An index signature already describes every OPTIONAL declared member + * whose type is its slot type: @types/node's `ProcessEnv extends + * Dict { TZ?: string }` and every spread of it, or a declared + * environment `{ CI?: string } & Dictionary`. At runtime such a + * member is just another key, so the shape interns as the pure + * index-signature record. Its slot admits undefined, as the optional + * members do (`env.CI = undefined` keeps the key). A hybrid layout would + * give each member a struct slot, which enumerates before the overflow + * keys (Node keeps one insertion order) and makes `delete` and spread + * answer differently for declared and undeclared keys. Required members, + * and members typed otherwise than the slot (whose reads the slot type + * could not give back), keep the hybrid shape. */ +function coveredOptionalFieldsShape( + widened: ts.Type, + parts: RecordShapeParts, + ctx: TypeMapperCtx, +): string | null { + const slot = parts.indexValue; + if (!slot || parts.fields.length === 0) return null; + const { checker, shapes, unions } = ctx; + // The members' common type must be the slot plus undefined. Read it off + // the members (already interned) rather than building it: a hybrid that + // does not qualify must not intern anything new. + const optionalSlot = parts.fields[0]!.type; + if (!parts.fields.every((field) => typeEquals(field.type, optionalSlot))) return null; + if (optionalSlot.kind !== "union" || unions.armTag(optionalSlot.unionId, UNDEFINED_T) < 0) + return null; + const memberArms = unions.get(optionalSlot.unionId)?.arms ?? []; + const slotArms = + slot.kind === "union" ? (unions.get(slot.unionId)?.arms ?? []) : isUnitType(slot) ? [] : [slot]; + const definedArms = memberArms.filter((arm) => arm.kind !== "undefinedT"); + const slotDefined = slotArms.filter((arm) => arm.kind !== "undefinedT"); + if ( + definedArms.length === 0 || + definedArms.length !== slotDefined.length || + !slotDefined.every((arm) => definedArms.some((other) => typeEquals(arm, other))) + ) + return null; + if (!isSupportedIndexValue(optionalSlot)) return null; + const props = checker.getPropertiesOfType(widened); + if (props.length !== parts.fields.length) return null; + if (!props.every((p) => (p.flags & ts.SymbolFlags.Optional) !== 0)) return null; + return shapes.intern([], false, optionalSlot, []); +} + /** A refinement intersection (`Expr & { kind: "mul" }`, which the checker * reduces to `Mul & { kind: "mul" }`) keeps the shape of the constituent it * refines when the refinement changes no field's representation. Recursive diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6465-optional-members-over-index-signature.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6465-optional-members-over-index-signature.ts.json new file mode 100644 index 000000000..91a157207 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6465-optional-members-over-index-signature.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6465-optional-members-over-index-signature.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6466-never-assertion-argument.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6466-never-assertion-argument.ts.json new file mode 100644 index 000000000..17f25aa22 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6466-never-assertion-argument.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6466-never-assertion-argument.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6467-fromentries-record-assertion.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6467-fromentries-record-assertion.ts.json new file mode 100644 index 000000000..21ca66953 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6467-fromentries-record-assertion.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6467-fromentries-record-assertion.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6465-optional-members-over-index-signature.ts b/tests/corpus/6465-optional-members-over-index-signature.ts new file mode 100644 index 000000000..df957c8d9 --- /dev/null +++ b/tests/corpus/6465-optional-members-over-index-signature.ts @@ -0,0 +1,73 @@ +// An index signature whose value admits undefined already describes an +// optional member of the same type (`interface Env extends Dict +// { TZ?: string }`, @types/node's ProcessEnv): such a record is one key +// set in insertion order, so spread, delete, `in` and every enumeration +// treat the declared member like any other key. +interface Env { + TZ?: string; + [key: string]: string | undefined; +} + +const base: Env = { A: "1", TZ: "UTC", B: "2" }; +const env = { ...base }; +env.C = "3"; +for (const key of ["A", "TZ", "MISSING"]) { + delete env[key]; +} +console.log(Object.entries(env), Object.keys(base)); +const probe = (key: string): boolean => key in env; +console.log(probe("TZ"), probe("B"), env.TZ, env.B); +env.TZ = "Europe/Berlin"; +console.log(JSON.stringify(env), env); + +const extended: Env = { ...base, D: "4" }; +delete extended.TZ; +extended.TZ = "Asia/Tokyo"; +console.log(extended, Object.keys(extended).join(",")); + +// A declared member written after another key comes after it. +interface Scores { + best?: number; + [name: string]: number | undefined; +} +const scores: Scores = {}; +scores["x"] = 1; +scores.best = 2; +console.log(Object.keys(scores), JSON.stringify(scores)); + +// The process environment has the same shape; a child environment built +// from it keeps the parent's keys in order. +process.env.SCX_FIRST = "first"; +process.env.SCX_DROP = "drop"; +process.env.SCX_LAST = "last"; +const DROP = ["SCX_DROP", "SCX_NOT_SET"]; +function childEnv(): string[] { + const runEnv = { ...process.env }; + runEnv.SCX_ADDED = "added"; + for (const key of DROP) { + delete runEnv[key]; + } + runEnv.SCX_FIRST = runEnv.SCX_FIRST ? `${runEnv.SCX_FIRST}!` : "none"; + return Object.entries(runEnv) + .filter(([key]) => key.startsWith("SCX_")) + .map(([key, value]) => `${key}=${value || ""}`); +} +console.log(childEnv()); + +// A record of declared optional members over a slot without undefined is +// the same key set: merging it over the process environment keeps both. +type Dictionary = { [key: string]: T }; +type BuildEnv = { CI?: string; DEBUG?: string } & Dictionary; +function merged(buildEnv: BuildEnv): string[] { + const env = { ...process.env, ...buildEnv }; + return [ + String(env.CI === "1" || env.SCX_FIRST === "first"), + `${env.DEBUG ?? "-"}`, + Object.keys(env) + .filter((key) => key.startsWith("SCX_") || key === "CI" || key === "DEBUG") + .join(","), + ]; +} +const buildEnv: BuildEnv = { SCX_BUILD: "b", CI: "1" }; +buildEnv.DEBUG = "yes"; +console.log(merged(buildEnv), Object.keys(buildEnv), buildEnv.CI, buildEnv["SCX_BUILD"]); diff --git a/tests/corpus/6466-never-assertion-argument.ts b/tests/corpus/6466-never-assertion-argument.ts new file mode 100644 index 000000000..8d2c1f2bf --- /dev/null +++ b/tests/corpus/6466-never-assertion-argument.ts @@ -0,0 +1,31 @@ +// `value as never` makes an unknown value fit any parameter: the argument +// is checked against the parameter's type like any unknown value the +// checker admits there, and a typed value passes unchanged. +type Out = { routes: { src: string; dest?: string }[]; count: number }; + +function show(tags: Record): void { + console.log(JSON.stringify(tags)); +} + +function report(tag: (result: Out) => Record, value: unknown): void { + show(tag(value as never)); +} + +const describe = (r: Out): Record => ({ count: r.count, first: r.routes[0]?.src }); +report(describe, JSON.parse('{"routes":[{"src":"/a"},{"src":"/b","dest":"/c"}],"count":2}')); + +// Through a promise of unknown, the way a wrapper tags an async result. +function later(value: Out): Promise { + return Promise.resolve(value); +} +later({ routes: [], count: 7 }).then((value) => { + show(describe(value as never)); +}); + +// A typed value keeps its identity through the assertion. +function bump(target: Out): void { + target.count++; +} +const typed: Out = { routes: [{ src: "/x" }], count: 1 }; +bump(typed as never); +console.log(typed.count); diff --git a/tests/corpus/6467-fromentries-record-assertion.ts b/tests/corpus/6467-fromentries-record-assertion.ts new file mode 100644 index 000000000..1496292b3 --- /dev/null +++ b/tests/corpus/6467-fromentries-record-assertion.ts @@ -0,0 +1,29 @@ +// `Object.fromEntries(...) as T` for a declared record T keeps exactly +// the keys the entries created, in their order, as Node keeps the object +// itself. +type Tags = { "error.type": string; "error.msg": string; "error.cause"?: string }; + +function scrub(input: string): string { + return input.replace(/secret/g, "***"); +} + +function redact(tags: Tags): Tags { + return Object.fromEntries( + Object.entries(tags).map(([key, value]) => [key, typeof value === "string" ? scrub(value) : value]), + ) as Tags; +} + +const e = new Error("a secret here"); +const plain = redact({ "error.type": e.name, "error.msg": e.message }); +console.log(plain, Object.keys(plain), "error.cause" in plain, plain["error.msg"].length); +const caused = redact({ "error.type": "TypeError", "error.msg": "m", "error.cause": "secret cause" }); +console.log(caused, JSON.stringify(caused)); + +// Keys the record does not declare stay with the object. +type Point = { x: number; y: number }; +const p = Object.fromEntries([ + ["y", 2], + ["x", 1], + ["z", 3], +]) as Point; +console.log(p, p.x + p.y, Object.keys(p), JSON.stringify(p)); From 7d1d440b7b25c56bbec94a5ba57ab5342ded9088 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 21:05:53 -0700 Subject: [PATCH 13/39] Adapt method overrides across ABI differences, write Error codes, and close wrapper-reachable gaps Overrides whose parameters widen and whose results convert into the inherited ones keep the inherited slot, which converts around the override's own body; Error values take code writes, `in` tests and Object.assign; and a few gaps behind generic wrappers close: - Method overrides: each inherited argument converts into the override's parameter (equal, wider, or a checked extraction from an `any` slot) and the override's result converts into the inherited one (narrower, a convertible union, a widening Promise payload, anything convertible over an `any` base). The slot %C.m keeps the inherited ABI and forwards to %C.m$own; TypeScript callers typed with the subclass call $own directly when nothing overrides below. Async overrides of sync and async bases, and JavaScript overrides of builtin or TypeScript bases (zod's ZodError.toString) are included; a toString slot converts its result with ToString. - `err.code = value` on Error values in TypeScript: strings set the runtime code slot (and the error's checked-dynamic node, if any); other values clear it and keep the dynamic own property. - `'key' in err` with any receiver: declared members answer true; otherwise a class test over the declaring subclasses, a runtime lookup of the error's own properties, or an Object.prototype member. - `Object.assign(err, ...sources)` onto an Error target copies onto the error, re-reads name, message, stack, cause and code into the typed slots, and returns the error. - `Error & { ... }` intersections whose extra members have checkable types are Error values; those members read and write the error's own properties, each read checked at its declared type. - Catch bindings typed `any` read as checked-dynamic values (member reads and writes, assertions); a multi-statement type guard with an `unknown` parameter takes the caught value as an ordinary argument; Error members of a binding narrowed to an Error-extending interface read through the same value. - Lambda parameters typed `any` by their default are checked-dynamic slots; forwarded-only rest tuples with optional positions forward their slots; `value as never` from an untyped value into a typed parameter takes the checked extraction to the parameter's type. - Lexical `this` stops at generic instance frames, so an instance no longer sees the receiver of the caller that triggered it. The fence for `this` captured through a plain function now points at the `this` keyword. Co-Authored-By: Claude Opus 5.5 --- .../compiler/src/backend/llvm/lib-shared.ts | 4 + .../src/frontend/lowering/builtins/errors.ts | 41 ++++ .../src/frontend/lowering/function-context.ts | 15 +- .../frontend/lowering/generic-functions.ts | 2 + .../src/frontend/lowering/lower-calls.ts | 91 ++++++++ .../src/frontend/lowering/lower-classes.ts | 202 +++++++++++++++++- .../src/frontend/lowering/lower-exprs.ts | 122 ++++++++--- .../src/frontend/lowering/lower-stmts.ts | 34 +++ .../compiler/src/frontend/lowering/lowerer.ts | 101 +++++++-- .../src/frontend/lowering/typed-arguments.ts | 4 +- packages/compiler/src/frontend/type-mapper.ts | 45 +++- packages/compiler/src/ir/builtin-effects.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 16 ++ packages/compiler/src/ir/validate.ts | 4 + .../corpus/6400-override-any-base.ts.json | 6 + .../6401-override-param-variance.ts.json | 6 + .../corpus/6402-override-js-base/main.ts.json | 7 + .../corpus/6403-error-code-write.ts.json | 6 + .../corpus/6404-error-in-and-assign.ts.json | 6 + .../6405-wrapped-default-parameters.ts.json | 6 + .../6406-npm-instance-receiver/main.ts.json | 6 + .../main.ts.json | 7 + .../6408-override-js-async-base/main.ts.json | 7 + .../corpus/6409-catch-binding-shapes.ts.json | 6 + packages/runtime/src/scr_error.h | 14 ++ packages/runtime/src/scr_json.c | 64 ++++++ tests/corpus/6400-override-any-base.ts | 35 +++ tests/corpus/6401-override-param-variance.ts | 33 +++ tests/corpus/6402-override-js-base/main.ts | 26 +++ tests/corpus/6402-override-js-base/pool.js | 17 ++ tests/corpus/6403-error-code-write.ts | 39 ++++ tests/corpus/6404-error-in-and-assign.ts | 105 +++++++++ .../corpus/6405-wrapped-default-parameters.ts | 67 ++++++ .../corpus/6406-npm-instance-receiver/main.ts | 7 + .../node_modules/corked-writer/index.d.ts | 4 + .../node_modules/corked-writer/index.js | 45 ++++ .../node_modules/corked-writer/package.json | 1 + .../6407-js-error-tostring-override/errors.js | 22 ++ .../6407-js-error-tostring-override/main.ts | 9 + .../6408-override-js-async-base/lock.js | 22 ++ .../6408-override-js-async-base/main.ts | 30 +++ tests/corpus/6409-catch-binding-shapes.ts | 69 ++++++ 42 files changed, 1296 insertions(+), 58 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6400-override-any-base.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6401-override-param-variance.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6402-override-js-base/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6403-error-code-write.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6404-error-in-and-assign.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6405-wrapped-default-parameters.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6406-npm-instance-receiver/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6407-js-error-tostring-override/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6408-override-js-async-base/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6409-catch-binding-shapes.ts.json create mode 100644 tests/corpus/6400-override-any-base.ts create mode 100644 tests/corpus/6401-override-param-variance.ts create mode 100644 tests/corpus/6402-override-js-base/main.ts create mode 100644 tests/corpus/6402-override-js-base/pool.js create mode 100644 tests/corpus/6403-error-code-write.ts create mode 100644 tests/corpus/6404-error-in-and-assign.ts create mode 100644 tests/corpus/6405-wrapped-default-parameters.ts create mode 100644 tests/corpus/6406-npm-instance-receiver/main.ts create mode 100644 tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/index.d.ts create mode 100644 tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/index.js create mode 100644 tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/package.json create mode 100644 tests/corpus/6407-js-error-tostring-override/errors.js create mode 100644 tests/corpus/6407-js-error-tostring-override/main.ts create mode 100644 tests/corpus/6408-override-js-async-base/lock.js create mode 100644 tests/corpus/6408-override-js-async-base/main.ts create mode 100644 tests/corpus/6409-catch-binding-shapes.ts diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 8ab89bd22..46dff20e1 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -125,6 +125,10 @@ export const LIB_FN_SYMS: Record = { "str.encodeUriComponent": "scr_str_encode_uri_component", "error.cause": "scr_error_cause", "error.setCause": "scr_error_set_cause", + "error.setCode": "scr_error_set_code_value", + "error.setCodeDyn": "scr_error_set_code_dyn", + "error.assign": "scr_error_assign_dyn", + "error.hasKey": "scr_error_has_key", "error.defineCause": "scr_error_define_cause", "error.deleteCause": "scr_error_delete_cause", "error.hasCause": "scr_error_has_cause", diff --git a/packages/compiler/src/frontend/lowering/builtins/errors.ts b/packages/compiler/src/frontend/lowering/builtins/errors.ts index 1572aa6ab..ad0b044b9 100644 --- a/packages/compiler/src/frontend/lowering/builtins/errors.ts +++ b/packages/compiler/src/frontend/lowering/builtins/errors.ts @@ -43,6 +43,20 @@ export function refuseExecExceptionCode(lowerer: Lowerer, node: ts.Node): never * declaration is not stdlib). Reads only: writes keep their fence (no * compiled program constructs an errno error). Null for non-error * receivers and non-stdlib members, so the chain keeps trying. */ +/** Error members with slots of their own: never read through the dynamic + * node, even when an intersection restates them. */ +const ERROR_SLOT_MEMBERS = new Set([ + "code", + "cause", + "stack", + "message", + "name", + "errno", + "syscall", + "path", + "dest", +]); + export function lowerErrorCodeProperty( lowerer: Lowerer, expr: ts.PropertyAccessExpression, @@ -126,6 +140,33 @@ export function lowerErrorCodeProperty( declared, ); } + // A member an `Error & { ... }` intersection adds beyond Error's own and + // the system-error metadata (`Object.assign(new Error(m), { status })`): + // an own property of the error's checked-dynamic node, read at the + // declared type (the intersection mapping admits only checkable types). + if ( + recvT.className === "%Error" && + !ERROR_SLOT_MEMBERS.has(expr.name.text) && + !expr.questionDotToken && + !lowerer.isStdlibMember(expr) && + lowerer.typeOf(expr.expression).isIntersectionType() + ) { + const declared = lowerer.mapTypeOf(lowerer.typeOf(expr)); + if (declared && declared.kind !== "void") { + const receiver = lowerer.lowerExpr(expr.expression); + const loc = locOf(expr); + return lowerer.coerceToExpected( + { + kind: "dynKeyGet", + value: lowerer.coerceToExpected(receiver, DYN), + key: { kind: "strLit", value: expr.name.text, type: STRING, loc }, + type: DYN, + loc, + }, + declared, + ); + } + } const systemField = ["errno", "syscall", "path", "dest"].includes(expr.name.text); if ( !systemField && diff --git a/packages/compiler/src/frontend/lowering/function-context.ts b/packages/compiler/src/frontend/lowering/function-context.ts index 55d8ed0b0..92042b7d7 100644 --- a/packages/compiler/src/frontend/lowering/function-context.ts +++ b/packages/compiler/src/frontend/lowering/function-context.ts @@ -48,6 +48,10 @@ export interface FnCtx { argumentsLocal?: IrLocal | null; /** Arrows inherit the nearest ordinary function's arguments binding. */ inheritsArguments?: boolean; + /** A function lowered on demand on top of an unrelated caller's frames + * (a generic instance): lexical `this` resolution stops here, so the + * body sees what it sees when lowered alone. */ + thisBoundary?: true; /** Tuple bindings of this function that are only forwarded * (typed-arguments.ts onlyForwarded): binding local id → the native * slots forwarding reads. Such a binding is never materialized. Local ids @@ -161,7 +165,16 @@ export function captureContextBinding( throw new InternalCompilerError("lowerer bug: no active function context"); const direct = bindingInContext(current, symbol); if (direct !== null) return { local: direct, origin: direct, error: null }; - for (let depth = stack.length - 2; depth >= 0; depth--) { + let floor = 0; + if (symbol === undefined) { + for (let depth = stack.length - 1; depth >= 0; depth--) { + if (stack[depth]!.thisBoundary) { + floor = depth; + break; + } + } + } + for (let depth = stack.length - 2; depth >= floor; depth--) { const origin = bindingInContext(stack[depth]!, symbol); if (origin === null) continue; diff --git a/packages/compiler/src/frontend/lowering/generic-functions.ts b/packages/compiler/src/frontend/lowering/generic-functions.ts index ac611a7df..824880bd8 100644 --- a/packages/compiler/src/frontend/lowering/generic-functions.ts +++ b/packages/compiler/src/frontend/lowering/generic-functions.ts @@ -905,6 +905,8 @@ export function lowerGenericInstance( : lowerer.bodyReturnType(isAsync, inst.returnType); const fnCtx = newFnCtx(false, null, null, bodyReturn); fnCtx.isAsync = isAsync; + // Instances lower on demand, on top of whichever caller reached them. + fnCtx.thisBoundary = true; // Implicit-any instances whose declared return did not map lower in // return-INFERENCE mode: `return` statements record here bare, and the // post-pass (resolveInferredReturn) settles the type and wraps them. diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 23629a7ba..f9abf2d19 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -4285,6 +4285,14 @@ function lowerCaughtPredicateCall( const paramSymbol = lowerer.checker.getSymbolAtLocation(param.name); if (!paramSymbol) return null; const ret = decl.body.statements.nodes.length === 1 ? decl.body.statements.nodes[0] : undefined; + // A longer guard whose parameter is `unknown` (or `any`) takes the caught + // value as an ordinary checked-dynamic argument: the call path converts + // the binding, and the narrowed binding reads through the same value. + if ( + (!ret || !ts.isReturnStatement(ret) || !ret.expression) && + lowerer.mapTypeOf(lowerer.checker.getTypeOfSymbol(paramSymbol))?.kind === "dyn" + ) + return null; if (!ret || !ts.isReturnStatement(ret) || !ret.expression) { lowerer.unsupported( "SC1090", @@ -7258,6 +7266,8 @@ function lowerObjectStaticCall( }; } } + const onError = lowerObjectAssignOntoError(lowerer, call); + if (onError) return onError; const hybrid = lowerObjectAssignHybrid(lowerer, call); if (hybrid) return hybrid; // `Object.assign({}, lit)` — an EMPTY fresh-literal target and one @@ -9388,6 +9398,30 @@ export function lowerObjectMethodCall( `calls of the abstract method '${method}' with no concrete implementation below the receiver's static class`, ); } + // The static receiver's nearest declaration is an override adapted to + // the inherited ABI, and nothing below overrides it: call its body + // directly under its declared signature (exact parameters and result). + // The slot function stays reachable; it lifts the body. + const adapted = found.declarer.returnAdapters?.get(method); + // A TypeScript override's own entry answers its declared result. A + // JavaScript body's result is inferred, so its callers keep the slot. + const declarerDecl = found.declarer.decl; + if ( + adapted && + !(declarerDecl && isJsSourceFile(declarerDecl.getSourceFile())) && + !lowerer.overrideBelow(info, method) + ) { + lowerer.noteEdge(`%${found.declarer.def.name}.${method}`); + const receiver = lowerReceiver(); + const args = lowerer.completeArgs(call.arguments.nodes, adapted.params, locOf(call), call); + return { + kind: "call", + callee: `%${found.declarer.def.name}.${method}$own`, + args: [lowerer.upcastTo(receiver, found.declarer.def.name), ...args], + type: adapted.ret, + loc: locOf(call), + }; + } if (lowerer.overrideBelow(info, method)) lowerer.noteVirtualEdge(info, method); else lowerer.noteEdge(`%${found.declarer.def.name}.${method}`); const receiver = lowerReceiver(); @@ -9945,3 +9979,60 @@ function maybePromiseHandlerResult( } return stmt; } + +/** `Object.assign(err, ...sources)` in TypeScript onto an error-hierarchy + * target (`Object.assign(new Error(message), details)`): the sources' + * own members land on the error — the runtime copy over its + * checked-dynamic node, whose name, message, stack, cause and code feed + * back into the typed slots — and the call answers the error itself. + * Null for every other target. */ +function lowerObjectAssignOntoError(lowerer: Lowerer, call: ts.CallExpression): IrExpr | null { + const argNodes = call.arguments.nodes; + if ( + isJsSourceFile(call.getSourceFile()) || + argNodes.length < 2 || + argNodes.some((a) => ts.isSpreadElement(a)) + ) + return null; + const probe = tryLowerExpression(lowerer, argNodes[0]!); + if (probe?.type.kind !== "object" || !lowerer.isErrorRootedClass(probe.type.className)) + return null; + const loc = locOf(call); + const target = lowerer.lowerExpr(argNodes[0]!); + const slot = lowerer.declareHiddenLocal("%assignErr", target.type); + const sources: IrExpr[] = []; + for (const node of argNodes.slice(1)) { + const raw = lowerer.lowerExpr(node); + fenceSymbolFieldCopy(lowerer, node, raw.type); + const source = lowerer.coerceToExpected(raw, DYN); + if (source.type.kind !== "dyn") { + lowerer.unsupported( + "SC1090", + node, + `Object.assign onto an Error from a '${lowerer.fmt(raw.type)}' source (sources enter the error's dynamic properties)`, + ); + } + sources.push(source); + } + const ref = (): IrExpr => ({ kind: "varRef", localId: slot.id, type: target.type, loc }); + return { + kind: "seqExpr", + stmts: [ + { kind: "varDecl", localId: slot.id, init: target, loc }, + { + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "error.assign", + args: [ref(), { kind: "dynArrLit", elems: sources, type: DYN, loc }], + type: VOID, + loc, + }, + loc, + }, + ], + result: ref(), + type: target.type, + loc, + }; +} diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 770c74840..14c8d1806 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -23,6 +23,7 @@ import type { FnCtx, Lowerer } from "./lowerer.js"; import { inlineNamespaceRequireOf, lowerWithInlineRequireInit } from "./cjs-inline-require.js"; import { BOOL, + canDynCheckTo, DATE_T, DYN, F64, @@ -462,6 +463,12 @@ export interface ClassInfo { /** Own JS overrides whose signature cannot use the inherited ABI. The slot * retains that ABI, but its implementation throws before executing. */ methodEntryFences?: Map; + /** Own TypeScript overrides whose declared result differs from the + * inherited ABI's but converts into it (`Promise` over `any`, a + * union narrowed to its inherited arm): the slot function `%C.m` keeps the + * inherited ABI and converts the result of the body, which lowers as + * `%C.m$own` with the declared result (async when declared so). */ + returnAdapters?: Map; /** OWN GENERIC instance methods (own type parameters — `m(x: T)`), * monomorphized per call site like top-level generic functions: instance * `n` is the module function `%C.m%n` taking `this` as param 0. They @@ -2225,6 +2232,7 @@ export function collectClassShapeInner( } >(); const methodEntryFences = new Map(); + const returnAdapters = new Map(); // Own accessor declarations ("get:x"/"set:x" → node), for the // partial-override analysis below (diagnostics need the node). const accessorNodes = new Map(); @@ -3360,7 +3368,67 @@ export function collectClassShapeInner( overridden.declarer.decl !== null && isJsSourceFile(overridden.declarer.decl.getSourceFile()) && overridden.sig.gen === undefined; - if (fencedJsOverride) { + // A TypeScript override that only changes the result, into a + // type that converts into the inherited one (`Promise` over + // an `any` base, `string | undefined` over `string`): the slot + // keeps the inherited ABI and converts the body's result at the + // boundary (lowerClassMethodMemberInner). + const ownAsync = + member.modifiers?.nodes.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) === true; + if ( + !fencedJsOverride && + !functionLocalClass(decl) && + overridden.sig.gen === undefined && + // An async base's slot answers its promise: a Promise type, or + // the checked-dynamic value of an untyped async method. + (overridden.sig.async !== true || + overridden.sig.ret.kind === "promise" || + overridden.sig.ret.kind === "dyn") && + !overridden.sig.abstract && + overridden.sig.params.length === shapes.length && + overridden.sig.params.every( + (p, i) => + p.mode === shapes[i]!.mode && + (p.mode === "required" || p.mode === "omittable") && + // Each inherited argument converts into the override's + // parameter: equal, a checked extraction from an `any` + // slot, or a widening (a contravariant parameter). + (typeEquals(p.type, shapes[i]!.type) || + (p.type.kind === "dyn" && + canDynCheckTo( + shapes[i]!.type, + (id) => lowerer.shapes.get(id), + (id) => lowerer.unions.get(id), + )) || + lowerer.coercibleValue(p.type, shapes[i]!.type)), + ) && + (ownAsync ? ft.ret.kind === "promise" : true) && + (typeEquals(ft.ret, overridden.sig.ret) || + (overridden.sig.ret.kind === "dyn" + ? ft.ret.kind !== "void" && lowerer.dynConvertible(ft.ret) + : lowerer.coercibleValue(ft.ret, overridden.sig.ret) || + // A promise whose payload widens into the inherited one + // (`Promise` over an untyped async `Promise`). + (ft.ret.kind === "promise" && + overridden.sig.ret.kind === "promise" && + lowerer.promisePayloadWidens(ft.ret, overridden.sig.ret)) || + // A JavaScript override's inferred `any` result checks + // into the inherited type (`toString() { return + // this.message }` over Error's). + (ft.ret.kind === "dyn" && + isJsSourceFile(member.getSourceFile()) && + overridden.sig.ret.kind !== "void" && + canDynCheckTo( + overridden.sig.ret, + (id) => lowerer.shapes.get(id), + (id) => lowerer.unions.get(id), + )))) + ) { + returnAdapters.set(mName, { params: [...shapes], ret: ft.ret, async: ownAsync }); + shapes.splice(0, shapes.length, ...overridden.sig.params); + ft.ret = overridden.sig.ret; + if (overridden.sig.async === true) thunkAsyncSlot(overridden, mName); + } else if (fencedJsOverride) { // A dormant JS method must not poison the whole class. Keep // the inherited call/dispatch ABI and refuse at method entry; // lowering this body with the base signature would change JS. @@ -3415,7 +3483,34 @@ export function collectClassShapeInner( // fiber spawn wrapper; vtable slots hold raw implementations) — // an override chain touching an async method on either end would // put a spawn wrapper behind a virtual slot, so it fences. - if (overridden && (asyncMember || overridden.sig.async === true)) { + // An override chain touching async methods dispatches through + // plain slot functions that return the body's promise: the async + // bodies lower as `%C.m$own` behind them (thunkAsyncSlot). + if ( + overridden && + !returnAdapters.has(mName) && + (asyncMember || overridden.sig.async === true) && + !isJsSourceFile(member.getSourceFile()) && + !functionLocalClass(decl) && + member.asteriskToken === undefined && + overridden.sig.gen === undefined && + !overridden.sig.abstract && + ft.ret.kind === "promise" && + typeEquals(ft.ret, overridden.sig.ret) && + overridden.sig.params.length === shapes.length && + overridden.sig.params.every( + (p, i) => typeEquals(p.type, shapes[i]!.type) && p.mode === shapes[i]!.mode, + ) + ) { + if (overridden.sig.async === true) thunkAsyncSlot(overridden, mName); + if (asyncMember) + returnAdapters.set(mName, { params: [...shapes], ret: ft.ret, async: true }); + } + if ( + overridden && + !returnAdapters.has(mName) && + (asyncMember || overridden.sig.async === true) + ) { const message = `overriding ${overridden.sig.async === true ? "the async method" : "a method with an async method"} '${mName}' (async methods dispatch statically — the vtable slot machinery has no fiber-spawn story)`; if (isJsSourceFile(member.getSourceFile())) methodEntryFences.set(mName, unsupportedDiag("SC1090", locOf(member.name), message)); @@ -3446,7 +3541,7 @@ export function collectClassShapeInner( } else { methods.set( mName, - asyncMember + asyncMember && !returnAdapters.has(mName) ? { params: shapes, ret: ft.ret, async: true as const } : { params: shapes, ret: ft.ret }, ); @@ -4166,6 +4261,7 @@ export function collectClassShapeInner( fieldOrder, methods, ...(methodEntryFences.size > 0 ? { methodEntryFences } : {}), + ...(returnAdapters.size > 0 ? { returnAdapters } : {}), decl, ...(emitOverride !== undefined ? { emitOverride } : {}), ctor, @@ -6474,6 +6570,28 @@ function abstractMemberSignature( /** A nominal return subtype uses the same owned pointer as the inherited * return slot. The current class is still being collected, so consult its * already collected base chain before the complete class graph is available. */ +/** An inherited ASYNC method that an override now dispatches against: its + * slot becomes a plain function returning the body's promise, and the + * async body lowers behind it as `%C.m$own` (the adapter path with an + * identity conversion), so a virtual call never enters an async body + * without its spawn wrapper. */ +function thunkAsyncSlot( + overridden: { declarer: ClassInfo; sig: ClassMethodSignature }, + mName: string, +): void { + if (overridden.sig.async !== true) return; + const declarer = overridden.declarer; + declarer.returnAdapters ??= new Map(); + if (!declarer.returnAdapters.has(mName)) { + declarer.returnAdapters.set(mName, { + params: [...overridden.sig.params], + ret: overridden.sig.ret, + async: true, + }); + } + delete overridden.sig.async; +} + function overrideReturnAbi( lowerer: Lowerer, declared: IrType, @@ -7672,6 +7790,82 @@ function lowerClassMethodMemberInner( allowDiagSink: true, }); } + // An override converting its declared result into the inherited ABI: + // the body lowers as `%C.m$own` under its declared result, and the slot + // function forwards to it and converts what it returns. + const adapter = info.returnAdapters?.get(mName); + if (adapter) { + const ownSig: ClassMethodSignature = { ...sig, params: adapter.params, ret: adapter.ret }; + if (adapter.async) ownSig.async = true; + const own = lowerClassMethodBody(lowerer, info, fnLike, `%${className}.${mName}$own`, ownSig); + if (!own) return null; + lowerer.liftedFns.push(own); + const loc = locOf(fnLike); + const params: IrParam[] = [ + { localId: "this.0", name: "this", type: thisType }, + ...sig.params.map((p, i) => ({ localId: `p.${i}`, name: `p${i}`, type: p.type })), + ]; + const fnCtx = newFnCtx(false, null, null, sig.ret); + lowerer.fnStack.push(fnCtx); + try { + const call: IrExpr = { + kind: "call", + callee: own.name, + args: params.map((p, i): IrExpr => { + const ref: IrExpr = { kind: "varRef", localId: p.localId, type: p.type, loc }; + // `this` passes through; each inherited argument converts into + // the override's declared parameter (checked where it narrows). + return i === 0 ? ref : lowerer.coerceInto(fnLike.name, ref, adapter.params[i - 1]!.type); + }), + type: adapter.ret, + loc, + }; + // A void slot discards the override's result after running it. A + // toString slot hands on what every ToString consumer of the result + // makes of it (`String(err)`, templates): undefined reads + // "undefined", as in Node. Other slots check the result into the + // inherited type. + const result = (): IrExpr => + mName === "toString" && sig.ret.kind === "string" + ? call.type.kind === "dyn" + ? { kind: "libCall", fn: "dyn.stringConstructor", args: [call], type: STRING, loc } + : lowerer.ensureString(call, fnLike.name) + : lowerer.coerceInto(fnLike.name, call, sig.ret); + const body: IrStmt[] = + sig.ret.kind === "void" + ? [ + { kind: "exprStmt", expr: call, loc }, + { kind: "return", value: null, loc }, + ] + : [{ kind: "return", value: result(), loc }]; + return { + name: `%${className}.${mName}`, + params, + returnType: sig.ret, + locals: [ + ...params.map((p) => ({ id: p.localId, name: p.name, type: p.type, mutable: false })), + ...lowerer.ctx.locals, + ], + body, + loc, + }; + } finally { + lowerer.fnStack.pop(); + } + } + return lowerClassMethodBody(lowerer, info, fnLike, `%${className}.${mName}`, sig); +} + +function lowerClassMethodBody( + lowerer: Lowerer, + info: ClassInfo, + fnLike: ts.MethodDeclaration | ts.AccessorDeclaration, + fnName: string, + sig: ClassMethodSignature, +): IrFunction | null { + const className = info.def.name; + const thisType: IrType = { kind: "object", className }; + if (!fnLike.body) return null; const prevClass = lowerer.currentClass; lowerer.currentClass = info; // ASYNC methods: the module function is an async IrFunction — its @@ -7713,7 +7907,7 @@ function lowerClassMethodMemberInner( const body = [...declared.prologue, ...lowerer.lowerStmts(fnLike.body.statements.nodes)]; appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(fnLike)); const fn: IrFunction = { - name: `%${className}.${mName}`, + name: fnName, params, returnType: bodyReturn, locals: lowerer.ctx.locals, diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index aa597d8a2..8b02597ab 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -1724,7 +1724,7 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { // Only arrows can see an enclosing method's `this` (JS lexical-this); // `this` in plain nested functions is already a tsc error under // noImplicitThis, so the generic scope walk here is preflight-safe. - const local = lowerer.resolveThis(); + const local = lowerer.resolveThis(expr); if (local) { const value: IrExpr = { kind: "varRef", localId: local.id, type: local.type, loc }; const initialized = lowerer.ctx.superInitialized; @@ -2768,6 +2768,25 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { ); } } + // A stdlib-declared member (`message` of an interface extending Error) + // on a catch binding narrowed to a structural type: the binding reads + // as its checked-dynamic value, so the member does too. + if (!expr.questionDotToken && lowerer.caughtLocalOf(expr.expression)) { + const recv = lowerer.lowerExpr(expr.expression); + if (recv.kind === "caughtToDyn") { + const read: IrExpr = { + kind: "dynKeyGet", + key: { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) }, + value: recv, + type: DYN, + loc, + }; + const declared = lowerer.mapTypeOf(lowerer.typeOf(expr)); + return declared && declared.kind !== "void" + ? lowerer.coerceToExpected(read, declared) + : read; + } + } // The lib fence's PROPERTY chokepoint: a stdlib-declared member that // no lowering above claimed ([1,2].entries, Math.SQRT2, Promise.all, // re.exec as a value, ...) reports SC2020 here. @@ -9433,12 +9452,14 @@ export function lowerAsExpression( // the requested shape; an assertion does not bypass runtime checks. const narrowed = lowerer.mapTypeOf(lowerer.typeOf(expr.expression)); const bridged = - narrowed && - (narrowed.kind === "f64" || - narrowed.kind === "bool" || - narrowed.kind === "string" || - narrowed.kind === "object" || - narrowed.kind === "dyn"); + (narrowed && + (narrowed.kind === "f64" || + narrowed.kind === "bool" || + narrowed.kind === "string" || + narrowed.kind === "object" || + narrowed.kind === "dyn")) || + // `catch (e: any)`: the binding reads as its checked-dynamic value. + (narrowed === null && (lowerer.typeOf(expr.expression).flags & ts.TypeFlags.Any) !== 0); if (!bridged) lowerer.unsupported("SC1063", expr); } const inner = lowerer.lowerExpr(expr.expression); @@ -12708,7 +12729,11 @@ export function caughtRead( // Unnarrowed reads cross into unknown. The caught-value dispatch pass // retains known native class payloads through live identity capsules; // other payload kinds use the runtime's ordinary conversion. - if (narrowed?.kind === "dyn") { + // `catch (e: any)` (or useUnknownInCatchVariables off) reads the same way. + if ( + narrowed?.kind === "dyn" || + (narrowed === null && (lowerer.typeOf(node).flags & ts.TypeFlags.Any) !== 0) + ) { return { kind: "caughtToDyn", value: ref, type: DYN, loc }; } // A binding a user type predicate (or an assertion) narrowed to a @@ -14030,41 +14055,68 @@ function lowerInExpression(lowerer: Lowerer, expr: ts.BinaryExpression, loc: Src loc, }; } - if ( - (key === "message" || key === "name") && - (recv.kind === "varRef" || recv.kind === "caughtNarrow") - ) { - return { kind: "boolLit", value: true, type: BOOL, loc }; - } - // Any other key: a member a program class declares. The receiver's - // runtime class is its static class or a descendant; the key is - // present exactly when that class (or an ancestor) declares it. - if (recv.kind === "varRef" || recv.kind === "caughtNarrow") { - const declares = (c: ClassInfo): boolean => - c.fields.has(key) || - lowerer.findMethodOn(c, key) !== null || - lowerer.findMethodOn(c, `get:${key}`) !== null || - lowerer.findMethodOn(c, `set:${key}`) !== null; - const staticName = recv.type.className; - const staticInfo = lowerer.classes.get(staticName); - if (staticInfo && declares(staticInfo)) - return { kind: "boolLit", value: true, type: BOOL, loc }; + // The receiver evaluates for its effects when the answer is static. + const always = (): IrExpr => + recv.kind === "varRef" || recv.kind === "caughtNarrow" + ? { kind: "boolLit", value: true, type: BOOL, loc } + : { + kind: "seqExpr", + stmts: [{ kind: "exprStmt", expr: recv, loc }], + result: { kind: "boolLit", value: true, type: BOOL, loc }, + type: BOOL, + loc, + }; + if (key === "message" || key === "name") return always(); + // A member the static class declares is always present. + const declares = (c: ClassInfo): boolean => + c.fields.has(key) || + lowerer.findMethodOn(c, key) !== null || + lowerer.findMethodOn(c, `get:${key}`) !== null || + lowerer.findMethodOn(c, `set:${key}`) !== null; + const staticInfo = lowerer.classes.get(recv.type.className); + if (staticInfo && declares(staticInfo)) return always(); + // Any other key: a descendant class that declares it (instanceof), + // an own property set at runtime (a throw site's extra fields, + // Object.assign, writes through a dynamic view), or an + // Object.prototype member. `stack` stays fenced: Node has one, a + // compiled error has none. + if (key !== "stack") { + const stable = recv.kind === "varRef" || recv.kind === "caughtNarrow"; + const slot = stable ? null : lowerer.declareHiddenLocal("%inRecv", recv.type); + const ref = (): IrExpr => (slot ? varRef(slot.id, recv.type, loc) : recv); const tests: IrExpr[] = []; + const staticName = recv.type.className; for (const c of lowerer.classes.values()) { const name = c.def.name; if (name === staticName || !lowerer.isSubclassOf(name, staticName) || !declares(c)) continue; // A declaring ancestor below the static class already covers it. if (c.base && c.base.def.name !== staticName && declares(c.base)) continue; - tests.push({ kind: "instanceOf", value: recv, className: name, type: BOOL, loc }); + tests.push({ kind: "instanceOf", value: ref(), className: name, type: BOOL, loc }); } - return tests.reduce( - (acc, test) => - acc.kind === "boolLit" - ? test - : { kind: "logical", op: "||", left: acc, right: test, type: BOOL, loc }, - { kind: "boolLit", value: false, type: BOOL, loc }, - ); + tests.push({ + kind: "libCall", + fn: "error.hasKey", + args: [ref(), { kind: "strLit", value: key, type: STRING, loc }], + type: BOOL, + loc, + }); + const answer = tests.reduce((acc, test) => ({ + kind: "logical", + op: "||", + left: acc, + right: test, + type: BOOL, + loc, + })); + if (!slot) return answer; + return { + kind: "seqExpr", + stmts: [{ kind: "varDecl", localId: slot.id, init: recv, loc }], + result: answer, + type: BOOL, + loc, + }; } lowerer.unsupported( "SC1090", diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 3af47f614..eb0d31cbd 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -7124,6 +7124,34 @@ export function lowerExprStatement(lowerer: Lowerer, expr: ts.Expression): IrStm loc, }; } + // `err.code = v` on an Error value (`err as Error & { code?: + // string }`): typed reads come from the runtime error's code + // slot, so the write lands there. A value that is not statically + // a string checks at runtime: strings take the slot, anything + // else clears it and stays a dynamic own property. The + // system-error members (errno, syscall, path, dest) read + // through the checked-dynamic node and keep the dynamic write, as + // do JavaScript files, whose reads use that node too. + if ( + !isJsSourceFile(expr.getSourceFile()) && + recv?.type.kind === "object" && + lowerer.isErrorRootedClass(recv.type.className) && + expr.left.name.text === "code" + ) { + const loc = locOf(expr); + const stringValue = isStringTyped(lowerer.typeOf(expr.right)); + return { + kind: "exprStmt", + expr: { + kind: "libCall", + fn: stringValue ? "error.setCode" : "error.setCodeDyn", + args: [recv, lowerer.lowerExprExpecting(expr.right, stringValue ? STRING : DYN)], + type: VOID, + loc, + }, + loc, + }; + } if (recv?.type.kind === "object" && recv.type.className === "%Error") { const loc = locOf(expr); return { @@ -10815,3 +10843,9 @@ export function lowerForStatement(lowerer: Lowerer, stmt: ts.ForStatement): IrSt lowerer.scopes.pop(); } } + +/** A checker type that is a string or string literal (or a union of them). */ +function isStringTyped(t: ts.Type): boolean { + if (t.isUnionType()) return ts.constituentTypes(t).every(isStringTyped); + return (t.flags & (ts.TypeFlags.String | ts.TypeFlags.StringLiteral)) !== 0; +} diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 8913b9eeb..6bc661c4c 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -9512,6 +9512,8 @@ export class Lowerer { node = node.expression; if (expected) { if (ts.isConditionalExpression(node)) return lowerTernary(this, node, expected); + const escaped = this.neverAssertionInto(node, expected); + if (escaped) return escaped; const fresh = this.emptyCollectionFor(node, expected); if (fresh) return this.coerceInto(node, fresh, expected); } @@ -10408,6 +10410,14 @@ export class Lowerer { return findMethodOn(this, info, name); } + /** A class whose root is the runtime's %Error (builtin errors and their + * program subclasses). */ + isErrorRootedClass(className: string): boolean { + let info = this.classes.get(className) ?? null; + while (info && info.base) info = info.base; + return info?.def.name === "%Error"; + } + isSubclassOf(sub: string, sup: string): boolean { return isSubclassOf(this, sub, sup); } @@ -10706,24 +10716,30 @@ export class Lowerer { ): void { const loc = locOf(decl); const name = nameNode.text; - const tupleType = this.irTypeOf(nameNode); + const fn = decl.parent; + const symbol = this.checker.getSymbolAtLocation(nameNode); + const isRead = (id: ts.Identifier): boolean => + id !== nameNode && this.checker.getSymbolAtLocation(id) === symbol; + const pure = fn !== undefined && symbol !== undefined && onlyForwarded(this, fn, isRead); + // A forwarded-only tuple is never built: a tuple with optional + // positions (`Parameters<(n?: T) => R>`, whose length varies per call) + // forwards its slots, an omitted position as undefined — which a + // callee's default treats exactly as an omitted argument. Its length + // is the one read that would observe the difference. + const tupleType = + pure && + elemShapes.length > 0 && + this.mapTypeOf(this.typeOf(nameNode)) === null && + !readsLength(fn!, isRead) + ? this.forwardedSlotsTuple(elemShapes) + : this.irTypeOf(nameNode); const slots = elemShapes.map((shape, i) => { const slot = this.declareHiddenLocal(`%${name}.${i}`, shape.type); params.push({ localId: slot.id, name: `%${name}.${i}`, type: shape.type }); return slot; }); const body = this.declareLocal(nameNode, name, tupleType, true); - const fn = decl.parent; - const symbol = this.checker.getSymbolAtLocation(nameNode); - if ( - fn !== undefined && - symbol !== undefined && - onlyForwarded( - this, - fn, - (id) => id !== nameNode && this.checker.getSymbolAtLocation(id) === symbol, - ) - ) { + if (pure) { this.ctx.pureTuples.set(body.id, slots); return; } @@ -10731,6 +10747,38 @@ export class Lowerer { prologue.push({ kind: "varDecl", localId: body.id, init, loc }); } + /** `value as never` flowing into a typed slot: `never` is assignable to + * every type, so the assertion promises the slot's type. A dynamic value + * takes the checked extraction to it, as `value as T` would. Null for + * every other form, and for numeric, dynamic and union slots, which + * keep the existing lowering. */ + private neverAssertionInto(node: ts.Expression, expected: IrType): IrExpr | null { + if (!(ts.isAsExpression(node) || ts.isTypeAssertion(node))) return null; + if (expected.kind === "f64" || expected.kind === "dyn" || expected.kind === "union") + return null; + if (!(this.checker.getTypeFromTypeNode(node.type).flags & ts.TypeFlags.Never)) return null; + const innerTs = this.typeOf(node.expression); + if (!(innerTs.flags & ts.TypeFlags.Any) && this.mapTypeOf(innerTs)?.kind !== "dyn") return null; + if ( + !canDynCheckTo( + expected, + (id) => this.shapes.get(id), + (id) => this.unions.get(id), + ) + ) + return null; + const inner = this.lowerExpr(node.expression); + if (inner.type.kind !== "dyn") return null; + return { kind: "dynCheck", value: inner, type: expected, loc: locOf(node) }; + } + + /** The tuple record of a forwarded-only rest tuple's native slots. */ + private forwardedSlotsTuple(elemShapes: readonly ParamShape[]): IrType { + const fields = elemShapes.map((shape, i) => ({ name: String(i), type: shape.type })); + fields.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)); + return { kind: "record", shapeId: this.shapes.intern(fields, true) }; + } + /** A fresh tuple holding the given positional slots, typed `tupleType` * (a tuple record, or the empty-array form of `[]`). */ tupleOfSlots(slots: readonly IrLocal[], tupleType: IrType, blame: ts.Node, loc: SrcLoc): IrExpr { @@ -11157,8 +11205,8 @@ export class Lowerer { /** Lexical `this` — the enclosing method's this-param, possibly captured * through arrows (function expressions/declarations reset `this` in JS; * their bodies never see an enclosing method's binding). */ - resolveThis(): IrLocal | null { - return this.resolveKey(undefined); + resolveThis(blame?: ts.Node): IrLocal | null { + return this.resolveKey(undefined, blame); } peekLocal(ident: ts.Identifier): IrLocal | null { @@ -12980,3 +13028,28 @@ export class Lowerer { return lowerStdlibMethodCall(this, call, access); } } + +/** Whether some read of a binding (identified by `isRead`) in `fn` takes + * its `.length`. */ +function readsLength(fn: ts.Node, isRead: (id: ts.Identifier) => boolean): boolean { + let found = false; + ts.walkPreorder(fn, (n) => { + if (found) return "stop"; + if (!ts.isIdentifier(n) || !isRead(n)) return undefined; + let top: ts.Node = n; + while ( + top.parent && + (ts.isParenthesizedExpression(top.parent) || + ts.isAsExpression(top.parent) || + ts.isTypeAssertion(top.parent) || + ts.isSatisfiesExpression(top.parent) || + ts.isNonNullExpression(top.parent)) + ) + top = top.parent; + const p = top.parent; + if (p && ts.isPropertyAccessExpression(p) && p.expression === top && p.name.text === "length") + found = true; + return undefined; + }); + return found; +} diff --git a/packages/compiler/src/frontend/lowering/typed-arguments.ts b/packages/compiler/src/frontend/lowering/typed-arguments.ts index 82b7f23c3..0170e87b3 100644 --- a/packages/compiler/src/frontend/lowering/typed-arguments.ts +++ b/packages/compiler/src/frontend/lowering/typed-arguments.ts @@ -321,7 +321,9 @@ export function forwardedTupleType(lowerer: Lowerer, node: ts.Expression): IrTyp // Checker-only probe first: an ordinary array rest never maps here. restTupleElementTypes(lowerer.typeOf(operand), lowerer.typeCtx) !== null ) { - const t = lowerer.mapTypeOf(lowerer.typeOf(operand)); + // A tuple with optional positions has no value type of its own; its + // forwarded-only binding carries the slots' tuple (declareRestTupleParam). + const t = lowerer.mapTypeOf(lowerer.typeOf(operand)) ?? lowerer.peekLocal(operand)?.type; if (t && isTupleValueType(lowerer, t)) return t; } return null; diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 1e3954586..2d083d0cb 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -4373,7 +4373,9 @@ function mapCallSignature(sig: ts.Signature, ctx: TypeMapperCtx): IrType | null // A parameter a TypeScript program types `any` takes whatever the // caller passes: the checked-dynamic slot, as an `any`-typed binding // already is (dynFallbackType). Declaration files keep their paths. - // Only function declarations and spelled function types: lambdas and + // Only function declarations, spelled function types and lambda + // parameters whose default is the only source of their type (`(n = + // lookup() ?? 5) => ...` with an `any` lookup): other lambdas and // methods in object literals keep their existing checked-dynamic story. if ( !pt && @@ -4381,7 +4383,12 @@ function mapCallSignature(sig: ts.Signature, ctx: TypeMapperCtx): IrType | null decl !== undefined && ts.isParameter(decl) && decl.parent !== undefined && - (ts.isFunctionDeclaration(decl.parent) || ts.isFunctionTypeNode(decl.parent)) && + (ts.isFunctionDeclaration(decl.parent) || + ts.isFunctionTypeNode(decl.parent) || + ((ts.isArrowFunction(decl.parent) || ts.isFunctionExpression(decl.parent)) && + decl.initializer !== undefined && + decl.type === undefined && + !isJsSourceFile(decl.getSourceFile()))) && !decl.getSourceFile().isDeclarationFile && (checker.getTypeOfSymbol(p).flags & ts.TypeFlags.Any) !== 0 ) @@ -5748,6 +5755,7 @@ function mapErrorMetadataIntersection(type: ts.Type, ctx: TypeMapperCtx): IrType }); if (!hasError) return null; let error: IrType | null = null; + const extra: ts.Symbol[] = []; for (const part of parts) { const mapped = mapType(part, ctx); if (mapped?.kind === "object" && RUNTIME_ERROR_CLASSES.has(mapped.className)) { @@ -5768,14 +5776,45 @@ function mapErrorMetadataIntersection(type: ts.Type, ctx: TypeMapperCtx): IrType : ["code", "syscall", "path", "dest"].includes(property.name) ? "string" : null; - if (!expected || !(property.flags & ts.SymbolFlags.Optional)) return null; + if (!expected) { + extra.push(property); + continue; + } const field = mapType(ctx.checker.getTypeOfSymbol(property), ctx); const arms = field?.kind === "union" ? ctx.unions.get(field.unionId)?.arms : field ? [field] : []; if (!arms?.length || !arms.every((arm) => arm.kind === expected || arm.kind === "undefinedT")) return null; + // A required member must still admit the absent value the slot reads. + if ( + !(property.flags & ts.SymbolFlags.Optional) && + !arms.some((arm) => arm.kind === "undefinedT") + ) + return null; } } + if (!error) return null; + // Members beyond Error's own and the system-error metadata (`Error & { + // status: number }`, Object.assign's result) are own properties of the + // error's checked-dynamic node: each must map to a type a checked read + // can produce. Error's own string members keep their slots. + for (const property of extra) { + const field = mapType(ctx.checker.getTypeOfSymbol(property), ctx); + if (!field || field.kind === "void") return null; + if (property.name === "message" || property.name === "name") { + if (field.kind !== "string") return null; + continue; + } + if (property.name === "stack" || property.name === "cause") return null; + if ( + !canDynCheckTo( + field, + (id) => ctx.shapes.get(id), + (id) => ctx.unions.get(id), + ) + ) + return null; + } return error; } diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index f20d0945e..f2041a6aa 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -389,6 +389,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "error.stack", "error.cause", "error.setCause", + "error.assign", "error.deleteCause", "dyn.objectTag", // Numeric coercion runs user valueOf/toString — throws propagate. diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 02943ae1b..34f9da161 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -3101,6 +3101,22 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "error.hasCause": { argTypes: [null], result: BOOL }, /** Assignment borrows both operands and retains the new cause. */ "error.setCause": { argTypes: [null, DYN], result: VOID }, + /** `err.code = s` on an error-hierarchy receiver: the code slot that + * error.code reads and coded throws stamp. Borrows both; never throws. */ + "error.setCode": { argTypes: [null, STRING], result: VOID }, + /** `err.code = v` with a value that is not statically a string: strings + * take the code slot, anything else clears it and sets the dynamic own + * property. Borrows both; never throws. */ + "error.setCodeDyn": { argTypes: [null, DYN], result: VOID }, + /** `Object.assign(err, ...sources)` onto an error-hierarchy receiver + * (args: the error, a dyn array of the sources): the own-member copy + * onto its checked-dynamic node, then the typed slots (name, message, + * stack, cause, code) re-read from it. Throws what the copy throws. */ + "error.assign": { argTypes: [null, DYN], result: VOID }, + /** `key in err` for a key no compiled class of the receiver declares + * (args: the error, the key): a runtime-set own property (Object.assign, + * throw-site fields, dynamic writes) or an Object.prototype member. */ + "error.hasKey": { argTypes: [null, STRING], result: BOOL }, "error.defineCause": { argTypes: [null, DYN], result: VOID }, "error.deleteCause": { argTypes: [null], result: VOID }, /** The compiler-resolved Node-parity throw for always-throwing lowered diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index 5cf262e1f..0bbc948a0 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -4112,6 +4112,10 @@ function validateFunction( e.fn === "error.cause" || e.fn === "error.hasCause" || e.fn === "error.setCause" || + e.fn === "error.setCode" || + e.fn === "error.setCodeDyn" || + e.fn === "error.assign" || + e.fn === "error.hasKey" || e.fn === "error.defineCause" || e.fn === "error.deleteCause" ) { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6400-override-any-base.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6400-override-any-base.ts.json new file mode 100644 index 000000000..a885a5175 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6400-override-any-base.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6400-override-any-base.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6401-override-param-variance.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6401-override-param-variance.ts.json new file mode 100644 index 000000000..ee14b5af3 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6401-override-param-variance.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6401-override-param-variance.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6402-override-js-base/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6402-override-js-base/main.ts.json new file mode 100644 index 000000000..3ac1bf1fe --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6402-override-js-base/main.ts.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/6402-override-js-base/pool.js", + "/tests/corpus/6402-override-js-base/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6403-error-code-write.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6403-error-code-write.ts.json new file mode 100644 index 000000000..b673f7920 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6403-error-code-write.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6403-error-code-write.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6404-error-in-and-assign.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6404-error-in-and-assign.ts.json new file mode 100644 index 000000000..c880bc57b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6404-error-in-and-assign.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6404-error-in-and-assign.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6405-wrapped-default-parameters.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6405-wrapped-default-parameters.ts.json new file mode 100644 index 000000000..8be83f858 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6405-wrapped-default-parameters.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6405-wrapped-default-parameters.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6406-npm-instance-receiver/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6406-npm-instance-receiver/main.ts.json new file mode 100644 index 000000000..e651808f7 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6406-npm-instance-receiver/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6406-npm-instance-receiver/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6407-js-error-tostring-override/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6407-js-error-tostring-override/main.ts.json new file mode 100644 index 000000000..057a8a163 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6407-js-error-tostring-override/main.ts.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/6407-js-error-tostring-override/errors.js", + "/tests/corpus/6407-js-error-tostring-override/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6408-override-js-async-base/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6408-override-js-async-base/main.ts.json new file mode 100644 index 000000000..6acb919ed --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6408-override-js-async-base/main.ts.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/6408-override-js-async-base/lock.js", + "/tests/corpus/6408-override-js-async-base/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6409-catch-binding-shapes.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6409-catch-binding-shapes.ts.json new file mode 100644 index 000000000..57e3aeaf1 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6409-catch-binding-shapes.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6409-catch-binding-shapes.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_error.h b/packages/runtime/src/scr_error.h index ce60dac23..597361d59 100644 --- a/packages/runtime/src/scr_error.h +++ b/packages/runtime/src/scr_error.h @@ -279,6 +279,20 @@ SCR_COLD void scr_undef_global_read(ScrStr *name); * +1 or NULL when absent (the compiler's undefined arm). The _msg_code * thrower is scr_throw_error_msg with the code stamped on the payload. */ void scr_error_set_code(ScrError *e, const char *code); +/* The program's `err.code = s` write into the same slot (and the error's + * checked-dynamic node, when it has one). Borrows both (scr_json.c). */ +void scr_error_set_code_value(ScrError *e, ScrStr *code); +/* `err.code = v` with a value that is not statically a string: a string + * takes the slot as above; anything else clears the slot and lands on the + * error's checked-dynamic node, as a dynamic property write would. + * Borrows both (scr_json.c). */ +void scr_error_set_code_dyn(ScrError *e, struct ScrDyn *value); +/* Object.assign(err, ...sources): the copy onto the error's checked-dynamic + * node, then the typed slots re-read from it. Borrows both (scr_json.c). */ +void scr_error_assign_dyn(ScrError *e, const struct ScrDyn *sources); +/* `key in err` for a key no compiled class declares: a runtime-set own + * property or an Object.prototype member. Borrows both (scr_json.c). */ +bool scr_error_has_key(ScrError *e, const ScrStr *key); const char *scr_error_message_code(const ScrStr *msg); ScrStr *scr_error_code(ScrError *e); SCR_COLD void scr_throw_error_msg_code(int kind, const char *message, size_t len, const char *code); diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 6174913c0..56edcf049 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -14092,3 +14092,67 @@ ScrDyn *scr_dyn_iter_take(const ScrDyn *src, size_t n, const char *spell) { bool scr_dyn_iterates_by_protocol(const ScrDyn *value) { return scr_dyn_sync_generator(value); } + +/* The program's writes onto compiled errors (scr_error.h). Kept at the end + * of the file, after every function they call, so the rest of the unit + * emits in its existing order. */ + +/* `err.code = s` from the program (an Error asserted to carry `code`): + * the same slot every coded throw stamps, so reads and `'code' in err` + * observe the write. Borrows both. */ +void scr_error_set_code_value(ScrError *e, ScrStr *code) { + scr_str_release(e->code); + e->code = scr_str_retain(code); + /* An error that already crossed into the checked-dynamic tree renders + * and reads through that node, so the write lands there too. */ + ScrDyn *view = scr_errdyn_view_of(e); + if (view != NULL && view->kind == SCR_DYN_OBJ) scr_dyn_obj_set(view, "code", 4, scr_dyn_new_str(code)); +} + +void scr_error_set_code_dyn(ScrError *e, ScrDyn *value) { + if (value != NULL && value->kind == SCR_DYN_STR) { + scr_error_set_code_value(e, value->v.str); + return; + } + scr_str_release(e->code); + e->code = NULL; + ScrDyn *view = scr_dyn_from_error(e); + ScrStr *key = scr_str_new("code", 4); + scr_dyn_key_set(view, key, value); + scr_str_release(key); + scr_dyn_release(view); +} + +/* Object.assign(err, ...sources) onto a compiled error: each source's own + * members land on the error's checked-dynamic node, then the slots that + * typed reads use (name, message, stack, cause, code) take the result. + * Borrows both; throws what the copy throws (a nullish source is skipped, + * as in JS). */ +void scr_error_assign_dyn(ScrError *e, const ScrDyn *sources) { + ScrDyn *view = scr_dyn_from_error(e); + ScrDyn *r = scr_dyn_assign_all(view, sources); + if (r != NULL) { + scr_dyn_release(r); + if (view->kind == SCR_DYN_OBJ) { + scr_error_commit_dyn(e, view); + if (!scr_exc_pending()) { + ScrDyn *code = scr_dyn_obj_get(view, "code", 4); + ScrStr *next = code != NULL && code->kind == SCR_DYN_STR ? scr_str_retain(code->v.str) : NULL; + scr_str_release(e->code); + e->code = next; + } + } + } + scr_dyn_release(view); +} + +/* `key in err` for a key no compiled class of the receiver declares: an own + * property set at runtime, which lives on the error's checked-dynamic node + * (that node exists once anything reflected or wrote through it), or a + * member of Object.prototype. Borrows both; never throws. */ +bool scr_error_has_key(ScrError *e, const ScrStr *key) { + const ScrDyn *view = scr_errdyn_view_of(e); + if (view != NULL && view->kind == SCR_DYN_OBJ && scr_dyn_find_entry(view, key->data, key->len) != NULL) + return true; + return scr_dyn_object_proto_name(key); +} diff --git a/tests/corpus/6400-override-any-base.ts b/tests/corpus/6400-override-any-base.ts new file mode 100644 index 000000000..72b050425 --- /dev/null +++ b/tests/corpus/6400-override-any-base.ts @@ -0,0 +1,35 @@ +// Overrides that narrow an `any`-typed base result: a typed async override +// over an untyped base method, and a sync override returning a union. +class Pool { + name = "pool"; + acquire(): any { + return Promise.resolve("base"); + } + describe(): any { + return this.name; + } +} +class MeteredPool extends Pool { + waits = 0; + override async acquire(): Promise { + this.waits++; + await super.acquire(); + } + override describe(): string | undefined { + return this.waits > 1 ? `metered ${this.waits}` : undefined; + } +} +async function use(pool: Pool, label: string): Promise { + const got = await pool.acquire(); + console.log(label, got === undefined ? "undefined" : got, String(pool.describe())); +} +async function main(): Promise { + const metered = new MeteredPool(); + await use(new Pool(), "plain"); + await use(metered, "metered"); + await metered.acquire(); + console.log(metered.waits, metered.describe()); + const pools: Pool[] = [new Pool(), metered]; + for (const p of pools) console.log(typeof p.describe()); +} +main(); diff --git a/tests/corpus/6401-override-param-variance.ts b/tests/corpus/6401-override-param-variance.ts new file mode 100644 index 000000000..997207af8 --- /dev/null +++ b/tests/corpus/6401-override-param-variance.ts @@ -0,0 +1,33 @@ +// Overrides whose parameters differ from the base: a typed parameter over +// an `any` slot, a wider (contravariant) parameter, and a narrowed result. +class Handler { + handle(input: any): any { + return `base:${input}`; + } + score(value: string): number | undefined { + return value.length; + } +} +class TypedHandler extends Handler { + override handle(input: string): string { + return `typed:${input.toUpperCase()}`; + } + override score(value: string | number): number { + return typeof value === "string" ? value.length * 10 : value; + } +} +function run(h: Handler): void { + console.log(h.handle("abc"), h.score("xy")); +} +run(new Handler()); +run(new TypedHandler()); +const typed = new TypedHandler(); +console.log(typed.handle("q"), typed.score(7)); +try { + run2(new TypedHandler()); +} catch (e) { + console.log("caught", (e as Error).name); +} +function run2(h: Handler): void { + console.log(h.handle(42)); +} diff --git a/tests/corpus/6402-override-js-base/main.ts b/tests/corpus/6402-override-js-base/main.ts new file mode 100644 index 000000000..6821f09dd --- /dev/null +++ b/tests/corpus/6402-override-js-base/main.ts @@ -0,0 +1,26 @@ +// TypeScript overrides of an untyped JavaScript base: a typed async +// override over an untyped method, and a narrowed toString. +import { Pool } from "./pool.js"; + +class MeteredPool extends Pool { + waits = 0; + override async acquire(): Promise { + this.waits++; + const n: number = await super.acquire(); + return n * 10; + } + override toString(): string { + return `Metered(${this.waits})`; + } +} +async function main(): Promise { + const pools: Pool[] = [new Pool(2), new MeteredPool(3)]; + for (const pool of pools) { + const got = await pool.acquire(); + console.log(String(got), pool.toString(), `${pool}`); + pool.release(); + } + const metered = new MeteredPool(1); + console.log(await metered.acquire(), metered.waits); +} +main(); diff --git a/tests/corpus/6402-override-js-base/pool.js b/tests/corpus/6402-override-js-base/pool.js new file mode 100644 index 000000000..d1a337882 --- /dev/null +++ b/tests/corpus/6402-override-js-base/pool.js @@ -0,0 +1,17 @@ +// An untyped JavaScript base class, the shape of a small npm semaphore. +export class Pool { + constructor(size) { + this.size = size; + this.taken = 0; + } + async acquire() { + this.taken++; + return this.taken; + } + release() { + this.taken--; + } + toString() { + return `Pool(${this.taken}/${this.size})`; + } +} diff --git a/tests/corpus/6403-error-code-write.ts b/tests/corpus/6403-error-code-write.ts new file mode 100644 index 000000000..3d6efc2a0 --- /dev/null +++ b/tests/corpus/6403-error-code-write.ts @@ -0,0 +1,39 @@ +// Own properties written on Error values typed with an intersection. +const coded = new Error("c") as Error & { code?: string }; +coded.code = "E1"; +console.log(coded.code, "code" in coded); +function has(err: Error): boolean { + return "code" in err; +} +console.log(has(coded), has(new Error("plain"))); +try { + throw coded; +} catch (e) { + console.log((e as Error & { code?: string }).code); +} + +// System-error members first, then the code: reads stay consistent. +type SysError = Error & { code?: string; errno?: number; syscall?: string; path?: string }; +function sysError(message: string, code: string | undefined): SysError { + const err = new Error(message) as SysError; + err.errno = -2; + err.syscall = "open"; + err.path = "/missing"; + err.code = code; + return err; +} +const enoent = sysError("no such file", "ENOENT"); +console.log(enoent.code, enoent.errno, enoent.syscall, enoent.path, "code" in enoent); +console.log(enoent.message, enoent instanceof Error); +const uncoded = sysError("no code", undefined); +console.log(uncoded.code, uncoded.syscall); + +// A code that is only known at runtime. +function withCode(err: Error & { code?: string }, code: unknown): void { + err.code = code as string; +} +const late = new Error("late") as Error & { code?: string }; +withCode(late, "ELATE"); +console.log(late.code); +late.code = "EAGAIN"; +console.log(late.code, late.message); diff --git a/tests/corpus/6404-error-in-and-assign.ts b/tests/corpus/6404-error-in-and-assign.ts new file mode 100644 index 000000000..7003a8ae8 --- /dev/null +++ b/tests/corpus/6404-error-in-and-assign.ts @@ -0,0 +1,105 @@ +// `'key' in err` on Error values of every receiver form, and +// Object.assign onto a fresh Error. +class HttpError extends Error { + status = 404; + get retryable(): boolean { + return this.status >= 500; + } + describe(): string { + return `${this.status}`; + } +} + +// A receiver narrowed from unknown by instanceof. +function statusOf(value: unknown): unknown { + if (value instanceof Error) { + return "status" in value ? value.status : "none"; + } + return "not an error"; +} +console.log(statusOf(new HttpError("not found")), statusOf(new Error("plain")), statusOf("text")); + +// Parameters, call results and caught values; members a subclass declares +// as fields, accessors and methods; Error.prototype's own members. +function keys(err: Error): string { + return [ + "status" in err, + "retryable" in err, + "describe" in err, + "toString" in err, + "missing" in err, + "message" in err, + ].join(" "); +} +console.log(keys(new HttpError("h"))); +console.log(keys(new Error("e"))); +console.log(keys(new TypeError("t"))); +function latest(): Error { + return new HttpError("latest"); +} +console.log("status" in latest(), "message" in latest()); +function caught(fn: () => void): string { + try { + fn(); + return "ok"; + } catch (e) { + if (e instanceof Error && "status" in e) return `status ${String(e.status)}`; + return "plain"; + } +} +console.log( + caught(() => { + throw new HttpError("t"); + }), + caught(() => { + throw new Error("u"); + }), +); + +// Properties set at runtime are own properties too. +const expando = new Error("x"); +(expando as unknown as { status: number }).status = 1; +console.log(keys(expando)); + +// Object.assign copies the source's own properties onto the error and +// answers the error itself. +interface ErrorLike { + message: string; + status?: number; + code?: string; +} +function toError(error: ErrorLike | string): Error { + return typeof error === "string" + ? new Error(error) + : Object.assign(new Error(error.message), error); +} +const assigned = toError({ message: "boom", status: 500, code: "EBOOM" }); +console.log(assigned.message, (assigned as Error & { code?: string }).code, "status" in assigned); +console.log(statusOf(assigned), assigned instanceof Error, keys(assigned)); +const renamed = toError({ message: "renamed" }); +console.log(renamed.message, "status" in renamed, toError("text").message); +const fresh = new Error("before"); +console.log(Object.assign(fresh, { message: "after" }) === fresh, fresh.message); + +// An Error intersection carrying extra fields: Object.assign's result, +// read and written through its declared members. +interface ApiErrorFields { + status: number; + action: string | undefined; + code: string | undefined; + link: string | undefined; +} +function apiError(message: string, fields: ApiErrorFields) { + const error = Object.assign(new Error(message), fields); + return error; +} +const gateway = apiError("bad gateway", { status: 502, action: undefined, code: "E502", link: "https://example.com" }); +console.log(gateway.message, gateway.status, gateway.code, gateway.link, "action" in gateway, gateway.action); +gateway.status = 503; +console.log(gateway.status, gateway instanceof Error); +Object.assign(gateway, { status: 504, code: "E504" }); +console.log(gateway.status, gateway.code); +function describeApiError(error: Error & { status?: number }): string { + return `${error.message}:${error.status ?? "none"}`; +} +console.log(describeApiError(gateway), describeApiError(new Error("plain"))); diff --git a/tests/corpus/6405-wrapped-default-parameters.ts b/tests/corpus/6405-wrapped-default-parameters.ts new file mode 100644 index 000000000..f607eb885 --- /dev/null +++ b/tests/corpus/6405-wrapped-default-parameters.ts @@ -0,0 +1,67 @@ +// Lambdas whose parameters take their type from an `any` default, passed +// through generic wrappers that forward their arguments. +function trace any>(name: string, fn: F): F { + return ((...args: Parameters) => { + console.log("span", name); + return fn(...args); + }) as F; +} +function traceArgs(name: string, fn: (...args: A) => R): (...args: A) => R { + return (...args: A) => { + console.log("span", name); + return fn(...args); + }; +} +function lookup(key: string): any { + return key === "set" ? 7 : undefined; +} + +const doubled = trace("doubled", (n = lookup("unset") ?? 5) => n * 2); +console.log(doubled(), doubled(4)); +const sum = trace("sum", (n = lookup("set") ?? 5, m = 1) => n * 4 + m); +console.log(sum(), sum(2), sum(2, 3)); +const label = trace("label", (prefix = lookup("unset") ?? "item", count: number = 0) => `${prefix}#${count}`); +console.log(label(), label("row"), label(undefined, 3)); +const tripled = traceArgs("tripled", (n: number = lookup("unset") ?? 5) => n * 3); +console.log(tripled(), tripled(2)); + +// A wrapper that also reports tags computed from the wrapped function's +// result, handing its untyped result on through `as never`. +function traceTagged any>( + name: string, + fn: F, + resultTags?: ( + result: ReturnType extends PromiseLike ? U : ReturnType, + ) => Record, +): F { + return ((...args: Parameters) => { + const result: unknown = fn(...args); + if (resultTags) console.log(name, JSON.stringify(resultTags(result as never))); + return result; + }) as F; +} +const summarize = traceTagged( + "summarize", + (limit = lookup("unset") ?? 2) => ({ kept: Number(limit), dropped: 1 }), + (r) => ({ total: r.kept + r.dropped }), +); +console.log(summarize().kept, summarize(5).kept); + +// The same through a function expression whose result is untyped. +function traceTaggedAny any>( + name: string, + fn: F, + resultTags: (result: ReturnType) => Record, +): F { + return function (this: unknown, ...args: Parameters) { + const result = fn.apply(this, args); + console.log(name, JSON.stringify(resultTags(result as never))); + return result; + } as F; +} +const measure = traceTaggedAny( + "measure", + (width = lookup("set") ?? 1, height = 2) => ({ area: Number(width) * height }), + (r) => ({ area: r.area }), +); +console.log(measure().area, measure(3, 4).area); diff --git a/tests/corpus/6406-npm-instance-receiver/main.ts b/tests/corpus/6406-npm-instance-receiver/main.ts new file mode 100644 index 000000000..3dc893548 --- /dev/null +++ b/tests/corpus/6406-npm-instance-receiver/main.ts @@ -0,0 +1,7 @@ +// A package's constructor function, compiled per call site, reads its own +// receiver while the constructor that reached it has a receiver too. +import { create } from "corked-writer"; +const w = create({ highWaterMark: 4 }); +console.log(w.uncork()); +console.log(w.uncork()); +console.log(create().uncork()); diff --git a/tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/index.d.ts b/tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/index.d.ts new file mode 100644 index 000000000..1de006a3d --- /dev/null +++ b/tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/index.d.ts @@ -0,0 +1,4 @@ +export interface Writable { + uncork(): string; +} +export function create(options?: { highWaterMark?: number }): Writable; diff --git a/tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/index.js b/tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/index.js new file mode 100644 index 000000000..6a7e75541 --- /dev/null +++ b/tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/index.js @@ -0,0 +1,45 @@ +'use strict'; + +// Constructor functions in the shape of a stream implementation: a request +// object built inside another constructor keeps its receiver in a var for +// a callback, and the writer is also exported as a value. + +function CorkedRequest(state) { + var _this = this; + this.next = null; + this.entry = null; + this.finish = function () { + onCorkedFinish(_this, state); + }; +} +module.exports = { + create: function (options) { + return new Writable(options); + }, + Writable: Writable, +}; +Writable.WritableState = WritableState; +function WritableState(options, stream) { + this.highWaterMark = options.highWaterMark || 16; + this.pending = 2; + this.stream = stream; + this.corkedRequestsFree = new CorkedRequest(this); +} +WritableState.prototype.getBuffer = function getBuffer() { + return this.pending; +}; +function Writable(options) { + this._writableState = new WritableState(options || {}, this); + this.label = "w"; +} +Writable.prototype.uncork = function () { + var state = this._writableState; + var req = state.corkedRequestsFree; + req.finish(); + state.corkedRequestsFree = new CorkedRequest(state); + return this.label + " " + req.next + " " + state.highWaterMark; +}; +function onCorkedFinish(corkReq, state) { + state.pending--; + corkReq.next = "finished:" + state.pending; +} diff --git a/tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/package.json b/tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/package.json new file mode 100644 index 000000000..94a00403d --- /dev/null +++ b/tests/corpus/6406-npm-instance-receiver/node_modules/corked-writer/package.json @@ -0,0 +1 @@ +{ "name": "corked-writer", "version": "1.0.0", "main": "index.js", "types": "index.d.ts" } diff --git a/tests/corpus/6407-js-error-tostring-override/errors.js b/tests/corpus/6407-js-error-tostring-override/errors.js new file mode 100644 index 000000000..839b57a67 --- /dev/null +++ b/tests/corpus/6407-js-error-tostring-override/errors.js @@ -0,0 +1,22 @@ +// JavaScript Error subclasses whose toString overrides infer results that +// differ from Error.prototype.toString's string. +export class IssueError extends Error { + constructor(issues) { + super("invalid"); + this.issues = issues; + this.name = "IssueError"; + } + /** @returns {string | undefined} */ + toString() { + return this.issues.length > 0 ? this.issues.join("; ") : undefined; + } +} +export class LabelError extends Error { + constructor(label, detail) { + super(detail); + this.label = label; + } + toString() { + return this.label; + } +} diff --git a/tests/corpus/6407-js-error-tostring-override/main.ts b/tests/corpus/6407-js-error-tostring-override/main.ts new file mode 100644 index 000000000..15a857efd --- /dev/null +++ b/tests/corpus/6407-js-error-tostring-override/main.ts @@ -0,0 +1,9 @@ +// TypeScript callers of JavaScript toString overrides whose inferred +// results differ from the inherited string. +import { IssueError, LabelError } from "./errors.js"; +const issues = new IssueError(["a is required", "b must be a number"]); +console.log(issues.toString()); +console.log(String(issues), `${new IssueError([])}`); +const errors: Error[] = [issues, new LabelError("db", "down"), new Error("plain")]; +for (const e of errors) console.log(e.toString(), e instanceof IssueError); +console.log(errors.map((e) => String(e)).join(" | ")); diff --git a/tests/corpus/6408-override-js-async-base/lock.js b/tests/corpus/6408-override-js-async-base/lock.js new file mode 100644 index 000000000..1ea00239d --- /dev/null +++ b/tests/corpus/6408-override-js-async-base/lock.js @@ -0,0 +1,22 @@ +// An untyped JavaScript lock whose async acquire resolves to an untyped +// ticket. +export class Lock { + constructor() { + this.held = false; + this.log = []; + this.queue = makeQueue(this.log); + } + async acquire() { + const ticket = await this.queue.wait(); + this.held = true; + this.log.push("base acquire"); + return ticket; + } + release() { + this.held = false; + } +} + +function makeQueue(log) { + return { wait: () => new Promise((resolve) => setTimeout(() => resolve(log.length), 1)) }; +} diff --git a/tests/corpus/6408-override-js-async-base/main.ts b/tests/corpus/6408-override-js-async-base/main.ts new file mode 100644 index 000000000..da0c0b183 --- /dev/null +++ b/tests/corpus/6408-override-js-async-base/main.ts @@ -0,0 +1,30 @@ +// TypeScript overrides returning Promise over an untyped JavaScript +// async method: an async override and a promise-returning one. +import { Lock } from "./lock.js"; +class TimedLock extends Lock { + waits = 0; + async acquire(): Promise { + this.waits++; + await super.acquire(); + this.log.push("timed acquire"); + } +} +class EagerLock extends Lock { + acquire(): Promise { + this.log.push("eager"); + return Promise.resolve(); + } +} +async function main(): Promise { + const locks: Lock[] = [new TimedLock(), new EagerLock(), new Lock()]; + for (const lock of locks) { + await lock.acquire(); + console.log(lock.held, lock.log.join(",")); + } + const timed = new TimedLock(); + await timed.acquire(); + console.log(timed.waits, timed.held); + const viaBase: Lock = new TimedLock(); + console.log(await new Lock().acquire(), await viaBase.acquire()); +} +main(); diff --git a/tests/corpus/6409-catch-binding-shapes.ts b/tests/corpus/6409-catch-binding-shapes.ts new file mode 100644 index 000000000..930c41f38 --- /dev/null +++ b/tests/corpus/6409-catch-binding-shapes.ts @@ -0,0 +1,69 @@ +// Catch bindings typed any, multi-statement guards over catch bindings, +// and writes into a caught error. +interface SafeFetchError extends Error { + kind: "safe-fetch"; + host: string; +} +function isSafeFetchError(e: unknown): e is SafeFetchError { + if (!(e instanceof Error)) return false; + return "kind" in e && e.kind === "safe-fetch"; +} +function blocked(host: string): Error { + return Object.assign(new Error(`blocked ${host}`), { kind: "safe-fetch", host }); +} +function run(fn: () => void): string { + try { + fn(); + return "ok"; + } catch (err) { + if (isSafeFetchError(err)) return `guarded ${err.host} ${err.message}`; + return `other ${err instanceof Error ? err.message : String(err)}`; + } +} +console.log(run(() => {})); +console.log(run(() => { + throw blocked("example.com"); +})); +console.log(run(() => { + throw new Error("plain"); +})); +console.log(run(() => { + throw "text"; +})); + +function annotate(fn: () => void): void { + try { + fn(); + } catch (e: any) { + e.message = `config: ${e.message}`; + if (e.code === "ENOPE") e.hint = "check the file"; + throw e; + } +} +for (const code of ["ENOPE", "EOTHER"]) { + try { + annotate(() => { + throw Object.assign(new Error("missing"), { code }); + }); + } catch (e) { + const err = e as Error & { code?: string; hint?: string }; + console.log(err.message, err.code, err.hint, err instanceof Error); + } +} + +// An assertion on a catch binding typed any. +function codeOf(fn: () => void): string { + try { + fn(); + return "none"; + } catch (e: any) { + const err = e as Error & { code?: string }; + return `${err.message}:${err.code ?? "-"}`; + } +} +console.log( + codeOf(() => { + throw Object.assign(new Error("coded"), { code: "E1" }); + }), + codeOf(() => {}), +); From 0e8b4cf9909dbad22e7a4f350191b4576c2ec68e Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 23:36:12 -0700 Subject: [PATCH 14/39] Hand back untyped wrapper results at the slot's type, and no-op transpiled prototype resets - A function adapter whose source returns `any`/`unknown` (a generic wrapper's result handed back `as F`) converts the result through the checked-dynamic bridge when the slot's result is checkable: a record checks its shape, and a Promise keeps its identity and checks its payload when it settles. Before, these adapters threw "the call has no exact lowering" when called. - In a class constructor, `Object.setPrototypeOf(this, new.target.prototype)` (directly, through a const, or the `if (Object.setPrototypeOf) ... else this.__proto__ = ...` form), and `Object.setPrototypeOf(this, C.prototype)` in C's own constructor when no class extends C, are no-ops: a compiled instance already has that prototype. - Object.assign between records copies a source field into a wider target field (`{ bail: true }` into `bail?: boolean`). Co-Authored-By: Claude Opus 5.5 --- .../lowering/coercions/function-adapters.ts | 16 +++ .../src/frontend/lowering/lower-calls.ts | 11 +- .../src/frontend/lowering/lower-exprs.ts | 9 ++ .../src/frontend/lowering/lower-stmts.ts | 123 ++++++++++++++++++ tests/corpus/6404-error-in-and-assign.ts | 14 ++ tests/corpus/6410-wrapper-untyped-results.ts | 50 +++++++ .../issues.js | 27 ++++ .../6411-prototype-reset-constructors/main.ts | 33 +++++ 8 files changed, 281 insertions(+), 2 deletions(-) create mode 100644 tests/corpus/6410-wrapper-untyped-results.ts create mode 100644 tests/corpus/6411-prototype-reset-constructors/issues.js create mode 100644 tests/corpus/6411-prototype-reset-constructors/main.ts diff --git a/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts b/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts index b99c24a15..14cc8ba86 100644 --- a/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts +++ b/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts @@ -4,6 +4,7 @@ import { InternalCompilerError } from "../../../errors.js"; import type { IrExpr, IrParam, IrStmt, IrType, SrcLoc } from "../../../ir/ir.js"; import { canAdaptDynFuncTo, + canDynCheckTo, DYN, F64, isUnitType, @@ -208,6 +209,19 @@ export function funcCoerceAdapter( voidRet = toT.ret.kind === "dyn" ? "dyn" : "strand"; } } + // An untyped result (a generic wrapper's `any` handed back `as F`) takes + // the checked-dynamic extraction to the slot's result: a record checks + // its shape, a Promise keeps its identity and checks its payload when it + // settles. + const checkedRet = + strandRet && + fromT.ret.kind === "dyn" && + canDynCheckTo( + toT.ret, + (id) => lowerer.shapes.get(id), + (id) => lowerer.unions.get(id), + ); + if (checkedRet) strandRet = false; const key = `fnadapt:${typeKey(fromT)}:${typeKey(toT)}`; const existing = lowerer.coercions.retags.get(key); if (existing) return existing; @@ -307,6 +321,8 @@ export function funcCoerceAdapter( `a '${lowerer.fmt(fromT)}' function invoked through a '${lowerer.fmt(toT)}' slot (the result cannot convert to '${lowerer.fmt(toT.ret)}' — the checker's loose function compatibility admitted the assignment, but the call has no exact lowering)`, ), ]; + } else if (checkedRet) { + body = [{ kind: "return", value: { kind: "dynCheck", value: call, type: toT.ret, loc }, loc }]; } else { const result = lowerer.coerceToExpected(call, toT.ret); if (!typeEquals(result.type, toT.ret)) diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index f9abf2d19..14d5d71d3 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -6699,6 +6699,7 @@ function recordAssignHelper( const helper = `%obj.assign.${lowerer.arrHofHelpers.size}`; lowerer.arrHofHelpers.set(key, helper); const sShape = lowerer.shapes.get(srcShapeId)!; + const tShape = lowerer.shapes.get(targetShapeId)!; const tT: IrType = { kind: "record", shapeId: targetShapeId }; const sT: IrType = { kind: "record", shapeId: srcShapeId }; const tRef: IrExpr = { kind: "varRef", localId: "t.0", type: tT, loc }; @@ -6713,12 +6714,13 @@ function recordAssignHelper( type: f.type, loc, }; + const targetType = tShape.fields.find((x) => x.name === f.name)!.type; const set: IrStmt = { kind: "recordSet", obj: tRef, shapeId: targetShapeId, field: f.name, - value: get, + value: typeEquals(targetType, f.type) ? get : lowerer.coerceToExpected(get, targetType), loc, }; const present = lowerer.recordFieldPresent(sRef, srcShapeId, f.name, loc); @@ -7338,7 +7340,12 @@ function lowerObjectStaticCall( !shapeHasAccessorSlots(sShape) && sShape.fields.every((sf) => { const tf = tShape.fields.find((x) => x.name === sf.name); - return tf !== undefined && typeEquals(tf.type, sf.type); + // A source value converts into a wider target field (`{ bail: + // true }` into `bail?: boolean`). + return ( + tf !== undefined && + (typeEquals(tf.type, sf.type) || lowerer.coercibleValue(sf.type, tf.type)) + ); }); if (ok) { const loc = locOf(call); diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 8b02597ab..61fc0f8d0 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -4824,6 +4824,15 @@ function nullishBranches( export function lowerCondition(lowerer: Lowerer, expr: ts.Expression): IrExpr { let e: ts.Expression = expr; while (ts.isParenthesizedExpression(e)) e = e.expression; + // `if (Object.setPrototypeOf)`: the feature test of transpiled Error + // subclasses' prototype reset. Node always has it. + if ( + ts.isPropertyAccessExpression(e) && + !e.questionDotToken && + e.name.text === "setPrototypeOf" && + lowerer.isStdlibGlobal(e.expression, "Object") + ) + return { kind: "boolLit", value: true, type: BOOL, loc: locOf(e) }; if (ts.isPropertyAccessExpression(e)) { const presence = lowerPromiseThenPresence(lowerer, e, { kind: "boolLit", diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index eb0d31cbd..e6c6720e0 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -1350,6 +1350,7 @@ function lowerLabeled(lowerer: Lowerer, stmt: ts.LabeledStatement): IrStmt | IrS } export function lowerStmt(lowerer: Lowerer, stmt: ts.Statement): IrStmt | IrStmt[] | null { + if (ownPrototypeResetStatement(lowerer, stmt)) return { kind: "block", body: [], loc: locOf(stmt) }; if (ts.isClassDeclaration(stmt)) { if (!stmt.name) lowerer.unsupported("SC1090", stmt, "anonymous local class declarations"); const info = lowerer.lowerClassExpressionInfo(stmt); @@ -10849,3 +10850,125 @@ function isStringTyped(t: ts.Type): boolean { if (t.isUnionType()) return ts.constituentTypes(t).every(isStringTyped); return (t.flags & (ts.TypeFlags.String | ts.TypeFlags.StringLiteral)) !== 0; } + +/** The Error-subclass prototype reset of transpiled code, inside a class + * constructor: + * + * const proto = new.target.prototype; + * if (Object.setPrototypeOf) Object.setPrototypeOf(this, proto); + * else this.__proto__ = proto; + * + * (also `Object.setPrototypeOf(this, new.target.prototype)` and + * `Object.setPrototypeOf(this, C.prototype)` in C's own constructor when no + * class extends C). A compiled instance already has exactly that prototype, + * so each statement is a no-op. True for those statements. */ +function ownPrototypeResetStatement(lowerer: Lowerer, stmt: ts.Statement): boolean { + if (ts.isVariableStatement(stmt)) { + const decls = stmt.declarationList.declarations.nodes; + if (decls.length !== 1 || (stmt.declarationList.flags & ts.NodeFlags.Const) === 0) return false; + const decl = decls[0]!; + if (!ts.isIdentifier(decl.name) || !decl.initializer) return false; + const ctor = enclosingConstructor(decl); + if (!ctor || !ownPrototypeRef(lowerer, decl.initializer, ctor)) return false; + const symbol = lowerer.checker.getSymbolAtLocation(decl.name); + if (!symbol) return false; + // Every other use of the binding must be one of the reset statements. + let onlyResets = true; + ts.walkPreorder(ctor, (n) => { + if (!onlyResets) return "stop"; + if (!ts.isIdentifier(n) || n === decl.name) return undefined; + if (lowerer.checker.getSymbolAtLocation(n) !== symbol) return undefined; + const statement = n.parent?.parent; + if ( + !statement || + !ts.isExpressionStatement(statement) || + resetTarget(lowerer, statement.expression) !== n + ) + onlyResets = false; + return undefined; + }); + return onlyResets; + } + if (!ts.isExpressionStatement(stmt)) return false; + const ctor = enclosingConstructor(stmt); + if (!ctor) return false; + const target = resetTarget(lowerer, stmt.expression); + return target !== null && ownPrototypeRef(lowerer, target, ctor); +} + +/** The prototype operand of `Object.setPrototypeOf(this, P)` or + * `this.__proto__ = P`, or null. */ +function resetTarget(lowerer: Lowerer, expr: ts.Expression): ts.Expression | null { + if ( + ts.isCallExpression(expr) && + expr.arguments.nodes.length === 2 && + expr.arguments.nodes[0]!.kind === ts.SyntaxKind.ThisKeyword && + ts.isPropertyAccessExpression(expr.expression) && + expr.expression.name.text === "setPrototypeOf" && + lowerer.isStdlibGlobal(expr.expression.expression, "Object") + ) + return expr.arguments.nodes[1]!; + if ( + ts.isBinaryExpression(expr) && + expr.operatorToken.kind === ts.SyntaxKind.EqualsToken && + ts.isPropertyAccessExpression(expr.left) && + expr.left.expression.kind === ts.SyntaxKind.ThisKeyword && + expr.left.name.text === "__proto__" + ) + return expr.right; + return null; +} + +/** The class constructor whose body holds `node`, crossing only statements + * and blocks (any nested function rebinds `this`). */ +function enclosingConstructor(node: ts.Node): ts.ConstructorDeclaration | null { + for (let cur = node.parent; cur !== undefined; cur = cur.parent) { + if (ts.isConstructorDeclaration(cur)) return cur; + if (ts.isFunctionLike(cur) || (ts.isClassDeclaration(cur) || ts.isClassExpression(cur)) || ts.isSourceFile(cur)) return null; + } + return null; +} + +/** Whether `node` denotes the prototype of the object `ctor` constructs: + * `new.target.prototype`, a const holding it, or the class's own + * `C.prototype` when no class extends C. */ +function ownPrototypeRef( + lowerer: Lowerer, + node: ts.Expression, + ctor: ts.ConstructorDeclaration, +): boolean { + while (ts.isParenthesizedExpression(node)) node = node.expression; + if (ts.isPropertyAccessExpression(node) && node.name.text === "prototype") { + const base = node.expression; + if ( + ts.isMetaProperty(base) && + base.keywordToken === ts.SyntaxKind.NewKeyword && + base.name.text === "target" + ) + return true; + const cls = ctor.parent; + if (!ts.isIdentifier(base) || !(ts.isClassDeclaration(cls) || ts.isClassExpression(cls))) return false; + const symbol = lowerer.resolveValueSymbol(base); + const info = symbol ? lowerer.classBySymbol.get(symbol) : undefined; + if (!info || lowerer.checker.valueDeclarationOf(symbol!) !== cls) return false; + for (const other of lowerer.classes.values()) { + if (other !== info && lowerer.isSubclassOf(other.def.name, info.def.name)) return false; + } + return true; + } + if (ts.isIdentifier(node)) { + const symbol = lowerer.resolveValueSymbol(node); + const decl = symbol ? lowerer.checker.valueDeclarationOf(symbol) : undefined; + return ( + decl !== undefined && + ts.isVariableDeclaration(decl) && + decl.initializer !== undefined && + ts.isVariableDeclarationList(decl.parent) && + (decl.parent.flags & ts.NodeFlags.Const) !== 0 && + enclosingConstructor(decl) === ctor && + !ts.isIdentifier(decl.initializer) && + ownPrototypeRef(lowerer, decl.initializer, ctor) + ); + } + return false; +} diff --git a/tests/corpus/6404-error-in-and-assign.ts b/tests/corpus/6404-error-in-and-assign.ts index 7003a8ae8..fc6f470e6 100644 --- a/tests/corpus/6404-error-in-and-assign.ts +++ b/tests/corpus/6404-error-in-and-assign.ts @@ -103,3 +103,17 @@ function describeApiError(error: Error & { status?: number }): string { return `${error.message}:${error.status ?? "none"}`; } console.log(describeApiError(gateway), describeApiError(new Error("plain"))); + +// Object.assign into a record whose fields are wider than the source's. +interface BuildFailure { + message: string; + bail?: boolean; + code?: string; +} +function failure(message: string, bail: boolean): BuildFailure { + const err: BuildFailure = { message }; + if (bail) Object.assign(err, { bail: true }); + return Object.assign(err, { code: "E_BUILD" }); +} +for (const f of [failure("stop", true), failure("go", false)]) + console.log(f.message, f.bail, f.code); diff --git a/tests/corpus/6410-wrapper-untyped-results.ts b/tests/corpus/6410-wrapper-untyped-results.ts new file mode 100644 index 000000000..f8df7683a --- /dev/null +++ b/tests/corpus/6410-wrapper-untyped-results.ts @@ -0,0 +1,50 @@ +// Generic wrappers returning their untyped result `as F`: async functions, +// records with unknown fields, and rejections passing through. +function trace any>(name: string, fn: F): F { + return ((...args: Parameters) => { + console.log("span", name); + return fn(...args); + }) as F; +} +function traceThis any>(name: string, fn: F): F { + return function (this: unknown, ...args: Parameters) { + const result: unknown = fn.apply(this, args); + console.log("span", name, typeof result); + return result; + } as F; +} +function lookup(key: string): any { + return key === "set" ? 7 : undefined; +} +const fetchCount = trace("fetchCount", async (base: number): Promise => { + await null; + return base + 1; +}); +const fetchUser = traceThis("fetchUser", async (id: string): Promise<{ id: string; admin: boolean }> => ({ + id, + admin: id === "root", +})); +const fails = trace("fails", async (why: string): Promise => { + throw new Error(why); +}); +const summarize = trace("summarize", (limit = lookup("unset") ?? 2) => ({ kept: limit, dropped: 1 })); +const measure = traceThis("measure", (n: number) => ({ size: n, label: lookup("set") })); +async function main(): Promise { + console.log(await fetchCount(1)); + const user = await fetchUser("root"); + console.log(user.id, user.admin); + try { + await fails("nope"); + } catch (e) { + console.log("caught", e instanceof Error ? e.message : String(e)); + } + const s = summarize(); + console.log(s.kept, s.dropped, summarize(5).kept); + const m = measure(3); + console.log(m.size, m.label); + const pending = fetchCount(10); + console.log("before"); + console.log(await pending); +} +main(); +export {}; diff --git a/tests/corpus/6411-prototype-reset-constructors/issues.js b/tests/corpus/6411-prototype-reset-constructors/issues.js new file mode 100644 index 000000000..1058d7188 --- /dev/null +++ b/tests/corpus/6411-prototype-reset-constructors/issues.js @@ -0,0 +1,27 @@ +// An Error subclass in the shape of a validation library's: the constructor +// resets the prototype to new.target's, as transpiled code does. +export class IssueError extends Error { + constructor(issues) { + super(); + this.issues = []; + const actualProto = new.target.prototype; + if (Object.setPrototypeOf) { + Object.setPrototypeOf(this, actualProto); + } else { + this.__proto__ = actualProto; + } + this.name = "IssueError"; + this.issues = issues; + } + get message() { + return JSON.stringify(this.issues); + } + get isEmpty() { + return this.issues.length === 0; + } +} +export class StrictIssueError extends IssueError { + get strict() { + return true; + } +} diff --git a/tests/corpus/6411-prototype-reset-constructors/main.ts b/tests/corpus/6411-prototype-reset-constructors/main.ts new file mode 100644 index 000000000..65f155e8d --- /dev/null +++ b/tests/corpus/6411-prototype-reset-constructors/main.ts @@ -0,0 +1,33 @@ +// Constructors that reset the instance prototype, the transpiled idiom for +// Error subclasses. +import { IssueError, StrictIssueError } from "./issues.js"; +class AppError extends Error { + constructor(message: string) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + this.name = "AppError"; + } + describe(): string { + return `${this.name}: ${this.message}`; + } +} +class NotFound extends AppError { + constructor(what: string) { + super(`${what} not found`); + Object.setPrototypeOf(this, NotFound.prototype); + this.name = "NotFound"; + } +} +const app = new AppError("boom"); +const missing = new NotFound("user"); +console.log(app.describe(), app instanceof AppError, app instanceof Error); +console.log(missing.describe(), missing instanceof NotFound, missing instanceof AppError); +const issues = new IssueError([{ path: "a" }]); +console.log(issues.message, issues.isEmpty, issues instanceof IssueError, issues.name); +const strict = new StrictIssueError([]); +console.log(strict.isEmpty, strict.strict, strict instanceof IssueError, String(strict instanceof StrictIssueError)); +try { + throw new NotFound("page"); +} catch (e) { + console.log(e instanceof NotFound ? e.describe() : "other"); +} From b3bcbaaf7cea09e9a17582ad9249f887db081f2a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 01:46:36 -0500 Subject: [PATCH 15/39] Decode memargs the same way in validation and translation Validation, translation and instruction skipping now read memarg flags through one function, readMemargFlags in module.ts. Flags with bit 6 set are followed by an explicit memory index, which may be 0; flags of 128 or more are malformed. The translator refuses a module (WasmTranslateError) when a memarg, memory.size, memory.grow, memory.init, memory.copy or memory.fill names a memory other than 0, and when the operand of local.set, local.tee, global.set, table.set, a load or a store does not have the type of its destination. Locals are stored with their declared type. --- packages/compiler/src/wasm/binary.ts | 23 +++---- packages/compiler/src/wasm/module.ts | 18 +++++- packages/compiler/src/wasm/translate.ts | 83 ++++++++++++++++++------- 3 files changed, 85 insertions(+), 39 deletions(-) diff --git a/packages/compiler/src/wasm/binary.ts b/packages/compiler/src/wasm/binary.ts index 5ddc28cc9..ad5297739 100644 --- a/packages/compiler/src/wasm/binary.ts +++ b/packages/compiler/src/wasm/binary.ts @@ -20,6 +20,7 @@ * The decoder never evaluates anything and keeps no module contents beyond * the counts and the feature set it reports. It is plain TypeScript that * the native compiler also compiles. */ +import { readMemargFlags } from "./module.js"; /** Proposals the summary can name, in report order. The first group is the * translatable set; the rest are reported as unsupported. */ @@ -1244,19 +1245,9 @@ class FunctionValidator { /** A memarg. A memory other than 0 stops typing (multi-memory). */ memarg(naturalAlign: number): void { const r = this.r; - let align = r.u32(); - let multi = false; - if (align >= 64 && align < 128) { - align -= 64; - multi = true; - } else if (align >= 64) { - r.malformed("malformed memop flags"); - } - let memory = 0; - if (multi) { - memory = r.u32(); - if (memory !== 0) this.otherMemory(memory); - } + const { align, memory } = readMemargFlags(r); + if (align < 0) r.malformed("malformed memop flags"); + if (memory !== 0) this.otherMemory(memory); if (this.m.memory64) r.u64(); else r.u32(); if (!this.typed) return; @@ -1840,9 +1831,9 @@ class FunctionValidator { scanMemarg(): void { const r = this.r; - const align = r.u32(); - if (align >= 128) r.malformed("malformed memop flags"); - if (align >= 64 && r.u32() !== 0) this.m.feature("multi-memory"); + const { align, memory } = readMemargFlags(r); + if (align < 0) r.malformed("malformed memop flags"); + if (memory !== 0) this.m.feature("multi-memory"); if (this.m.memory64) r.u64(); else r.u32(); } diff --git a/packages/compiler/src/wasm/module.ts b/packages/compiler/src/wasm/module.ts index 3b0dd54c0..d7ec38701 100644 --- a/packages/compiler/src/wasm/module.ts +++ b/packages/compiler/src/wasm/module.ts @@ -283,6 +283,20 @@ function decodeUtf8(bytes: Uint8Array, start: number, end: number): string { return out; } +/** The flags of a memarg (the immediates of loads, stores and atomics): + * the alignment exponent and the memory index. Flags with bit 6 set + * (multi-memory) are followed by an explicit memory index, which may be + * 0; flags of 128 or more are malformed and answer align -1 without + * reading further. The offset follows. Validation (binary.ts), translation + * and skipImmediates all read memargs through this function, so they agree + * on where each instruction ends. */ +export function readMemargFlags(r: { u32(): number }): { align: number; memory: number } { + const flags = r.u32(); + if (flags >= 128) return { align: -1, memory: 0 }; + if (flags >= 64) return { align: flags - 64, memory: r.u32() }; + return { align: flags, memory: 0 }; +} + /** Reads the immediates of opcode `op` (already consumed). Covers the * translatable feature level; anything else was refused before * translation. */ @@ -372,7 +386,9 @@ export function skipImmediates(c: WasmCursor, op: number): void { } default: if (op >= 0x28 && op <= 0x3e) { - c.u32(); + const flags = readMemargFlags(c); + if (flags.align < 0 || flags.memory !== 0) + throw new Error(`wasm: memarg of memory ${flags.memory} is not supported`); c.u32(); } return; diff --git a/packages/compiler/src/wasm/translate.ts b/packages/compiler/src/wasm/translate.ts index e0ce27be5..813dab84a 100644 --- a/packages/compiler/src/wasm/translate.ts +++ b/packages/compiler/src/wasm/translate.ts @@ -48,6 +48,7 @@ import { VAL_I64, WasmCursor, parseWasmModule, + readMemargFlags, skipImmediates, type WasmFuncType, type WasmModule, @@ -830,6 +831,39 @@ class FunctionTranslator { return v; } + /** Pops a value that must have type `t`: the type a local, global, + * table or memory store writes. Validation guarantees it; a mismatch + * means the translator and the validator disagree about the code, so + * the module is not translated. */ + popType(t: number, what: string): StackValue { + const v = this.pop(); + if (v.t !== t) throw new WasmTranslateError(`${what} operand type does not match`); + return v; + } + + /** The declared type of local `i` (parameters first). */ + localType(i: number): number { + const t = this.localTypes[i]; + if (t === undefined) throw new WasmTranslateError(`unknown local ${i}`); + return t; + } + + /** The offset of a memarg over memory 0 (the only memory a translatable + * module has). */ + memargOffset(c: WasmCursor): number { + const flags = readMemargFlags(c); + if (flags.align < 0 || flags.memory !== 0) + throw new WasmTranslateError(`memarg of memory ${flags.memory} is not supported`); + return c.u32(); + } + + /** A memory index immediate (memory.size, memory.grow and the bulk + * memory instructions), which must be 0. */ + memoryIndex(c: WasmCursor): void { + const index = c.u32(); + if (index !== 0) throw new WasmTranslateError(`memory ${index} is not supported`); + } + popN(n: number): StackValue[] { const out = this.stack.splice(this.stack.length - n, n); if (out.length !== n) throw new Error("wasm translator: operand stack underflow"); @@ -1540,20 +1574,23 @@ class FunctionTranslator { } case 0x20: { const i = c.u32(); - const t = this.localTypes[i]!; + const t = this.localType(i); this.push(this.emit(`load ${llType(t)}, ptr %l${i}`), t); return; } case 0x21: { const i = c.u32(); - const v = this.pop(); - this.add(` store ${llType(v.t)} ${v.v}, ptr %l${i}`); + const t = this.localType(i); + const v = this.popType(t, "local.set"); + this.add(` store ${llType(t)} ${v.v}, ptr %l${i}`); return; } case 0x22: { const i = c.u32(); - const v = this.stack[this.stack.length - 1]!; - this.add(` store ${llType(v.t)} ${v.v}, ptr %l${i}`); + const t = this.localType(i); + const v = this.popType(t, "local.tee"); + this.stack.push(v); + this.add(` store ${llType(t)} ${v.v}, ptr %l${i}`); return; } case 0x23: { @@ -1565,7 +1602,9 @@ class FunctionTranslator { } case 0x24: { const g = c.u32(); - const v = this.pop(); + const global = this.m.globals[g]; + if (global === undefined) throw new WasmTranslateError(`unknown global ${g}`); + const v = this.popType(global.type, "global.set"); const cell = this.loadPtrSlot(this.mt.globalSlot(g)); if (v.t === VAL_EXTERNREF) this.add(` call void @scr_wasm_global_set_ref(ptr ${cell}, ptr ${v.v})`); @@ -1583,13 +1622,15 @@ class FunctionTranslator { } case 0x26: { const t = c.u32(); - const v = this.pop(); - const i = this.pop(); + const table = this.m.tables[t]; + if (table === undefined) throw new WasmTranslateError(`unknown table ${t}`); + const v = this.popType(table.elemType, "table.set"); + const i = this.popType(VAL_I32, "table.set"); this.add(` call void @scr_wasm_table_set(ptr %inst, i32 ${t}, i32 ${i.v}, ptr ${v.v})`); return; } case 0x3f: { - c.u32(); + this.memoryIndex(c); const mem = this.loadPtrSlot(OFF_MEMORY); const sizePtr = this.emit(`getelementptr inbounds i8, ptr ${mem}, i64 8`); const size = this.emit(`load i64, ptr ${sizePtr}, align 8`); @@ -1598,7 +1639,7 @@ class FunctionTranslator { return; } case 0x40: { - c.u32(); + this.memoryIndex(c); const delta = this.pop(); this.push(this.emit(`call i32 @scr_wasm_memory_grow(ptr %inst, i32 ${delta.v})`), VAL_I32); this.refreshMemory(); @@ -1641,10 +1682,9 @@ class FunctionTranslator { break; } if (op >= 0x28 && op <= 0x35) { - c.u32(); - const offset = c.u32(); + const offset = this.memargOffset(c); const [vt, mt, bytes, ext] = LOAD_INFO[op]!; - const addr = this.pop(); + const addr = this.popType(VAL_I32, "load address"); const p = this.address(addr.v, offset, bytes); const line = this.lines.lines.length; const loaded = this.emit(`load ${mt}, ptr ${p}, align 1`); @@ -1656,11 +1696,10 @@ class FunctionTranslator { return; } if (op >= 0x36 && op <= 0x3e) { - c.u32(); - const offset = c.u32(); - const [, mt, bytes] = STORE_INFO[op]!; - const v = this.pop(); - const addr = this.pop(); + const offset = this.memargOffset(c); + const [vt, mt, bytes] = STORE_INFO[op]!; + const v = this.popType(vt, "store"); + const addr = this.popType(VAL_I32, "store address"); const p = this.address(addr.v, offset, bytes); let value = v.v; if (mt === "i8" || mt === "i16" || (mt === "i32" && v.t === VAL_I64)) { @@ -1960,7 +1999,7 @@ class FunctionTranslator { case 8: { // memory.init const seg = c.u32(); - c.u32(); + this.memoryIndex(c); const n = this.pop(); const s = this.pop(); const d = this.pop(); @@ -1973,8 +2012,8 @@ class FunctionTranslator { this.add(` call void @scr_wasm_data_drop(ptr %inst, i32 ${c.u32()})`); return; case 10: { - c.u32(); - c.u32(); + this.memoryIndex(c); + this.memoryIndex(c); const n = this.pop(); const s = this.pop(); const d = this.pop(); @@ -1984,7 +2023,7 @@ class FunctionTranslator { return; } case 11: { - c.u32(); + this.memoryIndex(c); const n = this.pop(); const v = this.pop(); const d = this.pop(); From 45431aec320c53e12e9b664e80d8d48ffbb4f547 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 02:01:48 -0500 Subject: [PATCH 16/39] Choose comptime union arms by discriminant and refuse recursive records A comptime record value whose union has a discriminant takes the arm its discriminant field names, so a value that fits two arms with overlapping shapes gets that arm's tag and layout instead of the first arm it fits. comptimeBakeable reports a record type reachable from its own fields as not bakeable instead of recursing without end, so such a comptime result reports SC1090, and the message names unions and that limit. --- .../src/frontend/lowering/lower-comptime.ts | 54 ++++++++++++++----- tests/corpus/1052-comptime-records.ts | 17 ++++++ tests/diagnostics/comptime.ts | 7 +++ tests/harness/__snapshots__/comptime.ts.txt | 9 +++- 4 files changed, 74 insertions(+), 13 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/lower-comptime.ts b/packages/compiler/src/frontend/lowering/lower-comptime.ts index 31fa5afe0..bdd020127 100644 --- a/packages/compiler/src/frontend/lowering/lower-comptime.ts +++ b/packages/compiler/src/frontend/lowering/lower-comptime.ts @@ -76,7 +76,7 @@ export function lowerComptime(lowerer: Lowerer, expr: ts.CallExpression): IrExpr "SC1090", expr, `baking comptime results of type '${lowerer.fmt(target)}' into the binary ` + - `(only number, string, boolean, arrays, and records lower to literals)`, + `(number, string, boolean, and arrays, records and unions of those lower to literals; a record type reachable from its own fields does not)`, ); } // 5. The host executes the extracted callback under a finite budget. @@ -112,25 +112,36 @@ function comptimeFailureDetail(error: unknown): string { * expression: number/string/boolean, arrays and record shapes of those, * and unions of those with null or undefined (the mixed rows of a JSON * table: `(string | number)[][]`), nested. Closures, class instances, - * promises, dyn, and void cannot be baked. */ + * promises, dyn, void, and recursive record types (a record reachable + * from its own fields) cannot be baked. */ export function comptimeBakeable(lowerer: Lowerer, t: IrType): boolean { + return bakeableWithin(lowerer, t, new Set()); +} + +/** comptimeBakeable below the records in `open`, whose fields are being + * checked: reaching one of them again means the type is recursive. */ +function bakeableWithin(lowerer: Lowerer, t: IrType, open: Set): boolean { switch (t.kind) { case "f64": case "string": case "bool": return true; case "array": - return lowerer.comptimeBakeable(t.elem); + return bakeableWithin(lowerer, t.elem, open); case "record": { const shape = lowerer.shapes.get(t.shapeId); - return !!shape && shape.fields.every((f) => lowerer.comptimeBakeable(f.type)); + if (!shape || open.has(t.shapeId)) return false; + open.add(t.shapeId); + const bakeable = shape.fields.every((f) => bakeableWithin(lowerer, f.type, open)); + open.delete(t.shapeId); + return bakeable; } case "union": { const arms = lowerer.unions.get(t.unionId)?.arms; return ( arms !== undefined && arms.every( - (arm) => isUnitType(arm) || (arm.kind !== "union" && comptimeBakeable(lowerer, arm)), + (arm) => isUnitType(arm) || (arm.kind !== "union" && bakeableWithin(lowerer, arm, open)), ) ); } @@ -139,6 +150,30 @@ export function comptimeBakeable(lowerer: Lowerer, t: IrType): boolean { } } +/** The tag of the arm of union `unionId` that `value` bakes into, or -1. + * A record value whose discriminant field holds one of the union's + * discriminant values takes that case's arm, since arms with overlapping + * shapes can both fit it. Any other value takes the first arm it fits, in + * the union's arm order: a JSON value fits exactly one scalar arm, and + * array or record arms are told apart by their contents. */ +function comptimeUnionArm(lowerer: Lowerer, unionId: string, value: unknown): number { + const def = lowerer.unions.get(unionId); + if (!def) return -1; + const discriminant = def.discriminant; + if ( + discriminant !== undefined && + typeof value === "object" && + value !== null && + !Array.isArray(value) + ) { + const key = (value as Record)[discriminant.field]; + const named = discriminant.cases.find((c) => c.values.some((v) => v === key)); + if (named !== undefined) + return comptimeFits(lowerer, value, def.arms[named.tag]!) ? named.tag : -1; + } + return def.arms.findIndex((arm) => comptimeFits(lowerer, value, arm)); +} + /** Whether `value` bakes into the bakeable type `t` without a mismatch: * the arm choice of a union literal. Records are exact, as in * comptimeValueToIr; an absent field reads as undefined. */ @@ -168,9 +203,7 @@ function comptimeFits(lowerer: Lowerer, value: unknown, t: IrType): boolean { ); } case "union": - return (lowerer.unions.get(t.unionId)?.arms ?? []).some((arm) => - comptimeFits(lowerer, value, arm), - ); + return comptimeUnionArm(lowerer, t.unionId, value) >= 0; default: return false; } @@ -313,11 +346,8 @@ export function comptimeValueToIr( return { kind: "recordLit", fields, type: expected, loc }; } case "union": { - // The first arm the value fits, in the union's arm order: a JSON - // value fits exactly one scalar arm, and array or record arms are - // told apart by their contents. const arms = lowerer.unions.get(expected.unionId)!.arms; // bakeable-checked - const tag = arms.findIndex((arm) => comptimeFits(lowerer, value, arm)); + const tag = comptimeUnionArm(lowerer, expected.unionId, value); if (tag < 0) fail(describeComptimeValue(value)); const arm = arms[tag]!; const payload: IrExpr = isUnitType(arm) diff --git a/tests/corpus/1052-comptime-records.ts b/tests/corpus/1052-comptime-records.ts index 47cccf7b3..658aaed32 100644 --- a/tests/corpus/1052-comptime-records.ts +++ b/tests/corpus/1052-comptime-records.ts @@ -43,3 +43,20 @@ const meta = comptime(() => { return { kind: "meta", tags, count: tags.length }; }); console.log(meta.kind, meta.tags.join("|"), meta.count); + +// A discriminated union whose arms both fit a "labeled" value without a +// label: the discriminant picks the arm. +type Item = { kind: "plain"; v: number } | { kind: "labeled"; v: number; label?: string }; +const items: Item[] = comptime( + () => + [ + { kind: "plain", v: 1 }, + { kind: "labeled", v: 2 }, + { kind: "labeled", v: 3, label: "x" }, + ] as Item[], +); +for (const item of items) { + if (item.kind === "labeled") console.log("labeled", item.v, item.label); + else console.log("plain", item.v); +} +console.log(JSON.stringify(items)); diff --git a/tests/diagnostics/comptime.ts b/tests/diagnostics/comptime.ts index 9ba882aaf..9c8239464 100644 --- a/tests/diagnostics/comptime.ts +++ b/tests/diagnostics/comptime.ts @@ -20,3 +20,10 @@ const nested = comptime(() => comptime(() => 1)); const eventually = comptime(async () => 1); const lied = comptime(() => 1 as unknown as string); + +// A record type reachable from its own fields has no literal form. +interface Chain { + value: number; + next: Chain | null; +} +const chain: Chain = comptime(() => ({ value: 1, next: null }) as Chain); diff --git a/tests/harness/__snapshots__/comptime.ts.txt b/tests/harness/__snapshots__/comptime.ts.txt index 2b1411ae5..603c297a8 100644 --- a/tests/harness/__snapshots__/comptime.ts.txt +++ b/tests/harness/__snapshots__/comptime.ts.txt @@ -45,4 +45,11 @@ comptime.ts:22:23 - error SC1110: comptime evaluation failed: expected 'string' 21 | 22 | const lied = comptime(() => 1 as unknown as string); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 23 | \ No newline at end of file + 23 | + +comptime.ts:29:22 - error SC1090: baking comptime results of type '{ next: null | ...; value: number }' into the binary (number, string, boolean, and arrays, records and unions of those lower to literals; a record type reachable from its own fields does not) is not supported yet + + 28 | } + 29 | const chain: Chain = comptime(() => ({ value: 1, next: null }) as Chain); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 30 | \ No newline at end of file From 069545a126a0d48e1a7c0bd39130906fd4ab4f86 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 02:07:46 -0500 Subject: [PATCH 17/39] Address review: monitorEventLoopDelay spellings and validation, Error 'in' keys, event-loop metrics in libraries - monitorEventLoopDelay is lowered from the builtin call dispatch, by module and member, so aliased named imports, namespace members and destructured requires all reach it. Shorthand and possibly undefined resolutions take Node's default. - The runtime validates the resolution as Node does (an integer of at least 1) and throws a catchable RangeError with ERR_OUT_OF_RANGE. - `'stack' in err` and Object.prototype's keys are true for every Error. The declared-member fold applies only to keys some program class declares and that built-in errors don't carry in runtime slots; other keys stay fenced. - Library mode's async_free gate refuses the event-loop metrics, which library links leave out. They join the perf_hooks fence family. --- .../src/frontend/lowering/builtin-calls.ts | 4 ++ .../frontend/lowering/builtins/performance.ts | 32 ++++++------- .../src/frontend/lowering/lower-calls.ts | 11 ----- .../src/frontend/lowering/lower-exprs.ts | 46 ++++++++++++++++--- packages/compiler/src/ir/builtin-effects.ts | 2 + .../compiler/src/ir/builtin-signatures.ts | 2 +- packages/compiler/src/ir/runtime-features.ts | 4 +- packages/compiler/src/library/ir-policy.ts | 6 +++ packages/runtime/src/scr_perf_loop.c | 24 +++++++++- tests/corpus/6394-in-key-error-subclasses.ts | 6 +++ tests/corpus/6397-event-loop-metrics.ts | 21 +++++++++ tests/harness/library-asyncfree.test.ts | 15 ++++++ tests/harness/library-profile.test.ts | 5 +- 13 files changed, 138 insertions(+), 40 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/builtin-calls.ts b/packages/compiler/src/frontend/lowering/builtin-calls.ts index 7e1852600..7d3a5d41a 100644 --- a/packages/compiler/src/frontend/lowering/builtin-calls.ts +++ b/packages/compiler/src/frontend/lowering/builtin-calls.ts @@ -1,4 +1,5 @@ import { lowerReadlineCursorCall } from "./builtins/readline.js"; +import { lowerMonitorEventLoopDelayCall } from "./builtins/performance.js"; import { lowerEnvironmentData, lowerReceiveMessageOnPort, @@ -69,6 +70,9 @@ export function lowerBuiltinCall( return lowerAddAbortListener(lowerer, expr, loc); } if (bi.module === "events" && bi.member === "once") return lowerEventsOnce(lowerer, expr, loc); + if (bi.module === "perf_hooks" && bi.member === "monitorEventLoopDelay") { + return lowerMonitorEventLoopDelayCall(lowerer, expr); + } if (bi.module === "events") { const helper = lowerEventsEmitterHelper(lowerer, expr, bi.member, loc); if (helper) return helper; diff --git a/packages/compiler/src/frontend/lowering/builtins/performance.ts b/packages/compiler/src/frontend/lowering/builtins/performance.ts index 19b585e37..7aac3b80c 100644 --- a/packages/compiler/src/frontend/lowering/builtins/performance.ts +++ b/packages/compiler/src/frontend/lowering/builtins/performance.ts @@ -18,6 +18,7 @@ import { } from "../../../ir/ir.js"; import { PERF_ENTRY_FIELDS, PERF_ENTRY_MARKER, perfEntryJsonShape } from "../../type-mapper.js"; import { builtinImportOf } from "./module-bindings.js"; +import { lowerOptionalArgument } from "../optional-arguments.js"; import { checkedIterableSpread } from "../checked-iterable-spread.js"; /** True for any spelling of node:perf_hooks' `performance` object — the @@ -663,21 +664,11 @@ export function lowerHistogramMethodCall( ); } -/** `monitorEventLoopDelay(options?)` from node:perf_hooks (a named import - * or a namespace member): a new sampling histogram handle. The resolution - * must be a literal-free number expression or an object literal option. */ -export function lowerMonitorEventLoopDelayCall( - lowerer: Lowerer, - expr: ts.CallExpression, -): IrExpr | null { - const callee = expr.expression; - const bi = ts.isIdentifier(callee) - ? builtinImportOf(lowerer, callee) - : ts.isPropertyAccessExpression(callee) && !callee.questionDotToken - ? lowerer.builtinMemberOf(callee) - : null; - if (bi === null || bi.module !== "perf_hooks" || bi.member !== "monitorEventLoopDelay") - return null; +/** `monitorEventLoopDelay(options?)` from node:perf_hooks, in any import + * spelling (`lowerBuiltinCall`): a new sampling histogram handle. The + * options are an inline object literal; the runtime validates the + * resolution as Node does (an integer of at least 1). */ +export function lowerMonitorEventLoopDelayCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { const loc = locOf(expr); const args = expr.arguments.nodes; let resolution: IrExpr = numLit(10, loc); @@ -698,8 +689,9 @@ export function lowerMonitorEventLoopDelayCall( ); } for (const property of options.properties.nodes) { + const shorthand = ts.isShorthandPropertyAssignment(property); if ( - !ts.isPropertyAssignment(property) || + (!shorthand && !ts.isPropertyAssignment(property)) || !ts.isIdentifier(property.name) || property.name.text !== "resolution" ) { @@ -709,7 +701,13 @@ export function lowerMonitorEventLoopDelayCall( "resolution is the one option", ); } - resolution = lowerer.lowerExprExpecting(property.initializer, F64); + // An undefined resolution takes the default, as Node's destructuring. + resolution = lowerOptionalArgument( + lowerer, + shorthand ? property.name : property.initializer, + F64, + numLit(10, loc), + ); } } return { kind: "libCall", fn: "perf.eldNew", args: [resolution], type: F64, loc }; diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 23629a7ba..e60ee2367 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -144,7 +144,6 @@ import { fencePerfEntryKeyWalk, isPerfEntryType, lowerHistogramMethodCall, - lowerMonitorEventLoopDelayCall, lowerPerfHooksCall, perfEntryTag, } from "./builtins/performance.js"; @@ -243,16 +242,6 @@ const ZLIB_STREAM_METHODS: ReadonlySet = new Set(["flush", "params", "cl export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { const loc = locOf(expr); - // node:perf_hooks monitorEventLoopDelay (named import or namespace member). - if ( - (ts.isIdentifier(expr.expression) && expr.expression.text === "monitorEventLoopDelay") || - (ts.isPropertyAccessExpression(expr.expression) && - expr.expression.name.text === "monitorEventLoopDelay") - ) { - const histogram = lowerMonitorEventLoopDelayCall(lowerer, expr); - if (histogram) return histogram; - } - // Object's checker return type is `any`. Claim known object inputs // before generic checked-dynamic dispatch tries to load the constructor. if ( diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index aa597d8a2..684ffde58 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -13801,6 +13801,24 @@ const OBJECT_PROTOTYPE_KEYS: ReadonlySet = new Set([ * idiom over multiple shapes), index-signature keys, class instances, * and dyn/unknown stay fenced. Keys are literal strings — a computed key * over a shape would need the runtime key table. */ +/** Keys built-in errors carry outside their class fields: Node's system + * error properties, and AggregateError's, SuppressedError's and + * AssertionError's own members. */ +const BUILTIN_ERROR_SLOT_KEYS: ReadonlySet = new Set([ + "errno", + "syscall", + "path", + "dest", + "info", + "errors", + "error", + "suppressed", + "actual", + "expected", + "operator", + "generatedMessage", +]); + function lowerInExpression(lowerer: Lowerer, expr: ts.BinaryExpression, loc: SrcLoc): IrExpr { if ( lowerer.isStdlibGlobal(expr.right, "process") && @@ -14036,15 +14054,29 @@ function lowerInExpression(lowerer: Lowerer, expr: ts.BinaryExpression, loc: Src ) { return { kind: "boolLit", value: true, type: BOOL, loc }; } + // Every Error has its own `stack`, and Error.prototype's `toString` + // and `constructor` are among Object.prototype's keys. + if ( + (key === "stack" || OBJECT_PROTOTYPE_KEYS.has(key)) && + (recv.kind === "varRef" || recv.kind === "caughtNarrow") + ) { + return { kind: "boolLit", value: true, type: BOOL, loc }; + } // Any other key: a member a program class declares. The receiver's // runtime class is its static class or a descendant; the key is - // present exactly when that class (or an ancestor) declares it. - if (recv.kind === "varRef" || recv.kind === "caughtNarrow") { - const declares = (c: ClassInfo): boolean => - c.fields.has(key) || - lowerer.findMethodOn(c, key) !== null || - lowerer.findMethodOn(c, `get:${key}`) !== null || - lowerer.findMethodOn(c, `set:${key}`) !== null; + // present exactly when that class (or an ancestor) declares it. Keys + // built-in errors keep outside their class fields depend on the + // runtime error and stay fenced, as do keys no program class declares. + const declares = (c: ClassInfo): boolean => + c.fields.has(key) || + lowerer.findMethodOn(c, key) !== null || + lowerer.findMethodOn(c, `get:${key}`) !== null || + lowerer.findMethodOn(c, `set:${key}`) !== null; + if ( + (recv.kind === "varRef" || recv.kind === "caughtNarrow") && + !BUILTIN_ERROR_SLOT_KEYS.has(key) && + [...lowerer.classes.values()].some((c) => c.builtinError !== true && declares(c)) + ) { const staticName = recv.type.className; const staticInfo = lowerer.classes.get(staticName); if (staticInfo && declares(staticInfo)) diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index f20d0945e..9a7ca178b 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -363,6 +363,8 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "perf.entries", "perf.clearMarks", "perf.clearMeasures", + // monitorEventLoopDelay's resolution: Node's ERR_OUT_OF_RANGE. + "perf.eldNew", // Non-TTY stdin: Node's stdin has no setRawMode member, so the call is // the exact catchable TypeError. "process.stdinSetRawMode", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 02943ae1b..de50aab1c 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -364,7 +364,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ /** perf_hooks event-loop metrics (scr_perf_loop.c): loopStart is the * loop's start in performance.now() ms (0 before it), idleTime the idle * ms since. eldNew(resolution ms) creates a monitorEventLoopDelay - * histogram handle; enable/disable answer whether the state changed; + * histogram handle (MAY THROW Node's resolution RangeError); enable/disable answer whether the state changed; * eldPercentile expects Node's validated range; eldStat(which) reads * 0 min, 1 max, 2 mean, 3 stddev, 4 count, 5 exceeds. */ "perf.loopStart": { argTypes: [], result: F64 }, diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index b2628fa10..1946faeb3 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -506,11 +506,11 @@ function scanRuntimeFeatures(mod: IrModule, stopAt?: keyof RuntimeFeatures): Run } if (fn.startsWith("dgram.") || fn.startsWith("dns.")) features.dgram = true; if (fn.startsWith("tlsca.")) features.tlsCa = true; + if (fn.startsWith("perf.loop") || fn === "perf.idleTime" || fn.startsWith("perf.eld")) + features.perfLoop = true; // scr_cipher.c over the mbedTLS archive; DEP0182 reports through the // process-warning unit, and unknown output encodings render through // the inspect unit. - if (fn.startsWith("perf.loop") || fn === "perf.idleTime" || fn.startsWith("perf.eld")) - features.perfLoop = true; if (fn === "crypto.cipherNew") { features.cipher = true; features.dynAsync = true; diff --git a/packages/compiler/src/library/ir-policy.ts b/packages/compiler/src/library/ir-policy.ts index 3c3855e5c..a9c9609f5 100644 --- a/packages/compiler/src/library/ir-policy.ts +++ b/packages/compiler/src/library/ir-policy.ts @@ -53,6 +53,11 @@ const LIB_MODE_REFUSED_PREFIXES: readonly [string, string][] = [ ["crypto.cipherNew", "crypto.createCipheriv and createDecipheriv"], ["fs.watch", "fs.watch"], ["watcher.", "fs.watch"], + // The event-loop metrics sample the loop and its timers (scr_perf_loop.c), + // which library links exclude. + ["perf.loopStart", "performance.eventLoopUtilization"], + ["perf.idleTime", "performance.eventLoopUtilization"], + ["perf.eld", "perf_hooks.monitorEventLoopDelay"], ["test.", "the node:test surface"], ["readable.", "the node:stream surface"], ["writable.", "the node:stream surface"], @@ -157,6 +162,7 @@ export function moduleLibAsyncSurface(mod: IrModule): { surface: string; loc: Sr [features.nodeTest, "the node:test surface"], [features.dynAsync, "the checked-dynamic async surface"], [features.dc, "the diagnostics_channel surface"], + [features.perfLoop, "the perf_hooks event-loop metrics"], ]; for (const [on, surface] of coarse) { if (on) return { surface, loc: entryLoc }; diff --git a/packages/runtime/src/scr_perf_loop.c b/packages/runtime/src/scr_perf_loop.c index 29d98ea29..68d3bf10f 100644 --- a/packages/runtime/src/scr_perf_loop.c +++ b/packages/runtime/src/scr_perf_loop.c @@ -21,7 +21,9 @@ #include #include +#include #include +#include #include #ifdef _WIN32 #include @@ -212,7 +214,27 @@ static void scr_eld_cleanup(void) { scr_elds_len = 0; } +/* Node's validateInteger(resolution, 'options.resolution', 1): a catchable + * RangeError (ERR_OUT_OF_RANGE) for a non-integer or a value out of range, + * with the value as util.inspect renders it ("-0" included). */ +static bool scr_eld_resolution_ok(double resolution) { + bool integer = isfinite(resolution) && trunc(resolution) == resolution; + if (integer && resolution >= 1 && resolution <= 9007199254740991.0) return true; + char received[48]; + if (resolution == 0 && signbit(resolution)) + memcpy(received, "-0", 3); + else + scr_num_received(resolution, received); + char msg[192]; + int len = snprintf(msg, sizeof msg, + "The value of \"options.resolution\" is out of range. It must be %s. Received %s", + integer ? ">= 1 && <= 9007199254740991" : "an integer", received); + scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE"); + return false; +} + double scr_eld_new(double resolution) { + if (!scr_eld_resolution_ok(resolution)) return 0; if (scr_elds_len == 0 && scr_elds == NULL) scr_atexit(scr_eld_cleanup); ScrEld *h = calloc(1, sizeof(ScrEld)); ScrEld **grown = realloc(scr_elds, (scr_elds_len + 1) * sizeof(ScrEld *)); @@ -223,7 +245,7 @@ double scr_eld_new(double resolution) { } scr_elds = grown; h->min_value = INT64_MAX; - h->resolution = resolution >= 1 ? resolution : 10; + h->resolution = resolution; h->tick = scr_closure_new((void *)scr_eld_tick, 0); scr_elds[scr_elds_len++] = h; return (double)scr_elds_len; diff --git a/tests/corpus/6394-in-key-error-subclasses.ts b/tests/corpus/6394-in-key-error-subclasses.ts index cdb28a5a3..5ade6bcd1 100644 --- a/tests/corpus/6394-in-key-error-subclasses.ts +++ b/tests/corpus/6394-in-key-error-subclasses.ts @@ -23,3 +23,9 @@ function retryable(err: Error): boolean { } console.log(retryable(new Error("x")), retryable(new HttpError("a", 500)), retryable(new Timeout("t", 504))); console.log(describe(new Timeout("t", 504))); +// Keys every Error has: its own stack, and Error.prototype's and +// Object.prototype's members. +function inherent(err: Error): boolean[] { + return ["stack" in err, "toString" in err, "constructor" in err, "hasOwnProperty" in err]; +} +console.log(inherent(new Error("s")), inherent(new HttpError("h", 400)), inherent(new TypeError("t"))); diff --git a/tests/corpus/6397-event-loop-metrics.ts b/tests/corpus/6397-event-loop-metrics.ts index e1c3829ac..8477dcc48 100644 --- a/tests/corpus/6397-event-loop-metrics.ts +++ b/tests/corpus/6397-event-loop-metrics.ts @@ -1,6 +1,8 @@ // Event-loop monitoring under @types/node: monitorEventLoopDelay's histogram, // eventLoopUtilization deltas, and an unref'd interval typed NodeJS.Timeout. import { monitorEventLoopDelay, performance } from "node:perf_hooks"; +import * as perfHooks from "node:perf_hooks"; +import { monitorEventLoopDelay as eld } from "node:perf_hooks"; const histogram = monitorEventLoopDelay({ resolution: 10 }); console.log("enable", histogram.enable(), histogram.enable()); @@ -47,3 +49,22 @@ const interval = setInterval(() => { }, 50); interval.unref(); console.log("hasRef", interval.hasRef()); + +// Other import spellings, and Node's resolution validation. +const aliased = eld(); +const namespaced = perfHooks.monitorEventLoopDelay({ resolution: 20 }); +console.log("spellings", aliased.enable(), namespaced.enable(), aliased.disable(), namespaced.disable()); +for (const resolution of [0, -0, -1, 1.5, NaN, Infinity, 1e16, 1]) { + try { + eld({ resolution }); + console.log("created", resolution); + } catch (e) { + console.log((e as Error).name, (e as { code?: string }).code, (e as Error).message); + } +} +// An undefined resolution takes Node's default. +function withResolution(resolution?: number): boolean { + const h = monitorEventLoopDelay({ resolution }); + return h.enable() && h.disable(); +} +console.log("defaults", withResolution(), withResolution(20), eld({ resolution: undefined }).enable()); diff --git a/tests/harness/library-asyncfree.test.ts b/tests/harness/library-asyncfree.test.ts index 0adbef7bc..7c4d029cc 100644 --- a/tests/harness/library-asyncfree.test.ts +++ b/tests/harness/library-asyncfree.test.ts @@ -73,6 +73,21 @@ describe("async_free detection over the IR", () => { ); }); + test("the event-loop metrics refuse", async () => { + expect( + await surfaceOf( + "eld", + `import { monitorEventLoopDelay } from "node:perf_hooks";\nconst h = monitorEventLoopDelay();\nconsole.log(h.enable());\n`, + ), + ).toContain("monitorEventLoopDelay"); + expect( + await surfaceOf( + "elu", + `import { performance } from "node:perf_hooks";\nconsole.log(performance.eventLoopUtilization().idle >= 0);\n`, + ), + ).toContain("eventLoopUtilization"); + }); + test("child_process refuses even in its synchronous spelling", async () => { expect( await surfaceOf( diff --git a/tests/harness/library-profile.test.ts b/tests/harness/library-profile.test.ts index c7cb13751..c83b31ada 100644 --- a/tests/harness/library-profile.test.ts +++ b/tests/harness/library-profile.test.ts @@ -569,10 +569,13 @@ describe("library profile fences", () => { expect(processIds).toContain("node-builtin.process.isTTY"); expect(r.profile.fences[1]!.surfaces.every((s) => s.detector !== undefined)).toBe(true); // The user-timing timeline reads the same clock (mark() and measure() - // default to performance.now()), so it joins the perf_hooks family. + // default to performance.now()), and so do the event-loop metrics, so + // they join the perf_hooks family. expect(r.profile.fences[2]!.surfaces.map((s) => s.id)).toEqual([ + "node-builtin.perf_hooks.monitorEventLoopDelay", "node-builtin.perf_hooks.performance.clearMarks", "node-builtin.perf_hooks.performance.clearMeasures", + "node-builtin.perf_hooks.performance.eventLoopUtilization", "node-builtin.perf_hooks.performance.getEntries", "node-builtin.perf_hooks.performance.mark", "node-builtin.perf_hooks.performance.measure", From 1fb1d9c829002f78b5449b1937897ad32647a490 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Mon, 19 Oct 2026 23:16:01 -0700 Subject: [PATCH 18/39] Let constructor functions inherit from EventEmitter and the stream classes Bundled npm code (glob, yazl, from2, multistream) subclasses Node's classes with constructor functions: util.inherits(Ctor, EventEmitter) and EventEmitter.call(this). util.inherits received an identity token and threw ERR_INVALID_ARG_TYPE, EventEmitter.call(this) and EventEmitter.prototype were refused, and `this instanceof Ctor` against a function was refused. A new runtime unit (scr_dyn_builtin_class.c, linked by the new dynBuiltinClass feature) provides EventEmitter, the legacy Stream and the stream classes as untyped constructor functions with Node's prototype chain. EventEmitter's prototype ports lib/events.js over the object's own _events, _eventsCount and _maxListeners properties; Stream adds the legacy pipe. util.inherits, Base.call/apply(this, ...), Base.prototype, instanceof on untyped values and JavaScript value reads of these classes use them. Constructing over a stream class throws SC2020 where it runs. instanceof against a compiled constructor function compares its prototype with the value's prototype chain. Co-Authored-By: Claude Opus 5.5 --- .../limitations/builtin-function-values.mdx | 6 +- .../src/backend/executable-features.ts | 1 + packages/compiler/src/backend/library-pack.ts | 1 + .../compiler/src/backend/llvm/lib-shared.ts | 3 + .../src/backend/native-link-info-core.ts | 1 + .../compiler/src/backend/native/contracts.ts | 5 + .../compiler/src/backend/native/executable.ts | 4 + .../src/backend/runtime-pack-targets.test.ts | 1 + .../compiler/src/backend/runtime-pack.test.ts | 1 + packages/compiler/src/backend/warm-cache.ts | 1 + .../src/executable/executable-cache.test.ts | 1 + .../src/executable/executable-cache.ts | 2 + .../lowering/builtins/builtin-class-dyn.ts | 149 ++ .../src/frontend/lowering/class-prototypes.ts | 14 + .../lowering/expressions/identifiers.ts | 5 + .../lowering/expressions/relational.ts | 25 + .../src/frontend/lowering/lower-calls.ts | 6 + .../src/frontend/lowering/lower-inspect.ts | 19 +- .../compiler/src/frontend/lowering/lowerer.ts | 7 + packages/compiler/src/index.ts | 1 + packages/compiler/src/ir/builtin-effects.ts | 3 + .../compiler/src/ir/builtin-signatures.ts | 10 + packages/compiler/src/ir/runtime-features.ts | 20 +- packages/compiler/src/native/cli.ts | 1 + packages/compiler/src/native/prepare.ts | 1 + .../compiler/src/native/sanitizer.test.ts | 1 + ...6453-constructor-function-emitter.cjs.json | 6 + ...constructor-function-stream-bases.cjs.json | 6 + .../runtime-pack-matrix.mjs | 4 + packages/runtime/src/scr_dyn.h | 6 + packages/runtime/src/scr_dyn_builtin_class.c | 1469 +++++++++++++++++ .../6453-constructor-function-emitter.cjs | 114 ++ ...6454-constructor-function-stream-bases.cjs | 65 + .../self-hosting-native-toolchain.test.ts | 1 + .../self-hosting-runtime-features.test.ts | 1 + .../harness/self-hosting-runtime-pack.test.ts | 1 + 36 files changed, 1955 insertions(+), 7 deletions(-) create mode 100644 packages/compiler/src/frontend/lowering/builtins/builtin-class-dyn.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6453-constructor-function-emitter.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6454-constructor-function-stream-bases.cjs.json create mode 100644 packages/runtime/src/scr_dyn_builtin_class.c create mode 100644 tests/corpus/6453-constructor-function-emitter.cjs create mode 100644 tests/corpus/6454-constructor-function-stream-bases.cjs diff --git a/docs/content/limitations/builtin-function-values.mdx b/docs/content/limitations/builtin-function-values.mdx index c08540c1a..f3902e75b 100644 --- a/docs/content/limitations/builtin-function-values.mdx +++ b/docs/content/limitations/builtin-function-values.mdx @@ -12,7 +12,11 @@ Other immutable aliases of table-backed Node builtins support direct calls, but Native calls accept standard process streams; custom native streams and mutations to `util.inspect.colors` remain unsupported. `util.inherits` links the prototypes of constructor functions, and `util.deprecate`, `util.callbackify`, and `util.debuglog` return native function values that forward receivers and arguments. -Class constructors passed to `util.inherits` or `util.deprecate` are refused. +In JavaScript, a constructor function can inherit from `EventEmitter`, the legacy `Stream` constructor, or a stream class through `util.inherits` or `Object.setPrototypeOf`. +`EventEmitter.call(this)` and `Stream.call(this)` initialize the object as Node does, and its listener methods keep their state in the object's own `_events`, `_eventsCount`, and `_maxListeners` properties. +The `captureRejections` option and `events.errorMonitor` listeners are not supported on such objects. +Calling `Readable`, `Writable`, `Duplex`, `Transform`, or `PassThrough` with a constructor function's receiver throws `SC2020` where the call runs. +Other class constructors passed to `util.inherits` or `util.deprecate` are refused. Deprecation warnings are emitted on the next tick and follow assignments to `process.noDeprecation` and `process.throwDeprecation`; compiled binaries take no Node command-line flags such as `--no-deprecation` or `--trace-deprecation`, and `process.traceDeprecation` is unsupported. A stored `util.deprecate` reports a `length` of 4, where Node reports 3. In TypeScript, a `util.callbackify` result must reach a callback whose error parameter accepts `null`; the @types/node overloads that type it as non-null are refused. diff --git a/packages/compiler/src/backend/executable-features.ts b/packages/compiler/src/backend/executable-features.ts index eeb6c6900..a6e228b2e 100644 --- a/packages/compiler/src/backend/executable-features.ts +++ b/packages/compiler/src/backend/executable-features.ts @@ -31,6 +31,7 @@ export function executableLinkFeatures(mod: IrModule): NativeLinkFeatures { bigint: features.bigint, searchParams: features.searchParams, qs: features.qs, + dynBuiltinClass: features.dynBuiltinClass, parseArgs: features.parseArgs, stream: features.stream, net: features.net, diff --git a/packages/compiler/src/backend/library-pack.ts b/packages/compiler/src/backend/library-pack.ts index 5070a47a8..efabdc9d4 100644 --- a/packages/compiler/src/backend/library-pack.ts +++ b/packages/compiler/src/backend/library-pack.ts @@ -42,6 +42,7 @@ export async function compilePackedLibrary( bigint: options.bigint ?? false, searchParams: options.searchParams ?? false, qs: false, + dynBuiltinClass: false, parseArgs: false, stream: false, net: false, diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 44741edc8..2b25cc92e 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -1404,6 +1404,9 @@ export const LIB_FN_SYMS: Record = { "dyn.classPrototype": "scr_dyn_class_prototype", "dyn.classBasePrototype": "scr_dyn_class_base_prototype", "dyn.classInherit": "scr_dyn_class_inherit", + "dyn.builtinClass": "scr_dyn_builtin_class", + "dyn.builtinInstanceOf": "scr_dyn_builtin_instanceof", + "dyn.functionInstanceOf": "scr_dyn_function_instanceof", "dyn.classSuper": "scr_dyn_class_super", "dyn.assignPrototype": "scr_dyn_assign_prototype", "dyn.definePrototypeProps": "scr_dyn_define_prototype_props", diff --git a/packages/compiler/src/backend/native-link-info-core.ts b/packages/compiler/src/backend/native-link-info-core.ts index 86146259d..d7cf78327 100644 --- a/packages/compiler/src/backend/native-link-info-core.ts +++ b/packages/compiler/src/backend/native-link-info-core.ts @@ -46,6 +46,7 @@ export interface NativeLinkFeatures { bigint: boolean; searchParams: boolean; qs: boolean; + dynBuiltinClass: boolean; parseArgs: boolean; stream: boolean; net: boolean; diff --git a/packages/compiler/src/backend/native/contracts.ts b/packages/compiler/src/backend/native/contracts.ts index 33b13960e..d978d4387 100644 --- a/packages/compiler/src/backend/native/contracts.ts +++ b/packages/compiler/src/backend/native/contracts.ts @@ -150,6 +150,11 @@ export interface CcOptions { * line (escape-only programs ride the always-linked component encoder * and never flip this). */ qs?: boolean; + /** The program uses EventEmitter or a stream class as an untyped + * constructor value (a constructor function's base): compiles + * scr_dyn_builtin_class.c, which also references the inspection, + * dyn-invoke and symbol units. */ + dynBuiltinClass?: boolean; /** The program uses native util parsing, comparison, or styling. Optional * utility units also require their symbol, inspection, and warning features. */ parseArgs?: boolean; diff --git a/packages/compiler/src/backend/native/executable.ts b/packages/compiler/src/backend/native/executable.ts index 5ebb4796e..bbb720cc7 100644 --- a/packages/compiler/src/backend/native/executable.ts +++ b/packages/compiler/src/backend/native/executable.ts @@ -235,6 +235,10 @@ const RUNTIME_UNITS: readonly RuntimeUnit[] = [ (u) => u.opts.parseArgs && u.opts.inspect && u.opts.dynAsync && u.opts.dynInvoke && u.regex, "scr_util_callable.c", ), + unit( + (u) => u.opts.dynBuiltinClass && u.opts.inspect && u.opts.dynInvoke && u.opts.symbol, + "scr_dyn_builtin_class.c", + ), unit((u) => u.opts.stream, "scr_stream.c", "scr_fs_stream.c"), // The zlib stream classes reference both the zlib engine and the // stream unit. diff --git a/packages/compiler/src/backend/runtime-pack-targets.test.ts b/packages/compiler/src/backend/runtime-pack-targets.test.ts index fd57cb49d..8b0689c51 100644 --- a/packages/compiler/src/backend/runtime-pack-targets.test.ts +++ b/packages/compiler/src/backend/runtime-pack-targets.test.ts @@ -107,6 +107,7 @@ const features = { bigint: false, searchParams: false, qs: false, + dynBuiltinClass: false, parseArgs: false, stream: false, net: false, diff --git a/packages/compiler/src/backend/runtime-pack.test.ts b/packages/compiler/src/backend/runtime-pack.test.ts index 61d1dba5e..5af267d96 100644 --- a/packages/compiler/src/backend/runtime-pack.test.ts +++ b/packages/compiler/src/backend/runtime-pack.test.ts @@ -44,6 +44,7 @@ const BASE: NativeLinkFeatures = { bigint: false, searchParams: false, qs: false, + dynBuiltinClass: false, parseArgs: false, stream: false, net: false, diff --git a/packages/compiler/src/backend/warm-cache.ts b/packages/compiler/src/backend/warm-cache.ts index 2cd111060..b0736f102 100644 --- a/packages/compiler/src/backend/warm-cache.ts +++ b/packages/compiler/src/backend/warm-cache.ts @@ -50,6 +50,7 @@ export async function warmNativeCaches( bigint: false, searchParams: false, qs: false, + dynBuiltinClass: false, parseArgs: false, stream: false, net: false, diff --git a/packages/compiler/src/executable/executable-cache.test.ts b/packages/compiler/src/executable/executable-cache.test.ts index 1b42c3eca..cdd24ff7b 100644 --- a/packages/compiler/src/executable/executable-cache.test.ts +++ b/packages/compiler/src/executable/executable-cache.test.ts @@ -45,6 +45,7 @@ const native: EarlyExecutableNativeFeatures = { bigint: false, searchParams: false, qs: false, + dynBuiltinClass: false, parseArgs: false, stream: false, net: false, diff --git a/packages/compiler/src/executable/executable-cache.ts b/packages/compiler/src/executable/executable-cache.ts index 8c67c1006..349c07d42 100644 --- a/packages/compiler/src/executable/executable-cache.ts +++ b/packages/compiler/src/executable/executable-cache.ts @@ -71,6 +71,7 @@ export interface EarlyExecutableNativeFeatures { bigint: boolean; searchParams: boolean; qs: boolean; + dynBuiltinClass: boolean; parseArgs: boolean; stream: boolean; net: boolean; @@ -185,6 +186,7 @@ const BOOLEAN_NATIVE_KEYS = [ "bigint", "searchParams", "qs", + "dynBuiltinClass", "parseArgs", "stream", "net", diff --git a/packages/compiler/src/frontend/lowering/builtins/builtin-class-dyn.ts b/packages/compiler/src/frontend/lowering/builtins/builtin-class-dyn.ts new file mode 100644 index 000000000..ac73924ad --- /dev/null +++ b/packages/compiler/src/frontend/lowering/builtins/builtin-class-dyn.ts @@ -0,0 +1,149 @@ +import { numLit } from "../../../ir/build.js"; +import { BOOL, DYN, RUNTIME_EMITTER_CLASS, type IrExpr, type SrcLoc } from "../../../ir/ir.js"; +import * as ts from "../../ts7/adapter.js"; +import { locOf } from "../../program.js"; +import type { Lowerer } from "../lowerer.js"; + +/* EventEmitter and the stream classes as untyped constructor values, the + * bases of JavaScript constructor functions: + * + * function Bus() { EventEmitter.call(this); } + * util.inherits(Bus, EventEmitter); + * + * A compiled `class Bus extends EventEmitter` gets a native emitter prefix, + * but `new Bus()` on a constructor function builds an untyped object, so + * the base is the runtime's dyn constructor (scr_dyn_builtin_class.c): a + * function whose prototype carries Node's EventEmitter methods over the + * object's own `_events` table. The stream classes have prototype chains + * for util.inherits and instanceof; constructing over them refuses where + * it runs. These values appear only where a constructor function uses its + * base: util.inherits, `Base.call(this, …)` and `Base.apply(this, …)`, + * `Base.prototype` and `instanceof Base` on an untyped value. */ + +/** scr_dyn_builtin_class's kind for a runtime class, or null. */ +export function builtinClassKind(className: string): number | null { + switch (className) { + case RUNTIME_EMITTER_CLASS: + return 0; + case "%Readable": + return 2; + case "%Writable": + return 3; + case "%Duplex": + return 4; + case "%Transform": + return 5; + case "%PassThrough": + return 6; + default: + return null; + } +} + +/** The classes by builtin module member. JavaScript sources bind + * `require("events").EventEmitter` as a module member rather than a class + * value, and `require("stream")` is the legacy Stream constructor. */ +const MODULE_CLASS_KINDS: Readonly>>> = { + events: { EventEmitter: 0, default: 0 }, + stream: { Stream: 1, Readable: 2, Writable: 3, Duplex: 4, Transform: 5, PassThrough: 6 }, +}; + +/** The kind of a builtin module member that is one of those classes. */ +export function builtinMemberClassKind(module: string, member: string): number | null { + return MODULE_CLASS_KINDS[module]?.[member] ?? null; +} + +function unparenthesized(node: ts.Expression): ts.Expression { + let current = node; + while (ts.isParenthesizedExpression(current)) current = current.expression; + return current; +} + +/** The kind of a node that names one of those classes: a class value, a + * builtin module member, or the events and stream modules themselves. */ +export function builtinClassKindOf(lowerer: Lowerer, node: ts.Expression): number | null { + const expr = unparenthesized(node); + const mapped = lowerer.mapTypeOf(lowerer.typeOf(expr)); + if (mapped?.kind === "classval") return builtinClassKind(mapped.className); + const member = ts.isIdentifier(expr) + ? lowerer.builtinImportOf(expr) + : ts.isPropertyAccessExpression(expr) + ? lowerer.builtinMemberOf(expr) + : null; + if (member) return MODULE_CLASS_KINDS[member.module]?.[member.member] ?? null; + const module = lowerer.builtinNamespaceModuleOf(expr); + return module === "events" ? 0 : module === "stream" ? 1 : null; +} + +/** Whether evaluating the node can be skipped: a binding or a member of + * one, or of a builtin require. */ +function referenceOnly(node: ts.Expression): boolean { + const expr = unparenthesized(node); + if (ts.isIdentifier(expr)) return true; + if (ts.isPropertyAccessExpression(expr) && !expr.questionDotToken) { + const base = unparenthesized(expr.expression); + return ( + ts.isIdentifier(base) || + (ts.isCallExpression(base) && + ts.isIdentifier(base.expression) && + base.expression.text === "require" && + base.arguments.nodes.length === 1 && + ts.isStringLiteral(base.arguments.nodes[0]!)) + ); + } + return false; +} + +/** The untyped constructor named by a node, or null when it names none of + * those classes. */ +export function builtinClassDynValueOf(lowerer: Lowerer, node: ts.Expression): IrExpr | null { + const kind = builtinClassKindOf(lowerer, node); + if (kind === null) return null; + const loc = locOf(node); + const value = builtinClassValue(kind, loc); + if (referenceOnly(node)) return value; + return { + kind: "seqExpr", + stmts: [{ kind: "exprStmt", expr: lowerer.lowerExpr(node), loc }], + result: value, + type: DYN, + loc, + }; +} + +export function builtinClassValue(kind: number, loc: SrcLoc): IrExpr { + return { kind: "libCall", fn: "dyn.builtinClass", args: [numLit(kind, loc)], type: DYN, loc }; +} + +/** `Base.call(this, …)` / `Base.apply(this, args)` on one of those class + * values: Function.prototype.call/apply over the untyped constructor. */ +export function lowerBuiltinClassCall(lowerer: Lowerer, call: ts.CallExpression): IrExpr | null { + const callee = call.expression; + if (!ts.isPropertyAccessExpression(callee) || callee.questionDotToken) return null; + const method = callee.name.text; + if (method !== "call" && method !== "apply") return null; + if (call.arguments.nodes.some(ts.isSpreadElement)) return null; + const receiver = builtinClassDynValueOf(lowerer, callee.expression); + if (receiver === null) return null; + const loc = locOf(call); + return { + kind: "dynInvoke", + recv: receiver, + method, + calleeName: callee.getText(), + args: call.arguments.nodes.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), + type: DYN, + loc, + }; +} + +/** `value instanceof Base` for an untyped value. */ +export function builtinClassInstanceOf(value: IrExpr, kind: number, loc: SrcLoc): IrExpr { + return { + kind: "libCall", + fn: "dyn.builtinInstanceOf", + args: [value, numLit(kind, loc)], + type: BOOL, + loc, + }; +} diff --git a/packages/compiler/src/frontend/lowering/class-prototypes.ts b/packages/compiler/src/frontend/lowering/class-prototypes.ts index d337dc802..6c6c7811d 100644 --- a/packages/compiler/src/frontend/lowering/class-prototypes.ts +++ b/packages/compiler/src/frontend/lowering/class-prototypes.ts @@ -1,4 +1,5 @@ import { dynUndefinedExpr, varRef } from "../../ir/build.js"; +import { builtinClassKind, builtinClassValue } from "./builtins/builtin-class-dyn.js"; import * as ts from "../ts7/adapter.js"; import { BOOL, @@ -450,6 +451,19 @@ export function lowerClassPrototypeData( exactClassOfReceiver(lowerer, expr.expression) ?? (stored?.kind === "classval" ? lowerer.classes.get(stored.className) : undefined); if (!info) return null; + // EventEmitter.prototype and the stream prototypes: the untyped + // constructor's prototype object (builtin-class-dyn.ts). + const builtinKind = builtinClassKind(info.def.name); + if (builtinKind !== null) { + const loc = locOf(expr); + return { + kind: "dynKeyGet", + value: builtinClassValue(builtinKind, loc), + key: { kind: "strLit", value: "prototype", type: STRING, loc }, + type: DYN, + loc, + }; + } const parent = expr.parent; const descriptorKey = ts.isCallExpression(parent) && diff --git a/packages/compiler/src/frontend/lowering/expressions/identifiers.ts b/packages/compiler/src/frontend/lowering/expressions/identifiers.ts index 2ee56573c..83761d131 100644 --- a/packages/compiler/src/frontend/lowering/expressions/identifiers.ts +++ b/packages/compiler/src/frontend/lowering/expressions/identifiers.ts @@ -1,5 +1,6 @@ /* Identifier references in expression position: lowerExprInner's identifier branch and its helpers. */ import { cjsMemberAliasValueOf } from "../cjs-exports-object.js"; +import { builtinClassValue, builtinMemberClassKind } from "../builtins/builtin-class-dyn.js"; import * as ts from "../../ts7/adapter.js"; import * as posix from "node:path/posix"; import { type Lowerer, PoisonError } from "../lowerer.js"; @@ -524,6 +525,10 @@ export function lowerIdentifierExpr(lowerer: Lowerer, expr: ts.Identifier, loc: // the same identity-token story as stdlib globals above (the // harness adds worker_threads.Worker to its identity Set). if (isJsSourceFile(expr.getSourceFile())) { + // EventEmitter and the stream classes are the runtime's untyped + // constructors, so constructor functions can inherit from them. + const classKind = builtinMemberClassKind(bi.module, bi.member); + if (classKind !== null) return builtinClassValue(classKind, loc); // A function member is a function value that fences when called. if (builtinModuleFnOf(lowerer, bi.module, bi.member)) return builtinFunctionFenceValue(lowerer, bi, expr, loc); diff --git a/packages/compiler/src/frontend/lowering/expressions/relational.ts b/packages/compiler/src/frontend/lowering/expressions/relational.ts index 619c0fe37..8accf2994 100644 --- a/packages/compiler/src/frontend/lowering/expressions/relational.ts +++ b/packages/compiler/src/frontend/lowering/expressions/relational.ts @@ -1,5 +1,6 @@ /* instanceof and in, including private-name and runtime-key in. */ import * as ts from "../../ts7/adapter.js"; +import { builtinClassInstanceOf, builtinClassKind } from "../builtins/builtin-class-dyn.js"; import { checkedPrivateIn, localPrivateBrandClass, @@ -471,6 +472,22 @@ export function lowerInstanceOf(lowerer: Lowerer, expr: ts.BinaryExpression, loc const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN); return checkedClassInstanceOf(lowerer, value, constructor, loc); } + // `this instanceof Glob` in a JavaScript constructor function: the + // function's prototype against the value's prototype chain. + if ( + constructor?.type.kind === "func" && + isJsSourceFile(expr.getSourceFile()) && + lowerer.dynConvertible(constructor.type) + ) { + const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN); + return { + kind: "libCall", + fn: "dyn.functionInstanceOf", + args: [value, { kind: "dynFrom", value: constructor, type: DYN, loc }], + type: BOOL, + loc, + }; + } lowerer.unsupported( "SC1090", expr.right, @@ -579,6 +596,14 @@ export function lowerInstanceOf(lowerer: Lowerer, expr: ts.BinaryExpression, loc loc, }; } + // `u instanceof EventEmitter` (or a stream class): an untyped object + // built by a constructor function inherits the untyped constructor's + // prototype (builtin-class-dyn.ts). Compiled emitters and streams have + // no untyped form, so the prototype chain answers for every value. + const builtinKind = builtinClassKind(target.def.name); + if (left.type.kind === "dyn" && builtinKind !== null) { + return builtinClassInstanceOf(left, builtinKind, loc); + } if (left.type.kind === "dyn") { lowerer.unsupported( "SC1090", diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index ed549e4ff..cc14c74ce 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -1,4 +1,5 @@ import { guardNullProto, nullProtoRecordShape } from "./null-prototype.js"; +import { lowerBuiltinClassCall } from "./builtins/builtin-class-dyn.js"; import { refuseModuleMemberThis } from "./module-member-this.js"; import { lowerUnionEquality, tagEqualityMayMissAlias } from "./strict-equality.js"; import { lowerHashStreamCall } from "./builtins/hash-stream.js"; @@ -263,6 +264,11 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { if (object) return object; } + // `EventEmitter.call(this)` in a constructor function: the untyped + // EventEmitter constructor initializes the receiver. + const builtinClassCall = lowerBuiltinClassCall(lowerer, expr); + if (builtinClassCall) return builtinClassCall; + // require() of a JSON document: the shared parsed object. const json = lowerJsonRequireCall(lowerer, expr); if (json) return json; diff --git a/packages/compiler/src/frontend/lowering/lower-inspect.ts b/packages/compiler/src/frontend/lowering/lower-inspect.ts index 245d1b676..ff5fb495d 100644 --- a/packages/compiler/src/frontend/lowering/lower-inspect.ts +++ b/packages/compiler/src/frontend/lowering/lower-inspect.ts @@ -1,4 +1,5 @@ import { dynUndefinedExpr, boolLit, helperLoc, numLit, strLit, varRef } from "../../ir/build.js"; +import { builtinClassDynValueOf, builtinClassKindOf } from "./builtins/builtin-class-dyn.js"; import { InternalCompilerError } from "../../errors.js"; import * as ts from "../ts7/adapter.js"; @@ -2544,8 +2545,15 @@ function lowerUtilCallableCall( const arity = member === "deprecate" ? 4 : member === "callbackify" ? 1 : 2; // Program classes keep static prototypes: there is no function object // whose prototype chain the runtime could relink or wrap. + // EventEmitter and the stream classes are the exception as superCtor: + // the runtime has untyped constructors for them (builtin-class-dyn.ts). const classArgs = member === "inherits" ? 2 : member === "deprecate" ? 1 : 0; - for (const arg of expr.arguments.nodes.slice(0, classArgs)) { + const builtinBase = + member === "inherits" && expr.arguments.nodes[1] !== undefined + ? builtinClassKindOf(lowerer, expr.arguments.nodes[1]) + : null; + for (const [index, arg] of expr.arguments.nodes.slice(0, classArgs).entries()) { + if (index === 1 && builtinBase !== null) continue; if (lowerer.mapTypeOf(lowerer.typeOf(arg))?.kind === "classval") lowerer.noLowering( `util.${member} over a class constructor`, @@ -2564,9 +2572,12 @@ function lowerUtilCallableCall( const stmts: IrStmt[] = []; const args: IrExpr[] = []; for (let i = 0; i < arity; i++) { - const input: IrExpr = expr.arguments.nodes[i] - ? lowerer.lowerExprExpecting(expr.arguments.nodes[i]!, DYN) - : dynUndefinedExpr(loc); + const node = expr.arguments.nodes[i]; + const input: IrExpr = !node + ? dynUndefinedExpr(loc) + : i === 1 && builtinBase !== null + ? (builtinClassDynValueOf(lowerer, node) ?? lowerer.lowerExprExpecting(node, DYN)) + : lowerer.lowerExprExpecting(node, DYN); const saved = lowerer.declareHiddenLocal("%utilInput", DYN); stmts.push({ kind: "varDecl", localId: saved.id, init: input, loc }); args.push(varRef(saved.id, DYN, loc)); diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 7144e574e..1a050f6c4 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1,4 +1,5 @@ import { jsDynamicDeclarations } from "./js-dynamic-objects.js"; +import { builtinClassValue, builtinMemberClassKind } from "./builtins/builtin-class-dyn.js"; import { lifetimeRegionType, lowerLifetimeRegionCall, @@ -12535,6 +12536,12 @@ export class Lowerer { } // A bare `fs.constants` read (not one of the baked bits above). if (bi.member === "constants" && bi.module === "fs") return fsConstantsObject(loc); + // `stream.Readable` as a JavaScript value: the runtime's untyped + // constructor, the base a constructor function inherits. + if (isJsSourceFile(expr.getSourceFile())) { + const classKind = builtinMemberClassKind(bi.module, bi.member); + if (classKind !== null) return builtinClassValue(classKind, loc); + } if (builtinModuleFnOf(this, bi.module, bi.member)) { this.unsupported( "SC1090", diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index 7d8d88889..05a6f7423 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -543,6 +543,7 @@ async function compileExecutableNative( bigint: features.bigint, searchParams: features.searchParams, qs: features.qs, + dynBuiltinClass: features.dynBuiltinClass, parseArgs: features.parseArgs, stream: features.stream, net: features.net, diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 826151009..1b84c5888 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -556,6 +556,9 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "dyn.objCreateWithProperties", "dyn.getPrototype", "dyn.setPrototype", + // a proxy in the prototype chain can throw + "dyn.builtinInstanceOf", + "dyn.functionInstanceOf", "dyn.getOwnPropertyNames", "dyn.ownKeys", "dyn.getOwnPropertySymbols", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index c55444e60..a3480eb2c 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -3409,6 +3409,16 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "dyn.classPrototype": { argTypes: [DYN, DYN], result: DYN }, "dyn.classBasePrototype": { argTypes: [DYN], result: DYN }, "dyn.classInherit": { argTypes: [DYN, DYN], result: DYN }, + /** EventEmitter (0), Stream (1), Readable (2), Writable (3), Duplex (4), + * Transform (5) and PassThrough (6) as untyped constructor values, one + * per thread (scr_dyn_builtin_class.c). */ + "dyn.builtinClass": { argTypes: [F64], result: DYN }, + /** `value instanceof C` for those constructors, over the value's + * prototype chain. */ + "dyn.builtinInstanceOf": { argTypes: [DYN, F64], result: BOOL }, + /** `value instanceof f` for an untyped constructor function: the + * prototype chain against f.prototype. */ + "dyn.functionInstanceOf": { argTypes: [DYN, DYN], result: BOOL }, "dyn.classSuper": { argTypes: [DYN, DYN, DYN], result: VOID }, "dyn.assignPrototype": { argTypes: [DYN, DYN, DYN], result: DYN }, "dyn.definePrototypeProps": { argTypes: [DYN, DYN, DYN], result: DYN }, diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 9abe15345..de91b4b78 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -222,6 +222,8 @@ const CHILD_PROCESS_LIB_PREFIXES: readonly string[] = ["child.", "cp.", "spawnRe /** Entry points that link the symbol unit, besides the sym. and disposable. families. */ const SYMBOL_LIB_FNS: ReadonlySet = new Set([ + // EventEmitter's kShapeMode and kCapture properties + "dyn.builtinClass", "dyn.usingDispose", "dyn.usingMethod", "util.isDeepStrictEqual", @@ -490,9 +492,16 @@ const RUNTIME_FEATURE_RULES = { (node.name === "promise.allSettled" || node.name === "promise.any")) || (node.kind === "dynFrom" && boxesPromise(node.value.type, tables(), new Set())), }), + /** EventEmitter and the stream classes as untyped constructor values + * (scr_dyn_builtin_class.c), which call listeners through the dyn-invoke + * unit, render unhandled 'error' payloads through the inspect unit and + * create EventEmitter's private symbols through the symbol unit. */ + dynBuiltinClass: rule({ + fns: ["dyn.builtinClass", "dyn.builtinInstanceOf", "dyn.functionInstanceOf"], + }), dynInvoke: rule({ initial: (mod) => mod.workers === true, - fns: [...DYN_INVOKE_LIB_FNS, ...UTIL_CALLABLE_LIB_FNS], + fns: [...DYN_INVOKE_LIB_FNS, ...UTIL_CALLABLE_LIB_FNS, "dyn.builtinClass"], expr: (node, _tables) => node.kind === "dynInvoke", }), /** The program has dynamic-tier jsval operations (js.* builtins, the @@ -534,7 +543,13 @@ const RUNTIME_FEATURE_RULES = { * terminal unit prints completion errors through it when there is a * completer. */ inspect: rule({ - fns: ["global.native", "util.styleText", "crypto.cipherNew", ...UTIL_CALLABLE_LIB_FNS], + fns: [ + "global.native", + "util.styleText", + "crypto.cipherNew", + "dyn.builtinClass", + ...UTIL_CALLABLE_LIB_FNS, + ], prefixes: ["insp.", "console.", "test."], libCall: (node) => node.fn === "rl.terminal" && !isDynUndefined(node.args[3]!), }), @@ -637,6 +652,7 @@ function noRuntimeFeatures(): RuntimeFeatures { dc: false, dgram: false, dynAsync: false, + dynBuiltinClass: false, dynInvoke: false, dynTier: false, emitter: false, diff --git a/packages/compiler/src/native/cli.ts b/packages/compiler/src/native/cli.ts index 7d00acbc8..ce11aadf6 100644 --- a/packages/compiler/src/native/cli.ts +++ b/packages/compiler/src/native/cli.ts @@ -89,6 +89,7 @@ async function main(): Promise { bigint: false, searchParams: false, qs: false, + dynBuiltinClass: false, parseArgs: false, stream: false, net: false, diff --git a/packages/compiler/src/native/prepare.ts b/packages/compiler/src/native/prepare.ts index 54100a413..b95b978ff 100644 --- a/packages/compiler/src/native/prepare.ts +++ b/packages/compiler/src/native/prepare.ts @@ -143,6 +143,7 @@ function validFeatures(value: unknown): value is NativeLinkFeatures { "bigint", "searchParams", "qs", + "dynBuiltinClass", "parseArgs", "stream", "net", diff --git a/packages/compiler/src/native/sanitizer.test.ts b/packages/compiler/src/native/sanitizer.test.ts index 6ca84af6f..bbd07a6cd 100644 --- a/packages/compiler/src/native/sanitizer.test.ts +++ b/packages/compiler/src/native/sanitizer.test.ts @@ -95,6 +95,7 @@ test.skipIf(process.platform !== "linux" && process.platform !== "darwin")( bigint: false, searchParams: false, qs: false, + dynBuiltinClass: false, parseArgs: false, stream: false, net: false, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6453-constructor-function-emitter.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6453-constructor-function-emitter.cjs.json new file mode 100644 index 000000000..ae5c0050e --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6453-constructor-function-emitter.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6453-constructor-function-emitter.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6454-constructor-function-stream-bases.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6454-constructor-function-stream-bases.cjs.json new file mode 100644 index 000000000..bc48a7f35 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6454-constructor-function-stream-bases.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6454-constructor-function-stream-bases.cjs" + ], + "diags": [] +} diff --git a/packages/runtime-pack-common/runtime-pack-matrix.mjs b/packages/runtime-pack-common/runtime-pack-matrix.mjs index 1e959eccc..a6b11f53e 100644 --- a/packages/runtime-pack-common/runtime-pack-matrix.mjs +++ b/packages/runtime-pack-common/runtime-pack-matrix.mjs @@ -88,6 +88,10 @@ export const OPTIONAL_RUNTIME_SOURCES = [ ["scr_util_compare.c", all("parseArgs", "symbol")], ["scr_util_style.c", all("parseArgs", "inspect", "dynAsync")], ["scr_util_callable.c", all("parseArgs", "inspect", "dynAsync", "dynInvoke", "regex")], + // Untyped EventEmitter and stream constructor values call listeners + // through the dyn-invoke unit, inspect unhandled 'error' payloads and + // create EventEmitter's private symbols. + ["scr_dyn_builtin_class.c", all("dynBuiltinClass", "inspect", "dynInvoke", "symbol")], ["scr_stream.c", "stream"], // The zlib stream classes reference both the zlib engine and the stream unit. ["scr_zlib_stream.c", all("zlib", "stream")], diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index a3d506a10..91919b641 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -1116,6 +1116,12 @@ ScrDyn *scr_dyn_define_prototype_props(ScrDyn *target, ScrDyn *descs, ScrDyn *pr * must be static literals (the box never frees them; name may be NULL). */ ScrDyn *scr_dyn_new_func(ScrClosure *clo, ScrDynThunk thunk, uint32_t arity, const char *sig, const char *name); ScrDyn *scr_dyn_new_class(ScrClassObj *cls, const char *type_key); +/* EventEmitter and the stream constructors as untyped constructor values, + * and instanceof over untyped constructor functions + * (scr_dyn_builtin_class.c, linked with the dynBuiltinClass feature). */ +ScrDyn *scr_dyn_builtin_class(double kind); +bool scr_dyn_builtin_instanceof(ScrDyn *value, double kind); +bool scr_dyn_function_instanceof(ScrDyn *value, ScrDyn *callee); bool scr_dyn_class_is_key(const ScrDyn *value, const ScrStr *type_key); bool scr_dyn_class_is(const ScrDyn *value, const char *type_key); /* Calls a dyn value: a non-function kind throws the catchable TypeError diff --git a/packages/runtime/src/scr_dyn_builtin_class.c b/packages/runtime/src/scr_dyn_builtin_class.c new file mode 100644 index 000000000..76a7ab15e --- /dev/null +++ b/packages/runtime/src/scr_dyn_builtin_class.c @@ -0,0 +1,1469 @@ +/* EventEmitter and the node:stream constructors as checked-dynamic + * constructor values. JavaScript constructor functions inherit from them + * the pre-class way: + * + * function Bus() { EventEmitter.call(this); } + * util.inherits(Bus, EventEmitter); + * + * A compiled EventEmitter instance keeps its listeners in native state, but + * the receiver here is an ordinary dyn object built by `new Bus()`. So the + * EventEmitter value is a native function whose prototype carries Node's + * lib/events.js methods over that object's own `_events`, `_eventsCount` + * and `_maxListeners` properties, the state Node's own implementation + * keeps there. Calling it with a receiver runs EventEmitter.init. + * + * Stream is Node's legacy constructor: EventEmitter.call(this, opts) and a + * prototype that inherits EventEmitter's. Readable, Writable, Duplex, + * Transform and PassThrough have prototypes chained as in Node, so + * util.inherits onto them and instanceof work, but their native state has + * no dyn object form: calling one with a receiver throws the "not + * supported yet" Error where the construction runs. + * + * One constructor per kind and thread, so every boxing of the same class + * value is the same function. All arguments are borrowed. */ +#include "scr_runtime.h" + +#include +#include +#include + +#ifdef _WIN32 +#include +#define BC_PID() ((long)_getpid()) +#else +#include +#define BC_PID() ((long)getpid()) +#endif + +enum { + BC_EMITTER, + BC_STREAM, + BC_READABLE, + BC_WRITABLE, + BC_DUPLEX, + BC_TRANSFORM, + BC_PASSTHROUGH, + BC_COUNT +}; + +static const char *const bc_names[BC_COUNT] = { + "EventEmitter", "Stream", "Readable", "Writable", "Duplex", "Transform", "PassThrough", +}; + +static SCR_TL ScrDyn *bc_ctors[BC_COUNT]; +static SCR_TL bool bc_teardown_registered; +/* Node's private kShapeMode and kCapture symbols, which util.inspect shows + * on every emitter as Symbol(shapeMode) and Symbol(kCapture). */ +enum { BC_SHAPE_MODE, BC_CAPTURE, BC_SYMBOLS }; +static SCR_TL ScrDyn *bc_symbols[BC_SYMBOLS]; + +static ScrDyn *bc_class(int kind); + +/* ── property helpers ───────────────────────────────────────────────── */ + +static ScrDyn *bc_key(const char *name) { + ScrStr *text = scr_str_new(name, strlen(name)); + ScrDyn *key = scr_dyn_new_str(text); + scr_str_release(text); + return key; +} + +/* object[key] with object as the receiver: +1, or NULL with an exception + * pending. */ +static ScrDyn *bc_get_key(ScrDyn *object, ScrDyn *key) { + ScrDyn *value = scr_dyn_reflect_get(object, key, object); + if (!value && !scr_exc_pending()) value = scr_dyn_retain(scr_dyn_undefined()); + return value; +} + +static ScrDyn *bc_get(ScrDyn *object, const char *name) { + ScrDyn *key = bc_key(name); + ScrDyn *value = bc_get_key(object, key); + scr_dyn_release(key); + return value; +} + +/* object[key] = value; the value moves in. False with an exception + * pending. */ +static bool bc_set_key(ScrDyn *object, ScrDyn *key, ScrDyn *value) { + scr_dyn_key_set_computed(object, key, value); + scr_dyn_release(value); + return !scr_exc_pending(); +} + +static bool bc_set(ScrDyn *object, const char *name, ScrDyn *value) { + ScrDyn *key = bc_key(name); + bool ok = bc_set_key(object, key, value); + scr_dyn_release(key); + return ok; +} + +static bool bc_undefined(const ScrDyn *value) { + return value->kind == SCR_DYN_UNDEF; +} + +static double bc_number(const ScrDyn *value) { + return value->kind == SCR_DYN_NUM ? value->v.num : 0; +} + +/* receiver.method(...args), dispatched through the receiver's own lookup + * like Node's `this.emit(...)`. +1 or NULL. */ +static ScrDyn *bc_invoke(ScrDyn *receiver, const char *method, ScrDyn *const *args, size_t argc) { + ScrDyn *fn = bc_get(receiver, method); + if (!fn) return NULL; + scr_dyn_this_push_dyn(receiver); + ScrDyn *result = scr_dyn_call(fn, args, argc, method); + scr_dyn_this_pop(); + scr_dyn_release(fn); + return result; +} + +static ScrDyn *bc_apply(ScrDyn *fn, ScrDyn *receiver, ScrDyn *const *args, size_t argc) { + scr_dyn_this_push_dyn(receiver); + ScrDyn *result = scr_dyn_call(fn, args, argc, "listener"); + scr_dyn_this_pop(); + return result; +} + +/* Listener lists are replaced rather than mutated: a fresh array with item + * first, or without the item at index. Node mutates its array in place, + * which nothing outside the emitter observes (emit iterates a copy and + * listeners() answers one). A leak warning already given stays given. */ +static ScrDyn *bc_list_copy(ScrDyn *list, ScrDyn *first, double skip) { + ScrDyn *copy = scr_dyn_new_arr(); + if (first) scr_dyn_arr_push(copy, scr_dyn_retain(first)); + double length = scr_dyn_arr_len(list); + for (double i = 0; i < length; i++) { + if (i == skip) continue; + ScrDyn *item = scr_dyn_index_get(list, i); + if (!item) { + scr_dyn_release(copy); + return NULL; + } + scr_dyn_arr_push(copy, item); + } + ScrDyn *warned = bc_get(list, "warned"); + if (!warned || (scr_dyn_truthy(warned) && !bc_set(copy, "warned", scr_dyn_new_bool(true)))) { + if (warned) scr_dyn_release(warned); + scr_dyn_release(copy); + return NULL; + } + scr_dyn_release(warned); + return copy; +} + +static ScrDyn *bc_unused_args[1]; + +static ScrDyn *bc_arg(ScrDyn *const *args, size_t argc, size_t index) { + return index < argc ? args[index] : scr_dyn_undefined(); +} + +/* The receiver of a prototype method call, +1. Methods called without one + * (an extracted `emitter.on`) read `this` as undefined, as in strict code. */ +static ScrDyn *bc_this(void) { + return scr_dyn_this_get(); +} + +static bool bc_require_object(ScrDyn *self, const char *reading) { + if (self->kind != SCR_DYN_UNDEF && self->kind != SCR_DYN_NULL) return true; + char message[96]; + snprintf(message, sizeof message, "Cannot read properties of %s (reading '%s')", + self->kind == SCR_DYN_NULL ? "null" : "undefined", reading); + scr_throw_error_msg(SCR_ERR_TYPE, message, strlen(message)); + return false; +} + +static bool bc_check_listener(const ScrDyn *listener) { + if (scr_dyn_is_callable(listener)) return true; + scr_dyn_arg_type_fail("listener", "of type function", listener); + return false; +} + +static void bc_teardown(void); + +static ScrDyn *bc_symbol(int which) { + if (!bc_symbols[which]) { + if (!bc_teardown_registered) { + bc_teardown_registered = true; + scr_atexit(bc_teardown); + } + const char *name = which == BC_SHAPE_MODE ? "shapeMode" : "kCapture"; + ScrStr *description = scr_str_new(name, strlen(name)); + ScrSym *symbol = scr_sym_new(description); + scr_str_release(description); + bc_symbols[which] = scr_dyn_new_symbol(symbol); + scr_sym_release(symbol); + } + return bc_symbols[which]; +} + +/* ── EventEmitter.init ──────────────────────────────────────────────── */ + +/* `_events` is fresh unless the receiver already has its own (Node's + * shapeMode, a subclass that pre-populates it); `_maxListeners` keeps a + * value set before the call. */ +static bool bc_emitter_init(ScrDyn *self, ScrDyn *opts) { + if (!bc_require_object(self, "_events")) return false; + ScrDyn *events = bc_get(self, "_events"); + if (!events) return false; + bool fresh = bc_undefined(events); + if (!fresh) { + ScrDyn *proto = scr_dyn_get_prototype(self); + if (!proto) { + scr_dyn_release(events); + return false; + } + if (proto->kind != SCR_DYN_NULL) { + ScrDyn *inherited = bc_get(proto, "_events"); + if (!inherited) { + scr_dyn_release(proto); + scr_dyn_release(events); + return false; + } + fresh = scr_dyn_strict_eq(events, inherited); + scr_dyn_release(inherited); + } + scr_dyn_release(proto); + } + scr_dyn_release(events); + if (fresh) { + if (!bc_set(self, "_events", scr_dyn_new_obj_null_proto())) return false; + if (!bc_set(self, "_eventsCount", scr_dyn_new_num(0))) return false; + } + if (!bc_set_key(self, bc_symbol(BC_SHAPE_MODE), scr_dyn_new_bool(!fresh))) return false; + ScrDyn *max = bc_get(self, "_maxListeners"); + if (!max) return false; + bool keep = scr_dyn_truthy(max); + if (!bc_set(self, "_maxListeners", keep ? max : (scr_dyn_release(max), scr_dyn_retain(scr_dyn_undefined())))) + return false; + if (opts->kind != SCR_DYN_UNDEF && opts->kind != SCR_DYN_NULL) { + ScrDyn *capture = bc_get(opts, "captureRejections"); + if (!capture) return false; + bool requested = !bc_undefined(capture); + if (requested && capture->kind != SCR_DYN_BOOL) { + scr_dyn_arg_type_fail("options.captureRejections", "of type boolean", capture); + scr_dyn_release(capture); + return false; + } + bool enabled = requested && capture->v.b; + scr_dyn_release(capture); + if (enabled) { + static const char message[] = "EventEmitter captureRejections on a constructor function is not supported yet"; + scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020"); + return false; + } + } + return bc_set_key(self, bc_symbol(BC_CAPTURE), scr_dyn_new_bool(false)); +} + +/* ── listener bookkeeping (lib/events.js) ───────────────────────────── */ + +static double bc_max_listeners(ScrDyn *self) { + ScrDyn *max = bc_get(self, "_maxListeners"); + if (!max) return -1; + double value; + if (bc_undefined(max)) { + ScrDyn *fallback = bc_get(bc_class(BC_EMITTER), "defaultMaxListeners"); + value = fallback ? bc_number(fallback) : 10; + if (fallback) scr_dyn_release(fallback); + } else { + value = bc_number(max); + } + scr_dyn_release(max); + return value; +} + +static void bc_warn_tick(ScrClosure *self) { + ScrStr *message = (ScrStr *)scr_box_get_ref(self->caps[0]); + if (scr_warning_emit_hook) { + scr_warning_emit_hook("MaxListenersExceededWarning", NULL, message); + } else { + fflush(stdout); + fprintf(stderr, "(node:%ld) MaxListenersExceededWarning: %.*s\n", BC_PID(), + (int)message->len, message->data); + if (!scr_warning_trace_hint_shown) { + scr_warning_trace_hint_shown = true; + fputs("(Use `node --trace-warnings ...` to show where the warning was created)\n", stderr); + } + } + scr_str_release(message); +} + +/* The constructor name util.inspect prints at depth -1: `[Bus]`. */ +static ScrStr *bc_constructor_name(ScrDyn *self) { + ScrDyn *ctor = bc_get(self, "constructor"); + ScrStr *name = NULL; + if (ctor && scr_dyn_is_callable(ctor)) { + ScrDyn *text = bc_get(ctor, "name"); + if (text && text->kind == SCR_DYN_STR && text->v.str->len) name = scr_str_retain(text->v.str); + if (text) scr_dyn_release(text); + } + if (ctor) scr_dyn_release(ctor); + if (scr_exc_pending()) scr_exc_clear(); + return name ? name : scr_str_new("Object", 6); +} + +static void bc_warn_leak(ScrDyn *self, ScrDyn *type, double count, double max) { + char counted[32], limit[32]; + snprintf(counted, sizeof counted, "%g", count); + snprintf(limit, sizeof limit, "%g", max); + ScrStr *event = scr_dyn_string_coerce_js(type); + if (!event) { + scr_exc_clear(); + event = scr_str_new("", 0); + } + ScrStr *cls = bc_constructor_name(self); + ScrJsonBuf text; + scr_jb_init(&text); + scr_jb_puts(&text, "Possible EventEmitter memory leak detected. "); + scr_jb_puts(&text, counted); + scr_jb_putc(&text, ' '); + scr_jb_put_str(&text, event); + scr_jb_puts(&text, " listeners added to ["); + scr_jb_put_str(&text, cls); + scr_jb_puts(&text, "]. MaxListeners is "); + scr_jb_puts(&text, limit); + scr_jb_puts(&text, ". Use emitter.setMaxListeners() to increase limit"); + scr_str_release(event); + scr_str_release(cls); + ScrClosure *tick = scr_closure_new((void *)&bc_warn_tick, 1); + ScrBox *box = scr_box_new(SCR_BOX_STR); + scr_box_set_ref(box, scr_jb_finish(&text)); + tick->caps[0] = box; + scr_next_tick(tick); +} + +/* _addListener(target, type, listener, prepend): +1 target or NULL. */ +static ScrDyn *bc_add_listener(ScrDyn *self, ScrDyn *type, ScrDyn *listener, bool prepend) { + if (!bc_check_listener(listener)) return NULL; + ScrDyn *events = bc_get(self, "_events"); + if (!events) return NULL; + ScrDyn *existing = NULL; + if (bc_undefined(events)) { + scr_dyn_release(events); + events = scr_dyn_new_obj_null_proto(); + if (!bc_set(self, "_events", scr_dyn_retain(events)) || !bc_set(self, "_eventsCount", scr_dyn_new_num(0))) + goto fail; + } else { + ScrDyn *watcher = bc_get(events, "newListener"); + if (!watcher) goto fail; + bool watched = !bc_undefined(watcher); + scr_dyn_release(watcher); + if (watched) { + ScrDyn *inner = bc_get(listener, "listener"); + if (!inner) goto fail; + ScrDyn *name = bc_key("newListener"); + ScrDyn *args[3] = { name, type, bc_undefined(inner) || inner->kind == SCR_DYN_NULL ? listener : inner }; + ScrDyn *emitted = bc_invoke(self, "emit", args, 3); + scr_dyn_release(name); + scr_dyn_release(inner); + if (!emitted) goto fail; + scr_dyn_release(emitted); + /* the listener may have replaced _events */ + scr_dyn_release(events); + events = bc_get(self, "_events"); + if (!events) return NULL; + } + existing = bc_get_key(events, type); + if (!existing) goto fail; + } + if (!existing || bc_undefined(existing)) { + if (!bc_set_key(events, type, scr_dyn_retain(listener))) goto fail; + ScrDyn *count = bc_get(self, "_eventsCount"); + if (!count) goto fail; + double next = bc_number(count) + 1; + scr_dyn_release(count); + if (!bc_set(self, "_eventsCount", scr_dyn_new_num(next))) goto fail; + } else { + if (scr_dyn_is_callable(existing)) { + ScrDyn *list = scr_dyn_new_arr(); + scr_dyn_arr_push(list, scr_dyn_retain(prepend ? listener : existing)); + scr_dyn_arr_push(list, scr_dyn_retain(prepend ? existing : listener)); + if (!bc_set_key(events, type, scr_dyn_retain(list))) { + scr_dyn_release(list); + goto fail; + } + scr_dyn_release(existing); + existing = list; + } else if (prepend) { + ScrDyn *list = bc_list_copy(existing, listener, -1); + if (!list) goto fail; + if (!bc_set_key(events, type, scr_dyn_retain(list))) { + scr_dyn_release(list); + goto fail; + } + scr_dyn_release(existing); + existing = list; + } else if (existing->kind == SCR_DYN_ARR) { + scr_dyn_arr_push(existing, scr_dyn_retain(listener)); + } + double max = bc_max_listeners(self); + if (scr_exc_pending()) goto fail; + double length = existing->kind == SCR_DYN_ARR ? scr_dyn_arr_len(existing) : 0; + if (max > 0 && length > max) { + ScrDyn *warned = bc_get(existing, "warned"); + if (!warned) goto fail; + bool already = scr_dyn_truthy(warned); + scr_dyn_release(warned); + if (!already) { + if (!bc_set(existing, "warned", scr_dyn_new_bool(true))) goto fail; + bc_warn_leak(self, type, length, max); + } + } + } + if (existing) scr_dyn_release(existing); + scr_dyn_release(events); + return scr_dyn_retain(self); +fail: + if (existing) scr_dyn_release(existing); + scr_dyn_release(events); + return NULL; +} + +/* removeListener(type, listener): +1 self or NULL. */ +static ScrDyn *bc_remove_listener(ScrDyn *self, ScrDyn *type, ScrDyn *listener) { + if (!bc_check_listener(listener)) return NULL; + ScrDyn *events = bc_get(self, "_events"); + if (!events) return NULL; + if (bc_undefined(events)) { + scr_dyn_release(events); + return scr_dyn_retain(self); + } + ScrDyn *list = bc_get_key(events, type); + if (!list) goto fail_events; + if (bc_undefined(list)) { + scr_dyn_release(list); + scr_dyn_release(events); + return scr_dyn_retain(self); + } + ScrDyn *wrapped = scr_dyn_is_callable(list) ? bc_get(list, "listener") : NULL; + if (scr_exc_pending()) goto fail_list; + bool match = scr_dyn_is_callable(list) && + (scr_dyn_strict_eq(list, listener) || (wrapped && scr_dyn_strict_eq(wrapped, listener))); + if (match) { + ScrDyn *count = bc_get(self, "_eventsCount"); + if (!count) goto fail_wrapped; + double left = bc_number(count) - 1; + scr_dyn_release(count); + if (!bc_set(self, "_eventsCount", scr_dyn_new_num(left))) goto fail_wrapped; + ScrDyn *shaped = bc_get_key(self, bc_symbol(BC_SHAPE_MODE)); + if (!shaped) goto fail_wrapped; + bool shape_mode = scr_dyn_truthy(shaped); + scr_dyn_release(shaped); + if (shape_mode) { + if (!bc_set_key(events, type, scr_dyn_retain(scr_dyn_undefined()))) goto fail_wrapped; + } else if (left == 0) { + if (!bc_set(self, "_events", scr_dyn_new_obj_null_proto())) goto fail_wrapped; + } else { + scr_dyn_key_delete_computed(events, type, false); + if (scr_exc_pending()) goto fail_wrapped; + ScrDyn *watcher = bc_get(events, "removeListener"); + if (!watcher) goto fail_wrapped; + bool watched = scr_dyn_truthy(watcher); + scr_dyn_release(watcher); + if (watched) { + ScrDyn *name = bc_key("removeListener"); + ScrDyn *args[3] = { name, type, wrapped && scr_dyn_truthy(wrapped) ? wrapped : listener }; + ScrDyn *emitted = bc_invoke(self, "emit", args, 3); + scr_dyn_release(name); + if (!emitted) goto fail_wrapped; + scr_dyn_release(emitted); + } + } + } else if (list->kind == SCR_DYN_ARR) { + double length = scr_dyn_arr_len(list); + double position = -1; + for (double i = length - 1; i >= 0; i--) { + ScrDyn *item = scr_dyn_index_get(list, i); + if (!item) goto fail_wrapped; + bool same = scr_dyn_strict_eq(item, listener); + if (!same && scr_dyn_is_callable(item)) { + ScrDyn *inner = bc_get(item, "listener"); + if (!inner) { + scr_dyn_release(item); + goto fail_wrapped; + } + same = scr_dyn_strict_eq(inner, listener); + scr_dyn_release(inner); + } + scr_dyn_release(item); + if (same) { + position = i; + break; + } + } + if (position >= 0) { + ScrDyn *rest = bc_list_copy(list, NULL, position); + if (!rest) goto fail_wrapped; + ScrDyn *stored = scr_dyn_arr_len(rest) == 1 ? scr_dyn_index_get(rest, 0) : scr_dyn_retain(rest); + scr_dyn_release(rest); + if (!stored || !bc_set_key(events, type, stored)) goto fail_wrapped; + ScrDyn *watcher = bc_get(events, "removeListener"); + if (!watcher) goto fail_wrapped; + bool watched = !bc_undefined(watcher); + scr_dyn_release(watcher); + if (watched) { + ScrDyn *name = bc_key("removeListener"); + ScrDyn *args[3] = { name, type, listener }; + ScrDyn *emitted = bc_invoke(self, "emit", args, 3); + scr_dyn_release(name); + if (!emitted) goto fail_wrapped; + scr_dyn_release(emitted); + } + } + } + if (wrapped) scr_dyn_release(wrapped); + scr_dyn_release(list); + scr_dyn_release(events); + return scr_dyn_retain(self); +fail_wrapped: + if (wrapped) scr_dyn_release(wrapped); +fail_list: + scr_dyn_release(list); +fail_events: + scr_dyn_release(events); + return NULL; +} + +/* ── once wrappers ──────────────────────────────────────────────────── */ + +enum { BC_ONCE_FIRED, BC_ONCE_TARGET, BC_ONCE_TYPE, BC_ONCE_LISTENER, BC_ONCE_SELF, BC_ONCE_CAPS }; + +static ScrBox *bc_box(ScrDyn *value /* moves in */) { + ScrBox *box = scr_box_new_obj(scr_dyn_retain_v, scr_dyn_release_v, scr_dyn_trace_v); + scr_box_set_ref(box, value); + return box; +} + +static ScrDyn *bc_cap(ScrClosure *closure, size_t index) { + return scr_box_get_ref(closure->caps[index]); /* +1 */ +} + +/* onceWrapper: the first call removes the wrapper, then calls the listener + * with the target as its receiver. The wrapper's reference to itself is + * dropped when it fires, so a fired wrapper holds no cycle. */ +static ScrDyn *bc_once_call(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + if (scr_box_get_f64(closure->caps[BC_ONCE_FIRED]) != 0) return scr_dyn_retain(scr_dyn_undefined()); + ScrDyn *target = bc_cap(closure, BC_ONCE_TARGET); + ScrDyn *type = bc_cap(closure, BC_ONCE_TYPE); + ScrDyn *listener = bc_cap(closure, BC_ONCE_LISTENER); + ScrDyn *self = bc_cap(closure, BC_ONCE_SELF); + ScrDyn *result = NULL; + ScrDyn *removal[2] = { type, self }; + ScrDyn *removed = bc_invoke(target, "removeListener", removal, 2); + if (removed) { + scr_dyn_release(removed); + scr_box_set_f64(closure->caps[BC_ONCE_FIRED], 1); + scr_box_set_ref(closure->caps[BC_ONCE_SELF], scr_dyn_retain(scr_dyn_undefined())); + result = bc_apply(listener, target, args, argc); + } + scr_dyn_release(self); + scr_dyn_release(listener); + scr_dyn_release(type); + scr_dyn_release(target); + return result; +} + +static ScrDyn *bc_once_wrap(ScrDyn *target, ScrDyn *type, ScrDyn *listener) { + ScrClosure *closure = scr_closure_new(NULL, BC_ONCE_CAPS); + closure->caps[BC_ONCE_FIRED] = scr_box_new(SCR_BOX_F64); + closure->caps[BC_ONCE_TARGET] = bc_box(scr_dyn_retain(target)); + closure->caps[BC_ONCE_TYPE] = bc_box(scr_dyn_retain(type)); + closure->caps[BC_ONCE_LISTENER] = bc_box(scr_dyn_retain(listener)); + closure->caps[BC_ONCE_SELF] = bc_box(scr_dyn_retain(scr_dyn_undefined())); + scr_closure_retain(closure); + ScrDyn *wrapper = scr_dyn_new_func(closure, bc_once_call, 0, "native:events", "bound onceWrapper"); + scr_box_set_ref(closure->caps[BC_ONCE_SELF], scr_dyn_retain(wrapper)); + scr_closure_release(closure); + if (!bc_set(wrapper, "listener", scr_dyn_retain(listener))) { + scr_dyn_release(wrapper); + return NULL; + } + return wrapper; +} + +/* ── EventEmitter.prototype ─────────────────────────────────────────── */ + +static ScrDyn *bc_on(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + ScrDyn *self = bc_this(); + ScrDyn *result = bc_require_object(self, "_events") + ? bc_add_listener(self, bc_arg(args, argc, 0), bc_arg(args, argc, 1), false) : NULL; + scr_dyn_release(self); + return result; +} + +static ScrDyn *bc_prepend(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + ScrDyn *self = bc_this(); + ScrDyn *result = bc_require_object(self, "_events") + ? bc_add_listener(self, bc_arg(args, argc, 0), bc_arg(args, argc, 1), true) : NULL; + scr_dyn_release(self); + return result; +} + +static ScrDyn *bc_once_common(ScrDyn *const *args, size_t argc, bool prepend) { + ScrDyn *self = bc_this(); + ScrDyn *type = bc_arg(args, argc, 0); + ScrDyn *listener = bc_arg(args, argc, 1); + ScrDyn *result = NULL; + if (bc_check_listener(listener) && bc_require_object(self, "_events")) { + ScrDyn *wrapper = bc_once_wrap(self, type, listener); + if (wrapper) { + result = bc_add_listener(self, type, wrapper, prepend); + scr_dyn_release(wrapper); + } + } + scr_dyn_release(self); + return result; +} + +static ScrDyn *bc_once(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + return bc_once_common(args, argc, false); +} + +static ScrDyn *bc_prepend_once(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + return bc_once_common(args, argc, true); +} + +static ScrDyn *bc_off(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + ScrDyn *self = bc_this(); + ScrDyn *result = bc_require_object(self, "_events") + ? bc_remove_listener(self, bc_arg(args, argc, 0), bc_arg(args, argc, 1)) : NULL; + scr_dyn_release(self); + return result; +} + +/* removeAllListeners(type?): with no 'removeListener' watcher the table is + * reset; otherwise every listener is removed through removeListener, last + * first, so the watcher sees each one (and itself last). */ +static ScrDyn *bc_remove_all(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + ScrDyn *self = bc_this(); + if (!bc_require_object(self, "_events")) { + scr_dyn_release(self); + return NULL; + } + ScrDyn *type = bc_arg(args, argc, 0); + bool all = argc == 0; + ScrDyn *events = bc_get(self, "_events"); + ScrDyn *watcher = NULL; + if (!events) goto fail; + if (bc_undefined(events)) goto done; + watcher = bc_get(events, "removeListener"); + if (!watcher) goto fail; + if (bc_undefined(watcher)) { + if (all) { + if (!bc_set(self, "_events", scr_dyn_new_obj_null_proto()) || !bc_set(self, "_eventsCount", scr_dyn_new_num(0))) + goto fail; + } else { + ScrDyn *present = bc_get_key(events, type); + if (!present) goto fail; + bool has = !bc_undefined(present); + scr_dyn_release(present); + if (has) { + ScrDyn *count = bc_get(self, "_eventsCount"); + if (!count) goto fail; + double left = bc_number(count) - 1; + scr_dyn_release(count); + if (left == 0) { + if (!bc_set(self, "_events", scr_dyn_new_obj_null_proto()) || !bc_set(self, "_eventsCount", scr_dyn_new_num(0))) + goto fail; + } else { + if (!bc_set(self, "_eventsCount", scr_dyn_new_num(left))) goto fail; + scr_dyn_key_delete_computed(events, type, false); + if (scr_exc_pending()) goto fail; + } + } + } + goto done; + } + if (all) { + ScrDyn *keys = scr_dyn_own_keys(events); + if (!keys) goto fail; + double length = scr_dyn_arr_len(keys); + for (double i = 0; i < length; i++) { + ScrDyn *key = scr_dyn_index_get(keys, i); + if (!key) { + scr_dyn_release(keys); + goto fail; + } + bool skip = key->kind == SCR_DYN_STR && key->v.str->len == 14 && memcmp(key->v.str->data, "removeListener", 14) == 0; + ScrDyn *done_key = NULL; + if (!skip) { + ScrDyn *one[1] = { key }; + done_key = bc_invoke(self, "removeAllListeners", one, 1); + } + scr_dyn_release(key); + if (!skip && !done_key) { + scr_dyn_release(keys); + goto fail; + } + if (done_key) scr_dyn_release(done_key); + } + scr_dyn_release(keys); + ScrDyn *name = bc_key("removeListener"); + ScrDyn *one[1] = { name }; + ScrDyn *cleared = bc_invoke(self, "removeAllListeners", one, 1); + scr_dyn_release(name); + if (!cleared) goto fail; + scr_dyn_release(cleared); + if (!bc_set(self, "_events", scr_dyn_new_obj_null_proto()) || !bc_set(self, "_eventsCount", scr_dyn_new_num(0))) + goto fail; + goto done; + } + { + ScrDyn *listeners = bc_get_key(events, type); + if (!listeners) goto fail; + if (scr_dyn_is_callable(listeners)) { + ScrDyn *pair[2] = { type, listeners }; + ScrDyn *removed = bc_invoke(self, "removeListener", pair, 2); + scr_dyn_release(listeners); + if (!removed) goto fail; + scr_dyn_release(removed); + } else if (listeners->kind == SCR_DYN_ARR) { + for (double i = scr_dyn_arr_len(listeners) - 1; i >= 0; i--) { + ScrDyn *item = scr_dyn_index_get(listeners, i); + if (!item) { + scr_dyn_release(listeners); + goto fail; + } + ScrDyn *pair[2] = { type, item }; + ScrDyn *removed = bc_invoke(self, "removeListener", pair, 2); + scr_dyn_release(item); + if (!removed) { + scr_dyn_release(listeners); + goto fail; + } + scr_dyn_release(removed); + } + scr_dyn_release(listeners); + } else { + scr_dyn_release(listeners); + } + } +done: + if (watcher) scr_dyn_release(watcher); + if (events) scr_dyn_release(events); + return self; +fail: + if (watcher) scr_dyn_release(watcher); + if (events) scr_dyn_release(events); + scr_dyn_release(self); + return NULL; +} + +/* emit(type, ...args): Node's unhandled 'error' rule, then each listener + * with the emitter as its receiver over a copy of the list. */ +static ScrDyn *bc_emit(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + ScrDyn *self = bc_this(); + if (!bc_require_object(self, "_events")) { + scr_dyn_release(self); + return NULL; + } + ScrDyn *type = bc_arg(args, argc, 0); + ScrDyn *const *rest = argc > 1 ? args + 1 : bc_unused_args; + size_t restc = argc > 1 ? argc - 1 : 0; + bool error = type->kind == SCR_DYN_STR && type->v.str->len == 5 && memcmp(type->v.str->data, "error", 5) == 0; + ScrDyn *events = bc_get(self, "_events"); + if (!events) goto fail_self; + if (!bc_undefined(events)) { + if (error) { + ScrDyn *handler = bc_get(events, "error"); + if (!handler) goto fail_events; + error = bc_undefined(handler); + scr_dyn_release(handler); + } + } else if (!error) { + scr_dyn_release(events); + scr_dyn_release(self); + return scr_dyn_new_bool(false); + } + if (error) { + ScrDyn *payload = restc ? rest[0] : scr_dyn_undefined(); + if (scr_dyn_err_instanceof(payload, SCR_ERR_ERROR)) { + scr_dyn_throw(scr_dyn_retain(payload)); + } else { + ScrStr *shown = scr_insp_dyn(payload, 0, 2); + ScrJsonBuf text; + scr_jb_init(&text); + scr_jb_puts(&text, "Unhandled error. ("); + scr_jb_put_str(&text, shown); + scr_jb_putc(&text, ')'); + scr_str_release(shown); + ScrStr *message = scr_jb_finish(&text); + scr_throw_error_msg_code(SCR_ERR_ERROR, message->data, message->len, "ERR_UNHANDLED_ERROR"); + scr_str_release(message); + } + goto fail_events; + } + ScrDyn *handler = bc_get_key(events, type); + if (!handler) goto fail_events; + bool fired = !bc_undefined(handler); + if (scr_dyn_is_callable(handler)) { + ScrDyn *result = bc_apply(handler, self, rest, restc); + scr_dyn_release(handler); + if (!result) goto fail_events; + scr_dyn_release(result); + } else if (handler->kind == SCR_DYN_ARR) { + /* arrayClone: listeners added or removed during the emit run next time */ + size_t length = (size_t)scr_dyn_arr_len(handler); + ScrDyn **listeners = malloc((length ? length : 1) * sizeof *listeners); + if (!listeners) scr_trap("out of memory"); + for (size_t i = 0; i < length; i++) listeners[i] = scr_dyn_index_get(handler, (double)i); + scr_dyn_release(handler); + bool ok = true; + for (size_t i = 0; i < length && ok; i++) { + if (!listeners[i]) { + ok = false; + break; + } + ScrDyn *result = bc_apply(listeners[i], self, rest, restc); + if (!result) ok = false; + else scr_dyn_release(result); + } + for (size_t i = 0; i < length; i++) + if (listeners[i]) scr_dyn_release(listeners[i]); + free(listeners); + if (!ok) goto fail_events; + } else { + scr_dyn_release(handler); + } + scr_dyn_release(events); + scr_dyn_release(self); + return scr_dyn_new_bool(fired); +fail_events: + scr_dyn_release(events); +fail_self: + scr_dyn_release(self); + return NULL; +} + +/* _listeners(target, type, unwrap): a fresh array. */ +static ScrDyn *bc_listeners_of(bool unwrap, ScrDyn *const *args, size_t argc) { + ScrDyn *self = bc_this(); + if (!bc_require_object(self, "_events")) { + scr_dyn_release(self); + return NULL; + } + ScrDyn *result = scr_dyn_new_arr(); + ScrDyn *events = bc_get(self, "_events"); + ScrDyn *list = NULL; + if (!events) goto fail; + if (bc_undefined(events)) goto done; + list = bc_get_key(events, bc_arg(args, argc, 0)); + if (!list) goto fail; + size_t length = scr_dyn_is_callable(list) ? 1 : list->kind == SCR_DYN_ARR ? (size_t)scr_dyn_arr_len(list) : 0; + for (size_t i = 0; i < length; i++) { + ScrDyn *item = scr_dyn_is_callable(list) ? scr_dyn_retain(list) : scr_dyn_index_get(list, (double)i); + if (!item) goto fail; + if (unwrap && scr_dyn_is_callable(item)) { + ScrDyn *inner = bc_get(item, "listener"); + if (!inner) { + scr_dyn_release(item); + goto fail; + } + if (!bc_undefined(inner)) { + scr_dyn_release(item); + item = inner; + } else { + scr_dyn_release(inner); + } + } + scr_dyn_arr_push(result, item); + } +done: + if (list) scr_dyn_release(list); + if (events) scr_dyn_release(events); + scr_dyn_release(self); + return result; +fail: + if (list) scr_dyn_release(list); + if (events) scr_dyn_release(events); + scr_dyn_release(result); + scr_dyn_release(self); + return NULL; +} + +static ScrDyn *bc_listeners(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + return bc_listeners_of(true, args, argc); +} + +static ScrDyn *bc_raw_listeners(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + return bc_listeners_of(false, args, argc); +} + +/* listenerCount(type, listener?) over an emitter's _events. */ +static ScrDyn *bc_count_listeners(ScrDyn *self, ScrDyn *type, ScrDyn *only) { + ScrDyn *events = bc_get(self, "_events"); + if (!events) return NULL; + double count = 0; + if (!bc_undefined(events)) { + ScrDyn *list = bc_get_key(events, type); + if (!list) { + scr_dyn_release(events); + return NULL; + } + size_t length = scr_dyn_is_callable(list) ? 1 : list->kind == SCR_DYN_ARR ? (size_t)scr_dyn_arr_len(list) : 0; + for (size_t i = 0; i < length; i++) { + if (!only) { + count++; + continue; + } + ScrDyn *item = scr_dyn_is_callable(list) ? scr_dyn_retain(list) : scr_dyn_index_get(list, (double)i); + if (!item) break; + bool same = scr_dyn_strict_eq(item, only); + if (!same && scr_dyn_is_callable(item)) { + ScrDyn *inner = bc_get(item, "listener"); + if (inner) { + same = scr_dyn_strict_eq(inner, only); + scr_dyn_release(inner); + } + } + scr_dyn_release(item); + if (same) count++; + } + scr_dyn_release(list); + } + scr_dyn_release(events); + if (scr_exc_pending()) return NULL; + return scr_dyn_new_num(count); +} + +static ScrDyn *bc_listener_count(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + ScrDyn *self = bc_this(); + ScrDyn *result = bc_require_object(self, "_events") + ? bc_count_listeners(self, bc_arg(args, argc, 0), + argc > 1 && !bc_undefined(args[1]) && args[1]->kind != SCR_DYN_NULL ? args[1] : NULL) + : NULL; + scr_dyn_release(self); + return result; +} + +/* EventEmitter.listenerCount(emitter, type): the deprecated static. */ +static ScrDyn *bc_static_listener_count(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + ScrDyn *emitter = bc_arg(args, argc, 0); + ScrDyn *type = bc_arg(args, argc, 1); + ScrDyn *method = bc_require_object(emitter, "listenerCount") ? bc_get(emitter, "listenerCount") : NULL; + if (!method) return NULL; + ScrDyn *result; + if (scr_dyn_is_callable(method)) result = bc_apply(method, emitter, &type, 1); + else result = bc_count_listeners(emitter, type, NULL); + scr_dyn_release(method); + return result; +} + +static ScrDyn *bc_event_names(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + (void)args; + (void)argc; + ScrDyn *self = bc_this(); + if (!bc_require_object(self, "_eventsCount")) { + scr_dyn_release(self); + return NULL; + } + ScrDyn *count = bc_get(self, "_eventsCount"); + ScrDyn *result = NULL; + if (count) { + if (bc_number(count) > 0) { + ScrDyn *events = bc_get(self, "_events"); + if (events) { + result = scr_dyn_own_keys(events); + scr_dyn_release(events); + } + } else { + result = scr_dyn_new_arr(); + } + scr_dyn_release(count); + } + scr_dyn_release(self); + return result; +} + +static ScrDyn *bc_set_max(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + ScrDyn *self = bc_this(); + ScrDyn *n = bc_arg(args, argc, 0); + if (n->kind != SCR_DYN_NUM) { + scr_dyn_arg_type_fail("n", "of type number", n); + scr_dyn_release(self); + return NULL; + } + if (n->v.num < 0 || n->v.num != n->v.num) { + ScrStr *shown = scr_dyn_string_coerce_js(n); + ScrJsonBuf text; + scr_jb_init(&text); + scr_jb_puts(&text, "The value of \"n\" is out of range. It must be a non-negative number. Received "); + if (shown) scr_jb_put_str(&text, shown); + if (shown) scr_str_release(shown); + ScrStr *message = scr_jb_finish(&text); + scr_throw_error_msg_code(SCR_ERR_RANGE, message->data, message->len, "ERR_OUT_OF_RANGE"); + scr_str_release(message); + scr_dyn_release(self); + return NULL; + } + if (!bc_require_object(self, "_maxListeners") || !bc_set(self, "_maxListeners", scr_dyn_retain(n))) { + scr_dyn_release(self); + return NULL; + } + return self; +} + +static ScrDyn *bc_get_max(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + (void)args; + (void)argc; + ScrDyn *self = bc_this(); + double max = bc_require_object(self, "_maxListeners") ? bc_max_listeners(self) : -1; + scr_dyn_release(self); + if (scr_exc_pending()) return NULL; + return scr_dyn_new_num(max); +} + +/* ── Stream.prototype.pipe (lib/internal/streams/legacy.js) ─────────── */ + +enum { BC_PIPE_SOURCE, BC_PIPE_DEST, BC_PIPE_ENDED, BC_PIPE_HANDLERS, BC_PIPE_CAPS }; +enum { BC_ONDATA, BC_ONDRAIN, BC_ONEND, BC_ONCLOSE, BC_ONERROR, BC_CLEANUP, BC_HANDLER_COUNT }; + +static ScrDyn *bc_pipe_handler(ScrClosure *state, int which); + +static ScrDyn *bc_pipe_get_handler(ScrClosure *state, int which) { + ScrDyn *handlers = bc_cap(state, BC_PIPE_HANDLERS); + ScrDyn *handler = scr_dyn_index_get(handlers, which); + scr_dyn_release(handlers); + return handler; +} + +/* Calls source/dest.removeListener for one pipe handler. */ +static bool bc_pipe_remove(ScrDyn *emitter, const char *event, ScrClosure *state, int which) { + ScrDyn *handler = bc_pipe_get_handler(state, which); + if (!handler) return false; + ScrDyn *name = bc_key(event); + ScrDyn *pair[2] = { name, handler }; + ScrDyn *removed = bc_invoke(emitter, "removeListener", pair, 2); + scr_dyn_release(name); + scr_dyn_release(handler); + if (!removed) return false; + scr_dyn_release(removed); + return true; +} + +static bool bc_pipe_on(ScrDyn *emitter, const char *event, ScrClosure *state, int which) { + ScrDyn *handler = bc_pipe_get_handler(state, which); + if (!handler) return false; + ScrDyn *name = bc_key(event); + ScrDyn *pair[2] = { name, handler }; + ScrDyn *added = bc_invoke(emitter, "on", pair, 2); + scr_dyn_release(name); + scr_dyn_release(handler); + if (!added) return false; + scr_dyn_release(added); + return true; +} + +static bool bc_pipe_cleanup(ScrClosure *state) { + ScrDyn *source = bc_cap(state, BC_PIPE_SOURCE); + ScrDyn *dest = bc_cap(state, BC_PIPE_DEST); + bool ok = bc_pipe_remove(source, "data", state, BC_ONDATA) && + bc_pipe_remove(dest, "drain", state, BC_ONDRAIN) && + bc_pipe_remove(source, "end", state, BC_ONEND) && + bc_pipe_remove(source, "close", state, BC_ONCLOSE) && + bc_pipe_remove(source, "error", state, BC_ONERROR) && + bc_pipe_remove(dest, "error", state, BC_ONERROR) && + bc_pipe_remove(source, "end", state, BC_CLEANUP) && + bc_pipe_remove(source, "close", state, BC_CLEANUP) && + bc_pipe_remove(dest, "close", state, BC_CLEANUP); + scr_dyn_release(dest); + scr_dyn_release(source); + /* the handlers array held the closures that hold this state */ + if (ok) scr_box_set_ref(state->caps[BC_PIPE_HANDLERS], scr_dyn_new_arr()); + return ok; +} + +static ScrDyn *bc_pipe_event(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + ScrClosure *state = (ScrClosure *)scr_box_get_ref(closure->caps[0]); + int which = (int)scr_box_get_f64(closure->caps[1]); + ScrDyn *source = bc_cap(state, BC_PIPE_SOURCE); + ScrDyn *dest = bc_cap(state, BC_PIPE_DEST); + bool ok = true; + switch (which) { + case BC_ONDATA: { + ScrDyn *writable = bc_get(dest, "writable"); + if (!writable) { + ok = false; + break; + } + bool open = scr_dyn_truthy(writable); + scr_dyn_release(writable); + if (!open) break; + ScrDyn *chunk = bc_arg(args, argc, 0); + ScrDyn *written = bc_invoke(dest, "write", &chunk, 1); + if (!written) { + ok = false; + break; + } + bool full = written->kind == SCR_DYN_BOOL && !written->v.b; + scr_dyn_release(written); + if (full) { + ScrDyn *pause = bc_get(source, "pause"); + if (!pause) { + ok = false; + break; + } + if (scr_dyn_is_callable(pause)) { + ScrDyn *paused = bc_apply(pause, source, bc_unused_args, 0); + if (paused) scr_dyn_release(paused); + else ok = false; + } + scr_dyn_release(pause); + } + break; + } + case BC_ONDRAIN: { + ScrDyn *readable = bc_get(source, "readable"); + ScrDyn *resume = readable ? bc_get(source, "resume") : NULL; + if (!readable || !resume) { + ok = false; + } else if (scr_dyn_truthy(readable) && scr_dyn_is_callable(resume)) { + ScrDyn *resumed = bc_apply(resume, source, bc_unused_args, 0); + if (resumed) scr_dyn_release(resumed); + else ok = false; + } + if (readable) scr_dyn_release(readable); + if (resume) scr_dyn_release(resume); + break; + } + case BC_ONEND: + case BC_ONCLOSE: { + if (scr_box_get_f64(state->caps[BC_PIPE_ENDED]) != 0) break; + scr_box_set_f64(state->caps[BC_PIPE_ENDED], 1); + ScrDyn *done = which == BC_ONEND ? bc_invoke(dest, "end", bc_unused_args, 0) : NULL; + if (which == BC_ONCLOSE) { + ScrDyn *destroy = bc_get(dest, "destroy"); + if (!destroy) { + ok = false; + break; + } + if (scr_dyn_is_callable(destroy)) done = bc_apply(destroy, dest, bc_unused_args, 0); + else done = scr_dyn_retain(scr_dyn_undefined()); + scr_dyn_release(destroy); + } + if (done) scr_dyn_release(done); + else ok = false; + break; + } + case BC_ONERROR: { + ok = bc_pipe_cleanup(state); + if (!ok) break; + ScrDyn *rethrow = scr_dyn_this_get(); + ScrDyn *name = bc_key("error"); + ScrDyn *count = rethrow->kind == SCR_DYN_UNDEF ? NULL : bc_invoke(rethrow, "listenerCount", &name, 1); + scr_dyn_release(name); + if (count && bc_number(count) == 0) { + scr_dyn_throw(scr_dyn_retain(bc_arg(args, argc, 0))); + ok = false; + } else if (!count && scr_exc_pending()) { + ok = false; + } + if (count) scr_dyn_release(count); + scr_dyn_release(rethrow); + break; + } + case BC_CLEANUP: + ok = bc_pipe_cleanup(state); + break; + default: + break; + } + scr_dyn_release(dest); + scr_dyn_release(source); + scr_closure_release(state); + return ok ? scr_dyn_retain(scr_dyn_undefined()) : NULL; +} + +static ScrDyn *bc_pipe_handler(ScrClosure *state, int which) { + ScrClosure *closure = scr_closure_new(NULL, 2); + ScrBox *owner = scr_box_new_obj(scr_closure_retain_v, scr_closure_release_v, scr_closure_trace_v); + scr_box_set_ref(owner, scr_closure_retain(state)); + closure->caps[0] = owner; + closure->caps[1] = scr_box_new(SCR_BOX_F64); + scr_box_set_f64(closure->caps[1], which); + return scr_dyn_new_func(closure, bc_pipe_event, 0, "native:stream", which == BC_ONDATA ? "ondata" + : which == BC_ONDRAIN ? "ondrain" : which == BC_ONEND ? "onend" : which == BC_ONCLOSE ? "onclose" + : which == BC_ONERROR ? "onerror" : "cleanup"); +} + +/* Stream.prototype.pipe(dest, options): Node's legacy pipe for streams + * that are only EventEmitters. 'end' and 'close' end or destroy the + * destination unless options.end is false or the destination is stdio. */ +static ScrDyn *bc_pipe(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + ScrDyn *source = bc_this(); + ScrDyn *dest = bc_arg(args, argc, 0); + ScrDyn *options = bc_arg(args, argc, 1); + if (!bc_require_object(source, "on") || !bc_require_object(dest, "on")) { + scr_dyn_release(source); + return NULL; + } + ScrClosure *state = scr_closure_new(NULL, BC_PIPE_CAPS); + state->caps[BC_PIPE_SOURCE] = bc_box(scr_dyn_retain(source)); + state->caps[BC_PIPE_DEST] = bc_box(scr_dyn_retain(dest)); + state->caps[BC_PIPE_ENDED] = scr_box_new(SCR_BOX_F64); + ScrDyn *handlers = scr_dyn_new_arr(); + for (int i = 0; i < BC_HANDLER_COUNT; i++) scr_dyn_arr_push(handlers, bc_pipe_handler(state, i)); + state->caps[BC_PIPE_HANDLERS] = bc_box(handlers); + bool ok = bc_pipe_on(source, "data", state, BC_ONDATA) && bc_pipe_on(dest, "drain", state, BC_ONDRAIN); + bool end_dest = true; + if (ok && options->kind != SCR_DYN_UNDEF && options->kind != SCR_DYN_NULL) { + ScrDyn *end = bc_get(options, "end"); + if (!end) ok = false; + else { + end_dest = !(end->kind == SCR_DYN_BOOL && !end->v.b); + scr_dyn_release(end); + } + } + if (ok && end_dest) { + ScrDyn *stdio = bc_get(dest, "_isStdio"); + if (!stdio) ok = false; + else { + end_dest = !scr_dyn_truthy(stdio); + scr_dyn_release(stdio); + } + } + if (ok && end_dest) + ok = bc_pipe_on(source, "end", state, BC_ONEND) && bc_pipe_on(source, "close", state, BC_ONCLOSE); + if (ok) { + /* prependListener(source, 'error', onerror) and the same on dest */ + ScrDyn *onerror = bc_pipe_get_handler(state, BC_ONERROR); + ScrDyn *name = bc_key("error"); + ScrDyn *pair[2] = { name, onerror }; + ScrDyn *a = onerror ? bc_invoke(source, "prependListener", pair, 2) : NULL; + ScrDyn *b = a ? bc_invoke(dest, "prependListener", pair, 2) : NULL; + ok = a && b; + if (a) scr_dyn_release(a); + if (b) scr_dyn_release(b); + scr_dyn_release(name); + if (onerror) scr_dyn_release(onerror); + } + if (ok) + ok = bc_pipe_on(source, "end", state, BC_CLEANUP) && bc_pipe_on(source, "close", state, BC_CLEANUP) && + bc_pipe_on(dest, "close", state, BC_CLEANUP); + ScrDyn *result = NULL; + if (ok) { + ScrDyn *name = bc_key("pipe"); + ScrDyn *pair[2] = { name, source }; + ScrDyn *emitted = bc_invoke(dest, "emit", pair, 2); + scr_dyn_release(name); + if (emitted) { + scr_dyn_release(emitted); + result = scr_dyn_retain(dest); + } + } + scr_closure_release(state); + scr_dyn_release(source); + return result; +} + +/* ── the constructors ───────────────────────────────────────────────── */ + +static ScrDyn *bc_construct(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + int kind = (int)scr_box_get_f64(closure->caps[0]); + ScrDyn *self = bc_this(); + ScrDyn *result = NULL; + if (kind == BC_EMITTER || kind == BC_STREAM) { + if (bc_emitter_init(self, bc_arg(args, argc, 0))) result = scr_dyn_retain(scr_dyn_undefined()); + } else { + char message[160]; + snprintf(message, sizeof message, + "'%s' as the base of a constructor function (util.inherits or %s.call(this)) is not supported yet", + bc_names[kind], bc_names[kind]); + scr_throw_error_msg_code(SCR_ERR_ERROR, message, strlen(message), "SC2020"); + } + scr_dyn_release(self); + return result; +} + +static void bc_method(ScrDyn *prototype, const char *name, ScrDynThunk thunk, uint32_t arity) { + ScrDyn *fn = scr_dyn_new_func(scr_closure_new(NULL, 0), thunk, arity, "native:events", name); + bc_set(prototype, name, fn); +} + +static void bc_alias(ScrDyn *prototype, const char *alias, const char *name) { + ScrDyn *fn = bc_get(prototype, name); + if (fn) bc_set(prototype, alias, fn); +} + +static void bc_teardown(void) { + for (int i = 0; i < BC_COUNT; i++) { + if (!bc_ctors[i]) continue; + ScrDyn *ctor = bc_ctors[i]; + /* prototype.constructor, EventEmitter.EventEmitter and Stream.Stream + * point back at the constructor, and Stream.Readable … at constructors + * whose own prototype is Stream: break those cycles first. */ + ScrDyn *prototype = bc_get(ctor, "prototype"); + if (prototype && prototype->kind == SCR_DYN_OBJ) bc_set(prototype, "constructor", scr_dyn_retain(scr_dyn_undefined())); + if (prototype) scr_dyn_release(prototype); + bc_set(ctor, bc_names[i], scr_dyn_retain(scr_dyn_undefined())); + if (i == BC_STREAM) + for (int other = BC_READABLE; other < BC_COUNT; other++) + bc_set(ctor, bc_names[other], scr_dyn_retain(scr_dyn_undefined())); + if (scr_exc_pending()) scr_exc_clear(); + } + for (int i = 0; i < BC_COUNT; i++) { + if (!bc_ctors[i]) continue; + ScrDyn *ctor = bc_ctors[i]; + bc_ctors[i] = NULL; + scr_dyn_release(ctor); + } + for (int i = 0; i < BC_SYMBOLS; i++) { + if (bc_symbols[i]) scr_dyn_release(bc_symbols[i]); + bc_symbols[i] = NULL; + } + if (scr_exc_pending()) scr_exc_clear(); +} + +static ScrDyn *bc_new_class(int kind, ScrDyn *parent) { + ScrClosure *closure = scr_closure_new(NULL, 1); + closure->function_kind = 4; /* an ordinary function with its own prototype */ + closure->caps[0] = scr_box_new(SCR_BOX_F64); + scr_box_set_f64(closure->caps[0], kind); + ScrDyn *ctor = scr_dyn_new_func(closure, bc_construct, 1, "native:events", bc_names[kind]); + ScrDyn *prototype = parent ? NULL : scr_dyn_new_obj(); + if (parent) { + ScrDyn *base = bc_get(parent, "prototype"); + prototype = scr_dyn_obj_create(base); + scr_dyn_release(base); + ScrDyn *linked = scr_dyn_set_prototype(ctor, parent); + if (linked) scr_dyn_release(linked); + } + bc_set(prototype, "constructor", scr_dyn_retain(ctor)); + bc_set(ctor, "prototype", scr_dyn_retain(prototype)); + if (kind == BC_EMITTER) { + bc_set(prototype, "_events", scr_dyn_retain(scr_dyn_undefined())); + bc_set(prototype, "_eventsCount", scr_dyn_new_num(0)); + bc_set(prototype, "_maxListeners", scr_dyn_retain(scr_dyn_undefined())); + bc_set_key(prototype, bc_symbol(BC_CAPTURE), scr_dyn_new_bool(false)); + bc_method(prototype, "setMaxListeners", bc_set_max, 1); + bc_method(prototype, "getMaxListeners", bc_get_max, 0); + bc_method(prototype, "emit", bc_emit, 1); + bc_method(prototype, "addListener", bc_on, 2); + bc_alias(prototype, "on", "addListener"); + bc_method(prototype, "prependListener", bc_prepend, 2); + bc_method(prototype, "once", bc_once, 2); + bc_method(prototype, "prependOnceListener", bc_prepend_once, 2); + bc_method(prototype, "removeListener", bc_off, 2); + bc_alias(prototype, "off", "removeListener"); + bc_method(prototype, "removeAllListeners", bc_remove_all, 1); + bc_method(prototype, "listeners", bc_listeners, 1); + bc_method(prototype, "rawListeners", bc_raw_listeners, 1); + bc_method(prototype, "listenerCount", bc_listener_count, 2); + bc_method(prototype, "eventNames", bc_event_names, 0); + bc_set(ctor, "EventEmitter", scr_dyn_retain(ctor)); + bc_set(ctor, "defaultMaxListeners", scr_dyn_new_num(10)); + ScrDyn *count = scr_dyn_new_func(scr_closure_new(NULL, 0), bc_static_listener_count, 2, "native:events", "listenerCount"); + bc_set(ctor, "listenerCount", count); + } else if (kind == BC_STREAM) { + ScrDyn *pipe = scr_dyn_new_func(scr_closure_new(NULL, 0), bc_pipe, 2, "native:stream", "pipe"); + bc_set(prototype, "pipe", pipe); + } + scr_dyn_release(prototype); + if (scr_exc_pending()) scr_exc_clear(); + return ctor; +} + +/* All seven constructors are created together, each after its parent, so + * Stream's static members name the same constructors every other read + * answers. */ +static ScrDyn *bc_class(int kind) { + if (!bc_ctors[kind]) { + static const int parents[BC_COUNT] = { + -1, BC_EMITTER, BC_STREAM, BC_STREAM, BC_READABLE, BC_DUPLEX, BC_TRANSFORM, + }; + for (int each = 0; each < BC_COUNT; each++) { + if (bc_ctors[each]) continue; + bc_ctors[each] = bc_new_class(each, parents[each] >= 0 ? bc_ctors[parents[each]] : NULL); + } + /* Registered after the constructors exist, so the teardown runs before + * the runtime state their properties were stored in (scr_atexit is + * last in, first out). */ + if (!bc_teardown_registered) { + bc_teardown_registered = true; + scr_atexit(bc_teardown); + } + /* require("stream") is Stream itself, carrying its classes */ + ScrDyn *stream = bc_ctors[BC_STREAM]; + bc_set(stream, "Stream", scr_dyn_retain(stream)); + for (int other = BC_READABLE; other < BC_COUNT; other++) + bc_set(stream, bc_names[other], scr_dyn_retain(bc_ctors[other])); + if (scr_exc_pending()) scr_exc_clear(); + } + return bc_ctors[kind]; +} + +/* The constructor value for kind (the BC_* order), +1. */ +ScrDyn *scr_dyn_builtin_class(double kind) { + int index = (int)kind; + if (index < 0 || index >= BC_COUNT) scr_trap("scriptc: unknown builtin class value\n"); + return scr_dyn_retain(bc_class(index)); +} + +/* OrdinaryHasInstance over the value's prototype chain. */ +static bool bc_chain_has(ScrDyn *value, ScrDyn *prototype) { + if (value->kind != SCR_DYN_OBJ && value->kind != SCR_DYN_ARR && value->kind != SCR_DYN_FUNC && + value->kind != SCR_DYN_PROXY) + return false; + ScrDyn *current = scr_dyn_get_prototype(value); + while (current && current->kind != SCR_DYN_NULL) { + if (scr_dyn_strict_eq(current, prototype)) { + scr_dyn_release(current); + return true; + } + ScrDyn *next = scr_dyn_get_prototype(current); + scr_dyn_release(current); + current = next; + } + if (current) scr_dyn_release(current); + return false; +} + +/* `value instanceof `. Node's Writable also answers true for an + * object whose _writableState is a WritableState, which no untyped object + * has, so the prototype chain answers for every kind. */ +bool scr_dyn_builtin_instanceof(ScrDyn *value, double kind) { + int index = (int)kind; + if (index < 0 || index >= BC_COUNT) scr_trap("scriptc: unknown builtin class value\n"); + ScrDyn *prototype = bc_get(bc_class(index), "prototype"); + if (!prototype) return false; + bool found = bc_chain_has(value, prototype); + scr_dyn_release(prototype); + return found; +} + +/* `value instanceof callee` for an untyped constructor function. */ +bool scr_dyn_function_instanceof(ScrDyn *value, ScrDyn *callee) { + if (!scr_dyn_is_callable(callee)) { + static const char message[] = "Right-hand side of 'instanceof' is not callable"; + scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + return false; + } + ScrDyn *prototype = bc_get(callee, "prototype"); + if (!prototype) return false; + bool found = false; + if (prototype->kind == SCR_DYN_OBJ || prototype->kind == SCR_DYN_ARR || prototype->kind == SCR_DYN_FUNC || + prototype->kind == SCR_DYN_PROXY) { + found = bc_chain_has(value, prototype); + } else if (value->kind == SCR_DYN_OBJ || value->kind == SCR_DYN_ARR || value->kind == SCR_DYN_FUNC) { + static const char message[] = "Function has non-object prototype 'undefined' in instanceof check"; + scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + } + scr_dyn_release(prototype); + return found; +} diff --git a/tests/corpus/6453-constructor-function-emitter.cjs b/tests/corpus/6453-constructor-function-emitter.cjs new file mode 100644 index 000000000..d07453e14 --- /dev/null +++ b/tests/corpus/6453-constructor-function-emitter.cjs @@ -0,0 +1,114 @@ +// Constructor functions that inherit from EventEmitter the pre-class way: +// util.inherits and EventEmitter.call(this), the call-without-new guard, +// prototype methods that emit, and the listener API over the instance. +"use strict"; +const util = require("util"); +const { EventEmitter } = require("events"); + +util.inherits(Bus, EventEmitter); +function Bus(name) { + if (!(this instanceof Bus)) return new Bus(name); + EventEmitter.call(this); + this.name = name; + this.entries = []; +} +Bus.prototype.add = function (entry) { + this.entries.push(entry); + this.emit("added", entry, this.entries.length); + return this; +}; + +// A second level: Sub inherits Bus, and Bus's constructor runs through call. +function Sub(name) { + Bus.call(this, name); + this.sub = true; +} +util.inherits(Sub, Bus); +Sub.prototype.add = function (entry) { + return Bus.prototype.add.call(this, entry.toUpperCase()); +}; + +// Object.setPrototypeOf instead of util.inherits. +function Legacy() { + EventEmitter.call(this); +} +Object.setPrototypeOf(Legacy.prototype, EventEmitter.prototype); + +function main() { + const bus = Bus("main"); + console.log(bus instanceof Bus, bus instanceof EventEmitter, Bus.super_ === EventEmitter); + console.log(Object.keys(bus).join(","), bus._eventsCount, bus._maxListeners); + bus.on("added", function (entry, count) { + console.log("added", entry, count, this === bus); + }); + bus.once("added", (entry) => console.log("first only", entry)); + bus.prependListener("added", () => console.log("prepended")); + bus.prependOnceListener("added", () => console.log("prepended once")); + bus.add("a").add("b"); + console.log(bus.listenerCount("added"), bus.eventNames(), bus.getMaxListeners()); + + const handler = () => console.log("never"); + bus.on("x", handler); + bus.on("x", () => console.log("kept")); + bus.off("x", handler); + console.log(bus.emit("x"), bus.emit("nothing"), bus.listeners("x").length, bus.rawListeners("added").length); + + try { + bus.emit("error", new Error("boom")); + } catch (err) { + console.log("caught", err.message); + } + try { + bus.emit("error", "plain"); + } catch (err) { + console.log("caught", err.code, err.message); + } + bus.on("error", (err) => console.log("handled", err.message)); + bus.emit("error", new Error("quiet")); + + bus.on("newListener", (event, listener) => console.log("newListener", event, typeof listener)); + bus.on("removeListener", (event) => console.log("removeListener", event)); + bus.on("later", () => {}); + bus.removeAllListeners("added"); + console.log(bus.listenerCount("added"), bus.listenerCount("later")); + bus.removeAllListeners(); + console.log(bus.eventNames().length); + + const sub = new Sub("child"); + sub.on("added", (entry) => console.log("sub added", entry)); + sub.add("c"); + console.log(sub instanceof Sub, sub instanceof Bus, sub instanceof EventEmitter, sub.entries); + + const legacy = new Legacy(); + console.log("legacy", legacy instanceof EventEmitter, legacy.getMaxListeners()); + try { + legacy.setMaxListeners(-1); + } catch (err) { + console.log(err.name, err.code); + } + try { + legacy.on("bad", "not a function"); + } catch (err) { + console.log(err.name, err.code); + } + console.log(new Legacy()); + + // The leak warning goes to stderr with the process id: run it in a child + // and print its output with the id normalized. + const { spawnSync } = require("child_process"); + const child = spawnSync(process.execPath, [process.argv[1], "leak"], { encoding: "utf8" }); + console.log(child.stdout + child.stderr.replace(/\(node:\d+\)/g, "(node:)")); +} + +function leak() { + const legacy = new Legacy(); + legacy.setMaxListeners(1); + legacy.on("many", () => {}); + legacy.on("many", () => {}); + legacy.on("many", () => {}); + console.log("leak", legacy.listenerCount("many")); + setTimeout(() => console.log("leak done"), 1); +} + +if (process.argv[2] === "leak") leak(); +else main(); diff --git a/tests/corpus/6454-constructor-function-stream-bases.cjs b/tests/corpus/6454-constructor-function-stream-bases.cjs new file mode 100644 index 000000000..4b2bb6789 --- /dev/null +++ b/tests/corpus/6454-constructor-function-stream-bases.cjs @@ -0,0 +1,65 @@ +// The legacy Stream constructor as a constructor function's base: its +// EventEmitter state and the legacy pipe between two such streams. The +// stream classes take util.inherits, and instanceof follows the chain. +"use strict"; +const util = require("util"); +const Stream = require("stream"); +const { Readable, Writable, Duplex, Transform, PassThrough } = require("stream"); + +function Source(items) { + Stream.call(this); + this.items = items; + this.readable = true; +} +util.inherits(Source, Stream); +Source.prototype.start = function () { + for (const item of this.items) this.emit("data", item); + this.emit("end"); +}; + +function Sink() { + Stream.call(this); + this.writable = true; + this.chunks = []; +} +util.inherits(Sink, Stream); +Sink.prototype.write = function (chunk) { + this.chunks.push(chunk); + return true; +}; +Sink.prototype.end = function () { + console.log("sink end", this.chunks.join("+")); +}; + +const source = new Source(["a", "b", "c"]); +const sink = new Sink(); +sink.on("pipe", (from) => console.log("piped", from === source)); +console.log(source.pipe(sink) === sink, sink.listenerCount("pipe")); +source.start(); +console.log("after end", source.listenerCount("data"), sink.listenerCount("drain")); + +const kept = new Sink(); +const second = new Source(["x"]); +second.pipe(kept, { end: false }); +second.start(); +console.log("kept open", kept.chunks); + +function Reader() {} +util.inherits(Reader, Readable); +function Both() {} +util.inherits(Both, Duplex); +function Shift() {} +util.inherits(Shift, Transform); +function Through() {} +util.inherits(Through, PassThrough); +function Out() {} +util.inherits(Out, Writable); +console.log(Reader.super_ === Readable, Through.super_ === PassThrough, Out.super_ === Writable); +const reader = Object.create(Reader.prototype); +const through = Object.create(Through.prototype); +const out = Object.create(Out.prototype); +const both = Object.create(Both.prototype); +console.log(reader instanceof Readable, reader instanceof Writable); +console.log(through instanceof Transform, through instanceof Duplex, through instanceof Readable); +console.log(out instanceof Writable, out instanceof Readable, both instanceof Readable); +console.log(typeof Shift.prototype.constructor, Shift.prototype instanceof Duplex); diff --git a/tests/harness/self-hosting-native-toolchain.test.ts b/tests/harness/self-hosting-native-toolchain.test.ts index fa71b5a08..1de960368 100644 --- a/tests/harness/self-hosting-native-toolchain.test.ts +++ b/tests/harness/self-hosting-native-toolchain.test.ts @@ -30,6 +30,7 @@ const features: NativeLinkFeatures = { bigint: false, searchParams: false, qs: false, + dynBuiltinClass: false, parseArgs: false, stream: false, net: false, diff --git a/tests/harness/self-hosting-runtime-features.test.ts b/tests/harness/self-hosting-runtime-features.test.ts index d2c2b589b..8d65d72cd 100644 --- a/tests/harness/self-hosting-runtime-features.test.ts +++ b/tests/harness/self-hosting-runtime-features.test.ts @@ -50,6 +50,7 @@ const featureCalls: readonly [string, IrLibFn][] = [ ["bigint", "bigint.parse"], ["searchParams", "sp.new"], ["qs", "qs.parse"], + ["dynBuiltinClass", "dyn.builtinClass"], ["parseArgs", "util.parseArgs"], ["parseArgs", "util.isDeepStrictEqual"], ["parseArgs", "util.styleText"], diff --git a/tests/harness/self-hosting-runtime-pack.test.ts b/tests/harness/self-hosting-runtime-pack.test.ts index c95d6d9a0..42cf8a729 100644 --- a/tests/harness/self-hosting-runtime-pack.test.ts +++ b/tests/harness/self-hosting-runtime-pack.test.ts @@ -31,6 +31,7 @@ const base: NativeLinkFeatures = { bigint: false, searchParams: false, qs: false, + dynBuiltinClass: false, parseArgs: false, stream: false, net: false, From fc9a8650af902da45ac0ac3c42d867edc4c3e72f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 03:05:32 -0500 Subject: [PATCH 19/39] Keep an Error's code slot in step with dynamic writes and own properties Writes and deletes of `code` through an error's checked-dynamic node (a `catch (e: any)` binding, a reflective write) changed only the node, so typed `err.code` reads kept the old value. The slot sync that already covered name, message, stack and cause now covers code: a string takes the slot, any other value or a delete clears it. A write, delete or Object.assign through an Error subclass's typed view now syncs the slots the subclass inherits from Error after the class commit, which writes only declared fields. `'code' in err` read the code slot, so an own `code` set to undefined answered false. It now asks the runtime: the slot holds a string, or the error has an own `code` property on its node. --- .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../src/frontend/lowering/lower-exprs.ts | 23 +------ .../compiler/src/ir/builtin-signatures.ts | 1 + packages/compiler/src/ir/validate.ts | 1 + .../6417-error-code-dynamic-writes.ts.json | 6 ++ packages/runtime/src/scr_error.h | 1 + packages/runtime/src/scr_json.c | 67 ++++++++++++++++--- .../corpus/6417-error-code-dynamic-writes.ts | 36 ++++++++++ .../6417-error-code-dynamic-writes.ts.json | 1 + 9 files changed, 109 insertions(+), 28 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6417-error-code-dynamic-writes.ts.json create mode 100644 tests/corpus/6417-error-code-dynamic-writes.ts create mode 100644 tests/harness/corpus-costs/6417-error-code-dynamic-writes.ts.json diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 46dff20e1..027fde012 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -129,6 +129,7 @@ export const LIB_FN_SYMS: Record = { "error.setCodeDyn": "scr_error_set_code_dyn", "error.assign": "scr_error_assign_dyn", "error.hasKey": "scr_error_has_key", + "error.hasCode": "scr_error_has_code", "error.defineCause": "scr_error_define_cause", "error.deleteCause": "scr_error_delete_cause", "error.hasCause": "scr_error_has_cause", diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index a84e37180..1a1fabdb5 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -14061,27 +14061,10 @@ function lowerInExpression(lowerer: Lowerer, expr: ts.BinaryExpression, loc: Src if (key === "cause") { return { kind: "libCall", fn: "error.hasCause", args: [recv], type: BOOL, loc }; } + // The code slot, or an own `code` with another value + // (`err.code = undefined` is present). if (key === "code") { - const codeType = lowerer.envValueType(); - if (codeType.kind !== "union") - throw new InternalCompilerError("lowerer bug: error code type is not a union"); - const undefTag = lowerer.armTag(codeType.unionId, UNDEFINED_T); - const read: IrExpr = { - kind: "libCall", - fn: "error.code", - args: [recv], - type: codeType, - loc, - }; - return { - kind: "unionIsTag", - unionId: codeType.unionId, - tag: undefTag, - negated: true, - value: read, - type: BOOL, - loc, - }; + return { kind: "libCall", fn: "error.hasCode", args: [recv], type: BOOL, loc }; } // The receiver evaluates for its effects when the answer is static. const always = (): IrExpr => diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 57ecbc8d4..f279d3948 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -3117,6 +3117,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * (args: the error, the key): a runtime-set own property (Object.assign, * throw-site fields, dynamic writes) or an Object.prototype member. */ "error.hasKey": { argTypes: [null, STRING], result: BOOL }, + "error.hasCode": { argTypes: [null], result: BOOL }, "error.defineCause": { argTypes: [null, DYN], result: VOID }, "error.deleteCause": { argTypes: [null], result: VOID }, /** The compiler-resolved Node-parity throw for always-throwing lowered diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index 0bbc948a0..4fb8ae2b4 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -4116,6 +4116,7 @@ function validateFunction( e.fn === "error.setCodeDyn" || e.fn === "error.assign" || e.fn === "error.hasKey" || + e.fn === "error.hasCode" || e.fn === "error.defineCause" || e.fn === "error.deleteCause" ) { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6417-error-code-dynamic-writes.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6417-error-code-dynamic-writes.ts.json new file mode 100644 index 000000000..a5a455a9a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6417-error-code-dynamic-writes.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6417-error-code-dynamic-writes.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_error.h b/packages/runtime/src/scr_error.h index 597361d59..bc64be4d2 100644 --- a/packages/runtime/src/scr_error.h +++ b/packages/runtime/src/scr_error.h @@ -293,6 +293,7 @@ void scr_error_assign_dyn(ScrError *e, const struct ScrDyn *sources); /* `key in err` for a key no compiled class declares: a runtime-set own * property or an Object.prototype member. Borrows both (scr_json.c). */ bool scr_error_has_key(ScrError *e, const ScrStr *key); +bool scr_error_has_code(ScrError *e); const char *scr_error_message_code(const ScrStr *msg); ScrStr *scr_error_code(ScrError *e); SCR_COLD void scr_throw_error_msg_code(int kind, const char *message, size_t len, const char *code); diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 56edcf049..a89880e89 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -4271,6 +4271,7 @@ static void scr_dyn_descriptor_fields_drop(ScrDyn **fields) { } static bool scr_dyn_key_is_index(const char *key, size_t len, double *out); static void scr_error_sync_cause(ScrDyn *view, const ScrStr *key); +static void scr_error_sync_slots(const ScrDyn *view, ScrDyn *obj, const ScrStr *key); /* Property tables belong to closures, not temporary checked wrappers. Seed * the configurable, non-writable builtin members once so redefinitions and @@ -6893,18 +6894,33 @@ ScrError *scr_errdyn_err_of(const ScrDyn *d) { void scr_errdyn_put(ScrError *e, ScrDyn *d) { scr_errdyn_append(e, d); } -/* Error.cause has one live value even when the Error already crossed a - * checked-value boundary. Reflective data-property edits update its slot. */ -static void scr_error_sync_cause(ScrDyn *view, const ScrStr *key) { +/* An Error's slots (name, message, stack, cause, code) have one live value + * even when the Error already crossed a checked-value boundary: writes and + * deletes of those own properties through its checked-dynamic node update + * the slots typed reads use. `view` is the error's node; `obj` holds the + * properties (the node itself, or a typed view's materialized object). */ +static void scr_error_sync_slots(const ScrDyn *view, ScrDyn *obj, const ScrStr *key) { bool cause = key->len == 5 && memcmp(key->data, "cause", 5) == 0; bool stack = key->len == 5 && memcmp(key->data, "stack", 5) == 0; bool name = key->len == 4 && memcmp(key->data, "name", 4) == 0; bool message = key->len == 7 && memcmp(key->data, "message", 7) == 0; - if (!cause && !stack && !name && !message) return; + bool code = key->len == 4 && memcmp(key->data, "code", 4) == 0; + if (!cause && !stack && !name && !message && !code) return; + if (obj == NULL || obj->kind != SCR_DYN_OBJ) return; size_t hit = scr_errdyn_find(view, false); if (hit == SIZE_MAX) return; - ScrDynEntry *entry = scr_dyn_entry(view, key); + ScrDynEntry *entry = scr_dyn_entry(obj, key); ScrError *e = scr_errdyn_cache[hit].err; + if (code) { + /* A string takes the slot; any other value, or none, clears it and + * stays an own property of the node. */ + ScrStr *next = entry && !entry->accessor && entry->value->kind == SCR_DYN_STR + ? scr_str_retain(entry->value->v.str) + : NULL; + scr_str_release(e->code); + e->code = next; + return; + } if (name || message) { /* The native error's toString and inspect read these fields. */ if (!entry || entry->accessor || entry->value->kind != SCR_DYN_STR) return; @@ -6935,6 +6951,10 @@ static void scr_error_sync_cause(ScrDyn *view, const ScrStr *key) { e->cause_enumerable = entry && entry->enumerable; } +static void scr_error_sync_cause(ScrDyn *view, const ScrStr *key) { + scr_error_sync_slots(view, view, key); +} + /* Error.prototype.toString over the checked-dynamic error encoding (an * object carrying the reserved "%error" marker): `name` defaults to "Error" * and `message` to "", both read through the prototype; either empty leaves @@ -7963,7 +7983,12 @@ void scr_dyn_key_set(ScrDyn *recv, ScrStr *key, ScrDyn *value) { if (scr_event_ref_hooks && scr_event_ref_hooks->set(recv, key, value)) return; ScrDyn *materialized = scr_dyn_typed_ref_materialize(recv); scr_dyn_key_set(materialized, key, value); - if (!scr_exc_pending()) scr_dyn_typed_ref_commit(recv); + if (!scr_exc_pending()) { + scr_dyn_typed_ref_commit(recv); + /* An Error subclass's class commit writes its declared fields; the + * slots it inherits from Error take the write here. */ + scr_error_sync_slots(recv, materialized, key); + } scr_dyn_release(materialized); return; } @@ -9737,7 +9762,10 @@ void scr_dyn_key_delete(ScrDyn *recv, const ScrStr *key, bool strict) { scr_dyn_entry(materialized, key) != NULL; if (!scr_exc_pending()) scr_dyn_key_delete(materialized, key, strict); bool deleted = own && !scr_exc_pending(); - if (!scr_exc_pending()) scr_dyn_typed_ref_commit(recv); + if (!scr_exc_pending()) { + scr_dyn_typed_ref_commit(recv); + scr_error_sync_slots(recv, materialized, key); + } scr_dyn_release(materialized); if (deleted && scr_exc_pending()) { /* The native layout requires this field, so the commit rejected the @@ -12094,7 +12122,17 @@ ScrDyn *scr_dyn_assign(ScrDyn *target, const ScrDyn *src) { if (target->kind == SCR_DYN_TYPED_REF) { ScrDyn *materialized = scr_dyn_typed_ref_materialize(target); ScrDyn *assigned = scr_dyn_assign(materialized, src); - if (!scr_exc_pending()) scr_dyn_typed_ref_commit(target); + if (!scr_exc_pending()) { + scr_dyn_typed_ref_commit(target); + /* An Error subclass's inherited slots take the copied values. */ + static const char *const slots[] = { "name", "message", "stack", "cause", "code" }; + for (size_t i = 0; i < sizeof slots / sizeof slots[0]; i++) { + ScrStr *key = scr_str_new(slots[i], strlen(slots[i])); + if (materialized->kind == SCR_DYN_OBJ && scr_dyn_entry(materialized, key) != NULL) + scr_error_sync_slots(target, materialized, key); + scr_str_release(key); + } + } scr_dyn_release(assigned); scr_dyn_release(materialized); return scr_exc_pending() ? NULL : scr_dyn_retain(target); @@ -14146,6 +14184,19 @@ void scr_error_assign_dyn(ScrError *e, const ScrDyn *sources) { scr_dyn_release(view); } +/* `'code' in err`: the code slot holds a string, or the error has an own + * `code` property with another value (`err.code = undefined`), which lives + * on its checked-dynamic node. Borrows; never throws. */ +bool scr_error_has_code(ScrError *e) { + if (e->code != NULL) return true; + const ScrDyn *view = scr_errdyn_view_of(e); + if (view == NULL) return false; + ScrStr *key = scr_str_new("code", 4); + bool own = scr_dyn_has_own(view, key); + scr_str_release(key); + return own; +} + /* `key in err` for a key no compiled class of the receiver declares: an own * property set at runtime, which lives on the error's checked-dynamic node * (that node exists once anything reflected or wrote through it), or a diff --git a/tests/corpus/6417-error-code-dynamic-writes.ts b/tests/corpus/6417-error-code-dynamic-writes.ts new file mode 100644 index 000000000..2eb23cbd7 --- /dev/null +++ b/tests/corpus/6417-error-code-dynamic-writes.ts @@ -0,0 +1,36 @@ +// An Error's code written through a dynamic view (a `catch (e: any)` +// binding), copied onto an Error subclass with Object.assign, set to +// undefined, or deleted is what typed reads and `'code' in err` see. +class CodedError extends Error {} + +const original = new Error("a") as NodeJS.ErrnoException; +try { + throw original; +} catch (e: any) { + e.code = "E_ANY"; +} +console.log("any write", original.code, "code" in original); + +try { + throw original; +} catch (e: any) { + delete e.code; +} +console.log("any delete", original.code, "code" in original); + +function codeOf(err: NodeJS.ErrnoException): string | undefined { + return err.code; +} +const sub = new CodedError("b"); +Object.assign(sub, { code: "E_ASSIGN" }); +console.log("subclass assign", codeOf(sub), "code" in sub); + +const plain = new Error("c") as NodeJS.ErrnoException; +Object.assign(plain, { code: "E_PLAIN" }); +console.log("assign", plain.code, "code" in plain); + +const cleared = new Error("d") as NodeJS.ErrnoException; +cleared.code = undefined; +console.log("undefined", cleared.code, "code" in cleared); +const fresh = new Error("e") as NodeJS.ErrnoException; +console.log("fresh", fresh.code, "code" in fresh); diff --git a/tests/harness/corpus-costs/6417-error-code-dynamic-writes.ts.json b/tests/harness/corpus-costs/6417-error-code-dynamic-writes.ts.json new file mode 100644 index 000000000..fb3867563 --- /dev/null +++ b/tests/harness/corpus-costs/6417-error-code-dynamic-writes.ts.json @@ -0,0 +1 @@ +{"plain":3425} From 08fb421628ea11b7c94855f5dd2e51399129174f Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Tue, 20 Oct 2026 01:27:17 -0700 Subject: [PATCH 20/39] Compile NodeJS stream interfaces as general streams when other streams flow into them Co-Authored-By: Claude Opus 5.5 --- .../ambient/scriptc-node-fallback.d.ts | 59 +++++++++--- .../src/backend/llvm/expr-stream-callbacks.ts | 42 ++++++++- .../compiler/src/backend/llvm/lib-process.ts | 22 +++++ .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../frontend/lowering/builtins/properties.ts | 38 +++++++- .../src/frontend/lowering/general-streams.ts | 94 +++++++++++++++++++ .../frontend/lowering/lower-event-emitter.ts | 14 ++- .../src/frontend/lowering/lower-modules.ts | 8 ++ .../src/frontend/lowering/lower-stdlib.ts | 11 ++- .../src/frontend/lowering/lower-stream.ts | 62 +++++++++++- .../compiler/src/frontend/lowering/lowerer.ts | 55 ++++++++++- packages/compiler/src/frontend/type-mapper.ts | 66 +++++++++---- packages/compiler/src/ir/builtin-effects.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 12 +++ packages/compiler/src/ir/runtime-features.ts | 2 + packages/compiler/src/ir/validate.ts | 14 +++ packages/runtime/src/scr_stream.c | 39 ++++++++ packages/runtime/src/scr_stream.h | 5 + .../6463-node-readable-stream-producers.ts | 75 +++++++++++++++ .../6464-node-writable-stream-producers.ts | 68 ++++++++++++++ .../6465-node-stream-js-boundary/consume.js | 12 +++ .../6465-node-stream-js-boundary/main.ts | 33 +++++++ .../node-types/node-stream-interfaces.ts | 61 ++++++++++++ tests/harness/project-config.test.ts | 18 ++++ 24 files changed, 774 insertions(+), 38 deletions(-) create mode 100644 packages/compiler/src/frontend/lowering/general-streams.ts create mode 100644 tests/corpus/6463-node-readable-stream-producers.ts create mode 100644 tests/corpus/6464-node-writable-stream-producers.ts create mode 100644 tests/corpus/6465-node-stream-js-boundary/consume.js create mode 100644 tests/corpus/6465-node-stream-js-boundary/main.ts create mode 100644 tests/fixtures/node-types/node-stream-interfaces.ts diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 436bcace3..28e481b9d 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -80,21 +80,56 @@ declare namespace NodeJS { path?: string | undefined; syscall?: string | undefined; } - /* The piped child-output stream (child.stdout / child.stderr under - * stdio ["ignore", "pipe", "pipe"]): 'data' fires one Buffer chunk per - * read (≤64KB, consumer-driven — no listener, no read), 'end' fires - * once at EOF and always BEFORE the child's 'exit'. A flowing stream - * keeps the loop alive. */ + /* The readable-stream interface every Node stream implements. The + * piped child-output stream (child.stdout / child.stderr under stdio + * ["ignore", "pipe", "pipe"]) is declared with it: 'data' fires one + * Buffer chunk per read (≤64KB, consumer-driven — no listener, no + * read), 'end' fires once at EOF and always BEFORE the child's 'exit'. A + * flowing stream keeps the loop alive. A program that also passes + * other streams (fs, zlib, node:stream) where this interface is + * expected compiles it as the node:stream Readable, with child output + * bridged into one. */ interface ReadableStream { on(event: "data", listener: (chunk: Buffer) => void): void; on(event: "data", listener: (chunk: string) => void): void; on(event: "end", listener: () => void): void; + on(event: "close", listener: () => void): void; + on(event: "error", listener: (err: Error) => void): void; once(event: "data", listener: (chunk: Buffer) => void): void; once(event: "data", listener: (chunk: string) => void): void; once(event: "end", listener: () => void): void; + once(event: "close", listener: () => void): void; + once(event: "error", listener: (err: Error) => void): void; /* setEncoding('utf8') makes subsequent data chunks strings, including * multibyte sequences split across native pipe reads. */ setEncoding(encoding: string): this; + readonly readable: boolean; + pause(): this; + resume(): this; + isPaused(): boolean; + pipe(destination: T, options?: { end?: boolean }): T; + unpipe(destination?: WritableStream): this; + } + /* The writable-stream interface every Node stream implements: + * process.stdout/process.stderr, fs.WriteStream and the node:stream + * Writable family. Written only to the process streams, it compiles as + * their descriptor; with other streams flowing into it, as the + * node:stream Writable (the process streams convert into one). */ + interface WritableStream { + readonly writable: boolean; + write(data: string | Uint8Array, callback?: (error?: Error | null) => void): boolean; + write( + data: string | Uint8Array, + encoding: BufferEncoding, + callback?: (error?: Error | null) => void, + ): boolean; + end(callback?: () => void): this; + end(data: string | Uint8Array, callback?: () => void): this; + end(data: string | Uint8Array, encoding: BufferEncoding, callback?: () => void): this; + on(event: "drain" | "finish" | "close", listener: () => void): void; + on(event: "error", listener: (err: Error) => void): void; + once(event: "drain" | "finish" | "close", listener: () => void): void; + once(event: "error", listener: (err: Error) => void): void; } } @@ -6317,7 +6352,7 @@ declare module "node:cluster" { /* node:tty — the fd probe (the same isatty(3) behind process.*.isTTY) * and the supported structural view of a process output stream. */ declare module "tty" { - export interface WriteStream { + export interface WriteStream extends NodeJS.WritableStream { write(data: string | Uint8Array, callback?: (error?: Error | null) => void): boolean; write( data: string | Uint8Array, @@ -6567,8 +6602,8 @@ declare module "stream" { resume(): this; isPaused(): boolean; setEncoding(encoding: string): this; - pipe(destination: T, options?: { end?: boolean }): T; - unpipe(destination?: Writable): this; + pipe(destination: T, options?: { end?: boolean }): T; + unpipe(destination?: NodeJS.WritableStream): this; destroy(error?: Error): this; readonly readable: boolean; readonly readableEnded: boolean; @@ -6701,12 +6736,12 @@ declare module "stream" { readonly closed: boolean; readonly destroyed: boolean; readonly errored: Error | null; - on(event: "drain" | "finish" | "close", listener: () => void): this; - on(event: "error", listener: (err: Error) => void): this; + on(event: "drain" | "finish" | "close", listener: () => void): void; + on(event: "error", listener: (err: Error) => void): void; on(event: "pipe" | "unpipe", listener: (src: Readable) => void): this; on(event: string, listener: (...args: any[]) => void): this; - once(event: "drain" | "finish" | "close", listener: () => void): this; - once(event: "error", listener: (err: Error) => void): this; + once(event: "drain" | "finish" | "close", listener: () => void): void; + once(event: "error", listener: (err: Error) => void): void; once(event: "pipe" | "unpipe", listener: (src: Readable) => void): this; once(event: string, listener: (...args: any[]) => void): this; addListener(event: "drain" | "finish" | "close", listener: () => void): this; diff --git a/packages/compiler/src/backend/llvm/expr-stream-callbacks.ts b/packages/compiler/src/backend/llvm/expr-stream-callbacks.ts index 3f7961163..9be757a20 100644 --- a/packages/compiler/src/backend/llvm/expr-stream-callbacks.ts +++ b/packages/compiler/src/backend/llvm/expr-stream-callbacks.ts @@ -17,7 +17,7 @@ export function streamDataAdapter( const p = cbT.params[0]; if ( cbT.params.length > 1 || - (p && p.kind !== "bytes" && p.kind !== "string" && p.kind !== "dyn") + (p && p.kind !== "bytes" && p.kind !== "string" && p.kind !== "dyn" && p.kind !== "union") ) { throw new InternalCompilerError( "llvm emitter bug: stream data listener param shape (frontend must fence)", @@ -73,6 +73,46 @@ export function streamDataAdapter( ); finish("%r0"); d.push(`}`, ``); + } else if (p.kind === "union") { + // A `Buffer | string` chunk: wrap whichever slot the stream filled at + // its arm of the (boxed) union. + const def = host.unionsById.get(p.unionId); + const bytesTag = def ? def.arms.findIndex((a) => a.kind === "bytes" && a.elem === "u8") : -1; + const strTag = def ? def.arms.findIndex((a) => a.kind === "string") : -1; + if ( + !def || + host.nullableUnions.has(p.unionId) || + bytesTag < 0 || + strTag < 0 || + def.arms.length !== 2 + ) + throw new InternalCompilerError( + "llvm emitter bug: stream data listener union is not Buffer | string (frontend must fence)", + ); + host.declare(`declare ptr @scr_union_new_ref(i32, ptr, ptr, ptr, ptr)`); + host.declare(`declare ptr @scr_bytes_retain_v(ptr)`); + host.declare(`declare void @scr_bytes_release_v(ptr)`); + host.declare(`declare ptr @scr_str_retain_v(ptr)`); + host.declare(`declare void @scr_str_release_v(ptr)`); + d.push( + ` %uslot = alloca ptr`, + ` %isb = icmp ne ptr %a0, null`, + ` br i1 %isb, label %buf, label %str`, + `buf:`, + ` %rb = call ptr @scr_bytes_retain_v(ptr %a0)`, + ` %ub = call ptr @scr_union_new_ref(i32 ${bytesTag}, ptr %rb, ptr @scr_bytes_retain_v, ptr @scr_bytes_release_v, ptr null)`, + ` store ptr %ub, ptr %uslot`, + ` br label %go`, + `str:`, + ` %rs = call ptr @scr_str_retain_v(ptr %a1)`, + ` %us = call ptr @scr_union_new_ref(i32 ${strTag}, ptr %rs, ptr @scr_str_retain_v, ptr @scr_str_release_v, ptr null)`, + ` store ptr %us, ptr %uslot`, + ` br label %go`, + `go:`, + ` %uv = load ptr, ptr %uslot`, + ); + finish("%uv"); + d.push(`}`, ``); } else { // dyn: box by runtime tag — the JS lane's adapter parameter. host.declare(`declare ptr @scr_dyn_new_buffer(ptr)`); diff --git a/packages/compiler/src/backend/llvm/lib-process.ts b/packages/compiler/src/backend/llvm/lib-process.ts index eaf7f31cd..4a7be1a35 100644 --- a/packages/compiler/src/backend/llvm/lib-process.ts +++ b/packages/compiler/src/backend/llvm/lib-process.ts @@ -305,6 +305,28 @@ export function emitChildProcessLibCall(host: LlvmEmitterContext, e: LibCallExpr B.line(`${raw} = call ptr @${get}(ptr ${recv.name}) ; +1 or NULL`); return host.wrapNullable(raw, raw, def!.arms[streamTag]!, streamTag, e.type, nullTag); } + if (e.fn === "child.stdioStream") { + // The general stream representation's stdio read: the child's bridged + // runtime stream (+1) or NULL for an unpiped slot. + if (e.type.kind !== "union") + throw new InternalCompilerError(`llvm emitter bug: ${e.fn} result is not a union`); + const def = host.unionsById.get(e.type.unionId); + const streamTag = def ? def.arms.findIndex((a) => a.kind === "object") : -1; + const nullTag = def ? def.arms.findIndex((a) => a.kind === "nullT") : -1; + const fd = e.args[1]; + if (streamTag < 0 || nullTag < 0 || fd?.kind !== "numLit") + throw new InternalCompilerError(`llvm emitter bug: ${e.fn} lacks its arms or slot`); + const recv = host.emitExpr(e.args[0]!); + const key = fd.value === 0 ? "stdin" : fd.value === 1 ? "stdout" : "stderr"; + host.declare(`declare ptr @scr_stream_child_stdio(ptr, ptr, ${host.sizeType})`); + const raw = B.tmp(); + B.line( + `${raw} = call ptr @scr_stream_child_stdio(ptr ${recv.name}, ptr ${host.cstr(key)}, ${host.sizeType} ${key.length}) ; +1 or NULL`, + ); + const out = host.wrapNullable(raw, raw, def!.arms[streamTag]!, streamTag, e.type, nullTag); + host.emitPendingCheck(); + return out; + } if (e.fn === "writer.writeString" || e.fn === "writer.writeBytes") { const writer = host.emitExpr(e.args[0]!); const data = host.emitExpr(e.args[1]!); diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 294128107..61d31435c 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -726,6 +726,7 @@ export const LIB_FN_SYMS: Record = { "child.unref": "scr_child_unref", "child.ref": "scr_child_ref", "procStream.write": "scr_proc_stream_write", + "stream.stdioWritable": "scr_stream_stdio_writable", "process.kill": "scr_process_kill_named", "process.killNum": "scr_process_kill", // fs.promises (scr_bytes_io.c / scr_lib.c): the promise forms settle diff --git a/packages/compiler/src/frontend/lowering/builtins/properties.ts b/packages/compiler/src/frontend/lowering/builtins/properties.ts index b0caa0456..3c0486f82 100644 --- a/packages/compiler/src/frontend/lowering/builtins/properties.ts +++ b/packages/compiler/src/frontend/lowering/builtins/properties.ts @@ -1,5 +1,5 @@ import { isBuiltinClassInstance } from "./receiver-types.js"; -import { strLit } from "../../../ir/build.js"; +import { numLit, strLit } from "../../../ir/build.js"; import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; import { locOf } from "../../program.js"; @@ -192,6 +192,25 @@ export function lowerBuiltinExtraProperty( // +1-or-NULL runtime pair. if (kind === "child" && (name === "stdin" || name === "stdout" || name === "stderr")) { const receiver = lowerer.lowerExpr(expr.expression); + // Under the general stream representation (general-streams.ts) the + // declared stream type maps to a runtime stream class: the read + // answers the child's bridged stream (one per stdio slot, so repeated + // reads keep identity), fed by the same pipe. + const general = lowerer.generalNodeStreams ? generalChildStdioType(lowerer, expr, name) : null; + if (general) { + const type: IrType = { + kind: "union", + unionId: lowerer.unions.intern([general, { kind: "nullT" }]), + }; + const read: IrExpr = { + kind: "libCall", + fn: "child.stdioStream", + args: [receiver, numLit(name === "stdin" ? 0 : name === "stdout" ? 1 : 2, loc)], + type, + loc, + }; + return lowerer.maybeNarrow(read, expr); + } const streamType = name === "stdin" ? CHILDWRITER_T : CHILDSTREAM_T; const type: IrType = { kind: "union", @@ -259,3 +278,20 @@ export function lowerBuiltinExtraProperty( } return null; } + +/** The runtime stream class a child stdio read produces under the general + * stream representation, or null when the declared type keeps the stdio + * handle (the fallback declarations' ChildStdin). */ +function generalChildStdioType( + lowerer: Lowerer, + expr: ts.PropertyAccessExpression, + name: "stdin" | "stdout" | "stderr", +): IrType | null { + const className = name === "stdin" ? "%Writable" : "%Readable"; + const mapped = lowerer.mapTypeOf(lowerer.typeOf(expr)); + if (!mapped) return null; + const arms = mapped.kind === "union" ? (lowerer.unions.get(mapped.unionId)?.arms ?? []) : [mapped]; + return arms.some((arm) => arm.kind === "object" && arm.className === className) + ? { kind: "object", className } + : null; +} diff --git a/packages/compiler/src/frontend/lowering/general-streams.ts b/packages/compiler/src/frontend/lowering/general-streams.ts new file mode 100644 index 000000000..6b51ce545 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/general-streams.ts @@ -0,0 +1,94 @@ +/* The general stream representation (TypeMapperCtx.generalNodeStreams). + * + * NodeJS.ReadableStream and NodeJS.WritableStream (and @types/node's + * stream.Readable / stream.Writable, which also type child stdio) name the + * interface every Node stream implements. By default they map to the + * child/process stdio handles: the specialized representation of the + * values that commonly fill them (child.stdout, process.stdout). A program + * that moves another stream — fs.createReadStream(), a zlib Transform, a + * Readable subclass — into one of those slots needs the general + * representation instead: the runtime stream classes, with the stdio + * handles converted into them where they are read or flow. + * + * The decision is per program. Reachable emit lowers without it; a flow + * that needs it marks the lowerer (needsGeneralNodeStreams) and lowerToIr + * lowers the whole program again with it. Programs without such a flow + * never take the second pass, so their IR is unchanged. */ +import type { IrExpr, IrType } from "../../ir/ir.js"; +import { everyTypeChild } from "../../ir/traverse.js"; +import type { Lowerer } from "./lowerer.js"; +import { streamSidesOf } from "./lower-stream.js"; + +const STDIO_STREAM_KINDS: ReadonlySet = new Set([ + "childStream", + "childWriter", + "procStream", +]); + +/** Whether `type` (through union arms, record fields and the structural + * type children) contains a part satisfying `test`. */ +function containsPart(lowerer: Lowerer, type: IrType, test: (part: IrType) => boolean): boolean { + const seen = new Set(); + const walk = (part: IrType): boolean => { + if (test(part)) return true; + if (part.kind === "union") { + if (seen.has(`u:${part.unionId}`)) return false; + seen.add(`u:${part.unionId}`); + return (lowerer.unions.get(part.unionId)?.arms ?? []).some(walk); + } + if (part.kind === "record") { + if (seen.has(`r:${part.shapeId}`)) return false; + seen.add(`r:${part.shapeId}`); + return (lowerer.shapes.get(part.shapeId)?.fields ?? []).some((f) => walk(f.type)); + } + let found = false; + everyTypeChild(part, (child) => { + found = walk(child); + return !found; + }); + return found; + }; + return walk(type); +} + +function isGeneralStream(lowerer: Lowerer, part: IrType): boolean { + return ( + part.kind === "object" && streamSidesOf(lowerer, lowerer.classes.get(part.className)) !== null + ); +} + +/** A mismatched flow (requireExactShape's input) that the general stream + * representation resolves: a general stream into a stdio-represented + * slot, a stdio handle into an 'unknown' slot, or an 'unknown' value + * checked into a stdio-represented slot. */ +export function needsGeneralNodeStreams( + lowerer: Lowerer, + actual: IrType, + expected: IrType, +): boolean { + const stdio = (part: IrType): boolean => STDIO_STREAM_KINDS.has(part.kind); + const pipeHandle = (part: IrType): boolean => + part.kind === "childStream" || part.kind === "childWriter"; + if (containsPart(lowerer, expected, stdio)) { + return actual.kind === "dyn" || containsPart(lowerer, actual, (p) => isGeneralStream(lowerer, p)); + } + return expected.kind === "dyn" && containsPart(lowerer, actual, pipeHandle); +} + +/** Under the general representation, process.stdout / process.stderr (the + * procStream fd scalar) flowing into a runtime Writable slot: an + * fd-backed Writable whose writes take the same synchronous path as + * process.stdout.write. Null when the flow is not that one. */ +export function stdioIntoGeneralStream( + lowerer: Lowerer, + expr: IrExpr, + expected: IrType, +): IrExpr | null { + if (!lowerer.generalNodeStreams || expr.type.kind !== "procStream") return null; + const writable: IrType = { kind: "object", className: "%Writable" }; + const accepts = + (expected.kind === "object" && expected.className === "%Writable") || + (expected.kind === "union" && lowerer.armTag(expected.unionId, writable) >= 0); + if (!accepts) return null; + return { kind: "libCall", fn: "stream.stdioWritable", args: [expr], type: writable, loc: expr.loc }; +} diff --git a/packages/compiler/src/frontend/lowering/lower-event-emitter.ts b/packages/compiler/src/frontend/lowering/lower-event-emitter.ts index 06e9c4ab1..4b8b9ea14 100644 --- a/packages/compiler/src/frontend/lowering/lower-event-emitter.ts +++ b/packages/compiler/src/frontend/lowering/lower-event-emitter.ts @@ -1245,7 +1245,19 @@ export function lowerEmitterMethodCall( ); } const p = cbT.params[0]; - if (p !== undefined && !(p.kind === "bytes" && p.elem === "u8") && p.kind !== "string") { + // A `Buffer | string` chunk (NodeJS.ReadableStream's listener + // shape) takes whichever side the stream delivers. + const chunkUnion = + p?.kind === "union" && + (lowerer.unions.get(p.unionId)?.arms ?? []).every( + (arm) => (arm.kind === "bytes" && arm.elem === "u8") || arm.kind === "string", + ); + if ( + p !== undefined && + !(p.kind === "bytes" && p.elem === "u8") && + p.kind !== "string" && + !chunkUnion + ) { lowerer.noLowering( `a 'data' listener whose chunk parameter is '${lowerer.fmt(p)}'`, args[1]!, diff --git a/packages/compiler/src/frontend/lowering/lower-modules.ts b/packages/compiler/src/frontend/lowering/lower-modules.ts index fa4c98372..aac5883cd 100644 --- a/packages/compiler/src/frontend/lowering/lower-modules.ts +++ b/packages/compiler/src/frontend/lowering/lower-modules.ts @@ -872,6 +872,14 @@ export function moduleArtifacts( valueInstanceOfRoots.add(root.def.name); } break; + case "libCall": + // The general stream representation's child stdio read bridges + // through the runtime install that boxes both stream classes. + if (node.fn === "child.stdioStream") { + visitClass("%Readable"); + visitClass("%Writable"); + } + break; case "dynFrom": if (boxedChild(node.value.type)) { // A generic child can expose native stdio without importing stream. diff --git a/packages/compiler/src/frontend/lowering/lower-stdlib.ts b/packages/compiler/src/frontend/lowering/lower-stdlib.ts index 2f0e1c66f..4ddfbe5ba 100644 --- a/packages/compiler/src/frontend/lowering/lower-stdlib.ts +++ b/packages/compiler/src/frontend/lowering/lower-stdlib.ts @@ -4,6 +4,7 @@ import { InternalCompilerError } from "../../errors.js"; import * as ts from "../ts7/adapter.js"; import { lowerToNumberArgument } from "./lower-exprs.js"; import type { Lowerer } from "./lowerer.js"; +import { isDeclaredInAmbientNamespace } from "../type-mapper.js"; import { arrayOf, BOOL, @@ -1021,7 +1022,15 @@ export function fenceStaticAbortControllerMemberRead( function isStdlibFetchInterface(lowerer: Lowerer, node: ts.Node, owner: string): ts.Symbol | null { const type = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(node)); for (const symbol of [type.getSymbol(), type.getAliasSymbol()]) { - if (symbol?.name === owner && lowerer.isStdlibSymbol(symbol)) return symbol; + // NodeJS.ReadableStream shares the WHATWG interface's name. + if ( + symbol?.name === owner && + lowerer.isStdlibSymbol(symbol) && + !symbol.declarations.some( + (d) => ts.isInterfaceDeclaration(d) && isDeclaredInAmbientNamespace(d, "NodeJS"), + ) + ) + return symbol; } return null; } diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index dd0ddcc0e..66595c473 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -3296,6 +3296,62 @@ function pipeEndOption(lowerer: Lowerer, options: ts.Expression | undefined, loc return end; } +/** `readable.pipe(process.stdout)`: the process stream joins the pipe as + * an fd-backed Writable (stream.stdioWritable), and — like Node, which + * never ends process.stdout or process.stderr from a pipe — the source's + * end does not end it. pipe() answers the process stream itself. */ +function pipeIntoStdio( + lowerer: Lowerer, + call: ts.CallExpression, + access: ts.PropertyAccessExpression, + target: IrExpr, +): IrExpr { + const loc = locOf(call); + // JS order: the receiver, then the destination, then the options. + const receiverValue = lowerer.lowerExpr(access.expression); + const source = lowerer.declareHiddenLocal("%pipeSource", receiverValue.type); + const stdio = lowerer.declareHiddenLocal("%pipeStdio", target.type); + const options = call.arguments.nodes[1]; + const stmts: IrStmt[] = [ + { kind: "varDecl", localId: source.id, init: receiverValue, loc }, + { kind: "varDecl", localId: stdio.id, init: target, loc }, + ]; + // The options literal still evaluates; its end flag has no effect here. + if (options !== undefined) { + stmts.push({ kind: "exprStmt", expr: pipeEndOption(lowerer, options, loc), loc }); + } + const receiver: IrExpr = { kind: "varRef", localId: source.id, type: receiverValue.type, loc }; + const writable: IrType = { kind: "object", className: "%Writable" }; + stmts.push({ + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "readable.pipe", + args: [ + receiver, + { + kind: "libCall", + fn: "stream.stdioWritable", + args: [{ kind: "varRef", localId: stdio.id, type: target.type, loc }], + type: writable, + loc, + }, + boolLit(false, loc), + ], + type: writable, + loc, + }, + loc, + }); + return { + kind: "seqExpr", + stmts, + result: { kind: "varRef", localId: stdio.id, type: target.type, loc }, + type: target.type, + loc, + }; +} + export function lowerStreamMethodCall( lowerer: Lowerer, call: ts.CallExpression, @@ -3545,7 +3601,9 @@ export function lowerStreamMethodCall( loc, }; } - const dst = lowerer.lowerExpr(args[0]!); + const target = lowerer.lowerExpr(args[0]!); + if (target.type.kind === "procStream") return pipeIntoStdio(lowerer, call, access, target); + const dst = target; const dstInfo = dst.type.kind === "object" ? lowerer.classes.get(dst.type.className) : undefined; const dstSides = streamSidesOf(lowerer, dstInfo); @@ -3553,7 +3611,7 @@ export function lowerStreamMethodCall( lowerer.noLowering( `pipe into a '${lowerer.fmt(dst.type)}'`, args[0]!, - "the destination must be a stream Writable/Duplex (process streams and sockets are not pipe destinations yet)", + "the destination must be a stream Writable/Duplex, process.stdout or process.stderr (sockets are not pipe destinations yet)", ); } const end = pipeEndOption(lowerer, args[1], loc); diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 1361b346f..2973498e5 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1,3 +1,4 @@ +import { needsGeneralNodeStreams, stdioIntoGeneralStream } from "./general-streams.js"; import { extendAssertedRecordMembers } from "./assertion-members.js"; import { jsDynamicDeclarations } from "./js-dynamic-objects.js"; import { @@ -877,6 +878,10 @@ export interface LowererMode { /** Statically resolved child_process.fork program roots, in stable target-id order. */ forkTargets?: readonly ts.SourceFile[]; frontendServices?: FrontendServices | undefined; + /** The program's general stream representation (TypeMapperCtx. + * generalNodeStreams). lowerToIr turns it on only after a pass without + * it saw a stream flow that needs it (requiresGeneralNodeStreams). */ + generalNodeStreams?: boolean; /** LoadResult.inlineRequireCycleCalls. */ inlineRequireCycleCalls?: ReadonlySet | undefined; /** LowerOptions.libraryCallbacks (see there). */ @@ -1033,10 +1038,40 @@ export function lowerToIr( for (const d of extraModuleCycleDiags) reachableEmit.pushDiag(d); for (const d of ffiValidation.diagnostics) reachableEmit.pushDiag(d); const emitted = reachableEmit.emitReachable(options.libRoots); - const { reachable } = emitted; + let { reachable } = emitted; let result = emitted.result; let resultLowerer = reachableEmit; timing("reachable-emit", { reachable: reachable.size }); + // The general stream representation (TypeMapperCtx.generalNodeStreams) + // is a per-program decision: only a program whose reachable code moved + // a general stream into a stdio-represented stream slot lowers again + // with it. Every other program keeps the single pass above unchanged. + const generalNodeStreams = reachableEmit.requiresGeneralNodeStreams; + if (generalNodeStreams) { + const general = new Lowerer(program, entry, moduleOrder, { + frontendServices: options.frontendServices, + projectCheckJs: options.projectCheckJs ?? false, + targetPlatform, + startupCrash, + inlineRequireCycleCalls: options.inlineRequireCycleCalls, + ffiImports, + libraryCallbacks, + forkTargets, + workerTargets, + externalTypes, + externalTypeSpecifiersByFile, + tierMode, + ffiBindingSymbols: ffiValidation.symbolsByName, + generalNodeStreams: true, + }); + for (const d of extraModuleCycleDiags) general.pushDiag(d); + for (const d of ffiValidation.diagnostics) general.pushDiag(d); + const generalEmitted = general.emitReachable(options.libRoots); + reachable = generalEmitted.reachable; + result = generalEmitted.result; + resultLowerer = general; + timing("general-streams-relower", { reachable: reachable.size }); + } // A generic class-rest support decision can depend on record metadata // whose historical owner is discovered only while retained bodies lower. // If the settled answer is a fence, rerun the ordinary reachable emit so @@ -1044,10 +1079,11 @@ export function lowerToIr( // declarators stay unvisited, bindings block, cascades and stats match the // historical compiler. This is a rare compatibility fallback; programs // without such a settled fence retain checker-backed IR exactly once. - if (reachableEmit.requiresHistoricalOrderRelower) { + if (resultLowerer.requiresHistoricalOrderRelower) { const emit = new Lowerer(program, entry, moduleOrder, { frontendServices: options.frontendServices, projectCheckJs: options.projectCheckJs ?? false, + ...(generalNodeStreams ? { generalNodeStreams: true } : {}), reachable, targetPlatform, startupCrash, @@ -1107,6 +1143,7 @@ export function lowerToIr( const remainder = new Lowerer(program, entry, moduleOrder, { frontendServices: options.frontendServices, projectCheckJs: options.projectCheckJs ?? false, + ...(generalNodeStreams ? { generalNodeStreams: true } : {}), reachable, remainder: true, alreadyFlushed: resultLowerer.flushedSymbols, @@ -2496,6 +2533,12 @@ export class Lowerer { /** Settled generic class-rest metadata requires the historical emit * fallback so its fence can poison the original statement atomically. */ requiresHistoricalOrderRelower = false; + /** A general stream value (a runtime stream class instance) reached a + * slot the child/process stdio handles represent — NodeJS.ReadableStream, + * NodeJS.WritableStream, or @types/node's stream.Readable/Writable — or + * a stdio handle reached an 'unknown' slot. lowerToIr then lowers the + * program again under the general stream representation. */ + requiresGeneralNodeStreams = false; /** Helpers that snapshot shape declaration order into their bodies. * Reachability lowers inits before the declarations they discover, so * these rebuild after the worklist restores historical shape metadata. */ @@ -2943,6 +2986,7 @@ export class Lowerer { * refuse and fence exactly as before. Stage S6 demotes the units of * committed refusals in "auto" and keeps them refusals in "static-only". */ readonly tierMode: TierMode; + readonly generalNodeStreams: boolean; /** Functions finishModule placed in the dynamic tier (ir/tiers.ts). */ dynamicFunctions: DynamicFunction[] = []; /** Their IR, for coverage's dynamic statement count. */ @@ -3071,6 +3115,7 @@ export class Lowerer { this.startupCrash = mode.startupCrash ?? null; this.targetPlatform = mode.targetPlatform ?? process.platform; this.tierMode = mode.tierMode ?? "auto"; + this.generalNodeStreams = mode.generalNodeStreams ?? false; this.workerTargets = mode.workerTargets ?? []; this.workerTargets.forEach((sf, id) => { this.workerTargetIdByPath.set(tsgoPath(resolve(sf.fileName)), id); @@ -3167,6 +3212,7 @@ export class Lowerer { isExternalTypeFile: (sf) => this.externalTypeSpecifiersByFile.has(tsgoPath(resolve(sf.fileName))), typeMemo: this.typeMemo, + ...(this.generalNodeStreams ? { generalNodeStreams: true } : {}), canMemoizeType: () => this.typeParamBindings === null && this.typeParamTsBindings === null && @@ -8451,6 +8497,8 @@ export class Lowerer { * validator ICEs on them as the usual backstop. */ requireExactShape(node: ts.Node, actual: IrType, expected: IrType): void { if (typeEquals(actual, expected)) return; + if (!this.generalNodeStreams && needsGeneralNodeStreams(this, actual, expected)) + this.requiresGeneralNodeStreams = true; // dyn mismatches first. A dyn ('unknown') value flowing into a typed // slot needs a CHECKED cast — the hint points at `as `; tsc // usually rejects this before we do, so the fence is mostly defensive. @@ -8657,6 +8705,9 @@ export class Lowerer { } if (expr.type.kind === "void" && expected.kind !== "void" && this.neverValued.has(expr)) return this.divergentValue(expr, expected); + // process.stdout/stderr into a general Writable slot (general-streams.ts). + const stdioStream = stdioIntoGeneralStream(this, expr, expected); + if (stdioStream) return this.coerceToExpected(stdioStream, expected); // Iterator-typed slots: native iterators and differently typed // generators step through an adapter generator. if (expected.kind === "generator" && !typeEquals(expr.type, expected)) { diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 94506f034..afa9f4311 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -980,7 +980,7 @@ function isDeclaredInAmbientModule(d: ts.Declaration, name: string): boolean { /** True when the declaration's nearest enclosing namespace is `name` * (`declare global { namespace NodeJS { ... } }` — the NodeJS-global * interfaces @types/node declares outside any ambient module). */ -function isDeclaredInAmbientNamespace(d: ts.Declaration, name: string): boolean { +export function isDeclaredInAmbientNamespace(d: ts.Declaration, name: string): boolean { let node: ts.Node | undefined = d.parent; while (node) { if (ts.isModuleDeclaration(node) && ts.isIdentifier(node.name)) { @@ -1146,6 +1146,13 @@ export interface TypeMapperCtx { * type descriptions for project-owned values, but their imported runtime * bindings are fenced separately by the Lowerer. */ isExternalTypeFile: (sf: ts.SourceFile) => boolean; + /** The program's general stream representation (lowerToIr decides it + * per program): NodeJS.ReadableStream / NodeJS.WritableStream and + * @types/node's stream.Readable / stream.Writable map to the runtime + * stream classes instead of the child/process stdio handles, so values + * from every stream producer share their slots. Off (the default), the + * stdio handles keep those spellings. */ + generalNodeStreams?: boolean; /** Successful context-free mappings, keyed by the * TypeScript server's stable type id. A generated facade can reference the * same large record/function type thousands of times; remapping its full @@ -2998,6 +3005,20 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { // global-namespace interface real code writes in its own signatures — // prefixStream's `output` param). The representation is the raw fd // scalar; the lowered surface is write(string). + // Under the program's general stream representation (generalNodeStreams) + // NodeJS.WritableStream is the runtime Writable instead: the process + // streams convert into it where they flow (process.stdioWritable). + const nodeWritableInterface = + psym?.name === "WritableStream" && + psym.declarations.some( + (d) => + ts.isInterfaceDeclaration(d) && + ctx.isStdlibFile(d.getSourceFile()) && + isDeclaredInAmbientNamespace(d, "NodeJS"), + ); + if (nodeWritableInterface && ctx.generalNodeStreams === true) { + return { kind: "object", className: "%Writable" }; + } if ( (psym?.name === "WriteStream" && psym.declarations.some( @@ -3007,13 +3028,7 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { (isDeclaredInAmbientModule(d, "tty") || (isDeclaredInAmbientModule(d, "process") && isDeclaredInAmbientNamespace(d, "NodeJS"))), )) || - (psym?.name === "WritableStream" && - psym.declarations.some( - (d) => - ts.isInterfaceDeclaration(d) && - ctx.isStdlibFile(d.getSourceFile()) && - isDeclaredInAmbientNamespace(d, "NodeJS"), - )) + nodeWritableInterface ) { return PROCSTREAM_T; } @@ -3030,6 +3045,7 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { isDeclaredInAmbientModule(d, "child_process"), )) || (psym?.name === "Writable" && + ctx.generalNodeStreams !== true && psym.declarations.some( (d) => (ts.isInterfaceDeclaration(d) || ts.isClassDeclaration(d)) && @@ -3047,6 +3063,9 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { // branch: the fallback's Readable must map to the runtime class, and // under the fallback child.stdout is NodeJS.ReadableStream (its own // branch below), so the two never collide. + // @types/node's Duplex/Transform/PassThrough classes have no child-stdio + // reading, so they map to the runtime classes too; its Readable and + // Writable join them under the general representation. for (const [irName, rec] of RUNTIME_STREAM_CLASSES) { if ( psym?.name === rec.lib && @@ -3054,15 +3073,17 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { (d) => ts.isClassDeclaration(d) && ctx.isStdlibFile(d.getSourceFile()) && - !isNodeTypesPath(d.getSourceFile().fileName) && + (!isNodeTypesPath(d.getSourceFile().fileName) || + ctx.generalNodeStreams === true || + (rec.lib !== "Readable" && rec.lib !== "Writable")) && isDeclaredInAmbientModule(d, "stream"), ) ) { return { kind: "object", className: irName }; } } - // node:zlib's stream classes (the shipped fallback declarations): their - // instances are runtime Transform streams. + // node:zlib's stream classes (the shipped fallback declarations and + // @types/node's): their instances are runtime Transform streams. if ( psym !== undefined && ZLIB_STREAM_MODES.has(psym.name) && @@ -3070,22 +3091,20 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { (d) => ts.isClassDeclaration(d) && ctx.isStdlibFile(d.getSourceFile()) && - !isNodeTypesPath(d.getSourceFile().fileName) && isDeclaredInAmbientModule(d, "zlib"), ) ) { return { kind: "object", className: "%Transform" }; } - // fs.ReadStream / fs.WriteStream (the shipped fallback declarations): - // their instances are runtime Readable / Writable streams - // (scr_fs_stream.c). + // fs.ReadStream / fs.WriteStream (the shipped fallback declarations and + // @types/node's): their instances are runtime Readable / Writable + // streams (scr_fs_stream.c). if ( (psym?.name === "ReadStream" || psym?.name === "WriteStream") && psym.declarations.some( (d) => ts.isClassDeclaration(d) && ctx.isStdlibFile(d.getSourceFile()) && - !isNodeTypesPath(d.getSourceFile().fileName) && isDeclaredInAmbientModule(d, "fs"), ) ) { @@ -3107,6 +3126,9 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { isDeclaredInAmbientNamespace(d, "NodeJS"), )) ) { + // The general representation: the runtime Readable, which child + // stdio reads produce through the child stream bridge. + if (ctx.generalNodeStreams === true) return { kind: "object", className: "%Readable" }; return { kind: "childStream" }; } // dgram.Socket: the same ambiguous "Socket" name disambiguated by its @@ -4125,10 +4147,18 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { const mapped = mapType(checker.getTypeOfSymbol(p), ctx); if (!mapped) return false; const arms = mapped.kind === "union" ? ctx.unions.get(mapped.unionId)?.arms : [mapped]; + // Under the general stream representation the stdio members are the + // runtime stream classes. + const isExpected = (arm: IrType): boolean => + arm.kind === expected || + (ctx.generalNodeStreams === true && + arm.kind === "object" && + ((expected === "childStream" && arm.className === "%Readable") || + (expected === "childWriter" && arm.className === "%Writable"))); return ( arms !== undefined && - arms.some((arm) => arm.kind === expected) && - arms.every((arm) => arm.kind === expected || arm.kind === unit) + arms.some(isExpected) && + arms.every((arm) => isExpected(arm) || arm.kind === unit) ); }; const childShaped = diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 6757851d9..2973a9aa2 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -75,6 +75,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "process.stdoutWriteBytes", "process.stderrWriteBytes", "procStream.write", + "child.stdioStream", "weakMap.new", "weakSet.new", "dyn.fromEntries", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 2cbb35185..2e4faedb4 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -2534,6 +2534,11 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * queue, end/destroy settle it, writable is a pure state read, and * listener callbacks move into the writer registry. */ "child.stdin": { argTypes: [CHILD_T], result: VOID }, + /** Under the general stream representation (general-streams.ts), a + * stdio read (slot 0, 1 or 2) answers the child's bridged runtime stream + * — `Writable | null` for stdin, `Readable | null` otherwise; the bridge + * throws when the program lacks the stream unit's boxing helpers. */ + "child.stdioStream": { argTypes: [CHILD_T, F64], result: VOID }, // Listener registrations: callback func shapes are program-dependent // (zero-param / Buffer / Buffer-armed union) — the slots pin arity, // the stream receiver, and the once-flag. @@ -2555,6 +2560,13 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * stderrWrite paths so buffering and ordering stay identical. Data * borrowed; the bool is Node's always-true backpressure signal. */ "procStream.write": { argTypes: [PROCSTREAM_T, STRING], result: BOOL }, + /** process.stdout/stderr flowing into a runtime Writable slot under the + * general stream representation: an fd-backed Writable (+1) whose + * writes take process.stdout.write's synchronous path. */ + "stream.stdioWritable": { + argTypes: [PROCSTREAM_T], + result: { kind: "object", className: "%Writable" }, + }, "child.killed": { argTypes: [CHILD_T], result: BOOL }, "child.kill": { argTypes: [CHILD_T, STRING], result: BOOL }, "child.killNum": { argTypes: [CHILD_T, F64], result: BOOL }, diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 4d59a6241..572a93273 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -144,6 +144,7 @@ const ABORT_SIGNAL_LIB_FNS: ReadonlySet = new Set([ /** Entry points that link the stream unit (with STREAM_LIB_PREFIXES). */ const STREAM_LIB_FNS: ReadonlySet = new Set([ + "child.stdioStream", "console.bind", "crypto.hashStream", "crypto.hashStreamPiped", @@ -162,6 +163,7 @@ const STREAM_LIB_FNS: ReadonlySet = new Set([ "stream.destroyErr", "stream.errored", "stream.prop", + "stream.stdioWritable", "stream.workerStdio", ]); diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index 50ba236b8..63078ae4a 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -5224,6 +5224,20 @@ function validateFunction( } return true; } + if (e.fn === "child.stdioStream") { + const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined; + const slot = e.args[1]; + const className = + slot?.kind === "numLit" ? (slot.value === 0 ? "%Writable" : "%Readable") : null; + const ok = + def && + className !== null && + def.arms.length === 2 && + def.arms.some((a) => a.kind === "object" && a.className === className) && + def.arms.some((a) => a.kind === "nullT"); + if (!ok) err(`libCall ${e.fn} must return the stream class of its stdio slot or null`, e.loc); + return true; + } if (e.fn === "child.stdin" || e.fn === "child.stdout" || e.fn === "child.stderr") { const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined; const handleKind = e.fn === "child.stdin" ? "childWriter" : "childStream"; diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index 5f0bb493d..b7d99984a 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -6619,3 +6619,42 @@ ScrStream *scr_crypto_hash_stream_piped(ScrCryptoHash *hash) { if (s) scr_crypto_hash_stream_hold(hash); return s; } + +/* ── the compiler's general stream representation ───────────────────── + * NodeJS.ReadableStream / NodeJS.WritableStream slots that also hold other + * streams compile as this unit's classes; the stdio handles convert into + * them where they are read or flow. Both entry points sit last in the unit + * and reference only global symbols and no new constant data, so programs + * that never convert link the same bytes as before. */ + +/* A child stdio read (the child.stdioStream libCall): the bridged stream + * the checked-dynamic ChildProcess view answers for the same key ("stdin", + * "stdout" or "stderr", passed by the compiled program), so both views + * share one stream per slot. +1, or NULL for an unpiped slot or a throw. */ +ScrStream *scr_stream_child_stdio(void *child, const char *key, size_t key_len) { + ScrDyn *handle = scr_dyn_new_handle(child, SCR_DYNH_CHILD); + ScrDyn *box = scr_dyn_handle_ops_of(handle)->get(child, key, key_len); + scr_dyn_release(handle); + if (box == NULL) return NULL; + ScrStream *stream = box->kind == SCR_DYN_TYPED_REF ? scr_dyn_typed_ref_unbox(box) : NULL; + scr_dyn_release(box); + return stream; +} + +/* process.stdout / process.stderr flowing into a Writable slot (the + * stream.stdioWritable libCall): a Writable whose _write hands each chunk + * to the descriptor through process.stdout.write's synchronous path and + * completes at once, so ordering against console output and direct writes + * is unchanged. The closure keeps the fd as given (1 or 2). */ +static void scr_stream_stdio_write(ScrClosure *cb, ScrStream *s, ScrBytes *chunk) { + int fd = (int)scr_box_get_f64(cb->caps[0]); + (void)scr_stdio_write(fd == 2 ? 2 : 1, chunk->data, chunk->len * scr_bytes_elem_size(chunk->elem)); + scr_stream_write_done(s, NULL); +} +ScrStream *scr_stream_stdio_writable(double fd) { + ScrClosure *write = scr_closure_new((void *)scr_stream_stdio_write, 1); + write->caps[0] = scr_box_new(SCR_BOX_F64); + scr_box_set_f64(write->caps[0], fd); + return scr_stream_new_writable(-1, true, true, write, scr_stream_stdio_write, + NULL, NULL, NULL, NULL); +} diff --git a/packages/runtime/src/scr_stream.h b/packages/runtime/src/scr_stream.h index 82727c1dc..f6c3c24e5 100644 --- a/packages/runtime/src/scr_stream.h +++ b/packages/runtime/src/scr_stream.h @@ -125,6 +125,11 @@ void scr_stream_init_passthrough(ScrStream *s, double rhwm, double whwm, bool au ScrStream *scr_stream_new_readable_dyn(struct ScrDyn *opts); void scr_stream_worker_stdio(void); ScrStream *scr_stream_new_writable_dyn(struct ScrDyn *opts); +/* The general stream representation's conversions (+1): a child's bridged + * stdio stream by key (NULL when unpiped), and process.stdout/stderr as a + * Writable (fd 1 or 2). */ +ScrStream *scr_stream_child_stdio(void *child, const char *key, size_t key_len); +ScrStream *scr_stream_stdio_writable(double fd); ScrStream *scr_stream_new_duplex_dyn(struct ScrDyn *opts); ScrStream *scr_stream_new_transform_dyn(struct ScrDyn *opts); ScrStream *scr_stream_new_passthrough_dyn(struct ScrDyn *opts); diff --git a/tests/corpus/6463-node-readable-stream-producers.ts b/tests/corpus/6463-node-readable-stream-producers.ts new file mode 100644 index 000000000..4d06fac94 --- /dev/null +++ b/tests/corpus/6463-node-readable-stream-producers.ts @@ -0,0 +1,75 @@ +// NodeJS.ReadableStream is the interface every Node readable implements. +// One helper typed with it consumes a file stream, a Readable subclass, +// Readable.from, a gunzip Transform fed through pipe(), and a child's +// stdout. A program that mixes those producers compiles the interface as +// the node:stream Readable, with the child's pipe bridged into one. +import { spawn } from "node:child_process"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import { Readable } from "node:stream"; +import * as zlib from "node:zlib"; + +function drain(label: string, src: NodeJS.ReadableStream): Promise { + return new Promise((resolve, reject) => { + let text = ""; + let chunks = 0; + src.on("data", (chunk: Buffer | string) => { + chunks++; + text += typeof chunk === "string" ? `[s]${chunk}` : chunk.toString("utf8"); + }); + src.on("error", (err) => reject(err)); + src.on("end", () => { + console.log(label, "end", chunks > 0, src.readable); + resolve(text); + }); + }); +} + +class Countdown extends Readable { + private left = 3; + _read(): void { + this.push(this.left > 0 ? `t-${this.left--};` : null); + } +} + +function openText(file: string): NodeJS.ReadableStream { + return fs.createReadStream(file); +} + +function openDecoded(file: string): NodeJS.ReadableStream { + const stream = fs.createReadStream(file); + stream.setEncoding("utf8"); + return stream; +} + +async function main(): Promise { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "scriptc-node-readable-")); + const plain = path.join(dir, "plain.txt"); + const packed = path.join(dir, "packed.gz"); + fs.writeFileSync(plain, "hello from a file\n"); + fs.writeFileSync(packed, zlib.gzipSync(Buffer.from("inflated text\n"))); + + console.log(JSON.stringify(await drain("file", openText(plain)))); + console.log(JSON.stringify(await drain("decoded", openDecoded(plain)))); + console.log(JSON.stringify(await drain("subclass", new Countdown()))); + console.log(JSON.stringify(await drain("from", Readable.from(["a", "b", "c"])))); + const gunzip = fs.createReadStream(packed).pipe(zlib.createGunzip()); + console.log(JSON.stringify(await drain("gunzip", gunzip))); + + const child = spawn("sh", ["-c", "printf 'child line\\n'"], { + stdio: ["ignore", "pipe", "inherit"], + }); + const out = child.stdout; + if (out !== null) console.log(JSON.stringify(await drain("child", out))); + console.log("same stdout", child.stdout === out); + + try { + await drain("missing", openText(path.join(dir, "missing.txt"))); + } catch (err) { + console.log("missing", (err as NodeJS.ErrnoException).code); + } + fs.rmSync(dir, { recursive: true }); +} + +void main(); diff --git a/tests/corpus/6464-node-writable-stream-producers.ts b/tests/corpus/6464-node-writable-stream-producers.ts new file mode 100644 index 000000000..bc9986b9b --- /dev/null +++ b/tests/corpus/6464-node-writable-stream-producers.ts @@ -0,0 +1,68 @@ +// NodeJS.WritableStream is the interface every Node writable implements: +// process.stdout/stderr, fs.WriteStream and the node:stream Writable +// family. Helpers typed with it accept all of them, a copy helper pipes a +// file stream into one, and readable.pipe(process.stdout) leaves the +// process stream open afterwards, as in Node. +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import { Readable, Writable } from "node:stream"; + +function emit(dst: NodeJS.WritableStream, line: string): boolean { + return dst.write(`${line}\n`); +} + +function copy(src: NodeJS.ReadableStream, dst: NodeJS.WritableStream): Promise { + return new Promise((resolve, reject) => { + src.on("error", reject); + dst.on("error", reject); + dst.on("finish", () => resolve()); + src.pipe(dst); + }); +} + +class Collector extends Writable { + readonly parts: string[] = []; + _write(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void): void { + this.parts.push(chunk.toString("utf8")); + callback(); + } +} + +function finished(stream: NodeJS.WritableStream): Promise { + return new Promise((resolve) => { + stream.end(() => resolve()); + }); +} + +async function main(): Promise { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "scriptc-node-writable-")); + const target = path.join(dir, "out.txt"); + const file = fs.createWriteStream(target); + console.log("file write", emit(file, "to a file")); + console.log("stdout write", emit(process.stdout, "to stdout")); + emit(process.stderr, "to stderr"); + const collector = new Collector(); + emit(collector, "to a collector"); + await finished(file); + await finished(collector); + console.log(JSON.stringify(fs.readFileSync(target, "utf8"))); + console.log(JSON.stringify(collector.parts)); + + const source = path.join(dir, "source.txt"); + const copied = path.join(dir, "copied.txt"); + fs.writeFileSync(source, "copied through pipe\n"); + await copy(fs.createReadStream(source), fs.createWriteStream(copied)); + console.log(JSON.stringify(fs.readFileSync(copied, "utf8"))); + + await new Promise((resolve) => { + const piped = Readable.from(["piped ", "to ", "stdout\n"]); + piped.on("end", () => resolve()); + console.log("pipe answers stdout", piped.pipe(process.stdout) === process.stdout); + }); + // The pipe did not end process.stdout. + emit(process.stdout, "still writable"); + fs.rmSync(dir, { recursive: true }); +} + +void main(); diff --git a/tests/corpus/6465-node-stream-js-boundary/consume.js b/tests/corpus/6465-node-stream-js-boundary/consume.js new file mode 100644 index 000000000..ceb8f3abf --- /dev/null +++ b/tests/corpus/6465-node-stream-js-boundary/consume.js @@ -0,0 +1,12 @@ +export function streamToText(stream) { + return new Promise((resolve, reject) => { + const chunks = []; + stream.on("data", (chunk) => chunks.push(Buffer.from(chunk))); + stream.on("error", reject); + stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8"))); + }); +} + +export function describeStream(stream) { + console.log(typeof stream.on, typeof stream.pipe, stream.readable); +} diff --git a/tests/corpus/6465-node-stream-js-boundary/main.ts b/tests/corpus/6465-node-stream-js-boundary/main.ts new file mode 100644 index 000000000..0079c0733 --- /dev/null +++ b/tests/corpus/6465-node-stream-js-boundary/main.ts @@ -0,0 +1,33 @@ +// NodeJS.ReadableStream values crossing into untyped JavaScript and into +// 'unknown': a file stream and a child's stdout share one helper with a +// JavaScript stream consumer, which sees ordinary Node streams. +import { spawn } from "node:child_process"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import { describeStream, streamToText } from "./consume.js"; + +function open(file: string): NodeJS.ReadableStream { + return fs.createReadStream(file); +} + +function textOf(stream: NodeJS.ReadableStream): Promise { + return streamToText(stream); +} + +async function main(): Promise { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "scriptc-node-stream-js-")); + const file = path.join(dir, "input.txt"); + fs.writeFileSync(file, "through javascript\n"); + const held: unknown = open(file); + console.log(typeof held); + describeStream(held); + console.log(JSON.stringify(await textOf(open(file)))); + const child = spawn("sh", ["-c", "printf 'child output\\n'"], { + stdio: ["ignore", "pipe", "inherit"], + }); + if (child.stdout !== null) console.log(JSON.stringify(await textOf(child.stdout))); + fs.rmSync(dir, { recursive: true }); +} + +void main(); diff --git a/tests/fixtures/node-types/node-stream-interfaces.ts b/tests/fixtures/node-types/node-stream-interfaces.ts new file mode 100644 index 000000000..2809dc315 --- /dev/null +++ b/tests/fixtures/node-types/node-stream-interfaces.ts @@ -0,0 +1,61 @@ +// @types/node's stream interfaces fed by every producer: NodeJS.ReadableStream +// and stream.Readable slots take file streams, a gunzip Transform and a +// child's stdout; NodeJS.WritableStream and stream.Writable slots take file +// streams and process.stdout. +import { spawn } from "node:child_process"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import { Readable, Writable } from "node:stream"; +import * as zlib from "node:zlib"; + +function drain(label: string, src: NodeJS.ReadableStream): Promise { + return new Promise((resolve, reject) => { + let text = ""; + src.on("data", (chunk: Buffer | string) => { + text += chunk.toString(); + }); + src.on("error", reject); + src.on("end", () => { + console.log(label, "end"); + resolve(text); + }); + }); +} + +function emit(dst: NodeJS.WritableStream, line: string): void { + dst.write(`${line}\n`); +} + +function finish(dst: Writable): Promise { + return new Promise((resolve) => dst.end(() => resolve())); +} + +async function main(): Promise { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "scriptc-node-types-streams-")); + const plain = path.join(dir, "plain.txt"); + const packed = path.join(dir, "packed.gz"); + fs.writeFileSync(plain, "from a file\n"); + fs.writeFileSync(packed, zlib.gzipSync(Buffer.from("from gunzip\n"))); + const file: Readable = fs.createReadStream(plain); + console.log(JSON.stringify(await drain("file", file))); + console.log(JSON.stringify(await drain("gunzip", fs.createReadStream(packed).pipe(zlib.createGunzip())))); + const child = spawn("sh", ["-c", "printf 'from a child\\n'"], { stdio: ["ignore", "pipe", "inherit"] }); + if (child.stdout) console.log(JSON.stringify(await drain("child", child.stdout))); + + const target = path.join(dir, "out.txt"); + const out: Writable = fs.createWriteStream(target); + emit(out, "to a file"); + emit(process.stdout, "to stdout"); + await finish(out); + console.log(JSON.stringify(fs.readFileSync(target, "utf8"))); + await new Promise((resolve) => { + const piped = fs.createReadStream(plain); + piped.on("end", () => resolve()); + piped.pipe(process.stdout); + }); + emit(process.stdout, "stdout still open"); + fs.rmSync(dir, { recursive: true }); +} + +void main(); diff --git a/tests/harness/project-config.test.ts b/tests/harness/project-config.test.ts index 14e4c27af..34063aa9c 100644 --- a/tests/harness/project-config.test.ts +++ b/tests/harness/project-config.test.ts @@ -461,6 +461,24 @@ test("node-types: stream subclasses extend the @types/node stream classes", asyn expect(comparableStderr(native.stderr)).toBe(node.stderr); }); +test("node-types: NodeJS stream interfaces and stream.Readable/Writable take every stream producer", async () => { + const outDir = outDirFor("node-stream-interfaces"); + const entry = join(nodeTypesDir, "node-stream-interfaces.ts"); + const result = await compile(entry, { + outPath: join(outDir, "node-stream-interfaces"), + outDir, + sanitize, + }); + expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true); + if (!result.ok) return; + const [native, node] = await Promise.all([ + execFileAsync(result.binaryPath), + execFileAsync(process.execPath, ["--disable-warning=MODULE_TYPELESS_PACKAGE_JSON", entry]), + ]); + expect(native.stdout).toBe(node.stdout); + expect(comparableStderr(native.stderr)).toBe(node.stderr); +}); + test("node-types: promisified setTimeout and setImmediate lower as timers/promises", async () => { const outDir = outDirFor("promisify-timers"); const entry = join(nodeTypesDir, "promisify-timers.ts"); From 915c0f63c5e30bbee77662e894ae409348073618 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Tue, 20 Oct 2026 01:40:28 -0700 Subject: [PATCH 21/39] Request the general stream representation where a stdio handle meets the stream surface child.stdout.pipe(), stream events and writes beyond write(string) on a NodeJS stream interface slot, and pipes into a child's stdin now lower the program with the general representation instead of fencing. The fallback ChildStdin is a NodeJS.WritableStream, and the coverage remainder relowers its unreached code the same way. Co-Authored-By: Claude Opus 5.5 --- .../builtin-apis/streams-and-readline.mdx | 2 + .../console-and-process-streams.mdx | 3 +- .../ambient/scriptc-node-fallback.d.ts | 10 ++-- .../builtins/child-process-methods.ts | 7 +++ .../src/frontend/lowering/builtins/process.ts | 3 ++ .../frontend/lowering/builtins/properties.ts | 3 +- .../src/frontend/lowering/general-streams.ts | 30 +++++++++--- .../src/frontend/lowering/lower-stream.ts | 2 + .../compiler/src/frontend/lowering/lowerer.ts | 47 +++++++++++-------- packages/compiler/src/frontend/type-mapper.ts | 40 ++++++++++++++++ .../corpus/6466-node-stdio-stream-surface.ts | 45 ++++++++++++++++++ 11 files changed, 160 insertions(+), 32 deletions(-) create mode 100644 tests/corpus/6466-node-stdio-stream-surface.ts diff --git a/docs/content/limitations/builtin-apis/streams-and-readline.mdx b/docs/content/limitations/builtin-apis/streams-and-readline.mdx index 0ac0ca3a6..860daa5d8 100644 --- a/docs/content/limitations/builtin-apis/streams-and-readline.mdx +++ b/docs/content/limitations/builtin-apis/streams-and-readline.mdx @@ -1,4 +1,6 @@ - **Streams and readline:** Stream chunks are Buffers or strings. + `NodeJS.ReadableStream` and `NodeJS.WritableStream`, and `stream.Readable` and `stream.Writable` under `@types/node`, accept every stream: when a program passes file, zlib, or `node:stream` streams through them, child-process pipes and `process.stdout` and `process.stderr` join those streams as `Readable` and `Writable` instances. + `readable.pipe(process.stdout)` and `readable.pipe(process.stderr)` compile and, as in Node, do not end the process stream. `Readable.from` accepts arrays, Sets, Map and Set iterators, generators, async generators, and class iterables and async iterables whose values are strings or Buffers, and in JavaScript any iterable or async iterable of them; a stream that mixes strings and Buffers is unsupported. In JavaScript, a sync iterator value with a `then` method that is not a promise, and an object whose `[Symbol.asyncIterator]` or `[Symbol.iterator]` method is a generator method, are unsupported. Object-mode streams of other values (including `Readable.from` over a `Map`, whose values are entry arrays) are unsupported. diff --git a/docs/content/limitations/console-and-process-streams.mdx b/docs/content/limitations/console-and-process-streams.mdx index 0d7cd8f30..c62b82f0c 100644 --- a/docs/content/limitations/console-and-process-streams.mdx +++ b/docs/content/limitations/console-and-process-streams.mdx @@ -9,4 +9,5 @@ JavaScript can store `process.stdin`, `stdout`, and `stderr`, replace output `wr Input supports data/end/error listeners, pause/resume, buffered reads, and TTY raw mode. Output writes are synchronous, with successful callbacks on the next-tick queue; queued backpressure is not modeled. Stored streams do not support piping, encoding changes, arbitrary properties, or other events. -TypeScript output parameters support `write(string)`. +A TypeScript `NodeJS.WritableStream` parameter that only receives `process.stdout` or `process.stderr` supports `write(string)`. +When other streams flow into the same parameter, the process streams join them as `Writable` instances with the full writable surface. diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 28e481b9d..0df5aceeb 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -123,9 +123,9 @@ declare namespace NodeJS { encoding: BufferEncoding, callback?: (error?: Error | null) => void, ): boolean; - end(callback?: () => void): this; - end(data: string | Uint8Array, callback?: () => void): this; - end(data: string | Uint8Array, encoding: BufferEncoding, callback?: () => void): this; + end(callback?: () => void): void; + end(data: string | Uint8Array, callback?: () => void): void; + end(data: string | Uint8Array, encoding: BufferEncoding, callback?: () => void): void; on(event: "drain" | "finish" | "close", listener: () => void): void; on(event: "error", listener: (err: Error) => void): void; once(event: "drain" | "finish" | "close", listener: () => void): void; @@ -3092,9 +3092,9 @@ declare module "child_process" { write(chunk: string | Uint8Array): boolean; end(): void; destroy(): void; - on(event: "drain" | "finish", listener: () => void): void; + on(event: "drain" | "finish" | "close", listener: () => void): void; on(event: "error", listener: (err: Error) => void): void; - once(event: "drain" | "finish", listener: () => void): void; + once(event: "drain" | "finish" | "close", listener: () => void): void; once(event: "error", listener: (err: Error) => void): void; } diff --git a/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts b/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts index a435bf740..7f0c2cde0 100644 --- a/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts +++ b/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts @@ -1,5 +1,6 @@ import { boolLit, strLit } from "../../../ir/build.js"; import * as ts from "../../ts7/adapter.js"; +import { requestGeneralStreamSurface } from "../general-streams.js"; import { type Lowerer } from "../lowerer.js"; import { isJsSourceFile, locOf } from "../../program.js"; import { isChildSurfaceMember } from "../surfaces.js"; @@ -335,6 +336,7 @@ export function lowerChildStreamMethodCall( const evT = lowerer.typeOf(call.arguments.nodes[0]!); const event = evT.isStringLiteralType() ? evT.value : null; if (event !== "data" && event !== "end") { + requestGeneralStreamSurface(lowerer, access.expression); lowerer.noLowering( `stream.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, call.arguments.nodes[0]!, @@ -342,6 +344,7 @@ export function lowerChildStreamMethodCall( ); } if (!ts.isExpressionStatement(call.parent)) { + requestGeneralStreamSurface(lowerer, access.expression); lowerer.unsupported( "SC1090", call, @@ -393,6 +396,7 @@ export function lowerChildStreamMethodCall( loc, }; } + requestGeneralStreamSurface(lowerer, access.expression); lowerer.noLowering( `ReadableStream.${name}`, call, @@ -418,6 +422,7 @@ export function lowerChildWriterMethodCall( if (name === "write") { if (call.arguments.nodes.length !== 1 || call.arguments.nodes.some(ts.isSpreadElement)) { + requestGeneralStreamSurface(lowerer, access.expression); lowerer.noLowering( `child stdin write with ${call.arguments.nodes.length} arguments`, call, @@ -461,6 +466,7 @@ export function lowerChildWriterMethodCall( const eventType = lowerer.typeOf(call.arguments.nodes[0]!); const event = eventType.isStringLiteralType() ? eventType.value : null; if (event !== "drain" && event !== "finish" && event !== "error") { + requestGeneralStreamSurface(lowerer, access.expression); lowerer.noLowering( `child stdin ${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, call.arguments.nodes[0]!, @@ -507,6 +513,7 @@ export function lowerChildWriterMethodCall( return { kind: "libCall", fn, args: [receiver, cb, once], type: VOID, loc }; } + requestGeneralStreamSurface(lowerer, access.expression); lowerer.noLowering( `Writable.${name}`, call, diff --git a/packages/compiler/src/frontend/lowering/builtins/process.ts b/packages/compiler/src/frontend/lowering/builtins/process.ts index dc2f5ee89..5dd747065 100644 --- a/packages/compiler/src/frontend/lowering/builtins/process.ts +++ b/packages/compiler/src/frontend/lowering/builtins/process.ts @@ -3,6 +3,7 @@ import { envSnapshotHelper, lowerProcessLoadEnvFile } from "./environment.js"; import { dynUndefinedExpr, boolLit, numLit, strLit, varRef } from "../../../ir/build.js"; import { timerStyleCallback } from "../lower-timers.js"; import * as ts from "../../ts7/adapter.js"; +import { requestGeneralStreamSurface } from "../general-streams.js"; import { type Lowerer, own } from "../lowerer.js"; import { isJsSourceFile, locOf } from "../../program.js"; import { isSafeToDiscard } from "../expressions/evaluation-safety.js"; @@ -224,6 +225,7 @@ export function lowerProcStreamMethodCall( const receiver = lowerer.lowerExpr(access.expression); const data = lowerer.lowerExpr(call.arguments.nodes[0]!); if (data.type.kind !== "string") { + requestGeneralStreamSurface(lowerer, access.expression); lowerer.noLowering( `write of '${lowerer.fmt(data.type)}' data on a stream value`, call.arguments.nodes[0]!, @@ -232,6 +234,7 @@ export function lowerProcStreamMethodCall( } return { kind: "libCall", fn: "procStream.write", args: [receiver, data], type: BOOL, loc }; } + requestGeneralStreamSurface(lowerer, access.expression); lowerer.noLowering( `WritableStream.${name}`, call, diff --git a/packages/compiler/src/frontend/lowering/builtins/properties.ts b/packages/compiler/src/frontend/lowering/builtins/properties.ts index 3c0486f82..e60a14c0c 100644 --- a/packages/compiler/src/frontend/lowering/builtins/properties.ts +++ b/packages/compiler/src/frontend/lowering/builtins/properties.ts @@ -290,7 +290,8 @@ function generalChildStdioType( const className = name === "stdin" ? "%Writable" : "%Readable"; const mapped = lowerer.mapTypeOf(lowerer.typeOf(expr)); if (!mapped) return null; - const arms = mapped.kind === "union" ? (lowerer.unions.get(mapped.unionId)?.arms ?? []) : [mapped]; + const arms = + mapped.kind === "union" ? (lowerer.unions.get(mapped.unionId)?.arms ?? []) : [mapped]; return arms.some((arm) => arm.kind === "object" && arm.className === className) ? { kind: "object", className } : null; diff --git a/packages/compiler/src/frontend/lowering/general-streams.ts b/packages/compiler/src/frontend/lowering/general-streams.ts index 6b51ce545..98993798c 100644 --- a/packages/compiler/src/frontend/lowering/general-streams.ts +++ b/packages/compiler/src/frontend/lowering/general-streams.ts @@ -16,6 +16,8 @@ * never take the second pass, so their IR is unchanged. */ import type { IrExpr, IrType } from "../../ir/ir.js"; import { everyTypeChild } from "../../ir/traverse.js"; +import * as ts from "../ts7/adapter.js"; +import { isGeneralNodeStreamInterface } from "../type-mapper.js"; import type { Lowerer } from "./lowerer.js"; import { streamSidesOf } from "./lower-stream.js"; @@ -59,8 +61,7 @@ function isGeneralStream(lowerer: Lowerer, part: IrType): boolean { /** A mismatched flow (requireExactShape's input) that the general stream * representation resolves: a general stream into a stdio-represented - * slot, a stdio handle into an 'unknown' slot, or an 'unknown' value - * checked into a stdio-represented slot. */ + * slot, or a child pipe handle into an 'unknown' slot. */ export function needsGeneralNodeStreams( lowerer: Lowerer, actual: IrType, @@ -69,9 +70,8 @@ export function needsGeneralNodeStreams( const stdio = (part: IrType): boolean => STDIO_STREAM_KINDS.has(part.kind); const pipeHandle = (part: IrType): boolean => part.kind === "childStream" || part.kind === "childWriter"; - if (containsPart(lowerer, expected, stdio)) { - return actual.kind === "dyn" || containsPart(lowerer, actual, (p) => isGeneralStream(lowerer, p)); - } + if (containsPart(lowerer, expected, stdio)) + return containsPart(lowerer, actual, (p) => isGeneralStream(lowerer, p)); return expected.kind === "dyn" && containsPart(lowerer, actual, pipeHandle); } @@ -90,5 +90,23 @@ export function stdioIntoGeneralStream( (expected.kind === "object" && expected.className === "%Writable") || (expected.kind === "union" && lowerer.armTag(expected.unionId, writable) >= 0); if (!accepts) return null; - return { kind: "libCall", fn: "stream.stdioWritable", args: [expr], type: writable, loc: expr.loc }; + return { + kind: "libCall", + fn: "stream.stdioWritable", + args: [expr], + type: writable, + loc: expr.loc, + }; +} + +/** A stdio-handle receiver whose member has no lowering on the handle + * (`out.on("error", ...)`, `child.stdout.pipe(...)`, `output.end()`): when + * its declared type is one the general representation maps to a runtime + * stream class, the program lowers again with it, where the full stream + * surface applies. The caller still reports its fence for this pass. */ +export function requestGeneralStreamSurface(lowerer: Lowerer, receiver: ts.Expression): void { + if (lowerer.generalNodeStreams) return; + const type = lowerer.checker.getNonNullableType(lowerer.typeOf(receiver)); + if (isGeneralNodeStreamInterface(type, lowerer.typeCtx)) + lowerer.requiresGeneralNodeStreams = true; } diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index 66595c473..c73945d2b 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -49,6 +49,7 @@ import { sideEffectFreeOptionValue } from "./surfaces.js"; import { lowerDynObjectLiteral } from "./expressions/object-literals.js"; import { dynUndefinedExpr, varRef } from "../../ir/build.js"; import { genResultRecord } from "../type-mapper.js"; +import { requestGeneralStreamSurface } from "./general-streams.js"; import { extractIteratorValue, genStep, genValue, stepDrivable } from "./lower-generators.js"; import { BOOL, @@ -3608,6 +3609,7 @@ export function lowerStreamMethodCall( dst.type.kind === "object" ? lowerer.classes.get(dst.type.className) : undefined; const dstSides = streamSidesOf(lowerer, dstInfo); if (dstSides !== "w" && dstSides !== "rw") { + requestGeneralStreamSurface(lowerer, args[0]!); lowerer.noLowering( `pipe into a '${lowerer.fmt(dst.type)}'`, args[0]!, diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 2973498e5..c9a0c6435 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1140,25 +1140,34 @@ export function lowerToIr( }; else if (contracts.count > 0) result = { ...result, contracts }; if (options.coverage !== true) return result; - const remainder = new Lowerer(program, entry, moduleOrder, { - frontendServices: options.frontendServices, - projectCheckJs: options.projectCheckJs ?? false, - ...(generalNodeStreams ? { generalNodeStreams: true } : {}), - reachable, - remainder: true, - alreadyFlushed: resultLowerer.flushedSymbols, - inlineRequireCycleCalls: options.inlineRequireCycleCalls, - targetPlatform, - ffiImports, - libraryCallbacks, - forkTargets, - workerTargets, - ffiBindingSymbols: ffiValidation.symbolsByName, - externalTypes, - externalTypeSpecifiersByFile, - tierMode, - }); - const rem = remainder.run(); + const remainderPass = (general: boolean): Lowerer => + new Lowerer(program, entry, moduleOrder, { + frontendServices: options.frontendServices, + projectCheckJs: options.projectCheckJs ?? false, + ...(general ? { generalNodeStreams: true } : {}), + reachable, + remainder: true, + alreadyFlushed: resultLowerer.flushedSymbols, + inlineRequireCycleCalls: options.inlineRequireCycleCalls, + targetPlatform, + ffiImports, + libraryCallbacks, + forkTargets, + workerTargets, + ffiBindingSymbols: ffiValidation.symbolsByName, + externalTypes, + externalTypeSpecifiersByFile, + tierMode, + }); + let remainder = remainderPass(generalNodeStreams); + let rem = remainder.run(); + // Unreached code reports what it would compile to once reached: a + // stream flow there that needs the general representation lowers the + // remainder again with it, as reachable emit would. + if (!generalNodeStreams && remainder.requiresGeneralNodeStreams) { + remainder = remainderPass(true); + rem = remainder.run(); + } timing("coverage-remainder"); // Tiers (tier-analysis.ts): reached statements in dynamic-tier functions, // and with tierReport the report-only demotion analysis. diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index afa9f4311..08e603211 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -991,6 +991,31 @@ export function isDeclaredInAmbientNamespace(d: ts.Declaration, name: string): b return false; } +/** Whether `type` is one of the stream spellings the general stream + * representation (TypeMapperCtx.generalNodeStreams) maps differently: + * NodeJS.ReadableStream / NodeJS.WritableStream, @types/node's + * stream.Readable / stream.Writable, or the fallback declarations' + * ChildStdin. */ +export function isGeneralNodeStreamInterface( + type: ts.Type, + ctx: Pick, +): boolean { + const psym = type.getSymbol() ?? type.getAliasSymbol(); + if (psym === undefined) return false; + return psym.declarations.some((d) => { + if (!(ts.isInterfaceDeclaration(d) || ts.isClassDeclaration(d))) return false; + if (!ctx.isStdlibFile(d.getSourceFile())) return false; + if (psym.name === "ReadableStream" || psym.name === "WritableStream") + return ts.isInterfaceDeclaration(d) && isDeclaredInAmbientNamespace(d, "NodeJS"); + if (psym.name === "ChildStdin") return isDeclaredInAmbientModule(d, "child_process"); + return ( + (psym.name === "Readable" || psym.name === "Writable") && + isNodeTypesPath(d.getSourceFile().fileName) && + isDeclaredInAmbientModule(d, "stream") + ); + }); +} + /** A type declared in the shipped WebAssembly namespace (scriptc.d.ts): * its modules, instances, memories, tables, globals, error classes and the * Exports/Imports records. */ @@ -3038,6 +3063,7 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { // of the broad @types class fence where they are constructed. if ( (psym?.name === "ChildStdin" && + ctx.generalNodeStreams !== true && psym.declarations.some( (d) => ts.isInterfaceDeclaration(d) && @@ -3056,6 +3082,20 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { ) { return { kind: "childWriter" }; } + // Under the general stream representation the fallback declarations' + // ChildStdin is the runtime Writable too (child.stdioStream bridges it). + if ( + ctx.generalNodeStreams === true && + psym?.name === "ChildStdin" && + psym.declarations.some( + (d) => + ts.isInterfaceDeclaration(d) && + ctx.isStdlibFile(d.getSourceFile()) && + isDeclaredInAmbientModule(d, "child_process"), + ) + ) { + return { kind: "object", className: "%Writable" }; + } // The static node:stream classes (the shipped fallback declarations — // NOT @types/node, whose stream.Readable also types child stdio; under // @types/node the childStream mapping below keeps priority and the diff --git a/tests/corpus/6466-node-stdio-stream-surface.ts b/tests/corpus/6466-node-stdio-stream-surface.ts new file mode 100644 index 000000000..d3726360f --- /dev/null +++ b/tests/corpus/6466-node-stdio-stream-surface.ts @@ -0,0 +1,45 @@ +// The stdio handles reach the full stream surface when a program uses it: +// child.stdout piped to process.stdout, a file stream piped into a +// child's stdin, and an 'error' listener on a NodeJS.WritableStream +// parameter that only receives the process streams. Each of these +// compiles the NodeJS stream interfaces as the node:stream classes. +import { spawn } from "node:child_process"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; + +function report(out: NodeJS.WritableStream, text: string): void { + out.on("error", (err) => console.log("error", err.message)); + out.write(`${text}\n`); +} + +function echo(text: string): Promise { + return new Promise((resolve) => { + const child = spawn("sh", ["-c", `echo ${text}`], { stdio: ["ignore", "pipe", "inherit"] }); + child.stdout?.pipe(process.stdout); + child.on("close", (code) => resolve(code)); + }); +} + +function cat(input: string): Promise { + return new Promise((resolve) => { + const child = spawn("cat", [], { stdio: ["pipe", "pipe", "inherit"] }); + child.stdout?.pipe(process.stdout); + child.on("close", (code) => resolve(code)); + if (child.stdin) fs.createReadStream(input).pipe(child.stdin); + }); +} + +async function main(): Promise { + report(process.stdout, "reported"); + report(process.stderr, "reported to stderr"); + console.log("echo exit", await echo("piped from a child")); + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "scriptc-node-stdio-")); + const input = path.join(dir, "input.txt"); + fs.writeFileSync(input, "file contents through cat\n"); + console.log("cat exit", await cat(input)); + report(process.stdout, "stdout stays open"); + fs.rmSync(dir, { recursive: true }); +} + +void main(); From 7cc8179a22a93218fe42bb21173e9717c8842ff3 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Tue, 20 Oct 2026 02:31:27 -0700 Subject: [PATCH 22/39] Close a bridged child stdin on destroy and keep stream listener typing untyped The fallback NodeJS stream interfaces declare Node's EventEmitter listener signature for events beyond data/end, so checked JavaScript keeps its contextual typing for process stream listeners. The child stdin fence fixture becomes a differential test of the forms that now compile. Co-Authored-By: Claude Opus 5.5 --- .../ambient/scriptc-node-fallback.d.ts | 19 +++++---- ...463-node-readable-stream-producers.ts.json | 6 +++ ...464-node-writable-stream-producers.ts.json | 6 +++ .../6465-node-stream-js-boundary/main.ts.json | 7 ++++ .../6466-node-stdio-stream-surface.ts.json | 6 +++ .../node-types/child-stdin-fences.ts.json | 6 --- .../node-types/child-stdin-streams.ts.json | 6 +++ .../node-types/node-stream-interfaces.ts.json | 6 +++ packages/runtime/src/scr_stream.c | 22 +++++++++- .../fixtures/node-types/child-stdin-fences.ts | 6 --- .../node-types/child-stdin-streams.ts | 40 +++++++++++++++++++ tests/harness/project-config.test.ts | 26 +++++------- 12 files changed, 118 insertions(+), 38 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6463-node-readable-stream-producers.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6464-node-writable-stream-producers.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6465-node-stream-js-boundary/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6466-node-stdio-stream-surface.ts.json delete mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-stdin-fences.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-stdin-streams.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/node-stream-interfaces.ts.json delete mode 100644 tests/fixtures/node-types/child-stdin-fences.ts create mode 100644 tests/fixtures/node-types/child-stdin-streams.ts diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 0df5aceeb..037801338 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -93,13 +93,11 @@ declare namespace NodeJS { on(event: "data", listener: (chunk: Buffer) => void): void; on(event: "data", listener: (chunk: string) => void): void; on(event: "end", listener: () => void): void; - on(event: "close", listener: () => void): void; - on(event: "error", listener: (err: Error) => void): void; + on(event: string, listener: (...args: any[]) => void): void; once(event: "data", listener: (chunk: Buffer) => void): void; once(event: "data", listener: (chunk: string) => void): void; once(event: "end", listener: () => void): void; - once(event: "close", listener: () => void): void; - once(event: "error", listener: (err: Error) => void): void; + once(event: string, listener: (...args: any[]) => void): void; /* setEncoding('utf8') makes subsequent data chunks strings, including * multibyte sequences split across native pipe reads. */ setEncoding(encoding: string): this; @@ -126,10 +124,9 @@ declare namespace NodeJS { end(callback?: () => void): void; end(data: string | Uint8Array, callback?: () => void): void; end(data: string | Uint8Array, encoding: BufferEncoding, callback?: () => void): void; - on(event: "drain" | "finish" | "close", listener: () => void): void; - on(event: "error", listener: (err: Error) => void): void; - once(event: "drain" | "finish" | "close", listener: () => void): void; - once(event: "error", listener: (err: Error) => void): void; + /* Node's EventEmitter signature: listeners take untyped arguments. */ + on(event: string, listener: (...args: any[]) => void): void; + once(event: string, listener: (...args: any[]) => void): void; } } @@ -3092,10 +3089,12 @@ declare module "child_process" { write(chunk: string | Uint8Array): boolean; end(): void; destroy(): void; - on(event: "drain" | "finish" | "close", listener: () => void): void; + on(event: "drain" | "finish", listener: () => void): void; on(event: "error", listener: (err: Error) => void): void; - once(event: "drain" | "finish" | "close", listener: () => void): void; + on(event: string, listener: (...args: any[]) => void): void; + once(event: "drain" | "finish", listener: () => void): void; once(event: "error", listener: (err: Error) => void): void; + once(event: string, listener: (...args: any[]) => void): void; } export interface ChildProcess extends Disposable { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6463-node-readable-stream-producers.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6463-node-readable-stream-producers.ts.json new file mode 100644 index 000000000..e413951ae --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6463-node-readable-stream-producers.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6463-node-readable-stream-producers.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6464-node-writable-stream-producers.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6464-node-writable-stream-producers.ts.json new file mode 100644 index 000000000..fd805a2af --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6464-node-writable-stream-producers.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6464-node-writable-stream-producers.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6465-node-stream-js-boundary/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6465-node-stream-js-boundary/main.ts.json new file mode 100644 index 000000000..95278eab8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6465-node-stream-js-boundary/main.ts.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/6465-node-stream-js-boundary/consume.js", + "/tests/corpus/6465-node-stream-js-boundary/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6466-node-stdio-stream-surface.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6466-node-stdio-stream-surface.ts.json new file mode 100644 index 000000000..8ebcddd22 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6466-node-stdio-stream-surface.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6466-node-stdio-stream-surface.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-stdin-fences.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-stdin-fences.ts.json deleted file mode 100644 index cfa602a2e..000000000 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-stdin-fences.ts.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "order": [ - "/tests/fixtures/node-types/child-stdin-fences.ts" - ], - "diags": [] -} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-stdin-streams.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-stdin-streams.ts.json new file mode 100644 index 000000000..2bb443d2a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/child-stdin-streams.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/child-stdin-streams.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/node-stream-interfaces.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/node-stream-interfaces.ts.json new file mode 100644 index 000000000..cfb5c1a10 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/node-stream-interfaces.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/node-stream-interfaces.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index b7d99984a..3b2f7c8f6 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -6627,10 +6627,20 @@ ScrStream *scr_crypto_hash_stream_piped(ScrCryptoHash *hash) { * and reference only global symbols and no new constant data, so programs * that never convert link the same bytes as before. */ +/* destroy() on a bridged child stdin closes the pipe, as Node's does. */ +static void scr_stream_child_stdin_destroy(ScrClosure *cb, ScrStream *s, ScrError *err) { + ScrChildWriter *writer = scr_box_get_ref(cb->caps[0]); + scr_child_writer_destroy(writer); + scr_child_writer_release(writer); + scr_stream_destroy_done(s, err ? scr_error_retain(err) : NULL); +} + /* A child stdio read (the child.stdioStream libCall): the bridged stream * the checked-dynamic ChildProcess view answers for the same key ("stdin", * "stdout" or "stderr", passed by the compiled program), so both views - * share one stream per slot. +1, or NULL for an unpiped slot or a throw. */ + * share one stream per slot. The stdin stream (the only five-byte key) + * gains the destroy hook that closes the pipe. +1, or NULL for an unpiped + * slot or a throw. */ ScrStream *scr_stream_child_stdio(void *child, const char *key, size_t key_len) { ScrDyn *handle = scr_dyn_new_handle(child, SCR_DYNH_CHILD); ScrDyn *box = scr_dyn_handle_ops_of(handle)->get(child, key, key_len); @@ -6638,6 +6648,16 @@ ScrStream *scr_stream_child_stdio(void *child, const char *key, size_t key_len) if (box == NULL) return NULL; ScrStream *stream = box->kind == SCR_DYN_TYPED_REF ? scr_dyn_typed_ref_unbox(box) : NULL; scr_dyn_release(box); + if (stream != NULL && key_len == 5 && stream->st->destroy_cb == NULL) { + ScrChildWriter *writer = scr_child_stdin(child); + if (writer != NULL) { + ScrClosure *destroy = scr_closure_new((void *)scr_stream_child_stdin_destroy, 1); + destroy->caps[0] = scr_box_new_obj(scr_child_writer_retain_v, scr_child_writer_release_v, NULL); + scr_box_set_ref(destroy->caps[0], writer); + stream->st->destroy_cb = destroy; + stream->st->destroy_inv = scr_stream_child_stdin_destroy; + } + } return stream; } diff --git a/tests/fixtures/node-types/child-stdin-fences.ts b/tests/fixtures/node-types/child-stdin-fences.ts deleted file mode 100644 index 0859d8513..000000000 --- a/tests/fixtures/node-types/child-stdin-fences.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { spawn } from "node:child_process"; - -const child = spawn("node", []); -child.stdin.write("x", "utf8"); -child.stdin.end("x"); -child.stdin.destroy(new Error("stop")); diff --git a/tests/fixtures/node-types/child-stdin-streams.ts b/tests/fixtures/node-types/child-stdin-streams.ts new file mode 100644 index 000000000..c433d7bfb --- /dev/null +++ b/tests/fixtures/node-types/child-stdin-streams.ts @@ -0,0 +1,40 @@ +// child.stdin forms beyond write(string): a write with an encoding, end +// with a final chunk, and destroy with an error observed by an 'error' +// listener. They compile through the general stream representation, where +// child.stdin is the child's bridged Writable. +import { spawn } from "node:child_process"; + +function feed(): Promise { + return new Promise((resolve) => { + const child = spawn("cat", [], { stdio: ["pipe", "pipe", "inherit"] }); + let out = ""; + child.stdout.on("data", (chunk: Buffer) => { + out += chunk.toString(); + }); + child.on("close", (code) => { + console.log("fed", JSON.stringify(out), code); + resolve(); + }); + child.stdin.write("first ", "utf8"); + child.stdin.end("second\n"); + }); +} + +function abort(): Promise { + return new Promise((resolve) => { + const child = spawn("cat", [], { stdio: ["pipe", "ignore", "inherit"] }); + child.stdin.on("error", (err) => console.log("stdin error", err.message)); + child.on("close", (code) => { + console.log("aborted", code); + resolve(); + }); + child.stdin.destroy(new Error("stop")); + }); +} + +async function main(): Promise { + await feed(); + await abort(); +} + +void main(); diff --git a/tests/harness/project-config.test.ts b/tests/harness/project-config.test.ts index 34063aa9c..3635c88ed 100644 --- a/tests/harness/project-config.test.ts +++ b/tests/harness/project-config.test.ts @@ -551,26 +551,22 @@ test("node-types: promisified dns lookups settle with the lookup objects", async expect(comparableStderr(native.stderr)).toBe(node.stderr); }); -test("node-types: unsupported child stdin forms remain named fences", async () => { - const dir = outDirFor("node-child-stdin-fences"); - const entry = join(nodeTypesDir, "child-stdin-fences.ts"); +test("node-types: child stdin forms beyond write(string) compile through the general stream representation", async () => { + const dir = outDirFor("node-child-stdin-streams"); + const entry = join(nodeTypesDir, "child-stdin-streams.ts"); const result = await compile(entry, { - outPath: join(dir, "child-stdin-fences"), + outPath: join(dir, "child-stdin-streams"), outDir: dir, sanitize, }); - expect(result.ok).toBe(false); - if (result.ok) return; - expect(result.diagnostics.map((diagnostic) => diagnostic.code)).toEqual([ - "SC2020", - "SC2020", - "SC2020", - ]); - expect(result.diagnostics.map((diagnostic) => diagnostic.message)).toEqual([ - expect.stringContaining("child stdin write with 2 arguments"), - expect.stringContaining("Writable.end"), - expect.stringContaining("Writable.destroy"), + expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true); + if (!result.ok) return; + const [native, node] = await Promise.all([ + execFileAsync(result.binaryPath), + execFileAsync(process.execPath, ["--disable-warning=MODULE_TYPELESS_PACKAGE_JSON", entry]), ]); + expect(native.stdout).toBe(node.stdout); + expect(comparableStderr(native.stderr)).toBe(node.stderr); }); test("node-types: callback exec uses the typed ExecException overloads", async () => { From 1e96179f3a4e6b81d881688bc4250168fffd662c Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Tue, 20 Oct 2026 03:13:15 -0700 Subject: [PATCH 23/39] Carry untyped streams, casts, for await and pipeline stages into the general stream representation An 'unknown' value flowing or cast into a NodeJS.ReadableStream slot and 'for await' over one now select the general representation, where the checked cast to Readable applies. pipeline() stages that arrive untyped unwrap boxed native streams at run time. @types/node's zlib interface declarations map to the runtime Transform. Co-Authored-By: Claude Opus 5.5 --- .../ambient/scriptc-node-fallback.d.ts | 1 + .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../lowering/expressions/narrowing.ts | 4 ++ .../src/frontend/lowering/general-streams.ts | 4 +- .../src/frontend/lowering/lower-stmts.ts | 3 ++ .../src/frontend/lowering/lower-stream.ts | 18 +++++++ packages/compiler/src/frontend/type-mapper.ts | 3 +- packages/compiler/src/ir/builtin-effects.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 8 +++ packages/compiler/src/ir/runtime-features.ts | 1 + packages/runtime/src/scr_stream.c | 17 +++++++ packages/runtime/src/scr_stream.h | 3 ++ .../6467-node-stream-untyped-sources/main.ts | 51 +++++++++++++++++++ .../sources.js | 20 ++++++++ 14 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 tests/corpus/6467-node-stream-untyped-sources/main.ts create mode 100644 tests/corpus/6467-node-stream-untyped-sources/sources.js diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 037801338..3885e0fef 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -107,6 +107,7 @@ declare namespace NodeJS { isPaused(): boolean; pipe(destination: T, options?: { end?: boolean }): T; unpipe(destination?: WritableStream): this; + [Symbol.asyncIterator](): AsyncIterableIterator; } /* The writable-stream interface every Node stream implements: * process.stdout/process.stderr, fs.WriteStream and the node:stream diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 61d31435c..4602a2bdd 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -727,6 +727,7 @@ export const LIB_FN_SYMS: Record = { "child.ref": "scr_child_ref", "procStream.write": "scr_proc_stream_write", "stream.stdioWritable": "scr_stream_stdio_writable", + "stream.unboxDyn": "scr_stream_unbox_dyn", "process.kill": "scr_process_kill_named", "process.killNum": "scr_process_kill", // fs.promises (scr_bytes_io.c / scr_lib.c): the promise forms settle diff --git a/packages/compiler/src/frontend/lowering/expressions/narrowing.ts b/packages/compiler/src/frontend/lowering/expressions/narrowing.ts index b54da8180..6b75755b1 100644 --- a/packages/compiler/src/frontend/lowering/expressions/narrowing.ts +++ b/packages/compiler/src/frontend/lowering/expressions/narrowing.ts @@ -26,6 +26,7 @@ import { jsBindingHasOpenWrites } from "../lower-stmts.js"; import { narrowClassUnion, narrowStoredClassValue, structuralNarrowing } from "../class-unions.js"; import { checkedClassAssertion, checkedClassUnionAssertion } from "../class-assertions.js"; import { isOptionalProcessStreamProperty } from "../builtins/process.js"; +import { requestGeneralStreamSurface } from "../general-streams.js"; import { literalValues } from "../../literal-values.js"; import { literalUnionArm } from "../../union-discriminants.js"; import { checkedArmExtraction } from "../coercions/unions.js"; @@ -1450,6 +1451,9 @@ export function lowerAsExpression( if (DYN_HANDLE_KINDS.has(target.kind)) { return { kind: "dynCheck", value: inner, type: target, loc: locOf(expr) }; } + // `value as NodeJS.ReadableStream`: the general stream classes take + // the checked cast (general-streams.ts). + requestGeneralStreamSurface(lowerer, expr); lowerer.unsupported( "SC1090", expr, diff --git a/packages/compiler/src/frontend/lowering/general-streams.ts b/packages/compiler/src/frontend/lowering/general-streams.ts index 98993798c..0113a9958 100644 --- a/packages/compiler/src/frontend/lowering/general-streams.ts +++ b/packages/compiler/src/frontend/lowering/general-streams.ts @@ -61,7 +61,8 @@ function isGeneralStream(lowerer: Lowerer, part: IrType): boolean { /** A mismatched flow (requireExactShape's input) that the general stream * representation resolves: a general stream into a stdio-represented - * slot, or a child pipe handle into an 'unknown' slot. */ + * slot, a child pipe handle into an 'unknown' slot, or an 'unknown' value + * into a child-pipe slot (the general classes take a checked cast). */ export function needsGeneralNodeStreams( lowerer: Lowerer, actual: IrType, @@ -70,6 +71,7 @@ export function needsGeneralNodeStreams( const stdio = (part: IrType): boolean => STDIO_STREAM_KINDS.has(part.kind); const pipeHandle = (part: IrType): boolean => part.kind === "childStream" || part.kind === "childWriter"; + if (actual.kind === "dyn") return containsPart(lowerer, expected, pipeHandle); if (containsPart(lowerer, expected, stdio)) return containsPart(lowerer, actual, (p) => isGeneralStream(lowerer, p)); return expected.kind === "dyn" && containsPart(lowerer, actual, pipeHandle); diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 064cd7a7b..afc329f40 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -1,4 +1,5 @@ import { hostsAll } from "./expressions/hosted-narrowing.js"; +import { requestGeneralStreamSurface } from "./general-streams.js"; import { matchAllRowsReadByElements, storedMatchAllRowsReadByElements, @@ -8916,6 +8917,8 @@ export function lowerForOf(lowerer: Lowerer, stmt: ts.ForOfStatement): IrStmt { } const builtin = lowerForAwaitBuiltin(lowerer, stmt); if (builtin) return builtin; + // A NodeJS.ReadableStream iterates as the general Readable. + requestGeneralStreamSurface(lowerer, stmt.expression); lowerer.unsupported( "SC1070", stmt, diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index c73945d2b..400fd79ac 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -2045,6 +2045,24 @@ function lowerStreamArg( const v = isHashValueType(lowered.type) ? hashStreamOf(lowered, what === "pipeline" || what === "compose") : lowered; + // A checked-dynamic pipeline stage (an untyped source or destination): + // a boxed native stream unwraps at run time; other values (iterables, + // functions) throw the not-supported Error there. + if (v.type.kind === "dyn" && what === "pipeline") { + return { + kind: "libCall", + fn: "stream.unboxDyn", + args: [ + v, + strLit( + "pipeline stages other than native streams (iterables, generators, plain functions, and { readable, writable } pairs) are not supported yet", + locOf(node), + ), + ], + type: { kind: "object", className: "%Duplex" }, + loc: locOf(node), + }; + } const info = v.type.kind === "object" ? lowerer.classes.get(v.type.className) : undefined; if (!streamSidesOf(lowerer, info)) { // A provably-non-stream value in a JS source (the invalid-input diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 08e603211..7acb539d1 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -3129,7 +3129,8 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { ZLIB_STREAM_MODES.has(psym.name) && psym.declarations.some( (d) => - ts.isClassDeclaration(d) && + (ts.isClassDeclaration(d) || + (ts.isInterfaceDeclaration(d) && isNodeTypesPath(d.getSourceFile().fileName))) && ctx.isStdlibFile(d.getSourceFile()) && isDeclaredInAmbientModule(d, "zlib"), ) diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 2973a9aa2..1c390bbe4 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -76,6 +76,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "process.stderrWriteBytes", "procStream.write", "child.stdioStream", + "stream.unboxDyn", "weakMap.new", "weakSet.new", "dyn.fromEntries", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 2e4faedb4..597076cb1 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -2563,6 +2563,14 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ /** process.stdout/stderr flowing into a runtime Writable slot under the * general stream representation: an fd-backed Writable (+1) whose * writes take process.stdout.write's synchronous path. */ + /** A pipeline() stage that is a checked-dynamic value: a boxed native + * stream unwraps by identity (+1); anything else throws the given + * not-supported message. Typed as a Duplex so every stage position + * accepts it; the runtime pipeline checks the stream's real sides. */ + "stream.unboxDyn": { + argTypes: [DYN, STRING], + result: { kind: "object", className: "%Duplex" }, + }, "stream.stdioWritable": { argTypes: [PROCSTREAM_T], result: { kind: "object", className: "%Writable" }, diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 572a93273..99ba76f79 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -164,6 +164,7 @@ const STREAM_LIB_FNS: ReadonlySet = new Set([ "stream.errored", "stream.prop", "stream.stdioWritable", + "stream.unboxDyn", "stream.workerStdio", ]); diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index 3b2f7c8f6..1c5e339a0 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -6678,3 +6678,20 @@ ScrStream *scr_stream_stdio_writable(double fd) { return scr_stream_new_writable(-1, true, true, write, scr_stream_stdio_write, NULL, NULL, NULL, NULL); } + +/* A pipeline() stage that arrives as a checked-dynamic value (the + * stream.unboxDyn libCall): a boxed native stream unwraps by identity + * (+1); any other value throws the compiled program's not-supported + * message (Node also takes iterables and functions there). */ +ScrStream *scr_stream_unbox_dyn(const ScrDyn *value, const ScrStr *message) { + if (value->kind == SCR_DYN_TYPED_REF && value->v.typed_ref.type_key_len > 7 && + !memcmp(value->v.typed_ref.type_key, "object:", 7)) { + ScrStream *stream = scr_dyn_typed_ref_unbox(value); + const ScrVt *vt = stream->vt; + if ((vt->pre >= scr_readable_vt.pre && vt->pre <= scr_readable_vt.post) || + (vt->pre >= scr_writable_vt.pre && vt->pre <= scr_writable_vt.post)) return stream; + value->v.typed_ref.release(stream); + } + scr_throw_error_msg_code(SCR_ERR_ERROR, message->data, message->len, "SC2020"); + return NULL; +} diff --git a/packages/runtime/src/scr_stream.h b/packages/runtime/src/scr_stream.h index f6c3c24e5..63ed0c28a 100644 --- a/packages/runtime/src/scr_stream.h +++ b/packages/runtime/src/scr_stream.h @@ -130,6 +130,9 @@ ScrStream *scr_stream_new_writable_dyn(struct ScrDyn *opts); * Writable (fd 1 or 2). */ ScrStream *scr_stream_child_stdio(void *child, const char *key, size_t key_len); ScrStream *scr_stream_stdio_writable(double fd); +/* A boxed native stream out of a checked-dynamic pipeline stage (+1), or + * NULL with `message` thrown as the not-supported Error. */ +ScrStream *scr_stream_unbox_dyn(const struct ScrDyn *value, const ScrStr *message); ScrStream *scr_stream_new_duplex_dyn(struct ScrDyn *opts); ScrStream *scr_stream_new_transform_dyn(struct ScrDyn *opts); ScrStream *scr_stream_new_passthrough_dyn(struct ScrDyn *opts); diff --git a/tests/corpus/6467-node-stream-untyped-sources/main.ts b/tests/corpus/6467-node-stream-untyped-sources/main.ts new file mode 100644 index 000000000..bab7e8cc7 --- /dev/null +++ b/tests/corpus/6467-node-stream-untyped-sources/main.ts @@ -0,0 +1,51 @@ +// Streams that arrive untyped meet NodeJS stream interface slots: an +// untyped JavaScript function's stream returned as NodeJS.ReadableStream, +// a checked cast from 'unknown', pipeline() over untyped source and +// destination stages, and 'for await' over a NodeJS.ReadableStream +// parameter fed by a file stream and a child's stdout. +import { spawn } from "node:child_process"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import { pipeline } from "node:stream/promises"; +import * as zlib from "node:zlib"; +import { collector, joined, openUntyped } from "./sources.js"; + +function open(file: string): NodeJS.ReadableStream { + return openUntyped(file); +} + +function held(file: string): unknown { + return fs.createReadStream(file); +} + +async function collect(label: string, src: NodeJS.ReadableStream): Promise { + let text = ""; + for await (const chunk of src) text += chunk.toString(); + console.log(label, JSON.stringify(text)); +} + +async function main(): Promise { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "scriptc-node-stream-untyped-")); + const plain = path.join(dir, "plain.txt"); + const packed = path.join(dir, "packed.gz"); + fs.writeFileSync(plain, "plain text\n"); + fs.writeFileSync(packed, zlib.gzipSync(Buffer.from("packed text\n"))); + + await collect("returned", open(plain)); + await collect("cast", held(plain) as NodeJS.ReadableStream); + const child = spawn("sh", ["-c", "printf 'child text\\n'"], { stdio: ["ignore", "pipe", "inherit"] }); + if (child.stdout) await collect("child", child.stdout); + + const sink = collector(); + await pipeline(openUntyped(packed), zlib.createGunzip(), sink); + console.log("pipeline", JSON.stringify(joined())); + try { + await pipeline(openUntyped(path.join(dir, "missing.gz")), zlib.createGunzip(), collector()); + } catch (err) { + console.log("pipeline error", (err as NodeJS.ErrnoException).code); + } + fs.rmSync(dir, { recursive: true }); +} + +void main(); diff --git a/tests/corpus/6467-node-stream-untyped-sources/sources.js b/tests/corpus/6467-node-stream-untyped-sources/sources.js new file mode 100644 index 000000000..ce4b5dcb7 --- /dev/null +++ b/tests/corpus/6467-node-stream-untyped-sources/sources.js @@ -0,0 +1,20 @@ +import * as fs from "node:fs"; +import { PassThrough } from "node:stream"; + +const parts = []; + +/** @returns {any} */ +export function openUntyped(file) { + return fs.createReadStream(file); +} + +/** @returns {any} */ +export function collector() { + const sink = new PassThrough(); + sink.on("data", (chunk) => parts.push(chunk.toString("utf8"))); + return sink; +} + +export function joined() { + return parts.splice(0).join(""); +} From 95b2f81716dc644ec5a58309cf6d08ff71c81ca9 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Tue, 20 Oct 2026 03:24:08 -0700 Subject: [PATCH 24/39] Pipe into untyped destinations by unwrapping boxed native streams Co-Authored-By: Claude Opus 5.5 --- .../builtin-apis/streams-and-readline.mdx | 1 + .../src/frontend/lowering/lower-stream.ts | 53 +++++++++++++++++++ .../6467-node-stream-untyped-sources/main.ts | 11 +++- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/docs/content/limitations/builtin-apis/streams-and-readline.mdx b/docs/content/limitations/builtin-apis/streams-and-readline.mdx index 860daa5d8..042fd1e50 100644 --- a/docs/content/limitations/builtin-apis/streams-and-readline.mdx +++ b/docs/content/limitations/builtin-apis/streams-and-readline.mdx @@ -1,6 +1,7 @@ - **Streams and readline:** Stream chunks are Buffers or strings. `NodeJS.ReadableStream` and `NodeJS.WritableStream`, and `stream.Readable` and `stream.Writable` under `@types/node`, accept every stream: when a program passes file, zlib, or `node:stream` streams through them, child-process pipes and `process.stdout` and `process.stderr` join those streams as `Readable` and `Writable` instances. `readable.pipe(process.stdout)` and `readable.pipe(process.stderr)` compile and, as in Node, do not end the process stream. + A `pipeline` stage that arrives as an untyped value must be a native stream at run time; other values throw a not-supported error. `Readable.from` accepts arrays, Sets, Map and Set iterators, generators, async generators, and class iterables and async iterables whose values are strings or Buffers, and in JavaScript any iterable or async iterable of them; a stream that mixes strings and Buffers is unsupported. In JavaScript, a sync iterator value with a `then` method that is not a promise, and an object whose `[Symbol.asyncIterator]` or `[Symbol.iterator]` method is a generator method, are unsupported. Object-mode streams of other values (including `Readable.from` over a `Map`, whose values are entry arrays) are unsupported. diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index 400fd79ac..51c86fe39 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -3371,6 +3371,58 @@ function pipeIntoStdio( }; } +/** `readable.pipe(untyped)`: a checked-dynamic destination unwraps a boxed + * native stream at run time (stream.unboxDyn; other values throw the + * not-supported Error), and pipe() answers the destination value itself. */ +function pipeIntoDyn( + lowerer: Lowerer, + call: ts.CallExpression, + access: ts.PropertyAccessExpression, + target: IrExpr, +): IrExpr { + const loc = locOf(call); + const receiverValue = lowerer.lowerExpr(access.expression); + const source = lowerer.declareHiddenLocal("%pipeSource", receiverValue.type); + const destination = lowerer.declareHiddenLocal("%pipeDestination", target.type); + const stmts: IrStmt[] = [ + { kind: "varDecl", localId: source.id, init: receiverValue, loc }, + { kind: "varDecl", localId: destination.id, init: target, loc }, + ]; + const end = pipeEndOption(lowerer, call.arguments.nodes[1], loc); + const duplex: IrType = { kind: "object", className: "%Duplex" }; + stmts.push({ + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "readable.pipe", + args: [ + { kind: "varRef", localId: source.id, type: receiverValue.type, loc }, + { + kind: "libCall", + fn: "stream.unboxDyn", + args: [ + { kind: "varRef", localId: destination.id, type: target.type, loc }, + strLit("pipe destinations other than native streams are not supported yet", loc), + ], + type: duplex, + loc, + }, + end, + ], + type: duplex, + loc, + }, + loc, + }); + return { + kind: "seqExpr", + stmts, + result: { kind: "varRef", localId: destination.id, type: target.type, loc }, + type: target.type, + loc, + }; +} + export function lowerStreamMethodCall( lowerer: Lowerer, call: ts.CallExpression, @@ -3622,6 +3674,7 @@ export function lowerStreamMethodCall( } const target = lowerer.lowerExpr(args[0]!); if (target.type.kind === "procStream") return pipeIntoStdio(lowerer, call, access, target); + if (target.type.kind === "dyn") return pipeIntoDyn(lowerer, call, access, target); const dst = target; const dstInfo = dst.type.kind === "object" ? lowerer.classes.get(dst.type.className) : undefined; diff --git a/tests/corpus/6467-node-stream-untyped-sources/main.ts b/tests/corpus/6467-node-stream-untyped-sources/main.ts index bab7e8cc7..5cb3a628d 100644 --- a/tests/corpus/6467-node-stream-untyped-sources/main.ts +++ b/tests/corpus/6467-node-stream-untyped-sources/main.ts @@ -1,7 +1,7 @@ // Streams that arrive untyped meet NodeJS stream interface slots: an // untyped JavaScript function's stream returned as NodeJS.ReadableStream, -// a checked cast from 'unknown', pipeline() over untyped source and -// destination stages, and 'for await' over a NodeJS.ReadableStream +// a checked cast from 'unknown', pipe() and pipeline() into untyped +// destinations, and 'for await' over a NodeJS.ReadableStream // parameter fed by a file stream and a child's stdout. import { spawn } from "node:child_process"; import * as fs from "node:fs"; @@ -37,6 +37,13 @@ async function main(): Promise { const child = spawn("sh", ["-c", "printf 'child text\\n'"], { stdio: ["ignore", "pipe", "inherit"] }); if (child.stdout) await collect("child", child.stdout); + await new Promise((resolve) => { + const piped = fs.createReadStream(plain); + piped.on("end", () => resolve()); + piped.pipe(collector()); + }); + console.log("pipe", JSON.stringify(joined())); + const sink = collector(); await pipeline(openUntyped(packed), zlib.createGunzip(), sink); console.log("pipeline", JSON.stringify(joined())); From ac6b5ebe9715ff0f86a0da59ca8a1c71928f8fc0 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Tue, 20 Oct 2026 03:08:21 -0700 Subject: [PATCH 25/39] Throw a record extended by Object.assign as a checked-dynamic copy `throw Object.assign(failure, { bail: true })`, where the record's type lacks the source's member, used to fall to the Object.assign fence: a fixed record cannot grow a field. As the operand of a throw, the call now copies the target into a checked-dynamic object and adds the source's members. The copy is unobservable, because control leaves with the throw and nothing on that path reads the target again. Paths that already lowered run first, so no compiled program changes. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/lower-calls.ts | 31 +++++++++++++++++++ tests/corpus/6404-error-in-and-assign.ts | 25 +++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 6862d2d52..c51b75b03 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -7601,6 +7601,37 @@ function lowerObjectStaticCall( } } } + // `throw Object.assign(record, { extra })`: an error-shaped record given + // a member its type lacks, thrown at once. A fixed record cannot grow + // the member, so the throw carries a checked-dynamic copy of the target + // with the source's members added. The copy is unobservable: control + // leaves with the throw, so nothing on that path reads the target again. + { + let parent: ts.Node | undefined = call.parent; + while (parent && ts.isParenthesizedExpression(parent)) parent = parent.parent; + const argNodes = call.arguments.nodes; + if ( + parent && + ts.isThrowStatement(parent) && + argNodes.length === 2 && + !argNodes.some((a) => ts.isSpreadElement(a)) + ) { + const tProbe = tryLowerExpression(lowerer, argNodes[0]!); + const sProbe = tryLowerExpression(lowerer, argNodes[1]!); + if ( + tProbe?.type.kind === "record" && + lowerer.dynConvertible(tProbe.type) && + sProbe && + (sProbe.type.kind === "dyn" || lowerer.dynConvertible(sProbe.type)) + ) { + const loc = locOf(call); + const target = lowerer.coerceToExpected(lowerer.lowerExpr(argNodes[0]!), DYN); + const source = lowerer.coerceToExpected(lowerer.lowerExpr(argNodes[1]!), DYN); + if (target.type.kind === "dyn" && source.type.kind === "dyn") + return { kind: "libCall", fn: "dyn.assign", args: [target, source], type: DYN, loc }; + } + } + } // `Object.assign(target, ...sources)` over a CHECKED-DYNAMIC target // — the n-ary/spread form (`Object.assign({}, ...plugins.map(p => // p.options), coreOptions)`, support.js's option-table merge). The diff --git a/tests/corpus/6404-error-in-and-assign.ts b/tests/corpus/6404-error-in-and-assign.ts index fc6f470e6..a9bb6d086 100644 --- a/tests/corpus/6404-error-in-and-assign.ts +++ b/tests/corpus/6404-error-in-and-assign.ts @@ -117,3 +117,28 @@ function failure(message: string, bail: boolean): BuildFailure { } for (const f of [failure("stop", true), failure("go", false)]) console.log(f.message, f.bail, f.code); + +// A record given a member its type lacks and thrown at once. +interface FailureRecord { + from: string; + isGraceful: boolean; + errorValue: unknown; +} +function classifyFailure(err: unknown, from: string): FailureRecord { + return { from, isGraceful: from === "user", errorValue: err }; +} +function handleFailure(err: unknown, from: string): string { + const failure = classifyFailure(err, from); + if (failure.from === "build") { + throw Object.assign(failure, { bail: true }); + } + return `${failure.from} ${failure.isGraceful}`; +} +for (const from of ["build", "user"]) { + try { + console.log("handled", handleFailure(new Error("x"), from)); + } catch (e) { + const thrownRecord = e as { from: string; bail?: boolean; isGraceful: boolean }; + console.log("thrown", thrownRecord.from, thrownRecord.bail, thrownRecord.isGraceful); + } +} From 1f58ff62568fd3cb1656dd0db1524ba5660d7467 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Tue, 20 Oct 2026 03:41:24 -0700 Subject: [PATCH 26/39] Record the order-parity baseline for the untyped stream corpus program Co-Authored-By: Claude Opus 5.5 --- .../corpus/6467-node-stream-untyped-sources/main.ts.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6467-node-stream-untyped-sources/main.ts.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6467-node-stream-untyped-sources/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6467-node-stream-untyped-sources/main.ts.json new file mode 100644 index 000000000..dc843c047 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6467-node-stream-untyped-sources/main.ts.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/6467-node-stream-untyped-sources/sources.js", + "/tests/corpus/6467-node-stream-untyped-sources/main.ts" + ], + "diags": [] +} From 447e9bf000a87d14757d9b9def438eb2afe8bdf5 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Tue, 20 Oct 2026 04:14:52 -0700 Subject: [PATCH 27/39] Compile Transform option callbacks and loosely typed child-process listeners @types/node types the transform/flush completion callback's data as any and a child stream 'data' chunk as any, and ChildProcess accepts (code: number, signal: string) exit and close listeners through its catch-all overload. None of these compiled: the any-typed completion callback crashed the LLVM emitter, and the child listeners were refused. The completion callback's data parameter is typed Buffer | string | undefined while the option callback lowers. Child stream 'data' listeners with an unknown or any chunk box it as a checked-dynamic value, taking strings when a setEncoding statement on the same stream precedes the listener and Buffers when the function never calls setEncoding on it; other placements are refused. Exit and close listener parameters declared number or string bind as checked-dynamic values, so the body sees the null Node passes. Co-Authored-By: Claude Opus 5.5 --- .../builtin-apis/streams-and-readline.mdx | 1 + .../limitations/child-process-workers.mdx | 4 + packages/compiler/src/backend/llvm/emitter.ts | 5 + .../src/backend/llvm/expr-callbacks.ts | 25 +++ .../compiler/src/backend/llvm/lib-stream.ts | 11 +- .../builtins/child-process-methods.ts | 156 +++++++++++++++++- .../src/frontend/lowering/lower-stream.ts | 64 +++++-- .../compiler/src/frontend/lowering/lowerer.ts | 4 +- .../compiler/src/ir/builtin-signatures.ts | 2 +- ...stream-transform-any-data-callback.ts.json | 6 + .../6471-stream-data-buffer-or-string.ts.json | 6 + .../6472-child-data-unknown-chunk.ts.json | 6 + .../node-types/stream-construction.ts.json | 6 + ...6470-stream-transform-any-data-callback.ts | 60 +++++++ .../6471-stream-data-buffer-or-string.ts | 44 +++++ tests/corpus/6472-child-data-unknown-chunk.ts | 65 ++++++++ tests/diagnostics/child-process.ts | 5 + .../node-types/stream-construction.ts | 100 +++++++++++ .../__snapshots__/child-process.ts.txt | 9 +- tests/harness/project-config.test.ts | 18 ++ 20 files changed, 568 insertions(+), 29 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6470-stream-transform-any-data-callback.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6471-stream-data-buffer-or-string.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6472-child-data-unknown-chunk.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/stream-construction.ts.json create mode 100644 tests/corpus/6470-stream-transform-any-data-callback.ts create mode 100644 tests/corpus/6471-stream-data-buffer-or-string.ts create mode 100644 tests/corpus/6472-child-data-unknown-chunk.ts create mode 100644 tests/fixtures/node-types/stream-construction.ts diff --git a/docs/content/limitations/builtin-apis/streams-and-readline.mdx b/docs/content/limitations/builtin-apis/streams-and-readline.mdx index 042fd1e50..3de3e5628 100644 --- a/docs/content/limitations/builtin-apis/streams-and-readline.mdx +++ b/docs/content/limitations/builtin-apis/streams-and-readline.mdx @@ -14,6 +14,7 @@ `stream.compose` accepts two or more streams, or one `Duplex`; functions, iterables, and web streams as stages are unsupported, and the `ERR_INVALID_ARG_VALUE` message for a stream that is no longer readable or writable names the stream's class instead of printing the stream. `pipeline` from `node:stream/promises` accepts a trailing `{ signal, end }` object, and `finished` accepts `readable`, `writable`, `error`, `cleanup`, and `signal` options, with boolean literals for the flags. Stream constructors accept a `signal` option in an options object literal, and `stream.addAbortSignal` accepts any stream. + A `transform` or `flush` option callback whose completion callback types `data` as `any`, as @types/node's `TransformCallback` does, may pass a Buffer, a string, or nothing; any other value throws a TypeError where the callback is called, instead of Node's `ERR_INVALID_ARG_TYPE` stream error. `node:readline` and `node:readline/promises` (also reached as `readline.promises`) interfaces, from `createInterface(options)` or `createInterface(input, output, completer, terminal)`, read `process.stdin` or a readable stream: `question`, `prompt`, `write` (with a key object literal of `name`, `ctrl`, `meta`, and `shift`), `pause`, `resume`, `'line'`/`'close'`/`'pause'`/`'resume'`/`'error'`/`'history'`/`'SIGINT'`/`'SIGTSTP'`/`'SIGCONT'` listeners, and `for await` compile. The `history`, `historySize`, `removeHistoryDuplicates`, `completer`, `tabSize`, and `escapeCodeTimeout` options are validated as in Node. With `terminal: true`, or with no `terminal` option and `process.stdout` as the output when it is a TTY, the interface runs Node's terminal mode: the editing keys, the kill ring, undo and redo, history recording and recall, Tab completion through the completer, Ctrl+C, Ctrl+D, and Ctrl+Z, `TERM=dumb`, and the same escape sequences written to the output. diff --git a/docs/content/limitations/child-process-workers.mdx b/docs/content/limitations/child-process-workers.mdx index 5b41c5e53..9d6602509 100644 --- a/docs/content/limitations/child-process-workers.mdx +++ b/docs/content/limitations/child-process-workers.mdx @@ -12,3 +12,7 @@ Message listeners may return `void` or `Promise`. Messages use newline-delimited JSON, so their static types must be JSON-stringifiable or `unknown` backed by a checked JSON tree. `send()` returns the channel's backpressure state and invokes its callback later with `null` or an `Error`. `disconnect()` changes `connected` synchronously, before the later disconnect events. + +A `'data'` listener on a child's `stdout` or `stderr` whose chunk is `unknown` or `any` receives strings when a `setEncoding()` statement on the same stream precedes it in its block or an enclosing block, and Buffers when the function never calls `setEncoding()` on that stream. +Any other placement of `setEncoding()` is refused at compile time, and a `setEncoding()` call that runs elsewhere afterwards makes the listener throw a TypeError instead of receiving strings. +An inline `'exit'` or `'close'` listener may declare `(code: number, signal: string)`, which TypeScript accepts through the catch-all `on` overload; it receives the `null` values Node passes, and a typed use of a `null` value throws a TypeError. diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index f7b9f2517..427c15aac 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -181,6 +181,7 @@ import { genResultThunkFor, childExitThunkFor, childExitSignalThunkFor, + childDataDynThunkFor, childDataThunkFor, execFileThunkFor, ipcMessageThunkFor, @@ -5564,6 +5565,10 @@ export class LlEmitter { return childDataThunkFor(this, param); } + childDataDynThunkFor(chunk: "bytes" | "str"): string { + return childDataDynThunkFor(this, chunk); + } + emitterFixedAdapter(cbT: IrType & { kind: "func" }): { fn: string; shim: string } { return emitterFixedAdapter(this, cbT); } diff --git a/packages/compiler/src/backend/llvm/expr-callbacks.ts b/packages/compiler/src/backend/llvm/expr-callbacks.ts index db1dca1af..6b6aae055 100644 --- a/packages/compiler/src/backend/llvm/expr-callbacks.ts +++ b/packages/compiler/src/backend/llvm/expr-callbacks.ts @@ -754,6 +754,31 @@ export function childDataThunkFor(host: LlvmEmitterContext, param: IrType): stri return sym; } +/** The child-stream 'data' thunk for an unknown/any chunk parameter: the + * runtime's Buffer (or, after setEncoding, string) chunk boxes into a + * checked-dynamic value the listener owns. */ +export function childDataDynThunkFor(host: LlvmEmitterContext, chunk: "bytes" | "str"): string { + const key = `cdd:${chunk}`; + let sym = host.resolveThunks.get(key); + if (sym) return sym; + sym = `sc_cdd_${host.resolveThunks.size}`; + host.resolveThunks.set(key, sym); + const box = chunk === "bytes" ? "scr_dyn_new_buffer" : "scr_dyn_new_str"; + host.declare(`declare ptr @${box}(ptr)`); + host.resolveThunkDefs.push( + `define internal void @${sym}(ptr %cb, ptr %chunk) ${FN_ATTRS} { ; child 'data' → dyn (${chunk})`, + `entry:`, + ` %d = call ptr @${box}(ptr %chunk)`, + ` %fnp = getelementptr inbounds %ScrClosure, ptr %cb, i64 0, i32 1`, + ` %fn = load ptr, ptr %fnp`, + ` call void %fn(ptr %cb, ptr %d)`, + ` ret void`, + `}`, + ``, + ); + return sym; +} + export function emitterFixedAdapter( host: LlvmEmitterContext, cbT: IrType & { kind: "func" }, diff --git a/packages/compiler/src/backend/llvm/lib-stream.ts b/packages/compiler/src/backend/llvm/lib-stream.ts index b62b237df..0ded59a1a 100644 --- a/packages/compiler/src/backend/llvm/lib-stream.ts +++ b/packages/compiler/src/backend/llvm/lib-stream.ts @@ -56,6 +56,8 @@ export function emitStreamLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlV host.declare(`declare void @scr_child_stream_thunk0(ptr, ptr)`); } else if (param.kind === "union") { adapter = host.childDataThunkFor(param); + } else if (param.kind === "dyn") { + adapter = host.childDataDynThunkFor("bytes"); } else { adapter = "scr_child_stream_thunk_bytes"; host.declare(`declare void @scr_child_stream_thunk_bytes(ptr, ptr)`); @@ -78,7 +80,8 @@ export function emitStreamLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlV if (e.fn === "stream.onDataStr") { host.usesTimers = true; const cbT = e.args[1]!.type; - if (cbT.kind !== "func" || cbT.params[0]?.kind !== "string") { + const strParam = cbT.kind === "func" ? cbT.params[0]?.kind : undefined; + if (strParam !== "string" && strParam !== "dyn") { throw new InternalCompilerError( "llvm emitter bug: stream.onDataStr callback not a string func", ); @@ -87,10 +90,12 @@ export function emitStreamLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlV const cb = host.emitExpr(e.args[1]!); const once = host.emitExpr(e.args[2]!); host.toHeap(cb); - host.declare(`declare void @scr_child_stream_thunk_str(ptr, ptr)`); + let adapter = "scr_child_stream_thunk_str"; + if (strParam === "dyn") adapter = host.childDataDynThunkFor("str"); + else host.declare(`declare void @scr_child_stream_thunk_str(ptr, ptr)`); host.declare(`declare void @scr_child_stream_on_data_str(ptr, ptr, ptr, i1 zeroext)`); B.line( - `call void @scr_child_stream_on_data_str(ptr ${s0.name}, ptr ${cb.name}, ptr @scr_child_stream_thunk_str, i1 ${once.name})`, + `call void @scr_child_stream_on_data_str(ptr ${s0.name}, ptr ${cb.name}, ptr @${adapter}, i1 ${once.name})`, ); return { name: "", type: e.type }; } diff --git a/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts b/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts index 7f0c2cde0..a2b0e1f57 100644 --- a/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts +++ b/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts @@ -132,8 +132,16 @@ export function lowerChildMethodCall( ) { for (const param of listenerNode.parameters.nodes) lowerer.checkedCallbackParams.add(param); } - const cb = lowerer.lowerExpr(call.arguments.nodes[1]!); + const narrowed = + event === "exit" || event === "close" + ? narrowedExitListenerParams(lowerer, listenerNode) + : []; + const cb = + narrowed.length > 0 + ? lowerWithCheckedParams(lowerer, listenerNode, narrowed) + : lowerer.lowerExpr(call.arguments.nodes[1]!); if ( + narrowed.length > 0 || (isJsSourceFile(listenerNode.getSourceFile()) && cb.type.kind === "dyn") || (cb.type.kind === "func" && (cb.type.rest || @@ -302,10 +310,12 @@ export function lowerChildMethodCall( /** Method calls on piped child-output stream receivers (child.stdout / * child.stderr — the childStream kind): on/once("data" | "end"). - * 'data' listeners take zero parameters, `(chunk: Buffer)`, or a - * `Buffer | string`-union chunk (the ngrok appendOutput shape — the - * runtime only ever fires Buffers; the compiler-emitted adapter wraps - * the chunk at the union's Buffer arm); 'end' listeners take none. + * 'data' listeners take zero parameters, `(chunk: Buffer)`, `(chunk: + * string)`, an unknown/any chunk (boxed as a checked-dynamic value; see + * childStreamEncodedAt), or a `Buffer | string`-union chunk (the ngrok + * appendOutput shape — the runtime only ever fires Buffers; the + * compiler-emitted adapter wraps the chunk at the union's Buffer arm); + * 'end' listeners take none. * Statement position only (Node returns the stream for chaining; here * the result is void). Chained receivers (`child.stdout?.on(...)`) * ride the optional-chain re-dispatch (chainBlocked). Everything else @@ -379,18 +389,26 @@ export function lowerChildStreamMethodCall( if ( param !== undefined && param.kind !== "string" && + param.kind !== "dyn" && !(param.kind === "bytes" && param.elem === "u8") && !unionOk(param) ) { lowerer.unsupported( "SC1090", call.arguments.nodes[1]!, - `data listeners whose parameter is not 'Buffer', 'string', or a Buffer-armed union (got '${lowerer.fmt(param)}')`, + `data listeners whose parameter is not 'Buffer', 'string', 'unknown', or a Buffer-armed union (got '${lowerer.fmt(param)}')`, ); } + // An unknown/any chunk is a Buffer, or a string once setEncoding ran. + // The registration takes whichever the enclosing code establishes; a + // later setEncoding that contradicts it throws the runtime's + // listener-type TypeError instead of delivering the other kind. + const strings = + param?.kind === "string" || + (param?.kind === "dyn" && childStreamEncodedAt(lowerer, access.expression, call)); return { kind: "libCall", - fn: param?.kind === "string" ? "stream.onDataStr" : "stream.onData", + fn: strings ? "stream.onDataStr" : "stream.onData", args: [receiver, cb, once], type: VOID, loc, @@ -521,3 +539,127 @@ export function lowerChildWriterMethodCall( lowerer.checker.getSymbolAtLocation(access.name), ); } + +/** A receiver spelled as a plain access path (`child.stdout`, `out`): its + * root symbol and member names, or null for other forms. */ +function accessPathOf( + lowerer: Lowerer, + expr: ts.Expression, +): { root: ts.Symbol; path: string } | null { + if (ts.isParenthesizedExpression(expr) || ts.isNonNullExpression(expr)) { + return accessPathOf(lowerer, expr.expression); + } + if (ts.isIdentifier(expr)) { + const root = lowerer.checker.getSymbolAtLocation(expr); + return root ? { root, path: "" } : null; + } + if (ts.isPropertyAccessExpression(expr) && !expr.questionDotToken) { + const base = accessPathOf(lowerer, expr.expression); + return base === null ? null : { root: base.root, path: `${base.path}.${expr.name.text}` }; + } + return null; +} + +/** Whether an unknown-typed 'data' listener registered by `call` receives + * strings: a `setEncoding` statement on the same receiver path precedes + * the registration in its own block or an enclosing block of the same + * function. With no setEncoding on that path in the function, chunks are + * Buffers. Any other placement leaves the encoding state unclear, which + * is reported. */ +function childStreamEncodedAt( + lowerer: Lowerer, + receiver: ts.Expression, + call: ts.CallExpression, +): boolean { + const key = accessPathOf(lowerer, receiver); + const statement: ts.Node = call.parent!; + let scope: ts.Node | undefined = statement; + while (scope && !ts.isFunctionLike(scope) && !ts.isSourceFile(scope)) scope = scope.parent; + const unclear = (): never => + lowerer.unsupported( + "SC1090", + call.arguments.nodes[1]!, + "untyped child-stream 'data' listeners whose setEncoding state is unclear at their registration sites (declare the chunk as 'Buffer' or 'string')", + ); + if (key === null || scope === undefined) return unclear(); + const preceding = new Set(); + for (let node: ts.Node = statement; node !== scope;) { + const parent: ts.Node | undefined = node.parent; + if (parent === undefined) break; + if (ts.isBlock(parent) || ts.isSourceFile(parent)) { + for (const sibling of parent.statements.nodes) { + if (sibling === node) break; + preceding.add(sibling); + } + } + node = parent; + } + const samePath = ( + a: { root: ts.Symbol; path: string } | null, + b: { root: ts.Symbol; path: string }, + ): boolean => a !== null && a.root === b.root && a.path === b.path; + let before = false; + let elsewhere = false; + const visit = (node: ts.Node): void => { + if (node !== scope && ts.isFunctionLike(node)) return; + if ( + ts.isCallExpression(node) && + ts.isPropertyAccessExpression(node.expression) && + node.expression.name.text === "setEncoding" && + samePath(accessPathOf(lowerer, node.expression.expression), key) + ) { + if (ts.isExpressionStatement(node.parent) && preceding.has(node.parent)) before = true; + else elsewhere = true; + } + ts.forEachChild(node, visit); + }; + visit(scope); + if (elsewhere) return unclear(); + return before; +} + +/** An inline 'exit'/'close' listener may declare `(code: number, signal: + * string)`: TypeScript accepts it through ChildProcess's catch-all `on` + * overload, while Node passes `number | null` and `Signals | null`. Those + * parameters bind as checked-dynamic values (the socket 'data' listener + * precedent), so the body observes the null Node passes; a typed use of a + * null value throws the checked conversion's TypeError. Returns the + * narrowed parameter symbols, empty when the declared types already + * admit null. */ +function narrowedExitListenerParams(lowerer: Lowerer, listener: ts.Expression): ts.Symbol[] { + if (!ts.isArrowFunction(listener) && !ts.isFunctionExpression(listener)) return []; + if (isJsSourceFile(listener.getSourceFile())) return []; + const symbols: ts.Symbol[] = []; + const wanted: readonly string[] = ["f64", "string"]; + listener.parameters.nodes.slice(0, 2).forEach((param, i) => { + if (!ts.isIdentifier(param.name) || param.dotDotDotToken || param.initializer) return; + if (param.questionToken) return; + const symbol = lowerer.checker.getSymbolAtLocation(param.name); + if (!symbol || lowerer.runtimeOptionalBindingTypes.has(symbol)) return; + if (lowerer.paramShape(param).type.kind !== wanted[i]) return; + symbols.push(symbol); + }); + return symbols; +} + +/** Lowers an inline listener with the given parameters bound as + * checked-dynamic values typed `unknown` for the body. */ +function lowerWithCheckedParams( + lowerer: Lowerer, + listener: ts.Expression, + symbols: readonly ts.Symbol[], +): IrExpr { + const previousImplicit = lowerer.implicitParamTypes; + const implicit = new Map(previousImplicit ?? []); + for (const symbol of symbols) { + implicit.set(symbol, lowerer.checker.getUnknownType()); + lowerer.runtimeOptionalBindingTypes.set(symbol, DYN); + } + lowerer.implicitParamTypes = implicit; + try { + return lowerer.lowerExpr(listener); + } finally { + for (const symbol of symbols) lowerer.runtimeOptionalBindingTypes.delete(symbol); + lowerer.implicitParamTypes = previousImplicit; + } +} diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index 51c86fe39..fc89858b5 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -587,6 +587,33 @@ function dynOptionsValue(lowerer: Lowerer, arg: ts.Expression): IrExpr | null { return v.type.kind === "dyn" ? v : null; } +/** @types/node declares the transform/flush completion callback as + * `(error?: Error | null, data?: any) => void`. Outside objectMode Node + * accepts only a Buffer, a string or nothing as `data`, so the callback + * parameter is typed with that union while the option callback lowers: a + * checked-dynamic value passed as `data` converts at the call. Returns the + * pinned parameter symbol (the caller unpins it), or null when the + * declared type needs no pin. */ +function pinAnyDataCompletion( + lowerer: Lowerer, + which: string, + fnNode: ts.MethodDeclaration | ts.FunctionExpression | ts.ArrowFunction, +): ts.Symbol | null { + const index = which === "transform" ? 2 : which === "flush" ? 0 : -1; + const param = index < 0 ? undefined : fnNode.parameters.nodes[index]; + if (param === undefined || !ts.isIdentifier(param.name) || param.dotDotDotToken) return null; + const symbol = lowerer.checker.getSymbolAtLocation(param.name); + if (!symbol || lowerer.stageSourceTypes.has(symbol)) return null; + const declared = lowerer.paramShape(param).type; + if (declared.kind !== "func" || declared.rest || declared.params[1]?.kind !== "dyn") return null; + const data = unionOf(lowerer, [BYTES, STRING, { kind: "undefinedT" }]); + lowerer.stageSourceTypes.set( + symbol, + funcOf([declared.params[0]!, data, ...declared.params.slice(2)], declared.ret), + ); + return symbol; +} + /** Parses the options object literal of a stream constructor. `which` * names the callbacks this class accepts, in canonical flag order. */ function parseStreamOptions( @@ -672,22 +699,27 @@ function parseStreamOptions( continue; } const full = tuples[name]!.map((t) => (t === "fn" ? null : t)); - // The completion-callback tail: typed by the checker contextually; - // accept the user's declared func type as the tuple's entry so the - // prefix check compares like with like. - const { funcType } = lowerer.lambdaSignature(fnNode); - const tuple: IrType[] = full.map((t, i) => { - if (t !== null) return t; - const declared = funcType.params[i]; - if (declared !== undefined && declared.kind !== "func" && declared.kind !== "dyn") { - lowerer.noLowering( - `a '${name}' callback whose parameter ${i} is '${lowerer.fmt(declared)}' where Node passes the completion callback`, - fnNode!, - ); - } - return declared ?? funcOf([], VOID); - }); - present.set(name, lowerStreamCallback(lowerer, name, fnNode, thisType, tuple)); + const pinned = pinAnyDataCompletion(lowerer, name, fnNode); + try { + // The completion-callback tail: typed by the checker contextually; + // accept the user's declared func type as the tuple's entry so the + // prefix check compares like with like. + const { funcType } = lowerer.lambdaSignature(fnNode); + const tuple: IrType[] = full.map((t, i) => { + if (t !== null) return t; + const declared = funcType.params[i]; + if (declared !== undefined && declared.kind !== "func" && declared.kind !== "dyn") { + lowerer.noLowering( + `a '${name}' callback whose parameter ${i} is '${lowerer.fmt(declared)}' where Node passes the completion callback`, + fnNode!, + ); + } + return declared ?? funcOf([], VOID); + }); + present.set(name, lowerStreamCallback(lowerer, name, fnNode, thisType, tuple)); + } finally { + if (pinned) lowerer.stageSourceTypes.delete(pinned); + } continue; } // `{ signal }` shorthand: the binding is the value. diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index c9a0c6435..393db65d9 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -2064,7 +2064,9 @@ export class Lowerer { /** A pipeline() function stage's `source` parameter: the IR type of what * the pipeline passes it (the previous stage as an async iterable), set * while the stage lowers. Parameter typing and `for await` heads read - * it before the checker's `AsyncIterable`. */ + * it before the checker's `AsyncIterable`. A stream option callback's + * completion parameter declared with an any-typed `data` is pinned here + * too while the callback lowers (pinAnyDataCompletion). */ readonly stageSourceTypes = new Map(); /** Set when a match result lowers to execGroups/matchGroups, the inputs * of regex span folding. */ diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 597076cb1..57c5af04c 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -2540,7 +2540,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * throws when the program lacks the stream unit's boxing helpers. */ "child.stdioStream": { argTypes: [CHILD_T, F64], result: VOID }, // Listener registrations: callback func shapes are program-dependent - // (zero-param / Buffer / Buffer-armed union) — the slots pin arity, + // (zero-param / Buffer / string / unknown / Buffer-armed union) — the slots pin arity, // the stream receiver, and the once-flag. "stream.onData": { argTypes: [CHILDSTREAM_T, null, BOOL], result: VOID }, "stream.onDataStr": { argTypes: [CHILDSTREAM_T, null, BOOL], result: VOID }, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6470-stream-transform-any-data-callback.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6470-stream-transform-any-data-callback.ts.json new file mode 100644 index 000000000..3d4a39486 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6470-stream-transform-any-data-callback.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6470-stream-transform-any-data-callback.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6471-stream-data-buffer-or-string.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6471-stream-data-buffer-or-string.ts.json new file mode 100644 index 000000000..e8ff1e084 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6471-stream-data-buffer-or-string.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6471-stream-data-buffer-or-string.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6472-child-data-unknown-chunk.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6472-child-data-unknown-chunk.ts.json new file mode 100644 index 000000000..3c7183bb6 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6472-child-data-unknown-chunk.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6472-child-data-unknown-chunk.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/stream-construction.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/stream-construction.ts.json new file mode 100644 index 000000000..35dc0be0d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/stream-construction.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/stream-construction.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6470-stream-transform-any-data-callback.ts b/tests/corpus/6470-stream-transform-any-data-callback.ts new file mode 100644 index 000000000..cc4935a7e --- /dev/null +++ b/tests/corpus/6470-stream-transform-any-data-callback.ts @@ -0,0 +1,60 @@ +// Transform option callbacks whose completion callback declares an +// any-typed `data` (the @types/node TransformCallback spelling): the data +// passed back may be a Buffer, a string, or omitted. +import { PassThrough, Transform } from "node:stream"; +import { createGunzip, gzipSync } from "node:zlib"; + +type Done = (error?: Error | null, data?: any) => void; + +interface Progress { + bytes: number; + chunks: number; +} + +function counting(progress: Progress): Transform { + return new Transform({ + transform(chunk: Buffer, _encoding: string, callback: Done) { + progress.bytes += chunk.length; + progress.chunks++; + callback(null, chunk); + }, + }); +} + +const upper = new Transform({ + transform(chunk: Buffer, _encoding: string, callback: Done) { + const text = chunk.toString(); + if (text === "skip") { + callback(); + return; + } + callback(null, text.toUpperCase()); + }, + flush(callback: Done) { + callback(null, Buffer.from("!")); + }, +}); +upper.on("data", (d: Buffer) => console.log("upper", JSON.stringify(d.toString()))); +upper.on("end", () => console.log("upper end")); +upper.write("hello"); +upper.write("skip"); +upper.end("world"); + +const failing = new Transform({ + transform(chunk: Buffer, _encoding: string, callback: Done) { + callback(new Error(`refused ${chunk.length} bytes`)); + }, +}); +failing.on("error", (e: Error) => console.log("error", e.message)); +failing.write("abc"); + +const progress: Progress = { bytes: 0, chunks: 0 }; +const counter = counting(progress); +const out = new PassThrough(); +counter.pipe(createGunzip()).pipe(out); +const parts: string[] = []; +out.on("data", (d: Buffer) => parts.push(d.toString())); +out.on("end", () => { + console.log("gunzip", JSON.stringify(parts.join("")), progress.bytes > 0, progress.chunks); +}); +counter.end(gzipSync(Buffer.from("compressed payload"))); diff --git a/tests/corpus/6471-stream-data-buffer-or-string.ts b/tests/corpus/6471-stream-data-buffer-or-string.ts new file mode 100644 index 000000000..69289ced5 --- /dev/null +++ b/tests/corpus/6471-stream-data-buffer-or-string.ts @@ -0,0 +1,44 @@ +// 'data' listeners on runtime streams may declare the chunk as +// `Buffer | string` (the @types/node ReadStream listener type): the +// listener receives a Buffer, or a string once an encoding applies. +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import { PassThrough, Readable } from "node:stream"; + +function describe(label: string, chunk: Buffer | string): void { + if (typeof chunk === "string") console.log(label, "string", JSON.stringify(chunk)); + else console.log(label, "buffer", chunk.length, JSON.stringify(chunk.toString())); +} + +const raw = new PassThrough(); +raw.on("data", (chunk: Buffer | string) => describe("raw", chunk)); +raw.write("abc"); +raw.end(Buffer.from("de")); + +const text = new PassThrough(); +text.setEncoding("utf8"); +text.on("data", (chunk: Buffer | string) => describe("text", chunk)); +text.end("héllo"); + +const r = new Readable({ read() {} }); +r.on("data", (chunk: Buffer | string) => describe("readable", chunk)); +r.on("end", () => console.log("readable end")); +r.push("one"); +r.push(null); + +const file = path.join(os.tmpdir(), `scriptc-6471-${process.pid}.txt`); +fs.writeFileSync(file, "file contents\n"); +const stream = fs.createReadStream(file); +const release = (): void => console.log("released"); +stream.on("data", (chunk: Buffer | string) => describe("file", chunk)); +stream.on("close", release); +stream.on("error", release); +stream.on("end", () => { + const encoded = fs.createReadStream(file, { encoding: "utf8" }); + encoded.on("data", (chunk: Buffer | string) => describe("file utf8", chunk)); + encoded.on("close", () => { + fs.unlinkSync(file); + console.log("done"); + }); +}); diff --git a/tests/corpus/6472-child-data-unknown-chunk.ts b/tests/corpus/6472-child-data-unknown-chunk.ts new file mode 100644 index 000000000..4a0e97d34 --- /dev/null +++ b/tests/corpus/6472-child-data-unknown-chunk.ts @@ -0,0 +1,65 @@ +// A child stream 'data' listener whose chunk is unknown or any receives a +// Buffer, or a string when setEncoding ran before the listener registered. +import { spawn } from "node:child_process"; + +function report(code: number | null, kinds: string[], stdout: string, stderr: string): void { + console.log("code", code, "kinds", [...new Set(kinds)].join(",")); + console.log("stdout", JSON.stringify(stdout)); + console.log("stderr", JSON.stringify(stderr)); +} + +function runEncoded(script: string): Promise { + return new Promise((resolve) => { + const child = spawn("/bin/sh", ["-c", script], { stdio: "pipe" }); + let stdout = ""; + let stderr = ""; + const kinds: string[] = []; + if (child.stdout) { + child.stdout.setEncoding("utf8"); + child.stdout.on("data", (c: any) => { + kinds.push(typeof c); + stdout += c; + }); + } + const err = child.stderr; + if (err !== null) { + err.setEncoding("utf8"); + err.on("data", (c: unknown) => { + kinds.push(typeof c); + stderr += String(c); + }); + } + child.on("close", (code) => { + report(code, kinds, stdout, stderr); + resolve(); + }); + }); +} + +function runRaw(script: string): Promise { + return new Promise((resolve) => { + const child = spawn("/bin/sh", ["-c", script], { stdio: "pipe" }); + let stdout = ""; + let stderr = ""; + const kinds: string[] = []; + child.stdout?.on("data", (c: unknown) => { + kinds.push(Buffer.isBuffer(c) ? "buffer" : typeof c); + stdout += String(c); + }); + if (child.stderr) { + child.stderr.on("data", (c: any) => { + const chunk = String(c); + kinds.push(Buffer.isBuffer(c) ? "buffer" : typeof c); + stderr += chunk; + }); + } + child.on("close", (code) => { + report(code, kinds, stdout, stderr); + resolve(); + }); + }); +} + +runEncoded("printf 'h\\303\\251llo'; echo warn >&2") + .then(() => runRaw("printf raw; echo oops >&2; exit 2")) + .then(() => console.log("done")); diff --git a/tests/diagnostics/child-process.ts b/tests/diagnostics/child-process.ts index f96bce418..6c5683efc 100644 --- a/tests/diagnostics/child-process.ts +++ b/tests/diagnostics/child-process.ts @@ -42,3 +42,8 @@ const staticWorker = new URL("./child-process.ts", import.meta.url); fork(staticWorker, [], { serialization: "advanced" }); fork(staticWorker, [], { stdio: ["ignore", "ignore", "ignore", "ignore"] }); // Keep each fence on its own statement so diagnostics remain site-specific. +// An unknown 'data' chunk takes the setEncoding state established before +// the listener registers; a setEncoding placed elsewhere leaves it unclear. +const pipedOut = piped.stdout!; +pipedOut.on("data", (chunk: unknown) => console.log(String(chunk))); +pipedOut.setEncoding("utf8"); diff --git a/tests/fixtures/node-types/stream-construction.ts b/tests/fixtures/node-types/stream-construction.ts new file mode 100644 index 000000000..37a1b852e --- /dev/null +++ b/tests/fixtures/node-types/stream-construction.ts @@ -0,0 +1,100 @@ +// Streams constructed under @types/node: option-bag Transform and +// PassThrough streams with @types/node's TransformCallback, a gunzip stage, +// fs.ReadStream listeners, and child-process listeners declared with +// unknown chunks and non-null exit types. +import { spawn } from "node:child_process"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import { PassThrough, Transform } from "node:stream"; +import { createGunzip, gzipSync } from "node:zlib"; + +interface Progress { + bytes: number; + chunks: number; +} + +function createCounter(progress: Progress) { + return new Transform({ + transform(chunk, _encoding, callback) { + const length = typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length; + progress.bytes += length; + progress.chunks++; + callback(null, chunk); + }, + flush(callback) { + callback(); + }, + }); +} + +function gunzipThrough(payload: Buffer): Promise { + return new Promise((resolve) => { + const progress: Progress = { bytes: 0, chunks: 0 }; + const counter = createCounter(progress); + const gunzip = createGunzip(); + const out = new PassThrough(); + const parts: string[] = []; + counter.pipe(gunzip).pipe(out); + out.on("data", (d: Buffer) => parts.push(d.toString())); + out.on("end", () => resolve(`${parts.join("")} ${progress.bytes > 0} ${progress.chunks}`)); + counter.end(payload); + }); +} + +function readFileStream(file: string): Promise { + return new Promise((resolve) => { + const stream = fs.createReadStream(file); + let text = ""; + const release = () => console.log("released"); + stream.on("close", release); + stream.on("error", release); + stream.on("data", (chunk) => { + text += chunk.toString(); + }); + stream.on("end", () => resolve(text)); + }); +} + +function run(script: string): Promise { + return new Promise((resolve, reject) => { + const child = spawn("/bin/sh", ["-c", script], { stdio: "pipe" }); + let stdout = ""; + let stderr = ""; + if (child.stdout) { + child.stdout.setEncoding("utf8"); + child.stdout.on("data", (c) => { + stdout += c; + }); + } + if (child.stderr) { + child.stderr.on("data", (c) => { + const chunk = String(c); + stderr += chunk; + }); + } + child.on("error", reject); + child.on("close", (code: number, signal: string) => { + if (code === 0) return resolve(stdout); + reject(new Error(`Exited with ${code || signal}: ${stderr.trim()}`)); + }); + }); +} + +async function main(): Promise { + console.log("gunzip", await gunzipThrough(gzipSync(Buffer.from("payload")))); + const file = path.join(os.tmpdir(), `scriptc-stream-construction-${process.pid}.txt`); + fs.writeFileSync(file, "file text\n"); + console.log("file", JSON.stringify(await readFileStream(file))); + fs.unlinkSync(file); + console.log("run", JSON.stringify(await run("echo hi; echo warn >&2"))); + for (const script of ["echo bad >&2; exit 3", "kill -TERM $$"]) { + try { + await run(script); + } catch (e) { + console.log("error", (e as Error).message); + } + } +} + +void main(); diff --git a/tests/harness/__snapshots__/child-process.ts.txt b/tests/harness/__snapshots__/child-process.ts.txt index 2d83132f5..6fee8a2c2 100644 --- a/tests/harness/__snapshots__/child-process.ts.txt +++ b/tests/harness/__snapshots__/child-process.ts.txt @@ -91,4 +91,11 @@ child-process.ts:43:64 - error SC2020: 'fork without a fourth-slot IPC channel' | ^~~~~~~~ 44 | // Keep each fence on its own statement so diagnostics remain site-specific. - hint: the fourth stdio entry must be "ipc" \ No newline at end of file + hint: the fourth stdio entry must be "ipc" + +child-process.ts:48:21 - error SC1090: untyped child-stream 'data' listeners whose setEncoding state is unclear at their registration sites (declare the chunk as 'Buffer' or 'string') are not supported yet + + 47 | const pipedOut = piped.stdout!; + 48 | pipedOut.on("data", (chunk: unknown) => console.log(String(chunk))); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 49 | pipedOut.setEncoding("utf8"); \ No newline at end of file diff --git a/tests/harness/project-config.test.ts b/tests/harness/project-config.test.ts index 3635c88ed..31e84fdbb 100644 --- a/tests/harness/project-config.test.ts +++ b/tests/harness/project-config.test.ts @@ -479,6 +479,24 @@ test("node-types: NodeJS stream interfaces and stream.Readable/Writable take eve expect(comparableStderr(native.stderr)).toBe(node.stderr); }); +test("node-types: streams construct and child listeners take @types/node's parameter types", async () => { + const outDir = outDirFor("stream-construction"); + const entry = join(nodeTypesDir, "stream-construction.ts"); + const result = await compile(entry, { + outPath: join(outDir, "stream-construction"), + outDir, + sanitize, + }); + expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true); + if (!result.ok) return; + const [native, node] = await Promise.all([ + execFileAsync(result.binaryPath), + execFileAsync(process.execPath, ["--disable-warning=MODULE_TYPELESS_PACKAGE_JSON", entry]), + ]); + expect(native.stdout).toBe(node.stdout); + expect(comparableStderr(native.stderr)).toBe(node.stderr); +}); + test("node-types: promisified setTimeout and setImmediate lower as timers/promises", async () => { const outDir = outDirFor("promisify-timers"); const entry = join(nodeTypesDir, "promisify-timers.ts"); From 8e87f6f9ef5a5b90444f7cd624902bf87f163238 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 08:49:48 -0500 Subject: [PATCH 28/39] Resolve const aliases when deciding a child stream's setEncoding state An untyped child-stream 'data' listener takes strings when a setEncoding call on the same stream precedes it. A const alias of an access path (`const out = child.stdout`) now resolves to that path, so a setEncoding through one alias and a listener through another, or through the stream itself, agree. A setEncoding on another receiver that can hold the same stream (a let copy, a parameter, a call result) leaves the state unclear and reports the existing SC1090. Receivers that name different members of one root, or two const roots each initialized by a call or new, are treated as different streams. --- .../builtins/child-process-methods.ts | 70 +++++++++++++++---- tests/corpus/6472-child-data-unknown-chunk.ts | 22 ++++++ tests/diagnostics/child-process.ts | 5 ++ .../__snapshots__/child-process.ts.txt | 9 ++- 4 files changed, 93 insertions(+), 13 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts b/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts index a2b0e1f57..aae51a8be 100644 --- a/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts +++ b/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts @@ -541,25 +541,64 @@ export function lowerChildWriterMethodCall( } /** A receiver spelled as a plain access path (`child.stdout`, `out`): its - * root symbol and member names, or null for other forms. */ + * root symbol and member names, or null for other forms. A `const` alias + * of an access path (`const out = child.stdout`) resolves to that path, + * so every spelling of one stream gets the same key. */ function accessPathOf( lowerer: Lowerer, expr: ts.Expression, + depth = 0, ): { root: ts.Symbol; path: string } | null { + if (depth > 16) return null; if (ts.isParenthesizedExpression(expr) || ts.isNonNullExpression(expr)) { - return accessPathOf(lowerer, expr.expression); + return accessPathOf(lowerer, expr.expression, depth + 1); } if (ts.isIdentifier(expr)) { const root = lowerer.checker.getSymbolAtLocation(expr); - return root ? { root, path: "" } : null; + if (!root) return null; + const init = constInitializerOf(root); + const aliased = init === null ? null : accessPathOf(lowerer, init, depth + 1); + return aliased ?? { root, path: "" }; } if (ts.isPropertyAccessExpression(expr) && !expr.questionDotToken) { - const base = accessPathOf(lowerer, expr.expression); + const base = accessPathOf(lowerer, expr.expression, depth + 1); return base === null ? null : { root: base.root, path: `${base.path}.${expr.name.text}` }; } return null; } +/** The initializer of a symbol declared once as a `const` variable, else null. */ +function constInitializerOf(symbol: ts.Symbol): ts.Expression | null { + const decls = symbol.declarations; + if (decls.length !== 1) return null; + const decl = decls[0]!; + if ( + !ts.isVariableDeclaration(decl) || + !ts.isIdentifier(decl.name) || + decl.initializer === undefined || + (ts.getCombinedNodeFlags(decl) & ts.NodeFlags.Const) === 0 + ) + return null; + return decl.initializer; +} + +/** Whether two resolved access paths name different objects: the same root + * with different members, or two `const` roots each initialized by a call + * or `new` (such as two `spawn()` results). */ +function distinctPaths( + a: { root: ts.Symbol; path: string }, + b: { root: ts.Symbol; path: string }, +): boolean { + if (a.root === b.root) return a.path !== b.path; + const fresh = (root: ts.Symbol): boolean => { + let init = constInitializerOf(root); + while (init !== null && (ts.isParenthesizedExpression(init) || ts.isAwaitExpression(init))) + init = init.expression; + return init !== null && (ts.isCallExpression(init) || ts.isNewExpression(init)); + }; + return fresh(a.root) && fresh(b.root); +} + /** Whether an unknown-typed 'data' listener registered by `call` receives * strings: a `setEncoding` statement on the same receiver path precedes * the registration in its own block or an enclosing block of the same @@ -594,10 +633,7 @@ function childStreamEncodedAt( } node = parent; } - const samePath = ( - a: { root: ts.Symbol; path: string } | null, - b: { root: ts.Symbol; path: string }, - ): boolean => a !== null && a.root === b.root && a.path === b.path; + const receiverType = lowerer.checker.getNonNullableType(lowerer.typeOf(receiver)); let before = false; let elsewhere = false; const visit = (node: ts.Node): void => { @@ -605,11 +641,21 @@ function childStreamEncodedAt( if ( ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && - node.expression.name.text === "setEncoding" && - samePath(accessPathOf(lowerer, node.expression.expression), key) + node.expression.name.text === "setEncoding" ) { - if (ts.isExpressionStatement(node.parent) && preceding.has(node.parent)) before = true; - else elsewhere = true; + const target = node.expression.expression; + const path = accessPathOf(lowerer, target); + if (path !== null && path.root === key.root && path.path === key.path) { + if (ts.isExpressionStatement(node.parent) && preceding.has(node.parent)) before = true; + else elsewhere = true; + } else if ( + (path === null || !distinctPaths(path, key)) && + lowerer.checker.isTypeAssignableTo(receiverType, lowerer.typeOf(target)) + ) { + // Another spelling that can hold this stream (a parameter, a `let` + // copy, a call result): its setEncoding may be this stream's. + elsewhere = true; + } } ts.forEachChild(node, visit); }; diff --git a/tests/corpus/6472-child-data-unknown-chunk.ts b/tests/corpus/6472-child-data-unknown-chunk.ts index 4a0e97d34..8308aa8cf 100644 --- a/tests/corpus/6472-child-data-unknown-chunk.ts +++ b/tests/corpus/6472-child-data-unknown-chunk.ts @@ -60,6 +60,28 @@ function runRaw(script: string): Promise { }); } +// setEncoding through one const alias of the stream and the listener +// through another: both name child.stdout, so chunks are strings. +function runAliased(script: string): Promise { + return new Promise((resolve) => { + const child = spawn("/bin/sh", ["-c", script], { stdio: "pipe" }); + const encoded = child.stdout!; + const listened = child.stdout!; + let stdout = ""; + const kinds: string[] = []; + encoded.setEncoding("utf8"); + listened.on("data", (c: unknown) => { + kinds.push(typeof c); + stdout += String(c); + }); + child.on("close", (code) => { + report(code, kinds, stdout, ""); + resolve(); + }); + }); +} + runEncoded("printf 'h\\303\\251llo'; echo warn >&2") .then(() => runRaw("printf raw; echo oops >&2; exit 2")) + .then(() => runAliased("printf alias")) .then(() => console.log("done")); diff --git a/tests/diagnostics/child-process.ts b/tests/diagnostics/child-process.ts index 6c5683efc..02b4349e8 100644 --- a/tests/diagnostics/child-process.ts +++ b/tests/diagnostics/child-process.ts @@ -47,3 +47,8 @@ fork(staticWorker, [], { stdio: ["ignore", "ignore", "ignore", "ignore"] }); const pipedOut = piped.stdout!; pipedOut.on("data", (chunk: unknown) => console.log(String(chunk))); pipedOut.setEncoding("utf8"); +// A setEncoding through a copy that can hold the same stream (a `let` +// binding here) leaves the state unclear as well. +let pipedErr = piped.stderr!; +pipedErr.setEncoding("utf8"); +piped.stderr!.on("data", (chunk: unknown) => console.log(String(chunk))); diff --git a/tests/harness/__snapshots__/child-process.ts.txt b/tests/harness/__snapshots__/child-process.ts.txt index 6fee8a2c2..f5f9f8f86 100644 --- a/tests/harness/__snapshots__/child-process.ts.txt +++ b/tests/harness/__snapshots__/child-process.ts.txt @@ -98,4 +98,11 @@ child-process.ts:48:21 - error SC1090: untyped child-stream 'data' listeners who 47 | const pipedOut = piped.stdout!; 48 | pipedOut.on("data", (chunk: unknown) => console.log(String(chunk))); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 49 | pipedOut.setEncoding("utf8"); \ No newline at end of file + 49 | pipedOut.setEncoding("utf8"); + +child-process.ts:54:26 - error SC1090: untyped child-stream 'data' listeners whose setEncoding state is unclear at their registration sites (declare the chunk as 'Buffer' or 'string') are not supported yet + + 53 | pipedErr.setEncoding("utf8"); + 54 | piped.stderr!.on("data", (chunk: unknown) => console.log(String(chunk))); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 55 | \ No newline at end of file From 02fc8ab13c512df7224be4a1ce6f73f9f604dab2 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 08:54:18 -0500 Subject: [PATCH 29/39] Keep one process-stream Writable per descriptor and never end it from a pipe Under the general stream representation, every conversion of process.stdout or process.stderr into a Writable slot made a new stream, so two NodeJS.WritableStream slots holding process.stdout compared unequal and kept separate listeners and writable state. A pipe into such a slot also ended the converted Writable at the source's end, so later writes through the slot failed; Node never ends process.stdout or process.stderr from a pipe. scr_stream_stdio_writable now keeps one Writable per descriptor and thread, released at exit. Under the general representation, a pipe into a Writable slot lowers to readable.pipeGeneral (scr_stream_pipe_general, last in the stream unit), which keeps end off when the destination is one of those Writables; programs without the general representation lower pipes as before. The fallback stream.Writable's on() and once() overloads for drain, finish, close and error return the stream again, so listener chains such as out.on("finish", listener).end(data) type-check. Adds corpus 6468. --- .../ambient/scriptc-node-fallback.d.ts | 8 +-- .../compiler/src/backend/llvm/lib-shared.ts | 2 + .../src/frontend/lowering/lower-stream.ts | 14 +++++- packages/compiler/src/ir/builtin-effects.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 5 +- packages/compiler/src/ir/validate.ts | 4 +- .../6468-node-stdio-writable-slot.ts.json | 6 +++ packages/runtime/src/scr_stream.c | 36 +++++++++++--- packages/runtime/src/scr_stream.h | 3 ++ tests/corpus/6468-node-stdio-writable-slot.ts | 49 +++++++++++++++++++ .../6468-node-stdio-writable-slot.ts.json | 1 + 11 files changed, 114 insertions(+), 15 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6468-node-stdio-writable-slot.ts.json create mode 100644 tests/corpus/6468-node-stdio-writable-slot.ts create mode 100644 tests/harness/corpus-costs/6468-node-stdio-writable-slot.ts.json diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 3885e0fef..4e39d9e42 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -6736,12 +6736,12 @@ declare module "stream" { readonly closed: boolean; readonly destroyed: boolean; readonly errored: Error | null; - on(event: "drain" | "finish" | "close", listener: () => void): void; - on(event: "error", listener: (err: Error) => void): void; + on(event: "drain" | "finish" | "close", listener: () => void): this; + on(event: "error", listener: (err: Error) => void): this; on(event: "pipe" | "unpipe", listener: (src: Readable) => void): this; on(event: string, listener: (...args: any[]) => void): this; - once(event: "drain" | "finish" | "close", listener: () => void): void; - once(event: "error", listener: (err: Error) => void): void; + once(event: "drain" | "finish" | "close", listener: () => void): this; + once(event: "error", listener: (err: Error) => void): this; once(event: "pipe" | "unpipe", listener: (src: Readable) => void): this; once(event: string, listener: (...args: any[]) => void): this; addListener(event: "drain" | "finish" | "close", listener: () => void): this; diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 4602a2bdd..d38379bf0 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -1106,6 +1106,7 @@ export const LIB_FN_SYMS: Record = { "readable.opFind": "scr_stream_op_find", "readable.opReduce": "scr_stream_op_reduce", "readable.pipe": "scr_stream_pipe", + "readable.pipeGeneral": "scr_stream_pipe_general", "writable.cork": "scr_stream_cork", "writable.uncork": "scr_stream_uncork", "stream.destroyErr": "scr_stream_destroy", @@ -1588,6 +1589,7 @@ export const USES_TIMERS_LIB_FNS = new Set([ "readable.opReduce", "readable.resume", "readable.pipe", + "readable.pipeGeneral", "readable.unpipe", "writable.write", "writable.writeStr", diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index 51c86fe39..88ba1f5b8 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -3371,6 +3371,16 @@ function pipeIntoStdio( }; } +/** The pipe() libCall for a destination of type `dst`. Under the general + * stream representation a Writable slot can hold the converted + * process.stdout / process.stderr, which a pipe never ends (as in Node), so + * the pipe takes readable.pipeGeneral, which checks for them. */ +function generalPipe(lowerer: Lowerer, dst: IrType): "readable.pipe" | "readable.pipeGeneral" { + return lowerer.generalNodeStreams && dst.kind === "object" && dst.className === "%Writable" + ? "readable.pipeGeneral" + : "readable.pipe"; +} + /** `readable.pipe(untyped)`: a checked-dynamic destination unwraps a boxed * native stream at run time (stream.unboxDyn; other values throw the * not-supported Error), and pipe() answers the destination value itself. */ @@ -3394,7 +3404,7 @@ function pipeIntoDyn( kind: "exprStmt", expr: { kind: "libCall", - fn: "readable.pipe", + fn: lowerer.generalNodeStreams ? "readable.pipeGeneral" : "readable.pipe", args: [ { kind: "varRef", localId: source.id, type: receiverValue.type, loc }, { @@ -3691,7 +3701,7 @@ export function lowerStreamMethodCall( const receiver = lowerer.lowerExpr(access.expression); return { kind: "libCall", - fn: "readable.pipe", + fn: generalPipe(lowerer, dst.type), args: [receiver, dst, end], type: dst.type, loc, diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 1c390bbe4..11a292a2e 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -326,6 +326,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "stream.onDyn", "readable.resume", "readable.pipe", + "readable.pipeGeneral", "readable.unpipe", "writable.write", "writable.writeStr", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 597076cb1..82ecf461d 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -3612,7 +3612,9 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * returns the below-hwm answer. readable.read: (recv, size — -1 for * absent) → Buffer|null union. pause/resume return recv +1 (`this`); * isPaused answers the flag. readable.pipe: (recv, dst, end) → dst +1, - * fires 'pipe' on dst; readable.unpipe (recv[, dst]) → recv +1. + * fires 'pipe' on dst; readable.pipeGeneral: the same, with `end` off + * when dst is the converted process.stdout / process.stderr; + * readable.unpipe (recv[, dst]) → recv +1. * writable.write/writeStr: (recv, chunk[, cb]) → below-hwm bool (cb * MOVES when present, called after the user write completes). * writable.end: (recv, flags[, chunk][, cb]) → recv +1. cork/uncork are @@ -3810,6 +3812,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "readable.resume": { argTypes: [null], result: VOID }, "readable.isPaused": { argTypes: [null], result: BOOL }, "readable.pipe": { argTypes: [null, null, BOOL], result: VOID }, + "readable.pipeGeneral": { argTypes: [null, null, BOOL], result: VOID }, "readable.unpipe": { argTypes: [null], result: VOID }, "readable.flowing": { argTypes: [null], result: VOID }, "writable.write": { argTypes: [null, BYTES_U8], result: BOOL }, diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index 63078ae4a..742787d98 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -5729,9 +5729,9 @@ function validateFunction( } return true; } - if (e.fn === "readable.pipe") { + if (e.fn === "readable.pipe" || e.fn === "readable.pipeGeneral") { if (!isStreamObject(e.args[1]?.type) || !typeEquals(e.type, e.args[1]!.type)) { - err(`libCall readable.pipe must return its destination's type`, e.loc); + err(`libCall ${e.fn} must return its destination's type`, e.loc); } return true; } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6468-node-stdio-writable-slot.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6468-node-stdio-writable-slot.ts.json new file mode 100644 index 000000000..baf428dee --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6468-node-stdio-writable-slot.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6468-node-stdio-writable-slot.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index 1c5e339a0..7c7b2279c 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -6665,18 +6665,42 @@ ScrStream *scr_stream_child_stdio(void *child, const char *key, size_t key_len) * stream.stdioWritable libCall): a Writable whose _write hands each chunk * to the descriptor through process.stdout.write's synchronous path and * completes at once, so ordering against console output and direct writes - * is unchanged. The closure keeps the fd as given (1 or 2). */ + * is unchanged. The closure keeps the fd as given (1 or 2). Each thread + * keeps one per descriptor, so every conversion of process.stdout answers + * the same stream, as Node's process.stdout is one object: listeners, + * writable state and identity are shared. The cache is released at exit. */ +static SCR_TL ScrStream *scr_stream_stdio_writables[2]; static void scr_stream_stdio_write(ScrClosure *cb, ScrStream *s, ScrBytes *chunk) { int fd = (int)scr_box_get_f64(cb->caps[0]); (void)scr_stdio_write(fd == 2 ? 2 : 1, chunk->data, chunk->len * scr_bytes_elem_size(chunk->elem)); scr_stream_write_done(s, NULL); } +static void scr_stream_stdio_writables_free(void) { + for (int i = 0; i < 2; i++) { + ScrStream *s = scr_stream_stdio_writables[i]; + scr_stream_stdio_writables[i] = NULL; + if (s) scr_stream_release(s); + } +} ScrStream *scr_stream_stdio_writable(double fd) { - ScrClosure *write = scr_closure_new((void *)scr_stream_stdio_write, 1); - write->caps[0] = scr_box_new(SCR_BOX_F64); - scr_box_set_f64(write->caps[0], fd); - return scr_stream_new_writable(-1, true, true, write, scr_stream_stdio_write, - NULL, NULL, NULL, NULL); + int i = fd == 2 ? 1 : 0; + if (scr_stream_stdio_writables[i] == NULL) { + if (scr_stream_stdio_writables[1 - i] == NULL) scr_atexit(scr_stream_stdio_writables_free); + ScrClosure *write = scr_closure_new((void *)scr_stream_stdio_write, 1); + write->caps[0] = scr_box_new(SCR_BOX_F64); + scr_box_set_f64(write->caps[0], i ? 2 : 1); + scr_stream_stdio_writables[i] = scr_stream_new_writable(-1, true, true, write, + scr_stream_stdio_write, NULL, NULL, NULL, NULL); + } + return scr_stream_retain(scr_stream_stdio_writables[i]); +} + +/* readable.pipe() into a Writable slot under the general representation + * (the readable.pipeGeneral libCall): Node never ends process.stdout or + * process.stderr from a pipe, so their converted Writable keeps `end` off. */ +ScrStream *scr_stream_pipe_general(ScrStream *src, ScrStream *dst, bool end) { + if (dst == scr_stream_stdio_writables[0] || dst == scr_stream_stdio_writables[1]) end = false; + return scr_stream_pipe(src, dst, end); } /* A pipeline() stage that arrives as a checked-dynamic value (the diff --git a/packages/runtime/src/scr_stream.h b/packages/runtime/src/scr_stream.h index 63ed0c28a..69da3dc0e 100644 --- a/packages/runtime/src/scr_stream.h +++ b/packages/runtime/src/scr_stream.h @@ -130,6 +130,9 @@ ScrStream *scr_stream_new_writable_dyn(struct ScrDyn *opts); * Writable (fd 1 or 2). */ ScrStream *scr_stream_child_stdio(void *child, const char *key, size_t key_len); ScrStream *scr_stream_stdio_writable(double fd); +/* readable.pipe() under the general representation: a converted + * process.stdout / process.stderr destination is never ended (dst +1). */ +ScrStream *scr_stream_pipe_general(ScrStream *src, ScrStream *dst, bool end); /* A boxed native stream out of a checked-dynamic pipeline stage (+1), or * NULL with `message` thrown as the not-supported Error. */ ScrStream *scr_stream_unbox_dyn(const struct ScrDyn *value, const ScrStr *message); diff --git a/tests/corpus/6468-node-stdio-writable-slot.ts b/tests/corpus/6468-node-stdio-writable-slot.ts new file mode 100644 index 000000000..a326344d1 --- /dev/null +++ b/tests/corpus/6468-node-stdio-writable-slot.ts @@ -0,0 +1,49 @@ +// process.stdout and process.stderr in NodeJS.WritableStream slots of a +// program that also passes other streams there: every slot holds the same +// stream object, a pipe through such a slot leaves the process stream +// open, and Writable's listener methods return the stream for chaining. +import { Readable, Writable } from "node:stream"; + +class Sink extends Writable { + _write(_chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void): void { + callback(); + } +} + +function same(a: NodeJS.WritableStream, b: NodeJS.WritableStream): boolean { + return a === b; +} + +function pipeInto(dst: NodeJS.WritableStream, parts: string[]): Promise { + return new Promise((resolve) => { + const src = Readable.from(parts); + src.on("end", () => resolve()); + src.pipe(dst); + }); +} + +function write(dst: NodeJS.WritableStream, text: string): boolean { + return dst.write(text); +} + +async function main(): Promise { + console.log("stdout same", same(process.stdout, process.stdout)); + console.log("stderr same", same(process.stderr, process.stderr)); + console.log("stdout and stderr", same(process.stdout, process.stderr)); + console.log("sink and stdout", same(new Sink(), process.stdout)); + + await pipeInto(process.stdout, ["piped ", "through ", "a slot\n"]); + // The pipe did not end process.stdout: writes through a slot still work. + console.log("write after pipe", write(process.stdout, "still open\n")); + await pipeInto(process.stderr, ["piped to stderr\n"]); + write(process.stderr, "stderr still open\n"); + + // Writable's listener methods return the stream. + const sink = new Sink(); + await new Promise((resolve) => { + sink.on("finish", () => resolve()).end("done"); + }); + console.log("sink finished", sink.writableFinished); +} + +void main(); diff --git a/tests/harness/corpus-costs/6468-node-stdio-writable-slot.ts.json b/tests/harness/corpus-costs/6468-node-stdio-writable-slot.ts.json new file mode 100644 index 000000000..3fafdfc4b --- /dev/null +++ b/tests/harness/corpus-costs/6468-node-stdio-writable-slot.ts.json @@ -0,0 +1 @@ +{ "plain": 3000, "san": 3500 } From da0f6b642ba11624a37d4366589141454d47a3da Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 09:52:32 -0500 Subject: [PATCH 30/39] Merge main --- docs/content/docs/limitations.mdx | 4 + .../limitations/builtin-apis/exit-status.mdx | 3 +- .../builtin-apis/object-freezing.mdx | 5 + .../limitations/builtin-apis/test-mocks.mdx | 3 +- .../language-features/function-values.mdx | 2 +- .../limitations/module-path-globals.mdx | 4 + .../null-and-optional-values.mdx | 3 +- .../generated/node-v24-backlog.json | 28 +- .../generated/node-v24-internal.json | 36 +- internal/compatibility/static-support.json | 8 +- .../ambient/scriptc-node-fallback.d.ts | 7 + .../compiler/src/backend/llvm/byte-numbers.ts | 7 +- .../compiler/src/backend/llvm/bytes-alias.ts | 23 + .../backend/llvm/bytes-loop-versions.test.ts | 278 ++++++ .../src/backend/llvm/bytes-loop-versions.ts | 578 ++++++++++++ .../src/backend/llvm/counted-loops.ts | 51 ++ .../src/backend/llvm/emit-function.ts | 5 + .../src/backend/llvm/emit-statements.ts | 89 +- packages/compiler/src/backend/llvm/emitter.ts | 45 + .../compiler/src/backend/llvm/expr-bytes.ts | 64 +- .../src/backend/llvm/expr-callbacks.ts | 17 +- .../src/backend/llvm/expr-containers.ts | 2 +- .../src/backend/llvm/expr-primitives.ts | 2 +- .../src/backend/llvm/expr-stream-bridges.ts | 34 +- .../compiler/src/backend/llvm/lib-shared.ts | 10 + .../compiler/src/backend/llvm/receivers.ts | 2 +- .../src/backend/stack-observations.test.ts | 35 + .../src/backend/stack-observations.ts | 35 +- .../src/frontend/helper-tokens.test.ts | 8 +- .../compiler/src/frontend/helper-tokens.ts | 15 +- .../compiler/src/frontend/input-tracker.ts | 34 +- .../frontend/lowering/assertion-members.ts | 168 ++++ .../src/frontend/lowering/builtin-calls.ts | 5 + .../lowering/builtins/callable-aliases.ts | 8 +- .../src/frontend/lowering/builtins/ipc.ts | 58 +- .../src/frontend/lowering/builtins/process.ts | 213 ++++- .../frontend/lowering/builtins/promises.ts | 3 + .../lowering/builtins/promisify-callback.ts | 377 ++++++++ .../src/frontend/lowering/call-signatures.ts | 26 + .../src/frontend/lowering/class-attributes.ts | 440 +++++++++ .../frontend/lowering/class-descriptors.ts | 2 +- .../lowering/class-dynamic-dispatch.ts | 105 +++ .../src/frontend/lowering/class-protocols.ts | 6 - .../lowering/coercions/function-adapters.ts | 137 ++- .../lowering/expressions/hosted-narrowing.ts | 157 ++++ .../lowering/expressions/identifiers.ts | 22 +- .../lowering/expressions/narrowing.ts | 35 + .../lowering/expressions/relational.ts | 89 +- .../frontend/lowering/expressions/typeof.ts | 36 +- .../frontend/lowering/expressions/updates.ts | 2 + .../frontend/lowering/key-order-witness.ts | 20 +- .../src/frontend/lowering/lower-calls.ts | 18 + .../src/frontend/lowering/lower-classes.ts | 7 +- .../src/frontend/lowering/lower-inspect.ts | 11 +- .../src/frontend/lowering/lower-mock.ts | 75 +- .../src/frontend/lowering/lower-stmts.ts | 64 +- .../src/frontend/lowering/lower-stream.ts | 24 +- .../compiler/src/frontend/lowering/lowerer.ts | 13 + .../src/frontend/lowering/strict-mode.ts | 34 + .../src/frontend/lowering/surfaces.ts | 6 +- packages/compiler/src/frontend/mock-shapes.ts | 19 +- .../npm-static-bundled-chunks.test.ts | 300 ++++++ .../src/frontend/npm-static-bundled-chunks.ts | 858 ++++++++++++++++++ .../src/frontend/npm-static-rewrite-host.ts | 12 +- .../src/frontend/npm-static-rewrite-syntax.ts | 236 +++-- packages/compiler/src/frontend/npm-static.ts | 65 +- packages/compiler/src/frontend/pipeline.ts | 11 + packages/compiler/src/frontend/program.ts | 225 ++++- packages/compiler/src/frontend/services.ts | 20 +- packages/compiler/src/frontend/type-mapper.ts | 148 ++- packages/compiler/src/ir/builtin-effects.ts | 4 + .../compiler/src/ir/builtin-signatures.ts | 26 + packages/compiler/src/ir/ir.ts | 40 +- packages/compiler/src/ir/runtime-features.ts | 1 + packages/compiler/src/ir/validate.ts | 1 + packages/compiler/surface-manifest.json | 4 +- .../compiler/test/class-attributes.test.ts | 84 ++ .../test/native-class-descriptors.test.ts | 38 +- .../5467-typed-array-loop-versions.ts.json | 6 + .../5468-typed-array-loop-aliasing.ts.json | 6 + ...d-array-loop-initializer-rebinding.ts.json | 6 + .../5816-fixed-into-unknown-rest.ts.json | 6 + .../5916-dyn-error-stack-property.ts.json | 6 + .../6004-class-instance-integrity.ts.json | 6 + ...5-class-instance-integrity-sloppy.cjs.json | 6 + ...4-protocol-subinterface-assertions.ts.json | 6 - .../6398-conditional-fixed-arity.ts.json | 6 + .../6400-dyn-error-stack-property-js.js.json | 6 + .../6401-dyn-error-own-property-names.ts.json | 6 + ...02-dyn-error-own-property-names-js.js.json | 6 + .../corpus/6420-process-send-presence.ts.json | 6 + .../main.ts.json | 6 + .../corpus/6422-process-exitcode-read.ts.json | 6 + .../6423-process-exitcode-default.ts.json | 6 + .../6424-process-exit-keeps-exitcode.ts.json | 6 + .../6425-stream-hook-wider-chunk.ts.json | 6 + .../6426-promise-race-void-entry.ts.json | 6 + .../6427-http-request-options-type.ts.json | 6 + .../6428-promisify-callback-functions.ts.json | 6 + .../tests/corpus/6429-esm-js-dirname.mjs.json | 6 + .../6445-rest-function-fixed-slot.ts.json | 6 + ...6-rest-function-nested-declaration.ts.json | 6 + .../6460-in-union-optional-slots.ts.json | 6 + ...1-predicate-intersection-narrowing.ts.json | 6 + .../6462-assertion-attached-members.ts.json | 6 + .../6480-catch-typeof-untyped-throws.ts.json | 6 + .../boot-path-node-surface-fences.ts.json | 6 + .../class-field-accessor-descriptor.ts.json | 6 + .../promisify-callback-functions.ts.json | 6 + .../node-types/stream-subclass-hooks.ts.json | 6 + .../cases/2558-bundled-chunks/main.ts.json | 6 + .../npm/cases/2559-cjs-cycle/main.ts.json | 6 + .../2560-cjs-cycle-partner-first/main.ts.json | 6 + .../2561-cjs-cycle-early-read/main.ts.json | 6 + .../npm/cases/2562-subpath-leaf/main.ts.json | 6 + .../2564-chunk-helper-shadowing/main.ts.json | 6 + .../2565-chunk-shared-function/main.ts.json | 6 + .../2566-cjs-cycle-indirect-call/main.ts.json | 6 + .../main.ts.json | 6 + packages/runtime/src/scr_alloc.c | 102 ++- packages/runtime/src/scr_alloc.test.c | 87 +- packages/runtime/src/scr_async.c | 6 + packages/runtime/src/scr_child.c | 1 + packages/runtime/src/scr_child.h | 3 + packages/runtime/src/scr_dyn.h | 10 + packages/runtime/src/scr_error.c | 6 + packages/runtime/src/scr_error.h | 3 + packages/runtime/src/scr_json.c | 353 ++++++- packages/runtime/src/scr_lib.c | 13 + packages/runtime/src/scr_lib.h | 5 + packages/runtime/src/scr_message.c | 6 + packages/runtime/src/scr_rc.h | 4 + .../corpus/5467-typed-array-loop-versions.ts | 298 ++++++ .../corpus/5468-typed-array-loop-aliasing.ts | 107 +++ ...-typed-array-loop-initializer-rebinding.ts | 46 + tests/corpus/5816-fixed-into-unknown-rest.ts | 39 + tests/corpus/5916-dyn-error-stack-property.ts | 147 +++ tests/corpus/6004-class-instance-integrity.ts | 169 ++++ .../6005-class-instance-integrity-sloppy.cjs | 40 + .../6064-protocol-subinterface-assertions.ts | 80 -- tests/corpus/6398-conditional-fixed-arity.ts | 40 + .../6400-dyn-error-stack-property-js.js | 148 +++ .../6401-dyn-error-own-property-names.ts | 44 + .../6402-dyn-error-own-property-names-js.js | 44 + tests/corpus/6420-process-send-presence.ts | 24 + .../6421-process-send-presence-fork/main.ts | 13 + .../6421-process-send-presence-fork/worker.ts | 6 + tests/corpus/6422-process-exitcode-read.ts | 22 + tests/corpus/6423-process-exitcode-default.ts | 10 + .../6424-process-exit-keeps-exitcode.ts | 5 + tests/corpus/6425-stream-hook-wider-chunk.ts | 46 + tests/corpus/6426-promise-race-void-entry.ts | 31 + .../corpus/6427-http-request-options-type.ts | 10 + .../6428-promisify-callback-functions.ts | 80 ++ tests/corpus/6429-esm-js-dirname.mjs | 15 + tests/corpus/6445-rest-function-fixed-slot.ts | 49 + .../6446-rest-function-nested-declaration.ts | 26 + tests/corpus/6460-in-union-optional-slots.ts | 53 ++ .../6461-predicate-intersection-narrowing.ts | 70 ++ .../corpus/6462-assertion-attached-members.ts | 58 ++ .../6480-catch-typeof-untyped-throws.ts | 40 + .../boot-path-node-surface-fences.ts | 23 + .../class-field-accessor-descriptor.ts | 14 + tests/diagnostics/maybe-promise-fences.ts | 5 - tests/diagnostics/mock-fences.ts | 12 +- tests/fixtures/esm-path-globals/lib/helper.ts | 2 + tests/fixtures/esm-path-globals/main.ts | 12 + .../node-test/cases/mock-fn-default.ts | 72 ++ .../promisify-callback-functions.ts | 67 ++ .../node-types/stream-subclass-hooks.ts | 46 + .../npm/cases/2558-bundled-chunks/main.ts | 29 + .../fixtures/npm/cases/2559-cjs-cycle/main.ts | 11 + .../2560-cjs-cycle-partner-first/main.ts | 11 + .../cases/2561-cjs-cycle-early-read/main.ts | 6 + .../npm/cases/2562-subpath-leaf/main.ts | 10 + .../cases/2564-chunk-helper-shadowing/main.ts | 7 + .../cases/2565-chunk-shared-function/main.ts | 7 + .../2566-cjs-cycle-indirect-call/main.ts | 7 + .../2571-cjs-cycle-stored-function/main.ts | 8 + .../npm/node_modules/gtchunk/dist/index.d.ts | 4 + .../npm/node_modules/gtchunk/dist/index.js | 132 +++ .../npm/node_modules/gtchunk/package.json | 10 + .../node_modules/gtchunk17/dist/index.d.ts | 4 + .../npm/node_modules/gtchunk17/dist/index.js | 132 +++ .../npm/node_modules/gtchunk17/package.json | 10 + .../gtchunkshadow/dist/index.d.ts | 2 + .../node_modules/gtchunkshadow/dist/index.js | 52 ++ .../node_modules/gtchunkshadow/package.json | 7 + .../gtchunkshared/dist/index.d.ts | 2 + .../node_modules/gtchunkshared/dist/index.js | 56 ++ .../node_modules/gtchunkshared/package.json | 7 + .../node_modules/gtchunkws/dist/index.d.ts | 4 + .../npm/node_modules/gtchunkws/dist/index.js | 1 + .../npm/node_modules/gtchunkws/package.json | 10 + .../npm/node_modules/gtcjsdist/dist/index.cjs | 43 + .../node_modules/gtcjsdist/dist/index.d.cts | 1 + .../npm/node_modules/gtcjsdist/package.json | 11 + .../npm/node_modules/gtcycle/dist/append.d.ts | 1 + .../npm/node_modules/gtcycle/dist/append.js | 30 + .../npm/node_modules/gtcycle/dist/index.d.ts | 4 + .../npm/node_modules/gtcycle/dist/index.js | 44 + .../npm/node_modules/gtcycle/dist/merge.d.ts | 1 + .../npm/node_modules/gtcycle/dist/merge.js | 30 + .../npm/node_modules/gtcycle/package.json | 7 + .../node_modules/gtcyclealias/dist/index.d.ts | 3 + .../node_modules/gtcyclealias/dist/index.js | 37 + .../node_modules/gtcyclealias/dist/reader.js | 34 + .../node_modules/gtcyclealias/package.json | 7 + .../node_modules/gtcyclebad/dist/index.d.ts | 2 + .../npm/node_modules/gtcyclebad/dist/index.js | 33 + .../node_modules/gtcyclebad/dist/reader.js | 33 + .../npm/node_modules/gtcyclebad/package.json | 7 + .../node_modules/gtcyclebox/dist/index.d.ts | 3 + .../npm/node_modules/gtcyclebox/dist/index.js | 37 + .../node_modules/gtcyclebox/dist/reader.js | 34 + .../npm/node_modules/gtcyclebox/package.json | 7 + .../node_modules/gtcyclecall/dist/index.d.ts | 3 + .../node_modules/gtcyclecall/dist/index.js | 37 + .../node_modules/gtcyclecall/dist/reader.js | 33 + .../npm/node_modules/gtcyclecall/package.json | 7 + .../npm/node_modules/gtsubpath/dist/data.d.ts | 2 + .../npm/node_modules/gtsubpath/dist/data.js | 6 + .../npm/node_modules/gtsubpath/dist/detect.js | 11 + .../node_modules/gtsubpath/dist/index.d.ts | 6 + .../npm/node_modules/gtsubpath/dist/index.js | 5 + .../npm/node_modules/gtsubpath/package.json | 10 + .../boot-path-node-surface-fences.ts.txt | 35 + .../class-field-accessor-descriptor.ts.txt | 6 + .../__snapshots__/maybe-promise-fences.ts.txt | 9 +- .../harness/__snapshots__/mock-fences.ts.txt | 60 +- tests/harness/corpus-costs.json | 12 +- .../5816-fixed-into-unknown-rest.ts.json | 1 + .../5916-dyn-error-stack-property.ts.json | 1 + ...4-protocol-subinterface-assertions.ts.json | 1 - ...0-variadic-wrapper-arguments-apply.ts.json | 1 + .../6381-variadic-wrapper-async.ts.json | 1 + ...6382-variadic-wrapper-methods-this.ts.json | 1 + .../6383-variadic-wrapper-rest-tuple.ts.json | 1 + .../6384-variadic-wrapper-nested.ts.json | 1 + .../6390-catch-binding-predicate.ts.json | 1 + .../6391-nullish-function-default.ts.json | 1 + ...6392-optional-chain-protocol-calls.ts.json | 1 + .../6393-function-types-any-params.ts.json | 1 + .../6394-in-key-error-subclasses.ts.json | 1 + .../6395-generic-object-entries.ts.json | 1 + .../6396-generic-any-instantiation.ts.json | 1 + .../6397-event-loop-metrics.ts.json | 1 + .../6398-conditional-fixed-arity.ts.json | 1 + .../6400-dyn-error-stack-property-js.js.json | 1 + .../6401-dyn-error-own-property-names.ts.json | 1 + ...02-dyn-error-own-property-names-js.js.json | 1 + .../6414-catch-values-roundtrip.ts.json | 1 + .../6445-rest-function-fixed-slot.ts.json | 1 + ...6-rest-function-nested-declaration.ts.json | 1 + ...468-generic-unknown-record-entries.ts.json | 1 + tests/harness/esm-path-globals.test.ts | 38 + tests/harness/npm-cases.ts | 4 +- tests/harness/npm-static.test.ts | 136 ++- tests/harness/project-config.test.ts | 36 + 259 files changed, 9524 insertions(+), 442 deletions(-) create mode 100644 docs/content/limitations/module-path-globals.mdx create mode 100644 packages/compiler/src/backend/llvm/bytes-alias.ts create mode 100644 packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts create mode 100644 packages/compiler/src/backend/llvm/bytes-loop-versions.ts create mode 100644 packages/compiler/src/frontend/lowering/assertion-members.ts create mode 100644 packages/compiler/src/frontend/lowering/builtins/promisify-callback.ts create mode 100644 packages/compiler/src/frontend/lowering/class-attributes.ts create mode 100644 packages/compiler/src/frontend/lowering/expressions/hosted-narrowing.ts create mode 100644 packages/compiler/src/frontend/lowering/strict-mode.ts create mode 100644 packages/compiler/src/frontend/npm-static-bundled-chunks.test.ts create mode 100644 packages/compiler/src/frontend/npm-static-bundled-chunks.ts create mode 100644 packages/compiler/test/class-attributes.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5467-typed-array-loop-versions.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5468-typed-array-loop-aliasing.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5469-typed-array-loop-initializer-rebinding.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5816-fixed-into-unknown-rest.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5916-dyn-error-stack-property.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6004-class-instance-integrity.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6005-class-instance-integrity-sloppy.cjs.json delete mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6064-protocol-subinterface-assertions.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6398-conditional-fixed-arity.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6400-dyn-error-stack-property-js.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6401-dyn-error-own-property-names.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6402-dyn-error-own-property-names-js.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6420-process-send-presence.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6421-process-send-presence-fork/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6422-process-exitcode-read.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6423-process-exitcode-default.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6424-process-exit-keeps-exitcode.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6425-stream-hook-wider-chunk.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6426-promise-race-void-entry.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6427-http-request-options-type.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6428-promisify-callback-functions.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6429-esm-js-dirname.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6445-rest-function-fixed-slot.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6446-rest-function-nested-declaration.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6460-in-union-optional-slots.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6461-predicate-intersection-narrowing.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6462-assertion-attached-members.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6480-catch-typeof-untyped-throws.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/boot-path-node-surface-fences.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/class-field-accessor-descriptor.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-callback-functions.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/stream-subclass-hooks.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2558-bundled-chunks/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2559-cjs-cycle/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2560-cjs-cycle-partner-first/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2561-cjs-cycle-early-read/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2562-subpath-leaf/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2564-chunk-helper-shadowing/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2565-chunk-shared-function/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2566-cjs-cycle-indirect-call/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2571-cjs-cycle-stored-function/main.ts.json create mode 100644 tests/corpus/5467-typed-array-loop-versions.ts create mode 100644 tests/corpus/5468-typed-array-loop-aliasing.ts create mode 100644 tests/corpus/5469-typed-array-loop-initializer-rebinding.ts create mode 100644 tests/corpus/5816-fixed-into-unknown-rest.ts create mode 100644 tests/corpus/5916-dyn-error-stack-property.ts create mode 100644 tests/corpus/6004-class-instance-integrity.ts create mode 100644 tests/corpus/6005-class-instance-integrity-sloppy.cjs delete mode 100644 tests/corpus/6064-protocol-subinterface-assertions.ts create mode 100644 tests/corpus/6398-conditional-fixed-arity.ts create mode 100644 tests/corpus/6400-dyn-error-stack-property-js.js create mode 100644 tests/corpus/6401-dyn-error-own-property-names.ts create mode 100644 tests/corpus/6402-dyn-error-own-property-names-js.js create mode 100644 tests/corpus/6420-process-send-presence.ts create mode 100644 tests/corpus/6421-process-send-presence-fork/main.ts create mode 100644 tests/corpus/6421-process-send-presence-fork/worker.ts create mode 100644 tests/corpus/6422-process-exitcode-read.ts create mode 100644 tests/corpus/6423-process-exitcode-default.ts create mode 100644 tests/corpus/6424-process-exit-keeps-exitcode.ts create mode 100644 tests/corpus/6425-stream-hook-wider-chunk.ts create mode 100644 tests/corpus/6426-promise-race-void-entry.ts create mode 100644 tests/corpus/6427-http-request-options-type.ts create mode 100644 tests/corpus/6428-promisify-callback-functions.ts create mode 100644 tests/corpus/6429-esm-js-dirname.mjs create mode 100644 tests/corpus/6445-rest-function-fixed-slot.ts create mode 100644 tests/corpus/6446-rest-function-nested-declaration.ts create mode 100644 tests/corpus/6460-in-union-optional-slots.ts create mode 100644 tests/corpus/6461-predicate-intersection-narrowing.ts create mode 100644 tests/corpus/6462-assertion-attached-members.ts create mode 100644 tests/corpus/6480-catch-typeof-untyped-throws.ts create mode 100644 tests/diagnostics/boot-path-node-surface-fences.ts create mode 100644 tests/diagnostics/class-field-accessor-descriptor.ts create mode 100644 tests/fixtures/esm-path-globals/lib/helper.ts create mode 100644 tests/fixtures/esm-path-globals/main.ts create mode 100644 tests/fixtures/node-test/cases/mock-fn-default.ts create mode 100644 tests/fixtures/node-types/promisify-callback-functions.ts create mode 100644 tests/fixtures/node-types/stream-subclass-hooks.ts create mode 100644 tests/fixtures/npm/cases/2558-bundled-chunks/main.ts create mode 100644 tests/fixtures/npm/cases/2559-cjs-cycle/main.ts create mode 100644 tests/fixtures/npm/cases/2560-cjs-cycle-partner-first/main.ts create mode 100644 tests/fixtures/npm/cases/2561-cjs-cycle-early-read/main.ts create mode 100644 tests/fixtures/npm/cases/2562-subpath-leaf/main.ts create mode 100644 tests/fixtures/npm/cases/2564-chunk-helper-shadowing/main.ts create mode 100644 tests/fixtures/npm/cases/2565-chunk-shared-function/main.ts create mode 100644 tests/fixtures/npm/cases/2566-cjs-cycle-indirect-call/main.ts create mode 100644 tests/fixtures/npm/cases/2571-cjs-cycle-stored-function/main.ts create mode 100644 tests/fixtures/npm/node_modules/gtchunk/dist/index.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtchunk/dist/index.js create mode 100644 tests/fixtures/npm/node_modules/gtchunk/package.json create mode 100644 tests/fixtures/npm/node_modules/gtchunk17/dist/index.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtchunk17/dist/index.js create mode 100644 tests/fixtures/npm/node_modules/gtchunk17/package.json create mode 100644 tests/fixtures/npm/node_modules/gtchunkshadow/dist/index.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtchunkshadow/dist/index.js create mode 100644 tests/fixtures/npm/node_modules/gtchunkshadow/package.json create mode 100644 tests/fixtures/npm/node_modules/gtchunkshared/dist/index.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtchunkshared/dist/index.js create mode 100644 tests/fixtures/npm/node_modules/gtchunkshared/package.json create mode 100644 tests/fixtures/npm/node_modules/gtchunkws/dist/index.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtchunkws/dist/index.js create mode 100644 tests/fixtures/npm/node_modules/gtchunkws/package.json create mode 100644 tests/fixtures/npm/node_modules/gtcjsdist/dist/index.cjs create mode 100644 tests/fixtures/npm/node_modules/gtcjsdist/dist/index.d.cts create mode 100644 tests/fixtures/npm/node_modules/gtcjsdist/package.json create mode 100644 tests/fixtures/npm/node_modules/gtcycle/dist/append.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtcycle/dist/append.js create mode 100644 tests/fixtures/npm/node_modules/gtcycle/dist/index.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtcycle/dist/index.js create mode 100644 tests/fixtures/npm/node_modules/gtcycle/dist/merge.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtcycle/dist/merge.js create mode 100644 tests/fixtures/npm/node_modules/gtcycle/package.json create mode 100644 tests/fixtures/npm/node_modules/gtcyclealias/dist/index.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtcyclealias/dist/index.js create mode 100644 tests/fixtures/npm/node_modules/gtcyclealias/dist/reader.js create mode 100644 tests/fixtures/npm/node_modules/gtcyclealias/package.json create mode 100644 tests/fixtures/npm/node_modules/gtcyclebad/dist/index.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtcyclebad/dist/index.js create mode 100644 tests/fixtures/npm/node_modules/gtcyclebad/dist/reader.js create mode 100644 tests/fixtures/npm/node_modules/gtcyclebad/package.json create mode 100644 tests/fixtures/npm/node_modules/gtcyclebox/dist/index.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtcyclebox/dist/index.js create mode 100644 tests/fixtures/npm/node_modules/gtcyclebox/dist/reader.js create mode 100644 tests/fixtures/npm/node_modules/gtcyclebox/package.json create mode 100644 tests/fixtures/npm/node_modules/gtcyclecall/dist/index.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtcyclecall/dist/index.js create mode 100644 tests/fixtures/npm/node_modules/gtcyclecall/dist/reader.js create mode 100644 tests/fixtures/npm/node_modules/gtcyclecall/package.json create mode 100644 tests/fixtures/npm/node_modules/gtsubpath/dist/data.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtsubpath/dist/data.js create mode 100644 tests/fixtures/npm/node_modules/gtsubpath/dist/detect.js create mode 100644 tests/fixtures/npm/node_modules/gtsubpath/dist/index.d.ts create mode 100644 tests/fixtures/npm/node_modules/gtsubpath/dist/index.js create mode 100644 tests/fixtures/npm/node_modules/gtsubpath/package.json create mode 100644 tests/harness/__snapshots__/boot-path-node-surface-fences.ts.txt create mode 100644 tests/harness/__snapshots__/class-field-accessor-descriptor.ts.txt create mode 100644 tests/harness/corpus-costs/5816-fixed-into-unknown-rest.ts.json create mode 100644 tests/harness/corpus-costs/5916-dyn-error-stack-property.ts.json delete mode 100644 tests/harness/corpus-costs/6064-protocol-subinterface-assertions.ts.json create mode 100644 tests/harness/corpus-costs/6380-variadic-wrapper-arguments-apply.ts.json create mode 100644 tests/harness/corpus-costs/6381-variadic-wrapper-async.ts.json create mode 100644 tests/harness/corpus-costs/6382-variadic-wrapper-methods-this.ts.json create mode 100644 tests/harness/corpus-costs/6383-variadic-wrapper-rest-tuple.ts.json create mode 100644 tests/harness/corpus-costs/6384-variadic-wrapper-nested.ts.json create mode 100644 tests/harness/corpus-costs/6390-catch-binding-predicate.ts.json create mode 100644 tests/harness/corpus-costs/6391-nullish-function-default.ts.json create mode 100644 tests/harness/corpus-costs/6392-optional-chain-protocol-calls.ts.json create mode 100644 tests/harness/corpus-costs/6393-function-types-any-params.ts.json create mode 100644 tests/harness/corpus-costs/6394-in-key-error-subclasses.ts.json create mode 100644 tests/harness/corpus-costs/6395-generic-object-entries.ts.json create mode 100644 tests/harness/corpus-costs/6396-generic-any-instantiation.ts.json create mode 100644 tests/harness/corpus-costs/6397-event-loop-metrics.ts.json create mode 100644 tests/harness/corpus-costs/6398-conditional-fixed-arity.ts.json create mode 100644 tests/harness/corpus-costs/6400-dyn-error-stack-property-js.js.json create mode 100644 tests/harness/corpus-costs/6401-dyn-error-own-property-names.ts.json create mode 100644 tests/harness/corpus-costs/6402-dyn-error-own-property-names-js.js.json create mode 100644 tests/harness/corpus-costs/6414-catch-values-roundtrip.ts.json create mode 100644 tests/harness/corpus-costs/6445-rest-function-fixed-slot.ts.json create mode 100644 tests/harness/corpus-costs/6446-rest-function-nested-declaration.ts.json create mode 100644 tests/harness/corpus-costs/6468-generic-unknown-record-entries.ts.json create mode 100644 tests/harness/esm-path-globals.test.ts diff --git a/docs/content/docs/limitations.mdx b/docs/content/docs/limitations.mdx index d261b6385..c64c5cebd 100644 --- a/docs/content/docs/limitations.mdx +++ b/docs/content/docs/limitations.mdx @@ -228,6 +228,10 @@ title: "Limitations" ../limitations/process-arguments-and-errors.mdx +### Module path globals + +../limitations/module-path-globals.mdx + ## Runtime code evaluation diff --git a/docs/content/limitations/builtin-apis/exit-status.mdx b/docs/content/limitations/builtin-apis/exit-status.mdx index d9bb779db..3cdf10496 100644 --- a/docs/content/limitations/builtin-apis/exit-status.mdx +++ b/docs/content/limitations/builtin-apis/exit-status.mdx @@ -1,3 +1,4 @@ - **Exit status:** Numeric `process.exitCode = value` writes in statement position set the implicit exit status, which `process.exit()` uses when called without an argument. `process.exit(code)` and `process.exitCode` throw a `RangeError` (`ERR_OUT_OF_RANGE`) for a code that is not a safe integer, and convert other codes to int32, as Node does. - Reads, resets, and assignments used as values are unsupported. + Reading `process.exitCode` answers the assigned code, or `undefined` before any assignment; `process.exit(code)` assigns it before the `'exit'` listeners run. + Resets (`process.exitCode = undefined`) and assignments used as values are unsupported. diff --git a/docs/content/limitations/builtin-apis/object-freezing.mdx b/docs/content/limitations/builtin-apis/object-freezing.mdx index 9784cd715..38f0155c0 100644 --- a/docs/content/limitations/builtin-apis/object-freezing.mdx +++ b/docs/content/limitations/builtin-apis/object-freezing.mdx @@ -1,3 +1,8 @@ - **Object freezing:** `Object.freeze` and `Object.isFrozen` support plain checked dictionaries and primitives. Freezing is shallow and preserves accessors. Aliased typed records, arrays, proxies, and other native objects cannot be frozen. + Class instances support `Object.freeze`, `Object.seal`, `Object.preventExtensions`, `Object.isFrozen`, `Object.isSealed`, and `Object.isExtensible` when the static type of the argument names the class. + A write to a read-only field throws Node's `TypeError` in strict mode code and leaves the field unchanged in sloppy mode code. + `Object.defineProperty` with a string-literal key changes the value, `writable`, `enumerable`, and `configurable` attributes of a declared field; an object-literal accessor descriptor (`get` or `set`) for a declared field is refused at compile time with `SC2020`, and another accessor descriptor for a declared field throws `SC2020` when the call runs. + Freezing, sealing, or preventing extensions of a class instance held in an untyped value throws `SC2020`. + A JavaScript class field that is first created after its instance became non-extensible is added instead of throwing. diff --git a/docs/content/limitations/builtin-apis/test-mocks.mdx b/docs/content/limitations/builtin-apis/test-mocks.mdx index abfdb3657..903a873b9 100644 --- a/docs/content/limitations/builtin-apis/test-mocks.mdx +++ b/docs/content/limitations/builtin-apis/test-mocks.mdx @@ -3,7 +3,8 @@ Class instances, builtin objects, and object literals whose methods use `this` throw `SC2020`. Calls through the object record it as `this`, including calls of a method read off the object and called on its own, where Node records `undefined`. `object.method === mock` is `false`, because the field holds a wrapper of the mock. - `mock.fn()` without an original, `mock.getter`, `mock.setter`, `mock.property`, `mock.module` and mock options throw `SC2020`. + `mock.fn()` without an original returns `undefined` and records the arguments of each call, as in Node; with a function type whose return type does not include `undefined`, such as `mock.fn<() => number>()`, it throws `SC2020`. + `mock.getter`, `mock.setter`, `mock.property`, `mock.module` and mock options throw `SC2020`. - **Mock timers:** `mock.timers.enable`, `tick`, `runAll`, `reset`, `setTime` and `[Symbol.dispose]()` compile, on the module's `mock` and on `t.mock`, for the `setTimeout`, `setInterval`, `setImmediate`, `Date`, `scheduler.wait` and `AbortSignal.timeout` APIs. `enable()` takes no options or an object literal whose `apis`, when given, is an array literal. Options and `apis` lists that are not literals, and the `MockTimers` object used as a value, throw `SC2020`. diff --git a/docs/content/limitations/language-features/function-values.mdx b/docs/content/limitations/language-features/function-values.mdx index 88422c406..75229ff95 100644 --- a/docs/content/limitations/language-features/function-values.mdx +++ b/docs/content/limitations/language-features/function-values.mdx @@ -1,4 +1,4 @@ - **Function values:** Immutable aliases of overloaded program functions retain per-call overload resolution and identity. A function stored in a slot with a different signature remains the same function for equality, array searches, `length`, and own properties. - Typed rest-parameter functions can be stored and called indirectly. + Typed rest-parameter functions can be stored and called indirectly, including through a slot with fixed parameters, where the slot's arguments arrive in the rest array. Builtin function values have API-specific restrictions; see [Builtin function values](#builtin-function-values). diff --git a/docs/content/limitations/module-path-globals.mdx b/docs/content/limitations/module-path-globals.mdx new file mode 100644 index 000000000..358d96f95 --- /dev/null +++ b/docs/content/limitations/module-path-globals.mdx @@ -0,0 +1,4 @@ +`__dirname` and `__filename` are compile-time constants: the absolute path of the module's source directory and file at build time, the same strings as `import.meta.dirname` and `import.meta.filename`. +A `.ts` or `.tsx` file keeps them even when it uses `import` syntax, which Node.js would load as an ES module without these globals, because TypeScript projects are commonly shipped as CommonJS bundles where they exist. +In such a file `typeof __dirname` is `"string"`, where Node.js running the source directly reports `"undefined"`. +JavaScript ES modules (`.mjs`, or `.js` in a `"type": "module"` package) do not have them, as in Node.js. diff --git a/docs/content/limitations/types-and-class-definitions/null-and-optional-values.mdx b/docs/content/limitations/types-and-class-definitions/null-and-optional-values.mdx index e8b351679..be8b07571 100644 --- a/docs/content/limitations/types-and-class-definitions/null-and-optional-values.mdx +++ b/docs/content/limitations/types-and-class-definitions/null-and-optional-values.mdx @@ -1,3 +1,4 @@ - **Null and optional values:** `undefined` and `null` compile as standalone values and union members. Optional record and class fields and optional, default, and rest parameters also compile, including rest parameters typed `unknown[]` or `any[]`, whose functions take any number of arguments. - A function value with fixed parameters cannot be stored where such a variadic function type is expected. + A function value whose fixed parameters are all `unknown` or `any`, or that has none, can be stored where such a variadic function type without fixed parameters is expected: each call passes the arguments in order, `undefined` for the ones the caller left out. + Other function values with fixed parameters cannot be stored there. diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 0bb3a119d..55483f3b3 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -55958,7 +55958,9 @@ "confidence": "high", "source": "compiler-feature:process.'disconnect'", "tests": [ - "tests/corpus/2946-child-fork-ipc/main.ts" + "tests/corpus/2946-child-fork-ipc/main.ts", + "tests/corpus/6420-process-send-presence.ts", + "tests/corpus/6421-process-send-presence-fork/main.ts" ] } } @@ -56000,7 +56002,9 @@ "confidence": "high", "source": "compiler-feature:process.'message'", "tests": [ - "tests/corpus/2946-child-fork-ipc/main.ts" + "tests/corpus/2946-child-fork-ipc/main.ts", + "tests/corpus/6420-process-send-presence.ts", + "tests/corpus/6421-process-send-presence-fork/main.ts" ] } } @@ -56383,7 +56387,9 @@ "confidence": "high", "source": "compiler-feature:process.process.disconnect", "tests": [ - "tests/corpus/2946-child-fork-ipc/main.ts" + "tests/corpus/2946-child-fork-ipc/main.ts", + "tests/corpus/6420-process-send-presence.ts", + "tests/corpus/6421-process-send-presence-fork/main.ts" ] } } @@ -57031,7 +57037,9 @@ "confidence": "high", "source": "compiler-feature:process.process.send", "tests": [ - "tests/corpus/2946-child-fork-ipc/main.ts" + "tests/corpus/2946-child-fork-ipc/main.ts", + "tests/corpus/6420-process-send-presence.ts", + "tests/corpus/6421-process-send-presence-fork/main.ts" ] } } @@ -57485,7 +57493,9 @@ "confidence": "high", "source": "compiler-feature:process.connected", "tests": [ - "tests/corpus/2946-child-fork-ipc/main.ts" + "tests/corpus/2946-child-fork-ipc/main.ts", + "tests/corpus/6420-process-send-presence.ts", + "tests/corpus/6421-process-send-presence-fork/main.ts" ] } } @@ -57600,7 +57610,10 @@ "tests/corpus/2941-process-exit-code.ts", "tests/corpus/2942-process-exit-code-override.ts", "tests/corpus/2943-process-exit-code-invalid.ts", - "tests/corpus/2944-process-exit-code-wrap.ts" + "tests/corpus/2944-process-exit-code-wrap.ts", + "tests/corpus/6422-process-exitcode-read.ts", + "tests/corpus/6423-process-exitcode-default.ts", + "tests/corpus/6424-process-exit-keeps-exitcode.ts" ] } } @@ -66549,6 +66562,7 @@ "source": "compiler-feature:test.mock.fn", "tests": [ "tests/fixtures/node-test/cases/mock-fn.ts", + "tests/fixtures/node-test/cases/mock-fn-default.ts", "tests/harness/node-test.test.ts" ] } @@ -76221,6 +76235,8 @@ "tests/fixtures/node-types/promisify-crypto.ts", "tests/corpus/5632-promisify-dns.ts", "tests/fixtures/node-types/promisify-dns.ts", + "tests/corpus/6428-promisify-callback-functions.ts", + "tests/fixtures/node-types/promisify-callback-functions.ts", "tests/harness/project-config.test.ts" ] } diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 0ccdfdce2..903547576 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -79435,6 +79435,11 @@ "tests/corpus/5210-process-memory-usage.ts", "tests/corpus/5211-process-identity.ts", "tests/corpus/5809-process-exit-and-rejections.cjs", + "tests/corpus/6420-process-send-presence.ts", + "tests/corpus/6421-process-send-presence-fork/main.ts", + "tests/corpus/6422-process-exitcode-read.ts", + "tests/corpus/6423-process-exitcode-default.ts", + "tests/corpus/6424-process-exit-keeps-exitcode.ts", "tests/corpus/990-process-basics.ts", "tests/corpus/node24-env-files-errors.ts", "tests/corpus/node24-env-files.ts", @@ -79512,7 +79517,9 @@ "status": "partial", "evidence": "compiler-feature:process.'disconnect'", "tests": [ - "tests/corpus/2946-child-fork-ipc/main.ts" + "tests/corpus/2946-child-fork-ipc/main.ts", + "tests/corpus/6420-process-send-presence.ts", + "tests/corpus/6421-process-send-presence-fork/main.ts" ] }, "anchorSource": "exact" @@ -79551,7 +79558,9 @@ "status": "partial", "evidence": "compiler-feature:process.'message'", "tests": [ - "tests/corpus/2946-child-fork-ipc/main.ts" + "tests/corpus/2946-child-fork-ipc/main.ts", + "tests/corpus/6420-process-send-presence.ts", + "tests/corpus/6421-process-send-presence-fork/main.ts" ] }, "anchorSource": "exact" @@ -79964,7 +79973,9 @@ "status": "partial", "evidence": "compiler-feature:process.process.disconnect", "tests": [ - "tests/corpus/2946-child-fork-ipc/main.ts" + "tests/corpus/2946-child-fork-ipc/main.ts", + "tests/corpus/6420-process-send-presence.ts", + "tests/corpus/6421-process-send-presence-fork/main.ts" ] }, "anchorSource": "exact" @@ -80609,7 +80620,9 @@ "status": "partial", "evidence": "compiler-feature:process.process.send", "tests": [ - "tests/corpus/2946-child-fork-ipc/main.ts" + "tests/corpus/2946-child-fork-ipc/main.ts", + "tests/corpus/6420-process-send-presence.ts", + "tests/corpus/6421-process-send-presence-fork/main.ts" ] }, "anchorSource": "exact" @@ -81028,7 +81041,9 @@ "status": "partial", "evidence": "compiler-feature:process.connected", "tests": [ - "tests/corpus/2946-child-fork-ipc/main.ts" + "tests/corpus/2946-child-fork-ipc/main.ts", + "tests/corpus/6420-process-send-presence.ts", + "tests/corpus/6421-process-send-presence-fork/main.ts" ] }, "anchorSource": "chapter" @@ -81137,7 +81152,10 @@ "tests/corpus/2941-process-exit-code.ts", "tests/corpus/2942-process-exit-code-override.ts", "tests/corpus/2943-process-exit-code-invalid.ts", - "tests/corpus/2944-process-exit-code-wrap.ts" + "tests/corpus/2944-process-exit-code-wrap.ts", + "tests/corpus/6422-process-exitcode-read.ts", + "tests/corpus/6423-process-exitcode-default.ts", + "tests/corpus/6424-process-exit-keeps-exitcode.ts" ] }, "anchorSource": "chapter" @@ -91171,6 +91189,7 @@ "tests/fixtures/node-test/cases/ctx-plan.ts", "tests/fixtures/node-test/cases/get-test-context-cancelled.ts", "tests/fixtures/node-test/cases/get-test-context.ts", + "tests/fixtures/node-test/cases/mock-fn-default.ts", "tests/fixtures/node-test/cases/mock-fn.ts", "tests/fixtures/node-test/cases/mock-method.ts", "tests/fixtures/node-test/cases/mock-timers-date.ts", @@ -92582,6 +92601,7 @@ "evidence": "compiler-feature:test.mock.fn", "tests": [ "tests/fixtures/node-test/cases/mock-fn.ts", + "tests/fixtures/node-test/cases/mock-fn-default.ts", "tests/harness/node-test.test.ts" ] }, @@ -101263,6 +101283,7 @@ "tests/corpus/5832-util-types-brands-dynamic.js", "tests/corpus/5835-util-format-integer-specifiers.ts", "tests/corpus/5884-inspect-layout-options.ts", + "tests/corpus/6428-promisify-callback-functions.ts", "tests/corpus/node24-deep-equality-properties.js", "tests/corpus/node24-deep-equality.cjs", "tests/corpus/node24-deep-equality.ts", @@ -101289,6 +101310,7 @@ "tests/corpus/text-codec-values/main.ts", "tests/fixtures/node-types/deep-equality.ts", "tests/fixtures/node-types/env-files.ts", + "tests/fixtures/node-types/promisify-callback-functions.ts", "tests/fixtures/node-types/promisify-crypto.ts", "tests/fixtures/node-types/promisify-dns.ts", "tests/fixtures/node-types/promisify-fs.ts", @@ -102947,6 +102969,8 @@ "tests/fixtures/node-types/promisify-crypto.ts", "tests/corpus/5632-promisify-dns.ts", "tests/fixtures/node-types/promisify-dns.ts", + "tests/corpus/6428-promisify-callback-functions.ts", + "tests/fixtures/node-types/promisify-callback-functions.ts", "tests/harness/project-config.test.ts" ] }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index 927870590..3fb7803b1 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -150,7 +150,7 @@ "node-builtin.process.versions": ["tests/corpus/process-versions-storage.ts"], "node-builtin.process.rows": ["tests/corpus/2992-stream-rows.ts", "tests/harness/terminal-geometry.test.ts"], "node-builtin.process.columns": ["tests/corpus/1448-stream-columns.ts", "tests/harness/terminal-geometry.test.ts"], - "node-builtin.process.exitCode": ["tests/corpus/5809-process-exit-and-rejections.cjs", "tests/corpus/2941-process-exit-code.ts", "tests/corpus/2942-process-exit-code-override.ts", "tests/corpus/2943-process-exit-code-invalid.ts", "tests/corpus/2944-process-exit-code-wrap.ts"], + "node-builtin.process.exitCode": ["tests/corpus/5809-process-exit-and-rejections.cjs", "tests/corpus/2941-process-exit-code.ts", "tests/corpus/2942-process-exit-code-override.ts", "tests/corpus/2943-process-exit-code-invalid.ts", "tests/corpus/2944-process-exit-code-wrap.ts", "tests/corpus/6422-process-exitcode-read.ts", "tests/corpus/6423-process-exitcode-default.ts", "tests/corpus/6424-process-exit-keeps-exitcode.ts"], "node-builtin.punycode": ["tests/corpus/6122-punycode-conversions.ts", "tests/corpus/6124-punycode-require-warnings.cjs", "tests/corpus/6126-punycode-dependency/main.cjs"], "node-builtin.querystring": ["tests/corpus/957-builtins-namespace.ts", "tests/corpus/2917-builtin-callable-widths.ts"], "node-builtin.readline": ["tests/corpus/1475-readline-closed-stdin.ts"], @@ -345,7 +345,7 @@ { "chapter": "fs", "signatures": ["`fsPromises.lstat(path[, options])`"], "status": "partial", "evidence": ["tests/corpus/2941-fsp-lstat-identity.ts"] }, { "chapter": "fs", "signatures": ["`fs.globSync(pattern[, options])`", "`fs.glob(pattern[, options], callback)`", "`fsPromises.glob(pattern[, options])`"], "status": "partial", "evidence": ["tests/corpus/5448-fs-glob-patterns.ts", "tests/corpus/5449-fs-glob-options.ts", "tests/corpus/5450-fs-glob-validation.js", "tests/corpus/5451-fs-promises-glob.ts", "tests/corpus/5452-fs-glob-callback.ts", "tests/fixtures/node-types/fs-glob.ts"] }, { "chapter": "fs", "signatures": ["`fs.cpSync(src, dest[, options])`", "`fs.cp(src, dest[, options], callback)`", "`fsPromises.cp(src, dest[, options])`"], "status": "partial", "evidence": ["tests/corpus/5567-fs-cpsync.ts", "tests/corpus/5568-fs-cp-errors.js", "tests/corpus/5569-fs-cp-symlinks.ts", "tests/corpus/5570-fs-cp-async.ts"] }, - { "chapter": "process", "signatures": ["`process.send(message[, sendHandle[, options]][, callback])`", "`process.disconnect()`", "`connected` Type: {boolean}", "Event: `'message'`", "Event: `'disconnect'`"], "status": "partial", "evidence": ["tests/corpus/2946-child-fork-ipc/main.ts"] }, + { "chapter": "process", "signatures": ["`process.send(message[, sendHandle[, options]][, callback])`", "`process.disconnect()`", "`connected` Type: {boolean}", "Event: `'message'`", "Event: `'disconnect'`"], "status": "partial", "evidence": ["tests/corpus/2946-child-fork-ipc/main.ts", "tests/corpus/6420-process-send-presence.ts", "tests/corpus/6421-process-send-presence-fork/main.ts"] }, { "chapter": "fs", "symbols": ["fs.Stats", "stats.isBlockDevice", "stats.isCharacterDevice", "stats.isDirectory", "stats.isFIFO", "stats.isFile", "stats.isSocket", "stats.isSymbolicLink"], "status": "partial", "evidence": ["tests/corpus/5541-fs-stats-fields.cjs"] }, { "chapter": "fs", "parent": "Class: `fs.Stats`", "signatures": ["`mode` Type: {number|bigint}", "`nlink` Type: {number|bigint}", "`uid` Type: {number|bigint}", "`gid` Type: {number|bigint}", "`rdev` Type: {number|bigint}", "`size` Type: {number|bigint}", "`blksize` Type: {number|bigint}", "`blocks` Type: {number|bigint}", "`atimeMs` Type: {number|bigint}", "`mtimeMs` Type: {number|bigint}", "`birthtimeMs` Type: {number|bigint}", "`atimeNs` Type: {bigint}", "`mtimeNs` Type: {bigint}", "`ctimeNs` Type: {bigint}", "`birthtimeNs` Type: {bigint}", "`atime` Type: {Date}", "`mtime` Type: {Date}", "`ctime` Type: {Date}", "`birthtime` Type: {Date}"], "status": "partial", "evidence": ["tests/corpus/5541-fs-stats-fields.cjs"] }, { "chapter": "fs", "signatures": ["`dev` Type: {number|bigint}", "`ino` Type: {number|bigint}", "`ctimeMs` Type: {number|bigint}"], "status": "partial", "evidence": ["tests/corpus/2941-fsp-lstat-identity.ts"] }, @@ -374,7 +374,7 @@ { "chapter": "test", "parent": "Class: `TestContext`", "symbols": ["context.filePath", "passed", "attempt", "tags", "workerId"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/ctx-members.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `SuiteContext`", "symbols": ["context.name", "context.fullName", "context.filePath", "context.diagnostic", "passed", "attempt"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/suite-context.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `TestContext`", "symbols": ["context.diagnostic", "context.name"], "status": "partial", "evidence": ["tests/harness/node-test.test.ts"] }, - { "chapter": "test", "parent": "Class: `MockTracker`", "symbols": ["mock.fn"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-fn.ts", "tests/harness/node-test.test.ts"] }, + { "chapter": "test", "parent": "Class: `MockTracker`", "symbols": ["mock.fn"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-fn.ts", "tests/fixtures/node-test/cases/mock-fn-default.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockTracker`", "symbols": ["mock.method", "mock.reset", "mock.restoreAll"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-method.ts", "tests/corpus/5810-mock-method-records.ts", "tests/corpus/5811-mock-tracker-restore.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockTimers`", "symbols": ["timers.enable", "timers.reset", "timers.tick", "timers.runAll", "timers.setTime"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-timers.ts", "tests/fixtures/node-test/cases/mock-timers-date.ts", "tests/corpus/5813-mock-timers-module.ts", "tests/corpus/5814-mock-timers-date.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "parent": "Class: `MockTimers`", "signatures": ["`timers[Symbol.dispose]()`"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/mock-timers-date.ts", "tests/harness/node-test.test.ts"] }, @@ -382,7 +382,7 @@ { "chapter": "test", "parent": "Class: `TestContext`", "symbols": ["context.before", "context.after", "context.beforeEach", "context.afterEach", "context.plan", "context.fullName"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/ctx-hooks.ts", "tests/fixtures/node-test/cases/ctx-plan.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "symbols": ["getTestContext"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/get-test-context.ts", "tests/fixtures/node-test/cases/get-test-context-cancelled.ts", "tests/harness/node-test.test.ts"] }, { "chapter": "test", "symbols": ["describe.skip", "describe.todo", "describe.only", "suite.skip", "suite.todo", "suite.only", "it.skip", "it.todo", "it.only"], "status": "partial", "evidence": ["tests/fixtures/node-test/cases/suite-variants.ts", "tests/fixtures/node-test/cases/only-nested.ts", "tests/fixtures/node-test/cases/todo-suites.ts", "tests/harness/node-test.test.ts"] }, - { "chapter": "util", "signatures": ["`util.promisify(original)`"], "status": "partial", "evidence": ["tests/corpus/1473-promisify-execfile.ts", "tests/corpus/1573-promisify-execfile-env-spread.ts", "tests/corpus/2912-promisify-fs-readfile.ts", "tests/corpus/5625-promisify-exec.ts", "tests/corpus/5626-promisify-forms.ts", "tests/fixtures/node-types/promisify-fs.ts", "tests/corpus/5628-promisify-timers.ts", "tests/fixtures/node-types/promisify-timers.ts", "tests/corpus/5629-promisify-stream.ts", "tests/corpus/5630-promisify-zlib.ts", "tests/fixtures/node-types/promisify-zlib.ts", "tests/corpus/5631-promisify-crypto.ts", "tests/fixtures/node-types/promisify-crypto.ts", "tests/corpus/5632-promisify-dns.ts", "tests/fixtures/node-types/promisify-dns.ts", "tests/harness/project-config.test.ts"] }, + { "chapter": "util", "signatures": ["`util.promisify(original)`"], "status": "partial", "evidence": ["tests/corpus/1473-promisify-execfile.ts", "tests/corpus/1573-promisify-execfile-env-spread.ts", "tests/corpus/2912-promisify-fs-readfile.ts", "tests/corpus/5625-promisify-exec.ts", "tests/corpus/5626-promisify-forms.ts", "tests/fixtures/node-types/promisify-fs.ts", "tests/corpus/5628-promisify-timers.ts", "tests/fixtures/node-types/promisify-timers.ts", "tests/corpus/5629-promisify-stream.ts", "tests/corpus/5630-promisify-zlib.ts", "tests/fixtures/node-types/promisify-zlib.ts", "tests/corpus/5631-promisify-crypto.ts", "tests/fixtures/node-types/promisify-crypto.ts", "tests/corpus/5632-promisify-dns.ts", "tests/fixtures/node-types/promisify-dns.ts", "tests/corpus/6428-promisify-callback-functions.ts", "tests/fixtures/node-types/promisify-callback-functions.ts", "tests/harness/project-config.test.ts"] }, { "chapter": "typescript", "symbols": ["type"], "status": "supported", "evidence": ["tests/corpus/2702-type-import-link-static/main.ts", "tests/corpus/2703-type-import-link-static-reexport/main.ts", "tests/corpus/2704-type-import-link-static-success/main.ts", "tests/corpus/2707-type-import-link-static-default-reexport/main.ts", "tests/harness/errors.test.ts"] }, { "chapter": "zlib", "signatures": ["Class: `zlib.Deflate`", "Class: `zlib.Inflate`", "Class: `zlib.Gzip`", "Class: `zlib.Gunzip`", "Class: `zlib.DeflateRaw`", "Class: `zlib.InflateRaw`", "Class: `zlib.Unzip`", "Class: `zlib.ZlibBase`", "`zlib.close([callback])`", "`zlib.flush([kind, ]callback)`", "`zlib.params(level, strategy, callback)`", "`zlib.reset()`", "`bytesWritten` Type: {number}", "Class: `Options`"], "status": "partial", "evidence": ["tests/corpus/5370-zlib-stream-roundtrip.ts", "tests/corpus/5371-zlib-stream-chunking.cjs", "tests/corpus/5372-zlib-stream-errors.cjs", "tests/corpus/5373-zlib-stream-options.cjs", "tests/corpus/5374-zlib-stream-flush-params.ts", "tests/corpus/5375-zlib-stream-promises.ts", "tests/corpus/5377-zlib-stream-backpressure.cjs"] }, { "chapter": "zlib", "signatures": ["`zlib.constants`"], "status": "partial", "evidence": ["tests/corpus/5376-zlib-constants.cjs", "tests/corpus/5374-zlib-stream-flush-params.ts"] } diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 2e3691cd6..d733aef19 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3401,6 +3401,13 @@ declare module "util" { info: import("node:crypto").BinaryLike, keylen: number, ) => Promise; + /* A callback-only function (`obj.close.bind(obj)`): before the targets + * whose leading parameters would otherwise capture it. Builtins that take + * arguments before their callback never match these. */ + export function promisify( + fn: (callback: (err: any, result: TResult) => void) => void, + ): () => Promise; + export function promisify(fn: (callback: (err?: any) => void) => void): () => Promise; export function promisify( fn: typeof import("node:crypto").randomFill, ): ( diff --git a/packages/compiler/src/backend/llvm/byte-numbers.ts b/packages/compiler/src/backend/llvm/byte-numbers.ts index c51d03744..9001e015d 100644 --- a/packages/compiler/src/backend/llvm/byte-numbers.ts +++ b/packages/compiler/src/backend/llvm/byte-numbers.ts @@ -4,6 +4,7 @@ import type { LlValue, LlvmEmitterContext } from "./expr-context.js"; import { f64Lit } from "./common.js"; import { exactInteger, widenInteger } from "./integer-values.js"; import { emitTruncF64 } from "./trunc.js"; +import { bytesElementAlias, bytesHeaderAlias } from "./bytes-alias.js"; /** Supported LLVM targets are little-endian. All memory accesses use align * 1: Buffer fields and DataView windows can start at arbitrary byte offsets. */ @@ -79,7 +80,7 @@ export function emitByteNumber( capacity = B.tmp(); room = B.tmp(); B.line(`${lengthPtr} = getelementptr inbounds %ScrBytes, ptr ${receiver.name}, i64 0, i32 1`); - B.line(`${length} = load ${size}, ptr ${lengthPtr}`); + B.line(`${length} = load ${size}, ptr ${lengthPtr}${bytesHeaderAlias(host)}`); B.line(`${room} = icmp uge ${size} ${length}, ${spec.width}`); B.line(`${capacity} = sub ${size} ${length}, ${spec.width}`); if (integer) { @@ -221,14 +222,14 @@ export function emitByteNumber( } } const stored = endianBits(host, raw, spec.width, little); - B.line(`store i${bits} ${stored}, ptr ${pointer}, align 1`); + B.line(`store i${bits} ${stored}, ptr ${pointer}, align 1${bytesElementAlias(host)}`); if (!spec.dataView) { fastResult = B.tmp(); B.line(`${fastResult} = fadd double ${offset.name}, ${f64Lit(spec.width)}`); } } else { const loaded = B.tmp(); - B.line(`${loaded} = load i${bits}, ptr ${pointer}, align 1`); + B.line(`${loaded} = load i${bits}, ptr ${pointer}, align 1${bytesElementAlias(host)}`); const raw = endianBits(host, loaded, spec.width, little); fastResult = B.tmp(); if (spec.floating) { diff --git a/packages/compiler/src/backend/llvm/bytes-alias.ts b/packages/compiler/src/backend/llvm/bytes-alias.ts new file mode 100644 index 000000000..9aaeaa6c7 --- /dev/null +++ b/packages/compiler/src/backend/llvm/bytes-alias.ts @@ -0,0 +1,23 @@ +import type { LlvmEmitterContext } from "./expr-context.js"; + +/** Alias categories of typed-array storage. A ScrBytes header (length, + * data pointer, shared backing) is fixed at construction and only ever + * written by runtime code, never by emitted code. Element storage is one + * category for every element type: views of different types may share a + * buffer. Neither overlaps the other, a native field, array storage or a + * module global's slot, so element stores leave header loads and global + * receiver slots loop-invariant. Untagged accesses and calls still alias + * every category. */ +export function bytesHeaderAlias(host: LlvmEmitterContext): string { + return host.memoryAliasAttachment("bytes:header"); +} + +export function bytesElementAlias(host: LlvmEmitterContext): string { + return host.memoryAliasAttachment("bytes:elements"); +} + +/** A module global's slot is its own category for whole-slot loads of a + * scalar or typed-array binding. Stores stay untagged (and so alias it). */ +export function globalSlotAlias(host: LlvmEmitterContext, id: string, type: string): string { + return type === "bytes" || type === "f64" ? host.memoryAliasAttachment(`global:${id}`) : ""; +} diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts new file mode 100644 index 000000000..ddcfd667d --- /dev/null +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts @@ -0,0 +1,278 @@ +import { expect, test } from "vitest"; +import { + BOOL, + F64, + VOID, + type IrExpr, + type IrFunction, + type IrLocal, + type IrModule, + type IrStmt, + type IrType, +} from "../../ir/ir.js"; +import { analyzeIntegerRanges } from "../../ir/integer-ranges.js"; +import { matchIntegerCountedForLoop } from "../../ir/integer-loops.js"; +import { findInitializedByteLoopBindings } from "./byte-windows.js"; +import { matchBytesLoopVersion, type BytesLoopVersion } from "./bytes-loop-versions.js"; +import { emitLlvmModule } from "./emitter.js"; + +const loc = { file: "versions.ts", start: 0, end: 0 }; +const f64s: IrType = { kind: "bytes", elem: "f64" }; +const i32s: IrType = { kind: "bytes", elem: "i32" }; +const num = (value: number): IrExpr => ({ kind: "numLit", value, type: F64, loc }); +const ref = (localId: string, type: IrType = F64): IrExpr => ({ + kind: "varRef", + localId, + type, + loc, +}); +const bin = (op: string, left: IrExpr, right: IrExpr): IrExpr => + ({ kind: "bin", op, left, right, type: F64, loc }) as IrExpr; +const get = (receiver: IrExpr, index: IrExpr): IrExpr => ({ + kind: "bytesIntrinsic", + method: "get", + receiver, + args: [index], + invalidNaN: true, + type: F64, + loc, +}); +const set = (arr: IrExpr, index: IrExpr, value: IrExpr): IrStmt => ({ + kind: "bytesSet", + arr, + index, + value, + loc, +}); +const counted = ( + body: IrStmt[], + limit: IrExpr = ref("n"), + counter = "i", +): IrStmt & { kind: "for" } => ({ + kind: "for", + init: { kind: "varDecl", localId: counter, init: num(0), loc }, + cond: { kind: "bin", op: "<", left: ref(counter), right: limit, type: BOOL, loc }, + update: { kind: "assign", localId: counter, value: bin("+", ref(counter), num(1)), loc }, + body, + loc, +}); +const local = ( + id: string, + type: IrType, + mutable = false, + extra: Partial = {}, +): IrLocal => ({ + id, + name: id, + type, + mutable, + ...extra, +}); + +function fn(body: IrStmt[], extra: IrLocal[] = []): IrFunction { + return { + name: "kernel", + params: [ + { localId: "out", name: "out", type: f64s }, + { localId: "src", name: "src", type: f64s }, + { localId: "table", name: "table", type: i32s }, + { localId: "n", name: "n", type: F64 }, + { localId: "k", name: "k", type: F64 }, + ], + returnType: VOID, + locals: [ + local("out", f64s), + local("src", f64s), + local("table", i32s), + local("n", F64), + local("k", F64), + local("i", F64, true), + local("j", F64, true), + ...extra, + ], + body, + loc, + }; +} + +function match( + f: IrFunction, + loop: IrStmt & { kind: "for" }, + captured: string[] = [], +): BytesLoopVersion | null { + const ranges = analyzeIntegerRanges(f); + const locals = new Map(f.locals.map((l) => [l.id, l])); + return matchBytesLoopVersion(loop, matchIntegerCountedForLoop(loop, locals, ranges), { + locals, + invariantGlobals: new Set(), + captured: new Set(captured), + ranges, + initialized: findInitializedByteLoopBindings(f).get(loop) ?? new Set(), + proven: new Set(), + }); +} + +test("a counted loop's affine accesses get one guard and exact operand ranges", () => { + const shifted = bin("+", ref("i"), num(1)); + const loop = counted([set(ref("out", f64s), ref("i"), get(ref("src", f64s), shifted))]); + const version = match(fn([loop]), loop)!; + expect(version).not.toBeNull(); + expect(version.bounds.size).toBe(2); + expect(version.receivers.map((r) => r.ref.kind === "varRef" && r.ref.localId)).toEqual([ + "out", + "src", + ]); + expect(version.affine.map((c) => [c.scale, c.minOffset, c.maxEnd])).toEqual([ + [1, 0, 0], + [1, 1, 1], + ]); + // `n` is unproven: the guard bounds the counter so `i + 1` stays exact. + expect(version.counted?.limitGuarded).toBe(true); + expect(version.counterBound).toBe(Number.MAX_SAFE_INTEGER - 1); + expect(version.ranges.get(shifted)).toEqual({ min: 1, max: Number.MAX_SAFE_INTEGER }); +}); + +test("statically ranged indices compare one constant with the length", () => { + const masked = bin("&", bin("^", ref("i"), ref("k")), num(255)); + const loop = counted([set(ref("out", f64s), num(0), get(ref("table", i32s), masked))]); + const version = match(fn([loop]), loop)!; + expect(version.fixed.map((c) => [version.receivers[c.receiver]!.ref, c.end])).toEqual([ + [ref("out", f64s), 0], + [ref("table", i32s), 255], + ]); + expect(version.affine).toEqual([]); + expect(version.counted).toBeNull(); +}); + +test("scaled counters and body temps resolve to their receiver and index", () => { + const temps = [local("view", f64s), local("at", F64)]; + const at = bin("+", bin("*", ref("i"), num(4)), num(3)); + const loop = counted([ + { kind: "varDecl", localId: "view", init: ref("src", f64s), loc }, + { kind: "varDecl", localId: "at", init: at, loc }, + set(ref("view", f64s), ref("at"), num(1)), + // (The integer counted loop needs one direct counter index.) + set(ref("out", f64s), ref("i"), num(0)), + ]); + const version = match(fn([loop], temps), loop)!; + expect(version.receivers.map((r) => r.ref)).toEqual([ref("src", f64s), ref("out", f64s)]); + expect(version.affine.map((c) => [c.scale, c.minOffset, c.maxEnd])).toEqual([ + [4, 3, 3], + [1, 0, 0], + ]); + expect(version.ranges.has(at)).toBe(true); +}); + +test("negative factors, rebinding, captures and outer loops are not versioned", () => { + // `i * -1` is -0 at zero, so it is not treated as an affine operand. + const negative = counted([set(ref("out", f64s), bin("*", ref("i"), num(-1)), num(1))]); + expect(match(fn([negative]), negative)).toBeNull(); + const rebound = counted([ + set(ref("out", f64s), ref("i"), num(1)), + { kind: "assign", localId: "out", value: ref("src", f64s), loc }, + ]); + expect(match(fn([rebound]), rebound)).toBeNull(); + const plain = counted([set(ref("out", f64s), ref("i"), num(1))]); + expect(match(fn([plain]), plain, ["out"])).toBeNull(); + const inner = counted([set(ref("out", f64s), ref("j"), num(1))], ref("n"), "j"); + const outer = counted([inner]); + expect(match(fn([outer]), outer)).toBeNull(); + expect(match(fn([outer]), inner)).not.toBeNull(); +}); + +test("emitted loops version the body and tag typed-array memory", () => { + const loop = counted([ + set(ref("out", f64s), ref("i"), bin("*", get(ref("src", f64s), ref("i")), num(2))), + ]); + const kernel = fn([loop]); + const mod: IrModule = { + irVersion: 17, + sourceFile: loc.file, + entry: "__main", + functions: [ + { name: "__main", params: [], returnType: VOID, locals: [], body: [], loc }, + kernel, + ], + }; + const llvm = emitLlvmModule(mod); + const body = /^define internal [^\n]*@sc_bf_kernel[^]*?^}/m.exec(llvm)![0]; + expect(body).toContain("bytes.version.fast"); + expect(body).toContain("bytes.version.slow"); + // The checked copy keeps its per-element tests; the guard reads lengths. + expect(body).toContain("bytes.index.invalid"); + expect(body).toMatch(/store double [^\n]*, align 1, !tbaa !\d+/); + expect(body).toMatch(/load double, ptr [^\n]*, align 1, !tbaa !\d+/); + expect(body).toMatch(/load i64, ptr [^\n]*, !tbaa !\d+/); + expect(body).toMatch(/load ptr, ptr [^\n]*, !tbaa !\d+/); + const elements = /store double [^\n]*!tbaa !(\d+)/.exec(body)![1]; + const header = /load ptr, ptr [^\n]*!tbaa !(\d+)/.exec(body)![1]; + expect(elements).not.toBe(header); +}); + +test("Float16Array accesses version in elements and share the element tag", () => { + const f16s: IrType = { kind: "bytes", elem: "f16" }; + const withHalves = (body: IrStmt[]): IrFunction => { + const f = fn(body, [local("half", f16s)]); + return { ...f, params: [...f.params, { localId: "half", name: "half", type: f16s }] }; + }; + // half[i] = src[i + 1]; out[i] = half[i] * 2 + const loop = counted([ + set(ref("half", f16s), ref("i"), get(ref("src", f64s), bin("+", ref("i"), num(1)))), + set(ref("out", f64s), ref("i"), bin("*", get(ref("half", f16s), ref("i")), num(2))), + ]); + const kernel = withHalves([loop]); + const version = match(kernel, loop)!; + expect(version.bounds.size).toBe(4); + expect(version.receivers.map((r) => r.ref)).toEqual([ + ref("half", f16s), + ref("src", f64s), + ref("out", f64s), + ]); + // Element offsets against the element count, whatever the element size. + expect(version.affine.map((c) => [c.scale, c.minOffset, c.maxEnd])).toEqual([ + [1, 0, 0], + [1, 1, 1], + [1, 0, 0], + ]); + + const mod: IrModule = { + irVersion: 17, + sourceFile: loc.file, + entry: "__main", + functions: [ + { name: "__main", params: [], returnType: VOID, locals: [], body: [], loc }, + kernel, + ], + }; + const body = /^define internal [^\n]*@sc_bf_kernel[^]*?^}/m.exec(emitLlvmModule(mod))![0]; + const fast = /^bytes\.version\.fast\d+:$[^]*?^bytes\.version\.done\d+:$/m.exec(body)![0]; + expect(fast).toContain("call double @scr_f16_to_f64"); + expect(fast).toContain("call zeroext i16 @scr_f16_from_f64"); + expect(fast).not.toContain("bytes.index"); + const halfStore = /store i16 [^\n]*, align 1, !tbaa !(\d+)/.exec(fast)![1]; + const halfLoad = /load i16, ptr [^\n]*, align 1, !tbaa !(\d+)/.exec(fast)![1]; + const doubleStore = /store double [^\n]*, align 1, !tbaa !(\d+)/.exec(fast)![1]; + // Views of any element type may share a buffer: one element category. + expect(halfStore).toBe(doubleStore); + expect(halfLoad).toBe(doubleStore); + // The checked copy keeps its per-element tests. + expect(body.slice(0, body.indexOf(fast))).toContain("bytes.index.invalid"); +}); + +test("bodies compiled without optimization keep one checked loop", () => { + const loop = counted([set(ref("out", f64s), ref("i"), get(ref("src", f64s), ref("i")))]); + const boxes = Array.from({ length: 512 }, (_, k) => local(`box${k}`, F64, true, { boxed: true })); + const mod: IrModule = { + irVersion: 17, + sourceFile: loc.file, + entry: "__main", + functions: [ + { name: "__main", params: [], returnType: VOID, locals: [], body: [], loc }, + fn([loop], boxes), + ], + }; + const body = /^define internal [^\n]*@sc_bf_kernel[^]*?^}/m.exec(emitLlvmModule(mod))![0]; + expect(body.split("\n", 1)[0]).toContain("optnone"); + expect(body).not.toContain("bytes.version"); + expect(body).toContain("bytes.index.invalid"); +}); diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts new file mode 100644 index 000000000..df8977426 --- /dev/null +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts @@ -0,0 +1,578 @@ +import type { IrExpr, IrLocal, IrStmt } from "../../ir/ir.js"; +import type { IntegerRange, IntegerRanges } from "../../ir/integer-ranges.js"; +import type { IntegerCountedForLoop } from "../../ir/integer-loops.js"; +import type { LlvmEmitterContext } from "./expr-context.js"; +import { byteNumberAccess } from "../../ir/byte-numbers.js"; +import { everyExprChild, everyStmtChild } from "../../ir/traverse.js"; +import { exactInteger, widenInteger } from "./integer-values.js"; +import { emitCountedLoopLimit, emitCountedLoopSafety } from "./counted-loops.js"; +import { emitBytesHeaderLength } from "./expr-bytes.js"; + +type Node = IrExpr | IrStmt; +type VarRef = IrExpr & { kind: "varRef" }; + +/** One loop-invariant integer operand of an affine index. */ +interface Term { + expr: IrExpr; + /** 1 or -1. */ + sign: number; +} + +interface KeyedTerm extends Term { + key: string; +} + +/** Every access of `receiver` at a static index range ends below `end + 1`. */ +interface FixedCheck { + receiver: number; + end: number; +} + +/** Every access of `receiver` at `scale * counter + Σ terms + offset` has an + * offset in [minOffset, maxEnd - width + 1]; `maxEnd` includes the width. */ +interface AffineCheck { + receiver: number; + scale: number; + terms: KeyedTerm[]; + minOffset: number; + maxEnd: number; +} + +export interface BytesLoopVersion { + /** Typed-array accesses that are in bounds whenever the guard holds. */ + bounds: ReadonlySet; + /** Root receiver bindings, read once before the loop. */ + receivers: { ref: VarRef; global: boolean }[]; + fixed: FixedCheck[]; + affine: AffineCheck[]; + /** The counted loop whose iteration space the affine checks cover. */ + counted: IntegerCountedForLoop | null; + /** The guard also requires every counter value within [-bound, bound]. */ + counterBound: number | null; + /** Integer ranges of affine index operands that hold in the unchecked + * loop (where the guard bounds the counter). */ + ranges: ReadonlyMap; +} + +export interface BytesLoopFacts { + /** The function's own locals (not module globals). */ + locals: ReadonlyMap; + /** Module globals whose slot no call can replace: stable constants and + * the private bindings of a guarded initializer. */ + invariantGlobals: ReadonlySet; + captured: ReadonlySet; + ranges: IntegerRanges; + /** Locals definitely initialized when the loop is entered. */ + initialized: ReadonlySet; + /** Accesses already proved in bounds without a guard. */ + proven: ReadonlySet; +} + +const MAX_COST = 400; +const MAX_FIXED_END = 2 ** 32; +const MAX_CHECKS = 8; +const MAX_OFFSET = 2 ** 31; +const SAFE = Number.MAX_SAFE_INTEGER; +const INVARIANT_OPS = new Set(["+", "-", "*", "&", "|", "^", "<<", ">>", ">>>"]); + +/** Loop versioning for typed-array bounds. A typed array's length and data + * pointer are fixed at construction (ScrBytes has no resize, transfer or + * detach), so an access is in bounds for the whole loop when its receiver + * binding and index operands cannot change while it runs. One test before + * the loop then covers every iteration: + * + * - a statically ranged integer index `[lo, hi]` (lo >= 0) needs + * `hi < length`, such as `table[x & 0xff]` or a constant-trip counter; + * - an index `k * counter + invariant + c` of a counted loop needs its first + * and last values in bounds, such as `out[base + i]` for `i < n` or + * `view.getUint32(i * 4)`. + * + * Only small synchronous loops are versioned (nested loops included), and + * the emitter bounds how deeply versions nest. The checked loop runs + * whenever the guard fails, and keeps every out-of-bounds read, ignored + * write and NaN-index behavior. */ +export function matchBytesLoopVersion( + loop: IrStmt & { kind: "for" }, + counted: IntegerCountedForLoop | null, + facts: BytesLoopFacts, +): BytesLoopVersion | null { + const written = new Set(); + const temps = new Map(); + let cost = 0; + const scanExpr = (e: IrExpr): boolean => { + if (++cost > MAX_COST) return false; + if (e.kind === "assignExpr" || e.kind === "incDec") written.add(e.localId); + return everyExprChild(e, scanExpr, scanStmt); + }; + const scanStmt = (s: IrStmt): boolean => { + if (++cost > MAX_COST) return false; + switch (s.kind) { + case "forOf": + written.add(s.localId); + break; + case "varDecl": { + if (temps.has(s.localId) || written.has(s.localId)) temps.delete(s.localId); + else if (s.init) temps.set(s.localId, s.init); + written.add(s.localId); + break; + } + case "assign": + written.add(s.localId); + break; + case "tryCatch": + if (s.catchLocalId) written.add(s.catchLocalId); + break; + default: + break; + } + return everyStmtChild(s, scanExpr, scanStmt); + }; + // The guard runs before the initializer, so a binding the initializer + // writes is not invariant either: `for (let i = (a = b, 0); ...)` must + // not keep the bounds the guard proved for the old `a`. + if ( + (loop.init !== null && !scanStmt(loop.init)) || + !loop.body.every(scanStmt) || + (loop.cond !== null && !scanExpr(loop.cond)) || + (loop.update !== null && !scanStmt(loop.update)) + ) + return null; + // A body temp stands for its initializer only when it is a constant + // binding assigned exactly once, by that declaration. + const declared = new Map(); + const countDecls = (s: IrStmt): boolean => { + if (s.kind === "varDecl") declared.set(s.localId, (declared.get(s.localId) ?? 0) + 1); + return everyStmtChild(s, countExprDecls, countDecls); + }; + const countExprDecls = (e: IrExpr): boolean => everyExprChild(e, countExprDecls, countDecls); + loop.body.every(countDecls); + const temp = (id: string): IrExpr | null => { + const local = facts.locals.get(id); + const init = temps.get(id); + if ( + !init || + !local || + local.mutable || + local.boxed || + local.tdz || + facts.captured.has(id) || + declared.get(id) !== 1 + ) + return null; + return init; + }; + const counter = counted?.localId ?? null; + // A binding keeps its loop-entry value for the whole loop. + const invariant = (id: string): boolean => { + if (written.has(id) || id === counter) return false; + const local = facts.locals.get(id); + if (local) + return !local.boxed && !local.tdz && !facts.captured.has(id) && facts.initialized.has(id); + return facts.invariantGlobals.has(id); + }; + const resolving = new Set(); + const root = (e: IrExpr): VarRef | null => { + if (e.kind !== "varRef" || e.type.kind !== "bytes") return null; + const init = temp(e.localId); + if (init) { + if (resolving.has(e.localId)) return null; + resolving.add(e.localId); + const result = root(init); + resolving.delete(e.localId); + return result; + } + return invariant(e.localId) ? e : null; + }; + // A pure integer operand evaluated again before the loop. + const invariantKey = (e: IrExpr): string | null => { + if (!facts.ranges.get(e)) return null; + if (e.kind === "numLit") return Number.isSafeInteger(e.value) ? `n${e.value}` : null; + if (e.kind === "varRef") + return invariant(e.localId) ? `v${e.localId.length}:${e.localId}` : null; + if ( + e.kind === "bin" && + INVARIANT_OPS.has(e.op) && + e.left.type.kind === "f64" && + e.right.type.kind === "f64" + ) { + const left = invariantKey(e.left), + right = invariantKey(e.right); + return left !== null && right !== null ? `(${e.op} ${left} ${right})` : null; + } + return null; + }; + interface Affine { + /** The counter's coefficient; 0 when the value is loop-invariant. */ + counter: number; + terms: KeyedTerm[]; + offset: number; + } + // Every operand of an affine index is `counter * k + Σ terms + offset`. + // Invariant terms need proven ranges. Operands that involve the counter + // need none: the guard bounds the counter so that each of them is a safe + // integer, which makes the index's double arithmetic exact. + const shapes = new Map(); + const affine = (e: IrExpr): Affine | null => { + if (shapes.has(e)) return shapes.get(e)!; + const result = affineShape(e); + shapes.set(e, result); + return result; + }; + const affineShape = (e: IrExpr): Affine | null => { + if (e.kind === "numLit") + return Number.isSafeInteger(e.value) && Math.abs(e.value) <= MAX_OFFSET + ? { counter: 0, terms: [], offset: e.value } + : null; + if (e.kind === "varRef") { + if (e.localId === counter) return { counter: 1, terms: [], offset: 0 }; + const init = temp(e.localId); + if (init) { + if (resolving.has(e.localId)) return null; + resolving.add(e.localId); + const result = affine(init); + resolving.delete(e.localId); + return result; + } + } + if ( + e.kind === "bin" && + (e.op === "+" || e.op === "-") && + e.left.type.kind === "f64" && + e.right.type.kind === "f64" + ) { + const left = affine(e.left), + right = affine(e.right); + if (left && right && (left.counter === 0 || right.counter === 0)) { + const sign = e.op === "+" ? 1 : -1; + const offset = left.offset + sign * right.offset; + if (Math.abs(offset) > MAX_OFFSET) return null; + const terms = [ + ...left.terms, + ...right.terms.map((t) => ({ expr: t.expr, sign: sign * t.sign, key: t.key })), + ]; + const result = { counter: left.counter + sign * right.counter, terms, offset }; + if (result.counter !== 0 || facts.ranges.get(e)) return result; + } + } + // A positive constant multiple of the counter: `i * 4`, `4 * i`, + // `(i + 1) * 8`. (A negative factor turns a zero into -0.) + if (e.kind === "bin" && e.op === "*") { + const rightLiteral = e.right.kind === "numLit"; + const scaled = rightLiteral ? e.left : e.right; + const literal = rightLiteral ? e.right : e.left; + const factor = literal.kind === "numLit" ? literal.value : 0; + if ( + literal.kind === "numLit" && + scaled.type.kind === "f64" && + Number.isSafeInteger(factor) && + factor > 0 && + factor <= MAX_OFFSET + ) { + const inner = affine(scaled); + if (inner && inner.counter !== 0 && inner.terms.length === 0) { + const counterScale = inner.counter * factor, + offset = inner.offset * factor; + if (Math.abs(counterScale) <= MAX_OFFSET && Math.abs(offset) <= MAX_OFFSET) + return { counter: counterScale, terms: [], offset }; + } + } + } + const key = invariantKey(e); + return key !== null ? { counter: 0, terms: [{ expr: e, sign: 1, key }], offset: 0 } : null; + }; + // The operands of an index that involve the counter. + const chain = (e: IrExpr, out: Set): void => { + if (!shapes.get(e)?.counter) return; + out.add(e); + if (e.kind === "varRef") { + const init = temp(e.localId); + if (init) chain(init, out); + } else if (e.kind === "bin") { + chain(e.left, out); + chain(e.right, out); + } + }; + const termMagnitude = (terms: Term[]): number => + terms.reduce((sum, t) => { + const r = facts.ranges.get(t.expr)!; + return sum + Math.max(Math.abs(r.min), Math.abs(r.max)); + }, 0); + + const receivers: { ref: VarRef; global: boolean }[] = []; + const receiverIndex = new Map(); + const fixed = new Map(); + const affineChecks = new Map< + string, + { check: AffineCheck; nodes: Node[]; operands: Set } + >(); + const receiverOf = (ref: VarRef): number => { + let index = receiverIndex.get(ref.localId); + if (index === undefined) { + index = receivers.length; + receiverIndex.set(ref.localId, index); + receivers.push({ ref, global: !facts.locals.has(ref.localId) }); + } + return index; + }; + const access = (node: Node, array: IrExpr, index: IrExpr, width: number): void => { + if (facts.proven.has(node)) return; + const ref = root(array); + if (!ref) return; + const shape = counter !== null ? affine(index) : null; + if (shape && shape.counter !== 0) { + const operands = new Set(); + chain(index, operands); + const terms = [...shape.terms].sort((a, b) => + a.key < b.key ? -1 : a.key > b.key ? 1 : a.sign - b.sign, + ); + const receiver = receiverOf(ref); + const key = `${receiver}|${shape.counter}|${terms.map((t) => `${t.sign}${t.key}`).join(",")}`; + const end = shape.offset + width - 1; + const group = affineChecks.get(key); + if (group) { + group.check.minOffset = Math.min(group.check.minOffset, shape.offset); + group.check.maxEnd = Math.max(group.check.maxEnd, end); + group.nodes.push(node); + for (const operand of operands) group.operands.add(operand); + } else + affineChecks.set(key, { + check: { receiver, scale: shape.counter, terms, minOffset: shape.offset, maxEnd: end }, + nodes: [node], + operands, + }); + return; + } + const range = facts.ranges.get(index); + if (!range) return; + const end = range.max + width - 1; + // Only a length a buffer can have: an outer loop must not pay for a + // guard that bounds an inner loop's unbounded counter. + if (range.min < 0 || end >= MAX_FIXED_END) return; + const receiver = receiverOf(ref); + const group = fixed.get(receiver); + if (group) { + group.check.end = Math.max(group.check.end, end); + group.nodes.push(node); + } else fixed.set(receiver, { check: { receiver, end }, nodes: [node] }); + }; + const visitExpr = (e: IrExpr): boolean => { + if (e.kind === "bytesIntrinsic") { + const numeric = byteNumberAccess(e); + if (numeric) access(e, e.receiver, e.args[numeric.offsetArg]!, numeric.width); + else if (e.method === "get" && e.args[0]) access(e, e.receiver, e.args[0], 1); + } + return everyExprChild(e, visitExpr, visitStmt); + }; + const visitStmt = (s: IrStmt): boolean => { + if (s.kind === "bytesSet") access(s, s.arr, s.index, 1); + return everyStmtChild(s, visitExpr, visitStmt); + }; + loop.body.every(visitStmt); + // Bound the counter so every counter operand stays a safe integer. + let bound = SAFE; + const affineGroups = [...affineChecks.values()].filter((group) => { + let limit = SAFE; + for (const operand of group.operands) { + const shape = shapes.get(operand)!; + const room = SAFE - termMagnitude(shape.terms) - Math.abs(shape.offset); + limit = Math.min(limit, Math.floor(room / Math.abs(shape.counter))); + } + if (limit < 0 || !counted) return false; + bound = Math.min(bound, limit); + return true; + }); + const fixedKept = [...fixed.values()].slice(0, MAX_CHECKS); + const affineKept = affineGroups.slice(0, MAX_CHECKS - fixedKept.length); + if (fixedKept.length === 0 && affineKept.length === 0) return null; + const bounds = new Set(); + const used = new Set(); + const ranges = new Map(); + const counterLow = Math.max(counted?.range.min ?? 0, -bound), + counterHigh = Math.min(counted?.range.max ?? 0, bound); + for (const group of fixedKept) { + used.add(group.check.receiver); + for (const node of group.nodes) bounds.add(node); + } + for (const group of affineKept) { + used.add(group.check.receiver); + for (const node of group.nodes) bounds.add(node); + for (const operand of group.operands) { + if (facts.ranges.get(operand)) continue; + const shape = shapes.get(operand)!; + const a = shape.counter * counterLow, + b = shape.counter * counterHigh; + let min = Math.min(a, b) + shape.offset, + max = Math.max(a, b) + shape.offset; + for (const term of shape.terms) { + const r = facts.ranges.get(term.expr)!; + min += term.sign > 0 ? r.min : -r.max; + max += term.sign > 0 ? r.max : -r.min; + } + if (counterLow <= counterHigh) ranges.set(operand, { min, max }); + } + } + // Renumber the receivers the kept checks use. + const order = [...used].sort((a, b) => a - b); + const renumber = new Map(order.map((old, index) => [old, index])); + const needsBound = + affineKept.length > 0 && + counted !== null && + (counted.range.min < -bound || counted.range.max > bound); + return { + bounds, + receivers: order.map((index) => receivers[index]!), + fixed: fixedKept.map((g) => ({ + receiver: renumber.get(g.check.receiver)!, + end: g.check.end, + })), + affine: affineKept.map((g) => ({ + receiver: renumber.get(g.check.receiver)!, + scale: g.check.scale, + terms: g.check.terms, + minOffset: g.check.minOffset, + maxEnd: g.check.maxEnd, + })), + counted: affineKept.length > 0 ? counted : null, + counterBound: needsBound ? bound : null, + ranges, + }; +} + +/** Branches to `fast` when every access the version proves is in bounds for + * every iteration, and to `slow` otherwise (including a counted loop whose + * integer form is not established, or a module receiver not yet set). */ +export function emitBytesLoopVersionGuard( + host: LlvmEmitterContext, + version: BytesLoopVersion, + fast: string, + slow: string, +): void { + const B = host.B; + const next = (cond: string): void => { + if (cond === "true") return; + const ok = B.newLabel("bytes.version.check"); + B.condBr(cond, ok, slow); + B.startBlock(ok); + }; + const counted = version.counted; + if (counted?.guarded) next(emitCountedLoopSafety(host, counted)); + const receivers = version.receivers.map(({ ref, global }) => { + const value = host.emitReadReceiver(ref).name; + if (global) { + const set = B.tmp(); + B.line(`${set} = icmp ne ptr ${value}, null`); + next(set); + } + return value; + }); + const lengths = receivers.map((receiver) => { + const len = emitBytesHeaderLength(host, receiver); + if (host.sizeType === "i64") return len; + const wide = B.tmp(); + B.line(`${wide} = zext ${host.sizeType} ${len} to i64`); + return wide; + }); + const conditions: string[] = []; + for (const check of version.fixed) { + const ok = B.tmp(); + B.line(`${ok} = icmp ugt i64 ${lengths[check.receiver]}, ${check.end}`); + conditions.push(ok); + } + if (counted && version.affine.length > 0) { + // The first and last counter values, in ascending order. The last value + // of a non-unit step is exact: `start + ⌊(limit ∓ 1 - start) / step⌋ * + // step`. A loop that runs no iteration may compute anything here. + const startValue = host.emitExpr(counted.start); + const startInteger = exactInteger(host, startValue, counted.start); + let start: string; + if (startInteger) start = widenInteger(host, startInteger); + else { + // The counted-loop safety test above proved an exact integer. + start = B.tmp(); + B.line(`${start} = fptosi double ${startValue.name} to i64`); + } + const limit = emitCountedLoopLimit(host, counted); + const step = Math.abs(counted.step); + const edge = B.tmp(); + B.line(`${edge} = add i64 ${limit}, ${counted.step > 0 ? -1 : 1}`); + let last = edge; + if (step !== 1) { + const span = B.tmp(), + whole = B.tmp(), + covered = B.tmp(); + last = B.tmp(); + B.line( + counted.step > 0 + ? `${span} = sub i64 ${edge}, ${start}` + : `${span} = sub i64 ${start}, ${edge}`, + ); + B.line(`${whole} = sdiv i64 ${span}, ${step}`); + B.line(`${covered} = mul i64 ${whole}, ${step}`); + B.line(`${last} = ${counted.step > 0 ? "add" : "sub"} i64 ${start}, ${covered}`); + } + const low = counted.step > 0 ? start : last; + const high = counted.step > 0 ? last : start; + if (version.counterBound !== null) { + const above = B.tmp(), + below = B.tmp(); + B.line(`${above} = icmp sge i64 ${low}, ${-version.counterBound}`); + B.line(`${below} = icmp sle i64 ${high}, ${version.counterBound}`); + conditions.push(above, below); + } + for (const check of version.affine) { + let base = "0"; + for (const term of check.terms) { + const value = host.emitExpr(term.expr); + const integer = exactInteger(host, value, term.expr); + if (!integer) { + // Unreachable: every term has a proven range. Stay checked. + B.br(slow); + B.startBlock(B.newLabel("bytes.version.dead")); + return; + } + const wide = widenInteger(host, integer); + const sum = B.tmp(); + B.line(`${sum} = ${term.sign > 0 ? "add" : "sub"} i64 ${base}, ${wide}`); + base = sum; + } + // Products wrap only for a loop with no iteration: within the + // iteration space every scaled counter is a proven safe integer. + const scaledLow = scaleCounter(host, low, check.scale), + scaledHigh = scaleCounter(host, high, check.scale); + const first = B.tmp(), + final = B.tmp(), + nonNegative = B.tmp(), + below = B.tmp(), + both = B.tmp(); + B.line(`${first} = add i64 ${check.scale > 0 ? scaledLow : scaledHigh}, ${base}`); + B.line(`${final} = add i64 ${check.scale > 0 ? scaledHigh : scaledLow}, ${base}`); + const firstOffset = B.tmp(), + lastEnd = B.tmp(); + B.line(`${firstOffset} = add i64 ${first}, ${check.minOffset}`); + B.line(`${lastEnd} = add i64 ${final}, ${check.maxEnd}`); + B.line(`${nonNegative} = icmp sge i64 ${firstOffset}, 0`); + // Lengths are at most 2^53 elements: a signed comparison is exact. + B.line(`${below} = icmp slt i64 ${lastEnd}, ${lengths[check.receiver]}`); + B.line(`${both} = and i1 ${nonNegative}, ${below}`); + conditions.push(both); + } + } + let valid = "true"; + for (const cond of conditions) { + if (valid === "true") valid = cond; + else { + const all = B.tmp(); + B.line(`${all} = and i1 ${valid}, ${cond}`); + valid = all; + } + } + if (valid === "true") B.br(fast); + else B.condBr(valid, fast, slow); +} + +function scaleCounter(host: LlvmEmitterContext, value: string, scale: number): string { + if (scale === 1) return value; + const scaled = host.B.tmp(); + host.B.line(`${scaled} = mul i64 ${value}, ${scale}`); + return scaled; +} diff --git a/packages/compiler/src/backend/llvm/counted-loops.ts b/packages/compiler/src/backend/llvm/counted-loops.ts index 03e0ed4f3..36fc63e1f 100644 --- a/packages/compiler/src/backend/llvm/counted-loops.ts +++ b/packages/compiler/src/backend/llvm/counted-loops.ts @@ -42,3 +42,54 @@ export function emitCountedLoopLimit( B.line(`${limit} = add nsw i64 ${integer}, ${ascending ? 1 : -1}`); return limit; } + +/** The run-time test of a guarded counted loop: an unproven limit is within + * the integer form's finite range and an unproven start is an exact safe + * integer. Returns `true` when nothing needs testing. */ +export function emitCountedLoopSafety( + host: LlvmEmitterContext, + loop: IntegerCountedForLoop, +): string { + const B = host.B; + let safe = "true"; + if (loop.limitGuarded) { + const bound = host.emitExpr(loop.limit); + safe = B.tmp(); + B.line( + `${safe} = fcmp ${loop.step > 0 ? "ole" : "oge"} double ${bound.name}, ${f64Lit(loop.guardLimit)}`, + ); + } + if (loop.startGuarded) { + // An exact integer of at most 2^53 - 1 in magnitude, and not -0 + // (the bit patterns of the value and its round trip agree). + // NaN and infinities fail the ordered range tests. + const start = host.emitExpr(loop.start); + const low = B.tmp(), + high = B.tmp(), + raw = B.tmp(), + wide = B.tmp(), + back = B.tmp(), + bits = B.tmp(), + backBits = B.tmp(), + exact = B.tmp(), + inRange = B.tmp(), + ok = B.tmp(); + B.line(`${low} = fcmp oge double ${start.name}, ${f64Lit(-Number.MAX_SAFE_INTEGER)}`); + B.line(`${high} = fcmp ole double ${start.name}, ${f64Lit(Number.MAX_SAFE_INTEGER)}`); + B.line(`${inRange} = and i1 ${low}, ${high}`); + B.line(`${raw} = fptosi double ${start.name} to i64`); + B.line(`${wide} = freeze i64 ${raw}`); + B.line(`${back} = sitofp i64 ${wide} to double`); + B.line(`${bits} = bitcast double ${start.name} to i64`); + B.line(`${backBits} = bitcast double ${back} to i64`); + B.line(`${exact} = icmp eq i64 ${bits}, ${backBits}`); + B.line(`${ok} = and i1 ${inRange}, ${exact}`); + if (safe === "true") safe = ok; + else { + const both = B.tmp(); + B.line(`${both} = and i1 ${safe}, ${ok}`); + safe = both; + } + } + return safe; +} diff --git a/packages/compiler/src/backend/llvm/emit-function.ts b/packages/compiler/src/backend/llvm/emit-function.ts index 78f208ff1..9e50bea6d 100644 --- a/packages/compiler/src/backend/llvm/emit-function.ts +++ b/packages/compiler/src/backend/llvm/emit-function.ts @@ -137,6 +137,9 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { constructorClass(fn.name) === null && emitter.finalFields.size > 0; emitter.byteWindowsEnabled = emitter.countedLoopsEnabled; + emitter.bytesLoopVersionsEnabled = emitter.countedLoopsEnabled; + emitter.bytesLoopEntries = null; + emitter.bytesLoopFunction = fn; emitter.denseLoopsEnabled = emitter.countedLoopsEnabled; emitter.denseLoop = null; emitter.denseLoopEntries = @@ -399,6 +402,8 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { for (const local of emitter.currentLocals.values()) if (local.boxed || emitter.captureIds.has(local.id)) slots.add(`%${mangleLocal(local.id)}`); B.volatileSlots = slots; + // Without optimization a versioned copy only adds code. + emitter.bytesLoopVersionsEnabled = false; } // Captured bindings come in through the environment — borrowed for the // whole call (the closure owns them): bound here, never released here. diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index 01fa11035..a5da56f55 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -1,5 +1,10 @@ /* LlEmitter's statement emission: the statement switch, try/catch, switch, loop copies, speculative writes and string self-concatenation. */ -import { type LlEmitter, type LlScopeEntry, adoptingAwaitOf } from "./emitter.js"; +import { + type LlEmitter, + type LlScopeEntry, + adoptingAwaitOf, + MAX_BYTES_LOOP_VERSION_DEPTH, +} from "./emitter.js"; import { CAUGHT, F64, type IrExpr, type IrStmt, STRING, isRefCounted } from "../../ir/ir.js"; import { emitStringSliceSnapshot } from "./string-slices.js"; import { @@ -40,7 +45,8 @@ import { } from "../../ir/integer-loops.js"; import { emitByteWindowGuard, matchByteWindow } from "./byte-windows.js"; import { countedDenseShape, emitDenseLoopGuard, matchDenseArrayLoop } from "./dense-array-loops.js"; -import { emitCountedLoopLimit } from "./counted-loops.js"; +import { emitCountedLoopLimit, emitCountedLoopSafety } from "./counted-loops.js"; +import { emitBytesLoopVersionGuard } from "./bytes-loop-versions.js"; import { mangleLocal } from "../mangle.js"; import { LlvmUnsupportedError } from "./unsupported.js"; import type { LlValue } from "./expr-context.js"; @@ -939,48 +945,43 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { B.startBlock(done); break; } + const version = + emitter.bytesLoopVersionsEnabled && + emitter.bytesLoopVersioning.size < MAX_BYTES_LOOP_VERSION_DEPTH && + !emitter.bytesLoopVersioning.has(s) + ? emitter.matchBytesLoopVersion(s, countedLoop) + : null; + if (version) { + const fast = B.newLabel("bytes.version.fast"), + slow = B.newLabel("bytes.version.slow"), + done = B.newLabel("bytes.version.done"); + emitBytesLoopVersionGuard(emitter, version, fast, slow); + const originalBounds = emitter.bytesBounds, + originalRanges = emitter.integerRanges; + emitter.bytesLoopVersioning.add(s); + try { + B.startBlock(slow); + emitter.emitStmt(s); + B.br(done); + B.startBlock(fast); + emitter.bytesBounds = new Set([...originalBounds, ...version.bounds]); + if (version.ranges.size > 0) + emitter.integerRanges = new Map([...originalRanges, ...version.ranges]); + if (version.counted?.guarded) emitter.provenCountedGuards.add(s); + emitter.emitStmt(s); + B.br(done); + } finally { + emitter.bytesBounds = originalBounds; + emitter.integerRanges = originalRanges; + emitter.provenCountedGuards.delete(s); + emitter.bytesLoopVersioning.delete(s); + } + B.startBlock(done); + break; + } let countedJoin: string | null = null; - if (countedLoop?.guarded) { - let safe = "true"; - if (countedLoop.limitGuarded) { - const bound = emitter.emitExpr(countedLoop.limit); - safe = B.tmp(); - B.line( - `${safe} = fcmp ${countedLoop.step > 0 ? "ole" : "oge"} double ${bound.name}, ${f64Lit(countedLoop.guardLimit)}`, - ); - } - if (countedLoop.startGuarded) { - // An exact integer of at most 2^53 - 1 in magnitude, and not -0 - // (the bit patterns of the value and its round trip agree). - // NaN and infinities fail the ordered range tests. - const start = emitter.emitExpr(countedLoop.start); - const low = B.tmp(), - high = B.tmp(), - raw = B.tmp(), - wide = B.tmp(), - back = B.tmp(), - bits = B.tmp(), - backBits = B.tmp(), - exact = B.tmp(), - inRange = B.tmp(), - ok = B.tmp(); - B.line(`${low} = fcmp oge double ${start.name}, ${f64Lit(-Number.MAX_SAFE_INTEGER)}`); - B.line(`${high} = fcmp ole double ${start.name}, ${f64Lit(Number.MAX_SAFE_INTEGER)}`); - B.line(`${inRange} = and i1 ${low}, ${high}`); - B.line(`${raw} = fptosi double ${start.name} to i64`); - B.line(`${wide} = freeze i64 ${raw}`); - B.line(`${back} = sitofp i64 ${wide} to double`); - B.line(`${bits} = bitcast double ${start.name} to i64`); - B.line(`${backBits} = bitcast double ${back} to i64`); - B.line(`${exact} = icmp eq i64 ${bits}, ${backBits}`); - B.line(`${ok} = and i1 ${inRange}, ${exact}`); - if (safe === "true") safe = ok; - else { - const both = B.tmp(); - B.line(`${both} = and i1 ${safe}, ${ok}`); - safe = both; - } - } + if (countedLoop?.guarded && !emitter.provenCountedGuards.has(s)) { + const safe = emitCountedLoopSafety(emitter, countedLoop); const fast = B.newLabel("counted.fast"); const slow = B.newLabel("counted.slow"); countedJoin = B.newLabel("counted.done"); @@ -1091,7 +1092,7 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { B.line( `${lenPtr} = getelementptr inbounds %${integerArrayLoop ? "ScrArr" : "ScrBytes"}, ptr ${receiver.name}, i64 0, i32 1`, ); - if (integerArrayLoop) emitter.markMemoryPointer(lenPtr, "array:header"); + emitter.markMemoryPointer(lenPtr, integerArrayLoop ? "array:header" : "bytes:header"); B.line( `${len} = load ${emitter.sizeType}, ptr ${lenPtr}${emitter.fieldAliasAttachment(lenPtr)}`, ); diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index a6b67b33f..9d8bd1f9e 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -56,6 +56,9 @@ import { moduleRuntimeFeatures, moduleUsesMockTimers } from "../../ir/runtime-fe import { captureFreeFunctions, observesStacks } from "../stack-observations.js"; import { type DenseArrayLoop } from "./dense-array-loops.js"; import { findInitializedByteLoopBindings } from "./byte-windows.js"; +import { matchBytesLoopVersion } from "./bytes-loop-versions.js"; +import { globalSlotAlias } from "./bytes-alias.js"; +import type { IntegerCountedForLoop } from "../../ir/integer-loops.js"; import { materializeSplitPiece, type SplitSpan, @@ -522,6 +525,9 @@ export function boxSlotCount(fn: IrFunction): number { /** Whether any node of `e` names the local (reads, writes, declarations, * captures). */ +/** Typed-array loop versions nest at most this deep (each doubles a body). */ +export const MAX_BYTES_LOOP_VERSION_DEPTH = 3; + function mentionsLocal(e: IrExpr, localId: string): boolean { const exprNames = (node: IrExpr): boolean => { if (node.kind === "varRef" || node.kind === "incDec" || node.kind === "assignExpr") @@ -1029,6 +1035,17 @@ export class LlEmitter { wrappingSums = new Set(); byteWindowsEnabled = true; byteWindowEntries: ReturnType = new Map(); + /** Typed-array loop versioning (bytes-loop-versions.ts) for the current + * function: off in debug and suspending functions and inside a copy. */ + bytesLoopVersionsEnabled = false; + /** Loops being versioned around the statement being emitted: a loop is + * never versioned inside its own copies, and versions nest boundedly. */ + readonly bytesLoopVersioning = new Set(); + bytesLoopEntries: ReturnType | null = null; + bytesLoopFunction: IrFunction | null = null; + /** Counted loops whose integer-form safety test an enclosing version + * guard already passed. */ + readonly provenCountedGuards = new Set(); bytesBounds: ReadonlySet = new Set(); integerViews = new Map(); /** Module globals the current function owns outright (initializer @@ -3347,6 +3364,34 @@ export class LlEmitter { /** A binding's storage: a module global, a plain local slot, or a boxed * local (the slot holds the capture BOX; access goes through it). */ + matchBytesLoopVersion( + s: IrStmt & { kind: "for" }, + counted: IntegerCountedForLoop | null, + ): ReturnType { + const fn = this.bytesLoopFunction; + if (!fn) return null; + this.bytesLoopEntries ??= findInitializedByteLoopBindings(fn); + const initialized = this.bytesLoopEntries.get(s); + if (!initialized) return null; + const invariantGlobals = new Set(this.stableGlobals); + for (const global of this.initializerBindings.get(fn.name) ?? []) + invariantGlobals.add(global.id); + return matchBytesLoopVersion(s, counted, { + locals: this.currentLocals, + invariantGlobals, + captured: this.captureIds, + ranges: this.integerRanges, + initialized, + proven: this.bytesBounds, + }); + } + + /** The alias tag of a whole-slot load of a binding (module globals only). */ + slotAlias(id: string): string { + const binding = this.binding(id); + return binding.kind === "global" ? globalSlotAlias(this, id, binding.type.kind) : ""; + } + binding(id: string): { kind: "global" | "local" | "boxed"; slot: string; diff --git a/packages/compiler/src/backend/llvm/expr-bytes.ts b/packages/compiler/src/backend/llvm/expr-bytes.ts index ac025df09..485b7a6b3 100644 --- a/packages/compiler/src/backend/llvm/expr-bytes.ts +++ b/packages/compiler/src/backend/llvm/expr-bytes.ts @@ -8,6 +8,7 @@ import { exactInteger, widenInteger } from "./integer-values.js"; import { byteNumberAccess } from "../../ir/byte-numbers.js"; import { emitByteNumber } from "./byte-numbers.js"; import { integerOrNaNRange } from "./wrapping-sums.js"; +import { bytesElementAlias, bytesHeaderAlias } from "./bytes-alias.js"; const BYTES_NUM_KIND: Record = { u8: { kind: 0, le: false }, @@ -93,10 +94,7 @@ export function emitBytesIndex( B.line(`${narrow} = trunc i64 ${wide} to ${host.sizeType}`); return narrow; } - const lenPtr = B.tmp(); - const len = B.tmp(); - B.line(`${lenPtr} = getelementptr inbounds %ScrBytes, ptr ${receiver}, i64 0, i32 1`); - B.line(`${len} = load ${host.sizeType}, ptr ${lenPtr}`); + const len = emitBytesHeaderLength(host, receiver); if (integer) { const wideIndex = widenInteger(host, integer); const wideLength = host.sizeType === "i64" ? len : B.tmp(); @@ -145,11 +143,20 @@ export function emitBytesIndex( return idx; } +/** The element count of a typed array, in the target's size type. */ +export function emitBytesHeaderLength(host: LlvmEmitterContext, receiver: string): string { + const p = host.B.tmp(); + const len = host.B.tmp(); + host.B.line(`${p} = getelementptr inbounds %ScrBytes, ptr ${receiver}, i64 0, i32 1`); + host.B.line(`${len} = load ${host.sizeType}, ptr ${p}${bytesHeaderAlias(host)}`); + return len; +} + export function emitBytesData(host: LlvmEmitterContext, receiver: string): string { const p = host.B.tmp(); const data = host.B.tmp(); host.B.line(`${p} = getelementptr inbounds %ScrBytes, ptr ${receiver}, i64 0, i32 3`); - host.B.line(`${data} = load ptr, ptr ${p}`); + host.B.line(`${data} = load ptr, ptr ${p}${bytesHeaderAlias(host)}`); return data; } @@ -160,10 +167,7 @@ export function emitBytesLength( bytes: boolean, ): LlValue { const B = host.B; - const p = B.tmp(); - const len = B.tmp(); - B.line(`${p} = getelementptr inbounds %ScrBytes, ptr ${receiver}, i64 0, i32 1`); - B.line(`${len} = load ${host.sizeType}, ptr ${p}`); + const len = emitBytesHeaderLength(host, receiver); const size = BYTES_ELEMENT_SIZE[elem]; const count = bytes && size !== 1 ? B.tmp() : len; if (count !== len) B.line(`${count} = shl ${host.sizeType} ${len}, ${Math.log2(size)}`); @@ -187,7 +191,7 @@ function emitSharedBytesSplit(host: LlvmEmitterContext, receiver: string): strin isShared = B.tmp(), expected = B.tmp(); B.line(`${slot} = getelementptr inbounds %ScrBytes, ptr ${receiver}, i64 0, i32 9`); - B.line(`${storage} = load ptr, ptr ${slot}`); + B.line(`${storage} = load ptr, ptr ${slot}${bytesHeaderAlias(host)}`); B.line(`${isShared} = icmp ne ptr ${storage}, null`); B.line(`${expected} = call i1 @llvm.expect.i1(i1 ${isShared}, i1 false)`); const shared = B.newLabel("bytes.shared"), @@ -257,9 +261,15 @@ function emitBytesLoad( inBounds: boolean, invalid: string | undefined, ): LlValue { + if (host.mod.workers) { + const idx = emitBytesIndex(host, receiver, index, expr, invalid, inBounds); + return emitSharedOrLocalLoad(host, elem, receiver, idx); + } + // The header is immutable, so the data pointer loads beside the length, + // ahead of the bounds branch: an unconditional load LICM can hoist. + const data = host.emitBytesData(receiver); const idx = emitBytesIndex(host, receiver, index, expr, invalid, inBounds); - if (host.mod.workers) return emitSharedOrLocalLoad(host, elem, receiver, idx); - return emitBytesLoadAt(host, elem, receiver, idx); + return emitBytesLoadAt(host, elem, data, idx); } /** Worker programs: the element at a checked index of a view that may be @@ -285,7 +295,7 @@ function emitSharedOrLocalLoad( const sharedDone = B.newLabel("bytes.shared.done"); B.br(sharedDone); B.startBlock(local); - const own = emitBytesLoadAt(host, elem, receiver, idx); + const own = emitBytesLoadAt(host, elem, host.emitBytesData(receiver), idx); const localDone = B.newLabel("bytes.local.done"); B.br(localDone); B.startBlock(localDone); @@ -306,15 +316,15 @@ function emitSharedOrLocalLoad( return { name: out, type: F64, uint32: u32 }; } -/** The element at a checked index of a thread-owned view. */ +/** The element at a checked index of a thread-owned view, given its data + * pointer. */ function emitBytesLoadAt( host: LlvmEmitterContext, elem: IrBytesElem, - receiver: string, + data: string, idx: string, ): LlValue { const B = host.B; - const data = host.emitBytesData(receiver); const p = B.tmp(); if (elem === "f16") { // Half-precision bits widen exactly; the runtime converts them. @@ -322,7 +332,7 @@ function emitBytesLoadAt( const raw = B.tmp(); const out = B.tmp(); B.line(`${p} = getelementptr inbounds i16, ptr ${data}, ${host.sizeType} ${idx}`); - B.line(`${raw} = load i16, ptr ${p}, align 1`); + B.line(`${raw} = load i16, ptr ${p}, align 1${bytesElementAlias(host)}`); B.line(`${out} = call double @scr_f16_to_f64(i16 zeroext ${raw})`); return { name: out, type: F64 }; } @@ -333,7 +343,7 @@ function emitBytesLoadAt( const wide = B.tmp(); const out = B.tmp(); B.line(`${p} = getelementptr inbounds i${bits}, ptr ${data}, ${host.sizeType} ${idx}`); - B.line(`${raw} = load i${bits}, ptr ${p}, align 1`); + B.line(`${raw} = load i${bits}, ptr ${p}, align 1${bytesElementAlias(host)}`); B.line(`${wide} = ${signed ? "sext" : "zext"} i${bits} ${raw} to i32`); B.line(`${out} = ${signed ? "sitofp" : "uitofp"} i32 ${wide} to double`); return { name: out, type: F64, uint32: wide }; @@ -342,20 +352,20 @@ function emitBytesLoadAt( const raw = B.tmp(); const out = B.tmp(); B.line(`${p} = getelementptr inbounds float, ptr ${data}, ${host.sizeType} ${idx}`); - B.line(`${raw} = load float, ptr ${p}, align 1`); + B.line(`${raw} = load float, ptr ${p}, align 1${bytesElementAlias(host)}`); B.line(`${out} = fpext float ${raw} to double`); return { name: out, type: F64 }; } if (elem === "f64") { const out = B.tmp(); B.line(`${p} = getelementptr inbounds double, ptr ${data}, ${host.sizeType} ${idx}`); - B.line(`${out} = load double, ptr ${p}, align 1`); + B.line(`${out} = load double, ptr ${p}, align 1${bytesElementAlias(host)}`); return { name: out, type: F64 }; } const raw = B.tmp(); const out = B.tmp(); B.line(`${p} = getelementptr inbounds i32, ptr ${data}, ${host.sizeType} ${idx}`); - B.line(`${raw} = load i32, ptr ${p}, align 1`); + B.line(`${raw} = load i32, ptr ${p}, align 1${bytesElementAlias(host)}`); B.line(`${out} = ${elem === "i32" ? "sitofp" : "uitofp"} i32 ${raw} to double`); return { name: out, type: F64, uint32: raw }; } @@ -465,6 +475,7 @@ export function emitBytesSet( const B = host.B; // Invalid integer-indexed writes are ignored after evaluating the RHS. const done = B.newLabel("bytes.store.done"); + const data = host.emitBytesData(receiver); const idx = emitBytesIndex(host, receiver, index, indexExpr, done, inBounds); if (host.mod.workers) { host.declare(`declare void @scr_bytes_shared_set(ptr, ${host.sizeType}, double)`); @@ -487,7 +498,6 @@ export function emitBytesSet( elem === "f16" || elem === "f32" || elem === "f64" ? null : host.emitToUint32(value.name, expr, value.uint32); - const data = host.emitBytesData(receiver); const p = B.tmp(); if (elem === "f16") { // One round-to-nearest-even step from the double, in the runtime. @@ -495,24 +505,24 @@ export function emitBytesSet( const narrowed = B.tmp(); B.line(`${narrowed} = call zeroext i16 @scr_f16_from_f64(double ${value.name})`); B.line(`${p} = getelementptr inbounds i16, ptr ${data}, ${host.sizeType} ${idx}`); - B.line(`store i16 ${narrowed}, ptr ${p}, align 1`); + B.line(`store i16 ${narrowed}, ptr ${p}, align 1${bytesElementAlias(host)}`); } else if (BYTES_ELEMENT_SIZE[elem] < 4) { const bits = BYTES_ELEMENT_SIZE[elem] * 8; const byte = B.tmp(); B.line(`${byte} = trunc i32 ${stored!} to i${bits}`); B.line(`${p} = getelementptr inbounds i${bits}, ptr ${data}, ${host.sizeType} ${idx}`); - B.line(`store i${bits} ${byte}, ptr ${p}, align 1`); + B.line(`store i${bits} ${byte}, ptr ${p}, align 1${bytesElementAlias(host)}`); } else if (elem === "f32") { const narrowed = B.tmp(); B.line(`${narrowed} = fptrunc double ${value.name} to float`); B.line(`${p} = getelementptr inbounds float, ptr ${data}, ${host.sizeType} ${idx}`); - B.line(`store float ${narrowed}, ptr ${p}, align 1`); + B.line(`store float ${narrowed}, ptr ${p}, align 1${bytesElementAlias(host)}`); } else if (elem === "f64") { B.line(`${p} = getelementptr inbounds double, ptr ${data}, ${host.sizeType} ${idx}`); - B.line(`store double ${value.name}, ptr ${p}, align 1`); + B.line(`store double ${value.name}, ptr ${p}, align 1${bytesElementAlias(host)}`); } else { B.line(`${p} = getelementptr inbounds i32, ptr ${data}, ${host.sizeType} ${idx}`); - B.line(`store i32 ${stored!}, ptr ${p}, align 1`); + B.line(`store i32 ${stored!}, ptr ${p}, align 1${bytesElementAlias(host)}`); } B.br(done); B.startBlock(done); diff --git a/packages/compiler/src/backend/llvm/expr-callbacks.ts b/packages/compiler/src/backend/llvm/expr-callbacks.ts index d71df333a..db1dca1af 100644 --- a/packages/compiler/src/backend/llvm/expr-callbacks.ts +++ b/packages/compiler/src/backend/llvm/expr-callbacks.ts @@ -1,6 +1,13 @@ /* Focused LLVM expression emission extracted from emitter.ts. */ import { InternalCompilerError } from "../../errors.js"; -import { type IrType, isRefCounted, isUnitType, typeEquals, typeKey } from "../../ir/ir.js"; +import { + type IrType, + UNDEFINED_T, + isRefCounted, + isUnitType, + typeEquals, + typeKey, +} from "../../ir/ir.js"; import { mangleGenResThunk, mangleRecordNew, mangleRecordStruct } from "../mangle.js"; import { FN_ATTRS, llFieldType, releaseSym, retainSym, traceArg, vAdapters } from "./shapes.js"; import { LlvmUnsupportedError } from "./unsupported.js"; @@ -68,6 +75,14 @@ export function raceAdapterFor(host: LlvmEmitterContext, from: IrType, to: IrTyp `define internal void @${sym}(ptr %dst, ptr %src) ${FN_ATTRS} { ; race ${key}`, `entry:`, ]; + if (from.kind === "void") { + // A Promise entry fulfills with undefined: the result's + // undefined arm, whatever the entry's payload slot holds. + const tag = tagOf(UNDEFINED_T); + d.push(` ${fulfill(host.unitInstanceRef(to.unionId, tag))}`, ` ret void`, `}`, ``); + host.resolveThunkDefs.push(...d); + return sym; + } if (from.kind !== "union") { // One arm wrap, straight off the payload accessors. const tag = tagOf(from); diff --git a/packages/compiler/src/backend/llvm/expr-containers.ts b/packages/compiler/src/backend/llvm/expr-containers.ts index a04f46f7b..0ca76e2d5 100644 --- a/packages/compiler/src/backend/llvm/expr-containers.ts +++ b/packages/compiler/src/backend/llvm/expr-containers.ts @@ -528,7 +528,7 @@ export function emitStableReceiver( if (b.kind !== "boxed") { if (b.kind === "global") host.checkGlobalTdz(receiver.localId); const value = host.B.tmp(); - host.B.line(`${value} = load ptr, ptr ${b.slot}`); + host.B.line(`${value} = load ptr, ptr ${b.slot}${host.slotAlias(receiver.localId)}`); return { name: value, type: receiver.type }; } } diff --git a/packages/compiler/src/backend/llvm/expr-primitives.ts b/packages/compiler/src/backend/llvm/expr-primitives.ts index 9cbd8de74..0d2cd90e8 100644 --- a/packages/compiler/src/backend/llvm/expr-primitives.ts +++ b/packages/compiler/src/backend/llvm/expr-primitives.ts @@ -116,7 +116,7 @@ export function emitLiteralExpr( return host.own({ name: host.adoptHeap(v, e.type), type: e.type }); } const t = B.tmp(); - B.line(`${t} = load ${host.llType(b.type)}, ptr ${b.slot}`); + B.line(`${t} = load ${host.llType(b.type)}, ptr ${b.slot}${host.slotAlias(e.localId)}`); const integerView = host.integerViews.get(e.localId); if (integerView !== undefined) { // Snapshot both representations before later operands can write diff --git a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts index 8a53b5fa8..134c74b92 100644 --- a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts +++ b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts @@ -5,10 +5,12 @@ import { streamTypedRefEligible, undefinedArmTag } from "../../ir/analysis.js"; import { type IrRecordShape, type IrType, + CLASS_ATTRIBUTES, DYN_CLASS_PROPERTIES, RUNTIME_STREAM_CLASSES, SYMBOL_T, classDynViewSupported, + classFieldAttributesName, isClassOwnEnumerableFieldName, isDirentShape, isDynTypedRefType, @@ -766,6 +768,7 @@ export function streamTypedRefMaterializeAdapter( host.declare(`declare ptr @scr_stream_dyn_view(ptr)`); B.line(`${out} = call ptr @scr_stream_dyn_view(ptr %p)`); } else B.line(`${out} = call ptr @scr_dyn_new_obj()`); + const withAttributes = meta.def.fields.some((field) => field.name === CLASS_ATTRIBUTES); if (meta.def.tracksOwnFields) { host.declare(`declare ptr @scr_dyn_copy_property_descriptors(ptr, ptr)`); host.declare(`declare void @scr_dyn_release_v(ptr)`); @@ -835,9 +838,27 @@ export function streamTypedRefMaterializeAdapter( const nullable = host.nullableFields.get(t.className, field.name); if (nullable) fieldValue = nullableFieldUnion(host, B, fieldValue, nullable); const boxed = host.streamTypedRefBoxValue(B, field.type, fieldValue); + // Attributes copied from the bag do not stop the view taking the value. + const setter = withAttributes ? "scr_dyn_obj_set_field" : "scr_dyn_obj_set"; + if (withAttributes) + host.declare(`declare void @scr_dyn_obj_set_field(ptr, ptr, ${host.sizeType}, ptr)`); B.line( - `call void @scr_dyn_obj_set(ptr ${out}, ptr ${host.cstr(field.name)}, ${host.sizeType} ${Buffer.byteLength(field.name, "utf8")}, ptr ${boxed})`, + `call void @${setter}(ptr ${out}, ptr ${host.cstr(field.name)}, ${host.sizeType} ${Buffer.byteLength(field.name, "utf8")}, ptr ${boxed})`, ); + // A field redefined through Object.defineProperty keeps its attributes. + const attributesField = classFieldAttributesName(field.name); + if (meta.def.fields.some((f) => f.name === attributesField)) { + host.declare(`declare void @scr_dyn_class_field_attributes(ptr, ptr, double)`); + const slot = B.tmp(), + bits = B.tmp(); + B.line( + `${slot} = getelementptr inbounds %${classStructSym(t.className)}, ptr %p, i64 0, i32 ${classFieldIndex(meta, attributesField).index}`, + ); + B.line(`${bits} = load double, ptr ${slot}`); + B.line( + `call void @scr_dyn_class_field_attributes(ptr ${out}, ptr ${host.internLiteral(field.name)}, double ${bits})`, + ); + } if (nullable) { host.declare(`declare void @scr_union_release(ptr)`); B.line(`call void @scr_union_release(ptr ${fieldValue})`); @@ -920,6 +941,17 @@ export function streamTypedRefMaterializeAdapter( B.line(`${copied} = call ptr @scr_dyn_copy_property_descriptors(ptr ${out}, ptr ${bag})`); B.line(`call void @scr_dyn_release_v(ptr ${copied})`); } + // A frozen, sealed or non-extensible instance's view says so. + if (withAttributes) { + host.declare(`declare void @scr_dyn_class_view_attributes(ptr, double)`); + const slot = B.tmp(), + bits = B.tmp(); + B.line( + `${slot} = getelementptr inbounds %${classStructSym(t.className)}, ptr %p, i64 0, i32 ${classFieldIndex(meta, CLASS_ATTRIBUTES).index}`, + ); + B.line(`${bits} = load double, ptr ${slot}`); + B.line(`call void @scr_dyn_class_view_attributes(ptr ${out}, double ${bits})`); + } B.terminate(`ret ptr ${out}`); } else if (t.kind === "record") { const shape = host.recordsById.get(t.shapeId); diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index e537d3d74..3c277cc8b 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -307,9 +307,12 @@ export const LIB_FN_SYMS: Record = { "process.rusage": "scr_process_rusage", "process.activeResources": "scr_active_resources", "process.exiting": "scr_process_exiting", + "process.ipcOpen": "scr_process_ipc_open", "process.exit": "scr_process_exit", "process.setExitCode": "scr_process_set_exit_code", "process.currentExitCode": "scr_process_exit_code_or_zero", + "process.setExitCodeTracked": "scr_process_set_exit_code_tracked", + "process.hasExitCode": "scr_process_has_exit_code", "process.envSet": "scr_env_set", "process.envUnset": "scr_env_unset", "process.envPairs": "scr_env_pairs", @@ -840,6 +843,7 @@ export const LIB_FN_SYMS: Record = { "dyn.sameValue": "scr_dyn_same_value", "error.toString": "scr_error_to_string", "error.stack": "scr_error_stack", + "error.setStack": "scr_error_set_stack", "error.stackLimitGet": "scr_stack_limit_get", "error.stackLimitSet": "scr_stack_limit_set", "class.name": "scr_classobj_name", @@ -939,6 +943,12 @@ export const LIB_FN_SYMS: Record = { "dyn.objectTag": "scr_dyn_object_tag", "dyn.freeze": "scr_dyn_freeze", "dyn.isFrozen": "scr_dyn_is_frozen", + "class.defineField": "scr_class_define_field", + "class.definedBits": "scr_class_defined_bits", + "class.definedValue": "scr_class_defined_value", + "class.descriptorHasValue": "scr_class_descriptor_has_value", + "class.throwReadOnly": "scr_class_throw_read_only", + "class.throwNotExtensible": "scr_class_throw_not_extensible", "dyn.nativeSetNew": "scr_dyn_native_set_new", "dyn.nativeSetIs": "scr_dyn_native_set_is", "dyn.nativeMapIs": "scr_dyn_native_map_is", diff --git a/packages/compiler/src/backend/llvm/receivers.ts b/packages/compiler/src/backend/llvm/receivers.ts index a1c771797..50b9485a1 100644 --- a/packages/compiler/src/backend/llvm/receivers.ts +++ b/packages/compiler/src/backend/llvm/receivers.ts @@ -50,7 +50,7 @@ export function emitReadReceiver(emitter: LlEmitter, e: IrExpr): LlValue { } if (binding.kind === "global") emitter.checkGlobalTdz(e.localId); const value = emitter.B.tmp(); - emitter.B.line(`${value} = load ptr, ptr ${binding.slot}`); + emitter.B.line(`${value} = load ptr, ptr ${binding.slot}${emitter.slotAlias(e.localId)}`); return { name: value, type: e.type }; } if (e.kind === "dynCheck" && e.exact) return emitter.emitExactCapsuleObject(e.value, e.type); diff --git a/packages/compiler/src/backend/stack-observations.test.ts b/packages/compiler/src/backend/stack-observations.test.ts index a95f0140f..0e1178ce9 100644 --- a/packages/compiler/src/backend/stack-observations.test.ts +++ b/packages/compiler/src/backend/stack-observations.test.ts @@ -1,5 +1,6 @@ import { expect, test } from "vitest"; import { + DYN, F64, STRING, VOID, @@ -49,6 +50,40 @@ test("a reachable stack read is observed", () => { expect(observesStacks(mod([fn("%main", [call("parse")]), fn("parse", [stackRead])]))).toBe(true); }); +test("a stack read on a checked-dynamic value is observed", () => { + const value: IrExpr = { loc, kind: "varRef", localId: "d", type: DYN }; + const read = (key: string): IrStmt => ({ + loc, + kind: "exprStmt", + expr: { + loc, + kind: "dynKeyGet", + value, + key: { loc, kind: "strLit", value: key, type: STRING }, + type: DYN, + }, + }); + expect(observesStacks(mod([fn("%main", [read("stack")])]))).toBe(true); + expect(observesStacks(mod([fn("%main", [read("message")])]))).toBe(false); +}); + +test("a computed key reads the stack when the program spells it", () => { + const value: IrExpr = { loc, kind: "varRef", localId: "d", type: DYN }; + const key: IrExpr = { loc, kind: "varRef", localId: "k", type: STRING }; + const computed: IrStmt = { + loc, + kind: "exprStmt", + expr: { loc, kind: "dynKeyGet", value, key, type: DYN }, + }; + const spelled: IrStmt = { + loc, + kind: "exprStmt", + expr: { loc, kind: "strLit", value: "stack", type: STRING }, + }; + expect(observesStacks(mod([fn("%main", [computed, spelled])]))).toBe(true); + expect(observesStacks(mod([fn("%main", [computed])]))).toBe(false); +}); + test("programs without stack reads are not", () => { expect(observesStacks(mod([fn("%main", [call("helper")]), fn("helper", [ret])]))).toBe(false); }); diff --git a/packages/compiler/src/backend/stack-observations.ts b/packages/compiler/src/backend/stack-observations.ts index 7debf0751..cc6d109e4 100644 --- a/packages/compiler/src/backend/stack-observations.ts +++ b/packages/compiler/src/backend/stack-observations.ts @@ -13,12 +13,34 @@ import { writesPublished } from "./publication.js"; /** Lib calls that read a captured stack trace. */ const STACK_READS: ReadonlySet = new Set(["error.stack"]); -function readsStack(expr: IrExpr): boolean { - return expr.kind === "libCall" && STACK_READS.has(expr.fn); +/** A typed `error.stack` read, or a read on a checked-dynamic value that + * can reach an error's own `stack` accessor: the constant key `stack`, or + * a computed key when `computedKeys` (the program spells "stack", so a + * computed key can name it). A key the program assembles from other + * strings or from data it reads keeps the static answer. */ +function readsStack(expr: IrExpr, computedKeys: boolean): boolean { + if (expr.kind === "libCall") return STACK_READS.has(expr.fn); + if (expr.kind !== "dynKeyGet") return false; + if (expr.key.kind === "strLit") return expr.key.value === "stack"; + return computedKeys; } -function containsStackRead(fn: IrFunction): boolean { - return !everyStmtList(fn.body, { stmt: () => true, expr: (expr) => !readsStack(expr) }); +/** Whether the module contains the string literal "stack". */ +function spellsStack(mod: IrModule): boolean { + return mod.functions.some( + (fn) => + !everyStmtList(fn.body, { + stmt: () => true, + expr: (expr) => !(expr.kind === "strLit" && expr.value === "stack"), + }), + ); +} + +function containsStackRead(fn: IrFunction, computedKeys: boolean): boolean { + return !everyStmtList(fn.body, { + stmt: () => true, + expr: (expr) => !readsStack(expr, computedKeys), + }); } /** Visit every expression of `body` that execution can reach: statements @@ -43,7 +65,8 @@ function visitLiveExprs(body: IrStmt[], visit: (expr: IrExpr) => void): void { * and those reads must not cost every call of the program a frame. * Programs without any stack read answer false without the walk. */ export function observesStacks(mod: IrModule): boolean { - if (!mod.functions.some(containsStackRead)) return false; + const computedKeys = spellsStack(mod); + if (!mod.functions.some((fn) => containsStackRead(fn, computedKeys))) return false; const byName = new Map(mod.functions.map((fn) => [fn.name, fn])); const classNames = new Set((mod.classes ?? []).map((cls) => cls.name)); const pending: string[] = [...moduleFunctionReferences(mod)]; @@ -67,7 +90,7 @@ export function observesStacks(mod: IrModule): boolean { const fn = byName.get(name); if (fn === undefined) continue; visitLiveExprs(fn.body, (expr) => { - if (readsStack(expr)) observed = true; + if (readsStack(expr, computedKeys)) observed = true; if (expr.kind === "call" && !reached.has(expr.callee)) pending.push(expr.callee); const referenced = exprFunctionReference(expr); if (referenced !== undefined && !reached.has(referenced)) pending.push(referenced); diff --git a/packages/compiler/src/frontend/helper-tokens.test.ts b/packages/compiler/src/frontend/helper-tokens.test.ts index c6355cef9..522b39545 100644 --- a/packages/compiler/src/frontend/helper-tokens.test.ts +++ b/packages/compiler/src/frontend/helper-tokens.test.ts @@ -27,6 +27,8 @@ test.each([ ['"default"', '"default;s3:foo;"'], ['"default"', '"default\\0"'], ["mod", "mod other"], + ["cb[0]", "cb[1]"], + ["cb[1]", "cb[10]"], ])("retains a semantic difference between %s and %s", (a, b) => { expect(helperTokens(a)).not.toBe(helperTokens(b)); }); @@ -44,8 +46,12 @@ test.each([ "'\\8'", "`template`", "/regexp/", - "0", "0x10", + "07", + "1.5", + "1e3", + "1n", + "1_000", "a / b", "\\u0061", "café", diff --git a/packages/compiler/src/frontend/helper-tokens.ts b/packages/compiler/src/frontend/helper-tokens.ts index d7a968755..908cc0d22 100644 --- a/packages/compiler/src/frontend/helper-tokens.ts +++ b/packages/compiler/src/frontend/helper-tokens.ts @@ -1,8 +1,8 @@ /** Token fingerprints for the fixed bundler helpers we recognize. This is * deliberately not a JavaScript parser: regexes, templates, escaped names, - * numbers, and unknown punctuation refuse the helper. None occur in the - * canonical helpers. Every accepted token is represented in the result; - * comments and whitespace alone may disappear. */ + * numbers other than plain decimal integers, and unknown punctuation refuse + * the helper. None occur in the canonical helpers. Every accepted token is + * represented in the result; comments and whitespace alone may disappear. */ const operators = [ ">>>=", "===", @@ -157,6 +157,15 @@ export function helperTokens(text: string): string | null { result += fingerprint("s", token.value); i = token.end; previous = "string"; + } else if (/[0-9]/.test(ch)) { + // Plain decimal integers only (esbuild's `cb[keys(cb)[0]]`): a + // legacy octal, fraction, exponent, radix prefix, BigInt suffix or + // numeric separator refuses rather than aliasing another value. + const start = i++; + while (i < text.length && /[0-9]/.test(text.charAt(i))) i++; + if (/[A-Za-z0-9_$.\\]/.test(text.charAt(i)) || (ch === "0" && i - start > 1)) return null; + previous = text.slice(start, i); + result += fingerprint("n", previous); } else if (/[A-Za-z_$]/.test(ch)) { const start = i++; while (i < text.length && /[A-Za-z0-9_$]/.test(text.charAt(i))) i++; diff --git a/packages/compiler/src/frontend/input-tracker.ts b/packages/compiler/src/frontend/input-tracker.ts index 304a21cfa..fa2e92568 100644 --- a/packages/compiler/src/frontend/input-tracker.ts +++ b/packages/compiler/src/frontend/input-tracker.ts @@ -164,8 +164,28 @@ export function markFrontendInputsUnstable(): void { (synchronousTracker ?? activeTracker.getStore())?.markUnstable(); } +/** Compiler-synthesized module sources (a bundle's CommonJS chunks split + * into sibling modules, npm-static-bundled-chunks.ts). They answer like + * regular files but are never recorded: each derives from the content of + * a recorded bundle read, which already keys every cache that sees it. */ +const virtualSources = new Map(); + +export function setVirtualSource(path: string, text: string): void { + virtualSources.set(resolve(path), text); +} + +export function isVirtualSource(path: string): boolean { + return virtualSources.has(resolve(path)); +} + +export function clearVirtualSources(): void { + virtualSources.clear(); +} + export function trackedReadFile(path: string): string | null { path = resolve(path); + const virtual = virtualSources.get(path); + if (virtual !== undefined) return virtual; try { const text = readFileSync(path, "utf8"); record({ op: "file", path, digest: frontendSourceDigest(text) }); @@ -178,6 +198,7 @@ export function trackedReadFile(path: string): string | null { export function trackedFileExists(path: string): boolean { path = resolve(path); + if (virtualSources.has(path)) return true; const kind = pathKind(path); record({ op: "kind", path, kind }); return kind === "file"; @@ -185,6 +206,7 @@ export function trackedFileExists(path: string): boolean { export function trackedDirectoryExists(path: string): boolean { path = resolve(path); + if (virtualSources.has(path)) return false; const kind = pathKind(path); record({ op: "kind", path, kind }); return kind === "directory"; @@ -192,6 +214,7 @@ export function trackedDirectoryExists(path: string): boolean { export function trackedExists(path: string): boolean { path = resolve(path); + if (virtualSources.has(path)) return true; const kind = pathKind(path); record({ op: "kind", path, kind }); return kind !== "missing"; @@ -199,6 +222,7 @@ export function trackedExists(path: string): boolean { export function trackedRealpath(path: string): string | null { path = resolve(path); + if (virtualSources.has(path)) return path; try { const target = systemRealpath(path); record({ op: "realpath", path, target }); @@ -223,9 +247,13 @@ export function trackedAccessibleEntries( } files.sort(); directories.sort(); - const answer = { files, directories }; - record({ op: "entries", path, files, directories }); - return answer; + record({ op: "entries", path, files: [...files], directories }); + for (const virtual of virtualSources.keys()) { + if (dirname(virtual) === path && !files.includes(basename(virtual))) + files.push(basename(virtual)); + } + files.sort(); + return { files, directories }; } catch { // Enumeration can fail even while the path remains a directory. Preserve // the failed operation itself so a permission/ACL repair invalidates the diff --git a/packages/compiler/src/frontend/lowering/assertion-members.ts b/packages/compiler/src/frontend/lowering/assertion-members.ts new file mode 100644 index 000000000..d61c379d6 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/assertion-members.ts @@ -0,0 +1,168 @@ +/* Members a type assertion attaches to record values. */ +import * as ts from "../ts7/adapter.js"; +import type { Lowerer } from "./lowerer.js"; +import { type IrType, typeEquals } from "../../ir/ir.js"; +import { hostsAll } from "./expressions/hosted-narrowing.js"; + +/** `route as Route & { order: number; internal: boolean }` followed by + * `view.internal = true` adds a property to the very object `route` + * names: Node has no layouts, so every later read of `route` (its JSON, + * its keys, a spread) sees the member. Native records are closed structs, + * and the asserted intersection maps to a different struct, so neither a + * conversion (a copy that severs the write from `route`) nor an erasure + * (a struct without the slot) is faithful. + * + * This pass finds such assertions before any body lowers and gives each + * record arm of the operand's type the asserted members it does not + * declare, as optional fields. Values the program builds hold them absent, + * which is invisible to every key surface (`in`, Object.keys, JSON, + * inspect, spread). The asserted type then refines the stored arms + * instead of naming new ones (hosted-narrowing.ts), so the assertion keeps + * the value and its writes land in the stored object. + * + * Only the plain form qualifies: one intersection whose constituents are + * the operand's own type and type literals of required property + * signatures, over plain data types (object types, aliases and interfaces; + * not classes or the standard library's types). Arms that are tuples or + * carry an index signature, members whose type does not map, and members + * two assertions type differently are left alone: those assertions keep + * their exact-shape diagnostics. Assertions whose operand already declares + * every member are skipped before any type maps, so programs without the + * form intern exactly the types they did before. */ +export function extendAssertedRecordMembers( + lowerer: Lowerer, + files: readonly ts.SourceFile[], +): void { + const additions = new Map>(); + const conflicts = new Set(); + const consider = (node: ts.AsExpression | ts.TypeAssertion): void => { + let typeNode: ts.TypeNode = node.type; + while (ts.isParenthesizedTypeNode(typeNode)) typeNode = typeNode.type; + if (!ts.isIntersectionTypeNode(typeNode)) return; + const parts = typeNode.types.nodes; + const literals = parts.filter((p) => ts.isTypeLiteralNode(p)); + const bases = parts.filter((p) => !ts.isTypeLiteralNode(p)); + if (literals.length === 0 || bases.length !== 1) return; + const memberNodes: { name: string; type: ts.TypeNode }[] = []; + for (const literal of literals) { + if (!ts.isTypeLiteralNode(literal)) return; + for (const member of literal.members.nodes) { + // A required member: the form that writes through the view. An + // optional one only reads, and keeps its exact-shape fence. + if (!ts.isPropertySignatureDeclaration(member) || !member.type || member.questionToken) + return; + const name = ts.isIdentifier(member.name) + ? member.name.text + : ts.isStringLiteral(member.name) + ? member.name.text + : null; + if (name === null || name.startsWith("%")) return; + memberNodes.push({ name, type: member.type }); + } + } + // Checker-only gate first: an assertion every constituent of whose + // operand type already declares the members (`e as Expr & { kind: + // "mul" }`, the refinement idiom) attaches nothing, and mapping its + // types here would intern them out of the usual order. + const operandTs = lowerer.typeOf(node.expression); + const constituents = operandTs.isUnionType() ? ts.constituentTypes(operandTs) : [operandTs]; + const declares = (t: ts.Type, name: string): boolean => + lowerer.checker.getPropertyOfType(t, name) !== undefined; + if (constituents.every((t) => memberNodes.every((m) => declares(t, m.name)))) return; + // Plain data types only: object literal types, aliases and interfaces + // (not classes, and not the standard library's types). + const dataType = (t: ts.Type): boolean => { + const symbol = t.getAliasSymbol() ?? t.getSymbol(); + return ( + !!symbol && + (symbol.flags & ts.SymbolFlags.Class) === 0 && + symbol.declarations.length > 0 && + symbol.declarations.every( + (d) => + !lowerer.isStdlibFile(d.getSourceFile()) && + (ts.isTypeLiteralNode(d) || + ts.isInterfaceDeclaration(d) || + ts.isTypeAliasDeclaration(d)), + ) + ); + }; + if (!constituents.every(dataType)) return; + const operand = lowerer.mapTypeOf(operandTs); + const base = lowerer.mapTypeOf(lowerer.checker.getTypeFromTypeNode(bases[0]!)); + if (!operand || !base || !typeEquals(operand, base)) return; + const arms = + operand.kind === "union" ? (lowerer.unions.get(operand.unionId)?.arms ?? []) : [operand]; + if (arms.length === 0) return; + const shapeIds: string[] = []; + for (const arm of arms) { + if (arm.kind !== "record") return; + const shape = lowerer.shapes.get(arm.shapeId); + if (!shape || shape.tuple || shape.indexValue) return; + shapeIds.push(arm.shapeId); + } + const members: { name: string; type: IrType }[] = []; + for (const { name, type } of memberNodes) { + if (shapeIds.every((id) => lowerer.shapes.get(id)!.fields.some((f) => f.name === name))) + continue; + const mapped = lowerer.mapTypeOf(lowerer.checker.getTypeFromTypeNode(type)); + if (!mapped || mapped.kind === "void") return; + const optional = lowerer.withUndefinedArmOf(mapped); + if (!optional) return; + members.push({ name, type: optional }); + } + for (const shapeId of shapeIds) { + const shape = lowerer.shapes.get(shapeId)!; + for (const member of members) { + if (shape.fields.some((f) => f.name === member.name)) continue; + let added = additions.get(shapeId); + if (!added) additions.set(shapeId, (added = new Map())); + const prior = added.get(member.name); + if (prior && !typeEquals(prior, member.type)) conflicts.add(`${shapeId}:${member.name}`); + else added.set(member.name, member.type); + } + } + }; + const visit = (node: ts.Node): void => { + if (ts.isAsExpression(node) || ts.isTypeAssertion(node)) consider(node); + ts.forEachChild(node, visit); + }; + for (const sf of files) { + if (sf.isDeclarationFile) continue; + // Cheap text gate: the form needs an intersection with a type literal. + if (!/&\s*\{/.test(sf.text)) continue; + visit(sf); + } + for (const [shapeId, added] of additions) { + const extra = [...added] + .filter(([name]) => !conflicts.has(`${shapeId}:${name}`)) + .map(([name, type]) => ({ name, type })); + lowerer.shapes.extendShape(shapeId, extra); + } + if (additions.size > 0) keepStoredTypeOfAssertedGlobals(lowerer, files); +} + +/** A module-level `const view = value as T & { member: X }` binding keeps + * the stored type of `value` once the members are attached, exactly as a + * local binding does (lowerVarDecl): the assertion keeps the object, and + * writes through the binding must reach it. Globals took their checker + * (or annotated) type during collection, before the members existed; an + * annotation the stored type hosts gives way to it the same way. */ +function keepStoredTypeOfAssertedGlobals(lowerer: Lowerer, files: readonly ts.SourceFile[]): void { + for (const sf of files) { + if (sf.isDeclarationFile) continue; + for (const statement of sf.statements.nodes) { + if (!ts.isVariableStatement(statement)) continue; + if ((statement.declarationList.flags & ts.NodeFlags.Const) === 0) continue; + for (const decl of statement.declarationList.declarations.nodes) { + if (!ts.isIdentifier(decl.name) || !decl.initializer) continue; + let init: ts.Expression = decl.initializer; + while (ts.isParenthesizedExpression(init)) init = init.expression; + if (!ts.isAsExpression(init) && !ts.isTypeAssertion(init)) continue; + const global = lowerer.globalOf(decl.name); + const stored = lowerer.mapTypeOf(lowerer.typeOf(init.expression)); + if (!global || !stored || (stored.kind !== "union" && stored.kind !== "record")) continue; + if (hostsAll(lowerer, stored, global.type)) global.type = stored; + } + } + } +} diff --git a/packages/compiler/src/frontend/lowering/builtin-calls.ts b/packages/compiler/src/frontend/lowering/builtin-calls.ts index 7d3a5d41a..f83958b32 100644 --- a/packages/compiler/src/frontend/lowering/builtin-calls.ts +++ b/packages/compiler/src/frontend/lowering/builtin-calls.ts @@ -13,6 +13,7 @@ import { lowerEventsEmitterHelper, lowerEventsOnce } from "./lower-event-emitter import type { Lowerer } from "./lowerer.js"; import { lowerTimersMemberCall } from "./lower-timers.js"; import { lowerStreamModuleCall } from "./lower-stream.js"; +import { lowerCallbackPromisify } from "./builtins/promisify-callback.js"; import { lowerNodeModuleCall } from "./builtins/module-resolution.js"; import { builtinModuleFnOf, builtinFenceHintOf } from "./surfaces.js"; @@ -91,6 +92,10 @@ export function lowerBuiltinCall( if (testServed) return testServed; const utilServed = lowerer.lowerUtilModuleCall(expr, bi, loc); if (utilServed) return utilServed; + if (bi.module === "util" && bi.member === "promisify") { + const promisified = lowerCallbackPromisify(lowerer, expr, loc); + if (promisified) return promisified; + } const streamServed = lowerStreamModuleCall(lowerer, expr, bi, loc); if (streamServed) return streamServed; const fsTs = lowerer.lowerFsToUnixTimestampCall(expr, bi, loc); diff --git a/packages/compiler/src/frontend/lowering/builtins/callable-aliases.ts b/packages/compiler/src/frontend/lowering/builtins/callable-aliases.ts index 1669978af..afb221d04 100644 --- a/packages/compiler/src/frontend/lowering/builtins/callable-aliases.ts +++ b/packages/compiler/src/frontend/lowering/builtins/callable-aliases.ts @@ -1,11 +1,12 @@ import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; -import { isJsSourceFile } from "../../program.js"; +import { isJsSourceFile, locOf } from "../../program.js"; import { builtinModuleFnOf } from "../surfaces.js"; import { registerHttpClientFnBinding } from "../lower-server.js"; import { isPromisifiedZlibMember } from "./compression.js"; import { isPromisifiedCryptoMember } from "./crypto.js"; import { isPromisifiedDnsMember } from "../lower-dgram.js"; +import { callbackPromisifyShape } from "./promisify-callback.js"; /** Compile-time util.promisify projections. The immutable result binding * owns no runtime slot: calls rewrite to the target's promise lowering, @@ -164,11 +165,14 @@ export function registerPromisifiedBuiltinDecl( : target?.module === "dns" && isPromisifiedDnsMember(target.member) ? { kind: "promisified-dns" as const, member: target.member } : null; + // A typed callback-last function value: the call lowers to a native + // promisified function, and the binding holds it like any closure. + if (!projection && callbackPromisifyShape(lowerer, e, locOf(e)) !== null) return false; if (!projection) { lowerer.noLowering( "util.promisify of this target", argNode ?? e, - "child_process.exec, child_process.execFile, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots, the crypto callback functions (randomBytes, pbkdf2, scrypt, hkdf, randomFill, randomInt, generateKey), dns.lookup, dns.lookupService and the fs callback functions with an fs/promises counterpart are the supported targets", + "child_process.exec, child_process.execFile, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots, the crypto callback functions (randomBytes, pbkdf2, scrypt, hkdf, randomFill, randomInt, generateKey), dns.lookup, dns.lookupService, the fs callback functions with an fs/promises counterpart, and typed callback-last functions whose callback takes (error?: Error | null, value?) are the supported targets", ); } const symbol = lowerer.checker.getSymbolAtLocation(nameNode); diff --git a/packages/compiler/src/frontend/lowering/builtins/ipc.ts b/packages/compiler/src/frontend/lowering/builtins/ipc.ts index cf9d96117..90448854d 100644 --- a/packages/compiler/src/frontend/lowering/builtins/ipc.ts +++ b/packages/compiler/src/frontend/lowering/builtins/ipc.ts @@ -1,7 +1,17 @@ import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; import { locOf } from "../../program.js"; -import { BOOL, type IrExpr, type IrType, STRING, type SrcLoc } from "../../../ir/ir.js"; +import { + BOOL, + type IrExpr, + type IrStmt, + type IrType, + STRING, + type SrcLoc, + UNDEFINED_T, +} from "../../../ir/ir.js"; +import { nodeThrowExpr } from "../../../ir/build.js"; +import { processHasIpc } from "./process.js"; /** Method calls on ChildProcess receivers: `child.on("exit"|"error", cb)` * registers a listener with the event loop's child registry. The event @@ -86,8 +96,54 @@ export function ipcSendCallback(lowerer: Lowerer, node: ts.Expression): IrExpr { return cb; } +/** process.send in a program without fork targets. This binary never opens + * a channel then, so only a Node.js parent's NODE_CHANNEL_FD can define + * process.send, and that channel has no lowering: a call fences when it runs. + * Without any channel the calls behave as Node's do on an undefined member: + * `process.send?.(...)` skips its arguments and answers undefined, and + * `process.send(...)` evaluates them and throws a TypeError. The message is + * never sent, so its type is not checked. */ +function lowerChannelLessSend(lowerer: Lowerer, call: ts.CallExpression): IrExpr { + const loc = locOf(call); + const fence = (type: IrType): IrExpr => + nodeThrowExpr( + 0, + "SC2020", + "process.send over an IPC channel opened by a Node.js parent (NODE_CHANNEL_FD) is not supported yet", + type, + loc, + ); + const hasIpc = processHasIpc(lowerer, loc); + if (call.questionDotToken) { + const type = lowerer.mapTypeOf(lowerer.typeOf(call)) ?? BOOL; + const absent: IrExpr = + type.kind === "bool" + ? { kind: "boolLit", value: false, type: BOOL, loc } + : lowerer.coerceToExpected( + { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, + type, + ); + return { kind: "ternary", cond: hasIpc, then: fence(type), else_: absent, type, loc }; + } + const stmts: IrStmt[] = call.arguments.nodes.map((arg) => ({ + kind: "exprStmt", + expr: lowerer.lowerExpr(ts.isSpreadElement(arg) ? arg.expression : arg), + loc: locOf(arg), + })); + const result: IrExpr = { + kind: "ternary", + cond: hasIpc, + then: fence(BOOL), + else_: nodeThrowExpr(1, "", "process.send is not a function", BOOL, loc), + type: BOOL, + loc, + }; + return stmts.length === 0 ? result : { kind: "seqExpr", stmts, result, type: BOOL, loc }; +} + export function lowerProcessIpcSend(lowerer: Lowerer, call: ts.CallExpression): IrExpr { const loc = locOf(call); + if (lowerer.forkTargets.length === 0) return lowerChannelLessSend(lowerer, call); if ( call.arguments.nodes.length < 1 || call.arguments.nodes.length > 2 || diff --git a/packages/compiler/src/frontend/lowering/builtins/process.ts b/packages/compiler/src/frontend/lowering/builtins/process.ts index 555eaf84f..dc2f5ee89 100644 --- a/packages/compiler/src/frontend/lowering/builtins/process.ts +++ b/packages/compiler/src/frontend/lowering/builtins/process.ts @@ -17,6 +17,7 @@ import { type IrExpr, type IrLibFn, type IrStmt, + type IrType, STRING, type SrcLoc, UNDEFINED_T, @@ -30,6 +31,144 @@ import { canonicalBuiltinModule } from "../../builtin-modules.js"; import { lowerProcessIpcSend, ipcMessageListener, ipcDisconnectListener } from "./ipc.js"; import { lowerDiagnosticsSubscriber, lowerTracingArguments } from "./async-context.js"; +/** Whether the process has an IPC channel, Node's test for defining + * process.send and process.disconnect: a channel this fork child opened + * (programs with fork targets only), or a non-empty NODE_CHANNEL_FD from a + * Node.js parent, the variable Node itself tests at startup. Built from the + * existing environment read, so the presence test links no runtime code. */ +export function processHasIpc(lowerer: Lowerer, loc: SrcLoc): IrExpr { + const envT = lowerer.envValueType(); + const unionId = (envT as IrType & { kind: "union" }).unionId; + const stringTag = lowerer.armTag(unionId, STRING); + const value = lowerer.declareHiddenLocal("%channelFd", envT); + const fromNode: IrExpr = { + kind: "seqExpr", + stmts: [ + { + kind: "varDecl", + localId: value.id, + init: { + kind: "libCall", + fn: "process.envGet", + args: [strLit("NODE_CHANNEL_FD", loc)], + type: envT, + loc, + }, + loc, + }, + ], + result: { + kind: "logical", + op: "&&", + left: { + kind: "unionIsTag", + unionId, + tag: stringTag, + negated: false, + value: varRef(value.id, envT, loc), + type: BOOL, + loc, + }, + right: { + kind: "toBool", + operand: { + kind: "unionNarrow", + unionId, + tag: stringTag, + value: varRef(value.id, envT, loc), + type: STRING, + loc, + }, + type: BOOL, + loc, + }, + type: BOOL, + loc, + }, + type: BOOL, + loc, + }; + if (lowerer.forkTargets.length === 0) return fromNode; + return { + kind: "logical", + op: "||", + left: { kind: "libCall", fn: "process.ipcOpen", args: [], type: BOOL, loc }, + right: fromNode, + type: BOOL, + loc, + }; +} + +/** True when the value of `node` is consumed only by ToBoolean: a + * condition, the operand of `!`, `Boolean(node)`, or an operand of `&&` / + * `||` whose own value is consumed that way (or discarded, for the left + * operand). */ +export function isTruthinessOnlyRead(lowerer: Lowerer, node: ts.Expression): boolean { + let child: ts.Node = node; + let parent = node.parent; + while (parent !== undefined && ts.isParenthesizedExpression(parent)) { + child = parent; + parent = parent.parent; + } + if (parent === undefined) return false; + if (ts.isIfStatement(parent) || ts.isWhileStatement(parent) || ts.isDoStatement(parent)) + return parent.expression === child; + if (ts.isForStatement(parent)) return parent.condition === child; + if (ts.isConditionalExpression(parent)) return parent.condition === child; + if (ts.isPrefixUnaryExpression(parent)) return parent.operator === ts.SyntaxKind.ExclamationToken; + if (ts.isCallExpression(parent)) { + return ( + !parent.questionDotToken && + parent.arguments.nodes.length === 1 && + parent.arguments.nodes[0] === child && + lowerer.isStdlibGlobal(parent.expression, "Boolean") + ); + } + if (ts.isBinaryExpression(parent)) { + const op = parent.operatorToken.kind; + if (op !== ts.SyntaxKind.AmpersandAmpersandToken && op !== ts.SyntaxKind.BarBarToken) + return false; + if (isTruthinessOnlyRead(lowerer, parent)) return true; + let outer: ts.Node | undefined = parent.parent; + while (outer !== undefined && ts.isParenthesizedExpression(outer)) outer = outer.parent; + return parent.left === child && outer !== undefined && ts.isExpressionStatement(outer); + } + return false; +} + +/** Whether a program source reads process.exitCode. Such a program + * records its exit-code assignments (process.setExitCodeTracked), so a + * read can tell an unset code from 0; other programs keep the untracked + * write. Computed once per lowering pass. */ +export function programReadsExitCode(lowerer: Lowerer): boolean { + if (lowerer.readsExitCode !== null) return lowerer.readsExitCode; + let found = false; + const walk = (node: ts.Node): void => { + if (found) return; + if ( + ts.isPropertyAccessExpression(node) && + node.name.text === "exitCode" && + !( + ts.isBinaryExpression(node.parent) && + node.parent.left === node && + node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken + ) && + lowerer.stdlibGlobalMember(node, "process") === "exitCode" + ) { + found = true; + return; + } + ts.forEachChild(node, walk); + }; + for (const sf of lowerer.program.getImplementationSourceFiles()) { + if (sf.isDeclarationFile) continue; + walk(sf); + if (found) break; + } + lowerer.readsExitCode = found; + return found; +} + /** The pinned Node release the runtime reports as process.versions.node * (packages/runtime/src/scr_lib.c SCR_NODE_COMPAT_VERSION, kept equal to * internal/compatibility/node-v24.json by test/node-pin.test.ts). */ @@ -374,9 +513,45 @@ export function lowerProcessProperty( const member = lowerer.stdlibGlobalMember(expr, "process"); if (member === null) return null; const loc = locOf(expr); + // `if (process.send)`: Node defines process.send and process.disconnect + // only when the process has an IPC channel. A read whose value only + // feeds a truthiness test answers that presence; other value uses keep + // the member fence. + if ( + (member === "send" || member === "disconnect") && + !expr.questionDotToken && + isTruthinessOnlyRead(lowerer, expr) + ) { + return processHasIpc(lowerer, loc); + } if (member === "versions") { return { kind: "libCall", fn: "process.versions", args: [], type: DYN, loc }; } + // process.exitCode: undefined until something assigns it, then the + // assigned code. A read the checker narrowed to number follows an + // assignment, so the code is set. + if (member === "exitCode" && !expr.questionDotToken) { + const current: IrExpr = { + kind: "libCall", + fn: "process.currentExitCode", + args: [], + type: F64, + loc, + }; + if (lowerer.mapTypeOf(lowerer.typeOf(expr))?.kind === "f64") return current; + const type: IrType = { kind: "union", unionId: lowerer.unions.intern([F64, UNDEFINED_T]) }; + return { + kind: "ternary", + cond: { kind: "libCall", fn: "process.hasExitCode", args: [], type: BOOL, loc }, + then: lowerer.coerceToExpected(current, type), + else_: lowerer.coerceToExpected( + { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, + type, + ), + type, + loc, + }; + } // process.features as a value (`"sea" in process.features`): an object // holding none of the flags, consistent with the member reads above. if (member === "features") { @@ -1575,10 +1750,36 @@ export function lowerProcessMethodCall( } if (member === "exit") { const arg = call.arguments.nodes[0]; - const code: IrExpr = + let code: IrExpr = arg !== undefined ? lowerer.lowerExprExpecting(arg, F64) : { kind: "libCall", fn: "process.currentExitCode", args: [], type: F64, loc }; + // process.exit(code) assigns process.exitCode before the 'exit' + // listeners run. Only a program that reads the property can observe + // that, so only such a program records the assignment. + if (arg !== undefined && programReadsExitCode(lowerer)) { + const binding = lowerer.declareHiddenLocal("%exitCode", F64); + code = { + kind: "seqExpr", + stmts: [ + { kind: "varDecl", localId: binding.id, init: code, loc }, + { + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "process.setExitCodeTracked", + args: [varRef(binding.id, F64, loc)], + type: VOID, + loc, + }, + loc, + }, + ], + result: varRef(binding.id, F64, loc), + type: F64, + loc, + }; + } return { kind: "libCall", fn: "process.exit", args: [code], type: VOID, loc }; } return null; // process.argv(...) etc. are tsc errors before lowering @@ -1594,6 +1795,16 @@ export function lowerProcessOptionalMethodCall( lowerer: Lowerer, expr: ts.CallExpression, ): IrExpr | null { + // `process.send!(message)`: the asserted direct call of the optional + // member (the @types/node spelling under strict null checks). + if ( + !expr.questionDotToken && + ts.isNonNullExpression(expr.expression) && + ts.isPropertyAccessExpression(expr.expression.expression) && + !expr.expression.expression.questionDotToken && + lowerer.stdlibGlobalMember(expr.expression.expression, "process") === "send" + ) + return lowerProcessIpcSend(lowerer, expr); if (!expr.questionDotToken) return null; if (!ts.isPropertyAccessExpression(expr.expression)) return null; const member = lowerer.stdlibGlobalMember(expr.expression, "process"); diff --git a/packages/compiler/src/frontend/lowering/builtins/promises.ts b/packages/compiler/src/frontend/lowering/builtins/promises.ts index 2656da18b..48106d082 100644 --- a/packages/compiler/src/frontend/lowering/builtins/promises.ts +++ b/packages/compiler/src/frontend/lowering/builtins/promises.ts @@ -65,6 +65,9 @@ export function lowerPromiseStaticCall( const compatible = (inner: IrType): boolean => { if (typeEquals(inner, resultT.inner)) return true; if (!resultArms) return false; + // A Promise entry fulfills with undefined, which the result + // holds when the checker folded `void` into its undefined arm. + if (inner.kind === "void") return resultArms.some((a) => a.kind === "undefinedT"); if (inner.kind === "union") { const arms = lowerer.unions.get(inner.unionId)?.arms ?? []; return arms.every((a) => resultArms.some((b) => typeEquals(a, b))); diff --git a/packages/compiler/src/frontend/lowering/builtins/promisify-callback.ts b/packages/compiler/src/frontend/lowering/builtins/promisify-callback.ts new file mode 100644 index 000000000..cdb8a1fbb --- /dev/null +++ b/packages/compiler/src/frontend/lowering/builtins/promisify-callback.ts @@ -0,0 +1,377 @@ +import * as ts from "../../ts7/adapter.js"; +import { type Lowerer } from "../lowerer.js"; +import { varRef } from "../../../ir/build.js"; +import { + BOOL, + type IrExpr, + type IrLocal, + type IrParam, + type IrStmt, + type IrType, + type SrcLoc, + VOID, + funcOf, + isUnitType, + typeEquals, + typeKey, +} from "../../../ir/ir.js"; + +const ERROR_T: IrType = { kind: "object", className: "%Error" }; + +/** The parts of `util.promisify(fn)` for a typed callback-last function: + * `fn(...args, (err, value) => void)` becomes `(...args) => Promise`. */ +export interface CallbackShape { + fnT: IrType & { kind: "func" }; + resultT: IrType & { kind: "func" }; + args: readonly IrType[]; + callbackT: IrType & { kind: "func" }; + /** The parameter's declared type: callbackT, or `callbackT | undefined` + * for an optional callback. */ + callbackParamT: IrType; + inner: IrType; + /** The error parameter's union and the tag of its Error arm, or null when + * the callback declares no error parameter. */ + error: { type: IrType; errorTag: number; unitTags: number[] } | null; +} + +function callbackShape( + lowerer: Lowerer, + fnT: IrType | null, + resultT: IrType | null, + loc: SrcLoc, +): CallbackShape | null { + if (fnT?.kind !== "func" || resultT?.kind !== "func") return null; + if (fnT.rest || fnT.restAbi || fnT.argumentsAll || resultT.rest || resultT.restAbi) return null; + const callbackParamT = fnT.params[fnT.params.length - 1]; + // An optional callback (`close(callback?: (err?: Error) => void)`) takes + // its function arm; the call passes the callback into the union. + const callbackT = + callbackParamT?.kind === "union" + ? (() => { + const arms = lowerer.unions.get(callbackParamT.unionId)?.arms ?? []; + const fns = arms.filter((arm) => arm.kind === "func"); + return fns.length === 1 && + arms.every((arm) => arm.kind === "func" || arm.kind === "undefinedT") + ? fns[0] + : undefined; + })() + : callbackParamT; + if (callbackT?.kind !== "func" || callbackT.ret.kind !== "void") return null; + if (callbackT.rest || callbackT.restAbi || callbackT.params.length > 2) return null; + const args = fnT.params.slice(0, -1); + if ( + resultT.ret.kind !== "promise" || + resultT.params.length !== args.length || + !resultT.params.every((type, i) => typeEquals(type, args[i]!)) + ) + return null; + const inner = resultT.ret.inner; + let error: CallbackShape["error"] = null; + const errorT = callbackT.params[0]; + if (errorT !== undefined) { + if (errorT.kind !== "union") return null; + const arms = lowerer.unions.get(errorT.unionId)?.arms ?? []; + const errorTags = arms.flatMap((arm, tag) => + arm.kind === "object" && + (arm.className === "%Error" || lowerer.isSubclassOf(arm.className, "%Error")) + ? [tag] + : [], + ); + const unitTags = arms.flatMap((arm, tag) => (isUnitType(arm) ? [tag] : [])); + if (errorTags.length !== 1 || errorTags.length + unitTags.length !== arms.length) return null; + error = { type: errorT, errorTag: errorTags[0]!, unitTags }; + } + if (inner.kind !== "void") { + const valueT = callbackT.params[1]; + if (valueT === undefined) return null; + const probe: IrExpr = { kind: "varRef", localId: "%probe", type: valueT, loc }; + if (!typeEquals(lowerer.coerceToExpected(probe, inner).type, inner)) return null; + } + return { fnT, resultT, args, callbackT, callbackParamT: callbackParamT!, inner, error }; +} + +/** The callback shape of a `promisify(fn)` call, or null. */ +export function callbackPromisifyShape( + lowerer: Lowerer, + call: ts.CallExpression, + loc: SrcLoc, +): CallbackShape | null { + if (call.questionDotToken || call.arguments.nodes.length !== 1) return null; + const argNode = call.arguments.nodes[0]!; + if (ts.isSpreadElement(argNode)) return null; + return callbackShape( + lowerer, + lowerer.mapTypeOf(lowerer.typeOf(argNode)), + lowerer.mapTypeOf(lowerer.typeOf(call)), + loc, + ); +} + +function captureParam(localId: string, type: IrType): IrParam { + return { localId, name: localId, type }; +} + +function boxedLocal(localId: string, type: IrType): IrLocal { + return { id: localId, name: localId, type, mutable: false, boxed: true }; +} + +function plainLocal(localId: string, type: IrType): IrLocal { + return { id: localId, name: localId, type, mutable: false }; +} + +/** `util.promisify(fn)` over a typed callback-last function value (a bound + * method, a function declaration, a closure): a native function that calls + * `fn` with the arguments and a callback, and settles its promise from the + * callback like Node's wrapper: a truthy error rejects, otherwise the first + * value fulfills. A synchronous throw rejects (the executor's rule). Null + * when the argument or result does not have that typed shape. */ +export function lowerCallbackPromisify( + lowerer: Lowerer, + call: ts.CallExpression, + loc: SrcLoc, +): IrExpr | null { + const shape = callbackPromisifyShape(lowerer, call, loc); + if (shape === null) return null; + const argNode = call.arguments.nodes[0]!; + let fn = lowerer.lowerExpr(argNode); + if (!typeEquals(fn.type, shape.fnT)) fn = lowerer.coerceToExpected(fn, shape.fnT); + if (!typeEquals(fn.type, shape.fnT)) return null; + return { + kind: "call", + callee: promisifyMaker(lowerer, shape, loc), + args: [fn], + type: shape.resultT, + loc, + }; +} + +/** Interns the helper family for one (function, result) type pair and + * answers the maker: `(fn) => closure(...args) => Promise`. */ +function promisifyMaker(lowerer: Lowerer, shape: CallbackShape, loc: SrcLoc): string { + const key = `promisify:${typeKey(shape.fnT)}=>${typeKey(shape.resultT)}`; + const existing = lowerer.arrHofHelpers.get(key); + if (existing) return existing; + const base = `%promisify.${lowerer.arrHofHelpers.size}`; + lowerer.arrHofHelpers.set(key, base); + const { fnT, resultT, args, callbackT, callbackParamT, inner, error } = shape; + const promiseT = resultT.ret; + const resolveT = funcOf(inner.kind === "void" ? [] : [inner], VOID); + const rejectT = funcOf([ERROR_T], VOID); + const executorT = funcOf([resolveT, rejectT], VOID); + const argIds = args.map((_, i) => `a${i}.0`); + + // The callback: (err, value) => err ? reject(err) : resolve(value). + const cbParams: IrParam[] = []; + callbackT.params.forEach((type, i) => + cbParams.push(captureParam(i === 0 ? "err.0" : "value.0", type)), + ); + const cbBody: IrStmt[] = []; + if (error !== null) { + const err = varRef("err.0", error.type, loc); + let truthy: IrExpr | null = null; + for (const tag of error.unitTags) { + const part: IrExpr = { + kind: "unionIsTag", + unionId: (error.type as IrType & { kind: "union" }).unionId, + tag, + negated: true, + value: err, + type: BOOL, + loc, + }; + truthy = + truthy === null + ? part + : { kind: "logical", op: "&&", left: truthy, right: part, type: BOOL, loc }; + } + const errorArm = lowerer.unions.get((error.type as IrType & { kind: "union" }).unionId)!.arms[ + error.errorTag + ]!; + let reason: IrExpr = { + kind: "unionNarrow", + unionId: (error.type as IrType & { kind: "union" }).unionId, + tag: error.errorTag, + value: err, + type: errorArm, + loc, + }; + if (!typeEquals(errorArm, ERROR_T)) + reason = { kind: "upcast", value: reason, type: ERROR_T, loc }; + const reject: IrStmt[] = [ + { + kind: "exprStmt", + expr: { + kind: "callValue", + callee: varRef("rej.0", rejectT, loc), + args: [reason], + type: VOID, + loc, + }, + loc, + }, + { kind: "return", value: null, loc }, + ]; + cbBody.push( + truthy === null ? reject[0]! : { kind: "if", cond: truthy, then: reject, else_: null, loc }, + ); + if (truthy === null) cbBody.push(reject[1]!); + } + const value = + inner.kind === "void" + ? [] + : [lowerer.coerceToExpected(varRef("value.0", callbackT.params[1]!, loc), inner)]; + cbBody.push({ + kind: "exprStmt", + expr: { + kind: "callValue", + callee: varRef("res.0", resolveT, loc), + args: value, + type: VOID, + loc, + }, + loc, + }); + lowerer.liftedFns.push({ + name: `${base}.cb`, + params: cbParams, + returnType: VOID, + captures: [captureParam("res.0", resolveT), captureParam("rej.0", rejectT)], + locals: [ + boxedLocal("res.0", resolveT), + boxedLocal("rej.0", rejectT), + ...cbParams.map((p) => plainLocal(p.localId, p.type)), + ], + body: cbBody, + loc, + }); + lowerer.liftedFns.push({ + name: `${base}.mkcb`, + params: [captureParam("res.0", resolveT), captureParam("rej.0", rejectT)], + returnType: callbackT, + locals: [boxedLocal("res.0", resolveT), boxedLocal("rej.0", rejectT)], + body: [ + { + kind: "return", + value: { + kind: "closure", + fnName: `${base}.cb`, + captures: ["res.0", "rej.0"], + type: callbackT, + loc, + }, + loc, + }, + ], + loc, + }); + + // The executor: (resolve, reject) => fn(...args, callback). + const captured: IrParam[] = [captureParam("f.0", fnT)]; + args.forEach((type, i) => captured.push(captureParam(argIds[i]!, type))); + lowerer.liftedFns.push({ + name: `${base}.exec`, + params: [captureParam("res.0", resolveT), captureParam("rej.0", rejectT)], + returnType: VOID, + captures: captured, + locals: [ + ...captured.map((p) => boxedLocal(p.localId, p.type)), + plainLocal("res.0", resolveT), + plainLocal("rej.0", rejectT), + ], + body: [ + { + kind: "exprStmt", + expr: { + kind: "callValue", + callee: varRef("f.0", fnT, loc), + args: [ + ...args.map((type, i) => varRef(argIds[i]!, type, loc)), + lowerer.coerceToExpected( + { + kind: "call", + callee: `${base}.mkcb`, + args: [varRef("res.0", resolveT, loc), varRef("rej.0", rejectT, loc)], + type: callbackT, + loc, + }, + callbackParamT, + ), + ], + // The function's own return type; the value is discarded. + type: fnT.ret, + loc, + }, + loc, + }, + ], + loc, + }); + lowerer.liftedFns.push({ + name: `${base}.mkexec`, + params: captured, + returnType: executorT, + locals: captured.map((p) => boxedLocal(p.localId, p.type)), + body: [ + { + kind: "return", + value: { + kind: "closure", + fnName: `${base}.exec`, + captures: captured.map((p) => p.localId), + type: executorT, + loc, + }, + loc, + }, + ], + loc, + }); + + // The promisified function: (...args) => new Promise(executor). + const implParams: IrParam[] = []; + args.forEach((type, i) => implParams.push(captureParam(argIds[i]!, type))); + lowerer.liftedFns.push({ + name: `${base}.impl`, + params: implParams, + returnType: promiseT, + captures: [captureParam("f.0", fnT)], + locals: [boxedLocal("f.0", fnT), ...implParams.map((p) => plainLocal(p.localId, p.type))], + body: [ + { + kind: "return", + value: { + kind: "newPromise", + executor: { + kind: "call", + callee: `${base}.mkexec`, + args: [ + varRef("f.0", fnT, loc), + ...implParams.map((p) => varRef(p.localId, p.type, loc)), + ], + type: executorT, + loc, + }, + type: promiseT, + loc, + }, + loc, + }, + ], + loc, + }); + lowerer.liftedFns.push({ + name: base, + params: [captureParam("f.0", fnT)], + returnType: resultT, + locals: [boxedLocal("f.0", fnT)], + body: [ + { + kind: "return", + value: { kind: "closure", fnName: `${base}.impl`, captures: ["f.0"], type: resultT, loc }, + loc, + }, + ], + loc, + }); + return base; +} diff --git a/packages/compiler/src/frontend/lowering/call-signatures.ts b/packages/compiler/src/frontend/lowering/call-signatures.ts index aae73076b..954122a16 100644 --- a/packages/compiler/src/frontend/lowering/call-signatures.ts +++ b/packages/compiler/src/frontend/lowering/call-signatures.ts @@ -33,6 +33,7 @@ import { isStreamUndefCallExpr } from "./lower-server.js"; import { nsPathPrefix } from "./lower-namespaces.js"; import { declSymbolOf } from "./lower-modules.js"; import { npmStaticPackageOfPath } from "../npm-static.js"; +import { restPackingAdapterFits } from "./coercions/function-adapters.js"; import { implicitMonoFile, implicitAnyParamSymbolsOf } from "./generic-functions.js"; /** How a parameter participates in CALL-SITE COMPLETION (the frontend @@ -608,6 +609,21 @@ export function requireExactArityValue( // optional/defaulted params spell their `T | undefined` slots (mapType's // completed-signature contract), so omitted trailing args complete with // the undefined arm like any direct call. + // A nested function declaration whose only non-required parameter is a + // typed rest: its value carries the typed-rest ABI its own type spells, + // and every use converts it at its slot (same signature, or the rest + // packing adapter for fixed parameters). + if ( + contextual === null && + ts.isFunctionDeclaration(blame) && + blame.name !== undefined && + funcType.kind === "func" && + funcType.restAbi === "typed" && + shapes.every((s) => s.mode === "required" || s.mode === "rest") + ) { + const own = lowerer.mapTypeOf(lowerer.typeOf(blame.name)); + if (own && typeEquals(own, funcType)) return; + } const target = contextual ? lowerer.checker.getContextualType(contextual) : undefined; const mapped = target ? lowerer.mapTypeOf(target) @@ -668,6 +684,16 @@ export function requireExactArityValue( ) { return; } + // A typed-rest function in a slot with fixed parameters (`log(...m: + // string[])` into `(m: string) => void`): the slot coercion's packing + // adapter collects the slot's arguments into the rest array. + if ( + mappedFn?.kind === "func" && + funcType.kind === "func" && + restPackingAdapterFits(lowerer, funcType, mappedFn) + ) { + return; + } // An uncontextualized npm-static implementation function can still // have a declaration-backed completed ABI: the package's .d.ts // projection supplies the body-facing parameter/return types while diff --git a/packages/compiler/src/frontend/lowering/class-attributes.ts b/packages/compiler/src/frontend/lowering/class-attributes.ts new file mode 100644 index 000000000..4e7bbe801 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/class-attributes.ts @@ -0,0 +1,440 @@ +import * as ts from "../ts7/adapter.js"; +import { + BOOL, + CLASS_ATTRIBUTES, + CLASS_FROZEN, + CLASS_NOT_EXTENSIBLE, + CLASS_SEALED, + DYN, + F64, + FIELD_NOT_WRITABLE, + STRING, + VOID, + canConvertToDyn, + canDynCheckTo, + classFieldAttributesName, + isClassOwnEnumerableFieldName, + isDynTypedRefType, + type IrExpr, + type IrFunction, + type IrStmt, + type IrType, + type SrcLoc, +} from "../../ir/ir.js"; +import { numLit, strLit, varRef } from "../../ir/build.js"; +import { transformStmtList } from "../../ir/traverse.js"; +import { locOf } from "../program.js"; +import { type Lowerer, PoisonError } from "./lowerer.js"; +import type { ClassInfo } from "./lower-classes.js"; +import { classPropertiesHelper } from "./class-dynamic-dispatch.js"; +import { runtimeRooted } from "./class-descriptors.js"; + +/* Object.freeze, Object.seal, Object.preventExtensions and + * Object.defineProperty on class instances. Only the hierarchies these calls + * name pay for them: such a hierarchy gets a CLASS_ATTRIBUTES integrity word + * per instance, an attribute word per redefined field, and a check before + * each write to a declared field (guardClassAttributeWrites). The instance's + * checked view carries the attributes, so reflection answers from it. */ + +type ClassObjectType = Extract; + +function attributeClass(lowerer: Lowerer, target: IrExpr): ClassInfo | null { + if (!isDynTypedRefType(target.type)) return null; + const info = lowerer.classes.get(target.type.className); + if (!info || runtimeRooted(info) || info.decl == null) return null; + return info; +} + +/** Adds a zero-initialized f64 to every class of the hierarchy, at the same + * offset, like the property bag. */ +function addHiddenField(info: ClassInfo, name: string): void { + let root = info; + while (root.base && !root.base.def.runtime) root = root.base; + if (root.fields.has(name)) return; + const index = root.def.fields.length; + const add = (current: ClassInfo): void => { + if (!current.fields.has(name)) { + current.fields.set(name, F64); + current.def.fields.splice(index, 0, { name, type: F64 }); + } + current.subclasses.forEach(add); + }; + add(root); +} + +function hiddenFieldGet(receiver: IrExpr, className: string, field: string, loc: SrcLoc): IrExpr { + return { kind: "fieldGet", obj: receiver, className, field, type: F64, loc }; +} + +/** Object.freeze, Object.seal and Object.preventExtensions of a class + * instance: sets the instance's integrity bits, then applies the operation to + * the properties added to the instance. Answers the instance. */ +export function lowerClassIntegrity( + lowerer: Lowerer, + call: ts.CallExpression, + member: "freeze" | "seal" | "preventExtensions", + target: IrExpr, +): IrExpr | null { + const info = attributeClass(lowerer, target); + if (!info) return null; + addHiddenField(info, CLASS_ATTRIBUTES); + const loc = locOf(call); + const type = target.type as ClassObjectType; + const bits = + member === "freeze" + ? CLASS_NOT_EXTENSIBLE | CLASS_SEALED | CLASS_FROZEN + : member === "seal" + ? CLASS_NOT_EXTENSIBLE | CLASS_SEALED + : CLASS_NOT_EXTENSIBLE; + const slot = lowerer.declareHiddenLocal("%integrityReceiver", type); + const receiver = (): IrExpr => varRef(slot.id, type, loc); + const bag: IrExpr = { + kind: "call", + callee: classPropertiesHelper(lowerer, loc).name, + args: [lowerer.coerceToExpected(receiver(), DYN)], + type: DYN, + loc, + }; + const operation = { + freeze: "dyn.freeze", + seal: "dyn.seal", + preventExtensions: "dyn.preventExtensions", + } as const; + return { + kind: "seqExpr", + stmts: [ + { kind: "varDecl", localId: slot.id, init: target, loc }, + { + kind: "fieldSet", + obj: receiver(), + className: type.className, + field: CLASS_ATTRIBUTES, + value: { + kind: "bin", + op: "|", + left: hiddenFieldGet(receiver(), type.className, CLASS_ATTRIBUTES, loc), + right: numLit(bits, loc), + type: F64, + loc, + }, + attributesChecked: true, + loc, + }, + { + kind: "exprStmt", + expr: { kind: "libCall", fn: operation[member], args: [bag], type: DYN, loc }, + loc, + }, + ], + result: receiver(), + type, + loc, + }; +} + +/** An object literal with a get or set property. */ +function literalAccessorDescriptor(node: ts.Expression): boolean { + while (ts.isParenthesizedExpression(node)) node = node.expression; + return ( + ts.isObjectLiteralExpression(node) && + node.properties.nodes.some( + (property) => + property.name !== undefined && + (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) && + (property.name.text === "get" || property.name.text === "set"), + ) + ); +} + +/** Object.defineProperty with a string-literal key naming a declared field + * of a class instance: a data descriptor changes the field's value and + * attributes, validated as Node validates ordinary objects. Answers the + * instance, or null when the call is not of that form. An object-literal + * accessor descriptor is refused at compile time; other accessor + * descriptors throw SC2020 when the call runs. */ +export function lowerClassFieldDefine( + lowerer: Lowerer, + call: ts.CallExpression, + target: IrExpr, +): IrExpr | null { + const info = attributeClass(lowerer, target); + const key = call.arguments.nodes[1]!; + if (!info || !ts.isStringLiteral(key)) return null; + const field = key.text; + const fieldType = info.fields.get(field); + if ( + fieldType === undefined || + !isClassOwnEnumerableFieldName(field) || + [...(info.symbolFields?.values() ?? [])].includes(field) + ) + return null; + if (literalAccessorDescriptor(call.arguments.nodes[2]!)) { + lowerer.pushDiag({ + code: "SC2020", + message: `Object.defineProperty with an accessor descriptor for the declared field '${field}' is not supported yet`, + loc: locOf(call), + }); + throw new PoisonError(); + } + const getRecord = (id: string) => lowerer.shapes.get(id); + const getUnion = (id: string) => lowerer.unions.get(id); + if ( + !canConvertToDyn(fieldType, getRecord, getUnion) || + !canDynCheckTo(fieldType, getRecord, getUnion) + ) + return null; + const attributesField = classFieldAttributesName(field); + addHiddenField(info, CLASS_ATTRIBUTES); + addHiddenField(info, attributesField); + const loc = locOf(call); + const type = target.type as ClassObjectType; + const receiverSlot = lowerer.declareHiddenLocal("%defineReceiver", type); + const descriptorSlot = lowerer.declareHiddenLocal("%defineDescriptor", DYN); + const holderSlot = lowerer.declareHiddenLocal("%defineHolder", DYN); + const receiver = (): IrExpr => varRef(receiverSlot.id, type, loc); + const descriptor = (): IrExpr => varRef(descriptorSlot.id, DYN, loc); + const holder = (): IrExpr => varRef(holderSlot.id, DYN, loc); + const name = (): IrExpr => strLit(field, loc); + const current: IrExpr = { + kind: "fieldGet", + obj: receiver(), + className: type.className, + field, + type: fieldType, + loc, + }; + const defined: IrExpr = { + kind: "libCall", + fn: "class.definedValue", + args: [holder(), name()], + type: DYN, + loc, + }; + return { + kind: "seqExpr", + stmts: [ + { kind: "varDecl", localId: receiverSlot.id, init: target, loc }, + { + kind: "varDecl", + localId: descriptorSlot.id, + init: lowerer.lowerExprExpecting(call.arguments.nodes[2]!, DYN), + loc, + }, + { + kind: "varDecl", + localId: holderSlot.id, + init: { + kind: "libCall", + fn: "class.defineField", + args: [ + lowerer.coerceToExpected(current, DYN), + hiddenFieldGet(receiver(), type.className, attributesField, loc), + hiddenFieldGet(receiver(), type.className, CLASS_ATTRIBUTES, loc), + name(), + descriptor(), + ], + type: DYN, + loc, + }, + loc, + }, + { + kind: "if", + cond: { + kind: "libCall", + fn: "class.descriptorHasValue", + args: [descriptor()], + type: BOOL, + loc, + }, + then: [ + { + kind: "fieldSet", + obj: receiver(), + className: type.className, + field, + value: lowerer.coerceToExpected(defined, fieldType), + attributesChecked: true, + loc, + }, + ], + else_: null, + loc, + }, + { + kind: "fieldSet", + obj: receiver(), + className: type.className, + field: attributesField, + value: { + kind: "libCall", + fn: "class.definedBits", + args: [holder(), name()], + type: F64, + loc, + }, + attributesChecked: true, + loc, + }, + ], + result: receiver(), + type, + loc, + }; +} + +function classDisplayName(info: ClassInfo): string { + return info.def.jsName ?? info.decl?.name?.text ?? info.def.name.replace(/^%/, ""); +} + +/** The instance's own class name for an error message: a helper testing the + * most derived classes of the hierarchy first. */ +function instanceClassName( + lowerer: Lowerer, + info: ClassInfo, + receiver: IrExpr, + helpers: Map, + loc: SrcLoc, +): IrExpr { + if (info.subclasses.length === 0) return strLit(classDisplayName(info), loc); + let helper = helpers.get(info.def.name); + if (!helper) { + const type: IrType = { kind: "object", className: info.def.name }; + const value = varRef("value", type, loc); + const descendants = (current: ClassInfo): ClassInfo[] => + current.subclasses.flatMap((child) => [...descendants(child), child]); + const body: IrStmt[] = descendants(info).map((child): IrStmt => ({ + kind: "if", + cond: { kind: "instanceOf", value, className: child.def.name, type: BOOL, loc }, + then: [{ kind: "return", value: strLit(classDisplayName(child), loc), loc }], + else_: null, + loc, + })); + body.push({ kind: "return", value: strLit(classDisplayName(info), loc), loc }); + helper = { + name: `%class.instanceName.${helpers.size}`, + params: [{ localId: "value", name: "value", type }], + returnType: STRING, + locals: [{ id: "value", name: "value", type, mutable: false }], + body, + loc, + }; + helpers.set(info.def.name, helper); + } + return { kind: "call", callee: helper.name, args: [receiver], type: STRING, loc }; +} + +/** Checks the integrity word, and the field's attribute word when it has one, + * before every write to a declared field of a hierarchy that has them. A + * read-only field throws Node's TypeError in strict mode code; a sloppy-mode + * write leaves it unchanged. Other classes keep their plain stores. */ +export function guardClassAttributeWrites(lowerer: Lowerer, functions: IrFunction[]): void { + const guarded = new Set( + [...lowerer.classes.values()] + .filter((info) => info.def.fields.some((field) => field.name === CLASS_ATTRIBUTES)) + .map((info) => info.def.name), + ); + if (guarded.size === 0) return; + const helpers = new Map(); + for (const fn of functions) { + const local = (type: IrType, loc: SrcLoc): Extract => { + const id = `%attributeWrite.${fn.locals.length}`; + fn.locals.push({ id, name: id, type, mutable: false }); + return { kind: "varRef", localId: id, type, loc }; + }; + fn.body = transformStmtList(fn.body, { + stmt: (statement) => { + if ( + statement.kind !== "fieldSet" || + statement.attributesChecked || + !guarded.has(statement.className) || + !isClassOwnEnumerableFieldName(statement.field) + ) + return statement; + const info = lowerer.classes.get(statement.className)!; + const loc = statement.loc; + const receiver = local(statement.obj.type, loc); + const value = local(statement.value.type, loc); + const masked = (field: string, bit: number): IrExpr => ({ + kind: "bin", + op: "&", + left: hiddenFieldGet(receiver, statement.className, field, loc), + right: numLit(bit, loc), + type: F64, + loc, + }); + const attributesField = classFieldAttributesName(statement.field); + let readOnly = masked( + CLASS_ATTRIBUTES, + statement.define ? CLASS_NOT_EXTENSIBLE : CLASS_FROZEN, + ); + if (!statement.define && info.fields.has(attributesField)) { + readOnly = { + kind: "bin", + op: "|", + left: readOnly, + right: masked(attributesField, FIELD_NOT_WRITABLE), + type: F64, + loc, + }; + } + const reject: IrStmt[] = statement.define + ? [ + { + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "class.throwNotExtensible", + args: [strLit(statement.field, loc)], + type: VOID, + loc, + }, + loc, + }, + ] + : statement.sloppy + ? [] + : [ + { + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "class.throwReadOnly", + args: [ + strLit(statement.field, loc), + instanceClassName(lowerer, info, receiver, helpers, loc), + ], + type: VOID, + loc, + }, + loc, + }, + ]; + return { + kind: "block", + body: [ + { kind: "varDecl", localId: receiver.localId, init: statement.obj, loc }, + { kind: "varDecl", localId: value.localId, init: statement.value, loc }, + { + kind: "if", + cond: { + kind: "bin", + op: "!==", + left: readOnly, + right: numLit(0, loc), + type: BOOL, + loc, + }, + then: reject, + else_: [{ ...statement, obj: receiver, value, attributesChecked: true }], + loc, + }, + ], + loc, + }; + }, + expr: (expression) => expression, + }); + } + for (const helper of helpers.values()) functions.push(helper); +} diff --git a/packages/compiler/src/frontend/lowering/class-descriptors.ts b/packages/compiler/src/frontend/lowering/class-descriptors.ts index 473ed2496..cb980f0d0 100644 --- a/packages/compiler/src/frontend/lowering/class-descriptors.ts +++ b/packages/compiler/src/frontend/lowering/class-descriptors.ts @@ -23,7 +23,7 @@ function bagOnlyProperty(owner: ClassInfo, name: string): boolean { return !owner.fields.has(name) && owner.subclasses.every((child) => bagOnlyProperty(child, name)); } -function runtimeRooted(info: ClassInfo): boolean { +export function runtimeRooted(info: ClassInfo): boolean { for (let current: ClassInfo | null = info; current; current = current.base) { if ( current.def.runtime || diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index d2ef7f6cd..2587a4b65 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -2695,6 +2695,7 @@ export class ClassDynamicDispatch { !findGenericMethodOn(lowerer, info, dispatch.name) && dispatch.name !== "constructor" && !info.fields.has(dispatch.name) && + !(dispatch.name === "stack" && lowerer.isSubclassOf(info.def.name, "%Error")) && !findMethodOn(lowerer, info, `get:${dispatch.name}`) && !findMethodOn(lowerer, info, `set:${dispatch.name}`)) ) @@ -4525,6 +4526,110 @@ export class ClassDynamicDispatch { }, ]; } + // An Error's own `stack`: a string is the native error's stack, which + // typed reads share; any other value is kept with the instance's own + // properties, which a read checks first. A class whose chain declares + // a `stack` accessor answers through it (the accessor code below). + if ( + name === "stack" && + !info.fields.has(name) && + lowerer.isSubclassOf(info.def.name, "%Error") && + !findMethodOn(lowerer, info, "get:stack") && + !findMethodOn(lowerer, info, "set:stack") + ) { + const key: IrExpr = { kind: "strLit", value: name, type: STRING, loc }; + const error = lowerer.upcastTo(receiver, "%Error"); + if (write) { + const helper = classPropertiesHelper(lowerer, loc); + this.generated.add(helper); + const store: IrStmt = { + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "dyn.keySet", + args: [ + { + kind: "call", + callee: helper.name, + args: [lowerer.coerceToExpected(receiver, DYN)], + type: DYN, + loc, + }, + key, + varRef("p.1", DYN, loc), + ], + type: VOID, + loc, + }, + loc, + }; + return [ + { + kind: "if", + cond: { + kind: "dynTest", + test: "string", + value: varRef("p.1", DYN, loc), + type: BOOL, + loc, + }, + then: [ + { + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "error.setStack", + args: [error, lowerer.coerceToExpected(varRef("p.1", DYN, loc), STRING)], + type: VOID, + loc, + }, + loc, + }, + { + kind: "if", + cond: this.readBagHas( + lowerer, + "dyn.hasKey", + this.readPropertyBag(lowerer, receiver, loc), + key, + loc, + ), + then: [store], + else_: null, + loc, + }, + ], + else_: [store], + loc, + }, + { kind: "return", value: null, loc }, + ]; + } + const bag = this.readPropertyBag(lowerer, receiver, loc); + return [ + { + kind: "return", + value: { + kind: "ternary", + cond: this.readBagHas(lowerer, "dyn.hasKey", bag, key, loc), + then: { + kind: "libCall", + fn: "dyn.bagGet", + args: [bag, key, lowerer.coerceToExpected(receiver, DYN)], + type: DYN, + loc, + }, + else_: lowerer.coerceToExpected( + { kind: "libCall", fn: "error.stack", args: [error], type: STRING, loc }, + DYN, + ), + type: DYN, + loc, + }, + loc, + }, + ]; + } if ((name === "message" || name === "name") && lowerer.isSubclassOf(info.def.name, "%Error")) return write ? [ diff --git a/packages/compiler/src/frontend/lowering/class-protocols.ts b/packages/compiler/src/frontend/lowering/class-protocols.ts index 65d74ab9d..5a27f0815 100644 --- a/packages/compiler/src/frontend/lowering/class-protocols.ts +++ b/packages/compiler/src/frontend/lowering/class-protocols.ts @@ -722,12 +722,6 @@ export class ClassProtocols { return true; } } - // An interface extending a class-backed protocol holds values of that - // protocol (`interface TupleType extends Type`), so an assertion from - // the base to it keeps the instance and its methods. - const target = type.isTypeReference() ? type.getTarget() : type; - if (target?.isClassOrInterface()) - for (const base of this.checker.getBaseTypes(target)) if (this.protocol(base)) return true; return false; } } diff --git a/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts b/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts index ed0f1f91c..3d8817ab1 100644 --- a/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts +++ b/packages/compiler/src/frontend/lowering/coercions/function-adapters.ts @@ -112,12 +112,15 @@ export function coercibleValue(lowerer: Lowerer, src: IrType, dst: IrType): bool } /** Whether all parameters and the result adapt without a trap-only path. - * Rest signatures are excluded; extra destination parameters are ignored. */ + * Rest signatures are excluded, except a typed-rest source in a slot with + * fixed parameters (the rest packing adapter); extra destination + * parameters are ignored. */ export function cleanFuncAdaptable( lowerer: Lowerer, src: IrType & { kind: "func" }, dst: IrType & { kind: "func" }, ): boolean { + if (restPackingAdapterFits(lowerer, src, dst)) return true; if (src.rest === true || dst.rest === true) return false; if (src.params.length > dst.params.length) return false; for (let i = 0; i < src.params.length; i++) { @@ -128,15 +131,145 @@ export function cleanFuncAdaptable( return src.ret.kind === "void" && dst.ret.kind === "dyn"; } +/** Whether a typed-rest function (`(...m: T[]) => R`) can serve a slot + * with fixed parameters (`(m: T) => void`): the slot's parameters convert + * to the function's fixed parameters, then to the rest element type. */ +export function restPackingAdapterFits( + lowerer: Lowerer, + fromT: IrType & { kind: "func" }, + toT: IrType & { kind: "func" }, +): boolean { + if (fromT.rest !== true || fromT.restAbi !== "typed" || toT.rest === true) return false; + const fixed = fromT.params.length - 1; + const restT = fromT.params[fixed]; + if (restT?.kind !== "array" || toT.params.length < fixed) return false; + for (let i = 0; i < toT.params.length; i++) { + if (!lowerer.coercibleValue(toT.params[i]!, i < fixed ? fromT.params[i]! : restT.elem)) + return false; + } + return toT.ret.kind === "void" || lowerer.coercibleValue(fromT.ret, toT.ret); +} + +/** The adapter for restPackingAdapterFits: forwards the fixed arguments and + * packs the remaining ones into the rest array, as a JavaScript call of the + * function with those arguments does. */ +function restPackingAdapter( + lowerer: Lowerer, + fromT: IrType & { kind: "func" }, + toT: IrType & { kind: "func" }, + loc: SrcLoc, +): string { + const key = `fnrestadapt:${typeKey(fromT)}:${typeKey(toT)}`; + const existing = lowerer.coercions.retags.get(key); + if (existing) return existing; + const name = `%fn.adapt.${lowerer.coercions.retags.size}`; + lowerer.coercions.retags.set(key, name); + lowerer.freshClosureAdapters.add(name); + const fixed = fromT.params.length - 1; + const restT = fromT.params[fixed] as IrType & { kind: "array" }; + const params: IrParam[] = toT.params.map((t, i) => ({ + localId: `a.${i}`, + name: `a${i}`, + type: t, + })); + const arg = (i: number, want: IrType): IrExpr => + lowerer.coerceToExpected( + { kind: "varRef", localId: `a.${i}`, type: toT.params[i]!, loc }, + want, + ); + const args: IrExpr[] = []; + for (let i = 0; i < fixed; i++) args.push(arg(i, fromT.params[i]!)); + const packed: IrExpr[] = []; + for (let i = fixed; i < toT.params.length; i++) packed.push(arg(i, restT.elem)); + args.push({ kind: "arrayLit", elems: packed, type: restT, loc }); + const call: IrExpr = { + kind: "callValue", + callee: { kind: "varRef", localId: "f.0", type: fromT, loc }, + receiver: { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc }, + args, + type: fromT.ret, + loc, + }; + const body: IrStmt[] = + toT.ret.kind === "void" + ? [ + { kind: "exprStmt", expr: call, loc }, + { kind: "return", value: null, loc }, + ] + : [{ kind: "return", value: lowerer.coerceToExpected(call, toT.ret), loc }]; + lowerer.liftedFns.push(...buildFunctionAdapter(name, fromT, toT, params, [], body, loc)); + return name; +} + +/** Adapt a fixed-parameter function to a checked-dynamic rest signature + * without fixed parameters (`() => {}` into mock.fn()'s `(...args: any[]) + * => undefined`): the adapter receives the hidden argument array and + * passes its element i as parameter i, undefined when the caller passed + * fewer arguments, as JS does. Null unless every parameter is + * checked-dynamic, which holds a missing argument as undefined, and the + * result is discarded or converts. */ +function funcIntoDynRestAdapter( + lowerer: Lowerer, + fromT: IrType & { kind: "func" }, + toT: IrType & { kind: "func" }, + loc: SrcLoc, +): string | null { + if (fromT.rest === true || fromT.params.some((p) => p.kind !== "dyn")) return null; + if (toT.ret.kind !== "void" && !lowerer.coercibleValue(fromT.ret, toT.ret)) return null; + const key = `fnadapt:${typeKey(fromT)}:${typeKey(toT)}`; + const existing = lowerer.coercions.retags.get(key); + if (existing) return existing; + const name = `%fn.adapt.${lowerer.coercions.retags.size}`; + lowerer.coercions.retags.set(key, name); + lowerer.freshClosureAdapters.add(name); + const params: IrParam[] = [{ localId: "rest.0", name: "args", type: DYN }]; + const call: IrExpr = { + kind: "callValue", + callee: { kind: "varRef", localId: "f.0", type: fromT, loc }, + receiver: { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc }, + args: fromT.params.map((_, i): IrExpr => ({ + kind: "dynKeyGet", + value: { kind: "varRef", localId: "rest.0", type: DYN, loc }, + key: { kind: "strLit", value: String(i), type: STRING, loc }, + type: DYN, + loc, + })), + type: fromT.ret, + loc, + }; + let body: IrStmt[]; + if (toT.ret.kind === "void") { + body = [ + { kind: "exprStmt", expr: call, loc }, + { kind: "return", value: null, loc }, + ]; + } else { + const result = lowerer.coerceToExpected(call, toT.ret); + if (!typeEquals(result.type, toT.ret)) + throw new InternalCompilerError("lowerer bug: probed fn-adapter return stopped coercing"); + body = [{ kind: "return", value: result, loc }]; + } + lowerer.liftedFns.push(...buildFunctionAdapter(name, fromT, toT, params, [], body, loc)); + return name; +} + /** Adapt a function value to a destination signature, forwarding and * converting its arguments and result. Unsupported parameter/result pairs - * produce checked traps when called; rest signatures remain refused. */ + * produce checked traps when called. Rest signatures are refused, except a + * typed-rest source in a slot with fixed parameters, which the rest + * packing adapter serves, and a fixed-parameter function into a + * checked-dynamic rest signature without fixed parameters + * (funcIntoDynRestAdapter). */ export function funcCoerceAdapter( lowerer: Lowerer, fromT: IrType & { kind: "func" }, toT: IrType & { kind: "func" }, loc: SrcLoc, ): string | null { + if (restPackingAdapterFits(lowerer, fromT, toT)) + return restPackingAdapter(lowerer, fromT, toT, loc); + if (toT.rest === true && toT.restAbi === undefined && toT.params.length === 0) + return funcIntoDynRestAdapter(lowerer, fromT, toT, loc); if (fromT.rest === true || toT.rest === true) return null; if (fromT.params.length > toT.params.length) return null; // Piece dispositions beyond coercibleValue, all CHECKER-APPROVED diff --git a/packages/compiler/src/frontend/lowering/expressions/hosted-narrowing.ts b/packages/compiler/src/frontend/lowering/expressions/hosted-narrowing.ts new file mode 100644 index 000000000..87a7ba38e --- /dev/null +++ b/packages/compiler/src/frontend/lowering/expressions/hosted-narrowing.ts @@ -0,0 +1,157 @@ +/* Narrowings that refine record arms without naming a stored arm. */ +import type { Lowerer } from "../lowerer.js"; +import { type IrExpr, type IrType, type SrcLoc, typeEquals } from "../../../ir/ir.js"; + +/** A checker narrowing can refine the arms of a union of records with an + * intersection: a predicate `r is Route & { path: string }`, or the + * `"path" in r` narrowing, which intersects arms that do not declare the + * name with `Record<"path", unknown>`. Each narrowed arm then maps to a + * new record shape that is not an arm of the stored union, although the + * value never changed layout. A stored record arm HOSTS a narrowed record + * when both name the same members, each narrowed member refined to a + * subset of the stored slot type (or to `unknown`); a member an assertion + * attached to the stored shape (assertion-members.ts) may be missing from + * the narrowed one. A required member the stored arm does not declare + * cannot exist on its values: native records are closed, so `in` already + * answers false there and the narrowed arm is uninhabited. + * + * Only unions of two or more record arms without a literal discriminant + * qualify: discriminated unions narrow by their discriminant, and a + * record with unit arms keeps its own predicate-strengthening reads. + * + * Returns the stored arms that can hold a value of the narrowed type, or + * null when the union does not qualify, when some narrowed arm is neither + * a stored arm nor a record, or when no stored arm is excluded (there is + * nothing to narrow). */ +export function hostedArmTags( + lowerer: Lowerer, + fromId: string, + narrowed: IrType, +): Set | null { + const from = lowerer.unions.get(fromId); + if (!from || !recordUnion(lowerer, fromId)) return null; + const narrowedArms = + narrowed.kind === "union" ? lowerer.unions.get(narrowed.unionId)?.arms : [narrowed]; + if (!narrowedArms || narrowedArms.length === 0) return null; + const allowed = new Set(); + let refined = false; + for (const arm of narrowedArms) { + const direct = lowerer.armTag(fromId, arm); + if (direct >= 0) { + allowed.add(direct); + continue; + } + if (arm.kind !== "record") return null; + refined = true; + from.arms.forEach((stored, tag) => { + if (stored.kind === "record" && recordHosts(lowerer, stored.shapeId, arm.shapeId)) { + allowed.add(tag); + } + }); + } + if (!refined || allowed.size === 0 || allowed.size === from.arms.length) return null; + return allowed; +} + +/** A union of at least two record arms without a literal discriminant. */ +function recordUnion(lowerer: Lowerer, unionId: string): boolean { + const def = lowerer.unions.get(unionId); + if (!def || def.discriminant) return false; + return def.arms.filter((arm) => arm.kind === "record").length >= 2; +} + +/** Whether every value of `narrowed` (a checker refinement of a value + * stored as `storage`) lives in the stored layout: each narrowed arm is a + * stored arm or a record a stored record arm hosts (see hostedArmTags), + * and at least one needs the hosting. A union storage must qualify as in + * hostedArmTags; a single record only when an assertion attached members + * to it. A binding initialized by such an assertion keeps the stored type, + * so its member writes reach the asserted object. */ +export function hostsAll(lowerer: Lowerer, storage: IrType, narrowed: IrType): boolean { + if (typeEquals(storage, narrowed)) return false; + let storedArms: readonly IrType[]; + if (storage.kind === "union") { + if (!recordUnion(lowerer, storage.unionId)) return false; + storedArms = lowerer.unions.get(storage.unionId)!.arms; + } else if (storage.kind === "record" && lowerer.shapes.attachedNames(storage.shapeId).length) { + storedArms = [storage]; + } else { + return false; + } + const narrowedArms = + narrowed.kind === "union" ? lowerer.unions.get(narrowed.unionId)?.arms : [narrowed]; + if (!narrowedArms || narrowedArms.length === 0) return false; + let refined = false; + for (const arm of narrowedArms) { + if (storedArms.some((stored) => typeEquals(stored, arm))) continue; + if (arm.kind !== "record") return false; + const hosted = storedArms.some( + (stored) => stored.kind === "record" && recordHosts(lowerer, stored.shapeId, arm.shapeId), + ); + if (!hosted) return false; + refined = true; + } + return refined; +} + +function recordHosts(lowerer: Lowerer, storedId: string, narrowedId: string): boolean { + const stored = lowerer.shapes.get(storedId); + const narrowed = lowerer.shapes.get(narrowedId); + if (!stored || !narrowed || stored.tuple || narrowed.tuple) return false; + if (stored.indexValue || narrowed.indexValue) return false; + const attached = lowerer.shapes.attachedNames(storedId); + for (const sf of stored.fields) { + if (!narrowed.fields.some((nf) => nf.name === sf.name) && !attached.includes(sf.name)) + return false; + } + for (const nf of narrowed.fields) { + const sf = stored.fields.find((f) => f.name === nf.name); + if (!sf || !slotRefines(lowerer, nf.type, sf.type)) return false; + } + return true; +} + +/** Whether a stored slot of type `stored` can be read as `narrowed`: the + * same type, `unknown`, or a subset of the stored union's arms (a read + * site narrows from the stored slot exactly as it does for a predicate + * strengthening one record). */ +function slotRefines(lowerer: Lowerer, narrowed: IrType, stored: IrType): boolean { + if (typeEquals(narrowed, stored) || narrowed.kind === "dyn") return true; + if (stored.kind !== "union") return false; + if (narrowed.kind !== "union") return lowerer.armTag(stored.unionId, narrowed) >= 0; + const arms = lowerer.unions.get(narrowed.unionId)?.arms; + return !!arms && arms.every((arm) => lowerer.armTag(stored.unionId, arm) >= 0); +} + +/** The stored view of a hosted narrowing (see hostedArmTags): one stored + * record arm extracted with the checked helper, or the sub-union of the + * hosting arms re-tagged with the excluded arms as traps. Both keep the + * value's stored layout, so member reads and writes reach the same + * object. Null when the narrowing is not a hosted one. */ +export function hostedStorageView( + lowerer: Lowerer, + value: IrExpr, + narrowed: IrType, + loc: SrcLoc, +): IrExpr | null { + if (value.type.kind !== "union") return null; + const fromId = value.type.unionId; + const allowed = hostedArmTags(lowerer, fromId, narrowed); + if (!allowed) return null; + const from = lowerer.unions.get(fromId)!; + if (allowed.size === 1) { + const arm = from.arms[[...allowed][0]!]!; + const helper = lowerer.narrowedArmHelper(fromId, arm, loc); + return helper ? lowerer.checkedNarrowCall(helper, value, arm, loc) : null; + } + const arms = from.arms.filter((_, tag) => allowed.has(tag)); + const subId = lowerer.unions.transform(from, arms); + const trappable = new Set(); + from.arms.forEach((_, tag) => { + if (!allowed.has(tag)) trappable.add(tag); + }); + const helper = lowerer.unionRetagHelper(fromId, subId, loc, trappable); + if (!helper) return null; + const type: IrType = { kind: "union", unionId: subId }; + return { kind: "call", callee: helper, args: [value], type, loc }; +} diff --git a/packages/compiler/src/frontend/lowering/expressions/identifiers.ts b/packages/compiler/src/frontend/lowering/expressions/identifiers.ts index 1a1ad6e1e..27ce7327e 100644 --- a/packages/compiler/src/frontend/lowering/expressions/identifiers.ts +++ b/packages/compiler/src/frontend/lowering/expressions/identifiers.ts @@ -365,19 +365,25 @@ export function lowerIdentifierExpr(lowerer: Lowerer, expr: ts.Identifier, loc: // MODULE compile-time constants, the containing file's location // (Node's exact values when the same tree runs in place; WASI uses // the equivalent guest-visible path; locals shadowing the names - // resolved above). In a file with ESM syntax Node never defines them - // (ReferenceError) — fence rather than invent a value there. + // resolved above), the same strings as import.meta.dirname/filename. + // In a JavaScript ES module Node never defines them, so the read throws + // Node's catchable ReferenceError. A .ts/.tsx file keeps them even when + // Node's strip-types rule would load it as ESM: TypeScript projects are + // commonly built as CommonJS bundles (tsc, esbuild, tsx) where these + // globals exist, and @types/node declares them for every file. if ( (expr.text === "__dirname" || expr.text === "__filename") && lowerer.isStdlibGlobal(expr, expr.text) ) { const sf = expr.getSourceFile(); - if (isNodeEsmFile(sf, lowerer.program)) { - lowerer.unsupported( - "SC1090", - expr, - `'${expr.text}' in an ES module (Node defines the CJS module globals only in CommonJS modules)`, - ); + if (isNodeEsmFile(sf, lowerer.program) && !/\.tsx?$/.test(sf.fileName)) { + return { + kind: "libCall", + fn: "global.undefRead", + args: [{ kind: "strLit", value: expr.text, type: STRING, loc }], + type: STRING, + loc, + }; } // The WASI runner mounts the host cwd at guest `/` and the host temp // directory at `/tmp`. Bake the matching GUEST spelling so resource diff --git a/packages/compiler/src/frontend/lowering/expressions/narrowing.ts b/packages/compiler/src/frontend/lowering/expressions/narrowing.ts index f0a78a1c5..fc78e3a38 100644 --- a/packages/compiler/src/frontend/lowering/expressions/narrowing.ts +++ b/packages/compiler/src/frontend/lowering/expressions/narrowing.ts @@ -29,6 +29,7 @@ import { isOptionalProcessStreamProperty } from "../builtins/process.js"; import { literalValues } from "../../literal-values.js"; import { literalUnionArm } from "../../union-discriminants.js"; import { checkedArmExtraction } from "../coercions/unions.js"; +import { hostedStorageView, hostsAll } from "./hosted-narrowing.js"; import { nodeThrowExpr, varRef } from "../../../ir/build.js"; import { InternalCompilerError } from "../../../errors.js"; import { @@ -659,6 +660,12 @@ export function maybeNarrow(lowerer: Lowerer, expr: IrExpr, node: ts.Node): IrEx }; } } + // A narrowing that refines record arms with an intersection keeps the + // stored layout: view the value as the stored arms that can hold it. + if (narrowed?.kind === "union") { + const hosted = hostedStorageView(lowerer, expr, narrowed, expr.loc); + if (hosted) return hosted; + } // A checker type narrowed to a UNIT arm (the `=== undefined` branch) // also stays union-typed: a unit arm has no payload to extract, and // nothing useful reads such a value anyway. (Standalone undefined maps @@ -668,6 +675,14 @@ export function maybeNarrow(lowerer: Lowerer, expr: IrExpr, node: ts.Node): IrEx return expr; } const tag = lowerer.armTag(expr.type.unionId, narrowed); + if ( + tag < 0 && + narrowed.kind === "record" && + !lowerer.unions.get(expr.type.unionId)?.discriminant + ) { + const hosted = hostedStorageView(lowerer, expr, narrowed, expr.loc); + if (hosted) return hosted; + } if (tag < 0) { // The checker may refine fields inside a discriminated record too. // That creates a different mapped shape, but does not change the @@ -926,6 +941,10 @@ export function runtimeOptionalReceiverRead( loc, ); if (!helper) { + // Intersection-refined record arms read through their stored + // layout (the predicate `r is Route & { path: string }`). + const hosted = hostedStorageView(lowerer, varRef(local.id, local.type, loc), narrowed, loc); + if (hosted) return hosted; lowerer.unsupported( "SC1090", expr, @@ -946,6 +965,10 @@ export function runtimeOptionalReceiverRead( // path below; mixed storage also needs to validate its concrete class. if (view && (lowerer.unions.get(local.type.unionId)?.arms.length ?? 0) > 2) return view; } + if (narrowed.kind === "record" && lowerer.armTag(local.type.unionId, narrowed) < 0) { + const hosted = hostedStorageView(lowerer, varRef(local.id, local.type, loc), narrowed, loc); + if (hosted) return hosted; + } const undefTag = lowerer.armTag(local.type.unionId, UNDEFINED_T); const def = lowerer.unions.get(local.type.unionId); if (!def || undefTag < 0) @@ -1302,6 +1325,12 @@ export function lowerAsExpression( ) { return lowerer.coerceInto(expr, inner, target); } + // `job as Job & { startedAt: number }` on a record: the asserted + // record refines the stored one, so the assertion keeps the object + // (a width copy would sever writes through the asserted view). + if (inner.type.kind === "record" && target && hostsAll(lowerer, inner.type, target)) { + return inner; + } // Static assertions normally erase, but record layouts are // monomorphic: a consumer selected from the asserted shape must see // that shape physically. Reuse the ordinary slot coercion so plain @@ -1328,6 +1357,12 @@ export function lowerAsExpression( return lowerer.checkedNarrowCall(helper, inner, target, locOf(expr)); } } + // An intersection refining the stored record arms keeps the value + // (hosted-narrowing.ts): the stored arms that can hold it. + if (target && (target.kind === "union" || target.kind === "record")) { + const hosted = hostedStorageView(lowerer, inner, target, locOf(expr)); + if (hosted) return hosted; + } } // `node.parent as Sub | undefined`: a union target whose class arm is // narrower than the stored class gets the same checked class view as diff --git a/packages/compiler/src/frontend/lowering/expressions/relational.ts b/packages/compiler/src/frontend/lowering/expressions/relational.ts index d1a9b8b3a..146766a46 100644 --- a/packages/compiler/src/frontend/lowering/expressions/relational.ts +++ b/packages/compiler/src/frontend/lowering/expressions/relational.ts @@ -38,7 +38,7 @@ import { lowerCryptoKeyInstanceof } from "../builtins/webcrypto.js"; import { lowerNetAddressInstanceof } from "../builtins/net-address.js"; import { fenceEarlyNsMemberRef, nsMemberIdentOf } from "../lower-namespaces.js"; import { maybePromiseInstanceOf } from "../maybe-promise.js"; -import { isSafeToDiscard } from "./evaluation-safety.js"; +import { isSafeToDiscard, isSafeToRepeat } from "./evaluation-safety.js"; import { type ClassInfo, storedClassValueType } from "../lower-classes.js"; import { classInstanceOf } from "../class-dynamic-dispatch.js"; import { InternalCompilerError } from "../../../errors.js"; @@ -1491,13 +1491,14 @@ export function lowerInExpression( // arm answers membership STATICALLY (a declared non-optional field is // always present, an undeclared name never is), so the whole test // collapses to runtime TAG tests — tsc's own narrowing then types the - // branches (the discriminating-`in` idiom). Optional (undefined-armed) - // fields and tuple/index-signature arms answer per VALUE, not per arm - // — those unions keep the fence below. + // branches (the discriminating-`in` idiom). An arm declaring the key + // as an optional (undefined-armed) slot answers per VALUE instead: + // its tag test joins that payload's presence test (see + // perValueUnionIn). Tuple/index-signature arms keep the fence below. if (recv.type.kind === "union") { const unionId = recv.type.unionId; const arms = lowerer.unions.get(unionId)?.arms ?? []; - const answers: { tag: number; has: boolean }[] = []; + const answers: { tag: number; has: boolean | "slot"; arm: IrType }[] = []; let staticAnswers = arms.length > 0; for (const arm of arms) { const tag = lowerer.armTag(unionId, arm); @@ -1514,14 +1515,17 @@ export function lowerInExpression( f.type.kind === "union" && lowerer.armTag(f.type.unionId, UNDEFINED_T) >= 0 ) { - staticAnswers = false; // an optional slot: presence is per-value - break; + answers.push({ tag, has: "slot", arm }); // presence is per-value + continue; } // Accessor properties are own properties to `in` (Node answers // true without invoking the getter) — either slot present makes // the name a member. const acc = shape.fields.some((x) => x.name === `%get:${key}` || x.name === `%set:${key}`); - answers.push({ tag, has: f !== undefined || acc || inherited }); + answers.push({ tag, has: f !== undefined || acc || inherited, arm }); + } + if (staticAnswers && answers.some((a) => a.has === "slot")) { + return perValueUnionIn(lowerer, recv, unionId, key, answers, loc); } if (staticAnswers) { const pureRecv = @@ -1673,6 +1677,75 @@ export function lowerInExpression( ); } +/** `"k" in u` over a union of fixed record shapes where some arm declares + * `k` as an optional slot. Arms without the name answer false and arms + * with an always-present member answer true, both by tag; an optional + * slot answers its payload's own-property presence (an explicit + * undefined is present, an omitted or deleted property is not), read + * through the checked arm extraction the tag test has just proven. The + * receiver evaluates once: a non-repeatable one is stabilized in a + * hidden local first. */ +function perValueUnionIn( + lowerer: Lowerer, + recv: IrExpr, + unionId: string, + key: string, + answers: readonly { tag: number; has: boolean | "slot"; arm: IrType }[], + loc: SrcLoc, +): IrExpr { + const recvType = recv.type; + const stable = isSafeToRepeat(recv) ? null : lowerer.declareHiddenLocal("%inRecv", recvType); + const ref = (): IrExpr => (stable ? varRef(stable.id, recvType, loc) : recv); + const isTag = (tag: number): IrExpr => ({ + kind: "unionIsTag", + unionId, + tag, + negated: false, + value: ref(), + type: BOOL, + loc, + }); + let out: IrExpr | null = null; + for (const a of answers) { + if (a.has === false) continue; + let test = isTag(a.tag); + if (a.has === "slot" && a.arm.kind === "record") { + test = { + kind: "logical", + op: "&&", + left: test, + right: { + kind: "recordHas", + obj: { + kind: "unionNarrow", + unionId, + tag: a.tag, + value: ref(), + type: a.arm, + loc, + }, + shapeId: a.arm.shapeId, + field: key, + type: BOOL, + loc, + }, + type: BOOL, + loc, + }; + } + out = out ? { kind: "logical", op: "||", left: out, right: test, type: BOOL, loc } : test; + } + const result: IrExpr = out ?? { kind: "boolLit", value: false, type: BOOL, loc }; + if (!stable) return result; + return { + kind: "seqExpr", + stmts: [{ kind: "varDecl", localId: stable.id, init: recv, loc }], + result, + type: BOOL, + loc, + }; +} + /** The runtime-key `in` (see lowerInExpression): `k in r` where k is a * runtime string and r an index-signature record — an interned * `%rec.haskey.(k, r)` walks the declared names (a string-equality diff --git a/packages/compiler/src/frontend/lowering/expressions/typeof.ts b/packages/compiler/src/frontend/lowering/expressions/typeof.ts index 30d24e22a..c56ef4097 100644 --- a/packages/compiler/src/frontend/lowering/expressions/typeof.ts +++ b/packages/compiler/src/frontend/lowering/expressions/typeof.ts @@ -13,6 +13,7 @@ import { } from "../../../ir/ir.js"; import { lowerWebAssemblyTypeof } from "../builtins/webassembly.js"; import { isNavigatorGlobal } from "../builtins/navigator.js"; +import { processHasIpc } from "../builtins/process.js"; import { lowerPerfHooksTypeof } from "../builtins/performance.js"; import { isNodeModuleValue } from "../lower-node-module.js"; import { builtinClassRefOf } from "../builtins/class-values.js"; @@ -27,7 +28,7 @@ import { typeofAnswer, } from "../lower-exprs.js"; import { tryLowerExpression } from "./try-lower-expression.js"; -import { isJsSourceFile } from "../../program.js"; +import { isJsSourceFile, isNodeEsmFile } from "../../program.js"; import { isSafeToDiscard, isSafeToRepeat } from "./evaluation-safety.js"; import { varRef } from "../../../ir/build.js"; import { isExecExceptionType, refuseExecExceptionCode } from "../builtins/errors.js"; @@ -38,8 +39,41 @@ export function lowerTypeofExpr(lowerer: Lowerer, expr: ts.TypeOfExpression, loc if (webAssembly) return webAssembly; if (lowerer.isStdlibGlobal(expr.expression, "process")) return { kind: "strLit", value: "object", type: STRING, loc }; + { + let operand = expr.expression; + while (ts.isParenthesizedExpression(operand)) operand = operand.expression; + const ipcMember = + ts.isPropertyAccessExpression(operand) && !operand.questionDotToken + ? lowerer.stdlibGlobalMember(operand, "process") + : null; + if (ipcMember === "send" || ipcMember === "disconnect") { + return { + kind: "ternary", + cond: processHasIpc(lowerer, loc), + then: { kind: "strLit", value: "function", type: STRING, loc }, + else_: { kind: "strLit", value: "undefined", type: STRING, loc }, + type: STRING, + loc, + }; + } + } if (lowerer.isStdlibGlobal(expr.expression, "fetch")) return { kind: "strLit", value: "function", type: STRING, loc }; + // `__dirname` / `__filename` in a JavaScript ES module, where Node never + // defines them: typeof answers "undefined" instead of throwing. + { + let operand = expr.expression; + while (ts.isParenthesizedExpression(operand)) operand = operand.expression; + if ( + ts.isIdentifier(operand) && + (operand.text === "__dirname" || operand.text === "__filename") && + lowerer.isStdlibGlobal(operand, operand.text) + ) { + const sf = operand.getSourceFile(); + if (isNodeEsmFile(sf, lowerer.program) && !/\.tsx?$/.test(sf.fileName)) + return { kind: "strLit", value: "undefined", type: STRING, loc }; + } + } if (isNavigatorGlobal(lowerer, expr.expression)) return { kind: "strLit", value: "object", type: STRING, loc }; const performance = lowerPerfHooksTypeof(lowerer, expr.expression); diff --git a/packages/compiler/src/frontend/lowering/expressions/updates.ts b/packages/compiler/src/frontend/lowering/expressions/updates.ts index 8b98389b6..2270f6043 100644 --- a/packages/compiler/src/frontend/lowering/expressions/updates.ts +++ b/packages/compiler/src/frontend/lowering/expressions/updates.ts @@ -1,5 +1,6 @@ /* Increment, decrement and prefix unary operators, and compound field updates. */ import * as ts from "../../ts7/adapter.js"; +import { isStrictCode } from "../strict-mode.js"; import { isPrivateWriteReceiver } from "../private-brands.js"; import type { Lowerer } from "../lowerer.js"; import { @@ -751,6 +752,7 @@ export function fieldSetStmt( className: target.className, field: target.field, value, + ...(isStrictCode(blame) ? {} : { sloppy: true as const }), loc, } : { diff --git a/packages/compiler/src/frontend/lowering/key-order-witness.ts b/packages/compiler/src/frontend/lowering/key-order-witness.ts index ba8001792..437a29563 100644 --- a/packages/compiler/src/frontend/lowering/key-order-witness.ts +++ b/packages/compiler/src/frontend/lowering/key-order-witness.ts @@ -224,12 +224,30 @@ export function applyKeyOrderWitnesses(lowerer: Lowerer, fns: readonly IrFunctio const loops: number[] = []; let loopIds = 0; const loopKey = (): string => loops.join("/"); + /** Bindings initialized by another binding's reference (`const view = + * value`, the snapshot a union-receiver write takes), so writes through + * either count as writes through the one object. */ + const aliases = new Map(); + const bindingOf = (obj: IrExpr): string | null => { + let o = obj; + while (o.kind === "unionNarrow" || o.kind === "downcast") o = o.value; + if (o.kind !== "varRef") return null; + let id = o.localId; + const seen = new Set(); + for (;;) { + const alias = aliases.get(id); + if (!alias || alias.fn !== fnName || inits.get(id)?.count !== 1 || seen.has(id)) return id; + seen.add(id); + id = alias.target; + } + }; const noteInit = (id: string, init: IrExpr): void => { const previous = inits.get(id); if (previous !== undefined) { previous.count++; return; } + if (init.kind === "varRef") aliases.set(id, { target: init.localId, fn: fnName }); const fresh = init.kind === "recordLit" || init.kind === "recordClone" || @@ -315,7 +333,7 @@ export function applyKeyOrderWitnesses(lowerer: Lowerer, fns: readonly IrFunctio field: st.field, kind: st.value.kind === "fieldAbsent" ? "delete" : "write", fn: fnName, - binding: st.obj.kind === "varRef" ? st.obj.localId : null, + binding: bindingOf(st.obj), loop: loopKey(), pos, }); diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index c51b75b03..edd36b9cc 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -229,6 +229,7 @@ import { } from "./optional-arguments.js"; import { fenceSymbolFieldCopy } from "./symbol-fields.js"; import { lowerClassDataDescriptor, lowerClassDescriptorRead } from "./class-descriptors.js"; +import { lowerClassFieldDefine, lowerClassIntegrity } from "./class-attributes.js"; import { classStaticDataFor } from "./class-static-data.js"; import { lowerUrlFactory } from "./lower-url.js"; import { nullishValueUnitOf } from "./binding-analysis.js"; @@ -7789,6 +7790,8 @@ function lowerObjectStaticCall( if (target && declaredTarget && isDynTypedRefType(declaredTarget)) target = lowerer.coerceToExpected(target, declaredTarget); if (target && member === "defineProperty") { + const field = lowerClassFieldDefine(lowerer, call, target); + if (field) return field; const native = lowerClassDataDescriptor(lowerer, call, member, target); if (native) return native; } @@ -7931,6 +7934,19 @@ function lowerObjectStaticCall( loc, }; } + if (member === "preventExtensions" || member === "seal") { + const integrity = lowerClassIntegrity(lowerer, call, member, value); + if (integrity) return integrity; + } else if (isDynTypedRefType(value.type)) { + // The instance's checked view carries its integrity state. + return { + kind: "libCall", + fn: member === "isSealed" ? "dyn.isSealed" : "dyn.isExtensible", + args: [lowerer.coerceToExpected(value, DYN)], + type: BOOL, + loc: locOf(call), + }; + } if (value.type.kind === "dyn") { const operation = { preventExtensions: "dyn.preventExtensions", @@ -8001,6 +8017,8 @@ function lowerObjectStaticCall( ) ) return value; + const integrity = lowerClassIntegrity(lowerer, call, "freeze", value); + if (integrity) return integrity; lowerer.noLowering( "Object.freeze of a possibly-aliased value", call, diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 1525c6137..241c6f580 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -89,7 +89,6 @@ import { isCjsJsFile, isJsSourceFile, isModuleExportsAccess, - isNodeTypesPath, locOf, } from "../program.js"; import { PoisonError, dynFallbackType, jsFuncNameOf, newFnCtx, own } from "./lowerer.js"; @@ -1053,9 +1052,11 @@ export function builtinStreamInfoOf( if (rec.lib === symbol.name) irName = name; } if (!irName) return null; + // Both the bundled declarations and @types/node declare the classes + // inside `declare module "stream"` (@types/node nests them in the module's + // `internal` namespace). const declared = symbol.declarations.some((d) => { if (!ts.isClassDeclaration(d)) return false; - if (isNodeTypesPath(d.getSourceFile().fileName)) return false; let node: ts.Node | undefined = d.parent; while (node) { if (ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name)) { @@ -8256,6 +8257,7 @@ export function fieldInitStmts(lowerer: Lowerer, info: ClassInfo, thisLocal: IrL className: info.def.name, field: f.name, value: dynUndefinedExpr(loc), + define: true, loc, }); } @@ -8271,6 +8273,7 @@ export function fieldInitStmts(lowerer: Lowerer, info: ClassInfo, thisLocal: IrL className: info.def.name, field: f.name, value, + define: true, loc: locOf(f.initializer), }); } catch (e) { diff --git a/packages/compiler/src/frontend/lowering/lower-inspect.ts b/packages/compiler/src/frontend/lowering/lower-inspect.ts index 6f01cee19..3be155402 100644 --- a/packages/compiler/src/frontend/lowering/lower-inspect.ts +++ b/packages/compiler/src/frontend/lowering/lower-inspect.ts @@ -21,6 +21,7 @@ import { type SrcLoc, canConvertToDyn, canDynCheckTo, + CLASS_FIELD_ATTRIBUTES_PREFIX, classDynViewSupported, DYN_CLASS_PROPERTIES, isClassOwnEnumerableFieldName, @@ -500,12 +501,16 @@ function classInspectsThroughView(lowerer: Lowerer, info: ClassInfo | undefined) ); } -/** Whether a class holds properties added outside its declared layout, which - * only its checked-dynamic view can list. Decided after lowering, when the +/** Whether a class holds properties added outside its declared layout, or + * fields Object.defineProperty can make non-enumerable, which only its + * checked-dynamic view lists as Node does. Decided after lowering, when the * class has its final fields. */ function classInspectsAddedProperties(lowerer: Lowerer, info: ClassInfo): boolean { return ( - info.def.fields.some((field) => field.name === DYN_CLASS_PROPERTIES) && + info.def.fields.some( + (field) => + field.name === DYN_CLASS_PROPERTIES || field.name.startsWith(CLASS_FIELD_ATTRIBUTES_PREFIX), + ) && classDynViewSupported( info.def.fields, (id) => lowerer.shapes.get(id), diff --git a/packages/compiler/src/frontend/lowering/lower-mock.ts b/packages/compiler/src/frontend/lowering/lower-mock.ts index 4f446bb89..be68abaca 100644 --- a/packages/compiler/src/frontend/lowering/lower-mock.ts +++ b/packages/compiler/src/frontend/lowering/lower-mock.ts @@ -154,7 +154,12 @@ function mockWrapperFactory( const { fn, call, calls, once, onceEntry, result, args } = mockContextFields(lowerer, ctxType)!; const impl = `${name}.impl`; const ctx = () => varRef("ctx.0", ctxType, loc); + // A checked-dynamic rest function (mock.fn()'s default type) takes its + // arguments as one trailing dyn array, recorded as the call's arguments + // and spread into the implementation. + const dynRest = fn.rest === true && fn.restAbi === undefined; const params = fn.params.map((type, i) => ({ localId: `p${i}.0`, name: `p${i}`, type })); + if (dynRest) params.push({ localId: "rest.0", name: "args", type: DYN }); const paramRefs = () => params.map((p) => varRef(p.localId, p.type, loc)); const argumentsValue = (): IrExpr => fn.rest @@ -219,13 +224,23 @@ function mockWrapperFactory( loc, }; }; - const invoke: IrExpr = { - kind: "callValue", - callee: varRef("f.0", fn, loc), - args: paramRefs(), - type: fn.ret, - loc, - }; + const invoke: IrExpr = dynRest + ? { + kind: "dynCall", + callee: { kind: "dynFrom", value: varRef("f.0", fn, loc), type: DYN, loc }, + calleeName: "implementation", + args: paramRefs(), + spreads: [{ arg: 0, what: "args" }], + type: DYN, + loc, + } + : { + kind: "callValue", + callee: varRef("f.0", fn, loc), + args: paramRefs(), + type: fn.ret, + loc, + }; const tryBody: IrStmt[] = voidReturn ? [ { kind: "exprStmt", expr: invoke, loc }, @@ -629,7 +644,37 @@ function requireUndefinedResultArm( } } -/** mock.fn(original, implementation?) and t.mock.fn(...). */ +/** `%mock.noop.N`: mock.fn()'s original, Node's `function () {}` — it + * returns undefined. Null when the function type's return type cannot hold + * undefined. */ +function mockNoopOriginal( + lowerer: Lowerer, + ctxType: IrType, + fn: FuncType, + loc: SrcLoc, +): IrExpr | null { + const voidReturn = fn.ret.kind === "void" || fn.ret.kind === "undefinedT"; + const undefinedValue = voidReturn ? null : lowerer.wrappedUndefined(fn.ret, loc); + if (!voidReturn && !undefinedValue) return null; + const name = liftOnce(lowerer, ctxType, "noop", (name) => { + const params = fn.params.map((type, i) => ({ localId: `p${i}.0`, name: `p${i}`, type })); + if (fn.rest === true && fn.restAbi === undefined) + params.push({ localId: "rest.0", name: "args", type: DYN }); + lowerer.liftedFns.push({ + name, + params, + returnType: fn.ret, + locals: params.map((p) => local(p.localId, p.name, p.type)), + body: [{ kind: "return", value: undefinedValue, loc }], + loc, + }); + }); + return { kind: "closure", fnName: name, captures: [], type: fn, loc }; +} + +/** mock.fn(original?, implementation?) and t.mock.fn(...). Without an + * original, the mock's original and implementation are a function that + * returns undefined, as in Node. */ export function lowerMockFn( lowerer: Lowerer, call: ts.CallExpression, @@ -658,11 +703,19 @@ export function lowerMockFn( const { fn } = fields; requireUndefinedResultArm(lowerer, fields, call, what); const args = call.arguments.nodes; - if (args.length === 0 || args.length > 2 || args.some(ts.isSpreadElement)) { + if (args.length > 2 || args.some(ts.isSpreadElement)) { lowerer.noLowering( `${what} with ${args.length} arguments`, call, - "the supported forms are mock.fn(original) and mock.fn(original, implementation); mock.fn() and mock options have no lowering", + "the supported forms are mock.fn(), mock.fn(original) and mock.fn(original, implementation); mock options have no lowering", + ); + } + const noop = args.length === 0 ? mockNoopOriginal(lowerer, ctxType!, fn, loc) : null; + if (args.length === 0 && !noop) { + lowerer.noLowering( + `${what}() of a function returning '${lowerer.fmt(fn.ret)}'`, + call, + "mock.fn() without an original returns undefined: pass an original, or use a function type whose return type includes undefined", ); } const stmts: IrStmt[] = []; @@ -670,7 +723,7 @@ export function lowerMockFn( stmts.push({ kind: "varDecl", localId: originalLocal.id, - init: lowerer.lowerExprExpecting(args[0]!, fn), + init: noop ?? lowerer.lowerExprExpecting(args[0]!, fn), loc, }); const implementation = diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index c79f2a9cd..9831ad0be 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -1,4 +1,5 @@ import { lowerTupleAliasDecl, stripTypeWrappers } from "./typed-arguments.js"; +import { hostsAll } from "./expressions/hosted-narrowing.js"; import { matchAllRowsReadByElements, storedMatchAllRowsReadByElements, @@ -16,7 +17,7 @@ import { InternalCompilerError } from "../../errors.js"; * flow (if/while/for/for-of/do, switch, try/catch, abrupt completions), * explicit resource management, and blocked-binding poisoning. */ import * as ts from "../ts7/adapter.js"; -import { processDataMemberValue } from "./builtins/process.js"; +import { processDataMemberValue, programReadsExitCode } from "./builtins/process.js"; import { requireInitFlagStmt } from "./require-initialization.js"; import { isJsonRequireDecl } from "./json-require.js"; import { bindingSource } from "../binding-source.js"; @@ -87,11 +88,11 @@ import { isCjsJsFile, isEsModuleStamp, isJsSourceFile, - isNodeEsmFile, locOf, requireEarlyReference, requireSpecOf, } from "../program.js"; +import { isStrictCode } from "./strict-mode.js"; import { COMPOUND_ASSIGN_OPS, type CompoundOp, @@ -5498,6 +5499,23 @@ export function lowerVarDecl( settledType = init.type; } } + // `const view = route as Route & { order: number }`: the asserted type + // refines the record arms the value is stored in (the assertion keeps + // that value, see hosted-narrowing.ts). The binding keeps the stored + // type, so writes through it reach the asserted object. An annotation + // the stored type hosts (`const view: Route & { order: number } = ...`) + // keeps it too: coercing into the annotated layout would copy the + // value and read members the writes have not created yet. + if ( + !isLet && + decl.initializer && + isAssertionInitializer(decl.initializer) && + (settledType.kind === "union" || settledType.kind === "record") && + (init.type.kind === "union" || init.type.kind === "record") && + hostsAll(lowerer, init.type, settledType) + ) { + settledType = init.type; + } // An exact class behind a generic interface keeps its native // representation so generic calls can specialize against its body. if ( @@ -6175,35 +6193,6 @@ export function lowerTry(lowerer: Lowerer, stmt: ts.TryStatement): IrStmt { }; } -function hasUseStrictDirective(statements: readonly ts.Statement[]): boolean { - for (const statement of statements) { - if (!ts.isExpressionStatement(statement) || !ts.isStringLiteral(statement.expression)) - return false; - if (statement.expression.text === "use strict") return true; - } - return false; -} - -function isStrictDelete(node: ts.DeleteExpression): boolean { - for (let parent: ts.Node | undefined = node.parent; parent; parent = parent.parent) { - if (ts.isClassDeclaration(parent) || ts.isClassExpression(parent)) return true; - if ( - ts.isFunctionLike(parent) && - parent.body && - ts.isBlock(parent.body) && - hasUseStrictDirective(parent.body.statements.nodes) - ) - return true; - if (ts.isSourceFile(parent)) { - return ( - hasUseStrictDirective(parent.statements.nodes) || - (!isCjsJsFile(parent) && (isNodeEsmFile(parent) || ts.isExternalModule(parent))) - ); - } - } - return false; -} - /** Statement-position `delete`: process.env keys → process.envUnset * (unsetenv), pure `Record` keys → recordKeyDelete (the * overflow Map delete), declared OPTIONAL fields → the field's ABSENT @@ -6319,7 +6308,7 @@ function lowerDeleteStatement(lowerer: Lowerer, expr: ts.DeleteExpression): IrSt obj = lowerer.coerceToExpected(obj, DYN); } if (obj.type.kind === "dyn") { - const strict = { kind: "boolLit", value: isStrictDelete(expr), type: BOOL, loc } as const; + const strict = { kind: "boolLit", value: isStrictCode(expr), type: BOOL, loc } as const; if (ts.isElementAccessExpression(target)) { const key = lowerer.lowerExprExpecting(target.argumentExpression, DYN); return { @@ -7305,9 +7294,12 @@ export function lowerExprStatement(lowerer: Lowerer, expr: ts.Expression): IrStm ) { const loc = locOf(expr); const value = lowerer.lowerExprExpecting(expr.right, F64); + const fn = programReadsExitCode(lowerer) + ? "process.setExitCodeTracked" + : "process.setExitCode"; return { kind: "exprStmt", - expr: { kind: "libCall", fn: "process.setExitCode", args: [value], type: VOID, loc }, + expr: { kind: "libCall", fn, args: [value], type: VOID, loc }, loc, }; } @@ -11392,3 +11384,9 @@ function ownPrototypeRef( } return false; } + +function isAssertionInitializer(node: ts.Expression): boolean { + let e = node; + while (ts.isParenthesizedExpression(e)) e = e.expression; + return ts.isAsExpression(e) || ts.isTypeAssertion(e); +} diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index 5769e1e0a..dd0ddcc0e 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -999,6 +999,15 @@ export function lowerStreamNew(lowerer: Lowerer, expr: ts.NewExpression, info: C }; } +/** True when a value of Node's argument type `passed` widens implicitly + * into the declared parameter type `declared` (one of its union arms, or a + * sub-union of it). */ +function widensInto(lowerer: Lowerer, passed: IrType, declared: IrType, loc: SrcLoc): boolean { + if (declared.kind !== "union") return false; + const probe: IrExpr = { kind: "varRef", localId: "%probe", type: passed, loc }; + return typeEquals(lowerer.coerceToExpected(probe, declared).type, declared); +} + /* ── user subclasses (`extends Readable`, the underscore-override form) ── */ /** The wrapper closure binding one overridden underscore method as the @@ -1075,10 +1084,17 @@ function streamMethodWrapper( ); } } else if (!typeEquals(got.type, want)) { + // A declared supertype of what Node passes (`chunk: Buffer | string`) + // is sound: the wrapper takes Node's value and widens it into the + // declared parameter. + if (widensInto(lowerer, want, got.type, loc)) { + paramTypes.push(want); + continue; + } lowerer.noLowering( `a '${methodName}' method whose parameter ${i} is '${lowerer.fmt(got.type)}' where Node passes '${lowerer.fmt(want)}'`, blame, - "annotate the parameter with the Node signature's type (chunks are Buffers here)", + "annotate the parameter with the Node signature's type or a supertype of it (chunks are Buffers here)", ); } paramTypes.push(got.type); @@ -1094,7 +1110,11 @@ function streamMethodWrapper( for (let i = 0; i < paramTypes.length; i++) { const local = lowerer.declareHiddenLocal(`a${i}`, paramTypes[i]!); params.push({ localId: local.id, name: local.name, type: paramTypes[i]! }); - argRefs.push({ kind: "varRef", localId: local.id, type: paramTypes[i]!, loc }); + const arg: IrExpr = { kind: "varRef", localId: local.id, type: paramTypes[i]!, loc }; + const declaredType = declared[i]!.type; + argRefs.push( + typeEquals(arg.type, declaredType) ? arg : lowerer.coerceToExpected(arg, declaredType), + ); } const thisRef: IrExpr = { kind: "varRef", localId: thisLocal.id, type: thisType, loc }; let call: IrExpr; diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index e27bf5105..6c9ccd0b7 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1,4 +1,5 @@ import { onlyForwarded } from "./typed-arguments.js"; +import { extendAssertedRecordMembers } from "./assertion-members.js"; import { jsDynamicDeclarations } from "./js-dynamic-objects.js"; import { lifetimeRegionType, @@ -117,6 +118,7 @@ import { InternalCompilerError } from "../../errors.js"; import { defaultAfterUndefined, lowerStaticallyUndefinedArgument } from "./optional-arguments.js"; import { type ProtocolDispatch } from "./class-protocol-dispatch.js"; import { ClassDynamicDispatch, trackClassFieldCreation } from "./class-dynamic-dispatch.js"; +import { guardClassAttributeWrites } from "./class-attributes.js"; import { ClassProtocols } from "./class-protocols.js"; import { earlyReadVarSymbols } from "./var-hoisting.js"; import { recordTextCodecClass } from "../../ir/ir.js"; @@ -1981,6 +1983,8 @@ export class Lowerer { readonly symbolFieldIdentities = new Map(); readonly httpClientFnBindings = new Map(); streamPropMutatedSyms: Set | null = null; + /** Whether some source reads process.exitCode (processReadsExitCode). */ + readsExitCode: boolean | null = null; requestInitPropMutatedSyms: Set | null = null; emitterEventTable: Map | null = null; emitterComputedPatterns: ComputedEventPattern[] = []; @@ -6794,6 +6798,10 @@ export class Lowerer { } this.collectProgram(parts); this.speculativeTypeQueries(() => { + extendAssertedRecordMembers( + this, + parts.map((fp) => fp.sf), + ); this.analyzeRuntimeOptionalArrayReads(parts); this.analyzeDateJsonResults(parts); this.analyzeGuardedRecordReadGlobals(parts); @@ -6942,6 +6950,7 @@ export class Lowerer { finalizeClassMethodValues(this, functions); finalizePrivateBrands(this, functions); trackClassFieldCreation(this, functions); + guardClassAttributeWrites(this, functions); // Globals typed by a class that never REGISTERED (a JS class whose // collection fenced — Symbol-keyed fields, an unsupported base): the @@ -7201,6 +7210,10 @@ export class Lowerer { }; this.collectProgram(parts); this.speculativeTypeQueries(() => { + extendAssertedRecordMembers( + this, + parts.map((fp) => fp.sf), + ); this.analyzeRuntimeOptionalArrayReads(parts); this.analyzeDateJsonResults(parts); this.analyzeGuardedRecordReadGlobals(parts); diff --git a/packages/compiler/src/frontend/lowering/strict-mode.ts b/packages/compiler/src/frontend/lowering/strict-mode.ts new file mode 100644 index 000000000..86653c1d3 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/strict-mode.ts @@ -0,0 +1,34 @@ +import * as ts from "../ts7/adapter.js"; +import { isCjsJsFile, isNodeEsmFile } from "../program.js"; + +function hasUseStrictDirective(statements: readonly ts.Statement[]): boolean { + for (const statement of statements) { + if (!ts.isExpressionStatement(statement) || !ts.isStringLiteral(statement.expression)) + return false; + if (statement.expression.text === "use strict") return true; + } + return false; +} + +/** Whether `node` runs in strict mode code: inside a class body, a function + * with a "use strict" directive, a module, or a script that starts with + * "use strict". CommonJS JavaScript is sloppy otherwise. */ +export function isStrictCode(node: ts.Node): boolean { + for (let parent: ts.Node | undefined = node.parent; parent; parent = parent.parent) { + if (ts.isClassDeclaration(parent) || ts.isClassExpression(parent)) return true; + if ( + ts.isFunctionLike(parent) && + parent.body && + ts.isBlock(parent.body) && + hasUseStrictDirective(parent.body.statements.nodes) + ) + return true; + if (ts.isSourceFile(parent)) { + return ( + hasUseStrictDirective(parent.statements.nodes) || + (!isCjsJsFile(parent) && (isNodeEsmFile(parent) || ts.isExternalModule(parent))) + ); + } + } + return false; +} diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index 0f582258a..ba1ea3c08 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -2677,8 +2677,8 @@ export const AMBIENT_SURFACE_FNS: readonly AmbientSurfaceRow[] = [ id: "node-builtin.process.exitCode", kind: "node-builtin", name: "process.exitCode", - fns: ["process.setExitCode"], - note: "numeric writes in statement position set the implicit exit status; process.exit() reads it", + fns: ["process.setExitCode", "process.setExitCodeTracked", "process.hasExitCode"], + note: "numeric writes in statement position set the implicit exit status; reads answer the assigned code or undefined; process.exit() reads it", }, // ── the tls CA store (lowerTlsCaCall / lowerTlsRootCertificates): the // host's trust anchors, read and replaced. Dedicated paths, and @@ -2990,7 +2990,7 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record< }, util: { promisify: - "the lowered shapes are const bindings over child_process.execFile, child_process.exec, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots, the crypto callback functions, dns.lookup, dns.lookupService and the fs callback functions with an fs/promises counterpart; call the bound function directly", + "the lowered shapes are const bindings over child_process.execFile, child_process.exec, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots, the crypto callback functions, dns.lookup, dns.lookupService and the fs callback functions with an fs/promises counterpart, plus typed callback-last function values whose callback takes (error?: Error | null, value?); call the bound function directly", }, "stream/consumers": { blob: diff --git a/packages/compiler/src/frontend/mock-shapes.ts b/packages/compiler/src/frontend/mock-shapes.ts index 1baf2cd04..50781c272 100644 --- a/packages/compiler/src/frontend/mock-shapes.ts +++ b/packages/compiler/src/frontend/mock-shapes.ts @@ -12,10 +12,11 @@ * object; empty for mock.fn * * A MockFunctionCall is { arguments, error, result, this }: the - * arguments as a tuple of F's parameters, the result as F's return type or - * undefined (a checked-dynamic value for functions returning void or - * undefined, since a record field cannot have a unit type), and error and - * this as checked-dynamic values. */ + * arguments as a tuple of F's parameters (a checked-dynamic array for + * mock.fn()'s `(...args: any[]) => undefined`), the result as F's return + * type or undefined (a checked-dynamic value for functions returning void + * or undefined, since a record field cannot have a unit type), and error + * and this as checked-dynamic values. */ import { DYN, F64, NULL_T, UNDEFINED_T, VOID, typeKey, type IrType } from "../ir/ir.js"; import type { TypeMapperCtx } from "./type-mapper.js"; @@ -34,11 +35,17 @@ function orUndefined(t: IrType, reg: MockShapeRegistries): IrType { } /** The arguments type of a call record: a tuple of the parameters, or the - * rest array itself for a function whose only parameter is a rest array. - * Null for other rest shapes. A function without parameters records the + * rest array itself for a function whose only parameter is a rest array, + * or a checked-dynamic array for a function returning nothing whose only + * parameter is a checked-dynamic rest (mock.fn()'s default, `(...args: + * any[]) => undefined`). Null for other rest shapes. A function without parameters records the * empty tuple, which maps to an array of the unit-only union, as * type-mapper.ts maps `[]`. */ function mockArgumentsType(fn: IrType & { kind: "func" }, reg: MockShapeRegistries): IrType | null { + if (fn.rest && fn.restAbi === undefined) { + const returnsNothing = fn.ret.kind === "void" || fn.ret.kind === "undefinedT"; + return fn.params.length === 0 && returnsNothing ? DYN : null; + } if (fn.rest) { if (fn.params.length !== 1 || fn.params[0]!.kind !== "array") return null; return fn.params[0]!; diff --git a/packages/compiler/src/frontend/npm-static-bundled-chunks.test.ts b/packages/compiler/src/frontend/npm-static-bundled-chunks.test.ts new file mode 100644 index 000000000..6bc830d74 --- /dev/null +++ b/packages/compiler/src/frontend/npm-static-bundled-chunks.test.ts @@ -0,0 +1,300 @@ +import { spawnSync } from "node:child_process"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { basename, join } from "node:path"; +import { afterAll, expect, test } from "vitest"; +import { nodeFrontendServices } from "./services-node.js"; +import { rewriteBundlerCjsExports } from "./npm-static-rewrite.js"; +import type { BundledChunkSplit } from "./npm-static-bundled-chunks.js"; + +const keyedHelper = `var __getOwnPropNames = Object.getOwnPropertyNames; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +`; + +const dirs: string[] = []; +afterAll(() => { + for (const dir of dirs) rmSync(dir, { recursive: true, force: true }); +}); + +function split(source: string, file = "/pkg/dist/index.js") { + return nodeFrontendServices().splitCjsChunks(source, file); +} + +function run(file: string) { + const result = spawnSync(process.execPath, [file], { encoding: "utf8" }); + return { status: result.status, stdout: result.stdout, stderr: result.stderr }; +} + +/** Runs the original bundle and its split modules side by side. */ +function expectSameBehavior(source: string): BundledChunkSplit { + const dir = mkdtempSync(join(tmpdir(), "scriptc-chunks-")); + dirs.push(dir); + const original = join(dir, "original.js"); + writeFileSync(original, source); + const bundle = join(dir, "index.js"); + const result = split(source, bundle); + expect(result).not.toBeNull(); + expect(result).not.toHaveProperty("degrade"); + const answer = result as BundledChunkSplit; + writeFileSync(bundle, answer.text); + for (const chunk of answer.chunks) writeFileSync(chunk.path, chunk.source); + // Respelled calls and blanked declarations keep the line structure. + expect(answer.text.split("\n")).toHaveLength(source.split("\n").length); + const oracle = run(original); + expect(oracle.status).toBe(0); + expect(run(bundle)).toEqual(oracle); + return answer; +} + +test("chunks run once, at their first require, with shared module instances", () => { + const answer = expectSameBehavior(`"use strict"; +${keyedHelper} +var require_b = __commonJS({ + "b.js"(exports2, module2) { + console.log("b init"); + module2.exports = { n: 1 }; + } +}); +var require_a = __commonJS({ + "a.js"(exports2) { + console.log("a init"); + var b = require_b(); + exports2.value = b.n + 1; + exports2.keys = Object.keys({ exports2 }); + } +}); +console.log("start"); +console.log(require_a().value, require_a().value, require_b().n, require_a().keys); +`); + expect(answer.chunks.map((c) => basename(c.path))).toEqual([ + "index.js.require_b.cjs", + "index.js.require_a.cjs", + ]); + expect(answer.text).not.toContain("require_a()"); +}); + +test("the arrow helper form and minified spellings split the same way", () => { + expectSameBehavior( + `var __commonJS=(cb,mod)=>()=>(mod||cb((mod={exports:{}}).exports,mod),mod.exports);` + + `var require_x=__commonJS((exports,module)=>{module.exports={v:"x"}});` + + `console.log(require_x().v,require_x()===require_x());`, + ); +}); + +test("esbuild 0.11's Object.keys spelling is recognized", () => { + expectSameBehavior(`var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[Object.keys(cb)[0]])((mod = {exports: {}}).exports, mod), mod.exports; +}; +var require_y = __commonJS({ + "y.js"(exports) { + exports.y = 3; + } +}); +console.log(require_y().y); +`); +}); + +test("pure helpers a chunk reads travel with it", () => { + const answer = expectSameBehavior(`${keyedHelper}var __defProp = Object.defineProperty; +var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); +var require_named = __commonJS({ + "named.js"(exports2, module2) { + module2.exports = __name(function () {}, "renamed"); + } +}); +console.log(require_named().name); +`); + const chunk = answer.chunks[0]!.source; + expect(chunk).toContain("var __name ="); + expect(chunk).toContain("var __defProp = Object.defineProperty;"); +}); + +test("a helper travels with a chunk whose nested scopes declare its name", () => { + const answer = expectSameBehavior(`${keyedHelper}function label(n) { + return "label " + n; +} +function wrap(n) { + function inner() { + var label = "inner"; + return label; + } + return label(n) + " " + inner(); +} +var require_e = __commonJS({ + "e.js"(exports2, module2) { + function nested() { + var label = "nested"; + return label; + } + var seen = []; + for (let label of ["loop"]) seen.push(label); + try { + throw "caught"; + } catch (label) { + seen.push(label); + } + { + const label = "block"; + seen.push(label); + } + module2.exports = { outer: label(1), indirect: (0, label)(3), wrapped: wrap(2), nested: nested(), seen }; + } +}); +var e = require_e(); +console.log(e.outer, e.indirect, e.wrapped, e.nested, e.seen.join(",")); +`); + const chunk = answer.chunks[0]!.source; + expect(chunk).toContain("function label(n)"); + expect(chunk).toContain("function wrap(n)"); +}); + +test("a named function expression that only calls itself travels with a chunk", () => { + const answer = expectSameBehavior(`${keyedHelper}var fact = function self(n) { + return n <= 1 ? 1 : n * self(n - 1); +}; +var kind = function self(self) { + return typeof self; +}; +var outer = function self() { + var self = 2; + return self; +}; +var require_g = __commonJS({ + "g.js"(exports2, module2) { + module2.exports = [fact(5), kind(1), outer()]; + } +}); +console.log(require_g().join(",")); +`); + const chunk = answer.chunks[0]!.source; + expect(chunk).toContain("var fact = function self(n)"); +}); + +test("a helper a parameter default reads travels with a chunk whose body declares its name", () => { + const answer = expectSameBehavior(`${keyedHelper}var ten = function () { + return 10; +}; +var add = function (n, base = ten()) { + var ten = 1; + return n + base + ten; +}; +var require_g = __commonJS({ + "g.js"(exports2, module2) { + module2.exports = add(1); + } +}); +console.log(require_g()); +`); + const chunk = answer.chunks[0]!.source; + expect(chunk).toContain("var ten = function ()"); +}); + +test.each([ + ["exports it", `function tally() {}`, `module2.exports = { tally };`], + ["reads its properties", `function tally() {}`, `exports2.calls = tally.calls;`], + ["constructs it", `function tally() {}`, `exports2.made = new tally();`], + ["stores an arrow helper", `var tally = () => 1;`, `exports2.fn = tally;`], + [ + "calls a function that reads its own name as a value", + `var tally = function self() { self.n = (self.n || 0) + 1; return self.n; };`, + `exports2.count = tally();`, + ], + [ + "calls a function whose parameter default reads its own name", + `var tally = function self(box = self) { box.n = (box.n || 0) + 1; return box.n; };`, + `exports2.count = tally();`, + ], + [ + "calls a function whose parameter default reads its own name past a body var of that name", + `var tally = function self(box = self) { var self = 0; box.n = (box.n || 0) + 1; return box.n + self; };`, + `exports2.count = tally();`, + ], +])("a chunk that %s keeps the package refused", (_, declaration, statement) => { + const result = split(`${keyedHelper}${declaration} +var require_f = __commonJS({ + "f.js"(exports2, module2) { + ${statement} + } +}); +require_f(); +`); + expect(result).toEqual({ + degrade: expect.stringContaining( + "uses the bundle's top-level function 'tally' as a value", + ) as string, + }); +}); + +test.each([ + ["reads its factory's receiver", `console.log(this);`], + ["reads its factory's arguments object", `console.log(arguments.length);`], + ["returns from its top level", `if (exports2) return;`], + ["uses its module object beyond module.exports", `console.log(module2.id);`], + ["reads __filename", `console.log(__filename);`], + ["rebinds its module parameters", `function f(module2) { return module2; }`], + ["reads the bundle's top-level binding 'state'", `console.log(state);`], +])("a chunk that %s keeps the package refused", (reason, statement) => { + const result = split(`${keyedHelper}var state = { n: 1 }; +var require_c = __commonJS({ + "c.js"(exports2, module2) { + ${statement} + } +}); +require_c(); +`); + expect(result).toEqual({ degrade: expect.stringContaining(reason) as string }); +}); + +test("a factory used other than as a direct call keeps the package refused", () => { + const result = + split(`${keyedHelper}var require_d = __commonJS({ "d.js"(exports2) { exports2.d = 1; } }); +var load = require_d; +load(); +`); + expect(result).toEqual({ + degrade: expect.stringContaining("used other than as a direct call") as string, + }); +}); + +test("an unrecognized helper body keeps the package refused", () => { + const result = + split(`var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod); +var require_e = __commonJS((exports) => { exports.e = 1; }); +require_e(); +`); + expect(result).toEqual({ degrade: expect.stringContaining("__commonJS helper") as string }); +}); + +test("files without chunks and ES-module bundles are left alone", () => { + expect(split("exports.x = 1;\n")).toBeNull(); + expect( + split(`${keyedHelper}var require_f = __commonJS({ "f.js"(e) { e.f = 1; } }); +export default require_f(); +`), + ).toBeNull(); +}); + +test("an identifier-minified bundle names its lost helper names", () => { + // esbuild --minify output: the helper shapes survive, their names do not. + const result = split( + `var c=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports);` + + `var x=c((t,m)=>{m.exports={v:1}});console.log(x().v);`, + ); + expect(result).toEqual({ degrade: expect.stringContaining("identifier-minified") as string }); +}); + +test("an ES-module bundle of CommonJS chunks names the chunk interop", () => { + const result = rewriteBundlerCjsExports( + `${keyedHelper}var __toESM = (mod) => mod; +var require_g = __commonJS({ "g.js"(exports) { exports.g = 1; } }); +var import_g = __toESM(require_g()); +export const g = import_g.g; +`, + "/pkg/dist/index.js", + ); + expect(result).toEqual({ + degrade: expect.stringContaining("bundled CommonJS modules") as string, + }); +}); diff --git a/packages/compiler/src/frontend/npm-static-bundled-chunks.ts b/packages/compiler/src/frontend/npm-static-bundled-chunks.ts new file mode 100644 index 000000000..33ff865ec --- /dev/null +++ b/packages/compiler/src/frontend/npm-static-bundled-chunks.ts @@ -0,0 +1,858 @@ +/* Bundled CommonJS chunks: esbuild wraps every CommonJS module it bundles + * in a lazily evaluated factory, + * + * var require_x = __commonJS({ "src/x.js"(exports, module) { BODY } }); + * + * and each `require_x()` runs BODY once (later calls answer the cached + * module.exports, a call during BODY answers the partial one). That is + * exactly a CommonJS module that the bundle requires at the call's + * position, so each recognized chunk becomes its own module: a virtual + * sibling file `..cjs` holding BODY, its module + * parameters respelled as the CommonJS globals, and every `require_x()` + * call becomes `require("./..cjs")`. The program then + * compiles chunks with the ordinary CommonJS machinery: evaluation at the + * require's position, the run-once module cache, export tables, and the + * __toESM interop erasure. + * + * Only shapes whose meaning is verified move: the helper must be one of + * the recognized __commonJS spellings, every reference to a factory + * binding must be a direct call, and BODY must not observe the + * difference between a factory and a module (its `this`, `arguments`, + * `__filename`, the module object beyond `module.exports`, a top-level + * return, or a binding of the bundle other than the pure helpers copied + * beside it). Anything else answers a degrade reason. */ +import * as ts from "./ts7/syntax.js"; +import { helperTokens } from "./helper-tokens.js"; + +export interface BundledChunkSplit { + /** The bundle with chunk declarations blanked and calls respelled. */ + text: string; + /** Virtual sibling modules, in declaration order. */ + chunks: { path: string; source: string }[]; +} + +interface Edit { + start: number; + end: number; + text: string; +} + +const CHUNK_SHAPE_DEGRADE = + "its shipped JS bundles CommonJS modules through the __commonJS helper in a shape the " + + "recognizer cannot verify"; + +/** The helper a counter-suffixed bundler name spells (`__commonJS2`). */ +function helperBase(name: string): string { + return /^__[A-Za-z]+\d+$/.test(name) ? name.replace(/\d+$/, "") : name; +} + +function unparen(e: ts.Expression): ts.Expression { + while (ts.isParenthesizedExpression(e)) e = e.expression; + return e; +} + +/** True for an identifier occurrence that reads or writes a binding (as + * opposed to a property name, a label, or a declaration's own name). + * Shorthand property values count: `{ x }` reads x. */ +function isReference(id: ts.Identifier): boolean { + const p = id.parent; + if (p === undefined) return false; + if (ts.isPropertyAccessExpression(p)) return p.expression === id; + if (ts.isPropertyAssignment(p)) return p.initializer === id; + if ( + ts.isMethodDeclaration(p) || + ts.isPropertyDeclaration(p) || + ts.isGetAccessorDeclaration(p) || + ts.isSetAccessorDeclaration(p) + ) + return p.name !== id; + if (ts.isBindingElement(p)) return p.initializer === id; + if (ts.isVariableDeclaration(p) || ts.isParameter(p)) return p.initializer === id; + if ( + ts.isFunctionDeclaration(p) || + ts.isFunctionExpression(p) || + ts.isClassDeclaration(p) || + ts.isClassExpression(p) + ) + return p.name !== id; + if (ts.isLabeledStatement(p)) return p.label !== id; + if (ts.isBreakStatement(p) || ts.isContinueStatement(p)) return false; + if (ts.isMetaProperty(p)) return false; + return true; +} + +/** Names a subtree declares anywhere inside it: variables (destructuring + * included), parameters, function and class names, catch bindings. */ +function declaredNames(root: ts.Node): Set { + const names = new Set(); + // Binding patterns nest BindingElements, which the walk visits too. + ts.walkPreorder(root, (n) => { + if (n.kind >= ts.SyntaxKind.FirstJSDocNode && n.kind <= ts.SyntaxKind.LastJSDocNode) + return "skip"; + if (ts.isVariableDeclaration(n) || ts.isParameter(n) || ts.isBindingElement(n)) { + const name = n.name; + if (name !== undefined && ts.isIdentifier(name)) names.add(name.text); + } else if ( + (ts.isFunctionDeclaration(n) || + ts.isFunctionExpression(n) || + ts.isClassDeclaration(n) || + ts.isClassExpression(n)) && + n.name !== undefined + ) + names.add(n.name.text); + return undefined; + }); + return names; +} + +/** Adds the identifiers a binding name (an identifier or a destructuring + * pattern) declares. */ +function addBindingNames(name: ts.BindingName, out: Set): void { + if (ts.isIdentifier(name)) { + out.add(name.text); + return; + } + for (const element of name.elements.nodes) { + if (!ts.isOmittedExpression(element) && element.name !== undefined) + addBindingNames(element.name, out); + } +} + +function isFunctionScope(n: ts.Node): n is ts.SignatureDeclaration { + return ( + ts.isFunctionDeclaration(n) || + ts.isFunctionExpression(n) || + ts.isArrowFunction(n) || + ts.isMethodDeclaration(n) || + ts.isGetAccessorDeclaration(n) || + ts.isSetAccessorDeclaration(n) || + ts.isConstructorDeclaration(n) + ); +} + +/** The `var` names a function body declares, without entering nested + * functions. Function declarations in nested blocks count as block-scoped + * here; treating one as free only adds an unused helper copy. */ +function varScopedNames(body: ts.Node): Set { + const out = new Set(); + ts.walkPreorder(body, (n) => { + if (n !== body && (isFunctionScope(n) || ts.isClassDeclaration(n) || ts.isClassExpression(n))) + return "skip"; + if (ts.isVariableDeclarationList(n) && (n.flags & ts.NodeFlags.BlockScoped) === 0) { + for (const d of n.declarations.nodes) addBindingNames(d.name, out); + } + return undefined; + }); + return out; +} + +/** The names a function binds for references in its parameter list + * (default values, computed keys of destructuring patterns): its + * parameters and a function expression's own name. Parameter initializers + * run in their own scope, so the body's `var`s are not visible there. */ +function parameterScopeNames(scope: ts.SignatureDeclaration): Set { + const out = new Set(); + for (const param of scope.parameters.nodes) addBindingNames(param.name, out); + if (ts.isFunctionExpression(scope) && scope.name !== undefined) out.add(scope.name.text); + return out; +} + +const NO_NAMES: ReadonlySet = new Set(); + +/** True when `node` lies inside `ancestor` (or is it). */ +function within(node: ts.Node, ancestor: ts.Node): boolean { + for (let n: ts.Node | undefined = node; n !== undefined; n = n.parent) + if (n === ancestor) return true; + return false; +} + +/** The names one scope node binds for the references inside it. */ +function scopeNames(scope: ts.Node): Set { + const out = new Set(); + if (isFunctionScope(scope)) { + for (const param of scope.parameters.nodes) addBindingNames(param.name, out); + if (ts.isFunctionExpression(scope) && scope.name !== undefined) out.add(scope.name.text); + if (scope.body !== undefined) for (const name of varScopedNames(scope.body)) out.add(name); + } else if (ts.isBlock(scope) || ts.isSourceFile(scope) || ts.isCaseBlock(scope)) { + const statements = ts.isCaseBlock(scope) + ? scope.clauses.nodes.flatMap((clause) => clause.statements.nodes) + : scope.statements.nodes; + for (const stmt of statements) { + if ((ts.isFunctionDeclaration(stmt) || ts.isClassDeclaration(stmt)) && stmt.name) + out.add(stmt.name.text); + else if ( + ts.isVariableStatement(stmt) && + (stmt.declarationList.flags & ts.NodeFlags.BlockScoped) !== 0 + ) { + for (const d of stmt.declarationList.declarations.nodes) addBindingNames(d.name, out); + } + } + } else if (ts.isCatchClause(scope) && scope.variableDeclaration !== undefined) { + addBindingNames(scope.variableDeclaration.name, out); + } else if ( + (ts.isForStatement(scope) || ts.isForInStatement(scope) || ts.isForOfStatement(scope)) && + scope.initializer !== undefined && + ts.isVariableDeclarationList(scope.initializer) && + (scope.initializer.flags & ts.NodeFlags.BlockScoped) !== 0 + ) { + for (const d of scope.initializer.declarations.nodes) addBindingNames(d.name, out); + } else if ( + (ts.isClassDeclaration(scope) || ts.isClassExpression(scope)) && + scope.name !== undefined + ) { + out.add(scope.name.text); + } + return out; +} + +/** Resolves references against one bundle's scopes, keeping each scope's + * names for the bundle's split. */ +class BundleScopes { + private readonly names = new Map>(); + private readonly parameterNames = new Map>(); + + private of(scope: ts.Node): Set { + let names = this.names.get(scope); + if (names === undefined) { + names = scopeNames(scope); + this.names.set(scope, names); + } + return names; + } + + /** The names `scope` binds for a reference reached through its child + * `from`: a function's parameter list sees its parameters and own name + * but not its body's `var`s, and a computed method name sees none of + * them. */ + private visible(scope: ts.Node, from: ts.Node): ReadonlySet { + if (!isFunctionScope(scope) || from === scope.body) return this.of(scope); + if (from === scope.name) return NO_NAMES; + let names = this.parameterNames.get(scope); + if (names === undefined) { + names = parameterScopeNames(scope); + this.parameterNames.set(scope, names); + } + return names; + } + + /** True when a scope between the reference and `root` (inclusive) + * binds its name. */ + boundWithin(id: ts.Identifier, root: ts.Node): boolean { + for (let from: ts.Node = id, n = id.parent; n !== undefined; from = n, n = n.parent) { + if (this.visible(n, from).has(id.text)) return true; + if (n === root) return false; + } + return false; + } + + /** True when a scope inside `root` (exclusive) binds the reference's + * name. */ + boundInside(id: ts.Identifier, root: ts.Node): boolean { + for ( + let from: ts.Node = id, n = id.parent; + n !== undefined && n !== root; + from = n, n = n.parent + ) { + if (this.visible(n, from).has(id.text)) return true; + } + return false; + } + + /** True when the reference resolves to a top-level binding of `sf`. */ + topLevel(id: ts.Identifier, sf: ts.SourceFile): boolean { + for ( + let from: ts.Node = id, n = id.parent; + n !== undefined && n !== sf; + from = n, n = n.parent + ) { + if (this.visible(n, from).has(id.text)) return false; + } + return true; + } +} + +/** Every binding reference inside a subtree. */ +function references(root: ts.Node): ts.Identifier[] { + const out: ts.Identifier[] = []; + ts.walkPreorder(root, (n) => { + if (n.kind >= ts.SyntaxKind.FirstJSDocNode && n.kind <= ts.SyntaxKind.LastJSDocNode) + return "skip"; + if (ts.isIdentifier(n) && isReference(n)) out.push(n); + return undefined; + }); + return out; +} + +/** True when the reference is written (assignment target, update operand, + * loop target, delete operand). */ +function isWritten(id: ts.Identifier): boolean { + let child: ts.Node = id; + for (let p = child.parent; p !== undefined; child = p, p = p.parent) { + if (ts.isBinaryExpression(p)) { + return ( + p.left === child && + p.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && + p.operatorToken.kind <= ts.SyntaxKind.LastAssignment + ); + } + if (ts.isPrefixUnaryExpression(p) || ts.isPostfixUnaryExpression(p)) { + return ( + p.operator === ts.SyntaxKind.PlusPlusToken || p.operator === ts.SyntaxKind.MinusMinusToken + ); + } + if (ts.isForInStatement(p) || ts.isForOfStatement(p)) return p.initializer === child; + if (ts.isDeleteExpression(p)) return true; + if ( + !( + ts.isParenthesizedExpression(p) || + ts.isArrayLiteralExpression(p) || + ts.isObjectLiteralExpression(p) || + ts.isShorthandPropertyAssignment(p) || + ts.isPropertyAssignment(p) || + ts.isSpreadElement(p) + ) + ) + return false; + } + return false; +} + +/** The recognized __commonJS helper forms, as token templates over the + * helper's own parameter names (CB, MOD) and the own-key reader (KEYS: + * esbuild's `__getOwnPropNames` alias, or `Object.keys` in esbuild 0.11): + * keyed: `(CB, MOD) => function [name]() { return ; }` — the + * factory is the only method of an object literal; + * arrow: `(CB, MOD) => () => ()` — the factory itself. */ +const KEYED_RETURN = + "MOD || (0, CB[KEYS(CB)[0]])((MOD = { exports: {} }).exports, MOD), MOD.exports"; +const ARROW_BODY = "(MOD || CB((MOD = { exports: {} }).exports, MOD), MOD.exports)"; + +function template(text: string, cb: string, mod: string, keys: string): string | null { + return helperTokens( + text + .replace(/\bCB\b/g, cb) + .replace(/\bMOD\b/g, mod) + .replace(/\bKEYS\b/g, keys), + ); +} + +type HelperForm = "keyed" | "arrow"; + +/** The helper's form, or null when its initializer is not recognized. + * `ownNames` answers whether an identifier names the verified + * Object.getOwnPropertyNames alias. */ +function helperForm( + init: ts.Expression, + sf: ts.SourceFile, + ownNames: (name: string) => boolean, +): HelperForm | null { + const fn = unparen(init); + if (!ts.isArrowFunction(fn) || fn.parameters.nodes.length !== 2) return null; + const params = fn.parameters.nodes.map((p) => + ts.isIdentifier(p.name) && p.initializer === undefined && p.dotDotDotToken === undefined + ? p.name.text + : null, + ); + const [cb, mod] = params; + if (cb === null || mod === null || cb === undefined || mod === undefined || cb === mod) + return null; + if (ts.isBlock(fn.body)) return null; + const body = unparen(fn.body); + if (ts.isFunctionExpression(body)) { + if (body.parameters.nodes.length !== 0 || body.asteriskToken || body.modifiers?.nodes.length) + return null; + const stmts = body.body.statements.nodes; + const ret = stmts[0]; + if (stmts.length !== 1 || ret === undefined || !ts.isReturnStatement(ret) || !ret.expression) + return null; + const actual = helperTokens(ret.expression.getText(sf)); + if (actual === null) return null; + // The own-key reader: esbuild's alias or the 0.11 spelling. + const keysRef = /\[\s*([A-Za-z_$][\w$]*(?:\.keys)?)\s*\(/.exec(ret.expression.getText(sf)); + const keys = keysRef?.[1]; + if (keys === undefined || (keys !== "Object.keys" && !ownNames(keys))) return null; + return actual === template(KEYED_RETURN, cb, mod, keys) ? "keyed" : null; + } + if (ts.isArrowFunction(body) && body.parameters.nodes.length === 0 && !ts.isBlock(body.body)) { + const actual = helperTokens(body.body.getText(sf)); + return actual !== null && actual === template(ARROW_BODY, cb, mod, "") ? "arrow" : null; + } + return null; +} + +/** A top-level declaration the virtual chunk can copy verbatim: a pure + * helper whose evaluation runs nothing (a function, or a member read of + * Object such as `Object.create` / `Object.prototype.hasOwnProperty`). */ +function copyableInitializer(init: ts.Expression | undefined): boolean { + if (init === undefined) return false; + const e = unparen(init); + if (ts.isArrowFunction(e) || ts.isFunctionExpression(e)) return true; + let walk: ts.Expression = e; + let depth = 0; + while (ts.isPropertyAccessExpression(walk) && ts.isIdentifier(walk.name)) { + walk = walk.expression; + depth++; + } + return depth > 0 && ts.isIdentifier(walk) && walk.text === "Object"; +} + +/** A top-level declaration whose value is a function. */ +function isFunctionValued(node: ts.VariableDeclaration | ts.FunctionDeclaration): boolean { + if (ts.isFunctionDeclaration(node)) return true; + const init = node.initializer && unparen(node.initializer); + return init !== undefined && (ts.isArrowFunction(init) || ts.isFunctionExpression(init)); +} + +/** True when a named function expression initializer (`var f = function + * self() {}`) uses its own name only as a callee: `self` is the copied + * function, so it is as observable as the top-level binding. */ +function selfCalledOnly( + node: ts.VariableDeclaration | ts.FunctionDeclaration, + scopes: BundleScopes, +): boolean { + if (!ts.isVariableDeclaration(node) || node.initializer === undefined) return true; + const fn = unparen(node.initializer); + if (!ts.isFunctionExpression(fn) || fn.name === undefined || fn.body === undefined) return true; + const self = fn.name.text; + // A parameter of the same name hides the function's own name everywhere + // in it; a `var` of the same name hides it only in the body, since the + // parameter initializers do not see the body's `var`s. + if (fn.parameters.nodes.some((p) => bindsName(p.name, self))) return true; + const bodyVar = varScopedNames(fn.body).has(self); + const body = fn.body; + return references(fn).every( + (r) => + r.text !== self || scopes.boundInside(r, fn) || (bodyVar && within(r, body)) || isCallee(r), + ); +} + +/** True when a binding name (an identifier or a destructuring pattern) + * declares `name`. */ +function bindsName(binding: ts.BindingName, name: string): boolean { + const names = new Set(); + addBindingNames(binding, names); + return names.has(name); +} + +/** True when a reference is the function a call invokes: `f(...)`, or the + * `(0, f)(...)` form that drops the receiver. */ +function isCallee(id: ts.Identifier): boolean { + let callee: ts.Node = id; + const p = id.parent; + if ( + p !== undefined && + ts.isBinaryExpression(p) && + p.operatorToken.kind === ts.SyntaxKind.CommaToken && + p.right === id && + p.parent !== undefined && + ts.isParenthesizedExpression(p.parent) + ) + callee = p.parent; + while (callee.parent !== undefined && ts.isParenthesizedExpression(callee.parent)) + callee = callee.parent; + const call = callee.parent; + return call !== undefined && ts.isCallExpression(call) && call.expression === callee; +} + +/** One recognized chunk declaration. */ +interface Chunk { + name: string; + stmt: ts.VariableStatement; + params: string[]; + body: ts.Block; + path: string; + spec: string; +} + +interface TopLevel { + stmt: ts.Statement; + /** The declarator (or function declaration) itself. */ + node: ts.VariableDeclaration | ts.FunctionDeclaration; +} + +/** True when the file opens with a "use strict" directive prologue. */ +function strictPrologue(stmts: readonly ts.Statement[]): boolean { + for (const s of stmts) { + if (!ts.isExpressionStatement(s) || !ts.isStringLiteral(s.expression)) return false; + if (s.expression.text === "use strict") return true; + } + return false; +} + +/** A cheap text probe: the helper's name, or its minified body's + * `(m={exports:{}}).exports,m` fragment. */ +export function mayBundleChunks(source: string): boolean { + return ( + source.includes("__commonJS") || + /\{\s*exports\s*:\s*\{\s*\}\s*\}\s*\)\s*\.exports\s*,/.test(source) + ); +} + +/** Splits a CommonJS bundle's __commonJS chunks into virtual modules (see + * the header). Null: no chunks (or not a CommonJS bundle) — serve the file + * unchanged. */ +export function splitBundledChunks( + sf: ts.SourceFile, + filePath: string, +): BundledChunkSplit | { degrade: string } | null { + const source = sf.text; + if (!mayBundleChunks(source)) return null; + // ES-module bundles have no require: their chunks keep the existing + // treatment (the Bun factory recognizer, or the ESM interop refusal). + if (!filePath.endsWith(".cjs") && ts.isExternalModule(sf)) return null; + + const top = new Map(); + const duplicate = new Set(); + for (const stmt of sf.statements.nodes) { + const add = (name: string, node: TopLevel["node"]): void => { + if (top.has(name)) duplicate.add(name); + else top.set(name, { stmt, node }); + }; + if (ts.isFunctionDeclaration(stmt) && stmt.name !== undefined) add(stmt.name.text, stmt); + else if (ts.isVariableStatement(stmt)) { + for (const d of stmt.declarationList.declarations.nodes) { + if (ts.isIdentifier(d.name)) add(d.name.text, d); + } + } + } + const helperNames = [...top.keys()].filter((n) => helperBase(n) === "__commonJS"); + + // Every name a recognizer relies on is written nowhere and declared + // once at the top level; `Object` itself is never rebound. + const allRefs = references(sf); + const written = new Set(); + for (const r of allRefs) if (isWritten(r)) written.add(r.text); + const declaredAnywhere = declaredNames(sf); + if (declaredAnywhere.has("Object") || written.has("Object")) + return { degrade: CHUNK_SHAPE_DEGRADE }; + const stable = (name: string): boolean => !duplicate.has(name) && !written.has(name); + // Names whose every reference in the bundle is a callee: `f(...)` or the + // `(0, f)(...)` form. + const scopes = new BundleScopes(); + const valueUsed = new Set(); + for (const r of allRefs) if (!isCallee(r) && scopes.topLevel(r, sf)) valueUsed.add(r.text); + const calledOnly = (name: string): boolean => !valueUsed.has(name); + const ownNames = (name: string): boolean => { + const t = top.get(name); + if (t === undefined || !stable(name) || !ts.isVariableDeclaration(t.node)) return false; + const init = t.node.initializer; + return ( + init !== undefined && + helperTokens(init.getText(sf)) === helperTokens("Object.getOwnPropertyNames") + ); + }; + if (helperNames.length === 0) { + // The helper's shape under another name: an identifier-minified bundle, + // whose other interop helpers lost their names as well. + for (const [name, t] of top) { + const init = ts.isVariableDeclaration(t.node) ? t.node.initializer : undefined; + if (init !== undefined && stable(name) && helperForm(init, sf, ownNames) !== null) + return { + degrade: + "its shipped JS is an identifier-minified bundle whose bundler-interop helpers " + + "(__commonJS and the rest) have lost the names the recognizers verify", + }; + } + return null; + } + const forms = new Map(); + for (const name of helperNames) { + const t = top.get(name)!; + const init = ts.isVariableDeclaration(t.node) ? t.node.initializer : undefined; + const form = init !== undefined && stable(name) ? helperForm(init, sf, ownNames) : null; + if (form === null) return { degrade: CHUNK_SHAPE_DEGRADE }; + forms.set(name, form); + } + + // The chunk declarations: `var NAME = HELPER(factory);`, one declarator. + const chunks = new Map(); + const base = filePath.replace(/^.*[\\/]/, ""); + for (const [name, t] of top) { + if (!ts.isVariableDeclaration(t.node) || t.node.initializer === undefined) continue; + const call = unparen(t.node.initializer); + if (!ts.isCallExpression(call) || !ts.isIdentifier(call.expression)) continue; + const form = forms.get(call.expression.text); + if (form === undefined) continue; + const stmt = t.stmt; + if ( + !ts.isVariableStatement(stmt) || + stmt.declarationList.declarations.nodes.length !== 1 || + call.arguments.nodes.length !== 1 || + !stable(name) + ) + return { degrade: CHUNK_SHAPE_DEGRADE }; + let factory: ts.Node = call.arguments.nodes[0]!; + if (form === "keyed") { + if (!ts.isObjectLiteralExpression(factory) || factory.properties.nodes.length !== 1) + return { degrade: CHUNK_SHAPE_DEGRADE }; + factory = factory.properties.nodes[0]!; + if (!ts.isMethodDeclaration(factory) || ts.isComputedPropertyName(factory.name)) + return { degrade: CHUNK_SHAPE_DEGRADE }; + } else { + factory = unparen(factory as ts.Expression); + if (!ts.isArrowFunction(factory) && !ts.isFunctionExpression(factory)) + return { degrade: CHUNK_SHAPE_DEGRADE }; + } + const fn = factory as ts.MethodDeclaration | ts.ArrowFunction | ts.FunctionExpression; + if ( + fn.body === undefined || + !ts.isBlock(fn.body) || + fn.asteriskToken !== undefined || + (fn.modifiers?.nodes.length ?? 0) > 0 || + fn.parameters.nodes.length > 2 + ) + return { degrade: CHUNK_SHAPE_DEGRADE }; + const params: string[] = []; + for (const p of fn.parameters.nodes) { + if (!ts.isIdentifier(p.name) || p.initializer !== undefined || p.dotDotDotToken) + return { degrade: CHUNK_SHAPE_DEGRADE }; + params.push(p.name.text); + } + const file = `${base}.${name}.cjs`; + chunks.set(name, { + name, + stmt, + params, + body: fn.body, + path: filePath.slice(0, filePath.length - base.length) + file, + spec: `./${file}`, + }); + } + if (chunks.size === 0) return null; + + // Every factory reference is a direct zero-argument call. Calls inside a + // chunk body belong to that chunk's text, the rest to the bundle's. + const callEdits: Edit[] = []; + for (const r of allRefs) { + const chunk = chunks.get(r.text); + if (chunk === undefined) continue; + const call = r.parent; + if ( + call === undefined || + !ts.isCallExpression(call) || + call.expression !== r || + call.arguments.nodes.length !== 0 || + call.questionDotToken !== undefined + ) + return { + degrade: `its bundled CommonJS module factory '${r.text}' is used other than as a direct call`, + }; + callEdits.push({ + start: call.getStart(sf), + end: call.getEnd(), + text: `require(${JSON.stringify(chunk.spec)})`, + }); + } + for (const name of chunks.keys()) { + if (declaredAnywhere.has(name) && countDeclarations(sf, name) > 1) + return { degrade: CHUNK_SHAPE_DEGRADE }; + } + + const bundleStrict = strictPrologue(sf.statements.nodes); + const out: BundledChunkSplit["chunks"] = []; + const bundleEdits: Edit[] = [...callEdits]; + for (const chunk of chunks.values()) { + const result = chunkSource( + sf, + chunk, + chunks, + top, + stable, + calledOnly, + scopes, + callEdits, + bundleStrict, + ); + if (typeof result !== "string") return result; + out.push({ path: chunk.path, source: result }); + bundleEdits.push({ start: chunk.stmt.getStart(sf), end: chunk.stmt.getEnd(), text: "" }); + } + return { text: applyEdits(source, 0, source.length, bundleEdits), chunks: out }; +} + +function countDeclarations(sf: ts.SourceFile, name: string): number { + let n = 0; + ts.walkPreorder(sf, (node) => { + if ( + (ts.isVariableDeclaration(node) || + ts.isParameter(node) || + ts.isBindingElement(node) || + ts.isFunctionDeclaration(node) || + ts.isFunctionExpression(node) || + ts.isClassDeclaration(node) || + ts.isClassExpression(node)) && + node.name !== undefined && + ts.isIdentifier(node.name) && + node.name.text === name + ) + n++; + return undefined; + }); + return n; +} + +/** Applies non-overlapping edits inside [from, to): replaced spans keep + * their newlines (blanked text stays line-aligned); edits nested in a + * blanked span vanish with it. */ +function applyEdits(source: string, from: number, to: number, edits: Edit[]): string { + const inside = edits + .filter((e) => e.start >= from && e.end <= to) + .sort((a, b) => a.start - b.start || b.end - a.end); + let text = ""; + let at = from; + for (const e of inside) { + if (e.start < at) continue; // nested in an earlier edit + text += source.slice(at, e.start); + const replaced = source.slice(e.start, e.end); + // A respelled span keeps its line breaks after the replacement. + text += + e.text === "" ? replaced.replace(/[^\r\n]/g, " ") : e.text + replaced.replace(/[^\n]/g, ""); + at = e.end; + } + return text + source.slice(at, to); +} + +/** The virtual module text for one chunk, or a degrade reason. */ +function chunkSource( + sf: ts.SourceFile, + chunk: Chunk, + chunks: ReadonlyMap, + top: ReadonlyMap, + stable: (name: string) => boolean, + calledOnly: (name: string) => boolean, + scopes: BundleScopes, + callEdits: readonly Edit[], + bundleStrict: boolean, +): string | { degrade: string } { + const why = (reason: string): { degrade: string } => ({ + degrade: `its bundled CommonJS module '${chunk.name}' ${reason}`, + }); + const [exportsParam, moduleParam] = chunk.params; + const body = chunk.body; + const local = declaredNames(body); + for (const p of chunk.params) { + if ( + local.has(p) || + (p !== "exports" && local.has("exports")) || + (p !== "module" && local.has("module")) + ) + return why( + "rebinds its module parameters inside its body (an identifier-minified bundle the recognizer cannot respell)", + ); + } + + /* The factory's own frame must stay unobservable: its receiver, its + * arguments object, and a top-level return have no module equivalent. */ + let frameUse: string | null = null; + /** The innermost frame boundary between a node and the chunk body. */ + const frameOf = (n: ts.Node): "factory" | "arrow" | "function" => { + let arrow = false; + for (let p = n.parent; p !== undefined && p !== body; p = p.parent) { + if ( + ts.isFunctionDeclaration(p) || + ts.isFunctionExpression(p) || + ts.isMethodDeclaration(p) || + ts.isGetAccessorDeclaration(p) || + ts.isSetAccessorDeclaration(p) || + ts.isConstructorDeclaration(p) || + ts.isClassDeclaration(p) || + ts.isClassExpression(p) + ) + return "function"; + if (ts.isArrowFunction(p)) arrow = true; + } + return arrow ? "arrow" : "factory"; + }; + ts.walkPreorder(body, (n) => { + if (frameUse !== null) return "stop"; + if (n.kind >= ts.SyntaxKind.FirstJSDocNode && n.kind <= ts.SyntaxKind.LastJSDocNode) + return "skip"; + let use: string | null = null; + if (n.kind === ts.SyntaxKind.ThisKeyword) use = "reads its factory's receiver (`this`)"; + else if (n.kind === ts.SyntaxKind.SuperKeyword) use = "reads `super` at its top level"; + else if (ts.isIdentifier(n) && n.text === "arguments" && isReference(n)) + use = "reads its factory's arguments object"; + else if (ts.isMetaProperty(n)) use = "reads a meta property at its top level"; + else if (ts.isReturnStatement(n)) { + if (frameOf(n) === "factory") frameUse = "returns from its top level"; + return undefined; + } + if (use !== null && frameOf(n) !== "function") frameUse = use; + return undefined; + }); + if (frameUse !== null) return why(frameUse); + + const edits: Edit[] = callEdits.filter((e) => e.start >= body.pos && e.end <= body.end); + const copied = new Set(); + const copyQueue: string[] = []; + for (const r of references(body)) { + const name = r.text; + if (chunks.has(name)) continue; // a call edit already respells it + if (name === exportsParam || name === moduleParam) { + if (name === moduleParam) { + const p = r.parent; + if (!ts.isPropertyAccessExpression(p) || p.expression !== r || p.name.text !== "exports") + return why("uses its module object beyond module.exports"); + } + const global = name === exportsParam ? "exports" : "module"; + if (name !== global) { + const p = r.parent; + edits.push( + ts.isShorthandPropertyAssignment(p) + ? { start: r.getStart(sf), end: r.getEnd(), text: `${name}: ${global}` } + : { start: r.getStart(sf), end: r.getEnd(), text: global }, + ); + } + continue; + } + // The factory function itself binds the parameters and `var`s. + if (scopes.boundWithin(r, body.parent ?? body)) continue; + if (name === "exports" || name === "module") + return why(`reads the bundle's own '${name}' binding`); + if (name === "__filename") return why("reads __filename, which names the bundle file"); + if (top.has(name)) { + if (!copied.has(name)) { + copied.add(name); + copyQueue.push(name); + } + } + } + + // The pure helpers BODY reads, closed over their own top-level reads. + const header: string[] = []; + for (let i = 0; i < copyQueue.length; i++) { + const name = copyQueue[i]!; + const t = top.get(name)!; + const node = t.node; + const pure = + stable(name) && + (ts.isFunctionDeclaration(node) || + (ts.isVariableDeclaration(node) && copyableInitializer(node.initializer))); + if (!pure || chunks.has(name)) + return why(`reads the bundle's top-level binding '${name}', which it cannot carry along`); + // Each chunk gets its own copy, so a function's identity and its + // properties must stay unobservable: the bundle only ever calls it. + if (isFunctionValued(node) && (!calledOnly(name) || !selfCalledOnly(node, scopes))) + return why( + `uses the bundle's top-level function '${name}' as a value, which its chunks cannot share`, + ); + for (const r of references(node)) { + if (scopes.boundWithin(r, node) || !top.has(r.text) || copied.has(r.text)) continue; + copied.add(r.text); + copyQueue.push(r.text); + } + } + // Declaration order of the bundle: a helper reads only earlier ones. + const ordered = [...copied].sort( + (a, b) => top.get(a)!.node.getStart(sf) - top.get(b)!.node.getStart(sf), + ); + for (const name of ordered) { + const node = top.get(name)!.node; + header.push(ts.isFunctionDeclaration(node) ? node.getText(sf) : `var ${node.getText(sf)};`); + } + + const bodyStrict = strictPrologue(body.statements.nodes); + const text = applyEdits(sf.text, body.getStart(sf) + 1, body.getEnd() - 1, edits); + const prologue = bundleStrict || bodyStrict ? '"use strict";\n' : ""; + return prologue + (header.length > 0 ? header.join("\n") + "\n" : "") + text + "\n"; +} diff --git a/packages/compiler/src/frontend/npm-static-rewrite-host.ts b/packages/compiler/src/frontend/npm-static-rewrite-host.ts index ee36f58d1..524239901 100644 --- a/packages/compiler/src/frontend/npm-static-rewrite-host.ts +++ b/packages/compiler/src/frontend/npm-static-rewrite-host.ts @@ -2,7 +2,12 @@ import { dirname, join, resolve as resolvePath } from "node:path"; import { cjsLexedExportsOfFile, cjsVisibleNames } from "./cjs-syntax.js"; import type { Ts7SourceParser } from "./ts7/source-parser.js"; -import { trackedDirectoryExists, trackedFileExists, trackedReadFile } from "./input-tracker.js"; +import { + isVirtualSource, + trackedDirectoryExists, + trackedFileExists, + trackedReadFile, +} from "./input-tracker.js"; import { resolveExports } from "./resolve.js"; import { packageNameOfSpecifier } from "./workspace-registry.js"; import { isBundlerCjsCandidate, rewriteBundlerCjsSyntax } from "./npm-static-rewrite-syntax.js"; @@ -134,7 +139,7 @@ function requireTargetEsModuleStamped( } catch { /* unlexable — keep probing */ } - if (src.includes("__toCommonJS(")) return true; + if (/__toCommonJS\d*\(/.test(src)) return true; const fwd = /module\.exports\s*=\s*require\(\s*["']([^"']+)["']\s*\)/.exec(src); if (fwd !== null) return requireTargetEsModuleStamped(parser, file, fwd[1]!, depth + 1); return false; @@ -163,9 +168,12 @@ export function rewriteBundlerCjsWithParser( parser: Ts7SourceParser, source: string, filePath: string, + liveExportTable?: (filePath: string) => void, ): string | { degrade: string } | null { if (!isBundlerCjsCandidate(source)) return null; return rewriteBundlerCjsSyntax(parser.parse(filePath, source, "js"), filePath, { + liveExportTable, + requireOnly: isVirtualSource, requireTargetEsModuleStamped: (from, spec) => requireTargetEsModuleStamped(parser, from, spec), starTargetNames: (from, spec) => { const target = resolveRelativeCjs(from, spec); diff --git a/packages/compiler/src/frontend/npm-static-rewrite-syntax.ts b/packages/compiler/src/frontend/npm-static-rewrite-syntax.ts index 7938471f3..1730e1153 100644 --- a/packages/compiler/src/frontend/npm-static-rewrite-syntax.ts +++ b/packages/compiler/src/frontend/npm-static-rewrite-syntax.ts @@ -12,6 +12,70 @@ import { rewriteBundledFunctionImports } from "./npm-static-bundled-cjs.js"; export interface CjsRewriteHost { requireTargetEsModuleStamped(fromFile: string, specifier: string): boolean; starTargetNames(fromFile: string, specifier: string): Set; + /** Told when the rewritten file's tail export table stands for a live + * getter table the original installed before it could run another + * module's code (liveExportTableFirst): a module of a require cycle that + * captured the export object early observes exactly that table. */ + liveExportTable?: ((filePath: string) => void) | undefined; + /** True for a module only ever loaded through require() (a bundle's + * CommonJS chunk split into its own module): no ES-module importer + * exists, so Node's lexer-visible name set bounds nothing and every + * name the export plumbing defines is part of its surface. */ + requireOnly?: ((filePath: string) => boolean) | undefined; +} + +/** True when esbuild's export object (`module.exports = __toCommonJS(T)` + * over a getter table `__export(T, {...})`) is installed before anything + * that can run another module's code, and nothing else writes the export + * object. Every statement before the installation is then a declaration, + * a directive, or the getter-table call (whose getters run only when + * read), and variable initializers evaluate no calls outside function + * bodies. The getters read live bindings, so the object a cycle partner + * captures early answers every later read exactly like the final table. */ +function liveExportTableFirst( + sf: ts.SourceFile, + installAt: number, + target: string, + exportTables: readonly { target: string }[], +): boolean { + if (!exportTables.some((t) => t.target === target)) return false; + let callsOutsideFunctions = false; + const noCalls = (root: ts.Node): boolean => { + callsOutsideFunctions = false; + ts.walkPreorder(root, (n) => { + if (callsOutsideFunctions) return "stop"; + if (ts.isArrowFunction(n) || ts.isFunctionExpression(n) || ts.isFunctionDeclaration(n)) + return "skip"; + if (ts.isCallExpression(n) || ts.isNewExpression(n) || ts.isTaggedTemplateExpression(n)) + callsOutsideFunctions = true; + return undefined; + }); + return !callsOutsideFunctions; + }; + let sawTable = false; + for (const stmt of sf.statements.nodes) { + if (stmt.getStart(sf) >= installAt) return sawTable; + if (ts.isFunctionDeclaration(stmt) || ts.isEmptyStatement(stmt)) continue; + if (ts.isExpressionStatement(stmt) && ts.isStringLiteral(stmt.expression)) continue; + if (ts.isVariableStatement(stmt)) { + if ( + stmt.declarationList.declarations.nodes.every( + (d) => ts.isIdentifier(d.name) && (d.initializer === undefined || noCalls(d.initializer)), + ) + ) + continue; + return false; + } + if (ts.isExpressionStatement(stmt) && ts.isCallExpression(stmt.expression)) { + const table = exportCallOf(stmt.expression); + if (table !== null && table.target === target) { + sawTable = true; + continue; + } + } + return false; + } + return false; } export function isBundlerCjsCandidate(source: string): boolean { @@ -24,16 +88,31 @@ export function isBundlerCjsCandidate(source: string): boolean { ); } +/** The helper a bundler-emitted name spells. esbuild suffixes a helper + * that a bundled module declares again with a counter (a bundled esbuild + * dist inside another bundle carries `__export2`, `__toCommonJS2`, …); the + * recognizers below verify each call's shape, so the counter carries no + * meaning beyond the name collision it avoided. */ +export function bundlerHelperBase(name: string): string { + return /^__[A-Za-z]+\d+$/.test(name) ? name.replace(/\d+$/, "") : name; +} + /** The last NAME of a callee: bare identifier or any member chain's final - * name (`tslib_1.__exportStar` → "__exportStar"). */ + * name (`tslib_1.__exportStar` → "__exportStar"), helper counters dropped. */ function calleeNameOf(call: ts.CallExpression): string | null { const callee = call.expression; - if (ts.isIdentifier(callee)) return callee.text; + if (ts.isIdentifier(callee)) return bundlerHelperBase(callee.text); if (ts.isPropertyAccessExpression(callee) && ts.isIdentifier(callee.name)) - return callee.name.text; + return bundlerHelperBase(callee.name.text); return null; } +/** True for an identifier spelling the named helper (counter-suffixed + * spellings included). */ +function isHelperIdent(node: ts.Node, base: string): node is ts.Identifier { + return ts.isIdentifier(node) && bundlerHelperBase(node.text) === base; +} + /** An entry the canonical table can carry. */ interface EntrySpec { /** The export name (may need string-key spelling). */ @@ -194,13 +273,8 @@ interface ToEsmPlan { * __copyProps(…, mod) call copying onto a conditional that tests * isNodeMode/__esModule and defines "default" with value mod. Comments and * formatting are free; the SHAPE is the contract. */ -function recognizedToEsmDecl(stmt: ts.Statement): boolean { - if (!ts.isVariableStatement(stmt)) return false; - const decls = stmt.declarationList.declarations.nodes; - if (decls.length !== 1) return false; - const d = decls[0]!; - if (!ts.isIdentifier(d.name) || d.name.text !== "__toESM" || d.initializer === undefined) - return false; +function recognizedToEsmDecl(d: ts.VariableDeclaration): boolean { + if (!isHelperIdent(d.name, "__toESM") || d.initializer === undefined) return false; let init: ts.Expression = d.initializer; while (ts.isParenthesizedExpression(init)) init = init.expression; if (!ts.isArrowFunction(init)) return false; @@ -218,12 +292,7 @@ function recognizedToEsmDecl(stmt: ts.Statement): boolean { expr = expr.right; } while (ts.isParenthesizedExpression(expr)) expr = expr.expression; - if ( - !ts.isCallExpression(expr) || - !ts.isIdentifier(expr.expression) || - expr.expression.text !== "__copyProps" - ) - return false; + if (!ts.isCallExpression(expr) || !isHelperIdent(expr.expression, "__copyProps")) return false; if (expr.arguments.nodes.length < 2) return false; const from = expr.arguments.nodes[1]!; if (!ts.isIdentifier(from) || from.text !== mod) return false; @@ -234,12 +303,7 @@ function recognizedToEsmDecl(stmt: ts.Statement): boolean { if (!condText.includes(isNodeMode) || !condText.includes("__esModule")) return false; let stamp: ts.Expression = to.whenTrue; while (ts.isParenthesizedExpression(stamp)) stamp = stamp.expression; - if ( - !ts.isCallExpression(stamp) || - !ts.isIdentifier(stamp.expression) || - stamp.expression.text !== "__defProp" - ) - return false; + if (!ts.isCallExpression(stamp) || !isHelperIdent(stamp.expression, "__defProp")) return false; if (stamp.arguments.nodes.length !== 3) return false; const nameArg = stamp.arguments.nodes[1]!; if (!ts.isStringLiteral(nameArg) || nameArg.text !== "default") return false; @@ -278,19 +342,23 @@ function planToEsmInterop(sf: ts.SourceFile, filePath: string, host: CjsRewriteH degrade: reason, }); - const declStmts = sf.statements.nodes.filter( - (s) => - ts.isVariableStatement(s) && - s.declarationList.declarations.nodes.some( - (d) => ts.isIdentifier(d.name) && d.name.text === "__toESM", - ), - ); + // Top-level declarators of the helper, any statement shape (minified + // dists share one `var` among several helpers), by spelling. + const decls = new Map(); + for (const s of sf.statements.nodes) { + if (!ts.isVariableStatement(s)) continue; + for (const d of s.declarationList.declarations.nodes) { + if (!isHelperIdent(d.name, "__toESM")) continue; + const list = decls.get(d.name.text); + if (list === undefined) decls.set(d.name.text, [d]); + else list.push(d); + } + } const refs: ts.Identifier[] = []; const calls: ts.CallExpression[] = []; const collect = (n: ts.Node): void => { - if (ts.isIdentifier(n) && n.text === "__toESM") refs.push(n); - if (ts.isCallExpression(n) && ts.isIdentifier(n.expression) && n.expression.text === "__toESM") - calls.push(n); + if (isHelperIdent(n, "__toESM")) refs.push(n); + if (ts.isCallExpression(n) && isHelperIdent(n.expression, "__toESM")) calls.push(n); }; ts.walkPreorder(sf, collect); if (calls.length === 0 && refs.length === 0) return plan; @@ -298,15 +366,16 @@ function planToEsmInterop(sf: ts.SourceFile, filePath: string, host: CjsRewriteH // a helper that escapes as a VALUE is outside the recognized shape. const callees = new Set(calls.map((c) => c.expression)); const declNames = new Set(); - for (const s of declStmts) { - for (const d of (s as ts.VariableStatement).declarationList.declarations.nodes) { - if (ts.isIdentifier(d.name) && d.name.text === "__toESM") declNames.add(d.name); - } - } + for (const list of decls.values()) for (const d of list) declNames.add(d.name); if (refs.some((r) => !callees.has(r) && !declNames.has(r))) return fail(TO_ESM_ESCAPE_DEGRADE); if (calls.length === 0) return plan; // declared but never called — dead helper - if (declStmts.length !== 1 || !recognizedToEsmDecl(declStmts[0]!)) - return fail(TO_ESM_SHAPE_DEGRADE); + // Every spelling a call uses must be declared exactly once, in the + // recognized shape. + for (const call of calls) { + const list = decls.get((call.expression as ts.Identifier).text); + if (list === undefined || list.length !== 1 || !recognizedToEsmDecl(list[0]!)) + return fail(TO_ESM_SHAPE_DEGRADE); + } /** Module-scope interop bindings: name → whether `.default` IS the * module (pad the access) rather than a member read of its `default`. */ @@ -467,16 +536,20 @@ export function rewriteBundlerCjsSyntax( // ESM bundles can contain closed CommonJS function factories. Recognize // those before refusing interop that needs a dynamic module namespace. - if (ts.isExternalModule(sf)) { + // TypeScript forces every `.cjs` file to be an external module + // (isFileForcedToBeModuleByFormat), yet Node always loads one as + // CommonJS: the extension, not that flag, decides the format there. + if (!filePath.endsWith(".cjs") && ts.isExternalModule(sf)) { const bundled = rewriteBundledFunctionImports(source, sf); if (bundled !== null) return bundled; - return source.includes("__toESM(") - ? { - degrade: - "its ES-module dist routes an external dependency through the __toESM " + - "bundler-interop helper, which cannot compile natively in ESM output", - } - : null; + if (!source.includes("__toESM(")) return null; + return { + degrade: source.includes("__commonJS") + ? "its ES-module bundle reaches bundled CommonJS modules through the __commonJS and " + + "__toESM bundler-interop helpers, which cannot compile natively in ESM output" + : "its ES-module dist routes an external dependency through the __toESM " + + "bundler-interop helper, which cannot compile natively in ESM output", + }; } // The __toESM interop pass (see the section header): wrapper call sites @@ -644,6 +717,11 @@ export function rewriteBundlerCjsSyntax( } const lexed = cjsLexedExportsOfFile(sf); + if (host.requireOnly?.(filePath) === true) { + for (const t of exportTables) for (const [name] of t.entries) lexed.exports.add(name); + for (const d of definePropEntries) lexed.exports.add(d.name); + for (const m of memberStmts) for (const name of m.names) lexed.exports.add(name); + } let emitTable = sawBundleShape && (lexed.exports.size > 0 || lexed.reexports.length > 0); const starSpecs: string[] = []; @@ -814,21 +892,35 @@ export function rewriteBundlerCjsSyntax( "__reExport", "__toESM", "__toCommonJS", + "__commonJS", "__exportStar", "__createBinding", "__setModuleDefault", "__importStar", "__importDefault", ]); + /* Helper declarators by name. A minified dist shares one `var` among + * several helpers (`var __getProtoOf=…,__hasOwnProp=…;`): each + * declarator is its own candidate, and the statement pads whole only + * once every declarator in it is dead. */ const helperDecls = new Map(); + const helperStmts: ts.VariableStatement[] = []; for (const stmt of sf.statements.nodes) { if (!ts.isVariableStatement(stmt)) continue; const decls = stmt.declarationList.declarations.nodes; - if (decls.length !== 1) continue; - const d = decls[0]!; - if (ts.isIdentifier(d.name) && HELPER_NAMES.has(d.name.text)) { - helperDecls.set(d.name.text, { start: stmt.getStart(sf), end: stmt.getEnd() }); + let anyHelper = false; + for (const d of decls) { + if (!ts.isIdentifier(d.name) || !HELPER_NAMES.has(bundlerHelperBase(d.name.text))) continue; + if (helperDecls.has(d.name.text)) continue; // redeclared: keep the first, never sweep twice + anyHelper = true; + helperDecls.set( + d.name.text, + decls.length === 1 + ? { start: stmt.getStart(sf), end: stmt.getEnd() } + : { start: d.getStart(sf), end: d.getEnd() }, + ); } + if (anyHelper && decls.length > 1) helperStmts.push(stmt); } // every identifier occurrence of a helper name outside its own // declarator name node, position-recorded for the span test @@ -862,8 +954,39 @@ export function rewriteBundlerCjsSyntax( } } } + // A swept declarator of a shared statement pads with its separating + // comma, and the statement pads whole once every declarator is dead: + // padding the bare declarator span would leave a dangling comma. + const declaratorSpans = new Set<{ start: number; end: number }>(); + const declaratorPads: { start: number; end: number }[] = []; + for (const stmt of helperStmts) { + const decls = stmt.declarationList.declarations.nodes; + const deadAt = decls.map((d) => { + if (!ts.isIdentifier(d.name) || !removed.has(d.name.text)) return false; + const span = helperDecls.get(d.name.text)!; + if (span.start !== d.getStart(sf)) return false; + declaratorSpans.add(span); + return true; + }); + if (deadAt.every((x) => x)) { + declaratorPads.push({ start: stmt.getStart(sf), end: stmt.getEnd() }); + continue; + } + // Dead declarators before the last live one take their trailing + // comma; the dead tail after it pads from that declarator's end. + const lastLive = deadAt.lastIndexOf(false); + for (let i = 0; i < decls.length; i++) { + if (!deadAt[i]) continue; + const d = decls[i]!; + declaratorPads.push( + i < lastLive + ? { start: d.getStart(sf), end: decls[i + 1]!.getStart(sf) } + : { start: decls[lastLive]!.getEnd(), end: d.getEnd() }, + ); + } + } neutralize.length = 0; - neutralize.push(...dead); + neutralize.push(...dead.filter((span) => !declaratorSpans.has(span)), ...declaratorPads); } /* ── emission ─────────────────────────────────────────────────────── */ @@ -875,6 +998,15 @@ export function rewriteBundlerCjsSyntax( if (!emitTable) return text; // interop pads only — nothing appends + if ( + esbuildMainTarget !== null && + tablePos !== null && + memberStmts.length === 0 && + definePropEntries.length === 0 && + liveExportTableFirst(sf, tablePos, esbuildMainTarget, exportTables) + ) + host.liveExportTable?.(filePath); + const lines: string[] = [""]; const hasAnyFallback = [...entries.values()].some((s) => s.kind === "any"); if (hasAnyFallback) { diff --git a/packages/compiler/src/frontend/npm-static.ts b/packages/compiler/src/frontend/npm-static.ts index 3c8fa22e9..7dffd05f7 100644 --- a/packages/compiler/src/frontend/npm-static.ts +++ b/packages/compiler/src/frontend/npm-static.ts @@ -13,7 +13,13 @@ import { registerWorkspacePackage, workspacePackageOfPath, } from "./workspace-registry.js"; -import { trackedExists, trackedReadFile, trackedRealpath } from "./input-tracker.js"; +import { + clearVirtualSources, + setVirtualSource, + trackedExists, + trackedReadFile, + trackedRealpath, +} from "./input-tracker.js"; let activePackages: ReadonlySet = new Set(); let declarationOverloads: ReadonlyMap = new Map(); @@ -28,12 +34,24 @@ const offenders = new Map(); * the host probes the same file many times, and the rewrite parses. */ const rewriteCache = new Map(); +/** Rewritten files whose tail export table stands for a live getter table + * installed before the file could run another module's code (the rewrite + * certifies it; require-cycle admission consults it). */ +const liveExportFiles = new Set(); + +export function npmStaticLiveExportTable(path: string): boolean { + return liveExportFiles.has(path.split("\\").join("/")); +} + export function setNpmStaticPackages>(packages: T): void { activePackages = new Set(packages); declarationOverloads = new Map(); declarationProperties = new Map(); offenders.clear(); + fileDegrades.clear(); rewriteCache.clear(); + liveExportFiles.clear(); + clearVirtualSources(); untypedPkgCache.clear(); realpathProbed.clear(); } @@ -81,6 +99,21 @@ export function npmStaticOffenders(): ReadonlyMap { return offenders; } +/** Files whose bundler interop the rewrite could not finish this attempt, + * with their package and reason. A file refuses its package only when + * the compiled program can load it (npmStaticLoadableFiles): a package is + * judged by what its imported subpaths reach, not by every file it ships. */ +const fileDegrades = new Map(); + +export function npmStaticFileDegrades(): ReadonlyMap { + return fileDegrades; +} + +function reportFileDegrade(path: string, pkg: string, reason: string): void { + const key = path.split("\\").join("/"); + if (!fileDegrades.has(key)) fileDegrades.set(key, { pkg, reason }); +} + /** The DefinitelyTyped name mangling ("@scope/pkg" → "scope__pkg") — the * @types twin that must hide alongside the package's own declarations. */ function mangledTypesName(name: string): string { @@ -362,7 +395,18 @@ export function npmStaticFsShadow(services: FrontendServices): NpmStaticFsShadow if (hit !== undefined) return hit ?? undefined; let rewritten: string | null = null; try { - const original = trackedReadFile(path); + let original = trackedReadFile(path); + // A bundle's CommonJS chunks move to their own modules first, so + // every later pass (and this shadow, for each chunk) sees plain + // CommonJS module text. + const split = original === null ? null : services.splitCjsChunks(original, path); + if (split !== null && "degrade" in split) { + reportFileDegrade(path, target.pkg, split.degrade); + original = null; + } else if (split !== null) { + for (const chunk of split.chunks) setVirtualSource(chunk.path, chunk.source); + original = split.text; + } if (original !== null) { const namepaths = services.jsDocNamepaths(path, original); const source = namepaths ?? original; @@ -385,9 +429,10 @@ export function npmStaticFsShadow(services: FrontendServices): NpmStaticFsShadow classFields?.text ?? source, path, + (live) => liveExportFiles.add(live.split("\\").join("/")), ); if (answer !== null && typeof answer === "object") { - reportNpmStaticOffender(target.pkg, answer.degrade); + reportFileDegrade(path, target.pkg, answer.degrade); } else { rewritten = answer ?? @@ -395,7 +440,8 @@ export function npmStaticFsShadow(services: FrontendServices): NpmStaticFsShadow propertyProjected?.text ?? findWidened?.text ?? classFields?.text ?? - namepaths; + namepaths ?? + (split !== null ? original : null); } } } catch { @@ -434,6 +480,14 @@ function looksUnminified(source: string): boolean { return source.length / lines.length <= 200; } +/** A whitespace/syntax-minified bundler dist whose interop helpers keep + * their names (`var __toESM=…,__toCommonJS=mod=>…`): the recognizers + * verify those shapes and refuse the package precisely when they cannot, + * so the minification heuristic need not refuse it up front. */ +function namedBundlerHelpers(source: string): boolean { + return /\b__(?:toCommonJS|commonJS|toESM)\d*\s*=\s*(?:\(|[A-Za-z_$][\w$]*\s*=>)/.test(source); +} + function hasTransformMarkers(source: string): boolean { return TRANSFORM_MARKERS.some((m) => source.includes(m)); } @@ -456,7 +510,8 @@ export function npmStaticIneligibleReason( if (jsEntry === null) return "no runtime JS entry resolves"; const source = trackedReadFile(jsEntry); if (source === null) return `its runtime entry ${jsEntry} cannot be read`; - if (!looksUnminified(source)) return "its shipped JS looks minified"; + if (!looksUnminified(source) && !namedBundlerHelpers(source)) + return "its shipped JS looks minified"; if (hasTransformMarkers(source)) { return "its shipped JS carries build-transform markers (bundled/transpiled dist)"; } diff --git a/packages/compiler/src/frontend/pipeline.ts b/packages/compiler/src/frontend/pipeline.ts index 024c69d98..676b2bb3e 100644 --- a/packages/compiler/src/frontend/pipeline.ts +++ b/packages/compiler/src/frontend/pipeline.ts @@ -10,11 +10,13 @@ import { checkPreflight, isNodeTypesPath, locOf, + npmStaticLoadableFiles, requiresOf, resolveNpmImport, type LoadResult, } from "./program.js"; import { + npmStaticFileDegrades, npmStaticIneligibleReason, npmStaticOffenders, npmStaticPackageOfPath, @@ -458,6 +460,15 @@ function loadFrontend( const typecheckRefused = new Set(); while (effective.size > 0) { const reasons = new Map(npmStaticOffenders()); + // Bundler interop the rewrite could not finish refuses its package + // only where the compiled program can load the file. + if (npmStaticFileDegrades().size > 0) { + const loadable = npmStaticLoadableFiles(load.program, load.moduleOrder); + for (const [file, { pkg, reason }] of npmStaticFileDegrades()) { + if (!reasons.has(pkg) && (loadable === null || loadable.has(file))) + reasons.set(pkg, reason); + } + } for (const d of preflight) { const pkg = npmStaticPackageOfPath(d.loc.file); if (pkg !== null && !reasons.has(pkg)) diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index 906d901fe..192a36ef9 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -68,6 +68,7 @@ import { isNpmStaticPackage, npmStaticActive, npmStaticFsShadow, + npmStaticLiveExportTable, npmStaticPackageOfPath, reportNpmStaticOffender, setNpmStaticDeclarationOverloads, @@ -1438,6 +1439,8 @@ export function requireBindingEarlyUse7( k: number, decl: ts.VariableDeclaration, precedingDecls: readonly ts.VariableDeclaration[], + /** A reference of the binding whose early evaluation is known exact. */ + exactEarlyRead?: (reference: ts.Identifier) => boolean, ): ts.Identifier | null { const checker = program.getTypeChecker(); const bindings = new Set(); @@ -1669,6 +1672,7 @@ export function requireBindingEarlyUse7( const sym = symbolOf(n); if (sym === undefined) return undefined; if (bindings.has(sym)) { + if (exactEarlyRead?.(n) === true) return undefined; hit = n; return "stop"; } @@ -3119,6 +3123,16 @@ function cjsCycleRefusal7( // anything else can change what a module of the cycle observes. let stray: ts.Node | null = null; const settled = new Set(stmts.slice(0, firstEntry).filter(exportStatement)); + // A bundler export table the rewrite certified (npmStaticLiveExportTable) + // stands for the live getter object the original installed before its + // first require: the tail table settles as if it ran there. + const tail = stmts[stmts.length - 1]; + if ( + tail !== undefined && + npmStaticLiveExportTable(m.fileName) && + cjsExportAssignmentOf(tail)?.kind === "table" + ) + settled.add(tail); ts.walkPreorder(m, (n) => { if (stray !== null) return "stop"; if (ts.isStatement(n) && settled.has(n)) return "skip"; @@ -3171,7 +3185,9 @@ function cjsCycleRefusal7( if (req.decl === null) continue; const dep = resolveImport7(program, m, req.spec, "require"); if (dep === null || !members.has(dep)) continue; - const reached = requireBindingEarlyUse7(program, m, stmts.length, req.decl, []); + const reached = requireBindingEarlyUse7(program, m, stmts.length, req.decl, [], (id) => + functionExportRead7(id, dep), + ); if (reached !== null) { return `the top-level code of ${m.fileName} can use its binding '${reached.text}' of a module of the cycle (${lineOf(reached)}) while the cycle initializes`; } @@ -3181,6 +3197,161 @@ function cjsCycleRefusal7( return null; } +/** True when `use` initializes a top-level const whose every other + * reference is a value of an export statement (`module.exports = { … }` + * or `exports.n = …`). */ +function publishedAlias7(use: ts.Node, decl: ts.Node | undefined): boolean { + if ( + decl === undefined || + !ts.isVariableDeclaration(decl) || + decl.initializer !== use || + !ts.isIdentifier(decl.name) + ) + return false; + const list = decl.parent; + const stmt = list?.parent; + const sf = stmt?.parent; + if ( + list === undefined || + (list.flags & ts.NodeFlags.Const) === 0 || + stmt === undefined || + !ts.isVariableStatement(stmt) || + sf === undefined || + !ts.isSourceFile(sf) + ) + return false; + const alias = decl.name; + const published = new Set(); + for (const st of sf.statements.nodes) { + const cjs = cjsExportAssignmentOf(st); + if (cjs === null) continue; + if (cjs.kind === "member") published.add(cjs.value); + else if (cjs.obj !== null) { + for (const p of cjs.obj.properties.nodes) { + if (ts.isPropertyAssignment(p) && !ts.isComputedPropertyName(p.name)) + published.add(p.initializer); + else if (ts.isShorthandPropertyAssignment(p)) published.add(p.name); + } + } + } + let kept = false; + ts.walkPreorder(sf, (n) => { + if (kept) return "stop"; + if (!ts.isIdentifier(n) || n === alias || n.text !== alias.text) return undefined; + const p = n.parent; + if ( + p !== undefined && + ((ts.isPropertyAccessExpression(p) && p.name === n) || + (ts.isPropertyAssignment(p) && p.name === n)) + ) + return undefined; + if (!published.has(n)) kept = true; + return undefined; + }); + return !kept; +} + +/** True for a plain read `binding.name` (not a call, not a write, not a + * value that is stored or passed on) of the cycle member `dep` whose + * export `name` is a top-level function declaration nothing reassigns. + * Every member settles its exports before entering the cycle, so Node + * reads that same function whenever the read runs, and the compiled read + * resolves to the declaration itself. */ +function functionExportRead7(id: ts.Identifier, dep: ts.SourceFile): boolean { + const access = id.parent; + if (!ts.isPropertyAccessExpression(access) || access.expression !== id) return false; + // The value the read yields: through parentheses and the right operand + // of a comma, so `(0, binding.name)(...)` is the call it spells. + let use: ts.Node = access; + for (;;) { + const p = use.parent; + if (ts.isParenthesizedExpression(p)) use = p; + else if ( + ts.isBinaryExpression(p) && + p.operatorToken.kind === ts.SyntaxKind.CommaToken && + p.right === use + ) + use = p; + else break; + } + const parent = use.parent; + // Only a use that neither runs the function nor keeps it is a read: a + // stored alias (`const f = binding.name`, `{ f: binding.name }`) or an + // argument can be called while the cycle initializes. A top-level const + // that only publishes it (`module.exports = { name: f }`, the static + // rewrite's re-export spelling) runs nothing: a module that reads the + // export back checks that read itself. + const observes = + publishedAlias7(use, parent) || + ts.isExpressionStatement(parent) || + ts.isTypeOfExpression(parent) || + ts.isVoidExpression(parent) || + (ts.isPrefixUnaryExpression(parent) && parent.operator === ts.SyntaxKind.ExclamationToken) || + (ts.isBinaryExpression(parent) && + (parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken || + parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken || + parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken || + parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken)) || + ((ts.isIfStatement(parent) || ts.isWhileStatement(parent) || ts.isDoStatement(parent)) && + parent.expression === use) || + (ts.isConditionalExpression(parent) && parent.condition === use); + if (!observes) return false; + const name = access.name.text; + // The exported value's identifier: a table entry or a member export. + const values: ts.Expression[] = []; + for (const stmt of dep.statements.nodes) { + if (!ts.isExpressionStatement(stmt) || !ts.isBinaryExpression(stmt.expression)) continue; + const e = stmt.expression; + if (e.operatorToken.kind !== ts.SyntaxKind.EqualsToken) continue; + if (isModuleExportsAccess(e.left)) { + if (!ts.isObjectLiteralExpression(e.right)) return false; + for (const p of e.right.properties.nodes) { + if (ts.isSpreadAssignment(p)) return false; + if (ts.isShorthandPropertyAssignment(p) && p.name.text === name) + values.push(p.name as ts.Identifier); + else if ( + ts.isPropertyAssignment(p) && + (ts.isIdentifier(p.name) || ts.isStringLiteral(p.name)) && + p.name.text === name + ) + values.push(p.initializer); + } + } else if ( + ts.isPropertyAccessExpression(e.left) && + e.left.name.text === name && + ((ts.isIdentifier(e.left.expression) && e.left.expression.text === "exports") || + isModuleExportsAccess(e.left.expression)) + ) { + values.push(e.right); + } + } + const value = values.length === 1 ? values[0]! : null; + if (value === null || !ts.isIdentifier(value)) return false; + const fnName = value.text; + if ( + !dep.statements.nodes.some( + (st) => ts.isFunctionDeclaration(st) && st.name?.text === fnName && st.body !== undefined, + ) + ) + return false; + let rebound = false; + ts.walkPreorder(dep, (n) => { + if (rebound) return "stop"; + if ( + (ts.isBinaryExpression(n) && + ts.isIdentifier(n.left) && + n.left.text === fnName && + n.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && + n.operatorToken.kind <= ts.SyntaxKind.LastAssignment) || + (ts.isVariableDeclaration(n) && ts.isIdentifier(n.name) && n.name.text === fnName) || + (ts.isFunctionDeclaration(n) && n.name?.text === fnName && !ts.isSourceFile(n.parent)) + ) + rebound = true; + return undefined; + }); + return !rebound; +} + /* ── exact cyclic initialization ───────────────────────────────────────── * Cycles that fail the declaration-only rule still evaluate exactly like * Node when their shape is representable: the guarded %init calls already @@ -5930,6 +6101,58 @@ export function orderedImportsOf( return out; } +/** The files a compiled program can load: the module order closed over + * every literal require() and import() call it contains (deferred and + * nested ones included) and, for opted-in package JavaScript, over every + * import and export declaration as well. A package file outside this set + * is reachable only through types, so whatever it spells cannot affect + * the compiled program. Null when a reachable file loads a computed + * specifier: then any file may load. */ +export function npmStaticLoadableFiles( + program: ts.Program, + moduleOrder: readonly ts.SourceFile[], +): Set | null { + const seen = new Set(); + const work: ts.SourceFile[] = []; + const add = (sf: ts.SourceFile | null | undefined): void => { + if (sf === null || sf === undefined || seen.has(sf) || sf.isDeclarationFile) return; + seen.add(sf); + work.push(sf); + }; + for (const sf of moduleOrder) add(sf); + let computed = false; + while (work.length > 0 && !computed) { + const sf = work.pop()!; + const packageJs = + npmStaticPackageOfPath(sf.fileName) !== null && isJsSourceFileName(sf.fileName); + const follow = (spec: string, kind: "import" | "require"): void => { + if (canonicalBuiltinModule(spec) !== null) return; + add(resolveImport7(program, sf, spec, kind) ?? npmStaticDepSf7(program, sf, spec, kind)); + }; + ts.walkPreorder(sf, (n) => { + if (computed) return "stop"; + if (ts.isCallExpression(n)) { + const isImport = n.expression.kind === ts.SyntaxKind.ImportKeyword; + const isRequire = ts.isIdentifier(n.expression) && n.expression.text === "require"; + if (!isImport && !isRequire) return undefined; + const arg = n.arguments.nodes[0]; + if (arg !== undefined && ts.isStringLiteralLike(arg)) + follow(arg.text, isImport ? "import" : "require"); + else if (packageJs || isImport) computed = true; + } else if ( + packageJs && + (ts.isImportDeclaration(n) || ts.isExportDeclaration(n)) && + n.moduleSpecifier !== undefined && + ts.isStringLiteral(n.moduleSpecifier) + ) { + follow(n.moduleSpecifier.text, "import"); + } + return undefined; + }); + } + return computed ? null : new Set([...seen].map((sf) => sf.fileName.split("\\").join("/"))); +} + /** The program source file a bare specifier reaches when it names an * opted-in --npm-static package (the shipped-JS entry preflight admitted * as a module edge), else null. No offender reporting here — preflight diff --git a/packages/compiler/src/frontend/services.ts b/packages/compiler/src/frontend/services.ts index ca4dd2b36..c6bb24ae5 100644 --- a/packages/compiler/src/frontend/services.ts +++ b/packages/compiler/src/frontend/services.ts @@ -2,6 +2,11 @@ import { Ts7SourceParser, type Ts7SourceKind } from "./ts7/source-parser.js"; import { Ts7Host, type Ts7ApiFactory, type Ts7HostOptions } from "./ts7/program-host.js"; import { rewriteBundlerCjsWithParser } from "./npm-static-rewrite-host.js"; import { isBundlerCjsCandidate } from "./npm-static-rewrite-syntax.js"; +import { + mayBundleChunks, + splitBundledChunks, + type BundledChunkSplit, +} from "./npm-static-bundled-chunks.js"; import * as syntax from "./npm-static-declaration-syntax.js"; import type { SourceFile } from "./ts7/ast-types.js"; @@ -55,10 +60,21 @@ export class FrontendServices { this.ensureOpen(); return new Ts7Host(this.createApi, { ...options, cwd: options?.cwd ?? this.cwd }); } - rewriteCjs(source: string, path: string): string | { degrade: string } | null { + rewriteCjs( + source: string, + path: string, + liveExportTable?: (path: string) => void, + ): string | { degrade: string } | null { this.ensureOpen(); if (!isBundlerCjsCandidate(source)) return null; - return rewriteBundlerCjsWithParser(this.sourceParser(), source, path); + return rewriteBundlerCjsWithParser(this.sourceParser(), source, path, liveExportTable); + } + /** A CommonJS bundle's __commonJS chunks as their own modules (null: no + * chunks; a degrade reason: chunks the recognizer cannot move). */ + splitCjsChunks(source: string, path: string): BundledChunkSplit | { degrade: string } | null { + this.ensureOpen(); + if (!mayBundleChunks(source)) return null; + return splitBundledChunks(this.parse(path, source, "js"), path); } nullableClassFields(path: string, source: string): syntax.NpmStaticOverloadRewrite | null { return syntax.applyNpmStaticNullableClassFields(this.parse(path, source, "js"), source); diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index b6447454b..bd6723dfc 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -6,6 +6,7 @@ import type { IrRecordShape, IrType, IrUnionDef, IrUnionDiscriminant } from "../ import { BYTES_ELEMENT_NAME, arrayOf, + isDynTypedRefType, BOOL, bytesOf, canConvertToDyn, @@ -125,6 +126,14 @@ export function jsOpenObjectType( : type; } +/** The modules whose RequestOptions interface maps to the checked dynamic. */ +const HTTP_REQUEST_OPTION_MODULES: ReadonlySet = new Set([ + "http", + "node:http", + "https", + "node:https", +]); + /** The WebCrypto interfaces whose values are checked-dynamic: the crypto * global, SubtleCrypto, CryptoKey handles and the algorithm dictionaries * (scr_webcrypto.c). */ @@ -325,7 +334,7 @@ export class ShapeRegistry { ) { return; } - shape.declaredOrder = declaredOrder; + shape.declaredOrder = this.withExtendedNames(shape.id, declaredOrder); this.declaredOrderPriority.set(shape.id, this.currentDeclaredOrderPriority); } @@ -341,7 +350,7 @@ export class ShapeRegistry { } const shape = this.byId.get(shapeId); if (!shape) continue; - shape.declaredOrder = best.order; + shape.declaredOrder = this.withExtendedNames(shapeId, best.order); this.declaredOrderPriority.set(shapeId, best.priority); } for (const finalize of this.derivedDeclaredOrderFinalizers) finalize(); @@ -374,7 +383,7 @@ export class ShapeRegistry { // still obeys first-writer-wins. if (shape?.declaredOrder !== originalOrder) return; const next = order(); - if (next !== undefined) shape.declaredOrder = next; + if (next !== undefined) shape.declaredOrder = this.withExtendedNames(shape.id, next); }; } @@ -482,6 +491,53 @@ export class ShapeRegistry { get(shapeId: string): IrRecordShape | undefined { return this.byId.get(shapeId); } + + /** Names extendShape added to a shape, which every key-order table the + * shape adopts lists after its declared names. */ + private readonly extendedNames = new Map(); + + /** The members extendShape attached to a shape (empty for most). */ + attachedNames(shapeId: string): readonly string[] { + return this.extendedNames.get(shapeId) ?? []; + } + + private withExtendedNames(shapeId: string, order: string[]): string[] { + const extra = this.extendedNames.get(shapeId); + if (!extra) return order; + const missing = extra.filter((name) => !order.includes(name)); + return missing.length === 0 ? order : [...order, ...missing]; + } + + /** Adds optional fields to an interned shape in place: members a type + * assertion attaches to the shape's values (`r as R & { tag: string }` + * followed by `view.tag = ...`; see assertion-members.ts). Every value + * of the shape holds them absent until a write through such a view, so + * the shape keeps its id, both structural keys resolve to it, and its + * key-order table lists the new names after the declared ones. Runs + * before any body lowers; existing layouts change, so the revision + * advances like a closing recursive placeholder. */ + extendShape(shapeId: string, extra: readonly { name: string; type: IrType }[]): void { + const shape = this.byId.get(shapeId); + if (!shape || shape.tuple || extra.length === 0) return; + const fresh = extra.filter((f) => !shape.fields.some((x) => x.name === f.name)); + if (fresh.length === 0) return; + shape.fields = [...shape.fields, ...fresh].sort((a, b) => + a.name < b.name ? -1 : a.name > b.name ? 1 : 0, + ); + this.extendedNames.set(shapeId, [ + ...(this.extendedNames.get(shapeId) ?? []), + ...fresh.map((f) => f.name), + ]); + if (shape.declaredOrder) + shape.declaredOrder = this.withExtendedNames(shapeId, shape.declaredOrder); + const candidates = this.declaredOrderCandidates.get(shapeId); + if (candidates) { + for (const c of candidates) c.order = this.withExtendedNames(shapeId, c.order); + } + this.revision++; + const key = this.keyOf(shape.fields, false, shape.indexValue); + if (!this.byKey.has(key)) this.byKey.set(key, shapeId); + } } /** The frontend's union interner — mirrors ShapeRegistry. A union's @@ -1543,6 +1599,10 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { contextResolutions++; return DYN; } + // Readonly over a program class (Object.freeze's result type) is the + // same instance. + const readonlyClass = readonlyClassType(type, ctx); + if (readonlyClass !== null) return readonlyClass; if (resolveTypeParam && type.flags & ts.TypeFlags.TypeParameter) { const bound = resolveTypeParam(type); if (bound) { @@ -2461,6 +2521,21 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { // spawn consumes a presence-sensitive option bag, including optional // stdio and env values. Keep it checked-dynamic for native normalization. if (isStdlibInterface("SpawnOptions")) return DYN; + // http.RequestOptions / https.RequestOptions as a declared type: an + // option record whose members include functions, agents and signals. + // Values ride checked-dynamic storage, like SpawnOptions. + if ( + psym?.name === "RequestOptions" && + psym.declarations.some((d) => { + if (!ts.isInterfaceDeclaration(d) || !ctx.isStdlibFile(d.getSourceFile())) return false; + for (let p: ts.Node | undefined = d.parent; p !== undefined; p = p.parent) { + if (ts.isModuleDeclaration(p) && ts.isStringLiteral(p.name)) + return HTTP_REQUEST_OPTION_MODULES.has(p.name.text); + } + return false; + }) + ) + return DYN; // exactly like npm-declared types. Static fetch has one deliberately // narrower native representation: Response is an opaque checked- @@ -4388,10 +4463,13 @@ function mapCallSignature(sig: ts.Signature, ctx: TypeMapperCtx): IrType | null // params). Declaration files keep their existing paths: library // callback slots such as String#replace's `(substring, ...args: any[])` // have intrinsic lowerings that inspect the unmapped type. + // node:test's default mock function type, `(...args: any[]) => + // undefined` (the type parameter default of mock.fn), takes the same + // ABI: mock.fn() without an original records whatever its callers pass. if ( rest && decl !== undefined && - !decl.getSourceFile().isDeclarationFile && + (!decl.getSourceFile().isDeclarationFile || isNodeTestDefaultFunctionParam(decl, ctx)) && (pt?.kind === "dyn" || (!pt && isAnyArrayType(checker.getTypeOfSymbol(p), checker))) ) { dynRest = true; @@ -5347,7 +5425,8 @@ function inferSymbolOf(t: ts.Type, _ctx: TypeMapperCtx): ts.Symbol | undefined { /** `checked extends (...args: any) => infer R` — the shape of the standard * library's ReturnType, over a concrete function type: R binds to its * result. Parameters must be `any` (they constrain nothing); anything else - * stays undecided. A primitive never matches a function type. */ + * stays undecided. A primitive never matches a function type, and neither + * does a function that needs more arguments than fixed parameters pass. */ function matchInferSignature( checked: ts.Type, extendsType: ts.Type, @@ -5370,12 +5449,41 @@ function matchInferSignature( const gotSigs = checker.getCallSignatures(checked); const got = gotSigs[0]; if (gotSigs.length !== 1 || !got || got.getTypeParameters().length > 0) return undefined; + // A pattern with fixed parameters admits only functions that need no + // more arguments than it passes: `(a: any) => infer R` rejects + // `(a: string, b: string) => R`, as TypeScript's assignability does. + const wantArity = signatureArity(want); + const gotArity = signatureArity(got); + if ( + wantArity !== undefined && + gotArity !== undefined && + !wantArity.rest && + gotArity.required > want.getParameters().length + ) + return false; const wantRet = checker.getReturnTypeOfSignature(want); const infer = inferSymbolOf(wantRet, ctx); if (infer) return new Map([[infer, checker.getReturnTypeOfSignature(got)]]); return wantRet.flags & ts.TypeFlags.Any ? new Map() : undefined; } +/** How many arguments a call of `sig` must pass (up to its last required + * parameter), and whether it takes a rest parameter. Undefined when a + * parameter has no declaration to read this from; the arity check is then + * skipped. */ +function signatureArity(sig: ts.Signature): { required: number; rest: boolean } | undefined { + let required = 0; + let rest = false; + const params = sig.getParameters(); + for (let i = 0; i < params.length; i++) { + const decl = params[i]!.valueDeclaration; + if (decl === undefined || !ts.isParameter(decl)) return undefined; + if (decl.dotDotDotToken !== undefined) rest = true; + else if (decl.questionToken === undefined && decl.initializer === undefined) required = i + 1; + } + return { required, rest }; +} + /** `checked extends PromiseLike` (or `Promise`) over the * standard library's Promise: U binds to the settled type. An object with * no `then` member is no thenable. Everything else stays undecided. */ @@ -5420,6 +5528,19 @@ function mentionsMappedParams( return false; } +function readonlyClassType(type: ts.Type, ctx: TypeMapperCtx): IrType | null { + const alias = type.getAliasSymbol(); + if (alias?.name !== "Readonly") return null; + const args = type.getAliasTypeArguments(); + if (args.length !== 1 || !args[0]) return null; + const isLibAlias = alias.declarations.some( + (d) => ts.isTypeAliasDeclaration(d) && ctx.isStdlibFile(d.getSourceFile()), + ); + if (!isLibAlias) return null; + const mapped = mapType(args[0], ctx); + return mapped !== null && isDynTypedRefType(mapped) ? mapped : null; +} + function mapGenericUtilityAlias(widened: ts.Type, ctx: TypeMapperCtx): IrType | null { const { resolveTypeParam, shapes, unions } = ctx; if (!resolveTypeParam) return null; @@ -6698,6 +6819,23 @@ function dynSubsumableUnionArm(arm: IrType, ctx: TypeMapperCtx): boolean { } } +/** A parameter of a function type that is the default of a type parameter + * declared in node:test's standard-library declarations (MockTracker.fn's + * `F extends Function = (...args: any[]) => undefined`). */ +function isNodeTestDefaultFunctionParam(decl: ts.Declaration, ctx: TypeMapperCtx): boolean { + const fnType = decl.parent; + return ( + ts.isParameter(decl) && + fnType !== undefined && + ts.isFunctionTypeNode(fnType) && + fnType.parent !== undefined && + ts.isTypeParameterDeclaration(fnType.parent) && + fnType.parent.defaultType === fnType && + ctx.isStdlibFile(decl.getSourceFile()) && + isDeclaredInAmbientModule(decl, "test") + ); +} + /** `any[]` (or `readonly any[]`): an array type whose element is `any`. */ export function isAnyArrayType(t: ts.Type, checker: ts.TypeChecker): boolean { if (!checker.isArrayType(t)) return false; diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 14bf8760d..03fa5c6fd 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -346,6 +346,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "process.kill", "process.killNum", "process.setExitCode", + "process.setExitCodeTracked", // Node's argument grammar throws ERR_INVALID_ARG_TYPE at the call. "process.emitWarning", // cpuUsage(prev)'s field validation: negative/non-finite prev fields @@ -600,6 +601,9 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "dyn.mapSeedEntry", "dyn.freeze", "dyn.isFrozen", + "class.defineField", + "class.throwReadOnly", + "class.throwNotExtensible", "dyn.toString", "dyn.valueOf", "string.fromCodePoint", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 36b2bedc8..b807c7b42 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -206,6 +206,23 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "dyn.in": { argTypes: [DYN, STRING], result: BOOL }, "dyn.freeze": { argTypes: [DYN], result: DYN }, "dyn.isFrozen": { argTypes: [DYN], result: BOOL }, + /** Object.defineProperty on a declared class field (scr_json.c): the + * field's current value (borrowed), its FIELD_* attribute word, the + * instance's CLASS_* integrity word, the field name and the descriptor. + * Validates as Node does (TypeError "Cannot redefine property: f") and + * answers a one-property holder of the defined value and attributes (+1), + * read back with class.definedBits and class.definedValue. */ + "class.defineField": { argTypes: [DYN, F64, F64, STRING, DYN], result: DYN }, + "class.definedBits": { argTypes: [DYN, STRING], result: F64 }, + "class.definedValue": { argTypes: [DYN, STRING], result: DYN }, + /** Whether a property descriptor has a `value` member. */ + "class.descriptorHasValue": { argTypes: [DYN], result: BOOL }, + /** Throws Node's TypeError for a write to a read-only class field: the + * field name and the instance's class name. */ + "class.throwReadOnly": { argTypes: [STRING, STRING], result: VOID }, + /** Throws Node's TypeError for a class field initializer on a + * non-extensible instance: the field name. */ + "class.throwNotExtensible": { argTypes: [STRING], result: VOID }, "dyn.nativeSetNew": { argTypes: [DYN], result: DYN }, "dyn.nativeSetIs": { argTypes: [DYN], result: BOOL }, "dyn.nativeMapIs": { argTypes: [DYN], result: BOOL }, @@ -2405,6 +2422,9 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ /** Rest listeners use the checked function bridge to pack event arguments. */ "child.onDyn": { argTypes: [CHILD_T, STRING, DYN], result: VOID }, "process.connected": { argTypes: [], result: BOOL }, + /** Whether this fork child opened its channel; part of process.send's + * presence in programs with fork targets. Never throws. */ + "process.ipcOpen": { argTypes: [], result: BOOL }, "process.send": { argTypes: [STRING], result: BOOL }, "process.sendCb": { argTypes: [STRING, null], result: BOOL }, "process.disconnect": { argTypes: [], result: VOID }, @@ -3039,8 +3059,13 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "process.exit": { argTypes: [F64], result: VOID }, /** Numeric process.exitCode write (integer validation, implicit exit status). */ "process.setExitCode": { argTypes: [F64], result: VOID }, + /** The process.exitCode write of a program that also reads the + * property: the same validation, and the code counts as assigned. */ + "process.setExitCodeTracked": { argTypes: [F64], result: VOID }, /** The code for process.exit() with no argument, or zero when unset. */ "process.currentExitCode": { argTypes: [], result: F64 }, + /** Whether process.exitCode reads a code rather than undefined. Never throws. */ + "process.hasExitCode": { argTypes: [], result: BOOL }, "process.cwd": { argTypes: [], result: STRING }, /** getpid(2) / getuid(2): zero args → f64. POSIX-only target, so both * always answer (the checker's `getuid?` optionality covers Windows — @@ -3262,6 +3287,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ /** SameValue over checked values, including NaN, signed zero and reference identity. */ "dyn.sameValue": { argTypes: [DYN, DYN], result: BOOL }, "error.stack": { argTypes: [null], result: STRING }, + "error.setStack": { argTypes: [null, STRING], result: VOID }, "error.stackLimitGet": { argTypes: [], result: F64 }, "error.stackLimitSet": { argTypes: [F64], result: VOID }, // Receiver (any error-hierarchy object) and the program-dependent diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 9a8f1121c..d6ff0fe72 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -1932,8 +1932,23 @@ export type IrStmt = | { kind: "return"; value: IrExpr | null; awaited?: true; loc: SrcLoc } /** Field write `obj.f = v` — statement-only, like `assign`/`arraySet`. * Evaluation order: obj, then value. The old value is released; ownership - * of a refcounted new value MOVES into the object. */ - | { kind: "fieldSet"; obj: IrExpr; className: string; field: string; value: IrExpr; loc: SrcLoc } + * of a refcounted new value MOVES into the object. `sloppy` marks a write + * in sloppy-mode code, which skips a read-only field instead of throwing. + * `define` marks a class field initializer, which defines the property + * (a non-extensible instance rejects it). `attributesChecked` marks a + * write that already honors the instance's property attributes + * (CLASS_ATTRIBUTES). */ + | { + kind: "fieldSet"; + obj: IrExpr; + className: string; + field: string; + value: IrExpr; + sloppy?: true; + define?: true; + attributesChecked?: true; + loc: SrcLoc; + } /** Record field write `r.f = v` — mirrors `fieldSet` exactly (evaluation * order obj then value; old value released; refcounted new value moved * in), with a shape id in place of a class name. */ @@ -4078,6 +4093,27 @@ export function isClassOwnEnumerableFieldName(name: string): boolean { /** Compiler-owned storage for properties added through untyped references. */ export const DYN_CLASS_PROPERTIES = "%dynProperties"; +/** Compiler-owned integrity state of a class instance whose hierarchy is + * passed to Object.freeze, Object.seal, Object.preventExtensions or + * Object.defineProperty: an f64 holding CLASS_NOT_EXTENSIBLE, CLASS_SEALED + * and CLASS_FROZEN bits. Other hierarchies have no such field. */ +export const CLASS_ATTRIBUTES = "%attributes"; +export const CLASS_NOT_EXTENSIBLE = 1; +export const CLASS_SEALED = 2; +export const CLASS_FROZEN = 4; + +/** Compiler-owned attributes of one declared field that Object.defineProperty + * changes: an f64 holding FIELD_NOT_WRITABLE, FIELD_NOT_ENUMERABLE and + * FIELD_NOT_CONFIGURABLE bits (zero is an ordinary data property). */ +export const CLASS_FIELD_ATTRIBUTES_PREFIX = "%attr:"; +export const FIELD_NOT_WRITABLE = 1; +export const FIELD_NOT_ENUMERABLE = 2; +export const FIELD_NOT_CONFIGURABLE = 4; + +export function classFieldAttributesName(field: string): string { + return CLASS_FIELD_ATTRIBUTES_PREFIX + field; +} + /** A class capsule can always preserve its exact native identity. Its * optional property view additionally needs converters in both directions; * fields such as Maps may remain opaque without preventing the round trip. */ diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 69656576b..4ba157d74 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -211,6 +211,7 @@ const CHILD_PROCESS_LIB_FNS: ReadonlySet = new Set([ "process.connected", "process.disconnect", "process.forkTarget", + "process.ipcOpen", "process.onDisconnect", "process.onMessage", "process.send", diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index 1c069531f..ec37ddcf8 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -4109,6 +4109,7 @@ function validateFunction( if (checkLibEmitterCall(e, sig.result)) return; if ( e.fn === "error.stack" || + e.fn === "error.setStack" || e.fn === "error.cause" || e.fn === "error.hasCause" || e.fn === "error.setCause" || diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 41fef3232..1fc595f5f 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -2002,7 +2002,7 @@ "kind": "node-builtin", "name": "process.exitCode", "status": "static", - "note": "numeric writes in statement position set the implicit exit status; process.exit() reads it" + "note": "numeric writes in statement position set the implicit exit status; reads answer the assigned code or undefined; process.exit() reads it" }, { "id": "node-builtin.process.getBuiltinModule", @@ -2546,7 +2546,7 @@ "name": "util.promisify", "status": "unsupported", "code": "SC2020", - "note": "the lowered shapes are const bindings over child_process.execFile, child_process.exec, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots, the crypto callback functions, dns.lookup, dns.lookupService and the fs callback functions with an fs/promises counterpart; call the bound function directly" + "note": "the lowered shapes are const bindings over child_process.execFile, child_process.exec, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots, the crypto callback functions, dns.lookup, dns.lookupService and the fs callback functions with an fs/promises counterpart, plus typed callback-last function values whose callback takes (error?: Error | null, value?); call the bound function directly" }, { "id": "node-builtin.util.stripVTControlCharacters", diff --git a/packages/compiler/test/class-attributes.test.ts b/packages/compiler/test/class-attributes.test.ts new file mode 100644 index 000000000..1a6fea654 --- /dev/null +++ b/packages/compiler/test/class-attributes.test.ts @@ -0,0 +1,84 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule } from "../src/index.js"; +import type { IrModule } from "../src/ir/ir.js"; + +async function lowerModule(source: string, file = "main.ts"): Promise { + const dir = await mkdtemp(join(tmpdir(), "scriptc-class-attributes-")); + try { + const entry = join(dir, file); + const outPath = join(dir, "main.ir.json"); + await writeFile(entry, source); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + return deserializeModule(await readFile(outPath, "utf8")); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +function fieldsOf(mod: IrModule, className: string): string[] { + const cls = (mod.classes ?? []).find( + (c) => c.name === className || c.name.endsWith(`.${className}`), + ); + if (!cls) throw new Error(`no class ${className}`); + return cls.fields.map((f) => f.name); +} + +function functionsCalling(mod: IrModule, fn: string): string[] { + return mod.functions + .filter((f) => JSON.stringify(f.body).includes(`"fn":"${fn}"`)) + .map((f) => f.name); +} + +test("only hierarchies passed to an integrity call get attribute state and write checks", async () => { + const mod = await lowerModule(` +export {}; +class Point { x = 1; } +class Other { x = 1; } +function movePoint(p: Point): void { p.x = 2; } +function moveOther(o: Other): void { o.x = 2; } +const p = new Point(); +Object.freeze(p); +movePoint(p); +moveOther(new Other()); +`); + expect(fieldsOf(mod, "Point")).toContain("%attributes"); + expect(fieldsOf(mod, "Other")).not.toContain("%attributes"); + const checked = functionsCalling(mod, "class.throwReadOnly"); + expect(checked).toContain("movePoint"); + expect(checked).not.toContain("moveOther"); +}); + +test("a redefined field gets its own attribute word", async () => { + const mod = await lowerModule(` +export {}; +class Config { mode = "dev"; level = 1; } +const c = new Config(); +Object.defineProperty(c, "mode", { writable: false }); +`); + const fields = fieldsOf(mod, "Config"); + expect(fields).toContain("%attributes"); + expect(fields).toContain("%attr:mode"); + expect(fields).not.toContain("%attr:level"); +}); + +test("sloppy-mode writes skip a read-only field without throwing", async () => { + const mod = await lowerModule( + ` +class Box { constructor() { this.x = 1; } } +const b = new Box(); +Object.freeze(b); +b.x = 2; +`, + "main.cjs", + ); + expect(fieldsOf(mod, "Box")).toContain("%attributes"); + // Class bodies are strict mode code; the top-level write is not. + const throwing = functionsCalling(mod, "class.throwReadOnly"); + expect(throwing.length).toBeGreaterThan(0); + expect(throwing.every((name) => name.includes("constructor"))).toBe(true); +}); diff --git a/packages/compiler/test/native-class-descriptors.test.ts b/packages/compiler/test/native-class-descriptors.test.ts index d4aff3949..bd0a06dac 100644 --- a/packages/compiler/test/native-class-descriptors.test.ts +++ b/packages/compiler/test/native-class-descriptors.test.ts @@ -12,7 +12,7 @@ function fixture(source: string) { } test.each([ - "Object.defineProperty(value, 'x', {value: 2, writable: false});", + "Object.defineProperty(value, 'x', {get() { return 2; }});", "Object.defineProperties(value, {x: {value: 2}});", ])("keeps unsafe native descriptor changes fenced: %s", (operation) => { const { dir, entry } = fixture( @@ -30,6 +30,42 @@ test.each([ } }); +test("data descriptor changes on native fields match Node", async () => { + const { dir, entry } = fixture(` +class Value { constructor() { this.x = 1; } } +const value = new Value(); +Object.defineProperty(value, 'x', { value: 2, writable: false }); +console.log(value.x, JSON.stringify(Object.getOwnPropertyDescriptor(value, 'x'))); +value.x = 3; +console.log(value.x, Object.keys(value)); +`); + try { + const result = await compile(entry, { + outDir: dir, + outPath: join(dir, "program"), + sanitize: process.env["SCRIPTC_SAN"] === "1", + }); + if (!result.ok) throw new Error(JSON.stringify(result.diagnostics)); + const run = spawnSync(result.binaryPath, { encoding: "utf8", timeout: 30_000 }); + const oracle = spawnSync(process.execPath, [entry], { encoding: "utf8", timeout: 30_000 }); + expect(run.error).toBeUndefined(); + expect(oracle.status).toBe(0); + expect({ + status: run.status, + signal: run.signal, + stdout: run.stdout, + stderr: run.stderr, + }).toEqual({ + status: oracle.status, + signal: oracle.signal, + stdout: oracle.stdout, + stderr: oracle.stderr, + }); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +}); + test("JS overrides with different return types match Node", async () => { const { dir, entry } = fixture(` class Base { copy(value = 1) { return value; } } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5467-typed-array-loop-versions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5467-typed-array-loop-versions.ts.json new file mode 100644 index 000000000..a4be59696 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5467-typed-array-loop-versions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5467-typed-array-loop-versions.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5468-typed-array-loop-aliasing.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5468-typed-array-loop-aliasing.ts.json new file mode 100644 index 000000000..517cbab4c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5468-typed-array-loop-aliasing.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5468-typed-array-loop-aliasing.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5469-typed-array-loop-initializer-rebinding.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5469-typed-array-loop-initializer-rebinding.ts.json new file mode 100644 index 000000000..79c7d0c63 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5469-typed-array-loop-initializer-rebinding.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5469-typed-array-loop-initializer-rebinding.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5816-fixed-into-unknown-rest.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5816-fixed-into-unknown-rest.ts.json new file mode 100644 index 000000000..8354f5c48 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5816-fixed-into-unknown-rest.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5816-fixed-into-unknown-rest.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5916-dyn-error-stack-property.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5916-dyn-error-stack-property.ts.json new file mode 100644 index 000000000..fa5b5460f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5916-dyn-error-stack-property.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5916-dyn-error-stack-property.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6004-class-instance-integrity.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6004-class-instance-integrity.ts.json new file mode 100644 index 000000000..4d21236c0 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6004-class-instance-integrity.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6004-class-instance-integrity.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6005-class-instance-integrity-sloppy.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6005-class-instance-integrity-sloppy.cjs.json new file mode 100644 index 000000000..1101d2180 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6005-class-instance-integrity-sloppy.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6005-class-instance-integrity-sloppy.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6064-protocol-subinterface-assertions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6064-protocol-subinterface-assertions.ts.json deleted file mode 100644 index e81d7e9e7..000000000 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6064-protocol-subinterface-assertions.ts.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "order": [ - "/tests/corpus/6064-protocol-subinterface-assertions.ts" - ], - "diags": [] -} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6398-conditional-fixed-arity.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6398-conditional-fixed-arity.ts.json new file mode 100644 index 000000000..878f45b09 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6398-conditional-fixed-arity.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6398-conditional-fixed-arity.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6400-dyn-error-stack-property-js.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6400-dyn-error-stack-property-js.js.json new file mode 100644 index 000000000..7bea48883 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6400-dyn-error-stack-property-js.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6400-dyn-error-stack-property-js.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6401-dyn-error-own-property-names.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6401-dyn-error-own-property-names.ts.json new file mode 100644 index 000000000..cf96c4f96 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6401-dyn-error-own-property-names.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6401-dyn-error-own-property-names.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6402-dyn-error-own-property-names-js.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6402-dyn-error-own-property-names-js.js.json new file mode 100644 index 000000000..49cf88884 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6402-dyn-error-own-property-names-js.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6402-dyn-error-own-property-names-js.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6420-process-send-presence.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6420-process-send-presence.ts.json new file mode 100644 index 000000000..69db221e2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6420-process-send-presence.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6420-process-send-presence.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6421-process-send-presence-fork/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6421-process-send-presence-fork/main.ts.json new file mode 100644 index 000000000..abde055bf --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6421-process-send-presence-fork/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6421-process-send-presence-fork/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6422-process-exitcode-read.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6422-process-exitcode-read.ts.json new file mode 100644 index 000000000..15abd3cdc --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6422-process-exitcode-read.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6422-process-exitcode-read.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6423-process-exitcode-default.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6423-process-exitcode-default.ts.json new file mode 100644 index 000000000..31bf2584e --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6423-process-exitcode-default.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6423-process-exitcode-default.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6424-process-exit-keeps-exitcode.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6424-process-exit-keeps-exitcode.ts.json new file mode 100644 index 000000000..ce051e3fa --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6424-process-exit-keeps-exitcode.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6424-process-exit-keeps-exitcode.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6425-stream-hook-wider-chunk.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6425-stream-hook-wider-chunk.ts.json new file mode 100644 index 000000000..4c6db1400 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6425-stream-hook-wider-chunk.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6425-stream-hook-wider-chunk.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6426-promise-race-void-entry.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6426-promise-race-void-entry.ts.json new file mode 100644 index 000000000..e4d66ecf4 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6426-promise-race-void-entry.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6426-promise-race-void-entry.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6427-http-request-options-type.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6427-http-request-options-type.ts.json new file mode 100644 index 000000000..3e403ece6 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6427-http-request-options-type.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6427-http-request-options-type.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6428-promisify-callback-functions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6428-promisify-callback-functions.ts.json new file mode 100644 index 000000000..76c3e65d0 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6428-promisify-callback-functions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6428-promisify-callback-functions.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6429-esm-js-dirname.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6429-esm-js-dirname.mjs.json new file mode 100644 index 000000000..0168f85ee --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6429-esm-js-dirname.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6429-esm-js-dirname.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6445-rest-function-fixed-slot.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6445-rest-function-fixed-slot.ts.json new file mode 100644 index 000000000..b39c2fa38 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6445-rest-function-fixed-slot.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6445-rest-function-fixed-slot.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6446-rest-function-nested-declaration.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6446-rest-function-nested-declaration.ts.json new file mode 100644 index 000000000..41c034395 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6446-rest-function-nested-declaration.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6446-rest-function-nested-declaration.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6460-in-union-optional-slots.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6460-in-union-optional-slots.ts.json new file mode 100644 index 000000000..8491507eb --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6460-in-union-optional-slots.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6460-in-union-optional-slots.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6461-predicate-intersection-narrowing.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6461-predicate-intersection-narrowing.ts.json new file mode 100644 index 000000000..3ce078006 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6461-predicate-intersection-narrowing.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6461-predicate-intersection-narrowing.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6462-assertion-attached-members.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6462-assertion-attached-members.ts.json new file mode 100644 index 000000000..36e333373 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6462-assertion-attached-members.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6462-assertion-attached-members.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6480-catch-typeof-untyped-throws.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6480-catch-typeof-untyped-throws.ts.json new file mode 100644 index 000000000..38b99f9fc --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6480-catch-typeof-untyped-throws.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6480-catch-typeof-untyped-throws.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/boot-path-node-surface-fences.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/boot-path-node-surface-fences.ts.json new file mode 100644 index 000000000..de58c3423 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/boot-path-node-surface-fences.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/boot-path-node-surface-fences.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/class-field-accessor-descriptor.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/class-field-accessor-descriptor.ts.json new file mode 100644 index 000000000..3d6639169 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/class-field-accessor-descriptor.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/class-field-accessor-descriptor.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-callback-functions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-callback-functions.ts.json new file mode 100644 index 000000000..a4a753c3d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/promisify-callback-functions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/promisify-callback-functions.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/stream-subclass-hooks.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/stream-subclass-hooks.ts.json new file mode 100644 index 000000000..295d7deda --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/stream-subclass-hooks.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/stream-subclass-hooks.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2558-bundled-chunks/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2558-bundled-chunks/main.ts.json new file mode 100644 index 000000000..cc5bc69c8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2558-bundled-chunks/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/2558-bundled-chunks/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2559-cjs-cycle/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2559-cjs-cycle/main.ts.json new file mode 100644 index 000000000..382eef7b4 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2559-cjs-cycle/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/2559-cjs-cycle/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2560-cjs-cycle-partner-first/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2560-cjs-cycle-partner-first/main.ts.json new file mode 100644 index 000000000..f609f128e --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2560-cjs-cycle-partner-first/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/2560-cjs-cycle-partner-first/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2561-cjs-cycle-early-read/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2561-cjs-cycle-early-read/main.ts.json new file mode 100644 index 000000000..be3b2af16 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2561-cjs-cycle-early-read/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/2561-cjs-cycle-early-read/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2562-subpath-leaf/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2562-subpath-leaf/main.ts.json new file mode 100644 index 000000000..68cde3de1 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2562-subpath-leaf/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/2562-subpath-leaf/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2564-chunk-helper-shadowing/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2564-chunk-helper-shadowing/main.ts.json new file mode 100644 index 000000000..90e304cbe --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2564-chunk-helper-shadowing/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/2564-chunk-helper-shadowing/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2565-chunk-shared-function/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2565-chunk-shared-function/main.ts.json new file mode 100644 index 000000000..6443d170b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2565-chunk-shared-function/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/2565-chunk-shared-function/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2566-cjs-cycle-indirect-call/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2566-cjs-cycle-indirect-call/main.ts.json new file mode 100644 index 000000000..f51a29951 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2566-cjs-cycle-indirect-call/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/2566-cjs-cycle-indirect-call/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2571-cjs-cycle-stored-function/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2571-cjs-cycle-stored-function/main.ts.json new file mode 100644 index 000000000..c3e0442f9 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/2571-cjs-cycle-stored-function/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/2571-cjs-cycle-stored-function/main.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_alloc.c b/packages/runtime/src/scr_alloc.c index 246d27f0a..935736612 100644 --- a/packages/runtime/src/scr_alloc.c +++ b/packages/runtime/src/scr_alloc.c @@ -935,12 +935,19 @@ static void scr_sa_trim(void) { * interrupts every running thread of the process to flush its TLB, and * glibc's trim locks the arenas other threads allocate from, so discards * wait for the last worker of a group, which hands them to one helper; - * - the helper waits SCR_SA_DISCARD_DELAY_MS (100 by default) and stops if + * - the helper waits a delay (scr_sa_discard_delay_ms: 1 s to start, + * doubled each time workers start again soon after a discard) and stops if * a worker started meanwhile: a program that starts its next workers or * exits within that time does not return pages it would fault back in or * never touch again, and the last worker of the next group hands the * discards to a new helper; a thread that finds every arena claimed * discards one waiting arena and claims it; + * - once the event loop of the thread that is not a worker runs, the + * helper then discards one arena at a time, and only while that loop + * waits with nothing ready (scr_sa_loop_waiting): a program that does + * its next work on that thread alone (a compiler rebuilding one file in + * watch mode) would otherwise have it slowed by the discards. A loop that + * does not wait gets them SCR_SA_DISCARD_DELAY_MAX_MS after the delay; * - the helper then returns the pages * it carved (MADV_DONTNEED; the start of the first page, which it may * share with older blocks, is cleared), frees the recorded system blocks, @@ -1214,12 +1221,20 @@ void scr_sa_thread_shares(void) { /* Worker threads that started and have not parked. */ static _Atomic(unsigned) scr_sa_workers_live; +#ifdef SCR_SA_TRIM +static void scr_sa_group_starting(void); +#endif + /* Library archives run on their embedder's threads and keep their memory. */ static void scr_sa_worker_starting(void) { #ifndef SCR_LIB scr_sa_worker = true; +#ifdef SCR_SA_TRIM + if (atomic_fetch_add_explicit(&scr_sa_workers_live, 1, memory_order_relaxed) == 0) scr_sa_group_starting(); +#else atomic_fetch_add_explicit(&scr_sa_workers_live, 1, memory_order_relaxed); #endif +#endif } #define SCR_SA_WORKER_STARTING() scr_sa_worker_starting() #endif @@ -1309,28 +1324,91 @@ static bool scr_sa_drain_some(bool one) { static bool scr_sa_drain(void) { return scr_sa_drain_some(false); } -/* SCR_SA_DISCARD_DELAY_MS: how long the trim helper waits after the last - * worker parks before it returns their memory (default 100). */ -static long scr_sa_discard_delay_ms(void) { - const char *delay = getenv("SCR_SA_DISCARD_DELAY_MS"); - if (!delay) return 100; - long ms = strtol(delay, NULL, 10); +/* How long the trim helper waits after the last worker parks before it + * returns their memory: SCR_SA_DISCARD_DELAY_MS (1000 by default) to start. + * Each time workers start again within ten delays of a discard, the delay + * doubles, up to SCR_SA_DISCARD_DELAY_MAX_MS (10000 by default): a program + * that keeps starting workers (a compiler rebuilding in watch mode, a + * server) would fault the returned pages straight back in. Memory that + * stays idle for the grown delay still goes back. */ +static _Atomic(long) scr_sa_delay_grown_ms; /* 0 until a discard proved too early */ +static _Atomic(long) scr_sa_discarded_ms; /* when the helper last discarded; 0: not since */ + +static long scr_sa_env_ms(const char *name, long fallback) { + const char *value = getenv(name); + if (!value) return fallback; + long ms = strtol(value, NULL, 10); return ms < 0 ? 0 : ms; } +static long scr_sa_discard_delay_ms(void) { + long start = scr_sa_env_ms("SCR_SA_DISCARD_DELAY_MS", 1000); + long max = scr_sa_env_ms("SCR_SA_DISCARD_DELAY_MAX_MS", 10000); + long grown = atomic_load_explicit(&scr_sa_delay_grown_ms, memory_order_relaxed); + long delay = grown > start ? grown : start; + return max >= start && delay > max ? max : delay; +} + +static long scr_sa_now_ms(void) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return (long)now.tv_sec * 1000 + now.tv_nsec / 1000000 + 1; +} + +/* The first worker of a group starts: a discard shortly before means the + * delay was too short for this program. */ +static void scr_sa_group_starting(void) { + long at = atomic_exchange_explicit(&scr_sa_discarded_ms, 0, memory_order_relaxed); + if (!at) return; + long delay = scr_sa_discard_delay_ms(); + if (scr_sa_now_ms() - at >= 10 * (delay > 10 ? delay : 10)) return; + long max = scr_sa_env_ms("SCR_SA_DISCARD_DELAY_MAX_MS", 10000); + long grown = delay > 0 ? 2 * delay : 1; + if (grown > max) grown = max; + if (grown > atomic_load_explicit(&scr_sa_delay_grown_ms, memory_order_relaxed)) + atomic_store_explicit(&scr_sa_delay_grown_ms, grown, memory_order_relaxed); +} + +/* The event loop of the thread that is not a worker: an odd count while it + * waits with nothing ready, an even one while it runs, 0 until it first + * waits. Only that thread writes it. */ +static _Atomic(unsigned long) scr_sa_loop_turns; + +void scr_sa_loop_waiting(bool waiting) { + if (scr_sa_worker) return; + unsigned long turns = atomic_load_explicit(&scr_sa_loop_turns, memory_order_relaxed); + if ((bool)(turns & 1) != waiting) atomic_store_explicit(&scr_sa_loop_turns, turns + 1, memory_order_relaxed); +} + /* Waits out the delay first, and stops if a worker starts meanwhile: the * discards then wait for the last worker of that group. A program that exits * within the delay does not spend its last milliseconds returning pages, and * one that starts its next workers within it does not return pages while - * they start. */ + * they start. Once the event loop runs, each discard then waits until the + * loop has been in one wait for a step, or until the maximum delay has + * passed. */ static void *scr_sa_drain_main(void *arg) { (void)arg; - for (long left = scr_sa_discard_delay_ms(); left > 0; left -= 5) { - struct timespec pause = {0, (left < 5 ? left : 5) * 1000000L}; + long delay = scr_sa_discard_delay_ms(), step = delay > 200 ? 20 : 5; + for (long left = delay; left > 0; left -= step) { + struct timespec pause = {0, (left < step ? left : step) * 1000000L}; nanosleep(&pause, NULL); if (atomic_load_explicit(&scr_sa_workers_live, memory_order_acquire) != 0) return NULL; } - if (atomic_load_explicit(&scr_sa_workers_live, memory_order_acquire) == 0) scr_sa_drain(); + long max = scr_sa_env_ms("SCR_SA_DISCARD_DELAY_MAX_MS", 10000); + unsigned long seen = 0; + for (long waited = 0; atomic_load_explicit(&scr_sa_workers_live, memory_order_acquire) == 0;) { + unsigned long turns = atomic_load_explicit(&scr_sa_loop_turns, memory_order_relaxed); + if (turns == 0 || ((turns & 1) && turns == seen) || waited >= max) { + if (!scr_sa_drain_some(true)) break; + atomic_store_explicit(&scr_sa_discarded_ms, scr_sa_now_ms(), memory_order_relaxed); + continue; + } + seen = turns; + struct timespec pause = {0, step * 1000000L}; + nanosleep(&pause, NULL); + waited += step; + } return NULL; } @@ -1361,6 +1439,7 @@ void scr_sa_wait_trims(void) { #else void scr_sa_wait_trims(void) {} void scr_sa_thread_shares(void) {} +void scr_sa_loop_waiting(bool waiting) { (void)waiting; } #endif static void scr_sa_park_arena(void); @@ -1564,6 +1643,7 @@ void *scr_mem_realloc(void *p, size_t n) { return realloc(p, n); } void scr_sa_thread_park(void) {} void scr_sa_wait_trims(void) {} void scr_sa_thread_shares(void) {} +void scr_sa_loop_waiting(bool waiting) { (void)waiting; } void scr_sa_free_foreign(void *p) { free(p); } #endif #endif diff --git a/packages/runtime/src/scr_alloc.test.c b/packages/runtime/src/scr_alloc.test.c index aa6b0b60b..6c83afdf9 100644 --- a/packages/runtime/src/scr_alloc.test.c +++ b/packages/runtime/src/scr_alloc.test.c @@ -700,11 +700,91 @@ static void check_discard_delay(void) { assert(pthread_join(holder, NULL) == 0); assert(pthread_join(plain, NULL) == 0); scr_sa_wait_trims(); - unsetenv("SCR_SA_DISCARD_DELAY_MS"); + setenv("SCR_SA_DISCARD_DELAY_MS", "100", 1); assert(resident_pages(first, discard_hi) < total / 2); discard_in_old_arena = true; } +/* A discard that workers follow within ten delays was too early: the next + * delay is twice as long, and memory idle for that long still goes back. */ +static void *plain_discard_worker(void *arg) { + (void)arg; + scr_sa_thread_starting(); + allocate_discardable(); + scr_sa_thread_park(); + return NULL; +} + +static void check_discard_delay_grows(void) { + size_t page = (size_t)sysconf(_SC_PAGESIZE); + setenv("SCR_SA_DISCARD_DELAY_MS", "100", 1); + setenv("SCR_SA_DISCARD_DELAY_MAX_MS", "10000", 1); + discard_blocks = malloc(DISCARD_BLOCKS * sizeof *discard_blocks); + assert(discard_blocks); + /* A plain thread holds the arena whose slice the earlier checks filled. */ + atomic_store(&discard_step, 0); + pthread_t plain; + assert(pthread_create(&plain, NULL, holding_thread, NULL) == 0); + wait_step(1); + run(plain_discard_worker); /* returned after the delay */ + pthread_t t; + assert(pthread_create(&t, NULL, plain_discard_worker, NULL) == 0); + assert(pthread_join(t, NULL) == 0); + uintptr_t first = (discard_lo + page - 1) & ~(uintptr_t)(page - 1); + size_t total = (discard_hi - first) / page; + struct timespec pause = {0, 140000000L}; + nanosleep(&pause, NULL); + assert(resident_pages(first, discard_hi) > total / 2); /* the delay is 200 ms or more now */ + scr_sa_wait_trims(); + assert(resident_pages(first, discard_hi) < total / 2); + setenv("SCR_SA_DISCARD_DELAY_MS", "100", 1); + setenv("SCR_SA_DISCARD_DELAY_MAX_MS", "0", 1); + atomic_store(&discard_step, 3); + assert(pthread_join(plain, NULL) == 0); + free(discard_blocks); +} + +/* Once the event loop runs, discards wait for it to wait with nothing + * ready; a loop that does not wait gets them SCR_SA_DISCARD_DELAY_MAX_MS + * after the delay. The test's thread plays the loop's. */ +static void check_discard_waits_for_loop(void) { + size_t page = (size_t)sysconf(_SC_PAGESIZE); + setenv("SCR_SA_DISCARD_DELAY_MS", "100", 1); + setenv("SCR_SA_DISCARD_DELAY_MAX_MS", "10000", 1); + discard_blocks = malloc(DISCARD_BLOCKS * sizeof *discard_blocks); + assert(discard_blocks); + atomic_store(&discard_step, 0); + pthread_t plain; + assert(pthread_create(&plain, NULL, holding_thread, NULL) == 0); + wait_step(1); + scr_sa_loop_waiting(true); + scr_sa_loop_waiting(false); /* the loop runs */ + pthread_t t; + assert(pthread_create(&t, NULL, plain_discard_worker, NULL) == 0); + assert(pthread_join(t, NULL) == 0); + uintptr_t first = (discard_lo + page - 1) & ~(uintptr_t)(page - 1); + size_t total = (discard_hi - first) / page; + struct timespec pause = {0, 900000000L}; + nanosleep(&pause, NULL); + assert(resident_pages(first, discard_hi) > total / 2); /* past the delay */ + scr_sa_loop_waiting(true); + scr_sa_wait_trims(); + assert(resident_pages(first, discard_hi) < total / 2); + /* A loop that keeps running. */ + scr_sa_loop_waiting(false); + setenv("SCR_SA_DISCARD_DELAY_MAX_MS", "300", 1); + assert(pthread_create(&t, NULL, plain_discard_worker, NULL) == 0); + assert(pthread_join(t, NULL) == 0); + first = (discard_lo + page - 1) & ~(uintptr_t)(page - 1); + total = (discard_hi - first) / page; + scr_sa_wait_trims(); + assert(resident_pages(first, discard_hi) < total / 2); + setenv("SCR_SA_DISCARD_DELAY_MAX_MS", "0", 1); + atomic_store(&discard_step, 3); + assert(pthread_join(plain, NULL) == 0); + free(discard_blocks); +} + static void check_discard(void) { discard_blocks = malloc(DISCARD_BLOCKS * sizeof *discard_blocks); assert(discard_blocks); @@ -819,10 +899,15 @@ int main(void) { check_heap_huge_pages(); #endif #if defined(SCR_WORKERS) && SCR_SMALL_ALLOC + /* A short discard delay, which stays at its start until check_discard_delay_grows. */ + setenv("SCR_SA_DISCARD_DELAY_MS", "100", 1); + setenv("SCR_SA_DISCARD_DELAY_MAX_MS", "0", 1); check_threads(); #ifdef __linux__ check_trim(); check_discard(); + check_discard_delay_grows(); + check_discard_waits_for_loop(); #endif printf("allocator checks passed: size-class workers\n"); #else diff --git a/packages/runtime/src/scr_async.c b/packages/runtime/src/scr_async.c index 155f91be4..8185422af 100644 --- a/packages/runtime/src/scr_async.c +++ b/packages/runtime/src/scr_async.c @@ -4410,6 +4410,9 @@ static bool scr_loop_run_pass(ScrPromise *top_level, bool first_checkpoint) { #endif #if !defined(_WIN32) && !defined(__wasi__) if (due > now) scr_fiber_stacks_clear(); +#endif +#ifdef SCR_WORKERS + if (due > now) scr_sa_loop_waiting(true); #endif bool evw = scr_events_watching_fn != NULL && scr_events_watching_fn(); #ifdef SCR_WORKERS @@ -4564,6 +4567,9 @@ static bool scr_loop_run_pass(ScrPromise *top_level, bool first_checkpoint) { now = due; } } +#ifdef SCR_WORKERS + scr_sa_loop_waiting(false); +#endif while (scr_ntimers > 0 && scr_timers[0].deadline_ms <= now) { ScrTimer t = scr_timer_pop(); /* Timer callbacks are plain sync closures, run on the main stack. diff --git a/packages/runtime/src/scr_child.c b/packages/runtime/src/scr_child.c index 184e3be9b..ec685656d 100644 --- a/packages/runtime/src/scr_child.c +++ b/packages/runtime/src/scr_child.c @@ -6410,6 +6410,7 @@ void scr_child_ipc_on_disconnect(ScrChild *c, ScrClosure *cb, bool once) { bool scr_process_ipc_connected(void) { return scr_process_ipc != NULL && scr_process_ipc->connected; } +bool scr_process_ipc_open(void) { return scr_process_ipc != NULL; } bool scr_process_ipc_send(ScrStr *json) { return scr_ipc_send(scr_process_ipc, json, NULL, NULL); } diff --git a/packages/runtime/src/scr_child.h b/packages/runtime/src/scr_child.h index 6492aefe8..f59e02e74 100644 --- a/packages/runtime/src/scr_child.h +++ b/packages/runtime/src/scr_child.h @@ -182,6 +182,9 @@ void scr_child_ipc_on_disconnect(ScrChild *c, ScrClosure *cb /*moves*/, bool once); double scr_process_fork_target(double target_count); bool scr_process_ipc_connected(void); +/* Whether this fork child opened its channel (process.send's presence in + * a program with fork targets; disconnecting keeps it). */ +bool scr_process_ipc_open(void); bool scr_process_ipc_send(ScrStr *json); bool scr_process_ipc_send_cb(ScrStr *json, ScrClosure *cb /*moves*/, ScrIpcSendFn fn); diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index a3d506a10..6fdbbb408 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -937,7 +937,17 @@ double scr_dyn_arr_len(const ScrDyn *d); ScrDyn *scr_dyn_arr_at(const ScrDyn *d, double i); ScrDyn *scr_dyn_arr_named_get(const ScrDyn *d, const ScrStr *key); void scr_dyn_obj_set(ScrDyn *obj, const char *key, size_t key_len, ScrDyn *value); +void scr_dyn_obj_set_field(ScrDyn *obj, const char *key, size_t key_len, ScrDyn *value); ScrDyn *scr_dyn_define_property(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor); +void scr_dyn_class_field_attributes(ScrDyn *view, ScrStr *name, double bits); +void scr_dyn_class_view_attributes(ScrDyn *view, double bits); +ScrDyn *scr_class_define_field(ScrDyn *current, double field_bits, double object_bits, ScrStr *name, + ScrDyn *descriptor); +double scr_class_defined_bits(ScrDyn *holder, ScrStr *name); +ScrDyn *scr_class_defined_value(ScrDyn *holder, ScrStr *name); +bool scr_class_descriptor_has_value(ScrDyn *descriptor); +void scr_class_throw_read_only(ScrStr *field, ScrStr *owner); +void scr_class_throw_not_extensible(ScrStr *field); ScrDyn *scr_dyn_get_own_property_descriptor(ScrDyn *target, ScrDyn *key); ScrDyn *scr_dyn_array_proto_call(ScrDyn *target, ScrStr *method, ScrDyn *args); ScrDyn *scr_dyn_array_prototype(void); /* +1, installs native method adapters */ diff --git a/packages/runtime/src/scr_error.c b/packages/runtime/src/scr_error.c index 6f616c35a..4f514681b 100644 --- a/packages/runtime/src/scr_error.c +++ b/packages/runtime/src/scr_error.c @@ -354,6 +354,12 @@ ScrStr *scr_error_stack(ScrError *e) { return scr_str_retain(e->stack); } +void scr_error_set_stack(ScrError *e, ScrStr *stack) { + ScrStr *replacement = scr_str_retain(stack); + scr_str_release(e->stack); + e->stack = replacement; +} + bool scr_error_is(const void *obj) { const ScrVt *vt = ((const ScrError *)obj)->vt; return scr_error_vts[SCR_ERR_ERROR].pre <= vt->pre && diff --git a/packages/runtime/src/scr_error.h b/packages/runtime/src/scr_error.h index bc64be4d2..a7c921f23 100644 --- a/packages/runtime/src/scr_error.h +++ b/packages/runtime/src/scr_error.h @@ -252,6 +252,9 @@ void scr_error_install_message_reader(ScrStr *(*reader)(ScrError *)); void scr_error_install_name_reader(ScrStr *(*reader)(ScrError *)); ScrStr *scr_error_default_name(const ScrError *e); ScrStr *scr_error_stack(ScrError *e); +/* Replaces the error's stack string, as an assignment to `stack` does. + * Borrowed operands. */ +void scr_error_set_stack(ScrError *e, ScrStr *stack); ScrError *scr_error_retain(ScrError *e); void scr_error_release(ScrError *e); /* dispatches through e->vt */ diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index b8c2accea..ceddf1397 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -1585,8 +1585,12 @@ static void scr_dyn_obj_put(ScrDyn *obj, const char *key, size_t key_len, ScrDyn } if (obj->non_extensible) { scr_dyn_release(value); - static const char message[] = "Cannot add property, object is not extensible"; - scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + ScrJsonBuf buffer; + scr_jb_init(&buffer); + scr_jb_puts(&buffer, "Cannot add property "); + scr_jb_write(&buffer, key, key_len); + scr_jb_puts(&buffer, ", object is not extensible"); + scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&buffer)); return; } if (obj->v.obj.len == obj->v.obj.cap) { @@ -1922,9 +1926,40 @@ ScrDyn *scr_dyn_set_prototype(ScrDyn *object, ScrDyn *prototype) { return scr_dyn_retain(object); } +/* A class instance's integrity state lives in its native layout, which only + * statically typed calls can reach (the compiler adds the state to the + * hierarchies they name). Through an untyped value the operation throws. */ +static bool scr_dyn_class_integrity_fence(const ScrDyn *object, const char *operation) { + if (object->kind != SCR_DYN_TYPED_REF) return false; + ScrJsonBuf buffer; + scr_jb_init(&buffer); + scr_jb_puts(&buffer, operation); + scr_jb_puts(&buffer, " of a class instance held in an untyped value is not supported yet"); + ScrStr *message = scr_jb_finish(&buffer); + scr_throw_error_msg_code(SCR_ERR_ERROR, message->data, message->len, "SC2020"); + scr_str_release(message); + return true; +} + +/* Integrity queries on a class instance answer from its checked view, which + * carries the instance's attributes (scr_dyn_class_view_attributes). */ +static bool scr_dyn_typed_ref_view_answer(ScrDyn *object, bool (*query)(const ScrDyn *), + bool *answer) { + if (object->kind != SCR_DYN_TYPED_REF) return false; + ScrDyn *view = scr_dyn_typed_ref_materialize(object); + *answer = scr_exc_pending() ? false : query(view); + scr_dyn_release(view); + return true; +} + +static bool scr_dyn_is_extensible_view(const ScrDyn *view) { + return (view->kind == SCR_DYN_OBJ || view->kind == SCR_DYN_ARR) && !view->non_extensible; +} + ScrDyn *scr_dyn_prevent_extensions(ScrDyn *object) { if (scr_dyn_class_reflection_fence(object)) return NULL; if (object->kind == SCR_DYN_PROXY) { scr_dyn_proxy_unsupported("Object.preventExtensions"); return NULL; } + if (scr_dyn_class_integrity_fence(object, "Object.preventExtensions")) return NULL; if (object->kind == SCR_DYN_OBJ || object->kind == SCR_DYN_ARR) { object->non_extensible = true; if (object->kind == SCR_DYN_ARR && object->v.arr.properties) @@ -1936,12 +1971,15 @@ ScrDyn *scr_dyn_prevent_extensions(ScrDyn *object) { bool scr_dyn_is_extensible(ScrDyn *object) { if (scr_dyn_class_reflection_fence(object)) return false; if (object->kind == SCR_DYN_PROXY) { scr_dyn_proxy_unsupported("Object.isExtensible"); return false; } - return (object->kind == SCR_DYN_OBJ || object->kind == SCR_DYN_ARR) && !object->non_extensible; + bool answer; + if (scr_dyn_typed_ref_view_answer(object, scr_dyn_is_extensible_view, &answer)) return answer; + return scr_dyn_is_extensible_view(object); } ScrDyn *scr_dyn_seal(ScrDyn *object) { if (scr_dyn_class_reflection_fence(object)) return NULL; if (object->kind == SCR_DYN_PROXY) { scr_dyn_proxy_unsupported("Object.seal"); return NULL; } + if (scr_dyn_class_integrity_fence(object, "Object.seal")) return NULL; if (object->symbol_properties) scr_dyn_release(scr_dyn_seal(object->symbol_properties)); if (object->kind == SCR_DYN_OBJ) { object->non_extensible = true; @@ -1958,6 +1996,8 @@ ScrDyn *scr_dyn_seal(ScrDyn *object) { bool scr_dyn_is_sealed(const ScrDyn *object) { if (scr_dyn_class_reflection_fence(object)) return false; if (object->kind == SCR_DYN_PROXY) { scr_dyn_proxy_unsupported("Object.isSealed"); return false; } + bool answer; + if (scr_dyn_typed_ref_view_answer((ScrDyn *)object, scr_dyn_is_sealed, &answer)) return answer; if (object->symbol_properties && !scr_dyn_is_sealed(object->symbol_properties)) return false; if (object->kind == SCR_DYN_ARR) return object->non_extensible && (object->v.arr.len == 0 || object->v.arr.sealed) && @@ -4316,6 +4356,25 @@ void scr_dyn_obj_set(ScrDyn *obj, const char *key, size_t key_len, ScrDyn *value scr_dyn_obj_put(obj, key, key_len, value); } +/* A class instance's view takes its native field values whatever the + * attributes copied into it (a frozen instance's view is built the same way + * as any other). Consumes value. */ +void scr_dyn_obj_set_field(ScrDyn *obj, const char *key, size_t key_len, ScrDyn *value) { + ScrDynEntry *existing = obj->v.obj.index ? scr_dyn_find_entry(obj, key, key_len) + : scr_dyn_find_linear_entry(obj, key, key_len); + if (existing && !existing->accessor) { + scr_dyn_region_store(obj, value); + ScrDyn *old = existing->value; + existing->value = value; + scr_dyn_release(old); + return; + } + bool non_extensible = obj->non_extensible; + obj->non_extensible = false; + scr_dyn_obj_put(obj, key, key_len, value); + obj->non_extensible = non_extensible; +} + static ScrStr *scr_dyn_property_key(const ScrDyn *key) { return scr_dyn_string_coerce_js(key); } @@ -6178,9 +6237,12 @@ ScrDyn *scr_dyn_define_property(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor) (!accessor && ((!prior->writable && writable) || (!prior->writable && value && !scr_dyn_property_same_value(prior->value, value)))))) { scr_dyn_descriptor_fields_drop(fields); + ScrJsonBuf buffer; + scr_jb_init(&buffer); + scr_jb_puts(&buffer, "Cannot redefine property: "); + scr_jb_write(&buffer, name->data, name->len); scr_str_release(name); - static const char msg[] = "Cannot redefine property"; - scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1); + scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&buffer)); return NULL; } if (prior) { @@ -6360,6 +6422,28 @@ void scr_dyn_throw(ScrDyn *d) { scr_dyn_release(d); return; } + /* A checked-dynamic primitive throws as the primitive itself, as a + * statically typed `throw 5` does: catch bindings test and extract the + * same snapshot kinds (`typeof e === "number"`), and a primitive has no + * identity to keep. */ + if (d->kind == SCR_DYN_NUM) { + double value = d->v.num; + scr_dyn_release(d); + scr_throw_f64(value); + return; + } + if (d->kind == SCR_DYN_BOOL) { + bool value = d->v.b; + scr_dyn_release(d); + scr_throw_bool(value); + return; + } + if (d->kind == SCR_DYN_STR) { + ScrStr *value = scr_str_retain(d->v.str); + scr_dyn_release(d); + scr_throw_str(value); + return; + } scr_throw_ref_classified(d, scr_dyn_retain_v, scr_dyn_release_v, scr_dyn_trace_v, scr_dyn_is_object(d)); } @@ -6793,10 +6877,111 @@ static void scr_errdyn_teardown(void) { free(cache); } +/* An error's own `stack`: a non-enumerable accessor shared by every error, + * as V8 defines it. The getter formats the stack on first access, so its + * heading is the name and message at that point, and later reads answer + * the same string. Both functions find the error through the receiver or + * its prototype chain; on any other receiver the getter answers undefined + * and the setter changes nothing but the receiver's own accessor. */ +static SCR_TL ScrDyn *scr_error_stack_accessors[2]; +static SCR_TL bool scr_error_stack_accessors_registered; + +static void scr_error_stack_accessors_cleanup(void) { + for (size_t i = 0; i < 2; i++) { + scr_dyn_release(scr_error_stack_accessors[i]); + scr_error_stack_accessors[i] = NULL; + } + scr_error_stack_accessors_registered = false; +} + +/* The native error behind an accessor receiver. +1 or NULL. */ +static ScrError *scr_error_stack_holder(const ScrDyn *receiver) { + for (const ScrDyn *current = receiver; current; current = scr_dyn_proto_next(current)) { + ScrError *error = scr_errdyn_err_of(current); + if (error) return error; + if (current->kind != SCR_DYN_OBJ) return NULL; + } + return NULL; +} + +static ScrDyn *scr_error_stack_get_call(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; (void)args; (void)argc; + ScrDyn *self = scr_dyn_this_get(); + ScrError *error = scr_error_stack_holder(self); + scr_dyn_release(self); + if (!error) return scr_dyn_retain(scr_dyn_undefined()); + ScrStr *stack = scr_error_stack(error); + scr_error_release(error); + /* A name or message getter that throws leaves its exception pending. */ + if (!stack) return NULL; + ScrDyn *out = scr_dyn_new_str(stack); + scr_str_release(stack); + return out; +} + +static ScrDyn *scr_error_stack_set_call(ScrClosure *closure, ScrDyn *const *args, size_t argc); + +/* Whether an own property is an error's `stack` accessor. */ +static bool scr_dyn_entry_is_error_stack(const ScrDynEntry *entry) { + return entry->accessor && entry->setter && entry->setter->kind == SCR_DYN_FUNC && + entry->setter->v.fn.thunk == scr_error_stack_set_call; +} + +static ScrDyn *scr_error_stack_set_call(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + ScrDyn *self = scr_dyn_this_get(); + ScrError *error = scr_error_stack_holder(self); + ScrDyn *value = argc > 0 ? args[0] : scr_dyn_undefined(); + if (error && value->kind == SCR_DYN_STR) { + scr_error_set_stack(error, value->v.str); + } else if (self->kind == SCR_DYN_OBJ) { + /* The native slot holds strings only, and a typed reference's + * snapshot names no error: the receiver's own accessor becomes a data + * property holding the value, which a snapshot's commit stores. */ + ScrStr *key = scr_str_new("stack", 5); + ScrDynEntry *entry = scr_dyn_entry(self, key); + scr_str_release(key); + if (entry && scr_dyn_entry_is_error_stack(entry)) { + ScrDyn *old_value = entry->value, *old_getter = entry->getter, *old_setter = entry->setter; + entry->value = scr_dyn_retain(value); + entry->getter = entry->setter = NULL; + entry->accessor = false; + entry->writable = true; + scr_dyn_release(old_value); + scr_dyn_release(old_getter); + scr_dyn_release(old_setter); + } + } + scr_error_release(error); + scr_dyn_release(self); + return scr_dyn_retain(scr_dyn_undefined()); +} + +static void scr_error_dyn_add_stack(ScrDyn *d) { + if (!scr_error_stack_accessors_registered) { + scr_error_stack_accessors_registered = true; + scr_atexit(scr_error_stack_accessors_cleanup); + } + if (!scr_error_stack_accessors[0]) { + scr_error_stack_accessors[0] = + scr_dyn_new_func(scr_closure_new(NULL, 0), scr_error_stack_get_call, 0, "native:error.stack", NULL); + scr_error_stack_accessors[1] = + scr_dyn_new_func(scr_closure_new(NULL, 0), scr_error_stack_set_call, 1, "native:error.stack", NULL); + } + scr_dyn_obj_set(d, "stack", 5, scr_dyn_retain(scr_dyn_undefined())); + ScrDynEntry *entry = &d->v.obj.entries[d->v.obj.len - 1]; + entry->accessor = true; + entry->getter = scr_dyn_retain(scr_error_stack_accessors[0]); + entry->setter = scr_dyn_retain(scr_error_stack_accessors[1]); + entry->enumerable = false; +} + ScrDyn *scr_error_dyn_fields(const ScrError *e) { ScrDyn *d = scr_dyn_new_obj(); scr_dyn_obj_set(d, "%error", 6, scr_dyn_new_bool(true)); /* the checked-dynamic tree's error marker */ d->v.obj.entries[d->v.obj.len - 1].enumerable = false; + /* Node lists `stack` first among an error's own properties. */ + scr_error_dyn_add_stack(d); if (e->name_present) { scr_dyn_obj_set(d, "name", 4, scr_dyn_new_str(e->name)); d->v.obj.entries[d->v.obj.len - 1].enumerable = e->name_enumerable; @@ -6818,11 +7003,6 @@ ScrDyn *scr_error_dyn_fields(const ScrError *e) { scr_dyn_obj_set(d, "message", 7, scr_dyn_new_str(e->message)); d->v.obj.entries[d->v.obj.len - 1].enumerable = e->message_enumerable; } - if (e->stack) { - /* Node's own `stack` is non-enumerable. */ - scr_dyn_obj_set(d, "stack", 5, scr_dyn_new_str(e->stack)); - d->v.obj.entries[d->v.obj.len - 1].enumerable = false; - } if (e->system_message) { /* SystemError: code, the read-only `info` context ({ message, path, * syscall, errno, code }), then errno, syscall, path and dest. */ @@ -10964,6 +11144,17 @@ static ScrDyn *scr_sc_clone(const ScrDyn *v, const ScrScParent *up, ScrDynRegion ScrDyn *out = scr_dyn_new_obj(); for (size_t i = 0; i < v->v.obj.len; i++) { const ScrDynEntry *e = &v->v.obj.entries[i]; + if (scr_dyn_entry_is_error_stack(e)) { + /* A stack that was already formatted copies as a non-enumerable + * data property; an unformatted one has nothing to copy. */ + ScrError *error = scr_errdyn_err_of(v); + if (error && error->stack) { + scr_dyn_obj_set(out, "stack", 5, scr_dyn_new_str(error->stack)); + out->v.obj.entries[out->v.obj.len - 1].enumerable = false; + } + scr_error_release(error); + continue; + } ScrDyn *c = scr_sc_clone(e->value, &self, region); if (c == NULL) { scr_dyn_release(out); @@ -11487,7 +11678,20 @@ ScrDyn *scr_dyn_get_own_property_names(const ScrDyn *value) { scr_dyn_release(table); return out; } - if (value->kind == SCR_DYN_OBJ) return scr_dyn_obj_own_keys(value); + if (value->kind == SCR_DYN_OBJ) { + ScrDyn *keys = scr_dyn_obj_own_keys(value); + if (!scr_dyn_obj_get(value, "%error", 6)) return keys; + /* The checked-dynamic tree's error marker is not a property. */ + ScrDyn *names = scr_dyn_new_arr(); + scr_dyn_arr_reserve(names, keys->v.arr.len); + for (size_t i = 0; i < keys->v.arr.len; i++) { + const ScrStr *key = keys->v.arr.items[i]->v.str; + if (key->len == 6 && memcmp(key->data, "%error", 6) == 0) continue; + scr_dyn_arr_push(names, scr_dyn_retain(keys->v.arr.items[i])); + } + scr_dyn_release(keys); + return names; + } if (value->kind == SCR_DYN_ARR || value->kind == SCR_DYN_STR || value->kind == SCR_DYN_BYTES) { ScrDyn *keys = scr_dyn_new_arr(); size_t length = value->kind == SCR_DYN_ARR ? value->v.arr.len : @@ -14069,6 +14273,7 @@ ScrStr *scr_dyn_to_string_method(const ScrDyn *d, const ScrStr *enc, const ScrSt ScrDyn *scr_dyn_freeze(ScrDyn *value) { if (scr_dyn_class_reflection_fence(value)) return NULL; + if (scr_dyn_class_integrity_fence(value, "Object.freeze")) return NULL; if (value->symbol_properties) scr_dyn_release(scr_dyn_freeze(value->symbol_properties)); if (value->kind == SCR_DYN_ARR) { value->non_extensible = true; @@ -14096,6 +14301,8 @@ ScrDyn *scr_dyn_freeze(ScrDyn *value) { bool scr_dyn_is_frozen(const ScrDyn *value) { if (scr_dyn_class_reflection_fence(value)) return false; + bool answer; + if (scr_dyn_typed_ref_view_answer((ScrDyn *)value, scr_dyn_is_frozen, &answer)) return answer; if (value->symbol_properties && !scr_dyn_is_frozen(value->symbol_properties)) return false; if (value->kind == SCR_DYN_ARR) return scr_dyn_is_sealed(value) && (value->v.arr.len == 0 || value->v.arr.frozen) && @@ -14150,6 +14357,130 @@ ScrDyn *scr_caught_to_dyn(const ScrCaught *c) { } } +/* ── class instance attributes ─────────────────────────────────────────── + * A hierarchy passed to Object.freeze, Object.seal, Object.preventExtensions + * or Object.defineProperty keeps an integrity state per instance and an + * attribute word per redefined field (CLASS_* and FIELD_* bits in the + * compiler's ir.ts). The checked view of an instance carries them, so + * reflection over the view answers as Node does. */ +enum { + SCR_CLASS_NOT_EXTENSIBLE = 1, + SCR_CLASS_SEALED = 2, + SCR_CLASS_FROZEN = 4, + SCR_FIELD_NOT_WRITABLE = 1, + SCR_FIELD_NOT_ENUMERABLE = 2, + SCR_FIELD_NOT_CONFIGURABLE = 4, +}; + +void scr_dyn_class_field_attributes(ScrDyn *view, ScrStr *name, double bits) { + unsigned b = (unsigned)bits; + if (b == 0 || view->kind != SCR_DYN_OBJ) return; + ScrDynEntry *entry = scr_dyn_entry(view, name); + if (!entry) return; + if (b & SCR_FIELD_NOT_WRITABLE) entry->writable = false; + if (b & SCR_FIELD_NOT_ENUMERABLE) entry->enumerable = false; + if (b & SCR_FIELD_NOT_CONFIGURABLE) entry->configurable = false; +} + +void scr_dyn_class_view_attributes(ScrDyn *view, double bits) { + unsigned b = (unsigned)bits; + if (b == 0 || view->kind != SCR_DYN_OBJ) return; + view->non_extensible = true; + for (size_t i = 0; i < view->v.obj.len; i++) { + ScrDynEntry *entry = &view->v.obj.entries[i]; + if (b & (SCR_CLASS_SEALED | SCR_CLASS_FROZEN)) entry->configurable = false; + if ((b & SCR_CLASS_FROZEN) && !entry->accessor) entry->writable = false; + } +} + +/* Object.defineProperty on a declared class field. The descriptor applies to + * a one-property object holding the field's current value and attributes, + * so validation and errors match ordinary objects. Answers that object (+1), + * or NULL with a pending exception. */ +ScrDyn *scr_class_define_field(ScrDyn *current, double field_bits, double object_bits, ScrStr *name, + ScrDyn *descriptor) { + unsigned f = (unsigned)field_bits, o = (unsigned)object_bits; + ScrDyn *holder = scr_dyn_new_obj(); + scr_dyn_obj_set(holder, name->data, name->len, scr_dyn_retain(current)); + ScrDynEntry *entry = scr_dyn_entry(holder, name); + entry->writable = !(f & SCR_FIELD_NOT_WRITABLE) && !(o & SCR_CLASS_FROZEN); + entry->enumerable = !(f & SCR_FIELD_NOT_ENUMERABLE); + entry->configurable = + !(f & SCR_FIELD_NOT_CONFIGURABLE) && !(o & (SCR_CLASS_SEALED | SCR_CLASS_FROZEN)); + ScrDyn *key = scr_dyn_new_str(name); + ScrDyn *defined = scr_dyn_define_property(holder, key, descriptor); + scr_dyn_release(key); + if (!defined) { + scr_dyn_release(holder); + return NULL; + } + scr_dyn_release(defined); + entry = scr_dyn_entry(holder, name); + if (entry->accessor) { + scr_dyn_release(holder); + ScrJsonBuf buffer; + scr_jb_init(&buffer); + scr_jb_puts(&buffer, "Object.defineProperty with an accessor descriptor for the declared field '"); + scr_jb_write(&buffer, name->data, name->len); + scr_jb_puts(&buffer, "' is not supported yet"); + ScrStr *message = scr_jb_finish(&buffer); + scr_throw_error_msg_code(SCR_ERR_ERROR, message->data, message->len, "SC2020"); + scr_str_release(message); + return NULL; + } + return holder; +} + +/* The field attribute word of a scr_class_define_field result. */ +double scr_class_defined_bits(ScrDyn *holder, ScrStr *name) { + const ScrDynEntry *entry = scr_dyn_entry(holder, name); + unsigned bits = 0; + if (!entry->writable) bits |= SCR_FIELD_NOT_WRITABLE; + if (!entry->enumerable) bits |= SCR_FIELD_NOT_ENUMERABLE; + if (!entry->configurable) bits |= SCR_FIELD_NOT_CONFIGURABLE; + return (double)bits; +} + +/* The value a scr_class_define_field result holds (+1). */ +ScrDyn *scr_class_defined_value(ScrDyn *holder, ScrStr *name) { + return scr_dyn_retain(scr_dyn_entry(holder, name)->value); +} + +/* Whether a property descriptor names a value (Node's ToPropertyDescriptor + * reads `value` with [[HasProperty]]). */ +bool scr_class_descriptor_has_value(ScrDyn *descriptor) { + if (descriptor->kind == SCR_DYN_TYPED_REF) { + ScrDyn *view = scr_dyn_typed_ref_materialize(descriptor); + bool has = !scr_exc_pending() && scr_class_descriptor_has_value(view); + scr_dyn_release(view); + return has; + } + return descriptor->kind == SCR_DYN_OBJ && scr_dyn_obj_get(descriptor, "value", 5) != NULL; +} + +/* Node's TypeError for a write to a read-only field of a class instance. */ +void scr_class_throw_read_only(ScrStr *field, ScrStr *owner) { + ScrJsonBuf buffer; + scr_jb_init(&buffer); + scr_jb_puts(&buffer, "Cannot assign to read only property '"); + scr_jb_write(&buffer, field->data, field->len); + scr_jb_puts(&buffer, "' of object '#<"); + scr_jb_write(&buffer, owner->data, owner->len); + scr_jb_puts(&buffer, ">'"); + scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&buffer)); +} + +/* Node's TypeError for a class field initializer on a non-extensible + * instance (a base constructor froze or sealed `this`). */ +void scr_class_throw_not_extensible(ScrStr *field) { + ScrJsonBuf buffer; + scr_jb_init(&buffer); + scr_jb_puts(&buffer, "Cannot define property "); + scr_jb_write(&buffer, field->data, field->len); + scr_jb_puts(&buffer, ", object is not extensible"); + scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&buffer)); +} + /* ── compiled generators through untyped values ─────────────────────── */ static SCR_TL ScrDyn *scr_generator_next_getter; diff --git a/packages/runtime/src/scr_lib.c b/packages/runtime/src/scr_lib.c index bd7d599ce..2e6f35f67 100644 --- a/packages/runtime/src/scr_lib.c +++ b/packages/runtime/src/scr_lib.c @@ -2037,6 +2037,19 @@ double scr_process_exit_code_or_zero(void) { return (double)scr_exit_code_hint_get(); } +static SCR_TL bool scr_exit_code_assigned = false; + +void scr_process_set_exit_code_tracked(double code) { + int converted; + if (!scr_process_exit_code_of(code, &converted)) return; + scr_exit_code_note(converted); + scr_exit_code_assigned = true; +} + +bool scr_process_has_exit_code(void) { + return scr_exit_code_assigned || scr_exit_code_hint_get() != 0; +} + #if defined(__linux__) #include #include diff --git a/packages/runtime/src/scr_lib.h b/packages/runtime/src/scr_lib.h index 4b1094d54..bae678292 100644 --- a/packages/runtime/src/scr_lib.h +++ b/packages/runtime/src/scr_lib.h @@ -149,6 +149,11 @@ void scr_process_exit(double code); extern const unsigned char scr_detached_exit; void scr_process_set_exit_code(double code); double scr_process_exit_code_or_zero(void); +/* The writer and the presence test of programs that read process.exitCode: + * the code reads undefined until an assignment (or a nonzero exit status + * the runtime chose, such as an uncaught exception's 1). */ +void scr_process_set_exit_code_tracked(double code); +bool scr_process_has_exit_code(void); /* process._exiting: true once the exit sequence began (process.exit or * the exit-listener runner set the flag). Never throws. */ extern SCR_TL bool scr_process_in_exit; diff --git a/packages/runtime/src/scr_message.c b/packages/runtime/src/scr_message.c index 1d01e5573..374b5469a 100644 --- a/packages/runtime/src/scr_message.c +++ b/packages/runtime/src/scr_message.c @@ -810,6 +810,12 @@ ScrDyn *scr_message_decode(const ScrMessage *message) { } if (!values[i]->v.arr.properties) values[i]->v.arr.properties = scr_dyn_new_obj(); scr_dyn_obj_set(values[i]->v.arr.properties, property->key, property->length, value); + } else if (node->kind == SCR_MESSAGE_ERROR && property->length == 5 && !memcmp(property->key, "stack", 5)) { + /* The new error's own `stack` accessor stores the value. */ + ScrStr *key = scr_str_new(property->key, property->length); + scr_dyn_key_set(values[i], key, value); + scr_str_release(key); + scr_dyn_release(value); } else scr_dyn_obj_set(values[i], property->key, property->length, value); } if (node->kind == SCR_MESSAGE_ERROR) { diff --git a/packages/runtime/src/scr_rc.h b/packages/runtime/src/scr_rc.h index eb28fb2e7..8611741da 100644 --- a/packages/runtime/src/scr_rc.h +++ b/packages/runtime/src/scr_rc.h @@ -352,6 +352,10 @@ void scr_sa_thread_starting(void); * pointer, or a process-wide cache keeps an immortal object. Its memory * then stays when it exits (scr_alloc.c). */ void scr_sa_thread_shares(void); +/* The event loop of the calling thread is about to wait with nothing ready + * (true), or is done waiting (false); worker threads are ignored. The + * memory of parked workers goes back while the loop waits (scr_alloc.c). */ +void scr_sa_loop_waiting(bool waiting); #define SCR_SA_FREE_FOREIGN(p) scr_sa_free_foreign(p) #else #define SCR_SA_FREE_FOREIGN(p) free(p) diff --git a/tests/corpus/5467-typed-array-loop-versions.ts b/tests/corpus/5467-typed-array-loop-versions.ts new file mode 100644 index 000000000..35a1da145 --- /dev/null +++ b/tests/corpus/5467-typed-array-loop-versions.ts @@ -0,0 +1,298 @@ +// Typed-array loops whose accesses are proved in bounds by one test before +// the loop run without per-element checks; every other entry runs the +// checked loop. Both must keep JavaScript's exact out-of-bounds behavior: +// reads of missing elements are undefined (NaN in arithmetic), writes are +// ignored, DataView accesses throw at the failing iteration, and +// fractional, negative and NaN indices never touch storage. + +const table: Int32Array = new Int32Array(256); +for (let n = 0; n < 256; n++) table[n] = (n * 2654435761) | 0; +const shortTable: Int32Array = new Int32Array(100); +for (let n = 0; n < 100; n++) shortTable[n] = n + 1; + +function masked(t: Int32Array, data: Uint8Array): number { + let h = 0; + for (let i = 0; i < data.length; i++) h = (h ^ t[(h ^ data[i]) & 0xff]) | 0; + return h; +} + +function maskedWrite(t: Int32Array, count: number): void { + for (let i = 0; i < count; i++) t[(i * 7) & 0xff] = i; +} + +const data = new Uint8Array(64); +for (let i = 0; i < data.length; i++) data[i] = (i * 37 + 11) & 0xff; +console.log("masked full", masked(table, data)); +console.log("masked short", masked(shortTable, data)); +const writable = new Int32Array(200); +maskedWrite(writable, 300); +console.log("masked write", writable[0], writable[7], writable[199], writable.length); + +// Counter plus an invariant base, in bounds and running off either end. +function shifted(src: Float64Array, out: Float64Array, base: number, n: number): number { + let sum = 0; + for (let i = 0; i < n; i++) { + out[base + i] = src[i] * 2; + sum += src[base + i - 1]; + } + return sum; +} + +const src = new Float64Array(8); +for (let i = 0; i < 8; i++) src[i] = i + 0.25; +for (const [base, n] of [ + [1, 4], + [0, 8], + [5, 8], + [-3, 6], + [2, 0], + [3, 2.5], +]) { + const out = new Float64Array(8); + const sum = shifted(src, out, base, n); + console.log("shifted", base, n, sum, Array.from(out).join(",")); +} + +// Descending loops, including ones that walk below zero. +function descending(a: Uint16Array, low: number): number { + let sum = 0; + for (let i = a.length - 1; i >= low; i--) { + a[i] = a[i] + 1000; + sum += a[i]; + } + return sum; +} +const u16 = new Uint16Array([65000, 1, 2, 3]); +console.log("descending", descending(u16, 0), Array.from(u16).join(",")); +console.log("descending below", descending(u16, -2), Array.from(u16).join(",")); + +// Fractional starts and offsets never name an element. +function fractional(a: Float32Array): string { + const seen: string[] = []; + for (let i = 0.5; i < 3; i++) seen.push(String(a[i])); + for (let i = 0; i < 3; i++) { + a[i + 0.5] = 99; + seen.push(String(a[i] + a[i - 0.5])); + } + return seen.join(" "); +} +console.log("fractional", fractional(new Float32Array([1.5, 2.5, 3.5]))); + +function nanIndex(a: Int8Array, offset: number): number { + let sum = 0; + for (let i = 0; i < a.length; i++) { + a[i + offset] = 120; + sum += a[i + offset] | 0; + } + return sum; +} +const i8 = new Int8Array([1, 2, 3]); +console.log("nan index", nanIndex(i8, NaN), nanIndex(i8, -0), Array.from(i8).join(",")); + +// Unproven limits keep the integer loop's guard: huge, infinite and NaN. +function limits(a: Uint8Array, limit: number): number { + let sum = 0; + for (let i = 0; i < limit; i++) { + if (i >= a.length + 2) break; + sum += a[i] | 0; + a[i] = i; + } + return sum; +} +const lim = new Uint8Array([5, 6, 7]); +console.log("limits", limits(lim, 2), limits(lim, 1e300), limits(lim, Infinity), limits(lim, NaN)); + +// A DataView access past the end throws after the earlier iterations ran. +const viewProgress: number[] = [0]; +function viewLoop(view: DataView, n: number): number { + let sum = 0; + for (let i = 0; i < n; i++) { + sum += view.getUint32(i * 4, true) + view.getUint8(i * 4 + 3); + viewProgress[0] = sum; + } + return sum; +} +function viewSum(view: DataView, n: number): number { + viewProgress[0] = -1; + try { + return viewLoop(view, n); + } catch (e) { + console.log("view throw", (e as Error).name, viewProgress[0]); + } + return viewProgress[0]; +} +const dvBytes = new Uint8Array(16); +for (let i = 0; i < 16; i++) dvBytes[i] = i * 3; +const view = new DataView(dvBytes.buffer); +console.log("view ok", viewSum(view, 4)); +console.log("view partial", viewSum(view, 6)); + +// Strided loops: the last counter value of a non-unit step is exact, so a +// record that ends at the last element still takes the unchecked loop and +// a partial trailing record does not. +function quads(words: Uint16Array): number { + let sum = 0; + for (let i = 0; i < words.length; i += 4) sum += words[i] + words[i + 3] * 2; + return sum; +} +console.log("quads", quads(new Uint16Array([1, 2, 3, 4, 5, 6, 7, 8]))); +console.log("quads partial", quads(new Uint16Array([1, 2, 3, 4, 5, 6]))); +function backTriples(words: Uint16Array): number { + let sum = 0; + for (let i = words.length - 1; i >= 0; i -= 3) sum = sum * 3 + words[i] + (words[i - 2] | 0); + return sum; +} +console.log("back triples", backTriples(new Uint16Array([1, 2, 3, 4, 5, 6]))); +console.log("back triples partial", backTriples(new Uint16Array([1, 2, 3, 4, 5, 6, 7]))); +function scaled(words: Uint16Array, n: number): number { + let sum = 0; + for (let i = 0; i < n; i++) sum += words[i * 2] - (words[(i + 1) * 2 - 1] | 0) + (words[9 - i] | 0); + return sum; +} +const scaledWords = new Uint16Array(10); +for (let i = 0; i < 10; i++) scaledWords[i] = i * i; +console.log("scaled", scaled(scaledWords, 5), scaled(scaledWords, 6), scaled(scaledWords, 11)); +// A negative zero index names element 0 and stays -0 as a number. +function negativeZero(words: Uint16Array, n: number): string { + const seen: string[] = []; + for (let i = 0; i < n; i++) { + const k = i * -1; + const m = (i - 1) * 2; + seen.push(`${words[k]}:${Object.is(k, -0)}:${words[m] | 0}:${Object.is(m, -0)}`); + } + return seen.join(" "); +} +console.log("negative zero", negativeZero(scaledWords, 3)); + +// Clamped and wrapping element types on the unchecked path. +function convert(c: Uint8ClampedArray, s: Int16Array): string { + for (let i = 0; i < 4; i++) { + c[i] = i * 100 - 50.5; + s[i] = i * 20000; + } + return Array.from(c).join(",") + " " + Array.from(s).join(","); +} +console.log("convert", convert(new Uint8ClampedArray(4), new Int16Array(4))); + +// Module receivers stay correct across calls in the loop body, including a +// call that writes the same arrays. +const left: Float64Array = new Float64Array(16); +const right: Float64Array = new Float64Array(16); +function poke(k: number): number { + right[k] = right[k] + 1; + return k; +} +for (let i = 0; i < 16; i++) left[i] = i; +let crossed = 0; +for (let i = 0; i < 16; i++) { + right[i] = left[i] * 3; + crossed += right[poke(i)]; +} +console.log("module receivers", crossed, right[0], right[15]); + +// A body that reassigns its receiver keeps reading the current binding. +function rebinding(first: Uint8Array, second: Uint8Array): number { + let current = first; + let sum = 0; + for (let i = 0; i < 4; i++) { + sum += current[i] | 0; + if (i === 1) current = second; + } + return sum; +} +console.log("rebinding", rebinding(new Uint8Array([1, 2, 3, 4]), new Uint8Array([10, 20]))); + +// A throwing body leaves the writes of earlier iterations in place. +function failing(a: Uint32Array, at: number): void { + for (let i = 0; i < a.length; i++) { + if (i === at) throw new Error("stop at " + i); + a[i] = 4294967295 - i; + } +} +const u32 = new Uint32Array(5); +try { + failing(u32, 3); +} catch (e) { + console.log((e as Error).message, Array.from(u32).join(",")); +} + +// An outer loop proved in bounds around an inner loop that is not. +function nested(grid: Int32Array, w: number, h: number): number { + let sum = 0; + for (let y = 0; y < h; y++) { + sum += grid[y & 7]; + for (let x = 0; x < w; x++) { + grid[y * w + x] = grid[y * w + x] + 1; + sum += grid[y * w + x] | 0; + } + } + return sum; +} +const grid = new Int32Array(16); +console.log("nested", nested(grid, 4, 4), nested(grid, 5, 4), nested(grid, 4, 5), grid.join(",")); + +// A matrix product over module-level constant arrays. +const N = 6; +const ma: Float64Array = new Float64Array(N * N); +const mb: Float64Array = new Float64Array(N * N); +const mc: Float64Array = new Float64Array(N * N); +for (let i = 0; i < N * N; i++) { + ma[i] = (i % 7) - 3; + mb[i] = (i % 5) * 0.5; +} +for (let i = 0; i < N; i++) { + for (let k = 0; k < N; k++) { + const aik = ma[i * N + k]; + const kOff = k * N; + const iOff = i * N; + for (let j = 0; j < N; j++) mc[iOff + j] += aik * mb[kOff + j]; + } +} +let trace = 0; +for (let i = 0; i < N; i++) trace += mc[i * N + i]; +console.log("matmul", trace, mc[1], mc[N * N - 1]); + +// Float16Array elements are two bytes; versioned loops bound them in +// elements, and stores round to nearest-even in the unchecked copy too. +function halves(src: Float16Array, out: Float16Array, n: number): number { + let sum = 0; + for (let i = 0; i < n; i++) { + out[i] = src[i + 1] * 1.001 + 0.1; + sum += src[i]; + } + return sum; +} +const halfSrc = new Float16Array(10); +for (let i = 0; i < halfSrc.length; i++) halfSrc[i] = i * 0.3 - 1; +const halfOut = new Float16Array(10); +console.log("f16 in bounds", halves(halfSrc, halfOut, 9), Array.from(halfOut).join(",")); +console.log("f16 past end", halves(halfSrc, halfOut, 12), Array.from(halfOut).join(",")); +const halfShort = new Float16Array(4); +console.log("f16 short out", halves(halfSrc, halfShort, 9), Array.from(halfShort).join(",")); +console.log("f16 rounding", halves(new Float16Array([65519, 2049, 1e-8, 0]), new Float16Array(3), 3)); + +function halfTable(t: Float16Array, n: number): number { + let sum = 0; + for (let i = 0; i < n; i++) sum += t[i & 7]; + return sum; +} +console.log("f16 masked", halfTable(new Float16Array([0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5]), 20)); +console.log("f16 masked short", halfTable(new Float16Array([0.5, 1.5, 2.5, 3.5, 4.5]), 20)); + +// DataView half-precision accesses are two bytes wide: the last odd offset +// throws. +function halfView(v: DataView, n: number): number { + let sum = 0; + for (let i = 0; i < n; i++) { + v.setFloat16(i * 2, i + 0.25, true); + sum += v.getFloat16(i * 2 + 1, false); + } + return sum; +} +const halfBytes = new DataView(new ArrayBuffer(11)); +console.log("f16 view", halfView(halfBytes, 4)); +try { + halfView(halfBytes, 6); +} catch (e) { + console.log((e as Error).message, new Uint8Array(halfBytes.buffer).join(",")); +} diff --git a/tests/corpus/5468-typed-array-loop-aliasing.ts b/tests/corpus/5468-typed-array-loop-aliasing.ts new file mode 100644 index 000000000..019913d1c --- /dev/null +++ b/tests/corpus/5468-typed-array-loop-aliasing.ts @@ -0,0 +1,107 @@ +// Element stores may alias any other view of the same buffer, whatever its +// element type, offset or length, but never a typed array's own length and +// data pointer. Loops that write through one view and read through another +// must observe every store in program order, also when the loop runs +// without per-element bounds checks. + +const buffer = new ArrayBuffer(64); +const f64 = new Float64Array(buffer); +const u8 = new Uint8Array(buffer); +const i32 = new Int32Array(buffer, 8, 8); + +// Writes through Float64Array observed through a Uint8Array in the same +// iteration. +let topBytes = 0; +for (let i = 0; i < f64.length; i++) { + f64[i] = -(i + 1) * 1.5; + topBytes += u8[i * 8 + 7]; +} +console.log("f64 then u8", topBytes, u8[7], u8[63]); + +// Byte stores observed through an overlapping Int32Array window. +let words = 0; +for (let i = 0; i < 32; i++) { + u8[8 + i] = i + 1; + words = (words + i32[i >> 2]) | 0; +} +console.log("u8 then i32", words, i32[0], i32[7]); + +// A shifted subarray reads what the previous iteration wrote: a prefix +// recurrence that any reordering or vector widening would break. +const chain = new Uint8Array(40); +chain[0] = 1; +const ahead = chain.subarray(1); +for (let i = 0; i < ahead.length; i++) ahead[i] = chain[i] + 2; +console.log("recurrence", chain[0], chain[1], chain[20], chain[39]); + +// Overlapping copies in both directions. +const values = new Int16Array(12); +for (let i = 0; i < values.length; i++) values[i] = i * 10; +const lower = values.subarray(0, 11); +const upper = values.subarray(1); +for (let i = 0; i < lower.length; i++) lower[i] = upper[i]; +console.log("copy down", Array.from(values).join(",")); +for (let i = 0; i < values.length; i++) values[i] = i * 10; +for (let i = 0; i < lower.length; i++) upper[i] = lower[i]; +console.log("copy up", Array.from(values).join(",")); + +// Same-array accumulation with a lagging read. +function lagged(a: Float64Array, lag: number): number { + for (let i = lag; i < a.length; i++) a[i] = a[i] + a[i - lag]; + return a[a.length - 1]; +} +const fib = new Float64Array(30); +fib[0] = 1; +fib[1] = 1; +console.log("lagged", lagged(fib, 1), lagged(fib, 2)); + +// Two parameters that are the same array, and a destination that aliases +// part of its own source. +function axpy(alpha: number, x: Float64Array, y: Float64Array, n: number): void { + for (let i = 0; i < n; i++) y[i] = y[i] + alpha * x[i]; +} +const same = new Float64Array([1, 2, 3, 4, 5, 6, 7, 8]); +axpy(2, same, same, same.length); +console.log("axpy same", Array.from(same).join(",")); +const whole = new Float64Array([1, 2, 3, 4, 5, 6, 7, 8]); +axpy(1, whole, whole.subarray(2), 6); +console.log("axpy shifted", Array.from(whole).join(",")); + +// Element stores never change a length or a module binding, even when a +// float store writes the bit pattern of a small length. +const meta: Float64Array = new Float64Array(4); +const lengths: number[] = []; +for (let i = 0; i < 4; i++) { + meta[i] = 5e-324 * (i + 1); + lengths.push(meta.length); +} +console.log("lengths", lengths.join(","), meta[3] > 0); + +// Global numbers next to typed-array stores keep their values. +let scale = 3; +const scaled: Float32Array = new Float32Array(6); +for (let i = 0; i < scaled.length; i++) { + scaled[i] = scale * i; + if (i === 2) scale = 0.5; +} +console.log("scaled", Array.from(scaled).join(",")); + +// Half-precision stores observed through integer views of the same buffer +// in the same iteration, and byte stores observed through Float16Array. +const halfBuffer = new ArrayBuffer(32); +const f16 = new Float16Array(halfBuffer); +const u16 = new Uint16Array(halfBuffer); +const halfBytes = new Uint8Array(halfBuffer); +let bits = 0; +for (let i = 0; i < f16.length; i++) { + f16[i] = (i - 8) * 0.75; + bits = (bits + u16[i]) | 0; +} +console.log("f16 then u16", bits, u16[0], u16[15]); +let halfSum = 0; +for (let i = 0; i < f16.length; i++) { + halfBytes[i * 2 + 1] = 0x3c + (i & 3); + halfBytes[i * 2] = i; + halfSum += f16[i]; +} +console.log("u8 then f16", halfSum, f16[0], f16[15]); diff --git a/tests/corpus/5469-typed-array-loop-initializer-rebinding.ts b/tests/corpus/5469-typed-array-loop-initializer-rebinding.ts new file mode 100644 index 000000000..f899b9d07 --- /dev/null +++ b/tests/corpus/5469-typed-array-loop-initializer-rebinding.ts @@ -0,0 +1,46 @@ +// A typed-array loop whose initializer rebinds the array it indexes: the +// bounds the loop relies on belong to the array the initializer installs, +// so reads past the shorter replacement are undefined (NaN in arithmetic) +// and writes past it are ignored, as in JavaScript. + +function sumAfterRebinding(data: Uint8Array, replacement: Uint8Array, n: number): number { + let total = 0; + for (let i = ((data = replacement), 0); i < n; i++) total += data[i]; + return total; +} + +function fillAfterRebinding(data: Int32Array, replacement: Int32Array, n: number): Int32Array { + for (let i = ((data = replacement), 0); i < n; i++) data[i] = i + 1; + return data; +} + +// The initializer assigns the receiver without declaring the counter. +function countAfterAssignment(data: Float64Array, replacement: Float64Array, n: number): number { + let i: number; + let total = 0; + for (data = replacement, i = 0; i < n; i++) total += data[i]; + return total; +} + +const long = new Uint8Array(64).fill(1); +const short = new Uint8Array(4).fill(2); +console.log("sum", sumAfterRebinding(long, short, 64)); +console.log("sum in bounds", sumAfterRebinding(long, short, 4)); + +const target = new Int32Array(64); +const small = new Int32Array(3); +const filled = fillAfterRebinding(target, small, 64); +console.log("fill", filled.length, Array.from(filled).join(","), target[0], target[63]); + +const wide = new Float64Array(32).fill(0.5); +const narrow = new Float64Array(2).fill(4); +console.log("count", countAfterAssignment(wide, narrow, 32)); +console.log("count in bounds", countAfterAssignment(wide, narrow, 2)); + +// A loop whose initializer leaves the receiver alone still runs normally. +function plainSum(data: Uint8Array, n: number): number { + let total = 0; + for (let i = 0; i < n; i++) total += data[i]; + return total; +} +console.log("plain", plainSum(long, 64), plainSum(short, 6)); diff --git a/tests/corpus/5816-fixed-into-unknown-rest.ts b/tests/corpus/5816-fixed-into-unknown-rest.ts new file mode 100644 index 000000000..f6d287021 --- /dev/null +++ b/tests/corpus/5816-fixed-into-unknown-rest.ts @@ -0,0 +1,39 @@ +// A function with only `unknown` parameters, or none, flows into a +// `(...args: unknown[]) => R` slot: each call passes the callers' +// arguments in order, undefined for a parameter the caller left out, and +// drops the extra ones, as JS calls do. Sync and async functions, stored +// in variables and arrays and passed as arguments. +type Handler = (...args: unknown[]) => void; +type AsyncHandler = (...args: unknown[]) => Promise; + +const none: Handler = () => console.log("none"); +const one: Handler = (a: unknown) => console.log("one", a); +const two: Handler = (a: unknown, b: unknown) => console.log("two", a, b); + +none(); +none(1, 2, 3); +one(); +one("x"); +one("x", "y"); +two(1); +two(1, [2], { three: 3 }); + +const handlers: Handler[] = [none, one, two]; +for (const h of handlers) h("all", true); + +function dispatch(h: Handler, ...args: unknown[]): void { + h(...args); +} +dispatch(two, "spread", null); +dispatch(one); + +const first: AsyncHandler = async (value: unknown) => value; +const pair: AsyncHandler = async (a: unknown, b: unknown) => [a, b]; + +async function main(): Promise { + console.log(await first(10, 20)); + console.log(await first()); + console.log(await pair("p")); + console.log(await pair("p", "q", "r")); +} +main().then(() => console.log("done")); diff --git a/tests/corpus/5916-dyn-error-stack-property.ts b/tests/corpus/5916-dyn-error-stack-property.ts new file mode 100644 index 000000000..2e1b42ef3 --- /dev/null +++ b/tests/corpus/5916-dyn-error-stack-property.ts @@ -0,0 +1,147 @@ +// Errors held as `any` or `unknown` have an own `stack` like Node's: a +// non-enumerable accessor that every error shares. The first read formats +// "Name: message" from the error's name and message at that point, and +// later reads answer the same string. Assigning a value replaces it, +// `delete` removes it, Object.keys, spread, Object.assign and +// JSON.stringify leave it out, `in` and Object.hasOwn find it, objects +// that inherit from an error read the error's stack. Typed and dynamic +// reads answer the same string, and a stack read through `any` captures +// frames. Only the first line is printed: frame lines differ between +// runtimes. + +class ParseError extends Error { + constructor(message: string) { + super(message); + this.name = "ParseError"; + } +} + +class PlainSubclass extends Error {} + +function dyn(value: unknown): any { + return value; +} + +function firstLine(value: unknown): string { + return typeof value === "string" ? JSON.stringify(value.split("\n")[0]) : `(${typeof value} ${String(value)})`; +} + +function describe(label: string, error: any): void { + console.log( + label, + "|", + typeof error.stack, + firstLine(error.stack), + "|", + Object.keys(error).join(","), + JSON.stringify(error), + "|", + "stack" in error, + Object.hasOwn(error, "stack"), + error.propertyIsEnumerable("stack"), + ); +} + +try { + throw new RangeError("thrown"); +} catch (error) { + describe("caught", error); +} + +const unknownError: unknown = new TypeError("bad thing"); +describe("unknown", unknownError); +describe("plain", dyn(new Error("plain"))); +describe("no message", dyn(new SyntaxError())); +describe("subclass", dyn(new ParseError("line 3"))); +describe("plain subclass", dyn(new PlainSubclass("inherited name"))); + +const coded = dyn(new Error("with code")); +coded.code = "E_CODE"; +describe("own property", coded); + +const descriptor = Object.getOwnPropertyDescriptor(dyn(new Error("a")), "stack")!; +const other = Object.getOwnPropertyDescriptor(dyn(new TypeError("b")), "stack")!; +console.log("descriptor", Object.keys(descriptor).join(","), descriptor.enumerable, descriptor.configurable); +console.log("shared accessors", typeof descriptor.get, descriptor.get === other.get, descriptor.set === other.set); +console.log("foreign receiver", descriptor.get!.call({}), firstLine(descriptor.get!.call(dyn(new TypeError("b"))))); +const subclassDescriptor = Object.getOwnPropertyDescriptor(dyn(new PlainSubclass("s")), "stack")!; +console.log("subclass descriptor", Object.keys(subclassDescriptor).join(","), subclassDescriptor.get === descriptor.get); + +const renamed = dyn(new Error("before")); +renamed.message = "after"; +renamed.name = "Renamed"; +console.log("first read", firstLine(renamed.stack)); +renamed.message = "later"; +console.log("later read", firstLine(renamed.stack)); +const subclassRenamed = dyn(new PlainSubclass("before")); +subclassRenamed.message = "after"; +console.log("subclass first read", firstLine(subclassRenamed.stack)); + +const replaced = dyn(new Error("replaced")); +replaced.stack = "custom stack\n at nowhere"; +describe("assigned", replaced); +console.log("assigned descriptor", Object.keys(Object.getOwnPropertyDescriptor(replaced, "stack")!).join(",")); +const subclassReplaced = dyn(new ParseError("replaced")); +subclassReplaced.stack = "subclass stack"; +console.log("subclass assigned", subclassReplaced.stack); +const typedReplaced = new ParseError("typed write"); +typedReplaced.stack = "typed subclass stack"; +console.log("typed subclass assigned", typedReplaced.stack, dyn(typedReplaced).stack); +const subclassNumbered = dyn(new PlainSubclass("numbered")); +subclassNumbered.stack = 7; +console.log("subclass number", subclassNumbered.stack, typeof subclassNumbered.stack); +subclassNumbered.stack = "string again"; +console.log("subclass string again", subclassNumbered.stack); +const numbered = dyn(new Error("numbered")); +numbered.stack = 5; +console.log("number", numbered.stack, typeof numbered.stack); +const removed = dyn(new Error("removed")); +delete removed.stack; +console.log("deleted", removed.stack, "stack" in removed, Object.hasOwn(removed, "stack")); + +const spreadSource = dyn(new Error("spread")); +console.log("spread", Object.keys({ ...spreadSource }).length, Object.keys(Object.assign({}, spreadSource)).length); +console.log("inherited", firstLine(Object.create(dyn(new RangeError("prototype"))).stack)); + +const typed = new Error("typed"); +const view = dyn(typed); +console.log("typed and dynamic", view.stack === typed.stack, firstLine(typed.stack)); +const typedSubclass = new ParseError("typed subclass"); +console.log("typed subclass", firstLine(dyn(typedSubclass).stack), dyn(typedSubclass).stack === typedSubclass.stack); +const assignedThroughView = new Error("typed"); +dyn(assignedThroughView).stack = "through the view"; +console.log("assigned through view", assignedThroughView.stack); + +function inner(): any { + return dyn(new Error("deep")); +} +function outer(): any { + return inner(); +} +const deep: string = outer().stack; +console.log("frames", deep.split("\n").length > 1, deep.includes("at inner"), deep.includes("at outer")); +function makeSubclass(): any { + return dyn(new PlainSubclass("deep")); +} +console.log("subclass frames", (makeSubclass().stack as string).includes("at makeSubclass")); + +const formatted = dyn(new Error("formatted")); +console.log("formatted before clone", firstLine(formatted.stack)); +console.log("clone keeps a formatted stack", firstLine(dyn(structuredClone(formatted)).stack)); + +class GrumpyError extends Error { + override get name(): string { + throw new Error("no name today"); + } +} +try { + console.log("throwing name getter", firstLine(dyn(new GrumpyError("grumpy")).stack)); +} catch (error) { + console.log("throwing name getter threw", (error as Error).message); +} + +function readKey(target: any, key: string): unknown { + return target[key]; +} +const computed = readKey(inner(), ["sta", "ck"].join("")) as string; +console.log("computed key", firstLine(computed), computed.includes("at inner")); diff --git a/tests/corpus/6004-class-instance-integrity.ts b/tests/corpus/6004-class-instance-integrity.ts new file mode 100644 index 000000000..7df516802 --- /dev/null +++ b/tests/corpus/6004-class-instance-integrity.ts @@ -0,0 +1,169 @@ +export {}; +import { inspect } from "node:util"; + +const message = (run: () => void): string => { + try { + run(); + return "no error"; + } catch (e) { + return `${e instanceof TypeError ? "TypeError" : "Error"}: ${(e as Error).message}`; + } +}; + +class Point { + x = 1; + y = 2; + label = "p"; + move(dx: number): void { + this.x += dx; + } +} + +const p = new Point(); +console.log(Object.isFrozen(p), Object.isSealed(p), Object.isExtensible(p)); +const same = Object.freeze(p); +console.log(same === p, Object.isFrozen(p), Object.isSealed(p), Object.isExtensible(p)); +console.log(message(() => { + p.x = 5; +})); +console.log(message(() => p.move(1))); +console.log(p.x, Object.keys(p)); +const q = new Point(); +q.x = 9; +console.log(q.x, Object.isFrozen(q)); + +class Point3 extends Point { + z = 3; +} +const p3 = new Point3(); +Object.freeze(p3); +console.log(message(() => { + p3.z = 1; +})); +const asBase: Point = new Point3(); +Object.freeze(asBase); +console.log(message(() => { + asBase.y = 0; +})); +console.log(asBase.y); + +class Counter { + n = 0; +} +const c = Object.seal(new Counter()); +c.n = 5; +console.log(c.n, Object.isSealed(c), Object.isFrozen(c), Object.isExtensible(c)); +const d = new Counter(); +Object.preventExtensions(d); +d.n = 2; +console.log(d.n, Object.isExtensible(d), Object.isSealed(d), Object.isFrozen(d)); +const loose: any = d; +console.log(message(() => { + loose.extra = 1; +})); + +class Config { + mode = "dev"; + level = 1; +} +const cfg = new Config(); +Object.defineProperty(cfg, "mode", { value: "prod", writable: false }); +console.log(cfg.mode, Object.keys(cfg), Object.values(cfg)); +console.log(message(() => { + cfg.mode = "x"; +})); +Object.defineProperty(cfg, "level", { enumerable: false }); +console.log(Object.keys(cfg), Object.entries(cfg), cfg.level); +Object.defineProperty(cfg, "level", { configurable: false }); +console.log(message(() => Object.defineProperty(cfg, "level", { enumerable: true }))); +console.log(JSON.stringify(Object.getOwnPropertyDescriptor(cfg, "mode"))); +console.log(JSON.stringify(Object.getOwnPropertyDescriptor(cfg, "level"))); +cfg.level = 7; +console.log(cfg.level); + +const fz = Object.freeze(new Config()); +console.log(message(() => Object.defineProperty(fz, "level", { value: 2 }))); +console.log(message(() => Object.defineProperty(fz, "level", { value: 1 }))); +console.log(fz.level, JSON.stringify(Object.getOwnPropertyDescriptor(fz, "level"))); + +class Frozen { + a = 1; + constructor() { + Object.freeze(this); + } +} +const frozenInCtor = new Frozen(); +console.log(frozenInCtor.a, Object.isFrozen(frozenInCtor)); +console.log(message(() => { + frozenInCtor.a = 2; +})); + +class Extended extends Frozen { + b = 2; +} +console.log(message(() => new Extended())); + +class Empty {} +const empty = new Empty(); +console.log(Object.isExtensible(empty), Object.isSealed(empty), Object.isFrozen(empty)); +Object.preventExtensions(empty); +console.log(Object.isExtensible(empty), Object.isSealed(empty), Object.isFrozen(empty)); + +class Totals { + count = 1; + items: string[] = []; +} +const t = new Totals(); +Object.freeze(t); +console.log(message(() => { + t.count += 1; +})); +console.log(message(() => { + t.count++; +})); +console.log(message(() => { + ({ value: t.count } = { value: 5 }); +})); +t.items.push("still mutable"); +console.log(t.count, t.items, Object.isFrozen(t.items)); +console.log(JSON.stringify(Object.getOwnPropertyDescriptor(t, "count"))); + +class Holder { + value: T; + constructor(value: T) { + this.value = value; + } +} +const h = Object.freeze(new Holder("text")); +console.log(h.value, Object.isFrozen(h)); +const h2 = new Holder(4); +Object.seal(h2); +h2.value = 5; +console.log(h2.value, Object.isSealed(h2)); + +class Settings { + mode = "dev"; + level = 1; +} +const settings = new Settings(); +console.log(settings); +Object.defineProperty(settings, "level", { enumerable: false }); +console.log(settings, inspect(settings)); +console.log([settings], { settings }); + +class Pair { + x = 1; + y = 2; +} +const pair = new Pair(); +Object.freeze(pair); +console.log(pair, Object.isFrozen(pair)); +const sealed = new Pair(); +(sealed as any).extra = "added"; +Object.seal(sealed); +console.log(sealed, Object.isSealed(sealed)); + +// JSON.stringify reads the same view: non-enumerable fields are skipped. +console.log(JSON.stringify(cfg), JSON.stringify(settings)); +console.log(JSON.stringify({ settings, pair, sealed })); +console.log(JSON.stringify([fz, t])); diff --git a/tests/corpus/6005-class-instance-integrity-sloppy.cjs b/tests/corpus/6005-class-instance-integrity-sloppy.cjs new file mode 100644 index 000000000..92c959d34 --- /dev/null +++ b/tests/corpus/6005-class-instance-integrity-sloppy.cjs @@ -0,0 +1,40 @@ +class Box { + constructor() { + this.x = 1; + } + bump() { + this.x = 2; + } +} + +const b = new Box(); +Object.freeze(b); +b.x = 5; +console.log(b.x, Object.isFrozen(b)); + +function strictWrite() { + "use strict"; + try { + b.x = 6; + } catch (e) { + console.log(e instanceof TypeError, e.message); + } +} +strictWrite(); + +try { + b.bump(); +} catch (e) { + console.log("class body:", e.message); +} +console.log(b.x); + +const s = new Box(); +Object.seal(s); +s.x = 3; +console.log(s.x, Object.isSealed(s), Object.isFrozen(s)); + +const plain = new Box(); +Object.defineProperty(plain, "x", { writable: false }); +plain.x = 9; +console.log(plain.x, JSON.stringify(Object.getOwnPropertyDescriptor(plain, "x"))); diff --git a/tests/corpus/6064-protocol-subinterface-assertions.ts b/tests/corpus/6064-protocol-subinterface-assertions.ts deleted file mode 100644 index 1d1656c5c..000000000 --- a/tests/corpus/6064-protocol-subinterface-assertions.ts +++ /dev/null @@ -1,80 +0,0 @@ -// An interface that extends a class-backed protocol holds values of that -// protocol, so asserting a base-typed value to it (`type as -// TupleTypeReference`, where TupleTypeReference redeclares `getTarget(): -// TupleType`) keeps the class instance: its methods run and its fields read -// as on the base type. -interface Type { - readonly flags: number; - getTarget(): Type | undefined; - isTypeReference(): this is TypeReference; - isTupleType(): this is TupleType; -} -interface ObjectType extends Type {} -interface TypeReference extends ObjectType { - getTarget(): Type; -} -interface InterfaceType extends TypeReference {} -interface TupleType extends InterfaceType { - readonly elementFlags: readonly number[]; - readonly fixedLength: number; -} -interface TupleTypeReference extends TypeReference { - getTarget(): TupleType; -} -class CompilerType { - flags: number; - target: CompilerType | undefined; - elementFlags: number[] = []; - fixedLength = 0; - constructor(flags: number, target?: CompilerType) { - this.flags = flags; - this.target = target; - } - getTarget(): CompilerType | undefined { - return this.target; - } - isTypeReference(): boolean { - return (this.flags & 4) !== 0; - } - isTupleType(): boolean { - return (this.flags & 8) !== 0; - } -} -const tuple = new CompilerType(8); -tuple.elementFlags = [1, 1, 2]; -tuple.fixedLength = 2; -const reference = new CompilerType(4, tuple); -const publicType = (t: CompilerType): Type => t as unknown as Type; -function describe(type: Type): string { - if (type.isTypeReference() && type.getTarget().isTupleType()) { - const ref = type as TupleTypeReference; - const target = ref.getTarget(); - return `tuple ${target.fixedLength} [${target.elementFlags.join(",")}]`; - } - return `flags ${type.flags}`; -} -const seen = new Set([publicType(tuple)]); -console.log(describe(publicType(reference)), describe(publicType(tuple)), seen.has(publicType(tuple))); - -interface Shape { - readonly sides: number; - area(): number; -} -interface Square extends Shape { - readonly side: number; -} -class SquareImpl implements Shape { - readonly sides = 4; - readonly side: number; - constructor(side: number) { - this.side = side; - } - area(): number { - return this.side * this.side; - } -} -const shapes: Shape[] = [new SquareImpl(3), new SquareImpl(5)]; -for (const shape of shapes) { - const square = shape as Square; - console.log(square.sides, square.side, square.area(), square === shape); -} diff --git a/tests/corpus/6398-conditional-fixed-arity.ts b/tests/corpus/6398-conditional-fixed-arity.ts new file mode 100644 index 000000000..beb75583a --- /dev/null +++ b/tests/corpus/6398-conditional-fixed-arity.ts @@ -0,0 +1,40 @@ +// Conditional types over function types with fixed `any` parameters, as +// a generic wrapper's specialization sees them: a function that needs +// more arguments than the pattern passes takes the false branch. +type FirstResult = F extends (a: any) => infer R ? R : "takes more"; +type NoArgResult = F extends () => infer R ? R : "takes some"; + +function label any>(fn: F, value: FirstResult): string { + const local: FirstResult = value; + return `${fn.name}: ${typeof local} ${String(local)}`; +} + +function labelNoArgs any>(fn: F, value: NoArgResult): string { + const local: NoArgResult = value; + return `${fn.name}: ${typeof local} ${String(local)}`; +} + +function none(): boolean { + return true; +} +function one(a: string): number { + return a.length; +} +function two(a: string, b: string): number { + return a.length + b.length; +} +function optional(a: string, b?: string): number { + return a.length + (b?.length ?? 0); +} +function rest(a: string, ...more: string[]): number { + return a.length + more.length; +} + +console.log(label(none, true)); +console.log(label(one, 3)); +console.log(label(two, "takes more")); +console.log(label(optional, 4)); +console.log(label(rest, 5)); +console.log(labelNoArgs(none, false)); +console.log(labelNoArgs(one, "takes some")); +console.log(labelNoArgs(optional, "takes some")); diff --git a/tests/corpus/6400-dyn-error-stack-property-js.js b/tests/corpus/6400-dyn-error-stack-property-js.js new file mode 100644 index 000000000..f0f666103 --- /dev/null +++ b/tests/corpus/6400-dyn-error-stack-property-js.js @@ -0,0 +1,148 @@ +// In JavaScript sources, errors have an own `stack` like Node's: a +// non-enumerable accessor that every error shares. The first read formats +// "Name: message" from the error's name and message at that point, and +// later reads answer the same string. Assigning a value replaces it, +// `delete` removes it, Object.keys, spread, Object.assign and +// JSON.stringify leave it out, `in` and Object.hasOwn find it, objects +// that inherit from an error read the error's stack. Typed and dynamic +// reads answer the same string, and a stack read through `any` captures +// frames. Only the first line is printed: frame lines differ between +// runtimes. + +class ParseError extends Error { + constructor(message) { + super(message); + this.name = "ParseError"; + } +} + +class PlainSubclass extends Error {} + +function dyn(value) { + return value; +} + +function firstLine(value) { + return typeof value === "string" ? JSON.stringify(value.split("\n")[0]) : `(${typeof value} ${String(value)})`; +} + +function describe(label, error) { + console.log( + label, + "|", + typeof error.stack, + firstLine(error.stack), + "|", + Object.keys(error).join(","), + JSON.stringify(error), + "|", + "stack" in error, + Object.hasOwn(error, "stack"), + error.propertyIsEnumerable("stack"), + ); +} + +try { + throw new RangeError("thrown"); +} catch (error) { + describe("caught", error); +} + +const unknownError = new TypeError("bad thing"); +describe("unknown", unknownError); +describe("plain", dyn(new Error("plain"))); +describe("no message", dyn(new SyntaxError())); +describe("subclass", dyn(new ParseError("line 3"))); +describe("plain subclass", dyn(new PlainSubclass("inherited name"))); + +const coded = dyn(new Error("with code")); +coded.code = "E_CODE"; +describe("own property", coded); + +const descriptor = dyn(Object.getOwnPropertyDescriptor(dyn(new Error("a")), "stack")); +const other = dyn(Object.getOwnPropertyDescriptor(dyn(new TypeError("b")), "stack")); +console.log("descriptor", Object.keys(descriptor).join(","), descriptor.enumerable, descriptor.configurable); +console.log("shared accessors", typeof descriptor.get, descriptor.get === other.get, descriptor.set === other.set); +console.log("foreign receiver", descriptor.get.call({}), firstLine(descriptor.get.call(dyn(new TypeError("b"))))); +const subclassDescriptor = dyn(Object.getOwnPropertyDescriptor(dyn(new PlainSubclass("s")), "stack")); +console.log("subclass descriptor", Object.keys(subclassDescriptor).join(","), subclassDescriptor.get === descriptor.get); + +const renamed = dyn(new Error("before")); +renamed.message = "after"; +renamed.name = "Renamed"; +console.log("first read", firstLine(renamed.stack)); +renamed.message = "later"; +console.log("later read", firstLine(renamed.stack)); +const subclassRenamed = dyn(new PlainSubclass("before")); +subclassRenamed.message = "after"; +console.log("subclass first read", firstLine(subclassRenamed.stack)); + +const replaced = dyn(new Error("replaced")); +replaced.stack = "custom stack\n at nowhere"; +describe("assigned", replaced); +console.log("assigned descriptor", Object.keys(Object.getOwnPropertyDescriptor(replaced, "stack")).join(",")); +const subclassReplaced = dyn(new ParseError("replaced")); +subclassReplaced.stack = "subclass stack"; +console.log("subclass assigned", subclassReplaced.stack); +const typedReplaced = new ParseError("typed write"); +typedReplaced.stack = "typed subclass stack"; +console.log("typed subclass assigned", typedReplaced.stack, dyn(typedReplaced).stack); +const subclassNumbered = dyn(new PlainSubclass("numbered")); +subclassNumbered.stack = 7; +console.log("subclass number", subclassNumbered.stack, typeof subclassNumbered.stack); +subclassNumbered.stack = "string again"; +console.log("subclass string again", subclassNumbered.stack); +const numbered = dyn(new Error("numbered")); +numbered.stack = 5; +console.log("number", numbered.stack, typeof numbered.stack); +const removed = dyn(new Error("removed")); +delete removed.stack; +console.log("deleted", removed.stack, "stack" in removed, Object.hasOwn(removed, "stack")); + +const spreadSource = dyn(new Error("spread")); +console.log("spread", Object.keys({ ...spreadSource }).length, Object.keys(Object.assign({}, spreadSource)).length); +console.log("inherited", firstLine(Object.create(dyn(new RangeError("prototype"))).stack)); + +const typed = new Error("typed"); +const view = dyn(typed); +console.log("typed and dynamic", view.stack === typed.stack, firstLine(typed.stack)); +const typedSubclass = new ParseError("typed subclass"); +console.log("typed subclass", firstLine(dyn(typedSubclass).stack), dyn(typedSubclass).stack === typedSubclass.stack); +const assignedThroughView = new Error("typed"); +dyn(assignedThroughView).stack = "through the view"; +console.log("assigned through view", assignedThroughView.stack); + +function inner() { + return dyn(new Error("deep")); +} +function outer() { + return inner(); +} +const deep = outer().stack; +console.log("frames", deep.split("\n").length > 1, deep.includes("at inner"), deep.includes("at outer")); +function makeSubclass() { + return dyn(new PlainSubclass("deep")); +} +console.log("subclass frames", makeSubclass().stack.includes("at makeSubclass")); + +const formatted = dyn(new Error("formatted")); +console.log("formatted before clone", firstLine(formatted.stack)); +console.log("clone keeps a formatted stack", firstLine(dyn(structuredClone(formatted)).stack)); + +class GrumpyError extends Error { + /** @returns {string} */ + get name() { + throw new Error("no name today"); + } +} +try { + console.log("throwing name getter", firstLine(dyn(new GrumpyError("grumpy")).stack)); +} catch (error) { + console.log("throwing name getter threw", error.message); +} + +function readKey(target, key) { + return target[key]; +} +const computed = readKey(inner(), ["sta", "ck"].join("")); +console.log("computed key", firstLine(computed), computed.includes("at inner")); diff --git a/tests/corpus/6401-dyn-error-own-property-names.ts b/tests/corpus/6401-dyn-error-own-property-names.ts new file mode 100644 index 000000000..1020cf014 --- /dev/null +++ b/tests/corpus/6401-dyn-error-own-property-names.ts @@ -0,0 +1,44 @@ +// The own property names of errors held as `any` or `unknown` match +// Node's: Object.getOwnPropertyNames, Reflect.ownKeys and +// Object.getOwnPropertyDescriptors list `stack`, `message` and the +// properties the error has, in order, and nothing else. + +class PlainSubclass extends Error {} + +function dyn(value: unknown): any { + return value; +} + +function names(label: string, error: any): void { + console.log( + label, + "|", + Object.getOwnPropertyNames(error).join(","), + "|", + Reflect.ownKeys(error).map(String).join(","), + "|", + Object.keys(Object.getOwnPropertyDescriptors(error)).join(","), + ); +} + +names("error", dyn(new Error("plain"))); +names("type error", dyn(new TypeError("bad thing"))); +names("no message", dyn(new RangeError())); +names("cause", dyn(new Error("outer", { cause: new Error("inner") }))); +names("subclass", dyn(new PlainSubclass("sub"))); + +const unknownError: unknown = new SyntaxError("unexpected"); +names("unknown", unknownError); + +const coded = dyn(new Error("with code")); +coded.code = "E_CODE"; +coded.detail = 1; +names("own properties", coded); + +try { + throw new URIError("thrown"); +} catch (error) { + names("caught", error); +} + +console.log("marker", Object.getOwnPropertyNames(dyn(new Error("x"))).some((name) => name.startsWith("%"))); diff --git a/tests/corpus/6402-dyn-error-own-property-names-js.js b/tests/corpus/6402-dyn-error-own-property-names-js.js new file mode 100644 index 000000000..6f6ca7fb7 --- /dev/null +++ b/tests/corpus/6402-dyn-error-own-property-names-js.js @@ -0,0 +1,44 @@ +// In JavaScript sources, the own property names of errors match +// Node's: Object.getOwnPropertyNames, Reflect.ownKeys and +// Object.getOwnPropertyDescriptors list `stack`, `message` and the +// properties the error has, in order, and nothing else. + +class PlainSubclass extends Error {} + +function dyn(value) { + return value; +} + +function names(label, error) { + console.log( + label, + "|", + Object.getOwnPropertyNames(error).join(","), + "|", + Reflect.ownKeys(error).map(String).join(","), + "|", + Object.keys(Object.getOwnPropertyDescriptors(error)).join(","), + ); +} + +names("error", dyn(new Error("plain"))); +names("type error", dyn(new TypeError("bad thing"))); +names("no message", dyn(new RangeError())); +names("cause", dyn(new Error("outer", { cause: new Error("inner") }))); +names("subclass", dyn(new PlainSubclass("sub"))); + +const unknownError = new SyntaxError("unexpected"); +names("unknown", unknownError); + +const coded = dyn(new Error("with code")); +coded.code = "E_CODE"; +coded.detail = 1; +names("own properties", coded); + +try { + throw new URIError("thrown"); +} catch (error) { + names("caught", error); +} + +console.log("marker", Object.getOwnPropertyNames(dyn(new Error("x"))).some((name) => name.startsWith("%"))); diff --git a/tests/corpus/6420-process-send-presence.ts b/tests/corpus/6420-process-send-presence.ts new file mode 100644 index 000000000..59773ab44 --- /dev/null +++ b/tests/corpus/6420-process-send-presence.ts @@ -0,0 +1,24 @@ +// process.send exists only with an IPC channel: presence checks in every +// truthiness position, typeof, and guarded calls. +const viaIpc = Boolean(process.send); +console.log("Boolean", viaIpc); +console.log("not", !process.send, !!process.disconnect); +console.log("typeof", typeof process.send, typeof process.disconnect); +console.log("ternary", process.send ? "ipc" : "stdout"); +if (process.send) { + process.send({ kind: "log", line: "never" }); +} else { + console.log("if: no channel"); +} +let polls = 0; +while (process.send && polls < 3) polls++; +console.log("while", polls); +process.send && process.send({ unused: true }); +const sink = !process.send || !process.disconnect ? "console" : "ipc"; +console.log("or", sink); +console.log("optional", process.send?.({ value: 1 })); +try { + process.send!({ value: 2 }); +} catch (e) { + console.log("direct", (e as Error).name, (e as Error).message); +} diff --git a/tests/corpus/6421-process-send-presence-fork/main.ts b/tests/corpus/6421-process-send-presence-fork/main.ts new file mode 100644 index 000000000..11a634672 --- /dev/null +++ b/tests/corpus/6421-process-send-presence-fork/main.ts @@ -0,0 +1,13 @@ +// process.send and process.disconnect exist in a forked child (an IPC +// channel) and not in the parent; the child's presence checks pick the +// channel and its guarded send reaches the parent. +import { fork } from "node:child_process"; + +console.log("parent", Boolean(process.send), typeof process.send, typeof process.disconnect); +const child = fork(new URL("./worker.ts", import.meta.url), [], { + stdio: ["ignore", "inherit", "inherit", "ipc"], +}); +child.on("message", (message: { sink: string; send: string; disconnect: string }) => { + console.log("child says", message.sink, message.send, message.disconnect); +}); +child.on("exit", (code) => console.log("child exit", code)); diff --git a/tests/corpus/6421-process-send-presence-fork/worker.ts b/tests/corpus/6421-process-send-presence-fork/worker.ts new file mode 100644 index 000000000..81e8288a7 --- /dev/null +++ b/tests/corpus/6421-process-send-presence-fork/worker.ts @@ -0,0 +1,6 @@ +const sink = process.send ? "ipc" : "stdout"; +if (process.send) { + process.send({ sink, send: typeof process.send, disconnect: typeof process.disconnect }); +} +if (!process.send) console.log("unreachable"); +process.disconnect(); diff --git a/tests/corpus/6422-process-exitcode-read.ts b/tests/corpus/6422-process-exitcode-read.ts new file mode 100644 index 000000000..c320b4a0d --- /dev/null +++ b/tests/corpus/6422-process-exitcode-read.ts @@ -0,0 +1,22 @@ +// @exit: 7 +// process.exitCode: unset reads undefined, assignments (including 0) read back, +// and process.exit(n) assigns the code before 'exit' listeners run. +console.log("initial", process.exitCode); +process.on("exit", (code) => { + console.log("exit listener", code, process.exitCode); +}); +process.exitCode = 0; +console.log("after 0", process.exitCode); +process.exitCode = 4; +const seen = process.exitCode; +console.log("after 4", seen, typeof process.exitCode); +process.exitCode = process.exitCode ?? 9; +console.log("kept", process.exitCode); +try { + process.exitCode = 1.5; +} catch (e) { + console.log("rejected", (e as Error).message, process.exitCode); +} +setTimeout(() => { + process.exit(7); +}, 1); diff --git a/tests/corpus/6423-process-exitcode-default.ts b/tests/corpus/6423-process-exitcode-default.ts new file mode 100644 index 000000000..5dbc72294 --- /dev/null +++ b/tests/corpus/6423-process-exitcode-default.ts @@ -0,0 +1,10 @@ +// @exit: 2 +// The exit status follows process.exitCode when the program ends normally. +function settle(failed: boolean): void { + if (failed) process.exitCode = process.exitCode ?? 2; +} +console.log("start", process.exitCode === undefined); +settle(true); +settle(true); +console.log("code", process.exitCode); +process.on("exit", () => console.log("exiting with", process.exitCode)); diff --git a/tests/corpus/6424-process-exit-keeps-exitcode.ts b/tests/corpus/6424-process-exit-keeps-exitcode.ts new file mode 100644 index 000000000..e5a0b86d2 --- /dev/null +++ b/tests/corpus/6424-process-exit-keeps-exitcode.ts @@ -0,0 +1,5 @@ +// @exit: 5 +// process.exit() without an argument keeps process.exitCode. +process.exitCode = 5; +process.on("exit", (code) => console.log("exit", code, process.exitCode)); +process.exit(); diff --git a/tests/corpus/6425-stream-hook-wider-chunk.ts b/tests/corpus/6425-stream-hook-wider-chunk.ts new file mode 100644 index 000000000..be46b18be --- /dev/null +++ b/tests/corpus/6425-stream-hook-wider-chunk.ts @@ -0,0 +1,46 @@ +// Stream hooks may declare a supertype of what Node passes: chunks typed +// Buffer | string still arrive as Buffers. +import { Transform, Writable } from "node:stream"; + +class LineSink extends Writable { + private rest = ""; + readonly lines: string[] = []; + _write(chunk: Buffer | string, encoding: BufferEncoding, cb: (err?: Error | null) => void): void { + console.log("chunk", typeof chunk, Buffer.isBuffer(chunk), encoding); + const parts = (this.rest + chunk.toString()).split("\n"); + this.rest = parts.pop() ?? ""; + this.lines.push(...parts); + cb(); + } + _final(cb: (err?: Error | null) => void): void { + if (this.rest !== "") this.lines.push(this.rest); + cb(); + } +} + +class Upper extends Transform { + _transform(chunk: string | Buffer, _enc: string, cb: (err?: Error | null, data?: string) => void): void { + cb(null, chunk.toString().toUpperCase()); + } +} + +class Failing extends Writable { + _write(chunk: Uint8Array | string, _enc: BufferEncoding, cb: (err?: Error | null) => void): void { + cb(new Error(`refused ${chunk.toString().length} bytes`)); + } +} + +const sink = new LineSink(); +sink.write("a\nb"); +sink.write(Buffer.from("c\nd")); +sink.end("e"); +sink.on("finish", () => console.log("lines", JSON.stringify(sink.lines))); + +const up = new Upper(); +up.on("data", (d: Buffer) => console.log("upper", d.toString())); +up.write("hello "); +up.end("world"); + +const bad = new Failing(); +bad.on("error", (e) => console.log("error", e.message)); +bad.write("xyz"); diff --git a/tests/corpus/6426-promise-race-void-entry.ts b/tests/corpus/6426-promise-race-void-entry.ts new file mode 100644 index 000000000..b33f3b664 --- /dev/null +++ b/tests/corpus/6426-promise-race-void-entry.ts @@ -0,0 +1,31 @@ +// Promise.race over Promise and Promise: the void +// entry fulfills the race with undefined. +interface Msg { id: string } +function delay(ms: number, value: T): Promise { + return new Promise((resolve) => setTimeout(() => resolve(value), ms)); +} +function poll(ms: number, id: string | null): Promise { + return delay(ms, id === null ? undefined : { id }); +} +function exited(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} +async function main(): Promise { + const a = await Promise.race([poll(5, "m1"), exited(50)]); + console.log("message first:", a ? a.id : "none"); + const b = await Promise.race([poll(50, "m2"), exited(5)]); + console.log("exit first:", b === undefined, b ? b.id : "none"); + const c = await Promise.race([exited(5), poll(1, null)]); + console.log("empty poll first:", c); + const settled = Promise.resolve(); + const d = await Promise.race([settled, poll(0, "m3")]); + console.log("settled void entry wins:", d); + const n = await Promise.race([delay(20, 42), exited(1)]); + console.log("number or void:", n); + try { + await Promise.race([poll(20, "late"), Promise.reject(new Error("boom"))]); + } catch (e) { + console.log("rejected:", (e as Error).message); + } +} +void main(); diff --git a/tests/corpus/6427-http-request-options-type.ts b/tests/corpus/6427-http-request-options-type.ts new file mode 100644 index 000000000..17cb2d855 --- /dev/null +++ b/tests/corpus/6427-http-request-options-type.ts @@ -0,0 +1,10 @@ +// http.RequestOptions as a declared type: a checked-dynamic option record. +import type http from "node:http"; +const socket = process.env.NO_SUCH_SOCKET_VAR; +const base: http.RequestOptions = socket ? { socketPath: socket } : { host: "127.0.0.1", port: 8080 }; +const full: http.RequestOptions = { ...base, path: "/x", method: "POST", headers: { "x-a": "1" } }; +console.log(JSON.stringify(base), JSON.stringify(full)); +function describe(o: http.RequestOptions): string { + return `${String(o.host)}:${String(o.port)}${String(o.path ?? "/")}`; +} +console.log(describe(full), describe({ host: "h" })); diff --git a/tests/corpus/6428-promisify-callback-functions.ts b/tests/corpus/6428-promisify-callback-functions.ts new file mode 100644 index 000000000..b899dd292 --- /dev/null +++ b/tests/corpus/6428-promisify-callback-functions.ts @@ -0,0 +1,80 @@ +// util.promisify over typed callback-only functions (bound methods, one with +// an optional callback, a function declaration, an inline arrow, a function +// that returns a value): the error argument rejects, the value fulfills, the +// return value is ignored, a synchronous throw rejects, and settlement is +// async. +import { promisify } from "node:util"; + +class Connection { + private closed = false; + private readonly name: string; + constructor(name: string) { + this.name = name; + } + close(callback: (error?: Error) => void): void { + setTimeout(() => { + if (this.closed) { + callback(new Error(`${this.name} already closed`)); + return; + } + this.closed = true; + callback(); + }, 1); + } + flush(callback?: (error?: Error) => void): void { + setImmediate(() => callback?.(this.closed ? new Error("flushed after close") : undefined)); + } + stats(callback: (error: Error | null, open: number) => void): void { + setImmediate(() => (this.closed ? callback(new RangeError("closed"), 0) : callback(null, 3))); + } +} + +function boom(callback: (error: Error | null) => void): void { + if (callback !== undefined) throw new TypeError("synchronous failure"); +} + +let pending = 0; +function size(callback: (error: Error | null, size: number) => void): number { + setImmediate(() => callback(null, 4)); + return ++pending; +} + +async function main(): Promise { + const c = new Connection("db"); + const stats = promisify(c.stats.bind(c)); + console.log("open", await stats()); + await promisify(c.flush.bind(c))(); + console.log("flushed"); + const closeAsync = promisify(c.close.bind(c)); + await closeAsync(); + console.log("closed once"); + try { + await closeAsync(); + } catch (e) { + console.log("second close:", (e as Error).message); + } + try { + await stats(); + } catch (e) { + console.log("stats:", (e as Error).name, (e as Error).message); + } + await promisify(c.flush.bind(c))().catch((e) => console.log("flush:", (e as Error).message)); + try { + await promisify(boom)(); + } catch (e) { + console.log("sync throw:", (e as Error).name, (e as Error).message); + } + const order: string[] = []; + const tick = promisify((done: (error?: Error) => void) => { + order.push("called"); + done(); + }); + const p = tick().then(() => order.push("settled")); + order.push("returned"); + await p; + console.log(order.join(", ")); + await promisify(new Connection("inline").close.bind(new Connection("inline")))(); + console.log("inline done"); + console.log("size", await promisify(size)(), pending); +} +void main(); diff --git a/tests/corpus/6429-esm-js-dirname.mjs b/tests/corpus/6429-esm-js-dirname.mjs new file mode 100644 index 000000000..2ecc4088a --- /dev/null +++ b/tests/corpus/6429-esm-js-dirname.mjs @@ -0,0 +1,15 @@ +// A JavaScript ES module has no __dirname or __filename (Node throws a +// ReferenceError where they are read); import.meta carries the location. +// TypeScript files keep the CommonJS globals as the source path. +try { + console.log(__dirname); +} catch (error) { + console.log("no __dirname:", error instanceof Error); +} +console.log(import.meta.filename.endsWith("6429-esm-js-dirname.mjs")); +console.log(typeof __dirname, typeof __filename); +try { + console.log(__filename.length); +} catch (error) { + console.log(error.name, error.message); +} diff --git a/tests/corpus/6445-rest-function-fixed-slot.ts b/tests/corpus/6445-rest-function-fixed-slot.ts new file mode 100644 index 000000000..e78e83836 --- /dev/null +++ b/tests/corpus/6445-rest-function-fixed-slot.ts @@ -0,0 +1,49 @@ +// A rest-parameter function in a slot with fixed parameters: the slot's +// arguments arrive in the rest array, as in a JavaScript call. +function log(...messages: string[]): void { + console.log(`log(${messages.length}):`, messages.join(" | ")); +} +function tagged(tag: string, ...values: number[]): number { + console.log(tag, values.join(",")); + return values.length; +} + +class Line { + private readonly sink: (m: string) => void; + constructor(sink: (m: string) => void) { + this.sink = sink; + } + emit(m: string): void { + this.sink(m); + } +} + +new Line(log).emit("one"); +const pair: (a: string, b: string) => void = log; +pair("x", "y"); +const none: () => void = log; +none(); +const count: (tag: string, a: number, b: number) => number = tagged; +console.log("count", count("t", 1, 2)); +["a", "b"].forEach((m) => new Line(log).emit(m)); + +// Nullable and optional slots: the value takes the slot's function arm. +class OptionalLine { + private readonly sink: ((m: string) => void) | null; + constructor(sink: ((m: string) => void) | null) { + this.sink = sink; + } + emit(m: string): void { + if (this.sink) this.sink(m); + else console.log("no sink:", m); + } +} +new OptionalLine(log).emit("nullable"); +new OptionalLine(null).emit("dropped"); +function relay(m: string, sink?: (m: string) => void): void { + sink?.(m); +} +relay("optional", log); +relay("absent"); +const maybe: ((a: string, b: string) => void) | undefined = log; +maybe?.("p", "q"); diff --git a/tests/corpus/6446-rest-function-nested-declaration.ts b/tests/corpus/6446-rest-function-nested-declaration.ts new file mode 100644 index 000000000..1b2d7aa17 --- /dev/null +++ b/tests/corpus/6446-rest-function-nested-declaration.ts @@ -0,0 +1,26 @@ +// Nested rest-parameter function declarations passed to a fixed slot. +class Line { + private readonly sink: (m: string) => void; + constructor(sink: (m: string) => void) { + this.sink = sink; + } + emit(m: string): void { + this.sink(m); + } +} +interface Logger { + line: () => Line; + log: (...messages: string[]) => void; +} +function makeLogger(prefix: string): Logger { + return { + line: () => new Line(log), + log, + }; + function log(...messages: string[]) { + console.log(prefix, messages.join(" ")); + } +} +const logger = makeLogger(">"); +logger.log("a", "b"); +logger.line().emit("c"); diff --git a/tests/corpus/6460-in-union-optional-slots.ts b/tests/corpus/6460-in-union-optional-slots.ts new file mode 100644 index 000000000..f381217b9 --- /dev/null +++ b/tests/corpus/6460-in-union-optional-slots.ts @@ -0,0 +1,53 @@ +// `"k" in u` over a union of records where some arms declare `k` as an +// optional slot: those arms answer by the value's own property presence +// (an explicit undefined is present, an omitted or deleted key is not), +// the other arms by their tag. +type Cond = { type: string; value?: string }; +type HandleRoute = { handle: string; src?: string; dest?: string; status?: number }; +type SourceRoute = { + src: string; + dest?: string; + headers?: { [key: string]: string }; + middlewarePath?: string; + continue?: boolean; + status?: number; + has?: Cond[]; +}; +type Route = HandleRoute | SourceRoute; + +const routes: Route[] = [ + { handle: "filesystem" }, + { src: "/a", middlewarePath: "/mw" }, + { src: "/b", dest: "/c", status: undefined }, + { handle: "miss", src: "/x", dest: undefined }, + { src: "/d", has: [{ type: "header" }] }, +]; + +for (const r of routes) { + console.log("handle" in r, "middlewarePath" in r, "dest" in r, "status" in r, "has" in r, "toString" in r); +} + +// A deleted optional key leaves the value; a later write brings it back. +const second = routes[1]!; +if ("middlewarePath" in second) { + delete second.middlewarePath; +} +console.log("middlewarePath" in second, JSON.stringify(second)); +if (!("handle" in second)) { + second.middlewarePath = "/again"; +} +console.log("middlewarePath" in second, JSON.stringify(second)); + +// The receiver evaluates once, even when it is a call. +let calls = 0; +function pick(i: number): Route { + calls++; + return routes[i]!; +} +console.log("dest" in pick(2), "dest" in pick(0), "src" in pick(3), calls); + +// `in` as a narrowing test inside a predicate and a filter callback. +function hasMiddleware(route: Route): boolean { + return "middlewarePath" in route && typeof route.middlewarePath === "string"; +} +console.log(routes.filter(hasMiddleware).length, routes.filter((r) => "status" in r).length); diff --git a/tests/corpus/6461-predicate-intersection-narrowing.ts b/tests/corpus/6461-predicate-intersection-narrowing.ts new file mode 100644 index 000000000..7e8ff9d8a --- /dev/null +++ b/tests/corpus/6461-predicate-intersection-narrowing.ts @@ -0,0 +1,70 @@ +// A predicate `r is Route & { path: string }` refines the record arms of +// a union without naming a stored arm: arms that do not declare `path` +// cannot hold such a value, the others are read through their own +// layout. The narrowed value can be read in place, in templates, in +// object literals and from closures. +type HandleRoute = { handle: string; src?: string; dest?: string }; +type SourceRoute = { src: string; dest?: string; path?: string; status?: number }; +type Route = HandleRoute | SourceRoute; + +function isPathRoute(route: Route): route is Route & { path: string } { + return "path" in route && typeof route.path === "string"; +} + +type Output = { path: string; index: number }; + +function collect(result: { names: Set; routes: Route[] }): Map { + const out = new Map(); + for (const route of result.routes) { + if (!isPathRoute(route)) continue; + let name = route.path; + if (!result.names.has(name)) name = name.replace(/^\//, ""); + if (!result.names.has(name)) { + throw new Error(`Mapping ${route.path} not found`); + } + out.set(name, { path: route.path, index: out.get(name)?.index ?? out.size }); + } + return out; +} + +const routes: Route[] = [ + { handle: "filesystem" }, + { src: "/a", path: "/one" }, + { src: "/b" }, + { src: "/c", path: "two" }, + { src: "/d", path: "/one", status: 308 }, +]; +console.log([...collect({ names: new Set(["one", "two"]), routes })]); +try { + collect({ names: new Set(), routes: [{ src: "/z", path: "/missing" }] }); +} catch (e) { + console.log((e as Error).message); +} + +// Closures capture the narrowed binding. +const readers: (() => string)[] = []; +for (const route of routes) { + if (!isPathRoute(route)) continue; + readers.push(() => `${route.src} -> ${route.path}`); +} +console.log(readers.map((read) => read())); + +// Three arms, two of which can hold the refinement: the narrowed value is +// either of them, and their shared members still read. +type A = { kind: string; a: number; tag?: string }; +type B = { kind: string; b: boolean; tag?: string }; +type C = { kind: string; c: string }; +type Item = A | B | C; +function isTagged(item: Item): item is Item & { tag: string } { + return "tag" in item && item.tag !== undefined; +} +const items: Item[] = [ + { kind: "a", a: 1, tag: "x" }, + { kind: "b", b: true }, + { kind: "c", c: "plain" }, + { kind: "b", b: false, tag: "y" }, +]; +for (const item of items) { + if (isTagged(item)) console.log(item.kind, item.tag.toUpperCase()); + else console.log(item.kind, "untagged"); +} diff --git a/tests/corpus/6462-assertion-attached-members.ts b/tests/corpus/6462-assertion-attached-members.ts new file mode 100644 index 000000000..8a2be31b7 --- /dev/null +++ b/tests/corpus/6462-assertion-attached-members.ts @@ -0,0 +1,58 @@ +// `route as Route & { order: number; internal: boolean }` followed by +// writes through the asserted view adds the members to the object the +// original binding names: they appear wherever the route is observed +// later, in the order the writes created them. +type HandleRoute = { handle: string; src?: string; dest?: string; status?: number }; +type SourceRoute = { src: string; dest?: string; path?: string; status?: number }; +type Route = HandleRoute | SourceRoute; + +function markInternal(input: Route[], out: Route[], order: number): void { + for (const route of input) { + const marked = route as Route & { internal: boolean; order: number }; + marked.internal = true; + marked.order = order; + out.unshift(route); + } +} + +const out: Route[] = [{ handle: "filesystem" }, { src: "/plain", dest: "/x" }]; +markInternal([{ src: "/a" }, { handle: "miss" }, { src: "/b", status: 404 }], out, 3); +console.log(JSON.stringify(out)); +console.log(out); +console.log(out.map((r) => ("internal" in (r as Route & { internal?: boolean }) ? "marked" : "plain"))); +console.log(out.map((r) => ({ ...r }))); + +// Values the assertion never reached keep no trace of the members. +const fresh: Route = { src: "/new" }; +console.log(JSON.stringify(fresh), Object.keys(fresh)); + +// A single record shape works the same way, and the asserted view reads +// back what it wrote. +type Job = { id: string; retries?: number }; +const job: Job = { id: "j1" }; +const tracked = job as Job & { startedAt: number }; +tracked.startedAt = 42; +console.log(tracked.startedAt + 1, JSON.stringify(job), Object.keys(job)); + +// An annotated binding of the asserted type keeps the object as well: +// the members appear on it once written, not before. +function stamp(job: Job): Job & { finishedAt: number } { + const done: Job & { finishedAt: number } = job as Job & { finishedAt: number }; + done.finishedAt = 7; + return done; +} +const second: Job = { id: "j2", retries: 1 }; +console.log(stamp(second).finishedAt, JSON.stringify(second), Object.keys(second)); + +const third: Job = { id: "j3" }; +const queued: Job & { queuedAt: number } = third as Job & { queuedAt: number }; +queued.queuedAt = 9; +console.log(queued.queuedAt, JSON.stringify(third), Object.keys(third)); + +function markAnnotated(route: Route): void { + const marked: Route & { internal: boolean } = route as Route & { internal: boolean }; + marked.internal = false; +} +const annotatedRoute: Route = { handle: "hit" }; +markAnnotated(annotatedRoute); +console.log(JSON.stringify(annotatedRoute)); diff --git a/tests/corpus/6480-catch-typeof-untyped-throws.ts b/tests/corpus/6480-catch-typeof-untyped-throws.ts new file mode 100644 index 000000000..98122f851 --- /dev/null +++ b/tests/corpus/6480-catch-typeof-untyped-throws.ts @@ -0,0 +1,40 @@ +// Values thrown from `unknown` storage read back through typeof tests on +// the catch binding, like the same values thrown with static types. +const thrown: unknown[] = [5, 0, -1.5, "text", "", true, false, null, undefined, { kind: "box" }]; +function describe(value: unknown): string { + try { + throw value; + } catch (e) { + const same = e === value; + if (typeof e === "number") return `${same} number ${e + 1}`; + if (typeof e === "string") return `${same} string ${e.length}`; + if (typeof e === "boolean") return `${same} boolean ${!e}`; + if (typeof e === "object") return `${same} object ${e === null ? "null" : "value"}`; + return `${same} ${typeof e}`; + } +} +for (const value of thrown) console.log(describe(value)); +function rethrow(value: unknown): void { + try { + throw value; + } catch (e) { + if (typeof e !== "string") throw e; + console.log("kept string", e); + } +} +for (const value of ["s", 7, false]) { + try { + rethrow(value); + } catch (e) { + console.log("rethrown", typeof e, String(e)); + } +} +let count = 0; +for (const value of thrown) { + try { + throw value; + } catch (e) { + if (typeof e === "number" && e > 0) count += e; + } +} +console.log(count); diff --git a/tests/diagnostics/boot-path-node-surface-fences.ts b/tests/diagnostics/boot-path-node-surface-fences.ts new file mode 100644 index 000000000..146a32aa1 --- /dev/null +++ b/tests/diagnostics/boot-path-node-surface-fences.ts @@ -0,0 +1,23 @@ +// The boot-path Node surface keeps its boundaries: process.send answers +// presence checks but stays fenced as a stored value, a stream hook must +// declare Node's argument type or a supertype of it, and util.promisify +// over a function value needs an Error-typed callback error. +import { promisify } from "node:util"; +import { Writable } from "node:stream"; + +const send = process.send; +console.log(typeof send); + +class Counter extends Writable { + _write(chunk: number, _encoding: BufferEncoding, cb: (err?: Error | null) => void): void { + console.log(chunk); + cb(); + } +} +new Counter().end("x"); + +function legacy(cb: (code: number, value: string) => void): void { + cb(0, "v"); +} +const legacyAsync = promisify(legacy); +legacyAsync().then((v) => console.log(v)); diff --git a/tests/diagnostics/class-field-accessor-descriptor.ts b/tests/diagnostics/class-field-accessor-descriptor.ts new file mode 100644 index 000000000..66078f6c2 --- /dev/null +++ b/tests/diagnostics/class-field-accessor-descriptor.ts @@ -0,0 +1,14 @@ +// Object.defineProperty can change a declared class field's value and +// attributes, but not turn it into an accessor: a literal get or set +// descriptor is refused at compile time, naming the field. +class Value { + x = 1; +} + +const value = new Value(); +Object.defineProperty(value, "x", { + get() { + return 2; + }, +}); +console.log(value.x); diff --git a/tests/diagnostics/maybe-promise-fences.ts b/tests/diagnostics/maybe-promise-fences.ts index efe541c9e..1dcccaf08 100644 --- a/tests/diagnostics/maybe-promise-fences.ts +++ b/tests/diagnostics/maybe-promise-fences.ts @@ -30,8 +30,3 @@ console.log(typeof widened); // `instanceof Promise` on a value that is never a promise. const record = { v: 1 }; console.log(record instanceof Promise); - -// A variadic `unknown[]` slot takes closures with the same variadic ABI. -type HandlerFn = (...args: unknown[]) => Promise; -const fixed: HandlerFn = async (first: unknown) => first; -fixed(1, 2).then((v) => console.log(v)); diff --git a/tests/diagnostics/mock-fences.ts b/tests/diagnostics/mock-fences.ts index 4425dfa5f..ef92f366f 100644 --- a/tests/diagnostics/mock-fences.ts +++ b/tests/diagnostics/mock-fences.ts @@ -1,8 +1,9 @@ -// node:test mocks lower for mock.fn(original[, implementation]), +// node:test mocks lower for mock.fn([original[, implementation]]), // mock.method(object, methodName[, implementation]) on records, their // t.mock twins, and the trackers' restoreAll and reset. The rest of the // mock surface is refused, each with a named diagnostic: mock.fn() without -// an original; mock.method on a class instance or a builtin object, with +// an original for a function type whose return type does not include +// undefined; mock.method on a class instance or a builtin object, with // an options object, or with an implementation of another type when the // result is used; and functions whose union return type has no undefined // arm (the calls log records undefined for calls that throw). @@ -11,8 +12,11 @@ import { mock, test } from "node:test"; const add = mock.fn((a: number, b: number) => a + b); // lowers add(1, 2); -const empty = mock.fn(); // no original function -empty(); +const empty = mock.fn(); // lowers +empty(1, "two"); + +const counted = mock.fn<() => number>(); // no original, returns number +counted(); const obj = { value: () => 1 }; mock.method(obj, "value"); // lowers diff --git a/tests/fixtures/esm-path-globals/lib/helper.ts b/tests/fixtures/esm-path-globals/lib/helper.ts new file mode 100644 index 000000000..61960c097 --- /dev/null +++ b/tests/fixtures/esm-path-globals/lib/helper.ts @@ -0,0 +1,2 @@ +export const helperDir: string = __dirname; +export const helperFile: string = __filename; diff --git a/tests/fixtures/esm-path-globals/main.ts b/tests/fixtures/esm-path-globals/main.ts new file mode 100644 index 000000000..d3d3c3b8a --- /dev/null +++ b/tests/fixtures/esm-path-globals/main.ts @@ -0,0 +1,12 @@ +// __dirname and __filename in TypeScript files with import syntax: each +// module reads its own source location, the same strings as +// import.meta.dirname and import.meta.filename. +import { basename, join } from "node:path"; +import { helperDir, helperFile } from "./lib/helper.ts"; + +console.log(typeof __dirname, typeof __filename); +console.log(basename(__dirname), basename(__filename)); +console.log(__dirname === import.meta.dirname, __filename === import.meta.filename); +console.log(join(__dirname, "lib") === helperDir, basename(helperFile)); +const home = typeof __dirname === "string" && __dirname.endsWith("/lib") ? join(__dirname, "..") : "/tmp"; +console.log(home); diff --git a/tests/fixtures/node-test/cases/mock-fn-default.ts b/tests/fixtures/node-test/cases/mock-fn-default.ts new file mode 100644 index 000000000..4666dfa5e --- /dev/null +++ b/tests/fixtures/node-test/cases/mock-fn-default.ts @@ -0,0 +1,72 @@ +// mock.fn() and t.mock.fn() without an original: the mock returns +// undefined and records the arguments of each call, whatever its callers +// pass. mockImplementation and mockImplementationOnce replace its +// behavior, and restore() brings back the function that returns undefined. +// mock.fn() records F's parameters, for a function type whose return +// type is void or includes undefined. +import assert from "node:assert"; +import { mock, test } from "node:test"; + +test("records calls with any arguments", () => { + const fn = mock.fn(); + fn(1, "two"); + fn(); + fn(true, null, [3]); + assert.strictEqual(fn.mock.callCount(), 3); + const [first, second, third] = fn.mock.calls; + assert.deepStrictEqual(first!.arguments, [1, "two"]); + assert.strictEqual(second!.arguments.length, 0); + assert.deepStrictEqual(third!.arguments, [true, null, [3]]); + assert.ok(first!.result === undefined); + assert.ok(first!.error === undefined); + assert.ok(first!.this === undefined); +}); + +test("changes implementations", () => { + const seen: string[] = []; + const fn = mock.fn(); + fn.mock.mockImplementation((...args: unknown[]) => { + seen.push(`impl ${args.length}`); + return undefined; + }); + fn.mock.mockImplementationOnce(() => { + seen.push("once"); + return undefined; + }); + fn("a"); + fn("a", "b"); + fn.mock.restore(); + fn("c"); + assert.deepStrictEqual(seen, ["once", "impl 2"]); + assert.strictEqual(fn.mock.callCount(), 3); + fn.mock.resetCalls(); + assert.strictEqual(fn.mock.callCount(), 0); +}); + +test("records a throwing implementation", () => { + const fn = mock.fn(); + fn.mock.mockImplementation(() => { + throw new Error("boom"); + }); + assert.throws(() => fn(7), { message: "boom" }); + const call = fn.mock.calls[0]!; + assert.deepStrictEqual(call.arguments, [7]); + assert.ok(call.error instanceof Error); +}); + +test("t.mock.fn() and typed mock.fn()", (t) => { + const fn = t.mock.fn(); + fn("x"); + assert.strictEqual(fn.mock.callCount(), 1); + const typed = t.mock.fn<(a: number, b: string) => void>(); + typed(1, "x"); + typed(2, "y"); + assert.strictEqual(typed.mock.callCount(), 2); + assert.strictEqual(typed.mock.calls[1]!.arguments[0], 2); + assert.strictEqual(typed.mock.calls[1]!.arguments[1], "y"); + const maybe = t.mock.fn<() => number | undefined>(); + assert.ok(maybe() === undefined); + maybe.mock.mockImplementation(() => 4); + assert.ok(maybe() === 4); + assert.ok(maybe.mock.calls[1]!.result === 4); +}); diff --git a/tests/fixtures/node-types/promisify-callback-functions.ts b/tests/fixtures/node-types/promisify-callback-functions.ts new file mode 100644 index 000000000..78be5e3bd --- /dev/null +++ b/tests/fixtures/node-types/promisify-callback-functions.ts @@ -0,0 +1,67 @@ +// util.promisify over typed callback-last functions with leading arguments +// under @types/node: bound methods, a function declaration, rejection from +// the callback error, a synchronous throw, and asynchronous settlement. +import { promisify } from "node:util"; + +class Client { + private closed = false; + private readonly name: string; + constructor(name: string) { + this.name = name; + } + close(callback: (error?: Error) => void): void { + setTimeout(() => { + if (this.closed) { + callback(new Error(`${this.name} already closed`)); + return; + } + this.closed = true; + callback(); + }, 1); + } + fetch(key: string, callback: (error: Error | null, value?: string) => void): void { + setImmediate(() => { + if (key === "") callback(new RangeError("empty key")); + else callback(null, `${this.name}:${key}`); + }); + } +} + +function sum(a: number, b: number, done: (err: Error | null, total: number) => void): void { + if (a < 0) throw new TypeError("negative"); + process.nextTick(() => done(null, a + b)); +} + +async function main(): Promise { + const c = new Client("db"); + const closeAsync = promisify(c.close.bind(c)); + await closeAsync(); + console.log("closed once"); + try { + await closeAsync(); + } catch (e) { + console.log("second close:", (e as Error).message); + } + const fetchAsync = promisify(c.fetch.bind(c)); + console.log(await fetchAsync("k")); + try { + await fetchAsync(""); + } catch (e) { + console.log("fetch:", (e as Error).name, (e as Error).message); + } + const sumAsync = promisify(sum); + console.log("sum", await sumAsync(2, 3)); + try { + await sumAsync(-1, 3); + } catch (e) { + console.log("sync throw:", (e as Error).name, (e as Error).message); + } + await promisify(new Client("inline").close.bind(new Client("inline")))(); + console.log("inline done"); + const order: string[] = []; + const p = sumAsync(1, 1).then((v) => order.push(`then ${v}`)); + order.push("after call"); + await p; + console.log(order.join(", ")); +} +void main(); diff --git a/tests/fixtures/node-types/stream-subclass-hooks.ts b/tests/fixtures/node-types/stream-subclass-hooks.ts new file mode 100644 index 000000000..0e7cfbad5 --- /dev/null +++ b/tests/fixtures/node-types/stream-subclass-hooks.ts @@ -0,0 +1,46 @@ +// Stream subclasses under @types/node: a Writable whose hooks declare a +// supertype of Node's chunk type, a Transform, and an erroring Writable. +import { Transform, Writable } from "node:stream"; + +class LineSink extends Writable { + private rest = ""; + readonly lines: string[] = []; + _write(chunk: Buffer | string, encoding: BufferEncoding, cb: (err?: Error | null) => void): void { + console.log("chunk", typeof chunk, Buffer.isBuffer(chunk), encoding); + const parts = (this.rest + chunk.toString()).split("\n"); + this.rest = parts.pop() ?? ""; + this.lines.push(...parts); + cb(); + } + _final(cb: (err?: Error | null) => void): void { + if (this.rest !== "") this.lines.push(this.rest); + cb(); + } +} + +class Upper extends Transform { + _transform(chunk: string | Buffer, _enc: string, cb: (err?: Error | null, data?: string) => void): void { + cb(null, chunk.toString().toUpperCase()); + } +} + +class Failing extends Writable { + _write(chunk: Uint8Array | string, _enc: BufferEncoding, cb: (err?: Error | null) => void): void { + cb(new Error(`refused ${chunk.toString().length} bytes`)); + } +} + +const sink = new LineSink(); +sink.write("a\nb"); +sink.write(Buffer.from("c\nd")); +sink.end("e"); +sink.on("finish", () => console.log("lines", JSON.stringify(sink.lines))); + +const up = new Upper(); +up.on("data", (d: Buffer) => console.log("upper", d.toString())); +up.write("hello "); +up.end("world"); + +const bad = new Failing(); +bad.on("error", (e) => console.log("error", e.message)); +bad.write("xyz"); diff --git a/tests/fixtures/npm/cases/2558-bundled-chunks/main.ts b/tests/fixtures/npm/cases/2558-bundled-chunks/main.ts new file mode 100644 index 000000000..5cbbc3dbc --- /dev/null +++ b/tests/fixtures/npm/cases/2558-bundled-chunks/main.ts @@ -0,0 +1,29 @@ +// esbuild's bundled CommonJS chunks: each package below is real esbuild +// output (0.25 unminified, 0.25 whitespace+syntax minified, 0.17) of one +// source that bundles CommonJS modules through the __commonJS helper. +// Every chunk compiles as its own CommonJS module: it runs once, at its +// first require (the top-level interop imports run while the bundle +// loads; `lazy` requires its chunk only when called), chunk-to-chunk +// requires share one module instance, an esbuild-built dist bundled as a +// chunk keeps its suffixed helpers, and the external dependency passes +// through the __toESM interop. gtcjsdist is a "type": "module" package +// whose CommonJS entry is a .cjs bundle using the node-mode interop. +import { describe, external, lazy, nested } from "gtchunk"; +import { describe as dws, external as ews, lazy as lws, nested as nws } from "gtchunkws"; +import { describe as d17, external as e17, lazy as l17, nested as n17 } from "gtchunk17"; +import { viaNodeMode } from "gtcjsdist"; + +console.log("main start"); +console.log("plain", describe()); +console.log("plain", external()); +console.log("plain", nested()); +console.log("plain", lazy(), lazy()); +console.log("minified", dws()); +console.log("minified", ews()); +console.log("minified", nws()); +console.log("minified", lws(), lws()); +console.log("older", d17()); +console.log("older", e17()); +console.log("older", n17()); +console.log("older", l17(), l17()); +console.log(viaNodeMode()); diff --git a/tests/fixtures/npm/cases/2559-cjs-cycle/main.ts b/tests/fixtures/npm/cases/2559-cjs-cycle/main.ts new file mode 100644 index 000000000..042102b64 --- /dev/null +++ b/tests/fixtures/npm/cases/2559-cjs-cycle/main.ts @@ -0,0 +1,11 @@ +// A require cycle between esbuild's per-file CommonJS outputs (index ↔ +// merge, index ↔ append). Each file installs its live getter table +// before its first require, so a partner that loads while index.js is +// still initializing sees index's partially initialized exports, and both +// partners call back into index from their functions. index.js re-exports +// mergeAll from merge.js through its getter table. +import { run, mergeAll } from "gtcycle"; + +console.log(run([" a ", "", "@x"], ["b", "@keep"])); +console.log(run(["c"], [])); +console.log(mergeAll(["@keep", " d"], ["@drop"]).join("|")); diff --git a/tests/fixtures/npm/cases/2560-cjs-cycle-partner-first/main.ts b/tests/fixtures/npm/cases/2560-cjs-cycle-partner-first/main.ts new file mode 100644 index 000000000..1ed90d432 --- /dev/null +++ b/tests/fixtures/npm/cases/2560-cjs-cycle-partner-first/main.ts @@ -0,0 +1,11 @@ +// The same esbuild CommonJS cycle entered through a partner: merge.js +// loads first, requires index.js, which requires merge.js back while +// merge is still initializing (its getter table is already installed) and +// re-exports mergeAll from it: the re-export reads merge's hoisted +// function while merge is still initializing. +import { mergeAll } from "gtcycle/dist/merge.js"; +import { run, mergeAll as reexported } from "gtcycle"; + +console.log(mergeAll([" x "], ["@keep"]).join(",")); +console.log(reexported === mergeAll); +console.log(run(["y"], ["@z"])); diff --git a/tests/fixtures/npm/cases/2561-cjs-cycle-early-read/main.ts b/tests/fixtures/npm/cases/2561-cjs-cycle-early-read/main.ts new file mode 100644 index 000000000..3efeb9eb1 --- /dev/null +++ b/tests/fixtures/npm/cases/2561-cjs-cycle-early-read/main.ts @@ -0,0 +1,6 @@ +// A require cycle whose partner reads a const export of index.js while +// index is still initializing: Node throws a ReferenceError (the binding +// is in its temporal dead zone), and scriptc refuses the cycle. +import { show } from "gtcyclebad"; + +console.log(show()); diff --git a/tests/fixtures/npm/cases/2562-subpath-leaf/main.ts b/tests/fixtures/npm/cases/2562-subpath-leaf/main.ts new file mode 100644 index 000000000..b34359cc7 --- /dev/null +++ b/tests/fixtures/npm/cases/2562-subpath-leaf/main.ts @@ -0,0 +1,10 @@ +// The program reaches gtsubpath only through its leaf data module (and a +// type from its main entry). The main entry reaches a file whose bundler +// interop the recognizer cannot verify, but no compiled code can load it, +// so the package compiles: a package is judged by what its imported +// subpaths reach. +import type { Manager } from "gtsubpath"; +import { managers } from "gtsubpath/dist/data.js"; + +const names: Manager[] = managers.filter((m) => m.lockfile.endsWith(".yaml")); +console.log(managers.length, names.map((m) => m.name).join(",")); diff --git a/tests/fixtures/npm/cases/2564-chunk-helper-shadowing/main.ts b/tests/fixtures/npm/cases/2564-chunk-helper-shadowing/main.ts new file mode 100644 index 000000000..d52b3731d --- /dev/null +++ b/tests/fixtures/npm/cases/2564-chunk-helper-shadowing/main.ts @@ -0,0 +1,7 @@ +// A bundled CommonJS chunk that calls the bundle's top-level `label` while +// a nested function of the chunk declares its own `label`: the chunk +// carries the top-level function along, and each reference keeps its own +// binding. +import { inner, outer } from "gtchunkshadow"; + +console.log(outer(), inner()); diff --git a/tests/fixtures/npm/cases/2565-chunk-shared-function/main.ts b/tests/fixtures/npm/cases/2565-chunk-shared-function/main.ts new file mode 100644 index 000000000..21ca81b40 --- /dev/null +++ b/tests/fixtures/npm/cases/2565-chunk-shared-function/main.ts @@ -0,0 +1,7 @@ +// Two bundled CommonJS chunks export the bundle's top-level `tally` and +// count calls on a property of it. Node prints "1 2 true": both chunks +// share one function. A per-chunk copy would split its identity and its +// properties, so the package stays refused. +import { counts, same } from "gtchunkshared"; + +console.log(counts(), same()); diff --git a/tests/fixtures/npm/cases/2566-cjs-cycle-indirect-call/main.ts b/tests/fixtures/npm/cases/2566-cjs-cycle-indirect-call/main.ts new file mode 100644 index 000000000..3cca145e0 --- /dev/null +++ b/tests/fixtures/npm/cases/2566-cjs-cycle-indirect-call/main.ts @@ -0,0 +1,7 @@ +// A require cycle whose partner calls an export of index.js with esbuild's +// `(0, import_index.peek)()` spelling while index is still initializing: +// peek reads a const in its temporal dead zone, so Node throws a +// ReferenceError, and scriptc refuses the cycle. +import { show } from "gtcyclecall"; + +console.log(show()); diff --git a/tests/fixtures/npm/cases/2571-cjs-cycle-stored-function/main.ts b/tests/fixtures/npm/cases/2571-cjs-cycle-stored-function/main.ts new file mode 100644 index 000000000..ae2be341a --- /dev/null +++ b/tests/fixtures/npm/cases/2571-cjs-cycle-stored-function/main.ts @@ -0,0 +1,8 @@ +// Require cycles whose partner stores an export of index.js (in a const, +// or in an object literal) and calls it while index is still +// initializing: the export reads a const in its temporal dead zone, so +// Node throws a ReferenceError, and scriptc refuses both cycles. +import { show } from "gtcyclealias"; +import { show as showBox } from "gtcyclebox"; + +console.log(show(), showBox()); diff --git a/tests/fixtures/npm/node_modules/gtchunk/dist/index.d.ts b/tests/fixtures/npm/node_modules/gtchunk/dist/index.d.ts new file mode 100644 index 000000000..bd3d4e582 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunk/dist/index.d.ts @@ -0,0 +1,4 @@ +export declare function describe(): string; +export declare function external(): string; +export declare function nested(): string; +export declare function lazy(): string; diff --git a/tests/fixtures/npm/node_modules/gtchunk/dist/index.js b/tests/fixtures/npm/node_modules/gtchunk/dist/index.js new file mode 100644 index 000000000..7820e3ae4 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunk/dist/index.js @@ -0,0 +1,132 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// chunk/vendor/settings/counter.js +var require_counter = __commonJS({ + "chunk/vendor/settings/counter.js"(exports2, module2) { + var n = 0; + console.log("counter init"); + module2.exports = { + next() { + n += 1; + return n; + } + }; + } +}); + +// chunk/vendor/settings/index.js +var require_settings = __commonJS({ + "chunk/vendor/settings/index.js"(exports2) { + "use strict"; + console.log("settings init"); + var counter = require_counter(); + exports2.LABEL = "bundled"; + exports2.VERSION = 2; + exports2.bump = function() { + return counter.next(); + }; + } +}); + +// chunk/vendor/prebuilt/index.js +var require_prebuilt = __commonJS({ + "chunk/vendor/prebuilt/index.js"(exports2, module2) { + var __defProp2 = Object.defineProperty; + var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor; + var __getOwnPropNames2 = Object.getOwnPropertyNames; + var __hasOwnProp2 = Object.prototype.hasOwnProperty; + var __export2 = (target, all) => { + for (var name in all) + __defProp2(target, name, { get: all[name], enumerable: true }); + }; + var __copyProps2 = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames2(from)) + if (!__hasOwnProp2.call(to, key) && key !== except) + __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable }); + } + return to; + }; + var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod); + var prebuilt_exports = {}; + __export2(prebuilt_exports, { + PREBUILT_TAG: () => PREBUILT_TAG2, + greet: () => greet2 + }); + module2.exports = __toCommonJS2(prebuilt_exports); + function greet2(name) { + return "hello " + name; + } + var PREBUILT_TAG2 = "prebuilt"; + } +}); + +// chunk/vendor/lazy.js +var require_lazy = __commonJS({ + "chunk/vendor/lazy.js"(exports2, module2) { + console.log("lazy init"); + module2.exports = { value: "lazy-value" }; + } +}); + +// chunk/src/index.ts +var index_exports = {}; +__export(index_exports, { + describe: () => describe, + external: () => external, + lazy: () => lazy, + nested: () => nested +}); +module.exports = __toCommonJS(index_exports); +var import_settings = __toESM(require_settings()); +var core = __toESM(require("gtcore")); +var import_gtcore = __toESM(require("gtcore")); +var import_prebuilt = __toESM(require_prebuilt()); +function describe() { + return import_settings.LABEL + "@" + import_settings.default.VERSION + " bump " + (0, import_settings.bump)() + " " + (0, import_settings.bump)(); +} +function external() { + return core.tag + ":" + core.label(1) + ":" + import_gtcore.default.label(2); +} +function nested() { + return (0, import_prebuilt.greet)("chunk") + " " + import_prebuilt.PREBUILT_TAG; +} +function lazy() { + return require_lazy().value; +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + describe, + external, + lazy, + nested +}); diff --git a/tests/fixtures/npm/node_modules/gtchunk/package.json b/tests/fixtures/npm/node_modules/gtchunk/package.json new file mode 100644 index 000000000..2812a5188 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunk/package.json @@ -0,0 +1,10 @@ +{ + "name": "gtchunk", + "version": "1.0.0", + "description": "esbuild 0.25.10 output (--bundle --platform=node --format=cjs --external:gtcore): bundled CommonJS modules behind the __commonJS helper, including an esbuild-built dist with suffixed helpers", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "dependencies": { + "gtcore": "1.0.0" + } +} diff --git a/tests/fixtures/npm/node_modules/gtchunk17/dist/index.d.ts b/tests/fixtures/npm/node_modules/gtchunk17/dist/index.d.ts new file mode 100644 index 000000000..bd3d4e582 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunk17/dist/index.d.ts @@ -0,0 +1,4 @@ +export declare function describe(): string; +export declare function external(): string; +export declare function nested(): string; +export declare function lazy(): string; diff --git a/tests/fixtures/npm/node_modules/gtchunk17/dist/index.js b/tests/fixtures/npm/node_modules/gtchunk17/dist/index.js new file mode 100644 index 000000000..afda6af56 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunk17/dist/index.js @@ -0,0 +1,132 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// chunk/vendor/settings/counter.js +var require_counter = __commonJS({ + "chunk/vendor/settings/counter.js"(exports, module2) { + var n = 0; + console.log("counter init"); + module2.exports = { + next() { + n += 1; + return n; + } + }; + } +}); + +// chunk/vendor/settings/index.js +var require_settings = __commonJS({ + "chunk/vendor/settings/index.js"(exports) { + "use strict"; + console.log("settings init"); + var counter = require_counter(); + exports.LABEL = "bundled"; + exports.VERSION = 2; + exports.bump = function() { + return counter.next(); + }; + } +}); + +// chunk/vendor/prebuilt/index.js +var require_prebuilt = __commonJS({ + "chunk/vendor/prebuilt/index.js"(exports, module2) { + var __defProp2 = Object.defineProperty; + var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor; + var __getOwnPropNames2 = Object.getOwnPropertyNames; + var __hasOwnProp2 = Object.prototype.hasOwnProperty; + var __export2 = (target, all) => { + for (var name in all) + __defProp2(target, name, { get: all[name], enumerable: true }); + }; + var __copyProps2 = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames2(from)) + if (!__hasOwnProp2.call(to, key) && key !== except) + __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable }); + } + return to; + }; + var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod); + var prebuilt_exports = {}; + __export2(prebuilt_exports, { + PREBUILT_TAG: () => PREBUILT_TAG2, + greet: () => greet2 + }); + module2.exports = __toCommonJS2(prebuilt_exports); + function greet2(name) { + return "hello " + name; + } + var PREBUILT_TAG2 = "prebuilt"; + } +}); + +// chunk/vendor/lazy.js +var require_lazy = __commonJS({ + "chunk/vendor/lazy.js"(exports, module2) { + console.log("lazy init"); + module2.exports = { value: "lazy-value" }; + } +}); + +// chunk/src/index.ts +var src_exports = {}; +__export(src_exports, { + describe: () => describe, + external: () => external, + lazy: () => lazy, + nested: () => nested +}); +module.exports = __toCommonJS(src_exports); +var import_settings = __toESM(require_settings()); +var core = __toESM(require("gtcore")); +var import_gtcore = __toESM(require("gtcore")); +var import_prebuilt = __toESM(require_prebuilt()); +function describe() { + return import_settings.LABEL + "@" + import_settings.default.VERSION + " bump " + (0, import_settings.bump)() + " " + (0, import_settings.bump)(); +} +function external() { + return core.tag + ":" + core.label(1) + ":" + import_gtcore.default.label(2); +} +function nested() { + return (0, import_prebuilt.greet)("chunk") + " " + import_prebuilt.PREBUILT_TAG; +} +function lazy() { + return require_lazy().value; +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + describe, + external, + lazy, + nested +}); diff --git a/tests/fixtures/npm/node_modules/gtchunk17/package.json b/tests/fixtures/npm/node_modules/gtchunk17/package.json new file mode 100644 index 000000000..73761f181 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunk17/package.json @@ -0,0 +1,10 @@ +{ + "name": "gtchunk17", + "version": "1.0.0", + "description": "the gtchunk source bundled by esbuild 0.17.19: chunk factories take (exports, module2)", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "dependencies": { + "gtcore": "1.0.0" + } +} diff --git a/tests/fixtures/npm/node_modules/gtchunkshadow/dist/index.d.ts b/tests/fixtures/npm/node_modules/gtchunkshadow/dist/index.d.ts new file mode 100644 index 000000000..238cf1744 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunkshadow/dist/index.d.ts @@ -0,0 +1,2 @@ +export declare function outer(): string; +export declare function inner(): string; diff --git a/tests/fixtures/npm/node_modules/gtchunkshadow/dist/index.js b/tests/fixtures/npm/node_modules/gtchunkshadow/dist/index.js new file mode 100644 index 000000000..0f89c7ec5 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunkshadow/dist/index.js @@ -0,0 +1,52 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +function label(n) { + return "label " + n; +} + +// chunk/vendor/shadow.js +var require_shadow = __commonJS({ + "chunk/vendor/shadow.js"(exports2, module2) { + function nested() { + var label = "nested"; + return label; + } + module2.exports = { outer: label(1), inner: nested() }; + } +}); + +// chunk/src/index.ts +var index_exports = {}; +__export(index_exports, { + inner: () => inner, + outer: () => outer +}); +module.exports = __toCommonJS(index_exports); +function outer() { + return require_shadow().outer; +} +function inner() { + return require_shadow().inner; +} +0 && (module.exports = { + inner, + outer +}); diff --git a/tests/fixtures/npm/node_modules/gtchunkshadow/package.json b/tests/fixtures/npm/node_modules/gtchunkshadow/package.json new file mode 100644 index 000000000..6830fbd2c --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunkshadow/package.json @@ -0,0 +1,7 @@ +{ + "name": "gtchunkshadow", + "version": "1.0.0", + "description": "esbuild's CommonJS bundle shape: a chunk calls a top-level function whose name a nested scope of the chunk also declares", + "main": "./dist/index.js", + "types": "./dist/index.d.ts" +} diff --git a/tests/fixtures/npm/node_modules/gtchunkshared/dist/index.d.ts b/tests/fixtures/npm/node_modules/gtchunkshared/dist/index.d.ts new file mode 100644 index 000000000..3a47a0495 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunkshared/dist/index.d.ts @@ -0,0 +1,2 @@ +export declare function same(): boolean; +export declare function counts(): string; diff --git a/tests/fixtures/npm/node_modules/gtchunkshared/dist/index.js b/tests/fixtures/npm/node_modules/gtchunkshared/dist/index.js new file mode 100644 index 000000000..0d3aacec8 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunkshared/dist/index.js @@ -0,0 +1,56 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +function tally() { + tally.calls = (tally.calls || 0) + 1; + return tally.calls; +} + +// chunk/vendor/a.js +var require_a = __commonJS({ + "chunk/vendor/a.js"(exports2, module2) { + module2.exports = { tally, first: tally() }; + } +}); + +// chunk/vendor/b.js +var require_b = __commonJS({ + "chunk/vendor/b.js"(exports2, module2) { + module2.exports = { tally, second: tally() }; + } +}); + +// chunk/src/index.ts +var index_exports = {}; +__export(index_exports, { + counts: () => counts, + same: () => same +}); +module.exports = __toCommonJS(index_exports); +function same() { + return require_a().tally === require_b().tally; +} +function counts() { + return require_a().first + " " + require_b().second; +} +0 && (module.exports = { + counts, + same +}); diff --git a/tests/fixtures/npm/node_modules/gtchunkshared/package.json b/tests/fixtures/npm/node_modules/gtchunkshared/package.json new file mode 100644 index 000000000..bfc90c5d2 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunkshared/package.json @@ -0,0 +1,7 @@ +{ + "name": "gtchunkshared", + "version": "1.0.0", + "description": "esbuild's CommonJS bundle shape: two chunks export one top-level function and count calls on a property of it", + "main": "./dist/index.js", + "types": "./dist/index.d.ts" +} diff --git a/tests/fixtures/npm/node_modules/gtchunkws/dist/index.d.ts b/tests/fixtures/npm/node_modules/gtchunkws/dist/index.d.ts new file mode 100644 index 000000000..bd3d4e582 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunkws/dist/index.d.ts @@ -0,0 +1,4 @@ +export declare function describe(): string; +export declare function external(): string; +export declare function nested(): string; +export declare function lazy(): string; diff --git a/tests/fixtures/npm/node_modules/gtchunkws/dist/index.js b/tests/fixtures/npm/node_modules/gtchunkws/dist/index.js new file mode 100644 index 000000000..f022baf09 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunkws/dist/index.js @@ -0,0 +1 @@ +var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __commonJS=(cb,mod)=>function(){return mod||(0,cb[__getOwnPropNames(cb)[0]])((mod={exports:{}}).exports,mod),mod.exports};var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod)),__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var require_counter=__commonJS({"chunk/vendor/settings/counter.js"(exports2,module2){var n=0;console.log("counter init");module2.exports={next(){return n+=1,n}}}});var require_settings=__commonJS({"chunk/vendor/settings/index.js"(exports2){"use strict";console.log("settings init");var counter=require_counter();exports2.LABEL="bundled";exports2.VERSION=2;exports2.bump=function(){return counter.next()}}});var require_prebuilt=__commonJS({"chunk/vendor/prebuilt/index.js"(exports2,module2){var __defProp2=Object.defineProperty,__getOwnPropDesc2=Object.getOwnPropertyDescriptor,__getOwnPropNames2=Object.getOwnPropertyNames,__hasOwnProp2=Object.prototype.hasOwnProperty,__export2=(target,all)=>{for(var name in all)__defProp2(target,name,{get:all[name],enumerable:!0})},__copyProps2=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames2(from))!__hasOwnProp2.call(to,key)&&key!==except&&__defProp2(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc2(from,key))||desc.enumerable});return to},__toCommonJS2=mod=>__copyProps2(__defProp2({},"__esModule",{value:!0}),mod),prebuilt_exports={};__export2(prebuilt_exports,{PREBUILT_TAG:()=>PREBUILT_TAG2,greet:()=>greet2});module2.exports=__toCommonJS2(prebuilt_exports);function greet2(name){return"hello "+name}var PREBUILT_TAG2="prebuilt"}});var require_lazy=__commonJS({"chunk/vendor/lazy.js"(exports2,module2){console.log("lazy init");module2.exports={value:"lazy-value"}}});var index_exports={};__export(index_exports,{describe:()=>describe,external:()=>external,lazy:()=>lazy,nested:()=>nested});module.exports=__toCommonJS(index_exports);var import_settings=__toESM(require_settings()),core=__toESM(require("gtcore")),import_gtcore=__toESM(require("gtcore")),import_prebuilt=__toESM(require_prebuilt());function describe(){return import_settings.LABEL+"@"+import_settings.default.VERSION+" bump "+(0,import_settings.bump)()+" "+(0,import_settings.bump)()}function external(){return core.tag+":"+core.label(1)+":"+import_gtcore.default.label(2)}function nested(){return(0,import_prebuilt.greet)("chunk")+" "+import_prebuilt.PREBUILT_TAG}function lazy(){return require_lazy().value}0&&(module.exports={describe,external,lazy,nested}); diff --git a/tests/fixtures/npm/node_modules/gtchunkws/package.json b/tests/fixtures/npm/node_modules/gtchunkws/package.json new file mode 100644 index 000000000..5502f80a0 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtchunkws/package.json @@ -0,0 +1,10 @@ +{ + "name": "gtchunkws", + "version": "1.0.0", + "description": "the gtchunk source bundled by esbuild 0.25.10 with --minify-whitespace --minify-syntax: helpers share var statements", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "dependencies": { + "gtcore": "1.0.0" + } +} diff --git a/tests/fixtures/npm/node_modules/gtcjsdist/dist/index.cjs b/tests/fixtures/npm/node_modules/gtcjsdist/dist/index.cjs new file mode 100644 index 000000000..8836b5691 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcjsdist/dist/index.cjs @@ -0,0 +1,43 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// cjsdist/src/index.ts +var index_exports = {}; +__export(index_exports, { + viaNodeMode: () => viaNodeMode +}); +module.exports = __toCommonJS(index_exports); +var core = __toESM(require("gtcore"), 1); +var import_gtcore = __toESM(require("gtcore"), 1); +function viaNodeMode() { + return import_gtcore.default.tag + "/" + core.label(7) + "/" + import_gtcore.default.label(8); +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + viaNodeMode +}); diff --git a/tests/fixtures/npm/node_modules/gtcjsdist/dist/index.d.cts b/tests/fixtures/npm/node_modules/gtcjsdist/dist/index.d.cts new file mode 100644 index 000000000..6f77b9943 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcjsdist/dist/index.d.cts @@ -0,0 +1 @@ +export declare function viaNodeMode(): string; diff --git a/tests/fixtures/npm/node_modules/gtcjsdist/package.json b/tests/fixtures/npm/node_modules/gtcjsdist/package.json new file mode 100644 index 000000000..8b416fca1 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcjsdist/package.json @@ -0,0 +1,11 @@ +{ + "name": "gtcjsdist", + "version": "1.0.0", + "description": "a type-module package whose CommonJS entry is an esbuild 0.25.10 .cjs bundle using the node-mode __toESM interop", + "type": "module", + "main": "./dist/index.cjs", + "types": "./dist/index.d.cts", + "dependencies": { + "gtcore": "1.0.0" + } +} diff --git a/tests/fixtures/npm/node_modules/gtcycle/dist/append.d.ts b/tests/fixtures/npm/node_modules/gtcycle/dist/append.d.ts new file mode 100644 index 000000000..e33c31f90 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcycle/dist/append.d.ts @@ -0,0 +1 @@ +export declare function appendAll(xs: string[], tail: string): string[]; diff --git a/tests/fixtures/npm/node_modules/gtcycle/dist/append.js b/tests/fixtures/npm/node_modules/gtcycle/dist/append.js new file mode 100644 index 000000000..cdfeb6c6c --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcycle/dist/append.js @@ -0,0 +1,30 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var append_exports = {}; +__export(append_exports, { + appendAll: () => appendAll +}); +module.exports = __toCommonJS(append_exports); +var import_index = require("./index"); +function appendAll(xs, tail) { + return xs.some(import_index.isHandler) ? xs : xs.concat([tail]); +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + appendAll +}); diff --git a/tests/fixtures/npm/node_modules/gtcycle/dist/index.d.ts b/tests/fixtures/npm/node_modules/gtcycle/dist/index.d.ts new file mode 100644 index 000000000..4b86308a9 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcycle/dist/index.d.ts @@ -0,0 +1,4 @@ +export { mergeAll } from "./merge"; +export declare function isHandler(x: string): boolean; +export declare function normalize(xs: string[]): string[]; +export declare function run(a: string[], b: string[]): string; diff --git a/tests/fixtures/npm/node_modules/gtcycle/dist/index.js b/tests/fixtures/npm/node_modules/gtcycle/dist/index.js new file mode 100644 index 000000000..92f6d2a39 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcycle/dist/index.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var index_exports = {}; +__export(index_exports, { + isHandler: () => isHandler, + mergeAll: () => import_merge2.mergeAll, + normalize: () => normalize, + run: () => run +}); +module.exports = __toCommonJS(index_exports); +var import_append = require("./append"); +var import_merge = require("./merge"); +var import_merge2 = require("./merge"); +function isHandler(x) { + return x.startsWith("@"); +} +function normalize(xs) { + return xs.map((x) => x.trim()).filter((x) => x.length > 0); +} +function run(a, b) { + return (0, import_append.appendAll)((0, import_merge.mergeAll)(a, b), "@end").join(","); +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + isHandler, + mergeAll, + normalize, + run +}); diff --git a/tests/fixtures/npm/node_modules/gtcycle/dist/merge.d.ts b/tests/fixtures/npm/node_modules/gtcycle/dist/merge.d.ts new file mode 100644 index 000000000..bbe6b6a4d --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcycle/dist/merge.d.ts @@ -0,0 +1 @@ +export declare function mergeAll(a: string[], b: string[]): string[]; diff --git a/tests/fixtures/npm/node_modules/gtcycle/dist/merge.js b/tests/fixtures/npm/node_modules/gtcycle/dist/merge.js new file mode 100644 index 000000000..114e7d8cf --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcycle/dist/merge.js @@ -0,0 +1,30 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var merge_exports = {}; +__export(merge_exports, { + mergeAll: () => mergeAll +}); +module.exports = __toCommonJS(merge_exports); +var import_index = require("./index"); +function mergeAll(a, b) { + return (0, import_index.normalize)(a.concat(b)).filter((x) => !(0, import_index.isHandler)(x) || x === "@keep"); +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + mergeAll +}); diff --git a/tests/fixtures/npm/node_modules/gtcycle/package.json b/tests/fixtures/npm/node_modules/gtcycle/package.json new file mode 100644 index 000000000..5b41b8a52 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcycle/package.json @@ -0,0 +1,7 @@ +{ + "name": "gtcycle", + "version": "1.0.0", + "description": "esbuild 0.25.10 per-file CommonJS output (no bundling) of three modules that import each other", + "main": "./dist/index.js", + "types": "./dist/index.d.ts" +} diff --git a/tests/fixtures/npm/node_modules/gtcyclealias/dist/index.d.ts b/tests/fixtures/npm/node_modules/gtcyclealias/dist/index.d.ts new file mode 100644 index 000000000..5f4373e2f --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclealias/dist/index.d.ts @@ -0,0 +1,3 @@ +export declare const LIMIT = 3; +export declare function show(): string; +export declare function peek(): number; diff --git a/tests/fixtures/npm/node_modules/gtcyclealias/dist/index.js b/tests/fixtures/npm/node_modules/gtcyclealias/dist/index.js new file mode 100644 index 000000000..77aca3c9b --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclealias/dist/index.js @@ -0,0 +1,37 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var index_exports = {}; +__export(index_exports, { + LIMIT: () => LIMIT, + peek: () => peek, + show: () => show +}); +module.exports = __toCommonJS(index_exports); +var import_reader = require("./reader"); +const LIMIT = 3; +function peek() { + return LIMIT; +} +function show() { + return (0, import_reader.describe)(); +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + LIMIT, + show +}); diff --git a/tests/fixtures/npm/node_modules/gtcyclealias/dist/reader.js b/tests/fixtures/npm/node_modules/gtcyclealias/dist/reader.js new file mode 100644 index 000000000..943e61a0a --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclealias/dist/reader.js @@ -0,0 +1,34 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var reader_exports = {}; +__export(reader_exports, { + captured: () => captured, + describe: () => describe +}); +module.exports = __toCommonJS(reader_exports); +var import_index = require("./index"); +const read = import_index.peek; +const captured = read(); +function describe() { + return "limit " + captured; +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + captured, + describe +}); diff --git a/tests/fixtures/npm/node_modules/gtcyclealias/package.json b/tests/fixtures/npm/node_modules/gtcyclealias/package.json new file mode 100644 index 000000000..9ee7441e0 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclealias/package.json @@ -0,0 +1,7 @@ +{ + "name": "gtcyclealias", + "version": "1.0.0", + "description": "esbuild 0.25.10 per-file CommonJS output shape of a cycle whose partner stores an exported function in a const and calls it while that function's const binding is uninitialized", + "main": "./dist/index.js", + "types": "./dist/index.d.ts" +} diff --git a/tests/fixtures/npm/node_modules/gtcyclebad/dist/index.d.ts b/tests/fixtures/npm/node_modules/gtcyclebad/dist/index.d.ts new file mode 100644 index 000000000..0fa366319 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclebad/dist/index.d.ts @@ -0,0 +1,2 @@ +export declare const LIMIT = 3; +export declare function show(): string; diff --git a/tests/fixtures/npm/node_modules/gtcyclebad/dist/index.js b/tests/fixtures/npm/node_modules/gtcyclebad/dist/index.js new file mode 100644 index 000000000..5bd708a37 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclebad/dist/index.js @@ -0,0 +1,33 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var index_exports = {}; +__export(index_exports, { + LIMIT: () => LIMIT, + show: () => show +}); +module.exports = __toCommonJS(index_exports); +var import_reader = require("./reader"); +const LIMIT = 3; +function show() { + return (0, import_reader.describe)(); +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + LIMIT, + show +}); diff --git a/tests/fixtures/npm/node_modules/gtcyclebad/dist/reader.js b/tests/fixtures/npm/node_modules/gtcyclebad/dist/reader.js new file mode 100644 index 000000000..a58bdaa51 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclebad/dist/reader.js @@ -0,0 +1,33 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var reader_exports = {}; +__export(reader_exports, { + captured: () => captured, + describe: () => describe +}); +module.exports = __toCommonJS(reader_exports); +var import_index = require("./index"); +const captured = import_index.LIMIT; +function describe() { + return "limit " + captured; +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + captured, + describe +}); diff --git a/tests/fixtures/npm/node_modules/gtcyclebad/package.json b/tests/fixtures/npm/node_modules/gtcyclebad/package.json new file mode 100644 index 000000000..793c97fc9 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclebad/package.json @@ -0,0 +1,7 @@ +{ + "name": "gtcyclebad", + "version": "1.0.0", + "description": "esbuild 0.25.10 per-file CommonJS output of a cycle whose partner reads a const binding before its declaration runs", + "main": "./dist/index.js", + "types": "./dist/index.d.ts" +} diff --git a/tests/fixtures/npm/node_modules/gtcyclebox/dist/index.d.ts b/tests/fixtures/npm/node_modules/gtcyclebox/dist/index.d.ts new file mode 100644 index 000000000..5f4373e2f --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclebox/dist/index.d.ts @@ -0,0 +1,3 @@ +export declare const LIMIT = 3; +export declare function show(): string; +export declare function peek(): number; diff --git a/tests/fixtures/npm/node_modules/gtcyclebox/dist/index.js b/tests/fixtures/npm/node_modules/gtcyclebox/dist/index.js new file mode 100644 index 000000000..77aca3c9b --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclebox/dist/index.js @@ -0,0 +1,37 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var index_exports = {}; +__export(index_exports, { + LIMIT: () => LIMIT, + peek: () => peek, + show: () => show +}); +module.exports = __toCommonJS(index_exports); +var import_reader = require("./reader"); +const LIMIT = 3; +function peek() { + return LIMIT; +} +function show() { + return (0, import_reader.describe)(); +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + LIMIT, + show +}); diff --git a/tests/fixtures/npm/node_modules/gtcyclebox/dist/reader.js b/tests/fixtures/npm/node_modules/gtcyclebox/dist/reader.js new file mode 100644 index 000000000..b8f8a927e --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclebox/dist/reader.js @@ -0,0 +1,34 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var reader_exports = {}; +__export(reader_exports, { + captured: () => captured, + describe: () => describe +}); +module.exports = __toCommonJS(reader_exports); +var import_index = require("./index"); +const box = { read: import_index.peek }; +const captured = box.read(); +function describe() { + return "limit " + captured; +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + captured, + describe +}); diff --git a/tests/fixtures/npm/node_modules/gtcyclebox/package.json b/tests/fixtures/npm/node_modules/gtcyclebox/package.json new file mode 100644 index 000000000..67f943195 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclebox/package.json @@ -0,0 +1,7 @@ +{ + "name": "gtcyclebox", + "version": "1.0.0", + "description": "esbuild 0.25.10 per-file CommonJS output shape of a cycle whose partner stores an exported function in an object literal and calls it while that function's const binding is uninitialized", + "main": "./dist/index.js", + "types": "./dist/index.d.ts" +} diff --git a/tests/fixtures/npm/node_modules/gtcyclecall/dist/index.d.ts b/tests/fixtures/npm/node_modules/gtcyclecall/dist/index.d.ts new file mode 100644 index 000000000..5f4373e2f --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclecall/dist/index.d.ts @@ -0,0 +1,3 @@ +export declare const LIMIT = 3; +export declare function show(): string; +export declare function peek(): number; diff --git a/tests/fixtures/npm/node_modules/gtcyclecall/dist/index.js b/tests/fixtures/npm/node_modules/gtcyclecall/dist/index.js new file mode 100644 index 000000000..77aca3c9b --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclecall/dist/index.js @@ -0,0 +1,37 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var index_exports = {}; +__export(index_exports, { + LIMIT: () => LIMIT, + peek: () => peek, + show: () => show +}); +module.exports = __toCommonJS(index_exports); +var import_reader = require("./reader"); +const LIMIT = 3; +function peek() { + return LIMIT; +} +function show() { + return (0, import_reader.describe)(); +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + LIMIT, + show +}); diff --git a/tests/fixtures/npm/node_modules/gtcyclecall/dist/reader.js b/tests/fixtures/npm/node_modules/gtcyclecall/dist/reader.js new file mode 100644 index 000000000..c98d1ae46 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclecall/dist/reader.js @@ -0,0 +1,33 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var reader_exports = {}; +__export(reader_exports, { + captured: () => captured, + describe: () => describe +}); +module.exports = __toCommonJS(reader_exports); +var import_index = require("./index"); +const captured = (0, import_index.peek)(); +function describe() { + return "limit " + captured; +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + captured, + describe +}); diff --git a/tests/fixtures/npm/node_modules/gtcyclecall/package.json b/tests/fixtures/npm/node_modules/gtcyclecall/package.json new file mode 100644 index 000000000..cc1069a6f --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtcyclecall/package.json @@ -0,0 +1,7 @@ +{ + "name": "gtcyclecall", + "version": "1.0.0", + "description": "esbuild 0.25.10 per-file CommonJS output shape of a cycle whose partner calls an exported function through (0, binding.fn)() while that function's const binding is uninitialized", + "main": "./dist/index.js", + "types": "./dist/index.d.ts" +} diff --git a/tests/fixtures/npm/node_modules/gtsubpath/dist/data.d.ts b/tests/fixtures/npm/node_modules/gtsubpath/dist/data.d.ts new file mode 100644 index 000000000..356c8bbc9 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtsubpath/dist/data.d.ts @@ -0,0 +1,2 @@ +import type { Manager } from "./index.js"; +export declare const managers: Manager[]; diff --git a/tests/fixtures/npm/node_modules/gtsubpath/dist/data.js b/tests/fixtures/npm/node_modules/gtsubpath/dist/data.js new file mode 100644 index 000000000..918a296a8 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtsubpath/dist/data.js @@ -0,0 +1,6 @@ +"use strict"; +exports.managers = [ + { name: "npm", lockfile: "package-lock.json" }, + { name: "pnpm", lockfile: "pnpm-lock.yaml" }, + { name: "yarn", lockfile: "yarn.lock" }, +]; diff --git a/tests/fixtures/npm/node_modules/gtsubpath/dist/detect.js b/tests/fixtures/npm/node_modules/gtsubpath/dist/detect.js new file mode 100644 index 000000000..d129041fe --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtsubpath/dist/detect.js @@ -0,0 +1,11 @@ +// A hand-rolled __toESM the recognizer cannot verify (see gtdrift). +"use strict"; +var __toESM = (mod) => { + var ns = { default: mod }; + for (var key in mod) ns[key] = mod[key]; + return ns; +}; +var import_gtcore = __toESM(require("gtcore")); +exports.detect = function detect(files) { + return import_gtcore.default.label(files.length); +}; diff --git a/tests/fixtures/npm/node_modules/gtsubpath/dist/index.d.ts b/tests/fixtures/npm/node_modules/gtsubpath/dist/index.d.ts new file mode 100644 index 000000000..24b05d86d --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtsubpath/dist/index.d.ts @@ -0,0 +1,6 @@ +export interface Manager { + name: string; + lockfile: string; +} +export declare const managers: Manager[]; +export declare function detect(files: string[]): string; diff --git a/tests/fixtures/npm/node_modules/gtsubpath/dist/index.js b/tests/fixtures/npm/node_modules/gtsubpath/dist/index.js new file mode 100644 index 000000000..a330d28c0 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtsubpath/dist/index.js @@ -0,0 +1,5 @@ +"use strict"; +const detect = require("./detect.js"); +const data = require("./data.js"); +exports.detect = detect.detect; +exports.managers = data.managers; diff --git a/tests/fixtures/npm/node_modules/gtsubpath/package.json b/tests/fixtures/npm/node_modules/gtsubpath/package.json new file mode 100644 index 000000000..f785cb154 --- /dev/null +++ b/tests/fixtures/npm/node_modules/gtsubpath/package.json @@ -0,0 +1,10 @@ +{ + "name": "gtsubpath", + "version": "1.0.0", + "description": "a package whose main entry reaches a file with bundler interop the recognizer cannot verify, beside a leaf data module the program imports by subpath", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "dependencies": { + "gtcore": "1.0.0" + } +} diff --git a/tests/harness/__snapshots__/boot-path-node-surface-fences.ts.txt b/tests/harness/__snapshots__/boot-path-node-surface-fences.ts.txt new file mode 100644 index 000000000..c287a1641 --- /dev/null +++ b/tests/harness/__snapshots__/boot-path-node-surface-fences.ts.txt @@ -0,0 +1,35 @@ +boot-path-node-surface-fences.ts:8:14 - error SC2020: 'process.send' is part of the standard library types but has no scriptc lowering yet + + 7 | + 8 | const send = process.send; + | ^~~~~~~~~~~~ + 9 | console.log(typeof send); + + hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) + +boot-path-node-surface-fences.ts:11:1 - error SC2020: 'a '_write' method whose parameter 0 is 'number' where Node passes 'Uint8Array'' is part of the standard library types but has no scriptc lowering yet + + 10 | + 11 | class Counter extends Writable { + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 12 | _write(chunk: number, _encoding: BufferEncoding, cb: (err?: Error | null) => void): void { + + hint: annotate the parameter with the Node signature's type or a supertype of it (chunks are Buffers here) + +boot-path-node-surface-fences.ts:22:31 - error SC2020: 'util.promisify of this target' is part of the standard library types but has no scriptc lowering yet + + 21 | } + 22 | const legacyAsync = promisify(legacy); + | ^~~~~~ + 23 | legacyAsync().then((v) => console.log(v)); + + hint: child_process.exec, child_process.execFile, setTimeout, setImmediate, stream.finished, stream.pipeline, the zlib callback one-shots, the crypto callback functions (randomBytes, pbkdf2, scrypt, hkdf, randomFill, randomInt, generateKey), dns.lookup, dns.lookupService, the fs callback functions with an fs/promises counterpart, and typed callback-last functions whose callback takes (error?: Error | null, value?) are the supported targets + +boot-path-node-surface-fences.ts:23:1 - error SC2004: uses of 'legacyAsync' inherit the blocker on its declaration + + 22 | const legacyAsync = promisify(legacy); + 23 | legacyAsync().then((v) => console.log(v)); + | ^~~~~~~~~~~ + 24 | + + hint: the declaration of 'legacyAsync' did not compile — fix the diagnostic reported there and these sites clear with it \ No newline at end of file diff --git a/tests/harness/__snapshots__/class-field-accessor-descriptor.ts.txt b/tests/harness/__snapshots__/class-field-accessor-descriptor.ts.txt new file mode 100644 index 000000000..986e0d023 --- /dev/null +++ b/tests/harness/__snapshots__/class-field-accessor-descriptor.ts.txt @@ -0,0 +1,6 @@ +class-field-accessor-descriptor.ts:9:1 - error SC2020: Object.defineProperty with an accessor descriptor for the declared field 'x' is not supported yet + + 8 | const value = new Value(); + 9 | Object.defineProperty(value, "x", { + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 10 | get() { \ No newline at end of file diff --git a/tests/harness/__snapshots__/maybe-promise-fences.ts.txt b/tests/harness/__snapshots__/maybe-promise-fences.ts.txt index 58fb23517..159e88f76 100644 --- a/tests/harness/__snapshots__/maybe-promise-fences.ts.txt +++ b/tests/harness/__snapshots__/maybe-promise-fences.ts.txt @@ -55,11 +55,4 @@ maybe-promise-fences.ts:32:13 - error SC1090: 'instanceof Promise' on '{ v: numb 31 | const record = { v: 1 }; 32 | console.log(record instanceof Promise); | ^~~~~~~~~~~~~~~~~~~~~~~~~ - 33 | - -maybe-promise-fences.ts:36:26 - error SC1090: '(unknown) => Promise' values where '() => Promise' is expected is not supported yet - - 35 | type HandlerFn = (...args: unknown[]) => Promise; - 36 | const fixed: HandlerFn = async (first: unknown) => first; - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 37 | fixed(1, 2).then((v) => console.log(v)); \ No newline at end of file + 33 | \ No newline at end of file diff --git a/tests/harness/__snapshots__/mock-fences.ts.txt b/tests/harness/__snapshots__/mock-fences.ts.txt index 6b4defcbb..d4b8115e8 100644 --- a/tests/harness/__snapshots__/mock-fences.ts.txt +++ b/tests/harness/__snapshots__/mock-fences.ts.txt @@ -1,62 +1,62 @@ -mock-fences.ts:14:15 - error SC2020: 'mock.fn of this function type' is part of the standard library types but has no scriptc lowering yet +mock-fences.ts:18:17 - error SC2020: 'mock.fn() of a function returning 'number'' is part of the standard library types but has no scriptc lowering yet - 13 | - 14 | const empty = mock.fn(); // no original function - | ^~~~~~~~~ - 15 | empty(); + 17 | + 18 | const counted = mock.fn<() => number>(); // no original, returns number + | ^~~~~~~~~~~~~~~~~~~~~~~ + 19 | counted(); - hint: mock functions lower for functions with fixed parameters, or a single rest array parameter, and an implementation of the same type + hint: mock.fn() without an original returns undefined: pass an original, or use a function type whose return type includes undefined -mock-fences.ts:27:13 - error SC2020: 'mock.method on 'Counter'' is part of the standard library types but has no scriptc lowering yet +mock-fences.ts:31:13 - error SC2020: 'mock.method on 'Counter'' is part of the standard library types but has no scriptc lowering yet - 26 | } - 27 | mock.method(new Counter(), "count"); // class instance + 30 | } + 31 | mock.method(new Counter(), "count"); // class instance | ^~~~~~~~~~~~~ - 28 | mock.method(console, "log"); // builtin object + 32 | mock.method(console, "log"); // builtin object hint: mock.method lowers for objects whose type maps to a record (object literals and interface-typed objects) and a function-valued field named by a string literal -mock-fences.ts:28:13 - error SC2020: 'mock.method on this object' is part of the standard library types but has no scriptc lowering yet +mock-fences.ts:32:13 - error SC2020: 'mock.method on this object' is part of the standard library types but has no scriptc lowering yet - 27 | mock.method(new Counter(), "count"); // class instance - 28 | mock.method(console, "log"); // builtin object + 31 | mock.method(new Counter(), "count"); // class instance + 32 | mock.method(console, "log"); // builtin object | ^~~~~~~ - 29 | mock.method(obj, "value", { times: 1 }); // options + 33 | mock.method(obj, "value", { times: 1 }); // options hint: mock.method lowers for objects whose type maps to a record (object literals and interface-typed objects) and a function-valued field named by a string literal -mock-fences.ts:29:27 - error SC2020: 'mock.method with an options object' is part of the standard library types but has no scriptc lowering yet +mock-fences.ts:33:27 - error SC2020: 'mock.method with an options object' is part of the standard library types but has no scriptc lowering yet - 28 | mock.method(console, "log"); // builtin object - 29 | mock.method(obj, "value", { times: 1 }); // options + 32 | mock.method(console, "log"); // builtin object + 33 | mock.method(obj, "value", { times: 1 }); // options | ^~~~~~~~~~~~ - 30 | const other = mock.method(obj, "value", () => "one"); // implementation of another type + 34 | const other = mock.method(obj, "value", () => "one"); // implementation of another type hint: mock options (times, getter and setter) have no lowering -mock-fences.ts:30:41 - error SC2020: 'mock.method with an implementation of another type' is part of the standard library types but has no scriptc lowering yet +mock-fences.ts:34:41 - error SC2020: 'mock.method with an implementation of another type' is part of the standard library types but has no scriptc lowering yet - 29 | mock.method(obj, "value", { times: 1 }); // options - 30 | const other = mock.method(obj, "value", () => "one"); // implementation of another type + 33 | mock.method(obj, "value", { times: 1 }); // options + 34 | const other = mock.method(obj, "value", () => "one"); // implementation of another type | ^~~~~~~~~~~ - 31 | other(); + 35 | other(); hint: give the implementation the method's parameter and return types, or discard the result -mock-fences.ts:35:31 - error SC2020: 't.mock.method with an options object' is part of the standard library types but has no scriptc lowering yet +mock-fences.ts:39:31 - error SC2020: 't.mock.method with an options object' is part of the standard library types but has no scriptc lowering yet - 34 | t.mock.method(obj, "value"); // lowers - 35 | t.mock.method(obj, "value", { times: 2 }); // options + 38 | t.mock.method(obj, "value"); // lowers + 39 | t.mock.method(obj, "value", { times: 2 }); // options | ^~~~~~~~~~~~ - 36 | }); + 40 | }); hint: mock options (times, getter and setter) have no lowering -mock-fences.ts:38:14 - error SC2020: 'mock.fn of a function returning 'number | string'' is part of the standard library types but has no scriptc lowering yet +mock-fences.ts:42:14 - error SC2020: 'mock.fn of a function returning 'number | string'' is part of the standard library types but has no scriptc lowering yet - 37 | - 38 | const pick = mock.fn((flag: boolean): number | string => (flag ? 1 : "one")); // union without undefined + 41 | + 42 | const pick = mock.fn((flag: boolean): number | string => (flag ? 1 : "one")); // union without undefined | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 39 | pick(true); + 43 | pick(true); hint: a union return type needs an undefined arm here (the calls log records undefined for calls that throw) \ No newline at end of file diff --git a/tests/harness/corpus-costs.json b/tests/harness/corpus-costs.json index b18e2ab28..85e4ba4aa 100644 --- a/tests/harness/corpus-costs.json +++ b/tests/harness/corpus-costs.json @@ -1886,6 +1886,7 @@ "5464-locale-compare-fractions.ts": 2833, "5465-dyn-index-read-arrays.ts": 3603, "5466-dyn-index-read-special.ts": 2823, + "5469-typed-array-loop-initializer-rebinding.ts": 1453, "5470-strip-vt-osc.cjs": 2497, "5471-strip-vt-csi.cjs": 2651, "5472-strip-vt-random.cjs": 2375, @@ -2189,9 +2190,6 @@ "5940-callback-helper-specialization.ts": 3109, "5941-callback-specialization-recursion.ts": 3112, "5942-callback-specialization-throws.ts": 3221, - "5942-local-class-observed-methods.ts": 5063, - "5943-fields-read-before-assignment.ts": 6856, - "5944-js-fields-read-before-assignment.js": 4247, "5945-local-class-observed-methods.ts": 5063, "5946-nested-record-field-optional-writes.ts": 6045, "5950-tuple-predicate-methods.ts": 5990, @@ -2233,6 +2231,8 @@ "6001-json-stringify-js-class-instances.js": 4668, "6002-inspect-class-added-properties.ts": 6044, "6003-inspect-js-class-properties.js": 2752, + "6004-class-instance-integrity.ts": 10548, + "6005-class-instance-integrity-sloppy.cjs": 7466, "601-closures-loops.ts": 1788, "6010-match-metadata.ts": 3990, "6011-match-metadata-js.js": 3660, @@ -4983,6 +4983,7 @@ "5464-locale-compare-fractions.ts": 3312, "5465-dyn-index-read-arrays.ts": 3798, "5466-dyn-index-read-special.ts": 4384, + "5469-typed-array-loop-initializer-rebinding.ts": 2058, "5470-strip-vt-osc.cjs": 2708, "5471-strip-vt-csi.cjs": 3038, "5472-strip-vt-random.cjs": 2850, @@ -5286,9 +5287,6 @@ "5940-callback-helper-specialization.ts": 4548, "5941-callback-specialization-recursion.ts": 4448, "5942-callback-specialization-throws.ts": 3443, - "5942-local-class-observed-methods.ts": 6212, - "5943-fields-read-before-assignment.ts": 72293, - "5944-js-fields-read-before-assignment.js": 40310, "5945-local-class-observed-methods.ts": 6212, "5946-nested-record-field-optional-writes.ts": 68117, "5950-tuple-predicate-methods.ts": 7790, @@ -5330,6 +5328,8 @@ "6001-json-stringify-js-class-instances.js": 7469, "6002-inspect-class-added-properties.ts": 9670, "6003-inspect-js-class-properties.js": 4403, + "6004-class-instance-integrity.ts": 16877, + "6005-class-instance-integrity-sloppy.cjs": 11946, "601-closures-loops.ts": 2297, "6010-match-metadata.ts": 5450, "6011-match-metadata-js.js": 4890, diff --git a/tests/harness/corpus-costs/5816-fixed-into-unknown-rest.ts.json b/tests/harness/corpus-costs/5816-fixed-into-unknown-rest.ts.json new file mode 100644 index 000000000..2b149eb6a --- /dev/null +++ b/tests/harness/corpus-costs/5816-fixed-into-unknown-rest.ts.json @@ -0,0 +1 @@ +{ "plain": 3028, "san": 5470 } diff --git a/tests/harness/corpus-costs/5916-dyn-error-stack-property.ts.json b/tests/harness/corpus-costs/5916-dyn-error-stack-property.ts.json new file mode 100644 index 000000000..3ed0acb36 --- /dev/null +++ b/tests/harness/corpus-costs/5916-dyn-error-stack-property.ts.json @@ -0,0 +1 @@ +{ "plain": 3232, "san": 4298 } diff --git a/tests/harness/corpus-costs/6064-protocol-subinterface-assertions.ts.json b/tests/harness/corpus-costs/6064-protocol-subinterface-assertions.ts.json deleted file mode 100644 index c05586e43..000000000 --- a/tests/harness/corpus-costs/6064-protocol-subinterface-assertions.ts.json +++ /dev/null @@ -1 +0,0 @@ -{ "plain": 4411, "san": 5159 } diff --git a/tests/harness/corpus-costs/6380-variadic-wrapper-arguments-apply.ts.json b/tests/harness/corpus-costs/6380-variadic-wrapper-arguments-apply.ts.json new file mode 100644 index 000000000..553943f5a --- /dev/null +++ b/tests/harness/corpus-costs/6380-variadic-wrapper-arguments-apply.ts.json @@ -0,0 +1 @@ +{ "plain": 3870, "san": 3660 } diff --git a/tests/harness/corpus-costs/6381-variadic-wrapper-async.ts.json b/tests/harness/corpus-costs/6381-variadic-wrapper-async.ts.json new file mode 100644 index 000000000..5cad95fef --- /dev/null +++ b/tests/harness/corpus-costs/6381-variadic-wrapper-async.ts.json @@ -0,0 +1 @@ +{ "plain": 3550, "san": 4820 } diff --git a/tests/harness/corpus-costs/6382-variadic-wrapper-methods-this.ts.json b/tests/harness/corpus-costs/6382-variadic-wrapper-methods-this.ts.json new file mode 100644 index 000000000..644fc5fea --- /dev/null +++ b/tests/harness/corpus-costs/6382-variadic-wrapper-methods-this.ts.json @@ -0,0 +1 @@ +{ "plain": 3000, "san": 6260 } diff --git a/tests/harness/corpus-costs/6383-variadic-wrapper-rest-tuple.ts.json b/tests/harness/corpus-costs/6383-variadic-wrapper-rest-tuple.ts.json new file mode 100644 index 000000000..f83a73df7 --- /dev/null +++ b/tests/harness/corpus-costs/6383-variadic-wrapper-rest-tuple.ts.json @@ -0,0 +1 @@ +{ "plain": 3140, "san": 4540 } diff --git a/tests/harness/corpus-costs/6384-variadic-wrapper-nested.ts.json b/tests/harness/corpus-costs/6384-variadic-wrapper-nested.ts.json new file mode 100644 index 000000000..21dee9274 --- /dev/null +++ b/tests/harness/corpus-costs/6384-variadic-wrapper-nested.ts.json @@ -0,0 +1 @@ +{ "plain": 3220, "san": 2960 } diff --git a/tests/harness/corpus-costs/6390-catch-binding-predicate.ts.json b/tests/harness/corpus-costs/6390-catch-binding-predicate.ts.json new file mode 100644 index 000000000..5b661172c --- /dev/null +++ b/tests/harness/corpus-costs/6390-catch-binding-predicate.ts.json @@ -0,0 +1 @@ +{ "plain": 3020, "san": 3560 } diff --git a/tests/harness/corpus-costs/6391-nullish-function-default.ts.json b/tests/harness/corpus-costs/6391-nullish-function-default.ts.json new file mode 100644 index 000000000..a3ae15ea4 --- /dev/null +++ b/tests/harness/corpus-costs/6391-nullish-function-default.ts.json @@ -0,0 +1 @@ +{ "plain": 4100, "san": 3150 } diff --git a/tests/harness/corpus-costs/6392-optional-chain-protocol-calls.ts.json b/tests/harness/corpus-costs/6392-optional-chain-protocol-calls.ts.json new file mode 100644 index 000000000..3fa72b729 --- /dev/null +++ b/tests/harness/corpus-costs/6392-optional-chain-protocol-calls.ts.json @@ -0,0 +1 @@ +{ "plain": 4400, "san": 4200 } diff --git a/tests/harness/corpus-costs/6393-function-types-any-params.ts.json b/tests/harness/corpus-costs/6393-function-types-any-params.ts.json new file mode 100644 index 000000000..73f790694 --- /dev/null +++ b/tests/harness/corpus-costs/6393-function-types-any-params.ts.json @@ -0,0 +1 @@ +{ "plain": 2790, "san": 3150 } diff --git a/tests/harness/corpus-costs/6394-in-key-error-subclasses.ts.json b/tests/harness/corpus-costs/6394-in-key-error-subclasses.ts.json new file mode 100644 index 000000000..6fe8b6765 --- /dev/null +++ b/tests/harness/corpus-costs/6394-in-key-error-subclasses.ts.json @@ -0,0 +1 @@ +{ "plain": 2900, "san": 3120 } diff --git a/tests/harness/corpus-costs/6395-generic-object-entries.ts.json b/tests/harness/corpus-costs/6395-generic-object-entries.ts.json new file mode 100644 index 000000000..d38b11826 --- /dev/null +++ b/tests/harness/corpus-costs/6395-generic-object-entries.ts.json @@ -0,0 +1 @@ +{ "plain": 2990, "san": 3030 } diff --git a/tests/harness/corpus-costs/6396-generic-any-instantiation.ts.json b/tests/harness/corpus-costs/6396-generic-any-instantiation.ts.json new file mode 100644 index 000000000..d38f92d43 --- /dev/null +++ b/tests/harness/corpus-costs/6396-generic-any-instantiation.ts.json @@ -0,0 +1 @@ +{ "plain": 2590, "san": 2850 } diff --git a/tests/harness/corpus-costs/6397-event-loop-metrics.ts.json b/tests/harness/corpus-costs/6397-event-loop-metrics.ts.json new file mode 100644 index 000000000..26c5a51a4 --- /dev/null +++ b/tests/harness/corpus-costs/6397-event-loop-metrics.ts.json @@ -0,0 +1 @@ +{ "plain": 3300, "san": 4140 } diff --git a/tests/harness/corpus-costs/6398-conditional-fixed-arity.ts.json b/tests/harness/corpus-costs/6398-conditional-fixed-arity.ts.json new file mode 100644 index 000000000..c8912b309 --- /dev/null +++ b/tests/harness/corpus-costs/6398-conditional-fixed-arity.ts.json @@ -0,0 +1 @@ +{ "plain": 3630, "san": 3870 } diff --git a/tests/harness/corpus-costs/6400-dyn-error-stack-property-js.js.json b/tests/harness/corpus-costs/6400-dyn-error-stack-property-js.js.json new file mode 100644 index 000000000..c51a3475f --- /dev/null +++ b/tests/harness/corpus-costs/6400-dyn-error-stack-property-js.js.json @@ -0,0 +1 @@ +{ "plain": 3172, "san": 4044 } diff --git a/tests/harness/corpus-costs/6401-dyn-error-own-property-names.ts.json b/tests/harness/corpus-costs/6401-dyn-error-own-property-names.ts.json new file mode 100644 index 000000000..f85c4901a --- /dev/null +++ b/tests/harness/corpus-costs/6401-dyn-error-own-property-names.ts.json @@ -0,0 +1 @@ +{ "plain": 3175, "san": 4362 } diff --git a/tests/harness/corpus-costs/6402-dyn-error-own-property-names-js.js.json b/tests/harness/corpus-costs/6402-dyn-error-own-property-names-js.js.json new file mode 100644 index 000000000..55012b442 --- /dev/null +++ b/tests/harness/corpus-costs/6402-dyn-error-own-property-names-js.js.json @@ -0,0 +1 @@ +{ "plain": 3056, "san": 4620 } diff --git a/tests/harness/corpus-costs/6414-catch-values-roundtrip.ts.json b/tests/harness/corpus-costs/6414-catch-values-roundtrip.ts.json new file mode 100644 index 000000000..502f0220d --- /dev/null +++ b/tests/harness/corpus-costs/6414-catch-values-roundtrip.ts.json @@ -0,0 +1 @@ +{"plain":4942} diff --git a/tests/harness/corpus-costs/6445-rest-function-fixed-slot.ts.json b/tests/harness/corpus-costs/6445-rest-function-fixed-slot.ts.json new file mode 100644 index 000000000..858c662a8 --- /dev/null +++ b/tests/harness/corpus-costs/6445-rest-function-fixed-slot.ts.json @@ -0,0 +1 @@ +{ "plain": 2526, "san": 3450 } diff --git a/tests/harness/corpus-costs/6446-rest-function-nested-declaration.ts.json b/tests/harness/corpus-costs/6446-rest-function-nested-declaration.ts.json new file mode 100644 index 000000000..39f698b22 --- /dev/null +++ b/tests/harness/corpus-costs/6446-rest-function-nested-declaration.ts.json @@ -0,0 +1 @@ +{ "plain": 2222, "san": 3035 } diff --git a/tests/harness/corpus-costs/6468-generic-unknown-record-entries.ts.json b/tests/harness/corpus-costs/6468-generic-unknown-record-entries.ts.json new file mode 100644 index 000000000..8489daced --- /dev/null +++ b/tests/harness/corpus-costs/6468-generic-unknown-record-entries.ts.json @@ -0,0 +1 @@ +{ "plain": 4560, "san": 4770 } diff --git a/tests/harness/esm-path-globals.test.ts b/tests/harness/esm-path-globals.test.ts new file mode 100644 index 000000000..546c924a9 --- /dev/null +++ b/tests/harness/esm-path-globals.test.ts @@ -0,0 +1,38 @@ +/* __dirname / __filename in TypeScript files that Node's strip-types rule + * loads as ES modules: scriptc compiles them to the module's source path, + * the CommonJS-bundle reading. Node itself has no such globals in an ES + * module, so the oracle runs a twin of each source with the globals spelled + * import.meta.dirname / import.meta.filename, at the same paths. */ +import { execFile } from "node:child_process"; +import { cpSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { promisify } from "node:util"; +import { expect, test } from "vitest"; +import { compile } from "@scriptc/compiler"; + +const execFileAsync = promisify(execFile); +const fixture = join(import.meta.dirname, "../fixtures/esm-path-globals"); + +test("__dirname and __filename in TypeScript ES modules read the module's source path", async () => { + const dir = mkdtempSync(join(tmpdir(), "scriptc-esm-path-globals-")); + cpSync(fixture, join(dir, "src"), { recursive: true }); + const entry = join(dir, "src", "main.ts"); + const result = await compile(entry, { + outPath: join(dir, "main"), + outDir: dir, + sanitize: process.env["SCRIPTC_SAN"] === "1", + }); + expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true); + if (!result.ok) return; + const native = await execFileAsync(result.binaryPath); + for (const file of [entry, join(dir, "src", "lib", "helper.ts")]) { + const text = readFileSync(file, "utf8") + .replaceAll("__dirname", "import.meta.dirname") + .replaceAll("__filename", "import.meta.filename"); + writeFileSync(file, text); + } + const node = await execFileAsync(process.execPath, [entry]); + expect(native.stdout).toBe(node.stdout); + expect(native.stdout).toContain("string string\nsrc main.ts\ntrue true\ntrue helper.ts\n"); +}); diff --git a/tests/harness/npm-cases.ts b/tests/harness/npm-cases.ts index 4dda0b9ad..0830d4162 100644 --- a/tests/harness/npm-cases.ts +++ b/tests/harness/npm-cases.ts @@ -19,12 +19,12 @@ export function npmCases(fixturesRoot: string): NpmCase[] { return [ ...globSync(join(fixturesRoot, "npm/cases/*/main.ts")) .sort() - // 2465-2469 and 2556-2557 are the --npm-static bundler-emitted-CJS + // 2465-2469, 2556-2566 and 2571 are the --npm-static bundler-emitted-CJS // cases (npm-static.test.ts drives them with the opt-in): their // consumers exercise the static rewrite's surface (lexer-visible // names the shipped .d.ts never declares, the __toESM interop // family), so they stay out of the flagless island lane by design. - .filter((entry) => !/\/(246[5-9]|255[67])-[^/]+\/main\.ts$/.test(entry)) + .filter((entry) => !/\/(246[5-9]|255[6-9]|256[0-24-6]|2571)-[^/]+\/main\.ts$/.test(entry)) .map((entry) => ({ name: entry.split("/").at(-2)!, entry, diff --git a/tests/harness/npm-static.test.ts b/tests/harness/npm-static.test.ts index 356d2fa6d..8325e2998 100644 --- a/tests/harness/npm-static.test.ts +++ b/tests/harness/npm-static.test.ts @@ -76,8 +76,8 @@ async function buildStatic(entry: string, npmStatic: string[] | "auto"): Promise ...globSync( join(fixturesRoot, "npm/node_modules/cryptozoo/**/*.{js,mjs,cjs,json,d.ts}"), ).sort(), - // the bundler-emitted-CJS mini packages (cases 2465-2469, 2556-2557) - ...globSync(join(fixturesRoot, "npm/node_modules/gt*/**/*.{js,json}")).sort(), + // the bundler-emitted-CJS mini packages (cases 2465-2469, 2556-2566, 2571) + ...globSync(join(fixturesRoot, "npm/node_modules/gt*/**/*.{js,cjs,json}")).sort(), ]; for (const f of inputs) hash.update(f).update(readFileSync(f)); const key = hash @@ -1389,6 +1389,138 @@ describe(`npm-static pilots${sanitize ? " (sanitized)" : ""}`, () => { ]); }, 120_000); + /* ── 2558-2561: esbuild's bundled CommonJS chunks and per-file CommonJS + * cycles ─ every __commonJS chunk compiles as its own CommonJS module + * (evaluated once, at its first require); a require cycle between + * esbuild outputs whose live getter tables install before their first + * require initializes exactly like Node, and a cycle that reads a + * binding in its temporal dead zone stays refused. */ + async function expectNodeParity(entry: string, packages: string[]): Promise { + const { coverage } = analyze(entry, { npmStatic: packages }); + expect(coverage.npmStatic).toEqual(packages.map((pkg) => ({ package: pkg, status: "static" }))); + expect(coverage.preflightFailed).toBe(false); + expect(coverage.diagnostics).toHaveLength(0); + const binary = await buildStatic(entry, packages); + const [nodeRes, nativeRes] = await Promise.all([ + runBinary("node", [entry]), + runBinary(binary, []), + ]); + // Node's stderr carries its type-stripping warning; the programs write + // only to stdout. + expect(nativeRes.stdout.toString("utf8")).toBe(nodeRes.stdout.toString("utf8")); + expect(comparableStderr(nativeRes.stderr).toString("utf8")).toBe(""); + expect(nativeRes.exitCode).toBe(nodeRes.exitCode); + expect(nativeRes.exitCode).toBe(0); + } + + // 2558: esbuild 0.25 (plain and whitespace/syntax minified) and 0.17 + // CommonJS bundles of one source, plus a .cjs bundle in a type-module + // package with the node-mode interop. + test("bundled CommonJS chunks 2558-bundled-chunks compile statically and byte-match Node", async () => { + await expectNodeParity(join(fixturesRoot, "npm/cases/2558-bundled-chunks/main.ts"), [ + "gtchunk", + "gtchunkws", + "gtchunk17", + "gtcjsdist", + "gtcore", + ]); + }, 180_000); + + // A whitespace/syntax-minified bundle whose helpers keep their names is + // judged by the recognizers, not refused up front as minified. + test("--npm-static=auto opts a minified bundle with named helpers in", () => { + const entry = join(fixturesRoot, "npm/cases/2558-bundled-chunks/main.ts"); + const { coverage } = analyze(entry, { npmStatic: "auto" }); + expect(coverage.npmStatic).toContainEqual({ package: "gtchunkws", status: "static" }); + }, 120_000); + + test.each(["2559-cjs-cycle", "2560-cjs-cycle-partner-first"])( + "the esbuild CommonJS cycle %s compiles statically and byte-matches Node", + async (name) => { + await expectNodeParity(join(fixturesRoot, `npm/cases/${name}/main.ts`), ["gtcycle"]); + }, + 180_000, + ); + + // 2561: Node throws a ReferenceError there; the cycle keeps SC1016. + test("a CommonJS cycle that reads a binding before its declaration stays refused", () => { + const entry = join(fixturesRoot, "npm/cases/2561-cjs-cycle-early-read/main.ts"); + const { coverage } = analyze(entry, { npmStatic: ["gtcyclebad"] }); + expect(coverage.npmStatic).toEqual([ + { + package: "gtcyclebad", + status: "refused", + detail: expect.stringMatching( + /circular imports .*can use its binding 'import_index' of a module of the cycle/, + ) as string, + }, + ]); + }, 120_000); + + // 2562: a file with unverifiable interop that no compiled code can load + // (the program imports a leaf data module and only a type from the + // main entry) leaves its package static. + test("a package is judged by the files its imported subpaths can load", async () => { + await expectNodeParity(join(fixturesRoot, "npm/cases/2562-subpath-leaf/main.ts"), [ + "gtsubpath", + ]); + }, 180_000); + + // 2566: the same early read through esbuild's `(0, binding.fn)()` call + // spelling also keeps SC1016. + test("a CommonJS cycle that calls an export during initialization stays refused", () => { + const entry = join(fixturesRoot, "npm/cases/2566-cjs-cycle-indirect-call/main.ts"); + const { coverage } = analyze(entry, { npmStatic: ["gtcyclecall"] }); + expect(coverage.npmStatic).toEqual([ + { + package: "gtcyclecall", + status: "refused", + detail: expect.stringMatching( + /circular imports .*can use its binding 'import_index' of a module of the cycle/, + ) as string, + }, + ]); + }, 120_000); + + // 2571: the partner stores the export (in a const, or in an object + // literal) and calls it while the cycle initializes; both keep SC1016. + test("a CommonJS cycle that stores an export and calls it stays refused", () => { + const entry = join(fixturesRoot, "npm/cases/2571-cjs-cycle-stored-function/main.ts"); + const { coverage } = analyze(entry, { npmStatic: ["gtcyclealias", "gtcyclebox"] }); + for (const pkg of ["gtcyclealias", "gtcyclebox"]) + expect(coverage.npmStatic).toContainEqual({ + package: pkg, + status: "refused", + detail: expect.stringMatching( + /circular imports .*can use its binding 'import_index' of a module of the cycle/, + ) as string, + }); + }, 120_000); + + // 2564: a chunk reads a top-level function whose name a nested scope of + // the chunk also declares; the function still travels with the chunk. + test("a chunk carries a top-level function its nested scopes shadow", async () => { + await expectNodeParity(join(fixturesRoot, "npm/cases/2564-chunk-helper-shadowing/main.ts"), [ + "gtchunkshadow", + ]); + }, 180_000); + + // 2565: Node shares one function between the chunks that export it; a + // per-chunk copy would not, so the package stays refused. + test("chunks that export a shared top-level function stay refused", () => { + const entry = join(fixturesRoot, "npm/cases/2565-chunk-shared-function/main.ts"); + const { coverage } = analyze(entry, { npmStatic: ["gtchunkshared"] }); + expect(coverage.npmStatic).toEqual([ + { + package: "gtchunkshared", + status: "refused", + detail: expect.stringMatching( + /uses the bundle's top-level function 'tally' as a value, which its chunks cannot share/, + ) as string, + }, + ]); + }, 120_000); + test("published type-only declarations coexist with a static runtime bundle", async () => { const entry = join(fixturesRoot, "npm/cases/2469-bundle-offender/main.ts"); const { coverage } = analyze(entry, { npmStatic: ["gtghost"] }); diff --git a/tests/harness/project-config.test.ts b/tests/harness/project-config.test.ts index d2c442517..79bf42b84 100644 --- a/tests/harness/project-config.test.ts +++ b/tests/harness/project-config.test.ts @@ -451,6 +451,42 @@ test("node-types: promisified fs callback functions lower as their fs/promises c expect(comparableStderr(native.stderr)).toBe(node.stderr); }); +test("node-types: util.promisify over typed callback-last functions settles like Node", async () => { + const outDir = outDirFor("promisify-callback-functions"); + const entry = join(nodeTypesDir, "promisify-callback-functions.ts"); + const result = await compile(entry, { + outPath: join(outDir, "promisify-callback-functions"), + outDir, + sanitize, + }); + expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true); + if (!result.ok) return; + const [native, node] = await Promise.all([ + execFileAsync(result.binaryPath), + execFileAsync(process.execPath, ["--disable-warning=MODULE_TYPELESS_PACKAGE_JSON", entry]), + ]); + expect(native.stdout).toBe(node.stdout); + expect(comparableStderr(native.stderr)).toBe(node.stderr); +}); + +test("node-types: stream subclasses extend the @types/node stream classes", async () => { + const outDir = outDirFor("stream-subclass-hooks"); + const entry = join(nodeTypesDir, "stream-subclass-hooks.ts"); + const result = await compile(entry, { + outPath: join(outDir, "stream-subclass-hooks"), + outDir, + sanitize, + }); + expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true); + if (!result.ok) return; + const [native, node] = await Promise.all([ + execFileAsync(result.binaryPath), + execFileAsync(process.execPath, ["--disable-warning=MODULE_TYPELESS_PACKAGE_JSON", entry]), + ]); + expect(native.stdout).toBe(node.stdout); + expect(comparableStderr(native.stderr)).toBe(node.stderr); +}); + test("node-types: promisified setTimeout and setImmediate lower as timers/promises", async () => { const outDir = outDirFor("promisify-timers"); const entry = join(nodeTypesDir, "promisify-timers.ts"); From e5b9102e0d5b3f002477900f6cf0a8f760dce50d Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Tue, 20 Oct 2026 08:32:19 -0700 Subject: [PATCH 31/39] Compile compound assignment, ++/-- and ??= through literal-union and index-signature record keys `totals[side] += n`, where `side` is a union of string literals naming declared fields of one type, now dispatches over those fields: the receiver and key evaluate once, the old value is read from the field the key names, then the right side, then the write to that same field. Every compound operator, prefix and postfix ++/--, and ??=/||=/&&= share the path. A single literal key (spelled at the site or carried by a const) reads and writes the field directly. A key smuggled outside its literal type throws the fixed-shape TypeError of a keyed write miss. A string key into a pure index-signature record (`counts[name] += 1`, `counts[name]++`) reads the entry, NaN for a missing one under numeric operators, and inserts or replaces it. Keys naming fields of different types, class instances and JavaScript sources keep their refusals. Co-Authored-By: Claude Opus 5.5 --- .../lowering/expressions/element-access.ts | 7 + .../expressions/keyed-field-targets.ts | 271 ++++++++++++++++++ .../expressions/nullish-assignment.ts | 17 ++ .../lowering/expressions/property-access.ts | 2 + .../frontend/lowering/expressions/updates.ts | 8 +- .../src/frontend/lowering/lower-exprs.ts | 15 + .../6490-literal-key-field-updates.ts.json | 6 + .../corpus/6491-index-record-updates.ts.json | 6 + .../corpus/6490-literal-key-field-updates.ts | 132 +++++++++ tests/corpus/6491-index-record-updates.ts | 44 +++ 10 files changed, 506 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/src/frontend/lowering/expressions/keyed-field-targets.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6490-literal-key-field-updates.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6491-index-record-updates.ts.json create mode 100644 tests/corpus/6490-literal-key-field-updates.ts create mode 100644 tests/corpus/6491-index-record-updates.ts diff --git a/packages/compiler/src/frontend/lowering/expressions/element-access.ts b/packages/compiler/src/frontend/lowering/expressions/element-access.ts index 144742257..f39b7c428 100644 --- a/packages/compiler/src/frontend/lowering/expressions/element-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/element-access.ts @@ -63,6 +63,8 @@ import { npmStaticPackageOfPath } from "../../npm-static.js"; import { isSafeToRepeat } from "./evaluation-safety.js"; import { lowerClassPrototypeComputedAssignment } from "../class-prototypes.js"; import { isClassCallback } from "../class-callbacks.js"; +import { isKeyedFieldAccess } from "./keyed-field-targets.js"; +import { lowerFieldCompoundValue } from "./updates.js"; /** `a[i]` reads. Only f64 indices into array receivers are modeled; JS * string-key element access (`a["length"]`) and string indexing (`s[0]` @@ -1417,6 +1419,11 @@ export function lowerElementCompoundParts( const target = expr.left as ts.ElementAccessExpression; fenceNodeModuleMutation(lowerer, target, "assignment"); const loc = locOf(expr); + // A record through a computed key (`totals[side] += n` with a literal + // union key, `counts[name] += 1` on an index-signature record): the + // member compound's receiver, key, old value, rhs, write sequence. + if (isKeyedFieldAccess(lowerer, target)) + return { expr: lowerFieldCompoundValue(lowerer, target, op, expr.right, loc), stmts: null }; const checked = lowerer.lowerExpr(target.expression); if (checked?.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) { const stmts: IrStmt[] = []; diff --git a/packages/compiler/src/frontend/lowering/expressions/keyed-field-targets.ts b/packages/compiler/src/frontend/lowering/expressions/keyed-field-targets.ts new file mode 100644 index 000000000..7a4f9c557 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/expressions/keyed-field-targets.ts @@ -0,0 +1,271 @@ +/* Read-modify-write targets for computed record keys: `r[k] op= v`, `r[k]++` and `r[k] ??= v`. */ +import * as ts from "../../ts7/adapter.js"; +import { + BOOL, + F64, + STRING, + typeEquals, + type IrExpr, + type IrStmt, + type SrcLoc, +} from "../../../ir/ir.js"; +import { isJsSourceFile } from "../../program.js"; +import { constituentTypes } from "../../ts7/checker.js"; +import type { FieldTarget } from "../lower-exprs.js"; +import type { Lowerer } from "../lowerer.js"; + +export type KeyedFieldTarget = FieldTarget & { container: "recordKeyed" }; + +/** The property names a computed key's type allows: one or more string + * literals (a literal union such as `"sent" | "received"`, enum string + * members, or a type parameter bound to one inside a generic instance). + * Null for any other key type. */ +export function literalFieldKeys(lowerer: Lowerer, keyNode: ts.Expression): string[] | null { + let t: ts.Type = lowerer.typeOf(keyNode); + if (t.flags & ts.TypeFlags.TypeParameter) { + const bound = lowerer.typeParamTsResolver(t); + if (!bound) return null; + t = bound; + } + const parts = t.flags & ts.TypeFlags.Union ? constituentTypes(t) : [t]; + const keys: string[] = []; + for (const part of parts) { + if (!part.isStringLiteralType()) return null; + if (!keys.includes(part.value)) keys.push(part.value); + } + return keys.length > 0 ? keys : null; +} + +/** Does `r[k]` read and write through declared record storage by key? A + * checker-only test (nothing lowers), so a caller can route before it + * evaluates the receiver: TypeScript sources only, a record whose declared + * fields include every name the key's literal type allows, or a pure + * index-signature record with a string key. */ +export function isKeyedFieldAccess(lowerer: Lowerer, access: ts.ElementAccessExpression): boolean { + if ( + access.questionDotToken || + isJsSourceFile(access.getSourceFile()) || + lowerer.isProcessEnv(access.expression) + ) + return false; + const keys = literalFieldKeys(lowerer, access.argumentExpression); + if (!keys && !(lowerer.typeOf(access.argumentExpression).flags & ts.TypeFlags.StringLike)) + return false; + const receiver = lowerer.mapTypeOf(lowerer.typeOf(access.expression)); + if (receiver?.kind !== "record") return false; + const shape = lowerer.shapes.get(receiver.shapeId); + if (!shape || shape.tuple) return false; + if (shape.fields.length === 0) return shape.indexValue !== undefined; + return keys !== null && keys.every((k) => shape.fields.some((f) => f.name === k)); +} + +/** The target of a read-modify-write through `r[k]`, or null when + * isKeyedFieldAccess declines. A literal-union key dispatches over the + * declared fields it names, which must share one type; a string key on a + * pure index-signature record reads and writes its entries. The receiver + * and key may arrive already lowered (and saved) by the caller; otherwise + * both lower here, unsaved. A caller that evaluates the target more than + * once saves `obj` and then `key`, the JavaScript evaluation order. With + * `numeric`, a missing index-signature entry reads as NaN (every numeric + * update applies ToNumber to it) instead of a value armed with undefined. */ +export function keyedFieldTarget( + lowerer: Lowerer, + access: ts.ElementAccessExpression, + numeric: boolean, + lowered?: { obj: IrExpr; key: IrExpr }, +): KeyedFieldTarget | null { + if (!isKeyedFieldAccess(lowerer, access)) return null; + const keyNode = access.argumentExpression; + const keys = literalFieldKeys(lowerer, keyNode); + const obj = lowered?.obj ?? lowerer.lowerExpr(access.expression); + if (obj.type.kind !== "record") { + lowerer.unsupported( + "SC1090", + access.expression, + `updating a computed key of a '${lowerer.fmt(obj.type)}' value (narrow the receiver to its record type first)`, + ); + } + const shapeId = obj.type.shapeId; + const shape = lowerer.shapes.get(shapeId)!; + // A single literal spelled at the site (or an identifier whose type is + // that one literal) names the field statically: identifier evaluation + // is pure, so skipping it matches JavaScript. + const indexed = shape.fields.length === 0; + const staticKey = + !indexed && keys?.length === 1 && (ts.isStringLiteralLike(keyNode) || ts.isIdentifier(keyNode)); + const key = staticKey ? null : (lowered?.key ?? lowerer.lowerExpr(keyNode)); + if (key && key.type.kind !== "string") { + lowerer.unsupported( + "SC1090", + keyNode, + `updating a record through a '${lowerer.fmt(key.type)}' key (convert the key to a string first)`, + ); + } + if (keys && !indexed) { + const fields = keys.map((k) => shape.fields.find((f) => f.name === k)); + const first = fields[0]; + if (!first || fields.some((f) => !f || !typeEquals(f.type, first.type))) { + lowerer.unsupported( + "SC1090", + access, + `updating '${lowerer.fmt(obj.type)}' through a key whose fields are not all stored with one type (${keys.map((k) => `'${k}'`).join(", ")}; switch over the key and update each field)`, + ); + } + return { + container: "recordKeyed", + obj, + shapeId, + field: keys[0]!, + keys, + key, + fieldType: first.type, + }; + } + if (!indexed || !shape.indexValue) { + lowerer.unsupported( + "SC1090", + access, + `updating '${lowerer.fmt(obj.type)}' through a runtime key (the stored record declares fields)`, + ); + } + return { + container: "recordKeyed", + obj, + shapeId, + field: "", + keys: null, + key, + fieldType: shape.indexValue, + ...(numeric && shape.indexValue.kind === "f64" ? { missNaN: true as const } : {}), + }; +} + +/** Does `key` name `field`? */ +function keyIs(key: IrExpr, field: string, loc: SrcLoc): IrExpr { + return { + kind: "strEq", + negated: false, + left: key, + right: { kind: "strLit", value: field, type: STRING, loc }, + type: BOOL, + loc, + }; +} + +/** A key outside its literal type (smuggled through a cast) names no + * declared field: a fixed-shape record cannot add the property, so the + * update throws the TypeError of a keyed write miss. */ +function keyMiss(key: IrExpr, target: KeyedFieldTarget, loc: SrcLoc): IrExpr { + const message: IrExpr = { + kind: "strConcat", + left: { + kind: "strConcat", + left: { kind: "strLit", value: "Cannot add property '", type: STRING, loc }, + right: key, + type: STRING, + loc, + }, + right: { kind: "strLit", value: "' to a fixed-shape object", type: STRING, loc }, + type: STRING, + loc, + }; + return { + kind: "libCall", + fn: "error.nodeThrow", + args: [ + { kind: "numLit", value: 1, type: F64, loc }, + { kind: "strLit", value: "", type: STRING, loc }, + message, + ], + type: target.fieldType, + loc, + }; +} + +/** The current value of a keyed target. */ +export function keyedFieldRead(lowerer: Lowerer, target: KeyedFieldTarget, loc: SrcLoc): IrExpr { + const { obj, shapeId, key, fieldType } = target; + if (!target.keys) { + const type = target.missNaN + ? fieldType + : fieldType.kind === "dyn" + ? fieldType + : lowerer.withUndefinedArmOf(fieldType); + if (!type || !key) throw new Error("keyed index-signature target without a key or read type"); + return { + kind: "recordKeyGet", + obj, + shapeId, + key, + ...(target.missNaN ? { missNaN: true as const } : {}), + type, + loc, + }; + } + const get = (field: string): IrExpr => ({ + kind: "recordGet", + obj, + shapeId, + field, + type: fieldType, + loc, + }); + if (!key) return get(target.keys[0]!); + return target.keys.reduceRight( + (otherwise, field) => ({ + kind: "ternary", + cond: keyIs(key, field, loc), + then: get(field), + else_: otherwise, + type: fieldType, + loc, + }), + keyMiss(key, target, loc), + ); +} + +/** Store `value` (already of the target's field type) through a keyed + * target. A multi-key dispatch references the value once per field, so a + * value that is not a plain local is saved first. */ +export function keyedFieldWrite( + lowerer: Lowerer, + target: KeyedFieldTarget, + value: IrExpr, + loc: SrcLoc, +): IrStmt { + const { obj, shapeId, key } = target; + if (!target.keys) { + if (!key) throw new Error("keyed index-signature target without a key"); + return { kind: "recordKeySet", obj, shapeId, key, value, loc }; + } + if (!key) return { kind: "recordSet", obj, shapeId, field: target.keys[0]!, value, loc }; + const prefix: IrStmt[] = []; + let stored = value; + if (value.kind !== "varRef") { + const local = lowerer.declareHiddenLocal("%keyedValue", value.type); + prefix.push({ kind: "varDecl", localId: local.id, init: value, loc }); + stored = { kind: "varRef", localId: local.id, type: value.type, loc }; + } + const chain = target.keys.reduceRight( + (otherwise, field) => [ + { + kind: "if", + cond: keyIs(key, field, loc), + then: [{ kind: "recordSet", obj, shapeId, field, value: stored, loc }], + else_: otherwise, + loc, + }, + ], + [{ kind: "exprStmt", expr: keyMiss(key, target, loc), loc }], + ); + return { kind: "block", body: [...prefix, ...chain], loc }; +} + +/** Save a keyed target's key after its receiver, so a multi-key dispatch + * reads and writes the field the key named when it was evaluated. */ +export function saveKeyedFieldKey( + target: FieldTarget, + save: (value: IrExpr, name: string) => IrExpr, +): void { + if (target.container === "recordKeyed" && target.key) target.key = save(target.key, "%keyedKey"); +} diff --git a/packages/compiler/src/frontend/lowering/expressions/nullish-assignment.ts b/packages/compiler/src/frontend/lowering/expressions/nullish-assignment.ts index 4366b8d6b..81b3b9d69 100644 --- a/packages/compiler/src/frontend/lowering/expressions/nullish-assignment.ts +++ b/packages/compiler/src/frontend/lowering/expressions/nullish-assignment.ts @@ -18,6 +18,11 @@ import { arrayNumberRead, arrayValueRead, arrayValueStore } from "../array-value import { fenceNodeModuleMutation } from "../lower-node-module.js"; import { globalSymbolKey } from "./global-symbols.js"; import { tryLowerExpression } from "./try-lower-expression.js"; +import { + type KeyedFieldTarget, + keyedFieldTarget, + saveKeyedFieldKey, +} from "./keyed-field-targets.js"; import { eventAccessorRead, eventAccessorWrite, @@ -147,6 +152,7 @@ export function lowerShortCircuitAssignment(lowerer: Lowerer, expr: ts.BinaryExp } else { const receiver = save(lowerer.lowerExpr(target.expression), "%shortCircuitReceiver"); let key = lowerer.lowerExpr(target.argumentExpression); + let keyed: KeyedFieldTarget | null = null; if (receiver.type.kind === "dyn") { key = save( { @@ -245,6 +251,17 @@ export function lowerShortCircuitAssignment(lowerer: Lowerer, expr: ts.BinaryExp value: lowerer.coerceToExpected(value, indexValue), loc, }); + } else if ( + receiver.type.kind === "record" && + (keyed = keyedFieldTarget(lowerer, target, false, { obj: receiver, key })) + ) { + // `totals[side] ??= v` through a literal-union key: the read and + // the write dispatch over the declared fields the key can name. + const field = keyed; + saveKeyedFieldKey(field, save); + storage = field.fieldType; + read = lowerer.fieldGetExpr(field, locOf(target), target); + write = (value) => lowerer.fieldSetStmt(field, value, loc, target); } else { lowerer.unsupported( "SC1090", diff --git a/packages/compiler/src/frontend/lowering/expressions/property-access.ts b/packages/compiler/src/frontend/lowering/expressions/property-access.ts index 6b37b7a19..1de1ec83d 100644 --- a/packages/compiler/src/frontend/lowering/expressions/property-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/property-access.ts @@ -154,6 +154,7 @@ import { errorPropertyRead } from "../error-methods.js"; import { isSafeToRepeat } from "./evaluation-safety.js"; import { isZlibStreamMember, lowerZlibStreamBytesWritten } from "../builtins/compression.js"; import { isFsStreamMember, lowerFsStreamProperty } from "../builtins/fs-streams.js"; +import { keyedFieldRead } from "./keyed-field-targets.js"; /** True when a property access names an ABSTRACT property declaration * (`abstract p: number` — a PropertyDeclaration, not an accessor). @@ -3505,6 +3506,7 @@ export function fieldGetExpr( ); if (checked) target = { ...target, obj: checked }; } + if (target.container === "recordKeyed") return keyedFieldRead(lowerer, target, loc); if (target.container === "dynamic") return lowerer.coerceInto( blame, diff --git a/packages/compiler/src/frontend/lowering/expressions/updates.ts b/packages/compiler/src/frontend/lowering/expressions/updates.ts index 2270f6043..41d8f6332 100644 --- a/packages/compiler/src/frontend/lowering/expressions/updates.ts +++ b/packages/compiler/src/frontend/lowering/expressions/updates.ts @@ -42,6 +42,7 @@ import type { CompoundOp } from "../surfaces.js"; import { tryLowerExpression } from "./try-lower-expression.js"; import { hasRuntimeStatics } from "../class-runtime-statics.js"; import { declareContextLocal } from "../function-context.js"; +import { keyedFieldTarget, keyedFieldWrite, saveKeyedFieldKey } from "./keyed-field-targets.js"; /** Read-modify-write updates read the member first: an unassigned * deferred-init receiver throws Node's member-read TypeError. */ @@ -337,10 +338,11 @@ export function lowerIncDec( } const target = ts.isPropertyAccessExpression(access) ? lowerer.fieldTarget(access) - : symbolFieldTarget(lowerer, access); + : (symbolFieldTarget(lowerer, access) ?? keyedFieldTarget(lowerer, access, true)); if (target && lowerer.dynConvertible(target.fieldType)) { checkDeferredMemberReceiver(lowerer, target, access); target.obj = save(target.obj, "%incrementReceiver"); + saveKeyedFieldKey(target, save); return finish(lowerer.fieldGetExpr(target, loc, access), (value) => lowerer.fieldSetStmt( target, @@ -617,6 +619,7 @@ export function fieldSetStmt( }; } } + if (target.container === "recordKeyed") return keyedFieldWrite(lowerer, target, value, loc); if (target.container === "dynamic") return { kind: "exprStmt", @@ -872,12 +875,13 @@ export function lowerFieldCompoundValue( const targetOf = (): FieldTarget | null => ts.isPropertyAccessExpression(access) ? lowerer.fieldTarget(access) - : symbolFieldTarget(lowerer, access); + : (symbolFieldTarget(lowerer, access) ?? keyedFieldTarget(lowerer, access, true)); const target = targetOf(); if (!target) lowerer.unsupported("SC1090", access, "compound assignment to unsupported field targets"); checkDeferredMemberReceiver(lowerer, target, access); target.obj = save(target.obj, "%compoundReceiver"); + saveKeyedFieldKey(target, save); // Accessors observe getter, RHS side effects, then setter, all through // the saved receiver. const fieldRead = lowerer.fieldGetExpr(target, locOf(access), access); diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 5cbf103d5..b33700b7e 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -151,6 +151,21 @@ export type FieldTarget = // (the write-slot type; reads arm it with undefined under // noUncheckedIndexedAccess in fieldGetExpr). | { container: "recordOvf"; obj: IrExpr; shapeId: string; field: string; fieldType: IrType } + // A computed key of a record in a read-modify-write (`r[k] += v`, + // `r[k]++`, `r[k] ??= v`; keyed-field-targets.ts): `keys` lists the + // declared fields a literal-union key can name, which share fieldType; + // null keys mean a string key into a pure index-signature record, whose + // entries fieldType types. `key` is null when the one literal is static. + | { + container: "recordKeyed"; + obj: IrExpr; + shapeId: string; + field: string; + keys: readonly string[] | null; + key: IrExpr | null; + fieldType: IrType; + missNaN?: true; + } | { container: "accessor"; obj: IrExpr; className: string; field: string; fieldType: IrType } // A RECORD accessor property (an object-literal `get x()`/`set x(v)` — // the shape carries %get:/%set: closure slots): reads call the getter diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6490-literal-key-field-updates.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6490-literal-key-field-updates.ts.json new file mode 100644 index 000000000..1e4e1e939 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6490-literal-key-field-updates.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6490-literal-key-field-updates.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6491-index-record-updates.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6491-index-record-updates.ts.json new file mode 100644 index 000000000..babda8c3c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6491-index-record-updates.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6491-index-record-updates.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6490-literal-key-field-updates.ts b/tests/corpus/6490-literal-key-field-updates.ts new file mode 100644 index 000000000..f90739c31 --- /dev/null +++ b/tests/corpus/6490-literal-key-field-updates.ts @@ -0,0 +1,132 @@ +// Read-modify-write through a key whose type is a union of literal field +// names (`totals[side] += n`): every compound operator, ++/-- and logical +// assignment dispatch over the declared fields the key can name. The +// receiver and key evaluate once, before the right side. +type Side = "sent" | "received"; +interface Traffic { + sent: number; + received: number; + label: string; + updatedAt: number; +} + +const traffic: Traffic = { sent: 0, received: 0, label: "link", updatedAt: 0 }; + +function record(side: Side, bytes: number): void { + traffic[side] += bytes; + traffic.updatedAt++; +} +record("sent", 120); +record("received", 64); +record("sent", 8); +console.log(JSON.stringify(traffic)); + +function adjust(side: Side): string { + const parts: number[] = []; + parts.push((traffic[side] -= 3)); + parts.push((traffic[side] *= 2)); + parts.push((traffic[side] /= 4)); + parts.push((traffic[side] %= 7)); + parts.push((traffic[side] **= 2)); + parts.push((traffic[side] |= 1)); + parts.push((traffic[side] &= 0xff)); + parts.push((traffic[side] ^= 0x0f)); + parts.push((traffic[side] <<= 2)); + parts.push((traffic[side] >>= 1)); + parts.push((traffic[side] >>>= 1)); + return parts.join(","); +} +console.log(adjust("sent"), adjust("received")); + +// ++ and -- in statement and value positions, prefix and postfix. +const sides: Side[] = ["sent", "received", "sent"]; +for (const s of sides) traffic[s]++; +for (const s of sides) --traffic[s]; +const post = traffic[sides[1]!]--; +const pre = ++traffic[sides[0]!]; +console.log(post, pre, traffic.sent, traffic.received); + +// One literal key, spelled at the site or carried by a const. +traffic["sent"] += 1000; +const fixed = "received"; +traffic[fixed] -= 1; +traffic["received"]++; +console.log(traffic.sent, traffic.received); + +// Evaluation order: receiver, key, old value, right side, write. +let trace = ""; +function pick(s: Side): Side { + trace += `key:${s};`; + return s; +} +function target(): Traffic { + trace += "receiver;"; + return traffic; +} +function amount(n: number): number { + trace += `rhs:${n};`; + return n; +} +console.log((target()[pick("received")] += amount(5)), trace); +trace = ""; +console.log(target()[pick("sent")]++, trace); +trace = ""; +let current = traffic; +function swap(): number { + current = { sent: -1, received: -1, label: "other", updatedAt: 0 }; + return 1; +} +current[pick("sent")] += swap(); +console.log(traffic.sent, current.sent, trace); + +// The right side throws after the old value is read: nothing is written. +function fail(): number { + throw new Error("rhs failed"); +} +try { + traffic[pick("received")] *= fail(); +} catch (e) { + if (e instanceof Error) console.log(e.message, traffic.received); +} + +// String fields append. +type Part = "head" | "tail"; +const text: { head: string; tail: string; size: number } = { head: "a", tail: "z", size: 0 }; +function append(p: Part, s: string): string { + return (text[p] += s); +} +console.log(append("head", "bc"), append("tail", "yx"), append("head", "!")); +console.log(JSON.stringify(text)); + +// Optional fields with ??=: only a missing value takes the right side. +type Phase = "dns" | "connect" | "tls"; +const timings: { dns?: number; connect?: number; tls?: number; total: number } = { total: 0 }; +function mark(phase: Phase, at: number): number { + return (timings[phase] ??= at); +} +console.log(mark("dns", 4), mark("connect", 9), mark("dns", 12), mark("tls", 0), mark("tls", 7)); +console.log(timings.dns, timings.connect, timings.tls, timings.total); + +// ||= and &&= test truthiness and write only in the selected branch. +const flags = { quiet: false, verbose: true, color: false }; +type Flag = keyof typeof flags; +function settle(f: Flag, value: boolean): string { + const a = (flags[f] ||= value); + const b = (flags[f] &&= f !== "color"); + return `${f}:${a}:${b}`; +} +console.log(settle("quiet", true), settle("verbose", false), settle("color", true)); +console.log(JSON.stringify(flags)); + +// Nested receivers and keys from a typed lookup. +const stats = { day: { hits: 1, misses: 2 }, week: { hits: 10, misses: 20 } }; +type Window = keyof typeof stats; +type Outcome = "hits" | "misses"; +const events: [Window, Outcome][] = [ + ["day", "hits"], + ["week", "misses"], + ["day", "misses"], + ["day", "hits"], +]; +for (const [w, o] of events) stats[w][o] += 1; +console.log(JSON.stringify(stats)); diff --git a/tests/corpus/6491-index-record-updates.ts b/tests/corpus/6491-index-record-updates.ts new file mode 100644 index 000000000..108d34012 --- /dev/null +++ b/tests/corpus/6491-index-record-updates.ts @@ -0,0 +1,44 @@ +// Compound assignment and ++/-- through a string key of an +// index-signature record: a missing entry reads as undefined, which every +// numeric operator turns into NaN, and the write inserts or replaces it. +const counts: Record = {}; +const words = "the cat and the hat and the bat".split(" "); +for (const w of words) { + counts[w] ??= 0; + counts[w]++; +} +console.log(JSON.stringify(counts)); + +const sums: { [key: string]: number } = { a: 1, b: 2 }; +sums["a"] += 10; +sums.b *= 3; +const key = "a"; +sums[key] -= 1; +console.log(JSON.stringify(sums)); + +// A missing entry: undefined op number is NaN, and the value form yields it. +console.log((sums["missing"] += 1), sums["missing"], Number.isNaN(sums["missing"])); +const later = sums["gone"]++; +console.log(later, sums["gone"], Object.keys(sums).join(",")); + +// Totals keyed by a runtime string, with the key and right side evaluated once. +let trace = ""; +function name(n: string): string { + trace += `key:${n};`; + return n; +} +function size(n: number): number { + trace += `rhs:${n};`; + return n; +} +const totals: Record = { disk: 0, net: 0 }; +const samples: [string, number][] = [ + ["disk", 4], + ["net", 7], + ["disk", 2], +]; +for (const [k, v] of samples) totals[name(k)] += size(v); +console.log(JSON.stringify(totals), trace); +const before = totals["net"]--; +const after = --totals["net"]; +console.log(before, after, totals["net"]); From 68dac76fdcd35fe3ad82d377b32d2c54c7562bae Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 11:11:59 -0500 Subject: [PATCH 32/39] Treat setEncoding's return value as the stream it was called on A method call declared to return `this`, such as setEncoding, resolves to its receiver's access path, so a 'data' listener on the stream that `const out = child.stdout.setEncoding("utf8")` returns receives strings. A setEncoding call that a preceding statement always evaluates (its expression, a variable initializer, or the receiver of a method chain in one of those) counts as preceding the listener. Only `new` and the child_process factories (spawn, fork, exec, execFile) count as creating a separate stream; any other call result may be a stream another binding already holds. --- .../builtins/child-process-methods.ts | 98 +++++++++++++++++-- .../node-types/stream-construction.ts | 21 ++++ 2 files changed, 111 insertions(+), 8 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts b/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts index aae51a8be..e1a25d169 100644 --- a/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts +++ b/packages/compiler/src/frontend/lowering/builtins/child-process-methods.ts @@ -543,7 +543,9 @@ export function lowerChildWriterMethodCall( /** A receiver spelled as a plain access path (`child.stdout`, `out`): its * root symbol and member names, or null for other forms. A `const` alias * of an access path (`const out = child.stdout`) resolves to that path, - * so every spelling of one stream gets the same key. */ + * and so does a method call declared to return `this` + * (`child.stdout.setEncoding("utf8")`), so every spelling of one stream + * gets the same key. */ function accessPathOf( lowerer: Lowerer, expr: ts.Expression, @@ -564,9 +566,84 @@ function accessPathOf( const base = accessPathOf(lowerer, expr.expression, depth + 1); return base === null ? null : { root: base.root, path: `${base.path}.${expr.name.text}` }; } + if (returnsReceiver(lowerer, expr)) { + return accessPathOf( + lowerer, + (expr.expression as ts.PropertyAccessExpression).expression, + depth + 1, + ); + } return null; } +/** A method call (`recv.m(...)`, not optional) whose declaration returns + * `this`, so its value is the receiver itself. */ +function returnsReceiver(lowerer: Lowerer, expr: ts.Expression): expr is ts.CallExpression { + if ( + !ts.isCallExpression(expr) || + expr.questionDotToken || + !ts.isPropertyAccessExpression(expr.expression) || + expr.expression.questionDotToken + ) + return false; + const declaration = lowerer.checker.getResolvedSignature(expr)?.declaration; + return declaration?.type?.kind === ts.SyntaxKind.ThisType; +} + +/** A call of a child_process factory (spawn, fork, exec, execFile), each + * of which returns a new ChildProcess. */ +function createsChildProcess(lowerer: Lowerer, call: ts.CallExpression): boolean { + const declaration = lowerer.checker.getResolvedSignature(call)?.declaration; + if ( + declaration === undefined || + !ts.isFunctionDeclaration(declaration) || + declaration.name === undefined || + !["spawn", "fork", "exec", "execFile"].includes(declaration.name.text) + ) + return false; + for (let node: ts.Node | undefined = declaration.parent; node; node = node.parent) { + if (ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name)) { + return node.name.text === "child_process" || node.name.text === "node:child_process"; + } + } + return false; +} + +/** The statement that always evaluates `call` when it runs: the call is + * the statement's expression, a variable's initializer, or the receiver of + * a method chain that is one of those. Null for calls under a condition, + * an operator, an argument list or any other construct. */ +function unconditionalStatementOf(call: ts.CallExpression): ts.Statement | null { + let node: ts.Node = call; + for (;;) { + const parent: ts.Node | undefined = node.parent; + if (parent === undefined) return null; + if ( + ts.isParenthesizedExpression(parent) || + ts.isNonNullExpression(parent) || + (ts.isPropertyAccessExpression(parent) && + parent.expression === node && + !parent.questionDotToken) || + (ts.isCallExpression(parent) && parent.expression === node && !parent.questionDotToken) + ) { + node = parent; + continue; + } + if (ts.isExpressionStatement(parent)) return parent; + if (ts.isVariableDeclaration(parent) && parent.initializer === node) { + const list = parent.parent; + const statement = list?.parent; + return list !== undefined && + ts.isVariableDeclarationList(list) && + statement !== undefined && + ts.isVariableStatement(statement) + ? statement + : null; + } + return null; + } +} + /** The initializer of a symbol declared once as a `const` variable, else null. */ function constInitializerOf(symbol: ts.Symbol): ts.Expression | null { const decls = symbol.declarations; @@ -583,18 +660,22 @@ function constInitializerOf(symbol: ts.Symbol): ts.Expression | null { } /** Whether two resolved access paths name different objects: the same root - * with different members, or two `const` roots each initialized by a call - * or `new` (such as two `spawn()` results). */ + * with different members, or two `const` roots each initialized by `new` + * or a child_process factory (such as two `spawn()` results). Any other + * call may return an object another binding already holds. */ function distinctPaths( + lowerer: Lowerer, a: { root: ts.Symbol; path: string }, b: { root: ts.Symbol; path: string }, ): boolean { if (a.root === b.root) return a.path !== b.path; const fresh = (root: ts.Symbol): boolean => { let init = constInitializerOf(root); - while (init !== null && (ts.isParenthesizedExpression(init) || ts.isAwaitExpression(init))) - init = init.expression; - return init !== null && (ts.isCallExpression(init) || ts.isNewExpression(init)); + while (init !== null && ts.isParenthesizedExpression(init)) init = init.expression; + if (init === null) return false; + return ( + ts.isNewExpression(init) || (ts.isCallExpression(init) && createsChildProcess(lowerer, init)) + ); }; return fresh(a.root) && fresh(b.root); } @@ -646,10 +727,11 @@ function childStreamEncodedAt( const target = node.expression.expression; const path = accessPathOf(lowerer, target); if (path !== null && path.root === key.root && path.path === key.path) { - if (ts.isExpressionStatement(node.parent) && preceding.has(node.parent)) before = true; + const statement = unconditionalStatementOf(node); + if (statement !== null && preceding.has(statement)) before = true; else elsewhere = true; } else if ( - (path === null || !distinctPaths(path, key)) && + (path === null || !distinctPaths(lowerer, path, key)) && lowerer.checker.isTypeAssignableTo(receiverType, lowerer.typeOf(target)) ) { // Another spelling that can hold this stream (a parameter, a `let` diff --git a/tests/fixtures/node-types/stream-construction.ts b/tests/fixtures/node-types/stream-construction.ts index 37a1b852e..a28643f7c 100644 --- a/tests/fixtures/node-types/stream-construction.ts +++ b/tests/fixtures/node-types/stream-construction.ts @@ -81,6 +81,26 @@ function run(script: string): Promise { }); } +// setEncoding returns its stream: a listener on the returned value, or on +// the stream after `const out = stream.setEncoding(...)`, receives strings. +function readEncoded(script: string): Promise { + return new Promise((resolve) => { + const child = spawn("/bin/sh", ["-c", script], { stdio: "pipe" }); + let outText = ""; + let errText = ""; + const out = child.stdout.setEncoding("utf8"); + out.on("data", (c: unknown) => { + outText += typeof c + ":" + String(c) + ";"; + }); + const err = child.stderr.setEncoding("utf8"); + child.stderr.on("data", (c: unknown) => { + errText += typeof c + ":" + String(c) + ";"; + }); + void err; + child.on("close", () => resolve(outText + " err " + errText)); + }); +} + async function main(): Promise { console.log("gunzip", await gunzipThrough(gzipSync(Buffer.from("payload")))); const file = path.join(os.tmpdir(), `scriptc-stream-construction-${process.pid}.txt`); @@ -88,6 +108,7 @@ async function main(): Promise { console.log("file", JSON.stringify(await readFileStream(file))); fs.unlinkSync(file); console.log("run", JSON.stringify(await run("echo hi; echo warn >&2"))); + console.log("encoded", JSON.stringify(await readEncoded("printf hi; printf warn >&2"))); for (const script of ["echo bad >&2; exit 3", "kill -TERM $$"]) { try { await run(script); From 1818faef10ebb0281e9eedbec51b307f049ecdb3 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 11:20:28 -0500 Subject: [PATCH 33/39] Keep a process stream open when JavaScript pipes into it pipe() called from untyped JavaScript on a native stream went through scr_stream_pipe directly, so a helper that piped into the converted process.stdout or process.stderr ended it at the source's end, and later writes through the program's NodeJS.WritableStream slots failed. The stream view's pipe now calls scr_stream_pipe_general, which keeps end off for those Writables, as Node's pipe() does for process.stdout and process.stderr. Adds corpus 6469. --- .../main.ts.json | 7 ++++ packages/runtime/src/scr_stream.c | 9 +++-- .../6469-node-stdio-writable-js-pipe/main.ts | 36 +++++++++++++++++++ .../6469-node-stdio-writable-js-pipe/pipe.js | 4 +++ .../main.ts.json | 1 + 5 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6469-node-stdio-writable-js-pipe/main.ts.json create mode 100644 tests/corpus/6469-node-stdio-writable-js-pipe/main.ts create mode 100644 tests/corpus/6469-node-stdio-writable-js-pipe/pipe.js create mode 100644 tests/harness/corpus-costs/6469-node-stdio-writable-js-pipe/main.ts.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6469-node-stdio-writable-js-pipe/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6469-node-stdio-writable-js-pipe/main.ts.json new file mode 100644 index 000000000..60b1360b0 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6469-node-stdio-writable-js-pipe/main.ts.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/6469-node-stdio-writable-js-pipe/pipe.js", + "/tests/corpus/6469-node-stdio-writable-js-pipe/main.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index 7c7b2279c..56f9fd54b 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -6451,8 +6451,10 @@ static ScrDyn *scr_stream_view_call(ScrClosure *cb, ScrDyn *const *args, size_t end = option->kind == SCR_DYN_UNDEF || scr_dyn_truthy(option); scr_dyn_release(option); } + /* scr_stream_pipe_general: a JavaScript caller can pipe into the + * converted process.stdout / process.stderr, which a pipe never ends. */ ScrStream *returned = !strcmp(method, "pipe") - ? scr_stream_pipe(stream, destination, end) : scr_stream_unpipe(stream, destination); + ? scr_stream_pipe_general(stream, destination, end) : scr_stream_unpipe(stream, destination); scr_stream_release(returned); if (!strcmp(method, "pipe") && !scr_exc_pending()) result = scr_dyn_retain(first); } @@ -6696,8 +6698,9 @@ ScrStream *scr_stream_stdio_writable(double fd) { } /* readable.pipe() into a Writable slot under the general representation - * (the readable.pipeGeneral libCall): Node never ends process.stdout or - * process.stderr from a pipe, so their converted Writable keeps `end` off. */ + * (the readable.pipeGeneral libCall), and pipe() called from JavaScript on + * a native stream: Node never ends process.stdout or process.stderr from a + * pipe, so their converted Writable keeps `end` off. */ ScrStream *scr_stream_pipe_general(ScrStream *src, ScrStream *dst, bool end) { if (dst == scr_stream_stdio_writables[0] || dst == scr_stream_stdio_writables[1]) end = false; return scr_stream_pipe(src, dst, end); diff --git a/tests/corpus/6469-node-stdio-writable-js-pipe/main.ts b/tests/corpus/6469-node-stdio-writable-js-pipe/main.ts new file mode 100644 index 000000000..258755f83 --- /dev/null +++ b/tests/corpus/6469-node-stdio-writable-js-pipe/main.ts @@ -0,0 +1,36 @@ +// process.stdout and process.stderr reach an untyped JavaScript helper +// through NodeJS.WritableStream slots, and the helper pipes into them. As +// in Node, the pipe leaves the process stream open, so later writes +// through the same slots still work. +import { Readable, Writable } from "node:stream"; +import { pipeAll } from "./pipe.js"; + +class Sink extends Writable { + readonly parts: string[] = []; + _write(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void): void { + this.parts.push(chunk.toString("utf8")); + callback(); + } +} + +function into(destination: NodeJS.WritableStream, parts: string[]): Promise { + return new Promise((resolve) => { + pipeAll(Readable.from(parts), destination, () => resolve()); + }); +} + +function write(destination: NodeJS.WritableStream, text: string): boolean { + return destination.write(text); +} + +async function main(): Promise { + const sink = new Sink(); + await into(sink, ["to ", "a sink"]); + console.log("sink", JSON.stringify(sink.parts), sink.writableEnded); + await into(process.stdout, ["piped ", "by javascript\n"]); + console.log("write after pipe", write(process.stdout, "still open\n")); + await into(process.stderr, ["piped to stderr\n"]); + write(process.stderr, "stderr still open\n"); +} + +void main(); diff --git a/tests/corpus/6469-node-stdio-writable-js-pipe/pipe.js b/tests/corpus/6469-node-stdio-writable-js-pipe/pipe.js new file mode 100644 index 000000000..d48d592ad --- /dev/null +++ b/tests/corpus/6469-node-stdio-writable-js-pipe/pipe.js @@ -0,0 +1,4 @@ +export function pipeAll(source, destination, done) { + source.on("end", () => done()); + source.pipe(destination); +} diff --git a/tests/harness/corpus-costs/6469-node-stdio-writable-js-pipe/main.ts.json b/tests/harness/corpus-costs/6469-node-stdio-writable-js-pipe/main.ts.json new file mode 100644 index 000000000..3fafdfc4b --- /dev/null +++ b/tests/harness/corpus-costs/6469-node-stdio-writable-js-pipe/main.ts.json @@ -0,0 +1 @@ +{ "plain": 3000, "san": 3500 } From 447f56e5c37193842269a997dadeecd7bbd931da Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 11:28:28 -0500 Subject: [PATCH 34/39] Share defaultMaxListeners with the typed EventEmitter, link instanceof alone, and clean up a pipe once - EventEmitter.defaultMaxListeners on the untyped constructor is Node's accessor over the default the typed EventEmitter reads: assignments validate as validateNumber(arg, 'defaultMaxListeners', 0) does, and getMaxListeners() of emitters without their own limit answers the new value. - dyn.builtinInstanceOf and dyn.functionInstanceOf link the constructor-function unit and the units it calls (dyn-invoke, inspect, symbol, emitter), so a program whose only use is `this instanceof F` links. - The legacy pipe's cleanup runs once: when the destination emits 'close' from end(), the cleanup still queued on the source's 'end' finds the listeners removed and emit('end') answers true. --- .../compiler/src/backend/native/executable.ts | 7 ++- packages/compiler/src/ir/runtime-features.ts | 21 ++++++-- ...7-constructor-function-instanceof.cjs.json | 6 +++ ...tructor-function-emitter-defaults.cjs.json | 6 +++ .../runtime-pack-matrix.mjs | 2 +- packages/runtime/src/scr_dyn_builtin_class.c | 49 +++++++++++++++-- .../5817-constructor-function-instanceof.cjs | 15 ++++++ ...-constructor-function-emitter-defaults.cjs | 53 +++++++++++++++++++ ...7-constructor-function-instanceof.cjs.json | 1 + ...tructor-function-emitter-defaults.cjs.json | 1 + 10 files changed, 150 insertions(+), 11 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5817-constructor-function-instanceof.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5818-constructor-function-emitter-defaults.cjs.json create mode 100644 tests/corpus/5817-constructor-function-instanceof.cjs create mode 100644 tests/corpus/5818-constructor-function-emitter-defaults.cjs create mode 100644 tests/harness/corpus-costs/5817-constructor-function-instanceof.cjs.json create mode 100644 tests/harness/corpus-costs/5818-constructor-function-emitter-defaults.cjs.json diff --git a/packages/compiler/src/backend/native/executable.ts b/packages/compiler/src/backend/native/executable.ts index bbb720cc7..740697323 100644 --- a/packages/compiler/src/backend/native/executable.ts +++ b/packages/compiler/src/backend/native/executable.ts @@ -236,7 +236,12 @@ const RUNTIME_UNITS: readonly RuntimeUnit[] = [ "scr_util_callable.c", ), unit( - (u) => u.opts.dynBuiltinClass && u.opts.inspect && u.opts.dynInvoke && u.opts.symbol, + (u) => + u.opts.dynBuiltinClass && + u.opts.inspect && + u.opts.dynInvoke && + u.opts.symbol && + (u.opts.emitter || u.opts.workers), "scr_dyn_builtin_class.c", ), unit((u) => u.opts.stream, "scr_stream.c", "scr_fs_stream.c"), diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 162bf55d3..02a4dd52a 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -234,10 +234,21 @@ const CHILD_PROCESS_LIB_FNS: ReadonlySet = new Set([ /** libCall name prefixes that link the child-process unit. */ const CHILD_PROCESS_LIB_PREFIXES: readonly string[] = ["child.", "cp.", "spawnRes.", "writer."]; +/** The entry points scr_dyn_builtin_class.c defines. The unit calls + * listeners through the dyn-invoke unit, renders unhandled 'error' + * payloads through the inspect unit, creates EventEmitter's private + * symbols through the symbol unit and shares defaultMaxListeners with the + * emitter unit, so each of them links all five. */ +const BUILTIN_CLASS_LIB_FNS: readonly IrLibFn[] = [ + "dyn.builtinClass", + "dyn.builtinInstanceOf", + "dyn.functionInstanceOf", +]; + /** Entry points that link the symbol unit, besides the sym. and disposable. families. */ const SYMBOL_LIB_FNS: ReadonlySet = new Set([ // EventEmitter's kShapeMode and kCapture properties - "dyn.builtinClass", + ...BUILTIN_CLASS_LIB_FNS, "dyn.usingDispose", "dyn.usingMethod", "util.isDeepStrictEqual", @@ -511,11 +522,11 @@ const RUNTIME_FEATURE_RULES = { * unit, render unhandled 'error' payloads through the inspect unit and * create EventEmitter's private symbols through the symbol unit. */ dynBuiltinClass: rule({ - fns: ["dyn.builtinClass", "dyn.builtinInstanceOf", "dyn.functionInstanceOf"], + fns: [...BUILTIN_CLASS_LIB_FNS], }), dynInvoke: rule({ initial: (mod) => mod.workers === true, - fns: [...DYN_INVOKE_LIB_FNS, ...UTIL_CALLABLE_LIB_FNS, "dyn.builtinClass"], + fns: [...DYN_INVOKE_LIB_FNS, ...UTIL_CALLABLE_LIB_FNS, ...BUILTIN_CLASS_LIB_FNS], // Constant-key reads of Object.prototype member names answer the // inherited member through scr_dyn_invoke.c. expr: (node, _tables) => @@ -532,7 +543,7 @@ const RUNTIME_FEATURE_RULES = { emitter: rule({ initial: (mod) => mod.workers === true || (mod.classes ?? []).some((c) => c.name === RUNTIME_EMITTER_CLASS), - fns: [...STREAM_LIB_FNS], + fns: [...STREAM_LIB_FNS, ...BUILTIN_CLASS_LIB_FNS], prefixes: ["emitter.", ...STREAM_LIB_PREFIXES], }), /** Subclasses of the runtime EventTarget/Event bases tear down and box @@ -567,7 +578,7 @@ const RUNTIME_FEATURE_RULES = { "global.native", "util.styleText", "crypto.cipherNew", - "dyn.builtinClass", + ...BUILTIN_CLASS_LIB_FNS, ...UTIL_CALLABLE_LIB_FNS, ], prefixes: ["insp.", "console.", "test."], diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5817-constructor-function-instanceof.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5817-constructor-function-instanceof.cjs.json new file mode 100644 index 000000000..d9ad97beb --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5817-constructor-function-instanceof.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5817-constructor-function-instanceof.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5818-constructor-function-emitter-defaults.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5818-constructor-function-emitter-defaults.cjs.json new file mode 100644 index 000000000..f22e1aaeb --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/5818-constructor-function-emitter-defaults.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/5818-constructor-function-emitter-defaults.cjs" + ], + "diags": [] +} diff --git a/packages/runtime-pack-common/runtime-pack-matrix.mjs b/packages/runtime-pack-common/runtime-pack-matrix.mjs index a6b11f53e..8f9a0bc69 100644 --- a/packages/runtime-pack-common/runtime-pack-matrix.mjs +++ b/packages/runtime-pack-common/runtime-pack-matrix.mjs @@ -91,7 +91,7 @@ export const OPTIONAL_RUNTIME_SOURCES = [ // Untyped EventEmitter and stream constructor values call listeners // through the dyn-invoke unit, inspect unhandled 'error' payloads and // create EventEmitter's private symbols. - ["scr_dyn_builtin_class.c", all("dynBuiltinClass", "inspect", "dynInvoke", "symbol")], + ["scr_dyn_builtin_class.c", all("dynBuiltinClass", "inspect", "dynInvoke", "symbol", "emitter")], ["scr_stream.c", "stream"], // The zlib stream classes reference both the zlib engine and the stream unit. ["scr_zlib_stream.c", all("zlib", "stream")], diff --git a/packages/runtime/src/scr_dyn_builtin_class.c b/packages/runtime/src/scr_dyn_builtin_class.c index 76a7ab15e..6d894615b 100644 --- a/packages/runtime/src/scr_dyn_builtin_class.c +++ b/packages/runtime/src/scr_dyn_builtin_class.c @@ -263,9 +263,7 @@ static double bc_max_listeners(ScrDyn *self) { if (!max) return -1; double value; if (bc_undefined(max)) { - ScrDyn *fallback = bc_get(bc_class(BC_EMITTER), "defaultMaxListeners"); - value = fallback ? bc_number(fallback) : 10; - if (fallback) scr_dyn_release(fallback); + value = scr_emitter_get_default_max(); } else { value = bc_number(max); } @@ -1017,6 +1015,42 @@ static ScrDyn *bc_set_max(ScrClosure *closure, ScrDyn *const *args, size_t argc) return self; } +/* EventEmitter.defaultMaxListeners, Node's accessor over the one default + * the typed EventEmitter reads too (scr_events_emitter.c). The setter + * validates as Node's validateNumber(arg, 'defaultMaxListeners', 0). */ +static ScrDyn *bc_default_max_get(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + (void)args; + (void)argc; + return scr_dyn_new_num(scr_emitter_get_default_max()); +} + +static ScrDyn *bc_default_max_set(ScrClosure *closure, ScrDyn *const *args, size_t argc) { + (void)closure; + static const char name[] = "defaultMaxListeners"; + ScrStr *key = scr_str_new(name, sizeof name - 1); + scr_emitter_set_default_max_chk(argc ? args[0] : scr_dyn_undefined(), key); + scr_str_release(key); + if (scr_exc_pending()) return NULL; + return scr_dyn_retain(scr_dyn_undefined()); +} + +static void bc_define_default_max(ScrDyn *ctor) { + ScrDyn *descriptor = scr_dyn_new_obj(); + scr_dyn_obj_set(descriptor, "get", 3, + scr_dyn_new_func(scr_closure_new(NULL, 0), bc_default_max_get, 0, "native:events", "get")); + scr_dyn_obj_set(descriptor, "set", 3, + scr_dyn_new_func(scr_closure_new(NULL, 0), bc_default_max_set, 1, "native:events", "set")); + scr_dyn_obj_set(descriptor, "enumerable", 10, scr_dyn_new_bool(true)); + ScrStr *name = scr_str_new("defaultMaxListeners", 19); + ScrDyn *key = scr_dyn_new_str(name); + scr_str_release(name); + ScrDyn *defined = scr_dyn_define_property(ctor, key, descriptor); + if (defined) scr_dyn_release(defined); + scr_dyn_release(key); + scr_dyn_release(descriptor); +} + static ScrDyn *bc_get_max(ScrClosure *closure, ScrDyn *const *args, size_t argc) { (void)closure; (void)args; @@ -1070,6 +1104,13 @@ static bool bc_pipe_on(ScrDyn *emitter, const char *event, ScrClosure *state, in } static bool bc_pipe_cleanup(ScrClosure *state) { + /* A second run (dest emitting 'close' from end(), with cleanup still + * queued on the source's 'end') finds the listeners removed, as Node's + * repeated removeListener calls do. */ + ScrDyn *handlers = bc_cap(state, BC_PIPE_HANDLERS); + bool cleaned = handlers->kind == SCR_DYN_ARR && scr_dyn_arr_len(handlers) == 0; + scr_dyn_release(handlers); + if (cleaned) return true; ScrDyn *source = bc_cap(state, BC_PIPE_SOURCE); ScrDyn *dest = bc_cap(state, BC_PIPE_DEST); bool ok = bc_pipe_remove(source, "data", state, BC_ONDATA) && @@ -1367,7 +1408,7 @@ static ScrDyn *bc_new_class(int kind, ScrDyn *parent) { bc_method(prototype, "listenerCount", bc_listener_count, 2); bc_method(prototype, "eventNames", bc_event_names, 0); bc_set(ctor, "EventEmitter", scr_dyn_retain(ctor)); - bc_set(ctor, "defaultMaxListeners", scr_dyn_new_num(10)); + bc_define_default_max(ctor); ScrDyn *count = scr_dyn_new_func(scr_closure_new(NULL, 0), bc_static_listener_count, 2, "native:events", "listenerCount"); bc_set(ctor, "listenerCount", count); } else if (kind == BC_STREAM) { diff --git a/tests/corpus/5817-constructor-function-instanceof.cjs b/tests/corpus/5817-constructor-function-instanceof.cjs new file mode 100644 index 000000000..355f53a64 --- /dev/null +++ b/tests/corpus/5817-constructor-function-instanceof.cjs @@ -0,0 +1,15 @@ +// `this instanceof F` in a constructor function, in a program that uses no +// EventEmitter or stream constructor value: the call-without-new idiom +// returns a new instance, and instanceof follows the function's prototype. +"use strict"; +function Glob(pattern) { + if (!(this instanceof Glob)) return new Glob(pattern); + this.pattern = pattern; +} +Glob.prototype.describe = function () { + return `glob ${this.pattern}`; +}; +const called = Glob("*.ts"); +const constructed = new Glob("*.js"); +console.log(called.describe(), constructed.describe()); +console.log(called instanceof Glob, {} instanceof Glob, Object.create(Glob.prototype) instanceof Glob); diff --git a/tests/corpus/5818-constructor-function-emitter-defaults.cjs b/tests/corpus/5818-constructor-function-emitter-defaults.cjs new file mode 100644 index 000000000..d89383b3a --- /dev/null +++ b/tests/corpus/5818-constructor-function-emitter-defaults.cjs @@ -0,0 +1,53 @@ +// EventEmitter.defaultMaxListeners read and written through the untyped +// EventEmitter constructor (Node's accessor and its validation), and a +// legacy pipe whose destination emits 'close' synchronously from end(). +"use strict"; +const util = require("util"); +const EventEmitter = require("events"); +const Stream = require("stream"); + +function Bus() { + EventEmitter.call(this); +} +util.inherits(Bus, EventEmitter); + +console.log(EventEmitter.defaultMaxListeners); +console.log(new Bus().getMaxListeners()); +EventEmitter.defaultMaxListeners = 3; +console.log(EventEmitter.defaultMaxListeners, new Bus().getMaxListeners()); +for (const value of [-1, "4", Number.NaN]) { + try { + EventEmitter.defaultMaxListeners = value; + } catch (error) { + console.log(error.name, error.code, error.message); + } +} +console.log(EventEmitter.defaultMaxListeners); +EventEmitter.defaultMaxListeners = 10; + +function Source() { + Stream.call(this); + this.readable = true; +} +util.inherits(Source, Stream); + +function Sink() { + Stream.call(this); + this.writable = true; +} +util.inherits(Sink, Stream); +Sink.prototype.write = function (chunk) { + console.log("write", chunk); + return true; +}; +Sink.prototype.end = function () { + console.log("sink end"); + this.emit("close"); +}; + +const source = new Source(); +const sink = new Sink(); +source.pipe(sink); +source.emit("data", "a"); +console.log("emit end", source.emit("end")); +console.log("listeners", source.listenerCount("end"), source.listenerCount("data"), sink.listenerCount("close")); diff --git a/tests/harness/corpus-costs/5817-constructor-function-instanceof.cjs.json b/tests/harness/corpus-costs/5817-constructor-function-instanceof.cjs.json new file mode 100644 index 000000000..15eedbeaa --- /dev/null +++ b/tests/harness/corpus-costs/5817-constructor-function-instanceof.cjs.json @@ -0,0 +1 @@ +{ "plain": 2655, "san": 7944 } diff --git a/tests/harness/corpus-costs/5818-constructor-function-emitter-defaults.cjs.json b/tests/harness/corpus-costs/5818-constructor-function-emitter-defaults.cjs.json new file mode 100644 index 000000000..0f4eb2e02 --- /dev/null +++ b/tests/harness/corpus-costs/5818-constructor-function-emitter-defaults.cjs.json @@ -0,0 +1 @@ +{ "plain": 2746, "san": 51663 } From 5aa4ccc3f2e1e07c518c91747c5277d97e17bef2 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 11:28:48 -0500 Subject: [PATCH 35/39] Update tests for the EvalError and builtin module changes --- .../compiler/test/native-callable-values.test.ts | 12 ++++++------ .../corpus/6126-punycode-dependency/main.cjs.json | 2 +- tests/harness/errors.test.ts | 8 ++++---- tests/harness/npm.test.ts | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/compiler/test/native-callable-values.test.ts b/packages/compiler/test/native-callable-values.test.ts index e64a9319e..6e65b0c99 100644 --- a/packages/compiler/test/native-callable-values.test.ts +++ b/packages/compiler/test/native-callable-values.test.ts @@ -102,19 +102,19 @@ test.each(["llvm"] as const)( writeFileSync( join(pkg, "index.js"), ` -const inspect = (value) => eval(value); +const inspect = (value) => process.on("__proto__", value); function stopped(value) { - eval(value); + process.on("__proto__", value); return { done() { return "wrong"; } }; } -try { console.log(stopped("0").done()); } -catch (error) { console.log(String(error).includes("SC2009")); } +try { console.log(stopped(() => {}).done()); } +catch (error) { console.log(String(error).includes("SC2020")); } const first = { inspect }; const second = { inspect }; console.log(typeof first.inspect, first.inspect === second.inspect); for (const callback of [first.inspect, second.inspect]) { - try { callback({}); } - catch (error) { console.log(String(error).includes("SC2009")); } + try { callback(() => {}); } + catch (error) { console.log(String(error).includes("SC2020")); } } `, ); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6126-punycode-dependency/main.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6126-punycode-dependency/main.cjs.json index 5de83361a..36f02246c 100644 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6126-punycode-dependency/main.cjs.json +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6126-punycode-dependency/main.cjs.json @@ -12,7 +12,7 @@ "end": 376 }, "milestone": "M4", - "hint": "relative imports (./file, ../dir/file), package.json-mediated project imports (#alias via the imports field, self-name references via exports), statically compiled npm packages, and the built-in fs, fs/promises, path, os, url, crypto, zlib, child_process, net, http, tls, https, http2, dgram, dns, util, util/types, string_decoder, querystring, readline, events, stream, stream/promises, stream/consumers, buffer, assert, assert/strict, worker_threads, cluster, tty, async_hooks, timers, timers/promises, diagnostics_channel, perf_hooks, module, and console modules (bare or node:-prefixed) and node:test (node:-prefixed only, like in Node) are supported" + "hint": "relative imports (./file, ../dir/file), package.json-mediated project imports (#alias via the imports field, self-name references via exports), statically compiled npm packages, and the built-in fs, fs/promises, path, os, url, crypto, zlib, child_process, net, http, tls, https, http2, dgram, dns, dns/promises, util, util/types, string_decoder, querystring, readline, events, stream, stream/promises, stream/consumers, stream/web, buffer, assert, assert/strict, worker_threads, cluster, tty, async_hooks, timers, timers/promises, diagnostics_channel, perf_hooks, module, v8, and console modules (bare or node:-prefixed) and node:test (node:-prefixed only, like in Node) are supported" } ] } diff --git a/tests/harness/errors.test.ts b/tests/harness/errors.test.ts index 6d93675ef..c35022f51 100644 --- a/tests/harness/errors.test.ts +++ b/tests/harness/errors.test.ts @@ -1040,7 +1040,7 @@ describe("refused statements in speculatively lowered JavaScript functions", () `(function () { var root = this; console.log("before"); - console.log(root === eval("this")); + process.on("__proto__", () => root); console.log("after"); }).call(this); `, @@ -1051,7 +1051,7 @@ describe("refused statements in speculatively lowered JavaScript functions", () "speculative-apply", `(function () { console.log("before"); - console.log(typeof eval("1")); + process.on("__proto__", () => {}); }).apply(null, []); `, "before\n", @@ -1062,7 +1062,7 @@ describe("refused statements in speculatively lowered JavaScript functions", () `class Base {} class Derived extends (function () { console.log("before"); - console.log(typeof eval("1")); + process.on("__proto__", () => {}); return Base; })() {} console.log(typeof Derived); @@ -1076,7 +1076,7 @@ console.log(typeof Derived); expect(r.stdout).toBe(stdout); expect(r.stderr).toMatch( new RegExp( - `^Uncaught Error: values of type '\\(x: string\\) => any' cannot be compiled: .* \\[SC2009 at .*${name}\\.cjs:${line}\\]\\n$`, + `^Uncaught Error: 'process\\.on\\("__proto__", \\.\\.\\.\\)' is part of the standard library types but has no scriptc lowering yet \\[SC2020 at .*${name}\\.cjs:${line}\\]\\n$`, ), ); }); diff --git a/tests/harness/npm.test.ts b/tests/harness/npm.test.ts index 25baaded6..168fdb6bd 100644 --- a/tests/harness/npm.test.ts +++ b/tests/harness/npm.test.ts @@ -60,7 +60,7 @@ const KNOWN: Record = { }, "island-web-plumbing": { run: "SC2020" }, "lazy-traps": { build: "SC2013" }, - "misc-shims": { build: "SC2013" }, + "misc-shims": { run: "SC2020" }, "namespace": { build: "SC1013" }, "node24-async-events": { run: "SC2020" }, "node24-commonjs-metadata": { run: "SC2020" }, From 437dc1163f77466486a63d759c57d15b70077b8e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 11:39:23 -0500 Subject: [PATCH 36/39] Refuse recursive unions in comptime baking The bakeability check tracks the unions it is inside as well as the records, so a union reachable from itself through an array (`type Tree = number | Tree[]`) reports SC1090 instead of recursing without end. The message names both recursive records and recursive unions. --- .../src/frontend/lowering/lower-comptime.ts | 28 +++++++++++-------- tests/diagnostics/comptime.ts | 4 +++ tests/harness/__snapshots__/comptime.ts.txt | 11 ++++++-- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/lower-comptime.ts b/packages/compiler/src/frontend/lowering/lower-comptime.ts index bdd020127..f239eea82 100644 --- a/packages/compiler/src/frontend/lowering/lower-comptime.ts +++ b/packages/compiler/src/frontend/lowering/lower-comptime.ts @@ -76,7 +76,7 @@ export function lowerComptime(lowerer: Lowerer, expr: ts.CallExpression): IrExpr "SC1090", expr, `baking comptime results of type '${lowerer.fmt(target)}' into the binary ` + - `(number, string, boolean, and arrays, records and unions of those lower to literals; a record type reachable from its own fields does not)`, + `(number, string, boolean, and arrays, records and unions of those lower to literals; a record or union type reachable from itself does not)`, ); } // 5. The host executes the extracted callback under a finite budget. @@ -112,13 +112,14 @@ function comptimeFailureDetail(error: unknown): string { * expression: number/string/boolean, arrays and record shapes of those, * and unions of those with null or undefined (the mixed rows of a JSON * table: `(string | number)[][]`), nested. Closures, class instances, - * promises, dyn, void, and recursive record types (a record reachable - * from its own fields) cannot be baked. */ + * promises, dyn, void, and recursive types (a record or union reachable + * from itself, directly or through arrays) cannot be baked. */ export function comptimeBakeable(lowerer: Lowerer, t: IrType): boolean { return bakeableWithin(lowerer, t, new Set()); } -/** comptimeBakeable below the records in `open`, whose fields are being +/** comptimeBakeable below the records and unions in `open` (keyed + * `record:` and `union:`), whose members are being * checked: reaching one of them again means the type is recursive. */ function bakeableWithin(lowerer: Lowerer, t: IrType, open: Set): boolean { switch (t.kind) { @@ -130,20 +131,23 @@ function bakeableWithin(lowerer: Lowerer, t: IrType, open: Set): boolean return bakeableWithin(lowerer, t.elem, open); case "record": { const shape = lowerer.shapes.get(t.shapeId); - if (!shape || open.has(t.shapeId)) return false; - open.add(t.shapeId); + const key = `record:${t.shapeId}`; + if (!shape || open.has(key)) return false; + open.add(key); const bakeable = shape.fields.every((f) => bakeableWithin(lowerer, f.type, open)); - open.delete(t.shapeId); + open.delete(key); return bakeable; } case "union": { const arms = lowerer.unions.get(t.unionId)?.arms; - return ( - arms !== undefined && - arms.every( - (arm) => isUnitType(arm) || (arm.kind !== "union" && bakeableWithin(lowerer, arm, open)), - ) + const key = `union:${t.unionId}`; + if (arms === undefined || open.has(key)) return false; + open.add(key); + const bakeable = arms.every( + (arm) => isUnitType(arm) || (arm.kind !== "union" && bakeableWithin(lowerer, arm, open)), ); + open.delete(key); + return bakeable; } default: return false; diff --git a/tests/diagnostics/comptime.ts b/tests/diagnostics/comptime.ts index 9c8239464..645779ea7 100644 --- a/tests/diagnostics/comptime.ts +++ b/tests/diagnostics/comptime.ts @@ -27,3 +27,7 @@ interface Chain { next: Chain | null; } const chain: Chain = comptime(() => ({ value: 1, next: null }) as Chain); + +// A union reachable from itself through an array has no literal form either. +type Tree = number | Tree[]; +const tree: Tree = comptime((): Tree => [1, [2, [3]]]); diff --git a/tests/harness/__snapshots__/comptime.ts.txt b/tests/harness/__snapshots__/comptime.ts.txt index 603c297a8..757c30e6c 100644 --- a/tests/harness/__snapshots__/comptime.ts.txt +++ b/tests/harness/__snapshots__/comptime.ts.txt @@ -47,9 +47,16 @@ comptime.ts:22:23 - error SC1110: comptime evaluation failed: expected 'string' | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 | -comptime.ts:29:22 - error SC1090: baking comptime results of type '{ next: null | ...; value: number }' into the binary (number, string, boolean, and arrays, records and unions of those lower to literals; a record type reachable from its own fields does not) is not supported yet +comptime.ts:29:22 - error SC1090: baking comptime results of type '{ next: null | ...; value: number }' into the binary (number, string, boolean, and arrays, records and unions of those lower to literals; a record or union type reachable from itself does not) is not supported yet 28 | } 29 | const chain: Chain = comptime(() => ({ value: 1, next: null }) as Chain); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 30 | \ No newline at end of file + 30 | + +comptime.ts:33:20 - error SC1090: baking comptime results of type '(...)[] | number' into the binary (number, string, boolean, and arrays, records and unions of those lower to literals; a record or union type reachable from itself does not) is not supported yet + + 32 | type Tree = number | Tree[]; + 33 | const tree: Tree = comptime((): Tree => [1, [2, [3]]]); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 34 | \ No newline at end of file From f7287e30ff72d988d0f49cb42a7fd3e6bbd8e4e7 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 11:40:52 -0500 Subject: [PATCH 37/39] Keep the fromEntries assertion bridge to entries without native arrays or records Object.fromEntries(...) as T passed the entries through the checked-dynamic bridge, which copies native arrays and records: an array shared by two entries, or held elsewhere, became separate copies, and writes through the asserted object no longer reached it. The bridge now applies only when the entries' values are scalars or checked-dynamic values, which pass by value or by identity; other entries keep the exact-shape fence (SC2002). Corpus 6467 checks that entries held as unknown keep their identity; diagnostics fixture fromentries-aliased-entries.ts pins the fence. --- .../frontend/lowering/expressions/narrowing.ts | 12 +++++++++--- .../fromentries-aliased-entries.ts.json | 6 ++++++ .../corpus/6467-fromentries-record-assertion.ts | 16 +++++++++++++++- tests/diagnostics/fromentries-aliased-entries.ts | 13 +++++++++++++ .../fromentries-aliased-entries.ts.txt | 8 ++++++++ 5 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/fromentries-aliased-entries.ts.json create mode 100644 tests/diagnostics/fromentries-aliased-entries.ts create mode 100644 tests/harness/__snapshots__/fromentries-aliased-entries.ts.txt diff --git a/packages/compiler/src/frontend/lowering/expressions/narrowing.ts b/packages/compiler/src/frontend/lowering/expressions/narrowing.ts index 0397497a8..ef6a30c03 100644 --- a/packages/compiler/src/frontend/lowering/expressions/narrowing.ts +++ b/packages/compiler/src/frontend/lowering/expressions/narrowing.ts @@ -1194,9 +1194,11 @@ function classInstanceOrAbsent(lowerer: Lowerer, type: IrType): boolean { * fresh object nothing else references, so the checked-dynamic bridge, * which keeps keys and their order the same way `JSON.parse(text) as T` * does, cannot be told apart from the original object; a value outside - * T throws the catchable TypeError of every checked cast. Other sources - * may be aliased, where a rebuilt object would sever mutation, so they - * keep the exact-shape fence. */ + * T throws the catchable TypeError of every checked cast. The entries' + * values must be scalars or checked-dynamic values, which the bridge + * passes by value or by identity; native arrays and records would be + * copied. Other sources may be aliased, where a rebuilt object would sever + * mutation, so they keep the exact-shape fence. */ function freshEntriesRecordAssertion( lowerer: Lowerer, expr: ts.AsExpression | ts.TypeAssertion, @@ -1208,6 +1210,10 @@ function freshEntriesRecordAssertion( const dest = lowerer.shapes.get(target.shapeId); if (!source?.indexValue || source.tuple || source.fields.length > 0) return null; if (!dest || dest.tuple || dest.indexValue || shapeHasAccessorSlots(dest)) return null; + // Native arrays and records in the entries would be copied on the way + // through the checked-dynamic bridge, severing their identity: only + // slots of scalars or checked-dynamic values pass. + if (extractionCopiesReference(lowerer, source.indexValue)) return null; let operand: ts.Expression = expr.expression; while (ts.isParenthesizedExpression(operand)) operand = operand.expression; if ( diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/fromentries-aliased-entries.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/fromentries-aliased-entries.ts.json new file mode 100644 index 000000000..7388f2b71 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/fromentries-aliased-entries.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/fromentries-aliased-entries.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6467-fromentries-record-assertion.ts b/tests/corpus/6467-fromentries-record-assertion.ts index 1496292b3..cf8f1c1ff 100644 --- a/tests/corpus/6467-fromentries-record-assertion.ts +++ b/tests/corpus/6467-fromentries-record-assertion.ts @@ -1,6 +1,6 @@ // `Object.fromEntries(...) as T` for a declared record T keeps exactly // the keys the entries created, in their order, as Node keeps the object -// itself. +// itself, as long as the entries hold scalars or checked-dynamic values. type Tags = { "error.type": string; "error.msg": string; "error.cause"?: string }; function scrub(input: string): string { @@ -27,3 +27,17 @@ const p = Object.fromEntries([ ["z", 3], ]) as Point; console.log(p, p.x + p.y, Object.keys(p), JSON.stringify(p)); + +// Entries held as unknown keep their identity: the object's members are +// the same array and record, and writes through either reach both. +type Holder = { list: number[]; point: { x: number } }; +const list = [1, 2]; +const point = { x: 1 }; +const entries: [string, unknown][] = [ + ["list", list], + ["point", point], +]; +const held = Object.fromEntries(entries) as Holder; +held.list.push(3); +held.point.x = 5; +console.log(list.length, point.x, held.list === list, held.point === point); diff --git a/tests/diagnostics/fromentries-aliased-entries.ts b/tests/diagnostics/fromentries-aliased-entries.ts new file mode 100644 index 000000000..ee5cc5338 --- /dev/null +++ b/tests/diagnostics/fromentries-aliased-entries.ts @@ -0,0 +1,13 @@ +// `Object.fromEntries(...) as T` keeps the object only when the entries' +// values are scalars or checked-dynamic values. Native arrays and records +// in the entries would be copied, severing their identity, so the +// assertion keeps the exact-shape fence (corpus 6467 covers the cases that +// lower). +type Scores = { a: number[]; b: number[] }; +const shared = [10]; +const scores = Object.fromEntries([ + ["a", shared], + ["b", shared], +]) as Scores; +scores.a.push(11); +console.log(shared.length, scores.b.length); diff --git a/tests/harness/__snapshots__/fromentries-aliased-entries.ts.txt b/tests/harness/__snapshots__/fromentries-aliased-entries.ts.txt new file mode 100644 index 000000000..7b0f02266 --- /dev/null +++ b/tests/harness/__snapshots__/fromentries-aliased-entries.ts.txt @@ -0,0 +1,8 @@ +fromentries-aliased-entries.ts:8:16 - error SC2002: record shapes must match exactly or width-coerce: expected '{ a: number[]; b: number[] }', got '{ [key: string]: number[] }' — 'a' is not a declared field of the source, and the source's index signature could hold it at runtime (a completed undefined would drop that value) + + 7 | const shared = [10]; + 8 | const scores = Object.fromEntries([ + | ^~~~~~~~~~~~~~~~~~~~ + 9 | ["a", shared], + + hint: width subtyping compiles as a copy (each expected field copied off the source; extra fields drop) — this pair is outside the copy's rules; build a literal with exactly the expected fields instead \ No newline at end of file From 08a3a7cf0624df62a3ed137a2f9969f2ec6e894c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 11:41:40 -0500 Subject: [PATCH 38/39] Read memarg flags through a function so the compiler compiles itself readMemargFlags took its reader as a `{ u32(): number }` record, and the validator (Reader) and translator (WasmCursor) pass class instances. The self-hosted compiler refuses a class instance in a record-typed parameter (SC2002), so the self-hosted LLVM emitter, the native frontend programs and the bootstrap seed builds failed. readMemargFlags now takes the reader's u32 function, and each caller passes `() => r.u32()`. --- packages/compiler/src/wasm/binary.ts | 4 ++-- packages/compiler/src/wasm/module.ts | 11 ++++++----- packages/compiler/src/wasm/translate.ts | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/compiler/src/wasm/binary.ts b/packages/compiler/src/wasm/binary.ts index ad5297739..eaedf25af 100644 --- a/packages/compiler/src/wasm/binary.ts +++ b/packages/compiler/src/wasm/binary.ts @@ -1245,7 +1245,7 @@ class FunctionValidator { /** A memarg. A memory other than 0 stops typing (multi-memory). */ memarg(naturalAlign: number): void { const r = this.r; - const { align, memory } = readMemargFlags(r); + const { align, memory } = readMemargFlags(() => r.u32()); if (align < 0) r.malformed("malformed memop flags"); if (memory !== 0) this.otherMemory(memory); if (this.m.memory64) r.u64(); @@ -1831,7 +1831,7 @@ class FunctionValidator { scanMemarg(): void { const r = this.r; - const { align, memory } = readMemargFlags(r); + const { align, memory } = readMemargFlags(() => r.u32()); if (align < 0) r.malformed("malformed memop flags"); if (memory !== 0) this.m.feature("multi-memory"); if (this.m.memory64) r.u64(); diff --git a/packages/compiler/src/wasm/module.ts b/packages/compiler/src/wasm/module.ts index d7ec38701..587a20d81 100644 --- a/packages/compiler/src/wasm/module.ts +++ b/packages/compiler/src/wasm/module.ts @@ -289,11 +289,12 @@ function decodeUtf8(bytes: Uint8Array, start: number, end: number): string { * 0; flags of 128 or more are malformed and answer align -1 without * reading further. The offset follows. Validation (binary.ts), translation * and skipImmediates all read memargs through this function, so they agree - * on where each instruction ends. */ -export function readMemargFlags(r: { u32(): number }): { align: number; memory: number } { - const flags = r.u32(); + * on where each instruction ends; `u32` reads the next u32 immediate of + * their own reader. */ +export function readMemargFlags(u32: () => number): { align: number; memory: number } { + const flags = u32(); if (flags >= 128) return { align: -1, memory: 0 }; - if (flags >= 64) return { align: flags - 64, memory: r.u32() }; + if (flags >= 64) return { align: flags - 64, memory: u32() }; return { align: flags, memory: 0 }; } @@ -386,7 +387,7 @@ export function skipImmediates(c: WasmCursor, op: number): void { } default: if (op >= 0x28 && op <= 0x3e) { - const flags = readMemargFlags(c); + const flags = readMemargFlags(() => c.u32()); if (flags.align < 0 || flags.memory !== 0) throw new Error(`wasm: memarg of memory ${flags.memory} is not supported`); c.u32(); diff --git a/packages/compiler/src/wasm/translate.ts b/packages/compiler/src/wasm/translate.ts index 813dab84a..f17c5dae3 100644 --- a/packages/compiler/src/wasm/translate.ts +++ b/packages/compiler/src/wasm/translate.ts @@ -851,7 +851,7 @@ class FunctionTranslator { /** The offset of a memarg over memory 0 (the only memory a translatable * module has). */ memargOffset(c: WasmCursor): number { - const flags = readMemargFlags(c); + const flags = readMemargFlags(() => c.u32()); if (flags.align < 0 || flags.memory !== 0) throw new WasmTranslateError(`memarg of memory ${flags.memory} is not supported`); return c.u32(); From cf003870eef41776060fd1a16b9b062726ecfe63 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 12:18:55 -0500 Subject: [PATCH 39/39] Write invisible characters in the WebAssembly spec data as escapes --- tests/corpus/webassembly-spec-imports/data.mjs | 2 +- tests/wasm-spec/gen.mjs | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/corpus/webassembly-spec-imports/data.mjs b/tests/corpus/webassembly-spec-imports/data.mjs index c082547b8..5ecccab26 100644 --- a/tests/corpus/webassembly-spec-imports/data.mjs +++ b/tests/corpus/webassembly-spec-imports/data.mjs @@ -134,4 +134,4 @@ export const modules = [ "AGFzbQEAAAABBQFgAAF/A+ED3wMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAerId8DAAAAATAAAQItMAACAV8AAwEkAAQBQAAFIX4hQCMkJV4mKigpXytgLT17fXxbXVw6IjsnPD4/LC4vIAAGA05hTgAHCEluZmluaXR5AAgCaWYACQZtYWxsb2MACgdfbWFsbG9jAAsIX19tYWxsb2MADAFhAA0BQQAOA++7vwAPAsOFABADQcyKABED4oSrABID76yDABMEZu+sgQAUA2ZmaQAVEAABAgMEBQYHCAkKCwwNDg8AFhAQERITFBUWFxgZGhscHR4fABcCIH8AGCDCgMKBwoLCg8KEwoXChsKHwojCicKKwovCjMKNwo7CjwAZIMKQwpHCksKTwpTClcKWwpfCmMKZwprCm8Kcwp3CnsKfABoY77+w77+x77+y77+z77+077+177+277+3ABsY77+477+577+677+777+877+977++77+/ABww4pCA4pCB4pCC4pCD4pCE4pCF4pCG4pCH4pCI4pCJ4pCK4pCL4pCM4pCN4pCO4pCPAB0w4pCQ4pCR4pCS4pCT4pCU4pCV4pCW4pCX4pCY4pCZ4pCa4pCb4pCc4pCd4pCe4pCfAB4G4pCg4pChAB8q77+w77+x77+y77+z77+077+177+277+377+477+577+677+777+877+9ACAD4oCNACED4oCMACICzY8AIwPigaAAJAPitb8AJQTwkYG/ACYD4aCOACcW77+v4oCLwqDCreKBoOGagOKAruKArQAoJ+KAjuKAj+KAkeKAqOKAqeKAquKAq+KArOKAr+KBpuKBp+KBqOKBqQApEuKBquKBq+KBrOKBreKBruKBrwAqDOKBoeKBouKBo+KBpAArDPCQgIDzn7+/9I+/vwAsgQJazI/NhsyGzZvNjMy0zZjNns2HzKvMpcyqzZPNiM2UzY7Ml8yezLrMr8yxzJ7MmcyxzJzMlsygYc2XzajMjsyEzIbNl8y/zaHNn82AzLbNgcylzLDMs8ytzZnMssyxzLnMnc2OzLxszYTNisyazZfNps2EzavMh82BzLbMt82JzKnMucyrzJ3Nls2FzJnMssy8zYfNms2NzK7NjsylzYXMnmfNg8yQzIXNrsyUzJDMjsyCzI/Mvs2KzI3Ni82KzafMgcyGzabNnsy2zZXNlM2azKlvzYvMlM2QzarNqcyhzY/MosynzYHMq8yZzKTMrs2WzZnNk8y6zJzMqcy8zJjMoAAtDOGFn+GFoOOFpO++oAAuA++4gAAvA++4hAAwBPOghIAAMQTzoIevADICzIgAMwEKADQD4pCkADUD4oCoADYBDQA3Ag0KADgCCg0AOQEeADoBCwA7AQwAPALChQA9A+KAqQA+A+KApgA/A+KPjgBAAsKLAEECwowAQgLCjQBDA+KGtQBEA+KGqQBFA+KMpABGA+KktgBHA+KGsgBIA+KuqABJA+KusABKA++/vQBLA++3kABMA++3kQBNA++3kgBOA++3kwBPA++3lABQA++3lQBRA++3lgBSA++3lwBTA++3mABUA++3mQBVA++3mgBWA++3mwBXA++3nABYA++3nQBZA++3ngBaA++3nwBbA++3oABcA++3oQBdA++3ogBeA++3owBfA++3pABgA++3pQBhA++3pgBiA++3pwBjA++3qABkA++3qQBlA++3qgBmA++3qwBnA++3rABoA++3rQBpA++3rgBqA++3rwBrA++/vgBsA++/vwBtBPCfv74AbgTwn7+/AG8E8K+/vgBwBPCvv78AcQTwv7++AHIE8L+/vwBzBPGPv74AdATxj7+/AHUE8Z+/vgB2BPGfv78AdwTxr7++AHgE8a+/vwB5BPG/v74AegTxv7+/AHsE8o+/vgB8BPKPv78AfQTyn7++AH4E8p+/vwB/BPKvv74AgAEE8q+/vwCBAQTyv7++AIIBBPK/v78AgwEE84+/vgCEAQTzj7+/AIUBBPOfv74AhgEE85+/vwCHAQTzr7++AIgBBPOvv78AiQEE87+/vgCKAQTzv7+/AIsBBPSPv74AjAEE9I+/vwCNAQnMiOKAvcyIzIkAjgEDYWJjAI8BBuKArWFiYwCQAQbigK5jYmEAkQEJ4oCtYWJj4oCuAJIBCeKArmNiYeKArQCTAQTwnZGoAJQBBPCdkLQAlQEE8J2YiACWAQTwnZi8AJcBBPCdkIAAmAEE8J2TkACZAQTwnZWsAJoBBPCdl5QAmwEE8J2SnACcAQTwnZSEAJ0BBPCdlLgAngEE8J2WoACfAQTwnZmwAKABA+G0gAChAQPhtKwAogED4pK2AKMBA++8oQCkAQTwn4SQAKUBBPCfhLAApgEE86CBgQCnAQZVKzAwNDEAqAEEQeKAiwCpAQLQkACqAQPqmZYAqwED4re8AKwBA+K3tgCtAQPisa8ArgEE8J+FkACvAQTwn4WwALABA+KwrQCxAQTwkJCCALIBBPCQkIgAswEE8JCSsAC0AQLDgAC1AQLDgQC2AQLDggC3AQLDgwC4AQLDhAC5AQLEgAC6AQLEggC7AQLEhAC8AQLHjQC9AQLHngC+AQLHoAC/AQLHugDAAQLIgADBAQLIggDCAQLIpgDDAQLIugDEAQLTkADFAQLTkgDGAQLfigDHAQPgoKEAyAED4KCiAMkBA+CgowDKAQPgoKQAywED4KClAMwBA+CkhADNAQPgpIUAzgED4KWyAM8BA+CmhQDQAQPgqIUA0QED4KqFANIBA+CshQDTAQPgroUA1AED4LCFANUBA+CyhQDWAQPgtIUA1wED4LiwANgBA+C6sADZAQPgvIEA2gED4L2oANsBA+C+uADcAQPhgKEA3QED4YCiAN4BA+GCnADfAQPhhaEA4AED4YqgAOEBA+GLkADiAQPhjqAA4wED4ZCKAOQBA+GWswDlAQPhmqgA5gED4ZqqAOcBA+GbhgDoAQPhnIAA6QED4ZygAOoBA+GdgADrAQPhnaAA7AED4aCgAO0BA+GihwDuAQPhpKAA7wED4aWjAPABA+GolQDxAQPhqYsA8gED4amhAPMBA+GugwD0AQPhr4AA9QED4a+BAPYBA+GwowD3AQPhuIAA+AED4bqgAPkBA+G6ogD6AQPhuqQA+wED4bqmAPwBA+G6qAD9AQPhuqoA/gED4bqsAP8BA+G6rgCAAgPhurAAgQID4bqyAIICA+G6tACDAgPhurYAhAID44GCAIUCA+OCogCGAgPjhJoAhwID44WPAIgCA+OIjgCJAgPjiI8AigID44iQAIsCA+OIkQCMAgPjiJIAjQID44iTAI4CA+OIlACPAgPjiJUAkAID44iWAJECA+OIlwCSAgPjiJgAkwID44iZAJQCA+OImgCVAgPjiJsAlgID44muAJcCA+OJrwCYAgPjibAAmQID44mxAJoCA+OJsgCbAgPjibMAnAID44m0AJ0CA+OJtQCeAgPjibYAnwID44m3AKACA+OJuAChAgPjibkAogID44m6AKMCA+OJuwCkAgPji5AApQID6oCKAKYCA+qTrgCnAgPqlYkAqAID6pqgAKkCA+qggACqAgPqoKMAqwID6qGdAKwCA+qiggCtAgPqo6oArgID6qSiAK8CA+qlhgCwAgPqpoQAsQID6qiAALICA++9sQCzAgPvv4IAtAIE8JCAgAC1AgTwkIqAALYCBPCQiqAAtwIE8JCMgAC4AgTwkI6gALkCBPCQkpYAugIE8JCUgAC7AgTwkJ2AALwCBPCQoIAAvQIE8JCkoAC+AgTwkKaAAL8CBPCQpqAAwAIE8JCogADBAgTwkKyAAMICBPCQsIAAwwIE8JCwgQDEAgTwkLKAAMUCBPCRgIUAxgIE8JGCgwDHAgTwkYSnAMgCBPCRhZAAyQIE8JGGgwDKAgTwkYiAAMsCBPCRioAAzAIE8JGKsADNAgTwkYyFAM4CBPCRjbAAzwIE8JGQgADQAgTwkZKBANECBPCRloAA0gIE8JGYgADTAgTwkZqAANQCBPCRnJIA1QIE8JGcoADWAgTwkaKhANcCBPCRq5UA2AIE8JGwgADZAgTwkbKPANoCBPCRsq8A2wIE8JKAgADcAgTwlqeVAN0CBPCWqYYA3gIE8JarpwDfAgTwlr2UAOACBPCbsYEA4QIE8JuxpADiAgTwnqCjAOMCBPCfh6YA5AID4rGtAOUCAs6bAOYCA+KxsADnAgLCqgDoAgPiiIAA6QID4oKzAOoCBPCQpIAA6wID4rKAAOwCBPCQjLAA7QICzoYA7gICzpEA7wID4byIAPACA+G8iQDxAgPhvIoA8gID4byLAPMCA+G8jAD0AgPhvI0A9QID4byOAPYCA+G8jwD3AgPhvogA+AID4b6JAPkCA+G+igD6AgPhvosA+wID4b6MAPwCA+G+jQD9AgPhvo4A/gID4b6PAP8CA+G+uACAAwPhvrkAgQMD4b66AIIDA+G+uwCDAwPhvrwAhAME8J2aqACFAwTwnZuiAIYDBPCdnJwAhwME8J2dlgCIAwTwnZ6QAIkDA+KNtgCKAwPijboAiwMD4qmcAIwDA+GXhQCNAwPhjqoAjgOcASnLusu88JSXj/CdhbTwnYW28J2FuPCdhbrigb7igo7inaninavin6/vtL/vuLbvuZrvvInvvaDzoICp4p2z4p214p+n4p+p4p+r4p+t4qaI4qaK4qaW4rij4ril77iY77i477i677i877i+77mA77mC77mE77mI77mc77me77y9772d772j86CBnfOggb3Cu+KAmeKAneKAuuKdrwCPA5wBKMu5y7vwlJeO8J2Fs/CdhbXwnYW38J2FueKBveKCjeKdqOKdquKfru+0vu+4te+5me+8iO+9n/OggKjinbLinbTin6bin6jin6rin6zipofiponippXiuKLiuKTvuJfvuLfvuLnvuLvvuL3vuL/vuYHvuYPvuYfvuZvvuZ3vvLvvvZvvvaLzoIGb86CBu8Kr4oCY4oCc4oC54p2uAJADCPCdqovwnaqkAJEDBPCdqosAkgMCwr0AkwMFMeKBhDIAlAMDMS8yAJUDA+CtswCWAwPgtbQAlwMD4rO9AJgDA+qgsQCZAwTwkIWBAJoDBPCQhbUAmwME8JCFtgCcAwTwkKa9AJ0DBPCQubsAngMD77yCAJ8DAX8AoAMBCAChAwPijKsAogMD4oymAKMDA+KQiACkAwPikKEApQMD4be7AKYDAQ8ApwMD4oaQAKgDA+KMpwCpAwPijZIAqgMD4o2UAKsDA+KNogCsAwPijasArQMBGgCuAwPikKYArwMD4pCaALADA++/vACxAwE/ALIDAsK/ALMDA+GlhQC0AwLNvgC1AwLVngC2AwLYnwC3AwPhjacAuAMD4oGHALkDA+KNsAC6AwPinZMAuwMD4p2UALwDA+KzugC9AwPis7sAvgMD4riuAL8DA+OJhADAAwPqmI8AwQMD6pu3AMIDA++4lgDDAwPvuZYAxAMD77yfAMUDBPCRhYMAxgME8J6lnwDHAwTzoIC/AMgDBPCWoYQAyQMD4q+RAMoDAsK2AMsDA+KBiwDMAwLcgADNAwPhg7sAzgMD4Y2oAM8DA+OAtwDQAwPinaEA0QMD4riPANIDA+K4kADTAwPiuJEA1AMD4riOANUDARQA1gMD4piZANcDA+K4vwDYAwPjgIcA2QMD4LmbANoDA+qZrgDbAwLPkwDcAwLPlADdAwPhupsA3gMK/BXfAwQAQQALBABBAQsEAEECCwQAQQMLBABBBAsEAEEFCwQAQQYLBABBBwsEAEEICwQAQQkLBABBCgsEAEELCwQAQQwLBABBDQsEAEEOCwQAQQ8LBABBEAsEAEERCwQAQRILBABBEwsEAEEUCwQAQRULBABBFgsEAEEXCwQAQRgLBABBGQsEAEEaCwQAQRsLBABBHAsEAEEdCwQAQR4LBABBHwsEAEEgCwQAQSELBABBIgsEAEEjCwQAQSQLBABBJQsEAEEmCwQAQScLBABBKAsEAEEpCwQAQSoLBABBKwsEAEEsCwQAQS0LBABBLgsEAEEvCwQAQTALBABBMQsEAEEyCwQAQTMLBABBNAsEAEE1CwQAQTYLBABBNwsEAEE4CwQAQTkLBABBOgsEAEE7CwQAQTwLBABBPQsEAEE+CwQAQT8LBQBBwAALBQBBwQALBQBBwgALBQBBwwALBQBBxAALBQBBxQALBQBBxgALBQBBxwALBQBByAALBQBByQALBQBBygALBQBBywALBQBBzAALBQBBzQALBQBBzgALBQBBzwALBQBB0AALBQBB0QALBQBB0gALBQBB0wALBQBB1AALBQBB1QALBQBB1gALBQBB1wALBQBB2AALBQBB2QALBQBB2gALBQBB2wALBQBB3AALBQBB3QALBQBB3gALBQBB3wALBQBB4AALBQBB4QALBQBB4gALBQBB4wALBQBB5AALBQBB5QALBQBB5gALBQBB5wALBQBB6AALBQBB6QALBQBB6gALBQBB6wALBQBB7AALBQBB7QALBQBB7gALBQBB7wALBQBB8AALBQBB8QALBQBB8gALBQBB8wALBQBB9AALBQBB9QALBQBB9gALBQBB9wALBQBB+AALBQBB+QALBQBB+gALBQBB+wALBQBB/AALBQBB/QALBQBB/gALBQBB/wALBQBBgAELBQBBgQELBQBBggELBQBBgwELBQBBhAELBQBBhQELBQBBhgELBQBBhwELBQBBiAELBQBBiQELBQBBigELBQBBiwELBQBBjAELBQBBjQELBQBBjgELBQBBjwELBQBBkAELBQBBkQELBQBBkgELBQBBkwELBQBBlAELBQBBlQELBQBBlgELBQBBlwELBQBBmAELBQBBmQELBQBBmgELBQBBmwELBQBBnAELBQBBnQELBQBBngELBQBBnwELBQBBoAELBQBBoQELBQBBogELBQBBowELBQBBpAELBQBBpQELBQBBpgELBQBBpwELBQBBqAELBQBBqQELBQBBqgELBQBBqwELBQBBrAELBQBBrQELBQBBrgELBQBBrwELBQBBsAELBQBBsQELBQBBsgELBQBBswELBQBBtAELBQBBtQELBQBBtgELBQBBtwELBQBBuAELBQBBuQELBQBBugELBQBBuwELBQBBvAELBQBBvQELBQBBvgELBQBBvwELBQBBwAELBQBBwQELBQBBwgELBQBBwwELBQBBxAELBQBBxQELBQBBxgELBQBBxwELBQBByAELBQBByQELBQBBygELBQBBywELBQBBzAELBQBBzQELBQBBzgELBQBBzwELBQBB0AELBQBB0QELBQBB0gELBQBB0wELBQBB1AELBQBB1QELBQBB1gELBQBB1wELBQBB2AELBQBB2QELBQBB2gELBQBB2wELBQBB3AELBQBB3QELBQBB3gELBQBB3wELBQBB4AELBQBB4QELBQBB4gELBQBB4wELBQBB5AELBQBB5QELBQBB5gELBQBB5wELBQBB6AELBQBB6QELBQBB6gELBQBB6wELBQBB7AELBQBB7QELBQBB7gELBQBB7wELBQBB8AELBQBB8QELBQBB8gELBQBB8wELBQBB9AELBQBB9QELBQBB9gELBQBB9wELBQBB+AELBQBB+QELBQBB+gELBQBB+wELBQBB/AELBQBB/QELBQBB/gELBQBB/wELBQBBgAILBQBBgQILBQBBggILBQBBgwILBQBBhAILBQBBhQILBQBBhgILBQBBhwILBQBBiAILBQBBiQILBQBBigILBQBBiwILBQBBjAILBQBBjQILBQBBjgILBQBBjwILBQBBkAILBQBBkQILBQBBkgILBQBBkwILBQBBlAILBQBBlQILBQBBlgILBQBBlwILBQBBmAILBQBBmQILBQBBmgILBQBBmwILBQBBnAILBQBBnQILBQBBngILBQBBnwILBQBBoAILBQBBoQILBQBBogILBQBBowILBQBBpAILBQBBpQILBQBBpgILBQBBpwILBQBBqAILBQBBqQILBQBBqgILBQBBqwILBQBBrAILBQBBrQILBQBBrgILBQBBrwILBQBBsAILBQBBsQILBQBBsgILBQBBswILBQBBtAILBQBBtQILBQBBtgILBQBBtwILBQBBuAILBQBBuQILBQBBugILBQBBuwILBQBBvAILBQBBvQILBQBBvgILBQBBvwILBQBBwAILBQBBwQILBQBBwgILBQBBwwILBQBBxAILBQBBxQILBQBBxgILBQBBxwILBQBByAILBQBByQILBQBBygILBQBBywILBQBBzAILBQBBzQILBQBBzgILBQBBzwILBQBB0AILBQBB0QILBQBB0gILBQBB0wILBQBB1AILBQBB1QILBQBB1gILBQBB1wILBQBB2AILBQBB2QILBQBB2gILBQBB2wILBQBB3AILBQBB3QILBQBB3gILBQBB3wILBQBB4AILBQBB4QILBQBB4gILBQBB4wILBQBB5AILBQBB5QILBQBB5gILBQBB5wILBQBB6AILBQBB6QILBQBB6gILBQBB6wILBQBB7AILBQBB7QILBQBB7gILBQBB7wILBQBB8AILBQBB8QILBQBB8gILBQBB8wILBQBB9AILBQBB9QILBQBB9gILBQBB9wILBQBB+AILBQBB+QILBQBB+gILBQBB+wILBQBB/AILBQBB/QILBQBB/gILBQBB/wILBQBBgAMLBQBBgQMLBQBBggMLBQBBgwMLBQBBhAMLBQBBhQMLBQBBhgMLBQBBhwMLBQBBiAMLBQBBiQMLBQBBigMLBQBBiwMLBQBBjAMLBQBBjQMLBQBBjgMLBQBBjwMLBQBBkAMLBQBBkQMLBQBBkgMLBQBBkwMLBQBBlAMLBQBBlQMLBQBBlgMLBQBBlwMLBQBBmAMLBQBBmQMLBQBBmgMLBQBBmwMLBQBBnAMLBQBBnQMLBQBBngMLBQBBnwMLBQBBoAMLBQBBoQMLBQBBogMLBQBBowMLBQBBpAMLBQBBpQMLBQBBpgMLBQBBpwMLBQBBqAMLBQBBqQMLBQBBqgMLBQBBqwMLBQBBrAMLBQBBrQMLBQBBrgMLBQBBrwMLBQBBsAMLBQBBsQMLBQBBsgMLBQBBswMLBQBBtAMLBQBBtQMLBQBBtgMLBQBBtwMLBQBBuAMLBQBBuQMLBQBBugMLBQBBuwMLBQBBvAMLBQBBvQMLBQBBvgMLBQBBvwMLBQBBwAMLBQBBwQMLBQBBwgMLBQBBwwMLBQBBxAMLBQBBxQMLBQBBxgMLBQBBxwMLBQBByAMLBQBByQMLBQBBygMLBQBBywMLBQBBzAMLBQBBzQMLBQBBzgMLBQBBzwMLBQBB0AMLBQBB0QMLBQBB0gMLBQBB0wMLBQBB1AMLBQBB1QMLBQBB1gMLBQBB1wMLBQBB2AMLBQBB2QMLBQBB2gMLBQBB2wMLBQBB3AMLBQBB3QMLBQBB3gML", "AGFzbQEAAAABCgJgAX8AYAJ/fwACKwIIc3BlY3Rlc3QJcHJpbnRfaTMyAAAIc3BlY3Rlc3QJcHJpbnRfaTMyAAADAgEBBwsBB3ByaW50MzIAAgoMAQoAIAAQACABEAEL", ]; -export const script = "[[\"file\",\"imports.wast\"],[\"module\",3,0],[\"register\",\"test\"],[\"module\",26,1],[\"invoke\",85,0,\"print32\",[\"i32:13\"]],[\"invoke\",86,0,\"print64\",[\"i64:24\"]],[\"module\",97,2],[\"invoke\",104,0,\"print_i32\",[\"i32:13\"]],[\"module\",107,3],[\"invoke\",114,0,\"print_i32\",[\"i32:5\",\"i32:11\"]],[\"module\",116,4],[\"module\",117,5],[\"module\",118,6],[\"module\",119,7],[\"module\",120,8],[\"module\",121,9],[\"module\",122,10],[\"instantiate\",125,11],[\"instantiate\",129,12],[\"instantiate\",134,13],[\"instantiate\",138,14],[\"instantiate\",142,15],[\"instantiate\",146,16],[\"instantiate\",150,17],[\"instantiate\",154,18],[\"instantiate\",158,19],[\"instantiate\",162,20],[\"instantiate\",166,21],[\"instantiate\",170,22],[\"instantiate\",174,23],[\"instantiate\",178,24],[\"instantiate\",182,25],[\"instantiate\",186,26],[\"instantiate\",190,27],[\"instantiate\",194,28],[\"instantiate\",199,29],[\"instantiate\",203,30],[\"instantiate\",207,31],[\"instantiate\",211,32],[\"instantiate\",215,33],[\"instantiate\",219,34],[\"module\",226,35],[\"invoke\",246,0,\"get-0\",[]],[\"invoke\",247,0,\"get-1\",[]],[\"invoke\",248,0,\"get-x\",[]],[\"invoke\",249,0,\"get-y\",[]],[\"invoke\",250,0,\"get-4\",[]],[\"invoke\",251,0,\"get-5\",[]],[\"invoke\",252,0,\"get-6\",[]],[\"module\",254,36],[\"module\",255,37],[\"module\",256,38],[\"instantiate\",259,39],[\"instantiate\",263,40],[\"instantiate\",268,41],[\"instantiate\",272,42],[\"instantiate\",276,43],[\"instantiate\",280,44],[\"instantiate\",284,45],[\"instantiate\",288,46],[\"instantiate\",292,47],[\"instantiate\",296,48],[\"instantiate\",300,49],[\"instantiate\",304,50],[\"instantiate\",308,51],[\"instantiate\",312,52],[\"instantiate\",317,53],[\"instantiate\",321,54],[\"instantiate\",325,55],[\"instantiate\",329,56],[\"instantiate\",333,57],[\"instantiate\",337,58],[\"module\",344,59],[\"invoke\",356,0,\"call\",[\"i32:0\"]],[\"invoke\",357,0,\"call\",[\"i32:1\"]],[\"invoke\",358,0,\"call\",[\"i32:2\"]],[\"invoke\",359,0,\"call\",[\"i32:3\"]],[\"invoke\",360,0,\"call\",[\"i32:100\"]],[\"module\",363,59],[\"invoke\",375,0,\"call\",[\"i32:0\"]],[\"invoke\",376,0,\"call\",[\"i32:1\"]],[\"invoke\",377,0,\"call\",[\"i32:2\"]],[\"invoke\",378,0,\"call\",[\"i32:3\"]],[\"invoke\",379,0,\"call\",[\"i32:100\"]],[\"module\",381,60],[\"module\",388,61],[\"module\",389,62],[\"module\",390,63],[\"module\",391,64],[\"module\",392,65],[\"module\",393,66],[\"module\",394,67],[\"module\",395,68],[\"module\",396,69],[\"module\",397,70],[\"module\",398,71],[\"module\",399,72],[\"module\",400,73],[\"module\",401,74],[\"module\",402,75],[\"module\",403,76],[\"module\",404,77],[\"module\",405,78],[\"module\",406,79],[\"module\",407,80],[\"instantiate\",410,81],[\"instantiate\",414,82],[\"instantiate\",419,83],[\"instantiate\",423,84],[\"instantiate\",427,85],[\"instantiate\",431,86],[\"instantiate\",435,87],[\"instantiate\",439,88],[\"instantiate\",444,89],[\"instantiate\",448,90],[\"instantiate\",452,91],[\"instantiate\",456,92],[\"module\",464,93],[\"invoke\",471,0,\"load\",[\"i32:0\"]],[\"invoke\",472,0,\"load\",[\"i32:10\"]],[\"invoke\",473,0,\"load\",[\"i32:8\"]],[\"invoke\",474,0,\"load\",[\"i32:1000000\"]],[\"module\",476,93],[\"invoke\",482,0,\"load\",[\"i32:0\"]],[\"invoke\",483,0,\"load\",[\"i32:10\"]],[\"invoke\",484,0,\"load\",[\"i32:8\"]],[\"invoke\",485,0,\"load\",[\"i32:1000000\"]],[\"module\",500,94],[\"module\",501,95],[\"module\",502,96],[\"module\",503,97],[\"module\",504,98],[\"module\",505,99],[\"module\",506,100],[\"module\",507,101],[\"module\",508,102],[\"instantiate\",511,103],[\"instantiate\",515,104],[\"instantiate\",520,105],[\"instantiate\",524,106],[\"instantiate\",528,107],[\"instantiate\",532,108],[\"instantiate\",537,109],[\"instantiate\",541,110],[\"instantiate\",545,111],[\"instantiate\",549,112],[\"instantiate\",553,113],[\"instantiate\",557,114],[\"instantiate\",562,107],[\"instantiate\",566,108],[\"module\",570,115],[\"invoke\",574,0,\"grow\",[\"i32:0\"]],[\"invoke\",575,0,\"grow\",[\"i32:1\"]],[\"invoke\",576,0,\"grow\",[\"i32:0\"]],[\"invoke\",577,0,\"grow\",[\"i32:1\"]],[\"invoke\",578,0,\"grow\",[\"i32:0\"]],[\"module\",654,116],[\"register\",\"not wasm\"],[\"instantiate\",657,117],[\"file\",\"table.wast\"],[\"module\",3,118],[\"module\",4,119],[\"module\",5,120],[\"module\",6,121],[\"module\",7,122],[\"module\",8,123],[\"module\",9,124],[\"module\",11,125],[\"module\",12,126],[\"file\",\"names.wast\"],[\"module\",4,127],[\"invoke\",8,0,\"foo\",[]],[\"module\",12,128],[\"module\",19,129],[\"invoke\",615,0,\"\",[]],[\"invoke\",616,0,\"0\",[]],[\"invoke\",617,0,\"-0\",[]],[\"invoke\",618,0,\"_\",[]],[\"invoke\",620,0,\"@\",[]],[\"invoke\",621,0,\"~!@#$%^&*()_+`-={}|[]\\\\:\\\";'<>?,./ \",[]],[\"invoke\",622,0,\"NaN\",[]],[\"invoke\",623,0,\"Infinity\",[]],[\"invoke\",624,0,\"if\",[]],[\"invoke\",626,0,\"_malloc\",[]],[\"invoke\",627,0,\"__malloc\",[]],[\"invoke\",628,0,\"a\",[]],[\"invoke\",629,0,\"A\",[]],[\"invoke\",630,0,\"\",[]],[\"invoke\",632,0,\"Å\",[]],[\"invoke\",633,0,\"Å\",[]],[\"invoke\",634,0,\"ffi\",[]],[\"invoke\",635,0,\"ffi\",[]],[\"invoke\",636,0,\"ffi\",[]],[\"invoke\",638,0,\"\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\",[]],[\"invoke\",639,0,\" \",[]],[\"invoke\",640,0,\"€‚ƒ„…†‡ˆ‰Š‹ŒŽ\",[]],[\"invoke\",641,0,\"‘’“”•–—˜™š›œžŸ\",[]],[\"invoke\",642,0,\"￰￱￲￳￴￵￶￷\",[]],[\"invoke\",644,0,\"␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏\",[]],[\"invoke\",645,0,\"␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟\",[]],[\"invoke\",646,0,\"␠␡\",[]],[\"invoke\",647,0,\"￰￱￲￳￴￵￶￷￸�\",[]],[\"invoke\",648,0,\"‍\",[]],[\"invoke\",650,0,\"͏\",[]],[\"invoke\",651,0,\"⁠\",[]],[\"invoke\",652,0,\"⵿\",[]],[\"invoke\",653,0,\"𑁿\",[]],[\"invoke\",654,0,\"᠎\",[]],[\"invoke\",656,0,\"‎‏‑

‪‫‬ ⁦⁧⁨⁩\",[]],[\"invoke\",657,0,\"\",[]],[\"invoke\",658,0,\"⁡⁢⁣⁤\",[]],[\"invoke\",659,0,\"𐀀󟿿􏿿\",[]],[\"invoke\",660,0,\"Z̴͇̫̥̪͓͈͔͎̗̞̺̯̱̞̙̱̜̖̠̏͆̆͛͌͘͞ḁ̶̰̳̭͙̲̱̹̝͎̼͗ͨ̎̄̆͗̿̀́͟͡l̶̷͉̩̹̫̝͖̙̲̼͇͚͍̮͎̥̞̈́͊͗ͦ̈́ͫ̇́̚ͅͅg̶͕͔͚̩̓̐̅ͮ̔̐̎̂̏̾͊̍͋͊ͧ́̆ͦ͞o̡͋̔͐ͪͩ͏̢̧̫̙̤̮͖͙͓̺̜̩̼̘̠́\",[]],[\"invoke\",662,0,\"︀\",[]],[\"invoke\",663,0,\"︄\",[]],[\"invoke\",664,0,\"󠄀\",[]],[\"invoke\",665,0,\"󠇯\",[]],[\"invoke\",667,0,\"\\n\",[]],[\"invoke\",668,0,\"␤\",[]],[\"invoke\",669,0,\"
\",[]],[\"invoke\",670,0,\"\\r\",[]],[\"invoke\",671,0,\"\\r\\n\",[]],[\"invoke\",673,0,\"\\u001e\",[]],[\"invoke\",674,0,\"\\u000b\",[]],[\"invoke\",675,0,\"\\f\",[]],[\"invoke\",676,0,\"…\",[]],[\"invoke\",677,0,\"
\",[]],[\"invoke\",679,0,\"⏎\",[]],[\"invoke\",680,0,\"‹\",[]],[\"invoke\",681,0,\"Œ\",[]],[\"invoke\",682,0,\"\",[]],[\"invoke\",683,0,\"↵\",[]],[\"invoke\",685,0,\"⌤\",[]],[\"invoke\",686,0,\"⤶\",[]],[\"invoke\",687,0,\"↲\",[]],[\"invoke\",688,0,\"⮨\",[]],[\"invoke\",689,0,\"⮰\",[]],[\"invoke\",691,0,\"﷐\",[]],[\"invoke\",692,0,\"﷑\",[]],[\"invoke\",693,0,\"﷒\",[]],[\"invoke\",694,0,\"﷓\",[]],[\"invoke\",695,0,\"﷔\",[]],[\"invoke\",697,0,\"﷖\",[]],[\"invoke\",698,0,\"﷗\",[]],[\"invoke\",699,0,\"﷘\",[]],[\"invoke\",700,0,\"﷙\",[]],[\"invoke\",701,0,\"﷚\",[]],[\"invoke\",703,0,\"﷜\",[]],[\"invoke\",704,0,\"﷝\",[]],[\"invoke\",705,0,\"﷞\",[]],[\"invoke\",706,0,\"﷟\",[]],[\"invoke\",707,0,\"﷠\",[]],[\"invoke\",709,0,\"﷢\",[]],[\"invoke\",710,0,\"﷣\",[]],[\"invoke\",711,0,\"﷤\",[]],[\"invoke\",712,0,\"﷥\",[]],[\"invoke\",714,0,\"﷧\",[]],[\"invoke\",715,0,\"﷨\",[]],[\"invoke\",716,0,\"﷩\",[]],[\"invoke\",717,0,\"﷪\",[]],[\"invoke\",718,0,\"﷫\",[]],[\"invoke\",720,0,\"﷭\",[]],[\"invoke\",721,0,\"﷮\",[]],[\"invoke\",722,0,\"﷯\",[]],[\"invoke\",723,0,\"￾\",[]],[\"invoke\",724,0,\"￿\",[]],[\"invoke\",726,0,\"🿿\",[]],[\"invoke\",727,0,\"𯿾\",[]],[\"invoke\",728,0,\"𯿿\",[]],[\"invoke\",729,0,\"𿿾\",[]],[\"invoke\",730,0,\"𿿿\",[]],[\"invoke\",732,0,\"񏿿\",[]],[\"invoke\",733,0,\"񟿾\",[]],[\"invoke\",734,0,\"񟿿\",[]],[\"invoke\",735,0,\"񯿾\",[]],[\"invoke\",736,0,\"񯿿\",[]],[\"invoke\",738,0,\"񿿿\",[]],[\"invoke\",739,0,\"򏿾\",[]],[\"invoke\",740,0,\"򏿿\",[]],[\"invoke\",741,0,\"򟿾\",[]],[\"invoke\",742,0,\"򟿿\",[]],[\"invoke\",744,0,\"򯿿\",[]],[\"invoke\",745,0,\"򿿾\",[]],[\"invoke\",746,0,\"򿿿\",[]],[\"invoke\",747,0,\"󏿾\",[]],[\"invoke\",748,0,\"󏿿\",[]],[\"invoke\",750,0,\"󟿿\",[]],[\"invoke\",751,0,\"󯿾\",[]],[\"invoke\",752,0,\"󯿿\",[]],[\"invoke\",753,0,\"󿿾\",[]],[\"invoke\",754,0,\"󿿿\",[]],[\"invoke\",756,0,\"􏿿\",[]],[\"invoke\",757,0,\"̈‽̈̉\",[]],[\"invoke\",758,0,\"abc\",[]],[\"invoke\",759,0,\"‭abc\",[]],[\"invoke\",761,0,\"‭abc‮\",[]],[\"invoke\",762,0,\"‮cba‭\",[]],[\"invoke\",763,0,\"𝑨\",[]],[\"invoke\",764,0,\"𝐴\",[]],[\"invoke\",765,0,\"𝘈\",[]],[\"invoke\",767,0,\"𝐀\",[]],[\"invoke\",768,0,\"𝓐\",[]],[\"invoke\",769,0,\"𝕬\",[]],[\"invoke\",770,0,\"𝗔\",[]],[\"invoke\",771,0,\"𝒜\",[]],[\"invoke\",773,0,\"𝔸\",[]],[\"invoke\",774,0,\"𝖠\",[]],[\"invoke\",775,0,\"𝙰\",[]],[\"invoke\",776,0,\"ᴀ\",[]],[\"invoke\",777,0,\"ᴬ\",[]],[\"invoke\",779,0,\"A\",[]],[\"invoke\",780,0,\"🄐\",[]],[\"invoke\",781,0,\"🄰\",[]],[\"invoke\",782,0,\"󠁁\",[]],[\"invoke\",783,0,\"U+0041\",[]],[\"invoke\",785,0,\"А\",[]],[\"invoke\",786,0,\"Ꙗ\",[]],[\"invoke\",787,0,\"ⷼ\",[]],[\"invoke\",788,0,\"ⷶ\",[]],[\"invoke\",789,0,\"Ɐ\",[]],[\"invoke\",791,0,\"🅰\",[]],[\"invoke\",792,0,\"Ⱝ\",[]],[\"invoke\",793,0,\"𐐂\",[]],[\"invoke\",794,0,\"𐐈\",[]],[\"invoke\",795,0,\"𐒰\",[]],[\"invoke\",797,0,\"Á\",[]],[\"invoke\",798,0,\"Â\",[]],[\"invoke\",799,0,\"Ã\",[]],[\"invoke\",800,0,\"Ä\",[]],[\"invoke\",801,0,\"Ā\",[]],[\"invoke\",803,0,\"Ą\",[]],[\"invoke\",804,0,\"Ǎ\",[]],[\"invoke\",805,0,\"Ǟ\",[]],[\"invoke\",806,0,\"Ǡ\",[]],[\"invoke\",808,0,\"Ȁ\",[]],[\"invoke\",809,0,\"Ȃ\",[]],[\"invoke\",810,0,\"Ȧ\",[]],[\"invoke\",811,0,\"Ⱥ\",[]],[\"invoke\",812,0,\"Ӑ\",[]],[\"invoke\",814,0,\"ߊ\",[]],[\"invoke\",815,0,\"ࠡ\",[]],[\"invoke\",816,0,\"ࠢ\",[]],[\"invoke\",817,0,\"ࠣ\",[]],[\"invoke\",818,0,\"ࠤ\",[]],[\"invoke\",820,0,\"ऄ\",[]],[\"invoke\",821,0,\"अ\",[]],[\"invoke\",822,0,\"ॲ\",[]],[\"invoke\",823,0,\"অ\",[]],[\"invoke\",824,0,\"ਅ\",[]],[\"invoke\",826,0,\"ଅ\",[]],[\"invoke\",827,0,\"அ\",[]],[\"invoke\",828,0,\"అ\",[]],[\"invoke\",829,0,\"ಅ\",[]],[\"invoke\",830,0,\"അ\",[]],[\"invoke\",832,0,\"ະ\",[]],[\"invoke\",833,0,\"༁\",[]],[\"invoke\",834,0,\"ཨ\",[]],[\"invoke\",835,0,\"ྸ\",[]],[\"invoke\",836,0,\"အ\",[]],[\"invoke\",838,0,\"ႜ\",[]],[\"invoke\",839,0,\"ᅡ\",[]],[\"invoke\",840,0,\"አ\",[]],[\"invoke\",841,0,\"ዐ\",[]],[\"invoke\",842,0,\"Ꭰ\",[]],[\"invoke\",844,0,\"ᖳ\",[]],[\"invoke\",845,0,\"ᚨ\",[]],[\"invoke\",846,0,\"ᚪ\",[]],[\"invoke\",847,0,\"ᛆ\",[]],[\"invoke\",848,0,\"ᜀ\",[]],[\"invoke\",850,0,\"ᝀ\",[]],[\"invoke\",851,0,\"ᝠ\",[]],[\"invoke\",852,0,\"ᠠ\",[]],[\"invoke\",853,0,\"ᢇ\",[]],[\"invoke\",855,0,\"ᥣ\",[]],[\"invoke\",856,0,\"ᨕ\",[]],[\"invoke\",857,0,\"ᩋ\",[]],[\"invoke\",858,0,\"ᩡ\",[]],[\"invoke\",859,0,\"ᮃ\",[]],[\"invoke\",861,0,\"ᯁ\",[]],[\"invoke\",862,0,\"ᰣ\",[]],[\"invoke\",863,0,\"Ḁ\",[]],[\"invoke\",864,0,\"Ạ\",[]],[\"invoke\",865,0,\"Ả\",[]],[\"invoke\",867,0,\"Ầ\",[]],[\"invoke\",868,0,\"Ẩ\",[]],[\"invoke\",869,0,\"Ẫ\",[]],[\"invoke\",870,0,\"Ậ\",[]],[\"invoke\",871,0,\"Ắ\",[]],[\"invoke\",873,0,\"Ẳ\",[]],[\"invoke\",874,0,\"Ẵ\",[]],[\"invoke\",875,0,\"Ặ\",[]],[\"invoke\",876,0,\"あ\",[]],[\"invoke\",877,0,\"ア\",[]],[\"invoke\",879,0,\"ㅏ\",[]],[\"invoke\",880,0,\"㈎\",[]],[\"invoke\",881,0,\"㈏\",[]],[\"invoke\",882,0,\"㈐\",[]],[\"invoke\",883,0,\"㈑\",[]],[\"invoke\",885,0,\"㈓\",[]],[\"invoke\",886,0,\"㈔\",[]],[\"invoke\",887,0,\"㈕\",[]],[\"invoke\",888,0,\"㈖\",[]],[\"invoke\",889,0,\"㈗\",[]],[\"invoke\",891,0,\"㈙\",[]],[\"invoke\",892,0,\"㈚\",[]],[\"invoke\",893,0,\"㈛\",[]],[\"invoke\",894,0,\"㉮\",[]],[\"invoke\",895,0,\"㉯\",[]],[\"invoke\",897,0,\"㉱\",[]],[\"invoke\",898,0,\"㉲\",[]],[\"invoke\",899,0,\"㉳\",[]],[\"invoke\",900,0,\"㉴\",[]],[\"invoke\",901,0,\"㉵\",[]],[\"invoke\",903,0,\"㉷\",[]],[\"invoke\",904,0,\"㉸\",[]],[\"invoke\",905,0,\"㉹\",[]],[\"invoke\",906,0,\"㉺\",[]],[\"invoke\",908,0,\"㋐\",[]],[\"invoke\",909,0,\"ꀊ\",[]],[\"invoke\",910,0,\"ꓮ\",[]],[\"invoke\",911,0,\"ꕉ\",[]],[\"invoke\",912,0,\"ꚠ\",[]],[\"invoke\",914,0,\"ꠣ\",[]],[\"invoke\",915,0,\"ꡝ\",[]],[\"invoke\",916,0,\"ꢂ\",[]],[\"invoke\",917,0,\"꣪\",[]],[\"invoke\",918,0,\"ꤢ\",[]],[\"invoke\",920,0,\"ꦄ\",[]],[\"invoke\",921,0,\"ꨀ\",[]],[\"invoke\",922,0,\"ア\",[]],[\"invoke\",923,0,\"ᅡ\",[]],[\"invoke\",924,0,\"𐀀\",[]],[\"invoke\",926,0,\"𐊠\",[]],[\"invoke\",927,0,\"𐌀\",[]],[\"invoke\",928,0,\"𐎠\",[]],[\"invoke\",929,0,\"𐒖\",[]],[\"invoke\",930,0,\"𐔀\",[]],[\"invoke\",932,0,\"𐠀\",[]],[\"invoke\",933,0,\"𐤠\",[]],[\"invoke\",934,0,\"𐦀\",[]],[\"invoke\",935,0,\"𐦠\",[]],[\"invoke\",936,0,\"𐨀\",[]],[\"invoke\",938,0,\"𐰀\",[]],[\"invoke\",939,0,\"𐰁\",[]],[\"invoke\",940,0,\"𐲀\",[]],[\"invoke\",941,0,\"𑀅\",[]],[\"invoke\",942,0,\"𑂃\",[]],[\"invoke\",944,0,\"𑅐\",[]],[\"invoke\",945,0,\"𑆃\",[]],[\"invoke\",946,0,\"𑈀\",[]],[\"invoke\",947,0,\"𑊀\",[]],[\"invoke\",948,0,\"𑊰\",[]],[\"invoke\",950,0,\"𑍰\",[]],[\"invoke\",951,0,\"𑐀\",[]],[\"invoke\",952,0,\"𑒁\",[]],[\"invoke\",953,0,\"𑖀\",[]],[\"invoke\",955,0,\"𑚀\",[]],[\"invoke\",956,0,\"𑜒\",[]],[\"invoke\",957,0,\"𑜠\",[]],[\"invoke\",958,0,\"𑢡\",[]],[\"invoke\",959,0,\"𑫕\",[]],[\"invoke\",961,0,\"𑲏\",[]],[\"invoke\",962,0,\"𑲯\",[]],[\"invoke\",963,0,\"𒀀\",[]],[\"invoke\",964,0,\"𖧕\",[]],[\"invoke\",965,0,\"𖩆\",[]],[\"invoke\",967,0,\"𖽔\",[]],[\"invoke\",968,0,\"𛱁\",[]],[\"invoke\",969,0,\"𛱤\",[]],[\"invoke\",970,0,\"𞠣\",[]],[\"invoke\",971,0,\"🇦\",[]],[\"invoke\",973,0,\"Λ\",[]],[\"invoke\",974,0,\"Ɒ\",[]],[\"invoke\",975,0,\"ª\",[]],[\"invoke\",976,0,\"∀\",[]],[\"invoke\",977,0,\"₳\",[]],[\"invoke\",979,0,\"Ⲁ\",[]],[\"invoke\",980,0,\"𐌰\",[]],[\"invoke\",981,0,\"Ά\",[]],[\"invoke\",982,0,\"Α\",[]],[\"invoke\",983,0,\"Ἀ\",[]],[\"invoke\",985,0,\"Ἂ\",[]],[\"invoke\",986,0,\"Ἃ\",[]],[\"invoke\",987,0,\"Ἄ\",[]],[\"invoke\",988,0,\"Ἅ\",[]],[\"invoke\",989,0,\"Ἆ\",[]],[\"invoke\",991,0,\"ᾈ\",[]],[\"invoke\",992,0,\"ᾉ\",[]],[\"invoke\",993,0,\"ᾊ\",[]],[\"invoke\",994,0,\"ᾋ\",[]],[\"invoke\",995,0,\"ᾌ\",[]],[\"invoke\",997,0,\"ᾎ\",[]],[\"invoke\",998,0,\"ᾏ\",[]],[\"invoke\",999,0,\"Ᾰ\",[]],[\"invoke\",1000,0,\"Ᾱ\",[]],[\"invoke\",1002,0,\"Ά\",[]],[\"invoke\",1003,0,\"ᾼ\",[]],[\"invoke\",1004,0,\"𝚨\",[]],[\"invoke\",1005,0,\"𝛢\",[]],[\"invoke\",1006,0,\"𝜜\",[]],[\"invoke\",1008,0,\"𝞐\",[]],[\"invoke\",1009,0,\"⍶\",[]],[\"invoke\",1010,0,\"⍺\",[]],[\"invoke\",1011,0,\"⩜\",[]],[\"invoke\",1012,0,\"ᗅ\",[]],[\"invoke\",1014,0,\")˺˼𔗏𝅴𝅶𝅸𝅺⁾₎❩❫⟯﴿︶﹚)⦆󠀩❳❵⟧⟩⟫⟭⦈⦊⦖⸣⸥︘︸︺︼︾﹀﹂﹄﹈﹜﹞]}」󠁝󠁽»’”›❯\",[]],[\"invoke\",1015,0,\"(˹˻𔗎𝅳𝅵𝅷𝅹⁽₍❨❪⟮﴾︵﹙(⦅󠀨❲❴⟦⟨⟪⟬⦇⦉⦕⸢⸤︗︷︹︻︽︿﹁﹃﹇﹛﹝[{「󠁛󠁻«‘“‹❮\",[]],[\"invoke\",1016,0,\"𝪋𝪤\",[]],[\"invoke\",1017,0,\"𝪋\",[]],[\"invoke\",1018,0,\"½\",[]],[\"invoke\",1020,0,\"1/2\",[]],[\"invoke\",1021,0,\"୳\",[]],[\"invoke\",1022,0,\"൴\",[]],[\"invoke\",1023,0,\"⳽\",[]],[\"invoke\",1024,0,\"꠱\",[]],[\"invoke\",1026,0,\"𐅵\",[]],[\"invoke\",1027,0,\"𐅶\",[]],[\"invoke\",1028,0,\"𐦽\",[]],[\"invoke\",1029,0,\"𐹻\",[]],[\"invoke\",1030,0,\""\",[]],[\"invoke\",1032,0,\"\\b\",[]],[\"invoke\",1033,0,\"⌫\",[]],[\"invoke\",1034,0,\"⌦\",[]],[\"invoke\",1035,0,\"␈\",[]],[\"invoke\",1036,0,\"␡\",[]],[\"invoke\",1038,0,\"\\u000f\",[]],[\"invoke\",1039,0,\"←\",[]],[\"invoke\",1040,0,\"⌧\",[]],[\"invoke\",1041,0,\"⍒\",[]],[\"invoke\",1042,0,\"⍔\",[]],[\"invoke\",1044,0,\"⍫\",[]],[\"invoke\",1045,0,\"\\u001a\",[]],[\"invoke\",1046,0,\"␦\",[]],[\"invoke\",1047,0,\"␚\",[]],[\"invoke\",1049,0,\"?\",[]],[\"invoke\",1050,0,\"¿\",[]],[\"invoke\",1051,0,\"᥅\",[]],[\"invoke\",1052,0,\";\",[]],[\"invoke\",1053,0,\"՞\",[]],[\"invoke\",1055,0,\"፧\",[]],[\"invoke\",1056,0,\"⁇\",[]],[\"invoke\",1057,0,\"⍰\",[]],[\"invoke\",1058,0,\"❓\",[]],[\"invoke\",1059,0,\"❔\",[]],[\"invoke\",1061,0,\"⳻\",[]],[\"invoke\",1062,0,\"⸮\",[]],[\"invoke\",1063,0,\"㉄\",[]],[\"invoke\",1064,0,\"꘏\",[]],[\"invoke\",1065,0,\"꛷\",[]],[\"invoke\",1067,0,\"﹖\",[]],[\"invoke\",1068,0,\"?\",[]],[\"invoke\",1069,0,\"𑅃\",[]],[\"invoke\",1070,0,\"𞥟\",[]],[\"invoke\",1071,0,\"󠀿\",[]],[\"invoke\",1073,0,\"⯑\",[]],[\"invoke\",1074,0,\"¶\",[]],[\"invoke\",1075,0,\"⁋\",[]],[\"invoke\",1076,0,\"܀\",[]],[\"invoke\",1077,0,\"჻\",[]],[\"invoke\",1079,0,\"〷\",[]],[\"invoke\",1080,0,\"❡\",[]],[\"invoke\",1081,0,\"⸏\",[]],[\"invoke\",1082,0,\"⸐\",[]],[\"invoke\",1083,0,\"⸑\",[]],[\"invoke\",1085,0,\"\\u0014\",[]],[\"invoke\",1086,0,\"☙\",[]],[\"invoke\",1087,0,\"⸿\",[]],[\"invoke\",1088,0,\"〇\",[]],[\"invoke\",1089,0,\"๛\",[]],[\"invoke\",1091,0,\"ϓ\",[]],[\"invoke\",1092,0,\"ϔ\",[]],[\"invoke\",1093,0,\"ẛ\",[]],[\"module\",1095,130],[\"invoke\",1107,0,\"print32\",[\"i32:42\",\"i32:123\"]]]"; +export const script = "[[\"file\",\"imports.wast\"],[\"module\",3,0],[\"register\",\"test\"],[\"module\",26,1],[\"invoke\",85,0,\"print32\",[\"i32:13\"]],[\"invoke\",86,0,\"print64\",[\"i64:24\"]],[\"module\",97,2],[\"invoke\",104,0,\"print_i32\",[\"i32:13\"]],[\"module\",107,3],[\"invoke\",114,0,\"print_i32\",[\"i32:5\",\"i32:11\"]],[\"module\",116,4],[\"module\",117,5],[\"module\",118,6],[\"module\",119,7],[\"module\",120,8],[\"module\",121,9],[\"module\",122,10],[\"instantiate\",125,11],[\"instantiate\",129,12],[\"instantiate\",134,13],[\"instantiate\",138,14],[\"instantiate\",142,15],[\"instantiate\",146,16],[\"instantiate\",150,17],[\"instantiate\",154,18],[\"instantiate\",158,19],[\"instantiate\",162,20],[\"instantiate\",166,21],[\"instantiate\",170,22],[\"instantiate\",174,23],[\"instantiate\",178,24],[\"instantiate\",182,25],[\"instantiate\",186,26],[\"instantiate\",190,27],[\"instantiate\",194,28],[\"instantiate\",199,29],[\"instantiate\",203,30],[\"instantiate\",207,31],[\"instantiate\",211,32],[\"instantiate\",215,33],[\"instantiate\",219,34],[\"module\",226,35],[\"invoke\",246,0,\"get-0\",[]],[\"invoke\",247,0,\"get-1\",[]],[\"invoke\",248,0,\"get-x\",[]],[\"invoke\",249,0,\"get-y\",[]],[\"invoke\",250,0,\"get-4\",[]],[\"invoke\",251,0,\"get-5\",[]],[\"invoke\",252,0,\"get-6\",[]],[\"module\",254,36],[\"module\",255,37],[\"module\",256,38],[\"instantiate\",259,39],[\"instantiate\",263,40],[\"instantiate\",268,41],[\"instantiate\",272,42],[\"instantiate\",276,43],[\"instantiate\",280,44],[\"instantiate\",284,45],[\"instantiate\",288,46],[\"instantiate\",292,47],[\"instantiate\",296,48],[\"instantiate\",300,49],[\"instantiate\",304,50],[\"instantiate\",308,51],[\"instantiate\",312,52],[\"instantiate\",317,53],[\"instantiate\",321,54],[\"instantiate\",325,55],[\"instantiate\",329,56],[\"instantiate\",333,57],[\"instantiate\",337,58],[\"module\",344,59],[\"invoke\",356,0,\"call\",[\"i32:0\"]],[\"invoke\",357,0,\"call\",[\"i32:1\"]],[\"invoke\",358,0,\"call\",[\"i32:2\"]],[\"invoke\",359,0,\"call\",[\"i32:3\"]],[\"invoke\",360,0,\"call\",[\"i32:100\"]],[\"module\",363,59],[\"invoke\",375,0,\"call\",[\"i32:0\"]],[\"invoke\",376,0,\"call\",[\"i32:1\"]],[\"invoke\",377,0,\"call\",[\"i32:2\"]],[\"invoke\",378,0,\"call\",[\"i32:3\"]],[\"invoke\",379,0,\"call\",[\"i32:100\"]],[\"module\",381,60],[\"module\",388,61],[\"module\",389,62],[\"module\",390,63],[\"module\",391,64],[\"module\",392,65],[\"module\",393,66],[\"module\",394,67],[\"module\",395,68],[\"module\",396,69],[\"module\",397,70],[\"module\",398,71],[\"module\",399,72],[\"module\",400,73],[\"module\",401,74],[\"module\",402,75],[\"module\",403,76],[\"module\",404,77],[\"module\",405,78],[\"module\",406,79],[\"module\",407,80],[\"instantiate\",410,81],[\"instantiate\",414,82],[\"instantiate\",419,83],[\"instantiate\",423,84],[\"instantiate\",427,85],[\"instantiate\",431,86],[\"instantiate\",435,87],[\"instantiate\",439,88],[\"instantiate\",444,89],[\"instantiate\",448,90],[\"instantiate\",452,91],[\"instantiate\",456,92],[\"module\",464,93],[\"invoke\",471,0,\"load\",[\"i32:0\"]],[\"invoke\",472,0,\"load\",[\"i32:10\"]],[\"invoke\",473,0,\"load\",[\"i32:8\"]],[\"invoke\",474,0,\"load\",[\"i32:1000000\"]],[\"module\",476,93],[\"invoke\",482,0,\"load\",[\"i32:0\"]],[\"invoke\",483,0,\"load\",[\"i32:10\"]],[\"invoke\",484,0,\"load\",[\"i32:8\"]],[\"invoke\",485,0,\"load\",[\"i32:1000000\"]],[\"module\",500,94],[\"module\",501,95],[\"module\",502,96],[\"module\",503,97],[\"module\",504,98],[\"module\",505,99],[\"module\",506,100],[\"module\",507,101],[\"module\",508,102],[\"instantiate\",511,103],[\"instantiate\",515,104],[\"instantiate\",520,105],[\"instantiate\",524,106],[\"instantiate\",528,107],[\"instantiate\",532,108],[\"instantiate\",537,109],[\"instantiate\",541,110],[\"instantiate\",545,111],[\"instantiate\",549,112],[\"instantiate\",553,113],[\"instantiate\",557,114],[\"instantiate\",562,107],[\"instantiate\",566,108],[\"module\",570,115],[\"invoke\",574,0,\"grow\",[\"i32:0\"]],[\"invoke\",575,0,\"grow\",[\"i32:1\"]],[\"invoke\",576,0,\"grow\",[\"i32:0\"]],[\"invoke\",577,0,\"grow\",[\"i32:1\"]],[\"invoke\",578,0,\"grow\",[\"i32:0\"]],[\"module\",654,116],[\"register\",\"not wasm\"],[\"instantiate\",657,117],[\"file\",\"table.wast\"],[\"module\",3,118],[\"module\",4,119],[\"module\",5,120],[\"module\",6,121],[\"module\",7,122],[\"module\",8,123],[\"module\",9,124],[\"module\",11,125],[\"module\",12,126],[\"file\",\"names.wast\"],[\"module\",4,127],[\"invoke\",8,0,\"foo\",[]],[\"module\",12,128],[\"module\",19,129],[\"invoke\",615,0,\"\",[]],[\"invoke\",616,0,\"0\",[]],[\"invoke\",617,0,\"-0\",[]],[\"invoke\",618,0,\"_\",[]],[\"invoke\",620,0,\"@\",[]],[\"invoke\",621,0,\"~!@#$%^&*()_+`-={}|[]\\\\:\\\";'<>?,./ \",[]],[\"invoke\",622,0,\"NaN\",[]],[\"invoke\",623,0,\"Infinity\",[]],[\"invoke\",624,0,\"if\",[]],[\"invoke\",626,0,\"_malloc\",[]],[\"invoke\",627,0,\"__malloc\",[]],[\"invoke\",628,0,\"a\",[]],[\"invoke\",629,0,\"A\",[]],[\"invoke\",630,0,\"\u{feff}\",[]],[\"invoke\",632,0,\"Å\",[]],[\"invoke\",633,0,\"Å\",[]],[\"invoke\",634,0,\"ffi\",[]],[\"invoke\",635,0,\"ffi\",[]],[\"invoke\",636,0,\"ffi\",[]],[\"invoke\",638,0,\"\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\",[]],[\"invoke\",639,0,\" \u{7f}\",[]],[\"invoke\",640,0,\"\u{80}\u{81}\u{82}\u{83}\u{84}\u{85}\u{86}\u{87}\u{88}\u{89}\u{8a}\u{8b}\u{8c}\u{8d}\u{8e}\u{8f}\",[]],[\"invoke\",641,0,\"\u{90}\u{91}\u{92}\u{93}\u{94}\u{95}\u{96}\u{97}\u{98}\u{99}\u{9a}\u{9b}\u{9c}\u{9d}\u{9e}\u{9f}\",[]],[\"invoke\",642,0,\"￰￱￲￳￴￵￶￷\",[]],[\"invoke\",644,0,\"␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏\",[]],[\"invoke\",645,0,\"␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟\",[]],[\"invoke\",646,0,\"␠␡\",[]],[\"invoke\",647,0,\"￰￱￲￳￴￵￶￷￸\u{fff9}\u{fffa}\u{fffb}�\",[]],[\"invoke\",648,0,\"\u{200d}\",[]],[\"invoke\",650,0,\"͏\",[]],[\"invoke\",651,0,\"\u{2060}\",[]],[\"invoke\",652,0,\"⵿\",[]],[\"invoke\",653,0,\"𑁿\",[]],[\"invoke\",654,0,\"\u{180e}\",[]],[\"invoke\",656,0,\"\u{200e}\u{200f}‑\u{2028}\u{2029}\u{202a}\u{202b}\u{202c} \u{2066}\u{2067}\u{2068}\u{2069}\",[]],[\"invoke\",657,0,\"\u{206a}\u{206b}\u{206c}\u{206d}\u{206e}\u{206f}\",[]],[\"invoke\",658,0,\"\u{2061}\u{2062}\u{2063}\u{2064}\",[]],[\"invoke\",659,0,\"𐀀󟿿􏿿\",[]],[\"invoke\",660,0,\"Z̴͇̫̥̪͓͈͔͎̗̞̺̯̱̞̙̱̜̖̠̏͆̆͛͌͘͞ḁ̶̰̳̭͙̲̱̹̝͎̼͗ͨ̎̄̆͗̿̀́͟͡l̶̷͉̩̹̫̝͖̙̲̼͇͚͍̮͎̥̞̈́͊͗ͦ̈́ͫ̇́̚ͅͅg̶͕͔͚̩̓̐̅ͮ̔̐̎̂̏̾͊̍͋͊ͧ́̆ͦ͞o̡͋̔͐ͪͩ͏̢̧̫̙̤̮͖͙͓̺̜̩̼̘̠́\",[]],[\"invoke\",662,0,\"︀\",[]],[\"invoke\",663,0,\"︄\",[]],[\"invoke\",664,0,\"󠄀\",[]],[\"invoke\",665,0,\"󠇯\",[]],[\"invoke\",667,0,\"\\n\",[]],[\"invoke\",668,0,\"␤\",[]],[\"invoke\",669,0,\"\u{2028}\",[]],[\"invoke\",670,0,\"\\r\",[]],[\"invoke\",671,0,\"\\r\\n\",[]],[\"invoke\",673,0,\"\\u001e\",[]],[\"invoke\",674,0,\"\\u000b\",[]],[\"invoke\",675,0,\"\\f\",[]],[\"invoke\",676,0,\"\u{85}\",[]],[\"invoke\",677,0,\"\u{2029}\",[]],[\"invoke\",679,0,\"⏎\",[]],[\"invoke\",680,0,\"\u{8b}\",[]],[\"invoke\",681,0,\"\u{8c}\",[]],[\"invoke\",682,0,\"\u{8d}\",[]],[\"invoke\",683,0,\"↵\",[]],[\"invoke\",685,0,\"⌤\",[]],[\"invoke\",686,0,\"⤶\",[]],[\"invoke\",687,0,\"↲\",[]],[\"invoke\",688,0,\"⮨\",[]],[\"invoke\",689,0,\"⮰\",[]],[\"invoke\",691,0,\"﷐\",[]],[\"invoke\",692,0,\"﷑\",[]],[\"invoke\",693,0,\"﷒\",[]],[\"invoke\",694,0,\"﷓\",[]],[\"invoke\",695,0,\"﷔\",[]],[\"invoke\",697,0,\"﷖\",[]],[\"invoke\",698,0,\"﷗\",[]],[\"invoke\",699,0,\"﷘\",[]],[\"invoke\",700,0,\"﷙\",[]],[\"invoke\",701,0,\"﷚\",[]],[\"invoke\",703,0,\"﷜\",[]],[\"invoke\",704,0,\"﷝\",[]],[\"invoke\",705,0,\"﷞\",[]],[\"invoke\",706,0,\"﷟\",[]],[\"invoke\",707,0,\"﷠\",[]],[\"invoke\",709,0,\"﷢\",[]],[\"invoke\",710,0,\"﷣\",[]],[\"invoke\",711,0,\"﷤\",[]],[\"invoke\",712,0,\"﷥\",[]],[\"invoke\",714,0,\"﷧\",[]],[\"invoke\",715,0,\"﷨\",[]],[\"invoke\",716,0,\"﷩\",[]],[\"invoke\",717,0,\"﷪\",[]],[\"invoke\",718,0,\"﷫\",[]],[\"invoke\",720,0,\"﷭\",[]],[\"invoke\",721,0,\"﷮\",[]],[\"invoke\",722,0,\"﷯\",[]],[\"invoke\",723,0,\"￾\",[]],[\"invoke\",724,0,\"￿\",[]],[\"invoke\",726,0,\"🿿\",[]],[\"invoke\",727,0,\"𯿾\",[]],[\"invoke\",728,0,\"𯿿\",[]],[\"invoke\",729,0,\"𿿾\",[]],[\"invoke\",730,0,\"𿿿\",[]],[\"invoke\",732,0,\"񏿿\",[]],[\"invoke\",733,0,\"񟿾\",[]],[\"invoke\",734,0,\"񟿿\",[]],[\"invoke\",735,0,\"񯿾\",[]],[\"invoke\",736,0,\"񯿿\",[]],[\"invoke\",738,0,\"񿿿\",[]],[\"invoke\",739,0,\"򏿾\",[]],[\"invoke\",740,0,\"򏿿\",[]],[\"invoke\",741,0,\"򟿾\",[]],[\"invoke\",742,0,\"򟿿\",[]],[\"invoke\",744,0,\"򯿿\",[]],[\"invoke\",745,0,\"򿿾\",[]],[\"invoke\",746,0,\"򿿿\",[]],[\"invoke\",747,0,\"󏿾\",[]],[\"invoke\",748,0,\"󏿿\",[]],[\"invoke\",750,0,\"󟿿\",[]],[\"invoke\",751,0,\"󯿾\",[]],[\"invoke\",752,0,\"󯿿\",[]],[\"invoke\",753,0,\"󿿾\",[]],[\"invoke\",754,0,\"󿿿\",[]],[\"invoke\",756,0,\"􏿿\",[]],[\"invoke\",757,0,\"̈‽̈̉\",[]],[\"invoke\",758,0,\"abc\",[]],[\"invoke\",759,0,\"\u{202d}abc\",[]],[\"invoke\",761,0,\"\u{202d}abc\u{202e}\",[]],[\"invoke\",762,0,\"\u{202e}cba\u{202d}\",[]],[\"invoke\",763,0,\"𝑨\",[]],[\"invoke\",764,0,\"𝐴\",[]],[\"invoke\",765,0,\"𝘈\",[]],[\"invoke\",767,0,\"𝐀\",[]],[\"invoke\",768,0,\"𝓐\",[]],[\"invoke\",769,0,\"𝕬\",[]],[\"invoke\",770,0,\"𝗔\",[]],[\"invoke\",771,0,\"𝒜\",[]],[\"invoke\",773,0,\"𝔸\",[]],[\"invoke\",774,0,\"𝖠\",[]],[\"invoke\",775,0,\"𝙰\",[]],[\"invoke\",776,0,\"ᴀ\",[]],[\"invoke\",777,0,\"ᴬ\",[]],[\"invoke\",779,0,\"A\",[]],[\"invoke\",780,0,\"🄐\",[]],[\"invoke\",781,0,\"🄰\",[]],[\"invoke\",782,0,\"\u{e0041}\",[]],[\"invoke\",783,0,\"U+0041\",[]],[\"invoke\",785,0,\"А\",[]],[\"invoke\",786,0,\"Ꙗ\",[]],[\"invoke\",787,0,\"ⷼ\",[]],[\"invoke\",788,0,\"ⷶ\",[]],[\"invoke\",789,0,\"Ɐ\",[]],[\"invoke\",791,0,\"🅰\",[]],[\"invoke\",792,0,\"Ⱝ\",[]],[\"invoke\",793,0,\"𐐂\",[]],[\"invoke\",794,0,\"𐐈\",[]],[\"invoke\",795,0,\"𐒰\",[]],[\"invoke\",797,0,\"Á\",[]],[\"invoke\",798,0,\"Â\",[]],[\"invoke\",799,0,\"Ã\",[]],[\"invoke\",800,0,\"Ä\",[]],[\"invoke\",801,0,\"Ā\",[]],[\"invoke\",803,0,\"Ą\",[]],[\"invoke\",804,0,\"Ǎ\",[]],[\"invoke\",805,0,\"Ǟ\",[]],[\"invoke\",806,0,\"Ǡ\",[]],[\"invoke\",808,0,\"Ȁ\",[]],[\"invoke\",809,0,\"Ȃ\",[]],[\"invoke\",810,0,\"Ȧ\",[]],[\"invoke\",811,0,\"Ⱥ\",[]],[\"invoke\",812,0,\"Ӑ\",[]],[\"invoke\",814,0,\"ߊ\",[]],[\"invoke\",815,0,\"ࠡ\",[]],[\"invoke\",816,0,\"ࠢ\",[]],[\"invoke\",817,0,\"ࠣ\",[]],[\"invoke\",818,0,\"ࠤ\",[]],[\"invoke\",820,0,\"ऄ\",[]],[\"invoke\",821,0,\"अ\",[]],[\"invoke\",822,0,\"ॲ\",[]],[\"invoke\",823,0,\"অ\",[]],[\"invoke\",824,0,\"ਅ\",[]],[\"invoke\",826,0,\"ଅ\",[]],[\"invoke\",827,0,\"அ\",[]],[\"invoke\",828,0,\"అ\",[]],[\"invoke\",829,0,\"ಅ\",[]],[\"invoke\",830,0,\"അ\",[]],[\"invoke\",832,0,\"ະ\",[]],[\"invoke\",833,0,\"༁\",[]],[\"invoke\",834,0,\"ཨ\",[]],[\"invoke\",835,0,\"ྸ\",[]],[\"invoke\",836,0,\"အ\",[]],[\"invoke\",838,0,\"ႜ\",[]],[\"invoke\",839,0,\"ᅡ\",[]],[\"invoke\",840,0,\"አ\",[]],[\"invoke\",841,0,\"ዐ\",[]],[\"invoke\",842,0,\"Ꭰ\",[]],[\"invoke\",844,0,\"ᖳ\",[]],[\"invoke\",845,0,\"ᚨ\",[]],[\"invoke\",846,0,\"ᚪ\",[]],[\"invoke\",847,0,\"ᛆ\",[]],[\"invoke\",848,0,\"ᜀ\",[]],[\"invoke\",850,0,\"ᝀ\",[]],[\"invoke\",851,0,\"ᝠ\",[]],[\"invoke\",852,0,\"ᠠ\",[]],[\"invoke\",853,0,\"ᢇ\",[]],[\"invoke\",855,0,\"ᥣ\",[]],[\"invoke\",856,0,\"ᨕ\",[]],[\"invoke\",857,0,\"ᩋ\",[]],[\"invoke\",858,0,\"ᩡ\",[]],[\"invoke\",859,0,\"ᮃ\",[]],[\"invoke\",861,0,\"ᯁ\",[]],[\"invoke\",862,0,\"ᰣ\",[]],[\"invoke\",863,0,\"Ḁ\",[]],[\"invoke\",864,0,\"Ạ\",[]],[\"invoke\",865,0,\"Ả\",[]],[\"invoke\",867,0,\"Ầ\",[]],[\"invoke\",868,0,\"Ẩ\",[]],[\"invoke\",869,0,\"Ẫ\",[]],[\"invoke\",870,0,\"Ậ\",[]],[\"invoke\",871,0,\"Ắ\",[]],[\"invoke\",873,0,\"Ẳ\",[]],[\"invoke\",874,0,\"Ẵ\",[]],[\"invoke\",875,0,\"Ặ\",[]],[\"invoke\",876,0,\"あ\",[]],[\"invoke\",877,0,\"ア\",[]],[\"invoke\",879,0,\"ㅏ\",[]],[\"invoke\",880,0,\"㈎\",[]],[\"invoke\",881,0,\"㈏\",[]],[\"invoke\",882,0,\"㈐\",[]],[\"invoke\",883,0,\"㈑\",[]],[\"invoke\",885,0,\"㈓\",[]],[\"invoke\",886,0,\"㈔\",[]],[\"invoke\",887,0,\"㈕\",[]],[\"invoke\",888,0,\"㈖\",[]],[\"invoke\",889,0,\"㈗\",[]],[\"invoke\",891,0,\"㈙\",[]],[\"invoke\",892,0,\"㈚\",[]],[\"invoke\",893,0,\"㈛\",[]],[\"invoke\",894,0,\"㉮\",[]],[\"invoke\",895,0,\"㉯\",[]],[\"invoke\",897,0,\"㉱\",[]],[\"invoke\",898,0,\"㉲\",[]],[\"invoke\",899,0,\"㉳\",[]],[\"invoke\",900,0,\"㉴\",[]],[\"invoke\",901,0,\"㉵\",[]],[\"invoke\",903,0,\"㉷\",[]],[\"invoke\",904,0,\"㉸\",[]],[\"invoke\",905,0,\"㉹\",[]],[\"invoke\",906,0,\"㉺\",[]],[\"invoke\",908,0,\"㋐\",[]],[\"invoke\",909,0,\"ꀊ\",[]],[\"invoke\",910,0,\"ꓮ\",[]],[\"invoke\",911,0,\"ꕉ\",[]],[\"invoke\",912,0,\"ꚠ\",[]],[\"invoke\",914,0,\"ꠣ\",[]],[\"invoke\",915,0,\"ꡝ\",[]],[\"invoke\",916,0,\"ꢂ\",[]],[\"invoke\",917,0,\"꣪\",[]],[\"invoke\",918,0,\"ꤢ\",[]],[\"invoke\",920,0,\"ꦄ\",[]],[\"invoke\",921,0,\"ꨀ\",[]],[\"invoke\",922,0,\"ア\",[]],[\"invoke\",923,0,\"ᅡ\",[]],[\"invoke\",924,0,\"𐀀\",[]],[\"invoke\",926,0,\"𐊠\",[]],[\"invoke\",927,0,\"𐌀\",[]],[\"invoke\",928,0,\"𐎠\",[]],[\"invoke\",929,0,\"𐒖\",[]],[\"invoke\",930,0,\"𐔀\",[]],[\"invoke\",932,0,\"𐠀\",[]],[\"invoke\",933,0,\"𐤠\",[]],[\"invoke\",934,0,\"𐦀\",[]],[\"invoke\",935,0,\"𐦠\",[]],[\"invoke\",936,0,\"𐨀\",[]],[\"invoke\",938,0,\"𐰀\",[]],[\"invoke\",939,0,\"𐰁\",[]],[\"invoke\",940,0,\"𐲀\",[]],[\"invoke\",941,0,\"𑀅\",[]],[\"invoke\",942,0,\"𑂃\",[]],[\"invoke\",944,0,\"𑅐\",[]],[\"invoke\",945,0,\"𑆃\",[]],[\"invoke\",946,0,\"𑈀\",[]],[\"invoke\",947,0,\"𑊀\",[]],[\"invoke\",948,0,\"𑊰\",[]],[\"invoke\",950,0,\"𑍰\",[]],[\"invoke\",951,0,\"𑐀\",[]],[\"invoke\",952,0,\"𑒁\",[]],[\"invoke\",953,0,\"𑖀\",[]],[\"invoke\",955,0,\"𑚀\",[]],[\"invoke\",956,0,\"𑜒\",[]],[\"invoke\",957,0,\"𑜠\",[]],[\"invoke\",958,0,\"𑢡\",[]],[\"invoke\",959,0,\"𑫕\",[]],[\"invoke\",961,0,\"𑲏\",[]],[\"invoke\",962,0,\"𑲯\",[]],[\"invoke\",963,0,\"𒀀\",[]],[\"invoke\",964,0,\"𖧕\",[]],[\"invoke\",965,0,\"𖩆\",[]],[\"invoke\",967,0,\"𖽔\",[]],[\"invoke\",968,0,\"𛱁\",[]],[\"invoke\",969,0,\"𛱤\",[]],[\"invoke\",970,0,\"𞠣\",[]],[\"invoke\",971,0,\"🇦\",[]],[\"invoke\",973,0,\"Λ\",[]],[\"invoke\",974,0,\"Ɒ\",[]],[\"invoke\",975,0,\"ª\",[]],[\"invoke\",976,0,\"∀\",[]],[\"invoke\",977,0,\"₳\",[]],[\"invoke\",979,0,\"Ⲁ\",[]],[\"invoke\",980,0,\"𐌰\",[]],[\"invoke\",981,0,\"Ά\",[]],[\"invoke\",982,0,\"Α\",[]],[\"invoke\",983,0,\"Ἀ\",[]],[\"invoke\",985,0,\"Ἂ\",[]],[\"invoke\",986,0,\"Ἃ\",[]],[\"invoke\",987,0,\"Ἄ\",[]],[\"invoke\",988,0,\"Ἅ\",[]],[\"invoke\",989,0,\"Ἆ\",[]],[\"invoke\",991,0,\"ᾈ\",[]],[\"invoke\",992,0,\"ᾉ\",[]],[\"invoke\",993,0,\"ᾊ\",[]],[\"invoke\",994,0,\"ᾋ\",[]],[\"invoke\",995,0,\"ᾌ\",[]],[\"invoke\",997,0,\"ᾎ\",[]],[\"invoke\",998,0,\"ᾏ\",[]],[\"invoke\",999,0,\"Ᾰ\",[]],[\"invoke\",1000,0,\"Ᾱ\",[]],[\"invoke\",1002,0,\"Ά\",[]],[\"invoke\",1003,0,\"ᾼ\",[]],[\"invoke\",1004,0,\"𝚨\",[]],[\"invoke\",1005,0,\"𝛢\",[]],[\"invoke\",1006,0,\"𝜜\",[]],[\"invoke\",1008,0,\"𝞐\",[]],[\"invoke\",1009,0,\"⍶\",[]],[\"invoke\",1010,0,\"⍺\",[]],[\"invoke\",1011,0,\"⩜\",[]],[\"invoke\",1012,0,\"ᗅ\",[]],[\"invoke\",1014,0,\")˺˼𔗏\u{1d174}\u{1d176}\u{1d178}\u{1d17a}⁾₎❩❫⟯﴿︶﹚)⦆\u{e0029}❳❵⟧⟩⟫⟭⦈⦊⦖⸣⸥︘︸︺︼︾﹀﹂﹄﹈﹜﹞]}」\u{e005d}\u{e007d}»’”›❯\",[]],[\"invoke\",1015,0,\"(˹˻𔗎\u{1d173}\u{1d175}\u{1d177}\u{1d179}⁽₍❨❪⟮﴾︵﹙(⦅\u{e0028}❲❴⟦⟨⟪⟬⦇⦉⦕⸢⸤︗︷︹︻︽︿﹁﹃﹇﹛﹝[{「\u{e005b}\u{e007b}«‘“‹❮\",[]],[\"invoke\",1016,0,\"𝪋𝪤\",[]],[\"invoke\",1017,0,\"𝪋\",[]],[\"invoke\",1018,0,\"½\",[]],[\"invoke\",1020,0,\"1/2\",[]],[\"invoke\",1021,0,\"୳\",[]],[\"invoke\",1022,0,\"൴\",[]],[\"invoke\",1023,0,\"⳽\",[]],[\"invoke\",1024,0,\"꠱\",[]],[\"invoke\",1026,0,\"𐅵\",[]],[\"invoke\",1027,0,\"𐅶\",[]],[\"invoke\",1028,0,\"𐦽\",[]],[\"invoke\",1029,0,\"𐹻\",[]],[\"invoke\",1030,0,\""\",[]],[\"invoke\",1032,0,\"\\b\",[]],[\"invoke\",1033,0,\"⌫\",[]],[\"invoke\",1034,0,\"⌦\",[]],[\"invoke\",1035,0,\"␈\",[]],[\"invoke\",1036,0,\"␡\",[]],[\"invoke\",1038,0,\"\\u000f\",[]],[\"invoke\",1039,0,\"←\",[]],[\"invoke\",1040,0,\"⌧\",[]],[\"invoke\",1041,0,\"⍒\",[]],[\"invoke\",1042,0,\"⍔\",[]],[\"invoke\",1044,0,\"⍫\",[]],[\"invoke\",1045,0,\"\\u001a\",[]],[\"invoke\",1046,0,\"␦\",[]],[\"invoke\",1047,0,\"␚\",[]],[\"invoke\",1049,0,\"?\",[]],[\"invoke\",1050,0,\"¿\",[]],[\"invoke\",1051,0,\"᥅\",[]],[\"invoke\",1052,0,\";\",[]],[\"invoke\",1053,0,\"՞\",[]],[\"invoke\",1055,0,\"፧\",[]],[\"invoke\",1056,0,\"⁇\",[]],[\"invoke\",1057,0,\"⍰\",[]],[\"invoke\",1058,0,\"❓\",[]],[\"invoke\",1059,0,\"❔\",[]],[\"invoke\",1061,0,\"⳻\",[]],[\"invoke\",1062,0,\"⸮\",[]],[\"invoke\",1063,0,\"㉄\",[]],[\"invoke\",1064,0,\"꘏\",[]],[\"invoke\",1065,0,\"꛷\",[]],[\"invoke\",1067,0,\"﹖\",[]],[\"invoke\",1068,0,\"?\",[]],[\"invoke\",1069,0,\"𑅃\",[]],[\"invoke\",1070,0,\"𞥟\",[]],[\"invoke\",1071,0,\"\u{e003f}\",[]],[\"invoke\",1073,0,\"⯑\",[]],[\"invoke\",1074,0,\"¶\",[]],[\"invoke\",1075,0,\"⁋\",[]],[\"invoke\",1076,0,\"܀\",[]],[\"invoke\",1077,0,\"჻\",[]],[\"invoke\",1079,0,\"〷\",[]],[\"invoke\",1080,0,\"❡\",[]],[\"invoke\",1081,0,\"⸏\",[]],[\"invoke\",1082,0,\"⸐\",[]],[\"invoke\",1083,0,\"⸑\",[]],[\"invoke\",1085,0,\"\\u0014\",[]],[\"invoke\",1086,0,\"☙\",[]],[\"invoke\",1087,0,\"⸿\",[]],[\"invoke\",1088,0,\"〇\",[]],[\"invoke\",1089,0,\"๛\",[]],[\"invoke\",1091,0,\"ϓ\",[]],[\"invoke\",1092,0,\"ϔ\",[]],[\"invoke\",1093,0,\"ẛ\",[]],[\"module\",1095,130],[\"invoke\",1107,0,\"print32\",[\"i32:42\",\"i32:123\"]]]"; diff --git a/tests/wasm-spec/gen.mjs b/tests/wasm-spec/gen.mjs index bfb6dd9ee..2b4e5c9fb 100644 --- a/tests/wasm-spec/gen.mjs +++ b/tests/wasm-spec/gen.mjs @@ -123,6 +123,12 @@ const { values } = parseArgs({ }); const repo = join(dirname(new URL(import.meta.url).pathname), "../.."); +// Writes control and format characters (names.wast has several) as escapes, so the +// generated file holds the same strings without invisible characters in its source. +function escapeInvisible(literal) { + return literal.replace(/[\u007f-\u009f\u2028\u2029\p{Cf}]/gu, (c) => `\\u{${c.codePointAt(0).toString(16)}}`); +} + function value(v) { if (v.type === "v128") return null; return `${v.type}:${v.value}`; @@ -257,7 +263,7 @@ for (const [group, names] of Object.entries(GROUPS)) { * ${names.map((n) => `${n}.wast`).join(", ")}. Do not edit. */\n`; const body = `export const modules = [\n${modules.map((m) => ` "${m}",`).join("\n")}\n];\n` + - `export const script = ${JSON.stringify(JSON.stringify(commands))};\n`; + `export const script = ${escapeInvisible(JSON.stringify(JSON.stringify(commands)))};\n`; writeFileSync(join(out, "data.mjs"), header + body); writeFileSync( join(out, "main.mjs"),