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 + -
显示快捷键?