176 lines
4.8 KiB
C++
176 lines
4.8 KiB
C++
// Copyright 2020 The PDFium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "fxjs/gc/heap.h"
|
|
|
|
#include <memory>
|
|
#include <set>
|
|
|
|
#include "testing/fxgc_unittest.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
#include "testing/v8_test_environment.h"
|
|
#include "third_party/base/containers/contains.h"
|
|
#include "v8/include/cppgc/allocation.h"
|
|
#include "v8/include/cppgc/persistent.h"
|
|
|
|
namespace {
|
|
|
|
class PseudoCollectible : public cppgc::GarbageCollected<PseudoCollectible> {
|
|
public:
|
|
static void ClearCounts() {
|
|
s_live_.clear();
|
|
s_dead_.clear();
|
|
}
|
|
static size_t LiveCount() { return s_live_.size(); }
|
|
static size_t DeadCount() { return s_dead_.size(); }
|
|
|
|
PseudoCollectible() { s_live_.insert(this); }
|
|
virtual ~PseudoCollectible() {
|
|
s_live_.erase(this);
|
|
s_dead_.insert(this);
|
|
}
|
|
|
|
bool IsLive() const { return pdfium::Contains(s_live_, this); }
|
|
|
|
virtual void Trace(cppgc::Visitor* visitor) const {}
|
|
|
|
private:
|
|
static std::set<const PseudoCollectible*> s_live_;
|
|
static std::set<const PseudoCollectible*> s_dead_;
|
|
};
|
|
|
|
std::set<const PseudoCollectible*> PseudoCollectible::s_live_;
|
|
std::set<const PseudoCollectible*> PseudoCollectible::s_dead_;
|
|
|
|
class CollectibleHolder {
|
|
public:
|
|
explicit CollectibleHolder(PseudoCollectible* holdee) : holdee_(holdee) {}
|
|
~CollectibleHolder() = default;
|
|
|
|
PseudoCollectible* holdee() const { return holdee_; }
|
|
|
|
private:
|
|
cppgc::Persistent<PseudoCollectible> holdee_;
|
|
};
|
|
|
|
class Bloater : public cppgc::GarbageCollected<Bloater> {
|
|
public:
|
|
void Trace(cppgc::Visitor* visitor) const {}
|
|
uint8_t bloat_[65536];
|
|
};
|
|
|
|
} // namespace
|
|
|
|
class HeapUnitTest : public FXGCUnitTest {
|
|
public:
|
|
HeapUnitTest() = default;
|
|
~HeapUnitTest() override = default;
|
|
|
|
// FXGCUnitTest:
|
|
void TearDown() override {
|
|
PseudoCollectible::ClearCounts();
|
|
FXGCUnitTest::TearDown();
|
|
}
|
|
};
|
|
|
|
TEST_F(HeapUnitTest, SeveralHeaps) {
|
|
FXGCScopedHeap heap1 = FXGC_CreateHeap();
|
|
EXPECT_TRUE(heap1);
|
|
|
|
FXGCScopedHeap heap2 = FXGC_CreateHeap();
|
|
EXPECT_TRUE(heap2);
|
|
|
|
FXGCScopedHeap heap3 = FXGC_CreateHeap();
|
|
EXPECT_TRUE(heap3);
|
|
|
|
// Test manually destroying the heap.
|
|
heap3.reset();
|
|
EXPECT_FALSE(heap3);
|
|
heap3.reset();
|
|
EXPECT_FALSE(heap3);
|
|
}
|
|
|
|
TEST_F(HeapUnitTest, NoReferences) {
|
|
FXGCScopedHeap heap1 = FXGC_CreateHeap();
|
|
ASSERT_TRUE(heap1);
|
|
{
|
|
auto holder = std::make_unique<CollectibleHolder>(
|
|
cppgc::MakeGarbageCollected<PseudoCollectible>(
|
|
heap1->GetAllocationHandle()));
|
|
|
|
EXPECT_TRUE(holder->holdee()->IsLive());
|
|
EXPECT_EQ(1u, PseudoCollectible::LiveCount());
|
|
EXPECT_EQ(0u, PseudoCollectible::DeadCount());
|
|
}
|
|
FXGC_ForceGarbageCollection(heap1.get());
|
|
EXPECT_EQ(0u, PseudoCollectible::LiveCount());
|
|
EXPECT_EQ(1u, PseudoCollectible::DeadCount());
|
|
}
|
|
|
|
TEST_F(HeapUnitTest, HasReferences) {
|
|
FXGCScopedHeap heap1 = FXGC_CreateHeap();
|
|
ASSERT_TRUE(heap1);
|
|
{
|
|
auto holder = std::make_unique<CollectibleHolder>(
|
|
cppgc::MakeGarbageCollected<PseudoCollectible>(
|
|
heap1->GetAllocationHandle()));
|
|
|
|
EXPECT_TRUE(holder->holdee()->IsLive());
|
|
EXPECT_EQ(1u, PseudoCollectible::LiveCount());
|
|
EXPECT_EQ(0u, PseudoCollectible::DeadCount());
|
|
|
|
FXGC_ForceGarbageCollection(heap1.get());
|
|
EXPECT_TRUE(holder->holdee()->IsLive());
|
|
EXPECT_EQ(1u, PseudoCollectible::LiveCount());
|
|
EXPECT_EQ(0u, PseudoCollectible::DeadCount());
|
|
}
|
|
}
|
|
|
|
// TODO(tsepez): enable when CPPGC fixes this segv.
|
|
TEST_F(HeapUnitTest, DISABLED_DeleteHeapHasReferences) {
|
|
FXGCScopedHeap heap1 = FXGC_CreateHeap();
|
|
ASSERT_TRUE(heap1);
|
|
{
|
|
auto holder = std::make_unique<CollectibleHolder>(
|
|
cppgc::MakeGarbageCollected<PseudoCollectible>(
|
|
heap1->GetAllocationHandle()));
|
|
|
|
EXPECT_TRUE(holder->holdee()->IsLive());
|
|
EXPECT_EQ(1u, PseudoCollectible::LiveCount());
|
|
EXPECT_EQ(0u, PseudoCollectible::DeadCount());
|
|
|
|
heap1.reset();
|
|
|
|
// Maybe someday magically nulled by heap destruction.
|
|
EXPECT_FALSE(holder->holdee());
|
|
EXPECT_EQ(1u, PseudoCollectible::LiveCount());
|
|
EXPECT_EQ(0u, PseudoCollectible::DeadCount());
|
|
}
|
|
}
|
|
|
|
TEST_F(HeapUnitTest, DeleteHeapNoReferences) {
|
|
FXGCScopedHeap heap1 = FXGC_CreateHeap();
|
|
ASSERT_TRUE(heap1);
|
|
{
|
|
auto holder = std::make_unique<CollectibleHolder>(
|
|
cppgc::MakeGarbageCollected<PseudoCollectible>(
|
|
heap1->GetAllocationHandle()));
|
|
|
|
EXPECT_TRUE(holder->holdee()->IsLive());
|
|
EXPECT_EQ(1u, PseudoCollectible::LiveCount());
|
|
EXPECT_EQ(0u, PseudoCollectible::DeadCount());
|
|
}
|
|
heap1.reset();
|
|
EXPECT_EQ(0u, PseudoCollectible::LiveCount());
|
|
EXPECT_EQ(1u, PseudoCollectible::DeadCount());
|
|
}
|
|
|
|
TEST_F(HeapUnitTest, Bloat) {
|
|
ASSERT_TRUE(heap());
|
|
for (int i = 0; i < 100000; ++i) {
|
|
cppgc::MakeGarbageCollected<Bloater>(heap()->GetAllocationHandle());
|
|
Pump(); // Do not force GC, must happen implicitly when space required.
|
|
}
|
|
}
|