Commit Graph
35 Commits
Author SHA1 Message Date
Matteo Collina ace91de608 stream: use the ring buffer for WHATWG stream request queues
The [[queue]] backing the controllers became a ring buffer, but the
read and write request queues (readRequests, readIntoRequests,
writeRequests) were left as plain arrays consumed with
ArrayPrototypeShift, which is O(n) and, even for the single pending
request of the await-each regime, far slower than an indexed head
advance. Back them with the same Queue, materialized lazily from the
shared empty queue so acquiring a reader or constructing a writer
allocates no request storage until a read or write actually parks.

pipe-to: +4.7% to +9.4% (all 16 configs, ***)
readable-read type=byob: +2.3% (**)
parked read loop: +15%, write loop: +11% (local harness)

Follow-up to https://github.com/nodejs/node/pull/64312.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64431
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2026-07-13 20:07:12 +00:00
Yagiz Nizipli 1912893c29 stream: use ring buffer for WHATWG stream queues
The [[queue]] backing every default readable/writable controller was a
plain array of { value, size } wrappers consumed with
ArrayPrototypeShift, so each buffered chunk allocated a wrapper object
and each dequeue moved (or forced the engine to re-linearize) the
remaining elements; the byte controller queue paid the same shift cost
for its chunk descriptor records.

Replace the array with a power-of-two ring buffer. Default controller
queues store each entry as (value, size) in two consecutive slots, so
the per-chunk wrapper allocation disappears; the byte controller keeps
its descriptor records (they are mutated in place at the head) in
single slots. Controllers start from (and are reset to) a shared
immutable empty queue, so constructing a stream allocates no queue
storage until a chunk is actually buffered. Enqueues measured by the
internal default size algorithm (never observable by user code, always
returns 1, cannot throw) skip the algorithm call and its try/catch
entirely.

The layout mirrors what Bun/WebKit use for the same spec structure:
[[queue]] as a ring-buffer deque (WTF::Deque in Bun's
src/jsc/bindings/webcore/streams/StreamQueue.h), the pure-JS ring
buffer in Bun's src/js/internal/fifo.ts, and the trivial-size-algorithm
bypass in
src/jsc/bindings/webcore/streams/JSReadableStreamDefaultController.cpp.

benchmark/compare.js against the unmodified baseline (30-run capture
plus an independent 15-run repeat, Welch t-test, all p < 1e-5):
webstreams/pipe-to.js +12-17% across all sixteen high-water-mark
configurations, readable-read-buffered +20% (bufferSize=1) to +49%
(bufferSize=1000), readable-async-iterator +21%. No stable significant
regression across the rest of the webstreams suite: the creation.js and
readable-read.js deltas seen in the full-suite capture disappear in
isolated 60-run rechecks.

Refs: https://github.com/oven-sh/bun/blob/main/src/js/internal/fifo.ts
Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
Assisted-by: Grok (Grok Build)
PR-URL: https://github.com/nodejs/node/pull/64312
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-07-08 15:05:45 +00:00
Matteo Collina 309213f5d8 stream: speed up async iteration over WHATWG byte streams
for await / reader.read() loops over byte streams were ~4x slower than
over default streams. Three per-chunk costs, none required by the spec:

- ArrayBufferViewGetBuffer/ByteLength/ByteOffset went through
  ReflectGet(view.constructor.prototype, ...), a reflective get that is
  ~3.5x slower than the original prototype getters from primordials and
  spoofable through a user-defined .constructor to boot.

- The buffered fast paths in ReadableStreamDefaultReader.read() and the
  async iterator only covered default controllers, so byte streams with
  queued data still allocated a read request and PromiseWithResolvers
  per chunk. Byte-queue dequeue is fully synchronous (it is the
  queue-filled arm of the byte controller's pull steps), so both fast
  paths now resolve directly from the byte queue.

- readableByteStreamControllerEnqueue re-ran the reader brand check and
  re-loaded the read request list four times per chunk across
  HasDefaultReader / ProcessReadRequestsUsingQueue / GetNumReadRequests
  / FulfillReadRequest; it now does a single pass. The async iterator
  also reuses its read request object across reads (at most one is ever
  in flight).

benchmark/webstreams interleaved same-day A/B, --runs 10:
readable-async-iterator bytes +16.3% (***), readable-read byob +9.1%
(***), all other rows neutral. Profiler harness: parked byte iteration
+14%, buffered byte iteration +37%, buffered byte read loop +18%,
default-stream rows at parity. WPT streams/compression/encoding
subtests identical to baseline.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64291
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-07-07 09:38:24 +00:00
Matteo Collina cc05d1cf58 stream: cut per-chunk overhead in WHATWG streams
Consolidate the spec's per-chunk predicate chains (CanCloseOrEnqueue,
IsLocked, HasDefaultReader, GetNumReadRequests, GetDesiredSize and the
writable-side equivalents) into single passes over the controller and
stream state, mirror "close queued or in flight" as a boolean flag
maintained at the few close-request transition sites, and materialize
the TransformStream [[backpressureChangePromise]] record lazily on
first observation so backpressure flips nobody is waiting on allocate
nothing.

