| /* -*- 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; |
| } |