@scriptc/compiler 0.0.20 → 0.0.22

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 (75) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +78 -34
  2. package/dist/backend/cc-cache.test.d.ts +1 -0
  3. package/dist/backend/cc-cache.test.js +2507 -0
  4. package/dist/backend/cc-cache.test.js.map +1 -0
  5. package/dist/backend/cc.d.ts +69 -11
  6. package/dist/backend/cc.js +1937 -222
  7. package/dist/backend/cc.js.map +1 -1
  8. package/dist/backend/emission/emit-exprs.js +355 -8
  9. package/dist/backend/emission/emit-exprs.js.map +1 -1
  10. package/dist/backend/emission/emit-walkers.js +108 -7
  11. package/dist/backend/emission/emit-walkers.js.map +1 -1
  12. package/dist/backend/emission/emitter.d.ts +16 -0
  13. package/dist/backend/emission/emitter.js +23 -2
  14. package/dist/backend/emission/emitter.js.map +1 -1
  15. package/dist/backend/llvm/dyn.d.ts +1 -0
  16. package/dist/backend/llvm/dyn.js +305 -8
  17. package/dist/backend/llvm/dyn.js.map +1 -1
  18. package/dist/backend/llvm/emitter.js +527 -2
  19. package/dist/backend/llvm/emitter.js.map +1 -1
  20. package/dist/compat/fetch-profile.d.ts +108 -0
  21. package/dist/compat/fetch-profile.js +482 -0
  22. package/dist/compat/fetch-profile.js.map +1 -0
  23. package/dist/coverage/surface-manifest.js +54 -0
  24. package/dist/coverage/surface-manifest.js.map +1 -1
  25. package/dist/frontend/lowering/lower-builtins.d.ts +21 -8
  26. package/dist/frontend/lowering/lower-builtins.js +137 -14
  27. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  28. package/dist/frontend/lowering/lower-calls.js +40 -0
  29. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  30. package/dist/frontend/lowering/lower-classes.js +4 -3
  31. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  32. package/dist/frontend/lowering/lower-exprs.d.ts +2 -2
  33. package/dist/frontend/lowering/lower-exprs.js +63 -12
  34. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  35. package/dist/frontend/lowering/lower-island.d.ts +102 -7
  36. package/dist/frontend/lowering/lower-island.js +1702 -26
  37. package/dist/frontend/lowering/lower-island.js.map +1 -1
  38. package/dist/frontend/lowering/lower-modules.js +17 -1
  39. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  40. package/dist/frontend/lowering/lower-stmts.js +25 -5
  41. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  42. package/dist/frontend/lowering/lowerer.d.ts +39 -0
  43. package/dist/frontend/lowering/lowerer.js +286 -18
  44. package/dist/frontend/lowering/lowerer.js.map +1 -1
  45. package/dist/frontend/lowering/surfaces.js +12 -0
  46. package/dist/frontend/lowering/surfaces.js.map +1 -1
  47. package/dist/frontend/program.d.ts +16 -0
  48. package/dist/frontend/program.js +130 -6
  49. package/dist/frontend/program.js.map +1 -1
  50. package/dist/frontend/types.d.ts +14 -7
  51. package/dist/frontend/types.js +95 -31
  52. package/dist/frontend/types.js.map +1 -1
  53. package/dist/index.d.ts +7 -1
  54. package/dist/index.js +86 -20
  55. package/dist/index.js.map +1 -1
  56. package/dist/ir/nodes.d.ts +32 -16
  57. package/dist/ir/nodes.js +36 -28
  58. package/dist/ir/nodes.js.map +1 -1
  59. package/dist/ir/validate.js +61 -1
  60. package/dist/ir/validate.js.map +1 -1
  61. package/dist/library/int-infer.d.ts +7 -12
  62. package/dist/library/int-infer.js +72 -30
  63. package/dist/library/int-infer.js.map +1 -1
  64. package/dist/library/int-infer.test.js +200 -1
  65. package/dist/library/int-infer.test.js.map +1 -1
  66. package/dist/library/profile.d.ts +7 -0
  67. package/dist/library/profile.js +2 -0
  68. package/dist/library/profile.js.map +1 -1
  69. package/dist/library/sidecar-validate.js +5 -0
  70. package/dist/library/sidecar-validate.js.map +1 -1
  71. package/dist/library/sidecar.d.ts +3 -0
  72. package/dist/library/sidecar.js +168 -30
  73. package/dist/library/sidecar.js.map +1 -1
  74. package/package.json +2 -2
  75. package/surface-manifest.json +859 -1
