📄 typeanalysis.java
字号:
if (ACCURATE_EXCEPTIONS) { try { // Ideally, the exceptions that can be propagated // on this edge has already been computed. CachedExceptionSet cachedExceptionSet = getCachedExceptionSet(edge.getSource()); ExceptionSet edgeExceptionSet = cachedExceptionSet.getEdgeExceptionSet(edge); if (!edgeExceptionSet.isEmpty()) { //System.out.println("Using computed edge exception set!"); catchType = ExceptionObjectType.fromExceptionSet(edgeExceptionSet); } } catch (ClassNotFoundException e) { lookupFailureCallback.reportMissingClass(e); } } if (catchType == null) { // No information about propagated exceptions, so // pick a type conservatively using the handler catch type. catchType = exceptionGen.getCatchType(); if (catchType == null) catchType = Type.THROWABLE; // handle catches anything throwable } tmpFact.pushValue(catchType); fact = tmpFact; } mergeInto(fact, result); } protected Type mergeValues(TypeFrame frame, int slot, Type a, Type b) throws DataflowAnalysisException { return typeMerger.mergeTypes(a, b); } /** * Get the cached set of exceptions that can be thrown * from given basic block. If this information hasn't * been computed yet, then an empty exception set is * returned. * * @param basicBlock the block to get the cached exception set for * @return the CachedExceptionSet for the block */ private CachedExceptionSet getCachedExceptionSet(BasicBlock basicBlock) { CachedExceptionSet cachedExceptionSet = thrownExceptionSetMap.get(basicBlock); if (cachedExceptionSet == null) { // When creating the cached exception type set for the first time: // - the block result is set to TOP, so it won't match // any block result that has actually been computed // using the analysis transfer function // - the exception set is created as empty (which makes it // return TOP as its common superclass) TypeFrame top = createFact(); makeFactTop(top); cachedExceptionSet = new CachedExceptionSet(top, exceptionSetFactory.createExceptionSet()); thrownExceptionSetMap.put(basicBlock, cachedExceptionSet); } return cachedExceptionSet; } /** * Compute the set of exceptions that can be * thrown from the given basic block. * This should only be called if the existing cached * exception set is out of date. * * @param basicBlock the basic block * @param result the result fact for the block; this is used * to determine whether or not the cached exception * set is up to date * @return the cached exception set for the block */ private CachedExceptionSet computeBlockExceptionSet(BasicBlock basicBlock, TypeFrame result) throws DataflowAnalysisException { ExceptionSet exceptionSet = null; try { exceptionSet = computeThrownExceptionTypes(basicBlock); } catch (ClassNotFoundException e) { // Special case: be as conservative as possible // if a class hierarchy lookup fails. lookupFailureCallback.reportMissingClass(e); exceptionSet = exceptionSetFactory.createExceptionSet(); exceptionSet.addExplicit(Type.THROWABLE); } TypeFrame copyOfResult = createFact(); copy(result, copyOfResult); CachedExceptionSet cachedExceptionSet = new CachedExceptionSet(copyOfResult, exceptionSet); thrownExceptionSetMap.put(basicBlock, cachedExceptionSet); return cachedExceptionSet; } /** * Based on the set of exceptions that can be thrown * from the source basic block, * compute the set of exceptions that can propagate * along given exception edge. This method should be * called for each outgoing exception edge in sequence, * so the caught exceptions can be removed from the * thrown exception set as needed. * * @param edge the exception edge * @param thrownExceptionSet current set of exceptions that * can be thrown, taking earlier (higher priority) * exception edges into account * @return the set of exceptions that can propagate * along this edge */ private ExceptionSet computeEdgeExceptionSet(Edge edge, ExceptionSet thrownExceptionSet) { ExceptionSet result = exceptionSetFactory.createExceptionSet(); if (edge.getType() == UNHANDLED_EXCEPTION_EDGE) { // The unhandled exception edge always comes // after all of the handled exception edges. result.addAll(thrownExceptionSet); thrownExceptionSet.clear(); return result; } BasicBlock handlerBlock = edge.getTarget(); CodeExceptionGen handler = handlerBlock.getExceptionGen(); ObjectType catchType = handler.getCatchType(); if (Hierarchy.isUniversalExceptionHandler(catchType)) { result.addAll(thrownExceptionSet); thrownExceptionSet.clear(); } else { // Go through the set of thrown exceptions. // Any that will DEFINITELY be caught be this handler, remove. // Any that MIGHT be caught, but won't definitely be caught, // remain. for (ExceptionSet.ThrownExceptionIterator i = thrownExceptionSet.iterator(); i.hasNext();) { //ThrownException thrownException = i.next(); ObjectType thrownType = i.next(); boolean explicit = i.isExplicit(); if (DEBUG) System.out.println("\texception type " + thrownType + ", catch type " + catchType); try { if (Hierarchy.isSubtype(thrownType, catchType)) { // Exception can be thrown along this edge result.add(thrownType, explicit); // And it will definitely be caught i.remove(); if (DEBUG) System.out.println("\tException is subtype of catch type: " + "will definitely catch"); } else if (Hierarchy.isSubtype(catchType, thrownType)) { // Exception possibly thrown along this edge result.add(thrownType, explicit); if (DEBUG) System.out.println("\tException is supertype of catch type: " + "might catch"); } } catch (ClassNotFoundException e) { // As a special case, if a class hierarchy lookup // fails, then we will conservatively assume that the // exception in question CAN, but WON'T NECESSARILY // be caught by the handler. result.add(thrownType, explicit); } } } return result; } /** * Compute the set of exception types that can * be thrown by given basic block. * * @param basicBlock the basic block * @return the set of exceptions that can be thrown by the block */ private ExceptionSet computeThrownExceptionTypes(BasicBlock basicBlock) throws ClassNotFoundException, DataflowAnalysisException { ExceptionSet exceptionTypeSet = exceptionSetFactory.createExceptionSet(); InstructionHandle pei = basicBlock.getExceptionThrower(); Instruction ins = pei.getInstruction(); // Get the exceptions that BCEL knows about. // Note that all of these are unchecked. ExceptionThrower exceptionThrower = (ExceptionThrower) ins; Class[] exceptionList = exceptionThrower.getExceptions(); for (int i = 0; i < exceptionList.length; ++i) { exceptionTypeSet.addImplicit(new ObjectType(exceptionList[i].getName())); } // Assume that an Error may be thrown by any instruction. exceptionTypeSet.addImplicit(Hierarchy.ERROR_TYPE); if (ins instanceof ATHROW) { // For ATHROW instructions, we generate *two* blocks // for which the ATHROW is an exception thrower. // // - The first, empty basic block, does the null check // - The second block, which actually contains the ATHROW, // throws the object on the top of the operand stack // // We make a special case of the block containing the ATHROW, // by removing all of the implicit exceptions, // and using type information to figure out what is thrown. if (basicBlock.containsInstruction(pei)) { // This is the actual ATHROW, not the null check // and implicit exceptions. exceptionTypeSet.clear(); // The frame containing the thrown value is the start fact // for the block, because ATHROW is guaranteed to be // the only instruction in the block. TypeFrame frame = getStartFact(basicBlock); // Check whether or not the frame is valid. // Sun's javac sometimes emits unreachable code. // For example, it will emit code that follows a JSR // subroutine call that never returns. // If the frame is invalid, then we can just make // a conservative assumption that anything could be // thrown at this ATHROW. if (!frame.isValid()) { exceptionTypeSet.addExplicit(Type.THROWABLE); } else { Type throwType = frame.getTopValue(); if (throwType instanceof ObjectType) { exceptionTypeSet.addExplicit((ObjectType) throwType); } else if (throwType instanceof ExceptionObjectType) { exceptionTypeSet.addAll(((ExceptionObjectType) throwType).getExceptionSet()); } else { // Not sure what is being thrown here. // Be conservative. if (DEBUG) { System.out.println("Non object type " + throwType + " thrown by " + pei + " in " + SignatureConverter.convertMethodSignature(methodGen)); } exceptionTypeSet.addExplicit(Type.THROWABLE); } } } } // If it's an InvokeInstruction, add declared exceptions and RuntimeException if (ins instanceof InvokeInstruction) { ConstantPoolGen cpg = methodGen.getConstantPool(); InvokeInstruction inv = (InvokeInstruction) ins; ObjectType[] declaredExceptionList = Hierarchy.findDeclaredExceptions(inv, cpg); if (declaredExceptionList == null) { // Couldn't find declared exceptions, // so conservatively assume it could thrown any checked exception. if (DEBUG) System.out.println("Couldn't find declared exceptions for " + SignatureConverter.convertMethodSignature(inv, cpg)); exceptionTypeSet.addExplicit(Hierarchy.EXCEPTION_TYPE); } else { for (int i = 0; i < declaredExceptionList.length; ++i) { exceptionTypeSet.addExplicit(declaredExceptionList[i]); } } exceptionTypeSet.addImplicit(Hierarchy.RUNTIME_EXCEPTION_TYPE); } if (DEBUG) System.out.println(pei + " can throw " + exceptionTypeSet); return exceptionTypeSet; } public static void main(String[] argv) throws Exception { if (argv.length != 1) { System.err.println("Usage: " + TypeAnalysis.class.getName() + " <class file>"); System.exit(1); } DataflowTestDriver<TypeFrame, TypeAnalysis> driver = new DataflowTestDriver<TypeFrame, TypeAnalysis>() { public Dataflow<TypeFrame, TypeAnalysis> createDataflow(ClassContext classContext, Method method) throws CFGBuilderException, DataflowAnalysisException { return classContext.getTypeDataflow(method); } }; driver.execute(argv[0]); }}// vim:ts=3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -