@scriptc/compiler 0.3.1 → 0.3.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 (492) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +832 -55
  2. package/dist/backend/cycle-analysis.js +6 -1
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/executable-features.js +1 -0
  5. package/dist/backend/executable-features.js.map +1 -1
  6. package/dist/backend/literals.d.ts +7 -0
  7. package/dist/backend/literals.js +32 -0
  8. package/dist/backend/literals.js.map +1 -1
  9. package/dist/backend/literals.test.js +17 -1
  10. package/dist/backend/literals.test.js.map +1 -1
  11. package/dist/backend/llvm/alloc.d.ts +15 -4
  12. package/dist/backend/llvm/alloc.js +63 -25
  13. package/dist/backend/llvm/alloc.js.map +1 -1
  14. package/dist/backend/llvm/alloc.test.js +62 -2
  15. package/dist/backend/llvm/alloc.test.js.map +1 -1
  16. package/dist/backend/llvm/appended-array-literals.d.ts +2 -0
  17. package/dist/backend/llvm/appended-array-literals.js +109 -0
  18. package/dist/backend/llvm/appended-array-literals.js.map +1 -0
  19. package/dist/backend/llvm/appended-array-literals.test.d.ts +1 -0
  20. package/dist/backend/llvm/appended-array-literals.test.js +90 -0
  21. package/dist/backend/llvm/appended-array-literals.test.js.map +1 -0
  22. package/dist/backend/llvm/array-search.d.ts +8 -0
  23. package/dist/backend/llvm/array-search.js +52 -0
  24. package/dist/backend/llvm/array-search.js.map +1 -0
  25. package/dist/backend/llvm/array-search.test.d.ts +1 -0
  26. package/dist/backend/llvm/array-search.test.js +72 -0
  27. package/dist/backend/llvm/array-search.test.js.map +1 -0
  28. package/dist/backend/llvm/call-lifetimes.d.ts +11 -1
  29. package/dist/backend/llvm/call-lifetimes.js +74 -4
  30. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  31. package/dist/backend/llvm/call-lifetimes.test.js +54 -0
  32. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  33. package/dist/backend/llvm/classes.js +97 -38
  34. package/dist/backend/llvm/classes.js.map +1 -1
  35. package/dist/backend/llvm/classes.test.js +2 -2
  36. package/dist/backend/llvm/common.d.ts +1 -1
  37. package/dist/backend/llvm/common.js +1 -1
  38. package/dist/backend/llvm/dense-array-access.d.ts +5 -0
  39. package/dist/backend/llvm/dense-array-access.js +18 -13
  40. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  41. package/dist/backend/llvm/dense-array-access.test.js +15 -2
  42. package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
  43. package/dist/backend/llvm/dyn.d.ts +6 -0
  44. package/dist/backend/llvm/dyn.js +84 -11
  45. package/dist/backend/llvm/dyn.js.map +1 -1
  46. package/dist/backend/llvm/emitter.d.ts +108 -16
  47. package/dist/backend/llvm/emitter.js +598 -108
  48. package/dist/backend/llvm/emitter.js.map +1 -1
  49. package/dist/backend/llvm/emitter.test.js +26 -3
  50. package/dist/backend/llvm/emitter.test.js.map +1 -1
  51. package/dist/backend/llvm/expr-async.js +174 -7
  52. package/dist/backend/llvm/expr-async.js.map +1 -1
  53. package/dist/backend/llvm/expr-bytes.js +11 -0
  54. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  55. package/dist/backend/llvm/expr-callbacks.d.ts +8 -0
  56. package/dist/backend/llvm/expr-callbacks.js +96 -2
  57. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  58. package/dist/backend/llvm/expr-calls.d.ts +12 -1
  59. package/dist/backend/llvm/expr-calls.js +133 -54
  60. package/dist/backend/llvm/expr-calls.js.map +1 -1
  61. package/dist/backend/llvm/expr-containers.d.ts +7 -0
  62. package/dist/backend/llvm/expr-containers.js +80 -22
  63. package/dist/backend/llvm/expr-containers.js.map +1 -1
  64. package/dist/backend/llvm/expr-context.d.ts +2 -0
  65. package/dist/backend/llvm/expr-control.d.ts +8 -0
  66. package/dist/backend/llvm/expr-control.js +103 -69
  67. package/dist/backend/llvm/expr-control.js.map +1 -1
  68. package/dist/backend/llvm/expr-dynamic.js +21 -10
  69. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  70. package/dist/backend/llvm/expr-primitives.d.ts +7 -0
  71. package/dist/backend/llvm/expr-primitives.js +53 -51
  72. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  73. package/dist/backend/llvm/expr-records.js +19 -5
  74. package/dist/backend/llvm/expr-records.js.map +1 -1
  75. package/dist/backend/llvm/expr-stream-bridges.d.ts +8 -0
  76. package/dist/backend/llvm/expr-stream-bridges.js +111 -39
  77. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  78. package/dist/backend/llvm/expr-stream-bridges.test.js +49 -1
  79. package/dist/backend/llvm/expr-stream-bridges.test.js.map +1 -1
  80. package/dist/backend/llvm/expr-stream-callbacks.d.ts +13 -2
  81. package/dist/backend/llvm/expr-stream-callbacks.js +80 -5
  82. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  83. package/dist/backend/llvm/inline-unions.d.ts +48 -0
  84. package/dist/backend/llvm/inline-unions.js +134 -0
  85. package/dist/backend/llvm/inline-unions.js.map +1 -0
  86. package/dist/backend/llvm/inline-unions.test.d.ts +1 -0
  87. package/dist/backend/llvm/inline-unions.test.js +124 -0
  88. package/dist/backend/llvm/inline-unions.test.js.map +1 -0
  89. package/dist/backend/llvm/int32-abi.d.ts +18 -2
  90. package/dist/backend/llvm/int32-abi.js +23 -2
  91. package/dist/backend/llvm/int32-abi.js.map +1 -1
  92. package/dist/backend/llvm/int32-abi.test.js +75 -1
  93. package/dist/backend/llvm/int32-abi.test.js.map +1 -1
  94. package/dist/backend/llvm/integer-remainder.d.ts +28 -5
  95. package/dist/backend/llvm/integer-remainder.js +80 -9
  96. package/dist/backend/llvm/integer-remainder.js.map +1 -1
  97. package/dist/backend/llvm/lib-dispatch.js +170 -28
  98. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  99. package/dist/backend/llvm/lib-filesystem.js +181 -5
  100. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  101. package/dist/backend/llvm/lib-network.js +9 -6
  102. package/dist/backend/llvm/lib-network.js.map +1 -1
  103. package/dist/backend/llvm/lib-process.js +2 -2
  104. package/dist/backend/llvm/lib-process.js.map +1 -1
  105. package/dist/backend/llvm/lib-shared.js +208 -9
  106. package/dist/backend/llvm/lib-shared.js.map +1 -1
  107. package/dist/backend/llvm/lib-stream.js +97 -0
  108. package/dist/backend/llvm/lib-stream.js.map +1 -1
  109. package/dist/backend/llvm/local-array-reads.js +12 -6
  110. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  111. package/dist/backend/llvm/local-array-reads.test.js +6 -3
  112. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  113. package/dist/backend/llvm/local-union-storage.d.ts +26 -2
  114. package/dist/backend/llvm/local-union-storage.js +132 -12
  115. package/dist/backend/llvm/local-union-storage.js.map +1 -1
  116. package/dist/backend/llvm/local-union-storage.test.js +107 -1
  117. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  118. package/dist/backend/llvm/loop-array-borrows.d.ts +8 -2
  119. package/dist/backend/llvm/loop-array-borrows.js +93 -13
  120. package/dist/backend/llvm/loop-array-borrows.js.map +1 -1
  121. package/dist/backend/llvm/map-number-lookup.d.ts +20 -0
  122. package/dist/backend/llvm/map-number-lookup.js +66 -0
  123. package/dist/backend/llvm/map-number-lookup.js.map +1 -1
  124. package/dist/backend/llvm/map-number-lookup.test.d.ts +1 -0
  125. package/dist/backend/llvm/map-number-lookup.test.js +102 -0
  126. package/dist/backend/llvm/map-number-lookup.test.js.map +1 -0
  127. package/dist/backend/llvm/map-read-lifetimes.js +1 -0
  128. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  129. package/dist/backend/llvm/publish.d.ts +4 -0
  130. package/dist/backend/llvm/publish.js +3 -1
  131. package/dist/backend/llvm/publish.js.map +1 -1
  132. package/dist/backend/llvm/record-results.d.ts +29 -0
  133. package/dist/backend/llvm/record-results.js +260 -0
  134. package/dist/backend/llvm/record-results.js.map +1 -0
  135. package/dist/backend/llvm/reference-effects.js +15 -0
  136. package/dist/backend/llvm/reference-effects.js.map +1 -1
  137. package/dist/backend/llvm/reference-writes.js +29 -9
  138. package/dist/backend/llvm/reference-writes.js.map +1 -1
  139. package/dist/backend/llvm/regions.d.ts +68 -0
  140. package/dist/backend/llvm/regions.js +314 -0
  141. package/dist/backend/llvm/regions.js.map +1 -0
  142. package/dist/backend/llvm/regions.test.d.ts +1 -0
  143. package/dist/backend/llvm/regions.test.js +173 -0
  144. package/dist/backend/llvm/regions.test.js.map +1 -0
  145. package/dist/backend/llvm/serialized-ir-emission.test.js +2 -0
  146. package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -1
  147. package/dist/backend/llvm/shapes.d.ts +86 -13
  148. package/dist/backend/llvm/shapes.js +208 -54
  149. package/dist/backend/llvm/shapes.js.map +1 -1
  150. package/dist/backend/llvm/shapes.test.js +68 -9
  151. package/dist/backend/llvm/shapes.test.js.map +1 -1
  152. package/dist/backend/llvm/split-loops.js +1 -1
  153. package/dist/backend/llvm/split-loops.js.map +1 -1
  154. package/dist/backend/llvm/stack-objects.d.ts +29 -0
  155. package/dist/backend/llvm/stack-objects.js +142 -0
  156. package/dist/backend/llvm/stack-objects.js.map +1 -0
  157. package/dist/backend/llvm/stack-objects.test.d.ts +1 -0
  158. package/dist/backend/llvm/stack-objects.test.js +255 -0
  159. package/dist/backend/llvm/stack-objects.test.js.map +1 -0
  160. package/dist/backend/llvm/string-reads.d.ts +4 -1
  161. package/dist/backend/llvm/string-reads.js +89 -9
  162. package/dist/backend/llvm/string-reads.js.map +1 -1
  163. package/dist/backend/llvm/switch-dispatch.js +5 -4
  164. package/dist/backend/llvm/switch-dispatch.js.map +1 -1
  165. package/dist/backend/llvm/walkers.d.ts +13 -0
  166. package/dist/backend/llvm/walkers.js +108 -10
  167. package/dist/backend/llvm/walkers.js.map +1 -1
  168. package/dist/backend/may-throw.js +10 -4
  169. package/dist/backend/may-throw.js.map +1 -1
  170. package/dist/backend/native/contracts.d.ts +7 -2
  171. package/dist/backend/native/executable.js +28 -2
  172. package/dist/backend/native/executable.js.map +1 -1
  173. package/dist/backend/native/library.js +1 -1
  174. package/dist/backend/native/library.js.map +1 -1
  175. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  176. package/dist/backend/native/runtime-inputs.js +3 -0
  177. package/dist/backend/native/runtime-inputs.js.map +1 -1
  178. package/dist/backend/native-link-info-core.d.ts +1 -0
  179. package/dist/backend/native-link-info-core.js.map +1 -1
  180. package/dist/backend/native-toolchain.test.js +1 -1
  181. package/dist/backend/native-toolchain.test.js.map +1 -1
  182. package/dist/backend/runtime-abi.d.ts +2 -2
  183. package/dist/backend/runtime-abi.js +2 -2
  184. package/dist/backend/runtime-pack-core.d.ts +1 -0
  185. package/dist/backend/runtime-pack-core.js +1 -0
  186. package/dist/backend/runtime-pack-core.js.map +1 -1
  187. package/dist/backend/runtime-pack-targets.test.js +1 -1
  188. package/dist/backend/runtime-pack.test.js +1 -1
  189. package/dist/backend/target-diagnostics.js +17 -0
  190. package/dist/backend/target-diagnostics.js.map +1 -1
  191. package/dist/backend/target-diagnostics.test.js +16 -0
  192. package/dist/backend/target-diagnostics.test.js.map +1 -1
  193. package/dist/compat/fetch-profile.js +4 -4
  194. package/dist/compat/fetch-profile.js.map +1 -1
  195. package/dist/contracts/check.js +2 -0
  196. package/dist/contracts/check.js.map +1 -1
  197. package/dist/coverage/report.js +1 -1
  198. package/dist/coverage/report.js.map +1 -1
  199. package/dist/diagnostics/diagnostic.d.ts +6 -5
  200. package/dist/diagnostics/diagnostic.js +7 -6
  201. package/dist/diagnostics/diagnostic.js.map +1 -1
  202. package/dist/executable/executable-cache.d.ts +1 -0
  203. package/dist/executable/executable-cache.js.map +1 -1
  204. package/dist/frontend/builtin-modules.d.ts +1 -1
  205. package/dist/frontend/builtin-modules.js +1 -0
  206. package/dist/frontend/builtin-modules.js.map +1 -1
  207. package/dist/frontend/comptime-node.js +2 -2
  208. package/dist/frontend/comptime-node.js.map +1 -1
  209. package/dist/frontend/experimental-import.d.ts +12 -0
  210. package/dist/frontend/experimental-import.js +63 -0
  211. package/dist/frontend/experimental-import.js.map +1 -0
  212. package/dist/frontend/lowering/binding-analysis.d.ts +1 -1
  213. package/dist/frontend/lowering/binding-analysis.js +1 -1
  214. package/dist/frontend/lowering/builtin-calls.d.ts +6 -1
  215. package/dist/frontend/lowering/builtin-calls.js +36 -0
  216. package/dist/frontend/lowering/builtin-calls.js.map +1 -1
  217. package/dist/frontend/lowering/builtins/arguments.d.ts +4 -0
  218. package/dist/frontend/lowering/builtins/arguments.js +8 -4
  219. package/dist/frontend/lowering/builtins/arguments.js.map +1 -1
  220. package/dist/frontend/lowering/builtins/blob.d.ts +20 -0
  221. package/dist/frontend/lowering/builtins/blob.js +167 -0
  222. package/dist/frontend/lowering/builtins/blob.js.map +1 -0
  223. package/dist/frontend/lowering/builtins/child-process-async.d.ts +2 -2
  224. package/dist/frontend/lowering/builtins/child-process-async.js +2 -2
  225. package/dist/frontend/lowering/builtins/child-process-methods.js +1 -1
  226. package/dist/frontend/lowering/builtins/child-process-methods.js.map +1 -1
  227. package/dist/frontend/lowering/builtins/child-process-sync.js +1 -1
  228. package/dist/frontend/lowering/builtins/child-process-sync.js.map +1 -1
  229. package/dist/frontend/lowering/builtins/compression.js +3 -2
  230. package/dist/frontend/lowering/builtins/compression.js.map +1 -1
  231. package/dist/frontend/lowering/builtins/console.d.ts +16 -6
  232. package/dist/frontend/lowering/builtins/console.js +33 -9
  233. package/dist/frontend/lowering/builtins/console.js.map +1 -1
  234. package/dist/frontend/lowering/builtins/crypto.js +415 -120
  235. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  236. package/dist/frontend/lowering/builtins/errors.js +20 -0
  237. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  238. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +10 -0
  239. package/dist/frontend/lowering/builtins/filesystem-calls.js +89 -1
  240. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  241. package/dist/frontend/lowering/builtins/filesystem.d.ts +16 -7
  242. package/dist/frontend/lowering/builtins/filesystem.js +97 -15
  243. package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
  244. package/dist/frontend/lowering/builtins/fs-glob.d.ts +23 -0
  245. package/dist/frontend/lowering/builtins/fs-glob.js +224 -0
  246. package/dist/frontend/lowering/builtins/fs-glob.js.map +1 -0
  247. package/dist/frontend/lowering/builtins/json.d.ts +2 -2
  248. package/dist/frontend/lowering/builtins/json.js +13 -4
  249. package/dist/frontend/lowering/builtins/json.js.map +1 -1
  250. package/dist/frontend/lowering/builtins/key-object.d.ts +13 -0
  251. package/dist/frontend/lowering/builtins/key-object.js +56 -0
  252. package/dist/frontend/lowering/builtins/key-object.js.map +1 -0
  253. package/dist/frontend/lowering/builtins/module-calls.js +60 -12
  254. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  255. package/dist/frontend/lowering/builtins/numbers.d.ts +1 -0
  256. package/dist/frontend/lowering/builtins/numbers.js +17 -0
  257. package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
  258. package/dist/frontend/lowering/builtins/operating-system.d.ts +18 -0
  259. package/dist/frontend/lowering/builtins/operating-system.js +361 -1
  260. package/dist/frontend/lowering/builtins/operating-system.js.map +1 -1
  261. package/dist/frontend/lowering/builtins/performance.d.ts +25 -3
  262. package/dist/frontend/lowering/builtins/performance.js +340 -5
  263. package/dist/frontend/lowering/builtins/performance.js.map +1 -1
  264. package/dist/frontend/lowering/builtins/process.d.ts +2 -2
  265. package/dist/frontend/lowering/builtins/process.js +122 -17
  266. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  267. package/dist/frontend/lowering/builtins/promises.js +109 -2
  268. package/dist/frontend/lowering/builtins/promises.js.map +1 -1
  269. package/dist/frontend/lowering/builtins/properties.d.ts +0 -7
  270. package/dist/frontend/lowering/builtins/properties.js +39 -11
  271. package/dist/frontend/lowering/builtins/properties.js.map +1 -1
  272. package/dist/frontend/lowering/builtins/readline.d.ts +23 -8
  273. package/dist/frontend/lowering/builtins/readline.js +266 -90
  274. package/dist/frontend/lowering/builtins/readline.js.map +1 -1
  275. package/dist/frontend/lowering/builtins/text-codecs.d.ts +3 -4
  276. package/dist/frontend/lowering/builtins/text-codecs.js +3 -4
  277. package/dist/frontend/lowering/builtins/text-codecs.js.map +1 -1
  278. package/dist/frontend/lowering/builtins/url.d.ts +8 -0
  279. package/dist/frontend/lowering/builtins/url.js +36 -0
  280. package/dist/frontend/lowering/builtins/url.js.map +1 -1
  281. package/dist/frontend/lowering/call-arguments.js +1 -1
  282. package/dist/frontend/lowering/call-arguments.js.map +1 -1
  283. package/dist/frontend/lowering/call-signatures.js +20 -2
  284. package/dist/frontend/lowering/call-signatures.js.map +1 -1
  285. package/dist/frontend/lowering/checked-promise-all.d.ts +10 -3
  286. package/dist/frontend/lowering/checked-promise-all.js +52 -6
  287. package/dist/frontend/lowering/checked-promise-all.js.map +1 -1
  288. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +8 -3
  289. package/dist/frontend/lowering/class-dynamic-dispatch.js +159 -32
  290. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  291. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +1 -0
  292. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  293. package/dist/frontend/lowering/class-protocol-dispatch.d.ts +45 -0
  294. package/dist/frontend/lowering/class-protocol-dispatch.js +516 -0
  295. package/dist/frontend/lowering/class-protocol-dispatch.js.map +1 -0
  296. package/dist/frontend/lowering/coercions/structural-plans.js +2 -1
  297. package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
  298. package/dist/frontend/lowering/coercions/structural.js +3 -3
  299. package/dist/frontend/lowering/coercions/structural.js.map +1 -1
  300. package/dist/frontend/lowering/collation-repertoire.js +6 -5
  301. package/dist/frontend/lowering/collation-repertoire.js.map +1 -1
  302. package/dist/frontend/lowering/containers/array-callbacks.js +33 -6
  303. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  304. package/dist/frontend/lowering/containers/array-construction.js +8 -4
  305. package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
  306. package/dist/frontend/lowering/containers/array-methods.d.ts +0 -7
  307. package/dist/frontend/lowering/containers/array-methods.js +43 -2
  308. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  309. package/dist/frontend/lowering/containers/array-pipelines.js +1 -1
  310. package/dist/frontend/lowering/containers/array-pipelines.js.map +1 -1
  311. package/dist/frontend/lowering/containers/bytes.js +38 -26
  312. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  313. package/dist/frontend/lowering/containers/for-of.d.ts +1 -1
  314. package/dist/frontend/lowering/containers/for-of.js +5 -1
  315. package/dist/frontend/lowering/containers/for-of.js.map +1 -1
  316. package/dist/frontend/lowering/containers/indexed-objects.js +1 -1
  317. package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
  318. package/dist/frontend/lowering/containers/string-and-regexp.js +91 -0
  319. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  320. package/dist/frontend/lowering/crypto-tables.d.ts +3 -3
  321. package/dist/frontend/lowering/crypto-tables.js +77 -12
  322. package/dist/frontend/lowering/crypto-tables.js.map +1 -1
  323. package/dist/frontend/lowering/cycle-initialization.d.ts +18 -2
  324. package/dist/frontend/lowering/cycle-initialization.js +166 -12
  325. package/dist/frontend/lowering/cycle-initialization.js.map +1 -1
  326. package/dist/frontend/lowering/deferred-module-initializers.js +7 -2
  327. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -1
  328. package/dist/frontend/lowering/deferred-module-initializers.test.js +28 -0
  329. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -1
  330. package/dist/frontend/lowering/expressions/nullish-assignment.js +10 -0
  331. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  332. package/dist/frontend/lowering/expressions/object-literals.js +21 -68
  333. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  334. package/dist/frontend/lowering/generator-delegation.d.ts +8 -0
  335. package/dist/frontend/lowering/generator-delegation.js +231 -10
  336. package/dist/frontend/lowering/generator-delegation.js.map +1 -1
  337. package/dist/frontend/lowering/generic-functions.d.ts +2 -2
  338. package/dist/frontend/lowering/generic-functions.js +2 -2
  339. package/dist/frontend/lowering/generic-functions.js.map +1 -1
  340. package/dist/frontend/lowering/http2-constants.js +1 -1
  341. package/dist/frontend/lowering/lifetime-regions.d.ts +11 -0
  342. package/dist/frontend/lowering/lifetime-regions.js +216 -0
  343. package/dist/frontend/lowering/lifetime-regions.js.map +1 -0
  344. package/dist/frontend/lowering/lower-array-sort.d.ts +40 -3
  345. package/dist/frontend/lowering/lower-array-sort.js +661 -194
  346. package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
  347. package/dist/frontend/lowering/lower-array-sort.test.js +103 -4
  348. package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -1
  349. package/dist/frontend/lowering/lower-assert.js +2 -2
  350. package/dist/frontend/lowering/lower-async-iteration.d.ts +6 -3
  351. package/dist/frontend/lowering/lower-async-iteration.js +248 -2
  352. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
  353. package/dist/frontend/lowering/lower-calls.js +173 -111
  354. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  355. package/dist/frontend/lowering/lower-classes.d.ts +12 -5
  356. package/dist/frontend/lowering/lower-classes.js +156 -11
  357. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  358. package/dist/frontend/lowering/lower-comptime.d.ts +1 -1
  359. package/dist/frontend/lowering/lower-comptime.js +4 -4
  360. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  361. package/dist/frontend/lowering/lower-console.d.ts +13 -0
  362. package/dist/frontend/lowering/lower-console.js +460 -4
  363. package/dist/frontend/lowering/lower-console.js.map +1 -1
  364. package/dist/frontend/lowering/lower-event-emitter.d.ts +6 -0
  365. package/dist/frontend/lowering/lower-event-emitter.js +124 -38
  366. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  367. package/dist/frontend/lowering/lower-event-target.d.ts +63 -0
  368. package/dist/frontend/lowering/lower-event-target.js +362 -0
  369. package/dist/frontend/lowering/lower-event-target.js.map +1 -0
  370. package/dist/frontend/lowering/lower-expando.js +2 -2
  371. package/dist/frontend/lowering/lower-exprs.js +247 -42
  372. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  373. package/dist/frontend/lowering/lower-generators.d.ts +15 -7
  374. package/dist/frontend/lowering/lower-generators.js +183 -99
  375. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  376. package/dist/frontend/lowering/lower-inspect.d.ts +8 -1
  377. package/dist/frontend/lowering/lower-inspect.js +247 -28
  378. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  379. package/dist/frontend/lowering/lower-mixins.js +1 -1
  380. package/dist/frontend/lowering/lower-modules.d.ts +1 -1
  381. package/dist/frontend/lowering/lower-modules.js +27 -17
  382. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  383. package/dist/frontend/lowering/lower-namespaces.d.ts +2 -2
  384. package/dist/frontend/lowering/lower-namespaces.js +2 -2
  385. package/dist/frontend/lowering/lower-server.js +39 -14
  386. package/dist/frontend/lowering/lower-server.js.map +1 -1
  387. package/dist/frontend/lowering/lower-stdlib.d.ts +11 -1
  388. package/dist/frontend/lowering/lower-stdlib.js +45 -4
  389. package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
  390. package/dist/frontend/lowering/lower-stmts.d.ts +2 -2
  391. package/dist/frontend/lowering/lower-stmts.js +112 -23
  392. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  393. package/dist/frontend/lowering/lower-stream.js +234 -22
  394. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  395. package/dist/frontend/lowering/lower-timers.js +1 -1
  396. package/dist/frontend/lowering/lowerer.d.ts +45 -6
  397. package/dist/frontend/lowering/lowerer.js +360 -48
  398. package/dist/frontend/lowering/lowerer.js.map +1 -1
  399. package/dist/frontend/lowering/native-ffi.js +2 -2
  400. package/dist/frontend/lowering/native-ffi.js.map +1 -1
  401. package/dist/frontend/lowering/regex-span-reads.d.ts +12 -0
  402. package/dist/frontend/lowering/regex-span-reads.js +164 -0
  403. package/dist/frontend/lowering/regex-span-reads.js.map +1 -0
  404. package/dist/frontend/lowering/runtime-optional-records.d.ts +115 -0
  405. package/dist/frontend/lowering/runtime-optional-records.js +715 -0
  406. package/dist/frontend/lowering/runtime-optional-records.js.map +1 -0
  407. package/dist/frontend/lowering/runtime-optional-records.test.d.ts +1 -0
  408. package/dist/frontend/lowering/runtime-optional-records.test.js +175 -0
  409. package/dist/frontend/lowering/runtime-optional-records.test.js.map +1 -0
  410. package/dist/frontend/lowering/surfaces.d.ts +7 -3
  411. package/dist/frontend/lowering/surfaces.js +385 -32
  412. package/dist/frontend/lowering/surfaces.js.map +1 -1
  413. package/dist/frontend/lowering/var-hoisting.d.ts +3 -0
  414. package/dist/frontend/lowering/var-hoisting.js +261 -0
  415. package/dist/frontend/lowering/var-hoisting.js.map +1 -0
  416. package/dist/frontend/module-syntax.d.ts +1 -1
  417. package/dist/frontend/module-syntax.js +1 -1
  418. package/dist/frontend/npm-static-prune.js +1 -1
  419. package/dist/frontend/npm-static-prune.js.map +1 -1
  420. package/dist/frontend/npm-static-rewrite-syntax.js +4 -3
  421. package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -1
  422. package/dist/frontend/pipeline.js +6 -4
  423. package/dist/frontend/pipeline.js.map +1 -1
  424. package/dist/frontend/program.d.ts +6 -5
  425. package/dist/frontend/program.js +42 -22
  426. package/dist/frontend/program.js.map +1 -1
  427. package/dist/frontend/program.test.js +13 -0
  428. package/dist/frontend/program.test.js.map +1 -1
  429. package/dist/frontend/resolve.js +1 -1
  430. package/dist/frontend/ts7/adapter.js +1 -1
  431. package/dist/frontend/ts7/ast-bytes.d.ts +1 -1
  432. package/dist/frontend/ts7/ast-bytes.js +1 -1
  433. package/dist/frontend/ts7/semantic-json.d.ts +1 -1
  434. package/dist/frontend/ts7/semantic-json.js +1 -1
  435. package/dist/frontend/ts7/semantic-json.js.map +1 -1
  436. package/dist/frontend/ts7/world-check.js +1 -1
  437. package/dist/frontend/tsc-codes.js +2 -2
  438. package/dist/frontend/tsc-codes.js.map +1 -1
  439. package/dist/frontend/type-mapper.d.ts +28 -1
  440. package/dist/frontend/type-mapper.js +288 -30
  441. package/dist/frontend/type-mapper.js.map +1 -1
  442. package/dist/index.js +6 -4
  443. package/dist/index.js.map +1 -1
  444. package/dist/ir/analysis.d.ts +12 -6
  445. package/dist/ir/analysis.js +26 -10
  446. package/dist/ir/analysis.js.map +1 -1
  447. package/dist/ir/analysis.test.js +15 -3
  448. package/dist/ir/analysis.test.js.map +1 -1
  449. package/dist/ir/builtin-effects.js +108 -2
  450. package/dist/ir/builtin-effects.js.map +1 -1
  451. package/dist/ir/builtin-signatures.d.ts +1 -1
  452. package/dist/ir/builtin-signatures.js +436 -53
  453. package/dist/ir/builtin-signatures.js.map +1 -1
  454. package/dist/ir/function-references.test.js +1 -0
  455. package/dist/ir/function-references.test.js.map +1 -1
  456. package/dist/ir/int32-slots.js +2 -0
  457. package/dist/ir/int32-slots.js.map +1 -1
  458. package/dist/ir/intrinsic-signatures.js +2 -0
  459. package/dist/ir/intrinsic-signatures.js.map +1 -1
  460. package/dist/ir/ir.d.ts +129 -36
  461. package/dist/ir/ir.js +42 -1
  462. package/dist/ir/ir.js.map +1 -1
  463. package/dist/ir/runtime-features.d.ts +1 -0
  464. package/dist/ir/runtime-features.js +116 -5
  465. package/dist/ir/runtime-features.js.map +1 -1
  466. package/dist/ir/scalar-records.js +1 -2
  467. package/dist/ir/scalar-records.js.map +1 -1
  468. package/dist/ir/serialize.js +1 -1
  469. package/dist/ir/serialize.js.map +1 -1
  470. package/dist/ir/traverse.js +1 -0
  471. package/dist/ir/traverse.js.map +1 -1
  472. package/dist/ir/validate.js +250 -34
  473. package/dist/ir/validate.js.map +1 -1
  474. package/dist/ir/validate.test.js +125 -0
  475. package/dist/ir/validate.test.js.map +1 -1
  476. package/dist/library/fence-eval.d.ts +1 -1
  477. package/dist/library/fence-eval.js +5 -4
  478. package/dist/library/fence-eval.js.map +1 -1
  479. package/dist/library/ir-policy.js +11 -4
  480. package/dist/library/ir-policy.js.map +1 -1
  481. package/dist/library/library-profile.js +13 -13
  482. package/dist/library/library-profile.js.map +1 -1
  483. package/dist/library/prepare.js +1 -1
  484. package/dist/library/prepare.js.map +1 -1
  485. package/dist/library/sidecar.js +3 -3
  486. package/dist/library/sidecar.js.map +1 -1
  487. package/dist/native/prepare.js +3 -2
  488. package/dist/native/prepare.js.map +1 -1
  489. package/dist/native/sanitizer.test.js +1 -0
  490. package/dist/native/sanitizer.test.js.map +1 -1
  491. package/package.json +20 -20
  492. package/surface-manifest.json +537 -142
