Bug 737364 - part 1 - stop using the cx in the GC implementation

This part removes JSContext::gcBackgroundFree, moves all mark-related
cleanup code to run right after the marking is done for clear mark/sweep
separation and eliminates all JSContext references in the GC
implementation. That allowed to remove a wait for the bakground
finalization to finish in js_DestroyContext. As a followup for the bug
737365 the patch also replaces in few cases the JSContext argument with
FreeOp in infallible code that only free/destroy things.
This commit is contained in:
Igor Bukanov 2012-03-25 09:48:45 +02:00
parent 5ed6f42383
commit f16ca3a2a1
13 changed files with 153 additions and 217 deletions

View File

@ -234,7 +234,7 @@ VerifyBarriers(JSContext *cx, unsigned argc, jsval *vp)
ReportUsageError(cx, &JS_CALLEE(cx, vp).toObject(), "Too many arguments");
return JS_FALSE;
}
gc::VerifyBarriers(cx);
gc::VerifyBarriers(cx->runtime);
*vp = JSVAL_VOID;
return JS_TRUE;
}
@ -469,7 +469,6 @@ MJitCodeStats(JSContext *cx, unsigned argc, jsval *vp)
{
#ifdef JS_METHODJIT
JSRuntime *rt = cx->runtime;
AutoLockGC lock(rt);
size_t n = 0;
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
n += (*c)->sizeOfMjitCode();

View File

@ -245,8 +245,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
* JSCONTEXT_DESTROY callback is not allowed to fail and must
* return true.
*/
DebugOnly<JSBool> callbackStatus = cxCallback(cx, JSCONTEXT_DESTROY);
JS_ASSERT(callbackStatus);
JS_ALWAYS_TRUE(cxCallback(cx, JSCONTEXT_DESTROY));
}
}
@ -255,13 +254,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
if (last) {
JS_ASSERT(!rt->gcRunning);
#ifdef JS_THREADSAFE
{
AutoLockGC lock(rt);
rt->gcHelperThread.waitBackgroundSweepEnd();
}
#endif
/*
* Dump remaining type inference results first. This printing
* depends on atoms still existing.
@ -270,11 +262,11 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
c->types.print(cx, false);
/* Unpin all common atoms before final GC. */
FinishCommonAtoms(cx->runtime);
FinishCommonAtoms(rt);
/* Clear debugging state to remove GC roots. */
for (CompartmentsIter c(rt); !c.done(); c.next())
c->clearTraps(cx);
c->clearTraps(rt->defaultFreeOp());
JS_ClearAllWatchPoints(cx);
PrepareForFullGC(rt);
@ -288,12 +280,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
JS_MaybeGC(cx);
}
#ifdef JS_THREADSAFE
{
AutoLockGC lock(rt);
rt->gcHelperThread.waitBackgroundSweepEnd();
}
#endif
Foreground::delete_(cx);
}
@ -990,9 +976,6 @@ JSContext::JSContext(JSRuntime *rt)
functionCallback(NULL),
#endif
enumerators(NULL),
#ifdef JS_THREADSAFE
gcBackgroundFree(NULL),
#endif
activeCompilations(0)
#ifdef DEBUG
, stackIterAssertionEnabled(true)

View File

@ -1126,14 +1126,6 @@ struct JSContext : js::ContextFriendFields
genStack.popBack();
}
#ifdef JS_THREADSAFE
/*
* When non-null JSContext::free_ delegates the job to the background
* thread.
*/
js::GCHelperThread *gcBackgroundFree;
#endif
inline void* malloc_(size_t bytes) {
return runtime->malloc_(bytes, this);
}
@ -1157,12 +1149,6 @@ struct JSContext : js::ContextFriendFields
}
inline void free_(void* p) {
#ifdef JS_THREADSAFE
if (gcBackgroundFree) {
gcBackgroundFree->freeLater(p);
return;
}
#endif
runtime->free_(p);
}

View File

