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 */ 30package com.sleepycat.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 */ 38public 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 296 public String toString() { 297 return "L" + System.identityHashCode(this); 298 } 299} 300