• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 package proguard.optimize.peephole;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.CodeAttribute;
25 import proguard.classfile.editor.CodeAttributeEditor;
26 import proguard.classfile.instruction.*;
27 import proguard.classfile.instruction.visitor.InstructionVisitor;
28 import proguard.classfile.util.SimplifiedVisitor;
29 
30 /**
31  * This InstructionVisitor simplifies unconditional branches to other
32  * unconditional branches.
33  *
34  * @author Eric Lafortune
35  */
36 public class GotoGotoReplacer
37 extends      SimplifiedVisitor
38 implements   InstructionVisitor
39 {
40     private final CodeAttributeEditor codeAttributeEditor;
41     private final InstructionVisitor  extraInstructionVisitor;
42 
43 
44     /**
45      * Creates a new GotoGotoReplacer.
46      * @param codeAttributeEditor     a code editor that can be used for
47      *                                accumulating changes to the code.
48      */
GotoGotoReplacer(CodeAttributeEditor codeAttributeEditor)49     public GotoGotoReplacer(CodeAttributeEditor codeAttributeEditor)
50     {
51         this(codeAttributeEditor, null);
52     }
53 
54 
55     /**
56      * Creates a new GotoGotoReplacer.
57      * @param codeAttributeEditor     a code editor that can be used for
58      *                                accumulating changes to the code.
59      * @param extraInstructionVisitor an optional extra visitor for all replaced
60      *                                goto instructions.
61      */
GotoGotoReplacer(CodeAttributeEditor codeAttributeEditor, InstructionVisitor extraInstructionVisitor)62     public GotoGotoReplacer(CodeAttributeEditor codeAttributeEditor,
63                             InstructionVisitor  extraInstructionVisitor)
64     {
65         this.codeAttributeEditor     = codeAttributeEditor;
66         this.extraInstructionVisitor = extraInstructionVisitor;
67     }
68 
69 
70     // Implementations for InstructionVisitor.
71 
visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)72     public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
73 
74 
visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)75     public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
76     {
77         // Check if the instruction is an unconditional goto instruction.
78         byte opcode = branchInstruction.opcode;
79         if (opcode == InstructionConstants.OP_GOTO ||
80             opcode == InstructionConstants.OP_GOTO_W)
81         {
82             // Check if the goto instruction points to another simple goto
83             // instruction.
84             int branchOffset = branchInstruction.branchOffset;
85             int targetOffset = offset + branchOffset;
86 
87             if (branchOffset != 0                                &&
88                 branchOffset != branchInstruction.length(offset) &&
89                 !codeAttributeEditor.isModified(offset)          &&
90                 !codeAttributeEditor.isModified(targetOffset))
91             {
92                 Instruction targetInstruction =
93                     InstructionFactory.create(codeAttribute.code, targetOffset);
94 
95                 if (targetInstruction.opcode == InstructionConstants.OP_GOTO)
96                 {
97                     // Simplify the goto instruction.
98                     int targetBranchOffset = ((BranchInstruction)targetInstruction).branchOffset;
99 
100                     Instruction newBranchInstruction =
101                          new BranchInstruction(opcode,
102                                                (branchOffset + targetBranchOffset));
103                     codeAttributeEditor.replaceInstruction(offset,
104                                                            newBranchInstruction);
105 
106                     // Visit the instruction, if required.
107                     if (extraInstructionVisitor != null)
108                     {
109                         extraInstructionVisitor.visitBranchInstruction(clazz, method, codeAttribute, offset, branchInstruction);
110                     }
111                 }
112             }
113         }
114     }
115 }
116