@scriptc/compiler 0.3.2 → 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 (364) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +490 -39
  2. package/dist/backend/cycle-analysis.js +6 -1
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/llvm/alloc.js +24 -10
  5. package/dist/backend/llvm/alloc.js.map +1 -1
  6. package/dist/backend/llvm/alloc.test.js +47 -1
  7. package/dist/backend/llvm/alloc.test.js.map +1 -1
  8. package/dist/backend/llvm/array-search.d.ts +8 -0
  9. package/dist/backend/llvm/array-search.js +52 -0
  10. package/dist/backend/llvm/array-search.js.map +1 -0
  11. package/dist/backend/llvm/array-search.test.d.ts +1 -0
  12. package/dist/backend/llvm/array-search.test.js +72 -0
  13. package/dist/backend/llvm/array-search.test.js.map +1 -0
  14. package/dist/backend/llvm/call-lifetimes.d.ts +8 -1
  15. package/dist/backend/llvm/call-lifetimes.js +33 -11
  16. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  17. package/dist/backend/llvm/call-lifetimes.test.js +54 -0
  18. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  19. package/dist/backend/llvm/classes.js +87 -36
  20. package/dist/backend/llvm/classes.js.map +1 -1
  21. package/dist/backend/llvm/common.d.ts +1 -1
  22. package/dist/backend/llvm/common.js +1 -1
  23. package/dist/backend/llvm/dense-array-access.d.ts +5 -0
  24. package/dist/backend/llvm/dense-array-access.js +1 -1
  25. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  26. package/dist/backend/llvm/dyn.d.ts +4 -0
  27. package/dist/backend/llvm/dyn.js +73 -9
  28. package/dist/backend/llvm/dyn.js.map +1 -1
  29. package/dist/backend/llvm/emitter.d.ts +65 -14
  30. package/dist/backend/llvm/emitter.js +297 -81
  31. package/dist/backend/llvm/emitter.js.map +1 -1
  32. package/dist/backend/llvm/emitter.test.js +26 -3
  33. package/dist/backend/llvm/emitter.test.js.map +1 -1
  34. package/dist/backend/llvm/expr-async.js +52 -1
  35. package/dist/backend/llvm/expr-async.js.map +1 -1
  36. package/dist/backend/llvm/expr-bytes.js +11 -0
  37. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  38. package/dist/backend/llvm/expr-callbacks.js +16 -2
  39. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  40. package/dist/backend/llvm/expr-calls.js +8 -1
  41. package/dist/backend/llvm/expr-calls.js.map +1 -1
  42. package/dist/backend/llvm/expr-containers.js +42 -15
  43. package/dist/backend/llvm/expr-containers.js.map +1 -1
  44. package/dist/backend/llvm/expr-dynamic.js +19 -8
  45. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  46. package/dist/backend/llvm/expr-primitives.js +28 -30
  47. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  48. package/dist/backend/llvm/expr-records.js +8 -4
  49. package/dist/backend/llvm/expr-records.js.map +1 -1
  50. package/dist/backend/llvm/expr-stream-bridges.js +35 -32
  51. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  52. package/dist/backend/llvm/expr-stream-callbacks.d.ts +13 -2
  53. package/dist/backend/llvm/expr-stream-callbacks.js +80 -5
  54. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  55. package/dist/backend/llvm/inline-unions.d.ts +48 -0
  56. package/dist/backend/llvm/inline-unions.js +134 -0
  57. package/dist/backend/llvm/inline-unions.js.map +1 -0
  58. package/dist/backend/llvm/inline-unions.test.d.ts +1 -0
  59. package/dist/backend/llvm/inline-unions.test.js +124 -0
  60. package/dist/backend/llvm/inline-unions.test.js.map +1 -0
  61. package/dist/backend/llvm/integer-remainder.d.ts +28 -5
  62. package/dist/backend/llvm/integer-remainder.js +80 -9
  63. package/dist/backend/llvm/integer-remainder.js.map +1 -1
  64. package/dist/backend/llvm/lib-dispatch.js +163 -28
  65. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  66. package/dist/backend/llvm/lib-filesystem.js +125 -7
  67. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  68. package/dist/backend/llvm/lib-network.js +9 -6
  69. package/dist/backend/llvm/lib-network.js.map +1 -1
  70. package/dist/backend/llvm/lib-process.js +2 -2
  71. package/dist/backend/llvm/lib-process.js.map +1 -1
  72. package/dist/backend/llvm/lib-shared.js +132 -0
  73. package/dist/backend/llvm/lib-shared.js.map +1 -1
  74. package/dist/backend/llvm/lib-stream.js +97 -0
  75. package/dist/backend/llvm/lib-stream.js.map +1 -1
  76. package/dist/backend/llvm/local-array-reads.js +7 -3
  77. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  78. package/dist/backend/llvm/local-array-reads.test.js +6 -3
  79. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  80. package/dist/backend/llvm/local-union-storage.d.ts +2 -0
  81. package/dist/backend/llvm/local-union-storage.js +5 -0
  82. package/dist/backend/llvm/local-union-storage.js.map +1 -1
  83. package/dist/backend/llvm/local-union-storage.test.js +1 -0
  84. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  85. package/dist/backend/llvm/loop-array-borrows.d.ts +8 -2
  86. package/dist/backend/llvm/loop-array-borrows.js +93 -13
  87. package/dist/backend/llvm/loop-array-borrows.js.map +1 -1
  88. package/dist/backend/llvm/map-number-lookup.d.ts +20 -0
  89. package/dist/backend/llvm/map-number-lookup.js +66 -0
  90. package/dist/backend/llvm/map-number-lookup.js.map +1 -1
  91. package/dist/backend/llvm/map-number-lookup.test.d.ts +1 -0
  92. package/dist/backend/llvm/map-number-lookup.test.js +102 -0
  93. package/dist/backend/llvm/map-number-lookup.test.js.map +1 -0
  94. package/dist/backend/llvm/map-read-lifetimes.js +1 -0
  95. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  96. package/dist/backend/llvm/publish.d.ts +4 -0
  97. package/dist/backend/llvm/publish.js +3 -1
  98. package/dist/backend/llvm/publish.js.map +1 -1
  99. package/dist/backend/llvm/record-results.d.ts +8 -5
  100. package/dist/backend/llvm/record-results.js +20 -12
  101. package/dist/backend/llvm/record-results.js.map +1 -1
  102. package/dist/backend/llvm/reference-effects.js +13 -0
  103. package/dist/backend/llvm/reference-effects.js.map +1 -1
  104. package/dist/backend/llvm/reference-writes.js +14 -0
  105. package/dist/backend/llvm/reference-writes.js.map +1 -1
  106. package/dist/backend/llvm/regions.d.ts +1 -0
  107. package/dist/backend/llvm/regions.js +12 -7
  108. package/dist/backend/llvm/regions.js.map +1 -1
  109. package/dist/backend/llvm/serialized-ir-emission.test.js +2 -0
  110. package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -1
  111. package/dist/backend/llvm/shapes.d.ts +56 -10
  112. package/dist/backend/llvm/shapes.js +178 -39
  113. package/dist/backend/llvm/shapes.js.map +1 -1
  114. package/dist/backend/llvm/shapes.test.js +61 -3
  115. package/dist/backend/llvm/shapes.test.js.map +1 -1
  116. package/dist/backend/llvm/stack-objects.js +16 -4
  117. package/dist/backend/llvm/stack-objects.js.map +1 -1
  118. package/dist/backend/llvm/stack-objects.test.js +3 -0
  119. package/dist/backend/llvm/stack-objects.test.js.map +1 -1
  120. package/dist/backend/llvm/walkers.d.ts +11 -0
  121. package/dist/backend/llvm/walkers.js +106 -10
  122. package/dist/backend/llvm/walkers.js.map +1 -1
  123. package/dist/backend/may-throw.js +9 -4
  124. package/dist/backend/may-throw.js.map +1 -1
  125. package/dist/backend/native/contracts.d.ts +2 -2
  126. package/dist/backend/native/executable.js +14 -3
  127. package/dist/backend/native/executable.js.map +1 -1
  128. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  129. package/dist/backend/native/runtime-inputs.js +1 -0
  130. package/dist/backend/native/runtime-inputs.js.map +1 -1
  131. package/dist/backend/native-toolchain.test.js +1 -1
  132. package/dist/backend/native-toolchain.test.js.map +1 -1
  133. package/dist/backend/runtime-abi.d.ts +2 -2
  134. package/dist/backend/runtime-abi.js +2 -2
  135. package/dist/backend/runtime-pack-targets.test.js +1 -1
  136. package/dist/backend/runtime-pack.test.js +1 -1
  137. package/dist/backend/target-diagnostics.js +4 -1
  138. package/dist/backend/target-diagnostics.js.map +1 -1
  139. package/dist/backend/target-diagnostics.test.js +4 -1
  140. package/dist/backend/target-diagnostics.test.js.map +1 -1
  141. package/dist/compat/fetch-profile.js +4 -4
  142. package/dist/compat/fetch-profile.js.map +1 -1
  143. package/dist/contracts/check.js +2 -0
  144. package/dist/contracts/check.js.map +1 -1
  145. package/dist/coverage/report.js +1 -1
  146. package/dist/coverage/report.js.map +1 -1
  147. package/dist/diagnostics/diagnostic.d.ts +6 -5
  148. package/dist/diagnostics/diagnostic.js +7 -6
  149. package/dist/diagnostics/diagnostic.js.map +1 -1
  150. package/dist/frontend/builtin-modules.d.ts +1 -1
  151. package/dist/frontend/builtin-modules.js +1 -0
  152. package/dist/frontend/builtin-modules.js.map +1 -1
  153. package/dist/frontend/comptime-node.js +2 -2
  154. package/dist/frontend/comptime-node.js.map +1 -1
  155. package/dist/frontend/lowering/binding-analysis.d.ts +1 -1
  156. package/dist/frontend/lowering/binding-analysis.js +1 -1
  157. package/dist/frontend/lowering/builtins/arguments.d.ts +4 -0
  158. package/dist/frontend/lowering/builtins/arguments.js +8 -4
  159. package/dist/frontend/lowering/builtins/arguments.js.map +1 -1
  160. package/dist/frontend/lowering/builtins/blob.d.ts +20 -0
  161. package/dist/frontend/lowering/builtins/blob.js +167 -0
  162. package/dist/frontend/lowering/builtins/blob.js.map +1 -0
  163. package/dist/frontend/lowering/builtins/child-process-async.d.ts +2 -2
  164. package/dist/frontend/lowering/builtins/child-process-async.js +2 -2
  165. package/dist/frontend/lowering/builtins/child-process-methods.js +1 -1
  166. package/dist/frontend/lowering/builtins/child-process-methods.js.map +1 -1
  167. package/dist/frontend/lowering/builtins/child-process-sync.js +1 -1
  168. package/dist/frontend/lowering/builtins/child-process-sync.js.map +1 -1
  169. package/dist/frontend/lowering/builtins/compression.js +3 -2
  170. package/dist/frontend/lowering/builtins/compression.js.map +1 -1
  171. package/dist/frontend/lowering/builtins/crypto.js +415 -120
  172. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  173. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +10 -0
  174. package/dist/frontend/lowering/builtins/filesystem-calls.js +89 -1
  175. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  176. package/dist/frontend/lowering/builtins/filesystem.d.ts +16 -7
  177. package/dist/frontend/lowering/builtins/filesystem.js +97 -15
  178. package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
  179. package/dist/frontend/lowering/builtins/fs-glob.d.ts +23 -0
  180. package/dist/frontend/lowering/builtins/fs-glob.js +224 -0
  181. package/dist/frontend/lowering/builtins/fs-glob.js.map +1 -0
  182. package/dist/frontend/lowering/builtins/key-object.d.ts +13 -0
  183. package/dist/frontend/lowering/builtins/key-object.js +56 -0
  184. package/dist/frontend/lowering/builtins/key-object.js.map +1 -0
  185. package/dist/frontend/lowering/builtins/module-calls.js +44 -11
  186. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  187. package/dist/frontend/lowering/builtins/performance.d.ts +25 -3
  188. package/dist/frontend/lowering/builtins/performance.js +340 -5
  189. package/dist/frontend/lowering/builtins/performance.js.map +1 -1
  190. package/dist/frontend/lowering/builtins/process.d.ts +2 -2
  191. package/dist/frontend/lowering/builtins/process.js +107 -14
  192. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  193. package/dist/frontend/lowering/builtins/properties.d.ts +0 -7
  194. package/dist/frontend/lowering/builtins/properties.js +39 -11
  195. package/dist/frontend/lowering/builtins/properties.js.map +1 -1
  196. package/dist/frontend/lowering/builtins/readline.d.ts +23 -8
  197. package/dist/frontend/lowering/builtins/readline.js +266 -90
  198. package/dist/frontend/lowering/builtins/readline.js.map +1 -1
  199. package/dist/frontend/lowering/builtins/url.d.ts +8 -0
  200. package/dist/frontend/lowering/builtins/url.js +36 -0
  201. package/dist/frontend/lowering/builtins/url.js.map +1 -1
  202. package/dist/frontend/lowering/call-arguments.js +1 -1
  203. package/dist/frontend/lowering/call-arguments.js.map +1 -1
  204. package/dist/frontend/lowering/call-signatures.js +20 -2
  205. package/dist/frontend/lowering/call-signatures.js.map +1 -1
  206. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +2 -0
  207. package/dist/frontend/lowering/class-dynamic-dispatch.js +105 -1
  208. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  209. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +1 -0
  210. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  211. package/dist/frontend/lowering/class-protocol-dispatch.d.ts +45 -0
  212. package/dist/frontend/lowering/class-protocol-dispatch.js +516 -0
  213. package/dist/frontend/lowering/class-protocol-dispatch.js.map +1 -0
  214. package/dist/frontend/lowering/coercions/structural-plans.js +2 -1
  215. package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
  216. package/dist/frontend/lowering/coercions/structural.js +3 -3
  217. package/dist/frontend/lowering/coercions/structural.js.map +1 -1
  218. package/dist/frontend/lowering/collation-repertoire.js +6 -5
  219. package/dist/frontend/lowering/collation-repertoire.js.map +1 -1
  220. package/dist/frontend/lowering/containers/array-callbacks.js +4 -7
  221. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  222. package/dist/frontend/lowering/containers/array-methods.d.ts +0 -7
  223. package/dist/frontend/lowering/containers/array-methods.js +43 -2
  224. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  225. package/dist/frontend/lowering/containers/bytes.js +38 -26
  226. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  227. package/dist/frontend/lowering/containers/for-of.d.ts +1 -1
  228. package/dist/frontend/lowering/containers/for-of.js +5 -1
  229. package/dist/frontend/lowering/containers/for-of.js.map +1 -1
  230. package/dist/frontend/lowering/containers/indexed-objects.js +1 -1
  231. package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
  232. package/dist/frontend/lowering/crypto-tables.d.ts +3 -3
  233. package/dist/frontend/lowering/crypto-tables.js +77 -12
  234. package/dist/frontend/lowering/crypto-tables.js.map +1 -1
  235. package/dist/frontend/lowering/expressions/nullish-assignment.js +10 -0
  236. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  237. package/dist/frontend/lowering/expressions/object-literals.js +16 -12
  238. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  239. package/dist/frontend/lowering/generic-functions.d.ts +2 -2
  240. package/dist/frontend/lowering/generic-functions.js +2 -2
  241. package/dist/frontend/lowering/generic-functions.js.map +1 -1
  242. package/dist/frontend/lowering/http2-constants.js +1 -1
  243. package/dist/frontend/lowering/lower-array-sort.d.ts +12 -1
  244. package/dist/frontend/lowering/lower-array-sort.js +561 -191
  245. package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
  246. package/dist/frontend/lowering/lower-array-sort.test.js +4 -2
  247. package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -1
  248. package/dist/frontend/lowering/lower-assert.js +2 -2
  249. package/dist/frontend/lowering/lower-async-iteration.d.ts +6 -3
  250. package/dist/frontend/lowering/lower-async-iteration.js +248 -2
  251. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
  252. package/dist/frontend/lowering/lower-calls.js +101 -9
  253. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  254. package/dist/frontend/lowering/lower-classes.d.ts +8 -2
  255. package/dist/frontend/lowering/lower-classes.js +40 -9
  256. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  257. package/dist/frontend/lowering/lower-comptime.d.ts +1 -1
  258. package/dist/frontend/lowering/lower-comptime.js +4 -4
  259. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  260. package/dist/frontend/lowering/lower-event-target.d.ts +63 -0
  261. package/dist/frontend/lowering/lower-event-target.js +362 -0
  262. package/dist/frontend/lowering/lower-event-target.js.map +1 -0
  263. package/dist/frontend/lowering/lower-expando.js +2 -2
  264. package/dist/frontend/lowering/lower-exprs.js +112 -22
  265. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  266. package/dist/frontend/lowering/lower-inspect.js +129 -11
  267. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  268. package/dist/frontend/lowering/lower-mixins.js +1 -1
  269. package/dist/frontend/lowering/lower-modules.d.ts +1 -1
  270. package/dist/frontend/lowering/lower-modules.js +7 -3
  271. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  272. package/dist/frontend/lowering/lower-namespaces.d.ts +2 -2
  273. package/dist/frontend/lowering/lower-namespaces.js +2 -2
  274. package/dist/frontend/lowering/lower-server.js +39 -14
  275. package/dist/frontend/lowering/lower-server.js.map +1 -1
  276. package/dist/frontend/lowering/lower-stdlib.d.ts +7 -1
  277. package/dist/frontend/lowering/lower-stdlib.js +10 -3
  278. package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
  279. package/dist/frontend/lowering/lower-stmts.d.ts +2 -2
  280. package/dist/frontend/lowering/lower-stmts.js +46 -12
  281. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  282. package/dist/frontend/lowering/lower-stream.js +234 -22
  283. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  284. package/dist/frontend/lowering/lower-timers.js +1 -1
  285. package/dist/frontend/lowering/lowerer.d.ts +23 -5
  286. package/dist/frontend/lowering/lowerer.js +245 -41
  287. package/dist/frontend/lowering/lowerer.js.map +1 -1
  288. package/dist/frontend/lowering/native-ffi.js +2 -2
  289. package/dist/frontend/lowering/native-ffi.js.map +1 -1
  290. package/dist/frontend/lowering/runtime-optional-records.d.ts +115 -0
  291. package/dist/frontend/lowering/runtime-optional-records.js +715 -0
  292. package/dist/frontend/lowering/runtime-optional-records.js.map +1 -0
  293. package/dist/frontend/lowering/runtime-optional-records.test.d.ts +1 -0
  294. package/dist/frontend/lowering/runtime-optional-records.test.js +175 -0
  295. package/dist/frontend/lowering/runtime-optional-records.test.js.map +1 -0
  296. package/dist/frontend/lowering/surfaces.d.ts +7 -3
  297. package/dist/frontend/lowering/surfaces.js +273 -22
  298. package/dist/frontend/lowering/surfaces.js.map +1 -1
  299. package/dist/frontend/module-syntax.d.ts +1 -1
  300. package/dist/frontend/module-syntax.js +1 -1
  301. package/dist/frontend/npm-static-prune.js +1 -1
  302. package/dist/frontend/npm-static-prune.js.map +1 -1
  303. package/dist/frontend/npm-static-rewrite-syntax.js +4 -3
  304. package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -1
  305. package/dist/frontend/pipeline.js +1 -1
  306. package/dist/frontend/pipeline.js.map +1 -1
  307. package/dist/frontend/program.d.ts +3 -3
  308. package/dist/frontend/program.js +19 -17
  309. package/dist/frontend/program.js.map +1 -1
  310. package/dist/frontend/resolve.js +1 -1
  311. package/dist/frontend/ts7/adapter.js +1 -1
  312. package/dist/frontend/ts7/ast-bytes.d.ts +1 -1
  313. package/dist/frontend/ts7/ast-bytes.js +1 -1
  314. package/dist/frontend/ts7/semantic-json.d.ts +1 -1
  315. package/dist/frontend/ts7/semantic-json.js +1 -1
  316. package/dist/frontend/ts7/semantic-json.js.map +1 -1
  317. package/dist/frontend/ts7/world-check.js +1 -1
  318. package/dist/frontend/tsc-codes.js +2 -2
  319. package/dist/frontend/tsc-codes.js.map +1 -1
  320. package/dist/frontend/type-mapper.d.ts +16 -1
  321. package/dist/frontend/type-mapper.js +143 -18
  322. package/dist/frontend/type-mapper.js.map +1 -1
  323. package/dist/index.js +5 -4
  324. package/dist/index.js.map +1 -1
  325. package/dist/ir/analysis.d.ts +12 -6
  326. package/dist/ir/analysis.js +26 -10
  327. package/dist/ir/analysis.js.map +1 -1
  328. package/dist/ir/analysis.test.js +15 -3
  329. package/dist/ir/analysis.test.js.map +1 -1
  330. package/dist/ir/builtin-effects.js +79 -0
  331. package/dist/ir/builtin-effects.js.map +1 -1
  332. package/dist/ir/builtin-signatures.d.ts +1 -1
  333. package/dist/ir/builtin-signatures.js +291 -38
  334. package/dist/ir/builtin-signatures.js.map +1 -1
  335. package/dist/ir/int32-slots.js +1 -0
  336. package/dist/ir/int32-slots.js.map +1 -1
  337. package/dist/ir/ir.d.ts +64 -16
  338. package/dist/ir/ir.js +37 -1
  339. package/dist/ir/ir.js.map +1 -1
  340. package/dist/ir/runtime-features.js +83 -6
  341. package/dist/ir/runtime-features.js.map +1 -1
  342. package/dist/ir/serialize.js +1 -1
  343. package/dist/ir/serialize.js.map +1 -1
  344. package/dist/ir/traverse.js +1 -0
  345. package/dist/ir/traverse.js.map +1 -1
  346. package/dist/ir/validate.js +100 -9
  347. package/dist/ir/validate.js.map +1 -1
  348. package/dist/ir/validate.test.js +60 -0
  349. package/dist/ir/validate.test.js.map +1 -1
  350. package/dist/library/fence-eval.d.ts +1 -1
  351. package/dist/library/fence-eval.js +5 -4
  352. package/dist/library/fence-eval.js.map +1 -1
  353. package/dist/library/ir-policy.js +10 -4
  354. package/dist/library/ir-policy.js.map +1 -1
  355. package/dist/library/library-profile.js +13 -13
  356. package/dist/library/library-profile.js.map +1 -1
  357. package/dist/library/prepare.js +1 -1
  358. package/dist/library/prepare.js.map +1 -1
  359. package/dist/library/sidecar.js +3 -3
  360. package/dist/library/sidecar.js.map +1 -1
  361. package/dist/native/prepare.js +3 -2
  362. package/dist/native/prepare.js.map +1 -1
  363. package/package.json +20 -20
  364. package/surface-manifest.json +379 -142
