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 #ifndef gc_FreeOp_h 8 #define gc_FreeOp_h 9 10 #include "mozilla/Assertions.h" // MOZ_ASSERT 11 12 #include "jstypes.h" // JS_PUBLIC_API 13 #include "gc/GCEnum.h" // js::MemoryUse 14 #include "jit/ExecutableAllocator.h" // jit::JitPoisonRangeVector 15 #include "js/AllocPolicy.h" // SystemAllocPolicy 16 #include "js/MemoryFunctions.h" // JSFreeOp 17 #include "js/Utility.h" // AutoEnterOOMUnsafeRegion, js_free 18 #include "js/Vector.h" // js::Vector 19 20 struct JS_PUBLIC_API JSRuntime; 21 22 namespace js { 23 namespace gc { 24 class AutoSetThreadIsPerformingGC; 25 } // namespace gc 26 } // namespace js 27 28 /* 29 * A JSFreeOp can do one thing: free memory. For convenience, it has delete_ 30 * convenience methods that also call destructors. 31 * 32 * JSFreeOp is passed to finalizers and other sweep-phase hooks so that we do 33 * not need to pass a JSContext to those hooks. 34 */ 35 class JSFreeOp { 36 using Cell = js::gc::Cell; 37 using MemoryUse = js::MemoryUse; 38 39 JSRuntime* runtime_; 40 41 js::jit::JitPoisonRangeVector jitPoisonRanges; 42 43 const bool isDefault; 44 bool isCollecting_; 45 46 friend class js::gc::AutoSetThreadIsPerformingGC; 47 48 public: 49 explicit JSFreeOp(JSRuntime* maybeRuntime, bool isDefault = false); 50 ~JSFreeOp(); 51 runtime()52 JSRuntime* runtime() const { 53 MOZ_ASSERT(runtime_); 54 return runtime_; 55 } 56 onMainThread()57 bool onMainThread() const { return runtime_ != nullptr; } 58 maybeOnHelperThread()59 bool maybeOnHelperThread() const { 60 // Sometimes background finalization happens on the main thread so 61 // runtime_ being null doesn't always mean we are off thread. 62 return !runtime_; 63 } 64 isDefaultFreeOp()65 bool isDefaultFreeOp() const { return isDefault; } isCollecting()66 bool isCollecting() const { return isCollecting_; } 67 68 // Deprecated. Where possible, memory should be tracked against the owning GC 69 // thing by calling js::AddCellMemory and the memory freed with free_() below. freeUntracked(void * p)70 void freeUntracked(void* p) { js_free(p); } 71 72 // Free memory associated with a GC thing and update the memory accounting. 73 // 74 // The memory should have been associated with the GC thing using 75 // js::InitReservedSlot or js::InitObjectPrivate, or possibly 76 // js::AddCellMemory. 77 void free_(Cell* cell, void* p, size_t nbytes, MemoryUse use); 78 appendJitPoisonRange(const js::jit::JitPoisonRange & range)79 bool appendJitPoisonRange(const js::jit::JitPoisonRange& range) { 80 // JSFreeOps other than the defaultFreeOp() are constructed on the stack, 81 // and won't hold onto the pointers to free indefinitely. 82 MOZ_ASSERT(!isDefaultFreeOp()); 83 84 return jitPoisonRanges.append(range); 85 } 86 87 // Deprecated. Where possible, memory should be tracked against the owning GC 88 // thing by calling js::AddCellMemory and the memory freed with delete_() 89 // below. 90 template <class T> deleteUntracked(T * p)91 void deleteUntracked(T* p) { 92 if (p) { 93 p->~T(); 94 js_free(p); 95 } 96 } 97 98 // Delete a C++ object that was associated with a GC thing and update the 99 // memory accounting. The size is determined by the type T. 100 // 101 // The memory should have been associated with the GC thing using 102 // js::InitReservedSlot or js::InitObjectPrivate, or possibly 103 // js::AddCellMemory. 104 template <class T> delete_(Cell * cell,T * p,MemoryUse use)105 void delete_(Cell* cell, T* p, MemoryUse use) { 106 delete_(cell, p, sizeof(T), use); 107 } 108 109 // Delete a C++ object that was associated with a GC thing and update the 110 // memory accounting. 111 // 112 // The memory should have been associated with the GC thing using 113 // js::InitReservedSlot or js::InitObjectPrivate, or possibly 114 // js::AddCellMemory. 115 template <class T> delete_(Cell * cell,T * p,size_t nbytes,MemoryUse use)116 void delete_(Cell* cell, T* p, size_t nbytes, MemoryUse use) { 117 if (p) { 118 p->~T(); 119 free_(cell, p, nbytes, use); 120 } 121 } 122 123 // Release a RefCounted object that was associated with a GC thing and update 124 // the memory accounting. 125 // 126 // The memory should have been associated with the GC thing using 127 // js::InitReservedSlot or js::InitObjectPrivate, or possibly 128 // js::AddCellMemory. 129 // 130 // This counts the memory once per association with a GC thing. It's not 131 // expected that the same object is associated with more than one GC thing in 132 // each zone. If this is the case then some other form of accounting would be 133 // more appropriate. 134 template <class T> release(Cell * cell,T * p,MemoryUse use)135 void release(Cell* cell, T* p, MemoryUse use) { 136 release(cell, p, sizeof(T), use); 137 } 138 139 // Release a RefCounted object and that was associated with a GC thing and 140 // update the memory accounting. 141 // 142 // The memory should have been associated with the GC thing using 143 // js::InitReservedSlot or js::InitObjectPrivate, or possibly 144 // js::AddCellMemory. 145 template <class T> 146 void release(Cell* cell, T* p, size_t nbytes, MemoryUse use); 147 148 // Update the memory accounting for a GC for memory freed by some other 149 // method. 150 void removeCellMemory(Cell* cell, size_t nbytes, MemoryUse use); 151 }; 152 153 #endif // gc_FreeOp_h 154