Store a full pointer in the Metaslab
This improves the codegen.
This commit is contained in:
@@ -484,7 +484,7 @@ namespace snmalloc
|
||||
if (likely(size == PMSuperslab))
|
||||
{
|
||||
RemoteAllocator* target = super->get_allocator();
|
||||
Slab* slab = Slab::get(p);
|
||||
Slab* slab = Metaslab::get_slab(p);
|
||||
Metaslab& meta = super->get_meta(slab);
|
||||
|
||||
// Reading a remote sizeclass won't fail, since the other allocator
|
||||
@@ -552,7 +552,7 @@ namespace snmalloc
|
||||
Superslab* super = Superslab::get(p);
|
||||
if (size == PMSuperslab)
|
||||
{
|
||||
Slab* slab = Slab::get(p);
|
||||
Slab* slab = Metaslab::get_slab(p);
|
||||
Metaslab& meta = super->get_meta(slab);
|
||||
|
||||
sizeclass_t sc = meta.sizeclass;
|
||||
@@ -621,7 +621,7 @@ namespace snmalloc
|
||||
|
||||
// Reading a remote sizeclass won't fail, since the other allocator
|
||||
// can't reuse the slab, as we have no yet deallocated this pointer.
|
||||
Slab* slab = Slab::get(p);
|
||||
Slab* slab = Metaslab::get_slab(p);
|
||||
Metaslab& meta = super->get_meta(slab);
|
||||
|
||||
return sizeclass_to_size(meta.sizeclass);
|
||||
@@ -968,7 +968,7 @@ namespace snmalloc
|
||||
#endif
|
||||
if (likely(super->get_kind() == Super))
|
||||
{
|
||||
Slab* slab = Slab::get(p);
|
||||
Slab* slab = Metaslab::get_slab(p);
|
||||
Metaslab& meta = super->get_meta(slab);
|
||||
if (likely(p->target_id() == id()))
|
||||
{
|
||||
@@ -1000,7 +1000,7 @@ namespace snmalloc
|
||||
else
|
||||
{
|
||||
assert(likely(p->target_id() != id()));
|
||||
Slab* slab = Slab::get(p);
|
||||
Slab* slab = Metaslab::get_slab(p);
|
||||
Metaslab& meta = super->get_meta(slab);
|
||||
// Queue for remote dealloc elsewhere.
|
||||
remote.dealloc(p->target_id(), p, meta.sizeclass);
|
||||
@@ -1210,7 +1210,7 @@ namespace snmalloc
|
||||
small_dealloc(Superslab* super, void* p, sizeclass_t sizeclass)
|
||||
{
|
||||
#ifdef CHECK_CLIENT
|
||||
Slab* slab = Slab::get(p);
|
||||
Slab* slab = Metaslab::get_slab(p);
|
||||
if (!slab->is_start_of_object(super, p))
|
||||
{
|
||||
error("Not deallocating start of an object");
|
||||
@@ -1233,7 +1233,7 @@ namespace snmalloc
|
||||
SNMALLOC_FAST_PATH void small_dealloc_offseted_inner(
|
||||
Superslab* super, void* p, sizeclass_t sizeclass)
|
||||
{
|
||||
Slab* slab = Slab::get(p);
|
||||
Slab* slab = Metaslab::get_slab(p);
|
||||
if (likely(slab->dealloc_fast(super, p)))
|
||||
return;
|
||||
|
||||
@@ -1245,7 +1245,7 @@ namespace snmalloc
|
||||
{
|
||||
bool was_full = super->is_full();
|
||||
SlabList* sl = &small_classes[sizeclass];
|
||||
Slab* slab = Slab::get(p);
|
||||
Slab* slab = Metaslab::get_slab(p);
|
||||
Superslab::Action a =
|
||||
slab->dealloc_slow(sl, super, p, large_allocator.memory_provider);
|
||||
if (likely(a == Superslab::NoSlabReturn))
|
||||
|
||||
@@ -30,23 +30,15 @@ namespace snmalloc
|
||||
class Metaslab
|
||||
{
|
||||
public:
|
||||
// Ppinter to first free entry in this slab
|
||||
void* head;
|
||||
|
||||
// How many entries are not in the free list of slab.
|
||||
uint16_t used = 0;
|
||||
|
||||
// How many entries have been allocated from this slab.
|
||||
uint16_t allocated;
|
||||
|
||||
// Index of first entry in this slab that forms the free
|
||||
// list. The list entries are stored as the first pointer
|
||||
// in each unused object. The terminator is a pointer or
|
||||
// offset into the block with the bottom bit set. This means
|
||||
// I.e.
|
||||
// * an empty list has a head of 1.
|
||||
// * a one element list has an head contains an offset to this
|
||||
// this block, and then contains a pointer with the bottom
|
||||
// bit set.
|
||||
Mod<SLAB_SIZE, uint16_t> head;
|
||||
|
||||
// When a slab has free space it will be on the has space list for
|
||||
// that size class. We use an empty block in this slab to be the
|
||||
// doubly linked node into that size class's free list.
|
||||
@@ -80,13 +72,13 @@ namespace snmalloc
|
||||
bool is_full()
|
||||
{
|
||||
auto result = link == 1;
|
||||
assert(!result || head == 1);
|
||||
assert(!result || head == nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
void set_full()
|
||||
{
|
||||
assert(head == 1);
|
||||
assert(head == nullptr);
|
||||
assert(link != 1);
|
||||
link = 1;
|
||||
// Set used to 1, so that "sub_use" will return true after calling
|
||||
@@ -128,16 +120,19 @@ namespace snmalloc
|
||||
return *static_cast<void**>(node);
|
||||
}
|
||||
|
||||
bool valid_head(bool is_short)
|
||||
bool valid_head()
|
||||
{
|
||||
size_t size = sizeclass_to_size(sizeclass);
|
||||
size_t slab_start = get_initial_offset(sizeclass, is_short);
|
||||
size_t all_high_bits = ~static_cast<size_t>(1);
|
||||
size_t slab_end = (address_cast(head) | ~SLAB_MASK) + 1;
|
||||
uintptr_t allocation_start =
|
||||
remove_cache_friendly_offset(address_cast(head), sizeclass);
|
||||
|
||||
size_t head_start =
|
||||
remove_cache_friendly_offset(head & all_high_bits, sizeclass);
|
||||
return (slab_end - allocation_start) % size == 0;
|
||||
}
|
||||
|
||||
return ((head_start - slab_start) % size) == 0;
|
||||
static Slab* get_slab(void* p)
|
||||
{
|
||||
return pointer_cast<Slab>(address_cast(p) & SLAB_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,11 +147,15 @@ namespace snmalloc
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
size_t length = 0;
|
||||
void* curr = (head == 1) ? nullptr : pointer_offset(slab, head);
|
||||
void* curr_slow = (head == 1) ? nullptr : pointer_offset(slab, head);
|
||||
void* curr = head;
|
||||
void* curr_slow = head;
|
||||
bool both = false;
|
||||
while (curr != nullptr)
|
||||
{
|
||||
if (get_slab(curr) != slab)
|
||||
{
|
||||
error("Free list corruption, not correct slab.");
|
||||
}
|
||||
curr = follow_next(curr);
|
||||
if (both)
|
||||
{
|
||||
@@ -195,7 +194,6 @@ namespace snmalloc
|
||||
size_t offset = get_initial_offset(sizeclass, is_short);
|
||||
size_t accounted_for = used * size + offset;
|
||||
|
||||
|
||||
// Block is not full
|
||||
assert(SLAB_SIZE > accounted_for);
|
||||
|
||||
@@ -204,7 +202,7 @@ namespace snmalloc
|
||||
UNUSED(length);
|
||||
|
||||
// Walk bump-free-list-segment accounting for unused space
|
||||
void* curr = (head == 1) ? nullptr : pointer_offset(slab, head);
|
||||
void* curr = head;
|
||||
while (curr != nullptr)
|
||||
{
|
||||
// Check we are looking at a correctly aligned block
|
||||
|
||||
@@ -153,8 +153,8 @@ namespace snmalloc
|
||||
return p = (void*)((uintptr_t)p & mask);
|
||||
}
|
||||
|
||||
SNMALLOC_FAST_PATH static uint16_t
|
||||
remove_cache_friendly_offset(uint16_t relative, sizeclass_t sizeclass)
|
||||
SNMALLOC_FAST_PATH static uintptr_t
|
||||
remove_cache_friendly_offset(uintptr_t relative, sizeclass_t sizeclass)
|
||||
{
|
||||
size_t mask = sizeclass_to_inverse_cache_friendly_mask(sizeclass);
|
||||
return relative & mask;
|
||||
@@ -167,8 +167,8 @@ namespace snmalloc
|
||||
return p;
|
||||
}
|
||||
|
||||
SNMALLOC_FAST_PATH static uint16_t
|
||||
remove_cache_friendly_offset(uint16_t relative, sizeclass_t sizeclass)
|
||||
SNMALLOC_FAST_PATH static uintptr_t
|
||||
remove_cache_friendly_offset(uintptr_t relative, sizeclass_t sizeclass)
|
||||
{
|
||||
UNUSED(sizeclass);
|
||||
return relative;
|
||||
|
||||
@@ -20,11 +20,6 @@ namespace snmalloc
|
||||
}
|
||||
|
||||
public:
|
||||
static Slab* get(void* p)
|
||||
{
|
||||
return pointer_cast<Slab>(address_cast(p) & SLAB_MASK);
|
||||
}
|
||||
|
||||
Metaslab& get_meta()
|
||||
{
|
||||
Superslab* super = Superslab::get(this);
|
||||
@@ -45,7 +40,7 @@ namespace snmalloc
|
||||
{
|
||||
// Read the head from the metadata stored in the superslab.
|
||||
Metaslab& meta = get_meta();
|
||||
uint16_t head = meta.head;
|
||||
void* head = meta.head;
|
||||
|
||||
assert(rsize == sizeclass_to_size(meta.sizeclass));
|
||||
meta.debug_slab_invariant(is_short(), this);
|
||||
@@ -55,7 +50,7 @@ namespace snmalloc
|
||||
void* p = nullptr;
|
||||
bool p_has_value = false;
|
||||
|
||||
if (head == 1)
|
||||
if (head == nullptr)
|
||||
{
|
||||
size_t bumpptr = get_initial_offset(meta.sizeclass, is_short());
|
||||
bumpptr += meta.allocated * rsize;
|
||||
@@ -96,7 +91,7 @@ namespace snmalloc
|
||||
|
||||
if (curr == nullptr)
|
||||
{
|
||||
meta.head = static_cast<uint16_t>(bumpptr);
|
||||
meta.head = pointer_offset(this, bumpptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -115,12 +110,12 @@ namespace snmalloc
|
||||
|
||||
if (!p_has_value)
|
||||
{
|
||||
p = pointer_offset(this, meta.head);
|
||||
p = meta.head;
|
||||
|
||||
// Read the next slot from the memory that's about to be allocated.
|
||||
void* next = Metaslab::follow_next(p);
|
||||
// Put everything in allocators small_class free list.
|
||||
meta.head = 1;
|
||||
meta.head = nullptr;
|
||||
fast_free_list.value = next;
|
||||
// Treat stealing the free list as allocating it all.
|
||||
// Link is not in use, i.e. - 1 is required.
|
||||
@@ -164,21 +159,18 @@ namespace snmalloc
|
||||
#endif
|
||||
meta.debug_slab_invariant(is_short(), this);
|
||||
|
||||
|
||||
if (unlikely(meta.sub_use()))
|
||||
return false;
|
||||
|
||||
// Update the head and the next pointer in the free list.
|
||||
uint16_t head = meta.head;
|
||||
uint16_t current = pointer_to_index(p);
|
||||
void* head = meta.head;
|
||||
|
||||
// Set the head to the memory being deallocated.
|
||||
meta.head = current;
|
||||
assert(meta.valid_head(is_short()));
|
||||
meta.head = p;
|
||||
assert(meta.valid_head());
|
||||
|
||||
// Set the next pointer to the previous head.
|
||||
Metaslab::store_next(
|
||||
p, (head == 1) ? nullptr : pointer_offset(this, head));
|
||||
Metaslab::store_next(p, head);
|
||||
meta.debug_slab_invariant(is_short(), this);
|
||||
return true;
|
||||
}
|
||||
@@ -206,7 +198,7 @@ namespace snmalloc
|
||||
}
|
||||
// Update the head and the sizeclass link.
|
||||
uint16_t index = pointer_to_index(p);
|
||||
assert(meta.head == 1);
|
||||
assert(meta.head == nullptr);
|
||||
// assert(meta.fully_allocated(is_short()));
|
||||
meta.link = index;
|
||||
meta.used = meta.allocated - 1;
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace snmalloc
|
||||
return alloc_slab(sizeclass, memory_provider);
|
||||
|
||||
meta[0].allocated = 1;
|
||||
meta[0].head = 1;
|
||||
meta[0].head = nullptr;
|
||||
meta[0].sizeclass = static_cast<uint8_t>(sizeclass);
|
||||
meta[0].link = get_initial_offset(sizeclass, true);
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace snmalloc
|
||||
|
||||
uint8_t n = meta[h].next;
|
||||
|
||||
meta[h].head = 1;
|
||||
meta[h].head = nullptr;
|
||||
meta[h].allocated = 1;
|
||||
meta[h].sizeclass = static_cast<uint8_t>(sizeclass);
|
||||
meta[h].link = get_initial_offset(sizeclass, false);
|
||||
|
||||
Reference in New Issue
Block a user