Commit 8f39e07d authored by Eric Holk's avatar Eric Holk Committed by Commit Bot

Add allocation information to ArrayBuffer::Contents

Array buffers can now have an allocation that is larger than the actual
buffer, such as when WebAssembly guard regions are enabled. Embedders
need to know the actual allocation start and length when externalizing
a buffer so they can deallocate it properly.

Bug: chromium:720302, v8:5277
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: Ifc184fdd59d77af01c07a64d2c0229ca859a01b0
Reviewed-on: https://chromium-review.googlesource.com/523271
Commit-Queue: Eric Holk <eholk@chromium.org>
Reviewed-by: 's avatarJochen Eisinger <jochen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45777}
parent e285b712
......@@ -4262,12 +4262,26 @@ class V8_EXPORT ArrayBuffer : public Object {
*/
class V8_EXPORT Contents { // NOLINT
public:
Contents() : data_(NULL), byte_length_(0) {}
Contents()
: allocation_base_(nullptr),
allocation_length_(0),
allocation_mode_(Allocator::AllocationMode::kNormal),
data_(nullptr),
byte_length_(0) {}
void* AllocationBase() const { return allocation_base_; }
size_t AllocationLength() const { return allocation_length_; }
Allocator::AllocationMode AllocationMode() const {
return allocation_mode_;
}
void* Data() const { return data_; }
size_t ByteLength() const { return byte_length_; }
private:
void* allocation_base_;
size_t allocation_length_;
Allocator::AllocationMode allocation_mode_;
void* data_;
size_t byte_length_;
......@@ -4618,12 +4632,26 @@ class V8_EXPORT SharedArrayBuffer : public Object {
*/
class V8_EXPORT Contents { // NOLINT
public:
Contents() : data_(NULL), byte_length_(0) {}
Contents()
: allocation_base_(nullptr),
allocation_length_(0),
allocation_mode_(ArrayBuffer::Allocator::AllocationMode::kNormal),
data_(nullptr),
byte_length_(0) {}
void* AllocationBase() const { return allocation_base_; }
size_t AllocationLength() const { return allocation_length_; }
ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
return allocation_mode_;
}
void* Data() const { return data_; }
size_t ByteLength() const { return byte_length_; }
private:
void* allocation_base_;
size_t allocation_length_;
ArrayBuffer::Allocator::Allocator::AllocationMode allocation_mode_;
void* data_;
size_t byte_length_;
......
......@@ -7784,6 +7784,11 @@ v8::ArrayBuffer::Contents v8::ArrayBuffer::GetContents() {
i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this);
size_t byte_length = static_cast<size_t>(self->byte_length()->Number());
Contents contents;
contents.allocation_base_ = self->allocation_base();
contents.allocation_length_ = self->allocation_length();
contents.allocation_mode_ = self->has_guard_region()
? Allocator::AllocationMode::kReservation
: Allocator::AllocationMode::kNormal;
contents.data_ = self->backing_store();
contents.byte_length_ = byte_length;
return contents;
......@@ -7992,6 +7997,12 @@ v8::SharedArrayBuffer::Contents v8::SharedArrayBuffer::GetContents() {
Contents contents;
contents.data_ = self->backing_store();
contents.byte_length_ = byte_length;
// SharedArrayBuffers never have guard regions, so their allocation and data
// are equivalent.
contents.allocation_base_ = self->backing_store();
contents.allocation_length_ = byte_length;
contents.allocation_mode_ =
ArrayBufferAllocator::Allocator::AllocationMode::kNormal;
return contents;
}
......
......@@ -3416,10 +3416,16 @@ class ScopedArrayBufferContents {
public:
explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
: contents_(contents) {}
~ScopedArrayBufferContents() { free(contents_.Data()); }
~ScopedArrayBufferContents() { free(contents_.AllocationBase()); }
void* Data() const { return contents_.Data(); }
size_t ByteLength() const { return contents_.ByteLength(); }
void* AllocationBase() const { return contents_.AllocationBase(); }
size_t AllocationLength() const { return contents_.AllocationLength(); }
v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
return contents_.AllocationMode();
}
private:
const v8::ArrayBuffer::Contents contents_;
};
......@@ -3695,16 +3701,43 @@ THREADED_TEST(ArrayBuffer_NeuteringScript) {
CheckDataViewIsNeutered(dv);
}
THREADED_TEST(ArrayBuffer_AllocationInformation) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope handle_scope(isolate);
const size_t ab_size = 1024;
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, ab_size);
ScopedArrayBufferContents contents(ab->Externalize());
// Array buffers should have normal allocation mode.
CHECK(contents.AllocationMode() ==
v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
// The allocation must contain the buffer (normally they will be equal, but
// this is not required by the contract).
CHECK_NOT_NULL(contents.AllocationBase());
const uintptr_t alloc =
reinterpret_cast<uintptr_t>(contents.AllocationBase());
const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
CHECK_LE(alloc, data);
CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
}
class ScopedSharedArrayBufferContents {
public:
explicit ScopedSharedArrayBufferContents(
const v8::SharedArrayBuffer::Contents& contents)
: contents_(contents) {}
~ScopedSharedArrayBufferContents() { free(contents_.Data()); }
~ScopedSharedArrayBufferContents() { free(contents_.AllocationBase()); }
void* Data() const { return contents_.Data(); }
size_t ByteLength() const { return contents_.ByteLength(); }
void* AllocationBase() const { return contents_.AllocationBase(); }
size_t AllocationLength() const { return contents_.AllocationLength(); }
v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
return contents_.AllocationMode();
}
private:
const v8::SharedArrayBuffer::Contents contents_;
};
......@@ -25952,6 +25985,29 @@ TEST(FutexInterruption) {
timeout_thread.Join();
}
THREADED_TEST(SharedArrayBuffer_AllocationInformation) {
i::FLAG_harmony_sharedarraybuffer = true;
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope handle_scope(isolate);
const size_t ab_size = 1024;
Local<v8::SharedArrayBuffer> ab =
v8::SharedArrayBuffer::New(isolate, ab_size);
ScopedSharedArrayBufferContents contents(ab->Externalize());
// Array buffers should have normal allocation mode.
CHECK(contents.AllocationMode() ==
v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
// The allocation must contain the buffer (normally they will be equal, but
// this is not required by the contract).
CHECK_NOT_NULL(contents.AllocationBase());
const uintptr_t alloc =
reinterpret_cast<uintptr_t>(contents.AllocationBase());
const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
CHECK_LE(alloc, data);
CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
}
static int nb_uncaught_exception_callback_calls = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment