xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/allocator_config_wrapper.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===-- allocator_config_wrapper.h ------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_
10 #define SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_
11 
12 #include "condition_variable.h"
13 #include "internal_defs.h"
14 #include "secondary.h"
15 
16 namespace {
17 
18 template <typename T> struct removeConst {
19   using type = T;
20 };
21 template <typename T> struct removeConst<const T> {
22   using type = T;
23 };
24 
25 // This is only used for SFINAE when detecting if a type is defined.
26 template <typename T> struct voidAdaptor {
27   using type = void;
28 };
29 
30 // This is used for detecting the case that defines the flag with wrong type and
31 // it'll be viewed as undefined optional flag.
32 template <typename L, typename R> struct assertSameType {
33   template <typename, typename> struct isSame {
34     static constexpr bool value = false;
35   };
36   template <typename T> struct isSame<T, T> {
37     static constexpr bool value = true;
38   };
39   static_assert(isSame<L, R>::value, "Flag type mismatches");
40   using type = R;
41 };
42 
43 } // namespace
44 
45 namespace scudo {
46 
47 #define OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, MEMBER)                         \
48   template <typename Config, typename = TYPE> struct NAME##State {             \
49     static constexpr removeConst<TYPE>::type getValue() { return DEFAULT; }    \
50   };                                                                           \
51   template <typename Config>                                                   \
52   struct NAME##State<                                                          \
53       Config, typename assertSameType<decltype(Config::MEMBER), TYPE>::type> { \
54     static constexpr removeConst<TYPE>::type getValue() {                      \
55       return Config::MEMBER;                                                   \
56     }                                                                          \
57   };
58 
59 #define OPTIONAL_TYPE_TEMPLATE(NAME, DEFAULT, MEMBER)                          \
60   template <typename Config, typename Void = void> struct NAME##Type {         \
61     static constexpr bool enabled() { return false; }                          \
62     using NAME = DEFAULT;                                                      \
63   };                                                                           \
64   template <typename Config>                                                   \
65   struct NAME##Type<Config,                                                    \
66                     typename voidAdaptor<typename Config::MEMBER>::type> {     \
67     static constexpr bool enabled() { return true; }                           \
68     using NAME = typename Config::MEMBER;                                      \
69   };
70 
71 template <typename AllocatorConfig> struct BaseConfig {
72 #define BASE_REQUIRED_TEMPLATE_TYPE(NAME)                                      \
73   template <typename T> using NAME = typename AllocatorConfig::template NAME<T>;
74 
75 #define BASE_OPTIONAL(TYPE, NAME, DEFAULT)                                     \
76   OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, NAME)                                 \
77   static constexpr removeConst<TYPE>::type get##NAME() {                       \
78     return NAME##State<AllocatorConfig>::getValue();                           \
79   }
80 
81 #include "allocator_config.def"
82 }; // BaseConfig
83 
84 template <typename AllocatorConfig> struct PrimaryConfig {
85   // TODO: Pass this flag through template argument to remove this hard-coded
86   //       function.
87   static constexpr bool getMaySupportMemoryTagging() {
88     return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
89   }
90 
91 #define PRIMARY_REQUIRED_TYPE(NAME)                                            \
92   using NAME = typename AllocatorConfig::Primary::NAME;
93 
94 #define PRIMARY_REQUIRED(TYPE, NAME)                                           \
95   static constexpr removeConst<TYPE>::type get##NAME() {                       \
96     return AllocatorConfig::Primary::NAME;                                     \
97   }
98 
99 #define PRIMARY_OPTIONAL(TYPE, NAME, DEFAULT)                                  \
100   OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, NAME)                                 \
101   static constexpr removeConst<TYPE>::type get##NAME() {                       \
102     return NAME##State<typename AllocatorConfig::Primary>::getValue();         \
103   }
104 
105 #define PRIMARY_OPTIONAL_TYPE(NAME, DEFAULT)                                   \
106   OPTIONAL_TYPE_TEMPLATE(NAME, DEFAULT, NAME)                                  \
107   static constexpr bool has##NAME() {                                          \
108     return NAME##Type<typename AllocatorConfig::Primary>::enabled();           \
109   }                                                                            \
110   using NAME = typename NAME##Type<typename AllocatorConfig::Primary>::NAME;
111 
112 #include "allocator_config.def"
113 
114 }; // PrimaryConfig
115 
116 template <typename AllocatorConfig> struct SecondaryConfig {
117   // TODO: Pass this flag through template argument to remove this hard-coded
118   //       function.
119   static constexpr bool getMaySupportMemoryTagging() {
120     return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
121   }
122 
123 #define SECONDARY_REQUIRED_TEMPLATE_TYPE(NAME)                                 \
124   template <typename T>                                                        \
125   using NAME = typename AllocatorConfig::Secondary::template NAME<T>;
126 #include "allocator_config.def"
127 
128   struct CacheConfig {
129     // TODO: Pass this flag through template argument to remove this hard-coded
130     //       function.
131     static constexpr bool getMaySupportMemoryTagging() {
132       return BaseConfig<AllocatorConfig>::getMaySupportMemoryTagging();
133     }
134 
135 #define SECONDARY_CACHE_OPTIONAL(TYPE, NAME, DEFAULT)                          \
136   OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, Cache::NAME)                          \
137   static constexpr removeConst<TYPE>::type get##NAME() {                       \
138     return NAME##State<typename AllocatorConfig::Secondary>::getValue();       \
139   }
140 #include "allocator_config.def"
141   }; // CacheConfig
142 };   // SecondaryConfig
143 
144 #undef OPTIONAL_TEMPLATE
145 #undef OPTIONAL_TEMPLATE_TYPE
146 
147 } // namespace scudo
148 
149 #endif // SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_
150