From b9465e1bccf91eb1902a93ccf0d13f56486f03e1 Mon Sep 17 00:00:00 2001 From: sjfink Date: Tue, 17 Jul 2007 13:46:35 +0000 Subject: [PATCH] replace broken ExpandedControlFlowGraph with hopefully somewhat less broken ExplodedControlFlowGraph git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@1499 f5eafffb-2e1d-0410-98e4-8ec43c5233c4 --- .../ibm/wala/ipa/slicer/HeapReachingDefs.java | 32 +- .../analysis/DeadAssignmentElimination.java | 5 +- .../ssa/analysis/ExpandedCFGDotWriter.java | 144 -- .../analysis/ExpandedControlFlowGraph.java | 1323 ----------------- .../analysis/ExplodedControlFlowGraph.java | 418 ++++++ 5 files changed, 432 insertions(+), 1490 deletions(-) delete mode 100644 com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExpandedCFGDotWriter.java delete mode 100644 com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExpandedControlFlowGraph.java create mode 100644 com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExplodedControlFlowGraph.java diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/HeapReachingDefs.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/HeapReachingDefs.java index 8cb2aa844..cd01064dc 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/HeapReachingDefs.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/HeapReachingDefs.java @@ -40,8 +40,8 @@ import com.ibm.wala.ipa.slicer.Statement.Kind; import com.ibm.wala.ssa.IR; import com.ibm.wala.ssa.SSAInstruction; import com.ibm.wala.ssa.SSAInvokeInstruction; -import com.ibm.wala.ssa.analysis.ExpandedControlFlowGraph; -import com.ibm.wala.ssa.analysis.ExpandedControlFlowGraph.SingleInstructionBasicBlock; +import com.ibm.wala.ssa.analysis.ExplodedControlFlowGraph; +import com.ibm.wala.ssa.analysis.ExplodedControlFlowGraph.ExplodedBasicBlock; import com.ibm.wala.util.collections.Filter; import com.ibm.wala.util.collections.FilterIterator; import com.ibm.wala.util.collections.HashMapFactory; @@ -104,12 +104,11 @@ public class HeapReachingDefs { } System.err.println("Reaching Defs " + node); if (VERBOSE) { - // System.err.println("Reaching Defs " + node); System.err.println(statements.size()); } // create a control flow graph with one instruction per basic block. - ExpandedControlFlowGraph cfg = new ExpandedControlFlowGraph(ir); + ExplodedControlFlowGraph cfg = ExplodedControlFlowGraph.make(ir); // create a mapping between statements and integers, used in bit vectors // shortly @@ -137,11 +136,11 @@ public class HeapReachingDefs { final Map> delegate = HashMapFactory.make(); private final HeapExclusions exclusions; - + private final CallGraph cg; RDMap(BitVectorSolver solver, OrdinalSetMapping domain, CGNode node, ExtendedHeapModel h, - PointerAnalysis pa, Map> mod, ExpandedControlFlowGraph cfg, + PointerAnalysis pa, Map> mod, ExplodedControlFlowGraph cfg, Map ssaInstructionIndex2Statement, HeapExclusions exclusions, CallGraph cg) { if (VERBOSE) { System.err.println("Init pointer Key mod "); @@ -160,7 +159,7 @@ public class HeapReachingDefs { private void eagerPopulate(Map pointerKeyMod, BitVectorSolver solver, OrdinalSetMapping domain, CGNode node, ExtendedHeapModel h, PointerAnalysis pa, - Map> mod, ExpandedControlFlowGraph cfg, + Map> mod, ExplodedControlFlowGraph cfg, Map ssaInstruction2Statement) { for (Statement s : domain) { delegate.put(s, computeResult(s, pointerKeyMod, solver, domain, node, h, pa, mod, cfg, ssaInstruction2Statement)); @@ -169,11 +168,6 @@ public class HeapReachingDefs { /** * For each pointerKey, which statements may def it - * - * @param domain - * @param node - * @param h - * @param pa */ private Map initPointerKeyMod(OrdinalSetMapping domain, CGNode node, ExtendedHeapModel h, PointerAnalysis pa) { @@ -285,7 +279,7 @@ public class HeapReachingDefs { */ private OrdinalSet computeResult(Statement s, Map pointerKeyMod, BitVectorSolver solver, OrdinalSetMapping domain, CGNode node, ExtendedHeapModel h, - PointerAnalysis pa, Map> mod, ExpandedControlFlowGraph cfg, + PointerAnalysis pa, Map> mod, ExplodedControlFlowGraph cfg, Map ssaInstructionIndex2Statement) { switch (s.getKind()) { case NORMAL: @@ -367,7 +361,7 @@ public class HeapReachingDefs { */ private static Map> makeResult(BitVectorSolver solver, OrdinalSetMapping domain, CGNode node, ExtendedHeapModel h, PointerAnalysis pa, - Map> mod, ExpandedControlFlowGraph cfg, + Map> mod, ExplodedControlFlowGraph cfg, Map ssaInstructionIndex2Statement, HeapExclusions exclusions, CallGraph cg) { return new RDMap(solver, domain, node, h, pa, mod, cfg, ssaInstructionIndex2Statement, exclusions, cg); @@ -447,7 +441,7 @@ public class HeapReachingDefs { private final CGNode node; - private final ExpandedControlFlowGraph cfg; + private final ExplodedControlFlowGraph cfg; private final OrdinalSetMapping domain; @@ -466,7 +460,7 @@ public class HeapReachingDefs { */ private final IBinaryNaturalRelation heapReturnCaller = new BasicNaturalRelation(); - public RD(CGNode node, ExpandedControlFlowGraph cfg, PointerAnalysis pa, OrdinalSetMapping domain, + public RD(CGNode node, ExplodedControlFlowGraph cfg, PointerAnalysis pa, OrdinalSetMapping domain, Map ssaInstructionIndex2Statement, HeapExclusions exclusions) { this.node = node; this.cfg = cfg; @@ -491,7 +485,7 @@ public class HeapReachingDefs { } public UnaryOperator getEdgeTransferFunction(IBasicBlock src, IBasicBlock dst) { - SingleInstructionBasicBlock s = (SingleInstructionBasicBlock) src; + ExplodedBasicBlock s = (ExplodedBasicBlock) src; if (s.getInstruction() != null && !(s.getInstruction() instanceof SSAInvokeInstruction) && !cfg.getNormalSuccessors(src).contains(dst)) { // if the edge only happens due to exceptional control flow, then no @@ -538,7 +532,7 @@ public class HeapReachingDefs { * @return int set representing the heap def statements that are gen'ed by * the basic block. null if none. */ - IntSet gen(SingleInstructionBasicBlock b) { + IntSet gen(ExplodedBasicBlock b) { if (b.isEntryBlock()) { return heapEntryStatements(); } else { @@ -588,7 +582,7 @@ public class HeapReachingDefs { * @return int set representing the heap def statements that are killed by * the basic block. null if none. */ - BitVector kill(SingleInstructionBasicBlock b) { + BitVector kill(ExplodedBasicBlock b) { SSAInstruction s = b.getInstruction(); if (s == null) { return null; diff --git a/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/DeadAssignmentElimination.java b/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/DeadAssignmentElimination.java index 4f573e60d..d27a98721 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/DeadAssignmentElimination.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/DeadAssignmentElimination.java @@ -28,8 +28,7 @@ import com.ibm.wala.util.collections.HashSetFactory; import com.ibm.wala.util.debug.Trace; /** - * - * Eliminate dead assignnments (phis) from an SSA IR. + * Eliminate dead assignments (phis) from an SSA IR. * * @author sfink */ @@ -84,8 +83,6 @@ public class DeadAssignmentElimination { } /** - * @author sfink - * * A dataflow system which computes whether or not a value is dead */ private static class DeadValueSystem extends DefaultFixedPointSolver { diff --git a/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExpandedCFGDotWriter.java b/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExpandedCFGDotWriter.java deleted file mode 100644 index 0c46bd3c3..000000000 --- a/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExpandedCFGDotWriter.java +++ /dev/null @@ -1,144 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package com.ibm.wala.ssa.analysis; - -import java.io.FileWriter; -import java.util.Iterator; - -import com.ibm.wala.ssa.SSACFG; -import com.ibm.wala.ssa.SSACFG.BasicBlock; -import com.ibm.wala.ssa.analysis.ExpandedControlFlowGraph.SingleInstructionBasicBlock; - -/** - * @author Eran Yahav (yahave) - * - */ -public class ExpandedCFGDotWriter { - - public static void write(String fileName, ExpandedControlFlowGraph cfg) throws IllegalArgumentException { - if (cfg == null) { - throw new IllegalArgumentException("cfg cannot be null"); - } - StringBuffer result = new StringBuffer(); - result.append(dotOutput(cfg)); - try { - FileWriter fw = new FileWriter(fileName, false); - fw.write(result.toString()); - fw.close(); - } catch (Exception e) { - throw new RuntimeException("Error writing dot file"); - } - } - - public static void write(String fileName, SSACFG cfg) { - if (cfg == null) { - throw new IllegalArgumentException("cfg cannot be null"); - } - StringBuffer result = new StringBuffer(); - result.append(dotOutput(cfg)); - try { - FileWriter fw = new FileWriter(fileName, false); - fw.write(result.toString()); - fw.close(); - } catch (Exception e) { - throw new RuntimeException("Error writing dot file"); - } - } - - private static StringBuffer dotOutput(ExpandedControlFlowGraph cfg) { - StringBuffer result = new StringBuffer("digraph \"ExpandedControlFlowGraph:\" {\n"); - result.append("center=true;fontsize=12;node [fontsize=12];edge [fontsize=12]; \n"); - - // create nodes for basic-blocks - for (Iterator it = cfg.iterator(); it.hasNext();) { - - SingleInstructionBasicBlock bb = (SingleInstructionBasicBlock) it.next(); - result.append(dotOutput(bb)); - if (bb.isEntryBlock()) { - result.append(" [color=green]\n"); - } else if (bb.isExitBlock()) { - result.append(" [color=red]\n"); - } else { - result.append("\n"); - } - - } - // create edges - for (Iterator it = cfg.iterator(); it.hasNext();) { - SingleInstructionBasicBlock bb = (SingleInstructionBasicBlock) it.next(); - for (Iterator succIt = cfg.getSuccNodes(bb); succIt.hasNext();) { - SingleInstructionBasicBlock succ = (SingleInstructionBasicBlock) succIt.next(); - result.append(dotOutput(bb)); - result.append(" -> "); - result.append(dotOutput(succ)); - - result.append("\n"); - } - } - // close digraph - result.append("}"); - return result; - } - - private static StringBuffer dotOutput(SSACFG cfg) { - StringBuffer result = new StringBuffer("digraph \"ControlFlowGraph:\" {\n"); - result.append("center=true;fontsize=12;node [fontsize=12];edge [fontsize=12]; \n"); - - // create nodes for basic-blocks - for (Iterator it = cfg.iterator(); it.hasNext();) { - - BasicBlock bb = (BasicBlock) it.next(); - result.append(dotOutput(bb)); - if (bb.isEntryBlock()) { - result.append(" [color=green]\n"); - } else if (bb.isExitBlock()) { - result.append(" [color=red]\n"); - } else { - result.append("\n"); - } - - } - // create edges - for (Iterator it = cfg.iterator(); it.hasNext();) { - BasicBlock bb = (BasicBlock) it.next(); - for (Iterator succIt = cfg.getSuccNodes(bb); succIt.hasNext();) { - BasicBlock succ = (BasicBlock) succIt.next(); - result.append(dotOutput(bb)); - result.append(" -> "); - result.append(dotOutput(succ)); - result.append("\n"); - } - } - // close digraph - result.append("}"); - return result; - } - - private static StringBuffer dotOutput(BasicBlock bb) { - StringBuffer result = new StringBuffer(); - result.append("\""); - result.append(bb.getNumber()); - result.append("\""); - return result; - } - - private static StringBuffer dotOutput(SingleInstructionBasicBlock bb) { - StringBuffer result = new StringBuffer(); - result.append("\""); - result.append(bb.getNumber()); - result.append("-"); - result.append(bb.getInstruction()); - result.append("\""); - return result; - } - -} \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExpandedControlFlowGraph.java b/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExpandedControlFlowGraph.java deleted file mode 100644 index 1b40b37e9..000000000 --- a/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExpandedControlFlowGraph.java +++ /dev/null @@ -1,1323 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2002 - 2006 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package com.ibm.wala.ssa.analysis; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.ibm.wala.cfg.ControlFlowGraph; -import com.ibm.wala.cfg.IBasicBlock; -import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.shrikeBT.IInstruction; -import com.ibm.wala.ssa.IR; -import com.ibm.wala.ssa.ISSABasicBlock; -import com.ibm.wala.ssa.SSAInstruction; -import com.ibm.wala.ssa.SSAPhiInstruction; -import com.ibm.wala.ssa.SSAPiInstruction; -import com.ibm.wala.ssa.SSACFG.BasicBlock; -import com.ibm.wala.ssa.SSACFG.ExceptionHandlerBasicBlock; -import com.ibm.wala.util.collections.EmptyIterator; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.collections.HashSetFactory; -import com.ibm.wala.util.debug.Assertions; -import com.ibm.wala.util.debug.Trace; -import com.ibm.wala.util.intset.BitVector; -import com.ibm.wala.util.intset.IntSet; - -/** - * The ExpandedControlFlowGraph provides a convenient way of performing dataflow - * analyses over the SSA IR. The SSA IR is efficient, but complicates analyses - * by exposing null instructions, and by working at the (more efficient) - * basic-blocks level. - * - * The ExpandedControlFlowGraph has the following features: 1. it has a single - * instruction per basic block (acutally, it uses SingleInstructionBasicBlocks) - * 2. all instructions, including phi instructions, are present in the graph 3. - * there are no null instructions in the graph, these are skipped over 4. there - * are designated single entry and single exit nodes that do not contain any - * instructions - * - * At least at this stage, I prefer the less efficient, but more clear - * ExpandedControlFlowGraph representation. - * - * TODO: this needs MAJOR refactoring !!! [EY] - * - * SJF: the treatment of phis here is extremely problematic. This whole thing needs - * major redesign. Slicer uses it now, but it's too fragile. - * - * @author Eran Yahav (yahave) - */ -public class ExpandedControlFlowGraph implements ControlFlowGraph { - private static final boolean DEBUG = false; - - /** - * underlying array of basic blocks - */ - private SingleInstructionBasicBlock[] basicBlocks; - - /** - * map SSAInstructions to their corresponding SingleInstructionBlocks - */ - final Map instructionToBlock = HashMapFactory.make(); - - /** - * underlying IR - */ - final private IR ir; - - /** - * successor relation - */ - final private Map> successors; - - /** - * predecessor relation - */ - final private Map> predecessors; - - /** - * number of entry instruction - */ - private int entry; - - /** - * number of exit instruction - */ - private int exit; - - /** - * A set of blocks that are true-pi instructions - */ - final private Set trueCasePiInstructions = HashSetFactory.make(); - - /** - * entry block - */ - SingleInstructionBasicBlock entryBlock; - - /** - * exit block - */ - SingleInstructionBasicBlock exitBlock; - - /** - * map of fall-through targets - */ - final private Map fallThroughTargets = HashMapFactory.make(); - - /** - * create an ExpandedControlFlowGraph - * - * @param ir - - * method's IR (just to avoid re-getting it) - * @throws IllegalArgumentException if ir is null - */ - public ExpandedControlFlowGraph(IR ir) { - if (ir == null) { - throw new IllegalArgumentException("ir is null"); - } - this.ir = ir; - if (DEBUG) { - debugDump(); - } - - successors = HashMapFactory.make(); - predecessors = HashMapFactory.make(); - createBasicBlocks(); - createGraphEdges(); - if (DEBUG) { - dumpBasicBlocks(); - dumpGraphEdges(); - } - } - - /** - * dump basic blocks into the trace file. debugging only - */ - private void dumpBasicBlocks() { - for (int i = 0; i < basicBlocks.length; i++) { - Trace.println("BB[" + i + "] = " + basicBlocks[i]); - } - } - - /** - * dump graph edges into the trace file debugging only - */ - private void dumpGraphEdges() { - Trace.println("Succ: " + successors.toString()); - Trace.println("Pred: " + predecessors.toString()); - } - - /** - * return the Instruction-Block for the given instruction. - * - * DEPRECATED: use getBlockForInstruction instead. - * - * @param inst - - * instruction - * @return SingleInstructionBasicBlock containing the given instruction - */ - @Deprecated - public SingleInstructionBasicBlock getInstructionBlock(SSAInstruction inst) { - return instructionToBlock.get(inst); - } - - /** - * get all instructions in the method - * - * @return a collection of SSAInstructions - */ - public Collection/* */getAllInstructions() { - return instructionToBlock.keySet(); - } - - /** - * create single-instruction basic-blocks distinguish blocks inside exception - * handler from other blocks. - * - * This is pretty horrible. - * - */ - private void createBasicBlocks() { - - List basicBlockList = new ArrayList(); - - entry = 0; // -1; - entryBlock = new SingleInstructionBasicBlock(entry, null, -1); - entryBlock.setIsEntryBlock(true); - basicBlockList.add(entryBlock); - - for (Iterator it = ir.getControlFlowGraph().iterator(); it.hasNext();) { - BasicBlock bb = (BasicBlock) it.next(); - // add phis first - for (Iterator phiIt = bb.iteratePhis(); phiIt.hasNext();) { - SSAPhiInstruction phi = (SSAPhiInstruction) phiIt.next(); - if (phi != null) { - int blockNum = basicBlockList.size(); - basicBlockList.add(new SingleInstructionBasicBlock(blockNum, phi, -1)); - } - } - - // add pis - for (Iterator piIt = bb.iteratePis(); piIt.hasNext();) { - SSAPiInstruction pi = (SSAPiInstruction) piIt.next(); - if (pi != null) { - int blockNum = basicBlockList.size(); - basicBlockList.add(new SingleInstructionBasicBlock(blockNum, pi, -1)); - } - } - - // then other instructions - for (int i = bb.getFirstInstructionIndex(); i <= bb.getLastInstructionIndex(); i++) { - SSAInstruction s = ir.getInstructions()[i]; - if (s != null) { - int blockNum = basicBlockList.size(); - basicBlockList.add(new SingleInstructionBasicBlock(blockNum, s, i)); - } - } - - // if this is an ExceptionHandlerBasicBlock, add the catch instruction - // too - if (bb instanceof ExceptionHandlerBasicBlock) { - ExceptionHandlerBasicBlock ebb = (ExceptionHandlerBasicBlock) bb; - SSAInstruction catchInst = ebb.getCatchInstruction(); - if (catchInst != null) { - int blockNum = basicBlockList.size(); - basicBlockList.add(new SingleInstructionExceptionHandlerBlock(blockNum, catchInst)); - } - } - } - exit = basicBlockList.size(); - exitBlock = new SingleInstructionBasicBlock(exit, null, -1); - exitBlock.setIsExitBlock(true); - basicBlockList.add(exitBlock); - - basicBlocks = new SingleInstructionBasicBlock[basicBlockList.size()]; - for (int i = 0; i < basicBlockList.size(); i++) { - SingleInstructionBasicBlock sibb = (SingleInstructionBasicBlock) basicBlockList.get(i); - basicBlocks[i] = sibb; - SSAInstruction blockInstruction = sibb.getInstruction(); - if (blockInstruction != null) { - instructionToBlock.put(blockInstruction, sibb); - } - - } - } - - /** - * create graph edges - */ - private void createGraphEdges() { - - for (Iterator it = ir.getControlFlowGraph().iterator(); it.hasNext();) { - BasicBlock bb = (BasicBlock) it.next(); - - if (!basicBlockHasNonNullInstruction(bb) && bb.isEntryBlock()) { - handleLastInstruction(bb, entryBlock); - continue; - } - - List blockInstrctions = getBlockInstructions(bb); - Object[] blockInstructionArray = blockInstrctions.toArray(); - - if (bb.isEntryBlock()) { - SSAInstruction inst = (SSAInstruction) blockInstructionArray[0]; - Assertions.productionAssertion(inst != null); - SingleInstructionBasicBlock currBlock = getInstructionBlock(inst); - addEdge(entryBlock, currBlock); - } - - if (bb.isExitBlock()) { - // TODO: treatment of instructions in the exit block seems to be wrong - if (DEBUG) { - Trace.println(bb + " is the exit block with " + blockInstructionArray.length + " instructions"); - } - } - - if (!basicBlockHasPi(bb)) { - processNoPi(bb, blockInstructionArray); - } else { - processWithPi(bb, blockInstructionArray); - } - } - } - - /** - * process a basic block that does not have pi nodes - * - * @param bb - - * basic block - * @param blockInstructionArray - - * instructions of the basic-block - */ - private void processNoPi(BasicBlock bb, Object[] blockInstructionArray) { - int size = blockInstructionArray.length; - for (int i = 0; i < size; i++) { - SSAInstruction inst = (SSAInstruction) blockInstructionArray[i]; - Assertions.productionAssertion(inst != null); - SingleInstructionBasicBlock currBlock = getInstructionBlock(inst); - if (currBlock == null) { - Assertions.UNREACHABLE("bang " + inst); - } - if (i < size - 1) { - // System.out.println("ADDED EDGE TO SUCCESSOR " + instNum); - SSAInstruction nextInst = (SSAInstruction) blockInstructionArray[i + 1]; - Assertions.productionAssertion(nextInst != null); - SingleInstructionBasicBlock nextBlock = getInstructionBlock(nextInst); - addEdge(currBlock, nextBlock); - fallThroughTargets.put(currBlock, nextBlock); - } else { - handleLastInstruction(bb, currBlock); - } - } - } - - /** - * process a basic block that contain pi nodes - * - * @param bb - - * basic block - * @param blockInstructionArray - - * instructions of the basic-block - */ - private void processWithPi(BasicBlock bb, Object[] blockInstructionArray) { - int size = blockInstructionArray.length; - for (int i = 0; i < size; i++) { - SSAInstruction inst = (SSAInstruction) blockInstructionArray[i]; - Assertions.productionAssertion(inst != null); - SingleInstructionBasicBlock currBlock = getInstructionBlock(inst); - if (i < size - 1 && !(inst instanceof SSAPiInstruction)) { - int j = i + 1; - SSAInstruction nextInst = (SSAInstruction) blockInstructionArray[j]; - while (j < size - 1 && nextInst instanceof SSAPiInstruction) { - j = j + 1; - nextInst = (SSAInstruction) blockInstructionArray[j]; - } - Assertions.productionAssertion(nextInst != null); - SingleInstructionBasicBlock nextBlock = getInstructionBlock(nextInst); - if (!nextBlock.isPiBlock()) { - addEdge(currBlock, nextBlock); - fallThroughTargets.put(currBlock, nextBlock); - } - } else if (i == size - 1) { - for (Iterator it = bb.iteratePis(); it.hasNext();) { - SSAPiInstruction pi = (SSAPiInstruction) it.next(); - SingleInstructionBasicBlock piBlock = getInstructionBlock(pi); - - int piSuccNumber = pi.getSuccessor(); - int currBlockNum = bb.getNumber(); - if (currBlockNum + 1 != piSuccNumber) { - trueCasePiInstructions.add(pi); - } else { - fallThroughTargets.put(currBlock, piBlock); - } - - addEdge(currBlock, piBlock); - } - } else { - handleLastInstruction(bb, currBlock); - } - } - } - - /** - * some code is required here in order to "hop-over" dead blocks that only - * contain null-instructions. - * - * @param bb - - * basic block - * @param instbb - - * an instruction basic-block (SingleInstructionBasicBlock) - */ - private void handleLastInstruction(BasicBlock bb, SingleInstructionBasicBlock instbb) { - assert instbb != null; - // Set successorInstructions = HashSetFactory.make(); - Set edgeWorkSet = HashSetFactory.make(); - - // create initial set of edges - if (!instbb.isPiBlock()) { - for (Iterator sit = ir.getControlFlowGraph().getSuccNodes(bb); sit.hasNext();) { - BasicBlock succNode = (BasicBlock) sit.next(); - boolean fallThrough = isFallThroughEdge(bb, succNode); - edgeWorkSet.add(new BBEdge(bb, succNode, fallThrough)); - } - } else { - SSAPiInstruction pi = (SSAPiInstruction) instbb.getInstruction(); - int succNum = pi.getSuccessor(); - BasicBlock succNode = (BasicBlock) ir.getControlFlowGraph().getNode(succNum); - boolean fallThrough = isFallThroughEdge(bb, succNode); - edgeWorkSet.add(new BBEdge(bb, succNode, fallThrough)); - } - - if (bb.isExitBlock()) { - addEdge(instbb, exitBlock); - } - - while (!edgeWorkSet.isEmpty()) { - // select and remove edge - Iterator workIt = edgeWorkSet.iterator(); - BBEdge edge = (BBEdge) workIt.next(); - boolean fallThru = false; - if (isFallThroughEdge(edge.src, edge.dest)) { - fallThru = true; - } - workIt.remove(); - - if (edge.dest.isEntryBlock()) { - addEdge(instbb, entryBlock); - if (fallThru) { - fallThroughTargets.put(instbb, entryBlock); - } - } else if (edge.dest.isExitBlock()) { - // should go to the entry of the exit block - if (basicBlockHasNonNullInstruction(edge.dest)) { - SSAInstruction succInst = getBasicBlockEntry(edge.dest); - SingleInstructionBasicBlock succBlock = getInstructionBlock(succInst); - addEdge(instbb, succBlock); - if (fallThru) { - fallThroughTargets.put(instbb, succBlock); - } - } else { - // DONE: this is still broken when exit block has no instructions ?? - // FIXED BY ADDING THIS ELSE BRANCH [EY] - addEdge(instbb, exitBlock); - if (fallThru) { - fallThroughTargets.put(instbb, exitBlock); - } - } - } else if (basicBlockHasNonNullInstruction(edge.dest)) { - SSAInstruction succInst = getBasicBlockEntry(edge.dest); - SingleInstructionBasicBlock succBlock = getInstructionBlock(succInst); - addEdge(instbb, succBlock); - if (fallThru) { - fallThroughTargets.put(instbb, succBlock); - } - } else { - // we should skip the block, and add its successor to the - // workset - for (Iterator sit = ir.getControlFlowGraph().getSuccNodes(edge.dest); sit.hasNext();) { - BasicBlock succNode = (BasicBlock) sit.next(); - // preserve the "fallthrough" label - edgeWorkSet.add(new BBEdge(bb, succNode, edge.isFallThrough)); - } - } - - } - } - - /** - * get a set of true-case pi instructions - * - * @return a set of SSAPiInstructions - */ - public Set/* */getTrueCasePiInstructions() { - return trueCasePiInstructions; - } - - /** - * Edge between basic-blocks - * - * @author Eran Yahav (yahave) - */ - private class BBEdge { - /** - * is this a fallthrough edge? - */ - final public boolean isFallThrough; - - /** - * source basic-block - */ - final public BasicBlock src; - - /** - * destination basic-block - */ - final public BasicBlock dest; - - /** - * create a new Edge - * - * @param src - - * source BB - * @param dest - - * destination BB - * @param isFallThrough - - * is the edge a fallthrough edge? - */ - public BBEdge(BasicBlock src, BasicBlock dest, boolean isFallThrough) { - this.src = src; - this.dest = dest; - this.isFallThrough = isFallThrough; - } - - /** - * is this BBEdge equal to another object? - * - * @param other - - * another object to be compared with - * @return true if BBEdge equals to another given BBEdge, false otherwise - */ - @Override - public boolean equals(Object other) { - if (!(other instanceof BBEdge)) { - return false; - } - BBEdge otherEdge = (BBEdge) other; - return src.equals(otherEdge.src) && dest.equals(otherEdge.dest) && isFallThrough == otherEdge.isFallThrough; - } - - /** - * @return BBEdge hashcode - */ - @Override - public int hashCode() { - return src.hashCode() + dest.hashCode(); - } - - /** - * @return string representation of the BBEdge - */ - @Override - public String toString() { - return src + " -> " + dest; - } - - } - - /** - * return all the instructions in a given basic-block - * - * @param bb - - * basic-block - * @return a List of SSAInstructions - */ - private List getBlockInstructions(BasicBlock bb) { - List result = new ArrayList(); - // add phis first - for (Iterator phiIt = bb.iteratePhis(); phiIt.hasNext();) { - SSAPhiInstruction phi = (SSAPhiInstruction) phiIt.next(); - if (phi != null) { - result.add(phi); - } - } - - // add pis - for (Iterator piIt = bb.iteratePis(); piIt.hasNext();) { - SSAPiInstruction pi = (SSAPiInstruction) piIt.next(); - if (pi != null) { - result.add(pi); - if (DEBUG) { - Trace.println("PINODE added"); - } - } - } - - // then other instructions - for (int i = bb.getFirstInstructionIndex(); i <= bb.getLastInstructionIndex(); i++) { - SSAInstruction s = ir.getInstructions()[i]; - if (s != null) { - result.add(s); - } - } - - // if this is an ExceptionHandlerBasicBlock, add the catch instruction - // too - if (bb instanceof ExceptionHandlerBasicBlock) { - ExceptionHandlerBasicBlock ebb = (ExceptionHandlerBasicBlock) bb; - SSAInstruction catchInst = ebb.getCatchInstruction(); - if (catchInst != null) { - result.add(catchInst); - } - } - - return result; - } - - /** - * until DOMO is fixed TODO: once hasPhi is fixed, migrate to use it - * - * @param bb - - * basic-block - * @return true when basic-block has phi nodes, false otherwise - */ - private boolean basicBlockHasPhi(BasicBlock bb) { - List result = new ArrayList(); - for (Iterator phiIt = bb.iteratePhis(); phiIt.hasNext();) { - SSAPhiInstruction phi = (SSAPhiInstruction) phiIt.next(); - if (phi != null) { - result.add(phi); - } - } - return !result.isEmpty(); - } - - /** - * check whether a basic block has non-null instructions - * - * @param bb - - * basic block - * @return true when basic block has non-null instruction, false otherwise. - */ - private boolean basicBlockHasNonNullInstruction(BasicBlock bb) { - for (Iterator it = bb.iterator(); it.hasNext();) { - SSAInstruction inst = (SSAInstruction) it.next(); - if (inst != null) { - return true; - } - } - return false; - } - - /** - * check whether basic-block contains a pi node - * - * @param bb - - * basic block - * @return true when basic-block contains a pi node, false otherwise. - */ - private boolean basicBlockHasPi(BasicBlock bb) { - List result = new ArrayList(); - for (Iterator piIt = bb.iteratePis(); piIt.hasNext();) { - SSAPiInstruction pi = (SSAPiInstruction) piIt.next(); - if (pi != null) { - result.add(pi); - } - } - return !result.isEmpty(); - } - - /** - * returns a basic-block entry the BB entry is either: 1. if block has no - * phis, this is the number of the instructiona at firstInstructionIndex 2. if - * block has phi, it is the number of the first phi instruction - * - * TODO: once hasPhi is fixed, migrate to use it - * - * @param bb - - * basic-block - * @return SSAInstruction which is the basic-block's entry - */ - private SSAInstruction getBasicBlockEntry(BasicBlock bb) { - if (!basicBlockHasPhi(bb)) { - - int origIndex = bb.getFirstInstructionIndex(); - SSAInstruction origInst = ir.getInstructions()[origIndex]; - if (origInst == null) { - int i = origIndex; - while (origInst == null && i < bb.getLastInstructionIndex()) { - i++; - origInst = ir.getInstructions()[i]; - } - } - if (bb.isCatchBlock() && origInst == null) { - origInst = ((ExceptionHandlerBasicBlock) bb).getCatchInstruction(); - } - - Assertions.productionAssertion(origInst != null); - - return origInst; - } else { - SSAInstruction origInst = null; - for (Iterator it = bb.iteratePhis(); it.hasNext() && origInst == null;) { - origInst = (SSAInstruction) it.next(); - } - Assertions.productionAssertion(origInst != null); - return origInst; - } - } - - /** - * add an edge to the expanded graph - * - * @param src - * @param dest - */ - private void addEdge(SingleInstructionBasicBlock src, SingleInstructionBasicBlock dest) { - if (successors.get(src) == null) { - successors.put(src, new ArrayList()); - } - if (predecessors.get(dest) == null) { - predecessors.put(dest, new ArrayList()); - } - - List succList = successors.get(src); - succList.add(dest); - List predList = predecessors.get(dest); - predList.add(src); - } - - /** - * get successors of a basic block - * - * @param src - - * source basic block - * @return a List of successor basic-blocks - */ - public List/* */getSuccessors(BasicBlock src) { - return successors.get(src); - } - - /** - * get predecessors of a basic block - * - * @param dest - - * destination basic block (starting point) - * @return a List of predecessor basic-blocks - */ - public List/* */getPredecessors(BasicBlock dest) { - return predecessors.get(dest); - } - - /** - * Return the entry basic block in the CFG - */ - public IBasicBlock entry() { - return basicBlocks[entry]; - } - - /** - * @return the synthetic exit block for the cfg - */ - public IBasicBlock exit() { - return basicBlocks[exit]; - } - - /** - * @return the indices of the catch blocks, as a bit vector - */ - public BitVector getCatchBlocks() { - // todo ... this can't be correct, can it? - return ir.getControlFlowGraph().getCatchBlocks(); - } - - /** - * @param index - * an instruction index from the original SSA IR - * @return the basic block which contains this instruction. - */ - public IBasicBlock getBlockForInstruction(int index) { - // this is horrible and ugly. - SSAInstruction s = null; - // find the first non-null instruction following the index, since this class elides null instructions. - do { - s = ir.getInstructions()[index++]; - } while (s == null); - return instructionToBlock.get(s); - } - - /** - * @return the instructions of this CFG, as an array. - */ - public IInstruction[] getInstructions() { - return ir.getControlFlowGraph().getInstructions(); - } - - /** - * @param index - * an instruction index - * @return the program counter (bytecode index) corresponding to that - * instruction - */ - public int getProgramCounter(int index) { - return ir.getControlFlowGraph().getProgramCounter(index); - } - - /** - * @return the Method this CFG represents - */ - public IMethod getMethod() { - return ir.getMethod(); - } - - /** - * @param b - * @return the basic blocks which may be reached from b via exceptional - * control flow - */ - public Collection getExceptionalSuccessors(IBasicBlock b) { - return ir.getControlFlowGraph().getExceptionalSuccessors(b); - } - - /** - * @param b - * @return the basic blocks which may be reached from b via normal control - * flow - */ - public Collection getNormalSuccessors(IBasicBlock b) { - return Collections.unmodifiableCollection(successors.get(b)); - } - - /** - * @param node - - * source node - */ - public int getPredNodeCount(IBasicBlock node) { - List l = predecessors.get(node); - return l == null ? 0 : l.size(); - } - - /** - * @param node - - * source node - * @return iterator over successor nodes - */ - public Iterator getSuccNodes(IBasicBlock node) { - List succNodes = successors.get(node); - if (succNodes != null) { - return succNodes.iterator(); - } else { - List l = Collections.emptyList(); - return l.iterator(); - } - } - - /** - * @param node - - * source node - * @return number of successor nodes - */ - public int getSuccNodeCount(IBasicBlock node) { - return successors.get(node).size(); - } - - /** - * unsupported operation - * @throws UnsupportedOperationException unconditionally - */ - public void addEdge(IBasicBlock src, IBasicBlock dst) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * unsupported operation - */ - public void removeEdge(IBasicBlock src, IBasicBlock dst) { - throw new UnsupportedOperationException(); - } - - /** - * unsupported operation - */ - public void removeAllIncidentEdges(IBasicBlock node) { - throw new UnsupportedOperationException(); - } - - /** - * unsupported operation - */ - public void removeIncomingEdges(IBasicBlock node) { - throw new UnsupportedOperationException(); - } - - /** - * unsupported operation - */ - public void removeOutgoingEdges(IBasicBlock node) { - throw new UnsupportedOperationException(); - } - - /** - * unsupported operation - */ - public Iterator iterateNodes(IntSet set) { - throw new UnsupportedOperationException(); - } - - /** - * unsupported operation - */ - public boolean containsNode(IBasicBlock n) { - throw new UnsupportedOperationException(); - } - - /** - * unsupported operation - */ - public int getMaxNumber() { - throw new UnsupportedOperationException(); - } - - public Iterator iterator() { - List a = new ArrayList(); - for (SingleInstructionBasicBlock b : basicBlocks) { - a.add(b); - } - return a.iterator(); - } - - /** - * unsupported operation - * - * @param obj - - * object to be removed - */ - public void removeNode(IBasicBlock obj) { - throw new UnsupportedOperationException(); - } - - /** - * @param node - - * source node - * @return iterator over predecssors of given node - */ - public Iterator getPredNodes(IBasicBlock node) { - List predNodes = predecessors.get(node); - if (predNodes != null) { - return predNodes.iterator(); - } else { - return EmptyIterator.instance(); - } - } - - /** - * unsupported operation - * - * @param n - * @throws UnsupportedOperationException unconditionally - */ - public void addNode(IBasicBlock n) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * unsupported operation - * - * @param n - */ - public void removeNodeAndEdges(IBasicBlock n) { - throw new UnsupportedOperationException(); - } - - /** - * unsupported operation - * - * @param n - */ - public int getNumber(IBasicBlock n) { - throw new UnsupportedOperationException(); - } - - /** - * @param i - - * number of node to be returned - * @return the i-th node - */ - public IBasicBlock getNode(int i) { - return basicBlocks[i]; - } - - /** - * @return number of nodes in the graph - */ - public int getNumberOfNodes() { - return basicBlocks.length; - } - - /** - * is the given edge a fall-through edge? - * - * @return note: this is based on a WALA-invariant that guarantees the blocks - * are numbered in a certain way. This is the "WALA-way" of - * identifying fall-through edges, and is mainly done due for - * efficiency reasons (as many other software crimes). - */ - private boolean isFallThroughEdge(IBasicBlock src, IBasicBlock dest) { - if (ir.getControlFlowGraph().getSuccNodeCount(src) == 2) { - return ((src.getNumber() + 1) == dest.getNumber()); - } else { - return false; - } - } - - public boolean isFallThroughTarget(IBasicBlock src, IBasicBlock dest) { - IBasicBlock ftt = getFallThroughTarget(src); - return (ftt != null) && ftt.equals(dest); - } - - /** - * get the fall-through target of a given source block - * - * @param src - - * source block - * @return the fall-through target of the given src block - */ - public IBasicBlock getFallThroughTarget(IBasicBlock src) { - return fallThroughTargets.get(src); - } - - /** - * SingleInstructionBasicBlock A basic-block containing a single instructions. - * These are used as building-blocks of the ExpandedControlFlowGraph. - * - * @author Eran Yahav (yahave) - */ - public class SingleInstructionBasicBlock implements ISSABasicBlock { - /** - * block number - */ - private int number; - - /** - * instruction contained in the block (a single instruction!) - */ - final private SSAInstruction instruction; - - - /** - * If the instruction is a normal instruction, then the index of said instruction - * in the SSA instruction array. If the instruction is a phi or pi, then this is - * -1. - */ - private final int normalInstructionIndex; - - /** - * is this an exit block? - */ - private boolean isExit = false; - - /** - * is this an entry block? - */ - private boolean isEntry = false; - - /** - * create a new SingleInstructionBasicBlock - * - * @param number - - * block number - * @param instruction - - * contained instruction - */ - public SingleInstructionBasicBlock(int number, SSAInstruction instruction, int normalInstructionIndex) { - this.number = number; - this.instruction = instruction; - this.normalInstructionIndex = normalInstructionIndex; - } - - /** - * get block instruction - * - * @return instruction in the block - */ - public SSAInstruction getInstruction() { - return instruction; - } - - /** - * get the index of the first (and only) normal instruction in the block - */ - public int getFirstInstructionIndex() { - return normalInstructionIndex; - } - - /** - * get the index of the last (and only) normal instruction in the block - */ - public int getLastInstructionIndex() { - return normalInstructionIndex; - } - - /** - * is this a catch block? - * - * @return false, this class does not represent catch blocks - */ - public boolean isCatchBlock() { - return false; - } - - /** - * does this single-instruction block contains a pi-instruction? - * - * @return true if it is a Pi instruction - */ - public boolean isPiBlock() { - return (instruction instanceof SSAPiInstruction); - } - - /** - * set this block as an entry block - * - * @param val - - * new value - */ - public void setIsEntryBlock(boolean val) { - isEntry = val; - } - - /** - * set this block as exit block - * - * @param val - - * new value - */ - public void setIsExitBlock(boolean val) { - isExit = val; - } - - /** - * is this block an exit block? - * - * @return true if this is an exit block, false otherwise - */ - public boolean isExitBlock() { - return isExit; - } - - /** - * is this block an entry block? - * - * @return true if this is an entry block, false otherwise - */ - public boolean isEntryBlock() { - return isEntry; - } - - /** - * get the method containing this block - * - * @return IMethod of the method containing this block - */ - public IMethod getMethod() { - return ir.getMethod(); - } - - /** - * @return the {@link ExpandedControlFlowGraph} to which this block belongs - */ - public ExpandedControlFlowGraph getCFG() { - return ExpandedControlFlowGraph.this; - } - - /** - * get number of the block - * - * @return block number - */ - public int getNumber() { - return number; - } - - /** - * get graph-node ID - * - * @return graph-node ID (same as block number) - */ - public int getGraphNodeId() { - return number; - } - - /** - * set the graph-node ID - * - * @param id - - * node ID to be set. - */ - public void setGraphNodeId(int id) { - number = id; - } - - public Iterator iteratePhis() { - throw new UnsupportedOperationException("NYI"); - } - - public Iterator iteratePis() { - throw new UnsupportedOperationException("NYI"); - } - - public Iterator iterator() { - Collection s = Collections.singleton((IInstruction)instruction); - return s.iterator(); - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof SingleInstructionBasicBlock)) { - return false; - } - SingleInstructionBasicBlock otherBlock = (SingleInstructionBasicBlock) other; - return (otherBlock.number == number); - } - - @Override - public int hashCode() { - return number; - } - - @Override - public String toString() { - if (isEntry) { - return "entry"; - } else if (isExit) { - return "exit"; - } else { - return number + " : " + instruction.toString(); - } - } - - public SSAInstruction getLastInstruction() { - return instruction; - } - - } - - /** - * SingleInstructionExceptionHandlerBlock BB for exception handler. - * - * @author Eran Yahav (yahave) - */ - public class SingleInstructionExceptionHandlerBlock extends SingleInstructionBasicBlock { - /** - * create a new exception handler block. - * - * @param number - - * number of block - * @param instruction - - * instruction contained in the block - */ - public SingleInstructionExceptionHandlerBlock(int number, SSAInstruction instruction) { - // note that the single instruction, GetCaughtException, is not in the normal - // ssa instruction array, so we pass -1 as the normalInstructionIndex - super(number, instruction, -1); - } - - /** - * is this block a catch block? - * - * @return true, since SingleInstructionExceptionHandlerBlock is always a - * catch block. - */ - @Override - public boolean isCatchBlock() { - return true; - } - } - - /** - * dump dot files of the current CFG and the underlying original CFG. note: - * only used for debugging. - */ - public void dumpDotFile() { - ExpandedCFGDotWriter.write("c:/temp/original.dt", ir.getControlFlowGraph()); - ExpandedCFGDotWriter.write("c:/temp/expanded.dt", this); - } - - /** - * dump debug information. note: only used for debugging. - */ - private void debugDump() { - Trace.println("IR INST: " + ir.getInstructions().length); - Trace.println("CFG INST: " + ir.getControlFlowGraph().getInstructions().length); - - SSAInstruction[] debugInstIR = ir.getInstructions(); - - int countDebugIR = 0; - for (int i = 0; i < debugInstIR.length; i++) { - if (debugInstIR[i] != null) { - countDebugIR++; - } - } - - Trace.println("The countDebugIR is:" + countDebugIR); - - int countInst = 0; - for (Iterator it = ir.iterateAllInstructions(); it.hasNext();) { - SSAInstruction inst = (SSAInstruction) it.next(); - if (inst == null) { - Trace.println("*KABOOM*"); - } - countInst++; - } - - Trace.println("The countInst is:" + countInst); - - for (Iterator debugIt = ir.iteratePhis(); debugIt.hasNext();) { - SSAPhiInstruction phi = (SSAPhiInstruction) debugIt.next(); - Trace.println(phi); - } - } - - public Collection getExceptionalPredecessors(IBasicBlock b) { - Assertions.UNREACHABLE(); - return null; - } - - public Collection getNormalPredecessors(IBasicBlock b) { - Assertions.UNREACHABLE(); - return null; - } - - public boolean hasEdge(IBasicBlock src, IBasicBlock dst) { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - return false; - } - - public IntSet getSuccNodeNumbers(IBasicBlock node) { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - return null; - } - - public IntSet getPredNodeNumbers(IBasicBlock node) { - // TODO Auto-generated method stub - Assertions.UNREACHABLE(); - return null; - } - -} diff --git a/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExplodedControlFlowGraph.java b/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExplodedControlFlowGraph.java new file mode 100644 index 000000000..6f8ce76da --- /dev/null +++ b/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/ExplodedControlFlowGraph.java @@ -0,0 +1,418 @@ +/******************************************************************************* + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package com.ibm.wala.ssa.analysis; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.cfg.IBasicBlock; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.shrikeBT.IInstruction; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.NonNullSingletonIterator; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.intset.BitVector; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.SimpleVector; + +/** + * A view of a control flow graph where each basic block corresponds to exactly + * one SSA instruction index. + * + * Prototype: Not terribly efficient. + */ +public class ExplodedControlFlowGraph implements ControlFlowGraph { + + private final IR ir; + + private final SimpleVector normalNodes = new SimpleVector(); + + private final Collection allNodes = HashSetFactory.make(); + + private final ExplodedBasicBlock entry; + + private final ExplodedBasicBlock exit; + + private ExplodedControlFlowGraph(IR ir) { + this.ir = ir; + this.entry = new ExplodedBasicBlock(-2, ir.getControlFlowGraph().entry()); + this.exit = new ExplodedBasicBlock(-2, ir.getControlFlowGraph().exit()); + createNodes(); + } + + private void createNodes() { + allNodes.add(entry); + allNodes.add(exit); + for (IBasicBlock b : ir.getControlFlowGraph()) { + for (int i = b.getFirstInstructionIndex(); i <= b.getLastInstructionIndex(); i++) { + ExplodedBasicBlock bb = new ExplodedBasicBlock(i, b); + normalNodes.set(i, bb); + allNodes.add(bb); + } + } + } + + public static ExplodedControlFlowGraph make(IR ir) { + return new ExplodedControlFlowGraph(ir); + } + + public IBasicBlock entry() { + return entry; + } + + public IBasicBlock exit() { + return exit; + } + + public IBasicBlock getBlockForInstruction(int index) { + return normalNodes.get(index); + } + + public BitVector getCatchBlocks() { + Assertions.UNREACHABLE(); + return null; + } + + public Collection getExceptionalPredecessors(IBasicBlock b) { + Assertions.UNREACHABLE(); + return null; + } + + public Collection getExceptionalSuccessors(IBasicBlock b) { + assert b != null; + if (b.equals(exit)) { + return Collections.emptySet(); + } + ExplodedBasicBlock eb = (ExplodedBasicBlock) b; + if (eb.isEntryBlock() || eb.instructionIndex == eb.original.getLastInstructionIndex()) { + List result = new ArrayList(); + for (IBasicBlock s : ir.getControlFlowGraph().getExceptionalSuccessors(eb.original)) { + if (s.equals(ir.getControlFlowGraph().exit())) { + result.add(exit()); + } else { + assert normalNodes.get(s.getFirstInstructionIndex()) != null; + result.add(normalNodes.get(s.getFirstInstructionIndex())); + } + } + return result; + } else { + return Collections.emptySet(); + } + } + + public IInstruction[] getInstructions() { + return ir.getInstructions(); + } + + public IMethod getMethod() { + Assertions.UNREACHABLE(); + return null; + } + + public Collection getNormalPredecessors(IBasicBlock b) { + Assertions.UNREACHABLE(); + return null; + } + + public Collection getNormalSuccessors(IBasicBlock b) { + assert b != null; + if (b.equals(exit)) { + return Collections.emptySet(); + } + ExplodedBasicBlock eb = (ExplodedBasicBlock) b; + if (eb.isEntryBlock() || eb.instructionIndex == eb.original.getLastInstructionIndex()) { + List result = new ArrayList(); + for (IBasicBlock s : ir.getControlFlowGraph().getNormalSuccessors(eb.original)) { + if (s.equals(ir.getControlFlowGraph().exit())) { + result.add(exit()); + } else { + assert normalNodes.get(s.getFirstInstructionIndex()) != null; + result.add(normalNodes.get(s.getFirstInstructionIndex())); + } + } + return result; + } else { + assert normalNodes.get(eb.instructionIndex + 1) != null; + return Collections.singleton(normalNodes.get(eb.instructionIndex + 1)); + } + } + + public int getProgramCounter(int index) { + Assertions.UNREACHABLE(); + return 0; + } + + public void removeNodeAndEdges(IBasicBlock N) throws UnsupportedOperationException { + Assertions.UNREACHABLE(); + + } + + public void addNode(IBasicBlock n) { + Assertions.UNREACHABLE(); + + } + + public boolean containsNode(IBasicBlock N) { + Assertions.UNREACHABLE(); + return false; + } + + public int getNumberOfNodes() { + return allNodes.size(); + } + + public Iterator iterator() { + return allNodes.iterator(); + } + + public void removeNode(IBasicBlock n) { + Assertions.UNREACHABLE(); + + } + + public void addEdge(IBasicBlock src, IBasicBlock dst) { + Assertions.UNREACHABLE(); + + } + + public int getPredNodeCount(IBasicBlock N) { + ExplodedBasicBlock b = (ExplodedBasicBlock) N; + if (b.isEntryBlock()) { + return 0; + } + if (b.equals(exit) || b.instructionIndex == b.original.getFirstInstructionIndex()) { + return ir.getControlFlowGraph().getPredNodeCount(b.original); + } else { + return 1; + } + } + + public Iterator getPredNodes(IBasicBlock N) { + ExplodedBasicBlock b = (ExplodedBasicBlock) N; + if (b.isEntryBlock()) { + return EmptyIterator.instance(); + } + if (b.equals(exit) || b.instructionIndex == b.original.getFirstInstructionIndex()) { + List result = new ArrayList(); + for (Iterator it = ir.getControlFlowGraph().getPredNodes(b.original); it.hasNext();) { + IBasicBlock s = it.next(); + if (s.isEntryBlock()) { + result.add(entry); + } else { + assert normalNodes.get(s.getLastInstructionIndex()) != null; + result.add(normalNodes.get(s.getLastInstructionIndex())); + } + } + return result.iterator(); + } else { + assert normalNodes.get(b.instructionIndex - 1) != null; + return NonNullSingletonIterator.make(normalNodes.get(b.instructionIndex - 1)); + } + } + + public int getSuccNodeCount(IBasicBlock N) { + Assertions.UNREACHABLE(); + return 0; + } + + public Iterator getSuccNodes(IBasicBlock N) { + assert N != null; + if (N.equals(exit)) { + return EmptyIterator.instance(); + } + ExplodedBasicBlock b = (ExplodedBasicBlock) N; + if (b.isEntryBlock() || b.instructionIndex == b.original.getLastInstructionIndex()) { + List result = new ArrayList(); + for (Iterator it = ir.getControlFlowGraph().getSuccNodes(b.original); it.hasNext();) { + IBasicBlock s = it.next(); + if (s.equals(ir.getControlFlowGraph().exit())) { + result.add(exit()); + } else { + assert normalNodes.get(s.getFirstInstructionIndex()) != null; + result.add(normalNodes.get(s.getFirstInstructionIndex())); + } + } + return result.iterator(); + } else { + assert normalNodes.get(b.instructionIndex + 1) != null; + return NonNullSingletonIterator.make(normalNodes.get(b.instructionIndex + 1)); + } + } + + public boolean hasEdge(IBasicBlock src, IBasicBlock dst) { + Assertions.UNREACHABLE(); + return false; + } + + public void removeAllIncidentEdges(IBasicBlock node) throws UnsupportedOperationException { + Assertions.UNREACHABLE(); + + } + + public void removeEdge(IBasicBlock src, IBasicBlock dst) throws UnsupportedOperationException { + Assertions.UNREACHABLE(); + + } + + public void removeIncomingEdges(IBasicBlock node) throws UnsupportedOperationException { + Assertions.UNREACHABLE(); + + } + + public void removeOutgoingEdges(IBasicBlock node) throws UnsupportedOperationException { + Assertions.UNREACHABLE(); + + } + + public int getMaxNumber() { + Assertions.UNREACHABLE(); + return 0; + } + + public IBasicBlock getNode(int number) { + if (number == 0) { + return entry(); + } else if (number == getNumberOfNodes() -1) { + return exit(); + } else { + return normalNodes.get(number); + } + } + + public int getNumber(IBasicBlock N) { + Assertions.UNREACHABLE(); + return 0; + } + + public Iterator iterateNodes(IntSet s) { + Assertions.UNREACHABLE(); + return null; + } + + public IntSet getPredNodeNumbers(IBasicBlock node) { + Assertions.UNREACHABLE(); + return null; + } + + public IntSet getSuccNodeNumbers(IBasicBlock node) { + Assertions.UNREACHABLE(); + return null; + } + + public class ExplodedBasicBlock implements IBasicBlock { + + private final int instructionIndex; + + private final IBasicBlock original; + + public ExplodedBasicBlock(int instructionIndex, IBasicBlock original) { + this.instructionIndex = instructionIndex; + this.original = original; + assert original != null; + } + + public int getFirstInstructionIndex() { + return instructionIndex; + } + + public int getLastInstructionIndex() { + return instructionIndex; + } + + public IMethod getMethod() { + Assertions.UNREACHABLE(); + return null; + } + + public int getNumber() { + if (isEntryBlock()) { + return 0; + } else if (isExitBlock()) { + return getNumberOfNodes() -1; + } else { + return instructionIndex; + } + } + + public boolean isCatchBlock() { + Assertions.UNREACHABLE(); + return false; + } + + public boolean isEntryBlock() { + return original.isEntryBlock(); + } + + public boolean isExitBlock() { + return original.isExitBlock(); + } + + public int getGraphNodeId() { + Assertions.UNREACHABLE(); + return 0; + } + + public void setGraphNodeId(int number) { + Assertions.UNREACHABLE(); + + } + + public Iterator iterator() { + Assertions.UNREACHABLE(); + return null; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + instructionIndex; + result = prime * result + ((original == null) ? 0 : original.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final ExplodedBasicBlock other = (ExplodedBasicBlock) obj; + if (instructionIndex != other.instructionIndex) + return false; + if (original == null) { + if (other.original != null) + return false; + } else if (!original.equals(other.original)) + return false; + return true; + } + + public SSAInstruction getInstruction() { + if (isEntryBlock() || isExitBlock()) { + return null; + } else { + return ir.getInstructions()[instructionIndex]; + } + } + } + +} \ No newline at end of file