crypto.subtle.importKey('raw', ...) for HMAC keys, HMAC sign and verify,
and the SHA-1/SHA-2 digests compile through the crypto global, with
CryptoKey values as native handles. scr_webcrypto.c is only the WebCrypto
layer (Web IDL conversion, algorithm normalization, the CryptoKey handle,
promise wrapping and Node's TypeErrors and DOMExceptions) over node:crypto's
digest core and deferred promise queue. It links only into programs that
call these methods (the new webcrypto link feature). Other algorithms, the
jwk format and the other SubtleCrypto methods are SC2020 refusals.
The real jose@6.2.12 HS256 path (SignJWT, jwtVerify) now runs natively. It
also needed four compiler fixes: object patterns of positions and length
over arrays, the Uint8Array base64/hex feature probes, a compile-time
String.fromCharCode.apply, and structuredClone of a parameter whose default
is {}.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A build now translates every WebAssembly module whose bytes it can see
(W2's discovery) into LLVM IR with a TypeScript translator
(packages/compiler/src/wasm/module.ts, translate.ts) and appends it to the
program module, so the existing LLVM helper optimizes, partitions and
caches it with the program. The program also emits scr_wasm_registry, a
portable table of module descriptors (scr_wasm_abi.h). At run time,
WebAssembly.compile, instantiate, validate, new Module and new Instance
find the translated module by the SHA-256 of its bytes; bytes the build did
not see reject with a CompileError. There is no interpreter and no JIT.
The runtime (scr_wasm.c, link-gated by the new `wasm` feature, handle tags
inside W0's headroom) implements the JavaScript API once, over
descriptors, with Node's semantics and messages: exports (functions,
memories, tables, globals), imports (functions, immutable globals, and
memories, tables and globals other instances export), every trap as
WebAssembly.RuntimeError, the CompileError, LinkError and RuntimeError
classes, compile and instantiate settling on a later turn, and
globalThis.WebAssembly as a value. On 64-bit Linux and macOS, memories sit
in 8 GiB guard reservations and a SIGSEGV/SIGBUS handler turns faults into
traps or stack exhaustion; async fibers get a guard page on first use.
Sanitizer builds and Windows check bounds and the stack explicitly. A
WebAssembly.Module crosses to workers through W0's transfer hook (W4).
W1's refusals become lowerings; the Memory, Table and Global constructors,
Module.imports/exports/customSections and the streaming functions still
refuse with SC2020. The globals: WebAssembly compatibility row moves to
partial.
Evidence: differential corpus programs for the API, TypeScript use and the
codemode worker shape, plus five programs executing about 9,300 commands
of the WebAssembly 2.0 spec suite; all match Node in the plain and
sanitized lanes. quickjs-wasi runs through its own glue, matching Node
(apart from a pre-existing non-wasm fence) and on par with or faster than
V8. The zero-cost gate leaves every non-wasm program byte-identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The process.emitWarning replacement and the stdin encoding, string data
listener and stdio 'resize' support changed runtime functions every
program with the dyn-async or events unit links (the shared warning
paths, stdin delivery, the process stream object) and grew their
thread-local state. That code now compiles only into new runtime-pack
variants, SCR_WARNING_REPLACE of scr_async_dyn.c and SCR_STDIO_EXTENDED
of scr_events.c, which the link selects when the program assigns
process.emitWarning or reaches setEncoding, a string 'data' listener or
'resize'. The default objects are byte-identical to before, so other
executables do not change. The development and sanitizer builds pass the
same defines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stage S3 of the two-tier design: dynamic-tier functions compute with
jsval, a new IR type holding a 64-bit NaN-boxed word whose numbers,
booleans, undefined and null are immediates, so a number between two
dynamic operators is no longer a heap node.
- IR: the jsval type and js.* builtins (operators and the boundary
conversions fromDyn/toDyn/fromF64/fromBool/fromStr/fromBigInt/toF64).
The jsval pass rewrites dynamic-tier functions after tier assignment:
operator chains, comparisons, number checks and truthiness of operator
results run on jsvals; dyn locals become jsval locals when that saves
boxing; dynamic functions called only from dynamic functions return a
jsval. IR version 17 serializes each function's tier.
- Runtime: scr_js.h and scr_js_value.c behind the dynTier feature
(invariant I3); static runtime units never include scr_js.h.
- Backend: number cases inline (immediate doubles and NUM cells), always
inlined jsval retain/release; 32-bit targets keep boxed cells.
- Interprocedural analyses see jsval conversions as the dyn forms they
replace, so no fact about a static function changes.
Static functions are untouched: typed programs and the self-hosted
compiler's static functions compile to byte-identical LLVM.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main now has #1286 and later collector changes. Resolved in scr_cycle.c:
the scheduled collection point collects the nursery, then notes the
live-count fall (death rule). Semantic fixes for the new main code:
a full pass's markGray no longer overwrites a young object's `buf` (its
nursery index) with the component number, and a nursery collection
refreshes the death rule's live reading at its end so the young garbage
it frees does not count as deaths outside passes. Formats the runtime
pack matrix test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SCRIPTC_YOUNG_NURSERY=1 at compile time makes an executable allocate
traced, program-owned class instances and records young and link the
collector unit built with SCR_YIN (a runtime pack variant of
scr_cycle.c; libraries never get it). The emitted constructor lists the
object in a per-thread nursery and marks its header: generation
SCR_CYC_YOUNG and its nursery index under the buffered bit, so every
existing release path treats it as a buffered candidate (no call while it
stays alive; scr_cyc_on_dead takes it out of the nursery at its death).
A nursery collection (whenever 4096 young objects are live, at collection
points, before full sweeps and limited passes) counts each young object's
references from other young objects, marks from the objects whose count is
below their reference count (referenced from outside the nursery: stacks,
globals, older objects, runtime structures, FFI, fibers, coroutine
frames), frees what stays unmarked, and gives up the dead set's outgoing
edges after the teardowns. The counts are recomputed at every collection
instead of maintained by a store barrier, so soundness rests only on the
invariants trial deletion already needs. Survivors join trial deletion's
nursery and outside roots become candidates; trial deletion walks young
objects it reaches as nursery-level objects. Per-type admission statistics
send types that do not die in young cycles back to trial deletion for a
while. Publication takes young objects out of the nursery. The RC audit
build checks nursery membership and counts at every collection.
With the flag off, the compiler emits and links exactly what it did
before (249 programs and the self-hosted compiler compared
byte-identical). Measured with the flag on: cg-rings -38%, cg-pairs -27%,
the runtime suite geomean -0.3% (published-graphs +3.4%), the self-hosted
compiler neutral; shapes whose cycles go through arrays or closures
(phase 2) pay without gaining.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stage S2 of the two-tier design. IrFunction gains a tier (absent means
static); lowering assigns it from function bodies, placing functions that
use the dyn vocabulary in the dynamic tier, and the validator enforces
invariant I1: a static function performs no dynamic operation, only
boundary operations (dynFrom, dynCheck, kind tests) and moves. Serialized
IR keeps the field out in this stage and loaders derive it again, so every
IR, LLVM and executable artifact is unchanged.
Every committed refusal and runtime fence becomes a recorded demotion
request attributed to the binding, field, function instance, class or
module the dynamic tier would take over, while the compiler still refuses
and fences as before. `scriptc coverage` reports dynamic-tier statements
(statementsDynamic), `--explain-dynamic[=<name>]` prints the demotion
chains, and `--tier=auto|static-only` is wired through build, run and
coverage for stage S6; both modes compile identically today.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A package typed only by an @types twin was judged under the twin's name
and refused with "its import resolves to '@types/x/index.d.ts', not to
runtime JavaScript". Selection now resolves the runtime package, and the
refusal names it with the --npm-static option that compiles it anyway.
- Refusals the declaration and shipped-JS heuristics make carry the same
remedy as a diagnostic hint; a dependency of a named package suggests
the transitive form.
- `--npm-static=pkg...` (and `"pkg..."` in a library profile) selects the
package and every package its files import, nested require() calls
included, without the eligibility heuristics.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`scriptc build|run --detached-exit` opts an executable into handing the address-space teardown after process.exit to a helper process on Linux. The helper shares the address space (CLONE_VM), blocks signals, closes every descriptor but the read end of a pipe and waits for EOF on it. The kernel releases an exiting process's memory (exit_mm) before its files (exit_files), so EOF means the helper holds the last reference; it then exits and the kernel frees the pages there instead of before the parent sees the exit (30-40 ms per GB of 4 KiB pages; tsc-ts 20-110 ms). The same latency mold hides with --fork.
It is a build-time choice, not a run-time knob, because the helper keeps the executable mapped (overwriting the binary right after it exits can fail with ETXTBSY) and the memory charged to the cgroup for up to ~100 ms, and the teardown CPU time leaves the parent's rusage. The program object defines `scr_detached_exit = 1`, overriding the runtime's weak default of 0, so no runtime flavor or linker flag is added. The option is part of the early executable cache and route keys; executables only, no effect on other platforms.
Speed is a third native optimization posture next to release (default,
-O2) and dev (-O0). It is optimized exactly like release at the C/LLVM
level and is the switch for optimizations that trade executable size and
build time for run-time speed, so the default release build stays inside
the binary-size budget.
- backend/optimization.ts: the NativeOptimization type, its -O class, and
cache-key helpers. Release keeps its historical key shapes (absent).
- CLI: build/run/cache warm accept speed; usage text names the trade.
Bootstrap's routed executable cache mirrors the posture.
- Early executable cache keys and native-feature validation include speed,
so release, dev, and speed entries never satisfy one another.
- Runtime packs: an optional executable `speed` flavor (-O2, only beside
release). Speed links it when present and the release objects otherwise;
library modes link their release flavor. The sanitizer lane follows the
same flavor key.
- Library profiles accept "speed".
- WASI release-only linker flags apply to speed too.
- bench-runtime: --baseline-optimization/--candidate-optimization and a
per-contender cold_build_ms.
Release executables are byte-identical to the stack tip for all 14
benchmark workloads (macOS arm64, sha256 of executables built from both
trees).
- Add native worker execution with isolated module state, structured messages, and lifecycle controls.
- Support shared buffers and integer atomics with coordinated runtime ownership and cancellation.
- Extend compiler, runtime-pack, differential, and compatibility coverage for native concurrency.
- Enforce oxlint and oxfmt for owned JavaScript and TypeScript with independent CI checks.
- Preserve compiler import boundaries and protected fixtures while cleaning up lint findings.
- Standardize source formatting and validate import, fixture, and embedded-source protections.
* feat: ship the self-hosted native scriptc CLI
- Run the shared compiler and CLI natively, including library builds and compile-time evaluation.
- Install native platform packages and ship relocatable standalone distributions.
- Preserve program semantics and reuse validated build artifacts for fast rebuilds.
* fix: complete native CLI integration and validation
- Preserve library diagnostics and run recursive compiler work on the main stack.
- Restore packaged helper permissions and exercise native npm and Wasm library builds.
- Recover interrupted Sandbox status probes within the original command deadline.
- Remove C emission, debugging options, and automatic backend fallback.
- Complete LLVM lowering and native bootstrap coverage across supported targets.
- Link executables and libraries with precompiled C runtime packs, including iOS and Android.
- Emit source locations for native TypeScript and JavaScript debugging across C and LLVM backends.
- Preserve macOS debug symbols through linking and cache reuse, with regression coverage and Xcode guidance.
Fixes#461
Co-authored-by: timokosonen <325538238+timokosonen@users.noreply.github.com>
- Link smaller executables across native targets with an explicit --strip flag.
- Keep stripped and default builds separate in the cache and cover their behavior.
* fix(windows): support GUI executables
- Add Windows subsystem selection across executable link paths and cache keys.
- Verify PE subsystem output and add Windows CI coverage.
Fixes#259
Co-authored-by: Mateus Mamede Lage <23098414+mmamedel@users.noreply.github.com>
* fix(ci): restore cross-platform test parity
- Make the Windows subsystem test use a portable loader URL.
- Sync TS7 order-parity baselines with current corpus fixtures.
---------
Co-authored-by: Mateus Mamede Lage <23098414+mmamedel@users.noreply.github.com>
- Add an explicit executable dev posture using native -O0 builds
- Split large LLVM programs into parallel, independently cached objects
- Preserve release cache compatibility and safe single-TU fallbacks
* perf: lazy-load the compiler from the CLI
- Serve help and version from a lightweight bootstrap and route exact executable cache hits before loading the compiler graph.
- Validate routed hits against compiler, frontend, toolchain, and native dependency proofs with portable cache publication.
* fix: repair lazy executable cache routes