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) { ...@@ -541,18 +541,33 @@ static void InitializeV8Common(v8::Isolate* isolate) {
namespace { 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 { class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
// Allocate() methods return null to signal allocation failure to V8, which // Allocate() methods return null to signal allocation failure to V8, which
// should respond by throwing a RangeError, per // should respond by throwing a RangeError, per
// http://www.ecma-international.org/ecma-262/6.0/#sec-createbytedatablock. // http://www.ecma-international.org/ecma-262/6.0/#sec-createbytedatablock.
void* Allocate(size_t size) override { void* Allocate(size_t size) override {
return WTF::ArrayBufferContents::AllocateMemoryOrNull( return WTF::ArrayBufferContents::AllocateMemoryOrNull(
size, WTF::ArrayBufferContents::kZeroInitialize); GetPartitionKey(), size, WTF::ArrayBufferContents::kZeroInitialize);
} }
void* AllocateUninitialized(size_t size) override { void* AllocateUninitialized(size_t size) override {
return WTF::ArrayBufferContents::AllocateMemoryOrNull( return WTF::ArrayBufferContents::AllocateMemoryOrNull(
size, WTF::ArrayBufferContents::kDontInitialize); GetPartitionKey(), size, WTF::ArrayBufferContents::kDontInitialize);
} }
void Free(void* data, size_t size) override { void Free(void* data, size_t size) override {
......
...@@ -33,10 +33,43 @@ ...@@ -33,10 +33,43 @@
#endif #endif
#include "base/allocator/partition_allocator/partition_alloc.h" #include "base/allocator/partition_allocator/partition_alloc.h"
#include "platform/wtf/Assertions.h" #include "platform/wtf/Assertions.h"
#include "platform/wtf/CheckedNumeric.h"
#include "platform/wtf/Vector.h"
#include "platform/wtf/allocator/Partitions.h" #include "platform/wtf/allocator/Partitions.h"
namespace WTF { 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( void ArrayBufferContents::DefaultAdjustAmountOfExternalAllocatedMemoryFunction(
int64_t diff) { int64_t diff) {
// Do nothing by default. // Do nothing by default.
...@@ -108,20 +141,37 @@ void ArrayBufferContents::CopyTo(ArrayBufferContents& other) { ...@@ -108,20 +141,37 @@ void ArrayBufferContents::CopyTo(ArrayBufferContents& other) {
other.holder_->CopyMemoryFrom(*holder_); other.holder_->CopyMemoryFrom(*holder_);
} }
void* ArrayBufferContents::AllocateMemoryWithFlags(size_t size, void* ArrayBufferContents::AllocateMemoryWithFlags(
base::PartitionRootGeneric* partition_root,
size_t size,
InitializationPolicy policy, InitializationPolicy policy,
int flags) { int flags) {
void* data = PartitionAllocGenericFlags( // Allocate extra space for a partition pointer at the beginning.
Partitions::ArrayBufferPartition(), flags, size, size_t alloc_size = CheckAdd(size, sizeof(void*)).ValueOrDie();
void* base_ptr = PartitionAllocGenericFlags(
partition_root, flags, alloc_size,
WTF_HEAP_PROFILER_TYPE_NAME(ArrayBufferContents)); 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); memset(data, '\0', size);
return data; return data;
} }
void* ArrayBufferContents::AllocateMemoryOrNull(size_t size, void* ArrayBufferContents::AllocateMemoryOrNull(size_t size,
InitializationPolicy policy) { 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 // This method is used by V8's WebAssembly implementation to reserve a large
...@@ -152,7 +202,11 @@ void* ArrayBufferContents::ReserveMemory(size_t size) { ...@@ -152,7 +202,11 @@ void* ArrayBufferContents::ReserveMemory(size_t size) {
} }
void ArrayBufferContents::FreeMemory(void* data) { 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) { void ArrayBufferContents::ReleaseReservedMemory(void* data, size_t size) {
......
...@@ -35,6 +35,10 @@ ...@@ -35,6 +35,10 @@
#include "platform/wtf/WTF.h" #include "platform/wtf/WTF.h"
#include "platform/wtf/WTFExport.h" #include "platform/wtf/WTFExport.h"
namespace base {
struct PartitionRootGeneric;
} // namespace base
namespace WTF { namespace WTF {
class WTF_EXPORT ArrayBufferContents { class WTF_EXPORT ArrayBufferContents {
...@@ -177,8 +181,9 @@ class WTF_EXPORT ArrayBufferContents { ...@@ -177,8 +181,9 @@ class WTF_EXPORT ArrayBufferContents {
void CopyTo(ArrayBufferContents& other); void CopyTo(ArrayBufferContents& other);
static void* AllocateMemoryOrNull(size_t, InitializationPolicy); static void* AllocateMemoryOrNull(size_t, InitializationPolicy);
static void* ReserveMemory(size_t); static void* AllocateMemoryOrNull(void*, size_t, InitializationPolicy);
static void FreeMemory(void*); static void FreeMemory(void*);
static void* ReserveMemory(size_t);
static void ReleaseReservedMemory(void*, size_t); static void ReleaseReservedMemory(void*, size_t);
static DataHandle CreateDataHandle(size_t, InitializationPolicy); static DataHandle CreateDataHandle(size_t, InitializationPolicy);
static void Initialize( static void Initialize(
...@@ -200,7 +205,10 @@ class WTF_EXPORT ArrayBufferContents { ...@@ -200,7 +205,10 @@ class WTF_EXPORT ArrayBufferContents {
} }
private: private:
static void* AllocateMemoryWithFlags(size_t, InitializationPolicy, int); static void* AllocateMemoryWithFlags(base::PartitionRootGeneric*,
size_t,
InitializationPolicy,
int);
static void DefaultAdjustAmountOfExternalAllocatedMemoryFunction( static void DefaultAdjustAmountOfExternalAllocatedMemoryFunction(
int64_t diff); 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