From 4f6cf8cb40f43d1ff271505637fd801d6248c620 Mon Sep 17 00:00:00 2001 From: Nathaniel Filardo Date: Fri, 5 Mar 2021 13:22:26 +0000 Subject: [PATCH] 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; 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. --- src/mem/alloc.h | 27 +++++++++++++++------------ src/mem/mediumslab.h | 32 ++++++++++++++++---------------- src/mem/metaslab.h | 34 +++++++++++++++++++--------------- src/mem/slab.h | 44 +++++++++++++++++++++++--------------------- 4 files changed, 73 insertions(+), 64 deletions(-) diff --git a/src/mem/alloc.h b/src/mem/alloc.h index 2f897c3..35184b3 100644 --- a/src/mem/alloc.h +++ b/src/mem/alloc.h @@ -1081,7 +1081,8 @@ namespace snmalloc auto meta = reinterpret_cast(sl.get_next()); auto& ffl = small_fast_free_lists[sizeclass]; - return meta->alloc(ffl, rsize); + return Metaslab::alloc( + meta, ffl, rsize); } return small_alloc_rare(sizeclass, size); } @@ -1172,8 +1173,8 @@ namespace snmalloc Slab* slab = alloc_slab(sizeclass); if (slab == nullptr) return nullptr; - bp = reinterpret_cast( - pointer_offset(slab, get_initial_offset(sizeclass, slab->is_short()))); + bp = reinterpret_cast(pointer_offset( + slab, get_initial_offset(sizeclass, Metaslab::is_short(slab)))); return small_alloc_build_free_list(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(size); + p = + Mediumslab::alloc(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(size); + p = + Mediumslab::alloc(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) { diff --git a/src/mem/mediumslab.h b/src/mem/mediumslab.h index 905d760..ee167f2 100644 --- a/src/mem/mediumslab.h +++ b/src/mem/mediumslab.h @@ -82,13 +82,13 @@ namespace snmalloc } template - 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(index) << 8)); - free--; + uint16_t index = self->stack[self->head++]; + void* p = pointer_offset(self, (static_cast(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(pointer_diff(this, p) >> 8); + return static_cast((p - address_cast(this)) >> 8); } }; } // namespace snmalloc diff --git a/src/mem/metaslab.h b/src/mem/metaslab.h index 86ea3d2..ac4f8b3 100644 --- a/src/mem/metaslab.h +++ b/src/mem/metaslab.h @@ -155,10 +155,10 @@ namespace snmalloc return pointer_align_down(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(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 - 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) { diff --git a/src/mem/slab.h b/src/mem/slab.h index 3d54d28..ae2f0eb 100644 --- a/src/mem/slab.h +++ b/src/mem/slab.h @@ -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(pointer_diff(this, p)); + return static_cast(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(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