SP: start plumbing CapPtr<>s
This commit is contained in:
committed by
Nathaniel Wesley Filardo
parent
313a682faf
commit
005f5787ef
@@ -17,9 +17,12 @@ namespace snmalloc
|
||||
}
|
||||
|
||||
public:
|
||||
static Metaslab& get_meta(Slab* self)
|
||||
template<capptr_bounds B>
|
||||
static CapPtr<Metaslab, B> get_meta(CapPtr<Slab, B> self)
|
||||
{
|
||||
Superslab* super = Superslab::get(self);
|
||||
static_assert(B == CBArena || B == CBChunk);
|
||||
|
||||
auto super = Superslab::get(self);
|
||||
return super->get_meta(self);
|
||||
}
|
||||
|
||||
@@ -30,12 +33,12 @@ namespace snmalloc
|
||||
* page.
|
||||
*/
|
||||
static SNMALLOC_FAST_PATH void alloc_new_list(
|
||||
void*& bumpptr,
|
||||
CapPtr<void, CBArena>& bumpptr,
|
||||
FreeListIter& fast_free_list,
|
||||
size_t rsize,
|
||||
LocalEntropy& entropy)
|
||||
{
|
||||
void* slab_end = pointer_align_up<SLAB_SIZE>(pointer_offset(bumpptr, 1));
|
||||
auto slab_end = pointer_align_up<SLAB_SIZE>(pointer_offset(bumpptr, 1));
|
||||
|
||||
FreeListBuilder<false> b;
|
||||
SNMALLOC_ASSERT(b.empty());
|
||||
@@ -46,23 +49,27 @@ namespace snmalloc
|
||||
// Structure to represent the temporary list elements
|
||||
struct PreAllocObject
|
||||
{
|
||||
PreAllocObject* next;
|
||||
CapPtr<PreAllocObject, CBArena> next;
|
||||
};
|
||||
// The following code implements Sattolo's algorithm for generating
|
||||
// random cyclic permutations. This implementation is in the opposite
|
||||
// direction, so that the original space does not need initialising. This
|
||||
// is described as outside-in without citation on Wikipedia, appears to be
|
||||
// Folklore algorithm.
|
||||
PreAllocObject* curr = pointer_offset<PreAllocObject>(bumpptr, 0);
|
||||
auto curr =
|
||||
pointer_offset(bumpptr, 0).template as_static<PreAllocObject>();
|
||||
curr->next = curr;
|
||||
uint16_t count = 1;
|
||||
for (PreAllocObject* p = pointer_offset<PreAllocObject>(bumpptr, rsize);
|
||||
p < slab_end;
|
||||
p = pointer_offset<PreAllocObject>(p, rsize))
|
||||
for (auto p = pointer_offset(bumpptr, rsize)
|
||||
.template as_static<PreAllocObject>();
|
||||
p.as_void() < slab_end;
|
||||
p = pointer_offset(p, rsize).template as_static<PreAllocObject>())
|
||||
{
|
||||
size_t insert_index = entropy.sample(count);
|
||||
p->next = std::exchange(
|
||||
pointer_offset<PreAllocObject>(bumpptr, insert_index * rsize)->next,
|
||||
pointer_offset(bumpptr, insert_index * rsize)
|
||||
.template as_static<PreAllocObject>()
|
||||
->next,
|
||||
p);
|
||||
count++;
|
||||
}
|
||||
@@ -70,18 +77,18 @@ namespace snmalloc
|
||||
// Pick entry into space, and then build linked list by traversing cycle
|
||||
// to the start.
|
||||
auto start_index = entropy.sample(count);
|
||||
auto start_ptr =
|
||||
pointer_offset<PreAllocObject>(bumpptr, start_index * rsize);
|
||||
auto start_ptr = pointer_offset(bumpptr, start_index * rsize)
|
||||
.template as_static<PreAllocObject>();
|
||||
auto curr_ptr = start_ptr;
|
||||
do
|
||||
{
|
||||
b.add(curr_ptr, entropy);
|
||||
b.add(FreeObject::make(curr_ptr.as_void()), entropy);
|
||||
curr_ptr = curr_ptr->next;
|
||||
} while (curr_ptr != start_ptr);
|
||||
#else
|
||||
for (void* p = bumpptr; p < slab_end; p = pointer_offset<void>(p, rsize))
|
||||
for (auto p = bumpptr; p < slab_end; p = pointer_offset(p, rsize))
|
||||
{
|
||||
b.add(p, entropy);
|
||||
b.add(FreeObject::make(p.as_void()), entropy);
|
||||
}
|
||||
#endif
|
||||
// This code consumes everything up to slab_end.
|
||||
@@ -94,20 +101,20 @@ namespace snmalloc
|
||||
// Returns true, if it deallocation can proceed without changing any status
|
||||
// bits. Note that this does remove the use from the meta slab, so it
|
||||
// doesn't need doing on the slow path.
|
||||
//
|
||||
// This is pre-factored to take an explicit self parameter so that we can
|
||||
// eventually annotate that pointer with additional information.
|
||||
static SNMALLOC_FAST_PATH bool
|
||||
dealloc_fast(Slab* self, Superslab* super, void* p, LocalEntropy& entropy)
|
||||
static SNMALLOC_FAST_PATH bool dealloc_fast(
|
||||
CapPtr<Slab, CBArena> self,
|
||||
CapPtr<Superslab, CBArena> super,
|
||||
CapPtr<FreeObject, CBArena> p,
|
||||
LocalEntropy& entropy)
|
||||
{
|
||||
Metaslab& meta = super->get_meta(self);
|
||||
SNMALLOC_ASSERT(!meta.is_unused());
|
||||
auto meta = super->get_meta(self);
|
||||
SNMALLOC_ASSERT(!meta->is_unused());
|
||||
|
||||
if (unlikely(meta.return_object()))
|
||||
if (unlikely(meta->return_object()))
|
||||
return false;
|
||||
|
||||
// Update the head and the next pointer in the free list.
|
||||
meta.free_queue.add(p, entropy);
|
||||
meta->free_queue.add(p, entropy);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -116,23 +123,20 @@ namespace snmalloc
|
||||
// This does not need to remove the "use" as done by the fast path.
|
||||
// Returns a complex return code for managing the superslab meta data.
|
||||
// i.e. This deallocation could make an entire superslab free.
|
||||
//
|
||||
// This is pre-factored to take an explicit self parameter so that we can
|
||||
// eventually annotate that pointer with additional information.
|
||||
static SNMALLOC_SLOW_PATH typename Superslab::Action dealloc_slow(
|
||||
Slab* self,
|
||||
CapPtr<Slab, CBArena> self,
|
||||
SlabList* sl,
|
||||
Superslab* super,
|
||||
void* p,
|
||||
CapPtr<Superslab, CBArena> super,
|
||||
CapPtr<FreeObject, CBArena> p,
|
||||
LocalEntropy& entropy)
|
||||
{
|
||||
Metaslab& meta = super->get_meta(self);
|
||||
meta.debug_slab_invariant(self, entropy);
|
||||
auto meta = super->get_meta(self);
|
||||
meta->debug_slab_invariant(self, entropy);
|
||||
|
||||
if (meta.is_full())
|
||||
if (meta->is_full())
|
||||
{
|
||||
auto allocated = get_slab_capacity(
|
||||
meta.sizeclass(), Metaslab::is_short(Metaslab::get_slab(p)));
|
||||
meta->sizeclass(), Metaslab::is_short(Metaslab::get_slab(p)));
|
||||
// We are not on the sizeclass list.
|
||||
if (allocated == 1)
|
||||
{
|
||||
@@ -143,15 +147,15 @@ namespace snmalloc
|
||||
return super->dealloc_slab(self);
|
||||
}
|
||||
|
||||
meta.free_queue.add(p, entropy);
|
||||
meta->free_queue.add(p, entropy);
|
||||
// Remove trigger threshold from how many we need before we have fully
|
||||
// freed the slab.
|
||||
meta.needed() =
|
||||
allocated - meta.threshold_for_waking_slab(Metaslab::is_short(self));
|
||||
meta->needed() =
|
||||
allocated - meta->threshold_for_waking_slab(Metaslab::is_short(self));
|
||||
|
||||
// Push on the list of slabs for this sizeclass.
|
||||
sl->insert_prev(&meta);
|
||||
meta.debug_slab_invariant(self, entropy);
|
||||
sl->insert_prev(meta.template as_static<SlabLink>());
|
||||
meta->debug_slab_invariant(self, entropy);
|
||||
return Superslab::NoSlabReturn;
|
||||
}
|
||||
|
||||
@@ -160,7 +164,7 @@ namespace snmalloc
|
||||
// Check free list is well-formed on platforms with
|
||||
// integers as pointers.
|
||||
FreeListIter fl;
|
||||
meta.free_queue.close(fl, entropy);
|
||||
meta->free_queue.close(fl, entropy);
|
||||
|
||||
while (!fl.empty())
|
||||
{
|
||||
@@ -169,7 +173,7 @@ namespace snmalloc
|
||||
}
|
||||
#endif
|
||||
|
||||
meta.remove();
|
||||
meta->remove();
|
||||
|
||||
if (Metaslab::is_short(self))
|
||||
return super->dealloc_short_slab();
|
||||
|
||||
Reference in New Issue
Block a user