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);