Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / js / src / vm / MallocProvider.h
blobb9ce9b0a4fddaa2456d60f0d594f9fbe4845905d
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 /*
8 * Hierarchy of SpiderMonkey system memory allocators:
10 * - System {m,c,re}alloc/new/free: Overridden by jemalloc in most
11 * environments. Do not use these functions directly.
13 * - js_{m,c,re}alloc/new/free: Wraps the system allocators and adds a
14 * failure injection framework for use by the fuzzers as well as templated,
15 * typesafe variants. See js/public/Utility.h.
17 * - AllocPolicy: An interface for the js allocators, for use with templates.
18 * These allocators are for system memory whose lifetime is not associated
19 * with a GC thing. See js/public/AllocPolicy.h.
21 * - SystemAllocPolicy: No extra functionality over bare allocators.
23 * - TempAllocPolicy: Adds automatic error reporting to the provided
24 * JSContext when allocations fail.
26 * - ZoneAllocPolicy: Forwards to the Zone MallocProvider.
28 * - MallocProvider. A mixin base class that handles automatically updating
29 * the GC's state in response to allocations that are tied to a GC lifetime
30 * or are for a particular GC purpose. These allocators must only be used
31 * for memory that will be freed when a GC thing is swept.
33 * - gc::Zone: Automatically triggers zone GC.
34 * - JSRuntime: Automatically triggers full GC.
35 * - JSContext: Dispatches directly to the runtime.
38 #ifndef vm_MallocProvider_h
39 #define vm_MallocProvider_h
41 #include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE
42 #include "mozilla/Likely.h" // MOZ_LIKELY, MOZ_UNLIKELY
44 #include <stddef.h> // size_t
45 #include <stdint.h> // uint8_t
47 #include "js/AllocPolicy.h" // AllocFunction
48 #include "js/UniquePtr.h" // UniquePtr
49 #include "js/Utility.h" // js_malloc, MallocArena, CalculateAllocSize, CalculateAllocSizeWithExtra, JS::FreePolicy
51 namespace js {
53 template <class Client>
54 struct MallocProvider {
55 template <class T>
56 T* maybe_pod_arena_malloc(arena_id_t arena, size_t numElems) {
57 T* p = js_pod_arena_malloc<T>(arena, numElems);
58 if (MOZ_LIKELY(p)) {
59 client()->updateMallocCounter(numElems * sizeof(T));
61 return p;
64 template <class T>
65 T* maybe_pod_arena_calloc(arena_id_t arena, size_t numElems) {
66 T* p = js_pod_arena_calloc<T>(arena, numElems);
67 if (MOZ_LIKELY(p)) {
68 client()->updateMallocCounter(numElems * sizeof(T));
70 return p;
73 template <class T>
74 T* maybe_pod_arena_realloc(arena_id_t arena, T* prior, size_t oldSize,
75 size_t newSize) {
76 T* p = js_pod_arena_realloc<T>(arena, prior, oldSize, newSize);
77 if (MOZ_LIKELY(p)) {
78 // For compatibility we do not account for realloc that decreases
79 // previously allocated memory.
80 if (newSize > oldSize) {
81 client()->updateMallocCounter((newSize - oldSize) * sizeof(T));
84 return p;
87 template <class T>
88 T* maybe_pod_malloc(size_t numElems) {
89 return maybe_pod_arena_malloc<T>(js::MallocArena, numElems);
92 template <class T>
93 T* maybe_pod_calloc(size_t numElems) {
94 return maybe_pod_arena_calloc<T>(js::MallocArena, numElems);
97 template <class T>
98 T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) {
99 return maybe_pod_arena_realloc<T>(js::MallocArena, prior, oldSize, newSize);
102 template <class T>
103 T* pod_malloc() {
104 return pod_malloc<T>(1);
107 template <class T>
108 T* pod_arena_malloc(arena_id_t arena, size_t numElems) {
109 T* p = maybe_pod_arena_malloc<T>(arena, numElems);
110 if (MOZ_LIKELY(p)) {
111 return p;
113 size_t bytes;
114 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
115 client()->reportAllocationOverflow();
116 return nullptr;
118 p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, arena, bytes);
119 if (p) {
120 client()->updateMallocCounter(bytes);
122 return p;
125 template <class T>
126 T* pod_malloc(size_t numElems) {
127 return pod_arena_malloc<T>(js::MallocArena, numElems);
130 template <class T, class U>
131 T* pod_malloc_with_extra(size_t numExtra) {
132 size_t bytes;
133 if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) {
134 client()->reportAllocationOverflow();
135 return nullptr;
137 T* p = static_cast<T*>(js_malloc(bytes));
138 if (MOZ_LIKELY(p)) {
139 client()->updateMallocCounter(bytes);
140 return p;
142 p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, js::MallocArena,
143 bytes);
144 if (p) {
145 client()->updateMallocCounter(bytes);
147 return p;
150 template <class T>
151 UniquePtr<T[], JS::FreePolicy> make_pod_arena_array(arena_id_t arena,
152 size_t numElems) {
153 return UniquePtr<T[], JS::FreePolicy>(pod_arena_malloc<T>(arena, numElems));
156 template <class T>
157 UniquePtr<T[], JS::FreePolicy> make_pod_array(size_t numElems) {
158 return make_pod_arena_array<T>(js::MallocArena, numElems);
161 template <class T>
162 T* pod_arena_calloc(arena_id_t arena, size_t numElems = 1) {
163 T* p = maybe_pod_arena_calloc<T>(arena, numElems);
164 if (MOZ_LIKELY(p)) {
165 return p;
167 size_t bytes;
168 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
169 client()->reportAllocationOverflow();
170 return nullptr;
172 p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, arena, bytes);
173 if (p) {
174 client()->updateMallocCounter(bytes);
176 return p;
179 template <class T>
180 T* pod_calloc(size_t numElems = 1) {
181 return pod_arena_calloc<T>(js::MallocArena, numElems);
184 template <class T, class U>
185 T* pod_calloc_with_extra(size_t numExtra) {
186 size_t bytes;
187 if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) {
188 client()->reportAllocationOverflow();
189 return nullptr;
191 T* p = static_cast<T*>(js_calloc(bytes));
192 if (p) {
193 client()->updateMallocCounter(bytes);
194 return p;
196 p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, js::MallocArena,
197 bytes);
198 if (p) {
199 client()->updateMallocCounter(bytes);
201 return p;
204 template <class T>
205 UniquePtr<T[], JS::FreePolicy> make_zeroed_pod_array(size_t numElems) {
206 return UniquePtr<T[], JS::FreePolicy>(pod_calloc<T>(numElems));
209 template <class T>
210 T* pod_arena_realloc(arena_id_t arena, T* prior, size_t oldSize,
211 size_t newSize) {
212 T* p = maybe_pod_arena_realloc(arena, prior, oldSize, newSize);
213 if (MOZ_LIKELY(p)) {
214 return p;
216 size_t bytes;
217 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(newSize, &bytes))) {
218 client()->reportAllocationOverflow();
219 return nullptr;
221 p = (T*)client()->onOutOfMemory(AllocFunction::Realloc, arena, bytes,
222 prior);
223 if (p && newSize > oldSize) {
224 client()->updateMallocCounter((newSize - oldSize) * sizeof(T));
226 return p;
229 template <class T>
230 T* pod_realloc(T* prior, size_t oldSize, size_t newSize) {
231 return pod_arena_realloc<T>(js::MallocArena, prior, oldSize, newSize);
234 JS_DECLARE_NEW_METHODS(new_, pod_malloc<uint8_t>, MOZ_ALWAYS_INLINE)
235 JS_DECLARE_NEW_ARENA_METHODS(
236 arena_new_,
237 [this](arena_id_t arena, size_t size) {
238 return pod_malloc<uint8_t>(size, arena);
240 MOZ_ALWAYS_INLINE)
242 JS_DECLARE_MAKE_METHODS(make_unique, new_, MOZ_ALWAYS_INLINE)
243 JS_DECLARE_MAKE_METHODS(arena_make_unique, arena_new_, MOZ_ALWAYS_INLINE)
245 private:
246 Client* client() { return static_cast<Client*>(this); }
248 // The Default implementation is a no-op which can be overridden by the
249 // client.
250 void updateMallocCounter(size_t nbytes) {}
253 } /* namespace js */
255 #endif /* vm_MallocProvider_h */