📄 evmmethodinfo.java
字号:
/* * EVMMethodInfo.java 1.6 01/04/27 SMI * * Copyright (c) 1999 Sun Microsystems, Inc. All Rights Reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. * * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING * THIS SOFTWARE OR ITS DERIVATIVES. * Use is subject to license terms. */package vm;/* * VM-specific internal representation of * a method. Target-machine independent. * * See also EVMClass for VM-specific info associated with each class. * See also EVMVM for VM-specific info not associated directly with any class. */import components.*;import vm.VMMethodInfo;import vm.Const;import vm.EVMConst;import util.DataFormatException;import java.util.Enumeration;import java.util.Vector;import java.util.Hashtable;import java.util.StringTokenizer;public classEVMMethodInfo extends VMMethodInfo implements Const, EVMConst { private boolean impureCode = false; private boolean mustAlign = false; private boolean codeExamined = false; public MethodInfo method; private String myNativeName; 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); /** Keep this var to make code look the same as in inline.c */ static final boolean UseLosslessQuickOpcodes = false; /** * 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 EVMMethodInfo( MethodInfo m ){ method = m; method.vmMethodInfo = this; } private void examineCode( ) throws DataFormatException { impureCode = false; mustAlign = 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_ldc: case opc_ldc_w: 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; } } 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; } private static int methodNumber = 0; public String getNativeName() { if ( myNativeName == null ){ // need to take parameter list into account. // OR just enumerate, as the actual name doesn't matter. // FIXME myNativeName = ((EVMClass)(method.parent.vmClass)).getNativeName()+ methodNumber; methodNumber+= 1; } return myNativeName; } public boolean hasBody(){ return ( (method.access & (ACC_ABSTRACT|ACC_NATIVE) )== 0 ); } public int EVMflags(){ int flagval = 0; int a = method.access; if ( (a&ACC_PUBLIC) != 0 ) flagval |= EVM_METHOD_ACC_PUBLIC; if ( (a&ACC_PRIVATE) != 0 ) flagval |= EVM_METHOD_ACC_PRIVATE; if ( (a&ACC_PROTECTED) != 0 ) flagval |= EVM_METHOD_ACC_PROTECTED; if ( (a&ACC_STATIC) != 0 ) flagval |= EVM_METHOD_ACC_STATIC; if ( (a&ACC_FINAL) != 0 ) flagval |= EVM_METHOD_ACC_FINAL; if ( (a&ACC_SYNCHRONIZED) != 0 ) flagval |= EVM_METHOD_ACC_SYNCHRONIZED; if ( (a&ACC_NATIVE) != 0 ) flagval |= EVM_METHOD_ACC_NATIVE; if ( (a&ACC_ABSTRACT) != 0 ) flagval |= EVM_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() { new Error().printStackTrace(); boolean isRewritten = false; if (inlineState == inline_NOT_DONE) { inlineState = inline_IN_PROGRESS; } else { return; } ConstantObject[] cp = method.parent.constants; 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_fast: case opc_invokespecial_fast: case opc_invokestatic_fast: { int index = method.getUnsignedShort(pc + 1); MethodConstant mc = (MethodConstant) cp[index]; VMMethodInfo targetMethod = mc.find().vmMethodInfo; rewrite = MethodCallInline(pc, (EVMMethodInfo)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, EVMMethodInfo mb) { byte code[] = method.code; int opcode = code[pc] & 0xff; if (opcode == opc_invokevirtual_fast) { /* 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; OpcodeInfoType 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_iadd: { /* any simple instruction */ int ilength = opcLengths[opcode]; int result; opcode2 = code[pc + ilength] & 0xff; if (!((opPtr.outStack > 0) ? isXreturn(opcode2) : (opcode2 == opc_return || opcode == opc_athrow))) return NO_INLINE_FLAG; if ((opPtr.flags & OpcodeInfoType.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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -