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:
committed by
Matthew Parkinson
parent
49fefc3f83
commit
4f6cf8cb40
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user