Bug 826526 - Modify the orphan node reporter so it handles WebIDL objects. r=bz.
authorNicholas Nethercote <nnethercote@mozilla.com>
Sun, 06 Jan 2013 20:43:54 -0800
changeset 117854 48abe27b73b7ede067b1fefe50fc26823078ff0a
parent 117853 9fe346fc7b6ded9899531098cb75a7defd579ecf
child 117855 965e97b75bfab0686ac6323a9815940fd4fd34d9
push id20714
push usernnethercote@mozilla.com
push dateMon, 07 Jan 2013 04:45:19 +0000
treeherdermozilla-inbound@48abe27b73b7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs826526
milestone20.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
Bug 826526 - Modify the orphan node reporter so it handles WebIDL objects. r=bz.
js/public/MemoryMetrics.h
js/src/jsmemorymetrics.cpp
js/xpconnect/src/XPCJSRuntime.cpp
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -14,16 +14,18 @@
 #include <string.h>
 
 #include "jsalloc.h"
 #include "jspubtd.h"
 
 #include "js/Utility.h"
 #include "js/Vector.h"
 
+class nsISupports;      // This is needed for ObjectPrivateVisitor.
+
 namespace js {
 
 // In memory reporting, we have concept of "sundries", line items which are too
 // small to be worth reporting individually.  Under some circumstances, a memory
 // reporter gets tossed into the sundries bucket if it's smaller than
 // MemoryReportingSundriesThreshold() bytes.
 //
 // We need to define this value here, rather than in the code which actually
@@ -386,18 +388,27 @@ struct RuntimeStats
 };
 
 #ifdef JS_THREADSAFE
 
 class ObjectPrivateVisitor
 {
 public:
     // Within CollectRuntimeStats, this method is called for each JS object
-    // that has a private slot containing an nsISupports pointer.
-    virtual size_t sizeOfIncludingThis(void *aSupports) = 0;
+    // that has an nsISupports pointer.
+    virtual size_t sizeOfIncludingThis(nsISupports *aSupports) = 0;
+
+    // A callback that gets a JSObject's nsISupports pointer, if it has one.
+    // Note: this function does *not* addref |iface|.
+    typedef JSBool(*GetISupportsFun)(JSObject *obj, nsISupports **iface);
+    GetISupportsFun getISupports;
+
+    ObjectPrivateVisitor(GetISupportsFun getISupports)
+      : getISupports(getISupports)
+    {}
 };
 
 extern JS_PUBLIC_API(bool)
 CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv);
 
 extern JS_PUBLIC_API(int64_t)
 GetExplicitNonHeapForRuntime(JSRuntime *rt, JSMallocSizeOfFun mallocSizeOf);
 
