@scriptc/compiler 0.3.2 → 0.3.4

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 (454) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +1202 -64
  2. package/dist/backend/cycle-analysis.js +6 -1
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/cycle-mutability.d.ts +5 -0
  5. package/dist/backend/cycle-mutability.js +62 -3
  6. package/dist/backend/cycle-mutability.js.map +1 -1
  7. package/dist/backend/executable-features.js +1 -0
  8. package/dist/backend/executable-features.js.map +1 -1
  9. package/dist/backend/library-pack.js +1 -0
  10. package/dist/backend/library-pack.js.map +1 -1
  11. package/dist/backend/llvm/alloc.js +24 -10
  12. package/dist/backend/llvm/alloc.js.map +1 -1
  13. package/dist/backend/llvm/alloc.test.js +47 -1
  14. package/dist/backend/llvm/alloc.test.js.map +1 -1
  15. package/dist/backend/llvm/array-search.d.ts +8 -0
  16. package/dist/backend/llvm/array-search.js +52 -0
  17. package/dist/backend/llvm/array-search.js.map +1 -0
  18. package/dist/backend/llvm/array-search.test.d.ts +1 -0
  19. package/dist/backend/llvm/array-search.test.js +72 -0
  20. package/dist/backend/llvm/array-search.test.js.map +1 -0
  21. package/dist/backend/llvm/call-lifetimes.d.ts +12 -1
  22. package/dist/backend/llvm/call-lifetimes.js +41 -11
  23. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  24. package/dist/backend/llvm/call-lifetimes.test.js +85 -1
  25. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  26. package/dist/backend/llvm/classes.js +87 -36
  27. package/dist/backend/llvm/classes.js.map +1 -1
  28. package/dist/backend/llvm/common.d.ts +6 -1
  29. package/dist/backend/llvm/common.js +8 -1
  30. package/dist/backend/llvm/common.js.map +1 -1
  31. package/dist/backend/llvm/dense-array-access.d.ts +5 -0
  32. package/dist/backend/llvm/dense-array-access.js +3 -3
  33. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  34. package/dist/backend/llvm/dyn.d.ts +44 -1
  35. package/dist/backend/llvm/dyn.js +251 -36
  36. package/dist/backend/llvm/dyn.js.map +1 -1
  37. package/dist/backend/llvm/emitter.d.ts +77 -14
  38. package/dist/backend/llvm/emitter.js +461 -108
  39. package/dist/backend/llvm/emitter.js.map +1 -1
  40. package/dist/backend/llvm/emitter.test.js +26 -3
  41. package/dist/backend/llvm/emitter.test.js.map +1 -1
  42. package/dist/backend/llvm/expr-async.js +52 -1
  43. package/dist/backend/llvm/expr-async.js.map +1 -1
  44. package/dist/backend/llvm/expr-bytes.d.ts +9 -0
  45. package/dist/backend/llvm/expr-bytes.js +169 -63
  46. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  47. package/dist/backend/llvm/expr-callbacks.js +16 -2
  48. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  49. package/dist/backend/llvm/expr-calls.d.ts +3 -1
  50. package/dist/backend/llvm/expr-calls.js +57 -2
  51. package/dist/backend/llvm/expr-calls.js.map +1 -1
  52. package/dist/backend/llvm/expr-containers.js +57 -19
  53. package/dist/backend/llvm/expr-containers.js.map +1 -1
  54. package/dist/backend/llvm/expr-dynamic.js +19 -8
  55. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  56. package/dist/backend/llvm/expr-primitives.js +28 -30
  57. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  58. package/dist/backend/llvm/expr-records.js +8 -4
  59. package/dist/backend/llvm/expr-records.js.map +1 -1
  60. package/dist/backend/llvm/expr-stream-bridges.js +35 -32
  61. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  62. package/dist/backend/llvm/expr-stream-callbacks.d.ts +13 -2
  63. package/dist/backend/llvm/expr-stream-callbacks.js +80 -5
  64. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  65. package/dist/backend/llvm/inline-unions.d.ts +48 -0
  66. package/dist/backend/llvm/inline-unions.js +134 -0
  67. package/dist/backend/llvm/inline-unions.js.map +1 -0
  68. package/dist/backend/llvm/inline-unions.test.d.ts +1 -0
  69. package/dist/backend/llvm/inline-unions.test.js +124 -0
  70. package/dist/backend/llvm/inline-unions.test.js.map +1 -0
  71. package/dist/backend/llvm/integer-remainder.d.ts +28 -5
  72. package/dist/backend/llvm/integer-remainder.js +80 -9
  73. package/dist/backend/llvm/integer-remainder.js.map +1 -1
  74. package/dist/backend/llvm/intern-tables.test.d.ts +1 -0
  75. package/dist/backend/llvm/intern-tables.test.js +77 -0
  76. package/dist/backend/llvm/intern-tables.test.js.map +1 -0
  77. package/dist/backend/llvm/lib-datagram.js +10 -0
  78. package/dist/backend/llvm/lib-datagram.js.map +1 -1
  79. package/dist/backend/llvm/lib-dispatch.js +255 -29
  80. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  81. package/dist/backend/llvm/lib-filesystem.js +176 -7
  82. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  83. package/dist/backend/llvm/lib-network.js +25 -6
  84. package/dist/backend/llvm/lib-network.js.map +1 -1
  85. package/dist/backend/llvm/lib-process.js +2 -2
  86. package/dist/backend/llvm/lib-process.js.map +1 -1
  87. package/dist/backend/llvm/lib-shared.d.ts +5 -0
  88. package/dist/backend/llvm/lib-shared.js +212 -1
  89. package/dist/backend/llvm/lib-shared.js.map +1 -1
  90. package/dist/backend/llvm/lib-stream.js +184 -0
  91. package/dist/backend/llvm/lib-stream.js.map +1 -1
  92. package/dist/backend/llvm/lib-test.js +9 -0
  93. package/dist/backend/llvm/lib-test.js.map +1 -1
  94. package/dist/backend/llvm/local-array-reads.js +7 -3
  95. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  96. package/dist/backend/llvm/local-array-reads.test.js +6 -3
  97. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  98. package/dist/backend/llvm/local-union-storage.d.ts +2 -0
  99. package/dist/backend/llvm/local-union-storage.js +5 -0
  100. package/dist/backend/llvm/local-union-storage.js.map +1 -1
  101. package/dist/backend/llvm/local-union-storage.test.js +1 -0
  102. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  103. package/dist/backend/llvm/loop-array-borrows.d.ts +8 -2
  104. package/dist/backend/llvm/loop-array-borrows.js +93 -13
  105. package/dist/backend/llvm/loop-array-borrows.js.map +1 -1
  106. package/dist/backend/llvm/map-number-lookup.d.ts +24 -0
  107. package/dist/backend/llvm/map-number-lookup.js +88 -0
  108. package/dist/backend/llvm/map-number-lookup.js.map +1 -1
  109. package/dist/backend/llvm/map-number-lookup.test.d.ts +1 -0
  110. package/dist/backend/llvm/map-number-lookup.test.js +158 -0
  111. package/dist/backend/llvm/map-number-lookup.test.js.map +1 -0
  112. package/dist/backend/llvm/map-read-lifetimes.d.ts +9 -0
  113. package/dist/backend/llvm/map-read-lifetimes.js +90 -1
  114. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  115. package/dist/backend/llvm/map-read-lifetimes.test.js +129 -1
  116. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
  117. package/dist/backend/llvm/publish.d.ts +9 -0
  118. package/dist/backend/llvm/publish.js +25 -4
  119. package/dist/backend/llvm/publish.js.map +1 -1
  120. package/dist/backend/llvm/record-results.d.ts +8 -5
  121. package/dist/backend/llvm/record-results.js +20 -12
  122. package/dist/backend/llvm/record-results.js.map +1 -1
  123. package/dist/backend/llvm/reference-effects.js +13 -0
  124. package/dist/backend/llvm/reference-effects.js.map +1 -1
  125. package/dist/backend/llvm/reference-writes.js +19 -2
  126. package/dist/backend/llvm/reference-writes.js.map +1 -1
  127. package/dist/backend/llvm/regions.d.ts +5 -1
  128. package/dist/backend/llvm/regions.js +24 -10
  129. package/dist/backend/llvm/regions.js.map +1 -1
  130. package/dist/backend/llvm/serialized-ir-emission.test.js +2 -0
  131. package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -1
  132. package/dist/backend/llvm/shapes.d.ts +56 -10
  133. package/dist/backend/llvm/shapes.js +178 -39
  134. package/dist/backend/llvm/shapes.js.map +1 -1
  135. package/dist/backend/llvm/shapes.test.js +61 -3
  136. package/dist/backend/llvm/shapes.test.js.map +1 -1
  137. package/dist/backend/llvm/stack-objects.js +16 -4
  138. package/dist/backend/llvm/stack-objects.js.map +1 -1
  139. package/dist/backend/llvm/stack-objects.test.js +3 -0
  140. package/dist/backend/llvm/stack-objects.test.js.map +1 -1
  141. package/dist/backend/llvm/string-reads.js +2 -2
  142. package/dist/backend/llvm/string-reads.js.map +1 -1
  143. package/dist/backend/llvm/string-slices.js +2 -2
  144. package/dist/backend/llvm/string-slices.js.map +1 -1
  145. package/dist/backend/llvm/walkers.d.ts +11 -0
  146. package/dist/backend/llvm/walkers.js +106 -10
  147. package/dist/backend/llvm/walkers.js.map +1 -1
  148. package/dist/backend/may-throw.js +13 -4
  149. package/dist/backend/may-throw.js.map +1 -1
  150. package/dist/backend/native/contracts.d.ts +5 -2
  151. package/dist/backend/native/executable.js +27 -8
  152. package/dist/backend/native/executable.js.map +1 -1
  153. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  154. package/dist/backend/native/runtime-inputs.js +2 -0
  155. package/dist/backend/native/runtime-inputs.js.map +1 -1
  156. package/dist/backend/native-codegen-core.d.ts +4 -4
  157. package/dist/backend/native-codegen-core.js +4 -6
  158. package/dist/backend/native-codegen-core.js.map +1 -1
  159. package/dist/backend/native-codegen.test.js +7 -8
  160. package/dist/backend/native-codegen.test.js.map +1 -1
  161. package/dist/backend/native-link-info-core.d.ts +3 -0
  162. package/dist/backend/native-link-info-core.js.map +1 -1
  163. package/dist/backend/native-toolchain.test.js +1 -1
  164. package/dist/backend/native-toolchain.test.js.map +1 -1
  165. package/dist/backend/publication.js +3 -1
  166. package/dist/backend/publication.js.map +1 -1
  167. package/dist/backend/runtime-abi.d.ts +2 -2
  168. package/dist/backend/runtime-abi.js +2 -2
  169. package/dist/backend/runtime-pack-targets.test.js +2 -1
  170. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  171. package/dist/backend/runtime-pack.test.js +2 -1
  172. package/dist/backend/runtime-pack.test.js.map +1 -1
  173. package/dist/backend/target-diagnostics.js +11 -1
  174. package/dist/backend/target-diagnostics.js.map +1 -1
  175. package/dist/backend/target-diagnostics.test.js +4 -1
  176. package/dist/backend/target-diagnostics.test.js.map +1 -1
  177. package/dist/backend/warm-cache.js +1 -0
  178. package/dist/backend/warm-cache.js.map +1 -1
  179. package/dist/compat/fetch-profile.js +4 -4
  180. package/dist/compat/fetch-profile.js.map +1 -1
  181. package/dist/contracts/check.js +2 -0
  182. package/dist/contracts/check.js.map +1 -1
  183. package/dist/coverage/report.js +1 -1
  184. package/dist/coverage/report.js.map +1 -1
  185. package/dist/diagnostics/diagnostic.d.ts +6 -5
  186. package/dist/diagnostics/diagnostic.js +7 -6
  187. package/dist/diagnostics/diagnostic.js.map +1 -1
  188. package/dist/executable/executable-cache.d.ts +1 -0
  189. package/dist/executable/executable-cache.js +1 -0
  190. package/dist/executable/executable-cache.js.map +1 -1
  191. package/dist/executable/executable-cache.test.js +1 -0
  192. package/dist/executable/executable-cache.test.js.map +1 -1
  193. package/dist/frontend/builtin-modules.d.ts +1 -1
  194. package/dist/frontend/builtin-modules.js +1 -0
  195. package/dist/frontend/builtin-modules.js.map +1 -1
  196. package/dist/frontend/comptime-node.js +2 -2
  197. package/dist/frontend/comptime-node.js.map +1 -1
  198. package/dist/frontend/experimental-import.d.ts +5 -1
  199. package/dist/frontend/experimental-import.js +28 -3
  200. package/dist/frontend/experimental-import.js.map +1 -1
  201. package/dist/frontend/lowering/assert-instances.d.ts +38 -0
  202. package/dist/frontend/lowering/assert-instances.js +269 -0
  203. package/dist/frontend/lowering/assert-instances.js.map +1 -0
  204. package/dist/frontend/lowering/binding-analysis.d.ts +1 -1
  205. package/dist/frontend/lowering/binding-analysis.js +1 -1
  206. package/dist/frontend/lowering/builtins/arguments.d.ts +4 -0
  207. package/dist/frontend/lowering/builtins/arguments.js +8 -4
  208. package/dist/frontend/lowering/builtins/arguments.js.map +1 -1
  209. package/dist/frontend/lowering/builtins/blob.d.ts +20 -0
  210. package/dist/frontend/lowering/builtins/blob.js +167 -0
  211. package/dist/frontend/lowering/builtins/blob.js.map +1 -0
  212. package/dist/frontend/lowering/builtins/child-process-async.d.ts +2 -2
  213. package/dist/frontend/lowering/builtins/child-process-async.js +2 -2
  214. package/dist/frontend/lowering/builtins/child-process-methods.js +1 -1
  215. package/dist/frontend/lowering/builtins/child-process-methods.js.map +1 -1
  216. package/dist/frontend/lowering/builtins/child-process-sync.js +1 -1
  217. package/dist/frontend/lowering/builtins/child-process-sync.js.map +1 -1
  218. package/dist/frontend/lowering/builtins/compression.d.ts +18 -0
  219. package/dist/frontend/lowering/builtins/compression.js +178 -4
  220. package/dist/frontend/lowering/builtins/compression.js.map +1 -1
  221. package/dist/frontend/lowering/builtins/constants.js +7 -2
  222. package/dist/frontend/lowering/builtins/constants.js.map +1 -1
  223. package/dist/frontend/lowering/builtins/crypto.d.ts +6 -0
  224. package/dist/frontend/lowering/builtins/crypto.js +526 -121
  225. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  226. package/dist/frontend/lowering/builtins/errors.js +23 -0
  227. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  228. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +10 -0
  229. package/dist/frontend/lowering/builtins/filesystem-calls.js +89 -1
  230. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  231. package/dist/frontend/lowering/builtins/filesystem.d.ts +16 -7
  232. package/dist/frontend/lowering/builtins/filesystem.js +97 -15
  233. package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
  234. package/dist/frontend/lowering/builtins/fs-glob.d.ts +23 -0
  235. package/dist/frontend/lowering/builtins/fs-glob.js +224 -0
  236. package/dist/frontend/lowering/builtins/fs-glob.js.map +1 -0
  237. package/dist/frontend/lowering/builtins/key-object.d.ts +13 -0
  238. package/dist/frontend/lowering/builtins/key-object.js +56 -0
  239. package/dist/frontend/lowering/builtins/key-object.js.map +1 -0
  240. package/dist/frontend/lowering/builtins/module-calls.js +44 -11
  241. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  242. package/dist/frontend/lowering/builtins/performance.d.ts +25 -3
  243. package/dist/frontend/lowering/builtins/performance.js +340 -5
  244. package/dist/frontend/lowering/builtins/performance.js.map +1 -1
  245. package/dist/frontend/lowering/builtins/process.d.ts +2 -2
  246. package/dist/frontend/lowering/builtins/process.js +107 -14
  247. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  248. package/dist/frontend/lowering/builtins/properties.d.ts +0 -7
  249. package/dist/frontend/lowering/builtins/properties.js +39 -11
  250. package/dist/frontend/lowering/builtins/properties.js.map +1 -1
  251. package/dist/frontend/lowering/builtins/readline.d.ts +23 -8
  252. package/dist/frontend/lowering/builtins/readline.js +266 -90
  253. package/dist/frontend/lowering/builtins/readline.js.map +1 -1
  254. package/dist/frontend/lowering/builtins/timers.d.ts +3 -0
  255. package/dist/frontend/lowering/builtins/timers.js +109 -23
  256. package/dist/frontend/lowering/builtins/timers.js.map +1 -1
  257. package/dist/frontend/lowering/builtins/url.d.ts +8 -0
  258. package/dist/frontend/lowering/builtins/url.js +36 -0
  259. package/dist/frontend/lowering/builtins/url.js.map +1 -1
  260. package/dist/frontend/lowering/call-arguments.js +1 -1
  261. package/dist/frontend/lowering/call-arguments.js.map +1 -1
  262. package/dist/frontend/lowering/call-signatures.js +26 -2
  263. package/dist/frontend/lowering/call-signatures.js.map +1 -1
  264. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +2 -0
  265. package/dist/frontend/lowering/class-dynamic-dispatch.js +171 -13
  266. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  267. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +1 -0
  268. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  269. package/dist/frontend/lowering/class-protocol-dispatch.d.ts +45 -0
  270. package/dist/frontend/lowering/class-protocol-dispatch.js +516 -0
  271. package/dist/frontend/lowering/class-protocol-dispatch.js.map +1 -0
  272. package/dist/frontend/lowering/coercions/structural-plans.js +2 -1
  273. package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
  274. package/dist/frontend/lowering/coercions/structural.js +3 -3
  275. package/dist/frontend/lowering/coercions/structural.js.map +1 -1
  276. package/dist/frontend/lowering/collation-repertoire.js +6 -5
  277. package/dist/frontend/lowering/collation-repertoire.js.map +1 -1
  278. package/dist/frontend/lowering/containers/array-callbacks.js +4 -7
  279. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  280. package/dist/frontend/lowering/containers/array-methods.d.ts +0 -7
  281. package/dist/frontend/lowering/containers/array-methods.js +43 -2
  282. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  283. package/dist/frontend/lowering/containers/bytes.js +38 -26
  284. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  285. package/dist/frontend/lowering/containers/for-of.d.ts +1 -1
  286. package/dist/frontend/lowering/containers/for-of.js +5 -1
  287. package/dist/frontend/lowering/containers/for-of.js.map +1 -1
  288. package/dist/frontend/lowering/containers/indexed-objects.js +1 -1
  289. package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
  290. package/dist/frontend/lowering/crypto-tables.d.ts +3 -3
  291. package/dist/frontend/lowering/crypto-tables.js +77 -12
  292. package/dist/frontend/lowering/crypto-tables.js.map +1 -1
  293. package/dist/frontend/lowering/expressions/nullish-assignment.js +10 -0
  294. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  295. package/dist/frontend/lowering/expressions/object-literals.js +16 -12
  296. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  297. package/dist/frontend/lowering/generic-functions.d.ts +2 -2
  298. package/dist/frontend/lowering/generic-functions.js +2 -2
  299. package/dist/frontend/lowering/generic-functions.js.map +1 -1
  300. package/dist/frontend/lowering/http2-constants.js +1 -1
  301. package/dist/frontend/lowering/intern-tables.d.ts +13 -0
  302. package/dist/frontend/lowering/intern-tables.js +536 -0
  303. package/dist/frontend/lowering/intern-tables.js.map +1 -0
  304. package/dist/frontend/lowering/lower-array-sort.d.ts +12 -1
  305. package/dist/frontend/lowering/lower-array-sort.js +561 -191
  306. package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
  307. package/dist/frontend/lowering/lower-array-sort.test.js +4 -2
  308. package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -1
  309. package/dist/frontend/lowering/lower-assert.js +702 -63
  310. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  311. package/dist/frontend/lowering/lower-async-iteration.d.ts +6 -3
  312. package/dist/frontend/lowering/lower-async-iteration.js +259 -4
  313. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
  314. package/dist/frontend/lowering/lower-calls.js +118 -12
  315. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  316. package/dist/frontend/lowering/lower-classes.d.ts +11 -2
  317. package/dist/frontend/lowering/lower-classes.js +76 -9
  318. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  319. package/dist/frontend/lowering/lower-comptime.d.ts +1 -1
  320. package/dist/frontend/lowering/lower-comptime.js +4 -4
  321. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  322. package/dist/frontend/lowering/lower-dgram.js +77 -52
  323. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  324. package/dist/frontend/lowering/lower-event-target.d.ts +63 -0
  325. package/dist/frontend/lowering/lower-event-target.js +362 -0
  326. package/dist/frontend/lowering/lower-event-target.js.map +1 -0
  327. package/dist/frontend/lowering/lower-expando.js +2 -2
  328. package/dist/frontend/lowering/lower-exprs.js +124 -22
  329. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  330. package/dist/frontend/lowering/lower-inspect.d.ts +6 -0
  331. package/dist/frontend/lowering/lower-inspect.js +240 -49
  332. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  333. package/dist/frontend/lowering/lower-mixins.js +1 -1
  334. package/dist/frontend/lowering/lower-mock.d.ts +11 -0
  335. package/dist/frontend/lowering/lower-mock.js +504 -0
  336. package/dist/frontend/lowering/lower-mock.js.map +1 -0
  337. package/dist/frontend/lowering/lower-modules.d.ts +1 -1
  338. package/dist/frontend/lowering/lower-modules.js +14 -3
  339. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  340. package/dist/frontend/lowering/lower-namespaces.d.ts +2 -2
  341. package/dist/frontend/lowering/lower-namespaces.js +2 -2
  342. package/dist/frontend/lowering/lower-server.d.ts +3 -0
  343. package/dist/frontend/lowering/lower-server.js +419 -44
  344. package/dist/frontend/lowering/lower-server.js.map +1 -1
  345. package/dist/frontend/lowering/lower-stdlib.d.ts +7 -1
  346. package/dist/frontend/lowering/lower-stdlib.js +10 -3
  347. package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
  348. package/dist/frontend/lowering/lower-stmts.d.ts +2 -2
  349. package/dist/frontend/lowering/lower-stmts.js +69 -14
  350. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  351. package/dist/frontend/lowering/lower-stream.d.ts +10 -6
  352. package/dist/frontend/lowering/lower-stream.js +1020 -49
  353. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  354. package/dist/frontend/lowering/lower-test.js +86 -8
  355. package/dist/frontend/lowering/lower-test.js.map +1 -1
  356. package/dist/frontend/lowering/lower-timers.js +1 -1
  357. package/dist/frontend/lowering/lowerer.d.ts +45 -5
  358. package/dist/frontend/lowering/lowerer.js +317 -48
  359. package/dist/frontend/lowering/lowerer.js.map +1 -1
  360. package/dist/frontend/lowering/native-ffi.js +2 -2
  361. package/dist/frontend/lowering/native-ffi.js.map +1 -1
  362. package/dist/frontend/lowering/pairs-snapshot.d.ts +6 -0
  363. package/dist/frontend/lowering/pairs-snapshot.js +49 -0
  364. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
  365. package/dist/frontend/lowering/runtime-optional-records.d.ts +115 -0
  366. package/dist/frontend/lowering/runtime-optional-records.js +715 -0
  367. package/dist/frontend/lowering/runtime-optional-records.js.map +1 -0
  368. package/dist/frontend/lowering/runtime-optional-records.test.d.ts +1 -0
  369. package/dist/frontend/lowering/runtime-optional-records.test.js +175 -0
  370. package/dist/frontend/lowering/runtime-optional-records.test.js.map +1 -0
  371. package/dist/frontend/lowering/surfaces.d.ts +11 -3
  372. package/dist/frontend/lowering/surfaces.js +334 -37
  373. package/dist/frontend/lowering/surfaces.js.map +1 -1
  374. package/dist/frontend/lowering/zlib-constants.d.ts +1 -0
  375. package/dist/frontend/lowering/zlib-constants.js +181 -0
  376. package/dist/frontend/lowering/zlib-constants.js.map +1 -0
  377. package/dist/frontend/mock-shapes.d.ts +10 -0
  378. package/dist/frontend/mock-shapes.js +76 -0
  379. package/dist/frontend/mock-shapes.js.map +1 -0
  380. package/dist/frontend/module-syntax.d.ts +1 -1
  381. package/dist/frontend/module-syntax.js +1 -1
  382. package/dist/frontend/npm-static-prune.js +1 -1
  383. package/dist/frontend/npm-static-prune.js.map +1 -1
  384. package/dist/frontend/npm-static-rewrite-syntax.js +4 -3
  385. package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -1
  386. package/dist/frontend/pipeline.js +6 -4
  387. package/dist/frontend/pipeline.js.map +1 -1
  388. package/dist/frontend/program.d.ts +3 -3
  389. package/dist/frontend/program.js +25 -18
  390. package/dist/frontend/program.js.map +1 -1
  391. package/dist/frontend/resolve.d.ts +4 -0
  392. package/dist/frontend/resolve.js +15 -1
  393. package/dist/frontend/resolve.js.map +1 -1
  394. package/dist/frontend/ts7/adapter.js +1 -1
  395. package/dist/frontend/ts7/ast-bytes.d.ts +1 -1
  396. package/dist/frontend/ts7/ast-bytes.js +1 -1
  397. package/dist/frontend/ts7/semantic-json.d.ts +1 -1
  398. package/dist/frontend/ts7/semantic-json.js +1 -1
  399. package/dist/frontend/ts7/semantic-json.js.map +1 -1
  400. package/dist/frontend/ts7/world-check.js +1 -1
  401. package/dist/frontend/tsc-codes.js +3 -2
  402. package/dist/frontend/tsc-codes.js.map +1 -1
  403. package/dist/frontend/type-mapper.d.ts +21 -1
  404. package/dist/frontend/type-mapper.js +245 -27
  405. package/dist/frontend/type-mapper.js.map +1 -1
  406. package/dist/index.js +7 -5
  407. package/dist/index.js.map +1 -1
  408. package/dist/ir/analysis.d.ts +12 -6
  409. package/dist/ir/analysis.js +26 -10
  410. package/dist/ir/analysis.js.map +1 -1
  411. package/dist/ir/analysis.test.js +15 -3
  412. package/dist/ir/analysis.test.js.map +1 -1
  413. package/dist/ir/builtin-effects.js +115 -0
  414. package/dist/ir/builtin-effects.js.map +1 -1
  415. package/dist/ir/builtin-signatures.d.ts +1 -1
  416. package/dist/ir/builtin-signatures.js +438 -46
  417. package/dist/ir/builtin-signatures.js.map +1 -1
  418. package/dist/ir/int32-slots.js +1 -0
  419. package/dist/ir/int32-slots.js.map +1 -1
  420. package/dist/ir/ir.d.ts +84 -17
  421. package/dist/ir/ir.js +54 -1
  422. package/dist/ir/ir.js.map +1 -1
  423. package/dist/ir/runtime-features.d.ts +1 -0
  424. package/dist/ir/runtime-features.js +111 -7
  425. package/dist/ir/runtime-features.js.map +1 -1
  426. package/dist/ir/serialize.js +1 -1
  427. package/dist/ir/serialize.js.map +1 -1
  428. package/dist/ir/traverse.js +1 -0
  429. package/dist/ir/traverse.js.map +1 -1
  430. package/dist/ir/validate.js +295 -14
  431. package/dist/ir/validate.js.map +1 -1
  432. package/dist/ir/validate.test.js +60 -0
  433. package/dist/ir/validate.test.js.map +1 -1
  434. package/dist/library/fence-eval.d.ts +1 -1
  435. package/dist/library/fence-eval.js +5 -4
  436. package/dist/library/fence-eval.js.map +1 -1
  437. package/dist/library/ir-policy.js +11 -4
  438. package/dist/library/ir-policy.js.map +1 -1
  439. package/dist/library/library-profile.js +13 -13
  440. package/dist/library/library-profile.js.map +1 -1
  441. package/dist/library/prepare.js +1 -1
  442. package/dist/library/prepare.js.map +1 -1
  443. package/dist/library/sidecar.js +3 -3
  444. package/dist/library/sidecar.js.map +1 -1
  445. package/dist/native/cli.js +1 -0
  446. package/dist/native/cli.js.map +1 -1
  447. package/dist/native/compiler.js +1 -3
  448. package/dist/native/compiler.js.map +1 -1
  449. package/dist/native/prepare.js +4 -2
  450. package/dist/native/prepare.js.map +1 -1
  451. package/dist/native/sanitizer.test.js +1 -0
  452. package/dist/native/sanitizer.test.js.map +1 -1
  453. package/package.json +20 -20
  454. package/surface-manifest.json +1279 -221
