001: /*
002: * ProGuard -- shrinking, optimization, obfuscation, and preverification
003: * of Java bytecode.
004: *
005: * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
006: *
007: * This program is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the Free
009: * Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This program is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
015: * more details.
016: *
017: * You should have received a copy of the GNU General Public License along
018: * with this program; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: package proguard.optimize.info;
022:
023: import proguard.classfile.*;
024: import proguard.classfile.attribute.CodeAttribute;
025: import proguard.classfile.constant.RefConstant;
026: import proguard.classfile.constant.visitor.ConstantVisitor;
027: import proguard.classfile.instruction.*;
028: import proguard.classfile.instruction.visitor.InstructionVisitor;
029: import proguard.classfile.util.SimplifiedVisitor;
030: import proguard.classfile.visitor.MemberVisitor;
031:
032: /**
033: * This class can tell whether an instruction might throw exceptions.
034: *
035: * @author Eric Lafortune
036: */
037: public class ExceptionInstructionChecker extends SimplifiedVisitor
038: implements InstructionVisitor, ConstantVisitor, MemberVisitor {
039: // A return value for the visitor methods.
040: private boolean mayThrowExceptions;
041:
042: /**
043: * Returns whether the given instruction may throw exceptions.
044: */
045: public boolean mayThrowExceptions(Clazz clazz, Method method,
046: CodeAttribute codeAttribute, int offset,
047: Instruction instruction) {
048: mayThrowExceptions = false;
049:
050: instruction.accept(clazz, method, codeAttribute, offset, this );
051:
052: return mayThrowExceptions;
053: }
054:
055: // Implementations for InstructionVisitor.
056:
057: public void visitAnyInstruction(Clazz clazz, Method method,
058: CodeAttribute codeAttribute, int offset,
059: Instruction instruction) {
060: }
061:
062: public void visitSimpleInstruction(Clazz clazz, Method method,
063: CodeAttribute codeAttribute, int offset,
064: SimpleInstruction simpleInstruction) {
065: byte opcode = simpleInstruction.opcode;
066:
067: // Check for instructions that may throw exceptions.
068: if (opcode == InstructionConstants.OP_IDIV
069: || opcode == InstructionConstants.OP_LDIV
070: || opcode == InstructionConstants.OP_IREM
071: || opcode == InstructionConstants.OP_LREM
072: || opcode == InstructionConstants.OP_IALOAD
073: || opcode == InstructionConstants.OP_LALOAD
074: || opcode == InstructionConstants.OP_FALOAD
075: || opcode == InstructionConstants.OP_DALOAD
076: || opcode == InstructionConstants.OP_AALOAD
077: || opcode == InstructionConstants.OP_BALOAD
078: || opcode == InstructionConstants.OP_CALOAD
079: || opcode == InstructionConstants.OP_SALOAD
080: || opcode == InstructionConstants.OP_IASTORE
081: || opcode == InstructionConstants.OP_LASTORE
082: || opcode == InstructionConstants.OP_FASTORE
083: || opcode == InstructionConstants.OP_DASTORE
084: || opcode == InstructionConstants.OP_AASTORE
085: || opcode == InstructionConstants.OP_BASTORE
086: || opcode == InstructionConstants.OP_CASTORE
087: || opcode == InstructionConstants.OP_SASTORE
088: || opcode == InstructionConstants.OP_NEWARRAY
089: || opcode == InstructionConstants.OP_ARRAYLENGTH
090: || opcode == InstructionConstants.OP_ATHROW
091: || opcode == InstructionConstants.OP_MONITORENTER
092: || opcode == InstructionConstants.OP_MONITOREXIT) {
093: // These instructions may throw exceptions.
094: mayThrowExceptions = true;
095: }
096:
097: }
098:
099: public void visitConstantInstruction(Clazz clazz, Method method,
100: CodeAttribute codeAttribute, int offset,
101: ConstantInstruction constantInstruction) {
102: byte opcode = constantInstruction.opcode;
103:
104: // Check for instructions that may throw exceptions.
105: if (opcode == InstructionConstants.OP_GETSTATIC
106: || opcode == InstructionConstants.OP_PUTSTATIC
107: || opcode == InstructionConstants.OP_GETFIELD
108: || opcode == InstructionConstants.OP_PUTFIELD
109: || opcode == InstructionConstants.OP_INVOKEVIRTUAL
110: || opcode == InstructionConstants.OP_INVOKESPECIAL
111: || opcode == InstructionConstants.OP_INVOKESTATIC
112: || opcode == InstructionConstants.OP_INVOKEINTERFACE
113: || opcode == InstructionConstants.OP_NEW
114: || opcode == InstructionConstants.OP_ANEWARRAY
115: || opcode == InstructionConstants.OP_CHECKCAST
116: || opcode == InstructionConstants.OP_MULTIANEWARRAY) {
117: // These instructions may throw exceptions.
118: mayThrowExceptions = true;
119: }
120: // else
121: // if (opcode == InstructionConstants.OP_INVOKEVIRTUAL ||
122: // opcode == InstructionConstants.OP_INVOKESPECIAL ||
123: // opcode == InstructionConstants.OP_INVOKESTATIC ||
124: // opcode == InstructionConstants.OP_INVOKEINTERFACE)
125: // {
126: // // Check if the invoking the method may throw an exception.
127: // clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
128: // }
129: }
130:
131: // Implementations for ConstantVisitor.
132:
133: public void visitAnyMethodrefConstant(Clazz clazz,
134: RefConstant refConstant) {
135: Member referencedMember = refConstant.referencedMember;
136:
137: // Do we have a reference to the method?
138: if (referencedMember == null) {
139: // We'll have to assume invoking the unknown method may throw an
140: // an exception.
141: mayThrowExceptions = true;
142: } else {
143: // First check the referenced method itself.
144: refConstant.referencedMemberAccept(this );
145:
146: // If the result isn't conclusive, check down the hierarchy.
147: if (!mayThrowExceptions) {
148: Clazz referencedClass = refConstant.referencedClass;
149: Method referencedMethod = (Method) referencedMember;
150:
151: // Check all other implementations of the method in the class
152: // hierarchy.
153: referencedClass.methodImplementationsAccept(
154: referencedMethod, false, this );
155: }
156: }
157: }
158:
159: // Implementations for MemberVisitor.
160:
161: public void visitProgramMethod(ProgramClass programClass,
162: ProgramMethod programMethod) {
163: // mayThrowExceptions = mayThrowExceptions ||
164: // ExceptionMethodMarker.mayThrowExceptions(programMethod);
165: }
166:
167: public void visitLibraryMethod(LibraryClass libraryClass,
168: LibraryMethod libraryMethod) {
169: // mayThrowExceptions = mayThrowExceptions ||
170: // !NoExceptionMethodMarker.doesntThrowExceptions(libraryMethod);
171: }
172: }
|