@scriptc/compiler 0.2.1 → 0.2.3

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 (315) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +158 -31
  2. package/dist/backend/cycle-analysis.js +63 -50
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/cycle-analysis.test.js +51 -0
  5. package/dist/backend/cycle-analysis.test.js.map +1 -1
  6. package/dist/backend/llvm/borrowed-receivers.d.ts +9 -0
  7. package/dist/backend/llvm/borrowed-receivers.js +58 -0
  8. package/dist/backend/llvm/borrowed-receivers.js.map +1 -0
  9. package/dist/backend/llvm/call-lifetimes.d.ts +20 -0
  10. package/dist/backend/llvm/call-lifetimes.js +179 -0
  11. package/dist/backend/llvm/call-lifetimes.js.map +1 -0
  12. package/dist/backend/llvm/call-lifetimes.test.d.ts +1 -0
  13. package/dist/backend/llvm/call-lifetimes.test.js +205 -0
  14. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -0
  15. package/dist/backend/llvm/dyn.d.ts +5 -2
  16. package/dist/backend/llvm/dyn.js +163 -47
  17. package/dist/backend/llvm/dyn.js.map +1 -1
  18. package/dist/backend/llvm/emitter.d.ts +37 -1
  19. package/dist/backend/llvm/emitter.js +209 -21
  20. package/dist/backend/llvm/emitter.js.map +1 -1
  21. package/dist/backend/llvm/emitter.test.js +29 -2
  22. package/dist/backend/llvm/emitter.test.js.map +1 -1
  23. package/dist/backend/llvm/expr-async.js +1 -1
  24. package/dist/backend/llvm/expr-async.js.map +1 -1
  25. package/dist/backend/llvm/expr-calls.js +42 -5
  26. package/dist/backend/llvm/expr-calls.js.map +1 -1
  27. package/dist/backend/llvm/expr-containers.js +75 -13
  28. package/dist/backend/llvm/expr-containers.js.map +1 -1
  29. package/dist/backend/llvm/expr-dynamic.js +31 -6
  30. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  31. package/dist/backend/llvm/expr-primitives.js +6 -5
  32. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  33. package/dist/backend/llvm/expr-records.js +1 -1
  34. package/dist/backend/llvm/expr-records.js.map +1 -1
  35. package/dist/backend/llvm/expr-stream-bridges.js +75 -19
  36. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  37. package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
  38. package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
  39. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  40. package/dist/backend/llvm/lib-dispatch.js +41 -3
  41. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  42. package/dist/backend/llvm/lib-filesystem.js +12 -9
  43. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  44. package/dist/backend/llvm/lib-shared.js +70 -2
  45. package/dist/backend/llvm/lib-shared.js.map +1 -1
  46. package/dist/backend/llvm/local-array-reads.d.ts +44 -0
  47. package/dist/backend/llvm/local-array-reads.js +313 -0
  48. package/dist/backend/llvm/local-array-reads.js.map +1 -0
  49. package/dist/backend/llvm/local-array-reads.test.d.ts +1 -0
  50. package/dist/backend/llvm/local-array-reads.test.js +446 -0
  51. package/dist/backend/llvm/local-array-reads.test.js.map +1 -0
  52. package/dist/backend/llvm/map-read-lifetimes.d.ts +36 -0
  53. package/dist/backend/llvm/map-read-lifetimes.js +128 -0
  54. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -0
  55. package/dist/backend/llvm/map-read-lifetimes.test.d.ts +1 -0
  56. package/dist/backend/llvm/map-read-lifetimes.test.js +123 -0
  57. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -0
  58. package/dist/backend/llvm/shapes.js +1 -0
  59. package/dist/backend/llvm/shapes.js.map +1 -1
  60. package/dist/backend/llvm/split.js +15 -5
  61. package/dist/backend/llvm/split.js.map +1 -1
  62. package/dist/backend/llvm/split.test.js +17 -0
  63. package/dist/backend/llvm/split.test.js.map +1 -1
  64. package/dist/backend/llvm/stack-unions.d.ts +20 -0
  65. package/dist/backend/llvm/stack-unions.js +61 -0
  66. package/dist/backend/llvm/stack-unions.js.map +1 -0
  67. package/dist/backend/llvm/stack-unions.test.d.ts +1 -0
  68. package/dist/backend/llvm/stack-unions.test.js +241 -0
  69. package/dist/backend/llvm/stack-unions.test.js.map +1 -0
  70. package/dist/backend/llvm/string-lifetimes.d.ts +12 -0
  71. package/dist/backend/llvm/string-lifetimes.js +70 -0
  72. package/dist/backend/llvm/string-lifetimes.js.map +1 -0
  73. package/dist/backend/llvm/string-lifetimes.test.d.ts +1 -0
  74. package/dist/backend/llvm/string-lifetimes.test.js +230 -0
  75. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -0
  76. package/dist/backend/mangle.d.ts +2 -0
  77. package/dist/backend/mangle.js +4 -0
  78. package/dist/backend/mangle.js.map +1 -1
  79. package/dist/backend/may-throw.js +71 -29
  80. package/dist/backend/may-throw.js.map +1 -1
  81. package/dist/backend/may-throw.test.js +104 -1
  82. package/dist/backend/may-throw.test.js.map +1 -1
  83. package/dist/backend/native-codegen.d.ts +1 -1
  84. package/dist/backend/native-codegen.js +4 -3
  85. package/dist/backend/native-codegen.js.map +1 -1
  86. package/dist/backend/native-codegen.test.js +11 -0
  87. package/dist/backend/native-codegen.test.js.map +1 -1
  88. package/dist/backend/native-toolchain.d.ts +2 -2
  89. package/dist/backend/native-toolchain.js +2 -0
  90. package/dist/backend/native-toolchain.js.map +1 -1
  91. package/dist/backend/target-diagnostics.d.ts +5 -0
  92. package/dist/backend/target-diagnostics.js +72 -1
  93. package/dist/backend/target-diagnostics.js.map +1 -1
  94. package/dist/backend/target-diagnostics.test.d.ts +1 -0
  95. package/dist/backend/target-diagnostics.test.js +68 -0
  96. package/dist/backend/target-diagnostics.test.js.map +1 -0
  97. package/dist/coverage/surface-manifest.js +5 -3
  98. package/dist/coverage/surface-manifest.js.map +1 -1
  99. package/dist/executable/executable-cache.d.ts +7 -3
  100. package/dist/executable/executable-cache.js +47 -11
  101. package/dist/executable/executable-cache.js.map +1 -1
  102. package/dist/executable/executable-cache.test.js +109 -2
  103. package/dist/executable/executable-cache.test.js.map +1 -1
  104. package/dist/executable/prepare.js +2 -1
  105. package/dist/executable/prepare.js.map +1 -1
  106. package/dist/frontend/builtin-modules.d.ts +1 -1
  107. package/dist/frontend/builtin-modules.js +1 -1
  108. package/dist/frontend/builtin-modules.js.map +1 -1
  109. package/dist/frontend/function-completion.d.ts +6 -0
  110. package/dist/frontend/function-completion.js +50 -0
  111. package/dist/frontend/function-completion.js.map +1 -0
  112. package/dist/frontend/input-tracker.js +3 -3
  113. package/dist/frontend/input-tracker.js.map +1 -1
  114. package/dist/frontend/input-tracker.test.js +38 -2
  115. package/dist/frontend/input-tracker.test.js.map +1 -1
  116. package/dist/frontend/lowering/abstract-equality.js +5 -1
  117. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  118. package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
  119. package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
  120. package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
  121. package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
  122. package/dist/frontend/lowering/checked-promise-all.js +31 -0
  123. package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
  124. package/dist/frontend/lowering/class-callbacks.d.ts +1 -1
  125. package/dist/frontend/lowering/class-callbacks.js +7 -6
  126. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  127. package/dist/frontend/lowering/class-construction.d.ts +2 -0
  128. package/dist/frontend/lowering/class-construction.js +34 -5
  129. package/dist/frontend/lowering/class-construction.js.map +1 -1
  130. package/dist/frontend/lowering/class-descriptors.d.ts +1 -1
  131. package/dist/frontend/lowering/class-descriptors.js +12 -5
  132. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  133. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +25 -0
  134. package/dist/frontend/lowering/class-dynamic-dispatch.js +597 -78
  135. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  136. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +64 -2
  137. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  138. package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
  139. package/dist/frontend/lowering/class-instance-constructor.js +11 -41
  140. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  141. package/dist/frontend/lowering/class-method-values.d.ts +16 -0
  142. package/dist/frontend/lowering/class-method-values.js +60 -29
  143. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  144. package/dist/frontend/lowering/class-prototypes.d.ts +5 -1
  145. package/dist/frontend/lowering/class-prototypes.js +69 -10
  146. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  147. package/dist/frontend/lowering/class-runtime-statics.d.ts +4 -4
  148. package/dist/frontend/lowering/class-runtime-statics.js +26 -8
  149. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
  150. package/dist/frontend/lowering/class-static-data.d.ts +1 -0
  151. package/dist/frontend/lowering/class-static-data.js +4 -2
  152. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  153. package/dist/frontend/lowering/collection-ingestion.d.ts +31 -0
  154. package/dist/frontend/lowering/collection-ingestion.js +215 -0
  155. package/dist/frontend/lowering/collection-ingestion.js.map +1 -0
  156. package/dist/frontend/lowering/containers/bytes.js +19 -4
  157. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  158. package/dist/frontend/lowering/containers/string-and-regexp.js +6 -1
  159. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  160. package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
  161. package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
  162. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
  163. package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
  164. package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
  165. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
  166. package/dist/frontend/lowering/expressions/object-literals.js +31 -1
  167. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  168. package/dist/frontend/lowering/expressions/optional-chains.js +3 -3
  169. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  170. package/dist/frontend/lowering/import-meta.d.ts +10 -0
  171. package/dist/frontend/lowering/import-meta.js +52 -0
  172. package/dist/frontend/lowering/import-meta.js.map +1 -0
  173. package/dist/frontend/lowering/lower-assert.js +105 -41
  174. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  175. package/dist/frontend/lowering/lower-builtin-values.d.ts +2 -0
  176. package/dist/frontend/lowering/lower-builtin-values.js +22 -1
  177. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  178. package/dist/frontend/lowering/lower-builtins.d.ts +7 -22
  179. package/dist/frontend/lowering/lower-builtins.js +439 -95
  180. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  181. package/dist/frontend/lowering/lower-calls.js +289 -76
  182. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  183. package/dist/frontend/lowering/lower-classes.d.ts +5 -0
  184. package/dist/frontend/lowering/lower-classes.js +443 -29
  185. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  186. package/dist/frontend/lowering/lower-containers.d.ts +6 -2
  187. package/dist/frontend/lowering/lower-containers.js +79 -20
  188. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  189. package/dist/frontend/lowering/lower-exprs.d.ts +10 -6
  190. package/dist/frontend/lowering/lower-exprs.js +329 -170
  191. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  192. package/dist/frontend/lowering/lower-generators.js +5 -1
  193. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  194. package/dist/frontend/lowering/lower-inspect.js +58 -1
  195. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  196. package/dist/frontend/lowering/lower-island.js +4 -0
  197. package/dist/frontend/lowering/lower-island.js.map +1 -1
  198. package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
  199. package/dist/frontend/lowering/lower-island.test.js +51 -0
  200. package/dist/frontend/lowering/lower-island.test.js.map +1 -0
  201. package/dist/frontend/lowering/lower-modules.d.ts +1 -3
  202. package/dist/frontend/lowering/lower-modules.js +186 -82
  203. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  204. package/dist/frontend/lowering/lower-modules.test.js +69 -1
  205. package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
  206. package/dist/frontend/lowering/lower-stmts.js +172 -103
  207. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  208. package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
  209. package/dist/frontend/lowering/lower-stmts.test.js +77 -0
  210. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
  211. package/dist/frontend/lowering/lower-stream.js +2 -0
  212. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  213. package/dist/frontend/lowering/lower-system-errors.d.ts +6 -0
  214. package/dist/frontend/lowering/lower-system-errors.js +29 -0
  215. package/dist/frontend/lowering/lower-system-errors.js.map +1 -0
  216. package/dist/frontend/lowering/lower-url.d.ts +2 -1
  217. package/dist/frontend/lowering/lower-url.js +32 -9
  218. package/dist/frontend/lowering/lower-url.js.map +1 -1
  219. package/dist/frontend/lowering/lowerer.d.ts +30 -12
  220. package/dist/frontend/lowering/lowerer.js +268 -49
  221. package/dist/frontend/lowering/lowerer.js.map +1 -1
  222. package/dist/frontend/lowering/lowerer.test.js +38 -0
  223. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  224. package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
  225. package/dist/frontend/lowering/module-namespace-elements.js +54 -0
  226. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
  227. package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
  228. package/dist/frontend/lowering/object-factory-new.js +27 -14
  229. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  230. package/dist/frontend/lowering/surfaces.d.ts +3 -2
  231. package/dist/frontend/lowering/surfaces.js +93 -33
  232. package/dist/frontend/lowering/surfaces.js.map +1 -1
  233. package/dist/frontend/lowering/text-decoder-encoding.js +3 -0
  234. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  235. package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
  236. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
  237. package/dist/frontend/module-syntax.d.ts +1 -1
  238. package/dist/frontend/module-syntax.js +8 -1
  239. package/dist/frontend/module-syntax.js.map +1 -1
  240. package/dist/frontend/module-syntax.test.js +10 -0
  241. package/dist/frontend/module-syntax.test.js.map +1 -1
  242. package/dist/frontend/npm.d.ts +4 -0
  243. package/dist/frontend/npm.js +86 -33
  244. package/dist/frontend/npm.js.map +1 -1
  245. package/dist/frontend/npm.test.js +103 -0
  246. package/dist/frontend/npm.test.js.map +1 -1
  247. package/dist/frontend/pipeline-native.js +2 -1
  248. package/dist/frontend/pipeline-native.js.map +1 -1
  249. package/dist/frontend/program.js +4 -2
  250. package/dist/frontend/program.js.map +1 -1
  251. package/dist/frontend/services-node.js +3 -2
  252. package/dist/frontend/services-node.js.map +1 -1
  253. package/dist/frontend/services.d.ts +5 -1
  254. package/dist/frontend/services.js +9 -1
  255. package/dist/frontend/services.js.map +1 -1
  256. package/dist/frontend/services.test.js +21 -0
  257. package/dist/frontend/services.test.js.map +1 -1
  258. package/dist/frontend/ts7/ast-node.d.ts +2 -0
  259. package/dist/frontend/ts7/ast-node.js +30 -4
  260. package/dist/frontend/ts7/ast-node.js.map +1 -1
  261. package/dist/frontend/ts7/ast-node.test.js +60 -1
  262. package/dist/frontend/ts7/ast-node.test.js.map +1 -1
  263. package/dist/frontend/type-mapper.js +89 -14
  264. package/dist/frontend/type-mapper.js.map +1 -1
  265. package/dist/frontend/union-discriminants.js +22 -7
  266. package/dist/frontend/union-discriminants.js.map +1 -1
  267. package/dist/index.js +19 -12
  268. package/dist/index.js.map +1 -1
  269. package/dist/ir/analysis.js +1 -0
  270. package/dist/ir/analysis.js.map +1 -1
  271. package/dist/ir/integer-loops.d.ts +7 -0
  272. package/dist/ir/integer-loops.js +23 -0
  273. package/dist/ir/integer-loops.js.map +1 -1
  274. package/dist/ir/integer-loops.test.d.ts +1 -0
  275. package/dist/ir/integer-loops.test.js +41 -0
  276. package/dist/ir/integer-loops.test.js.map +1 -0
  277. package/dist/ir/ir.d.ts +44 -26
  278. package/dist/ir/ir.js +69 -11
  279. package/dist/ir/ir.js.map +1 -1
  280. package/dist/ir/ir.test.js +18 -0
  281. package/dist/ir/ir.test.js.map +1 -1
  282. package/dist/ir/serialize.js +21 -1
  283. package/dist/ir/serialize.js.map +1 -1
  284. package/dist/ir/serialize.test.js +21 -0
  285. package/dist/ir/serialize.test.js.map +1 -1
  286. package/dist/ir/traverse.d.ts +0 -3
  287. package/dist/ir/traverse.js +33 -20
  288. package/dist/ir/traverse.js.map +1 -1
  289. package/dist/ir/validate.js +216 -80
  290. package/dist/ir/validate.js.map +1 -1
  291. package/dist/ir/validate.test.js +244 -1
  292. package/dist/ir/validate.test.js.map +1 -1
  293. package/dist/library/compiler-self-identity.js +1 -1
  294. package/dist/library/compiler-self-identity.test.js +2 -2
  295. package/dist/library/compiler-self-identity.test.js.map +1 -1
  296. package/dist/library/fence-eval.js +9 -2
  297. package/dist/library/fence-eval.js.map +1 -1
  298. package/dist/library/fence-eval.test.d.ts +1 -0
  299. package/dist/library/fence-eval.test.js +21 -0
  300. package/dist/library/fence-eval.test.js.map +1 -0
  301. package/dist/library/int-infer.d.ts +2 -2
  302. package/dist/library/int-infer.js +10 -7
  303. package/dist/library/int-infer.js.map +1 -1
  304. package/dist/library/int-infer.test.js +44 -0
  305. package/dist/library/int-infer.test.js.map +1 -1
  306. package/dist/library/prepare.js +2 -1
  307. package/dist/library/prepare.js.map +1 -1
  308. package/dist/native/runtime-typescript.d.ts +4 -0
  309. package/dist/native/runtime-typescript.js +61 -0
  310. package/dist/native/runtime-typescript.js.map +1 -0
  311. package/dist/native/runtime-typescript.test.d.ts +1 -0
  312. package/dist/native/runtime-typescript.test.js +41 -0
  313. package/dist/native/runtime-typescript.test.js.map +1 -0
  314. package/package.json +20 -20
  315. package/surface-manifest.json +385 -29
