Bug 706227 - Add way for JS_GC API users to give detailed reason for invocation (r=mccr8)

This commit is contained in:
Bill McCloskey 2012-01-25 10:59:55 -08:00
parent 7b71a67efd
commit 502e67c72c
25 changed files with 163 additions and 103 deletions

View File

@ -816,7 +816,7 @@ nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener *aListener)
}
#endif
nsJSContext::GarbageCollectNow();
nsJSContext::GarbageCollectNow(js::gcreason::DOM_UTILS);
nsJSContext::CycleCollectNow(aListener);
return NS_OK;

View File

@ -2272,7 +2272,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
newInnerWindow->mChromeEventHandler = mChromeEventHandler;
}
mContext->GC();
mContext->GC(js::gcreason::SET_NEW_DOCUMENT);
mContext->DidInitializeContext();
if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
@ -2429,7 +2429,7 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
}
if (mContext) {
mContext->GC();
mContext->GC(js::gcreason::SET_DOC_SHELL);
mContext->FinalizeContext();
mContext = nsnull;
}

View File

@ -43,6 +43,7 @@
#include "nsISupports.h"
#include "nsCOMPtr.h"
#include "nsIProgrammingLanguage.h"
#include "jsfriendapi.h"
#include "jspubtd.h"
class nsIScriptGlobalObject;
@ -354,7 +355,7 @@ public:
*
* @return NS_OK if the method is successful
*/
virtual void GC() = 0;
virtual void GC(js::gcreason::Reason aReason) = 0;
/**
* Inform the context that a script was evaluated.

View File

@ -203,7 +203,7 @@ nsMemoryPressureObserver::Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData)
{
if (sGCOnMemoryPressure) {
nsJSContext::GarbageCollectNow(true);
nsJSContext::GarbageCollectNow(js::gcreason::MEM_PRESSURE, nsGCShrinking);
nsJSContext::CycleCollectNow();
}
return NS_OK;
@ -1111,7 +1111,7 @@ nsJSContext::DestroyJSContext()
js_options_dot_str, this);
if (mGCOnDestruction) {
PokeGC();
PokeGC(js::gcreason::NSJSCONTEXT_DESTROY);
}
// Let xpconnect destroy the JSContext when it thinks the time is right.
@ -3220,7 +3220,7 @@ nsJSContext::ScriptExecuted()
//static
void
nsJSContext::GarbageCollectNow(bool shrinkingGC)
nsJSContext::GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind)
{
NS_TIME_FUNCTION_MIN(1.0);
SAMPLE_LABEL("GC", "GarbageCollectNow");
@ -3238,7 +3238,7 @@ nsJSContext::GarbageCollectNow(bool shrinkingGC)
sLoadingInProgress = false;
if (nsContentUtils::XPConnect()) {
nsContentUtils::XPConnect()->GarbageCollect(shrinkingGC);
nsContentUtils::XPConnect()->GarbageCollect(reason, gckind);
}
}
@ -3276,7 +3276,7 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener)
// If we collected a substantial amount of cycles, poke the GC since more objects
// might be unreachable now.
if (sCCollectedWaitingForGC > 250) {
PokeGC();
PokeGC(js::gcreason::CC_WAITING);
}
PRTime now = PR_Now();
@ -3315,7 +3315,8 @@ GCTimerFired(nsITimer *aTimer, void *aClosure)
{
NS_RELEASE(sGCTimer);
nsJSContext::GarbageCollectNow();
uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason), nsGCNormal);
}
void
@ -3359,12 +3360,12 @@ nsJSContext::LoadEnd()
// Its probably a good idea to GC soon since we have finished loading.
sLoadingInProgress = false;
PokeGC();
PokeGC(js::gcreason::LOAD_END);
}
// static
void
nsJSContext::PokeGC()
nsJSContext::PokeGC(js::gcreason::Reason aReason)
{
if (sGCTimer) {
// There's already a timer for GC'ing, just return
@ -3380,7 +3381,7 @@ nsJSContext::PokeGC()
static bool first = true;
sGCTimer->InitWithFuncCallback(GCTimerFired, nsnull,
sGCTimer->InitWithFuncCallback(GCTimerFired, reinterpret_cast<void *>(aReason),
first
? NS_FIRST_GC_DELAY
: NS_GC_DELAY,
@ -3473,9 +3474,9 @@ nsJSContext::KillCCTimer()
}
void
nsJSContext::GC()
nsJSContext::GC(js::gcreason::Reason aReason)
{
PokeGC();
PokeGC(aReason);
}
static void
@ -3513,7 +3514,7 @@ DOMGCFinishedCallback(JSRuntime *rt, JSCompartment *comp, const char *status)
// probably a time of heavy activity and we want to delay
// the full GC, but we do want it to happen eventually.
if (comp) {
nsJSContext::PokeGC();
nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
// We poked the GC, so we can kill any pending CC here.
nsJSContext::KillCCTimer();

View File

@ -41,10 +41,12 @@
#include "nsIScriptRuntime.h"
#include "nsCOMPtr.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "nsIObserver.h"
#include "nsIXPCScriptNotify.h"
#include "prtime.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIXPConnect.h"
class nsIXPConnectJSObjectHolder;
class nsRootedJSValueArray;
@ -179,11 +181,11 @@ public:
static void LoadStart();
static void LoadEnd();
static void GarbageCollectNow(bool shrinkingGC = false);
static void GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind = nsGCNormal);
static void ShrinkGCBuffersNow();
static void CycleCollectNow(nsICycleCollectorListener *aListener = nsnull);
static void PokeGC();
static void PokeGC(js::gcreason::Reason aReason);
static void KillGCTimer();
static void PokeShrinkGCBuffers();
@ -193,7 +195,7 @@ public:
static void MaybePokeCC();
static void KillCCTimer();
virtual void GC();
virtual void GC(js::gcreason::Reason aReason);
protected:
nsresult InitializeExternalClasses();

View File

@ -800,14 +800,14 @@ ContentChild::GetIndexedDBPath()
bool
ContentChild::RecvGarbageCollect()
{
nsJSContext::GarbageCollectNow();
nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC);
return true;
}
bool
ContentChild::RecvCycleCollect()
{
nsJSContext::GarbageCollectNow();
nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC);
nsJSContext::CycleCollectNow();
return true;
}

View File

@ -3794,10 +3794,10 @@ WorkerPrivate::GarbageCollectInternal(JSContext* aCx, bool aShrinking,
AssertIsOnWorkerThread();
if (aShrinking) {
JS_ShrinkingGC(aCx);
js::ShrinkingGC(aCx, js::gcreason::DOM_WORKER);
}
else {
JS_GC(aCx);
js::GCForReason(aCx, js::gcreason::DOM_WORKER);
}
if (aCollectChildren) {

View File

@ -38,6 +38,7 @@
* ***** END LICENSE BLOCK ***** */
#include <stdio.h>
#include <ctype.h>
#include "jscntxt.h"
#include "jscrashformat.h"
@ -52,6 +53,22 @@
namespace js {
namespace gcstats {
static const char *
ExplainReason(gcreason::Reason reason)
{
switch (reason) {
#define SWITCH_REASON(name) \
case gcreason::name: \
return #name;
GCREASONS(SWITCH_REASON)
default:
JS_NOT_REACHED("bad GC reason");
return "?";
#undef SWITCH_REASON
}
}
Statistics::ColumnInfo::ColumnInfo(const char *title, double t, double total)
: title(title)
{
@ -117,8 +134,8 @@ Statistics::makeTable(ColumnInfo *cols)
}
Statistics::Statistics(JSRuntime *rt)
: runtime(rt)
, triggerReason(PUBLIC_API) //dummy reason to satisfy makeTable
: runtime(rt),
triggerReason(gcreason::NO_REASON)
{
PodArrayZero(counts);
PodArrayZero(totals);
@ -178,7 +195,7 @@ struct GCCrashData
};
void
Statistics::beginGC(JSCompartment *comp, Reason reason)
Statistics::beginGC(JSCompartment *comp, gcreason::Reason reason)
{
compartment = comp;
@ -276,7 +293,6 @@ Statistics::endGC()
if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
(*cb)(JS_TELEMETRY_GC_REASON, triggerReason);
(*cb)(JS_TELEMETRY_GC_IS_COMPARTMENTAL, compartment ? 1 : 0);
(*cb)(JS_TELEMETRY_GC_IS_SHAPE_REGEN, 0);
(*cb)(JS_TELEMETRY_GC_MS, t(PHASE_GC));
(*cb)(JS_TELEMETRY_GC_MARK_MS, t(PHASE_MARK));
(*cb)(JS_TELEMETRY_GC_SWEEP_MS, t(PHASE_SWEEP));

View File

@ -42,6 +42,7 @@
#include <string.h>
#include "jsfriendapi.h"
#include "jspubtd.h"
#include "jsutil.h"
@ -50,32 +51,6 @@ struct JSCompartment;
namespace js {
namespace gcstats {
enum Reason {
PUBLIC_API,
MAYBEGC,
LASTCONTEXT,
DESTROYCONTEXT,
LASTDITCH,
TOOMUCHMALLOC,
ALLOCTRIGGER,
CHUNK,
SHAPE,
REFILL
};
static const int NUM_REASONS = REFILL + 1;
static inline const char *
ExplainReason(Reason r)
{
static const char *strs[] = {" API", "Maybe", "LastC", "DestC", "LastD",
"Mallc", "Alloc", "Chunk", "Shape", "Refil"};
JS_ASSERT(strcmp(strs[SHAPE], "Shape") == 0 &&
sizeof(strs) / sizeof(strs[0]) == NUM_REASONS);
return strs[r];
}
enum Phase {
PHASE_GC,
PHASE_MARK,
@ -103,7 +78,7 @@ struct Statistics {
Statistics(JSRuntime *rt);
~Statistics();
void beginGC(JSCompartment *comp, Reason reason);
void beginGC(JSCompartment *comp, gcreason::Reason reason);
void endGC();
void beginPhase(Phase phase);
@ -122,7 +97,7 @@ struct Statistics {
FILE *fp;
bool fullFormat;
Reason triggerReason;
gcreason::Reason triggerReason;
JSCompartment *compartment;
uint64_t phaseStarts[PHASE_LIMIT];
@ -140,8 +115,8 @@ struct Statistics {
struct ColumnInfo {
const char *title;
char str[12];
char totalStr[12];
char str[32];
char totalStr[32];
int width;
ColumnInfo() {}
@ -155,7 +130,8 @@ struct Statistics {
};
struct AutoGC {
AutoGC(Statistics &stats, JSCompartment *comp, Reason reason JS_GUARD_OBJECT_NOTIFIER_PARAM)
AutoGC(Statistics &stats, JSCompartment *comp, gcreason::Reason reason
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: stats(stats) { JS_GUARD_OBJECT_NOTIFIER_INIT; stats.beginGC(comp, reason); }
~AutoGC() { stats.endGC(); }

View File

@ -735,6 +735,7 @@ JSRuntime::JSRuntime()
gcIsNeeded(0),
gcWeakMapList(NULL),
gcStats(thisFromCtor()),
gcTriggerReason(gcreason::NO_REASON),
gcTriggerCompartment(NULL),
gcCurrentCompartment(NULL),
gcCheckCompartment(NULL),
@ -2857,7 +2858,7 @@ JS_CompartmentGC(JSContext *cx, JSCompartment *comp)
JS_ASSERT(comp != cx->runtime->atomsCompartment);
js::gc::VerifyBarriers(cx, true);
js_GC(cx, comp, GC_NORMAL, gcstats::PUBLIC_API);
js_GC(cx, comp, GC_NORMAL, gcreason::API);
}
JS_PUBLIC_API(void)

View File

@ -323,13 +323,13 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
#endif
if (last) {
js_GC(cx, NULL, GC_NORMAL, gcstats::LASTCONTEXT);
js_GC(cx, NULL, GC_NORMAL, gcreason::LAST_CONTEXT);
/* Take the runtime down, now that it has no contexts or atoms. */
JS_LOCK_GC(rt);
} else {
if (mode == JSDCM_FORCE_GC)
js_GC(cx, NULL, GC_NORMAL, gcstats::DESTROYCONTEXT);
js_GC(cx, NULL, GC_NORMAL, gcreason::DESTROY_CONTEXT);
else if (mode == JSDCM_MAYBE_GC)
JS_MaybeGC(cx);
@ -1179,7 +1179,7 @@ JSContext::runningWithTrustedPrincipals() const
JS_FRIEND_API(void)
JSRuntime::onTooMuchMalloc()
{
TriggerGC(this, gcstats::TOOMUCHMALLOC);
TriggerGC(this, gcreason::TOO_MUCH_MALLOC);
}
JS_FRIEND_API(void *)

View File

@ -318,7 +318,7 @@ struct JSRuntime
js::gcstats::Statistics gcStats;
/* The reason that an interrupt-triggered GC should be called. */
js::gcstats::Reason gcTriggerReason;
js::gcreason::Reason gcTriggerReason;
/* Pre-allocated space for the GC mark stack. */
uintptr_t gcMarkStackArray[js::MARK_STACK_LENGTH];

View File

@ -128,9 +128,15 @@ JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObj
}
JS_FRIEND_API(void)
JS_ShrinkingGC(JSContext *cx)
js::GCForReason(JSContext *cx, gcreason::Reason reason)
{
js_GC(cx, NULL, GC_SHRINK, gcstats::PUBLIC_API);
js_GC(cx, NULL, GC_NORMAL, reason);
}
JS_FRIEND_API(void)
js::ShrinkingGC(JSContext *cx, gcreason::Reason reason)
{
js_GC(cx, NULL, GC_SHRINK, reason);
}
JS_FRIEND_API(void)

View File

@ -72,9 +72,6 @@ JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObj
extern JS_FRIEND_API(uint32_t)
JS_ObjectCountDynamicSlots(JSObject *obj);
extern JS_FRIEND_API(void)
JS_ShrinkingGC(JSContext *cx);
extern JS_FRIEND_API(void)
JS_ShrinkGCBuffers(JSRuntime *rt);
@ -101,7 +98,6 @@ JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape);
enum {
JS_TELEMETRY_GC_REASON,
JS_TELEMETRY_GC_IS_COMPARTMENTAL,
JS_TELEMETRY_GC_IS_SHAPE_REGEN,
JS_TELEMETRY_GC_MS,
JS_TELEMETRY_GC_MARK_MS,
JS_TELEMETRY_GC_SWEEP_MS
@ -572,6 +568,56 @@ GetRuntimeCompartments(JSRuntime *rt);
extern JS_FRIEND_API(size_t)
SizeOfJSContext();
#define GCREASONS(D) \
/* Reasons internal to the JS engine */ \
D(API) \
D(MAYBEGC) \
D(LAST_CONTEXT) \
D(DESTROY_CONTEXT) \
D(LAST_DITCH) \
D(TOO_MUCH_MALLOC) \
D(ALLOC_TRIGGER) \
D(UNUSED1) /* was CHUNK */ \
D(UNUSED2) /* was SHAPE */ \
D(UNUSED3) /* was REFILL */ \
\
/* Reasons from Firefox */ \
D(DOM_WINDOW_UTILS) \
D(COMPONENT_UTILS) \
D(MEM_PRESSURE) \
D(CC_WAITING) \
D(CC_FORCED) \
D(LOAD_END) \
D(POST_COMPARTMENT) \
D(PAGE_HIDE) \
D(NSJSCONTEXT_DESTROY) \
D(SET_NEW_DOCUMENT) \
D(SET_DOC_SHELL) \
D(DOM_UTILS) \
D(DOM_IPC) \
D(DOM_WORKER) \
D(INTER_SLICE_GC) \
D(REFRESH_FRAME)
namespace gcreason {
/* GCReasons will end up looking like JSGC_MAYBEGC */
enum Reason {
#define MAKE_REASON(name) name,
GCREASONS(MAKE_REASON)
#undef MAKE_REASON
NO_REASON,
NUM_REASONS
};
} /* namespace gcreason */
extern JS_FRIEND_API(void)
GCForReason(JSContext *cx, gcreason::Reason reason);
extern JS_FRIEND_API(void)
ShrinkingGC(JSContext *cx, gcreason::Reason reason);
extern JS_FRIEND_API(bool)
IsIncrementalBarrierNeeded(JSRuntime *rt);

View File

@ -742,7 +742,7 @@ Chunk::allocateArena(JSCompartment *comp, AllocKind thingKind)
rt->gcBytes += ArenaSize;
comp->gcBytes += ArenaSize;
if (comp->gcBytes >= comp->gcTriggerBytes)
TriggerCompartmentGC(comp, gcstats::ALLOCTRIGGER);
TriggerCompartmentGC(comp, gcreason::ALLOC_TRIGGER);
return aheader;
}
@ -1647,7 +1647,7 @@ RunLastDitchGC(JSContext *cx)
/* The last ditch GC preserves all atoms. */
AutoKeepAtoms keep(rt);
js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL, gcstats::LASTDITCH);
js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL, gcreason::LAST_DITCH);
}
/* static */ void *
@ -2137,7 +2137,7 @@ MarkRuntime(JSTracer *trc)
}
void
TriggerGC(JSRuntime *rt, gcstats::Reason reason)
TriggerGC(JSRuntime *rt, gcreason::Reason reason)
{
JS_ASSERT(rt->onOwnerThread());
@ -2152,7 +2152,7 @@ TriggerGC(JSRuntime *rt, gcstats::Reason reason)
}
void
TriggerCompartmentGC(JSCompartment *comp, gcstats::Reason reason)
TriggerCompartmentGC(JSCompartment *comp, gcreason::Reason reason)
{
JSRuntime *rt = comp->rt;
JS_ASSERT(!rt->gcRunning);
@ -2198,18 +2198,18 @@ MaybeGC(JSContext *cx)
JS_ASSERT(rt->onOwnerThread());
if (rt->gcZeal()) {
js_GC(cx, NULL, GC_NORMAL, gcstats::MAYBEGC);
js_GC(cx, NULL, GC_NORMAL, gcreason::MAYBEGC);
return;
}
JSCompartment *comp = cx->compartment;
if (rt->gcIsNeeded) {
js_GC(cx, (comp == rt->gcTriggerCompartment) ? comp : NULL, GC_NORMAL, gcstats::MAYBEGC);
js_GC(cx, (comp == rt->gcTriggerCompartment) ? comp : NULL, GC_NORMAL, gcreason::MAYBEGC);
return;
}
if (comp->gcBytes > 8192 && comp->gcBytes >= 3 * (comp->gcTriggerBytes / 4)) {
js_GC(cx, (rt->gcMode == JSGC_MODE_COMPARTMENT) ? comp : NULL, GC_NORMAL, gcstats::MAYBEGC);
js_GC(cx, (rt->gcMode == JSGC_MODE_COMPARTMENT) ? comp : NULL, GC_NORMAL, gcreason::MAYBEGC);
return;
}
@ -2223,7 +2223,7 @@ MaybeGC(JSContext *cx)
if (rt->gcChunkAllocationSinceLastGC ||
rt->gcNumArenasFreeCommitted > FreeCommittedArenasThreshold)
{
js_GC(cx, NULL, GC_SHRINK, gcstats::MAYBEGC);
js_GC(cx, NULL, GC_SHRINK, gcreason::MAYBEGC);
} else {
rt->gcNextFullGCTime = now + GC_IDLE_FULL_SPAN;
}
@ -2966,7 +2966,7 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
}
void
js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcstats::Reason reason)
js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcreason::Reason reason)
{
JSRuntime *rt = cx->runtime;
JS_AbortIfWrongThread(rt);

View File

@ -1382,11 +1382,11 @@ MarkContext(JSTracer *trc, JSContext *acx);
/* Must be called with GC lock taken. */
extern void
TriggerGC(JSRuntime *rt, js::gcstats::Reason reason);
TriggerGC(JSRuntime *rt, js::gcreason::Reason reason);
/* Must be called with GC lock taken. */
extern void
TriggerCompartmentGC(JSCompartment *comp, js::gcstats::Reason reason);
TriggerCompartmentGC(JSCompartment *comp, js::gcreason::Reason reason);
extern void
MaybeGC(JSContext *cx);
@ -1409,7 +1409,7 @@ typedef enum JSGCInvocationKind {
/* Pass NULL for |comp| to get a full GC. */
extern void
js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, js::gcstats::Reason r);
js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, js::gcreason::Reason r);
namespace js {

View File

@ -390,9 +390,15 @@ interface nsIXPCFunctionThisTranslator : nsISupports
#define NS_XPCONNECT_CID \
{ 0xcb6593e0, 0xf9b2, 0x11d2, \
{ 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
enum nsGCType {
nsGCNormal,
nsGCShrinking,
nsGCIncremental
};
%}
[uuid(241e6db3-e018-4d99-b976-c782a05f9c77)]
[uuid(686bb1d0-4711-11e1-b86c-0800200c9a66)]
interface nsIXPConnect : nsISupports
{
%{ C++
@ -723,8 +729,10 @@ interface nsIXPConnect : nsISupports
/**
* Trigger a JS garbage collection.
* Use a js::gcreason::Reason from jsfriendapi.h for the kind.
* Use the nsGCType enum for the kind.
*/
void GarbageCollect(in boolean shrinkingGC);
void GarbageCollect(in PRUint32 reason, in PRUint32 kind);
/**
* Define quick stubs on the given object, @a proto.

View File

@ -3600,7 +3600,7 @@ nsXPCComponents_Utils::GetWeakReference(const JS::Value &object, JSContext *cx,
NS_IMETHODIMP
nsXPCComponents_Utils::ForceGC(JSContext *cx)
{
JS_GC(cx);
js::GCForReason(cx, js::gcreason::COMPONENT_UTILS);
return NS_OK;
}
@ -3608,7 +3608,7 @@ nsXPCComponents_Utils::ForceGC(JSContext *cx)
NS_IMETHODIMP
nsXPCComponents_Utils::ForceShrinkingGC(JSContext *cx)
{
JS_ShrinkingGC(cx);
js::ShrinkingGC(cx, js::gcreason::COMPONENT_UTILS);
return NS_OK;
}
@ -3636,9 +3636,9 @@ class PreciseGCRunnable : public nsRunnable
}
if (mShrinking)
JS_ShrinkingGC(mCx);
js::ShrinkingGC(mCx, js::gcreason::COMPONENT_UTILS);
else
JS_GC(mCx);
js::GCForReason(mCx, js::gcreason::COMPONENT_UTILS);
mCallback->Callback();
return NS_OK;

View File

@ -1870,9 +1870,6 @@ AccumulateTelemetryCallback(int id, uint32_t sample)
case JS_TELEMETRY_GC_IS_COMPARTMENTAL:
Telemetry::Accumulate(Telemetry::GC_IS_COMPARTMENTAL, sample);
break;
case JS_TELEMETRY_GC_IS_SHAPE_REGEN:
Telemetry::Accumulate(Telemetry::GC_IS_SHAPE_REGEN, sample);
break;
case JS_TELEMETRY_GC_MS:
Telemetry::Accumulate(Telemetry::GC_MS, sample);
break;

View File

@ -365,7 +365,7 @@ nsXPConnect::NeedCollect()
}
void
nsXPConnect::Collect(bool shrinkingGC)
nsXPConnect::Collect(PRUint32 reason, PRUint32 kind)
{
// We're dividing JS objects into 2 categories:
//
@ -424,16 +424,20 @@ nsXPConnect::Collect(bool shrinkingGC)
// XPCCallContext::Init we disable the conservative scanner if that call
// has started the request on this thread.
js::AutoSkipConservativeScan ascs(cx);
if (shrinkingGC)
JS_ShrinkingGC(cx);
else
JS_GC(cx);
MOZ_ASSERT(reason < js::gcreason::NUM_REASONS);
js::gcreason::Reason gcreason = (js::gcreason::Reason)reason;
if (kind == nsGCShrinking) {
js::ShrinkingGC(cx, gcreason);
} else {
MOZ_ASSERT(kind == nsGCNormal);
js::GCForReason(cx, gcreason);
}
}
NS_IMETHODIMP
nsXPConnect::GarbageCollect(bool shrinkingGC)
nsXPConnect::GarbageCollect(PRUint32 reason, PRUint32 kind)
{
Collect(shrinkingGC);
Collect(reason, kind);
return NS_OK;
}

View File

@ -549,7 +549,7 @@ public:
virtual nsresult FinishCycleCollection();
virtual nsCycleCollectionParticipant *ToParticipant(void *p);
virtual bool NeedCollect();
virtual void Collect(bool shrinkingGC=false);
virtual void Collect(PRUint32 reason, PRUint32 kind);
#ifdef DEBUG_CC
virtual void PrintAllReferencesTo(void *p);
#endif

View File

@ -198,6 +198,8 @@ static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printset
#include "mozilla/dom/Element.h"
#include "jsfriendapi.h"
using namespace mozilla;
#ifdef NS_DEBUG
@ -1287,7 +1289,7 @@ DocumentViewerImpl::PageHide(bool aIsUnload)
if (aIsUnload) {
// Poke the GC. The window might be collectable garbage now.
nsJSContext::PokeGC();
nsJSContext::PokeGC(js::gcreason::PAGE_HIDE);
// if Destroy() was called during OnPageHide(), mDocument is nsnull.
NS_ENSURE_STATE(mDocument);

View File

@ -75,7 +75,6 @@ HISTOGRAM(CYCLE_COLLECTOR_TIME_BETWEEN, 1, 120, 50, EXPONENTIAL, "Time spent in
*/
HISTOGRAM(GC_REASON, 1, 20, 20, LINEAR, "Reason (enum value) for initiating a GC")
HISTOGRAM_BOOLEAN(GC_IS_COMPARTMENTAL, "Is it a compartmental GC?")
HISTOGRAM_BOOLEAN(GC_IS_SHAPE_REGEN, "Is it a shape regenerating GC?")
HISTOGRAM(GC_MS, 1, 10000, 50, EXPONENTIAL, "Time spent running JS GC (ms)")
HISTOGRAM(GC_MARK_MS, 1, 10000, 50, EXPONENTIAL, "Time spent running JS GC mark phase (ms)")
HISTOGRAM(GC_SWEEP_MS, 1, 10000, 50, EXPONENTIAL, "Time spent running JS GC sweep phase (ms)")

View File

@ -2823,7 +2823,7 @@ nsCycleCollector::GCIfNeeded(bool aForceGC)
// rt->Collect() must be called from the main thread,
// because it invokes XPCJSRuntime::GCCallback(cx, JSGC_BEGIN)
// which returns false if not in the main thread.
rt->Collect();
rt->Collect(js::gcreason::CC_FORCED, nsGCNormal);
#ifdef COLLECT_TIME_DEBUG
printf("cc: GC() took %lldms\n", (PR_Now() - start) / PR_USEC_PER_MSEC);
#endif

View File

@ -106,9 +106,10 @@ struct nsCycleCollectionJSRuntime : public nsCycleCollectionLanguageRuntime
virtual bool NeedCollect() = 0;
/**
* Runs the JavaScript GC.
* Runs the JavaScript GC. |reason| is a gcreason::Reason from jsfriendapi.h.
* |kind| is a nsGCType from nsIXPConnect.idl.
*/
virtual void Collect(bool shrinkingGC = false) = 0;
virtual void Collect(PRUint32 reason, PRUint32 kind) = 0;
};
#ifdef DEBUG