diff --git a/js/src/devtools/rootAnalysis/analyzeRoots.js b/js/src/devtools/rootAnalysis/analyzeRoots.js index a10f63d0cadd..a0fa94e061c2 100644 --- a/js/src/devtools/rootAnalysis/analyzeRoots.js +++ b/js/src/devtools/rootAnalysis/analyzeRoots.js @@ -29,7 +29,7 @@ var batch = (scriptArgs[5]|0) || 1; var numBatches = (scriptArgs[6]|0) || 1; var tmpfile = scriptArgs[7] || "tmp.txt"; -GCSuppressionTypes = loadTypeInfo(typeInfoFile)["Suppress GC"]; +GCSuppressionTypes = loadTypeInfo(typeInfoFile)["Suppress GC"] || []; var gcFunctions = {}; var text = snarf("gcFunctions.lst").split("\n"); diff --git a/js/src/devtools/rootAnalysis/computeCallgraph.js b/js/src/devtools/rootAnalysis/computeCallgraph.js index ae30d9bd5bca..dab3f76216f6 100644 --- a/js/src/devtools/rootAnalysis/computeCallgraph.js +++ b/js/src/devtools/rootAnalysis/computeCallgraph.js @@ -308,7 +308,7 @@ function processBody(functionName, body) } } -GCSuppressionTypes = loadTypeInfo(typeInfo_filename)["Suppress GC"]; +GCSuppressionTypes = loadTypeInfo(typeInfo_filename)["Suppress GC"] || []; var xdb = xdbLibrary(); xdb.open("src_comp.xdb"); diff --git a/js/src/devtools/rootAnalysis/run-test.py b/js/src/devtools/rootAnalysis/run-test.py index 113e5fe351a1..3bc9085a0aaf 100644 --- a/js/src/devtools/rootAnalysis/run-test.py +++ b/js/src/devtools/rootAnalysis/run-test.py @@ -40,7 +40,7 @@ parser.add_argument( '--verbose', '-v', action='store_true', help='Display verbose output, including commands executed') parser.add_argument( - 'tests', nargs='*', default=['sixgill-tree', 'suppression', 'hazards'], + 'tests', nargs='*', default=['sixgill-tree', 'suppression', 'hazards', 'exceptions'], help='tests to run') cfg = parser.parse_args() diff --git a/js/src/devtools/rootAnalysis/t/exceptions/source.cpp b/js/src/devtools/rootAnalysis/t/exceptions/source.cpp new file mode 100644 index 000000000000..14169740e8f8 --- /dev/null +++ b/js/src/devtools/rootAnalysis/t/exceptions/source.cpp @@ -0,0 +1,42 @@ +#define ANNOTATE(property) __attribute__((tag(property))) + +struct Cell { int f; } ANNOTATE("GC Thing"); + +extern void GC() ANNOTATE("GC Call"); + +void GC() +{ + // If the implementation is too trivial, the function body won't be emitted at all. + asm(""); +} + +class RAII_GC { + public: + RAII_GC() {} + ~RAII_GC() { GC(); } +}; + +// ~AutoSomething calls GC because of the RAII_GC field. The constructor, +// though, should *not* GC -- unless it throws an exception. Which is not +// possible when compiled with -fno-exceptions. +class AutoSomething { + RAII_GC gc; + public: + AutoSomething() : gc() { + asm(""); // Ooh, scary, this might throw an exception + } + ~AutoSomething() { + asm(""); + } +}; + +extern void usevar(Cell* cell); + +void f() { + Cell* thing = nullptr; // Live range starts here + + { + AutoSomething smth; // Constructor can GC only if exceptions are enabled + usevar(thing); // Live range ends here + } // In particular, 'thing' is dead at the destructor, so no hazard +} diff --git a/js/src/devtools/rootAnalysis/t/exceptions/test.py b/js/src/devtools/rootAnalysis/t/exceptions/test.py new file mode 100644 index 000000000000..f6d7f5e353f2 --- /dev/null +++ b/js/src/devtools/rootAnalysis/t/exceptions/test.py @@ -0,0 +1,19 @@ +test.compile("source.cpp", '-fno-exceptions') +test.run_analysis_script('gcTypes') + +hazards = test.load_hazards() +assert(len(hazards) == 0) + +# If we compile with exceptions, then there *should* be a hazard because +# AutoSomething::AutoSomething might throw an exception, which would cause the +# partially-constructed value to be torn down, which will call ~RAII_GC. + +test.compile("source.cpp", '-fexceptions') +test.run_analysis_script('gcTypes') + +hazards = test.load_hazards() +assert(len(hazards) == 1) +hazard = hazards[0] +assert(hazard.function == 'void f()') +assert(hazard.variable == 'thing') +assert("AutoSomething::AutoSomething" in hazard.GCFunction) diff --git a/js/src/devtools/rootAnalysis/t/testlib.py b/js/src/devtools/rootAnalysis/t/testlib.py index 6f48ab19f278..438398f1ed66 100644 --- a/js/src/devtools/rootAnalysis/t/testlib.py +++ b/js/src/devtools/rootAnalysis/t/testlib.py @@ -31,10 +31,11 @@ class Test(object): def binpath(self, prog): return os.path.join(self.cfg.sixgill_bin, prog) - def compile(self, source): - cmd = "{CXX} -c {source} -O3 -std=c++11 -fplugin={sixgill} -fplugin-arg-xgill-mangle=1".format( + def compile(self, source, options = ''): + cmd = "{CXX} -c {source} -O3 -std=c++11 -fplugin={sixgill} -fplugin-arg-xgill-mangle=1 {options}".format( source=self.infile(source), - CXX=self.cfg.cxx, sixgill=self.cfg.sixgill_plugin) + CXX=self.cfg.cxx, sixgill=self.cfg.sixgill_plugin, + options=options) if self.cfg.verbose: print("Running %s" % cmd) subprocess.check_call(["sh", "-c", cmd]) @@ -75,7 +76,7 @@ sixgill_bin = '{bindir}' self.run_analysis_script("gcTypes", upto="gcTypes") def computeHazards(self): - self.run_analysis_script("callgraph") + self.run_analysis_script("gcTypes") def load_text_file(self, filename, extract=lambda l: l): fullpath = os.path.join(self.outdir, filename)