| /* |
| * Copyright (c) 1994, 2013, 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. |
| */ |
| public |
| class 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 = ((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<Integer> e = sw.tab.keys() ; e.hasMoreElements() ; ) { |
| Integer k = e.nextElement(); |
| Label lbl = 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<CatchData> e = ((TryData)value).catches.elements() ; e.hasMoreElements() ;) { |
| CatchData cd = 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: |
| return ((MemberDefinition)value).getType().getReturnType().stackSize() - |
| (((MemberDefinition)value).getType().stackSize()); |
| } |
| throw new CompilerError("invalid opcode: " + toString()); |
| } |
| |
| /** |
| * Return the size of the instruction |
| */ |
| int size(ConstantPool tab) { |
| switch (opc) { |
| case opc_try: case opc_label: case opc_dead: |
| return 0; |
| |
| case opc_bipush: case opc_newarray: |
| return 2; |
| |
| case opc_sipush: case opc_goto: case opc_jsr: |
| case opc_ifeq: case opc_ifne: case opc_ifgt: |
| case opc_ifge: case opc_iflt: case opc_ifle: |
| case opc_ifnull: case opc_ifnonnull: 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: |
| return 3; |
| |
| case opc_ldc: |
| case opc_ldc_w: |
| if (tab.index(value) < 256) { |
| opc = opc_ldc; |
| return 2; |
| } else { |
| opc = opc_ldc_w; |
| return 3; |
| } |
| |
| case opc_iload: case opc_lload: case opc_fload: |
| case opc_dload: case opc_aload: { |
| int v = ((Number)value).intValue(); |
| if (v < 4) { |
| if (v < 0) { |
| throw new CompilerError("invalid slot: " + toString() |
| + "\nThis error possibly resulted from poorly constructed class paths."); |
| } |
| opc = opc_iload_0 + (opc - opc_iload) * 4 + v; |
| return 1; |
| } else if (v <= 255) { |
| return 2; |
| } else { |
| opc += 256; // indicate wide variant |
| return 4; |
| } |
| } |
| |
| case opc_iinc: { |
| int register = ((int[])value)[0]; |
| int increment = ((int[])value)[1]; |
| if (register < 0) { |
| throw new CompilerError("invalid slot: " + toString()); |
| } |
| if (register <= 255 && (((byte)increment) == increment)) { |
| return 3; |
| } else { |
| opc += 256; // indicate wide variant |
| return 6; |
| } |
| } |
| |
| case opc_istore: case opc_lstore: case opc_fstore: |
| case opc_dstore: case opc_astore: { |
| int v = (value instanceof Number) ? |
| ((Number)value).intValue() : ((LocalVariable)value).slot; |
| if (v < 4) { |
| if (v < 0) { |
| throw new CompilerError("invalid slot: " + toString()); |
| } |
| opc = opc_istore_0 + (opc - opc_istore) * 4 + v; |
| return 1; |
| } else if (v <= 255) { |
| return 2; |
| } else { |
| opc += 256; // indicate wide variant |
| return 4; |
| } |
| } |
| |
| case opc_ret: { |
| int v = ((Number)value).intValue(); |
| if (v <= 255) { |
| if (v < 0) { |
| throw new CompilerError("invalid slot: " + toString()); |
| } |
| return 2; |
| } else { |
| opc += 256; // indicate wide variant |
| return 4; |
| } |
| } |
| |
| case opc_ldc2_w: case opc_new: |
| case opc_putstatic: case opc_getstatic: |
| case opc_putfield: case opc_getfield: |
| case opc_invokevirtual: case opc_invokespecial: |
| case opc_invokestatic: case opc_instanceof: |
| case opc_checkcast: case opc_anewarray: |
| return 3; |
| |
| case opc_multianewarray: |
| return 4; |
| |
| case opc_invokeinterface: |
| case opc_goto_w: |
| case opc_jsr_w: |
| return 5; |
| |
| case opc_tableswitch: { |
| SwitchData sw = (SwitchData)value; |
| int n = 1; |
| for(; ((pc + n) % 4) != 0 ; n++); |
| return n + 16 + (sw.maxValue - sw.minValue) * 4; |
| } |
| |
| case opc_lookupswitch: { |
| SwitchData sw = (SwitchData)value; |
| int n = 1; |
| for(; ((pc + n) % 4) != 0 ; n++); |
| return n + 8 + sw.tab.size() * 8; |
| } |
| |
| case opc_nop: |
| if ((value != null) && !(value instanceof Integer)) |
| return 2; |
| else |
| return 1; |
| } |
| |
| // most opcodes are only 1 byte long |
| return 1; |
| } |
| |
| /** |
| * Generate code |
| */ |
| @SuppressWarnings("fallthrough") |
| void write(DataOutputStream out, ConstantPool tab) throws IOException { |
| switch (opc) { |
| case opc_try: case opc_label: case opc_dead: |
| break; |
| |
| case opc_bipush: case opc_newarray: |
| case opc_iload: case opc_lload: case opc_fload: |
| case opc_dload: case opc_aload: case opc_ret: |
| out.writeByte(opc); |
| out.writeByte(((Number)value).intValue()); |
| break; |
| |
| case opc_iload + 256: case opc_lload + 256: |
| case opc_fload + 256: case opc_dload + 256: |
| case opc_aload + 256: case opc_ret + 256: |
| out.writeByte(opc_wide); |
| out.writeByte(opc - 256); |
| out.writeShort(((Number)value).intValue()); |
| break; |
| |
| case opc_istore: case opc_lstore: case opc_fstore: |
| case opc_dstore: case opc_astore: |
| out.writeByte(opc); |
| out.writeByte((value instanceof Number) ? |
| ((Number)value).intValue() : ((LocalVariable)value).slot); |
| break; |
| |
| case opc_istore + 256: case opc_lstore + 256: |
| case opc_fstore + 256: case opc_dstore + 256: |
| case opc_astore + 256: |
| out.writeByte(opc_wide); |
| out.writeByte(opc - 256); |
| out.writeShort((value instanceof Number) ? |
| ((Number)value).intValue() : ((LocalVariable)value).slot); |
| break; |
| |
| case opc_sipush: |
| out.writeByte(opc); |
| out.writeShort(((Number)value).intValue()); |
| break; |
| |
| case opc_ldc: |
| out.writeByte(opc); |
| out.writeByte(tab.index(value)); |
| break; |
| |
| case opc_ldc_w: case opc_ldc2_w: |
| case opc_new: case opc_putstatic: |
| case opc_getstatic: case opc_putfield: |
| case opc_getfield: case opc_invokevirtual: |
| case opc_invokespecial: case opc_invokestatic: |
| case opc_instanceof: case opc_checkcast: |
| out.writeByte(opc); |
| out.writeShort(tab.index(value)); |
| break; |
| |
| case opc_iinc: |
| out.writeByte(opc); |
| out.writeByte(((int[])value)[0]); // register |
| out.writeByte(((int[])value)[1]); // increment |
| break; |
| |
| case opc_iinc + 256: |
| out.writeByte(opc_wide); |
| out.writeByte(opc - 256); |
| out.writeShort(((int[])value)[0]); // register |
| out.writeShort(((int[])value)[1]); // increment |
| break; |
| |
| case opc_anewarray: |
| out.writeByte(opc); |
| out.writeShort(tab.index(value)); |
| break; |
| |
| case opc_multianewarray: |
| out.writeByte(opc); |
| out.writeShort(tab.index(((ArrayData)value).type)); |
| out.writeByte(((ArrayData)value).nargs); |
| break; |
| |
| case opc_invokeinterface: |
| out.writeByte(opc); |
| out.writeShort(tab.index(value)); |
| out.writeByte(((MemberDefinition)value).getType().stackSize() + 1); |
| out.writeByte(0); |
| break; |
| |
| case opc_goto: case opc_jsr: case opc_ifeq: |
| case opc_ifne: case opc_ifgt: case opc_ifge: |
| case opc_iflt: case opc_ifle: case opc_ifnull: |
| case opc_ifnonnull: 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: |
| out.writeByte(opc); |
| out.writeShort(((Instruction)value).pc - pc); |
| break; |
| |
| case opc_goto_w: |
| case opc_jsr_w: |
| out.writeByte(opc); |
| out.writeLong(((Instruction)value).pc - pc); |
| break; |
| |
| case opc_tableswitch: { |
| SwitchData sw = (SwitchData)value; |
| out.writeByte(opc); |
| for(int n = 1 ; ((pc + n) % 4) != 0 ; n++) { |
| out.writeByte(0); |
| } |
| out.writeInt(sw.defaultLabel.pc - pc); |
| out.writeInt(sw.minValue); |
| out.writeInt(sw.maxValue); |
| for (int n = sw.minValue ; n <= sw.maxValue ; n++) { |
| Label lbl = sw.get(n); |
| int target_pc = (lbl != null) ? lbl.pc : sw.defaultLabel.pc; |
| out.writeInt(target_pc - pc); |
| } |
| break; |
| } |
| |
| case opc_lookupswitch: { |
| SwitchData sw = (SwitchData)value; |
| out.writeByte(opc); |
| int n = pc + 1; |
| for(; (n % 4) != 0 ; n++) { |
| out.writeByte(0); |
| } |
| out.writeInt(sw.defaultLabel.pc - pc); |
| out.writeInt(sw.tab.size()); |
| for (Enumeration<Integer> e = sw.sortedKeys(); e.hasMoreElements() ; ) { |
| Integer v = e.nextElement(); |
| out.writeInt(v.intValue()); |
| out.writeInt(sw.get(v).pc - pc); |
| } |
| break; |
| } |
| |
| case opc_nop: |
| if (value != null) { |
| if (value instanceof Integer) |
| out.writeByte(((Integer)value).intValue()); |
| else |
| out.writeShort(tab.index(value)); |
| return; |
| } |
| // fall through |
| |
| default: |
| out.writeByte(opc); |
| break; |
| } |
| } |
| |
| /** |
| * toString |
| */ |
| public String toString() { |
| String prefix = (where >> WHEREOFFSETBITS) + ":\t"; |
| switch (opc) { |
| case opc_try: |
| return prefix + "try " + ((TryData)value).getEndLabel().hashCode(); |
| |
| case opc_dead: |
| return prefix + "dead"; |
| |
| case opc_iinc: { |
| int register = ((int[])value)[0]; |
| int increment = ((int[])value)[1]; |
| return prefix + opcNames[opc] + " " + register + ", " + increment; |
| } |
| |
| default: |
| if (value != null) { |
| if (value instanceof Label) { |
| return prefix + opcNames[opc] + " " + value.toString(); |
| } else if (value instanceof Instruction) { |
| return prefix + opcNames[opc] + " " + value.hashCode(); |
| } else if (value instanceof String) { |
| return prefix + opcNames[opc] + " \"" + value + "\""; |
| } else { |
| return prefix + opcNames[opc] + " " + value; |
| } |
| } else { |
| return prefix + opcNames[opc]; |
| } |
| } |
| } |
| } |