@@ -1,13 +1,15 @@
1
+ import { emitArraySearchHelpers } from "./array-search.js";
2
+ import { emitStringInputs } from "./string-lifetimes.js";
1
3
  import { emitLlvmLayouts } from "./layouts.js";
2
4
  import { compileRegexMatcher } from "./regex-matchers.js";
3
- import { FIRST_EMITTED_CYC_KIND, inlineAllocSupported } from "./alloc.js";
4
- import { llvmBytes as llBytes } from "../literals.js";
5
+ import { CYC_BUF, CYC_HDR, FIRST_EMITTED_CYC_KIND, inlineAllocSupported } from "./alloc.js";
6
+ import { hasLoneSurrogate, llvmBytes as llBytes, wtf8Bytes } from "../literals.js";
5
7
  import { InternalCompilerError } from "../../errors.js";
6
8
  import { createHash } from "node:crypto";
7
9
  import { endsWithJump, matchStringSelfConcat, streamTypedRefEligible, undefinedArmTag, } from "../../ir/analysis.js";
8
10
  import { emitLibraryIdentityLines } from "../library-identity-markers.js";
9
11
  import { loopTestsEveryIteration } from "../loop-polls.js";
10
- import { CAUGHT, ffiCallbackType, isDynTypedRefType, isFfiContextParam, isRefCounted, isUnitType, POINTER_KINDS, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, typeEquals, typeKey, STRING, VOID, } from "../../ir/ir.js";
12
+ import { CAUGHT, ffiCallbackType, isDynTypedRefType, isFfiContextParam, isRefCounted, isUnitType, POINTER_KINDS, RUNTIME_EMITTER_CLASS, RUNTIME_EVENT_CLASS, RUNTIME_EVENT_TARGET_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, typeEquals, typeKey, STRING, VOID, } from "../../ir/ir.js";
11
13
  import { moduleRuntimeFeatures } from "../../ir/runtime-features.js";
