1 // Copyright 2020 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ 6 #define INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ 7 8 #include <cstddef> 9 #include <type_traits> 10 11 #include "cppgc/name-provider.h" 12 #include "v8config.h" // NOLINT(build/include_directory) 13 14 namespace cppgc { 15 namespace internal { 16 17 #if CPPGC_SUPPORTS_OBJECT_NAMES && defined(__clang__) 18 #define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 1 19 20 // Provides constexpr c-string storage for a name of fixed |Size| characters. 21 // Automatically appends terminating 0 byte. 22 template <size_t Size> 23 struct NameBuffer { 24 char name[Size + 1]{}; 25 FromCStringNameBuffer26 static constexpr NameBuffer FromCString(const char* str) { 27 NameBuffer result; 28 for (size_t i = 0; i < Size; ++i) result.name[i] = str[i]; 29 result.name[Size] = 0; 30 return result; 31 } 32 }; 33 34 template <typename T> GetTypename()35const char* GetTypename() { 36 static constexpr char kSelfPrefix[] = 37 "const char *cppgc::internal::GetTypename() [T ="; 38 static_assert(__builtin_strncmp(__PRETTY_FUNCTION__, kSelfPrefix, 39 sizeof(kSelfPrefix) - 1) == 0, 40 "The prefix must match"); 41 static constexpr const char* kTypenameStart = 42 __PRETTY_FUNCTION__ + sizeof(kSelfPrefix); 43 static constexpr size_t kTypenameSize = 44 __builtin_strlen(__PRETTY_FUNCTION__) - sizeof(kSelfPrefix) - 1; 45 // NameBuffer is an indirection that is needed to make sure that only a 46 // substring of __PRETTY_FUNCTION__ gets materialized in the binary. 47 static constexpr auto buffer = 48 NameBuffer<kTypenameSize>::FromCString(kTypenameStart); 49 return buffer.name; 50 } 51 52 #else 53 #define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 0 54 #endif 55 56 struct HeapObjectName { 57 const char* value; 58 bool name_was_hidden; 59 }; 60 61 class V8_EXPORT NameTraitBase { 62 protected: 63 static HeapObjectName GetNameFromTypeSignature(const char*); 64 }; 65 66 // Trait that specifies how the garbage collector retrieves the name for a 67 // given object. 68 template <typename T> 69 class NameTrait final : public NameTraitBase { 70 public: HasNonHiddenName()71 static constexpr bool HasNonHiddenName() { 72 #if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 73 return true; 74 #elif CPPGC_SUPPORTS_OBJECT_NAMES 75 return true; 76 #else // !CPPGC_SUPPORTS_OBJECT_NAMES 77 return std::is_base_of<NameProvider, T>::value; 78 #endif // !CPPGC_SUPPORTS_OBJECT_NAMES 79 } 80 GetName(const void * obj)81 static HeapObjectName GetName(const void* obj) { 82 return GetNameFor(static_cast<const T*>(obj)); 83 } 84 85 private: GetNameFor(const NameProvider * name_provider)86 static HeapObjectName GetNameFor(const NameProvider* name_provider) { 87 return {name_provider->GetHumanReadableName(), false}; 88 } 89 GetNameFor(...)90 static HeapObjectName GetNameFor(...) { 91 #if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 92 return {GetTypename<T>(), false}; 93 #elif CPPGC_SUPPORTS_OBJECT_NAMES 94 95 #if defined(V8_CC_GNU) 96 #define PRETTY_FUNCTION_VALUE __PRETTY_FUNCTION__ 97 #elif defined(V8_CC_MSVC) 98 #define PRETTY_FUNCTION_VALUE __FUNCSIG__ 99 #else 100 #define PRETTY_FUNCTION_VALUE nullptr 101 #endif 102 103 static const HeapObjectName leaky_name = 104 GetNameFromTypeSignature(PRETTY_FUNCTION_VALUE); 105 return {leaky_name, false}; 106 107 #undef PRETTY_FUNCTION_VALUE 108 109 #else // !CPPGC_SUPPORTS_OBJECT_NAMES 110 return {NameProvider::kHiddenName, true}; 111 #endif // !CPPGC_SUPPORTS_OBJECT_NAMES 112 } 113 }; 114 115 using NameCallback = HeapObjectName (*)(const void*); 116 117 } // namespace internal 118 } // namespace cppgc 119 120 #undef CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 121 122 #endif // INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ 123