From 4f88013a359303098b1923ca319e1633f244999f Mon Sep 17 00:00:00 2001 From: "peterv%propagandism.org" Date: Fri, 23 Mar 2007 13:21:22 +0000 Subject: [PATCH] Relanding part of the fix for bug 372960 (Make XPConnect traverse more JS edges). r=brendan, sr=jst. git-svn-id: svn://10.0.0.236/trunk@222257 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js/src/xpconnect/src/nsXPConnect.cpp | 136 +++++++++++++++++-- 1 file changed, 127 insertions(+), 9 deletions(-) diff --git a/mozilla/js/src/xpconnect/src/nsXPConnect.cpp b/mozilla/js/src/xpconnect/src/nsXPConnect.cpp index 26dbcb9fd23..22ac5fd56f8 100644 --- a/mozilla/js/src/xpconnect/src/nsXPConnect.cpp +++ b/mozilla/js/src/xpconnect/src/nsXPConnect.cpp @@ -46,7 +46,10 @@ #include "XPCNativeWrapper.h" #include "nsBaseHashtable.h" #include "nsHashKeys.h" +#include "jsatom.h" +#include "jsfun.h" #include "jsobj.h" +#include "jsscript.h" NS_IMPL_THREADSAFE_ISUPPORTS2(nsXPConnect,nsIXPConnect,nsISupportsWeakReference) @@ -577,6 +580,22 @@ nsXPConnect::Unroot(const nsDeque &nodes) return NS_OK; } +static void +TraverseJSScript(JSScript* script, nsCycleCollectionTraversalCallback& cb) +{ + JSAtomMap* map = &script->atomMap; + uintN i, length = map->length; + JSAtom** vector = map->vector; + + for(i = 0; i < length; i++) + { + JSAtom* atom = vector[i]; + if(ATOM_IS_OBJECT(atom)) + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, + ATOM_TO_OBJECT(atom)); + } +} + nsresult nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) { @@ -594,14 +613,46 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) if(XPCNativeWrapper::IsNativeWrapperClass(clazz)) { XPCWrappedNative* wn = XPCNativeWrapper::GetWrappedNative(cx, obj); - XPCNativeScriptableInfo* si = wn ? wn->GetScriptableInfo() : nsnull; - if(si) - JS_snprintf(name, sizeof(name), "XPCNativeWrapper (%s)", - si->GetJSClass()->name); + if(wn) + { + XPCNativeScriptableInfo* si = wn->GetScriptableInfo(); + if(si) + { + JS_snprintf(name, sizeof(name), "XPCNativeWrapper (%s)", + si->GetJSClass()->name); + } + else + { + nsIClassInfo* ci = wn->GetClassInfo(); + char* className = nsnull; + if(ci) + ci->GetClassDescription(&className); + if(className) + { + JS_snprintf(name, sizeof(name), "XPCNativeWrapper (%s)", + className); + PR_Free(className); + } + else + { + XPCNativeSet* set = wn->GetSet(); + XPCNativeInterface** array = set->GetInterfaceArray(); + PRUint16 count = set->GetInterfaceCount(); + + if(count > 0) + JS_snprintf(name, sizeof(name), "XPCNativeWrapper (%s)", + array[0]->GetNameString()); + else + JS_snprintf(name, sizeof(name), "XPCNativeWrapper"); + } + } + } else + { JS_snprintf(name, sizeof(name), "XPCNativeWrapper"); + } } - else if(obj) + else { XPCNativeScriptableInfo* si = nsnull; if(IS_PROTO_CLASS(clazz)) @@ -611,15 +662,42 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) si = p->GetScriptableInfo(); } if(si) + { JS_snprintf(name, sizeof(name), "JS Object (%s - %s)", clazz->name, si->GetJSClass()->name); + } + else if(clazz == &js_ScriptClass) + { + JSScript* script = (JSScript*) JS_GetPrivate(cx, obj); + if(script->filename) + { + JS_snprintf(name, sizeof(name), "JS Object (Script - %s)", + script->filename); + } + else + { + JS_snprintf(name, sizeof(name), "JS Object (Script)"); + } + } + else if(clazz == &js_FunctionClass) + { + JSFunction* fun = (JSFunction*) JS_GetPrivate(cx, obj); + if(fun->atom) + { + JS_snprintf(name, sizeof(name), "JS Object (Function - %s)", + js_AtomToPrintableString(cx, fun->atom)); + } + else + { + JS_snprintf(name, sizeof(name), "JS Object (Function)"); + } + } else + { JS_snprintf(name, sizeof(name), "JS Object (%s)", clazz->name); + } } - else - { - JS_snprintf(name, sizeof(name), "JS Object"); - } + cb.DescribeNode(refcount, sizeof(JSObject), name); #else cb.DescribeNode(refcount, sizeof(JSObject), "JS Object"); @@ -658,6 +736,24 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) { cb.NoteXPCOMChild(NS_STATIC_CAST(nsISupports*, JS_GetPrivate(cx, obj))); } + else if(clazz == &js_ScriptClass) + { + JSScript* script = (JSScript*) JS_GetPrivate(cx, obj); + TraverseJSScript(script, cb); + } + else if(clazz == &js_FunctionClass) + { + JSFunction* fun = (JSFunction*) JS_GetPrivate(cx, obj); + if (fun) { + JSAtom* atom = fun->atom; + if(atom && ATOM_IS_OBJECT(atom)) + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, + ATOM_TO_OBJECT(atom)); + JSScript* script = FUN_SCRIPT(fun); + if (script) + TraverseJSScript(script, cb); + } + } cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, OBJ_GET_PARENT(cx, obj)); @@ -672,6 +768,28 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) JSVAL_TO_OBJECT(val)); } + JSScope* scope; + if(OBJ_IS_NATIVE(obj) && (scope = OBJ_SCOPE(obj))) + { + JSScopeProperty* sprop; + for(sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) + { + if(SCOPE_HAD_MIDDLE_DELETE(scope) && + !SCOPE_HAS_PROPERTY(scope, sprop)) + continue; + jsid id = sprop->id; + if(JSID_IS_OBJECT(id)) + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, + JSID_TO_OBJECT(id)); + if(sprop->attrs & JSPROP_GETTER) + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, + JSVAL_TO_GCTHING((jsval)sprop->getter)); + if(sprop->attrs & JSPROP_SETTER) + cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, + JSVAL_TO_GCTHING((jsval)sprop->setter)); + } + } + #ifndef XPCONNECT_STANDALONE if(clazz->flags & JSCLASS_IS_GLOBAL) {