Commit Graph
6750 Commits
Author SHA1 Message Date
Malte UblandClaude Opus 5.5 b0bbae15ac Spread an empty-object default like its source
`...(x ?? {})` and `...(x || {})` spread exactly what `...x` spreads, but
the defaulted source lowered as a `??` expression into a checked-dynamic
value, which failed for records with function fields. When x is a record
or an optional record, the spread now lowers as a spread of x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:37:45 -07:00
Malte UblandClaude Opus 5.5 980a1af682 Build nested literals at the enclosing literal's own layout
An object literal whose context has no layout builds at its own type,
but its nested literals still chose their own contextual layout, so the
nested record could not convert into the field the outer literal had
built, and SC2002 named the source literal's type as the expected one.
A nested literal now builds at the layout the enclosing literal asked
for when its contextual layout cannot reach it, and the outer coercion
lifts the whole tree into the real destination.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:37:45 -07:00
Malte UblandClaude Opus 5.5 5a6f2c0902 Destructure options ?? {} over records with required members
`const { a, ...rest } = options ?? {}` destructures the options record or
an empty object. Where the record had a required member, the `{}`
fallback was coerced into the record and failed with SC2002. The source
now lowers to the union of the record and the empty record, so the
union pattern lowering reads each key from the arm that holds it, the
empty arm answers undefined and the rest element packs nothing. A
record arm without a literal key now answers undefined in unionKeyGet
too, which the frontend already asked for and the validator rejected
as an internal error. All-optional options keep their lowering.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:37:44 -07:00
Malte UblandClaude Opus 5.5 e86800de67 Spread unions with several record arms
An object spread of a union with several record arms was refused. Two
cases are now lowered. Where the checker narrowed the source to fewer
arms than its stored union holds (an optional-chain discriminant test
on an element read, a type predicate), the source converts through the
checked narrowing, so an excluded arm throws the catchable TypeError,
and the narrowed record spreads as before. A union spread into one
declared record copies each arm's own keys behind its tag test: a key
the running arm lacks keeps the earlier value or stays absent. One
record arm emits the same code as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:37:44 -07:00
Malte UblandClaude Opus 5.5 f76a8202dd Record order-parity baselines for the group C fixtures
Add the TS7 preflight/order baselines for the new diagnostics and corpus
fixtures so the completeness check and the parity batches cover them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:34:49 -07:00
Malte UblandClaude Opus 5.5 b1b7aff25c Renumber the new corpus programs to 8514 and 8515
Group C adds two corpus programs whose 8423 prefix another group also
proposes; main's highest corpus number is 8513, so take the next two free
numbers and move the matching per-program cost files with them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:34:49 -07:00
Malte UblandClaude Opus 5.5 48d524a321 Lower a JavaScript read of an undeclared name to Node's ReferenceError
D-2: Node resolves a name nothing declares at run time, and the read always
throws the catchable `ReferenceError: x is not defined` at the access. A
`.js` read of such a name now compiles to exactly that throw instead of
refusing the program, with Node's message and Node's catchability.

The read's value is checked-dynamic (the checker's error-any after the
relaxation in the previous commit, narrowed by the use site where one
provides context), and every path through it unwinds before a use observes
the value, so the dynamic slot never carries a wrong value. Shorthand
position (`{ x }`) needs its own declaration test: there the checker
answers the PROPERTY symbol, so the name is bound when
`getShorthandAssignmentValueSymbol` has no value for it.

`typeof` is the one operator that never touches its operand value, and Node
answers "undefined" for an undeclared name, so `lowerDynTypeofTest` folds
the test to a literal before the read is ever lowered — `typeof x ===
"undefined"` stays true and `typeof x` alone prints "undefined".

No name that Node serves from the global object reaches this branch: the
compiler models those as declared (that is how the corpus reads `process`,
`console` and friends), so this is the name Node itself would report
missing.

