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 : /*
8 : * Hierarchy of SpiderMonkey system memory allocators:
9 : *
10 : * - System {m,c,re}alloc/new/free: Overridden by jemalloc in most
11 : * environments. Do not use these functions directly.
12 : *
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.
16 : *
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/src/jsalloc.h.
20 : *
21 : * - SystemAllocPolicy: No extra functionality over bare allocators.
22 : *
23 : * - TempAllocPolicy: Adds automatic error reporting to the provided
24 : * JSContext when allocations fail.
25 : *
26 : * - RuntimeAllocPolicy: Forwards to the JSRuntime MallocProvider.
27 : *
28 : * - ZoneAllocPolicy: Forwards to the Zone MallocProvider.
29 : *
30 : * - MallocProvider. A mixin base class that handles automatically updating
31 : * the GC's state in response to allocations that are tied to a GC lifetime
32 : * or are for a particular GC purpose. These allocators must only be used
33 : * for memory that will be freed when a GC thing is swept.
34 : *
35 : * - gc::Zone: Automatically triggers zone GC.
36 : * - JSRuntime: Automatically triggers full GC.
37 : * - JSContext: Dispatches directly to the runtime.
38 : */
39 :
40 : #ifndef vm_MallocProvider_h
41 : #define vm_MallocProvider_h
42 :
43 : #include "mozilla/Attributes.h"
44 : #include "mozilla/Likely.h"
45 :
46 : #include "js/UniquePtr.h"
47 : #include "js/Utility.h"
48 :
49 : namespace js {
50 :
51 : template<class Client>
52 75 : struct MallocProvider
53 : {
54 : template <class T>
55 94955 : T* maybe_pod_malloc(size_t numElems) {
56 94955 : T* p = js_pod_malloc<T>(numElems);
57 94955 : if (MOZ_LIKELY(p))
58 94955 : client()->updateMallocCounter(numElems * sizeof(T));
59 94955 : return p;
60 : }
61 :
62 : template <class T>
63 52619 : T* maybe_pod_calloc(size_t numElems) {
64 52619 : T* p = js_pod_calloc<T>(numElems);
65 52620 : if (MOZ_LIKELY(p))
66 52620 : client()->updateMallocCounter(numElems * sizeof(T));
67 52620 : return p;
68 : }
69 :
70 : template <class T>
71 5835 : T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) {
72 5835 : T* p = js_pod_realloc(prior, oldSize, newSize);
73 5835 : if (MOZ_LIKELY(p)) {
74 : // For compatibility we do not account for realloc that decreases
75 : // previously allocated memory.
76 5835 : if (newSize > oldSize)
77 5801 : client()->updateMallocCounter((newSize - oldSize) * sizeof(T));
78 : }
79 5835 : return p;
80 : }
81 :
82 : template <class T>
83 : T* pod_malloc() {
84 : return pod_malloc<T>(1);
85 : }
86 :
87 : template <class T>
88 94956 : T* pod_malloc(size_t numElems) {
89 94956 : T* p = maybe_pod_malloc<T>(numElems);
90 94956 : if (MOZ_LIKELY(p))
91 94956 : return p;
92 : size_t bytes;
93 0 : if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
94 0 : client()->reportAllocationOverflow();
95 0 : return nullptr;
96 : }
97 0 : p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, bytes);
98 0 : if (p)
99 0 : client()->updateMallocCounter(bytes);
100 0 : return p;
101 : }
102 :
103 : template <class T, class U>
104 723 : T* pod_malloc_with_extra(size_t numExtra) {
105 : size_t bytes;
106 723 : if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) {
107 0 : client()->reportAllocationOverflow();
108 0 : return nullptr;
109 : }
110 723 : T* p = static_cast<T*>(js_malloc(bytes));
111 723 : if (MOZ_LIKELY(p)) {
112 723 : client()->updateMallocCounter(bytes);
113 723 : return p;
114 : }
115 0 : p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, bytes);
116 0 : if (p)
117 0 : client()->updateMallocCounter(bytes);
118 0 : return p;
119 : }
120 :
121 : template <class T>
122 : UniquePtr<T[], JS::FreePolicy>
123 1791 : make_pod_array(size_t numElems) {
124 1791 : return UniquePtr<T[], JS::FreePolicy>(pod_malloc<T>(numElems));
125 : }
126 :
127 : template <class T>
128 : T* pod_calloc() {
129 : return pod_calloc<T>(1);
130 : }
131 :
132 : template <class T>
133 52548 : T* pod_calloc(size_t numElems) {
134 52548 : T* p = maybe_pod_calloc<T>(numElems);
135 52549 : if (MOZ_LIKELY(p))
136 52549 : return p;
137 : size_t bytes;
138 0 : if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
139 0 : client()->reportAllocationOverflow();
140 0 : return nullptr;
141 : }
142 0 : p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, bytes);
143 0 : if (p)
144 0 : client()->updateMallocCounter(bytes);
145 0 : return p;
146 : }
147 :
148 : template <class T, class U>
149 : T* pod_calloc_with_extra(size_t numExtra) {
150 : size_t bytes;
151 : if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) {
152 : client()->reportAllocationOverflow();
153 : return nullptr;
154 : }
155 : T* p = static_cast<T*>(js_calloc(bytes));
156 : if (p) {
157 : client()->updateMallocCounter(bytes);
158 : return p;
159 : }
160 : p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, bytes);
161 : if (p)
162 : client()->updateMallocCounter(bytes);
163 : return p;
164 : }
165 :
166 : template <class T>
167 : UniquePtr<T[], JS::FreePolicy>
168 : make_zeroed_pod_array(size_t numElems)
169 : {
170 : return UniquePtr<T[], JS::FreePolicy>(pod_calloc<T>(numElems));
171 : }
172 :
173 : template <class T>
174 5835 : T* pod_realloc(T* prior, size_t oldSize, size_t newSize) {
175 5835 : T* p = maybe_pod_realloc(prior, oldSize, newSize);
176 5835 : if (MOZ_LIKELY(p))
177 5835 : return p;
178 : size_t bytes;
179 0 : if (MOZ_UNLIKELY(!CalculateAllocSize<T>(newSize, &bytes))) {
180 0 : client()->reportAllocationOverflow();
181 0 : return nullptr;
182 : }
183 0 : p = (T*)client()->onOutOfMemory(AllocFunction::Realloc, bytes, prior);
184 0 : if (p && newSize > oldSize)
185 0 : client()->updateMallocCounter((newSize - oldSize) * sizeof(T));
186 0 : return p;
187 : }
188 :
189 12126 : JS_DECLARE_NEW_METHODS(new_, pod_malloc<uint8_t>, MOZ_ALWAYS_INLINE)
190 444 : JS_DECLARE_MAKE_METHODS(make_unique, new_, MOZ_ALWAYS_INLINE)
191 :
192 : private:
193 154227 : Client* client() { return static_cast<Client*>(this); }
194 : };
195 :
196 : } /* namespace js */
197 :
198 : #endif /* vm_MallocProvider_h */
|