diff --git a/src/snmalloc/mem/corealloc.h b/src/snmalloc/mem/corealloc.h index cb70f5d77..e2a99f2c5 100644 --- a/src/snmalloc/mem/corealloc.h +++ b/src/snmalloc/mem/corealloc.h @@ -621,8 +621,7 @@ namespace snmalloc template< typename Config_ = Config, typename = std::enable_if_t> - CoreAllocator(Range& spare, LocalCache* cache) - : attached_cache(cache) + CoreAllocator(Range& spare) { init(spare); } @@ -1015,9 +1014,42 @@ namespace snmalloc } }; + template + class ConstructCoreAlloc + { + using CA = CoreAllocator; + + public: + static capptr::Alloc make() + { + size_t size = sizeof(CA); + size_t round_sizeof = Aal::capptr_size_round(size); + size_t request_size = bits::next_pow2(round_sizeof); + size_t spare = request_size - round_sizeof; + + auto raw = + Config::Backend::template alloc_meta_data(nullptr, request_size); + + if (raw == nullptr) + { + Config::Pal::error("Failed to initialise thread local allocator."); + } + + capptr::Alloc spare_start = pointer_offset(raw, round_sizeof); + Range r{spare_start, spare}; + + auto p = capptr::Alloc::unsafe_from(new (raw.unsafe_ptr()) CA(r)); + + // Remove excess from the bounds. + p = Aal::capptr_bound(p, round_sizeof); + return p; + } + }; + /** * Use this alias to access the pool of allocators throughout snmalloc. */ template - using AllocPool = Pool, Config, Config::pool>; + using AllocPool = + Pool, ConstructCoreAlloc, Config::pool>; } // namespace snmalloc diff --git a/src/snmalloc/mem/localalloc.h b/src/snmalloc/mem/localalloc.h index 75be56ecc..e26243a9b 100644 --- a/src/snmalloc/mem/localalloc.h +++ b/src/snmalloc/mem/localalloc.h @@ -393,7 +393,7 @@ namespace snmalloc // Initialise the global allocator structures ensure_init(); // Grab an allocator for this thread. - init(AllocPool::acquire(&(this->local_cache))); + init(AllocPool::acquire()); } // Return all state in the fast allocator and release the underlying diff --git a/src/snmalloc/mem/pool.h b/src/snmalloc/mem/pool.h index cbcbdb12d..8db58eccc 100644 --- a/src/snmalloc/mem/pool.h +++ b/src/snmalloc/mem/pool.h @@ -22,7 +22,7 @@ namespace snmalloc { template< typename TT, - SNMALLOC_CONCEPT(IsConfig) Config, + SNMALLOC_CONCEPT(Constructable) Construct, PoolState& get_state()> friend class Pool; @@ -45,50 +45,10 @@ namespace snmalloc * SingletonPoolState::pool is the default provider for the PoolState within * the Pool class. */ - template + template class SingletonPoolState { - /** - * SFINAE helper. Matched only if `T` implements `ensure_init`. Calls it - * if it exists. - */ - template - SNMALLOC_FAST_PATH static auto call_ensure_init(SharedStateHandle_*, int) - -> decltype(SharedStateHandle_::ensure_init()) - { - static_assert( - std::is_same::value, - "SFINAE parameter, should only be used with Config"); - SharedStateHandle_::ensure_init(); - } - - /** - * SFINAE helper. Matched only if `T` does not implement `ensure_init`. - * Does nothing if called. - */ - template - SNMALLOC_FAST_PATH static auto call_ensure_init(SharedStateHandle_*, long) - { - static_assert( - std::is_same::value, - "SFINAE parameter, should only be used with Config"); - } - - /** - * Call `Config::ensure_init()` if it is implemented, do nothing - * otherwise. - */ - SNMALLOC_FAST_PATH static void ensure_init() - { - call_ensure_init(nullptr, 0); - } - - static void make_pool(PoolState*) noexcept - { - ensure_init(); - // Default initializer already called on PoolState, no need to use - // placement new. - } + static void make_pool(PoolState*) noexcept {} public: /** @@ -101,6 +61,22 @@ namespace snmalloc } }; + /** + * @brief Default construct helper for the pool. Just uses `new`. This can't + * be used by the allocator pool as it has not created memory yet. + * + * @tparam T + */ + template + class DefaultConstruct + { + public: + static capptr::Alloc make() + { + return capptr::Alloc::unsafe_from(new T()); + } + }; + /** * Wrapper class to access a pool of a particular type of object. * @@ -116,13 +92,12 @@ namespace snmalloc */ template< typename T, - SNMALLOC_CONCEPT(IsConfig) Config, - PoolState& get_state() = SingletonPoolState::pool> + SNMALLOC_CONCEPT(Constructable) ConstructT = DefaultConstruct, + PoolState& get_state() = SingletonPoolState::pool> class Pool { public: - template - static T* acquire(Args&&... args) + static T* acquire() { PoolState& pool = get_state(); { @@ -141,26 +116,7 @@ namespace snmalloc } } - size_t request_size = bits::next_pow2(sizeof(T)); - size_t round_sizeof = Aal::capptr_size_round(sizeof(T)); - size_t spare = request_size - round_sizeof; - - auto raw = - Config::Backend::template alloc_meta_data(nullptr, request_size); - - if (raw == nullptr) - { - Config::Pal::error("Failed to initialise thread local allocator."); - } - - capptr::Alloc spare_start = pointer_offset(raw, round_sizeof); - Range r{spare_start, spare}; - - auto p = capptr::Alloc::unsafe_from( - new (raw.unsafe_ptr()) T(r, std::forward(args)...)); - - // Remove excess from the permissions. - p = Aal::capptr_bound(p, round_sizeof); + auto p = ConstructT::make(); FlagLock f(pool.lock); p->list_next = pool.list; diff --git a/src/snmalloc/mem/pooled.h b/src/snmalloc/mem/pooled.h index 7fb0ce33e..4e7c76884 100644 --- a/src/snmalloc/mem/pooled.h +++ b/src/snmalloc/mem/pooled.h @@ -15,6 +15,15 @@ namespace snmalloc template class PoolState; +#ifdef __cpp_concepts + template + concept Constructable = requires() { + { + C::make() + } -> ConceptSame>; + }; +#endif // __cpp_concepts + /** * Required to be implemented by all types that are pooled. * @@ -29,7 +38,7 @@ namespace snmalloc public: template< typename TT, - SNMALLOC_CONCEPT(IsConfig) Config, + SNMALLOC_CONCEPT(Constructable) Construct, PoolState& get_state()> friend class Pool; diff --git a/src/test/func/cheri/cheri.cc b/src/test/func/cheri/cheri.cc index 4efaec6b7..cde8be071 100644 --- a/src/test/func/cheri/cheri.cc +++ b/src/test/func/cheri/cheri.cc @@ -133,8 +133,7 @@ int main() static_assert( std::is_same_v>); - LocalCache lc{&StandardConfig::unused_remote}; - auto* ca = AllocPool::acquire(&lc); + auto* ca = AllocPool::acquire(); SNMALLOC_CHECK(cap_len_is(ca, sizeof(*ca))); SNMALLOC_CHECK(cap_vmem_perm_is(ca, false)); diff --git a/src/test/func/pool/pool.cc b/src/test/func/pool/pool.cc index 600118d58..2ed960a45 100644 --- a/src/test/func/pool/pool.cc +++ b/src/test/func/pool/pool.cc @@ -11,26 +11,25 @@ struct PoolAEntry : Pooled { int field; - PoolAEntry(Range&) : field(1){}; + PoolAEntry() : field(1){}; }; -using PoolA = Pool; +using PoolA = Pool; struct PoolBEntry : Pooled { int field; - PoolBEntry(Range&) : field(0){}; - PoolBEntry(Range&, int f) : field(f){}; + PoolBEntry() : field(0){}; }; -using PoolB = Pool; +using PoolB = Pool; struct PoolLargeEntry : Pooled { std::array payload; - PoolLargeEntry(Range&) + PoolLargeEntry() { printf("."); fflush(stdout); @@ -41,18 +40,18 @@ struct PoolLargeEntry : Pooled }; }; -using PoolLarge = Pool; +using PoolLarge = Pool; template struct PoolSortEntry : Pooled> { int field; - PoolSortEntry(Range&, int f) : field(f){}; + PoolSortEntry() : field(1){}; }; template -using PoolSort = Pool, Alloc::Config>; +using PoolSort = Pool>; void test_alloc() { @@ -73,13 +72,8 @@ void test_constructor() SNMALLOC_CHECK(ptr2 != nullptr); SNMALLOC_CHECK(ptr2->field == 0); - auto ptr3 = PoolB::acquire(1); - SNMALLOC_CHECK(ptr3 != nullptr); - SNMALLOC_CHECK(ptr3->field == 1); - PoolA::release(ptr1); PoolB::release(ptr2); - PoolB::release(ptr3); } void test_alloc_many() @@ -181,8 +175,8 @@ void test_sort() // This test checks that `sort` puts the elements in the right order, // so it is the same as if they had been allocated in that order. - auto a1 = PoolSort::acquire(1); - auto a2 = PoolSort::acquire(1); + auto a1 = PoolSort::acquire(); + auto a2 = PoolSort::acquire(); auto position1 = position(a1); auto position2 = position(a2); @@ -201,8 +195,8 @@ void test_sort() PoolSort::sort(); - auto b1 = PoolSort::acquire(1); - auto b2 = PoolSort::acquire(1); + auto b1 = PoolSort::acquire(); + auto b2 = PoolSort::acquire(); SNMALLOC_CHECK(position1 == position(b1)); SNMALLOC_CHECK(position2 == position(b2));