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.CodeAttribute;
025: import proguard.classfile.editor.CodeAttributeEditor;
026: import proguard.classfile.instruction.*;
027: import proguard.classfile.instruction.visitor.InstructionVisitor;
028: import proguard.classfile.util.SimplifiedVisitor;
029:
030: /**
031: * This InstructionVisitor simplifies unconditional branches to other
032: * unconditional branches.
033: *
034: * @author Eric Lafortune
035: */
036: public class GotoGotoReplacer extends SimplifiedVisitor implements
037: InstructionVisitor {
038: private final CodeAttributeEditor codeAttributeEditor;
039: private final InstructionVisitor extraInstructionVisitor;
040:
041: /**
042: * Creates a new GotoGotoReplacer.
043: * @param codeAttributeEditor a code editor that can be used for
044: * accumulating changes to the code.
045: */
046: public GotoGotoReplacer(CodeAttributeEditor codeAttributeEditor) {
047: this (codeAttributeEditor, null);
048: }
049:
050: /**
051: * Creates a new GotoGotoReplacer.
052: * @param codeAttributeEditor a code editor that can be used for
053: * accumulating changes to the code.
054: * @param extraInstructionVisitor an optional extra visitor for all replaced
055: * goto instructions.
056: */
057: public GotoGotoReplacer(CodeAttributeEditor codeAttributeEditor,
058: InstructionVisitor extraInstructionVisitor) {
059: this .codeAttributeEditor = codeAttributeEditor;
060: this .extraInstructionVisitor = extraInstructionVisitor;
061: }
062:
063: // Implementations for InstructionVisitor.
064:
065: public void visitAnyInstruction(Clazz clazz, Method method,
066: CodeAttribute codeAttribute, int offset,
067: Instruction instruction) {
068: }
069:
070: public void visitBranchInstruction(Clazz clazz, Method method,
071: CodeAttribute codeAttribute, int offset,
072: BranchInstruction branchInstruction) {
073: // Check if the instruction is an unconditional goto instruction.
074: byte opcode = branchInstruction.opcode;
075: if (opcode == InstructionConstants.OP_GOTO
076: || opcode == InstructionConstants.OP_GOTO_W) {
077: // Check if the goto instruction points to another simple goto
078: // instruction.
079: int branchOffset = branchInstruction.branchOffset;
080: int targetOffset = offset + branchOffset;
081:
082: if (branchOffset != branchInstruction.length(offset)
083: && !codeAttributeEditor.isModified(offset)
084: && !codeAttributeEditor.isModified(targetOffset)) {
085: Instruction targetInstruction = InstructionFactory
086: .create(codeAttribute.code, targetOffset);
087:
088: if (targetInstruction.opcode == InstructionConstants.OP_GOTO) {
089: // Simplify the goto instruction.
090: int targetBranchOffset = ((BranchInstruction) targetInstruction).branchOffset;
091:
092: Instruction newBranchInstruction = new BranchInstruction(
093: opcode, (branchOffset + targetBranchOffset));
094: codeAttributeEditor.replaceInstruction(offset,
095: newBranchInstruction);
096:
097: // Visit the instruction, if required.
098: if (extraInstructionVisitor != null) {
099: extraInstructionVisitor.visitBranchInstruction(
100: clazz, method, codeAttribute, offset,
101: branchInstruction);
102: }
103: }
104: }
105: }
106: }
107: }
|