@@ -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,25 +42,26 @@ 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";
46
- import { emitStackMapRead, findMapReadLifetimes, matchMapRead, } from "./map-read-lifetimes.js";
49
+ import { emitStackMapRead, findMapReadLifetimes, findReadNumberMapWrites, matchMapRead, } from "./map-read-lifetimes.js";
47
50
  import { emitBorrowedFieldSequence, guardedValue } from "./borrowed-receivers.js";
48
- import { borrowableInputs, emitBorrowedInput } from "./borrowed-inputs.js";
51
+ import { borrowableInputs, emitBorrowedInput, emitBorrowedInputs } from "./borrowed-inputs.js";
49
52
  import { analyzeWalks, findWalkBorrows } from "./walk-borrows.js";
50
53
  import { findReboundParameters } from "./rebound-parameters.js";
51
54
  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";
59
62
  import { LazyCaptures } from "./lazy-captures.js";
60
63
  import { StackCaptures } from "./stack-captures.js";
61
- import { ABSENT_FIELD_PAYLOAD, emitFieldAbsentTest, exactIndexLines, f64Lit, ffiNativeTypeLl, ffiNativeParamLl, ffiNativeReturnLl, llvmCommentText, } from "./common.js";
64
+ import { ABSENT_FIELD_PAYLOAD, emitFieldAbsentTest, exactIndexLines, f64Lit, ffiNativeTypeLl, ffiNativeParamLl, ffiNativeReturnLl, llvmCommentText, sizeToDouble, } from "./common.js";
62
65
  import { ffiExtendsNarrowIntegers } from "../targets.js";
