Commit Graph
1681 Commits
Author SHA1 Message Date
Malte UblandClaude Opus 5.5 1b5c90549a Answer Error.prototype for Object.getPrototypeOf of an Error
An Error's view had no prototype or a holder of its default name and
message, so Object.getPrototypeOf(new Error()) was Object.prototype or a
fresh object. A view of an error built as an Error, whose prototype is
still the one its view starts with, now answers Error.prototype.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 17:47:47 -07:00
Chris Tate 9adb9692cd Accept file URL paths in existsSync and fs.promises (#2042) 2026-10-23 18:47:49 -05:00
Chris Tate b7f86b9bb5 Run TypedArray methods on typed arrays held as untyped values (#2043) 2026-10-23 18:14:18 -05:00
Chris Tate 5a4935ed9e Settle Promise.all over different entry types on Node's turns (#1843) 2026-10-23 17:49:52 -05:00
Chris Tate 537710f61d buffer: fromArrayBuffer ranges, the deprecated constructor, Buffer as a value (#1970) 2026-10-23 17:46:42 -05:00
Chris Tate b09d5c6862 Merge main 2026-10-23 17:43:25 -05:00
Chris Tate 47d573d216 Pass undefined as this to strict callbacks and read Symbol.iterator once 2026-10-23 17:41:37 -05:00
Chris Tate da6419b2a8 Bound each epoll timer's deadline by clock reads around its arm call (#2045) 2026-10-23 17:36:22 -05:00
Chris Tate 7f8b0c2a09 Support X25519 keys and crypto.diffieHellman (#2039) 2026-10-23 17:23:19 -05:00
Chris Tate 0687bc4c0e Bound each epoll timer's deadline by clock reads around its arm call
The epoll timer heap test recorded a key's deadline from a clock read taken
before scrp_timer_arm, but the poller reads the clock again inside the call.
A loaded runner that paused the test between the two reads for more than a
millisecond made the poller's deadline later than the recorded one, and the
test's deadline-order check failed although the heap delivered every timer
in order.

The test now records the clock before and after each arm call and checks
order against those bounds, which hold however long the test is paused and
need no slack. A mutated heap that skips sifting down still fails the check.
2026-10-23 17:06:16 -05:00
Chris Tate 37b409897c Merge main 2026-10-23 17:01:10 -05:00
Chris Tate 7230b14f9d Represent Dates as objects with identity (#1915) 2026-10-23 16:49:26 -05:00
Chris Tate 6b3297e3a6 Run TypedArray methods on typed arrays held as untyped values 2026-10-23 16:33:09 -05:00
Chris Tateandjlucaso1 0b83599af4 Accept file URL paths in existsSync, fs.promises and order-checked fs calls
existsSync and the fs.promises functions accept a file: URL wherever
they accept a path. They convert it after their arguments are evaluated,
and a URL that does not convert gives false from existsSync and a promise
rejected with fileURLToPath's error from fs.promises, as in Node.

copyFileSync and renameSync check a string source for null bytes before
they convert a URL destination, and readFileSync checks a runtime
encoding before it converts a URL path, so the error Node reports first
is the one thrown.

Refs #1616

Co-authored-by: jlucaso1 <55464917+jlucaso1@users.noreply.github.com>
2026-10-23 16:27:40 -05:00
Chris Tate fc229822e7 Support X25519 keys and crypto.diffieHellman
X25519 KeyObjects come from generateKeyPair(Sync)("x25519"), which keeps
the private key clamped as OpenSSL does, and from createPrivateKey and
createPublicKey of PKCS#8, SubjectPublicKeyInfo, JWK (OKP, X25519) and
raw keys. They export in the same forms. sign, verify, createSign and
createVerify throw OpenSSL's "operation not supported for this keytype",
with its library, reason and code properties. X25519 uses mbedTLS's
Curve25519 group.

crypto.diffieHellman({ privateKey, publicKey }[, callback]) computes the
X25519 and ECDH secrets of two keys of one type, given as KeyObjects or
in any form createPrivateKey and createPublicKey read. The checks run in
Node's order: the options, the callback, both keys present, the key types
when both are KeyObjects ("Incompatible key types for Diffie-Hellman"),
then the public and private key inputs. Mismatched curves, a small-order
X25519 point and key types other than EC and X25519 throw OpenSSL's
errors. The callback form passes the secret, or the error without the
OpenSSL properties, in a later macrotask, as Node's DHBitsJob does.

createPublicKey also reads a private key's DER encodings (pkcs8 and
sec1), which Node accepts there.
2026-10-23 15:56:08 -05:00
Chris Tate 9eb14207a6 Revert "Cache untyped property access in programs that declare classes (reland)"
This reverts #2017 (adb8690f1), which made main CI fail.
2026-10-23 15:53:36 -05:00
Chris Tate 4acf7f047d Keep the key order of records spread from values JavaScript built (#2024) 2026-10-23 15:52:49 -05:00
Chris Tate e7943984a5 Bind both Dates before comparing, and cache only new Date locals as time values 2026-10-23 15:50:09 -05:00
Chris Tate 24a89488f9 Give glibc's per-thread heaps huge pages (#2032) 2026-10-23 15:41:30 -05:00
Chris Tate 9a2d378fba Run completion callbacks in their call's AsyncLocalStorage context (#1804) 2026-10-23 15:29:35 -05:00
Chris Tate 59e5c0cf8a Merge main and keep declared keys in ordered spreads 2026-10-23 15:20:26 -05:00
Chris Tate 97b64fae1c Turn the thread-heap huge-page policy off under memory tagging 2026-10-23 15:13:36 -05:00
Chris Tate 850710fbea Box TextEncoder and TextDecoder records as checked-dynamic handles (#2022) 2026-10-23 15:03:43 -05:00
Chris Tate adb8690f11 Cache untyped property access in programs that declare classes (reland) (#2017) 2026-10-23 14:47:10 -05:00
Chris Tate 807d281baf Support raw key formats, X25519 keys and crypto.diffieHellman (#2029) 2026-10-23 14:40:52 -05:00
Chris Tate 46b00f69c9 Give glibc's per-thread heaps huge pages
Blocks above 512 bytes come from glibc, which serves each worker thread
from a 64 MiB heap of its own and makes it accessible with mprotect a
page-rounded step at a time. Every 2 MiB range of a heap is first touched
while part of it is still inaccessible, so the heaps never get transparent
huge pages: on a 16-checker type check of VS Code they hold about 0.9 GB on
small pages, close to half of the process's page faults.

Once a worker thread has allocated 16 MiB of large blocks, the heap of each
large block it gets is made accessible whole and advised MADV_HUGEPAGE,
once per heap. glibc's calloc still clears only what lies below its own
high-water mark, so no page is touched early. glibc's mmap and trim
thresholds are set to 4 MiB and 8 MiB, so that the largest blocks get
mappings of their own and a heap's free top goes back to the system: with
huge pages, a heap otherwise keeps resident memory it never writes. The brk
heap policy's own thresholds take precedence once it switches on.

The policy is off unless THP is in madvise mode and malloc is glibc's, and
when the glibc.malloc.hugetlb tunable is set or the system forbids
overcommit. A heap is advised only when /proc/self/maps shows anonymous
mappings covering exactly its range. Library archives leave their
embedder's heaps alone.
2026-10-23 14:30:29 -05:00
Chris Tate e7c2462e7a Rule out global constructor names by their first byte (#2028) 2026-10-23 14:27:01 -05:00
Chris Tate 3a5f563e70 Iterate untyped arrays without the generic iterator protocol (#2027) 2026-10-23 14:18:14 -05:00
Chris Tate 96a5954940 Merge main 2026-10-23 14:09:13 -05:00
Chris Tate 693e33742a Support the raw-public and raw-private key formats
EC and Ed25519 keys read and write Node 24's raw formats:

- generateKeyPair(Sync) encodings: raw-public gives the EC point,
  uncompressed or, with type "compressed", compressed, or the Ed25519
  public key; raw-private gives the EC scalar at the curve's size or the
  Ed25519 seed.
- KeyObject.export({ format: "raw-public" | "raw-private" | "raw-seed" }),
  with Node's check of the point type, and Node's error for a passphrase
  with any format other than PEM and DER, which now also covers JWK.
- createPublicKey and createPrivateKey of { key, format,
  asymmetricKeyType, namedCurve }, in Node's argument order, with
  compressed EC points, and createPublicKey of a raw private key.

As in Node, raw-seed and every raw format of an RSA, RSA-PSS, DSA or DH
key throw ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS, which generateKeyPair
passes to its callback. Invalid key data throws ERR_INVALID_ARG_VALUE.
Raw X25519, X448, Ed448 and post-quantum keys, EC scalars of 0 or at
least the curve order, and the EC point at infinity, which Node accepts,
throw a coded SC2020 error.
2026-10-23 13:59:28 -05:00
Chris Tate 08f282e1b6 Merge main and run finish, close and pipeline callbacks in their AsyncLocalStorage context 2026-10-23 13:57:55 -05:00
Chris Tate 47636f2fa5 Implement the identity TransformStream natively (#2009) 2026-10-23 13:51:52 -05:00
Malte UblandClaude Opus 5.5 c81ee69da7 Rule out global constructor names by their first byte
A global constructor read as a value in untyped code (zod's
`data instanceof Map`, `Set`, `Date` in getParsedType) resolves its name
at run time: Function, then the Error constructors, then the other
globals, each by strcmp. Every miss in the Error and global tables cost a
call, about a dozen per read.

Each table entry is now skipped unless its first byte matches the name's,
before the strcmp. The tables, their order and the values they return are
unchanged.

zod 3, z.array(Order).parse over 500 orders: 187.3M -> 183.2M
instructions per round (-2.2%).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 11:49:36 -07:00
Malte UblandClaude Opus 5.5 26d2c8bae1 Iterate untyped arrays without the generic iterator protocol
for...of, spread and destructuring over an untyped array opened the
iterator by calling the builtin values() function through scr_dyn_call
with the array as `this`, and stepped it through the general element
path: retain the source, compute the live length, read the element with
hole handling, release the source.

An array whose iterator method is the builtin values() now gets the
native iterator that call returns directly. A step over a plain array
whose index is an own element, or past the end, answers without the
general path; no getter can run there. Holes, keys(), entries(), typed
array capsules and every other source keep the general path.

zod 3, z.array(Order).parse over 500 orders: 187.3M -> 182.2M
instructions per round (-2.7%).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 11:33:28 -07:00
Chris Tate 285a92354e Wake TransformStream pulls waiting on a static fetch body 2026-10-23 13:21:29 -05:00
Chris Tate c7fd9dcdf0 Merge main 2026-10-23 12:59:08 -05:00
Chris Tate 934d254a41 Keep the inline-cache record list within the shape budget 2026-10-23 12:44:35 -05:00
Chris Tate 49e35b6755 Answer untyped property reads of plain values without the class tables (#2013) 2026-10-23 12:38:38 -05:00
Malte UblandClaude Opus 5.5 f14997776b Box TextEncoder and TextDecoder records as checked-dynamic handles
A codec stored in untyped storage (hono's StreamingApi keeps
`this.encoder = new TextEncoder()` in a JavaScript class field) had no
dynamic representation and threw SC1101 at run time. The codec records
now cross 'unknown' slots as handles of two new tags that hold the record
itself, so identity and a decoder's streaming state survive the round
trip, and checked casts unbox the same record.

The handles answer encode, encodeInto and decode (with options objects),
the encoding, fatal and ignoreBOM properties, method values with Node's
ERR_INVALID_THIS, instanceof, String() tags and JSON's {}. The unit
scr_text_codec_dyn.c links only into programs that convert a codec to or
from an untyped value (the textCodecDyn runtime feature, found with the
dgram carrier walk, now shared).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:33:06 -07:00
Chris Tate d891a245ab Clone Response and Request bodies by teeing their streams (#2008) 2026-10-23 12:16:46 -05:00
Malte UblandClaude Opus 5.5 7fb73b7d9d Keep the key order of records spread from values JavaScript built
A literal that starts with `...value` creates value's keys first, in
value's own order. When checked conversions build value's shape (records
JavaScript hands back through replaceable methods, field setters,
generator calls or callbacks), the key-order witness could not order the
literal statically and kept the declared table, so `{ ...draft, id }`
and `{ ...current, ...patch }` enumerated `id` first natively.

Every value of a record shape already enumerates either in its table or
in the order its record source holds: a checked conversion keeps the
source's order there whenever it differs from the table. Such a literal
(an ordered spread) now carries that order over: after it builds the
record, record.sourceSpread gives the record a source listing the keys
it declares in value's order, and the keys value lacks follow in the
table's order, which every literal sequence of the shape agrees with.
The literal then resolves as if value were in its table's order, and its
own shape counts as built at run time, since its values may carry a
source too. It qualifies only when every value of the source has all of
the source's keys, both shapes can keep a source, every later spread of
a shape whose values may carry a source only overwrites the source's
keys, and the source shape resolves (or is the literal's own shape).
Literals of shapes that do not resolve are left as they were.

Programs without such literals compile to identical IR.

Corpus 7750-key-order-javascript-spread-sources.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:15:58 -07:00
Chris Tate a36ef0b4ca Settle aborts and pull TransformStream uploads as Node does 2026-10-23 12:11:48 -05:00
Chris Tate 4dcb83c418 Free a typed teardown's blocks in the order it met them (#1849) 2026-10-23 12:09:37 -05:00
Malte Ubl 00fc647ca1 Merge remote-tracking branch 'origin/main' into perf/dyn-plain-property-reads 2026-10-23 10:05:34 -07:00
Chris Tate bd36b77a8f Cache untyped property access in programs that declare classes (reland) 2026-10-23 11:57:22 -05:00
Chris Tate fd592d61df Merge main 2026-10-23 11:56:40 -05:00
Chris Tate dc1d99835d Merge main 2026-10-23 11:54:20 -05:00
Malte UblandClaude Opus 5.5 a77fe8c21c Decide an untyped property write with one own-property lookup
scr_dyn_object_key_set, behind every untyped property write and every
member of an untyped object literal, looked the key up as many as five
times: a linear scan for an own accessor or read-only entry, a lookup
before the prototype walk, one before the non-extensible check, one to
know whether the key was created, and one more inside the store.

The own property is now looked up once. An own data property is written
in place (an own setter still runs; a read-only or getter-only property
still refuses), and an absent key walks the prototype chain as before
and is then added by scr_dyn_obj_set, which is unchanged.

zod 3, z.array(Order).parse over 500 orders: 199.8M -> 194.1M
instructions per round (-2.8%).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 09:24:47 -07:00
Chris Tate 6828c23b50 Error tee branches when the source errors with no read pending
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.
2026-10-23 11:20:05 -05:00
Chris Tate 2d4aac0976 Read Web Headers pairs without copying them, and cache their sorted list (#2000) 2026-10-23 10:50:13 -05:00