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 * 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
53 template <class Client
>
54 struct MallocProvider
{
56 T
* maybe_pod_arena_malloc(arena_id_t arena
, size_t numElems
) {
57 T
* p
= js_pod_arena_malloc
<T
>(arena
, numElems
);
59 client()->updateMallocCounter(numElems
* sizeof(T
));
65 T
* maybe_pod_arena_calloc(arena_id_t arena
, size_t numElems
) {
66 T
* p
= js_pod_arena_calloc
<T
>(arena
, numElems
);
68 client()->updateMallocCounter(numElems
* sizeof(T
));
74 T
* maybe_pod_arena_realloc(arena_id_t arena
, T
* prior
, size_t oldSize
,
76 T
* p
= js_pod_arena_realloc
<T
>(arena
, prior
, oldSize
, newSize
);
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
));
88 T
* maybe_pod_malloc(size_t numElems
) {
89 return maybe_pod_arena_malloc
<T
>(js::MallocArena
, numElems
);
93 T
* maybe_pod_calloc(size_t numElems
) {
94 return maybe_pod_arena_calloc
<T
>(js::MallocArena
, numElems
);
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
);
104 return pod_malloc
<T
>(1);
108 T
* pod_arena_malloc(arena_id_t arena
, size_t numElems
) {
109 T
* p
= maybe_pod_arena_malloc
<T
>(arena
, numElems
);
114 if (MOZ_UNLIKELY(!CalculateAllocSize
<T
>(numElems
, &bytes
))) {
115 client()->reportAllocationOverflow();
118 p
= (T
*)client()->onOutOfMemory(AllocFunction::Malloc
, arena
, bytes
);
120 client()->updateMallocCounter(bytes
);
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
) {
133 if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra
<T
, U
>(numExtra
, &bytes
)))) {
134 client()->reportAllocationOverflow();
137 T
* p
= static_cast<T
*>(js_malloc(bytes
));
139 client()->updateMallocCounter(bytes
);
142 p
= (T
*)client()->onOutOfMemory(AllocFunction::Malloc
, js::MallocArena
,
145 client()->updateMallocCounter(bytes
);
151 UniquePtr
<T
[], JS::FreePolicy
> make_pod_arena_array(arena_id_t arena
,
153 return UniquePtr
<T
[], JS::FreePolicy
>(pod_arena_malloc
<T
>(arena
, numElems
));
157 UniquePtr
<T
[], JS::FreePolicy
> make_pod_array(size_t numElems
) {
158 return make_pod_arena_array
<T
>(js::MallocArena
, numElems
);
162 T
* pod_arena_calloc(arena_id_t arena
, size_t numElems
= 1) {
163 T
* p
= maybe_pod_arena_calloc
<T
>(arena
, numElems
);
168 if (MOZ_UNLIKELY(!CalculateAllocSize
<T
>(numElems
, &bytes
))) {
169 client()->reportAllocationOverflow();
172 p
= (T
*)client()->onOutOfMemory(AllocFunction::Calloc
, arena
, bytes
);
174 client()->updateMallocCounter(bytes
);
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
) {
187 if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra
<T
, U
>(numExtra
, &bytes
)))) {
188 client()->reportAllocationOverflow();
191 T
* p
= static_cast<T
*>(js_calloc(bytes
));
193 client()->updateMallocCounter(bytes
);
196 p
= (T
*)client()->onOutOfMemory(AllocFunction::Calloc
, js::MallocArena
,
199 client()->updateMallocCounter(bytes
);
205 UniquePtr
<T
[], JS::FreePolicy
> make_zeroed_pod_array(size_t numElems
) {
206 return UniquePtr
<T
[], JS::FreePolicy
>(pod_calloc
<T
>(numElems
));
210 T
* pod_arena_realloc(arena_id_t arena
, T
* prior
, size_t oldSize
,
212 T
* p
= maybe_pod_arena_realloc(arena
, prior
, oldSize
, newSize
);
217 if (MOZ_UNLIKELY(!CalculateAllocSize
<T
>(newSize
, &bytes
))) {
218 client()->reportAllocationOverflow();
221 p
= (T
*)client()->onOutOfMemory(AllocFunction::Realloc
, arena
, bytes
,
223 if (p
&& newSize
> oldSize
) {
224 client()->updateMallocCounter((newSize
- oldSize
) * sizeof(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(
237 [this](arena_id_t arena
, size_t size
) {
238 return pod_malloc
<uint8_t>(size
, arena
);
242 JS_DECLARE_MAKE_METHODS(make_unique
, new_
, MOZ_ALWAYS_INLINE
)
243 JS_DECLARE_MAKE_METHODS(arena_make_unique
, arena_new_
, MOZ_ALWAYS_INLINE
)
246 Client
* client() { return static_cast<Client
*>(this); }
248 // The Default implementation is a no-op which can be overridden by the
250 void updateMallocCounter(size_t nbytes
) {}
255 #endif /* vm_MallocProvider_h */