1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#pragma once
#include "../ds/ds.h"
#include "../mem/mem.h"
#include "snmalloc/stl/atomic.h"
#include "snmalloc/stl/utility.h"
namespace snmalloc
{
/**
* 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 PAL,
typename ConcreteMap,
typename PagemapEntry,
bool fixed_range>
class BasicPagemap
{
public:
/**
* Export the type stored in the pagemap.
*/
using Entry = PagemapEntry;
static_assert(
stl::is_same_v<PagemapEntry, typename ConcreteMap::EntryType>,
"BasicPagemap's PagemapEntry and ConcreteMap disagree!");
static_assert(
stl::is_base_of_v<MetaEntryBase, PagemapEntry>,
"BasicPagemap's PagemapEntry type is not a MetaEntryBase");
/**
* Prevent snmalloc's backend ranges from consolidating across adjacent OS
* allocations on platforms (e.g., Windows or StrictProvenance) where
* that's required.
*/
#if defined(_WIN32) || defined(__CHERI_PURE_CAPABILITY__)
static constexpr bool CONSOLIDATE_PAL_ALLOCS = false;
#else
static constexpr bool CONSOLIDATE_PAL_ALLOCS = true;
#endif
/**
* 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);
}
}
/**
* 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.
*
* Mark the MetaEntry at the bottom of the range as a boundary, preventing
* consolidation with a lower range, unless CONSOLIDATE_PAL_ALLOCS.
*/
static bool register_range(capptr::Arena<void> p, size_t sz)
{
auto result = concretePagemap.register_range(address_cast(p), sz);
if (!result)
{
return false;
}
if constexpr (!CONSOLIDATE_PAL_ALLOCS)
{
// Mark start of allocation in pagemap.
auto& entry = get_metaentry_mut(address_cast(p));
entry.set_boundary();
}
return true;
}
/**
* 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
stl::enable_if_t<fixed_range_, stl::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