Perform more cleanup in FXGCScopedHeap destruction.
Then enable the test that this new cleanup allows to pass.
We respect the following constraints:
-- Heaps will not invoke finalizers (dtors) on any object -- either
alive or dead -- when the heap is destroyed.
-- Running a full GC before destroying a heap will ensure that
finalizers are applied to all dead objects.
-- Non-NULL Persistents can not outlive the heap containing the (live)
object to which they refer.
-- Heaps can't pump their own event loops to clear any pending tasks
because they don't know the specific implementation of the message
loop nor can they be permitted to dispatch other non-heap related
messages which might also be pending on said loop.
Change-Id: I2ae6a4b3c48bb337a10890799c410f2667083c30
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/71110
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fxjs/gc/heap.cpp b/fxjs/gc/heap.cpp
index 9dade5c..3c729c7 100644
--- a/fxjs/gc/heap.cpp
+++ b/fxjs/gc/heap.cpp
@@ -73,5 +73,8 @@
ASSERT(heap);
ASSERT(g_platform_ref_count > 0);
--g_platform_ref_count;
+
+ heap->ForceGarbageCollectionSlow("FXGCHeapDeleter", "FinalGCBeforeDelete",
+ cppgc::Heap::StackState::kNoHeapPointers);
delete heap;
}
diff --git a/fxjs/gc/heap_embeddertest.cpp b/fxjs/gc/heap_embeddertest.cpp
index 90b45d2..b7cac35 100644
--- a/fxjs/gc/heap_embeddertest.cpp
+++ b/fxjs/gc/heap_embeddertest.cpp
@@ -7,6 +7,7 @@
#include <memory>
#include <set>
+#include "core/fxcrt/autorestorer.h"
#include "testing/gced_embeddertest.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/base/stl_util.h"
@@ -19,10 +20,9 @@
public:
static cppgc::Persistent<PseudoCollectible> s_persistent_;
- static void Clear() {
+ static void ClearCounts() {
s_live_.clear();
s_dead_.clear();
- s_persistent_ = nullptr;
}
static size_t LiveCount() { return s_live_.size(); }
static size_t DeadCount() { return s_dead_.size(); }
@@ -48,7 +48,13 @@
} // namespace
-class HeapEmbedderTest : public GCedEmbedderTest {};
+class HeapEmbedderTest : public GCedEmbedderTest {
+ public:
+ void TearDown() override {
+ PseudoCollectible::ClearCounts();
+ GCedEmbedderTest::TearDown();
+ }
+};
TEST_F(HeapEmbedderTest, SeveralHeaps) {
FXGCScopedHeap heap1 = FXGC_CreateHeap();
@@ -70,79 +76,91 @@
TEST_F(HeapEmbedderTest, NoReferences) {
FXGCScopedHeap heap1 = FXGC_CreateHeap();
ASSERT_TRUE(heap1);
+ {
+ ASSERT_FALSE(PseudoCollectible::s_persistent_);
+ AutoRestorer<cppgc::Persistent<PseudoCollectible>> restorer(
+ &PseudoCollectible::s_persistent_);
- PseudoCollectible::s_persistent_ =
- cppgc::MakeGarbageCollected<PseudoCollectible>(
- heap1->GetAllocationHandle());
- EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
- EXPECT_EQ(1u, PseudoCollectible::LiveCount());
- EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+ PseudoCollectible::s_persistent_ =
+ cppgc::MakeGarbageCollected<PseudoCollectible>(
+ heap1->GetAllocationHandle());
- PseudoCollectible::s_persistent_ = nullptr;
+ EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
+ EXPECT_EQ(1u, PseudoCollectible::LiveCount());
+ EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+ }
heap1->ForceGarbageCollectionSlow("NoReferences", "test",
cppgc::Heap::StackState::kNoHeapPointers);
- PumpPlatformMessageLoop();
EXPECT_EQ(0u, PseudoCollectible::LiveCount());
EXPECT_EQ(1u, PseudoCollectible::DeadCount());
- PseudoCollectible::Clear();
}
TEST_F(HeapEmbedderTest, HasReferences) {
FXGCScopedHeap heap1 = FXGC_CreateHeap();
ASSERT_TRUE(heap1);
+ {
+ ASSERT_FALSE(PseudoCollectible::s_persistent_);
+ AutoRestorer<cppgc::Persistent<PseudoCollectible>> restorer(
+ &PseudoCollectible::s_persistent_);
- PseudoCollectible::s_persistent_ =
- cppgc::MakeGarbageCollected<PseudoCollectible>(
- heap1->GetAllocationHandle());
- EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
- EXPECT_EQ(1u, PseudoCollectible::LiveCount());
- EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+ PseudoCollectible::s_persistent_ =
+ cppgc::MakeGarbageCollected<PseudoCollectible>(
+ heap1->GetAllocationHandle());
- heap1->ForceGarbageCollectionSlow("HasReferences", "test",
- cppgc::Heap::StackState::kNoHeapPointers);
- PumpPlatformMessageLoop();
- EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
- EXPECT_EQ(1u, PseudoCollectible::LiveCount());
- EXPECT_EQ(0u, PseudoCollectible::DeadCount());
- PseudoCollectible::Clear();
+ EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
+ EXPECT_EQ(1u, PseudoCollectible::LiveCount());
+ EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+
+ heap1->ForceGarbageCollectionSlow("HasReferences", "test",
+ cppgc::Heap::StackState::kNoHeapPointers);
+
+ EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
+ EXPECT_EQ(1u, PseudoCollectible::LiveCount());
+ EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+ }
}
// TODO(tsepez): enable when CPPGC fixes this segv.
TEST_F(HeapEmbedderTest, DISABLED_DeleteHeapHasReferences) {
FXGCScopedHeap heap1 = FXGC_CreateHeap();
ASSERT_TRUE(heap1);
+ {
+ ASSERT_FALSE(PseudoCollectible::s_persistent_);
+ AutoRestorer<cppgc::Persistent<PseudoCollectible>> restorer(
+ &PseudoCollectible::s_persistent_);
- PseudoCollectible::s_persistent_ =
- cppgc::MakeGarbageCollected<PseudoCollectible>(
- heap1->GetAllocationHandle());
- EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
- EXPECT_EQ(1u, PseudoCollectible::LiveCount());
- EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+ PseudoCollectible::s_persistent_ =
+ cppgc::MakeGarbageCollected<PseudoCollectible>(
+ heap1->GetAllocationHandle());
- heap1.reset();
- PumpPlatformMessageLoop();
- EXPECT_FALSE(PseudoCollectible::s_persistent_);
- EXPECT_EQ(1u, PseudoCollectible::LiveCount());
- EXPECT_EQ(1u, PseudoCollectible::DeadCount());
- PseudoCollectible::Clear();
+ EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
+ EXPECT_EQ(1u, PseudoCollectible::LiveCount());
+ EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+
+ heap1.reset();
+ EXPECT_FALSE(PseudoCollectible::s_persistent_);
+ EXPECT_EQ(1u, PseudoCollectible::LiveCount());
+ EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+ }
}
-// TODO(tsepez): enable when CPPGC cleans this up.
-TEST_F(HeapEmbedderTest, DISABLED_DeleteHeapNoReferences) {
+TEST_F(HeapEmbedderTest, DeleteHeapNoReferences) {
FXGCScopedHeap heap1 = FXGC_CreateHeap();
ASSERT_TRUE(heap1);
+ {
+ ASSERT_FALSE(PseudoCollectible::s_persistent_);
+ AutoRestorer<cppgc::Persistent<PseudoCollectible>> restorer(
+ &PseudoCollectible::s_persistent_);
- PseudoCollectible::s_persistent_ =
- cppgc::MakeGarbageCollected<PseudoCollectible>(
- heap1->GetAllocationHandle());
- EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
- EXPECT_EQ(1u, PseudoCollectible::LiveCount());
- EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+ PseudoCollectible::s_persistent_ =
+ cppgc::MakeGarbageCollected<PseudoCollectible>(
+ heap1->GetAllocationHandle());
- PseudoCollectible::s_persistent_ = nullptr;
+ EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
+ EXPECT_EQ(1u, PseudoCollectible::LiveCount());
+ EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+ }
heap1.reset();
- PumpPlatformMessageLoop();
- EXPECT_EQ(1u, PseudoCollectible::LiveCount());
+ EXPECT_EQ(0u, PseudoCollectible::LiveCount());
EXPECT_EQ(1u, PseudoCollectible::DeadCount());
- PseudoCollectible::Clear();
}