Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/AddressSpace.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Its contents can be decoded as follows:
This trick of pointing at the child's chunk rather than at the child `MetaEntry` is particularly useful on CHERI:
it allows us to capture the authority to the chunk without needing another pointer and costs just a shift and add.)

3. The `meta` field's `LargeBuddyRep::RED_BIT` is used to carry the red/black color of this node.
3. The `meta` field's `LargeBuddyRep::TREE_TAG_BIT` is used to carry the red/black color of this node.

See `src/backend/largebuddyrange.h`.

Expand All @@ -135,7 +135,7 @@ The following cases apply:
The `MetaEntry`...
* has `REMOTE_BACKEND_MARKER` asserted in `remote_and_sizeclass`.
* has "small" sizeclass 0, which has size 0.
* the remainder of its `MetaEntry` structure will be a Large Buddy Allocator rbtree node.
* the remainder of its `MetaEntry` structure will be a Large Buddy Allocator DefaultRBTree node.
* has no associated metadata structure.

3. The address is part of a free chunk inside a backend's Small Buddy Allocator:
Expand Down
4 changes: 2 additions & 2 deletions src/snmalloc/backend_helpers/buddy.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ namespace snmalloc
struct Entry
{
typename Rep::Contents cache[3];
RBTree<Rep> tree{};
DefaultRBTree<Rep> tree{};
};

stl::Array<Entry, MAX_SIZE_BITS - MIN_SIZE_BITS> entries{};
// All RBtrees at or above this index should be empty.
// All DefaultRBTrees at or above this index should be empty.
size_t empty_at_or_above{0};

size_t to_index(size_t size)
Expand Down
34 changes: 17 additions & 17 deletions src/snmalloc/backend_helpers/largebuddyrange.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ namespace snmalloc
{
public:
/*
* The values we store in our rbtree are the addresses of (combined spans
* of) chunks of the address space; as such, bits in (MIN_CHUNK_SIZE - 1)
* are unused and so the RED_BIT is packed therein. However, in practice,
* these are not "just any" uintptr_t-s, but specifically the uintptr_t-s
* inside the Pagemap's BackendAllocator::Entry structures.
* The values we store in our DefaultRBTree are the addresses of (combined
* spans of) chunks of the address space; as such, bits in (MIN_CHUNK_SIZE -
* 1) are unused and so the TREE_TAG_BIT is packed therein. However, in
* practice, these are not "just any" uintptr_t-s, but specifically the
* uintptr_t-s inside the Pagemap's BackendAllocator::Entry structures.
*
* The BackendAllocator::Entry provides us with helpers that guarantee that
* we use only the bits that we are allowed to.
Expand All @@ -37,13 +37,13 @@ namespace snmalloc
* a bit that is a valid part of the address of a chunk.
* @{
*/
static constexpr address_t RED_BIT = 1 << 8;
static constexpr address_t TREE_TAG_BIT = 1 << 8;

static_assert(RED_BIT < MIN_CHUNK_SIZE);
static_assert(TREE_TAG_BIT < MIN_CHUNK_SIZE);
static_assert(MetaEntryBase::is_backend_allowed_value(
MetaEntryBase::Word::One, RED_BIT));
MetaEntryBase::Word::One, TREE_TAG_BIT));
static_assert(MetaEntryBase::is_backend_allowed_value(
MetaEntryBase::Word::Two, RED_BIT));
MetaEntryBase::Word::Two, TREE_TAG_BIT));
///@}

/// The value of a null node, as returned by `get`
Expand All @@ -56,15 +56,15 @@ namespace snmalloc
*/
static void set(Handle ptr, Contents r)
{
ptr = r | (static_cast<address_t>(ptr.get()) & RED_BIT);
ptr = r | (static_cast<address_t>(ptr.get()) & TREE_TAG_BIT);
}

/**
* Returns the value, stripping out the red/black colour.
*/
static Contents get(const Handle ptr)
{
return ptr.get() & ~RED_BIT;
return ptr.get() & ~TREE_TAG_BIT;
}