The corpus program pins every shape: bare read, call, member read,
arithmetic, comparison, shorthand, destructuring default, typeof test, a
guarded read that keeps running after the throw, and a declared control.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:34:48 -07:00
Malte UblandClaude Opus 5.5 ff93a5a4de Refuse sloppy implicit-global writes by name, and relax undeclared JS names
Node resolves a name nothing declares at run time. In sloppy mode a WRITE
creates a property on the process-wide global object, which a native binary
has no object for, so those programs belong on the Node island route (plan
D-2/D-5). Until that routing exists, an undeclared write in a `.js` source
is refused at build time under a dedicated code, SC1091, whose text names
the island route instead of failing with a generic no-lowering message.

Reaching that refusal at all means the checker has to stop treating an
undeclared name in a JavaScript source as a compile error, so 2304, its
did-you-mean spelling 2552, and shorthand position's 18004 join the JS
relaxation set. The relaxation stays `isJsSourceFileName`-gated: TypeScript
input keeps the compile error, where an undeclared name is a bug rather
than a runtime path.

The refusal is a preflight walk over every JavaScript file, so it reports
once per write, before any code is emitted, at the span the checker used.
`isJsWriteTarget7` is shared with the lowerer's unresolved-reference fence,
which supplies the same refusal for a write that reaches lowering by a path
preflight does not model. An empty identifier is skipped: it is a parse
recovery artifact, never a name a program writes.

The JS-read half of D-2 (the name lowers to Node's catchable
`ReferenceError`) is the next commit; this one only changes what the build
says about a write.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:34:47 -07:00
Malte UblandClaude Opus 5.5 b234e06f20 Enforce the ECMAScript early errors the checker does not model
Static semantics reject a program before it runs. Until now the compiler
borrowed that rejection from whatever tsc happened to report, and Test262's
negative-parse suites show where the borrowing stops: programs the spec
makes SyntaxErrors compile and run. This adds the two largest families the
grab-bag misses (plan §7.7 D-4, option c), each under its own preflight
code, so a checker relaxation can never remove the only rejection a
parse-negative program had:

  SC0005  a statement list declares one lexical name twice
          (`{ class f {} async function f() {} }`)
  SC0006  a lexical name is `var`-declared in the same statement list
          (`switch (1) { case 1: let x; case 2: var x; }`)
  SC0007  a declaration where the grammar admits only a Statement
          (`while (false) function f() {}`, `l: class c {}`,
          `if (x) async function f() {}`)

frontend/early-errors.ts is a preflight walk over JavaScript sources, so a
rejected program fails where a tsc parse error fails, before any lowering.
A case block is one lexical scope across its clauses; a list's
VarDeclaredNames reach into nested blocks but never into a function or a
class body; and Annex B's allowances are honored exactly: two plain
function declarations may repeat in a sloppy block (B.3.3.1), and a plain
function may be an if/else body or a labelled statement in sloppy code
(B.3.2) — an async function, a generator or a class never gets either
allowance, and neither does any function as a loop or 'with' body.

Strictness comes from Node's own module classification (isNodeEsmFile7),
not from the checker's external-module bit: moduleDetection=force gives
every file module scope, CommonJS included, and taking that bit as
strictness cost the Annex B exemption on the annexB
function-redeclaration tests. Typed sources are untouched — their checker
diagnostics (TS2451 and friends) remain the gate, and re-reporting a
collision under a second code would only duplicate them.

tests/test262/support.mjs counts one of these codes at a location inside
the test's own source as the parse-negative match, the same standard the
helper already applies to tsc's early errors. The diagnostics fixtures pin
both families, including the strict half of SC0007 where Node refuses the
two Annex B shapes as well.

The pass only reads the AST and only refuses programs, so no typed
program's IR changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:34:47 -07:00
Malte UblandClaude Opus 5.5 c6db09c8e4 Relax the async-iterator protocol demand in untyped JavaScript
TS2504 demands a `[Symbol.asyncIterator]()` method that returns an async
iterator. In untyped JavaScript, whether a value is async-iterable is a
runtime fact of the value rather than a static one, exactly like the sync
demand (2488) relaxed just above. `for await` over a non-async-iterable
and `yield*` in an async generator both lower through the runtime
protocol openers, which read the method, call it, and throw the same
TypeError Node throws when it is missing, uncallable, or returns a
non-object.

