Store a full pointer in the Metaslab

This improves the codegen.
This commit is contained in:
Matthew Parkinson
2019-11-19 17:55:51 +00:00
parent cb4b8fa545
commit efd5228da6
5 changed files with 45 additions and 55 deletions

View File

@@ -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))

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);