@@ -2,7 +2,10 @@ import type { IrBytesElem, IrExpr, IrFfiImport, IrFunction, IrLocal, IrModule, I
2
2
  import { type IntegerRanges } from "../../ir/integer-ranges.js";
3
3
  import { type ConstantNumericTable } from "../../ir/constant-tables.js";
4
4
  import { type FfiCallbackAdapter } from "../ffi-callbacks.js";
5
+ import { type CallLifetimes } from "./call-lifetimes.js";
5
6
  import { BlockBuilder } from "./blocks.js";
7
+ import { type LocalArrayRead } from "./local-array-reads.js";
8
+ import { type MapReadLifetimes } from "./map-read-lifetimes.js";
6
9
  import { type LlClassMeta } from "./classes.js";
7
10
  import { LlDyn, type DynHost } from "./dyn.js";
8
11
  import { LlWalkers } from "./walkers.js";
@@ -25,8 +28,23 @@ export interface LlvmTargetOptions {
25
28
  runtimeAbiMarker?: boolean;
26
29
  }
27
30
  export declare function emitLlvmModule(mod: IrModule, options?: LlvmTargetOptions): string;
31
+ /** Keep large translation units below the host's single-string limit. */
32
+ export declare function emitLlvmModuleSource(mod: IrModule, options?: LlvmTargetOptions): string | readonly string[];
28
33
  export declare class LlEmitter {
29
34
  readonly mod: IrModule;
35
+ localArrayReads: Map<string, LocalArrayRead>;
36
+ private localStackUnions;
37
+ integerArrayBindings: Set<string>;
38
+ private readonly fieldAliasTags;
39
+ private readonly fieldPointerTags;
40
+ /** Native class fields with different property names cannot occupy the
41
+ * same slot of one object. Inherited views of the same property share a
42
+ * tag. Array storage has its own disjoint categories; untagged runtime
43
+ * operations and record views conservatively alias all of them. */
44
+ private markFieldPointer;
45
+ markMemoryPointer(ptr: string, field: string): void;
46
+ fieldAliasAttachment(ptr: string): string;
47
+ private fieldAliasMetadata;
30
48
  private readonly debug;
31
49
  private debugScope;
32
50
  readonly sizeType: "i32" | "i64";
@@ -82,6 +100,12 @@ export declare class LlEmitter {
82
100
  needsBadKey: boolean;
83
101
  private needsRetainBox;
84
102
  readonly fnByName: Map<string, IrFunction>;
103
+ private readonly arrayPreservingFunctions;
104
+ private readonly optionalArrayReads;
105
+ callArrayReads: Map<IrExpr, LocalArrayRead>;
106
+ mapReadLifetimes: MapReadLifetimes;
107
+ readonly callLifetimes: CallLifetimes;
108
+ private borrowedParameters;
85
109
  /** Manifest-bound native imports, used by ffiCall emission. */
86
110
  readonly ffiByName: Map<string, IrFfiImport>;
87
111
  /** C-ABI callback trampolines and (for raw/no-userdata callbacks) their
@@ -216,6 +240,7 @@ export declare class LlEmitter {
216
240
  * outer native call. */
217
241
  private emitFfiCallbackDefs;
218
242
  emit(): string;
243
+ emitParts(): string[];
219
244
  /** LIBRARY mode: the profile-declared external definitions — the
220
245
  * export-map wrappers plus init / sink-registration / reset / collect.
221
246
  * Plain `define` (not `define internal`) — the exact linkage distinction
@@ -409,6 +434,16 @@ export declare class LlEmitter {
409
434
  /** Move a clean async return value into the current fiber's promise. */
410
435
  private emitWasiFulfill;
411
436
  private emitFunction;
437
+ /** Keep the ordinary owned ABI for closures, virtual dispatch, generated
438
+ * runtime adapters and library exports. Only direct IR calls select the
439
+ * borrowing body. Ownership of other parameters moves into that body;
440
+ * borrowed parameters are released here on normal and exceptional exits.
441
+ * The pending exception remains for the adapter's caller to handle. */
442
+ private emitOwnedCallAdapter;
443
+ /** A local immutable binding keeps its value alive while later arguments
444
+ * and the callee execute. Global, captured, TDZ and mutable bindings need
445
+ * an owned snapshot, even when the callee only inspects the value. */
446
+ canBorrowCallArgument(value: IrExpr): boolean;
412
447
  private emitStmts;
413
448
  /** Emits a block in its own lexical scope (refcounted locals released at
414
449
  * end). `setup` runs after the
@@ -484,6 +519,7 @@ export declare class LlEmitter {
484
519
  * their ordinary statement-frame ownership. The caller must retain any
485
520
  * reference result before evaluating another expression. */
486
521
  emitReadReceiver(e: IrExpr): LlValue;
522
+ canBorrowReceiver(e: IrExpr): boolean;
487
523
  emitExpr(e: IrExpr): LlValue;
488
524
  emitJsMarshal(e: IrExpr & {
489
525
  kind: "jsMarshal";
@@ -538,7 +574,7 @@ export declare class LlEmitter {
538
574
  }): string;
539
575
  cryptoBytesThunkFor(cbT: IrType & {
540
576
  kind: "func";
541
- }): string;
577
+ }, arrayBuffer?: boolean): string;
542
578
  zlibBytesThunkFor(cbT: IrType & {
543
579
  kind: "func";
544
580
  }): string;
@@ -22,7 +22,7 @@ import { deflateRawSync } from "node:zlib";
22
22
  import { endsWithJump, matchStringSelfConcat, streamTypedRefEligible } from "../../ir/analysis.js";
23
23
  import { emitLibraryIdentityLines } from "../library-identity-markers.js";
24
24
  import { CAUGHT, ffiCallbackType, isDynTypedRefType, isFfiContextParam, isRefCounted, isUnitType, moduleRuntimeFeatures, moduleEmbedsBuiltin, moduleEmbedsCompressedNpm, NPM_COMPRESS_MIN, POINTER_KINDS, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, typeKey, VOID } from "../../ir/ir.js";
25
- import { matchIntegerBytesForLoop } from "../../ir/integer-loops.js";
25
+ import { matchIntegerArrayForLoop, matchIntegerBytesForLoop } from "../../ir/integer-loops.js";
26
26
  import { scalarizeNumericRecords } from "../../ir/scalar-records.js";
27
27
  import { everyStmtList } from "../../ir/traverse.js";
28
28
  import { analyzeIntegerRanges } from "../../ir/integer-ranges.js";
@@ -30,8 +30,13 @@ import { findConstantNumericTables } from "../../ir/constant-tables.js";
30
30
  import { allocateFfiCallbackAdapters, hasForeignFfiCallback, hasRetainedFfiCallback } from "../ffi-callbacks.js";
31
31
  import { RUNTIME_ABI_MARKER } from "../runtime-abi.js";
32
32
  import { computeMayThrow } from "../may-throw.js";
33
- import { mangleArgPack, mangleAsyncSpawn, mangleClassObj, mangleClassStruct, mangleFnClosure, mangleFunction, mangleGenDrop, mangleGenSpawn, mangleGlobal, mangleLocal, mangleRecordStruct, mangleTrampoline, mangleWrapper, mangleVtInstance } from "../mangle.js";
33
+ import { mangleArgPack, mangleAsyncSpawn, mangleBorrowedFunction, mangleClassObj, mangleClassStruct, mangleFnClosure, mangleFunction, mangleGenDrop, mangleGenSpawn, mangleGlobal, mangleLocal, mangleRecordStruct, mangleTrampoline, mangleWrapper, mangleVtInstance } from "../mangle.js";
34
+ import { analyzeCallLifetimes } from "./call-lifetimes.js";
35
+ import { emitStackUnion, findLocalStackUnions } from "./stack-unions.js";
34
36
  import { BlockBuilder } from "./blocks.js";
37
+ import { emitLocalArrayRead, findArrayPreservingFunctions, findLocalArrayReads, findCallArrayReads, OptionalArrayReads } from "./local-array-reads.js";
38
+ import { emitStackMapRead, findMapReadLifetimes } from "./map-read-lifetimes.js";
39
+ import { emitBorrowedFieldSequence } from "./borrowed-receivers.js";
35
40
  import { LlvmDebugInfo } from "./debug-info.js";
36
41
  import { f64Lit, ffiNativeTypeLl, ffiNativeParamLl, ffiNativeReturnLl, llvmCommentText } from "./common.js";
37
42
  import { ffiExtendsNarrowIntegers } from "../targets.js";
@@ -88,11 +93,54 @@ export function emitLlvmModule(mod, options = {}) {
88
93
  // Keep source storage intact for debugger inspection in dev builds.
89
94
  return new LlEmitter(options.debugSources === undefined ? scalarizeNumericRecords(mod) : mod, options).emit();
90
95
  }
96
+ /** Keep large translation units below the host's single-string limit. */
97
+ export function emitLlvmModuleSource(mod, options = {}) {
98
+ const parts = new LlEmitter(options.debugSources === undefined ? scalarizeNumericRecords(mod) : mod, options).emitParts();
99
+ const length = parts.reduce((total, part) => total + part.length, Math.max(0, parts.length - 1));
100
+ if (length <= 256 * 1024 * 1024)
101
+ return parts.join("\n");
102
+ return parts.flatMap((part, index) => index === 0 ? [part] : ["\n", part]);
103
+ }
91
104
  function llStrBytes(text) {
92
105
  return llBytes(Buffer.from(text, "utf8"));
93
106
  }
94
107
  export class LlEmitter {
95
108
  mod;
109
+ localArrayReads = new Map();
110
+ localStackUnions = new Map();
111
+ integerArrayBindings = new Set();
112
+ fieldAliasTags = new Map();
113
+ fieldPointerTags = new Map();
114
+ /** Native class fields with different property names cannot occupy the
115
+ * same slot of one object. Inherited views of the same property share a
116
+ * tag. Array storage has its own disjoint categories; untagged runtime
117
+ * operations and record views conservatively alias all of them. */
118
+ markFieldPointer(ptr, field) {
119
+ this.markMemoryPointer(ptr, `field:${field}`);
120
+ }
121
+ markMemoryPointer(ptr, field) {
122
+ if (this.debug !== null)
123
+ return;
124
+ let tag = this.fieldAliasTags.get(field);
125
+ if (tag === undefined) {
126
+ tag = 2 + this.fieldAliasTags.size * 2;
127
+ this.fieldAliasTags.set(field, tag);
128
+ }
129
+ this.fieldPointerTags.set(ptr, tag);
130
+ }
131
+ fieldAliasAttachment(ptr) {
132
+ const tag = this.fieldPointerTags.get(ptr);
133
+ return tag === undefined ? "" : `, !tbaa !${tag}`;
134
+ }
135
+ fieldAliasMetadata() {
136
+ if (this.fieldAliasTags.size === 0)
137
+ return [];
138
+ const lines = ['!0 = !{!"scriptc native fields"}'];
139
+ for (const tag of this.fieldAliasTags.values()) {
140
+ lines.push(`!${tag - 1} = !{!"field.${tag}", !0, i64 0}`, `!${tag} = !{!${tag - 1}, !${tag - 1}, i64 0}`);
141
+ }
142
+ return lines;
143
+ }
96
144
  debug;
97
145
  debugScope = null;
98
146
  sizeType;
@@ -141,6 +189,12 @@ export class LlEmitter {
141
189
  needsBadKey = false;
142
190
  needsRetainBox = false;
143
191
  fnByName = new Map();
192
+ arrayPreservingFunctions;
193
+ optionalArrayReads;
194
+ callArrayReads = new Map();
195
+ mapReadLifetimes = { locals: new Map(), arguments: new Map() };
196
+ callLifetimes;
197
+ borrowedParameters = new Set();
144
198
  /** Manifest-bound native imports, used by ffiCall emission. */
145
199
  ffiByName = new Map();
146
200
  /** C-ABI callback trampolines and (for raw/no-userdata callbacks) their
@@ -290,6 +344,9 @@ export class LlEmitter {
290
344
  }
291
345
  for (const u of mod.unions ?? [])
292
346
  this.unionsById.set(u.id, u);
347
+ this.optionalArrayReads = new OptionalArrayReads(this.fnByName, this.unionsById);
348
+ this.arrayPreservingFunctions = findArrayPreservingFunctions(this.fnByName, this.unionsById, this.optionalArrayReads);
349
+ this.callLifetimes = analyzeCallLifetimes(this.fnByName);
293
350
  for (const r of mod.records ?? [])
294
351
  this.recordsById.set(r.id, r);
295
352
  const traced = computeTraced(mod);
@@ -310,6 +367,7 @@ export class LlEmitter {
310
367
  cstr: (text) => this.cstr(text),
311
368
  unitInstanceRef: (unionId, tag) => this.unitInstanceRef(unionId, tag),
312
369
  liveDynRefAdapter: (type) => this.liveDynRefAdapter(type),
370
+ liveDynUnionRefAdapter: (type) => this.liveDynUnionRefAdapter(type),
313
371
  dynPromiseAdapter: (type) => this.dynPromiseAdapter(type),
314
372
  isErrorClass: (name) => this.classMeta.get(name)?.root.def.name === "%Error",
315
373
  classSubtypes: (name) => {
@@ -671,6 +729,9 @@ export class LlEmitter {
671
729
  return { globals, defs };
672
730
  }
673
731
  emit() {
732
+ return this.emitParts().join("\n");
733
+ }
734
+ emitParts() {
674
735
  // Function bodies first (the literal/unit/fn-value tables fill as they
675
736
  // emit), then the file assembles around them — the runtime ABI’s order.
676
737
  const fnDefs = [];
@@ -837,6 +898,7 @@ export class LlEmitter {
837
898
  this.declare(`declare void @scr_net_island_install()`);
838
899
  if (usesIsland) {
839
900
  this.declare(`declare void @scr_island_modules(ptr, ${this.sizeType}, ptr, ${this.sizeType})`);
901
+ this.declare(`declare void @scr_island_entry_module(ptr)`);
840
902
  this.declare(`declare i32 @scr_island_exit_code()`);
841
903
  if (moduleEmbedsCompressedNpm(this.mod)) {
842
904
  this.declare(`declare void @scr_island_set_inflate(ptr)`);
@@ -1104,6 +1166,7 @@ export class LlEmitter {
1104
1166
  }
1105
1167
  if (this.templateStringsInstances.size > 0)
1106
1168
  out.push(``);
1169
+ const islandEntryPath = usesIsland ? this.cstr(this.mod.sourceFile) : null;
1107
1170
  for (const [text, c] of this.cstrs) {
1108
1171
  // NUL-terminated byte-array constants for scr_jb_puts and indentation.
1109
1172
  out.push(`@${c.sym} = internal constant [${c.len + 1} x i8] c"${llStrBytes(text)}"`);
@@ -1177,7 +1240,10 @@ export class LlEmitter {
1177
1240
  out.push(line);
1178
1241
  for (const line of this.resolveThunkDefs)
1179
1242
  out.push(line);
1180
- out.push(fnDefs.join("\n\n"), ``);
1243
+ out.push(fnDefs[0] ?? "");
1244
+ for (let i = 1; i < fnDefs.length; i++)
1245
+ out.push("", fnDefs[i]);
1246
+ out.push("");
1181
1247
  // main(): scr_init, the program-dependent error-vt interval stamps,
1182
1248
  // scr_lib_init(argc, argv), then the entry function. An uncaught
1183
1249
  // exception escaping top-level code prints and exits 1 (Node).
@@ -1232,9 +1298,10 @@ export class LlEmitter {
1232
1298
  if (hasNoInlineRecordClone)
1233
1299
  out.push(`attributes #2 = { noinline sanitize_address }`);
1234
1300
  out.push(``);
1301
+ out.push(...this.fieldAliasMetadata());
1235
1302
  if (this.debug !== null)
1236
1303
  out.push(this.debug.render());
1237
- return out.join("\n");
1304
+ return out;
1238
1305
  }
1239
1306
  out.push(`define i32 @${this.wasi ? "__main_argc_argv" : "main"}(i32 %argc, ptr %argv) ${FN_ATTRS} {`, `entry:`, ...(this.runtimeAbiMarker ? [` call void @${RUNTIME_ABI_MARKER}()`] : []), ` call void @scr_init()`, ...stamps,
1240
1307
  // Event-surface programs (signal/exit listeners) fill the loop's
@@ -1245,6 +1312,7 @@ export class LlEmitter {
1245
1312
  // scr_watch.c links only when this line is emitted.
1246
1313
  ...(usesFsWatch ? [` call void @scr_watch_install()`] : []), ...(this.ffiHasForeignCallback ? [` call void @scr_ffi_install()`] : []), ...(snapshotsTlsCa ? [` call void @scr_tls_ca_install()`] : []), ...(usesFetch ? [` call void @scr_fetch_install()`] : []), ...(embedsZlib ? [` call void @scr_zlib_island_install()`] : []), ...(embedsNet ? [` call void @scr_net_island_install()`] : []), ...(usesNet ? [` call void @scr_net_install()`, ` call void @scr_net_dyn_install()`] : []), ...(usesHttp ? [` call void @scr_http_dyn_install()`] : []), ...(usesDgram ? [` call void @scr_dgram_install()`] : []), ...(usesHttp2 ? [` call void @scr_http2_dyn_install()`] : []), ...(usesStream ? [` call void @scr_stream_install()`] : []), ` call void @scr_lib_init(i32 %argc, ptr %argv)`, ...(usesIsland
1247
1314
  ? [
1315
+ ` call void @scr_island_entry_module(ptr ${islandEntryPath})`,
1248
1316
  ...(moduleEmbedsCompressedNpm(this.mod)
1249
1317
  ? [` call void @scr_island_set_inflate(ptr @scr_zlib_inflate_exact)`]
1250
1318
  : []),
@@ -1344,9 +1412,10 @@ export class LlEmitter {
1344
1412
  // lane's -fsanitize=address link activates instrumentation over the
1345
1413
  // emitted functions too (the runtime TUs get theirs from clang).
1346
1414
  `attributes #0 = { sanitize_address }`, ...(this.wasi ? [`attributes #1 = { sanitize_address presplitcoroutine }`] : []), ...(hasNoInlineRecordClone ? [`attributes #2 = { noinline sanitize_address }`] : []), ``);
1415
+ out.push(...this.fieldAliasMetadata());
1347
1416
  if (this.debug !== null)
1348
1417
  out.push(this.debug.render());
1349
- return out.join("\n");
1418
+ return out;
1350
1419
  }
1351
1420
  /** LIBRARY mode: the profile-declared external definitions — the
1352
1421
  * export-map wrappers plus init / sink-registration / reset / collect.
@@ -2403,7 +2472,7 @@ export class LlEmitter {
2403
2472
  * a retained peek. */
2404
2473
  unionExtract(uName, arm) {
2405
2474
  const B = this.B;
2406
- if (arm.kind === "f64") {
2475
+ if (arm.kind === "f64" || arm.kind === "procStream") {
2407
2476
  const t = B.tmp();
2408
2477
  this.declare(`declare double @scr_union_get_f64(ptr)`);
2409
2478
  B.line(`${t} = call double @scr_union_get_f64(ptr ${uName})`);
@@ -2423,7 +2492,7 @@ export class LlEmitter {
2423
2492
  unionNewOwned(tag, v) {
2424
2493
  const B = this.B;
2425
2494
  const t = B.tmp();
2426
- if (v.type.kind === "f64") {
2495
+ if (v.type.kind === "f64" || v.type.kind === "procStream") {
2427
2496
  this.declare(`declare ptr @scr_union_new_f64(i32, double)`);
2428
2497
  B.line(`${t} = call ptr @scr_union_new_f64(i32 ${tag}, double ${v.name})`);
2429
2498
  return t;
@@ -2454,6 +2523,7 @@ export class LlEmitter {
2454
2523
  const { index, type } = classFieldIndex(meta, field);
2455
2524
  const p = this.B.tmp();
2456
2525
  this.B.line(`${p} = getelementptr inbounds %${classStructSym(className)}, ptr ${objName}, i64 0, i32 ${index}`);
2526
+ this.markFieldPointer(p, field);
2457
2527
  return { ptr: p, type };
2458
2528
  }
2459
2529
  /** `o->vt->pre` — the dynamic class's preorder number (borrowed object;
@@ -2544,7 +2614,7 @@ export class LlEmitter {
2544
2614
  const B = this.B;
2545
2615
  const fieldTy = llFieldType(t);
2546
2616
  const raw = B.tmp();
2547
- B.line(`${raw} = load ${fieldTy}, ptr ${ptr}`);
2617
+ B.line(`${raw} = load ${fieldTy}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
2548
2618
  if (fieldTy !== "i8")
2549
2619
  return raw;
2550
2620
  const b = B.tmp();
@@ -2556,12 +2626,12 @@ export class LlEmitter {
2556
2626
  const B = this.B;
2557
2627
  const fieldTy = llFieldType(t);
2558
2628
  if (fieldTy !== "i8") {
2559
- B.line(`store ${fieldTy} ${value}, ptr ${ptr}`);
2629
+ B.line(`store ${fieldTy} ${value}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
2560
2630
  return;
2561
2631
  }
2562
2632
  const z = B.tmp();
2563
2633
  B.line(`${z} = zext i1 ${value} to i8`);
2564
- B.line(`store i8 ${z}, ptr ${ptr}`);
2634
+ B.line(`store i8 ${z}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
2565
2635
  }
2566
2636
  // ── bindings ────────────────────────────────────────────────────────────
2567
2637
  /** A binding's storage: a module global, a plain local slot, or a boxed
@@ -2841,8 +2911,20 @@ export class LlEmitter {
2841
2911
  this.unwindCleanups.clear();
2842
2912
  this.jumpTargets = [];
2843
2913
  this.currentLocals = new Map(fn.locals.map((l) => [l.id, l]));
2914
+ this.borrowedParameters.clear();
2915
+ const borrowedParameterIndexes = this.callLifetimes.parameters.get(fn.name);
2916
+ if (borrowedParameterIndexes) {
2917
+ for (const index of borrowedParameterIndexes)
2918
+ this.borrowedParameters.add(fn.params[index].localId);
2919
+ }
2844
2920
  this.captureIds = new Set([...(fn.captures ?? []), ...(fn.classCaptures ?? [])].map((c) => c.localId));
2845
2921
  this.integerLoopBindings.clear();
2922
+ this.fieldPointerTags.clear();
2923
+ this.integerArrayBindings.clear();
2924
+ this.localArrayReads = findLocalArrayReads(fn, this.fnByName, this.unionsById, this.arrayPreservingFunctions, this.callLifetimes, this.optionalArrayReads);
2925
+ this.callArrayReads = findCallArrayReads(fn, this.optionalArrayReads, this.arrayPreservingFunctions, this.callLifetimes);
2926
+ this.mapReadLifetimes = findMapReadLifetimes(fn, this.unionsById, this.callLifetimes);
2927
+ this.localStackUnions = findLocalStackUnions(fn, this.callLifetimes, this.unionsById);
2846
2928
  this.integerRanges = analyzeIntegerRanges(fn);
2847
2929
  this.chainSlots.clear();
2848
2930
  this.finallyStack = [];
@@ -2934,7 +3016,8 @@ export class LlEmitter {
2934
3016
  // params (callees own their params — callers passed +1). Boxed params
2935
3017
  // allocate the shared binding and move the raw value in.
2936
3018
  const fnScope = [];
2937
- for (const p of fn.params) {
3019
+ const borrowed = this.callLifetimes.parameters.get(fn.name);
3020
+ for (const [index, p] of fn.params.entries()) {
2938
3021
  const local = this.currentLocals.get(p.localId);
2939
3022
  const slot = `%${mangleLocal(p.localId)}`;
2940
3023
  if (local.boxed) {
@@ -2946,7 +3029,7 @@ export class LlEmitter {
2946
3029
  continue;
2947
3030
  }
2948
3031
  B.line(`store ${this.llType(p.type)} %p_${mangleLocal(p.localId)}, ptr ${slot}`);
2949
- if (isRefCounted(p.type))
3032
+ if (isRefCounted(p.type) && !borrowed?.has(index))
2950
3033
  fnScope.push({ slot, type: p.type });
2951
3034
  }
2952
3035
  this.scopes.push(fnScope);
@@ -3028,7 +3111,38 @@ export class LlEmitter {
3028
3111
  const ret = this.llType(fn.returnType);
3029
3112
  const attrs = coro !== null ? "#1" : FN_ATTRS;
3030
3113
  const debug = this.debugScope === null ? "" : ` !dbg ${this.debugScope}`;
3031
- return `define internal ${ret} @${mangleFunction(fn.name)}(${params.join(", ")}) ${attrs}${debug} { ; ${fn.name}\n${B.render()}\n}`;
3114
+ const symbol = borrowed ? mangleBorrowedFunction(fn.name) : mangleFunction(fn.name);
3115
+ const body = `define internal ${ret} @${symbol}(${params.join(", ")}) ${attrs}${debug} { ; ${fn.name}\n${B.render()}\n}`;
3116
+ return borrowed ? body + "\n" + this.emitOwnedCallAdapter(fn, borrowed) : body;
3117
+ }
3118
+ /** Keep the ordinary owned ABI for closures, virtual dispatch, generated
3119
+ * runtime adapters and library exports. Only direct IR calls select the
3120
+ * borrowing body. Ownership of other parameters moves into that body;
3121
+ * borrowed parameters are released here on normal and exceptional exits.
3122
+ * The pending exception remains for the adapter's caller to handle. */
3123
+ emitOwnedCallAdapter(fn, borrowed) {
3124
+ const B = new BlockBuilder();
3125
+ this.B = B;
3126
+ const params = fn.params.map((param, index) => `${this.llType(param.type)} %p${index}`);
3127
+ const ret = this.llType(fn.returnType);
3128
+ const call = `call ${ret} @${mangleBorrowedFunction(fn.name)}(${params.join(", ")})`;
3129
+ B.line(ret === "void" ? call : `%result = ${call}`);
3130
+ for (const index of borrowed)
3131
+ this.releaseValue(`%p${index}`, fn.params[index].type);
3132
+ B.terminate(ret === "void" ? "ret void" : `ret ${ret} %result`);
3133
+ return `define internal ${ret} @${mangleFunction(fn.name)}(${params.join(", ")}) ${FN_ATTRS} {\n${B.render()}\n}`;
3134
+ }
3135
+ /** A local immutable binding keeps its value alive while later arguments
3136
+ * and the callee execute. Global, captured, TDZ and mutable bindings need
3137
+ * an owned snapshot, even when the callee only inspects the value. */
3138
+ canBorrowCallArgument(value) {
3139
+ if (value.kind === "strLit")
3140
+ return true;
3141
+ if (value.kind !== "varRef")
3142
+ return false;
3143
+ const binding = this.binding(value.localId);
3144
+ return binding.kind === "local" && binding.local !== undefined &&
3145
+ (!binding.local.mutable || this.borrowedParameters.has(value.localId)) && !binding.local.boxed && !binding.local.tdz;
3032
3146
  }
3033
3147
  // ── statements ──────────────────────────────────────────────────────────
3034
3148
  emitStmts(stmts) {
@@ -3072,6 +3186,31 @@ export class LlEmitter {
3072
3186
  switch (s.kind) {
3073
3187
  case "varDecl": {
3074
3188
  const b = this.binding(s.localId);
3189
+ const localUnion = this.localStackUnions.get(s.localId);
3190
+ if (localUnion) {
3191
+ const union = emitStackUnion(this, localUnion);
3192
+ B.line(`store ptr ${union.value.name}, ptr ${b.slot}`);
3193
+ if (union.payload) {
3194
+ this.moveTemp(union.payload);
3195
+ this.scopes[this.scopes.length - 1].push({ slot: union.payloadSlot, type: union.payload.type });
3196
+ }
3197
+ break;
3198
+ }
3199
+ const localRead = this.localArrayReads.get(s.localId);
3200
+ if (localRead) {
3201
+ const owner = emitLocalArrayRead(this, localRead, b.slot);
3202
+ if (owner)
3203
+ this.scopes[this.scopes.length - 1].push(owner);
3204
+ break;
3205
+ }
3206
+ const mapRead = this.mapReadLifetimes.locals.get(s.localId);
3207
+ if (mapRead) {
3208
+ const result = emitStackMapRead(this, mapRead);
3209
+ B.line(`store ptr ${result.value.name}, ptr ${b.slot}`);
3210
+ if (result.owner)
3211
+ this.scopes[this.scopes.length - 1].push(result.owner);
3212
+ break;
3213
+ }
3075
3214
  if (b.kind === "boxed") {
3076
3215
  // Box FIRST, then evaluate the initializer: a named function
3077
3216
  // expression's closure captures this box during init evaluation.
@@ -3210,7 +3349,7 @@ export class LlEmitter {
3210
3349
  // release — a release can trigger a cycle collection, which must
3211
3350
  // never see a heap edge whose count was already given up).
3212
3351
  // Classes and records share the struct layout, so one emission.
3213
- const obj = this.emitExpr(s.obj);
3352
+ const obj = isRefCounted(s.value.type) ? this.emitExpr(s.obj) : this.emitStableReceiver(s.obj, [s.value]);
3214
3353
  const v = this.emitExpr(s.value);
3215
3354
  const { ptr, type } = s.kind === "fieldSet"
3216
3355
  ? this.classFieldPtr(obj.name, s.className, s.field)
@@ -3471,13 +3610,21 @@ export class LlEmitter {
3471
3610
  case "for": {
3472
3611
  // The init's scope wraps the whole loop (break/continue must NOT
3473
3612
  // release it — scopeDepth captured after the push, C parity).
3474
- const integerLoop = this.debug === null ? matchIntegerBytesForLoop(s, this.currentLocals) : null;
3613
+ const integerArrayLoop = this.debug === null ? matchIntegerArrayForLoop(s, this.currentLocals, this.integerArrayBindings) : null;
3614
+ const integerLoop = integerArrayLoop ?? (this.debug === null ? matchIntegerBytesForLoop(s, this.currentLocals) : null);
3475
3615
  this.scopes.push([]);
3476
3616
  let integerSlot = null;
3477
3617
  if (integerLoop) {
3478
3618
  integerSlot = B.slot();
3479
3619
  B.entryAllocas.push(`${integerSlot} = alloca ${this.sizeType} ; integer induction ${this.currentLocals.get(integerLoop.localId).name}`);
3480
- B.line(`store ${this.sizeType} 0, ptr ${integerSlot}`);
3620
+ let start = "0";
3621
+ if (integerArrayLoop && s.init?.kind === "varDecl" && s.init.init) {
3622
+ const value = this.emitExpr(s.init.init);
3623
+ start = B.tmp();
3624
+ B.line(`${start} = fptoui double ${value.name} to ${this.sizeType}`);
3625
+ this.integerArrayBindings.add(integerLoop.localId);
3626
+ }
3627
+ B.line(`store ${this.sizeType} ${start}, ptr ${integerSlot}`);
3481
3628
  this.integerLoopBindings.set(integerLoop.localId, integerSlot);
3482
3629
  }
3483
3630
  else if (s.init) {
@@ -3525,8 +3672,10 @@ export class LlEmitter {
3525
3672
  const len = B.tmp();
3526
3673
  const index = B.tmp();
3527
3674
  const inBounds = B.tmp();
3528
- B.line(`${lenPtr} = getelementptr inbounds %ScrBytes, ptr ${receiver.name}, i64 0, i32 1`);
3529
- B.line(`${len} = load ${this.sizeType}, ptr ${lenPtr}`);
3675
+ B.line(`${lenPtr} = getelementptr inbounds %${integerArrayLoop ? "ScrArr" : "ScrBytes"}, ptr ${receiver.name}, i64 0, i32 1`);
3676
+ if (integerArrayLoop)
3677
+ this.markMemoryPointer(lenPtr, "array:header");
3678
+ B.line(`${len} = load ${this.sizeType}, ptr ${lenPtr}${this.fieldAliasAttachment(lenPtr)}`);
3530
3679
  B.line(`${index} = load ${this.sizeType}, ptr ${integerSlot}`);
3531
3680
  B.line(`${inBounds} = icmp ult ${this.sizeType} ${index}, ${len}`);
3532
3681
  B.condBr(inBounds, lb, le);
@@ -3566,6 +3715,8 @@ export class LlEmitter {
3566
3715
  this.releaseScope(this.scopes.pop());
3567
3716
  if (integerLoop)
3568
3717
  this.integerLoopBindings.delete(integerLoop.localId);
3718
+ if (integerArrayLoop)
3719
+ this.integerArrayBindings.delete(integerArrayLoop.localId);
3569
3720
  break;
3570
3721
  }
3571
3722
  case "forOf": {
@@ -4068,7 +4219,7 @@ export class LlEmitter {
4068
4219
  // to this expression's frame so they survive those reads and still
4069
4220
  // die on the path that created them, including inside lazy branches.
4070
4221
  this.scopes.push([]);
4071
- const result = emitOperatorExpr(this, e);
4222
+ const result = emitBorrowedFieldSequence(this, e) ?? emitOperatorExpr(this, e);
4072
4223
  for (const local of this.scopes.pop()) {
4073
4224
  this.currentFrame().push({ name: local.slot, type: local.type, slot: true, ...(local.boxed ? { boxed: true } : {}) });
4074
4225
  }
@@ -4155,6 +4306,8 @@ export class LlEmitter {
4155
4306
  emitReadReceiver(e) {
4156
4307
  if (!isRefCounted(e.type))
4157
4308
  return this.emitExpr(e);
4309
+ if (e.kind === "strLit")
4310
+ return { name: this.internLiteral(e.value), type: e.type };
4158
4311
  if (e.kind === "varRef") {
4159
4312
  const binding = this.binding(e.localId);
4160
4313
  // Capture boxes can carry TDZ and caught-value conversion semantics.
@@ -4177,8 +4330,43 @@ export class LlEmitter {
4177
4330
  : this.classFieldPtr(receiver.name, e.className, e.field);
4178
4331
  return { name: this.loadField(ptr, type), type: e.type };
4179
4332
  }
4333
+ if (e.kind === "ternary" && this.canBorrowReceiver(e.then) && this.canBorrowReceiver(e.else_)) {
4334
+ // Checked projections lower to a ternary with an always-throwing
4335
+ // arm. Keep that check at the use, but borrow the successful arm.
4336
+ const B = this.B;
4337
+ const cond = this.emitExpr(e.cond);
4338
+ const slot = B.slot();
4339
+ B.entryAllocas.push(`${slot} = alloca ptr`);
4340
+ const yes = B.newLabel("read.then"), no = B.newLabel("read.else"), join = B.newLabel("read.join");
4341
+ B.condBr(cond.name, yes, no);
4342
+ for (const [label, value] of [[yes, e.then], [no, e.else_]]) {
4343
+ B.startBlock(label);
4344
+ this.frames.push([]);
4345
+ const result = this.emitReadReceiver(value);
4346
+ B.line(`store ptr ${result.name}, ptr ${slot}`);
4347
+ this.releaseFrame(this.frames.pop());
4348
+ B.br(join);
4349
+ }
4350
+ B.startBlock(join);
4351
+ const value = B.tmp();
4352
+ B.line(`${value} = load ptr, ptr ${slot}`);
4353
+ return { name: value, type: e.type };
4354
+ }
4180
4355
  return this.emitExpr(e);
4181
4356
  }
4357
+ canBorrowReceiver(e) {
4358
+ switch (e.kind) {
4359
+ case "varRef": return this.binding(e.localId).kind !== "boxed";
4360
+ case "unionNarrow": return this.canBorrowReceiver(e.value);
4361
+ case "fieldGet":
4362
+ case "recordGet": return this.canBorrowReceiver(e.obj);
4363
+ case "ternary": return this.canBorrowReceiver(e.then) && this.canBorrowReceiver(e.else_);
4364
+ // The runtime always sets a pending exception; its unreachable
4365
+ // typed dummy is null and owns no receiver.
4366
+ case "libCall": return e.fn === "error.nodeThrow";
4367
+ default: return false;
4368
+ }
4369
+ }
4182
4370
  emitExpr(e) {
4183
4371
  return emitExpr(this, e);
4184
4372
  }
@@ -4248,8 +4436,8 @@ export class LlEmitter {
4248
4436
  fsRenameThunkFor(cbT) {
4249
4437
  return fsRenameThunkFor(this, cbT);
4250
4438
  }
4251
- cryptoBytesThunkFor(cbT) {
4252
- return cryptoBytesThunkFor(this, cbT);
4439
+ cryptoBytesThunkFor(cbT, arrayBuffer = false) {
4440
+ return cryptoBytesThunkFor(this, cbT, arrayBuffer);
4253
4441
  }
4254
4442
  zlibBytesThunkFor(cbT) {
4255
4443
  return zlibBytesThunkFor(this, cbT);