--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -41,17 +41,20 @@
* ***** END LICENSE BLOCK ***** */
/* High level class and public functions implementation. */
#include "xpcprivate.h"
#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)
nsXPConnect* nsXPConnect::gSelf = nsnull;
JSBool nsXPConnect::gOnceAliveNowDead = JS_FALSE;
const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;1";
const char XPC_RUNTIME_CONTRACTID[] = "@mozilla.org/js/xpc/RuntimeService;1";
@@ -572,16 +575,32 @@ nsXPConnect::Unroot(const nsDeque &nodes
continue;
JSObject *obj = NS_STATIC_CAST(JSObject*, p);
if (!JS_UnlockGCThing(cx, obj))
return NS_ERROR_FAILURE;
}
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)
{
XPCCallContext cx(NATIVE_CALLER);
PRUint32 refcount = 0;
if (!mObjRefcounts->Get(p, refcount))
return NS_OK;
@@ -589,42 +608,101 @@ nsXPConnect::Traverse(void *p, nsCycleCo
JSObject *obj = NS_STATIC_CAST(JSObject*, p);
JSClass* clazz = OBJ_GET_CLASS(cx, obj);
#ifdef DEBUG
char name[72];
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))
{
XPCWrappedNativeProto* p =
(XPCWrappedNativeProto*) JS_GetPrivate(cx, obj);
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");
#endif
if (!p)
return NS_OK;
if(XPCNativeWrapper::IsNativeWrapperClass(clazz))
@@ -653,30 +731,70 @@ nsXPConnect::Traverse(void *p, nsCycleCo
// Mark scope.
p->GetScope()->Traverse(cb);
}
else if(clazz->flags & JSCLASS_HAS_PRIVATE &&
clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS)
{
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));
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
OBJ_GET_PROTO(cx, obj));
for(uint32 i = JSSLOT_START(clazz); i < STOBJ_NSLOTS(obj); ++i)
{
jsval val = STOBJ_GET_SLOT(obj, i);
if (JSVAL_IS_OBJECT(val))
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
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)
{
nsISupports *principal = nsnull;
mObjRefcounts->mScopes.Get(obj, &principal);
cb.NoteXPCOMChild(principal);
}
#endif