KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > 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  * Contact: Eric.Bruneton@rd.francetelecom.com
31  *
32  * Author: Eric Bruneton
33  */

34
35 package org.logicalcobwebs.asm;
36
37 /**
38  * A label represents a position in the bytecode of a method. Labels are used
39  * for jump, goto, and switch instructions, and for try catch blocks.
40  */

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

47
48   CodeWriter owner;
49
50   /**
51    * Indicates if the position of this label is known.
52    */

53
54   boolean resolved;
55
56   /**
57    * The position of this label in the code, if known.
58    */

59
60   int position;
61
62   /**
63    * Number of forward references to this label, times two.
64    */

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

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

90   /**
91    * The stack size at the beginning of this basic block.
92    * This size is initially unknown. It is computed by the control flow
93    * analysis algorithm (see {@link CodeWriter#visitMaxs visitMaxs}).
94    */

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

104
105   int maxStackSize;
106
107   /**
108    * The successors of this node in the control flow graph. These successors
109    * are stored in a linked list of {@link Edge Edge} objects, linked to each
110    * other by their {@link Edge#next} field.
111    */

112
113   Edge successors;
114
115   /**
116    * The next basic block in the basic block stack.
117    * See {@link CodeWriter#visitMaxs visitMaxs}.
118    */

119
120   Label next;
121
122   /**
123    * <tt>true</tt> if this basic block has been pushed in the basic block stack.
124    * See {@link CodeWriter#visitMaxs visitMaxs}.
125    */

126
127   boolean pushed;
128
129   // --------------------------------------------------------------------------
130
// Constructor
131
// --------------------------------------------------------------------------
132

133   /**
134    * Constructs a new label.
135    */

136
137   public Label () {
138   }
139
140   // --------------------------------------------------------------------------
141
// Methods to compute offsets and to manage forward references
142
// --------------------------------------------------------------------------
143

144   /**
145    * Puts a reference to this label in the bytecode of a method. If the position
146    * of the label is known, the offset is computed and written directly.
147    * Otherwise, a null offset is written and a new forward reference is declared
148    * for this label.
149    *
150    * @param owner the code writer that calls this method.
151    * @param out the bytecode of the method.
152    * @param source the position of first byte of the bytecode instruction that
153    * contains this label.
154    * @param wideOffset <tt>true</tt> if the reference must be stored in 4 bytes,
155    * or <tt>false</tt> if it must be stored with 2 bytes.
156    * @throws IllegalArgumentException if this label has not been created by the
157    * given code writer.
158    */

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

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

236
237   boolean resolve (
238     final CodeWriter owner,
239     final int position,
240     final byte[] data)
241   {
242     if (CodeWriter.CHECK) {
243       if (this.owner == null) {
244         this.owner = owner;
245       }
246       if (resolved || this.owner != owner) {
247         throw new IllegalArgumentException JavaDoc();
248       }
249     }
250     boolean needUpdate = false;
251     this.resolved = true;
252     this.position = position;
253     int i = 0;
254     while (i < referenceCount) {
255       int source = srcAndRefPositions[i++];
256       int reference = srcAndRefPositions[i++];
257       int offset;
258       if (source >= 0) {
259         offset = position - source;
260         if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
261           // changes the opcode of the jump instruction, in order to be able to
262
// find it later (see resizeInstructions in CodeWriter). These
263
// temporary opcodes are similar to jump instruction opcodes, except
264
// that the 2 bytes offset is unsigned (and can therefore represent
265
// values from 0 to 65535, which is sufficient since the size of a
266
// method is limited to 65535 bytes).
267
int opcode = data[reference - 1] & 0xFF;
268           if (opcode <= Constants.JSR) {
269             // changes IFEQ ... JSR to opcodes 202 to 217 (inclusive)
270
data[reference - 1] = (byte)(opcode + 49);
271           } else {
272             // changes IFNULL and IFNONNULL to opcodes 218 and 219 (inclusive)
273
data[reference - 1] = (byte)(opcode + 20);
274           }
275           needUpdate = true;
276         }
277         data[reference++] = (byte)(offset >>> 8);
278         data[reference] = (byte)offset;
279       } else {
280         offset = position + source + 1;
281         data[reference++] = (byte)(offset >>> 24);
282         data[reference++] = (byte)(offset >>> 16);
283         data[reference++] = (byte)(offset >>> 8);
284         data[reference] = (byte)offset;
285       }
286     }
287     return needUpdate;
288   }
289 }
290
Popular Tags