Major refactor of snmalloc (#343)
# Pagemap The Pagemap now stores all the meta-data for the object allocation. The meta-data in the pagemap is effectively a triple of the sizeclass, the remote allocator, and a pointer to a 64 byte block of meta-data for this chunk of memory. By storing the pointer to a block, it allows the pagemap to handle multiple slab sizes without branching on the fast path. There is one entry in the pagemap per 16KiB of address space, but by using the same entry in the pagemap for 4 adjacent entries, then we can treat a 64KiB range can be treated as a single slab of allocations. This change also means there is almost no capability amplification required by the implementation on CHERI for finding meta-data. The only amplification is required, when we change the way a chunk is used to a size of object allocation. # Backend There is a second major aspect of the refactor that there is now a narrow API that abstracts the Pagemap, PAL and address space management. This should better enable the compartmentalisation and makes it easier to produce alternative backends for various research directions. This is a template parameter that can be used to specialised by the front-end in different ways. # Thread local state The thread local state has been refactored into two components, one (called 'localalloc') that is stored directly in the TLS and is constant initialised, and one that is allocated in the address space (called 'coreallloc') which is lazily created and pooled. # Difference This removes Superslabs/Medium slabs as there meta-data is now part of the pagemap.
This commit is contained in:
committed by
GitHub
parent
18d7cc99b6
commit
f0e2ab702a
@@ -1,31 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ds/bits.h"
|
||||
#include "../pal/pal.h"
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
// The CHECK_CLIENT macro is used to turn on minimal checking of the client
|
||||
// calling the API correctly.
|
||||
#if !defined(NDEBUG) && !defined(CHECK_CLIENT)
|
||||
# define CHECK_CLIENT
|
||||
#endif
|
||||
|
||||
SNMALLOC_FAST_PATH void check_client_impl(bool test, const char* const str)
|
||||
{
|
||||
#ifdef CHECK_CLIENT
|
||||
if (unlikely(!test))
|
||||
error(str);
|
||||
#else
|
||||
UNUSED(test);
|
||||
UNUSED(str);
|
||||
#endif
|
||||
}
|
||||
#ifdef CHECK_CLIENT
|
||||
# define check_client(test, str) check_client_impl(test, str)
|
||||
#else
|
||||
# define check_client(test, str)
|
||||
#endif
|
||||
|
||||
// 0 intermediate bits results in power of 2 small allocs. 1 intermediate
|
||||
// bit gives additional sizeclasses at the midpoint between each power of 2.
|
||||
// 2 intermediate bits gives 3 intermediate sizeclasses, etc.
|
||||
@@ -55,26 +34,6 @@ namespace snmalloc
|
||||
#endif
|
||||
;
|
||||
|
||||
// Specifies smaller slab and super slab sizes for address space
|
||||
// constrained scenarios.
|
||||
static constexpr size_t USE_LARGE_CHUNKS =
|
||||
#ifdef SNMALLOC_USE_LARGE_CHUNKS
|
||||
// In 32 bit uses smaller superslab.
|
||||
(bits::is64())
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
;
|
||||
|
||||
// Specifies even smaller slab and super slab sizes for open enclave.
|
||||
static constexpr size_t USE_SMALL_CHUNKS =
|
||||
#ifdef SNMALLOC_USE_SMALL_CHUNKS
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
;
|
||||
|
||||
enum DecommitStrategy
|
||||
{
|
||||
/**
|
||||
@@ -116,26 +75,24 @@ namespace snmalloc
|
||||
static constexpr size_t MIN_ALLOC_SIZE = 2 * sizeof(void*);
|
||||
static constexpr size_t MIN_ALLOC_BITS = bits::ctz_const(MIN_ALLOC_SIZE);
|
||||
|
||||
// Slabs are 64 KiB unless constrained to 16 or even 8 KiB
|
||||
static constexpr size_t SLAB_BITS =
|
||||
USE_SMALL_CHUNKS ? 13 : (USE_LARGE_CHUNKS ? 16 : 14);
|
||||
static constexpr size_t SLAB_SIZE = 1 << SLAB_BITS;
|
||||
static constexpr size_t SLAB_MASK = ~(SLAB_SIZE - 1);
|
||||
// Minimum slab size.
|
||||
static constexpr size_t MIN_CHUNK_BITS = 14;
|
||||
static constexpr size_t MIN_CHUNK_SIZE = bits::one_at_bit(MIN_CHUNK_BITS);
|
||||
|
||||
// Superslabs are composed of this many slabs. Slab offsets are encoded as
|
||||
// a byte, so the maximum count is 256. This must be a power of two to
|
||||
// allow fast masking to find a superslab start address.
|
||||
static constexpr size_t SLAB_COUNT_BITS =
|
||||
USE_SMALL_CHUNKS ? 5 : (USE_LARGE_CHUNKS ? 8 : 6);
|
||||
static constexpr size_t SLAB_COUNT = 1 << SLAB_COUNT_BITS;
|
||||
static constexpr size_t SUPERSLAB_SIZE = SLAB_SIZE * SLAB_COUNT;
|
||||
static constexpr size_t SUPERSLAB_MASK = ~(SUPERSLAB_SIZE - 1);
|
||||
static constexpr size_t SUPERSLAB_BITS = SLAB_BITS + SLAB_COUNT_BITS;
|
||||
// Minimum number of objects on a slab
|
||||
#ifdef CHECK_CLIENT
|
||||
static constexpr size_t MIN_OBJECT_COUNT = 13;
|
||||
#else
|
||||
static constexpr size_t MIN_OBJECT_COUNT = 4;
|
||||
#endif
|
||||
|
||||
static_assert((1ULL << SUPERSLAB_BITS) == SUPERSLAB_SIZE, "Sanity check");
|
||||
// Maximum size of an object that uses sizeclasses.
|
||||
static constexpr size_t MAX_SIZECLASS_BITS = 16;
|
||||
static constexpr size_t MAX_SIZECLASS_SIZE =
|
||||
bits::one_at_bit(MAX_SIZECLASS_BITS);
|
||||
|
||||
// Number of slots for remote deallocation.
|
||||
static constexpr size_t REMOTE_SLOT_BITS = 6;
|
||||
static constexpr size_t REMOTE_SLOT_BITS = 8;
|
||||
static constexpr size_t REMOTE_SLOTS = 1 << REMOTE_SLOT_BITS;
|
||||
static constexpr size_t REMOTE_MASK = REMOTE_SLOTS - 1;
|
||||
|
||||
@@ -145,12 +102,4 @@ namespace snmalloc
|
||||
static_assert(
|
||||
MIN_ALLOC_SIZE >= (sizeof(void*) * 2),
|
||||
"MIN_ALLOC_SIZE must be sufficient for two pointers");
|
||||
static_assert(
|
||||
SLAB_BITS <= (sizeof(uint16_t) * 8),
|
||||
"SLAB_BITS must not be more than the bits in a uint16_t");
|
||||
static_assert(
|
||||
SLAB_COUNT == bits::next_pow2_const(SLAB_COUNT),
|
||||
"SLAB_COUNT must be a power of 2");
|
||||
static_assert(
|
||||
SLAB_COUNT <= (UINT8_MAX + 1), "SLAB_COUNT must fit in a uint8_t");
|
||||
} // namespace snmalloc
|
||||
|
||||
Reference in New Issue
Block a user