@scriptc/compiler 0.3.1 → 0.3.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 (280) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +342 -16
  2. package/dist/backend/executable-features.js +1 -0
  3. package/dist/backend/executable-features.js.map +1 -1
  4. package/dist/backend/literals.d.ts +7 -0
  5. package/dist/backend/literals.js +32 -0
  6. package/dist/backend/literals.js.map +1 -1
  7. package/dist/backend/literals.test.js +17 -1
  8. package/dist/backend/literals.test.js.map +1 -1
  9. package/dist/backend/llvm/alloc.d.ts +15 -4
  10. package/dist/backend/llvm/alloc.js +39 -15
  11. package/dist/backend/llvm/alloc.js.map +1 -1
  12. package/dist/backend/llvm/alloc.test.js +15 -1
  13. package/dist/backend/llvm/alloc.test.js.map +1 -1
  14. package/dist/backend/llvm/appended-array-literals.d.ts +2 -0
  15. package/dist/backend/llvm/appended-array-literals.js +109 -0
  16. package/dist/backend/llvm/appended-array-literals.js.map +1 -0
  17. package/dist/backend/llvm/appended-array-literals.test.d.ts +1 -0
  18. package/dist/backend/llvm/appended-array-literals.test.js +90 -0
  19. package/dist/backend/llvm/appended-array-literals.test.js.map +1 -0
  20. package/dist/backend/llvm/call-lifetimes.d.ts +4 -1
  21. package/dist/backend/llvm/call-lifetimes.js +51 -3
  22. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  23. package/dist/backend/llvm/classes.js +10 -2
  24. package/dist/backend/llvm/classes.js.map +1 -1
  25. package/dist/backend/llvm/classes.test.js +2 -2
  26. package/dist/backend/llvm/dense-array-access.js +17 -12
  27. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  28. package/dist/backend/llvm/dense-array-access.test.js +15 -2
  29. package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
  30. package/dist/backend/llvm/dyn.d.ts +2 -0
  31. package/dist/backend/llvm/dyn.js +11 -2
  32. package/dist/backend/llvm/dyn.js.map +1 -1
  33. package/dist/backend/llvm/emitter.d.ts +43 -2
  34. package/dist/backend/llvm/emitter.js +306 -32
  35. package/dist/backend/llvm/emitter.js.map +1 -1
  36. package/dist/backend/llvm/expr-async.js +122 -6
  37. package/dist/backend/llvm/expr-async.js.map +1 -1
  38. package/dist/backend/llvm/expr-callbacks.d.ts +8 -0
  39. package/dist/backend/llvm/expr-callbacks.js +81 -1
  40. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  41. package/dist/backend/llvm/expr-calls.d.ts +12 -1
  42. package/dist/backend/llvm/expr-calls.js +126 -54
  43. package/dist/backend/llvm/expr-calls.js.map +1 -1
  44. package/dist/backend/llvm/expr-containers.d.ts +7 -0
  45. package/dist/backend/llvm/expr-containers.js +38 -7
  46. package/dist/backend/llvm/expr-containers.js.map +1 -1
  47. package/dist/backend/llvm/expr-context.d.ts +2 -0
  48. package/dist/backend/llvm/expr-control.d.ts +8 -0
  49. package/dist/backend/llvm/expr-control.js +103 -69
  50. package/dist/backend/llvm/expr-control.js.map +1 -1
  51. package/dist/backend/llvm/expr-dynamic.js +2 -2
  52. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  53. package/dist/backend/llvm/expr-primitives.d.ts +7 -0
  54. package/dist/backend/llvm/expr-primitives.js +30 -26
  55. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  56. package/dist/backend/llvm/expr-records.js +11 -1
  57. package/dist/backend/llvm/expr-records.js.map +1 -1
  58. package/dist/backend/llvm/expr-stream-bridges.d.ts +8 -0
  59. package/dist/backend/llvm/expr-stream-bridges.js +77 -8
  60. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  61. package/dist/backend/llvm/expr-stream-bridges.test.js +49 -1
  62. package/dist/backend/llvm/expr-stream-bridges.test.js.map +1 -1
  63. package/dist/backend/llvm/int32-abi.d.ts +18 -2
  64. package/dist/backend/llvm/int32-abi.js +23 -2
  65. package/dist/backend/llvm/int32-abi.js.map +1 -1
  66. package/dist/backend/llvm/int32-abi.test.js +75 -1
  67. package/dist/backend/llvm/int32-abi.test.js.map +1 -1
  68. package/dist/backend/llvm/lib-dispatch.js +7 -0
  69. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  70. package/dist/backend/llvm/lib-filesystem.js +58 -0
  71. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  72. package/dist/backend/llvm/lib-shared.js +76 -9
  73. package/dist/backend/llvm/lib-shared.js.map +1 -1
  74. package/dist/backend/llvm/local-array-reads.js +5 -3
  75. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  76. package/dist/backend/llvm/local-union-storage.d.ts +24 -2
  77. package/dist/backend/llvm/local-union-storage.js +127 -12
  78. package/dist/backend/llvm/local-union-storage.js.map +1 -1
  79. package/dist/backend/llvm/local-union-storage.test.js +106 -1
  80. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  81. package/dist/backend/llvm/record-results.d.ts +26 -0
  82. package/dist/backend/llvm/record-results.js +252 -0
  83. package/dist/backend/llvm/record-results.js.map +1 -0
  84. package/dist/backend/llvm/reference-effects.js +2 -0
  85. package/dist/backend/llvm/reference-effects.js.map +1 -1
  86. package/dist/backend/llvm/reference-writes.js +15 -9
  87. package/dist/backend/llvm/reference-writes.js.map +1 -1
  88. package/dist/backend/llvm/regions.d.ts +67 -0
  89. package/dist/backend/llvm/regions.js +309 -0
  90. package/dist/backend/llvm/regions.js.map +1 -0
  91. package/dist/backend/llvm/regions.test.d.ts +1 -0
  92. package/dist/backend/llvm/regions.test.js +173 -0
  93. package/dist/backend/llvm/regions.test.js.map +1 -0
  94. package/dist/backend/llvm/shapes.d.ts +34 -7
  95. package/dist/backend/llvm/shapes.js +31 -16
  96. package/dist/backend/llvm/shapes.js.map +1 -1
  97. package/dist/backend/llvm/shapes.test.js +7 -6
  98. package/dist/backend/llvm/shapes.test.js.map +1 -1
  99. package/dist/backend/llvm/split-loops.js +1 -1
  100. package/dist/backend/llvm/split-loops.js.map +1 -1
  101. package/dist/backend/llvm/stack-objects.d.ts +29 -0
  102. package/dist/backend/llvm/stack-objects.js +130 -0
  103. package/dist/backend/llvm/stack-objects.js.map +1 -0
  104. package/dist/backend/llvm/stack-objects.test.d.ts +1 -0
  105. package/dist/backend/llvm/stack-objects.test.js +252 -0
  106. package/dist/backend/llvm/stack-objects.test.js.map +1 -0
  107. package/dist/backend/llvm/string-reads.d.ts +4 -1
  108. package/dist/backend/llvm/string-reads.js +89 -9
  109. package/dist/backend/llvm/string-reads.js.map +1 -1
  110. package/dist/backend/llvm/switch-dispatch.js +5 -4
  111. package/dist/backend/llvm/switch-dispatch.js.map +1 -1
  112. package/dist/backend/llvm/walkers.d.ts +2 -0
  113. package/dist/backend/llvm/walkers.js +4 -2
  114. package/dist/backend/llvm/walkers.js.map +1 -1
  115. package/dist/backend/may-throw.js +1 -0
  116. package/dist/backend/may-throw.js.map +1 -1
  117. package/dist/backend/native/contracts.d.ts +5 -0
  118. package/dist/backend/native/executable.js +16 -1
  119. package/dist/backend/native/executable.js.map +1 -1
  120. package/dist/backend/native/library.js +1 -1
  121. package/dist/backend/native/library.js.map +1 -1
  122. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  123. package/dist/backend/native/runtime-inputs.js +2 -0
  124. package/dist/backend/native/runtime-inputs.js.map +1 -1
  125. package/dist/backend/native-link-info-core.d.ts +1 -0
  126. package/dist/backend/native-link-info-core.js.map +1 -1
  127. package/dist/backend/runtime-abi.d.ts +2 -2
  128. package/dist/backend/runtime-abi.js +2 -2
  129. package/dist/backend/runtime-pack-core.d.ts +1 -0
  130. package/dist/backend/runtime-pack-core.js +1 -0
  131. package/dist/backend/runtime-pack-core.js.map +1 -1
  132. package/dist/backend/runtime-pack-targets.test.js +1 -1
  133. package/dist/backend/runtime-pack.test.js +1 -1
  134. package/dist/backend/target-diagnostics.js +14 -0
  135. package/dist/backend/target-diagnostics.js.map +1 -1
  136. package/dist/backend/target-diagnostics.test.js +13 -0
  137. package/dist/backend/target-diagnostics.test.js.map +1 -1
  138. package/dist/executable/executable-cache.d.ts +1 -0
  139. package/dist/executable/executable-cache.js.map +1 -1
  140. package/dist/frontend/experimental-import.d.ts +12 -0
  141. package/dist/frontend/experimental-import.js +63 -0
  142. package/dist/frontend/experimental-import.js.map +1 -0
  143. package/dist/frontend/lowering/builtin-calls.d.ts +6 -1
  144. package/dist/frontend/lowering/builtin-calls.js +36 -0
  145. package/dist/frontend/lowering/builtin-calls.js.map +1 -1
  146. package/dist/frontend/lowering/builtins/console.d.ts +16 -6
  147. package/dist/frontend/lowering/builtins/console.js +33 -9
  148. package/dist/frontend/lowering/builtins/console.js.map +1 -1
  149. package/dist/frontend/lowering/builtins/errors.js +20 -0
  150. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  151. package/dist/frontend/lowering/builtins/json.d.ts +2 -2
  152. package/dist/frontend/lowering/builtins/json.js +13 -4
  153. package/dist/frontend/lowering/builtins/json.js.map +1 -1
  154. package/dist/frontend/lowering/builtins/module-calls.js +16 -1
  155. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  156. package/dist/frontend/lowering/builtins/numbers.d.ts +1 -0
  157. package/dist/frontend/lowering/builtins/numbers.js +17 -0
  158. package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
  159. package/dist/frontend/lowering/builtins/operating-system.d.ts +18 -0
  160. package/dist/frontend/lowering/builtins/operating-system.js +361 -1
  161. package/dist/frontend/lowering/builtins/operating-system.js.map +1 -1
  162. package/dist/frontend/lowering/builtins/process.js +15 -3
  163. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  164. package/dist/frontend/lowering/builtins/promises.js +109 -2
  165. package/dist/frontend/lowering/builtins/promises.js.map +1 -1
  166. package/dist/frontend/lowering/builtins/text-codecs.d.ts +3 -4
  167. package/dist/frontend/lowering/builtins/text-codecs.js +3 -4
  168. package/dist/frontend/lowering/builtins/text-codecs.js.map +1 -1
  169. package/dist/frontend/lowering/checked-promise-all.d.ts +10 -3
  170. package/dist/frontend/lowering/checked-promise-all.js +52 -6
  171. package/dist/frontend/lowering/checked-promise-all.js.map +1 -1
  172. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +6 -3
  173. package/dist/frontend/lowering/class-dynamic-dispatch.js +54 -31
  174. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  175. package/dist/frontend/lowering/containers/array-callbacks.js +34 -4
  176. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  177. package/dist/frontend/lowering/containers/array-construction.js +8 -4
  178. package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
  179. package/dist/frontend/lowering/containers/array-pipelines.js +1 -1
  180. package/dist/frontend/lowering/containers/array-pipelines.js.map +1 -1
  181. package/dist/frontend/lowering/containers/string-and-regexp.js +91 -0
  182. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  183. package/dist/frontend/lowering/cycle-initialization.d.ts +18 -2
  184. package/dist/frontend/lowering/cycle-initialization.js +166 -12
  185. package/dist/frontend/lowering/cycle-initialization.js.map +1 -1
  186. package/dist/frontend/lowering/deferred-module-initializers.js +7 -2
  187. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -1
  188. package/dist/frontend/lowering/deferred-module-initializers.test.js +28 -0
  189. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -1
  190. package/dist/frontend/lowering/expressions/object-literals.js +5 -56
  191. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  192. package/dist/frontend/lowering/generator-delegation.d.ts +8 -0
  193. package/dist/frontend/lowering/generator-delegation.js +231 -10
  194. package/dist/frontend/lowering/generator-delegation.js.map +1 -1
  195. package/dist/frontend/lowering/lifetime-regions.d.ts +11 -0
  196. package/dist/frontend/lowering/lifetime-regions.js +216 -0
  197. package/dist/frontend/lowering/lifetime-regions.js.map +1 -0
  198. package/dist/frontend/lowering/lower-array-sort.d.ts +28 -2
  199. package/dist/frontend/lowering/lower-array-sort.js +100 -3
  200. package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
  201. package/dist/frontend/lowering/lower-array-sort.test.js +99 -2
  202. package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -1
  203. package/dist/frontend/lowering/lower-calls.js +72 -102
  204. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  205. package/dist/frontend/lowering/lower-classes.d.ts +4 -3
  206. package/dist/frontend/lowering/lower-classes.js +116 -2
  207. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  208. package/dist/frontend/lowering/lower-console.d.ts +13 -0
  209. package/dist/frontend/lowering/lower-console.js +460 -4
  210. package/dist/frontend/lowering/lower-console.js.map +1 -1
  211. package/dist/frontend/lowering/lower-event-emitter.d.ts +6 -0
  212. package/dist/frontend/lowering/lower-event-emitter.js +124 -38
  213. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  214. package/dist/frontend/lowering/lower-exprs.js +137 -22
  215. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  216. package/dist/frontend/lowering/lower-generators.d.ts +15 -7
  217. package/dist/frontend/lowering/lower-generators.js +183 -99
  218. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  219. package/dist/frontend/lowering/lower-inspect.d.ts +8 -1
  220. package/dist/frontend/lowering/lower-inspect.js +119 -18
  221. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  222. package/dist/frontend/lowering/lower-modules.js +20 -14
  223. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  224. package/dist/frontend/lowering/lower-stdlib.d.ts +4 -0
  225. package/dist/frontend/lowering/lower-stdlib.js +35 -1
  226. package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
  227. package/dist/frontend/lowering/lower-stmts.js +66 -11
  228. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  229. package/dist/frontend/lowering/lowerer.d.ts +22 -1
  230. package/dist/frontend/lowering/lowerer.js +116 -8
  231. package/dist/frontend/lowering/lowerer.js.map +1 -1
  232. package/dist/frontend/lowering/regex-span-reads.d.ts +12 -0
  233. package/dist/frontend/lowering/regex-span-reads.js +164 -0
  234. package/dist/frontend/lowering/regex-span-reads.js.map +1 -0
  235. package/dist/frontend/lowering/surfaces.js +112 -10
  236. package/dist/frontend/lowering/surfaces.js.map +1 -1
  237. package/dist/frontend/lowering/var-hoisting.d.ts +3 -0
  238. package/dist/frontend/lowering/var-hoisting.js +261 -0
  239. package/dist/frontend/lowering/var-hoisting.js.map +1 -0
  240. package/dist/frontend/pipeline.js +5 -3
  241. package/dist/frontend/pipeline.js.map +1 -1
  242. package/dist/frontend/program.d.ts +3 -2
  243. package/dist/frontend/program.js +23 -5
  244. package/dist/frontend/program.js.map +1 -1
  245. package/dist/frontend/program.test.js +13 -0
  246. package/dist/frontend/program.test.js.map +1 -1
  247. package/dist/frontend/type-mapper.d.ts +13 -1
  248. package/dist/frontend/type-mapper.js +146 -13
  249. package/dist/frontend/type-mapper.js.map +1 -1
  250. package/dist/index.js +1 -0
  251. package/dist/index.js.map +1 -1
  252. package/dist/ir/builtin-effects.js +29 -2
  253. package/dist/ir/builtin-effects.js.map +1 -1
  254. package/dist/ir/builtin-signatures.d.ts +1 -1
  255. package/dist/ir/builtin-signatures.js +145 -15
  256. package/dist/ir/builtin-signatures.js.map +1 -1
  257. package/dist/ir/function-references.test.js +1 -0
  258. package/dist/ir/function-references.test.js.map +1 -1
  259. package/dist/ir/int32-slots.js +1 -0
  260. package/dist/ir/int32-slots.js.map +1 -1
  261. package/dist/ir/intrinsic-signatures.js +2 -0
  262. package/dist/ir/intrinsic-signatures.js.map +1 -1
  263. package/dist/ir/ir.d.ts +65 -20
  264. package/dist/ir/ir.js +5 -0
  265. package/dist/ir/ir.js.map +1 -1
  266. package/dist/ir/runtime-features.d.ts +1 -0
  267. package/dist/ir/runtime-features.js +35 -1
  268. package/dist/ir/runtime-features.js.map +1 -1
  269. package/dist/ir/scalar-records.js +1 -2
  270. package/dist/ir/scalar-records.js.map +1 -1
  271. package/dist/ir/validate.js +150 -25
  272. package/dist/ir/validate.js.map +1 -1
  273. package/dist/ir/validate.test.js +65 -0
  274. package/dist/ir/validate.test.js.map +1 -1
  275. package/dist/library/ir-policy.js +1 -0
  276. package/dist/library/ir-policy.js.map +1 -1
  277. package/dist/native/sanitizer.test.js +1 -0
  278. package/dist/native/sanitizer.test.js.map +1 -1
  279. package/package.json +20 -20
  280. package/surface-manifest.json +159 -1
