@scriptc/compiler 0.0.8 → 0.0.10
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.
- package/ambient/scriptc-node-fallback.d.ts +13 -0
- package/dist/backend/cc.js +14 -0
- package/dist/backend/cc.js.map +1 -1
- package/dist/backend/emission/emit-exprs.js +244 -17
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emit-types.d.ts +3 -0
- package/dist/backend/emission/emit-types.js +12 -0
- package/dist/backend/emission/emit-types.js.map +1 -1
- package/dist/backend/emission/emit-walkers.d.ts +7 -5
- package/dist/backend/emission/emit-walkers.js +52 -12
- package/dist/backend/emission/emit-walkers.js.map +1 -1
- package/dist/backend/emission/emitter.d.ts +1 -1
- package/dist/backend/emission/emitter.js +30 -9
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +1 -0
- package/dist/backend/llvm/dyn.js +83 -1
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +357 -20
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +73 -14
- package/dist/diagnostics/diagnostic.js +112 -31
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/render.js +8 -0
- package/dist/diagnostics/render.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.js +11 -1
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-assert.js +16 -0
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +24 -0
- package/dist/frontend/lowering/lower-builtins.js +256 -3
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +71 -11
- package/dist/frontend/lowering/lower-calls.js +942 -18
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +27 -1
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +21 -2
- package/dist/frontend/lowering/lower-containers.js +386 -53
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +92 -17
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-emitter.js +54 -0
- package/dist/frontend/lowering/lower-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +231 -17
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +33 -2
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +25 -11
- package/dist/frontend/lowering/lower-namespaces.js +50 -15
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.js +211 -4
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +1 -5
- package/dist/frontend/lowering/lower-stmts.js +660 -19
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +92 -5
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +102 -15
- package/dist/frontend/lowering/lowerer.js +378 -30
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.js +20 -3
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm-static-rewrite.d.ts +7 -2
- package/dist/frontend/npm-static-rewrite.js +566 -138
- package/dist/frontend/npm-static-rewrite.js.map +1 -1
- package/dist/frontend/npm-static.js +11 -2
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/program.js +5 -5
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/shared.d.ts +6 -1
- package/dist/frontend/shared.js +46 -1
- package/dist/frontend/shared.js.map +1 -1
- package/dist/frontend/types.d.ts +13 -0
- package/dist/frontend/types.js +88 -9
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.js +169 -32
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +230 -12
- package/dist/ir/nodes.js +85 -6
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +109 -9
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/fence-eval.d.ts +77 -0
- package/dist/library/fence-eval.js +385 -0
- package/dist/library/fence-eval.js.map +1 -0
- package/dist/library/profile.d.ts +11 -1
- package/dist/library/profile.js +102 -18
- package/dist/library/profile.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +10 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { canMarshalFuncIntoIsland, CAUGHT, F64, islandCallbackRet, isRefCounted, isUnitType, MAY_THROW_LIB_FNS, moduleUsesDynInvoke, moduleUsesFetch, moduleUsesFsWatch, moduleUsesHttpServer, moduleUsesNet, moduleUsesProcessEvents, moduleUsesStream, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, STRING, typeEquals, typeKey, VOID } from "../../ir/nodes.js";
|
|
1
|
+
import { canMarshalFuncIntoIsland, CAUGHT, DYN, F64, islandCallbackRet, isRefCounted, isUnitType, MAY_THROW_LIB_FNS, moduleUsesDynInvoke, moduleUsesFetch, moduleUsesFsWatch, moduleUsesHttpServer, moduleUsesNet, moduleUsesProcessEvents, moduleUsesStream, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, STRING, typeEquals, typeKey, VOID } from "../../ir/nodes.js";
|
|
2
2
|
import { computeMayThrow } from "../emission/may-throw.js";
|
|
3
3
|
import { mangleArgPack, mangleAsyncSpawn, mangleClassNew, mangleClassObj, mangleClassRetain, mangleFnClosure, mangleFunction, mangleGenDrop, mangleGenResThunk, mangleGenSpawn, mangleGlobal, mangleLocal, mangleRecordNew, mangleRecordStruct, mangleResolveThunk, mangleTrampoline, mangleVtStruct, mangleWrapper } from "../mangle.js";
|
|
4
4
|
import { BlockBuilder } from "./blocks.js";
|
|
@@ -60,6 +60,8 @@ 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.sameValue": "scr_num_same_value",
|
|
64
|
+
"intl.numFormatEnUs": "scr_intl_num_format_en_us",
|
|
63
65
|
"number.isFinite": "scr_num_is_finite",
|
|
64
66
|
"number.isNaN": "scr_num_is_nan",
|
|
65
67
|
"number.isInteger": "scr_num_is_integer",
|
|
@@ -187,6 +189,19 @@ const LIB_FN_SYMS = {
|
|
|
187
189
|
"buffer.concatLen": "scr_bytes_concat_len",
|
|
188
190
|
"buffer.byteLenStr": "scr_bytes_byte_length_str",
|
|
189
191
|
"buffer.isEncoding": "scr_bytes_is_encoding",
|
|
192
|
+
// The checked-dynamic compare/equals validators (scr_bytes_io.c):
|
|
193
|
+
// Node's argument ladders throw catchably (MAY_THROW_LIB_FNS).
|
|
194
|
+
"dyn.toStringCoerce": "scr_dyn_string_coerce_js",
|
|
195
|
+
"buffer.compareChk": "scr_buffer_compare_chk",
|
|
196
|
+
"bytes.equalsChk": "scr_bytes_equals_chk",
|
|
197
|
+
"bytes.compareChk": "scr_bytes_compare_chk",
|
|
198
|
+
"buffer.newStringFail": "scr_buffer_new_string_fail",
|
|
199
|
+
"fs.toUnixTimestamp": "scr_fs_to_unix_timestamp",
|
|
200
|
+
"fs.existsChk": "scr_fs_exists_async",
|
|
201
|
+
"fs.mkdtempSyncChk": "scr_fs_mkdtemp_sync_chk",
|
|
202
|
+
"net.connectAttempt": "scr_net_connect_attempt",
|
|
203
|
+
"fs.lchmodSyncChk": "scr_fs_lchmod_sync_chk",
|
|
204
|
+
"fsp.lchmodChk": "scr_fsp_lchmod_chk",
|
|
190
205
|
"fs.readFileSyncBuf": "scr_fs_read_file_bytes",
|
|
191
206
|
"fs.readFileSyncBytes": "scr_fs_read_file_bytes",
|
|
192
207
|
"fs.writeFileSyncBytes": "scr_fs_write_file_bytes",
|
|
@@ -332,9 +347,10 @@ const LIB_FN_SYMS = {
|
|
|
332
347
|
// ambient-this read never throw. The fs dyn read is the sync-fs story.
|
|
333
348
|
"json.parse": "scr_json_parse",
|
|
334
349
|
"dyn.keySet": "scr_dyn_key_set",
|
|
350
|
+
"dyn.iterPack": "scr_dyn_iter_pack",
|
|
335
351
|
"dyn.defineProps": "scr_dyn_define_props",
|
|
336
352
|
"dyn.typeof": "scr_dyn_typeof",
|
|
337
|
-
"dyn.toString": "
|
|
353
|
+
"dyn.toString": "scr_dyn_to_string_method",
|
|
338
354
|
"dyn.this": "scr_dyn_this_get",
|
|
339
355
|
"insp.dyn": "scr_insp_dyn",
|
|
340
356
|
"insp.dynS": "scr_insp_dyn_s",
|
|
@@ -376,6 +392,8 @@ const LIB_FN_SYMS = {
|
|
|
376
392
|
"emitter.names": "scr_emitter_event_names",
|
|
377
393
|
"emitter.listeners": "scr_emitter_listeners",
|
|
378
394
|
"emitter.setMax": "scr_emitter_set_max",
|
|
395
|
+
"emitter.setMaxChk": "scr_emitter_set_max_chk",
|
|
396
|
+
"emitter.setDefaultMaxChk": "scr_emitter_set_default_max_chk",
|
|
379
397
|
"emitter.getMax": "scr_emitter_get_max",
|
|
380
398
|
"emitter.setDefaultMax": "scr_emitter_set_default_max",
|
|
381
399
|
"emitter.getDefaultMax": "scr_emitter_get_default_max",
|
|
@@ -483,6 +501,9 @@ const LIB_FN_SYMS = {
|
|
|
483
501
|
// generic shapes; the throwing members ride the pending check.
|
|
484
502
|
"tp.setTimeout": "scr_tp_set_timeout",
|
|
485
503
|
"tp.setImmediate": "scr_tp_set_immediate",
|
|
504
|
+
// stream/promises' finished form (+1 promise; may-throw pending check;
|
|
505
|
+
// the pipeline form needs the stream-array compound and emits below).
|
|
506
|
+
"sp.finished": "scr_sp_finished",
|
|
486
507
|
"dc.channel": "scr_dc_channel",
|
|
487
508
|
"dc.subscribe": "scr_dc_subscribe",
|
|
488
509
|
"dc.unsubscribe": "scr_dc_unsubscribe",
|
|
@@ -544,6 +565,14 @@ const LIB_FN_SYMS = {
|
|
|
544
565
|
"dyn.objKeys": "scr_dyn_obj_keys",
|
|
545
566
|
"dyn.hasOwn": "scr_dyn_has_own",
|
|
546
567
|
"dyn.assign": "scr_dyn_assign",
|
|
568
|
+
// variadic Object.assign: the source pack (push never throws; the
|
|
569
|
+
// spread flatten throws V8's spread-call TypeErrors) and the final
|
|
570
|
+
// left-to-right copy (ToObject TypeError on a nullish target).
|
|
571
|
+
"dyn.packPush": "scr_dyn_pack_push",
|
|
572
|
+
"dyn.packPushSpread": "scr_dyn_pack_push_spread",
|
|
573
|
+
"dyn.packPushSpreadIter": "scr_dyn_pack_push_spread_iter",
|
|
574
|
+
"dyn.assignAll": "scr_dyn_assign_all",
|
|
575
|
+
"dyn.objCreateNullProto": "scr_dyn_new_obj_null_proto",
|
|
547
576
|
"dyn.objValues": "scr_dyn_obj_values",
|
|
548
577
|
"dyn.objEntries": "scr_dyn_obj_entries",
|
|
549
578
|
"dyn.structuredClone": "scr_structured_clone",
|
|
@@ -586,8 +615,10 @@ const USES_TIMERS_LIB_FNS = new Set([
|
|
|
586
615
|
"stream.setTransform", "stream.setFlush",
|
|
587
616
|
"process.activeResources",
|
|
588
617
|
"stream.finished", "stream.finishedDyn", "stream.pipeline", "stream.pipelineDyn",
|
|
618
|
+
"sp.finished", "sp.pipeline",
|
|
589
619
|
"net.listen", "net.listenCb", "net.listenOpts", "net.listenOptsCb",
|
|
590
|
-
"net.connect", "net.connectCb", "net.connectLookup",
|
|
620
|
+
"net.connect", "net.connectCb", "net.connectLookup", "net.connectAttempt",
|
|
621
|
+
"fs.existsChk",
|
|
591
622
|
"http.createServer", "http.createServerEmpty",
|
|
592
623
|
"http.request", "http.requestCb", "http.requestUrl", "http.requestUrlCb",
|
|
593
624
|
"http.requestConn", "http.requestConnCb",
|
|
@@ -640,6 +671,18 @@ const DV_GET_KIND = {
|
|
|
640
671
|
dvGetBigUint64Number: 8,
|
|
641
672
|
dvGetBigInt64Number: 9,
|
|
642
673
|
};
|
|
674
|
+
/** ScrDataViewGet per dvSet* method (the setters reuse the getter kinds;
|
|
675
|
+
* no BIG setters exist). */
|
|
676
|
+
const DV_SET_KIND = {
|
|
677
|
+
dvSetUint8: 0,
|
|
678
|
+
dvSetInt8: 1,
|
|
679
|
+
dvSetUint16: 2,
|
|
680
|
+
dvSetInt16: 3,
|
|
681
|
+
dvSetUint32: 4,
|
|
682
|
+
dvSetInt32: 5,
|
|
683
|
+
dvSetFloat32: 6,
|
|
684
|
+
dvSetFloat64: 7,
|
|
685
|
+
};
|
|
643
686
|
class LlEmitter {
|
|
644
687
|
mod;
|
|
645
688
|
/** Interned string literals: UTF-8 text → { symbol, byte length } —
|
|
@@ -1015,7 +1058,7 @@ class LlEmitter {
|
|
|
1015
1058
|
// LIBRARY mode: the runtime entry points the generated library
|
|
1016
1059
|
// symbols delegate to — declared before the extern block flushes.
|
|
1017
1060
|
if (this.mod.lib !== undefined) {
|
|
1018
|
-
this.declare(`declare void @scr_library_entry(i1 zeroext)`);
|
|
1061
|
+
this.declare(`declare void @scr_library_entry(i1 zeroext, ptr)`);
|
|
1019
1062
|
this.declare(`declare void @scr_library_reset()`);
|
|
1020
1063
|
this.declare(`declare void @scr_library_check_exc()`);
|
|
1021
1064
|
this.declare(`declare void @scr_library_set_sink(ptr, ptr)`);
|
|
@@ -1259,6 +1302,45 @@ class LlEmitter {
|
|
|
1259
1302
|
const lib = this.mod.lib;
|
|
1260
1303
|
const autoReset = lib.resultResetSymbol === null;
|
|
1261
1304
|
const out = [``, `; ── library-mode entries (profile: ${lib.profileName}) ──`, ``];
|
|
1305
|
+
// Every entry's prologue records its external symbol in the funnel's
|
|
1306
|
+
// current-entry slot (structured trap-teaching field 2); the symbols
|
|
1307
|
+
// live as internal constants, one per entry.
|
|
1308
|
+
const symConst = (sym) => `@sc_lib_sym_${sym}`;
|
|
1309
|
+
const emitSymConst = (sym) => {
|
|
1310
|
+
out.push(`${symConst(sym)} = internal constant [${Buffer.byteLength(sym, "utf8") + 1} x i8] c"${llStrBytes(sym)}"`);
|
|
1311
|
+
};
|
|
1312
|
+
emitSymConst(lib.initSymbol);
|
|
1313
|
+
if (lib.resultResetSymbol !== null)
|
|
1314
|
+
emitSymConst(lib.resultResetSymbol);
|
|
1315
|
+
if (lib.collectSymbol !== null)
|
|
1316
|
+
emitSymConst(lib.collectSymbol);
|
|
1317
|
+
for (const e of lib.exports)
|
|
1318
|
+
emitSymConst(e.symbol);
|
|
1319
|
+
out.push(``);
|
|
1320
|
+
// The runtime detected-trap overlay table (scr_runtime.h declares it,
|
|
1321
|
+
// the library trap funnel consults it): flat code/teaching/remediation
|
|
1322
|
+
// triples, one per runtime trap code (SC4013–SC4019) the profile
|
|
1323
|
+
// declares text for — the same data the C emission defines, so the
|
|
1324
|
+
// funnel-assembled sink message is emission-invariant by construction.
|
|
1325
|
+
// The empty table still defines the symbols the funnel links against.
|
|
1326
|
+
const ovlCells = [];
|
|
1327
|
+
lib.trapOverlays.forEach((o, i) => {
|
|
1328
|
+
const cell = (name, text) => {
|
|
1329
|
+
if (text === undefined) {
|
|
1330
|
+
ovlCells.push("ptr null");
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
const sym = `@sc_lib_ovl_${i}_${name}`;
|
|
1334
|
+
out.push(`${sym} = internal constant [${Buffer.byteLength(text, "utf8") + 1} x i8] c"${llStrBytes(text)}"`);
|
|
1335
|
+
ovlCells.push(`ptr ${sym}`);
|
|
1336
|
+
};
|
|
1337
|
+
cell("code", o.code);
|
|
1338
|
+
cell("teach", o.teaching);
|
|
1339
|
+
cell("rem", o.remediation);
|
|
1340
|
+
});
|
|
1341
|
+
out.push(ovlCells.length === 0
|
|
1342
|
+
? `@scr_library_trap_overlays = constant [1 x ptr] zeroinitializer`
|
|
1343
|
+
: `@scr_library_trap_overlays = constant [${ovlCells.length} x ptr] [${ovlCells.join(", ")}]`, `@scr_library_trap_overlays_len = constant i64 ${lib.trapOverlays.length}`, ``);
|
|
1262
1344
|
// The init entry: full deterministic reset-and-reevaluate. Program
|
|
1263
1345
|
// globals release and zero first (run-once guards included), then the
|
|
1264
1346
|
// runtime session reset, the error-vt interval stamps verbatim from
|
|
@@ -1268,7 +1350,7 @@ class LlEmitter {
|
|
|
1268
1350
|
const zero = ty === "double" ? f64Lit(0) : ty === "ptr" ? "null" : "false";
|
|
1269
1351
|
return ` store ${ty} ${zero}, ptr @${mangleGlobal(g.id)} ; ${g.name}`;
|
|
1270
1352
|
});
|
|
1271
|
-
out.push(`define void @${lib.initSymbol}() ${FN_ATTRS} {`, `entry:`, ` call void @scr_library_entry(i1 zeroext true) ; init always resets the result arena`, ...globalReleaseLines("ci"), ...zeroStores, ` call void @scr_library_reset()`, ...stamps, ` call void @${mangleFunction(this.mod.entry)}()`, ` call void @scr_library_check_exc()`, ` ret void`, `}`, ``, `define void @${lib.sinkRegisterSymbol}(ptr %fn, ptr %ctx) ${FN_ATTRS} {`, `entry:`, ` call void @scr_library_set_sink(ptr %fn, ptr %ctx)`, ` ret void`, `}`, ``);
|
|
1353
|
+
out.push(`define void @${lib.initSymbol}() ${FN_ATTRS} {`, `entry:`, ` call void @scr_library_entry(i1 zeroext true, ptr ${symConst(lib.initSymbol)}) ; init always resets the result arena`, ...globalReleaseLines("ci"), ...zeroStores, ` call void @scr_library_reset()`, ...stamps, ` call void @${mangleFunction(this.mod.entry)}()`, ` call void @scr_library_check_exc()`, ` ret void`, `}`, ``, `define void @${lib.sinkRegisterSymbol}(ptr %fn, ptr %ctx) ${FN_ATTRS} {`, `entry:`, ` call void @scr_library_set_sink(ptr %fn, ptr %ctx)`, ` ret void`, `}`, ``);
|
|
1272
1354
|
if (lib.identity !== undefined) {
|
|
1273
1355
|
// Profile-declared identity getters (the ask-2 sidecar's boot-time
|
|
1274
1356
|
// pairing fence): pure data returns with NO entry prologue — exempt
|
|
@@ -1279,14 +1361,14 @@ class LlEmitter {
|
|
|
1279
1361
|
out.push(`define i64 @${lib.identity.buildIdSymbol}() ${FN_ATTRS} { ; identity getter build_id 0x${lib.identity.buildId}`, `entry:`, ` ret i64 ${buildId}`, `}`, ``, `define i32 @${lib.identity.abiVersionSymbol}() ${FN_ATTRS} { ; identity getter abi_version`, `entry:`, ` ret i32 ${lib.identity.abiVersion}`, `}`, ``);
|
|
1280
1362
|
}
|
|
1281
1363
|
if (lib.resultResetSymbol !== null) {
|
|
1282
|
-
out.push(`define void @${lib.resultResetSymbol}() ${FN_ATTRS} {`, `entry:`, ` call void @scr_library_entry(i1 zeroext false)`, ` call void @scr_library_arena_reset()`, ` ret void`, `}`, ``);
|
|
1364
|
+
out.push(`define void @${lib.resultResetSymbol}() ${FN_ATTRS} {`, `entry:`, ` call void @scr_library_entry(i1 zeroext false, ptr ${symConst(lib.resultResetSymbol)})`, ` call void @scr_library_arena_reset()`, ` ret void`, `}`, ``);
|
|
1283
1365
|
}
|
|
1284
1366
|
if (lib.collectSymbol !== null) {
|
|
1285
|
-
out.push(`define void @${lib.collectSymbol}() ${FN_ATTRS} {`, `entry:`, ` call void @scr_library_entry(i1 zeroext false)`, ` call void @scr_library_collect() ; arena reset + a full cycle collection`, ` ret void`, `}`, ``);
|
|
1367
|
+
out.push(`define void @${lib.collectSymbol}() ${FN_ATTRS} {`, `entry:`, ` call void @scr_library_entry(i1 zeroext false, ptr ${symConst(lib.collectSymbol)})`, ` call void @scr_library_collect() ; arena reset + a full cycle collection`, ` ret void`, `}`, ``);
|
|
1286
1368
|
}
|
|
1287
1369
|
for (const e of lib.exports) {
|
|
1288
1370
|
const params = [];
|
|
1289
|
-
const body = [` call void @scr_library_entry(i1 zeroext ${autoReset ? "true" : "false"})`];
|
|
1371
|
+
const body = [` call void @scr_library_entry(i1 zeroext ${autoReset ? "true" : "false"}, ptr ${symConst(e.symbol)})`];
|
|
1290
1372
|
const args = [];
|
|
1291
1373
|
if (e.inboundBytesTrap !== undefined) {
|
|
1292
1374
|
// The bytes-in helper's trap message: the compiler-assembled
|
|
@@ -3999,7 +4081,15 @@ class LlEmitter {
|
|
|
3999
4081
|
const t = B.tmp();
|
|
4000
4082
|
B.line(`${a} = call double @scr_union_get_f64(ptr ${l.name})`);
|
|
4001
4083
|
B.line(`${b} = call double @scr_union_get_f64(ptr ${r.name})`);
|
|
4002
|
-
|
|
4084
|
+
if (e.sameValue) {
|
|
4085
|
+
// Object.is's f64 compare: NaN equals NaN, +0 differs
|
|
4086
|
+
// from -0 — the runtime SameValue.
|
|
4087
|
+
this.declare(`declare zeroext i1 @scr_num_same_value(double, double)`);
|
|
4088
|
+
B.line(`${t} = call zeroext i1 @scr_num_same_value(double ${a}, double ${b})`);
|
|
4089
|
+
}
|
|
4090
|
+
else {
|
|
4091
|
+
B.line(`${t} = fcmp oeq double ${a}, ${b}`);
|
|
4092
|
+
}
|
|
4003
4093
|
B.line(`store i1 ${t}, ptr ${slot}`);
|
|
4004
4094
|
break;
|
|
4005
4095
|
}
|
|
@@ -4103,6 +4193,33 @@ class LlEmitter {
|
|
|
4103
4193
|
B.line(`${t} = load ptr, ptr ${slot}`);
|
|
4104
4194
|
return this.own({ name: t, type: e.type });
|
|
4105
4195
|
}
|
|
4196
|
+
if (e.left.type.kind === "dyn") {
|
|
4197
|
+
// The checked-dynamic form: the runtime kind decides (UNDEF/
|
|
4198
|
+
// NULL take the default; a wrapped island value asks the
|
|
4199
|
+
// engine); the right runs lazily in its branch (already dyn).
|
|
4200
|
+
const l = this.emitExpr(e.left);
|
|
4201
|
+
this.moveTemp(l);
|
|
4202
|
+
this.declare(`declare zeroext i1 @scr_dyn_is_nullish(ptr)`);
|
|
4203
|
+
const slot = B.slot();
|
|
4204
|
+
B.entryAllocas.push(`${slot} = alloca ptr`);
|
|
4205
|
+
const isN = B.tmp();
|
|
4206
|
+
B.line(`${isN} = call zeroext i1 @scr_dyn_is_nullish(ptr ${l.name})`);
|
|
4207
|
+
const lu = B.newLabel("nuld.u");
|
|
4208
|
+
const lv = B.newLabel("nuld.v");
|
|
4209
|
+
const lj = B.newLabel("nuld.j");
|
|
4210
|
+
B.condBr(isN, lu, lv);
|
|
4211
|
+
B.startBlock(lu);
|
|
4212
|
+
this.releaseValue(l.name, e.left.type);
|
|
4213
|
+
this.emitBranchInto(slot, e.right);
|
|
4214
|
+
B.br(lj);
|
|
4215
|
+
B.startBlock(lv);
|
|
4216
|
+
B.line(`store ptr ${l.name}, ptr ${slot}`);
|
|
4217
|
+
B.br(lj);
|
|
4218
|
+
B.startBlock(lj);
|
|
4219
|
+
const t = B.tmp();
|
|
4220
|
+
B.line(`${t} = load ptr, ptr ${slot}`);
|
|
4221
|
+
return this.own({ name: t, type: e.type });
|
|
4222
|
+
}
|
|
4106
4223
|
if (e.left.type.kind !== "union")
|
|
4107
4224
|
throw new Error("llvm emitter bug: nullish left is not a union");
|
|
4108
4225
|
const def = this.unionsById.get(e.left.type.unionId);
|
|
@@ -5272,14 +5389,18 @@ class LlEmitter {
|
|
|
5272
5389
|
}
|
|
5273
5390
|
if (e.name === "promise.reject") {
|
|
5274
5391
|
// A fresh promise rejected through the exception cell: the
|
|
5275
|
-
// %Error-rooted reason moves in as the cell's OBJ payload
|
|
5276
|
-
//
|
|
5277
|
-
//
|
|
5392
|
+
// %Error-rooted reason moves in as the cell's OBJ payload (a
|
|
5393
|
+
// checked-dynamic reason rides the thrown-dyn REF representation
|
|
5394
|
+
// instead — identity flows to catch/unhandledRejection observers,
|
|
5395
|
+
// emitThrowValue's dyn arm), and reject_pending moves the cell
|
|
5396
|
+
// into the promise (consumed immediately — no pending check runs
|
|
5397
|
+
// in between).
|
|
5278
5398
|
if (e.type.kind !== "promise")
|
|
5279
5399
|
throw new Error("llvm emitter bug: promise.reject type");
|
|
5280
5400
|
const reasonT = e.args[0].type;
|
|
5281
|
-
if (reasonT.kind !== "object")
|
|
5401
|
+
if (reasonT.kind !== "object" && reasonT.kind !== "dyn") {
|
|
5282
5402
|
throw new Error("llvm emitter bug: promise.reject reason");
|
|
5403
|
+
}
|
|
5283
5404
|
this.declare(`declare ptr @scr_promise_new()`);
|
|
5284
5405
|
this.declare(`declare void @scr_promise_reject_pending(ptr)`);
|
|
5285
5406
|
const reason = this.emitExpr(e.args[0]);
|
|
@@ -5421,6 +5542,16 @@ class LlEmitter {
|
|
|
5421
5542
|
B.line(`${t} = call ptr @${conv}(${valTy} ${v.name})`);
|
|
5422
5543
|
return this.own({ name: t, type: e.type });
|
|
5423
5544
|
}
|
|
5545
|
+
case "dynFromJsval": {
|
|
5546
|
+
// Island value → DOM: the by-reference wrap (scr_dyn_from_jsval
|
|
5547
|
+
// retains the cell in; engine scalars normalize to native DOM
|
|
5548
|
+
// kinds at wrap time). Operand borrowed, result +1, never throws.
|
|
5549
|
+
const v = this.emitExpr(e.value);
|
|
5550
|
+
this.declare(`declare ptr @scr_dyn_from_jsval(ptr)`);
|
|
5551
|
+
const t = B.tmp();
|
|
5552
|
+
B.line(`${t} = call ptr @scr_dyn_from_jsval(ptr ${v.name})`);
|
|
5553
|
+
return this.own({ name: t, type: e.type });
|
|
5554
|
+
}
|
|
5424
5555
|
case "caughtToDyn": {
|
|
5425
5556
|
// A catch binding flowing into an `unknown` slot: the snapshot's
|
|
5426
5557
|
// runtime kind converts through the interned helper (+1 fresh
|
|
@@ -5452,6 +5583,40 @@ class LlEmitter {
|
|
|
5452
5583
|
// boxed thunk builds its own typed copies. The callee's source
|
|
5453
5584
|
// spelling rides along for Node's "<name> is not a function".
|
|
5454
5585
|
const callee = this.emitExpr(e.callee);
|
|
5586
|
+
if (e.spreads !== undefined && e.spreads.length > 0) {
|
|
5587
|
+
// The RUNTIME-ARITY form (`f(...args)`): one fresh DOM array
|
|
5588
|
+
// collects the arguments left-to-right — plain args move in
|
|
5589
|
+
// (push takes ownership), spread args FLATTEN (push_spread
|
|
5590
|
+
// retains elements in and throws V8's spread-call TypeError for
|
|
5591
|
+
// non-iterable DOM kinds, checked per spread — JS's
|
|
5592
|
+
// ArgumentListEvaluation order) — then apply calls through the
|
|
5593
|
+
// array's elements (borrowed, exactly scr_dyn_call).
|
|
5594
|
+
this.declare(`declare ptr @scr_dyn_new_arr()`);
|
|
5595
|
+
this.declare(`declare void @scr_dyn_arr_push(ptr, ptr)`);
|
|
5596
|
+
this.declare(`declare void @scr_dyn_arr_push_spread(ptr, ptr, ptr)`);
|
|
5597
|
+
this.declare(`declare ptr @scr_dyn_apply(ptr, ptr, ptr)`);
|
|
5598
|
+
const spreadAt = new Map(e.spreads.map((s) => [s.arg, s.what]));
|
|
5599
|
+
const pack = B.tmp();
|
|
5600
|
+
B.line(`${pack} = call ptr @scr_dyn_new_arr()`);
|
|
5601
|
+
this.own({ name: pack, type: DYN });
|
|
5602
|
+
e.args.forEach((a, i) => {
|
|
5603
|
+
const v = this.emitExpr(a);
|
|
5604
|
+
const spreadWhat = spreadAt.get(i);
|
|
5605
|
+
if (spreadWhat !== undefined) {
|
|
5606
|
+
B.line(`call void @scr_dyn_arr_push_spread(ptr ${pack}, ptr ${v.name}, ptr ${this.cstr(spreadWhat)})`);
|
|
5607
|
+
this.emitPendingCheck();
|
|
5608
|
+
}
|
|
5609
|
+
else {
|
|
5610
|
+
this.moveTemp(v);
|
|
5611
|
+
B.line(`call void @scr_dyn_arr_push(ptr ${pack}, ptr ${v.name})`);
|
|
5612
|
+
}
|
|
5613
|
+
});
|
|
5614
|
+
const t = B.tmp();
|
|
5615
|
+
B.line(`${t} = call ptr @scr_dyn_apply(ptr ${callee.name}, ptr ${pack}, ptr ${this.cstr(e.calleeName)})`);
|
|
5616
|
+
const out = this.own({ name: t, type: e.type });
|
|
5617
|
+
this.emitPendingCheck();
|
|
5618
|
+
return out;
|
|
5619
|
+
}
|
|
5455
5620
|
const args = e.args.map((a) => this.emitExpr(a));
|
|
5456
5621
|
let argsPtr = "null";
|
|
5457
5622
|
if (args.length > 0) {
|
|
@@ -5568,7 +5733,8 @@ class LlEmitter {
|
|
|
5568
5733
|
B.startBlock(lNotObj);
|
|
5569
5734
|
const isArr = B.tmp();
|
|
5570
5735
|
B.line(`${isArr} = icmp eq i32 ${kd}, ${DK.ARR}`);
|
|
5571
|
-
B.
|
|
5736
|
+
const lNotArr = B.newLabel("dhk.na");
|
|
5737
|
+
B.condBr(isArr, lArr, lNotArr);
|
|
5572
5738
|
B.startBlock(lArr);
|
|
5573
5739
|
if (e.key === "length") {
|
|
5574
5740
|
B.line(`store i1 true, ptr ${slot}`);
|
|
@@ -5583,9 +5749,20 @@ class LlEmitter {
|
|
|
5583
5749
|
B.line(`store i1 ${inR}, ptr ${slot}`);
|
|
5584
5750
|
}
|
|
5585
5751
|
B.br(lj);
|
|
5752
|
+
// An ISLAND-held receiver fences loudly (Node asks the real
|
|
5753
|
+
// engine object — `false` would be a silent wrong answer); the
|
|
5754
|
+
// helper answers false for every other kind, so this arm is a
|
|
5755
|
+
// plain unconditional call.
|
|
5756
|
+
B.startBlock(lNotArr);
|
|
5757
|
+
this.declare(`declare zeroext i1 @scr_dyn_isl_fence(ptr, ptr)`);
|
|
5758
|
+
const fenced = B.tmp();
|
|
5759
|
+
B.line(`${fenced} = call zeroext i1 @scr_dyn_isl_fence(ptr ${d.name}, ptr ${this.cstr("'in'")})`);
|
|
5760
|
+
B.line(`store i1 ${fenced}, ptr ${slot}`);
|
|
5761
|
+
B.br(lj);
|
|
5586
5762
|
B.startBlock(lj);
|
|
5587
5763
|
const raw = B.tmp();
|
|
5588
5764
|
B.line(`${raw} = load i1, ptr ${slot}`);
|
|
5765
|
+
this.emitPendingCheck();
|
|
5589
5766
|
if (!e.negated)
|
|
5590
5767
|
return { name: raw, type: e.type };
|
|
5591
5768
|
const neg = B.tmp();
|
|
@@ -5665,13 +5842,18 @@ class LlEmitter {
|
|
|
5665
5842
|
}
|
|
5666
5843
|
else if (e.test === "error") {
|
|
5667
5844
|
// `u instanceof Error`: the DOM's error encoding — an object
|
|
5668
|
-
// carrying the reserved "%error" marker key
|
|
5845
|
+
// carrying the reserved "%error" marker key — or a real engine
|
|
5846
|
+
// Error held by reference (the isl helper answers false for
|
|
5847
|
+
// every non-JSVAL kind, so the call is unconditional).
|
|
5669
5848
|
const kd = this.dynKind(d.name);
|
|
5670
5849
|
const isObj = B.tmp();
|
|
5671
5850
|
B.line(`${isObj} = icmp eq i32 ${kd}, ${DK.OBJ}`);
|
|
5672
5851
|
const slot = B.slot();
|
|
5673
5852
|
B.entryAllocas.push(`${slot} = alloca i1`);
|
|
5674
|
-
|
|
5853
|
+
this.declare(`declare zeroext i1 @scr_dyn_isl_is_error(ptr)`);
|
|
5854
|
+
const isl = B.tmp();
|
|
5855
|
+
B.line(`${isl} = call zeroext i1 @scr_dyn_isl_is_error(ptr ${d.name})`);
|
|
5856
|
+
B.line(`store i1 ${isl}, ptr ${slot}`);
|
|
5675
5857
|
const lObj = B.newLabel("dts.o");
|
|
5676
5858
|
const lj = B.newLabel("dts.j");
|
|
5677
5859
|
B.condBr(isObj, lObj, lj);
|
|
@@ -5705,13 +5887,33 @@ class LlEmitter {
|
|
|
5705
5887
|
}
|
|
5706
5888
|
return acc;
|
|
5707
5889
|
};
|
|
5890
|
+
// ISLAND-held nodes route the tests that depend on the engine's
|
|
5891
|
+
// answer through the scr_dyn_isl_* helpers (false on every
|
|
5892
|
+
// other kind — the calls stay unconditional and branch-free).
|
|
5893
|
+
const orIsl = (acc, helper, arg) => {
|
|
5894
|
+
this.declare(`declare zeroext i1 @${helper}(ptr${arg !== undefined ? ", ptr" : ""})`);
|
|
5895
|
+
const c = B.tmp();
|
|
5896
|
+
B.line(`${c} = call zeroext i1 @${helper}(ptr ${d.name}${arg !== undefined ? `, ptr ${arg}` : ""})`);
|
|
5897
|
+
const o = B.tmp();
|
|
5898
|
+
B.line(`${o} = or i1 ${acc}, ${c}`);
|
|
5899
|
+
return o;
|
|
5900
|
+
};
|
|
5708
5901
|
if (e.test === "nullish") {
|
|
5709
5902
|
test = oneOf([DK.UNDEF, DK.NULL]);
|
|
5710
5903
|
}
|
|
5711
5904
|
else if (e.test === "object") {
|
|
5712
5905
|
// `typeof v === "object"`: objects, arrays, bytes, native
|
|
5713
|
-
// handles, promises, AND null
|
|
5714
|
-
|
|
5906
|
+
// handles, promises, AND null — engine-held objects by the
|
|
5907
|
+
// engine's own typeof.
|
|
5908
|
+
test = orIsl(oneOf([DK.OBJ, DK.ARR, DK.BYTES, DK.HANDLE, DK.PROMISE, DK.NULL]), "scr_dyn_isl_typeof_is", this.cstr("object"));
|
|
5909
|
+
}
|
|
5910
|
+
else if (e.test === "array") {
|
|
5911
|
+
// Array.isArray: the DOM's array kind, or the engine's own
|
|
5912
|
+
// answer for an engine-held value.
|
|
5913
|
+
test = orIsl(oneOf([DK.ARR]), "scr_dyn_isl_is_array");
|
|
5914
|
+
}
|
|
5915
|
+
else if (e.test === "function") {
|
|
5916
|
+
test = orIsl(oneOf([DK.FUNC]), "scr_dyn_isl_typeof_is", this.cstr("function"));
|
|
5715
5917
|
}
|
|
5716
5918
|
else {
|
|
5717
5919
|
const kindOf = {
|
|
@@ -5721,8 +5923,6 @@ class LlEmitter {
|
|
|
5721
5923
|
undefined: DK.UNDEF,
|
|
5722
5924
|
null: DK.NULL,
|
|
5723
5925
|
bytes: DK.BYTES,
|
|
5724
|
-
array: DK.ARR,
|
|
5725
|
-
function: DK.FUNC,
|
|
5726
5926
|
};
|
|
5727
5927
|
test = oneOf([kindOf[e.test]]);
|
|
5728
5928
|
}
|
|
@@ -5834,6 +6034,13 @@ class LlEmitter {
|
|
|
5834
6034
|
return simple("scr_jsval_from_bool", "i1", false);
|
|
5835
6035
|
case "string":
|
|
5836
6036
|
return simple("scr_jsval_from_str", "ptr", false);
|
|
6037
|
+
case "dyn":
|
|
6038
|
+
// A CHECKED-DYNAMIC (DOM) value entering the island: deep copy,
|
|
6039
|
+
// data kinds only — boxed functions/handles/promises throw the
|
|
6040
|
+
// catchable TypeError in the runtime, and a wrapped island value
|
|
6041
|
+
// unwraps to the SAME engine value (the identity round trip).
|
|
6042
|
+
// The C emitter's rule, mirrored.
|
|
6043
|
+
return simple("scr_jsval_from_dyn", "ptr", true);
|
|
5837
6044
|
case "bytes":
|
|
5838
6045
|
// A typed array crossing IN: a COPY (the boundary's copy stance).
|
|
5839
6046
|
return simple("scr_jsval_from_bytes", "ptr", true);
|
|
@@ -6037,6 +6244,18 @@ class LlEmitter {
|
|
|
6037
6244
|
return t;
|
|
6038
6245
|
});
|
|
6039
6246
|
}
|
|
6247
|
+
case "callSpread": {
|
|
6248
|
+
// Spread application (`f(...pre, ...s)`): the prelude helper's
|
|
6249
|
+
// real spread syntax — iterator protocols are the engine's own,
|
|
6250
|
+
// the guards front-run V8's spread-call TypeError texts (the name
|
|
6251
|
+
// literal is the spread expression's spelling).
|
|
6252
|
+
this.declare(`declare ptr @scr_jsval_call_spread(ptr, ptr, ptr, ptr)`);
|
|
6253
|
+
return fallible(() => {
|
|
6254
|
+
const t = B.tmp();
|
|
6255
|
+
B.line(`${t} = call ptr @scr_jsval_call_spread(ptr ${a(0)}, ptr ${a(1)}, ptr ${a(2)}, ptr ${nameSym()})`);
|
|
6256
|
+
return t;
|
|
6257
|
+
});
|
|
6258
|
+
}
|
|
6040
6259
|
case "construct": {
|
|
6041
6260
|
const pack = argPack(args.slice(1).map((x) => x.name));
|
|
6042
6261
|
this.declare(`declare ptr @scr_jsval_construct(ptr, i32, ptr)`);
|
|
@@ -8131,6 +8350,18 @@ class LlEmitter {
|
|
|
8131
8350
|
// DataView getters: an omitted littleEndian is big-endian (the JS
|
|
8132
8351
|
// default). Throw Node's constant RangeError on a bad offset.
|
|
8133
8352
|
return call("scr_dataview_get", "double (ptr, double, i32, i1 zeroext)", `ptr ${r.name}, double ${args[0].name}, i32 ${DV_GET_KIND[method]}, i1 ${args[1]?.name ?? "false"}`, false, true);
|
|
8353
|
+
case "dvSetUint8":
|
|
8354
|
+
case "dvSetInt8":
|
|
8355
|
+
case "dvSetUint16":
|
|
8356
|
+
case "dvSetInt16":
|
|
8357
|
+
case "dvSetUint32":
|
|
8358
|
+
case "dvSetInt32":
|
|
8359
|
+
case "dvSetFloat32":
|
|
8360
|
+
case "dvSetFloat64":
|
|
8361
|
+
// DataView setters: [offset, value, littleEndian?] — void; throw
|
|
8362
|
+
// the getters' constant RangeError on a bad offset.
|
|
8363
|
+
return call("scr_dataview_set", "void (ptr, double, double, i32, i1 zeroext)", `ptr ${r.name}, double ${args[0].name}, double ${args[1].name}, ` +
|
|
8364
|
+
`i32 ${DV_SET_KIND[method]}, i1 ${args[2]?.name ?? "false"}`, false, true);
|
|
8134
8365
|
default: {
|
|
8135
8366
|
const _exhaustive = method;
|
|
8136
8367
|
void _exhaustive;
|
|
@@ -8511,6 +8742,90 @@ class LlEmitter {
|
|
|
8511
8742
|
if (USES_TIMERS_LIB_FNS.has(e.fn))
|
|
8512
8743
|
this.usesTimers = true;
|
|
8513
8744
|
// The handful with non-generic shapes first.
|
|
8745
|
+
if (e.fn === "error.argTypeThrow") {
|
|
8746
|
+
// Always throws with the runtime-rendered Received tail (the
|
|
8747
|
+
// error.nodeThrow dummy pattern). Borrows all three.
|
|
8748
|
+
const an = this.emitExpr(e.args[0]);
|
|
8749
|
+
const ex = this.emitExpr(e.args[1]);
|
|
8750
|
+
const got = this.emitExpr(e.args[2]);
|
|
8751
|
+
this.declare(`declare void @scr_throw_arg_type(ptr, ptr, ptr)`);
|
|
8752
|
+
B.line(`call void @scr_throw_arg_type(ptr ${an.name}, ptr ${ex.name}, ptr ${got.name})`);
|
|
8753
|
+
const ty = this.llType(e.type);
|
|
8754
|
+
if (ty === "void") {
|
|
8755
|
+
this.emitPendingCheck();
|
|
8756
|
+
return { name: "", type: e.type };
|
|
8757
|
+
}
|
|
8758
|
+
const dummy = ty === "double" ? f64Lit(0) : ty === "i1" ? "false" : "null";
|
|
8759
|
+
const out = this.own({ name: dummy, type: e.type });
|
|
8760
|
+
this.emitPendingCheck();
|
|
8761
|
+
return out;
|
|
8762
|
+
}
|
|
8763
|
+
if (e.fn === "error.propTypeThrow") {
|
|
8764
|
+
// The property flavor of argTypeThrow — same always-throw shape.
|
|
8765
|
+
const an = this.emitExpr(e.args[0]);
|
|
8766
|
+
const ex = this.emitExpr(e.args[1]);
|
|
8767
|
+
const got = this.emitExpr(e.args[2]);
|
|
8768
|
+
this.declare(`declare void @scr_throw_prop_type(ptr, ptr, ptr)`);
|
|
8769
|
+
B.line(`call void @scr_throw_prop_type(ptr ${an.name}, ptr ${ex.name}, ptr ${got.name})`);
|
|
8770
|
+
const ty = this.llType(e.type);
|
|
8771
|
+
if (ty === "void") {
|
|
8772
|
+
this.emitPendingCheck();
|
|
8773
|
+
return { name: "", type: e.type };
|
|
8774
|
+
}
|
|
8775
|
+
const dummy = ty === "double" ? f64Lit(0) : ty === "i1" ? "false" : "null";
|
|
8776
|
+
const out = this.own({ name: dummy, type: e.type });
|
|
8777
|
+
this.emitPendingCheck();
|
|
8778
|
+
return out;
|
|
8779
|
+
}
|
|
8780
|
+
{
|
|
8781
|
+
// The fs validation-ladder Chk forms that ALWAYS throw (a
|
|
8782
|
+
// validation error or the trailing compiler-rendered fence): every
|
|
8783
|
+
// argument is a ptr (dyns + the fence string), and the typed dummy
|
|
8784
|
+
// is abandoned by the pending check's unwind.
|
|
8785
|
+
const FS_CHK_THROW_SYMS = {
|
|
8786
|
+
"fs.mkdtempChk": "scr_fs_mkdtemp_chk",
|
|
8787
|
+
"fs.readFileChk": "scr_fs_read_file_chk",
|
|
8788
|
+
"fs.opendirChk": "scr_fs_opendir_chk",
|
|
8789
|
+
"fs.watchFileChk": "scr_fs_watch_file_chk",
|
|
8790
|
+
"fs.lchmodChk": "scr_fs_lchmod_chk",
|
|
8791
|
+
"fs.readChk": "scr_fs_read_chk",
|
|
8792
|
+
"fs.streamOptsChk": "scr_fs_stream_opts_chk",
|
|
8793
|
+
"net.connectOptsChk": "scr_net_connect_opts_chk",
|
|
8794
|
+
};
|
|
8795
|
+
const sym = FS_CHK_THROW_SYMS[e.fn];
|
|
8796
|
+
if (sym !== undefined) {
|
|
8797
|
+
const args = e.args.map((a) => this.emitExpr(a));
|
|
8798
|
+
this.declare(`declare void @${sym}(${args.map(() => "ptr").join(", ")})`);
|
|
8799
|
+
B.line(`call void @${sym}(${args.map((a) => `ptr ${a.name}`).join(", ")})`);
|
|
8800
|
+
const ty = this.llType(e.type);
|
|
8801
|
+
if (ty === "void") {
|
|
8802
|
+
this.emitPendingCheck();
|
|
8803
|
+
return { name: "", type: e.type };
|
|
8804
|
+
}
|
|
8805
|
+
const dummy = ty === "double" ? f64Lit(0) : ty === "i1" ? "false" : "null";
|
|
8806
|
+
const out = this.own({ name: dummy, type: e.type });
|
|
8807
|
+
this.emitPendingCheck();
|
|
8808
|
+
return out;
|
|
8809
|
+
}
|
|
8810
|
+
}
|
|
8811
|
+
if (e.fn === "error.nodeThrow") {
|
|
8812
|
+
// The compiler-resolved Node-parity throw (always throws — the
|
|
8813
|
+
// typed dummy is abandoned by the pending check's unwind).
|
|
8814
|
+
const kind = this.emitExpr(e.args[0]);
|
|
8815
|
+
const code = this.emitExpr(e.args[1]);
|
|
8816
|
+
const msg = this.emitExpr(e.args[2]);
|
|
8817
|
+
this.declare(`declare void @scr_throw_node_coded(double, ptr, ptr)`);
|
|
8818
|
+
B.line(`call void @scr_throw_node_coded(double ${kind.name}, ptr ${code.name}, ptr ${msg.name})`);
|
|
8819
|
+
const ty = this.llType(e.type);
|
|
8820
|
+
if (ty === "void") {
|
|
8821
|
+
this.emitPendingCheck();
|
|
8822
|
+
return { name: "", type: e.type };
|
|
8823
|
+
}
|
|
8824
|
+
const dummy = ty === "double" ? f64Lit(0) : ty === "i1" ? "false" : "null";
|
|
8825
|
+
const out = this.own({ name: dummy, type: e.type });
|
|
8826
|
+
this.emitPendingCheck();
|
|
8827
|
+
return out;
|
|
8828
|
+
}
|
|
8514
8829
|
if (e.fn === "global.undefRead") {
|
|
8515
8830
|
// A declare-d const nothing defines: Node's catchable
|
|
8516
8831
|
// ReferenceError at the access (always throws — the typed dummy is
|
|
@@ -9742,6 +10057,28 @@ class LlEmitter {
|
|
|
9742
10057
|
this.emitPendingCheck();
|
|
9743
10058
|
return out;
|
|
9744
10059
|
}
|
|
10060
|
+
if (e.fn === "sp.pipeline") {
|
|
10061
|
+
// pipeline(count, s1..sn) settling a void promise: the stream list
|
|
10062
|
+
// rides the callback form's stack array, no callback slot.
|
|
10063
|
+
const countArg = e.args[0];
|
|
10064
|
+
if (countArg.kind !== "numLit")
|
|
10065
|
+
throw new Error(`llvm emitter bug: ${e.fn} count not a literal`);
|
|
10066
|
+
const n = countArg.value;
|
|
10067
|
+
const args = e.args.map((a) => this.emitExpr(a));
|
|
10068
|
+
const arr = B.slot();
|
|
10069
|
+
B.entryAllocas.push(`${arr} = alloca [${n} x ptr]`);
|
|
10070
|
+
for (let i = 0; i < n; i++) {
|
|
10071
|
+
const p = B.tmp();
|
|
10072
|
+
B.line(`${p} = getelementptr inbounds [${n} x ptr], ptr ${arr}, i64 0, i64 ${i}`);
|
|
10073
|
+
B.line(`store ptr ${args[1 + i].name}, ptr ${p}`);
|
|
10074
|
+
}
|
|
10075
|
+
const t = B.tmp();
|
|
10076
|
+
this.declare(`declare ptr @scr_sp_pipeline(double, ptr)`);
|
|
10077
|
+
B.line(`${t} = call ptr @scr_sp_pipeline(double ${f64Lit(n)}, ptr ${arr})`);
|
|
10078
|
+
const out = this.own({ name: t, type: e.type });
|
|
10079
|
+
this.emitPendingCheck();
|
|
10080
|
+
return out;
|
|
10081
|
+
}
|
|
9745
10082
|
if (e.fn === "stream.pipeline" || e.fn === "stream.pipelineDyn") {
|
|
9746
10083
|
// pipeline(count, s1..sn, cb): the destination answers +1. The
|
|
9747
10084
|
// stream list rides a stack array (the C compound literal).
|