From 479bfdb11b1f5eefb9048ba05a4c73ba55c7b4aa Mon Sep 17 00:00:00 2001 From: Michael Lippautz Date: Fri, 13 Aug 2021 10:01:26 +0200 Subject: [PATCH] cppgc: Optimize GCInfo setup In Blink's version of Oilpan, GCInfo objects would reside in .bss and a table would translate between an index and the .bss address. Upon retrieving a GCInfoIndex, the slow path merely passes a .bss pointer to a slow path setup method to create the table mapping. In cppgc, we set up GCInfo entries directly in the table. This is slightly faster for actually using GCInfo objects as there's no indirection between table and .bss, and it also saves one pointer (the indirection) per type that is set up. The downside of this approach is that individual components of a GCInfo objects, that are all type-dependent, need to be passed to the conditional setup method. Since GCInfo indices must be retrieved on each allocation, this pollutes the fast path with additional instructions. However, GCInfo components are actually known at compile-time for many objects. In such cases, we can use a compile-time static dispatch to encode the known parameters in different functions. This saves around 40KiB of memory on ChromePublic.apk and also creates a more compact fast path for allocation. Bug: chromium:1238884, chromium:1056170 Change-Id: Iedd809a8baefcc02f131d2b2c77d341b0abe43bb Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3094007 Reviewed-by: Anton Bikineev Reviewed-by: Omer Katz Commit-Queue: Michael Lippautz Cr-Commit-Position: refs/heads/master@{#76291} --- include/cppgc/allocation.h | 7 +- include/cppgc/internal/finalizer-trait.h | 2 + include/cppgc/internal/gc-info.h | 99 +++++++++++++++++++++--- include/cppgc/internal/name-trait.h | 11 +++ src/heap/cppgc/gc-info.cc | 78 +++++++++++++++++-- 5 files changed, 179 insertions(+), 18 deletions(-) diff --git a/include/cppgc/allocation.h b/include/cppgc/allocation.h index 5b7b5fc5f5..a3112dd61f 100644 --- a/include/cppgc/allocation.h +++ b/include/cppgc/allocation.h @@ -207,7 +207,7 @@ struct PostConstructionCallbackTrait { * \returns an instance of type T. */ template -T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) { +V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) { T* object = MakeGarbageCollectedTrait::Call(handle, std::forward(args)...); PostConstructionCallbackTrait::Call(object); @@ -225,8 +225,9 @@ T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) { * \returns an instance of type T. */ template -T* MakeGarbageCollected(AllocationHandle& handle, - AdditionalBytes additional_bytes, Args&&... args) { +V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, + AdditionalBytes additional_bytes, + Args&&... args) { T* object = MakeGarbageCollectedTrait::Call(handle, additional_bytes, std::forward(args)...); PostConstructionCallbackTrait::Call(object); diff --git a/include/cppgc/internal/finalizer-trait.h b/include/cppgc/internal/finalizer-trait.h index a95126591c..9af4f9a2ea 100644 --- a/include/cppgc/internal/finalizer-trait.h +++ b/include/cppgc/internal/finalizer-trait.h @@ -76,6 +76,8 @@ struct FinalizerTrait { } public: + static constexpr bool HasFinalizer() { return kCallback; } + // The callback used to finalize an object of type T. static constexpr FinalizationCallback kCallback = kNonTrivialFinalizer ? Finalize : nullptr; diff --git a/include/cppgc/internal/gc-info.h b/include/cppgc/internal/gc-info.h index 0830b19490..016670dc84 100644 --- a/include/cppgc/internal/gc-info.h +++ b/include/cppgc/internal/gc-info.h @@ -19,11 +19,93 @@ namespace internal { using GCInfoIndex = uint16_t; -// Acquires a new GC info object and returns the index. In addition, also -// updates `registered_index` atomically. -V8_EXPORT GCInfoIndex -EnsureGCInfoIndex(std::atomic& registered_index, - FinalizationCallback, TraceCallback, NameCallback, bool); +struct V8_EXPORT EnsureGCInfoIndexTrait final { + // Acquires a new GC info object and returns the index. In addition, also + // updates `registered_index` atomically. + template + V8_INLINE static GCInfoIndex EnsureIndex( + std::atomic& registered_index) { + return EnsureGCInfoIndexTraitDispatch{}(registered_index); + } + + private: + template ::value, + bool = FinalizerTrait::HasFinalizer(), + bool = NameTrait::HasNonHiddenName()> + struct EnsureGCInfoIndexTraitDispatch; + + static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, + TraceCallback, + FinalizationCallback, + NameCallback); + static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, + TraceCallback, + FinalizationCallback); + static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, + TraceCallback, NameCallback); + static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, + TraceCallback); + static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, + FinalizationCallback, + TraceCallback, + NameCallback); + static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, + TraceCallback, + FinalizationCallback); + static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, + TraceCallback, + NameCallback); + static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, + TraceCallback); +}; + +#define DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) \ + template \ + struct EnsureGCInfoIndexTrait::EnsureGCInfoIndexTraitDispatch< \ + T, is_polymorphic, has_finalizer, has_non_hidden_name> { \ + V8_INLINE GCInfoIndex \ + operator()(std::atomic& registered_index) { \ + return function; \ + } \ + }; + +// --------------------------------------------------------------------- // +// DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) +// --------------------------------------------------------------------- // +DISPATCH(true, true, true, // + EnsureGCInfoIndexPolymorphic(registered_index, // + TraceTrait::Trace, // + FinalizerTrait::kCallback, // + NameTrait::GetName)) // +DISPATCH(true, true, false, // + EnsureGCInfoIndexPolymorphic(registered_index, // + TraceTrait::Trace, // + FinalizerTrait::kCallback)) // +DISPATCH(true, false, true, // + EnsureGCInfoIndexPolymorphic(registered_index, // + TraceTrait::Trace, // + NameTrait::GetName)) // +DISPATCH(true, false, false, // + EnsureGCInfoIndexPolymorphic(registered_index, // + TraceTrait::Trace)) // +DISPATCH(false, true, true, // + EnsureGCInfoIndexNonPolymorphic(registered_index, // + TraceTrait::Trace, // + FinalizerTrait::kCallback, // + NameTrait::GetName)) // +DISPATCH(false, true, false, // + EnsureGCInfoIndexNonPolymorphic(registered_index, // + TraceTrait::Trace, // + FinalizerTrait::kCallback)) // +DISPATCH(false, false, true, // + EnsureGCInfoIndexNonPolymorphic(registered_index, // + TraceTrait::Trace, // + NameTrait::GetName)) // +DISPATCH(false, false, false, // + EnsureGCInfoIndexNonPolymorphic(registered_index, // + TraceTrait::Trace)) // + +#undef DISPATCH // Fold types based on finalizer behavior. Note that finalizer characteristics // align with trace behavior, i.e., destructors are virtual when trace methods @@ -57,16 +139,13 @@ struct GCInfoFolding { // finalization, and naming. template struct GCInfoTrait final { - static GCInfoIndex Index() { + V8_INLINE static GCInfoIndex Index() { static_assert(sizeof(T), "T must be fully defined"); static std::atomic registered_index; // Uses zero initialization. const GCInfoIndex index = registered_index.load(std::memory_order_acquire); return index ? index - : EnsureGCInfoIndex( - registered_index, FinalizerTrait::kCallback, - TraceTrait::Trace, NameTrait::GetName, - std::is_polymorphic::value); + : EnsureGCInfoIndexTrait::EnsureIndex(registered_index); } }; diff --git a/include/cppgc/internal/name-trait.h b/include/cppgc/internal/name-trait.h index 2e2da1eab4..32a3347859 100644 --- a/include/cppgc/internal/name-trait.h +++ b/include/cppgc/internal/name-trait.h @@ -6,6 +6,7 @@ #define INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ #include +#include #include "cppgc/name-provider.h" #include "v8config.h" // NOLINT(build/include_directory) @@ -67,6 +68,16 @@ class V8_EXPORT NameTraitBase { template class NameTrait final : public NameTraitBase { public: + static constexpr bool HasNonHiddenName() { +#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME + return true; +#elif CPPGC_SUPPORTS_OBJECT_NAMES + return true; +#else // !CPPGC_SUPPORTS_OBJECT_NAMES + return std::is_base_of::value; +#endif // !CPPGC_SUPPORTS_OBJECT_NAMES + } + static HeapObjectName GetName(const void* obj) { return GetNameFor(static_cast(obj)); } diff --git a/src/heap/cppgc/gc-info.cc b/src/heap/cppgc/gc-info.cc index de57805dcb..4598112d34 100644 --- a/src/heap/cppgc/gc-info.cc +++ b/src/heap/cppgc/gc-info.cc @@ -3,19 +3,87 @@ // found in the LICENSE file. #include "include/cppgc/internal/gc-info.h" + +#include "include/cppgc/internal/name-trait.h" #include "include/v8config.h" #include "src/heap/cppgc/gc-info-table.h" namespace cppgc { namespace internal { -GCInfoIndex EnsureGCInfoIndex(std::atomic& registered_index, - FinalizationCallback finalization_callback, - TraceCallback trace_callback, - NameCallback name_callback, bool has_v_table) { +namespace { + +HeapObjectName GetHiddenName(const void*) { + return {NameProvider::kHiddenName, true}; +} + +} // namespace + +// static +GCInfoIndex EnsureGCInfoIndexTrait::EnsureGCInfoIndexPolymorphic( + std::atomic& registered_index, TraceCallback trace_callback, + FinalizationCallback finalization_callback, NameCallback name_callback) { return GlobalGCInfoTable::GetMutable().RegisterNewGCInfo( registered_index, - {finalization_callback, trace_callback, name_callback, has_v_table}); + {finalization_callback, trace_callback, name_callback, true}); +} + +// static +GCInfoIndex EnsureGCInfoIndexTrait::EnsureGCInfoIndexPolymorphic( + std::atomic& registered_index, TraceCallback trace_callback, + FinalizationCallback finalization_callback) { + return GlobalGCInfoTable::GetMutable().RegisterNewGCInfo( + registered_index, + {finalization_callback, trace_callback, GetHiddenName, true}); +} + +// static +GCInfoIndex EnsureGCInfoIndexTrait::EnsureGCInfoIndexPolymorphic( + std::atomic& registered_index, TraceCallback trace_callback, + NameCallback name_callback) { + return GlobalGCInfoTable::GetMutable().RegisterNewGCInfo( + registered_index, {nullptr, trace_callback, name_callback, true}); +} + +// static +GCInfoIndex EnsureGCInfoIndexTrait::EnsureGCInfoIndexPolymorphic( + std::atomic& registered_index, TraceCallback trace_callback) { + return GlobalGCInfoTable::GetMutable().RegisterNewGCInfo( + registered_index, {nullptr, trace_callback, GetHiddenName, true}); +} + +// static +GCInfoIndex EnsureGCInfoIndexTrait::EnsureGCInfoIndexNonPolymorphic( + std::atomic& registered_index, + FinalizationCallback finalization_callback, TraceCallback trace_callback, + NameCallback name_callback) { + return GlobalGCInfoTable::GetMutable().RegisterNewGCInfo( + registered_index, + {finalization_callback, trace_callback, name_callback, false}); +} + +// static +GCInfoIndex EnsureGCInfoIndexTrait::EnsureGCInfoIndexNonPolymorphic( + std::atomic& registered_index, TraceCallback trace_callback, + FinalizationCallback finalization_callback) { + return GlobalGCInfoTable::GetMutable().RegisterNewGCInfo( + registered_index, + {finalization_callback, trace_callback, GetHiddenName, false}); +} + +// static +GCInfoIndex EnsureGCInfoIndexTrait::EnsureGCInfoIndexNonPolymorphic( + std::atomic& registered_index, TraceCallback trace_callback, + NameCallback name_callback) { + return GlobalGCInfoTable::GetMutable().RegisterNewGCInfo( + registered_index, {nullptr, trace_callback, name_callback, false}); +} + +// static +GCInfoIndex EnsureGCInfoIndexTrait::EnsureGCInfoIndexNonPolymorphic( + std::atomic& registered_index, TraceCallback trace_callback) { + return GlobalGCInfoTable::GetMutable().RegisterNewGCInfo( + registered_index, {nullptr, trace_callback, GetHiddenName, false}); } } // namespace internal