0001: /*
0002: *
0003: *
0004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: */
0026:
0027: package vm;
0028:
0029: /*
0030: * VM-specific internal representation of
0031: * a method. Target-machine independent.
0032: *
0033: * See also EVMClass for VM-specific info associated with each class.
0034: * See also EVMVM for VM-specific info not associated directly with any class.
0035: */
0036: import components.*;
0037: import vm.VMMethodInfo;
0038: import jcc.Const;
0039: import jcc.EVMConst;
0040: import util.DataFormatException;
0041: import java.util.Enumeration;
0042: import java.util.Vector;
0043: import java.util.Hashtable;
0044: import java.util.StringTokenizer;
0045:
0046: public class EVMMethodInfo extends VMMethodInfo implements Const,
0047: EVMConst {
0048: private boolean impureCode = false;
0049: private boolean mustAlign = false;
0050: private boolean codeExamined = false;
0051: public MethodInfo method;
0052:
0053: private String myNativeName;
0054:
0055: private int inlining;
0056: static final int NO_INLINE_FLAG = (0x1 << 24);
0057: static final int SAME_CLASS_FLAG = (0x1 << 25);
0058: static final int REDO_INLINING_FLAG = (0x1 << 26);
0059:
0060: /** Keep this var to make code look the same as in inline.c */
0061: static final boolean UseLosslessQuickOpcodes = false;
0062:
0063: /**
0064: * Flag used in quickenCode() to save old methodblock info so we can
0065: * use it here for inlining. This affects invokevirtual_quick which
0066: * typically overwrites the methodblock info with <methodtable offset>
0067: * and <nargs>.
0068: */
0069: public static final boolean SAVE_TARGET_METHODS = true;
0070:
0071: public EVMMethodInfo(MethodInfo m) {
0072: method = m;
0073: method.vmMethodInfo = this ;
0074: }
0075:
0076: private void examineCode() throws DataFormatException {
0077: impureCode = false;
0078: mustAlign = false;
0079: if (method.code == null) {
0080: codeExamined = true;
0081: return;
0082: }
0083: byte[] code = method.code;
0084: int ncode = code.length;
0085: int opcode;
0086: for (int i = 0; i < ncode; i += method.opcodeLength(i)) {
0087: switch (opcode = (int) code[i] & 0xff) {
0088:
0089: case opc_tableswitch:
0090: case opc_lookupswitch:
0091: mustAlign = true;
0092: break;
0093:
0094: case opc_ldc:
0095: case opc_ldc_w:
0096: case opc_ldc2_w:
0097: case opc_getstatic:
0098: case opc_putstatic:
0099: case opc_getfield:
0100: case opc_putfield:
0101: case opc_invokevirtual:
0102: case opc_invokespecial:
0103: case opc_invokestatic:
0104: case opc_invokeinterface:
0105: case opc_new:
0106: case opc_anewarray:
0107: case opc_checkcast:
0108: case opc_instanceof :
0109: case opc_multianewarray:
0110: impureCode = true; // all get quicked.
0111: break;
0112: }
0113: }
0114: codeExamined = true;
0115: }
0116:
0117: public boolean isCodePure() throws DataFormatException {
0118: if (!codeExamined) {
0119: examineCode(); // may throw exception without setting codeExamined
0120: }
0121: return !impureCode;
0122: }
0123:
0124: public int alignment() throws DataFormatException {
0125: if (!codeExamined) {
0126: examineCode(); // may throw exception without setting codeExamined
0127: }
0128: return mustAlign ? 4 : 1;
0129: }
0130:
0131: private static int methodNumber = 0;
0132:
0133: public String getNativeName() {
0134: if (myNativeName == null) {
0135: // need to take parameter list into account.
0136: // OR just enumerate, as the actual name doesn't matter.
0137: // IMPL_NOTE: consider whether this should be fixed.
0138: myNativeName = ((EVMClass) (method.parent.vmClass))
0139: .getNativeName()
0140: + methodNumber;
0141: methodNumber += 1;
0142: }
0143: return myNativeName;
0144: }
0145:
0146: public boolean hasBody() {
0147: return ((method.access & (ACC_ABSTRACT | ACC_NATIVE)) == 0);
0148: }
0149:
0150: public int EVMflags() {
0151: int flagval = 0;
0152: int a = method.access;
0153: if ((a & ACC_PUBLIC) != 0)
0154: flagval |= EVM_METHOD_ACC_PUBLIC;
0155: if ((a & ACC_PRIVATE) != 0)
0156: flagval |= EVM_METHOD_ACC_PRIVATE;
0157: if ((a & ACC_PROTECTED) != 0)
0158: flagval |= EVM_METHOD_ACC_PROTECTED;
0159: if ((a & ACC_STATIC) != 0)
0160: flagval |= EVM_METHOD_ACC_STATIC;
0161: if ((a & ACC_FINAL) != 0)
0162: flagval |= EVM_METHOD_ACC_FINAL;
0163: if ((a & ACC_SYNCHRONIZED) != 0)
0164: flagval |= EVM_METHOD_ACC_SYNCHRONIZED;
0165: if ((a & ACC_NATIVE) != 0)
0166: flagval |= EVM_METHOD_ACC_NATIVE;
0167: if ((a & ACC_ABSTRACT) != 0)
0168: flagval |= EVM_METHOD_ACC_ABSTRACT;
0169: return flagval;
0170:
0171: }
0172:
0173: public int methodOffset() {
0174: int off = method.methodTableIndex;
0175: if (off < 0) {
0176: /*
0177: * off < 0 means that we do not have a methodtable or
0178: * imethodtable entry for this method. This is ok if it is:
0179: * - private, or
0180: * - static, or
0181: * - <init>
0182: * Otherwise, this is an error.
0183: */
0184: if (method.isStaticMember() || method.isPrivateMember()
0185: || method.name.string.equals("<init>")) {
0186: return 0;
0187: } else {
0188: throw new Error("Bad method offset for "
0189: + method.qualifiedName());
0190: }
0191: }
0192: return off;
0193: }
0194:
0195: /** Attempt to inline the code of this method */
0196: final static int inline_NOT_DONE = 0;
0197: final static int inline_IN_PROGRESS = 1;
0198: final static int inline_DONE = 2;
0199:
0200: private int inlineState = inline_NOT_DONE;
0201:
0202: public void inlineCode() {
0203: new Error().printStackTrace();
0204:
0205: boolean isRewritten = false;
0206: if (inlineState == inline_NOT_DONE) {
0207: inlineState = inline_IN_PROGRESS;
0208: } else {
0209: return;
0210: }
0211: ConstantObject[] cp = method.parent.constants;
0212: byte[] code = method.code;
0213: byte[] rewrite;
0214: int tmi = 0; // target method index
0215:
0216: for (int pc = 0; pc < code.length;) {
0217: int opcode = code[pc] & 0xff;
0218:
0219: switch (opcode) {
0220:
0221: case opc_invokevirtual_fast:
0222: case opc_invokespecial_fast:
0223: case opc_invokestatic_fast: {
0224: int index = method.getUnsignedShort(pc + 1);
0225: MethodConstant mc = (MethodConstant) cp[index];
0226: VMMethodInfo targetMethod = mc.find().vmMethodInfo;
0227: rewrite = MethodCallInline(pc,
0228: (EVMMethodInfo) targetMethod);
0229: if (rewrite != null) {
0230: isRewritten = true;
0231: System.arraycopy(rewrite, 0, code, pc, 3);
0232: }
0233: pc += 3;
0234: break;
0235: }
0236:
0237: default:
0238: pc += method.opcodeLength(pc);
0239: break;
0240: }
0241: }
0242: if (isRewritten)
0243: compress();
0244: inlineState = inline_DONE;
0245: }
0246:
0247: /* This method is called to determine whether the method "mb" called at
0248: * from instruction "pc" can be inlined. If not, the value null is
0249: * returned. If so, an array of three bytes, which should overwrite the
0250: * method invocation, is returned
0251: */
0252: private byte[] MethodCallInline(int pc, EVMMethodInfo mb) {
0253: byte code[] = method.code;
0254: int opcode = code[pc] & 0xff;
0255:
0256: if (opcode == opc_invokevirtual_fast) {
0257: /* This is a virtual method call. No use even bother trying to
0258: * inline the method, unless its final
0259: */
0260: if (((mb.method.access & ACC_FINAL) == 0)
0261: && ((mb.method.parent.access & ACC_FINAL) == 0))
0262: return null;
0263: }
0264:
0265: int mbInlining = mb.getInlining();
0266: if ((mbInlining & NO_INLINE_FLAG) != 0)
0267: return null;
0268: /* Does this inlining have a dependency on the constant pool, and so
0269: * can only be used on a method in the same class. */
0270: if ((mbInlining & SAME_CLASS_FLAG) != 0) {
0271: if (this .method.parent != mb.method.parent)
0272: return null;
0273: }
0274: /* There is a inlining. Copy that value into "result" */
0275: byte[] result = new byte[3];
0276: result[0] = INLINING_WORD1(mbInlining);
0277: result[1] = INLINING_WORD2(mbInlining);
0278: result[2] = INLINING_WORD3(mbInlining);
0279: return result;
0280: }
0281:
0282: public int getInlining() {
0283: MethodInfo mi = this .method;
0284: if (inlining == 0) {
0285: if (((mi.access & (ACC_ABSTRACT | ACC_NATIVE | ACC_SYNCHRONIZED)) != 0)
0286: || (mi.exceptionTable.length > 0)) {
0287: inlining = NO_INLINE_FLAG;
0288: } else {
0289: inlineCode();
0290: inlining = calculateInlining();
0291:
0292: /*******
0293: if (inlining != NO_INLINE_FLAG) {
0294: String sameClass =
0295: ((inlining & SAME_CLASS_FLAG) != 0) ? "*" : "";
0296: System.out.print("get: " + this + " =>" + sameClass);
0297: System.out.println(" " + disassembleInlining());
0298: }
0299: ********/
0300: }
0301: }
0302: return inlining;
0303: }
0304:
0305: /* Given a method, determine if it can be "inlined" into three or fewer
0306: * bytes.
0307: */
0308: private int calculateInlining() {
0309: MethodInfo mb = this .method;
0310: byte[] code = mb.code;
0311:
0312: /* The checkThis flag indicates that the resulting code must
0313: * throw a NullPointerException if the first argument is null
0314: */
0315: boolean checkThis = ((mb.access & ACC_STATIC) == 0)
0316: && !method.name.string.equals("<init>");
0317:
0318: boolean redoInlining = false;
0319: int stackSize, stackBase;
0320: OpcodeInfoType opPtr;
0321:
0322: stackSize = 0;
0323: stackBase = 0; // Prevent javac warning
0324: for (int pc = 0;; pc++) {
0325: /* At this point in our simulation of the execution of the
0326: * method, registers stackBase .. stackBase+stackSize - 1 are
0327: * pushed onto the the stack. pc points to the next
0328: * instruction to look at.
0329: */
0330: int opcode = code[pc] & 0xff;
0331: int opcode2;
0332: int reg, regSize, nextReg;
0333:
0334: if (stackSize == 0)
0335: stackBase = 0;
0336: nextReg = stackBase + stackSize;
0337: opPtr = OpcodeInfo[opcode];
0338:
0339: switch (opPtr.opcode) {
0340:
0341: case opc_iload_0: /* register load. regnum from opcode */
0342: case opc_iload: /* register load. regnum from pc[1] */
0343: if (opPtr.opcode == opc_iload_0) {
0344: reg = REGNUM(opPtr);
0345: } else {
0346: reg = code[pc + 1] & 0xff;
0347: pc++;
0348: }
0349: regSize = REGSIZE(opPtr);
0350: if (stackSize == 0) /* stack is currently empty */
0351: stackBase = reg;
0352: else if (nextReg != reg)
0353: return NO_INLINE_FLAG;
0354: stackSize += regSize;
0355: continue;
0356:
0357: case opc_pop: /* pop stack, or nop */
0358: stackSize -= REGSIZE(opPtr);
0359: continue;
0360:
0361: case opc_nonnull_quick: /* special instruction */
0362: if (nextReg == 1) {
0363: /* We're checking register 0 to ensure that it isn't null */
0364: stackSize = 0;
0365: checkThis = true;
0366: continue;
0367: }
0368: return NO_INLINE_FLAG;
0369:
0370: case opc_invokeignored_quick: /* special instruction */
0371: {
0372: int popCount = code[pc + 1] & 0xff;
0373: if (code[pc + 2] != 0) {
0374: /* We only know how to check register 0 for non-null ness */
0375: if (nextReg != popCount)
0376: return NO_INLINE_FLAG;
0377: checkThis = true;
0378: stackSize -= popCount;
0379: } else {
0380: stackSize -= popCount;
0381: }
0382: pc += 2;
0383: continue;
0384: }
0385:
0386: case opc_return: /* return void or value */
0387: return makeReturnResult(checkThis, nextReg,
0388: REGSIZE(opPtr));
0389:
0390: case opc_iadd: { /* any simple instruction */
0391: int ilength = opcLengths[opcode];
0392: int result;
0393: opcode2 = code[pc + ilength] & 0xff;
0394:
0395: if (!((opPtr.outStack > 0) ? isXreturn(opcode2)
0396: : (opcode2 == opc_return || opcode == opc_athrow)))
0397: return NO_INLINE_FLAG;
0398:
0399: if ((opPtr.flags & OpcodeInfoType.NULL_CHECK) != 0
0400: && (stackBase == 0)) {
0401: /* We don't need to generate code to check for null, since
0402: * the instruction already does it.
0403: */
0404: checkThis = false;
0405: }
0406: switch (ilength) {
0407: case 1:
0408: result = makeOpcodeResult(checkThis, nextReg,
0409: opPtr.inStack, 1, opcode, 0, 0);
0410: break;
0411: case 2:
0412: result = makeOpcodeResult(checkThis, nextReg,
0413: opPtr.inStack, 2, opcode,
0414: code[pc + 1] & 0xff, 0);
0415: break;
0416: case 3:
0417: result = makeOpcodeResult(checkThis, nextReg,
0418: opPtr.inStack, 3, opcode,
0419: code[pc + 1] & 0xff, code[pc + 2] & 0xff);
0420: break;
0421: default:
0422: throw new RuntimeException("sysAssert(FALSE);");
0423: // result = NO_INLINE_FLAG; // not reached
0424: // break; // not reached
0425: }
0426: if ((result & NO_INLINE_FLAG) == 0) {
0427: if ((opPtr.flags & OpcodeInfoType.CONSTANT_POOL) != 0)
0428: result |= SAME_CLASS_FLAG;
0429: if (redoInlining)
0430: result |= REDO_INLINING_FLAG;
0431: }
0432: return result;
0433: }
0434:
0435: default:
0436: throw new RuntimeException("sysAssert(FALSE);");
0437: case 255: /* random instruction */
0438: return NO_INLINE_FLAG;
0439:
0440: } /* of switch statement */
0441: } /* end of for loop */
0442: }
0443:
0444: /* This method is called to create the code that is actually going to
0445: * replace the indicated method, when the method does nothing, or when
0446: * it simply returns one of its arguments.
0447: *
0448: * It takes the following arguments:
0449: * mb: Method we are examining
0450: * checkThis: If true, We must specially check that the first argument
0451: * "this" isn't null.
0452: * highReg, One greater than the highest register on the stack when
0453: * the return or Xreturn is called.
0454: * returnSize Size of the return (0 for return, 1 for ireturn,
0455: * 2 for lreturn, etc);
0456: *
0457: * We have to emulate the method call in 3 bytes. At the time the
0458: * method is called, the arguments reg[0] . . . reg[mb->args_size - 1]
0459: * are pushed on the stack.
0460: */
0461: static int[] poppers = { opc_nop, opc_pop, opc_pop2 };
0462:
0463: private int makeReturnResult(boolean checkThis, int highReg,
0464: int returnSize) {
0465: MethodInfo mb = method;
0466: int argsSize = mb.argsSize;
0467: if (returnSize == 0) {
0468: /* Return void */
0469: return MAKE_INLINING(opc_invokeignored_quick, argsSize,
0470: (checkThis ? 1 : 0));
0471: } else {
0472: /* Return some value from the stack */
0473: int returnReg = highReg - returnSize;
0474: int excessArgs = argsSize - returnSize - returnReg;
0475: // sysAssert(returnReg >= 0 && returnSize >= 0);
0476: if (returnReg == 0) {
0477: /* Returning reg0 or reg0/reg1 */
0478: if (checkThis) {
0479: /* Must be returning reg0, which is also checked. We
0480: * require argsSize >= 2 (which is the same thing as
0481: * excessArgs >= 1), because otherwise the "dup" might
0482: * overflow the stack. More sophisticated inliners
0483: * might see if there is space on the caller's stack.
0484: */
0485: // sysAssert(returnSize == 1);
0486: if (argsSize < 2) {
0487: return NO_INLINE_FLAG;
0488: } else if (excessArgs > 2) {
0489: return NO_INLINE_FLAG;
0490: } else {
0491: return MAKE_INLINING(poppers[excessArgs],
0492: opc_dup, opc_nonnull_quick);
0493: }
0494: } else {
0495: /* We're returning reg0 or reg0/reg1 which isn't null
0496: * checked. We just pop extraneous stuff off the stack
0497: * */
0498: return MAKE_INLINING(opc_invokeignored_quick,
0499: excessArgs, 0);
0500: }
0501: } else {
0502: /* At this point, returnReg > 0. We're returning something
0503: * other than the bottom of the stack.
0504: */
0505: if (returnSize == 1 && returnReg == 1) {
0506: if (excessArgs > 2) {
0507: return NO_INLINE_FLAG;
0508: }
0509: return MAKE_INLINING(poppers[excessArgs], opc_swap,
0510: checkThis ? opc_nonnull_quick : opc_pop);
0511: }
0512: return NO_INLINE_FLAG;
0513: }
0514: }
0515: }
0516:
0517: /* This method is called to create the code that is actually going to
0518: * replace the indicated method
0519: *
0520: * makeOpcodeResult is used to create a inlining that can be used anywhere
0521: * It takes the following arguments:
0522: *
0523: * mb: Method we are examining
0524: * checkThis: If true, We must specially check that the first argument
0525: * "this" isn't null. This condition is >>NOT<< tested by
0526: * the generated code.
0527: * nextReg: In the emulation, the highest register on the stack is
0528: * reg[nextReg - 1].
0529: * icount The number of bytes of instructions that follow.
0530: * opcode, op1, op2
0531: * The bytes of instruction.
0532: *
0533: * We have to emulate the method call in 3 bytes. At the time the
0534: * method is called, the arguments reg[0] . . . reg[mb->args_size - 1]
0535: * are pushed on the stack. So in three bytes, we have to:
0536: * Remove any excess arguments from the stack.
0537: * Perform the operation on the indicated stack registers
0538: * Remove any objects lower down on the stack (this is hard!)
0539: * Make sure that reg[0] is checked for being non-null, if necessary.
0540: */
0541: private int makeOpcodeResult(boolean checkThis, int nextReg,
0542: int opcodeArgCount, int icount, int opcode, int op1, int op2) {
0543: MethodInfo mb = method;
0544: int firstReg = (opcodeArgCount == 0) ? 0 : nextReg
0545: - opcodeArgCount;
0546: // sysAssert(firstReg >= 0 && opcodeArgCount >= 0 && icount > 0);
0547:
0548: if (firstReg > 0) {
0549: /* There are extra registers at the bottom of the stack */
0550: return makePoppingResult(checkThis, firstReg,
0551: opcodeArgCount, icount, opcode, op1, op2);
0552: } else {
0553: /* No extra registers at bottom of stack */
0554: int argsSize = mb.argsSize;
0555: int excessArgs = argsSize - opcodeArgCount; /* extra at top */
0556: int popSpace = 3 - icount; /* space to pop args at top */
0557:
0558: int result = 0;
0559: int i;
0560:
0561: if (checkThis) {
0562: /* Unless this is a constant method that ignores all of its
0563: * arguments, we don't really have any way of checking
0564: * register 0 if the instructions doesn't. If it is a
0565: * constant instruction, deduct one from both popSpace and
0566: * from excessArgs, since we are popping that last argument
0567: * when an opc_nonnull_quick;
0568: */
0569: if (opcodeArgCount > 0 || popSpace == 0)
0570: return NO_INLINE_FLAG;
0571: popSpace--;
0572: excessArgs--;
0573: // sysAssert(excessArgs >= 0);
0574: }
0575: if (excessArgs > 2 * popSpace)
0576: return NO_INLINE_FLAG;
0577: for (i = 0; i < popSpace; i++) {
0578: /* If excessArgs <= popSpace, the following generates excessArgs
0579: * "pops" followed by nops. Otherwise, it generates
0580: * excessArgs - popSpace pop2's followed by pop's.
0581: */
0582: int opcodeTmp = (excessArgs <= i) ? opc_nop
0583: : (excessArgs <= popSpace + i) ? opc_pop
0584: : opc_pop2;
0585: result |= (opcodeTmp << (i << 3));
0586: }
0587: if (checkThis)
0588: result |= opc_nonnull_quick << ((i++) << 3);
0589: // sysAssert(i + icount == 3);
0590: switch (icount) {
0591: case 3:
0592: result |= op2 << ((i + 2) << 3);
0593: case 2:
0594: result |= op1 << ((i + 1) << 3);
0595: case 1:
0596: result |= opcode << ((i + 0) << 3);
0597: }
0598: return result;
0599: }
0600: }
0601:
0602: /*
0603: * Called by makeOpcodeResult.
0604: * Same arguments. But there are extra arguments on the bottom to pop.
0605: */
0606: private int makePoppingResult(boolean checkThis, int firstReg,
0607: int opcodeArgCount, int icount, int opcode, int op1, int op2) {
0608: MethodInfo mb = method;
0609: int argsSize = mb.argsSize;
0610: int excessArgs = argsSize - opcodeArgCount - firstReg; /* extra on top*/
0611:
0612: if (icount > 1)
0613: /* We're just not prepared to deal with this. */
0614: return NO_INLINE_FLAG;
0615:
0616: if (OpcodeInfo[opcode].outStack == 0) {
0617: int result = 0;
0618: /* Something like an array store, that leaves no value on the
0619: stack */
0620: int i = 0;
0621: /* We can't deal with checkThis, since it might reverse the order of
0622: * an exception. We have a total of two instructions to do all the
0623: * pre and post popping.
0624: */
0625: if (checkThis
0626: || ((excessArgs + 1) / 2 + (firstReg + 1) / 2) > 2)
0627: return NO_INLINE_FLAG;
0628: for (; excessArgs > 0; excessArgs -= 2)
0629: /* pre popping */
0630: result |= (excessArgs == 1 ? opc_pop : opc_pop2) << ((i++) << 3);
0631: result |= opcode << ((i++) << 3);
0632: for (; firstReg > 0; firstReg -= 2)
0633: /* post popping */
0634: result |= (firstReg == 1 ? opc_pop : opc_pop2) << ((i++) << 3);
0635: while (i < 3)
0636: result |= opc_nop << ((i++) << 3);
0637: return result;
0638: }
0639:
0640: if (excessArgs > 0 || firstReg > 1)
0641: /* We can't both do useful work and remove more than this many
0642: * items from the stack. */
0643: return NO_INLINE_FLAG;
0644:
0645: if (opcodeArgCount == 1) {
0646: return MAKE_INLINING(opc_swap,
0647: checkThis ? opc_nonnull_quick : opc_pop, opcode);
0648: }
0649: if (((OpcodeInfo[opcode].flags & (OpcodeInfoType.NULL_CHECK | OpcodeInfoType.CAN_ERROR)) == 0)
0650: && (OpcodeInfo[opcode].outStack == 1)) {
0651: /* The result creates one thing on the stack, and it can't error */
0652: return MAKE_INLINING(opcode, opc_swap,
0653: checkThis ? opc_nonnull_quick : opc_pop);
0654: }
0655: return NO_INLINE_FLAG;
0656: }
0657:
0658: private static boolean isXreturn(int opcode) {
0659: return (opcode >= opc_ireturn) && (opcode <= opc_areturn);
0660: }
0661:
0662: private static byte INLINING_WORD1(int simp) {
0663: return (byte) (simp & 0xFF);
0664: }
0665:
0666: private static byte INLINING_WORD2(int simp) {
0667: return (byte) ((simp >> 8) & 0xFF);
0668: }
0669:
0670: private static byte INLINING_WORD3(int simp) {
0671: return (byte) ((simp >> 16) & 0xFF);
0672: }
0673:
0674: private static int MAKE_INLINING(int op1, int op2, int op3) {
0675: return (op1 << 0) + (op2 << 8) + (op3 << 16);
0676: }
0677:
0678: private static int REGSIZE(OpcodeInfoType ptr) {
0679: return (ptr.inStack);
0680: }
0681:
0682: private static int REGNUM(OpcodeInfoType ptr) {
0683: return (ptr.outStack);
0684: }
0685:
0686: static OpcodeInfoType[] OpcodeInfo = {
0687: /* { opc_pop <number of words to pop from stack> }
0688: * { opc_iadd <words popped from stack> <words pushed to stack> }
0689: * { opc_iload <words pushed to stack> }
0690: * { opc_iload_0 <words pushed to stack> <implicit register> }
0691: * { opc_return <words returned> }
0692: * 255 indicates opcode that we can't inline
0693: * other values are special opcodes that must be handled specially
0694: */
0695:
0696: /* nop */new OpcodeInfoType(opc_pop, 0),
0697: /* aconst_null */new OpcodeInfoType(opc_iadd, 0, 1),
0698: /* iconst_m1 */new OpcodeInfoType(opc_iadd, 0, 1),
0699: /* iconst_0 */new OpcodeInfoType(opc_iadd, 0, 1),
0700: /* iconst_1 */new OpcodeInfoType(opc_iadd, 0, 1),
0701: /* iconst_2 */new OpcodeInfoType(opc_iadd, 0, 1),
0702: /* iconst_3 */new OpcodeInfoType(opc_iadd, 0, 1),
0703: /* iconst_4 */new OpcodeInfoType(opc_iadd, 0, 1),
0704: /* iconst_5 */new OpcodeInfoType(opc_iadd, 0, 1),
0705: /* lconst_0 */new OpcodeInfoType(opc_iadd, 0, 2),
0706: /* lconst_1 */new OpcodeInfoType(opc_iadd, 0, 2),
0707: /* fconst_0 */new OpcodeInfoType(opc_iadd, 0, 1),
0708: /* fconst_1 */new OpcodeInfoType(opc_iadd, 0, 1),
0709: /* fconst_2 */new OpcodeInfoType(opc_iadd, 0, 1),
0710: /* dconst_0 */new OpcodeInfoType(opc_iadd, 0, 2),
0711: /* dconst_1 */new OpcodeInfoType(opc_iadd, 0, 2),
0712: /* bipush */new OpcodeInfoType(opc_iadd, 0, 1),
0713: /* sipush */new OpcodeInfoType(opc_iadd, 0, 1),
0714: /* ldc */new OpcodeInfoType(255),
0715: /* ldc_w */new OpcodeInfoType(255),
0716: /* ldc2_w */new OpcodeInfoType(255),
0717: /* iload */new OpcodeInfoType(opc_iload, 1),
0718: /* lload */new OpcodeInfoType(opc_iload, 2),
0719: /* fload */new OpcodeInfoType(opc_iload, 1),
0720: /* dload */new OpcodeInfoType(opc_iload, 2),
0721: /* aload */new OpcodeInfoType(opc_iload, 1),
0722: /* iload_0 */new OpcodeInfoType(opc_iload_0, 1,
0723: 0),
0724: /* iload_1 */new OpcodeInfoType(opc_iload_0, 1,
0725: 1),
0726: /* iload_2 */new OpcodeInfoType(opc_iload_0, 1,
0727: 2),
0728: /* iload_3 */new OpcodeInfoType(opc_iload_0, 1,
0729: 3),
0730: /* lload_0 */new OpcodeInfoType(opc_iload_0, 2,
0731: 0),
0732: /* lload_1 */new OpcodeInfoType(opc_iload_0, 2,
0733: 1),
0734: /* lload_2 */new OpcodeInfoType(opc_iload_0, 2,
0735: 2),
0736: /* lload_3 */new OpcodeInfoType(opc_iload_0, 2,
0737: 3),
0738: /* fload_0 */new OpcodeInfoType(opc_iload_0, 1,
0739: 0),
0740: /* fload_1 */new OpcodeInfoType(opc_iload_0, 1,
0741: 1),
0742: /* fload_2 */new OpcodeInfoType(opc_iload_0, 1,
0743: 2),
0744: /* fload_3 */new OpcodeInfoType(opc_iload_0, 1,
0745: 3),
0746: /* dload_0 */new OpcodeInfoType(opc_iload_0, 2,
0747: 0),
0748: /* dload_1 */new OpcodeInfoType(opc_iload_0, 2,
0749: 1),
0750: /* dload_2 */new OpcodeInfoType(opc_iload_0, 2,
0751: 2),
0752: /* dload_3 */new OpcodeInfoType(opc_iload_0, 2,
0753: 3),
0754: /* aload_0 */new OpcodeInfoType(opc_iload_0, 1,
0755: 0),
0756: /* aload_1 */new OpcodeInfoType(opc_iload_0, 1,
0757: 1),
0758: /* aload_2 */new OpcodeInfoType(opc_iload_0, 1,
0759: 2),
0760: /* aload_3 */new OpcodeInfoType(opc_iload_0, 1,
0761: 3),
0762: /* iaload */new OpcodeInfoType(opc_iadd, 2, 1,
0763: OpcodeInfoType.NULL_CHECK),
0764: /* laload */new OpcodeInfoType(opc_iadd, 2, 2,
0765: OpcodeInfoType.NULL_CHECK),
0766: /* faload */new OpcodeInfoType(opc_iadd, 2, 1,
0767: OpcodeInfoType.NULL_CHECK),
0768: /* daload */new OpcodeInfoType(opc_iadd, 2, 2,
0769: OpcodeInfoType.NULL_CHECK),
0770: /* aaload */new OpcodeInfoType(opc_iadd, 2, 1,
0771: OpcodeInfoType.NULL_CHECK),
0772: /* baload */new OpcodeInfoType(opc_iadd, 2, 1,
0773: OpcodeInfoType.NULL_CHECK),
0774: /* caload */new OpcodeInfoType(opc_iadd, 2, 1,
0775: OpcodeInfoType.NULL_CHECK),
0776: /* saload */new OpcodeInfoType(opc_iadd, 2, 1,
0777: OpcodeInfoType.NULL_CHECK),
0778: /* istore */new OpcodeInfoType(255),
0779: /* lstore */new OpcodeInfoType(255),
0780: /* fstore */new OpcodeInfoType(255),
0781: /* dstore */new OpcodeInfoType(255),
0782: /* astore */new OpcodeInfoType(255),
0783: /* istore_0 */new OpcodeInfoType(255),
0784: /* istore_1 */new OpcodeInfoType(255),
0785: /* istore_2 */new OpcodeInfoType(255),
0786: /* istore_3 */new OpcodeInfoType(255),
0787: /* lstore_0 */new OpcodeInfoType(255),
0788: /* lstore_1 */new OpcodeInfoType(255),
0789: /* lstore_2 */new OpcodeInfoType(255),
0790: /* lstore_3 */new OpcodeInfoType(255),
0791: /* fstore_0 */new OpcodeInfoType(255),
0792: /* fstore_1 */new OpcodeInfoType(255),
0793: /* fstore_2 */new OpcodeInfoType(255),
0794: /* fstore_3 */new OpcodeInfoType(255),
0795: /* dstore_0 */new OpcodeInfoType(255),
0796: /* dstore_1 */new OpcodeInfoType(255),
0797: /* dstore_2 */new OpcodeInfoType(255),
0798: /* dstore_3 */new OpcodeInfoType(255),
0799: /* astore_0 */new OpcodeInfoType(255),
0800: /* astore_1 */new OpcodeInfoType(255),
0801: /* astore_2 */new OpcodeInfoType(255),
0802: /* astore_3 */new OpcodeInfoType(255),
0803: /* iastore */new OpcodeInfoType(opc_iadd, 3, 0,
0804: OpcodeInfoType.NULL_CHECK),
0805: /* lastore */new OpcodeInfoType(opc_iadd, 4, 0,
0806: OpcodeInfoType.NULL_CHECK),
0807: /* fastore */new OpcodeInfoType(opc_iadd, 3, 0,
0808: OpcodeInfoType.NULL_CHECK),
0809: /* dastore */new OpcodeInfoType(opc_iadd, 4, 0,
0810: OpcodeInfoType.NULL_CHECK),
0811: /* aastore */new OpcodeInfoType(opc_iadd, 3, 0,
0812: OpcodeInfoType.NULL_CHECK),
0813: /* bastore */new OpcodeInfoType(opc_iadd, 3, 0,
0814: OpcodeInfoType.NULL_CHECK),
0815: /* castore */new OpcodeInfoType(opc_iadd, 3, 0,
0816: OpcodeInfoType.NULL_CHECK),
0817: /* sastore */new OpcodeInfoType(opc_iadd, 3, 0,
0818: OpcodeInfoType.NULL_CHECK),
0819: /* pop */new OpcodeInfoType(opc_pop, 1),
0820: /* pop2 */new OpcodeInfoType(opc_pop, 2),
0821: /* dup */new OpcodeInfoType(255),
0822: /* dup_x1 */new OpcodeInfoType(255),
0823: /* dup_x2 */new OpcodeInfoType(255),
0824: /* dup2 */new OpcodeInfoType(255),
0825: /* dup2_x1 */new OpcodeInfoType(255),
0826: /* dup2_x2 */new OpcodeInfoType(255),
0827: /* swap */new OpcodeInfoType(255),
0828: /* iadd */new OpcodeInfoType(opc_iadd, 2, 1),
0829: /* ladd */new OpcodeInfoType(opc_iadd, 4, 2),
0830: /* fadd */new OpcodeInfoType(opc_iadd, 2, 1),
0831: /* dadd */new OpcodeInfoType(opc_iadd, 4, 2),
0832: /* isub */new OpcodeInfoType(opc_iadd, 2, 1),
0833: /* lsub */new OpcodeInfoType(opc_iadd, 4, 2),
0834: /* fsub */new OpcodeInfoType(opc_iadd, 2, 1),
0835: /* dsub */new OpcodeInfoType(opc_iadd, 4, 2),
0836: /* imul */new OpcodeInfoType(opc_iadd, 2, 1),
0837: /* lmul */new OpcodeInfoType(opc_iadd, 4, 2),
0838: /* fmul */new OpcodeInfoType(opc_iadd, 2, 1),
0839: /* dmul */new OpcodeInfoType(opc_iadd, 4, 2),
0840: /* idiv */new OpcodeInfoType(opc_iadd, 2, 1,
0841: OpcodeInfoType.CAN_ERROR),
0842: /* ldiv */new OpcodeInfoType(opc_iadd, 4, 2,
0843: OpcodeInfoType.CAN_ERROR),
0844: /* fdiv */new OpcodeInfoType(opc_iadd, 2, 1),
0845: /* ddiv */new OpcodeInfoType(opc_iadd, 4, 2),
0846: /* irem */new OpcodeInfoType(opc_iadd, 2, 1,
0847: OpcodeInfoType.CAN_ERROR),
0848: /* lrem */new OpcodeInfoType(opc_iadd, 4, 2,
0849: OpcodeInfoType.CAN_ERROR),
0850: /* frem */new OpcodeInfoType(opc_iadd, 2, 1),
0851: /* drem */new OpcodeInfoType(opc_iadd, 4, 2),
0852: /* ineg */new OpcodeInfoType(opc_iadd, 1, 1),
0853: /* lneg */new OpcodeInfoType(opc_iadd, 2, 2),
0854: /* fneg */new OpcodeInfoType(opc_iadd, 1, 1),
0855: /* dneg */new OpcodeInfoType(opc_iadd, 2, 2),
0856: /* ishl */new OpcodeInfoType(opc_iadd, 2, 1),
0857: /* lshl */new OpcodeInfoType(opc_iadd, 3, 2),
0858: /* ishr */new OpcodeInfoType(opc_iadd, 2, 1),
0859: /* lshr */new OpcodeInfoType(opc_iadd, 3, 2),
0860: /* iushr */new OpcodeInfoType(opc_iadd, 2, 1),
0861: /* lushr */new OpcodeInfoType(opc_iadd, 3, 2),
0862: /* iand */new OpcodeInfoType(opc_iadd, 2, 1),
0863: /* land */new OpcodeInfoType(opc_iadd, 4, 2),
0864: /* ior */new OpcodeInfoType(opc_iadd, 2, 1),
0865: /* lor */new OpcodeInfoType(opc_iadd, 4, 2),
0866: /* ixor */new OpcodeInfoType(opc_iadd, 2, 1),
0867: /* lxor */new OpcodeInfoType(opc_iadd, 4, 2),
0868: /* iinc */new OpcodeInfoType(255),
0869: /* i2l */new OpcodeInfoType(opc_iadd, 1, 2),
0870: /* i2f */new OpcodeInfoType(opc_iadd, 1, 1),
0871: /* i2d */new OpcodeInfoType(opc_iadd, 1, 2),
0872: /* l2i */new OpcodeInfoType(opc_iadd, 2, 1),
0873: /* l2f */new OpcodeInfoType(opc_iadd, 2, 1),
0874: /* l2d */new OpcodeInfoType(opc_iadd, 2, 2),
0875: /* f2i */new OpcodeInfoType(opc_iadd, 1, 1),
0876: /* f2l */new OpcodeInfoType(opc_iadd, 1, 2),
0877: /* f2d */new OpcodeInfoType(opc_iadd, 1, 2),
0878: /* d2i */new OpcodeInfoType(opc_iadd, 2, 1),
0879: /* d2l */new OpcodeInfoType(opc_iadd, 2, 2),
0880: /* d2f */new OpcodeInfoType(opc_iadd, 2, 1),
0881: /* i2b */new OpcodeInfoType(opc_iadd, 1, 1),
0882: /* i2c */new OpcodeInfoType(opc_iadd, 1, 1),
0883: /* i2s */new OpcodeInfoType(opc_iadd, 1, 1),
0884: /* lcmp */new OpcodeInfoType(opc_iadd, 4, 1),
0885: /* fcmpl */new OpcodeInfoType(opc_iadd, 2, 1),
0886: /* fcmpg */new OpcodeInfoType(opc_iadd, 2, 1),
0887: /* dcmpl */new OpcodeInfoType(opc_iadd, 4, 1),
0888: /* dcmpg */new OpcodeInfoType(opc_iadd, 4, 1),
0889: /* ifeq */new OpcodeInfoType(255),
0890: /* ifne */new OpcodeInfoType(255),
0891: /* iflt */new OpcodeInfoType(255),
0892: /* ifge */new OpcodeInfoType(255),
0893: /* ifgt */new OpcodeInfoType(255),
0894: /* ifle */new OpcodeInfoType(255),
0895: /* if_icmpeq */new OpcodeInfoType(255),
0896: /* if_icmpne */new OpcodeInfoType(255),
0897: /* if_icmplt */new OpcodeInfoType(255),
0898: /* if_icmpge */new OpcodeInfoType(255),
0899: /* if_icmpgt */new OpcodeInfoType(255),
0900: /* if_icmple */new OpcodeInfoType(255),
0901: /* if_acmpeq */new OpcodeInfoType(255),
0902: /* if_acmpne */new OpcodeInfoType(255),
0903: /* goto */new OpcodeInfoType(255),
0904: /* jsr */new OpcodeInfoType(255),
0905: /* ret */new OpcodeInfoType(255),
0906: /* tableswitch */new OpcodeInfoType(255),
0907: /* lookupswitch */new OpcodeInfoType(255),
0908: /* ireturn */new OpcodeInfoType(opc_return, 1),
0909: /* lreturn */new OpcodeInfoType(opc_return, 2),
0910: /* freturn */new OpcodeInfoType(opc_return, 1),
0911: /* dreturn */new OpcodeInfoType(opc_return, 2),
0912: /* areturn */new OpcodeInfoType(opc_return, 1),
0913: /* return */new OpcodeInfoType(opc_return, 0),
0914: /* getstatic */new OpcodeInfoType(255),
0915: /* putstatic */new OpcodeInfoType(255),
0916: /* getfield */new OpcodeInfoType(255),
0917: /* putfield */new OpcodeInfoType(255),
0918: /* invokevirtual */new OpcodeInfoType(255),
0919: /* invokespecial */new OpcodeInfoType(255),
0920: /* invokestatic */new OpcodeInfoType(255),
0921: /* invokeinterface */new OpcodeInfoType(255),
0922: /* xxxunusedxxx */new OpcodeInfoType(255),
0923: /* new */new OpcodeInfoType(255),
0924: /* newarray */new OpcodeInfoType(opc_iadd, 1, 1,
0925: OpcodeInfoType.CAN_ERROR),
0926: /* anewarray */new OpcodeInfoType(255),
0927: /* arraylength */new OpcodeInfoType(opc_iadd, 1, 1,
0928: OpcodeInfoType.NULL_CHECK),
0929: /* athrow */new OpcodeInfoType(opc_iadd, 1, 0,
0930: OpcodeInfoType.NULL_CHECK
0931: | OpcodeInfoType.CAN_ERROR),
0932: /* checkcast */new OpcodeInfoType(255),
0933: /* instanceof */new OpcodeInfoType(255),
0934: /* monitorenter */new OpcodeInfoType(opc_iadd, 1, 0,
0935: OpcodeInfoType.NULL_CHECK
0936: | OpcodeInfoType.CAN_ERROR),
0937: /* monitorexit */new OpcodeInfoType(opc_iadd, 1, 0,
0938: OpcodeInfoType.NULL_CHECK
0939: | OpcodeInfoType.CAN_ERROR),
0940: /* wide */new OpcodeInfoType(255),
0941: /* multianewarray */new OpcodeInfoType(255),
0942: /* ifnull */new OpcodeInfoType(255),
0943: /* ifnonnull */new OpcodeInfoType(255),
0944: /* goto_w */new OpcodeInfoType(255),
0945: /* jsr_w */new OpcodeInfoType(255),
0946: /* breakpoint */new OpcodeInfoType(255)
0947:
0948: /* IMPL_NOTE: I still need to add more info here */
0949:
0950: };
0951:
0952: /**
0953: * Print the code as Java assembly language instructions
0954: */
0955: String disassembleInlining() {
0956: byte codeBytes[] = new byte[3];
0957: // Copy inlining into codeBytes[] buffer
0958: codeBytes[0] = (byte) (inlining & 0xff);
0959: codeBytes[1] = (byte) ((inlining >> 8) & 0xff);
0960: codeBytes[2] = (byte) ((inlining >> 16) & 0xff);
0961: return MethodInfo.disassemble(codeBytes, 0, 3);
0962: }
0963:
0964: private String myName;
0965:
0966: public String toString() {
0967: if (myName == null) {
0968: myName = method.parent.className + "." + method.name.string
0969: + method.type.string;
0970: }
0971: return myName;
0972: }
0973:
0974: static int total = 0;
0975:
0976: // After inlining some code, we try to see if we can remove code. For
0977: // example, the frequent case of opc_aload_0 invokeingored_quick #1 T can
0978: // simply "go away"
0979:
0980: final boolean compress() {
0981: MethodInfo mb = method;
0982: boolean rewritten = false;
0983: byte[] code = mb.code;
0984: int[] stack = new int[mb.stack + 1];
0985: int stackHeight = 0;
0986: int nextpc;
0987: java.util.BitSet targets = mb.getLabelTargets();
0988:
0989: for (int pc = 0; pc < code.length; pc = nextpc) {
0990: nextpc = pc + mb.opcodeLength(pc);
0991: int opcode = code[pc] & 0xff;
0992: int popping = 0;
0993: boolean checkThis = false;
0994:
0995: if (targets.get(pc)) {
0996: stackHeight = 0;
0997: }
0998: stack[stackHeight] = pc;
0999:
1000: // Invariant. the stackheight at this point is stackHeight or less.
1001: //
1002: // We can pop n items from the stack (where n <= stackHeight) by
1003: // simply deleting all the code from stackHeight[n] to this point
1004: // in the code. No side effects are removed.
1005: //
1006: // Note that instructions that have a side effect should set
1007: // stackHeight = 0, to indicate that it can't be deleted.
1008:
1009: switch (opcode) {
1010: case opc_nop:
1011: case opc_ineg:
1012: case opc_fneg:
1013: case opc_i2f:
1014: case opc_f2i:
1015: case opc_i2b:
1016: case opc_i2c:
1017: case opc_i2s:
1018: case opc_newarray:
1019: case opc_anewarray_fast:
1020: case opc_instanceof _fast:
1021: case opc_lneg:
1022: case opc_dneg:
1023: case opc_l2d:
1024: case opc_d2l:
1025: // these don't change stack height, and we know as much about
1026: // the stack before as we do after.
1027: break;
1028:
1029: case opc_aconst_null:
1030: case opc_iconst_m1:
1031: case opc_iconst_0:
1032: case opc_iconst_1:
1033: case opc_iconst_2:
1034: case opc_iconst_3:
1035: case opc_iconst_4:
1036: case opc_iconst_5:
1037: case opc_fconst_0:
1038: case opc_fconst_1:
1039: case opc_fconst_2:
1040: case opc_bipush:
1041: case opc_sipush:
1042: case opc_iload:
1043: case opc_fload:
1044: case opc_aload:
1045: case opc_iload_0:
1046: case opc_iload_1:
1047: case opc_iload_2:
1048: case opc_iload_3:
1049: case opc_fload_0:
1050: case opc_fload_1:
1051: case opc_fload_2:
1052: case opc_fload_3:
1053: case opc_aload_0:
1054: case opc_aload_1:
1055: case opc_aload_2:
1056: case opc_aload_3:
1057: case opc_getstatic_fast:
1058: case opc_dup:
1059: // These push some value onto the stack, no matter what was
1060: // there before
1061: stackHeight += 1;
1062: break;
1063:
1064: case opc_lconst_0:
1065: case opc_lconst_1:
1066: case opc_dconst_0:
1067: case opc_dconst_1:
1068: case opc_lload:
1069: case opc_dload:
1070: case opc_lload_0:
1071: case opc_lload_1:
1072: case opc_lload_2:
1073: case opc_lload_3:
1074: case opc_dload_0:
1075: case opc_dload_1:
1076: case opc_dload_2:
1077: case opc_dload_3:
1078: case opc_getstatic2_fast:
1079: // These push two values onto the stack, no matter what was
1080: // there before.
1081: stackHeight += 2;
1082: break;
1083:
1084: case opc_i2l:
1085: case opc_i2d:
1086: case opc_f2l:
1087: case opc_f2d:
1088: // if we knew the top element of the stack, we know more
1089: stackHeight = (stackHeight < 1) ? 0 : stackHeight + 1;
1090: break;
1091:
1092: case opc_iadd:
1093: case opc_fadd:
1094: case opc_isub:
1095: case opc_fsub:
1096: case opc_imul:
1097: case opc_fmul:
1098: case opc_fdiv:
1099: case opc_frem:
1100: case opc_ishl:
1101: case opc_ishr:
1102: case opc_iushr:
1103: case opc_iand:
1104: case opc_ior:
1105: case opc_ixor:
1106: case opc_l2i:
1107: case opc_l2f:
1108: case opc_d2i:
1109: case opc_d2f:
1110: case opc_fcmpl:
1111: case opc_fcmpg:
1112: // if we knew the top two elements of the stack, the stack
1113: // has just shrunk
1114: stackHeight = (stackHeight < 2) ? 0 : stackHeight - 1;
1115: break;
1116:
1117: case opc_lshl:
1118: case opc_lshr:
1119: case opc_lushr:
1120: // if we knew the top three elements of the stack, we now
1121: // know the top two
1122: stackHeight = (stackHeight < 3) ? 0 : stackHeight - 1;
1123: break;
1124:
1125: case opc_lcmp:
1126: case opc_dcmpl:
1127: case opc_dcmpg:
1128: // if we knew the top 4 elements of the stack, we now
1129: // know the top element
1130: stackHeight = (stackHeight < 4) ? 0 : stackHeight - 3;
1131: break;
1132:
1133: case opc_ladd:
1134: case opc_dadd:
1135: case opc_lsub:
1136: case opc_dsub:
1137: case opc_lmul:
1138: case opc_dmul:
1139: case opc_ddiv:
1140: case opc_drem:
1141: case opc_land:
1142: case opc_lor:
1143: case opc_lxor:
1144: // if we knew the top 4 elements of the stack, we now
1145: // know the top 2
1146: stackHeight = (stackHeight < 4) ? 0 : stackHeight - 2;
1147: break;
1148:
1149: // The dup's (other than opc_dup) deal with the stack in
1150: // a way that's not worth the hassle of dealing with.
1151:
1152: case opc_getfield_fast:
1153: case opc_arraylength:
1154: // If we throw away the result, then we just need to check that
1155: // the value is non-null.
1156: if (code[nextpc] == (byte) (opc_pop)) {
1157: checkThis = true;
1158: nextpc += 1;
1159: } else {
1160: stackHeight = 0;
1161: }
1162: break;
1163:
1164: case opc_pop2:
1165: popping++; // fall thru
1166: case opc_pop:
1167: // We have to be careful. The inliner may produce code that
1168: // does correspond to the stack. For example, it might
1169: // produce "pop pop2" to remove a double then an int. We need
1170: // to deal with series of them at once.
1171: if (stackHeight > 0) {
1172: popping++;
1173: for (;;) {
1174: opcode = code[++pc] & 0xFF;
1175: if (opcode == opc_pop)
1176: popping++;
1177: else if (opcode == opc_pop2)
1178: popping += 2;
1179: else
1180: break;
1181: }
1182: nextpc = pc;
1183: }
1184: break;
1185:
1186: case opc_invokeignored_quick:
1187: popping = code[pc + 1] & 0xff;
1188: if (code[pc + 2] != 0) {
1189: checkThis = true;
1190: popping--;
1191: }
1192: break;
1193:
1194: default:
1195: stackHeight = 0;
1196: }
1197:
1198: if (checkThis || (popping > 0 && stackHeight > 0)) {
1199: rewritten = true;
1200: if (stackHeight >= popping) {
1201: stackHeight -= popping;
1202: popping = 0;
1203: } else {
1204: popping -= stackHeight;
1205: stackHeight = 0;
1206: }
1207: int start = stack[stackHeight];
1208:
1209: if (checkThis) {
1210: if (popping == 0 && (nextpc - start != 3)) {
1211: mb
1212: .replaceCode(start, nextpc,
1213: opc_nonnull_quick);
1214: } else {
1215: mb
1216: .replaceCode(start, nextpc,
1217: opc_invokeignored_quick,
1218: popping + 1, 1);
1219: }
1220: stackHeight = 0;
1221: } else {
1222: switch (popping) {
1223: case 0:
1224: mb.replaceCode(start, nextpc);
1225: break;
1226: case 1:
1227: mb.replaceCode(start, nextpc, opc_pop);
1228: break;
1229: case 2:
1230: mb.replaceCode(start, nextpc, opc_pop2);
1231: break;
1232: default:
1233: mb.replaceCode(start, nextpc,
1234: opc_invokeignored_quick, popping, 0);
1235: break;
1236: }
1237: }
1238: }
1239: }
1240: return rewritten;
1241: }
1242: }
1243:
1244: /**
1245: * Class used for inlining info. See inlining code in MethodInfo
1246: */
1247: class OpcodeInfoType {
1248: int opcode; // really the opcode type
1249: int inStack;
1250: int outStack;
1251:
1252: static final int CAN_ERROR = 0x01; /* can give error in addition to
1253: NULL_CHECK */
1254: static final int NULL_CHECK = 0x02; /* checks that first arg isn't null */
1255: static final int CONSTANT_POOL = 0x04; /* uses the constant pool */
1256: int flags;
1257:
1258: OpcodeInfoType(int opcode, int inStack, int outStack, int flags) {
1259: this .opcode = opcode;
1260: this .inStack = inStack;
1261: this .outStack = outStack;
1262: this .flags = flags;
1263: }
1264:
1265: OpcodeInfoType(int opcode, int inStack, int outStack) {
1266: this (opcode, inStack, outStack, 0);
1267: }
1268:
1269: OpcodeInfoType(int opcode, int inStack) {
1270: this (opcode, inStack, 0, 0);
1271: }
1272:
1273: OpcodeInfoType(int opcode) {
1274: this (opcode, 0, 0, 0);
1275: }
1276: };
|