@scriptc/compiler 0.3.3 → 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 (213) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +713 -26
  2. package/dist/backend/cycle-mutability.d.ts +5 -0
  3. package/dist/backend/cycle-mutability.js +62 -3
  4. package/dist/backend/cycle-mutability.js.map +1 -1
  5. package/dist/backend/executable-features.js +1 -0
  6. package/dist/backend/executable-features.js.map +1 -1
  7. package/dist/backend/library-pack.js +1 -0
  8. package/dist/backend/library-pack.js.map +1 -1
  9. package/dist/backend/llvm/call-lifetimes.d.ts +5 -1
  10. package/dist/backend/llvm/call-lifetimes.js +11 -3
  11. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  12. package/dist/backend/llvm/call-lifetimes.test.js +31 -1
  13. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  14. package/dist/backend/llvm/common.d.ts +5 -0
  15. package/dist/backend/llvm/common.js +7 -0
  16. package/dist/backend/llvm/common.js.map +1 -1
  17. package/dist/backend/llvm/dense-array-access.js +2 -2
  18. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  19. package/dist/backend/llvm/dyn.d.ts +40 -1
  20. package/dist/backend/llvm/dyn.js +178 -27
  21. package/dist/backend/llvm/dyn.js.map +1 -1
  22. package/dist/backend/llvm/emitter.d.ts +12 -0
  23. package/dist/backend/llvm/emitter.js +164 -27
  24. package/dist/backend/llvm/emitter.js.map +1 -1
  25. package/dist/backend/llvm/expr-bytes.d.ts +9 -0
  26. package/dist/backend/llvm/expr-bytes.js +158 -63
  27. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  28. package/dist/backend/llvm/expr-calls.d.ts +3 -1
  29. package/dist/backend/llvm/expr-calls.js +49 -1
  30. package/dist/backend/llvm/expr-calls.js.map +1 -1
  31. package/dist/backend/llvm/expr-containers.js +16 -5
  32. package/dist/backend/llvm/expr-containers.js.map +1 -1
  33. package/dist/backend/llvm/intern-tables.test.d.ts +1 -0
  34. package/dist/backend/llvm/intern-tables.test.js +77 -0
  35. package/dist/backend/llvm/intern-tables.test.js.map +1 -0
  36. package/dist/backend/llvm/lib-datagram.js +10 -0
  37. package/dist/backend/llvm/lib-datagram.js.map +1 -1
  38. package/dist/backend/llvm/lib-dispatch.js +92 -1
  39. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  40. package/dist/backend/llvm/lib-filesystem.js +51 -0
  41. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  42. package/dist/backend/llvm/lib-network.js +16 -0
  43. package/dist/backend/llvm/lib-network.js.map +1 -1
  44. package/dist/backend/llvm/lib-shared.d.ts +5 -0
  45. package/dist/backend/llvm/lib-shared.js +80 -1
  46. package/dist/backend/llvm/lib-shared.js.map +1 -1
  47. package/dist/backend/llvm/lib-stream.js +87 -0
  48. package/dist/backend/llvm/lib-stream.js.map +1 -1
  49. package/dist/backend/llvm/lib-test.js +9 -0
  50. package/dist/backend/llvm/lib-test.js.map +1 -1
  51. package/dist/backend/llvm/map-number-lookup.d.ts +4 -0
  52. package/dist/backend/llvm/map-number-lookup.js +22 -0
  53. package/dist/backend/llvm/map-number-lookup.js.map +1 -1
  54. package/dist/backend/llvm/map-number-lookup.test.js +56 -0
  55. package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
  56. package/dist/backend/llvm/map-read-lifetimes.d.ts +9 -0
  57. package/dist/backend/llvm/map-read-lifetimes.js +89 -1
  58. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  59. package/dist/backend/llvm/map-read-lifetimes.test.js +129 -1
  60. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
  61. package/dist/backend/llvm/publish.d.ts +5 -0
  62. package/dist/backend/llvm/publish.js +22 -3
  63. package/dist/backend/llvm/publish.js.map +1 -1
  64. package/dist/backend/llvm/reference-writes.js +5 -2
  65. package/dist/backend/llvm/reference-writes.js.map +1 -1
  66. package/dist/backend/llvm/regions.d.ts +4 -1
  67. package/dist/backend/llvm/regions.js +12 -3
  68. package/dist/backend/llvm/regions.js.map +1 -1
  69. package/dist/backend/llvm/string-reads.js +2 -2
  70. package/dist/backend/llvm/string-reads.js.map +1 -1
  71. package/dist/backend/llvm/string-slices.js +2 -2
  72. package/dist/backend/llvm/string-slices.js.map +1 -1
  73. package/dist/backend/may-throw.js +4 -0
  74. package/dist/backend/may-throw.js.map +1 -1
  75. package/dist/backend/native/contracts.d.ts +3 -0
  76. package/dist/backend/native/executable.js +13 -5
  77. package/dist/backend/native/executable.js.map +1 -1
  78. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  79. package/dist/backend/native/runtime-inputs.js +1 -0
  80. package/dist/backend/native/runtime-inputs.js.map +1 -1
  81. package/dist/backend/native-codegen-core.d.ts +4 -4
  82. package/dist/backend/native-codegen-core.js +4 -6
  83. package/dist/backend/native-codegen-core.js.map +1 -1
  84. package/dist/backend/native-codegen.test.js +7 -8
  85. package/dist/backend/native-codegen.test.js.map +1 -1
  86. package/dist/backend/native-link-info-core.d.ts +3 -0
  87. package/dist/backend/native-link-info-core.js.map +1 -1
  88. package/dist/backend/publication.js +3 -1
  89. package/dist/backend/publication.js.map +1 -1
  90. package/dist/backend/runtime-pack-targets.test.js +1 -0
  91. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  92. package/dist/backend/runtime-pack.test.js +1 -0
  93. package/dist/backend/runtime-pack.test.js.map +1 -1
  94. package/dist/backend/target-diagnostics.js +7 -0
  95. package/dist/backend/target-diagnostics.js.map +1 -1
  96. package/dist/backend/warm-cache.js +1 -0
  97. package/dist/backend/warm-cache.js.map +1 -1
  98. package/dist/executable/executable-cache.d.ts +1 -0
  99. package/dist/executable/executable-cache.js +1 -0
  100. package/dist/executable/executable-cache.js.map +1 -1
  101. package/dist/executable/executable-cache.test.js +1 -0
  102. package/dist/executable/executable-cache.test.js.map +1 -1
  103. package/dist/frontend/experimental-import.d.ts +5 -1
  104. package/dist/frontend/experimental-import.js +28 -3
  105. package/dist/frontend/experimental-import.js.map +1 -1
  106. package/dist/frontend/lowering/assert-instances.d.ts +38 -0
  107. package/dist/frontend/lowering/assert-instances.js +269 -0
  108. package/dist/frontend/lowering/assert-instances.js.map +1 -0
  109. package/dist/frontend/lowering/builtins/compression.d.ts +18 -0
  110. package/dist/frontend/lowering/builtins/compression.js +175 -2
  111. package/dist/frontend/lowering/builtins/compression.js.map +1 -1
  112. package/dist/frontend/lowering/builtins/constants.js +7 -2
  113. package/dist/frontend/lowering/builtins/constants.js.map +1 -1
  114. package/dist/frontend/lowering/builtins/crypto.d.ts +6 -0
  115. package/dist/frontend/lowering/builtins/crypto.js +111 -1
  116. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  117. package/dist/frontend/lowering/builtins/errors.js +23 -0
  118. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  119. package/dist/frontend/lowering/builtins/timers.d.ts +3 -0
  120. package/dist/frontend/lowering/builtins/timers.js +109 -23
  121. package/dist/frontend/lowering/builtins/timers.js.map +1 -1
  122. package/dist/frontend/lowering/call-signatures.js +6 -0
  123. package/dist/frontend/lowering/call-signatures.js.map +1 -1
  124. package/dist/frontend/lowering/class-dynamic-dispatch.js +66 -12
  125. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  126. package/dist/frontend/lowering/intern-tables.d.ts +13 -0
  127. package/dist/frontend/lowering/intern-tables.js +536 -0
  128. package/dist/frontend/lowering/intern-tables.js.map +1 -0
  129. package/dist/frontend/lowering/lower-assert.js +700 -61
  130. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  131. package/dist/frontend/lowering/lower-async-iteration.js +11 -2
  132. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
  133. package/dist/frontend/lowering/lower-calls.js +17 -3
  134. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  135. package/dist/frontend/lowering/lower-classes.d.ts +3 -0
  136. package/dist/frontend/lowering/lower-classes.js +36 -0
  137. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  138. package/dist/frontend/lowering/lower-dgram.js +77 -52
  139. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  140. package/dist/frontend/lowering/lower-exprs.js +12 -0
  141. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  142. package/dist/frontend/lowering/lower-inspect.d.ts +6 -0
  143. package/dist/frontend/lowering/lower-inspect.js +112 -39
  144. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  145. package/dist/frontend/lowering/lower-mock.d.ts +11 -0
  146. package/dist/frontend/lowering/lower-mock.js +504 -0
  147. package/dist/frontend/lowering/lower-mock.js.map +1 -0
  148. package/dist/frontend/lowering/lower-modules.js +7 -0
  149. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  150. package/dist/frontend/lowering/lower-server.d.ts +3 -0
  151. package/dist/frontend/lowering/lower-server.js +380 -30
  152. package/dist/frontend/lowering/lower-server.js.map +1 -1
  153. package/dist/frontend/lowering/lower-stmts.js +23 -2
  154. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  155. package/dist/frontend/lowering/lower-stream.d.ts +10 -6
  156. package/dist/frontend/lowering/lower-stream.js +786 -27
  157. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  158. package/dist/frontend/lowering/lower-test.js +86 -8
  159. package/dist/frontend/lowering/lower-test.js.map +1 -1
  160. package/dist/frontend/lowering/lowerer.d.ts +22 -0
  161. package/dist/frontend/lowering/lowerer.js +72 -7
  162. package/dist/frontend/lowering/lowerer.js.map +1 -1
  163. package/dist/frontend/lowering/pairs-snapshot.d.ts +6 -0
  164. package/dist/frontend/lowering/pairs-snapshot.js +49 -0
  165. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
  166. package/dist/frontend/lowering/surfaces.d.ts +4 -0
  167. package/dist/frontend/lowering/surfaces.js +61 -15
  168. package/dist/frontend/lowering/surfaces.js.map +1 -1
  169. package/dist/frontend/lowering/zlib-constants.d.ts +1 -0
  170. package/dist/frontend/lowering/zlib-constants.js +181 -0
  171. package/dist/frontend/lowering/zlib-constants.js.map +1 -0
  172. package/dist/frontend/mock-shapes.d.ts +10 -0
  173. package/dist/frontend/mock-shapes.js +76 -0
  174. package/dist/frontend/mock-shapes.js.map +1 -0
  175. package/dist/frontend/pipeline.js +5 -3
  176. package/dist/frontend/pipeline.js.map +1 -1
  177. package/dist/frontend/program.js +6 -1
  178. package/dist/frontend/program.js.map +1 -1
  179. package/dist/frontend/resolve.d.ts +4 -0
  180. package/dist/frontend/resolve.js +14 -0
  181. package/dist/frontend/resolve.js.map +1 -1
  182. package/dist/frontend/tsc-codes.js +1 -0
  183. package/dist/frontend/tsc-codes.js.map +1 -1
  184. package/dist/frontend/type-mapper.d.ts +5 -0
  185. package/dist/frontend/type-mapper.js +102 -9
  186. package/dist/frontend/type-mapper.js.map +1 -1
  187. package/dist/index.js +2 -1
  188. package/dist/index.js.map +1 -1
  189. package/dist/ir/builtin-effects.js +36 -0
  190. package/dist/ir/builtin-effects.js.map +1 -1
  191. package/dist/ir/builtin-signatures.d.ts +1 -1
  192. package/dist/ir/builtin-signatures.js +147 -8
  193. package/dist/ir/builtin-signatures.js.map +1 -1
  194. package/dist/ir/ir.d.ts +20 -1
  195. package/dist/ir/ir.js +17 -0
  196. package/dist/ir/ir.js.map +1 -1
  197. package/dist/ir/runtime-features.d.ts +1 -0
  198. package/dist/ir/runtime-features.js +29 -2
  199. package/dist/ir/runtime-features.js.map +1 -1
  200. package/dist/ir/validate.js +195 -5
  201. package/dist/ir/validate.js.map +1 -1
  202. package/dist/library/ir-policy.js +1 -0
  203. package/dist/library/ir-policy.js.map +1 -1
  204. package/dist/native/cli.js +1 -0
  205. package/dist/native/cli.js.map +1 -1
  206. package/dist/native/compiler.js +1 -3
  207. package/dist/native/compiler.js.map +1 -1
  208. package/dist/native/prepare.js +1 -0
  209. package/dist/native/prepare.js.map +1 -1
  210. package/dist/native/sanitizer.test.js +1 -0
  211. package/dist/native/sanitizer.test.js.map +1 -1
  212. package/package.json +20 -20
  213. package/surface-manifest.json +869 -48
