mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-09 04:25:38 +00:00
Bug 988486 - Move verifier functions into GCRuntime r=terrence
This commit is contained in:
parent
ff878c9058
commit
f17bd34eff
@ -13,6 +13,12 @@
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/Value.h"
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
class GCRuntime;
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum JSGCMode {
|
||||
/* Perform only global GCs. */
|
||||
JSGC_MODE_GLOBAL = 0,
|
||||
@ -329,7 +335,7 @@ WasIncrementalGC(JSRuntime *rt);
|
||||
/* Ensure that generational GC is disabled within some scope. */
|
||||
class JS_FRIEND_API(AutoDisableGenerationalGC)
|
||||
{
|
||||
JSRuntime *runtime;
|
||||
js::gc::GCRuntime *gc;
|
||||
#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
|
||||
bool restartVerifier;
|
||||
#endif
|
||||
|
@ -91,24 +91,10 @@ IncrementalSafety
|
||||
IsIncrementalGCSafe(JSRuntime *rt);
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
void
|
||||
StartVerifyPreBarriers(JSRuntime *rt);
|
||||
|
||||
void
|
||||
EndVerifyPreBarriers(JSRuntime *rt);
|
||||
|
||||
void
|
||||
StartVerifyPostBarriers(JSRuntime *rt);
|
||||
|
||||
void
|
||||
EndVerifyPostBarriers(JSRuntime *rt);
|
||||
|
||||
void
|
||||
FinishVerifier(JSRuntime *rt);
|
||||
|
||||
class AutoStopVerifyingBarriers
|
||||
{
|
||||
JSRuntime *runtime;
|
||||
GCRuntime *gc;
|
||||
bool restartPreVerifier;
|
||||
bool restartPostVerifier;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
@ -116,22 +102,19 @@ class AutoStopVerifyingBarriers
|
||||
public:
|
||||
AutoStopVerifyingBarriers(JSRuntime *rt, bool isShutdown
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: runtime(rt)
|
||||
: gc(&rt->gc)
|
||||
{
|
||||
restartPreVerifier = !isShutdown && rt->gc.verifyPreData;
|
||||
restartPostVerifier = !isShutdown && rt->gc.verifyPostData && JS::IsGenerationalGCEnabled(rt);
|
||||
if (rt->gc.verifyPreData)
|
||||
EndVerifyPreBarriers(rt);
|
||||
if (rt->gc.verifyPostData)
|
||||
EndVerifyPostBarriers(rt);
|
||||
restartPreVerifier = gc->endVerifyPreBarriers() && !isShutdown;
|
||||
restartPostVerifier = gc->endVerifyPostBarriers() && !isShutdown &&
|
||||
JS::IsGenerationalGCEnabled(rt);
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
~AutoStopVerifyingBarriers() {
|
||||
if (restartPreVerifier)
|
||||
StartVerifyPreBarriers(runtime);
|
||||
gc->startVerifyPreBarriers();
|
||||
if (restartPostVerifier)
|
||||
StartVerifyPostBarriers(runtime);
|
||||
gc->startVerifyPostBarriers();
|
||||
}
|
||||
};
|
||||
#else
|
||||
|
@ -131,6 +131,13 @@ class GCRuntime
|
||||
|
||||
void markRuntime(JSTracer *trc, bool useSavedRoots = false);
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
void verifyPreBarriers();
|
||||
void verifyPostBarriers();
|
||||
void maybeVerifyPreBarriers(bool always);
|
||||
void maybeVerifyPostBarriers(bool always);
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Internal public interface
|
||||
void recordNativeStackTop();
|
||||
@ -179,6 +186,18 @@ class GCRuntime
|
||||
|
||||
void setAlwaysPreserveCode() { alwaysPreserveCode = true; }
|
||||
|
||||
bool isGenerationalGCEnabled() { return generationalDisabled == 0; }
|
||||
void disableGenerationalGC();
|
||||
void enableGenerationalGC();
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
void startVerifyPreBarriers();
|
||||
bool endVerifyPreBarriers();
|
||||
void startVerifyPostBarriers();
|
||||
bool endVerifyPostBarriers();
|
||||
void finishVerifier();
|
||||
#endif
|
||||
|
||||
private:
|
||||
// For ArenaLists::allocateFromArenaInline()
|
||||
friend class ArenaLists;
|
||||
|
@ -169,9 +169,9 @@ NextNode(VerifyNode *node)
|
||||
}
|
||||
|
||||
void
|
||||
gc::StartVerifyPreBarriers(JSRuntime *rt)
|
||||
gc::GCRuntime::startVerifyPreBarriers()
|
||||
{
|
||||
if (rt->gc.verifyPreData || rt->gc.incrementalState != NO_INCREMENTAL)
|
||||
if (verifyPreData || incrementalState != NO_INCREMENTAL)
|
||||
return;
|
||||
|
||||
/*
|
||||
@ -180,7 +180,7 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
|
||||
* starting the pre barrier verifier if the post barrier verifier is already
|
||||
* running.
|
||||
*/
|
||||
if (rt->gc.verifyPostData)
|
||||
if (verifyPostData)
|
||||
return;
|
||||
|
||||
MinorGC(rt, JS::gcreason::EVICT_NURSERY);
|
||||
@ -190,10 +190,10 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
|
||||
if (!IsIncrementalGCSafe(rt))
|
||||
return;
|
||||
|
||||
for (GCChunkSet::Range r(rt->gc.chunkSet.all()); !r.empty(); r.popFront())
|
||||
for (GCChunkSet::Range r(chunkSet.all()); !r.empty(); r.popFront())
|
||||
r.front()->bitmap.clear();
|
||||
|
||||
rt->gc.number++;
|
||||
number++;
|
||||
|
||||
VerifyPreTracer *trc = js_new<VerifyPreTracer>(rt, JSTraceCallback(nullptr));
|
||||
if (!trc)
|
||||
@ -219,10 +219,10 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
|
||||
trc->curnode = MakeNode(trc, nullptr, JSGCTraceKind(0));
|
||||
|
||||
/* We want MarkRuntime to save the roots to gcSavedRoots. */
|
||||
rt->gc.incrementalState = MARK_ROOTS;
|
||||
incrementalState = MARK_ROOTS;
|
||||
|
||||
/* Make all the roots be edges emanating from the root node. */
|
||||
rt->gc.markRuntime(trc);
|
||||
markRuntime(trc);
|
||||
|
||||
VerifyNode *node;
|
||||
node = trc->curnode;
|
||||
@ -245,9 +245,9 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
|
||||
node = NextNode(node);
|
||||
}
|
||||
|
||||
rt->gc.verifyPreData = trc;
|
||||
rt->gc.incrementalState = MARK;
|
||||
rt->gc.marker.start();
|
||||
verifyPreData = trc;
|
||||
incrementalState = MARK;
|
||||
marker.start();
|
||||
|
||||
rt->setNeedsBarrier(true);
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
|
||||
@ -259,9 +259,9 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
|
||||
return;
|
||||
|
||||
oom:
|
||||
rt->gc.incrementalState = NO_INCREMENTAL;
|
||||
incrementalState = NO_INCREMENTAL;
|
||||
js_delete(trc);
|
||||
rt->gc.verifyPreData = nullptr;
|
||||
verifyPreData = nullptr;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -316,18 +316,18 @@ AssertMarkedOrAllocated(const EdgeValue &edge)
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
void
|
||||
gc::EndVerifyPreBarriers(JSRuntime *rt)
|
||||
bool
|
||||
gc::GCRuntime::endVerifyPreBarriers()
|
||||
{
|
||||
VerifyPreTracer *trc = (VerifyPreTracer *)verifyPreData;
|
||||
|
||||
if (!trc)
|
||||
return false;
|
||||
|
||||
JS_ASSERT(!JS::IsGenerationalGCEnabled(rt));
|
||||
|
||||
AutoPrepareForTracing prep(rt, SkipAtoms);
|
||||
|
||||
VerifyPreTracer *trc = (VerifyPreTracer *)rt->gc.verifyPreData;
|
||||
|
||||
if (!trc)
|
||||
return;
|
||||
|
||||
bool compartmentCreated = false;
|
||||
|
||||
/* We need to disable barriers before tracing, which may invoke barriers. */
|
||||
@ -344,11 +344,11 @@ gc::EndVerifyPreBarriers(JSRuntime *rt)
|
||||
* We need to bump gcNumber so that the methodjit knows that jitcode has
|
||||
* been discarded.
|
||||
*/
|
||||
JS_ASSERT(trc->number == rt->gc.number);
|
||||
rt->gc.number++;
|
||||
JS_ASSERT(trc->number == number);
|
||||
number++;
|
||||
|
||||
rt->gc.verifyPreData = nullptr;
|
||||
rt->gc.incrementalState = NO_INCREMENTAL;
|
||||
verifyPreData = nullptr;
|
||||
incrementalState = NO_INCREMENTAL;
|
||||
|
||||
if (!compartmentCreated && IsIncrementalGCSafe(rt)) {
|
||||
trc->setTraceCallback(CheckEdge);
|
||||
@ -368,10 +368,11 @@ gc::EndVerifyPreBarriers(JSRuntime *rt)
|
||||
}
|
||||
}
|
||||
|
||||
rt->gc.marker.reset();
|
||||
rt->gc.marker.stop();
|
||||
marker.reset();
|
||||
marker.stop();
|
||||
|
||||
js_delete(trc);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*** Post-Barrier Verifyier ***/
|
||||
@ -399,24 +400,24 @@ struct VerifyPostTracer : JSTracer
|
||||
* important edges were inserted into the storebuffer.
|
||||
*/
|
||||
void
|
||||
gc::StartVerifyPostBarriers(JSRuntime *rt)
|
||||
gc::GCRuntime::startVerifyPostBarriers()
|
||||
{
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (rt->gc.verifyPostData ||
|
||||
rt->gc.incrementalState != NO_INCREMENTAL)
|
||||
if (verifyPostData ||
|
||||
incrementalState != NO_INCREMENTAL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MinorGC(rt, JS::gcreason::EVICT_NURSERY);
|
||||
|
||||
rt->gc.number++;
|
||||
number++;
|
||||
|
||||
VerifyPostTracer *trc = js_new<VerifyPostTracer>(rt, JSTraceCallback(nullptr));
|
||||
if (!trc)
|
||||
return;
|
||||
|
||||
rt->gc.verifyPostData = trc;
|
||||
verifyPostData = trc;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -485,21 +486,23 @@ PostVerifierVisitEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
js::gc::EndVerifyPostBarriers(JSRuntime *rt)
|
||||
bool
|
||||
js::gc::GCRuntime::endVerifyPostBarriers()
|
||||
{
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
VerifyPostTracer *trc = (VerifyPostTracer *)verifyPostData;
|
||||
if (!trc)
|
||||
return false;
|
||||
|
||||
VerifyPostTracer::EdgeSet edges;
|
||||
AutoPrepareForTracing prep(rt, SkipAtoms);
|
||||
|
||||
VerifyPostTracer *trc = (VerifyPostTracer *)rt->gc.verifyPostData;
|
||||
|
||||
/* Visit every entry in the store buffer and put the edges in a hash set. */
|
||||
trc->setTraceCallback(PostVerifierCollectStoreBufferEdges);
|
||||
if (!edges.init())
|
||||
goto oom;
|
||||
trc->edges = &edges;
|
||||
rt->gc.storeBuffer.markAll(trc);
|
||||
storeBuffer.markAll(trc);
|
||||
|
||||
/* Walk the heap to find any edges not the the |edges| set. */
|
||||
trc->setTraceCallback(PostVerifierVisitEdge);
|
||||
@ -514,96 +517,100 @@ js::gc::EndVerifyPostBarriers(JSRuntime *rt)
|
||||
|
||||
oom:
|
||||
js_delete(trc);
|
||||
rt->gc.verifyPostData = nullptr;
|
||||
verifyPostData = nullptr;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*** Barrier Verifier Scheduling ***/
|
||||
|
||||
static void
|
||||
VerifyPreBarriers(JSRuntime *rt)
|
||||
void
|
||||
gc::GCRuntime::verifyPreBarriers()
|
||||
{
|
||||
if (rt->gc.verifyPreData)
|
||||
EndVerifyPreBarriers(rt);
|
||||
if (verifyPreData)
|
||||
endVerifyPreBarriers();
|
||||
else
|
||||
StartVerifyPreBarriers(rt);
|
||||
startVerifyPreBarriers();
|
||||
}
|
||||
|
||||
static void
|
||||
VerifyPostBarriers(JSRuntime *rt)
|
||||
void
|
||||
gc::GCRuntime::verifyPostBarriers()
|
||||
{
|
||||
if (rt->gc.verifyPostData)
|
||||
EndVerifyPostBarriers(rt);
|
||||
if (verifyPostData)
|
||||
endVerifyPostBarriers();
|
||||
else
|
||||
StartVerifyPostBarriers(rt);
|
||||
startVerifyPostBarriers();
|
||||
}
|
||||
|
||||
void
|
||||
gc::VerifyBarriers(JSRuntime *rt, VerifierType type)
|
||||
{
|
||||
if (type == PreBarrierVerifier)
|
||||
VerifyPreBarriers(rt);
|
||||
rt->gc.verifyPreBarriers();
|
||||
else
|
||||
VerifyPostBarriers(rt);
|
||||
rt->gc.verifyPostBarriers();
|
||||
}
|
||||
|
||||
static void
|
||||
MaybeVerifyPreBarriers(JSRuntime *rt, bool always)
|
||||
void
|
||||
gc::GCRuntime::maybeVerifyPreBarriers(bool always)
|
||||
{
|
||||
if (rt->gcZeal() != ZealVerifierPreValue)
|
||||
if (zealMode != ZealVerifierPreValue)
|
||||
return;
|
||||
|
||||
if (rt->mainThread.suppressGC)
|
||||
return;
|
||||
|
||||
if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gc.verifyPreData) {
|
||||
if (++trc->count < rt->gc.zealFrequency && !always)
|
||||
if (VerifyPreTracer *trc = (VerifyPreTracer *)verifyPreData) {
|
||||
if (++trc->count < zealFrequency && !always)
|
||||
return;
|
||||
|
||||
EndVerifyPreBarriers(rt);
|
||||
endVerifyPreBarriers();
|
||||
}
|
||||
|
||||
StartVerifyPreBarriers(rt);
|
||||
startVerifyPreBarriers();
|
||||
}
|
||||
|
||||
static void
|
||||
MaybeVerifyPostBarriers(JSRuntime *rt, bool always)
|
||||
void
|
||||
gc::GCRuntime::maybeVerifyPostBarriers(bool always)
|
||||
{
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (rt->gcZeal() != ZealVerifierPostValue)
|
||||
if (zealMode != ZealVerifierPostValue)
|
||||
return;
|
||||
|
||||
if (rt->mainThread.suppressGC || !rt->gc.storeBuffer.isEnabled())
|
||||
if (rt->mainThread.suppressGC || !storeBuffer.isEnabled())
|
||||
return;
|
||||
|
||||
if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gc.verifyPostData) {
|
||||
if (++trc->count < rt->gc.zealFrequency && !always)
|
||||
if (VerifyPostTracer *trc = (VerifyPostTracer *)verifyPostData) {
|
||||
if (++trc->count < zealFrequency && !always)
|
||||
return;
|
||||
|
||||
EndVerifyPostBarriers(rt);
|
||||
endVerifyPostBarriers();
|
||||
}
|
||||
StartVerifyPostBarriers(rt);
|
||||
startVerifyPostBarriers();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
js::gc::MaybeVerifyBarriers(JSContext *cx, bool always)
|
||||
{
|
||||
MaybeVerifyPreBarriers(cx->runtime(), always);
|
||||
MaybeVerifyPostBarriers(cx->runtime(), always);
|
||||
GCRuntime *gc = &cx->runtime()->gc;
|
||||
gc->maybeVerifyPreBarriers(always);
|
||||
gc->maybeVerifyPostBarriers(always);
|
||||
}
|
||||
|
||||
void
|
||||
js::gc::FinishVerifier(JSRuntime *rt)
|
||||
js::gc::GCRuntime::finishVerifier()
|
||||
{
|
||||
if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gc.verifyPreData) {
|
||||
if (VerifyPreTracer *trc = (VerifyPreTracer *)verifyPreData) {
|
||||
js_delete(trc);
|
||||
rt->gc.verifyPreData = nullptr;
|
||||
verifyPreData = nullptr;
|
||||
}
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gc.verifyPostData) {
|
||||
if (VerifyPostTracer *trc = (VerifyPostTracer *)verifyPostData) {
|
||||
js_delete(trc);
|
||||
rt->gc.verifyPostData = nullptr;
|
||||
verifyPostData = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -928,37 +928,24 @@ JS::DisableIncrementalGC(JSRuntime *rt)
|
||||
}
|
||||
|
||||
JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSRuntime *rt)
|
||||
: runtime(rt)
|
||||
: gc(&rt->gc)
|
||||
#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
|
||||
, restartVerifier(rt->gc.verifyPostData)
|
||||
, restartVerifier(false)
|
||||
#endif
|
||||
{
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (IsGenerationalGCEnabled(rt)) {
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (restartVerifier)
|
||||
gc::EndVerifyPostBarriers(rt);
|
||||
#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
|
||||
restartVerifier = gc->endVerifyPostBarriers();
|
||||
#endif
|
||||
MinorGC(rt, JS::gcreason::API);
|
||||
rt->gc.nursery.disable();
|
||||
rt->gc.storeBuffer.disable();
|
||||
}
|
||||
#endif
|
||||
++rt->gc.generationalDisabled;
|
||||
gc->disableGenerationalGC();
|
||||
}
|
||||
|
||||
JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC()
|
||||
{
|
||||
JS_ASSERT(runtime->gc.generationalDisabled > 0);
|
||||
--runtime->gc.generationalDisabled;
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (runtime->gc.generationalDisabled == 0) {
|
||||
runtime->gc.nursery.enable();
|
||||
runtime->gc.storeBuffer.enable();
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (restartVerifier)
|
||||
gc::StartVerifyPostBarriers(runtime);
|
||||
#endif
|
||||
gc->enableGenerationalGC();
|
||||
#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
|
||||
if (restartVerifier) {
|
||||
JS_ASSERT(gc->isGenerationalGCEnabled());
|
||||
gc->startVerifyPostBarriers();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -966,7 +953,7 @@ JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC()
|
||||
extern JS_FRIEND_API(bool)
|
||||
JS::IsGenerationalGCEnabled(JSRuntime *rt)
|
||||
{
|
||||
return rt->gc.generationalDisabled == 0;
|
||||
return rt->gc.isGenerationalGCEnabled();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
|
@ -1244,7 +1244,7 @@ GCRuntime::finish()
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
/* Free memory associated with GC verification. */
|
||||
FinishVerifier(rt);
|
||||
finishVerifier();
|
||||
#endif
|
||||
|
||||
/* Delete all remaining zones. */
|
||||
@ -5007,6 +5007,32 @@ GCRuntime::minorGC(JSContext *cx, JS::gcreason::Reason reason)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::disableGenerationalGC()
|
||||
{
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (isGenerationalGCEnabled()) {
|
||||
minorGC(JS::gcreason::API);
|
||||
nursery.disable();
|
||||
storeBuffer.disable();
|
||||
}
|
||||
#endif
|
||||
++rt->gc.generationalDisabled;
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::enableGenerationalGC()
|
||||
{
|
||||
JS_ASSERT(generationalDisabled > 0);
|
||||
--generationalDisabled;
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
if (generationalDisabled == 0) {
|
||||
nursery.enable();
|
||||
storeBuffer.enable();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
js::gc::GCIfNeeded(JSContext *cx)
|
||||
{
|
||||
|
@ -311,7 +311,7 @@ class ZoneCellIterUnderGC : public ZoneCellIterImpl
|
||||
}
|
||||
};
|
||||
|
||||
/* In debug builds, assert that no allocation occurs while it is live. */
|
||||
/* In debug builds, assert that no allocation occurs. */
|
||||
class AutoAssertNoAlloc
|
||||
{
|
||||
#ifdef JS_DEBUG
|
||||
@ -335,6 +335,7 @@ class AutoAssertNoAlloc
|
||||
public:
|
||||
AutoAssertNoAlloc() {}
|
||||
AutoAssertNoAlloc(JSRuntime *) {}
|
||||
void disallowAlloc(JSRuntime *rt) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user