From 7a2a29c947f081e09df2b8a3f7cc0963a5568fc4 Mon Sep 17 00:00:00 2001 From: Till Schneidereit Date: Tue, 8 May 2012 18:49:13 -0400 Subject: [PATCH] Bug 723350 - Improve last-ditch GC trigger. r=billm --- js/src/jsapi.cpp | 1 - js/src/jscntxt.cpp | 14 +------------- js/src/jscntxt.h | 24 +----------------------- js/src/jscompartment.cpp | 8 ++------ js/src/jscompartment.h | 16 +++++++++++----- js/src/jsgc.cpp | 5 ++--- 6 files changed, 17 insertions(+), 51 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 0c18cf96ef1..290f32bc1dd 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -757,7 +757,6 @@ JSRuntime::JSRuntime() gcCallback(NULL), gcSliceCallback(NULL), gcFinalizeCallback(NULL), - gcMallocBytes(0), gcBlackRootsTraceOp(NULL), gcBlackRootsData(NULL), gcGrayRootsTraceOp(NULL), diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index fde86a9f215..afe73b52281 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -1102,22 +1102,10 @@ JSContext::runningWithTrustedPrincipals() const void JSRuntime::updateMallocCounter(JSContext *cx, size_t nbytes) { - /* We tolerate any thread races when updating gcMallocBytes. */ - ptrdiff_t oldCount = gcMallocBytes; - ptrdiff_t newCount = oldCount - ptrdiff_t(nbytes); - gcMallocBytes = newCount; - if (JS_UNLIKELY(newCount <= 0 && oldCount > 0)) - onTooMuchMalloc(); - else if (cx && cx->compartment) + if (cx && cx->compartment) cx->compartment->updateMallocCounter(nbytes); } -JS_FRIEND_API(void) -JSRuntime::onTooMuchMalloc() -{ - TriggerGC(this, gcreason::TOO_MUCH_MALLOC); -} - JS_FRIEND_API(void *) JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx) { diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index aa7cd9332cc..80c434e7b8c 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -644,13 +644,6 @@ struct JSRuntime : js::RuntimeFriendFields js::GCSliceCallback gcSliceCallback; JSFinalizeCallback gcFinalizeCallback; - private: - /* - * Malloc counter to measure memory pressure for GC scheduling. It runs - * from gcMaxMallocBytes down to zero. - */ - volatile ptrdiff_t gcMallocBytes; - public: /* * The trace operations to trace embedding-specific GC roots. One is for @@ -855,17 +848,8 @@ struct JSRuntime : js::RuntimeFriendFields JS_DECLARE_NEW_METHODS(malloc_, JS_ALWAYS_INLINE) JS_DECLARE_DELETE_METHODS(free_, JS_ALWAYS_INLINE) - bool isGCMallocLimitReached() const { return gcMallocBytes <= 0; } - - void resetGCMallocBytes() { gcMallocBytes = ptrdiff_t(gcMaxMallocBytes); } - void setGCMaxMallocBytes(size_t value) { - /* - * For compatibility treat any value that exceeds PTRDIFF_T_MAX to - * mean that value. - */ - gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1; - resetGCMallocBytes(); + gcMaxMallocBytes = value; } /* @@ -877,12 +861,6 @@ struct JSRuntime : js::RuntimeFriendFields * the caller must ensure that no deadlock possible during OOM reporting. */ void updateMallocCounter(JSContext *cx, size_t nbytes); - - /* - * The function must be called outside the GC lock. - */ - JS_FRIEND_API(void) onTooMuchMalloc(); - /* * This should be called after system malloc/realloc returns NULL to try * to recove some memory or to report an error. Failures in malloc and diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index c8be5a0893e..9d7e4b72f28 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -535,17 +535,13 @@ JSCompartment::purge() void JSCompartment::resetGCMallocBytes() { - gcMallocBytes = ptrdiff_t(gcMaxMallocBytes); + gcMallocBytes = gcMaxMallocBytes; } void JSCompartment::setGCMaxMallocBytes(size_t value) { - /* - * For compatibility treat any value that exceeds PTRDIFF_T_MAX to - * mean that value. - */ - gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1; + gcMaxMallocBytes = value; resetGCMallocBytes(); } diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 6cc00482460..460ae8c751e 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -178,7 +178,6 @@ struct JSCompartment size_t gcBytes; size_t gcTriggerBytes; - size_t gcMaxMallocBytes; bool hold; bool isSystemCompartment; @@ -245,7 +244,8 @@ struct JSCompartment * gcMaxMallocBytes down to zero. This counter should be used only when it's * not possible to know the size of a free. */ - ptrdiff_t gcMallocBytes; + size_t gcMallocBytes; + size_t gcMaxMallocBytes; enum { DebugFromC = 1, DebugFromJS = 2 }; @@ -281,13 +281,19 @@ struct JSCompartment void resetGCMallocBytes(); void setGCMaxMallocBytes(size_t value); void updateMallocCounter(size_t nbytes) { - ptrdiff_t oldCount = gcMallocBytes; - ptrdiff_t newCount = oldCount - ptrdiff_t(nbytes); + size_t oldCount = gcMallocBytes; + size_t newCount = oldCount - nbytes; gcMallocBytes = newCount; - if (JS_UNLIKELY(newCount <= 0 && oldCount > 0)) + // gcMallocBytes will wrap around and be bigger than gcMaxAllocBytes if a signed value + // would be < 0 + if (JS_UNLIKELY(oldCount <= gcMaxMallocBytes && newCount > gcMaxMallocBytes)) onTooMuchMalloc(); } + bool isTooMuchMalloc() const { + return gcMallocBytes > gcMaxMallocBytes; + } + void onTooMuchMalloc(); void mallocInCompartment(size_t nbytes) { diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 49ce6fdbf8f..8b3021fe63f 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1666,7 +1666,8 @@ ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind) JSRuntime *rt = comp->rt; JS_ASSERT(!rt->gcRunning); - bool runGC = rt->gcIncrementalState != NO_INCREMENTAL && comp->gcBytes > comp->gcTriggerBytes; + bool runGC = rt->gcIncrementalState != NO_INCREMENTAL && + (comp->gcBytes > comp->gcTriggerBytes || comp->isTooMuchMalloc()); for (;;) { if (JS_UNLIKELY(runGC)) { PrepareCompartmentForGC(comp); @@ -3308,8 +3309,6 @@ AutoGCSession::AutoGCSession(JSRuntime *rt) runtime->gcNumber++; - runtime->resetGCMallocBytes(); - /* Clear gcMallocBytes for all compartments */ for (CompartmentsIter c(runtime); !c.done(); c.next()) c->resetGCMallocBytes();