/**
Expand All @@ -87,19 +87,19 @@ namespace snmalloc
return entry.get_backend_word(Pagemap::Entry::Word::Two);
}

static bool is_red(Contents k)
static bool tree_tag(Contents k)
{
return (ref(true, k).get() & RED_BIT) == RED_BIT;
return (ref(true, k).get() & TREE_TAG_BIT) == TREE_TAG_BIT;
}

static void set_red(Contents k, bool new_is_red)
static void set_tree_tag(Contents k, bool new_tree_tag)
{
if (new_is_red != is_red(k))
if (new_tree_tag != tree_tag(k))
{
auto v = ref(true, k);
v = v.get() ^ RED_BIT;
v = v.get() ^ TREE_TAG_BIT;
}
SNMALLOC_ASSERT(is_red(k) == new_is_red);
SNMALLOC_ASSERT(tree_tag(k) == new_tree_tag);
}

static Contents offset(Contents k, size_t size)
Expand Down
12 changes: 6 additions & 6 deletions src/snmalloc/backend_helpers/smallbuddyrange.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace snmalloc
};

/**
* Class for using the allocations own space to store in the RBTree.
* Class for using the allocations own space to store in the DefaultRBTree.
*/
template<SNMALLOC_CONCEPT(capptr::IsBound) bounds>
class BuddyInplaceRep
Expand Down Expand Up @@ -57,21 +57,21 @@ namespace snmalloc
return &r->right;
}

static bool is_red(Contents k)
static bool tree_tag(Contents k)
{
if (k == nullptr)
return false;
return (address_cast(*ref(false, k)) & MASK) == MASK;
}

static void set_red(Contents k, bool new_is_red)
static void set_tree_tag(Contents k, bool new_tree_tag)
{
if (new_is_red != is_red(k))
if (new_tree_tag != tree_tag(k))
{
auto r = ref(false, k);
auto old_addr = pointer_align_down<2, FreeChunk<bounds>>(r->as_void());

if (new_is_red)
if (new_tree_tag)
{
if (old_addr == nullptr)
*r = CapPtr<FreeChunk<bounds>, bounds>::unsafe_from(
Expand All @@ -84,7 +84,7 @@ namespace snmalloc
{
*r = old_addr;
}
SNMALLOC_ASSERT(is_red(k) == new_is_red);
SNMALLOC_ASSERT(tree_tag(k) == new_tree_tag);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/snmalloc/ds_core/ds_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
#include "helpers.h"
#include "mitigations.h"
#include "ptrwrap.h"
#include "redblacktree.h"
#include "rankbalancetree.h"
#include "tid.h"
85 changes: 85 additions & 0 deletions src/snmalloc/ds_core/rankbalancetree.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#pragma once

#include "snmalloc/stl/array.h"

#include <stddef.h>
#include <stdint.h>

namespace snmalloc
{
#ifdef __cpp_concepts
/**
* The representation must define two types. `Contents` defines some
* identifier that can be mapped to a node as a value type. `Handle` defines
* a reference to the storage, which can be used to update it.
*
* Conceptually, `Contents` is a node ID and `Handle` is a pointer to a node
* ID.
*/
template<typename Rep>
concept RBRepTypes = requires() {
typename Rep::Handle;
typename Rep::Contents;
};

/**
* The representation must define operations on the holder and contents
* types. It must be able to 'dereference' a holder with `get`, assign to it
* with `set`, set and query the red/black colour of a node with
* `set_tree_tag` and `tree_tag`.
*
* The `ref` method provides uniform access to the children of a node,
* returning a holder pointing to either the left or right child, depending on
* the direction parameter.
*
* The backend must also provide two constant values.
* `Rep::null` defines a value that, if returned from `get`, indicates a null
* value. `Rep::root` defines a value that, if constructed directly, indicates
* a null value and can therefore be used as the initial raw bit pattern of
* the root node.
*/
template<typename Rep>
concept RBRepMethods =
requires(typename Rep::Handle hp, typename Rep::Contents k, bool b) {
{
Rep::get(hp)
} -> ConceptSame<typename Rep::Contents>;
{
Rep::set(hp, k)
} -> ConceptSame<void>;
{
Rep::tree_tag(k)
} -> ConceptSame<bool>;
{
Rep::set_tree_tag(k, b)
} -> ConceptSame<void>;
{
Rep::ref(b, k)
} -> ConceptSame<typename Rep::Handle>;
{
Rep::null
} -> ConceptSameModRef<const typename Rep::Contents>;
{
typename Rep::Handle{const_cast<
stl::remove_const_t<stl::remove_reference_t<decltype(Rep::root)>>*>(
&Rep::root)}
} -> ConceptSame<typename Rep::Handle>;
};

template<typename Rep>
concept RBRep = //
RBRepTypes<Rep> //
&& RBRepMethods<Rep> //
&&
ConceptSame<decltype(Rep::null), stl::add_const_t<typename Rep::Contents>>;
#endif
} // namespace snmalloc

#include "redblacktree.h"
#include "weakavltree.h"

namespace snmalloc
{
template<typename Rep, bool run_checks = Debug, bool TRACE = false>
using DefaultRBTree = WeakAVLTree<Rep, run_checks, TRACE>;
}
Loading
Loading