xref: /aosp_15_r20/external/pdfium/fxjs/gc/heap_unittest.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2020 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "fxjs/gc/heap.h"
6 
7 #include <memory>
8 #include <set>
9 
10 #include "testing/fxgc_unittest.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "testing/v8_test_environment.h"
13 #include "third_party/base/containers/contains.h"
14 #include "v8/include/cppgc/allocation.h"
15 #include "v8/include/cppgc/persistent.h"
16 
17 namespace {
18 
19 class PseudoCollectible : public cppgc::GarbageCollected<PseudoCollectible> {
20  public:
ClearCounts()21   static void ClearCounts() {
22     s_live_.clear();
23     s_dead_.clear();
24   }
LiveCount()25   static size_t LiveCount() { return s_live_.size(); }
DeadCount()26   static size_t DeadCount() { return s_dead_.size(); }
27 
PseudoCollectible()28   PseudoCollectible() { s_live_.insert(this); }
~PseudoCollectible()29   virtual ~PseudoCollectible() {
30     s_live_.erase(this);
31     s_dead_.insert(this);
32   }
33 
IsLive() const34   bool IsLive() const { return pdfium::Contains(s_live_, this); }
35 
Trace(cppgc::Visitor * visitor) const36   virtual void Trace(cppgc::Visitor* visitor) const {}
37 
38  private:
39   static std::set<const PseudoCollectible*> s_live_;
40   static std::set<const PseudoCollectible*> s_dead_;
41 };
42 
43 std::set<const PseudoCollectible*> PseudoCollectible::s_live_;
44 std::set<const PseudoCollectible*> PseudoCollectible::s_dead_;
45 
46 class CollectibleHolder {
47  public:
CollectibleHolder(PseudoCollectible * holdee)48   explicit CollectibleHolder(PseudoCollectible* holdee) : holdee_(holdee) {}
49   ~CollectibleHolder() = default;
50 
holdee() const51   PseudoCollectible* holdee() const { return holdee_; }
52 
53  private:
54   cppgc::Persistent<PseudoCollectible> holdee_;
55 };
56 
57 class Bloater : public cppgc::GarbageCollected<Bloater> {
58  public:
Trace(cppgc::Visitor * visitor) const59   void Trace(cppgc::Visitor* visitor) const {}
60   uint8_t bloat_[65536];
61 };
62 
63 }  // namespace
64 
65 class HeapUnitTest : public FXGCUnitTest {
66  public:
67   HeapUnitTest() = default;
68   ~HeapUnitTest() override = default;
69 
70   // FXGCUnitTest:
TearDown()71   void TearDown() override {
72     PseudoCollectible::ClearCounts();
73     FXGCUnitTest::TearDown();
74   }
75 };
76 
TEST_F(HeapUnitTest,SeveralHeaps)77 TEST_F(HeapUnitTest, SeveralHeaps) {
78   FXGCScopedHeap heap1 = FXGC_CreateHeap();
79   EXPECT_TRUE(heap1);
80 
81   FXGCScopedHeap heap2 = FXGC_CreateHeap();
82   EXPECT_TRUE(heap2);
83 
84   FXGCScopedHeap heap3 = FXGC_CreateHeap();
85   EXPECT_TRUE(heap3);
86 
87   // Test manually destroying the heap.
88   heap3.reset();
89   EXPECT_FALSE(heap3);
90   heap3.reset();
91   EXPECT_FALSE(heap3);
92 }
93 
TEST_F(HeapUnitTest,NoReferences)94 TEST_F(HeapUnitTest, NoReferences) {
95   FXGCScopedHeap heap1 = FXGC_CreateHeap();
96   ASSERT_TRUE(heap1);
97   {
98     auto holder = std::make_unique<CollectibleHolder>(
99         cppgc::MakeGarbageCollected<PseudoCollectible>(
100             heap1->GetAllocationHandle()));
101 
102     EXPECT_TRUE(holder->holdee()->IsLive());
103     EXPECT_EQ(1u, PseudoCollectible::LiveCount());
104     EXPECT_EQ(0u, PseudoCollectible::DeadCount());
105   }
106   FXGC_ForceGarbageCollection(heap1.get());
107   EXPECT_EQ(0u, PseudoCollectible::LiveCount());
108   EXPECT_EQ(1u, PseudoCollectible::DeadCount());
109 }
110 
TEST_F(HeapUnitTest,HasReferences)111 TEST_F(HeapUnitTest, HasReferences) {
112   FXGCScopedHeap heap1 = FXGC_CreateHeap();
113   ASSERT_TRUE(heap1);
114   {
115     auto holder = std::make_unique<CollectibleHolder>(
116         cppgc::MakeGarbageCollected<PseudoCollectible>(
117             heap1->GetAllocationHandle()));
118 
119     EXPECT_TRUE(holder->holdee()->IsLive());
120     EXPECT_EQ(1u, PseudoCollectible::LiveCount());
121     EXPECT_EQ(0u, PseudoCollectible::DeadCount());
122 
123     FXGC_ForceGarbageCollection(heap1.get());
124     EXPECT_TRUE(holder->holdee()->IsLive());
125     EXPECT_EQ(1u, PseudoCollectible::LiveCount());
126     EXPECT_EQ(0u, PseudoCollectible::DeadCount());
127   }
128 }
129 
130 // TODO(tsepez): enable when CPPGC fixes this segv.
TEST_F(HeapUnitTest,DISABLED_DeleteHeapHasReferences)131 TEST_F(HeapUnitTest, DISABLED_DeleteHeapHasReferences) {
132   FXGCScopedHeap heap1 = FXGC_CreateHeap();
133   ASSERT_TRUE(heap1);
134   {
135     auto holder = std::make_unique<CollectibleHolder>(
136         cppgc::MakeGarbageCollected<PseudoCollectible>(
137             heap1->GetAllocationHandle()));
138 
139     EXPECT_TRUE(holder->holdee()->IsLive());
140     EXPECT_EQ(1u, PseudoCollectible::LiveCount());
141     EXPECT_EQ(0u, PseudoCollectible::DeadCount());
142 
143     heap1.reset();
144 
145     // Maybe someday magically nulled by heap destruction.
146     EXPECT_FALSE(holder->holdee());
147     EXPECT_EQ(1u, PseudoCollectible::LiveCount());
148     EXPECT_EQ(0u, PseudoCollectible::DeadCount());
149   }
150 }
151 
TEST_F(HeapUnitTest,DeleteHeapNoReferences)152 TEST_F(HeapUnitTest, DeleteHeapNoReferences) {
153   FXGCScopedHeap heap1 = FXGC_CreateHeap();
154   ASSERT_TRUE(heap1);
155   {
156     auto holder = std::make_unique<CollectibleHolder>(
157         cppgc::MakeGarbageCollected<PseudoCollectible>(
158             heap1->GetAllocationHandle()));
159 
160     EXPECT_TRUE(holder->holdee()->IsLive());
161     EXPECT_EQ(1u, PseudoCollectible::LiveCount());
162     EXPECT_EQ(0u, PseudoCollectible::DeadCount());
163   }
164   heap1.reset();
165   EXPECT_EQ(0u, PseudoCollectible::LiveCount());
166   EXPECT_EQ(1u, PseudoCollectible::DeadCount());
167 }
168 
TEST_F(HeapUnitTest,Bloat)169 TEST_F(HeapUnitTest, Bloat) {
170   ASSERT_TRUE(heap());
171   for (int i = 0; i < 100000; ++i) {
172     cppgc::MakeGarbageCollected<Bloater>(heap()->GetAllocationHandle());
173     Pump();  // Do not force GC, must happen implicitly when space required.
174   }
175 }
176