cppgc: Hello world

"By my deeds I honor him. V8."

- Add basic build files for library and unittests.
- Integrate unittests also in existing V8 unittests for simplicity.

The CL also adds FinalizerTrait and unittests to allow building a
testing target that executes code.

FinalizerTrait is used to determine how managed C++ types are
finalized. The trait should not be overridable by users but needs to
be exposed on API-level to avoid including library-internal headers.

Bug: chromium:1056170
Change-Id: I64d91053410a17a7835e50547f58990625d2da28
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2108549
Reviewed-by: Hannes Payer <hpayer@chromium.org>
Reviewed-by: Omer Katz <omerkatz@chromium.org>
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66834}
diff --git a/BUILD.gn b/BUILD.gn
index ff0517f..1ed2de1 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -3920,6 +3920,20 @@
   ]
 }
 
+v8_source_set("cppgc_base") {
+  visibility = [ ":*" ]
+
+  sources = [
+    "include/cppgc/finalizer-trait.h",
+    "include/v8config.h",
+    "src/heap/cppgc/cppgc.cc",
+  ]
+
+  configs = [ ":internal_config" ]
+
+  public_deps = [ ":v8_libbase" ]
+}
+
 ###############################################################################
 # Produce a single static library for embedders
 #
@@ -3966,6 +3980,12 @@
   ]
 }
 
+v8_static_library("cppgc") {
+  deps = [ ":cppgc_base" ]
+
+  configs = [ ":internal_config" ]
+}
+
 ###############################################################################
 # Executables
 #
@@ -4257,6 +4277,15 @@
 
     public_configs = [ ":external_config" ]
   }
+
+  v8_component("cppgc_for_testing") {
+    testonly = true
+
+    public_deps = [ ":cppgc_base" ]
+
+    configs = [ ":internal_config" ]
+    public_configs = [ ":external_config" ]
+  }
 } else {
   group("v8") {
     public_deps = [
@@ -4280,6 +4309,14 @@
 
     public_configs = [ ":external_config" ]
   }
+
+  group("cppgc_for_testing") {
+    testonly = true
+
+    public_deps = [ ":cppgc_base" ]
+
+    public_configs = [ ":external_config" ]
+  }
 }
 
 v8_executable("d8") {
diff --git a/include/cppgc/README.md b/include/cppgc/README.md
new file mode 100644
index 0000000..3a2db6d
--- /dev/null
+++ b/include/cppgc/README.md
@@ -0,0 +1,5 @@
+# C++ Garbage Collection
+
+This directory provides an open-source garbage collection library for C++.
+
+The library is under construction, meaning that *all APIs in this directory are incomplete and considered unstable and should not be used*.
\ No newline at end of file
diff --git a/include/cppgc/finalizer-trait.h b/include/cppgc/finalizer-trait.h
new file mode 100644
index 0000000..474848b
--- /dev/null
+++ b/include/cppgc/finalizer-trait.h
@@ -0,0 +1,96 @@
+// Copyright 2020 the V8 project 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 INCLUDE_CPPGC_FINALIZER_TRAIT_H_
+#define INCLUDE_CPPGC_FINALIZER_TRAIT_H_
+
+#include <type_traits>
+
+namespace cppgc {
+namespace internal {
+
+using FinalizationCallback = void (*)(void*);
+
+// Pre-C++17 custom implementation of std::void_t.
+template <typename... Ts>
+struct make_void {
+  typedef void type;
+};
+template <typename... Ts>
+using void_t = typename make_void<Ts...>::type;
+
+template <typename T, typename = void>
+struct HasFinalizeGarbageCollectedObject : std::false_type {};
+
+template <typename T>
+struct HasFinalizeGarbageCollectedObject<
+    T, void_t<decltype(std::declval<T>().FinalizeGarbageCollectedObject())>>
+    : std::true_type {};
+
+// The FinalizerTraitImpl specifies how to finalize objects.
+template <typename T, bool isFinalized>
+struct FinalizerTraitImpl;
+
+template <typename T>
+struct FinalizerTraitImpl<T, true> {
+ private:
+  // Dispatch to custom FinalizeGarbageCollectedObject().
+  struct Custom {
+    static void Call(void* obj) {
+      static_cast<T*>(obj)->FinalizeGarbageCollectedObject();
+    }
+  };
+
+  // Dispatch to regular destructor.
+  struct Destructor {
+    static void Call(void* obj) { static_cast<T*>(obj)->~T(); }
+  };
+
+  using FinalizeImpl =
+      std::conditional_t<HasFinalizeGarbageCollectedObject<T>::value, Custom,
+                         Destructor>;
+
+ public:
+  static void Finalize(void* obj) {
+    static_assert(sizeof(T), "T must be fully defined");
+    FinalizeImpl::Call(obj);
+  }
+};
+
+template <typename T>
+struct FinalizerTraitImpl<T, false> {
+  static void Finalize(void* obj) {
+    static_assert(sizeof(T), "T must be fully defined");
+  }
+};
+
+// The FinalizerTrait is used to determine if a type requires finalization and
+// what finalization means.
+template <typename T>
+struct FinalizerTrait {
+ private:
+  // Object has a finalizer if it has
+  // - a custom FinalizeGarbageCollectedObject method, or
+  // - a destructor.
+  static constexpr bool kNonTrivialFinalizer =
+      internal::HasFinalizeGarbageCollectedObject<T>::value ||
+      !std::is_trivially_destructible<typename std::remove_cv<T>::type>::value;
+
+  static void Finalize(void* obj) {
+    internal::FinalizerTraitImpl<T, kNonTrivialFinalizer>::Finalize(obj);
+  }
+
+ public:
+  // The callback used to finalize an object of type T.
+  static constexpr FinalizationCallback kCallback =
+      kNonTrivialFinalizer ? Finalize : nullptr;
+};
+
+template <typename T>
+constexpr FinalizationCallback FinalizerTrait<T>::kCallback;
+
+}  // namespace internal
+}  // namespace cppgc
+
+#endif  // INCLUDE_CPPGC_FINALIZER_TRAIT_H_
diff --git a/src/heap/cppgc/cppgc.cc b/src/heap/cppgc/cppgc.cc
new file mode 100644
index 0000000..dcec740
--- /dev/null
+++ b/src/heap/cppgc/cppgc.cc
@@ -0,0 +1,16 @@
+// Copyright 2020 the V8 project 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 "include/v8config.h"
+
+namespace cppgc {
+namespace internal {
+
+V8_EXPORT void Dummy() {
+  // TODO(mlippautz): Placeholder to force building a library. Remove as soon as
+  // actual code is available.
+}
+
+}  // namespace internal
+}  // namespace cppgc
diff --git a/test/unittests/BUILD.gn b/test/unittests/BUILD.gn
index 16a4740..7e43244 100644
--- a/test/unittests/BUILD.gn
+++ b/test/unittests/BUILD.gn
@@ -20,6 +20,43 @@
   }
 }
 