63
66
  import { emitLiteralExpr, emitOperatorExpr, emitStringExpr, emitContainerExpr, emitRecordExpr, } from "./expr-primitives.js";
64
67
  import { emitControlExpr } from "./expr-control.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";
@@ -82,17 +85,17 @@ import { emitNetworkHttpLibCall } from "./lib-network.js";
82
85
  import { emitAssertInspectLibCall, emitIoLibCall, emitGenericLibCall, emitLibCall, } from "./lib-dispatch.js";
83
86
  import { buildClassGraph, classMembershipIntervals, emitClassMembershipHelper, classEnvironmentIndex, classFieldIndex, classStructSym, programLifetimeClass, } from "./classes.js";
84
87
  import { LifetimeRegions, REGION_TYPES } from "./regions.js";
85
- import { LlDyn } from "./dyn.js";
88
+ import { LlDyn, recordDynKeepsIdentity } from "./dyn.js";
86
89
  import { VirtualBorrows } from "./virtual-borrows.js";
87
90
  import { LlvmUnsupportedError } from "./unsupported.js";
88
91
  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();
@@ -347,6 +354,7 @@ export class LlEmitter {
347
354
  checkedNarrows;
348
355
  callArrayReads = new Map();
349
356
  mapReadLifetimes = { locals: new Map(), arguments: new Map() };
357
+ readNumberMapWrites = new Set();
350
358
  callLifetimes;
351
359
  constantCallbacks;
352
360
  currentConstantCallbacks = new Map();
@@ -439,6 +447,8 @@ export class LlEmitter {
439
447
  * typeKey → thunk symbol. */
440
448
  resolveThunks = new Map();
441
449
  resolveThunkDefs = [];
450
+ /** Inline array searches used by the module (array-search.ts). */
451
+ arraySearchKinds = new Set();
442
452
  /** Typed-ref recipe constants by type key (lazy receivers). */
443
453
  typedRefRecipes = new Map();
444
454
  /** ReadableStream.from adapters keep typed arrays by reference and box
@@ -452,6 +462,7 @@ export class LlEmitter {
452
462
  dynPromiseAdapters = new Map();
453
463
  unionsById = new Map();
454
464
  nullableFields;
465
+ inlineUnions;
455
466
  /** Unions whose values are nullable arm pointers (nullable-unions.ts). */
456
467
  nullableUnions;
457
468
  /** The union table without nullable unions: the stack-box analyses. */
@@ -624,7 +635,9 @@ export class LlEmitter {
624
635
  this.emitLibraryIdentity = options.emitLibraryIdentity !== false;
625
636
  this.runtimeAbiMarker = options.runtimeAbiMarker === true;
626
637
  this.detachedExit = options.detachedExit === true;
627
- this.rcHelpers = options.inlineRc === true ? new Set() : null;
638
+ this.rcHelpers = options.inlineRc !== undefined ? new Set() : null;
639
+ this.rcMode = options.inlineRc;
640
+ this.rcHelpersNoinline = options.rcHelpersNoinline === true;
628
641
  // ScrCycHdr.buf sits 4 bytes behind every object on every target.
629
642
  this.cycleBufOffset = CYC_HDR - CYC_BUF;
630
643
  this.ffiCallbackAdapters = allocateFfiCallbackAdapters(mod.ffiImports ?? []);
@@ -662,6 +675,9 @@ export class LlEmitter {
662
675
  this.immortalValues.add("null");
663
676
  this.immortalValues.add(NULLABLE_NULL);
664
677
  this.nullableFields = new NullableRefFields(mod.classes ?? [], this.boxedUnionsById);
678
+ this.inlineUnions = new InlineUnionFields(this.boxedUnionsById, mod.classes ?? []);
679
+ for (const r of mod.records ?? [])
680
+ this.recordsById.set(r.id, r);
665
681
  // Optional array reads also cover nullable unions: emitLocalArrayRead
666
682
  // then yields the (borrowed or owned) element pointer, not a stack box.
667
683
  // Arrays of such a union are read the same way.
@@ -670,6 +686,7 @@ export class LlEmitter {
670
686
  unions: this.boxedUnionsById,
671
687
  receiverUnions: this.unionsById,
672
688
  nullableField: (e) => this.nullableFieldGet(e) !== null,
689
+ inlineField: (e) => this.inlineFieldGet(e),
673
690
  arrayRead: (e) => this.optionalArrayReads.get(e) !== null,
674
691
  scalarCall: (e) => this.scalarResultCall(e),
675
692
  };
@@ -718,14 +735,18 @@ export class LlEmitter {
718
735
  walkParameters.set(fn.name, indexes);
719
736
  }
720
737
  }
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)));
738
+ 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)), {
739
+ record: (shapeId, field) => this.recordFieldInline(shapeId, field),
740
+ classField: (className, field) => this.inlineUnions.classField(className, field),
741
+ }, (shapeId) => {
742
+ const shape = this.recordsById.get(shapeId);
743
+ return shape !== undefined && !recordDynKeepsIdentity(shape);
744
+ });
722
745
  this.constantCallbacks = findConstantCallbacks(mod, this.callLifetimes);
723
746
  this.stackCallbacks = new StackCallbacks(this.fnByName);
724
747
  this.receiverReaders = new AmbientReceiverReaders(this.fnByName);
725
748
  this.stackCaptures = new StackCaptures(this.fnByName, this.callLifetimes, this.stackCallbacks);
726
749
  this.lazyCaptures = new LazyCaptures(this.fnByName);
727
- for (const r of mod.records ?? [])
728
- this.recordsById.set(r.id, r);
729
750
  const traced = computeTraced(mod);
