Bug 845545: Part 3 - Give the CycleCollectedJSRuntime more control over

SnowWhite. r=smaug
This commit is contained in:
Kyle Huey 2013-08-03 16:55:39 -07:00
parent 147c3dee65
commit 46d249128b
5 changed files with 75 additions and 68 deletions

View File

@ -222,6 +222,43 @@ XPCJSRuntime::CustomContextCallback(JSContext *cx, unsigned operation)
return true;
}
class AsyncFreeSnowWhite : public nsRunnable
{
public:
NS_IMETHOD Run()
{
TimeStamp start = TimeStamp::Now();
bool hadSnowWhiteObjects = nsCycleCollector_doDeferredDeletion();
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_ASYNC_SNOW_WHITE_FREEING,
uint32_t((TimeStamp::Now() - start).ToMilliseconds()));
if (hadSnowWhiteObjects && !mContinuation) {
mContinuation = true;
if (NS_FAILED(NS_DispatchToCurrentThread(this))) {
mActive = false;
}
} else {
mActive = false;
}
return NS_OK;
}
void Dispatch(bool aContinuation = false)
{
if (mContinuation) {
mContinuation = aContinuation;
}
if (!mActive && NS_SUCCEEDED(NS_DispatchToCurrentThread(this))) {
mActive = true;
}
}
AsyncFreeSnowWhite() : mContinuation(false), mActive(false) {}
public:
bool mContinuation;
bool mActive;
};
namespace xpc {
CompartmentPrivate::~CompartmentPrivate()
@ -566,6 +603,12 @@ XPCJSRuntime::PrepareForCollection()
}
}
void
XPCJSRuntime::DispatchDeferredDeletion(bool aContinuation)
{
mAsyncSnowWhiteFreer->Dispatch(aContinuation);
}
void
xpc_UnmarkSkippableJSHolders()
{
@ -2698,6 +2741,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
mObjectHolderRoots(nullptr),
mWatchdogManager(new WatchdogManager(this)),
mJunkScope(nullptr),
mAsyncSnowWhiteFreer(new AsyncFreeSnowWhite()),
mExceptionManagerNotAvailable(false)
{
#ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN

View File

@ -607,6 +607,8 @@ enum WatchdogTimestampCategory
TimestampCount
};
class AsyncFreeSnowWhite;
class XPCJSRuntime : public mozilla::CycleCollectedJSRuntime
{
public:
@ -729,6 +731,7 @@ public:
void UnmarkSkippableJSHolders();
void PrepareForForgetSkippable() MOZ_OVERRIDE;
void PrepareForCollection() MOZ_OVERRIDE;
void DispatchDeferredDeletion(bool continuation) MOZ_OVERRIDE;
void CustomGCCallback(JSGCStatus status) MOZ_OVERRIDE;
bool CustomContextCallback(JSContext *cx, unsigned operation) MOZ_OVERRIDE;
@ -871,6 +874,7 @@ private:
nsRefPtr<WatchdogManager> mWatchdogManager;
JS::GCSliceCallback mPrevGCSliceCallback;
JSObject* mJunkScope;
nsRefPtr<AsyncFreeSnowWhite> mAsyncSnowWhiteFreer;
nsCOMPtr<nsIException> mPendingException;
nsCOMPtr<nsIExceptionManager> mExceptionManager;

View File

@ -204,6 +204,8 @@ public:
void DeferredFinalize(nsISupports* aSupports);
void DumpJSHeap(FILE* aFile);
virtual void DispatchDeferredDeletion(bool aContinuation) = 0;
private:
JSGCThingParticipant mGCThingCycleCollectorGlobal;

View File

@ -1001,8 +1001,6 @@ public:
nsCycleCollectorParams mParams;
private:
nsRefPtr<AsyncFreeSnowWhite> mAsyncSnowWhiteFreer;
nsTArray<PtrInfo*> *mWhiteNodes;
uint32_t mWhiteNodeCount;
@ -1080,18 +1078,8 @@ public:
bool BeginCollection(ccType aCCType, nsICycleCollectorListener *aListener);
bool FinishCollection(nsICycleCollectorListener *aListener);
AsyncFreeSnowWhite* AsyncSnowWhiteFreer()
{
return mAsyncSnowWhiteFreer;
}
bool FreeSnowWhite(bool aUntilNoSWInPurpleBuffer);
// If there is a cycle collector available in the current thread,
// this calls FreeSnowWhite(false). Returns true if some
// snow-white objects were found.
static bool TryToFreeSnowWhite();
uint32_t SuspectedCount();
void Shutdown();
@ -2183,44 +2171,6 @@ MayHaveChild(void *o, nsCycleCollectionParticipant* cp)
return cf.MayHaveChild();
}
class AsyncFreeSnowWhite : public nsRunnable
{
public:
NS_IMETHOD Run()
{
TimeStamp start = TimeStamp::Now();
bool hadSnowWhiteObjects = nsCycleCollector::TryToFreeSnowWhite();
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_ASYNC_SNOW_WHITE_FREEING,
uint32_t((TimeStamp::Now() - start).ToMilliseconds()));
if (hadSnowWhiteObjects && !mContinuation) {
mContinuation = true;
if (NS_FAILED(NS_DispatchToCurrentThread(this))) {
mActive = false;
}
} else {
mActive = false;
}
return NS_OK;
}
static void Dispatch(nsCycleCollector* aCollector, bool aContinuation = false)
{
AsyncFreeSnowWhite* swf = aCollector->AsyncSnowWhiteFreer();
if (swf->mContinuation) {
swf->mContinuation = aContinuation;
}
if (!swf->mActive && NS_SUCCEEDED(NS_DispatchToCurrentThread(swf))) {
swf->mActive = true;
}
}
AsyncFreeSnowWhite() : mContinuation(false), mActive(false) {}
public:
bool mContinuation;
bool mActive;
};
struct SnowWhiteObject
{
void* mPointer;
@ -2302,7 +2252,7 @@ public:
}
if (HasSnowWhiteObjects()) {
// Effectively a continuation.
AsyncFreeSnowWhite::Dispatch(mCollector, true);
nsCycleCollector_dispatchDeferredDeletion(true);
}
}
@ -2315,7 +2265,7 @@ public:
SnowWhiteKiller::Visit(aBuffer, aEntry);
} else if (!mDispatchedDeferredDeletion) {
mDispatchedDeferredDeletion = true;
nsCycleCollector_dispatchDeferredDeletion();
nsCycleCollector_dispatchDeferredDeletion(false);
}
return;
}
@ -2364,15 +2314,6 @@ nsCycleCollector::FreeSnowWhite(bool aUntilNoSWInPurpleBuffer)
return hadSnowWhiteObjects;
}
/* static */ bool
nsCycleCollector::TryToFreeSnowWhite()
{
CollectorData* data = sCollectorData.get();
return data->mCollector ?
data->mCollector->FreeSnowWhite(false) :
false;
}
void
nsCycleCollector::SelectPurple(GCGraphBuilder &builder)
{
@ -2649,7 +2590,7 @@ nsCycleCollector::CollectWhite(nsICycleCollectorListener *aListener)
}
timeLog.Checkpoint("CollectWhite::Unroot");
nsCycleCollector_dispatchDeferredDeletion();
nsCycleCollector_dispatchDeferredDeletion(false);
return count > 0;
}
@ -2740,7 +2681,6 @@ nsCycleCollector::nsCycleCollector(CCThreadingModel aModel) :
mJSRuntime(nullptr),
mRunner(nullptr),
mThread(PR_GetCurrentThread()),
mAsyncSnowWhiteFreer(new AsyncFreeSnowWhite()),
mWhiteNodes(nullptr),
mWhiteNodeCount(0),
mVisitedRefCounted(0),
@ -3379,12 +3319,28 @@ nsCycleCollector_forgetSkippable(bool aRemoveChildlessNodes,
}
void
nsCycleCollector_dispatchDeferredDeletion()
nsCycleCollector_dispatchDeferredDeletion(bool aContinuation)
{
CollectorData* data = sCollectorData.get();
if (data && data->mCollector) {
AsyncFreeSnowWhite::Dispatch(data->mCollector);
CollectorData *data = sCollectorData.get();
if (!data || !data->mRuntime) {
return;
}
data->mRuntime->DispatchDeferredDeletion(aContinuation);
}
bool
nsCycleCollector_doDeferredDeletion()
{
CollectorData *data = sCollectorData.get();
// We should have started the cycle collector by now.
MOZ_ASSERT(data);
MOZ_ASSERT(data->mCollector);
MOZ_ASSERT(data->mRuntime);
return data->mCollector->FreeSnowWhite(false);
}
void

View File

@ -57,7 +57,8 @@ void nsCycleCollector_setForgetSkippableCallback(CC_ForgetSkippableCallback aCB)
void nsCycleCollector_forgetSkippable(bool aRemoveChildlessNodes = false,
bool aAsyncSnowWhiteFreeing = false);
void nsCycleCollector_dispatchDeferredDeletion();
void nsCycleCollector_dispatchDeferredDeletion(bool aContinuation = false);
bool nsCycleCollector_doDeferredDeletion();
void nsCycleCollector_collect(bool aManuallyTriggered,
nsCycleCollectorResults *aResults,