@@ -215,6 +215,7 @@ export declare class LlEmitter {
215
215
  readonly checkedNarrows: CheckedNarrows;
216
216
  callArrayReads: Map<IrExpr, LocalArrayRead>;
217
217
  mapReadLifetimes: MapReadLifetimes;
218
+ readNumberMapWrites: ReadonlySet<IrExpr>;
218
219
  readonly callLifetimes: CallLifetimes;
219
220
  readonly constantCallbacks: Map<string, Map<string, string>>;
220
221
  currentConstantCallbacks: ReadonlyMap<string, string>;
@@ -687,6 +688,11 @@ export declare class LlEmitter {
687
688
  * conditions in expr-calls.ts). */
688
689
  private callTestsPending;
689
690
  private workerLoopBudget;
691
+ /** The amortized cancellation poll, emitted on the loop's back edge (the
692
+ * continue target), after the body. A poll in the header would be a loop
693
+ * exit ahead of the body; LLVM then cannot rotate the loop, so loads that
694
+ * the body repeats on every iteration (a typed array's length, for one)
695
+ * stay in the loop. */
690
696
  private emitWorkerLoopCheck;
691
697
  /** Moves an already-evaluated value into the runtime's exception cell —
692
698
  * the `throw` statement's kind dispatch (stmts.ts's), shared with
@@ -1036,6 +1042,12 @@ export declare class LlEmitter {
1036
1042
  emitRecordExpr(e: ExprOf<"fieldGet" | "recordGet" | "recordLit" | "recordClone" | "recordKeyGet" | "recordOvfKeys" | "recordOvfHas" | "recordHas" | "fieldAbsent">): LlValue;
1037
1043
  emitDynamicExpr(e: ExprOf<"dynFrom" | "dynCall" | "dynInvoke" | "dynArrLit" | "dynObjLit" | "unionWrap" | "unionNarrow" | "unionDisc" | "unionKeyGet" | "unionIsTag" | "dynKeyGet" | "dynHasKey" | "dynScalarEq" | "dynTest" | "unionEq" | "unionFuncEq" | "caughtTest" | "caughtCheck" | "caughtNarrow" | "caughtToDyn">): LlValue;
1038
1044
  emitIntrinsicExpr(e: ExprOf<"intrinsic">): LlValue;
1045
+ /** InternTable's runtime calls (scr_itable.c). Table and entry handles
1046
+ * are f64 values carrying pointer bits; entry values are 64-bit slots
1047
+ * (double bits, a bool, or a pointer to an immortal value) that the
1048
+ * table neither retains nor releases. Lookups and inserts of array keys
1049
+ * throw a TypeError for keys longer than a table accepts. */
1050
+ private emitInternTableIntrinsic;
1039
1051
  /** Lifetime regions in modules with lifetimeRegions (llvm/regions.ts).
1040
1052
  * Created with the class graph; null elsewhere. */
1041
1053
  private regions;
@@ -46,9 +46,9 @@ import { InlineUnionFields, loadInlineUnion, presentBits, stackUnionBox, storeIn
46
46
  import { emitLocalArrayRead, emitProjectedArrayRead, emitBorrowedArrayRead, findLocalArrayReads, findCallArrayReads, OptionalArrayReads, } from "./local-array-reads.js";
47
47
  import { CheckedNarrows, emitCheckedNarrowReceiver } from "./checked-narrows.js";
48
48
  import { emitDenseArrayGet, emitDenseArraySet } from "./dense-array-access.js";
49
- import { emitStackMapRead, findMapReadLifetimes, matchMapRead, } from "./map-read-lifetimes.js";
49
+ import { emitStackMapRead, findMapReadLifetimes, findReadNumberMapWrites, matchMapRead, } from "./map-read-lifetimes.js";
50
50
  import { emitBorrowedFieldSequence, guardedValue } from "./borrowed-receivers.js";
51
- import { borrowableInputs, emitBorrowedInput } from "./borrowed-inputs.js";
51
+ import { borrowableInputs, emitBorrowedInput, emitBorrowedInputs } from "./borrowed-inputs.js";
52
52
  import { analyzeWalks, findWalkBorrows } from "./walk-borrows.js";
53
53
  import { findReboundParameters } from "./rebound-parameters.js";
54
54
  import { ReferenceEffects } from "./reference-effects.js";
@@ -61,7 +61,7 @@ import { AmbientReceiverReaders, findConstantCallbacks } from "./constant-callba
61
61
  import { findScalarStringSlices, emitStringSliceSnapshot, } from "./string-slices.js";
62
62
  import { LazyCaptures } from "./lazy-captures.js";
63
63
  import { StackCaptures } from "./stack-captures.js";
64
- 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";
65
65
  import { ffiExtendsNarrowIntegers } from "../targets.js";
66
66
  import { emitLiteralExpr, emitOperatorExpr, emitStringExpr, emitContainerExpr, emitRecordExpr, } from "./expr-primitives.js";
67
67
  import { emitControlExpr } from "./expr-control.js";
@@ -85,7 +85,7 @@ import { emitNetworkHttpLibCall } from "./lib-network.js";
85
85
  import { emitAssertInspectLibCall, emitIoLibCall, emitGenericLibCall, emitLibCall, } from "./lib-dispatch.js";
86
86
  import { buildClassGraph, classMembershipIntervals, emitClassMembershipHelper, classEnvironmentIndex, classFieldIndex, classStructSym, programLifetimeClass, } from "./classes.js";
87
87
  import { LifetimeRegions, REGION_TYPES } from "./regions.js";
88
- import { LlDyn } from "./dyn.js";
88
+ import { LlDyn, recordDynKeepsIdentity } from "./dyn.js";
89
89
  import { VirtualBorrows } from "./virtual-borrows.js";
90
90
  import { LlvmUnsupportedError } from "./unsupported.js";
91
91
  import { LlWalkers } from "./walkers.js";
@@ -354,6 +354,7 @@ export class LlEmitter {
354
354
  checkedNarrows;
355
355
  callArrayReads = new Map();
356
356
  mapReadLifetimes = { locals: new Map(), arguments: new Map() };
357
+ readNumberMapWrites = new Set();
357
358
  callLifetimes;
358
359
  constantCallbacks;
359
360
  currentConstantCallbacks = new Map();
@@ -737,6 +738,9 @@ export class LlEmitter {
737
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)), {
738
739
  record: (shapeId, field) => this.recordFieldInline(shapeId, field),
739
740
  classField: (className, field) => this.inlineUnions.classField(className, field),
741
+ }, (shapeId) => {
742
+ const shape = this.recordsById.get(shapeId);
743
+ return shape !== undefined && !recordDynKeepsIdentity(shape);
740
744
  });
741
745
  this.constantCallbacks = findConstantCallbacks(mod, this.callLifetimes);
742
746
  this.stackCallbacks = new StackCallbacks(this.fnByName);
@@ -1413,21 +1417,17 @@ export class LlEmitter {
1413
1417
  if (!asyncEntry)
1414
1418
  return [];
1415
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.
1416
1422
  if (usesNodeTest) {
1417
- 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)`);
1418
1424
  }
1419
- if (usesNodeTest) {
1420
- 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`);
1421
- }
1422
- const exitStatus = usesNodeTest ? "%tla_exit_status" : "%tla_status";
1423
- // finish_top_level initially notes 13. Replace that hint before exit
1424
- // listeners run when a higher-priority verdict was already selected.
1425
- lines.push(` call void @scr_exit_code_note(i32 ${exitStatus})`);
1426
1425
  for (const line of exitListenerLines("xp"))
