@loopdive/js2 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1425 -0
- package/LICENSE +189 -0
- package/README.md +451 -0
- package/dist/checker/index.d.ts +117 -0
- package/dist/checker/language-service.d.ts +39 -0
- package/dist/checker/node-capability-map.d.ts +63 -0
- package/dist/checker/type-mapper.d.ts +84 -0
- package/dist/cjs-rewrite.d.ts +19 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +363 -0
- package/dist/codegen/accessor-driver.d.ts +97 -0
- package/dist/codegen/any-helpers.d.ts +72 -0
- package/dist/codegen/array-element-typing.d.ts +46 -0
- package/dist/codegen/array-holes.d.ts +69 -0
- package/dist/codegen/array-methods.d.ts +68 -0
- package/dist/codegen/array-object-proto.d.ts +64 -0
- package/dist/codegen/array-reduce-fusion.d.ts +31 -0
- package/dist/codegen/array-to-primitive.d.ts +28 -0
- package/dist/codegen/async-cps.d.ts +239 -0
- package/dist/codegen/async-scheduler.d.ts +349 -0
- package/dist/codegen/binary-ops.d.ts +78 -0
- package/dist/codegen/binding-info.d.ts +31 -0
- package/dist/codegen/builtin-scaffold.d.ts +98 -0
- package/dist/codegen/builtin-static-globals.d.ts +8 -0
- package/dist/codegen/builtin-tags.d.ts +189 -0
- package/dist/codegen/case-convert-native.d.ts +12 -0
- package/dist/codegen/case-tables.d.ts +4 -0
- package/dist/codegen/class-bodies.d.ts +41 -0
- package/dist/codegen/class-member-keys.d.ts +33 -0
- package/dist/codegen/class-to-primitive.d.ts +39 -0
- package/dist/codegen/closed-method-dispatch.d.ts +42 -0
- package/dist/codegen/closures.d.ts +285 -0
- package/dist/codegen/coercion-engine.d.ts +154 -0
- package/dist/codegen/coercion-plan.d.ts +29 -0
- package/dist/codegen/context/bodies.d.ts +4 -0
- package/dist/codegen/context/create-context.d.ts +4 -0
- package/dist/codegen/context/errors.d.ts +39 -0
- package/dist/codegen/context/locals.d.ts +69 -0
- package/dist/codegen/context/source-pos.d.ts +5 -0
- package/dist/codegen/context/speculative.d.ts +95 -0
- package/dist/codegen/context/types.d.ts +1936 -0
- package/dist/codegen/custom-iterable.d.ts +34 -0
- package/dist/codegen/dataview-native.d.ts +51 -0
- package/dist/codegen/date-parse-native.d.ts +13 -0
- package/dist/codegen/dead-elimination.d.ts +26 -0
- package/dist/codegen/declarations.d.ts +147 -0
- package/dist/codegen/deno-api.d.ts +11 -0
- package/dist/codegen/destructuring-params.d.ts +102 -0
- package/dist/codegen/dyn-read.d.ts +26 -0
- package/dist/codegen/eval-tiering.d.ts +19 -0
- package/dist/codegen/expressions/assignment.d.ts +61 -0
- package/dist/codegen/expressions/builtins.d.ts +26 -0
- package/dist/codegen/expressions/calls-closures.d.ts +54 -0
- package/dist/codegen/expressions/calls-guards.d.ts +49 -0
- package/dist/codegen/expressions/calls-optional.d.ts +4 -0
- package/dist/codegen/expressions/calls.d.ts +83 -0
- package/dist/codegen/expressions/eval-inline.d.ts +24 -0
- package/dist/codegen/expressions/extern.d.ts +67 -0
- package/dist/codegen/expressions/fnctor-prototype.d.ts +52 -0
- package/dist/codegen/expressions/helpers.d.ts +212 -0
- package/dist/codegen/expressions/identifiers.d.ts +57 -0
- package/dist/codegen/expressions/late-imports.d.ts +81 -0
- package/dist/codegen/expressions/logical-ops.d.ts +18 -0
- package/dist/codegen/expressions/misc.d.ts +27 -0
- package/dist/codegen/expressions/new-super.d.ts +25 -0
- package/dist/codegen/expressions/promise-subclass.d.ts +38 -0
- package/dist/codegen/expressions/proto-override.d.ts +63 -0
- package/dist/codegen/expressions/unary-updates.d.ts +21 -0
- package/dist/codegen/expressions/unary.d.ts +6 -0
- package/dist/codegen/expressions.d.ts +31 -0
- package/dist/codegen/fallback-telemetry.d.ts +53 -0
- package/dist/codegen/fixups.d.ts +80 -0
- package/dist/codegen/fmod.d.ts +10 -0
- package/dist/codegen/fnctor-escape-gate.d.ts +92 -0
- package/dist/codegen/function-body.d.ts +52 -0
- package/dist/codegen/generators-native.d.ts +92 -0
- package/dist/codegen/helpers/body-references-own-this.d.ts +22 -0
- package/dist/codegen/helpers/body-uses-arguments.d.ts +12 -0
- package/dist/codegen/helpers/is-strict-function.d.ts +52 -0
- package/dist/codegen/host-import-allowlist.d.ts +140 -0
- package/dist/codegen/index.d.ts +500 -0
- package/dist/codegen/ir-tail-call.d.ts +8 -0
- package/dist/codegen/iterator-native.d.ts +44 -0
- package/dist/codegen/json-codec-native.d.ts +78 -0
- package/dist/codegen/json-runtime.d.ts +35 -0
- package/dist/codegen/json-standalone.d.ts +25 -0
- package/dist/codegen/linear-uint8-analysis.d.ts +46 -0
- package/dist/codegen/linear-uint8-arena.d.ts +7 -0
- package/dist/codegen/linear-uint8-codegen.d.ts +103 -0
- package/dist/codegen/linear-uint8-signatures.d.ts +26 -0
- package/dist/codegen/literals.d.ts +115 -0
- package/dist/codegen/map-runtime.d.ts +142 -0
- package/dist/codegen/math-helpers.d.ts +7 -0
- package/dist/codegen/member-get-dispatch.d.ts +42 -0
- package/dist/codegen/member-set-dispatch.d.ts +28 -0
- package/dist/codegen/native-proto.d.ts +98 -0
- package/dist/codegen/native-regex.d.ts +158 -0
- package/dist/codegen/native-strings.d.ts +146 -0
- package/dist/codegen/new-target.d.ts +30 -0
- package/dist/codegen/node-fs-api.d.ts +47 -0
- package/dist/codegen/number-format-native.d.ts +9 -0
- package/dist/codegen/number-ryu.d.ts +27 -0
- package/dist/codegen/object-ops.d.ts +94 -0
- package/dist/codegen/object-runtime.d.ts +171 -0
- package/dist/codegen/parse-number-native.d.ts +10 -0
- package/dist/codegen/peephole.d.ts +6 -0
- package/dist/codegen/property-access.d.ts +294 -0
- package/dist/codegen/raw-wasi-api.d.ts +13 -0
- package/dist/codegen/regex/bytecode.d.ts +140 -0
- package/dist/codegen/regex/casefold.d.ts +41 -0
- package/dist/codegen/regex/compile.d.ts +51 -0
- package/dist/codegen/regex/parse.d.ts +76 -0
- package/dist/codegen/regex/unicode.d.ts +42 -0
- package/dist/codegen/regex/vm.d.ts +24 -0
- package/dist/codegen/regexp-standalone.d.ts +350 -0
- package/dist/codegen/registry/error-types.d.ts +38 -0
- package/dist/codegen/registry/imports.d.ts +46 -0
- package/dist/codegen/registry/types.d.ts +59 -0
- package/dist/codegen/set-algebra.d.ts +17 -0
- package/dist/codegen/set-runtime.d.ts +74 -0
- package/dist/codegen/shared.d.ts +111 -0
- package/dist/codegen/stack-balance.d.ts +43 -0
- package/dist/codegen/statements/control-flow.d.ts +25 -0
- package/dist/codegen/statements/destructuring.d.ts +177 -0
- package/dist/codegen/statements/exceptions.d.ts +11 -0
- package/dist/codegen/statements/functions.d.ts +1 -0
- package/dist/codegen/statements/index.d.ts +1 -0
- package/dist/codegen/statements/loops.d.ts +7 -0
- package/dist/codegen/statements/nested-declarations.d.ts +78 -0
- package/dist/codegen/statements/shared.d.ts +38 -0
- package/dist/codegen/statements/tdz.d.ts +43 -0
- package/dist/codegen/statements/variables.d.ts +3 -0
- package/dist/codegen/statements.d.ts +9 -0
- package/dist/codegen/string-builder.d.ts +131 -0
- package/dist/codegen/string-ops.d.ts +87 -0
- package/dist/codegen/struct-accessor-closure.d.ts +36 -0
- package/dist/codegen/symbol-native.d.ts +55 -0
- package/dist/codegen/temporal-native.d.ts +8 -0
- package/dist/codegen/timsort.d.ts +2 -0
- package/dist/codegen/type-coercion.d.ts +123 -0
- package/dist/codegen/typeof-delete.d.ts +38 -0
- package/dist/codegen/uri-encoding-native.d.ts +33 -0
- package/dist/codegen/value-tags.d.ts +74 -0
- package/dist/codegen/walk-instructions.d.ts +20 -0
- package/dist/codegen/weak-collections-runtime.d.ts +16 -0
- package/dist/codegen/with-scope.d.ts +106 -0
- package/dist/codegen-linear/c-abi.d.ts +74 -0
- package/dist/codegen-linear/context.d.ts +86 -0
- package/dist/codegen-linear/index.d.ts +28 -0
- package/dist/codegen-linear/layout.d.ts +39 -0
- package/dist/codegen-linear/runtime.d.ts +161 -0
- package/dist/codegen-linear/simd.d.ts +7 -0
- package/dist/compiler/define-substitution.d.ts +27 -0
- package/dist/compiler/early-errors/assignment.d.ts +26 -0
- package/dist/compiler/early-errors/context.d.ts +17 -0
- package/dist/compiler/early-errors/duplicates.d.ts +20 -0
- package/dist/compiler/early-errors/index.d.ts +11 -0
- package/dist/compiler/early-errors/labels.d.ts +13 -0
- package/dist/compiler/early-errors/module-rules.d.ts +36 -0
- package/dist/compiler/early-errors/node-checks.d.ts +7 -0
- package/dist/compiler/early-errors/predicates.d.ts +140 -0
- package/dist/compiler/early-errors/tdz.d.ts +17 -0
- package/dist/compiler/import-manifest.d.ts +18 -0
- package/dist/compiler/output.d.ts +46 -0
- package/dist/compiler/validation.d.ts +45 -0
- package/dist/compiler.d.ts +48 -0
- package/dist/define-substitution-BcUeKC2A.js +109 -0
- package/dist/emit/binary.d.ts +50 -0
- package/dist/emit/c-header.d.ts +23 -0
- package/dist/emit/canonical-recgroup.d.ts +86 -0
- package/dist/emit/encoder.d.ts +28 -0
- package/dist/emit/object.d.ts +14 -0
- package/dist/emit/opcodes.d.ts +464 -0
- package/dist/emit/sourcemap.d.ts +33 -0
- package/dist/emit/wat.d.ts +6 -0
- package/dist/env.d.ts +46 -0
- package/dist/import-resolver.d.ts +68 -0
- package/dist/index.d.ts +486 -0
- package/dist/index.js +755 -0
- package/dist/ir/alloc-registry.d.ts +75 -0
- package/dist/ir/analysis/encoding.d.ts +38 -0
- package/dist/ir/analysis/escape.d.ts +32 -0
- package/dist/ir/analysis/lattice.d.ts +72 -0
- package/dist/ir/analysis/ownership.d.ts +31 -0
- package/dist/ir/analysis/stack-alloc.d.ts +20 -0
- package/dist/ir/backend/bytecode-emitter.d.ts +237 -0
- package/dist/ir/backend/bytecode-vm.d.ts +74 -0
- package/dist/ir/backend/emitter.d.ts +121 -0
- package/dist/ir/backend/handles.d.ts +133 -0
- package/dist/ir/backend/legality.d.ts +9 -0
- package/dist/ir/backend/linear-emitter.d.ts +41 -0
- package/dist/ir/backend/wasmgc-emitter.d.ts +43 -0
- package/dist/ir/builder.d.ts +401 -0
- package/dist/ir/from-ast.d.ts +192 -0
- package/dist/ir/index.d.ts +16 -0
- package/dist/ir/integration.d.ts +27 -0
- package/dist/ir/lower.d.ts +203 -0
- package/dist/ir/nodes.d.ts +1452 -0
- package/dist/ir/passes/alloc-discipline.d.ts +19 -0
- package/dist/ir/passes/constant-fold.d.ts +7 -0
- package/dist/ir/passes/dead-code.d.ts +18 -0
- package/dist/ir/passes/inline-small.d.ts +7 -0
- package/dist/ir/passes/monomorphize.d.ts +21 -0
- package/dist/ir/passes/simplify-cfg.d.ts +19 -0
- package/dist/ir/passes/tagged-union-types.d.ts +45 -0
- package/dist/ir/passes/tagged-unions.d.ts +22 -0
- package/dist/ir/propagate.d.ts +135 -0
- package/dist/ir/select.d.ts +81 -0
- package/dist/ir/types.d.ts +832 -0
- package/dist/ir/verify-alloc.d.ts +18 -0
- package/dist/ir/verify.d.ts +7 -0
- package/dist/link/index.d.ts +11 -0
- package/dist/link/isolation.d.ts +24 -0
- package/dist/link/linker.d.ts +37 -0
- package/dist/link/reader.d.ts +158 -0
- package/dist/link/resolver.d.ts +19 -0
- package/dist/optimize.d.ts +54 -0
- package/dist/optimize.js +262 -0
- package/dist/position-map.d.ts +64 -0
- package/dist/process-stdin-prelude.d.ts +16 -0
- package/dist/resolve.d.ts +82 -0
- package/dist/runtime/builtins.d.ts +1 -0
- package/dist/runtime-C-4q_KwU.js +164438 -0
- package/dist/runtime-containment.d.ts +6 -0
- package/dist/runtime-eval.d.ts +132 -0
- package/dist/runtime-instantiate.d.ts +16 -0
- package/dist/runtime.d.ts +128 -0
- package/dist/runtime.js +12 -0
- package/dist/shape-inference.d.ts +20 -0
- package/dist/treeshake.d.ts +17 -0
- package/dist/ts-api.d.ts +30 -0
- package/dist/wit-generator.d.ts +18 -0
- package/package.json +187 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { resolve, basename, dirname } from "node:path";
|
|
5
|
+
function getCliVersion() {
|
|
6
|
+
const bundledVersion = typeof __JS2WASM_CLI_VERSION__ === "string" ? __JS2WASM_CLI_VERSION__ : void 0;
|
|
7
|
+
if (bundledVersion) return bundledVersion;
|
|
8
|
+
const require2 = createRequire(import.meta.url);
|
|
9
|
+
const pkg = require2("../package.json");
|
|
10
|
+
return pkg.version ?? "0.0.0";
|
|
11
|
+
}
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
if (args.includes("--ts7")) {
|
|
14
|
+
process.env.JS2WASM_TS7 = "1";
|
|
15
|
+
}
|
|
16
|
+
const { compile } = await import("./index.js");
|
|
17
|
+
const { buildDefaultDefines } = await import("./define-substitution-BcUeKC2A.js").then((n) => n.d);
|
|
18
|
+
if (args.includes("--version") || args.includes("-v")) {
|
|
19
|
+
console.log(getCliVersion());
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
23
|
+
console.log(`Usage: js2wasm <input.ts> [options]
|
|
24
|
+
|
|
25
|
+
Compile a TypeScript file to WebAssembly (GC proposal).
|
|
26
|
+
|
|
27
|
+
Options:
|
|
28
|
+
-o, --out <dir> Output directory (default: same as input)
|
|
29
|
+
--target <t> Host/output target — the single host axis (#2736):
|
|
30
|
+
web (default) WasmGC / JS-host browser surface (DOM
|
|
31
|
+
ambient globals in scope);
|
|
32
|
+
node a real Node host (Node ambient surface, no DOM);
|
|
33
|
+
deno a real Deno host (Deno ambient surface, no DOM);
|
|
34
|
+
wasi standalone WASI Preview 1 (fd-based host calls).
|
|
35
|
+
Also accepts the backend-lowering names gc / linear /
|
|
36
|
+
standalone (orthogonal backend choice; gc is the default
|
|
37
|
+
backend for web/node/deno).
|
|
38
|
+
--standalone Shorthand for --target standalone (pure WasmGC, no JS host,
|
|
39
|
+
no WASI). Forces nativeStrings: true and refuses to emit
|
|
40
|
+
wasm:js-string or env JS-host imports.
|
|
41
|
+
--allocator <a> Linear backend allocator (#1856): bump (default,
|
|
42
|
+
allocate-and-exit arena, smallest binary) or arena-reset
|
|
43
|
+
(same arena + __arena_reset/__arena_used exports for hosts
|
|
44
|
+
reusing one instance across short-lived tasks). Linear
|
|
45
|
+
target only.
|
|
46
|
+
--allow-fs Allow node:fs JS-host imports (readFileSync, writeFileSync)
|
|
47
|
+
for non-WASI targets (#1491). Off by default to prevent
|
|
48
|
+
accidental capability leakage.
|
|
49
|
+
--utf8-storage Dual i8/i16 string storage (#1588): store strings proven
|
|
50
|
+
UTF-8 (literals, JSON, decoder results, ...) as i8-backed
|
|
51
|
+
Utf8String for a cheaper Component Model boundary. Implies
|
|
52
|
+
nativeStrings on the WasmGC backend. Off by default
|
|
53
|
+
(byte-identical output when off).
|
|
54
|
+
--wat Emit only WAT (no binary)
|
|
55
|
+
--no-wat Skip WAT output
|
|
56
|
+
--no-dts Skip .d.ts output
|
|
57
|
+
--wit Generate WIT interface file for Component Model
|
|
58
|
+
--wit-package <p> Package name for --wit output (ns:name[@version]).
|
|
59
|
+
Implies --wit. Defaults to js2wasm:<input-basename>.
|
|
60
|
+
-v, --verbose List every dropped host-import warning individually instead
|
|
61
|
+
of collapsing them into a one-line summary (WASI/strict mode)
|
|
62
|
+
-O, --optimize Run Binaryen wasm-opt optimizer (on by default at -O3)
|
|
63
|
+
-O1..-O4 Set optimization level (1-4)
|
|
64
|
+
--no-optimize, -O0
|
|
65
|
+
Disable the optimizer; emit raw codegen output. Optimization
|
|
66
|
+
is ON by default; this restores the pre-#1950 behaviour.
|
|
67
|
+
(No-op when binaryen/wasm-opt is unavailable — that path
|
|
68
|
+
already degrades to a one-line note, never a failure.)
|
|
69
|
+
--link-node-shims (WASI, #2625/#2633) Emit the per-module linkable node:<mod>
|
|
70
|
+
shims instead of inlining the host APIs. Std-IO goes through
|
|
71
|
+
node:fs: the module imports readSync/writeSync + its memory
|
|
72
|
+
from node:fs (no wasi_snapshot_preview1 for stream IO) and
|
|
73
|
+
links node-fs.wasm. console.log / process.std*.write lower to
|
|
74
|
+
writeSync(1|2, …); stdin is readSync(0, …). Off by default —
|
|
75
|
+
the inline fd_read/fd_write path is self-contained.
|
|
76
|
+
--emulate <env> Emulate a host runtime's globals so they type-check without
|
|
77
|
+
@types/node. 'node' = ambient process/etc.; 'none' = off.
|
|
78
|
+
Auto-enabled (type-level only) when the source imports a
|
|
79
|
+
'node:' builtin (use 'none' to disable that); otherwise off,
|
|
80
|
+
and using process warns to add this flag (#2603).
|
|
81
|
+
--platform <p> DEPRECATED (#2736): alias for --target {web,node,deno}.
|
|
82
|
+
'web' = DOM globals (window/document/…) in scope (today's
|
|
83
|
+
default); 'node'/'deno' = DOM globals NOT in scope (so
|
|
84
|
+
window.stop is a type error) and Node-style API emulation on
|
|
85
|
+
(implies --emulate node). Prefer --target; this prints a
|
|
86
|
+
deprecation warning. Unset preserves today's behaviour.
|
|
87
|
+
--no-host-imports Strict dual-mode: reject JS-host 'env' imports not on
|
|
88
|
+
the allowlist (#1524). Implied by --target wasi.
|
|
89
|
+
--allow-host-imports
|
|
90
|
+
Escape hatch: disable strict dual-mode for a WASI build
|
|
91
|
+
(debug-only). Useful when temporarily mixing host + WASI
|
|
92
|
+
imports while migrating to standalone mode.
|
|
93
|
+
--define K=V Substitute identifier path K with literal V before parsing.
|
|
94
|
+
Repeatable. Example:
|
|
95
|
+
--define process.env.NODE_ENV='"production"'
|
|
96
|
+
String values must include their own quotes.
|
|
97
|
+
--mode <m> Shorthand for --define-style production/development build.
|
|
98
|
+
'production' sets process.env.NODE_ENV="production" and
|
|
99
|
+
typeof process / typeof window to "undefined".
|
|
100
|
+
'development' sets process.env.NODE_ENV="development".
|
|
101
|
+
--ts7 Use @typescript/native-preview (TypeScript 7 Go-port) as
|
|
102
|
+
the parser/checker frontend (preview; full migration
|
|
103
|
+
tracked in #1029). Equivalent to JS2WASM_TS7=1.
|
|
104
|
+
-q, --quiet Suppress the post-compile "how to run" hint
|
|
105
|
+
-v, --version Print version and exit
|
|
106
|
+
-h, --help Show this help
|
|
107
|
+
|
|
108
|
+
Output files:
|
|
109
|
+
<name>.wasm WebAssembly binary
|
|
110
|
+
<name>.wat WebAssembly text format
|
|
111
|
+
<name>.d.ts TypeScript declarations
|
|
112
|
+
<name>.imports.js createImports() helper`);
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
let inputPath;
|
|
116
|
+
let outDir;
|
|
117
|
+
let emitWat = true;
|
|
118
|
+
let emitDts = true;
|
|
119
|
+
let watOnly = false;
|
|
120
|
+
let verbose = false;
|
|
121
|
+
let optimize = 3;
|
|
122
|
+
let target;
|
|
123
|
+
let allocator;
|
|
124
|
+
let emitWit = false;
|
|
125
|
+
let witPackageName;
|
|
126
|
+
let allowFs = false;
|
|
127
|
+
let quiet = false;
|
|
128
|
+
let utf8Storage = false;
|
|
129
|
+
let strictNoHostImports;
|
|
130
|
+
let linkNodeShims = false;
|
|
131
|
+
let emulateNode = false;
|
|
132
|
+
let emulateExplicit = false;
|
|
133
|
+
let platform;
|
|
134
|
+
const defines = {};
|
|
135
|
+
for (let i = 0; i < args.length; i++) {
|
|
136
|
+
const arg = args[i];
|
|
137
|
+
if (arg === "-o" || arg === "--out") {
|
|
138
|
+
outDir = args[++i];
|
|
139
|
+
} else if (arg === "--target" || arg.startsWith("--target=")) {
|
|
140
|
+
const t = arg.startsWith("--target=") ? arg.slice("--target=".length) : args[++i];
|
|
141
|
+
if (t === "gc" || t === "linear" || t === "wasi" || t === "standalone") {
|
|
142
|
+
target = t;
|
|
143
|
+
} else if (t === "web" || t === "node" || t === "deno") {
|
|
144
|
+
platform = t;
|
|
145
|
+
} else {
|
|
146
|
+
console.error(`Unknown target: ${t} (expected web, node, deno, wasi, gc, linear, or standalone)`);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
} else if (arg === "--standalone") {
|
|
150
|
+
target = "standalone";
|
|
151
|
+
} else if (arg === "--allocator") {
|
|
152
|
+
const a = args[++i];
|
|
153
|
+
if (a === "bump" || a === "arena-reset") {
|
|
154
|
+
allocator = a;
|
|
155
|
+
} else {
|
|
156
|
+
console.error(`Unknown allocator: ${a} (expected bump or arena-reset)`);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
} else if (arg === "--wat") {
|
|
160
|
+
watOnly = true;
|
|
161
|
+
} else if (arg === "--no-wat") {
|
|
162
|
+
emitWat = false;
|
|
163
|
+
} else if (arg === "--no-dts") {
|
|
164
|
+
emitDts = false;
|
|
165
|
+
} else if (arg === "--wit") {
|
|
166
|
+
emitWit = true;
|
|
167
|
+
} else if (arg === "--wit-package") {
|
|
168
|
+
const pkg = args[++i];
|
|
169
|
+
if (!pkg) {
|
|
170
|
+
console.error("--wit-package requires a package name argument");
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
witPackageName = pkg;
|
|
174
|
+
emitWit = true;
|
|
175
|
+
} else if (arg.startsWith("--wit-package=")) {
|
|
176
|
+
const pkg = arg.slice("--wit-package=".length);
|
|
177
|
+
if (!pkg) {
|
|
178
|
+
console.error("--wit-package requires a package name argument");
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
witPackageName = pkg;
|
|
182
|
+
emitWit = true;
|
|
183
|
+
} else if (arg === "--allow-fs") {
|
|
184
|
+
allowFs = true;
|
|
185
|
+
} else if (arg === "--quiet" || arg === "-q") {
|
|
186
|
+
quiet = true;
|
|
187
|
+
} else if (arg === "--utf8-storage") {
|
|
188
|
+
utf8Storage = true;
|
|
189
|
+
} else if (arg === "--link-node-shims") {
|
|
190
|
+
linkNodeShims = true;
|
|
191
|
+
} else if (arg === "--emulate" || arg.startsWith("--emulate=")) {
|
|
192
|
+
const env = arg.startsWith("--emulate=") ? arg.slice("--emulate=".length) : args[++i];
|
|
193
|
+
if (env === "node") {
|
|
194
|
+
emulateNode = true;
|
|
195
|
+
emulateExplicit = true;
|
|
196
|
+
} else if (env === "none") {
|
|
197
|
+
emulateNode = false;
|
|
198
|
+
emulateExplicit = true;
|
|
199
|
+
} else {
|
|
200
|
+
console.error(`Unknown --emulate value: ${env ?? "(missing)"} (expected: node | none)`);
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
} else if (arg === "--platform" || arg.startsWith("--platform=")) {
|
|
204
|
+
const p = arg.startsWith("--platform=") ? arg.slice("--platform=".length) : args[++i];
|
|
205
|
+
if (p === "node" || p === "web" || p === "deno") {
|
|
206
|
+
platform = p;
|
|
207
|
+
console.error(`warning: --platform is deprecated; use --target ${p} instead.`);
|
|
208
|
+
} else {
|
|
209
|
+
console.error(`Unknown --platform value: ${p ?? "(missing)"} (expected: node | web | deno)`);
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
} else if (arg === "--no-host-imports") {
|
|
213
|
+
strictNoHostImports = true;
|
|
214
|
+
} else if (arg === "--allow-host-imports") {
|
|
215
|
+
strictNoHostImports = false;
|
|
216
|
+
} else if (arg === "--verbose" || arg === "-v") {
|
|
217
|
+
verbose = true;
|
|
218
|
+
} else if (arg === "-O" || arg === "--optimize") {
|
|
219
|
+
optimize = true;
|
|
220
|
+
} else if (arg === "--no-optimize" || arg === "-O0") {
|
|
221
|
+
optimize = false;
|
|
222
|
+
} else if (/^-O[1-4]$/.test(arg)) {
|
|
223
|
+
optimize = parseInt(arg.slice(2));
|
|
224
|
+
} else if (arg === "--define") {
|
|
225
|
+
const kv = args[++i];
|
|
226
|
+
if (!kv) {
|
|
227
|
+
console.error("--define requires a KEY=VALUE argument");
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
const eq = kv.indexOf("=");
|
|
231
|
+
if (eq < 0) {
|
|
232
|
+
console.error(`--define expected KEY=VALUE, got: ${kv}`);
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
defines[kv.slice(0, eq)] = kv.slice(eq + 1);
|
|
236
|
+
} else if (arg.startsWith("--define=")) {
|
|
237
|
+
const kv = arg.slice("--define=".length);
|
|
238
|
+
const eq = kv.indexOf("=");
|
|
239
|
+
if (eq < 0) {
|
|
240
|
+
console.error(`--define expected KEY=VALUE, got: ${kv}`);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
defines[kv.slice(0, eq)] = kv.slice(eq + 1);
|
|
244
|
+
} else if (arg === "--mode") {
|
|
245
|
+
const m = args[++i];
|
|
246
|
+
if (m !== "production" && m !== "development") {
|
|
247
|
+
console.error(`Unknown --mode: ${m} (expected production or development)`);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
Object.assign(defines, buildDefaultDefines(m));
|
|
251
|
+
} else if (arg === "--ts7") ;
|
|
252
|
+
else if (!arg.startsWith("-")) {
|
|
253
|
+
inputPath = arg;
|
|
254
|
+
} else {
|
|
255
|
+
console.error(`Unknown option: ${arg}`);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (!inputPath) {
|
|
260
|
+
console.error("Error: no input file specified");
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
if (target === "standalone" && allowFs) {
|
|
264
|
+
console.error("error: --standalone and --allow-fs are mutually exclusive");
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
if (allocator !== void 0 && target !== "linear") {
|
|
268
|
+
console.error("error: --allocator requires --target linear");
|
|
269
|
+
process.exit(1);
|
|
270
|
+
}
|
|
271
|
+
const absInput = resolve(inputPath);
|
|
272
|
+
const source = readFileSync(absInput, "utf-8");
|
|
273
|
+
if (!emulateExplicit && !emulateNode && /['"]node:[A-Za-z0-9_./-]+['"]/.test(source)) {
|
|
274
|
+
emulateNode = true;
|
|
275
|
+
console.error("note: auto-enabled Node API emulation (found a `node:` import). Pass --emulate none to disable.");
|
|
276
|
+
}
|
|
277
|
+
const name = basename(absInput, ".ts");
|
|
278
|
+
const dir = outDir ? resolve(outDir) : dirname(absInput);
|
|
279
|
+
const result = await compile(source, {
|
|
280
|
+
...optimize ? { optimize } : {},
|
|
281
|
+
...target ? { target } : {},
|
|
282
|
+
...allocator ? { allocator } : {},
|
|
283
|
+
...emitWit ? { wit: witPackageName ? { packageName: witPackageName } : true } : {},
|
|
284
|
+
...allowFs ? { allowFs: true } : {},
|
|
285
|
+
...utf8Storage ? { utf8Storage: true } : {},
|
|
286
|
+
...linkNodeShims ? { linkNodeShims: true } : {},
|
|
287
|
+
...emulateNode ? { emulateNode: true } : {},
|
|
288
|
+
...platform ? { platform } : {},
|
|
289
|
+
fileName: absInput,
|
|
290
|
+
...strictNoHostImports !== void 0 ? { strictNoHostImports } : {},
|
|
291
|
+
...Object.keys(defines).length > 0 ? { define: defines } : {}
|
|
292
|
+
});
|
|
293
|
+
if (!result.success) {
|
|
294
|
+
for (const e of result.errors) {
|
|
295
|
+
const severity = e.severity === "warning" ? "warning" : "error";
|
|
296
|
+
const where = e.file ?? absInput;
|
|
297
|
+
console.error(`${where}:${e.line}:${e.column} - ${severity}: ${e.message}`);
|
|
298
|
+
}
|
|
299
|
+
process.exit(1);
|
|
300
|
+
}
|
|
301
|
+
const isAllowlistWarning = (msg) => msg.includes("not on the dual-mode allowlist");
|
|
302
|
+
let suppressedAllowlist = 0;
|
|
303
|
+
const warnCounts = /* @__PURE__ */ new Map();
|
|
304
|
+
for (const e of result.errors) {
|
|
305
|
+
if (e.severity !== "warning") continue;
|
|
306
|
+
if (!verbose && isAllowlistWarning(e.message)) {
|
|
307
|
+
suppressedAllowlist++;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
warnCounts.set(e.message, (warnCounts.get(e.message) ?? 0) + 1);
|
|
311
|
+
}
|
|
312
|
+
for (const [msg, count] of warnCounts) {
|
|
313
|
+
console.error(count > 1 ? `warning: ${msg} (${count}×)` : `warning: ${msg}`);
|
|
314
|
+
}
|
|
315
|
+
if (suppressedAllowlist > 0) {
|
|
316
|
+
console.error(
|
|
317
|
+
`warning: ${suppressedAllowlist} host import(s) not on the dual-mode allowlist were dropped (no-op under WASI/strict mode; not in the emitted .wasm). Re-run with --verbose to list them.`
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
if (watOnly) {
|
|
321
|
+
process.stdout.write(result.wat);
|
|
322
|
+
process.exit(0);
|
|
323
|
+
}
|
|
324
|
+
let emittedWasmPath;
|
|
325
|
+
{
|
|
326
|
+
const wasmPath = resolve(dir, `${name}.wasm`);
|
|
327
|
+
writeFileSync(wasmPath, result.binary);
|
|
328
|
+
console.log(`${wasmPath} (${result.binary.byteLength} bytes)`);
|
|
329
|
+
emittedWasmPath = wasmPath;
|
|
330
|
+
}
|
|
331
|
+
if (emitWat) {
|
|
332
|
+
const watPath = resolve(dir, `${name}.wat`);
|
|
333
|
+
writeFileSync(watPath, result.wat);
|
|
334
|
+
console.log(`${watPath} (${result.wat.length} chars)`);
|
|
335
|
+
}
|
|
336
|
+
if (emitDts) {
|
|
337
|
+
const dtsPath = resolve(dir, `${name}.d.ts`);
|
|
338
|
+
writeFileSync(dtsPath, result.dts);
|
|
339
|
+
console.log(`${dtsPath} (${result.dts.length} chars)`);
|
|
340
|
+
}
|
|
341
|
+
{
|
|
342
|
+
const helperPath = resolve(dir, `${name}.imports.js`);
|
|
343
|
+
writeFileSync(helperPath, result.importsHelper);
|
|
344
|
+
console.log(`${helperPath} (${result.importsHelper.length} chars)`);
|
|
345
|
+
}
|
|
346
|
+
if (emitWit && result.wit) {
|
|
347
|
+
const witPath = resolve(dir, `${name}.wit`);
|
|
348
|
+
writeFileSync(witPath, result.wit);
|
|
349
|
+
console.log(`${witPath} (${result.wit.length} chars)`);
|
|
350
|
+
}
|
|
351
|
+
if (!quiet && emittedWasmPath) {
|
|
352
|
+
if (target === "wasi" || target === "standalone" || target === "linear") {
|
|
353
|
+
console.log(`
|
|
354
|
+
To run: wasmtime -W gc=y,function-references=y,tail-call=y,exceptions=y ${emittedWasmPath}`);
|
|
355
|
+
} else {
|
|
356
|
+
console.log(
|
|
357
|
+
`
|
|
358
|
+
This is a JS-host build (default --target gc) — it needs the generated ${name}.imports.js helper. To run with Node.js:
|
|
359
|
+
node --experimental-wasm-imported-strings -e "import('./${name}.imports.js').then(async ({ createImports }) => { const { instance } = await WebAssembly.instantiate(require('fs').readFileSync('${emittedWasmPath}'), createImports()); /* call instance.exports.* */ })"
|
|
360
|
+
For a pure-Wasm build runnable under Wasmtime, recompile with --standalone.`
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { CodegenContext } from './context/types.js';
|
|
2
|
+
/** Reserved name for the accessor-get driver (arity-0 getter wrapper). */
|
|
3
|
+
export declare const CALL_ACCESSOR_GET = "__call_accessor_get";
|
|
4
|
+
/** Reserved name for the accessor-set driver (arity-1 setter wrapper). */
|
|
5
|
+
export declare const CALL_ACCESSOR_SET = "__call_accessor_set";
|
|
6
|
+
/**
|
|
7
|
+
* (#2166 PR-D1) Reserved name for the JSON reviver driver (arity-2 method
|
|
8
|
+
* wrapper: `reviver.call(holder, key, value)`).
|
|
9
|
+
*/
|
|
10
|
+
export declare const CALL_REVIVER = "__call_reviver";
|
|
11
|
+
/**
|
|
12
|
+
* (#2166 PR-D2) Reserved name for the JSON `toJSON` driver (arity-1 method
|
|
13
|
+
* wrapper: `value.toJSON(key)`).
|
|
14
|
+
*/
|
|
15
|
+
export declare const CALL_TO_JSON = "__call_to_json";
|
|
16
|
+
/**
|
|
17
|
+
* (#2166 PR-D3) Reserved name for the JSON `stringify` replacer driver (arity-2
|
|
18
|
+
* method wrapper: `replacer.call(holder, key, value)`).
|
|
19
|
+
*/
|
|
20
|
+
export declare const CALL_REPLACER = "__call_replacer";
|
|
21
|
+
/**
|
|
22
|
+
* Reserve the `__call_accessor_get` driver placeholder and return its funcIdx.
|
|
23
|
+
*
|
|
24
|
+
* Signature: `(externref recv, externref getter) -> externref`.
|
|
25
|
+
* The body is left as a bare `unreachable` and filled by `fillAccessorDrivers`
|
|
26
|
+
* in post-processing. The reservation must run while `ensureObjectRuntime` is
|
|
27
|
+
* emitting `__extern_get`, so the append-position funcIdx is stable before any
|
|
28
|
+
* accessor arm emits its `call`.
|
|
29
|
+
*
|
|
30
|
+
* Idempotent: a second call returns the already-reserved funcIdx.
|
|
31
|
+
*/
|
|
32
|
+
export declare function reserveAccessorGetDriver(ctx: CodegenContext): number;
|
|
33
|
+
/**
|
|
34
|
+
* Reserve the `__call_accessor_set` driver placeholder and return its funcIdx.
|
|
35
|
+
*
|
|
36
|
+
* Signature: `(externref recv, externref setter, externref value) -> ()`.
|
|
37
|
+
* Setters return no value (the assignment expression result is the RHS, handled
|
|
38
|
+
* at the call site), so the driver result type is empty. Body filled by
|
|
39
|
+
* `fillAccessorDrivers`. Idempotent.
|
|
40
|
+
*/
|
|
41
|
+
export declare function reserveAccessorSetDriver(ctx: CodegenContext): number;
|
|
42
|
+
/**
|
|
43
|
+
* (#2166 PR-D1) Reserve the `__call_reviver` driver placeholder and return its
|
|
44
|
+
* funcIdx.
|
|
45
|
+
*
|
|
46
|
+
* Signature: `(externref holder, externref key, externref value) -> externref`.
|
|
47
|
+
* Filled by `fillAccessorDrivers` to wrap `__call_fn_method_2(holder, reviver,
|
|
48
|
+
* key, value)` — but note the reviver closure itself is NOT a driver param: the
|
|
49
|
+
* §25.5.1 walk threads it separately and the driver receives `holder` as the
|
|
50
|
+
* `this` and `key`/`value` as the two reviver args, with the reviver closure
|
|
51
|
+
* passed as the dispatcher's 2nd operand by the codec via a 4th hidden param.
|
|
52
|
+
* To keep the driver arity fixed we instead make the reviver the FIRST arg and
|
|
53
|
+
* holder the receiver: see `fillAccessorDrivers`. Idempotent.
|
|
54
|
+
*/
|
|
55
|
+
export declare function reserveReviverDriver(ctx: CodegenContext): number;
|
|
56
|
+
/**
|
|
57
|
+
* (#2166 PR-D2) Reserve the `__call_to_json` driver placeholder and return its
|
|
58
|
+
* funcIdx.
|
|
59
|
+
*
|
|
60
|
+
* Signature: `(externref value, externref method, externref key) -> externref`.
|
|
61
|
+
* Filled by `fillAccessorDrivers` to wrap `__call_fn_method_1(value, method,
|
|
62
|
+
* key)` — `value` bound as the `toJSON` receiver (`this`), `key` the §25.5.2
|
|
63
|
+
* SerializeJSONProperty step-2.b argument. Idempotent.
|
|
64
|
+
*/
|
|
65
|
+
export declare function reserveToJsonDriver(ctx: CodegenContext): number;
|
|
66
|
+
/**
|
|
67
|
+
* (#2166 PR-D3) Reserve the `__call_replacer` driver placeholder and return its
|
|
68
|
+
* funcIdx.
|
|
69
|
+
*
|
|
70
|
+
* Signature: `(externref holder, externref replacer, externref key,
|
|
71
|
+
* externref value) -> externref`. The replacer function is invoked as
|
|
72
|
+
* `replacer.call(holder, key, value)` (§25.5.2 SerializeJSONProperty step 3),
|
|
73
|
+
* so `holder` binds as `this` and `key`/`value` are the two arguments — exactly
|
|
74
|
+
* the reviver driver's shape. Filled by `fillAccessorDrivers` wrapping
|
|
75
|
+
* `__call_fn_method_2`. Idempotent.
|
|
76
|
+
*/
|
|
77
|
+
export declare function reserveReplacerDriver(ctx: CodegenContext): number;
|
|
78
|
+
/**
|
|
79
|
+
* Fill the reserved accessor driver bodies in post-processing, AFTER
|
|
80
|
+
* `emitClosureMethodCallExportN(0)` / `(1)` have registered
|
|
81
|
+
* `__call_fn_method_0` / `__call_fn_method_1` in `funcMap`. Each driver is a
|
|
82
|
+
* thin wrapper that forwards to the matching closure-method dispatcher, reusing
|
|
83
|
+
* the proven re-entrancy-safe `__current_this` install/restore (#1636-S1)
|
|
84
|
+
* instead of duplicating funcref-type dispatch inside the object runtime:
|
|
85
|
+
*
|
|
86
|
+
* __call_accessor_get(recv, getter) = return __call_fn_method_0(recv, getter)
|
|
87
|
+
* __call_accessor_set(recv, setter, value) =
|
|
88
|
+
* __call_fn_method_1(recv, setter, value) ; drop result
|
|
89
|
+
*
|
|
90
|
+
* No-op when the corresponding driver was never reserved (no accessor arm
|
|
91
|
+
* needs it). When the driver WAS reserved but the matching dispatcher was never
|
|
92
|
+
* emitted (no closure of that arity exists — so no real getter/setter closure
|
|
93
|
+
* could have been installed either), the body is filled with a valid fallback
|
|
94
|
+
* (return-undefined for get; bare return for set) so the module still verifies —
|
|
95
|
+
* mirrors `fillProtoIteratorDriver`'s null fallback.
|
|
96
|
+
*/
|
|
97
|
+
export declare function fillAccessorDrivers(ctx: CodegenContext): void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ValType } from '../ir/types.js';
|
|
2
|
+
import { CodegenContext, FunctionContext } from './context/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Register the $AnyValue struct type for boxing `any` typed values.
|
|
5
|
+
* The struct has a tag field to distinguish the boxed type at runtime,
|
|
6
|
+
* plus payload fields for each possible value kind.
|
|
7
|
+
*
|
|
8
|
+
* Called lazily — only emitted when the module actually uses `any`-typed values.
|
|
9
|
+
*/
|
|
10
|
+
export declare function ensureAnyValueType(ctx: CodegenContext): void;
|
|
11
|
+
/**
|
|
12
|
+
* (#2106 S1.0) Push the standalone `$undefined` singleton (a `ref $AnyValue`,
|
|
13
|
+
* tag 1) onto the stack. Returns `false` (emitting nothing) when not in
|
|
14
|
+
* standalone/native-strings mode or the singleton was not reserved — callers
|
|
15
|
+
* then fall back to their existing `ref.null.extern` / host-`__get_undefined`
|
|
16
|
+
* path. INERT until S1.1 routes `emitUndefined` here.
|
|
17
|
+
*/
|
|
18
|
+
export declare function emitUndefinedSingleton(ctx: CodegenContext, fctx: FunctionContext): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* (#2106 S1.0) Test whether the `ref $AnyValue` on top of the stack is the
|
|
21
|
+
* `$undefined` singleton (tag === 1). Consumes the ref, leaves an i32. Returns
|
|
22
|
+
* `false` (emitting nothing) when the singleton is unavailable. INERT until S1.1
|
|
23
|
+
* routes the `=== undefined` / `typeof === "undefined"` consumers here.
|
|
24
|
+
*/
|
|
25
|
+
export declare function emitIsUndefinedSingleton(ctx: CodegenContext, fctx: FunctionContext): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Lazily register wrapper struct types for Number, String, Boolean.
|
|
28
|
+
* Each wrapper is a struct with a single `value` field holding the primitive.
|
|
29
|
+
* Also registers WrapperX_valueOf functions that extract the value.
|
|
30
|
+
* Must be called before resolveWasmType is used for wrapper types.
|
|
31
|
+
*/
|
|
32
|
+
export declare function ensureWrapperTypes(ctx: CodegenContext): void;
|
|
33
|
+
/**
|
|
34
|
+
* Emit valueOf helper functions for wrapper types.
|
|
35
|
+
* Must be called after all imports are registered (so function indices are stable)
|
|
36
|
+
* but before user functions that call valueOf.
|
|
37
|
+
*/
|
|
38
|
+
export declare function emitWrapperValueOfFunctions(ctx: CodegenContext): void;
|
|
39
|
+
/**
|
|
40
|
+
* Check if a ValType represents a boxed `any` value (ref $AnyValue).
|
|
41
|
+
*/
|
|
42
|
+
export declare function isAnyValue(type: ValType, ctx: CodegenContext): boolean;
|
|
43
|
+
export declare function ensureAnyFromExternHelper(ctx: CodegenContext): number | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* (#1461/#54) Native standalone `(externref, externref) -> i32` strict-equality
|
|
46
|
+
* (`===`, StrictEqualityComparison) over two boxed externref values. The pure-Wasm
|
|
47
|
+
* replacement for the `__host_eq` host import in the array-like search arm
|
|
48
|
+
* (`indexOf`/`lastIndexOf`). Composes the two existing engine-owned helpers:
|
|
49
|
+
* `__any_from_extern` (recovers a boxed externref primitive — number/boolean/
|
|
50
|
+
* string/null/object — into a uniform `(ref $AnyValue)`) then `__any_strict_eq`
|
|
51
|
+
* (===-compares two `$AnyValue`, numeric class unified via `f64.eq` ⇒ NaN≠NaN,
|
|
52
|
+
* strings by content, objects by identity). Standalone-only; returns undefined
|
|
53
|
+
* otherwise (caller keeps the host import).
|
|
54
|
+
*/
|
|
55
|
+
export declare function ensureExternStrictEqHelper(ctx: CodegenContext): number | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* (#1461/#54) Native standalone `(externref, externref) -> i32` SameValueZero
|
|
58
|
+
* (§7.2.11) over two boxed externref values — the pure-Wasm replacement for the
|
|
59
|
+
* `__same_value_zero` host import in the array-like `includes` search arm.
|
|
60
|
+
* SameValueZero differs from `===` ONLY in `NaN`: SameValueZero(NaN, NaN) is
|
|
61
|
+
* true (and +0/−0 are equal under both, which `f64.eq` already gives). So:
|
|
62
|
+
* `__extern_strict_eq(a, b) || (a and b are both NaN numbers)`. The NaN test
|
|
63
|
+
* recovers both via `__any_from_extern`, checks tag ∈ {2,3} (number) and the
|
|
64
|
+
* f64 self-inequality (`x !== x`).
|
|
65
|
+
*/
|
|
66
|
+
export declare function ensureExternSameValueZeroHelper(ctx: CodegenContext): number | undefined;
|
|
67
|
+
export declare function ensureAnyToExternHelper(ctx: CodegenContext): number | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Emit inline wasm helper functions for boxing/unboxing `any` values.
|
|
70
|
+
* Called lazily when any-typed operations are first encountered.
|
|
71
|
+
*/
|
|
72
|
+
export declare function ensureAnyHelpers(ctx: CodegenContext): void;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ts } from '../ts-api.js';
|
|
2
|
+
/**
|
|
3
|
+
* Return true if `expr` provably produces a 32-bit signed integer at runtime,
|
|
4
|
+
* given that `i32Locals` is the set of locals already known to hold i32.
|
|
5
|
+
*
|
|
6
|
+
* Recognised i32-safe forms (mirrors `isI32SafeExpr` in function-body.ts but
|
|
7
|
+
* is intentionally narrower — we err on the side of disqualification):
|
|
8
|
+
* - integer numeric literal in [-2^31, 2^31)
|
|
9
|
+
* - identifier referencing a known-i32 local
|
|
10
|
+
* - bitwise `|`, `&`, `^`, `<<`, `>>` (always produce int32 per ECMAScript)
|
|
11
|
+
* - comparison ops (return boolean = i32)
|
|
12
|
+
* - unary `+` / `-` / `~` of an i32-safe operand
|
|
13
|
+
* - `+` / `-` / `*` of two i32-safe operands (overflow wraps; receiver is i32)
|
|
14
|
+
* - parenthesised / `as`-cast / non-null-asserted i32-safe expr
|
|
15
|
+
*
|
|
16
|
+
* Note: `>>>` is intentionally excluded — it produces uint32 which can sit
|
|
17
|
+
* above 2^31 and would be reinterpreted as a negative i32 on store. The
|
|
18
|
+
* conservative choice is to disqualify (the array would then stay f64).
|
|
19
|
+
*/
|
|
20
|
+
export declare function isI32SafeExprForArray(expr: ts.Expression | undefined, i32Locals: ReadonlySet<string>, depth?: number): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Compute the set of `let arr: number[] = []`-style locals in `decl` whose
|
|
23
|
+
* element storage can safely lower to `i32` instead of `f64`.
|
|
24
|
+
*
|
|
25
|
+
* Pre-conditions for promotion (all must hold):
|
|
26
|
+
* 1. The declaration has an explicit `number[]` (or `Array<number>`) type
|
|
27
|
+
* annotation. Without the annotation, downstream codegen still picks
|
|
28
|
+
* f64 from the contextual type and the override would not flow to the
|
|
29
|
+
* assignment-site `compileExpression(value, arrDef.element)` path.
|
|
30
|
+
* 2. The initializer is `[]`, `new Array(n?)`, or `Array(n?)`.
|
|
31
|
+
* 3. The local is not captured in any nested function (closures break
|
|
32
|
+
* cross-scope type assumptions, exactly as for #1120 scalar locals).
|
|
33
|
+
* 4. The local is never used outside whitelisted positions:
|
|
34
|
+
* - `arr[i]` (read) (parent: ElementAccessExpression as receiver)
|
|
35
|
+
* - `arr[i] = E` (parent of `arr` is the LHS access)
|
|
36
|
+
* - `arr.length` (PropertyAccessExpression as receiver)
|
|
37
|
+
* - `arr.push(E)` / `arr[i]++` / etc. — only `arr.push(E)` is allowed,
|
|
38
|
+
* and only when E is i32-safe. All other method calls disqualify.
|
|
39
|
+
* 5. Every `arr[i] = E` has E i32-safe per `isI32SafeExprForArray`.
|
|
40
|
+
* 6. The local is never the LHS of a plain assignment (`arr = ...` after
|
|
41
|
+
* the declaration) — the candidate-collection step already restricts
|
|
42
|
+
* to let/const, but a single-let `let arr: number[]` could still be
|
|
43
|
+
* reassigned. We catch this in the use scan because a bare identifier
|
|
44
|
+
* reference on the LHS of `=` is not in the whitelist.
|
|
45
|
+
*/
|
|
46
|
+
export declare function collectI32SpecializedArrays(decl: ts.FunctionLikeDeclaration, i32CoercedLocals: ReadonlySet<string>): Set<string>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ts } from '../ts-api.js';
|
|
2
|
+
import { CodegenContext, FunctionContext } from './context/types.js';
|
|
3
|
+
import { Instr } from '../ir/types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Cheap AST pre-scan: set `ctx.usesArrayHoles` when the program contains any
|
|
6
|
+
* array-literal elision (`OmittedExpression`). Runs once before body
|
|
7
|
+
* compilation (mirrors `scanForNewTarget`). When clear — the common case — the
|
|
8
|
+
* hole read-guard is never emitted and every array read stays byte-identical.
|
|
9
|
+
*
|
|
10
|
+
* Setting the flag in a pre-pass (rather than lazily at the first hole-store)
|
|
11
|
+
* is what lets a `a[i]` element *read* in one function emit the `$Hole → undefined`
|
|
12
|
+
* guard even though the hole-bearing literal lives in a *different* function
|
|
13
|
+
* compiled later — function compilation order is not source order, so a per-site
|
|
14
|
+
* lazy flag would desync reads against stores.
|
|
15
|
+
*/
|
|
16
|
+
export declare function scanForArrayHoles(ctx: CodegenContext, root: ts.Node): void;
|
|
17
|
+
/**
|
|
18
|
+
* Lazily register the `$Hole` struct type and the `$__hole` singleton global.
|
|
19
|
+
* Idempotent — returns the absolute global index, caches both the type index
|
|
20
|
+
* (`ctx.holeTypeIdx`) and the global index (`ctx.holeGlobalIdx`).
|
|
21
|
+
*
|
|
22
|
+
* Registered **late** (during body compilation, after class collection) and
|
|
23
|
+
* **once**, per `project_type_index_shift_and_deadelim`: pushing a struct type
|
|
24
|
+
* mid-class-collection would desync class struct typeidxs. Both call sites
|
|
25
|
+
* (literal store + element read) run inside `compileDeclarations`, so the type
|
|
26
|
+
* is always appended after the class struct types are fixed.
|
|
27
|
+
*
|
|
28
|
+
* The global is **immutable** with a constant `struct.new $Hole` initializer —
|
|
29
|
+
* a valid WasmGC constant init expression for a zero-field immutable struct, so
|
|
30
|
+
* `$Hole`'s ref identity is fixed at instantiation and every `global.get`
|
|
31
|
+
* yields the same ref (required for `ref.test`/`ref.eq` identity). A const init
|
|
32
|
+
* never contains a `call`, so it is immune to late-import index shifts.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ensureHoleType(ctx: CodegenContext): number;
|
|
35
|
+
/**
|
|
36
|
+
* Push the `$Hole` sentinel as an `externref`, ready to store into an
|
|
37
|
+
* externref-element vec slot (`array.new_fixed` / `array.set`).
|
|
38
|
+
* Stack: `[] → [externref]`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function emitHoleSentinel(ctx: CodegenContext, fctx: FunctionContext): void;
|
|
41
|
+
/**
|
|
42
|
+
* Read-boundary mapping: if the externref on the stack is the `$Hole` sentinel,
|
|
43
|
+
* replace it with `undefined`; otherwise leave it unchanged.
|
|
44
|
+
* Stack: `[externref] → [externref]`.
|
|
45
|
+
*
|
|
46
|
+
* The single most important correctness rule for sparse arrays — the sentinel
|
|
47
|
+
* must never leak past a value-producing read. Reusable across S1 (element read,
|
|
48
|
+
* join) and the later HOF / destructuring slices.
|
|
49
|
+
*/
|
|
50
|
+
export declare function emitHoleToUndefined(ctx: CodegenContext, fctx: FunctionContext): void;
|
|
51
|
+
/**
|
|
52
|
+
* Detached-`Instr[]` form of {@link emitHoleToUndefined}, for call sites that
|
|
53
|
+
* assemble a callback-arg / loop-body instruction list off `fctx.body` (e.g.
|
|
54
|
+
* `buildClosureCallInstrs`). Allocates the scratch temp via `fctx` and resolves
|
|
55
|
+
* the `undefined` value up front (flushing any late-import shift into the
|
|
56
|
+
* current body BEFORE the funcIdx is baked into the returned instrs), so the
|
|
57
|
+
* sequence can be spliced anywhere. Stack: `[externref] → [externref]`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function holeToUndefinedInstrs(ctx: CodegenContext, fctx: FunctionContext): Instr[];
|
|
60
|
+
/**
|
|
61
|
+
* Instruction list form of the hole test for the array-join fold, where the
|
|
62
|
+
* element-to-string conversion is assembled as a detached `Instr[]` (not pushed
|
|
63
|
+
* onto `fctx.body`). Given the element `externref` already on the (virtual)
|
|
64
|
+
* stack, returns instrs that leave `i32` = 1 iff the element is `$Hole`.
|
|
65
|
+
* Caller wraps `whenHole` / `whenPresent` in the `if`. Registers `$Hole` on
|
|
66
|
+
* demand (caller gates on `usesArrayHoles`), so the `ref.test` typeidx is valid
|
|
67
|
+
* even if no hole-literal has been compiled yet in this module.
|
|
68
|
+
*/
|
|
69
|
+
export declare function holeTestInstrs(ctx: CodegenContext): Instr[];
|