Bug 910947 - More static rooting analysis fixes to get it all running on build slaves. r=divine-right

DONTBUILD 'cause NPOTB

--HG--
rename : js/src/devtools/rootAnalysis/suppressedPoints.js => js/src/devtools/rootAnalysis/CFG.js
This commit is contained in:
Steve Fink 2013-08-29 14:51:19 -07:00
parent a1c5c698e5
commit b333d20063
7 changed files with 205 additions and 125 deletions

View File

@ -0,0 +1,154 @@
/* -*- Mode: Javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
"use strict";
var functionBodies;
function findAllPoints(blockId)
{
var points = [];
var body;
for (var xbody of functionBodies) {
if (sameBlockId(xbody.BlockId, blockId)) {
assert(!body);
body = xbody;
}
}
assert(body);
if (!("PEdge" in body))
return;
for (var edge of body.PEdge) {
points.push([body, edge.Index[0]]);
if (edge.Kind == "Loop")
Array.prototype.push.apply(points, findAllPoints(edge.BlockId));
}
return points;
}
function isMatchingDestructor(constructor, edge)
{
if (edge.Kind != "Call")
return false;
var callee = edge.Exp[0];
if (callee.Kind != "Var")
return false;
var variable = callee.Variable;
assert(variable.Kind == "Func");
if (!/::~/.test(variable.Name[0]))
return false;
var constructExp = constructor.PEdgeCallInstance.Exp;
assert(constructExp.Kind == "Var");
var destructExp = edge.PEdgeCallInstance.Exp;
if (destructExp.Kind != "Var")
return false;
return sameVariable(constructExp.Variable, destructExp.Variable);
}
// Return all calls within the RAII scope of the constructor matched by
// isConstructor()
function allRAIIGuardedCallPoints(body, isConstructor)
{
if (!("PEdge" in body))
return [];
var points = [];
for (var edge of body.PEdge) {
if (edge.Kind != "Call")
continue;
var callee = edge.Exp[0];
if (callee.Kind != "Var")
continue;
var variable = callee.Variable;
assert(variable.Kind == "Func");
if (!isConstructor(variable.Name[0]))
continue;
if (edge.PEdgeCallInstance.Exp.Kind != "Var")
continue;
Array.prototype.push.apply(points, pointsInRAIIScope(body, edge));
}
return points;
}
// Test whether the given edge is the constructor corresponding to the given
// destructor edge
function isMatchingConstructor(destructor, edge)
{
if (edge.Kind != "Call")
return false;
var callee = edge.Exp[0];
if (callee.Kind != "Var")
return false;
var variable = callee.Variable;
if (variable.Kind != "Func")
return false;
var name = variable.Name[0];
var destructorName = destructor.Exp[0].Variable.Name[0];
var match = destructorName.match(/^(.*?::)~(\w+)\(/);
if (!match) {
printErr("Unhandled destructor syntax: " + destructorName);
return false;
}
var constructorSubstring = match[1] + match[2];
if (name.indexOf(constructorSubstring) == -1)
return false;
var destructExp = destructor.PEdgeCallInstance.Exp;
assert(destructExp.Kind == "Var");
var constructExp = edge.PEdgeCallInstance.Exp;
if (constructExp.Kind != "Var")
return false;
return sameVariable(constructExp.Variable, destructExp.Variable);
}
function findMatchingConstructor(destructorEdge, body)
{
var worklist = [destructorEdge];
var predecessors = getPredecessors(body);
while(worklist.length > 0) {
var edge = worklist.pop();
if (isMatchingConstructor(destructorEdge, edge))
return edge;
if (edge.Index[0] in predecessors) {
for (var e of predecessors[edge.Index[0]])
worklist.push(e);
}
}
printErr("Could not find matching constructor!");
debugger;
}
function pointsInRAIIScope(body, constructorEdge) {
var seen = {};
var worklist = [constructorEdge.Index[1]];
var points = [];
while (worklist.length) {
var point = worklist.pop();
if (point in seen)
continue;
seen[point] = true;
points.push([body, point]);
var successors = getSuccessors(body);
if (!(point in successors))
continue;
for (var nedge of successors[point]) {
if (isMatchingDestructor(constructorEdge, nedge))
continue;
if (nedge.Kind == "Loop")
Array.prototype.push.apply(points, findAllPoints(nedge.BlockId));
worklist.push(nedge.Index[1]);
}
}
return points;
}

View File

@ -97,6 +97,7 @@ def generate_hazards(config, outfilename):
JOBS = { 'dbs':
(('%(ANALYSIS_SCRIPTDIR)s/run_complete',
'--foreground',
'--no-logs',
'--build-root=%(objdir)s',
'--wrap-dir=%(sixgill)s/scripts/wrap_gcc',
'--work-dir=work',
@ -161,6 +162,7 @@ def run_job(name, config):
temp_map[command[i]] = outfiles[outfile]
outfile += 1
sys.stdout.flush()
with open(temp, 'w') as output:
subprocess.check_call(command, stdout=output, env=env(config))
for (temp, final) in temp_map.items():

View File

@ -4,7 +4,7 @@
loadRelativeToScript('utility.js');
loadRelativeToScript('annotations.js');
loadRelativeToScript('suppressedPoints.js');
loadRelativeToScript('CFG.js');
var sourceRoot = (environment['SOURCE'] || '') + '/'
@ -243,19 +243,6 @@ function edgeCanGC(edge)
return indirectCallCannotGC(functionName, calleeName) ? null : "*" + calleeName;
}
function computePredecessors(body)
{
body.predecessors = [];
if (!("PEdge" in body))
return;
for (var edge of body.PEdge) {
var target = edge.Index[1];
if (!(target in body.predecessors))
body.predecessors[target] = [];
body.predecessors[target].push(edge);
}
}
function variableUseFollowsGC(suppressed, variable, worklist)
{
// Scan through all edges following an unrooted variable use, using an
@ -573,8 +560,10 @@ for (var nameIndex = start; nameIndex <= end; nameIndex++) {
for (var body of functionBodies)
body.suppressed = [];
for (var body of functionBodies)
computeSuppressedPoints(body);
for (var body of functionBodies) {
for (var [pbody, id] of allRAIIGuardedCallPoints(body, isSuppressConstructor))
pbody.suppressed[id] = true;
}
processBodies(functionName);
xdb.free_string(name);

View File

@ -66,10 +66,10 @@ var ignoreCallees = {
"nsISupports.AddRef" : true,
"nsISupports.Release" : true, // makes me a bit nervous; this is a bug but can happen
"nsAXPCNativeCallContext.GetJSContext" : true,
"js::ion::MDefinition.op" : true, // macro generated virtuals just return a constant
"js::ion::MDefinition.opName" : true, // macro generated virtuals just return a constant
"js::ion::LInstruction.getDef" : true, // virtual but no implementation can GC
"js::ion::IonCache.kind" : true, // macro generated virtuals just return a constant
"js::jit::MDefinition.op" : true, // macro generated virtuals just return a constant
"js::jit::MDefinition.opName" : true, // macro generated virtuals just return a constant
"js::jit::LInstruction.getDef" : true, // virtual but no implementation can GC
"js::jit::IonCache.kind" : true, // macro generated virtuals just return a constant
"icu_50::UObject.__deleting_dtor" : true, // destructors in ICU code can't cause GC
"mozilla::CycleCollectedJSRuntime.DescribeCustomObjects" : true, // During tracing, cannot GC.
"mozilla::CycleCollectedJSRuntime.NoteCustomGCThingXPCOMChildren" : true, // During tracing, cannot GC.
@ -105,6 +105,8 @@ function ignoreEdgeUse(edge, variable)
return true;
if (/~DebugOnly/.test(name))
return true;
if (/~ScopedThreadSafeStringInspector/.test(name))
return true;
}
}

View File

@ -4,7 +4,7 @@
loadRelativeToScript('utility.js');
loadRelativeToScript('annotations.js');
loadRelativeToScript('suppressedPoints.js');
loadRelativeToScript('CFG.js');
var subclasses = {};
var superclasses = {};
@ -230,8 +230,10 @@ for (var nameIndex = minStream; nameIndex <= maxStream; nameIndex++) {
functionBodies = JSON.parse(data.readString());
for (var body of functionBodies)
body.suppressed = [];
for (var body of functionBodies)
computeSuppressedPoints(body);
for (var body of functionBodies) {
for (var [pbody, id] of allRAIIGuardedCallPoints(body, isSuppressConstructor))
pbody.suppressed[id] = true;
}
seenCallees = {};
seenSuppressedCallees = {};

View File

@ -27,6 +27,7 @@ use strict;
use IO::Handle;
use File::Basename qw(dirname);
use Getopt::Long;
use Cwd;
#################################
# environment specific settings #
@ -55,8 +56,10 @@ my $foreground;
my $builder = "make -j4";
my $suppress_logs;
GetOptions("build-root|b=s" => \$build_dir,
"poll-file=s" => \$poll_file,
"no-logs!" => \$suppress_logs,
"work-dir=s" => \$WORKDIR,
"sixgill-binaries|binaries|b=s" => \$SIXGILL_BIN,
"wrap-dir=s" => \$wrap_dir,
@ -103,6 +106,13 @@ sub build_project {
return system($builder) >> 8;
}
our %kill_on_exit;
END {
for my $pid (keys %kill_on_exit) {
kill($pid);
}
}
# commands to start the various xgill binaries. timeouts can be specified
# for the backend analyses here, and a memory limit can be specified for
# xmanager if desired (and USE_COUNT_ALLOCATOR is defined in util/alloc.h).
@ -143,12 +153,15 @@ if (not (-d $result_dir)) {
mkdir $result_dir;
}
open(OUT, ">> $result_dir/complete.log");
OUT->autoflush(1); # don't buffer writes to the main log.
if (!$suppress_logs) {
my $log_file = "$result_dir/complete.log";
open(OUT, ">>", $log_file) or die "append to $log_file: $!";
OUT->autoflush(1); # don't buffer writes to the main log.
# redirect stdout and stderr to the log.
STDOUT->fdopen(\*OUT, "w");
STDERR->fdopen(\*OUT, "w");
# redirect stdout and stderr to the log.
STDOUT->fdopen(\*OUT, "w");
STDERR->fdopen(\*OUT, "w");
}
# pids to wait on before exiting. these are collating worker output.
my @waitpids;
@ -161,8 +174,6 @@ my $status = run_build();
# end of run commands.
close(OUT);
for my $pid (@waitpids) {
waitpid($pid, 0);
$status ||= $? >> 8;
@ -197,20 +208,23 @@ sub run_build
defined(my $pid = fork) or die;
# log file for the manager.
my $log_file = "$result_dir/build_manager.log";
my $manager_log_file = "$result_dir/build_manager.log";
if (!$pid) {
# this is the child process, fork another process to run a manager.
defined(my $pid = fork) or die;
exec("$xmanager -terminate-on-assert > $log_file 2>&1") if (!$pid);
exec("$xmanager -terminate-on-assert > $manager_log_file 2>&1") if (!$pid);
$kill_on_exit{$pid} = 1;
# open new streams to redirect stdout and stderr.
open(LOGOUT, "> $result_dir/build.log");
open(LOGERR, "> $result_dir/build_err.log");
STDOUT->fdopen(\*LOGOUT, "w");
STDERR->fdopen(\*LOGERR, "w");
if (!$suppress_logs) {
# open new streams to redirect stdout and stderr.
open(LOGOUT, "> $result_dir/build.log");
open(LOGERR, "> $result_dir/build_err.log");
STDOUT->fdopen(\*LOGOUT, "w");
STDERR->fdopen(\*LOGERR, "w");
}
my $address = get_manager_address($log_file);
my $address = get_manager_address($manager_log_file);
# write the configuration file for the wrapper script.
my $config_file = "$WORKDIR/xgill.config";
@ -239,11 +253,13 @@ sub run_build
# wait for the manager to clean up and terminate.
print "Waiting for manager to finish (build status $exit_status)...\n";
waitpid($pid, 0);
my $manager_status = $?;
delete $kill_on_exit{$pid};
# build is finished, the complete run can resume.
# return value only useful if --foreground
print "Exiting with status " . ($? || $exit_status) . "\n";
exit($? || $exit_status);
print "Exiting with status " . ($manager_status || $exit_status) . "\n";
exit($manager_status || $exit_status);
}
# this is the complete process, wait for the build to finish.

View File

@ -1,85 +0,0 @@
/* -*- Mode: Javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
"use strict";
var functionBodies;
function findAllPoints(blockId)
{
var points = [];
var body;
for (var xbody of functionBodies) {
if (sameBlockId(xbody.BlockId, blockId)) {
assert(!body);
body = xbody;
}
}
assert(body);
if (!("PEdge" in body))
return;
for (var edge of body.PEdge) {
points.push([body, edge.Index[0]]);
if (edge.Kind == "Loop")
Array.prototype.push.apply(points, findAllPoints(edge.BlockId));
}
return points;
}
function isMatchingDestructor(constructor, edge)
{
if (edge.Kind != "Call")
return false;
var callee = edge.Exp[0];
if (callee.Kind != "Var")
return false;
var variable = callee.Variable;
assert(variable.Kind == "Func");
if (!/::~/.test(variable.Name[0]))
return false;
var constructExp = constructor.PEdgeCallInstance.Exp;
assert(constructExp.Kind == "Var");
var destructExp = edge.PEdgeCallInstance.Exp;
if (destructExp.Kind != "Var")
return false;
return sameVariable(constructExp.Variable, destructExp.Variable);
}
function allRAIIGuardedCallPoints(body, isConstructor)
{
if (!("PEdge" in body))
return [];
var points = [];
var successors = getSuccessors(body);
for (var edge of body.PEdge) {
if (edge.Kind != "Call")
continue;
var callee = edge.Exp[0];
if (callee.Kind != "Var")
continue;
var variable = callee.Variable;
assert(variable.Kind == "Func");
if (!isConstructor(variable.Name[0]))
continue;
if (edge.PEdgeCallInstance.Exp.Kind != "Var")
continue;
Array.prototype.push.apply(points, pointsInRAIIScope(body, edge, successors));
}
return points;
}
// Compute the points within a function body where GC is suppressed.
function computeSuppressedPoints(body)
{
for (var [pbody, id] of allRAIIGuardedCallPoints(body, isSuppressConstructor))
pbody.suppressed[id] = true;
}