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.AttributeVisitor;
026: import proguard.classfile.editor.CodeAttributeEditor;
027: import proguard.classfile.instruction.Instruction;
028: import proguard.classfile.instruction.visitor.InstructionVisitor;
029: import proguard.classfile.util.SimplifiedVisitor;
030:
031: /**
032: * This InstructionVisitor deletes blocks of code that can never be reached by
033: * regular calls or branches.
034: *
035: * @author Eric Lafortune
036: */
037: public class UnreachableCodeRemover extends SimplifiedVisitor implements
038: AttributeVisitor, InstructionVisitor {
039: //*
040: private static final boolean DEBUG = false;
041: /*/
042: private static boolean DEBUG = true;
043: //*/
044:
045: private final InstructionVisitor extraInstructionVisitor;
046:
047: private final ReachableCodeMarker reachableCodeMarker = new ReachableCodeMarker();
048: private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
049:
050: /**
051: * Creates a new UnreachableCodeRemover.
052: */
053: public UnreachableCodeRemover() {
054: this (null);
055: }
056:
057: /**
058: * Creates a new UnreachableCodeRemover.
059: * @param extraInstructionVisitor an optional extra visitor for all
060: * deleted instructions.
061: */
062: public UnreachableCodeRemover(
063: InstructionVisitor extraInstructionVisitor) {
064: this .extraInstructionVisitor = extraInstructionVisitor;
065: }
066:
067: // Implementations for AttributeVisitor.
068:
069: public void visitAnyAttribute(Clazz clazz, Attribute attribute) {
070: }
071:
072: public void visitCodeAttribute(Clazz clazz, Method method,
073: CodeAttribute codeAttribute) {
074: // DEBUG =
075: // clazz.getName().equals("abc/Def") &&
076: // method.getName(clazz).equals("abc");
077:
078: // TODO: Remove this when the code has stabilized.
079: // Catch any unexpected exceptions from the actual visiting method.
080: try {
081: // Process the code.
082: visitCodeAttribute0(clazz, method, codeAttribute);
083: } catch (RuntimeException ex) {
084: System.err
085: .println("Unexpected error while removing unreachable code:");
086: System.err.println(" Class = [" + clazz.getName()
087: + "]");
088: System.err.println(" Method = ["
089: + method.getName(clazz)
090: + method.getDescriptor(clazz) + "]");
091: System.err.println(" Exception = ["
092: + ex.getClass().getName() + "] (" + ex.getMessage()
093: + ")");
094:
095: throw ex;
096: }
097: }
098:
099: public void visitCodeAttribute0(Clazz clazz, Method method,
100: CodeAttribute codeAttribute) {
101: if (DEBUG) {
102: System.out.println("UnreachableCodeRemover: "
103: + clazz.getName() + "." + method.getName(clazz)
104: + method.getDescriptor(clazz));
105: }
106:
107: reachableCodeMarker.visitCodeAttribute(clazz, method,
108: codeAttribute);
109:
110: codeAttributeEditor.reset(codeAttribute.u4codeLength);
111:
112: codeAttribute.instructionsAccept(clazz, method, this );
113:
114: codeAttributeEditor.visitCodeAttribute(clazz, method,
115: codeAttribute);
116: }
117:
118: // Implementations for InstructionVisitor.
119:
120: public void visitAnyInstruction(Clazz clazz, Method method,
121: CodeAttribute codeAttribute, int offset,
122: Instruction instruction) {
123: if (DEBUG) {
124: System.out
125: .println(" "
126: + (reachableCodeMarker.isReachable(offset) ? "+"
127: : "-") + " "
128: + instruction.toString(offset));
129: }
130:
131: // Is this instruction unreachable?
132: if (!reachableCodeMarker.isReachable(offset)) {
133: // Then delete it.
134: codeAttributeEditor.deleteInstruction(offset);
135:
136: // Visit the instruction, if required.
137: if (extraInstructionVisitor != null) {
138: instruction.accept(clazz, method, codeAttribute,
139: offset, extraInstructionVisitor);
140: }
141: }
142: }
143: }
|