Bug 988486 - Move verifier functions into GCRuntime r=terrence

This commit is contained in:
Jon Coppeard 2014-05-19 11:09:55 +01:00
parent ff878c9058
commit f17bd34eff
7 changed files with 150 additions and 121 deletions

View File

@ -13,6 +13,12 @@
#include "js/RootingAPI.h" #include "js/RootingAPI.h"
#include "js/Value.h" #include "js/Value.h"
namespace js {
namespace gc {
class GCRuntime;
}
}
typedef enum JSGCMode { typedef enum JSGCMode {
/* Perform only global GCs. */ /* Perform only global GCs. */
JSGC_MODE_GLOBAL = 0, JSGC_MODE_GLOBAL = 0,
@ -329,7 +335,7 @@ WasIncrementalGC(JSRuntime *rt);
/* Ensure that generational GC is disabled within some scope. */ /* Ensure that generational GC is disabled within some scope. */
class JS_FRIEND_API(AutoDisableGenerationalGC) class JS_FRIEND_API(AutoDisableGenerationalGC)
{ {
JSRuntime *runtime; js::gc::GCRuntime *gc;
#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL) #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
bool restartVerifier; bool restartVerifier;
#endif #endif

View File

@ -91,24 +91,10 @@ IncrementalSafety
IsIncrementalGCSafe(JSRuntime *rt); IsIncrementalGCSafe(JSRuntime *rt);
#ifdef JS_GC_ZEAL #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 class AutoStopVerifyingBarriers
{ {
JSRuntime *runtime; GCRuntime *gc;
bool restartPreVerifier; bool restartPreVerifier;
bool restartPostVerifier; bool restartPostVerifier;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
@ -116,22 +102,19 @@ class AutoStopVerifyingBarriers
public: public:
AutoStopVerifyingBarriers(JSRuntime *rt, bool isShutdown AutoStopVerifyingBarriers(JSRuntime *rt, bool isShutdown
MOZ_GUARD_OBJECT_NOTIFIER_PARAM) MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: runtime(rt) : gc(&rt->gc)
{ {
restartPreVerifier = !isShutdown && rt->gc.verifyPreData; restartPreVerifier = gc->endVerifyPreBarriers() && !isShutdown;
restartPostVerifier = !isShutdown && rt->gc.verifyPostData && JS::IsGenerationalGCEnabled(rt); restartPostVerifier = gc->endVerifyPostBarriers() && !isShutdown &&
if (rt->gc.verifyPreData) JS::IsGenerationalGCEnabled(rt);
EndVerifyPreBarriers(rt);
if (rt->gc.verifyPostData)
EndVerifyPostBarriers(rt);
MOZ_GUARD_OBJECT_NOTIFIER_INIT; MOZ_GUARD_OBJECT_NOTIFIER_INIT;
} }
~AutoStopVerifyingBarriers() { ~AutoStopVerifyingBarriers() {
if (restartPreVerifier) if (restartPreVerifier)
StartVerifyPreBarriers(runtime); gc->startVerifyPreBarriers();
if (restartPostVerifier) if (restartPostVerifier)
StartVerifyPostBarriers(runtime); gc->startVerifyPostBarriers();
} }
}; };
#else #else

View File

@ -131,6 +131,13 @@ class GCRuntime
void markRuntime(JSTracer *trc, bool useSavedRoots = false); 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: public:
// Internal public interface // Internal public interface
void recordNativeStackTop(); void recordNativeStackTop();
@ -179,6 +186,18 @@ class GCRuntime
void setAlwaysPreserveCode() { alwaysPreserveCode = true; } 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: private:
// For ArenaLists::allocateFromArenaInline() // For ArenaLists::allocateFromArenaInline()
friend class ArenaLists; friend class ArenaLists;

View File

@ -169,9 +169,9 @@ NextNode(VerifyNode *node)
} }
void void
gc::StartVerifyPreBarriers(JSRuntime *rt) gc::GCRuntime::startVerifyPreBarriers()
{ {
if (rt->gc.verifyPreData || rt->gc.incrementalState != NO_INCREMENTAL) if (verifyPreData || incrementalState != NO_INCREMENTAL)
return; return;
/* /*
@ -180,7 +180,7 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
* starting the pre barrier verifier if the post barrier verifier is already * starting the pre barrier verifier if the post barrier verifier is already
* running. * running.
*/ */
if (rt->gc.verifyPostData) if (verifyPostData)
return; return;
MinorGC(rt, JS::gcreason::EVICT_NURSERY); MinorGC(rt, JS::gcreason::EVICT_NURSERY);
@ -190,10 +190,10 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
if (!IsIncrementalGCSafe(rt)) if (!IsIncrementalGCSafe(rt))
return; 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(); r.front()->bitmap.clear();
rt->gc.number++; number++;
VerifyPreTracer *trc = js_new<VerifyPreTracer>(rt, JSTraceCallback(nullptr)); VerifyPreTracer *trc = js_new<VerifyPreTracer>(rt, JSTraceCallback(nullptr));
if (!trc) if (!trc)
@ -219,10 +219,10 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
trc->curnode = MakeNode(trc, nullptr, JSGCTraceKind(0)); trc->curnode = MakeNode(trc, nullptr, JSGCTraceKind(0));
/* We want MarkRuntime to save the roots to gcSavedRoots. */ /* 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. */ /* Make all the roots be edges emanating from the root node. */
rt->gc.markRuntime(trc); markRuntime(trc);
VerifyNode *node; VerifyNode *node;
node = trc->curnode; node = trc->curnode;
@ -245,9 +245,9 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
node = NextNode(node); node = NextNode(node);
} }
rt->gc.verifyPreData = trc; verifyPreData = trc;
rt->gc.incrementalState = MARK; incrementalState = MARK;
rt->gc.marker.start(); marker.start();
rt->setNeedsBarrier(true); rt->setNeedsBarrier(true);
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
@ -259,9 +259,9 @@ gc::StartVerifyPreBarriers(JSRuntime *rt)
return; return;
oom: oom:
rt->gc.incrementalState = NO_INCREMENTAL; incrementalState = NO_INCREMENTAL;
js_delete(trc); js_delete(trc);
rt->gc.verifyPreData = nullptr; verifyPreData = nullptr;
} }
static bool static bool
@ -316,18 +316,18 @@ AssertMarkedOrAllocated(const EdgeValue &edge)
MOZ_CRASH(); MOZ_CRASH();
} }
void bool
gc::EndVerifyPreBarriers(JSRuntime *rt) gc::GCRuntime::endVerifyPreBarriers()
{ {
VerifyPreTracer *trc = (VerifyPreTracer *)verifyPreData;
if (!trc)
return false;
JS_ASSERT(!JS::IsGenerationalGCEnabled(rt)); JS_ASSERT(!JS::IsGenerationalGCEnabled(rt));
AutoPrepareForTracing prep(rt, SkipAtoms); AutoPrepareForTracing prep(rt, SkipAtoms);
VerifyPreTracer *trc = (VerifyPreTracer *)rt->gc.verifyPreData;
if (!trc)
return;
bool compartmentCreated = false; bool compartmentCreated = false;
/* We need to disable barriers before tracing, which may invoke barriers. */ /* 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 * We need to bump gcNumber so that the methodjit knows that jitcode has
* been discarded. * been discarded.
*/ */
JS_ASSERT(trc->number == rt->gc.number); JS_ASSERT(trc->number == number);
rt->gc.number++; number++;
rt->gc.verifyPreData = nullptr; verifyPreData = nullptr;
rt->gc.incrementalState = NO_INCREMENTAL; incrementalState = NO_INCREMENTAL;
if (!compartmentCreated && IsIncrementalGCSafe(rt)) { if (!compartmentCreated && IsIncrementalGCSafe(rt)) {
trc->setTraceCallback(CheckEdge); trc->setTraceCallback(CheckEdge);
@ -368,10 +368,11 @@ gc::EndVerifyPreBarriers(JSRuntime *rt)
} }
} }
rt->gc.marker.reset(); marker.reset();
rt->gc.marker.stop(); marker.stop();
js_delete(trc); js_delete(trc);
return true;
} }
/*** Post-Barrier Verifyier ***/ /*** Post-Barrier Verifyier ***/
@ -399,24 +400,24 @@ struct VerifyPostTracer : JSTracer
* important edges were inserted into the storebuffer. * important edges were inserted into the storebuffer.
*/ */
void void
gc::StartVerifyPostBarriers(JSRuntime *rt) gc::GCRuntime::startVerifyPostBarriers()
{ {
#ifdef JSGC_GENERATIONAL #ifdef JSGC_GENERATIONAL
if (rt->gc.verifyPostData || if (verifyPostData ||
rt->gc.incrementalState != NO_INCREMENTAL) incrementalState != NO_INCREMENTAL)
{ {
return; return;
} }
MinorGC(rt, JS::gcreason::EVICT_NURSERY); MinorGC(rt, JS::gcreason::EVICT_NURSERY);
rt->gc.number++; number++;
VerifyPostTracer *trc = js_new<VerifyPostTracer>(rt, JSTraceCallback(nullptr)); VerifyPostTracer *trc = js_new<VerifyPostTracer>(rt, JSTraceCallback(nullptr));
if (!trc) if (!trc)
return; return;
rt->gc.verifyPostData = trc; verifyPostData = trc;
#endif #endif
} }
@ -485,21 +486,23 @@ PostVerifierVisitEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
} }
#endif #endif
void bool
js::gc::EndVerifyPostBarriers(JSRuntime *rt) js::gc::GCRuntime::endVerifyPostBarriers()
{ {
#ifdef JSGC_GENERATIONAL #ifdef JSGC_GENERATIONAL
VerifyPostTracer *trc = (VerifyPostTracer *)verifyPostData;
if (!trc)
return false;
VerifyPostTracer::EdgeSet edges; VerifyPostTracer::EdgeSet edges;
AutoPrepareForTracing prep(rt, SkipAtoms); 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. */ /* Visit every entry in the store buffer and put the edges in a hash set. */
trc->setTraceCallback(PostVerifierCollectStoreBufferEdges); trc->setTraceCallback(PostVerifierCollectStoreBufferEdges);
if (!edges.init()) if (!edges.init())
goto oom; goto oom;
trc->edges = &edges; trc->edges = &edges;
rt->gc.storeBuffer.markAll(trc); storeBuffer.markAll(trc);
/* Walk the heap to find any edges not the the |edges| set. */ /* Walk the heap to find any edges not the the |edges| set. */
trc->setTraceCallback(PostVerifierVisitEdge); trc->setTraceCallback(PostVerifierVisitEdge);
@ -514,96 +517,100 @@ js::gc::EndVerifyPostBarriers(JSRuntime *rt)
oom: oom:
js_delete(trc); js_delete(trc);
rt->gc.verifyPostData = nullptr; verifyPostData = nullptr;
return true;
#else
return false;
#endif #endif
} }
/*** Barrier Verifier Scheduling ***/ /*** Barrier Verifier Scheduling ***/
static void void
VerifyPreBarriers(JSRuntime *rt) gc::GCRuntime::verifyPreBarriers()
{ {
if (rt->gc.verifyPreData) if (verifyPreData)
EndVerifyPreBarriers(rt); endVerifyPreBarriers();
else else
StartVerifyPreBarriers(rt); startVerifyPreBarriers();
} }
static void void
VerifyPostBarriers(JSRuntime *rt) gc::GCRuntime::verifyPostBarriers()
{ {
if (rt->gc.verifyPostData) if (verifyPostData)
EndVerifyPostBarriers(rt); endVerifyPostBarriers();
else else
StartVerifyPostBarriers(rt); startVerifyPostBarriers();
} }
void void
gc::VerifyBarriers(JSRuntime *rt, VerifierType type) gc::VerifyBarriers(JSRuntime *rt, VerifierType type)
{ {
if (type == PreBarrierVerifier) if (type == PreBarrierVerifier)
VerifyPreBarriers(rt); rt->gc.verifyPreBarriers();
else else
VerifyPostBarriers(rt); rt->gc.verifyPostBarriers();
} }
static void void
MaybeVerifyPreBarriers(JSRuntime *rt, bool always) gc::GCRuntime::maybeVerifyPreBarriers(bool always)
{ {
if (rt->gcZeal() != ZealVerifierPreValue) if (zealMode != ZealVerifierPreValue)
return; return;
if (rt->mainThread.suppressGC) if (rt->mainThread.suppressGC)
return; return;
if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gc.verifyPreData) { if (VerifyPreTracer *trc = (VerifyPreTracer *)verifyPreData) {
if (++trc->count < rt->gc.zealFrequency && !always) if (++trc->count < zealFrequency && !always)
return; return;
EndVerifyPreBarriers(rt); endVerifyPreBarriers();
} }
StartVerifyPreBarriers(rt); startVerifyPreBarriers();
} }
static void void
MaybeVerifyPostBarriers(JSRuntime *rt, bool always) gc::GCRuntime::maybeVerifyPostBarriers(bool always)
{ {
#ifdef JSGC_GENERATIONAL #ifdef JSGC_GENERATIONAL
if (rt->gcZeal() != ZealVerifierPostValue) if (zealMode != ZealVerifierPostValue)
return; return;
if (rt->mainThread.suppressGC || !rt->gc.storeBuffer.isEnabled()) if (rt->mainThread.suppressGC || !storeBuffer.isEnabled())
return; return;
if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gc.verifyPostData) { if (VerifyPostTracer *trc = (VerifyPostTracer *)verifyPostData) {
if (++trc->count < rt->gc.zealFrequency && !always) if (++trc->count < zealFrequency && !always)
return; return;
EndVerifyPostBarriers(rt); endVerifyPostBarriers();
} }
StartVerifyPostBarriers(rt); startVerifyPostBarriers();
#endif #endif
} }
void void
js::gc::MaybeVerifyBarriers(JSContext *cx, bool always) js::gc::MaybeVerifyBarriers(JSContext *cx, bool always)
{ {
MaybeVerifyPreBarriers(cx->runtime(), always); GCRuntime *gc = &cx->runtime()->gc;
MaybeVerifyPostBarriers(cx->runtime(), always); gc->maybeVerifyPreBarriers(always);
gc->maybeVerifyPostBarriers(always);
} }
void 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); js_delete(trc);
rt->gc.verifyPreData = nullptr; verifyPreData = nullptr;
} }
#ifdef JSGC_GENERATIONAL #ifdef JSGC_GENERATIONAL
if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gc.verifyPostData) { if (VerifyPostTracer *trc = (VerifyPostTracer *)verifyPostData) {
js_delete(trc); js_delete(trc);
rt->gc.verifyPostData = nullptr; verifyPostData = nullptr;
} }
#endif #endif
} }

