[heap] fix invocation of NearHeapLimitCallback

This patch makes sure that NearHeapLimitCallback can invoke
operations that trigger garbage collections. In addition
this adds code to make the tracers aware of NearHeapLimitCallback.

Bug: v8:12777
Change-Id: I959a23a3e0224ba536cb18b14933813e56fc5292
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3575468
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Joyee Cheung <joyee@igalia.com>
Cr-Commit-Position: refs/heads/main@{#79934}
This commit is contained in:
Joyee Cheung 2022-04-11 23:15:53 +08:00 committed by V8 LUCI CQ
parent 26d6f9ebcc
commit 4c29cf1b78
3 changed files with 60 additions and 0 deletions

View File

@ -4342,6 +4342,9 @@ void Heap::AutomaticallyRestoreInitialHeapLimit(double threshold_percent) {
bool Heap::InvokeNearHeapLimitCallback() {
if (near_heap_limit_callbacks_.size() > 0) {
AllowGarbageCollection allow_gc;
TRACE_GC(tracer(), GCTracer::Scope::HEAP_EXTERNAL_NEAR_HEAP_LIMIT);
VMState<EXTERNAL> callback_state(isolate());
HandleScope scope(isolate());
v8::NearHeapLimitCallback callback =
near_heap_limit_callbacks_.back().first;

View File

@ -527,6 +527,7 @@
F(HEAP_EPILOGUE_REDUCE_NEW_SPACE) \
F(HEAP_EPILOGUE_SAFEPOINT) \
F(HEAP_EXTERNAL_EPILOGUE) \
F(HEAP_EXTERNAL_NEAR_HEAP_LIMIT) \
F(HEAP_EXTERNAL_PROLOGUE) \
F(HEAP_EXTERNAL_WEAK_GLOBAL_HANDLES) \
F(HEAP_PROLOGUE) \

View File

@ -1272,6 +1272,62 @@ UNINITIALIZED_TEST(Regress10843) {
isolate->Dispose();
}
size_t near_heap_limit_invocation_count = 0;
size_t InvokeGCNearHeapLimitCallback(void* data, size_t current_heap_limit,
size_t initial_heap_limit) {
near_heap_limit_invocation_count++;
if (near_heap_limit_invocation_count > 1) {
// We are already in a GC triggered in this callback, raise the limit
// to avoid an OOM.
return current_heap_limit * 5;
}
DCHECK_EQ(near_heap_limit_invocation_count, 1);
// Operations that may cause GC (e.g. taking heap snapshots) in the
// near heap limit callback should not hit the AllowGarbageCollection
// assertion.
static_cast<v8::Isolate*>(data)->GetHeapProfiler()->TakeHeapSnapshot();
return current_heap_limit * 5;
}
UNINITIALIZED_TEST(Regress12777) {
v8::Isolate::CreateParams create_params;
create_params.constraints.set_max_old_generation_size_in_bytes(10 * i::MB);
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
isolate->AddNearHeapLimitCallback(InvokeGCNearHeapLimitCallback, isolate);
{
v8::Isolate::Scope isolate_scope(isolate);
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
// Allocate data to trigger the NearHeapLimitCallback.
HandleScope scope(i_isolate);
int length = 2 * i::MB / i::kTaggedSize;
std::vector<Handle<FixedArray>> arrays;
for (int i = 0; i < 5; i++) {
arrays.push_back(i_isolate->factory()->NewFixedArray(length));
}
CcTest::CollectAllGarbage(i_isolate);
for (int i = 0; i < 5; i++) {
arrays.push_back(i_isolate->factory()->NewFixedArray(length));
}
CcTest::CollectAllGarbage(i_isolate);
for (int i = 0; i < 5; i++) {
arrays.push_back(i_isolate->factory()->NewFixedArray(length));
}
// The work done above should trigger the heap limit callback at least
// twice to prove that the callback can raise the limit in the second
// or later calls to avoid an OOM.
CHECK_GE(near_heap_limit_invocation_count, 2);
}
isolate->GetHeapProfiler()->DeleteAllHeapSnapshots();
isolate->Dispose();
}
#ifndef V8_LITE_MODE
TEST(TestOptimizeAfterBytecodeFlushingCandidate) {