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