Bug 1251703 - Always resolve virtual calls to known callees, r=mccr8
authorSteve Fink <sfink@mozilla.com>
Fri, 26 Feb 2016 11:20:13 -0800
changeset 322525 fccf01d7567dd45a288909c65f6e759d8523a6ac
parent 322524 80869f1474a46dd2abe12c79410ff7d0126980b7
child 322526 b0cd29d16e6c742d685accf883dc7a657522327e
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1251703
milestone47.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 1251703 - Always resolve virtual calls to known callees, r=mccr8
js/src/devtools/rootAnalysis/computeCallgraph.js
--- a/js/src/devtools/rootAnalysis/computeCallgraph.js
+++ b/js/src/devtools/rootAnalysis/computeCallgraph.js
@@ -55,39 +55,42 @@ function processCSU(csuName, csu)
             classFunctions[key].push(name);
         }
     }
 }
 
 function findVirtualFunctions(initialCSU, field, suppressed)
 {
     var worklist = [initialCSU];
+    var functions = [];
 
     // 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
     // which should never enter the JS engine (even when calling dtors).
     while (worklist.length) {
         var csu = worklist.pop();
         if (csu == "nsISupports" && (field == "AddRef" || field == "Release")) {
             suppressed[0] = true;
             return [];
         }
-        if (isOverridableField(initialCSU, csu, field))
-            return null;
+        if (isOverridableField(initialCSU, csu, field)) {
+            // We will still resolve the virtual function call, because it's
+            // nice to have as complete a callgraph as possible for other uses.
+            // But push a token saying that we can run arbitrary code.
+            functions.push(null);
+        }
 
         if (csu in superclasses) {
             for (var superclass of superclasses[csu])
                 worklist.push(superclass);
         }
     }
 
-    var functions = [];
-    var worklist = [csu];
-
+    worklist = [csu];
     while (worklist.length) {
         var csu = worklist.pop();
         var key = csu + ":" + field;
 
         if (key in classFunctions) {
             for (var name of classFunctions[key])
                 functions.push(name);
         }
@@ -150,24 +153,31 @@ function getCallees(edge)
             if (functions) {
                 // Known set of virtual call targets. Treat them as direct
                 // calls to all possible resolved types, but also record edges
                 // from this field call to each final callee. When the analysis
                 // is checking whether an edge can GC and it sees an unrooted
                 // pointer held live across this field call, it will know
                 // whether any of the direct callees can GC or not.
                 var targets = [];
+                var fullyResolved = true;
                 for (var name of functions) {
-                    callees.push({'kind': "direct", 'name': name});
-                    targets.push({'kind': "direct", 'name': name});
+                    if (name === null) {
+                        // virtual call on an nsISupports object
+                        callees.push({'kind': "field", 'csu': csuName, 'field': fieldName});
+                        fullyResolved = false;
+                    } else {
+                        callees.push({'kind': "direct", 'name': name});
+                        targets.push({'kind': "direct", 'name': name});
+                    }
                 }
-                callees.push({'kind': "resolved-field", 'csu': csuName, 'field': fieldName, 'callees': targets});
+                if (fullyResolved)
+                    callees.push({'kind': "resolved-field", 'csu': csuName, 'field': fieldName, 'callees': targets});
             } else {
-                // Unknown set of call targets. Non-virtual field call,
-                // or virtual call on an nsISupports object.
+                // Unknown set of call targets. Non-virtual field call.
                 callees.push({'kind': "field", 'csu': csuName, 'field': fieldName});
             }
         } else if (callee.Exp[0].Kind == "Var") {
             // indirect call through a variable.
             callees.push({'kind': "indirect", 'variable': callee.Exp[0].Variable.Name[0]});
         } else {
             // unknown call target.
             callees.push({'kind': "unknown"});