1 /*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2005 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.objectweb.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 * The line number corresponding to this label, if known. 42 */ 43 int line; 44 45 /** 46 * Indicates if the position of this label is known. 47 */ 48 boolean resolved; 49 50 /** 51 * The position of this label in the code, if known. 52 */ 53 int position; 54 55 /** 56 * If the label position has been updated, after instruction resizing. 57 */ 58 boolean resized; 59 60 /** 61 * Number of forward references to this label, times two. 62 */ 63 private int referenceCount; 64 65 /** 66 * Informations about forward references. Each forward reference is 67 * described by two consecutive integers in this array: the first one is the 68 * position of the first byte of the bytecode instruction that contains the 69 * forward reference, while the second is the position of the first byte of 70 * the forward reference itself. In fact the sign of the first integer 71 * indicates if this reference uses 2 or 4 bytes, and its absolute value 72 * gives the position of the bytecode instruction. 73 */ 74 private int[] srcAndRefPositions; 75 76 /* 77 * Fields for the control flow graph analysis algorithm (used to compute the 78 * maximum stack size). A control flow graph contains one node per "basic 79 * block", and one edge per "jump" from one basic block to another. Each 80 * node (i.e., each basic block) is represented by the Label object that 81 * corresponds to the first instruction of this basic block. Each node also 82 * stores the list of it successors in the graph, as a linked list of Edge 83 * objects. 84 */ 85 86 /** 87 * The stack size at the beginning of this basic block. This size is 88 * initially unknown. It is computed by the control flow analysis algorithm 89 * (see {@link MethodWriter#visitMaxs visitMaxs}). 90 */ 91 int beginStackSize; 92 93 /** 94 * The (relative) maximum stack size corresponding to this basic block. This 95 * size is relative to the stack size at the beginning of the basic block, 96 * i.e., the true maximum stack size is equal to {@link #beginStackSize 97 * beginStackSize} + {@link #maxStackSize maxStackSize}. 98 */ 99 int maxStackSize; 100 101 /** 102 * The successors of this node in the control flow graph. These successors 103 * are stored in a linked list of {@link Edge Edge} objects, linked to each 104 * other by their {@link Edge#next} field. 105 */ 106 Edge successors; 107 108 /** 109 * The next basic block in the basic block stack. See 110 * {@link MethodWriter#visitMaxs visitMaxs}. 111 */ 112 Label next; 113 114 /** 115 * <tt>true</tt> if this basic block has been pushed in the basic block 116 * stack. See {@link MethodWriter#visitMaxs visitMaxs}. 117 */ 118 boolean pushed; 119 120 // ------------------------------------------------------------------------ 121 // Constructor 122 // ------------------------------------------------------------------------ 123 124 /** 125 * Constructs a new label. 126 */ Label()127 public Label() { 128 } 129 130 // ------------------------------------------------------------------------ 131 // Methods to compute offsets and to manage forward references 132 // ------------------------------------------------------------------------ 133 134 /** 135 * Returns the offset corresponding to this label. This offset is computed 136 * from the start of the method's bytecode. <i>This method is intended for 137 * {@link Attribute} sub classes, and is normally not needed by class 138 * generators or adapters.</i> 139 * 140 * @return the offset corresponding to this label. 141 * @throws IllegalStateException if this label is not resolved yet. 142 */ getOffset()143 public int getOffset() { 144 if (!resolved) { 145 throw new IllegalStateException("Label offset position has not been resolved yet"); 146 } 147 return position; 148 } 149 150 /** 151 * Puts a reference to this label in the bytecode of a method. If the 152 * position of the label is known, the offset is computed and written 153 * directly. Otherwise, a null offset is written and a new forward reference 154 * is declared for this label. 155 * 156 * @param owner the code writer that calls this method. 157 * @param out the bytecode of the method. 158 * @param source the position of first byte of the bytecode instruction that 159 * contains this label. 160 * @param wideOffset <tt>true</tt> if the reference must be stored in 4 161 * bytes, or <tt>false</tt> if it must be stored with 2 bytes. 162 * @throws IllegalArgumentException if this label has not been created by 163 * the given code writer. 164 */ put( final MethodWriter owner, final ByteVector out, final int source, final boolean wideOffset)165 void put( 166 final MethodWriter owner, 167 final ByteVector out, 168 final int source, 169 final boolean wideOffset) 170 { 171 if (resolved) { 172 if (wideOffset) { 173 out.putInt(position - source); 174 } else { 175 out.putShort(position - source); 176 } 177 } else { 178 if (wideOffset) { 179 addReference(-1 - source, out.length); 180 out.putInt(-1); 181 } else { 182 addReference(source, out.length); 183 out.putShort(-1); 184 } 185 } 186 } 187 188 /** 189 * Adds a forward reference to this label. This method must be called only 190 * for a true forward reference, i.e. only if this label is not resolved 191 * yet. For backward references, the offset of the reference can be, and 192 * must be, computed and stored directly. 193 * 194 * @param sourcePosition the position of the referencing instruction. This 195 * position will be used to compute the offset of this forward 196 * reference. 197 * @param referencePosition the position where the offset for this forward 198 * reference must be stored. 199 */ addReference( final int sourcePosition, final int referencePosition)200 private void addReference( 201 final int sourcePosition, 202 final int referencePosition) 203 { 204 if (srcAndRefPositions == null) { 205 srcAndRefPositions = new int[6]; 206 } 207 if (referenceCount >= srcAndRefPositions.length) { 208 int[] a = new int[srcAndRefPositions.length + 6]; 209 System.arraycopy(srcAndRefPositions, 210 0, 211 a, 212 0, 213 srcAndRefPositions.length); 214 srcAndRefPositions = a; 215 } 216 srcAndRefPositions[referenceCount++] = sourcePosition; 217 srcAndRefPositions[referenceCount++] = referencePosition; 218 } 219 220 /** 221 * Resolves all forward references to this label. This method must be called 222 * when this label is added to the bytecode of the method, i.e. when its 223 * position becomes known. This method fills in the blanks that where left 224 * in the bytecode by each forward reference previously added to this label. 225 * 226 * @param owner the code writer that calls this method. 227 * @param position the position of this label in the bytecode. 228 * @param data the bytecode of the method. 229 * @return <tt>true</tt> if a blank that was left for this label was to 230 * small to store the offset. In such a case the corresponding jump 231 * instruction is replaced with a pseudo instruction (using unused 232 * opcodes) using an unsigned two bytes offset. These pseudo 233 * instructions will need to be replaced with true instructions with 234 * wider offsets (4 bytes instead of 2). This is done in 235 * {@link MethodWriter#resizeInstructions}. 236 * @throws IllegalArgumentException if this label has already been resolved, 237 * or if it has not been created by the given code writer. 238 */ resolve( final MethodWriter owner, final int position, final byte[] data)239 boolean resolve( 240 final MethodWriter owner, 241 final int position, 242 final byte[] data) 243 { 244 boolean needUpdate = false; 245 this.resolved = true; 246 this.position = position; 247 int i = 0; 248 while (i < referenceCount) { 249 int source = srcAndRefPositions[i++]; 250 int reference = srcAndRefPositions[i++]; 251 int offset; 252 if (source >= 0) { 253 offset = position - source; 254 if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) { 255 /* 256 * changes the opcode of the jump instruction, in order to 257 * be able to find it later (see resizeInstructions in 258 * MethodWriter). These temporary opcodes are similar to 259 * jump instruction opcodes, except that the 2 bytes offset 260 * is unsigned (and can therefore represent values from 0 to 261 * 65535, which is sufficient since the size of a method is 262 * limited to 65535 bytes). 263 */ 264 int opcode = data[reference - 1] & 0xFF; 265 if (opcode <= Opcodes.JSR) { 266 // changes IFEQ ... JSR to opcodes 202 to 217 267 data[reference - 1] = (byte) (opcode + 49); 268 } else { 269 // changes IFNULL and IFNONNULL to opcodes 218 and 219 270 data[reference - 1] = (byte) (opcode + 20); 271 } 272 needUpdate = true; 273 } 274 data[reference++] = (byte) (offset >>> 8); 275 data[reference] = (byte) offset; 276 } else { 277 offset = position + source + 1; 278 data[reference++] = (byte) (offset >>> 24); 279 data[reference++] = (byte) (offset >>> 16); 280 data[reference++] = (byte) (offset >>> 8); 281 data[reference] = (byte) offset; 282 } 283 } 284 return needUpdate; 285 } 286 287 // ------------------------------------------------------------------------ 288 // Overriden Object methods 289 // ------------------------------------------------------------------------ 290 291 /** 292 * Returns a string representation of this label. 293 * 294 * @return a string representation of this label. 295 */ toString()296 public String toString() { 297 return "L" + System.identityHashCode(this); 298 } 299 } 300