Add Oilpan cppgc object allocation tests.

Creates an object and tracks that it is destroyed by GC.

Change-Id: I573787d0e413a40d2b0816f3bb2b93c5b1bdd6a9
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/70570
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fxjs/gc/heap_embeddertest.cpp b/fxjs/gc/heap_embeddertest.cpp
index 2696a91..381bd13 100644
--- a/fxjs/gc/heap_embeddertest.cpp
+++ b/fxjs/gc/heap_embeddertest.cpp
@@ -5,11 +5,82 @@
 #include "fxjs/gc/heap.h"
 
 #include <memory>
+#include <set>
 
 #include "testing/embedder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/base/stl_util.h"
+#include "v8/include/cppgc/allocation.h"
+#include "v8/include/cppgc/persistent.h"
+#include "v8/include/v8.h"
 
-TEST_F(EmbedderTest, SeveralHeaps) {
+namespace {
+
+class PseudoCollectible : public cppgc::GarbageCollected<PseudoCollectible> {
+ public:
+  static cppgc::Persistent<PseudoCollectible> s_persistent_;
+
+  static void Clear() {
+    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(); }
+
+  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_;
+cppgc::Persistent<PseudoCollectible> PseudoCollectible::s_persistent_;
+
+struct V8IsolateDeleter {
+  inline void operator()(v8::Isolate* ptr) { ptr->Dispose(); }
+};
+
+}  // namespace
+
+class HeapEmbedderTest : public EmbedderTest {
+ public:
+  void SetUp() override {
+    v8::Isolate::CreateParams params;
+    params.array_buffer_allocator = static_cast<v8::ArrayBuffer::Allocator*>(
+        FPDF_GetArrayBufferAllocatorSharedInstance());
+    isolate_.reset(v8::Isolate::New(params));
+    EmbedderTest::SetExternalIsolate(isolate_.get());
+    EmbedderTest::SetUp();
+  }
+
+  void TearDown() override {
+    EmbedderTest::TearDown();
+    isolate_.reset();
+  }
+
+  void PumpPlatformMessageLoop() {
+    while (v8::platform::PumpMessageLoop(
+        EmbedderTestEnvironment::GetInstance()->platform(), isolate_.get())) {
+      continue;
+    }
+  }
+
+ private:
+  std::unique_ptr<v8::Isolate, V8IsolateDeleter> isolate_;
+};
+
+TEST_F(HeapEmbedderTest, SeveralHeaps) {
   FXGCScopedHeap heap1 = FXGC_CreateHeap();
   EXPECT_TRUE(heap1);
 
@@ -19,3 +90,41 @@
   FXGCScopedHeap heap3 = FXGC_CreateHeap();
   EXPECT_TRUE(heap2);
 }
+
+TEST_F(HeapEmbedderTest, NoReferences) {
+  FXGCScopedHeap heap1 = FXGC_CreateHeap();
+  ASSERT_TRUE(heap1);
+
+  PseudoCollectible::s_persistent_ =
+      cppgc::MakeGarbageCollected<PseudoCollectible>(heap1.get());
+  EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
+  EXPECT_EQ(1u, PseudoCollectible::LiveCount());
+  EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+
+  PseudoCollectible::s_persistent_ = nullptr;
+  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);
+
+  PseudoCollectible::s_persistent_ =
+      cppgc::MakeGarbageCollected<PseudoCollectible>(heap1.get());
+  EXPECT_TRUE(PseudoCollectible::s_persistent_->IsLive());
+  EXPECT_EQ(1u, PseudoCollectible::LiveCount());
+  EXPECT_EQ(0u, PseudoCollectible::DeadCount());
+
+  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();
+}