/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ "use strict"; var functionBodies; function findAllPoints(bodies, blockId) { var points = []; var body; for (var xbody of bodies) { 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(bodies, 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 (variable.Name[1].charAt(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 any constructor matched by // isConstructor(). (Note that this would be insufficient if you needed to // treat each instance separately, such as when different regions of a function // body were guarded by these constructors and you needed to do something // different with each.) function allRAIIGuardedCallPoints(bodies, 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(edge.Type, variable.Name)) continue; if (!("PEdgeCallInstance" in edge)) continue; if (edge.PEdgeCallInstance.Exp.Kind != "Var") continue; Array.prototype.push.apply(points, pointsInRAIIScope(bodies, 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(bodies, 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(bodies, nedge.BlockId)); worklist.push(nedge.Index[1]); } } return points; }