001: /*
002: * Bytecode Analysis Framework
003: * Copyright (C) 2003-2005 University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.ba;
021:
022: import java.util.BitSet;
023: import java.util.HashSet;
024: import java.util.Iterator;
025: import java.util.Set;
026:
027: import org.apache.bcel.Constants;
028: import org.apache.bcel.classfile.JavaClass;
029: import org.apache.bcel.classfile.Method;
030: import org.apache.bcel.generic.ConstantPoolGen;
031: import org.apache.bcel.generic.Instruction;
032: import org.apache.bcel.generic.InstructionHandle;
033: import org.apache.bcel.generic.InvokeInstruction;
034: import org.apache.bcel.generic.MethodGen;
035:
036: import edu.umd.cs.findbugs.SystemProperties;
037: import edu.umd.cs.findbugs.ba.type.TypeDataflow;
038: import edu.umd.cs.findbugs.ba.type.TypeFrame;
039:
040: public class PruneUnconditionalExceptionThrowerEdges implements
041: EdgeTypes {
042: private static final boolean DEBUG = SystemProperties
043: .getBoolean("cfg.prune.throwers.debug");
044: private static final boolean DEBUG_DIFFERENCES = SystemProperties
045: .getBoolean("cfg.prune.throwers.differences.debug");
046:
047: private MethodGen methodGen;
048: private CFG cfg;
049: private ConstantPoolGen cpg;
050: private TypeDataflow typeDataflow;
051: private AnalysisContext analysisContext;
052: private boolean cfgModified;
053:
054: private static final BitSet RETURN_OPCODE_SET = new BitSet();
055: static {
056: RETURN_OPCODE_SET.set(Constants.ARETURN);
057: RETURN_OPCODE_SET.set(Constants.IRETURN);
058: RETURN_OPCODE_SET.set(Constants.LRETURN);
059: RETURN_OPCODE_SET.set(Constants.DRETURN);
060: RETURN_OPCODE_SET.set(Constants.FRETURN);
061: RETURN_OPCODE_SET.set(Constants.RETURN);
062: }
063:
064: public PruneUnconditionalExceptionThrowerEdges(
065: /*ClassContext classContext,*/JavaClass javaClass,
066: Method method, MethodGen methodGen, CFG cfg,
067: ConstantPoolGen cpg, TypeDataflow typeDataflow,
068: AnalysisContext analysisContext) {
069: // this.classContext = classContext;
070: this .methodGen = methodGen;
071: this .cfg = cfg;
072: this .cpg = cpg;
073: this .typeDataflow = typeDataflow;
074: this .analysisContext = analysisContext;
075: }
076:
077: public void execute() throws CFGBuilderException,
078: DataflowAnalysisException {
079: AnalysisContext currentAnalysisContext = AnalysisContext
080: .currentAnalysisContext();
081: if (currentAnalysisContext
082: .getBoolProperty(AnalysisFeatures.CONSERVE_SPACE))
083: throw new IllegalStateException("This should not happen");
084:
085: Set<Edge> deletedEdgeSet = new HashSet<Edge>();
086: // TypeDataflow typeDataflow = classContext.getTypeDataflow(method);
087:
088: if (DEBUG)
089: System.out
090: .println("PruneUnconditionalExceptionThrowerEdges: examining "
091: + SignatureConverter
092: .convertMethodSignature(methodGen));
093:
094: for (Iterator<BasicBlock> i = cfg.blockIterator(); i.hasNext();) {
095: BasicBlock basicBlock = i.next();
096: if (!basicBlock.isExceptionThrower())
097: continue;
098:
099: InstructionHandle instructionHandle = basicBlock
100: .getExceptionThrower();
101: Instruction exceptionThrower = instructionHandle
102: .getInstruction();
103: if (!(exceptionThrower instanceof InvokeInstruction))
104: continue;
105:
106: InvokeInstruction inv = (InvokeInstruction) exceptionThrower;
107: boolean foundThrower = false;
108: boolean foundNonThrower = false;
109:
110: String className = inv.getClassName(cpg);
111: if (DEBUG)
112: System.out.println("\tlooking up method for "
113: + instructionHandle + " in " + className);
114:
115: Location loc = new Location(instructionHandle, basicBlock);
116: TypeFrame typeFrame = typeDataflow.getFactAtLocation(loc);
117: XMethod primaryXMethod = null;
118: Set<XMethod> targetSet = null;
119: try {
120:
121: if (className.startsWith("["))
122: continue;
123: String methodSig = inv.getSignature(cpg);
124: if (!methodSig.endsWith("V"))
125: continue;
126:
127: targetSet = Hierarchy2.resolveMethodCallTargets(inv,
128: typeFrame, cpg);
129:
130: for (XMethod xMethod : targetSet) {
131: if (DEBUG)
132: System.out.println("\tFound " + xMethod);
133: // Ignore abstract and native methods
134: Boolean isUnconditionalThrower = doesMethodUnconditionallyThrowException(xMethod);
135:
136: if (isUnconditionalThrower) {
137: foundThrower = true;
138: if (DEBUG)
139: System.out.println("Found thrower");
140: } else {
141: foundNonThrower = true;
142: if (DEBUG)
143: System.out.println("Found non thrower");
144: }
145:
146: }
147: } catch (ClassNotFoundException e) {
148: analysisContext.getLookupFailureCallback()
149: .reportMissingClass(e);
150: }
151: boolean newResult = foundThrower && !foundNonThrower;
152: if (newResult) {
153: // Method always throws an unhandled exception
154: // Remove the normal control flow edge from the CFG.
155: Edge fallThrough = cfg.getOutgoingEdgeWithType(
156: basicBlock, FALL_THROUGH_EDGE);
157: if (fallThrough != null) {
158: if (DEBUG) {
159: System.out
160: .println("\tREMOVING normal return for: "
161: + XFactory.createXMethod(inv,
162: cpg));
163: }
164: deletedEdgeSet.add(fallThrough);
165: }
166: }
167:
168: }
169:
170: // Remove all edges marked for deletion
171: for (Edge edge : deletedEdgeSet) {
172: cfg.removeEdge(edge);
173: cfgModified = true;
174: }
175: }
176:
177: /**
178: * @param xMethod
179: * @param javaClass
180: * @param method
181: * @return true if method unconditionally throws
182: * @deprecated Use {@link #doesMethodUnconditionallyThrowException(XMethod)} instead
183: */
184: static public Boolean doesMethodUnconditionallyThrowException(
185: XMethod xMethod, JavaClass javaClass, Method method) {
186: return doesMethodUnconditionallyThrowException(xMethod);
187: }
188:
189: /**
190: * @param xMethod
191: * @return true if method unconditionally throws
192: */
193: static public boolean doesMethodUnconditionallyThrowException(
194: XMethod xMethod) {
195: return xMethod.isUnconditionalThrower();
196: }
197:
198: /**
199: * Return whether or not the CFG was modified.
200: *
201: * @return true if CFG was modified, false otherwise
202: */
203: public boolean wasCFGModified() {
204: return cfgModified;
205: }
206: }
207:
208: //vim:ts=4
|