Mercurial > lasercutter
view src/clojure/asm/Label.java @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line source
1 /***2 * ASM: a very small and fast Java bytecode manipulation framework3 * Copyright (c) 2000-2005 INRIA, France Telecom4 * All rights reserved.5 *6 * Redistribution and use in source and binary forms, with or without7 * modification, are permitted provided that the following conditions8 * are met:9 * 1. Redistributions of source code must retain the above copyright10 * notice, this list of conditions and the following disclaimer.11 * 2. Redistributions in binary form must reproduce the above copyright12 * notice, this list of conditions and the following disclaimer in the13 * documentation and/or other materials provided with the distribution.14 * 3. Neither the name of the copyright holders nor the names of its15 * contributors may be used to endorse or promote products derived from16 * 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, THE20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF28 * THE POSSIBILITY OF SUCH DAMAGE.29 */30 package clojure.asm;32 /**33 * A label represents a position in the bytecode of a method. Labels are used34 * for jump, goto, and switch instructions, and for try catch blocks.35 *36 * @author Eric Bruneton37 */38 public class Label{40 /**41 * Indicates if this label is only used for debug attributes. Such a label42 * is not the start of a basic block, the target of a jump instruction, or43 * an exception handler. It can be safely ignored in control flow graph44 * analysis algorithms (for optimization purposes).45 */46 final static int DEBUG = 1;48 /**49 * Indicates if the position of this label is known.50 */51 final static int RESOLVED = 2;53 /**54 * Indicates if this label has been updated, after instruction resizing.55 */56 final static int RESIZED = 4;58 /**59 * Indicates if this basic block has been pushed in the basic block stack.60 * See {@link MethodWriter#visitMaxs visitMaxs}.61 */62 final static int PUSHED = 8;64 /**65 * Indicates if this label is the target of a jump instruction, or the start66 * of an exception handler.67 */68 final static int TARGET = 16;70 /**71 * Indicates if a stack map frame must be stored for this label.72 */73 final static int STORE = 32;75 /**76 * Indicates if this label corresponds to a reachable basic block.77 */78 final static int REACHABLE = 64;80 /**81 * Indicates if this basic block ends with a JSR instruction.82 */83 final static int JSR = 128;85 /**86 * Indicates if this basic block ends with a RET instruction.87 */88 final static int RET = 256;90 /**91 * Field used to associate user information to a label.92 */93 public Object info;95 /**96 * Flags that indicate the status of this label.97 *98 * @see #DEBUG99 * @see #RESOLVED100 * @see #RESIZED101 * @see #PUSHED102 * @see #TARGET103 * @see #STORE104 * @see #REACHABLE105 * @see #JSR106 * @see #RET107 */108 int status;110 /**111 * The line number corresponding to this label, if known.112 */113 int line;115 /**116 * The position of this label in the code, if known.117 */118 int position;120 /**121 * Number of forward references to this label, times two.122 */123 private int referenceCount;125 /**126 * Informations about forward references. Each forward reference is127 * described by two consecutive integers in this array: the first one is the128 * position of the first byte of the bytecode instruction that contains the129 * forward reference, while the second is the position of the first byte of130 * the forward reference itself. In fact the sign of the first integer131 * indicates if this reference uses 2 or 4 bytes, and its absolute value132 * gives the position of the bytecode instruction.133 */134 private int[] srcAndRefPositions;136 // ------------------------------------------------------------------------138 /*139 * Fields for the control flow and data flow graph analysis algorithms (used140 * to compute the maximum stack size or the stack map frames). A control141 * flow graph contains one node per "basic block", and one edge per "jump"142 * from one basic block to another. Each node (i.e., each basic block) is143 * represented by the Label object that corresponds to the first instruction144 * of this basic block. Each node also stores the list of its successors in145 * the graph, as a linked list of Edge objects.146 *147 * The control flow analysis algorithms used to compute the maximum stack148 * size or the stack map frames are similar and use two steps. The first149 * step, during the visit of each instruction, builds information about the150 * state of the local variables and the operand stack at the end of each151 * basic block, called the "output frame", <i>relatively</i> to the frame152 * state at the beginning of the basic block, which is called the "input153 * frame", and which is <i>unknown</i> during this step. The second step,154 * in {@link MethodWriter#visitMaxs}, is a fix point algorithm that155 * computes information about the input frame of each basic block, from the156 * input state of the first basic block (known from the method signature),157 * and by the using the previously computed relative output frames.158 *159 * The algorithm used to compute the maximum stack size only computes the160 * relative output and absolute input stack heights, while the algorithm161 * used to compute stack map frames computes relative output frames and162 * absolute input frames.163 */165 /**166 * Start of the output stack relatively to the input stack. The exact167 * semantics of this field depends on the algorithm that is used.168 * <p/>169 * When only the maximum stack size is computed, this field is the number of170 * elements in the input stack.171 * <p/>172 * When the stack map frames are completely computed, this field is the173 * offset of the first output stack element relatively to the top of the174 * input stack. This offset is always negative or null. A null offset means175 * that the output stack must be appended to the input stack. A -n offset176 * means that the first n output stack elements must replace the top n input177 * stack elements, and that the other elements must be appended to the input178 * stack.179 */180 int inputStackTop;182 /**183 * Maximum height reached by the output stack, relatively to the top of the184 * input stack. This maximum is always positive or null.185 */186 int outputStackMax;188 /**189 * Information about the input and output stack map frames of this basic190 * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES}191 * option is used.192 */193 Frame frame;195 /**196 * The successor of this label, in the order they are visited. This linked197 * list does not include labels used for debug info only. If198 * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it199 * does not contain successive labels that denote the same bytecode position200 * (in this case only the first label appears in this list).201 */202 Label successor;204 /**205 * The successors of this node in the control flow graph. These successors206 * are stored in a linked list of {@link Edge Edge} objects, linked to each207 * other by their {@link Edge#next} field.208 */209 Edge successors;211 /**212 * The next basic block in the basic block stack. This stack is used in the213 * main loop of the fix point algorithm used in the second step of the214 * control flow analysis algorithms.215 *216 * @see MethodWriter#visitMaxs217 */218 Label next;220 // ------------------------------------------------------------------------221 // Constructor222 // ------------------------------------------------------------------------224 /**225 * Constructs a new label.226 */227 public Label(){228 }230 /**231 * Constructs a new label.232 *233 * @param debug if this label is only used for debug attributes.234 */235 Label(final boolean debug){236 this.status = debug ? DEBUG : 0;237 }239 // ------------------------------------------------------------------------240 // Methods to compute offsets and to manage forward references241 // ------------------------------------------------------------------------243 /**244 * Returns the offset corresponding to this label. This offset is computed245 * from the start of the method's bytecode. <i>This method is intended for246 * {@link Attribute} sub classes, and is normally not needed by class247 * generators or adapters.</i>248 *249 * @return the offset corresponding to this label.250 * @throws IllegalStateException if this label is not resolved yet.251 */252 public int getOffset(){253 if((status & RESOLVED) == 0)254 {255 throw new IllegalStateException("Label offset position has not been resolved yet");256 }257 return position;258 }260 /**261 * Puts a reference to this label in the bytecode of a method. If the262 * position of the label is known, the offset is computed and written263 * directly. Otherwise, a null offset is written and a new forward reference264 * is declared for this label.265 *266 * @param owner the code writer that calls this method.267 * @param out the bytecode of the method.268 * @param source the position of first byte of the bytecode instruction that269 * contains this label.270 * @param wideOffset <tt>true</tt> if the reference must be stored in 4271 * bytes, or <tt>false</tt> if it must be stored with 2 bytes.272 * @throws IllegalArgumentException if this label has not been created by273 * the given code writer.274 */275 void put(276 final MethodWriter owner,277 final ByteVector out,278 final int source,279 final boolean wideOffset){280 if((status & RESOLVED) != 0)281 {282 if(wideOffset)283 {284 out.putInt(position - source);285 }286 else287 {288 out.putShort(position - source);289 }290 }291 else292 {293 if(wideOffset)294 {295 addReference(-1 - source, out.length);296 out.putInt(-1);297 }298 else299 {300 addReference(source, out.length);301 out.putShort(-1);302 }303 }304 }306 /**307 * Adds a forward reference to this label. This method must be called only308 * for a true forward reference, i.e. only if this label is not resolved309 * yet. For backward references, the offset of the reference can be, and310 * must be, computed and stored directly.311 *312 * @param sourcePosition the position of the referencing instruction. This313 * position will be used to compute the offset of this forward314 * reference.315 * @param referencePosition the position where the offset for this forward316 * reference must be stored.317 */318 private void addReference(319 final int sourcePosition,320 final int referencePosition){321 if(srcAndRefPositions == null)322 {323 srcAndRefPositions = new int[6];324 }325 if(referenceCount >= srcAndRefPositions.length)326 {327 int[] a = new int[srcAndRefPositions.length + 6];328 System.arraycopy(srcAndRefPositions,329 0,330 a,331 0,332 srcAndRefPositions.length);333 srcAndRefPositions = a;334 }335 srcAndRefPositions[referenceCount++] = sourcePosition;336 srcAndRefPositions[referenceCount++] = referencePosition;337 }339 /**340 * Resolves all forward references to this label. This method must be called341 * when this label is added to the bytecode of the method, i.e. when its342 * position becomes known. This method fills in the blanks that where left343 * in the bytecode by each forward reference previously added to this label.344 *345 * @param owner the code writer that calls this method.346 * @param position the position of this label in the bytecode.347 * @param data the bytecode of the method.348 * @return <tt>true</tt> if a blank that was left for this label was to349 * small to store the offset. In such a case the corresponding jump350 * instruction is replaced with a pseudo instruction (using unused351 * opcodes) using an unsigned two bytes offset. These pseudo352 * instructions will need to be replaced with true instructions with353 * wider offsets (4 bytes instead of 2). This is done in354 * {@link MethodWriter#resizeInstructions}.355 * @throws IllegalArgumentException if this label has already been resolved,356 * or if it has not been created by the given code writer.357 */358 boolean resolve(359 final MethodWriter owner,360 final int position,361 final byte[] data){362 boolean needUpdate = false;363 this.status |= RESOLVED;364 this.position = position;365 int i = 0;366 while(i < referenceCount)367 {368 int source = srcAndRefPositions[i++];369 int reference = srcAndRefPositions[i++];370 int offset;371 if(source >= 0)372 {373 offset = position - source;374 if(offset < Short.MIN_VALUE || offset > Short.MAX_VALUE)375 {376 /*377 * changes the opcode of the jump instruction, in order to378 * be able to find it later (see resizeInstructions in379 * MethodWriter). These temporary opcodes are similar to380 * jump instruction opcodes, except that the 2 bytes offset381 * is unsigned (and can therefore represent values from 0 to382 * 65535, which is sufficient since the size of a method is383 * limited to 65535 bytes).384 */385 int opcode = data[reference - 1] & 0xFF;386 if(opcode <= Opcodes.JSR)387 {388 // changes IFEQ ... JSR to opcodes 202 to 217389 data[reference - 1] = (byte) (opcode + 49);390 }391 else392 {393 // changes IFNULL and IFNONNULL to opcodes 218 and 219394 data[reference - 1] = (byte) (opcode + 20);395 }396 needUpdate = true;397 }398 data[reference++] = (byte) (offset >>> 8);399 data[reference] = (byte) offset;400 }401 else402 {403 offset = position + source + 1;404 data[reference++] = (byte) (offset >>> 24);405 data[reference++] = (byte) (offset >>> 16);406 data[reference++] = (byte) (offset >>> 8);407 data[reference] = (byte) offset;408 }409 }410 return needUpdate;411 }413 /**414 * Returns the first label of the series to which this label belongs. For an415 * isolated label or for the first label in a series of successive labels,416 * this method returns the label itself. For other labels it returns the417 * first label of the series.418 *419 * @return the first label of the series to which this label belongs.420 */421 Label getFirst(){422 return frame == null ? this : frame.owner;423 }425 // ------------------------------------------------------------------------426 // Overriden Object methods427 // ------------------------------------------------------------------------429 /**430 * Returns a string representation of this label.431 *432 * @return a string representation of this label.433 */434 public String toString(){435 return "L" + System.identityHashCode(this);436 }437 }