diff options
Diffstat (limited to 'js/src/gc/FreeOp.h')
-rw-r--r-- | js/src/gc/FreeOp.h | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/js/src/gc/FreeOp.h b/js/src/gc/FreeOp.h new file mode 100644 index 0000000000..f33571d856 --- /dev/null +++ b/js/src/gc/FreeOp.h @@ -0,0 +1,153 @@ +/* -*- 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 <class T> + 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 <class T> + 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 <class T> + 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 <class T> + 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 <class T> + 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 |