|
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_IonAllocPolicy_h |
|
8 #define jit_IonAllocPolicy_h |
|
9 |
|
10 #include "mozilla/GuardObjects.h" |
|
11 #include "mozilla/TypeTraits.h" |
|
12 |
|
13 #include "jscntxt.h" |
|
14 |
|
15 #include "ds/LifoAlloc.h" |
|
16 #include "jit/InlineList.h" |
|
17 #include "jit/Ion.h" |
|
18 |
|
19 namespace js { |
|
20 namespace jit { |
|
21 |
|
22 class TempAllocator |
|
23 { |
|
24 LifoAllocScope lifoScope_; |
|
25 |
|
26 // Linked list of GCThings rooted by this allocator. |
|
27 CompilerRootNode *rootList_; |
|
28 |
|
29 public: |
|
30 TempAllocator(LifoAlloc *lifoAlloc) |
|
31 : lifoScope_(lifoAlloc), |
|
32 rootList_(nullptr) |
|
33 { } |
|
34 |
|
35 void *allocateOrCrash(size_t bytes) |
|
36 { |
|
37 void *p = lifoScope_.alloc().alloc(bytes); |
|
38 if (!p) |
|
39 js::CrashAtUnhandlableOOM("LifoAlloc::allocOrCrash"); |
|
40 return p; |
|
41 } |
|
42 |
|
43 void *allocate(size_t bytes) |
|
44 { |
|
45 void *p = lifoScope_.alloc().alloc(bytes); |
|
46 if (!ensureBallast()) |
|
47 return nullptr; |
|
48 return p; |
|
49 } |
|
50 |
|
51 template <size_t ElemSize> |
|
52 void *allocateArray(size_t n) |
|
53 { |
|
54 if (n & mozilla::tl::MulOverflowMask<ElemSize>::value) |
|
55 return nullptr; |
|
56 void *p = lifoScope_.alloc().alloc(n * ElemSize); |
|
57 if (!ensureBallast()) |
|
58 return nullptr; |
|
59 return p; |
|
60 } |
|
61 |
|
62 LifoAlloc *lifoAlloc() |
|
63 { |
|
64 return &lifoScope_.alloc(); |
|
65 } |
|
66 |
|
67 CompilerRootNode *&rootList() |
|
68 { |
|
69 return rootList_; |
|
70 } |
|
71 |
|
72 bool ensureBallast() { |
|
73 // Most infallible Ion allocations are small, so we use a ballast of |
|
74 // ~16K for now. |
|
75 return lifoScope_.alloc().ensureUnusedApproximate(16 * 1024); |
|
76 } |
|
77 }; |
|
78 |
|
79 // Stack allocated rooter for all roots associated with a TempAllocator |
|
80 class AutoTempAllocatorRooter : private AutoGCRooter |
|
81 { |
|
82 public: |
|
83 explicit AutoTempAllocatorRooter(JSContext *cx, TempAllocator *temp |
|
84 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
85 : AutoGCRooter(cx, IONALLOC), temp(temp) |
|
86 { |
|
87 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
88 } |
|
89 |
|
90 friend void AutoGCRooter::trace(JSTracer *trc); |
|
91 void trace(JSTracer *trc); |
|
92 |
|
93 private: |
|
94 TempAllocator *temp; |
|
95 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
|
96 }; |
|
97 |
|
98 class IonAllocPolicy |
|
99 { |
|
100 TempAllocator &alloc_; |
|
101 |
|
102 public: |
|
103 IonAllocPolicy(TempAllocator &alloc) |
|
104 : alloc_(alloc) |
|
105 {} |
|
106 void *malloc_(size_t bytes) { |
|
107 return alloc_.allocate(bytes); |
|
108 } |
|
109 void *calloc_(size_t bytes) { |
|
110 void *p = alloc_.allocate(bytes); |
|
111 if (p) |
|
112 memset(p, 0, bytes); |
|
113 return p; |
|
114 } |
|
115 void *realloc_(void *p, size_t oldBytes, size_t bytes) { |
|
116 void *n = malloc_(bytes); |
|
117 if (!n) |
|
118 return n; |
|
119 memcpy(n, p, Min(oldBytes, bytes)); |
|
120 return n; |
|
121 } |
|
122 void free_(void *p) { |
|
123 } |
|
124 void reportAllocOverflow() const { |
|
125 } |
|
126 }; |
|
127 |
|
128 // Deprecated. Don't use this. Will be removed after everything has been |
|
129 // converted to IonAllocPolicy. |
|
130 class OldIonAllocPolicy |
|
131 { |
|
132 public: |
|
133 OldIonAllocPolicy() |
|
134 {} |
|
135 void *malloc_(size_t bytes) { |
|
136 return GetIonContext()->temp->allocate(bytes); |
|
137 } |
|
138 void *calloc_(size_t bytes) { |
|
139 void *p = GetIonContext()->temp->allocate(bytes); |
|
140 if (p) |
|
141 memset(p, 0, bytes); |
|
142 return p; |
|
143 } |
|
144 void *realloc_(void *p, size_t oldBytes, size_t bytes) { |
|
145 void *n = malloc_(bytes); |
|
146 if (!n) |
|
147 return n; |
|
148 memcpy(n, p, Min(oldBytes, bytes)); |
|
149 return n; |
|
150 } |
|
151 void free_(void *p) { |
|
152 } |
|
153 void reportAllocOverflow() const { |
|
154 } |
|
155 }; |
|
156 |
|
157 class AutoIonContextAlloc |
|
158 { |
|
159 TempAllocator tempAlloc_; |
|
160 IonContext *icx_; |
|
161 TempAllocator *prevAlloc_; |
|
162 |
|
163 public: |
|
164 explicit AutoIonContextAlloc(JSContext *cx) |
|
165 : tempAlloc_(&cx->tempLifoAlloc()), |
|
166 icx_(GetIonContext()), |
|
167 prevAlloc_(icx_->temp) |
|
168 { |
|
169 icx_->temp = &tempAlloc_; |
|
170 } |
|
171 |
|
172 ~AutoIonContextAlloc() { |
|
173 JS_ASSERT(icx_->temp == &tempAlloc_); |
|
174 icx_->temp = prevAlloc_; |
|
175 } |
|
176 }; |
|
177 |
|
178 struct TempObject |
|
179 { |
|
180 inline void *operator new(size_t nbytes, TempAllocator &alloc) { |
|
181 return alloc.allocateOrCrash(nbytes); |
|
182 } |
|
183 template <class T> |
|
184 inline void *operator new(size_t nbytes, T *pos) { |
|
185 static_assert(mozilla::IsConvertible<T*, TempObject*>::value, |
|
186 "Placement new argument type must inherit from TempObject"); |
|
187 return pos; |
|
188 } |
|
189 }; |
|
190 |
|
191 template <typename T> |
|
192 class TempObjectPool |
|
193 { |
|
194 TempAllocator *alloc_; |
|
195 InlineForwardList<T> freed_; |
|
196 |
|
197 public: |
|
198 TempObjectPool() |
|
199 : alloc_(nullptr) |
|
200 {} |
|
201 void setAllocator(TempAllocator &alloc) { |
|
202 JS_ASSERT(freed_.empty()); |
|
203 alloc_ = &alloc; |
|
204 } |
|
205 T *allocate() { |
|
206 JS_ASSERT(alloc_); |
|
207 if (freed_.empty()) |
|
208 return new(*alloc_) T(); |
|
209 return freed_.popFront(); |
|
210 } |
|
211 void free(T *obj) { |
|
212 freed_.pushFront(obj); |
|
213 } |
|
214 void clear() { |
|
215 freed_.clear(); |
|
216 } |
|
217 }; |
|
218 |
|
219 } // namespace jit |
|
220 } // namespace js |
|
221 |
|
222 #endif /* jit_IonAllocPolicy_h */ |