@@ -1,7 +1,7 @@
1
1
  import { emitLlvmLayouts } from "./layouts.js";
2
2
  import { compileRegexMatcher } from "./regex-matchers.js";
3
- import { FIRST_EMITTED_CYC_KIND, inlineAllocSupported } from "./alloc.js";
4
- import { llvmBytes as llBytes } from "../literals.js";
3
+ import { CYC_BUF, CYC_HDR, FIRST_EMITTED_CYC_KIND, inlineAllocSupported } from "./alloc.js";
4
+ import { hasLoneSurrogate, llvmBytes as llBytes, wtf8Bytes } from "../literals.js";
5
5
  import { InternalCompilerError } from "../../errors.js";
6
6
  import { createHash } from "node:crypto";
7
7
  import { endsWithJump, matchStringSelfConcat, streamTypedRefEligible, undefinedArmTag, } from "../../ir/analysis.js";
@@ -16,6 +16,7 @@ import { findBytesBounds } from "./bytes-bounds.js";
16
16
  import { emitByteWindowGuard, findInitializedByteLoopBindings, matchByteWindow, } from "./byte-windows.js";
17
17
  import { canDeferSplitPiece, emitSplitSpanNext, materializeSplitPiece, emitSplitCursor, emitSplitNext, emitSplitScratch, emitSplitSnapshot, findPrivateSplitLocals, loadSplitSnapshot, storeSplitSnapshot, stringSplit, } from "./split-loops.js";
