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