KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > asm > Label


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2005 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */

30 package com.tc.asm;
31
32 /**
33  * A label represents a position in the bytecode of a method. Labels are used
34  * for jump, goto, and switch instructions, and for try catch blocks.
35  *
36  * @author Eric Bruneton
37  */

38 public class Label {
39
40     /**
41      * The line number corresponding to this label, if known.
42      */

43     int line;
44
45     /**
46      * Indicates if the position of this label is known.
47      */

48     boolean resolved;
49
50     /**
51      * The position of this label in the code, if known.
52      */

53     int position;
54
55     /**
56      * If the label position has been updated, after instruction resizing.
57      */

58     boolean resized;
59
60     /**
61      * Number of forward references to this label, times two.
62      */

63     private int referenceCount;
64
65     /**
66      * Informations about forward references. Each forward reference is
67      * described by two consecutive integers in this array: the first one is the
68      * position of the first byte of the bytecode instruction that contains the
69      * forward reference, while the second is the position of the first byte of
70      * the forward reference itself. In fact the sign of the first integer
71      * indicates if this reference uses 2 or 4 bytes, and its absolute value
72      * gives the position of the bytecode instruction.
73      */

74     private int[] srcAndRefPositions;
75
76     /*
77      * Fields for the control flow graph analysis algorithm (used to compute the
78      * maximum stack size). A control flow graph contains one node per "basic
79      * block", and one edge per "jump" from one basic block to another. Each
80      * node (i.e., each basic block) is represented by the Label object that
81      * corresponds to the first instruction of this basic block. Each node also
82      * stores the list of it successors in the graph, as a linked list of Edge
83      * objects.
84      */

85
86     /**
87      * The stack size at the beginning of this basic block. This size is
88      * initially unknown. It is computed by the control flow analysis algorithm
89      * (see {@link MethodWriter#visitMaxs visitMaxs}).
90      */

91     int beginStackSize;
92
93     /**
94      * The (relative) maximum stack size corresponding to this basic block. This
95      * size is relative to the stack size at the beginning of the basic block,
96      * i.e., the true maximum stack size is equal to {@link #beginStackSize
97      * beginStackSize} + {@link #maxStackSize maxStackSize}.
98      */

99     int maxStackSize;
100
101     /**
102      * The successors of this node in the control flow graph. These successors
103      * are stored in a linked list of {@link Edge Edge} objects, linked to each
104      * other by their {@link Edge#next} field.
105      */

106     Edge successors;
107
108     /**
109      * The next basic block in the basic block stack. See
110      * {@link MethodWriter#visitMaxs visitMaxs}.
111      */

112     Label next;
113
114     /**
115      * <tt>true</tt> if this basic block has been pushed in the basic block
116      * stack. See {@link MethodWriter#visitMaxs visitMaxs}.
117      */

118     boolean pushed;
119
120     // ------------------------------------------------------------------------
121
// Constructor
122
// ------------------------------------------------------------------------
123

124     /**
125      * Constructs a new label.
126      */

127     public Label() {
128     }
129
130     // ------------------------------------------------------------------------
131
// Methods to compute offsets and to manage forward references
132
// ------------------------------------------------------------------------
133

134     /**
135      * Returns the offset corresponding to this label. This offset is computed
136      * from the start of the method's bytecode. <i>This method is intended for
137      * {@link Attribute} sub classes, and is normally not needed by class
138      * generators or adapters.</i>
139      *
140      * @return the offset corresponding to this label.
141      * @throws IllegalStateException if this label is not resolved yet.
142      */

143     public int getOffset() {
144         if (!resolved) {
145             throw new IllegalStateException JavaDoc("Label offset position has not been resolved yet");
146         }
147         return position;
148     }
149
150     /**
151      * Puts a reference to this label in the bytecode of a method. If the
152      * position of the label is known, the offset is computed and written
153      * directly. Otherwise, a null offset is written and a new forward reference
154      * is declared for this label.
155      *
156      * @param owner the code writer that calls this method.
157      * @param out the bytecode of the method.
158      * @param source the position of first byte of the bytecode instruction that
159      * contains this label.
160      * @param wideOffset <tt>true</tt> if the reference must be stored in 4
161      * bytes, or <tt>false</tt> if it must be stored with 2 bytes.
162      * @throws IllegalArgumentException if this label has not been created by
163      * the given code writer.
164      */

165     void put(
166         final MethodWriter owner,
167         final ByteVector out,
168         final int source,
169         final boolean wideOffset)
170     {
171         if (resolved) {
172             if (wideOffset) {
173                 out.putInt(position - source);
174             } else {
175                 out.putShort(position - source);
176             }
177         } else {
178             if (wideOffset) {
179                 addReference(-1 - source, out.length);
180                 out.putInt(-1);
181             } else {
182                 addReference(source, out.length);
183                 out.putShort(-1);
184             }
185         }
186     }
187
188     /**
189      * Adds a forward reference to this label. This method must be called only
190      * for a true forward reference, i.e. only if this label is not resolved
191      * yet. For backward references, the offset of the reference can be, and
192      * must be, computed and stored directly.
193      *
194      * @param sourcePosition the position of the referencing instruction. This
195      * position will be used to compute the offset of this forward
196      * reference.
197      * @param referencePosition the position where the offset for this forward
198      * reference must be stored.
199      */

200     private void addReference(
201         final int sourcePosition,
202         final int referencePosition)
203     {
204         if (srcAndRefPositions == null) {
205             srcAndRefPositions = new int[6];
206         }
207         if (referenceCount >= srcAndRefPositions.length) {
208             int[] a = new int[srcAndRefPositions.length + 6];
209             System.arraycopy(srcAndRefPositions,
210                     0,
211                     a,
212                     0,
213                     srcAndRefPositions.length);
214             srcAndRefPositions = a;
215         }
216         srcAndRefPositions[referenceCount++] = sourcePosition;
217         srcAndRefPositions[referenceCount++] = referencePosition;
218     }
219
220     /**
221      * Resolves all forward references to this label. This method must be called
222      * when this label is added to the bytecode of the method, i.e. when its
223      * position becomes known. This method fills in the blanks that where left
224      * in the bytecode by each forward reference previously added to this label.
225      *
226      * @param owner the code writer that calls this method.
227      * @param position the position of this label in the bytecode.
228      * @param data the bytecode of the method.
229      * @return <tt>true</tt> if a blank that was left for this label was to
230      * small to store the offset. In such a case the corresponding jump
231      * instruction is replaced with a pseudo instruction (using unused
232      * opcodes) using an unsigned two bytes offset. These pseudo
233      * instructions will need to be replaced with true instructions with
234      * wider offsets (4 bytes instead of 2). This is done in
235      * {@link MethodWriter#resizeInstructions}.
236      * @throws IllegalArgumentException if this label has already been resolved,
237      * or if it has not been created by the given code writer.
238      */

239     boolean resolve(
240         final MethodWriter owner,
241         final int position,
242         final byte[] data)
243     {
244         boolean needUpdate = false;
245         this.resolved = true;
246         this.position = position;
247         int i = 0;
248         while (i < referenceCount) {
249             int source = srcAndRefPositions[i++];
250             int reference = srcAndRefPositions[i++];
251             int offset;
252             if (source >= 0) {
253                 offset = position - source;
254                 if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
255                     /*
256                      * changes the opcode of the jump instruction, in order to
257                      * be able to find it later (see resizeInstructions in
258                      * MethodWriter). These temporary opcodes are similar to
259                      * jump instruction opcodes, except that the 2 bytes offset
260                      * is unsigned (and can therefore represent values from 0 to
261                      * 65535, which is sufficient since the size of a method is
262                      * limited to 65535 bytes).
263                      */

264                     int opcode = data[reference - 1] & 0xFF;
265                     if (opcode <= Opcodes.JSR) {
266                         // changes IFEQ ... JSR to opcodes 202 to 217
267
data[reference - 1] = (byte) (opcode + 49);
268                     } else {
269                         // changes IFNULL and IFNONNULL to opcodes 218 and 219
270
data[reference - 1] = (byte) (opcode + 20);
271                     }
272                     needUpdate = true;
273                 }
274                 data[reference++] = (byte) (offset >>> 8);
275                 data[reference] = (byte) offset;
276             } else {
277                 offset = position + source + 1;
278                 data[reference++] = (byte) (offset >>> 24);
279                 data[reference++] = (byte) (offset >>> 16);
280                 data[reference++] = (byte) (offset >>> 8);
281                 data[reference] = (byte) offset;
282             }
283         }
284         return needUpdate;
285     }
286
287     // ------------------------------------------------------------------------
288
// Overriden Object methods
289
// ------------------------------------------------------------------------
290

291     /**
292      * Returns a string representation of this label.
293      *
294      * @return a string representation of this label.
295      */

296     public String JavaDoc toString() {
297         return "L" + System.identityHashCode(this);
298     }
299 }
300
Popular Tags