зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
2f76579091
Коммит
17570fc0b6
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -751,7 +751,7 @@ NotifyDidPaint(JSContext *cx)
|
|||
JSRuntime *rt = cx->runtime;
|
||||
|
||||
if (rt->gcZeal() == gc::ZealFrameVerifierValue) {
|
||||
gc::VerifyBarriers(cx);
|
||||
gc::VerifyBarriers(rt);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
283
js/src/jsgc.cpp
283
js/src/jsgc.cpp
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче