Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-11-07 15:34:32 +01:00
Родитель 55f4cbebd8 5b6c60725b
Коммит 20c938e8d7
32 изменённых файлов: 152 добавлений и 142 удалений

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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) { for (var i = 0; i < function(x) myObj(Date.prototype.toString.apply(x)); void i) {
eval(a.text.replace(/@/g, "")) eval(a.text.replace(/@/g, ""))
} }
gcslice(2601); gcslice(2600);
function testcase() {} function testcase() {}
new Uint16Array(testcase); new Uint16Array(testcase);

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -203,7 +203,7 @@ function test()
gc(); gc();
buffer = null; buffer = null;
views = 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; var buf, buf2;

Просмотреть файл

@ -177,6 +177,7 @@
#include "nsDumpUtils.h" #include "nsDumpUtils.h"
#include "xpcpublic.h" #include "xpcpublic.h"
#include "GeckoProfiler.h" #include "GeckoProfiler.h"
#include "js/SliceBudget.h"
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -3621,9 +3622,7 @@ nsCycleCollector::Collect(ccType aCCType,
break; break;
} }
if (continueSlice) { if (continueSlice) {
// Force SliceBudget::isOverBudget to check the time. continueSlice = !aBudget.checkOverBudget();
aBudget.step(SliceBudget::CounterReset);
continueSlice = !aBudget.isOverBudget();
} }
} while (continueSlice); } while (continueSlice);
@ -4187,7 +4186,7 @@ nsCycleCollector_collect(nsICycleCollectorListener* aManualListener)
} }
void void
nsCycleCollector_collectSlice(SliceBudget& budget) nsCycleCollector_collectSlice(int64_t aSliceTime)
{ {
CollectorData* data = sCollectorData.get(); CollectorData* data = sCollectorData.get();
@ -4198,6 +4197,29 @@ nsCycleCollector_collectSlice(SliceBudget& budget)
PROFILER_LABEL("nsCycleCollector", "collectSlice", PROFILER_LABEL("nsCycleCollector", "collectSlice",
js::ProfileEntry::Category::CC); 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); data->mCollector->Collect(SliceCC, budget, nullptr);
} }

Просмотреть файл

@ -15,8 +15,6 @@ template<class T> struct already_AddRefed;
#include "nsError.h" #include "nsError.h"
#include "nsID.h" #include "nsID.h"
#include "js/SliceBudget.h"
namespace mozilla { namespace mozilla {
class CycleCollectedJSRuntime; class CycleCollectedJSRuntime;
@ -58,7 +56,13 @@ already_AddRefed<nsICycleCollectorLogSink> nsCycleCollector_createLogSink();
void nsCycleCollector_collect(nsICycleCollectorListener* aManualListener); 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(); uint32_t nsCycleCollector_suspectedCount();
void nsCycleCollector_shutdown(); void nsCycleCollector_shutdown();