Commit c371f9de authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

[snapshot] Use AlwaysAllocateScope for ArrayBuffer backing stores.

This also changes Heap::AllocateExternalBackingStore to avoid GC
inside AlwaysAllocateScope.

Bug: chromium:1042566
Change-Id: Ifa8fe8227af2d6492dbb4f9c52f43754d44926fb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2060295
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66298}
parent de17316a
...@@ -2846,25 +2846,32 @@ HeapObject Heap::AlignWithFiller(HeapObject object, int object_size, ...@@ -2846,25 +2846,32 @@ HeapObject Heap::AlignWithFiller(HeapObject object, int object_size,
void* Heap::AllocateExternalBackingStore( void* Heap::AllocateExternalBackingStore(
const std::function<void*(size_t)>& allocate, size_t byte_length) { const std::function<void*(size_t)>& allocate, size_t byte_length) {
size_t new_space_backing_store_bytes = if (!always_allocate()) {
new_space()->ExternalBackingStoreBytes(); size_t new_space_backing_store_bytes =
if (new_space_backing_store_bytes >= 2 * kMaxSemiSpaceSize && new_space()->ExternalBackingStoreBytes();
new_space_backing_store_bytes >= byte_length) { if (new_space_backing_store_bytes >= 2 * kMaxSemiSpaceSize &&
// Performing a young generation GC amortizes over the allocated backing new_space_backing_store_bytes >= byte_length) {
// store bytes and may free enough external bytes for this allocation. // Performing a young generation GC amortizes over the allocated backing
CollectGarbage(NEW_SPACE, GarbageCollectionReason::kExternalMemoryPressure); // store bytes and may free enough external bytes for this allocation.
CollectGarbage(NEW_SPACE,
GarbageCollectionReason::kExternalMemoryPressure);
}
} }
// TODO(ulan): Perform GCs proactively based on the byte_length and // TODO(ulan): Perform GCs proactively based on the byte_length and
// the current external backing store counters. // the current external backing store counters.
void* result = allocate(byte_length); void* result = allocate(byte_length);
if (result) return result; if (result) return result;
for (int i = 0; i < 2; i++) { if (!always_allocate()) {
CollectGarbage(OLD_SPACE, GarbageCollectionReason::kExternalMemoryPressure); for (int i = 0; i < 2; i++) {
result = allocate(byte_length); CollectGarbage(OLD_SPACE,
if (result) return result; GarbageCollectionReason::kExternalMemoryPressure);
result = allocate(byte_length);
if (result) return result;
}
isolate()->counters()->gc_last_resort_from_handles()->Increment();
CollectAllAvailableGarbage(
GarbageCollectionReason::kExternalMemoryPressure);
} }
isolate()->counters()->gc_last_resort_from_handles()->Increment();
CollectAllAvailableGarbage(GarbageCollectionReason::kExternalMemoryPressure);
return allocate(byte_length); return allocate(byte_length);
} }
......
...@@ -667,6 +667,7 @@ bool Deserializer::ReadData(TSlot current, TSlot limit, ...@@ -667,6 +667,7 @@ bool Deserializer::ReadData(TSlot current, TSlot limit,
} }
case kOffHeapBackingStore: { case kOffHeapBackingStore: {
AlwaysAllocateScope scope(isolate->heap());
int byte_length = source_.GetInt(); int byte_length = source_.GetInt();
std::unique_ptr<BackingStore> backing_store = std::unique_ptr<BackingStore> backing_store =
BackingStore::Allocate(isolate, byte_length, SharedFlag::kNotShared, BackingStore::Allocate(isolate, byte_length, SharedFlag::kNotShared,
......
...@@ -907,7 +907,8 @@ void TestInt32Expectations(const Int32Expectations& expectations) { ...@@ -907,7 +907,8 @@ void TestInt32Expectations(const Int32Expectations& expectations) {
void TypedArrayTestHelper( void TypedArrayTestHelper(
const char* code, const Int32Expectations& expectations, const char* code, const Int32Expectations& expectations,
const char* code_to_run_after_restore = nullptr, const char* code_to_run_after_restore = nullptr,
const Int32Expectations& after_restore_expectations = Int32Expectations()) { const Int32Expectations& after_restore_expectations = Int32Expectations(),
v8::ArrayBuffer::Allocator* allocator = nullptr) {
DisableAlwaysOpt(); DisableAlwaysOpt();
i::FLAG_allow_natives_syntax = true; i::FLAG_allow_natives_syntax = true;
DisableEmbeddedBlobRefcounting(); DisableEmbeddedBlobRefcounting();
...@@ -933,7 +934,8 @@ void TypedArrayTestHelper( ...@@ -933,7 +934,8 @@ void TypedArrayTestHelper(
ReadOnlyHeap::ClearSharedHeapForTest(); ReadOnlyHeap::ClearSharedHeapForTest();
v8::Isolate::CreateParams create_params; v8::Isolate::CreateParams create_params;
create_params.snapshot_blob = &blob; create_params.snapshot_blob = &blob;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); create_params.array_buffer_allocator =
allocator != nullptr ? allocator : CcTest::array_buffer_allocator();
v8::Isolate* isolate = TestSerializer::NewIsolate(create_params); v8::Isolate* isolate = TestSerializer::NewIsolate(create_params);
{ {
v8::Isolate::Scope i_scope(isolate); v8::Isolate::Scope i_scope(isolate);
...@@ -1029,6 +1031,46 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobDataView) { ...@@ -1029,6 +1031,46 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobDataView) {
TypedArrayTestHelper(code, expectations); TypedArrayTestHelper(code, expectations);
} }
namespace {
class AlternatingArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
AlternatingArrayBufferAllocator()
: allocation_fails_(false),
allocator_(v8::ArrayBuffer::Allocator::NewDefaultAllocator()) {}
~AlternatingArrayBufferAllocator() { delete allocator_; }
void* Allocate(size_t length) override {
allocation_fails_ = !allocation_fails_;
if (allocation_fails_) return nullptr;
return allocator_->Allocate(length);
}
void* AllocateUninitialized(size_t length) override {
return this->Allocate(length);
}
void Free(void* data, size_t size) override { allocator_->Free(data, size); }
void* Reallocate(void* data, size_t old_length, size_t new_length) override {
return allocator_->Reallocate(data, old_length, new_length);
}
private:
bool allocation_fails_;
v8::ArrayBuffer::Allocator* allocator_;
};
} // anonymous namespace
UNINITIALIZED_TEST(CustomSnapshotManyArrayBuffers) {
const char* code =
"var buffers = [];"
"for (let i = 0; i < 70; i++) buffers.push(new Uint8Array(1000));";
Int32Expectations expectations = {std::make_tuple("buffers.length", 70)};
std::unique_ptr<v8::ArrayBuffer::Allocator> allocator(
new AlternatingArrayBufferAllocator());
TypedArrayTestHelper(code, expectations, nullptr, Int32Expectations(),
allocator.get());
}
UNINITIALIZED_TEST(CustomSnapshotDataBlobDetachedArrayBuffer) { UNINITIALIZED_TEST(CustomSnapshotDataBlobDetachedArrayBuffer) {
const char* code = const char* code =
"var x = new Int16Array([12, 24, 48]);" "var x = new Int16Array([12, 24, 48]);"
......
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