Skip to content

Commit d66c3a6

Browse files
ronagnodejs-github-bot
authored andcommitted
deps: V8: add CopyArrayBufferBytes API
Add v8::ArrayBuffer::CopyArrayBufferBytes and v8::SharedArrayBuffer::CopyArrayBufferBytes, which copy a byte range from one backing store to another. V8 clamps the byte range and handles detached and immutable buffers: nothing is copied when the source is detached or the target is detached or immutable, and the number of bytes actually copied is returned. The SharedArrayBuffer overload uses a relaxed-atomic memmove that honors the SharedArrayBuffer memory model. Carried as a floating patch cherry-picked from: https://chromium-review.googlesource.com/c/v8/v8/+/7735151 That CL is authored by a Node.js collaborator (Ben Noordhuis) and is expected to land upstream, so the floating patch should be easy to maintain: it touches nothing but the public ArrayBuffer API and can be dropped wholesale on the next V8 upgrade that includes it. v8_embedder_string is bumped to -node.21 accordingly. Refs: https://chromium-review.googlesource.com/c/v8/v8/+/7735151 Signed-off-by: Robert Nagy <ronagy@icloud.com> PR-URL: #63828 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
1 parent 20fda56 commit d66c3a6

4 files changed

Lines changed: 125 additions & 1 deletion

File tree

common.gypi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
# Reset this number to 0 on major V8 upgrades.
4242
# Increment by one for each non-official patch applied to deps/v8.
43-
'v8_embedder_string': '-node.20',
43+
'v8_embedder_string': '-node.21',
4444

4545
##### V8 defaults for Node.js #####
4646

