Backed out 7 changesets (bug 1084651) for ASAN Bustage on a CLOSED TREE

Backed out changeset dd2b3e78b425 (bug 1084651)
Backed out changeset 2711fbd91819 (bug 1084651)
Backed out changeset 59a163addd79 (bug 1084651)
Backed out changeset d36f6dbbf925 (bug 1084651)
Backed out changeset 78102b62a4a0 (bug 1084651)
Backed out changeset 06387a2343a0 (bug 1084651)
Backed out changeset 2f8e7c39573e (bug 1084651)
This commit is contained in:
Carsten "Tomcat" Book 2014-11-05 15:20:25 +01:00
parent 5fcc967a48
commit 13de0f42c9
32 changed files with 154 additions and 145 deletions

View File

@ -45,7 +45,6 @@
#include "jsapi.h"
#include "jswrapper.h"
#include "js/SliceBudget.h"
#include "nsIArray.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
@ -1693,24 +1692,24 @@ nsJSContext::RunCycleCollectorSlice()
// Decide how long we want to budget for this slice. By default,
// use an unlimited budget.
js::SliceBudget budget;
int64_t sliceBudget = -1;
if (sIncrementalCC) {
if (gCCStats.mBeginTime.IsNull()) {
// If no CC is in progress, use the standard slice time.
budget = js::SliceBudget(js::TimeBudget(kICCSliceBudget));
sliceBudget = kICCSliceBudget;
} else {
TimeStamp now = TimeStamp::Now();
// Only run a limited slice if we're within the max running time.
if (TimeBetween(gCCStats.mBeginTime, now) < kMaxICCDuration) {
float sliceMultiplier = std::max(TimeBetween(gCCStats.mEndSliceTime, now) / (float)kICCIntersliceDelay, 1.0f);
budget = js::SliceBudget(js::TimeBudget(kICCSliceBudget * sliceMultiplier));
sliceBudget = kICCSliceBudget * sliceMultiplier;
}
}
}
nsCycleCollector_collectSlice(budget);
nsCycleCollector_collectSlice(sliceBudget);
gCCStats.FinishCycleCollectionSlice();
}
@ -1727,10 +1726,7 @@ nsJSContext::RunCycleCollectorWorkSlice(int64_t aWorkBudget)
js::ProfileEntry::Category::CC);
gCCStats.PrepareForCycleCollectionSlice();
js::SliceBudget budget = js::SliceBudget(js::WorkBudget(aWorkBudget));
nsCycleCollector_collectSlice(budget);
nsCycleCollector_collectSliceWork(aWorkBudget);
gCCStats.FinishCycleCollectionSlice();
}

View File

@ -15,12 +15,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1027221
SimpleTest.waitForExplicitFinish();
var x = "x";
// Trigger some incremental gc
SpecialPowers.Cu.getJSTestingFunctions().gcslice(1);
SpecialPowers.Cu.getJSTestingFunctions().gcslice(0);
// Kick off a worker that uses this same atom
var w = new Worker("data:text/plain,Promise.resolve('x').then(function() { postMessage(1); });");
// Maybe trigger some more incremental gc
SpecialPowers.Cu.getJSTestingFunctions().gcslice(1);
SpecialPowers.Cu.getJSTestingFunctions().gcslice(0);
w.onmessage = function() {
ok(true, "Got here");

View File

@ -11,25 +11,11 @@
namespace js {
struct JS_PUBLIC_API(TimeBudget)
{
int64_t budget;
explicit TimeBudget(int64_t milliseconds) { budget = milliseconds; }
};
struct JS_PUBLIC_API(WorkBudget)
{
int64_t budget;
explicit WorkBudget(int64_t work) { budget = work; }
};
/*
* This class records how much work has been done in a given collection slice,
* so that we can return before pausing for too long. Some slices are allowed
* to run for unlimited time, and others are bounded. To reduce the number of
* gettimeofday calls, we only check the time every 1000 operations.
* This class records how much work has been done in a given collection slice, so that
* we can return before pausing for too long. Some slices are allowed to run for
* unlimited time, and others are bounded. To reduce the number of gettimeofday
* calls, we only check the time every 1000 operations.
*/
struct JS_PUBLIC_API(SliceBudget)
{
@ -38,18 +24,17 @@ struct JS_PUBLIC_API(SliceBudget)
static const intptr_t CounterReset = 1000;
static const int64_t Unlimited = -1;
static const int64_t Unlimited = 0;
static int64_t TimeBudget(int64_t millis);
static int64_t WorkBudget(int64_t work);
/* Use to create an unlimited budget. */
/* Equivalent to SliceBudget(UnlimitedBudget). */
SliceBudget();
/* Instantiate as SliceBudget(TimeBudget(n)). */
explicit SliceBudget(TimeBudget time);
/* Instantiate as SliceBudget(Time/WorkBudget(n)). */
explicit SliceBudget(int64_t budget);
/* Instantiate as SliceBudget(WorkBudget(n)). */
explicit SliceBudget(WorkBudget work);
void makeUnlimited() {
void reset() {
deadline = unlimitedDeadline;
counter = unlimitedStartCounter;
}
@ -58,8 +43,10 @@ struct JS_PUBLIC_API(SliceBudget)
counter -= amt;
}
bool checkOverBudget();
bool isOverBudget() {
if (counter > 0)
if (counter >= 0)
return false;
return checkOverBudget();
}
@ -68,11 +55,10 @@ struct JS_PUBLIC_API(SliceBudget)
return deadline == unlimitedDeadline;
}
private:
bool checkOverBudget();
private:
static const int64_t unlimitedDeadline = INT64_MAX;
static const intptr_t unlimitedStartCounter = INTPTR_MAX;
};
} // namespace js

View File

@ -628,15 +628,16 @@ GCSlice(JSContext *cx, unsigned argc, Value *vp)
return false;
}
SliceBudget budget;
bool limit = true;
uint32_t budget = 0;
if (args.length() == 1) {
uint32_t work = 0;
if (!ToUint32(cx, args[0], &work))
if (!ToUint32(cx, args[0], &budget))
return false;
budget = SliceBudget(WorkBudget(work));
} else {
limit = false;
}
cx->runtime()->gc.gcDebugSlice(budget);
cx->runtime()->gc.gcDebugSlice(limit, budget);
args.rval().setUndefined();
return true;
}

View File

@ -281,7 +281,7 @@ class GCRuntime
void gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
void gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0);
void gcFinalSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
void gcDebugSlice(SliceBudget &budget);
void gcDebugSlice(bool limit, int64_t objCount);
void runDebugGC();
inline void poke();
@ -509,14 +509,14 @@ class GCRuntime
bool initZeal();
void requestMajorGC(JS::gcreason::Reason reason);
void collect(bool incremental, SliceBudget &budget, JSGCInvocationKind gckind,
void collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
JS::gcreason::Reason reason);
bool gcCycle(bool incremental, SliceBudget &budget, JSGCInvocationKind gckind,
bool gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
JS::gcreason::Reason reason);
gcstats::ZoneGCStats scanZonesBeforeGC();
void budgetIncrementalGC(SliceBudget &budget);
void budgetIncrementalGC(int64_t *budget);
void resetIncrementalGC(const char *reason);
void incrementalCollectSlice(SliceBudget &budget, JS::gcreason::Reason reason);
void incrementalCollectSlice(int64_t budget, JS::gcreason::Reason reason);
void pushZealSelectedObjects();
void purgeRuntime();
bool beginMarkPhase(JS::gcreason::Reason reason);

View File

@ -28,7 +28,7 @@ gcPreserveCode();
try {
mjitChunkLimit(1);
} catch(exc1) {}
gcslice(1);
gcslice(0);
m(1);
gc();
m(2);

View File

@ -3,4 +3,4 @@
//
gc();
evaluate("gcslice(1);");
evaluate("gcslice(0);");

View File

@ -20,7 +20,7 @@ function h(code) {
h("\
p=m();\
gcPreserveCode();\
gcslice(8);\
gcslice(7);\
")
h("\"\"")
h("")

View File

@ -3,7 +3,7 @@
//
gc()
schedulegc(this)
gcslice(3)
gcslice(2)
function f() {
this["x"] = this["x"] = {}
}

View File

@ -5,8 +5,8 @@
function printBugNumber (num) {
BUGNUMBER = num;
}
gcslice(1)
gcslice(0)
schedulegc(this);
gcslice(2);
gcslice(1);
var BUGNUMBER = ("one");
printBugNumber();

View File

@ -1,6 +1,6 @@
var g1 = newGlobal();
schedulegc(g1);
gcslice(1);
gcslice(0);
function testEq(b) {
var a = deserialize(serialize(b));
}

View File

@ -4,7 +4,7 @@ function gen()
yield 1;
local = null;
gc();
gcslice(0); // Start IGC, but don't mark anything.
gcslice(0);
yield 2;
}

