blob: 4d2912114a2466240d0efdb43309f04b5e760876 [file] [log] [blame]
/* -*- indent-tabs-mode: nil; js-indent-level: 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 = readable(variable.Name[0]);
var destructorName = readable(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;
}