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 deletes load/store instruction pairs.
032: *
033: * @author Eric Lafortune
034: */
035: public class LoadStoreRemover extends SimplifiedVisitor implements
036: InstructionVisitor {
037: private final BranchTargetFinder branchTargetFinder;
038: private final CodeAttributeEditor codeAttributeEditor;
039: private final InstructionVisitor extraInstructionVisitor;
040:
041: /**
042: * Creates a new LoadStoreRemover.
043: * @param branchTargetFinder a branch target finder that has been
044: * initialized to indicate branch targets
045: * in the visited code.
046: * @param codeAttributeEditor a code editor that can be used for
047: * accumulating changes to the code.
048: */
049: public LoadStoreRemover(BranchTargetFinder branchTargetFinder,
050: CodeAttributeEditor codeAttributeEditor) {
051: this (branchTargetFinder, codeAttributeEditor, null);
052: }
053:
054: /**
055: * Creates a new LoadStoreRemover.
056: * @param branchTargetFinder a branch target finder that has been
057: * initialized to indicate branch targets
058: * in the visited code.
059: * @param codeAttributeEditor a code editor that can be used for
060: * accumulating changes to the code.
061: * @param extraInstructionVisitor an optional extra visitor for all deleted
062: * load instructions.
063: */
064: public LoadStoreRemover(BranchTargetFinder branchTargetFinder,
065: CodeAttributeEditor codeAttributeEditor,
066: InstructionVisitor extraInstructionVisitor) {
067: this .branchTargetFinder = branchTargetFinder;
068: this .codeAttributeEditor = codeAttributeEditor;
069: this .extraInstructionVisitor = extraInstructionVisitor;
070: }
071:
072: // Implementations for InstructionVisitor.
073:
074: public void visitAnyInstruction(Clazz clazz, Method method,
075: CodeAttribute codeAttribute, int offset,
076: Instruction instruction) {
077: }
078:
079: public void visitVariableInstruction(Clazz clazz, Method method,
080: CodeAttribute codeAttribute, int offset,
081: VariableInstruction variableInstruction) {
082: // Is this instruction a load instruction?
083: if (variableInstruction.isLoad()
084: && variableInstruction.opcode != InstructionConstants.OP_RET) {
085: int variableIndex = variableInstruction.variableIndex;
086:
087: int nextOffset = offset
088: + variableInstruction.length(offset);
089:
090: if (!codeAttributeEditor.isModified(offset)
091: && !codeAttributeEditor.isModified(nextOffset)
092: && !branchTargetFinder.isTarget(nextOffset)) {
093: // Is the next instruction a corresponding store instruction?
094: Instruction nextInstruction = InstructionFactory
095: .create(codeAttribute.code, nextOffset);
096:
097: if (nextInstruction instanceof VariableInstruction) {
098: variableInstruction = (VariableInstruction) nextInstruction;
099: if (!variableInstruction.isLoad()
100: && variableInstruction.opcode != InstructionConstants.OP_IINC
101: && variableInstruction.variableIndex == variableIndex) {
102: // Delete both instructions.
103: codeAttributeEditor.deleteInstruction(offset);
104: codeAttributeEditor
105: .deleteInstruction(nextOffset);
106:
107: // Visit the instruction, if required.
108: if (extraInstructionVisitor != null) {
109: extraInstructionVisitor
110: .visitVariableInstruction(clazz,
111: method, codeAttribute,
112: offset, variableInstruction);
113: }
114: }
115: }
116: }
117: }
118: }
119: }
|