diff --git a/src/snmalloc/backend/backend.h b/src/snmalloc/backend/backend.h index dda05abd8..5486e42aa 100644 --- a/src/snmalloc/backend/backend.h +++ b/src/snmalloc/backend/backend.h @@ -98,11 +98,12 @@ namespace snmalloc #endif // Set up source of memory - using P = PalRange; using Base = std::conditional_t< fixed_range, EmptyRange, - PagemapRegisterRange>; + Pipe< + PalRange, + PagemapRegisterRange>>; static constexpr size_t MinBaseSizeBits() { @@ -117,50 +118,56 @@ namespace snmalloc } // Global range of memory - using GlobalR = GlobalRange>>; + using GlobalR = Pipe< + Base, + LargeBuddyRange<24, bits::BITS - 1, Pagemap, MinBaseSizeBits()>, + LogRange<2>, + GlobalRange<>>; #ifdef SNMALLOC_META_PROTECTED // Introduce two global ranges, so we don't mix Object and Meta - using CentralObjectRange = GlobalRange>>; - using CentralMetaRange = GlobalRange, // Use SubRange to introduce guard pages. - 24, - bits::BITS - 1, - Pagemap, - MinBaseSizeBits()>>>; + using CentralObjectRange = Pipe< + GlobalR, + LargeBuddyRange<24, bits::BITS - 1, Pagemap, MinBaseSizeBits()>, + LogRange<3>, + GlobalRange<>>; + + using CentralMetaRange = Pipe< + GlobalR, + SubRange, // Use SubRange to introduce guard pages. + LargeBuddyRange<24, bits::BITS - 1, Pagemap, MinBaseSizeBits()>, + LogRange<4>, + GlobalRange<>>; // Source for object allocations - using StatsObject = StatsRange>; + using StatsObject = + Pipe, StatsRange<>>; + using ObjectRange = - LogRange<5, LargeBuddyRange>; + Pipe, LogRange<5>>; + + using StatsMeta = Pipe, StatsRange<>>; - using StatsMeta = StatsRange>; + using MetaRange = Pipe< + StatsMeta, + LargeBuddyRange<21 - 6, bits::BITS - 1, Pagemap>, + SmallBuddyRange<>>; - using MetaRange = SmallBuddyRange< - LargeBuddyRange>; // Create global range that can service small meta-data requests. // Don't want to add this to the CentralMetaRange to move Commit outside the // lock on the common case. - using GlobalMetaRange = GlobalRange>; + using GlobalMetaRange = Pipe, GlobalRange<>>; using Stats = StatsCombiner; #else // Source for object allocations and metadata // No separation between the two - using Stats = StatsRange; - using ObjectRange = SmallBuddyRange< - LargeBuddyRange, 21, 21, Pagemap>>; - using GlobalMetaRange = GlobalRange; + using Stats = Pipe>; + using ObjectRange = Pipe< + Stats, + CommitRange, + LargeBuddyRange<21, 21, Pagemap>, + SmallBuddyRange<>>; + using GlobalMetaRange = Pipe>; #endif struct LocalState diff --git a/src/snmalloc/backend_helpers/commitrange.h b/src/snmalloc/backend_helpers/commitrange.h index d2e6d54ff..c8d7c616c 100644 --- a/src/snmalloc/backend_helpers/commitrange.h +++ b/src/snmalloc/backend_helpers/commitrange.h @@ -1,15 +1,21 @@ #pragma once - #include "../pal/pal.h" +#include "empty_range.h" namespace snmalloc { - template + template class CommitRange { ParentRange parent{}; public: + /** + * We use a nested Apply type to enable a Pipe operation. + */ + template + using Apply = CommitRange; + static constexpr bool Aligned = ParentRange::Aligned; static constexpr bool ConcurrencySafe = ParentRange::ConcurrencySafe; diff --git a/src/snmalloc/backend_helpers/globalrange.h b/src/snmalloc/backend_helpers/globalrange.h index b21d4d08b..565b4f311 100644 --- a/src/snmalloc/backend_helpers/globalrange.h +++ b/src/snmalloc/backend_helpers/globalrange.h @@ -1,6 +1,7 @@ #pragma once #include "../ds/ds.h" +#include "empty_range.h" namespace snmalloc { @@ -8,7 +9,7 @@ namespace snmalloc * Makes the supplied ParentRange into a global variable, * and protects access with a lock. */ - template + template class GlobalRange { SNMALLOC_REQUIRE_CONSTINIT static inline ParentRange parent{}; @@ -20,6 +21,12 @@ namespace snmalloc SNMALLOC_REQUIRE_CONSTINIT static inline FlagWord spin_lock{}; public: + /** + * We use a nested Apply type to enable a Pipe operation. + */ + template + using Apply = GlobalRange; + static constexpr bool Aligned = ParentRange::Aligned; static constexpr bool ConcurrencySafe = true; diff --git a/src/snmalloc/backend_helpers/largebuddyrange.h b/src/snmalloc/backend_helpers/largebuddyrange.h index b81e392ef..f53fc0ba8 100644 --- a/src/snmalloc/backend_helpers/largebuddyrange.h +++ b/src/snmalloc/backend_helpers/largebuddyrange.h @@ -3,6 +3,7 @@ #include "../ds/ds.h" #include "../mem/mem.h" #include "buddy.h" +#include "empty_range.h" #include "range_helpers.h" #include @@ -183,11 +184,11 @@ namespace snmalloc * for */ template< - typename ParentRange, size_t REFILL_SIZE_BITS, size_t MAX_SIZE_BITS, SNMALLOC_CONCEPT(ConceptBuddyRangeMeta) Pagemap, - size_t MIN_REFILL_SIZE_BITS = 0> + size_t MIN_REFILL_SIZE_BITS = 0, + typename ParentRange = EmptyRange> class LargeBuddyRange { ParentRange parent{}; @@ -327,6 +328,17 @@ namespace snmalloc } public: + /** + * We use a nested Apply type to enable a Pipe operation. + */ + template + using Apply = LargeBuddyRange< + REFILL_SIZE_BITS, + MAX_SIZE_BITS, + Pagemap, + MIN_REFILL_SIZE_BITS, + ParentRange2>; + static constexpr bool Aligned = true; static constexpr bool ConcurrencySafe = false; diff --git a/src/snmalloc/backend_helpers/logrange.h b/src/snmalloc/backend_helpers/logrange.h index 432e8772c..8d5ef709a 100644 --- a/src/snmalloc/backend_helpers/logrange.h +++ b/src/snmalloc/backend_helpers/logrange.h @@ -1,5 +1,7 @@ #pragma once +#include "empty_range.h" + namespace snmalloc { /** @@ -8,12 +10,18 @@ namespace snmalloc * * ParentRange is what the range is logging calls to. */ - template + template class LogRange { ParentRange parent{}; public: + /** + * We use a nested Apply type to enable a Pipe operation. + */ + template + using Apply = LogRange; + static constexpr bool Aligned = ParentRange::Aligned; static constexpr bool ConcurrencySafe = ParentRange::ConcurrencySafe; diff --git a/src/snmalloc/backend_helpers/pagemapregisterrange.h b/src/snmalloc/backend_helpers/pagemapregisterrange.h index de60dd8da..e75b72fe3 100644 --- a/src/snmalloc/backend_helpers/pagemapregisterrange.h +++ b/src/snmalloc/backend_helpers/pagemapregisterrange.h @@ -1,18 +1,25 @@ #pragma once #include "../pal/pal.h" +#include "empty_range.h" namespace snmalloc { template< SNMALLOC_CONCEPT(ConceptBackendMetaRange) Pagemap, - typename ParentRange, - bool CanConsolidate = true> + bool CanConsolidate = true, + typename ParentRange = EmptyRange> class PagemapRegisterRange { ParentRange state{}; public: + /** + * We use a nested Apply type to enable a Pipe operation. + */ + template + using Apply = PagemapRegisterRange; + constexpr PagemapRegisterRange() = default; static constexpr bool Aligned = ParentRange::Aligned; diff --git a/src/snmalloc/backend_helpers/range_helpers.h b/src/snmalloc/backend_helpers/range_helpers.h index a9dc43c86..db1a12fb6 100644 --- a/src/snmalloc/backend_helpers/range_helpers.h +++ b/src/snmalloc/backend_helpers/range_helpers.h @@ -34,4 +34,39 @@ namespace snmalloc length -= align; } } + + /** + * Forward definition to allow multiple template specialisations. + * + * This struct is used to recursively compose ranges. + */ + template + struct PipeImpl; + + /** + * Base case of one range that needs nothing. + */ + template + struct PipeImpl + { + using result = Only; + }; + + /** + * Recursive case of applying a base range as an argument to the + * next, and then using that as the new base range. + */ + template + struct PipeImpl + { + public: + using result = + typename PipeImpl, Rest...>::result; + }; + + /** + * Nice type so the caller doesn't need to call result explicitly. + */ + template + using Pipe = typename PipeImpl::result; } // namespace snmalloc diff --git a/src/snmalloc/backend_helpers/smallbuddyrange.h b/src/snmalloc/backend_helpers/smallbuddyrange.h index b212323b5..b19919050 100644 --- a/src/snmalloc/backend_helpers/smallbuddyrange.h +++ b/src/snmalloc/backend_helpers/smallbuddyrange.h @@ -1,6 +1,7 @@ #pragma once #include "../pal/pal.h" +#include "empty_range.h" #include "range_helpers.h" namespace snmalloc @@ -142,7 +143,7 @@ namespace snmalloc } }; - template + template class SmallBuddyRange { ParentRange parent{}; @@ -179,6 +180,12 @@ namespace snmalloc } public: + /** + * We use a nested Apply type to enable a Pipe operation. + */ + template + using Apply = SmallBuddyRange; + static constexpr bool Aligned = true; static_assert(ParentRange::Aligned, "ParentRange must be aligned"); diff --git a/src/snmalloc/backend_helpers/statsrange.h b/src/snmalloc/backend_helpers/statsrange.h index 98a06aec3..49b18f729 100644 --- a/src/snmalloc/backend_helpers/statsrange.h +++ b/src/snmalloc/backend_helpers/statsrange.h @@ -1,5 +1,7 @@ #pragma once +#include "empty_range.h" + #include namespace snmalloc @@ -7,7 +9,7 @@ namespace snmalloc /** * Used to measure memory usage. */ - template + template class StatsRange { ParentRange parent{}; @@ -16,6 +18,12 @@ namespace snmalloc static inline std::atomic peak_usage{}; public: + /** + * We use a nested Apply type to enable a Pipe operation. + */ + template + using Apply = StatsRange; + static constexpr bool Aligned = ParentRange::Aligned; static constexpr bool ConcurrencySafe = ParentRange::ConcurrencySafe; diff --git a/src/snmalloc/backend_helpers/subrange.h b/src/snmalloc/backend_helpers/subrange.h index 3c6617d7c..f345806c2 100644 --- a/src/snmalloc/backend_helpers/subrange.h +++ b/src/snmalloc/backend_helpers/subrange.h @@ -1,5 +1,6 @@ #pragma once #include "../mem/mem.h" +#include "empty_range.h" namespace snmalloc { @@ -8,12 +9,18 @@ namespace snmalloc * 2^RATIO_BITS. Will not return a the block at the start or * the end of the large allocation. */ - template + template class SubRange { ParentRange parent{}; public: + /** + * We use a nested Apply type to enable a Pipe operation. + */ + template + using Apply = SubRange; + constexpr SubRange() = default; static constexpr bool Aligned = ParentRange::Aligned;