зеркало из https://github.com/mozilla/pjs.git
Bug 656120 - Change MaybeGC trigger. r=igor
This commit is contained in:
Родитель
d3a19207ce
Коммит
35b03ae9b3
|
@ -684,7 +684,7 @@ JSRuntime::init(uint32 maxbytes)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
atomsCompartment->setGCLastBytes(8192);
|
atomsCompartment->setGCLastBytes(8192, GC_NORMAL);
|
||||||
|
|
||||||
if (!js_InitAtomState(this))
|
if (!js_InitAtomState(this))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -422,6 +422,8 @@ struct JSRuntime {
|
||||||
uint32 gcEmptyArenaPoolLifespan;
|
uint32 gcEmptyArenaPoolLifespan;
|
||||||
uint32 gcNumber;
|
uint32 gcNumber;
|
||||||
js::GCMarker *gcMarkingTracer;
|
js::GCMarker *gcMarkingTracer;
|
||||||
|
bool gcChunkAllocationSinceLastGC;
|
||||||
|
int64 gcNextFullGCTime;
|
||||||
int64 gcJitReleaseTime;
|
int64 gcJitReleaseTime;
|
||||||
JSGCMode gcMode;
|
JSGCMode gcMode;
|
||||||
volatile bool gcIsNeeded;
|
volatile bool gcIsNeeded;
|
||||||
|
@ -793,7 +795,7 @@ struct JSRuntime {
|
||||||
|
|
||||||
bool init(uint32 maxbytes);
|
bool init(uint32 maxbytes);
|
||||||
|
|
||||||
void setGCLastBytes(size_t lastBytes);
|
void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
|
||||||
void reduceGCTriggerBytes(uint32 amount);
|
void reduceGCTriggerBytes(uint32 amount);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -493,7 +493,7 @@ struct JS_FRIEND_API(JSCompartment) {
|
||||||
void finalizeShapeArenaLists(JSContext *cx);
|
void finalizeShapeArenaLists(JSContext *cx);
|
||||||
bool arenaListsAreEmpty();
|
bool arenaListsAreEmpty();
|
||||||
|
|
||||||
void setGCLastBytes(size_t lastBytes);
|
void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
|
||||||
void reduceGCTriggerBytes(uint32 amount);
|
void reduceGCTriggerBytes(uint32 amount);
|
||||||
|
|
||||||
js::DtoaCache dtoaCache;
|
js::DtoaCache dtoaCache;
|
||||||
|
|
|
@ -514,11 +514,12 @@ PickChunk(JSContext *cx)
|
||||||
|
|
||||||
chunk->init(rt);
|
chunk->init(rt);
|
||||||
cx->compartment->chunk = chunk;
|
cx->compartment->chunk = chunk;
|
||||||
|
rt->gcChunkAllocationSinceLastGC = true;
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ExpireGCChunks(JSRuntime *rt)
|
ExpireGCChunks(JSRuntime *rt, JSGCInvocationKind gckind)
|
||||||
{
|
{
|
||||||
static const size_t MaxAge = 3;
|
static const size_t MaxAge = 3;
|
||||||
|
|
||||||
|
@ -530,7 +531,7 @@ ExpireGCChunks(JSRuntime *rt)
|
||||||
Chunk *chunk = e.front();
|
Chunk *chunk = e.front();
|
||||||
JS_ASSERT(chunk->info.runtime == rt);
|
JS_ASSERT(chunk->info.runtime == rt);
|
||||||
if (chunk->unused()) {
|
if (chunk->unused()) {
|
||||||
if (chunk->info.age++ > MaxAge) {
|
if (gckind == GC_SHRINK || chunk->info.age++ > MaxAge) {
|
||||||
e.removeFront();
|
e.removeFront();
|
||||||
ReleaseGCChunk(rt, chunk);
|
ReleaseGCChunk(rt, chunk);
|
||||||
continue;
|
continue;
|
||||||
|
@ -614,7 +615,7 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
|
||||||
* The assigned value prevents GC from running when GC memory is too low
|
* The assigned value prevents GC from running when GC memory is too low
|
||||||
* (during JS engine start).
|
* (during JS engine start).
|
||||||
*/
|
*/
|
||||||
rt->setGCLastBytes(8192);
|
rt->setGCLastBytes(8192, GC_NORMAL);
|
||||||
|
|
||||||
rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_EIGHTH_LIFETIME;
|
rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_EIGHTH_LIFETIME;
|
||||||
|
|
||||||
|
@ -1092,34 +1093,38 @@ js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSRuntime::setGCLastBytes(size_t lastBytes)
|
JSRuntime::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
|
||||||
{
|
{
|
||||||
gcLastBytes = lastBytes;
|
gcLastBytes = lastBytes;
|
||||||
float trigger = float(Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER)) * GC_HEAP_GROWTH_FACTOR;
|
|
||||||
|
size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER);
|
||||||
|
float trigger = float(base) * GC_HEAP_GROWTH_FACTOR;
|
||||||
gcTriggerBytes = size_t(Min(float(gcMaxBytes), trigger));
|
gcTriggerBytes = size_t(Min(float(gcMaxBytes), trigger));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSRuntime::reduceGCTriggerBytes(uint32 amount) {
|
JSRuntime::reduceGCTriggerBytes(uint32 amount) {
|
||||||
JS_ASSERT(amount > 0);
|
JS_ASSERT(amount > 0);
|
||||||
JS_ASSERT((gcTriggerBytes - amount) > 0);
|
JS_ASSERT(gcTriggerBytes - amount >= 0);
|
||||||
if (gcTriggerBytes - amount < GC_ARENA_ALLOCATION_TRIGGER * GC_HEAP_GROWTH_FACTOR)
|
if (gcTriggerBytes - amount < GC_ARENA_ALLOCATION_TRIGGER * GC_HEAP_GROWTH_FACTOR)
|
||||||
return;
|
return;
|
||||||
gcTriggerBytes -= amount;
|
gcTriggerBytes -= amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSCompartment::setGCLastBytes(size_t lastBytes)
|
JSCompartment::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
|
||||||
{
|
{
|
||||||
gcLastBytes = lastBytes;
|
gcLastBytes = lastBytes;
|
||||||
float trigger = float(Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER)) * GC_HEAP_GROWTH_FACTOR;
|
|
||||||
|
size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER);
|
||||||
|
float trigger = float(base) * GC_HEAP_GROWTH_FACTOR;
|
||||||
gcTriggerBytes = size_t(Min(float(rt->gcMaxBytes), trigger));
|
gcTriggerBytes = size_t(Min(float(rt->gcMaxBytes), trigger));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSCompartment::reduceGCTriggerBytes(uint32 amount) {
|
JSCompartment::reduceGCTriggerBytes(uint32 amount) {
|
||||||
JS_ASSERT(amount > 0);
|
JS_ASSERT(amount > 0);
|
||||||
JS_ASSERT((gcTriggerBytes - amount) > 0);
|
JS_ASSERT(gcTriggerBytes - amount >= 0);
|
||||||
if (gcTriggerBytes - amount < GC_ARENA_ALLOCATION_TRIGGER * GC_HEAP_GROWTH_FACTOR)
|
if (gcTriggerBytes - amount < GC_ARENA_ALLOCATION_TRIGGER * GC_HEAP_GROWTH_FACTOR)
|
||||||
return;
|
return;
|
||||||
gcTriggerBytes -= amount;
|
gcTriggerBytes -= amount;
|
||||||
|
@ -1960,6 +1965,21 @@ MaybeGC(JSContext *cx)
|
||||||
if (comp->gcBytes > 8192 && comp->gcBytes >= 3 * (comp->gcTriggerBytes / 4)) {
|
if (comp->gcBytes > 8192 && comp->gcBytes >= 3 * (comp->gcTriggerBytes / 4)) {
|
||||||
GCREASON(MAYBEGC);
|
GCREASON(MAYBEGC);
|
||||||
js_GC(cx, (rt->gcMode == JSGC_MODE_COMPARTMENT) ? comp : NULL, GC_NORMAL);
|
js_GC(cx, (rt->gcMode == JSGC_MODE_COMPARTMENT) ? comp : NULL, GC_NORMAL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On 32 bit setting gcNextFullGCTime below is not atomic and a race condition
|
||||||
|
* could trigger an GC. We tolerate this.
|
||||||
|
*/
|
||||||
|
int64 now = PRMJ_Now();
|
||||||
|
if (rt->gcNextFullGCTime && rt->gcNextFullGCTime <= now) {
|
||||||
|
if (rt->gcChunkAllocationSinceLastGC || rt->gcChunksWaitingToExpire) {
|
||||||
|
GCREASON(MAYBEGC);
|
||||||
|
js_GC(cx, NULL, GC_SHRINK);
|
||||||
|
} else {
|
||||||
|
rt->gcNextFullGCTime = now + GC_IDLE_FULL_SPAN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2094,10 +2114,11 @@ GCHelperThread::threadLoop(JSRuntime *rt)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GCHelperThread::startBackgroundSweep(JSRuntime *rt)
|
GCHelperThread::startBackgroundSweep(JSRuntime *rt, JSGCInvocationKind gckind)
|
||||||
{
|
{
|
||||||
/* The caller takes the GC lock. */
|
/* The caller takes the GC lock. */
|
||||||
JS_ASSERT(!sweeping);
|
JS_ASSERT(!sweeping);
|
||||||
|
lastGCKind = gckind;
|
||||||
sweeping = true;
|
sweeping = true;
|
||||||
PR_NotifyCondVar(wakeup);
|
PR_NotifyCondVar(wakeup);
|
||||||
}
|
}
|
||||||
|
@ -2138,7 +2159,7 @@ GCHelperThread::doSweep()
|
||||||
for (ArenaHeader **i = finalizeVector.begin(); i != finalizeVector.end(); ++i)
|
for (ArenaHeader **i = finalizeVector.begin(); i != finalizeVector.end(); ++i)
|
||||||
ArenaList::backgroundFinalize(cx, *i);
|
ArenaList::backgroundFinalize(cx, *i);
|
||||||
finalizeVector.resize(0);
|
finalizeVector.resize(0);
|
||||||
ExpireGCChunks(cx->runtime);
|
ExpireGCChunks(cx->runtime, lastGCKind);
|
||||||
cx = NULL;
|
cx = NULL;
|
||||||
|
|
||||||
if (freeCursor) {
|
if (freeCursor) {
|
||||||
|
@ -2405,7 +2426,7 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
|
||||||
* use IsAboutToBeFinalized().
|
* use IsAboutToBeFinalized().
|
||||||
* This is done on the GCHelperThread if JS_THREADSAFE is defined.
|
* This is done on the GCHelperThread if JS_THREADSAFE is defined.
|
||||||
*/
|
*/
|
||||||
ExpireGCChunks(rt);
|
ExpireGCChunks(rt, gckind);
|
||||||
#endif
|
#endif
|
||||||
GCTIMESTAMP(sweepDestroyEnd);
|
GCTIMESTAMP(sweepDestroyEnd);
|
||||||
|
|
||||||
|
@ -2661,7 +2682,7 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_P
|
||||||
if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
|
if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
|
||||||
JS_ASSERT(cx->gcBackgroundFree == &rt->gcHelperThread);
|
JS_ASSERT(cx->gcBackgroundFree == &rt->gcHelperThread);
|
||||||
cx->gcBackgroundFree = NULL;
|
cx->gcBackgroundFree = NULL;
|
||||||
rt->gcHelperThread.startBackgroundSweep(rt);
|
rt->gcHelperThread.startBackgroundSweep(rt, gckind);
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(!cx->gcBackgroundFree);
|
JS_ASSERT(!cx->gcBackgroundFree);
|
||||||
}
|
}
|
||||||
|
@ -2669,12 +2690,12 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_P
|
||||||
|
|
||||||
rt->gcMarkAndSweep = false;
|
rt->gcMarkAndSweep = false;
|
||||||
rt->gcRegenShapes = false;
|
rt->gcRegenShapes = false;
|
||||||
rt->setGCLastBytes(rt->gcBytes);
|
rt->setGCLastBytes(rt->gcBytes, gckind);
|
||||||
rt->gcCurrentCompartment = NULL;
|
rt->gcCurrentCompartment = NULL;
|
||||||
rt->gcWeakMapList = NULL;
|
rt->gcWeakMapList = NULL;
|
||||||
|
|
||||||
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
|
for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
|
||||||
(*c)->setGCLastBytes((*c)->gcBytes);
|
(*c)->setGCLastBytes((*c)->gcBytes, gckind);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2731,6 +2752,10 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
|
||||||
* stop creating garbage.
|
* stop creating garbage.
|
||||||
*/
|
*/
|
||||||
} while (gckind == GC_LAST_CONTEXT && rt->gcPoke);
|
} while (gckind == GC_LAST_CONTEXT && rt->gcPoke);
|
||||||
|
|
||||||
|
rt->gcNextFullGCTime = PRMJ_Now() + GC_IDLE_FULL_SPAN;
|
||||||
|
|
||||||
|
rt->gcChunkAllocationSinceLastGC = false;
|
||||||
#ifdef JS_GCMETER
|
#ifdef JS_GCMETER
|
||||||
js_DumpGCStats(cx->runtime, stderr);
|
js_DumpGCStats(cx->runtime, stderr);
|
||||||
#endif
|
#endif
|
||||||
|
@ -2857,7 +2882,7 @@ NewCompartment(JSContext *cx, JSPrincipals *principals)
|
||||||
JSPRINCIPALS_HOLD(cx, principals);
|
JSPRINCIPALS_HOLD(cx, principals);
|
||||||
}
|
}
|
||||||
|
|
||||||
compartment->setGCLastBytes(8192);
|
compartment->setGCLastBytes(8192, GC_NORMAL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Before reporting the OOM condition, |lock| needs to be cleaned up,
|
* Before reporting the OOM condition, |lock| needs to be cleaned up,
|
||||||
|
|
|
@ -636,6 +636,9 @@ const size_t GC_ARENA_ALLOCATION_TRIGGER = 30 * js::GC_CHUNK_SIZE;
|
||||||
*/
|
*/
|
||||||
const float GC_HEAP_GROWTH_FACTOR = 3.0f;
|
const float GC_HEAP_GROWTH_FACTOR = 3.0f;
|
||||||
|
|
||||||
|
/* Perform a Full GC every 20 seconds if MaybeGC is called */
|
||||||
|
static const int64 GC_IDLE_FULL_SPAN = 20 * 1000 * 1000;
|
||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
GetFinalizableTraceKind(size_t thingKind)
|
GetFinalizableTraceKind(size_t thingKind)
|
||||||
{
|
{
|
||||||
|
@ -1048,7 +1051,10 @@ typedef enum JSGCInvocationKind {
|
||||||
* Called from js_DestroyContext for last JSContext in a JSRuntime, when
|
* Called from js_DestroyContext for last JSContext in a JSRuntime, when
|
||||||
* it is imperative that rt->gcPoke gets cleared early in js_GC.
|
* it is imperative that rt->gcPoke gets cleared early in js_GC.
|
||||||
*/
|
*/
|
||||||
GC_LAST_CONTEXT = 1
|
GC_LAST_CONTEXT = 1,
|
||||||
|
|
||||||
|
/* Minimize GC triggers and release empty GC chunks right away. */
|
||||||
|
GC_SHRINK = 2
|
||||||
} JSGCInvocationKind;
|
} JSGCInvocationKind;
|
||||||
|
|
||||||
/* Pass NULL for |comp| to get a full GC. */
|
/* Pass NULL for |comp| to get a full GC. */
|
||||||
|
@ -1098,6 +1104,7 @@ class GCHelperThread {
|
||||||
PRCondVar* wakeup;
|
PRCondVar* wakeup;
|
||||||
PRCondVar* sweepingDone;
|
PRCondVar* sweepingDone;
|
||||||
bool shutdown;
|
bool shutdown;
|
||||||
|
JSGCInvocationKind lastGCKind;
|
||||||
|
|
||||||
Vector<void **, 16, js::SystemAllocPolicy> freeVector;
|
Vector<void **, 16, js::SystemAllocPolicy> freeVector;
|
||||||
void **freeCursor;
|
void **freeCursor;
|
||||||
|
@ -1137,7 +1144,7 @@ class GCHelperThread {
|
||||||
void finish(JSRuntime *rt);
|
void finish(JSRuntime *rt);
|
||||||
|
|
||||||
/* Must be called with GC lock taken. */
|
/* Must be called with GC lock taken. */
|
||||||
void startBackgroundSweep(JSRuntime *rt);
|
void startBackgroundSweep(JSRuntime *rt, JSGCInvocationKind gckind);
|
||||||
|
|
||||||
void waitBackgroundSweepEnd(JSRuntime *rt, bool gcUnlocked = true);
|
void waitBackgroundSweepEnd(JSRuntime *rt, bool gcUnlocked = true);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче