Metaslab: add MetaCommon field
This preserves the chunk pointer through the use of a chunk as a slab. It does grow the structure by one pointer, but on non-CHERI it is still padded to 64 bytes, even with CHECK_CLIENT guards in place: 0: MetaCommon chunk pointer 8: next pointer 16: builder head[0] 24: builder head[1] 32: builder tail[0] 40: builder tail[1] 48: builder length[0] (uint16_t) 50: builder length[1] (uint16_t) 52: padding (4 bytes) 56: needed (uint16_t) 58: sleeping (bool) (Sadly, on CHERI, even without CHECK_CLIENT guards and with no padding, there are now four pointers in the structure -- chunk, next, head, tail -- plus five extra bytes. We will likely wish to explore encoding the head and tail offsets relative to the chunk pointer.) This lets us remove the "subversive amplification" in dealloc() in favor of just preserving the chunk pointer. Speaking of, be sure to assign that in all the right places, and ASSERT that we've got it right.
This commit is contained in:
committed by
Nathaniel Wesley Filardo
parent
6c115eec18
commit
599ae0e632
@@ -87,6 +87,8 @@ namespace snmalloc
|
||||
return {p, nullptr};
|
||||
}
|
||||
|
||||
meta->meta_common.chunk = p;
|
||||
|
||||
MetaEntry t(meta, remote, sizeclass);
|
||||
Pagemap::set_metaentry(local_state, address_cast(p), size, t);
|
||||
return {p, meta};
|
||||
|
||||
@@ -321,13 +321,16 @@ namespace snmalloc
|
||||
// have the whole chunk.
|
||||
auto start_of_slab = pointer_align_down<void>(
|
||||
p, snmalloc::sizeclass_to_slab_size(sizeclass));
|
||||
// TODO Add bounds correctly here
|
||||
chunk_record->meta_common.chunk =
|
||||
capptr::Chunk<void>(start_of_slab.unsafe_ptr());
|
||||
|
||||
SNMALLOC_ASSERT(
|
||||
address_cast(start_of_slab) ==
|
||||
address_cast(chunk_record->meta_common.chunk));
|
||||
|
||||
#ifdef SNMALLOC_TRACING
|
||||
std::cout << "Slab " << start_of_slab.unsafe_ptr()
|
||||
<< " is unused, Object sizeclass " << sizeclass << std::endl;
|
||||
#else
|
||||
UNUSED(start_of_slab);
|
||||
#endif
|
||||
return chunk_record;
|
||||
}
|
||||
|
||||
@@ -536,15 +536,10 @@ namespace snmalloc
|
||||
|
||||
ChunkRecord* slab_record =
|
||||
reinterpret_cast<ChunkRecord*>(entry.get_metaslab());
|
||||
/*
|
||||
* StrictProvenance TODO: this is a subversive amplification. p_tame is
|
||||
* tame but Alloc-bounded, but we're coercing it to Chunk-bounded. We
|
||||
* should, instead, not be storing ->chunk here, but should be keeping
|
||||
* a CapPtr<void, Chunk> to this region internally even while it's
|
||||
* allocated.
|
||||
*/
|
||||
slab_record->meta_common.chunk =
|
||||
capptr::Chunk<void>(p_tame.unsafe_ptr());
|
||||
|
||||
SNMALLOC_ASSERT(
|
||||
address_cast(slab_record->meta_common.chunk) == address_cast(p_tame));
|
||||
|
||||
check_init(
|
||||
[](
|
||||
CoreAlloc* core_alloc,
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
|
||||
namespace snmalloc
|
||||
{
|
||||
/**
|
||||
* A guaranteed type-stable sub-structure of all metadata referenced by the
|
||||
* Pagemap. Use-specific structures (Metaslab, ChunkRecord) are expected to
|
||||
* have this at offset zero so that, even in the face of concurrent mutation
|
||||
* and reuse of the memory backing that metadata, the types of these fields
|
||||
* remain fixed.
|
||||
*/
|
||||
struct MetaCommon
|
||||
{
|
||||
capptr::Chunk<void> chunk;
|
||||
@@ -18,6 +25,8 @@ namespace snmalloc
|
||||
class alignas(CACHELINE_SIZE) Metaslab
|
||||
{
|
||||
public:
|
||||
MetaCommon meta_common;
|
||||
|
||||
// Used to link metaslabs together in various other data-structures.
|
||||
Metaslab* next{nullptr};
|
||||
|
||||
@@ -186,6 +195,11 @@ namespace snmalloc
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(std::is_standard_layout_v<Metaslab>);
|
||||
static_assert(
|
||||
offsetof(Metaslab, meta_common) == 0,
|
||||
"ChunkRecord and Metaslab must share a common prefix");
|
||||
|
||||
/**
|
||||
* Entry stored in the pagemap.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user