@ -746,22 +746,22 @@ JSCompartment::removeDebuggee(FreeOp *fop,
}
void
JSCompartment::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler)
JSCompartment::clearBreakpointsIn(FreeOp *fop, js::Debugger *dbg, JSObject *handler)
{
for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
if (script->hasAnyBreakpointsOrStepMode())
script->clearBreakpointsIn(cx, dbg, handler);
script->clearBreakpointsIn(fop, dbg, handler);
}
}
void
JSCompartment::clearTraps(JSContext *cx)
JSCompartment::clearTraps(FreeOp *fop)
{
for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
if (script->hasAnyBreakpointsOrStepMode())
script->clearTraps(cx->runtime->defaultFreeOp());
script->clearTraps(fop);
}
}

View File

@ -455,8 +455,8 @@ struct JSCompartment
js::GlobalObjectSet::Enum *debuggeesEnum = NULL);
bool setDebugModeFromC(JSContext *cx, bool b);
void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler);
void clearTraps(JSContext *cx);
void clearBreakpointsIn(js::FreeOp *fop, js::Debugger *dbg, JSObject *handler);
void clearTraps(js::FreeOp *fop);
private:
void sweepBreakpoints(js::FreeOp *fop);

View File

@ -231,7 +231,7 @@ JS_ClearScriptTraps(JSContext *cx, JSScript *script)
JS_PUBLIC_API(void)
JS_ClearAllTrapsForCompartment(JSContext *cx)
{
cx->compartment->clearTraps(cx);
cx->compartment->clearTraps(cx->runtime->defaultFreeOp());
}
JS_PUBLIC_API(JSBool)

View File

@ -751,7 +751,7 @@ NotifyDidPaint(JSContext *cx)
JSRuntime *rt = cx->runtime;
if (rt->gcZeal() == gc::ZealFrameVerifierValue) {
gc::VerifyBarriers(cx);
gc::VerifyBarriers(rt);
return;
}

View File

