diff --git a/src/mem/alloc.h b/src/mem/alloc.h index 598dc7b..38c89d1 100644 --- a/src/mem/alloc.h +++ b/src/mem/alloc.h @@ -521,9 +521,7 @@ namespace snmalloc this->size += sizeclass_to_size(sizeclass); Remote* r = (Remote*)p; - r->set_sizeclass(sizeclass); - assert(r->sizeclass() == sizeclass); - r->set_target_id(target_id); + r->set_sizeclass_and_target_id(target_id, sizeclass); assert(r->sizeclass() == sizeclass); assert(r->target_id() == target_id); @@ -588,10 +586,6 @@ namespace snmalloc } }; - static_assert( - sizeof(Remote) <= MIN_ALLOC_SIZE, - "Need to be able to cast any small alloc to Remote"); - SlabList small_classes[NUM_SMALL_CLASSES]; DLList medium_classes[NUM_MEDIUM_CLASSES]; diff --git a/src/mem/remoteallocator.h b/src/mem/remoteallocator.h index 60d4856..7e9b30a 100644 --- a/src/mem/remoteallocator.h +++ b/src/mem/remoteallocator.h @@ -9,11 +9,14 @@ namespace snmalloc { struct Remote { - static const uint64_t SIZECLASS_SHIFT = 56; - static const uint64_t SIZECLASS_MASK = 0xffULL << SIZECLASS_SHIFT; - static const uint64_t TARGET_MASK = ~SIZECLASS_MASK; - - static_assert(SIZECLASS_MASK == 0xff00'0000'0000'0000ULL); + static const size_t PTR_BITS = sizeof(void*) * 8; + static const size_t SIZECLASS_BITS = sizeof(uint8_t) * 8; + static const bool USE_TOP_BITS = + SIZECLASS_BITS + bits::ADDRESS_BITS <= PTR_BITS; + static const uintptr_t SIZECLASS_SHIFT = PTR_BITS - SIZECLASS_BITS; + static const uintptr_t SIZECLASS_MASK = ((1ULL << SIZECLASS_BITS) - 1) + << SIZECLASS_SHIFT; + static const uintptr_t TARGET_MASK = ~SIZECLASS_MASK; using alloc_id_t = size_t; union @@ -22,32 +25,64 @@ namespace snmalloc Remote* non_atomic_next; }; - uint64_t value; + uintptr_t value; + // This will not exist for the minimum object size. This is only used if + // USE_TOP_BITS is false, and the bottom bit of value is set. + uint8_t possible_sizeclass; - void set_target_id(alloc_id_t id) + void set_sizeclass_and_target_id(alloc_id_t id, uint8_t sizeclass) { - assert(id == (id & TARGET_MASK)); - value = (id & TARGET_MASK) | (value & SIZECLASS_MASK); - } - - void set_sizeclass(uint8_t sizeclass) - { - value = (value & TARGET_MASK) | - ((static_cast(sizeclass) << SIZECLASS_SHIFT) & - SIZECLASS_MASK); + if constexpr (USE_TOP_BITS) + { + assert(id == (id & TARGET_MASK)); + value = (id & TARGET_MASK) | + ((static_cast(sizeclass) << SIZECLASS_SHIFT) & + SIZECLASS_MASK); + } + else + { + assert((id & 1) == 0); + if (sizeclass == 0) + { + value = id | 1; + } + else + { + value = id; + possible_sizeclass = sizeclass; + } + } } alloc_id_t target_id() { - return value & TARGET_MASK; + if constexpr (USE_TOP_BITS) + { + return value & TARGET_MASK; + } + else + { + return value & ~1; + } } uint8_t sizeclass() { - return (value & SIZECLASS_MASK) >> SIZECLASS_SHIFT; + if constexpr (USE_TOP_BITS) + { + return (value & SIZECLASS_MASK) >> SIZECLASS_SHIFT; + } + else + { + return ((value & 1) == 1) ? 0 : possible_sizeclass; + } } }; + static_assert( + (offsetof(Remote, possible_sizeclass)) <= MIN_ALLOC_SIZE, + "Need to be able to cast any small alloc to Remote"); + struct RemoteAllocator { using alloc_id_t = Remote::alloc_id_t;