Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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/. */
6 :
7 : #ifndef jit_JitAllocPolicy_h
8 : #define jit_JitAllocPolicy_h
9 :
10 : #include "mozilla/Attributes.h"
11 : #include "mozilla/GuardObjects.h"
12 : #include "mozilla/OperatorNewExtensions.h"
13 : #include "mozilla/TypeTraits.h"
14 :
15 : #include "jscntxt.h"
16 :
17 : #include "ds/LifoAlloc.h"
18 : #include "jit/InlineList.h"
19 : #include "jit/Ion.h"
20 :
21 : namespace js {
22 : namespace jit {
23 :
24 4007 : class TempAllocator
25 : {
26 : LifoAllocScope lifoScope_;
27 :
28 : public:
29 : // Most infallible JIT allocations are small, so we use a ballast of 16
30 : // KiB. And with a ballast of 16 KiB, a chunk size of 32 KiB works well,
31 : // because TempAllocators with a peak allocation size of less than 16 KiB
32 : // (which is most of them) only have to allocate a single chunk.
33 : static const size_t BallastSize; // 16 KiB
34 : static const size_t PreferredLifoChunkSize; // 32 KiB
35 :
36 4660 : explicit TempAllocator(LifoAlloc* lifoAlloc)
37 4660 : : lifoScope_(lifoAlloc)
38 : {
39 4660 : lifoAlloc->setAsInfallibleByDefault();
40 4660 : }
41 :
42 69300 : void* allocateInfallible(size_t bytes)
43 : {
44 69300 : return lifoScope_.alloc().allocInfallible(bytes);
45 : }
46 :
47 46691 : MOZ_MUST_USE void* allocate(size_t bytes)
48 : {
49 93382 : LifoAlloc::AutoFallibleScope fallibleAllocator(lifoAlloc());
50 46691 : void* p = lifoScope_.alloc().alloc(bytes);
51 46691 : if (!ensureBallast())
52 0 : return nullptr;
53 46691 : return p;
54 : }
55 :
56 : template <typename T>
57 175 : MOZ_MUST_USE T* allocateArray(size_t n)
58 : {
59 350 : LifoAlloc::AutoFallibleScope fallibleAllocator(lifoAlloc());
60 : size_t bytes;
61 175 : if (MOZ_UNLIKELY(!CalculateAllocSize<T>(n, &bytes)))
62 0 : return nullptr;
63 175 : T* p = static_cast<T*>(lifoScope_.alloc().alloc(bytes));
64 175 : if (MOZ_UNLIKELY(!ensureBallast()))
65 0 : return nullptr;
66 175 : return p;
67 : }
68 :
69 : // View this allocator as a fallible allocator.
70 : struct Fallible { TempAllocator& alloc; };
71 22206 : Fallible fallible() { return { *this }; }
72 :
73 60673 : LifoAlloc* lifoAlloc() {
74 60673 : return &lifoScope_.alloc();
75 : }
76 :
77 114959 : MOZ_MUST_USE bool ensureBallast() {
78 114959 : JS_OOM_POSSIBLY_FAIL_BOOL();
79 114958 : return lifoScope_.alloc().ensureUnusedApproximate(BallastSize);
80 : }
81 : };
82 :
83 : class JitAllocPolicy
84 : {
85 : TempAllocator& alloc_;
86 :
87 : public:
88 58651 : MOZ_IMPLICIT JitAllocPolicy(TempAllocator& alloc)
89 58651 : : alloc_(alloc)
90 58651 : {}
91 : template <typename T>
92 7912 : T* maybe_pod_malloc(size_t numElems) {
93 : size_t bytes;
94 7912 : if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes)))
95 0 : return nullptr;
96 7912 : return static_cast<T*>(alloc_.allocate(bytes));
97 : }
98 : template <typename T>
99 42 : T* maybe_pod_calloc(size_t numElems) {
100 42 : T* p = maybe_pod_malloc<T>(numElems);
101 42 : if (MOZ_LIKELY(p))
102 42 : memset(p, 0, numElems * sizeof(T));
103 42 : return p;
104 : }
105 : template <typename T>
106 1753 : T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
107 1753 : T* n = pod_malloc<T>(newSize);
108 1753 : if (MOZ_UNLIKELY(!n))
109 0 : return n;
110 1753 : MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
111 1753 : memcpy(n, p, Min(oldSize * sizeof(T), newSize * sizeof(T)));
112 1753 : return n;
113 : }
114 : template <typename T>
115 7870 : T* pod_malloc(size_t numElems) {
116 7870 : return maybe_pod_malloc<T>(numElems);
117 : }
118 : template <typename T>
119 39 : T* pod_calloc(size_t numElems) {
120 39 : return maybe_pod_calloc<T>(numElems);
121 : }
122 : template <typename T>
123 1753 : T* pod_realloc(T* ptr, size_t oldSize, size_t newSize) {
124 1753 : return maybe_pod_realloc<T>(ptr, oldSize, newSize);
125 : }
126 3495 : void free_(void* p) {
127 3495 : }
128 0 : void reportAllocOverflow() const {
129 0 : }
130 7747 : MOZ_MUST_USE bool checkSimulatedOOM() const {
131 7747 : return !js::oom::ShouldFailWithOOM();
132 : }
133 : };
134 :
135 : class AutoJitContextAlloc
136 : {
137 : TempAllocator tempAlloc_;
138 : JitContext* jcx_;
139 : TempAllocator* prevAlloc_;
140 :
141 : public:
142 3871 : explicit AutoJitContextAlloc(JSContext* cx)
143 3871 : : tempAlloc_(&cx->tempLifoAlloc()),
144 3871 : jcx_(GetJitContext()),
145 7742 : prevAlloc_(jcx_->temp)
146 : {
147 3871 : jcx_->temp = &tempAlloc_;
148 3871 : }
149 :
150 7742 : ~AutoJitContextAlloc() {
151 3871 : MOZ_ASSERT(jcx_->temp == &tempAlloc_);
152 3871 : jcx_->temp = prevAlloc_;
153 3871 : }
154 : };
155 :
156 170744 : struct TempObject
157 : {
158 22206 : inline void* operator new(size_t nbytes, TempAllocator::Fallible view) throw() {
159 22206 : return view.alloc.allocate(nbytes);
160 : }
161 69300 : inline void* operator new(size_t nbytes, TempAllocator& alloc) {
162 69300 : return alloc.allocateInfallible(nbytes);
163 : }
164 : template <class T>
165 19133 : inline void* operator new(size_t nbytes, T* pos) {
166 : static_assert(mozilla::IsConvertible<T*, TempObject*>::value,
167 : "Placement new argument type must inherit from TempObject");
168 19133 : return pos;
169 : }
170 : template <class T>
171 25725 : inline void* operator new(size_t nbytes, mozilla::NotNullTag, T* pos) {
172 : static_assert(mozilla::IsConvertible<T*, TempObject*>::value,
173 : "Placement new argument type must inherit from TempObject");
174 25725 : MOZ_ASSERT(pos);
175 25725 : return pos;
176 : }
177 : };
178 :
179 : template <typename T>
180 : class TempObjectPool
181 : {
182 : TempAllocator* alloc_;
183 : InlineForwardList<T> freed_;
184 :
185 : public:
186 4503 : TempObjectPool()
187 4503 : : alloc_(nullptr)
188 4503 : {}
189 4503 : void setAllocator(TempAllocator& alloc) {
190 4503 : MOZ_ASSERT(freed_.empty());
191 4503 : alloc_ = &alloc;
192 4503 : }
193 19133 : T* allocate() {
194 19133 : MOZ_ASSERT(alloc_);
195 19133 : if (freed_.empty())
196 4915 : return new(alloc_->fallible()) T();
197 14218 : return freed_.popFront();
198 : }
199 19134 : void free(T* obj) {
200 19134 : freed_.pushFront(obj);
201 19134 : }
202 : void clear() {
203 : freed_.clear();
204 : }
205 : };
206 :
207 : } // namespace jit
208 : } // namespace js
209 :
210 : #endif /* jit_JitAllocPolicy_h */
|