View File

@ -928,37 +928,24 @@ JS::DisableIncrementalGC(JSRuntime *rt)
} }
JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSRuntime *rt) JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSRuntime *rt)
: runtime(rt) : gc(&rt->gc)
#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL) #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
, restartVerifier(rt->gc.verifyPostData) , restartVerifier(false)
#endif #endif
{ {
#ifdef JSGC_GENERATIONAL #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
if (IsGenerationalGCEnabled(rt)) { restartVerifier = gc->endVerifyPostBarriers();
#ifdef JS_GC_ZEAL
if (restartVerifier)
gc::EndVerifyPostBarriers(rt);
#endif #endif
MinorGC(rt, JS::gcreason::API); gc->disableGenerationalGC();
rt->gc.nursery.disable();
rt->gc.storeBuffer.disable();
}
#endif
++rt->gc.generationalDisabled;
} }
JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC() JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC()
{ {
JS_ASSERT(runtime->gc.generationalDisabled > 0); gc->enableGenerationalGC();
--runtime->gc.generationalDisabled; #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
#ifdef JSGC_GENERATIONAL if (restartVerifier) {
if (runtime->gc.generationalDisabled == 0) { JS_ASSERT(gc->isGenerationalGCEnabled());
runtime->gc.nursery.enable(); gc->startVerifyPostBarriers();
runtime->gc.storeBuffer.enable();
#ifdef JS_GC_ZEAL
if (restartVerifier)
gc::StartVerifyPostBarriers(runtime);
#endif
} }
#endif #endif
} }
@ -966,7 +953,7 @@ JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC()
extern JS_FRIEND_API(bool) extern JS_FRIEND_API(bool)
JS::IsGenerationalGCEnabled(JSRuntime *rt) JS::IsGenerationalGCEnabled(JSRuntime *rt)
{ {
return rt->gc.generationalDisabled == 0; return rt->gc.isGenerationalGCEnabled();
} }
JS_FRIEND_API(bool) JS_FRIEND_API(bool)

View File

@ -1244,7 +1244,7 @@ GCRuntime::finish()
#ifdef JS_GC_ZEAL #ifdef JS_GC_ZEAL
/* Free memory associated with GC verification. */ /* Free memory associated with GC verification. */
FinishVerifier(rt); finishVerifier();
#endif #endif
/* Delete all remaining zones. */ /* Delete all remaining zones. */
@ -5007,6 +5007,32 @@ GCRuntime::minorGC(JSContext *cx, JS::gcreason::Reason reason)
#endif #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 void
js::gc::GCIfNeeded(JSContext *cx) js::gc::GCIfNeeded(JSContext *cx)
{ {

View File

@ -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 class AutoAssertNoAlloc
{ {
#ifdef JS_DEBUG #ifdef JS_DEBUG
@ -335,6 +335,7 @@ class AutoAssertNoAlloc
public: public:
AutoAssertNoAlloc() {} AutoAssertNoAlloc() {}
AutoAssertNoAlloc(JSRuntime *) {} AutoAssertNoAlloc(JSRuntime *) {}
void disallowAlloc(JSRuntime *rt) {}
#endif #endif
}; };