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