Commit eaa730ff authored by Bill Budge's avatar Bill Budge Committed by Commit Bot

[ArrayBuffer] Give each SecurityOrigin a Partition for ArrayBuffers.

- Goes through SecurityOrigin's ArrayBuffer Partition for ArrayBuffers
  allocated from the V8 side.
- Reworks ArrayBufferContents to support multiple partitions for
  ArrayBuffers. Adds overload of AllocateMemoryOrNull to handle these
  allocations. Associates a PartitionRootGeneric with each allocation,
  storing a pointer just before the ArrayBuffer data.

Bug:chromium:799573

Change-Id: I712176c715d1fb2511d87892052ba9d2d8084336
Reviewed-on: https://chromium-review.googlesource.com/853120Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Commit-Queue: Bill Budge <bbudge@chromium.org>
Cr-Commit-Position: refs/heads/master@{#533921}
parent af540e8d
......@@ -541,18 +541,33 @@ static void InitializeV8Common(v8::Isolate* isolate) {
namespace {
// We try to give each SecurityOrigin its own array buffer partition. Use a
// SecurityOrigin pointer as an opaque key to tell ArrayBufferContents which
// partition to use.
void* GetPartitionKey() {
// TODO(bbudge): Pass in the isolate parameter from V8.
v8::Isolate* isolate = v8::Isolate::GetCurrent();
blink::ExecutionContext* context = CurrentExecutionContext(isolate);
// In some tests, there is no execution context.
if (!context)
return reinterpret_cast<void*>(isolate);
return reinterpret_cast<void*>(
const_cast<SecurityOrigin*>(context->GetSecurityOrigin()));
}
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
// Allocate() methods return null to signal allocation failure to V8, which
// should respond by throwing a RangeError, per
// http://www.ecma-international.org/ecma-262/6.0/#sec-createbytedatablock.
void* Allocate(size_t size) override {
return WTF::ArrayBufferContents::AllocateMemoryOrNull(
size, WTF::ArrayBufferContents::kZeroInitialize);
GetPartitionKey(), size, WTF::ArrayBufferContents::kZeroInitialize);
}
void* AllocateUninitialized(size_t size) override {
return WTF::ArrayBufferContents::AllocateMemoryOrNull(
size, WTF::ArrayBufferContents::kDontInitialize);
GetPartitionKey(), size, WTF::ArrayBufferContents::kDontInitialize);
}
void Free(void* data, size_t size) override {
......
......@@ -33,10 +33,43 @@
#endif
#include "base/allocator/partition_allocator/partition_alloc.h"
#include "platform/wtf/Assertions.h"
#include "platform/wtf/CheckedNumeric.h"
#include "platform/wtf/Vector.h"
#include "platform/wtf/allocator/Partitions.h"
namespace WTF {
namespace {
// Partitions are expensive; limit them so we don't run out of memory.
constexpr size_t kMaxPartitions = 4;
typedef std::unique_ptr<base::PartitionAllocatorGeneric> PartitionPtr;
// Use a vector of key/value pairs as a small map.
typedef std::pair<void*, PartitionPtr> PartitionEntry;
typedef WTF::Vector<PartitionEntry, kMaxPartitions> PartitionVector;
base::PartitionRootGeneric* FindOrCreatePartition(void* partition_key) {
DEFINE_THREAD_SAFE_STATIC_LOCAL(PartitionVector, partitions, ());
for (auto& entry : partitions) {
if (entry.first == partition_key) {
return entry.second->root();
}
}
if (partitions.size() < kMaxPartitions) {
partitions.emplace_back(std::make_pair(
partition_key, PartitionPtr(new base::PartitionAllocatorGeneric)));
auto& partition = partitions.back().second;
partition->init();
return partition->root();
}
// Use the global partition if we're at the limit.
// TODO(crbug.com/799573) Make sure the main frame doesn't use the global
// partition.
return Partitions::ArrayBufferPartition();
}
} // namespace
void ArrayBufferContents::DefaultAdjustAmountOfExternalAllocatedMemoryFunction(
int64_t diff) {
// Do nothing by default.
......@@ -108,20 +141,37 @@ void ArrayBufferContents::CopyTo(ArrayBufferContents& other) {
other.holder_->CopyMemoryFrom(*holder_);
}
void* ArrayBufferContents::AllocateMemoryWithFlags(size_t size,
InitializationPolicy policy,
int flags) {
void* data = PartitionAllocGenericFlags(
Partitions::ArrayBufferPartition(), flags, size,
void* ArrayBufferContents::AllocateMemoryWithFlags(
base::PartitionRootGeneric* partition_root,
size_t size,
InitializationPolicy policy,
int flags) {
// Allocate extra space for a partition pointer at the beginning.
size_t alloc_size = CheckAdd(size, sizeof(void*)).ValueOrDie();
void* base_ptr = PartitionAllocGenericFlags(
partition_root, flags, alloc_size,
WTF_HEAP_PROFILER_TYPE_NAME(ArrayBufferContents));
if (policy == kZeroInitialize && data)
if (!base_ptr)
return nullptr;
void** partition_root_ptr = reinterpret_cast<void**>(base_ptr);
*partition_root_ptr = partition_root;
void* data = reinterpret_cast<void*>(partition_root_ptr + 1);
if (policy == kZeroInitialize)
memset(data, '\0', size);
return data;
}
void* ArrayBufferContents::AllocateMemoryOrNull(size_t size,
InitializationPolicy policy) {
return AllocateMemoryWithFlags(size, policy, base::PartitionAllocReturnNull);
return AllocateMemoryWithFlags(Partitions::ArrayBufferPartition(), size,
policy, base::PartitionAllocReturnNull);
}
void* ArrayBufferContents::AllocateMemoryOrNull(void* partition_key,
size_t size,
InitializationPolicy policy) {
return AllocateMemoryWithFlags(FindOrCreatePartition(partition_key), size,
policy, base::PartitionAllocReturnNull);
}
// This method is used by V8's WebAssembly implementation to reserve a large
......@@ -152,7 +202,11 @@ void* ArrayBufferContents::ReserveMemory(size_t size) {
}
void ArrayBufferContents::FreeMemory(void* data) {
Partitions::ArrayBufferPartition()->Free(data);
// The partition pointer is just before |data|. See |AllocateMemoryWithFlags|.
base::PartitionRootGeneric** partition_root_ptr =
reinterpret_cast<base::PartitionRootGeneric**>(data) - 1;
void* base_ptr = reinterpret_cast<void*>(partition_root_ptr);
(*partition_root_ptr)->Free(base_ptr);
}
void ArrayBufferContents::ReleaseReservedMemory(void* data, size_t size) {
......
......@@ -35,6 +35,10 @@
#include "platform/wtf/WTF.h"
#include "platform/wtf/WTFExport.h"
namespace base {
struct PartitionRootGeneric;
} // namespace base
namespace WTF {
class WTF_EXPORT ArrayBufferContents {
......@@ -177,8 +181,9 @@ class WTF_EXPORT ArrayBufferContents {
void CopyTo(ArrayBufferContents& other);
static void* AllocateMemoryOrNull(size_t, InitializationPolicy);
static void* ReserveMemory(size_t);
static void* AllocateMemoryOrNull(void*, size_t, InitializationPolicy);
static void FreeMemory(void*);
static void* ReserveMemory(size_t);
static void ReleaseReservedMemory(void*, size_t);
static DataHandle CreateDataHandle(size_t, InitializationPolicy);
static void Initialize(
......@@ -200,7 +205,10 @@ class WTF_EXPORT ArrayBufferContents {
}
private:
static void* AllocateMemoryWithFlags(size_t, InitializationPolicy, int);
static void* AllocateMemoryWithFlags(base::PartitionRootGeneric*,
size_t,
InitializationPolicy,
int);
static void DefaultAdjustAmountOfExternalAllocatedMemoryFunction(
int64_t diff);
......
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