@scriptc/compiler 0.0.0 → 0.0.2
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/LICENSE +202 -0
- package/ambient/package.json +3 -0
- package/ambient/scriptc-node-fallback.d.ts +3001 -0
- package/ambient/scriptc-overrides.d.ts +95 -0
- package/ambient/scriptc.d.ts +74 -0
- package/dist/backend/cc.d.ts +169 -0
- package/dist/backend/cc.js +897 -0
- package/dist/backend/cc.js.map +1 -0
- package/dist/backend/emission/emit-async.d.ts +145 -0
- package/dist/backend/emission/emit-async.js +996 -0
- package/dist/backend/emission/emit-async.js.map +1 -0
- package/dist/backend/emission/emit-exprs.d.ts +3 -0
- package/dist/backend/emission/emit-exprs.js +5949 -0
- package/dist/backend/emission/emit-exprs.js.map +1 -0
- package/dist/backend/emission/emit-island.d.ts +45 -0
- package/dist/backend/emission/emit-island.js +271 -0
- package/dist/backend/emission/emit-island.js.map +1 -0
- package/dist/backend/emission/emit-shapes.d.ts +142 -0
- package/dist/backend/emission/emit-shapes.js +575 -0
- package/dist/backend/emission/emit-shapes.js.map +1 -0
- package/dist/backend/emission/emit-stmts.d.ts +78 -0
- package/dist/backend/emission/emit-stmts.js +960 -0
- package/dist/backend/emission/emit-stmts.js.map +1 -0
- package/dist/backend/emission/emit-types.d.ts +65 -0
- package/dist/backend/emission/emit-types.js +652 -0
- package/dist/backend/emission/emit-types.js.map +1 -0
- package/dist/backend/emission/emit-walkers.d.ts +154 -0
- package/dist/backend/emission/emit-walkers.js +1587 -0
- package/dist/backend/emission/emit-walkers.js.map +1 -0
- package/dist/backend/emission/emitter.d.ts +452 -0
- package/dist/backend/emission/emitter.js +1249 -0
- package/dist/backend/emission/emitter.js.map +1 -0
- package/dist/backend/emission/may-throw.d.ts +15 -0
- package/dist/backend/emission/may-throw.js +250 -0
- package/dist/backend/emission/may-throw.js.map +1 -0
- package/dist/backend/llvm/blocks.d.ts +21 -0
- package/dist/backend/llvm/blocks.js +68 -0
- package/dist/backend/llvm/blocks.js.map +1 -0
- package/dist/backend/llvm/classes.d.ts +84 -0
- package/dist/backend/llvm/classes.js +438 -0
- package/dist/backend/llvm/classes.js.map +1 -0
- package/dist/backend/llvm/dyn.d.ts +123 -0
- package/dist/backend/llvm/dyn.js +2624 -0
- package/dist/backend/llvm/dyn.js.map +1 -0
- package/dist/backend/llvm/emitter.d.ts +3 -0
- package/dist/backend/llvm/emitter.js +10102 -0
- package/dist/backend/llvm/emitter.js.map +1 -0
- package/dist/backend/llvm/shapes.d.ts +78 -0
- package/dist/backend/llvm/shapes.js +754 -0
- package/dist/backend/llvm/shapes.js.map +1 -0
- package/dist/backend/llvm/unsupported.d.ts +6 -0
- package/dist/backend/llvm/unsupported.js +12 -0
- package/dist/backend/llvm/unsupported.js.map +1 -0
- package/dist/backend/llvm/walkers.d.ts +58 -0
- package/dist/backend/llvm/walkers.js +793 -0
- package/dist/backend/llvm/walkers.js.map +1 -0
- package/dist/backend/mangle.d.ts +124 -0
- package/dist/backend/mangle.js +232 -0
- package/dist/backend/mangle.js.map +1 -0
- package/dist/coverage/report.d.ts +65 -0
- package/dist/coverage/report.js +238 -0
- package/dist/coverage/report.js.map +1 -0
- package/dist/diagnostics/diagnostic.d.ts +140 -0
- package/dist/diagnostics/diagnostic.js +458 -0
- package/dist/diagnostics/diagnostic.js.map +1 -0
- package/dist/diagnostics/render.d.ts +11 -0
- package/dist/diagnostics/render.js +58 -0
- package/dist/diagnostics/render.js.map +1 -0
- package/dist/frontend/cjs-lexer.d.ts +20 -0
- package/dist/frontend/cjs-lexer.js +813 -0
- package/dist/frontend/cjs-lexer.js.map +1 -0
- package/dist/frontend/lowering/http2-constants.d.ts +1 -0
- package/dist/frontend/lowering/http2-constants.js +251 -0
- package/dist/frontend/lowering/http2-constants.js.map +1 -0
- package/dist/frontend/lowering/lib-boundary.d.ts +6 -0
- package/dist/frontend/lowering/lib-boundary.js +143 -0
- package/dist/frontend/lowering/lib-boundary.js.map +1 -0
- package/dist/frontend/lowering/lower-assert.d.ts +18 -0
- package/dist/frontend/lowering/lower-assert.js +1269 -0
- package/dist/frontend/lowering/lower-assert.js.map +1 -0
- package/dist/frontend/lowering/lower-builtins.d.ts +511 -0
- package/dist/frontend/lowering/lower-builtins.js +5249 -0
- package/dist/frontend/lowering/lower-builtins.js.map +1 -0
- package/dist/frontend/lowering/lower-calls.d.ts +581 -0
- package/dist/frontend/lowering/lower-calls.js +6286 -0
- package/dist/frontend/lowering/lower-calls.js.map +1 -0
- package/dist/frontend/lowering/lower-classes.d.ts +727 -0
- package/dist/frontend/lowering/lower-classes.js +4701 -0
- package/dist/frontend/lowering/lower-classes.js.map +1 -0
- package/dist/frontend/lowering/lower-comptime.d.ts +53 -0
- package/dist/frontend/lowering/lower-comptime.js +244 -0
- package/dist/frontend/lowering/lower-comptime.js.map +1 -0
- package/dist/frontend/lowering/lower-containers.d.ts +486 -0
- package/dist/frontend/lowering/lower-containers.js +6345 -0
- package/dist/frontend/lowering/lower-containers.js.map +1 -0
- package/dist/frontend/lowering/lower-dgram.d.ts +20 -0
- package/dist/frontend/lowering/lower-dgram.js +319 -0
- package/dist/frontend/lowering/lower-dgram.js.map +1 -0
- package/dist/frontend/lowering/lower-emitter.d.ts +10 -0
- package/dist/frontend/lowering/lower-emitter.js +688 -0
- package/dist/frontend/lowering/lower-emitter.js.map +1 -0
- package/dist/frontend/lowering/lower-enums.d.ts +22 -0
- package/dist/frontend/lowering/lower-enums.js +235 -0
- package/dist/frontend/lowering/lower-enums.js.map +1 -0
- package/dist/frontend/lowering/lower-expando.d.ts +35 -0
- package/dist/frontend/lowering/lower-expando.js +276 -0
- package/dist/frontend/lowering/lower-expando.js.map +1 -0
- package/dist/frontend/lowering/lower-exprs.d.ts +524 -0
- package/dist/frontend/lowering/lower-exprs.js +8111 -0
- package/dist/frontend/lowering/lower-exprs.js.map +1 -0
- package/dist/frontend/lowering/lower-generators.d.ts +50 -0
- package/dist/frontend/lowering/lower-generators.js +421 -0
- package/dist/frontend/lowering/lower-generators.js.map +1 -0
- package/dist/frontend/lowering/lower-inspect.d.ts +20 -0
- package/dist/frontend/lowering/lower-inspect.js +1074 -0
- package/dist/frontend/lowering/lower-inspect.js.map +1 -0
- package/dist/frontend/lowering/lower-island.d.ts +108 -0
- package/dist/frontend/lowering/lower-island.js +650 -0
- package/dist/frontend/lowering/lower-island.js.map +1 -0
- package/dist/frontend/lowering/lower-mixins.d.ts +96 -0
- package/dist/frontend/lowering/lower-mixins.js +534 -0
- package/dist/frontend/lowering/lower-mixins.js.map +1 -0
- package/dist/frontend/lowering/lower-modules.d.ts +135 -0
- package/dist/frontend/lowering/lower-modules.js +1613 -0
- package/dist/frontend/lowering/lower-modules.js.map +1 -0
- package/dist/frontend/lowering/lower-namespaces.d.ts +168 -0
- package/dist/frontend/lowering/lower-namespaces.js +706 -0
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -0
- package/dist/frontend/lowering/lower-server.d.ts +90 -0
- package/dist/frontend/lowering/lower-server.js +3471 -0
- package/dist/frontend/lowering/lower-server.js.map +1 -0
- package/dist/frontend/lowering/lower-stmts.d.ts +361 -0
- package/dist/frontend/lowering/lower-stmts.js +5341 -0
- package/dist/frontend/lowering/lower-stmts.js.map +1 -0
- package/dist/frontend/lowering/lower-stream.d.ts +88 -0
- package/dist/frontend/lowering/lower-stream.js +1533 -0
- package/dist/frontend/lowering/lower-stream.js.map +1 -0
- package/dist/frontend/lowering/lower-test.d.ts +27 -0
- package/dist/frontend/lowering/lower-test.js +353 -0
- package/dist/frontend/lowering/lower-test.js.map +1 -0
- package/dist/frontend/lowering/lowerer.d.ts +1748 -0
- package/dist/frontend/lowering/lowerer.js +6257 -0
- package/dist/frontend/lowering/lowerer.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +272 -0
- package/dist/frontend/lowering/surfaces.js +1096 -0
- package/dist/frontend/lowering/surfaces.js.map +1 -0
- package/dist/frontend/npm-static.d.ts +55 -0
- package/dist/frontend/npm-static.js +300 -0
- package/dist/frontend/npm-static.js.map +1 -0
- package/dist/frontend/npm.d.ts +330 -0
- package/dist/frontend/npm.js +1259 -0
- package/dist/frontend/npm.js.map +1 -0
- package/dist/frontend/program.d.ts +186 -0
- package/dist/frontend/program.js +2255 -0
- package/dist/frontend/program.js.map +1 -0
- package/dist/frontend/provenance-registry.d.ts +48 -0
- package/dist/frontend/provenance-registry.js +87 -0
- package/dist/frontend/provenance-registry.js.map +1 -0
- package/dist/frontend/provenance.d.ts +6 -0
- package/dist/frontend/provenance.js +459 -0
- package/dist/frontend/provenance.js.map +1 -0
- package/dist/frontend/resolve.d.ts +56 -0
- package/dist/frontend/resolve.js +682 -0
- package/dist/frontend/resolve.js.map +1 -0
- package/dist/frontend/shared.d.ts +67 -0
- package/dist/frontend/shared.js +241 -0
- package/dist/frontend/shared.js.map +1 -0
- package/dist/frontend/ts7/adapter.d.ts +7 -0
- package/dist/frontend/ts7/adapter.js +54 -0
- package/dist/frontend/ts7/adapter.js.map +1 -0
- package/dist/frontend/ts7/ast.d.ts +50 -0
- package/dist/frontend/ts7/ast.js +211 -0
- package/dist/frontend/ts7/ast.js.map +1 -0
- package/dist/frontend/ts7/census-check.d.ts +1 -0
- package/dist/frontend/ts7/census-check.js +12 -0
- package/dist/frontend/ts7/census-check.js.map +1 -0
- package/dist/frontend/ts7/checker.d.ts +140 -0
- package/dist/frontend/ts7/checker.js +544 -0
- package/dist/frontend/ts7/checker.js.map +1 -0
- package/dist/frontend/ts7/enums.d.ts +18 -0
- package/dist/frontend/ts7/enums.js +43 -0
- package/dist/frontend/ts7/enums.js.map +1 -0
- package/dist/frontend/ts7/program.d.ts +99 -0
- package/dist/frontend/ts7/program.js +278 -0
- package/dist/frontend/ts7/program.js.map +1 -0
- package/dist/frontend/ts7/world-check.d.ts +3 -0
- package/dist/frontend/ts7/world-check.js +34 -0
- package/dist/frontend/ts7/world-check.js.map +1 -0
- package/dist/frontend/types.d.ts +205 -0
- package/dist/frontend/types.js +2485 -0
- package/dist/frontend/types.js.map +1 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +429 -0
- package/dist/index.js.map +1 -0
- package/dist/ir/nodes.d.ts +4334 -0
- package/dist/ir/nodes.js +1906 -0
- package/dist/ir/nodes.js.map +1 -0
- package/dist/ir/serialize.d.ts +4 -0
- package/dist/ir/serialize.js +34 -0
- package/dist/ir/serialize.js.map +1 -0
- package/dist/ir/validate.d.ts +36 -0
- package/dist/ir/validate.js +4885 -0
- package/dist/ir/validate.js.map +1 -0
- package/package.json +30 -6
- package/README.md +0 -3
- package/index.js +0 -2
|
@@ -0,0 +1,754 @@
|
|
|
1
|
+
import { funcOf, isRefCounted, mapOf, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, STRING, VOID } from "../../ir/nodes.js";
|
|
2
|
+
import { mangleClassRelease, mangleClassRetain, mangleClassTrace, mangleRecordGcFree, mangleRecordNew, mangleRecordRelease, mangleRecordRetain, mangleRecordStruct, mangleRecordTrace, } from "../mangle.js";
|
|
3
|
+
import { LlvmUnsupportedError } from "./unsupported.js";
|
|
4
|
+
/** Every emitted function/helper carries #0 = { sanitize_address } — see
|
|
5
|
+
* the emitter header. */
|
|
6
|
+
export const FN_ATTRS = "#0";
|
|
7
|
+
/* ── cycle capability (the CEmitter constructor's fixpoint, ported) ────
|
|
8
|
+
* Greatest fixpoint over shapes and unions: start optimistic (everything
|
|
9
|
+
* cycle-capable), repeatedly drop shapes with no cycle-capable field and
|
|
10
|
+
* unions with no cycle-capable arm until stable. Closures and promises
|
|
11
|
+
* are always cycle-capable; strings never are; arrays/maps inherit their
|
|
12
|
+
* element/value type's capability. A HIERARCHY is one unit of capability
|
|
13
|
+
* (a base-typed slot can hold any subclass and retain touches the cycle
|
|
14
|
+
* header, so header presence must be uniform across an extends tree): a
|
|
15
|
+
* unit is cycle-capable iff ANY member is — CEmitter's unit grouping,
|
|
16
|
+
* ported. */
|
|
17
|
+
export function computeTraced(mod) {
|
|
18
|
+
const tracedShapes = new Set();
|
|
19
|
+
const tracedUnions = new Set();
|
|
20
|
+
const classes = mod.classes ?? [];
|
|
21
|
+
const shapeDefs = [
|
|
22
|
+
...classes.map((c) => ({
|
|
23
|
+
key: `object:${c.name}`,
|
|
24
|
+
fields: c.name === RUNTIME_EMITTER_CLASS
|
|
25
|
+
? [...c.fields, { name: "<listeners>", type: funcOf([], VOID) }]
|
|
26
|
+
: c.fields,
|
|
27
|
+
})),
|
|
28
|
+
...(mod.records ?? []).map((r) => ({
|
|
29
|
+
key: `record:${r.id}`,
|
|
30
|
+
fields: r.indexValue
|
|
31
|
+
? [...r.fields, { name: "<overflow>", type: mapOf(STRING, r.indexValue) }]
|
|
32
|
+
: r.fields,
|
|
33
|
+
})),
|
|
34
|
+
];
|
|
35
|
+
for (const s of shapeDefs)
|
|
36
|
+
tracedShapes.add(s.key);
|
|
37
|
+
for (const u of mod.unions ?? [])
|
|
38
|
+
tracedUnions.add(u.id);
|
|
39
|
+
// Hierarchy units: root lookup over the base links (classes with a base
|
|
40
|
+
// or a subclass — and the runtime emitter class — form units under their
|
|
41
|
+
// root; standalone classes and records stay singleton units).
|
|
42
|
+
const baseOf = new Map(classes.map((c) => [c.name, c.base ?? null]));
|
|
43
|
+
const hasChildren = new Set(classes.map((c) => c.base).filter((b) => b !== undefined));
|
|
44
|
+
const rootOf = (name) => {
|
|
45
|
+
let cur = name;
|
|
46
|
+
for (let b = baseOf.get(cur); b !== null && b !== undefined; b = baseOf.get(cur))
|
|
47
|
+
cur = b;
|
|
48
|
+
return cur;
|
|
49
|
+
};
|
|
50
|
+
const unitKeyOf = (key) => {
|
|
51
|
+
if (!key.startsWith("object:"))
|
|
52
|
+
return key;
|
|
53
|
+
const name = key.slice("object:".length);
|
|
54
|
+
const inHierarchy = typeof baseOf.get(name) === "string" || hasChildren.has(name) || name === RUNTIME_EMITTER_CLASS;
|
|
55
|
+
return inHierarchy ? `object:${rootOf(name)}` : key;
|
|
56
|
+
};
|
|
57
|
+
const units = new Map();
|
|
58
|
+
for (const s of shapeDefs) {
|
|
59
|
+
const unit = unitKeyOf(s.key);
|
|
60
|
+
let members = units.get(unit);
|
|
61
|
+
if (!members)
|
|
62
|
+
units.set(unit, (members = []));
|
|
63
|
+
members.push(s);
|
|
64
|
+
}
|
|
65
|
+
const cycleCapable = (t) => {
|
|
66
|
+
switch (t.kind) {
|
|
67
|
+
case "func":
|
|
68
|
+
case "promise":
|
|
69
|
+
return true;
|
|
70
|
+
case "object":
|
|
71
|
+
return tracedShapes.has(`object:${t.className}`);
|
|
72
|
+
case "record":
|
|
73
|
+
return tracedShapes.has(`record:${t.shapeId}`);
|
|
74
|
+
case "union":
|
|
75
|
+
return tracedUnions.has(t.unionId);
|
|
76
|
+
case "map":
|
|
77
|
+
return cycleCapable(t.value);
|
|
78
|
+
case "array":
|
|
79
|
+
return cycleCapable(t.elem);
|
|
80
|
+
default:
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
let shrunk = true;
|
|
85
|
+
while (shrunk) {
|
|
86
|
+
shrunk = false;
|
|
87
|
+
for (const members of units.values()) {
|
|
88
|
+
if (tracedShapes.has(members[0].key) &&
|
|
89
|
+
!members.some((s) => s.fields.some((f) => cycleCapable(f.type)))) {
|
|
90
|
+
for (const s of members)
|
|
91
|
+
tracedShapes.delete(s.key);
|
|
92
|
+
shrunk = true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const u of mod.unions ?? []) {
|
|
96
|
+
if (tracedUnions.has(u.id) && !u.arms.some(cycleCapable)) {
|
|
97
|
+
tracedUnions.delete(u.id);
|
|
98
|
+
shrunk = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return { shapes: tracedShapes, unions: tracedUnions };
|
|
103
|
+
}
|
|
104
|
+
/* ── RC dispatch ──────────────────────────────────────────────────────── */
|
|
105
|
+
/** The runtime's `_v` (ptr → ptr / ptr → void) RC entry points for one
|
|
106
|
+
* refcounted type — used both as the CALL targets of the LLVM tier's
|
|
107
|
+
* retain/release (everything is `ptr` here, so the `_v` shape IS the
|
|
108
|
+
* direct shape) and as the function-pointer arguments of every container
|
|
109
|
+
* construction (unions, ref arrays, obj boxes, overflow maps). Records
|
|
110
|
+
* use their emitted per-shape helpers, whose signatures are already
|
|
111
|
+
* `_v`-shaped. */
|
|
112
|
+
export function vAdapters(host, t) {
|
|
113
|
+
switch (t.kind) {
|
|
114
|
+
case "caught":
|
|
115
|
+
// Catch-binding snapshot boxes (ScrCaught): the runtime pair is
|
|
116
|
+
// already `_v`-shaped. Caught values never enter containers — these
|
|
117
|
+
// arms serve retainSym/releaseSym only.
|
|
118
|
+
host.declare(`declare ptr @scr_caught_retain(ptr)`);
|
|
119
|
+
host.declare(`declare void @scr_caught_release(ptr)`);
|
|
120
|
+
return { retain: "@scr_caught_retain", release: "@scr_caught_release" };
|
|
121
|
+
case "string":
|
|
122
|
+
host.declare(`declare ptr @scr_str_retain_v(ptr)`);
|
|
123
|
+
host.declare(`declare void @scr_str_release_v(ptr)`);
|
|
124
|
+
return { retain: "@scr_str_retain_v", release: "@scr_str_release_v" };
|
|
125
|
+
case "array":
|
|
126
|
+
host.declare(`declare ptr @scr_arr_retain_v(ptr)`);
|
|
127
|
+
host.declare(`declare void @scr_arr_release_v(ptr)`);
|
|
128
|
+
return { retain: "@scr_arr_retain_v", release: "@scr_arr_release_v" };
|
|
129
|
+
case "map":
|
|
130
|
+
case "set":
|
|
131
|
+
host.declare(`declare ptr @scr_map_retain_v(ptr)`);
|
|
132
|
+
host.declare(`declare void @scr_map_release_v(ptr)`);
|
|
133
|
+
return { retain: "@scr_map_retain_v", release: "@scr_map_release_v" };
|
|
134
|
+
case "union":
|
|
135
|
+
host.declare(`declare ptr @scr_union_retain_v(ptr)`);
|
|
136
|
+
host.declare(`declare void @scr_union_release_v(ptr)`);
|
|
137
|
+
return { retain: "@scr_union_retain_v", release: "@scr_union_release_v" };
|
|
138
|
+
case "promise":
|
|
139
|
+
host.declare(`declare ptr @scr_promise_retain_v(ptr)`);
|
|
140
|
+
host.declare(`declare void @scr_promise_release_v(ptr)`);
|
|
141
|
+
return { retain: "@scr_promise_retain_v", release: "@scr_promise_release_v" };
|
|
142
|
+
case "bytes":
|
|
143
|
+
host.declare(`declare ptr @scr_bytes_retain_v(ptr)`);
|
|
144
|
+
host.declare(`declare void @scr_bytes_release_v(ptr)`);
|
|
145
|
+
return { retain: "@scr_bytes_retain_v", release: "@scr_bytes_release_v" };
|
|
146
|
+
case "url":
|
|
147
|
+
host.declare(`declare ptr @scr_url_retain_v(ptr)`);
|
|
148
|
+
host.declare(`declare void @scr_url_release_v(ptr)`);
|
|
149
|
+
return { retain: "@scr_url_retain_v", release: "@scr_url_release_v" };
|
|
150
|
+
case "searchParams":
|
|
151
|
+
host.declare(`declare ptr @scr_sp_retain_v(ptr)`);
|
|
152
|
+
host.declare(`declare void @scr_sp_release_v(ptr)`);
|
|
153
|
+
return { retain: "@scr_sp_retain_v", release: "@scr_sp_release_v" };
|
|
154
|
+
case "stats":
|
|
155
|
+
host.declare(`declare ptr @scr_stats_retain_v(ptr)`);
|
|
156
|
+
host.declare(`declare void @scr_stats_release_v(ptr)`);
|
|
157
|
+
return { retain: "@scr_stats_retain_v", release: "@scr_stats_release_v" };
|
|
158
|
+
case "spawnRes":
|
|
159
|
+
host.declare(`declare ptr @scr_spawn_res_retain_v(ptr)`);
|
|
160
|
+
host.declare(`declare void @scr_spawn_res_release_v(ptr)`);
|
|
161
|
+
return { retain: "@scr_spawn_res_retain_v", release: "@scr_spawn_res_release_v" };
|
|
162
|
+
case "child":
|
|
163
|
+
host.declare(`declare ptr @scr_child_retain_v(ptr)`);
|
|
164
|
+
host.declare(`declare void @scr_child_release_v(ptr)`);
|
|
165
|
+
return { retain: "@scr_child_retain_v", release: "@scr_child_release_v" };
|
|
166
|
+
case "childStream":
|
|
167
|
+
host.declare(`declare ptr @scr_child_stream_retain_v(ptr)`);
|
|
168
|
+
host.declare(`declare void @scr_child_stream_release_v(ptr)`);
|
|
169
|
+
return { retain: "@scr_child_stream_retain_v", release: "@scr_child_stream_release_v" };
|
|
170
|
+
case "generator":
|
|
171
|
+
host.declare(`declare ptr @scr_gen_retain_v(ptr)`);
|
|
172
|
+
host.declare(`declare void @scr_gen_release_v(ptr)`);
|
|
173
|
+
return { retain: "@scr_gen_retain_v", release: "@scr_gen_release_v" };
|
|
174
|
+
case "func":
|
|
175
|
+
host.declare(`declare ptr @scr_closure_retain_v(ptr)`);
|
|
176
|
+
host.declare(`declare void @scr_closure_release_v(ptr)`);
|
|
177
|
+
return { retain: "@scr_closure_retain_v", release: "@scr_closure_release_v" };
|
|
178
|
+
case "symbol":
|
|
179
|
+
host.declare(`declare ptr @scr_sym_retain_v(ptr)`);
|
|
180
|
+
host.declare(`declare void @scr_sym_release_v(ptr)`);
|
|
181
|
+
return { retain: "@scr_sym_retain_v", release: "@scr_sym_release_v" };
|
|
182
|
+
case "regex":
|
|
183
|
+
host.declare(`declare ptr @scr_regex_retain_v(ptr)`);
|
|
184
|
+
host.declare(`declare void @scr_regex_release_v(ptr)`);
|
|
185
|
+
return { retain: "@scr_regex_retain_v", release: "@scr_regex_release_v" };
|
|
186
|
+
case "record":
|
|
187
|
+
return { retain: `@${mangleRecordRetain(t.shapeId)}`, release: `@${mangleRecordRelease(t.shapeId)}` };
|
|
188
|
+
case "object":
|
|
189
|
+
if (RUNTIME_ERROR_CLASSES.has(t.className)) {
|
|
190
|
+
host.declare(`declare ptr @scr_error_retain_v(ptr)`);
|
|
191
|
+
host.declare(`declare void @scr_error_release_v(ptr)`);
|
|
192
|
+
return { retain: "@scr_error_retain_v", release: "@scr_error_release_v" };
|
|
193
|
+
}
|
|
194
|
+
if (t.className === RUNTIME_EMITTER_CLASS) {
|
|
195
|
+
// Bare EventEmitter instances: the runtime's `_v` pair (release
|
|
196
|
+
// dispatches through the stamped vtable, so a base-typed release
|
|
197
|
+
// tears down a user subclass too).
|
|
198
|
+
host.declare(`declare ptr @scr_emitter_retain_v(ptr)`);
|
|
199
|
+
host.declare(`declare void @scr_emitter_release_v(ptr)`);
|
|
200
|
+
return { retain: "@scr_emitter_retain_v", release: "@scr_emitter_release_v" };
|
|
201
|
+
}
|
|
202
|
+
if (RUNTIME_STREAM_CLASSES.has(t.className)) {
|
|
203
|
+
// The five runtime stream classes share ONE runtime layout; the
|
|
204
|
+
// `_v` pair dispatches teardown through the stamped vtable.
|
|
205
|
+
host.declare(`declare ptr @scr_stream_retain_v(ptr)`);
|
|
206
|
+
host.declare(`declare void @scr_stream_release_v(ptr)`);
|
|
207
|
+
return { retain: "@scr_stream_retain_v", release: "@scr_stream_release_v" };
|
|
208
|
+
}
|
|
209
|
+
// Emitted per-class helpers are already `_v`-shaped (ptr → ptr /
|
|
210
|
+
// ptr → void), so the same symbols serve as container entry points.
|
|
211
|
+
return { retain: `@${mangleClassRetain(t.className)}`, release: `@${mangleClassRelease(t.className)}` };
|
|
212
|
+
case "classval":
|
|
213
|
+
// No-ops on the immortal class object; container machinery uniform.
|
|
214
|
+
host.declare(`declare ptr @scr_classobj_retain_v(ptr)`);
|
|
215
|
+
host.declare(`declare void @scr_classobj_release_v(ptr)`);
|
|
216
|
+
return { retain: "@scr_classobj_retain_v", release: "@scr_classobj_release_v" };
|
|
217
|
+
case "fsWatcher":
|
|
218
|
+
// fs.watch handles (ScrWatcher): the runtime's `_v` pair; no trace
|
|
219
|
+
// (listeners drop at close — never part of a lasting cycle).
|
|
220
|
+
host.declare(`declare ptr @scr_watcher_retain_v(ptr)`);
|
|
221
|
+
host.declare(`declare void @scr_watcher_release_v(ptr)`);
|
|
222
|
+
return { retain: "@scr_watcher_retain_v", release: "@scr_watcher_release_v" };
|
|
223
|
+
case "netServer":
|
|
224
|
+
host.declare(`declare ptr @scr_net_server_retain_v(ptr)`);
|
|
225
|
+
host.declare(`declare void @scr_net_server_release_v(ptr)`);
|
|
226
|
+
return { retain: "@scr_net_server_retain_v", release: "@scr_net_server_release_v" };
|
|
227
|
+
case "netSocket":
|
|
228
|
+
host.declare(`declare ptr @scr_net_sock_retain_v(ptr)`);
|
|
229
|
+
host.declare(`declare void @scr_net_sock_release_v(ptr)`);
|
|
230
|
+
return { retain: "@scr_net_sock_retain_v", release: "@scr_net_sock_release_v" };
|
|
231
|
+
case "dgramSocket":
|
|
232
|
+
host.declare(`declare ptr @scr_dgram_retain_v(ptr)`);
|
|
233
|
+
host.declare(`declare void @scr_dgram_release_v(ptr)`);
|
|
234
|
+
return { retain: "@scr_dgram_retain_v", release: "@scr_dgram_release_v" };
|
|
235
|
+
case "httpReq":
|
|
236
|
+
host.declare(`declare ptr @scr_http_req_retain_v(ptr)`);
|
|
237
|
+
host.declare(`declare void @scr_http_req_release_v(ptr)`);
|
|
238
|
+
return { retain: "@scr_http_req_retain_v", release: "@scr_http_req_release_v" };
|
|
239
|
+
case "httpRes":
|
|
240
|
+
host.declare(`declare ptr @scr_http_res_retain_v(ptr)`);
|
|
241
|
+
host.declare(`declare void @scr_http_res_release_v(ptr)`);
|
|
242
|
+
return { retain: "@scr_http_res_retain_v", release: "@scr_http_res_release_v" };
|
|
243
|
+
case "httpClientReq":
|
|
244
|
+
host.declare(`declare ptr @scr_http_client_retain_v(ptr)`);
|
|
245
|
+
host.declare(`declare void @scr_http_client_release_v(ptr)`);
|
|
246
|
+
return { retain: "@scr_http_client_retain_v", release: "@scr_http_client_release_v" };
|
|
247
|
+
case "secureCtx":
|
|
248
|
+
host.declare(`declare ptr @scr_secure_ctx_retain_v(ptr)`);
|
|
249
|
+
host.declare(`declare void @scr_secure_ctx_release_v(ptr)`);
|
|
250
|
+
return { retain: "@scr_secure_ctx_retain_v", release: "@scr_secure_ctx_release_v" };
|
|
251
|
+
case "testCtx":
|
|
252
|
+
host.declare(`declare ptr @scr_testctx_retain_v(ptr)`);
|
|
253
|
+
host.declare(`declare void @scr_testctx_release_v(ptr)`);
|
|
254
|
+
return { retain: "@scr_testctx_retain_v", release: "@scr_testctx_release_v" };
|
|
255
|
+
case "jsval":
|
|
256
|
+
// Island handles (the --dynamic engine boundary): the runtime's
|
|
257
|
+
// `_v` pair; UNTRACED (engine values never join static cycles).
|
|
258
|
+
host.declare(`declare ptr @scr_jsval_retain_v(ptr)`);
|
|
259
|
+
host.declare(`declare void @scr_jsval_release_v(ptr)`);
|
|
260
|
+
return { retain: "@scr_jsval_retain_v", release: "@scr_jsval_release_v" };
|
|
261
|
+
case "dyn":
|
|
262
|
+
// DOM values (the `unknown` boundary): the runtime's `_v` pair —
|
|
263
|
+
// scr_dyn_retain is a header inline, so the `_v` symbols serve both
|
|
264
|
+
// roles. UNTRACED (the dyn→closure stance: cycles through dyn are
|
|
265
|
+
// never collected, SEMANTICS.md) — traceAdapter answers null.
|
|
266
|
+
host.declare(`declare ptr @scr_dyn_retain_v(ptr)`);
|
|
267
|
+
host.declare(`declare void @scr_dyn_release_v(ptr)`);
|
|
268
|
+
return { retain: "@scr_dyn_retain_v", release: "@scr_dyn_release_v" };
|
|
269
|
+
default:
|
|
270
|
+
throw new LlvmUnsupportedError(`rc:${t.kind}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/** The retain call target (ptr → ptr, +1 unless immortal) — the `_v`
|
|
274
|
+
* table above; the split exists so call sites read type-directedly. */
|
|
275
|
+
export function retainSym(host, t) {
|
|
276
|
+
return vAdapters(host, t).retain;
|
|
277
|
+
}
|
|
278
|
+
/** The release call target (ptr → void, NULL-tolerant). The runtime's
|
|
279
|
+
* typed releases are external symbols, so the direct (non-`_v`) entry
|
|
280
|
+
* points serve where one exists; records use their emitted helper. */
|
|
281
|
+
export function releaseSym(host, t) {
|
|
282
|
+
switch (t.kind) {
|
|
283
|
+
case "caught":
|
|
284
|
+
host.declare(`declare void @scr_caught_release(ptr)`);
|
|
285
|
+
return "@scr_caught_release";
|
|
286
|
+
case "string":
|
|
287
|
+
host.declare(`declare void @scr_str_release(ptr)`);
|
|
288
|
+
return "@scr_str_release";
|
|
289
|
+
case "array":
|
|
290
|
+
host.declare(`declare void @scr_arr_release(ptr)`);
|
|
291
|
+
return "@scr_arr_release";
|
|
292
|
+
case "map":
|
|
293
|
+
case "set":
|
|
294
|
+
host.declare(`declare void @scr_map_release(ptr)`);
|
|
295
|
+
return "@scr_map_release";
|
|
296
|
+
case "union":
|
|
297
|
+
host.declare(`declare void @scr_union_release(ptr)`);
|
|
298
|
+
return "@scr_union_release";
|
|
299
|
+
case "promise":
|
|
300
|
+
host.declare(`declare void @scr_promise_release(ptr)`);
|
|
301
|
+
return "@scr_promise_release";
|
|
302
|
+
case "bytes":
|
|
303
|
+
host.declare(`declare void @scr_bytes_release(ptr)`);
|
|
304
|
+
return "@scr_bytes_release";
|
|
305
|
+
case "url":
|
|
306
|
+
host.declare(`declare void @scr_url_release_v(ptr)`);
|
|
307
|
+
return "@scr_url_release_v";
|
|
308
|
+
case "searchParams":
|
|
309
|
+
host.declare(`declare void @scr_sp_release_v(ptr)`);
|
|
310
|
+
return "@scr_sp_release_v";
|
|
311
|
+
case "stats":
|
|
312
|
+
host.declare(`declare void @scr_stats_release_v(ptr)`);
|
|
313
|
+
return "@scr_stats_release_v";
|
|
314
|
+
case "spawnRes":
|
|
315
|
+
host.declare(`declare void @scr_spawn_res_release_v(ptr)`);
|
|
316
|
+
return "@scr_spawn_res_release_v";
|
|
317
|
+
case "child":
|
|
318
|
+
host.declare(`declare void @scr_child_release_v(ptr)`);
|
|
319
|
+
return "@scr_child_release_v";
|
|
320
|
+
case "childStream":
|
|
321
|
+
host.declare(`declare void @scr_child_stream_release_v(ptr)`);
|
|
322
|
+
return "@scr_child_stream_release_v";
|
|
323
|
+
case "generator":
|
|
324
|
+
host.declare(`declare void @scr_gen_release(ptr)`);
|
|
325
|
+
return "@scr_gen_release";
|
|
326
|
+
case "func":
|
|
327
|
+
host.declare(`declare void @scr_closure_release(ptr)`);
|
|
328
|
+
return "@scr_closure_release";
|
|
329
|
+
case "symbol":
|
|
330
|
+
host.declare(`declare void @scr_sym_release(ptr)`);
|
|
331
|
+
return "@scr_sym_release";
|
|
332
|
+
case "regex":
|
|
333
|
+
host.declare(`declare void @scr_regex_release(ptr)`);
|
|
334
|
+
return "@scr_regex_release";
|
|
335
|
+
case "record":
|
|
336
|
+
return `@${mangleRecordRelease(t.shapeId)}`;
|
|
337
|
+
case "object":
|
|
338
|
+
if (RUNTIME_ERROR_CLASSES.has(t.className)) {
|
|
339
|
+
host.declare(`declare void @scr_error_release_v(ptr)`);
|
|
340
|
+
return "@scr_error_release_v";
|
|
341
|
+
}
|
|
342
|
+
if (t.className === RUNTIME_EMITTER_CLASS) {
|
|
343
|
+
host.declare(`declare void @scr_emitter_release_v(ptr)`);
|
|
344
|
+
return "@scr_emitter_release_v";
|
|
345
|
+
}
|
|
346
|
+
if (RUNTIME_STREAM_CLASSES.has(t.className)) {
|
|
347
|
+
host.declare(`declare void @scr_stream_release_v(ptr)`);
|
|
348
|
+
return "@scr_stream_release_v";
|
|
349
|
+
}
|
|
350
|
+
return `@${mangleClassRelease(t.className)}`;
|
|
351
|
+
case "classval":
|
|
352
|
+
host.declare(`declare void @scr_classobj_release_v(ptr)`);
|
|
353
|
+
return "@scr_classobj_release_v";
|
|
354
|
+
case "fsWatcher":
|
|
355
|
+
host.declare(`declare void @scr_watcher_release_v(ptr)`);
|
|
356
|
+
return "@scr_watcher_release_v";
|
|
357
|
+
case "netServer":
|
|
358
|
+
case "netSocket":
|
|
359
|
+
case "dgramSocket":
|
|
360
|
+
case "httpReq":
|
|
361
|
+
case "httpRes":
|
|
362
|
+
case "httpClientReq":
|
|
363
|
+
case "secureCtx":
|
|
364
|
+
case "testCtx":
|
|
365
|
+
// The handle kinds share their `_v` pair for both roles.
|
|
366
|
+
return vAdapters(host, t).release;
|
|
367
|
+
case "jsval":
|
|
368
|
+
host.declare(`declare void @scr_jsval_release_v(ptr)`);
|
|
369
|
+
return "@scr_jsval_release_v";
|
|
370
|
+
case "dyn":
|
|
371
|
+
// scr_dyn_release releases the tree recursively; NULL-tolerant.
|
|
372
|
+
host.declare(`declare void @scr_dyn_release(ptr)`);
|
|
373
|
+
return "@scr_dyn_release";
|
|
374
|
+
default:
|
|
375
|
+
throw new LlvmUnsupportedError(`rc:${t.kind}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/** The trace entry point for a payload/field type, or null when the type
|
|
379
|
+
* cannot participate in a cycle — traceAdapterC's table over the LLVM
|
|
380
|
+
* tier's kinds (promise/object rows are out of tier and unreachable:
|
|
381
|
+
* their RC rows refuse first). */
|
|
382
|
+
export function traceAdapter(host, t) {
|
|
383
|
+
switch (t.kind) {
|
|
384
|
+
case "func":
|
|
385
|
+
host.declare(`declare void @scr_closure_trace_v(ptr, ptr, ptr)`);
|
|
386
|
+
return "@scr_closure_trace_v";
|
|
387
|
+
case "promise":
|
|
388
|
+
// Promises are unconditionally cycle-capable (a rejection payload
|
|
389
|
+
// is an arbitrary thrown value) — emit-shapes.ts's row.
|
|
390
|
+
host.declare(`declare void @scr_promise_trace_v(ptr, ptr, ptr)`);
|
|
391
|
+
return "@scr_promise_trace_v";
|
|
392
|
+
case "union":
|
|
393
|
+
if (!host.tracedUnions.has(t.unionId))
|
|
394
|
+
return null;
|
|
395
|
+
host.declare(`declare void @scr_union_trace_v(ptr, ptr, ptr)`);
|
|
396
|
+
return "@scr_union_trace_v";
|
|
397
|
+
case "record":
|
|
398
|
+
return host.tracedShapes.has(`record:${t.shapeId}`) ? `@${mangleRecordTrace(t.shapeId)}` : null;
|
|
399
|
+
case "object":
|
|
400
|
+
if (!host.tracedShapes.has(`object:${t.className}`))
|
|
401
|
+
return null;
|
|
402
|
+
if (RUNTIME_ERROR_CLASSES.has(t.className)) {
|
|
403
|
+
host.declare(`declare void @scr_error_trace(ptr, ptr, ptr)`);
|
|
404
|
+
return "@scr_error_trace";
|
|
405
|
+
}
|
|
406
|
+
if (t.className === RUNTIME_EMITTER_CLASS) {
|
|
407
|
+
// Unconditionally cycle-capable (the registry owns listener
|
|
408
|
+
// closures) — the fixpoint's <listeners> field keeps the whole
|
|
409
|
+
// emitter hierarchy in the traced set.
|
|
410
|
+
host.declare(`declare void @scr_emitter_trace(ptr, ptr, ptr)`);
|
|
411
|
+
return "@scr_emitter_trace";
|
|
412
|
+
}
|
|
413
|
+
if (RUNTIME_STREAM_CLASSES.has(t.className)) {
|
|
414
|
+
host.declare(`declare void @scr_stream_trace(ptr, ptr, ptr)`);
|
|
415
|
+
return "@scr_stream_trace";
|
|
416
|
+
}
|
|
417
|
+
return `@${mangleClassTrace(t.className)}`;
|
|
418
|
+
case "map":
|
|
419
|
+
if (traceAdapter(host, t.value) === null)
|
|
420
|
+
return null;
|
|
421
|
+
host.declare(`declare void @scr_map_trace_v(ptr, ptr, ptr)`);
|
|
422
|
+
return "@scr_map_trace_v";
|
|
423
|
+
case "array":
|
|
424
|
+
if (traceAdapter(host, t.elem) === null)
|
|
425
|
+
return null;
|
|
426
|
+
host.declare(`declare void @scr_arr_trace_v(ptr, ptr, ptr)`);
|
|
427
|
+
return "@scr_arr_trace_v";
|
|
428
|
+
default:
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
/** `@trace` or `null` — the trace argument at a container call site. */
|
|
433
|
+
export function traceArg(host, t) {
|
|
434
|
+
return traceAdapter(host, t) ?? "null";
|
|
435
|
+
}
|
|
436
|
+
/* ── arrays ───────────────────────────────────────────────────────────── */
|
|
437
|
+
/** Runtime accessor suffix for an element type (matches emit-types.ts:
|
|
438
|
+
* f64 and bool unboxed, everything refcounted through the `_ref` family). */
|
|
439
|
+
export function elemAccess(elem) {
|
|
440
|
+
return elem.kind === "f64" ? "f64" : elem.kind === "bool" ? "bool" : "ref";
|
|
441
|
+
}
|
|
442
|
+
/** The ScrElemKind constant for the plain (non-REF) construction path. */
|
|
443
|
+
function elemKindNum(elem) {
|
|
444
|
+
switch (elem.kind) {
|
|
445
|
+
case "f64":
|
|
446
|
+
return 0; // SCR_ELEM_F64
|
|
447
|
+
case "bool":
|
|
448
|
+
return 1; // SCR_ELEM_BOOL
|
|
449
|
+
case "string":
|
|
450
|
+
return 2; // SCR_ELEM_STR
|
|
451
|
+
case "array":
|
|
452
|
+
return 3; // SCR_ELEM_ARR
|
|
453
|
+
case "bytes":
|
|
454
|
+
return 4; // SCR_ELEM_BYTES
|
|
455
|
+
default:
|
|
456
|
+
throw new LlvmUnsupportedError(`arrayElem:${elem.kind}`);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
/** Array construction call text (arrNewC's dispatch): ref elements
|
|
460
|
+
* (records, unions, closures — and cycle-capable inner arrays, whose
|
|
461
|
+
* SCR_ELEM_ARR spelling would hide them from the outer array's trace)
|
|
462
|
+
* construct through scr_arr_new_ref with the element type's `_v` RC entry
|
|
463
|
+
* points; every other element kind keeps the plain scr_arr_new call. */
|
|
464
|
+
export function arrNewCall(host, elem, capText) {
|
|
465
|
+
const useRef = elem.kind === "record" || elem.kind === "object" || elem.kind === "union" || elem.kind === "func" ||
|
|
466
|
+
elem.kind === "symbol" || // symbol identities: scr_sym_* adapters, no trace
|
|
467
|
+
elem.kind === "classval" || // class objects: no-op adapters, no trace (immortal statics)
|
|
468
|
+
elem.kind === "promise" || // promise entries (Promise.all inputs): full REF story
|
|
469
|
+
elem.kind === "child" || // spawned child handles: scr_child_* adapters, no trace
|
|
470
|
+
elem.kind === "netServer" || // server handles ([...set] drains): REF, no trace
|
|
471
|
+
elem.kind === "jsval" || // island handles (`any[]` under --dynamic): REF, no trace
|
|
472
|
+
(elem.kind === "array" && traceAdapter(host, elem) !== null);
|
|
473
|
+
if (!useRef) {
|
|
474
|
+
host.declare(`declare ptr @scr_arr_new(i32, i64)`);
|
|
475
|
+
return `call ptr @scr_arr_new(i32 ${elemKindNum(elem)}, i64 ${capText})`;
|
|
476
|
+
}
|
|
477
|
+
const v = vAdapters(host, elem);
|
|
478
|
+
host.declare(`declare ptr @scr_arr_new_ref(ptr, ptr, ptr, i64)`);
|
|
479
|
+
return `call ptr @scr_arr_new_ref(ptr ${v.retain}, ptr ${v.release}, ptr ${traceArg(host, elem)}, i64 ${capText})`;
|
|
480
|
+
}
|
|
481
|
+
/* ── capture boxes ────────────────────────────────────────────────────── */
|
|
482
|
+
/** Box construction call text (boxNewC's dispatch): plain-kind boxes for
|
|
483
|
+
* the runtime-known payloads, obj-kind boxes (RC entry points + trace as
|
|
484
|
+
* data) for per-shape payloads and cycle-capable arrays. SCR_BOX_* tags
|
|
485
|
+
* from scr_runtime.h. */
|
|
486
|
+
export function boxNewCall(host, t) {
|
|
487
|
+
const plain = { f64: 0, bool: 1, string: 2, func: 4 };
|
|
488
|
+
const kind = plain[t.kind];
|
|
489
|
+
if (kind !== undefined) {
|
|
490
|
+
host.declare(`declare ptr @scr_box_new(i32)`);
|
|
491
|
+
return `call ptr @scr_box_new(i32 ${kind})`;
|
|
492
|
+
}
|
|
493
|
+
if (t.kind === "array" && traceAdapter(host, t) === null) {
|
|
494
|
+
host.declare(`declare ptr @scr_box_new(i32)`);
|
|
495
|
+
return `call ptr @scr_box_new(i32 3)`; // SCR_BOX_ARR
|
|
496
|
+
}
|
|
497
|
+
if (t.kind === "record" || t.kind === "object" || t.kind === "classval" || t.kind === "union" ||
|
|
498
|
+
t.kind === "array" || t.kind === "map" || t.kind === "set" || t.kind === "symbol" || t.kind === "regex" ||
|
|
499
|
+
t.kind === "promise" || t.kind === "bytes" || t.kind === "url" || t.kind === "searchParams" ||
|
|
500
|
+
t.kind === "stats" || t.kind === "spawnRes" || t.kind === "child" || t.kind === "childStream" ||
|
|
501
|
+
t.kind === "generator" ||
|
|
502
|
+
t.kind === "netServer" || t.kind === "netSocket" || t.kind === "dgramSocket" ||
|
|
503
|
+
t.kind === "httpReq" || t.kind === "httpRes" || t.kind === "httpClientReq" ||
|
|
504
|
+
t.kind === "secureCtx" || t.kind === "testCtx" ||
|
|
505
|
+
// Island handles: the box carries scr_jsval_retain_v/release_v and
|
|
506
|
+
// no trace — the same stance as jsval array elements.
|
|
507
|
+
t.kind === "jsval" ||
|
|
508
|
+
// Checked-dynamic captures (the mustCall wrapper closing over its
|
|
509
|
+
// implicit-any `fn` param): the box carries scr_dyn_retain_v/release_v
|
|
510
|
+
// and NO trace — cycles through dyn never collect (SEMANTICS.md).
|
|
511
|
+
t.kind === "dyn" ||
|
|
512
|
+
t.kind === "fsWatcher") {
|
|
513
|
+
const v = vAdapters(host, t);
|
|
514
|
+
host.declare(`declare ptr @scr_box_new_obj(ptr, ptr, ptr)`);
|
|
515
|
+
return `call ptr @scr_box_new_obj(ptr ${v.retain}, ptr ${v.release}, ptr ${traceArg(host, t)})`;
|
|
516
|
+
}
|
|
517
|
+
throw new LlvmUnsupportedError(`box:${t.kind}`);
|
|
518
|
+
}
|
|
519
|
+
/** Box accessor suffix (boxAccess): scalars unboxed, ref kinds pointers. */
|
|
520
|
+
export function boxAccess(t) {
|
|
521
|
+
return t.kind === "f64" ? "f64" : t.kind === "bool" ? "bool" : "ref";
|
|
522
|
+
}
|
|
523
|
+
/* ── record shapes ────────────────────────────────────────────────────── */
|
|
524
|
+
/** A record field's in-struct LLVM type. bool fields store as i8 (the C
|
|
525
|
+
* _Bool layout); loads/stores convert at the access site. */
|
|
526
|
+
export function llFieldType(t) {
|
|
527
|
+
switch (t.kind) {
|
|
528
|
+
case "f64":
|
|
529
|
+
return "double";
|
|
530
|
+
case "bool":
|
|
531
|
+
return "i8";
|
|
532
|
+
case "string":
|
|
533
|
+
case "array":
|
|
534
|
+
case "record":
|
|
535
|
+
case "object":
|
|
536
|
+
case "classval":
|
|
537
|
+
case "union":
|
|
538
|
+
case "func":
|
|
539
|
+
case "map":
|
|
540
|
+
case "set":
|
|
541
|
+
case "symbol":
|
|
542
|
+
case "regex":
|
|
543
|
+
case "promise":
|
|
544
|
+
case "bytes":
|
|
545
|
+
case "url":
|
|
546
|
+
case "searchParams":
|
|
547
|
+
case "stats":
|
|
548
|
+
case "spawnRes":
|
|
549
|
+
case "child":
|
|
550
|
+
case "childStream":
|
|
551
|
+
case "generator":
|
|
552
|
+
case "dyn":
|
|
553
|
+
case "jsval":
|
|
554
|
+
case "fsWatcher":
|
|
555
|
+
case "netServer":
|
|
556
|
+
case "netSocket":
|
|
557
|
+
case "dgramSocket":
|
|
558
|
+
case "httpReq":
|
|
559
|
+
case "httpRes":
|
|
560
|
+
case "httpClientReq":
|
|
561
|
+
case "secureCtx":
|
|
562
|
+
case "testCtx":
|
|
563
|
+
return "ptr";
|
|
564
|
+
default:
|
|
565
|
+
throw new LlvmUnsupportedError(`type:${t.kind}`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
/* ── maps and sets ────────────────────────────────────────────────────── */
|
|
569
|
+
/** Runtime suffix for a map's KEY kind (mapKeyAccess's table): f64 with
|
|
570
|
+
* SameValueZero, string content, or handle-identity REF (symbols). */
|
|
571
|
+
export function mapKeyAccess(key) {
|
|
572
|
+
if (key.kind === "f64")
|
|
573
|
+
return "f64";
|
|
574
|
+
if (key.kind === "string")
|
|
575
|
+
return "str";
|
|
576
|
+
if (key.kind === "symbol")
|
|
577
|
+
return "ref";
|
|
578
|
+
if (key.kind === "netServer")
|
|
579
|
+
return "ref"; // handle identity (Set<Server>)
|
|
580
|
+
throw new LlvmUnsupportedError(`mapKey:${key.kind}`);
|
|
581
|
+
}
|
|
582
|
+
/** The ScrMapKeyKind / ScrMapValKind constants for scr_map_new. */
|
|
583
|
+
export function mapKeyKindNum(key) {
|
|
584
|
+
const acc = mapKeyAccess(key);
|
|
585
|
+
return acc === "f64" ? 0 : acc === "str" ? 1 : 2;
|
|
586
|
+
}
|
|
587
|
+
export function mapValKindNum(value) {
|
|
588
|
+
return value.kind === "f64" ? 0 : value.kind === "bool" ? 1 : 2;
|
|
589
|
+
}
|
|
590
|
+
/** The RC-relevant members of a shape: every field, plus the overflow map
|
|
591
|
+
* on index-signature shapes (one more map-typed member). `index` is the
|
|
592
|
+
* member's field position in the emitted struct type (rc header at 0). */
|
|
593
|
+
function rcMembers(shape) {
|
|
594
|
+
return [
|
|
595
|
+
...shape.fields.map((f, i) => ({ index: i + 1, type: f.type, name: f.name })),
|
|
596
|
+
...(shape.indexValue
|
|
597
|
+
? [{ index: shape.fields.length + 1, type: mapOf(STRING, shape.indexValue), name: "[key: string] overflow" }]
|
|
598
|
+
: []),
|
|
599
|
+
];
|
|
600
|
+
}
|
|
601
|
+
/** The immortal-skip + mark-live retain body shared by every shape. The
|
|
602
|
+
* cycle header sits 32 bytes before the object; `color` is at header+16,
|
|
603
|
+
* so mark-live is one i32 store at obj-16 (scr_cyc_mark_live inlined —
|
|
604
|
+
* the runtime's is a static inline with no external symbol). */
|
|
605
|
+
function retainBody(fnName, traced) {
|
|
606
|
+
return [
|
|
607
|
+
`define internal ptr @${fnName}(ptr %o) ${FN_ATTRS} {`,
|
|
608
|
+
`entry:`,
|
|
609
|
+
` %isnull = icmp eq ptr %o, null`,
|
|
610
|
+
` br i1 %isnull, label %done, label %check`,
|
|
611
|
+
`check:`,
|
|
612
|
+
` %rc = load i64, ptr %o`,
|
|
613
|
+
` %imm = icmp eq i64 %rc, -1`,
|
|
614
|
+
` br i1 %imm, label %done, label %inc`,
|
|
615
|
+
`inc:`,
|
|
616
|
+
` %n = add i64 %rc, 1`,
|
|
617
|
+
` store i64 %n, ptr %o`,
|
|
618
|
+
...(traced
|
|
619
|
+
? [` %colorp = getelementptr i8, ptr %o, i64 -16`, ` store i32 0, ptr %colorp ; mark live`]
|
|
620
|
+
: []),
|
|
621
|
+
` br label %done`,
|
|
622
|
+
`done:`,
|
|
623
|
+
` ret ptr %o`,
|
|
624
|
+
`}`,
|
|
625
|
+
];
|
|
626
|
+
}
|
|
627
|
+
/** Per-record-shape LLVM emission: the named struct types (returned as
|
|
628
|
+
* `typeDefs`) and the new/retain/release (+trace/gcFree for cycle-capable
|
|
629
|
+
* shapes) function definitions (`defs`). Layout mirrors the C emitter:
|
|
630
|
+
* `{ i64 rc, fields..., [ptr overflow] }`; the retain/release signatures
|
|
631
|
+
* are already `_v`-shaped, so the same symbols serve as container RC
|
|
632
|
+
* entry points. */
|
|
633
|
+
export function emitRecordShapes(host, mod) {
|
|
634
|
+
const typeDefs = [];
|
|
635
|
+
const defs = [];
|
|
636
|
+
const records = mod.records ?? [];
|
|
637
|
+
if (records.length === 0)
|
|
638
|
+
return { typeDefs, defs };
|
|
639
|
+
host.declare(`declare void @scr_obj_alloc_note()`);
|
|
640
|
+
host.declare(`declare void @scr_obj_free_note()`);
|
|
641
|
+
for (const shape of records) {
|
|
642
|
+
const struct = mangleRecordStruct(shape.id);
|
|
643
|
+
const fieldTys = shape.fields.map((f) => llFieldType(f.type));
|
|
644
|
+
if (shape.indexValue)
|
|
645
|
+
fieldTys.push("ptr"); // the overflow ScrMap *
|
|
646
|
+
typeDefs.push(`%${struct} = type { i64${fieldTys.length ? ", " + fieldTys.join(", ") : ""} } ` +
|
|
647
|
+
`; record ${shape.id} { ${shape.fields.map((f) => f.name).join("; ")}${shape.indexValue ? "; [key: string]" : ""} }`);
|
|
648
|
+
}
|
|
649
|
+
for (const shape of records) {
|
|
650
|
+
const struct = mangleRecordStruct(shape.id);
|
|
651
|
+
const traced = host.tracedShapes.has(`record:${shape.id}`);
|
|
652
|
+
const members = rcMembers(shape);
|
|
653
|
+
const refMembers = members.filter((m) => isRefCounted(m.type));
|
|
654
|
+
const sizeOf = `ptrtoint (ptr getelementptr (%${struct}, ptr null, i32 1) to i64)`;
|
|
655
|
+
defs.push(...retainBody(mangleRecordRetain(shape.id), traced), ``);
|
|
656
|
+
// release: NULL-tolerant, immortal-skip; at rc == 0 release every
|
|
657
|
+
// refcounted member (runtime releases are NULL-tolerant) and free —
|
|
658
|
+
// traced shapes route through the collector (on_dead/on_release,
|
|
659
|
+
// scr_cyc_free) exactly like emit-shapes.ts.
|
|
660
|
+
const rel = [
|
|
661
|
+
`define internal void @${mangleRecordRelease(shape.id)}(ptr %o) ${FN_ATTRS} {`,
|
|
662
|
+
`entry:`,
|
|
663
|
+
` %isnull = icmp eq ptr %o, null`,
|
|
664
|
+
` br i1 %isnull, label %done, label %check`,
|
|
665
|
+
`check:`,
|
|
666
|
+
` %rc = load i64, ptr %o`,
|
|
667
|
+
` %imm = icmp eq i64 %rc, -1`,
|
|
668
|
+
` br i1 %imm, label %done, label %dec`,
|
|
669
|
+
`dec:`,
|
|
670
|
+
` %n = sub i64 %rc, 1`,
|
|
671
|
+
` store i64 %n, ptr %o`,
|
|
672
|
+
` %dead = icmp eq i64 %n, 0`,
|
|
673
|
+
` br i1 %dead, label %free, label %${traced ? "root" : "done"}`,
|
|
674
|
+
`free:`,
|
|
675
|
+
];
|
|
676
|
+
if (traced) {
|
|
677
|
+
host.declare(`declare void @scr_cyc_on_dead(ptr)`);
|
|
678
|
+
rel.push(` call void @scr_cyc_on_dead(ptr %o)`);
|
|
679
|
+
}
|
|
680
|
+
let t = 0;
|
|
681
|
+
for (const m of refMembers) {
|
|
682
|
+
rel.push(` %f${t} = getelementptr inbounds %${struct}, ptr %o, i64 0, i32 ${m.index}`, ` %v${t} = load ptr, ptr %f${t}`, ` call void ${releaseSym(host, m.type)}(ptr %v${t}) ; ${m.name}`);
|
|
683
|
+
t++;
|
|
684
|
+
}
|
|
685
|
+
rel.push(` call void @scr_obj_free_note()`);
|
|
686
|
+
if (traced) {
|
|
687
|
+
host.declare(`declare void @scr_cyc_free(ptr)`);
|
|
688
|
+
host.declare(`declare void @scr_cyc_on_release(ptr)`);
|
|
689
|
+
rel.push(` call void @scr_cyc_free(ptr %o)`, ` br label %done`, `root:`, ` call void @scr_cyc_on_release(ptr %o) ; possible cycle root; may collect`, ` br label %done`);
|
|
690
|
+
}
|
|
691
|
+
else {
|
|
692
|
+
host.declare(`declare void @free(ptr)`);
|
|
693
|
+
rel.push(` call void @free(ptr %o)`, ` br label %done`);
|
|
694
|
+
}
|
|
695
|
+
rel.push(`done:`, ` ret void`, `}`, ``);
|
|
696
|
+
defs.push(...rel);
|
|
697
|
+
// new: zeroed allocation (+ the overflow map on index-signature
|
|
698
|
+
// shapes), rc = 1, alloc note. Traced shapes allocate with the
|
|
699
|
+
// collector header (scr_cyc_alloc zeroes and aborts on OOM itself).
|
|
700
|
+
const nw = [
|
|
701
|
+
`define internal ptr @${mangleRecordNew(shape.id)}() ${FN_ATTRS} {`,
|
|
702
|
+
`entry:`,
|
|
703
|
+
];
|
|
704
|
+
if (traced) {
|
|
705
|
+
host.declare(`declare ptr @scr_cyc_alloc(i64, ptr, ptr)`);
|
|
706
|
+
nw.push(` %o = call ptr @scr_cyc_alloc(i64 ${sizeOf}, ptr @${mangleRecordTrace(shape.id)}, ptr @${mangleRecordGcFree(shape.id)})`);
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
host.declare(`declare ptr @calloc(i64, i64)`);
|
|
710
|
+
host.needOom();
|
|
711
|
+
nw.push(` %o = call ptr @calloc(i64 1, i64 ${sizeOf})`, ` %isnull = icmp eq ptr %o, null`, ` br i1 %isnull, label %oom, label %ok`, `oom:`, ` call void @sc_oom()`, ` unreachable`, `ok:`);
|
|
712
|
+
}
|
|
713
|
+
nw.push(` store i64 1, ptr %o`);
|
|
714
|
+
if (shape.indexValue) {
|
|
715
|
+
// The overflow map (string-keyed): value handling is type-directed
|
|
716
|
+
// exactly like emit-shapes.ts's overflowNewC.
|
|
717
|
+
host.declare(`declare ptr @scr_map_new(i32, i32, ptr, ptr, ptr)`);
|
|
718
|
+
const v = shape.indexValue;
|
|
719
|
+
const valKind = v.kind === "f64" ? 0 : v.kind === "bool" ? 1 : 2;
|
|
720
|
+
const rc = valKind === 2 ? vAdapters(host, v) : { retain: "null", release: "null" };
|
|
721
|
+
const trace = valKind === 2 ? traceArg(host, v) : "null";
|
|
722
|
+
nw.push(` %ovf = call ptr @scr_map_new(i32 1, i32 ${valKind}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${trace})`, ` %ovfp = getelementptr inbounds %${struct}, ptr %o, i64 0, i32 ${shape.fields.length + 1}`, ` store ptr %ovf, ptr %ovfp`);
|
|
723
|
+
}
|
|
724
|
+
nw.push(` call void @scr_obj_alloc_note()`, ` ret ptr %o`, `}`, ``);
|
|
725
|
+
defs.push(...nw);
|
|
726
|
+
if (traced) {
|
|
727
|
+
// trace: visit exactly the cycle-capable members; gcFree: release
|
|
728
|
+
// exactly the complement, then free (the trace/teardown complement
|
|
729
|
+
// contract in scr_runtime.h).
|
|
730
|
+
const tracedMembers = members.filter((m) => traceAdapter(host, m.type) !== null);
|
|
731
|
+
const untracedRefMembers = refMembers.filter((m) => traceAdapter(host, m.type) === null);
|
|
732
|
+
const tr = [
|
|
733
|
+
`define internal void @${mangleRecordTrace(shape.id)}(ptr %o, ptr %visit, ptr %ctx) ${FN_ATTRS} {`,
|
|
734
|
+
`entry:`,
|
|
735
|
+
];
|
|
736
|
+
tracedMembers.forEach((m, i) => {
|
|
737
|
+
tr.push(` %f${i} = getelementptr inbounds %${struct}, ptr %o, i64 0, i32 ${m.index}`, ` %v${i} = load ptr, ptr %f${i}`, ` call void %visit(ptr %v${i}, ptr %ctx) ; ${m.name}`);
|
|
738
|
+
});
|
|
739
|
+
tr.push(` ret void`, `}`, ``);
|
|
740
|
+
defs.push(...tr);
|
|
741
|
+
const gf = [
|
|
742
|
+
`define internal void @${mangleRecordGcFree(shape.id)}(ptr %o) ${FN_ATTRS} {`,
|
|
743
|
+
`entry:`,
|
|
744
|
+
];
|
|
745
|
+
untracedRefMembers.forEach((m, i) => {
|
|
746
|
+
gf.push(` %f${i} = getelementptr inbounds %${struct}, ptr %o, i64 0, i32 ${m.index}`, ` %v${i} = load ptr, ptr %f${i}`, ` call void ${releaseSym(host, m.type)}(ptr %v${i}) ; ${m.name} (acyclic)`);
|
|
747
|
+
});
|
|
748
|
+
gf.push(` call void @scr_obj_free_note()`, ` call void @scr_cyc_free(ptr %o)`, ` ret void`, `}`, ``);
|
|
749
|
+
defs.push(...gf);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
return { typeDefs, defs };
|
|
753
|
+
}
|
|
754
|
+
//# sourceMappingURL=shapes.js.map
|