v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
allocation.h
Go to the documentation of this file.
1// Copyright 2012 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_UTILS_ALLOCATION_H_
6#define V8_UTILS_ALLOCATION_H_
7
8#include <new>
9
10#include "include/v8-platform.h"
15#include "src/init/v8.h"
16
17namespace v8 {
18
19namespace base {
20class BoundedPageAllocator;
21} // namespace base
22
23namespace internal {
24
25class Isolate;
26
27// This file defines memory allocation functions. If a first attempt at an
28// allocation fails, these functions call back into the embedder, then attempt
29// the allocation a second time. The embedder callback must not reenter V8.
30
31// Superclass for classes managed with new & delete.
33 public:
34 static void* operator new(size_t size);
35 static void operator delete(void* p);
36};
37
38// Function that may release reserved memory regions to allow failed allocations
39// to succeed.
41
42template <typename T>
43T* NewArray(size_t size) {
44 T* result = new (std::nothrow) T[size];
45 if (V8_UNLIKELY(result == nullptr)) {
47 result = new (std::nothrow) T[size];
48 if (result == nullptr) V8::FatalProcessOutOfMemory(nullptr, "NewArray");
49 }
50 return result;
51}
52
53template <typename T>
54T* NewArray(size_t size, T default_val)
56{
57 T* result = reinterpret_cast<T*>(NewArray<uint8_t>(sizeof(T) * size));
58 for (size_t i = 0; i < size; ++i) result[i] = default_val;
59 return result;
60}
61
62template <typename T>
63void DeleteArray(T* array) {
64 delete[] array;
65}
66
67template <typename T>
69 void operator()(T* array) { DeleteArray(array); }
70};
71
72template <typename T>
73using ArrayUniquePtr = std::unique_ptr<T, ArrayDeleter<T>>;
74
75// The normal strdup functions use malloc. These versions of StrDup
76// and StrNDup uses new and calls the FatalProcessOutOfMemory handler
77// if allocation fails.
78V8_EXPORT_PRIVATE char* StrDup(const char* str);
79char* StrNDup(const char* str, int n);
80
81// Allocation policy for allocating in the C free store using malloc
82// and free. Used as the default policy for lists.
84 public:
85 template <typename T, typename TypeTag = T[]>
86 V8_INLINE T* AllocateArray(size_t length) {
87 return static_cast<T*>(Malloced::operator new(length * sizeof(T)));
88 }
89 template <typename T, typename TypeTag = T[]>
90 V8_INLINE void DeleteArray(T* p, size_t length) {
91 Malloced::operator delete(p);
92 }
93};
94
95using MallocFn = void* (*)(size_t);
96
97// Performs a malloc, with retry logic on failure. Returns nullptr on failure.
98// Call free to release memory allocated with this function.
99void* AllocWithRetry(size_t size, MallocFn = base::Malloc);
100
101// Performs a malloc, with retry logic on failure. Returns nullptr on failure.
102// Call free to release memory allocated with this function.
104
105V8_EXPORT_PRIVATE void* AlignedAllocWithRetry(size_t size, size_t alignment);
106V8_EXPORT_PRIVATE void AlignedFree(void* ptr);
107
108// Returns platfrom page allocator instance. Guaranteed to be a valid pointer.
110
111// Returns platfrom virtual memory space instance. Guaranteed to be a valid
112// pointer.
114
115#ifdef V8_ENABLE_SANDBOX
116// Returns the page allocator instance for allocating pages inside the sandbox.
117// Guaranteed to be a valid pointer.
118V8_EXPORT_PRIVATE v8::PageAllocator* GetSandboxPageAllocator();
119#endif
120
121// Returns the appropriate page allocator to use for ArrayBuffer backing
122// stores. If the sandbox is enabled, these must be allocated inside the
123// sandbox and so this will be the SandboxPageAllocator. Otherwise it will be
124// the PlatformPageAllocator.
126#ifdef V8_ENABLE_SANDBOX
127 return GetSandboxPageAllocator();
128#else
130#endif
131}
132
133// Sets the given page allocator as the platform page allocator and returns
134// the current one. This function *must* be used only for testing purposes.
135// It is not thread-safe and the testing infrastructure should ensure that
136// the tests do not modify the value simultaneously.
138 v8::PageAllocator* page_allocator);
139
140// Gets the page granularity for AllocatePages and FreePages. Addresses returned
141// by AllocatePages are aligned to this size.
143
144// Gets the granularity at which the permissions and release calls can be made.
146
147// Generate a random address to be used for hinting allocation calls.
149
150// Allocates memory. Permissions are set according to the access argument.
151// |address| is a hint. |size| and |alignment| must be multiples of
152// AllocatePageSize(). Returns the address of the allocated memory, with the
153// specified size and alignment, or nullptr on failure.
156 void* address, size_t size,
157 size_t alignment,
159
160// Frees memory allocated by a call to AllocatePages. |address| and |size| must
161// be multiples of AllocatePageSize().
163void FreePages(v8::PageAllocator* page_allocator, void* address,
164 const size_t size);
165
166// Releases memory that is no longer needed. The range specified by |address|
167// and |size| must be an allocated memory region. |size| and |new_size| must be
168// multiples of CommitPageSize(). Memory from |new_size| to |size| is released.
169// Released memory is left in an undefined state, so it should not be accessed.
171void ReleasePages(v8::PageAllocator* page_allocator, void* address, size_t size,
172 size_t new_size);
173
174// Sets permissions according to |access|. |address| and |size| must be
175// multiples of CommitPageSize(). Setting permission to kNoAccess may
176// cause the memory contents to be lost. Returns true on success, otherwise
177// false.
180 void* address, size_t size,
182inline bool SetPermissions(v8::PageAllocator* page_allocator, Address address,
183 size_t size, PageAllocator::Permission access) {
184 return SetPermissions(page_allocator, reinterpret_cast<void*>(address), size,
185 access);
186}
187
188// Defines whether the address space reservation is going to be used for
189// allocating executable pages.
191
192// Represents and controls an area of reserved memory.
193class VirtualMemory final {
194 public:
195 // Empty VirtualMemory object, controlling no reserved memory.
197
198 VirtualMemory(const VirtualMemory&) = delete;
200
201 // Reserves virtual memory containing an area of the given size that is
202 // aligned per |alignment| rounded up to the |page_allocator|'s allocate page
203 // size. The |size| must be aligned with |page_allocator|'s commit page size.
204 // This may not be at the position returned by address().
206 v8::PageAllocator* page_allocator, size_t size, void* hint,
207 size_t alignment = 1,
209
210 // Construct a virtual memory by assigning it some already mapped address
211 // and size.
218
219 // Releases the reserved memory, if any, controlled by this VirtualMemory
220 // object.
222
223 // Move constructor.
224 VirtualMemory(VirtualMemory&& other) V8_NOEXCEPT { *this = std::move(other); }
225
226 // Move assignment operator.
228 DCHECK(!IsReserved());
229 page_allocator_ = other.page_allocator_;
230 region_ = other.region_;
231 other.Reset();
232 return *this;
233 }
234
235 // Returns whether the memory has been reserved.
236 bool IsReserved() const { return region_.begin() != kNullAddress; }
237
238 // Initialize or resets an embedded VirtualMemory object.
240
242
243 const base::AddressRegion& region() const { return region_; }
244
245 // Returns the start address of the reserved memory.
246 // If the memory was reserved with an alignment, this address is not
247 // necessarily aligned. The user might need to round it up to a multiple of
248 // the alignment to get the start of the aligned block.
249 Address address() const {
251 return region_.begin();
252 }
253
254 Address end() const {
256 return region_.end();
257 }
258
259 // Returns the size of the reserved memory. The returned value is only
260 // meaningful when IsReserved() returns true.
261 // If the memory was reserved with an alignment, this size may be larger
262 // than the requested size.
263 size_t size() const { return region_.size(); }
264
265 // Sets permissions according to the access argument. address and size must be
266 // multiples of CommitPageSize(). Returns true on success, otherwise false.
268 Address address, size_t size, PageAllocator::Permission access);
269
270 // Recommits discarded pages in the given range with given permissions.
271 // Discarded pages must be recommitted with their original permissions
272 // before they are used again. |address| and |size| must be multiples of
273 // CommitPageSize(). Returns true on success, otherwise false.
275 Address address, size_t size, PageAllocator::Permission access);
276
277 // Frees memory in the given [address, address + size) range. address and size
278 // should be operating system page-aligned. The next write to this
279 // memory area brings the memory transparently back. This should be treated as
280 // a hint to the OS that the pages are no longer needed. It does not guarantee
281 // that the pages will be discarded immediately or at all.
283
284 // Releases memory after |free_start|. Returns the number of bytes released.
285 V8_EXPORT_PRIVATE size_t Release(Address free_start);
286
287 // Frees all memory.
288 V8_EXPORT_PRIVATE void Free();
289
290 bool InVM(Address address, size_t size) const {
291 return region_.contains(address, size);
292 }
293
294 private:
295 // Page allocator that controls the virtual memory.
298};
299
300// Represents a VirtualMemory reservation along with a BoundedPageAllocator that
301// can be used to allocate within the reservation.
302//
303// Virtual memory cages are used for the pointer compression cage, the code
304// ranges (on platforms that require code ranges), and trusted ranges (when the
305// sandbox is enabled). They are configurable via ReservationParams.
306//
307// +-----------+------------ ~~~ --+- ~~~ -+
308// | ... | ... | ... |
309// +-----------+------------ ~~~ --+- ~~~ -+
310// ^ ^
311// cage base allocatable base
312//
313// <------------------->
314// allocatable size
315// <------------------------------->
316// cage size
317// <--------------------------------------->
318// reservation size
319//
320// - The reservation is made using ReservationParams::page_allocator.
321// - cage base is the start of the virtual memory reservation and the base
322// address of the cage.
323// - allocatable base is the cage base rounded up to the nearest
324// ReservationParams::page_size, and is the start of the allocatable area for
325// the BoundedPageAllocator.
326// - cage size is the size of the area from cage base to the end of the
327// allocatable area.
328//
329// - The reservation size is configured by ReservationParams::reservation_size
330// but it might be actually bigger if we end up over-reserving the virtual
331// address space.
332//
333// Additionally,
334// - The alignment of the cage base is configured by
335// ReservationParams::base_alignment.
336// - The page size of the BoundedPageAllocator is configured by
337// ReservationParams::page_size.
338// - A hint for the value of start can be passed by
339// ReservationParams::requested_start_hint and it must be aligned to
340// ReservationParams::base_alignment.
341//
342// The configuration is subject to the following alignment requirements.
343// Below, AllocatePageSize is short for
344// ReservationParams::page_allocator->AllocatePageSize().
345//
346// - The reservation size must be AllocatePageSize-aligned.
347// - If the base alignment is not kAnyBaseAlignment then the base alignment
348// must be AllocatePageSize-aligned.
349// - The base alignment may be kAnyBaseAlignment to denote any alignment is
350// acceptable. In this case the base bias size does not need to be aligned.
352 public:
354 virtual ~VirtualMemoryCage();
355
358
361
362 Address base() const { return base_; }
363 size_t size() const { return size_; }
364
368
372
374 const VirtualMemory* reservation() const { return &reservation_; }
375
381
396
397 // A number of attempts is made to try to reserve a region that satisfies the
398 // constraints in params, but this may fail. The base address may be different
399 // than the one requested.
400 // If an existing reservation is provided, it will be used for this cage
401 // instead. The caller retains ownership of the reservation and is responsible
402 // for keeping the memory reserved during the lifetime of this object.
403 bool InitReservation(
404 const ReservationParams& params,
405 base::AddressRegion existing_reservation = base::AddressRegion());
406
407 void Free();
408
409 protected:
411 size_t size_ = 0;
412 std::unique_ptr<base::BoundedPageAllocator> page_allocator_;
414};
415
416} // namespace internal
417} // namespace v8
418
419#endif // V8_UTILS_ALLOCATION_H_
#define T
virtual size_t AllocatePageSize()=0
virtual size_t CommitPageSize()=0
bool contains(Address address) const
V8_INLINE void DeleteArray(T *p, size_t length)
Definition allocation.h:90
V8_INLINE T * AllocateArray(size_t length)
Definition allocation.h:86
static V8_EXPORT_PRIVATE void FatalProcessOutOfMemory(Isolate *isolate, const char *location, const OOMDetails &details=kNoOOMDetails)
base::BoundedPageAllocator * page_allocator() const
Definition allocation.h:369
base::AddressRegion region() const
Definition allocation.h:365
const VirtualMemory * reservation() const
Definition allocation.h:374
VirtualMemoryCage(const VirtualMemoryCage &)=delete
bool InitReservation(const ReservationParams &params, base::AddressRegion existing_reservation=base::AddressRegion())
std::unique_ptr< base::BoundedPageAllocator > page_allocator_
Definition allocation.h:412
VirtualMemory * reservation()
Definition allocation.h:373
VirtualMemoryCage & operator=(VirtualMemoryCage &)=delete
v8::PageAllocator * page_allocator_
Definition allocation.h:296
V8_EXPORT_PRIVATE ~VirtualMemory()
VirtualMemory(VirtualMemory &&other) V8_NOEXCEPT
Definition allocation.h:224
V8_EXPORT_PRIVATE bool DiscardSystemPages(Address address, size_t size)
V8_EXPORT_PRIVATE VirtualMemory()
bool InVM(Address address, size_t size) const
Definition allocation.h:290
VirtualMemory(v8::PageAllocator *page_allocator, Address address, size_t size)
Definition allocation.h:212
v8::PageAllocator * page_allocator()
Definition allocation.h:241
base::AddressRegion region_
Definition allocation.h:297
VirtualMemory(const VirtualMemory &)=delete
VirtualMemory & operator=(VirtualMemory &&other) V8_NOEXCEPT
Definition allocation.h:227
VirtualMemory & operator=(const VirtualMemory &)=delete
V8_EXPORT_PRIVATE void Free()
V8_EXPORT_PRIVATE void Reset()
V8_EXPORT_PRIVATE size_t Release(Address free_start)
V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT bool SetPermissions(Address address, size_t size, PageAllocator::Permission access)
const base::AddressRegion & region() const
Definition allocation.h:243
V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT bool RecommitPages(Address address, size_t size, PageAllocator::Permission access)
ZoneVector< RpoNumber > & result
void * Malloc(size_t size)
Definition memory.h:36
void DeleteArray(T *array)
Definition allocation.h:63
bool SetPermissions(v8::PageAllocator *page_allocator, void *address, size_t size, PageAllocator::Permission access)
v8::PageAllocator * GetPlatformPageAllocator()
Definition allocation.cc:66
void * AllocatePages(v8::PageAllocator *page_allocator, void *hint, size_t size, size_t alignment, PageAllocator::Permission access)
v8::PageAllocator * SetPlatformPageAllocatorForTesting(v8::PageAllocator *new_page_allocator)
Definition allocation.cc:88
void * AlignedAllocWithRetry(size_t size, size_t alignment)
void OnCriticalMemoryPressure()
void * GetRandomMmapAddr()
std::unique_ptr< T, ArrayDeleter< T > > ArrayUniquePtr
Definition allocation.h:73
v8::PageAllocator * GetArrayBufferPageAllocator()
Definition allocation.h:125
size_t CommitPageSize()
char * StrDup(const char *str)
void *(*)(size_t) MallocFn
Definition allocation.h:95
v8::VirtualAddressSpace * GetPlatformVirtualAddressSpace()
Definition allocation.cc:71
size_t AllocatePageSize()
void * AllocWithRetry(size_t size, MallocFn malloc_fn)
void AlignedFree(void *ptr)
base::AllocationResult< void * > AllocAtLeastWithRetry(size_t size)
char * StrNDup(const char *str, size_t n)
static constexpr Address kNullAddress
Definition v8-internal.h:53
void ReleasePages(v8::PageAllocator *page_allocator, void *address, size_t size, size_t new_size)
T * NewArray(size_t size)
Definition allocation.h:43
void FreePages(v8::PageAllocator *page_allocator, void *address, const size_t size)
#define V8_NOEXCEPT
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_EXPORT_PRIVATE
Definition macros.h:460
constexpr bool IsAligned(T value, U alignment)
Definition macros.h:403
void operator()(T *array)
Definition allocation.h:69
base::PageInitializationMode page_initialization_mode
Definition allocation.h:391
#define V8_INLINE
Definition v8config.h:500
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671
#define V8_UNLIKELY(condition)
Definition v8config.h:660