1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef jit_JitAllocPolicy_h
8 #define jit_JitAllocPolicy_h
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/Likely.h"
13 #include "mozilla/OperatorNewExtensions.h"
14 #include "mozilla/TemplateLib.h"
19 #include <type_traits>
22 #include "ds/LifoAlloc.h"
23 #include "jit/InlineList.h"
24 #include "js/Utility.h"
30 LifoAllocScope lifoScope_
;
33 // Most infallible JIT allocations are small, so we use a ballast of 16
34 // KiB. And with a ballast of 16 KiB, a chunk size of 32 KiB works well,
35 // because TempAllocators with a peak allocation size of less than 16 KiB
36 // (which is most of them) only have to allocate a single chunk.
37 static const size_t BallastSize
; // 16 KiB
38 static const size_t PreferredLifoChunkSize
; // 32 KiB
40 explicit TempAllocator(LifoAlloc
* lifoAlloc
) : lifoScope_(lifoAlloc
) {
41 lifoAlloc
->setAsInfallibleByDefault();
44 void* allocateInfallible(size_t bytes
) {
45 return lifoScope_
.alloc().allocInfallible(bytes
);
48 [[nodiscard
]] void* allocate(size_t bytes
) {
49 LifoAlloc::AutoFallibleScope
fallibleAllocator(lifoAlloc());
50 return lifoScope_
.alloc().allocEnsureUnused(bytes
, BallastSize
);
54 [[nodiscard
]] T
* allocateArray(size_t n
) {
55 LifoAlloc::AutoFallibleScope
fallibleAllocator(lifoAlloc());
57 if (MOZ_UNLIKELY(!CalculateAllocSize
<T
>(n
, &bytes
))) {
60 return static_cast<T
*>(
61 lifoScope_
.alloc().allocEnsureUnused(bytes
, BallastSize
));
64 // View this allocator as a fallible allocator.
68 Fallible
fallible() { return {*this}; }
70 LifoAlloc
* lifoAlloc() { return &lifoScope_
.alloc(); }
72 [[nodiscard
]] bool ensureBallast() {
73 JS_OOM_POSSIBLY_FAIL_BOOL();
74 return lifoScope_
.alloc().ensureUnusedApproximate(BallastSize
);
78 class JitAllocPolicy
{
79 TempAllocator
& alloc_
;
82 MOZ_IMPLICIT
JitAllocPolicy(TempAllocator
& alloc
) : alloc_(alloc
) {}
84 T
* maybe_pod_malloc(size_t numElems
) {
86 if (MOZ_UNLIKELY(!CalculateAllocSize
<T
>(numElems
, &bytes
))) {
89 return static_cast<T
*>(alloc_
.allocate(bytes
));
92 T
* maybe_pod_calloc(size_t numElems
) {
93 T
* p
= maybe_pod_malloc
<T
>(numElems
);
95 memset(p
, 0, numElems
* sizeof(T
));
100 T
* maybe_pod_realloc(T
* p
, size_t oldSize
, size_t newSize
) {
101 T
* n
= pod_malloc
<T
>(newSize
);
102 if (MOZ_UNLIKELY(!n
)) {
105 MOZ_ASSERT(!(oldSize
& mozilla::tl::MulOverflowMask
<sizeof(T
)>::value
));
106 memcpy(n
, p
, std::min(oldSize
* sizeof(T
), newSize
* sizeof(T
)));
109 template <typename T
>
110 T
* pod_malloc(size_t numElems
) {
111 return maybe_pod_malloc
<T
>(numElems
);
113 template <typename T
>
114 T
* pod_calloc(size_t numElems
) {
115 return maybe_pod_calloc
<T
>(numElems
);
117 template <typename T
>
118 T
* pod_realloc(T
* ptr
, size_t oldSize
, size_t newSize
) {
119 return maybe_pod_realloc
<T
>(ptr
, oldSize
, newSize
);
121 template <typename T
>
122 void free_(T
* p
, size_t numElems
= 0) {}
123 void reportAllocOverflow() const {}
124 [[nodiscard
]] bool checkSimulatedOOM() const {
125 return !js::oom::ShouldFailWithOOM();
130 inline void* operator new(size_t nbytes
,
131 TempAllocator::Fallible view
) noexcept(true) {
132 return view
.alloc
.allocate(nbytes
);
134 inline void* operator new(size_t nbytes
, TempAllocator
& alloc
) {
135 return alloc
.allocateInfallible(nbytes
);
138 inline void* operator new(size_t nbytes
, T
* pos
) {
139 static_assert(std::is_convertible_v
<T
*, TempObject
*>,
140 "Placement new argument type must inherit from TempObject");
144 inline void* operator new(size_t nbytes
, mozilla::NotNullTag
, T
* pos
) {
145 static_assert(std::is_convertible_v
<T
*, TempObject
*>,
146 "Placement new argument type must inherit from TempObject");
152 template <typename T
>
153 class TempObjectPool
{
154 TempAllocator
* alloc_
;
155 InlineForwardList
<T
> freed_
;
158 TempObjectPool() : alloc_(nullptr) {}
159 void setAllocator(TempAllocator
& alloc
) {
160 MOZ_ASSERT(freed_
.empty());
163 template <typename
... Args
>
164 T
* allocate(Args
&&... args
) {
166 if (freed_
.empty()) {
167 return new (alloc_
->fallible()) T(std::forward
<Args
>(args
)...);
169 T
* res
= freed_
.popFront();
170 return new (res
) T(std::forward
<Args
>(args
)...);
172 void free(T
* obj
) { freed_
.pushFront(obj
); }
173 void clear() { freed_
.clear(); }
179 #endif /* jit_JitAllocPolicy_h */