Bug 851340 - Make the rooting of scripts in nsXULPrototypeCache more efficient; r=smaug

This commit is contained in:
Terrence Cole 2013-03-19 10:20:21 -07:00
parent c9affe2adc
commit 2ae4b3c000
6 changed files with 43 additions and 42 deletions

View File

@ -434,8 +434,21 @@ TraceActiveWindowGlobal(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aCl
}
void
mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber)
mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownGC)
{
#ifdef MOZ_XUL
// Mark the scripts held in the XULPrototypeCache. This is required to keep
// the JS script in the cache live across GC.
nsXULPrototypeCache* cache = nsXULPrototypeCache::MaybeGetInstance();
if (cache) {
if (aIsShutdownGC) {
cache->FlushScripts();
} else {
cache->MarkInGC(aTrc);
}
}
#endif
if (!nsCCUncollectableMarker::sGeneration) {
return;
}

View File

@ -45,7 +45,7 @@ private:
namespace mozilla {
namespace dom {
void TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber);
void TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownGC);
}
}

View File

@ -251,8 +251,6 @@ protected:
static nsIRDFResource* kNC_attribute;
static nsIRDFResource* kNC_value;
static nsXULPrototypeCache* gXULCache;
static PRLogModuleInfo* gXULLog;
nsresult

View File

@ -190,17 +190,6 @@ nsXULPrototypeCache::GetScript(nsIURI* aURI)
return entry.mScriptObject;
}
/* static */
static PLDHashOperator
ReleaseScriptObjectCallback(nsIURI* aKey, CacheScriptEntry &aData, void* aClosure)
{
nsCOMPtr<nsIScriptRuntime> rt;
if (NS_SUCCEEDED(NS_GetJSRuntime(getter_AddRefs(rt))))
rt->DropScriptObject(aData.mScriptObject);
return PL_DHASH_REMOVE;
}
nsresult
nsXULPrototypeCache::PutScript(nsIURI* aURI, JSScript* aScriptObject)
{
@ -214,34 +203,15 @@ nsXULPrototypeCache::PutScript(nsIURI* aURI, JSScript* aScriptObject)
message += " twice (bug 392650)";
NS_WARNING(message.get());
#endif
// Reuse the callback used for enumeration in FlushScripts
ReleaseScriptObjectCallback(aURI, existingEntry, nullptr);
}
CacheScriptEntry entry = {aScriptObject};
mScriptTable.Put(aURI, entry);
// Lock the object from being gc'd until it is removed from the cache
nsCOMPtr<nsIScriptRuntime> rt;
nsresult rv = NS_GetJSRuntime(getter_AddRefs(rt));
if (NS_SUCCEEDED(rv))
rv = rt->HoldScriptObject(aScriptObject);
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to GC lock the object");
// On failure doing the lock, we should remove the map entry?
return rv;
return NS_OK;
}
void
nsXULPrototypeCache::FlushScripts()
{
// This callback will unlock each object so it can once again be gc'd.
// XXX - this might be slow - we fetch the runtime each and every object.
mScriptTable.Enumerate(ReleaseScriptObjectCallback, nullptr);
}
nsresult
nsXULPrototypeCache::PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo)
{
@ -307,15 +277,17 @@ nsXULPrototypeCache::FlushSkinFiles()
mXBLDocTable.Enumerate(FlushScopedSkinStylesheets, nullptr);
}
void
nsXULPrototypeCache::FlushScripts()
{
mScriptTable.Clear();
}
void
nsXULPrototypeCache::Flush()
{
mPrototypeTable.Clear();
// Clear the script cache, as it refers to prototype-owned mJSObjects.
FlushScripts();
mScriptTable.Clear();
mStyleSheetTable.Clear();
mXBLDocTable.Clear();
}
@ -666,3 +638,18 @@ nsXULPrototypeCache::MarkInCCGeneration(uint32_t aGeneration)
mXBLDocTable.Enumerate(MarkXBLInCCGeneration, &aGeneration);
mPrototypeTable.Enumerate(MarkXULInCCGeneration, &aGeneration);
}
static PLDHashOperator
MarkScriptsInGC(nsIURI* aKey, CacheScriptEntry& aScriptEntry, void* aClosure)
{
JSTracer* trc = static_cast<JSTracer*>(aClosure);
JS_CALL_SCRIPT_TRACER(trc, aScriptEntry.mScriptObject,
"nsXULPrototypeCache script");
return PL_DHASH_NEXT;
}
void
nsXULPrototypeCache::MarkInGC(JSTracer* aTrc)
{
mScriptTable.Enumerate(MarkScriptsInGC, aTrc);
}

View File

@ -107,6 +107,7 @@ public:
nsresult HasData(nsIURI* aURI, bool* exists);
static nsXULPrototypeCache* GetInstance();
static nsXULPrototypeCache* MaybeGetInstance() { return sInstance; }
static void ReleaseGlobals()
{
@ -114,6 +115,8 @@ public:
}
void MarkInCCGeneration(uint32_t aGeneration);
void MarkInGC(JSTracer* aTrc);
void FlushScripts();
protected:
friend nsresult
NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult);
@ -123,7 +126,6 @@ protected:
static nsXULPrototypeCache* sInstance;
void FlushScripts();
void FlushSkinFiles();
nsRefPtrHashtable<nsURIHashKey,nsXULPrototypeDocument> mPrototypeTable; // owns the prototypes
@ -135,7 +137,7 @@ protected:
nsInterfaceHashtable<nsURIHashKey, nsIStorageStream> mOutputStreamTable;
nsInterfaceHashtable<nsURIHashKey, nsIObjectInputStream> mInputStreamTable;
// Bootstrap caching service
nsresult BeginCaching(nsIURI* aDocumentURI);
};

View File

@ -377,7 +377,8 @@ void XPCJSRuntime::TraceBlackJS(JSTracer* trc, void* data)
static_cast<XPCJSObjectHolder*>(e)->TraceJS(trc);
}
dom::TraceBlackJS(trc, JS_GetGCParameter(self->GetJSRuntime(), JSGC_NUMBER));
dom::TraceBlackJS(trc, JS_GetGCParameter(self->GetJSRuntime(), JSGC_NUMBER),
self->GetXPConnect()->IsShuttingDown());
}
// static