18
18
  import { scalarizeNumericRecords } from "../../ir/scalar-records.js";
19
+ import { addRecordResultEntries } from "./record-results.js";
19
20
  import { specializeNumericCalls } from "../../ir/numeric-call-specialization.js";
20
21
  import { everyExpr, everyExprChild, everyStmtChild, everyStmtList } from "../../ir/traverse.js";
21
22
  import { analyzeIntegerRanges, INT32_RANGE } from "../../ir/integer-ranges.js";
@@ -24,7 +25,7 @@ import { analyzeInt32Slots } from "../../ir/int32-slots.js";
24
25
  import { analyzeFinalFields, constructorClass } from "../../ir/final-fields.js";
25
26
  import { foldConstantGlobals } from "../../ir/constant-globals.js";
26
27
  import { findIntegerViews } from "./integer-views.js";
27
- import { findInt32Abis, INT32_ABI_SUFFIX } from "./int32-abi.js";
28
+ import { findInt32Abis, INT32_ABI_SUFFIX, SCALAR_UNION_DUMMY, SCALAR_UNION_RESULT, } from "./int32-abi.js";
28
29
  import { findInt32Locals } from "./int32-locals.js";
29
30
  import { exactInteger, narrowInteger } from "./integer-values.js";
30
31
  import { findInitializerBindings, withInitializerBindings } from "../../ir/initializer-bindings.js";
@@ -35,7 +36,8 @@ import { computeMayThrow } from "../may-throw.js";
35
36
  import { mangleArgPack, mangleAsyncAdoptCall, mangleAsyncAwaitCall, mangleAsyncSpawn, mangleBorrowedFunction, mangleClassObj, mangleClassStruct, mangleFnClosure, mangleFunction, mangleGenDrop, mangleGenSpawn, mangleGlobal, mangleLocal, mangleRecordStruct, mangleTrampoline, mangleWrapper, mangleBorrowingWrapper, mangleVtInstance, } from "../mangle.js";
36
37
  import { analyzeCallLifetimes } from "./call-lifetimes.js";
37
38
  import { canStackUnion, emitStackUnion, findLocalStackUnions } from "./stack-unions.js";
38
- import { allocateLocalUnion, findLocalUnionStorage, storeLocalUnion, } from "./local-union-storage.js";
39
+ import { emitStackObject, findLocalStackObjects, findReassignedStackObjects, stackObjectStruct, } from "./stack-objects.js";
40
+ import { allocateLocalUnion, emitScalarOptional, findLocalUnionStorage, isScalarOptionalSource, storeLocalUnion, } from "./local-union-storage.js";
39
41
  import { BlockBuilder } from "./blocks.js";
40
42
  import { NullableRefFields } from "./nullable-fields.js";
41
43
  import { emitLocalArrayRead, emitProjectedArrayRead, emitBorrowedArrayRead, findLocalArrayReads, findCallArrayReads, OptionalArrayReads, } from "./local-array-reads.js";
@@ -51,6 +53,7 @@ import { ReferenceWrites } from "./reference-writes.js";
51
53
  import { LlvmDebugInfo } from "./debug-info.js";
52
54
  import { StackCallbacks } from "./stack-callbacks.js";
53
55
  import { findLoopArrayBorrows } from "./loop-array-borrows.js";
56
+ import { findAppendedArrayLiterals } from "./appended-array-literals.js";
54
57
  import { AmbientReceiverReaders, findConstantCallbacks } from "./constant-callbacks.js";
55
58
  import { findScalarStringSlices, emitStringSliceSnapshot, } from "./string-slices.js";
56
59
  import { LazyCaptures } from "./lazy-captures.js";
