diff --git a/deps/v8/include/v8-array-buffer.h b/deps/v8/include/v8-array-buffer.h index 4b55c445376530..13b91cf5b7265f 100644 --- a/deps/v8/include/v8-array-buffer.h +++ b/deps/v8/include/v8-array-buffer.h @@ -338,6 +338,17 @@ class V8_EXPORT ArrayBuffer : public Object { */ bool IsImmutable() const; + /** + * Copy up to |bytes_to_copy| bytes from this ArrayBuffer starting at + * position |source_start| to the target ArrayBuffer starting at position + * |target_start|. Nothing is copied if the source or target ArrayBuffer is + * detached. + * Returns the number of bytes actually copied. + */ + size_t CopyArrayBufferBytes(size_t source_start, size_t bytes_to_copy, + Local target, + size_t target_start) const; + /** * Detaches this ArrayBuffer and all its views (typed arrays). * Detaching sets the byte length of the buffer and all typed arrays to zero, @@ -605,6 +616,16 @@ class V8_EXPORT SharedArrayBuffer : public Object { */ void* Data() const; + /** + * Copy up to |bytes_to_copy| bytes from this SharedArrayBuffer starting at + * position |source_start| to the target SharedArrayBuffer starting at + * position |target_start|. + * Returns the number of bytes actually copied. + */ + size_t CopyArrayBufferBytes(size_t source_start, size_t bytes_to_copy, + Local target, + size_t target_start) const; + V8_INLINE static SharedArrayBuffer* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS CheckCast(value); diff --git a/deps/v8/src/api/api.cc b/deps/v8/src/api/api.cc index 9ef4e3b4a66006..bdb9f715de95b4 100644 --- a/deps/v8/src/api/api.cc +++ b/deps/v8/src/api/api.cc @@ -4221,6 +4221,44 @@ void* v8::SharedArrayBuffer::Data() const { return Utils::OpenDirectHandle(this)->backing_store(); } +template +static size_t CopyArrayBufferBytesImpl(const void* source_buffer, + size_t source_start, + size_t source_length, + void* target_buffer, size_t target_start, + size_t target_length, + size_t bytes_to_copy) { + source_start = std::min(source_start, source_length); + target_start = std::min(target_start, target_length); + size_t source_size = source_length - source_start; + size_t target_size = target_length - target_start; + bytes_to_copy = std::min({bytes_to_copy, source_size, target_size}); + if (bytes_to_copy == 0) return 0; + const char* src = static_cast(source_buffer) + source_start; + char* dst = static_cast(target_buffer) + target_start; + if (is_shared) { + base::Relaxed_Memmove(reinterpret_cast(dst), + reinterpret_cast(src), + bytes_to_copy); + } else { + std::memmove(dst, src, bytes_to_copy); + } + return bytes_to_copy; +} + +size_t v8::SharedArrayBuffer::CopyArrayBufferBytes( + size_t source_start, size_t bytes_to_copy, Local target, + size_t target_start) const { + i::DisallowGarbageCollection no_gc; + auto self = Utils::OpenDirectHandle(this); + auto that = Utils::OpenDirectHandle(*target); + DCHECK(!that->is_immutable()); + return CopyArrayBufferBytesImpl(self->backing_store(), source_start, + self->GetByteLength(), + that->backing_store(), target_start, + that->GetByteLength(), bytes_to_copy); +} + void v8::ArrayBuffer::CheckCast(Value* that) { auto obj = *Utils::OpenDirectHandle(that); Utils::ApiCheck( @@ -8907,6 +8945,21 @@ bool v8::ArrayBuffer::IsImmutable() const { return Utils::OpenDirectHandle(this)->is_immutable(); } +size_t v8::ArrayBuffer::CopyArrayBufferBytes(size_t source_start, + size_t bytes_to_copy, + Local target, + size_t target_start) const { + i::DisallowGarbageCollection no_gc; + auto self = Utils::OpenDirectHandle(this); + auto that = Utils::OpenDirectHandle(*target); + if (self->was_detached()) return 0; + if (that->was_detached() || that->is_immutable()) return 0; + return CopyArrayBufferBytesImpl(self->backing_store(), source_start, + self->GetByteLength(), + that->backing_store(), target_start, + that->GetByteLength(), bytes_to_copy); +} + namespace { std::shared_ptr ToInternal( std::shared_ptr backing_store) { diff --git a/deps/v8/test/cctest/test-api-array-buffer.cc b/deps/v8/test/cctest/test-api-array-buffer.cc index 955639f73650fd..e66b216f0751f1 100644 --- a/deps/v8/test/cctest/test-api-array-buffer.cc +++ b/deps/v8/test/cctest/test-api-array-buffer.cc @@ -1301,3 +1301,53 @@ TEST(ArrayBuffer_ImmutableBackingStore) { CHECK(ab->IsImmutable()); } + +TEST(ArrayBuffer_CopyArrayBufferBytes) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + auto ab1 = v8::ArrayBuffer::New(isolate, 6); + auto ab2 = v8::ArrayBuffer::New(isolate, 4); + std::memcpy(ab1->Data(), "123456", 6); + std::memcpy(ab2->Data(), "ABCD", 4); + CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 0, ab2, 0)); + CHECK_EQ(0, ab1->CopyArrayBufferBytes(6, 0, ab2, 6)); + CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 4, ab2, 6)); + CHECK_EQ(0, std::memcmp(ab2->Data(), "ABCD", 4)); + CHECK_EQ(4, ab1->CopyArrayBufferBytes(0, 6, ab2, 0)); + CHECK_EQ(0, std::memcmp(ab2->Data(), "1234", 4)); + CHECK_EQ(2, ab1->CopyArrayBufferBytes(0, 6, ab2, 2)); + CHECK_EQ(0, std::memcmp(ab2->Data(), "1212", 4)); + ab2->Detach(v8::Local()).Check(); + CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 6, ab2, 0)); + std::unique_ptr backing_store = + v8::ArrayBuffer::NewBackingStore(isolate, 6); + CHECK(backing_store); + v8::internal::BackingStore* i_backing_store = + reinterpret_cast(backing_store.get()); + i_backing_store->set_is_immutable(true); + CHECK(i_backing_store->is_immutable()); + std::shared_ptr shared_backing_store = + std::move(backing_store); + auto ab3 = v8::ArrayBuffer::New(isolate, shared_backing_store); + CHECK(ab3->IsImmutable()); + CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 6, ab3, 0)); +} + +TEST(SharedArrayBuffer_CopyArrayBufferBytes) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + auto ab1 = v8::SharedArrayBuffer::New(isolate, 6); + auto ab2 = v8::SharedArrayBuffer::New(isolate, 4); + std::memcpy(ab1->Data(), "123456", 6); + std::memcpy(ab2->Data(), "ABCD", 4); + CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 0, ab2, 0)); + CHECK_EQ(0, ab1->CopyArrayBufferBytes(6, 0, ab2, 6)); + CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 4, ab2, 6)); + CHECK_EQ(0, std::memcmp(ab2->Data(), "ABCD", 4)); + CHECK_EQ(4, ab1->CopyArrayBufferBytes(0, 6, ab2, 0)); + CHECK_EQ(0, std::memcmp(ab2->Data(), "1234", 4)); + CHECK_EQ(2, ab1->CopyArrayBufferBytes(0, 6, ab2, 2)); + CHECK_EQ(0, std::memcmp(ab2->Data(), "1212", 4)); +}