Mercurial > lasercutter
view src/clojure/asm/Frame.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 * Information about the input and output stack map frames of a basic block.34 *35 * @author Eric Bruneton36 */37 final class Frame{39 /*40 * Frames are computed in a two steps process: during the visit of each41 * instruction, the state of the frame at the end of current basic block is42 * updated by simulating the action of the instruction on the previous state43 * of this so called "output frame". In visitMaxs, a fix point algorithm is44 * used to compute the "input frame" of each basic block, i.e. the stack map45 * frame at the begining of the basic block, starting from the input frame46 * of the first basic block (which is computed from the method descriptor),47 * and by using the previously computed output frames to compute the input48 * state of the other blocks.49 *50 * All output and input frames are stored as arrays of integers. Reference51 * and array types are represented by an index into a type table (which is52 * not the same as the constant pool of the class, in order to avoid adding53 * unnecessary constants in the pool - not all computed frames will end up54 * being stored in the stack map table). This allows very fast type55 * comparisons.56 *57 * Output stack map frames are computed relatively to the input frame of the58 * basic block, which is not yet known when output frames are computed. It59 * is therefore necessary to be able to represent abstract types such as60 * "the type at position x in the input frame locals" or "the type at61 * position x from the top of the input frame stack" or even "the type at62 * position x in the input frame, with y more (or less) array dimensions".63 * This explains the rather complicated type format used in output frames.64 *65 * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a66 * signed number of array dimensions (from -8 to 7). KIND is either BASE,67 * LOCAL or STACK. BASE is used for types that are not relative to the input68 * frame. LOCAL is used for types that are relative to the input local69 * variable types. STACK is used for types that are relative to the input70 * stack types. VALUE depends on KIND. For LOCAL types, it is an index in71 * the input local variable types. For STACK types, it is a position72 * relatively to the top of input frame stack. For BASE types, it is either73 * one of the constants defined in FrameVisitor, or for OBJECT and74 * UNINITIALIZED types, a tag and an index in the type table.75 *76 * Output frames can contain types of any kind and with a positive or77 * negative dimension (and even unassigned types, represented by 0 - which78 * does not correspond to any valid type value). Input frames can only79 * contain BASE types of positive or null dimension. In all cases the type80 * table contains only internal type names (array type descriptors are81 * forbidden - dimensions must be represented through the DIM field).82 *83 * The LONG and DOUBLE types are always represented by using two slots (LONG +84 * TOP or DOUBLE + TOP), for local variable types as well as in the operand85 * stack. This is necessary to be able to simulate DUPx_y instructions,86 * whose effect would be dependent on the actual type values if types were87 * always represented by a single slot in the stack (and this is not88 * possible, since actual type values are not always known - cf LOCAL and89 * STACK type kinds).90 */92 /**93 * Mask to get the dimension of a frame type. This dimension is a signed94 * integer between -8 and 7.95 */96 final static int DIM = 0xF0000000;98 /**99 * Constant to be added to a type to get a type with one more dimension.100 */101 final static int ARRAY_OF = 0x10000000;103 /**104 * Constant to be added to a type to get a type with one less dimension.105 */106 final static int ELEMENT_OF = 0xF0000000;108 /**109 * Mask to get the kind of a frame type.110 *111 * @see #BASE112 * @see #LOCAL113 * @see #STACK114 */115 final static int KIND = 0xF000000;117 /**118 * Mask to get the value of a frame type.119 */120 final static int VALUE = 0xFFFFFF;122 /**123 * Mask to get the kind of base types.124 */125 final static int BASE_KIND = 0xFF00000;127 /**128 * Mask to get the value of base types.129 */130 final static int BASE_VALUE = 0xFFFFF;132 /**133 * Kind of the types that are not relative to an input stack map frame.134 */135 final static int BASE = 0x1000000;137 /**138 * Base kind of the base reference types. The BASE_VALUE of such types is an139 * index into the type table.140 */141 final static int OBJECT = BASE | 0x700000;143 /**144 * Base kind of the uninitialized base types. The BASE_VALUE of such types145 * in an index into the type table (the Item at that index contains both an146 * instruction offset and an internal class name).147 */148 final static int UNINITIALIZED = BASE | 0x800000;150 /**151 * Kind of the types that are relative to the local variable types of an152 * input stack map frame. The value of such types is a local variable index.153 */154 private final static int LOCAL = 0x2000000;156 /**157 * Kind of the the types that are relative to the stack of an input stack158 * map frame. The value of such types is a position relatively to the top of159 * this stack.160 */161 private final static int STACK = 0x3000000;163 /**164 * The TOP type. This is a BASE type.165 */166 final static int TOP = BASE | 0;168 /**169 * The BOOLEAN type. This is a BASE type mainly used for array types.170 */171 final static int BOOLEAN = BASE | 9;173 /**174 * The BYTE type. This is a BASE type mainly used for array types.175 */176 final static int BYTE = BASE | 10;178 /**179 * The CHAR type. This is a BASE type mainly used for array types.180 */181 final static int CHAR = BASE | 11;183 /**184 * The SHORT type. This is a BASE type mainly used for array types.185 */186 final static int SHORT = BASE | 12;188 /**189 * The INTEGER type. This is a BASE type.190 */191 final static int INTEGER = BASE | 1;193 /**194 * The FLOAT type. This is a BASE type.195 */196 final static int FLOAT = BASE | 2;198 /**199 * The DOUBLE type. This is a BASE type.200 */201 final static int DOUBLE = BASE | 3;203 /**204 * The LONG type. This is a BASE type.205 */206 final static int LONG = BASE | 4;208 /**209 * The NULL type. This is a BASE type.210 */211 final static int NULL = BASE | 5;213 /**214 * The UNINITIALIZED_THIS type. This is a BASE type.215 */216 final static int UNINITIALIZED_THIS = BASE | 6;218 /**219 * The stack size variation corresponding to each JVM instruction. This220 * stack variation is equal to the size of the values produced by an221 * instruction, minus the size of the values consumed by this instruction.222 */223 final static int[] SIZE;225 /**226 * Computes the stack size variation corresponding to each JVM instruction.227 */228 static229 {230 int i;231 int[] b = new int[202];232 String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD"233 + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD"234 + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED"235 + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";236 for(i = 0; i < b.length; ++i)237 {238 b[i] = s.charAt(i) - 'E';239 }240 SIZE = b;242 // code to generate the above string243 //244 // int NA = 0; // not applicable (unused opcode or variable size opcode)245 //246 // b = new int[] {247 // 0, //NOP, // visitInsn248 // 1, //ACONST_NULL, // -249 // 1, //ICONST_M1, // -250 // 1, //ICONST_0, // -251 // 1, //ICONST_1, // -252 // 1, //ICONST_2, // -253 // 1, //ICONST_3, // -254 // 1, //ICONST_4, // -255 // 1, //ICONST_5, // -256 // 2, //LCONST_0, // -257 // 2, //LCONST_1, // -258 // 1, //FCONST_0, // -259 // 1, //FCONST_1, // -260 // 1, //FCONST_2, // -261 // 2, //DCONST_0, // -262 // 2, //DCONST_1, // -263 // 1, //BIPUSH, // visitIntInsn264 // 1, //SIPUSH, // -265 // 1, //LDC, // visitLdcInsn266 // NA, //LDC_W, // -267 // NA, //LDC2_W, // -268 // 1, //ILOAD, // visitVarInsn269 // 2, //LLOAD, // -270 // 1, //FLOAD, // -271 // 2, //DLOAD, // -272 // 1, //ALOAD, // -273 // NA, //ILOAD_0, // -274 // NA, //ILOAD_1, // -275 // NA, //ILOAD_2, // -276 // NA, //ILOAD_3, // -277 // NA, //LLOAD_0, // -278 // NA, //LLOAD_1, // -279 // NA, //LLOAD_2, // -280 // NA, //LLOAD_3, // -281 // NA, //FLOAD_0, // -282 // NA, //FLOAD_1, // -283 // NA, //FLOAD_2, // -284 // NA, //FLOAD_3, // -285 // NA, //DLOAD_0, // -286 // NA, //DLOAD_1, // -287 // NA, //DLOAD_2, // -288 // NA, //DLOAD_3, // -289 // NA, //ALOAD_0, // -290 // NA, //ALOAD_1, // -291 // NA, //ALOAD_2, // -292 // NA, //ALOAD_3, // -293 // -1, //IALOAD, // visitInsn294 // 0, //LALOAD, // -295 // -1, //FALOAD, // -296 // 0, //DALOAD, // -297 // -1, //AALOAD, // -298 // -1, //BALOAD, // -299 // -1, //CALOAD, // -300 // -1, //SALOAD, // -301 // -1, //ISTORE, // visitVarInsn302 // -2, //LSTORE, // -303 // -1, //FSTORE, // -304 // -2, //DSTORE, // -305 // -1, //ASTORE, // -306 // NA, //ISTORE_0, // -307 // NA, //ISTORE_1, // -308 // NA, //ISTORE_2, // -309 // NA, //ISTORE_3, // -310 // NA, //LSTORE_0, // -311 // NA, //LSTORE_1, // -312 // NA, //LSTORE_2, // -313 // NA, //LSTORE_3, // -314 // NA, //FSTORE_0, // -315 // NA, //FSTORE_1, // -316 // NA, //FSTORE_2, // -317 // NA, //FSTORE_3, // -318 // NA, //DSTORE_0, // -319 // NA, //DSTORE_1, // -320 // NA, //DSTORE_2, // -321 // NA, //DSTORE_3, // -322 // NA, //ASTORE_0, // -323 // NA, //ASTORE_1, // -324 // NA, //ASTORE_2, // -325 // NA, //ASTORE_3, // -326 // -3, //IASTORE, // visitInsn327 // -4, //LASTORE, // -328 // -3, //FASTORE, // -329 // -4, //DASTORE, // -330 // -3, //AASTORE, // -331 // -3, //BASTORE, // -332 // -3, //CASTORE, // -333 // -3, //SASTORE, // -334 // -1, //POP, // -335 // -2, //POP2, // -336 // 1, //DUP, // -337 // 1, //DUP_X1, // -338 // 1, //DUP_X2, // -339 // 2, //DUP2, // -340 // 2, //DUP2_X1, // -341 // 2, //DUP2_X2, // -342 // 0, //SWAP, // -343 // -1, //IADD, // -344 // -2, //LADD, // -345 // -1, //FADD, // -346 // -2, //DADD, // -347 // -1, //ISUB, // -348 // -2, //LSUB, // -349 // -1, //FSUB, // -350 // -2, //DSUB, // -351 // -1, //IMUL, // -352 // -2, //LMUL, // -353 // -1, //FMUL, // -354 // -2, //DMUL, // -355 // -1, //IDIV, // -356 // -2, //LDIV, // -357 // -1, //FDIV, // -358 // -2, //DDIV, // -359 // -1, //IREM, // -360 // -2, //LREM, // -361 // -1, //FREM, // -362 // -2, //DREM, // -363 // 0, //INEG, // -364 // 0, //LNEG, // -365 // 0, //FNEG, // -366 // 0, //DNEG, // -367 // -1, //ISHL, // -368 // -1, //LSHL, // -369 // -1, //ISHR, // -370 // -1, //LSHR, // -371 // -1, //IUSHR, // -372 // -1, //LUSHR, // -373 // -1, //IAND, // -374 // -2, //LAND, // -375 // -1, //IOR, // -376 // -2, //LOR, // -377 // -1, //IXOR, // -378 // -2, //LXOR, // -379 // 0, //IINC, // visitIincInsn380 // 1, //I2L, // visitInsn381 // 0, //I2F, // -382 // 1, //I2D, // -383 // -1, //L2I, // -384 // -1, //L2F, // -385 // 0, //L2D, // -386 // 0, //F2I, // -387 // 1, //F2L, // -388 // 1, //F2D, // -389 // -1, //D2I, // -390 // 0, //D2L, // -391 // -1, //D2F, // -392 // 0, //I2B, // -393 // 0, //I2C, // -394 // 0, //I2S, // -395 // -3, //LCMP, // -396 // -1, //FCMPL, // -397 // -1, //FCMPG, // -398 // -3, //DCMPL, // -399 // -3, //DCMPG, // -400 // -1, //IFEQ, // visitJumpInsn401 // -1, //IFNE, // -402 // -1, //IFLT, // -403 // -1, //IFGE, // -404 // -1, //IFGT, // -405 // -1, //IFLE, // -406 // -2, //IF_ICMPEQ, // -407 // -2, //IF_ICMPNE, // -408 // -2, //IF_ICMPLT, // -409 // -2, //IF_ICMPGE, // -410 // -2, //IF_ICMPGT, // -411 // -2, //IF_ICMPLE, // -412 // -2, //IF_ACMPEQ, // -413 // -2, //IF_ACMPNE, // -414 // 0, //GOTO, // -415 // 1, //JSR, // -416 // 0, //RET, // visitVarInsn417 // -1, //TABLESWITCH, // visiTableSwitchInsn418 // -1, //LOOKUPSWITCH, // visitLookupSwitch419 // -1, //IRETURN, // visitInsn420 // -2, //LRETURN, // -421 // -1, //FRETURN, // -422 // -2, //DRETURN, // -423 // -1, //ARETURN, // -424 // 0, //RETURN, // -425 // NA, //GETSTATIC, // visitFieldInsn426 // NA, //PUTSTATIC, // -427 // NA, //GETFIELD, // -428 // NA, //PUTFIELD, // -429 // NA, //INVOKEVIRTUAL, // visitMethodInsn430 // NA, //INVOKESPECIAL, // -431 // NA, //INVOKESTATIC, // -432 // NA, //INVOKEINTERFACE, // -433 // NA, //UNUSED, // NOT VISITED434 // 1, //NEW, // visitTypeInsn435 // 0, //NEWARRAY, // visitIntInsn436 // 0, //ANEWARRAY, // visitTypeInsn437 // 0, //ARRAYLENGTH, // visitInsn438 // NA, //ATHROW, // -439 // 0, //CHECKCAST, // visitTypeInsn440 // 0, //INSTANCEOF, // -441 // -1, //MONITORENTER, // visitInsn442 // -1, //MONITOREXIT, // -443 // NA, //WIDE, // NOT VISITED444 // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn445 // -1, //IFNULL, // visitJumpInsn446 // -1, //IFNONNULL, // -447 // NA, //GOTO_W, // -448 // NA, //JSR_W, // -449 // };450 // for (i = 0; i < b.length; ++i) {451 // System.err.print((char)('E' + b[i]));452 // }453 // System.err.println();454 }456 /**457 * The label (i.e. basic block) to which these input and output stack map458 * frames correspond.459 */460 Label owner;462 /**463 * The input stack map frame locals.464 */465 int[] inputLocals;467 /**468 * The input stack map frame stack.469 */470 int[] inputStack;472 /**473 * The output stack map frame locals.474 */475 private int[] outputLocals;477 /**478 * The output stack map frame stack.479 */480 private int[] outputStack;482 /**483 * Relative size of the output stack. The exact semantics of this field484 * depends on the algorithm that is used.485 * <p/>486 * When only the maximum stack size is computed, this field is the size of487 * the output stack relatively to the top of the input stack.488 * <p/>489 * When the stack map frames are completely computed, this field is the490 * actual number of types in {@link #outputStack}.491 */492 private int outputStackTop;494 /**495 * Number of types that are initialized in the basic block.496 *497 * @see #initializations498 */499 private int initializationCount;501 /**502 * The types that are initialized in the basic block. A constructor503 * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace504 * <i>every occurence</i> of this type in the local variables and in the505 * operand stack. This cannot be done during the first phase of the506 * algorithm since, during this phase, the local variables and the operand507 * stack are not completely computed. It is therefore necessary to store the508 * types on which constructors are invoked in the basic block, in order to509 * do this replacement during the second phase of the algorithm, where the510 * frames are fully computed. Note that this array can contain types that511 * are relative to input locals or to the input stack (see below for the512 * description of the algorithm).513 */514 private int[] initializations;516 /**517 * Returns the output frame local variable type at the given index.518 *519 * @param local the index of the local that must be returned.520 * @return the output frame local variable type at the given index.521 */522 private int get(final int local){523 if(outputLocals == null || local >= outputLocals.length)524 {525 // this local has never been assigned in this basic block,526 // so it is still equal to its value in the input frame527 return LOCAL | local;528 }529 else530 {531 int type = outputLocals[local];532 if(type == 0)533 {534 // this local has never been assigned in this basic block,535 // so it is still equal to its value in the input frame536 type = outputLocals[local] = LOCAL | local;537 }538 return type;539 }540 }542 /**543 * Sets the output frame local variable type at the given index.544 *545 * @param local the index of the local that must be set.546 * @param type the value of the local that must be set.547 */548 private void set(final int local, final int type){549 // creates and/or resizes the output local variables array if necessary550 if(outputLocals == null)551 {552 outputLocals = new int[10];553 }554 int n = outputLocals.length;555 if(local >= n)556 {557 int[] t = new int[Math.max(local + 1, 2 * n)];558 System.arraycopy(outputLocals, 0, t, 0, n);559 outputLocals = t;560 }561 // sets the local variable562 outputLocals[local] = type;563 }565 /**566 * Pushes a new type onto the output frame stack.567 *568 * @param type the type that must be pushed.569 */570 private void push(final int type){571 // creates and/or resizes the output stack array if necessary572 if(outputStack == null)573 {574 outputStack = new int[10];575 }576 int n = outputStack.length;577 if(outputStackTop >= n)578 {579 int[] t = new int[Math.max(outputStackTop + 1, 2 * n)];580 System.arraycopy(outputStack, 0, t, 0, n);581 outputStack = t;582 }583 // pushes the type on the output stack584 outputStack[outputStackTop++] = type;585 // updates the maximun height reached by the output stack, if needed586 int top = owner.inputStackTop + outputStackTop;587 if(top > owner.outputStackMax)588 {589 owner.outputStackMax = top;590 }591 }593 /**594 * Pushes a new type onto the output frame stack.595 *596 * @param cw the ClassWriter to which this label belongs.597 * @param desc the descriptor of the type to be pushed. Can also be a method598 * descriptor (in this case this method pushes its return type onto599 * the output frame stack).600 */601 private void push(final ClassWriter cw, final String desc){602 int type = type(cw, desc);603 if(type != 0)604 {605 push(type);606 if(type == LONG || type == DOUBLE)607 {608 push(TOP);609 }610 }611 }613 /**614 * Returns the int encoding of the given type.615 *616 * @param cw the ClassWriter to which this label belongs.617 * @param desc a type descriptor.618 * @return the int encoding of the given type.619 */620 private int type(final ClassWriter cw, final String desc){621 String t;622 int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;623 switch(desc.charAt(index))624 {625 case'V':626 return 0;627 case'Z':628 case'C':629 case'B':630 case'S':631 case'I':632 return INTEGER;633 case'F':634 return FLOAT;635 case'J':636 return LONG;637 case'D':638 return DOUBLE;639 case'L':640 // stores the internal name, not the descriptor!641 t = desc.substring(index + 1, desc.length() - 1);642 return OBJECT | cw.addType(t);643 // case '[':644 default:645 // extracts the dimensions and the element type646 int data;647 int dims = index + 1;648 while(desc.charAt(dims) == '[')649 {650 ++dims;651 }652 switch(desc.charAt(dims))653 {654 case'Z':655 data = BOOLEAN;656 break;657 case'C':658 data = CHAR;659 break;660 case'B':661 data = BYTE;662 break;663 case'S':664 data = SHORT;665 break;666 case'I':667 data = INTEGER;668 break;669 case'F':670 data = FLOAT;671 break;672 case'J':673 data = LONG;674 break;675 case'D':676 data = DOUBLE;677 break;678 // case 'L':679 default:680 // stores the internal name, not the descriptor681 t = desc.substring(dims + 1, desc.length() - 1);682 data = OBJECT | cw.addType(t);683 }684 return (dims - index) << 28 | data;685 }686 }688 /**689 * Pops a type from the output frame stack and returns its value.690 *691 * @return the type that has been popped from the output frame stack.692 */693 private int pop(){694 if(outputStackTop > 0)695 {696 return outputStack[--outputStackTop];697 }698 else699 {700 // if the output frame stack is empty, pops from the input stack701 return STACK | -(--owner.inputStackTop);702 }703 }705 /**706 * Pops the given number of types from the output frame stack.707 *708 * @param elements the number of types that must be popped.709 */710 private void pop(final int elements){711 if(outputStackTop >= elements)712 {713 outputStackTop -= elements;714 }715 else716 {717 // if the number of elements to be popped is greater than the number718 // of elements in the output stack, clear it, and pops the remaining719 // elements from the input stack.720 owner.inputStackTop -= elements - outputStackTop;721 outputStackTop = 0;722 }723 }725 /**726 * Pops a type from the output frame stack.727 *728 * @param desc the descriptor of the type to be popped. Can also be a method729 * descriptor (in this case this method pops the types corresponding730 * to the method arguments).731 */732 private void pop(final String desc){733 char c = desc.charAt(0);734 if(c == '(')735 {736 pop((MethodWriter.getArgumentsAndReturnSizes(desc) >> 2) - 1);737 }738 else if(c == 'J' || c == 'D')739 {740 pop(2);741 }742 else743 {744 pop(1);745 }746 }748 /**749 * Adds a new type to the list of types on which a constructor is invoked in750 * the basic block.751 *752 * @param var a type on a which a constructor is invoked.753 */754 private void init(final int var){755 // creates and/or resizes the initializations array if necessary756 if(initializations == null)757 {758 initializations = new int[2];759 }760 int n = initializations.length;761 if(initializationCount >= n)762 {763 int[] t = new int[Math.max(initializationCount + 1, 2 * n)];764 System.arraycopy(initializations, 0, t, 0, n);765 initializations = t;766 }767 // stores the type to be initialized768 initializations[initializationCount++] = var;769 }771 /**772 * Replaces the given type with the appropriate type if it is one of the773 * types on which a constructor is invoked in the basic block.774 *775 * @param cw the ClassWriter to which this label belongs.776 * @param t a type777 * @return t or, if t is one of the types on which a constructor is invoked778 * in the basic block, the type corresponding to this constructor.779 */780 private int init(final ClassWriter cw, final int t){781 int s;782 if(t == UNINITIALIZED_THIS)783 {784 s = OBJECT | cw.addType(cw.thisName);785 }786 else if((t & (DIM | BASE_KIND)) == UNINITIALIZED)787 {788 String type = cw.typeTable[t & BASE_VALUE].strVal1;789 s = OBJECT | cw.addType(type);790 }791 else792 {793 return t;794 }795 for(int j = 0; j < initializationCount; ++j)796 {797 int u = initializations[j];798 int dim = u & DIM;799 int kind = u & KIND;800 if(kind == LOCAL)801 {802 u = dim + inputLocals[u & VALUE];803 }804 else if(kind == STACK)805 {806 u = dim + inputStack[inputStack.length - (u & VALUE)];807 }808 if(t == u)809 {810 return s;811 }812 }813 return t;814 }816 /**817 * Initializes the input frame of the first basic block from the method818 * descriptor.819 *820 * @param cw the ClassWriter to which this label belongs.821 * @param access the access flags of the method to which this label belongs.822 * @param args the formal parameter types of this method.823 * @param maxLocals the maximum number of local variables of this method.824 */825 void initInputFrame(826 final ClassWriter cw,827 final int access,828 final Type[] args,829 final int maxLocals){830 inputLocals = new int[maxLocals];831 inputStack = new int[0];832 int i = 0;833 if((access & Opcodes.ACC_STATIC) == 0)834 {835 if((access & MethodWriter.ACC_CONSTRUCTOR) == 0)836 {837 inputLocals[i++] = OBJECT | cw.addType(cw.thisName);838 }839 else840 {841 inputLocals[i++] = UNINITIALIZED_THIS;842 }843 }844 for(int j = 0; j < args.length; ++j)845 {846 int t = type(cw, args[j].getDescriptor());847 inputLocals[i++] = t;848 if(t == LONG || t == DOUBLE)849 {850 inputLocals[i++] = TOP;851 }852 }853 while(i < maxLocals)854 {855 inputLocals[i++] = TOP;856 }857 }859 /**860 * Simulates the action of the given instruction on the output stack frame.861 *862 * @param opcode the opcode of the instruction.863 * @param arg the operand of the instruction, if any.864 * @param cw the class writer to which this label belongs.865 * @param item the operand of the instructions, if any.866 */867 void execute(868 final int opcode,869 final int arg,870 final ClassWriter cw,871 final Item item){872 int t1, t2, t3, t4;873 switch(opcode)874 {875 case Opcodes.NOP:876 case Opcodes.INEG:877 case Opcodes.LNEG:878 case Opcodes.FNEG:879 case Opcodes.DNEG:880 case Opcodes.I2B:881 case Opcodes.I2C:882 case Opcodes.I2S:883 case Opcodes.GOTO:884 case Opcodes.RETURN:885 break;886 case Opcodes.ACONST_NULL:887 push(NULL);888 break;889 case Opcodes.ICONST_M1:890 case Opcodes.ICONST_0:891 case Opcodes.ICONST_1:892 case Opcodes.ICONST_2:893 case Opcodes.ICONST_3:894 case Opcodes.ICONST_4:895 case Opcodes.ICONST_5:896 case Opcodes.BIPUSH:897 case Opcodes.SIPUSH:898 case Opcodes.ILOAD:899 push(INTEGER);900 break;901 case Opcodes.LCONST_0:902 case Opcodes.LCONST_1:903 case Opcodes.LLOAD:904 push(LONG);905 push(TOP);906 break;907 case Opcodes.FCONST_0:908 case Opcodes.FCONST_1:909 case Opcodes.FCONST_2:910 case Opcodes.FLOAD:911 push(FLOAT);912 break;913 case Opcodes.DCONST_0:914 case Opcodes.DCONST_1:915 case Opcodes.DLOAD:916 push(DOUBLE);917 push(TOP);918 break;919 case Opcodes.LDC:920 switch(item.type)921 {922 case ClassWriter.INT:923 push(INTEGER);924 break;925 case ClassWriter.LONG:926 push(LONG);927 push(TOP);928 break;929 case ClassWriter.FLOAT:930 push(FLOAT);931 break;932 case ClassWriter.DOUBLE:933 push(DOUBLE);934 push(TOP);935 break;936 case ClassWriter.CLASS:937 push(OBJECT | cw.addType("java/lang/Class"));938 break;939 // case ClassWriter.STR:940 default:941 push(OBJECT | cw.addType("java/lang/String"));942 }943 break;944 case Opcodes.ALOAD:945 push(get(arg));946 break;947 case Opcodes.IALOAD:948 case Opcodes.BALOAD:949 case Opcodes.CALOAD:950 case Opcodes.SALOAD:951 pop(2);952 push(INTEGER);953 break;954 case Opcodes.LALOAD:955 case Opcodes.D2L:956 pop(2);957 push(LONG);958 push(TOP);959 break;960 case Opcodes.FALOAD:961 pop(2);962 push(FLOAT);963 break;964 case Opcodes.DALOAD:965 case Opcodes.L2D:966 pop(2);967 push(DOUBLE);968 push(TOP);969 break;970 case Opcodes.AALOAD:971 pop(1);972 t1 = pop();973 push(ELEMENT_OF + t1);974 break;975 case Opcodes.ISTORE:976 case Opcodes.FSTORE:977 case Opcodes.ASTORE:978 t1 = pop();979 set(arg, t1);980 if(arg > 0)981 {982 t2 = get(arg - 1);983 // if t2 is of kind STACK or LOCAL we cannot know its size!984 if(t2 == LONG || t2 == DOUBLE)985 {986 set(arg - 1, TOP);987 }988 }989 break;990 case Opcodes.LSTORE:991 case Opcodes.DSTORE:992 pop(1);993 t1 = pop();994 set(arg, t1);995 set(arg + 1, TOP);996 if(arg > 0)997 {998 t2 = get(arg - 1);999 // if t2 is of kind STACK or LOCAL we cannot know its size!1000 if(t2 == LONG || t2 == DOUBLE)1001 {1002 set(arg - 1, TOP);1003 }1004 }1005 break;1006 case Opcodes.IASTORE:1007 case Opcodes.BASTORE:1008 case Opcodes.CASTORE:1009 case Opcodes.SASTORE:1010 case Opcodes.FASTORE:1011 case Opcodes.AASTORE:1012 pop(3);1013 break;1014 case Opcodes.LASTORE:1015 case Opcodes.DASTORE:1016 pop(4);1017 break;1018 case Opcodes.POP:1019 case Opcodes.IFEQ:1020 case Opcodes.IFNE:1021 case Opcodes.IFLT:1022 case Opcodes.IFGE:1023 case Opcodes.IFGT:1024 case Opcodes.IFLE:1025 case Opcodes.IRETURN:1026 case Opcodes.FRETURN:1027 case Opcodes.ARETURN:1028 case Opcodes.TABLESWITCH:1029 case Opcodes.LOOKUPSWITCH:1030 case Opcodes.ATHROW:1031 case Opcodes.MONITORENTER:1032 case Opcodes.MONITOREXIT:1033 case Opcodes.IFNULL:1034 case Opcodes.IFNONNULL:1035 pop(1);1036 break;1037 case Opcodes.POP2:1038 case Opcodes.IF_ICMPEQ:1039 case Opcodes.IF_ICMPNE:1040 case Opcodes.IF_ICMPLT:1041 case Opcodes.IF_ICMPGE:1042 case Opcodes.IF_ICMPGT:1043 case Opcodes.IF_ICMPLE:1044 case Opcodes.IF_ACMPEQ:1045 case Opcodes.IF_ACMPNE:1046 case Opcodes.LRETURN:1047 case Opcodes.DRETURN:1048 pop(2);1049 break;1050 case Opcodes.DUP:1051 t1 = pop();1052 push(t1);1053 push(t1);1054 break;1055 case Opcodes.DUP_X1:1056 t1 = pop();1057 t2 = pop();1058 push(t1);1059 push(t2);1060 push(t1);1061 break;1062 case Opcodes.DUP_X2:1063 t1 = pop();1064 t2 = pop();1065 t3 = pop();1066 push(t1);1067 push(t3);1068 push(t2);1069 push(t1);1070 break;1071 case Opcodes.DUP2:1072 t1 = pop();1073 t2 = pop();1074 push(t2);1075 push(t1);1076 push(t2);1077 push(t1);1078 break;1079 case Opcodes.DUP2_X1:1080 t1 = pop();1081 t2 = pop();1082 t3 = pop();1083 push(t2);1084 push(t1);1085 push(t3);1086 push(t2);1087 push(t1);1088 break;1089 case Opcodes.DUP2_X2:1090 t1 = pop();1091 t2 = pop();1092 t3 = pop();1093 t4 = pop();1094 push(t2);1095 push(t1);1096 push(t4);1097 push(t3);1098 push(t2);1099 push(t1);1100 break;1101 case Opcodes.SWAP:1102 t1 = pop();1103 t2 = pop();1104 push(t1);1105 push(t2);1106 break;1107 case Opcodes.IADD:1108 case Opcodes.ISUB:1109 case Opcodes.IMUL:1110 case Opcodes.IDIV:1111 case Opcodes.IREM:1112 case Opcodes.IAND:1113 case Opcodes.IOR:1114 case Opcodes.IXOR:1115 case Opcodes.ISHL:1116 case Opcodes.ISHR:1117 case Opcodes.IUSHR:1118 case Opcodes.L2I:1119 case Opcodes.D2I:1120 case Opcodes.FCMPL:1121 case Opcodes.FCMPG:1122 pop(2);1123 push(INTEGER);1124 break;1125 case Opcodes.LADD:1126 case Opcodes.LSUB:1127 case Opcodes.LMUL:1128 case Opcodes.LDIV:1129 case Opcodes.LREM:1130 case Opcodes.LAND:1131 case Opcodes.LOR:1132 case Opcodes.LXOR:1133 pop(4);1134 push(LONG);1135 push(TOP);1136 break;1137 case Opcodes.FADD:1138 case Opcodes.FSUB:1139 case Opcodes.FMUL:1140 case Opcodes.FDIV:1141 case Opcodes.FREM:1142 case Opcodes.L2F:1143 case Opcodes.D2F:1144 pop(2);1145 push(FLOAT);1146 break;1147 case Opcodes.DADD:1148 case Opcodes.DSUB:1149 case Opcodes.DMUL:1150 case Opcodes.DDIV:1151 case Opcodes.DREM:1152 pop(4);1153 push(DOUBLE);1154 push(TOP);1155 break;1156 case Opcodes.LSHL:1157 case Opcodes.LSHR:1158 case Opcodes.LUSHR:1159 pop(3);1160 push(LONG);1161 push(TOP);1162 break;1163 case Opcodes.IINC:1164 set(arg, INTEGER);1165 break;1166 case Opcodes.I2L:1167 case Opcodes.F2L:1168 pop(1);1169 push(LONG);1170 push(TOP);1171 break;1172 case Opcodes.I2F:1173 pop(1);1174 push(FLOAT);1175 break;1176 case Opcodes.I2D:1177 case Opcodes.F2D:1178 pop(1);1179 push(DOUBLE);1180 push(TOP);1181 break;1182 case Opcodes.F2I:1183 case Opcodes.ARRAYLENGTH:1184 case Opcodes.INSTANCEOF:1185 pop(1);1186 push(INTEGER);1187 break;1188 case Opcodes.LCMP:1189 case Opcodes.DCMPL:1190 case Opcodes.DCMPG:1191 pop(4);1192 push(INTEGER);1193 break;1194 case Opcodes.JSR:1195 case Opcodes.RET:1196 throw new RuntimeException("JSR/RET are not supported with computeFrames option");1197 case Opcodes.GETSTATIC:1198 push(cw, item.strVal3);1199 break;1200 case Opcodes.PUTSTATIC:1201 pop(item.strVal3);1202 break;1203 case Opcodes.GETFIELD:1204 pop(1);1205 push(cw, item.strVal3);1206 break;1207 case Opcodes.PUTFIELD:1208 pop(item.strVal3);1209 pop();1210 break;1211 case Opcodes.INVOKEVIRTUAL:1212 case Opcodes.INVOKESPECIAL:1213 case Opcodes.INVOKESTATIC:1214 case Opcodes.INVOKEINTERFACE:1215 pop(item.strVal3);1216 if(opcode != Opcodes.INVOKESTATIC)1217 {1218 t1 = pop();1219 if(opcode == Opcodes.INVOKESPECIAL1220 && item.strVal2.charAt(0) == '<')1221 {1222 init(t1);1223 }1224 }1225 push(cw, item.strVal3);1226 break;1227 case Opcodes.NEW:1228 push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg));1229 break;1230 case Opcodes.NEWARRAY:1231 pop();1232 switch(arg)1233 {1234 case Opcodes.T_BOOLEAN:1235 push(ARRAY_OF | BOOLEAN);1236 break;1237 case Opcodes.T_CHAR:1238 push(ARRAY_OF | CHAR);1239 break;1240 case Opcodes.T_BYTE:1241 push(ARRAY_OF | BYTE);1242 break;1243 case Opcodes.T_SHORT:1244 push(ARRAY_OF | SHORT);1245 break;1246 case Opcodes.T_INT:1247 push(ARRAY_OF | INTEGER);1248 break;1249 case Opcodes.T_FLOAT:1250 push(ARRAY_OF | FLOAT);1251 break;1252 case Opcodes.T_DOUBLE:1253 push(ARRAY_OF | DOUBLE);1254 break;1255 // case Opcodes.T_LONG:1256 default:1257 push(ARRAY_OF | LONG);1258 break;1259 }1260 break;1261 case Opcodes.ANEWARRAY:1262 String s = item.strVal1;1263 pop();1264 if(s.charAt(0) == '[')1265 {1266 push(cw, "[" + s);1267 }1268 else1269 {1270 push(ARRAY_OF | OBJECT | cw.addType(s));1271 }1272 break;1273 case Opcodes.CHECKCAST:1274 s = item.strVal1;1275 pop();1276 if(s.charAt(0) == '[')1277 {1278 push(cw, s);1279 }1280 else1281 {1282 push(OBJECT | cw.addType(s));1283 }1284 break;1285 // case Opcodes.MULTIANEWARRAY:1286 default:1287 pop(arg);1288 push(cw, item.strVal1);1289 break;1290 }1291 }1293 /**1294 * Merges the input frame of the given basic block with the input and output1295 * frames of this basic block. Returns <tt>true</tt> if the input frame of1296 * the given label has been changed by this operation.1297 *1298 * @param cw the ClassWriter to which this label belongs.1299 * @param frame the basic block whose input frame must be updated.1300 * @param edge the kind of the {@link Edge} between this label and 'label'.1301 * See {@link Edge#info}.1302 * @return <tt>true</tt> if the input frame of the given label has been1303 * changed by this operation.1304 */1305 boolean merge(final ClassWriter cw, final Frame frame, final int edge){1306 boolean changed = false;1307 int i, s, dim, kind, t;1309 int nLocal = inputLocals.length;1310 int nStack = inputStack.length;1311 if(frame.inputLocals == null)1312 {1313 frame.inputLocals = new int[nLocal];1314 changed = true;1315 }1317 for(i = 0; i < nLocal; ++i)1318 {1319 if(outputLocals != null && i < outputLocals.length)1320 {1321 s = outputLocals[i];1322 if(s == 0)1323 {1324 t = inputLocals[i];1325 }1326 else1327 {1328 dim = s & DIM;1329 kind = s & KIND;1330 if(kind == LOCAL)1331 {1332 t = dim + inputLocals[s & VALUE];1333 }1334 else if(kind == STACK)1335 {1336 t = dim + inputStack[nStack - (s & VALUE)];1337 }1338 else1339 {1340 t = s;1341 }1342 }1343 }1344 else1345 {1346 t = inputLocals[i];1347 }1348 if(initializations != null)1349 {1350 t = init(cw, t);1351 }1352 changed |= merge(cw, t, frame.inputLocals, i);1353 }1355 if(edge > 0)1356 {1357 for(i = 0; i < nLocal; ++i)1358 {1359 t = inputLocals[i];1360 changed |= merge(cw, t, frame.inputLocals, i);1361 }1362 if(frame.inputStack == null)1363 {1364 frame.inputStack = new int[1];1365 changed = true;1366 }1367 changed |= merge(cw, edge, frame.inputStack, 0);1368 return changed;1369 }1371 int nInputStack = inputStack.length + owner.inputStackTop;1372 if(frame.inputStack == null)1373 {1374 frame.inputStack = new int[nInputStack + outputStackTop];1375 changed = true;1376 }1378 for(i = 0; i < nInputStack; ++i)1379 {1380 t = inputStack[i];1381 if(initializations != null)1382 {1383 t = init(cw, t);1384 }1385 changed |= merge(cw, t, frame.inputStack, i);1386 }1387 for(i = 0; i < outputStackTop; ++i)1388 {1389 s = outputStack[i];1390 dim = s & DIM;1391 kind = s & KIND;1392 if(kind == LOCAL)1393 {1394 t = dim + inputLocals[s & VALUE];1395 }1396 else if(kind == STACK)1397 {1398 t = dim + inputStack[nStack - (s & VALUE)];1399 }1400 else1401 {1402 t = s;1403 }1404 if(initializations != null)1405 {1406 t = init(cw, t);1407 }1408 changed |= merge(cw, t, frame.inputStack, nInputStack + i);1409 }1410 return changed;1411 }1413 /**1414 * Merges the type at the given index in the given type array with the given1415 * type. Returns <tt>true</tt> if the type array has been modified by this1416 * operation.1417 *1418 * @param cw the ClassWriter to which this label belongs.1419 * @param t the type with which the type array element must be merged.1420 * @param types an array of types.1421 * @param index the index of the type that must be merged in 'types'.1422 * @return <tt>true</tt> if the type array has been modified by this1423 * operation.1424 */1425 private boolean merge(1426 final ClassWriter cw,1427 int t,1428 final int[] types,1429 final int index){1430 int u = types[index];1431 if(u == t)1432 {1433 // if the types are equal, merge(u,t)=u, so there is no change1434 return false;1435 }1436 if((t & ~DIM) == NULL)1437 {1438 if(u == NULL)1439 {1440 return false;1441 }1442 t = NULL;1443 }1444 if(u == 0)1445 {1446 // if types[index] has never been assigned, merge(u,t)=t1447 types[index] = t;1448 return true;1449 }1450 int v;1451 if((u & BASE_KIND) == OBJECT || (u & DIM) != 0)1452 {1453 // if u is a reference type of any dimension1454 if(t == NULL)1455 {1456 // if t is the NULL type, merge(u,t)=u, so there is no change1457 return false;1458 }1459 else if((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND)))1460 {1461 if((u & BASE_KIND) == OBJECT)1462 {1463 // if t is also a reference type, and if u and t have the1464 // same dimension merge(u,t) = dim(t) | common parent of the1465 // element types of u and t1466 v = (t & DIM) | OBJECT1467 | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE);1468 }1469 else1470 {1471 // if u and t are array types, but not with the same element1472 // type, merge(u,t)=java/lang/Object1473 v = OBJECT | cw.addType("java/lang/Object");1474 }1475 }1476 else if((t & BASE_KIND) == OBJECT || (t & DIM) != 0)1477 {1478 // if t is any other reference or array type,1479 // merge(u,t)=java/lang/Object1480 v = OBJECT | cw.addType("java/lang/Object");1481 }1482 else1483 {1484 // if t is any other type, merge(u,t)=TOP1485 v = TOP;1486 }1487 }1488 else if(u == NULL)1489 {1490 // if u is the NULL type, merge(u,t)=t,1491 // or TOP if t is not a reference type1492 v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP;1493 }1494 else1495 {1496 // if u is any other type, merge(u,t)=TOP whatever t1497 v = TOP;1498 }1499 if(u != v)1500 {1501 types[index] = v;1502 return true;1503 }1504 return false;1505 }1506 }