Bug 1500247 - Move special-cased types to annotations, r=jonco
authorSteve Fink <sfink@mozilla.com>
Fri, 04 Jan 2019 13:18:00 -0800
changeset 458987 5e40a711ed0a
parent 458986 2a8867abaa0f
child 458988 7e7f4d97d178
push id35553
push usershindli@mozilla.com
push dateThu, 14 Feb 2019 04:41:18 +0000
treeherdermozilla-central@f0ea53f47215 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1500247
milestone67.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 1500247 - Move special-cased types to annotations, r=jonco
js/src/devtools/rootAnalysis/analyzeRoots.js
js/src/devtools/rootAnalysis/annotations.js
js/src/devtools/rootAnalysis/t/hazards/source.cpp
js/src/devtools/rootAnalysis/t/hazards/test.py
--- a/js/src/devtools/rootAnalysis/analyzeRoots.js
+++ b/js/src/devtools/rootAnalysis/analyzeRoots.js
@@ -448,36 +448,38 @@ function edgeInvalidatesVariable(edge, v
 
     if (edge.Type.Kind == 'Function' &&
         edge.Type.TypeFunctionCSU &&
         edge.PEdgeCallInstance &&
         edge.PEdgeCallInstance.Exp.Kind == 'Var' &&
         expressionIsVariable(edge.PEdgeCallInstance.Exp, variable))
     do {
         const typeName = edge.Type.TypeFunctionCSU.Type.Name;
-        const m = typeName.match(/^mozilla::(\w+)</);
+        const m = typeName.match(/^(((\w|::)+?)(\w+))</);
         if (!m)
             break;
-        const type = m[1];
-        if (!["Maybe", "UniquePtr"].includes(type))
-            break;
+        const [, type, namespace,, classname] = m;
 
-        // special-case: (type)::reset()
+        // special-case: the initial constructor that doesn't provide a value.
+        // Useful for things like Maybe<T>.
         if (callee.Kind == 'Var' &&
-            callee.Variable.Name[1] == 'reset')
+            typesWithSafeConstructors.has(type) &&
+            callee.Variable.Name[0].includes(`${namespace}${classname}<T>::${classname}()`))
         {
             return true;
         }
 
-        // special-case: the initial constructor that doesn't provide a value.
+        // special-case: UniquePtr::reset() and similar.
         if (callee.Kind == 'Var' &&
-            callee.Variable.Name[0].includes(`mozilla::${type}<T>::${type}()`))
+            type in resetterMethods &&
+            resetterMethods[type].has(callee.Variable.Name[1]))
         {
             return true;
         }
+
     } while(0);
 
     // special-case: passing UniquePtr<T> by value.
     if (edge.Type.Kind == 'Function' &&
         edge.Type.TypeFunctionArgument &&
         edge.PEdgeCallArguments)
     {
         for (const i in edge.Type.TypeFunctionArgument) {
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -7,16 +7,33 @@ var ignoreIndirectCalls = {
     "mallocSizeOf" : true,
     "aMallocSizeOf" : true,
     "__conv" : true,
     "__convf" : true,
     "prerrortable.c:callback_newtable" : true,
     "mozalloc_oom.cpp:void (* gAbortHandler)(size_t)" : true,
 };
 
+// Types that when constructed with no arguments, are "safe" values (they do
+// not contain GC pointers).
+var typesWithSafeConstructors = new Set([
+    "mozilla::Maybe",
+    "mozilla::dom::Nullable",
+    "mozilla::dom::Optional",
+    "mozilla::UniquePtr",
+    "js::UniquePtr"
+]);
+
+var resetterMethods = {
+    'mozilla::Maybe': new Set(["reset"]),
+    'mozilla::UniquePtr': new Set(["reset"]),
+    'js::UniquePtr': new Set(["reset"]),
+    'mozilla::dom::Nullable': new Set(["SetNull"]),
+};
+
 function indirectCallCannotGC(fullCaller, fullVariable)
 {
     var caller = readable(fullCaller);
 
     // This is usually a simple variable name, but sometimes a full name gets
     // passed through. And sometimes that name is truncated. Examples:
     //   _ZL13gAbortHandler|mozalloc_oom.cpp:void (* gAbortHandler)(size_t)
     //   _ZL14pMutexUnlockFn|umutex.cpp:void (* pMutexUnlockFn)(const void*
--- a/js/src/devtools/rootAnalysis/t/hazards/source.cpp
+++ b/js/src/devtools/rootAnalysis/t/hazards/source.cpp
@@ -244,16 +244,23 @@ void safevals() {
   // Unsafe because it may not be nullptr.
   Cell* unsafe3 = &cell;
   if (reinterpret_cast<long>(&cell) & 0x100) {
     unsafe3 = nullptr;
   }
   GC();
   use(unsafe3);
 
+  // Unsafe because it's not nullptr anymore.
+  Cell* unsafe3b = &cell;
+  unsafe3b = nullptr;
+  unsafe3b = &cell;
+  GC();
+  use(unsafe3b);
+
   // Hazard involving UniquePtr.
   {
     mozilla::UniquePtr<Cell> unsafe4(&cell);
     GC();
     // Destructor uses unsafe4.
   }
 
   // reset() to safe value before the GC.
--- a/js/src/devtools/rootAnalysis/t/hazards/test.py
+++ b/js/src/devtools/rootAnalysis/t/hazards/test.py
@@ -51,15 +51,16 @@ assert('haz5' in hazmap)
 assert('haz6' not in hazmap)
 assert('haz7' not in hazmap)
 assert('haz8' in hazmap)
 
 # safevals hazards. See comments in source.
 assert('unsafe1' in hazmap)
 assert('safe2' not in hazmap)
 assert('unsafe3' in hazmap)
+assert('unsafe3b' in hazmap)
 assert('unsafe4' in hazmap)
 assert('safe5' not in hazmap)
 assert('safe6' not in hazmap)
 assert('unsafe7' in hazmap)
 assert('safe8' not in hazmap)
 assert('safe9' not in hazmap)
 assert('safe10' not in hazmap)