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,
void* Heap::AllocateExternalBackingStore(
const std::function<void*(size_t)>& allocate, size_t byte_length) {
size_t new_space_backing_store_bytes =
new_space()->ExternalBackingStoreBytes();
if (new_space_backing_store_bytes >= 2 * kMaxSemiSpaceSize &&
new_space_backing_store_bytes >= byte_length) {
// Performing a young generation GC amortizes over the allocated backing
// store bytes and may free enough external bytes for this allocation.
CollectGarbage(NEW_SPACE, GarbageCollectionReason::kExternalMemoryPressure);
if (!always_allocate()) {
size_t new_space_backing_store_bytes =
new_space()->ExternalBackingStoreBytes();
if (new_space_backing_store_bytes >= 2 * kMaxSemiSpaceSize &&
new_space_backing_store_bytes >= byte_length) {
// Performing a young generation GC amortizes over the allocated backing
// 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
// the current external backing store counters.
void* result = allocate(byte_length);
if (result) return result;
for (int i = 0; i < 2; i++) {
CollectGarbage(OLD_SPACE, GarbageCollectionReason::kExternalMemoryPressure);
result = allocate(byte_length);
if (result) return result;
if (!always_allocate()) {
for (int i = 0; i < 2; i++) {
CollectGarbage(OLD_SPACE,
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);
}
......
......@@ -667,6 +667,7 @@ bool Deserializer::ReadData(TSlot current, TSlot limit,
}
case kOffHeapBackingStore: {
AlwaysAllocateScope scope(isolate->heap());
int byte_length = source_.GetInt();
std::unique_ptr<BackingStore> backing_store =
BackingStore::Allocate(isolate, byte_length, SharedFlag::kNotShared,
......
......@@ -907,7 +907,8 @@ void TestInt32Expectations(const Int32Expectations& expectations) {
void TypedArrayTestHelper(
const char* code, const Int32Expectations& expectations,
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();
i::FLAG_allow_natives_syntax = true;
DisableEmbeddedBlobRefcounting();
......@@ -933,7 +934,8 @@ void TypedArrayTestHelper(
ReadOnlyHeap::ClearSharedHeapForTest();
v8::Isolate::CreateParams create_params;
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::Scope i_scope(isolate);
......@@ -1029,6 +1031,46 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobDataView) {
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) {
const char* code =
"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