The tee learned a source error only through a pending read's error
steps, so a source that errored while both branches held buffered
chunks and no read was pending left the branches readable: the next read
returned a chunk where Node rejects. The tee now watches its source's
error, as the streams spec reacts to the source reader's closed promise,
and errors both branches in a microtask (resolving the cancel promise
unless both branches were canceled). A read's error steps only end the
read, and a clone of an already errored body errors both branches the
same way.
JSON.stringify walked a dense native array through its borrowed storage
and wrote record fields borrowed from the record. When an element's own
serialization can run user code (it reaches an array that may hold
foreign elements, whose getters and toJSON run, or a class instance or
checked-dynamic value), that code could grow the array, reallocating the
storage the walk still read, or replace the field it was writing.
In programs that store foreign elements, such arrays now take the
general walk, which reads each index afresh and holds its element, and
such record fields are held across their write. Programs without
foreign elements compile as before.
The differential and LLVM differential suites can run the same corpus
program's Node oracle at the same time in one shard. Programs whose
scratch directory or file was derived only from argv[1] collided, and
one oracle removed the paths under the other. Their names now include
the pid, as 1403 and 5567 already do. Printed output never carries the
name.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
'new TransformStream()' had no lowering, so hono's stream() and
streamSSE() helpers failed to compile their checked-dynamic paths. The
constructor without arguments now builds a native handle: its readable
side is a native ReadableStream with a zero high-water mark, and its
writable side runs the streams spec's WritableStream state machine
(getWriter, abort, close, locked; the writer's write, close, abort,
releaseLock, ready, closed and desiredSize). A write completes when the
readable side reads its chunk, close/abort/cancel propagate across the
pair, and deferred reactions take as many microtask turns as in Node.
Web ReadableStreams can also be weak collection keys (hono keys a
WeakMap by the response stream). A transformer, queuing strategies and
the WritableStream constructor keep the SC2020 refusal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Response.clone() and Request.clone() on checked-dynamic handles answered
'res.clone is not a function' (hono's etag middleware hashes
res.clone().body). The runtime now implements the streams spec's
ReadableStreamDefaultTee over native streams and clones the body with it,
so the original and the clone each read every chunk. A used or locked body
throws undici's TypeErrors, the clone's headers are a copy with the same
guard, and a cloned Request's signal follows the original's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Headers and Response constructors combine duplicate entries (a: x,
a: "") into one value with the separator, which can end in its space
("x, "). They marked the pairs canonical anyway, so a copy took them
unchanged where Node trims the copied value ("x,"). The constructors
now mark the pairs canonical only when every value is already trimmed;
otherwise copies normalize them pair by pair.
The differential and LLVM differential suites can run the same corpus
program at the same time in one shard. Their Node oracles had the same
argv[1] and so the same scratch directory, and one removed it under the
other. The directory name now includes the pid.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A present undefined that the fast copy stores leaves its slot out of the
hole-free prefix the entry test read. The matcher left out only the array
named by the store, so a store through another name for the same array,
such as `const b = a` followed by `(b as (number | undefined)[])[i] =
undefined`, kept `a` covered, and the fast copy read the slot as a number.
Such a store now leaves out every covered array it may reach: its own, and
every other array unless that array or the store's binding is a local
array no other binding holds. A store into a field reaches every array
except those local ones.
Every untyped property read or write in a program with dynamic-tier
classes calls a generated helper (%dyn.class.property.N). For a value that
is not a class instance, the helper still called the normalization, the
instance-bag and the static-bag tables, each of which returns the value
itself, then compared the bag with the value and finally read the key.
When every class branch of a helper tests a capsule key or a class key,
its fallthrough is still the access it was created with, and every table
that fallthrough calls has its kind exit, a value that is neither a class
capsule nor a function now gets the same access on itself at the top of
the helper. Helpers for `constructor` and `toString`, which answer
primitives and errors specially, keep their full body.
zod 3, z.array(Order).parse over 500 orders: 235.8M -> 199.8M
instructions per round (-15.3%).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A keyed read of a string-indexed record whose values are numbers or
booleans (`counts[key]` on a `Record<string, number>`, typed
`number | undefined`) allocated a heap union for every read, also when
the only consumer was `??`, `!` or a comparison with undefined. The
runtime already returns the entry's value and whether it is present;
the box came from wrapping that result.
Such a read is now a stack union source: under a projection, the read
writes the tag and bits of the declared field or index-signature entry
the key names, or the undefined arm for a missing key, into a private
stack box, and allocates nothing. This applies when every hit is a
number or boolean arm of the result union, or an inline field of the
same union, and also to an argument a callee only projects (the helper
that `x!` lowers to). Other consumers keep the heap union.
dictionary-walks allocates no union instead of 363,359 and runs 14.6%
faster; no other runtime benchmark's code changes.
Corpus 7390.
Appending an empty value to an existing header leaves the separator's
space at the end of the combined value ("x, "). Node keeps that in the
Headers object but trims it when the value is copied into another
Headers, Request or Response ("x,"). The copy fast path copied a
canonical object's pairs as they were, so the copy kept the space. Such
an append now marks the pairs as no longer canonical, and copies
normalize them pair by pair.
In JavaScript sources, Math, JSON or Reflect read as a value lowered to
an identity token, the string "[builtin Math]": typeof, String, `in`,
descriptors and member calls through an alias all had string semantics.
Each of these namespaces read as a value is now one object per program,
built on first use, with Node 24's own properties in Node's order:
function members are writable, configurable and non-enumerable with
Node's `length`, the Math constants are read-only, and
Symbol.toStringTag names the namespace. Members hold the same function
values the spelled member read gives; a member without one throws its
fence when called. Global reads, globalThis, destructuring and
shorthand properties all produce the same object, and an object with a
string Symbol.toStringTag coerces to "[object <tag>]".
Direct member calls keep their static lowerings, so replacing or
deleting a function member would not reach them: such changes throw
SC1090. New properties and attribute-only redefinitions behave as in
Node.
tsc-ts 0.0.9 answers getDiagnosticsOfCheckedFiles, which checks only the
listed files of a program and answers their semantic diagnostics and the
global diagnostics. The release-age exclusions admit it with its platform
packages.