@@ -77,7 +80,8 @@ import { emitChildProcessLibCall, emitAsyncContextLibCall, emitProcessLibCall, e
77
80
  import { emitStreamLibCall } from "./lib-stream.js";
78
81
  import { emitNetworkHttpLibCall } from "./lib-network.js";
79
82
  import { emitAssertInspectLibCall, emitIoLibCall, emitGenericLibCall, emitLibCall, } from "./lib-dispatch.js";
80
- import { buildClassGraph, classMembershipIntervals, emitClassMembershipHelper, classEnvironmentIndex, classFieldIndex, classStructSym, } from "./classes.js";
83
+ import { buildClassGraph, classMembershipIntervals, emitClassMembershipHelper, classEnvironmentIndex, classFieldIndex, classStructSym, programLifetimeClass, } from "./classes.js";
84
+ import { LifetimeRegions, REGION_TYPES } from "./regions.js";
81
85
  import { LlDyn } from "./dyn.js";
82
86
  import { VirtualBorrows } from "./virtual-borrows.js";
83
87
  import { LlvmUnsupportedError } from "./unsupported.js";
@@ -86,7 +90,7 @@ import { isObjectArm, NULLABLE_ABSENT, NULLABLE_NULL, NullableUnions } from "./n
86
90
  import { emitNullablePresent, emitUnionPeek, emitUnionTag } from "./union-repr.js";
87
91
  import { literalCapWord, literalCapWord32 } from "./string-key-hash.js";
88
92
  import { NUMBER_MAP_ENTRY_DECL, STRING_MAP_ENTRY_DECL } from "./map-number-lookup.js";
89
- import { STRING_READ_HELPERS } from "./string-reads.js";
93
+ import { STRING_READ_HELPERS, stringScanDecl } from "./string-reads.js";
90
94
  import { emitConcatInputs, emitMixedConcat, numberPart, stringParts, } from "./string-construction.js";
91
95
  import { arrNewCall, boxAccess, boxNewCall, boxReleaseSym, computeTraced, elemAccess, emitInlineRcHelpers, emitNullableRetainWrappers, FN_ATTRS, inlineRcDecls, llFieldType, releaseSym, retainSym, traceArg, typedRefConstructor, vAdapters, } from "./shapes.js";
92
96
  import { INLINE_LITERAL_BYTES, literalEqualityDefinition } from "./string-literal-equality.js";
@@ -122,14 +126,14 @@ export function emitLlvmModule(input, options = {}) {
122
126
  const mod = unshareNodes(input);
123
127
  // Keep source storage intact for debugger inspection in dev builds.
124
128
  return new LlEmitter(options.debugSources === undefined
125
- ? scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction))
129
+ ? addRecordResultEntries(scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction)))
126
130
  : mod, options).emit();
127
131
  }
128
132
  /** Keep large translation units below the host's single-string limit. */
129
133
  export function emitLlvmModuleSource(input, options = {}) {
130
134
  const mod = unshareNodes(input);
131
135
  const parts = new LlEmitter(options.debugSources === undefined
132
- ? scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction))
136
+ ? addRecordResultEntries(scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction)))
133
137
  : mod, options).emitParts();
134
138
  const length = parts.reduce((total, part) => total + part.length, Math.max(0, parts.length - 1));
135
139
  if (length <= 256 * 1024 * 1024)
@@ -137,7 +141,7 @@ export function emitLlvmModuleSource(input, options = {}) {
137
141
  return parts.flatMap((part, index) => (index === 0 ? [part] : ["\n", part]));
138
142
  }
139
143
  function llStrBytes(text) {
140
- return llBytes(Buffer.from(text, "utf8"));
144
+ return llBytes(wtf8Bytes(text));
141
145
  }
142
146
  const NO_BORROWED = new Set();
143
147
  /** Whether any node of `e` names the local (reads, writes, declarations,
@@ -181,6 +185,10 @@ export class LlEmitter {
181
185
  scalarStringSlices = new Map();
182
186
  stringSlices = new Map();
183
187
  localStackUnions = new Map();
188
+ localStackObjects = new Map();
189
+ reassignedStackObjects = new Set();
190
+ /** The binding slot of each reassigned stack-object local. */
191
+ stackObjectSlots = new Map();
184
192
  localUnionStorageProofs = new Map();
185
193
  localUnionStorage = new Map();
186
194
  integerArrayBindings = new Set();
@@ -203,6 +211,18 @@ export class LlEmitter {
203
211
  }
204
212
  this.fieldPointerTags.set(ptr, tag);
205
213
  }
