mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-25 03:05:34 +00:00
Bug 1259850 - Switch to using a Map for visited points within a function, and heavily comment, r=terrence
MozReview-Commit-ID: LvU4upaHt8b --HG-- extra : rebase_source : 2f6d0a05594047dd505e1c63e0b52a94e1d3f5da extra : source : 15de0d1d0b05457c18dcf70e4e81d9bfe5ad5f79
This commit is contained in:
parent
cf9da8546b
commit
bc7d8b91bd
@ -331,31 +331,57 @@ function edgeCanGC(edge)
|
||||
//
|
||||
// - 'gcInfo': a direct pointer to the GC call edge
|
||||
//
|
||||
function findGCBeforeVariableUse(suppressed, variable, worklist)
|
||||
function findGCBeforeVariableUse(start_body, start_point, suppressed, variable)
|
||||
{
|
||||
// Scan through all edges preceding an unrooted variable use, using an
|
||||
// explicit worklist, looking for a GC call. A worklist contains an
|
||||
// incoming edge together with a description of where it or one of its
|
||||
// successors GC'd (if any).
|
||||
|
||||
var bodies_visited = new Map();
|
||||
|
||||
let worklist = [{body: start_body, ppoint: start_point, gcInfo: null, why: null}];
|
||||
while (worklist.length) {
|
||||
// Grab an entry off of the worklist, representing a point within the
|
||||
// CFG identified by <body,ppoint>. If this point has a descendant
|
||||
// later in the CFG that can GC, gcInfo will be set to the information
|
||||
// about that GC call.
|
||||
|
||||
var entry = worklist.pop();
|
||||
var { body, ppoint, gcInfo } = entry;
|
||||
|
||||
if (body.seen) {
|
||||
if (ppoint in body.seen) {
|
||||
var seenEntry = body.seen[ppoint];
|
||||
if (!gcInfo || seenEntry.gcInfo)
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
body.seen = [];
|
||||
}
|
||||
body.seen[ppoint] = {body: body, gcInfo: gcInfo};
|
||||
// Handle the case where there are multiple ways to reach this point
|
||||
// (traversing backwards).
|
||||
var visited = bodies_visited.get(body);
|
||||
if (!visited)
|
||||
bodies_visited.set(body, visited = new Map());
|
||||
if (visited.has(ppoint)) {
|
||||
var seenEntry = visited.get(ppoint);
|
||||
|
||||
// This point already knows how to GC through some other path, so
|
||||
// we have nothing new to learn. (The other path will consider the
|
||||
// predecessors.)
|
||||
if (seenEntry.gcInfo)
|
||||
continue;
|
||||
|
||||
// If this worklist's entry doesn't know of any way to GC, then
|
||||
// there's no point in continuing the traversal through it. Perhaps
|
||||
// another edge will be found that *can* GC; otherwise, the first
|
||||
// route to the point will traverse through predecessors.
|
||||
//
|
||||
// Note that this means we may visit a point more than once, if the
|
||||
// first time we visit we don't have a known reachable GC call and
|
||||
// the second time we do.
|
||||
if (!gcInfo)
|
||||
continue;
|
||||
}
|
||||
visited.set(ppoint, {body: body, gcInfo: gcInfo});
|
||||
|
||||
// Check for hitting the entry point of the current body (which may be
|
||||
// the outer function or a loop within it.)
|
||||
if (ppoint == body.Index[0]) {
|
||||
if (body.BlockId.Kind == "Loop") {
|
||||
// propagate to parents that enter the loop body.
|
||||
// Propagate to outer body parents that enter the loop body.
|
||||
if ("BlockPPoint" in body) {
|
||||
for (var parent of body.BlockPPoint) {
|
||||
var found = false;
|
||||
@ -399,11 +425,10 @@ function findGCBeforeVariableUse(suppressed, variable, worklist)
|
||||
// to a use after the GC call that proves its live range
|
||||
// extends at least that far.
|
||||
if (gcInfo)
|
||||
return {gcInfo: gcInfo, why: {body: body, ppoint: source, gcInfo: gcInfo, why: entry } }
|
||||
return {gcInfo: gcInfo, why: {body: body, ppoint: source, gcInfo: gcInfo, why: entry } };
|
||||
|
||||
// Otherwise, we want to continue searching for the true
|
||||
// minimumUse, for use in reporting unnecessary rooting, but we
|
||||
// truncate this particular branch of the search at this edge.
|
||||
// Otherwise, keep searching through the graph, but truncate
|
||||
// this particular branch of the search at this edge.
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -415,7 +440,10 @@ function findGCBeforeVariableUse(suppressed, variable, worklist)
|
||||
|
||||
if (edge_uses) {
|
||||
// The live range starts at least this far back, so we're done
|
||||
// for the same reason as with edge_kills.
|
||||
// for the same reason as with edge_kills. The only difference
|
||||
// is that a GC on this edge indicates a hazard, whereas if
|
||||
// we're killing a live range in the GC call then it's not live
|
||||
// *across* the call.
|
||||
if (gcInfo)
|
||||
return {gcInfo:gcInfo, why:entry};
|
||||
}
|
||||
@ -446,13 +474,12 @@ function findGCBeforeVariableUse(suppressed, variable, worklist)
|
||||
|
||||
function variableLiveAcrossGC(suppressed, variable)
|
||||
{
|
||||
// A variable is live across a GC if (1) it is used by an edge, and (2) it
|
||||
// is used after a GC in a successor edge.
|
||||
// A variable is live across a GC if (1) it is used by an edge (as in, it
|
||||
// was at least initialized), and (2) it is used after a GC in a successor
|
||||
// edge.
|
||||
|
||||
for (var body of functionBodies) {
|
||||
body.seen = null;
|
||||
for (var body of functionBodies)
|
||||
body.minimumUse = 0;
|
||||
}
|
||||
|
||||
for (var body of functionBodies) {
|
||||
if (!("PEdge" in body))
|
||||
@ -467,8 +494,7 @@ function variableLiveAcrossGC(suppressed, variable)
|
||||
//
|
||||
if (usePoint && !edgeKillsVariable(edge, variable)) {
|
||||
// Found a use, possibly after a GC.
|
||||
var worklist = [{body:body, ppoint:usePoint, gcInfo:null, why:null}];
|
||||
var call = findGCBeforeVariableUse(suppressed, variable, worklist);
|
||||
var call = findGCBeforeVariableUse(body, usePoint, suppressed, variable);
|
||||
if (!call)
|
||||
continue;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user