Assisted-by: Claude Code
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64252
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-07-04 05:54:40 +00:00
Matteo Collina fa2eaa54fb stream: reduce allocations on WHATWG streams hot paths
Pure-JavaScript optimizations to lib/internal/webstreams/* that reduce
per-chunk and per-construction allocations on hot paths without
observable behavior change.

Per-chunk: reuse promise-reaction closures per controller, add buffered
fast path for async iterator, specialize callback wrappers by arity,
and share immutable nil records for writable stream resets.

Per-construction: use queueMicrotask for non-object start results,
materialize reader/writer .closed and .ready records lazily, and remove
dead allocations.

Assisted-by: Claude Fable 5
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/63876
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2026-06-20 14:19:08 +00:00
Antoine du HamelandMatteo Collina 65ffd025a5 stream: only pass the expected number of parameters to callbacks
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
Co-authored-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/63909
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-06-16 09:35:29 +00:00
Antoine du Hamel 13c2374d0b stream: remove unnecessary check
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/63030
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
2026-05-16 19:27:02 +00:00
Antoine du Hamel 266cd6749d stream: remove duplicated utility
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/63031
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-05-04 16:07:26 +00:00
Antoine du Hamel 5e61a07d03 stream: simplify setPromiseHandled utility
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/63032
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-05-01 22:08:25 +00:00
Filip Skokan 978a8c405e lib: fix lint in internal/webstreams/util.js
PR-URL: https://github.com/nodejs/node/pull/62806
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
Reviewed-By: Richard Lau <richard.lau@ibm.com>
2026-04-18 20:03:12 +02:00
Antoine du Hamel 1266013d19 stream: simplify readableStreamFromIterable
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/62651
Reviewed-By: Aviv Keller <me@aviv.sh>
2026-04-18 14:27:54 +00:00
Antoine du Hamel 0fea43023a stream: simplify createPromiseCallback
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/62650
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-04-11 15:45:39 +00:00
Mattias Buelens f6f519c6b6 stream: commit pull-into descriptors after filling from queue
Fixes: https://github.com/nodejs/node/issues/56044
PR-URL: https://github.com/nodejs/node/pull/56072
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
2024-12-07 03:45:13 +00:00
Jason Zhang 87a79cd8a1 stream: treat null asyncIterator as undefined
According to the spec, getIterator should normalize incoming method to
undefined if it is either undefined or null. This PR enforces that spec
compliance with passed WPT.

PR-URL: https://github.com/nodejs/node/pull/55119
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
2024-09-27 14:34:11 +00:00
Yagiz Nizipli 9195210399 lib,src: use built-in array buffer detach, transfer
PR-URL: https://github.com/nodejs/node/pull/54837
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
2024-09-16 00:32:04 +00:00
jakecastelli 1fd170a7fc stream: throw TypeError when criteria fulfilled in getIterator
PR-URL: https://github.com/nodejs/node/pull/53825
Fixes: https://github.com/nodejs/node/issues/53819
Refs: https://github.com/nodejs/node/issues/53819
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>
2024-08-01 02:00:47 +00:00
Antoine du Hamel 231548b5cf lib: enforce ASCII order in error code imports
PR-URL: https://github.com/nodejs/node/pull/52625
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
2024-04-23 17:05:38 +00:00
Mattias Buelens 20c63134fc stream: fix code style
PR-URL: https://github.com/nodejs/node/pull/51168
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2023-12-26 13:43:36 +00:00
Debadree Chatterjee b361ad72ce stream: implement ReadableStream.from
Fixes: https://github.com/nodejs/node/issues/48389
PR-URL: https://github.com/nodejs/node/pull/48395
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
2023-07-18 09:50:22 +00:00
Antoine du Hamel d42628d05a stream: add trailing commas in webstream source files
PR-URL: https://github.com/nodejs/node/pull/46685
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Darshan Sen <raisinten@gmail.com>
2023-02-18 18:55:52 +01:00
Antoine du Hamel fe514bf960 lib: enforce use of trailing commas for functions
PR-URL: https://github.com/nodejs/node/pull/46629
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
2023-02-14 18:45:16 +01:00
Jordan Harband 757c104147 tools: add prefer-proto rule
fixup: add support for `Object.create(null)`

fixup: extend to any 1-argument Object.create call

fixup: add tests
PR-URL: https://github.com/nodejs/node/pull/46083
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2023-01-10 05:38:36 +00:00
Deokjin Kim 979ec87665 stream: refactor to use validateFunction
PR-URL: https://github.com/nodejs/node/pull/46007
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
2023-01-01 06:33:41 +00:00
Yagiz Nizipli 9a8d82b99f src: add internal isArrayBufferDetached
PR-URL: https://github.com/nodejs/node/pull/45568
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: LiviaMedeiros <livia@cirno.name>
2022-11-27 03:14:57 +00:00
Daeyeon Jeong be9cd3ecb0 src,lib: group properties used as constants from util binding
Properties used as constants in `util` internal binding are
scattered. This suggests using an object holding all of them
for better maintenance.

Signed-off-by: Daeyeon Jeong <daeyeon.dev@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/45539
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2022-11-24 02:09:29 +00:00
Yagiz Nizipli 4bcc3aab76 stream: use ArrayBufferPrototypeGetByteLength
PR-URL: https://github.com/nodejs/node/pull/45528
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
2022-11-21 22:45:16 +00:00
Daeyeon Jeong e06384cb48 stream: add ReadableByteStream.tee()
This supports teeing readable byte streams to meet
the latest web streams standards.

Signed-off-by: Daeyeon Jeong daeyeon.dev@gmail.com
PR-URL: https://github.com/nodejs/node/pull/44505
Refs: https://streams.spec.whatwg.org/#readable-stream-tee
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2022-09-08 22:06:06 +00:00
Daeyeon Jeong 937520a764 stream: fix isDetachedBuffer validations
Signed-off-by: Daeyeon Jeong daeyeon.dev@gmail.com
PR-URL: https://github.com/nodejs/node/pull/44114
Refs: https://github.com/nodejs/node/pull/43866
Reviewed-By: LiviaMedeiros <livia@cirno.name>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2022-08-18 08:24:34 +00:00
Daeyeon Jeong 0c27ca4bc9 stream: improve respondWithNewView()
This fixes validating an ArrayBufferView given to
ReadableStreamBYOBRequest.respondWithNewView() to improve the web
streams compatibility.

Signed-off-by: Daeyeon Jeong daeyeon.dev@gmail.com

PR-URL: https://github.com/nodejs/node/pull/43866
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
2022-07-24 17:56:48 +01:00
Antoine du Hamel bb30e2da7a lib: use null-prototype objects for property descriptors
PR-URL: https://github.com/nodejs/node/pull/43473
Reviewed-By: Darshan Sen <raisinten@gmail.com>
2022-06-27 16:29:10 +01:00
Mestery 998e5acc69 lib: move kEnumerableProperty to internal/util
PR-URL: https://github.com/nodejs/node/pull/41877
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2022-02-11 17:30:47 +00:00
James M Snell 6ad3872d5e stream: import internal/util/types instead
Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: https://github.com/nodejs/node/pull/39331
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
2021-07-15 13:43:26 -07:00
James M Snell 2cc13ad6a8 stream: fixup property definition to avoid prototype polution
Fixup the definitions of the properties to avoid the possibility
of prototype polution on the object definitions.

Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: https://github.com/nodejs/node/pull/39371
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2021-07-13 10:50:02 -07:00
Tobias Nießen 528639c5fe lib: rename TransferedReadableStream etc
PR-URL: https://github.com/nodejs/node/pull/39352
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
2021-07-13 08:09:31 +02:00
James M Snell fa0c6883a6 stream: implement WHATWG streams
Experimental implementation of the WHATWG streams standard.

Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: https://github.com/nodejs/node/pull/39062
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
2021-06-30 12:54:41 -07:00