Move to FreeObject::T<capptr::bound<>>

FreeObject itself is now just a namespace (but `friend`-ly); the actual free
list nodes are FreeObject::T-s that are templatized on the (perceived)
`capptr::bound<>` of the pointer they contain.  (These may differ across an
instantiated snmalloc; for example, in the sandboxing design, the in-sandbox
allocators may perceive all remotes to be full of `AllocUser` while the
privileged allocator of sandbox memory should perceive its remote queue as
holding `AllocUserWild` pointers in need of domestication.)

The interfaces to `FreeObject::T`-s now let us distinguish between the base and
inductive cases of the queues:

* in the inductive case, the pointer we hold to a `FreeObject::T` and its
  next_object have the same bounds

* in the base case, the pointer we hold has different bounds (typically,
  domesticated by contrast to the wild pointers in the queues).

To keep the clutter down a bit, we occasionally use raw pointers when we can be
reasonably certain that domestication is assured.  Moreover, we define some type
aliases, `FreeObject::{HeadPtr, QueuePtr, AtomicQueuePtr}`, that are slightly
more convenient labels than, e.g., `CapPtr<FreeObject::T<BQueue>, BView>`.
Because we are using template parameters for the `capptr::bound<>`s themselves,
we cannot use the aliases for `CapPtr<>s` provided within `capptr::`.

The two primary interfaces around free objects (`FreeListIter` AND
`FreeListBuilder`) are adjusted appropriately and their `BView` and `BQueue`
template paramters are plumbed explicitly around the tree.  This makes for quite
a bit of noise at the moment, but means that we'll be able to evolve parts of
the tree separately and can consider putting defaults in once that's done.
This commit is contained in:
Nathaniel Wesley Filardo
2021-09-17 14:32:14 +01:00
committed by Nathaniel Wesley Filardo
parent d76f5fdd28
commit e25db7b832
7 changed files with 391 additions and 169 deletions

View File

@@ -161,8 +161,9 @@ namespace snmalloc
{
// Manufacture an allocation to prime the queue
// Using an actual allocation removes a conditional from a critical path.
auto dummy = capptr::AllocFull<void>(small_alloc_one(MIN_ALLOC_SIZE))
.template as_static<FreeObject>();
auto dummy =
capptr::AllocFull<void>(small_alloc_one(MIN_ALLOC_SIZE))
.template as_static<FreeObject::T<capptr::bounds::AllocFull>>();
if (dummy == nullptr)
{
error("Critical error: Out-of-memory during initialisation.");
@@ -181,9 +182,11 @@ namespace snmalloc
SNMALLOC_ASSERT(attached_cache != nullptr);
// Use attached cache, and fill it if it is empty.
return attached_cache->template alloc<NoZero, SharedStateHandle>(
size, [&](sizeclass_t sizeclass, FreeListIter* fl) {
return small_alloc<NoZero>(sizeclass, *fl);
});
size,
[&](
sizeclass_t sizeclass,
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull>*
fl) { return small_alloc<NoZero>(sizeclass, *fl); });
}
static SNMALLOC_FAST_PATH void alloc_new_list(
@@ -244,7 +247,10 @@ namespace snmalloc
auto curr_ptr = start_ptr;
do
{
b.add(FreeObject::make(curr_ptr.as_void()), key, entropy);
b.add(
FreeObject::make<capptr::bounds::AllocFull>(curr_ptr.as_void()),
key,
entropy);
curr_ptr = curr_ptr->next;
} while (curr_ptr != start_ptr);
#else
@@ -252,7 +258,9 @@ namespace snmalloc
do
{
b.add(
Aal::capptr_bound<FreeObject, capptr::bounds::AllocFull>(p, rsize),
Aal::capptr_bound<
FreeObject::T<capptr::bounds::AllocFull>,
capptr::bounds::AllocFull>(p, rsize),
key);
p = pointer_offset(p, rsize);
} while (p < slab_end);
@@ -264,7 +272,7 @@ namespace snmalloc
ChunkRecord* clear_slab(Metaslab* meta, sizeclass_t sizeclass)
{
auto& key = entropy.get_free_list_key();
FreeListIter fl;
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull> fl;
auto more = meta->free_queue.close(fl, key);
UNUSED(more);
void* p = finish_alloc_no_zero(fl.take(key), sizeclass);
@@ -426,7 +434,9 @@ namespace snmalloc
* need_post will be set to true, if capacity is exceeded.
*/
void handle_dealloc_remote(
const MetaEntry& entry, capptr::AllocFull<FreeObject> p, bool& need_post)
const MetaEntry& entry,
FreeObject::QueuePtr<capptr::bounds::AllocFull> p,
bool& need_post)
{
// TODO this needs to not double count stats
// TODO this needs to not double revoke if using MTE
@@ -580,7 +590,8 @@ namespace snmalloc
Metaslab::is_start_of_object(entry.get_sizeclass(), address_cast(p)),
"Not deallocating start of an object");
auto cp = capptr::AllocFull<FreeObject>(reinterpret_cast<FreeObject*>(p));
auto cp = FreeObject::QueuePtr<capptr::bounds::AllocFull>(
reinterpret_cast<FreeObject::T<capptr::bounds::AllocFull>*>(p));
auto& key = entropy.get_free_list_key();
@@ -591,8 +602,10 @@ namespace snmalloc
}
template<ZeroMem zero_mem>
SNMALLOC_SLOW_PATH void*
small_alloc(sizeclass_t sizeclass, FreeListIter& fast_free_list)
SNMALLOC_SLOW_PATH void* small_alloc(
sizeclass_t sizeclass,
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull>&
fast_free_list)
{
size_t rsize = sizeclass_to_size(sizeclass);
@@ -650,7 +663,10 @@ namespace snmalloc
template<ZeroMem zero_mem>
SNMALLOC_SLOW_PATH void* small_alloc_slow(
sizeclass_t sizeclass, FreeListIter& fast_free_list, size_t rsize)
sizeclass_t sizeclass,
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull>&
fast_free_list,
size_t rsize)
{
// No existing free list get a new slab.
size_t slab_size = sizeclass_to_slab_size(sizeclass);
@@ -712,6 +728,7 @@ namespace snmalloc
auto& entry = SharedStateHandle::Pagemap::get_metaentry(
backend_state_ptr(), snmalloc::address_cast(p));
handle_dealloc_remote(entry, p, need_post);
// XXX n is not known to be domesticated
p = n;
}
}