+# Stand-alone target for C++ GC unittests. This is used to ensure that it
+# builds without V8 as well. They are also included in the regular unittests
+# target for simplicity.
+v8_executable("cppgc_unittests") {
+  testonly = true
+
+  configs = [
+    "../..:external_config",
+    "../..:internal_config_base",
+  ]
+
+  sources = [ "heap/cppgc/run-all-unittests.cc" ]
+
+  deps = [
+    ":cppgc_unittests_sources",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
+
+v8_source_set("cppgc_unittests_sources") {
+  testonly = true
+
+  sources = [ "heap/cppgc/finalizer-trait_unittest.cc" ]
+
+  configs = [
+    "../..:external_config",
+    "../..:internal_config_base",
+  ]
+
+  deps = [
+    "../..:cppgc_for_testing",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
+
 v8_executable("unittests") {
   testonly = true
 
@@ -29,6 +66,7 @@
   #}],
 
   deps = [
+    ":cppgc_unittests_sources",
     ":unittests_sources",
     "../..:v8_for_testing",
     "../..:v8_libbase",
diff --git a/test/unittests/heap/cppgc/finalizer-trait_unittest.cc b/test/unittests/heap/cppgc/finalizer-trait_unittest.cc
new file mode 100644
index 0000000..91a255e
--- /dev/null
+++ b/test/unittests/heap/cppgc/finalizer-trait_unittest.cc
@@ -0,0 +1,118 @@
+// Copyright 2020 the V8 project 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 "include/cppgc/finalizer-trait.h"
+#include <type_traits>
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cppgc {
+namespace internal {
+
+namespace {
+
+// Trivially destructible types.
+class TypeWithoutDestructor final {};
+class TypeWithPrimitive final {
+ public:
+  int foo = 0;
+};
+
+class InvokeCounter {
+ public:
+  static size_t kCallcount;
+  static void Reset() { kCallcount = 0; }
+  static void Invoke() { kCallcount++; }
+};
+
+size_t InvokeCounter::kCallcount = 0;
+
+// Regular C++ use cases.
+
+class TypeWithDestructor final : public InvokeCounter {
+ public:
+  ~TypeWithDestructor() { Invoke(); }
+};
+
+class TypeWithVirtualDestructorBase {
+ public:
+  virtual ~TypeWithVirtualDestructorBase() = default;
+};
+
+class TypeWithVirtualDestructorChild final
+    : public TypeWithVirtualDestructorBase,
+      public InvokeCounter {
+ public:
+  ~TypeWithVirtualDestructorChild() final { Invoke(); }
+};
+
+// Manual dispatch to avoid vtables.
+
+class TypeWithCustomFinalizationMethod final : public InvokeCounter {
+ public:
+  void FinalizeGarbageCollectedObject() { Invoke(); }
+};
+
+class TypeWithCustomFinalizationMethodAtBase {
+ public:
+  void FinalizeGarbageCollectedObject();
+};
+
+class TypeWithCustomFinalizationMethodAtBaseChild
+    : public TypeWithCustomFinalizationMethodAtBase,
+      public InvokeCounter {
+ public:
+  ~TypeWithCustomFinalizationMethodAtBaseChild() { Invoke(); }
+};
+
+void TypeWithCustomFinalizationMethodAtBase::FinalizeGarbageCollectedObject() {
+  // The test knows that base is only inherited by a single child. In practice
+  // users can maintain a map of valid types in already existing storage.
+  static_cast<TypeWithCustomFinalizationMethodAtBaseChild*>(this)
+      ->~TypeWithCustomFinalizationMethodAtBaseChild();
+}
+
+template <typename Type>
+void ExpectFinalizerIsInvoked(Type* object) {
+  InvokeCounter::Reset();
+  EXPECT_NE(nullptr, FinalizerTrait<Type>::kCallback);
+  FinalizerTrait<Type>::kCallback(object);
+  EXPECT_EQ(1u, InvokeCounter::kCallcount);
+  operator delete(object);
+}
+
+}  // namespace
+
+TEST(FinalizerTrait, TypeWithoutDestructorHasNoFinalizer) {
+  static_assert(std::is_trivially_destructible<TypeWithoutDestructor>::value,
+                "trivially destructible");
+  EXPECT_EQ(nullptr, FinalizerTrait<TypeWithoutDestructor>::kCallback);
+}
+
+TEST(FinalizerTrait, TypeWithPrimitiveHasNoFinalizer) {
+  static_assert(std::is_trivially_destructible<TypeWithPrimitive>::value,
+                "trivially destructible");
+  EXPECT_EQ(nullptr, FinalizerTrait<TypeWithPrimitive>::kCallback);
+}
+
+TEST(FinalizerTrait, FinalizerForTypeWithDestructor) {
+  ExpectFinalizerIsInvoked(new TypeWithDestructor());
+}
+
+TEST(FinalizerTrait, FinalizerForTypeWithVirtualBaseDtor) {
+  TypeWithVirtualDestructorBase* base = new TypeWithVirtualDestructorChild();
+  ExpectFinalizerIsInvoked(base);
+}
+
+TEST(FinalizerTrait, FinalizerForCustomFinalizationMethod) {
+  ExpectFinalizerIsInvoked(new TypeWithCustomFinalizationMethod());
+}
+
+TEST(FinalizerTrait, FinalizerForCustomFinalizationMethodInBase) {
+  TypeWithCustomFinalizationMethodAtBase* base =
+      new TypeWithCustomFinalizationMethodAtBaseChild();
+  ExpectFinalizerIsInvoked(base);
+}
+
+}  // namespace internal
+}  // namespace cppgc
diff --git a/test/unittests/heap/cppgc/run-all-unittests.cc b/test/unittests/heap/cppgc/run-all-unittests.cc
new file mode 100644
index 0000000..cdc862e
--- /dev/null
+++ b/test/unittests/heap/cppgc/run-all-unittests.cc
@@ -0,0 +1,17 @@
+// Copyright 2020 the V8 project 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 "testing/gmock/include/gmock/gmock.h"
+
+int main(int argc, char** argv) {
+  // Don't catch SEH exceptions and continue as the following tests might hang
+  // in an broken environment on windows.
+  testing::GTEST_FLAG(catch_exceptions) = false;
+
+  // Most unit-tests are multi-threaded, so enable thread-safe death-tests.
+  testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  testing::InitGoogleMock(&argc, argv);
+  return RUN_ALL_TESTS();
+}