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/. */ 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/public/AllocPolicy.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 * - ZoneAllocPolicy: Forwards to the Zone MallocProvider. 27 * 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. 32 * 33 * - gc::Zone: Automatically triggers zone GC. 34 * - JSRuntime: Automatically triggers full GC. 35 * - JSContext: Dispatches directly to the runtime. 36 */ 37 38 #ifndef vm_MallocProvider_h 39 #define vm_MallocProvider_h 40 41 #include "mozilla/Attributes.h" 42 #include "mozilla/Likely.h" 43 44 #include "js/UniquePtr.h" 45 #include "js/Utility.h" 46 47 namespace js { 48 49 template <class Client> 50 struct MallocProvider { 51 template <class T> maybe_pod_arena_mallocMallocProvider52 T* maybe_pod_arena_malloc(arena_id_t arena, size_t numElems) { 53 T* p = js_pod_arena_malloc<T>(arena, numElems); 54 if (MOZ_LIKELY(p)) { 55 client()->updateMallocCounter(numElems * sizeof(T)); 56 } 57 return p; 58 } 59 60 template <class T> maybe_pod_arena_callocMallocProvider61 T* maybe_pod_arena_calloc(arena_id_t arena, size_t numElems) { 62 T* p = js_pod_arena_calloc<T>(arena, numElems); 63 if (MOZ_LIKELY(p)) { 64 client()->updateMallocCounter(numElems * sizeof(T)); 65 } 66 return p; 67 } 68 69 template <class T> maybe_pod_arena_reallocMallocProvider70 T* maybe_pod_arena_realloc(arena_id_t arena, T* prior, size_t oldSize, 71 size_t newSize) { 72 T* p = js_pod_arena_realloc<T>(arena, prior, oldSize, newSize); 73 if (MOZ_LIKELY(p)) { 74 // For compatibility we do not account for realloc that decreases 75 // previously allocated memory. 76 if (newSize > oldSize) { 77 client()->updateMallocCounter((newSize - oldSize) * sizeof(T)); 78 } 79 } 80 return p; 81 } 82 83 template <class T> maybe_pod_mallocMallocProvider84 T* maybe_pod_malloc(size_t numElems) { 85 return maybe_pod_arena_malloc<T>(js::MallocArena, numElems); 86 } 87 88 template <class T> maybe_pod_callocMallocProvider89 T* maybe_pod_calloc(size_t numElems) { 90 return maybe_pod_arena_calloc<T>(js::MallocArena, numElems); 91 } 92 93 template <class T> maybe_pod_reallocMallocProvider94 T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) { 95 return maybe_pod_arena_realloc<T>(js::MallocArena, prior, oldSize, newSize); 96 } 97 98 template <class T> pod_mallocMallocProvider99 T* pod_malloc() { 100 return pod_malloc<T>(1); 101 } 102 103 template <class T> pod_arena_mallocMallocProvider104 T* pod_arena_malloc(arena_id_t arena, size_t numElems) { 105 T* p = maybe_pod_arena_malloc<T>(arena, numElems); 106 if (MOZ_LIKELY(p)) { 107 return p; 108 } 109 size_t bytes; 110 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) { 111 client()->reportAllocationOverflow(); 112 return nullptr; 113 } 114 p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, arena, bytes); 115 if (p) { 116 client()->updateMallocCounter(bytes); 117 } 118 return p; 119 } 120 121 template <class T> pod_mallocMallocProvider122 T* pod_malloc(size_t numElems) { 123 return pod_arena_malloc<T>(js::MallocArena, numElems); 124 } 125 126 template <class T, class U> pod_malloc_with_extraMallocProvider127 T* pod_malloc_with_extra(size_t numExtra) { 128 size_t bytes; 129 if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) { 130 client()->reportAllocationOverflow(); 131 return nullptr; 132 } 133 T* p = static_cast<T*>(js_malloc(bytes)); 134 if (MOZ_LIKELY(p)) { 135 client()->updateMallocCounter(bytes); 136 return p; 137 } 138 p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, js::MallocArena, 139 bytes); 140 if (p) { 141 client()->updateMallocCounter(bytes); 142 } 143 return p; 144 } 145 146 template <class T> make_pod_arena_arrayMallocProvider147 UniquePtr<T[], JS::FreePolicy> make_pod_arena_array(arena_id_t arena, 148 size_t numElems) { 149 return UniquePtr<T[], JS::FreePolicy>(pod_arena_malloc<T>(arena, numElems)); 150 } 151 152 template <class T> make_pod_arrayMallocProvider153 UniquePtr<T[], JS::FreePolicy> make_pod_array(size_t numElems) { 154 return make_pod_arena_array<T>(js::MallocArena, numElems); 155 } 156 157 template <class T> 158 T* pod_arena_calloc(arena_id_t arena, size_t numElems = 1) { 159 T* p = maybe_pod_arena_calloc<T>(arena, numElems); 160 if (MOZ_LIKELY(p)) { 161 return p; 162 } 163 size_t bytes; 164 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) { 165 client()->reportAllocationOverflow(); 166 return nullptr; 167 } 168 p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, arena, bytes); 169 if (p) { 170 client()->updateMallocCounter(bytes); 171 } 172 return p; 173 } 174 175 template <class T> 176 T* pod_calloc(size_t numElems = 1) { 177 return pod_arena_calloc<T>(js::MallocArena, numElems); 178 } 179 180 template <class T, class U> pod_calloc_with_extraMallocProvider181 T* pod_calloc_with_extra(size_t numExtra) { 182 size_t bytes; 183 if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) { 184 client()->reportAllocationOverflow(); 185 return nullptr; 186 } 187 T* p = static_cast<T*>(js_calloc(bytes)); 188 if (p) { 189 client()->updateMallocCounter(bytes); 190 return p; 191 } 192 p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, js::MallocArena, 193 bytes); 194 if (p) { 195 client()->updateMallocCounter(bytes); 196 } 197 return p; 198 } 199 200 template <class T> make_zeroed_pod_arrayMallocProvider201 UniquePtr<T[], JS::FreePolicy> make_zeroed_pod_array(size_t numElems) { 202 return UniquePtr<T[], JS::FreePolicy>(pod_calloc<T>(numElems)); 203 } 204 205 template <class T> pod_arena_reallocMallocProvider206 T* pod_arena_realloc(arena_id_t arena, T* prior, size_t oldSize, 207 size_t newSize) { 208 T* p = maybe_pod_arena_realloc(arena, prior, oldSize, newSize); 209 if (MOZ_LIKELY(p)) { 210 return p; 211 } 212 size_t bytes; 213 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(newSize, &bytes))) { 214 client()->reportAllocationOverflow(); 215 return nullptr; 216 } 217 p = (T*)client()->onOutOfMemory(AllocFunction::Realloc, arena, bytes, 218 prior); 219 if (p && newSize > oldSize) { 220 client()->updateMallocCounter((newSize - oldSize) * sizeof(T)); 221 } 222 return p; 223 } 224 225 template <class T> pod_reallocMallocProvider226 T* pod_realloc(T* prior, size_t oldSize, size_t newSize) { 227 return pod_arena_realloc<T>(js::MallocArena, prior, oldSize, newSize); 228 } 229 JS_DECLARE_NEW_METHODSMallocProvider230 JS_DECLARE_NEW_METHODS(new_, pod_malloc<uint8_t>, MOZ_ALWAYS_INLINE) 231 JS_DECLARE_NEW_ARENA_METHODS( 232 arena_new_, 233 [this](arena_id_t arena, size_t size) { 234 return pod_malloc<uint8_t>(size, arena); 235 }, 236 MOZ_ALWAYS_INLINE) 237 238 JS_DECLARE_MAKE_METHODS(make_unique, new_, MOZ_ALWAYS_INLINE) 239 JS_DECLARE_MAKE_METHODS(arena_make_unique, arena_new_, MOZ_ALWAYS_INLINE) 240 241 private: 242 Client* client() { return static_cast<Client*>(this); } 243 244 // The Default implementation is a no-op which can be overridden by the 245 // client. updateMallocCounterMallocProvider246 void updateMallocCounter(size_t nbytes) {} 247 }; 248 249 } /* namespace js */ 250 251 #endif /* vm_MallocProvider_h */ 252