@scriptc/compiler 0.0.11 → 0.0.13

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 (97) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +153 -24
  2. package/ambient/scriptc.d.ts +2 -2
  3. package/dist/backend/cc.d.ts +10 -2
  4. package/dist/backend/cc.js +12 -0
  5. package/dist/backend/cc.js.map +1 -1
  6. package/dist/backend/emission/emit-async.js +1 -1
  7. package/dist/backend/emission/emit-exprs.js +235 -64
  8. package/dist/backend/emission/emit-exprs.js.map +1 -1
  9. package/dist/backend/emission/emit-island.js +1 -1
  10. package/dist/backend/emission/emit-shapes.js +1 -1
  11. package/dist/backend/emission/emit-walkers.d.ts +14 -14
  12. package/dist/backend/emission/emit-walkers.js +44 -44
  13. package/dist/backend/emission/emit-walkers.js.map +1 -1
  14. package/dist/backend/emission/emitter.d.ts +3 -3
  15. package/dist/backend/emission/emitter.js +8 -8
  16. package/dist/backend/emission/may-throw.js +1 -1
  17. package/dist/backend/llvm/dyn.d.ts +10 -10
  18. package/dist/backend/llvm/dyn.js +26 -26
  19. package/dist/backend/llvm/dyn.js.map +1 -1
  20. package/dist/backend/llvm/emitter.js +140 -49
  21. package/dist/backend/llvm/emitter.js.map +1 -1
  22. package/dist/backend/llvm/shapes.js +1 -1
  23. package/dist/backend/llvm/walkers.js +2 -2
  24. package/dist/backend/llvm/walkers.js.map +1 -1
  25. package/dist/diagnostics/diagnostic.d.ts +1 -1
  26. package/dist/diagnostics/diagnostic.js +4 -3
  27. package/dist/diagnostics/diagnostic.js.map +1 -1
  28. package/dist/frontend/lowering/crypto-tables.d.ts +7 -0
  29. package/dist/frontend/lowering/crypto-tables.js +139 -0
  30. package/dist/frontend/lowering/crypto-tables.js.map +1 -0
  31. package/dist/frontend/lowering/lib-boundary.js +5 -5
  32. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  33. package/dist/frontend/lowering/lower-assert.js +12 -12
  34. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  35. package/dist/frontend/lowering/lower-builtins.d.ts +45 -27
  36. package/dist/frontend/lowering/lower-builtins.js +203 -70
  37. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  38. package/dist/frontend/lowering/lower-calls.d.ts +4 -4
  39. package/dist/frontend/lowering/lower-calls.js +74 -66
  40. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  41. package/dist/frontend/lowering/lower-classes.js +41 -7
  42. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  43. package/dist/frontend/lowering/lower-containers.d.ts +5 -5
  44. package/dist/frontend/lowering/lower-containers.js +19 -19
  45. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  46. package/dist/frontend/lowering/lower-emitter.js +2 -2
  47. package/dist/frontend/lowering/lower-emitter.js.map +1 -1
  48. package/dist/frontend/lowering/lower-exprs.d.ts +7 -7
  49. package/dist/frontend/lowering/lower-exprs.js +227 -119
  50. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  51. package/dist/frontend/lowering/lower-inspect.js +5 -5
  52. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  53. package/dist/frontend/lowering/lower-island.js +12 -3
  54. package/dist/frontend/lowering/lower-island.js.map +1 -1
  55. package/dist/frontend/lowering/lower-modules.js +17 -17
  56. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  57. package/dist/frontend/lowering/lower-namespaces.d.ts +11 -1
  58. package/dist/frontend/lowering/lower-namespaces.js +41 -6
  59. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  60. package/dist/frontend/lowering/lower-server.d.ts +21 -0
  61. package/dist/frontend/lowering/lower-server.js +278 -23
  62. package/dist/frontend/lowering/lower-server.js.map +1 -1
  63. package/dist/frontend/lowering/lower-stmts.d.ts +1 -1
  64. package/dist/frontend/lowering/lower-stmts.js +195 -34
  65. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  66. package/dist/frontend/lowering/lower-stream.js +67 -23
  67. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  68. package/dist/frontend/lowering/lowerer.d.ts +31 -13
  69. package/dist/frontend/lowering/lowerer.js +99 -45
  70. package/dist/frontend/lowering/lowerer.js.map +1 -1
  71. package/dist/frontend/lowering/surfaces.d.ts +6 -0
  72. package/dist/frontend/lowering/surfaces.js +78 -2
  73. package/dist/frontend/lowering/surfaces.js.map +1 -1
  74. package/dist/frontend/program.js +1 -1
  75. package/dist/frontend/shared.js +7 -7
  76. package/dist/frontend/shared.js.map +1 -1
  77. package/dist/frontend/types.d.ts +2 -2
  78. package/dist/frontend/types.js +27 -15
  79. package/dist/frontend/types.js.map +1 -1
  80. package/dist/index.js +44 -8
  81. package/dist/index.js.map +1 -1
  82. package/dist/ir/nodes.d.ts +208 -106
  83. package/dist/ir/nodes.js +100 -22
  84. package/dist/ir/nodes.js.map +1 -1
  85. package/dist/ir/validate.js +96 -38
  86. package/dist/ir/validate.js.map +1 -1
  87. package/dist/library/int-infer.js +13 -0
  88. package/dist/library/int-infer.js.map +1 -1
  89. package/dist/library/profile.d.ts +8 -6
  90. package/dist/library/profile.js.map +1 -1
  91. package/dist/library/sidecar-validate.js +1 -1
  92. package/dist/library/sidecar-validate.js.map +1 -1
  93. package/dist/library/sidecar.d.ts +1 -1
  94. package/dist/library/sidecar.js +20 -7
  95. package/dist/library/sidecar.js.map +1 -1
  96. package/package.json +2 -2
  97. package/surface-manifest.json +289 -4
@@ -1,4 +1,4 @@
1
- import { arrayOf, BOOL, BYTES_U8, bytesOf, canMarshalFuncIntoIsland, CHILDSTREAM_T, DYN, F64, isRefCounted, isUnitType, MAY_THROW_LIB_FNS, RUNTIME_ERROR_CLASSES, STRING, typeEquals } from "../../ir/nodes.js";
1
+ import { arrayOf, BOOL, BYTES_U8, bytesOf, canMarshalFuncIntoIsland, CHILDSTREAM_T, DYN, F64, islandPromisePayloadTag, isRefCounted, isUnitType, MAY_THROW_LIB_FNS, RUNTIME_ERROR_CLASSES, STRING, typeEquals } from "../../ir/nodes.js";
2
2
  import { boxAccess, BYTES_NUM_KIND_C, BYTES_NUM_VAR_C, bytesElemKindC, cDecl, cFnPtrCast, cNumberLiteral, cStringLiteral, cType, DV_GET_KIND_C, DV_SET_KIND_C, elemAccess, mapKeyAccess, mapKeyKindC, mapValKindC, retainCallC, vAdapters } from "./emit-types.js";
