Commit Graph
6750 Commits
Author SHA1 Message Date
Malte Ubl 69ecfbe1fa Allocate the Node island handle tag by name
#2277 numbers new handle tags from their names, so the islands' tag no
longer picks a value that another branch can take.
2026-10-26 16:00:46 -07:00
Malte Ubl 437ad4ae38 Merge remote-tracking branch 'origin/ni/i1-stack-bound' into HEAD 2026-10-26 16:00:05 -07:00
Malte Ubl 4063f1e1f7 Merge remote-tracking branch 'origin/ni/islands-base' into HEAD 2026-10-26 15:59:32 -07:00
Malte Ubl 7a2fe9e726 Merge remote-tracking branch 'origin/ni/13-libnode-packs' into HEAD 2026-10-26 15:58:56 -07:00
Chris Tate f003bb4d68 Guard <riscv_vector.h> by target in the implicit toolchain probe
The implicit toolchain probe includes every system header that the
runtime and vendored sources spell, under __has_include. clang ships
<riscv_vector.h> for every target, and through clang 18 including it
without the RISC-V vector extension is an #error. Since the vendored
zlib's adler32_simd.c spells it, the probe failed with clang 18, which
disabled the native cache and program sharding: a sanitized dev build
then compiled the whole program as one translation unit.

The probe now includes <riscv_vector.h> only where __riscv_vector is
defined, and the probe's header test covers it and a riscv64 target.
2026-10-26 17:58:37 -05:00
Malte Ubl d245796462 Merge remote-tracking branch 'origin/ni/3-hosted-loop' into HEAD 2026-10-26 15:58:16 -07:00
Malte Ubl e99d3445bf Merge remote-tracking branch 'origin/ni/1-libnode-loader' into HEAD 2026-10-26 15:57:24 -07:00
Malte Ubl 05584c5bf7 Merge remote-tracking branch 'origin/ni/1-libnode-loader' into HEAD 2026-10-26 15:55:46 -07:00
Chris Tate c75c95d864 Check the native stack guard in one function per call cycle
Every unbounded recursion repeats some cycle of the call graph, so a
stack check in one function of each cycle bounds it. stackCheckedFunctions
now picks a feedback vertex set of the stack-check graph greedily (the
function with the most caller-callee pairs first) instead of checking
every function on a cycle, and adds a check where a run of unchecked cycle
functions would exceed 32 calls, so the stack used between two checks
stays of the same order as before.

Worker entry polls follow: a synchronous function on a cycle that may
throw needs no entry poll, since a descent that never returns ends at a
checked function of its cycle. NoThrow contracts keep the model in which
every function on a cycle checks, a superset that does not depend on the
choice.
2026-10-26 17:47:58 -05:00
Chris Tate 580f405727 Inline small leaf functions called only from loops
A small helper called once per element, such as

    function pick(list: Gene[], rand: number): number {
      for (const gene of list) if (rand < gene.c) return gene.sc;
      return list[list.length - 1]!.sc;
    }

called from a loop over the elements, is often past LLVM's inline cost
threshold once its loop versions and checks are emitted (fasta's
randomCode costs 430 against a threshold of 225), so every element pays a
call, the spills around it, and checks the caller's loop cannot hoist.

findLoopCallees (loop-callees.ts) finds functions that are synchronous,
non-generator, capture nothing, call nothing (no call, callValue,
virtualCall, dynCall, dynInvoke, new, newValue, newPromise, ffiCall or
await), have at most 12 statements and one loop, and have one or two
direct call sites in the module, each inside a loop of its caller. The
emitter marks those calls `alwaysinline` (a call-site attribute, so the
function's definition is unchanged). Library modules and debug builds
keep LLVM's cost decision.
2026-10-26 17:33:58 -05:00
Chris Tate 7e225c5d87 Merge main 2026-10-26 17:33:06 -05:00
Chris Tate a82a0dda93 Revert "Build node:zlib on the zlib Node bundles"
This reverts #2355. The sanitized three.js nodes CI job has failed on every main commit since it landed.
2026-10-26 17:05:37 -05:00
Malte UblandClaude Opus 5.5 c2f9b49113 Write untyped stores into live records and pass prefix records by pointer
An untyped write of a present declared field of a live record capsule now
stores into the native record through a per-shape `set` hook (checked like
the commit, refusing to the snapshot path for values the field cannot hold),
so the capsule keeps answering from the record instead of turning into a
permanent snapshot. Object.assign from a plain object takes the same path,
and checked conversions and matches read a capsule through a fresh,
uncached snapshot.

A checked conversion of a record capsule into a record type whose storage
is a same-offset prefix of the capsule's record (and whose extra fields hold
no references) passes the pointer: both names keep one object, writes show
through either, and the record remembers its own capsule parameters, so
every later box of it and the narrower type's reflective surfaces answer
for the whole object (decision D3). Other cross-layout conversions keep the
refreshed copy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 15:05:27 -07:00
Chris Tate 3c83fcb89c Allocate object groups that die together in arenas (#2348) 2026-10-26 16:54:31 -05:00
Chris Tate 2d557bc87b Test a scalar optional left of ?? in JavaScript on the typed path (#2345) 2026-10-26 16:54:11 -05:00
Chris Tate b242a2d09a Address review feedback 2026-10-26 16:45:40 -05:00
Chris Tate 0dbf1e911f Call constant function tables and cross-module namespace members directly (#2220) 2026-10-26 16:26:47 -05:00
Chris Tate 6bdd3e39ca Fix the self-hosting build of the arena runtime 2026-10-26 16:20:12 -05:00
Chris Tate 1b2e591a02 Keep the typed ?? path to literal defaults 2026-10-26 16:18:58 -05:00
Chris Tate c5e8a876ec Store ordinary objects as a layout plus value slots (#2353) 2026-10-26 16:18:38 -05:00
Malte UblandClaude Opus 5.5 c89c4a0e85 Merge the deferral test lint fix
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:07:50 -07:00
Malte UblandClaude Opus 5.5 d3c01b8871 Merge the deferral test lint fix
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:07:50 -07:00
Malte UblandClaude Opus 5.5 b3decaa4cd Strip script(1)'s EOF echo without a control-character regex
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:07:49 -07:00
Chris Tate 45d81216c0 Name modules by the same relative path on Windows
stableFileName used node:path's relative(), which returns paths with `\`
separators on Windows. The module tags hash that name, so Windows builds
named the functions of every non-entry module differently from Linux
builds, and a profile or layout collected on Linux no longer matched them.
Structural positions used the same name.

portableRelativePath computes the relative path with the platform's rules
and writes it with `/` separators, as tsgoPath does for checker paths.
Linux and macOS names are unchanged.
2026-10-26 16:05:57 -05:00
Chris Tate 9f47d74e21 Poll the loops of a nest on every iteration in ELF worker executables (#2351) 2026-10-26 16:04:06 -05:00
Chris Tate 4dd32da391 Lower discarded logical expressions over void conditionals as branches (#2356) 2026-10-26 15:56:00 -05:00
Chris Tate bfd3cf2daf Build node:zlib on the zlib Node bundles (#2355) 2026-10-26 15:48:37 -05:00
Chris Tate 6d8f0558ff Read int32-slot arrays at their width in integer clones 2026-10-26 15:45:29 -05:00
Chris Tate 301de61915 Read int32-slot arrays at their width in integer clones (#2354) 2026-10-26 15:43:31 -05:00
Malte UblandClaude Opus 5.5 147fbe080c Merge the ASan fix for nested entries on macOS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:34:52 -07:00
Malte UblandClaude Opus 5.5 6e58411489 Merge the ASan fix for nested entries on macOS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:34:51 -07:00
Malte UblandClaude Opus 5.5 e0fc59b82f Merge the ASan fix for nested entries on macOS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:34:50 -07:00
Malte Ubl 1839e2bfee Merge the ASan fix for nested entries on macOS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

# Conflicts:
#	packages/runtime/src/scr_node_island.c
2026-10-26 13:34:42 -07:00
Malte UblandClaude Opus 5.5 9ec81cff44 Merge the ASan fix for nested entries on macOS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:34:32 -07:00
Malte UblandClaude Opus 5.5 c4b5008d09 Merge the ASan fix for nested entries on macOS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:34:31 -07:00
Malte UblandClaude Opus 5.5 7b83b38f92 Merge the ASan fix for nested entries on macOS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:34:31 -07:00
Malte UblandClaude Opus 5.5 1dc043f706 Merge the ASan fix for nested entries on macOS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:34:30 -07:00
Malte UblandClaude Opus 5.5 43a55b2b68 Merge the ASan fix for nested entries on macOS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:34:29 -07:00
Malte UblandClaude Opus 5.5 3ea7031ea1 Merge the ASan fix for nested entries on macOS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:34:29 -07:00
Malte UblandClaude Opus 5.5 6748313cba Unpoison a nested entry's ending frame for ASan on macOS
The nested trampoline never returns (setcontext back), so the redzones
around its locals stayed poisoned in the shadow of Node's stack, and
Node's own frames tripped over them later (stack-buffer-underflow in
__bzero, sanitized corpus 6822/6823/6831/6832/6894 on macOS). Linux's
ASan clears a context's stack in its swapcontext interceptor; macOS's has
none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:34:14 -07:00
Chris Tate 5ab76a4d54 Keep the native compiler's profile matching its functions 2026-10-26 15:31:14 -05:00
Chris TateandMathurAditya724 3417a5adc4 Lower a discarded logical over a void conditional as a branch
`skip || (flag ? warnA() : warnB())`, with void calls in both arms, as
React's development warnings write it, failed with SC9001 "ternary must
not be void": the statement lowered the logical as a value, and a
conditional of void calls has none. A logical whose result is discarded
now lowers as `if (!skip) ...` (or `if (skip) ...` for `&&`) when its
right operand needs no value: its type maps to void, or it is a logical
or comma expression whose last operand needs none. This holds in
statements and in a for loop's initializer and update, and for a
generic callback's conditional whose type parameter maps to void.

Closes #2322

Co-authored-by: MathurAditya724 <57684218+MathurAditya724@users.noreply.github.com>
2026-10-26 15:25:52 -05:00
Chris Tate 133551d76e Build node:zlib on the zlib Node bundles
The runtime vendored zlib 1.3.1 and archived it at -Os, and host C-lane
builds linked the system libz, so deflate, raw deflate and gzip output
differed from Node's at every level. The vendored copy is now Node
v24.22.0's deps/zlib (Chromium's zlib, 1.3.2.1-motley-285e94b), built at
-O3 with the units and defines Node's zlib.gyp selects per target: the
SSSE3 Adler-32 and SSE2 inflate and slide-hash code on x86-64, the NEON
and ARMv8 CRC-32 code on arm64, and the portable code on wasm32. The SIMD
units check the CPU at run time and give the same output, so compressed
bytes match Node's on every target.

zlibInputs (runtime-pack-common/scripts/zlib-inputs.mjs for the runtime
packs, vendor-inputs.ts for Zig cross builds and the sanitized runtime)
holds the per-target table, and a unit test keeps the two identical.
Every C-lane driver now links the vendored objects instead of -lz.
Chromium's BSD license ships beside zlib's in the runtime packs.

Corpus 8405 compares compressed bytes with Node across levels,
strategies, memLevel, windowBits, dictionaries and flushing streams;
8406 covers chunked inflation with small input pieces and output chunks.
2026-10-26 15:12:51 -05:00
Chris Tate eb2ebb619f Cheaper trial deletion in the cycle collector (#2352) 2026-10-26 15:08:20 -05:00
Chris Tate 1d72466f51 Read int32-slot arrays at their width in integer clones
An integer clone reads a number array's element as an 8-byte double. A
number array proven to hold only int32s keeps 4-byte int32 slots
(SCR_ELEM_I32), so the clone read such an array at the wrong width: it
returned wrong values, and near the array's end it read past the slots.

The clone now tests the array's element kind: int32 slots load as 4-byte
int32s, double slots load as doubles and keep the exact-int32 test, and
any other storage bails to the ordinary body.

New corpus program: integer-clone-int32-slots.ts.
2026-10-26 15:00:12 -05:00
Malte Ubl 4c68e95384 Merge remote-tracking branch 'origin/ni/1-libnode-loader' into mac/ni1 2026-10-26 12:50:45 -07:00
Malte UblandClaude Opus 5.5 5a673f3919 Merge the macOS island fixes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:50:44 -07:00
Malte UblandClaude Opus 5.5 d93f457042 Merge the macOS island fixes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:50:44 -07:00
Malte UblandClaude Opus 5.5 4c9cfc1cc4 Run the deferral test's terminal case under macOS's script(1)
BSD script takes the command after the transcript file, needs a stdin
that is not a socket, and echoes the EOF it forwards from /dev/null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:50:43 -07:00
Malte Ubl 93283b5964 Merge the macOS island fixes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

# Conflicts:
#	packages/runtime/src/scr_node_island.c
2026-10-26 12:50:43 -07:00