author | Terrence Cole <terrence@mozilla.com> |
Tue, 19 Mar 2013 10:20:21 -0700 | |
changeset 125943 | 9b80bf15146cb8f06ecea1ea47eb4efd2b9b31f6 |
parent 125942 | 4b3ba25df1afbcd80b77a1465ce50c8acbb1a086 |
child 125944 | 6cb8dceb3ffdf8a98dea755f4356f787d10574e5 |
push id | 25181 |
push user | tcole@mozilla.com |
push date | Fri, 22 Mar 2013 18:05:28 +0000 |
treeherder | mozilla-inbound@9b80bf15146c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | smaug |
bugs | 851340 |
milestone | 22.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/base/src/nsCCUncollectableMarker.cpp +++ b/content/base/src/nsCCUncollectableMarker.cpp @@ -429,18 +429,31 @@ TraceActiveWindowGlobal(const uint64_t& xulDoc->TraceProtos(closure->mTrc, closure->mGCNumber); } #endif } return PL_DHASH_NEXT; } 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; } TraceClosure closure(aTrc, aGCNumber); // Mark globals of active windows black. nsGlobalWindow::WindowByIdTable* windowsById =
--- a/content/base/src/nsCCUncollectableMarker.h +++ b/content/base/src/nsCCUncollectableMarker.h @@ -40,13 +40,13 @@ class nsCCUncollectableMarker MOZ_FINAL private: nsCCUncollectableMarker() {} }; namespace mozilla { namespace dom { -void TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber); +void TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownGC); } } #endif
--- a/content/xul/document/src/nsXULDocument.h +++ b/content/xul/document/src/nsXULDocument.h @@ -246,18 +246,16 @@ protected: static nsIAtom** kIdentityAttrs[]; static nsIRDFService* gRDFService; static nsIRDFResource* kNC_persist; static nsIRDFResource* kNC_attribute; static nsIRDFResource* kNC_value; - static nsXULPrototypeCache* gXULCache; - static PRLogModuleInfo* gXULLog; nsresult Persist(nsIContent* aElement, int32_t aNameSpaceID, nsIAtom* aAttribute); // IMPORTANT: The ownership implicit in the following member // variables has been explicitly checked and set using nsCOMPtr // for owning pointers and raw COM interface pointers for weak
--- a/content/xul/document/src/nsXULPrototypeCache.cpp +++ b/content/xul/document/src/nsXULPrototypeCache.cpp @@ -185,68 +185,38 @@ nsXULPrototypeCache::GetScript(nsIURI* a { CacheScriptEntry entry; if (!mScriptTable.Get(aURI, &entry)) { return nullptr; } 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) { CacheScriptEntry existingEntry; if (mScriptTable.Get(aURI, &existingEntry)) { #ifdef DEBUG nsAutoCString scriptName; aURI->GetSpec(scriptName); nsAutoCString message("Loaded script "); message += scriptName; 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) { nsIURI* uri = aDocumentInfo->DocumentURI(); nsRefPtr<nsXBLDocumentInfo> info; mXBLDocTable.Get(uri, getter_AddRefs(info)); if (!info) { @@ -302,25 +272,27 @@ nsXULPrototypeCache::FlushSkinFiles() mStyleSheetTable.Enumerate(FlushSkinSheets, nullptr); // Iterate over all the remaining XBL and make sure cached // scoped skin stylesheets are flushed and refetched by the // prototype bindings. 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(); } bool nsXULPrototypeCache::IsEnabled() { @@ -661,8 +633,23 @@ MarkXULInCCGeneration(nsIURI* aKey, nsRe } void 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); +}
--- a/content/xul/document/src/nsXULPrototypeCache.h +++ b/content/xul/document/src/nsXULPrototypeCache.h @@ -102,42 +102,44 @@ public: */ nsresult GetInputStream(nsIURI* aURI, nsIObjectInputStream** objectInput); nsresult FinishInputStream(nsIURI* aURI); nsresult GetOutputStream(nsIURI* aURI, nsIObjectOutputStream** objectOutput); nsresult FinishOutputStream(nsIURI* aURI); nsresult HasData(nsIURI* aURI, bool* exists); static nsXULPrototypeCache* GetInstance(); + static nsXULPrototypeCache* MaybeGetInstance() { return sInstance; } static void ReleaseGlobals() { NS_IF_RELEASE(sInstance); } void MarkInCCGeneration(uint32_t aGeneration); + void MarkInGC(JSTracer* aTrc); + void FlushScripts(); protected: friend nsresult NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult); nsXULPrototypeCache(); virtual ~nsXULPrototypeCache(); static nsXULPrototypeCache* sInstance; - void FlushScripts(); void FlushSkinFiles(); nsRefPtrHashtable<nsURIHashKey,nsXULPrototypeDocument> mPrototypeTable; // owns the prototypes nsRefPtrHashtable<nsURIHashKey,nsCSSStyleSheet> mStyleSheetTable; nsDataHashtable<nsURIHashKey,CacheScriptEntry> mScriptTable; nsRefPtrHashtable<nsURIHashKey,nsXBLDocumentInfo> mXBLDocTable; nsTHashtable<nsURIHashKey> mCacheURITable; nsInterfaceHashtable<nsURIHashKey, nsIStorageStream> mOutputStreamTable; nsInterfaceHashtable<nsURIHashKey, nsIObjectInputStream> mInputStreamTable; - + // Bootstrap caching service nsresult BeginCaching(nsIURI* aDocumentURI); }; #endif // nsXULPrototypeCache_h__
--- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -372,17 +372,18 @@ void XPCJSRuntime::TraceBlackJS(JSTracer // XPCJSObjectHolders don't participate in cycle collection, so always // trace them here. XPCRootSetElem *e; for (e = self->mObjectHolderRoots; e; e = e->GetNextRoot()) 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 void XPCJSRuntime::TraceGrayJS(JSTracer* trc, void* data) { XPCJSRuntime* self = (XPCJSRuntime*)data; // Mark these roots as gray so the CC can walk them later.