CapPtr: shift free lists to Alloc bounds

This is incomplete, yet still more reflective of what's going on: we take the
exported pointers back from userspace and thread them directly into the free
lists.

So: move capptr_to_user_address_control to list construction time rather than
list consumption time.
This commit is contained in:
Nathaniel Wesley Filardo
2021-09-21 19:17:51 +01:00
committed by Nathaniel Wesley Filardo
parent 55cd5e87c0
commit 7e53a2e82a
7 changed files with 99 additions and 91 deletions

View File

@@ -214,30 +214,29 @@ namespace snmalloc
auto slowpath =
[&](
sizeclass_t sizeclass,
FreeListIter<capptr::bounds::AllocFull, capptr::bounds::AllocFull>*
fl) SNMALLOC_FAST_PATH_LAMBDA {
if (likely(core_alloc != nullptr))
{
return core_alloc->handle_message_queue(
[](
CoreAlloc* core_alloc,
sizeclass_t sizeclass,
FreeListIter<
capptr::bounds::AllocFull,
capptr::bounds::AllocFull>* fl) {
return core_alloc->template small_alloc<zero_mem>(
sizeclass, *fl);
FreeListIter<capptr::bounds::Alloc, capptr::bounds::Alloc>* fl)
SNMALLOC_FAST_PATH_LAMBDA {
if (likely(core_alloc != nullptr))
{
return core_alloc->handle_message_queue(
[](
CoreAlloc* core_alloc,
sizeclass_t sizeclass,
FreeListIter<capptr::bounds::Alloc, capptr::bounds::Alloc>*
fl) {
return core_alloc->template small_alloc<zero_mem>(
sizeclass, *fl);
},
core_alloc,
sizeclass,
fl);
}
return lazy_init(
[&](CoreAlloc*, sizeclass_t sizeclass) {
return small_alloc<zero_mem>(sizeclass_to_size(sizeclass));
},
core_alloc,
sizeclass,
fl);
}
return lazy_init(
[&](CoreAlloc*, sizeclass_t sizeclass) {
return small_alloc<zero_mem>(sizeclass_to_size(sizeclass));
},
sizeclass);
};
sizeclass);
};
return local_cache.template alloc<zero_mem, SharedStateHandle>(
size, slowpath);
@@ -260,20 +259,18 @@ namespace snmalloc
* In the second case we need to recheck if this is a remote deallocation,
* as we might acquire the originating allocator.
*/
SNMALLOC_SLOW_PATH void dealloc_remote_slow(void* p)
SNMALLOC_SLOW_PATH void dealloc_remote_slow(capptr::Alloc<void> p)
{
if (core_alloc != nullptr)
{
#ifdef SNMALLOC_TRACING
std::cout << "Remote dealloc post" << p << " size " << alloc_size(p)
<< std::endl;
std::cout << "Remote dealloc post" << p.unsafe_ptr() << " size "
<< alloc_size(p.unsafe_ptr()) << std::endl;
#endif
MetaEntry entry = SharedStateHandle::Pagemap::get_metaentry(
core_alloc->backend_state_ptr(), address_cast(p));
local_cache.remote_dealloc_cache.template dealloc<sizeof(CoreAlloc)>(
entry.get_remote()->trunc_id(),
capptr::AllocFull<void>(p),
key_global);
entry.get_remote()->trunc_id(), p, key_global);
post_remote_cache();
return;
}
@@ -281,8 +278,8 @@ namespace snmalloc
// Recheck what kind of dealloc we should do incase, the allocator we get
// from lazy_init is the originating allocator.
lazy_init(
[&](CoreAlloc*, void* p) {
dealloc(p); // TODO don't double count statistics
[&](CoreAlloc*, CapPtr<void, capptr::bounds::Alloc> p) {
dealloc(p.unsafe_ptr()); // TODO don't double count statistics
return nullptr;
},
p);
@@ -450,10 +447,10 @@ namespace snmalloc
return alloc<zero_mem>(size);
}
SNMALLOC_FAST_PATH void dealloc(void* p)
SNMALLOC_FAST_PATH void dealloc(void* p_raw)
{
#ifdef SNMALLOC_PASS_THROUGH
external_alloc::free(p);
external_alloc::free(p_raw);
#else
// TODO:
// Care is needed so that dealloc(nullptr) works before init
@@ -461,6 +458,7 @@ namespace snmalloc
// before init, that maps null to a remote_deallocator that will never be
// in thread local state.
auto p = capptr_from_client(p_raw);
const MetaEntry& entry = SharedStateHandle::Pagemap::get_metaentry(
core_alloc->backend_state_ptr(), address_cast(p));
if (likely(local_cache.remote_allocator == entry.get_remote()))
@@ -478,12 +476,10 @@ namespace snmalloc
if (local_cache.remote_dealloc_cache.reserve_space(entry))
{
local_cache.remote_dealloc_cache.template dealloc<sizeof(CoreAlloc)>(
entry.get_remote()->trunc_id(),
capptr::AllocFull<void>(p),
key_global);
entry.get_remote()->trunc_id(), p, key_global);
# ifdef SNMALLOC_TRACING
std::cout << "Remote dealloc fast" << p << " size " << alloc_size(p)
<< std::endl;
std::cout << "Remote dealloc fast" << p_raw << " size "
<< alloc_size(p_raw) << std::endl;
# endif
return;
}
@@ -493,7 +489,7 @@ namespace snmalloc
}
// Large deallocation or null.
if (likely(p != nullptr))
if (likely(p.unsafe_ptr() != nullptr))
{
// Check this is managed by this pagemap.
check_client(entry.get_sizeclass() != 0, "Not allocated by snmalloc.");
@@ -511,7 +507,14 @@ namespace snmalloc
# endif
ChunkRecord* slab_record =
reinterpret_cast<ChunkRecord*>(entry.get_metaslab());
slab_record->chunk = capptr::Chunk<void>(p);
/*
* StrictProvenance TODO: this is a subversive amplification. p is
* AllocWild-bounded, but we're coercing it to Chunk-bounded. We
* should, instead, not be storing ->chunk here, but should be keeping
* a CapPtr<void, Chunk> to this region internally even while it's
* allocated.
*/
slab_record->chunk = capptr::Chunk<void>(p.unsafe_ptr());
check_init(
[](
CoreAlloc* core_alloc,