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