730
751
  this.tracedShapes = traced.shapes;
731
752
  this.tracedUnions = traced.unions;
@@ -735,6 +756,8 @@ export class LlEmitter {
735
756
  tracedShapes: this.tracedShapes,
736
757
  tracedUnions: this.tracedUnions,
737
758
  nullableUnions: this.nullableUnions,
759
+ inlineUnions: this.inlineUnions,
760
+ unionNoneRef: () => this.unionNoneRef(),
738
761
  recordsById: this.recordsById,
739
762
  recordCloneShapes: this.recordCloneShapes,
740
763
  objectAudit: options.objectAudit !== false,
@@ -748,6 +771,8 @@ export class LlEmitter {
748
771
  // paths address its thread-local state.
749
772
  threadLocalAlloc: mod.workers === true,
750
773
  rcHelpers: this.rcHelpers,
774
+ ...(this.rcMode !== undefined ? { rcMode: this.rcMode } : {}),
775
+ ...(this.rcHelpersNoinline ? { rcHelpersNoinline: true } : {}),
751
776
  nextCycKind: () => FIRST_EMITTED_CYC_KIND + this.cycKinds++,
752
777
  unionsById: this.unionsById,
753
778
  declare: (decl) => this.declare(decl),
@@ -763,6 +788,7 @@ export class LlEmitter {
763
788
  liveDynUnionRefAdapter: (type) => this.liveDynUnionRefAdapter(type),
764
789
  dynPromiseAdapter: (type) => this.dynPromiseAdapter(type),
765
790
  isErrorClass: (name) => this.classMeta.get(name)?.root.def.name === "%Error",
791
+ classRootOf: (name) => this.classMeta.get(name)?.root.def.name,
766
792
  classSubtypes: (name) => {
767
793
  const target = this.classMetaOf(name);
768
794
  const intervals = classMembershipIntervals(this.classMeta, target.def.name);
@@ -796,13 +822,16 @@ export class LlEmitter {
796
822
  this.tdzGlobals.set(g.id, g.name);
797
823
  }
798
824
  this.stableGlobals = stableGlobals(mod);
799
- // Runtime error, EventEmitter, and stream classes have known layouts.
800
- // Subclasses embed the ScrEmitter/ScrStream prefixes from classes.ts.
825
+ // Runtime error, EventEmitter, stream, EventTarget and Event classes
826
+ // have known layouts. Subclasses embed the runtime prefixes from
827
+ // classes.ts.
801
828
  const classes = mod.classes ?? [];
802
829
  for (const cls of classes) {
803
830
  if (cls.runtime &&
804
831
  !RUNTIME_ERROR_CLASSES.has(cls.name) &&
805
832
  cls.name !== RUNTIME_EMITTER_CLASS &&
833
+ cls.name !== RUNTIME_EVENT_TARGET_CLASS &&
834
+ cls.name !== RUNTIME_EVENT_CLASS &&
806
835
  !RUNTIME_STREAM_CLASSES.has(cls.name)) {
807
836
  throw new LlvmUnsupportedError(`classDef:${cls.name}`, cls.loc);
808
837
  }
@@ -1162,7 +1191,7 @@ export class LlEmitter {
1162
1191
  return this.emitParts().join("\n");
1163
1192
  }
1164
1193
  emitParts() {
1165
- const parts = this.emitModuleParts();
1194
+ const parts = limitInlineDynReleases(this.emitModuleParts());
1166
1195
  if (!this.executableTls)
1167
1196
  return parts;
1168
1197
  // A worker executable's thread-locals all live in the executable's own
@@ -1215,7 +1244,7 @@ export class LlEmitter {
1215
1244
  // Module globals, FIRST OCCURRENCE per id: a class-expression static
1216
1245
  // instantiated through several mixin applications registers one global
1217
1246
  // id several times (2041-mixin-values) — C's tentative definitions
1218
- // absorb the duplicates silently, LLVM rejects redefinition, so the
1247
+ // accept the duplicates without an error, LLVM rejects redefinition, so the
1219
1248
  // storage AND the release emit once per id here.
1220
1249
  const seenGlobalIds = new Set();
1221
1250
  const globals = (this.mod.globals ?? []).filter((g) => {
@@ -1388,21 +1417,17 @@ export class LlEmitter {
1388
1417
  if (!asyncEntry)
1389
1418
  return [];
1390
1419
  const lines = [];
1420
+ // finish_top_level noted 13 unless the program set process.exitCode.
1421
+ // A failed node:test run outranks either before exit listeners run.
1391
1422
  if (usesNodeTest) {
1392
- lines.push(` %tla_program_exit = call i32 @scr_test_exit_code()`);
1423
+ lines.push(` %tla_program_exit = call i32 @scr_test_exit_code()`, ` %tla_program_exit_zero = icmp eq i32 %tla_program_exit, 0`, ` %tla_hint = call i32 @scr_exit_code_hint_get()`, ` %tla_exit_status = select i1 %tla_program_exit_zero, i32 %tla_hint, i32 %tla_program_exit`, ` call void @scr_exit_code_note(i32 %tla_exit_status)`);
1393
1424
  }
1394
- if (usesNodeTest) {
1395
- lines.push(` %tla_program_exit_zero = icmp eq i32 %tla_program_exit, 0`, ` %tla_exit_status = select i1 %tla_program_exit_zero, i32 %tla_status, i32 %tla_program_exit`);
1396
- }
1397
- const exitStatus = usesNodeTest ? "%tla_exit_status" : "%tla_status";
1398
- // finish_top_level initially notes 13. Replace that hint before exit
1399
- // listeners run when a higher-priority verdict was already selected.
1400
- lines.push(` call void @scr_exit_code_note(i32 ${exitStatus})`);
1401
1425
  for (const line of exitListenerLines("xp"))
1402
1426
  lines.push(line);
1403
1427
  for (const line of topPendingReleases)
1404
1428
  lines.push(line);
1405
- lines.push(` ret i32 ${exitStatus}`);
1429
+ // An exit listener may set process.exitCode again, as in Node.
1430
+ lines.push(` %tla_exit_code = call i32 @scr_exit_code_hint_get()`, ` ret i32 %tla_exit_code`);
1406
1431
  return lines;
1407
1432
  };
1408
1433
  // LIBRARY mode: the runtime entry points the generated library
@@ -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}`);
@@ -2145,9 +2185,13 @@ export class LlEmitter {
2145
2185
  // Number-key Map/Set lookups probe the runtime's direct index inline:
2146
2186
  // while ndense is nonzero every live key is an integer below it, so an
2147
2187
  // in-range integral key reads its slot (entry index + 1, 0 = absent) and
2148
- // any other key is absent. Maps without the index (ndense 0) and every
2149
- // non-integral probe outside the table take the runtime lookup, which
2150
- // keeps the complete SameValueZero semantics.
2188
+ // any other key is absent. Maps without the index (ndense 0) hash the
2189
+ // key in sc_map_entry_f64_hashed, which scans the entries of a small map
2190
+ // or probes a compact bucket table as scr_map_find_f64 does, and calls
2191
+ // the runtime lookup for a wide table. It stays out of line so that the
2192
+ // direct-index path stays small at every call site. Both only read
2193
+ // memory, so LLVM merges lookups of one key when nothing is stored in
2194
+ // between (a has() followed by get(), for example).
2151
2195
  if (this.decls.has(NUMBER_MAP_ENTRY_DECL)) {
2152
2196
  const sz = this.sizeType;
2153
2197
  let mapTmp = 0;
@@ -2156,7 +2200,24 @@ export class LlEmitter {
2156
2200
  // A non-integral key inside the table is as absent as one outside it.
2157
2201
  ...mapIndex.lines.map((line) => ` ${line}`), ` br i1 ${mapIndex.ok}, label %slot, label %outside`, `slot:`, sz === "i64"
2158
2202
  ? ` %i = add i64 ${mapIndex.wide}, 0`
2159
- : ` %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`, `}`, ``);
2203
+ : ` %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:`, ` %hashed = call ptr @sc_map_entry_f64_hashed(ptr %m, double %k)`, ` ret ptr %hashed`, `}`, ``,
2204
+ // Hashing (scr_map_find_f64): the SameValueZero key word, its
2205
+ // scr_key_mix hash (zero remapped to one) and the absent-key filter.
2206
+ `define internal ptr @sc_map_entry_f64_hashed(ptr %m, double %k) noinline ${FN_ATTRS} {`, `entry:`, ` %nan = fcmp uno double %k, %k`, ` %zero = fcmp oeq double %k, 0.0`, ` %kz = select i1 %zero, double 0.0, double %k`, ` %kzb = bitcast double %kz to i64`, ` %kb = select i1 %nan, i64 9221120237041090560, i64 %kzb`, ` %x1s = lshr i64 %kb, 30`, ` %x1 = xor i64 %kb, %x1s`, ` %x2 = mul i64 %x1, -4658895280553007687`, ` %x3s = lshr i64 %x2, 27`, ` %x3 = xor i64 %x2, %x3s`, ` %x4 = mul i64 %x3, -7723592293110705685`, ` %x5s = lshr i64 %x4, 31`, ` %x5 = xor i64 %x4, %x5s`, ` %hz = icmp eq i64 %x5, 0`, ` %h = select i1 %hz, i64 1, i64 %x5`, ` %f1s = lshr i64 %h, 44`, ` %f1a = and i64 %f1s, 63`, ` %f1 = shl i64 1, %f1a`, ` %f2s = lshr i64 %h, 50`, ` %f2a = and i64 %f2s, 63`, ` %f2 = shl i64 1, %f2a`, ` %fb = or i64 %f1, %f2`, ` %fp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 11`, ` %filter = load i64, ptr %fp`, ` %fm = and i64 %filter, %fb`, ` %fin = icmp eq i64 %fm, %fb`, ` br i1 %fin, label %table, label %miss`, `table:`, ` %nbp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 14`, ` %nb = load ${sz}, ptr %nbp`, ` %eps = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 13`, ` %ents = load ptr, ptr %eps`, ` %linear = icmp eq ${sz} %nb, 0`, ` br i1 %linear, label %scan, label %buckets`,
2207
+ // Small maps keep no bucket table: scan the cached entry hashes.
2208
+ `scan:`, ` %nep = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 9`, ` %ne = load ${sz}, ptr %nep`, ` br label %scan.loop`, `scan.loop:`, ` %si = phi ${sz} [ 0, %scan ], [ %si.next, %scan.next ]`, ` %sdone = icmp eq ${sz} %si, %ne`, ` br i1 %sdone, label %miss, label %scan.entry`, `scan.entry:`, ` %se = getelementptr inbounds %ScrMapEntry, ptr %ents, ${sz} %si`, ` %seh = getelementptr inbounds %ScrMapEntry, ptr %se, i32 0, i32 2`, ` %sh = load i64, ptr %seh`, ` %sk = load i64, ptr %se`, ` %shq = icmp eq i64 %sh, %h`, ` %skq = icmp eq i64 %sk, %kb`, ` %sq = and i1 %shq, %skq`, ` br i1 %sq, label %scan.found, label %scan.next`, `scan.found:`, ` ret ptr %se`, `scan.next:`, ` %si.next = add ${sz} %si, 1`, ` br label %scan.loop`,
2209
+ // Compact tables tag each 24-bit entry index (+1) with the hash's
2210
+ // top byte; wider tables take the runtime lookup.
2211
+ `buckets:`, ` %wide = icmp ugt ${sz} %nb, 16777216`, ` br i1 %wide, label %runtime, label %probe`, `probe:`, ` %bp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 15`, ` %bk = load ptr, ptr %bp`, ` %mask = sub ${sz} %nb, 1`, ` %ht = lshr i64 %h, 32`, ` %ht32 = trunc i64 %ht to i32`, ` %tag = and i32 %ht32, -16777216`, sz === "i64" ? ` %hi = add i64 %h, 0` : ` %hi = trunc i64 %h to ${sz}`, ` %i0 = and ${sz} %hi, %mask`, ` br label %probe.loop`, `probe.loop:`, ` %pi = phi ${sz} [ %i0, %probe ], [ %pi.next, %probe.next ]`, ` %bep = getelementptr inbounds i32, ptr %bk, ${sz} %pi`, ` %b = load i32, ptr %bep`, ` %bempty = icmp eq i32 %b, 0`, ` br i1 %bempty, label %miss, label %probe.tag`, `probe.tag:`, ` %bt = and i32 %b, -16777216`, ` %btq = icmp eq i32 %bt, %tag`, ` br i1 %btq, label %probe.entry, label %probe.next`, `probe.entry:`, ` %bix = and i32 %b, 16777215`, ` %bix1 = sub i32 %bix, 1`, sz === "i32" ? ` %bi = add i32 %bix1, 0` : ` %bi = zext i32 %bix1 to ${sz}`, ` %pe = getelementptr inbounds %ScrMapEntry, ptr %ents, ${sz} %bi`, ` %peh = getelementptr inbounds %ScrMapEntry, ptr %pe, i32 0, i32 2`, ` %ph = load i64, ptr %peh`, ` %pk = load i64, ptr %pe`, ` %phq = icmp eq i64 %ph, %h`, ` %pkq = icmp eq i64 %pk, %kb`, ` %pq = and i1 %phq, %pkq`, ` br i1 %pq, label %probe.found, label %probe.next`, `probe.found:`, ` ret ptr %pe`, `probe.next:`, ` %pi.inc = add ${sz} %pi, 1`, ` %pi.next = and ${sz} %pi.inc, %mask`, ` br label %probe.loop`, `miss:`, ` ret ptr null`, `runtime:`, ` %r = call ptr @scr_map_entry_f64(ptr %m, double %k) memory(read) nounwind willreturn`, ` ret ptr %r`, `}`, ``);
2212
+ }
2213
+ // Map/Set iteration steps read the entries array inline: an index is
2214
+ // live when it is below the entry count and its entry's cached hash is
2215
+ // nonzero (a tombstone's is zero), as scr_map_iter_live decides. The
2216
+ // entry count is read again at every step, so entries appended during
2217
+ // the iteration are visited.
2218
+ if (this.decls.has(MAP_ITER_DECL)) {
2219
+ const sz = this.sizeType;
2220
+ 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`, `}`, ``);
2160
2221
  }
2161
2222
  // String-key Map/Set lookups test the map's absent-key filter inline
2162
2223
  // (scr_map.c scr_map_filter_bits): a key whose two filter bits are not
@@ -2398,7 +2459,7 @@ export class LlEmitter {
2398
2459
  * programs keep fibers too: their fiber epilogue owns context
2399
2460
  * termination (a stopping worker rejects and observes the promise), which
2400
2461
  * the fiberless wrapper does not reproduce. A missed suspension still
2401
- * cannot reorder silently: the runtime traps when a context parks while a
2462
+ * cannot reorder execution undetected: the runtime traps when a context parks while a
2402
2463
  * fiberless body is on its stack. */
2403
2464
  fiberlessAsyncFunctions() {
2404
2465
  const eligible = new Set();
@@ -3050,8 +3111,13 @@ export class LlEmitter {
3050
3111
  * holding the ABSENT state surfaces as the ordinary undefined arm, so
3051
3112
  * absence never travels beyond its slot (a later `{ f: r.f }` is an
3052
3113
  * explicit, present property). */
3053
- loadRecordField(ptr, t) {
3054
- const v = this.loadField(ptr, t);
3114
+ loadRecordField(ptr, t, inline) {
3115
+ if (inline) {
3116
+ const { tag, bits } = loadInlineUnion(this.B, ptr);
3117
+ const present = presentBits(this.B, tag, bits, undefinedArmTag(t, this.unionsById));
3118
+ return stackUnionBox(this.B, this.sizeType, tag, present);
3119
+ }
3120
+ const v = this.loadField(ptr, t, false);
3055
3121
  if (t.kind !== "union" || undefinedArmTag(t, this.unionsById) < 0)
3056
3122
  return v;
3057
3123
  const absent = this.fieldAbsentTest(v, t.unionId);
@@ -3550,6 +3616,11 @@ export class LlEmitter {
3550
3616
  this.B.line(`store i32 0, ptr ${slot}`);
3551
3617
  return slot;
3552
3618
  }
3619
+ /** The amortized cancellation poll, emitted on the loop's back edge (the
3620
+ * continue target), after the body. A poll in the header would be a loop
3621
+ * exit ahead of the body; LLVM then cannot rotate the loop, so loads that
3622
+ * the body repeats on every iteration (a typed array's length, for one)
3623
+ * stay in the loop. */
3553
3624
  emitWorkerLoopCheck(slot) {
3554
3625
  if (slot === null)
3555
3626
  return;
@@ -3713,6 +3784,7 @@ export class LlEmitter {
3713
3784
  case "searchParams":
3714
3785
  case "stats":
3715
3786
  case "fileHandle":
3787
+ case "dir":
3716
3788
  case "spawnRes":
3717
3789
  case "child":
3718
3790
  case "childStream":
@@ -3755,7 +3827,7 @@ export class LlEmitter {
3755
3827
  }
3756
3828
  /** Guard for helpers that build or read a union's `%ScrUnion` box
3757
3829
  * directly (library-shaped unions with fixed arms): a nullable union
3758
- * reaching one is an emitter bug, never a silent miscompile. */
3830
+ * reaching one is an emitter bug and throws InternalCompilerError. */
3759
3831
  requireBoxedUnion(unionId) {
3760
3832
  if (this.nullableUnions.has(unionId))
3761
3833
  throw new InternalCompilerError(`llvm emitter bug: nullable union ${unionId} reached a tagged-box helper`);
@@ -3888,7 +3960,7 @@ export class LlEmitter {
3888
3960
  const p = this.B.tmp();
3889
3961
  this.B.line(`${p} = getelementptr inbounds %${classStructSym(className)}, ptr ${objName}, i64 0, i32 ${index}`);
3890
3962
  this.markFieldPointer(p, field);
3891
- return { ptr: p, type };
3963
+ return { ptr: p, type, inline: this.inlineUnions.classField(className, field) };
3892
3964
  }
3893
3965
  /** `o->vt->pre` — the dynamic class's preorder number (borrowed object;
3894
3966
  * the static class names which struct spelling carries the vt word). */
@@ -3939,8 +4011,10 @@ export class LlEmitter {
3939
4011
  if (index < 0)
3940
4012
  throw new InternalCompilerError(`llvm emitter bug: missing union field ${field}`);
3941
4013
  layout = "record:";
3942
- for (let i = 0; i <= index; i++)
3943
- layout += `${llFieldType(shape.fields[i].type)};`;
4014
+ for (let i = 0; i <= index; i++) {
4015
+ const type = shape.fields[i].type;
4016
+ layout += `${llFieldType(type, this.inlineUnions.record(type))};`;
4017
+ }
3944
4018
  }
3945
4019
  const group = groups.get(layout);
3946
4020
  if (group)
@@ -3952,7 +4026,13 @@ export class LlEmitter {
3952
4026
  this.unionFieldReadGroups.set(key, result);
3953
4027
  return result;
3954
4028
  }
3955
- /** The field-slot pointer of a record member (rc header at index 0). */
4029
+ /** The zeroed `%ScrUnion` constant (inline-unions.ts unionBoxBits). */
4030
+ unionNoneRef() {
4031
+ this.needsUnionNone = true;
4032
+ return "@sc_union_none";
4033
+ }
4034
+ /** The field-slot pointer of a record member (rc header at index 0).
4035
+ * `inline`: the slot stores a scalar union's tag and bits. */
3956
4036
  recordFieldPtr(objName, shapeId, field) {
3957
4037
  const shape = this.recordShape(shapeId);
3958
4038
  const idx = shape.fields.findIndex((f) => f.name === field);
@@ -3960,7 +4040,8 @@ export class LlEmitter {
3960
4040
  throw new InternalCompilerError(`llvm emitter bug: unknown field ${field} on shape ${shapeId}`);
3961
4041
  const p = this.B.tmp();
3962
4042
  this.B.line(`${p} = getelementptr inbounds %${mangleRecordStruct(shapeId)}, ptr ${objName}, i64 0, i32 ${idx + 1}`);
3963
- return { ptr: p, type: shape.fields[idx].type };
4043
+ const type = shape.fields[idx].type;
4044
+ return { ptr: p, type, inline: this.inlineUnions.record(type) };
3964
4045
  }
3965
4046
  /** The overflow map's slot pointer on an index-signature shape. */
3966
4047
  recordOvfPtr(objName, shapeId) {
@@ -3973,10 +4054,16 @@ export class LlEmitter {
3973
4054
  this.B.line(`${v} = load ptr, ptr ${p}`);
3974
4055
  return v;
3975
4056
  }
3976
- /** Loads a record field (i8-stored bools trunc to i1). */
3977
- loadField(ptr, t) {
4057
+ /** Loads a record field (i8-stored bools trunc to i1). An inline union
4058
+ * field answers a private stack box with the slot's own bits, ABSENT
4059
+ * included: it may only be borrowed. */
4060
+ loadField(ptr, t, inline) {
3978
4061
  const B = this.B;
3979
- const fieldTy = llFieldType(t);
4062
+ if (inline) {
4063
+ const { tag, bits } = loadInlineUnion(B, ptr);
4064
+ return stackUnionBox(B, this.sizeType, tag, bits);
4065
+ }
4066
+ const fieldTy = llFieldType(t, false);
3980
4067
  const raw = B.tmp();
3981
4068
  B.line(`${raw} = load ${fieldTy}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
3982
4069
  if (fieldTy !== "i8")
@@ -3985,10 +4072,46 @@ export class LlEmitter {
3985
4072
  B.line(`${b} = trunc i8 ${raw} to i1`);
3986
4073
  return b;
3987
4074
  }
3988
- /** Stores a record field (i1 zext to the i8 storage). */
3989
- storeField(ptr, t, value) {
4075
+ /** A record field of this shape stores its scalar union inline. */
4076
+ recordFieldInline(shapeId, field) {
4077
+ const type = this.recordShape(shapeId).fields.find((f) => f.name === field)?.type;
4078
+ return type !== undefined && this.inlineUnions.record(type);
4079
+ }
4080
+ /** The value a field store writes: an inline union slot copies the tag
4081
+ * and bits of a borrowed projection, so no box is built for it. */
4082
+ emitFieldValue(value, inline) {
4083
+ return inline ? this.emitUnionProjection(value) : this.emitExpr(value);
4084
+ }
4085
+ /** Overwrites a field with `v` (from emitFieldValue). A reference moves
4086
+ * in, and the old value is released AFTER the field is overwritten. */
4087
+ replaceField(ptr, type, inline, v) {
4088
+ if (!inline && isRefCounted(type)) {
4089
+ this.moveTemp(v);
4090
+ const old = this.B.tmp();
4091
+ this.B.line(`${old} = load ptr, ptr ${ptr}`);
4092
+ this.storeField(ptr, type, v.name, false);
4093
+ this.releaseValue(old, type);
4094
+ return;
4095
+ }
4096
+ this.storeField(ptr, type, v.name, inline);
4097
+ }
4098
+ /** Stores `v` (from emitFieldValue) into a fresh field slot. */
4099
+ initField(ptr, type, inline, v) {
4100
+ if (!inline && isRefCounted(type))
4101
+ this.moveTemp(v);
4102
+ this.storeField(ptr, type, v.name, inline);
4103
+ }
4104
+ /** Stores a record field (i1 zext to the i8 storage). An inline union
4105
+ * field copies the tag and bits of the union value, which its owner
4106
+ * keeps. */
4107
+ storeField(ptr, t, value, inline) {
3990
4108
  const B = this.B;
3991
- const fieldTy = llFieldType(t);
4109
+ if (inline) {
4110
+ const { tag, bits } = unionBoxBits(B, value, this.unionNoneRef());
4111
+ storeInlineUnion(B, ptr, tag, bits);
4112
+ return;
4113
+ }
4114
+ const fieldTy = llFieldType(t, false);
3992
4115
  if (fieldTy !== "i8") {
3993
4116
  B.line(`store ${fieldTy} ${value}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
3994
4117
  return;
@@ -4458,13 +4581,14 @@ export class LlEmitter {
4458
4581
  this.integerArrayBindings.clear();
4459
4582
  this.loopArrayBorrows =
4460
4583
  this.debug === null
4461
- ? findLoopArrayBorrows(fn, this.callLifetimes, this.referenceEffects, this.optionalArrayReads, this.referenceWrites)
4584
+ ? findLoopArrayBorrows(fn, this.callLifetimes, this.referenceEffects, this.optionalArrayReads, this.referenceWrites, this.fnByName)
4462
4585
  : new Set();
4463
4586
  this.localArrayReads = findLocalArrayReads(fn, this.fnByName, this.unionsById, this.referenceEffects.functions, this.callLifetimes, this.optionalArrayReads, this.loopArrayBorrows, this.debug === null ? this.referenceEffects : undefined);
4464
4587
  this.callArrayReads = findCallArrayReads(fn, this.optionalArrayReads, this.referenceEffects.functions, this.callLifetimes, this.debug === null ? this.referenceEffects : undefined);
4465
4588
  this.scalarStringSlices =
4466
4589
  this.debug === null ? findScalarStringSlices(fn, this.callLifetimes) : new Map();
4467
4590
  this.mapReadLifetimes = findMapReadLifetimes(fn, this.boxedUnionsById, this.callLifetimes);
4591
+ this.readNumberMapWrites = findReadNumberMapWrites(fn);
4468
4592
  this.localStackUnions = findLocalStackUnions(fn, this.callLifetimes, this.boxedUnionsById);
4469
4593
  this.localStackObjects = this.stackObjects
4470
4594
  ? findLocalStackObjects(this, fn, this.callLifetimes)
@@ -4775,6 +4899,15 @@ export class LlEmitter {
4775
4899
  // a call, and an integer index converts to a double and back across it.
4776
4900
  if (fn.name.startsWith("%arr.idxOr."))
4777
4901
  attrs = `inlinehint ${attrs}`;
4902
+ // Interface dispatch is a few key tests and direct calls ahead of the
4903
+ // checked dynamic call. Keeping that fallback out of line leaves the
4904
+ // tests small enough to inline at each call site.
4905
+ if (fn.name.startsWith("%dyn.class.protocol.fallback."))
4906
+ attrs = `noinline ${attrs}`;
4907
+ else if (fn.name.startsWith("%dyn.class.protocol."))
4908
+ attrs = `inlinehint ${attrs}`;
4909
+ if (fn.name.startsWith(RESULT_ENTRY_PREFIX))
4910
+ attrs = `inlinehint ${attrs}`;
4778
4911
  const debug = this.debugScope === null ? "" : ` !dbg ${this.debugScope}`;
4779
4912
  const symbol = borrowed ? mangleBorrowedFunction(fn.name) : mangleFunction(fn.name);
4780
4913
  let body = `define internal ${ret} @${symbol}${int32Abi ? INT32_ABI_SUFFIX : ""}(${params.join(", ")}) ${attrs}${debug} { ; ${fn.name}\n${B.render()}\n}`;
@@ -4861,11 +4994,23 @@ export class LlEmitter {
4861
4994
  * exception dummy (tag -1) answers NULL. */
4862
4995
  boxScalarUnion(pair, type) {
4863
4996
  const B = this.B;
4864
- const unionId = type.kind === "union" ? type.unionId : "";
4865
- const arms = this.unionsById.get(unionId).arms;
4866
4997
  const tag = B.tmp(), bits = B.tmp();
4867
4998
  B.line(`${tag} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 0`);
4868
4999
  B.line(`${bits} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 1`);
5000
+ return this.boxScalarUnionBits(tag, bits, type);
5001
+ }
5002
+ /** A fresh heap box (+1) for an inline union field's value; the ABSENT
5003
+ * state reads as the undefined arm. */
5004
+ inlineFieldUnion(ptr, type) {
5005
+ const { tag, bits } = loadInlineUnion(this.B, ptr);
5006
+ return this.boxScalarUnionBits(tag, bits, type);
5007
+ }
5008
+ /** boxScalarUnion over a separate tag and payload bits. Unit arms answer
5009
+ * their immortal instances whatever the bits. */
5010
+ boxScalarUnionBits(tag, bits, type) {
5011
+ const B = this.B;
5012
+ const unionId = type.kind === "union" ? type.unionId : "";
5013
+ const arms = this.unionsById.get(unionId).arms;
4869
5014
  const join = B.newLabel("union.box.join"), none = B.newLabel("union.box.none");
4870
5015
  const labels = arms.map(() => B.newLabel("union.box.arm"));
4871
5016
  B.terminate(`switch i32 ${tag}, label %${none} [ ${labels.map((label, armTag) => `i32 ${armTag}, label %${label}`).join(" ")} ]`);
@@ -4972,6 +5117,12 @@ export class LlEmitter {
4972
5117
  canBorrowCallArgument(value) {
4973
5118
  if (value.kind === "strLit")
4974
5119
  return true;
5120
+ // An exact capsule owns its instance while the capsule's binding holds it.
5121
+ if (value.kind === "dynCheck" && value.exact)
5122
+ return value.value.kind === "varRef" && this.canBorrowCallArgument(value.value);
5123
+ // An inline union field has no box to lend.
5124
+ if (this.inlineFieldGet(value))
5125
+ return false;
4975
5126
  // Class casts reinterpret the same pointer (prefix layouts).
4976
5127
  if ((value.kind === "upcast" || value.kind === "downcast") &&
4977
5128
  value.value.type.kind === "object")
@@ -5484,6 +5635,24 @@ export class LlEmitter {
5484
5635
  emitBorrowedArrayRead(this, s.init, b.slot);
5485
5636
  break;
5486
5637
  }
5638
+ const holeRead = this.loopArrayBorrows.has(s) ? dynHoleRead(s.init) : null;
5639
+ if (holeRead && s.init.kind === "ternary") {
5640
+ // A hole reads as the immortal undefined value, which needs no owner.
5641
+ const present = this.emitExpr(s.init.cond);
5642
+ const filled = B.newLabel("borrow.hole.filled"), missing = B.newLabel("borrow.hole.missing"), done = B.newLabel("borrow.hole.done");
5643
+ B.condBr(present.name, filled, missing);
5644
+ B.startBlock(filled);
5645
+ emitBorrowedArrayRead(this, holeRead, b.slot);
5646
+ B.br(done);
5647
+ B.startBlock(missing);
5648
+ this.declare("declare ptr @scr_dyn_undefined()");
5649
+ const undef = B.tmp();
5650
+ B.line(`${undef} = call ptr @scr_dyn_undefined()`);
5651
+ B.line(`store ptr ${undef}, ptr ${b.slot}`);
5652
+ B.br(done);
5653
+ B.startBlock(done);
5654
+ break;
5655
+ }
5487
5656
  // A stable lexical alias cannot outlive its unchanged local owner.
5488
5657
  // Whole-value uses still retain their own copies, so returning or
5489
5658
  // storing the alias preserves the ordinary heap representation.
@@ -5542,10 +5711,9 @@ export class LlEmitter {
5542
5711
  storeLocalUnion(this, localStorage, s.value);
5543
5712
  break;
5544
5713
  }
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);
5714
+ const self = matchStringSelfConcat(s.localId, s.value);
5715
+ if (self) {
5716
+ this.emitStringSelfConcatAssign(s.localId, self.left, self.suffix, false);
5549
5717
  break;
5550
5718
  }
5551
5719
  const b = this.binding(s.localId);
@@ -5646,7 +5814,7 @@ export class LlEmitter {
5646
5814
  B.line(`${lenPtr} = getelementptr inbounds %ScrArr, ptr ${arr.name}, i32 0, i32 1`);
5647
5815
  this.markMemoryPointer(lenPtr, "array:header");
5648
5816
  B.line(`${len} = load ${this.sizeType}, ptr ${lenPtr}${this.fieldAliasAttachment(lenPtr)}`);
5649
- B.line(`${lenNumber} = sitofp ${this.sizeType} ${len} to double`);
5817
+ B.line(`${lenNumber} = ${sizeToDouble(this.sizeType)} ${this.sizeType} ${len} to double`);
5650
5818
  B.line(`${same} = fcmp oeq double ${length.name}, ${lenNumber}`);
5651
5819
  B.condBr(same, done, resize);
5652
5820
  B.startBlock(resize);
@@ -5710,24 +5878,17 @@ export class LlEmitter {
5710
5878
  break;
5711
5879
  }
5712
5880
  const obj = this.emitStableReceiver(s.obj, [s.value]);
5713
- const v = this.emitExpr(s.value);
5881
+ const v = this.emitFieldValue(s.value, s.kind === "recordSet"
5882
+ ? this.recordFieldInline(s.shapeId, s.field)
5883
+ : this.inlineUnions.classField(s.className, s.field));
5714
5884
  if (s.kind === "fieldSet")
5715
5885
  this.emitStoreGuard(obj.name, s);
5716
5886
  else if (this.publishedTypes?.recordGuarded(s.shapeId) === true)
5717
5887
  this.emitPublishedFieldGuard(obj.name, null, s.field);
5718
- const { ptr, type } = s.kind === "fieldSet"
5888
+ const { ptr, type, inline } = s.kind === "fieldSet"
5719
5889
  ? this.classFieldPtr(obj.name, s.className, s.field)
5720
5890
  : 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
- }
5891
+ this.replaceField(ptr, type, inline, v);
5731
5892
  if (s.kind === "fieldSet" &&
5732
5893
  s.field === "name" &&
5733
5894
  this.classMeta.get(s.className)?.root.def.name === "%Error") {
@@ -5828,15 +5989,20 @@ export class LlEmitter {
5828
5989
  const lw = B.newLabel("rks.w");
5829
5990
  B.condBr(pend, join, lw);
5830
5991
  B.startBlock(lw);
5831
- const { ptr, type } = this.recordFieldPtr(obj.name, s.shapeId, f.name);
5832
- if (isRefCounted(type)) {
5992
+ const { ptr, type, inline } = this.recordFieldPtr(obj.name, s.shapeId, f.name);
5993
+ if (inline) {
5994
+ // The slot copies the checked value's bits; nv is released below.
5995
+ this.storeField(ptr, type, nv, true);
5996
+ this.releaseValue(nv, type);
5997
+ }
5998
+ else if (isRefCounted(type)) {
5833
5999
  const old = B.tmp();
5834
6000
  B.line(`${old} = load ptr, ptr ${ptr}`);
5835
- this.storeField(ptr, type, nv);
6001
+ this.storeField(ptr, type, nv, false);
5836
6002
  this.releaseValue(old, type);
5837
6003
  }
5838
6004
  else {
5839
- this.storeField(ptr, type, nv);
6005
+ this.storeField(ptr, type, nv, false);
5840
6006
  }
5841
6007
  B.br(join);
5842
6008
  B.startBlock(ln);
@@ -5859,15 +6025,20 @@ export class LlEmitter {
5859
6025
  const ln = B.newLabel("rks.n");
5860
6026
  B.condBr(hit, lh, ln);
5861
6027
  B.startBlock(lh);
5862
- const { ptr, type } = this.recordFieldPtr(obj.name, s.shapeId, f.name);
5863
- if (isRefCounted(type)) {
6028
+ const { ptr, type, inline } = this.recordFieldPtr(obj.name, s.shapeId, f.name);
6029
+ if (inline) {
6030
+ // The write owns the moved-in value; the slot copies its bits.
6031
+ this.storeField(ptr, type, v.name, true);
6032
+ this.releaseValue(v.name, type);
6033
+ }
6034
+ else if (isRefCounted(type)) {
5864
6035
  const old = B.tmp();
5865
6036
  B.line(`${old} = load ptr, ptr ${ptr}`);
5866
- this.storeField(ptr, type, v.name);
6037
+ this.storeField(ptr, type, v.name, false);
5867
6038
  this.releaseValue(old, type);
5868
6039
  }
5869
6040
  else {
5870
- this.storeField(ptr, type, v.name);
6041
+ this.storeField(ptr, type, v.name, false);
5871
6042
  }
5872
6043
  B.br(join);
5873
6044
  B.startBlock(ln);
@@ -5935,15 +6106,15 @@ export class LlEmitter {
5935
6106
  const lc = B.newLabel("loop.c");
5936
6107
  const lb = B.newLabel("loop.b");
5937
6108
  const le = B.newLabel("loop.e");
6109
+ const lp = workerBudget !== null ? B.newLabel("loop.p") : lc;
5938
6110
  B.br(lc);
5939
6111
  B.startBlock(lc);
5940
- this.emitWorkerLoopCheck(workerBudget);
5941
6112
  B.condBr(this.emitCondition(s.cond), lb, le);
5942
6113
  B.startBlock(lb);
5943
6114
  this.jumpTargets.push({
5944
6115
  kind: "loop",
5945
6116
  brkLabel: le,
5946
- contLabel: lc,
6117
+ contLabel: lp,
5947
6118
  labels: s.labels,
5948
6119
  frameDepth: this.frames.length,
5949
6120
  scopeDepth: this.scopes.length,
@@ -5951,7 +6122,12 @@ export class LlEmitter {
5951
6122
  });
5952
6123
  this.emitBlock(s.body);
5953
6124
  this.jumpTargets.pop();
5954
- B.br(lc);
6125
+ B.br(lp);
6126
+ if (lp !== lc) {
6127
+ B.startBlock(lp);
6128
+ this.emitWorkerLoopCheck(workerBudget);
6129
+ B.br(lc);
6130
+ }
5955
6131
  B.startBlock(le);
5956
6132
  break;
5957
6133
  }
@@ -5963,7 +6139,6 @@ export class LlEmitter {
5963
6139
  const le = B.newLabel("loop.e");
5964
6140
  B.br(lb);
5965
6141
  B.startBlock(lb);
5966
- this.emitWorkerLoopCheck(workerBudget);
5967
6142
  this.jumpTargets.push({
5968
6143
  kind: "loop",
5969
6144
  brkLabel: le,
@@ -5977,6 +6152,7 @@ export class LlEmitter {
5977
6152
  this.jumpTargets.pop();
5978
6153
  B.br(lc);
5979
6154
  B.startBlock(lc);
6155
+ this.emitWorkerLoopCheck(workerBudget);
5980
6156
  B.condBr(this.emitCondition(s.cond), lb, le);
5981
6157
  B.startBlock(le);
5982
6158
  break;
@@ -6136,12 +6312,11 @@ export class LlEmitter {
6136
6312
  B.line(`store ptr ${fresh}, ptr ${slot}`);
6137
6313
  }
6138
6314
  };
6139
- const lu = s.update || capturedLets.length > 0 ? B.newLabel("loop.u") : lc;
6140
- freshenBindings();
6141
6315
  const workerBudget = this.workerLoopBudget(s);
6316
+ const lu = s.update || capturedLets.length > 0 || workerBudget !== null ? B.newLabel("loop.u") : lc;
6317
+ freshenBindings();
6142
6318
  B.br(lc);
6143
6319
  B.startBlock(lc);
6144
- this.emitWorkerLoopCheck(workerBudget);
6145
6320
  if (integerLoop && integerSlot) {
6146
6321
  const receiver = this.emitStableReceiver(integerLoop.limitReceiver, []);
6147
6322
  const lenPtr = B.tmp();
@@ -6182,6 +6357,7 @@ export class LlEmitter {
6182
6357
  B.br(lu);
6183
6358
  if (lu !== lc) {
6184
6359
  B.startBlock(lu);
6360
+ this.emitWorkerLoopCheck(workerBudget);
6185
6361
  freshenBindings();
6186
6362
  if (integerLoop && integerSlot) {
6187
6363
  const old = B.tmp();
@@ -6249,7 +6425,6 @@ export class LlEmitter {
6249
6425
  const workerBudget = this.workerLoopBudget(s);
6250
6426
  B.br(lc);
6251
6427
  B.startBlock(lc);
6252
- this.emitWorkerLoopCheck(workerBudget);
6253
6428
  const inBounds = B.tmp();
6254
6429
  let cur;
6255
6430
  if (snapshot && cursor && scratch) {
@@ -6265,7 +6440,7 @@ export class LlEmitter {
6265
6440
  B.line(`${lenPtr} = getelementptr inbounds %ScrArr, ptr ${arr.name}, i32 0, i32 1`);
6266
6441
  this.markMemoryPointer(lenPtr, "array:header");
6267
6442
  B.line(`${rawLen} = load ${this.sizeType}, ptr ${lenPtr}${this.fieldAliasAttachment(lenPtr)}`);
6268
- B.line(`${len} = sitofp ${this.sizeType} ${rawLen} to double`);
6443
+ B.line(`${len} = ${sizeToDouble(this.sizeType)} ${this.sizeType} ${rawLen} to double`);
6269
6444
  B.line(`${inBounds} = fcmp olt double ${i}, ${len}`);
6270
6445
  cur = i;
6271
6446
  }
@@ -6323,6 +6498,7 @@ export class LlEmitter {
6323
6498
  this.jumpTargets.pop();
6324
6499
  B.br(lu);
6325
6500
  B.startBlock(lu);
6501
+ this.emitWorkerLoopCheck(workerBudget);
6326
6502
  if (idxSlot) {
6327
6503
  const i2 = B.tmp(), i3 = B.tmp();
6328
6504
  B.line(`${i2} = load double, ptr ${idxSlot}`);
@@ -6528,7 +6704,7 @@ export class LlEmitter {
6528
6704
  break;
6529
6705
  default: {
6530
6706
  // Statement coverage is now total (bytesSet closed the set) —
6531
- // keep the loud refusal for any future IR statement kind.
6707
+ // keep throwing LlvmUnsupportedError for any future IR statement kind.
6532
6708
  const rest = s;
6533
6709
  const k = rest.kind;
6534
6710
  throw new LlvmUnsupportedError(`stmt:${k}`, rest.loc);
@@ -6874,7 +7050,11 @@ export class LlEmitter {
6874
7050
  if (e.kind === "seqExpr" &&
6875
7051
  isRefCounted(e.result.type) &&
6876
7052
  e.result.kind !== "strLit" &&
6877
- this.discardableRead(e.result)) {
7053
+ (this.discardableRead(e.result) ||
7054
+ // A function-local binding's read has no effect of its own (a
7055
+ // compound assignment's result, say); a module binding's read may
7056
+ // throw before initialization, so it stays.
7057
+ (e.result.kind === "varRef" && this.binding(e.result.localId).kind === "local"))) {
6878
7058
  this.emitSequence(() => {
6879
7059
  for (const s of e.stmts)
6880
7060
  this.emitStmt(s);
@@ -6905,8 +7085,11 @@ export class LlEmitter {
6905
7085
  // of first building the suffix as a separate string.
6906
7086
  const parts = stringParts(suffix);
6907
7087
  const mixed = parts.length > 1 || numberPart(parts[0]) !== null;
7088
+ const charCode = mixed ? null : this.emitSingleCharCode(suffix);
6908
7089
  const inputs = mixed ? emitConcatInputs(this, parts) : [];
6909
- const right = mixed ? null : this.emitExpr(suffix);
7090
+ // The concat only reads the suffix; relinquishing the binding below
7091
+ // runs no code that could rebind a borrowed local.
7092
+ const right = mixed || charCode !== null ? null : emitStringInputs(this, [suffix])[0];
6910
7093
  const b = this.binding(localId);
6911
7094
  const B = this.B;
6912
7095
  if (b.kind === "boxed") {
@@ -6920,7 +7103,14 @@ export class LlEmitter {
6920
7103
  this.releaseValue(old, b.type);
6921
7104
  }
6922
7105
  let raw;
6923
- if (right === null) {
7106
+ if (charCode !== null) {
7107
+ // The snapshot moves into the consuming character append.
7108
+ this.moveTemp(snapshot);
7109
+ this.declare(`declare ptr @scr_str_concat_move_char_code(ptr, double)`);
7110
+ raw = B.tmp();
7111
+ B.line(`${raw} = call ptr @scr_str_concat_move_char_code(ptr ${snapshot.name}, double ${charCode.name})`);
7112
+ }
7113
+ else if (right === null) {
6924
7114
  raw = emitMixedConcat(this, snapshot.name, inputs);
6925
7115
  }
6926
7116
  else {
@@ -6945,6 +7135,17 @@ export class LlEmitter {
6945
7135
  }
6946
7136
  return result;
6947
7137
  }
7138
+ /** The code of a one-argument `String.fromCharCode(c)` suffix, emitted, so
7139
+ * `s += String.fromCharCode(c)` appends the character without building
7140
+ * the one-character string; null for any other suffix. */
7141
+ emitSingleCharCode(suffix) {
7142
+ if (suffix.kind !== "libCall" || suffix.fn !== "string.fromCharCode")
7143
+ return null;
7144
+ const packed = suffix.args[0];
7145
+ if (packed?.kind !== "arrayLit" || packed.elems.length !== 1 || packed.spreads?.length)
7146
+ return null;
7147
+ return this.emitExpr(packed.elems[0]);
7148
+ }
6948
7149
  /** `local = local + suffix` when the suffix cannot read or write the
6949
7150
  * local (an unboxed binding is only reachable through this function's own
6950
7151
  * expressions): reading the binding after the suffix gives the value the
@@ -6964,14 +7165,21 @@ export class LlEmitter {
6964
7165
  return null;
6965
7166
  const parts = stringParts(suffix);
6966
7167
  const mixed = parts.length > 1 || numberPart(parts[0]) !== null;
7168
+ const charCode = mixed ? null : this.emitSingleCharCode(suffix);
6967
7169
  const inputs = mixed ? emitConcatInputs(this, parts) : [];
6968
- const right = mixed ? null : this.emitExpr(suffix);
7170
+ // The concat only reads the suffix, which may stay borrowed.
7171
+ const right = mixed || charCode !== null ? null : emitStringInputs(this, [suffix])[0];
6969
7172
  this.materializeSplitLocal(localId);
6970
7173
  const B = this.B;
6971
7174
  const head = B.tmp();
6972
7175
  B.line(`${head} = load ptr, ptr ${b.slot}`);
6973
7176
  let raw;
6974
- if (right === null) {
7177
+ if (charCode !== null) {
7178
+ this.declare(`declare ptr @scr_str_concat_move_char_code(ptr, double)`);
7179
+ raw = B.tmp();
7180
+ B.line(`${raw} = call ptr @scr_str_concat_move_char_code(ptr ${head}, double ${charCode.name})`);
7181
+ }
7182
+ else if (right === null) {
6975
7183
  raw = emitMixedConcat(this, head, inputs, true);
6976
7184
  }
6977
7185
  else {
@@ -7007,8 +7215,122 @@ export class LlEmitter {
7007
7215
  e.name === "region.leave" ||
7008
7216
  e.name === "region.release")
7009
7217
  return this.emitRegionIntrinsic(e);
7218
+ if (e.name.startsWith("itable."))
7219
+ return this.emitInternTableIntrinsic(e);
7010
7220
  return emitIntrinsicExpr(this, e);
7011
7221
  }
7222
+ /** InternTable's runtime calls (scr_itable.c). Table and entry handles
7223
+ * are f64 values carrying pointer bits; entry values are 64-bit slots
7224
+ * (double bits, a bool, or a pointer to an immortal value) that the
7225
+ * table neither retains nor releases. Lookups and inserts of array keys
7226
+ * throw a TypeError for keys longer than a table accepts. */
7227
+ emitInternTableIntrinsic(e) {
7228
+ const B = this.B;
7229
+ // The runtime copies keys and stores published values without counts,
7230
+ // so every operand is borrowed.
7231
+ const args = emitBorrowedInputs(this, e.args);
7232
+ if (B.isTerminated())
7233
+ return { name: "", type: e.type };
7234
+ const toPtr = (handle) => {
7235
+ const bits = B.tmp(), ptr = B.tmp();
7236
+ B.line(`${bits} = bitcast double ${handle} to i64`);
7237
+ B.line(`${ptr} = inttoptr i64 ${bits} to ptr`);
7238
+ return ptr;
7239
+ };
7240
+ const toHandle = (ptr) => {
7241
+ const bits = B.tmp(), handle = B.tmp();
7242
+ B.line(`${bits} = ptrtoint ptr ${ptr} to i64`);
7243
+ B.line(`${handle} = bitcast i64 ${bits} to double`);
7244
+ return { name: handle, type: e.type };
7245
+ };
7246
+ const keyCall = (op) => {
7247
+ const kind = e.args[1].type.kind;
7248
+ const key = kind === "string" ? "str" : kind === "array" ? "arr" : "f64";
7249
+ const keyTy = key === "f64" ? "double" : "ptr";
7250
+ const value = op === "insert" ? ", i64" : "";
7251
+ this.declare(`declare ptr @scr_itable_${op}_${key}(ptr, ${keyTy}${value})`);
7252
+ return `@scr_itable_${op}_${key}(ptr ${toPtr(args[0].name)}, ${keyTy} ${args[1].name}`;
7253
+ };
7254
+ switch (e.name) {
7255
+ case "itable.open": {
7256
+ this.declare(`declare ptr @scr_itable_open(ptr, i32)`);
7257
+ const kind = B.tmp(), table = B.tmp();
7258
+ B.line(`${kind} = fptosi double ${args[1].name} to i32`);
7259
+ B.line(`${table} = call ptr @scr_itable_open(ptr ${args[0].name}, i32 ${kind})`);
7260
+ return toHandle(table);
7261
+ }
7262
+ case "itable.find": {
7263
+ const call = keyCall("find");
7264
+ const entry = B.tmp();
7265
+ B.line(`${entry} = call ptr ${call})`);
7266
+ // Array keys longer than a table accepts throw a TypeError.
7267
+ if (e.args[1].type.kind === "array")
7268
+ this.emitPendingCheck();
7269
+ return toHandle(entry);
7270
+ }
7271
+ case "itable.insert": {
7272
+ const value = args[2];
7273
+ const ty = this.llType(value.type);
7274
+ let slot = value.name;
7275
+ if (ty === "double") {
7276
+ slot = B.tmp();
7277
+ B.line(`${slot} = bitcast double ${value.name} to i64`);
7278
+ }
7279
+ else if (ty === "i1") {
7280
+ slot = B.tmp();
7281
+ B.line(`${slot} = zext i1 ${value.name} to i64`);
7282
+ }
7283
+ else if (ty === "ptr") {
7284
+ slot = B.tmp();
7285
+ B.line(`${slot} = ptrtoint ptr ${value.name} to i64`);
7286
+ }
7287
+ else
7288
+ throw new InternalCompilerError(`llvm emitter bug: itable value of type ${ty}`);
7289
+ const call = keyCall("insert");
7290
+ const entry = B.tmp();
7291
+ B.line(`${entry} = call ptr ${call}, i64 ${slot})`);
7292
+ if (e.args[1].type.kind === "array")
7293
+ this.emitPendingCheck();
7294
+ return toHandle(entry);
7295
+ }
7296
+ case "itable.value": {
7297
+ // The handle's bits reach the address through memory: at -O0, x86
7298
+ // FastISel folds inttoptr(bitcast double) into the load's address
7299
+ // without moving the value out of its XMM register. Optimized
7300
+ // builds turn the stack round trip back into one register move.
7301
+ const carrier = B.slot();
7302
+ B.entryAllocas.push(`${carrier} = alloca double`);
7303
+ B.line(`store double ${args[0].name}, ptr ${carrier}`);
7304
+ const bits = B.tmp(), entry = B.tmp();
7305
+ B.line(`${bits} = load i64, ptr ${carrier}`);
7306
+ B.line(`${entry} = inttoptr i64 ${bits} to ptr`);
7307
+ const slot = B.tmp();
7308
+ B.line(`${slot} = load i64, ptr ${entry}, align 8`);
7309
+ const ty = this.llType(e.type);
7310
+ const result = B.tmp();
7311
+ if (ty === "double")
7312
+ B.line(`${result} = bitcast i64 ${slot} to double`);
7313
+ else if (ty === "i1")
7314
+ B.line(`${result} = trunc i64 ${slot} to i1`);
7315
+ else if (ty === "ptr")
7316
+ B.line(`${result} = inttoptr i64 ${slot} to ptr`);
7317
+ else
7318
+ throw new InternalCompilerError(`llvm emitter bug: itable value of type ${ty}`);
7319
+ // Stored values are immortal: owning one adds no count.
7320
+ return isRefCounted(e.type)
7321
+ ? this.own({ name: result, type: e.type })
7322
+ : { name: result, type: e.type };
7323
+ }
7324
+ case "itable.size": {
7325
+ this.declare(`declare double @scr_itable_size(ptr)`);
7326
+ const size = B.tmp();
7327
+ B.line(`${size} = call double @scr_itable_size(ptr ${toPtr(args[0].name)})`);
7328
+ return { name: size, type: e.type };
7329
+ }
7330
+ default:
7331
+ throw new InternalCompilerError(`llvm emitter bug: unknown intrinsic ${e.name}`);
7332
+ }
7333
+ }
7012
7334
  /** Lifetime regions in modules with lifetimeRegions (llvm/regions.ts).
7013
7335
  * Created with the class graph; null elsewhere. */
7014
7336
  regions = null;
@@ -7054,6 +7376,7 @@ export class LlEmitter {
7054
7376
  tracedShapes: this.tracedShapes,
7055
7377
  unionsById: this.unionsById,
7056
7378
  recordsById: this.recordsById,
7379
+ inlineUnions: this.inlineUnions,
7057
7380
  nullableArm: (t) => this.nullableUnions.of(t)?.arm ?? null,
7058
7381
  classInfo: (className) => {
7059
7382
  const meta = this.classMetaOf(className);
@@ -7063,11 +7386,16 @@ export class LlEmitter {
7063
7386
  pre: meta.pre,
7064
7387
  post: meta.post,
7065
7388
  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
- })),
7389
+ // Inline scalar-union fields are plain bits: nothing to push.
7390
+ fields: meta.def.fields.flatMap((f) => this.inlineUnions.classField(className, f.name)
7391
+ ? []
7392
+ : [
7393
+ {
7394
+ name: f.name,
7395
+ index: classFieldIndex(meta, f.name).index,
7396
+ type: this.nullableFields.storageType(className, f.name, f.type),
7397
+ },
7398
+ ]),
7071
7399
  };
7072
7400
  },
7073
7401
  classesInInterval: (pre, post) => byPre.filter((m) => m.pre >= pre && m.pre <= post).map((m) => m.def.name),
@@ -7234,6 +7562,8 @@ export class LlEmitter {
7234
7562
  this.B.line(`${value} = load ptr, ptr ${binding.slot}`);
7235
7563
  return { name: value, type: e.type };
7236
7564
  }
7565
+ if (e.kind === "dynCheck" && e.exact)
7566
+ return this.emitExactCapsuleObject(e.value, e.type);
7237
7567
  if (e.kind === "chainRecv") {
7238
7568
  // The chain's bind slot holds its receiver unchanged until the body
7239
7569
  // finishes, owned by the slot itself or by the chain's receiver.
@@ -7294,13 +7624,14 @@ export class LlEmitter {
7294
7624
  if (e.kind === "recordGet" || e.kind === "fieldGet") {
7295
7625
  const receiver = this.emitReadReceiver(e.obj);
7296
7626
  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 };
7627
+ // An inline union field answers a private stack box.
7628
+ const { ptr, type, inline } = this.recordFieldPtr(receiver.name, e.shapeId, e.field);
7629
+ return { name: this.loadRecordField(ptr, type, inline), type: e.type };
7299
7630
  }
7300
- const { ptr, type } = this.classFieldPtr(receiver.name, e.className, e.field);
7631
+ const { ptr, type, inline } = this.classFieldPtr(receiver.name, e.className, e.field);
7301
7632
  if (this.int32Slots.isField(e.className, e.field))
7302
7633
  return this.loadInt32Field(ptr, e.type);
7303
- return { name: this.loadField(ptr, type), type: e.type };
7634
+ return { name: this.loadField(ptr, type, inline), type: e.type };
7304
7635
  }
7305
7636
  if (e.kind === "ternary" && this.canBorrowReceiver(e.then) && this.canBorrowReceiver(e.else_)) {
7306
7637
  // Checked projections lower to a ternary with an always-throwing
@@ -7364,7 +7695,15 @@ export class LlEmitter {
7364
7695
  matchMapRead(e, this.boxedUnionsById) !== null ||
7365
7696
  this.optionalArrayReads.get(e) !== null ||
7366
7697
  isScalarOptionalSource(e, this.unionSources) ||
7367
- this.scalarResultCall(e));
7698
+ this.scalarResultCall(e) ||
7699
+ this.inlineFieldGet(e));
7700
+ }
7701
+ /** A read of a record or class field that stores its scalar union
7702
+ * inline. */
7703
+ inlineFieldGet(e) {
7704
+ if (e.kind === "recordGet")
7705
+ return this.recordFieldInline(e.shapeId, e.field);
7706
+ return e.kind === "fieldGet" && this.inlineUnions.classField(e.className, e.field);
7368
7707
  }
7369
7708
  /** The nullable-pointer representation behind a union-typed class field
7370
7709
  * read, or null for every other expression. */
@@ -7503,6 +7842,15 @@ export class LlEmitter {
7503
7842
  this.localArrayReads.has(localId) ||
7504
7843
  this.mapReadLifetimes.locals.has(localId));
7505
7844
  }
7845
+ /** The instance of a capsule known to hold exactly this class (borrowed). */
7846
+ emitExactCapsuleObject(value, type) {
7847
+ const capsule = this.emitReadReceiver(value);
7848
+ const slot = this.B.tmp();
7849
+ const object = this.B.tmp();
7850
+ this.B.line(`${slot} = getelementptr inbounds i8, ptr ${capsule.name}, i64 16 ; ->v.typed_ref.ptr`);
7851
+ this.B.line(`${object} = load ptr, ptr ${slot}`);
7852
+ return { name: object, type };
7853
+ }
7506
7854
  canBorrowReceiver(e) {
7507
7855
  switch (e.kind) {
7508
7856
  case "chainRecv":
@@ -7520,9 +7868,11 @@ export class LlEmitter {
7520
7868
  case "downcast":
7521
7869
  case "upcast":
7522
7870
  return this.canBorrowReceiver(e.value);
7871
+ // An inline union field has no box to lend: projections read it
7872
+ // through emitReadReceiver's private stack box.
7523
7873
  case "fieldGet":
7524
7874
  case "recordGet":
7525
- return this.canBorrowReceiver(e.obj);
7875
+ return !this.inlineFieldGet(e) && this.canBorrowReceiver(e.obj);
7526
7876
  case "ternary":
7527
7877
  return this.canBorrowReceiver(e.then) && this.canBorrowReceiver(e.else_);
7528
7878
  case "seqExpr": {
@@ -7758,8 +8108,11 @@ export class LlEmitter {
7758
8108
  fsRenameThunkFor(cbT) {
7759
8109
  return fsRenameThunkFor(this, cbT);
7760
8110
  }
7761
- cryptoBytesThunkFor(cbT, arrayBuffer = false) {
7762
- return cryptoBytesThunkFor(this, cbT, arrayBuffer);
8111
+ cryptoBytesThunkFor(cbT, arrayBuffer = false, valueMode = "buffer") {
8112
+ return cryptoBytesThunkFor(this, cbT, arrayBuffer, valueMode);
8113
+ }
8114
+ cryptoIntThunkFor(cbT) {
8115
+ return cryptoIntThunkFor(this, cbT);
7763
8116
  }
7764
8117
  zlibBytesThunkFor(cbT) {
7765
8118
  return zlibBytesThunkFor(this, cbT);