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
14namespace cppgc {
15namespace 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.
22template <size_t Size>
23struct NameBuffer {
24  char name[Size + 1]{};
25
26  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
34template <typename T>
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
56struct HeapObjectName {
57  const char* value;
58  bool name_was_hidden;
59};
60
61class 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.
68template <typename T>
69class NameTrait final : public NameTraitBase {
70 public:
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
81  static HeapObjectName GetName(const void* obj) {
82    return GetNameFor(static_cast<const T*>(obj));
83  }
84
85 private:
86  static HeapObjectName GetNameFor(const NameProvider* name_provider) {
87    return {name_provider->GetHumanReadableName(), false};
88  }
89
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
115using 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