@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.
Files changed (233) hide show
  1. package/CHANGELOG.md +1425 -0
  2. package/LICENSE +189 -0
  3. package/README.md +451 -0
  4. package/dist/checker/index.d.ts +117 -0
  5. package/dist/checker/language-service.d.ts +39 -0
  6. package/dist/checker/node-capability-map.d.ts +63 -0
  7. package/dist/checker/type-mapper.d.ts +84 -0
  8. package/dist/cjs-rewrite.d.ts +19 -0
  9. package/dist/cli.d.ts +2 -0
  10. package/dist/cli.js +363 -0
  11. package/dist/codegen/accessor-driver.d.ts +97 -0
  12. package/dist/codegen/any-helpers.d.ts +72 -0
  13. package/dist/codegen/array-element-typing.d.ts +46 -0
  14. package/dist/codegen/array-holes.d.ts +69 -0
  15. package/dist/codegen/array-methods.d.ts +68 -0
  16. package/dist/codegen/array-object-proto.d.ts +64 -0
  17. package/dist/codegen/array-reduce-fusion.d.ts +31 -0
  18. package/dist/codegen/array-to-primitive.d.ts +28 -0
  19. package/dist/codegen/async-cps.d.ts +239 -0
  20. package/dist/codegen/async-scheduler.d.ts +349 -0
  21. package/dist/codegen/binary-ops.d.ts +78 -0
  22. package/dist/codegen/binding-info.d.ts +31 -0
  23. package/dist/codegen/builtin-scaffold.d.ts +98 -0
  24. package/dist/codegen/builtin-static-globals.d.ts +8 -0
  25. package/dist/codegen/builtin-tags.d.ts +189 -0
  26. package/dist/codegen/case-convert-native.d.ts +12 -0
  27. package/dist/codegen/case-tables.d.ts +4 -0
  28. package/dist/codegen/class-bodies.d.ts +41 -0
  29. package/dist/codegen/class-member-keys.d.ts +33 -0
  30. package/dist/codegen/class-to-primitive.d.ts +39 -0
  31. package/dist/codegen/closed-method-dispatch.d.ts +42 -0
  32. package/dist/codegen/closures.d.ts +285 -0
  33. package/dist/codegen/coercion-engine.d.ts +154 -0
  34. package/dist/codegen/coercion-plan.d.ts +29 -0
  35. package/dist/codegen/context/bodies.d.ts +4 -0
  36. package/dist/codegen/context/create-context.d.ts +4 -0
  37. package/dist/codegen/context/errors.d.ts +39 -0
  38. package/dist/codegen/context/locals.d.ts +69 -0
  39. package/dist/codegen/context/source-pos.d.ts +5 -0
  40. package/dist/codegen/context/speculative.d.ts +95 -0
  41. package/dist/codegen/context/types.d.ts +1936 -0
  42. package/dist/codegen/custom-iterable.d.ts +34 -0
  43. package/dist/codegen/dataview-native.d.ts +51 -0
  44. package/dist/codegen/date-parse-native.d.ts +13 -0
  45. package/dist/codegen/dead-elimination.d.ts +26 -0
  46. package/dist/codegen/declarations.d.ts +147 -0
  47. package/dist/codegen/deno-api.d.ts +11 -0
  48. package/dist/codegen/destructuring-params.d.ts +102 -0
  49. package/dist/codegen/dyn-read.d.ts +26 -0
  50. package/dist/codegen/eval-tiering.d.ts +19 -0
  51. package/dist/codegen/expressions/assignment.d.ts +61 -0
  52. package/dist/codegen/expressions/builtins.d.ts +26 -0
  53. package/dist/codegen/expressions/calls-closures.d.ts +54 -0
  54. package/dist/codegen/expressions/calls-guards.d.ts +49 -0
  55. package/dist/codegen/expressions/calls-optional.d.ts +4 -0
  56. package/dist/codegen/expressions/calls.d.ts +83 -0
  57. package/dist/codegen/expressions/eval-inline.d.ts +24 -0
  58. package/dist/codegen/expressions/extern.d.ts +67 -0
  59. package/dist/codegen/expressions/fnctor-prototype.d.ts +52 -0
  60. package/dist/codegen/expressions/helpers.d.ts +212 -0
  61. package/dist/codegen/expressions/identifiers.d.ts +57 -0
  62. package/dist/codegen/expressions/late-imports.d.ts +81 -0
  63. package/dist/codegen/expressions/logical-ops.d.ts +18 -0
  64. package/dist/codegen/expressions/misc.d.ts +27 -0
  65. package/dist/codegen/expressions/new-super.d.ts +25 -0
  66. package/dist/codegen/expressions/promise-subclass.d.ts +38 -0
  67. package/dist/codegen/expressions/proto-override.d.ts +63 -0
  68. package/dist/codegen/expressions/unary-updates.d.ts +21 -0
  69. package/dist/codegen/expressions/unary.d.ts +6 -0
  70. package/dist/codegen/expressions.d.ts +31 -0
  71. package/dist/codegen/fallback-telemetry.d.ts +53 -0
  72. package/dist/codegen/fixups.d.ts +80 -0
  73. package/dist/codegen/fmod.d.ts +10 -0
  74. package/dist/codegen/fnctor-escape-gate.d.ts +92 -0
  75. package/dist/codegen/function-body.d.ts +52 -0
  76. package/dist/codegen/generators-native.d.ts +92 -0
  77. package/dist/codegen/helpers/body-references-own-this.d.ts +22 -0
  78. package/dist/codegen/helpers/body-uses-arguments.d.ts +12 -0
  79. package/dist/codegen/helpers/is-strict-function.d.ts +52 -0
  80. package/dist/codegen/host-import-allowlist.d.ts +140 -0
  81. package/dist/codegen/index.d.ts +500 -0
  82. package/dist/codegen/ir-tail-call.d.ts +8 -0
  83. package/dist/codegen/iterator-native.d.ts +44 -0
  84. package/dist/codegen/json-codec-native.d.ts +78 -0
  85. package/dist/codegen/json-runtime.d.ts +35 -0
  86. package/dist/codegen/json-standalone.d.ts +25 -0
  87. package/dist/codegen/linear-uint8-analysis.d.ts +46 -0
  88. package/dist/codegen/linear-uint8-arena.d.ts +7 -0
  89. package/dist/codegen/linear-uint8-codegen.d.ts +103 -0
  90. package/dist/codegen/linear-uint8-signatures.d.ts +26 -0
  91. package/dist/codegen/literals.d.ts +115 -0
  92. package/dist/codegen/map-runtime.d.ts +142 -0
  93. package/dist/codegen/math-helpers.d.ts +7 -0
  94. package/dist/codegen/member-get-dispatch.d.ts +42 -0
  95. package/dist/codegen/member-set-dispatch.d.ts +28 -0
  96. package/dist/codegen/native-proto.d.ts +98 -0
  97. package/dist/codegen/native-regex.d.ts +158 -0
  98. package/dist/codegen/native-strings.d.ts +146 -0
  99. package/dist/codegen/new-target.d.ts +30 -0
  100. package/dist/codegen/node-fs-api.d.ts +47 -0
  101. package/dist/codegen/number-format-native.d.ts +9 -0
  102. package/dist/codegen/number-ryu.d.ts +27 -0
  103. package/dist/codegen/object-ops.d.ts +94 -0
  104. package/dist/codegen/object-runtime.d.ts +171 -0
  105. package/dist/codegen/parse-number-native.d.ts +10 -0
  106. package/dist/codegen/peephole.d.ts +6 -0
  107. package/dist/codegen/property-access.d.ts +294 -0
  108. package/dist/codegen/raw-wasi-api.d.ts +13 -0
  109. package/dist/codegen/regex/bytecode.d.ts +140 -0
  110. package/dist/codegen/regex/casefold.d.ts +41 -0
  111. package/dist/codegen/regex/compile.d.ts +51 -0
  112. package/dist/codegen/regex/parse.d.ts +76 -0
  113. package/dist/codegen/regex/unicode.d.ts +42 -0
  114. package/dist/codegen/regex/vm.d.ts +24 -0
  115. package/dist/codegen/regexp-standalone.d.ts +350 -0
  116. package/dist/codegen/registry/error-types.d.ts +38 -0
  117. package/dist/codegen/registry/imports.d.ts +46 -0
  118. package/dist/codegen/registry/types.d.ts +59 -0
  119. package/dist/codegen/set-algebra.d.ts +17 -0
  120. package/dist/codegen/set-runtime.d.ts +74 -0
  121. package/dist/codegen/shared.d.ts +111 -0
  122. package/dist/codegen/stack-balance.d.ts +43 -0
  123. package/dist/codegen/statements/control-flow.d.ts +25 -0
  124. package/dist/codegen/statements/destructuring.d.ts +177 -0
  125. package/dist/codegen/statements/exceptions.d.ts +11 -0
  126. package/dist/codegen/statements/functions.d.ts +1 -0
  127. package/dist/codegen/statements/index.d.ts +1 -0
  128. package/dist/codegen/statements/loops.d.ts +7 -0
  129. package/dist/codegen/statements/nested-declarations.d.ts +78 -0
  130. package/dist/codegen/statements/shared.d.ts +38 -0
  131. package/dist/codegen/statements/tdz.d.ts +43 -0
  132. package/dist/codegen/statements/variables.d.ts +3 -0
  133. package/dist/codegen/statements.d.ts +9 -0
  134. package/dist/codegen/string-builder.d.ts +131 -0
  135. package/dist/codegen/string-ops.d.ts +87 -0
  136. package/dist/codegen/struct-accessor-closure.d.ts +36 -0
  137. package/dist/codegen/symbol-native.d.ts +55 -0
  138. package/dist/codegen/temporal-native.d.ts +8 -0
  139. package/dist/codegen/timsort.d.ts +2 -0
  140. package/dist/codegen/type-coercion.d.ts +123 -0
  141. package/dist/codegen/typeof-delete.d.ts +38 -0
  142. package/dist/codegen/uri-encoding-native.d.ts +33 -0
  143. package/dist/codegen/value-tags.d.ts +74 -0
  144. package/dist/codegen/walk-instructions.d.ts +20 -0
  145. package/dist/codegen/weak-collections-runtime.d.ts +16 -0
  146. package/dist/codegen/with-scope.d.ts +106 -0
  147. package/dist/codegen-linear/c-abi.d.ts +74 -0
  148. package/dist/codegen-linear/context.d.ts +86 -0
  149. package/dist/codegen-linear/index.d.ts +28 -0
  150. package/dist/codegen-linear/layout.d.ts +39 -0
  151. package/dist/codegen-linear/runtime.d.ts +161 -0
  152. package/dist/codegen-linear/simd.d.ts +7 -0
  153. package/dist/compiler/define-substitution.d.ts +27 -0
  154. package/dist/compiler/early-errors/assignment.d.ts +26 -0
  155. package/dist/compiler/early-errors/context.d.ts +17 -0
  156. package/dist/compiler/early-errors/duplicates.d.ts +20 -0
  157. package/dist/compiler/early-errors/index.d.ts +11 -0
  158. package/dist/compiler/early-errors/labels.d.ts +13 -0
  159. package/dist/compiler/early-errors/module-rules.d.ts +36 -0
  160. package/dist/compiler/early-errors/node-checks.d.ts +7 -0
  161. package/dist/compiler/early-errors/predicates.d.ts +140 -0
  162. package/dist/compiler/early-errors/tdz.d.ts +17 -0
  163. package/dist/compiler/import-manifest.d.ts +18 -0
  164. package/dist/compiler/output.d.ts +46 -0
  165. package/dist/compiler/validation.d.ts +45 -0
  166. package/dist/compiler.d.ts +48 -0
  167. package/dist/define-substitution-BcUeKC2A.js +109 -0
  168. package/dist/emit/binary.d.ts +50 -0
  169. package/dist/emit/c-header.d.ts +23 -0
  170. package/dist/emit/canonical-recgroup.d.ts +86 -0
  171. package/dist/emit/encoder.d.ts +28 -0
  172. package/dist/emit/object.d.ts +14 -0
  173. package/dist/emit/opcodes.d.ts +464 -0
  174. package/dist/emit/sourcemap.d.ts +33 -0
  175. package/dist/emit/wat.d.ts +6 -0
  176. package/dist/env.d.ts +46 -0
  177. package/dist/import-resolver.d.ts +68 -0
  178. package/dist/index.d.ts +486 -0
  179. package/dist/index.js +755 -0
  180. package/dist/ir/alloc-registry.d.ts +75 -0
  181. package/dist/ir/analysis/encoding.d.ts +38 -0
  182. package/dist/ir/analysis/escape.d.ts +32 -0
  183. package/dist/ir/analysis/lattice.d.ts +72 -0
  184. package/dist/ir/analysis/ownership.d.ts +31 -0
  185. package/dist/ir/analysis/stack-alloc.d.ts +20 -0
  186. package/dist/ir/backend/bytecode-emitter.d.ts +237 -0
  187. package/dist/ir/backend/bytecode-vm.d.ts +74 -0
  188. package/dist/ir/backend/emitter.d.ts +121 -0
  189. package/dist/ir/backend/handles.d.ts +133 -0
  190. package/dist/ir/backend/legality.d.ts +9 -0
  191. package/dist/ir/backend/linear-emitter.d.ts +41 -0
  192. package/dist/ir/backend/wasmgc-emitter.d.ts +43 -0
  193. package/dist/ir/builder.d.ts +401 -0
  194. package/dist/ir/from-ast.d.ts +192 -0
  195. package/dist/ir/index.d.ts +16 -0
  196. package/dist/ir/integration.d.ts +27 -0
  197. package/dist/ir/lower.d.ts +203 -0
  198. package/dist/ir/nodes.d.ts +1452 -0
  199. package/dist/ir/passes/alloc-discipline.d.ts +19 -0
  200. package/dist/ir/passes/constant-fold.d.ts +7 -0
  201. package/dist/ir/passes/dead-code.d.ts +18 -0
  202. package/dist/ir/passes/inline-small.d.ts +7 -0
  203. package/dist/ir/passes/monomorphize.d.ts +21 -0
  204. package/dist/ir/passes/simplify-cfg.d.ts +19 -0
  205. package/dist/ir/passes/tagged-union-types.d.ts +45 -0
  206. package/dist/ir/passes/tagged-unions.d.ts +22 -0
  207. package/dist/ir/propagate.d.ts +135 -0
  208. package/dist/ir/select.d.ts +81 -0
  209. package/dist/ir/types.d.ts +832 -0
  210. package/dist/ir/verify-alloc.d.ts +18 -0
  211. package/dist/ir/verify.d.ts +7 -0
  212. package/dist/link/index.d.ts +11 -0
  213. package/dist/link/isolation.d.ts +24 -0
  214. package/dist/link/linker.d.ts +37 -0
  215. package/dist/link/reader.d.ts +158 -0
  216. package/dist/link/resolver.d.ts +19 -0
  217. package/dist/optimize.d.ts +54 -0
  218. package/dist/optimize.js +262 -0
  219. package/dist/position-map.d.ts +64 -0
  220. package/dist/process-stdin-prelude.d.ts +16 -0
  221. package/dist/resolve.d.ts +82 -0
  222. package/dist/runtime/builtins.d.ts +1 -0
  223. package/dist/runtime-C-4q_KwU.js +164438 -0
  224. package/dist/runtime-containment.d.ts +6 -0
  225. package/dist/runtime-eval.d.ts +132 -0
  226. package/dist/runtime-instantiate.d.ts +16 -0
  227. package/dist/runtime.d.ts +128 -0
  228. package/dist/runtime.js +12 -0
  229. package/dist/shape-inference.d.ts +20 -0
  230. package/dist/treeshake.d.ts +17 -0
  231. package/dist/ts-api.d.ts +30 -0
  232. package/dist/wit-generator.d.ts +18 -0
  233. package/package.json +187 -0
