/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef gc_FreeOp_h #define gc_FreeOp_h #include "mozilla/Assertions.h" // MOZ_ASSERT #include "jstypes.h" // JS_PUBLIC_API #include "gc/GCEnum.h" // js::MemoryUse #include "jit/ExecutableAllocator.h" // jit::JitPoisonRangeVector #include "js/AllocPolicy.h" // SystemAllocPolicy #include "js/MemoryFunctions.h" // JSFreeOp #include "js/Utility.h" // AutoEnterOOMUnsafeRegion, js_free #include "js/Vector.h" // js::Vector struct JS_PUBLIC_API JSRuntime; namespace js { namespace gc { class AutoSetThreadIsPerformingGC; } // namespace gc } // namespace js /* * A JSFreeOp can do one thing: free memory. For convenience, it has delete_ * convenience methods that also call destructors. * * JSFreeOp is passed to finalizers and other sweep-phase hooks so that we do * not need to pass a JSContext to those hooks. */ class JSFreeOp { using Cell = js::gc::Cell; using MemoryUse = js::MemoryUse; JSRuntime* runtime_; js::jit::JitPoisonRangeVector jitPoisonRanges; const bool isDefault; bool isCollecting_; friend class js::gc::AutoSetThreadIsPerformingGC; public: explicit JSFreeOp(JSRuntime* maybeRuntime, bool isDefault = false); ~JSFreeOp(); JSRuntime* runtime() const { MOZ_ASSERT(runtime_); return runtime_; } bool onMainThread() const { return runtime_ != nullptr; } bool maybeOnHelperThread() const { // Sometimes background finalization happens on the main thread so // runtime_ being null doesn't always mean we are off thread. return !runtime_; } bool isDefaultFreeOp() const { return isDefault; } bool isCollecting() const { return isCollecting_; } // Deprecated. Where possible, memory should be tracked against the owning GC // thing by calling js::AddCellMemory and the memory freed with free_() below. void freeUntracked(void* p) { js_free(p); } // Free memory associated with a GC thing and update the memory accounting. // // The memory should have been associated with the GC thing using // js::InitReservedSlot or js::InitObjectPrivate, or possibly // js::AddCellMemory. void free_(Cell* cell, void* p, size_t nbytes, MemoryUse use); bool appendJitPoisonRange(const js::jit::JitPoisonRange& range) { // JSFreeOps other than the defaultFreeOp() are constructed on the stack, // and won't hold onto the pointers to free indefinitely. MOZ_ASSERT(!isDefaultFreeOp()); return jitPoisonRanges.append(range); } // Deprecated. Where possible, memory should be tracked against the owning GC // thing by calling js::AddCellMemory and the memory freed with delete_() // below. template void deleteUntracked(T* p) { if (p) { p->~T(); js_free(p); } } // Delete a C++ object that was associated with a GC thing and update the // memory accounting. The size is determined by the type T. // // The memory should have been associated with the GC thing using // js::InitReservedSlot or js::InitObjectPrivate, or possibly // js::AddCellMemory. template void delete_(Cell* cell, T* p, MemoryUse use) { delete_(cell, p, sizeof(T), use); } // Delete a C++ object that was associated with a GC thing and update the // memory accounting. // // The memory should have been associated with the GC thing using // js::InitReservedSlot or js::InitObjectPrivate, or possibly // js::AddCellMemory. template void delete_(Cell* cell, T* p, size_t nbytes, MemoryUse use) { if (p) { p->~T(); free_(cell, p, nbytes, use); } } // Release a RefCounted object that was associated with a GC thing and update // the memory accounting. // // The memory should have been associated with the GC thing using // js::InitReservedSlot or js::InitObjectPrivate, or possibly // js::AddCellMemory. // // This counts the memory once per association with a GC thing. It's not // expected that the same object is associated with more than one GC thing in // each zone. If this is the case then some other form of accounting would be // more appropriate. template void release(Cell* cell, T* p, MemoryUse use) { release(cell, p, sizeof(T), use); } // Release a RefCounted object and that was associated with a GC thing and // update the memory accounting. // // The memory should have been associated with the GC thing using // js::InitReservedSlot or js::InitObjectPrivate, or possibly // js::AddCellMemory. template void release(Cell* cell, T* p, size_t nbytes, MemoryUse use); // Update the memory accounting for a GC for memory freed by some other // method. void removeCellMemory(Cell* cell, size_t nbytes, MemoryUse use); }; #endif // gc_FreeOp_h