1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/*
2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification
3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *             of Java bytecode.
4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
52270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom * Copyright (c) 2002-2014 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.*;
252270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstromimport proguard.classfile.attribute.annotation.*;
262270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstromimport proguard.classfile.attribute.annotation.target.*;
272270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstromimport proguard.classfile.attribute.annotation.target.visitor.*;
282270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstromimport proguard.classfile.attribute.annotation.visitor.TypeAnnotationVisitor;
29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.attribute.preverification.*;
30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.attribute.preverification.visitor.*;
31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.attribute.visitor.*;
32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.instruction.*;
33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.instruction.visitor.InstructionVisitor;
34b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.util.SimplifiedVisitor;
35b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wangimport proguard.util.ArrayUtil;
36b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
37b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wangimport java.util.Arrays;
38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/**
40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This AttributeVisitor accumulates specified changes to code, and then applies
41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * these accumulated changes to the code attributes that it visits.
42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
43b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @author Eric Lafortune
44b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */
45b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopublic class CodeAttributeEditor
46b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoextends      SimplifiedVisitor
47b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimplements   AttributeVisitor,
48b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             InstructionVisitor,
49b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             ExceptionInfoVisitor,
50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             StackMapFrameVisitor,
51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             VerificationTypeVisitor,
52b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             LineNumberInfoVisitor,
53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             LocalVariableInfoVisitor,
542270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom             LocalVariableTypeInfoVisitor,
552270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom             TypeAnnotationVisitor,
562270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom             TargetInfoVisitor,
572270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom             LocalVariableTargetElementVisitor
58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{
59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    //*
60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static final boolean DEBUG = false;
61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /*/
62b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    public  static       boolean DEBUG = false;
63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    //*/
64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
65b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
66b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    private final boolean updateFrameSizes;
67b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    private final boolean shrinkInstructions;
68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private int     codeLength;
70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private boolean modified;
71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private boolean simple;
72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /*private*/public Instruction[]    preInsertions  = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];
74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /*private*/public Instruction[]    replacements   = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];
75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /*private*/public Instruction[]    postInsertions = new Instruction[ClassConstants.TYPICAL_CODE_LENGTH];
76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /*private*/public boolean[]        deleted        = new boolean[ClassConstants.TYPICAL_CODE_LENGTH];
77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
78b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    private int[]   newInstructionOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH];
79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private int     newOffset;
80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private boolean lengthIncreased;
81b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private int expectedStackMapFrameOffset;
83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private final StackSizeUpdater    stackSizeUpdater    = new StackSizeUpdater();
85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private final VariableSizeUpdater variableSizeUpdater = new VariableSizeUpdater();
86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private final InstructionWriter   instructionWriter   = new InstructionWriter();
87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
89b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    /**
90b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * Creates a new CodeAttributeEditor that automatically updates frame
91b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * sizes and shrinks instructions.
92b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     */
93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public CodeAttributeEditor()
94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
95b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        this(true, true);
96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
99b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    /**
100b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * Creates a new CodeAttributeEditor.
101b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * @param updateFrameSizes   specifies whether frame sizes of edited code
102b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     *                           should be updated.
103b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * @param shrinkInstructions specifies whether added instructions should
104b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     *                           automatically be shrunk before being written.
105b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     */
106b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    public CodeAttributeEditor(boolean updateFrameSizes,
107b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                               boolean shrinkInstructions)
108b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
109b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        this.updateFrameSizes   = updateFrameSizes;
110b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        this.shrinkInstructions = shrinkInstructions;
111b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
112b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Resets the accumulated code changes.
116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param codeLength the length of the code that will be edited next.
117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void reset(int codeLength)
119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Try to reuse the previous arrays.
121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (preInsertions.length < codeLength)
122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            preInsertions  = new Instruction[codeLength];
124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            replacements   = new Instruction[codeLength];
125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            postInsertions = new Instruction[codeLength];
126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            deleted        = new boolean[codeLength];
127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        else
129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
130b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            Arrays.fill(preInsertions,  0, codeLength, null);
131b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            Arrays.fill(replacements,   0, codeLength, null);
132b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            Arrays.fill(postInsertions, 0, codeLength, null);
133b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            Arrays.fill(deleted,        0, codeLength, false);
134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
136b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        this.codeLength = codeLength;
137b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
138b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        modified = false;
139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        simple   = true;
140b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    }
141b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
142b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
143b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    /**
144b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * Extends the size of the accumulated code changes.
145b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * @param codeLength the length of the code that will be edited next.
146b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     */
147b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    public void extend(int codeLength)
148b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    {
149b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Try to reuse the previous arrays.
150b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        if (preInsertions.length < codeLength)
151b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        {
152b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            preInsertions  = (Instruction[])ArrayUtil.extendArray(preInsertions,  codeLength);
153b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            replacements   = (Instruction[])ArrayUtil.extendArray(replacements,   codeLength);
154b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            postInsertions = (Instruction[])ArrayUtil.extendArray(postInsertions, codeLength);
155b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            deleted        = ArrayUtil.extendArray(deleted, codeLength);
156b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        }
157b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        else
158b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        {
159b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            Arrays.fill(preInsertions,  this.codeLength, codeLength, null);
160b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            Arrays.fill(replacements,   this.codeLength, codeLength, null);
161b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            Arrays.fill(postInsertions, this.codeLength, codeLength, null);
162b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            Arrays.fill(deleted,        this.codeLength, codeLength, false);
163b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        }
164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
165b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        this.codeLength = codeLength;
166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
168b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
169b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Remembers to place the given instruction right before the instruction
171b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * at the given offset.
172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instructionOffset the offset of the instruction.
173b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instruction       the new instruction.
174b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
175b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void insertBeforeInstruction(int instructionOffset, Instruction instruction)
176b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
177b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (instructionOffset < 0 ||
178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            instructionOffset >= codeLength)
179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
183b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        preInsertions[instructionOffset] = shrinkInstructions ?
184b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction.shrink() :
185b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction;
186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        modified = true;
188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        simple   = false;
189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
192b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Remembers to place the given instructions right before the instruction
194b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * at the given offset.
195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instructionOffset the offset of the instruction.
196b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instructions      the new instructions.
197b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void insertBeforeInstruction(int instructionOffset, Instruction[] instructions)
199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (instructionOffset < 0 ||
201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            instructionOffset >= codeLength)
202b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
203b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
204b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
205b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
206b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        CompositeInstruction instruction =
207b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            new CompositeInstruction(instructions);
208b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
209b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        preInsertions[instructionOffset] = shrinkInstructions ?
210b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction.shrink() :
211b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction;
212b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
213b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        modified = true;
214b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        simple   = false;
215b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
216b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
217b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
218b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
219b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Remembers to replace the instruction at the given offset by the given
220b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * instruction.
221b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instructionOffset the offset of the instruction to be replaced.
222b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instruction       the new instruction.
223b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
224b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void replaceInstruction(int instructionOffset, Instruction instruction)
225b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
226b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (instructionOffset < 0 ||
227b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            instructionOffset >= codeLength)
228b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
229b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
230b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
231b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
232b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        replacements[instructionOffset] = shrinkInstructions ?
233b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction.shrink() :
234b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction;
235b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
236b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        modified = true;
237b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
238b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
239b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
240b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
241b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Remembers to replace the instruction at the given offset by the given
242b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * instructions.
243b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instructionOffset the offset of the instruction to be replaced.
244b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instructions      the new instructions.
245b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
246b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void replaceInstruction(int instructionOffset, Instruction[] instructions)
247b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
248b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (instructionOffset < 0 ||
249b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            instructionOffset >= codeLength)
250b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
251b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
252b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
253b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
254b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        CompositeInstruction instruction =
255b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            new CompositeInstruction(instructions);
256b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
257b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        replacements[instructionOffset] = shrinkInstructions ?
258b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction.shrink() :
259b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction;
260b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
261b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        modified = true;
262b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
263b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
264b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
265b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
266b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Remembers to place the given instruction right after the instruction
267b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * at the given offset.
268b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instructionOffset the offset of the instruction.
269b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instruction       the new instruction.
270b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
271b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void insertAfterInstruction(int instructionOffset, Instruction instruction)
272b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
273b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (instructionOffset < 0 ||
274b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            instructionOffset >= codeLength)
275b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
276b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
277b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
278b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
279b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        postInsertions[instructionOffset] = shrinkInstructions ?
280b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction.shrink() :
281b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction;
282b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
283b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        modified = true;
284b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        simple   = false;
285b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
286b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
287b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
288b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
289b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Remembers to place the given instructions right after the instruction
290b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * at the given offset.
291b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instructionOffset the offset of the instruction.
292b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instructions      the new instructions.
293b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
294b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void insertAfterInstruction(int instructionOffset, Instruction[] instructions)
295b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
296b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (instructionOffset < 0 ||
297b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            instructionOffset >= codeLength)
298b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
299b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
300b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
301b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
302b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        CompositeInstruction instruction =
303b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            new CompositeInstruction(instructions);
304b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
305b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        postInsertions[instructionOffset] = shrinkInstructions ?
306b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction.shrink() :
307b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instruction;
308b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
309b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        modified = true;
310b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        simple   = false;
311b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
312b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
313b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
314b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
315b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Remembers to delete the instruction at the given offset.
316b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instructionOffset the offset of the instruction to be deleted.
317b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
318b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void deleteInstruction(int instructionOffset)
319b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
320b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (instructionOffset < 0 ||
321b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            instructionOffset >= codeLength)
322b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
323b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
324b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
325b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
326b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        deleted[instructionOffset] = true;
327b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
328b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        modified = true;
329b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        simple   = false;
330b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
331b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
332b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
333b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
334b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Remembers not to delete the instruction at the given offset.
335b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instructionOffset the offset of the instruction not to be deleted.
336b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
337b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void undeleteInstruction(int instructionOffset)
338b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
339b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (instructionOffset < 0 ||
340b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            instructionOffset >= codeLength)
341b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
342b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
343b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
344b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
345b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        deleted[instructionOffset] = false;
346b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
347b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
348b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
349b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
350b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * Clears all modifications of the instruction at the given offset.
351b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * @param instructionOffset the offset of the instruction to be deleted.
352b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     */
353b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    public void clearModifications(int instructionOffset)
354b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    {
355b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        if (instructionOffset < 0 ||
356b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            instructionOffset >= codeLength)
357b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        {
358b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
359b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        }
360b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
361b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        preInsertions[instructionOffset]  = null;
362b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        replacements[instructionOffset]   = null;
363b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        postInsertions[instructionOffset] = null;
364b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        deleted[instructionOffset]        = false;
365b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    }
366b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
367b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
368b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    /**
369b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * Returns whether the code has been modified in any way.
370b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     */
371b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    public boolean isModified()
372b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    {
373b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        return modified;
374b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    }
375b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
376b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
377b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    /**
378b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether the instruction at the given offset has been modified
379b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * in any way.
380b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
381b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public boolean isModified(int instructionOffset)
382b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
383b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return preInsertions[instructionOffset]  != null ||
384b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               replacements[instructionOffset]   != null ||
385b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               postInsertions[instructionOffset] != null ||
386b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               deleted[instructionOffset];
387b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
388b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
389b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
390b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for AttributeVisitor.
391b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
392b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
393b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
394b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
395b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
396b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
397b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato//        DEBUG =
398b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato//            clazz.getName().equals("abc/Def") &&
399b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato//            method.getName(clazz).equals("abc");
400b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
401b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // TODO: Remove this when the code has stabilized.
402b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Catch any unexpected exceptions from the actual visiting method.
403b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        try
404b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
405b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Process the code.
406b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            visitCodeAttribute0(clazz, method, codeAttribute);
407b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
408b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        catch (RuntimeException ex)
409b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
410b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.err.println("Unexpected error while editing code:");
411b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.err.println("  Class       = ["+clazz.getName()+"]");
412b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.err.println("  Method      = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");
413b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.err.println("  Exception   = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");
414b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
415b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw ex;
416b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
417b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
418b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
419b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
420b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)
421b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
422b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Do we have to update the code?
423b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        if (modified)
424b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
425b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            if (DEBUG)
426b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            {
427b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                System.out.println("CodeAttributeEditor: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
428b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            }
429b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
430b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            // Can we perform a faster simple replacement of instructions?
431b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            if (canPerformSimpleReplacements(codeAttribute))
432b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            {
433b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                if (DEBUG)
434b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                {
435b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                    System.out.println("  Simple editing");
436b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                }
437b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
438b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                // Simply overwrite the instructions.
439b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                performSimpleReplacements(codeAttribute);
440b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            }
441b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            else
442b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            {
443b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                if (DEBUG)
444b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                {
445b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                    System.out.println("  Full editing");
446b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                }
447b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
448b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                // Move and remap the instructions.
449b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                codeAttribute.u4codeLength =
450b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                    updateInstructions(clazz, method, codeAttribute);
451b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
452b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                // Update the exception table.
453b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                codeAttribute.exceptionsAccept(clazz, method, this);
454b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
455b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                // Remove exceptions with empty code blocks.
456b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                codeAttribute.u2exceptionTableLength =
457b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                    removeEmptyExceptions(codeAttribute.exceptionTable,
458b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                                          codeAttribute.u2exceptionTableLength);
4599f606f95f03a75961498803e24bee6799a7c0885Ying Wang
460b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                // Update the line number table and the local variable tables.
461b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                codeAttribute.attributesAccept(clazz, method, this);
462b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            }
463b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
464b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Make sure instructions are widened if necessary.
465b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            instructionWriter.visitCodeAttribute(clazz, method, codeAttribute);
466b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
467b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
468b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the maximum stack size and local variable frame size.
469b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (updateFrameSizes)
470b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
471b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);
472b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            variableSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);
473b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
474b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
475b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
476b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
477b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
478b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
479b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update all stack map entries.
480b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        expectedStackMapFrameOffset = -1;
481b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
482b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
483b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
484b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
485b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
486b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
487b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update all stack map table entries.
488b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        expectedStackMapFrameOffset = 0;
489b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
490b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
491b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
492b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
493b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
494b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
495b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update all line number table entries.
496b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this);
497b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
498b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Remove line numbers with empty code blocks.
499b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        lineNumberTableAttribute.u2lineNumberTableLength =
500b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato           removeEmptyLineNumbers(lineNumberTableAttribute.lineNumberTable,
501b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                  lineNumberTableAttribute.u2lineNumberTableLength,
502b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                  codeAttribute.u4codeLength);
503b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
504b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
505b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
506b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
507b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
508b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update all local variable table entries.
509b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
510b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
511b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
512b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
513b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
514b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
515b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update all local variable table entries.
516b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
517b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
518b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
519b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
5202270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    public void visitAnyTypeAnnotationsAttribute(Clazz clazz, TypeAnnotationsAttribute typeAnnotationsAttribute)
5212270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    {
5222270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        typeAnnotationsAttribute.typeAnnotationsAccept(clazz, this);
5232270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    }
5242270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
5252270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
526b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
527b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Checks if it is possible to modifies the given code without having to
528b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * update any offsets.
529b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param codeAttribute the code to be changed.
530b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @return the new code length.
531b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
532b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private boolean canPerformSimpleReplacements(CodeAttribute codeAttribute)
533b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
534b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (!simple)
535b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
536b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            return false;
537b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
538b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
539b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        byte[] code       = codeAttribute.code;
540b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int    codeLength = codeAttribute.u4codeLength;
541b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
542b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Go over all replacement instructions.
543b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        for (int offset = 0; offset < codeLength; offset++)
544b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
545b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Check if the replacement instruction, if any, has a different
546b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // length than the original instruction.
547b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            Instruction replacementInstruction = replacements[offset];
548b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (replacementInstruction != null &&
549b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                replacementInstruction.length(offset) !=
550b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    InstructionFactory.create(code, offset).length(offset))
551b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
552b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                return false;
553b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
554b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
555b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
556b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return true;
557b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
558b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
559b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
560b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
561b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Modifies the given code without updating any offsets.
562b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param codeAttribute the code to be changed.
563b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
564b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private void performSimpleReplacements(CodeAttribute codeAttribute)
565b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
566b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int codeLength = codeAttribute.u4codeLength;
567b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
568b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Go over all replacement instructions.
569b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        for (int offset = 0; offset < codeLength; offset++)
570b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
571b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Overwrite the original instruction with the replacement
572b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // instruction if any.
573b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            Instruction replacementInstruction = replacements[offset];
574b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (replacementInstruction != null)
575b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
576b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                replacementInstruction.write(codeAttribute, offset);
577b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
578b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                if (DEBUG)
579b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                {
580b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                    System.out.println("  Replaced "+replacementInstruction.toString(offset));
581b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                }
582b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
583b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
584b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
585b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
586b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
587b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
588b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Modifies the given code based on the previously specified changes.
589b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param clazz         the class file of the code to be changed.
590b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param method        the method of the code to be changed.
591b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param codeAttribute the code to be changed.
592b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @return the new code length.
593b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
594b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private int updateInstructions(Clazz         clazz,
595b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                   Method        method,
596b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                   CodeAttribute codeAttribute)
597b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
598b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        byte[] oldCode   = codeAttribute.code;
599b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int    oldLength = codeAttribute.u4codeLength;
600b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
601b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Make sure there is a sufficiently large instruction offset map.
602b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        if (newInstructionOffsets.length < oldLength + 1)
603b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
604b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            newInstructionOffsets = new int[oldLength + 1];
605b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
606b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
607b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Fill out the instruction offset map.
608b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int newLength = mapInstructions(oldCode,
609b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                        oldLength);
610b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
611b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Create a new code array if necessary.
612b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (lengthIncreased)
613b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
614b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            codeAttribute.code = new byte[newLength];
615b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
616b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
617b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Prepare for possible widening of instructions.
618b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        instructionWriter.reset(newLength);
619b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
620b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Move the instructions into the new code array.
621b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        moveInstructions(clazz,
622b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                         method,
623b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                         codeAttribute,
624b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                         oldCode,
625b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                         oldLength);
626b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
627b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // We can return the new length.
628b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return newLength;
629b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
630b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
631b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
632b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
633b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Fills out the instruction offset map for the given code block.
634b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param oldCode   the instructions to be moved.
635b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param oldLength the code length.
636b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @return the new code length.
637b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
638b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private int mapInstructions(byte[] oldCode, int oldLength)
639b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
640b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Start mapping instructions at the beginning.
641b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        newOffset       = 0;
642b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        lengthIncreased = false;
643b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
644b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int oldOffset = 0;
645b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        do
646b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
647b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Get the next instruction.
648b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            Instruction instruction = InstructionFactory.create(oldCode, oldOffset);
649b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
650b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Compute the mapping of the instruction.
651b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            mapInstruction(oldOffset, instruction);
652b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
653b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            oldOffset += instruction.length(oldOffset);
654b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
655b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (newOffset > oldOffset)
656b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
657b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                lengthIncreased = true;
658b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
659b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
660b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        while (oldOffset < oldLength);
661b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
662b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Also add an entry for the first offset after the code.
663b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        newInstructionOffsets[oldOffset] = newOffset;
664b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
665b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return newOffset;
666b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
667b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
668b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
669b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
670b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Fills out the instruction offset map for the given instruction.
671b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param oldOffset   the instruction's old offset.
672b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instruction the instruction to be moved.
673b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
674b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private void mapInstruction(int         oldOffset,
675b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                Instruction instruction)
676b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
677b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        newInstructionOffsets[oldOffset] = newOffset;
678b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
679b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Account for the pre-inserted instruction, if any.
680b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Instruction preInstruction = preInsertions[oldOffset];
681b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (preInstruction != null)
682b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
683b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            newOffset += preInstruction.length(newOffset);
684b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
685b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
686b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Account for the replacement instruction, or for the current
687b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // instruction, if it shouldn't be  deleted.
688b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Instruction replacementInstruction = replacements[oldOffset];
689b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (replacementInstruction != null)
690b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
691b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            newOffset += replacementInstruction.length(newOffset);
692b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
693b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        else if (!deleted[oldOffset])
694b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
695b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Note that the instruction's length may change at its new offset,
696b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // e.g. if it is a switch instruction.
697b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            newOffset += instruction.length(newOffset);
698b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
699b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
700b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Account for the post-inserted instruction, if any.
701b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Instruction postInstruction = postInsertions[oldOffset];
702b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (postInstruction != null)
703b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
704b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            newOffset += postInstruction.length(newOffset);
705b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
706b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
707b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
708b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
709b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
710b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Moves the given code block to the new offsets.
711b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param clazz         the class file of the code to be changed.
712b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param method        the method of the code to be changed.
713b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param codeAttribute the code to be changed.
714b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param oldCode       the original code to be moved.
715b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param oldLength     the original code length.
716b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
717b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private void moveInstructions(Clazz         clazz,
718b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                  Method        method,
719b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                  CodeAttribute codeAttribute,
720b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                  byte[]        oldCode,
721b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                  int           oldLength)
722b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
723b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Start writing instructions at the beginning.
724b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        newOffset = 0;
725b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
726b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int oldOffset = 0;
727b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        do
728b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
729b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Get the next instruction.
730b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            Instruction instruction = InstructionFactory.create(oldCode, oldOffset);
731b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
732b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Move the instruction to its new offset.
733b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            moveInstruction(clazz,
734b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            method,
735b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            codeAttribute,
736b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            oldOffset,
737b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            instruction);
738b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
739b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            oldOffset += instruction.length(oldOffset);
740b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
741b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        while (oldOffset < oldLength);
742b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
743b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
744b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
745b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
746b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Moves the given instruction to its new offset.
747b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param clazz         the class file of the code to be changed.
748b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param method        the method of the code to be changed.
749b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param codeAttribute the code to be changed.
750b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param oldOffset     the original instruction offset.
751b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param instruction   the original instruction.
752b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
753b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private void moveInstruction(Clazz         clazz,
754b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                 Method        method,
755b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                 CodeAttribute codeAttribute,
756b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                 int           oldOffset,
757b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                 Instruction   instruction)
758b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
759b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update and insert the pre-inserted instruction, if any.
760b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Instruction preInstruction = preInsertions[oldOffset];
761b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (preInstruction != null)
762b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
763b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (DEBUG)
764b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
765b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                System.out.println("  Pre-inserted  ["+oldOffset+"] -> "+preInstruction.toString(newOffset));
766b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
767b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
768b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            // Update the instruction.
769b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            preInstruction.accept(clazz, method, codeAttribute, oldOffset, this);
770b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
771b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
772b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update and insert the replacement instruction, or the current
773b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // instruction, if it shouldn't be deleted.
774b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Instruction replacementInstruction = replacements[oldOffset];
775b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (replacementInstruction != null)
776b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
777b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (DEBUG)
778b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
779b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                System.out.println("  Replaced      ["+oldOffset+"] -> "+replacementInstruction.toString(newOffset));
780b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
781b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
782b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            // Update the instruction.
783b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            replacementInstruction.accept(clazz, method, codeAttribute, oldOffset, this);
784b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
785b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        else if (!deleted[oldOffset])
786b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
787b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (DEBUG)
788b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
789b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                System.out.println("  Copied        ["+oldOffset+"] -> "+instruction.toString(newOffset));
790b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
791b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
792b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            // Update the instruction.
793b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            instruction.accept(clazz, method, codeAttribute, oldOffset, this);
794b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
795b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
796b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update and insert the post-inserted instruction, if any.
797b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Instruction postInstruction = postInsertions[oldOffset];
798b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (postInstruction != null)
799b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
800b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (DEBUG)
801b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
802b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang                System.out.println("  Post-inserted ["+oldOffset+"] -> "+postInstruction.toString(newOffset));
803b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
804b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
805b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            // Update the instruction.
806b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            postInstruction.accept(clazz, method, codeAttribute, oldOffset, this);
807b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
808b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
809b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
810b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
811b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for InstructionVisitor.
812b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
813b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
814b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
815b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Write out the instruction.
816b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        instructionWriter.visitSimpleInstruction(clazz,
817b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                 method,
818b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                 codeAttribute,
819b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                 newOffset,
820b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                 simpleInstruction);
821b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
822b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        newOffset += simpleInstruction.length(newOffset);
823b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
824b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
825b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
826b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
827b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
828b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Write out the instruction.
829b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        instructionWriter.visitConstantInstruction(clazz,
830b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                   method,
831b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                   codeAttribute,
832b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                   newOffset,
833b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                   constantInstruction);
834b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
835b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        newOffset += constantInstruction.length(newOffset);
836b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
837b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
838b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
839b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
840b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
841b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Write out the instruction.
842b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        instructionWriter.visitVariableInstruction(clazz,
843b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                   method,
844b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                   codeAttribute,
845b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                   newOffset,
846b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                   variableInstruction);
847b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
848b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        newOffset += variableInstruction.length(newOffset);
849b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
850b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
851b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
852b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
853b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
8542270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Update the branch offset, relative to the precise new offset.
8552270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        branchInstruction.branchOffset =
8562270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom            newBranchOffset(offset, branchInstruction.branchOffset, newOffset);
857b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
858b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Write out the instruction.
859b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        instructionWriter.visitBranchInstruction(clazz,
860b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                 method,
861b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                 codeAttribute,
862b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                 newOffset,
863b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                 branchInstruction);
864b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
865b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        newOffset += branchInstruction.length(newOffset);
866b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
867b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
868b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
869b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
870b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
8712270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Update the default jump offset, relative to the precise new offset.
8722270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        tableSwitchInstruction.defaultOffset =
8732270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom            newBranchOffset(offset, tableSwitchInstruction.defaultOffset, newOffset);
874b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
8752270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Update the jump offsets, relative to the precise new offset.
876b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        newJumpOffsets(offset,
8772270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom                       tableSwitchInstruction.jumpOffsets,
8782270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom                       newOffset);
879b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
880b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Write out the instruction.
881b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        instructionWriter.visitTableSwitchInstruction(clazz,
882b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                      method,
883b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                      codeAttribute,
884b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                      newOffset,
885b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                      tableSwitchInstruction);
886b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
887b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        newOffset += tableSwitchInstruction.length(newOffset);
888b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
889b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
890b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
891b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
892b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
8932270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Update the default jump offset, relative to the precise new offset.
8942270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        lookUpSwitchInstruction.defaultOffset =
8952270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom            newBranchOffset(offset, lookUpSwitchInstruction.defaultOffset, newOffset);
896b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
8972270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Update the jump offsets, relative to the precise new offset.
898b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        newJumpOffsets(offset,
8992270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom                       lookUpSwitchInstruction.jumpOffsets,
9002270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom                       newOffset);
901b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
902b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Write out the instruction.
903b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        instructionWriter.visitLookUpSwitchInstruction(clazz,
904b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                       method,
905b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                       codeAttribute,
906b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                       newOffset,
907b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                       lookUpSwitchInstruction);
908b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
909b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        newOffset += lookUpSwitchInstruction.length(newOffset);
910b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
911b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
912b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
913b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for ExceptionInfoVisitor.
914b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
915b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
916b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
9172270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Update the code offsets. Note that the instruction offset map also
9182270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // has an entry for the first offset after the code, for u2endPC.
919b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        exceptionInfo.u2startPC   = newInstructionOffset(exceptionInfo.u2startPC);
920b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        exceptionInfo.u2endPC     = newInstructionOffset(exceptionInfo.u2endPC);
921b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        exceptionInfo.u2handlerPC = newInstructionOffset(exceptionInfo.u2handlerPC);
922b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
923b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
924b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
925b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for StackMapFrameVisitor.
926b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
927b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame)
928b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
929b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the stack map frame offset.
930b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        int stackMapFrameOffset = newInstructionOffset(offset);
931b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
932b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int offsetDelta = stackMapFrameOffset;
933b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
934b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Compute the offset delta if the frame is part of a stack map frame
935b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // table (for JDK 6.0) instead of a stack map (for Java Micro Edition).
936b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (expectedStackMapFrameOffset >= 0)
937b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
938b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            offsetDelta -= expectedStackMapFrameOffset;
939b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
940b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            expectedStackMapFrameOffset = stackMapFrameOffset + 1;
941b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
942b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
943b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        stackMapFrame.u2offsetDelta = offsetDelta;
944b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
945b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
946b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
947b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame)
948b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
949b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the stack map frame offset.
950b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        visitAnyStackMapFrame(clazz, method, codeAttribute, offset, sameOneFrame);
951b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
952b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the verification type offset.
953b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this);
954b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
955b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
956b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
957b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame)
958b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
959b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the stack map frame offset.
960b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        visitAnyStackMapFrame(clazz, method, codeAttribute, offset, moreZeroFrame);
961b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
962b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the verification type offsets.
963b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this);
964b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
965b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
966b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
967b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame)
968b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
969b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the stack map frame offset.
970b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        visitAnyStackMapFrame(clazz, method, codeAttribute, offset, fullFrame);
971b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
972b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the verification type offsets.
973b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this);
974b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        fullFrame.stackAccept(clazz, method, codeAttribute, offset, this);
975b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
976b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
977b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
978b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for VerificationTypeVisitor.
979b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
980b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {}
981b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
982b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
983b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType)
984b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
985b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the offset of the 'new' instruction.
986b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        uninitializedType.u2newInstructionOffset = newInstructionOffset(uninitializedType.u2newInstructionOffset);
987b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
988b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
989b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
990b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for LineNumberInfoVisitor.
991b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
992b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo)
993b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
994b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the code offset.
995b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        lineNumberInfo.u2startPC = newInstructionOffset(lineNumberInfo.u2startPC);
996b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
997b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
998b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
999b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for LocalVariableInfoVisitor.
1000b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1001b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
1002b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
1003b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the code offset and length.
10042270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Be careful to update the length first.
10052270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        localVariableInfo.u2length  = newBranchOffset(localVariableInfo.u2startPC, localVariableInfo.u2length);
10062270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        localVariableInfo.u2startPC = newInstructionOffset(localVariableInfo.u2startPC);
1007b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
1008b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1009b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1010b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for LocalVariableTypeInfoVisitor.
1011b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1012b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
1013b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
1014b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        // Update the code offset and length.
10152270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Be careful to update the length first.
10162270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        localVariableTypeInfo.u2length  = newBranchOffset(localVariableTypeInfo.u2startPC, localVariableTypeInfo.u2length);
10172270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        localVariableTypeInfo.u2startPC = newInstructionOffset(localVariableTypeInfo.u2startPC);
10182270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    }
10192270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10202270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10212270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    // Implementations for TypeAnnotationVisitor.
10222270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10232270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    public void visitTypeAnnotation(Clazz clazz, TypeAnnotation typeAnnotation)
10242270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    {
10252270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Update all local variable targets.
10262270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        typeAnnotation.targetInfoAccept(clazz, this);
10272270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    }
10282270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10292270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10302270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    // Implementations for TargetInfoVisitor.
10312270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10322270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    public void visitAnyTargetInfo(Clazz clazz, TypeAnnotation typeAnnotation, TargetInfo targetInfo) {}
10332270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
1034b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang
10352270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    public void visitLocalVariableTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, LocalVariableTargetInfo localVariableTargetInfo)
10362270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    {
10372270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Update the offsets of the variables.
10382270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        localVariableTargetInfo.targetElementsAccept(clazz, method, codeAttribute, typeAnnotation, this);
10392270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    }
10402270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10412270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10422270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    public void visitOffsetTargetInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, OffsetTargetInfo offsetTargetInfo)
10432270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    {
10442270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Update the offset.
10452270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        offsetTargetInfo.u2offset = newInstructionOffset(offsetTargetInfo.u2offset);
10462270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    }
10472270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10482270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10492270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    // Implementations for LocalVariableTargetElementVisitor.
10502270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10512270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    public void visitLocalVariableTargetElement(Clazz clazz, Method method, CodeAttribute codeAttribute, TypeAnnotation typeAnnotation, LocalVariableTargetInfo localVariableTargetInfo, LocalVariableTargetElement localVariableTargetElement)
10522270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    {
10532270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Update the variable start offset and length.
10542270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        // Be careful to update the length first.
10552270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        localVariableTargetElement.u2length  = newBranchOffset(localVariableTargetElement.u2startPC, localVariableTargetElement.u2length);
10562270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        localVariableTargetElement.u2startPC = newInstructionOffset(localVariableTargetElement.u2startPC);
1057b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
1058b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1059b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1060b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Small utility methods.
1061b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1062b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
10632270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom     * Updates the given jump offsets for the instruction at the given offset,
10642270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom     * relative to the given new offset.
1065b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
10662270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    private void newJumpOffsets(int   oldInstructionOffset,
10672270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom                                int[] oldJumpOffsets,
10682270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom                                int   newInstructionOffset)
1069b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
1070b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        for (int index = 0; index < oldJumpOffsets.length; index++)
1071b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
10722270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom            oldJumpOffsets[index] = newBranchOffset(oldInstructionOffset,
10732270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom                                                    oldJumpOffsets[index],
10742270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom                                                    newInstructionOffset);
1075b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1076b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
1077b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1078b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1079b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
1080b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Computes the new branch offset for the instruction at the given offset
10812270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom     * with the given branch offset, relative to the new instruction (block)
10822270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom     * offset.
10832270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom     */
10842270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    private int newBranchOffset(int oldInstructionOffset,
10852270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom                                int oldBranchOffset)
10862270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    {
10872270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        return newInstructionOffset(oldInstructionOffset + oldBranchOffset) -
10882270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom               newInstructionOffset(oldInstructionOffset);
10892270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    }
10902270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10912270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom
10922270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    /**
10932270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom     * Computes the new branch offset for the instruction at the given offset
10942270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom     * with the given branch offset, relative to the given new offset.
1095b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
10962270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom    private int newBranchOffset(int oldInstructionOffset,
10972270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom                                int oldBranchOffset,
10982270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom                                int newInstructionOffset)
1099b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
11002270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom        return newInstructionOffset(oldInstructionOffset + oldBranchOffset) -
11012270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom               newInstructionOffset;
1102b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
1103b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
11062270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom     * Computes the new instruction offset for the instruction at the given
11072270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom     * offset.
1108b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
1109b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang    private int newInstructionOffset(int oldInstructionOffset)
1110b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
1111b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        if (oldInstructionOffset < 0 ||
1112b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            oldInstructionOffset > codeLength)
1113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
1114b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            throw new IllegalArgumentException("Invalid instruction offset ["+oldInstructionOffset+"] in code with length ["+codeLength+"]");
1115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1117b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang        return newInstructionOffsets[oldInstructionOffset];
1118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
1119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
1122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns the given list of exceptions, without the ones that have empty
1123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * code blocks.
1124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
1125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private int removeEmptyExceptions(ExceptionInfo[] exceptionInfos,
1126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                      int             exceptionInfoCount)
1127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
1128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Overwrite all empty exceptions.
1129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int newIndex = 0;
1130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        for (int index = 0; index < exceptionInfoCount; index++)
1131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
1132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            ExceptionInfo exceptionInfo = exceptionInfos[index];
1133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (exceptionInfo.u2startPC < exceptionInfo.u2endPC)
1134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
1135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                exceptionInfos[newIndex++] = exceptionInfo;
1136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
1137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1138b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return newIndex;
1140b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
1141b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1142b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1143b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
1144b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns the given list of line numbers, without the ones that have empty
1145b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * code blocks or that exceed the code size.
1146b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
1147b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private int removeEmptyLineNumbers(LineNumberInfo[] lineNumberInfos,
1148b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                       int              lineNumberInfoCount,
1149b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                       int              codeLength)
1150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
1151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Overwrite all empty line number entries.
1152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int newIndex = 0;
1153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        for (int index = 0; index < lineNumberInfoCount; index++)
1154b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
1155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            LineNumberInfo lineNumberInfo = lineNumberInfos[index];
1156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            int startPC = lineNumberInfo.u2startPC;
1157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (startPC < codeLength &&
1158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                (index == 0 || startPC > lineNumberInfos[index-1].u2startPC))
1159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
1160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                lineNumberInfos[newIndex++] = lineNumberInfo;
1161b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
1162b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1163b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return newIndex;
1165b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
1166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
11689f606f95f03a75961498803e24bee6799a7c0885Ying Wang    /**
1169b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * This instruction is a composite of other instructions, for local use
1170b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang     * inside the editor class only.
11719f606f95f03a75961498803e24bee6799a7c0885Ying Wang     */
1172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private class CompositeInstruction
1173b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    extends       Instruction
1174b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
1175b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        private Instruction[] instructions;
1176b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1177b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        private CompositeInstruction(Instruction[] instructions)
1179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
1180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            this.instructions = instructions;
1181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Implementations for Instruction.
1185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        public Instruction shrink()
1187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
1188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            for (int index = 0; index < instructions.length; index++)
1189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
1190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                instructions[index] = instructions[index].shrink();
1191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
1192b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            return this;
1194b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1196b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1197b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        public void write(byte[] code, int offset)
1198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
1199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            for (int index = 0; index < instructions.length; index++)
1200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
1201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                Instruction instruction = instructions[index];
1202b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1203b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                instruction.write(code, offset);
1204b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1205b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                offset += instruction.length(offset);
1206b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
1207b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1208b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1209b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1210b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        protected void readInfo(byte[] code, int offset)
1211b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
1212b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw new UnsupportedOperationException("Can't read composite instruction");
1213b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1214b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1215b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1216b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        protected void writeInfo(byte[] code, int offset)
1217b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
1218b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw new UnsupportedOperationException("Can't write composite instruction");
1219b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1220b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1221b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1222b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        public int length(int offset)
1223b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
1224b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            int newOffset = offset;
1225b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1226b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            for (int index = 0; index < instructions.length; index++)
1227b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
1228b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                newOffset += instructions[index].length(newOffset);
1229b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
1230b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1231b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            return newOffset - offset;
1232b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1233b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1234b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1235b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
1236b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
1237b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (instructionVisitor != CodeAttributeEditor.this)
1238b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
1239b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                throw new UnsupportedOperationException("Unexpected visitor ["+instructionVisitor+"]");
1240b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
1241b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1242b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            for (int index = 0; index < instructions.length; index++)
1243b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
1244b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                Instruction instruction = instructions[index];
1245b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1246b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                instruction.accept(clazz, method, codeAttribute, offset, CodeAttributeEditor.this);
1247b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1248b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                offset += instruction.length(offset);
1249b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
1250b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1251b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1252b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1253b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Implementations for Object.
1254b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1255b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        public String toString()
1256b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
1257b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            StringBuffer stringBuffer = new StringBuffer();
1258b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1259b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            for (int index = 0; index < instructions.length; index++)
1260b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
1261b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                stringBuffer.append(instructions[index].toString()).append("; ");
1262b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
1263b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1264b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            return stringBuffer.toString();
1265b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
1266b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
1267b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato}
1268