v8/test/unittests/api/gc-callbacks-unittest.cc
Omer Katz 0cd0e4bb76 [heap] Implement SimulateFullSpace for PagedNewSpace
The existing version for paged spaces simply reset the freelist, which
doesn't work for tests that require actual objects in the space.
The version for new space also doesn't work because it assumes
everything after top is free space.

Fill the space with FixedArray by iterating over the freelist and
creating an object in place of each freelist entry.
This method actually fills the space, so that we can also use it to
force page promotion.

Bug: v8:12612
Change-Id: Ie0d73e846bbf688ea52030be29e0587b2f37ed4e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3823135
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Omer Katz <omerkatz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82437}
2022-08-12 12:55:52 +00:00

168 lines
5.9 KiB
C++

// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "test/unittests/heap/heap-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace {
namespace {
class GCCallbacksTest : public internal::TestWithHeapInternalsAndContext {
public:
static void PrologueCallbackAlloc(v8::Isolate* isolate, v8::GCType,
v8::GCCallbackFlags flags) {
v8::HandleScope scope(isolate);
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(current_test_->gc_callbacks_isolate_, isolate);
++current_test_->prologue_call_count_alloc_;
if (!v8::internal::FLAG_single_generation) {
// Simulate full heap to see if we will reenter this callback
current_test_->SimulateFullSpace(current_test_->heap()->new_space());
}
Local<Object> obj = Object::New(isolate);
CHECK(!obj.IsEmpty());
current_test_->PreciseCollectAllGarbage();
}
static void EpilogueCallbackAlloc(v8::Isolate* isolate, v8::GCType,
v8::GCCallbackFlags flags) {
v8::HandleScope scope(isolate);
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(current_test_->gc_callbacks_isolate_, isolate);
++current_test_->epilogue_call_count_alloc_;
if (!v8::internal::FLAG_single_generation) {
// Simulate full heap to see if we will reenter this callback
current_test_->SimulateFullSpace(current_test_->heap()->new_space());
}
Local<Object> obj = Object::New(isolate);
CHECK(!obj.IsEmpty());
current_test_->PreciseCollectAllGarbage();
}
static void PrologueCallback(v8::Isolate* isolate, v8::GCType,
v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(current_test_->gc_callbacks_isolate_, isolate);
++current_test_->prologue_call_count_;
}
static void EpilogueCallback(v8::Isolate* isolate, v8::GCType,
v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(current_test_->gc_callbacks_isolate_, isolate);
++current_test_->epilogue_call_count_;
}
static void PrologueCallbackSecond(v8::Isolate* isolate, v8::GCType,
v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(current_test_->gc_callbacks_isolate_, isolate);
++current_test_->prologue_call_count_second_;
}
static void EpilogueCallbackSecond(v8::Isolate* isolate, v8::GCType,
v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(current_test_->gc_callbacks_isolate_, isolate);
++current_test_->epilogue_call_count_second_;
}
static void PrologueCallbackNew(v8::Isolate* isolate, v8::GCType,
v8::GCCallbackFlags flags, void* data) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(current_test_->gc_callbacks_isolate_, isolate);
++*static_cast<int*>(data);
}
static void EpilogueCallbackNew(v8::Isolate* isolate, v8::GCType,
v8::GCCallbackFlags flags, void* data) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(current_test_->gc_callbacks_isolate_, isolate);
++*static_cast<int*>(data);
}
protected:
void SetUp() override {
internal::TestWithHeapInternalsAndContext::SetUp();
DCHECK_NULL(current_test_);
current_test_ = this;
}
void TearDown() override {
DCHECK_NOT_NULL(current_test_);
current_test_ = nullptr;
internal::TestWithHeapInternalsAndContext::TearDown();
}
static GCCallbacksTest* current_test_;
v8::Isolate* gc_callbacks_isolate_ = nullptr;
int prologue_call_count_ = 0;
int epilogue_call_count_ = 0;
int prologue_call_count_second_ = 0;
int epilogue_call_count_second_ = 0;
int prologue_call_count_alloc_ = 0;
int epilogue_call_count_alloc_ = 0;
};
GCCallbacksTest* GCCallbacksTest::current_test_ = nullptr;
} // namespace
TEST_F(GCCallbacksTest, GCCallbacks) {
// For SimulateFullSpace in PrologueCallbackAlloc and EpilogueCallbackAlloc.
i::FLAG_stress_concurrent_allocation = false;
v8::Isolate* isolate = context()->GetIsolate();
gc_callbacks_isolate_ = isolate;
isolate->AddGCPrologueCallback(PrologueCallback);
isolate->AddGCEpilogueCallback(EpilogueCallback);
CHECK_EQ(0, prologue_call_count_);
CHECK_EQ(0, epilogue_call_count_);
CollectAllGarbage();
CHECK_EQ(1, prologue_call_count_);
CHECK_EQ(1, epilogue_call_count_);
isolate->AddGCPrologueCallback(PrologueCallbackSecond);
isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
CollectAllGarbage();
CHECK_EQ(2, prologue_call_count_);
CHECK_EQ(2, epilogue_call_count_);
CHECK_EQ(1, prologue_call_count_second_);
CHECK_EQ(1, epilogue_call_count_second_);
isolate->RemoveGCPrologueCallback(PrologueCallback);
isolate->RemoveGCEpilogueCallback(EpilogueCallback);
CollectAllGarbage();
CHECK_EQ(2, prologue_call_count_);
CHECK_EQ(2, epilogue_call_count_);
CHECK_EQ(2, prologue_call_count_second_);
CHECK_EQ(2, epilogue_call_count_second_);
isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
CollectAllGarbage();
CHECK_EQ(2, prologue_call_count_);
CHECK_EQ(2, epilogue_call_count_);
CHECK_EQ(2, prologue_call_count_second_);
CHECK_EQ(2, epilogue_call_count_second_);
CHECK_EQ(0, prologue_call_count_alloc_);
CHECK_EQ(0, epilogue_call_count_alloc_);
isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
PreciseCollectAllGarbage();
CHECK_EQ(1, prologue_call_count_alloc_);
CHECK_EQ(1, epilogue_call_count_alloc_);
isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
}
} // namespace
} // namespace v8