Commit Graph
348 Commits
Author SHA1 Message Date
Chris Tate 13c5fc6748 pi wave 5: node process APIs, stdlib singletons, misc lowering (#2548) 2026-10-30 01:00:51 -05:00
Chris Tate bcda45ab7f Merge main 2026-10-29 23:58:03 -05:00
Chris Tate 902e8b4396 Ship ICU data without the categories no Intl form reads
The runtime pack shipped ICU's full icudt78l.dat (33.1 MB), and every
Intl executable gets a copy beside it. scr_intl.c answers its Intl forms
with ICU's break iterators, number and date formatters, calendars and
locale IDs, which never read the charset converters or the collation,
language, region, time zone name, unit, spell-out and transliterator
trees: 21.5 MB of the file.

- The pack build writes icudt78l.dat without those items
  (ICU_DATA_DROPPED in icu-inputs.mjs). filterIcuData rewrites the data
  file's table of contents to the remaining items, and the result is
  checked against a pinned sha256 and size (11,653,984 B).
- tests/harness/icu-data-filter.test.ts runs every @requires-icu corpus
  program under 47 locales and 3 time zones with the pack's data, with
  the full data and in Node, and fails when the outputs differ, so an
  Intl form that reads a dropped category fails there.
- intl-word-segmenter-dictionaries.ts segments Chinese, Japanese, Thai,
  Lao, Khmer and Burmese text, which ICU breaks with the dictionaries in
  brkitr/.
2026-10-29 22:17:47 -05:00
Chris Tate 2a1f7ac212 Give class methods and function values jsval entries for untyped calls (#2543) 2026-10-29 21:17:19 -05:00
Chris Tate 919151d339 Lower partial record assertions to record views (#2555) 2026-10-29 20:56:21 -05:00
Chris Tate d4c6aee135 Merge main 2026-10-29 20:04:10 -05:00
Chris Tate 78dbd98b1a Merge main 2026-10-29 16:39:31 -05:00
Chris Tate 4e67c5ce2c Host stdio: typed process.stdout.write slot, write-callback errors, drain, run-time-typed chunks (#2546) 2026-10-29 15:59:21 -05:00
Chris Tate 3b1a2c41b6 Merge main 2026-10-29 15:55:05 -05:00
Chris Tate f1825611fb Collect garbage cycles across the scriptc and V8 heaps (NI-8) (#1908) 2026-10-29 15:33:24 -05:00
Chris Tate 87c8d14510 Test262: String/Number/Boolean wrapper objects in JavaScript sources (#2550) 2026-10-29 15:24:04 -05:00
Chris Tate 145f8fcd5e fs.watch names the changed entry; fs.watchFile polls in its own gated unit (#2507) 2026-10-29 15:13:12 -05:00
Chris Tate dfa940a82d Return freed memory sooner: chunked shared writes, a bounded string spare, idle trims (#2518) 2026-10-29 15:12:10 -05:00
Chris Tate 42f8f30af6 Merge main 2026-10-29 11:19:38 -05:00
Chris Tate 1941a3e353 Merge main 2026-10-29 09:27:38 -05:00
Chris Tate 68ec61fe22 Replay jsval entry thunks in chunked emission and rename the profile's ABI marker
Chunked emission replays every numbered helper a range creates on the
merging emitter. The jsval entry thunks (dyn.jsEntryThunk) were missing
from the replayed dyn helpers, so a range that boxed a closure with a
jsval body failed to merge.

The committed runtime profile named the runtime ABI marker
scr_runtime_abi_v47, which ABI 48 renames to scr_runtime_abi_v48. The
profile's record now carries the new name; its hash and counts are
unchanged.
2026-10-29 08:15:44 -05:00
Malte UblandClaude Opus 5.5 ad8f8daccd Keep scr_lib.c's default object byte-identical for the fs.watchFile poll
Adding scr_stats_of_path and scr_stats_zero to scr_lib.c moved every
program's executable: scr_lib.o is linked everywhere, so its new symbols
and strings shifted addresses even for programs that never watch a file.

The two entry points now live in an SCR_FS_WATCH_FILE build of scr_lib.c,
the matrix's variant for programs whose feature set has watchFile, and the
poll unit calls the renamed scr_stats_poll_path. Programs that do not poll
link the default object unchanged: compiled without the define, scr_lib.o
is byte-identical to the base (verified by comparing the two objects).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:42:49 -07:00
Malte UblandClaude Opus 5.5 ac414df975 Select the partial-view runtime build per program
A record view's slot lookup answers NULL for a field a partial view lacks
(record-views.ts), but only a program that asserts a record literal to a
wider type ever asks for such a slot. Testing for the sentinel inside the
default scr_record_view_slot put a branch on a hot accessor of every
program that links a view: the zero-cost gate found fifteen typed
programs whose executables changed with byte-identical IR and LLVM.

Build the unit twice instead, as the fs.watchFile work does for its unit.
The default object is again byte-for-byte the one it was, and the
SCR_RECORD_VIEW_PARTIAL build — the one whose slot answers NULL — is
selected by the program's link features. `recordViewPartial` joins the
runtime features, set by a `partialView` dynCheck and carried through the
link features, the executable options and the early (cache-key) features,
so a cached executable can never link the other build. The runtime pack
gains the eight builds that pair the flag with the unit's existing
dynTier, webStreams and nodeIsland combinations; every program without a
partial assertion keeps the default object.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:39:31 -07:00
Malte UblandClaude Opus 5.5 fd7be9993d Add the primitive wrapper unit and its gated runtime feature
scr_js_wrapper.c constructs `new String/Number/Boolean` wrappers and
ToObject of a primitive as ordinary dictionary-mode objects whose
prototype is the unit's String, Number or Boolean prototype, with the
[[PrimitiveValue]] slot on the object's source identity. The unit also
answers instanceof, Object.prototype.toString, the util.types brands,
the String method receiver, and the guard of the graph-walking consumers
that cannot read the slot yet. A new `primitiveWrapper` runtime feature
(any `wrapper.` libCall) links it, so a program that never creates a
wrapper links no byte of the unit and the zero-cost gate keeps fully
typed programs clean. The `wrapper.*` signatures, symbols and dispatch
case are registered here; no frontend emits them yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:38:47 -07:00
Malte UblandClaude Opus 5.5 9172fecf19 runtime: link the wave's new entries only into the programs that use them
Every new runtime entry this wave added landed in a unit that baseline
programs link (scr_lib.c's write/copyFile flags, scr_bytes.c's
string_decoder dyn forms, scr_events.c's prepend registries and
stdin.isRaw, scr_async_dyn.c's uncaught prepend, scr_net.c's server.off).
A changed unit changes its object's build-id and symbol metadata even when
every retained function is byte-identical, so 1517 corpus programs
reported a runtime change for code they never call.

Each new entry now lives where only a program that uses it can reach it:

- writeFile's `flag` option and the fs/promises twins move to
  scr_fs_flags.c (feature fsFlags); copyFile's mode form reuses
  scr_fs_cp.c's reflink walk, so it is that unit's SCR_FS_FLAGS build.
- string_decoder's checked-dynamic chunk forms move to
  scr_bytes_strdec_dyn.c (feature strdecDyn).
- the prepend registrations, stdin.isRaw and server.off are the
  SCR_PROCESS_EXTRAS builds of scr_events.c and scr_async_dyn.c and the
  SCR_NET_SERVER_OFF build of scr_net.c (feature processExtras).

The prepend entry points reuse the append registration and move the new
entry to the front, so no existing function changes and every default
object stays byte-identical. The Windows copyFile arm stays beside the
Win32 path helpers in scr_lib.c, inside its _WIN32 block.

The source build (the -O1 -fsanitize=address lane) compiles these units
from their sources rather than from the prebuilt pack, so RUNTIME_DEFINES
names the same three builds the pack matrix selects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:38:30 -07:00
Malte UblandClaude Opus 5.5 e386da4aa4 Gate the typed stdio write slot out of the default events object
The typed write slot, the drain probes and the run-time-typed chunk write all
live in scr_events.c, a unit every program links. Unconditionally they changed
the default object, so executables of programs that never touch the write slot
changed byte for byte (three corpus programs differed runtime-only). Typed
programs must stay byte-identical.

Keep the default object exactly as it was and put the new code behind
SCR_STDIO_WRITE_SLOT, the way SCR_STREAM_WRITE_ERRORS gates the stream unit:
the shared write body, the run-time-typed chunk entry point and Node's
anonymous write function exist only in that build, and scr_stdio_method keeps
its own body everywhere else.

The lowering sites that reach the slot (the write method as a value, its
replacement, a patched program's typed writes) now emit a distinct marker lib
call, process.stdioSlot, which is the same scr_process_stdio at run time. The
feature scan turns it, together with process.stdioWriteDyn, into the
stdioWriteSlot runtime feature, which selects the matching runtime pack variant
and defines SCR_STDIO_WRITE_SLOT for the executable. The pack matrix enumerates
the combinations with stdioExtended and nodeIsland explicitly, so each existing
variant keeps its defines and its object.

Both new lib fns join USES_TIMERS_LIB_FNS: the write callbacks they queue run
from a nextTick, and a program whose only stdio use is the write slot would
otherwise drop the callback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:37:58 -07:00
Malte UblandClaude Opus 5.5 cf369f70af Fix write callbacks that take the error argument (W3)
`writable.write(chunk, cb)` with `cb` passed as a function VALUE lost the
completion's error: `lowerWriteCb` checked only the callback's syntax and
lowered every other callback through `lowerExprExpecting(cbArg,
funcOf([], VOID))`, which adapts a one-parameter function down to zero
parameters. The native binary therefore printed `undefined` where Node
prints `null`, or the write's own error (`ERR_STREAM_WRITE_AFTER_END` /
`ERR_STREAM_DESTROYED` for late and destroyed writes).

Lower such callbacks through a new `writable.writeEcb` libCall
`(recv, mode, chunk, encoding, cb)`: a zero-parameter callback keeps the
existing synchronous path, and a callback that declares the error (a dyn
value, or `null | Error`) is wrapped by `scr_stream_ecb_wrap` with the
compiler-built adapter that delivers the error the write completion
carries. The stream unit publishes that error only in its
`SCR_STREAM_WRITE_ERRORS` build, selected by the new `streamWriteErrors`
runtime feature (rule: any `writable.writeEcb`). Every other build
compiles `SCR_WCB_CALL` to the same plain call, so their objects are
unchanged.

The destruction path also matched Node: `afterWrite` calls `cb(null)`
even for a stream destroyed after the write was queued (Node 24
`internal/streams/writable`), so the destroyed `SCR_ST_AFTER_WRITE` tick
passes NULL rather than the stream's stored error.

Corpus: `tests/corpus/writable-error-callbacks.ts` covers success, an
erroring write, a write after end, and a write on a destroyed stream.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:37:57 -07:00
Chris Tate bbec52d459 Give class methods and function values jsval entries for untyped calls 2026-10-29 06:54:29 -05:00
Chris Tate 60be717d92 Merge main 2026-10-29 04:24:50 -05:00
Chris Tate 5f7a9cc8c7 Merge main 2026-10-29 03:34:56 -05:00
Chris Tate 7329f07d36 Match V8's default locale and calendar in the ICU formatters, and build Intl programs without Zig from the runtime pack
- scr_intl.c resolves the default locale as V8 does: ICU's POSIX locale
  (LC_ALL=C, C.UTF-8, POSIX) becomes en-US, so numbers keep their grouping
  separators, and other defaults round-trip through their BCP 47 tag. The
  number formatter, the date pattern generator, the date formatter and the
  default word segmenter use that locale.
- The date formatter moves the Gregorian calendar's Julian cutover to the
  start of ECMAScript time, so dates before October 1582 print their
  proleptic Gregorian fields, as in Node.
- icu.numFormatDefault, icu.dateLocaleString and icu.dateLocaleTimeString
  are in the may-throw set: a missing ICU data file throws an Error into the
  surrounding catch.
- `x.toLocaleString(undefined)` reads the receiver before the argument runs.
- The linux-x64-gnu runtime pack ships the ICU headers scr_intl.c includes
  beside its ICU archive (manifest `headers`, verified like the other
  artifacts). The native compiler's sanitized build compiles scr_intl.c
  against them and refuses with SC3003 when they are missing or changed.
  The C-source path (sanitized builds) links the pack's ICU archive and
  uses those headers, instead of building ICU with Zig's C++ driver.
- The macOS pack omits scr_intl.c, scr_intl.h declares ScrDyn, and the
  library-mode teachings test uses a locale argument, which still refuses
  with SC2020.

Corpus programs pin the C and C.UTF-8 locales, pre-1582 dates and the
receiver order against Node. intl-missing-data.test.ts covers the throw.
sanitizer.test.ts covers the header lookup.
2026-10-29 02:42:35 -05:00
Chris Tate 511bf04cb9 Refresh the runtime profile
The string spare, the main thread's idle trim and the shared-bytes writes
changed runtime functions that hold enough of the committed profile's counts
to fail its staleness check (7.3% against a 5% limit). The profile is
collected again on this change with scripts/refresh-runtime-profile.mjs
(327 raw profiles), with the LLVM helper built from this tree's sources.
2026-10-29 00:57:09 -05:00
Chris Tate 3e7528ca86 pi wave 4: path values, union delete, NonNullable unions, BigInt stats, optional-param function values, live accessor literals, clearer stdlib-alias errors (#2497) 2026-10-28 22:33:16 -05:00
Chris Tate 2ae08e4002 Route more packages and values through Node islands (NI-4c–4g) (#1904) 2026-10-28 21:53:40 -05:00
Malte UblandClaude Opus 5.5 7176257136 fs.watchFile: poll a path from its own gated runtime unit
fs.watchFile(path[, options], listener) polls the resolved path every
`interval` milliseconds (5007 by default, `persistent` by default) and
calls its listener with (current, previous) Stats when a poll sees a
difference. The first poll only records the baseline, a path that cannot
be stat'd polls as all-zero Stats, and a stat failure that repeats for
the same errno is not re-reported. One poller per RESOLVED path is
shared by every listener on it, and fs.unwatchFile(path[, listener])
removes the last listener registered with that callback, or every
listener when called without one. The call is a statement, since Node's
StatWatcher has no lowering, and bigint: true is refused.

The implementation is scr_watch_file.c, a new gated runtime unit
switched by moduleUsesFsWatchFile, so programs that do not poll link
none of it. The feature travels the usual chain (runtime-features,
executable-features, the native link info, the executable cache keys,
the runtime-pack matrix) and the validator learns that
fs.unwatchFile's trailing listener slot may be omitted.

Evidence:
- tests/corpus/fs-watch-file-names.ts and fs-watch-file-polling.ts match
  Node on stdout, stderr and exit status in the plain and sanitized lanes
- 1564-fs-watch.ts, 1751-options-record-stance.ts and the `fs` corpus stay
  green; the new order baselines and corpus cost files are recorded

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 19:49:44 -07:00
Malte UblandClaude Opus 5.5 fc708251c3 Ship ICU in the linux-x64-gnu runtime pack with its data beside binaries
The pack builds the ICU archive with the same Zig C++ recipe, adds
scr_intl.c as an optional unit under the intl predicate, and publishes
the archive under the id "icu". Its data file (icudt78l.dat) is not a
link input: the pack lists it in a new manifest "data" array, and every
Intl build copies it next to the executable it links (verifyArtifact
checked, atomic copy, size-checked before reuse). A pack that omits
scr_intl.c refuses an Intl program with SC3002 instead of linking
undefined scr_intl_ references.

The pack fetches both ICU inputs from the pinned release assets: the
source tarball (verified, cached, unpacked by the system tar) for the
archive, and the data zip (sha256 and size pinned twice) for the data,
unpacked by a small stored/deflate reader. Nothing is embedded in a
binary. The runtime fingerprint keeps covering the vendored trees, the
pinned ICU version keys the archive path, and the pack matrix gains the
icu archive with the intl predicate.

The isolated native host (native/compiler.ts) links outside the in-process
linker and writes its executables synchronously, so it installs the same
data artifacts itself (installNativeRuntimeData); the stored pack
selection gains a schema version so a selection cached before the data
list existed is discarded rather than trusted. Nothing selects a data
artifact for a program without the intl feature.

The sanitized lane links the pack's ICU archive as shipped. ICU is C++
and compiles with Zig's C++ driver for the packs' glibc floor, so it cannot
ride the sanitizer lane's per-TU C rebuild, and instrumenting ~600 C++ TUs
would add a multi-minute build to the first Intl program in every sanitized
lane. scr_intl.c itself still compiles instrumented with every other runtime
unit, and AddressSanitizer's interceptors cover ICU's allocations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 19:49:09 -07:00
Malte UblandClaude Opus 5.5 bece2646e6 Pin ICU 78.3, the release Node 24.22.0 bundles
Node answers every locale-dependent Intl form from ICU, so a compiled
binary that must match it byte for byte has to run the same release over
the same data. vendor-inputs.ts pins ICU_VERSION = "78.3" beside the
other vendored versions and vendor-inputs.test.ts asserts it against
process.versions.icu, the oracle the differential corpus compares with.

ICU is not vendored. Its source tarball (icu4c-78.3-sources.tgz,
27,977,255 B) and its prebuilt data zip (icu4c-78.3-data-bin-l.zip,
12,836,659 B) come from unicode-org/icu's official release-78.3 assets,
each pinned by version and sha256 beside ICU_VERSION and mirrored in the
runtime packs' icu-inputs.mjs, with a unit test that keeps the two
identical. The tarball carries ICU's own sources.txt lists, which stay
the list of record: icuSourceList() reads them so the archive holds
exactly the units ICU's autoconf build compiles. ICU_CXX_TARGET names
the glibc floor the archive is built for.

The data (icudt78l.dat, 33,107,232 B) is shipped beside the executable,
never embedded: 970 source files and 33 MiB of compiled CLDR tables are
a download, not a reviewable tree in this repository.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 19:49:07 -07:00
Malte UblandClaude Opus 5.5 cf7814d19c Lower fs statSync/lstatSync/fstatSync with { bigint: true }
Node answers a BigIntStats when the stat call is passed `bigint: true`: the
same snapshot, read through a bigint member table. Every number member of
Stats reads as a bigint — the integers, the `*Ms` millisecond members (the
truncated nanosecond quotient, as the binding computes them) and the
BigIntStats-only `*Ns` nanosecond members (sec * 1e9 + nsec, exactly) —
while only the four time members stay Dates. scriptc refused the option
outright.

The representation is static, chosen by the option literal: the lowerer
validates `bigint` against the call's result type (so
`{ bigint: true, throwIfNoEntry: false }` still narrows
`BigIntStats | undefined`), refuses a runtime-valued option and an option
that disagrees with the destination, and keeps every other option key
fenced. fstatSync joins statSync/lstatSync on the same path, with the
descriptor evaluated before the options.

The IR gains a `bigintStats` handle kind beside `stats`: the same RC
family, the same non-traced leaf and non-dynamic handle treatment, so no
shape, tracing or dyn-check behavior moves for any program that never asks
for one. Its member table is a `bigstats.*` lib-call family whose Date
members reuse the existing stat reads.

The runtime support is its own unit, scr_stats_bigint.c: the snapshot
layout moved into scr_stats_private.h so the bigint getters can read the
same fields without scr_lib.c carrying their code. The unit is gated on the
existing `bigint` feature in both the runtime-pack matrix and the
compiler's from-source unit table (the sanitized lane links from that one),
and `-ffunction-sections` keeps a bigint program that never reads a member
from linking any of the getters. No typed program's IR or LLVM changes.

tests/corpus/7018-bigint-stats.ts pins the member table, the Date/bigint
split, ms/ns agreement, arithmetic on a member, lstat over a symlink,
fstatSync over a descriptor, the throwIfNoEntry union, and the plain Stats
answers of the un-optioned and `bigint: false` forms against Node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 17:58:01 -07:00
Chris Tate 7a7fd8ce1d Match Node's node:path behavior from Node 24's path tests
path.posix, path.win32 and the bare path module are one module object
each, the handle process.getBuiltinModule answers, so require('path/posix'),
path.posix and the target platform's bare path compare as Node's do, a
namespace beside other values in one slot is untyped, and path[family]
reads that object. Functions read through them take checked arguments:
each string parameter passes Node's validateString under its own name
(basename's suffix first), resolve validates paths[i] only as far as its
last-first walk reads them, parse answers an untyped { root, dir, base,
ext, name }, format follows _format over any object, and
toNamespacedPath answers a non-string as it is. A JavaScript call whose
arguments are not strings, or omit one, goes through the same checks.
Typed slots keep the typed function values.

path.win32.relative lowercases both resolved paths with
String.prototype.toLowerCase and walks them by UTF-16 unit, comparing
segments instead when lowercasing changed a length, as Node does. It
folded ASCII only, so a path with İ or Ⱥ in a different case gave a
longer relative path. The function moves into its own runtime unit,
scr_path_win32_relative.c, which links with the regex unit whose case
mapping it uses. scr_path.c stays free of it, so library and
cross-target builds that link the path functions without the regex unit
still link.

A JavaScript binding whose inferred type holds a union of functions and
arrays (a test table of [fn, cases] rows, or one destructured row) takes
the checked-dynamic kind that dynFallbackType gives the unmappable
spellings of such tables. Its rows keep their functions' names, and
for-of, forEach and destructuring read the items as untyped values.
TypeScript bindings keep their typed layout.
2026-10-28 19:45:36 -05:00
Chris Tate 61c24c08e9 Refresh the runtime profile and convert ASCII case eight bytes at a time
scr_str_case_conv scans ASCII text for the first letter to convert eight
bytes at a time, then converts the rest eight bytes at a time; the tail
and big-endian targets take the byte loop. With a refreshed profile, the
byte-at-a-time scan compiled worse for short strings with nothing to
convert, which made validate-errors slower.

The runtime profile is collected again on this change with
scripts/refresh-runtime-profile.mjs (326 raw profiles). Changed
functions hold 0.0% of its counts, against 3.7% for the previous one.

tests/corpus/string-case-ascii-words.ts covers ASCII strings of every
length from 0 to 40, with letters at block boundaries and next to the
bytes just outside A-Z and a-z.
2026-10-28 18:43:37 -05:00
Malte UblandClaude Opus 5.5 f88019a8d1 Merge remote-tracking branch 'origin/ni/i10-js-island-requires' into ni/i11-cross-heap-gc
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 11:58:05 -07:00
Malte UblandClaude Opus 5.5 d4445ec628 Merge remote-tracking branch 'origin/ni/i6-subclasses' into ni/i7-routing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 11:57:10 -07:00
Malte UblandClaude Opus 5.5 753532a3da Merge origin/main into fix/pi-wp2-stdlib-node
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 11:33:39 -07:00
Malte UblandClaude Opus 5.5 10f974aab9 Merge ni/i6-subclasses into ni/i7-routing
Resolve tests/harness/npm.test.ts by keeping main's npm-suite split and
porting this branch's island KNOWN entry and stderr frame normalisation
into tests/harness/npm-suite.ts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 08:59:57 -07:00
Malte Ubl d1566d2746 Merge branch 'ni/i10-js-island-requires' into ni/i11-cross-heap-gc 2026-10-28 08:48:18 -07:00
Malte UblandClaude Opus 5.5 0fb9e25464 Merge ni/i6-subclasses into ni/i7-routing
Resolve tests/harness/npm.test.ts by keeping main's npm-suite split and
porting this branch's island KNOWN entry and stderr frame normalisation
into tests/harness/npm-suite.ts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 08:47:41 -07:00
Malte Ubl e5f57e2093 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-28 08:43:13 -07:00
Malte Ubl 29a31446d3 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-28 08:43:06 -07:00
Malte UblandClaude Opus 5.5 08ec7fd291 Merge ni/i10-js-island-requires into ni/i11-cross-heap-gc
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 05:43:05 -07:00
Malte UblandClaude Opus 5.5 9edf1d3aa3 Merge ni/i6-subclasses into ni/i7-routing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 05:42:18 -07:00
Malte UblandClaude Opus 5.5 39326c55be runtime: ship child.off/signalCode in a gated unit
Adding the six new entry points (scr_child_off_spawn/_exit/_close/_error,
scr_child_has_signal_code, scr_child_signal_code) to scr_child.c changed
the executable of every program that links the unit, although none of
them calls the new functions and IR and LLVM stayed identical: the extra
functions grow the unit's `.eh_frame` contribution, and the linker's
frame bookkeeping for the retained sections changes with it (the first
visible difference is the phdr sizes at byte offset 208). Appending them
after the unit's own functions does not help — the unit's frame section
still differs, so all 89 corpus programs that link scr_child.o got a
different binary.

Move the entries into scr_child_lifecycle.c, a unit of their own
selected only by programs that use them (feature childLifecycle, the
scr_dyn_handle_props.c pattern: the matrix's optional source list, the
RUNTIME_FEATURE_RULES rule for child.offSpawn/offExit/offClose/offError/
signalCode, and the link-feature plumbing through the executable cache,
CcOptions and RUNTIME_UNITS). scr_child.c keeps its original content and
layout; the new unit reads its registries through scr_child_private.h,
which holds the per-platform ScrChild layout both units compile against.

A program that does not call the new entries links exactly the units it
did before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 05:38:17 -07:00
Malte UblandClaude Opus 5.5 efc22a2fd3 Box user module namespaces as dynamic values
A `file:` module namespace handed to typed code now boxes as Node's
namespace object instead of the "converting typed values to 'unknown'"
fence: `const u: unknown = ns`, `take(ns)`, a `Promise<typeof
import("./m")>` widened to `Promise<unknown>` (or `Promise<unknown> |
undefined`), and `await import("./m")` in an `unknown` slot all see one
non-extensible null-prototype object per module whose own properties are
the module's exports in Node's sorted order. They are enumerable
read-only accessors whose reads call the compiled namespace getter, so
they stay live, and the object carries Symbol.toStringTag "Module",
Node's strict-mode write TypeErrors, the not-extensible add error and
the ToPrimitive throw. `node:` builtins have no compiled export table
and keep their SC1101 fence.

The object is built by a new gated runtime unit,
packages/runtime/src/scr_module_namespace_dyn.c, selected by the
`moduleNamespaceDyn` runtime feature (`module.namespaceDyn` in the IR).
It adds no field to ScrDynHandleOps and no branch to a shared unit: the
core reaches it through the ordinary SCR_DYN_OBJ paths, so key listing,
for-in, `in`, JSON, identity, property reads and assignment all reuse
the existing dispatch. The compiler reuses the getter lifted for
module.namespaceValue (existing programs' IR is unchanged) and adds
moduleNamespacePromiseDynValue, one lifted async mapper per module for
the promise slots.

Zero cost: a program that never boxes a namespace links exactly what it
did. The zero-cost gate reports every program identical, with
byte-identical IR and LLVM; the runtime pack's only difference is the
new unit (0 changed runtime functions), and among the namespace corpus
programs only 8412 links it.

Evidence: tests/corpus/8412-module-namespace-untyped is a differential
program against Node in both the plain and sanitized lanes, and the
diagnostics snapshots and TypeScript 7 baselines stay unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 05:37:45 -07:00
Chris Tate c9c8224aa2 Merge main 2026-10-28 02:45:59 -05:00
Chris Tate e8fdfa6a72 Pass native closures, promises and objects into Node islands by reference (NI-5) (#1900) 2026-10-28 02:40:19 -05:00
Chris Tate d47df7c9c6 Weigh the runtime profile's staleness by its counts
The runtime-unit helper now lists the functions the profile annotated and
the ones whose control flow changed since it was collected, each with the
sum of its counters in the profile. The Linux x64 pack manifest records the
counts on matched and on changed functions (flavors.speed.runtime_profile
annotated_counts and mismatched_counts) and names the changed functions
with the most counts. A function that one unit variant matches counts as
matched in the other variant too.

The runtime profile test fails when changed functions hold more than 5% of
the counts. RELEASING.md adds refreshing the runtime profile to the release
steps.
2026-10-27 23:20:02 -05:00