summaryrefslogtreecommitdiff
path: root/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/proguard/optimize/peephole/GotoCommonCodeReplacer.java')
-rw-r--r--src/proguard/optimize/peephole/GotoCommonCodeReplacer.java263
1 files changed, 0 insertions, 263 deletions
diff --git a/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java b/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
deleted file mode 100644
index a1f422f..0000000
--- a/src/proguard/optimize/peephole/GotoCommonCodeReplacer.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * ProGuard -- shrinking, optimization, obfuscation, and preverification
- * of Java bytecode.
- *
- * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-package proguard.optimize.peephole;
-
-import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.visitor.AttributeVisitor;
-import proguard.classfile.editor.CodeAttributeEditor;
-import proguard.classfile.instruction.*;
-import proguard.classfile.instruction.visitor.InstructionVisitor;
-import proguard.classfile.util.SimplifiedVisitor;
-
-/**
- * This AttributeVisitor redirects unconditional branches so any common code
- * is shared, and the code preceding the branch can be removed, in the code
- * attributes that it visits.
- *
- * @author Eric Lafortune
- */
-public class GotoCommonCodeReplacer
-extends SimplifiedVisitor
-implements AttributeVisitor,
- InstructionVisitor
-{
- //*
- private static final boolean DEBUG = false;
- /*/
- private static boolean DEBUG = true;
- //*/
-
-
- private final InstructionVisitor extraInstructionVisitor;
-
- private final BranchTargetFinder branchTargetFinder = new BranchTargetFinder();
- private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(true, false);
-
-
- /**
- * Creates a new GotoCommonCodeReplacer.
- * @param extraInstructionVisitor an optional extra visitor for all replaced
- * goto instructions.
- */
- public GotoCommonCodeReplacer(InstructionVisitor extraInstructionVisitor)
- {
- this.extraInstructionVisitor = extraInstructionVisitor;
- }
-
-
- // Implementations for AttributeVisitor.
-
- public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
-
-
- public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
- {
-// DEBUG =
-// clazz.getName().equals("abc/Def") &&
-// method.getName(clazz).equals("abc");
-
- // Mark all branch targets.
- branchTargetFinder.visitCodeAttribute(clazz, method, codeAttribute);
-
- // Reset the code attribute editor.
- codeAttributeEditor.reset(codeAttribute.u4codeLength);
-
- // Remap the variables of the instructions.
- codeAttribute.instructionsAccept(clazz, method, this);
-
- // Apply the code atribute editor.
- codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
- }
-
-
- // Implementations for InstructionVisitor.
-
- public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
-
-
- public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
- {
- // Check if the instruction is an unconditional goto instruction that
- // isn't the target of a branch itself.
- byte opcode = branchInstruction.opcode;
- if ((opcode == InstructionConstants.OP_GOTO ||
- opcode == InstructionConstants.OP_GOTO_W) &&
- !branchTargetFinder.isBranchTarget(offset))
- {
- int branchOffset = branchInstruction.branchOffset;
- int targetOffset = offset + branchOffset;
-
- // Get the number of common bytes.
- int commonCount = commonByteCodeCount(codeAttribute, offset, targetOffset);
-
- if (commonCount > 0 &&
- !exceptionBoundary(codeAttribute, offset, targetOffset))
- {
- if (DEBUG)
- {
- System.out.println("GotoCommonCodeReplacer: "+clazz.getName()+"."+method.getName(clazz)+" (["+(offset-commonCount)+"] - "+branchInstruction.toString(offset)+" -> "+targetOffset+")");
- }
-
- // Delete the common instructions.
- for (int delta = 0; delta <= commonCount; delta++)
- {
- int deleteOffset = offset - delta;
- if (branchTargetFinder.isInstruction(deleteOffset))
- {
- codeAttributeEditor.clearModifications(deleteOffset);
- codeAttributeEditor.deleteInstruction(deleteOffset);
- }
- }
-
- // Redirect the goto instruction, if it is still necessary.
- int newBranchOffset = branchOffset - commonCount;
- if (newBranchOffset != branchInstruction.length(offset))
- {
- Instruction newGotoInstruction =
- new BranchInstruction(opcode, newBranchOffset).shrink();
- codeAttributeEditor.replaceInstruction(offset,
- newGotoInstruction);
- }
-
- // Visit the instruction, if required.
- if (extraInstructionVisitor != null)
- {
- extraInstructionVisitor.visitBranchInstruction(clazz, method, codeAttribute, offset, branchInstruction);
- }
- }
- }
- }
-
-
- // Small utility methods.
-
- /**
- * Returns the number of common bytes preceding the given offsets,
- * avoiding branches and exception blocks.
- */
- private int commonByteCodeCount(CodeAttribute codeAttribute, int offset1, int offset2)
- {
- // Find the block of common instructions preceding it.
- byte[] code = codeAttribute.code;
-
- int successfulDelta = 0;
-
- for (int delta = 1;
- delta <= offset1 &&
- delta <= offset2 &&
- offset2 - delta != offset1;
- delta++)
- {
- int newOffset1 = offset1 - delta;
- int newOffset2 = offset2 - delta;
-
- // Is the code identical at both offsets?
- if (code[newOffset1] != code[newOffset2])
- {
- break;
- }
-
- // Are there instructions at either offset but not both?
- if (branchTargetFinder.isInstruction(newOffset1) ^
- branchTargetFinder.isInstruction(newOffset2))
- {
- break;
- }
-
- // Are there instructions at both offsets?
- if (branchTargetFinder.isInstruction(newOffset1) &&
- branchTargetFinder.isInstruction(newOffset2))
- {
- // Are the offsets involved in some branches?
- // Note that the preverifier doesn't like initializer
- // invocations to be moved around.
- // Also note that the preverifier doesn't like pop instructions
- // that work on different operands.
- if (branchTargetFinder.isBranchOrigin(newOffset1) ||
- branchTargetFinder.isBranchTarget(newOffset1) ||
- branchTargetFinder.isExceptionStart(newOffset1) ||
- branchTargetFinder.isExceptionEnd(newOffset1) ||
- branchTargetFinder.isInitializer(newOffset1) ||
- branchTargetFinder.isExceptionStart(newOffset2) ||
- branchTargetFinder.isExceptionEnd(newOffset2) ||
- isPop(code[newOffset1]))
- {
- break;
- }
-
- // Make sure the new branch target was a branch target before,
- // in order not to introduce new entries in the stack map table.
- if (branchTargetFinder.isBranchTarget(newOffset2))
- {
- successfulDelta = delta;
- }
-
- if (branchTargetFinder.isBranchTarget(newOffset1))
- {
- break;
- }
- }
- }
-
- return successfulDelta;
- }
-
-
- /**
- * Returns whether the given opcode represents a pop instruction that must
- * get a consistent type (pop, pop2, arraylength).
- */
- private boolean isPop(byte opcode)
- {
- return opcode == InstructionConstants.OP_POP ||
- opcode == InstructionConstants.OP_POP2 ||
- opcode == InstructionConstants.OP_ARRAYLENGTH;
- }
-
-
- /**
- * Returns the whether there is a boundary of an exception block between
- * the given offsets (including both).
- */
- private boolean exceptionBoundary(CodeAttribute codeAttribute, int offset1, int offset2)
- {
- // Swap the offsets if the second one is smaller than the first one.
- if (offset2 < offset1)
- {
- int offset = offset1;
- offset1 = offset2;
- offset2 = offset;
- }
-
- // Check if there is a boundary of an exception block.
- for (int offset = offset1; offset <= offset2; offset++)
- {
- if (branchTargetFinder.isExceptionStart(offset) ||
- branchTargetFinder.isExceptionEnd(offset))
- {
- return true;
- }
- }
-
- return false;
- }
-}