@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.
Files changed (206) hide show
  1. package/LICENSE +202 -0
  2. package/ambient/package.json +3 -0
  3. package/ambient/scriptc-node-fallback.d.ts +3001 -0
  4. package/ambient/scriptc-overrides.d.ts +95 -0
  5. package/ambient/scriptc.d.ts +74 -0
  6. package/dist/backend/cc.d.ts +169 -0
  7. package/dist/backend/cc.js +897 -0
  8. package/dist/backend/cc.js.map +1 -0
  9. package/dist/backend/emission/emit-async.d.ts +145 -0
  10. package/dist/backend/emission/emit-async.js +996 -0
  11. package/dist/backend/emission/emit-async.js.map +1 -0
  12. package/dist/backend/emission/emit-exprs.d.ts +3 -0
  13. package/dist/backend/emission/emit-exprs.js +5949 -0
  14. package/dist/backend/emission/emit-exprs.js.map +1 -0
  15. package/dist/backend/emission/emit-island.d.ts +45 -0
  16. package/dist/backend/emission/emit-island.js +271 -0
  17. package/dist/backend/emission/emit-island.js.map +1 -0
  18. package/dist/backend/emission/emit-shapes.d.ts +142 -0
  19. package/dist/backend/emission/emit-shapes.js +575 -0
  20. package/dist/backend/emission/emit-shapes.js.map +1 -0
  21. package/dist/backend/emission/emit-stmts.d.ts +78 -0
  22. package/dist/backend/emission/emit-stmts.js +960 -0
  23. package/dist/backend/emission/emit-stmts.js.map +1 -0
  24. package/dist/backend/emission/emit-types.d.ts +65 -0
  25. package/dist/backend/emission/emit-types.js +652 -0
  26. package/dist/backend/emission/emit-types.js.map +1 -0
  27. package/dist/backend/emission/emit-walkers.d.ts +154 -0
  28. package/dist/backend/emission/emit-walkers.js +1587 -0
  29. package/dist/backend/emission/emit-walkers.js.map +1 -0
  30. package/dist/backend/emission/emitter.d.ts +452 -0
  31. package/dist/backend/emission/emitter.js +1249 -0
  32. package/dist/backend/emission/emitter.js.map +1 -0
  33. package/dist/backend/emission/may-throw.d.ts +15 -0
  34. package/dist/backend/emission/may-throw.js +250 -0
  35. package/dist/backend/emission/may-throw.js.map +1 -0
  36. package/dist/backend/llvm/blocks.d.ts +21 -0
  37. package/dist/backend/llvm/blocks.js +68 -0
  38. package/dist/backend/llvm/blocks.js.map +1 -0
  39. package/dist/backend/llvm/classes.d.ts +84 -0
  40. package/dist/backend/llvm/classes.js +438 -0
  41. package/dist/backend/llvm/classes.js.map +1 -0
  42. package/dist/backend/llvm/dyn.d.ts +123 -0
  43. package/dist/backend/llvm/dyn.js +2624 -0
  44. package/dist/backend/llvm/dyn.js.map +1 -0
  45. package/dist/backend/llvm/emitter.d.ts +3 -0
  46. package/dist/backend/llvm/emitter.js +10102 -0
  47. package/dist/backend/llvm/emitter.js.map +1 -0
  48. package/dist/backend/llvm/shapes.d.ts +78 -0
  49. package/dist/backend/llvm/shapes.js +754 -0
  50. package/dist/backend/llvm/shapes.js.map +1 -0
  51. package/dist/backend/llvm/unsupported.d.ts +6 -0
  52. package/dist/backend/llvm/unsupported.js +12 -0
  53. package/dist/backend/llvm/unsupported.js.map +1 -0
  54. package/dist/backend/llvm/walkers.d.ts +58 -0
  55. package/dist/backend/llvm/walkers.js +793 -0
  56. package/dist/backend/llvm/walkers.js.map +1 -0
  57. package/dist/backend/mangle.d.ts +124 -0
  58. package/dist/backend/mangle.js +232 -0
  59. package/dist/backend/mangle.js.map +1 -0
  60. package/dist/coverage/report.d.ts +65 -0
  61. package/dist/coverage/report.js +238 -0
  62. package/dist/coverage/report.js.map +1 -0
  63. package/dist/diagnostics/diagnostic.d.ts +140 -0
  64. package/dist/diagnostics/diagnostic.js +458 -0
  65. package/dist/diagnostics/diagnostic.js.map +1 -0
  66. package/dist/diagnostics/render.d.ts +11 -0
  67. package/dist/diagnostics/render.js +58 -0
  68. package/dist/diagnostics/render.js.map +1 -0
  69. package/dist/frontend/cjs-lexer.d.ts +20 -0
  70. package/dist/frontend/cjs-lexer.js +813 -0
  71. package/dist/frontend/cjs-lexer.js.map +1 -0
  72. package/dist/frontend/lowering/http2-constants.d.ts +1 -0
  73. package/dist/frontend/lowering/http2-constants.js +251 -0
  74. package/dist/frontend/lowering/http2-constants.js.map +1 -0
  75. package/dist/frontend/lowering/lib-boundary.d.ts +6 -0
  76. package/dist/frontend/lowering/lib-boundary.js +143 -0
  77. package/dist/frontend/lowering/lib-boundary.js.map +1 -0
  78. package/dist/frontend/lowering/lower-assert.d.ts +18 -0
  79. package/dist/frontend/lowering/lower-assert.js +1269 -0
  80. package/dist/frontend/lowering/lower-assert.js.map +1 -0
  81. package/dist/frontend/lowering/lower-builtins.d.ts +511 -0
  82. package/dist/frontend/lowering/lower-builtins.js +5249 -0
  83. package/dist/frontend/lowering/lower-builtins.js.map +1 -0
  84. package/dist/frontend/lowering/lower-calls.d.ts +581 -0
  85. package/dist/frontend/lowering/lower-calls.js +6286 -0
  86. package/dist/frontend/lowering/lower-calls.js.map +1 -0
  87. package/dist/frontend/lowering/lower-classes.d.ts +727 -0
  88. package/dist/frontend/lowering/lower-classes.js +4701 -0
  89. package/dist/frontend/lowering/lower-classes.js.map +1 -0
  90. package/dist/frontend/lowering/lower-comptime.d.ts +53 -0
  91. package/dist/frontend/lowering/lower-comptime.js +244 -0
  92. package/dist/frontend/lowering/lower-comptime.js.map +1 -0
  93. package/dist/frontend/lowering/lower-containers.d.ts +486 -0
  94. package/dist/frontend/lowering/lower-containers.js +6345 -0
  95. package/dist/frontend/lowering/lower-containers.js.map +1 -0
  96. package/dist/frontend/lowering/lower-dgram.d.ts +20 -0
  97. package/dist/frontend/lowering/lower-dgram.js +319 -0
  98. package/dist/frontend/lowering/lower-dgram.js.map +1 -0
  99. package/dist/frontend/lowering/lower-emitter.d.ts +10 -0
  100. package/dist/frontend/lowering/lower-emitter.js +688 -0
  101. package/dist/frontend/lowering/lower-emitter.js.map +1 -0
  102. package/dist/frontend/lowering/lower-enums.d.ts +22 -0
  103. package/dist/frontend/lowering/lower-enums.js +235 -0
  104. package/dist/frontend/lowering/lower-enums.js.map +1 -0
  105. package/dist/frontend/lowering/lower-expando.d.ts +35 -0
  106. package/dist/frontend/lowering/lower-expando.js +276 -0
  107. package/dist/frontend/lowering/lower-expando.js.map +1 -0
  108. package/dist/frontend/lowering/lower-exprs.d.ts +524 -0
  109. package/dist/frontend/lowering/lower-exprs.js +8111 -0
  110. package/dist/frontend/lowering/lower-exprs.js.map +1 -0
  111. package/dist/frontend/lowering/lower-generators.d.ts +50 -0
  112. package/dist/frontend/lowering/lower-generators.js +421 -0
  113. package/dist/frontend/lowering/lower-generators.js.map +1 -0
  114. package/dist/frontend/lowering/lower-inspect.d.ts +20 -0
  115. package/dist/frontend/lowering/lower-inspect.js +1074 -0
  116. package/dist/frontend/lowering/lower-inspect.js.map +1 -0
  117. package/dist/frontend/lowering/lower-island.d.ts +108 -0
  118. package/dist/frontend/lowering/lower-island.js +650 -0
  119. package/dist/frontend/lowering/lower-island.js.map +1 -0
  120. package/dist/frontend/lowering/lower-mixins.d.ts +96 -0
  121. package/dist/frontend/lowering/lower-mixins.js +534 -0
  122. package/dist/frontend/lowering/lower-mixins.js.map +1 -0
  123. package/dist/frontend/lowering/lower-modules.d.ts +135 -0
  124. package/dist/frontend/lowering/lower-modules.js +1613 -0
  125. package/dist/frontend/lowering/lower-modules.js.map +1 -0
  126. package/dist/frontend/lowering/lower-namespaces.d.ts +168 -0
  127. package/dist/frontend/lowering/lower-namespaces.js +706 -0
  128. package/dist/frontend/lowering/lower-namespaces.js.map +1 -0
  129. package/dist/frontend/lowering/lower-server.d.ts +90 -0
  130. package/dist/frontend/lowering/lower-server.js +3471 -0
  131. package/dist/frontend/lowering/lower-server.js.map +1 -0
  132. package/dist/frontend/lowering/lower-stmts.d.ts +361 -0
  133. package/dist/frontend/lowering/lower-stmts.js +5341 -0
  134. package/dist/frontend/lowering/lower-stmts.js.map +1 -0
  135. package/dist/frontend/lowering/lower-stream.d.ts +88 -0
  136. package/dist/frontend/lowering/lower-stream.js +1533 -0
  137. package/dist/frontend/lowering/lower-stream.js.map +1 -0
  138. package/dist/frontend/lowering/lower-test.d.ts +27 -0
  139. package/dist/frontend/lowering/lower-test.js +353 -0
  140. package/dist/frontend/lowering/lower-test.js.map +1 -0
  141. package/dist/frontend/lowering/lowerer.d.ts +1748 -0
  142. package/dist/frontend/lowering/lowerer.js +6257 -0
  143. package/dist/frontend/lowering/lowerer.js.map +1 -0
  144. package/dist/frontend/lowering/surfaces.d.ts +272 -0
  145. package/dist/frontend/lowering/surfaces.js +1096 -0
  146. package/dist/frontend/lowering/surfaces.js.map +1 -0
  147. package/dist/frontend/npm-static.d.ts +55 -0
  148. package/dist/frontend/npm-static.js +300 -0
  149. package/dist/frontend/npm-static.js.map +1 -0
  150. package/dist/frontend/npm.d.ts +330 -0
  151. package/dist/frontend/npm.js +1259 -0
  152. package/dist/frontend/npm.js.map +1 -0
  153. package/dist/frontend/program.d.ts +186 -0
  154. package/dist/frontend/program.js +2255 -0
  155. package/dist/frontend/program.js.map +1 -0
  156. package/dist/frontend/provenance-registry.d.ts +48 -0
  157. package/dist/frontend/provenance-registry.js +87 -0
  158. package/dist/frontend/provenance-registry.js.map +1 -0
  159. package/dist/frontend/provenance.d.ts +6 -0
  160. package/dist/frontend/provenance.js +459 -0
  161. package/dist/frontend/provenance.js.map +1 -0
  162. package/dist/frontend/resolve.d.ts +56 -0
  163. package/dist/frontend/resolve.js +682 -0
  164. package/dist/frontend/resolve.js.map +1 -0
  165. package/dist/frontend/shared.d.ts +67 -0
  166. package/dist/frontend/shared.js +241 -0
  167. package/dist/frontend/shared.js.map +1 -0
  168. package/dist/frontend/ts7/adapter.d.ts +7 -0
  169. package/dist/frontend/ts7/adapter.js +54 -0
  170. package/dist/frontend/ts7/adapter.js.map +1 -0
  171. package/dist/frontend/ts7/ast.d.ts +50 -0
  172. package/dist/frontend/ts7/ast.js +211 -0
  173. package/dist/frontend/ts7/ast.js.map +1 -0
  174. package/dist/frontend/ts7/census-check.d.ts +1 -0
  175. package/dist/frontend/ts7/census-check.js +12 -0
  176. package/dist/frontend/ts7/census-check.js.map +1 -0
  177. package/dist/frontend/ts7/checker.d.ts +140 -0
  178. package/dist/frontend/ts7/checker.js +544 -0
  179. package/dist/frontend/ts7/checker.js.map +1 -0
  180. package/dist/frontend/ts7/enums.d.ts +18 -0
  181. package/dist/frontend/ts7/enums.js +43 -0
  182. package/dist/frontend/ts7/enums.js.map +1 -0
  183. package/dist/frontend/ts7/program.d.ts +99 -0
  184. package/dist/frontend/ts7/program.js +278 -0
  185. package/dist/frontend/ts7/program.js.map +1 -0
  186. package/dist/frontend/ts7/world-check.d.ts +3 -0
  187. package/dist/frontend/ts7/world-check.js +34 -0
  188. package/dist/frontend/ts7/world-check.js.map +1 -0
  189. package/dist/frontend/types.d.ts +205 -0
  190. package/dist/frontend/types.js +2485 -0
  191. package/dist/frontend/types.js.map +1 -0
  192. package/dist/index.d.ts +85 -0
  193. package/dist/index.js +429 -0
  194. package/dist/index.js.map +1 -0
  195. package/dist/ir/nodes.d.ts +4334 -0
  196. package/dist/ir/nodes.js +1906 -0
  197. package/dist/ir/nodes.js.map +1 -0
  198. package/dist/ir/serialize.d.ts +4 -0
  199. package/dist/ir/serialize.js +34 -0
  200. package/dist/ir/serialize.js.map +1 -0
  201. package/dist/ir/validate.d.ts +36 -0
  202. package/dist/ir/validate.js +4885 -0
  203. package/dist/ir/validate.js.map +1 -0
  204. package/package.json +30 -6
  205. package/README.md +0 -3
  206. 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