Bug 785493, part 2 - mark XUL protos of live docs black during GC. r=smaug

This commit is contained in:
Andrew McCreight 2012-08-24 13:22:23 -07:00
parent 3072627fad
commit 0654b292c3
9 changed files with 76 additions and 9 deletions

View File

@ -10,6 +10,7 @@
#include "nsServiceManagerUtils.h"
#include "nsIContentViewer.h"
#include "nsIDocument.h"
#include "nsXULDocument.h"
#include "nsIWindowMediator.h"
#include "nsPIDOMWindow.h"
#include "nsIWebNavigation.h"
@ -394,30 +395,48 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK;
}
struct TraceClosure
{
TraceClosure(JSTracer* aTrc, uint32_t aGCNumber)
: mTrc(aTrc), mGCNumber(aGCNumber)
{}
JSTracer* mTrc;
uint32_t mGCNumber;
};
static PLDHashOperator
TraceActiveWindowGlobal(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
{
if (aWindow->GetDocShell() && aWindow->IsOuterWindow()) {
TraceClosure* closure = static_cast<TraceClosure*>(aClosure);
if (JSObject* global = aWindow->FastGetGlobalJSObject()) {
JSTracer* trc = static_cast<JSTracer *>(aClosure);
JS_CALL_OBJECT_TRACER(trc, global, "active window global");
JS_CALL_OBJECT_TRACER(closure->mTrc, global, "active window global");
}
#ifdef MOZ_XUL
nsIDocument* doc = aWindow->GetExtantDoc();
if (doc && doc->IsXUL()) {
nsXULDocument* xulDoc = static_cast<nsXULDocument*>(doc);
xulDoc->TraceProtos(closure->mTrc, closure->mGCNumber);
}
#endif
}
return PL_DHASH_NEXT;
}
void
mozilla::dom::TraceBlackJS(JSTracer* aTrc)
mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber)
{
if (!nsCCUncollectableMarker::sGeneration) {
return;
}
TraceClosure closure(aTrc, aGCNumber);
// Mark globals of active windows black.
nsGlobalWindow::WindowByIdTable* windowsById =
nsGlobalWindow::GetWindowsTable();
if (windowsById) {
windowsById->Enumerate(TraceActiveWindowGlobal, aTrc);
windowsById->Enumerate(TraceActiveWindowGlobal, &closure);
}
// Mark the safe context black

View File

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

View File

@ -2231,6 +2231,22 @@ nsXULPrototypeElement::Unlink()
mAttributes = nullptr;
}
void
nsXULPrototypeElement::TraceAllScripts(JSTracer* aTrc)
{
for (uint32_t i = 0; i < mChildren.Length(); ++i) {
nsXULPrototypeNode* child = mChildren[i];
if (child->mType == nsXULPrototypeNode::eType_Element) {
static_cast<nsXULPrototypeElement*>(child)->TraceAllScripts(aTrc);
} else if (child->mType == nsXULPrototypeNode::eType_Script) {
JSScript* script = static_cast<nsXULPrototypeScript*>(child)->GetScriptObject();
if (script) {
JS_CALL_SCRIPT_TRACER(aTrc, script, "active window XUL prototype script");
}
}
}
}
//----------------------------------------------------------------------
//
// nsXULPrototypeScript

View File

@ -186,6 +186,9 @@ public:
void Unlink();
// Trace all scripts held by this element and its children.
void TraceAllScripts(JSTracer* aTrc);
nsPrototypeArray mChildren;
nsCOMPtr<nsINodeInfo> mNodeInfo; // [OWNER]

View File

@ -2221,6 +2221,15 @@ nsXULDocument::ApplyPersistentAttributesToElements(nsIRDFResource* aResource,
return NS_OK;
}
void
nsXULDocument::TraceProtos(JSTracer* aTrc, uint32_t aGCNumber)
{
uint32_t i, count = mPrototypes.Length();
for (i = 0; i < count; ++i) {
mPrototypes[i]->TraceProtos(aTrc, aGCNumber);
}
}
//----------------------------------------------------------------------
//
// nsXULDocument::ContextStack

View File

@ -40,8 +40,9 @@ class nsIXULPrototypeScript;
#endif
#include "nsURIHashKey.h"
#include "nsInterfaceHashtable.h"
struct JSObject;
struct JSTracer;
struct PRLogModuleInfo;
class nsRefMapEntry : public nsStringHashKey
@ -178,6 +179,9 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULDocument, nsXMLDocument)
virtual nsXPCClassInfo* GetClassInfo();
void TraceProtos(JSTracer* aTrc, uint32_t aGCNumber);
protected:
// Implementation methods
friend nsresult

View File

@ -127,7 +127,8 @@ JSClass nsXULPDGlobalObject::gSharedGlobalClass = {
nsXULPrototypeDocument::nsXULPrototypeDocument()
: mRoot(nullptr),
mLoaded(false),
mCCGeneration(0)
mCCGeneration(0),
mGCNumber(0)
{
++gRefCnt;
}
@ -678,6 +679,18 @@ nsXULPrototypeDocument::NotifyLoadDone()
return rv;
}
void
nsXULPrototypeDocument::TraceProtos(JSTracer* aTrc, uint32_t aGCNumber)
{
// Only trace the protos once per GC.
if (mGCNumber == aGCNumber) {
return;
}
mGCNumber = aGCNumber;
mRoot->TraceAllScripts(aTrc);
}
//----------------------------------------------------------------------
//
// nsIScriptGlobalObjectOwner methods

View File

@ -22,6 +22,7 @@ class nsXULDocument;
class nsXULPrototypeElement;
class nsXULPrototypePI;
class nsXULPDGlobalObject;
struct JSTracer;
/**
* A "prototype" document that stores shared document information
@ -118,6 +119,8 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULPrototypeDocument,
nsIScriptGlobalObjectOwner)
void TraceProtos(JSTracer* aTrc, uint32_t aGCNumber);
protected:
nsCOMPtr<nsIURI> mURI;
nsRefPtr<nsXULPrototypeElement> mRoot;
@ -132,6 +135,7 @@ protected:
nsRefPtr<nsNodeInfoManager> mNodeInfoManager;
uint32_t mCCGeneration;
uint32_t mGCNumber;
nsXULPrototypeDocument();
virtual ~nsXULPrototypeDocument();

View File

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