blob: faf38ea5856e084a217ad01eca485f5a42ba802c [file] [log] [blame]
/* -*- 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/PodOperations.h"
#include "jscntxt.h"
#include "gc/Zone.h"
#include "vm/HelperThreads.h"
#include "vm/Runtime.h"
namespace js {
namespace gc {
void
MarkPersistentRootedChains(JSTracer* trc);
class MOZ_RAII AutoCopyFreeListToArenas
{
JSRuntime* runtime;
ZoneSelector selector;
public:
AutoCopyFreeListToArenas(JSRuntime* rt, ZoneSelector selector);
~AutoCopyFreeListToArenas();
};
struct MOZ_RAII AutoFinishGC
{
explicit AutoFinishGC(JSRuntime* rt);
};
/*
* 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();
protected:
AutoLockForExclusiveAccess lock;
JSRuntime* runtime;
private:
AutoTraceSession(const AutoTraceSession&) = delete;
void operator=(const AutoTraceSession&) = delete;
JS::HeapState prevState;
AutoSPSEntry pseudoFrame;
};
struct MOZ_RAII AutoPrepareForTracing
{
AutoFinishGC finish;
AutoTraceSession session;
AutoCopyFreeListToArenas copy;
AutoPrepareForTracing(JSRuntime* rt, ZoneSelector selector);
};
class IncrementalSafety
{
const char* reason_;
explicit IncrementalSafety(const char* reason) : reason_(reason) {}
public:
static IncrementalSafety Safe() { return IncrementalSafety(nullptr); }
static IncrementalSafety Unsafe(const char* reason) { return IncrementalSafety(reason); }
explicit operator bool() const {
return reason_ == nullptr;
}
const char* reason() {
MOZ_ASSERT(reason_);
return reason_;
}
};
IncrementalSafety
IsIncrementalGCSafe(JSRuntime* rt);
class MOZ_RAII AutoStopVerifyingBarriers
{
GCRuntime* gc;
bool restartPreVerifier;
public:
AutoStopVerifyingBarriers(JSRuntime* rt, bool isShutdown)
: gc(&rt->gc)
{
if (cobalt::configuration::Configuration::GetInstance()->CobaltGcZeal()) {
restartPreVerifier = gc->endVerifyPreBarriers() && !isShutdown;
}
}
~AutoStopVerifyingBarriers() {
if (cobalt::configuration::Configuration::GetInstance()->CobaltGcZeal()) {
// 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);
}
}
};
#ifdef JSGC_HASH_TABLE_CHECKS
void
CheckHashTablesAfterMovingGC(JSRuntime* rt);
#endif
struct MovingTracer : JS::CallbackTracer
{
explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, TraceWeakMapKeysValues) {}
void onObjectEdge(JSObject** objp) override;
void onChild(const JS::GCCellPtr& thing) override {
MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
}
#ifdef DEBUG
TracerKind getTracerKind() const override { return TracerKind::Moving; }
#endif
};
class MOZ_RAII AutoMaybeStartBackgroundAllocation
{
private:
JSRuntime* runtime;
public:
AutoMaybeStartBackgroundAllocation()
: runtime(nullptr)
{}
void tryToStartBackgroundAllocation(JSRuntime* rt) {
runtime = rt;
}
~AutoMaybeStartBackgroundAllocation() {
if (runtime)
runtime->gc.startBackgroundAllocTaskIfIdle();
}
};
// In debug builds, set/unset the GC sweeping flag for the current thread.
struct MOZ_RAII AutoSetThreadIsSweeping
{
#ifdef DEBUG
AutoSetThreadIsSweeping()
: threadData_(js::TlsPerThreadData.get())
{
MOZ_ASSERT(!threadData_->gcSweeping);
threadData_->gcSweeping = true;
}
~AutoSetThreadIsSweeping() {
MOZ_ASSERT(threadData_->gcSweeping);
threadData_->gcSweeping = false;
}
private:
PerThreadData* threadData_;
#else
AutoSetThreadIsSweeping() {}
#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
{
TenureCount entries[16];
TenureCountCache() { mozilla::PodZero(this); }
TenureCount& findEntry(ObjectGroup* group) {
return entries[PointerHasher<ObjectGroup*, 3>::hash(group) % mozilla::ArrayLength(entries)];
}
};
} /* namespace gc */
} /* namespace js */
#endif /* gc_GCInternals_h */