@@ -24,6 +24,7 @@ export const DK = {
24
24
  HANDLE: 9,
25
25
  PROMISE: 10,
26
26
  JSVAL: 11, /* SCR_DYN_JSVAL — island values held by reference */
27
+ TYPED_REF: 12, /* SCR_DYN_TYPED_REF — static Web-stream transit capsule */
27
28
  };
28
29
  /** Exact double literal (the emitter's f64Lit — the walkers' copy). */
29
30
  function f64Lit(n) {
@@ -282,6 +283,35 @@ export class LlDyn {
282
283
  const name = `sc_dm_${this.dynMatchers.size}`;
283
284
  this.dynMatchers.set(key, name);
284
285
  const B = new BlockBuilder();
286
+ if (isRefCounted(t) && t.kind !== "dyn") {
287
+ this.host.declare(`declare zeroext i1 @scr_dyn_typed_ref_is(ptr, ptr, i64)`);
288
+ const matched = B.tmp();
289
+ B.line(`${matched} = call zeroext i1 @scr_dyn_typed_ref_is(ptr %d, ptr ${this.host.cstr(key)}, i64 ${Buffer.byteLength(key, "utf8")})`);
290
+ const lRef = B.newLabel("dm.tr");
291
+ const lNext = B.newLabel("dm.nt");
292
+ B.condBr(matched, lRef, lNext);
293
+ B.startBlock(lRef);
294
+ B.terminate(`ret i1 true`);
295
+ B.startBlock(lNext);
296
+ }
297
+ if (t.kind !== "dyn") {
298
+ this.host.declare(`declare ptr @scr_dyn_typed_ref_materialize(ptr)`);
299
+ this.host.declare(`declare void @scr_dyn_release_v(ptr)`);
300
+ const kind = this.kindOf(B, "%d");
301
+ const capsule = B.tmp();
302
+ B.line(`${capsule} = icmp eq i32 ${kind}, ${DK.TYPED_REF}`);
303
+ const lCapsule = B.newLabel("dm.tr.mat");
304
+ const lPlain = B.newLabel("dm.tr.plain");
305
+ B.condBr(capsule, lCapsule, lPlain);
306
+ B.startBlock(lCapsule);
307
+ const materialized = B.tmp();
308
+ const matched = B.tmp();
309
+ B.line(`${materialized} = call ptr @scr_dyn_typed_ref_materialize(ptr %d)`);
310
+ B.line(`${matched} = call zeroext i1 @${name}(ptr ${materialized})`);
311
+ B.line(`call void @scr_dyn_release_v(ptr ${materialized})`);
312
+ B.terminate(`ret i1 ${matched}`);
313
+ B.startBlock(lPlain);
314
+ }
285
315
  const kindIs = (k) => {
286
316
  const kd = this.kindOf(B, "%d");
287
317
  const r = B.tmp();
@@ -482,6 +512,129 @@ export class LlDyn {
482
512
  host.declare(`declare void @scr_dyn_check_fail(ptr, ptr, ptr)`);
483
513
  const want = host.cstr(this.dynDesc(t));
484
514
  const B = new BlockBuilder();
515
+ if (isRefCounted(t) && t.kind !== "dyn") {
516
+ host.declare(`declare zeroext i1 @scr_dyn_typed_ref_is(ptr, ptr, i64)`);
517
+ host.declare(`declare ptr @scr_dyn_typed_ref_unbox(ptr)`);
518
+ const matched = B.tmp();
519
+ B.line(`${matched} = call zeroext i1 @scr_dyn_typed_ref_is(ptr %d, ptr ${host.cstr(key)}, i64 ${Buffer.byteLength(key, "utf8")})`);
520
+ const lRef = B.newLabel("dc.tr");
521
+ const lNext = B.newLabel("dc.nt");
522
+ B.condBr(matched, lRef, lNext);
523
+ B.startBlock(lRef);
524
+ const ref = B.tmp();
525
+ B.line(`${ref} = call ptr @scr_dyn_typed_ref_unbox(ptr %d)`);
526
+ B.terminate(`ret ptr ${ref}`);
527
+ B.startBlock(lNext);
528
+ if (t.kind !== "union") {
529
+ host.declare(`declare ptr @scr_dyn_typed_ref_materialize(ptr)`);
530
+ host.declare(`declare ptr @scr_dyn_typed_ref_cached_cast(ptr, ptr, i64)`);
531
+ host.declare(`declare void @scr_dyn_typed_ref_cache_cast(ptr, ptr, i64, ptr, ptr, ptr)`);
532
+ host.declare(`declare void @scr_dyn_release_v(ptr)`);
533
+ const rc = vAdapters(host, t);
534
+ const kind = this.kindOf(B, "%d");
535
+ const capsule = B.tmp();
536
+ B.line(`${capsule} = icmp eq i32 ${kind}, ${DK.TYPED_REF}`);
537
+ const lCapsule = B.newLabel("dc.tr.cap");
538
+ const lPlain = B.newLabel("dc.tr.plain");
539
+ B.condBr(capsule, lCapsule, lPlain);
540
+ B.startBlock(lCapsule);
541
+ const cached = B.tmp();
542
+ B.line(`${cached} = call ptr @scr_dyn_typed_ref_cached_cast(ptr %d, ptr ${host.cstr(key)}, i64 ${Buffer.byteLength(key, "utf8")})`);
543
+ const hasCached = B.tmp();
544
+ B.line(`${hasCached} = icmp ne ptr ${cached}, null`);
545
+ if (t.kind !== "record" && t.kind !== "array") {
546
+ const lCached = B.newLabel("dc.tr.hit");
547
+ const lMaterialize = B.newLabel("dc.tr.mat");
548
+ B.condBr(hasCached, lCached, lMaterialize);
549
+ B.startBlock(lCached);
550
+ B.terminate(`ret ptr ${cached}`);
551
+ B.startBlock(lMaterialize);
552
+ }
553
+ const materialized = B.tmp();
554
+ const checked = B.tmp();
555
+ B.line(`${materialized} = call ptr @scr_dyn_typed_ref_materialize(ptr %d)`);
556
+ B.line(`${checked} = call ${retTy} @${name}(ptr ${materialized}, ptr %path)`);
557
+ B.line(`call void @scr_dyn_release_v(ptr ${materialized})`);
558
+ const ok = B.tmp();
559
+ B.line(`${ok} = icmp ne ptr ${checked}, null`);
560
+ if (t.kind === "record" || t.kind === "array") {
561
+ const shape = t.kind === "record"
562
+ ? host.recordsById.get(t.shapeId)
563
+ : undefined;
564
+ if (t.kind === "record" && !shape) {
565
+ throw new Error(`llvm emitter bug: cached typed-ref cast of unknown shape ${t.shapeId}`);
566
+ }
567
+ const lOk = B.newLabel("dc.tr.ok");
568
+ const lBad = B.newLabel("dc.tr.bad");
569
+ B.condBr(ok, lOk, lBad);
570
+ B.startBlock(lBad);
571
+ const lBadDrop = B.newLabel("dc.tr.bad.drop");
572
+ const lBadRet = B.newLabel("dc.tr.bad.ret");
573
+ B.condBr(hasCached, lBadDrop, lBadRet);
574
+ B.startBlock(lBadDrop);
575
+ B.line(`call void ${releaseSym(host, t)}(ptr ${cached})`);
576
+ B.br(lBadRet);
577
+ B.startBlock(lBadRet);
578
+ B.terminate(`ret ptr null`);
579
+ B.startBlock(lOk);
580
+ const lRefresh = B.newLabel("dc.tr.refresh");
581
+ const lCache = B.newLabel("dc.tr.put");
582
+ B.condBr(hasCached, lRefresh, lCache);
583
+ B.startBlock(lRefresh);
584
+ const members = t.kind === "record"
585
+ ? [
586
+ ...shape.fields.map((field, index) => ({
587
+ index: index + 1,
588
+ type: llFieldType(field.type),
589
+ name: field.name,
590
+ })),
591
+ ...(shape.indexValue
592
+ ? [{
593
+ index: shape.fields.length + 1,
594
+ type: "ptr",
595
+ name: "[key: string] overflow",
596
+ }]
597
+ : []),
598
+ ]
599
+ : [
600
+ { index: 1, type: "i64", name: "length" },
601
+ { index: 2, type: "i64", name: "capacity" },
602
+ { index: 7, type: "ptr", name: "data" },
603
+ ];
604
+ members.forEach((member) => {
605
+ const cachedPtr = B.tmp();
606
+ const checkedPtr = B.tmp();
607
+ const oldValue = B.tmp();
608
+ const newValue = B.tmp();
609
+ const struct = t.kind === "record"
610
+ ? `%${mangleRecordStruct(t.shapeId)}`
611
+ : "%ScrArr";
612
+ B.line(`${cachedPtr} = getelementptr inbounds ${struct}, ptr ${cached}, i64 0, i32 ${member.index}`);
613
+ B.line(`${checkedPtr} = getelementptr inbounds ${struct}, ptr ${checked}, i64 0, i32 ${member.index}`);
614
+ B.line(`${oldValue} = load ${member.type}, ptr ${cachedPtr} ; ${member.name}`);
615
+ B.line(`${newValue} = load ${member.type}, ptr ${checkedPtr}`);
616
+ B.line(`store ${member.type} ${newValue}, ptr ${cachedPtr}`);
617
+ B.line(`store ${member.type} ${oldValue}, ptr ${checkedPtr}`);
618
+ });
619
+ B.line(`call void ${releaseSym(host, t)}(ptr ${checked})`);
620
+ B.terminate(`ret ptr ${cached}`);
621
+ B.startBlock(lCache);
622
+ B.line(`call void @scr_dyn_typed_ref_cache_cast(ptr %d, ptr ${host.cstr(key)}, i64 ${Buffer.byteLength(key, "utf8")}, ptr ${checked}, ptr ${rc.retain}, ptr ${rc.release})`);
623
+ B.terminate(`ret ptr ${checked}`);
624
+ }
625
+ else {
626
+ const lCache = B.newLabel("dc.tr.put");
627
+ const lReturn = B.newLabel("dc.tr.ret");
628
+ B.condBr(ok, lCache, lReturn);
629
+ B.startBlock(lCache);
630
+ B.line(`call void @scr_dyn_typed_ref_cache_cast(ptr %d, ptr ${host.cstr(key)}, i64 ${Buffer.byteLength(key, "utf8")}, ptr ${checked}, ptr ${rc.retain}, ptr ${rc.release})`);
631
+ B.br(lReturn);
632
+ B.startBlock(lReturn);
633
+ B.terminate(`ret ptr ${checked}`);
634
+ }
635
+ B.startBlock(lPlain);
636
+ }
637
+ }
485
638
  /** kind test with the standard fail path (got = %d). */
486
639
  const requireKind = (k, hint) => {
487
640
  const kd = this.kindOf(B, "%d");
@@ -518,9 +671,11 @@ export class LlDyn {
518
671
  break;
519
672
  }
520
673
  case "dyn": {
521
- // An `unknown` slot: the checked-dynamic tree subtree passes through as-is.
522
- const r = this.retainDyn(B, "%d");
523
- B.terminate(`ret ptr ${r}`);
674
+ // Preserve the capsule at an unknown boundary. Generic dyn
675
+ // operations materialize its one cached detached view, while
676
+ // strict equality keeps repeated stream references identical.
677
+ const retained = this.retainDyn(B, "%d");
678
+ B.terminate(`ret ptr ${retained}`);
524
679
  break;
525
680
  }
526
681
  case "bytes": {
@@ -652,13 +807,17 @@ export class LlDyn {
652
807
  const m = this.objGetLit(B, "%d", f.name);
653
808
  if (f.type.kind === "dyn") {
654
809
  // An `unknown` field: a present key passes through, a missing
655
- // one IS the undefined dyn value.
810
+ // one IS the undefined dyn value. Go through the dyn builder so
811
+ // a Web-stream typed-ref capsule cannot escape inside a checked
812
+ // record field.
656
813
  const has = B.tmp();
657
814
  B.line(`${has} = icmp ne ptr ${m}, null`);
658
815
  const sel = B.tmp();
659
816
  const u = this.undef(B);
660
817
  B.line(`${sel} = select i1 ${has}, ptr ${m}, ptr ${u}`);
661
- storeInto(f.name, f.type, this.retainDyn(B, sel));
818
+ const value = B.tmp();
819
+ B.line(`${value} = call ptr @${this.dynCheckHelper(f.type)}(ptr ${sel}, ptr ${pathSlot})`);
820
+ storeInto(f.name, f.type, value);
662
821
  }
663
822
  else if (utag >= 0 && f.type.kind === "union") {
664
823
  const unit = host.unitInstanceRef(f.type.unionId, utag);
@@ -847,6 +1006,75 @@ export class LlDyn {
847
1006
  }
848
1007
  B.startBlock(lNext);
849
1008
  });
1009
+ // Preserve an exact typed-ref arm above. If no producer tag matched,
1010
+ // retry the union against the ordinary copy-based structural
1011
+ // snapshot (the compiler's width-coercion stance, rather than a
1012
+ // live narrowed alias).
1013
+ host.declare(`declare ptr @scr_dyn_typed_ref_materialize(ptr)`);
1014
+ host.declare(`declare ptr @scr_dyn_typed_ref_cached_cast(ptr, ptr, i64)`);
1015
+ host.declare(`declare void @scr_dyn_typed_ref_cache_cast(ptr, ptr, i64, ptr, ptr, ptr)`);
1016
+ host.declare(`declare void @scr_dyn_release_v(ptr)`);
1017
+ host.declare(`declare void @scr_union_release(ptr)`);
1018
+ const rc = vAdapters(host, t);
1019
+ const kind = this.kindOf(B, "%d");
1020
+ const capsule = B.tmp();
1021
+ B.line(`${capsule} = icmp eq i32 ${kind}, ${DK.TYPED_REF}`);
1022
+ const lCapsule = B.newLabel("dcu.cap");
1023
+ const lFail = B.newLabel("dcu.fail");
1024
+ B.condBr(capsule, lCapsule, lFail);
1025
+ B.startBlock(lCapsule);
1026
+ const cached = B.tmp();
1027
+ B.line(`${cached} = call ptr @scr_dyn_typed_ref_cached_cast(ptr %d, ptr ${host.cstr(key)}, i64 ${Buffer.byteLength(key, "utf8")})`);
1028
+ const hasCached = B.tmp();
1029
+ B.line(`${hasCached} = icmp ne ptr ${cached}, null`);
1030
+ const materialized = B.tmp();
1031
+ const checked = B.tmp();
1032
+ B.line(`${materialized} = call ptr @scr_dyn_typed_ref_materialize(ptr %d)`);
1033
+ B.line(`${checked} = call ptr @${name}(ptr ${materialized}, ptr %path)`);
1034
+ B.line(`call void @scr_dyn_release_v(ptr ${materialized})`);
1035
+ const ok = B.tmp();
1036
+ B.line(`${ok} = icmp ne ptr ${checked}, null`);
1037
+ const lOk = B.newLabel("dcu.ok");
1038
+ const lBad = B.newLabel("dcu.bad");
1039
+ B.condBr(ok, lOk, lBad);
1040
+ B.startBlock(lBad);
1041
+ const lBadDrop = B.newLabel("dcu.bad.drop");
1042
+ const lBadRet = B.newLabel("dcu.bad.ret");
1043
+ B.condBr(hasCached, lBadDrop, lBadRet);
1044
+ B.startBlock(lBadDrop);
1045
+ B.line(`call void @scr_union_release(ptr ${cached})`);
1046
+ B.br(lBadRet);
1047
+ B.startBlock(lBadRet);
1048
+ B.terminate(`ret ptr null`);
1049
+ B.startBlock(lOk);
1050
+ const lRefresh = B.newLabel("dcu.refresh");
1051
+ const lCache = B.newLabel("dcu.put");
1052
+ B.condBr(hasCached, lRefresh, lCache);
1053
+ B.startBlock(lRefresh);
1054
+ [
1055
+ [1, "i32", "tag"],
1056
+ [2, "ptr", "retain"],
1057
+ [3, "ptr", "release"],
1058
+ [4, "ptr", "trace"],
1059
+ [5, "i64", "slot"],
1060
+ ].forEach(([index, fieldType, fieldName]) => {
1061
+ const cachedPtr = B.tmp();
1062
+ const checkedPtr = B.tmp();
1063
+ const oldValue = B.tmp();
1064
+ const newValue = B.tmp();
1065
+ B.line(`${cachedPtr} = getelementptr inbounds %ScrUnion, ptr ${cached}, i64 0, i32 ${index}`);
1066
+ B.line(`${checkedPtr} = getelementptr inbounds %ScrUnion, ptr ${checked}, i64 0, i32 ${index}`);
1067
+ B.line(`${oldValue} = load ${fieldType}, ptr ${cachedPtr} ; ${fieldName}`);
1068
+ B.line(`${newValue} = load ${fieldType}, ptr ${checkedPtr}`);
1069
+ B.line(`store ${fieldType} ${newValue}, ptr ${cachedPtr}`);
1070
+ B.line(`store ${fieldType} ${oldValue}, ptr ${checkedPtr}`);
1071
+ });
1072
+ B.line(`call void @scr_union_release(ptr ${checked})`);
1073
+ B.terminate(`ret ptr ${cached}`);
1074
+ B.startBlock(lCache);
1075
+ B.line(`call void @scr_dyn_typed_ref_cache_cast(ptr %d, ptr ${host.cstr(key)}, i64 ${Buffer.byteLength(key, "utf8")}, ptr ${checked}, ptr ${rc.retain}, ptr ${rc.release})`);
1076
+ B.terminate(`ret ptr ${checked}`);
1077
+ B.startBlock(lFail);
850
1078
  B.line(`call void @scr_dyn_check_fail(ptr %path, ptr ${want}, ptr %d)`);
851
1079
  B.terminate(`ret ptr null`);
852
1080
  break;
@@ -929,6 +1157,7 @@ export class LlDyn {
929
1157
  this.toDynFns.set(key, name);
930
1158
  const host = this.host;
931
1159
  const B = new BlockBuilder();
1160
+ let sourceAccessor = null;
932
1161
  switch (t.kind) {
933
1162
  case "f64": {
934
1163
  host.declare(`declare ptr @scr_dyn_new_num(double)`);
@@ -967,6 +1196,12 @@ export class LlDyn {
967
1196
  B.terminate(`ret ptr ${r}`);
968
1197
  break;
969
1198
  }
1199
+ case "func": {
1200
+ const r = B.tmp();
1201
+ B.line(`${r} = call ptr @${this.dynFuncBoxHelper(t)}(ptr %v, ptr null)`);
1202
+ B.terminate(`ret ptr ${r}`);
1203
+ break;
1204
+ }
970
1205
  case "bytes": {
971
1206
  if (t.elem !== "u8")
972
1207
  throw new Error(`llvm emitter bug: to-dyn of bytes<${t.elem}>`);
@@ -1021,9 +1256,21 @@ export class LlDyn {
1021
1256
  B.terminate(`ret ptr ${d}`);
1022
1257
  break;
1023
1258
  }
1024
- host.declare(`declare ptr @scr_dyn_new_obj()`);
1025
1259
  const d = B.tmp();
1026
- B.line(`${d} = call ptr @scr_dyn_new_obj()`);
1260
+ const carriesListenerIdentity = shape.fields.some((f) => f.name === "handleEvent" && f.type.kind === "func");
1261
+ if (carriesListenerIdentity) {
1262
+ const rc = vAdapters(host, t);
1263
+ sourceAccessor = {
1264
+ name: `${name}_source_access`,
1265
+ release: rc.release,
1266
+ };
1267
+ host.declare(`declare ptr @scr_dyn_new_obj_with_identity(ptr, ptr, ptr)`);
1268
+ B.line(`${d} = call ptr @scr_dyn_new_obj_with_identity(ptr %v, ptr ${rc.retain}, ptr @${sourceAccessor.name})`);
1269
+ }
1270
+ else {
1271
+ host.declare(`declare ptr @scr_dyn_new_obj()`);
1272
+ B.line(`${d} = call ptr @scr_dyn_new_obj()`);
1273
+ }
1027
1274
  // Keys insert in DECLARED order (JS insertion order); internal
1028
1275
  // '%'-fields follow so a record→dyn→record round trip keeps them.
1029
1276
  const byName = new Map(shape.fields.map((f) => [f.name, f]));
@@ -1298,6 +1545,9 @@ export class LlDyn {
1298
1545
  }
1299
1546
  }
1300
1547
  this.defs.push(`define internal ptr @${name}(${this.valTy(t)} %v) ${FN_ATTRS} { ; to-dyn ${key}`, B.render(), `}`, ``);
1548
+ if (sourceAccessor) {
1549
+ this.defs.push(`define internal ptr @${sourceAccessor.name}(ptr %v, i1 %materialize) ${FN_ATTRS} { ; live listener source ${key}`, `entry:`, ` br i1 %materialize, label %snapshot, label %release`, `snapshot:`, ` %d = call ptr @${name}(ptr %v)`, ` ret ptr %d`, `release:`, ` call void ${sourceAccessor.release}(ptr %v)`, ` ret ptr null`, `}`, ``);
1550
+ }
1301
1551
  return name;
1302
1552
  }
1303
1553
  /** The checked-dynamic tree-promise settle adapter for one fulfillment payload type —
@@ -1407,7 +1657,7 @@ export class LlDyn {
1407
1657
  const kd = this.kindOf(B, "%d");
1408
1658
  const done = B.newLabel("ds.d");
1409
1659
  const labels = new Map();
1410
- for (const k of [DK.NULL, DK.BOOL, DK.NUM, DK.STR, DK.ARR, DK.OBJ, DK.UNDEF, DK.BYTES, DK.FUNC, DK.HANDLE, DK.PROMISE, DK.JSVAL]) {
1660
+ for (const k of [DK.NULL, DK.BOOL, DK.NUM, DK.STR, DK.ARR, DK.OBJ, DK.UNDEF, DK.BYTES, DK.FUNC, DK.HANDLE, DK.PROMISE, DK.JSVAL, DK.TYPED_REF]) {
1411
1661
  labels.set(k, B.newLabel(`ds.k${k}`));
1412
1662
  }
1413
1663
  B.terminate(`switch i32 ${kd}, label %${done} [ ${[...labels].map(([k, l]) => `i32 ${k}, label %${l}`).join(" ")} ]`);
@@ -1419,6 +1669,16 @@ export class LlDyn {
1419
1669
  B.line(`call void @scr_dyn_isl_tostr_buf(ptr %b, ptr %d)`);
1420
1670
  B.br(done);
1421
1671
  }
1672
+ B.startBlock(labels.get(DK.TYPED_REF));
1673
+ {
1674
+ host.declare(`declare ptr @scr_dyn_typed_ref_materialize(ptr)`);
1675
+ host.declare(`declare void @scr_dyn_release_v(ptr)`);
1676
+ const materialized = B.tmp();
1677
+ B.line(`${materialized} = call ptr @scr_dyn_typed_ref_materialize(ptr %d)`);
1678
+ B.line(`call void @sc_ds_buf(ptr %b, ptr ${materialized})`);
1679
+ B.line(`call void @scr_dyn_release_v(ptr ${materialized})`);
1680
+ B.br(done);
1681
+ }
1422
1682
  B.startBlock(labels.get(DK.UNDEF));
1423
1683
  this.puts(B, "%b", "undefined");
1424
1684
  B.br(done);
@@ -1859,6 +2119,25 @@ export class LlDyn {
1859
2119
  B.terminate(`ret ptr null`);
1860
2120
  B.startBlock(lNext);
1861
2121
  }
2122
+ // Typed stream capsules expose their one cached, refreshed dyn view to
2123
+ // ordinary property reads while the capsule itself keeps identity.
2124
+ {
2125
+ const isTyped = B.tmp();
2126
+ B.line(`${isTyped} = icmp eq i32 ${kd}, ${DK.TYPED_REF}`);
2127
+ const lTyped = B.newLabel("kg.tr");
2128
+ const lNext = B.newLabel("kg.n");
2129
+ B.condBr(isTyped, lTyped, lNext);
2130
+ B.startBlock(lTyped);
2131
+ host.declare(`declare ptr @scr_dyn_typed_ref_materialize(ptr)`);
2132
+ host.declare(`declare void @scr_dyn_release_v(ptr)`);
2133
+ const materialized = B.tmp();
2134
+ const r = B.tmp();
2135
+ B.line(`${materialized} = call ptr @scr_dyn_typed_ref_materialize(ptr %d)`);
2136
+ B.line(`${r} = call ptr @${name}(ptr ${materialized}, ptr %k, i1 %opt)`);
2137
+ B.line(`call void @scr_dyn_release_v(ptr ${materialized})`);
2138
+ B.terminate(`ret ptr ${r}`);
2139
+ B.startBlock(lNext);
2140
+ }
1862
2141
  // ISLAND-held receivers: o[k] reads the REAL engine property (getters
1863
2142
  // included, throws bridged catchably) and the result wraps back
1864
2143
  // scalar-normalized — the routed keyed read that retired the fence.
@@ -2240,6 +2519,24 @@ export class LlDyn {
2240
2519
  host.declare(`declare void @scr_str_release(ptr)`);
2241
2520
  const B = new BlockBuilder();
2242
2521
  const kd = this.kindOf(B, "%d");
2522
+ // Typed stream capsules iterate their cached, refreshed dyn view.
2523
+ {
2524
+ const isTyped = B.tmp();
2525
+ B.line(`${isTyped} = icmp eq i32 ${kd}, ${DK.TYPED_REF}`);
2526
+ const lTyped = B.newLabel("din.tr");
2527
+ const lNext = B.newLabel("din.nt");
2528
+ B.condBr(isTyped, lTyped, lNext);
2529
+ B.startBlock(lTyped);
2530
+ host.declare(`declare ptr @scr_dyn_typed_ref_materialize(ptr)`);
2531
+ host.declare(`declare void @scr_dyn_release_v(ptr)`);
2532
+ const materialized = B.tmp();
2533
+ const out = B.tmp();
2534
+ B.line(`${materialized} = call ptr @scr_dyn_typed_ref_materialize(ptr %d)`);
2535
+ B.line(`${out} = call ptr @${name}(ptr ${materialized}, i64 %n)`);
2536
+ B.line(`call void @scr_dyn_release_v(ptr ${materialized})`);
2537
+ B.terminate(`ret ptr ${out}`);
2538
+ B.startBlock(lNext);
2539
+ }
2243
2540
  // ISLAND-held sources: an engine array IS iterable — the not-iterable
2244
2541
  // TypeError below would be a wrong claim. Loud fence (lane
2245
2542
  // dyn-routing-ops).