From f5541a3cc2e6b42ce1600f022761d0901f0184c6 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Fri, 9 Jun 2017 11:40:41 +0100 Subject: [PATCH] Bug 1369748 - Refactor GCRuntime::beginMarkPhase r=sfink --- js/src/jsgc.cpp | 181 ++++++++++++++++++++++++++++-------------------- 1 file changed, 106 insertions(+), 75 deletions(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index b86f415117..41b0fce10d 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3421,6 +3421,8 @@ ArenaLists::checkEmptyArenaList(AllocKind kind) void GCRuntime::purgeRuntime(AutoLockForExclusiveAccess& lock) { + gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::PURGE); + for (GCCompartmentsIter comp(rt); !comp.done(); comp.next()) comp->purge(); @@ -3595,27 +3597,25 @@ ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason) } bool -GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock) +GCRuntime::prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOut, + AutoLockForExclusiveAccess& lock) { - int64_t currentTime = PRMJ_Now(); - #ifdef DEBUG - if (fullCompartmentChecks) - checkForCompartmentMismatches(); + /* Assert that zone state is as we expect */ + for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { + MOZ_ASSERT(!zone->isCollecting()); + MOZ_ASSERT(!zone->compartments().empty()); + for (auto i : AllAllocKinds()) + MOZ_ASSERT(!zone->arenas.arenaListsToSweep(i)); + } #endif - isFull = true; + *isFullOut = true; bool any = false; - for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { - /* Assert that zone state is as we expect */ - MOZ_ASSERT(!zone->isCollecting()); - MOZ_ASSERT(!zone->compartments.empty()); -#ifdef DEBUG - for (auto i : AllAllocKinds()) - MOZ_ASSERT(!zone->arenas.arenaListsToSweep[i]); -#endif + int64_t currentTime = PRMJ_Now(); + for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { /* Set up which zones will be collected. */ if (ShouldCollectZone(zone, reason)) { if (!zone->isAtomsZone()) { @@ -3623,7 +3623,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces zone->setGCState(Zone::Mark); } } else { - isFull = false; + *isFullOut = false; } zone->setPreservingCode(false); @@ -3641,9 +3641,10 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces c->zone()->setPreservingCode(true); } - if (!rt->gc.cleanUpEverything && canAllocateMoreCode) { - if (JSCompartment* comp = jit::TopmostIonActivationCompartment(rt)) - comp->zone()->setPreservingCode(true); + if (!cleanUpEverything && canAllocateMoreCode) { + jit::JitActivationIterator activation(TlsContext.get()); + if (!activation.done()) + activation->compartment()->zone()->setPreservingCode(true); } /* @@ -3667,7 +3668,68 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces } /* Check that at least one zone is scheduled for collection. */ - if (!any) + return any; +} + +static void +DiscardJITCodeForIncrementalGC(JSRuntime* rt) +{ + js::CancelOffThreadIonCompile(rt, JS::Zone::Mark); + for (GCZonesIter zone(rt); !zone.done(); zone.next()) { + gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::MARK_DISCARD_CODE); + zone->discardJitCode(rt->defaultFreeOp()); + } +} + +static void +RelazifyFunctionsForShrinkingGC(JSRuntime* rt) +{ + gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::RELAZIFY_FUNCTIONS); + for (GCZonesIter zone(rt); !zone.done(); zone.next()) { + if (zone->isSelfHostingZone()) + continue; + RelazifyFunctions(zone, AllocKind::FUNCTION); + RelazifyFunctions(zone, AllocKind::FUNCTION_EXTENDED); + } +} + +static void +PurgeShapeTablesForShrinkingGC(JSRuntime* rt) +{ + gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::PURGE_SHAPE_TABLES); + for (GCZonesIter zone(rt); !zone.done(); zone.next()) { + if (zone->keepShapeTables() || zone->isSelfHostingZone()) + continue; + for (auto baseShape = zone->cellIter(); !baseShape.done(); baseShape.next()) + baseShape->maybePurgeTable(); + } +} + +static void +UnmarkCollectedZones(JSRuntime* rt) +{ + gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::UNMARK); + + for (GCZonesIter zone(rt); !zone.done(); zone.next()) { + /* Unmark everything in the zones being collected. */ + zone->arenas.unmarkAll(); + } + + for (GCZonesIter zone(rt); !zone.done(); zone.next()) { + /* Unmark all weak maps in the zones being collected. */ + WeakMapBase::unmarkZone(zone); + } +} + +bool +GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock) +{ +#ifdef DEBUG + if (fullCompartmentChecks) + checkForCompartmentMismatches(); +#endif + + if (!prepareZonesForCollection(reason, &isFull.ref(), lock)) return false; /* @@ -3684,78 +3746,47 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces GCMarker* gcmarker = ▮ /* For non-incremental GC the following sweep discards the jit code. */ - if (isIncremental) { - js::CancelOffThreadIonCompile(rt, JS::Zone::Mark); - for (GCZonesIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_DISCARD_CODE); - zone->discardJitCode(rt->defaultFreeOp()); - } - } + if (isIncremental) + DiscardJITCodeForIncrementalGC(rt); /* - * Relazify functions after discarding JIT code (we can't relazify - * functions with JIT code) and before the actual mark phase, so that - * the current GC can collect the JSScripts we're unlinking here. - * We do this only when we're performing a shrinking GC, as too much - * relazification can cause performance issues when we have to reparse - * the same functions over and over. + * Relazify functions after discarding JIT code (we can't relazify functions + * with JIT code) and before the actual mark phase, so that the current GC + * can collect the JSScripts we're unlinking here. We do this only when + * we're performing a shrinking GC, as too much relazification can cause + * performance issues when we have to reparse the same functions over and + * over. */ if (invocationKind == GC_SHRINK) { - { - gcstats::AutoPhase ap(stats, gcstats::PHASE_RELAZIFY_FUNCTIONS); - for (GCZonesIter zone(rt); !zone.done(); zone.next()) { - if (zone->isSelfHostingZone()) - continue; - RelazifyFunctions(zone, AllocKind::FUNCTION); - RelazifyFunctions(zone, AllocKind::FUNCTION_EXTENDED); - } - } - - /* Purge ShapeTables. */ - gcstats::AutoPhase ap(stats, gcstats::PHASE_PURGE_SHAPE_TABLES); - for (GCZonesIter zone(rt); !zone.done(); zone.next()) { - if (zone->keepShapeTables() || zone->isSelfHostingZone()) - continue; - for (auto baseShape = zone->cellIter(); !baseShape.done(); baseShape.next()) - baseShape->maybePurgeTable(); - } + RelazifyFunctionsForShrinkingGC(rt); + PurgeShapeTablesForShrinkingGC(rt); } - startNumber = number; + updateMallocCountersOnGCStart(); + + /* Process any queued source compressions during the start of a major GC. */ + { + AutoLockHelperThreadState helperLock; + HelperThreadState().startHandlingCompressionTasks(helperLock); + } /* * We must purge the runtime at the beginning of an incremental GC. The - * danger if we purge later is that the snapshot invariant of incremental - * GC will be broken, as follows. If some object is reachable only through - * some cache (say the dtoaCache) then it will not be part of the snapshot. - * If we purge after root marking, then the mutator could obtain a pointer - * to the object and start using it. This object might never be marked, so - * a GC hazard would exist. + * danger if we purge later is that the snapshot invariant of incremental GC + * will be broken, as follows. If some object is reachable only through some + * cache (say the dtoaCache) then it will not be part of the snapshot. If + * we purge after root marking, then the mutator could obtain a pointer to + * the object and start using it. This object might never be marked, so a GC + * hazard would exist. */ - { - gcstats::AutoPhase ap(stats, gcstats::PHASE_PURGE); - purgeRuntime(lock); - } + purgeRuntime(lock); /* * Mark phase. */ gcstats::AutoPhase ap1(stats, gcstats::PHASE_MARK); - { - gcstats::AutoPhase ap(stats, gcstats::PHASE_UNMARK); - - for (GCZonesIter zone(rt); !zone.done(); zone.next()) { - /* Unmark everything in the zones being collected. */ - zone->arenas.unmarkAll(); - } - - for (GCZonesIter zone(rt); !zone.done(); zone.next()) { - /* Unmark all weak maps in the zones being collected. */ - WeakMapBase::unmarkZone(zone); - } - } - + UnmarkCollectedZones(rt); traceRuntimeForMajorGC(gcmarker, lock); gcstats::AutoPhase ap2(stats, gcstats::PHASE_MARK_ROOTS);