Only diagnostics change, so only variants that previously held a 2504
refusal can move: the relaxed set is consulted only when JavaScript
strictness is suppressed, and 2504 is the sole code this adds. The sync
sibling 2505 stays enforced on the typed lanes, and TypeScript sources
keep 2504 because the relaxation applies to `.js`/`.mjs`/`.cjs`/`.jsx`
only.

Corpus 8423-async-iterator-protocol-shapes.js pins the seven protocol
shapes Node rejects and the two it accepts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:34:46 -07:00
Malte UblandClaude Opus 5.5 a4c19ae4b4 Host the bare compareArray from the upstream assert.js harness
harness/assert.js defines `compareArray(a, b)` beside `assert`: a plain
function that RETURNS a boolean, whose throwing counterpart is
`assert.compareArray` (already hosted). The adapter now injects the bare
name into every prepared test and implements the upstream comparison:
read both `.length`s, so a nullish operand throws the same TypeError,
return false on a length mismatch, otherwise compare elements by
SameValue.

That also admits the compareArray.js include when the only use is a
direct call. A value reference or property read stays excluded, because
it would need the upstream function object and its `format` expando.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:34:44 -07:00
Chris Tate f96217e289 Count loop-body var initializers as writes, and skip overload signatures
- A `var` with an initializer inside a loop body of its own function runs
  once per iteration, so the binding counts as written, and generic
  instances share it instead of copying an earlier iteration's value.
- Only a function declaration with a body initializes its binding:
  overload signatures no longer make an overloaded function count as
  redeclared, so it is still a function that nothing reassigns (for
  example as a pipeline() function stage).

Adds the corpus program pipeline-overloaded-stage.ts, with its corpus cost
and order baseline, and a loop-body case to
generic-arrow-mutable-captures.ts.
2026-10-29 07:24:45 -05:00
Chris Tate 2473207af2 Name the emitter corpus programs instead of numbering them
Rename 8640-emitter-arguments-listeners.cjs and
8641-emitter-leak-warning-exit.cjs to emitter-arguments-listeners.cjs and
emitter-leak-warning-exit.cjs, with their cost files and ts7 baselines, as
AGENTS.md asks for new corpus programs.
2026-10-29 07:18:44 -05:00
Chris Tate b421cf6a38 Pass every argument to emitter listeners that read arguments, and deliver the leak warning at exit 2026-10-29 07:12:59 -05:00
Chris Tate d478dc9ec5 Send a zero from an inline RWF_NOWAIT read to the pool
Linux 5.9 and 5.10 answer 0 instead of EAGAIN for an RWF_NOWAIT read of
data that is not cached. The inline read took that 0 as end of file and
ended the ReadStream early. A zero from the inline read now goes to the
pool, whose read returns the data or confirms end of file; this costs one
pool round trip at the end of each file.

