/* * @(#)CVMMethodInfo.java 1.25 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program 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. * * This program 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 at /legal/license.txt). * * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */ package vm; /* * VM-specific internal representation of * a method. Target-machine independent. * * See also CVMClass for VM-specific info associated with each class. * See also CVMVM for VM-specific info not associated directly with any class. */ import components.*; import vm.VMMethodInfo; import consts.Const; import consts.CVMConst; import util.DataFormatException; import java.util.Enumeration; import java.util.Vector; import java.util.Hashtable; import java.util.StringTokenizer; public class CVMMethodInfo extends VMMethodInfo implements Const, CVMConst { private boolean impureCode = false; private boolean mustAlign = false; private boolean hasJsr = false; private boolean isStrictFP; private boolean codeExamined = false; public MethodInfo method; public CVMMethodType sigType; private String myNativeName; public CVMMethodStats.Entry statsEntry; private int inlining; static final int NO_INLINE_FLAG = (0x1 << 24); static final int SAME_CLASS_FLAG = (0x1 << 25); static final int REDO_INLINING_FLAG = (0x1 << 26); /** * Flag used in quickenCode() to save old methodblock info so we can * use it here for inlining. This affects invokevirtual_quick which * typically overwrites the methodblock info with <methodtable offset> * and <nargs>. */ public static final boolean SAVE_TARGET_METHODS = true; public CVMMethodInfo( MethodInfo m ){ method = m; method.vmMethodInfo = this; sigType = CVMMethodType.parseSignature( m.type.string ); this.isStrictFP = ((m.access & Const.ACC_STRICT) != 0); } private void examineCode( ) throws DataFormatException { ConstantPool cp = method.parent.getConstantPool(); boolean needsTypeTable = false; impureCode = false; mustAlign = false; hasJsr = false; if ( method.code == null ){ codeExamined = true; return; } byte [] code = method.code; int ncode = code.length; int opcode; for( int i = 0; i < ncode; i += method.opcodeLength(i)) { switch (opcode = (int)code[i]&0xff) { case opc_tableswitch: case opc_lookupswitch: mustAlign = true; break; case opc_jsr: case opc_jsr_w: hasJsr = true; break; case opc_ldc2_w: case opc_getstatic: case opc_putstatic: case opc_getfield: case opc_putfield: case opc_invokevirtual: case opc_invokespecial: case opc_invokestatic: case opc_invokeinterface: case opc_new: case opc_anewarray: case opc_checkcast: case opc_instanceof: case opc_multianewarray: impureCode = true; // all get quicked. break; // We don't currently quicken ldc of a Class constant case opc_ldc: { ConstantObject co = cp.elementAt((int)code[i + 1] & 0xff); if (!(co instanceof ClassConstant)) { impureCode = true; // all the rest get quickened. } else { needsTypeTable = true; } break; } case opc_ldc_w: { int index = method.getUnsignedShort(i + 1); ConstantObject co = cp.elementAt(index); if (!(co instanceof ClassConstant)) { impureCode = true; // all the rest get quickened. } else { needsTypeTable = true; } break; } } } if (impureCode || needsTypeTable) { cp.setNeedsTypeTable(); } codeExamined = true; } public boolean isCodePure() throws DataFormatException { if ( ! codeExamined ){ examineCode(); // may throw exception without setting codeExamined } return !impureCode; } public int alignment() throws DataFormatException { if ( ! codeExamined ){ examineCode(); // may throw exception without setting codeExamined } return mustAlign ? 4 : 1; } public boolean codeHasJsr() throws DataFormatException { if ( ! codeExamined ){ examineCode(); // may throw exception without setting codeExamined } return hasJsr; } public boolean isStrictFP() { return isStrictFP; } private static int methodNumber = 0; public String getNativeName() { if ( myNativeName == null ){ myNativeName = ((CVMClass)(method.parent.vmClass)).getNativeName()+ methodNumber; methodNumber+= 1; } return myNativeName; } public boolean hasBody(){ return ( (method.access & (ACC_ABSTRACT|ACC_NATIVE) )== 0 ); } public int CVMflags(){ int flagval = 0; int a = method.access; if ( (a&ACC_PUBLIC) != 0 ) flagval |= CVM_METHOD_ACC_PUBLIC; if ( (a&ACC_PRIVATE) != 0 ) flagval |= CVM_METHOD_ACC_PRIVATE; if ( (a&ACC_PROTECTED) != 0 ) flagval |= CVM_METHOD_ACC_PROTECTED; if ( (a&ACC_STATIC) != 0 ) flagval |= CVM_METHOD_ACC_STATIC; if ( (a&ACC_FINAL) != 0 ) flagval |= CVM_METHOD_ACC_FINAL; if ( (a&ACC_SYNCHRONIZED) != 0 ) flagval |= CVM_METHOD_ACC_SYNCHRONIZED; if ( (a&ACC_NATIVE) != 0 ) flagval |= CVM_METHOD_ACC_NATIVE; if ( (a&ACC_ABSTRACT) != 0 ) flagval |= CVM_METHOD_ACC_ABSTRACT; return flagval; } public int methodOffset( ){ int off = method.methodTableIndex; if ( off < 0 ){ /* * off < 0 means that we do not have a methodtable or * imethodtable entry for this method. This is ok if it is: * - private, or * - static, or * - <init> * Otherwise, this is an error. */ if ( method.isStaticMember( ) || method.isPrivateMember( ) || method.name.string.equals("<init>") ) { return 0; } else { throw new Error("Bad method offset for "+method.qualifiedName() ); } } return off; } /** Attempt to inline the code of this method */ final static int inline_NOT_DONE = 0; final static int inline_IN_PROGRESS = 1; final static int inline_DONE = 2; private int inlineState = inline_NOT_DONE; public void inlineCode() { boolean isRewritten = false; if (inlineState == inline_NOT_DONE) { inlineState = inline_IN_PROGRESS; } else { return; } ConstantObject[] cp = method.parent.getConstantPool().getConstants(); byte[] code = method.code; byte[] rewrite; int tmi = 0; // target method index for (int pc = 0; pc < code.length; ) { int opcode = code[pc] & 0xff; switch (opcode) { case opc_invokevirtual_quick: case opc_ainvokevirtual_quick: case opc_dinvokevirtual_quick: case opc_vinvokevirtual_quick: case opc_invokevirtualobject_quick: { // Target method is stored in array instead of code VMMethodInfo targetMethod = method.targetMethods[tmi++].vmMethodInfo; rewrite = MethodCallInline(pc, (CVMMethodInfo)targetMethod); if (rewrite != null) { isRewritten = true; System.arraycopy(rewrite, 0, code, pc, 3); } pc += 3; break; } case opc_invokevirtual_quick_w: case opc_invokenonvirtual_quick: case opc_invokesuper_quick: // not currently used by JavaCodeCompact case opc_invokestatic_quick: { int index = method.getUnsignedShort(pc + 1); MethodConstant mc = (MethodConstant) cp[index]; VMMethodInfo targetMethod = mc.find().vmMethodInfo; rewrite = MethodCallInline(pc, (CVMMethodInfo)targetMethod); if (rewrite != null) { isRewritten = true; System.arraycopy(rewrite, 0, code, pc, 3); } pc += 3; break; } default: pc += method.opcodeLength(pc); break; } } if (isRewritten) compress(); inlineState = inline_DONE; } /* This method is called to determine whether the method "mb" called at * from instruction "pc" can be inlined. If not, the value null is * returned. If so, an array of three bytes, which should overwrite the * method invocation, is returned */ private byte[] MethodCallInline(int pc, CVMMethodInfo mb) { byte code[] = method.code; int opcode = code[pc] & 0xff; if (opcode == opc_invokevirtual_quick || opcode == opc_ainvokevirtual_quick || opcode == opc_dinvokevirtual_quick || opcode == opc_vinvokevirtual_quick || opcode == opc_invokevirtual_quick_w) /* This is a virtual method call. No use even bother trying to * inline the method, unless its final */ if (((mb.method.access & ACC_FINAL) == 0) && ((mb.method.parent.access & ACC_FINAL) == 0)) return null; int mbInlining = mb.getInlining(); if ((mbInlining & NO_INLINE_FLAG) != 0) return null; /* Does this inlining have a dependency on the constant pool, and so * can only be used on a method in the same class. */ if ((mbInlining & SAME_CLASS_FLAG) != 0) { if (this.method.parent != mb.method.parent) return null; } /* There is a inlining. Copy that value into "result" */ byte[] result = new byte[3]; result[0] = INLINING_WORD1(mbInlining); result[1] = INLINING_WORD2(mbInlining); result[2] = INLINING_WORD3(mbInlining); return result; } public int getInlining() { MethodInfo mi = this.method; if (inlining == 0) { if ( ((mi.access & (ACC_ABSTRACT | ACC_NATIVE | ACC_SYNCHRONIZED)) != 0) || (mi.exceptionTable.length > 0)) { inlining = NO_INLINE_FLAG; } else { inlineCode(); inlining = calculateInlining(); /******* if (inlining != NO_INLINE_FLAG) { String sameClass = ((inlining & SAME_CLASS_FLAG) != 0) ? "*" : ""; System.out.print("get: " + this + " =>" + sameClass); System.out.println(" " + disassembleInlining()); } ********/ } } return inlining; } /* Given a method, determine if it can be "inlined" into three or fewer * bytes. */ private int calculateInlining() { MethodInfo mb = this.method; byte[] code = mb.code; /* The checkThis flag indicates that the resulting code must * throw a NullPointerException if the first argument is null */ boolean checkThis = ((mb.access & ACC_STATIC) == 0) && !method.name.string.equals("<init>"); boolean redoInlining = false; int stackSize, stackBase; CVMOpcodeInfoType opPtr; stackSize = 0; stackBase = 0; // Prevent javac warning for (int pc = 0; ; pc++) { /* At this point in our simulation of the execution of the * method, registers stackBase .. stackBase+stackSize - 1 are * pushed onto the the stack. pc points to the next * instruction to look at. */ int opcode = code[pc] & 0xff; int opcode2; int reg, regSize, nextReg; if (stackSize == 0) stackBase = 0; nextReg = stackBase + stackSize; opPtr = OpcodeInfo[opcode]; switch (opPtr.opcode) { case opc_iload_0: /* register load. regnum from opcode */ case opc_iload: /* register load. regnum from pc[1] */ if (opPtr.opcode == opc_iload_0) { reg = REGNUM(opPtr); } else { reg = code[pc + 1] & 0xff; pc++; } regSize = REGSIZE(opPtr); if (stackSize == 0) /* stack is currently empty */ stackBase = reg; else if (nextReg != reg) return NO_INLINE_FLAG; stackSize += regSize; continue; case opc_pop: /* pop stack, or nop */ stackSize -= REGSIZE(opPtr); continue; case opc_nonnull_quick: /* special instruction */ if (nextReg == 1) { /* We're checking register 0 to ensure that it isn't null */ stackSize = 0; checkThis = true; continue; } return NO_INLINE_FLAG; case opc_invokeignored_quick: /* special instruction */ { int popCount = code[pc + 1] & 0xff; if (code[pc + 2] != 0) { /* We only know how to check register 0 for non-null ness */ if (nextReg != popCount) return NO_INLINE_FLAG; checkThis = true; stackSize -= popCount; } else { stackSize -= popCount; } pc += 2; continue; } case opc_return: /* return void or value */ return makeReturnResult(checkThis, nextReg, REGSIZE(opPtr)); case opc_getfield_quick_w: /* or putfield_quick_w */ opcode2 = code[pc + 3] & 0xff; if (!((opcode == opc_getfield_quick_w) ? isXreturn(opcode2) : opcode2 == opc_return)) { return NO_INLINE_FLAG; } /* FALLTHROUGH */ case opc_iadd: { /* any simple instruction */ int ilength = opcLengths[opcode]; int result; if (opcode != opc_athrow) { // We are not inlinable unless we have athrow // as the last instruction, or we are returning if (pc + ilength >= code.length) { return NO_INLINE_FLAG; } else { opcode2 = code[pc + ilength] & 0xff; if (!isXreturn(opcode2) && (opcode2 != opc_return)) { return NO_INLINE_FLAG; } } } if ((opPtr.flags & CVMOpcodeInfoType.NULL_CHECK) != 0 && (stackBase == 0)) { /* We don't need to generate code to check for null, since * the instruction already does it. */ checkThis = false; } switch (ilength) { case 1: result = makeOpcodeResult(checkThis, nextReg, opPtr.inStack, 1, opcode, 0, 0); break; case 2: result = makeOpcodeResult(checkThis, nextReg, opPtr.inStack, 2, opcode, code[pc+1] & 0xff, 0); break; case 3: result = makeOpcodeResult(checkThis, nextReg, opPtr.inStack, 3, opcode, code[pc+1] & 0xff, code[pc+2] & 0xff); break; default: throw new RuntimeException("sysAssert(FALSE);"); // result = NO_INLINE_FLAG; // not reached // break; // not reached } if ((result & NO_INLINE_FLAG) == 0) { if ((opPtr.flags & CVMOpcodeInfoType.CONSTANT_POOL) != 0) result |= SAME_CLASS_FLAG; if (redoInlining) result |= REDO_INLINING_FLAG; } return result; } default: throw new RuntimeException("sysAssert(FALSE);"); case 255: /* random instruction */ return NO_INLINE_FLAG; } /* of switch statement */ } /* end of for loop */ } /* This method is called to create the code that is actually going to * replace the indicated method, when the method does nothing, or when * it simply returns one of its arguments. * * It takes the following arguments: * mb: Method we are examining * checkThis: If true, We must specially check that the first argument * "this" isn't null. * highReg, One greater than the highest register on the stack when * the return or Xreturn is called. * returnSize Size of the return (0 for return, 1 for ireturn, * 2 for lreturn, etc); * * We have to emulate the method call in 3 bytes. At the time the * method is called, the arguments reg[0] . . . reg[mb->args_size - 1] * are pushed on the stack. */ static int[] poppers = { opc_nop, opc_pop, opc_pop2 }; private int makeReturnResult(boolean checkThis, int highReg, int returnSize) { MethodInfo mb = method; int argsSize = mb.argsSize; if (returnSize == 0) { /* Return void */ return MAKE_INLINING(opc_invokeignored_quick, argsSize, (checkThis ? 1 : 0)); } else { /* Return some value from the stack */ int returnReg = highReg - returnSize; int excessArgs = argsSize - returnSize - returnReg; // sysAssert(returnReg >= 0 && returnSize >= 0); if (returnReg == 0) { /* Returning reg0 or reg0/reg1 */ if (checkThis) { /* Must be returning reg0, which is also checked. We * require argsSize >= 2 (which is the same thing as * excessArgs >= 1), because otherwise the "dup" might * overflow the stack. More sophisticated inliners * might see if there is space on the caller's stack. */ // sysAssert(returnSize == 1); if (argsSize < 2) { return NO_INLINE_FLAG; } else if (excessArgs > 2) { return NO_INLINE_FLAG; } else { return MAKE_INLINING(poppers[excessArgs], opc_dup, opc_nonnull_quick); } } else { /* We're returning reg0 or reg0/reg1 which isn't null * checked. We just pop extraneous stuff off the stack * */ return MAKE_INLINING(opc_invokeignored_quick, excessArgs, 0); } } else { /* At this point, returnReg > 0. We're returning something * other than the bottom of the stack. */ if (returnSize == 1 && returnReg == 1) { if (excessArgs > 2) { return NO_INLINE_FLAG; } return MAKE_INLINING(poppers[excessArgs], opc_swap, checkThis ? opc_nonnull_quick : opc_pop); } return NO_INLINE_FLAG; } } } /* This method is called to create the code that is actually going to * replace the indicated method * * makeOpcodeResult is used to create a inlining that can be used anywhere * It takes the following arguments: * * mb: Method we are examining * checkThis: If true, We must specially check that the first argument * "this" isn't null. This condition is >>NOT<< tested by * the generated code. * nextReg: In the emulation, the highest register on the stack is * reg[nextReg - 1]. * icount The number of bytes of instructions that follow. * opcode, op1, op2 * The bytes of instruction. * * We have to emulate the method call in 3 bytes. At the time the * method is called, the arguments reg[0] . . . reg[mb->args_size - 1] * are pushed on the stack. So in three bytes, we have to: * Remove any excess arguments from the stack. * Perform the operation on the indicated stack registers * Remove any objects lower down on the stack (this is hard!) * Make sure that reg[0] is checked for being non-null, if necessary. */ private int makeOpcodeResult(boolean checkThis, int nextReg, int opcodeArgCount, int icount, int opcode, int op1, int op2) { MethodInfo mb = method; int firstReg = (opcodeArgCount == 0) ? 0 : nextReg - opcodeArgCount; // sysAssert(firstReg >= 0 && opcodeArgCount >= 0 && icount > 0); if (firstReg > 0) { /* There are extra registers at the bottom of the stack */ return makePoppingResult(checkThis, firstReg, opcodeArgCount, icount, opcode, op1, op2); } else { /* No extra registers at bottom of stack */ int argsSize = mb.argsSize; int excessArgs = argsSize - opcodeArgCount; /* extra at top */ int popSpace = 3 - icount; /* space to pop args at top */ int result = 0; int i; if (checkThis) { /* Unless this is a constant method that ignores all of its * arguments, we don't really have any way of checking * register 0 if the instructions doesn't. If it is a * constant instruction, deduct one from both popSpace and * from excessArgs, since we are popping that last argument * when an opc_nonnull_quick; */ if (opcodeArgCount > 0 || popSpace == 0) return NO_INLINE_FLAG; popSpace--; excessArgs--; // sysAssert(excessArgs >= 0); } if (excessArgs > 2 * popSpace) return NO_INLINE_FLAG; for (i = 0; i < popSpace; i++) { /* If excessArgs <= popSpace, the following generates excessArgs * "pops" followed by nops. Otherwise, it generates * excessArgs - popSpace pop2's followed by pop's. */ int opcodeTmp = (excessArgs <= i) ? opc_nop : (excessArgs <= popSpace + i) ? opc_pop : opc_pop2; result |= (opcodeTmp << (i << 3)); } if (checkThis) result |= opc_nonnull_quick << ((i++) << 3); // sysAssert(i + icount == 3); switch (icount) { case 3: result |= op2 << ((i + 2) << 3); case 2: result |= op1 << ((i + 1) << 3); case 1: result |= opcode << ((i + 0) << 3); } return result; } } /* * Called by makeOpcodeResult. * Same arguments. But there are extra arguments on the bottom to pop. */ private int makePoppingResult(boolean checkThis, int firstReg, int opcodeArgCount, int icount, int opcode, int op1, int op2) { MethodInfo mb = method; int argsSize = mb.argsSize; int excessArgs = argsSize - opcodeArgCount - firstReg; /* extra on top*/ if (icount > 1) /* We're just not prepared to deal with this. */ return NO_INLINE_FLAG; if (OpcodeInfo[opcode].outStack == 0) { int result = 0; /* Something like an array store, that leaves no value on the stack */ int i = 0; /* We can't deal with checkThis, since it might reverse the order of * an exception. We have a total of two instructions to do all the * pre and post popping. */ if (checkThis || ((excessArgs + 1)/2 + (firstReg + 1)/2) > 2) return NO_INLINE_FLAG; for (; excessArgs > 0; excessArgs -=2) /* pre popping */ result |= (excessArgs == 1 ? opc_pop : opc_pop2) << ((i++) << 3); result |= opcode << ((i++) << 3); for (; firstReg > 0; firstReg -=2) /* post popping */ result |= (firstReg == 1 ? opc_pop : opc_pop2) << ((i++) << 3); while (i < 3) result |= opc_nop << ((i++) << 3); return result; } if (excessArgs > 0 || firstReg > 1) /* We can't both do useful work and remove more than this many * items from the stack. */ return NO_INLINE_FLAG; if (opcodeArgCount == 1) { return MAKE_INLINING(opc_swap, checkThis ? opc_nonnull_quick : opc_pop, opcode); } if (((OpcodeInfo[opcode].flags & (CVMOpcodeInfoType.NULL_CHECK | CVMOpcodeInfoType.CAN_ERROR)) == 0) && (OpcodeInfo[opcode].outStack == 1)) { /* The result creates one thing on the stack, and it can't error */ return MAKE_INLINING(opcode, opc_swap, checkThis ? opc_nonnull_quick : opc_pop); } return NO_INLINE_FLAG; } private static boolean isXreturn(int opcode) { return (opcode >= opc_ireturn) && (opcode <= opc_areturn); } private static byte INLINING_WORD1(int simp) { return (byte) (simp & 0xFF); } private static byte INLINING_WORD2(int simp) { return (byte) ((simp >> 8) & 0xFF); } private static byte INLINING_WORD3(int simp) { return (byte) ((simp >> 16) & 0xFF); } private static int MAKE_INLINING(int op1, int op2, int op3) { return (op1 << 0) + (op2 << 8) + (op3 << 16); } private static int REGSIZE(CVMOpcodeInfoType ptr) { return (ptr.inStack); } private static int REGNUM(CVMOpcodeInfoType ptr) { return (ptr.outStack); } static CVMOpcodeInfoType[] OpcodeInfo = new CVMOpcodeInfoType[256]; static { /* { opc_pop <number of words to pop from stack> } * { opc_iadd <words popped from stack> <words pushed to stack> } * { opc_iload <words pushed to stack> } * { opc_iload_0 <words pushed to stack> <implicit register> } * { opc_return <words returned> } * 255 indicates opcode that we can't inline * other values are special opcodes that must be handled specially */ OpcodeInfo[opc_nop] = new CVMOpcodeInfoType(opc_pop, 0); OpcodeInfo[opc_aconst_null] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_iconst_m1] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_iconst_0] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_iconst_1] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_iconst_2] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_iconst_3] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_iconst_4] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_iconst_5] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_lconst_0] = new CVMOpcodeInfoType(opc_iadd, 0, 2); OpcodeInfo[opc_lconst_1] = new CVMOpcodeInfoType(opc_iadd, 0, 2); OpcodeInfo[opc_fconst_0] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_fconst_1] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_fconst_2] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_dconst_0] = new CVMOpcodeInfoType(opc_iadd, 0, 2); OpcodeInfo[opc_dconst_1] = new CVMOpcodeInfoType(opc_iadd, 0, 2); OpcodeInfo[opc_bipush] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_sipush] = new CVMOpcodeInfoType(opc_iadd, 0, 1); OpcodeInfo[opc_ldc] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_ldc_w] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_ldc2_w] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_iload] = new CVMOpcodeInfoType(opc_iload, 1); OpcodeInfo[opc_lload] = new CVMOpcodeInfoType(opc_iload, 2); OpcodeInfo[opc_fload] = new CVMOpcodeInfoType(opc_iload, 1); OpcodeInfo[opc_dload] = new CVMOpcodeInfoType(opc_iload, 2); OpcodeInfo[opc_aload] = new CVMOpcodeInfoType(opc_iload, 1); OpcodeInfo[opc_iload_0] = new CVMOpcodeInfoType(opc_iload_0, 1, 0); OpcodeInfo[opc_iload_1] = new CVMOpcodeInfoType(opc_iload_0, 1, 1); OpcodeInfo[opc_iload_2] = new CVMOpcodeInfoType(opc_iload_0, 1, 2); OpcodeInfo[opc_iload_3] = new CVMOpcodeInfoType(opc_iload_0, 1, 3); OpcodeInfo[opc_lload_0] = new CVMOpcodeInfoType(opc_iload_0, 2, 0); OpcodeInfo[opc_lload_1] = new CVMOpcodeInfoType(opc_iload_0, 2, 1); OpcodeInfo[opc_lload_2] = new CVMOpcodeInfoType(opc_iload_0, 2, 2); OpcodeInfo[opc_lload_3] = new CVMOpcodeInfoType(opc_iload_0, 2, 3); OpcodeInfo[opc_fload_0] = new CVMOpcodeInfoType(opc_iload_0, 1, 0); OpcodeInfo[opc_fload_1] = new CVMOpcodeInfoType(opc_iload_0, 1, 1); OpcodeInfo[opc_fload_2] = new CVMOpcodeInfoType(opc_iload_0, 1, 2); OpcodeInfo[opc_fload_3] = new CVMOpcodeInfoType(opc_iload_0, 1, 3); OpcodeInfo[opc_dload_0] = new CVMOpcodeInfoType(opc_iload_0, 2, 0); OpcodeInfo[opc_dload_1] = new CVMOpcodeInfoType(opc_iload_0, 2, 1); OpcodeInfo[opc_dload_2] = new CVMOpcodeInfoType(opc_iload_0, 2, 2); OpcodeInfo[opc_dload_3] = new CVMOpcodeInfoType(opc_iload_0, 2, 3); OpcodeInfo[opc_aload_0] = new CVMOpcodeInfoType(opc_iload_0, 1, 0); OpcodeInfo[opc_aload_1] = new CVMOpcodeInfoType(opc_iload_0, 1, 1); OpcodeInfo[opc_aload_2] = new CVMOpcodeInfoType(opc_iload_0, 1, 2); OpcodeInfo[opc_aload_3] = new CVMOpcodeInfoType(opc_iload_0, 1, 3); OpcodeInfo[opc_iaload] = new CVMOpcodeInfoType(opc_iadd, 2, 1, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_laload] = new CVMOpcodeInfoType(opc_iadd, 2, 2, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_faload] = new CVMOpcodeInfoType(opc_iadd, 2, 1, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_daload] = new CVMOpcodeInfoType(opc_iadd, 2, 2, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_aaload] = new CVMOpcodeInfoType(opc_iadd, 2, 1, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_baload] = new CVMOpcodeInfoType(opc_iadd, 2, 1, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_caload] = new CVMOpcodeInfoType(opc_iadd, 2, 1, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_saload] = new CVMOpcodeInfoType(opc_iadd, 2, 1, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_istore] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_lstore] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_fstore] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_dstore] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_astore] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_istore_0] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_istore_1] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_istore_2] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_istore_3] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_lstore_0] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_lstore_1] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_lstore_2] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_lstore_3] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_fstore_0] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_fstore_1] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_fstore_2] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_fstore_3] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_dstore_0] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_dstore_1] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_dstore_2] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_dstore_3] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_astore_0] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_astore_1] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_astore_2] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_astore_3] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_iastore] = new CVMOpcodeInfoType(opc_iadd, 3, 0, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_lastore] = new CVMOpcodeInfoType(opc_iadd, 4, 0, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_fastore] = new CVMOpcodeInfoType(opc_iadd, 3, 0, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_dastore] = new CVMOpcodeInfoType(opc_iadd, 4, 0, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_aastore] = new CVMOpcodeInfoType(opc_iadd, 3, 0, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_bastore] = new CVMOpcodeInfoType(opc_iadd, 3, 0, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_castore] = new CVMOpcodeInfoType(opc_iadd, 3, 0, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_sastore] = new CVMOpcodeInfoType(opc_iadd, 3, 0, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_pop] = new CVMOpcodeInfoType(opc_pop, 1); OpcodeInfo[opc_pop2] = new CVMOpcodeInfoType(opc_pop, 2); OpcodeInfo[opc_dup] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_dup_x1] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_dup_x2] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_dup2] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_dup2_x1] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_dup2_x2] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_swap] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_iadd] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_ladd] = new CVMOpcodeInfoType(opc_iadd, 4, 2); OpcodeInfo[opc_fadd] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_dadd] = new CVMOpcodeInfoType(opc_iadd, 4, 2); OpcodeInfo[opc_isub] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_lsub] = new CVMOpcodeInfoType(opc_iadd, 4, 2); OpcodeInfo[opc_fsub] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_dsub] = new CVMOpcodeInfoType(opc_iadd, 4, 2); OpcodeInfo[opc_imul] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_lmul] = new CVMOpcodeInfoType(opc_iadd, 4, 2); OpcodeInfo[opc_fmul] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_dmul] = new CVMOpcodeInfoType(opc_iadd, 4, 2); OpcodeInfo[opc_idiv] = new CVMOpcodeInfoType(opc_iadd, 2, 1, CVMOpcodeInfoType.CAN_ERROR); OpcodeInfo[opc_ldiv] = new CVMOpcodeInfoType(opc_iadd, 4, 2, CVMOpcodeInfoType.CAN_ERROR); OpcodeInfo[opc_fdiv] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_ddiv] = new CVMOpcodeInfoType(opc_iadd, 4, 2); OpcodeInfo[opc_irem] = new CVMOpcodeInfoType(opc_iadd, 2, 1, CVMOpcodeInfoType.CAN_ERROR); OpcodeInfo[opc_lrem] = new CVMOpcodeInfoType(opc_iadd, 4, 2, CVMOpcodeInfoType.CAN_ERROR); OpcodeInfo[opc_frem] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_drem] = new CVMOpcodeInfoType(opc_iadd, 4, 2); OpcodeInfo[opc_ineg] = new CVMOpcodeInfoType(opc_iadd, 1, 1); OpcodeInfo[opc_lneg] = new CVMOpcodeInfoType(opc_iadd, 2, 2); OpcodeInfo[opc_fneg] = new CVMOpcodeInfoType(opc_iadd, 1, 1); OpcodeInfo[opc_dneg] = new CVMOpcodeInfoType(opc_iadd, 2, 2); OpcodeInfo[opc_ishl] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_lshl] = new CVMOpcodeInfoType(opc_iadd, 3, 2); OpcodeInfo[opc_ishr] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_lshr] = new CVMOpcodeInfoType(opc_iadd, 3, 2); OpcodeInfo[opc_iushr] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_lushr] = new CVMOpcodeInfoType(opc_iadd, 3, 2); OpcodeInfo[opc_iand] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_land] = new CVMOpcodeInfoType(opc_iadd, 4, 2); OpcodeInfo[opc_ior] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_lor] = new CVMOpcodeInfoType(opc_iadd, 4, 2); OpcodeInfo[opc_ixor] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_lxor] = new CVMOpcodeInfoType(opc_iadd, 4, 2); OpcodeInfo[opc_iinc] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_i2l] = new CVMOpcodeInfoType(opc_iadd, 1, 2); OpcodeInfo[opc_i2f] = new CVMOpcodeInfoType(opc_iadd, 1, 1); OpcodeInfo[opc_i2d] = new CVMOpcodeInfoType(opc_iadd, 1, 2); OpcodeInfo[opc_l2i] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_l2f] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_l2d] = new CVMOpcodeInfoType(opc_iadd, 2, 2); OpcodeInfo[opc_f2i] = new CVMOpcodeInfoType(opc_iadd, 1, 1); OpcodeInfo[opc_f2l] = new CVMOpcodeInfoType(opc_iadd, 1, 2); OpcodeInfo[opc_f2d] = new CVMOpcodeInfoType(opc_iadd, 1, 2); OpcodeInfo[opc_d2i] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_d2l] = new CVMOpcodeInfoType(opc_iadd, 2, 2); OpcodeInfo[opc_d2f] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_i2b] = new CVMOpcodeInfoType(opc_iadd, 1, 1); OpcodeInfo[opc_i2c] = new CVMOpcodeInfoType(opc_iadd, 1, 1); OpcodeInfo[opc_i2s] = new CVMOpcodeInfoType(opc_iadd, 1, 1); OpcodeInfo[opc_lcmp] = new CVMOpcodeInfoType(opc_iadd, 4, 1); OpcodeInfo[opc_fcmpl] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_fcmpg] = new CVMOpcodeInfoType(opc_iadd, 2, 1); OpcodeInfo[opc_dcmpl] = new CVMOpcodeInfoType(opc_iadd, 4, 1); OpcodeInfo[opc_dcmpg] = new CVMOpcodeInfoType(opc_iadd, 4, 1); OpcodeInfo[opc_ifeq] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_ifne] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_iflt] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_ifge] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_ifgt] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_ifle] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_if_icmpeq] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_if_icmpne] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_if_icmplt] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_if_icmpge] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_if_icmpgt] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_if_icmple] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_if_acmpeq] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_if_acmpne] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_goto] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_jsr] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_ret] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_tableswitch] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_lookupswitch] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_ireturn] = new CVMOpcodeInfoType(opc_return, 1); OpcodeInfo[opc_lreturn] = new CVMOpcodeInfoType(opc_return, 2); OpcodeInfo[opc_freturn] = new CVMOpcodeInfoType(opc_return, 1); OpcodeInfo[opc_dreturn] = new CVMOpcodeInfoType(opc_return, 2); OpcodeInfo[opc_areturn] = new CVMOpcodeInfoType(opc_return, 1); OpcodeInfo[opc_return] = new CVMOpcodeInfoType(opc_return, 0); OpcodeInfo[opc_getstatic] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_putstatic] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_getfield] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_putfield] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_invokevirtual] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_invokespecial] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_invokestatic] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_invokeinterface] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_xxxunusedxxx] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_new] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_newarray] = new CVMOpcodeInfoType(opc_iadd, 1, 1, CVMOpcodeInfoType.CAN_ERROR); OpcodeInfo[opc_anewarray] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_arraylength] = new CVMOpcodeInfoType(opc_iadd, 1, 1, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_athrow] = new CVMOpcodeInfoType(opc_iadd, 1, 0, CVMOpcodeInfoType.NULL_CHECK | CVMOpcodeInfoType.CAN_ERROR); OpcodeInfo[opc_checkcast] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_instanceof] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_monitorenter] = new CVMOpcodeInfoType(opc_iadd, 1, 0, CVMOpcodeInfoType.NULL_CHECK | CVMOpcodeInfoType.CAN_ERROR); OpcodeInfo[opc_monitorexit] = new CVMOpcodeInfoType(opc_iadd, 1, 0, CVMOpcodeInfoType.NULL_CHECK | CVMOpcodeInfoType.CAN_ERROR); OpcodeInfo[opc_wide] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_multianewarray] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_ifnull] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_ifnonnull] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_goto_w] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_jsr_w] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_breakpoint] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_aldc_quick] = new CVMOpcodeInfoType(opc_iadd, 0, 1, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_aldc_w_quick] = new CVMOpcodeInfoType(opc_iadd, 0, 1, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_aldc_ind_quick] = new CVMOpcodeInfoType(opc_iadd, 0, 1, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_aldc_ind_w_quick] = new CVMOpcodeInfoType(opc_iadd, 0, 1, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_ldc_quick] = new CVMOpcodeInfoType(opc_iadd, 0, 1, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_ldc_w_quick] = new CVMOpcodeInfoType(opc_iadd, 0, 1, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_ldc2_w_quick] = new CVMOpcodeInfoType(opc_iadd, 0, 2, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_getfield_quick] = new CVMOpcodeInfoType(opc_iadd, 1, 1, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_putfield_quick] = new CVMOpcodeInfoType(opc_iadd, 2, 0, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_getfield2_quick] = new CVMOpcodeInfoType(opc_iadd, 1, 2, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_putfield2_quick] = new CVMOpcodeInfoType(opc_iadd, 3, 0, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_getstatic_quick] = new CVMOpcodeInfoType(opc_iadd, 0, 1, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_putstatic_quick] = new CVMOpcodeInfoType(opc_iadd, 1, 0, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_agetstatic_quick] = new CVMOpcodeInfoType(opc_iadd, 0, 1, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_aputstatic_quick] = new CVMOpcodeInfoType(opc_iadd, 1, 0, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_getstatic2_quick] = new CVMOpcodeInfoType(opc_iadd, 0, 2, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_putstatic2_quick]= new CVMOpcodeInfoType(opc_iadd, 2, 0, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_invokevirtual_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_ainvokevirtual_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_dinvokevirtual_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_vinvokevirtual_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_invokenonvirtual_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_invokesuper_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_invokestatic_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_invokeinterface_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_invokevirtualobject_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_invokeignored_quick] = new CVMOpcodeInfoType(opc_invokeignored_quick); OpcodeInfo[opc_new_quick]= new CVMOpcodeInfoType(opc_iadd, 0, 1, CVMOpcodeInfoType.CAN_ERROR | CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_anewarray_quick] = new CVMOpcodeInfoType(opc_iadd, 1, 1, CVMOpcodeInfoType.CAN_ERROR | CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_multianewarray_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_checkcast_quick] = new CVMOpcodeInfoType(opc_iadd, 1, 1, CVMOpcodeInfoType.CAN_ERROR | CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_instanceof_quick] = new CVMOpcodeInfoType(opc_iadd, 1, 1, CVMOpcodeInfoType.CONSTANT_POOL); OpcodeInfo[opc_invokevirtual_quick_w] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_getfield_quick_w] = new CVMOpcodeInfoType(opc_getfield_quick_w); OpcodeInfo[opc_putfield_quick_w] = new CVMOpcodeInfoType(opc_getfield_quick_w); OpcodeInfo[opc_nonnull_quick] = new CVMOpcodeInfoType(opc_nonnull_quick); OpcodeInfo[opc_agetfield_quick] = new CVMOpcodeInfoType(opc_iadd, 1, 1, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_aputfield_quick] = new CVMOpcodeInfoType(opc_iadd, 2, 0, CVMOpcodeInfoType.NULL_CHECK); OpcodeInfo[opc_invokestatic_checkinit_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_getstatic_checkinit_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_putstatic_checkinit_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_agetstatic_checkinit_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_aputstatic_checkinit_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_getstatic2_checkinit_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_putstatic2_checkinit_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_new_checkinit_quick] = new CVMOpcodeInfoType(255); OpcodeInfo[opc_exittransition] = new CVMOpcodeInfoType(255); }; static CVMOpcodeInfoType[] OpcodeInfoSpecial = { /* getfield_quick */ new CVMOpcodeInfoType(opc_iadd, 1, 1, CVMOpcodeInfoType.NULL_CHECK | CVMOpcodeInfoType.CONSTANT_POOL), /* putfield_quick */ new CVMOpcodeInfoType(opc_iadd, 2, 0, CVMOpcodeInfoType.NULL_CHECK | CVMOpcodeInfoType.CONSTANT_POOL), /* getfield2_quick */ new CVMOpcodeInfoType(opc_iadd, 1, 2, CVMOpcodeInfoType.NULL_CHECK | CVMOpcodeInfoType.CONSTANT_POOL), /* putfield2_quick */ new CVMOpcodeInfoType(opc_iadd, 3, 0, CVMOpcodeInfoType.NULL_CHECK | CVMOpcodeInfoType.CONSTANT_POOL) }; /** * Print the code as Java assembly language instructions */ String disassembleInlining() { byte codeBytes[] = new byte[3]; // Copy inlining into codeBytes[] buffer codeBytes[0] = (byte)(inlining & 0xff); codeBytes[1] = (byte)((inlining >> 8) & 0xff); codeBytes[2] = (byte)((inlining >> 16) & 0xff); return MethodInfo.disassemble(codeBytes, 0, 3); } private String myName; public String toString() { if (myName == null) { myName = method.parent.className + "." + method.name.string + method.type.string; } return myName; } static int total = 0; // After inlining some code, we try to see if we can remove code. For // example, the frequent case of opc_aload_0 invokeingored_quick #1 T can // simply "go away" final boolean compress () { MethodInfo mb = method; boolean rewritten = false; byte[] code = mb.code; int[] stack = new int[mb.stack + 1]; int stackHeight = 0; int nextpc; java.util.BitSet targets = mb.getLabelTargets(); for (int pc = 0; pc < code.length; pc = nextpc) { nextpc = pc + mb.opcodeLength(pc); int opcode = code[pc] & 0xff; int popping = 0; boolean checkThis = false; if (targets.get(pc)) { stackHeight = 0; } stack[stackHeight] = pc; // Invariant. the stackheight at this point is stackHeight or less. // // We can pop n items from the stack (where n <= stackHeight) by // simply deleting all the code from stackHeight[n] to this point // in the code. No side effects are removed. // // Note that instructions that have a side effect should set // stackHeight = 0, to indicate that it can't be deleted. switch (opcode) { case opc_nop: case opc_ineg: case opc_fneg: case opc_i2f: case opc_f2i: case opc_i2b: case opc_i2c: case opc_i2s: case opc_newarray: case opc_anewarray_quick: case opc_instanceof_quick: case opc_lneg: case opc_dneg: case opc_l2d: case opc_d2l: // these don't change stack height, and we know as much about // the stack before as we do after. break; 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_bipush: case opc_sipush: case opc_iload: case opc_fload: case opc_aload: case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3: case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3: case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3: case opc_ldc_quick: case opc_ldc_w_quick: case opc_aldc_quick: case opc_aldc_w_quick: case opc_aldc_ind_quick: case opc_aldc_ind_w_quick: case opc_getstatic_quick: case opc_agetstatic_quick: case opc_dup: // These push some value onto the stack, no matter what was // there before stackHeight += 1; break; case opc_lconst_0: case opc_lconst_1: case opc_dconst_0: case opc_dconst_1: case opc_lload: case opc_dload: case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3: case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3: case opc_ldc2_w_quick: case opc_getstatic2_quick: // These push two values onto the stack, no matter what was // there before. stackHeight += 2; break; case opc_i2l: case opc_i2d: case opc_f2l: case opc_f2d: // if we knew the top element of the stack, we know more stackHeight = (stackHeight < 1) ? 0 : stackHeight + 1; break; case opc_iadd: case opc_fadd: case opc_isub: case opc_fsub: case opc_imul: case opc_fmul: case opc_fdiv: case opc_frem: case opc_ishl: case opc_ishr: case opc_iushr: case opc_iand: case opc_ior: case opc_ixor: case opc_l2i: case opc_l2f: case opc_d2i: case opc_d2f: case opc_fcmpl: case opc_fcmpg: // if we knew the top two elements of the stack, the stack // has just shrunk stackHeight = (stackHeight < 2) ? 0 : stackHeight - 1; break; case opc_lshl: case opc_lshr: case opc_lushr: // if we knew the top three elements of the stack, we now // know the top two stackHeight = (stackHeight < 3) ? 0 : stackHeight - 1; break; case opc_lcmp: case opc_dcmpl: case opc_dcmpg: // if we knew the top 4 elements of the stack, we now // know the top element stackHeight = (stackHeight < 4) ? 0 : stackHeight - 3; break; case opc_ladd: case opc_dadd: case opc_lsub: case opc_dsub: case opc_lmul: case opc_dmul: case opc_ddiv: case opc_drem: case opc_land: case opc_lor: case opc_lxor: // if we knew the top 4 elements of the stack, we now // know the top 2 stackHeight = (stackHeight < 4) ? 0 : stackHeight - 2; break; // The dup's (other than opc_dup) deal with the stack in // a way that's not worth the hassle of dealing with. case opc_getfield_quick: case opc_agetfield_quick: case opc_arraylength: // If we throw away the result, then we just need to check that // the value is non-null. if (code[nextpc] == (byte)(opc_pop)) { checkThis = true; nextpc += 1; } else { stackHeight = 0; } break; case opc_pop2: popping++; // fall thru case opc_pop: // We have to be careful. The inliner may produce code that // does correspond to the stack. For example, it might // produce "pop pop2" to remove a double then an int. We need // to deal with series of them at once. if (stackHeight > 0) { popping++; for(;;) { opcode = code[++pc] & 0xFF; if (opcode == opc_pop) popping++; else if (opcode == opc_pop2) popping += 2; else break; } nextpc = pc; } break; case opc_invokeignored_quick: popping = code[pc + 1] & 0xff; if (code[pc + 2] != 0) { checkThis = true; popping--; } break; default: stackHeight = 0; } if (checkThis || (popping > 0 && stackHeight > 0)) { rewritten = true; if (stackHeight >= popping) { stackHeight -= popping; popping = 0; } else { popping -= stackHeight; stackHeight = 0; } int start = stack[stackHeight]; if (checkThis) { if (popping == 0 && (nextpc - start != 3)) { mb.replaceCode(start, nextpc, opc_nonnull_quick); } else { mb.replaceCode(start, nextpc, opc_invokeignored_quick, popping+1, 1); } stackHeight = 0; } else { switch (popping) { case 0: mb.replaceCode(start, nextpc); break; case 1: mb.replaceCode(start, nextpc, opc_pop); break; case 2: mb.replaceCode(start, nextpc, opc_pop2); break; default: mb.replaceCode(start, nextpc, opc_invokeignored_quick, popping, 0); break; } } } } return rewritten; } } /** * Class used for inlining info. See inlining code in MethodInfo */ class CVMOpcodeInfoType { int opcode; // really the opcode type int inStack; int outStack; static final int CAN_ERROR = 0x01; /* can give error in addition to NULL_CHECK */ static final int NULL_CHECK = 0x02; /* checks that first arg isn't null */ static final int CONSTANT_POOL = 0x04; /* uses the constant pool */ int flags; CVMOpcodeInfoType(int opcode, int inStack, int outStack, int flags) { this.opcode = opcode; this.inStack = inStack; this.outStack = outStack; this.flags = flags; } CVMOpcodeInfoType(int opcode, int inStack, int outStack) { this(opcode, inStack, outStack, 0); } CVMOpcodeInfoType(int opcode, int inStack) { this(opcode, inStack, 0, 0); } CVMOpcodeInfoType(int opcode) { this(opcode, 0, 0, 0); } };