Commit a7e9f3b3aeb for nodejs

commit a7e9f3b3aeb1331774c3595369e7eda201135932
Author: René <contact.9a5d6388@renegade334.me.uk>
Date:   Wed Oct 7 17:00:15 2026 +0100

    src: use native CopyArrayBufferBytes for webstream buffer copy

    Signed-off-by: Renegade334 <contact.9a5d6388@renegade334.me.uk>
    PR-URL: https://github.com/nodejs/node/pull/66400
    Reviewed-By: Anna Henningsen <anna@addaleax.net>

diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index 69b4c0ac525..1d16813b380 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -1775,27 +1775,16 @@ static void SetDetachKey(const FunctionCallbackInfo<Value>& args) {
   ab->SetDetachKey(key);
 }

-namespace {
-
-std::pair<void*, size_t> DecomposeBufferToParts(Local<Value> buffer) {
-  void* pointer;
-  size_t byte_length;
-  if (buffer->IsArrayBuffer()) {
-    Local<ArrayBuffer> ab = buffer.As<ArrayBuffer>();
-    pointer = ab->Data();
-    byte_length = ab->ByteLength();
-  } else if (buffer->IsSharedArrayBuffer()) {
-    Local<SharedArrayBuffer> ab = buffer.As<SharedArrayBuffer>();
-    pointer = ab->Data();
-    byte_length = ab->ByteLength();
-  } else {
-    UNREACHABLE();  // Caller must validate.
-  }
-  return {pointer, byte_length};
+void CopyArrayBufferImpl(Local<ArrayBuffer> target,
+                         uint32_t target_start,
+                         Local<ArrayBuffer> source,
+                         uint32_t source_start,
+                         uint32_t bytes_to_copy) {
+  uint32_t bytes_copied = source->CopyArrayBufferBytes(
+      source_start, bytes_to_copy, target, target_start);
+  CHECK_EQ(bytes_copied, bytes_to_copy);
 }

-}  // namespace
-
 void CopyArrayBuffer(const FunctionCallbackInfo<Value>& args) {
   // args[0] == Destination ArrayBuffer
   // args[1] == Destination ArrayBuffer Offset
@@ -1803,37 +1792,37 @@ void CopyArrayBuffer(const FunctionCallbackInfo<Value>& args) {
   // args[3] == Source ArrayBuffer Offset
   // args[4] == bytesToCopy

-  CHECK(args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer());
+  CHECK(args[0]->IsArrayBuffer());
   CHECK(args[1]->IsUint32());
-  CHECK(args[2]->IsArrayBuffer() || args[2]->IsSharedArrayBuffer());
+  CHECK(args[2]->IsArrayBuffer());
   CHECK(args[3]->IsUint32());
   CHECK(args[4]->IsUint32());

-  void* destination;
-  size_t destination_byte_length;
-  std::tie(destination, destination_byte_length) =
-      DecomposeBufferToParts(args[0]);
-
-  void* source;
-  size_t source_byte_length;
-  std::tie(source, source_byte_length) = DecomposeBufferToParts(args[2]);
-
-  uint32_t destination_offset = args[1].As<Uint32>()->Value();
-  uint32_t source_offset = args[3].As<Uint32>()->Value();
-  size_t bytes_to_copy = args[4].As<Uint32>()->Value();
+  CopyArrayBufferImpl(args[0].As<ArrayBuffer>(),
+                      args[1].As<Uint32>()->Value(),
+                      args[2].As<ArrayBuffer>(),
+                      args[3].As<Uint32>()->Value(),
+                      args[4].As<Uint32>()->Value());
+}

-  // Assert the offsets are within bounds before the subtractions below, which
-  // would otherwise underflow and defeat the bytes_to_copy bounds checks.
-  CHECK_LE(destination_offset, destination_byte_length);
-  CHECK_LE(source_offset, source_byte_length);
-  CHECK_GE(destination_byte_length - destination_offset, bytes_to_copy);
-  CHECK_GE(source_byte_length - source_offset, bytes_to_copy);
+void FastCopyArrayBuffer(Local<Value> receiver,
+                         Local<Value> target,
+                         uint32_t target_start,
+                         Local<Value> source,
+                         uint32_t source_start,
+                         uint32_t bytes_to_copy) {
+  CHECK(target->IsArrayBuffer());
+  CHECK(source->IsArrayBuffer());

-  uint8_t* dest = static_cast<uint8_t*>(destination) + destination_offset;
-  uint8_t* src = static_cast<uint8_t*>(source) + source_offset;
-  memcpy(dest, src, bytes_to_copy);
+  CopyArrayBufferImpl(target.As<ArrayBuffer>(),
+                      target_start,
+                      source.As<ArrayBuffer>(),
+                      source_start,
+                      bytes_to_copy);
 }

+static CFunction fast_copy_array_buffer(CFunction::Make(FastCopyArrayBuffer));
+
 // Converts a number parameter to size_t suitable for ArrayBuffer sizes
 // Could be larger than uint32_t
 // See v8::internal::TryNumberToSize and v8::internal::NumberToSize
@@ -2057,7 +2046,11 @@ void Initialize(Local<Object> target,
                             &fast_index_of_number);
   SetMethodNoSideEffect(context, target, "indexOfString", IndexOfString);

-  SetMethod(context, target, "copyArrayBuffer", CopyArrayBuffer);
+  SetFastMethod(context,
+                target,
+                "copyArrayBuffer",
+                CopyArrayBuffer,
+                &fast_copy_array_buffer);
   SetMethodNoSideEffect(
       context, target, "createUnsafeArrayBuffer", CreateUnsafeArrayBuffer);
   SetMethodNoSideEffect(
@@ -2183,6 +2176,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
   registry->Register(StringWrite<UTF8>);

   registry->Register(CopyArrayBuffer);
+  registry->Register(fast_copy_array_buffer);
   registry->Register(CreateUnsafeArrayBuffer);
   registry->Register(ArrayBufferAlignedOffset);