Allocator.h (8148B)
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 // SpiderMonkey GC allocation API. 8 9 #ifndef gc_Allocator_h 10 #define gc_Allocator_h 11 12 #include "gc/AllocKind.h" 13 #include "gc/GCEnum.h" 14 #include "js/HeapAPI.h" 15 #include "js/TypeDecls.h" 16 17 namespace js { 18 namespace gc { 19 20 class AllocSite; 21 struct Cell; 22 class BufferAllocator; 23 class TenuredCell; 24 class TenuringTracer; 25 26 // Allocator implementation functions. SpiderMonkey code outside this file 27 // should use: 28 // 29 // cx->newCell<T>(...) 30 // 31 // or optionally: 32 // 33 // cx->newCell<T, AllowGC::NoGC>(...) 34 // 35 // `friend` js::gc::CellAllocator in a subtype T of Cell in order to allow it to 36 // be allocated with cx->newCell<T>(...). The friend declaration will allow 37 // calling T's constructor. 38 // 39 // The parameters will be passed to a type-specific function or constructor. For 40 // nursery-allocatable types, see e.g. the NewString, NewObject, and NewBigInt 41 // methods. For all other types, the parameters will be forwarded to the 42 // constructor. 43 class CellAllocator { 44 public: 45 // This is the entry point for all allocation, though callers should still not 46 // use this directly. Use cx->newCell<T>(...) instead. 47 // 48 // After a successful allocation the caller must fully initialize the thing 49 // before calling any function that can potentially trigger GC. This will 50 // ensure that GC tracing never sees junk values stored in the partially 51 // initialized thing. 52 template <typename T, AllowGC allowGC = CanGC, typename... Args> 53 static inline T* NewCell(JSContext* cx, Args&&... args); 54 friend class BufferAllocator; 55 56 private: 57 // Allocate a string. Use cx->newCell<T>([heap]). 58 // 59 // Use for nursery-allocatable strings. Returns a value cast to the correct 60 // type. Non-nursery-allocatable strings will go through the fallback 61 // tenured-only allocation path. 62 template <typename T, AllowGC allowGC, typename... Args> 63 static T* NewString(JSContext* cx, Heap heap, Args&&... args); 64 65 template <typename T, AllowGC allowGC> 66 static T* NewBigInt(JSContext* cx, Heap heap); 67 68 template <typename T, AllowGC allowGC, typename... Args> 69 static T* NewGetterSetter(JSContext* cx, Heap heap, Args&&... args); 70 71 template <typename T, AllowGC allowGC> 72 static T* NewObject(JSContext* cx, AllocKind kind, Heap heap, 73 const JSClass* clasp, AllocSite* site = nullptr); 74 75 // Allocate all other kinds of GC thing. 76 template <typename T, AllowGC allowGC, typename... Args> 77 static T* NewTenuredCell(JSContext* cx, Args&&... args); 78 79 // Allocate a cell in the nursery, unless |heap| is Heap::Tenured or nursery 80 // allocation is disabled for |traceKind| in the current zone. 81 template <JS::TraceKind traceKind, AllowGC allowGC> 82 static void* AllocNurseryOrTenuredCell(JSContext* cx, AllocKind allocKind, 83 size_t thingSize, Heap heap, 84 AllocSite* site); 85 friend class TenuringTracer; 86 87 template <AllowGC allowGC> 88 static void* RetryNurseryAlloc(JSContext* cx, JS::TraceKind traceKind, 89 AllocKind allocKind, size_t thingSize, 90 AllocSite* site); 91 template <AllowGC allowGC> 92 static void* AllocTenuredCellForNurseryAlloc(JSContext* cx, AllocKind kind); 93 94 // Allocate a cell in the tenured heap. 95 template <AllowGC allowGC> 96 static void* AllocTenuredCell(JSContext* cx, AllocKind kind); 97 98 template <AllowGC allowGC> 99 static void* AllocTenuredCellUnchecked(JS::Zone* zone, AllocKind kind); 100 101 static void* RetryTenuredAlloc(JS::Zone* zone, AllocKind kind); 102 103 #ifdef JS_GC_ZEAL 104 static AllocSite* MaybeGenerateMissingAllocSite(JSContext* cx, 105 JS::TraceKind traceKind, 106 AllocSite* site); 107 #endif 108 109 #ifdef DEBUG 110 static void CheckIncrementalZoneState(JS::Zone* zone, void* ptr); 111 #endif 112 113 static inline Heap CheckedHeap(Heap heap); 114 }; 115 116 // Buffer allocator public API. 117 118 size_t GetGoodAllocSize(size_t requiredBytes); 119 size_t GetGoodPower2AllocSize(size_t requiredBytes); 120 size_t GetGoodElementCount(size_t requiredCount, size_t elementSize); 121 size_t GetGoodPower2ElementCount(size_t requiredCount, size_t elementSize); 122 void* AllocBuffer(JS::Zone* zone, size_t bytes, bool nurseryOwned); 123 void* ReallocBuffer(JS::Zone* zone, void* alloc, size_t bytes, 124 bool nurseryOwned); 125 void FreeBuffer(JS::Zone* zone, void* alloc); 126 127 template <typename T, typename... Args> 128 T* NewBuffer(JS::Zone* zone, size_t bytes, bool nurseryOwned, Args&&... args) { 129 MOZ_ASSERT(sizeof(T) <= bytes); 130 void* ptr = AllocBuffer(zone, bytes, nurseryOwned); 131 if (!ptr) { 132 return nullptr; 133 } 134 135 return new (ptr) T(std::forward<Args>(args)...); 136 } 137 138 // Indicate whether |alloc| is a buffer allocation as opposed to a fixed size GC 139 // cell. Does not work for malloced memory. 140 bool IsBufferAlloc(void* alloc); 141 142 #ifdef DEBUG 143 // Check whether a buffer allocation is part of the specified zone. 144 bool IsBufferAllocInZone(void* alloc, JS::Zone* zone); 145 #endif 146 147 bool IsNurseryOwned(JS::Zone* zone, void* alloc); 148 149 size_t GetAllocSize(JS::Zone* zone, const void* alloc); 150 151 // Buffer allocator GC-internal API. 152 153 void* AllocBufferInGC(JS::Zone* zone, size_t bytes, bool nurseryOwned); 154 bool IsBufferAllocMarkedBlack(JS::Zone* zone, void* alloc); 155 void TraceBufferEdgeInternal(JSTracer* trc, Cell* owner, void** bufferp, 156 const char* name); 157 void TraceBufferEdgeInternal(JSTracer* trc, JS::Zone* zone, void** bufferp, 158 const char* name); 159 void MarkTenuredBuffer(JS::Zone* zone, void* alloc); 160 161 } // namespace gc 162 163 // Allow rooting buffers. 164 165 template <typename T> 166 class MutableHandleBuffer; 167 168 template <typename T> 169 class BufferHolder { 170 JS::Zone* zone; 171 T* buffer; 172 173 friend class MutableHandleBuffer<T>; 174 175 public: 176 BufferHolder(JS::Zone* zone, T* buffer) : zone(zone), buffer(buffer) { 177 MOZ_ASSERT_IF(buffer, IsBufferAllocInZone(buffer, zone)); 178 } 179 inline BufferHolder(JSContext* cx, T* buffer); 180 181 inline void trace(JSTracer* trc); 182 183 T* get() const { return buffer; } 184 operator T*() const { return get(); } 185 T* operator->() const { return get(); } 186 T& operator*() const { return *get(); } 187 }; 188 189 template <typename T> 190 class RootedBuffer : public JS::Rooted<BufferHolder<T>> { 191 using Base = JS::Rooted<BufferHolder<T>>; 192 193 public: 194 RootedBuffer(JSContext* cx, T* buffer) 195 : Base(cx, BufferHolder<T>(cx, buffer)) {} 196 T* get() const { return Base::get().get(); } 197 operator T*() const { return get(); } 198 T* operator->() const { return get(); } 199 T& operator*() const { return *get(); } 200 }; 201 202 template <typename T> 203 class HandleBuffer : public JS::Handle<BufferHolder<T>> { 204 using Base = JS::Handle<BufferHolder<T>>; 205 206 public: 207 HandleBuffer(const HandleBuffer& other) : Base(other) {} 208 MOZ_IMPLICIT HandleBuffer(const RootedBuffer<T>& root) : Base(root) {} 209 MOZ_IMPLICIT HandleBuffer(JS::MutableHandle<BufferHolder<T>>& handle) 210 : Base(handle) {} 211 212 T* get() const { return Base::get().get(); } 213 operator T*() const { return get(); } 214 T* operator->() const { return get(); } 215 T& operator*() const { return *get(); } 216 }; 217 218 template <typename T> 219 class MutableHandleBuffer : public JS::MutableHandle<BufferHolder<T>> { 220 using Base = JS::MutableHandle<BufferHolder<T>>; 221 222 public: 223 MutableHandleBuffer(const MutableHandleBuffer& other) : Base(other) {} 224 MOZ_IMPLICIT MutableHandleBuffer(RootedBuffer<T>* root) : Base(root) {} 225 226 void set(T* buffer) { 227 BufferHolder<T>& holder = Base::get(); 228 MOZ_ASSERT_IF(buffer, IsBufferAllocInZone(buffer, holder.zone)); 229 holder.buffer = buffer; 230 } 231 T* get() const { return Base::get().get(); } 232 operator T*() const { return get(); } 233 T* operator->() const { return get(); } 234 T& operator*() const { return *get(); } 235 }; 236 237 } // namespace js 238 239 #endif // gc_Allocator_h