Commit 63a25016 authored by Eric Holk's avatar Eric Holk Committed by Commit Bot

Implement updated V8 ArrayBuffer allocator API

For more details, see https://goo.gl/q2GSav

Bug: chromium:720302
Change-Id: Iebdadcb48633b9c05a8a8e6af4cc1b01fac01d6d
Reviewed-on: https://chromium-review.googlesource.com/534934
Commit-Queue: Eric Holk <eholk@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarJochen Eisinger <jochen@chromium.org>
Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#486538}
parent 1c014b7e
......@@ -409,6 +409,38 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
void Free(void* data, size_t size) override {
WTF::ArrayBufferContents::FreeMemory(data);
}
void* Reserve(size_t length) override {
return WTF::ArrayBufferContents::ReserveMemory(length);
}
void Free(void* data, size_t length, AllocationMode mode) override {
switch (mode) {
case AllocationMode::kNormal:
Free(data, length);
return;
case AllocationMode::kReservation:
WTF::ArrayBufferContents::ReleaseReservedMemory(data, length);
return;
default:
NOTREACHED();
}
}
void SetProtection(void* data,
size_t length,
Protection protection) override {
switch (protection) {
case Protection::kNoAccess:
WTF::SetSystemPagesInaccessible(data, length);
return;
case Protection::kReadWrite:
(void)WTF::SetSystemPagesAccessible(data, length);
return;
default:
NOTREACHED();
}
}
};
} // namespace
......
......@@ -890,7 +890,23 @@ v8::Local<v8::Object> {{v8_class}}::findInstanceInPrototypeChain(v8::Local<v8::V
// Transfer the ownership of the allocated memory to an {{interface_name}} without
// copying.
v8::{{interface_name}}::Contents v8Contents = v8buffer->Externalize();
WTF::ArrayBufferContents::DataHandle data(v8Contents.Data(), WTF::ArrayBufferContents::FreeMemory);
WTF::ArrayBufferContents::AllocationKind kind = WTF::ArrayBufferContents::AllocationKind::kNormal;
switch (v8Contents.AllocationMode()) {
case v8::ArrayBuffer::Allocator::AllocationMode::kNormal:
kind = WTF::ArrayBufferContents::AllocationKind::kNormal;
break;
case v8::ArrayBuffer::Allocator::AllocationMode::kReservation:
kind = WTF::ArrayBufferContents::AllocationKind::kReservation;
break;
default:
NOTREACHED();
};
WTF::ArrayBufferContents::DataHandle data(v8Contents.AllocationBase(),
v8Contents.AllocationLength(),
v8Contents.Data(),
v8Contents.ByteLength(),
kind,
WTF::ArrayBufferContents::FreeMemory);
WTF::ArrayBufferContents contents(std::move(data), v8Contents.ByteLength(), WTF::ArrayBufferContents::k{% if interface_name == 'ArrayBuffer' %}Not{% endif %}Shared);
{{cpp_class}}* buffer = {{cpp_class}}::Create(contents);
v8::Local<v8::Object> associatedWrapper = buffer->AssociateWithWrapper(v8::Isolate::GetCurrent(), buffer->GetWrapperTypeInfo(), object);
......
......@@ -78,7 +78,23 @@ TestArrayBuffer* V8ArrayBuffer::toImpl(v8::Local<v8::Object> object) {
// Transfer the ownership of the allocated memory to an ArrayBuffer without
// copying.
v8::ArrayBuffer::Contents v8Contents = v8buffer->Externalize();
WTF::ArrayBufferContents::DataHandle data(v8Contents.Data(), WTF::ArrayBufferContents::FreeMemory);
WTF::ArrayBufferContents::AllocationKind kind = WTF::ArrayBufferContents::AllocationKind::kNormal;
switch (v8Contents.AllocationMode()) {
case v8::ArrayBuffer::Allocator::AllocationMode::kNormal:
kind = WTF::ArrayBufferContents::AllocationKind::kNormal;
break;
case v8::ArrayBuffer::Allocator::AllocationMode::kReservation:
kind = WTF::ArrayBufferContents::AllocationKind::kReservation;
break;
default:
NOTREACHED();
};
WTF::ArrayBufferContents::DataHandle data(v8Contents.AllocationBase(),
v8Contents.AllocationLength(),
v8Contents.Data(),
v8Contents.ByteLength(),
kind,
WTF::ArrayBufferContents::FreeMemory);
WTF::ArrayBufferContents contents(std::move(data), v8Contents.ByteLength(), WTF::ArrayBufferContents::kNotShared);
TestArrayBuffer* buffer = TestArrayBuffer::Create(contents);
v8::Local<v8::Object> associatedWrapper = buffer->AssociateWithWrapper(v8::Isolate::GetCurrent(), buffer->GetWrapperTypeInfo(), object);
......
......@@ -123,10 +123,26 @@ void* ArrayBufferContents::AllocateMemoryOrNull(size_t size,
return AllocateMemoryWithFlags(size, policy, base::PartitionAllocReturnNull);
}
// This method is used by V8's WebAssembly implementation to reserve a large
// amount of inaccessible address space. This is used to enforce memory safety
// in Wasm programs.
void* ArrayBufferContents::ReserveMemory(size_t size) {
void* const hint = nullptr;
const size_t align = 64 << 10; // Wasm page size
// TODO(crbug.com/735209): On Windows this commits all the memory, rather than
// just reserving it. This is very bad and should be fixed, but we don't use
// this feature on Windows at all yet.
return base::AllocPages(hint, size, align, base::PageInaccessible);
}
void ArrayBufferContents::FreeMemory(void* data) {
PartitionFreeGeneric(Partitions::ArrayBufferPartition(), data);
}
void ArrayBufferContents::ReleaseReservedMemory(void* data, size_t size) {
base::FreePages(data, size);
}
ArrayBufferContents::DataHandle ArrayBufferContents::CreateDataHandle(
size_t size,
InitializationPolicy policy) {
......@@ -145,7 +161,6 @@ ArrayBufferContents::DataHolder::~DataHolder() {
AdjustAmountOfExternalAllocatedMemory(
-static_cast<int64_t>(size_in_bytes_));
data_.reset();
size_in_bytes_ = 0;
is_shared_ = kNotShared;
}
......@@ -191,7 +206,7 @@ void ArrayBufferContents::DataHolder::CopyMemoryFrom(const DataHolder& source) {
return;
size_in_bytes_ = source.SizeInBytes();
memcpy(data_.get(), source.Data(), source.SizeInBytes());
memcpy(data_.Data(), source.Data(), source.SizeInBytes());
AdjustAmountOfExternalAllocatedMemory(size_in_bytes_);
}
......
......@@ -51,7 +51,91 @@ class WTF_EXPORT ArrayBufferContents {
// Most clients would want to use ArrayBufferContents::createData, which
// allocates memory and specifies the correct deleter.
using DataDeleter = void (*)(void* data);
using DataHandle = std::unique_ptr<void, DataDeleter>;
enum class AllocationKind { kNormal, kReservation };
class DataHandle {
WTF_MAKE_NONCOPYABLE(DataHandle);
public:
DataHandle(void* data, DataDeleter deleter)
: allocation_base_(data),
allocation_length_(0),
data_(data),
data_length_(0),
kind_(AllocationKind::kNormal),
deleter_(deleter) {}
DataHandle(void* allocation_base,
size_t allocation_length,
void* data,
size_t data_length,
AllocationKind kind,
DataDeleter deleter)
: allocation_base_(allocation_base),
allocation_length_(allocation_length),
data_(data),
data_length_(data_length),
kind_(kind),
deleter_(deleter) {
DCHECK(reinterpret_cast<uintptr_t>(allocation_base_) <=
reinterpret_cast<uintptr_t>(data_));
DCHECK(reinterpret_cast<uintptr_t>(data_) + data_length_ <=
reinterpret_cast<uintptr_t>(allocation_base_) +
allocation_length_);
}
// Move constructor
DataHandle(DataHandle&& other) { *this = std::move(other); }
~DataHandle() {
if (!allocation_base_)
return;
DCHECK(reinterpret_cast<uintptr_t>(allocation_base_) <=
reinterpret_cast<uintptr_t>(data_));
DCHECK(reinterpret_cast<uintptr_t>(data_) + data_length_ <=
reinterpret_cast<uintptr_t>(allocation_base_) +
allocation_length_);
switch (kind_) {
case AllocationKind::kNormal:
DCHECK(deleter_);
deleter_(data_);
return;
case AllocationKind::kReservation:
ReleaseReservedMemory(allocation_base_, allocation_length_);
return;
}
}
// Move operator
DataHandle& operator=(DataHandle&& other) {
allocation_base_ = other.allocation_base_;
allocation_length_ = other.allocation_length_;
data_ = other.data_;
data_length_ = other.data_length_;
kind_ = other.kind_;
deleter_ = other.deleter_;
other.allocation_base_ = nullptr;
return *this;
}
void* AllocationBase() const { return allocation_base_; }
size_t AllocationLength() const { return allocation_length_; }
void* Data() const { return data_; }
size_t DataLength() const { return data_length_; }
AllocationKind AllocationKind() const { return kind_; }
operator bool() const { return allocation_base_; }
private:
void* allocation_base_;
size_t allocation_length_;
void* data_;
size_t data_length_;
ArrayBufferContents::AllocationKind kind_;
DataDeleter deleter_;
};
enum InitializationPolicy { kZeroInitialize, kDontInitialize };
......@@ -93,7 +177,9 @@ class WTF_EXPORT ArrayBufferContents {
void CopyTo(ArrayBufferContents& other);
static void* AllocateMemoryOrNull(size_t, InitializationPolicy);
static void* ReserveMemory(size_t);
static void FreeMemory(void*);
static void ReleaseReservedMemory(void*, size_t);
static DataHandle CreateDataHandle(size_t, InitializationPolicy);
static void Initialize(
AdjustAmountOfExternalAllocatedMemoryFunction function) {
......@@ -132,8 +218,8 @@ class WTF_EXPORT ArrayBufferContents {
void Adopt(DataHandle, unsigned size_in_bytes, SharingType is_shared);
void CopyMemoryFrom(const DataHolder& source);
const void* Data() const { return data_.get(); }
void* Data() { return data_.get(); }
const void* Data() const { return data_.Data(); }
void* Data() { return data_.Data(); }
unsigned SizeInBytes() const { return size_in_bytes_; }
bool IsShared() const { return is_shared_ == kShared; }
......
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