• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2007 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 org.mockito.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      * Indicates if this label is only used for debug attributes. Such a label
42      * is not the start of a basic block, the target of a jump instruction, or
43      * an exception handler. It can be safely ignored in control flow graph
44      * analysis algorithms (for optimization purposes).
45      */
46     static final int DEBUG = 1;
47 
48     /**
49      * Indicates if the position of this label is known.
50      */
51     static final int RESOLVED = 2;
52 
53     /**
54      * Indicates if this label has been updated, after instruction resizing.
55      */
56     static final int RESIZED = 4;
57 
58     /**
59      * Indicates if this basic block has been pushed in the basic block stack.
60      * See {@link MethodWriter#visitMaxs visitMaxs}.
61      */
62     static final int PUSHED = 8;
63 
64     /**
65      * Indicates if this label is the target of a jump instruction, or the start
66      * of an exception handler.
67      */
68     static final int TARGET = 16;
69 
70     /**
71      * Indicates if a stack map frame must be stored for this label.
72      */
73     static final int STORE = 32;
74 
75     /**
76      * Indicates if this label corresponds to a reachable basic block.
77      */
78     static final int REACHABLE = 64;
79 
80     /**
81      * Indicates if this basic block ends with a JSR instruction.
82      */
83     static final int JSR = 128;
84 
85     /**
86      * Indicates if this basic block ends with a RET instruction.
87      */
88     static final int RET = 256;
89 
90     /**
91      * Indicates if this basic block is the start of a subroutine.
92      */
93     static final int SUBROUTINE = 512;
94 
95     /**
96      * Indicates if this subroutine basic block has been visited.
97      */
98     static final int VISITED = 1024;
99 
100     /**
101      * Field used to associate user information to a label. Warning: this field
102      * is used by the ASM tree package. In order to use it with the ASM tree
103      * package you must override the {@link
104      * org.mockito.asm.tree.MethodNode#getLabelNode} method.
105      */
106     public Object info;
107 
108     /**
109      * Flags that indicate the status of this label.
110      *
111      * @see #DEBUG
112      * @see #RESOLVED
113      * @see #RESIZED
114      * @see #PUSHED
115      * @see #TARGET
116      * @see #STORE
117      * @see #REACHABLE
118      * @see #JSR
119      * @see #RET
120      */
121     int status;
122 
123     /**
124      * The line number corresponding to this label, if known.
125      */
126     int line;
127 
128     /**
129      * The position of this label in the code, if known.
130      */
131     int position;
132 
133     /**
134      * Number of forward references to this label, times two.
135      */
136     private int referenceCount;
137 
138     /**
139      * Informations about forward references. Each forward reference is
140      * described by two consecutive integers in this array: the first one is the
141      * position of the first byte of the bytecode instruction that contains the
142      * forward reference, while the second is the position of the first byte of
143      * the forward reference itself. In fact the sign of the first integer
144      * indicates if this reference uses 2 or 4 bytes, and its absolute value
145      * gives the position of the bytecode instruction. This array is also used
146      * as a bitset to store the subroutines to which a basic block belongs. This
147      * information is needed in {@linked  MethodWriter#visitMaxs}, after all
148      * forward references have been resolved. Hence the same array can be used
149      * for both purposes without problems.
150      */
151     private int[] srcAndRefPositions;
152 
153     // ------------------------------------------------------------------------
154 
155     /*
156      * Fields for the control flow and data flow graph analysis algorithms (used
157      * to compute the maximum stack size or the stack map frames). A control
158      * flow graph contains one node per "basic block", and one edge per "jump"
159      * from one basic block to another. Each node (i.e., each basic block) is
160      * represented by the Label object that corresponds to the first instruction
161      * of this basic block. Each node also stores the list of its successors in
162      * the graph, as a linked list of Edge objects.
163      *
164      * The control flow analysis algorithms used to compute the maximum stack
165      * size or the stack map frames are similar and use two steps. The first
166      * step, during the visit of each instruction, builds information about the
167      * state of the local variables and the operand stack at the end of each
168      * basic block, called the "output frame", <i>relatively</i> to the frame
169      * state at the beginning of the basic block, which is called the "input
170      * frame", and which is <i>unknown</i> during this step. The second step,
171      * in {@link MethodWriter#visitMaxs}, is a fix point algorithm that
172      * computes information about the input frame of each basic block, from the
173      * input state of the first basic block (known from the method signature),
174      * and by the using the previously computed relative output frames.
175      *
176      * The algorithm used to compute the maximum stack size only computes the
177      * relative output and absolute input stack heights, while the algorithm
178      * used to compute stack map frames computes relative output frames and
179      * absolute input frames.
180      */
181 
182     /**
183      * Start of the output stack relatively to the input stack. The exact
184      * semantics of this field depends on the algorithm that is used.
185      *
186      * When only the maximum stack size is computed, this field is the number of
187      * elements in the input stack.
188      *
189      * When the stack map frames are completely computed, this field is the
190      * offset of the first output stack element relatively to the top of the
191      * input stack. This offset is always negative or null. A null offset means
192      * that the output stack must be appended to the input stack. A -n offset
193      * means that the first n output stack elements must replace the top n input
194      * stack elements, and that the other elements must be appended to the input
195      * stack.
196      */
197     int inputStackTop;
198 
199     /**
200      * Maximum height reached by the output stack, relatively to the top of the
201      * input stack. This maximum is always positive or null.
202      */
203     int outputStackMax;
204 
205     /**
206      * Information about the input and output stack map frames of this basic
207      * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES}
208      * option is used.
209      */
210     Frame frame;
211 
212     /**
213      * The successor of this label, in the order they are visited. This linked
214      * list does not include labels used for debug info only. If
215      * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it
216      * does not contain successive labels that denote the same bytecode position
217      * (in this case only the first label appears in this list).
218      */
219     Label successor;
220 
221     /**
222      * The successors of this node in the control flow graph. These successors
223      * are stored in a linked list of {@link Edge Edge} objects, linked to each
224      * other by their {@link Edge#next} field.
225      */
226     Edge successors;
227 
228     /**
229      * The next basic block in the basic block stack. This stack is used in the
230      * main loop of the fix point algorithm used in the second step of the
231      * control flow analysis algorithms.
232      *
233      * @see MethodWriter#visitMaxs
234      */
235     Label next;
236 
237     // ------------------------------------------------------------------------
238     // Constructor
239     // ------------------------------------------------------------------------
240 
241     /**
242      * Constructs a new label.
243      */
Label()244     public Label() {
245     }
246 
247     // ------------------------------------------------------------------------
248     // Methods to compute offsets and to manage forward references
249     // ------------------------------------------------------------------------
250 
251     /**
252      * Returns the offset corresponding to this label. This offset is computed
253      * from the start of the method's bytecode. <i>This method is intended for
254      * {@link Attribute} sub classes, and is normally not needed by class
255      * generators or adapters.</i>
256      *
257      * @return the offset corresponding to this label.
258      * @throws IllegalStateException if this label is not resolved yet.
259      */
getOffset()260     public int getOffset() {
261         if ((status & RESOLVED) == 0) {
262             throw new IllegalStateException("Label offset position has not been resolved yet");
263         }
264         return position;
265     }
266 
267     /**
268      * Puts a reference to this label in the bytecode of a method. If the
269      * position of the label is known, the offset is computed and written
270      * directly. Otherwise, a null offset is written and a new forward reference
271      * is declared for this label.
272      *
273      * @param owner the code writer that calls this method.
274      * @param out the bytecode of the method.
275      * @param source the position of first byte of the bytecode instruction that
276      *        contains this label.
277      * @param wideOffset <tt>true</tt> if the reference must be stored in 4
278      *        bytes, or <tt>false</tt> if it must be stored with 2 bytes.
279      * @throws IllegalArgumentException if this label has not been created by
280      *         the given code writer.
281      */
put( final MethodWriter owner, final ByteVector out, final int source, final boolean wideOffset)282     void put(
283         final MethodWriter owner,
284         final ByteVector out,
285         final int source,
286         final boolean wideOffset)
287     {
288         if ((status & RESOLVED) == 0) {
289             if (wideOffset) {
290                 addReference(-1 - source, out.length);
291                 out.putInt(-1);
292             } else {
293                 addReference(source, out.length);
294                 out.putShort(-1);
295             }
296         } else {
297             if (wideOffset) {
298                 out.putInt(position - source);
299             } else {
300                 out.putShort(position - source);
301             }
302         }
303     }
304 
305     /**
306      * Adds a forward reference to this label. This method must be called only
307      * for a true forward reference, i.e. only if this label is not resolved
308      * yet. For backward references, the offset of the reference can be, and
309      * must be, computed and stored directly.
310      *
311      * @param sourcePosition the position of the referencing instruction. This
312      *        position will be used to compute the offset of this forward
313      *        reference.
314      * @param referencePosition the position where the offset for this forward
315      *        reference must be stored.
316      */
addReference( final int sourcePosition, final int referencePosition)317     private void addReference(
318         final int sourcePosition,
319         final int referencePosition)
320     {
321         if (srcAndRefPositions == null) {
322             srcAndRefPositions = new int[6];
323         }
324         if (referenceCount >= srcAndRefPositions.length) {
325             int[] a = new int[srcAndRefPositions.length + 6];
326             System.arraycopy(srcAndRefPositions,
327                     0,
328                     a,
329                     0,
330                     srcAndRefPositions.length);
331             srcAndRefPositions = a;
332         }
333         srcAndRefPositions[referenceCount++] = sourcePosition;
334         srcAndRefPositions[referenceCount++] = referencePosition;
335     }
336 
337     /**
338      * Resolves all forward references to this label. This method must be called
339      * when this label is added to the bytecode of the method, i.e. when its
340      * position becomes known. This method fills in the blanks that where left
341      * in the bytecode by each forward reference previously added to this label.
342      *
343      * @param owner the code writer that calls this method.
344      * @param position the position of this label in the bytecode.
345      * @param data the bytecode of the method.
346      * @return <tt>true</tt> if a blank that was left for this label was to
347      *         small to store the offset. In such a case the corresponding jump
348      *         instruction is replaced with a pseudo instruction (using unused
349      *         opcodes) using an unsigned two bytes offset. These pseudo
350      *         instructions will need to be replaced with true instructions with
351      *         wider offsets (4 bytes instead of 2). This is done in
352      *         {@link MethodWriter#resizeInstructions}.
353      * @throws IllegalArgumentException if this label has already been resolved,
354      *         or if it has not been created by the given code writer.
355      */
resolve( final MethodWriter owner, final int position, final byte[] data)356     boolean resolve(
357         final MethodWriter owner,
358         final int position,
359         final byte[] data)
360     {
361         boolean needUpdate = false;
362         this.status |= RESOLVED;
363         this.position = position;
364         int i = 0;
365         while (i < referenceCount) {
366             int source = srcAndRefPositions[i++];
367             int reference = srcAndRefPositions[i++];
368             int offset;
369             if (source >= 0) {
370                 offset = position - source;
371                 if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
372                     /*
373                      * changes the opcode of the jump instruction, in order to
374                      * be able to find it later (see resizeInstructions in
375                      * MethodWriter). These temporary opcodes are similar to
376                      * jump instruction opcodes, except that the 2 bytes offset
377                      * is unsigned (and can therefore represent values from 0 to
378                      * 65535, which is sufficient since the size of a method is
379                      * limited to 65535 bytes).
380                      */
381                     int opcode = data[reference - 1] & 0xFF;
382                     if (opcode <= Opcodes.JSR) {
383                         // changes IFEQ ... JSR to opcodes 202 to 217
384                         data[reference - 1] = (byte) (opcode + 49);
385                     } else {
386                         // changes IFNULL and IFNONNULL to opcodes 218 and 219
387                         data[reference - 1] = (byte) (opcode + 20);
388                     }
389                     needUpdate = true;
390                 }
391                 data[reference++] = (byte) (offset >>> 8);
392                 data[reference] = (byte) offset;
393             } else {
394                 offset = position + source + 1;
395                 data[reference++] = (byte) (offset >>> 24);
396                 data[reference++] = (byte) (offset >>> 16);
397                 data[reference++] = (byte) (offset >>> 8);
398                 data[reference] = (byte) offset;
399             }
400         }
401         return needUpdate;
402     }
403 
404     /**
405      * Returns the first label of the series to which this label belongs. For an
406      * isolated label or for the first label in a series of successive labels,
407      * this method returns the label itself. For other labels it returns the
408      * first label of the series.
409      *
410      * @return the first label of the series to which this label belongs.
411      */
getFirst()412     Label getFirst() {
413         return !ClassReader.FRAMES || frame == null ? this : frame.owner;
414     }
415 
416     // ------------------------------------------------------------------------
417     // Methods related to subroutines
418     // ------------------------------------------------------------------------
419 
420     /**
421      * Returns true is this basic block belongs to the given subroutine.
422      *
423      * @param id a subroutine id.
424      * @return true is this basic block belongs to the given subroutine.
425      */
inSubroutine(final long id)426     boolean inSubroutine(final long id) {
427         if ((status & Label.VISITED) != 0) {
428             return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
429         }
430         return false;
431     }
432 
433     /**
434      * Returns true if this basic block and the given one belong to a common
435      * subroutine.
436      *
437      * @param block another basic block.
438      * @return true if this basic block and the given one belong to a common
439      *         subroutine.
440      */
inSameSubroutine(final Label block)441     boolean inSameSubroutine(final Label block) {
442         for (int i = 0; i < srcAndRefPositions.length; ++i) {
443             if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
444                 return true;
445             }
446         }
447         return false;
448     }
449 
450     /**
451      * Marks this basic block as belonging to the given subroutine.
452      *
453      * @param id a subroutine id.
454      * @param nbSubroutines the total number of subroutines in the method.
455      */
addToSubroutine(final long id, final int nbSubroutines)456     void addToSubroutine(final long id, final int nbSubroutines) {
457         if ((status & VISITED) == 0) {
458             status |= VISITED;
459             srcAndRefPositions = new int[(nbSubroutines - 1) / 32 + 1];
460         }
461         srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
462     }
463 
464     /**
465      * Finds the basic blocks that belong to a given subroutine, and marks these
466      * blocks as belonging to this subroutine. This recursive method follows the
467      * control flow graph to find all the blocks that are reachable from the
468      * current block WITHOUT following any JSR target.
469      *
470      * @param JSR a JSR block that jumps to this subroutine. If this JSR is not
471      *        null it is added to the successor of the RET blocks found in the
472      *        subroutine.
473      * @param id the id of this subroutine.
474      * @param nbSubroutines the total number of subroutines in the method.
475      */
visitSubroutine(final Label JSR, final long id, final int nbSubroutines)476     void visitSubroutine(final Label JSR, final long id, final int nbSubroutines)
477     {
478         if (JSR != null) {
479             if ((status & VISITED) != 0) {
480                 return;
481             }
482             status |= VISITED;
483             // adds JSR to the successors of this block, if it is a RET block
484             if ((status & RET) != 0) {
485                 if (!inSameSubroutine(JSR)) {
486                     Edge e = new Edge();
487                     e.info = inputStackTop;
488                     e.successor = JSR.successors.successor;
489                     e.next = successors;
490                     successors = e;
491                 }
492             }
493         } else {
494             // if this block already belongs to subroutine 'id', returns
495             if (inSubroutine(id)) {
496                 return;
497             }
498             // marks this block as belonging to subroutine 'id'
499             addToSubroutine(id, nbSubroutines);
500         }
501         // calls this method recursively on each successor, except JSR targets
502         Edge e = successors;
503         while (e != null) {
504             // if this block is a JSR block, then 'successors.next' leads
505             // to the JSR target (see {@link #visitJumpInsn}) and must therefore
506             // not be followed
507             if ((status & Label.JSR) == 0 || e != successors.next) {
508                 e.successor.visitSubroutine(JSR, id, nbSubroutines);
509             }
510             e = e.next;
511         }
512     }
513 
514     // ------------------------------------------------------------------------
515     // Overriden Object methods
516     // ------------------------------------------------------------------------
517 
518     /**
519      * Returns a string representation of this label.
520      *
521      * @return a string representation of this label.
522      */
toString()523     public String toString() {
524         return "L" + System.identityHashCode(this);
525     }
526 }
527