Refactor MetaSlab / MetaCommon. (#501)
MetaCommon is now gone. The back end must provide a SlabMetadata, which must be a subtype of MetaSlab (i.e. MetaSlab or a subclass of MetaSlab). It may add additional state here. The MetaEntry is now templated on the concrete subclass of MetaSlab that the back-end uses. The MetaEntry still stores this as a `uintptr_t` to allow easier toggling of the boundary bit but the interfaces are all in terms of stable types now. Also some tidying of names (SharedStateHandle is now called Backend). In a follow-on PR, we can then remove the chunk field from the BackendMetadata in the non-CHERI back end and allow back ends that don't require extra state to use MetaSlab directly. Other cleanups: - Remove backend/metatypes, define the types that the front end expects in mem/metaslab. The back end may extend them but these types define part of the contract between the front and back ends. - Remove FrontendMetaEntry and fold its methods into MetaEntry. - For example purposes, the default back end now extends MetaEntry. This also ensures that nothing in the front end depends on the specific type of MetaEntry. - Some things now have more sensible names. The meta entry now operates in one of three modes: - When owned by the front end, it stores a pointer to a remote, a pointer to some MetaSlab subclass, and a sizeclass. - When owned by the back end, it stores two back-end defined values that must fit in the bits of `uintptr_t` that are not reserved for the MetaEntry itself. - When not owned by either, it can be queried as if owned by the front end. The red-black tree has been refactored to allow the holder to be a wrapper type, removing all of the Holder* and Holder& uses and treating it uniformly as a value type that can be used to access the contents. The chunk field is fone from the slab medatada. This will need to be added back in the CHERI back ends, but it's a back-end policy. The back end can choose to use it or not, depending on whether it can safely convert between an Alloc-bounded pointer and a Chunk-bounded pointer. The term 'metaslab' originated in snmalloc 1 to mean a slab of slabs. In the snmalloc2 branch it was repurposed to mean metadata about a slab. To make this clearer, all uses of metaslab are now gone and have been renamed to slab metadata. The frontend metadata classes are all prefixed Frontend and some extra invariants are checked with `static_assert`.
This commit is contained in:
@@ -146,8 +146,8 @@ int main()
|
||||
*
|
||||
* - RemoteAllocator::dequeue domesticating the stub's next pointer (p)
|
||||
*
|
||||
* - Metaslab::alloc_free_list, domesticating the successor object in the
|
||||
* newly minted freelist::Iter (i.e., the thing that would be allocated
|
||||
* - FrontendMetaData::alloc_free_list, domesticating the successor object
|
||||
* in the newly minted freelist::Iter (i.e., the thing that would be allocated
|
||||
* after q).
|
||||
*/
|
||||
static constexpr size_t expected_count =
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "ds/redblacktree.h"
|
||||
#include "snmalloc.h"
|
||||
|
||||
struct Wrapper
|
||||
struct NodeRef
|
||||
{
|
||||
// The redblack tree is going to be used inside the pagemap,
|
||||
// and the redblack tree cannot use all the bits. Applying an offset
|
||||
@@ -21,7 +21,33 @@ struct Wrapper
|
||||
// the representation.
|
||||
static constexpr size_t offset = 10000;
|
||||
|
||||
size_t value = offset << 1;
|
||||
size_t* ptr;
|
||||
constexpr NodeRef(size_t* p) : ptr(p) {}
|
||||
constexpr NodeRef() : ptr(nullptr) {}
|
||||
constexpr NodeRef(const NodeRef& other) : ptr(other.ptr) {}
|
||||
constexpr NodeRef(NodeRef&& other) : ptr(other.ptr) {}
|
||||
|
||||
bool operator!=(const NodeRef& other) const
|
||||
{
|
||||
return ptr != other.ptr;
|
||||
}
|
||||
NodeRef& operator=(const NodeRef& other)
|
||||
{
|
||||
ptr = other.ptr;
|
||||
return *this;
|
||||
}
|
||||
void set(uint16_t val)
|
||||
{
|
||||
*ptr = ((size_t(val) + offset) << 1) + (*ptr & 1);
|
||||
}
|
||||
explicit operator uint16_t()
|
||||
{
|
||||
return uint16_t((*ptr >> 1) - offset);
|
||||
}
|
||||
explicit operator size_t*()
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Simple representation that is like the pagemap.
|
||||
@@ -29,8 +55,8 @@ struct Wrapper
|
||||
// We shift the fields up to make room for the colour.
|
||||
struct node
|
||||
{
|
||||
Wrapper left;
|
||||
Wrapper right;
|
||||
size_t left;
|
||||
size_t right;
|
||||
};
|
||||
|
||||
inline static node array[2048];
|
||||
@@ -38,40 +64,41 @@ inline static node array[2048];
|
||||
class Rep
|
||||
{
|
||||
public:
|
||||
using key = size_t;
|
||||
using key = uint16_t;
|
||||
|
||||
static constexpr key null = 0;
|
||||
static constexpr size_t root{NodeRef::offset << 1};
|
||||
|
||||
using Holder = Wrapper;
|
||||
using Contents = size_t;
|
||||
using Handle = NodeRef;
|
||||
using Contents = uint16_t;
|
||||
|
||||
static void set(Holder* ptr, Contents r)
|
||||
static void set(Handle ptr, Contents r)
|
||||
{
|
||||
ptr->value = ((r + Wrapper::offset) << 1) + (ptr->value & 1);
|
||||
ptr.set(r);
|
||||
}
|
||||
|
||||
static Contents get(Holder* ptr)
|
||||
static Contents get(Handle ptr)
|
||||
{
|
||||
return (ptr->value >> 1) - Wrapper::offset;
|
||||
return static_cast<Contents>(ptr);
|
||||
}
|
||||
|
||||
static Holder& ref(bool direction, key k)
|
||||
static Handle ref(bool direction, key k)
|
||||
{
|
||||
if (direction)
|
||||
return array[k].left;
|
||||
return {&array[k].left};
|
||||
else
|
||||
return array[k].right;
|
||||
return {&array[k].right};
|
||||
}
|
||||
|
||||
static bool is_red(key k)
|
||||
{
|
||||
return (array[k].left.value & 1) == 1;
|
||||
return (array[k].left & 1) == 1;
|
||||
}
|
||||
|
||||
static void set_red(key k, bool new_is_red)
|
||||
{
|
||||
if (new_is_red != is_red(k))
|
||||
array[k].left.value ^= 1;
|
||||
array[k].left ^= 1;
|
||||
}
|
||||
|
||||
static bool compare(key k1, key k2)
|
||||
@@ -88,6 +115,16 @@ public:
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
static size_t* printable(NodeRef k)
|
||||
{
|
||||
return static_cast<size_t*>(k);
|
||||
}
|
||||
|
||||
static const char* name()
|
||||
{
|
||||
return "TestRep";
|
||||
}
|
||||
};
|
||||
|
||||
template<bool TRACE>
|
||||
@@ -112,9 +149,9 @@ void test(size_t size, unsigned int seed)
|
||||
for (auto j = batch; j > 0; j--)
|
||||
{
|
||||
auto index = 1 + rand.next() % size;
|
||||
if (tree.insert_elem(index))
|
||||
if (tree.insert_elem(Rep::key(index)))
|
||||
{
|
||||
entries.push_back(index);
|
||||
entries.push_back(Rep::key(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -189,4 +226,4 @@ int main(int argc, char** argv)
|
||||
// Trace particular example
|
||||
test<true>(size, seed);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user