@ -157,10 +157,10 @@ static const uint64_t GC_IDLE_FULL_SPAN = 20 * 1000 * 1000;
#ifdef JS_GC_ZEAL
static void
StartVerifyBarriers(JSContext *cx);
StartVerifyBarriers(JSRuntime *rt);
static void
EndVerifyBarriers(JSContext *cx);
EndVerifyBarriers(JSRuntime *rt);
void
FinishVerifier(JSRuntime *rt);
@ -2200,7 +2200,7 @@ AutoGCRooter::trace(JSTracer *trc)
case SHAPEVECTOR: {
AutoShapeVector::VectorImpl &vector = static_cast<js::AutoShapeVector *>(this)->vector;
MarkShapeRootRange(trc, vector.length(), const_cast<Shape **>(vector.begin()),
MarkShapeRootRange(trc, vector.length(), const_cast<Shape **>(vector.begin()),
"js::AutoShapeVector.vector");
return;
}
@ -2697,13 +2697,12 @@ GCHelperThread::prepareForBackgroundSweep()
/* Must be called with the GC lock taken. */
void
GCHelperThread::startBackgroundSweep(JSContext *cx, bool shouldShrink)
GCHelperThread::startBackgroundSweep(bool shouldShrink)
{
/* The caller takes the GC lock. */
JS_ASSERT(state == IDLE);
JS_ASSERT(cx);
JS_ASSERT(!finalizationContext);
finalizationContext = cx;
JS_ASSERT(!sweepFlag);
sweepFlag = true;
shrinkFlag = shouldShrink;
state = SWEEPING;
PR_NotifyCondVar(wakeup);
@ -2715,7 +2714,7 @@ GCHelperThread::startBackgroundShrink()
{
switch (state) {
case IDLE:
JS_ASSERT(!finalizationContext);
JS_ASSERT(!sweepFlag);
shrinkFlag = true;
state = SWEEPING;
PR_NotifyCondVar(wakeup);
@ -2786,8 +2785,8 @@ GCHelperThread::replenishAndFreeLater(void *ptr)
void
GCHelperThread::doSweep()
{
if (finalizationContext) {
finalizationContext = NULL;
if (sweepFlag) {
sweepFlag = false;
AutoUnlockGC unlock(rt);
/*
@ -2900,6 +2899,18 @@ PurgeRuntime(JSTracer *trc)
static void
BeginMarkPhase(JSRuntime *rt)
{
rt->gcMarker.start(rt);
JS_ASSERT(!rt->gcMarker.callback);
JS_ASSERT(IS_GC_MARKING_TRACER(&rt->gcMarker));
/* For non-incremental GC the following sweep discards the jit code. */
if (rt->gcIncrementalState != NO_INCREMENTAL) {
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE);
c->discardJitCode(rt->defaultFreeOp());
}
}
GCMarker *gcmarker = &rt->gcMarker;
rt->gcStartNumber = rt->gcNumber;
@ -2970,14 +2981,12 @@ MarkGrayAndWeak(JSRuntime *rt)
#ifdef DEBUG
static void
ValidateIncrementalMarking(JSContext *cx);
ValidateIncrementalMarking(JSRuntime *rt);
#endif
static void
EndMarkPhase(JSContext *cx)
EndMarkPhase(JSRuntime *rt)
{
JSRuntime *rt = cx->runtime;
{
gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_MARK);
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_MARK_OTHER);
@ -2988,7 +2997,7 @@ EndMarkPhase(JSContext *cx)
#ifdef DEBUG
if (rt->gcIncrementalState != NO_INCREMENTAL)
ValidateIncrementalMarking(cx);
ValidateIncrementalMarking(rt);
#endif
#ifdef DEBUG
@ -2998,18 +3007,21 @@ EndMarkPhase(JSContext *cx)
c->arenas.checkArenaListAllUnmarked());
}
#endif
rt->gcMarker.stop();
/* We do not discard JIT here code as the following sweeping does that. */
}
#ifdef DEBUG
static void
ValidateIncrementalMarking(JSContext *cx)
ValidateIncrementalMarking(JSRuntime *rt)
{
typedef HashMap<Chunk *, uintptr_t *, GCChunkHasher, SystemAllocPolicy> BitmapMap;
BitmapMap map;
if (!map.init())
return;
JSRuntime *rt = cx->runtime;
GCMarker *gcmarker = &rt->gcMarker;
/* Save existing mark bits. */
@ -3095,10 +3107,8 @@ ValidateIncrementalMarking(JSContext *cx)
#endif
static void
SweepPhase(JSContext *cx, JSGCInvocationKind gckind)
SweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool *startBackgroundSweep)
{
JSRuntime *rt = cx->runtime;
/*
* Sweep phase.
*
@ -3116,19 +3126,16 @@ SweepPhase(JSContext *cx, JSGCInvocationKind gckind)
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP);
#ifdef JS_THREADSAFE
if (rt->hasContexts() && rt->gcHelperThread.prepareForBackgroundSweep())
cx->gcBackgroundFree = &rt->gcHelperThread;
*startBackgroundSweep = (rt->hasContexts() && rt->gcHelperThread.prepareForBackgroundSweep());
#else
*startBackgroundSweep = false;
#endif
/* Purge the ArenaLists before sweeping. */
for (GCCompartmentsIter c(rt); !c.done(); c.next())
c->arenas.purge();
#ifdef JS_THREADSAFE
FreeOp fop(rt, !!cx->gcBackgroundFree, false);
#else
FreeOp fop(rt, false, false);
#endif
FreeOp fop(rt, *startBackgroundSweep, false);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_FINALIZE_START);
if (rt->gcFinalizeCallback)
@ -3225,27 +3232,17 @@ SweepPhase(JSContext *cx, JSGCInvocationKind gckind)
c->setGCLastBytes(c->gcBytes, c->gcMallocAndFreeBytes, gckind);
}
/* Perform mark-and-sweep GC. If comp is set, we perform a single-compartment GC. */
static void
MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind)
NonIncrementalMark(JSRuntime *rt, JSGCInvocationKind gckind)
{
JSRuntime *rt = cx->runtime;
AutoUnlockGC unlock(rt);
rt->gcMarker.start(rt);
JS_ASSERT(!rt->gcMarker.callback);
JS_ASSERT(rt->gcIncrementalState == NO_INCREMENTAL);
BeginMarkPhase(rt);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK);
SliceBudget budget;
rt->gcMarker.drainMarkStack(budget);
}
EndMarkPhase(cx);
SweepPhase(cx, gckind);
rt->gcMarker.stop();
EndMarkPhase(rt);
}
/*
@ -3345,18 +3342,16 @@ ResetIncrementalGC(JSRuntime *rt, const char *reason)
class AutoGCSlice {
public:
AutoGCSlice(JSContext *cx);
AutoGCSlice(JSRuntime *rt);
~AutoGCSlice();
private:
JSContext *context;
JSRuntime *runtime;
};
AutoGCSlice::AutoGCSlice(JSContext *cx)
: context(cx)
AutoGCSlice::AutoGCSlice(JSRuntime *rt)
: runtime(rt)
{
JSRuntime *rt = context->runtime;
/*
* During incremental GC, the compartment's active flag determines whether
* there are stack frames active for any of its scripts. Normally this flag
@ -3376,14 +3371,12 @@ AutoGCSlice::AutoGCSlice(JSContext *cx)
AutoGCSlice::~AutoGCSlice()
{
JSRuntime *rt = context->runtime;
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
if (rt->gcIncrementalState == MARK) {
for (GCCompartmentsIter c(runtime); !c.done(); c.next()) {
if (runtime->gcIncrementalState == MARK) {
c->needsBarrier_ = true;
c->arenas.prepareForIncrementalGC(rt);
c->arenas.prepareForIncrementalGC(runtime);
} else {
JS_ASSERT(rt->gcIncrementalState == NO_INCREMENTAL);
JS_ASSERT(runtime->gcIncrementalState == NO_INCREMENTAL);
c->needsBarrier_ = false;
}
}
@ -3406,12 +3399,9 @@ class AutoCopyFreeListToArenas {
};
static void
IncrementalGCSlice(JSContext *cx, int64_t budget, JSGCInvocationKind gckind)
IncrementalMarkSlice(JSRuntime *rt, int64_t budget, JSGCInvocationKind gckind, bool *shouldSweep)
{
JSRuntime *rt = cx->runtime;
AutoUnlockGC unlock(rt);
AutoGCSlice slice(cx);
AutoGCSlice slice(rt);
gc::State initialState = rt->gcIncrementalState;
@ -3421,19 +3411,11 @@ IncrementalGCSlice(JSContext *cx, int64_t budget, JSGCInvocationKind gckind)
}
if (rt->gcIncrementalState == MARK_ROOTS) {
rt->gcMarker.start(rt);
JS_ASSERT(IS_GC_MARKING_TRACER(&rt->gcMarker));
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE);
c->discardJitCode(rt->defaultFreeOp());
}
BeginMarkPhase(rt);
rt->gcIncrementalState = MARK;
}
*shouldSweep = false;
if (rt->gcIncrementalState == MARK) {
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK);
SliceBudget sliceBudget(budget);
@ -3453,26 +3435,17 @@ IncrementalGCSlice(JSContext *cx, int64_t budget, JSGCInvocationKind gckind)
#endif
bool finished = rt->gcMarker.drainMarkStack(sliceBudget);
if (finished) {
JS_ASSERT(rt->gcMarker.isDrained());
if (initialState == MARK && !rt->gcLastMarkSlice && budget != SliceBudget::Unlimited)
if (initialState == MARK && !rt->gcLastMarkSlice && budget != SliceBudget::Unlimited) {
rt->gcLastMarkSlice = true;
else
rt->gcIncrementalState = SWEEP;
} else {
EndMarkPhase(rt);
rt->gcIncrementalState = NO_INCREMENTAL;
*shouldSweep = true;
}
}
}
if (rt->gcIncrementalState == SWEEP) {
EndMarkPhase(cx);
SweepPhase(cx, gckind);
rt->gcMarker.stop();
/* JIT code was already discarded during sweeping. */
rt->gcIncrementalState = NO_INCREMENTAL;
}
}
class IncrementalSafety
@ -3561,10 +3534,8 @@ BudgetIncrementalGC(JSRuntime *rt, int64_t *budget)
* the marking implementation.
*/
static JS_NEVER_INLINE void
GCCycle(JSContext *cx, bool incremental, int64_t budget, JSGCInvocationKind gckind)
GCCycle(JSRuntime *rt, bool incremental, int64_t budget, JSGCInvocationKind gckind)
{
JSRuntime *rt = cx->runtime;
#ifdef DEBUG
for (CompartmentsIter c(rt); !c.done(); c.next())
JS_ASSERT_IF(rt->gcMode == JSGC_MODE_GLOBAL, c->isGCScheduled());
@ -3574,12 +3545,13 @@ GCCycle(JSContext *cx, bool incremental, int64_t budget, JSGCInvocationKind gcki
if (rt->gcRunning)
return;
AutoGCSession gcsession(rt);
/* Don't GC if we are reporting an OOM. */
if (rt->inOOMReport)
return;
AutoLockGC lock(rt);
AutoGCSession gcsession(rt);
#ifdef JS_THREADSAFE
/*
* As we about to purge caches and clear the mark bits we must wait for
@ -3589,41 +3561,45 @@ GCCycle(JSContext *cx, bool incremental, int64_t budget, JSGCInvocationKind gcki
*/
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
JS_ASSERT(!cx->gcBackgroundFree);
rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
}
#endif
if (!incremental) {
/* If non-incremental GC was requested, reset incremental GC. */
ResetIncrementalGC(rt, "requested");
rt->gcStats.nonincremental("requested");
} else {
BudgetIncrementalGC(rt, &budget);
}
bool startBackgroundSweep = false;
{
AutoUnlockGC unlock(rt);
AutoCopyFreeListToArenas copy(rt);
if (!incremental) {
/* If non-incremental GC was requested, reset incremental GC. */
ResetIncrementalGC(rt, "requested");
rt->gcStats.nonincremental("requested");
} else {
BudgetIncrementalGC(rt, &budget);
}
if (budget == SliceBudget::Unlimited && rt->gcIncrementalState == NO_INCREMENTAL)
MarkAndSweep(cx, gckind);
else
IncrementalGCSlice(cx, budget, gckind);
AutoCopyFreeListToArenas copy(rt);
bool shouldSweep;
if (budget == SliceBudget::Unlimited && rt->gcIncrementalState == NO_INCREMENTAL) {
NonIncrementalMark(rt, gckind);
shouldSweep = true;
} else {
IncrementalMarkSlice(rt, budget, gckind, &shouldSweep);
}
#ifdef DEBUG
if (rt->gcIncrementalState == NO_INCREMENTAL) {
for (CompartmentsIter c(rt); !c.done(); c.next())
JS_ASSERT(!c->needsBarrier_);
}
#endif
#ifdef JS_THREADSAFE
if (rt->gcIncrementalState == NO_INCREMENTAL) {
if (cx->gcBackgroundFree) {
JS_ASSERT(cx->gcBackgroundFree == &rt->gcHelperThread);
cx->gcBackgroundFree = NULL;
rt->gcHelperThread.startBackgroundSweep(cx, gckind == GC_SHRINK);
if (rt->gcIncrementalState == NO_INCREMENTAL) {
for (CompartmentsIter c(rt); !c.done(); c.next())
JS_ASSERT(!c->needsBarrier_);
}
#endif
if (shouldSweep)
SweepPhase(rt, gckind, &startBackgroundSweep);
}
#ifdef JS_THREADSAFE
if (startBackgroundSweep)
rt->gcHelperThread.startBackgroundSweep(gckind == GC_SHRINK);
#endif
}
@ -3642,10 +3618,9 @@ IsDeterministicGCReason(gcreason::Reason reason)
#endif
static void
Collect(JSContext *cx, bool incremental, int64_t budget,
Collect(JSRuntime *rt, bool incremental, int64_t budget,
JSGCInvocationKind gckind, gcreason::Reason reason)
{
JSRuntime *rt = cx->runtime;
JS_AbortIfWrongThread(rt);
#ifdef JS_GC_ZEAL
@ -3656,24 +3631,24 @@ Collect(JSContext *cx, bool incremental, int64_t budget,
JS_ASSERT_IF(!incremental || budget != SliceBudget::Unlimited, JSGC_INCREMENTAL);
#ifdef JS_GC_ZEAL
bool restartVerify = cx->runtime->gcVerifyData &&
cx->runtime->gcZeal() == ZealVerifierValue &&
bool restartVerify = rt->gcVerifyData &&
rt->gcZeal() == ZealVerifierValue &&
reason != gcreason::CC_FORCED;
struct AutoVerifyBarriers {
JSContext *cx;
JSRuntime *runtime;
bool restart;
AutoVerifyBarriers(JSContext *cx, bool restart)
: cx(cx), restart(restart)
AutoVerifyBarriers(JSRuntime *rt, bool restart)
: runtime(rt), restart(restart)
{
if (cx->runtime->gcVerifyData)
EndVerifyBarriers(cx);
if (rt->gcVerifyData)
EndVerifyBarriers(rt);
}
~AutoVerifyBarriers() {
if (restart)
StartVerifyBarriers(cx);
StartVerifyBarriers(runtime);
}
} av(cx, restartVerify);
} av(rt, restartVerify);
#endif
RecordNativeStackTopForGC(rt);
@ -3707,10 +3682,8 @@ Collect(JSContext *cx, bool incremental, int64_t budget,
}
{
/* Lock out other GC allocator and collector invocations. */
AutoLockGC lock(rt);
rt->gcPoke = false;
GCCycle(cx, incremental, budget, gckind);
GCCycle(rt, incremental, budget, gckind);
}
if (rt->gcIncrementalState == NO_INCREMENTAL) {
@ -3731,13 +3704,13 @@ namespace js {
void
GC(JSContext *cx, JSGCInvocationKind gckind, gcreason::Reason reason)
{
Collect(cx, false, SliceBudget::Unlimited, gckind, reason);
Collect(cx->runtime, false, SliceBudget::Unlimited, gckind, reason);
}
void
GCSlice(JSContext *cx, JSGCInvocationKind gckind, gcreason::Reason reason)
{
Collect(cx, true, cx->runtime->gcSliceBudget, gckind, reason);
Collect(cx->runtime, true, cx->runtime->gcSliceBudget, gckind, reason);
}
void
@ -3745,7 +3718,7 @@ GCDebugSlice(JSContext *cx, bool limit, int64_t objCount)
{
int64_t budget = limit ? SliceBudget::WorkBudget(objCount) : SliceBudget::Unlimited;
PrepareForDebugGC(cx->runtime);
Collect(cx, true, budget, GC_NORMAL, gcreason::API);
Collect(cx->runtime, true, budget, GC_NORMAL, gcreason::API);
}
/* Schedule a full GC unless a compartment will already be collected. */
@ -4170,10 +4143,8 @@ NextNode(VerifyNode *node)
}
static void
StartVerifyBarriers(JSContext *cx)
StartVerifyBarriers(JSRuntime *rt)
{
JSRuntime *rt = cx->runtime;
if (rt->gcVerifyData || rt->gcIncrementalState != NO_INCREMENTAL)
return;
@ -4317,10 +4288,8 @@ CheckReachable(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
}
static void
EndVerifyBarriers(JSContext *cx)
EndVerifyBarriers(JSRuntime *rt)
{
JSRuntime *rt = cx->runtime;
AutoLockGC lock(rt);
AutoHeapSession session(rt);
@ -4409,48 +4378,48 @@ FinishVerifier(JSRuntime *rt)
}
void
VerifyBarriers(JSContext *cx)
VerifyBarriers(JSRuntime *rt)
{
JSRuntime *rt = cx->runtime;
if (rt->gcVerifyData)
EndVerifyBarriers(cx);
EndVerifyBarriers(rt);
else
StartVerifyBarriers(cx);
StartVerifyBarriers(rt);
}
void
MaybeVerifyBarriers(JSContext *cx, bool always)
{
if (cx->runtime->gcZeal() != ZealVerifierValue) {
if (cx->runtime->gcVerifyData)
EndVerifyBarriers(cx);
JSRuntime *rt = cx->runtime;
if (rt->gcZeal() != ZealVerifierValue) {
if (rt->gcVerifyData)
EndVerifyBarriers(rt);
return;
}
uint32_t freq = cx->runtime->gcZealFrequency;
uint32_t freq = rt->gcZealFrequency;
JSRuntime *rt = cx->runtime;
if (VerifyTracer *trc = (VerifyTracer *)rt->gcVerifyData) {
if (++trc->count < freq && !always)
return;
EndVerifyBarriers(cx);
EndVerifyBarriers(rt);
}
StartVerifyBarriers(cx);
StartVerifyBarriers(rt);
}
#endif /* JS_GC_ZEAL */
} /* namespace gc */
static void ReleaseAllJITCode(JSContext *cx)
static void ReleaseAllJITCode(FreeOp *fop)
{
#ifdef JS_METHODJIT
for (GCCompartmentsIter c(cx->runtime); !c.done(); c.next()) {
for (GCCompartmentsIter c(fop->runtime()); !c.done(); c.next()) {
mjit::ClearAllFrames(c);
for (CellIter i(c, FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), script);
mjit::ReleaseScriptCode(fop, script);
}
}
#endif
@ -4481,17 +4450,17 @@ static void ReleaseAllJITCode(JSContext *cx)
*/
static void
ReleaseScriptCounts(JSContext *cx)
ReleaseScriptCounts(FreeOp *fop)
{
JSRuntime *rt = cx->runtime;
JSRuntime *rt = fop->runtime();
JS_ASSERT(rt->scriptAndCountsVector);
ScriptAndCountsVector &vec = *rt->scriptAndCountsVector;
for (size_t i = 0; i < vec.length(); i++)
vec[i].scriptCounts.destroy(cx);
vec[i].scriptCounts.destroy(fop);
cx->delete_(rt->scriptAndCountsVector);
fop->delete_(rt->scriptAndCountsVector);
rt->scriptAndCountsVector = NULL;
}
@ -4504,9 +4473,9 @@ StartPCCountProfiling(JSContext *cx)
return;
if (rt->scriptAndCountsVector)
ReleaseScriptCounts(cx);
ReleaseScriptCounts(rt->defaultFreeOp());
ReleaseAllJITCode(cx);
ReleaseAllJITCode(rt->defaultFreeOp());
rt->profilingScripts = true;
}
@ -4520,7 +4489,7 @@ StopPCCountProfiling(JSContext *cx)
return;
JS_ASSERT(!rt->scriptAndCountsVector);
ReleaseAllJITCode(cx);
ReleaseAllJITCode(rt->defaultFreeOp());
ScriptAndCountsVector *vec = cx->new_<ScriptAndCountsVector>(SystemAllocPolicy());
if (!vec)
@ -4534,7 +4503,7 @@ StopPCCountProfiling(JSContext *cx)
info.script = script;
info.scriptCounts.steal(script->scriptCounts);
if (!vec->append(info))
info.scriptCounts.destroy(cx);
info.scriptCounts.destroy(rt->defaultFreeOp());
}
}
}
@ -4552,7 +4521,7 @@ PurgePCCounts(JSContext *cx)
return;
JS_ASSERT(!rt->profilingScripts);
ReleaseScriptCounts(cx);
ReleaseScriptCounts(rt->defaultFreeOp());
}
} /* namespace js */

View File

@ -84,7 +84,6 @@ enum State {
NO_INCREMENTAL,
MARK_ROOTS,
MARK,
SWEEP,
INVALID
};
@ -1446,7 +1445,7 @@ class GCHelperThread {
PRCondVar *done;
volatile State state;
JSContext *finalizationContext;
bool sweepFlag;
bool shrinkFlag;
Vector<void **, 16, js::SystemAllocPolicy> freeVector;
@ -1482,7 +1481,7 @@ class GCHelperThread {
wakeup(NULL),
done(NULL),
state(IDLE),
finalizationContext(NULL),
sweepFlag(false),
shrinkFlag(false),
freeCursor(NULL),
freeCursorEnd(NULL),
@ -1493,7 +1492,7 @@ class GCHelperThread {
void finish();
/* Must be called with the GC lock taken. */
void startBackgroundSweep(JSContext *cx, bool shouldShrink);
void startBackgroundSweep(bool shouldShrink);
/* Must be called with the GC lock taken. */
void startBackgroundShrink();
@ -1994,7 +1993,7 @@ const int ZealFrameVerifierValue = 5;
/* Check that write barriers have been used correctly. See jsgc.cpp. */
void
VerifyBarriers(JSContext *cx);
VerifyBarriers(JSRuntime *rt);
void
MaybeVerifyBarriers(JSContext *cx, bool always = false);
@ -2002,7 +2001,7 @@ MaybeVerifyBarriers(JSContext *cx, bool always = false);
#else
static inline void
VerifyBarriers(JSContext *cx)
VerifyBarriers(JSRuntime *rt)
{
}

View File

@ -1796,7 +1796,7 @@ JSScript::destroyBreakpointSite(FreeOp *fop, jsbytecode *pc)
}
void
JSScript::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler)
JSScript::clearBreakpointsIn(FreeOp *fop, js::Debugger *dbg, JSObject *handler)
{
if (!hasAnyBreakpointsOrStepMode())
return;
@ -1809,7 +1809,7 @@ JSScript::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler
for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
nextbp = bp->nextInSite();
if ((!dbg || bp->debugger == dbg) && (!handler || bp->getHandler() == handler))
bp->destroy(cx->runtime->defaultFreeOp());
bp->destroy(fop);
}
}
}