12
14
  import { matchIntegerArrayForLoop, matchIntegerBytesForLoop, matchIntegerCountedForLoop, } from "../../ir/integer-loops.js";
13
15
  import { emitCountedLoopLimit } from "./counted-loops.js";
@@ -16,6 +18,7 @@ import { findBytesBounds } from "./bytes-bounds.js";
16
18
  import { emitByteWindowGuard, findInitializedByteLoopBindings, matchByteWindow, } from "./byte-windows.js";
17
19
  import { canDeferSplitPiece, emitSplitSpanNext, materializeSplitPiece, emitSplitCursor, emitSplitNext, emitSplitScratch, emitSplitSnapshot, findPrivateSplitLocals, loadSplitSnapshot, storeSplitSnapshot, stringSplit, } from "./split-loops.js";
18
20
  import { scalarizeNumericRecords } from "../../ir/scalar-records.js";
21
+ import { RESULT_ENTRY_PREFIX, addRecordResultEntries } from "./record-results.js";
19
22
  import { specializeNumericCalls } from "../../ir/numeric-call-specialization.js";
20
23
  import { everyExpr, everyExprChild, everyStmtChild, everyStmtList } from "../../ir/traverse.js";
21
24
  import { analyzeIntegerRanges, INT32_RANGE } from "../../ir/integer-ranges.js";
@@ -24,7 +27,7 @@ import { analyzeInt32Slots } from "../../ir/int32-slots.js";
24
27
  import { analyzeFinalFields, constructorClass } from "../../ir/final-fields.js";
25
28
  import { foldConstantGlobals } from "../../ir/constant-globals.js";
26
29
  import { findIntegerViews } from "./integer-views.js";
27
- import { findInt32Abis, INT32_ABI_SUFFIX } from "./int32-abi.js";
30
+ import { findInt32Abis, INT32_ABI_SUFFIX, SCALAR_UNION_DUMMY, SCALAR_UNION_RESULT, } from "./int32-abi.js";
28
31
  import { findInt32Locals } from "./int32-locals.js";
29
32
  import { exactInteger, narrowInteger } from "./integer-values.js";
30
33
  import { findInitializerBindings, withInitializerBindings } from "../../ir/initializer-bindings.js";
@@ -35,9 +38,11 @@ import { computeMayThrow } from "../may-throw.js";
35
38
  import { mangleArgPack, mangleAsyncAdoptCall, mangleAsyncAwaitCall, mangleAsyncSpawn, mangleBorrowedFunction, mangleClassObj, mangleClassStruct, mangleFnClosure, mangleFunction, mangleGenDrop, mangleGenSpawn, mangleGlobal, mangleLocal, mangleRecordStruct, mangleTrampoline, mangleWrapper, mangleBorrowingWrapper, mangleVtInstance, } from "../mangle.js";
36
39
  import { analyzeCallLifetimes } from "./call-lifetimes.js";
37
40
  import { canStackUnion, emitStackUnion, findLocalStackUnions } from "./stack-unions.js";
38
- import { allocateLocalUnion, findLocalUnionStorage, storeLocalUnion, } from "./local-union-storage.js";
41
+ import { emitStackObject, findLocalStackObjects, findReassignedStackObjects, stackObjectStruct, } from "./stack-objects.js";
42
+ import { allocateLocalUnion, emitScalarOptional, findLocalUnionStorage, isScalarOptionalSource, storeLocalUnion, } from "./local-union-storage.js";
39
43
  import { BlockBuilder } from "./blocks.js";
40
44
  import { NullableRefFields } from "./nullable-fields.js";
45
+ import { InlineUnionFields, loadInlineUnion, presentBits, stackUnionBox, storeInlineUnion, unionBoxBits, } from "./inline-unions.js";
41
46
  import { emitLocalArrayRead, emitProjectedArrayRead, emitBorrowedArrayRead, findLocalArrayReads, findCallArrayReads, OptionalArrayReads, } from "./local-array-reads.js";
42
47
  import { CheckedNarrows, emitCheckedNarrowReceiver } from "./checked-narrows.js";
43
48
  import { emitDenseArrayGet, emitDenseArraySet } from "./dense-array-access.js";
@@ -50,7 +55,8 @@ import { ReferenceEffects } from "./reference-effects.js";
50
55
  import { ReferenceWrites } from "./reference-writes.js";
51
56
  import { LlvmDebugInfo } from "./debug-info.js";
52
57
  import { StackCallbacks } from "./stack-callbacks.js";
53
- import { findLoopArrayBorrows } from "./loop-array-borrows.js";
58
+ import { dynHoleRead, findLoopArrayBorrows } from "./loop-array-borrows.js";
59
+ import { findAppendedArrayLiterals } from "./appended-array-literals.js";
54
60
  import { AmbientReceiverReaders, findConstantCallbacks } from "./constant-callbacks.js";
55
61
  import { findScalarStringSlices, emitStringSliceSnapshot, } from "./string-slices.js";
56
62
  import { LazyCaptures } from "./lazy-captures.js";
@@ -67,7 +73,7 @@ import { computeImmutableFields, stableGlobals } from "../immutability.js";
67
73
  import { computePublishedTypes } from "../publication.js";
68
74
  import { emitExpr } from "./expr-dispatch.js";
69
75
  import { dynKind, raceAdapterFor, genResultThunkFor, childExitThunkFor, childExitSignalThunkFor, childDataThunkFor, execFileThunkFor, ipcMessageThunkFor, ipcSendThunkFor, emitterFixedAdapter, wrapEmitterListener, unwrapNullableClosure, closeBindThunkFor, closeOverrideWrapFor, } from "./expr-callbacks.js";
70
- import { streamDataAdapter, streamDoneFnFor, cryptoBytesThunkFor, fsRenameThunkFor, streamCbThunkFor, zlibBytesThunkFor, } from "./expr-stream-callbacks.js";
76
+ import { streamDataAdapter, streamDoneFnFor, cryptoBytesThunkFor, cryptoIntThunkFor, fsRenameThunkFor, streamCbThunkFor, zlibBytesThunkFor, } from "./expr-stream-callbacks.js";
71
77
  import { emitStableReceiver, resolveThunkFor, tagInSet, arrPush, emitArrayCopyLoop, emitStrIntrinsic, emitArrIntrinsic, emitDiscardedSplice, wrapNullable, emitMapNew, mapSet, emitMapLikeIntrinsic, emitSetNew, } from "./expr-containers.js";
72
78
  import { emitIntegerLoopIndex, emitBytesIndex, emitBytesData, emitBytesLength, emitBytesGet, emitToUint32, emitBytesSet, emitBytesIntrinsic, } from "./expr-bytes.js";
73
79
  import { emitRegexIntrinsic, emitRecordKeyGet, keyedRecordReadInto } from "./expr-records.js";
@@ -77,7 +83,8 @@ import { emitChildProcessLibCall, emitAsyncContextLibCall, emitProcessLibCall, e
77
83
  import { emitStreamLibCall } from "./lib-stream.js";
78
84
  import { emitNetworkHttpLibCall } from "./lib-network.js";
79
85
  import { emitAssertInspectLibCall, emitIoLibCall, emitGenericLibCall, emitLibCall, } from "./lib-dispatch.js";
80
- import { buildClassGraph, classMembershipIntervals, emitClassMembershipHelper, classEnvironmentIndex, classFieldIndex, classStructSym, } from "./classes.js";
86
+ import { buildClassGraph, classMembershipIntervals, emitClassMembershipHelper, classEnvironmentIndex, classFieldIndex, classStructSym, programLifetimeClass, } from "./classes.js";
87
+ import { LifetimeRegions, REGION_TYPES } from "./regions.js";
81
88
  import { LlDyn } from "./dyn.js";
82
89
  import { VirtualBorrows } from "./virtual-borrows.js";
83
90
  import { LlvmUnsupportedError } from "./unsupported.js";
@@ -85,10 +92,10 @@ import { LlWalkers } from "./walkers.js";
85
92
  import { isObjectArm, NULLABLE_ABSENT, NULLABLE_NULL, NullableUnions } from "./nullable-unions.js";
86
93
  import { emitNullablePresent, emitUnionPeek, emitUnionTag } from "./union-repr.js";
87
94
  import { literalCapWord, literalCapWord32 } from "./string-key-hash.js";
88
- import { NUMBER_MAP_ENTRY_DECL, STRING_MAP_ENTRY_DECL } from "./map-number-lookup.js";
89
- import { STRING_READ_HELPERS } from "./string-reads.js";
95
+ import { MAP_ITER_DECL, NUMBER_MAP_ENTRY_DECL, STRING_MAP_ENTRY_DECL, } from "./map-number-lookup.js";
96
+ import { STRING_READ_HELPERS, stringScanDecl } from "./string-reads.js";
90
97
  import { emitConcatInputs, emitMixedConcat, numberPart, stringParts, } from "./string-construction.js";
91
- import { arrNewCall, boxAccess, boxNewCall, boxReleaseSym, computeTraced, elemAccess, emitInlineRcHelpers, emitNullableRetainWrappers, FN_ATTRS, inlineRcDecls, llFieldType, releaseSym, retainSym, traceArg, typedRefConstructor, vAdapters, } from "./shapes.js";
98
+ import { arrNewCall, boxAccess, boxNewCall, boxReleaseSym, computeTraced, elemAccess, emitInlineRcHelpers, emitNullableRetainWrappers, FN_ATTRS, inlineRcDecls, limitInlineDynReleases, llFieldType, releaseSym, retainSym, traceArg, typedRefConstructor, vAdapters, } from "./shapes.js";
92
99
  import { INLINE_LITERAL_BYTES, literalEqualityDefinition } from "./string-literal-equality.js";
93
100
  export { LlvmUnsupportedError } from "./unsupported.js";
94
101
  function ffiCallbackDummyLl(callback) {
@@ -122,14 +129,14 @@ export function emitLlvmModule(input, options = {}) {
122
129
  const mod = unshareNodes(input);
123
130
  // Keep source storage intact for debugger inspection in dev builds.
124
131
  return new LlEmitter(options.debugSources === undefined
125
- ? scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction))
132
+ ? addRecordResultEntries(scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction)))
126
133
  : mod, options).emit();
127
134
  }
128
135
  /** Keep large translation units below the host's single-string limit. */
129
136
  export function emitLlvmModuleSource(input, options = {}) {
130
137
  const mod = unshareNodes(input);
131
138
  const parts = new LlEmitter(options.debugSources === undefined
132
- ? scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction))
139
+ ? addRecordResultEntries(scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction)))
133
140
  : mod, options).emitParts();
134
141
  const length = parts.reduce((total, part) => total + part.length, Math.max(0, parts.length - 1));
135
142
  if (length <= 256 * 1024 * 1024)
@@ -137,7 +144,7 @@ export function emitLlvmModuleSource(input, options = {}) {
137
144
  return parts.flatMap((part, index) => (index === 0 ? [part] : ["\n", part]));
138
145
  }
139
146
  function llStrBytes(text) {
140
- return llBytes(Buffer.from(text, "utf8"));
147
+ return llBytes(wtf8Bytes(text));
141
148
  }
142
149
  const NO_BORROWED = new Set();
143
150
  /** Whether any node of `e` names the local (reads, writes, declarations,
@@ -181,6 +188,10 @@ export class LlEmitter {
181
188
  scalarStringSlices = new Map();
182
189
  stringSlices = new Map();
183
190
  localStackUnions = new Map();
191
+ localStackObjects = new Map();
192
+ reassignedStackObjects = new Set();
193
+ /** The binding slot of each reassigned stack-object local. */
194
+ stackObjectSlots = new Map();
184
195
  localUnionStorageProofs = new Map();
185
196
  localUnionStorage = new Map();
186
197
  integerArrayBindings = new Set();
@@ -203,6 +214,18 @@ export class LlEmitter {
203
214
  }
204
215
  this.fieldPointerTags.set(ptr, tag);
205
216
  }