@@ -1,3 +1,5 @@
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
5
  import { CYC_BUF, CYC_HDR, FIRST_EMITTED_CYC_KIND, inlineAllocSupported } from "./alloc.js";
@@ -7,7 +9,7 @@ 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,7 +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";
19
- import { addRecordResultEntries } from "./record-results.js";
21
+ import { RESULT_ENTRY_PREFIX, addRecordResultEntries } from "./record-results.js";
20
22
  import { specializeNumericCalls } from "../../ir/numeric-call-specialization.js";
21
23
  import { everyExpr, everyExprChild, everyStmtChild, everyStmtList } from "../../ir/traverse.js";
22
24
  import { analyzeIntegerRanges, INT32_RANGE } from "../../ir/integer-ranges.js";
@@ -40,6 +42,7 @@ import { emitStackObject, findLocalStackObjects, findReassignedStackObjects, sta
40
42
  import { allocateLocalUnion, emitScalarOptional, findLocalUnionStorage, isScalarOptionalSource, storeLocalUnion, } from "./local-union-storage.js";
41
43
  import { BlockBuilder } from "./blocks.js";
42
44
  import { NullableRefFields } from "./nullable-fields.js";
45
+ import { InlineUnionFields, loadInlineUnion, presentBits, stackUnionBox, storeInlineUnion, unionBoxBits, } from "./inline-unions.js";
43
46
  import { emitLocalArrayRead, emitProjectedArrayRead, emitBorrowedArrayRead, findLocalArrayReads, findCallArrayReads, OptionalArrayReads, } from "./local-array-reads.js";
44
47
  import { CheckedNarrows, emitCheckedNarrowReceiver } from "./checked-narrows.js";
45
48
  import { emitDenseArrayGet, emitDenseArraySet } from "./dense-array-access.js";
@@ -52,7 +55,7 @@ import { ReferenceEffects } from "./reference-effects.js";
52
55
  import { ReferenceWrites } from "./reference-writes.js";
53
56
  import { LlvmDebugInfo } from "./debug-info.js";
54
57
  import { StackCallbacks } from "./stack-callbacks.js";
55
- import { findLoopArrayBorrows } from "./loop-array-borrows.js";
58
+ import { dynHoleRead, findLoopArrayBorrows } from "./loop-array-borrows.js";
56
59
  import { findAppendedArrayLiterals } from "./appended-array-literals.js";
57
60
  import { AmbientReceiverReaders, findConstantCallbacks } from "./constant-callbacks.js";
58
61
  import { findScalarStringSlices, emitStringSliceSnapshot, } from "./string-slices.js";
@@ -70,7 +73,7 @@ import { computeImmutableFields, stableGlobals } from "../immutability.js";
70
73
  import { computePublishedTypes } from "../publication.js";
71
74
  import { emitExpr } from "./expr-dispatch.js";
72
75
  import { dynKind, raceAdapterFor, genResultThunkFor, childExitThunkFor, childExitSignalThunkFor, childDataThunkFor, execFileThunkFor, ipcMessageThunkFor, ipcSendThunkFor, emitterFixedAdapter, wrapEmitterListener, unwrapNullableClosure, closeBindThunkFor, closeOverrideWrapFor, } from "./expr-callbacks.js";
73
- 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";
74
77
  import { emitStableReceiver, resolveThunkFor, tagInSet, arrPush, emitArrayCopyLoop, emitStrIntrinsic, emitArrIntrinsic, emitDiscardedSplice, wrapNullable, emitMapNew, mapSet, emitMapLikeIntrinsic, emitSetNew, } from "./expr-containers.js";
75
78
  import { emitIntegerLoopIndex, emitBytesIndex, emitBytesData, emitBytesLength, emitBytesGet, emitToUint32, emitBytesSet, emitBytesIntrinsic, } from "./expr-bytes.js";
76
79
  import { emitRegexIntrinsic, emitRecordKeyGet, keyedRecordReadInto } from "./expr-records.js";
@@ -89,10 +92,10 @@ import { LlWalkers } from "./walkers.js";
89
92
  import { isObjectArm, NULLABLE_ABSENT, NULLABLE_NULL, NullableUnions } from "./nullable-unions.js";
90
93
  import { emitNullablePresent, emitUnionPeek, emitUnionTag } from "./union-repr.js";
91
94
  import { literalCapWord, literalCapWord32 } from "./string-key-hash.js";
92
- import { NUMBER_MAP_ENTRY_DECL, STRING_MAP_ENTRY_DECL } from "./map-number-lookup.js";
95
+ import { MAP_ITER_DECL, NUMBER_MAP_ENTRY_DECL, STRING_MAP_ENTRY_DECL, } from "./map-number-lookup.js";
93
96
  import { STRING_READ_HELPERS, stringScanDecl } from "./string-reads.js";
94
97
  import { emitConcatInputs, emitMixedConcat, numberPart, stringParts, } from "./string-construction.js";
95
- 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";
96
99
  import { INLINE_LITERAL_BYTES, literalEqualityDefinition } from "./string-literal-equality.js";
97
100
  export { LlvmUnsupportedError } from "./unsupported.js";
98
101
  function ffiCallbackDummyLl(callback) {
@@ -286,6 +289,8 @@ export class LlEmitter {
286
289
  unitInstances = new Map();
287
290
  /** unionId → symbol of the union's immortal ABSENT field-slot instance. */
288
291
  absentInstances = new Map();
292
+ /** The zeroed box an inline store reads for a NULL union dummy. */
293
+ needsUnionNone = false;
289
294
  /** unionId → symbol of a flag set once a checked-dynamic cast caches one
290
295
  * of the union's boxes. A cached box is refreshed in place, possibly with
291
296
  * a tag that another union numbers apart, so it is never shared. */
@@ -328,6 +333,8 @@ export class LlEmitter {
328
333
  /** Inline RC fast-path helpers requested by call sites (shapes.ts); null
329
334
  * when inline RC is off. */
330
335
  rcHelpers;
336
+ rcMode;
337
+ rcHelpersNoinline;
331
338
  fnByName = new Map();
332
339
  /** Empty literals that construct with inline slots (appended-array-literals.ts). */
333
340
  appendedArrayLiterals = new Set();
@@ -439,6 +446,8 @@ export class LlEmitter {
439
446
  * typeKey → thunk symbol. */
440
447
  resolveThunks = new Map();
441
448
  resolveThunkDefs = [];
449
+ /** Inline array searches used by the module (array-search.ts). */
450
+ arraySearchKinds = new Set();
442
451
  /** Typed-ref recipe constants by type key (lazy receivers). */
443
452
  typedRefRecipes = new Map();
444
453
  /** ReadableStream.from adapters keep typed arrays by reference and box
@@ -452,6 +461,7 @@ export class LlEmitter {
452
461
  dynPromiseAdapters = new Map();
453
462
  unionsById = new Map();
454
463
  nullableFields;
464
+ inlineUnions;
455
465
  /** Unions whose values are nullable arm pointers (nullable-unions.ts). */
456
466
  nullableUnions;
457
467
  /** The union table without nullable unions: the stack-box analyses. */
@@ -624,7 +634,9 @@ export class LlEmitter {
624
634
  this.emitLibraryIdentity = options.emitLibraryIdentity !== false;
625
635
  this.runtimeAbiMarker = options.runtimeAbiMarker === true;
626
636
  this.detachedExit = options.detachedExit === true;
627
- this.rcHelpers = options.inlineRc === true ? new Set() : null;
637
+ this.rcHelpers = options.inlineRc !== undefined ? new Set() : null;
638
+ this.rcMode = options.inlineRc;
639
+ this.rcHelpersNoinline = options.rcHelpersNoinline === true;
628
640
  // ScrCycHdr.buf sits 4 bytes behind every object on every target.
629
641
  this.cycleBufOffset = CYC_HDR - CYC_BUF;
630
642
  this.ffiCallbackAdapters = allocateFfiCallbackAdapters(mod.ffiImports ?? []);
@@ -662,6 +674,9 @@ export class LlEmitter {
662
674
  this.immortalValues.add("null");
663
675
  this.immortalValues.add(NULLABLE_NULL);
664
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);
665
680
  // Optional array reads also cover nullable unions: emitLocalArrayRead
666
681
  // then yields the (borrowed or owned) element pointer, not a stack box.
667
682
  // Arrays of such a union are read the same way.
@@ -670,6 +685,7 @@ export class LlEmitter {
670
685
  unions: this.boxedUnionsById,
671
686
  receiverUnions: this.unionsById,
672
687
  nullableField: (e) => this.nullableFieldGet(e) !== null,
688
+ inlineField: (e) => this.inlineFieldGet(e),
673
689
  arrayRead: (e) => this.optionalArrayReads.get(e) !== null,
674
690
  scalarCall: (e) => this.scalarResultCall(e),
675
691
  };
@@ -718,14 +734,15 @@ export class LlEmitter {
718
734
  walkParameters.set(fn.name, indexes);
719
735
  }
720
736
  }
721
- this.callLifetimes = analyzeCallLifetimes(this.fnByName, (className, field) => this.nullableFields.get(className, field) !== null, walkParameters, new Set([...this.int32Abis].filter(([, abi]) => abi.union).map(([name]) => name)));
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
+ });
722
741
  this.constantCallbacks = findConstantCallbacks(mod, this.callLifetimes);
723
742
  this.stackCallbacks = new StackCallbacks(this.fnByName);
724
743
  this.receiverReaders = new AmbientReceiverReaders(this.fnByName);
725
744
  this.stackCaptures = new StackCaptures(this.fnByName, this.callLifetimes, this.stackCallbacks);
726
745
  this.lazyCaptures = new LazyCaptures(this.fnByName);
727
- for (const r of mod.records ?? [])
728
- this.recordsById.set(r.id, r);
729
746
  const traced = computeTraced(mod);
730
747
  this.tracedShapes = traced.shapes;
731
748
  this.tracedUnions = traced.unions;
@@ -735,6 +752,8 @@ export class LlEmitter {
735
752
  tracedShapes: this.tracedShapes,
736
753
  tracedUnions: this.tracedUnions,
737
754
  nullableUnions: this.nullableUnions,
755
+ inlineUnions: this.inlineUnions,
756
+ unionNoneRef: () => this.unionNoneRef(),
738
757
  recordsById: this.recordsById,
739
758
  recordCloneShapes: this.recordCloneShapes,
740
759
  objectAudit: options.objectAudit !== false,
@@ -748,6 +767,8 @@ export class LlEmitter {
748
767
  // paths address its thread-local state.
749
768
  threadLocalAlloc: mod.workers === true,
750
769
  rcHelpers: this.rcHelpers,
770
+ ...(this.rcMode !== undefined ? { rcMode: this.rcMode } : {}),
771
+ ...(this.rcHelpersNoinline ? { rcHelpersNoinline: true } : {}),
751
772
  nextCycKind: () => FIRST_EMITTED_CYC_KIND + this.cycKinds++,
752
773
  unionsById: this.unionsById,
753
774
  declare: (decl) => this.declare(decl),
@@ -763,6 +784,7 @@ export class LlEmitter {
763
784
  liveDynUnionRefAdapter: (type) => this.liveDynUnionRefAdapter(type),
764
785
  dynPromiseAdapter: (type) => this.dynPromiseAdapter(type),
765
786
  isErrorClass: (name) => this.classMeta.get(name)?.root.def.name === "%Error",
787
+ classRootOf: (name) => this.classMeta.get(name)?.root.def.name,
766
788
  classSubtypes: (name) => {
767
789
  const target = this.classMetaOf(name);
768
790
  const intervals = classMembershipIntervals(this.classMeta, target.def.name);
@@ -796,13 +818,16 @@ export class LlEmitter {
796
818
  this.tdzGlobals.set(g.id, g.name);
797
819
  }
798
820
  this.stableGlobals = stableGlobals(mod);
799
- // Runtime error, EventEmitter, and stream classes have known layouts.
800
- // 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.
801
824
  const classes = mod.classes ?? [];
802
825
  for (const cls of classes) {
803
826
  if (cls.runtime &&
804
827
  !RUNTIME_ERROR_CLASSES.has(cls.name) &&
805
828
  cls.name !== RUNTIME_EMITTER_CLASS &&
829
+ cls.name !== RUNTIME_EVENT_TARGET_CLASS &&
830
+ cls.name !== RUNTIME_EVENT_CLASS &&
806
831
  !RUNTIME_STREAM_CLASSES.has(cls.name)) {
807
832
  throw new LlvmUnsupportedError(`classDef:${cls.name}`, cls.loc);
808
833
  }
@@ -1162,7 +1187,7 @@ export class LlEmitter {
1162
1187
  return this.emitParts().join("\n");
1163
1188
  }
1164
1189
  emitParts() {
1165
- const parts = this.emitModuleParts();
1190
+ const parts = limitInlineDynReleases(this.emitModuleParts());
1166
1191
  if (!this.executableTls)
1167
1192
  return parts;
1168
1193
  // A worker executable's thread-locals all live in the executable's own
@@ -1215,7 +1240,7 @@ export class LlEmitter {
1215
1240
  // Module globals, FIRST OCCURRENCE per id: a class-expression static
1216
1241
  // instantiated through several mixin applications registers one global
1217
1242
  // id several times (2041-mixin-values) — C's tentative definitions
1218
- // absorb the duplicates silently, LLVM rejects redefinition, so the
1243
+ // accept the duplicates without an error, LLVM rejects redefinition, so the
1219
1244
  // storage AND the release emit once per id here.
1220
1245
  const seenGlobalIds = new Set();
1221
1246
  const globals = (this.mod.globals ?? []).filter((g) => {
@@ -1451,6 +1476,7 @@ export class LlEmitter {
1451
1476
  // write/abort declarations).
1452
1477
  const helpers = [
1453
1478
  ...this.helperDefs(),
1479
+ ...emitArraySearchHelpers(this.arraySearchKinds, this.sizeType, (line) => this.declare(line)),
1454
1480
  ...emitClassMembershipHelper(this.classMeta, this.sizeType),
1455
1481
  ...(this.publishWalkersCache?.defs() ?? []),
1456
1482
  ...this.publishedClassNamesDefs(),
@@ -1500,17 +1526,22 @@ export class LlEmitter {
1500
1526
  ? []
1501
1527
  : [`%ScrMapRc = type { ${this.sizeType}, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr }`]),
1502
1528
  // The complete ScrMap and its { key, val, hash } entry, read by the
1503
- // inline number-key lookup (sc_map_entry_f64): field 11 is the i64
1504
- // absent-key filter, entries is field 13, the direct index and its
1505
- // length fields 19 and 20.
1506
- ...(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)
1507
1536
  ? [
1508
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} }`,
1509
1538
  ]
1510
1539
  : []),
1511
1540
  // String-keyed reference reads load the value slot of the entry
1512
1541
  // scr_map_entry_str returns (map-number-lookup.ts).
1513
- ...(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)
1514
1545
  ? [`%ScrMapEntry = type { i64, i64, i64 }`]
1515
1546
  : []),
1516
1547
  // The runtime error prefix { rc, vt, name, message, code, cause } and the
@@ -1524,6 +1555,13 @@ export class LlEmitter {
1524
1555
  // The runtime stream layout { rc, vt, reg, cls, st } — one struct
1525
1556
  // for all five stream classes; stream subclasses embed it.
1526
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
+ : []),
1527
1565
  // The catch-binding snapshot box { rc, kind, f64, b, payload,
1528
1566
  // retain_fn, release_fn, trace_fn } — caughtTest kind reads and
1529
1567
  // caughtNarrow payload extraction GEP through it (offsets match
@@ -1636,6 +1674,8 @@ export class LlEmitter {
1636
1674
  }
1637
1675
  if (this.absentInstances.size > 0)
1638
1676
  out.push(``);
1677
+ if (this.needsUnionNone)
1678
+ out.push(`@sc_union_none = internal constant %ScrUnion zeroinitializer ; NULL union dummy read by inline stores`, ``);
1639
1679
  if (this.nullableUnions.usesNullSentinel) {
1640
1680
  // `null` in every `C | null | undefined` union (NULL is undefined):
1641
1681
  // one module-scope immortal object like the ABSENT sentinel.
@@ -2050,7 +2090,7 @@ export class LlEmitter {
2050
2090
  case "i64":
2051
2091
  // Inbound declared-integer edge (ask 4): the helper converts
2052
2092
  // exactly or delivers the host-contract trap (past ±(2^53−1)
2053
- // the value cannot ride f64 without silent rounding).
2093
+ // the value cannot ride f64 without rounding).
2054
2094
  params.push(`i64 %a${i}`);
2055
2095
  body.push(` %c${i} = call double @scr_library_i64_in(i64 %a${i}, ptr @sc_lib_int_trap_${e.symbol})`);
2056
2096
  args.push(`double %c${i}`);
@@ -2158,6 +2198,15 @@ export class LlEmitter {
2158
2198
  ? ` %i = add i64 ${mapIndex.wide}, 0`
2159
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`, `}`, ``);
2160
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
+ }
2161
2210
  // String-key Map/Set lookups test the map's absent-key filter inline
2162
2211
  // (scr_map.c scr_map_filter_bits): a key whose two filter bits are not
2163
2212
  // both set is absent, so most misses on small and medium maps return
@@ -2398,7 +2447,7 @@ export class LlEmitter {
2398
2447
  * programs keep fibers too: their fiber epilogue owns context
2399
2448
  * termination (a stopping worker rejects and observes the promise), which
2400
2449
  * the fiberless wrapper does not reproduce. A missed suspension still
2401
- * 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
2402
2451
  * fiberless body is on its stack. */
2403
2452
  fiberlessAsyncFunctions() {
2404
2453
  const eligible = new Set();
@@ -3050,8 +3099,13 @@ export class LlEmitter {
3050
3099
  * holding the ABSENT state surfaces as the ordinary undefined arm, so
3051
3100
  * absence never travels beyond its slot (a later `{ f: r.f }` is an
3052
3101
  * explicit, present property). */
3053
- loadRecordField(ptr, t) {
3054
- 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);
3055
3109
  if (t.kind !== "union" || undefinedArmTag(t, this.unionsById) < 0)
3056
3110
  return v;
3057
3111
  const absent = this.fieldAbsentTest(v, t.unionId);
@@ -3713,6 +3767,7 @@ export class LlEmitter {
3713
3767
  case "searchParams":
3714
3768
  case "stats":
3715
3769
  case "fileHandle":
3770
+ case "dir":
3716
3771
  case "spawnRes":
3717
3772
  case "child":
3718
3773
  case "childStream":
@@ -3755,7 +3810,7 @@ export class LlEmitter {
3755
3810
  }
3756
3811
  /** Guard for helpers that build or read a union's `%ScrUnion` box
3757
3812
  * directly (library-shaped unions with fixed arms): a nullable union
3758
- * reaching one is an emitter bug, never a silent miscompile. */
3813
+ * reaching one is an emitter bug and throws InternalCompilerError. */
3759
3814
  requireBoxedUnion(unionId) {
3760
3815
  if (this.nullableUnions.has(unionId))
3761
3816
  throw new InternalCompilerError(`llvm emitter bug: nullable union ${unionId} reached a tagged-box helper`);
@@ -3888,7 +3943,7 @@ export class LlEmitter {
3888
3943
  const p = this.B.tmp();
3889
3944
  this.B.line(`${p} = getelementptr inbounds %${classStructSym(className)}, ptr ${objName}, i64 0, i32 ${index}`);
3890
3945
  this.markFieldPointer(p, field);
3891
- return { ptr: p, type };
3946
+ return { ptr: p, type, inline: this.inlineUnions.classField(className, field) };
3892
3947
  }
3893
3948
  /** `o->vt->pre` — the dynamic class's preorder number (borrowed object;
3894
3949
  * the static class names which struct spelling carries the vt word). */
@@ -3939,8 +3994,10 @@ export class LlEmitter {
3939
3994
  if (index < 0)
3940
3995
  throw new InternalCompilerError(`llvm emitter bug: missing union field ${field}`);
3941
3996
  layout = "record:";
3942
- for (let i = 0; i <= index; i++)
3943
- 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
+ }
3944
4001
  }
3945
4002
  const group = groups.get(layout);
3946
4003
  if (group)
@@ -3952,7 +4009,13 @@ export class LlEmitter {
3952
4009
  this.unionFieldReadGroups.set(key, result);
3953
4010
  return result;
3954
4011
  }
3955
- /** 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. */
3956
4019
  recordFieldPtr(objName, shapeId, field) {
3957
4020
  const shape = this.recordShape(shapeId);
3958
4021
  const idx = shape.fields.findIndex((f) => f.name === field);
@@ -3960,7 +4023,8 @@ export class LlEmitter {
3960
4023
  throw new InternalCompilerError(`llvm emitter bug: unknown field ${field} on shape ${shapeId}`);
3961
4024
  const p = this.B.tmp();
3962
4025
  this.B.line(`${p} = getelementptr inbounds %${mangleRecordStruct(shapeId)}, ptr ${objName}, i64 0, i32 ${idx + 1}`);
3963
- 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) };
3964
4028
  }
3965
4029
  /** The overflow map's slot pointer on an index-signature shape. */
3966
4030
  recordOvfPtr(objName, shapeId) {
@@ -3973,10 +4037,16 @@ export class LlEmitter {
3973
4037
  this.B.line(`${v} = load ptr, ptr ${p}`);
3974
4038
  return v;
3975
4039
  }
3976
- /** Loads a record field (i8-stored bools trunc to i1). */
3977
- 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) {
3978
4044
  const B = this.B;
3979
- 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);
3980
4050
  const raw = B.tmp();
3981
4051
  B.line(`${raw} = load ${fieldTy}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
3982
4052
  if (fieldTy !== "i8")
@@ -3985,10 +4055,46 @@ export class LlEmitter {
3985
4055
  B.line(`${b} = trunc i8 ${raw} to i1`);
3986
4056
  return b;
3987
4057
  }
3988
- /** Stores a record field (i1 zext to the i8 storage). */
3989
- 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) {
3990
4091
  const B = this.B;
3991
- 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);
3992
4098
  if (fieldTy !== "i8") {
3993
4099
  B.line(`store ${fieldTy} ${value}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
3994
4100
  return;
@@ -4458,7 +4564,7 @@ export class LlEmitter {
4458
4564
  this.integerArrayBindings.clear();
4459
4565
  this.loopArrayBorrows =
4460
4566
  this.debug === null
4461
- ? findLoopArrayBorrows(fn, this.callLifetimes, this.referenceEffects, this.optionalArrayReads, this.referenceWrites)
4567
+ ? findLoopArrayBorrows(fn, this.callLifetimes, this.referenceEffects, this.optionalArrayReads, this.referenceWrites, this.fnByName)
4462
4568
  : new Set();
4463
4569
  this.localArrayReads = findLocalArrayReads(fn, this.fnByName, this.unionsById, this.referenceEffects.functions, this.callLifetimes, this.optionalArrayReads, this.loopArrayBorrows, this.debug === null ? this.referenceEffects : undefined);
4464
4570
  this.callArrayReads = findCallArrayReads(fn, this.optionalArrayReads, this.referenceEffects.functions, this.callLifetimes, this.debug === null ? this.referenceEffects : undefined);
@@ -4775,6 +4881,15 @@ export class LlEmitter {
4775
4881
  // a call, and an integer index converts to a double and back across it.
4776
4882
  if (fn.name.startsWith("%arr.idxOr."))
4777
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}`;
4778
4893
  const debug = this.debugScope === null ? "" : ` !dbg ${this.debugScope}`;
4779
4894
  const symbol = borrowed ? mangleBorrowedFunction(fn.name) : mangleFunction(fn.name);
4780
4895
  let body = `define internal ${ret} @${symbol}${int32Abi ? INT32_ABI_SUFFIX : ""}(${params.join(", ")}) ${attrs}${debug} { ; ${fn.name}\n${B.render()}\n}`;
@@ -4861,11 +4976,23 @@ export class LlEmitter {
4861
4976
  * exception dummy (tag -1) answers NULL. */
4862
4977
  boxScalarUnion(pair, type) {
4863
4978
  const B = this.B;
4864
- const unionId = type.kind === "union" ? type.unionId : "";
4865
- const arms = this.unionsById.get(unionId).arms;
4866
4979
  const tag = B.tmp(), bits = B.tmp();
4867
4980
  B.line(`${tag} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 0`);
4868
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;
4869
4996
  const join = B.newLabel("union.box.join"), none = B.newLabel("union.box.none");
4870
4997
  const labels = arms.map(() => B.newLabel("union.box.arm"));
4871
4998
  B.terminate(`switch i32 ${tag}, label %${none} [ ${labels.map((label, armTag) => `i32 ${armTag}, label %${label}`).join(" ")} ]`);
@@ -4972,6 +5099,12 @@ export class LlEmitter {
4972
5099
  canBorrowCallArgument(value) {
4973
5100
  if (value.kind === "strLit")
4974
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;
4975
5108
  // Class casts reinterpret the same pointer (prefix layouts).
4976
5109
  if ((value.kind === "upcast" || value.kind === "downcast") &&
4977
5110
  value.value.type.kind === "object")
@@ -5484,6 +5617,24 @@ export class LlEmitter {
5484
5617
  emitBorrowedArrayRead(this, s.init, b.slot);
5485
5618
  break;
5486
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
+ }
5487
5638
  // A stable lexical alias cannot outlive its unchanged local owner.
5488
5639
  // Whole-value uses still retain their own copies, so returning or
5489
5640
  // storing the alias preserves the ordinary heap representation.
@@ -5542,10 +5693,9 @@ export class LlEmitter {
5542
5693
  storeLocalUnion(this, localStorage, s.value);
5543
5694
  break;
5544
5695
  }
5545
- const concat = s.value;
5546
- const suffix = matchStringSelfConcat(s.localId, concat);
5547
- if (suffix && concat.kind === "strConcat") {
5548
- 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);
5549
5699
  break;
5550
5700
  }
5551
5701
  const b = this.binding(s.localId);
@@ -5710,24 +5860,17 @@ export class LlEmitter {
5710
5860
  break;
5711
5861
  }
5712
5862
  const obj = this.emitStableReceiver(s.obj, [s.value]);
5713
- 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));
5714
5866
  if (s.kind === "fieldSet")
5715
5867
  this.emitStoreGuard(obj.name, s);
5716
5868
  else if (this.publishedTypes?.recordGuarded(s.shapeId) === true)
5717
5869
  this.emitPublishedFieldGuard(obj.name, null, s.field);
5718
- const { ptr, type } = s.kind === "fieldSet"
5870
+ const { ptr, type, inline } = s.kind === "fieldSet"
5719
5871
  ? this.classFieldPtr(obj.name, s.className, s.field)
5720
5872
  : this.recordFieldPtr(obj.name, s.shapeId, s.field);
5721
- if (isRefCounted(type)) {
5722
- this.moveTemp(v);
5723
- const old = B.tmp();
5724
- B.line(`${old} = load ptr, ptr ${ptr}`);
5725
- this.storeField(ptr, type, v.name);
5726
- this.releaseValue(old, type);
5727
- }
5728
- else {
5729
- this.storeField(ptr, type, v.name);
5730
- }
5873
+ this.replaceField(ptr, type, inline, v);
5731
5874
  if (s.kind === "fieldSet" &&
5732
5875
  s.field === "name" &&
5733
5876
  this.classMeta.get(s.className)?.root.def.name === "%Error") {
@@ -5828,15 +5971,20 @@ export class LlEmitter {
5828
5971
  const lw = B.newLabel("rks.w");
5829
5972
  B.condBr(pend, join, lw);
5830
5973
  B.startBlock(lw);
5831
- const { ptr, type } = this.recordFieldPtr(obj.name, s.shapeId, f.name);
5832
- 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)) {
5833
5981
  const old = B.tmp();
5834
5982
  B.line(`${old} = load ptr, ptr ${ptr}`);
5835
- this.storeField(ptr, type, nv);
5983
+ this.storeField(ptr, type, nv, false);
5836
5984
  this.releaseValue(old, type);
5837
5985
  }
5838
5986
  else {
5839
- this.storeField(ptr, type, nv);
5987
+ this.storeField(ptr, type, nv, false);
5840
5988
  }
5841
5989
  B.br(join);
5842
5990
  B.startBlock(ln);
@@ -5859,15 +6007,20 @@ export class LlEmitter {
5859
6007
  const ln = B.newLabel("rks.n");
5860
6008
  B.condBr(hit, lh, ln);
5861
6009
  B.startBlock(lh);
5862
- const { ptr, type } = this.recordFieldPtr(obj.name, s.shapeId, f.name);
5863
- 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)) {
5864
6017
  const old = B.tmp();
5865
6018
  B.line(`${old} = load ptr, ptr ${ptr}`);
5866
- this.storeField(ptr, type, v.name);
6019
+ this.storeField(ptr, type, v.name, false);
5867
6020
  this.releaseValue(old, type);
5868
6021
  }
5869
6022
  else {
5870
- this.storeField(ptr, type, v.name);
6023
+ this.storeField(ptr, type, v.name, false);
5871
6024
  }
5872
6025
  B.br(join);
5873
6026
  B.startBlock(ln);
@@ -6528,7 +6681,7 @@ export class LlEmitter {
6528
6681
  break;
6529
6682
  default: {
6530
6683
  // Statement coverage is now total (bytesSet closed the set) —
6531
- // keep the loud refusal for any future IR statement kind.
6684
+ // keep throwing LlvmUnsupportedError for any future IR statement kind.
6532
6685
  const rest = s;
6533
6686
  const k = rest.kind;
6534
6687
  throw new LlvmUnsupportedError(`stmt:${k}`, rest.loc);
@@ -6874,7 +7027,11 @@ export class LlEmitter {
6874
7027
  if (e.kind === "seqExpr" &&
6875
7028
  isRefCounted(e.result.type) &&
6876
7029
  e.result.kind !== "strLit" &&
6877
- 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"))) {
6878
7035
  this.emitSequence(() => {
6879
7036
  for (const s of e.stmts)
6880
7037
  this.emitStmt(s);
@@ -6905,8 +7062,11 @@ export class LlEmitter {
6905
7062
  // of first building the suffix as a separate string.
6906
7063
  const parts = stringParts(suffix);
6907
7064
  const mixed = parts.length > 1 || numberPart(parts[0]) !== null;
7065
+ const charCode = mixed ? null : this.emitSingleCharCode(suffix);
6908
7066
  const inputs = mixed ? emitConcatInputs(this, parts) : [];
6909
- 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];
6910
7070
  const b = this.binding(localId);
6911
7071
  const B = this.B;
6912
7072
  if (b.kind === "boxed") {
@@ -6920,7 +7080,14 @@ export class LlEmitter {
6920
7080
  this.releaseValue(old, b.type);
6921
7081
  }
6922
7082
  let raw;
6923
- 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) {
6924
7091
  raw = emitMixedConcat(this, snapshot.name, inputs);
6925
7092
  }
6926
7093
  else {
@@ -6945,6 +7112,17 @@ export class LlEmitter {
6945
7112
  }
6946
7113
  return result;
6947
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
+ }
6948
7126
  /** `local = local + suffix` when the suffix cannot read or write the
6949
7127
  * local (an unboxed binding is only reachable through this function's own
6950
7128
  * expressions): reading the binding after the suffix gives the value the
@@ -6964,14 +7142,21 @@ export class LlEmitter {
6964
7142
  return null;
6965
7143
  const parts = stringParts(suffix);
6966
7144
  const mixed = parts.length > 1 || numberPart(parts[0]) !== null;
7145
+ const charCode = mixed ? null : this.emitSingleCharCode(suffix);
6967
7146
  const inputs = mixed ? emitConcatInputs(this, parts) : [];
6968
- 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];
6969
7149
  this.materializeSplitLocal(localId);
6970
7150
  const B = this.B;
6971
7151
  const head = B.tmp();
6972
7152
  B.line(`${head} = load ptr, ptr ${b.slot}`);
6973
7153
  let raw;
6974
- 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) {
6975
7160
  raw = emitMixedConcat(this, head, inputs, true);
6976
7161
  }
6977
7162
  else {
@@ -7054,6 +7239,7 @@ export class LlEmitter {
7054
7239
  tracedShapes: this.tracedShapes,
7055
7240
  unionsById: this.unionsById,
7056
7241
  recordsById: this.recordsById,
7242
+ inlineUnions: this.inlineUnions,
7057
7243
  nullableArm: (t) => this.nullableUnions.of(t)?.arm ?? null,
7058
7244
  classInfo: (className) => {
7059
7245
  const meta = this.classMetaOf(className);
@@ -7063,11 +7249,16 @@ export class LlEmitter {
7063
7249
  pre: meta.pre,
7064
7250
  post: meta.post,
7065
7251
  runtimeRooted: meta.root.def.runtime === true,
7066
- fields: meta.def.fields.map((f) => ({
7067
- name: f.name,
7068
- index: classFieldIndex(meta, f.name).index,
7069
- type: this.nullableFields.storageType(className, f.name, f.type),
7070
- })),
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
+ ]),
7071
7262
  };
7072
7263
  },
7073
7264
  classesInInterval: (pre, post) => byPre.filter((m) => m.pre >= pre && m.pre <= post).map((m) => m.def.name),
@@ -7234,6 +7425,8 @@ export class LlEmitter {
7234
7425
  this.B.line(`${value} = load ptr, ptr ${binding.slot}`);
7235
7426
  return { name: value, type: e.type };
7236
7427
  }
7428
+ if (e.kind === "dynCheck" && e.exact)
7429
+ return this.emitExactCapsuleObject(e.value, e.type);
7237
7430
  if (e.kind === "chainRecv") {
7238
7431
  // The chain's bind slot holds its receiver unchanged until the body
7239
7432
  // finishes, owned by the slot itself or by the chain's receiver.
@@ -7294,13 +7487,14 @@ export class LlEmitter {
7294
7487
  if (e.kind === "recordGet" || e.kind === "fieldGet") {
7295
7488
  const receiver = this.emitReadReceiver(e.obj);
7296
7489
  if (e.kind === "recordGet") {
7297
- const { ptr, type } = this.recordFieldPtr(receiver.name, e.shapeId, e.field);
7298
- 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 };
7299
7493
  }
7300
- const { ptr, type } = this.classFieldPtr(receiver.name, e.className, e.field);
7494
+ const { ptr, type, inline } = this.classFieldPtr(receiver.name, e.className, e.field);
7301
7495
  if (this.int32Slots.isField(e.className, e.field))
7302
7496
  return this.loadInt32Field(ptr, e.type);
7303
- return { name: this.loadField(ptr, type), type: e.type };
7497
+ return { name: this.loadField(ptr, type, inline), type: e.type };
7304
7498
  }
7305
7499
  if (e.kind === "ternary" && this.canBorrowReceiver(e.then) && this.canBorrowReceiver(e.else_)) {
7306
7500
  // Checked projections lower to a ternary with an always-throwing
@@ -7364,7 +7558,15 @@ export class LlEmitter {
7364
7558
  matchMapRead(e, this.boxedUnionsById) !== null ||
7365
7559
  this.optionalArrayReads.get(e) !== null ||
7366
7560
  isScalarOptionalSource(e, this.unionSources) ||
7367
- this.scalarResultCall(e));
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);
7368
7570
  }
7369
7571
  /** The nullable-pointer representation behind a union-typed class field
7370
7572
  * read, or null for every other expression. */
@@ -7503,6 +7705,15 @@ export class LlEmitter {
7503
7705
  this.localArrayReads.has(localId) ||
7504
7706
  this.mapReadLifetimes.locals.has(localId));
7505
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
+ }
7506
7717
  canBorrowReceiver(e) {
7507
7718
  switch (e.kind) {
7508
7719
  case "chainRecv":
@@ -7520,9 +7731,11 @@ export class LlEmitter {
7520
7731
  case "downcast":
7521
7732
  case "upcast":
7522
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.
7523
7736
  case "fieldGet":
7524
7737
  case "recordGet":
7525
- return this.canBorrowReceiver(e.obj);
7738
+ return !this.inlineFieldGet(e) && this.canBorrowReceiver(e.obj);
7526
7739
  case "ternary":
7527
7740
  return this.canBorrowReceiver(e.then) && this.canBorrowReceiver(e.else_);
7528
7741
  case "seqExpr": {
@@ -7758,8 +7971,11 @@ export class LlEmitter {
7758
7971
  fsRenameThunkFor(cbT) {
7759
7972
  return fsRenameThunkFor(this, cbT);
7760
7973
  }
7761
- cryptoBytesThunkFor(cbT, arrayBuffer = false) {
7762
- 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);
7763
7979
  }
7764
7980
  zlibBytesThunkFor(cbT) {
7765
7981
  return zlibBytesThunkFor(this, cbT);