1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/*
2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification
3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *             of Java bytecode.
4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
5b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
6b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
7b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is free software; you can redistribute it and/or modify it
8b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * under the terms of the GNU General Public License as published by the Free
9b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Software Foundation; either version 2 of the License, or (at your option)
10b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * any later version.
11b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
12b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is distributed in the hope that it will be useful, but WITHOUT
13b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * more details.
16b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
17b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * You should have received a copy of the GNU General Public License along
18b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * with this program; if not, write to the Free Software Foundation, Inc.,
19b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */
21b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopackage proguard.classfile.editor;
22b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
23b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.*;
24b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.attribute.CodeAttribute;
25b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.attribute.visitor.AttributeVisitor;
26b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.instruction.*;
27b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.instruction.visitor.InstructionVisitor;
28b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.util.SimplifiedVisitor;
29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/**
31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This InstructionVisitor writes out the instructions that it visits,
32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * collecting instructions that have to be widened. As an AttributeVisitor,
33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * it then applies the collected changes. The process will be repeated
34b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang * recursively, if necessary. The caller still has to update the frame sizes.
35b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
36b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @author Eric Lafortune
37b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */
38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopublic class InstructionWriter
39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoextends      SimplifiedVisitor
40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimplements   InstructionVisitor,
41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             AttributeVisitor
42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{
43b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    //*
44b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    private static final boolean DEBUG = false;
45b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    /*/
46b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    public  static       boolean DEBUG = false;
47b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    //*/
48b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
49b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private int codeLength;
51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
52b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private CodeAttributeEditor codeAttributeEditor;
53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
54b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
56b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * Resets the accumulated code.
57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param codeLength the length of the code that will be edited next.
58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void reset(int codeLength)
60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        this.codeLength = codeLength;
62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (codeAttributeEditor != null)
64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            codeAttributeEditor.reset(codeLength);
66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
70b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    /**
71b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * Extends the size of the accumulated code.
72b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * @param codeLength the length of the code that will be edited next.
73b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     */
74b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    public void extend(int codeLength)
75b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    {
76b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        this.codeLength = codeLength;
77b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
78b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        if (codeAttributeEditor != null)
79b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        {
80b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            codeAttributeEditor.extend(codeLength);
81b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        }
82b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    }
83b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
84b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for InstructionVisitor.
86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
89b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Try to write out the instruction.
90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Simple instructions should always fit.
91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        simpleInstruction.write(codeAttribute, offset);
92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
95b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        try
98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
99b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Try to write out the instruction.
100b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            constantInstruction.write(codeAttribute, offset);
101b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
102b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        catch (IllegalArgumentException exception)
103b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Create a new constant instruction that will fit.
105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            Instruction replacementInstruction =
106b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                new ConstantInstruction(constantInstruction.opcode,
107b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                        constantInstruction.constantIndex,
108b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                                        constantInstruction.constant);
109b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
110b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            if (DEBUG)
111b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            {
112b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                System.out.println("  "+constantInstruction.toString(offset)+" will be widened to "+replacementInstruction.toString());
113b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            }
114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            replaceInstruction(offset, replacementInstruction);
116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Write out a dummy constant instruction for now.
118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            constantInstruction.constantIndex = 0;
119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            constantInstruction.constant      = 0;
120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            constantInstruction.write(codeAttribute, offset);
121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        try
128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Try to write out the instruction.
130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            variableInstruction.write(codeAttribute, offset);
131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        catch (IllegalArgumentException exception)
133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Create a new variable instruction that will fit.
135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            Instruction replacementInstruction =
136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                new VariableInstruction(variableInstruction.opcode,
137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                        variableInstruction.variableIndex,
138b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                                        variableInstruction.constant);
139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
140b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            replaceInstruction(offset, replacementInstruction);
141b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
142b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            if (DEBUG)
143b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            {
144b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                System.out.println("  "+variableInstruction.toString(offset)+" will be widened to "+replacementInstruction.toString());
145b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            }
146b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
147b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Write out a dummy variable instruction for now.
148b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            variableInstruction.variableIndex = 0;
149b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            variableInstruction.constant      = 0;
150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            variableInstruction.write(codeAttribute, offset);
151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
154b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        try
158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Try to write out the instruction.
160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            branchInstruction.write(codeAttribute, offset);
161b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
162b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        catch (IllegalArgumentException exception)
163b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Create a new unconditional branch that will fit.
165b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            Instruction replacementInstruction =
166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                new BranchInstruction(InstructionConstants.OP_GOTO_W,
167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                      branchInstruction.branchOffset);
168b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
169b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Create a new instruction that will fit.
170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            switch (branchInstruction.opcode)
171b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                default:
173b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                {
174b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    // Create a new branch instruction that will fit.
175b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    replacementInstruction =
176b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                        new BranchInstruction(branchInstruction.opcode,
177b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                                              branchInstruction.branchOffset);
178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    break;
180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                }
181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                // Some special cases, for which a wide branch doesn't exist.
183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFEQ:
184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFNE:
185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFLT:
186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFGE:
187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFGT:
188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFLE:
189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFICMPEQ:
190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFICMPNE:
191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFICMPLT:
192b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFICMPGE:
193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFICMPGT:
194b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFICMPLE:
195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFACMPEQ:
196b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFACMPNE:
197b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                {
198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    // Insert the complementary conditional branch.
199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    Instruction complementaryConditionalBranch =
200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                        new BranchInstruction((byte)(((branchInstruction.opcode+1) ^ 1) - 1),
201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                              (1+2) + (1+4));
202b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
203b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    insertBeforeInstruction(offset, complementaryConditionalBranch);
204b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
205b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    // Create a new unconditional branch that will fit.
206b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    break;
207b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                }
208b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
209b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFNULL:
210b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                case InstructionConstants.OP_IFNONNULL:
211b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                {
212b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    // Insert the complementary conditional branch.
213b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    Instruction complementaryConditionalBranch =
214b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                        new BranchInstruction((byte)(branchInstruction.opcode ^ 1),
215b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                              (1+2) + (1+4));
216b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
217b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    insertBeforeInstruction(offset, complementaryConditionalBranch);
218b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
219b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    // Create a new unconditional branch that will fit.
220b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    break;
221b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                }
222b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
223b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
224b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            if (DEBUG)
225b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            {
226b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                System.out.println("  "+branchInstruction.toString(offset)+" will be widened to "+replacementInstruction.toString());
227b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            }
228b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
229b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            replaceInstruction(offset, replacementInstruction);
230b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
231b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Write out a dummy branch instruction for now.
232b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            branchInstruction.branchOffset = 0;
233b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            branchInstruction.write(codeAttribute, offset);
234b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
235b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
236b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
237b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
238b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction)
239b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
240b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Try to write out the instruction.
241b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Switch instructions should always fit.
242b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        switchInstruction.write(codeAttribute, offset);
243b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
244b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
245b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
246b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for AttributeVisitor.
247b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
248b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
249b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
250b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Avoid doing any work if nothing is changing anyway.
251b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (codeAttributeEditor != null)
252b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
253b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            if (DEBUG)
254b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            {
255b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                System.out.println("InstructionWriter: widening instructions in "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
256b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            }
257b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
258b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Apply the collected expansions.
259b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
260b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
261b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            // Don't keep the editor around. We're assuming it won't be needed
262b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            // very often, so we don't want to be resetting it all the time.
263b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            codeAttributeEditor = null;
264b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
265b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
266b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
267b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
268b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Small utility methods.
269b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
270b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
271b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Remembers to place the given instruction right before the instruction
272b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * at the given offset.
273b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
274b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private void insertBeforeInstruction(int instructionOffset, Instruction instruction)
275b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
276b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        ensureCodeAttributeEditor();
277b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
278b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Replace the instruction.
279b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        codeAttributeEditor.insertBeforeInstruction(instructionOffset, instruction);
280b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
281b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
282b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
283b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
284b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Remembers to replace the instruction at the given offset by the given
285b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * instruction.
286b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
287b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private void replaceInstruction(int instructionOffset, Instruction instruction)
288b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
289b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        ensureCodeAttributeEditor();
290b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
291b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Replace the instruction.
292b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        codeAttributeEditor.replaceInstruction(instructionOffset, instruction);
293b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
294b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
295b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
296b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
297b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Remembers to place the given instruction right after the instruction
298b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * at the given offset.
299b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
300b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private void insertAfterInstruction(int instructionOffset, Instruction instruction)
301b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
302b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        ensureCodeAttributeEditor();
303b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
304b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Replace the instruction.
305b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        codeAttributeEditor.insertAfterInstruction(instructionOffset, instruction);
306b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
307b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
308b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
309b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
310b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Makes sure there is a code attribute editor for the given code attribute.
311b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
312b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private void ensureCodeAttributeEditor()
313b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
314b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (codeAttributeEditor == null)
315b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
316b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            codeAttributeEditor = new CodeAttributeEditor(false, true);
317b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            codeAttributeEditor.reset(codeLength);
318b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
319b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
320b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato}
321