v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
region-allocator.h
Go to the documentation of this file.
1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_BASE_REGION_ALLOCATOR_H_
6#define V8_BASE_REGION_ALLOCATOR_H_
7
8#include <set>
9
12#include "testing/gtest/include/gtest/gtest_prod.h" // nogncheck
13
14namespace v8 {
15namespace base {
16
17// Helper class for managing used/free regions within [address, address+size)
18// region. Minimum allocation unit is |page_size|. Requested allocation size
19// is rounded up to |page_size|.
20// The region allocation algorithm implements best-fit with coalescing strategy:
21// it tries to find a smallest suitable free region upon allocation and tries
22// to merge region with its neighbors upon freeing.
23//
24// This class does not perform any actual region reservation.
25// Not thread-safe.
27 public:
28 using Address = uintptr_t;
29
30 using SplitMergeCallback = std::function<void(Address start, size_t size)>;
31
32 static constexpr Address kAllocationFailure = static_cast<Address>(-1);
33
34 enum class RegionState {
35 // The region can be allocated from.
36 kFree,
37 // The region has been carved out of the wider area and is not allocatable.
38 kExcluded,
39 // The region has been allocated and is managed by a RegionAllocator.
40 kAllocated,
41 };
42
43 RegionAllocator(Address address, size_t size, size_t page_size);
47
48 // Split and merge callbacks.
49 //
50 // These callbacks can be installed to perform additional logic when regions
51 // are split or merged. For example, when managing Windows placeholder
52 // regions, a region must be split into sub-regions (using
53 // VirtualFree(MEM_PRESERVE_PLACEHOLDER)) before a part of it can be replaced
54 // with an actual memory mapping. Similarly, multiple sub-regions must be
55 // merged (using VirtualFree(MEM_COALESCE_PLACEHOLDERS)) when coalescing them
56 // into a larger, free region again.
57 //
58 // The on_split callback is called to signal that an existing region is split
59 // so that [start, start+size) becomes a new region.
63 // The on_merge callback is called to signal that all regions in the range
64 // [start, start+size) are merged into a single one.
68
69 // Allocates region of |size| (must be |page_size|-aligned). Returns
70 // the address of the region on success or kAllocationFailure.
71 Address AllocateRegion(size_t size);
72 // Same as above but tries to randomize the region displacement.
73 Address AllocateRegion(RandomNumberGenerator* rng, size_t size);
74
75 // Allocates region of |size| at |requested_address| if it's free. Both the
76 // address and the size must be |page_size|-aligned. On success returns
77 // true.
78 // This kind of allocation is supposed to be used during setup phase to mark
79 // certain regions as used or for randomizing regions displacement.
80 // By default regions are marked as used, but can also be allocated as
81 // RegionState::kExcluded to prevent the RegionAllocator from using that
82 // memory range, which is useful when reserving any area to remap shared
83 // memory into.
84 bool AllocateRegionAt(Address requested_address, size_t size,
85 RegionState region_state = RegionState::kAllocated);
86
87 // Allocates a region of |size| aligned to |alignment|. The size and alignment
88 // must be a multiple of |page_size|. Returns the address of the region on
89 // success or kAllocationFailure.
90 Address AllocateAlignedRegion(size_t size, size_t alignment);
91
92 // Attempts to allocate a region of the given size and alignment at the
93 // specified address but fall back to allocating the region elsewhere if
94 // necessary.
95 Address AllocateRegion(Address hint, size_t size, size_t alignment);
96
97 // Frees region at given |address|, returns the size of the region.
98 // There must be a used region starting at given address otherwise nothing
99 // will be freed and 0 will be returned.
100 size_t FreeRegion(Address address) { return TrimRegion(address, 0); }
101
102 // Decreases size of the previously allocated region at |address|, returns
103 // freed size. |new_size| must be |page_size|-aligned and
104 // less than or equal to current region's size. Setting new size to zero
105 // frees the region.
106 size_t TrimRegion(Address address, size_t new_size);
107
108 // If there is a used region starting at given address returns its size
109 // otherwise 0.
110 size_t CheckRegion(Address address);
111
112 // Returns true if there are no pages allocated in given region.
113 bool IsFree(Address address, size_t size);
114
115 Address begin() const { return whole_region_.begin(); }
116 Address end() const { return whole_region_.end(); }
117 size_t size() const { return whole_region_.size(); }
118
119 bool contains(Address address) const {
120 return whole_region_.contains(address);
121 }
122
123 bool contains(Address address, size_t size) const {
124 return whole_region_.contains(address, size);
125 }
126
127 // Total size of not yet acquired regions.
128 size_t free_size() const { return free_size_; }
129
130 // The alignment of the allocated region's addresses and granularity of
131 // the allocated region's sizes.
132 size_t page_size() const { return page_size_; }
133
134 void Print(std::ostream& os) const;
135
136 private:
137 class Region : public AddressRegion {
138 public:
139 Region(Address address, size_t size, RegionState state)
140 : AddressRegion(address, size), state_(state) {}
141
142 bool is_free() const { return state_ == RegionState::kFree; }
143 bool is_allocated() const { return state_ == RegionState::kAllocated; }
144 bool is_excluded() const { return state_ == RegionState::kExcluded; }
145
148
149 void Print(std::ostream& os) const;
150
151 private:
153 };
154
155 // The whole region.
157
158 // Number of |page_size_| in the whole region.
160
161 // If the free size is less than this value - stop trying to randomize the
162 // allocation addresses.
164
165 // Size of all free regions.
167
168 // Minimum region size. Must be a pow of 2.
169 const size_t page_size_;
170
172 bool operator()(const Region* a, const Region* b) const {
173 return a->end() < b->end();
174 }
175 };
176 // All regions ordered by addresses.
177 using AllRegionsSet = std::set<Region*, AddressEndOrder>;
179
181 bool operator()(const Region* a, const Region* b) const {
182 if (a->size() != b->size()) return a->size() < b->size();
183 return a->begin() < b->begin();
184 }
185 };
186 // Free regions ordered by sizes and addresses.
187 std::set<Region*, SizeAddressOrder> free_regions_;
188
189 // Callbacks called when regions are split or merged.
192
193 // Returns region containing given address or nullptr.
194 AllRegionsSet::iterator FindRegion(Address address);
195
196 // Adds given region to the set of free regions.
197 void FreeListAddRegion(Region* region);
198
199 // Finds best-fit free region for given size.
200 Region* FreeListFindRegion(size_t size);
201
202 // Removes given region from the set of free regions.
203 void FreeListRemoveRegion(Region* region);
204
205 // Splits given |region| into two: one of |new_size| size and a new one
206 // having the rest. The new region is returned.
207 Region* Split(Region* region, size_t new_size);
208
209 // For two coalescing regions merges |next| to |prev| and deletes |next|.
210 void Merge(AllRegionsSet::iterator prev_iter,
211 AllRegionsSet::iterator next_iter);
212
213 FRIEND_TEST(RegionAllocatorTest, AllocateExcluded);
214 FRIEND_TEST(RegionAllocatorTest, AllocateRegionRandom);
215 FRIEND_TEST(RegionAllocatorTest, Contains);
216 FRIEND_TEST(RegionAllocatorTest, FindRegion);
217 FRIEND_TEST(RegionAllocatorTest, Fragmentation);
218};
219
220} // namespace base
221} // namespace v8
222
223#endif // V8_BASE_REGION_ALLOCATOR_H_
#define V8_BASE_EXPORT
Definition base-export.h:26
Region(Address address, size_t size, RegionState state)
void set_state(RegionState state)
RegionAllocator(const RegionAllocator &)=delete
FRIEND_TEST(RegionAllocatorTest, Fragmentation)
FRIEND_TEST(RegionAllocatorTest, Contains)
FRIEND_TEST(RegionAllocatorTest, FindRegion)
RegionAllocator & operator=(const RegionAllocator &)=delete
FRIEND_TEST(RegionAllocatorTest, AllocateRegionRandom)
bool contains(Address address) const
void set_on_split_callback(SplitMergeCallback callback)
const size_t max_load_for_randomization_
SplitMergeCallback on_split_
std::set< Region *, AddressEndOrder > AllRegionsSet
SplitMergeCallback on_merge_
void set_on_merge_callback(SplitMergeCallback callback)
FRIEND_TEST(RegionAllocatorTest, AllocateExcluded)
bool contains(Address address, size_t size) const
std::function< void(Address start, size_t size)> SplitMergeCallback
size_t FreeRegion(Address address)
std::set< Region *, SizeAddressOrder > free_regions_
int start
enum v8::internal::@1270::DeoptimizableCodeIterator::@67 state_
TNode< Object > callback
LiftoffAssembler::CacheState state
uintptr_t Address
Definition memory.h:13
bool operator()(const Region *a, const Region *b) const
bool operator()(const Region *a, const Region *b) const