Bug 1259850 - Start searching from the most specialized csu, r=terrence
authorSteve Fink <sfink@mozilla.com>
Fri, 25 Mar 2016 15:25:46 -0700
changeset 338791 46da36d5dd6b157b6cd7445b273ec2c776cd61e9
parent 338790 4d7b3fc568de1d7b510a2894629d0e4e43b19f71
child 338792 d1d28cf9c0cb655ea924cd7ec317b46174116aad
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1259850
milestone49.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 1259850 - Start searching from the most specialized csu, r=terrence Previously, this mostly "worked" purely by chance -- it started gathering method definitions at the 'csu' variable, which JS helpfully hoisted up to the toplevel. It had the last value assigned to csu within the loop, which would have been the basest base class (don't think too hard about the case of multiple inheritance, it was wrong). Then we find all descendants, which was *too* much, but it ended up just making the analysis conservative. MozReview-Commit-ID: 2Ps8gJpztw2
js/src/devtools/rootAnalysis/computeCallgraph.js
--- a/js/src/devtools/rootAnalysis/computeCallgraph.js
+++ b/js/src/devtools/rootAnalysis/computeCallgraph.js
@@ -42,16 +42,34 @@ function processCSU(csuName, csu)
             // Note: not dealing with overloading correctly.
             var name = field.Variable.Name[0];
             var key = csuName + ":" + field.Field[0].Name[0];
             addEntry(classFunctions, key, name);
         }
     }
 }
 
+// Return the nearest ancestor method definition, or all nearest definitions in
+// the case of multiple inheritance.
+function nearestAncestorMethods(csu, method)
+{
+    var key = csu + ":" + method;
+
+    if (classFunctions.has(key))
+        return new Set(classFunctions.get(key));
+
+    var functions = new Set();
+    if (superclasses.has(csu)) {
+        for (var parent of superclasses.get(csu))
+            functions.update(nearestAncestorMethods(parent, method));
+    }
+
+    return functions;
+}
+
 function findVirtualFunctions(initialCSU, field, suppressed)
 {
     var worklist = [initialCSU];
     var functions = new Set();
 
     // Virtual call targets on subclasses of nsISupports may be incomplete,
     // if the interface is scriptable. Just treat all indirect calls on
     // nsISupports objects as potentially GC'ing, except AddRef/Release
@@ -68,17 +86,25 @@ function findVirtualFunctions(initialCSU
             // But push a token saying that we can run arbitrary code.
             functions.add(null);
         }
 
         if (superclasses.has(csu))
             worklist.push(...superclasses.get(csu));
     }
 
-    worklist = [csu];
+    // Now return a list of all the instantiations of the method named 'field'
+    // that could execute on an instance of initialCSU or a descendant class.
+
+    // Start with the class itself, or if it doesn't define the method, all
+    // nearest ancestor definitions.
+    functions.update(nearestAncestorMethods(initialCSU, field));
+
+    // Then recurse through all descendants to add in their definitions.
+    var worklist = [initialCSU];
     while (worklist.length) {
         var csu = worklist.pop();
         var key = csu + ":" + field;
 
         if (classFunctions.has(key))
             functions.update(classFunctions.get(key));
 
         if (subclasses.has(csu))