001/*** 002 * ASM: a very small and fast Java bytecode manipulation framework 003 * Copyright (c) 2000-2011 INRIA, France Telecom 004 * All rights reserved. 005 * 006 * Redistribution and use in source and binary forms, with or without 007 * modification, are permitted provided that the following conditions 008 * are met: 009 * 1. Redistributions of source code must retain the above copyright 010 * notice, this list of conditions and the following disclaimer. 011 * 2. Redistributions in binary form must reproduce the above copyright 012 * notice, this list of conditions and the following disclaimer in the 013 * documentation and/or other materials provided with the distribution. 014 * 3. Neither the name of the copyright holders nor the names of its 015 * contributors may be used to endorse or promote products derived from 016 * this software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 028 * THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package io.ebean.enhance.asm; 031 032import io.ebean.enhance.asm.tree.MethodNode; 033 034/** 035 * A label represents a position in the bytecode of a method. Labels are used 036 * for jump, goto, and switch instructions, and for try catch blocks. A label 037 * designates the <i>instruction</i> that is just after. Note however that there 038 * can be other elements between a label and the instruction it designates (such 039 * as other labels, stack map frames, line numbers, etc.). 040 * 041 * @author Eric Bruneton 042 */ 043public class Label { 044 045 /** 046 * Indicates if this label is only used for debug attributes. Such a label 047 * is not the start of a basic block, the target of a jump instruction, or 048 * an exception handler. It can be safely ignored in control flow graph 049 * analysis algorithms (for optimization purposes). 050 */ 051 static final int DEBUG = 1; 052 053 /** 054 * Indicates if the position of this label is known. 055 */ 056 static final int RESOLVED = 2; 057 058 /** 059 * Indicates if this label has been updated, after instruction resizing. 060 */ 061 static final int RESIZED = 4; 062 063 /** 064 * Indicates if this basic block has been pushed in the basic block stack. 065 * See {@link MethodWriter#visitMaxs visitMaxs}. 066 */ 067 static final int PUSHED = 8; 068 069 /** 070 * Indicates if this label is the target of a jump instruction, or the start 071 * of an exception handler. 072 */ 073 static final int TARGET = 16; 074 075 /** 076 * Indicates if a stack map frame must be stored for this label. 077 */ 078 static final int STORE = 32; 079 080 /** 081 * Indicates if this label corresponds to a reachable basic block. 082 */ 083 static final int REACHABLE = 64; 084 085 /** 086 * Indicates if this basic block ends with a JSR instruction. 087 */ 088 static final int JSR = 128; 089 090 /** 091 * Indicates if this basic block ends with a RET instruction. 092 */ 093 static final int RET = 256; 094 095 /** 096 * Indicates if this basic block is the start of a subroutine. 097 */ 098 static final int SUBROUTINE = 512; 099 100 /** 101 * Indicates if this subroutine basic block has been visited by a 102 * visitSubroutine(null, ...) call. 103 */ 104 static final int VISITED = 1024; 105 106 /** 107 * Indicates if this subroutine basic block has been visited by a 108 * visitSubroutine(!null, ...) call. 109 */ 110 static final int VISITED2 = 2048; 111 112 /** 113 * Field used to associate user information to a label. Warning: this field 114 * is used by the ASM tree package. In order to use it with the ASM tree 115 * package you must override the 116 * {@link MethodNode#getLabelNode} method. 117 */ 118 public Object info; 119 120 /** 121 * Flags that indicate the status of this label. 122 * 123 * @see #DEBUG 124 * @see #RESOLVED 125 * @see #RESIZED 126 * @see #PUSHED 127 * @see #TARGET 128 * @see #STORE 129 * @see #REACHABLE 130 * @see #JSR 131 * @see #RET 132 */ 133 int status; 134 135 /** 136 * The line number corresponding to this label, if known. If there are 137 * several lines, each line is stored in a separate label, all linked via 138 * their next field (these links are created in ClassReader and removed just 139 * before visitLabel is called, so that this does not impact the rest of the 140 * code). 141 */ 142 int line; 143 144 /** 145 * The position of this label in the code, if known. 146 */ 147 int position; 148 149 /** 150 * Number of forward references to this label, times two. 151 */ 152 private int referenceCount; 153 154 /** 155 * Informations about forward references. Each forward reference is 156 * described by two consecutive integers in this array: the first one is the 157 * position of the first byte of the bytecode instruction that contains the 158 * forward reference, while the second is the position of the first byte of 159 * the forward reference itself. In fact the sign of the first integer 160 * indicates if this reference uses 2 or 4 bytes, and its absolute value 161 * gives the position of the bytecode instruction. This array is also used 162 * as a bitset to store the subroutines to which a basic block belongs. This 163 * information is needed in {@linked MethodWriter#visitMaxs}, after all 164 * forward references have been resolved. Hence the same array can be used 165 * for both purposes without problems. 166 */ 167 private int[] srcAndRefPositions; 168 169 // ------------------------------------------------------------------------ 170 171 /* 172 * Fields for the control flow and data flow graph analysis algorithms (used 173 * to compute the maximum stack size or the stack map frames). A control 174 * flow graph contains one node per "basic block", and one edge per "jump" 175 * from one basic block to another. Each node (i.e., each basic block) is 176 * represented by the Label object that corresponds to the first instruction 177 * of this basic block. Each node also stores the list of its successors in 178 * the graph, as a linked list of Edge objects. 179 * 180 * The control flow analysis algorithms used to compute the maximum stack 181 * size or the stack map frames are similar and use two steps. The first 182 * step, during the visit of each instruction, builds information about the 183 * state of the local variables and the operand stack at the end of each 184 * basic block, called the "output frame", <i>relatively</i> to the frame 185 * state at the beginning of the basic block, which is called the "input 186 * frame", and which is <i>unknown</i> during this step. The second step, in 187 * {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes 188 * information about the input frame of each basic block, from the input 189 * state of the first basic block (known from the method signature), and by 190 * the using the previously computed relative output frames. 191 * 192 * The algorithm used to compute the maximum stack size only computes the 193 * relative output and absolute input stack heights, while the algorithm 194 * used to compute stack map frames computes relative output frames and 195 * absolute input frames. 196 */ 197 198 /** 199 * Start of the output stack relatively to the input stack. The exact 200 * semantics of this field depends on the algorithm that is used. 201 * 202 * When only the maximum stack size is computed, this field is the number of 203 * elements in the input stack. 204 * 205 * When the stack map frames are completely computed, this field is the 206 * offset of the first output stack element relatively to the top of the 207 * input stack. This offset is always negative or null. A null offset means 208 * that the output stack must be appended to the input stack. A -n offset 209 * means that the first n output stack elements must replace the top n input 210 * stack elements, and that the other elements must be appended to the input 211 * stack. 212 */ 213 int inputStackTop; 214 215 /** 216 * Maximum height reached by the output stack, relatively to the top of the 217 * input stack. This maximum is always positive or null. 218 */ 219 int outputStackMax; 220 221 /** 222 * Information about the input and output stack map frames of this basic 223 * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES} 224 * option is used. 225 */ 226 Frame frame; 227 228 /** 229 * The successor of this label, in the order they are visited. This linked 230 * list does not include labels used for debug info only. If 231 * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it 232 * does not contain successive labels that denote the same bytecode position 233 * (in this case only the first label appears in this list). 234 */ 235 Label successor; 236 237 /** 238 * The successors of this node in the control flow graph. These successors 239 * are stored in a linked list of {@link Edge Edge} objects, linked to each 240 * other by their {@link Edge#next} field. 241 */ 242 Edge successors; 243 244 /** 245 * The next basic block in the basic block stack. This stack is used in the 246 * main loop of the fix point algorithm used in the second step of the 247 * control flow analysis algorithms. It is also used in 248 * {@link #visitSubroutine} to avoid using a recursive method, and in 249 * ClassReader to temporarily store multiple source lines for a label. 250 * 251 * @see MethodWriter#visitMaxs 252 */ 253 Label next; 254 255 // ------------------------------------------------------------------------ 256 // Constructor 257 // ------------------------------------------------------------------------ 258 259 /** 260 * Constructs a new label. 261 */ 262 public Label() { 263 } 264 265 // ------------------------------------------------------------------------ 266 // Methods to compute offsets and to manage forward references 267 // ------------------------------------------------------------------------ 268 269 /** 270 * Returns the offset corresponding to this label. This offset is computed 271 * from the start of the method's bytecode. <i>This method is intended for 272 * {@link Attribute} sub classes, and is normally not needed by class 273 * generators or adapters.</i> 274 * 275 * @return the offset corresponding to this label. 276 * @throws IllegalStateException 277 * if this label is not resolved yet. 278 */ 279 public int getOffset() { 280 if ((status & RESOLVED) == 0) { 281 throw new IllegalStateException( 282 "Label offset position has not been resolved yet"); 283 } 284 return position; 285 } 286 287 /** 288 * Puts a reference to this label in the bytecode of a method. If the 289 * position of the label is known, the offset is computed and written 290 * directly. Otherwise, a null offset is written and a new forward reference 291 * is declared for this label. 292 * 293 * @param owner 294 * the code writer that calls this method. 295 * @param out 296 * the bytecode of the method. 297 * @param source 298 * the position of first byte of the bytecode instruction that 299 * contains this label. 300 * @param wideOffset 301 * <tt>true</tt> if the reference must be stored in 4 bytes, or 302 * <tt>false</tt> if it must be stored with 2 bytes. 303 * @throws IllegalArgumentException 304 * if this label has not been created by the given code writer. 305 */ 306 void put(final MethodWriter owner, final ByteVector out, final int source, 307 final boolean wideOffset) { 308 if ((status & RESOLVED) == 0) { 309 if (wideOffset) { 310 addReference(-1 - source, out.length); 311 out.putInt(-1); 312 } else { 313 addReference(source, out.length); 314 out.putShort(-1); 315 } 316 } else { 317 if (wideOffset) { 318 out.putInt(position - source); 319 } else { 320 out.putShort(position - source); 321 } 322 } 323 } 324 325 /** 326 * Adds a forward reference to this label. This method must be called only 327 * for a true forward reference, i.e. only if this label is not resolved 328 * yet. For backward references, the offset of the reference can be, and 329 * must be, computed and stored directly. 330 * 331 * @param sourcePosition 332 * the position of the referencing instruction. This position 333 * will be used to compute the offset of this forward reference. 334 * @param referencePosition 335 * the position where the offset for this forward reference must 336 * be stored. 337 */ 338 private void addReference(final int sourcePosition, 339 final int referencePosition) { 340 if (srcAndRefPositions == null) { 341 srcAndRefPositions = new int[6]; 342 } 343 if (referenceCount >= srcAndRefPositions.length) { 344 int[] a = new int[srcAndRefPositions.length + 6]; 345 System.arraycopy(srcAndRefPositions, 0, a, 0, 346 srcAndRefPositions.length); 347 srcAndRefPositions = a; 348 } 349 srcAndRefPositions[referenceCount++] = sourcePosition; 350 srcAndRefPositions[referenceCount++] = referencePosition; 351 } 352 353 /** 354 * Resolves all forward references to this label. This method must be called 355 * when this label is added to the bytecode of the method, i.e. when its 356 * position becomes known. This method fills in the blanks that where left 357 * in the bytecode by each forward reference previously added to this label. 358 * 359 * @param owner 360 * the code writer that calls this method. 361 * @param position 362 * the position of this label in the bytecode. 363 * @param data 364 * the bytecode of the method. 365 * @return <tt>true</tt> if a blank that was left for this label was too 366 * small to store the offset. In such a case the corresponding jump 367 * instruction is replaced with a pseudo instruction (using unused 368 * opcodes) using an unsigned two bytes offset. These pseudo 369 * instructions will be replaced with standard bytecode instructions 370 * with wider offsets (4 bytes instead of 2), in ClassReader. 371 * @throws IllegalArgumentException 372 * if this label has already been resolved, or if it has not 373 * been created by the given code writer. 374 */ 375 boolean resolve(final MethodWriter owner, final int position, 376 final byte[] data) { 377 boolean needUpdate = false; 378 this.status |= RESOLVED; 379 this.position = position; 380 int i = 0; 381 while (i < referenceCount) { 382 int source = srcAndRefPositions[i++]; 383 int reference = srcAndRefPositions[i++]; 384 int offset; 385 if (source >= 0) { 386 offset = position - source; 387 if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) { 388 /* 389 * changes the opcode of the jump instruction, in order to 390 * be able to find it later (see resizeInstructions in 391 * MethodWriter). These temporary opcodes are similar to 392 * jump instruction opcodes, except that the 2 bytes offset 393 * is unsigned (and can therefore represent values from 0 to 394 * 65535, which is sufficient since the size of a method is 395 * limited to 65535 bytes). 396 */ 397 int opcode = data[reference - 1] & 0xFF; 398 if (opcode <= Opcodes.JSR) { 399 // changes IFEQ ... JSR to opcodes 202 to 217 400 data[reference - 1] = (byte) (opcode + 49); 401 } else { 402 // changes IFNULL and IFNONNULL to opcodes 218 and 219 403 data[reference - 1] = (byte) (opcode + 20); 404 } 405 needUpdate = true; 406 } 407 data[reference++] = (byte) (offset >>> 8); 408 data[reference] = (byte) offset; 409 } else { 410 offset = position + source + 1; 411 data[reference++] = (byte) (offset >>> 24); 412 data[reference++] = (byte) (offset >>> 16); 413 data[reference++] = (byte) (offset >>> 8); 414 data[reference] = (byte) offset; 415 } 416 } 417 return needUpdate; 418 } 419 420 /** 421 * Returns the first label of the series to which this label belongs. For an 422 * isolated label or for the first label in a series of successive labels, 423 * this method returns the label itself. For other labels it returns the 424 * first label of the series. 425 * 426 * @return the first label of the series to which this label belongs. 427 */ 428 Label getFirst() { 429 return frame == null ? this : frame.owner; 430 } 431 432 // ------------------------------------------------------------------------ 433 // Methods related to subroutines 434 // ------------------------------------------------------------------------ 435 436 /** 437 * Returns true is this basic block belongs to the given subroutine. 438 * 439 * @param id 440 * a subroutine id. 441 * @return true is this basic block belongs to the given subroutine. 442 */ 443 boolean inSubroutine(final long id) { 444 if ((status & Label.VISITED) != 0) { 445 return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0; 446 } 447 return false; 448 } 449 450 /** 451 * Returns true if this basic block and the given one belong to a common 452 * subroutine. 453 * 454 * @param block 455 * another basic block. 456 * @return true if this basic block and the given one belong to a common 457 * subroutine. 458 */ 459 boolean inSameSubroutine(final Label block) { 460 if ((status & VISITED) == 0 || (block.status & VISITED) == 0) { 461 return false; 462 } 463 for (int i = 0; i < srcAndRefPositions.length; ++i) { 464 if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) { 465 return true; 466 } 467 } 468 return false; 469 } 470 471 /** 472 * Marks this basic block as belonging to the given subroutine. 473 * 474 * @param id 475 * a subroutine id. 476 * @param nbSubroutines 477 * the total number of subroutines in the method. 478 */ 479 void addToSubroutine(final long id, final int nbSubroutines) { 480 if ((status & VISITED) == 0) { 481 status |= VISITED; 482 srcAndRefPositions = new int[nbSubroutines / 32 + 1]; 483 } 484 srcAndRefPositions[(int) (id >>> 32)] |= (int) id; 485 } 486 487 /** 488 * Finds the basic blocks that belong to a given subroutine, and marks these 489 * blocks as belonging to this subroutine. This method follows the control 490 * flow graph to find all the blocks that are reachable from the current 491 * block WITHOUT following any JSR target. 492 * 493 * @param JSR 494 * a JSR block that jumps to this subroutine. If this JSR is not 495 * null it is added to the successor of the RET blocks found in 496 * the subroutine. 497 * @param id 498 * the id of this subroutine. 499 * @param nbSubroutines 500 * the total number of subroutines in the method. 501 */ 502 void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) { 503 // user managed stack of labels, to avoid using a recursive method 504 // (recursivity can lead to stack overflow with very large methods) 505 Label stack = this; 506 while (stack != null) { 507 // removes a label l from the stack 508 Label l = stack; 509 stack = l.next; 510 l.next = null; 511 512 if (JSR != null) { 513 if ((l.status & VISITED2) != 0) { 514 continue; 515 } 516 l.status |= VISITED2; 517 // adds JSR to the successors of l, if it is a RET block 518 if ((l.status & RET) != 0) { 519 if (!l.inSameSubroutine(JSR)) { 520 Edge e = new Edge(); 521 e.info = l.inputStackTop; 522 e.successor = JSR.successors.successor; 523 e.next = l.successors; 524 l.successors = e; 525 } 526 } 527 } else { 528 // if the l block already belongs to subroutine 'id', continue 529 if (l.inSubroutine(id)) { 530 continue; 531 } 532 // marks the l block as belonging to subroutine 'id' 533 l.addToSubroutine(id, nbSubroutines); 534 } 535 // pushes each successor of l on the stack, except JSR targets 536 Edge e = l.successors; 537 while (e != null) { 538 // if the l block is a JSR block, then 'l.successors.next' leads 539 // to the JSR target (see {@link #visitJumpInsn}) and must 540 // therefore not be followed 541 if ((l.status & Label.JSR) == 0 || e != l.successors.next) { 542 // pushes e.successor on the stack if it not already added 543 if (e.successor.next == null) { 544 e.successor.next = stack; 545 stack = e.successor; 546 } 547 } 548 e = e.next; 549 } 550 } 551 } 552 553 // ------------------------------------------------------------------------ 554 // Overriden Object methods 555 // ------------------------------------------------------------------------ 556 557 /** 558 * Returns a string representation of this label. 559 * 560 * @return a string representation of this label. 561 */ 562 @Override 563 public String toString() { 564 return "L" + System.identityHashCode(this); 565 } 566}