mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-24 06:14:01 +08:00
The new @scriptc/threads package exports publish(value) and
sharesPublishedGraphs. Node.js runs its JavaScript: publish validates
the whole graph (plain objects, arrays, class instances, Maps, Sets and
primitives other than symbols), then deep-freezes it, and published Maps
and Sets reject mutation. scriptc builds lower both exports to
intrinsics and never compile the package body.
In scriptc, publish makes the graph immutable and immortal: a
compiler-emitted walker per static type (llvm/publish.ts) marks every
object rc == SIZE_MAX through a runtime worklist (scr_publish.c), so
retains, releases and the collector skip it and nothing frees it, and
the objects leave the collector's buffers. Hierarchy members dispatch on
the concrete class; arrays, maps, sets, strings and dyn subgraphs have
runtime walkers. Static types over-approximate a graph, so an
unpublishable type gets a refusing walker that fails only when a value
is present, and every mark is logged so a refusal restores the whole
graph, exactly like the Node implementation's validate-first order.
A typed-ref capsule over a published object travels through postMessage
and workerData as a pointer (a fresh capsule in the receiver; vtables,
adapters and type keys are process-wide); immortal dyn graphs inside a
message are shared the same way. Iterating a published map no longer
writes its iteration depth.
Stores into the static types a program publishes (computed by
backend/publication.ts, a class with its whole hierarchy) carry a guard
that throws Node's frozen-object TypeErrors, and may-throw counts them.
The corpus program pins the contract against Node: shared and cyclic
class graphs with arrays, maps, sets and records read identically on
both threads, every write form fails with Node's message, unpublished
instances of the same classes stay writable, a refused publish leaves
its graph unchanged, and a worker-published graph reaches the main
thread. packages/threads/README.md documents the contract and the
differences (prototypes and identity across messages).
Each mark records its object kind, so a successful publish takes the
objects out of the RC audit's live counts (immortal objects are never
freed).
Dates (time values) and process streams (descriptors) are scalars in
scriptc, so their walkers refuse a date field or root directly instead
of pushing its bits as a pointer; the refusal corpus program pins the
statically typed refusals (date, function, RegExp, typed array and Error
values in class and record fields, and a date root) against Node.
Main lowers a discarded or union-typed `xs.pop()` to a length
truncation; those stores now carry a `pop` marker so a published array
fails with pop's own TypeError ("Cannot delete property 'N'", or the
length message for an empty array, whose `length = 0` store the emitter
drops unless the array type can be published).
155 lines
5.0 KiB
JavaScript
155 lines
5.0 KiB
JavaScript
import { withWorkerRuntimeVariants } from "../runtime-pack-common/worker-matrix.mjs";
|
|
import { withLibraryRuntimeFlavors } from "../runtime-pack-common/library-matrix.mjs";
|
|
|
|
/**
|
|
* The executable runtime-pack matrix. This is the single source of truth for
|
|
* both release compilation and the generated feature predicates consumed by
|
|
* the compiler. A predicate is intentionally data, not JavaScript, so the
|
|
* installed compiler can validate and evaluate it deterministically.
|
|
*/
|
|
|
|
const any = (...features) => ({ any: features });
|
|
const all = (...features) => ({ all: features });
|
|
|
|
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_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_path.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_alloc.c",
|
|
];
|
|
|
|
// ld64 dead-strips Mach-O symbol subsections without an ELF-style compile
|
|
// flag. Keep this checked-in metadata alongside the matrix so pack build and
|
|
// source/external linking share one documented executable recipe.
|
|
export const EXECUTABLE_SECTION_ELIMINATION = {
|
|
compile_flags: [],
|
|
link_flags: ["-Wl,-dead_strip"],
|
|
};
|
|
|
|
const optional = [
|
|
["scr_copying.c", "copying"],
|
|
["scr_file_handle.c", "fileHandle"],
|
|
["scr_regex.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")],
|
|
["scr_dc.c", "dc"],
|
|
["scr_async_dyn.c", any("dynAsync", "dynInvoke", "dc", "fileHandle", "nativeFetch")],
|
|
["scr_zlib.c", "zlib"],
|
|
["scr_zlib_island.c", all("zlib", "dynamic")],
|
|
["scr_events.c", "events"],
|
|
["scr_readline.c", "events"],
|
|
["scr_events_emitter.c", "emitter"],
|
|
["scr_dyn_handle.c", any("emitter", "netEffective")],
|
|
["scr_symbol.c", "symbol"],
|
|
["scr_bigint_assert.c", all("assert", "bigint")],
|
|
["scr_qs.c", "qs"],
|
|
["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_stream.c", "stream"],
|
|
["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"],
|
|
["scr_watch.c", "watch"],
|
|
["scr_ffi_queue.c", "foreignFfi"],
|
|
["scr_test.c", "nodeTest"],
|
|
["scr_tls_ca.c", "tlsCaEffective"],
|
|
["scr_tls.c", "tlsEffective"],
|
|
["scr_fetch.c", "nativeFetch"],
|
|
["scr_island.c", "dynamic"],
|
|
["scr_web.c", "dynamic"],
|
|
["scr_inspect_island.c", all("dynamic", "inspect")],
|
|
["scr_net_island.c", "netIslandEffective"],
|
|
];
|
|
|
|
function variantsFor(source) {
|
|
const dynamicOnly = new Set([
|
|
"scr_zlib_island.c",
|
|
"scr_island.c",
|
|
"scr_web.c",
|
|
"scr_inspect_island.c",
|
|
"scr_net_island.c",
|
|
]);
|
|
if (dynamicOnly.has(source)) {
|
|
return [{ id: "dynamic", when: { dynamic: true }, defines: ["SCR_DYNAMIC"] }];
|
|
}
|
|
const variants = [{ id: "default", when: {}, defines: [] }];
|
|
if (source === "scr_bytes.c") {
|
|
variants.push({
|
|
id: "text-decoder-legacy",
|
|
when: { textDecoderLegacy: true },
|
|
defines: ["SCR_TEXT_DECODER_LEGACY"],
|
|
});
|
|
}
|
|
variants.push({ id: "dynamic", when: { dynamic: true }, defines: ["SCR_DYNAMIC"] });
|
|
if (source === "scr_bytes.c") {
|
|
variants.push({
|
|
id: "dynamic-text-decoder-legacy",
|
|
when: { dynamic: true, textDecoderLegacy: true },
|
|
defines: ["SCR_DYNAMIC", "SCR_TEXT_DECODER_LEGACY"],
|
|
});
|
|
}
|
|
return variants;
|
|
}
|
|
|
|
export const RUNTIME_PACK_MATRIX = withLibraryRuntimeFlavors(
|
|
withWorkerRuntimeVariants({
|
|
schema: "scriptc.runtime-pack-matrix.v1",
|
|
target: {
|
|
name: "macos-arm64",
|
|
llvm_triple: "arm64-apple-macosx14.0.0",
|
|
architecture: "arm64",
|
|
object_format: "macho",
|
|
minimum_os: "14.0",
|
|
},
|
|
flavors: { release: { optimization: "-O2" }, dev: { optimization: "-O0" } },
|
|
executable_section_elimination: EXECUTABLE_SECTION_ELIMINATION,
|
|
runtime_units: [
|
|
...BASE_RUNTIME_SOURCES.map((source) => ({ source, predicate: true })),
|
|
...optional.map(([source, predicate]) => ({ source, predicate })),
|
|
].map((unit) => ({ ...unit, variants: variantsFor(unit.source) })),
|
|
archives: [
|
|
{ id: "quickjs", predicate: "dynamic" },
|
|
{ id: "libregexp", predicate: { all: ["regex"], not: ["dynamic"] } },
|
|
{ id: "zlib", predicate: "zlibEffective" },
|
|
{ id: "mbedtls", predicate: "tlsEffective" },
|
|
],
|
|
system_libraries: [
|
|
{ name: "System", predicate: true },
|
|
{ name: "m", predicate: "dynamic" },
|
|
],
|
|
}),
|
|
);
|