michael@0: /* -*- Mode: Javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: michael@0: "use strict"; michael@0: michael@0: var functionBodies; michael@0: michael@0: function findAllPoints(blockId) michael@0: { michael@0: var points = []; michael@0: var body; michael@0: michael@0: for (var xbody of functionBodies) { michael@0: if (sameBlockId(xbody.BlockId, blockId)) { michael@0: assert(!body); michael@0: body = xbody; michael@0: } michael@0: } michael@0: assert(body); michael@0: michael@0: if (!("PEdge" in body)) michael@0: return; michael@0: for (var edge of body.PEdge) { michael@0: points.push([body, edge.Index[0]]); michael@0: if (edge.Kind == "Loop") michael@0: Array.prototype.push.apply(points, findAllPoints(edge.BlockId)); michael@0: } michael@0: michael@0: return points; michael@0: } michael@0: michael@0: function isMatchingDestructor(constructor, edge) michael@0: { michael@0: if (edge.Kind != "Call") michael@0: return false; michael@0: var callee = edge.Exp[0]; michael@0: if (callee.Kind != "Var") michael@0: return false; michael@0: var variable = callee.Variable; michael@0: assert(variable.Kind == "Func"); michael@0: if (!/::~/.test(variable.Name[0])) michael@0: return false; michael@0: michael@0: var constructExp = constructor.PEdgeCallInstance.Exp; michael@0: assert(constructExp.Kind == "Var"); michael@0: michael@0: var destructExp = edge.PEdgeCallInstance.Exp; michael@0: if (destructExp.Kind != "Var") michael@0: return false; michael@0: michael@0: return sameVariable(constructExp.Variable, destructExp.Variable); michael@0: } michael@0: michael@0: // Return all calls within the RAII scope of the constructor matched by michael@0: // isConstructor() michael@0: function allRAIIGuardedCallPoints(body, isConstructor) michael@0: { michael@0: if (!("PEdge" in body)) michael@0: return []; michael@0: michael@0: var points = []; michael@0: michael@0: for (var edge of body.PEdge) { michael@0: if (edge.Kind != "Call") michael@0: continue; michael@0: var callee = edge.Exp[0]; michael@0: if (callee.Kind != "Var") michael@0: continue; michael@0: var variable = callee.Variable; michael@0: assert(variable.Kind == "Func"); michael@0: if (!isConstructor(variable.Name[0])) michael@0: continue; michael@0: if (edge.PEdgeCallInstance.Exp.Kind != "Var") michael@0: continue; michael@0: michael@0: Array.prototype.push.apply(points, pointsInRAIIScope(body, edge)); michael@0: } michael@0: michael@0: return points; michael@0: } michael@0: michael@0: // Test whether the given edge is the constructor corresponding to the given michael@0: // destructor edge michael@0: function isMatchingConstructor(destructor, edge) michael@0: { michael@0: if (edge.Kind != "Call") michael@0: return false; michael@0: var callee = edge.Exp[0]; michael@0: if (callee.Kind != "Var") michael@0: return false; michael@0: var variable = callee.Variable; michael@0: if (variable.Kind != "Func") michael@0: return false; michael@0: var name = readable(variable.Name[0]); michael@0: var destructorName = readable(destructor.Exp[0].Variable.Name[0]); michael@0: var match = destructorName.match(/^(.*?::)~(\w+)\(/); michael@0: if (!match) { michael@0: printErr("Unhandled destructor syntax: " + destructorName); michael@0: return false; michael@0: } michael@0: var constructorSubstring = match[1] + match[2]; michael@0: if (name.indexOf(constructorSubstring) == -1) michael@0: return false; michael@0: michael@0: var destructExp = destructor.PEdgeCallInstance.Exp; michael@0: assert(destructExp.Kind == "Var"); michael@0: michael@0: var constructExp = edge.PEdgeCallInstance.Exp; michael@0: if (constructExp.Kind != "Var") michael@0: return false; michael@0: michael@0: return sameVariable(constructExp.Variable, destructExp.Variable); michael@0: } michael@0: michael@0: function findMatchingConstructor(destructorEdge, body) michael@0: { michael@0: var worklist = [destructorEdge]; michael@0: var predecessors = getPredecessors(body); michael@0: while(worklist.length > 0) { michael@0: var edge = worklist.pop(); michael@0: if (isMatchingConstructor(destructorEdge, edge)) michael@0: return edge; michael@0: if (edge.Index[0] in predecessors) { michael@0: for (var e of predecessors[edge.Index[0]]) michael@0: worklist.push(e); michael@0: } michael@0: } michael@0: printErr("Could not find matching constructor!"); michael@0: debugger; michael@0: } michael@0: michael@0: function pointsInRAIIScope(body, constructorEdge) { michael@0: var seen = {}; michael@0: var worklist = [constructorEdge.Index[1]]; michael@0: var points = []; michael@0: while (worklist.length) { michael@0: var point = worklist.pop(); michael@0: if (point in seen) michael@0: continue; michael@0: seen[point] = true; michael@0: points.push([body, point]); michael@0: var successors = getSuccessors(body); michael@0: if (!(point in successors)) michael@0: continue; michael@0: for (var nedge of successors[point]) { michael@0: if (isMatchingDestructor(constructorEdge, nedge)) michael@0: continue; michael@0: if (nedge.Kind == "Loop") michael@0: Array.prototype.push.apply(points, findAllPoints(nedge.BlockId)); michael@0: worklist.push(nedge.Index[1]); michael@0: } michael@0: } michael@0: michael@0: return points; michael@0: }