summaryrefslogtreecommitdiffstats
path: root/js/src/gc/GCInternals.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/gc/GCInternals.h')
-rw-r--r--js/src/gc/GCInternals.h175
1 files changed, 175 insertions, 0 deletions
diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h
new file mode 100644
index 000000000..722539e1c
--- /dev/null
+++ b/js/src/gc/GCInternals.h
@@ -0,0 +1,175 @@
+/* -*- 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 "mozilla/PodOperations.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<AutoTraceSession> session_;
+
+ public:
+ AutoPrepareForTracing(JSContext* cx, ZoneSelector selector);
+ AutoTraceSession& session() { return session_.ref(); }
+};
+
+AbortReason
+IsIncrementalGCUnsafe(JSRuntime* rt);
+
+#ifdef JS_GC_ZEAL
+
+class MOZ_RAII AutoStopVerifyingBarriers
+{
+ GCRuntime* gc;
+ bool restartPreVerifier;
+
+ public:
+ AutoStopVerifyingBarriers(JSRuntime* rt, bool isShutdown)
+ : gc(&rt->gc)
+ {
+ if (gc->isVerifyPreBarriersEnabled()) {
+ gc->endVerifyPreBarriers();
+ restartPreVerifier = !isShutdown;
+ } else {
+ restartPreVerifier = false;
+ }
+ }
+
+ ~AutoStopVerifyingBarriers() {
+ // Nasty special case: verification runs a minor GC, which *may* nest
+ // inside of an outer minor GC. This is not allowed by the
+ // gc::Statistics phase tree. So we pause the "real" GC, if in fact one
+ // is in progress.
+ gcstats::Phase outer = gc->stats.currentPhase();
+ if (outer != gcstats::PHASE_NONE)
+ gc->stats.endPhase(outer);
+ MOZ_ASSERT((gc->stats.currentPhase() == gcstats::PHASE_NONE) ||
+ (gc->stats.currentPhase() == gcstats::PHASE_GC_BEGIN) ||
+ (gc->stats.currentPhase() == gcstats::PHASE_GC_END));
+
+ if (restartPreVerifier)
+ gc->startVerifyPreBarriers();
+
+ if (outer != gcstats::PHASE_NONE)
+ gc->stats.beginPhase(outer);
+ }
+};
+#else
+struct MOZ_RAII AutoStopVerifyingBarriers
+{
+ AutoStopVerifyingBarriers(JSRuntime*, bool) {}
+};
+#endif /* JS_GC_ZEAL */
+
+#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];
+
+ TenureCountCache() { mozilla::PodZero(this); }
+
+ 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 */