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 replaces unconditional branches to return instructions
032: * by these same return instructions.
033: *
034: * @author Eric Lafortune
035: */
036: public class GotoReturnReplacer extends SimplifiedVisitor implements
037: InstructionVisitor {
038: private final CodeAttributeEditor codeAttributeEditor;
039: private final InstructionVisitor extraInstructionVisitor;
040:
041: /**
042: * Creates a new GotoReturnReplacer.
043: * @param codeAttributeEditor a code editor that can be used for
044: * accumulating changes to the code.
045: */
046: public GotoReturnReplacer(CodeAttributeEditor codeAttributeEditor) {
047: this (codeAttributeEditor, null);
048: }
049:
050: /**
051: * Creates a new GotoReturnReplacer.
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 GotoReturnReplacer(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 a return instruction.
078: int targetOffset = offset + branchInstruction.branchOffset;
079:
080: if (!codeAttributeEditor.isModified(offset)
081: && !codeAttributeEditor.isModified(targetOffset)) {
082: Instruction targetInstruction = InstructionFactory
083: .create(codeAttribute.code, targetOffset);
084: switch (targetInstruction.opcode) {
085: case InstructionConstants.OP_IRETURN:
086: case InstructionConstants.OP_LRETURN:
087: case InstructionConstants.OP_FRETURN:
088: case InstructionConstants.OP_DRETURN:
089: case InstructionConstants.OP_ARETURN:
090: case InstructionConstants.OP_RETURN:
091: // Replace the goto instruction by the return instruction.
092: Instruction returnInstruction = new SimpleInstruction(
093: targetInstruction.opcode);
094: codeAttributeEditor.replaceInstruction(offset,
095: returnInstruction);
096:
097: // Visit the instruction, if required.
098: if (extraInstructionVisitor != null) {
099: extraInstructionVisitor.visitBranchInstruction(
100: clazz, method, codeAttribute, offset,
101: branchInstruction);
102: }
103:
104: break;
105: }
106: }
107: }
108: }
109: }
|