Pagemap move (#504)
* Move PageMap interface into pagemap.h and rename to BasicPagemap. Refactoring suggested by David. This allows custom backends to reuse or extend the BasicPagemap. It has template parameters for the PAL, concrete page map and page map entry types as well as the Backend (so that it can be friends). BackendAllocator provides an exmple page map entry type.
This commit is contained in:
@@ -24,135 +24,72 @@ namespace snmalloc
|
||||
class BackendAllocator : public CommonConfig
|
||||
{
|
||||
public:
|
||||
class PageMapEntry;
|
||||
using Pal = PAL;
|
||||
|
||||
using SlabMetadata = FrontendSlabMetadata;
|
||||
|
||||
class Pagemap
|
||||
private:
|
||||
using ConcretePagemap =
|
||||
FlatPagemap<MIN_CHUNK_BITS, PageMapEntry, PAL, fixed_range>;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Example of type stored in the pagemap.
|
||||
* The following class could be replaced by:
|
||||
*
|
||||
* ```
|
||||
* using PageMapEntry = FrontendMetaEntry<SlabMetadata>;
|
||||
* ```
|
||||
*
|
||||
* The full form here provides an example of how to extend the pagemap
|
||||
* entries. It also guarantees that the front end never directly
|
||||
* constructs meta entries, it only ever reads them or modifies them in
|
||||
* place.
|
||||
*/
|
||||
class PageMapEntry : public FrontendMetaEntry<SlabMetadata>
|
||||
{
|
||||
/**
|
||||
* The private initialising constructor is usable only by this back end.
|
||||
*/
|
||||
friend class BackendAllocator;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Export the type stored in the pagemap.
|
||||
* The following class could be replaced by:
|
||||
*
|
||||
* ```
|
||||
* using Entry = FrontendMetaEntry<SlabMetadata>;
|
||||
* ```
|
||||
*
|
||||
* The full form here provides an example of how to extend the pagemap
|
||||
* entries. It also guarantees that the front end never directly
|
||||
* constructs meta entries, it only ever reads them or modifies them in
|
||||
* place.
|
||||
* The private default constructor is usable only by the pagemap.
|
||||
*/
|
||||
class Entry : public FrontendMetaEntry<SlabMetadata>
|
||||
{
|
||||
/**
|
||||
* The private initialising constructor is usable only by this back end.
|
||||
*/
|
||||
friend class BackendAllocator;
|
||||
|
||||
/**
|
||||
* The private default constructor is usable only by the pagemap.
|
||||
*/
|
||||
friend class FlatPagemap<MIN_CHUNK_BITS, Entry, PAL, fixed_range>;
|
||||
|
||||
/**
|
||||
* The only constructor that creates newly initialised meta entries.
|
||||
* This is callable only by the back end. The front end may copy,
|
||||
* query, and update these entries, but it may not create them
|
||||
* directly. This contract allows the back end to store any arbitrary
|
||||
* metadata in meta entries when they are first constructed.
|
||||
*/
|
||||
SNMALLOC_FAST_PATH
|
||||
Entry(SlabMetadata* meta, uintptr_t ras)
|
||||
: FrontendMetaEntry<SlabMetadata>(meta, ras)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Default constructor. This must be callable from the pagemap.
|
||||
*/
|
||||
SNMALLOC_FAST_PATH Entry() = default;
|
||||
|
||||
/**
|
||||
* Copy assignment is used only by the pagemap.
|
||||
*/
|
||||
Entry& operator=(const Entry& other)
|
||||
{
|
||||
FrontendMetaEntry<SlabMetadata>::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
SNMALLOC_REQUIRE_CONSTINIT
|
||||
static inline FlatPagemap<MIN_CHUNK_BITS, Entry, PAL, fixed_range>
|
||||
concretePagemap;
|
||||
friend ConcretePagemap;
|
||||
|
||||
/**
|
||||
* Set the metadata associated with a chunk.
|
||||
* The only constructor that creates newly initialised meta entries.
|
||||
* This is callable only by the back end. The front end may copy,
|
||||
* query, and update these entries, but it may not create them
|
||||
* directly. This contract allows the back end to store any arbitrary
|
||||
* metadata in meta entries when they are first constructed.
|
||||
*/
|
||||
SNMALLOC_FAST_PATH
|
||||
static void set_metaentry(address_t p, size_t size, const Entry& t)
|
||||
{
|
||||
for (address_t a = p; a < p + size; a += MIN_CHUNK_SIZE)
|
||||
{
|
||||
concretePagemap.set(a, t);
|
||||
}
|
||||
}
|
||||
PageMapEntry(SlabMetadata* meta, uintptr_t ras)
|
||||
: FrontendMetaEntry<SlabMetadata>(meta, ras)
|
||||
{}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Get the metadata associated with a chunk.
|
||||
*
|
||||
* Set template parameter to true if it not an error
|
||||
* to access a location that is not backed by a chunk.
|
||||
* Copy assignment is used only by the pagemap.
|
||||
*/
|
||||
template<bool potentially_out_of_range = false>
|
||||
SNMALLOC_FAST_PATH static const auto& get_metaentry(address_t p)
|
||||
PageMapEntry& operator=(const PageMapEntry& other)
|
||||
{
|
||||
return concretePagemap.template get<potentially_out_of_range>(p);
|
||||
FrontendMetaEntry<SlabMetadata>::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata associated with a chunk.
|
||||
*
|
||||
* Set template parameter to true if it not an error
|
||||
* to access a location that is not backed by a chunk.
|
||||
* Default constructor. This must be callable from the pagemap.
|
||||
*/
|
||||
template<bool potentially_out_of_range = false>
|
||||
SNMALLOC_FAST_PATH static auto& get_metaentry_mut(address_t p)
|
||||
{
|
||||
return concretePagemap.template get_mut<potentially_out_of_range>(p);
|
||||
}
|
||||
|
||||
static void register_range(address_t p, size_t sz)
|
||||
{
|
||||
concretePagemap.register_range(p, sz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bounds of the memory this back-end manages as a pair of
|
||||
* addresses (start then end). This is available iff this is a
|
||||
* fixed-range Backend.
|
||||
*/
|
||||
template<bool fixed_range_ = fixed_range>
|
||||
static SNMALLOC_FAST_PATH
|
||||
std::enable_if_t<fixed_range_, std::pair<address_t, address_t>>
|
||||
get_bounds()
|
||||
{
|
||||
static_assert(
|
||||
fixed_range_ == fixed_range, "Don't set SFINAE parameter!");
|
||||
|
||||
return concretePagemap.get_bounds();
|
||||
}
|
||||
|
||||
static bool is_initialised()
|
||||
{
|
||||
return concretePagemap.is_initialised();
|
||||
}
|
||||
SNMALLOC_FAST_PATH PageMapEntry() = default;
|
||||
};
|
||||
using Pagemap = BasicPagemap<
|
||||
BackendAllocator,
|
||||
PAL,
|
||||
ConcretePagemap,
|
||||
PageMapEntry,
|
||||
fixed_range>;
|
||||
|
||||
#if defined(_WIN32) || defined(__CHERI_PURE_CAPABILITY__)
|
||||
static constexpr bool CONSOLIDATE_PAL_ALLOCS = false;
|
||||
|
||||
@@ -325,4 +325,105 @@ namespace snmalloc
|
||||
body[p >> SHIFT] = t;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a generic implementation of the backend's interface to the page
|
||||
* map. It takes a concrete page map implementation (probably FlatPageMap
|
||||
* above) and entry type. It is friends with the backend passed in as a
|
||||
* template parameter so that the backend can initialise the concrete page map
|
||||
* and use set_metaentry which no one else should use.
|
||||
*/
|
||||
template<
|
||||
typename Backend,
|
||||
typename PAL,
|
||||
typename ConcreteMap,
|
||||
typename PageMapEntry,
|
||||
bool fixed_range>
|
||||
class BasicPagemap
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Export the type stored in the pagemap.
|
||||
*/
|
||||
using Entry = PageMapEntry;
|
||||
|
||||
private:
|
||||
friend Backend;
|
||||
|
||||
/**
|
||||
* Instance of the concrete pagemap, accessible to the backend so that
|
||||
* it can call the init method whose type dependent on fixed_range.
|
||||
*/
|
||||
SNMALLOC_REQUIRE_CONSTINIT
|
||||
static inline ConcreteMap concretePagemap;
|
||||
|
||||
/**
|
||||
* Set the metadata associated with a chunk.
|
||||
*/
|
||||
SNMALLOC_FAST_PATH
|
||||
static void set_metaentry(address_t p, size_t size, const Entry& t)
|
||||
{
|
||||
for (address_t a = p; a < p + size; a += MIN_CHUNK_SIZE)
|
||||
{
|
||||
concretePagemap.set(a, t);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Get the metadata associated with a chunk.
|
||||
*
|
||||
* Set template parameter to true if it not an error
|
||||
* to access a location that is not backed by a chunk.
|
||||
*/
|
||||
template<bool potentially_out_of_range = false>
|
||||
SNMALLOC_FAST_PATH static const auto& get_metaentry(address_t p)
|
||||
{
|
||||
return concretePagemap.template get<potentially_out_of_range>(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata associated with a chunk.
|
||||
*
|
||||
* Set template parameter to true if it not an error
|
||||
* to access a location that is not backed by a chunk.
|
||||
*/
|
||||
template<bool potentially_out_of_range = false>
|
||||
SNMALLOC_FAST_PATH static auto& get_metaentry_mut(address_t p)
|
||||
{
|
||||
return concretePagemap.template get_mut<potentially_out_of_range>(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a range in the pagemap as in-use, requiring it to allow writing
|
||||
* to the underlying memory.
|
||||
*/
|
||||
static void register_range(address_t p, size_t sz)
|
||||
{
|
||||
concretePagemap.register_range(p, sz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bounds of the memory this back-end manages as a pair of
|
||||
* addresses (start then end). This is available iff this is a
|
||||
* fixed-range Backend.
|
||||
*/
|
||||
template<bool fixed_range_ = fixed_range>
|
||||
static SNMALLOC_FAST_PATH
|
||||
std::enable_if_t<fixed_range_, std::pair<address_t, address_t>>
|
||||
get_bounds()
|
||||
{
|
||||
static_assert(fixed_range_ == fixed_range, "Don't set SFINAE parameter!");
|
||||
|
||||
return concretePagemap.get_bounds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the pagemap is initialised, ready for access.
|
||||
*/
|
||||
static bool is_initialised()
|
||||
{
|
||||
return concretePagemap.is_initialised();
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
|
||||
Reference in New Issue
Block a user