mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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:
parent
a1c5c698e5
commit
b333d20063
154
js/src/devtools/rootAnalysis/CFG.js
Normal file
154
js/src/devtools/rootAnalysis/CFG.js
Normal 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;
|
||||
}
|
@ -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():
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 = {};
|
||||
|
@ -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;
|
||||
|
||||
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.
|
||||
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user