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