cvmmethodinfo.java

来自「This is a resource based on j2me embedde」· Java 代码 · 共 1,382 行 · 第 1/4 页

JAVA
1,382
字号
		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)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?