Commit e6c9c8eecdb for nodejs

commit e6c9c8eecdb49cfa4994f9fcc9bb5a7ff3f8d2ea
Author: James M Snell <jasnell@gmail.com>
Date:   Sun Oct 4 02:21:50 2026 +0000

    stream: construct stream/iter byte view snapshots and batch entries

    createBatchEntry() and recordChunk() snapshot every chunk in a
    seven-property `{ __proto__: null, ... }` literal, and every batch gets
    a `{ __proto__: null, views, byteLength }` record. V8 creates such
    literals in dictionary mode, which is expensive for objects created
    for every chunk.

    Create them with constructors whose prototype is an empty, frozen,
    null-prototype object instead, as for IterResult. They have fast
    properties and a single shape, and are only used internally.

    Writing 1e6 16-byte chunks into a push() stream and reading them back
    is about 6x faster with writeSync(), 3.7x faster with writevSync() (4
    chunks per call) and 1.7x faster with string chunks.
    benchmark/streams/iter-throughput-share-sync.js improves by 67-93%,
    iter-throughput-share.js by 4-8%, and iter-throughput-broadcast.js
    with 4 consumers by 8%. pipeTo() with small chunks is about 1.5x
    faster.

    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 d50ec639ab7..915e5340ceb 100644
--- a/lib/internal/streams/iter/utils.js
+++ b/lib/internal/streams/iter/utils.js
@@ -217,23 +217,35 @@ function toUint8Array(chunk) {
   return chunk;
 }

+// Byte view snapshots and batch entries are created for every chunk and
+// every batch, so like IterResult they are constructed rather than created
+// as `{ __proto__: null, ... }` literals (which are dictionary-mode objects),
+// and their prototype is an empty null-prototype object.
+function ByteViewSnapshot(value, buffer, sharedBufferView) {
+  this.value = value;
+  this.buffer = buffer;
+  this.bufferByteLength = sharedBufferView === undefined ?
+    ArrayBufferPrototypeGetByteLength(buffer) :
+    TypedArrayPrototypeGetByteLength(sharedBufferView);
+  this.byteLength = TypedArrayPrototypeGetByteLength(value);
+  this.byteOffset = TypedArrayPrototypeGetByteOffset(value);
+  this.detached = sharedBufferView === undefined &&
+    ArrayBufferPrototypeGetDetached(buffer);
+  this.sharedBufferView = sharedBufferView;
+}
+ByteViewSnapshot.prototype = ObjectFreeze({ __proto__: null });
+
+function BatchEntry(views, byteLength) {
+  this.views = views;
+  this.byteLength = byteLength;
+}
+BatchEntry.prototype = ObjectFreeze({ __proto__: null });
+
 function snapshotByteView(value) {
   const buffer = TypedArrayPrototypeGetBuffer(value);
   const sharedBufferView = isSharedArrayBuffer(buffer) ?
     new Uint8Array(buffer) : undefined;
-  return {
-    __proto__: null,
-    value,
-    buffer,
-    bufferByteLength: sharedBufferView === undefined ?
-      ArrayBufferPrototypeGetByteLength(buffer) :
-      TypedArrayPrototypeGetByteLength(sharedBufferView),
-    byteLength: TypedArrayPrototypeGetByteLength(value),
-    byteOffset: TypedArrayPrototypeGetByteOffset(value),
-    detached: sharedBufferView === undefined &&
-      ArrayBufferPrototypeGetDetached(buffer),
-    sharedBufferView,
-  };
+  return new ByteViewSnapshot(value, buffer, sharedBufferView);
 }

 function validateByteView(snapshot) {
@@ -325,7 +337,7 @@ function createBatchEntry(chunks) {
     views[i] = view;
     byteLength += view.byteLength;
   }
-  return { __proto__: null, views, byteLength };
+  return new BatchEntry(views, byteLength);
 }

 /**
@@ -345,15 +357,14 @@ function splitBatchEntry(entry, limit) {
   for (let i = 0; i < views.length; i++) {
     const view = views[i];
     if (current.length > 0 && byteLength + view.byteLength >= limit) {
-      ArrayPrototypePush(entries,
-                         { __proto__: null, views: current, byteLength });
+      ArrayPrototypePush(entries, new BatchEntry(current, byteLength));
       current = [];
       byteLength = 0;
     }
     ArrayPrototypePush(current, view);
     byteLength += view.byteLength;
   }
-  ArrayPrototypePush(entries, { __proto__: null, views: current, byteLength });
+  ArrayPrototypePush(entries, new BatchEntry(current, byteLength));
   return entries;
 }