1427
1426
  lines.push(line);
1428
1427
  for (const line of topPendingReleases)
1429
1428
  lines.push(line);
1430
- 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`);
1431
1431
  return lines;
1432
1432
  };
1433
1433
  // LIBRARY mode: the runtime entry points the generated library
@@ -2185,9 +2185,13 @@ export class LlEmitter {
2185
2185
  // Number-key Map/Set lookups probe the runtime's direct index inline:
2186
2186
  // while ndense is nonzero every live key is an integer below it, so an
2187
2187
  // in-range integral key reads its slot (entry index + 1, 0 = absent) and
2188
- // any other key is absent. Maps without the index (ndense 0) and every
2189
- // non-integral probe outside the table take the runtime lookup, which
2190
- // 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).
2191
2195
  if (this.decls.has(NUMBER_MAP_ENTRY_DECL)) {
2192
2196
  const sz = this.sizeType;
2193
2197
  let mapTmp = 0;
@@ -2196,7 +2200,15 @@ export class LlEmitter {
2196
2200
  // A non-integral key inside the table is as absent as one outside it.
2197
2201
  ...mapIndex.lines.map((line) => ` ${line}`), ` br i1 ${mapIndex.ok}, label %slot, label %outside`, `slot:`, sz === "i64"
2198
2202
  ? ` %i = add i64 ${mapIndex.wide}, 0`
2199
- : ` %i = trunc i64 ${mapIndex.wide} to ${sz}`, ` %dp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 19`, ` %dense = load ptr, ptr %dp`, ` %sp = getelementptr inbounds i32, ptr %dense, ${sz} %i`, ` %s = load i32, ptr %sp`, ` %empty = icmp eq i32 %s, 0`, ` br i1 %empty, label %miss, label %hit`, `hit:`, ` %e32 = sub i32 %s, 1`, sz === "i32" ? ` %e = add i32 %e32, 0` : ` %e = zext i32 %e32 to ${sz}`, ` %ep = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 13`, ` %entries = load ptr, ptr %ep`, ` %found = getelementptr inbounds %ScrMapEntry, ptr %entries, ${sz} %e`, ` ret ptr %found`, `miss:`, ` ret ptr null`, `outside:`, ` %dense.any = icmp ne ${sz} %nd, 0`, ` br i1 %dense.any, label %miss, label %slow`, `slow:`, ` %r = call ptr @scr_map_entry_f64(ptr %m, double %k)`, ` ret ptr %r`, `}`, ``);
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`, `}`, ``);
2200
2212
  }