214
+ /** The alias tag of a runtime word that emitted code reads and writes
215
+ * outside every field (the lifetime-region count, owner and cursors). */
216
+ memoryAliasAttachment(category) {
217
+ if (this.debug !== null)
218
+ return "";
219
+ let tag = this.fieldAliasTags.get(category);
220
+ if (tag === undefined) {
221
+ tag = 2 + this.fieldAliasTags.size * 2;
222
+ this.fieldAliasTags.set(category, tag);
223
+ }
224
+ return `, !tbaa !${tag}`;
225
+ }
206
226
  fieldAliasAttachment(ptr) {
207
227
  const tag = this.fieldPointerTags.get(ptr);
208
228
  return tag === undefined ? "" : `, !tbaa !${tag}`;
@@ -217,10 +237,12 @@ export class LlEmitter {
217
237
  return lines;
218
238
  }
219
239
  debug;
240
+ /** Projection-only scalar objects may live in frame storage (stack-objects.ts). */
241
+ stackObjects;
220
242
  debugScope = null;
221
243
  sizeType;
222
244
  ffiExtendNarrowIntegers;
223
- cycleBufferedOffset;
245
+ cycleBufOffset;
224
246
  /** Emitted ScrCycType descriptors so far (their collector statistics
225
247
  * indices; see ShapeHost.nextCycKind). */
226
248
  cycKinds = 0;
@@ -307,6 +329,8 @@ export class LlEmitter {
307
329
  * when inline RC is off. */
308
330
  rcHelpers;
309
331
  fnByName = new Map();
332
+ /** Empty literals that construct with inline slots (appended-array-literals.ts). */
333
+ appendedArrayLiterals = new Set();
310
334
  /** Emitted LLVM text of every IR function body, by function name: the
311
335
  * fiberless-async analysis scans it for suspension entry points. */
312
336
  fnDefText = new Map();
@@ -318,6 +342,8 @@ export class LlEmitter {
318
342
  * whose bindings end with the list (emitBlock and function bodies). */
319
343
  stmtCursor = null;
320
344
  optionalArrayReads;
345
+ /** Union sources a binding or projection can hold in a stack box. */
346
+ unionSources;
321
347
  checkedNarrows;
322
348
  callArrayReads = new Map();
323
349
  mapReadLifetimes = { locals: new Map(), arguments: new Map() };
@@ -413,6 +439,8 @@ export class LlEmitter {
413
439
  * typeKey → thunk symbol. */
414
440
  resolveThunks = new Map();
415
441
  resolveThunkDefs = [];
442
+ /** Typed-ref recipe constants by type key (lazy receivers). */
443
+ typedRefRecipes = new Map();
416
444
  /** ReadableStream.from adapters keep typed arrays by reference and box
417
445
  * one current element per pull. */
418
446
  streamFromArrayAdapters = new Map();
@@ -530,6 +558,9 @@ export class LlEmitter {
530
558
  currentReturnType = VOID;
531
559
  /** The current body returns its number result as i32. */
532
560
  currentInt32Result = false;
561
+ /** The function's i32 entry returns its scalar union result as tag and
562
+ * payload bits (Int32Abi.union). */
563
+ currentUnionResult = false;
533
564
  /** Active only while emitting a body lowered with LLVM's
534
565
  * switched-coroutine intrinsics (wasm32 async bodies and generators,
535
566
  * native synchronous generators; see coroLowered). */
@@ -538,6 +569,8 @@ export class LlEmitter {
538
569
  * generator bodies): yieldExpr emission reads them, and emitTryCatch's
539
570
  * catch prologue emits the GENRET sentinel re-unwind exactly here. */
540
571
  currentGenerator = null;
572
+ /** The function being emitted is an async generator body. */
573
+ currentAsyncGenerator = false;
541
574
  /** Active optional-chain bind slots, by chain id (chainRecv reads). */
542
575
  chainSlots = new Map();
543
576
  logArgSlots = 0;
@@ -565,6 +598,7 @@ export class LlEmitter {
565
598
  options.wasi === true || ffiExtendsNarrowIntegers(options.targetTriple);
566
599
  this.wasi = options.wasi === true;
567
600
  this.stacklessGenerators = !this.wasi && mod.workers !== true && this.debug === null;
601
+ this.stackObjects = this.debug === null;
568
602
  // An empty triple targets the host, as for executableTls below: the
569
603
  // Node-hosted CLI passes none, the native CLI passes its toolchain's, and
570
604
  // both must emit the same module for the same target.
@@ -591,15 +625,14 @@ export class LlEmitter {
591
625
  this.runtimeAbiMarker = options.runtimeAbiMarker === true;
592
626
  this.detachedExit = options.detachedExit === true;
593
627
  this.rcHelpers = options.inlineRc === true ? new Set() : null;
594
- // ScrCycHdr.buffered sits 6 bytes behind every object. The wasm32
595
- // header pads before its descriptor so its payload remains
596
- // double-aligned without changing this ABI offset.
597
- this.cycleBufferedOffset = 6;
628
+ // ScrCycHdr.buf sits 4 bytes behind every object on every target.
629
+ this.cycleBufOffset = CYC_HDR - CYC_BUF;
598
630
  this.ffiCallbackAdapters = allocateFfiCallbackAdapters(mod.ffiImports ?? []);
599
631
  this.ffiHasRetainedCallback = hasRetainedFfiCallback(mod.ffiImports ?? []);
600
632
  this.ffiHasForeignCallback = hasForeignFfiCallback(mod.ffiImports ?? []);
601
633
  for (const fn of mod.functions)
602
634
  this.fnByName.set(fn.name, fn);
635
+ this.appendedArrayLiterals = findAppendedArrayLiterals(mod);
603
636
  for (const entry of mod.ffiImports ?? []) {
604
637
  this.ffiByName.set(entry.name, entry);
605
638
  }
@@ -633,6 +666,13 @@ export class LlEmitter {
633
666
  // then yields the (borrowed or owned) element pointer, not a stack box.
634
667
  // Arrays of such a union are read the same way.
635
668
  this.optionalArrayReads = new OptionalArrayReads(this.fnByName, this.unionsById, (id) => this.nullableUnions.has(id));
669
+ this.unionSources = {
670
+ unions: this.boxedUnionsById,
671
+ receiverUnions: this.unionsById,
672
+ nullableField: (e) => this.nullableFieldGet(e) !== null,
673
+ arrayRead: (e) => this.optionalArrayReads.get(e) !== null,
674
+ scalarCall: (e) => this.scalarResultCall(e),
675
+ };
636
676
  this.checkedNarrows = new CheckedNarrows(this.fnByName);
637
677
  this.referenceEffects = new ReferenceEffects(this.fnByName, (call) => this.optionalArrayReads.get(call) !== null, mod.classes ?? []);
638
678
  if (this.debug === null)
@@ -678,7 +718,7 @@ export class LlEmitter {
678
718
  walkParameters.set(fn.name, indexes);
679
719
  }
680
720
  }
681
- this.callLifetimes = analyzeCallLifetimes(this.fnByName, (className, field) => this.nullableFields.get(className, field) !== null, walkParameters);
721
+ this.callLifetimes = analyzeCallLifetimes(this.fnByName, (className, field) => this.nullableFields.get(className, field) !== null, walkParameters, new Set([...this.int32Abis].filter(([, abi]) => abi.union).map(([name]) => name)));
682
722
  this.constantCallbacks = findConstantCallbacks(mod, this.callLifetimes);
683
723
  this.stackCallbacks = new StackCallbacks(this.fnByName);
684
724
  this.receiverReaders = new AmbientReceiverReaders(this.fnByName);
@@ -691,7 +731,7 @@ export class LlEmitter {
691
731
  this.tracedUnions = traced.unions;
692
732
  this.shapeHost = {
693
733
  sizeType: this.sizeType,
694
- cycleBufferedOffset: this.cycleBufferedOffset,
734
+ cycleBufOffset: this.cycleBufOffset,
695
735
  tracedShapes: this.tracedShapes,
696
736
  tracedUnions: this.tracedUnions,
697
737
  nullableUnions: this.nullableUnions,
@@ -733,6 +773,7 @@ export class LlEmitter {
733
773
  pendingTestLines: (dest) => this.pendingTestLines(dest),
734
774
  virtualEntry: (implFn) => this.virtualEntry(implFn),
735
775
  programLifetime: this.programLifetime,
776
+ regionAliasTag: (word) => this.memoryAliasAttachment(`region.${word}`),
736
777
  };
737
778
  this.walkers = new LlWalkers(this.shapeHost);
738
779
  this.dyn = new LlDyn(this.shapeHost);
@@ -770,6 +811,17 @@ export class LlEmitter {
770
811
  // whole-program preorder numbering for instanceof over runtime and
771
812
  // compiled error objects, and the per-hierarchy virtual slot lists.
772
813
  this.classMeta = buildClassGraph(mod, this.fnByName);
814
+ if (mod.lifetimeRegions === true) {
815
+ this.regions = new LifetimeRegions(this.shapeHost, mod, this.classMeta, (meta) => programLifetimeClass(this.shapeHost, meta), this.nullableFields);
816
+ const regions = this.regions;
817
+ // Member names differ from LifetimeRegions' own, which keeps the
818
+ // record from reading as that class's protocol.
819
+ this.shapeHost.regions = {
820
+ rcBody: (fnName, ret, comment) => regions.countBody(fnName, ret, comment),
821
+ newAlloc: (className, sizeOf) => regions.allocLines(className, sizeOf),
822
+ classDefinitions: (cls, sizeOf) => regions.classDefs(cls, sizeOf),
823
+ };
824
+ }
773
825
  for (const [name, rec] of RUNTIME_ERROR_CLASSES) {
774
826
  const meta = this.classMeta.get(name);
775
827
  if (!meta)
@@ -1402,6 +1454,7 @@ export class LlEmitter {
1402
1454
  ...emitClassMembershipHelper(this.classMeta, this.sizeType),
1403
1455
  ...(this.publishWalkersCache?.defs() ?? []),
1404
1456
  ...this.publishedClassNamesDefs(),
1457
+ ...(this.regions?.moduleDefs() ?? []),
1405
1458
  ];
1406
1459
  if (this.constantNumericTables.size > 0)
1407
1460
  this.declare(`declare double @scr_arr_get_number(ptr, double)`);
@@ -1529,8 +1582,8 @@ export class LlEmitter {
1529
1582
  // half carries the precomputed Map key hash (SCR_STR_HASH_CACHE).
1530
1583
  // Bit 31 marks all-ASCII literals (SCR_STR_ASCII_BIT) on every target.
1531
1584
  const capWord = this.sizeType === "i64"
1532
- ? literalCapWord(Buffer.from(text, "utf8"))
1533
- : literalCapWord32(Buffer.from(text, "utf8"));
1585
+ ? literalCapWord(wtf8Bytes(text))
1586
+ : literalCapWord32(wtf8Bytes(text));
1534
1587
  out.push(`@${lit.sym} = internal global { ${this.sizeType}, ${this.sizeType}, ${this.sizeType}, [${lit.len + 1} x i8] } ` +
1535
1588
  `{ ${this.sizeType} -1, ${this.sizeType} ${lit.len}, ${this.sizeType} ${capWord}, [${lit.len + 1} x i8] c"${llStrBytes(text)}" }`);
1536
1589
  }
@@ -1693,6 +1746,12 @@ export class LlEmitter {
1693
1746
  }
1694
1747
  if (this.streamIntervals.length > 0)
1695
1748
  out.push(``);
1749
+ if ([...this.literals.keys(), ...this.cstrs.keys()].some(hasLoneSurrogate)) {
1750
+ // The runtime skips surrogate work until a lone surrogate may exist
1751
+ // (scr_wtf8_any); its own producers note one, and literals do here.
1752
+ out.push(`declare void @scr_wtf8_note()`, ``);
1753
+ stamps.push(` call void @scr_wtf8_note()`);
1754
+ }
1696
1755
  if (this.errorIntervals.length > 0 && this.tracedShapes.has("object:%Error")) {
1697
1756
  // The cycle fixpoint marked the Error hierarchy (a user subclass
1698
1757
  // holds cycle-capable fields — capability is hierarchy-uniform), so
@@ -2140,16 +2199,24 @@ export class LlEmitter {
2140
2199
  defs.push(`define internal zeroext i1 @sc_str_eq(ptr %a, ptr %b) ${FN_ATTRS} {`, `entry:`, ` %same = icmp eq ptr %a, %b`, ` br i1 %same, label %yes, label %lengths`, `lengths:`, ` %alen.p = getelementptr inbounds %ScrStr, ptr %a, i32 0, i32 1`, ` %blen.p = getelementptr inbounds %ScrStr, ptr %b, i32 0, i32 1`, ` %alen = load ${this.sizeType}, ptr %alen.p`, ` %blen = load ${this.sizeType}, ptr %blen.p`, ` %samelen = icmp eq ${this.sizeType} %alen, %blen`, ` br i1 %samelen, label %bytes, label %no`, `bytes:`, ` %eq = call zeroext i1 @scr_str_eq(ptr %a, ptr %b)`, ` ret i1 %eq`, `yes:`, ` ret i1 true`, `no:`, ` ret i1 false`, `}`, ``);
2141
2200
  }
2142
2201
  for (const [text, name] of this.literalEqualities) {
2143
- defs.push(...literalEqualityDefinition(name, Buffer.from(text, "utf8"), this.internLiteral(text), this.sizeType, FN_ATTRS), ``);
2202
+ defs.push(...literalEqualityDefinition(name, wtf8Bytes(text), this.internLiteral(text), this.sizeType, FN_ATTRS), ``);
2144
2203
  }
2145
2204
  // String length and charCodeAt read proven-ASCII strings inline: bit 31
2146
2205
  // of the capacity word (SCR_STR_ASCII_BIT, the low half's sign bit on
2147
2206
  // little-endian targets) makes UTF-16 units bytes. Unproven strings and
2148
2207
  // anything but an in-range index take the runtime's UTF-16 mapping.
2208
+ // A scan's receiver reads inline too where runtime state is ordinary
2209
+ // global storage (ScrStrScan; SCR_TL makes it thread-local otherwise).
2210
+ const scanInline = this.mod.workers !== true && this.mod.lib?.threadInstances !== true;
2211
+ let scanDeclared = false;
2149
2212
  for (const helper of STRING_READ_HELPERS) {
2150
2213
  if (!this.decls.has(helper.decl))
2151
2214
  continue;
2152
- defs.push(...helper.define(this.sizeType, FN_ATTRS), ``);
2215
+ if (scanInline && !scanDeclared) {
2216
+ defs.push(stringScanDecl(this.sizeType), ``);
2217
+ scanDeclared = true;
2218
+ }
2219
+ defs.push(...helper.define(this.sizeType, FN_ATTRS, scanInline), ``);
2153
2220
  }
2154
2221
  // Ordering also decides inline when the first bytes differ: byte order
2155
2222
  // is the plain comparison's order, and the UTF-16 order whenever both
@@ -3197,11 +3264,13 @@ export class LlEmitter {
3197
3264
  ? "ret void"
3198
3265
  : this.currentInt32Result
3199
3266
  ? "ret i32 0"
3200
- : t === "double"
3201
- ? `ret double ${f64Lit(0)}`
3202
- : t === "i1"
3203
- ? "ret i1 false"
3204
- : "ret ptr null";
3267
+ : this.currentUnionResult
3268
+ ? `ret ${SCALAR_UNION_DUMMY}`
3269
+ : t === "double"
3270
+ ? `ret double ${f64Lit(0)}`
3271
+ : t === "i1"
3272
+ ? "ret i1 false"
3273
+ : "ret ptr null";
3205
3274
  }
3206
3275
  // Copy the entries now: later declarations extend these lexical scopes.
3207
3276
  // Release order and the handler are part of the shared block's identity.
@@ -4397,7 +4466,14 @@ export class LlEmitter {
4397
4466
  this.debug === null ? findScalarStringSlices(fn, this.callLifetimes) : new Map();
4398
4467
  this.mapReadLifetimes = findMapReadLifetimes(fn, this.boxedUnionsById, this.callLifetimes);
4399
4468
  this.localStackUnions = findLocalStackUnions(fn, this.callLifetimes, this.boxedUnionsById);
4400
- this.localUnionStorageProofs = findLocalUnionStorage(fn, this.callLifetimes, this.boxedUnionsById, (e) => this.nullableFieldGet(e) !== null);
4469
+ this.localStackObjects = this.stackObjects
4470
+ ? findLocalStackObjects(this, fn, this.callLifetimes)
4471
+ : new Map();
4472
+ this.reassignedStackObjects = this.stackObjects
4473
+ ? findReassignedStackObjects(this, fn, this.callLifetimes)
4474
+ : new Set();
4475
+ this.stackObjectSlots = new Map();
4476
+ this.localUnionStorageProofs = findLocalUnionStorage(fn, this.callLifetimes, this.unionSources);
4401
4477
  this.localUnionStorage = new Map();
4402
4478
  this.walkBorrows = this.walkBorrowsByFunction.get(fn.name) ?? new Set();
4403
4479
  this.integerRanges = analyzeIntegerRanges(numericFn, this.int32Slots.facts(fn.name));
@@ -4417,7 +4493,9 @@ export class LlEmitter {
4417
4493
  this.currentReturnType = fn.returnType;
4418
4494
  const int32Abi = this.int32Abis.get(fn.name);
4419
4495
  this.currentInt32Result = int32Abi?.result === true;
4496
+ this.currentUnionResult = int32Abi?.union === true;
4420
4497
  this.currentGenerator = fn.generator ?? null;
4498
+ this.currentAsyncGenerator = fn.async === true && fn.generator !== undefined;
4421
4499
  this.currentBorrowedReturn = this.borrowedReturns.has(fn.name);
4422
4500
  this.inConstructor = this.constructorFunctions.has(fn.name);
4423
4501
  this.currentCoro = null;
@@ -4604,6 +4682,9 @@ export class LlEmitter {
4604
4682
  // whose unwind released everything down to depth 0).
4605
4683
  if (fn.returnType.kind === "void" && !B.isTerminated()) {
4606
4684
  this.releaseScope(this.scopes[0]);
4685
+ // Completing by falling off the end has nothing to await.
4686
+ if (this.currentAsyncGenerator)
4687
+ this.emitAsyncGenSettled();
4607
4688
  if (this.currentCoro !== null) {
4608
4689
  this.emitWasiFulfill(null);
4609
4690
  B.terminate(`br label %${this.currentCoro.finalLabel}`);
@@ -4681,7 +4762,11 @@ export class LlEmitter {
4681
4762
  // Lifted functions receive their closure first (the callValue ABI).
4682
4763
  if (fn.captures !== undefined)
4683
4764
  params.unshift("ptr %sc_env");
4684
- const ret = int32Abi?.result ? "i32" : this.llType(fn.returnType);
4765
+ const ret = int32Abi?.result
4766
+ ? "i32"
4767
+ : int32Abi?.union
4768
+ ? SCALAR_UNION_RESULT
4769
+ : this.llType(fn.returnType);
4685
4770
  let attrs = coro !== null ? "#1" : FN_ATTRS;
4686
4771
  // The shared indexed-read helper (lowerSafeIndexRead) is a dense bounds
4687
4772
  // test, a state test and a load behind cold runtime fallbacks, called
@@ -4721,7 +4806,19 @@ export class LlEmitter {
4721
4806
  args.push(`${type} %p${index}`);
4722
4807
  });
4723
4808
  const ret = this.llType(fn.returnType);
4724
- const call = `call ${abi.result ? "i32" : ret} @${symbol}${INT32_ABI_SUFFIX}(${args.join(", ")})`;
4809
+ const entry = `@${symbol}${INT32_ABI_SUFFIX}(${args.join(", ")})`;
4810
+ if (abi.union) {
4811
+ // Box the register pair for every caller of the ordinary ABI.
4812
+ const B = new BlockBuilder();
4813
+ this.B = B;
4814
+ for (const line of lines)
4815
+ B.line(line.trim());
4816
+ const pair = B.tmp();
4817
+ B.line(`${pair} = call ${SCALAR_UNION_RESULT} ${entry}`);
4818
+ B.terminate(`ret ptr ${this.boxScalarUnion(pair, fn.returnType)}`);
4819
+ return `define internal ptr @${symbol}(${params.join(", ")}) ${FN_ATTRS} {\n${B.render()}\n}`;
4820
+ }
4821
+ const call = `call ${abi.result ? "i32" : ret} ${entry}`;
4725
4822
  if (ret === "void")
4726
4823
  lines.push(` ${call}`, " ret void");
4727
4824
  else if (abi.result)
@@ -4730,6 +4827,73 @@ export class LlEmitter {
4730
4827
  lines.push(` %r = ${call}`, ` ret ${ret} %r`);
4731
4828
  return `define internal ${ret} @${symbol}(${params.join(", ")}) ${FN_ATTRS} {\nentry:\n${lines.join("\n")}\n}`;
4732
4829
  }
4830
+ /** The SCALAR_UNION_RESULT pair of a `%ScrUnion` box of `type`. */
4831
+ scalarUnionPair(box, type) {
4832
+ const B = this.B;
4833
+ const unionId = type.kind === "union" ? type.unionId : "";
4834
+ const tag = this.unionTag(box, unionId);
4835
+ const payload = B.tmp(), bits = B.tmp(), partial = B.tmp(), pair = B.tmp();
4836
+ B.line(`${payload} = getelementptr inbounds %ScrUnion, ptr ${box}, i32 0, i32 5`);
4837
+ B.line(`${bits} = load i64, ptr ${payload}`);
4838
+ B.line(`${partial} = insertvalue ${SCALAR_UNION_RESULT} poison, i32 ${tag}, 0`);
4839
+ B.line(`${pair} = insertvalue ${SCALAR_UNION_RESULT} ${partial}, i64 ${bits}, 1`);
4840
+ return pair;
4841
+ }
4842
+ /** A private stack box holding a SCALAR_UNION_RESULT pair of `type`. */
4843
+ stackScalarUnion(pair, type) {
4844
+ const B = this.B;
4845
+ const box = B.slot(), tagSlot = B.slot(), payloadSlot = B.slot();
4846
+ B.entryAllocas.push(`${box} = alloca %ScrUnion`);
4847
+ B.entryAllocas.push(`${tagSlot} = getelementptr inbounds %ScrUnion, ptr ${box}, i32 0, i32 1`);
4848
+ B.entryAllocas.push(`${payloadSlot} = getelementptr inbounds %ScrUnion, ptr ${box}, i32 0, i32 5`);
4849
+ const tag = B.tmp(), bits = B.tmp();
4850
+ B.line(`${tag} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 0`);
4851
+ B.line(`${bits} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 1`);
4852
+ B.line(`store i32 ${tag}, ptr ${tagSlot}`);
4853
+ B.line(`store i64 ${bits}, ptr ${payloadSlot}`);
4854
+ return { name: box, type };
4855
+ }
4856
+ /** A direct call whose i32 entry returns its scalar union in registers. */
4857
+ scalarResultCall(e) {
4858
+ return e.kind === "call" && this.int32Abis.get(e.callee)?.union === true;
4859
+ }
4860
+ /** A fresh heap box (+1) for a SCALAR_UNION_RESULT pair of `type`; the
4861
+ * exception dummy (tag -1) answers NULL. */
4862
+ boxScalarUnion(pair, type) {
4863
+ const B = this.B;
4864
+ const unionId = type.kind === "union" ? type.unionId : "";
4865
+ const arms = this.unionsById.get(unionId).arms;
4866
+ const tag = B.tmp(), bits = B.tmp();
4867
+ B.line(`${tag} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 0`);
4868
+ B.line(`${bits} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 1`);
4869
+ const join = B.newLabel("union.box.join"), none = B.newLabel("union.box.none");
4870
+ const labels = arms.map(() => B.newLabel("union.box.arm"));
4871
+ B.terminate(`switch i32 ${tag}, label %${none} [ ${labels.map((label, armTag) => `i32 ${armTag}, label %${label}`).join(" ")} ]`);
4872
+ const incoming = [];
4873
+ arms.forEach((arm, armTag) => {
4874
+ B.startBlock(labels[armTag]);
4875
+ let value;
4876
+ if (isUnitType(arm))
4877
+ value = this.unitInstanceRef(unionId, armTag);
4878
+ else {
4879
+ const payload = B.tmp();
4880
+ if (arm.kind === "bool")
4881
+ B.line(`${payload} = trunc i64 ${bits} to i1`);
4882
+ else
4883
+ B.line(`${payload} = bitcast i64 ${bits} to double`);
4884
+ value = this.unionNewOwned(unionId, armTag, { name: payload, type: arm });
4885
+ }
4886
+ incoming.push(`[ ${value}, %${B.currentLabel()} ]`);
4887
+ B.br(join);
4888
+ });
4889
+ B.startBlock(none);
4890
+ incoming.push(`[ null, %${none} ]`);
4891
+ B.br(join);
4892
+ B.startBlock(join);
4893
+ const box = B.tmp();
4894
+ B.line(`${box} = phi ptr ${incoming.join(", ")}`);
4895
+ return box;
4896
+ }
4733
4897
  /** The i32 bits of a number proven an int32 (a direct call's i32
4734
4898
  * argument or an i32 result): its exact integer when the value carries
4735
4899
  * one, else the conversion the proof makes exact. */
@@ -5000,6 +5164,12 @@ export class LlEmitter {
5000
5164
  this.finallyStack = savedFinally;
5001
5165
  this.tryStack = savedTry;
5002
5166
  }
5167
+ /** An async generator completing without a further turn: its request
5168
+ * settles as the body returns (scr_async_gen_hop_done). */
5169
+ emitAsyncGenSettled() {
5170
+ this.declare(`declare void @scr_async_gen_hop_done()`);
5171
+ this.B.line(`call void @scr_async_gen_hop_done()`);
5172
+ }
5003
5173
  /** `return x` of a local whose slot is an owned scope entry of the same
5004
5174
  * type: the return can take over the local's reference. */
5005
5175
  movableReturn(value) {
@@ -5200,6 +5370,17 @@ export class LlEmitter {
5200
5370
  this.scopes[this.scopes.length - 1].push({ slot: snapshot.sourceSlot, type: STRING }, { slot: snapshot.separatorSlot, type: STRING });
5201
5371
  break;
5202
5372
  }
5373
+ const stackObject = this.localStackObjects.get(s.localId);
5374
+ if (stackObject) {
5375
+ B.line(`store ptr ${emitStackObject(this, stackObject).name}, ptr ${b.slot}`);
5376
+ break;
5377
+ }
5378
+ if (s.init && this.reassignedStackObjects.has(s.localId)) {
5379
+ const slot = this.stackObjectSlot(s.localId, s.init.type);
5380
+ emitStackObject(this, s.init, slot);
5381
+ B.line(`store ptr ${slot}, ptr ${b.slot}`);
5382
+ break;
5383
+ }
5203
5384
  const localUnion = this.localStackUnions.get(s.localId);
5204
5385
  if (localUnion) {
5205
5386
  const union = emitStackUnion(this, localUnion);
@@ -5347,6 +5528,15 @@ export class LlEmitter {
5347
5528
  B.line(`store ptr ${v.name}, ptr ${owner}`);
5348
5529
  break;
5349
5530
  }
5531
+ if (this.reassignedStackObjects.has(s.localId)) {
5532
+ // The new value may read the old one: build it apart, then copy.
5533
+ const struct = stackObjectStruct(s.value.type);
5534
+ const value = emitStackObject(this, s.value);
5535
+ const bits = B.tmp();
5536
+ B.line(`${bits} = load ${struct}, ptr ${value.name}`);
5537
+ B.line(`store ${struct} ${bits}, ptr ${this.stackObjectSlot(s.localId, s.value.type)}`);
5538
+ break;
5539
+ }
5350
5540
  const localStorage = this.localUnionStorage.get(s.localId);
5351
5541
  if (localStorage) {
5352
5542
  storeLocalUnion(this, localStorage, s.value);
@@ -6199,8 +6389,16 @@ export class LlEmitter {
6199
6389
  break;
6200
6390
  }
6201
6391
  let v = null;
6202
- const moved = this.finallyStack.length === 0 ? this.movableReturn(s.value) : null;
6203
- if (moved !== null) {
6392
+ const moved = this.finallyStack.length === 0 && !this.currentUnionResult
6393
+ ? this.movableReturn(s.value)
6394
+ : null;
6395
+ if (s.value !== null && this.currentUnionResult) {
6396
+ // The tag and payload bits leave in registers; a heap box the
6397
+ // value needed is released with its frame below.
6398
+ const box = this.emitUnionProjection(s.value);
6399
+ v = { name: this.scalarUnionPair(box.name, s.value.type), type: s.value.type };
6400
+ }
6401
+ else if (moved !== null) {
6204
6402
  // Returning an owned local hands its reference to the caller: no
6205
6403
  // retain now and no release of the local below.
6206
6404
  const t = B.tmp();
@@ -6230,9 +6428,22 @@ export class LlEmitter {
6230
6428
  v = this.emitExpr(s.value);
6231
6429
  this.moveTemp(v);
6232
6430
  }
6431
+ // An async generator's `return v` awaits v before any crossed
6432
+ // finally runs. Past finally regions that turn is taken here and
6433
+ // the request settles at completion; otherwise the completion's
6434
+ // own turn is the await (nothing runs in between).
6435
+ const genSettles = this.currentAsyncGenerator && (s.awaited === true || this.finallyStack.length > 0);
6436
+ if (this.currentAsyncGenerator && s.awaited !== true && this.finallyStack.length > 0) {
6437
+ if (this.wasi)
6438
+ this.emitWasiSuspend(null);
6439
+ else {
6440
+ this.declare(`declare void @scr_await_hop()`);
6441
+ B.line(`call void @scr_await_hop()`);
6442
+ }
6443
+ }
6233
6444
  if (this.finallyStack.length > 0) {
6234
6445
  let pretSlot = null;
6235
- if (v !== null && isRefCounted(v.type)) {
6446
+ if (v !== null && isRefCounted(v.type) && !this.currentUnionResult) {
6236
6447
  pretSlot = B.slot();
6237
6448
  B.entryAllocas.push(`${pretSlot} = alloca ptr ; pending return (through finally)`);
6238
6449
  B.line(`store ptr ${v.name}, ptr ${pretSlot}`);
@@ -6265,6 +6476,8 @@ export class LlEmitter {
6265
6476
  this.releaseForJump(0, 0);
6266
6477
  }
6267
6478
  if (!B.isTerminated()) {
6479
+ if (genSettles)
6480
+ this.emitAsyncGenSettled();
6268
6481
  if (this.currentCoro !== null) {
6269
6482
  this.emitWasiFulfill(v);
6270
6483
  B.terminate(`br label %${this.currentCoro.finalLabel}`);
@@ -6273,6 +6486,8 @@ export class LlEmitter {
6273
6486
  B.terminate("ret void");
6274
6487
  else if (this.currentInt32Result)
6275
6488
  B.terminate(`ret i32 ${this.int32Argument(v, s.value)}`);
6489
+ else if (this.currentUnionResult)
6490
+ B.terminate(`ret ${SCALAR_UNION_RESULT} ${v.name}`);
6276
6491
  else
6277
6492
  B.terminate(`ret ${this.llType(s.value.type)} ${v.name}`);
6278
6493
  }
@@ -6787,8 +7002,45 @@ export class LlEmitter {
6787
7002
  emitIntrinsicExpr(e) {
6788
7003
  if (e.name === "threads.publish")
6789
7004
  return this.emitPublish(e);
7005
+ if (e.name === "region.create" ||
7006
+ e.name === "region.enter" ||
7007
+ e.name === "region.leave" ||
7008
+ e.name === "region.release")
7009
+ return this.emitRegionIntrinsic(e);
6790
7010
  return emitIntrinsicExpr(this, e);
6791
7011
  }
7012
+ /** Lifetime regions in modules with lifetimeRegions (llvm/regions.ts).
7013
+ * Created with the class graph; null elsewhere. */
7014
+ regions = null;
7015
+ /** LifetimeRegion's runtime calls: create answers the region id, enter
7016
+ * and leave bracket run(), release condemns. */
7017
+ emitRegionIntrinsic(e) {
7018
+ if (this.regions === null)
7019
+ throw new InternalCompilerError(`llvm emitter bug: ${e.name} without lifetimeRegions`);
7020
+ const args = e.args.map((a) => this.emitExpr(a));
7021
+ if (this.B.isTerminated())
7022
+ return { name: "", type: e.type };
7023
+ switch (e.name) {
7024
+ case "region.create": {
7025
+ this.declare(`declare double @scr_region_create(ptr)`);
7026
+ const id = this.B.tmp();
7027
+ this.B.line(`${id} = call double @scr_region_create(ptr ${REGION_TYPES})`);
7028
+ return { name: id, type: e.type };
7029
+ }
7030
+ case "region.enter":
7031
+ this.declare(`declare void @scr_region_enter(double)`);
7032
+ this.B.line(`call void @scr_region_enter(double ${args[0].name})`);
7033
+ break;
7034
+ case "region.leave":
7035
+ this.declare(`declare void @scr_region_leave()`);
7036
+ this.B.line(`call void @scr_region_leave()`);
7037
+ break;
7038
+ default:
7039
+ this.declare(`declare void @scr_region_release(double)`);
7040
+ this.B.line(`call void @scr_region_release(double ${args[0].name})`);
7041
+ }
7042
+ return { name: "", type: e.type };
7043
+ }
6792
7044
  publishWalkersCache = null;
6793
7045
  /** Per-type publication walkers, created on the first publish. */
6794
7046
  get publishWalkers() {
@@ -7075,10 +7327,30 @@ export class LlEmitter {
7075
7327
  B.line(`${value} = load ptr, ptr ${slot}`);
7076
7328
  return { name: value, type: e.type };
7077
7329
  }
7330
+ // Scalar optional values and register results answer a private stack
7331
+ // box. A ternary of borrowable arms above keeps lending its arm.
7332
+ if ((e.kind === "optChain" ||
7333
+ e.kind === "nullish" ||
7334
+ e.kind === "ternary" ||
7335
+ e.kind === "arrIntrinsic") &&
7336
+ isScalarOptionalSource(e, this.unionSources))
7337
+ return emitScalarOptional(this, e);
7338
+ if (e.kind === "call" && this.scalarResultCall(e))
7339
+ return emitCallExpr(this, e, false, true);
7078
7340
  if (e.kind === "call" && this.canBorrowReceiver(e))
7079
7341
  return emitBorrowedResultCall(this, e);
7080
7342
  return this.emitExpr(e);
7081
7343
  }
7344
+ /** The frame slot a reassigned stack-object local keeps for its value. */
7345
+ stackObjectSlot(localId, type) {
7346
+ let slot = this.stackObjectSlots.get(localId);
7347
+ if (slot === undefined) {
7348
+ slot = this.B.slot();
7349
+ this.B.entryAllocas.push(`${slot} = alloca ${stackObjectStruct(type)}, align 8`);
7350
+ this.stackObjectSlots.set(localId, slot);
7351
+ }
7352
+ return slot;
7353
+ }
7082
7354
  /** A private stack union source with an independently owned payload. */
7083
7355
  canStackReceiver(e) {
7084
7356
  return this.isStackUnionSource(e);
@@ -7090,7 +7362,9 @@ export class LlEmitter {
7090
7362
  return false;
7091
7363
  return (canStackUnion(e, this.boxedUnionsById) ||
7092
7364
  matchMapRead(e, this.boxedUnionsById) !== null ||
7093
- this.optionalArrayReads.get(e) !== null);
7365
+ this.optionalArrayReads.get(e) !== null ||
7366
+ isScalarOptionalSource(e, this.unionSources) ||
7367
+ this.scalarResultCall(e));
7094
7368
  }
7095
7369
  /** The nullable-pointer representation behind a union-typed class field
7096
7370
  * read, or null for every other expression. */