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