0001: /*
0002: * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package sun.tools.asm;
0027:
0028: import sun.tools.java.*;
0029: import java.util.Enumeration;
0030: import java.io.IOException;
0031: import java.io.DataOutputStream;
0032:
0033: /**
0034: * An Java instruction
0035: *
0036: * WARNING: The contents of this source file are not part of any
0037: * supported API. Code that depends on them does so at its own risk:
0038: * they are subject to change or removal without notice.
0039: */
0040: public class Instruction implements Constants {
0041: long where;
0042: int pc;
0043: int opc;
0044: Object value;
0045: Instruction next;
0046: //JCOV
0047: boolean flagCondInverted; /* if true, the condition is reversed
0048: relatively of source code */
0049: boolean flagNoCovered = false; /* if true, the command will
0050: ignored for coverage */
0051:
0052: /**
0053: * Constructor
0054: */
0055: public Instruction(long where, int opc, Object value,
0056: boolean flagCondInverted) {
0057: this .where = where;
0058: this .opc = opc;
0059: this .value = value;
0060: this .flagCondInverted = flagCondInverted;
0061: }
0062:
0063: /**
0064: * Constructor
0065: */
0066: public Instruction(boolean flagNoCovered, long where, int opc,
0067: Object value) {
0068: this .where = where;
0069: this .opc = opc;
0070: this .value = value;
0071: this .flagNoCovered = flagNoCovered;
0072: }
0073:
0074: /**
0075: * Constructor
0076: */
0077: public Instruction(long where, int opc, boolean flagNoCovered) {
0078: this .where = where;
0079: this .opc = opc;
0080: this .flagNoCovered = flagNoCovered;
0081: }
0082:
0083: //end JCOV
0084:
0085: /**
0086: * Constructor
0087: */
0088: public Instruction(long where, int opc, Object value) {
0089: this .where = where;
0090: this .opc = opc;
0091: this .value = value;
0092: }
0093:
0094: /**
0095: * When deciding between a lookupswitch and a tableswitch, this
0096: * value is used in determining how much size increase is
0097: * acceptable.
0098: */
0099: public static final double SWITCHRATIO;
0100:
0101: static {
0102: // Set SWITCHRATIO from the property javac.switchratio
0103: // if it exists and is reasonable. Otherwise, set
0104: // SWITCHRATIO to 1.5, meaning that we will accept a 1.5x
0105: // blowup (for the instruction) to use a tableswitch instead
0106: // of a lookupswitch.
0107: double ratio = 1.5;
0108: String valStr = System.getProperty("javac.switchratio");
0109: if (valStr != null) {
0110: try {
0111: double temp = Double.valueOf(valStr).doubleValue();
0112: if (!(Double.isNaN(temp) || temp < 0.0)) {
0113: ratio = temp;
0114: }
0115: } catch (NumberFormatException ee) {
0116: }
0117: }
0118: SWITCHRATIO = ratio;
0119: }
0120:
0121: /**
0122: * Accessor
0123: */
0124: public int getOpcode() {
0125: return pc;
0126: }
0127:
0128: public Object getValue() {
0129: return value;
0130: }
0131:
0132: public void setValue(Object value) {
0133: this .value = value;
0134: }
0135:
0136: /**
0137: * Optimize
0138: */
0139: void optimize(Environment env) {
0140: switch (opc) {
0141: case opc_istore:
0142: case opc_lstore:
0143: case opc_fstore:
0144: case opc_dstore:
0145: case opc_astore:
0146: // Don't keep the LocalVariable info around, unless we
0147: // are actually going to generate a local variable table.
0148: if ((value instanceof LocalVariable) && !env.debug_vars()) {
0149: value = new Integer(((LocalVariable) value).slot);
0150: }
0151: break;
0152:
0153: case opc_goto: {
0154: Label lbl = (Label) value;
0155: value = lbl = lbl.getDestination();
0156: if (lbl == next) {
0157: // goto to the next instruction, obsolete
0158: opc = opc_dead;
0159: break;
0160: }
0161:
0162: // We optimize
0163: //
0164: // goto Tag
0165: // ...
0166: // Tag:
0167: // return
0168: //
0169: // except when we're generating debuggable code. When
0170: // we're generating debuggable code, we leave it alone,
0171: // in order to provide better stepping behavior. Consider
0172: // a method the end of which looks like this:
0173: //
0174: // ...
0175: // break;
0176: // } // end of loop
0177: // } // end of method
0178: //
0179: // If we optimize the goto away, we'll be left with a
0180: // single instruction (return) and the need to ascribe that
0181: // instruction to two source lines (the break statement and
0182: // the method's right curly). Can't get there from here.
0183: // Depending on which line-number ascription we choose, the
0184: // stepping user will step directly from the break statement
0185: // back into the caller of the method (case 1) or from the
0186: // statement that precedes the break statement to the method's
0187: // right curly (case 2). Similarly, he'll be able to set a
0188: // breakpoint on the break statement (case 1) or the method's
0189: // right curly (case 2), but not on both. Neither case 1 nor
0190: // case 2 is desirable. .We want him to see both the break
0191: // statement and the method's right curly when stepping,
0192: // and we want him to be able to set a breakpoint on either or
0193: // both. So we suppress the optimization when generating
0194: // debuggable code.
0195: // (Above notes from brucek@eng in JDK1.0.2, copied here
0196: // by kelly.ohair@eng for JDK1.1)
0197: //
0198: // With the changes to allow -O and -g at the same time,
0199: // I've changed the condition to be whether optimization is
0200: // on instead of the debugging flag being off.
0201: // - david.stoutamire@eng for 1.2
0202:
0203: if (lbl.next != null && env.opt()) {
0204: switch (lbl.next.opc) {
0205: case opc_return:
0206: case opc_ireturn:
0207: case opc_lreturn:
0208: case opc_freturn:
0209: case opc_dreturn:
0210: case opc_areturn:
0211: // goto to return
0212: opc = lbl.next.opc;
0213: value = lbl.next.value;
0214: break;
0215: }
0216: }
0217: break;
0218: }
0219:
0220: case opc_ifeq:
0221: case opc_ifne:
0222: case opc_ifgt:
0223: case opc_ifge:
0224: case opc_iflt:
0225: case opc_ifle:
0226: case opc_ifnull:
0227: case opc_ifnonnull:
0228: value = ((Label) value).getDestination();
0229: if (value == next) {
0230: // branch to next instruction, obsolete
0231: opc = opc_pop;
0232: break;
0233: }
0234: if ((next.opc == opc_goto) && (value == next.next)) {
0235: // Conditional branch over goto, invert
0236: // Note that you can't invert all conditions, condition
0237: // results for float/double compares are not invertable.
0238: switch (opc) {
0239: case opc_ifeq:
0240: opc = opc_ifne;
0241: break;
0242: case opc_ifne:
0243: opc = opc_ifeq;
0244: break;
0245: case opc_iflt:
0246: opc = opc_ifge;
0247: break;
0248: case opc_ifle:
0249: opc = opc_ifgt;
0250: break;
0251: case opc_ifgt:
0252: opc = opc_ifle;
0253: break;
0254: case opc_ifge:
0255: opc = opc_iflt;
0256: break;
0257: case opc_ifnull:
0258: opc = opc_ifnonnull;
0259: break;
0260: case opc_ifnonnull:
0261: opc = opc_ifnull;
0262: break;
0263: }
0264: //JCOV
0265: flagCondInverted = !flagCondInverted;
0266: //end JCOV
0267: value = next.value;
0268: next.opc = opc_dead;
0269: }
0270: break;
0271:
0272: case opc_if_acmpeq:
0273: case opc_if_acmpne:
0274: case opc_if_icmpeq:
0275: case opc_if_icmpne:
0276: case opc_if_icmpgt:
0277: case opc_if_icmpge:
0278: case opc_if_icmplt:
0279: case opc_if_icmple:
0280: value = ((Label) value).getDestination();
0281: if (value == next) {
0282: // branch to next instruction, obsolete
0283: opc = opc_pop2;
0284: break;
0285: }
0286: if ((next.opc == opc_goto) && (value == next.next)) {
0287: // Conditional branch over goto, invert
0288: switch (opc) {
0289: case opc_if_acmpeq:
0290: opc = opc_if_acmpne;
0291: break;
0292: case opc_if_acmpne:
0293: opc = opc_if_acmpeq;
0294: break;
0295: case opc_if_icmpeq:
0296: opc = opc_if_icmpne;
0297: break;
0298: case opc_if_icmpne:
0299: opc = opc_if_icmpeq;
0300: break;
0301: case opc_if_icmpgt:
0302: opc = opc_if_icmple;
0303: break;
0304: case opc_if_icmpge:
0305: opc = opc_if_icmplt;
0306: break;
0307: case opc_if_icmplt:
0308: opc = opc_if_icmpge;
0309: break;
0310: case opc_if_icmple:
0311: opc = opc_if_icmpgt;
0312: break;
0313: }
0314: //JCOV
0315: flagCondInverted = !flagCondInverted;
0316: //end JCOV
0317: value = next.value;
0318: next.opc = opc_dead;
0319: }
0320: break;
0321:
0322: case opc_tableswitch:
0323: case opc_lookupswitch: {
0324: SwitchData sw = (SwitchData) value;
0325: sw.defaultLabel = sw.defaultLabel.getDestination();
0326: for (Enumeration e = sw.tab.keys(); e.hasMoreElements();) {
0327: Integer k = (Integer) e.nextElement();
0328: Label lbl = (Label) sw.tab.get(k);
0329: sw.tab.put(k, lbl.getDestination());
0330: }
0331:
0332: // Compute the approximate sizes of a tableswitch and a
0333: // lookupswitch. Decide which one we want to generate.
0334:
0335: long range = (long) sw.maxValue - (long) sw.minValue + 1;
0336: long entries = sw.tab.size();
0337:
0338: long tableSize = 4 + range;
0339: long lookupSize = 3 + 2 * entries;
0340:
0341: if (tableSize <= lookupSize * SWITCHRATIO) {
0342: opc = opc_tableswitch;
0343: } else {
0344: opc = opc_lookupswitch;
0345: }
0346: break;
0347: }
0348:
0349: }
0350: }
0351:
0352: /**
0353: * Collect constants into the constant table
0354: */
0355: void collect(ConstantPool tab) {
0356: switch (opc) {
0357: case opc_istore:
0358: case opc_lstore:
0359: case opc_fstore:
0360: case opc_dstore:
0361: case opc_astore:
0362: if (value instanceof LocalVariable) {
0363: MemberDefinition field = ((LocalVariable) value).field;
0364: tab.put(field.getName().toString());
0365: tab.put(field.getType().getTypeSignature());
0366: }
0367: return;
0368:
0369: case opc_new:
0370: case opc_putfield:
0371: case opc_putstatic:
0372: case opc_getfield:
0373: case opc_getstatic:
0374: case opc_invokevirtual:
0375: case opc_invokespecial:
0376: case opc_invokestatic:
0377: case opc_invokeinterface:
0378: case opc_instanceof :
0379: case opc_checkcast:
0380: tab.put(value);
0381: return;
0382:
0383: case opc_anewarray:
0384: tab.put(value);
0385: return;
0386:
0387: case opc_multianewarray:
0388: tab.put(((ArrayData) value).type);
0389: return;
0390:
0391: case opc_ldc:
0392: case opc_ldc_w:
0393: if (value instanceof Integer) {
0394: int v = ((Integer) value).intValue();
0395: if ((v >= -1) && (v <= 5)) {
0396: opc = opc_iconst_0 + v;
0397: return;
0398: } else if ((v >= -(1 << 7)) && (v < (1 << 7))) {
0399: opc = opc_bipush;
0400: return;
0401: } else if ((v >= -(1 << 15)) && (v < (1 << 15))) {
0402: opc = opc_sipush;
0403: return;
0404: }
0405: } else if (value instanceof Float) {
0406: float v = ((Float) value).floatValue();
0407: if (v == 0) {
0408: if (Float.floatToIntBits(v) == 0) {
0409: opc = opc_fconst_0;
0410: return;
0411: }
0412: } else if (v == 1) {
0413: opc = opc_fconst_1;
0414: return;
0415: } else if (v == 2) {
0416: opc = opc_fconst_2;
0417: return;
0418: }
0419: }
0420: tab.put(value);
0421: return;
0422:
0423: case opc_ldc2_w:
0424: if (value instanceof Long) {
0425: long v = ((Long) value).longValue();
0426: if (v == 0) {
0427: opc = opc_lconst_0;
0428: return;
0429: } else if (v == 1) {
0430: opc = opc_lconst_1;
0431: return;
0432: }
0433: } else if (value instanceof Double) {
0434: double v = ((Double) value).doubleValue();
0435: if (v == 0) {
0436: if (Double.doubleToLongBits(v) == 0) {
0437: opc = opc_dconst_0;
0438: return;
0439: }
0440: } else if (v == 1) {
0441: opc = opc_dconst_1;
0442: return;
0443: }
0444: }
0445: tab.put(value);
0446: return;
0447:
0448: case opc_try:
0449: for (Enumeration e = ((TryData) value).catches.elements(); e
0450: .hasMoreElements();) {
0451: CatchData cd = (CatchData) e.nextElement();
0452: if (cd.getType() != null) {
0453: tab.put(cd.getType());
0454: }
0455: }
0456: return;
0457:
0458: case opc_nop:
0459: if ((value != null) && (value instanceof ClassDeclaration))
0460: tab.put(value);
0461: return;
0462: }
0463: }
0464:
0465: /**
0466: * Balance the stack
0467: */
0468: int balance() {
0469: switch (opc) {
0470: case opc_dead:
0471: case opc_label:
0472: case opc_iinc:
0473: case opc_arraylength:
0474: case opc_laload:
0475: case opc_daload:
0476: case opc_nop:
0477: case opc_ineg:
0478: case opc_fneg:
0479: case opc_lneg:
0480: case opc_dneg:
0481: case opc_i2f:
0482: case opc_f2i:
0483: case opc_l2d:
0484: case opc_d2l:
0485: case opc_i2b:
0486: case opc_i2c:
0487: case opc_i2s:
0488: case opc_jsr:
0489: case opc_goto:
0490: case opc_jsr_w:
0491: case opc_goto_w:
0492: case opc_return:
0493: case opc_ret:
0494: case opc_instanceof :
0495: case opc_checkcast:
0496: case opc_newarray:
0497: case opc_anewarray:
0498: case opc_try:
0499: case opc_swap:
0500: return 0;
0501:
0502: case opc_ldc:
0503: case opc_ldc_w:
0504: case opc_bipush:
0505: case opc_sipush:
0506: case opc_aconst_null:
0507: case opc_iconst_m1:
0508: case opc_iconst_0:
0509: case opc_iconst_1:
0510: case opc_iconst_2:
0511: case opc_iconst_3:
0512: case opc_iconst_4:
0513: case opc_iconst_5:
0514: case opc_fconst_0:
0515: case opc_fconst_1:
0516: case opc_fconst_2:
0517: case opc_iload:
0518: case opc_fload:
0519: case opc_aload:
0520: case opc_dup:
0521: case opc_dup_x1:
0522: case opc_dup_x2:
0523: case opc_i2l:
0524: case opc_i2d:
0525: case opc_f2l:
0526: case opc_f2d:
0527: case opc_new:
0528: return 1;
0529:
0530: case opc_lload:
0531: case opc_dload:
0532: case opc_dup2:
0533: case opc_dup2_x1:
0534: case opc_dup2_x2:
0535: case opc_ldc2_w:
0536: case opc_lconst_0:
0537: case opc_lconst_1:
0538: case opc_dconst_0:
0539: case opc_dconst_1:
0540: return 2;
0541:
0542: case opc_istore:
0543: case opc_fstore:
0544: case opc_astore:
0545: case opc_iaload:
0546: case opc_faload:
0547: case opc_aaload:
0548: case opc_baload:
0549: case opc_caload:
0550: case opc_saload:
0551: case opc_pop:
0552: case opc_iadd:
0553: case opc_fadd:
0554: case opc_isub:
0555: case opc_fsub:
0556: case opc_imul:
0557: case opc_fmul:
0558: case opc_idiv:
0559: case opc_fdiv:
0560: case opc_irem:
0561: case opc_frem:
0562: case opc_ishl:
0563: case opc_ishr:
0564: case opc_iushr:
0565: case opc_lshl:
0566: case opc_lshr:
0567: case opc_lushr:
0568: case opc_iand:
0569: case opc_ior:
0570: case opc_ixor:
0571: case opc_l2i:
0572: case opc_l2f:
0573: case opc_d2i:
0574: case opc_d2f:
0575: case opc_ifeq:
0576: case opc_ifne:
0577: case opc_iflt:
0578: case opc_ifle:
0579: case opc_ifgt:
0580: case opc_ifge:
0581: case opc_ifnull:
0582: case opc_ifnonnull:
0583: case opc_fcmpl:
0584: case opc_fcmpg:
0585: case opc_ireturn:
0586: case opc_freturn:
0587: case opc_areturn:
0588: case opc_tableswitch:
0589: case opc_lookupswitch:
0590: case opc_athrow:
0591: case opc_monitorenter:
0592: case opc_monitorexit:
0593: return -1;
0594:
0595: case opc_lstore:
0596: case opc_dstore:
0597: case opc_pop2:
0598: case opc_ladd:
0599: case opc_dadd:
0600: case opc_lsub:
0601: case opc_dsub:
0602: case opc_lmul:
0603: case opc_dmul:
0604: case opc_ldiv:
0605: case opc_ddiv:
0606: case opc_lrem:
0607: case opc_drem:
0608: case opc_land:
0609: case opc_lor:
0610: case opc_lxor:
0611: case opc_if_acmpeq:
0612: case opc_if_acmpne:
0613: case opc_if_icmpeq:
0614: case opc_if_icmpne:
0615: case opc_if_icmplt:
0616: case opc_if_icmple:
0617: case opc_if_icmpgt:
0618: case opc_if_icmpge:
0619: case opc_lreturn:
0620: case opc_dreturn:
0621: return -2;
0622:
0623: case opc_iastore:
0624: case opc_fastore:
0625: case opc_aastore:
0626: case opc_bastore:
0627: case opc_castore:
0628: case opc_sastore:
0629: case opc_lcmp:
0630: case opc_dcmpl:
0631: case opc_dcmpg:
0632: return -3;
0633:
0634: case opc_lastore:
0635: case opc_dastore:
0636: return -4;
0637:
0638: case opc_multianewarray:
0639: return 1 - ((ArrayData) value).nargs;
0640:
0641: case opc_getfield:
0642: return ((MemberDefinition) value).getType().stackSize() - 1;
0643:
0644: case opc_putfield:
0645: return -1
0646: - ((MemberDefinition) value).getType().stackSize();
0647:
0648: case opc_getstatic:
0649: return ((MemberDefinition) value).getType().stackSize();
0650:
0651: case opc_putstatic:
0652: return -((MemberDefinition) value).getType().stackSize();
0653:
0654: case opc_invokevirtual:
0655: case opc_invokespecial:
0656: case opc_invokeinterface:
0657: return ((MemberDefinition) value).getType().getReturnType()
0658: .stackSize()
0659: - (((MemberDefinition) value).getType().stackSize() + 1);
0660:
0661: case opc_invokestatic:
0662: return ((MemberDefinition) value).getType().getReturnType()
0663: .stackSize()
0664: - (((MemberDefinition) value).getType().stackSize());
0665: }
0666: throw new CompilerError("invalid opcode: " + toString());
0667: }
0668:
0669: /**
0670: * Return the size of the instruction
0671: */
0672: int size(ConstantPool tab) {
0673: switch (opc) {
0674: case opc_try:
0675: case opc_label:
0676: case opc_dead:
0677: return 0;
0678:
0679: case opc_bipush:
0680: case opc_newarray:
0681: return 2;
0682:
0683: case opc_sipush:
0684: case opc_goto:
0685: case opc_jsr:
0686: case opc_ifeq:
0687: case opc_ifne:
0688: case opc_ifgt:
0689: case opc_ifge:
0690: case opc_iflt:
0691: case opc_ifle:
0692: case opc_ifnull:
0693: case opc_ifnonnull:
0694: case opc_if_acmpeq:
0695: case opc_if_acmpne:
0696: case opc_if_icmpeq:
0697: case opc_if_icmpne:
0698: case opc_if_icmpgt:
0699: case opc_if_icmpge:
0700: case opc_if_icmplt:
0701: case opc_if_icmple:
0702: return 3;
0703:
0704: case opc_ldc:
0705: case opc_ldc_w:
0706: if (tab.index(value) < 256) {
0707: opc = opc_ldc;
0708: return 2;
0709: } else {
0710: opc = opc_ldc_w;
0711: return 3;
0712: }
0713:
0714: case opc_iload:
0715: case opc_lload:
0716: case opc_fload:
0717: case opc_dload:
0718: case opc_aload: {
0719: int v = ((Number) value).intValue();
0720: if (v < 4) {
0721: if (v < 0) {
0722: throw new CompilerError(
0723: "invalid slot: "
0724: + toString()
0725: + "\nThis error possibly resulted from poorly constructed class paths.");
0726: }
0727: opc = opc_iload_0 + (opc - opc_iload) * 4 + v;
0728: return 1;
0729: } else if (v <= 255) {
0730: return 2;
0731: } else {
0732: opc += 256; // indicate wide variant
0733: return 4;
0734: }
0735: }
0736:
0737: case opc_iinc: {
0738: int register = ((int[]) value)[0];
0739: int increment = ((int[]) value)[1];
0740: if (register < 0) {
0741: throw new CompilerError("invalid slot: " + toString());
0742: }
0743: if (register <= 255 && (((byte) increment) == increment)) {
0744: return 3;
0745: } else {
0746: opc += 256; // indicate wide variant
0747: return 6;
0748: }
0749: }
0750:
0751: case opc_istore:
0752: case opc_lstore:
0753: case opc_fstore:
0754: case opc_dstore:
0755: case opc_astore: {
0756: int v = (value instanceof Number) ? ((Number) value)
0757: .intValue() : ((LocalVariable) value).slot;
0758: if (v < 4) {
0759: if (v < 0) {
0760: throw new CompilerError("invalid slot: "
0761: + toString());
0762: }
0763: opc = opc_istore_0 + (opc - opc_istore) * 4 + v;
0764: return 1;
0765: } else if (v <= 255) {
0766: return 2;
0767: } else {
0768: opc += 256; // indicate wide variant
0769: return 4;
0770: }
0771: }
0772:
0773: case opc_ret: {
0774: int v = ((Number) value).intValue();
0775: if (v <= 255) {
0776: if (v < 0) {
0777: throw new CompilerError("invalid slot: "
0778: + toString());
0779: }
0780: return 2;
0781: } else {
0782: opc += 256; // indicate wide variant
0783: return 4;
0784: }
0785: }
0786:
0787: case opc_ldc2_w:
0788: case opc_new:
0789: case opc_putstatic:
0790: case opc_getstatic:
0791: case opc_putfield:
0792: case opc_getfield:
0793: case opc_invokevirtual:
0794: case opc_invokespecial:
0795: case opc_invokestatic:
0796: case opc_instanceof :
0797: case opc_checkcast:
0798: case opc_anewarray:
0799: return 3;
0800:
0801: case opc_multianewarray:
0802: return 4;
0803:
0804: case opc_invokeinterface:
0805: case opc_goto_w:
0806: case opc_jsr_w:
0807: return 5;
0808:
0809: case opc_tableswitch: {
0810: SwitchData sw = (SwitchData) value;
0811: int n = 1;
0812: for (; ((pc + n) % 4) != 0; n++)
0813: ;
0814: return n + 16 + (sw.maxValue - sw.minValue) * 4;
0815: }
0816:
0817: case opc_lookupswitch: {
0818: SwitchData sw = (SwitchData) value;
0819: int n = 1;
0820: for (; ((pc + n) % 4) != 0; n++)
0821: ;
0822: return n + 8 + sw.tab.size() * 8;
0823: }
0824:
0825: case opc_nop:
0826: if ((value != null) && !(value instanceof Integer))
0827: return 2;
0828: else
0829: return 1;
0830: }
0831:
0832: // most opcodes are only 1 byte long
0833: return 1;
0834: }
0835:
0836: /**
0837: * Generate code
0838: */
0839: void write(DataOutputStream out, ConstantPool tab)
0840: throws IOException {
0841: switch (opc) {
0842: case opc_try:
0843: case opc_label:
0844: case opc_dead:
0845: break;
0846:
0847: case opc_bipush:
0848: case opc_newarray:
0849: case opc_iload:
0850: case opc_lload:
0851: case opc_fload:
0852: case opc_dload:
0853: case opc_aload:
0854: case opc_ret:
0855: out.writeByte(opc);
0856: out.writeByte(((Number) value).intValue());
0857: break;
0858:
0859: case opc_iload + 256:
0860: case opc_lload + 256:
0861: case opc_fload + 256:
0862: case opc_dload + 256:
0863: case opc_aload + 256:
0864: case opc_ret + 256:
0865: out.writeByte(opc_wide);
0866: out.writeByte(opc - 256);
0867: out.writeShort(((Number) value).intValue());
0868: break;
0869:
0870: case opc_istore:
0871: case opc_lstore:
0872: case opc_fstore:
0873: case opc_dstore:
0874: case opc_astore:
0875: out.writeByte(opc);
0876: out.writeByte((value instanceof Number) ? ((Number) value)
0877: .intValue() : ((LocalVariable) value).slot);
0878: break;
0879:
0880: case opc_istore + 256:
0881: case opc_lstore + 256:
0882: case opc_fstore + 256:
0883: case opc_dstore + 256:
0884: case opc_astore + 256:
0885: out.writeByte(opc_wide);
0886: out.writeByte(opc - 256);
0887: out.writeShort((value instanceof Number) ? ((Number) value)
0888: .intValue() : ((LocalVariable) value).slot);
0889: break;
0890:
0891: case opc_sipush:
0892: out.writeByte(opc);
0893: out.writeShort(((Number) value).intValue());
0894: break;
0895:
0896: case opc_ldc:
0897: out.writeByte(opc);
0898: out.writeByte(tab.index(value));
0899: break;
0900:
0901: case opc_ldc_w:
0902: case opc_ldc2_w:
0903: case opc_new:
0904: case opc_putstatic:
0905: case opc_getstatic:
0906: case opc_putfield:
0907: case opc_getfield:
0908: case opc_invokevirtual:
0909: case opc_invokespecial:
0910: case opc_invokestatic:
0911: case opc_instanceof :
0912: case opc_checkcast:
0913: out.writeByte(opc);
0914: out.writeShort(tab.index(value));
0915: break;
0916:
0917: case opc_iinc:
0918: out.writeByte(opc);
0919: out.writeByte(((int[]) value)[0]); // register
0920: out.writeByte(((int[]) value)[1]); // increment
0921: break;
0922:
0923: case opc_iinc + 256:
0924: out.writeByte(opc_wide);
0925: out.writeByte(opc - 256);
0926: out.writeShort(((int[]) value)[0]); // register
0927: out.writeShort(((int[]) value)[1]); // increment
0928: break;
0929:
0930: case opc_anewarray:
0931: out.writeByte(opc);
0932: out.writeShort(tab.index(value));
0933: break;
0934:
0935: case opc_multianewarray:
0936: out.writeByte(opc);
0937: out.writeShort(tab.index(((ArrayData) value).type));
0938: out.writeByte(((ArrayData) value).nargs);
0939: break;
0940:
0941: case opc_invokeinterface:
0942: out.writeByte(opc);
0943: out.writeShort(tab.index(value));
0944: out.writeByte(((MemberDefinition) value).getType()
0945: .stackSize() + 1);
0946: out.writeByte(0);
0947: break;
0948:
0949: case opc_goto:
0950: case opc_jsr:
0951: case opc_ifeq:
0952: case opc_ifne:
0953: case opc_ifgt:
0954: case opc_ifge:
0955: case opc_iflt:
0956: case opc_ifle:
0957: case opc_ifnull:
0958: case opc_ifnonnull:
0959: case opc_if_acmpeq:
0960: case opc_if_acmpne:
0961: case opc_if_icmpeq:
0962: case opc_if_icmpne:
0963: case opc_if_icmpgt:
0964: case opc_if_icmpge:
0965: case opc_if_icmplt:
0966: case opc_if_icmple:
0967: out.writeByte(opc);
0968: out.writeShort(((Instruction) value).pc - pc);
0969: break;
0970:
0971: case opc_goto_w:
0972: case opc_jsr_w:
0973: out.writeByte(opc);
0974: out.writeLong(((Instruction) value).pc - pc);
0975: break;
0976:
0977: case opc_tableswitch: {
0978: SwitchData sw = (SwitchData) value;
0979: out.writeByte(opc);
0980: for (int n = 1; ((pc + n) % 4) != 0; n++) {
0981: out.writeByte(0);
0982: }
0983: out.writeInt(sw.defaultLabel.pc - pc);
0984: out.writeInt(sw.minValue);
0985: out.writeInt(sw.maxValue);
0986: for (int n = sw.minValue; n <= sw.maxValue; n++) {
0987: Label lbl = sw.get(n);
0988: int target_pc = (lbl != null) ? lbl.pc
0989: : sw.defaultLabel.pc;
0990: out.writeInt(target_pc - pc);
0991: }
0992: break;
0993: }
0994:
0995: case opc_lookupswitch: {
0996: SwitchData sw = (SwitchData) value;
0997: out.writeByte(opc);
0998: int n = pc + 1;
0999: for (; (n % 4) != 0; n++) {
1000: out.writeByte(0);
1001: }
1002: out.writeInt(sw.defaultLabel.pc - pc);
1003: out.writeInt(sw.tab.size());
1004: for (Enumeration e = sw.sortedKeys(); e.hasMoreElements();) {
1005: Integer v = (Integer) e.nextElement();
1006: out.writeInt(v.intValue());
1007: out.writeInt(sw.get(v).pc - pc);
1008: }
1009: break;
1010: }
1011:
1012: case opc_nop:
1013: if (value != null) {
1014: if (value instanceof Integer)
1015: out.writeByte(((Integer) value).intValue());
1016: else
1017: out.writeShort(tab.index(value));
1018: return;
1019: }
1020: // fall through
1021:
1022: default:
1023: out.writeByte(opc);
1024: break;
1025: }
1026: }
1027:
1028: /**
1029: * toString
1030: */
1031: public String toString() {
1032: String prefix = (where >> WHEREOFFSETBITS) + ":\t";
1033: switch (opc) {
1034: case opc_try:
1035: return prefix + "try "
1036: + ((TryData) value).getEndLabel().hashCode();
1037:
1038: case opc_dead:
1039: return prefix + "dead";
1040:
1041: case opc_iinc: {
1042: int register = ((int[]) value)[0];
1043: int increment = ((int[]) value)[1];
1044: return prefix + opcNames[opc] + " " + register + ", "
1045: + increment;
1046: }
1047:
1048: default:
1049: if (value != null) {
1050: if (value instanceof Label) {
1051: return prefix + opcNames[opc] + " "
1052: + value.toString();
1053: } else if (value instanceof Instruction) {
1054: return prefix + opcNames[opc] + " "
1055: + value.hashCode();
1056: } else if (value instanceof String) {
1057: return prefix + opcNames[opc] + " \"" + value
1058: + "\"";
1059: } else {
1060: return prefix + opcNames[opc] + " " + value;
1061: }
1062: } else {
1063: return prefix + opcNames[opc];
1064: }
1065: }
1066: }
1067: }
|