deps/v8/include/v8-array-buffer.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,17 @@ class V8_EXPORT ArrayBuffer : public Object {
338338
*/
339339
bool IsImmutable() const;
340340

341+
/**
342+
* Copy up to |bytes_to_copy| bytes from this ArrayBuffer starting at
343+
* position |source_start| to the target ArrayBuffer starting at position
344+
* |target_start|. Nothing is copied if the source ArrayBuffer is detached,
345+
* or if the target ArrayBuffer is detached or immutable.
346+
* Returns the number of bytes actually copied.
347+
*/
348+
size_t CopyArrayBufferBytes(size_t source_start, size_t bytes_to_copy,
349+
Local<ArrayBuffer> target,
350+
size_t target_start) const;
351+
341352
/**
342353
* Detaches this ArrayBuffer and all its views (typed arrays).
343354
* Detaching sets the byte length of the buffer and all typed arrays to zero,
@@ -605,6 +616,16 @@ class V8_EXPORT SharedArrayBuffer : public Object {
605616
*/
606617
void* Data() const;
607618

619+
/**
620+
* Copy up to |bytes_to_copy| bytes from this SharedArrayBuffer starting at
621+
* position |source_start| to the target SharedArrayBuffer starting at
622+
* position |target_start|.
623+
* Returns the number of bytes actually copied.
624+
*/
625+
size_t CopyArrayBufferBytes(size_t source_start, size_t bytes_to_copy,
626+
Local<SharedArrayBuffer> target,
627+
size_t target_start) const;
628+
608629
V8_INLINE static SharedArrayBuffer* Cast(Value* value) {
609630
#ifdef V8_ENABLE_CHECKS
610631
CheckCast(value);

deps/v8/src/api/api.cc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4221,6 +4221,44 @@ void* v8::SharedArrayBuffer::Data() const {
42214221
return Utils::OpenDirectHandle(this)->backing_store();
42224222
}
42234223

4224+
template <bool is_shared>
4225+
static size_t CopyArrayBufferBytesImpl(const void* source_buffer,
4226+
size_t source_start,
4227+
size_t source_length,
4228+
void* target_buffer, size_t target_start,
4229+
size_t target_length,
4230+
size_t bytes_to_copy) {
4231+
source_start = std::min(source_start, source_length);
4232+
target_start = std::min(target_start, target_length);
4233+
size_t source_size = source_length - source_start;
4234+
size_t target_size = target_length - target_start;
4235+
bytes_to_copy = std::min({bytes_to_copy, source_size, target_size});
4236+
if (bytes_to_copy == 0) return 0;
4237+
const char* src = static_cast<const char*>(source_buffer) + source_start;
4238+
char* dst = static_cast<char*>(target_buffer) + target_start;
4239+
if (is_shared) {
4240+
base::Relaxed_Memmove(reinterpret_cast<base::Atomic8*>(dst),
4241+
reinterpret_cast<const base::Atomic8*>(src),
4242+
bytes_to_copy);
4243+
} else {
4244+
std::memmove(dst, src, bytes_to_copy);
4245+
}
4246+
return bytes_to_copy;
4247+
}
4248+
4249+
size_t v8::SharedArrayBuffer::CopyArrayBufferBytes(
4250+
size_t source_start, size_t bytes_to_copy, Local<SharedArrayBuffer> target,
4251+
size_t target_start) const {
4252+
i::DisallowGarbageCollection no_gc;
4253+
auto self = Utils::OpenDirectHandle(this);
4254+
auto that = Utils::OpenDirectHandle(*target);
4255+
DCHECK(!that->is_immutable());
4256+
return CopyArrayBufferBytesImpl<true>(self->backing_store(), source_start,
4257+
self->GetByteLength(),
4258+
that->backing_store(), target_start,
4259+
that->GetByteLength(), bytes_to_copy);
4260+
}
4261+
42244262
void v8::ArrayBuffer::CheckCast(Value* that) {
42254263
auto obj = *Utils::OpenDirectHandle(that);
42264264
Utils::ApiCheck(
@@ -8907,6 +8945,21 @@ bool v8::ArrayBuffer::IsImmutable() const {
89078945
return Utils::OpenDirectHandle(this)->is_immutable();
89088946
}
89098947

8948+
size_t v8::ArrayBuffer::CopyArrayBufferBytes(size_t source_start,
8949+
size_t bytes_to_copy,
8950+
Local<ArrayBuffer> target,
8951+
size_t target_start) const {
8952+
i::DisallowGarbageCollection no_gc;
8953+
auto self = Utils::OpenDirectHandle(this);
8954+
auto that = Utils::OpenDirectHandle(*target);
8955+
if (self->was_detached()) return 0;
8956+
if (that->was_detached() || that->is_immutable()) return 0;
8957+
return CopyArrayBufferBytesImpl<false>(self->backing_store(), source_start,
8958+
self->GetByteLength(),
8959+
that->backing_store(), target_start,
8960+
that->GetByteLength(), bytes_to_copy);
8961+
}
8962+
89108963
namespace {
89118964
std::shared_ptr<i::BackingStore> ToInternal(
89128965
std::shared_ptr<i::BackingStoreBase> backing_store) {

deps/v8/test/cctest/test-api-array-buffer.cc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,3 +1301,53 @@ TEST(ArrayBuffer_ImmutableBackingStore) {
13011301

13021302
CHECK(ab->IsImmutable());
13031303
}
1304+
1305+
TEST(ArrayBuffer_CopyArrayBufferBytes) {
1306+
LocalContext env;
1307+
v8::Isolate* isolate = env.isolate();
1308+
v8::HandleScope scope(isolate);
1309+
auto ab1 = v8::ArrayBuffer::New(isolate, 6);
1310+
auto ab2 = v8::ArrayBuffer::New(isolate, 4);
1311+
std::memcpy(ab1->Data(), "123456", 6);
1312+
std::memcpy(ab2->Data(), "ABCD", 4);
1313+
CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 0, ab2, 0));
1314+
CHECK_EQ(0, ab1->CopyArrayBufferBytes(6, 0, ab2, 6));
1315+
CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 4, ab2, 6));
1316+
CHECK_EQ(0, std::memcmp(ab2->Data(), "ABCD", 4));
1317+
CHECK_EQ(4, ab1->CopyArrayBufferBytes(0, 6, ab2, 0));
1318+
CHECK_EQ(0, std::memcmp(ab2->Data(), "1234", 4));
1319+
CHECK_EQ(2, ab1->CopyArrayBufferBytes(0, 6, ab2, 2));
1320+
CHECK_EQ(0, std::memcmp(ab2->Data(), "1212", 4));
1321+
ab2->Detach(v8::Local<v8::Value>()).Check();
1322+
CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 6, ab2, 0));
1323+
std::unique_ptr<v8::BackingStore> backing_store =
1324+
v8::ArrayBuffer::NewBackingStore(isolate, 6);
1325+
CHECK(backing_store);
1326+
v8::internal::BackingStore* i_backing_store =
1327+
reinterpret_cast<v8::internal::BackingStore*>(backing_store.get());
1328+
i_backing_store->set_is_immutable(true);
1329+
CHECK(i_backing_store->is_immutable());
1330+
std::shared_ptr<v8::BackingStore> shared_backing_store =
1331+
std::move(backing_store);
1332+
auto ab3 = v8::ArrayBuffer::New(isolate, shared_backing_store);
1333+
CHECK(ab3->IsImmutable());
1334+
CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 6, ab3, 0));
1335+
}
1336+
1337+
TEST(SharedArrayBuffer_CopyArrayBufferBytes) {
1338+
LocalContext env;
1339+
v8::Isolate* isolate = env.isolate();
1340+
v8::HandleScope scope(isolate);
1341+
auto ab1 = v8::SharedArrayBuffer::New(isolate, 6);
1342+
auto ab2 = v8::SharedArrayBuffer::New(isolate, 4);
1343+
std::memcpy(ab1->Data(), "123456", 6);
1344+
std::memcpy(ab2->Data(), "ABCD", 4);
1345+
CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 0, ab2, 0));
1346+
CHECK_EQ(0, ab1->CopyArrayBufferBytes(6, 0, ab2, 6));
1347+
CHECK_EQ(0, ab1->CopyArrayBufferBytes(0, 4, ab2, 6));
1348+
CHECK_EQ(0, std::memcmp(ab2->Data(), "ABCD", 4));
1349+
CHECK_EQ(4, ab1->CopyArrayBufferBytes(0, 6, ab2, 0));
1350+
CHECK_EQ(0, std::memcmp(ab2->Data(), "1234", 4));
1351+
CHECK_EQ(2, ab1->CopyArrayBufferBytes(0, 6, ab2, 2));
1352+
CHECK_EQ(0, std::memcmp(ab2->Data(), "1212", 4));
1353+
}

0 commit comments

Comments
 (0)