3
3
  import { mangleClassNew, mangleClassRetain, mangleClassStruct, mangleField, mangleFnClosure, mangleFunction, mangleGlobal, mangleLocal, mangleRecordNew, mangleRecordStruct, mangleVtStruct } from "../mangle.js";
4
4
  import { OVERFLOW_MEMBER } from "./emit-shapes.js";
@@ -190,7 +190,7 @@ export function emitExpr(E, e) {
190
190
  return E.emitExpr(e.result);
191
191
  }
192
192
  case "dynDestrCheck": {
193
- // RequireObjectCoercible with V8's destructuring TypeError. DOM
193
+ // RequireObjectCoercible with V8's destructuring TypeError. dyn
194
194
  // values check in the runtime helper and pass through unchanged
195
195
  // (same temp, same ownership); island values check in the engine
196
196
  // (a fresh +1 cell for the same value comes back).
@@ -207,7 +207,7 @@ export function emitExpr(E, e) {
207
207
  }
208
208
  case "dynIterN": {
209
209
  // GetIterator + first-N steps as a fresh array (V8's exact
210
- // not-iterable TypeError on non-iterables): the DOM helper for
210
+ // not-iterable TypeError on non-iterables): the dyn helper for
211
211
  // dyn operands, the engine's real iterator protocol for island
212
212
  // ones.
213
213
  const v = E.emitExpr(e.value);
@@ -301,11 +301,11 @@ export function emitExpr(E, e) {
301
301
  E.currentFrame().push({ name, type: e.type });
302
302
  return { name, type: e.type };
303
303
  }
304
- // A dyn (DOM) receiver — the `rawName?.match(re)` step: the nullish
304
+ // A dyn (dyn) receiver — the `rawName?.match(re)` step: the nullish
305
305
  // test reads the node's kind tag; the unit path is the undefined
306
- // DOM singleton (dyn results) or nothing (void bodies), the body
306
+ // dyn singleton (dyn results) or nothing (void bodies), the body
307
307
  // runs over the bound receiver otherwise (the validated dynamic
308
- // dispatch, its result converted back into the DOM by the
308
+ // dispatch, its result converted back into the checked-dynamic tree by the
309
309
  // frontend's dynFrom wrap).
310
310
  if (e.receiver.type.kind === "dyn") {
311
311
  const r = E.emitExpr(e.receiver);
@@ -381,7 +381,7 @@ export function emitExpr(E, e) {
381
381
  return { name: "", type: e.type };
382
382
  }
383
383
  // A dyn-typed chain (`pricing?.[key]` over an unknown-valued index
384
- // signature): the unit path is the undefined DOM value — dyn
384
+ // signature): the unit path is the undefined dyn value — dyn
385
385
  // represents undefined directly, no union wrapper exists.
386
386
  if (e.type.kind === "dyn") {
387
387
  const name = `sc_t${E.tempCounter++}`;
@@ -441,14 +441,25 @@ export function emitExpr(E, e) {
441
441
  E.line(`${cDecl(e.type, name)};`);
442
442
  E.line(`if (${E.unionTruthyHelper(e.left.type.unionId)}(${l.name})) {`);
443
443
  E.indent++;
444
- const arm = e.type;
445
- const read = arm.kind === "f64"
446
- ? `scr_union_get_f64(${l.name})`
447
- : arm.kind === "bool"
448
- ? `scr_union_get_bool(${l.name})`
449
- : retainCallC(arm, `(${cType(arm).trim()})scr_union_peek(${l.name})`);
450
- E.line(`${name} = ${read};`);
451
- E.releaseValue(l.name, e.left.type);
444
+ if (e.retag !== undefined) {
445
+ // The helper CONSUMES the left box (callees own their params), so
446
+ // no release on this side — the falsy side still owns and frees it.
447
+ // An unwind here produces the NULL dummy and never reaches the
448
+ // frame push below, so the slot needs no early registration.
449
+ E.line(`${name} = ${E.callTargetC(e.retag)}(${l.name});`);
450
+ if (E.mayThrow.has(e.retag))
451
+ E.emitPendingCheck();
452
+ }
453
+ else {
454
+ const arm = e.type;
455
+ const read = arm.kind === "f64"
456
+ ? `scr_union_get_f64(${l.name})`
457
+ : arm.kind === "bool"
458
+ ? `scr_union_get_bool(${l.name})`
459
+ : retainCallC(arm, `(${cType(arm).trim()})scr_union_peek(${l.name})`);
460
+ E.line(`${name} = ${read};`);
461
+ E.releaseValue(l.name, e.left.type);
462
+ }
452
463
  E.indent--;
453
464
  E.line(`} else {`);
454
465
  E.indent++;
@@ -578,7 +589,7 @@ export function emitExpr(E, e) {
578
589
  return E.newTemp(e.type, `scr_caught_to_string(${v.name})`);
579
590
  }
580
591
  if (v.type.kind === "dyn") {
581
- // String(unknown): dispatch over the DOM kind (dynToStrHelper —
592
+ // String(unknown): dispatch over the dyn kind (dynToStrHelper —
582
593
  // Node's String() incl. arrays-join and "[object Object]").
583
594
  return E.newTemp(e.type, `${E.dynToStrHelper()}(${v.name})`);
584
595
  }
@@ -1597,10 +1608,10 @@ export function emitExpr(E, e) {
1597
1608
  return E.newTemp(e.type, `scr_map_keys_js_order(${obj.name}->${OVERFLOW_MEMBER})`);
1598
1609
  }
1599
1610
  case "dynFrom": {
1600
- // Static value → fresh DOM tree (+1) through the interned per-type
1611
+ // Static value → fresh dyn tree (+1) through the interned per-type
1601
1612
  // converter; the operand stays borrowed (frame-released as usual).
1602
1613
  // Bare unit literals (an `undefined`/`null` stored under an
1603
- // `unknown` index signature) are the DOM unit values directly.
1614
+ // `unknown` index signature) are the dyn unit values directly.
1604
1615
  if (e.value.kind === "unitLit") {
1605
1616
  return E.newTemp(e.type, e.value.unit === "undefined"
1606
1617
  ? "scr_dyn_retain(scr_dyn_undefined())"
@@ -1608,7 +1619,7 @@ export function emitExpr(E, e) {
1608
1619
  }
1609
1620
  const v = E.emitExpr(e.value);
1610
1621
  if (v.type.kind === "func") {
1611
- // A closure boxes as the DOM's function kind: retained closure +
1622
+ // A closure boxes as the checked-dynamic tree's function kind: retained closure +
1612
1623
  // the per-signature call thunk + the interned signature key. The
1613
1624
  // best-effort name rides along for inspect/error rendering (NULL
1614
1625
  // when the lowering had none).
@@ -1620,8 +1631,8 @@ export function emitExpr(E, e) {
1620
1631
  return E.newTemp(e.type, `${E.toDynHelper(v.type)}(${v.name})`);
1621
1632
  }
1622
1633
  case "dynFromJsval": {
1623
- // Island value → DOM: the by-reference wrap (scr_dyn_from_jsval
1624
- // retains the cell in; engine scalars normalize to native DOM
1634
+ // Island value → dyn: the by-reference wrap (scr_dyn_from_jsval
1635
+ // retains the cell in; engine scalars normalize to native dyn
1625
1636
  // kinds at wrap time). Operand borrowed, result +1, never throws.
1626
1637
  const v = E.emitExpr(e.value);
1627
1638
  return E.newTemp(e.type, `scr_dyn_from_jsval(${v.name})`);
@@ -1635,11 +1646,11 @@ export function emitExpr(E, e) {
1635
1646
  const callee = E.emitExpr(e.callee);
1636
1647
  const what = cStringLiteral(Buffer.from(e.calleeName, "utf8"));
1637
1648
  if (e.spreads !== undefined && e.spreads.length > 0) {
1638
- // The RUNTIME-ARITY form (`f(...args)`): one fresh DOM array
1649
+ // The RUNTIME-ARITY form (`f(...args)`): one fresh dyn array
1639
1650
  // collects the arguments left-to-right — plain args move in
1640
1651
  // (push takes ownership), spread args FLATTEN (push_spread
1641
1652
  // retains elements in and throws V8's spread-call TypeError for
1642
- // non-iterable DOM kinds, checked per spread — JS's
1653
+ // non-iterable dyn kinds, checked per spread — JS's
1643
1654
  // ArgumentListEvaluation order) — then apply calls through the
1644
1655
  // array's elements (borrowed, exactly scr_dyn_call).
1645
1656
  const spreadAt = new Map(e.spreads.map((s) => [s.arg, s.what]));
@@ -1685,7 +1696,7 @@ export function emitExpr(E, e) {
1685
1696
  return E.fallibleTemp(e.type, `scr_dyn_invoke(${recv.name}, ${method}, ${argsExpr}, ${args.length}, ${what})`);
1686
1697
  }
1687
1698
  case "dynArrLit": {
1688
- // A DOM array built element-by-element: ownership of each dyn
1699
+ // A dyn array built element-by-element: ownership of each dyn
1689
1700
  // element MOVES into the array (scr_dyn_arr_push's contract).
1690
1701
  const arr = E.newTemp(e.type, "scr_dyn_new_arr()");
1691
1702
  for (const el of e.elems) {
@@ -1696,7 +1707,7 @@ export function emitExpr(E, e) {
1696
1707
  return arr;
1697
1708
  }
1698
1709
  case "dynObjLit": {
1699
- // A DOM object built member-by-member: key then value, source
1710
+ // A dyn object built member-by-member: key then value, source
1700
1711
  // order (JS's literal evaluation). scr_dyn_key_set BORROWS all
1701
1712
  // three (the member retains the value in), so key/value temps
1702
1713
  // release with the frame as usual; the receiver is a fresh OBJ,
@@ -1890,7 +1901,7 @@ export function emitExpr(E, e) {
1890
1901
  return E.newTemp(e.type, `${u.name}->tag ${e.negated ? "!=" : "=="} ${e.tag}`);
1891
1902
  }
1892
1903
  case "dynKeyGet": {
1893
- // Keyed read on the DOM through the one interned helper — the
1904
+ // Keyed read on the checked-dynamic tree through the one interned helper — the
1894
1905
  // non-optional form throws JS's TypeError on an undefined/null
1895
1906
  // receiver, and HANDLE receivers can throw the loud unmodeled-
1896
1907
  // property ladder on EITHER form, so both ride a fallible temp;
@@ -1927,7 +1938,7 @@ export function emitExpr(E, e) {
1927
1938
  const r = E.emitExpr(e.right);
1928
1939
  const [d, s, st] = e.left.type.kind === "dyn" ? [l, r, e.right.type] : [r, l, e.left.type];
1929
1940
  const test = st.kind === "dyn"
1930
- ? // dyn vs dyn: whole-DOM strict equality (scalars by value,
1941
+ ? // dyn vs dyn: whole-dyn strict equality (scalars by value,
1931
1942
  // units by kind, reference kinds by node identity).
1932
1943
  `scr_dyn_strict_eq(${l.name}, ${r.name})`
1933
1944
  : st.kind === "string"
@@ -1938,7 +1949,7 @@ export function emitExpr(E, e) {
1938
1949
  return E.newTemp(e.type, e.negated ? `!${test}` : test);
1939
1950
  }
1940
1951
  case "dynTest": {
1941
- // A pure kind compare on the DOM node — borrowed; only the truthy
1952
+ // A pure kind compare on the dyn node — borrowed; only the truthy
1942
1953
  // form also reads a scalar payload. ISLAND-held nodes (the jsval
1943
1954
  // kind — engine objects/arrays/functions only, scalars normalize
1944
1955
  // at wrap time) route the tests that depend on the engine's
@@ -1954,20 +1965,20 @@ export function emitExpr(E, e) {
1954
1965
  // engine's own typeof.
1955
1966
  `(${d.name}->kind == SCR_DYN_OBJ || ${d.name}->kind == SCR_DYN_ARR || ${d.name}->kind == SCR_DYN_BYTES || ${d.name}->kind == SCR_DYN_HANDLE || ${d.name}->kind == SCR_DYN_PROMISE || ${d.name}->kind == SCR_DYN_NULL || scr_dyn_isl_typeof_is(${d.name}, "object"))`
1956
1967
  : e.test === "truthy"
1957
- ? // ToBoolean over the DOM: bool by value; number falsy for
1968
+ ? // ToBoolean over the checked-dynamic tree: bool by value; number falsy for
1958
1969
  // 0, -0 (== 0 in C), and NaN (self-inequality); string
1959
1970
  // falsy when empty; obj/arr/bytes/func/handle always true;
1960
1971
  // JSVAL through the runtime's routed arm (the bigint 0n
1961
1972
  // edge); the remaining kinds (undefined, null) always false.
1962
1973
  `(${d.name}->kind == SCR_DYN_BOOL ? ${d.name}->v.b : ${d.name}->kind == SCR_DYN_NUM ? (${d.name}->v.num == ${d.name}->v.num && ${d.name}->v.num != 0) : ${d.name}->kind == SCR_DYN_STR ? ${d.name}->v.str->len != 0 : ${d.name}->kind == SCR_DYN_JSVAL ? scr_dyn_truthy(${d.name}) : (${d.name}->kind == SCR_DYN_OBJ || ${d.name}->kind == SCR_DYN_ARR || ${d.name}->kind == SCR_DYN_BYTES || ${d.name}->kind == SCR_DYN_FUNC || ${d.name}->kind == SCR_DYN_HANDLE || ${d.name}->kind == SCR_DYN_PROMISE))`
1963
1974
  : e.test === "error"
1964
- ? // `u instanceof Error`: the DOM's error encoding — an
1975
+ ? // `u instanceof Error`: the checked-dynamic tree's error encoding — an
1965
1976
  // object carrying the reserved "%error" marker key
1966
1977
  // (built by caughtToDyn for Error payloads) — or a real
1967
1978
  // engine Error held by reference.
1968
1979
  `((${d.name}->kind == SCR_DYN_OBJ && scr_dyn_obj_get(${d.name}, "%error", 6) != NULL) || scr_dyn_isl_is_error(${d.name}))`
1969
1980
  : e.test === "array"
1970
- ? // Array.isArray: the DOM's array kind, or the engine's
1981
+ ? // Array.isArray: the checked-dynamic tree's array kind, or the engine's
1971
1982
  // own answer for an engine-held value.
1972
1983
  `(${d.name}->kind == SCR_DYN_ARR || scr_dyn_isl_is_array(${d.name}))`
1973
1984
  : e.test === "function"
@@ -2030,7 +2041,7 @@ export function emitExpr(E, e) {
2030
2041
  throw new Error(`emitter bug: caughtNarrow to ${e.type.kind}`);
2031
2042
  }
2032
2043
  case "caughtToDyn": {
2033
- // The caught snapshot converting to a dyn DOM value (an unknown
2044
+ // The caught snapshot converting to a dyn value (an unknown
2034
2045
  // slot) — the interned runtime-kind dispatch. Box borrowed; the
2035
2046
  // result is a fresh tree (+1). Never throws.
2036
2047
  const c = E.emitExpr(e.value);
@@ -2091,7 +2102,7 @@ export function emitExpr(E, e) {
2091
2102
  const rc = vAdapters(t);
2092
2103
  if (t.kind === "dyn") {
2093
2104
  // The thrown-dyn representation (REF + dyn adapters): catch
2094
- // bindings and the unhandled dispatch see the DOM value
2105
+ // bindings and the unhandled dispatch see the dyn value
2095
2106
  // itself — identity preserved.
2096
2107
  E.line(`scr_throw_ref(${reason.name}, &${rc.retain}, &${rc.release}, NULL);${E.srcComment(e.loc)}`);
2097
2108
  }
@@ -2230,25 +2241,37 @@ export function emitExpr(E, e) {
2230
2241
  // abandons (releases are NULL-tolerant).
2231
2242
  return finish(`(scr_jsval_cast_fail(${arg(0)}, ${arg(1)}), NULL)`);
2232
2243
  case "json.parse":
2233
- // Borrows the text; returns +1 on a fresh DOM, or throws a
2244
+ // Borrows the text; returns +1 on a fresh dyn, or throws a
2234
2245
  // catchable SyntaxError-shaped string (may-throw seed set).
2235
2246
  return finish(`scr_json_parse(${arg(0)})`);
2236
2247
  case "dyn.defineProps":
2237
- // Object.defineProperties over DOM values: both borrowed,
2248
+ // Object.defineProperties over dyn values: both borrowed,
2238
2249
  // result the target (+1); throws catchably (may-throw seed).
2239
2250
  return finish(`scr_dyn_define_props(${arg(0)}, ${arg(1)})`);
2251
+ case "dyn.hasKey":
2252
+ // `k in v` with a runtime key: the dyn presence answer (both
2253
+ // borrowed, no allocation, never throws).
2254
+ return finish(`scr_dyn_has_key(${arg(0)}, ${arg(1)})`);
2240
2255
  case "dyn.keySet":
2241
2256
  // Keyed write on a dyn receiver: all three borrowed (the
2242
2257
  // member retains the value in); throws Node's TypeErrors on
2243
2258
  // non-object receivers (may-throw seed set).
2244
2259
  return finish(`scr_dyn_key_set(${arg(0)}, ${arg(1)}, ${arg(2)})`);
2245
2260
  case "dyn.iterPack":
2246
- // Destructuring pack over a dyn source: both borrowed, fresh
2247
- // array +1; throws V8's destructuring TypeError on
2248
- // non-iterable DOM kinds (may-throw seed set).
2261
+ // Destructuring/for-of pack over a dyn source: both borrowed,
2262
+ // fresh array +1; throws V8's not-iterable TypeError on
2263
+ // non-iterable dyn kinds and drains wrapped engine values
2264
+ // through the engine's protocol (may-throw seed set).
2249
2265
  return finish(`scr_dyn_iter_pack(${arg(0)}, ${arg(1)})`);
2266
+ case "dyn.arrLen":
2267
+ // The for-of pack's length (borrowed; never throws).
2268
+ return finish(`scr_dyn_arr_len(${arg(0)})`);
2269
+ case "dyn.arrAt":
2270
+ // The for-of pack's element at index (+1; never throws — the
2271
+ // undefined singleton past the end).
2272
+ return finish(`scr_dyn_arr_at(${arg(0)}, ${arg(1)})`);
2250
2273
  case "dyn.typeof":
2251
- // Bare typeof on a dyn value: the DOM kind's JS answer (+1).
2274
+ // Bare typeof on a dyn value: the dyn kind's JS answer (+1).
2252
2275
  return finish(`scr_dyn_typeof(${arg(0)})`);
2253
2276
  case "dyn.toString":
2254
2277
  // Receiver-kind-dispatched toString (+1); throws Node's
@@ -2531,7 +2554,7 @@ export function emitExpr(E, e) {
2531
2554
  // borrows, +1 result, never throws.
2532
2555
  case "regexp.escape":
2533
2556
  return finish(`scr_regexp_escape(${arg(0)})`);
2534
- // The WHATWG base64 globals (scr_string.c): DOM arg borrowed
2557
+ // The WHATWG base64 globals (scr_string.c): dyn arg borrowed
2535
2558
  // (WebIDL ToString in the runtime), +1 string result; malformed
2536
2559
  // input throws the catchable DOMException InvalidCharacterError
2537
2560
  // (may-throw seed set). The zero-argument form always throws
@@ -3161,6 +3184,25 @@ export function emitExpr(E, e) {
3161
3184
  case "net.sockDestroy":
3162
3185
  E.line(`scr_net_sock_destroy(${arg(0)});${E.srcComment(e.loc)}`);
3163
3186
  return { name: "", type: e.type };
3187
+ case "net.sockPause":
3188
+ return finish(`scr_net_sock_pause(${arg(0)})`);
3189
+ case "net.sockResume":
3190
+ return finish(`scr_net_sock_resume(${arg(0)})`);
3191
+ case "net.sockSetNoDelay":
3192
+ return finish(`scr_net_sock_set_nodelay(${arg(0)}, ${arg(1)})`);
3193
+ case "net.sockDestroySoon":
3194
+ E.line(`scr_net_sock_destroy_soon(${arg(0)});${E.srcComment(e.loc)}`);
3195
+ return { name: "", type: e.type };
3196
+ case "net.sockBytesWritten":
3197
+ return finish(`scr_net_sock_bytes_written(${arg(0)})`);
3198
+ case "net.sockReadable":
3199
+ return finish(`scr_net_sock_readable(${arg(0)})`);
3200
+ case "net.sockOnFinish": {
3201
+ const cb = args[1];
3202
+ E.moveTemp(cb);
3203
+ E.line(`scr_net_sock_on_finish(${arg(0)}, ${cb.name});${E.srcComment(e.loc)}`);
3204
+ return { name: "", type: e.type };
3205
+ }
3164
3206
  case "net.sockPipe":
3165
3207
  E.line(`scr_net_sock_pipe(${arg(0)}, ${arg(1)});${E.srcComment(e.loc)}`);
3166
3208
  return { name: "", type: e.type };
@@ -3172,7 +3214,8 @@ export function emitExpr(E, e) {
3172
3214
  E.moveTemp(cb);
3173
3215
  const adapter = cbT.params.length === 0 ? "scr_net_data_thunk0"
3174
3216
  : cbT.params[0].kind === "dyn" ? "scr_net_data_thunk_dyn"
3175
- : "scr_net_data_thunk_bytes";
3217
+ : cbT.params[0].kind === "string" ? "scr_net_data_thunk_str"
3218
+ : "scr_net_data_thunk_bytes";
3176
3219
  E.line(`scr_net_sock_on_data(${arg(0)}, ${cb.name}, &${adapter}, ${arg(2)});${E.srcComment(e.loc)}`);
3177
3220
  return { name: "", type: e.type };
3178
3221
  }
@@ -3398,7 +3441,8 @@ export function emitExpr(E, e) {
3398
3441
  E.moveTemp(cb);
3399
3442
  const adapter = cbT.params.length === 0 ? "scr_net_data_thunk0"
3400
3443
  : cbT.params[0].kind === "dyn" ? "scr_net_data_thunk_dyn"
3401
- : "scr_net_data_thunk_bytes";
3444
+ : cbT.params[0].kind === "string" ? "scr_net_data_thunk_str"
3445
+ : "scr_net_data_thunk_bytes";
3402
3446
  E.line(`scr_http_req_on_data(${arg(0)}, ${cb.name}, &${adapter}, ${arg(2)});${E.srcComment(e.loc)}`);
3403
3447
  return { name: "", type: e.type };
3404
3448
  }
@@ -3718,6 +3762,25 @@ export function emitExpr(E, e) {
3718
3762
  }
3719
3763
  return finish(`scr_http_request(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)}, ${arg(6)}, ${cbExpr}, ${adapter})`);
3720
3764
  }
3765
+ case "http.agentNew":
3766
+ E.usesTimers = true; // queued dials hold the loop open
3767
+ return finish(`scr_http_agent_new(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)}, ${arg(6)})`);
3768
+ case "http.requestAgent":
3769
+ case "http.requestAgentCb": {
3770
+ E.usesTimers = true;
3771
+ let cbExpr = "NULL";
3772
+ let adapter = "NULL";
3773
+ if (e.fn === "http.requestAgentCb") {
3774
+ const cbT = e.args[8].type;
3775
+ if (cbT.kind !== "func")
3776
+ throw new Error("emitter bug: http.requestAgentCb callback not a func");
3777
+ const cb = args[8];
3778
+ E.moveTemp(cb);
3779
+ cbExpr = cb.name;
3780
+ adapter = cbT.params.length === 0 ? "&scr_http_resp_thunk0" : "&scr_http_resp_thunk_res";
3781
+ }
3782
+ return finish(`scr_http_request_agent(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)}, ${arg(6)}, ${arg(7)}, ${cbExpr}, ${adapter})`);
3783
+ }
3721
3784
  case "http.requestUrl":
3722
3785
  case "http.requestUrlCb": {
3723
3786
  E.usesTimers = true; // an in-flight request holds the loop open
@@ -3884,6 +3947,42 @@ export function emitExpr(E, e) {
3884
3947
  // 'stream'/'session' listeners, exactly the h2c surface.
3885
3948
  E.usesTimers = true;
3886
3949
  return finish(`scr_http2_create_secure_server((const char *)${arg(0)}->data, ${arg(0)}->len, (const char *)${arg(1)}->data, ${arg(1)}->len)`);
3950
+ case "http2.createSecureServerReq":
3951
+ case "http2.createSecureServerH2Req": {
3952
+ // createSecureServer(options, handler): the eager COMPAT
3953
+ // handler is the first 'request' listener on either flavor
3954
+ // (the createServerReq adapter family).
3955
+ E.usesTimers = true;
3956
+ const cbT = e.args[2].type;
3957
+ if (cbT.kind !== "func")
3958
+ throw new Error(`emitter bug: ${e.fn} handler not a func`);
3959
+ const cb = args[2];
3960
+ E.moveTemp(cb);
3961
+ const adapter = cbT.params.length === 2 ? "scr_http_handler_thunk2"
3962
+ : cbT.params.length === 1 ? "scr_http_handler_thunk1"
3963
+ : "scr_http_handler_thunk0";
3964
+ const certKey = `(const char *)${arg(0)}->data, ${arg(0)}->len, (const char *)${arg(1)}->data, ${arg(1)}->len`;
3965
+ return finish(fn === "http2.createSecureServerReq"
3966
+ ? `scr_https_create_server(${certKey}, ${cb.name}, &${adapter})`
3967
+ : `scr_http2_create_secure_server_req(${certKey}, ${cb.name}, &${adapter})`);
3968
+ }
3969
+ case "http2.createSecureServerDyn":
3970
+ // The runtime options record: allowHTTP1/cert/key read at
3971
+ // runtime (may-throw — the divergence-66 walk).
3972
+ E.usesTimers = true;
3973
+ return finish(`scr_http2_create_secure_server_dyn(${arg(0)}, NULL, NULL)`);
3974
+ case "http2.createSecureServerDynCb": {
3975
+ E.usesTimers = true;
3976
+ const cbT = e.args[1].type;
3977
+ if (cbT.kind !== "func")
3978
+ throw new Error("emitter bug: createSecureServerDynCb handler not a func");
3979
+ const cb = args[1];
3980
+ E.moveTemp(cb);
3981
+ const adapter = cbT.params.length === 2 ? "scr_http_handler_thunk2"
3982
+ : cbT.params.length === 1 ? "scr_http_handler_thunk1"
3983
+ : "scr_http_handler_thunk0";
3984
+ return finish(`scr_http2_create_secure_server_dyn(${arg(0)}, ${cb.name}, &${adapter})`);
3985
+ }
3887
3986
  case "http2.createSecureServerSni": {
3888
3987
  // The SNI form: the runtime parses each connection's
3889
3988
  // ClientHello for server_name BEFORE the handshake, calls the
@@ -3934,6 +4033,15 @@ export function emitExpr(E, e) {
3934
4033
  case "tls.caCertsChk":
3935
4034
  // Always throws (validation error or the trailing fence).
3936
4035
  return finish(`(scr_tls_ca_certs_chk(${arg(0)}, ${arg(1)}), ${isRefCounted(e.type) ? `(${cType(e.type).trim()})NULL` : "0"})`);
4036
+ // The CA-store introspection unit (scr_tls_ca.c): cached
4037
+ // per-type PEM string arrays (+1 retained answers), and the
4038
+ // default-set replacement. get/set are may-throw seeds.
4039
+ case "tlsca.get":
4040
+ return finish(`scr_tls_ca_get(${arg(0)})`);
4041
+ case "tlsca.root":
4042
+ return finish(`scr_tls_ca_root()`);
4043
+ case "tlsca.set":
4044
+ return finish(`scr_tls_ca_set_default(${arg(0)})`);
3937
4045
  case "http.serverOnRequest": {
3938
4046
  const cbT = e.args[1].type;
3939
4047
  if (cbT.kind !== "func")
@@ -4166,7 +4274,8 @@ export function emitExpr(E, e) {
4166
4274
  E.moveTemp(cb);
4167
4275
  const adapter = cbT.params.length === 0 ? "scr_net_data_thunk0"
4168
4276
  : cbT.params[0].kind === "dyn" ? "scr_net_data_thunk_dyn"
4169
- : "scr_net_data_thunk_bytes";
4277
+ : cbT.params[0].kind === "string" ? "scr_net_data_thunk_str"
4278
+ : "scr_net_data_thunk_bytes";
4170
4279
  E.line(`scr_http2_stream_on_data(${arg(0)}, ${cb.name}, &${adapter}, ${arg(2)});${E.srcComment(e.loc)}`);
4171
4280
  return { name: "", type: e.type };
4172
4281
  }
@@ -4232,6 +4341,22 @@ export function emitExpr(E, e) {
4232
4341
  }
4233
4342
  return finish(`scr_https_request(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)}, ${arg(6)}, ${arg(7)}, (const char *)${arg(8)}->data, ${arg(8)}->len, ${cbExpr}, ${adapter})`);
4234
4343
  }
4344
+ case "https.requestAgent":
4345
+ case "https.requestAgentCb": {
4346
+ E.usesTimers = true; // an in-flight request holds the loop open
4347
+ let cbExpr = "NULL";
4348
+ let adapter = "NULL";
4349
+ if (e.fn === "https.requestAgentCb") {
4350
+ const cbT = e.args[10].type;
4351
+ if (cbT.kind !== "func")
4352
+ throw new Error("emitter bug: https.requestAgentCb callback not a func");
4353
+ const cb = args[10];
4354
+ E.moveTemp(cb);
4355
+ cbExpr = cb.name;
4356
+ adapter = cbT.params.length === 0 ? "&scr_http_resp_thunk0" : "&scr_http_resp_thunk_res";
4357
+ }
4358
+ return finish(`scr_https_request_agent(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)}, ${arg(6)}, ${arg(7)}, (const char *)${arg(8)}->data, ${arg(8)}->len, ${arg(9)}, ${cbExpr}, ${adapter})`);
4359
+ }
4235
4360
  case "https.requestFn":
4236
4361
  case "https.requestFnCb": {
4237
4362
  // The requestFn binding's runtime dial: arg 0 picks the client
@@ -4501,7 +4626,16 @@ export function emitExpr(E, e) {
4501
4626
  case "process.onUnhandledRejection":
4502
4627
  // The report at loop end dispatches the listeners.
4503
4628
  E.usesTimers = true;
4504
- return finish(`scr_process_on_unhandled_rejection(${arg(0)})`);
4629
+ return finish(`scr_process_on_unhandled_rejection(${arg(0)}, ${arg(1)})`);
4630
+ case "process.offUnhandledRejection":
4631
+ return finish(`scr_process_off_unhandled_rejection(${arg(0)})`);
4632
+ case "process.onRejectionHandled":
4633
+ // Fires (if ever) during the loop-end report's listener
4634
+ // dispatch — the loop must be live for the report to run.
4635
+ E.usesTimers = true;
4636
+ return finish(`scr_process_on_rejection_handled(${arg(0)}, ${arg(1)})`);
4637
+ case "process.offRejectionHandled":
4638
+ return finish(`scr_process_off_rejection_handled(${arg(0)})`);
4505
4639
  case "fsp.readFile":
4506
4640
  return finish(`scr_fsp_read_file(${arg(0)})`);
4507
4641
  case "fsp.writeFile":
@@ -4797,7 +4931,7 @@ export function emitExpr(E, e) {
4797
4931
  // Borrowed receiver; +1 "name: message" (Node's toString rules).
4798
4932
  return finish(`scr_error_to_string(${arg(0)})`);
4799
4933
  case "error.newDom":
4800
- // new DOMException(message?, nameOrOptions?) — both DOM args
4934
+ // new DOMException(message?, nameOrOptions?) — both dyn args
4801
4935
  // borrowed (WebIDL resolution runs in the runtime); +1
4802
4936
  // %DOMException. Never throws.
4803
4937
  return finish(`scr_domex_new(${arg(0)}, ${arg(1)})`);
@@ -4808,7 +4942,7 @@ export function emitExpr(E, e) {
4808
4942
  // `'cause' in e` — the options form's own-property record.
4809
4943
  return finish(`scr_domex_has_cause(${arg(0)})`);
4810
4944
  case "error.domCause":
4811
- // +1 cause DOM value (the DOM undefined when absent).
4945
+ // +1 cause dyn value (the dyn undefined when absent).
4812
4946
  return finish(`scr_domex_cause(${arg(0)})`);
4813
4947
  case "error.domClone":
4814
4948
  // WebIDL serialization: name/message copy, code re-derives.
@@ -4818,7 +4952,7 @@ export function emitExpr(E, e) {
4818
4952
  case "dyn.objKeys":
4819
4953
  return finish(`scr_dyn_obj_keys(${arg(0)})`);
4820
4954
  case "dyn.assign":
4821
- // Object.assign over DOM values: own members copy, the target
4955
+ // Object.assign over dyn values: own members copy, the target
4822
4956
  // returns (+1); non-object receivers throw like Node.
4823
4957
  return finish(`scr_dyn_assign(${arg(0)}, ${arg(1)})`);
4824
4958
  case "dyn.packPush":
@@ -4843,7 +4977,7 @@ export function emitExpr(E, e) {
4843
4977
  // (+1). Never throws.
4844
4978
  return finish(`scr_dyn_new_obj_null_proto()`);
4845
4979
  case "dyn.hasOwn":
4846
- // Object.hasOwn over a DOM receiver (throws on nullish, like
4980
+ // Object.hasOwn over a dyn receiver (throws on nullish, like
4847
4981
  // Node's ToObject).
4848
4982
  return finish(`scr_dyn_has_own(${arg(0)}, ${arg(1)})`);
4849
4983
  case "dyn.objValues":
@@ -4851,11 +4985,11 @@ export function emitExpr(E, e) {
4851
4985
  case "dyn.objEntries":
4852
4986
  return finish(`scr_dyn_obj_entries(${arg(0)})`);
4853
4987
  case "dyn.errInstanceof":
4854
- // The from_error cache resolves the DOM value to its runtime
4988
+ // The from_error cache resolves the dyn value to its runtime
4855
4989
  // error; the class's stamped interval answers. Never throws.
4856
4990
  return finish(`scr_dyn_err_instanceof(${arg(0)}, ${arg(1)})`);
4857
4991
  case "dyn.structuredClone":
4858
- // Deep DOM clone (+1); option/DataClone/cycle errors throw
4992
+ // Deep dyn clone (+1); option/DataClone/cycle errors throw
4859
4993
  // (may-throw seed set). Both args borrowed.
4860
4994
  return finish(`scr_structured_clone(${arg(0)}, ${arg(1)})`);
4861
4995
  case "dyn.cloneMissing":
@@ -5410,7 +5544,7 @@ export function emitExpr(E, e) {
5410
5544
  return finish(`scr_assert_eq_sym(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)})`);
5411
5545
  case "assert.eqDyn":
5412
5546
  // The quartet over checked-dynamic operands: SameValue /
5413
- // DOM-walk deep equality, assertion_error.js messages.
5547
+ // dyn-walk deep equality, assertion_error.js messages.
5414
5548
  return finish(`scr_assert_eq_dyn(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)}, ${arg(4)}, ${arg(5)})`);
5415
5549
  case "assert.deepResult":
5416
5550
  return finish(`scr_assert_deep_result(${arg(0)}, ${arg(1)}, ${arg(2)}, ${arg(3)})`);
@@ -5675,14 +5809,14 @@ export function emitExpr(E, e) {
5675
5809
  }
5676
5810
  case "jsonStringify": {
5677
5811
  // Type-directed serialization: the STATIC type picks an emitted
5678
- // serializer (interned per type) — no DOM, no runtime dispatch. The
5812
+ // serializer (interned per type) — no dyn, no runtime dispatch. The
5679
5813
  // value temp is BORROWED (released with this statement's frame);
5680
5814
  // the result string is owned (+1). Throws only over CYCLE-CAPABLE
5681
5815
  // types (recursive records — the circular-structure TypeError) and
5682
5816
  // dyn roots; everything else keeps the throw-free path.
5683
5817
  const v = E.emitExpr(e.value);
5684
- // A dyn root: the runtime's DOM walker (scr_dyn_format_j — the %j
5685
- // serializer IS JSON.stringify over the DOM: number/string/bool/
5818
+ // A dyn root: the runtime's dyn walker (scr_dyn_format_j — the %j
5819
+ // serializer IS JSON.stringify over the checked-dynamic tree: number/string/bool/
5686
5820
  // null/array/object exact, dropped members omitted, a dropped ROOT
5687
5821
  // becomes the text "undefined", a runtime handle inside the tree
5688
5822
  // throws) — fallible, so the pending-exception check runs.
@@ -5714,7 +5848,7 @@ export function emitExpr(E, e) {
5714
5848
  return E.newTemp(e.type, `${E.jsonIndentHelper()}(${compact.name}, ${cStringLiteral(bytes)}, ${bytes.length})`);
5715
5849
  }
5716
5850
  case "dynCheck": {
5717
- // The dynamic boundary: validate the DOM against the target type
5851
+ // The dynamic boundary: validate the checked-dynamic tree against the target type
5718
5852
  // and BUILD the typed value (+1) — or throw a catchable
5719
5853
  // TypeError-shaped, path-annotated string. The dyn temp is BORROWED;
5720
5854
  // the result joins the frame BEFORE the pending check so an unwind
@@ -5866,7 +6000,7 @@ export function emitExpr(E, e) {
5866
6000
  return { name: "", type: e.type };
5867
6001
  }
5868
6002
  case "dyn":
5869
- // The DOM-crossing await: void fulfillments (a boxed
6003
+ // The checked-dynamic tree-crossing await: void fulfillments (a boxed
5870
6004
  // promise<void> that skipped its adapter) answer the
5871
6005
  // undefined VALUE, never NULL.
5872
6006
  read = `scr_await_dyn(${pr.name})`;
@@ -6071,7 +6205,7 @@ export function emitExpr(E, e) {
6071
6205
  case "string":
6072
6206
  return E.newTemp(e.type, `scr_jsval_from_str(${v.name})`);
6073
6207
  case "dyn":
6074
- // A CHECKED-DYNAMIC (DOM) value entering the island: deep
6208
+ // A CHECKED-DYNAMIC (dyn) value entering the island: deep
6075
6209
  // copy, data kinds only — boxed functions/handles/promises
6076
6210
  // throw the catchable TypeError in the runtime.
6077
6211
  return E.fallibleTemp(e.type, `scr_jsval_from_dyn(${v.name})`);
@@ -6082,6 +6216,20 @@ export function emitExpr(E, e) {
6082
6216
  case "url":
6083
6217
  // A URL crossing IN: an engine URL instance built from href.
6084
6218
  return E.fallibleTemp(e.type, `scr_jsval_from_url(${v.name})`);
6219
+ case "promise": {
6220
+ // A STATIC promise crossing IN: a real engine thenable
6221
+ // settled when the scriptc promise settles (the async-
6222
+ // callback return bridge). from_promise takes ownership of a
6223
+ // +1 — retain past the borrowed frame temp.
6224
+ const tag = islandPromisePayloadTag(e.value.type.inner);
6225
+ if (!tag)
6226
+ throw new Error("emitter bug: jsMarshal of a promise outside the bridge payload domain");
6227
+ const tagC = {
6228
+ void: "SCR_ISLP_VOID", f64: "SCR_ISLP_F64", bool: "SCR_ISLP_BOOL",
6229
+ string: "SCR_ISLP_STR", jsval: "SCR_ISLP_JSVAL", jsvalArr: "SCR_ISLP_JSVAL_ARR",
6230
+ }[tag];
6231
+ return E.fallibleTemp(e.type, `scr_jsval_from_promise(scr_promise_retain(${v.name}), ${tagC})`);
6232
+ }
6085
6233
  case "func": {
6086
6234
  // A closure entering the island as a host function (the
6087
6235
  // package-callback pattern). from_closure retains the closure;
@@ -6258,10 +6406,19 @@ export function emitExpr(E, e) {
6258
6406
  // emits u8 targets (canExitIslandToType).
6259
6407
  return E.fallibleTemp(e.type, `scr_jsval_exit_bytes(${v.name})`);
6260
6408
  default: {
6409
+ // `any[]`-declared slot: the engine array exits Array.isArray-
6410
+ // gated, elements BY REFERENCE (identity crosses; the spine is
6411
+ // a snapshot copy). JSON-safe element types keep the round
6412
+ // trip below.
6413
+ if (e.type.kind === "array" && e.type.elem.kind === "jsval") {
6414
+ return E.fallibleTemp(e.type, `scr_jsval_exit_jsval_arr(${v.name})`);
6415
+ }
6261
6416
  // An undefined-armed union target: the engine's undefined takes
6262
6417
  // the undefined arm FIRST — JSON cannot spell it (to_json would
6263
6418
  // refuse the exit) — then null and data ride the round trip
6264
- // into the union's dynCheck like any composite.
6419
+ // into the union's dynCheck like any composite (or, for the
6420
+ // `any[] | undefined` defaulted-parameter spelling, the
6421
+ // jsval-element array exit wrapped into the data arm).
6265
6422
  const undefTag = e.type.kind === "union" ? E.undefinedArmTag(e.type) : -1;
6266
6423
  if (e.type.kind === "union" && undefTag >= 0) {
6267
6424
  const name = `sc_t${E.tempCounter++}`;
@@ -6273,11 +6430,23 @@ export function emitExpr(E, e) {
6273
6430
  E.line(`} else {`);
6274
6431
  E.indent++;
6275
6432
  E.frames.push([]);
6276
- const json = E.fallibleTemp(STRING, `scr_jsval_to_json(${v.name})`);
6277
- const dom = E.fallibleTemp(DYN, `scr_json_parse(${json.name})`);
6278
- const out = E.fallibleTemp(e.type, `${E.dynCheckHelper(e.type)}(${dom.name}, NULL)`);
6279
- E.moveTemp(out);
6280
- E.line(`${name} = ${out.name};`);
6433
+ const unionDef = E.unionsById.get(e.type.unionId);
6434
+ const dataArms = unionDef ? unionDef.arms.flatMap((a, i) => (isUnitType(a) ? [] : [{ a, i }])) : [];
6435
+ const jsvalArr = dataArms.length === 1 && dataArms[0].a.kind === "array" && dataArms[0].a.elem.kind === "jsval" ? dataArms[0] : null;
6436
+ if (jsvalArr) {
6437
+ // The `any[] | undefined` defaulted-parameter spelling:
6438
+ // the engine array exits BY REFERENCE into the data arm.
6439
+ const arr = E.fallibleTemp(jsvalArr.a, `scr_jsval_exit_jsval_arr(${v.name})`);
6440
+ E.moveTemp(arr);
6441
+ E.line(`${name} = scr_union_new_ref(${jsvalArr.i}, ${arr.name}, &scr_arr_retain_v, &scr_arr_release_v, NULL);`);
6442
+ }
6443
+ else {
6444
+ const json = E.fallibleTemp(STRING, `scr_jsval_to_json(${v.name})`);
6445
+ const dom = E.fallibleTemp(DYN, `scr_json_parse(${json.name})`);
6446
+ const out = E.fallibleTemp(e.type, `${E.dynCheckHelper(e.type)}(${dom.name}, NULL)`);
6447
+ E.moveTemp(out);
6448
+ E.line(`${name} = ${out.name};`);
6449
+ }
6281
6450
  E.releaseFrame(E.frames.pop());
6282
6451
  E.indent--;
6283
6452
  E.line(`}`);
@@ -6299,7 +6468,9 @@ export function emitExpr(E, e) {
6299
6468
  const v = E.emitExpr(e.value);
6300
6469
  const payload = e.type.kind === "promise" && e.type.inner.kind === "void"
6301
6470
  ? "SCR_ISLP_VOID"
6302
- : "SCR_ISLP_JSVAL";
6471
+ : e.type.kind === "promise" && e.type.inner.kind === "array" && e.type.inner.elem.kind === "jsval"
6472
+ ? "SCR_ISLP_JSVAL_ARR" // `any[]` fulfillment: the Array.isArray-gated by-reference exit at settle
6473
+ : "SCR_ISLP_JSVAL";
6303
6474
  return E.fallibleTemp(e.type, `scr_jsval_bridge_promise(${v.name}, ${payload})`);
6304
6475
  }
6305
6476
  default: {