Commit 724190cfdcc for nodejs

commit 724190cfdccd3a4d2e2dca5b0c5de188d04e39db
Author: James M Snell <jasnell@gmail.com>
Date:   Sun Oct 4 02:13:10 2026 +0000

    stream: avoid per-write allocations in stream/iter writers

    Every write() and writeSync() allocated a `{ __proto__: null, context }`
    options object for the WebIDL chunk conversion, and for a Uint8Array
    chunk a second, six-property one with [AllowShared] and
    [AllowResizable]. Both are created in V8 dictionary mode.

    Return Uint8Array chunks directly from the WriterChunk converter: with
    [AllowShared] and [AllowResizable], the Uint8Array conversion cannot
    reject a value isUint8Array() accepts and returns the same object. Use
    shared, frozen conversion contexts for chunks, chunk sequences and
    write options; the converters only read them to build error messages.

    Writing 1e6 16-byte Uint8Array chunks into a push() stream and reading
    them back is about 27% faster with writeSync() and with writevSync()
    (4 chunks per call). String chunks are unaffected. Behavior and error
    messages are unchanged.

    Assisted-by: OpenCode
    Signed-off-by: James M Snell <jasnell@gmail.com>
    PR-URL: https://github.com/nodejs/node/pull/66648
    Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
    Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>

diff --git a/lib/internal/streams/iter/utils.js b/lib/internal/streams/iter/utils.js
index 0c6e1daaa32..d50ec639ab7 100644
--- a/lib/internal/streams/iter/utils.js
+++ b/lib/internal/streams/iter/utils.js
@@ -412,6 +412,14 @@ function concatBytes(chunks) {
   return concatenated;
 }

+// Conversion contexts for the per-write paths. The converters only read
+// them (to build error messages), so they are shared rather than allocated
+// on every write.
+const kChunkContext = ObjectFreeze({ __proto__: null, context: 'chunk' });
+const kChunksContext = ObjectFreeze({ __proto__: null, context: 'chunks' });
+const kWriteOptionsContext =
+  ObjectFreeze({ __proto__: null, context: 'options' });
+
 /**
  * Convert an array of chunks (strings or Uint8Arrays) to a Uint8Array[].
  * Always returns a fresh copy of the array.
@@ -419,10 +427,7 @@ function concatBytes(chunks) {
  * @returns {Uint8Array[]}
  */
 function convertChunks(chunks) {
-  chunks = converters.WriterChunkSequence(chunks, {
-    __proto__: null,
-    context: 'chunks',
-  });
+  chunks = converters.WriterChunkSequence(chunks, kChunksContext);
   const len = chunks.length;
   const result = new Array(len);
   for (let i = 0; i < len; i++) {
@@ -437,17 +442,11 @@ function convertChunks(chunks) {
  * @returns {AbortSignal|undefined}
  */
 function getWriterSignal(options) {
-  return converters.WriteOptions(options, {
-    __proto__: null,
-    context: 'options',
-  }).signal;
+  return converters.WriteOptions(options, kWriteOptionsContext).signal;
 }

 function toWriterUint8Array(chunk) {
-  return toUint8Array(converters.WriterChunk(chunk, {
-    __proto__: null,
-    context: 'chunk',
-  }));
+  return toUint8Array(converters.WriterChunk(chunk, kChunkContext));
 }

 /**
diff --git a/lib/internal/streams/iter/webidl.js b/lib/internal/streams/iter/webidl.js
index ef61abb7794..6ee1afd622a 100644
--- a/lib/internal/streams/iter/webidl.js
+++ b/lib/internal/streams/iter/webidl.js
@@ -27,17 +27,6 @@ function enforceRangeUnsignedLongLong(value, options = { __proto__: null }) {
   });
 }

-function allowStreamBufferOptions(options) {
-  return {
-    __proto__: null,
-    prefix: options.prefix,
-    context: options.context,
-    code: options.code,
-    allowShared: true,
-    allowResizable: true,
-  };
-}
-
 converters.AbortSignal = baseConverters.AbortSignal;
 converters.BackpressurePolicy = createEnumConverter('BackpressurePolicy', [
   'strict',
@@ -48,10 +37,11 @@ converters.BackpressurePolicy = createEnumConverter('BackpressurePolicy', [
 converters.unsignedLongLong = unsignedLongLong;
 converters.enforceRangeUnsignedLongLong = enforceRangeUnsignedLongLong;
 converters.WriterChunk = (value, options = { __proto__: null }) => {
-  if (isUint8Array(value)) {
-    return baseConverters.Uint8Array(
-      value, allowStreamBufferOptions(options));
-  }
+  // The chunk is a Uint8Array with [AllowShared] and [AllowResizable]. The
+  // Uint8Array conversion cannot reject a value isUint8Array() accepts when
+  // both are allowed, and returns the same object, so skip it: writes are
+  // hot, and the conversion would need its own options object.
+  if (isUint8Array(value)) return value;
   return baseConverters.USVString(value, options);
 };
 converters.WriterChunkSequence = createSequenceConverter(