--- a/js/src/jsmemorymetrics.cpp
+++ b/js/src/jsmemorymetrics.cpp
@@ -154,21 +154,19 @@ StatsCellCallback(JSRuntime *rt, void *d
 
         ObjectsExtraSizes objectsExtra;
         obj->sizeOfExcludingThis(rtStats->mallocSizeOf, &objectsExtra);
         cStats->objectsExtra.add(objectsExtra);
 
         // JSObject::sizeOfExcludingThis() doesn't measure objectsExtraPrivate,
         // so we do it here.
         if (ObjectPrivateVisitor *opv = closure->opv) {
-            js::Class *clazz = js::GetObjectClass(obj);
-            if (clazz->flags & JSCLASS_HAS_PRIVATE &&
-                clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS)
-            {
-                cStats->objectsExtra.private_ += opv->sizeOfIncludingThis(GetObjectPrivate(obj));
+            nsISupports *iface;
+            if (opv->getISupports(obj, &iface) && iface) {
+                cStats->objectsExtra.private_ += opv->sizeOfIncludingThis(iface);
             }
         }
         break;
     }
     case JSTRACE_STRING:
     {
         JSString *str = static_cast<JSString *>(thing);
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1990,25 +1990,26 @@ SizeOfTreeIncludingThis(nsINode *tree)
         n += child->SizeOfIncludingThis(OrphanMallocSizeOf);
     }   
     return n;
 }
 
 class OrphanReporter : public JS::ObjectPrivateVisitor
 {
 public:
-    OrphanReporter()
+    OrphanReporter(GetISupportsFun aGetISupports)
+      : JS::ObjectPrivateVisitor(aGetISupports)
     {
         mAlreadyMeasuredOrphanTrees.Init();
     }
 
-    virtual size_t sizeOfIncludingThis(void *aSupports)
+    virtual size_t sizeOfIncludingThis(nsISupports *aSupports)
     {
         size_t n = 0;
-        nsCOMPtr<nsINode> node = do_QueryInterface(static_cast<nsISupports*>(aSupports));
+        nsCOMPtr<nsINode> node = do_QueryInterface(aSupports);
         // https://bugzilla.mozilla.org/show_bug.cgi?id=773533#c11 explains
         // that we have to skip XBL elements because they violate certain
         // assumptions.  Yuk.
         if (node && !node->IsInDoc() &&
             !(node->IsElement() && node->AsElement()->IsInNamespace(kNameSpaceID_XBL)))
         {
             // This is an orphan node.  If we haven't already handled the
             // sub-tree that this node belongs to, measure the sub-tree's size
@@ -2060,25 +2061,25 @@ class XPCJSRuntimeStats : public JS::Run
                 // The global is a |window| object.  Use the path prefix that
                 // we should have already created for it.
                 if (mWindowPaths->Get(piwindow->WindowID(), &cJSPathPrefix)) {
                     cDOMPathPrefix.Assign(cJSPathPrefix);
                     cDOMPathPrefix.AppendLiteral("/dom/");
                     cJSPathPrefix.AppendLiteral("/js/");
                 } else {
                     cJSPathPrefix.AssignLiteral("explicit/js-non-window/compartments/unknown-window-global/");
-                    cDOMPathPrefix.AssignLiteral("explicit/dom/?!/");
+                    cDOMPathPrefix.AssignLiteral("explicit/dom/unknown-window-global?!/");
                 }
             } else {
                 cJSPathPrefix.AssignLiteral("explicit/js-non-window/compartments/non-window-global/");
-                cDOMPathPrefix.AssignLiteral("explicit/dom/?!/");
+                cDOMPathPrefix.AssignLiteral("explicit/dom/non-window-global?!/");
             }
         } else {
             cJSPathPrefix.AssignLiteral("explicit/js-non-window/compartments/no-global/");
-            cDOMPathPrefix.AssignLiteral("explicit/dom/?!/");
+            cDOMPathPrefix.AssignLiteral("explicit/dom/no-global?!/");
         }
 
         cJSPathPrefix += NS_LITERAL_CSTRING("compartment(") + cName + NS_LITERAL_CSTRING(")/");
 
         // cJSPathPrefix is used for almost all the compartment-specific
         // reports.  At this point it has the form
         // "<something>/compartment/(<cname>)/".
         //
@@ -2103,17 +2104,17 @@ JSMemoryMultiReporter::CollectReports(Wi
 
     // In the first step we get all the stats and stash them in a local
     // data structure.  In the second step we pass all the stashed stats to
     // the callback.  Separating these steps is important because the
     // callback may be a JS function, and executing JS while getting these
     // stats seems like a bad idea.
 
     XPCJSRuntimeStats rtStats(windowPaths);
-    OrphanReporter orphanReporter;
+    OrphanReporter orphanReporter(XPCConvert::GetISupportsFromJSObject);
     if (!JS::CollectRuntimeStats(xpcrt->GetJSRuntime(), &rtStats, &orphanReporter))
         return NS_ERROR_FAILURE;
 
     size_t xpconnect =
         xpcrt->SizeOfIncludingThis(JsMallocSizeOf) +
         XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(JsMallocSizeOf);
 
     // This is the second step (see above).  First we report stuff in the