/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * 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_GCInternals_h #define gc_GCInternals_h #include "mozilla/ArrayUtils.h" #include "mozilla/Maybe.h" #include "jscntxt.h" #include "gc/Zone.h" #include "vm/HelperThreads.h" #include "vm/Runtime.h" namespace js { namespace gc { void FinishGC(JSContext* cx); /* * This class should be used by any code that needs to exclusive access to the * heap in order to trace through it... */ class MOZ_RAII AutoTraceSession { public: explicit AutoTraceSession(JSRuntime* rt, JS::HeapState state = JS::HeapState::Tracing); ~AutoTraceSession(); // Threads with an exclusive context can hit refillFreeList while holding // the exclusive access lock. To avoid deadlocking when we try to acquire // this lock during GC and the other thread is waiting, make sure we hold // the exclusive access lock during GC sessions. AutoLockForExclusiveAccess lock; protected: JSRuntime* runtime; private: AutoTraceSession(const AutoTraceSession&) = delete; void operator=(const AutoTraceSession&) = delete; JS::HeapState prevState; AutoSPSEntry pseudoFrame; }; class MOZ_RAII AutoPrepareForTracing { mozilla::Maybe session_; public: AutoPrepareForTracing(JSContext* cx, ZoneSelector selector); AutoTraceSession& session() { return session_.ref(); } }; AbortReason IsIncrementalGCUnsafe(JSRuntime* rt); #ifdef JSGC_HASH_TABLE_CHECKS void CheckHashTablesAfterMovingGC(JSRuntime* rt); void CheckHeapAfterGC(JSRuntime* rt); #endif struct MovingTracer : JS::CallbackTracer { explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, TraceWeakMapKeysValues) {} void onObjectEdge(JSObject** objp) override; void onShapeEdge(Shape** shapep) override; void onStringEdge(JSString** stringp) override; void onScriptEdge(JSScript** scriptp) override; void onLazyScriptEdge(LazyScript** lazyp) override; void onBaseShapeEdge(BaseShape** basep) override; void onScopeEdge(Scope** basep) override; void onChild(const JS::GCCellPtr& thing) override { MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell())); } #ifdef DEBUG TracerKind getTracerKind() const override { return TracerKind::Moving; } #endif }; // Structure for counting how many times objects in a particular group have // been tenured during a minor collection. struct TenureCount { ObjectGroup* group; int count; }; // Keep rough track of how many times we tenure objects in particular groups // during minor collections, using a fixed size hash for efficiency at the cost // of potential collisions. struct TenureCountCache { static const size_t EntryShift = 4; static const size_t EntryCount = 1 << EntryShift; TenureCount entries[EntryCount] = {}; // zeroes TenureCountCache() = default; HashNumber hash(ObjectGroup* group) { #if JS_BITS_PER_WORD == 32 static const size_t ZeroBits = 3; #else static const size_t ZeroBits = 4; #endif uintptr_t word = uintptr_t(group); MOZ_ASSERT((word & ((1 << ZeroBits) - 1)) == 0); word >>= ZeroBits; return HashNumber((word >> EntryShift) ^ word); } TenureCount& findEntry(ObjectGroup* group) { return entries[hash(group) % EntryCount]; } }; } /* namespace gc */ } /* namespace js */ #endif /* gc_GCInternals_h */