@scriptc/compiler 0.0.16 → 0.0.18

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 (64) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +4 -4
  2. package/dist/backend/cc.d.ts +5 -0
  3. package/dist/backend/cc.js +2 -0
  4. package/dist/backend/cc.js.map +1 -1
  5. package/dist/backend/emission/emit-async.js +35 -2
  6. package/dist/backend/emission/emit-async.js.map +1 -1
  7. package/dist/backend/emission/emit-exprs.js +44 -6
  8. package/dist/backend/emission/emit-exprs.js.map +1 -1
  9. package/dist/backend/emission/emitter.js +69 -11
  10. package/dist/backend/emission/emitter.js.map +1 -1
  11. package/dist/backend/emission/may-throw.d.ts +3 -3
  12. package/dist/backend/emission/may-throw.js +15 -4
  13. package/dist/backend/emission/may-throw.js.map +1 -1
  14. package/dist/backend/llvm/emitter.js +200 -21
  15. package/dist/backend/llvm/emitter.js.map +1 -1
  16. package/dist/coverage/surface-manifest.js +27 -9
  17. package/dist/coverage/surface-manifest.js.map +1 -1
  18. package/dist/frontend/lowering/lower-builtins.js +4 -7
  19. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  20. package/dist/frontend/lowering/lower-calls.d.ts +4 -4
  21. package/dist/frontend/lowering/lower-calls.js +44 -11
  22. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  23. package/dist/frontend/lowering/lower-containers.d.ts +22 -17
  24. package/dist/frontend/lowering/lower-containers.js +628 -51
  25. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  26. package/dist/frontend/lowering/lower-exprs.js +19 -1
  27. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  28. package/dist/frontend/lowering/lower-island.d.ts +2 -2
  29. package/dist/frontend/lowering/lower-island.js +57 -9
  30. package/dist/frontend/lowering/lower-island.js.map +1 -1
  31. package/dist/frontend/lowering/lower-modules.js +144 -10
  32. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  33. package/dist/frontend/lowering/lower-stmts.d.ts +8 -0
  34. package/dist/frontend/lowering/lower-stmts.js +408 -21
  35. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  36. package/dist/frontend/lowering/lowerer.d.ts +38 -0
  37. package/dist/frontend/lowering/lowerer.js +149 -2
  38. package/dist/frontend/lowering/lowerer.js.map +1 -1
  39. package/dist/frontend/lowering/surfaces.d.ts +8 -0
  40. package/dist/frontend/lowering/surfaces.js +10 -0
  41. package/dist/frontend/lowering/surfaces.js.map +1 -1
  42. package/dist/frontend/shared.d.ts +4 -0
  43. package/dist/frontend/shared.js +9 -3
  44. package/dist/frontend/shared.js.map +1 -1
  45. package/dist/frontend/ts7/program.js +5 -4
  46. package/dist/frontend/ts7/program.js.map +1 -1
  47. package/dist/index.d.ts +7 -0
  48. package/dist/index.js +7 -3
  49. package/dist/index.js.map +1 -1
  50. package/dist/ir/nodes.d.ts +53 -22
  51. package/dist/ir/nodes.js +42 -0
  52. package/dist/ir/nodes.js.map +1 -1
  53. package/dist/ir/serialize.d.ts +1 -1
  54. package/dist/ir/serialize.js +1 -1
  55. package/dist/ir/validate.js +99 -39
  56. package/dist/ir/validate.js.map +1 -1
  57. package/dist/library/fence-eval.js +9 -1
  58. package/dist/library/fence-eval.js.map +1 -1
  59. package/dist/library/int-infer.js +191 -25
  60. package/dist/library/int-infer.js.map +1 -1
  61. package/dist/library/int-infer.test.js +206 -1
  62. package/dist/library/int-infer.test.js.map +1 -1
  63. package/package.json +2 -2
  64. package/surface-manifest.json +27 -3
