Remove indirection in the common case.

Rather than unconditionally storing a pointer to the pagemap and
initialising this with a global, we now provide a choice of three
compile-time options for how the pagemap should be accessed.
This commit is contained in:
David Chisnall
2019-04-11 10:33:52 +01:00
parent 29b45c3345
commit a64cc5562f

View File

@@ -62,30 +62,112 @@ namespace snmalloc
Pagemap<SUPERSLAB_BITS, uint8_t, 0>>;
HEADER_GLOBAL SuperslabPagemap global_pagemap;
/**
* Mixin used by `SuperslabMap` to directly access the pagemap via a global
* variable. This should be used from within the library or program that
* owns the pagemap.
*/
struct GlobalPagemap
{
/**
* Returns the pagemap.
*/
SuperslabPagemap& pagemap()
{
return global_pagemap;
}
};
/**
* Mixin used by `SuperslabMap` to access a pagemap provided by the user.
* This should be used by code that needs to access the canonical pagemap via
* some custom mechanism.
*/
class CustomPagemap
{
/**
* Reference to the pagemap that we're using, allowing it to not be the
* default pagemap.
*/
SuperslabPagemap& custom_pagemap;
public:
/**
* Constructor. Takes the pagemap to use as an argument. This constructor
* will be inherited by `SuperslabMap` if this mixin is used and so should
* be called as a constructor there, rather than directly.
*/
CustomPagemap(SuperslabPagemap& pm) : custom_pagemap(pm) {}
/**
* Returns the provided pagemap.
*/
SuperslabPagemap& pagemap()
{
return custom_pagemap;
}
};
/**
* 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 `SuperslabMap` 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.
*/
SuperslabPagemap* external_pagemap;
public:
/**
* Construtor. 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 =
SuperslabPagemap::cast_to_pagemap(snmalloc_get_global_pagemap(&c), c);
// FIXME: Report an error somehow in non-debug builds.
assert(external_pagemap);
}
/**
* Returns the exported pagemap.
*/
SuperslabPagemap& 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).
*/
struct SuperslabMap
template<typename PagemapProvider = GlobalPagemap>
struct SuperslabMap : public PagemapProvider
{
/**
* Reference to the pagemap that we're using, allowing it to not be the
* default pagemap.
*/
SuperslabPagemap& pagemap;
/**
* Constructor. Uses the global pagemap by default, but can use a
* different one if required.
*/
SuperslabMap(SuperslabPagemap& pm = global_pagemap) : pagemap(pm) {}
using PagemapProvider::PagemapProvider;
/**
* Get the pagemap entry corresponding to a specific address.
*/
uint8_t get(void* p)
{
return pagemap.get(p);
return PagemapProvider::pagemap().get(p);
}
/**
* Set a pagemap entry indicating that there is a superslab at the
@@ -131,10 +213,11 @@ namespace snmalloc
for (size_t i = 0; i < size_bits - SUPERSLAB_BITS; i++)
{
size_t run = 1ULL << i;
pagemap.set_range((void*)ss, (uint8_t)(64 + i + SUPERSLAB_BITS), run);
PagemapProvider::pagemap().set_range(
(void*)ss, (uint8_t)(64 + i + SUPERSLAB_BITS), run);
ss = (uintptr_t)ss + SUPERSLAB_SIZE * run;
}
pagemap.set(p, (uint8_t)size_bits);
PagemapProvider::pagemap().set(p, (uint8_t)size_bits);
}
/**
* Update the pagemap to remove a large allocation, of `size` bytes from
@@ -145,7 +228,7 @@ namespace snmalloc
size_t rounded_size = bits::next_pow2(size);
assert(get(p) == bits::next_pow2_bits(size));
auto count = rounded_size >> SUPERSLAB_BITS;
pagemap.set_range((void*)p, PMNotOurs, count);
PagemapProvider::pagemap().set_range((void*)p, PMNotOurs, count);
}
private:
@@ -156,12 +239,12 @@ namespace snmalloc
*/
void set(void* p, uint8_t x)
{
pagemap.set(p, x);
PagemapProvider::pagemap().set(p, x);
}
};
#ifndef SNMALLOC_DEFAULT_PAGEMAP
# define SNMALLOC_DEFAULT_PAGEMAP snmalloc::SuperslabMap
# define SNMALLOC_DEFAULT_PAGEMAP snmalloc::SuperslabMap<>
#endif
/**