View File

@ -12,5 +12,5 @@ function recur(n)
}
validategc(false);
gcslice(1);
gcslice(0);
recur(10);

View File

@ -11,8 +11,8 @@ expect = "generator function foo returns a value";
actual = (function (j) {}).message;
reportCompare(expect, actual, summary + ": 1");
reportCompare(expect, actual, summary + ": 2");
gcslice(0);
gcslice(1);
gcslice(2);
gc();
var strings = [ (0), ];
for (var i = 0; i < strings.length; i++)

View File

@ -4,7 +4,7 @@ evalcx("\
gcslice = function() { };\
array = new Uint8Array;\
t0 = array.subarray();\
gcslice(12); \
gcslice(11); \
array.subarray();\
gc();\
gc();\

View File

@ -3,7 +3,7 @@
if (typeof evalInWorker == "undefined")
quit();
gcslice(11);
gcslice(10);
evalInWorker("print('helo world');");
for (i = 0; i < 100000; i++) {}

View File

@ -1,6 +1,6 @@
if (this.hasOwnProperty('Intl')) {
gc();
gcslice(1);
gcslice(0);
var thisValues = [ "x" ];
thisValues.forEach(function (value) {
var format = Intl.DateTimeFormat.call(value);

View File

@ -1,5 +1,5 @@
gc();
gcslice(1);
gcslice(0);
function isClone(a, b) {
var rmemory = new WeakMap();
rmemory.set(a,b);

View File

@ -9,5 +9,5 @@ var recursiveFunctions = [{
eval(a.text.replace(/@/g, ""))
}
})();
gcslice(2869);
gcslice(2868);
Function("v={c:[{x:[[]],N:{x:[{}[d]]}}]}=minorgc(true)")()

View File

@ -10,5 +10,5 @@ var recursiveFunctions = [{
eval(a.text.replace(/@/g, ""))
}
})();
gcslice(2869);
gcslice(2868);
Function("v={c:[{x:[[]],N:{x:[{}[d]]}}]}=minorgc(true)")()

View File

@ -10,5 +10,5 @@ var recursiveFunctions = [{
eval(a.text.replace(/@/g, ""))
}
})();
gcslice(2869);
gcslice(2868);
Function("v={c:[{x:[[]],N:{x:[{}[d]]}}]}=minorgc(true)")()

View File

@ -4,6 +4,6 @@ var juneDate = new Date(2000, 5, 20, 0, 0, 0, 0);
for (var i = 0; i < function(x) myObj(Date.prototype.toString.apply(x)); void i) {
eval(a.text.replace(/@/g, ""))
}
gcslice(2601);
gcslice(2600);
function testcase() {}
new Uint16Array(testcase);

View File

@ -23,7 +23,7 @@ function init()
*/
eval("init()");
gcslice(0); // Start IGC, but don't mark anything.
gcslice(0);
selectforgc(objs.root2);
gcslice(1);
objs.root2.ptr = objs.root1.ptr;

View File

@ -22,7 +22,7 @@ function init()
*/
eval("init()");
gcslice(0); // Start IGC, but don't mark anything.
gcslice(0);
selectforgc(objs.root);
gcslice(1);
delete objs.root.b;

View File

@ -4,7 +4,7 @@ var g1 = newGlobal();
var g2 = newGlobal();
schedulegc(g1);
gcslice(0); // Start IGC, but don't mark anything.
gcslice(0);
schedulegc(g2);
gcslice(1);
gcslice();

View File

@ -5,7 +5,7 @@ var g2 = newGlobal();
schedulegc(g1);
schedulegc(g2);
gcslice(0); // Start IGC, but don't mark anything.
gcslice(0);
schedulegc(g1);
gcslice(1);
gcslice();

View File

@ -87,14 +87,12 @@ BEGIN_TEST(testGCFinalizeCallback)
FinalizeCalls = 0;
JS_SetGCZeal(cx, 9, 1000000);
JS::PrepareForFullGC(rt);
js::SliceBudget budget(js::WorkBudget(1));
rt->gc.gcDebugSlice(budget);
rt->gc.gcDebugSlice(true, 1);
CHECK(rt->gc.state() == js::gc::MARK);
CHECK(rt->gc.isFullGc());
JS::RootedObject global4(cx, createTestGlobal());
budget = js::SliceBudget(js::WorkBudget(1));
rt->gc.gcDebugSlice(budget);
rt->gc.gcDebugSlice(true, 1);
CHECK(rt->gc.state() == js::gc::NO_INCREMENTAL);
CHECK(!rt->gc.isFullGc());
CHECK(checkMultipleGroups());

View File

@ -89,8 +89,7 @@ BEGIN_TEST(testWeakMap_keyDelegates)
* zone to finish marking before the delegate zone.
*/
CHECK(newCCW(map, delegate));
js::SliceBudget budget(js::WorkBudget(1000000));
rt->gc.gcDebugSlice(budget);
rt->gc.gcDebugSlice(true, 1000000);
#ifdef DEBUG
CHECK(map->zone()->lastZoneGroupIndex() < delegate->zone()->lastZoneGroupIndex());
#endif
@ -103,8 +102,7 @@ BEGIN_TEST(testWeakMap_keyDelegates)
/* Check the delegate keeps the entry alive even if the key is not reachable. */
key = nullptr;
CHECK(newCCW(map, delegate));
budget = js::SliceBudget(js::WorkBudget(100000));
rt->gc.gcDebugSlice(budget);
rt->gc.gcDebugSlice(true, 100000);
CHECK(checkSize(map, 1));
/*

View File

@ -1457,7 +1457,7 @@ GCRuntime::setParameter(JSGCParamKey key, uint32_t value)
setMaxMallocBytes(value);
break;
case JSGC_SLICE_TIME_BUDGET:
sliceBudget = value ? value : SliceBudget::Unlimited;
sliceBudget = SliceBudget::TimeBudget(value);
break;
case JSGC_MARK_STACK_LIMIT:
setMarkStackLimit(value);
@ -1554,7 +1554,7 @@ GCRuntime::getParameter(JSGCParamKey key, const AutoLockGC &lock)
case JSGC_TOTAL_CHUNKS:
return uint32_t(chunkSet.count() + emptyChunks(lock).count());
case JSGC_SLICE_TIME_BUDGET:
return uint32_t(sliceBudget > 0 ? sliceBudget : 0);
return uint32_t(sliceBudget > 0 ? sliceBudget / PRMJ_USEC_PER_MSEC : 0);
case JSGC_MARK_STACK_LIMIT:
return marker.maxCapacity();
case JSGC_HIGH_FREQUENCY_TIME_LIMIT:
@ -2930,36 +2930,41 @@ GCRuntime::refillFreeListInGC(Zone *zone, AllocKind thingKind)
return allocator.arenas.allocateFromArena(zone, thingKind);
}
/* static */ int64_t
SliceBudget::TimeBudget(int64_t millis)
{
return millis * PRMJ_USEC_PER_MSEC;
}
/* static */ int64_t
SliceBudget::WorkBudget(int64_t work)
{
/* For work = 0 not to mean Unlimited, we subtract 1. */
return -work - 1;
}
SliceBudget::SliceBudget()
{
makeUnlimited();
reset();
}
SliceBudget::SliceBudget(TimeBudget time)
SliceBudget::SliceBudget(int64_t budget)
{
if (time.budget < 0) {
makeUnlimited();
} else {
// Note: TimeBudget(0) is equivalent to WorkBudget(CounterReset).
deadline = PRMJ_Now() + time.budget * PRMJ_USEC_PER_MSEC;
if (budget == Unlimited) {
reset();
} else if (budget > 0) {
deadline = PRMJ_Now() + budget;
counter = CounterReset;
}
}
SliceBudget::SliceBudget(WorkBudget work)
{
if (work.budget < 0) {
makeUnlimited();
} else {
deadline = 0;
counter = work.budget;
counter = -budget - 1;
}
}
bool
SliceBudget::checkOverBudget()
{
bool over = PRMJ_Now() >= deadline;
bool over = PRMJ_Now() > deadline;
if (!over)
counter = CounterReset;
return over;
@ -5528,7 +5533,7 @@ GCRuntime::resetIncrementalGC(const char *reason)
break;
}
case SWEEP: {
case SWEEP:
marker.reset();
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
@ -5536,15 +5541,13 @@ GCRuntime::resetIncrementalGC(const char *reason)
/* Finish sweeping the current zone group, then abort. */
abortSweepAfterCurrentGroup = true;
SliceBudget budget;
incrementalCollectSlice(budget, JS::gcreason::RESET);
incrementalCollectSlice(SliceBudget::Unlimited, JS::gcreason::RESET);
{
gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
rt->gc.waitBackgroundSweepOrAllocEnd();
}
break;
}
default:
MOZ_CRASH("Invalid incremental GC state");
@ -5632,7 +5635,8 @@ GCRuntime::pushZealSelectedObjects()
}
void
GCRuntime::incrementalCollectSlice(SliceBudget &budget, JS::gcreason::Reason reason)
GCRuntime::incrementalCollectSlice(int64_t budget,
JS::gcreason::Reason reason)
{
MOZ_ASSERT(rt->currentThreadHasExclusiveAccess());
@ -5645,7 +5649,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget &budget, JS::gcreason::Reason rea
int zeal = 0;
#ifdef JS_GC_ZEAL
if (reason == JS::gcreason::DEBUG_GC && !budget.isUnlimited()) {
if (reason == JS::gcreason::DEBUG_GC && budget != SliceBudget::Unlimited) {
/*
* Do the incremental collection type specified by zeal mode if the
* collection was triggered by runDebugGC() and incremental GC has not
@ -5656,16 +5660,18 @@ GCRuntime::incrementalCollectSlice(SliceBudget &budget, JS::gcreason::Reason rea
#endif
MOZ_ASSERT_IF(incrementalState != NO_INCREMENTAL, isIncremental);
isIncremental = !budget.isUnlimited();
isIncremental = budget != SliceBudget::Unlimited;
if (zeal == ZealIncrementalRootsThenFinish || zeal == ZealIncrementalMarkAllThenFinish) {
/*
* Yields between slices occurs at predetermined points in these modes;
* the budget is not used.
*/
budget.makeUnlimited();
budget = SliceBudget::Unlimited;
}
SliceBudget sliceBudget(budget);
if (incrementalState == NO_INCREMENTAL) {
incrementalState = MARK_ROOTS;
lastMarkSlice = false;
@ -5695,11 +5701,11 @@ GCRuntime::incrementalCollectSlice(SliceBudget &budget, JS::gcreason::Reason rea
case MARK: {
/* If we needed delayed marking for gray roots, then collect until done. */
if (!marker.hasBufferedGrayRoots()) {
budget.makeUnlimited();
sliceBudget.reset();
isIncremental = false;
}
bool finished = drainMarkStack(budget, gcstats::PHASE_MARK);
bool finished = drainMarkStack(sliceBudget, gcstats::PHASE_MARK);
if (!finished)
break;
@ -5725,7 +5731,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget &budget, JS::gcreason::Reason rea
* now exhasted.
*/
beginSweepPhase(lastGC);
if (budget.isOverBudget())
if (sliceBudget.isOverBudget())
break;
/*
@ -5739,7 +5745,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget &budget, JS::gcreason::Reason rea
}
case SWEEP: {
bool finished = sweepPhase(budget);
bool finished = sweepPhase(sliceBudget);
if (!finished)
break;
@ -5780,32 +5786,32 @@ gc::IsIncrementalGCSafe(JSRuntime *rt)
}
void
GCRuntime::budgetIncrementalGC(SliceBudget &budget)
GCRuntime::budgetIncrementalGC(int64_t *budget)
{
IncrementalSafety safe = IsIncrementalGCSafe(rt);
if (!safe) {
resetIncrementalGC(safe.reason());
budget.makeUnlimited();
*budget = SliceBudget::Unlimited;
stats.nonincremental(safe.reason());
return;
}
if (mode != JSGC_MODE_INCREMENTAL) {
resetIncrementalGC("GC mode change");
budget.makeUnlimited();
*budget = SliceBudget::Unlimited;
stats.nonincremental("GC mode");
return;
}
if (isTooMuchMalloc()) {
budget.makeUnlimited();
*budget = SliceBudget::Unlimited;
stats.nonincremental("malloc bytes trigger");
}
bool reset = false;
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
if (zone->usage.gcBytes() >= zone->threshold.gcTriggerBytes()) {
budget.makeUnlimited();
*budget = SliceBudget::Unlimited;
stats.nonincremental("allocation trigger");
}
@ -5816,7 +5822,7 @@ GCRuntime::budgetIncrementalGC(SliceBudget &budget)
}
if (zone->isTooMuchMalloc()) {
budget.makeUnlimited();
*budget = SliceBudget::Unlimited;
stats.nonincremental("malloc bytes trigger");
}
}
@ -5862,7 +5868,7 @@ struct AutoDisableStoreBuffer
* to run another cycle.
*/
MOZ_NEVER_INLINE bool
GCRuntime::gcCycle(bool incremental, SliceBudget &budget, JSGCInvocationKind gckind,
GCRuntime::gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
JS::gcreason::Reason reason)
{
minorGC(reason);
@ -5916,9 +5922,9 @@ GCRuntime::gcCycle(bool incremental, SliceBudget &budget, JSGCInvocationKind gck
resetIncrementalGC("requested");
stats.nonincremental("requested");
budget.makeUnlimited();
budget = SliceBudget::Unlimited;
} else {
budgetIncrementalGC(budget);
budgetIncrementalGC(&budget);
}
/* The GC was reset, so we need a do-over. */
@ -6011,7 +6017,7 @@ GCRuntime::scanZonesBeforeGC()
}
void
GCRuntime::collect(bool incremental, SliceBudget &budget, JSGCInvocationKind gckind,
GCRuntime::collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
JS::gcreason::Reason reason)
{
/* GC shouldn't be running in parallel execution mode */
@ -6036,7 +6042,7 @@ GCRuntime::collect(bool incremental, SliceBudget &budget, JSGCInvocationKind gck
return;
#endif
MOZ_ASSERT_IF(!incremental || !budget.isUnlimited(), JSGC_INCREMENTAL);
MOZ_ASSERT_IF(!incremental || budget != SliceBudget::Unlimited, JSGC_INCREMENTAL);
AutoStopVerifyingBarriers av(rt, reason == JS::gcreason::SHUTDOWN_CC ||
reason == JS::gcreason::DESTROY_RUNTIME);
@ -6103,22 +6109,21 @@ GCRuntime::collect(bool incremental, SliceBudget &budget, JSGCInvocationKind gck
void
GCRuntime::gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason)
{
SliceBudget budget;
collect(false, budget, gckind, reason);
collect(false, SliceBudget::Unlimited, gckind, reason);
}
void
GCRuntime::gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis)
{
SliceBudget budget;
int64_t budget;
if (millis)
budget = SliceBudget(TimeBudget(millis));
budget = SliceBudget::TimeBudget(millis);
else if (reason == JS::gcreason::ALLOC_TRIGGER)
budget = SliceBudget(TimeBudget(sliceBudget));
budget = sliceBudget;
else if (schedulingState.inHighFrequencyGCMode() && tunables.isDynamicMarkSliceEnabled())
budget = SliceBudget(TimeBudget(sliceBudget * IGC_MARK_SLICE_MULTIPLIER));
budget = sliceBudget * IGC_MARK_SLICE_MULTIPLIER;
else
budget = SliceBudget(TimeBudget(sliceBudget));
budget = sliceBudget;
collect(true, budget, gckind, reason);
}
@ -6126,8 +6131,7 @@ GCRuntime::gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64
void
GCRuntime::gcFinalSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason)
{
SliceBudget budget;
collect(true, budget, gckind, reason);
collect(true, SliceBudget::Unlimited, gckind, reason);
}
void
@ -6170,8 +6174,9 @@ ZonesSelected(JSRuntime *rt)
}
void
GCRuntime::gcDebugSlice(SliceBudget &budget)
GCRuntime::gcDebugSlice(bool limit, int64_t objCount)
{
int64_t budget = limit ? SliceBudget::WorkBudget(objCount) : SliceBudget::Unlimited;
if (!ZonesSelected(rt)) {
if (JS::IsIncrementalGCInProgress(rt))
JS::PrepareForIncrementalGC(rt);
@ -6422,12 +6427,12 @@ GCRuntime::runDebugGC()
PrepareForDebugGC(rt);
SliceBudget budget;
if (type == ZealIncrementalRootsThenFinish ||
type == ZealIncrementalMarkAllThenFinish ||
type == ZealIncrementalMultipleSlices)
{
js::gc::State initialState = incrementalState;
int64_t budget;
if (type == ZealIncrementalMultipleSlices) {
/*
* Start with a small slice limit and double it every slice. This
@ -6438,10 +6443,10 @@ GCRuntime::runDebugGC()
incrementalLimit = zealFrequency / 2;
else
incrementalLimit *= 2;
budget = SliceBudget(WorkBudget(incrementalLimit));
budget = SliceBudget::WorkBudget(incrementalLimit);
} else {
// This triggers incremental GC but is actually ignored by IncrementalMarkSlice.
budget = SliceBudget(WorkBudget(1));
budget = SliceBudget::WorkBudget(1);
}
collect(true, budget, GC_NORMAL, JS::gcreason::DEBUG_GC);
@ -6456,9 +6461,9 @@ GCRuntime::runDebugGC()
incrementalLimit = zealFrequency / 2;
}
} else if (type == ZealCompactValue) {
collect(false, budget, GC_SHRINK, JS::gcreason::DEBUG_GC);
collect(false, SliceBudget::Unlimited, GC_SHRINK, JS::gcreason::DEBUG_GC);
} else {
collect(false, budget, GC_NORMAL, JS::gcreason::DEBUG_GC);
collect(false, SliceBudget::Unlimited, GC_NORMAL, JS::gcreason::DEBUG_GC);
}
#endif

View File

@ -203,7 +203,7 @@ function test()
gc();
buffer = null;
views = null;
gcslice(3); gcslice(3); gcslice(3); gcslice(3); gcslice(3); gcslice(3); gc();
gcslice(2); gcslice(2); gcslice(2); gcslice(2); gcslice(2); gcslice(2); gc();
}
var buf, buf2;

View File

@ -3622,9 +3622,7 @@ nsCycleCollector::Collect(ccType aCCType,
break;
}
if (continueSlice) {
// Force SliceBudget::isOverBudget to check the time.
aBudget.step(SliceBudget::CounterReset);
continueSlice = !aBudget.isOverBudget();
continueSlice = !aBudget.checkOverBudget();
}
} while (continueSlice);
@ -4188,7 +4186,7 @@ nsCycleCollector_collect(nsICycleCollectorListener* aManualListener)
}
void
nsCycleCollector_collectSlice(SliceBudget& budget)
nsCycleCollector_collectSlice(int64_t aSliceTime)
{
CollectorData* data = sCollectorData.get();
@ -4199,6 +4197,29 @@ nsCycleCollector_collectSlice(SliceBudget& budget)
PROFILER_LABEL("nsCycleCollector", "collectSlice",
js::ProfileEntry::Category::CC);
SliceBudget budget;
if (aSliceTime >= 0) {
budget = SliceBudget(SliceBudget::TimeBudget(aSliceTime));
}
data->mCollector->Collect(SliceCC, budget, nullptr);
}
void
nsCycleCollector_collectSliceWork(int64_t aSliceWork)
{
CollectorData* data = sCollectorData.get();
// We should have started the cycle collector by now.
MOZ_ASSERT(data);
MOZ_ASSERT(data->mCollector);
PROFILER_LABEL("nsCycleCollector", "collectSliceWork",
js::ProfileEntry::Category::CC);
SliceBudget budget;
if (aSliceWork >= 0) {
budget = SliceBudget(SliceBudget::WorkBudget(aSliceWork));
}
data->mCollector->Collect(SliceCC, budget, nullptr);
}

View File

@ -15,8 +15,6 @@ template<class T> struct already_AddRefed;
#include "nsError.h"
#include "nsID.h"
namespace js { struct SliceBudget; };
namespace mozilla {
class CycleCollectedJSRuntime;
@ -58,7 +56,13 @@ already_AddRefed<nsICycleCollectorLogSink> nsCycleCollector_createLogSink();
void nsCycleCollector_collect(nsICycleCollectorListener* aManualListener);
void nsCycleCollector_collectSlice(js::SliceBudget& budget);
// If aSliceTime is negative, the CC will run to completion. Otherwise,
// aSliceTime will be used as the time budget for the slice, in ms.
void nsCycleCollector_collectSlice(int64_t aSliceTime);
// If aSliceTime is negative, the CC will run to completion. Otherwise,
// aSliceTime will be used as the work budget for the slice.
void nsCycleCollector_collectSliceWork(int64_t aSliceWork);
uint32_t nsCycleCollector_suspectedCount();
void nsCycleCollector_shutdown();