217
+ /** The alias tag of a runtime word that emitted code reads and writes
218
+ * outside every field (the lifetime-region count, owner and cursors). */
219
+ memoryAliasAttachment(category) {
220
+ if (this.debug !== null)
221
+ return "";
222
+ let tag = this.fieldAliasTags.get(category);
223
+ if (tag === undefined) {
224
+ tag = 2 + this.fieldAliasTags.size * 2;
225
+ this.fieldAliasTags.set(category, tag);
226
+ }
227
+ return `, !tbaa !${tag}`;
228
+ }
206
229
  fieldAliasAttachment(ptr) {
207
230
  const tag = this.fieldPointerTags.get(ptr);
208
231
  return tag === undefined ? "" : `, !tbaa !${tag}`;
@@ -217,10 +240,12 @@ export class LlEmitter {
217
240
  return lines;
218
241
  }
219
242
  debug;
243
+ /** Projection-only scalar objects may live in frame storage (stack-objects.ts). */
244
+ stackObjects;
220
245
  debugScope = null;
221
246
  sizeType;
222
247
  ffiExtendNarrowIntegers;
223
- cycleBufferedOffset;
248
+ cycleBufOffset;
224
249
  /** Emitted ScrCycType descriptors so far (their collector statistics
225
250
  * indices; see ShapeHost.nextCycKind). */
226
251
  cycKinds = 0;
@@ -264,6 +289,8 @@ export class LlEmitter {
264
289
  unitInstances = new Map();
265
290
  /** unionId → symbol of the union's immortal ABSENT field-slot instance. */
266
291
  absentInstances = new Map();
292
+ /** The zeroed box an inline store reads for a NULL union dummy. */
293
+ needsUnionNone = false;
267
294
  /** unionId → symbol of a flag set once a checked-dynamic cast caches one
268
295
  * of the union's boxes. A cached box is refreshed in place, possibly with
269
296
  * a tag that another union numbers apart, so it is never shared. */
@@ -306,7 +333,11 @@ export class LlEmitter {
306
333
  /** Inline RC fast-path helpers requested by call sites (shapes.ts); null
307
334
  * when inline RC is off. */
308
335
  rcHelpers;
336
+ rcMode;
337
+ rcHelpersNoinline;
309
338
  fnByName = new Map();
339
+ /** Empty literals that construct with inline slots (appended-array-literals.ts). */
340
+ appendedArrayLiterals = new Set();
310
341
  /** Emitted LLVM text of every IR function body, by function name: the
311
342
  * fiberless-async analysis scans it for suspension entry points. */
312
343
  fnDefText = new Map();
@@ -318,6 +349,8 @@ export class LlEmitter {
318
349
  * whose bindings end with the list (emitBlock and function bodies). */
319
350
  stmtCursor = null;
320
351
  optionalArrayReads;
352
+ /** Union sources a binding or projection can hold in a stack box. */
353
+ unionSources;
321
354
  checkedNarrows;
322
355
  callArrayReads = new Map();
323
356
  mapReadLifetimes = { locals: new Map(), arguments: new Map() };
@@ -413,6 +446,10 @@ export class LlEmitter {
413
446
  * typeKey → thunk symbol. */
414
447
  resolveThunks = new Map();
415
448
  resolveThunkDefs = [];
449
+ /** Inline array searches used by the module (array-search.ts). */
450
+ arraySearchKinds = new Set();
451
+ /** Typed-ref recipe constants by type key (lazy receivers). */
452
+ typedRefRecipes = new Map();
416
453
  /** ReadableStream.from adapters keep typed arrays by reference and box
417
454
  * one current element per pull. */
418
455
  streamFromArrayAdapters = new Map();
@@ -424,6 +461,7 @@ export class LlEmitter {
424
461
  dynPromiseAdapters = new Map();
425
462
  unionsById = new Map();
426
463
  nullableFields;
464
+ inlineUnions;
427
465
  /** Unions whose values are nullable arm pointers (nullable-unions.ts). */
428
466
  nullableUnions;
429
467
  /** The union table without nullable unions: the stack-box analyses. */
@@ -530,6 +568,9 @@ export class LlEmitter {
530
568
  currentReturnType = VOID;
531
569
  /** The current body returns its number result as i32. */
532
570
  currentInt32Result = false;
571
+ /** The function's i32 entry returns its scalar union result as tag and
572
+ * payload bits (Int32Abi.union). */
573
+ currentUnionResult = false;
533
574
  /** Active only while emitting a body lowered with LLVM's
534
575
  * switched-coroutine intrinsics (wasm32 async bodies and generators,
535
576
  * native synchronous generators; see coroLowered). */
@@ -538,6 +579,8 @@ export class LlEmitter {
538
579
  * generator bodies): yieldExpr emission reads them, and emitTryCatch's
539
580
  * catch prologue emits the GENRET sentinel re-unwind exactly here. */
540
581
  currentGenerator = null;
582
+ /** The function being emitted is an async generator body. */
583
+ currentAsyncGenerator = false;
541
584
  /** Active optional-chain bind slots, by chain id (chainRecv reads). */
542
585
  chainSlots = new Map();
543
586
  logArgSlots = 0;
@@ -565,6 +608,7 @@ export class LlEmitter {
565
608
  options.wasi === true || ffiExtendsNarrowIntegers(options.targetTriple);
566
609
  this.wasi = options.wasi === true;
567
610
  this.stacklessGenerators = !this.wasi && mod.workers !== true && this.debug === null;
611
+ this.stackObjects = this.debug === null;
568
612
  // An empty triple targets the host, as for executableTls below: the
569
613
  // Node-hosted CLI passes none, the native CLI passes its toolchain's, and
570
614
  // both must emit the same module for the same target.
@@ -590,16 +634,17 @@ export class LlEmitter {
590
634
  this.emitLibraryIdentity = options.emitLibraryIdentity !== false;
591
635
  this.runtimeAbiMarker = options.runtimeAbiMarker === true;
592
636
  this.detachedExit = options.detachedExit === true;
593
- 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;
637
+ this.rcHelpers = options.inlineRc !== undefined ? new Set() : null;
638
+ this.rcMode = options.inlineRc;
639
+ this.rcHelpersNoinline = options.rcHelpersNoinline === true;
640
+ // ScrCycHdr.buf sits 4 bytes behind every object on every target.
641
+ this.cycleBufOffset = CYC_HDR - CYC_BUF;
598
642
  this.ffiCallbackAdapters = allocateFfiCallbackAdapters(mod.ffiImports ?? []);
599
643
  this.ffiHasRetainedCallback = hasRetainedFfiCallback(mod.ffiImports ?? []);
600
644
  this.ffiHasForeignCallback = hasForeignFfiCallback(mod.ffiImports ?? []);
601
645
  for (const fn of mod.functions)
602
646
  this.fnByName.set(fn.name, fn);
647
+ this.appendedArrayLiterals = findAppendedArrayLiterals(mod);
603
648
  for (const entry of mod.ffiImports ?? []) {
604
649
  this.ffiByName.set(entry.name, entry);
605
650
  }
@@ -629,10 +674,21 @@ export class LlEmitter {
629
674
  this.immortalValues.add("null");
630
675
  this.immortalValues.add(NULLABLE_NULL);
631
676
  this.nullableFields = new NullableRefFields(mod.classes ?? [], this.boxedUnionsById);
677
+ this.inlineUnions = new InlineUnionFields(this.boxedUnionsById, mod.classes ?? []);
678
+ for (const r of mod.records ?? [])
679
+ this.recordsById.set(r.id, r);
632
680
  // Optional array reads also cover nullable unions: emitLocalArrayRead
633
681
  // then yields the (borrowed or owned) element pointer, not a stack box.
634
682
  // Arrays of such a union are read the same way.
635
683
  this.optionalArrayReads = new OptionalArrayReads(this.fnByName, this.unionsById, (id) => this.nullableUnions.has(id));
684
+ this.unionSources = {
685
+ unions: this.boxedUnionsById,
686
+ receiverUnions: this.unionsById,
687
+ nullableField: (e) => this.nullableFieldGet(e) !== null,
688
+ inlineField: (e) => this.inlineFieldGet(e),
689
+ arrayRead: (e) => this.optionalArrayReads.get(e) !== null,
690
+ scalarCall: (e) => this.scalarResultCall(e),
691
+ };
636
692
  this.checkedNarrows = new CheckedNarrows(this.fnByName);
637
693
  this.referenceEffects = new ReferenceEffects(this.fnByName, (call) => this.optionalArrayReads.get(call) !== null, mod.classes ?? []);
638
694
  if (this.debug === null)
@@ -678,23 +734,26 @@ export class LlEmitter {
678
734
  walkParameters.set(fn.name, indexes);
679
735
  }
680
736
  }
681
- this.callLifetimes = analyzeCallLifetimes(this.fnByName, (className, field) => this.nullableFields.get(className, field) !== null, walkParameters);
737
+ 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)), {
738
+ record: (shapeId, field) => this.recordFieldInline(shapeId, field),
739
+ classField: (className, field) => this.inlineUnions.classField(className, field),
740
+ });
682
741
  this.constantCallbacks = findConstantCallbacks(mod, this.callLifetimes);
683
742
  this.stackCallbacks = new StackCallbacks(this.fnByName);
684
743
  this.receiverReaders = new AmbientReceiverReaders(this.fnByName);
685
744
  this.stackCaptures = new StackCaptures(this.fnByName, this.callLifetimes, this.stackCallbacks);
686
745
  this.lazyCaptures = new LazyCaptures(this.fnByName);
687
- for (const r of mod.records ?? [])
688
- this.recordsById.set(r.id, r);
689
746
  const traced = computeTraced(mod);
690
747
  this.tracedShapes = traced.shapes;
691
748
  this.tracedUnions = traced.unions;
692
749
  this.shapeHost = {
693
750
  sizeType: this.sizeType,
694
- cycleBufferedOffset: this.cycleBufferedOffset,
751
+ cycleBufOffset: this.cycleBufOffset,
695
752
  tracedShapes: this.tracedShapes,
696
753
  tracedUnions: this.tracedUnions,
697
754
  nullableUnions: this.nullableUnions,
755
+ inlineUnions: this.inlineUnions,
756
+ unionNoneRef: () => this.unionNoneRef(),
698
757
  recordsById: this.recordsById,
699
758
  recordCloneShapes: this.recordCloneShapes,
700
759
  objectAudit: options.objectAudit !== false,
@@ -708,6 +767,8 @@ export class LlEmitter {
708
767
  // paths address its thread-local state.
709
768
  threadLocalAlloc: mod.workers === true,
710
769
  rcHelpers: this.rcHelpers,
770
+ ...(this.rcMode !== undefined ? { rcMode: this.rcMode } : {}),
771
+ ...(this.rcHelpersNoinline ? { rcHelpersNoinline: true } : {}),
711
772
  nextCycKind: () => FIRST_EMITTED_CYC_KIND + this.cycKinds++,
712
773
  unionsById: this.unionsById,
713
774
  declare: (decl) => this.declare(decl),
@@ -723,6 +784,7 @@ export class LlEmitter {
723
784
  liveDynUnionRefAdapter: (type) => this.liveDynUnionRefAdapter(type),
724
785
  dynPromiseAdapter: (type) => this.dynPromiseAdapter(type),
725
786
  isErrorClass: (name) => this.classMeta.get(name)?.root.def.name === "%Error",
787
+ classRootOf: (name) => this.classMeta.get(name)?.root.def.name,
726
788
  classSubtypes: (name) => {
727
789
  const target = this.classMetaOf(name);
728
790
  const intervals = classMembershipIntervals(this.classMeta, target.def.name);
@@ -733,6 +795,7 @@ export class LlEmitter {
733
795
  pendingTestLines: (dest) => this.pendingTestLines(dest),
734
796
  virtualEntry: (implFn) => this.virtualEntry(implFn),
735
797
  programLifetime: this.programLifetime,
798
+ regionAliasTag: (word) => this.memoryAliasAttachment(`region.${word}`),
736
799
  };
737
800
  this.walkers = new LlWalkers(this.shapeHost);
738
801
  this.dyn = new LlDyn(this.shapeHost);
@@ -755,13 +818,16 @@ export class LlEmitter {
755
818
  this.tdzGlobals.set(g.id, g.name);
756
819
  }
757
820
  this.stableGlobals = stableGlobals(mod);
758
- // Runtime error, EventEmitter, and stream classes have known layouts.
759
- // Subclasses embed the ScrEmitter/ScrStream prefixes from classes.ts.
821
+ // Runtime error, EventEmitter, stream, EventTarget and Event classes
822
+ // have known layouts. Subclasses embed the runtime prefixes from
823
+ // classes.ts.
760
824
  const classes = mod.classes ?? [];
761
825
  for (const cls of classes) {
762
826
  if (cls.runtime &&
763
827
  !RUNTIME_ERROR_CLASSES.has(cls.name) &&
764
828
  cls.name !== RUNTIME_EMITTER_CLASS &&
829
+ cls.name !== RUNTIME_EVENT_TARGET_CLASS &&
830
+ cls.name !== RUNTIME_EVENT_CLASS &&
765
831
  !RUNTIME_STREAM_CLASSES.has(cls.name)) {
766
832
  throw new LlvmUnsupportedError(`classDef:${cls.name}`, cls.loc);
767
833
  }
@@ -770,6 +836,17 @@ export class LlEmitter {
770
836
  // whole-program preorder numbering for instanceof over runtime and
771
837
  // compiled error objects, and the per-hierarchy virtual slot lists.
772
838
  this.classMeta = buildClassGraph(mod, this.fnByName);
839
+ if (mod.lifetimeRegions === true) {
840
+ this.regions = new LifetimeRegions(this.shapeHost, mod, this.classMeta, (meta) => programLifetimeClass(this.shapeHost, meta), this.nullableFields);
841
+ const regions = this.regions;
842
+ // Member names differ from LifetimeRegions' own, which keeps the
843
+ // record from reading as that class's protocol.
844
+ this.shapeHost.regions = {
845
+ rcBody: (fnName, ret, comment) => regions.countBody(fnName, ret, comment),
846
+ newAlloc: (className, sizeOf) => regions.allocLines(className, sizeOf),
847
+ classDefinitions: (cls, sizeOf) => regions.classDefs(cls, sizeOf),
848
+ };
849
+ }
773
850
  for (const [name, rec] of RUNTIME_ERROR_CLASSES) {
774
851
  const meta = this.classMeta.get(name);
775
852
  if (!meta)
@@ -1110,7 +1187,7 @@ export class LlEmitter {
1110
1187
  return this.emitParts().join("\n");
1111
1188
  }
1112
1189
  emitParts() {
1113
- const parts = this.emitModuleParts();
1190
+ const parts = limitInlineDynReleases(this.emitModuleParts());
1114
1191
  if (!this.executableTls)
1115
1192
  return parts;
1116
1193
  // A worker executable's thread-locals all live in the executable's own
@@ -1163,7 +1240,7 @@ export class LlEmitter {
1163
1240
  // Module globals, FIRST OCCURRENCE per id: a class-expression static
1164
1241
  // instantiated through several mixin applications registers one global
1165
1242
  // id several times (2041-mixin-values) — C's tentative definitions
1166
- // absorb the duplicates silently, LLVM rejects redefinition, so the
1243
+ // accept the duplicates without an error, LLVM rejects redefinition, so the
1167
1244
  // storage AND the release emit once per id here.
1168
1245
  const seenGlobalIds = new Set();
1169
1246
  const globals = (this.mod.globals ?? []).filter((g) => {
@@ -1399,9 +1476,11 @@ export class LlEmitter {
1399
1476
  // write/abort declarations).
1400
1477
  const helpers = [
1401
1478
  ...this.helperDefs(),
1479
+ ...emitArraySearchHelpers(this.arraySearchKinds, this.sizeType, (line) => this.declare(line)),
1402
1480
  ...emitClassMembershipHelper(this.classMeta, this.sizeType),
1403
1481
  ...(this.publishWalkersCache?.defs() ?? []),
1404
1482
  ...this.publishedClassNamesDefs(),
1483
+ ...(this.regions?.moduleDefs() ?? []),
1405
1484
  ];
1406
1485
  if (this.constantNumericTables.size > 0)
1407
1486
  this.declare(`declare double @scr_arr_get_number(ptr, double)`);
@@ -1447,17 +1526,22 @@ export class LlEmitter {
1447
1526
  ? []
1448
1527
  : [`%ScrMapRc = type { ${this.sizeType}, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr }`]),
1449
1528
  // The complete ScrMap and its { key, val, hash } entry, read by the
1450
- // inline number-key lookup (sc_map_entry_f64): field 11 is the i64
1451
- // absent-key filter, entries is field 13, the direct index and its
1452
- // length fields 19 and 20.
1453
- ...(this.decls.has(NUMBER_MAP_ENTRY_DECL) || this.decls.has(STRING_MAP_ENTRY_DECL)
1529
+ // inline number-key lookup (sc_map_entry_f64) and the inline
1530
+ // iteration steps (sc_map_iter_entry): field 9 is the entry count,
1531
+ // field 11 the i64 absent-key filter, entries is field 13, the direct
1532
+ // index and its length fields 19 and 20.
1533
+ ...(this.decls.has(NUMBER_MAP_ENTRY_DECL) ||
1534
+ this.decls.has(STRING_MAP_ENTRY_DECL) ||
1535
+ this.decls.has(MAP_ITER_DECL)
1454
1536
  ? [
1455
1537
  `%ScrMapIx = type { ${this.sizeType}, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ${this.sizeType}, ${this.sizeType}, i64, ${this.sizeType}, ptr, ${this.sizeType}, ptr, ${this.sizeType}, ptr, ptr, ptr, ${this.sizeType} }`,
1456
1538
  ]
1457
1539
  : []),
1458
1540
  // String-keyed reference reads load the value slot of the entry
1459
1541
  // scr_map_entry_str returns (map-number-lookup.ts).
1460
- ...(this.decls.has(NUMBER_MAP_ENTRY_DECL) || this.decls.has(STRING_MAP_ENTRY_DECL)
1542
+ ...(this.decls.has(NUMBER_MAP_ENTRY_DECL) ||
1543
+ this.decls.has(STRING_MAP_ENTRY_DECL) ||
1544
+ this.decls.has(MAP_ITER_DECL)
1461
1545
  ? [`%ScrMapEntry = type { i64, i64, i64 }`]
1462
1546
  : []),
1463
1547
  // The runtime error prefix { rc, vt, name, message, code, cause } and the
@@ -1471,6 +1555,13 @@ export class LlEmitter {
1471
1555
  // The runtime stream layout { rc, vt, reg, cls, st } — one struct
1472
1556
  // for all five stream classes; stream subclasses embed it.
1473
1557
  `%ScrStream = type { ${this.sizeType}, ptr, ptr, ptr, ptr }`,
1558
+ // The EventTarget and Event subclass prefixes { rc, vt, state, cls }.
1559
+ ...(this.classMeta.has(RUNTIME_EVENT_TARGET_CLASS)
1560
+ ? [`%ScrEventTargetObj = type { ${this.sizeType}, ptr, ptr, ptr }`]
1561
+ : []),
1562
+ ...(this.classMeta.has(RUNTIME_EVENT_CLASS)
1563
+ ? [`%ScrEventObj = type { ${this.sizeType}, ptr, ptr, ptr }`]
1564
+ : []),
1474
1565
  // The catch-binding snapshot box { rc, kind, f64, b, payload,
1475
1566
  // retain_fn, release_fn, trace_fn } — caughtTest kind reads and
1476
1567
  // caughtNarrow payload extraction GEP through it (offsets match
@@ -1529,8 +1620,8 @@ export class LlEmitter {
1529
1620
  // half carries the precomputed Map key hash (SCR_STR_HASH_CACHE).
1530
1621
  // Bit 31 marks all-ASCII literals (SCR_STR_ASCII_BIT) on every target.
1531
1622
  const capWord = this.sizeType === "i64"
1532
- ? literalCapWord(Buffer.from(text, "utf8"))
1533
- : literalCapWord32(Buffer.from(text, "utf8"));
1623
+ ? literalCapWord(wtf8Bytes(text))
1624
+ : literalCapWord32(wtf8Bytes(text));
1534
1625
  out.push(`@${lit.sym} = internal global { ${this.sizeType}, ${this.sizeType}, ${this.sizeType}, [${lit.len + 1} x i8] } ` +
1535
1626
  `{ ${this.sizeType} -1, ${this.sizeType} ${lit.len}, ${this.sizeType} ${capWord}, [${lit.len + 1} x i8] c"${llStrBytes(text)}" }`);
1536
1627
  }
@@ -1583,6 +1674,8 @@ export class LlEmitter {
1583
1674
  }
1584
1675
  if (this.absentInstances.size > 0)
1585
1676
  out.push(``);
1677
+ if (this.needsUnionNone)
1678
+ out.push(`@sc_union_none = internal constant %ScrUnion zeroinitializer ; NULL union dummy read by inline stores`, ``);
1586
1679
  if (this.nullableUnions.usesNullSentinel) {
1587
1680
  // `null` in every `C | null | undefined` union (NULL is undefined):
1588
1681
  // one module-scope immortal object like the ABSENT sentinel.
@@ -1693,6 +1786,12 @@ export class LlEmitter {
1693
1786
  }
1694
1787
  if (this.streamIntervals.length > 0)
1695
1788
  out.push(``);
1789
+ if ([...this.literals.keys(), ...this.cstrs.keys()].some(hasLoneSurrogate)) {
1790
+ // The runtime skips surrogate work until a lone surrogate may exist
1791
+ // (scr_wtf8_any); its own producers note one, and literals do here.
1792
+ out.push(`declare void @scr_wtf8_note()`, ``);
1793
+ stamps.push(` call void @scr_wtf8_note()`);
1794
+ }
1696
1795
  if (this.errorIntervals.length > 0 && this.tracedShapes.has("object:%Error")) {
1697
1796
  // The cycle fixpoint marked the Error hierarchy (a user subclass
1698
1797
  // holds cycle-capable fields — capability is hierarchy-uniform), so
@@ -1991,7 +2090,7 @@ export class LlEmitter {
1991
2090
  case "i64":
1992
2091
  // Inbound declared-integer edge (ask 4): the helper converts
1993
2092
  // exactly or delivers the host-contract trap (past ±(2^53−1)
1994
- // the value cannot ride f64 without silent rounding).
2093
+ // the value cannot ride f64 without rounding).
1995
2094
  params.push(`i64 %a${i}`);
1996
2095
  body.push(` %c${i} = call double @scr_library_i64_in(i64 %a${i}, ptr @sc_lib_int_trap_${e.symbol})`);
1997
2096
  args.push(`double %c${i}`);
@@ -2099,6 +2198,15 @@ export class LlEmitter {
2099
2198
  ? ` %i = add i64 ${mapIndex.wide}, 0`
2100
2199
  : ` %i = trunc i64 ${mapIndex.wide} to ${sz}`, ` %dp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 19`, ` %dense = load ptr, ptr %dp`, ` %sp = getelementptr inbounds i32, ptr %dense, ${sz} %i`, ` %s = load i32, ptr %sp`, ` %empty = icmp eq i32 %s, 0`, ` br i1 %empty, label %miss, label %hit`, `hit:`, ` %e32 = sub i32 %s, 1`, sz === "i32" ? ` %e = add i32 %e32, 0` : ` %e = zext i32 %e32 to ${sz}`, ` %ep = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 13`, ` %entries = load ptr, ptr %ep`, ` %found = getelementptr inbounds %ScrMapEntry, ptr %entries, ${sz} %e`, ` ret ptr %found`, `miss:`, ` ret ptr null`, `outside:`, ` %dense.any = icmp ne ${sz} %nd, 0`, ` br i1 %dense.any, label %miss, label %slow`, `slow:`, ` %r = call ptr @scr_map_entry_f64(ptr %m, double %k)`, ` ret ptr %r`, `}`, ``);
2101
2200
  }
2201
+ // Map/Set iteration steps read the entries array inline: an index is
2202
+ // live when it is below the entry count and its entry's cached hash is
2203
+ // nonzero (a tombstone's is zero), as scr_map_iter_live decides. The
2204
+ // entry count is read again at every step, so entries appended during
2205
+ // the iteration are visited.
2206
+ if (this.decls.has(MAP_ITER_DECL)) {
2207
+ const sz = this.sizeType;
2208
+ defs.push(`define internal ptr @sc_map_iter_entry(ptr %m, double %i) ${FN_ATTRS} {`, `entry:`, ` %np = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 9`, ` %n = load ${sz}, ptr %np`, ` %nf = uitofp ${sz} %n to double`, ` %lo = fcmp oge double %i, 0.0`, ` %hi = fcmp olt double %i, %nf`, ` %in = and i1 %lo, %hi`, ` br i1 %in, label %load, label %none`, `load:`, ` %ix = fptoui double %i to ${sz}`, ` %ep = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 13`, ` %entries = load ptr, ptr %ep`, ` %e = getelementptr inbounds %ScrMapEntry, ptr %entries, ${sz} %ix`, ` %hp = getelementptr inbounds %ScrMapEntry, ptr %e, i32 0, i32 2`, ` %h = load i64, ptr %hp`, ` %live = icmp ne i64 %h, 0`, ` br i1 %live, label %yes, label %none`, `yes:`, ` ret ptr %e`, `none:`, ` ret ptr null`, `}`, ``, `define internal double @sc_map_iter_count(ptr %m) ${FN_ATTRS} {`, `entry:`, ` %np = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 9`, ` %n = load ${sz}, ptr %np`, ` %nf = uitofp ${sz} %n to double`, ` ret double %nf`, `}`, ``);
2209
+ }
2102
2210
  // String-key Map/Set lookups test the map's absent-key filter inline
2103
2211
  // (scr_map.c scr_map_filter_bits): a key whose two filter bits are not
2104
2212
  // both set is absent, so most misses on small and medium maps return
@@ -2140,16 +2248,24 @@ export class LlEmitter {
2140
2248
  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
2249
  }
2142
2250
  for (const [text, name] of this.literalEqualities) {
2143
- defs.push(...literalEqualityDefinition(name, Buffer.from(text, "utf8"), this.internLiteral(text), this.sizeType, FN_ATTRS), ``);
2251
+ defs.push(...literalEqualityDefinition(name, wtf8Bytes(text), this.internLiteral(text), this.sizeType, FN_ATTRS), ``);
2144
2252
  }
2145
2253
  // String length and charCodeAt read proven-ASCII strings inline: bit 31
2146
2254
  // of the capacity word (SCR_STR_ASCII_BIT, the low half's sign bit on
2147
2255
  // little-endian targets) makes UTF-16 units bytes. Unproven strings and
2148
2256
  // anything but an in-range index take the runtime's UTF-16 mapping.
2257
+ // A scan's receiver reads inline too where runtime state is ordinary
2258
+ // global storage (ScrStrScan; SCR_TL makes it thread-local otherwise).
2259
+ const scanInline = this.mod.workers !== true && this.mod.lib?.threadInstances !== true;
2260
+ let scanDeclared = false;
2149
2261
  for (const helper of STRING_READ_HELPERS) {
2150
2262
  if (!this.decls.has(helper.decl))
2151
2263
  continue;
2152
- defs.push(...helper.define(this.sizeType, FN_ATTRS), ``);
2264
+ if (scanInline && !scanDeclared) {
2265
+ defs.push(stringScanDecl(this.sizeType), ``);
2266
+ scanDeclared = true;
2267
+ }
2268
+ defs.push(...helper.define(this.sizeType, FN_ATTRS, scanInline), ``);
2153
2269
  }
2154
2270
  // Ordering also decides inline when the first bytes differ: byte order
2155
2271
  // is the plain comparison's order, and the UTF-16 order whenever both
@@ -2331,7 +2447,7 @@ export class LlEmitter {
2331
2447
  * programs keep fibers too: their fiber epilogue owns context
2332
2448
  * termination (a stopping worker rejects and observes the promise), which
2333
2449
  * the fiberless wrapper does not reproduce. A missed suspension still
2334
- * cannot reorder silently: the runtime traps when a context parks while a
2450
+ * cannot reorder execution undetected: the runtime traps when a context parks while a
2335
2451
  * fiberless body is on its stack. */
2336
2452
  fiberlessAsyncFunctions() {
2337
2453
  const eligible = new Set();
@@ -2983,8 +3099,13 @@ export class LlEmitter {
2983
3099
  * holding the ABSENT state surfaces as the ordinary undefined arm, so
2984
3100
  * absence never travels beyond its slot (a later `{ f: r.f }` is an
2985
3101
  * explicit, present property). */
2986
- loadRecordField(ptr, t) {
2987
- const v = this.loadField(ptr, t);
3102
+ loadRecordField(ptr, t, inline) {
3103
+ if (inline) {
3104
+ const { tag, bits } = loadInlineUnion(this.B, ptr);
3105
+ const present = presentBits(this.B, tag, bits, undefinedArmTag(t, this.unionsById));
3106
+ return stackUnionBox(this.B, this.sizeType, tag, present);
3107
+ }
3108
+ const v = this.loadField(ptr, t, false);
2988
3109
  if (t.kind !== "union" || undefinedArmTag(t, this.unionsById) < 0)
2989
3110
  return v;
2990
3111
  const absent = this.fieldAbsentTest(v, t.unionId);
@@ -3197,11 +3318,13 @@ export class LlEmitter {
3197
3318
  ? "ret void"
3198
3319
  : this.currentInt32Result
3199
3320
  ? "ret i32 0"
3200
- : t === "double"
3201
- ? `ret double ${f64Lit(0)}`
3202
- : t === "i1"
3203
- ? "ret i1 false"
3204
- : "ret ptr null";
3321
+ : this.currentUnionResult
3322
+ ? `ret ${SCALAR_UNION_DUMMY}`
3323
+ : t === "double"
3324
+ ? `ret double ${f64Lit(0)}`
3325
+ : t === "i1"
3326
+ ? "ret i1 false"
3327
+ : "ret ptr null";
3205
3328
  }
3206
3329
  // Copy the entries now: later declarations extend these lexical scopes.
3207
3330
  // Release order and the handler are part of the shared block's identity.
@@ -3644,6 +3767,7 @@ export class LlEmitter {
3644
3767
  case "searchParams":
3645
3768
  case "stats":
3646
3769
  case "fileHandle":
3770
+ case "dir":
3647
3771
  case "spawnRes":
3648
3772
  case "child":
3649
3773
  case "childStream":
@@ -3686,7 +3810,7 @@ export class LlEmitter {
3686
3810
  }
3687
3811
  /** Guard for helpers that build or read a union's `%ScrUnion` box
3688
3812
  * directly (library-shaped unions with fixed arms): a nullable union
3689
- * reaching one is an emitter bug, never a silent miscompile. */
3813
+ * reaching one is an emitter bug and throws InternalCompilerError. */
3690
3814
  requireBoxedUnion(unionId) {
3691
3815
  if (this.nullableUnions.has(unionId))
3692
3816
  throw new InternalCompilerError(`llvm emitter bug: nullable union ${unionId} reached a tagged-box helper`);
@@ -3819,7 +3943,7 @@ export class LlEmitter {
3819
3943
  const p = this.B.tmp();
3820
3944
  this.B.line(`${p} = getelementptr inbounds %${classStructSym(className)}, ptr ${objName}, i64 0, i32 ${index}`);
3821
3945
  this.markFieldPointer(p, field);
3822
- return { ptr: p, type };
3946
+ return { ptr: p, type, inline: this.inlineUnions.classField(className, field) };
3823
3947
  }
3824
3948
  /** `o->vt->pre` — the dynamic class's preorder number (borrowed object;
3825
3949
  * the static class names which struct spelling carries the vt word). */
@@ -3870,8 +3994,10 @@ export class LlEmitter {
3870
3994
  if (index < 0)
3871
3995
  throw new InternalCompilerError(`llvm emitter bug: missing union field ${field}`);
3872
3996
  layout = "record:";
3873
- for (let i = 0; i <= index; i++)
3874
- layout += `${llFieldType(shape.fields[i].type)};`;
3997
+ for (let i = 0; i <= index; i++) {
3998
+ const type = shape.fields[i].type;
3999
+ layout += `${llFieldType(type, this.inlineUnions.record(type))};`;
4000
+ }
3875
4001
  }
3876
4002
  const group = groups.get(layout);
3877
4003
  if (group)
@@ -3883,7 +4009,13 @@ export class LlEmitter {
3883
4009
  this.unionFieldReadGroups.set(key, result);
3884
4010
  return result;
3885
4011
  }
3886
- /** The field-slot pointer of a record member (rc header at index 0). */
4012
+ /** The zeroed `%ScrUnion` constant (inline-unions.ts unionBoxBits). */
4013
+ unionNoneRef() {
4014
+ this.needsUnionNone = true;
4015
+ return "@sc_union_none";
4016
+ }
4017
+ /** The field-slot pointer of a record member (rc header at index 0).
4018
+ * `inline`: the slot stores a scalar union's tag and bits. */
3887
4019
  recordFieldPtr(objName, shapeId, field) {
3888
4020
  const shape = this.recordShape(shapeId);
3889
4021
  const idx = shape.fields.findIndex((f) => f.name === field);
@@ -3891,7 +4023,8 @@ export class LlEmitter {
3891
4023
  throw new InternalCompilerError(`llvm emitter bug: unknown field ${field} on shape ${shapeId}`);
3892
4024
  const p = this.B.tmp();
3893
4025
  this.B.line(`${p} = getelementptr inbounds %${mangleRecordStruct(shapeId)}, ptr ${objName}, i64 0, i32 ${idx + 1}`);
3894
- return { ptr: p, type: shape.fields[idx].type };
4026
+ const type = shape.fields[idx].type;
4027
+ return { ptr: p, type, inline: this.inlineUnions.record(type) };
3895
4028
  }
3896
4029
  /** The overflow map's slot pointer on an index-signature shape. */
3897
4030
  recordOvfPtr(objName, shapeId) {
@@ -3904,10 +4037,16 @@ export class LlEmitter {
3904
4037
  this.B.line(`${v} = load ptr, ptr ${p}`);
3905
4038
  return v;
3906
4039
  }
3907
- /** Loads a record field (i8-stored bools trunc to i1). */
3908
- loadField(ptr, t) {
4040
+ /** Loads a record field (i8-stored bools trunc to i1). An inline union
4041
+ * field answers a private stack box with the slot's own bits, ABSENT
4042
+ * included: it may only be borrowed. */
4043
+ loadField(ptr, t, inline) {
3909
4044
  const B = this.B;
3910
- const fieldTy = llFieldType(t);
4045
+ if (inline) {
4046
+ const { tag, bits } = loadInlineUnion(B, ptr);
4047
+ return stackUnionBox(B, this.sizeType, tag, bits);
4048
+ }
4049
+ const fieldTy = llFieldType(t, false);
3911
4050
  const raw = B.tmp();
3912
4051
  B.line(`${raw} = load ${fieldTy}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
3913
4052
  if (fieldTy !== "i8")
@@ -3916,10 +4055,46 @@ export class LlEmitter {
3916
4055
  B.line(`${b} = trunc i8 ${raw} to i1`);
3917
4056
  return b;
3918
4057
  }
3919
- /** Stores a record field (i1 zext to the i8 storage). */
3920
- storeField(ptr, t, value) {
4058
+ /** A record field of this shape stores its scalar union inline. */
4059
+ recordFieldInline(shapeId, field) {
4060
+ const type = this.recordShape(shapeId).fields.find((f) => f.name === field)?.type;
4061
+ return type !== undefined && this.inlineUnions.record(type);
4062
+ }
4063
+ /** The value a field store writes: an inline union slot copies the tag
4064
+ * and bits of a borrowed projection, so no box is built for it. */
4065
+ emitFieldValue(value, inline) {
4066
+ return inline ? this.emitUnionProjection(value) : this.emitExpr(value);
4067
+ }
4068
+ /** Overwrites a field with `v` (from emitFieldValue). A reference moves
4069
+ * in, and the old value is released AFTER the field is overwritten. */
4070
+ replaceField(ptr, type, inline, v) {
4071
+ if (!inline && isRefCounted(type)) {
4072
+ this.moveTemp(v);
4073
+ const old = this.B.tmp();
4074
+ this.B.line(`${old} = load ptr, ptr ${ptr}`);
4075
+ this.storeField(ptr, type, v.name, false);
4076
+ this.releaseValue(old, type);
4077
+ return;
4078
+ }
4079
+ this.storeField(ptr, type, v.name, inline);
4080
+ }
4081
+ /** Stores `v` (from emitFieldValue) into a fresh field slot. */
4082
+ initField(ptr, type, inline, v) {
4083
+ if (!inline && isRefCounted(type))
4084
+ this.moveTemp(v);
4085
+ this.storeField(ptr, type, v.name, inline);
4086
+ }
4087
+ /** Stores a record field (i1 zext to the i8 storage). An inline union
4088
+ * field copies the tag and bits of the union value, which its owner
4089
+ * keeps. */
4090
+ storeField(ptr, t, value, inline) {
3921
4091
  const B = this.B;
3922
- const fieldTy = llFieldType(t);
4092
+ if (inline) {
4093
+ const { tag, bits } = unionBoxBits(B, value, this.unionNoneRef());
4094
+ storeInlineUnion(B, ptr, tag, bits);
4095
+ return;
4096
+ }
4097
+ const fieldTy = llFieldType(t, false);
3923
4098
  if (fieldTy !== "i8") {
3924
4099
  B.line(`store ${fieldTy} ${value}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
3925
4100
  return;
@@ -4389,7 +4564,7 @@ export class LlEmitter {
4389
4564
  this.integerArrayBindings.clear();
4390
4565
  this.loopArrayBorrows =
4391
4566
  this.debug === null
4392
- ? findLoopArrayBorrows(fn, this.callLifetimes, this.referenceEffects, this.optionalArrayReads, this.referenceWrites)
4567
+ ? findLoopArrayBorrows(fn, this.callLifetimes, this.referenceEffects, this.optionalArrayReads, this.referenceWrites, this.fnByName)
4393
4568
  : new Set();
4394
4569
  this.localArrayReads = findLocalArrayReads(fn, this.fnByName, this.unionsById, this.referenceEffects.functions, this.callLifetimes, this.optionalArrayReads, this.loopArrayBorrows, this.debug === null ? this.referenceEffects : undefined);
4395
4570
  this.callArrayReads = findCallArrayReads(fn, this.optionalArrayReads, this.referenceEffects.functions, this.callLifetimes, this.debug === null ? this.referenceEffects : undefined);
@@ -4397,7 +4572,14 @@ export class LlEmitter {
4397
4572
  this.debug === null ? findScalarStringSlices(fn, this.callLifetimes) : new Map();
4398
4573
  this.mapReadLifetimes = findMapReadLifetimes(fn, this.boxedUnionsById, this.callLifetimes);
4399
4574
  this.localStackUnions = findLocalStackUnions(fn, this.callLifetimes, this.boxedUnionsById);
4400
- this.localUnionStorageProofs = findLocalUnionStorage(fn, this.callLifetimes, this.boxedUnionsById, (e) => this.nullableFieldGet(e) !== null);
4575
+ this.localStackObjects = this.stackObjects
4576
+ ? findLocalStackObjects(this, fn, this.callLifetimes)
4577
+ : new Map();
4578
+ this.reassignedStackObjects = this.stackObjects
4579
+ ? findReassignedStackObjects(this, fn, this.callLifetimes)
4580
+ : new Set();
4581
+ this.stackObjectSlots = new Map();
4582
+ this.localUnionStorageProofs = findLocalUnionStorage(fn, this.callLifetimes, this.unionSources);
4401
4583
  this.localUnionStorage = new Map();
4402
4584
  this.walkBorrows = this.walkBorrowsByFunction.get(fn.name) ?? new Set();
4403
4585
  this.integerRanges = analyzeIntegerRanges(numericFn, this.int32Slots.facts(fn.name));
@@ -4417,7 +4599,9 @@ export class LlEmitter {
4417
4599
  this.currentReturnType = fn.returnType;
4418
4600
  const int32Abi = this.int32Abis.get(fn.name);
4419
4601
  this.currentInt32Result = int32Abi?.result === true;
4602
+ this.currentUnionResult = int32Abi?.union === true;
4420
4603
  this.currentGenerator = fn.generator ?? null;
4604
+ this.currentAsyncGenerator = fn.async === true && fn.generator !== undefined;
4421
4605
  this.currentBorrowedReturn = this.borrowedReturns.has(fn.name);
4422
4606
  this.inConstructor = this.constructorFunctions.has(fn.name);
4423
4607
  this.currentCoro = null;
@@ -4604,6 +4788,9 @@ export class LlEmitter {
4604
4788
  // whose unwind released everything down to depth 0).
4605
4789
  if (fn.returnType.kind === "void" && !B.isTerminated()) {
4606
4790
  this.releaseScope(this.scopes[0]);
4791
+ // Completing by falling off the end has nothing to await.
4792
+ if (this.currentAsyncGenerator)
4793
+ this.emitAsyncGenSettled();
4607
4794
  if (this.currentCoro !== null) {
4608
4795
  this.emitWasiFulfill(null);
4609
4796
  B.terminate(`br label %${this.currentCoro.finalLabel}`);
@@ -4681,7 +4868,11 @@ export class LlEmitter {
4681
4868
  // Lifted functions receive their closure first (the callValue ABI).
4682
4869
  if (fn.captures !== undefined)
4683
4870
  params.unshift("ptr %sc_env");
4684
- const ret = int32Abi?.result ? "i32" : this.llType(fn.returnType);
4871
+ const ret = int32Abi?.result
4872
+ ? "i32"
4873
+ : int32Abi?.union
4874
+ ? SCALAR_UNION_RESULT
4875
+ : this.llType(fn.returnType);
4685
4876
  let attrs = coro !== null ? "#1" : FN_ATTRS;
4686
4877
  // The shared indexed-read helper (lowerSafeIndexRead) is a dense bounds
4687
4878
  // test, a state test and a load behind cold runtime fallbacks, called
@@ -4690,6 +4881,15 @@ export class LlEmitter {
4690
4881
  // a call, and an integer index converts to a double and back across it.
4691
4882
  if (fn.name.startsWith("%arr.idxOr."))
4692
4883
  attrs = `inlinehint ${attrs}`;
4884
+ // Interface dispatch is a few key tests and direct calls ahead of the
4885
+ // checked dynamic call. Keeping that fallback out of line leaves the
4886
+ // tests small enough to inline at each call site.
4887
+ if (fn.name.startsWith("%dyn.class.protocol.fallback."))
4888
+ attrs = `noinline ${attrs}`;
4889
+ else if (fn.name.startsWith("%dyn.class.protocol."))
4890
+ attrs = `inlinehint ${attrs}`;
4891
+ if (fn.name.startsWith(RESULT_ENTRY_PREFIX))
4892
+ attrs = `inlinehint ${attrs}`;
4693
4893
  const debug = this.debugScope === null ? "" : ` !dbg ${this.debugScope}`;
4694
4894
  const symbol = borrowed ? mangleBorrowedFunction(fn.name) : mangleFunction(fn.name);
4695
4895
  let body = `define internal ${ret} @${symbol}${int32Abi ? INT32_ABI_SUFFIX : ""}(${params.join(", ")}) ${attrs}${debug} { ; ${fn.name}\n${B.render()}\n}`;
@@ -4721,7 +4921,19 @@ export class LlEmitter {
4721
4921
  args.push(`${type} %p${index}`);
4722
4922
  });
4723
4923
  const ret = this.llType(fn.returnType);
4724
- const call = `call ${abi.result ? "i32" : ret} @${symbol}${INT32_ABI_SUFFIX}(${args.join(", ")})`;
4924
+ const entry = `@${symbol}${INT32_ABI_SUFFIX}(${args.join(", ")})`;
4925
+ if (abi.union) {
4926
+ // Box the register pair for every caller of the ordinary ABI.
4927
+ const B = new BlockBuilder();
4928
+ this.B = B;
4929
+ for (const line of lines)
4930
+ B.line(line.trim());
4931
+ const pair = B.tmp();
4932
+ B.line(`${pair} = call ${SCALAR_UNION_RESULT} ${entry}`);
4933
+ B.terminate(`ret ptr ${this.boxScalarUnion(pair, fn.returnType)}`);
4934
+ return `define internal ptr @${symbol}(${params.join(", ")}) ${FN_ATTRS} {\n${B.render()}\n}`;
4935
+ }
4936
+ const call = `call ${abi.result ? "i32" : ret} ${entry}`;
4725
4937
  if (ret === "void")
4726
4938
  lines.push(` ${call}`, " ret void");
4727
4939
  else if (abi.result)
@@ -4730,6 +4942,85 @@ export class LlEmitter {
4730
4942
  lines.push(` %r = ${call}`, ` ret ${ret} %r`);
4731
4943
  return `define internal ${ret} @${symbol}(${params.join(", ")}) ${FN_ATTRS} {\nentry:\n${lines.join("\n")}\n}`;
4732
4944
  }
4945
+ /** The SCALAR_UNION_RESULT pair of a `%ScrUnion` box of `type`. */
4946
+ scalarUnionPair(box, type) {
4947
+ const B = this.B;
4948
+ const unionId = type.kind === "union" ? type.unionId : "";
4949
+ const tag = this.unionTag(box, unionId);
4950
+ const payload = B.tmp(), bits = B.tmp(), partial = B.tmp(), pair = B.tmp();
4951
+ B.line(`${payload} = getelementptr inbounds %ScrUnion, ptr ${box}, i32 0, i32 5`);
4952
+ B.line(`${bits} = load i64, ptr ${payload}`);
4953
+ B.line(`${partial} = insertvalue ${SCALAR_UNION_RESULT} poison, i32 ${tag}, 0`);
4954
+ B.line(`${pair} = insertvalue ${SCALAR_UNION_RESULT} ${partial}, i64 ${bits}, 1`);
4955
+ return pair;
4956
+ }
4957
+ /** A private stack box holding a SCALAR_UNION_RESULT pair of `type`. */
4958
+ stackScalarUnion(pair, type) {
4959
+ const B = this.B;
4960
+ const box = B.slot(), tagSlot = B.slot(), payloadSlot = B.slot();
4961
+ B.entryAllocas.push(`${box} = alloca %ScrUnion`);
4962
+ B.entryAllocas.push(`${tagSlot} = getelementptr inbounds %ScrUnion, ptr ${box}, i32 0, i32 1`);
4963
+ B.entryAllocas.push(`${payloadSlot} = getelementptr inbounds %ScrUnion, ptr ${box}, i32 0, i32 5`);
4964
+ const tag = B.tmp(), bits = B.tmp();
4965
+ B.line(`${tag} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 0`);
4966
+ B.line(`${bits} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 1`);
4967
+ B.line(`store i32 ${tag}, ptr ${tagSlot}`);
4968
+ B.line(`store i64 ${bits}, ptr ${payloadSlot}`);
4969
+ return { name: box, type };
4970
+ }
4971
+ /** A direct call whose i32 entry returns its scalar union in registers. */
4972
+ scalarResultCall(e) {
4973
+ return e.kind === "call" && this.int32Abis.get(e.callee)?.union === true;
4974
+ }
4975
+ /** A fresh heap box (+1) for a SCALAR_UNION_RESULT pair of `type`; the
4976
+ * exception dummy (tag -1) answers NULL. */
4977
+ boxScalarUnion(pair, type) {
4978
+ const B = this.B;
4979
+ const tag = B.tmp(), bits = B.tmp();
4980
+ B.line(`${tag} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 0`);
4981
+ B.line(`${bits} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 1`);
4982
+ return this.boxScalarUnionBits(tag, bits, type);
4983
+ }
4984
+ /** A fresh heap box (+1) for an inline union field's value; the ABSENT
4985
+ * state reads as the undefined arm. */
4986
+ inlineFieldUnion(ptr, type) {
4987
+ const { tag, bits } = loadInlineUnion(this.B, ptr);
4988
+ return this.boxScalarUnionBits(tag, bits, type);
4989
+ }
4990
+ /** boxScalarUnion over a separate tag and payload bits. Unit arms answer
4991
+ * their immortal instances whatever the bits. */
4992
+ boxScalarUnionBits(tag, bits, type) {
4993
+ const B = this.B;
4994
+ const unionId = type.kind === "union" ? type.unionId : "";
4995
+ const arms = this.unionsById.get(unionId).arms;
4996
+ const join = B.newLabel("union.box.join"), none = B.newLabel("union.box.none");
4997
+ const labels = arms.map(() => B.newLabel("union.box.arm"));
4998
+ B.terminate(`switch i32 ${tag}, label %${none} [ ${labels.map((label, armTag) => `i32 ${armTag}, label %${label}`).join(" ")} ]`);
4999
+ const incoming = [];
5000
+ arms.forEach((arm, armTag) => {
5001
+ B.startBlock(labels[armTag]);
5002
+ let value;
5003
+ if (isUnitType(arm))
5004
+ value = this.unitInstanceRef(unionId, armTag);
5005
+ else {
5006
+ const payload = B.tmp();
5007
+ if (arm.kind === "bool")
5008
+ B.line(`${payload} = trunc i64 ${bits} to i1`);
5009
+ else
5010
+ B.line(`${payload} = bitcast i64 ${bits} to double`);
5011
+ value = this.unionNewOwned(unionId, armTag, { name: payload, type: arm });
5012
+ }
5013
+ incoming.push(`[ ${value}, %${B.currentLabel()} ]`);
5014
+ B.br(join);
5015
+ });
5016
+ B.startBlock(none);
5017
+ incoming.push(`[ null, %${none} ]`);
5018
+ B.br(join);
5019
+ B.startBlock(join);
5020
+ const box = B.tmp();
5021
+ B.line(`${box} = phi ptr ${incoming.join(", ")}`);
5022
+ return box;
5023
+ }
4733
5024
  /** The i32 bits of a number proven an int32 (a direct call's i32
4734
5025
  * argument or an i32 result): its exact integer when the value carries
4735
5026
  * one, else the conversion the proof makes exact. */
@@ -4808,6 +5099,12 @@ export class LlEmitter {
4808
5099
  canBorrowCallArgument(value) {
4809
5100
  if (value.kind === "strLit")
4810
5101
  return true;
5102
+ // An exact capsule owns its instance while the capsule's binding holds it.
5103
+ if (value.kind === "dynCheck" && value.exact)
5104
+ return value.value.kind === "varRef" && this.canBorrowCallArgument(value.value);
5105
+ // An inline union field has no box to lend.
5106
+ if (this.inlineFieldGet(value))
5107
+ return false;
4811
5108
  // Class casts reinterpret the same pointer (prefix layouts).
4812
5109
  if ((value.kind === "upcast" || value.kind === "downcast") &&
4813
5110
  value.value.type.kind === "object")
@@ -5000,6 +5297,12 @@ export class LlEmitter {
5000
5297
  this.finallyStack = savedFinally;
5001
5298
  this.tryStack = savedTry;
5002
5299
  }
5300
+ /** An async generator completing without a further turn: its request
5301
+ * settles as the body returns (scr_async_gen_hop_done). */
5302
+ emitAsyncGenSettled() {
5303
+ this.declare(`declare void @scr_async_gen_hop_done()`);
5304
+ this.B.line(`call void @scr_async_gen_hop_done()`);
5305
+ }
5003
5306
  /** `return x` of a local whose slot is an owned scope entry of the same
5004
5307
  * type: the return can take over the local's reference. */
5005
5308
  movableReturn(value) {
@@ -5200,6 +5503,17 @@ export class LlEmitter {
5200
5503
  this.scopes[this.scopes.length - 1].push({ slot: snapshot.sourceSlot, type: STRING }, { slot: snapshot.separatorSlot, type: STRING });
5201
5504
  break;
5202
5505
  }
5506
+ const stackObject = this.localStackObjects.get(s.localId);
5507
+ if (stackObject) {
5508
+ B.line(`store ptr ${emitStackObject(this, stackObject).name}, ptr ${b.slot}`);
5509
+ break;
5510
+ }
5511
+ if (s.init && this.reassignedStackObjects.has(s.localId)) {
5512
+ const slot = this.stackObjectSlot(s.localId, s.init.type);
5513
+ emitStackObject(this, s.init, slot);
5514
+ B.line(`store ptr ${slot}, ptr ${b.slot}`);
5515
+ break;
5516
+ }
5203
5517
  const localUnion = this.localStackUnions.get(s.localId);
5204
5518
  if (localUnion) {
5205
5519
  const union = emitStackUnion(this, localUnion);
@@ -5303,6 +5617,24 @@ export class LlEmitter {
5303
5617
  emitBorrowedArrayRead(this, s.init, b.slot);
5304
5618
  break;
5305
5619
  }
5620
+ const holeRead = this.loopArrayBorrows.has(s) ? dynHoleRead(s.init) : null;
5621
+ if (holeRead && s.init.kind === "ternary") {
5622
+ // A hole reads as the immortal undefined value, which needs no owner.
5623
+ const present = this.emitExpr(s.init.cond);
5624
+ const filled = B.newLabel("borrow.hole.filled"), missing = B.newLabel("borrow.hole.missing"), done = B.newLabel("borrow.hole.done");
5625
+ B.condBr(present.name, filled, missing);
5626
+ B.startBlock(filled);
5627
+ emitBorrowedArrayRead(this, holeRead, b.slot);
5628
+ B.br(done);
5629
+ B.startBlock(missing);
5630
+ this.declare("declare ptr @scr_dyn_undefined()");
5631
+ const undef = B.tmp();
5632
+ B.line(`${undef} = call ptr @scr_dyn_undefined()`);
5633
+ B.line(`store ptr ${undef}, ptr ${b.slot}`);
5634
+ B.br(done);
5635
+ B.startBlock(done);
5636
+ break;
5637
+ }
5306
5638
  // A stable lexical alias cannot outlive its unchanged local owner.
5307
5639
  // Whole-value uses still retain their own copies, so returning or
5308
5640
  // storing the alias preserves the ordinary heap representation.
@@ -5347,15 +5679,23 @@ export class LlEmitter {
5347
5679
  B.line(`store ptr ${v.name}, ptr ${owner}`);
5348
5680
  break;
5349
5681
  }
5682
+ if (this.reassignedStackObjects.has(s.localId)) {
5683
+ // The new value may read the old one: build it apart, then copy.
5684
+ const struct = stackObjectStruct(s.value.type);
5685
+ const value = emitStackObject(this, s.value);
5686
+ const bits = B.tmp();
5687
+ B.line(`${bits} = load ${struct}, ptr ${value.name}`);
5688
+ B.line(`store ${struct} ${bits}, ptr ${this.stackObjectSlot(s.localId, s.value.type)}`);
5689
+ break;
5690
+ }
5350
5691
  const localStorage = this.localUnionStorage.get(s.localId);
5351
5692
  if (localStorage) {
5352
5693
  storeLocalUnion(this, localStorage, s.value);
5353
5694
  break;
5354
5695
  }
5355
- const concat = s.value;
5356
- const suffix = matchStringSelfConcat(s.localId, concat);
5357
- if (suffix && concat.kind === "strConcat") {
5358
- this.emitStringSelfConcatAssign(s.localId, concat.left, suffix, false);
5696
+ const self = matchStringSelfConcat(s.localId, s.value);
5697
+ if (self) {
5698
+ this.emitStringSelfConcatAssign(s.localId, self.left, self.suffix, false);
5359
5699
  break;
5360
5700
  }
5361
5701
  const b = this.binding(s.localId);
@@ -5520,24 +5860,17 @@ export class LlEmitter {
5520
5860
  break;
5521
5861
  }
5522
5862
  const obj = this.emitStableReceiver(s.obj, [s.value]);
5523
- const v = this.emitExpr(s.value);
5863
+ const v = this.emitFieldValue(s.value, s.kind === "recordSet"
5864
+ ? this.recordFieldInline(s.shapeId, s.field)
5865
+ : this.inlineUnions.classField(s.className, s.field));
5524
5866
  if (s.kind === "fieldSet")
5525
5867
  this.emitStoreGuard(obj.name, s);
5526
5868
  else if (this.publishedTypes?.recordGuarded(s.shapeId) === true)
5527
5869
  this.emitPublishedFieldGuard(obj.name, null, s.field);
5528
- const { ptr, type } = s.kind === "fieldSet"
5870
+ const { ptr, type, inline } = s.kind === "fieldSet"
5529
5871
  ? this.classFieldPtr(obj.name, s.className, s.field)
5530
5872
  : this.recordFieldPtr(obj.name, s.shapeId, s.field);
5531
- if (isRefCounted(type)) {
5532
- this.moveTemp(v);
5533
- const old = B.tmp();
5534
- B.line(`${old} = load ptr, ptr ${ptr}`);
5535
- this.storeField(ptr, type, v.name);
5536
- this.releaseValue(old, type);
5537
- }
5538
- else {
5539
- this.storeField(ptr, type, v.name);
5540
- }
5873
+ this.replaceField(ptr, type, inline, v);
5541
5874
  if (s.kind === "fieldSet" &&
5542
5875
  s.field === "name" &&
5543
5876
  this.classMeta.get(s.className)?.root.def.name === "%Error") {
@@ -5638,15 +5971,20 @@ export class LlEmitter {
5638
5971
  const lw = B.newLabel("rks.w");
5639
5972
  B.condBr(pend, join, lw);
5640
5973
  B.startBlock(lw);
5641
- const { ptr, type } = this.recordFieldPtr(obj.name, s.shapeId, f.name);
5642
- if (isRefCounted(type)) {
5974
+ const { ptr, type, inline } = this.recordFieldPtr(obj.name, s.shapeId, f.name);
5975
+ if (inline) {
5976
+ // The slot copies the checked value's bits; nv is released below.
5977
+ this.storeField(ptr, type, nv, true);
5978
+ this.releaseValue(nv, type);
5979
+ }
5980
+ else if (isRefCounted(type)) {
5643
5981
  const old = B.tmp();
5644
5982
  B.line(`${old} = load ptr, ptr ${ptr}`);
5645
- this.storeField(ptr, type, nv);
5983
+ this.storeField(ptr, type, nv, false);
5646
5984
  this.releaseValue(old, type);
5647
5985
  }
5648
5986
  else {
5649
- this.storeField(ptr, type, nv);
5987
+ this.storeField(ptr, type, nv, false);
5650
5988
  }
5651
5989
  B.br(join);
5652
5990
  B.startBlock(ln);
@@ -5669,15 +6007,20 @@ export class LlEmitter {
5669
6007
  const ln = B.newLabel("rks.n");
5670
6008
  B.condBr(hit, lh, ln);
5671
6009
  B.startBlock(lh);
5672
- const { ptr, type } = this.recordFieldPtr(obj.name, s.shapeId, f.name);
5673
- if (isRefCounted(type)) {
6010
+ const { ptr, type, inline } = this.recordFieldPtr(obj.name, s.shapeId, f.name);
6011
+ if (inline) {
6012
+ // The write owns the moved-in value; the slot copies its bits.
6013
+ this.storeField(ptr, type, v.name, true);
6014
+ this.releaseValue(v.name, type);
6015
+ }
6016
+ else if (isRefCounted(type)) {
5674
6017
  const old = B.tmp();
5675
6018
  B.line(`${old} = load ptr, ptr ${ptr}`);
5676
- this.storeField(ptr, type, v.name);
6019
+ this.storeField(ptr, type, v.name, false);
5677
6020
  this.releaseValue(old, type);
5678
6021
  }
5679
6022
  else {
5680
- this.storeField(ptr, type, v.name);
6023
+ this.storeField(ptr, type, v.name, false);
5681
6024
  }
5682
6025
  B.br(join);
5683
6026
  B.startBlock(ln);
@@ -6199,8 +6542,16 @@ export class LlEmitter {
6199
6542
  break;
6200
6543
  }
6201
6544
  let v = null;
6202
- const moved = this.finallyStack.length === 0 ? this.movableReturn(s.value) : null;
6203
- if (moved !== null) {
6545
+ const moved = this.finallyStack.length === 0 && !this.currentUnionResult
6546
+ ? this.movableReturn(s.value)
6547
+ : null;
6548
+ if (s.value !== null && this.currentUnionResult) {
6549
+ // The tag and payload bits leave in registers; a heap box the
6550
+ // value needed is released with its frame below.
6551
+ const box = this.emitUnionProjection(s.value);
6552
+ v = { name: this.scalarUnionPair(box.name, s.value.type), type: s.value.type };
6553
+ }
6554
+ else if (moved !== null) {
6204
6555
  // Returning an owned local hands its reference to the caller: no
6205
6556
  // retain now and no release of the local below.
6206
6557
  const t = B.tmp();
@@ -6230,9 +6581,22 @@ export class LlEmitter {
6230
6581
  v = this.emitExpr(s.value);
6231
6582
  this.moveTemp(v);
6232
6583
  }
6584
+ // An async generator's `return v` awaits v before any crossed
6585
+ // finally runs. Past finally regions that turn is taken here and
6586
+ // the request settles at completion; otherwise the completion's
6587
+ // own turn is the await (nothing runs in between).
6588
+ const genSettles = this.currentAsyncGenerator && (s.awaited === true || this.finallyStack.length > 0);
6589
+ if (this.currentAsyncGenerator && s.awaited !== true && this.finallyStack.length > 0) {
6590
+ if (this.wasi)
6591
+ this.emitWasiSuspend(null);
6592
+ else {
6593
+ this.declare(`declare void @scr_await_hop()`);
6594
+ B.line(`call void @scr_await_hop()`);
6595
+ }
6596
+ }
6233
6597
  if (this.finallyStack.length > 0) {
6234
6598
  let pretSlot = null;
6235
- if (v !== null && isRefCounted(v.type)) {
6599
+ if (v !== null && isRefCounted(v.type) && !this.currentUnionResult) {
6236
6600
  pretSlot = B.slot();
6237
6601
  B.entryAllocas.push(`${pretSlot} = alloca ptr ; pending return (through finally)`);
6238
6602
  B.line(`store ptr ${v.name}, ptr ${pretSlot}`);
@@ -6265,6 +6629,8 @@ export class LlEmitter {
6265
6629
  this.releaseForJump(0, 0);
6266
6630
  }
6267
6631
  if (!B.isTerminated()) {
6632
+ if (genSettles)
6633
+ this.emitAsyncGenSettled();
6268
6634
  if (this.currentCoro !== null) {
6269
6635
  this.emitWasiFulfill(v);
6270
6636
  B.terminate(`br label %${this.currentCoro.finalLabel}`);
@@ -6273,6 +6639,8 @@ export class LlEmitter {
6273
6639
  B.terminate("ret void");
6274
6640
  else if (this.currentInt32Result)
6275
6641
  B.terminate(`ret i32 ${this.int32Argument(v, s.value)}`);
6642
+ else if (this.currentUnionResult)
6643
+ B.terminate(`ret ${SCALAR_UNION_RESULT} ${v.name}`);
6276
6644
  else
6277
6645
  B.terminate(`ret ${this.llType(s.value.type)} ${v.name}`);
6278
6646
  }
@@ -6313,7 +6681,7 @@ export class LlEmitter {
6313
6681
  break;
6314
6682
  default: {
6315
6683
  // Statement coverage is now total (bytesSet closed the set) —
6316
- // keep the loud refusal for any future IR statement kind.
6684
+ // keep throwing LlvmUnsupportedError for any future IR statement kind.
6317
6685
  const rest = s;
6318
6686
  const k = rest.kind;
6319
6687
  throw new LlvmUnsupportedError(`stmt:${k}`, rest.loc);
@@ -6659,7 +7027,11 @@ export class LlEmitter {
6659
7027
  if (e.kind === "seqExpr" &&
6660
7028
  isRefCounted(e.result.type) &&
6661
7029
  e.result.kind !== "strLit" &&
6662
- this.discardableRead(e.result)) {
7030
+ (this.discardableRead(e.result) ||
7031
+ // A function-local binding's read has no effect of its own (a
7032
+ // compound assignment's result, say); a module binding's read may
7033
+ // throw before initialization, so it stays.
7034
+ (e.result.kind === "varRef" && this.binding(e.result.localId).kind === "local"))) {
6663
7035
  this.emitSequence(() => {
6664
7036
  for (const s of e.stmts)
6665
7037
  this.emitStmt(s);
@@ -6690,8 +7062,11 @@ export class LlEmitter {
6690
7062
  // of first building the suffix as a separate string.
6691
7063
  const parts = stringParts(suffix);
6692
7064
  const mixed = parts.length > 1 || numberPart(parts[0]) !== null;
7065
+ const charCode = mixed ? null : this.emitSingleCharCode(suffix);
6693
7066
  const inputs = mixed ? emitConcatInputs(this, parts) : [];
6694
- const right = mixed ? null : this.emitExpr(suffix);
7067
+ // The concat only reads the suffix; relinquishing the binding below
7068
+ // runs no code that could rebind a borrowed local.
7069
+ const right = mixed || charCode !== null ? null : emitStringInputs(this, [suffix])[0];
6695
7070
  const b = this.binding(localId);
6696
7071
  const B = this.B;
6697
7072
  if (b.kind === "boxed") {
@@ -6705,7 +7080,14 @@ export class LlEmitter {
6705
7080
  this.releaseValue(old, b.type);
6706
7081
  }
6707
7082
  let raw;
6708
- if (right === null) {
7083
+ if (charCode !== null) {
7084
+ // The snapshot moves into the consuming character append.
7085
+ this.moveTemp(snapshot);
7086
+ this.declare(`declare ptr @scr_str_concat_move_char_code(ptr, double)`);
7087
+ raw = B.tmp();
7088
+ B.line(`${raw} = call ptr @scr_str_concat_move_char_code(ptr ${snapshot.name}, double ${charCode.name})`);
7089
+ }
7090
+ else if (right === null) {
6709
7091
  raw = emitMixedConcat(this, snapshot.name, inputs);
6710
7092
  }
6711
7093
  else {
@@ -6730,6 +7112,17 @@ export class LlEmitter {
6730
7112
  }
6731
7113
  return result;
6732
7114
  }
7115
+ /** The code of a one-argument `String.fromCharCode(c)` suffix, emitted, so
7116
+ * `s += String.fromCharCode(c)` appends the character without building
7117
+ * the one-character string; null for any other suffix. */
7118
+ emitSingleCharCode(suffix) {
7119
+ if (suffix.kind !== "libCall" || suffix.fn !== "string.fromCharCode")
7120
+ return null;
7121
+ const packed = suffix.args[0];
7122
+ if (packed?.kind !== "arrayLit" || packed.elems.length !== 1 || packed.spreads?.length)
7123
+ return null;
7124
+ return this.emitExpr(packed.elems[0]);
7125
+ }
6733
7126
  /** `local = local + suffix` when the suffix cannot read or write the
6734
7127
  * local (an unboxed binding is only reachable through this function's own
6735
7128
  * expressions): reading the binding after the suffix gives the value the
@@ -6749,14 +7142,21 @@ export class LlEmitter {
6749
7142
  return null;
6750
7143
  const parts = stringParts(suffix);
6751
7144
  const mixed = parts.length > 1 || numberPart(parts[0]) !== null;
7145
+ const charCode = mixed ? null : this.emitSingleCharCode(suffix);
6752
7146
  const inputs = mixed ? emitConcatInputs(this, parts) : [];
6753
- const right = mixed ? null : this.emitExpr(suffix);
7147
+ // The concat only reads the suffix, which may stay borrowed.
7148
+ const right = mixed || charCode !== null ? null : emitStringInputs(this, [suffix])[0];
6754
7149
  this.materializeSplitLocal(localId);
6755
7150
  const B = this.B;
6756
7151
  const head = B.tmp();
6757
7152
  B.line(`${head} = load ptr, ptr ${b.slot}`);
6758
7153
  let raw;
6759
- if (right === null) {
7154
+ if (charCode !== null) {
7155
+ this.declare(`declare ptr @scr_str_concat_move_char_code(ptr, double)`);
7156
+ raw = B.tmp();
7157
+ B.line(`${raw} = call ptr @scr_str_concat_move_char_code(ptr ${head}, double ${charCode.name})`);
7158
+ }
7159
+ else if (right === null) {
6760
7160
  raw = emitMixedConcat(this, head, inputs, true);
6761
7161
  }
6762
7162
  else {
@@ -6787,8 +7187,45 @@ export class LlEmitter {
6787
7187
  emitIntrinsicExpr(e) {
6788
7188
  if (e.name === "threads.publish")
6789
7189
  return this.emitPublish(e);
7190
+ if (e.name === "region.create" ||
7191
+ e.name === "region.enter" ||
7192
+ e.name === "region.leave" ||
7193
+ e.name === "region.release")
7194
+ return this.emitRegionIntrinsic(e);
6790
7195
  return emitIntrinsicExpr(this, e);
6791
7196
  }
7197
+ /** Lifetime regions in modules with lifetimeRegions (llvm/regions.ts).
7198
+ * Created with the class graph; null elsewhere. */
7199
+ regions = null;
7200
+ /** LifetimeRegion's runtime calls: create answers the region id, enter
7201
+ * and leave bracket run(), release condemns. */
7202
+ emitRegionIntrinsic(e) {
7203
+ if (this.regions === null)
7204
+ throw new InternalCompilerError(`llvm emitter bug: ${e.name} without lifetimeRegions`);
7205
+ const args = e.args.map((a) => this.emitExpr(a));
7206
+ if (this.B.isTerminated())
7207
+ return { name: "", type: e.type };
7208
+ switch (e.name) {
7209
+ case "region.create": {
7210
+ this.declare(`declare double @scr_region_create(ptr)`);
7211
+ const id = this.B.tmp();
7212
+ this.B.line(`${id} = call double @scr_region_create(ptr ${REGION_TYPES})`);
7213
+ return { name: id, type: e.type };
7214
+ }
7215
+ case "region.enter":
7216
+ this.declare(`declare void @scr_region_enter(double)`);
7217
+ this.B.line(`call void @scr_region_enter(double ${args[0].name})`);
7218
+ break;
7219
+ case "region.leave":
7220
+ this.declare(`declare void @scr_region_leave()`);
7221
+ this.B.line(`call void @scr_region_leave()`);
7222
+ break;
7223
+ default:
7224
+ this.declare(`declare void @scr_region_release(double)`);
7225
+ this.B.line(`call void @scr_region_release(double ${args[0].name})`);
7226
+ }
7227
+ return { name: "", type: e.type };
7228
+ }
6792
7229
  publishWalkersCache = null;
6793
7230
  /** Per-type publication walkers, created on the first publish. */
6794
7231
  get publishWalkers() {
@@ -6802,6 +7239,7 @@ export class LlEmitter {
6802
7239
  tracedShapes: this.tracedShapes,
6803
7240
  unionsById: this.unionsById,
6804
7241
  recordsById: this.recordsById,
7242
+ inlineUnions: this.inlineUnions,
6805
7243
  nullableArm: (t) => this.nullableUnions.of(t)?.arm ?? null,
6806
7244
  classInfo: (className) => {
6807
7245
  const meta = this.classMetaOf(className);
@@ -6811,11 +7249,16 @@ export class LlEmitter {
6811
7249
  pre: meta.pre,
6812
7250
  post: meta.post,
6813
7251
  runtimeRooted: meta.root.def.runtime === true,
6814
- fields: meta.def.fields.map((f) => ({
6815
- name: f.name,
6816
- index: classFieldIndex(meta, f.name).index,
6817
- type: this.nullableFields.storageType(className, f.name, f.type),
6818
- })),
7252
+ // Inline scalar-union fields are plain bits: nothing to push.
7253
+ fields: meta.def.fields.flatMap((f) => this.inlineUnions.classField(className, f.name)
7254
+ ? []
7255
+ : [
7256
+ {
7257
+ name: f.name,
7258
+ index: classFieldIndex(meta, f.name).index,
7259
+ type: this.nullableFields.storageType(className, f.name, f.type),
7260
+ },
7261
+ ]),
6819
7262
  };
6820
7263
  },
6821
7264
  classesInInterval: (pre, post) => byPre.filter((m) => m.pre >= pre && m.pre <= post).map((m) => m.def.name),
@@ -6982,6 +7425,8 @@ export class LlEmitter {
6982
7425
  this.B.line(`${value} = load ptr, ptr ${binding.slot}`);
6983
7426
  return { name: value, type: e.type };
6984
7427
  }
7428
+ if (e.kind === "dynCheck" && e.exact)
7429
+ return this.emitExactCapsuleObject(e.value, e.type);
6985
7430
  if (e.kind === "chainRecv") {
6986
7431
  // The chain's bind slot holds its receiver unchanged until the body
6987
7432
  // finishes, owned by the slot itself or by the chain's receiver.
@@ -7042,13 +7487,14 @@ export class LlEmitter {
7042
7487
  if (e.kind === "recordGet" || e.kind === "fieldGet") {
7043
7488
  const receiver = this.emitReadReceiver(e.obj);
7044
7489
  if (e.kind === "recordGet") {
7045
- const { ptr, type } = this.recordFieldPtr(receiver.name, e.shapeId, e.field);
7046
- return { name: this.loadRecordField(ptr, type), type: e.type };
7490
+ // An inline union field answers a private stack box.
7491
+ const { ptr, type, inline } = this.recordFieldPtr(receiver.name, e.shapeId, e.field);
7492
+ return { name: this.loadRecordField(ptr, type, inline), type: e.type };
7047
7493
  }
7048
- const { ptr, type } = this.classFieldPtr(receiver.name, e.className, e.field);
7494
+ const { ptr, type, inline } = this.classFieldPtr(receiver.name, e.className, e.field);
7049
7495
  if (this.int32Slots.isField(e.className, e.field))
7050
7496
  return this.loadInt32Field(ptr, e.type);
7051
- return { name: this.loadField(ptr, type), type: e.type };
7497
+ return { name: this.loadField(ptr, type, inline), type: e.type };
7052
7498
  }
7053
7499
  if (e.kind === "ternary" && this.canBorrowReceiver(e.then) && this.canBorrowReceiver(e.else_)) {
7054
7500
  // Checked projections lower to a ternary with an always-throwing
@@ -7075,10 +7521,30 @@ export class LlEmitter {
7075
7521
  B.line(`${value} = load ptr, ptr ${slot}`);
7076
7522
  return { name: value, type: e.type };
7077
7523
  }
7524
+ // Scalar optional values and register results answer a private stack
7525
+ // box. A ternary of borrowable arms above keeps lending its arm.
7526
+ if ((e.kind === "optChain" ||
7527
+ e.kind === "nullish" ||
7528
+ e.kind === "ternary" ||
7529
+ e.kind === "arrIntrinsic") &&
7530
+ isScalarOptionalSource(e, this.unionSources))
7531
+ return emitScalarOptional(this, e);
7532
+ if (e.kind === "call" && this.scalarResultCall(e))
7533
+ return emitCallExpr(this, e, false, true);
7078
7534
  if (e.kind === "call" && this.canBorrowReceiver(e))
7079
7535
  return emitBorrowedResultCall(this, e);
7080
7536
  return this.emitExpr(e);
7081
7537
  }
7538
+ /** The frame slot a reassigned stack-object local keeps for its value. */
7539
+ stackObjectSlot(localId, type) {
7540
+ let slot = this.stackObjectSlots.get(localId);
7541
+ if (slot === undefined) {
7542
+ slot = this.B.slot();
7543
+ this.B.entryAllocas.push(`${slot} = alloca ${stackObjectStruct(type)}, align 8`);
7544
+ this.stackObjectSlots.set(localId, slot);
7545
+ }
7546
+ return slot;
7547
+ }
7082
7548
  /** A private stack union source with an independently owned payload. */
7083
7549
  canStackReceiver(e) {
7084
7550
  return this.isStackUnionSource(e);
@@ -7090,7 +7556,17 @@ export class LlEmitter {
7090
7556
  return false;
7091
7557
  return (canStackUnion(e, this.boxedUnionsById) ||
7092
7558
  matchMapRead(e, this.boxedUnionsById) !== null ||
7093
- this.optionalArrayReads.get(e) !== null);
7559
+ this.optionalArrayReads.get(e) !== null ||
7560
+ isScalarOptionalSource(e, this.unionSources) ||
7561
+ this.scalarResultCall(e) ||
7562
+ this.inlineFieldGet(e));
7563
+ }
7564
+ /** A read of a record or class field that stores its scalar union
7565
+ * inline. */
7566
+ inlineFieldGet(e) {
7567
+ if (e.kind === "recordGet")
7568
+ return this.recordFieldInline(e.shapeId, e.field);
7569
+ return e.kind === "fieldGet" && this.inlineUnions.classField(e.className, e.field);
7094
7570
  }
7095
7571
  /** The nullable-pointer representation behind a union-typed class field
7096
7572
  * read, or null for every other expression. */
@@ -7229,6 +7705,15 @@ export class LlEmitter {
7229
7705
  this.localArrayReads.has(localId) ||
7230
7706
  this.mapReadLifetimes.locals.has(localId));
7231
7707
  }
7708
+ /** The instance of a capsule known to hold exactly this class (borrowed). */
7709
+ emitExactCapsuleObject(value, type) {
7710
+ const capsule = this.emitReadReceiver(value);
7711
+ const slot = this.B.tmp();
7712
+ const object = this.B.tmp();
7713
+ this.B.line(`${slot} = getelementptr inbounds i8, ptr ${capsule.name}, i64 16 ; ->v.typed_ref.ptr`);
7714
+ this.B.line(`${object} = load ptr, ptr ${slot}`);
7715
+ return { name: object, type };
7716
+ }
7232
7717
  canBorrowReceiver(e) {
7233
7718
  switch (e.kind) {
7234
7719
  case "chainRecv":
@@ -7246,9 +7731,11 @@ export class LlEmitter {
7246
7731
  case "downcast":
7247
7732
  case "upcast":
7248
7733
  return this.canBorrowReceiver(e.value);
7734
+ // An inline union field has no box to lend: projections read it
7735
+ // through emitReadReceiver's private stack box.
7249
7736
  case "fieldGet":
7250
7737
  case "recordGet":
7251
- return this.canBorrowReceiver(e.obj);
7738
+ return !this.inlineFieldGet(e) && this.canBorrowReceiver(e.obj);
7252
7739
  case "ternary":
7253
7740
  return this.canBorrowReceiver(e.then) && this.canBorrowReceiver(e.else_);
7254
7741
  case "seqExpr": {
@@ -7484,8 +7971,11 @@ export class LlEmitter {
7484
7971
  fsRenameThunkFor(cbT) {
7485
7972
  return fsRenameThunkFor(this, cbT);
7486
7973
  }
7487
- cryptoBytesThunkFor(cbT, arrayBuffer = false) {
7488
- return cryptoBytesThunkFor(this, cbT, arrayBuffer);
7974
+ cryptoBytesThunkFor(cbT, arrayBuffer = false, valueMode = "buffer") {
7975
+ return cryptoBytesThunkFor(this, cbT, arrayBuffer, valueMode);
7976
+ }
7977
+ cryptoIntThunkFor(cbT) {
7978
+ return cryptoIntThunkFor(this, cbT);
7489
7979
  }
7490
7980
  zlibBytesThunkFor(cbT) {
7491
7981
  return zlibBytesThunkFor(this, cbT);