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.peephole;
022:
023: import proguard.classfile.*;
024: import proguard.classfile.attribute.*;
025: import proguard.classfile.attribute.visitor.*;
026: import proguard.classfile.instruction.*;
027: import proguard.classfile.util.SimplifiedVisitor;
028: import proguard.optimize.info.ExceptionInstructionChecker;
029:
030: /**
031: * This AttributeVisitor removes exception handlers that are unreachable in the
032: * code attributes that it visits.
033: *
034: * @author Eric Lafortune
035: */
036: public class UnreachableExceptionRemover extends SimplifiedVisitor
037: implements AttributeVisitor, ExceptionInfoVisitor {
038: private final ExceptionInfoVisitor extraExceptionInfoVisitor;
039:
040: private final ExceptionInstructionChecker exceptionInstructionChecker = new ExceptionInstructionChecker();
041:
042: /**
043: * Creates a new UnreachableExceptionRemover.
044: */
045: public UnreachableExceptionRemover() {
046: this (null);
047: }
048:
049: /**
050: * Creates a new UnreachableExceptionRemover.
051: * @param extraExceptionInfoVisitor an optional extra visitor for all
052: * removed exceptions.
053: */
054: public UnreachableExceptionRemover(
055: ExceptionInfoVisitor extraExceptionInfoVisitor) {
056: this .extraExceptionInfoVisitor = extraExceptionInfoVisitor;
057: }
058:
059: // Implementations for AttributeVisitor.
060:
061: public void visitAnyAttribute(Clazz clazz, Attribute attribute) {
062: }
063:
064: public void visitCodeAttribute(Clazz clazz, Method method,
065: CodeAttribute codeAttribute) {
066: // Go over the exception table.
067: codeAttribute.exceptionsAccept(clazz, method, this );
068:
069: // Remove exceptions with empty code blocks.
070: codeAttribute.u2exceptionTableLength = removeEmptyExceptions(
071: codeAttribute.exceptionTable,
072: codeAttribute.u2exceptionTableLength);
073: }
074:
075: // Implementations for ExceptionInfoVisitor.
076:
077: public void visitExceptionInfo(Clazz clazz, Method method,
078: CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) {
079: if (!mayThrowExceptions(clazz, method, codeAttribute,
080: exceptionInfo.u2startPC, exceptionInfo.u2endPC)) {
081: // Make the code block empty.
082: exceptionInfo.u2endPC = exceptionInfo.u2startPC;
083:
084: if (extraExceptionInfoVisitor != null) {
085: extraExceptionInfoVisitor.visitExceptionInfo(clazz,
086: method, codeAttribute, exceptionInfo);
087: }
088: }
089: }
090:
091: // Small utility methods.
092:
093: /**
094: * Returns whether the specified block of code may throw exceptions.
095: */
096: private boolean mayThrowExceptions(Clazz clazz, Method method,
097: CodeAttribute codeAttribute, int startOffset, int endOffset) {
098: byte[] code = codeAttribute.code;
099:
100: // Go over all instructions.
101: int offset = startOffset;
102: while (offset < endOffset) {
103: // Get the current instruction.
104: Instruction instruction = InstructionFactory.create(code,
105: offset);
106:
107: // Check if it may be throwing exceptions.
108: if (exceptionInstructionChecker.mayThrowExceptions(clazz,
109: method, codeAttribute, offset, instruction)) {
110: return true;
111: }
112:
113: // Go to the next instruction.
114: offset += instruction.length(offset);
115: }
116:
117: return false;
118: }
119:
120: /**
121: * Returns the given list of exceptions, without the ones that have empty
122: * code blocks.
123: */
124: private int removeEmptyExceptions(ExceptionInfo[] exceptionInfos,
125: int exceptionInfoCount) {
126: // Overwrite all empty exceptions.
127: int newIndex = 0;
128: for (int index = 0; index < exceptionInfoCount; index++) {
129: ExceptionInfo exceptionInfo = exceptionInfos[index];
130: if (exceptionInfo.u2startPC < exceptionInfo.u2endPC) {
131: exceptionInfos[newIndex++] = exceptionInfo;
132: }
133: }
134:
135: return newIndex;
136: }
137: }
|