1 19 20 package edu.umd.cs.findbugs.ba; 21 22 import java.util.BitSet ; 23 import java.util.HashMap ; 24 import java.util.HashSet ; 25 import java.util.Iterator ; 26 import java.util.Map ; 27 import java.util.Set ; 28 29 import org.apache.bcel.Constants; 30 import org.apache.bcel.Repository; 31 import org.apache.bcel.classfile.JavaClass; 32 import org.apache.bcel.classfile.Method; 33 import org.apache.bcel.generic.ConstantPoolGen; 34 import org.apache.bcel.generic.Instruction; 35 import org.apache.bcel.generic.InvokeInstruction; 36 import org.apache.bcel.generic.MethodGen; 37 38 import edu.umd.cs.findbugs.AnalysisLocal; 39 import edu.umd.cs.findbugs.SystemProperties; 40 import edu.umd.cs.findbugs.ba.ch.Subtypes; 41 42 public class PruneUnconditionalExceptionThrowerEdges implements EdgeTypes { 43 private static final boolean DEBUG = SystemProperties.getBoolean("cfg.prune.throwers.debug"); 44 45 private MethodGen methodGen; 46 private CFG cfg; 47 private ConstantPoolGen cpg; 48 private AnalysisContext analysisContext; 49 private boolean cfgModified; 50 51 private static final BitSet RETURN_OPCODE_SET = new BitSet (); 52 static { 53 RETURN_OPCODE_SET.set(Constants.ARETURN); 54 RETURN_OPCODE_SET.set(Constants.IRETURN); 55 RETURN_OPCODE_SET.set(Constants.LRETURN); 56 RETURN_OPCODE_SET.set(Constants.DRETURN); 57 RETURN_OPCODE_SET.set(Constants.FRETURN); 58 RETURN_OPCODE_SET.set(Constants.RETURN); 59 } 60 61 public PruneUnconditionalExceptionThrowerEdges(MethodGen methodGen, CFG cfg, ConstantPoolGen cpg, 62 AnalysisContext analysisContext) { 63 this.methodGen = methodGen; 64 this.cfg = cfg; 65 this.cpg = cpg; 66 this.analysisContext = analysisContext; 67 } 68 69 static AnalysisLocal<Map <XMethod,Boolean >> cachedResults = new AnalysisLocal<Map <XMethod,Boolean >>() { 70 @Override 71 public Map <XMethod,Boolean > initialValue() { 72 return new HashMap <XMethod,Boolean >(); 73 } 74 }; 75 76 public void execute() throws CFGBuilderException, DataflowAnalysisException { 77 AnalysisContext currentAnalysisContext = AnalysisContext.currentAnalysisContext(); 78 if (currentAnalysisContext.getBoolProperty(AnalysisFeatures.CONSERVE_SPACE)) 79 throw new IllegalStateException ("This should not happen"); 80 81 Set <Edge> deletedEdgeSet = new HashSet <Edge>(); 82 83 if (DEBUG) 84 System.out.println("PruneUnconditionalExceptionThrowerEdges: examining " + 85 SignatureConverter.convertMethodSignature(methodGen)); 86 Subtypes subtypes = AnalysisContext.currentAnalysisContext() 87 .getSubtypes(); 88 for (Iterator <BasicBlock> i = cfg.blockIterator(); i.hasNext();) { 89 BasicBlock basicBlock = i.next(); 90 if (!basicBlock.isExceptionThrower()) 91 continue; 92 93 Instruction exceptionThrower = basicBlock.getExceptionThrower().getInstruction(); 94 if (!(exceptionThrower instanceof InvokeInstruction)) 95 continue; 96 97 InvokeInstruction inv = (InvokeInstruction) exceptionThrower; 98 try { 99 100 String className = inv.getClassName(cpg); 101 if (DEBUG) System.out.println("\tlooking up method for " + basicBlock.getExceptionThrower() + " in " + className); 102 103 if (className.startsWith("[")) 104 continue; 105 String methodSig = inv.getSignature(cpg); 106 if (!methodSig.endsWith("V")) 107 continue; 108 109 XMethod xMethod = XFactory.createXMethod(inv, cpg); 110 JavaClass javaClass = Repository.lookupClass(xMethod.getClassName()); 111 112 JavaClassAndMethod classAndMethod = Hierarchy.findMethod(javaClass, xMethod.getName(), xMethod.getSignature(), Hierarchy.CONCRETE_METHOD); 113 if (classAndMethod == null) { 114 if (DEBUG) System.out.println("\tNOT FOUND"); 115 continue; 116 } 117 Method method = classAndMethod.getMethod(); 118 if (DEBUG) System.out.println("\tFound " + xMethod); 119 120 if (!(method.isStatic() || method.isPrivate() || method.isFinal() || javaClass.isFinal() || !subtypes.hasSubtypes(javaClass))) { 121 if (!Repository.instanceOf(methodGen.getClassName(), javaClass)) continue; 122 } 123 124 if (method.getCode() == null) continue; 126 Boolean isUnconditionalThrower = doesMethodUnconditionallyThrowException(xMethod, javaClass, method); 127 if (false && isUnconditionalThrower.booleanValue()) { 128 ClassContext classContext = analysisContext.getClassContext(javaClass); 129 MethodGen calledMethodGen = classContext.getMethodGen(method); 130 132 if (calledMethodGen == null) 133 continue; 134 135 CFG calledCFG = classContext.getCFG(method); 138 ReturnPathDataflow pathDataflow = classContext 139 .getReturnPathDataflow(method); 140 ReturnPath pathValue = pathDataflow.getStartFact(calledCFG 141 .getExit()); 142 143 isUnconditionalThrower = pathValue.getKind() != ReturnPath.RETURNS; 144 if (true) cachedResults.get().put(xMethod, isUnconditionalThrower); 146 } 147 148 if (isUnconditionalThrower.booleanValue()) { 149 Edge fallThrough = cfg.getOutgoingEdgeWithType(basicBlock, 152 FALL_THROUGH_EDGE); 153 if (fallThrough != null) { 154 if (DEBUG) { 155 System.out.println("\tREMOVING normal return for: " + xMethod); 156 } 157 deletedEdgeSet.add(fallThrough); 158 } 159 } 160 } catch (ClassNotFoundException e) { 161 analysisContext.getLookupFailureCallback().reportMissingClass(e); 162 } 163 } 164 165 for (Edge edge : deletedEdgeSet) { 167 cfg.removeEdge(edge); 168 cfgModified = true; 169 } 170 } 171 172 178 static public Boolean doesMethodUnconditionallyThrowException(XMethod xMethod, JavaClass javaClass, Method method) { 179 Boolean isUnconditionalThrower = cachedResults.get().get(xMethod); 180 181 182 if (isUnconditionalThrower == null) { 183 isUnconditionalThrower = Boolean.FALSE; 184 try { 185 ClassContext classContext = AnalysisContext.currentAnalysisContext().getClassContext(javaClass); 186 BitSet bytecodeSet = classContext.getBytecodeSet(method); 187 if (bytecodeSet != null) { 188 189 if (DEBUG) System.out.println("\tChecking " + xMethod); 190 isUnconditionalThrower = Boolean.valueOf(!bytecodeSet.intersects(RETURN_OPCODE_SET)); 191 if (DEBUG && isUnconditionalThrower) { 192 System.out.println("Is unconditional thrower"); 193 System.out.println("Return opcode set: " + RETURN_OPCODE_SET); 194 System.out.println("Code opcode set: " + bytecodeSet); 195 } 196 } 197 } catch (Exception e) { 198 } 200 201 cachedResults.get().put(xMethod, isUnconditionalThrower); 202 203 } 204 return isUnconditionalThrower; 205 } 206 207 212 public boolean wasCFGModified() { 213 return cfgModified; 214 } 215 } 216 217 | Popular Tags |