/** * This file is licensed under the University of Illinois/NCSA Open Source License. See LICENSE.TXT for details. */ package edu.illinois.keshmesh.detector; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import org.eclipse.jdt.core.IJavaProject; import com.ibm.wala.classLoader.IMethod; import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.ssa.ISSABasicBlock; import com.ibm.wala.ssa.SSACFG; import com.ibm.wala.ssa.SSAInstruction; import edu.illinois.keshmesh.detector.bugs.CodePosition; import edu.illinois.keshmesh.detector.util.AnalysisUtils; /** * * @author Mohsen Vakilian * @author Stas Negara * */ public class InstructionInfo { private final IJavaProject javaProject; private final CGNode cgNode; private final SSAInstruction ssaInstruction; private final int instructionIndex; public InstructionInfo(IJavaProject javaProject, CGNode cgNode, int instructionIndex) { this.javaProject = javaProject; this.cgNode = cgNode; this.instructionIndex = instructionIndex; this.ssaInstruction = cgNode.getIR().getInstructions()[instructionIndex]; } public CodePosition getPosition() { IMethod method = cgNode.getMethod(); return AnalysisUtils.getPosition(javaProject, method, instructionIndex); } public CGNode getCGNode() { return cgNode; } public SSAInstruction getInstruction() { return ssaInstruction; } public int getInstructionIndex() { return instructionIndex; } public boolean isInside(InstructionInfo that) { if (!(AnalysisUtils.isMonitorEnter(that.ssaInstruction))) { throw new RuntimeException("Should not check 'is inside' relation for an instruction that is not a monitor enter: " + that); } if (cgNode != that.cgNode) { return false; } return that.getInsideInstructionIndexes().contains(instructionIndex); } private Collection<InstructionInfo> getMatchingMonitorExits() { if (!(AnalysisUtils.isMonitorEnter(ssaInstruction))) { throw new RuntimeException("Should not look matching monitor exits of an instruction that is not a monitor enter: " + this); } Collection<InstructionInfo> matchingMonitorExits = new HashSet<InstructionInfo>(); final int monitorEnterLockValueNumber = ssaInstruction.getUse(0); final int monitorEnterLineNumber = getPosition().getFirstLine(); AnalysisUtils.collect(javaProject, matchingMonitorExits, cgNode, new InstructionFilter() { @Override public boolean accept(InstructionInfo instructionInfo) { if (AnalysisUtils.isMonitorExit(instructionInfo.getInstruction())) { if (instructionInfo.getInstruction().getUse(0) == monitorEnterLockValueNumber && instructionInfo.getPosition().getFirstLine() == monitorEnterLineNumber) { return true; } } return false; } }); return matchingMonitorExits; } private Collection<Integer> getInsideInstructionIndexes() { Collection<Integer> matchingMonitorExitIndexes = getIndexes(getMatchingMonitorExits()); SSACFG controlFlowGraph = cgNode.getIR().getControlFlowGraph(); Collection<Integer> visitedInstructionIndexes = new HashSet<Integer>(); LinkedList<ISSABasicBlock> workList = new LinkedList<ISSABasicBlock>(); workList.add(controlFlowGraph.getBlockForInstruction(instructionIndex)); while (!workList.isEmpty()) { ISSABasicBlock basicBlock = workList.poll(); Iterator<ISSABasicBlock> succNodesIterator = controlFlowGraph.getSuccNodes(basicBlock); while (succNodesIterator.hasNext()) { ISSABasicBlock succBasicBlock = succNodesIterator.next(); boolean visitedNewInstructions = visitBasicBlockInstructions(succBasicBlock, matchingMonitorExitIndexes, visitedInstructionIndexes); if (visitedNewInstructions && !containsMonitorExit(succBasicBlock, matchingMonitorExitIndexes)) { workList.add(succBasicBlock); } } } return visitedInstructionIndexes; } private boolean visitBasicBlockInstructions(ISSABasicBlock basicBlock, Collection<Integer> matchingMonitorExitIndexes, Collection<Integer> visitedInstructionIndexes) { boolean visitedNewInstructions = false; for (int instructionIndex = basicBlock.getFirstInstructionIndex(); instructionIndex <= basicBlock.getLastInstructionIndex(); instructionIndex++) { if (matchingMonitorExitIndexes.contains(instructionIndex)) { break; } if (!visitedInstructionIndexes.contains(instructionIndex)) { visitedInstructionIndexes.add(instructionIndex); visitedNewInstructions = true; } } return visitedNewInstructions; } private boolean containsMonitorExit(ISSABasicBlock basicBlock, Collection<Integer> matchingMonitorExitIndexes) { for (int instructionIndex = basicBlock.getFirstInstructionIndex(); instructionIndex <= basicBlock.getLastInstructionIndex(); instructionIndex++) { if (matchingMonitorExitIndexes.contains(instructionIndex)) { return true; } } return false; } private Collection<Integer> getIndexes(Collection<InstructionInfo> instructionInfos) { Collection<Integer> instructionIndexes = new HashSet<Integer>(); for (InstructionInfo instructionInfo : instructionInfos) { instructionIndexes.add(instructionInfo.instructionIndex); } return instructionIndexes; } @Override public String toString() { return "InstructionInfo [method=" + cgNode.getMethod().getSignature() + ", ssaInstruction=" + ssaInstruction + ", instructionIndex=" + instructionIndex + "]"; } }