View File

@ -301,7 +301,7 @@ class ScriptCounts
ScriptCounts() : pcCountsVector(NULL) {
}
inline void destroy(JSContext *cx);
inline void destroy(FreeOp *fop);
void steal(ScriptCounts &other) {
*this = other;
@ -831,7 +831,7 @@ struct JSScript : public js::gc::Cell
void destroyBreakpointSite(js::FreeOp *fop, jsbytecode *pc);
void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler);
void clearBreakpointsIn(js::FreeOp *fop, js::Debugger *dbg, JSObject *handler);
void clearTraps(js::FreeOp *fop);
void markTrapClosures(JSTracer *trc);

View File

@ -139,9 +139,9 @@ CurrentScriptFileLineOrigin(JSContext *cx, const char **file, unsigned *linenop,
}
inline void
ScriptCounts::destroy(JSContext *cx)
ScriptCounts::destroy(FreeOp *fop)
{
cx->free_(pcCountsVector);
fop->free_(pcCountsVector);
}
} // namespace js

View File

@ -646,7 +646,7 @@ Debugger::slowPathOnLeaveFrame(JSContext *cx, bool frameOk)
*/
if (fp->isEvalFrame()) {
JSScript *script = fp->script();
script->clearBreakpointsIn(cx, NULL, NULL);
script->clearBreakpointsIn(cx->runtime->defaultFreeOp(), NULL, NULL);
}
/* Establish (status, value) as our resumption value. */
@ -1787,7 +1787,7 @@ Debugger::clearAllBreakpoints(JSContext *cx, unsigned argc, Value *vp)
{
THIS_DEBUGGER(cx, argc, vp, "clearAllBreakpoints", args, dbg);
for (GlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront())
r.front()->compartment()->clearBreakpointsIn(cx, dbg, NULL);
r.front()->compartment()->clearBreakpointsIn(cx->runtime->defaultFreeOp(), dbg, NULL);
return true;
}
@ -2900,7 +2900,7 @@ DebuggerScript_clearBreakpoint(JSContext *cx, unsigned argc, Value *vp)
if (!handler)
return false;
script->clearBreakpointsIn(cx, dbg, handler);
script->clearBreakpointsIn(cx->runtime->defaultFreeOp(), dbg, handler);
args.rval().setUndefined();
return true;
}
@ -2910,7 +2910,7 @@ DebuggerScript_clearAllBreakpoints(JSContext *cx, unsigned argc, Value *vp)
{
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "clearAllBreakpoints", args, obj, script);
Debugger *dbg = Debugger::fromChildJSObject(obj);
script->clearBreakpointsIn(cx, dbg, NULL);
script->clearBreakpointsIn(cx->runtime->defaultFreeOp(), dbg, NULL);
args.rval().setUndefined();
return true;
}