0cd0e4bb76
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}
168 lines
5.9 KiB
C++
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
|