mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-27 06:43:19 +08:00
251 lines
9.3 KiB
JavaScript
251 lines
9.3 KiB
JavaScript
import { withWorkerRuntimeVariants } from "./worker-matrix.mjs";
|
|
import { withLibraryRuntimeFlavors } from "./library-matrix.mjs";
|
|
|
|
/**
|
|
* Shared release-runtime pack matrix. Platform package scripts provide the
|
|
* target descriptor, then this module fixes feature reachability and the
|
|
* compile/link flags required by every generated runtime object.
|
|
*/
|
|
const any = (...features) => ({ any: features });
|
|
const all = (...features) => ({ all: features });
|
|
|
|
/* Every runtime pack matrix uses these lists, so a new runtime source is
|
|
* one line here. Their order is the link order of the units an executable
|
|
* selects: keep a new unit next to the units it references, and treat any
|
|
* reordering as a change to every executable's layout. */
|
|
export const BASE_RUNTIME_SOURCES = [
|
|
"scr_context.c",
|
|
"scr_shared.c",
|
|
"scr_number.c",
|
|
"scr_bigint.c",
|
|
"scr_string.c",
|
|
"scr_grapheme.c",
|
|
"scr_array.c",
|
|
"scr_bytes.c",
|
|
"scr_bytes_io.c",
|
|
"scr_fs_cp.c",
|
|
"scr_map.c",
|
|
"scr_closure.c",
|
|
"scr_ffi.c",
|
|
"scr_object.c",
|
|
"scr_union.c",
|
|
"scr_exception.c",
|
|
"scr_error.c",
|
|
"scr_console.c",
|
|
"scr_lib.c",
|
|
"scr_hash.c",
|
|
"scr_path.c",
|
|
"scr_os.c",
|
|
"scr_url.c",
|
|
"scr_url_params.c",
|
|
"scr_json.c",
|
|
"scr_node_builtin.c",
|
|
"scr_async.c",
|
|
"scr_crypto_async.c",
|
|
"scr_child.c",
|
|
"scr_cycle.c",
|
|
"scr_publish.c",
|
|
"scr_region.c",
|
|
"scr_itable.c",
|
|
"scr_slots.c",
|
|
"scr_alloc.c",
|
|
];
|
|
|
|
export const OPTIONAL_RUNTIME_SOURCES = [
|
|
["scr_copying.c", "copying"],
|
|
["scr_file_handle.c", "fileHandle"],
|
|
["scr_regex.c", "regex"],
|
|
["scr_glob.c", "regex"],
|
|
["scr_idna.c", "regex"],
|
|
["scr_assert.c", any("assert", "regex", "symbol")],
|
|
["scr_inspect.c", "inspect"],
|
|
["scr_console_native.c", "inspect"],
|
|
["scr_dyn_invoke.c", any("dynInvoke", "nativeFetch")],
|
|
// Buffer.prototype methods called on checked-dynamic values.
|
|
["scr_bytes_dyn.c", all("dynBuffer", "dynInvoke")],
|
|
// Builtin functions read as values in JavaScript dependencies.
|
|
["scr_builtin_values.c", "builtinValues"],
|
|
["scr_dc.c", "dc"],
|
|
// The dynamic tier's jsval values (two-tier design I3): linked only into
|
|
// programs whose IR has dynamic-tier operations.
|
|
["scr_js_value.c", "dynTier"],
|
|
["scr_js_object.c", "dynTier"],
|
|
["scr_event_target.c", any("eventTarget", "nativeFetch")],
|
|
["scr_async_dyn.c", any("dynAsync", "dynInvoke", "dc", "fileHandle", "nativeFetch")],
|
|
// The crypto global's object extends scr_async_dyn.c's crypto object.
|
|
["scr_webcrypto_object.c", all("webcrypto", "dynAsync")],
|
|
// The performance timeline emits its buffer warning through scr_async_dyn.c.
|
|
["scr_perf.c", "dynAsync"],
|
|
// perf_hooks event-loop metrics, only for programs that read them.
|
|
["scr_perf_loop.c", "perfLoop"],
|
|
// Blob and File box their reads as dyn promises through scr_async_dyn.c.
|
|
["scr_blob.c", "dynAsync"],
|
|
["scr_zlib.c", "zlib"],
|
|
["scr_events.c", "events"],
|
|
["scr_readline.c", "events"],
|
|
["scr_readline_tty.c", all("events", "regex")],
|
|
["scr_events_emitter.c", "emitter"],
|
|
// events.once with options registers through the emitter and event-target units.
|
|
["scr_events_once_signal.c", "eventsOnceSignal"],
|
|
["scr_dyn_handle.c", any("emitter", "netEffective")],
|
|
["scr_symbol.c", "symbol"],
|
|
["scr_bigint_assert.c", all("assert", "bigint")],
|
|
["scr_qs.c", "qs"],
|
|
// The legacy url unit lowercases and normalizes through the regex unit
|
|
// and warns through the dyn-async one.
|
|
["scr_url_legacy.c", all("regex", "qs", "dynAsync")],
|
|
["scr_util.c", "parseArgs"],
|
|
// Utility objects must only reference runtime families selected with them.
|
|
["scr_util_compare.c", all("parseArgs", "symbol")],
|
|
["scr_util_style.c", all("parseArgs", "inspect", "dynAsync")],
|
|
["scr_util_callable.c", all("parseArgs", "inspect", "dynAsync", "dynInvoke", "regex")],
|
|
// util.promisify over an untyped function creates dyn promises and calls.
|
|
["scr_util_promisify.c", all("utilPromisify", "dynAsync", "dynInvoke")],
|
|
// Untyped EventEmitter and stream constructor values call listeners
|
|
// through the dyn-invoke unit, inspect unhandled 'error' payloads and
|
|
// create EventEmitter's private symbols.
|
|
["scr_dyn_builtin_class.c", all("dynBuiltinClass", "inspect", "dynInvoke", "symbol", "emitter")],
|
|
// Their stream half also references the stream unit.
|
|
[
|
|
"scr_dyn_builtin_stream.c",
|
|
all(
|
|
"dynBuiltinStream",
|
|
"dynBuiltinClass",
|
|
"stream",
|
|
"inspect",
|
|
"dynInvoke",
|
|
"symbol",
|
|
"emitter",
|
|
),
|
|
],
|
|
["scr_stream.c", "stream"],
|
|
// The zlib stream classes reference both the zlib engine and the stream unit.
|
|
["scr_zlib_stream.c", all("zlib", "stream")],
|
|
// The Readable operators await through the dyn-async unit.
|
|
["scr_stream_ops.c", all("stream", "dynAsync")],
|
|
// Checked-dynamic stream slots call JavaScript members through the dyn-invoke unit.
|
|
["scr_stream_dyn.c", "streamDyn"],
|
|
// Own properties JavaScript adds to children.
|
|
["scr_dyn_handle_props.c", "handleProps"],
|
|
// for await over checked-dynamic values.
|
|
["scr_dyn_for_await.c", "dynForAwait"],
|
|
// fs.ReadStream / fs.WriteStream reference only the stream unit and base units.
|
|
["scr_fs_stream.c", "stream"],
|
|
// FileHandle streams reference both the stream unit and FileHandle.
|
|
["scr_fs_stream_fh.c", all("stream", "fileHandle")],
|
|
["scr_loop_kqueue.c", any("netEffective", "dgram")],
|
|
["scr_loop_epoll.c", any("netEffective", "dgram")],
|
|
["scr_loop_wsapoll.c", any("netEffective", "dgram")],
|
|
["scr_net.c", "netEffective"],
|
|
["scr_http.c", "httpEffective"],
|
|
["scr_http2.c", "http2"],
|
|
["scr_dgram.c", "dgram"],
|
|
// The dns promise forms run over the dgram unit's callback forms.
|
|
["scr_dns_promises.c", all("dgram", "dnsPromises")],
|
|
// Sockets as untyped values run over the dgram unit.
|
|
["scr_dgram_dyn.c", all("dgram", "dgramDyn")],
|
|
["scr_watch.c", "watch"],
|
|
["scr_ffi_queue.c", "foreignFfi"],
|
|
["scr_test.c", "nodeTest"],
|
|
["scr_tls_ca.c", "tlsCaEffective"],
|
|
["scr_tls.c", "tlsEffective"],
|
|
["scr_cipher.c", "cipher"],
|
|
["scr_ecdh.c", "ecdh"],
|
|
["scr_pki.c", "pki"],
|
|
["scr_wasm.c", "wasm"],
|
|
["scr_webcrypto.c", "webcrypto"],
|
|
["scr_webcrypto_pki.c", all("webcrypto", "pki")],
|
|
["scr_ed25519.c", all("pki", "ed25519")],
|
|
// WebCrypto's AES ciphers run over the cipher feature's mbedTLS archive.
|
|
["scr_webcrypto_aes.c", all("cipher", "webcrypto")],
|
|
["scr_fetch.c", "nativeFetch"],
|
|
];
|
|
|
|
export function variantsFor(source) {
|
|
const variants = [{ id: "default", when: {}, defines: [] }];
|
|
// Programs with dynamic-tier code keep the tier's hidden classes current
|
|
// in checked objects (two-tier design S4); every other program links the
|
|
// ordinary object, byte for byte.
|
|
if (source === "scr_json.c") {
|
|
variants.push({ id: "dyn-tier", when: { dynTier: true }, defines: ["SCR_JS_TIER"] });
|
|
}
|
|
if (source === "scr_bytes.c") {
|
|
variants.push({
|
|
id: "text-decoder-legacy",
|
|
when: { textDecoderLegacy: true },
|
|
defines: ["SCR_TEXT_DECODER_LEGACY"],
|
|
});
|
|
}
|
|
// Programs that assign process.emitWarning link the replacement-aware
|
|
// warning paths; every other program keeps the default object.
|
|
if (source === "scr_async_dyn.c") {
|
|
variants.push({
|
|
id: "warning-replace",
|
|
when: { warningReplace: true },
|
|
defines: ["SCR_WARNING_REPLACE"],
|
|
});
|
|
}
|
|
// stdin setEncoding, string data listeners and stdio 'resize' events.
|
|
if (source === "scr_events.c") {
|
|
variants.push({
|
|
id: "stdio-extended",
|
|
when: { stdioExtended: true },
|
|
defines: ["SCR_STDIO_EXTENDED"],
|
|
});
|
|
}
|
|
if (source === "scr_cycle.c") {
|
|
// The young-in nursery (SCRIPTC_YOUNG_NURSERY=1): the collector with
|
|
// nursery collections; programs built without it link the default.
|
|
variants.push({
|
|
id: "young-nursery",
|
|
when: { youngNursery: true },
|
|
defines: ["SCR_YIN"],
|
|
});
|
|
}
|
|
return variants;
|
|
}
|
|
|
|
export function createRuntimePackMatrix({
|
|
target,
|
|
compileFlags,
|
|
systemLibraries,
|
|
extraRuntimeSources = [],
|
|
omitRuntimeSources = [],
|
|
omitOptionalSources = [],
|
|
omitArchives = [],
|
|
libraryOnly = false,
|
|
}) {
|
|
const vendorArchives = [
|
|
{ id: "quickjs", predicate: false },
|
|
{ id: "libregexp", predicate: "regex" },
|
|
{ id: "zlib", predicate: "zlibEffective" },
|
|
{ id: "mbedtls", predicate: any("tlsEffective", "cipher", "ecdh", "pki") },
|
|
];
|
|
const matrix = withLibraryRuntimeFlavors(
|
|
withWorkerRuntimeVariants({
|
|
schema: "scriptc.runtime-pack-matrix.v1",
|
|
target,
|
|
flavors: { release: { optimization: "-O2" }, dev: { optimization: "-O0" } },
|
|
executable_section_elimination: { compile_flags: compileFlags },
|
|
runtime_units: [
|
|
...BASE_RUNTIME_SOURCES.filter((source) => !omitRuntimeSources.includes(source)).map(
|
|
(source) => ({ source, predicate: true }),
|
|
),
|
|
...extraRuntimeSources.map((source) => ({ source, predicate: true })),
|
|
...OPTIONAL_RUNTIME_SOURCES.filter(([source]) => !omitOptionalSources.includes(source)).map(
|
|
([source, predicate]) => ({ source, predicate }),
|
|
),
|
|
].map((unit) => ({ ...unit, variants: variantsFor(unit.source) })),
|
|
archives: vendorArchives.filter(({ id }) => !omitArchives.includes(id)),
|
|
system_libraries: systemLibraries,
|
|
}),
|
|
);
|
|
if (libraryOnly) {
|
|
matrix.flavors = Object.fromEntries(
|
|
Object.entries(matrix.flavors).filter(([name]) => name.startsWith("library-")),
|
|
);
|
|
matrix.archives = matrix.archives.filter(({ id }) => id === "libregexp" || id === "zlib");
|
|
}
|
|
return matrix;
|
|
}
|