@@ -60,6 +60,7 @@ const LIB_FN_SYMS = {
60
60
  "dyn.errInstanceof": "scr_dyn_err_instanceof",
61
61
  "num.toExponential": "scr_num_to_exponential",
62
62
  "num.toFixed0": "scr_num_to_fixed0",
63
+ "num.toFixed": "scr_num_to_fixed",
63
64
  "num.sameValue": "scr_num_same_value",
64
65
  "intl.numFormatEnUs": "scr_intl_num_format_en_us",
65
66
  "number.isFinite": "scr_num_is_finite",
@@ -563,7 +564,7 @@ const LIB_FN_SYMS = {
563
564
  "dc.chanRunStores": "scr_dc_chan_run_stores",
564
565
  // process warning/rejection events (scr_lib.c / scr_async_dyn.c):
565
566
  // dyn listeners are borrowed (the runtime retains its copy);
566
- // onUnhandledRejection marks the loop live (the loop-end report
567
+ // onUnhandledRejection marks the loop live (the checkpoint report
567
568
  // dispatches the listeners).
568
569
  "process.onWarning": "scr_process_on_warning",
569
570
  "process.offWarning": "scr_process_off_warning",
@@ -648,12 +649,12 @@ const USES_TIMERS_LIB_FNS = new Set([
648
649
  "fs.existsChk",
649
650
  "http.createServer", "http.createServerEmpty",
650
651
  "http.request", "http.requestCb", "http.requestUrl", "http.requestUrlCb",
651
- "https.requestUrl", "https.requestUrlCb",
652
+ "https.request", "https.requestCb", "https.requestUrl", "https.requestUrlCb",
652
653
  "http.requestConn", "http.requestConnCb",
653
654
  "http.agentNew", "http.requestAgent", "http.requestAgentCb",
654
655
  // The dyn-async slice (emit-exprs.ts's markings): fiber parks, the
655
656
  // microtask/immediate mints, the tracing-promise reaction fiber, and
656
- // the loop-end unhandled-rejection report.
657
+ // the checkpoint unhandled-rejection report.
657
658
  "async.hop", "async.awaitDyn",
658
659
  "dc.tcTracePromise",
659
660
  "process.onUnhandledRejection", "process.onRejectionHandled",
@@ -1067,6 +1068,7 @@ class LlEmitter {
1067
1068
  ];
1068
1069
  };
1069
1070
  const globalReleases = globalReleaseLines("g");
1071
+ const asyncEntry = this.fnByName.get(this.mod.entry)?.async === true;
1070
1072
  const entryMayThrow = this.mayThrow.has(this.mod.entry);
1071
1073
  // The event loop runs when timers appeared OR any async/generator
1072
1074
  // function exists (the C main's hasAsync || hasGenerators ||
@@ -1076,17 +1078,26 @@ class LlEmitter {
1076
1078
  // async loop-exhaustion story.
1077
1079
  const runsLoop = this.usesTimers ||
1078
1080
  this.mod.functions.some((f) => f.async === true || f.generator !== undefined);
1079
- const uncaughtReleases = entryMayThrow ? globalReleaseLines("gu") : [];
1081
+ const uncaughtReleases = entryMayThrow && !asyncEntry ? globalReleaseLines("gu") : [];
1080
1082
  const loopReleasesU = runsLoop ? globalReleaseLines("gl") : [];
1081
1083
  const loopReleasesR = runsLoop ? globalReleaseLines("gr") : [];
1084
+ const topRejectReleases = asyncEntry ? globalReleaseLines("gt") : [];
1085
+ const topPendingReleases = asyncEntry ? globalReleaseLines("gp") : [];
1086
+ const loopReportedReleases = runsLoop ? globalReleaseLines("gq") : [];
1082
1087
  // main's epilogues read the flag / the loop entry points — declared
1083
1088
  // HERE, before the extern block flushes (a pending check usually
1084
1089
  // declared the flag already; the Set dedupes).
1085
1090
  if (entryMayThrow || runsLoop)
1086
1091
  this.declare(`declare zeroext i1 @scr_exc_pending()`);
1087
1092
  if (runsLoop) {
1088
- this.declare(`declare void @scr_loop_run()`);
1093
+ this.declare(`declare zeroext i1 @scr_loop_run(ptr)`);
1089
1094
  this.declare(`declare zeroext i1 @scr_report_unhandled_rejections()`);
1095
+ this.declare(`declare void @scr_discard_unhandled_rejections()`);
1096
+ }
1097
+ if (asyncEntry) {
1098
+ this.declare(`declare i32 @scr_promise_finish_top_level(ptr)`);
1099
+ this.declare(`declare void @scr_promise_rethrow_top_level(ptr)`);
1100
+ this.declare(`declare void @scr_promise_release(ptr)`);
1090
1101
  }
1091
1102
  // LIBRARY mode: the runtime entry points the generated library
1092
1103
  // symbols delegate to — declared before the extern block flushes.
@@ -1287,9 +1298,11 @@ class LlEmitter {
1287
1298
  ...(usesEvents ? [` call void @scr_events_install()`] : []),
1288
1299
  // fs.watch programs fill the loop's watch hooks the same way —
1289
1300
  // scr_watch.c links only when this line is emitted.
1290
- ...(usesFsWatch ? [` call void @scr_watch_install()`] : []), ...(usesFetch ? [` call void @scr_fetch_install()`] : []), ...(usesNet ? [` call void @scr_net_install()`, ` call void @scr_net_dyn_install()`] : []), ...(usesHttp ? [` call void @scr_http_dyn_install()`] : []), ...(usesStream ? [` call void @scr_stream_install()`] : []), ` call void @scr_lib_init(i32 %argc, ptr %argv)`, ` call void @${mangleFunction(this.mod.entry)}()`,
1301
+ ...(usesFsWatch ? [` call void @scr_watch_install()`] : []), ...(usesFetch ? [` call void @scr_fetch_install()`] : []), ...(usesNet ? [` call void @scr_net_install()`, ` call void @scr_net_dyn_install()`] : []), ...(usesHttp ? [` call void @scr_http_dyn_install()`] : []), ...(usesStream ? [` call void @scr_stream_install()`] : []), ` call void @scr_lib_init(i32 %argc, ptr %argv)`, ...(asyncEntry
1302
+ ? [` %top = call ptr @${mangleAsyncSpawn(this.mod.entry)}()`]
1303
+ : [` call void @${mangleFunction(this.mod.entry)}()`]),
1291
1304
  // Uncaught exception from top-level code: Node exits 1.
1292
- ...(entryMayThrow
1305
+ ...(entryMayThrow && !asyncEntry
1293
1306
  ? [
1294
1307
  ` %exc = call zeroext i1 @scr_exc_pending()`,
1295
1308
  ` br i1 %exc, label %uncaught, label %ok`,
@@ -1306,15 +1319,44 @@ class LlEmitter {
1306
1319
  // both exit 1, like Node — the C main's loop block exactly.
1307
1320
  ...(runsLoop
1308
1321
  ? [
1309
- ` call void @scr_loop_run()`,
1322
+ ` %loop_rejection = call zeroext i1 @scr_loop_run(ptr ${asyncEntry ? "%top" : "null"})`,
1310
1323
  ` %lexc = call zeroext i1 @scr_exc_pending()`,
1311
1324
  ` br i1 %lexc, label %luncaught, label %lok`,
1312
1325
  `luncaught:`,
1313
1326
  ` call void @scr_exc_print_uncaught()`,
1327
+ ...(asyncEntry ? [` call void @scr_promise_release(ptr %top)`] : []),
1314
1328
  ...exitListenerLines("xl"),
1315
1329
  ...loopReleasesU,
1316
1330
  ` ret i32 1`,
1317
1331
  `lok:`,
1332
+ ` br i1 %loop_rejection, label %lreported, label %lclean`,
1333
+ `lreported:`,
1334
+ ` call void @scr_discard_unhandled_rejections()`,
1335
+ ...(asyncEntry ? [` call void @scr_promise_release(ptr %top)`] : []),
1336
+ ...exitListenerLines("xq"),
1337
+ ...loopReportedReleases,
1338
+ ` ret i32 1`,
1339
+ `lclean:`,
1340
+ ...(asyncEntry
1341
+ ? [
1342
+ ` %tla_status = call i32 @scr_promise_finish_top_level(ptr %top)`,
1343
+ ` %tla_rejected = icmp eq i32 %tla_status, 1`,
1344
+ ` br i1 %tla_rejected, label %tla_fail, label %tla_not_rejected`,
1345
+ `tla_fail:`,
1346
+ // The loop already delivered every earlier-checkpoint
1347
+ // rejection. Drop same-checkpoint competitors before
1348
+ // surfacing the fatal module verdict.
1349
+ ` call void @scr_discard_unhandled_rejections()`,
1350
+ ` call void @scr_promise_rethrow_top_level(ptr %top)`,
1351
+ ` call void @scr_promise_release(ptr %top)`,
1352
+ ` call void @scr_exc_print_uncaught()`,
1353
+ ...exitListenerLines("xt"),
1354
+ ...topRejectReleases,
1355
+ ` ret i32 1`,
1356
+ `tla_not_rejected:`,
1357
+ ` call void @scr_promise_release(ptr %top)`,
1358
+ ]
1359
+ : []),
1318
1360
  ` %rej = call zeroext i1 @scr_report_unhandled_rejections()`,
1319
1361
  ` br i1 %rej, label %lrej, label %lrok`,
1320
1362
  `lrej:`,
@@ -1322,6 +1364,17 @@ class LlEmitter {
1322
1364
  ...loopReleasesR,
1323
1365
  ` ret i32 1`,
1324
1366
  `lrok:`,
1367
+ ...(asyncEntry
1368
+ ? [
1369
+ ` %tla_pending = icmp eq i32 %tla_status, 13`,
1370
+ ` br i1 %tla_pending, label %tla_stuck, label %tla_ok`,
1371
+ `tla_stuck:`,
1372
+ ...exitListenerLines("xp"),
1373
+ ...topPendingReleases,
1374
+ ` ret i32 13`,
1375
+ `tla_ok:`,
1376
+ ]
1377
+ : []),
1325
1378
  ]
1326
1379
  : []), ...exitListenerLines("xn"), ...globalReleases, ` ret i32 0`, `}`, ``,
1327
1380
  // sanitize_address is inert under the plain pipeline; the sanitized
@@ -1644,9 +1697,29 @@ class LlEmitter {
1644
1697
  out.push(...tr);
1645
1698
  // Spawn wrapper: pack the args (+1 moves in), spawn the fiber.
1646
1699
  const params = fieldTys.map((ty, i) => `${ty} %a${i}`);
1700
+ const cache = fn.asyncCacheGlobal !== undefined ? mangleGlobal(fn.asyncCacheGlobal) : null;
1701
+ const cycleCache = fn.asyncCycleCacheGlobal !== undefined ? mangleGlobal(fn.asyncCycleCacheGlobal) : null;
1702
+ if (cache !== null || cycleCache !== null) {
1703
+ this.declare(`declare ptr @scr_promise_retain_v(ptr)`);
1704
+ this.declare(`declare void @scr_promise_release(ptr)`);
1705
+ }
1706
+ if (cache !== null) {
1707
+ this.declare(`declare void @scr_promise_mark_handled(ptr)`);
1708
+ }
1647
1709
  const sp = [
1648
1710
  `define internal ptr @${mangleAsyncSpawn(fn.name)}(${params.join(", ")}) ${FN_ATTRS} { ; spawn ${fn.name}`,
1649
1711
  `entry:`,
1712
+ ...(cache !== null
1713
+ ? [
1714
+ ` %cached = load ptr, ptr @${cache}`,
1715
+ ` %cache_hit = icmp ne ptr %cached, null`,
1716
+ ` br i1 %cache_hit, label %cached_return, label %cache_miss`,
1717
+ `cached_return:`,
1718
+ ` %cached_owned = call ptr @scr_promise_retain_v(ptr %cached)`,
1719
+ ` ret ptr %cached_owned`,
1720
+ `cache_miss:`,
1721
+ ]
1722
+ : []),
1650
1723
  ` %ap = call ptr @malloc(i64 ${sizeOf})`,
1651
1724
  ` %isnull = icmp eq ptr %ap, null`,
1652
1725
  ` br i1 %isnull, label %oom, label %ok`,
@@ -1665,7 +1738,36 @@ class LlEmitter {
1665
1738
  const src = lifted && i === 0 ? "%env" : `%a${i}`;
1666
1739
  sp.push(` %sp${i} = getelementptr inbounds %${pack}, ptr %ap, i64 0, i32 ${i}`, ` store ${ty} ${src}, ptr %sp${i}`);
1667
1740
  });
1668
- sp.push(` %p = call ptr @scr_async_spawn(ptr @${mangleTrampoline(fn.name)}, ptr %ap)`, ` ret ptr %p`, `}`, ``);
1741
+ sp.push(` %p = call ptr @scr_async_spawn(ptr @${mangleTrampoline(fn.name)}, ptr %ap)`, ...(cache !== null
1742
+ ? [
1743
+ // The module loader owns this evaluation promise
1744
+ // immediately. A later sibling can throw before the
1745
+ // aggregate dependency wait is built, but this rejection
1746
+ // must never become an unrelated unhandled rejection.
1747
+ ` call void @scr_promise_mark_handled(ptr %p)`,
1748
+ ]
1749
+ : []), ...(cache !== null
1750
+ ? [
1751
+ ` %cache_owned = call ptr @scr_promise_retain_v(ptr %p)`,
1752
+ // The eager spawn may have re-entered this guarded module
1753
+ // through an admitted async cycle and installed a temporary
1754
+ // cache entry. Drop that owned slot before replacing it
1755
+ // with the outer evaluation promise.
1756
+ ` %replaced_cache = load ptr, ptr @${cache}`,
1757
+ ` call void @scr_promise_release(ptr %replaced_cache)`,
1758
+ ` store ptr %cache_owned, ptr @${cache}`,
1759
+ ]
1760
+ : []), ...(cycleCache !== null
1761
+ ? [
1762
+ // Eager recursive spawns publish from the inside out. The
1763
+ // runtime-requested outermost member writes last and is the
1764
+ // SCC's actual evaluation root.
1765
+ ` %cycle_cache_owned = call ptr @scr_promise_retain_v(ptr %p)`,
1766
+ ` %replaced_cycle_cache = load ptr, ptr @${cycleCache}`,
1767
+ ` call void @scr_promise_release(ptr %replaced_cycle_cache)`,
1768
+ ` store ptr %cycle_cache_owned, ptr @${cycleCache}`,
1769
+ ]
1770
+ : []), ` ret ptr %p`, `}`, ``);
1669
1771
  out.push(...sp);
1670
1772
  }
1671
1773
  out.push(...this.emitGenScaffolding());
@@ -3650,11 +3752,12 @@ class LlEmitter {
3650
3752
  case "strCmp": {
3651
3753
  const l = this.emitExpr(e.left);
3652
3754
  const r = this.emitExpr(e.right);
3653
- this.declare(`declare i32 @scr_str_cmp(ptr, ptr)`);
3755
+ const fn = e.utf16 === true ? "scr_str_cmp_u16" : "scr_str_cmp";
3756
+ this.declare(`declare i32 @${fn}(ptr, ptr)`);
3654
3757
  const c = B.tmp();
3655
3758
  const t = B.tmp();
3656
3759
  const pred = { "<": "slt", "<=": "sle", ">": "sgt", ">=": "sge" }[e.op];
3657
- B.line(`${c} = call i32 @scr_str_cmp(ptr ${l.name}, ptr ${r.name})`);
3760
+ B.line(`${c} = call i32 @${fn}(ptr ${l.name}, ptr ${r.name})`);
3658
3761
  B.line(`${t} = icmp ${pred} i32 ${c}, 0`);
3659
3762
  return { name: t, type: e.type };
3660
3763
  }
@@ -5532,6 +5635,15 @@ class LlEmitter {
5532
5635
  case "libCall":
5533
5636
  return this.emitLibCall(e);
5534
5637
  case "intrinsic": {
5638
+ if (e.name === "module.await") {
5639
+ // Internal ESM dependency wait: pending promises park the module
5640
+ // fiber, while settled ones continue synchronously.
5641
+ const p = this.emitExpr(e.args[0]);
5642
+ this.declare(`declare void @scr_module_await(ptr)`);
5643
+ B.line(`call void @scr_module_await(ptr ${p.name})`);
5644
+ this.emitPendingCheck();
5645
+ return { name: "", type: e.type };
5646
+ }
5535
5647
  if (e.name === "promise.all") {
5536
5648
  // The runtime countdown combinator (emit-exprs.ts): a pre-sized
5537
5649
  // values array filled per INPUT index as entries fulfill, plus
@@ -8051,6 +8163,33 @@ class LlEmitter {
8051
8163
  B.line(`${t} = call ptr @scr_arr_slice(ptr ${r.name}, double ${start}, double ${end})`);
8052
8164
  return this.own({ name: t, type: e.type });
8053
8165
  }
8166
+ case "toReversed": {
8167
+ this.declare(`declare ptr @scr_arr_to_reversed(ptr)`);
8168
+ const t = B.tmp();
8169
+ B.line(`${t} = call ptr @scr_arr_to_reversed(ptr ${r.name})`);
8170
+ return this.own({ name: t, type: e.type });
8171
+ }
8172
+ case "toSpliced": {
8173
+ const start = this.emitExpr(e.args[0]);
8174
+ const count = this.emitExpr(e.args[1]);
8175
+ const items = this.emitExpr(e.args[2]);
8176
+ this.declare(`declare ptr @scr_arr_to_spliced(ptr, double, double, ptr)`);
8177
+ const t = B.tmp();
8178
+ B.line(`${t} = call ptr @scr_arr_to_spliced(ptr ${r.name}, double ${start.name}, ` +
8179
+ `double ${count.name}, ptr ${items.name})`);
8180
+ return this.own({ name: t, type: e.type });
8181
+ }
8182
+ case "with": {
8183
+ const index = this.emitExpr(e.args[0]);
8184
+ const value = this.emitExpr(e.args[1]);
8185
+ this.declare(`declare ptr @scr_arr_with_${acc}(ptr, double, ${accArg})`);
8186
+ const t = B.tmp();
8187
+ B.line(`${t} = call ptr @scr_arr_with_${acc}(ptr ${r.name}, double ${index.name}, ` +
8188
+ `${accTy} ${value.name})`);
8189
+ const out = this.own({ name: t, type: e.type });
8190
+ this.emitPendingCheck();
8191
+ return out;
8192
+ }
8054
8193
  case "splice": {
8055
8194
  // The removal splice: removed elements come back as a fresh +1
8056
8195
  // array, ownership MOVED out of the receiver. An omitted count
@@ -8494,6 +8633,14 @@ class LlEmitter {
8494
8633
  // A +1 VIEW aliasing the receiver's storage (subarray / Buffer's
8495
8634
  // slice); same index defaults as slice.
8496
8635
  return call("scr_bytes_subarray", "ptr (ptr, double, double)", `ptr ${r.name}, double ${args[0]?.name ?? f64Lit(0)}, double ${args[1]?.name ?? F64_INF}`, true, false);
8636
+ case "toReversed":
8637
+ return call("scr_bytes_to_reversed", "ptr (ptr)", `ptr ${r.name}`, true, false);
8638
+ case "with":
8639
+ return call("scr_bytes_with", "ptr (ptr, double, double)", `ptr ${r.name}, double ${args[0].name}, double ${args[1].name}`, true, true);
8640
+ case "join":
8641
+ return call("scr_bytes_join", "ptr (ptr, ptr)", `ptr ${r.name}, ptr ${args[0].name}`, true, false);
8642
+ case "toArray":
8643
+ return call("scr_bytes_to_arr", "ptr (ptr)", `ptr ${r.name}`, true, false);
8497
8644
  case "setFrom":
8498
8645
  // dst.set(src, offset?) — void; throws Node's RangeError on
8499
8646
  // overflow.
@@ -10735,14 +10882,17 @@ class LlEmitter {
10735
10882
  }
10736
10883
  if (e.fn === "http.request" || e.fn === "http.requestCb" || e.fn === "http.requestUrl" || e.fn === "http.requestUrlCb" ||
10737
10884
  e.fn === "http.requestAgent" || e.fn === "http.requestAgentCb" ||
10885
+ e.fn === "https.request" || e.fn === "https.requestCb" ||
10738
10886
  e.fn === "https.requestUrl" || e.fn === "https.requestUrlCb") {
10739
10887
  // The https URL row is the http one with the TLS entry point — same
10740
- // three arguments, same response-callback adapter. (The https
10741
- // OPTIONS forms are a separate, wider row and are not here yet.)
10888
+ // three arguments, same response-callback adapter. The https options
10889
+ // row is wider: rejectUnauthorized stays an i1, while its ScrStr or
10890
+ // ScrBytes CA value expands to the runtime's raw pointer + length.
10742
10891
  const isTls = e.fn.startsWith("https.");
10743
- const isUrl = isTls || e.fn.startsWith("http.requestUrl");
10892
+ const isUrl = e.fn.includes("requestUrl");
10893
+ const isTlsOptions = isTls && !isUrl;
10744
10894
  const isAgent = e.fn.startsWith("http.requestAgent");
10745
- const cbIdx = isUrl ? 3 : isAgent ? 8 : 7;
10895
+ const cbIdx = isUrl ? 3 : isTlsOptions ? 9 : isAgent ? 8 : 7;
10746
10896
  const hasCb = e.fn.endsWith("Cb");
10747
10897
  const args = e.args.map((a) => this.emitExpr(a));
10748
10898
  let cb = "null";
@@ -10758,13 +10908,42 @@ class LlEmitter {
10758
10908
  adapter = `@${sym}`;
10759
10909
  }
10760
10910
  const head = args.slice(0, cbIdx);
10761
- const decls = head.map((a) => (this.llType(a.type) === "i1" ? "i1 zeroext" : this.llType(a.type)));
10762
- const entry = isTls ? "scr_https_request_url"
10763
- : isUrl ? "scr_http_request_url"
10764
- : isAgent ? "scr_http_request_agent" : "scr_http_request";
10765
- this.declare(`declare ptr @${entry}(${[...decls, "ptr", "ptr"].join(", ")})`);
10911
+ const entry = isTlsOptions ? "scr_https_request"
10912
+ : isTls ? "scr_https_request_url"
10913
+ : isUrl ? "scr_http_request_url"
10914
+ : isAgent ? "scr_http_request_agent" : "scr_http_request";
10915
+ let callArgs = head.map((a) => `${this.llType(a.type)} ${a.name}`);
10916
+ if (isTlsOptions) {
10917
+ const ca = args[8];
10918
+ const caLenPtr = B.tmp();
10919
+ const caLen = B.tmp();
10920
+ let caData;
10921
+ if (ca.type.kind === "string") {
10922
+ caData = B.tmp();
10923
+ B.line(`${caLenPtr} = getelementptr inbounds %ScrStr, ptr ${ca.name}, i64 0, i32 1`);
10924
+ B.line(`${caLen} = load i64, ptr ${caLenPtr}`);
10925
+ B.line(`${caData} = getelementptr inbounds i8, ptr ${ca.name}, i64 24`);
10926
+ }
10927
+ else if (ca.type.kind === "bytes" && ca.type.elem === "u8") {
10928
+ const caDataPtr = B.tmp();
10929
+ caData = B.tmp();
10930
+ B.line(`${caLenPtr} = getelementptr inbounds i8, ptr ${ca.name}, i64 8`);
10931
+ B.line(`${caLen} = load i64, ptr ${caLenPtr}`);
10932
+ B.line(`${caDataPtr} = getelementptr inbounds i8, ptr ${ca.name}, i64 24`);
10933
+ B.line(`${caData} = load ptr, ptr ${caDataPtr}`);
10934
+ }
10935
+ else {
10936
+ throw new Error(`llvm emitter bug: ${e.fn} CA is not a string or Buffer`);
10937
+ }
10938
+ callArgs = [...callArgs.slice(0, 8), `ptr ${caData}`, `i64 ${caLen}`];
10939
+ this.declare(`declare ptr @scr_https_request(ptr, double, ptr, ptr, double, ptr, i1 zeroext, i1 zeroext, ptr, i64, ptr, ptr)`);
10940
+ }
10941
+ else {
10942
+ const decls = head.map((a) => (this.llType(a.type) === "i1" ? "i1 zeroext" : this.llType(a.type)));
10943
+ this.declare(`declare ptr @${entry}(${[...decls, "ptr", "ptr"].join(", ")})`);
10944
+ }
10766
10945
  const t = B.tmp();
10767
- B.line(`${t} = call ptr @${entry}(${[...head.map((a) => `${this.llType(a.type)} ${a.name}`), `ptr ${cb}`, `ptr ${adapter}`].join(", ")})`);
10946
+ B.line(`${t} = call ptr @${entry}(${[...callArgs, `ptr ${cb}`, `ptr ${adapter}`].join(", ")})`);
10768
10947
  const out = this.own({ name: t, type: e.type });
10769
10948
  if (MAY_THROW_LIB_FNS.has(e.fn))
10770
10949
  this.emitPendingCheck();