diff --git a/lib/buffer.js b/lib/buffer.js index 54fa97202057c4..23149e09d64a0c 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -58,7 +58,7 @@ const { byteLengthUtf8, compare: _compare, compareOffset, - copyArrayBuffer, + copy: _copy, createFromString, fill: bindingFill, isAscii: bindingIsAscii, @@ -204,7 +204,7 @@ function toInteger(n, defaultVal) { return defaultVal; } -function _copy(source, target, targetStart, sourceStart, sourceEnd) { +function copyImpl(source, target, targetStart, sourceStart, sourceEnd) { if (!isUint8Array(source)) throw new ERR_INVALID_ARG_TYPE('source', ['Buffer', 'Uint8Array'], source); if (!isUint8Array(target)) @@ -253,13 +253,7 @@ function _copyActual(source, target, targetStart, sourceStart, sourceEnd) { return 0; if (sourceStart !== 0 || sourceEnd < source.length) { - copyArrayBuffer( - target.buffer, - target.byteOffset + targetStart, - source.buffer, - source.byteOffset + sourceStart, - nb, - ); + _copy(source, target, targetStart, sourceStart, sourceEnd); } else { TypedArrayPrototypeSet(target, source, targetStart); } @@ -816,7 +810,7 @@ ObjectDefineProperty(Buffer.prototype, 'offset', { Buffer.prototype.copy = function copy(target, targetStart, sourceStart, sourceEnd) { - return _copy(this, target, targetStart, sourceStart, sourceEnd); + return copyImpl(this, target, targetStart, sourceStart, sourceEnd); }; // No need to verify that "buf.length <= MAX_UINT32" since it's a read-only diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 300060f9d24290..038c9e563653d9 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -569,7 +569,7 @@ void StringSlice(const FunctionCallbackInfo& args) { } // bytesCopied = copy(buffer, target[, targetStart][, sourceStart][, sourceEnd]) -void Copy(const FunctionCallbackInfo &args) { +void SlowCopy(const FunctionCallbackInfo &args) { Environment* env = Environment::GetCurrent(args); THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]); @@ -606,6 +606,34 @@ void Copy(const FunctionCallbackInfo &args) { args.GetReturnValue().Set(to_copy); } +uint32_t FastCopy(Local receiver, + const v8::FastApiArrayBufferView& source, + v8::FastApiArrayBufferView& target, + uint32_t target_start, + uint32_t source_start, + uint32_t source_end, + v8::FastApiCallbackOptions& options) { + // Copy 0 bytes; we're done + if (target_start >= target.byte_length || source_start >= source_end) + return 0; + + assert(source_start <= source_end); + + if (source_end - source_start > target.byte_length - target_start) + source_end = source_start + target.byte_length - target_start; + + uint32_t to_copy = std::min( + std::min(source_end - source_start, target.byte_length - target_start), + source.byte_length - source_start); + + memmove(reinterpret_cast(target.data) + target_start, + reinterpret_cast(source.data) + source_start, to_copy); + + return to_copy; +} + +static v8::CFunction fast_copy( + v8::CFunction::Make(FastCopy)); void Fill(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -1275,7 +1303,7 @@ void Initialize(Local target, "byteLengthUtf8", SlowByteLengthUtf8, &fast_byte_length_utf8); - SetMethod(context, target, "copy", Copy); + SetFastMethod(context, target, "copy", SlowCopy, &fast_copy); SetMethodNoSideEffect(context, target, "compare", Compare); SetMethodNoSideEffect(context, target, "compareOffset", CompareOffset); SetMethod(context, target, "fill", Fill); @@ -1335,6 +1363,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(fast_byte_length_utf8.GetTypeInfo()); registry->Register(FastByteLengthUtf8); registry->Register(Copy); + registry->Register(FastCopy); + registry->Register(fast_copy.GetTypeInfo()); registry->Register(Compare); registry->Register(CompareOffset); registry->Register(Fill);