Commit Graph
2765 Commits
Author SHA1 Message Date
Chris Tate 714dbfe2bb Merge main 2026-10-22 06:59:47 -05:00
Chris Tate 3fecf687f5 Throw Node's TypeError for member reads of holes in wide unions
A binding that may hold a value its declared type omits (a function
parameter fed array elements, which can be holes) and that the checker
narrowed to one record or class arm of a union with more than two arms
was read through a checked extraction of that arm. When the binding held
a hole, a member read or method call threw "undefined is not
representable in the target union ..." for a record arm and "Value is
not an instance of 'Shape'" for a class arm, where Node throws "Cannot
read properties of undefined (reading 'a')".

The read now tests for undefined first and throws Node's TypeError, as
the two-arm path already does.
2026-10-22 06:31:30 -05:00
Chris Tate 3edec984d5 Compile JSX with the classic runtime (#1786) 2026-10-22 06:29:40 -05:00
Chris Tate 8ff58d2810 Match Node for generic arrow bindings used before their declarations (#1773) 2026-10-22 06:19:57 -05:00
Chris Tate 0f6ea63f21 Give each evaluation of a forward-read generic binding its own function
A generic binding inside a function that a nested function read before
the declaration lowered stores its instance into a TDZ box when the
declaration runs. That value was the instance's closure, which the
backend interns for module functions, so every evaluation of the
declaration stored the same function object. JavaScript makes a new one
each time. The stored value is now a closure over a lifted forwarder that
calls the instance, so each evaluation allocates a new closure; the
forwarder is created once per instance. Async and rest-parameter
bindings read this way report SC1090.

Corpus 7180 checks the identities.
2026-10-22 06:17:05 -05:00
Chris Tate 655c36c880 Match Node's AsyncLocalStorage context in async prefixes and generator steps (#1774) 2026-10-22 06:09:13 -05:00
Chris Tate fb403d5755 Clear a store that an async prefix enters in a loop callback
When an event-loop callback calls an async function or steps a generator
that enters a store before its first await, the store becomes the
callback's at the end of the prefix. On the main slot it now ends with
that callback, as an enterWith there does: the copy schedules the tick
that clears the main slot, so the store does not reach later callbacks.
2026-10-22 06:06:45 -05:00
Chris Tate 7f19e582e3 Read error constructors as values and destructure workerData in JavaScript (reland) (#1803) 2026-10-22 06:05:36 -05:00
Chris Tate df6de14c94 Support new tls.TLSSocket and tls.connect({ socket }) (#1791) 2026-10-22 06:01:47 -05:00
Chris Tate 4e834f8eed Read error constructors as values and destructure workerData in JavaScript (reland) 2026-10-22 06:00:28 -05:00
Chris Tate 3cefd421a1 Fence requestCert beside a secureContext and free failed TLSSockets
new tls.TLSSocket(socket, { isServer: true, secureContext, requestCert:
true }) skipped the options walk that refuses requestCert, so the server
asked for no client certificate and accepted every client, even with
rejectUnauthorized: true. With a secureContext, Node still reads the
socket's own options, so a truthy requestCert, SNICallback and
ALPNCallback now throw the fence there too.

A TLS socket's transport kept its 'secure' and 'session' listeners until
the socket was freed. A handshake that fails never fires 'secure', so a
listener that captures the socket kept the socket and its TLS state alive
after it closed. The transport now drops those listeners when the socket
settles, and ignores listeners added after that.
2026-10-22 05:58:32 -05:00
Chris Tate daac2a4a15 Support objectMode streams with any value as a chunk (#1785) 2026-10-22 05:55:45 -05:00
Chris Tate 2e29fd6a8c Support asymmetric keys, signatures and Ed25519 in node:crypto and WebCrypto (#1771) 2026-10-22 05:54:11 -05:00
Chris Tate c14e2607c5 Address #1785 review: Buffer|string data adapter and objectMode chunk handling 2026-10-22 05:52:31 -05:00
Chris Tate c086610b94 Keep each build's translation unit private until the build ends (#1766) 2026-10-22 05:50:07 -05:00
Chris Tate 01a467060b Support WebCrypto wrapKey and unwrapKey
crypto.subtle.wrapKey exports a secret key (raw, raw-secret or jwk) and
encrypts it, and unwrapKey decrypts and imports one, as Node's
webcrypto.js does: the wrap algorithm normalizes through the wrapKey
registry (AES-KW) and then the encrypt registry (AES-GCM, AES-CBC and
AES-CTR with their dictionaries), the wrapping key's algorithm and
usages are checked, and a JWK payload is its JSON text, padded with
spaces to a multiple of 8 bytes for AES-KW. A wrapped JWK that is not
UTF-8 JSON with a kty member rejects with Node's DataError.

AES-KW is RFC 3394 key wrap over the vendored mbedTLS block cipher, in
scr_webcrypto_aes.c beside the other AES modes: wrapping takes a
multiple of 8 bytes and at least 16, unwrapping a multiple of 8 and at
least 24, and the integrity check value is compared in constant time.
The cipher's failures, and unwrapKey's import errors, reject on a later
loop turn as Node's job promises do.

This completes jose's symmetric key management: 7132 runs the real
jose 6.2.12 PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW,
A128KW and A256KW paths (EncryptJWT and jwtDecrypt) against Node.
getPublicKey replaces wrapKey as the refused method in the fenced
fixture and the JavaScript refusal test.
2026-10-22 05:48:30 -05:00
Chris Tate 6f11afa09e Size crypto error messages to their whole text
The key and signature errors formatted into fixed stack buffers and
passed snprintf's return value on as the message length. A message
longer than the buffer, such as "Invalid digest: " with a long algorithm
name from crypto.sign or crypto.verify, then copied bytes past the end of
the buffer into the error. The messages are now sized to their whole
text, so a long name appears in full, as in Node.

The received values in these messages also follow Node: strings as
util.inspect quotes them, cut at 128 characters, and large integers with
ERR_OUT_OF_RANGE's separators. A fractional, NaN or infinite
modulusLength reports "It must be an integer", as validateUint32 does.
2026-10-22 05:46:53 -05:00
Chris Tate 1917d1aa00 Test an array read's hole-free prefix before its capacity
The dense path of an element read that may be undefined (the
`%arr.idxOr` reads behind `a[i]` as `T | undefined`, the store
`a[x] = a[y]!`, and the element reads of the lowered array methods)
tested the index against the capacity, then against the hole-free prefix
(`filled`), and only above the prefix against the length and the slot's
state. `filled` is at most the length and the capacity (scr_array.h), so
an index below it needs no other test: the read now tests `filled` first
and takes the value path on that test alone. Above the prefix it tests
the capacity, the length and the state as before.

A double index first branches to the runtime lookup when it is not an
exact integer, then takes the same tests on its i64 value, which a 32-bit
target compares before truncating it.
2026-10-22 05:25:02 -05:00
Chris Tate 1360830149 Support new tls.TLSSocket and tls.connect({ socket }) 2026-10-22 04:52:44 -05:00
Chris Tate 883f22ddd6 Run two-counter for loops on integer counters
`for (let lo = a, hi = b; lo < hi; lo++, hi--)` kept both counters as
doubles: the counted-loop match takes a single counter, so every
`a[lo]`/`a[hi]` converted and tested its index. A loop whose two counters
close in on each other by positive literal steps, are not written by the
body and index something now stores both as i64: on every body entry both
lie between the first start and the second. A start without a proven
integer range is tested at run time on a versioned loop, as a counted
loop's is.
2026-10-22 04:50:13 -05:00
Chris Tate feec4bf4df Call typed-array callbacks directly and visit on an integer counter
The helpers of the typed-array callback methods (forEach, map, filter,
some, every, find, findIndex, findLast, findLastIndex, reduce,
reduceRight) called their callback through the closure's code pointer on
every element, and one helper served every call with the same signature,
so the callback was never inlined. A literal callback now gets a helper
of its own, as for the array methods, and the constant-callback census
accepts the typed-array helpers, so the helper calls that function
directly.

The visit is now a loop on its own counter, `for (let i = 0; i < a.length;
i++)` or down from the last index, instead of a loop on a counter
declared before it, so the counter is an integer and element reads need no
index test. reduce and reduceRight without an initial value read their
seed at the first visited index and start one past it.

Adds reduce, some and map callbacks to the typed-array-kernels workload.
2026-10-22 04:44:34 -05:00
Chris Tate b03e965bf9 Resolve 7058's promises with undefined so both checkers agree 2026-10-22 04:35:27 -05:00
Chris Tate cab2db4f96 Drop the Cipheriv stream fence from the node-types fixture 2026-10-22 04:27:50 -05:00
Chris Tate c47a0e90ae Compile JSX with the classic runtime
Fixes #889
Co-authored-by: papack <33105506+papack@users.noreply.github.com>
2026-10-22 04:27:35 -05:00
Chris Tate 67247dd26b Support objectMode streams with any value as a chunk
Readable, Writable, Duplex, Transform and PassThrough take the
objectMode option, and a Duplex, Transform or PassThrough the
readableObjectMode and writableObjectMode options, as true or false
literals in an options object literal or in an options value. An
object-mode side holds any value that converts to a checked-dynamic
value: push, unshift, write, end, pipe, pipeline, for await, 'data'
listeners, Readable.from and the transform callback carry values in
TypeScript and JavaScript, and constructor-function streams and options
held in variables do the same. The object-mode high-water mark counts
values and defaults to 16. A readable buffer that mixes strings, Buffers
and other values holds them all, and push(undefined) and other values on
a byte-mode stream report ERR_INVALID_ARG_TYPE through 'error', as in
Node.

In typed code a write or transform callback, or a _write or _transform
method, may declare its chunk with any such type, which converts when
the callback runs. Writes pass the encoding argument to _write and
_transform as Node does: undefined when absent, null when a callback
took its place, otherwise the value unchanged. A parameter declared
string | null | undefined receives that value and one declared string
receives "" for undefined and null. write(chunk, encoding) on a
byte-mode stream encodes a string chunk with any known encoding and
throws ERR_UNKNOWN_ENCODING for an unknown one. Readable.from takes
typed Maps and Sets of any such value, and arrays that mix strings and
Buffers.

for await over a readable-only stream that will emit 'close' now ends
after 'close', as Node's eos does. Buffered writes that complete inside
clearBuffer run their callbacks in order, and 'finish' waits for a
deferred afterWrite that carries a callback, as Node's pendingcb does,
unless a _final callback schedules it.

The 'data' listener adapters take three slots and write and transform
callbacks read their chunk and encoding through runtime accessors, so
RUNTIME_ABI_VERSION is now 26.
2026-10-22 04:21:55 -05:00
Chris Tate 6e25c5ddb7 Compile js-yaml and smol-toml statically and match Node (#1751) 2026-10-22 04:15:26 -05:00
Chris Tate d5489cabd7 Merge main 2026-10-22 04:10:59 -05:00
Chris Tate b99094543f Revert "Read error constructors as values and destructure workerData in JavaScript"
This reverts #1776, which made main CI fail.
2026-10-22 04:04:16 -05:00
Chris Tate ebbc6c1831 Fix recursive JSON unions and primitive constructors as array callbacks 2026-10-22 03:56:15 -05:00
Chris Tate a9e23d2a09 Store assignment expressions into module lets declared without an initializer (#1780) 2026-10-22 03:45:00 -05:00
Chris Tate 144bfb2724 Store assignment expressions into module lets declared without an initializer
A module `let` declared without an initializer whose type uses its null
pointer as the TDZ sentinel (a function, for example) is initialized when
its declaration runs, while its slot is still empty. markUninitializedWrites
marked the assignment statements that run after the declaration as
initializing, but not assignments in expression position. Those ran the
pointer check and threw "ReferenceError: Cannot access 'g' before
initialization" where Node stores the value, so the deferred-resolver
pattern `let resolve!: ...; new Promise((r) => (resolve = r))` failed, as
did `(h) => (g = h)` and `const r = (g = h)`.

An assignment expression to such a binding now becomes an initializing
`assign` whose value a temp holds and yields. Writes that can run before
the declaration keep the flag check, so they still throw Node's
ReferenceError.
2026-10-22 03:41:43 -05:00
Chris Tate 931f6d48b5 Evaluate the extends expression of classes defined inside functions
A class defined inside a function whose base resolves to a known class
lowered to its class value alone, so the `extends` expression never ran.
Node evaluates it each time the definition runs, so its calls and other
effects were missing (`class Local extends select(2) {}` never called
select). The class value now follows the heritage expression's
evaluation when that expression can have effects: a call, construction,
assignment, update, delete, await or yield outside nested functions.
Module-scope classes already evaluated it.
2026-10-22 03:35:33 -05:00
Chris Tate b5fb4115e1 Merge main 2026-10-22 03:33:29 -05:00
Chris Tate 8e3c115cec Serialize the self-hosted emitter's IR compactly in its test (#1778) 2026-10-22 03:32:27 -05:00
Chris Tate e37b94cc94 Serialize the self-hosted emitter's IR compactly in its test
The pretty-printed IR of the self-hosted LLVM emitter is close to the
JavaScript string length limit on CI checkouts, so any growth of the
emitter fails the test with "Invalid string length".
2026-10-22 03:29:38 -05:00
Chris Tate f3efa0b38b Read error constructors as values and destructure workerData in JavaScript (#1776) 2026-10-22 03:29:21 -05:00
Chris Tate 3a879f4f05 Read error constructors as values and destructure workerData in JavaScript 2026-10-22 03:24:50 -05:00
Chris Tate 7d20212dd4 Merge main 2026-10-22 03:24:23 -05:00
Chris Tate 7019893664 Compute index temps of a typed-array loop counter as integers (#1775) 2026-10-22 03:16:13 -05:00
Chris Tate fe02190d1d Compile JavaScript-path calls that Node runs (#1756) 2026-10-22 03:15:48 -05:00
Chris Tate 921f054891 Extend a generic factory's local class returned through a constructor type (#1761) 2026-10-22 03:15:25 -05:00
Chris Tate ec0574f44b Read the byte offset of every untyped ArrayBuffer Buffer.from in one place
All Buffer.from paths over an untyped ArrayBuffer or SharedArrayBuffer now
go through one function that takes the byte offset explicitly, as Node's
fromArrayBuffer does. The start-offset RangeError prints the offset as
JavaScript does (-1.5, -1e+21, -Infinity) and builds its message without a
fixed-size buffer, which a large negative offset overran.
2026-10-22 03:13:24 -05:00
Chris Tate 42dd9390c1 Compute index temps of a typed-array loop counter as integers
In `for (let i = 0; i < out.length; i++) { const j = i * 4; ... px[j + 1] }`
the fast copy of the typed-array loop version computed `j` as a double and
converted every index back. The version gives each affine index operand
its range under the guard's bound on the counter, but kept the range an
operand already had, and the counter of a loop to a length is only known
to be below 2^53, so `i * 4` stayed a double multiply. The version now
narrows the existing range to the guard's.

A constant number local whose initializer has an exact integer form now
keeps that integer in an i64 slot beside the double, and its reads carry
both, so `px[j + 1]` indexes with integer arithmetic. Only optimized
synchronous functions keep these integers, and every other declaration of
the local drops its integer, since one declaration is emitted once per
loop copy.
2026-10-22 03:10:30 -05:00
Chris Tate b2b216c3df Extend a generic factory's anonymous local class returned through a constructor type
A generic factory declared to return a constructor type now also extends
when it returns an anonymous class expression (`return class { ... } as
Struct<S>`) or a `const` bound to one (`const Hold = class { ... }; return
Hold`). The result's class value is the class expression's own
constructor type; before, it was read through the class's name, so an
anonymous class refused with SC1090 and SC2008.
2026-10-22 03:10:12 -05:00
Chris Tate 32da078c11 Match Node's AsyncLocalStorage context in async prefixes and generator steps 2026-10-22 03:00:21 -05:00
Chris Tate 70697b45c3 Give generic arrow bindings Node's behavior before their declarations run
Generic arrow and function-expression bindings compile to shared
instances, and their declarations emit no store. Code that can run before
the declaration then diverged from Node.

- Inside a function, a nested function lowered before the declaration
  reads the binding through a TDZ box that nothing initialized. That
  covers closures above the declaration and hoisted function
  declarations. Such a read threw a ReferenceError even after the
  declaration ran. The declaration now stores the instance its declared
  signature pins into that box.
- At module scope, calls and pinned value reads went straight to the
  instances even when a hoisted function or an earlier closure ran them
  before the declaration. A binding with such a use now has a flag that
  its declaration sets.
  - Uses that can run first check the flag.
  - A let or const throws Node's ReferenceError before the arguments
    run.
  - A var runs the arguments and then throws "is not a function".
- Uses that follow the declaration stay direct calls: later statements,
  closures created after it, its own initializer, and function
  declarations that only such code calls.

A var binding inside a function that is called from a place that can run
before its declaration would need a per-call flag shared with its
closures. That shape now fails with SC1090 instead of calling the
instance.
2026-10-22 02:56:39 -05:00
Chris Tate f00428ccb1 Keep pipe() answering its destination and evaluate pipeline() arguments in source order 2026-10-22 02:53:03 -05:00
Chris Tate 1773ffbef3 WebCrypto: the crypto global, node:crypto's webcrypto, and secret-key SubtleCrypto 2026-10-22 02:52:01 -05:00
Chris Tateandsaboursepideh 1a240fbf10 Support asymmetric keys, signatures and Ed25519 in node:crypto and WebCrypto
Co-authored-by: saboursepideh <25549001+saboursepideh@users.noreply.github.com>
2026-10-22 02:49:33 -05:00
Chris Tate d1ff061833 Revert "Run two-counter for loops on integer counters"
This reverts #1768 (8fec4484d), which made main CI fail.
2026-10-22 02:48:13 -05:00