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 * - ThreadsafeContext > ExclusiveContext > JSContext: 38 * Dispatches directly to the runtime. 39 */ 40 41 #ifndef vm_MallocProvider_h 42 #define vm_MallocProvider_h 43 44 #include "mozilla/Attributes.h" 45 #include "mozilla/Likely.h" 46 47 #include "js/UniquePtr.h" 48 #include "js/Utility.h" 49 50 namespace js { 51 52 template<class Client> 53 struct MallocProvider 54 { 55 template <class T> maybe_pod_mallocMallocProvider56 T* maybe_pod_malloc(size_t numElems) { 57 T* p = js_pod_malloc<T>(numElems); 58 if (MOZ_LIKELY(p)) 59 client()->updateMallocCounter(numElems * sizeof(T)); 60 return p; 61 } 62 63 template <class T> maybe_pod_callocMallocProvider64 T* maybe_pod_calloc(size_t numElems) { 65 T* p = js_pod_calloc<T>(numElems); 66 if (MOZ_LIKELY(p)) 67 client()->updateMallocCounter(numElems * sizeof(T)); 68 return p; 69 } 70 71 template <class T> maybe_pod_reallocMallocProvider72 T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) { 73 T* p = js_pod_realloc(prior, oldSize, newSize); 74 if (MOZ_LIKELY(p)) { 75 // For compatibility we do not account for realloc that decreases 76 // previously allocated memory. 77 if (newSize > oldSize) 78 client()->updateMallocCounter((newSize - oldSize) * sizeof(T)); 79 } 80 return p; 81 } 82 83 template <class T> pod_mallocMallocProvider84 T* pod_malloc() { 85 return pod_malloc<T>(1); 86 } 87 88 template <class T> pod_mallocMallocProvider89 T* pod_malloc(size_t numElems) { 90 T* p = maybe_pod_malloc<T>(numElems); 91 if (MOZ_LIKELY(p)) 92 return p; 93 size_t bytes; 94 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) { 95 client()->reportAllocationOverflow(); 96 return nullptr; 97 } 98 p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, bytes); 99 if (p) 100 client()->updateMallocCounter(bytes); 101 return p; 102 } 103 104 template <class T, class U> pod_malloc_with_extraMallocProvider105 T* pod_malloc_with_extra(size_t numExtra) { 106 size_t bytes; 107 if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) { 108 client()->reportAllocationOverflow(); 109 return nullptr; 110 } 111 T* p = static_cast<T*>(js_malloc(bytes)); 112 if (MOZ_LIKELY(p)) { 113 client()->updateMallocCounter(bytes); 114 return p; 115 } 116 p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, bytes); 117 if (p) 118 client()->updateMallocCounter(bytes); 119 return p; 120 } 121 122 template <class T> 123 UniquePtr<T[], JS::FreePolicy> make_pod_arrayMallocProvider124 make_pod_array(size_t numElems) { 125 return UniquePtr<T[], JS::FreePolicy>(pod_malloc<T>(numElems)); 126 } 127 128 template <class T> pod_callocMallocProvider129 T* pod_calloc() { 130 return pod_calloc<T>(1); 131 } 132 133 template <class T> pod_callocMallocProvider134 T* pod_calloc(size_t numElems) { 135 T* p = maybe_pod_calloc<T>(numElems); 136 if (MOZ_LIKELY(p)) 137 return p; 138 size_t bytes; 139 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) { 140 client()->reportAllocationOverflow(); 141 return nullptr; 142 } 143 p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, bytes); 144 if (p) 145 client()->updateMallocCounter(bytes); 146 return p; 147 } 148 149 template <class T, class U> pod_calloc_with_extraMallocProvider150 T* pod_calloc_with_extra(size_t numExtra) { 151 size_t bytes; 152 if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) { 153 client()->reportAllocationOverflow(); 154 return nullptr; 155 } 156 T* p = static_cast<T*>(js_calloc(bytes)); 157 if (p) { 158 client()->updateMallocCounter(bytes); 159 return p; 160 } 161 p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, bytes); 162 if (p) 163 client()->updateMallocCounter(bytes); 164 return p; 165 } 166 167 template <class T> 168 UniquePtr<T[], JS::FreePolicy> make_zeroed_pod_arrayMallocProvider169 make_zeroed_pod_array(size_t numElems) 170 { 171 return UniquePtr<T[], JS::FreePolicy>(pod_calloc<T>(numElems)); 172 } 173 174 template <class T> pod_reallocMallocProvider175 T* pod_realloc(T* prior, size_t oldSize, size_t newSize) { 176 T* p = maybe_pod_realloc(prior, oldSize, newSize); 177 if (MOZ_LIKELY(p)) 178 return p; 179 size_t bytes; 180 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(newSize, &bytes))) { 181 client()->reportAllocationOverflow(); 182 return nullptr; 183 } 184 p = (T*)client()->onOutOfMemory(AllocFunction::Realloc, bytes, prior); 185 if (p && newSize > oldSize) 186 client()->updateMallocCounter((newSize - oldSize) * sizeof(T)); 187 return p; 188 } 189 JS_DECLARE_NEW_METHODSMallocProvider190 JS_DECLARE_NEW_METHODS(new_, pod_malloc<uint8_t>, MOZ_ALWAYS_INLINE) 191 JS_DECLARE_MAKE_METHODS(make_unique, new_, MOZ_ALWAYS_INLINE) 192 193 private: 194 Client* client() { return static_cast<Client*>(this); } 195 }; 196 197 } /* namespace js */ 198 199 #endif /* vm_MallocProvider_h */ 200