Deconflate "Pagemap" objects

There are two things calling themselves pagemaps:

- the src/mem/pagemap.h objects of that name

- the SuperslabMap object gets called a PageMap inside the Allocator

Rename the latter to chunkmap, with appropriate case and snake,
everywhere, and pull it out to its own file (chunkmap.h).

The default implementation of a chunkmap is a purely static object, but
we nevertheless instantiate it per allocator, so that other
implementations can use stateful instances when interposing on the
mutation methods.  Note that the "get" method, however, must remain
static to support the interface required by Allocator objects.
This commit is contained in:
Nathaniel Filardo
2019-11-21 15:23:35 +00:00
parent b889f11d04
commit d5b478ecb3
6 changed files with 255 additions and 235 deletions

215
src/mem/chunkmap.h Normal file
View File

@@ -0,0 +1,215 @@
#pragma once
using namespace std;
#include "../ds/address.h"
#include "largealloc.h"
#include "mediumslab.h"
#include "pagemap.h"
#include "slab.h"
namespace snmalloc
{
enum ChunkMapSuperslabKind
{
CMNotOurs = 0,
CMSuperslab = 1,
CMMediumslab = 2
};
#ifndef SNMALLOC_MAX_FLATPAGEMAP_SIZE
// Use flat map is under a single node.
# define SNMALLOC_MAX_FLATPAGEMAP_SIZE PAGEMAP_NODE_SIZE
#endif
static constexpr bool USE_FLATPAGEMAP = pal_supports<LazyCommit>() ||
(SNMALLOC_MAX_FLATPAGEMAP_SIZE >=
sizeof(FlatPagemap<SUPERSLAB_BITS, uint8_t>));
using ChunkmapPagemap = std::conditional_t<
USE_FLATPAGEMAP,
FlatPagemap<SUPERSLAB_BITS, uint8_t>,
Pagemap<SUPERSLAB_BITS, uint8_t, 0>>;
/**
* Mixin used by `ChunkMap` to directly access the pagemap via a global
* variable. This should be used from within the library or program that
* owns the pagemap.
*
* This class makes the global pagemap a static field so that its name
* includes the type mangling. If two compilation units try to instantiate
* two different types of pagemap then they will see two distinct pagemaps.
* This will prevent allocating with one and freeing with the other (because
* the memory will show up as not owned by any allocator in the other
* compilation unit) but will prevent the same memory being interpreted as
* having two different types.
*/
template<typename T>
class GlobalPagemapTemplate
{
/**
* The global pagemap variable. The name of this symbol will include the
* type of `T`.
*/
inline static T global_pagemap;
public:
/**
* Returns the pagemap.
*/
static ChunkmapPagemap& pagemap()
{
return global_pagemap;
}
};
using GlobalPagemap = GlobalPagemapTemplate<ChunkmapPagemap>;
/**
* Optionally exported function that accesses the global pagemap provided by
* a shared library.
*/
extern "C" void* snmalloc_pagemap_global_get(snmalloc::PagemapConfig const**);
/**
* Mixin used by `ChunkMap` to access the global pagemap via a
* type-checked C interface. This should be used when another library (e.g.
* your C standard library) uses snmalloc and you wish to use a different
* configuration in your program or library, but wish to share a pagemap so
* that either version can deallocate memory.
*/
class ExternalGlobalPagemap
{
/**
* A pointer to the pagemap.
*/
inline static ChunkmapPagemap* external_pagemap;
public:
/**
* Constructor. Accesses the pagemap via the C ABI accessor and casts it to
* the expected type, failing in cases of ABI mismatch.
*/
ExternalGlobalPagemap()
{
const snmalloc::PagemapConfig* c;
external_pagemap =
ChunkmapPagemap::cast_to_pagemap(snmalloc_pagemap_global_get(&c), c);
// FIXME: Report an error somehow in non-debug builds.
assert(external_pagemap);
}
/**
* Returns the exported pagemap.
*/
static ChunkmapPagemap& pagemap()
{
return *external_pagemap;
}
};
/**
* Class that defines an interface to the pagemap. This is provided to
* `Allocator` as a template argument and so can be replaced by a compatible
* implementation (for example, to move pagemap updates to a different
* protection domain).
*/
template<typename PagemapProvider = GlobalPagemap>
struct DefaultChunkMap
{
/**
* Get the pagemap entry corresponding to a specific address.
*/
static uint8_t get(address_t p)
{
return PagemapProvider::pagemap().get(p);
}
/**
* Get the pagemap entry corresponding to a specific address.
*/
static uint8_t get(void* p)
{
return get(address_cast(p));
}
/**
* Set a pagemap entry indicating that there is a superslab at the
* specified index.
*/
static void set_slab(Superslab* slab)
{
set(slab, static_cast<size_t>(CMSuperslab));
}
/**
* Add a pagemap entry indicating that a medium slab has been allocated.
*/
static void set_slab(Mediumslab* slab)
{
set(slab, static_cast<size_t>(CMMediumslab));
}
/**
* Remove an entry from the pagemap corresponding to a superslab.
*/
static void clear_slab(Superslab* slab)
{
assert(get(slab) == CMSuperslab);
set(slab, static_cast<size_t>(CMNotOurs));
}
/**
* Remove an entry corresponding to a medium slab.
*/
static void clear_slab(Mediumslab* slab)
{
assert(get(slab) == CMMediumslab);
set(slab, static_cast<size_t>(CMNotOurs));
}
/**
* Update the pagemap to reflect a large allocation, of `size` bytes from
* address `p`.
*/
static void set_large_size(void* p, size_t size)
{
size_t size_bits = bits::next_pow2_bits(size);
set(p, static_cast<uint8_t>(size_bits));
// Set redirect slide
auto ss = address_cast(p) + SUPERSLAB_SIZE;
for (size_t i = 0; i < size_bits - SUPERSLAB_BITS; i++)
{
size_t run = 1ULL << i;
PagemapProvider::pagemap().set_range(
ss, static_cast<uint8_t>(64 + i + SUPERSLAB_BITS), run);
ss = ss + SUPERSLAB_SIZE * run;
}
PagemapProvider::pagemap().set(
address_cast(p), static_cast<uint8_t>(size_bits));
}
/**
* Update the pagemap to remove a large allocation, of `size` bytes from
* address `p`.
*/
static void clear_large_size(void* vp, size_t size)
{
auto p = address_cast(vp);
size_t rounded_size = bits::next_pow2(size);
assert(get(p) == bits::next_pow2_bits(size));
auto count = rounded_size >> SUPERSLAB_BITS;
PagemapProvider::pagemap().set_range(p, CMNotOurs, count);
}
private:
/**
* Helper function to set a pagemap entry. This is not part of the public
* interface and exists to make it easy to reuse the code in the public
* methods in other pagemap adaptors.
*/
static void set(void* p, uint8_t x)
{
PagemapProvider::pagemap().set(address_cast(p), x);
}
};
#ifndef SNMALLOC_DEFAULT_CHUNKMAP
# define SNMALLOC_DEFAULT_CHUNKMAP snmalloc::DefaultChunkMap<>
#endif
} // namespace snmalloc