diff --git a/src/mem/pagemap.h b/src/mem/pagemap.h index 0774c68..5b78572 100644 --- a/src/mem/pagemap.h +++ b/src/mem/pagemap.h @@ -184,25 +184,35 @@ namespace snmalloc size_t shift = TOPLEVEL_SHIFT; std::atomic* e = &top[ix]; - for (size_t i = 0; i < INDEX_LEVELS; i++) + // This is effectively a + // for (size_t i = 0; i < INDEX_LEVELS; i++) + // loop, but uses constexpr to guarantee optimised version + // where the INDEX_LEVELS in {0,1}. + if constexpr (INDEX_LEVELS != 0) { - PagemapEntry* value = get_node(e, result); - if (unlikely(!result)) - return {nullptr, 0}; - - shift -= BITS_PER_INDEX_LEVEL; - ix = (static_cast(addr) >> shift) & ENTRIES_MASK; - e = &value->entries[ix]; - - if constexpr (INDEX_LEVELS == 1) + size_t i = 0; + while (true) { - UNUSED(i); - break; - } - i++; + PagemapEntry* value = get_node(e, result); + if (unlikely(!result)) + return {nullptr, 0}; - if (i == INDEX_LEVELS) - break; + shift -= BITS_PER_INDEX_LEVEL; + ix = (static_cast(addr) >> shift) & ENTRIES_MASK; + e = &value->entries[ix]; + + if constexpr (INDEX_LEVELS == 1) + { + UNUSED(i); + break; + } + else + { + i++; + if (i == INDEX_LEVELS) + break; + } + } } Leaf* leaf = reinterpret_cast(get_node(e, result)); diff --git a/src/test/func/pagemap/pagemap.cc b/src/test/func/pagemap/pagemap.cc new file mode 100644 index 0000000..571cff0 --- /dev/null +++ b/src/test/func/pagemap/pagemap.cc @@ -0,0 +1,55 @@ +/** + * Unit tests for operations in pagemap operations. + * + * Currently this tests a very specific case where the pagemap + * requires multiple levels of index. This was incorrectly implemented, + * but no examples were using multiple levels of pagemap. + */ + +#include +#include +#include +#include + +using namespace snmalloc; +using T = size_t; +static constexpr size_t GRANULARITY_BITS = 9; +static constexpr T PRIME = 251; +Pagemap pagemap_test; + +int main(int argc, char** argv) +{ + UNUSED(argc); + UNUSED(argv); + + setup(); + + T value = 0; + for (uintptr_t ptr = 0; ptr < bits::one_at_bit(36); + ptr += bits::one_at_bit(GRANULARITY_BITS + 3)) + { + pagemap_test.set(ptr, value); + value++; + if (value == PRIME) + value = 0; + if ((ptr % (1ULL << 32)) == 0) + std::cout << "." << std::flush; + } + + std::cout << std::endl; + value = 0; + for (uintptr_t ptr = 0; ptr < bits::one_at_bit(36); + ptr += bits::one_at_bit(GRANULARITY_BITS + 3)) + { + T result = pagemap_test.get(ptr); + if (value != result) + Pal::error("Pagemap corrupt!"); + value++; + if (value == PRIME) + value = 0; + + if ((ptr % (1ULL << 32)) == 0) + std::cout << "." << std::flush; + } + std::cout << std::endl; +}