2201
2213
  // Map/Set iteration steps read the entries array inline: an index is
2202
2214
  // live when it is below the entry count and its entry's cached hash is
@@ -3604,6 +3616,11 @@ export class LlEmitter {
3604
3616
  this.B.line(`store i32 0, ptr ${slot}`);
3605
3617
  return slot;
3606
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. */
3607
3624
  emitWorkerLoopCheck(slot) {
3608
3625
  if (slot === null)
3609
3626
  return;
@@ -4571,6 +4588,7 @@ export class LlEmitter {
4571
4588
  this.scalarStringSlices =
4572
4589
  this.debug === null ? findScalarStringSlices(fn, this.callLifetimes) : new Map();
4573
4590
  this.mapReadLifetimes = findMapReadLifetimes(fn, this.boxedUnionsById, this.callLifetimes);
4591
+ this.readNumberMapWrites = findReadNumberMapWrites(fn);
4574
4592
  this.localStackUnions = findLocalStackUnions(fn, this.callLifetimes, this.boxedUnionsById);
4575
4593
  this.localStackObjects = this.stackObjects
4576
4594
  ? findLocalStackObjects(this, fn, this.callLifetimes)
@@ -5796,7 +5814,7 @@ export class LlEmitter {
5796
5814
  B.line(`${lenPtr} = getelementptr inbounds %ScrArr, ptr ${arr.name}, i32 0, i32 1`);
5797
5815
  this.markMemoryPointer(lenPtr, "array:header");
5798
5816
  B.line(`${len} = load ${this.sizeType}, ptr ${lenPtr}${this.fieldAliasAttachment(lenPtr)}`);
5799
- B.line(`${lenNumber} = sitofp ${this.sizeType} ${len} to double`);
5817
+ B.line(`${lenNumber} = ${sizeToDouble(this.sizeType)} ${this.sizeType} ${len} to double`);
5800
5818
  B.line(`${same} = fcmp oeq double ${length.name}, ${lenNumber}`);
5801
5819
  B.condBr(same, done, resize);
5802
5820
  B.startBlock(resize);
@@ -6088,15 +6106,15 @@ export class LlEmitter {
6088
6106
  const lc = B.newLabel("loop.c");
6089
6107
  const lb = B.newLabel("loop.b");
6090
6108
  const le = B.newLabel("loop.e");
6109
+ const lp = workerBudget !== null ? B.newLabel("loop.p") : lc;
6091
6110
  B.br(lc);
6092
6111
  B.startBlock(lc);
6093
- this.emitWorkerLoopCheck(workerBudget);
6094
6112
  B.condBr(this.emitCondition(s.cond), lb, le);
6095
6113
  B.startBlock(lb);
6096
6114
  this.jumpTargets.push({
6097
6115
  kind: "loop",
6098
6116
  brkLabel: le,
6099
- contLabel: lc,
6117
+ contLabel: lp,
6100
6118
  labels: s.labels,
6101
6119
  frameDepth: this.frames.length,
6102
6120
  scopeDepth: this.scopes.length,
@@ -6104,7 +6122,12 @@ export class LlEmitter {
6104
6122
  });
6105
6123
  this.emitBlock(s.body);
6106
6124
  this.jumpTargets.pop();
6107
- B.br(lc);
6125
+ B.br(lp);
6126
+ if (lp !== lc) {
6127
+ B.startBlock(lp);
6128
+ this.emitWorkerLoopCheck(workerBudget);
6129
+ B.br(lc);
6130
+ }
6108
6131
  B.startBlock(le);
6109
6132
  break;
6110
6133
  }
@@ -6116,7 +6139,6 @@ export class LlEmitter {
6116
6139
  const le = B.newLabel("loop.e");
6117
6140
  B.br(lb);
6118
6141
  B.startBlock(lb);
6119
- this.emitWorkerLoopCheck(workerBudget);
6120
6142
  this.jumpTargets.push({
6121
6143
  kind: "loop",
6122
6144
  brkLabel: le,
@@ -6130,6 +6152,7 @@ export class LlEmitter {
6130
6152
  this.jumpTargets.pop();
6131
6153
  B.br(lc);
6132
6154
  B.startBlock(lc);
6155
+ this.emitWorkerLoopCheck(workerBudget);
6133
6156
  B.condBr(this.emitCondition(s.cond), lb, le);
6134
6157
  B.startBlock(le);
6135
6158
  break;
@@ -6289,12 +6312,11 @@ export class LlEmitter {
6289
6312
  B.line(`store ptr ${fresh}, ptr ${slot}`);
6290
6313
  }
6291
6314
  };
6292
- const lu = s.update || capturedLets.length > 0 ? B.newLabel("loop.u") : lc;
6293
- freshenBindings();
6294
6315
  const workerBudget = this.workerLoopBudget(s);
6316
+ const lu = s.update || capturedLets.length > 0 || workerBudget !== null ? B.newLabel("loop.u") : lc;
6317
+ freshenBindings();
6295
6318
  B.br(lc);
6296
6319
  B.startBlock(lc);
6297
- this.emitWorkerLoopCheck(workerBudget);
6298
6320
  if (integerLoop && integerSlot) {
6299
6321
  const receiver = this.emitStableReceiver(integerLoop.limitReceiver, []);
6300
6322
  const lenPtr = B.tmp();
@@ -6335,6 +6357,7 @@ export class LlEmitter {
6335
6357
  B.br(lu);
6336
6358
  if (lu !== lc) {
6337
6359
  B.startBlock(lu);
6360
+ this.emitWorkerLoopCheck(workerBudget);
6338
6361
  freshenBindings();
6339
6362
  if (integerLoop && integerSlot) {
6340
6363
  const old = B.tmp();
@@ -6402,7 +6425,6 @@ export class LlEmitter {
6402
6425
  const workerBudget = this.workerLoopBudget(s);
6403
6426
  B.br(lc);
6404
6427
  B.startBlock(lc);
6405
- this.emitWorkerLoopCheck(workerBudget);
6406
6428
  const inBounds = B.tmp();
6407
6429
  let cur;
6408
6430
  if (snapshot && cursor && scratch) {
@@ -6418,7 +6440,7 @@ export class LlEmitter {
6418
6440
  B.line(`${lenPtr} = getelementptr inbounds %ScrArr, ptr ${arr.name}, i32 0, i32 1`);
6419
6441
  this.markMemoryPointer(lenPtr, "array:header");
6420
6442
  B.line(`${rawLen} = load ${this.sizeType}, ptr ${lenPtr}${this.fieldAliasAttachment(lenPtr)}`);
6421
- B.line(`${len} = sitofp ${this.sizeType} ${rawLen} to double`);
6443
+ B.line(`${len} = ${sizeToDouble(this.sizeType)} ${this.sizeType} ${rawLen} to double`);
6422
6444
  B.line(`${inBounds} = fcmp olt double ${i}, ${len}`);
6423
6445
  cur = i;
6424
6446
  }
@@ -6476,6 +6498,7 @@ export class LlEmitter {
6476
6498
  this.jumpTargets.pop();
6477
6499
  B.br(lu);
6478
6500
  B.startBlock(lu);
6501
+ this.emitWorkerLoopCheck(workerBudget);
6479
6502
  if (idxSlot) {
6480
6503
  const i2 = B.tmp(), i3 = B.tmp();
6481
6504
  B.line(`${i2} = load double, ptr ${idxSlot}`);
@@ -7192,8 +7215,122 @@ export class LlEmitter {
7192
7215
  e.name === "region.leave" ||
7193
7216
  e.name === "region.release")
7194
7217
  return this.emitRegionIntrinsic(e);
7218
+ if (e.name.startsWith("itable."))
7219
+ return this.emitInternTableIntrinsic(e);
7195
7220
  return emitIntrinsicExpr(this, e);
7196
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
+ }
7197
7334
  /** Lifetime regions in modules with lifetimeRegions (llvm/regions.ts).
7198
7335
  * Created with the class graph; null elsewhere. */
7199
7336
  regions = null;