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/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_mallocMallocProvider52 T* maybe_pod_malloc(size_t numElems) { 53 T* p = js_pod_malloc<T>(numElems); 54 if (MOZ_LIKELY(p)) client()->updateMallocCounter(numElems * sizeof(T)); 55 return p; 56 } 57 58 template <class T> maybe_pod_callocMallocProvider59 T* maybe_pod_calloc(size_t numElems) { 60 T* p = js_pod_calloc<T>(numElems); 61 if (MOZ_LIKELY(p)) client()->updateMallocCounter(numElems * sizeof(T)); 62 return p; 63 } 64 65 template <class T> maybe_pod_reallocMallocProvider66 T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) { 67 T* p = js_pod_realloc(prior, oldSize, newSize); 68 if (MOZ_LIKELY(p)) { 69 // For compatibility we do not account for realloc that decreases 70 // previously allocated memory. 71 if (newSize > oldSize) 72 client()->updateMallocCounter((newSize - oldSize) * sizeof(T)); 73 } 74 return p; 75 } 76 77 template <class T> pod_mallocMallocProvider78 T* pod_malloc() { 79 return pod_malloc<T>(1); 80 } 81 82 template <class T> pod_mallocMallocProvider83 T* pod_malloc(size_t numElems) { 84 T* p = maybe_pod_malloc<T>(numElems); 85 if (MOZ_LIKELY(p)) return p; 86 size_t bytes; 87 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) { 88 client()->reportAllocationOverflow(); 89 return nullptr; 90 } 91 p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, bytes); 92 if (p) client()->updateMallocCounter(bytes); 93 return p; 94 } 95 96 template <class T, class U> pod_malloc_with_extraMallocProvider97 T* pod_malloc_with_extra(size_t numExtra) { 98 size_t bytes; 99 if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) { 100 client()->reportAllocationOverflow(); 101 return nullptr; 102 } 103 T* p = static_cast<T*>(js_malloc(bytes)); 104 if (MOZ_LIKELY(p)) { 105 client()->updateMallocCounter(bytes); 106 return p; 107 } 108 p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, bytes); 109 if (p) client()->updateMallocCounter(bytes); 110 return p; 111 } 112 113 template <class T> make_pod_arrayMallocProvider114 UniquePtr<T[], JS::FreePolicy> make_pod_array(size_t numElems) { 115 return UniquePtr<T[], JS::FreePolicy>(pod_malloc<T>(numElems)); 116 } 117 118 template <class T> pod_callocMallocProvider119 T* pod_calloc() { 120 return pod_calloc<T>(1); 121 } 122 123 template <class T> pod_callocMallocProvider124 T* pod_calloc(size_t numElems) { 125 T* p = maybe_pod_calloc<T>(numElems); 126 if (MOZ_LIKELY(p)) return p; 127 size_t bytes; 128 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) { 129 client()->reportAllocationOverflow(); 130 return nullptr; 131 } 132 p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, bytes); 133 if (p) client()->updateMallocCounter(bytes); 134 return p; 135 } 136 137 template <class T, class U> pod_calloc_with_extraMallocProvider138 T* pod_calloc_with_extra(size_t numExtra) { 139 size_t bytes; 140 if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) { 141 client()->reportAllocationOverflow(); 142 return nullptr; 143 } 144 T* p = static_cast<T*>(js_calloc(bytes)); 145 if (p) { 146 client()->updateMallocCounter(bytes); 147 return p; 148 } 149 p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, bytes); 150 if (p) client()->updateMallocCounter(bytes); 151 return p; 152 } 153 154 template <class T> make_zeroed_pod_arrayMallocProvider155 UniquePtr<T[], JS::FreePolicy> make_zeroed_pod_array(size_t numElems) { 156 return UniquePtr<T[], JS::FreePolicy>(pod_calloc<T>(numElems)); 157 } 158 159 template <class T> pod_reallocMallocProvider160 T* pod_realloc(T* prior, size_t oldSize, size_t newSize) { 161 T* p = maybe_pod_realloc(prior, oldSize, newSize); 162 if (MOZ_LIKELY(p)) return p; 163 size_t bytes; 164 if (MOZ_UNLIKELY(!CalculateAllocSize<T>(newSize, &bytes))) { 165 client()->reportAllocationOverflow(); 166 return nullptr; 167 } 168 p = (T*)client()->onOutOfMemory(AllocFunction::Realloc, bytes, prior); 169 if (p && newSize > oldSize) 170 client()->updateMallocCounter((newSize - oldSize) * sizeof(T)); 171 return p; 172 } 173 JS_DECLARE_NEW_METHODSMallocProvider174 JS_DECLARE_NEW_METHODS(new_, pod_malloc<uint8_t>, MOZ_ALWAYS_INLINE) 175 JS_DECLARE_MAKE_METHODS(make_unique, new_, MOZ_ALWAYS_INLINE) 176 177 private: 178 Client* client() { return static_cast<Client*>(this); } 179 }; 180 181 } /* namespace js */ 182 183 #endif /* vm_MallocProvider_h */ 184