Add fxjs/gc interface to Oilpan's CPP GCed heaps.

Only provides one small test since the FX API is expected to
change, but ensures we can link, initialize, and make a heap.

-- Use FXGC naming for parallelism with FXJS.
-- The Oilpan layer will now be initialized for XFA builds.
-- The platform is now only passed to the new FXGC side.

Change-Id: I452050556554bf03fdc319f8e16ec71ff2dac176
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/70510
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fxjs/BUILD.gn b/fxjs/BUILD.gn
index 8f6225f..6ec9276 100644
--- a/fxjs/BUILD.gn
+++ b/fxjs/BUILD.gn
@@ -114,6 +114,8 @@
 
     if (pdf_enable_xfa) {
       sources += [
+        "gc/heap.cpp",
+        "gc/heap.h",
         "xfa/cfxjse_class.cpp",
         "xfa/cfxjse_class.h",
         "xfa/cfxjse_context.cpp",
@@ -205,6 +207,7 @@
       deps += [
         "../xfa/fgas",
         "../xfa/fxfa/fm2js",
+        "//v8:cppgc",
       ]
     }
   }
@@ -237,16 +240,19 @@
       "../fpdfsdk",
     ]
     pdfium_root_dir = "../"
-
     if (pdf_enable_xfa) {
       sources += [
+        "gc/heap_embeddertest.cpp",
         "xfa/cfxjse_app_embeddertest.cpp",
         "xfa/cfxjse_formcalc_context_embeddertest.cpp",
         "xfa/cfxjse_value_embeddertest.cpp",
         "xfa/cjx_hostpseudomodel_embeddertest.cpp",
         "xfa/cjx_list_embeddertest.cpp",
       ]
-      deps += [ "../xfa/fxfa" ]
+      deps += [
+        "../xfa/fxfa",
+        "//v8:cppgc",
+      ]
     }
   }
 }
diff --git a/fxjs/cfxjs_engine.cpp b/fxjs/cfxjs_engine.cpp
index cb0cede..ae1a9bc 100644
--- a/fxjs/cfxjs_engine.cpp
+++ b/fxjs/cfxjs_engine.cpp
@@ -14,7 +14,6 @@
 #include "fxjs/fxv8.h"
 #include "fxjs/xfa/cfxjse_runtimedata.h"
 #include "third_party/base/stl_util.h"
-#include "v8/include/libplatform/libplatform.h"
 #include "v8/include/v8-util.h"
 
 class CFXJS_PerObjectData;
@@ -23,7 +22,6 @@
 
 unsigned int g_embedderDataSlot = 1u;
 v8::Isolate* g_isolate = nullptr;
-v8::Platform* g_platform = nullptr;
 size_t g_isolate_ref_count = 0;
 CFX_V8ArrayBufferAllocator* g_arrayBufferAllocator = nullptr;
 v8::Global<v8::ObjectTemplate>* g_DefaultGlobalObjectTemplate = nullptr;
@@ -271,9 +269,7 @@
   return pMap ? &pMap->m_map : nullptr;
 }
 
