KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > libraries > asm > Label


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000,2002,2003 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
31 package oracle.toplink.libraries.asm;
32
33 /**
34  * A label represents a position in the bytecode of a method. Labels are used
35  * for jump, goto, and switch instructions, and for try catch blocks.
36  *
37  * @author Eric Bruneton
38  */

39
40 public class Label {
41
42   /**
43    * The code writer to which this label belongs, or <tt>null</tt> if unknown.
44    */

45
46   CodeWriter owner;
47
48   /**
49    * The line number corresponding to this label, if known.
50    */

51
52   int line;
53   
54   /**
55    * Indicates if the position of this label is known.
56    */

57
58   boolean resolved;
59
60   /**
61    * The position of this label in the code, if known.
62    */

63
64   int position;
65
66   /**
67    * If the label position has been updated, after instruction resizing.
68    */

69
70   boolean resized;
71
72   /**
73    * Number of forward references to this label, times two.
74    */

75
76   private int referenceCount;
77
78   /**
79    * Informations about forward references. Each forward reference is described
80    * by two consecutive integers in this array: the first one is the position
81    * of the first byte of the bytecode instruction that contains the forward
82    * reference, while the second is the position of the first byte of the
83    * forward reference itself. In fact the sign of the first integer indicates
84    * if this reference uses 2 or 4 bytes, and its absolute value gives the
85    * position of the bytecode instruction.
86    */

87
88   private int[] srcAndRefPositions;
89
90   // --------------------------------------------------------------------------
91
// Fields for the control flow graph analysis algorithm (used to compute the
92
// maximum stack size). A control flow graph contains one node per "basic
93
// block", and one edge per "jump" from one basic block to another. Each node
94
// (i.e., each basic block) is represented by the Label object that
95
// corresponds to the first instruction of this basic block. Each node also
96
// stores the list of it successors in the graph, as a linked list of Edge
97
// objects.
98
// --------------------------------------------------------------------------
99

100   /**
101    * The stack size at the beginning of this basic block.
102    * This size is initially unknown. It is computed by the control flow
103    * analysis algorithm (see {@link CodeWriter#visitMaxs visitMaxs}).
104    */

105
106   int beginStackSize;
107
108   /**
109    * The (relative) maximum stack size corresponding to this basic block. This
110    * size is relative to the stack size at the beginning of the basic block,
111    * i.e., the true maximum stack size is equal to {@link #beginStackSize
112    * beginStackSize} + {@link #maxStackSize maxStackSize}.
113    */

114
115   int maxStackSize;
116
117   /**
118    * The successors of this node in the control flow graph. These successors
119    * are stored in a linked list of {@link Edge Edge} objects, linked to each
120    * other by their {@link Edge#next} field.
121    */

122
123   Edge successors;
124
125   /**
126    * The next basic block in the basic block stack.
127    * See {@link CodeWriter#visitMaxs visitMaxs}.
128    */

129
130   Label next;
131
132   /**
133    * <tt>true</tt> if this basic block has been pushed in the basic block stack.
134    * See {@link CodeWriter#visitMaxs visitMaxs}.
135    */

136
137   boolean pushed;
138
139   // --------------------------------------------------------------------------
140
// Constructor
141
// --------------------------------------------------------------------------
142

143   /**
144    * Constructs a new label.
145    */

146
147   public Label () {
148   }
149
150   // --------------------------------------------------------------------------
151
// Methods to compute offsets and to manage forward references
152
// --------------------------------------------------------------------------
153

154   /**
155    * Returns the offset corresponding to this label. This offset is computed
156    * from the start of the method's bytecode. <i>This method is intended for
157    * {@link Attribute} sub classes, and is normally not needed by class
158    * generators or adapters.</i>
159    *
160    * @return the offset corresponding to this label.
161    * @throws IllegalStateException if this label is not resolved yet.
162    */

163
164   public int getOffset () {
165     if (!resolved) {
166       throw new IllegalStateException JavaDoc(
167         "Label offset position has not been resolved yet");
168     }
169     return position;
170   }
171
172   /**
173    * Puts a reference to this label in the bytecode of a method. If the position
174    * of the label is known, the offset is computed and written directly.
175    * Otherwise, a null offset is written and a new forward reference is declared
176    * for this label.
177    *
178    * @param owner the code writer that calls this method.
179    * @param out the bytecode of the method.
180    * @param source the position of first byte of the bytecode instruction that
181    * contains this label.
182    * @param wideOffset <tt>true</tt> if the reference must be stored in 4 bytes,
183    * or <tt>false</tt> if it must be stored with 2 bytes.
184    * @throws IllegalArgumentException if this label has not been created by the
185    * given code writer.
186    */

187
188   void put (
189     final CodeWriter owner,
190     final ByteVector out,
191     final int source,
192     final boolean wideOffset)
193   {
194     if (CodeWriter.CHECK) {
195       if (this.owner == null) {
196         this.owner = owner;
197       } else if (this.owner != owner) {
198         throw new IllegalArgumentException JavaDoc();
199       }
200     }
201     if (resolved) {
202       if (wideOffset) {
203         out.putInt(position - source);
204       } else {
205         out.putShort(position - source);
206       }
207     } else {
208       if (wideOffset) {
209         addReference(-1 - source, out.length);
210         out.putInt(-1);
211       } else {
212         addReference(source, out.length);
213         out.putShort(-1);
214       }
215     }
216   }
217
218   /**
219    * Adds a forward reference to this label. This method must be called only for
220    * a true forward reference, i.e. only if this label is not resolved yet. For
221    * backward references, the offset of the reference can be, and must be,
222    * computed and stored directly.
223    *
224    * @param sourcePosition the position of the referencing instruction. This
225    * position will be used to compute the offset of this forward reference.
226    * @param referencePosition the position where the offset for this forward
227    * reference must be stored.
228    */

229
230   private void addReference (
231     final int sourcePosition,
232     final int referencePosition)
233   {
234     if (srcAndRefPositions == null) {
235       srcAndRefPositions = new int[6];
236     }
237     if (referenceCount >= srcAndRefPositions.length) {
238       int[] a = new int[srcAndRefPositions.length + 6];
239       System.arraycopy(srcAndRefPositions, 0, a, 0, srcAndRefPositions.length);
240       srcAndRefPositions = a;
241     }
242     srcAndRefPositions[referenceCount++] = sourcePosition;
243     srcAndRefPositions[referenceCount++] = referencePosition;
244   }
245
246   /**
247    * Resolves all forward references to this label. This method must be called
248    * when this label is added to the bytecode of the method, i.e. when its
249    * position becomes known. This method fills in the blanks that where left in
250    * the bytecode by each forward reference previously added to this label.
251    *
252    * @param owner the code writer that calls this method.
253    * @param position the position of this label in the bytecode.
254    * @param data the bytecode of the method.
255    * @return <tt>true</tt> if a blank that was left for this label was to small
256    * to store the offset. In such a case the corresponding jump instruction
257    * is replaced with a pseudo instruction (using unused opcodes) using an
258    * unsigned two bytes offset. These pseudo instructions will need to be
259    * replaced with true instructions with wider offsets (4 bytes instead of
260    * 2). This is done in {@link CodeWriter#resizeInstructions}.
261    * @throws IllegalArgumentException if this label has already been resolved,
262    * or if it has not been created by the given code writer.
263    */

264
265   boolean resolve (
266     final CodeWriter owner,
267     final int position,
268     final byte[] data)
269   {
270     if (CodeWriter.CHECK) {
271       if (this.owner == null) {
272         this.owner = owner;
273       }
274       if (resolved || this.owner != owner) {
275         throw new IllegalArgumentException JavaDoc();
276       }
277     }
278     boolean needUpdate = false;
279     this.resolved = true;
280     this.position = position;
281     int i = 0;
282     while (i < referenceCount) {
283       int source = srcAndRefPositions[i++];
284       int reference = srcAndRefPositions[i++];
285       int offset;
286       if (source >= 0) {
287         offset = position - source;
288         if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
289           // changes the opcode of the jump instruction, in order to be able to
290
// find it later (see resizeInstructions in CodeWriter). These
291
// temporary opcodes are similar to jump instruction opcodes, except
292
// that the 2 bytes offset is unsigned (and can therefore represent
293
// values from 0 to 65535, which is sufficient since the size of a
294
// method is limited to 65535 bytes).
295
int opcode = data[reference - 1] & 0xFF;
296           if (opcode <= Constants.JSR) {
297             // changes IFEQ ... JSR to opcodes 202 to 217 (inclusive)
298
data[reference - 1] = (byte)(opcode + 49);
299           } else {
300             // changes IFNULL and IFNONNULL to opcodes 218 and 219 (inclusive)
301
data[reference - 1] = (byte)(opcode + 20);
302           }
303           needUpdate = true;
304         }
305         data[reference++] = (byte)(offset >>> 8);
306         data[reference] = (byte)offset;
307       } else {
308         offset = position + source + 1;
309         data[reference++] = (byte)(offset >>> 24);
310         data[reference++] = (byte)(offset >>> 16);
311         data[reference++] = (byte)(offset >>> 8);
312         data[reference] = (byte)offset;
313       }
314     }
315     return needUpdate;
316   }
317
318   // --------------------------------------------------------------------------
319
// Overriden Object methods
320
// --------------------------------------------------------------------------
321

322   /**
323    * Returns a string representation of this label.
324    *
325    * @return a string representation of this label.
326    */

327
328   public String JavaDoc toString () {
329     return "L" + System.identityHashCode(this);
330   }
331 }
332
Popular Tags