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/. */
8 * JS allocation policies.
10 * The allocators here are for system memory with lifetimes which are not
11 * managed by the GC. See the comment at the top of vm/MallocProvider.h.
14 #ifndef js_AllocPolicy_h
15 #define js_AllocPolicy_h
17 #include "js/TypeDecls.h"
18 #include "js/Utility.h"
20 extern MOZ_COLD JS_PUBLIC_API
void JS_ReportOutOfMemory(JSContext
* cx
);
24 class FrontendContext
;
26 enum class AllocFunction
{ Malloc
, Calloc
, Realloc
};
28 /* Base class allocation policies providing allocation methods. */
29 class AllocPolicyBase
{
32 T
* maybe_pod_arena_malloc(arena_id_t arenaId
, size_t numElems
) {
33 return js_pod_arena_malloc
<T
>(arenaId
, numElems
);
36 T
* maybe_pod_arena_calloc(arena_id_t arenaId
, size_t numElems
) {
37 return js_pod_arena_calloc
<T
>(arenaId
, numElems
);
40 T
* maybe_pod_arena_realloc(arena_id_t arenaId
, T
* p
, size_t oldSize
,
42 return js_pod_arena_realloc
<T
>(arenaId
, p
, oldSize
, newSize
);
45 T
* pod_arena_malloc(arena_id_t arenaId
, size_t numElems
) {
46 return maybe_pod_arena_malloc
<T
>(arenaId
, numElems
);
49 T
* pod_arena_calloc(arena_id_t arenaId
, size_t numElems
) {
50 return maybe_pod_arena_calloc
<T
>(arenaId
, numElems
);
53 T
* pod_arena_realloc(arena_id_t arenaId
, T
* p
, size_t oldSize
,
55 return maybe_pod_arena_realloc
<T
>(arenaId
, p
, oldSize
, newSize
);
59 T
* maybe_pod_malloc(size_t numElems
) {
60 return maybe_pod_arena_malloc
<T
>(js::MallocArena
, numElems
);
63 T
* maybe_pod_calloc(size_t numElems
) {
64 return maybe_pod_arena_calloc
<T
>(js::MallocArena
, numElems
);
67 T
* maybe_pod_realloc(T
* p
, size_t oldSize
, size_t newSize
) {
68 return maybe_pod_arena_realloc
<T
>(js::MallocArena
, p
, oldSize
, newSize
);
71 T
* pod_malloc(size_t numElems
) {
72 return pod_arena_malloc
<T
>(js::MallocArena
, numElems
);
75 T
* pod_calloc(size_t numElems
) {
76 return pod_arena_calloc
<T
>(js::MallocArena
, numElems
);
79 T
* pod_realloc(T
* p
, size_t oldSize
, size_t newSize
) {
80 return pod_arena_realloc
<T
>(js::MallocArena
, p
, oldSize
, newSize
);
84 void free_(T
* p
, size_t numElems
= 0) {
89 /* Policy for using system memory functions and doing no error reporting. */
90 class SystemAllocPolicy
: public AllocPolicyBase
{
92 void reportAllocOverflow() const {}
93 bool checkSimulatedOOM() const { return !js::oom::ShouldFailWithOOM(); }
96 MOZ_COLD JS_PUBLIC_API
void ReportOutOfMemory(JSContext
* cx
);
97 MOZ_COLD JS_PUBLIC_API
void ReportOutOfMemory(FrontendContext
* fc
);
99 // An out of memory condition which is easily user generatable and should
100 // be specially handled to try and avoid a tab crash.
101 MOZ_COLD JS_PUBLIC_API
void ReportLargeOutOfMemory(JSContext
* cx
);
104 * Allocation policy that calls the system memory functions and reports errors
105 * to the context. Since the JSContext given on construction is stored for
106 * the lifetime of the container, this policy may only be used for containers
107 * whose lifetime is a shorter than the given JSContext.
109 * FIXME bug 647103 - rewrite this in terms of temporary allocation functions,
110 * not the system ones.
112 class JS_PUBLIC_API TempAllocPolicy
: public AllocPolicyBase
{
113 // Type tag for context_bits_
114 static constexpr uintptr_t JsContextTag
= 0x1;
116 // Either a JSContext* (if JsContextTag is set), or FrontendContext*
117 uintptr_t const context_bits_
;
119 MOZ_ALWAYS_INLINE
bool hasJSContext() const {
120 return (context_bits_
& JsContextTag
) == JsContextTag
;
123 MOZ_ALWAYS_INLINE JSContext
* cx() const {
124 MOZ_ASSERT(hasJSContext());
125 return reinterpret_cast<JSContext
*>(context_bits_
^ JsContextTag
);
128 MOZ_ALWAYS_INLINE FrontendContext
* fc() const {
129 MOZ_ASSERT(!hasJSContext());
130 return reinterpret_cast<FrontendContext
*>(context_bits_
);
134 * Non-inline helper to call JSRuntime::onOutOfMemory with minimal
137 void* onOutOfMemory(arena_id_t arenaId
, AllocFunction allocFunc
,
138 size_t nbytes
, void* reallocPtr
= nullptr);
140 template <typename T
>
141 T
* onOutOfMemoryTyped(arena_id_t arenaId
, AllocFunction allocFunc
,
142 size_t numElems
, void* reallocPtr
= nullptr) {
144 if (MOZ_UNLIKELY(!CalculateAllocSize
<T
>(numElems
, &bytes
))) {
147 return static_cast<T
*>(
148 onOutOfMemory(arenaId
, allocFunc
, bytes
, reallocPtr
));
152 MOZ_IMPLICIT
TempAllocPolicy(JSContext
* cx
)
153 : context_bits_(uintptr_t(cx
) | JsContextTag
) {
154 MOZ_ASSERT((uintptr_t(cx
) & JsContextTag
) == 0);
156 MOZ_IMPLICIT
TempAllocPolicy(FrontendContext
* fc
)
157 : context_bits_(uintptr_t(fc
)) {
158 MOZ_ASSERT((uintptr_t(fc
) & JsContextTag
) == 0);
161 template <typename T
>
162 T
* pod_arena_malloc(arena_id_t arenaId
, size_t numElems
) {
163 T
* p
= this->maybe_pod_arena_malloc
<T
>(arenaId
, numElems
);
164 if (MOZ_UNLIKELY(!p
)) {
165 p
= onOutOfMemoryTyped
<T
>(arenaId
, AllocFunction::Malloc
, numElems
);
170 template <typename T
>
171 T
* pod_arena_calloc(arena_id_t arenaId
, size_t numElems
) {
172 T
* p
= this->maybe_pod_arena_calloc
<T
>(arenaId
, numElems
);
173 if (MOZ_UNLIKELY(!p
)) {
174 p
= onOutOfMemoryTyped
<T
>(arenaId
, AllocFunction::Calloc
, numElems
);
179 template <typename T
>
180 T
* pod_arena_realloc(arena_id_t arenaId
, T
* prior
, size_t oldSize
,
182 T
* p2
= this->maybe_pod_arena_realloc
<T
>(arenaId
, prior
, oldSize
, newSize
);
183 if (MOZ_UNLIKELY(!p2
)) {
184 p2
= onOutOfMemoryTyped
<T
>(arenaId
, AllocFunction::Realloc
, newSize
,
190 template <typename T
>
191 T
* pod_malloc(size_t numElems
) {
192 return pod_arena_malloc
<T
>(js::MallocArena
, numElems
);
195 template <typename T
>
196 T
* pod_calloc(size_t numElems
) {
197 return pod_arena_calloc
<T
>(js::MallocArena
, numElems
);
200 template <typename T
>
201 T
* pod_realloc(T
* prior
, size_t oldSize
, size_t newSize
) {
202 return pod_arena_realloc
<T
>(js::MallocArena
, prior
, oldSize
, newSize
);
205 template <typename T
>
206 void free_(T
* p
, size_t numElems
= 0) {
210 void reportAllocOverflow() const;
212 bool checkSimulatedOOM() const {
213 if (js::oom::ShouldFailWithOOM()) {
214 if (hasJSContext()) {
215 ReportOutOfMemory(cx());
217 ReportOutOfMemory(fc());
227 * A replacement for MallocAllocPolicy that allocates in the JS heap and adds no
230 * This is currently used for allocating source buffers for parsing. Since these
231 * are temporary and will not be freed by GC, the memory is not tracked by the
234 class MallocAllocPolicy
: public AllocPolicyBase
{
236 void reportAllocOverflow() const {}
238 [[nodiscard
]] bool checkSimulatedOOM() const { return true; }
243 #endif /* js_AllocPolicy_h */