@@ -0,0 +1,75 @@
1
+ import { AllocKind, AllocSiteId, IrSiteId, IrType } from './nodes.js';
2
+ /**
3
+ * A live allocation site. `metadata` is stored out-of-band in the registry
4
+ * (keyed by id + namespace), not on this record, so analyses can annotate
5
+ * without mutating the IR.
6
+ */
7
+ export interface AllocSite {
8
+ readonly id: AllocSiteId;
9
+ readonly kind: AllocKind;
10
+ readonly type: IrType;
11
+ /** Reuses the defining instr's source location, when present. */
12
+ readonly origin?: IrSiteId;
13
+ }
14
+ /**
15
+ * Reserved metadata namespaces. Each analysis owns exactly one and may not
16
+ * write to another's. Enforced by convention in this issue (#1586); the ADR
17
+ * documents the ownership table.
18
+ */
19
+ export declare const ALLOC_NAMESPACES: {
20
+ /** #1587 — ownership and access-semantics analysis. */
21
+ readonly ownership: "ownership";
22
+ /** #1588 — string encoding tracking. */
23
+ readonly encoding: "encoding";
24
+ /** #1585 — dual-target IR / lifetime analysis. */
25
+ readonly lifetime: "lifetime";
26
+ /** Closure-capture escape analysis (#747). */
27
+ readonly escape: "escape";
28
+ };
29
+ /**
30
+ * Module-global allocation-site registry. One per `IrModule` compile, threaded
31
+ * through every pass invocation (see integration.ts). Not a per-function
32
+ * singleton — inlining merges functions, so ids must be module-stable.
33
+ */
34
+ export declare class AllocSiteRegistry {
35
+ /** index === AllocSiteId. */
36
+ private readonly sites;
37
+ /** metadata[id] = Map<namespace, value>. Sparse — created lazily. */
38
+ private readonly meta;
39
+ /** Mint a fresh, live allocation-site id. */
40
+ fresh(kind: AllocKind, type: IrType, origin?: IrSiteId): AllocSiteId;
41
+ /** True iff `id` indexes a known site (any state). */
42
+ isKnown(id: AllocSiteId): boolean;
43
+ /**
44
+ * Resolve through alias chains to the canonical live site, or `null` if the
45
+ * id is unknown, retired, or its chain terminates in a non-live entry. The
46
+ * `seen` guard makes a malformed cycle resolve to `null` rather than loop.
47
+ */
48
+ resolve(id: AllocSiteId): AllocSite | null;
49
+ /**
50
+ * Resolve `id` to the index of its canonical entry (following alias chains),
51
+ * or `null` on a broken/cyclic/unknown chain. Used internally so metadata
52
+ * writes after fusion land on the canonical site.
53
+ */
54
+ private canonicalIndex;
55
+ /**
56
+ * Record that `from` was fused into `to` (rule 2 — alias). Any metadata on
57
+ * `from` is merged onto the canonical site `to` (existing keys on `to` win,
58
+ * so a deliberate annotation is never clobbered by a fused-in default).
59
+ * No-op if either id is unknown.
60
+ */
61
+ alias(from: AllocSiteId, to: AllocSiteId): void;
62
+ /** Mark an allocation dead and removed (rule 3 — retire). No-op if unknown. */
63
+ retire(id: AllocSiteId): void;
64
+ /**
65
+ * Attach `value` under `ns` to the canonical site behind `id`. No-op if the
66
+ * id resolves to nothing live (retired/unknown/broken chain).
67
+ */
68
+ annotate<T>(id: AllocSiteId, ns: string, value: T): void;
69
+ /** Read the `ns` annotation on the canonical site behind `id`. */
70
+ read<T>(id: AllocSiteId, ns: string): T | undefined;
71
+ /** Number of sites ever minted (including aliased/retired). For diagnostics. */
72
+ get size(): number;
73
+ /** Snapshot of live sites — for debugging / tooling, not hot paths. */
74
+ liveSites(): AllocSite[];
75
+ }
@@ -0,0 +1,38 @@
1
+ import { AllocSiteRegistry } from '../alloc-registry.js';
2
+ import { IrFunction } from '../nodes.js';
3
+ /**
4
+ * Encoding lattice. Ordering (most → least restrictive):
5
+ * ascii ⊑ utf8-guaranteed ⊑ wtf16
6
+ * `wtf16` is top (the conservative default); `ascii` is bottom (the
7
+ * strongest claim). The join of two encodings is their least upper bound:
8
+ * any operand being `wtf16` forces `wtf16`; otherwise `utf8-guaranteed`
9
+ * unless both are `ascii`.
10
+ */
11
+ export type Encoding = "ascii" | "utf8-guaranteed" | "wtf16";
12
+ /** Least upper bound of two encodings (the conservative join). */
13
+ export declare function joinEncoding(a: Encoding, b: Encoding): Encoding;
14
+ /**
15
+ * Classify a statically known string literal by its code units.
16
+ * - all code units ≤ 0x7F → `ascii`
17
+ * - else, no lone surrogates → `utf8-guaranteed`
18
+ * - else (a lone surrogate present) → `wtf16`
19
+ *
20
+ * A surrogate is lone when a high surrogate (0xD800–0xDBFF) is not
21
+ * immediately followed by a low surrogate (0xDC00–0xDFFF), or a low
22
+ * surrogate appears without a preceding high surrogate. Such a string
23
+ * cannot be encoded as UTF-8, so it must stay `wtf16`.
24
+ */
25
+ export declare function classifyLiteral(value: string): Encoding;
26
+ /**
27
+ * Run the encoding analysis over a single IR function, writing `encoding`
28
+ * annotations onto the string allocation sites in `registry`. Read-only on
29
+ * the IR. Idempotent: re-running overwrites the same annotations with the
30
+ * same values.
31
+ *
32
+ * The analysis is a single forward pass. SSA dominance guarantees each
33
+ * value is defined before use within a block, and string values in Phase 1
34
+ * are produced and consumed locally (literals + concat), so a per-function
35
+ * value→encoding map filled in instruction order is sufficient. Values with
36
+ * no tracked origin are absent from the map and treated as `wtf16`.
37
+ */
38
+ export declare function analyzeEncoding(fn: IrFunction, registry: AllocSiteRegistry): void;
@@ -0,0 +1,32 @@
1
+ import { AllocSiteRegistry } from '../alloc-registry.js';
2
+ import { IrFunction, IrValueId } from '../nodes.js';
3
+ import { OwnershipResult } from './ownership.js';
4
+ /**
5
+ * How an allocation escapes its defining function. Ordered most-precise →
6
+ * most-conservative; `local` is the only stack-allocatable classification.
7
+ */
8
+ export type EscapeClass = "local" | "returned" | "stored" | "captured" | "opaque";
9
+ export interface EscapeInfo {
10
+ readonly classification: EscapeClass;
11
+ /** True iff `classification === "local"` — safe for scalar replacement. */
12
+ readonly stackAllocatable: boolean;
13
+ }
14
+ /** Per-function escape-analysis result, keyed by allocation result value. */
15
+ export declare class EscapeResult {
16
+ private readonly infos;
17
+ constructor(infos: ReadonlyMap<IrValueId, EscapeInfo>);
18
+ /** Escape info for an allocation value, or `undefined` if it is not an alloc. */
19
+ of(value: IrValueId): EscapeInfo | undefined;
20
+ classOf(value: IrValueId): EscapeClass | undefined;
21
+ /** Allocation values proven `local` — the stack-allocation candidates. */
22
+ localAllocations(): IrValueId[];
23
+ entries(): Iterable<[IrValueId, EscapeInfo]>;
24
+ }
25
+ /**
26
+ * Run escape analysis on `fn`. Uses the #1587 ownership result (computed fresh
27
+ * when not supplied) as the escape oracle, then walks the IR to attribute the
28
+ * strongest escape edge per allocation. When `registry` is supplied, each
29
+ * allocation's classification is written under the `escape` namespace keyed by
30
+ * the defining instr's alloc id.
31
+ */
32
+ export declare function analyzeEscape(fn: IrFunction, registry?: AllocSiteRegistry, precomputedOwnership?: OwnershipResult): EscapeResult;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Ownership state — a totally ordered lattice from most-precise (`owned`) to
3
+ * most-permissive (`escaped`). Higher = more conservative = safer default.
4
+ *
5
+ * owned ⊑ borrowed ⊑ shared ⊑ escaped
6
+ *
7
+ * - `owned` — exactly one live reference (this one) for its liveness.
8
+ * - `borrowed` — referenced elsewhere; this ref must not deallocate/invalidate.
9
+ * - `shared` — multiple references; mutation must be observable to all.
10
+ * - `escaped` — lifetime extends beyond this function (return, capture,
11
+ * store-to-heap, pass to opaque code).
12
+ */
13
+ export type Ownership = "owned" | "borrowed" | "shared" | "escaped";
14
+ /** Bottom of the ownership lattice — the most precise classification. */
15
+ export declare const OWNERSHIP_BOTTOM: Ownership;
16
+ /** Top of the ownership lattice — the conservative default. */
17
+ export declare const OWNERSHIP_TOP: Ownership;
18
+ /**
19
+ * Join (least upper bound) of two ownership states. Used at control-flow merge
20
+ * points and whenever an operation widens a value's classification: the result
21
+ * is the *more conservative* of the two. Commutative, associative, idempotent.
22
+ */
23
+ export declare function joinOwnership(a: Ownership, b: Ownership): Ownership;
24
+ /** True iff `a` is at least as precise as `b` (`a ⊑ b`). */
25
+ export declare function ownershipLeq(a: Ownership, b: Ownership): boolean;
26
+ /**
27
+ * Access operation — how a reference is used. The access lattice is the
28
+ * powerset of these tags ordered by ⊆; join is set union, bottom is `{}`, top
29
+ * is the full set. A value that escapes to opaque code conservatively widens
30
+ * to the full set (the callee may do anything).
31
+ */
32
+ export type AccessOp = "read" | "write" | "mutate" | "identity" | "escape";
33
+ /**
34
+ * An access set — a small immutable wrapper over `Set<AccessOp>` with union
35
+ * (join) and subset (⊑) operations. Kept as a class so the query API can hand
36
+ * consumers a value they cannot accidentally mutate.
37
+ */
38
+ export declare class AccessSet {
39
+ private readonly ops;
40
+ private constructor();
41
+ /** Bottom — no observed access. */
42
+ static empty(): AccessSet;
43
+ /** Top — the conservative full access set. */
44
+ static full(): AccessSet;
45
+ static of(...ops: readonly AccessOp[]): AccessSet;
46
+ has(op: AccessOp): boolean;
47
+ /** Join — set union. Returns `this` unchanged when `op` is already present. */
48
+ with(op: AccessOp): AccessSet;
49
+ /** Join — set union of two access sets. */
50
+ union(other: AccessSet): AccessSet;
51
+ /** True iff `this ⊆ other`. */
52
+ subsetOf(other: AccessSet): boolean;
53
+ equals(other: AccessSet): boolean;
54
+ /** Stable, sorted array view — for annotations, tests, and diagnostics. */
55
+ toArray(): AccessOp[];
56
+ }
57
+ /**
58
+ * The full classification the analysis attaches to a value. This is the shape
59
+ * stored in the registry `ownership` namespace and the parallel `ValueAnnot`
60
+ * map. Consumers must treat it as the analysis's *tightest provable* result
61
+ * and fall back to their conservative path when it is not tight enough — they
62
+ * may never assume a tighter classification than this carries (ADR-0014).
63
+ */
64
+ export interface OwnershipAnnotation {
65
+ readonly ownership: Ownership;
66
+ readonly access: AccessSet;
67
+ }
68
+ /** The conservative TOP annotation — used for anything not provably tighter. */
69
+ export declare function topAnnotation(): OwnershipAnnotation;
70
+ /** Join two annotations component-wise (used at CFG merges). */
71
+ export declare function joinAnnotations(a: OwnershipAnnotation, b: OwnershipAnnotation): OwnershipAnnotation;
72
+ export declare function annotationsEqual(a: OwnershipAnnotation, b: OwnershipAnnotation): boolean;
@@ -0,0 +1,31 @@
1
+ import { AllocSiteRegistry } from '../alloc-registry.js';
2
+ import { IrFunction, IrValueId } from '../nodes.js';
3
+ import { AccessSet, OwnershipAnnotation, Ownership } from './lattice.js';
4
+ /**
5
+ * The analysis result for one function. `of` returns the inferred annotation
6
+ * for any value; values the analysis never saw resolve to the conservative
7
+ * TOP, so consumers always get a correctness-preserving answer.
8
+ */
9
+ export declare class OwnershipResult {
10
+ private readonly annots;
11
+ /** Value -> the alloc id of the instr that defined it, when allocated. */
12
+ private readonly allocOf;
13
+ constructor(annots: ReadonlyMap<IrValueId, OwnershipAnnotation>,
14
+ /** Value -> the alloc id of the instr that defined it, when allocated. */
15
+ allocOf: ReadonlyMap<IrValueId, number>);
16
+ /** Inferred annotation for `value` — TOP if the value was never classified. */
17
+ of(value: IrValueId): OwnershipAnnotation;
18
+ ownershipOf(value: IrValueId): Ownership;
19
+ accessOf(value: IrValueId): AccessSet;
20
+ /** True iff `value` is a heap allocation proven `owned` and never `escaped`. */
21
+ isStackAllocatable(value: IrValueId): boolean;
22
+ /** All classified values — for diagnostics / tests. */
23
+ entries(): Iterable<[IrValueId, OwnershipAnnotation]>;
24
+ }
25
+ /**
26
+ * Run the analysis on `fn`. When `registry` is supplied, the result for each
27
+ * allocated value is also written under the `ownership` namespace keyed by the
28
+ * defining instr's alloc id (the durable cross-pass channel). The returned
29
+ * `OwnershipResult` is the in-function view keyed by `IrValueId`.
30
+ */
31
+ export declare function analyzeOwnership(fn: IrFunction, registry?: AllocSiteRegistry): OwnershipResult;
@@ -0,0 +1,20 @@
1
+ import { AllocSiteRegistry } from '../alloc-registry.js';
2
+ import { AllocKind, IrFunction } from '../nodes.js';
3
+ import { OwnershipResult } from './ownership.js';
4
+ /** A value-creating instr the analysis proved safe to stack-allocate. */
5
+ export interface StackAllocCandidate {
6
+ readonly allocId: number;
7
+ readonly kind: AllocKind;
8
+ }
9
+ /**
10
+ * Find stack-allocation candidates in `fn` using an ownership result (computed
11
+ * fresh when not supplied). A candidate is an allocation that is:
12
+ * - of a "small" kind (object / refcell / box — not array/closure/string),
13
+ * - proven `owned`, and
14
+ * - never `escaped`.
15
+ *
16
+ * When `registry` is supplied, each candidate's site is marked with a
17
+ * `stackCandidate: true` flag merged into its existing ownership annotation.
18
+ * The marker is inert at lowering — it changes no emitted Wasm.
19
+ */
20
+ export declare function findStackAllocCandidates(fn: IrFunction, registry?: AllocSiteRegistry, precomputed?: OwnershipResult): StackAllocCandidate[];
@@ -0,0 +1,237 @@
1
+ import { IrBinop, IrInstr, IrUnop } from '../nodes.js';
2
+ import { BlockType, Instr } from '../types.js';
3
+ import { BackendEmitter } from './emitter.js';
4
+ import { IrClassLowering, IrObjectStructLowering } from './handles.js';
5
+ export declare const OP: {
6
+ readonly CONST: 0;
7
+ readonly LOAD: 1;
8
+ readonly STORE: 2;
9
+ readonly ADD: 3;
10
+ readonly SUB: 4;
11
+ readonly MUL: 5;
12
+ readonly CMP_GT: 6;
13
+ readonly CMP_LT: 7;
14
+ readonly CMP_GE: 8;
15
+ readonly CMP_LE: 9;
16
+ readonly CMP_EQ: 10;
17
+ readonly NEG: 11;
18
+ readonly JZ: 12;
19
+ readonly JMP: 13;
20
+ readonly RET: 14;
21
+ readonly DIV: 15;
22
+ readonly CMP_NE: 16;
23
+ readonly TEE: 17;
24
+ readonly GLOBAL_GET: 18;
25
+ readonly GLOBAL_SET: 19;
26
+ readonly SELECT: 20;
27
+ readonly DROP: 21;
28
+ readonly UNREACHABLE: 22;
29
+ readonly CALL: 23;
30
+ readonly CALL_REF: 24;
31
+ readonly STRUCT_NEW: 25;
32
+ readonly STRUCT_GET: 26;
33
+ readonly STRUCT_SET: 27;
34
+ readonly JNZ: 28;
35
+ readonly THROW: 29;
36
+ readonly TRY_START: 30;
37
+ readonly TRY_END: 31;
38
+ };
39
+ export type Opcode = (typeof OP)[keyof typeof OP];
40
+ /**
41
+ * The bytecode equivalent of `BackendEmitter`'s `Instr[]` sink — the ONE seam
42
+ * generalisation #1715 required. A flat `code` opcode stream plus a side
43
+ * constant pool for f64 immediates. A label backpatch list lets `emitIf`
44
+ * forward-reference jump targets it does not yet know.
45
+ */
46
+ export declare class BytecodeSink {
47
+ readonly code: number[];
48
+ readonly constPool: number[];
49
+ /**
50
+ * (a3 #1584) Structured-branch backpatch list. A `br` / `br_if` (`emitBr` /
51
+ * `emitBrIf`) emits a `JMP` / `JNZ` placeholder whose target is the construct
52
+ * `depth` levels out (De Bruijn) — UNKNOWN until the enclosing `block`/`loop`
53
+ * splices this sink. Each entry pins the operand slot + its outward depth.
54
+ * `emitBlock`/`emitLoop` resolve depth-0 entries (this construct) and carry
55
+ * deeper ones outward (depth-1). A sink with a non-empty list at function exit
56
+ * is an internal error (a `br` with no enclosing construct).
57
+ */
58
+ readonly pendingBranches: {
59
+ slot: number;
60
+ depth: number;
61
+ }[];
62
+ /**
63
+ * (a4 #1584) Per-function exception table (table-scan model, §1c). One entry
64
+ * per `try` region: the protected code range `[tryStart, tryEnd)` (absolute
65
+ * code indices), the `catchTarget` THROW jumps to on a covered throw, and
66
+ * `spAtEntry` — the value-stack depth to truncate to on catch (always 0: a
67
+ * `try` is a statement-level node lowered at empty operand-stack depth).
68
+ * The VM scans this for the innermost covering entry on THROW; TRY_START/
69
+ * TRY_END are runtime no-ops (the table is authoritative). Travels with the
70
+ * function on its FuncEntry, alongside `code`/`constPool`.
71
+ */
72
+ readonly exceptionTable: {
73
+ tryStart: number;
74
+ tryEnd: number;
75
+ catchTarget: number;
76
+ spAtEntry: number;
77
+ }[];
78
+ /** Intern an f64 immediate into the constant pool, returning its index. */
79
+ internConst(value: number): number;
80
+ /** Current write position (a jump target / patch site is a code index). */
81
+ here(): number;
82
+ /** Emit an opcode followed by zero or more inline integer operands. */
83
+ emit(op: Opcode, ...operands: number[]): void;
84
+ /**
85
+ * Emit a jump whose target is not yet known; returns the code index of the
86
+ * *operand slot* to backpatch once the target is known.
87
+ */
88
+ emitJumpPlaceholder(op: typeof OP.JZ | typeof OP.JMP | typeof OP.JNZ | typeof OP.TRY_START): number;
89
+ /** Fill a previously-reserved jump operand slot with the resolved target. */
90
+ patch(slot: number, target: number): void;
91
+ /**
92
+ * (a3 #1584) Record a structured branch (`br`/`br_if`) whose target is the
93
+ * construct `depth` levels out. The placeholder jump was just emitted; `slot`
94
+ * is its operand index. Resolved by the enclosing `emitBlock`/`emitLoop`.
95
+ */
96
+ recordPendingBranch(slot: number, depth: number): void;
97
+ /**
98
+ * #1584: append another sink's code at the current position, relocating its
99
+ * internal jump targets into this sink's address space and remapping its
100
+ * const-pool indices into this sink's pool. Used by the production
101
+ * `BytecodeEmitter.emitIf` to splice already-lowered `if`-arm buffers (the
102
+ * real `lower.ts` builds each arm into its own sink, exactly as it builds the
103
+ * WasmGC `if`'s `then`/`else` as separate `Instr[]`).
104
+ *
105
+ * (a3) An arm may carry UNPATCHED structured branches (`br`/`br_if` in
106
+ * `pendingBranches`) bound for an enclosing `block`/`loop`. Those slots
107
+ * relocate by `+base` and their depth-tagged entries migrate onto THIS sink's
108
+ * `pendingBranches` so the enclosing construct can resolve them. A leftover
109
+ * unpatched jump that is NOT a recorded structured branch is still an internal
110
+ * error (a forward `if`/`block` exit the owner forgot to patch).
111
+ */
112
+ spliceArm(arm: BytecodeSink): void;
113
+ }
114
+ /**
115
+ * #1584 PRODUCTION emitter. Implements the {@link BackendEmitter}<{@link
116
+ * BytecodeSink}> trait surface so the REAL `lower.ts` drives it identically to
117
+ * how it drives {@link WasmGcEmitter}<Instr[]> — same primitive set, same
118
+ * caller-owns-operand-order contract, different execution model. (This
119
+ * supersedes the #1715 proof's hand-driven emitter: the proof's thunked
120
+ * `emitIf` is replaced by the trait's pre-built-arm `emitIf`, since real
121
+ * `lower.ts` builds each arm into its own sink then hands them over.)
122
+ *
123
+ * STACK encoding for the first increment (contract §1a staging note). The opcode
124
+ * set lives above (`OP`, the single source of truth the VM imports read-only);
125
+ * this class only decides which opcode each primitive emits.
126
+ */
127
+ export declare class BytecodeEmitter implements BackendEmitter<BytecodeSink> {
128
+ readonly backend: "bytecode";
129
+ /** Factory for a child sink — used by `lower.ts` to build `if`-arm buffers. */
130
+ newSink(): BytecodeSink;
131
+ /**
132
+ * The raw-`Instr` escape hatch (the #1584 contract §0a-1). `lower.ts` still
133
+ * has ~119 inline `out.push({op})` sites for op families not yet migrated
134
+ * behind the trait. On the WasmGC path those append to the `Instr[]`; on the
135
+ * bytecode path they reach a node family with no opcode realization yet, so
136
+ * this throws — surfacing the not-yet-migrated boundary loudly rather than
137
+ * silently mis-lowering. As each op family migrates (§2a), its `lower.ts`
138
+ * sites move from `pushRaw` to a typed emitter primitive + opcode.
139
+ */
140
+ pushRaw(_out: BytecodeSink, instr: Instr): void;
141
+ emitConst(instr: Extract<IrInstr, {
142
+ kind: "const";
143
+ }>, funcName: string, out: BytecodeSink): void;
144
+ emitBinary(op: IrBinop, out: BytecodeSink): void;
145
+ emitUnary(op: IrUnop, out: BytecodeSink): void;
146
+ emitLocalGet(index: number, out: BytecodeSink): void;
147
+ emitLocalSet(index: number, out: BytecodeSink): void;
148
+ emitLocalTee(index: number, out: BytecodeSink): void;
149
+ emitGlobalGet(index: number, out: BytecodeSink): void;
150
+ emitGlobalSet(index: number, out: BytecodeSink): void;
151
+ emitDrop(out: BytecodeSink): void;
152
+ emitSelect(out: BytecodeSink): void;
153
+ emitReturn(out: BytecodeSink): void;
154
+ emitUnreachable(out: BytecodeSink): void;
155
+ /**
156
+ * Structured two-arm conditional. Mirrors `WasmGcEmitter.emitIf(blockType,
157
+ * then: Instr[], els: Instr[], out)`: the caller (real `lower.ts`) pre-lowers
158
+ * each arm into its own {@link BytecodeSink} (via `newSink()`), then hands
159
+ * them here. The cond value is already on the stack. The stack VM has no
160
+ * structured block, so we lower to JZ/JMP + spliced arms with backpatched
161
+ * targets:
162
+ *
163
+ * <cond on stack>
164
+ * JZ elseLabel
165
+ * <then arm>
166
+ * JMP endLabel
167
+ * elseLabel: <else arm>
168
+ * endLabel:
169
+ *
170
+ * `blockType` is ignored (the bytecode VM is untyped over boxed values); it is
171
+ * part of the trait signature for the WasmGC realization.
172
+ */
173
+ emitIf(_blockType: BlockType, then: BytecodeSink, els: BytecodeSink, out: BytecodeSink): void;
174
+ emitBr(depth: number, out: BytecodeSink): void;
175
+ emitBrIf(depth: number, out: BytecodeSink): void;
176
+ /**
177
+ * Structured `block`. Splices the pre-lowered `body` sink at the current
178
+ * position, then resolves the body's pending structured branches: a branch
179
+ * with `depth === 0` targets THIS block, so it jumps to the block's EXIT (the
180
+ * code position just past the spliced body); deeper branches belong to an
181
+ * outer construct and migrate outward with `depth - 1`. `blockType` is ignored
182
+ * (the VM is untyped over boxed values) — it is part of the trait signature
183
+ * for the WasmGC realization.
184
+ */
185
+ emitBlock(_blockType: BlockType, body: BytecodeSink, out: BytecodeSink): void;
186
+ /**
187
+ * Structured `loop`. Like `emitBlock`, but a `depth === 0` branch targets the
188
+ * loop HEADER (the code position where the body begins) — `br 0` is "continue"
189
+ * — so the back-edge target is captured BEFORE the splice.
190
+ */
191
+ emitLoop(_blockType: BlockType, body: BytecodeSink, out: BytecodeSink): void;
192
+ /**
193
+ * Resolve the structured branches `spliceArm` just migrated onto `out`
194
+ * (`out.pendingBranches[firstNew..]`): patch each `depth === 0` branch to
195
+ * `selfTarget` (block exit / loop header) and drop it; decrement the depth of
196
+ * each deeper branch so the next-outer construct resolves it. Entries added
197
+ * before `firstNew` (already-pending outer branches) are untouched.
198
+ */
199
+ private resolveSplicedBranches;
200
+ emitCall(funcIdx: number, out: BytecodeSink): void;
201
+ emitCallRef(funcTypeIdx: number, out: BytecodeSink): void;
202
+ emitAggregateNew(_layout: IrObjectStructLowering, fieldCount: number, out: BytecodeSink): void;
203
+ emitFieldGet(layout: IrObjectStructLowering | IrClassLowering, name: string, out: BytecodeSink): void;
204
+ emitFieldSet(layout: IrObjectStructLowering | IrClassLowering, name: string, out: BytecodeSink): void;
205
+ emitThrow(_tagIdx: number, out: BytecodeSink): void;
206
+ emitRethrow(_depth: number, out: BytecodeSink): void;
207
+ /**
208
+ * Structured `try`. Table-scan realization:
209
+ *
210
+ * TRY_START <catchTarget> ; no-op marker
211
+ * <tryBody>
212
+ * TRY_END ; no-op marker (end of protected region)
213
+ * JMP endLabel ; normal exit skips the handler
214
+ * catchTarget: <handler> ; THROW lands here (VM pushed exn, truncated sp)
215
+ * endLabel:
216
+ *
217
+ * + an exceptionTable entry {tryStart, tryEnd, catchTarget, spAtEntry:0}.
218
+ * The protected region is [tryStart, tryEnd) = the spliced tryBody (between the
219
+ * markers). spAtEntry is 0: `try` is a statement-level node lowered at empty
220
+ * operand-stack depth, so on catch the VM truncates back to the empty base.
221
+ *
222
+ * Handler selection: our system has ONE exception tag (`__exn`), so a thrown
223
+ * value always matches a source `catch` if present; `catchAll` (emitted for
224
+ * the finally-leak path) is the handler only when there is no `catch`. With a
225
+ * single tag, `catchAll`-alongside-`catch` is the unreachable non-`__exn`
226
+ * leak path — we still splice it after the catch for structural fidelity, but
227
+ * `catchTarget` points at the live handler.
228
+ */
229
+ emitTry(_blockType: BlockType, body: BytecodeSink, catches: {
230
+ tagIdx: number;
231
+ body: BytecodeSink;
232
+ }[], catchAll: BytecodeSink | undefined, out: BytecodeSink): void;
233
+ emitVecLen(): void;
234
+ emitVecDataPtr(): void;
235
+ emitElemGet(): void;
236
+ emitVecNewFixed(): void;
237
+ }
@@ -0,0 +1,74 @@
1
+ import { BytecodeSink } from './bytecode-emitter.js';
2
+ /**
3
+ * One entry in a {@link Program}'s function table. A function lowers to its own
4
+ * {@link BytecodeSink} (own `code` + own `constPool` + own jump address-space),
5
+ * so a call switches BOTH `code` and `constPool` and the call frame restores
6
+ * both on return.
7
+ */
8
+ export interface FuncEntry {
9
+ /** The function's opcode stream (`sink.code`). */
10
+ code: number[];
11
+ /** The function's f64 immediate pool (`sink.constPool`). */
12
+ constPool: number[];
13
+ /** Declared parameter count — `CALL` pops this many args (arity not inline). */
14
+ arity: number;
15
+ /**
16
+ * Local-slot count (params + declared locals). A call installs a fresh
17
+ * `locals[nLocals]` seeded `locals[0..arity-1]` with the popped args; higher
18
+ * slots are lazily 0-init on first `LOAD` (same contract as `runBytecode`).
19
+ */
20
+ nLocals: number;
21
+ /**
22
+ * #1584 a4 try-throw: the STATIC per-function exception table (table-scan
23
+ * model). `THROW` scans it for the innermost entry whose `[tryStart, tryEnd)`
24
+ * covers the throwing pc, then truncates the value stack to `spAtEntry`, pushes
25
+ * the exn, and jumps to `catchTarget`. `TRY_START`/`TRY_END` are runtime
26
+ * no-ops (the table is authoritative). Array-of-objects with number-only
27
+ * fields (no `readonly`/nested-struct — same js2wasm-codegen accommodation as
28
+ * the FuncEntry array fields). `spAtEntry` is always 0 today (`try` is a
29
+ * statement-level node with an empty operand stack at entry), but it travels
30
+ * in the entry for correctness if a non-statement `try` ever appears.
31
+ */
32
+ exceptionTable: ExcEntry[];
33
+ }
34
+ /** One protected region in a {@link FuncEntry}'s {@link FuncEntry.exceptionTable}. */
35
+ export interface ExcEntry {
36
+ /** Absolute code index of the region start (inclusive). */
37
+ tryStart: number;
38
+ /** Absolute code index of the region end (exclusive). */
39
+ tryEnd: number;
40
+ /** Absolute code index of the catch arm to jump to on a covered throw. */
41
+ catchTarget: number;
42
+ /** Value-stack depth at try-entry; the stack is truncated to this on catch. */
43
+ spAtEntry: number;
44
+ }
45
+ /**
46
+ * A whole compiled program: a function table plus the entry function index.
47
+ * `runProgram` runs `functions[entry]` as the bottom frame.
48
+ */
49
+ export interface Program {
50
+ functions: FuncEntry[];
51
+ entry: number;
52
+ }
53
+ /**
54
+ * Run a whole {@link Program} — the multi-frame call-stack VM (#1584 a1).
55
+ *
56
+ * @param program function table + entry index
57
+ * @param args initial values of the entry function's locals 0..arity-1
58
+ * @returns the number the entry function's `RET` leaves on the stack
59
+ */
60
+ export declare function runProgram(program: Program, args: readonly number[]): number;
61
+ /**
62
+ * Run a single compiled bytecode function (the #1715 numeric proof entry).
63
+ * Implemented as a one-function {@link Program} so the single- and multi-frame
64
+ * paths share one dispatch loop.
65
+ *
66
+ * @param code flat opcode + inline-operand stream (`sink.code`)
67
+ * @param constPool f64 immediates referenced by `OP.CONST <poolIdx>` (`sink.constPool`)
68
+ * @param args initial values of locals 0..n-1 (the function parameters);
69
+ * any higher local index used by STORE/LOAD is lazily 0-init.
70
+ * @returns the number left on the stack by `OP.RET`
71
+ */
72
+ export declare function runBytecode(code: readonly number[], constPool: readonly number[], args: readonly number[]): number;
73
+ /** Convenience: run a {@link BytecodeSink}'s program as a single function. */
74
+ export declare function runSink(sink: BytecodeSink, args: readonly number[]): number;