NFC: make Slab, Mediumslab interfaces static

Going forward, this gives us explicit pointers with which to carry bounds
annotations.  Otherwise, assuming AuthPtr overloads operator->, a OOP-style call
like

    AuthPtr<Slab, Bounds> slab;
    slab->foo()

will create a `Slab* this` within the body of `Slab::foo`, leaving it unable to
see or propagate the Bounds annotation.  If it invokes callees that expect
`AuthPtr` arguments, it will therefore have to fabricate new `Bounds` unsafely.
This commit is contained in:
Nathaniel Filardo
2021-03-05 13:22:26 +00:00
committed by Matthew Parkinson
parent 49fefc3f83
commit 4f6cf8cb40
4 changed files with 73 additions and 64 deletions

View File

@@ -1081,7 +1081,8 @@ namespace snmalloc
auto meta = reinterpret_cast<Metaslab*>(sl.get_next());
auto& ffl = small_fast_free_lists[sizeclass];
return meta->alloc<zero_mem, typename MemoryProvider::Pal>(ffl, rsize);
return Metaslab::alloc<zero_mem, typename MemoryProvider::Pal>(
meta, ffl, rsize);
}
return small_alloc_rare<zero_mem, allow_reserve>(sizeclass, size);
}
@@ -1172,8 +1173,8 @@ namespace snmalloc
Slab* slab = alloc_slab<allow_reserve>(sizeclass);
if (slab == nullptr)
return nullptr;
bp = reinterpret_cast<SlabNext*>(
pointer_offset(slab, get_initial_offset(sizeclass, slab->is_short())));
bp = reinterpret_cast<SlabNext*>(pointer_offset(
slab, get_initial_offset(sizeclass, Metaslab::is_short(slab))));
return small_alloc_build_free_list<zero_mem, allow_reserve>(sizeclass);
}
@@ -1211,7 +1212,7 @@ namespace snmalloc
Superslab* super, Slab* slab, void* p, sizeclass_t sizeclass)
{
#ifdef CHECK_CLIENT
if (!slab->get_meta().is_start_of_object(p))
if (!Metaslab::is_start_of_object(&Slab::get_meta(slab), p))
{
error("Not deallocating start of an object");
}
@@ -1248,7 +1249,7 @@ namespace snmalloc
SNMALLOC_FAST_PATH void small_dealloc_offseted_inner(
Superslab* super, Slab* slab, void* p, sizeclass_t sizeclass)
{
if (likely(slab->dealloc_fast(super, p)))
if (likely(Slab::dealloc_fast(slab, super, p)))
return;
small_dealloc_offseted_slow(super, slab, p, sizeclass);
@@ -1259,7 +1260,7 @@ namespace snmalloc
{
bool was_full = super->is_full();
SlabList* sl = &small_classes[sizeclass];
Superslab::Action a = slab->dealloc_slow(sl, super, p);
Superslab::Action a = Slab::dealloc_slow(slab, sl, super, p);
if (likely(a == Superslab::NoSlabReturn))
return;
stats().sizeclass_dealloc_slab(sizeclass);
@@ -1326,9 +1327,10 @@ namespace snmalloc
if (slab != nullptr)
{
p = slab->alloc<zero_mem, typename MemoryProvider::Pal>(size);
p =
Mediumslab::alloc<zero_mem, typename MemoryProvider::Pal>(slab, size);
if (slab->full())
if (Mediumslab::full(slab))
sc->pop();
}
else
@@ -1349,9 +1351,10 @@ namespace snmalloc
slab->init(public_state(), sizeclass, rsize);
chunkmap().set_slab(slab);
p = slab->alloc<zero_mem, typename MemoryProvider::Pal>(size);
p =
Mediumslab::alloc<zero_mem, typename MemoryProvider::Pal>(slab, size);
if (!slab->full())
if (!Mediumslab::full(slab))
sc->insert(slab);
}
@@ -1423,9 +1426,9 @@ namespace snmalloc
{
MEASURE_TIME(medium_dealloc, 4, 16);
stats().sizeclass_dealloc(sizeclass);
bool was_full = slab->dealloc(p);
bool was_full = Mediumslab::dealloc(slab, p);
if (slab->empty())
if (Mediumslab::empty(slab))
{
if (!was_full)
{

View File

@@ -82,13 +82,13 @@ namespace snmalloc
}
template<ZeroMem zero_mem, SNMALLOC_CONCEPT(ConceptPAL) PAL>
void* alloc(size_t size)
static void* alloc(Mediumslab* self, size_t size)
{
SNMALLOC_ASSERT(!full());
SNMALLOC_ASSERT(!full(self));
uint16_t index = stack[head++];
void* p = pointer_offset(this, (static_cast<size_t>(index) << 8));
free--;
uint16_t index = self->stack[self->head++];
void* p = pointer_offset(self, (static_cast<size_t>(index) << 8));
self->free--;
if constexpr (zero_mem == YesZero)
PAL::zero(p, size);
@@ -98,33 +98,33 @@ namespace snmalloc
return p;
}
bool dealloc(void* p)
static bool dealloc(Mediumslab* self, void* p)
{
SNMALLOC_ASSERT(head > 0);
SNMALLOC_ASSERT(self->head > 0);
// Returns true if the Mediumslab was full before this deallocation.
bool was_full = full();
free++;
stack[--head] = pointer_to_index(p);
bool was_full = full(self);
self->free++;
self->stack[--(self->head)] = self->address_to_index(address_cast(p));
return was_full;
}
bool full()
static bool full(Mediumslab* self)
{
return free == 0;
return self->free == 0;
}
bool empty()
static bool empty(Mediumslab* self)
{
return head == 0;
return self->head == 0;
}
private:
uint16_t pointer_to_index(void* p)
uint16_t address_to_index(address_t p)
{
// Get the offset from the slab for a memory location.
return static_cast<uint16_t>(pointer_diff(this, p) >> 8);
return static_cast<uint16_t>((p - address_cast(this)) >> 8);
}
};
} // namespace snmalloc

View File

@@ -155,10 +155,10 @@ namespace snmalloc
return pointer_align_down<SUPERSLAB_SIZE>(p) == p;
}
bool is_start_of_object(void* p)
static bool is_start_of_object(Metaslab* self, void* p)
{
return is_multiple_of_sizeclass(
sizeclass_to_size(sizeclass),
sizeclass_to_size(self->sizeclass),
pointer_diff(p, pointer_align_up<SLAB_SIZE>(pointer_offset(p, 1))));
}
@@ -166,31 +166,35 @@ namespace snmalloc
* Takes a free list out of a slabs meta data.
* Returns the link as the allocation, and places the free list into the
* `fast_free_list` for further allocations.
*
* This is pre-factored to take an explicit self parameter so that we can
* eventually annotate that pointer with additional information.
*/
template<ZeroMem zero_mem, SNMALLOC_CONCEPT(ConceptPAL) PAL>
SNMALLOC_FAST_PATH void* alloc(FreeListHead& fast_free_list, size_t rsize)
static SNMALLOC_FAST_PATH void*
alloc(Metaslab* self, FreeListHead& fast_free_list, size_t rsize)
{
SNMALLOC_ASSERT(rsize == sizeclass_to_size(sizeclass));
SNMALLOC_ASSERT(!is_full());
SNMALLOC_ASSERT(rsize == sizeclass_to_size(self->sizeclass));
SNMALLOC_ASSERT(!self->is_full());
auto slab = get_slab(head);
debug_slab_invariant(slab);
auto slab = get_slab(self->head);
self->debug_slab_invariant(slab);
// Use first element as the allocation
SlabNext* h = head;
SlabNext* h = self->head;
// Put the rest in allocators small_class fast free list.
fast_free_list.value = Metaslab::follow_next(h);
head = nullptr;
self->head = nullptr;
// Treat stealing the free list as allocating it all.
needed = allocated;
remove();
set_full();
self->needed = self->allocated;
self->remove();
self->set_full();
void* p = remove_cache_friendly_offset(h, sizeclass);
SNMALLOC_ASSERT(is_start_of_object(p));
void* p = remove_cache_friendly_offset(h, self->sizeclass);
SNMALLOC_ASSERT(is_start_of_object(self, p));
debug_slab_invariant(slab);
self->debug_slab_invariant(slab);
if constexpr (zero_mem == YesZero)
{

View File

@@ -7,17 +7,17 @@ namespace snmalloc
class Slab
{
private:
uint16_t pointer_to_index(void* p)
uint16_t address_to_index(address_t p)
{
// Get the offset from the slab for a memory location.
return static_cast<uint16_t>(pointer_diff(this, p));
return static_cast<uint16_t>(p - address_cast(this));
}
public:
Metaslab& get_meta()
static Metaslab& get_meta(Slab* self)
{
Superslab* super = Superslab::get(this);
return super->get_meta(this);
Superslab* super = Superslab::get(self);
return super->get_meta(self);
}
/**
@@ -55,9 +55,13 @@ 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.
SNMALLOC_FAST_PATH bool dealloc_fast(Superslab* super, void* p)
//
// 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)
{
Metaslab& meta = super->get_meta(this);
Metaslab& meta = super->get_meta(self);
#ifdef CHECK_CLIENT
if (meta.is_unused())
error("Detected potential double free.");
@@ -85,11 +89,14 @@ 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.
SNMALLOC_SLOW_PATH typename Superslab::Action
dealloc_slow(SlabList* sl, Superslab* super, void* p)
//
// 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, SlabList* sl, Superslab* super, void* p)
{
Metaslab& meta = super->get_meta(this);
meta.debug_slab_invariant(this);
Metaslab& meta = super->get_meta(self);
meta.debug_slab_invariant(self);
if (meta.is_full())
{
@@ -97,10 +104,10 @@ namespace snmalloc
if (meta.allocated == 1)
{
// Dealloc on the superslab.
if (is_short())
if (Metaslab::is_short(self))
return super->dealloc_short_slab();
return super->dealloc_slab(this);
return super->dealloc_slab(self);
}
SNMALLOC_ASSERT(meta.head == nullptr);
SlabNext* psn = static_cast<SlabNext*>(p);
@@ -110,22 +117,17 @@ namespace snmalloc
// Push on the list of slabs for this sizeclass.
sl->insert_prev(&meta);
meta.debug_slab_invariant(this);
meta.debug_slab_invariant(self);
return Superslab::NoSlabReturn;
}
// Remove from the sizeclass list and dealloc on the superslab.
meta.remove();
if (is_short())
if (Metaslab::is_short(self))
return super->dealloc_short_slab();
return super->dealloc_slab(this);
}
bool is_short()
{
return Metaslab::is_short(this);
return super->dealloc_slab(self);
}
};
} // namespace snmalloc