@scriptc/compiler 0.0.7 → 0.0.9
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 +155 -6
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emit-island.js +9 -1
- package/dist/backend/emission/emit-island.js.map +1 -1
- package/dist/backend/emission/emit-stmts.js +3 -1
- package/dist/backend/emission/emit-stmts.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 +45 -18
- 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 +35 -10
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/emission/may-throw.js +4 -3
- package/dist/backend/emission/may-throw.js.map +1 -1
- package/dist/backend/llvm/emitter.js +300 -18
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +98 -11
- package/dist/diagnostics/diagnostic.js +185 -25
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/frontend/lib-contract.d.ts +24 -6
- package/dist/frontend/lib-contract.js +125 -44
- package/dist/frontend/lib-contract.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 +11 -0
- package/dist/frontend/lowering/lower-builtins.js +127 -4
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +77 -18
- package/dist/frontend/lowering/lower-calls.js +978 -44
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +14 -1
- package/dist/frontend/lowering/lower-classes.js +112 -16
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +4 -2
- package/dist/frontend/lowering/lower-containers.js +236 -44
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-emitter.js +55 -1
- package/dist/frontend/lowering/lower-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +26 -3
- package/dist/frontend/lowering/lower-exprs.js +507 -47
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +7 -0
- package/dist/frontend/lowering/lower-island.js +71 -10
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-mixins.d.ts +1 -1
- package/dist/frontend/lowering/lower-mixins.js +1 -1
- package/dist/frontend/lowering/lower-modules.js +95 -4
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +866 -56
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +28 -2
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +85 -17
- package/dist/frontend/lowering/lowerer.js +459 -37
- 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 +28 -1
- package/dist/frontend/types.js +304 -10
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +181 -26
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +159 -9
- package/dist/ir/nodes.js +76 -6
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +93 -14
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/profile.d.ts +17 -3
- package/dist/library/profile.js +38 -9
- package/dist/library/profile.js.map +1 -1
- package/dist/library/sidecar.js +162 -43
- package/dist/library/sidecar.js.map +1 -1
- package/dist/library/trap-teaching.d.ts +11 -0
- package/dist/library/trap-teaching.js +49 -0
- package/dist/library/trap-teaching.js.map +1 -0
- package/package.json +2 -2
- package/surface-manifest.json +46 -4
|
@@ -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,14 @@ 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",
|
|
190
200
|
"fs.readFileSyncBuf": "scr_fs_read_file_bytes",
|
|
191
201
|
"fs.readFileSyncBytes": "scr_fs_read_file_bytes",
|
|
192
202
|
"fs.writeFileSyncBytes": "scr_fs_write_file_bytes",
|
|
@@ -376,6 +386,8 @@ const LIB_FN_SYMS = {
|
|
|
376
386
|
"emitter.names": "scr_emitter_event_names",
|
|
377
387
|
"emitter.listeners": "scr_emitter_listeners",
|
|
378
388
|
"emitter.setMax": "scr_emitter_set_max",
|
|
389
|
+
"emitter.setMaxChk": "scr_emitter_set_max_chk",
|
|
390
|
+
"emitter.setDefaultMaxChk": "scr_emitter_set_default_max_chk",
|
|
379
391
|
"emitter.getMax": "scr_emitter_get_max",
|
|
380
392
|
"emitter.setDefaultMax": "scr_emitter_set_default_max",
|
|
381
393
|
"emitter.getDefaultMax": "scr_emitter_get_default_max",
|
|
@@ -483,6 +495,9 @@ const LIB_FN_SYMS = {
|
|
|
483
495
|
// generic shapes; the throwing members ride the pending check.
|
|
484
496
|
"tp.setTimeout": "scr_tp_set_timeout",
|
|
485
497
|
"tp.setImmediate": "scr_tp_set_immediate",
|
|
498
|
+
// stream/promises' finished form (+1 promise; may-throw pending check;
|
|
499
|
+
// the pipeline form needs the stream-array compound and emits below).
|
|
500
|
+
"sp.finished": "scr_sp_finished",
|
|
486
501
|
"dc.channel": "scr_dc_channel",
|
|
487
502
|
"dc.subscribe": "scr_dc_subscribe",
|
|
488
503
|
"dc.unsubscribe": "scr_dc_unsubscribe",
|
|
@@ -542,6 +557,8 @@ const LIB_FN_SYMS = {
|
|
|
542
557
|
// (option/DataClone/cycle errors), and new RegExp's eager compile
|
|
543
558
|
// (catchable SyntaxError) — all may-throw generics over the DOM.
|
|
544
559
|
"dyn.objKeys": "scr_dyn_obj_keys",
|
|
560
|
+
"dyn.hasOwn": "scr_dyn_has_own",
|
|
561
|
+
"dyn.assign": "scr_dyn_assign",
|
|
545
562
|
"dyn.objValues": "scr_dyn_obj_values",
|
|
546
563
|
"dyn.objEntries": "scr_dyn_obj_entries",
|
|
547
564
|
"dyn.structuredClone": "scr_structured_clone",
|
|
@@ -584,6 +601,7 @@ const USES_TIMERS_LIB_FNS = new Set([
|
|
|
584
601
|
"stream.setTransform", "stream.setFlush",
|
|
585
602
|
"process.activeResources",
|
|
586
603
|
"stream.finished", "stream.finishedDyn", "stream.pipeline", "stream.pipelineDyn",
|
|
604
|
+
"sp.finished", "sp.pipeline",
|
|
587
605
|
"net.listen", "net.listenCb", "net.listenOpts", "net.listenOptsCb",
|
|
588
606
|
"net.connect", "net.connectCb", "net.connectLookup",
|
|
589
607
|
"http.createServer", "http.createServerEmpty",
|
|
@@ -638,6 +656,18 @@ const DV_GET_KIND = {
|
|
|
638
656
|
dvGetBigUint64Number: 8,
|
|
639
657
|
dvGetBigInt64Number: 9,
|
|
640
658
|
};
|
|
659
|
+
/** ScrDataViewGet per dvSet* method (the setters reuse the getter kinds;
|
|
660
|
+
* no BIG setters exist). */
|
|
661
|
+
const DV_SET_KIND = {
|
|
662
|
+
dvSetUint8: 0,
|
|
663
|
+
dvSetInt8: 1,
|
|
664
|
+
dvSetUint16: 2,
|
|
665
|
+
dvSetInt16: 3,
|
|
666
|
+
dvSetUint32: 4,
|
|
667
|
+
dvSetInt32: 5,
|
|
668
|
+
dvSetFloat32: 6,
|
|
669
|
+
dvSetFloat64: 7,
|
|
670
|
+
};
|
|
641
671
|
class LlEmitter {
|
|
642
672
|
mod;
|
|
643
673
|
/** Interned string literals: UTF-8 text → { symbol, byte length } —
|
|
@@ -1013,7 +1043,7 @@ class LlEmitter {
|
|
|
1013
1043
|
// LIBRARY mode: the runtime entry points the generated library
|
|
1014
1044
|
// symbols delegate to — declared before the extern block flushes.
|
|
1015
1045
|
if (this.mod.lib !== undefined) {
|
|
1016
|
-
this.declare(`declare void @scr_library_entry(i1 zeroext)`);
|
|
1046
|
+
this.declare(`declare void @scr_library_entry(i1 zeroext, ptr)`);
|
|
1017
1047
|
this.declare(`declare void @scr_library_reset()`);
|
|
1018
1048
|
this.declare(`declare void @scr_library_check_exc()`);
|
|
1019
1049
|
this.declare(`declare void @scr_library_set_sink(ptr, ptr)`);
|
|
@@ -1023,7 +1053,7 @@ class LlEmitter {
|
|
|
1023
1053
|
this.declare(`declare ptr @scr_library_str_in(ptr, i64)`);
|
|
1024
1054
|
}
|
|
1025
1055
|
if (this.mod.lib.exports.some((e) => e.params.includes("bytes"))) {
|
|
1026
|
-
this.declare(`declare ptr @scr_library_bytes_in(ptr, i64)`);
|
|
1056
|
+
this.declare(`declare ptr @scr_library_bytes_in(ptr, i64, ptr)`);
|
|
1027
1057
|
}
|
|
1028
1058
|
if (this.mod.lib.exports.some((e) => e.returns === "string")) {
|
|
1029
1059
|
this.declare(`declare void @scr_library_str_out(ptr, ptr, ptr)`);
|
|
@@ -1257,6 +1287,45 @@ class LlEmitter {
|
|
|
1257
1287
|
const lib = this.mod.lib;
|
|
1258
1288
|
const autoReset = lib.resultResetSymbol === null;
|
|
1259
1289
|
const out = [``, `; ── library-mode entries (profile: ${lib.profileName}) ──`, ``];
|
|
1290
|
+
// Every entry's prologue records its external symbol in the funnel's
|
|
1291
|
+
// current-entry slot (structured trap-teaching field 2); the symbols
|
|
1292
|
+
// live as internal constants, one per entry.
|
|
1293
|
+
const symConst = (sym) => `@sc_lib_sym_${sym}`;
|
|
1294
|
+
const emitSymConst = (sym) => {
|
|
1295
|
+
out.push(`${symConst(sym)} = internal constant [${Buffer.byteLength(sym, "utf8") + 1} x i8] c"${llStrBytes(sym)}"`);
|
|
1296
|
+
};
|
|
1297
|
+
emitSymConst(lib.initSymbol);
|
|
1298
|
+
if (lib.resultResetSymbol !== null)
|
|
1299
|
+
emitSymConst(lib.resultResetSymbol);
|
|
1300
|
+
if (lib.collectSymbol !== null)
|
|
1301
|
+
emitSymConst(lib.collectSymbol);
|
|
1302
|
+
for (const e of lib.exports)
|
|
1303
|
+
emitSymConst(e.symbol);
|
|
1304
|
+
out.push(``);
|
|
1305
|
+
// The runtime detected-trap overlay table (scr_runtime.h declares it,
|
|
1306
|
+
// the library trap funnel consults it): flat code/teaching/remediation
|
|
1307
|
+
// triples, one per runtime trap code (SC4013–SC4019) the profile
|
|
1308
|
+
// declares text for — the same data the C emission defines, so the
|
|
1309
|
+
// funnel-assembled sink message is emission-invariant by construction.
|
|
1310
|
+
// The empty table still defines the symbols the funnel links against.
|
|
1311
|
+
const ovlCells = [];
|
|
1312
|
+
lib.trapOverlays.forEach((o, i) => {
|
|
1313
|
+
const cell = (name, text) => {
|
|
1314
|
+
if (text === undefined) {
|
|
1315
|
+
ovlCells.push("ptr null");
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
const sym = `@sc_lib_ovl_${i}_${name}`;
|
|
1319
|
+
out.push(`${sym} = internal constant [${Buffer.byteLength(text, "utf8") + 1} x i8] c"${llStrBytes(text)}"`);
|
|
1320
|
+
ovlCells.push(`ptr ${sym}`);
|
|
1321
|
+
};
|
|
1322
|
+
cell("code", o.code);
|
|
1323
|
+
cell("teach", o.teaching);
|
|
1324
|
+
cell("rem", o.remediation);
|
|
1325
|
+
});
|
|
1326
|
+
out.push(ovlCells.length === 0
|
|
1327
|
+
? `@scr_library_trap_overlays = constant [1 x ptr] zeroinitializer`
|
|
1328
|
+
: `@scr_library_trap_overlays = constant [${ovlCells.length} x ptr] [${ovlCells.join(", ")}]`, `@scr_library_trap_overlays_len = constant i64 ${lib.trapOverlays.length}`, ``);
|
|
1260
1329
|
// The init entry: full deterministic reset-and-reevaluate. Program
|
|
1261
1330
|
// globals release and zero first (run-once guards included), then the
|
|
1262
1331
|
// runtime session reset, the error-vt interval stamps verbatim from
|
|
@@ -1266,7 +1335,7 @@ class LlEmitter {
|
|
|
1266
1335
|
const zero = ty === "double" ? f64Lit(0) : ty === "ptr" ? "null" : "false";
|
|
1267
1336
|
return ` store ${ty} ${zero}, ptr @${mangleGlobal(g.id)} ; ${g.name}`;
|
|
1268
1337
|
});
|
|
1269
|
-
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`, `}`, ``);
|
|
1338
|
+
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`, `}`, ``);
|
|
1270
1339
|
if (lib.identity !== undefined) {
|
|
1271
1340
|
// Profile-declared identity getters (the ask-2 sidecar's boot-time
|
|
1272
1341
|
// pairing fence): pure data returns with NO entry prologue — exempt
|
|
@@ -1277,15 +1346,23 @@ class LlEmitter {
|
|
|
1277
1346
|
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}`, `}`, ``);
|
|
1278
1347
|
}
|
|
1279
1348
|
if (lib.resultResetSymbol !== null) {
|
|
1280
|
-
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`, `}`, ``);
|
|
1349
|
+
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`, `}`, ``);
|
|
1281
1350
|
}
|
|
1282
1351
|
if (lib.collectSymbol !== null) {
|
|
1283
|
-
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`, `}`, ``);
|
|
1352
|
+
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`, `}`, ``);
|
|
1284
1353
|
}
|
|
1285
1354
|
for (const e of lib.exports) {
|
|
1286
1355
|
const params = [];
|
|
1287
|
-
const body = [` call void @scr_library_entry(i1 zeroext ${autoReset ? "true" : "false"})`];
|
|
1356
|
+
const body = [` call void @scr_library_entry(i1 zeroext ${autoReset ? "true" : "false"}, ptr ${symConst(e.symbol)})`];
|
|
1288
1357
|
const args = [];
|
|
1358
|
+
if (e.inboundBytesTrap !== undefined) {
|
|
1359
|
+
// The bytes-in helper's trap message: the compiler-assembled
|
|
1360
|
+
// structured trap-teaching form (0x01 text 0x1F SC4012 0x1F symbol
|
|
1361
|
+
// [0x1F remediation]) — the same bytes the C emission passes, so
|
|
1362
|
+
// the sink message is emission-invariant by construction.
|
|
1363
|
+
const trapBytes = Buffer.byteLength(e.inboundBytesTrap, "utf8");
|
|
1364
|
+
out.push(`@sc_lib_bytes_trap_${e.symbol} = internal constant [${trapBytes + 1} x i8] c"${llStrBytes(e.inboundBytesTrap)}"`, ``);
|
|
1365
|
+
}
|
|
1289
1366
|
e.params.forEach((cls, i) => {
|
|
1290
1367
|
switch (cls) {
|
|
1291
1368
|
case "f64":
|
|
@@ -1319,7 +1396,7 @@ class LlEmitter {
|
|
|
1319
1396
|
break;
|
|
1320
1397
|
case "bytes":
|
|
1321
1398
|
params.push(`ptr %a${i}_ptr`, `i64 %a${i}_len`);
|
|
1322
|
-
body.push(` %c${i} = call ptr @scr_library_bytes_in(ptr %a${i}_ptr, i64 %a${i}_len)`);
|
|
1399
|
+
body.push(` %c${i} = call ptr @scr_library_bytes_in(ptr %a${i}_ptr, i64 %a${i}_len, ptr @sc_lib_bytes_trap_${e.symbol})`);
|
|
1323
1400
|
args.push(`ptr %c${i}`);
|
|
1324
1401
|
break;
|
|
1325
1402
|
}
|
|
@@ -2558,9 +2635,13 @@ class LlEmitter {
|
|
|
2558
2635
|
if (isRefCounted(v.type))
|
|
2559
2636
|
this.moveTemp(v);
|
|
2560
2637
|
const shape = this.recordShape(s.shapeId);
|
|
2561
|
-
|
|
2638
|
+
// Signature-free shapes dispatch over their (one-typed) declared
|
|
2639
|
+
// fields and TRAP on a miss (scr_record_key_miss — JS would add
|
|
2640
|
+
// the property, which a monomorphic struct cannot); overflow
|
|
2641
|
+
// shapes keep the map insert tail.
|
|
2642
|
+
const iv = shape.indexValue ?? shape.fields[0]?.type;
|
|
2562
2643
|
if (!iv)
|
|
2563
|
-
throw new Error(`llvm emitter bug: keyed write on non-overflow shape ${s.shapeId}`);
|
|
2644
|
+
throw new Error(`llvm emitter bug: keyed write on field-free non-overflow shape ${s.shapeId}`);
|
|
2564
2645
|
const vAcc = iv.kind === "f64" ? "f64" : iv.kind === "bool" ? "bool" : "ref";
|
|
2565
2646
|
if (s.overflowOnly === true) {
|
|
2566
2647
|
// A LITERAL key naming no declared field: a plain overflow
|
|
@@ -2571,7 +2652,7 @@ class LlEmitter {
|
|
|
2571
2652
|
}
|
|
2572
2653
|
const join = B.newLabel("rks.j");
|
|
2573
2654
|
this.declare(`declare zeroext i1 @scr_str_eq(ptr, ptr)`);
|
|
2574
|
-
if (iv.kind === "dyn") {
|
|
2655
|
+
if (iv.kind === "dyn" && shape.indexValue) {
|
|
2575
2656
|
// A dyn-valued shape (the C recordKeySetHelper's dyn arm,
|
|
2576
2657
|
// inline): declared keys VALIDATE the dyn value against the
|
|
2577
2658
|
// field's type first (dynCheck — a mismatched write throws the
|
|
@@ -2656,6 +2737,19 @@ class LlEmitter {
|
|
|
2656
2737
|
B.br(join);
|
|
2657
2738
|
B.startBlock(ln);
|
|
2658
2739
|
}
|
|
2740
|
+
if (!shape.indexValue) {
|
|
2741
|
+
// The MISS on a fixed shape: release the moved-in value, throw
|
|
2742
|
+
// the catchable TypeError naming the key (scr_record_key_miss —
|
|
2743
|
+
// JS would add the property, the documented divergence).
|
|
2744
|
+
if (isRefCounted(iv))
|
|
2745
|
+
this.releaseValue(v.name, iv);
|
|
2746
|
+
this.declare(`declare void @scr_record_key_miss(ptr)`);
|
|
2747
|
+
B.line(`call void @scr_record_key_miss(ptr ${key.name})`);
|
|
2748
|
+
B.br(join);
|
|
2749
|
+
B.startBlock(join);
|
|
2750
|
+
this.emitPendingCheck();
|
|
2751
|
+
break;
|
|
2752
|
+
}
|
|
2659
2753
|
const ovf = this.recordOvfPtr(obj.name, s.shapeId);
|
|
2660
2754
|
this.mapSet(ovf, "str", vAcc, key.name, v.name);
|
|
2661
2755
|
B.br(join);
|
|
@@ -3972,7 +4066,15 @@ class LlEmitter {
|
|
|
3972
4066
|
const t = B.tmp();
|
|
3973
4067
|
B.line(`${a} = call double @scr_union_get_f64(ptr ${l.name})`);
|
|
3974
4068
|
B.line(`${b} = call double @scr_union_get_f64(ptr ${r.name})`);
|
|
3975
|
-
|
|
4069
|
+
if (e.sameValue) {
|
|
4070
|
+
// Object.is's f64 compare: NaN equals NaN, +0 differs
|
|
4071
|
+
// from -0 — the runtime SameValue.
|
|
4072
|
+
this.declare(`declare zeroext i1 @scr_num_same_value(double, double)`);
|
|
4073
|
+
B.line(`${t} = call zeroext i1 @scr_num_same_value(double ${a}, double ${b})`);
|
|
4074
|
+
}
|
|
4075
|
+
else {
|
|
4076
|
+
B.line(`${t} = fcmp oeq double ${a}, ${b}`);
|
|
4077
|
+
}
|
|
3976
4078
|
B.line(`store i1 ${t}, ptr ${slot}`);
|
|
3977
4079
|
break;
|
|
3978
4080
|
}
|
|
@@ -4051,6 +4153,31 @@ class LlEmitter {
|
|
|
4051
4153
|
// TAG against its unit arms as the test. Pass-through shape: the
|
|
4052
4154
|
// result IS the left box. Narrowed shape: the single non-unit
|
|
4053
4155
|
// arm's payload extracts (+1 for ref kinds) and the box releases.
|
|
4156
|
+
if (e.left.type.kind === "jsval") {
|
|
4157
|
+
// The island form: engine nullish test, lazy right (jsval).
|
|
4158
|
+
const l = this.emitExpr(e.left);
|
|
4159
|
+
this.moveTemp(l);
|
|
4160
|
+
this.declare(`declare zeroext i1 @scr_jsval_is_nullish(ptr)`);
|
|
4161
|
+
const slot = B.slot();
|
|
4162
|
+
B.entryAllocas.push(`${slot} = alloca ptr`);
|
|
4163
|
+
const isN = B.tmp();
|
|
4164
|
+
B.line(`${isN} = call zeroext i1 @scr_jsval_is_nullish(ptr ${l.name})`);
|
|
4165
|
+
const lu = B.newLabel("nulj.u");
|
|
4166
|
+
const lv = B.newLabel("nulj.v");
|
|
4167
|
+
const lj = B.newLabel("nulj.j");
|
|
4168
|
+
B.condBr(isN, lu, lv);
|
|
4169
|
+
B.startBlock(lu);
|
|
4170
|
+
this.releaseValue(l.name, e.left.type);
|
|
4171
|
+
this.emitBranchInto(slot, e.right);
|
|
4172
|
+
B.br(lj);
|
|
4173
|
+
B.startBlock(lv);
|
|
4174
|
+
B.line(`store ptr ${l.name}, ptr ${slot}`);
|
|
4175
|
+
B.br(lj);
|
|
4176
|
+
B.startBlock(lj);
|
|
4177
|
+
const t = B.tmp();
|
|
4178
|
+
B.line(`${t} = load ptr, ptr ${slot}`);
|
|
4179
|
+
return this.own({ name: t, type: e.type });
|
|
4180
|
+
}
|
|
4054
4181
|
if (e.left.type.kind !== "union")
|
|
4055
4182
|
throw new Error("llvm emitter bug: nullish left is not a union");
|
|
4056
4183
|
const def = this.unionsById.get(e.left.type.unionId);
|
|
@@ -5220,14 +5347,18 @@ class LlEmitter {
|
|
|
5220
5347
|
}
|
|
5221
5348
|
if (e.name === "promise.reject") {
|
|
5222
5349
|
// A fresh promise rejected through the exception cell: the
|
|
5223
|
-
// %Error-rooted reason moves in as the cell's OBJ payload
|
|
5224
|
-
//
|
|
5225
|
-
//
|
|
5350
|
+
// %Error-rooted reason moves in as the cell's OBJ payload (a
|
|
5351
|
+
// checked-dynamic reason rides the thrown-dyn REF representation
|
|
5352
|
+
// instead — identity flows to catch/unhandledRejection observers,
|
|
5353
|
+
// emitThrowValue's dyn arm), and reject_pending moves the cell
|
|
5354
|
+
// into the promise (consumed immediately — no pending check runs
|
|
5355
|
+
// in between).
|
|
5226
5356
|
if (e.type.kind !== "promise")
|
|
5227
5357
|
throw new Error("llvm emitter bug: promise.reject type");
|
|
5228
5358
|
const reasonT = e.args[0].type;
|
|
5229
|
-
if (reasonT.kind !== "object")
|
|
5359
|
+
if (reasonT.kind !== "object" && reasonT.kind !== "dyn") {
|
|
5230
5360
|
throw new Error("llvm emitter bug: promise.reject reason");
|
|
5361
|
+
}
|
|
5231
5362
|
this.declare(`declare ptr @scr_promise_new()`);
|
|
5232
5363
|
this.declare(`declare void @scr_promise_reject_pending(ptr)`);
|
|
5233
5364
|
const reason = this.emitExpr(e.args[0]);
|
|
@@ -5400,6 +5531,40 @@ class LlEmitter {
|
|
|
5400
5531
|
// boxed thunk builds its own typed copies. The callee's source
|
|
5401
5532
|
// spelling rides along for Node's "<name> is not a function".
|
|
5402
5533
|
const callee = this.emitExpr(e.callee);
|
|
5534
|
+
if (e.spreads !== undefined && e.spreads.length > 0) {
|
|
5535
|
+
// The RUNTIME-ARITY form (`f(...args)`): one fresh DOM array
|
|
5536
|
+
// collects the arguments left-to-right — plain args move in
|
|
5537
|
+
// (push takes ownership), spread args FLATTEN (push_spread
|
|
5538
|
+
// retains elements in and throws V8's spread-call TypeError for
|
|
5539
|
+
// non-iterable DOM kinds, checked per spread — JS's
|
|
5540
|
+
// ArgumentListEvaluation order) — then apply calls through the
|
|
5541
|
+
// array's elements (borrowed, exactly scr_dyn_call).
|
|
5542
|
+
this.declare(`declare ptr @scr_dyn_new_arr()`);
|
|
5543
|
+
this.declare(`declare void @scr_dyn_arr_push(ptr, ptr)`);
|
|
5544
|
+
this.declare(`declare void @scr_dyn_arr_push_spread(ptr, ptr, ptr)`);
|
|
5545
|
+
this.declare(`declare ptr @scr_dyn_apply(ptr, ptr, ptr)`);
|
|
5546
|
+
const spreadAt = new Map(e.spreads.map((s) => [s.arg, s.what]));
|
|
5547
|
+
const pack = B.tmp();
|
|
5548
|
+
B.line(`${pack} = call ptr @scr_dyn_new_arr()`);
|
|
5549
|
+
this.own({ name: pack, type: DYN });
|
|
5550
|
+
e.args.forEach((a, i) => {
|
|
5551
|
+
const v = this.emitExpr(a);
|
|
5552
|
+
const spreadWhat = spreadAt.get(i);
|
|
5553
|
+
if (spreadWhat !== undefined) {
|
|
5554
|
+
B.line(`call void @scr_dyn_arr_push_spread(ptr ${pack}, ptr ${v.name}, ptr ${this.cstr(spreadWhat)})`);
|
|
5555
|
+
this.emitPendingCheck();
|
|
5556
|
+
}
|
|
5557
|
+
else {
|
|
5558
|
+
this.moveTemp(v);
|
|
5559
|
+
B.line(`call void @scr_dyn_arr_push(ptr ${pack}, ptr ${v.name})`);
|
|
5560
|
+
}
|
|
5561
|
+
});
|
|
5562
|
+
const t = B.tmp();
|
|
5563
|
+
B.line(`${t} = call ptr @scr_dyn_apply(ptr ${callee.name}, ptr ${pack}, ptr ${this.cstr(e.calleeName)})`);
|
|
5564
|
+
const out = this.own({ name: t, type: e.type });
|
|
5565
|
+
this.emitPendingCheck();
|
|
5566
|
+
return out;
|
|
5567
|
+
}
|
|
5403
5568
|
const args = e.args.map((a) => this.emitExpr(a));
|
|
5404
5569
|
let argsPtr = "null";
|
|
5405
5570
|
if (args.length > 0) {
|
|
@@ -5797,8 +5962,12 @@ class LlEmitter {
|
|
|
5797
5962
|
? this.islandAdapter(fn.params.length, fn.ret.kind)
|
|
5798
5963
|
: this.islandTypedAdapter(fn);
|
|
5799
5964
|
this.declare(`declare ptr @scr_jsval_from_closure(ptr, i32, ptr)`);
|
|
5965
|
+
// ISLAND-REST closures encode a NEGATIVE arity (the C emitter's
|
|
5966
|
+
// rule): the wrapper hands the trailing slot the engine array of
|
|
5967
|
+
// the surplus arguments.
|
|
5968
|
+
const arity = fn.rest === true && fn.restAbi === "jsval" ? -fn.params.length : fn.params.length;
|
|
5800
5969
|
const t = B.tmp();
|
|
5801
|
-
B.line(`${t} = call ptr @scr_jsval_from_closure(ptr ${v.name}, i32 ${
|
|
5970
|
+
B.line(`${t} = call ptr @scr_jsval_from_closure(ptr ${v.name}, i32 ${arity}, ptr @${adapter})`);
|
|
5802
5971
|
return this.own({ name: t, type: e.type });
|
|
5803
5972
|
}
|
|
5804
5973
|
default: {
|
|
@@ -5981,6 +6150,18 @@ class LlEmitter {
|
|
|
5981
6150
|
return t;
|
|
5982
6151
|
});
|
|
5983
6152
|
}
|
|
6153
|
+
case "callSpread": {
|
|
6154
|
+
// Spread application (`f(...pre, ...s)`): the prelude helper's
|
|
6155
|
+
// real spread syntax — iterator protocols are the engine's own,
|
|
6156
|
+
// the guards front-run V8's spread-call TypeError texts (the name
|
|
6157
|
+
// literal is the spread expression's spelling).
|
|
6158
|
+
this.declare(`declare ptr @scr_jsval_call_spread(ptr, ptr, ptr, ptr)`);
|
|
6159
|
+
return fallible(() => {
|
|
6160
|
+
const t = B.tmp();
|
|
6161
|
+
B.line(`${t} = call ptr @scr_jsval_call_spread(ptr ${a(0)}, ptr ${a(1)}, ptr ${a(2)}, ptr ${nameSym()})`);
|
|
6162
|
+
return t;
|
|
6163
|
+
});
|
|
6164
|
+
}
|
|
5984
6165
|
case "construct": {
|
|
5985
6166
|
const pack = argPack(args.slice(1).map((x) => x.name));
|
|
5986
6167
|
this.declare(`declare ptr @scr_jsval_construct(ptr, i32, ptr)`);
|
|
@@ -5997,6 +6178,30 @@ class LlEmitter {
|
|
|
5997
6178
|
B.line(`${t} = call ptr @scr_jsval_obj_lit(i32 ${args.length / 2}, ptr ${pack})`);
|
|
5998
6179
|
return this.own({ name: t, type: e.type });
|
|
5999
6180
|
}
|
|
6181
|
+
case "tplStrings": {
|
|
6182
|
+
const pack = argPack(args.map((x) => x.name));
|
|
6183
|
+
this.declare(`declare ptr @scr_jsval_tpl_strings(i32, ptr)`);
|
|
6184
|
+
const t = B.tmp();
|
|
6185
|
+
B.line(`${t} = call ptr @scr_jsval_tpl_strings(i32 ${args.length / 2}, ptr ${pack})`);
|
|
6186
|
+
return this.own({ name: t, type: e.type });
|
|
6187
|
+
}
|
|
6188
|
+
case "objSpread": {
|
|
6189
|
+
this.declare(`declare ptr @scr_jsval_obj_spread(ptr, ptr)`);
|
|
6190
|
+
return fallible(() => {
|
|
6191
|
+
const t = B.tmp();
|
|
6192
|
+
B.line(`${t} = call ptr @scr_jsval_obj_spread(ptr ${a(0)}, ptr ${a(1)})`);
|
|
6193
|
+
return t;
|
|
6194
|
+
});
|
|
6195
|
+
}
|
|
6196
|
+
case "defineGetter": {
|
|
6197
|
+
// Getter completion for an island literal (the C emitter's
|
|
6198
|
+
// scr_jsval_define_getter shape): defines key a(1) on obj a(0)
|
|
6199
|
+
// as an engine getter invoking a(2); answers the object (+1).
|
|
6200
|
+
this.declare(`declare ptr @scr_jsval_define_getter(ptr, ptr, ptr)`);
|
|
6201
|
+
const t = B.tmp();
|
|
6202
|
+
B.line(`${t} = call ptr @scr_jsval_define_getter(ptr ${a(0)}, ptr ${a(1)}, ptr ${a(2)})`);
|
|
6203
|
+
return this.own({ name: t, type: e.type });
|
|
6204
|
+
}
|
|
6000
6205
|
case "arrLit": {
|
|
6001
6206
|
const pack = argPack(args.map((x) => x.name));
|
|
6002
6207
|
this.declare(`declare ptr @scr_jsval_arr_lit(i32, ptr)`);
|
|
@@ -6306,7 +6511,7 @@ class LlEmitter {
|
|
|
6306
6511
|
d.push(` %fnp = getelementptr inbounds %ScrClosure, ptr %c, i64 0, i32 1`, ` %fn = load ptr, ptr %fnp`);
|
|
6307
6512
|
if (ret.async) {
|
|
6308
6513
|
// The closure returns a +1 ScrPromise; from_promise takes ownership.
|
|
6309
|
-
const tagN = { void: 0, f64: 1, bool: 2, string: 3, jsval: 4, json: 0 }[ret.tag];
|
|
6514
|
+
const tagN = { void: 0, f64: 1, bool: 2, string: 3, jsval: 4, json: 0, dyn: 0 }[ret.tag];
|
|
6310
6515
|
this.declare(`declare ptr @scr_jsval_from_promise(ptr, i32)`);
|
|
6311
6516
|
d.push(` %pr = call ptr %fn(${passed.join(", ")})`, ` %prn = icmp eq ptr %pr, null`, ` br i1 %prn, label %pnull, label %pok`, `pnull:`, ` ret ptr null`, `pok:`, ` %pj = call ptr @scr_jsval_from_promise(ptr %pr, i32 ${tagN})`, ` ret ptr %pj`);
|
|
6312
6517
|
}
|
|
@@ -6331,6 +6536,13 @@ class LlEmitter {
|
|
|
6331
6536
|
this.declare(`declare void @scr_str_release(ptr)`);
|
|
6332
6537
|
d.push(` %r = call ptr %fn(${passed.join(", ")})`, ` %rn = icmp eq ptr %r, null`, ` br i1 %rn, label %snull, label %sok`, `snull:`, ` ret ptr null`, `sok:`, ` %j = call ptr @scr_jsval_from_str(ptr %r)`, ` call void @scr_str_release(ptr %r)`, ` ret ptr %j`);
|
|
6333
6538
|
break;
|
|
6539
|
+
case "dyn":
|
|
6540
|
+
// A checked-dynamic (+1 DOM) result: deep copy into the engine
|
|
6541
|
+
// (the jsMarshal dyn rule); NULL is the throw-path dummy.
|
|
6542
|
+
this.declare(`declare ptr @scr_jsval_from_dyn(ptr)`);
|
|
6543
|
+
this.declare(`declare void @scr_dyn_release(ptr)`);
|
|
6544
|
+
d.push(` %r = call ptr %fn(${passed.join(", ")})`, ` %rn = icmp eq ptr %r, null`, ` br i1 %rn, label %dnull, label %dok`, `dnull:`, ` ret ptr null`, `dok:`, ` %j = call ptr @scr_jsval_from_dyn(ptr %r)`, ` call void @scr_dyn_release(ptr %r)`, ` ret ptr %j`);
|
|
6545
|
+
break;
|
|
6334
6546
|
case "json": {
|
|
6335
6547
|
// A JSON-safe composite return: the jsMarshal path — the type-
|
|
6336
6548
|
// directed serializer, then the engine's JSON parser (deep
|
|
@@ -8044,6 +8256,18 @@ class LlEmitter {
|
|
|
8044
8256
|
// DataView getters: an omitted littleEndian is big-endian (the JS
|
|
8045
8257
|
// default). Throw Node's constant RangeError on a bad offset.
|
|
8046
8258
|
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);
|
|
8259
|
+
case "dvSetUint8":
|
|
8260
|
+
case "dvSetInt8":
|
|
8261
|
+
case "dvSetUint16":
|
|
8262
|
+
case "dvSetInt16":
|
|
8263
|
+
case "dvSetUint32":
|
|
8264
|
+
case "dvSetInt32":
|
|
8265
|
+
case "dvSetFloat32":
|
|
8266
|
+
case "dvSetFloat64":
|
|
8267
|
+
// DataView setters: [offset, value, littleEndian?] — void; throw
|
|
8268
|
+
// the getters' constant RangeError on a bad offset.
|
|
8269
|
+
return call("scr_dataview_set", "void (ptr, double, double, i32, i1 zeroext)", `ptr ${r.name}, double ${args[0].name}, double ${args[1].name}, ` +
|
|
8270
|
+
`i32 ${DV_SET_KIND[method]}, i1 ${args[2]?.name ?? "false"}`, false, true);
|
|
8047
8271
|
default: {
|
|
8048
8272
|
const _exhaustive = method;
|
|
8049
8273
|
void _exhaustive;
|
|
@@ -8424,6 +8648,42 @@ class LlEmitter {
|
|
|
8424
8648
|
if (USES_TIMERS_LIB_FNS.has(e.fn))
|
|
8425
8649
|
this.usesTimers = true;
|
|
8426
8650
|
// The handful with non-generic shapes first.
|
|
8651
|
+
if (e.fn === "error.argTypeThrow") {
|
|
8652
|
+
// Always throws with the runtime-rendered Received tail (the
|
|
8653
|
+
// error.nodeThrow dummy pattern). Borrows all three.
|
|
8654
|
+
const an = this.emitExpr(e.args[0]);
|
|
8655
|
+
const ex = this.emitExpr(e.args[1]);
|
|
8656
|
+
const got = this.emitExpr(e.args[2]);
|
|
8657
|
+
this.declare(`declare void @scr_throw_arg_type(ptr, ptr, ptr)`);
|
|
8658
|
+
B.line(`call void @scr_throw_arg_type(ptr ${an.name}, ptr ${ex.name}, ptr ${got.name})`);
|
|
8659
|
+
const ty = this.llType(e.type);
|
|
8660
|
+
if (ty === "void") {
|
|
8661
|
+
this.emitPendingCheck();
|
|
8662
|
+
return { name: "", type: e.type };
|
|
8663
|
+
}
|
|
8664
|
+
const dummy = ty === "double" ? f64Lit(0) : ty === "i1" ? "false" : "null";
|
|
8665
|
+
const out = this.own({ name: dummy, type: e.type });
|
|
8666
|
+
this.emitPendingCheck();
|
|
8667
|
+
return out;
|
|
8668
|
+
}
|
|
8669
|
+
if (e.fn === "error.nodeThrow") {
|
|
8670
|
+
// The compiler-resolved Node-parity throw (always throws — the
|
|
8671
|
+
// typed dummy is abandoned by the pending check's unwind).
|
|
8672
|
+
const kind = this.emitExpr(e.args[0]);
|
|
8673
|
+
const code = this.emitExpr(e.args[1]);
|
|
8674
|
+
const msg = this.emitExpr(e.args[2]);
|
|
8675
|
+
this.declare(`declare void @scr_throw_node_coded(double, ptr, ptr)`);
|
|
8676
|
+
B.line(`call void @scr_throw_node_coded(double ${kind.name}, ptr ${code.name}, ptr ${msg.name})`);
|
|
8677
|
+
const ty = this.llType(e.type);
|
|
8678
|
+
if (ty === "void") {
|
|
8679
|
+
this.emitPendingCheck();
|
|
8680
|
+
return { name: "", type: e.type };
|
|
8681
|
+
}
|
|
8682
|
+
const dummy = ty === "double" ? f64Lit(0) : ty === "i1" ? "false" : "null";
|
|
8683
|
+
const out = this.own({ name: dummy, type: e.type });
|
|
8684
|
+
this.emitPendingCheck();
|
|
8685
|
+
return out;
|
|
8686
|
+
}
|
|
8427
8687
|
if (e.fn === "global.undefRead") {
|
|
8428
8688
|
// A declare-d const nothing defines: Node's catchable
|
|
8429
8689
|
// ReferenceError at the access (always throws — the typed dummy is
|
|
@@ -9655,6 +9915,28 @@ class LlEmitter {
|
|
|
9655
9915
|
this.emitPendingCheck();
|
|
9656
9916
|
return out;
|
|
9657
9917
|
}
|
|
9918
|
+
if (e.fn === "sp.pipeline") {
|
|
9919
|
+
// pipeline(count, s1..sn) settling a void promise: the stream list
|
|
9920
|
+
// rides the callback form's stack array, no callback slot.
|
|
9921
|
+
const countArg = e.args[0];
|
|
9922
|
+
if (countArg.kind !== "numLit")
|
|
9923
|
+
throw new Error(`llvm emitter bug: ${e.fn} count not a literal`);
|
|
9924
|
+
const n = countArg.value;
|
|
9925
|
+
const args = e.args.map((a) => this.emitExpr(a));
|
|
9926
|
+
const arr = B.slot();
|
|
9927
|
+
B.entryAllocas.push(`${arr} = alloca [${n} x ptr]`);
|
|
9928
|
+
for (let i = 0; i < n; i++) {
|
|
9929
|
+
const p = B.tmp();
|
|
9930
|
+
B.line(`${p} = getelementptr inbounds [${n} x ptr], ptr ${arr}, i64 0, i64 ${i}`);
|
|
9931
|
+
B.line(`store ptr ${args[1 + i].name}, ptr ${p}`);
|
|
9932
|
+
}
|
|
9933
|
+
const t = B.tmp();
|
|
9934
|
+
this.declare(`declare ptr @scr_sp_pipeline(double, ptr)`);
|
|
9935
|
+
B.line(`${t} = call ptr @scr_sp_pipeline(double ${f64Lit(n)}, ptr ${arr})`);
|
|
9936
|
+
const out = this.own({ name: t, type: e.type });
|
|
9937
|
+
this.emitPendingCheck();
|
|
9938
|
+
return out;
|
|
9939
|
+
}
|
|
9658
9940
|
if (e.fn === "stream.pipeline" || e.fn === "stream.pipelineDyn") {
|
|
9659
9941
|
// pipeline(count, s1..sn, cb): the destination answers +1. The
|
|
9660
9942
|
// stream list rides a stack array (the C compound literal).
|