-void FXJS_Initialize(unsigned int embedderDataSlot,
-                     v8::Isolate* pIsolate,
-                     v8::Platform* pPlatform) {
+void FXJS_Initialize(unsigned int embedderDataSlot, v8::Isolate* pIsolate) {
   if (g_isolate) {
     ASSERT(g_embedderDataSlot == embedderDataSlot);
     ASSERT(g_isolate == pIsolate);
@@ -281,7 +277,6 @@
   }
   g_embedderDataSlot = embedderDataSlot;
   g_isolate = pIsolate;
-  g_platform = pPlatform;
 }
 
 void FXJS_Release() {
diff --git a/fxjs/cfxjs_engine.h b/fxjs/cfxjs_engine.h
index cd337fe..933c250 100644
--- a/fxjs/cfxjs_engine.h
+++ b/fxjs/cfxjs_engine.h
@@ -63,9 +63,7 @@
   explicit FXJS_PerIsolateData(v8::Isolate* pIsolate);
 };
 
-void FXJS_Initialize(unsigned int embedderDataSlot,
-                     v8::Isolate* pIsolate,
-                     v8::Platform* platform);
+void FXJS_Initialize(unsigned int embedderDataSlot, v8::Isolate* pIsolate);
 void FXJS_Release();
 
 // Gets the global isolate set by FXJS_Initialize(), or makes a new one each
diff --git a/fxjs/cfxjs_engine_unittest.cpp b/fxjs/cfxjs_engine_unittest.cpp
index d91fcd1..c8e844c 100644
--- a/fxjs/cfxjs_engine_unittest.cpp
+++ b/fxjs/cfxjs_engine_unittest.cpp
@@ -17,7 +17,7 @@
 
   void SetUp() override {
     FXV8UnitTest::SetUp();
-    FXJS_Initialize(1, isolate(), nullptr);
+    FXJS_Initialize(1, isolate());
     engine_ = std::make_unique<CFXJS_Engine>(isolate());
   }
 
diff --git a/fxjs/cjs_runtime.cpp b/fxjs/cjs_runtime.cpp
index b6b5722..d2c30d3 100644
--- a/fxjs/cjs_runtime.cpp
+++ b/fxjs/cjs_runtime.cpp
@@ -52,7 +52,7 @@
       pExternalIsolate = static_cast<v8::Isolate*>(pPlatform->m_isolate);
       embedderDataSlot = pPlatform->m_v8EmbedderSlot;
     }
-    FXJS_Initialize(embedderDataSlot, pExternalIsolate, nullptr);
+    FXJS_Initialize(embedderDataSlot, pExternalIsolate);
   }
   m_isolateManaged = FXJS_GetIsolate(&pIsolate);
   SetIsolate(pIsolate);
