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/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

View File

@ -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

View File

@ -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;

View File

@ -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
}

View File

@ -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)

View File

@ -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)
{

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