fs-stream-nowait.test.ts preloads a preadv2 shim that answers 0 for every
RWF_NOWAIT read and checks that a ReadStream still reads the whole file,
as Node does.
2026-10-29 07:05:55 -05:00
Chris Tate 4af5844f52 Prepare v0.4.6 release (#2539) 2026-10-29 06:57:21 -05: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 593673f87a Provide the libnode pack to the shape overlay npm lanes
The scheduled shape overlay lanes for npm and npm-static failed: on Linux
x64 CI the npm suites' Node island cases require SCRIPTC_LIBNODE
(tests/harness/libnode.ts), and this job did not run
.github/actions/libnode. The job now runs it for those two suites, as the
other Linux x64 and macOS test lanes do.
2026-10-29 06:38:22 -05:00
Chris Tate ea0cdd0418 Match macOS objects and paths in the native install, loop poll and profile tests
The nightly macOS lanes failed these tests on Linux-specific expectations:

- native-install: installNativeCli resolves the installation directory,
  and on macOS /tmp is a link to /private/tmp. The fixture root is now
  resolved too.
- counted-loop-emission: two tests counted polls of @scr_exc_flag, the
  thread's pending word that ELF executables read. Other targets poll the
  process-wide alert word. The tests now emit for x86_64 Linux, as the
  file's other ELF tests do.
- native-partitions: Mach-O objects define an ltmp<N> label at the start
  of each section, which the function lists now leave out.
- native-profile: profile temperature appears in ELF section names
  (.text.hot.); Mach-O sections carry no such prefix. The section name
  check, and the check that recovered block counts change the objects (they
  move f4 into the hot section), now run on ELF objects only.
2026-10-29 06:36:29 -05:00
Chris Tate 1acdda7328 Read and write cached regular files on the loop thread in fs streams
On Linux, an fs stream's read or write of a regular file first tries
preadv2/pwritev2 with RWF_NOWAIT on the loop thread. When the page cache
holds the data, the step completes there and its completion waits for the
next loop turn (scr_work_submit_done), as a pool job's completion does,
so timers and I/O still run between steps. EAGAIN, a kernel or file
system without RWF_NOWAIT, and other files take the pool as before.

- A read the cache holds only part of finishes on the pool, so each chunk
  is the one a single read() returns.
- A partial write completes with the bytes written; the stream submits
  the rest, as after any partial write.
- Writes stay on the pool when RLIMIT_FSIZE is finite, so SIGXFSZ cannot
  reach the loop thread.

scr_work_submit_done queues a completed job on a list the loop moves to
the done queue at its next sleep step, which is skipped while jobs wait.

Corpus 8530 covers a positioned read with a small highWaterMark, a write
stream with a start position into an existing file, and an append stream
over cached files, against Node.
2026-10-29 06:33:43 -05:00
Chris Tate 96739536d2 Read fs.read's position option once and check a bigint against length |= 0
fs.read's options forms read the position option a second time when it
was not a bigint, so a getter ran twice and a stateful one could move the
read. The option is now read once.

A bigint position was checked against the length before `length |= 0`.
A fractional or infinite length made the range check build its bound
from a null BigInt and crash. The check and the read now take the
converted length, so such a read completes with zero or the truncated
count of bytes, as in Node.
2026-10-29 06:22:18 -05:00
Chris Tate a2e1251759 Prepare v0.4.6 release 2026-10-29 06:02:00 -05:00
Chris Tate 7d1f9580ee Release path module members through the object core's accessors
The exit-time cleanup of the path module objects swapped each member
value out of the object's storage by reading v.obj.slots and
v.obj.entries directly. It now goes through scr_dyn_obj_count and a new
scr_dyn.h accessor, scr_dyn_obj_exchange_value_at, which stores a value at
an index without reading the keys, so the cleanup still runs after the
exit-time layout reset.
2026-10-29 04:55:52 -05:00
Chris Tate de5c5c2517 Follow renamed and default imports and exports in reuse's changed names
A changed name now also changes the names that hold it under another
name: a renamed or default import, a renamed or default export, an
`import x = A.b` and a renamed `require()` destructuring. A unit that
spells only the local name of such an import lowers again when the
imported declaration changes.

Regenerate codec.generated.ts for the bigintStats IR type, and round-trip
a BigIntStats program in the codec tests.
2026-10-29 04:54:25 -05:00
Chris Tate 64f9481fb8 Link the web stream classes for an element-access tee, pipeTo or pipeThrough
The scan that decides whether a program uses a web stream operation the
native streams lack only matched property accesses, so a TypeScript
program whose one such operation was `body["tee"]()` kept the native
streams and threw a TypeError at the call. Element accesses with a string
literal key now count the same way, in the TypeScript scan and in the
JavaScript one.

Adds the corpus program web-streams-typed-element-tee.ts, with its corpus
cost and order baseline.
2026-10-29 04:41:05 -05:00
Chris Tate 32745afc07 Bind generic arrow captures before parameter defaults, and count var redeclarations as writes
- A generic arrow instance binds its trailing capture locals before it
  lowers the declared parameters, so a parameter default that reads an
  immutable enclosing binding resolves it instead of failing with SC1090.
  The captures stay trailing parameters.
- A binding is written when one of its own declarations writes it: a
  `var` in a for-in or for-of head (every iteration), or a redeclaration
  that initializes (`var x = 1; ... var x = 2;`, a parameter or function
  declaration that a `var` redeclares). Such a binding is now shared with
  generic instances through the environment form, so a closure an
  instance returns reads the current value instead of a copy.
2026-10-29 04:30:06 -05:00
Chris Tate 60be717d92 Merge main 2026-10-29 04:24:50 -05:00
Chris Tate 442c06fde3 Throw Node's TypeError when a nullable destructuring source is null
In JavaScript files, a destructuring declaration whose source is one object or array type or null/undefined (`text.match(re)`, `items.find(...)`) threw a plain Error when the source was null or undefined. It now throws Node's TypeError with V8's message: "Cannot destructure property 'index' of 'text.match(...)' as it is null." for an object pattern, and "found is not iterable" or "object null is not iterable (cannot read property Symbol(Symbol.iterator))" for an array pattern. An object pattern whose source V8 spells in a form the compiler does not reproduce keeps the runtime fence.
2026-10-29 04:20:01 -05:00
Chris Tate c533750aa3 Test a jammed loop's exit every iteration when its counter may not advance
The jammed loop tests its exit only when `(j & 3) === 3`. When the inner
counter starts at NaN, an infinity, or a value that `j + 1` leaves unchanged,
`j & 3` never becomes 3, and the loop ran past the point where every
accumulator was full, without end when its bound never ends it.

The every-fourth test is now used only when the inner loop starts at an
int32 literal: the counter then takes consecutive integer values, so its low
bits reach 3 within four iterations. From any other start, the jammed loop
tests its exit every iteration.

The unit test checks which starts get each test, and the corpus program adds
loops starting at -Infinity and -(2 ** 54) that end once both pixels escape.
2026-10-29 04:17:06 -05:00
Chris Tate 2fee369fe9 Split the Linux LLVM artifacts job and take its glibc packages from native_linux 2026-10-29 04:14:27 -05:00
Chris Tate 7e898a39ba Record the ts7 order baseline of os-userinfo-passwd-entry.ts without diagnostics
The program has no preflight diagnostics; the recorded baseline listed an
SC0001 for NodeJS.ProcessEnv that the 5.9.3 preflight does not report.
2026-10-29 04:11:38 -05:00
Chris Tate eff8ef743d Read at the exact bigint position in fs.readSync
Co-authored-by: MathurAditya724 <57684218+MathurAditya724@users.noreply.github.com>
Fixes #2404
2026-10-29 04:11:04 -05:00
Chris TateandMathurAditya724 7f33f37384 Run for-in over a receiver that may be null or undefined
for-in over a value whose type adds null or undefined to one enumerable
type (a record, an index-signature record, an array) was refused with
SC1052. JavaScript runs such a loop zero times for null and undefined. The
loop now evaluates the receiver once, skips it when it is null or
undefined, and otherwise walks the value as its own type.

Fixes #2403

Co-authored-by: MathurAditya724 <57684218+MathurAditya724@users.noreply.github.com>
2026-10-29 03:58:21 -05:00
Chris Tate 82fbe022b4 Deliver the lines a chunk split after a line listener closes the interface 2026-10-29 03:51:59 -05:00
Chris Tate 6d170bf082 Check every path namespace key now that format and parse have function values 2026-10-29 03:36:13 -05:00
Chris Tate 5f7a9cc8c7 Merge main 2026-10-29 03:34:56 -05:00
Chris Tate a7b673e4ff Keep path module objects and bound path functions Node's values in untyped code
A path family read by untyped code is a plain object holding Node's
members in Node's order, built once per family and kept in the
builtin-module registry. Object.keys, Object.entries, Object.assign,
spreads, for-in and own-property checks over it see those members.
path.posix.posix and the cross-family members refer to the registered
objects; the registry releases their members at exit through the objects'
own storage.

Every builtin function value that becomes untyped boxes as its checked
twin, under the builtin's name and length, after lowering: a module
object's member, an assertion's argument, and a read of a binding whose
only stores are that builtin (a const local, or a module-level binding).
`ns.join === path.posix.join` holds for an untyped path namespace, and
`const join = path.join` passed to an untyped function compares equal to
path.join and validates its arguments with Node's errors.

The lowerer journals the checked-twin table (each builtin's data, display
name and location), so a unit replayed from the journal keeps its twins.
2026-10-29 03:32:36 -05:00
Chris Tate 37128308c3 Match Node's emitWarning, kill, chdir and userInfo behavior
process.emitWarning checks its arguments in Node's order: an options
object replaces type with `options.type || "Warning"` and code with
`options.code`, type and code are checked before the warning and for
Error warnings too, an empty type names the warning "Warning", and a
DeprecationWarning type returns at once under process.noDeprecation.
Wrong kinds throw ERR_INVALID_ARG_TYPE with Node's "Received ..." tail.
An instance of an Error subclass is an Error warning, and a typed record
in the options position is read as the options object. The default
report reads the warning's message, code and detail as property reads
do, so an Error subclass's own code is reported. A deprecation thrown
under process.throwDeprecation is thrown as the Error it encodes, so the
uncaught report names it.

process.kill throws ERR_UNKNOWN_SIGNAL for an unknown signal name, as
subprocess.kill does, and a failed kill(2) is Node's errnoException with
errno, code and syscall. A failed process.chdir names the working
directory as path and the target as dest.

os.userInfo() reads the passwd entry of the effective uid: uid and gid
are the entry's pw_uid and pw_gid (-1 on Windows), not the process ids.
os.homedir() answers $HOME whenever it is set, an empty value included.

The minimal test/common for Node's test/parallel files gains isAIX,
isIBMi and isSunOS.
2026-10-29 03:22:35 -05:00
Chris Tate 7921e020c2 Deliver a line to a single line listener without the listener snapshot 2026-10-29 03:13:45 -05:00
Chris Tate b319186a68 Count the arguments a replaced stdio write receives
A JavaScript function assigned to process.stdout.write or
process.stderr.write takes its parameters from the call, not from Node's
overloads, but the lowering returned before giving the function its
arguments slot. `arguments.length` then folded to the declared parameter
count (3 for `function (chunk, encoding, callback)` called with one
argument, 0 for a function without parameters), and reading
`arguments[i]` was refused at run time.

The replacement now receives the call's arguments, so `arguments` holds
what the caller passed, as in Node.
2026-10-29 03:01:39 -05:00
Chris Tate b7bcbc68d8 Pass a Buffer to a patched stdio write from an encoded data listener
A byte write to a replaced process.stdout.write or process.stderr.write
was boxed with the 'data' chunk helper, which answers a string while a
listener of a socket or HTTP response with setEncoding("utf8") runs. A
`process.stdout.write(buffer)` from such a listener reached the
replacement as a string. Node passes the Buffer it was given.

The stdio hook now boxes a byte write as a Buffer whatever listener is
running.
2026-10-29 02:58:50 -05:00
Chris Tate bfc32449bd Check section names only for ELF objects in the never-ran profile test
Mach-O and COFF objects keep every function in one text section, so the
test compares the objects built with and without the block counts on
every target and checks the hot and unlikely sections on ELF targets.
2026-10-29 02:49:31 -05:00
Chris Tate 398e2e9e9c Weigh program profile matches by the profile's counts
The LLVM helper's emit reports the sums of the profile's counters on the
functions it annotated and on the functions whose control flow changed since
the profile was collected (annotated_counts and mismatched_counts), and the
partition cache keeps them with each partition's match. The annotated ones
are listed as the profile annotation leaves them, before block counts
recover any. Builds of the native compiler print the share of the profile's
counts that changed functions hold.
2026-10-29 02:42:47 -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 ed46427ea7 Read /proc/self/maps once per glibc thread heap
A worker thread's large blocks come from glibc heaps, and the first large
block of each heap made the allocator check /proc/self/maps before
advising the heap huge pages. The check was skipped only for the heap the
thread advised last, so threads that switched between heaps read the maps
again at every switch: 9,000 to 11,000 reads in a type check of T3 web with
four checkers. A process-wide table now records every heap decided, and
each heap is read once.
2026-10-29 02:41:44 -05:00
Chris Tate ad9fa7f510 Compile the functions a sparse profile never ran as cold code
A profile merged with --sparse has no record of the functions its
training never ran, so a build with it optimized them as without a
profile, and on tsc-ts they are 72% of the program's IR. The block-count
file a recording build writes now also names those functions, with an
entry count of zero and no blocks. A --profile-use build that reads the
file gives such a function an entry count of 0 and the cold attribute,
as it does for a mismatched function the file records as never run, so
LLVM optimizes it for size and places it with the other unlikely code.
A function the file does not name, such as one added since the profile
was collected, keeps no counts.
2026-10-29 02:07:17 -05:00
Chris Tate 8537c41171 Keep the receiver bracket around stream completion calls
The stream completion closures carried SCR_CLOSURE_KIND_RECEIVER_FREE, so
compiled callers skipped the receiver bracket around cb(). A completion
runs user code synchronously (the write(chunk, callback) callback, the
next queued _write), and that code reads the ambient receiver, so the
flag is removed and the completions bind `this` as any unbound call
does. Corpus programs 8531 and 8532 call a saved completion from inside
another object's method, from JavaScript and from a TypeScript class
method that JavaScript calls, and check `this` in the callbacks it runs
against Node.
2026-10-29 02:05:14 -05:00
Chris Tate 02d7230c66 Link the scriptc CLI without huge text (#2524) 2026-10-29 01:47:52 -05:00
Chris Tate 089a8e1799 fs.watch/fs.watchFile: fix listener removal, adapter ownership and argument checks
- watcher.off/removeListener of a listener that is not the last one moves
  the later listeners down instead of up, so the removed closure leaves
  the list.
- The watchFile adapters for zero- and one-parameter listeners release
  the Stats their listener has no parameter for, and the fs.watch adapter
  releases the event string once a dynamic value holds it.
- A one-parameter fs.watch listener whose eventType is dynamic receives a
  boxed string through the emitted adapter.
- fs.watch, fs.watchFile and fs.unwatchFile throw ERR_INVALID_ARG_VALUE
  for a path holding a null byte, and a new watchFile poller throws
  ERR_OUT_OF_RANGE when interval is not a uint32, as Node does. Both
  watchFile libCalls check for the pending exception.
- fs.watchFile and fs.unwatchFile have surface-manifest entries, so a
  fence can deny them.
- The self-hosted feature records list watchFile, and the node-types
  fence fixture uses fs.openAsBlob in place of the now-lowered
  fs.watchFile.

Tests: tests/corpus/fs-watch-listener-shapes.ts (listener shapes, off of
a middle listener, null-byte path) with its order baseline and cost file,
the validation cases in fs-watch-file-polling.ts, and
tests/harness/fs-watch-leaks.test.ts, which runs both programs under
LeakSanitizer in the sanitized lane.
2026-10-29 01:47:31 -05:00
Chris Tate 2a39a97699 Test the direct index once in number-key lookups, and inline the probe in loops 2026-10-29 01:32:04 -05:00