831 lines · 30.1 KB · Java
RawDownload
/* * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.asm; import sun.tools.java.*;import java.util.Enumeration;import java.io.IOException;import java.io.DataOutputStream; /** * An Java instruction * * WARNING: The contents of this source file are not part of any * supported API.  Code that depends on them does so at its own risk: * they are subject to change or removal without notice. */publicclass Instruction implements Constants {    long where;    int pc;    int opc;    Object value;    Instruction next;//JCOV    boolean flagCondInverted;        /* if true, the condition  is reversed                                   relatively of source code */    boolean flagNoCovered = false; /* if true, the command will                                   ignored for coverage */      /**     * Constructor     */    public Instruction(long where, int opc, Object value, boolean flagCondInverted) {        this.where = where;        this.opc = opc;        this.value = value;        this.flagCondInverted = flagCondInverted;    }     /**     * Constructor     */    public Instruction(boolean flagNoCovered, long where, int opc, Object value) {        this.where = where;        this.opc = opc;        this.value = value;        this.flagNoCovered = flagNoCovered;    }     /**     * Constructor     */    public Instruction(long where, int opc, boolean flagNoCovered) {        this.where = where;        this.opc = opc;        this.flagNoCovered = flagNoCovered;    }//end JCOV     /**     * Constructor     */    public Instruction(long where, int opc, Object value) {        this.where = where;        this.opc = opc;        this.value = value;    }     /**     * When deciding between a lookupswitch and a tableswitch, this     * value is used in determining how much size increase is     * acceptable.     */    public static final double SWITCHRATIO;     static {        // Set SWITCHRATIO from the property javac.switchratio        // if it exists and is reasonable.  Otherwise, set        // SWITCHRATIO to 1.5, meaning that we will accept a 1.5x        // blowup (for the instruction) to use a tableswitch instead        // of a lookupswitch.        double ratio = 1.5;        String valStr = System.getProperty("javac.switchratio");        if (valStr != null) {            try {                double temp = Double.valueOf(valStr).doubleValue();                if (!(Double.isNaN(temp) || temp < 0.0)) {                    ratio = temp;                }            } catch (NumberFormatException ee) {}        }        SWITCHRATIO = ratio;    }     /**     * Accessor     */    public int getOpcode() {        return pc;     }     public Object getValue() {        return value;     }     public void setValue(Object value) {        this.value = value;     }      /**     * Optimize     */    void optimize(Environment env) {        switch (opc) {          case opc_istore: case opc_lstore: case opc_fstore:          case opc_dstore: case opc_astore:            // Don't keep the LocalVariable info around, unless we            // are actually going to generate a local variable table.            if ((value instanceof LocalVariable) && !env.debug_vars()) {                value = new Integer(((LocalVariable)value).slot);            }            break;           case opc_goto: {            Label lbl = (Label)value;            value = lbl = lbl.getDestination();            if (lbl == next) {                // goto to the next instruction, obsolete                opc = opc_dead;                break;            }             // We optimize            //            //          goto Tag            //          ...            //    Tag:            //          return            //            // except when we're generating debuggable code.  When            // we're generating debuggable code, we leave it alone,            // in order to provide better stepping behavior.  Consider            // a method the end of which looks like this:            //            //          ...            //          break;            //      }   // end of loop            //  }   // end of method            //            // If we optimize the goto away, we'll be left with a            // single instruction (return) and the need to ascribe that            // instruction to two source lines (the break statement and            // the method's right curly).  Can't get there from here.            // Depending on which line-number ascription we choose, the            // stepping user will step directly from the break statement            // back into the caller of the method (case 1) or from the            // statement that precedes the break statement to the method's            // right curly (case 2).  Similarly, he'll be able to set a            // breakpoint on the break statement (case 1) or the method's            // right curly (case 2), but not on both.  Neither case 1 nor            // case 2 is desirable.  .We want him to see both the break            // statement and the method's right curly when stepping,            // and we want him to be able to set a breakpoint on either or            // both.  So we suppress the optimization when generating            // debuggable code.            // (Above notes from brucek@eng in JDK1.0.2, copied here            //  by kelly.ohair@eng for JDK1.1)            //            // With the changes to allow -O and -g at the same time,            // I've changed the condition to be whether optimization is            // on instead of the debugging flag being off.            //     - david.stoutamire@eng for 1.2             if (lbl.next != null && env.opt()) {                switch (lbl.next.opc) {                  case opc_return:  case opc_ireturn: case opc_lreturn:                  case opc_freturn: case opc_dreturn: case opc_areturn:                    // goto to return                    opc = lbl.next.opc;                    value = lbl.next.value;                    break;                }            }            break;          }           case opc_ifeq:   case opc_ifne:   case opc_ifgt:          case opc_ifge:   case opc_iflt:   case opc_ifle:          case opc_ifnull: case opc_ifnonnull:            value = ((Label)value).getDestination();            if (value == next) {                // branch to next instruction, obsolete                opc = opc_pop;                break;            }            if ((next.opc == opc_goto) && (value == next.next)) {                // Conditional branch over goto, invert                // Note that you can't invert all conditions, condition                // results for float/double compares are not invertable.                switch (opc) {                  case opc_ifeq:      opc = opc_ifne; break;                  case opc_ifne:      opc = opc_ifeq; break;                  case opc_iflt:      opc = opc_ifge; break;                  case opc_ifle:      opc = opc_ifgt; break;                  case opc_ifgt:      opc = opc_ifle; break;                  case opc_ifge:      opc = opc_iflt; break;                  case opc_ifnull:    opc = opc_ifnonnull; break;                  case opc_ifnonnull: opc = opc_ifnull; break;                }//JCOV                flagCondInverted = !flagCondInverted;//end JCOV                value = next.value;                next.opc = opc_dead;            }            break;           case opc_if_acmpeq:   case opc_if_acmpne:          case opc_if_icmpeq:   case opc_if_icmpne:          case opc_if_icmpgt:   case opc_if_icmpge:          case opc_if_icmplt:   case opc_if_icmple:            value = ((Label)value).getDestination();            if (value == next) {                // branch to next instruction, obsolete                opc = opc_pop2;                break;            }            if ((next.opc == opc_goto) && (value == next.next)) {                // Conditional branch over goto, invert                switch (opc) {                  case opc_if_acmpeq: opc = opc_if_acmpne; break;                  case opc_if_acmpne: opc = opc_if_acmpeq; break;                  case opc_if_icmpeq: opc = opc_if_icmpne; break;                  case opc_if_icmpne: opc = opc_if_icmpeq; break;                  case opc_if_icmpgt: opc = opc_if_icmple; break;                  case opc_if_icmpge: opc = opc_if_icmplt; break;                  case opc_if_icmplt: opc = opc_if_icmpge; break;                  case opc_if_icmple: opc = opc_if_icmpgt; break;                }//JCOV                flagCondInverted = !flagCondInverted;//end JCOV                value = next.value;                next.opc = opc_dead;            }            break;           case opc_tableswitch:          case opc_lookupswitch: {            SwitchData sw = (SwitchData)value;            sw.defaultLabel = sw.defaultLabel.getDestination();            for (Enumeration e = sw.tab.keys() ; e.hasMoreElements() ; ) {                Integer k = (Integer)e.nextElement();                Label lbl = (Label)sw.tab.get(k);                sw.tab.put(k, lbl.getDestination());            }             // Compute the approximate sizes of a tableswitch and a            // lookupswitch.  Decide which one we want to generate.             long range = (long)sw.maxValue - (long)sw.minValue + 1;            long entries = sw.tab.size();             long tableSize = 4 + range;            long lookupSize = 3 + 2 * entries;             if (tableSize <= lookupSize * SWITCHRATIO) {                opc = opc_tableswitch;            } else {                opc = opc_lookupswitch;            }            break;          }         }    }     /**     * Collect constants into the constant table     */    void collect(ConstantPool tab) {        switch (opc) {          case opc_istore:      case opc_lstore:        case opc_fstore:          case opc_dstore:      case opc_astore:            if (value instanceof LocalVariable) {                MemberDefinition field = ((LocalVariable)value).field;                tab.put(field.getName().toString());                tab.put(field.getType().getTypeSignature());            }            return;           case opc_new:                 case opc_putfield:          case opc_putstatic:           case opc_getfield:          case opc_getstatic:           case opc_invokevirtual:          case opc_invokespecial:       case opc_invokestatic:          case opc_invokeinterface:     case opc_instanceof:          case opc_checkcast:            tab.put(value);            return;           case opc_anewarray:            tab.put(value);            return;           case opc_multianewarray:            tab.put(((ArrayData)value).type);            return;           case opc_ldc:          case opc_ldc_w:            if (value instanceof Integer) {                int v = ((Integer)value).intValue();                if ((v >= -1) && (v <= 5)) {                    opc = opc_iconst_0 + v;                    return;                } else if ((v >= -(1 << 7)) && (v < (1 << 7))) {                    opc = opc_bipush;                    return;                } else if ((v >= -(1 << 15)) && (v < (1 << 15))) {                    opc = opc_sipush;                    return;                }            } else if (value instanceof Float) {                float v = ((Float)value).floatValue();                if (v == 0) {                    if (Float.floatToIntBits(v) == 0) {                        opc = opc_fconst_0;                        return;                    }                } else if (v == 1) {                    opc = opc_fconst_1;                    return;                } else if (v == 2) {                    opc = opc_fconst_2;                    return;                }            }            tab.put(value);            return;           case opc_ldc2_w:            if (value instanceof Long) {                long v = ((Long)value).longValue();                if (v == 0) {                    opc = opc_lconst_0;                    return;                } else if (v == 1) {                    opc = opc_lconst_1;                    return;                }            } else if (value instanceof Double) {                double v = ((Double)value).doubleValue();                if (v == 0) {                    if (Double.doubleToLongBits(v) == 0) {                        opc = opc_dconst_0;                        return;                    }                } else if (v == 1) {                    opc = opc_dconst_1;                    return;                }            }            tab.put(value);            return;           case opc_try:            for (Enumeration e = ((TryData)value).catches.elements() ; e.hasMoreElements() ;) {                CatchData cd = (CatchData)e.nextElement();                if (cd.getType() != null) {                    tab.put(cd.getType());                }            }            return;           case opc_nop:            if ((value != null) && (value instanceof ClassDeclaration))                tab.put(value);                return;        }    }     /**     * Balance the stack     */    int balance() {        switch (opc) {          case opc_dead:        case opc_label:         case opc_iinc:          case opc_arraylength: case opc_laload:        case opc_daload:          case opc_nop:         case opc_ineg:          case opc_fneg:          case opc_lneg:        case opc_dneg:          case opc_i2f:          case opc_f2i:         case opc_l2d:           case opc_d2l:          case opc_i2b:         case opc_i2c:           case opc_i2s:          case opc_jsr:         case opc_goto:          case opc_jsr_w:          case opc_goto_w:      case opc_return:        case opc_ret:          case opc_instanceof:  case opc_checkcast:     case opc_newarray:          case opc_anewarray:   case opc_try:           case opc_swap:            return 0;           case opc_ldc:         case opc_ldc_w:         case opc_bipush:          case opc_sipush:      case opc_aconst_null:   case opc_iconst_m1:          case opc_iconst_0:    case opc_iconst_1:      case opc_iconst_2:          case opc_iconst_3:    case opc_iconst_4:      case opc_iconst_5:          case opc_fconst_0:    case opc_fconst_1:      case opc_fconst_2:          case opc_iload:       case opc_fload:         case opc_aload:          case opc_dup:         case opc_dup_x1:        case opc_dup_x2:          case opc_i2l:         case opc_i2d:           case opc_f2l:          case opc_f2d:         case opc_new:            return 1;           case opc_lload:       case opc_dload:         case opc_dup2:          case opc_dup2_x1:     case opc_dup2_x2:       case opc_ldc2_w:          case opc_lconst_0:    case opc_lconst_1:      case opc_dconst_0:          case opc_dconst_1:            return 2;           case opc_istore:      case opc_fstore:        case opc_astore:          case opc_iaload:      case opc_faload:        case opc_aaload:          case opc_baload:      case opc_caload:        case opc_saload:          case opc_pop:         case opc_iadd:          case opc_fadd:          case opc_isub:        case opc_fsub:          case opc_imul:          case opc_fmul:        case opc_idiv:          case opc_fdiv:          case opc_irem:        case opc_frem:          case opc_ishl:          case opc_ishr:        case opc_iushr:         case opc_lshl:          case opc_lshr:        case opc_lushr:         case opc_iand:          case opc_ior:         case opc_ixor:          case opc_l2i:          case opc_l2f:         case opc_d2i:           case opc_d2f:          case opc_ifeq:        case opc_ifne:          case opc_iflt:          case opc_ifle:        case opc_ifgt:          case opc_ifge:          case opc_ifnull:      case opc_ifnonnull:     case opc_fcmpl:          case opc_fcmpg:       case opc_ireturn:       case opc_freturn:          case opc_areturn:     case opc_tableswitch:   case opc_lookupswitch:          case opc_athrow:      case opc_monitorenter:  case opc_monitorexit:            return -1;           case opc_lstore:      case opc_dstore:        case opc_pop2:          case opc_ladd:        case opc_dadd:          case opc_lsub:          case opc_dsub:        case opc_lmul:          case opc_dmul:          case opc_ldiv:        case opc_ddiv:          case opc_lrem:          case opc_drem:        case opc_land:          case opc_lor:          case opc_lxor:        case opc_if_acmpeq:     case opc_if_acmpne:          case opc_if_icmpeq:   case opc_if_icmpne:     case opc_if_icmplt:          case opc_if_icmple:   case opc_if_icmpgt:     case opc_if_icmpge:          case opc_lreturn:     case opc_dreturn:            return -2;           case opc_iastore:     case opc_fastore:       case opc_aastore:          case opc_bastore:     case opc_castore:       case opc_sastore:          case opc_lcmp:        case opc_dcmpl:         case opc_dcmpg:            return -3;           case opc_lastore:     case opc_dastore:            return -4;           case opc_multianewarray:            return 1 - ((ArrayData)value).nargs;           case opc_getfield:            return ((MemberDefinition)value).getType().stackSize() - 1;           case opc_putfield:            return -1 - ((MemberDefinition)value).getType().stackSize();           case opc_getstatic:            return ((MemberDefinition)value).getType().stackSize();           case opc_putstatic:            return -((MemberDefinition)value).getType().stackSize();           case opc_invokevirtual:          case opc_invokespecial:          case opc_invokeinterface:            return ((MemberDefinition)value).getType().getReturnType().stackSize() -                   (((MemberDefinition)value).getType().stackSize() + 1);           case opc_invokestatic:

Lines 1–500 of 831.