//===-- allocator_config_wrapper.h ------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_ #define SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_ #include "condition_variable.h" #include "internal_defs.h" #include "secondary.h" namespace { template struct removeConst { using type = T; }; template struct removeConst { using type = T; }; // This is only used for SFINAE when detecting if a type is defined. template struct voidAdaptor { using type = void; }; // This is used for detecting the case that defines the flag with wrong type and // it'll be viewed as undefined optional flag. template struct assertSameType { template struct isSame { static constexpr bool value = false; }; template struct isSame { static constexpr bool value = true; }; static_assert(isSame::value, "Flag type mismatches"); using type = R; }; } // namespace namespace scudo { #define OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, MEMBER) \ template struct NAME##State { \ static constexpr removeConst::type getValue() { return DEFAULT; } \ }; \ template \ struct NAME##State< \ Config, typename assertSameType::type> { \ static constexpr removeConst::type getValue() { \ return Config::MEMBER; \ } \ }; #define OPTIONAL_TYPE_TEMPLATE(NAME, DEFAULT, MEMBER) \ template struct NAME##Type { \ static constexpr bool enabled() { return false; } \ using NAME = DEFAULT; \ }; \ template \ struct NAME##Type::type> { \ static constexpr bool enabled() { return true; } \ using NAME = typename Config::MEMBER; \ }; template struct BaseConfig { #define BASE_REQUIRED_TEMPLATE_TYPE(NAME) \ template using NAME = typename AllocatorConfig::template NAME; #define BASE_OPTIONAL(TYPE, NAME, DEFAULT) \ OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, NAME) \ static constexpr removeConst::type get##NAME() { \ return NAME##State::getValue(); \ } #include "allocator_config.def" }; // BaseConfig template struct PrimaryConfig { // TODO: Pass this flag through template argument to remove this hard-coded // function. static constexpr bool getMaySupportMemoryTagging() { return BaseConfig::getMaySupportMemoryTagging(); } #define PRIMARY_REQUIRED_TYPE(NAME) \ using NAME = typename AllocatorConfig::Primary::NAME; #define PRIMARY_REQUIRED(TYPE, NAME) \ static constexpr removeConst::type get##NAME() { \ return AllocatorConfig::Primary::NAME; \ } #define PRIMARY_OPTIONAL(TYPE, NAME, DEFAULT) \ OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, NAME) \ static constexpr removeConst::type get##NAME() { \ return NAME##State::getValue(); \ } #define PRIMARY_OPTIONAL_TYPE(NAME, DEFAULT) \ OPTIONAL_TYPE_TEMPLATE(NAME, DEFAULT, NAME) \ static constexpr bool has##NAME() { \ return NAME##Type::enabled(); \ } \ using NAME = typename NAME##Type::NAME; #include "allocator_config.def" }; // PrimaryConfig template struct SecondaryConfig { // TODO: Pass this flag through template argument to remove this hard-coded // function. static constexpr bool getMaySupportMemoryTagging() { return BaseConfig::getMaySupportMemoryTagging(); } #define SECONDARY_REQUIRED_TEMPLATE_TYPE(NAME) \ template \ using NAME = typename AllocatorConfig::Secondary::template NAME; #include "allocator_config.def" struct CacheConfig { // TODO: Pass this flag through template argument to remove this hard-coded // function. static constexpr bool getMaySupportMemoryTagging() { return BaseConfig::getMaySupportMemoryTagging(); } #define SECONDARY_CACHE_OPTIONAL(TYPE, NAME, DEFAULT) \ OPTIONAL_TEMPLATE(TYPE, NAME, DEFAULT, Cache::NAME) \ static constexpr removeConst::type get##NAME() { \ return NAME##State::getValue(); \ } #include "allocator_config.def" }; // CacheConfig }; // SecondaryConfig #undef OPTIONAL_TEMPLATE #undef OPTIONAL_TEMPLATE_TYPE } // namespace scudo #endif // SCUDO_ALLOCATOR_CONFIG_WRAPPER_H_