diff --git a/fxjs/gc/heap.cpp b/fxjs/gc/heap.cpp
new file mode 100644
index 0000000..02319eb
--- /dev/null
+++ b/fxjs/gc/heap.cpp
@@ -0,0 +1,65 @@
+// Copyright 2020 PDFium 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 "fxjs/gc/heap.h"
+
+#include "third_party/base/ptr_util.h"
+
+namespace {
+
+size_t g_platform_ref_count = 0;
+v8::Platform* g_platform = nullptr;
+
+}  // namespace
+
+class CFXGC_Platform final : public cppgc::Platform {
+ public:
+  CFXGC_Platform() = default;
+  ~CFXGC_Platform() override = default;
+
+  cppgc::PageAllocator* GetPageAllocator() override {
+    return g_platform->GetPageAllocator();
+  }
+
+  double MonotonicallyIncreasingTime() override {
+    return g_platform->MonotonicallyIncreasingTime();
+  }
+
+  std::shared_ptr<cppgc::TaskRunner> GetForegroundTaskRunner() override {
+    // V8's default platform creates a new task runner when passed the
+    // v8::Isolate pointer the first time. For non-default platforms this will
+    // require getting the appropriate task runner.
+    return g_platform->GetForegroundTaskRunner(nullptr);
+  }
+
+  std::unique_ptr<cppgc::JobHandle> PostJob(
+      cppgc::TaskPriority priority,
+      std::unique_ptr<cppgc::JobTask> job_task) override {
+    return g_platform->PostJob(priority, std::move(job_task));
+  }
+};
+
+void FXGC_Initialize(v8::Platform* platform) {
+  if (platform) {
+    g_platform = platform;
+    cppgc::InitializeProcess(platform->GetPageAllocator());
+  }
+}
+
+void FXGC_Release() {
+  if (g_platform && g_platform_ref_count == 0) {
+    cppgc::ShutdownProcess();
+    g_platform = nullptr;
+  }
+}
+
+std::unique_ptr<cppgc::Heap> FXGC_CreateHeap() {
+  ++g_platform_ref_count;
+  return cppgc::Heap::Create(std::make_shared<CFXGC_Platform>());
+}
+
+void FXGC_ReleaseHeap(std::unique_ptr<cppgc::Heap> heap) {
+  --g_platform_ref_count;
+  // |heap| destroyed when it goes out of scope.
+}
diff --git a/fxjs/gc/heap.h b/fxjs/gc/heap.h
new file mode 100644
index 0000000..2e25517
--- /dev/null
+++ b/fxjs/gc/heap.h
@@ -0,0 +1,19 @@
+// Copyright 2020 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FXJS_GC_HEAP_H_
+#define FXJS_GC_HEAP_H_
+
+#include <memory>
+
+#include "v8/include/cppgc/heap.h"
+#include "v8/include/libplatform/libplatform.h"
+
+void FXGC_Initialize(v8::Platform* platform);
+void FXGC_Release();
+
+std::unique_ptr<cppgc::Heap> FXGC_CreateHeap();
+void FXGC_ReleaseHeap(std::unique_ptr<cppgc::Heap> heap);
+
+#endif  // FXJS_GC_HEAP_H_
diff --git a/fxjs/gc/heap_embeddertest.cpp b/fxjs/gc/heap_embeddertest.cpp
new file mode 100644
index 0000000..8ee42ca
--- /dev/null
+++ b/fxjs/gc/heap_embeddertest.cpp
@@ -0,0 +1,31 @@
+// Copyright 2020 PDFium 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 "fxjs/gc/heap.h"
+
+#include <memory>
+
+#include "testing/embedder_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class HeapEmbedderTest : public EmbedderTest {};
+
+TEST(HeapEmbedderTest, SeveralHeaps) {
+  FXGC_Initialize(EmbedderTestEnvironment::GetInstance()->platform());
+
+  std::unique_ptr<cppgc::Heap> heap1 = FXGC_CreateHeap();
+  EXPECT_TRUE(heap1);
+
+  std::unique_ptr<cppgc::Heap> heap2 = FXGC_CreateHeap();
+  EXPECT_TRUE(heap2);
+
+  std::unique_ptr<cppgc::Heap> heap3 = FXGC_CreateHeap();
+  EXPECT_TRUE(heap2);
+
+  FXGC_ReleaseHeap(std::move(heap1));
+  FXGC_ReleaseHeap(std::move(heap2));
+  FXGC_ReleaseHeap(std::move(heap3));
+
+  FXGC_Release();
+}
diff --git a/fxjs/ijs_runtime.cpp b/fxjs/ijs_runtime.cpp
index f16385a..05027e4 100644
--- a/fxjs/ijs_runtime.cpp
+++ b/fxjs/ijs_runtime.cpp
@@ -9,7 +9,10 @@
 #ifdef PDF_ENABLE_V8
 #include "fxjs/cfxjs_engine.h"
 #include "fxjs/cjs_runtime.h"
-#endif
+#ifdef PDF_ENABLE_XFA
+#include "fxjs/gc/heap.h"
+#endif  // PDF_ENABLE_XFA
+#endif  // PDF_ENABLE_V8
 
 IJS_Runtime::ScopedEventContext::ScopedEventContext(IJS_Runtime* pRuntime)
     : m_pRuntime(pRuntime), m_pContext(pRuntime->NewEventContext()) {}
@@ -21,16 +24,21 @@
 // static
 void IJS_Runtime::Initialize(unsigned int slot, void* isolate, void* platform) {
 #ifdef PDF_ENABLE_V8
-  FXJS_Initialize(slot, static_cast<v8::Isolate*>(isolate),
-                  static_cast<v8::Platform*>(platform));
-#endif
+  FXJS_Initialize(slot, static_cast<v8::Isolate*>(isolate));
+#ifdef PDF_ENABLE_XFA
+  FXGC_Initialize(static_cast<v8::Platform*>(platform));
+#endif  // PDF_ENABLE_XFA
+#endif  // PDF_ENABLE_V8
 }
 
 // static
 void IJS_Runtime::Destroy() {
 #ifdef PDF_ENABLE_V8
+#ifdef PDF_ENABL_XFA
+  FXGC_Release();
+#endif  // PDF_ENABLE_XFA
   FXJS_Release();
-#endif
+#endif  // PDF_ENABLE_V8
 }
 
 // static