5 #include "src/base/region-allocator.h" 6 #include "src/base/bits.h" 7 #include "src/base/macros.h" 14 constexpr
double kMaxLoadFactorForRandomization = 0.40;
17 constexpr
int kMaxRandomizationAttempts = 3;
19 RegionAllocator::RegionAllocator(Address memory_region_begin,
20 size_t memory_region_size,
size_t page_size)
21 : whole_region_(memory_region_begin, memory_region_size, false),
22 region_size_in_pages_(size() / page_size),
23 max_load_for_randomization_(
24 static_cast<
size_t>(size() * kMaxLoadFactorForRandomization)),
26 page_size_(page_size) {
27 CHECK_LT(begin(), end());
28 CHECK(base::bits::IsPowerOfTwo(page_size_));
29 CHECK(IsAligned(size(), page_size_));
30 CHECK(IsAligned(begin(), page_size_));
33 Region* region =
new Region(whole_region_);
35 all_regions_.insert(region);
37 FreeListAddRegion(region);
40 RegionAllocator::~RegionAllocator() {
41 for (Region* region : all_regions_) {
46 RegionAllocator::AllRegionsSet::iterator RegionAllocator::FindRegion(
48 if (!whole_region_.contains(address))
return all_regions_.end();
50 Region key(address, 0,
false);
51 AllRegionsSet::iterator iter = all_regions_.upper_bound(&key);
55 DCHECK_NE(iter, all_regions_.end());
56 DCHECK((*iter)->contains(address));
60 void RegionAllocator::FreeListAddRegion(Region* region) {
61 free_size_ += region->size();
62 free_regions_.insert(region);
65 RegionAllocator::Region* RegionAllocator::FreeListFindRegion(
size_t size) {
66 Region key(0, size,
false);
67 auto iter = free_regions_.lower_bound(&key);
68 return iter == free_regions_.end() ? nullptr : *iter;
71 void RegionAllocator::FreeListRemoveRegion(Region* region) {
72 DCHECK(!region->is_used());
73 auto iter = free_regions_.find(region);
74 DCHECK_NE(iter, free_regions_.end());
75 DCHECK_EQ(region, *iter);
76 DCHECK_LE(region->size(), free_size_);
77 free_size_ -= region->size();
78 free_regions_.erase(iter);
81 RegionAllocator::Region* RegionAllocator::Split(Region* region,
83 DCHECK(IsAligned(new_size, page_size_));
84 DCHECK_NE(new_size, 0);
85 DCHECK_GT(region->size(), new_size);
88 bool used = region->is_used();
90 new Region(region->begin() + new_size, region->size() - new_size, used);
93 FreeListRemoveRegion(region);
95 region->set_size(new_size);
97 all_regions_.insert(new_region);
100 FreeListAddRegion(region);
101 FreeListAddRegion(new_region);
106 void RegionAllocator::Merge(AllRegionsSet::iterator prev_iter,
107 AllRegionsSet::iterator next_iter) {
108 Region* prev = *prev_iter;
109 Region* next = *next_iter;
110 DCHECK_EQ(prev->end(), next->begin());
111 prev->set_size(prev->size() + next->size());
113 all_regions_.erase(next_iter);
116 DCHECK_EQ(free_regions_.find(next), free_regions_.end());
120 RegionAllocator::Address RegionAllocator::AllocateRegion(
size_t size) {
122 DCHECK(IsAligned(size, page_size_));
124 Region* region = FreeListFindRegion(size);
125 if (region ==
nullptr)
return kAllocationFailure;
127 if (region->size() != size) {
130 DCHECK(IsAligned(region->begin(), page_size_));
131 DCHECK_EQ(region->size(), size);
134 FreeListRemoveRegion(region);
135 region->set_is_used(
true);
136 return region->begin();
139 RegionAllocator::Address RegionAllocator::AllocateRegion(
140 RandomNumberGenerator* rng,
size_t size) {
141 if (free_size() >= max_load_for_randomization_) {
145 for (
int i = 0;
i < kMaxRandomizationAttempts;
i++) {
146 rng->NextBytes(&random,
sizeof(random));
147 size_t random_offset = page_size_ * (random % region_size_in_pages_);
148 Address address = begin() + random_offset;
149 if (AllocateRegionAt(address, size)) {
155 return AllocateRegion(size);
158 bool RegionAllocator::AllocateRegionAt(Address requested_address,
size_t size) {
159 DCHECK(IsAligned(requested_address, page_size_));
161 DCHECK(IsAligned(size, page_size_));
163 Address requested_end = requested_address + size;
164 DCHECK_LE(requested_end, end());
168 AllRegionsSet::iterator region_iter = FindRegion(requested_address);
169 if (region_iter == all_regions_.end()) {
172 region = *region_iter;
174 if (region->is_used() || region->end() < requested_end) {
178 if (region->begin() != requested_address) {
180 size_t new_size = requested_address - region->begin();
181 DCHECK(IsAligned(new_size, page_size_));
182 region = Split(region, new_size);
184 if (region->end() != requested_end) {
188 DCHECK_EQ(region->begin(), requested_address);
189 DCHECK_EQ(region->size(), size);
192 FreeListRemoveRegion(region);
193 region->set_is_used(
true);
197 size_t RegionAllocator::TrimRegion(Address address,
size_t new_size) {
198 DCHECK(IsAligned(new_size, page_size_));
200 AllRegionsSet::iterator region_iter = FindRegion(address);
201 if (region_iter == all_regions_.end()) {
204 Region* region = *region_iter;
205 if (region->begin() != address || !region->is_used()) {
210 DCHECK_EQ(free_regions_.find(*region_iter), free_regions_.end());
213 region = Split(region, new_size);
216 size_t size = region->size();
217 region->set_is_used(
false);
220 if (region->end() != whole_region_.end()) {
222 AllRegionsSet::iterator next_iter = std::next(region_iter);
223 DCHECK_NE(next_iter, all_regions_.end());
224 if (!(*next_iter)->is_used()) {
227 FreeListRemoveRegion(*next_iter);
228 Merge(region_iter, next_iter);
231 if (new_size == 0 && region->begin() != whole_region_.begin()) {
233 AllRegionsSet::iterator prev_iter = std::prev(region_iter);
234 DCHECK_NE(prev_iter, all_regions_.end());
235 if (!(*prev_iter)->is_used()) {
238 FreeListRemoveRegion(*prev_iter);
239 Merge(prev_iter, region_iter);
241 region_iter = prev_iter;
242 region = *region_iter;
245 FreeListAddRegion(region);
249 size_t RegionAllocator::CheckRegion(Address address) {
250 AllRegionsSet::iterator region_iter = FindRegion(address);
251 if (region_iter == all_regions_.end()) {
254 Region* region = *region_iter;
255 if (region->begin() != address || !region->is_used()) {
258 return region->size();
261 bool RegionAllocator::IsFree(Address address,
size_t size) {
262 CHECK(contains(address, size));
263 AllRegionsSet::iterator region_iter = FindRegion(address);
264 if (region_iter == all_regions_.end()) {
267 Region* region = *region_iter;
268 return !region->is_used() && region->contains(address, size);
271 void RegionAllocator::Region::Print(std::ostream& os)
const {
272 std::ios::fmtflags flags = os.flags(std::ios::hex | std::ios::showbase);
273 os <<
"[" << begin() <<
", " << end() <<
"), size: " << size();
274 os <<
", " << (is_used() ?
"used" :
"free");
278 void RegionAllocator::Print(std::ostream& os)
const {
279 std::ios::fmtflags flags = os.flags(std::ios::hex | std::ios::showbase);
280 os <<
"RegionAllocator: [" << begin() <<
", " << end() <<
")";
281 os <<
"\nsize: " << size();
282 os <<
"\nfree_size: " << free_size();
283 os <<
"\npage_size: " << page_size_;
285 os <<
"\nall regions: ";
286 for (
const Region* region : all_regions_) {
291 os <<
"\nfree regions: ";
292 for (
const Region* region : free_regions_) {