зеркало из https://github.com/mozilla/gecko-dev.git
bug 713916 - JS API to shrink GC buffers. r=wmccloskey
This commit is contained in:
Родитель
7f5979a559
Коммит
7c688c1bdd
|
@ -1592,13 +1592,13 @@ JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
|
|||
* Retry when we are done with the background sweeping and have stopped
|
||||
* all the allocations and released the empty GC chunks.
|
||||
*/
|
||||
{
|
||||
ShrinkGCBuffers(this);
|
||||
#ifdef JS_THREADSAFE
|
||||
{
|
||||
AutoLockGC lock(this);
|
||||
gcHelperThread.waitBackgroundSweepOrAllocEnd();
|
||||
#endif
|
||||
gcChunkPool.expireAndFree(this, true);
|
||||
}
|
||||
#endif
|
||||
if (!p)
|
||||
p = OffTheBooks::malloc_(nbytes);
|
||||
else if (p == reinterpret_cast<void *>(1))
|
||||
|
|
|
@ -125,12 +125,18 @@ JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObj
|
|||
return obj;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_FRIEND_API(void)
|
||||
JS_ShrinkingGC(JSContext *cx)
|
||||
{
|
||||
js_GC(cx, NULL, GC_SHRINK, gcstats::PUBLIC_API);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
JS_ShrinkGCBuffers(JSRuntime *rt)
|
||||
{
|
||||
ShrinkGCBuffers(rt);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSPrincipals *)
|
||||
JS_GetCompartmentPrincipals(JSCompartment *compartment)
|
||||
{
|
||||
|
|
|
@ -73,6 +73,9 @@ JS_ObjectCountDynamicSlots(JSObject *obj);
|
|||
extern JS_FRIEND_API(void)
|
||||
JS_ShrinkingGC(JSContext *cx);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
JS_ShrinkGCBuffers(JSRuntime *rt);
|
||||
|
||||
extern JS_FRIEND_API(size_t)
|
||||
JS_GetE4XObjectsCreated(JSContext *cx);
|
||||
|
||||
|
|
|
@ -2423,28 +2423,53 @@ GCHelperThread::threadLoop()
|
|||
}
|
||||
|
||||
bool
|
||||
GCHelperThread::prepareForBackgroundSweep(JSContext *cx)
|
||||
GCHelperThread::prepareForBackgroundSweep()
|
||||
{
|
||||
JS_ASSERT(cx->runtime == rt);
|
||||
JS_ASSERT(state == IDLE);
|
||||
size_t maxArenaLists = MAX_BACKGROUND_FINALIZE_KINDS * rt->compartments.length();
|
||||
if (!finalizeVector.reserve(maxArenaLists))
|
||||
return false;
|
||||
context = cx;
|
||||
return true;
|
||||
return finalizeVector.reserve(maxArenaLists);
|
||||
}
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
inline void
|
||||
GCHelperThread::startBackgroundSweep(bool shouldShrink)
|
||||
void
|
||||
GCHelperThread::startBackgroundSweep(JSContext *cx, bool shouldShrink)
|
||||
{
|
||||
/* The caller takes the GC lock. */
|
||||
JS_ASSERT(state == IDLE);
|
||||
JS_ASSERT(cx);
|
||||
JS_ASSERT(!finalizationContext);
|
||||
finalizationContext = cx;
|
||||
shrinkFlag = shouldShrink;
|
||||
state = SWEEPING;
|
||||
PR_NotifyCondVar(wakeup);
|
||||
}
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void
|
||||
GCHelperThread::startBackgroundShrink()
|
||||
{
|
||||
switch (state) {
|
||||
case IDLE:
|
||||
JS_ASSERT(!finalizationContext);
|
||||
shrinkFlag = true;
|
||||
state = SWEEPING;
|
||||
PR_NotifyCondVar(wakeup);
|
||||
break;
|
||||
case SWEEPING:
|
||||
shrinkFlag = true;
|
||||
break;
|
||||
case ALLOCATING:
|
||||
case CANCEL_ALLOCATION:
|
||||
/*
|
||||
* If we have started background allocation there is nothing to
|
||||
* shrink.
|
||||
*/
|
||||
break;
|
||||
case SHUTDOWN:
|
||||
JS_NOT_REACHED("No shrink on shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void
|
||||
GCHelperThread::waitBackgroundSweepEnd()
|
||||
|
@ -2496,9 +2521,8 @@ GCHelperThread::replenishAndFreeLater(void *ptr)
|
|||
void
|
||||
GCHelperThread::doSweep()
|
||||
{
|
||||
JS_ASSERT(context);
|
||||
|
||||
{
|
||||
if (JSContext *cx = finalizationContext) {
|
||||
finalizationContext = NULL;
|
||||
AutoUnlockGC unlock(rt);
|
||||
|
||||
/*
|
||||
|
@ -2506,11 +2530,9 @@ GCHelperThread::doSweep()
|
|||
* finalizeObjects.
|
||||
*/
|
||||
for (ArenaHeader **i = finalizeVector.begin(); i != finalizeVector.end(); ++i)
|
||||
ArenaLists::backgroundFinalize(context, *i);
|
||||
ArenaLists::backgroundFinalize(cx, *i);
|
||||
finalizeVector.resize(0);
|
||||
|
||||
context = NULL;
|
||||
|
||||
if (freeCursor) {
|
||||
void **array = freeCursorEnd - FREE_ARRAY_LENGTH;
|
||||
freeElementsAndArray(array, freeCursor);
|
||||
|
@ -2525,7 +2547,18 @@ GCHelperThread::doSweep()
|
|||
freeVector.resize(0);
|
||||
}
|
||||
|
||||
ExpireChunksAndArenas(rt, shouldShrink());
|
||||
bool shrinking = shrinkFlag;
|
||||
ExpireChunksAndArenas(rt, shrinking);
|
||||
|
||||
/*
|
||||
* The main thread may have called ShrinkGCBuffers while
|
||||
* ExpireChunksAndArenas(rt, false) was running, so we recheck the flag
|
||||
* afterwards.
|
||||
*/
|
||||
if (!shrinking && shrinkFlag) {
|
||||
shrinkFlag = false;
|
||||
ExpireChunksAndArenas(rt, true);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
@ -3008,7 +3041,7 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
|
|||
JS_ASSERT(!cx->gcBackgroundFree);
|
||||
rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
|
||||
if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
|
||||
if (rt->gcHelperThread.prepareForBackgroundSweep(cx))
|
||||
if (rt->gcHelperThread.prepareForBackgroundSweep())
|
||||
cx->gcBackgroundFree = &rt->gcHelperThread;
|
||||
}
|
||||
#endif
|
||||
|
@ -3022,7 +3055,7 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
|
|||
if (cx->gcBackgroundFree) {
|
||||
JS_ASSERT(cx->gcBackgroundFree == &rt->gcHelperThread);
|
||||
cx->gcBackgroundFree = NULL;
|
||||
rt->gcHelperThread.startBackgroundSweep(gckind == GC_SHRINK);
|
||||
rt->gcHelperThread.startBackgroundSweep(cx, gckind == GC_SHRINK);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3100,6 +3133,18 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcstats::Re
|
|||
|
||||
namespace js {
|
||||
|
||||
void
|
||||
ShrinkGCBuffers(JSRuntime *rt)
|
||||
{
|
||||
AutoLockGC lock(rt);
|
||||
JS_ASSERT(!rt->gcRunning);
|
||||
#ifndef JS_THREADSAFE
|
||||
ExpireChunksAndArenas(rt, true);
|
||||
#else
|
||||
rt->gcHelperThread.startBackgroundShrink();
|
||||
#endif
|
||||
}
|
||||
|
||||
class AutoCopyFreeListToArenas {
|
||||
JSRuntime *rt;
|
||||
|
||||
|
@ -3312,7 +3357,7 @@ RunDebugGC(JSContext *cx)
|
|||
rt->gcTriggerCompartment = rt->gcDebugCompartmentGC ? cx->compartment : NULL;
|
||||
if (rt->gcTriggerCompartment == rt->atomsCompartment)
|
||||
rt->gcTriggerCompartment = NULL;
|
||||
|
||||
|
||||
RunLastDitchGC(cx);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1388,6 +1388,9 @@ TriggerCompartmentGC(JSCompartment *comp, js::gcstats::Reason reason);
|
|||
extern void
|
||||
MaybeGC(JSContext *cx);
|
||||
|
||||
extern void
|
||||
ShrinkGCBuffers(JSRuntime *rt);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
|
@ -1459,7 +1462,7 @@ class GCHelperThread {
|
|||
PRCondVar *done;
|
||||
volatile State state;
|
||||
|
||||
JSContext *context;
|
||||
JSContext *finalizationContext;
|
||||
bool shrinkFlag;
|
||||
|
||||
Vector<void **, 16, js::SystemAllocPolicy> freeVector;
|
||||
|
@ -1495,6 +1498,8 @@ class GCHelperThread {
|
|||
wakeup(NULL),
|
||||
done(NULL),
|
||||
state(IDLE),
|
||||
finalizationContext(NULL),
|
||||
shrinkFlag(false),
|
||||
freeCursor(NULL),
|
||||
freeCursorEnd(NULL),
|
||||
backgroundAllocation(true)
|
||||
|
@ -1504,7 +1509,10 @@ class GCHelperThread {
|
|||
void finish();
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
inline void startBackgroundSweep(bool shouldShrink);
|
||||
void startBackgroundSweep(JSContext *cx, bool shouldShrink);
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void startBackgroundShrink();
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void waitBackgroundSweepEnd();
|
||||
|
@ -1549,7 +1557,7 @@ class GCHelperThread {
|
|||
}
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
bool prepareForBackgroundSweep(JSContext *cx);
|
||||
bool prepareForBackgroundSweep();
|
||||
};
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
|
Загрузка…
Ссылка в новой задаче