0001: /*
0002: * Copyright 2004 Brian S O'Neill
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.cojen.classfile;
0018:
0019: import java.util.ArrayList;
0020: import java.util.HashMap;
0021: import java.util.List;
0022: import java.util.Map;
0023: import java.util.Vector;
0024: import org.cojen.classfile.attribute.CodeAttr;
0025: import org.cojen.classfile.constant.ConstantClassInfo;
0026: import org.cojen.classfile.constant.ConstantDoubleInfo;
0027: import org.cojen.classfile.constant.ConstantFieldInfo;
0028: import org.cojen.classfile.constant.ConstantFloatInfo;
0029: import org.cojen.classfile.constant.ConstantIntegerInfo;
0030: import org.cojen.classfile.constant.ConstantInterfaceMethodInfo;
0031: import org.cojen.classfile.constant.ConstantLongInfo;
0032: import org.cojen.classfile.constant.ConstantMethodInfo;
0033: import org.cojen.classfile.constant.ConstantNameAndTypeInfo;
0034: import org.cojen.classfile.constant.ConstantStringInfo;
0035:
0036: /**
0037: * Disassembles a method into a CodeAssembler, which acts as a visitor.
0038: *
0039: * @author Brian S O'Neill
0040: */
0041: public class CodeDisassembler {
0042: private final MethodInfo mMethod;
0043: private final String mEnclosingClassName;
0044: private final String mSuperClassName;
0045: private final CodeAttr mCode;
0046: private final ConstantPool mCp;
0047: private final byte[] mByteCodes;
0048: private final ExceptionHandler[] mExceptionHandlers;
0049:
0050: // Current CodeAssembler in use for disassembly.
0051: private CodeAssembler mAssembler;
0052:
0053: // List of all the LocalVariable objects in use.
0054: private Vector mLocals;
0055:
0056: // True if the method being decompiled still has a "this" reference.
0057: private boolean mHasThis;
0058:
0059: private Location mReturnLocation;
0060:
0061: // Maps Integer address keys to itself, but to Label objects after first
0062: // needed.
0063: private Map mLabels;
0064:
0065: // Maps Integer catch locations to Lists of ExceptionHandler objects.
0066: private Map mCatchLocations;
0067:
0068: // Current address being decompiled.
0069: private int mAddress;
0070:
0071: /**
0072: * @throws IllegalArgumentException if method has no code
0073: */
0074: public CodeDisassembler(MethodInfo method)
0075: throws IllegalArgumentException {
0076: mMethod = method;
0077: mEnclosingClassName = method.getClassFile().getClassName();
0078: mSuperClassName = method.getClassFile().getSuperClassName();
0079: if ((mCode = method.getCodeAttr()) == null) {
0080: throw new IllegalArgumentException("Method defines no code");
0081: }
0082: mCp = mCode.getConstantPool();
0083: CodeBuffer buffer = mCode.getCodeBuffer();
0084: mByteCodes = buffer.getByteCodes();
0085: mExceptionHandlers = buffer.getExceptionHandlers();
0086: }
0087:
0088: /**
0089: * Disassemble the MethodInfo into the given assembler.
0090: *
0091: * @see CodeAssemblerPrinter
0092: */
0093: public void disassemble(CodeAssembler assembler) {
0094: disassemble(assembler, null, null);
0095: }
0096:
0097: /**
0098: * Disassemble the MethodInfo into the given assembler.
0099: *
0100: * @param params if not null, override the local variables which hold parameter values
0101: * @param returnLocation if not null, disassemble will branch to this location upon seeing
0102: * a return, leaving any arguments on the stack
0103: * @see CodeAssemblerPrinter
0104: */
0105: public synchronized void disassemble(CodeAssembler assembler,
0106: LocalVariable[] params, Location returnLocation) {
0107: mAssembler = assembler;
0108: mLocals = new Vector();
0109: if (mHasThis = !mMethod.getModifiers().isStatic()) {
0110: // Reserve a slot for "this" parameter.
0111: mLocals.add(null);
0112: }
0113:
0114: gatherLabels();
0115:
0116: // Gather the local variables of the parameters.
0117: {
0118: TypeDesc[] paramTypes = mMethod.getMethodDescriptor()
0119: .getParameterTypes();
0120:
0121: if (params == null) {
0122: params = new LocalVariable[assembler
0123: .getParameterCount()];
0124: for (int i = params.length; --i >= 0;) {
0125: params[i] = assembler.getParameter(i);
0126: }
0127: }
0128: if (paramTypes.length != params.length) {
0129: throw new IllegalArgumentException(
0130: "Method parameter count doesn't match given parameter count: "
0131: + paramTypes.length + " != "
0132: + params.length);
0133: }
0134:
0135: for (int i = 0; i < paramTypes.length; i++) {
0136: LocalVariable paramVar = params[i];
0137: if (!compatibleType(paramTypes[i], paramVar.getType())) {
0138: throw new IllegalArgumentException(
0139: "Method parameter type is not compatible with given type: "
0140: + paramTypes[i] + " != "
0141: + paramVar.getType());
0142: }
0143: mLocals.add(paramVar);
0144: if (paramVar.getType().isDoubleWord()) {
0145: // Reserve slot for least significant word.
0146: mLocals.add(null);
0147: }
0148: }
0149: }
0150:
0151: mReturnLocation = returnLocation;
0152:
0153: Location currentLoc = new Location() {
0154: public int getLocation() {
0155: return mAddress;
0156: }
0157:
0158: public int compareTo(Object obj) {
0159: if (this == obj) {
0160: return 0;
0161: }
0162: Location other = (Location) obj;
0163:
0164: int loca = getLocation();
0165: int locb = other.getLocation();
0166:
0167: if (loca < locb) {
0168: return -1;
0169: } else if (loca > locb) {
0170: return 1;
0171: } else {
0172: return 0;
0173: }
0174: }
0175: };
0176:
0177: int currentLine = -1;
0178:
0179: for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
0180: int nextLine = mCode.getLineNumber(currentLoc);
0181: if (nextLine != currentLine) {
0182: if ((currentLine = nextLine) >= 0) {
0183: mAssembler.mapLineNumber(currentLine);
0184: }
0185: }
0186:
0187: // Check if a label needs to be created and/or located.
0188: locateLabel();
0189:
0190: byte opcode = mByteCodes[mAddress];
0191:
0192: int index;
0193: Location loc;
0194: TypeDesc type;
0195: ConstantInfo ci;
0196:
0197: switch (opcode) {
0198:
0199: default:
0200: error(opcode, "Unknown opcode: " + (opcode & 0xff));
0201: break;
0202:
0203: // Opcodes with no operands...
0204:
0205: case Opcode.NOP:
0206: assembler.nop();
0207: break;
0208: case Opcode.BREAKPOINT:
0209: assembler.breakpoint();
0210: break;
0211:
0212: case Opcode.ACONST_NULL:
0213: assembler.loadNull();
0214: break;
0215: case Opcode.ICONST_M1:
0216: assembler.loadConstant(-1);
0217: break;
0218: case Opcode.ICONST_0:
0219: assembler.loadConstant(0);
0220: break;
0221: case Opcode.ICONST_1:
0222: assembler.loadConstant(1);
0223: break;
0224: case Opcode.ICONST_2:
0225: assembler.loadConstant(2);
0226: break;
0227: case Opcode.ICONST_3:
0228: assembler.loadConstant(3);
0229: break;
0230: case Opcode.ICONST_4:
0231: assembler.loadConstant(4);
0232: break;
0233: case Opcode.ICONST_5:
0234: assembler.loadConstant(5);
0235: break;
0236: case Opcode.LCONST_0:
0237: assembler.loadConstant(0L);
0238: break;
0239: case Opcode.LCONST_1:
0240: assembler.loadConstant(1L);
0241: break;
0242: case Opcode.FCONST_0:
0243: assembler.loadConstant(0f);
0244: break;
0245: case Opcode.FCONST_1:
0246: assembler.loadConstant(1f);
0247: break;
0248: case Opcode.FCONST_2:
0249: assembler.loadConstant(2f);
0250: break;
0251: case Opcode.DCONST_0:
0252: assembler.loadConstant(0d);
0253: break;
0254: case Opcode.DCONST_1:
0255: assembler.loadConstant(1d);
0256: break;
0257:
0258: case Opcode.POP:
0259: assembler.pop();
0260: break;
0261: case Opcode.POP2:
0262: assembler.pop2();
0263: break;
0264: case Opcode.DUP:
0265: assembler.dup();
0266: break;
0267: case Opcode.DUP_X1:
0268: assembler.dupX1();
0269: break;
0270: case Opcode.DUP_X2:
0271: assembler.dupX2();
0272: break;
0273: case Opcode.DUP2:
0274: assembler.dup2();
0275: break;
0276: case Opcode.DUP2_X1:
0277: assembler.dup2X2();
0278: break;
0279: case Opcode.DUP2_X2:
0280: assembler.dup2X2();
0281: break;
0282: case Opcode.SWAP:
0283: assembler.swap();
0284: break;
0285:
0286: case Opcode.IADD:
0287: case Opcode.LADD:
0288: case Opcode.FADD:
0289: case Opcode.DADD:
0290: case Opcode.ISUB:
0291: case Opcode.LSUB:
0292: case Opcode.FSUB:
0293: case Opcode.DSUB:
0294: case Opcode.IMUL:
0295: case Opcode.LMUL:
0296: case Opcode.FMUL:
0297: case Opcode.DMUL:
0298: case Opcode.IDIV:
0299: case Opcode.LDIV:
0300: case Opcode.FDIV:
0301: case Opcode.DDIV:
0302: case Opcode.IREM:
0303: case Opcode.LREM:
0304: case Opcode.FREM:
0305: case Opcode.DREM:
0306: case Opcode.INEG:
0307: case Opcode.LNEG:
0308: case Opcode.FNEG:
0309: case Opcode.DNEG:
0310: case Opcode.ISHL:
0311: case Opcode.LSHL:
0312: case Opcode.ISHR:
0313: case Opcode.LSHR:
0314: case Opcode.IUSHR:
0315: case Opcode.LUSHR:
0316: case Opcode.IAND:
0317: case Opcode.LAND:
0318: case Opcode.IOR:
0319: case Opcode.LOR:
0320: case Opcode.IXOR:
0321: case Opcode.LXOR:
0322: case Opcode.FCMPL:
0323: case Opcode.DCMPL:
0324: case Opcode.FCMPG:
0325: case Opcode.DCMPG:
0326: case Opcode.LCMP:
0327: assembler.math(opcode);
0328: break;
0329:
0330: case Opcode.I2L:
0331: assembler.convert(TypeDesc.INT, TypeDesc.LONG);
0332: break;
0333: case Opcode.I2F:
0334: assembler.convert(TypeDesc.INT, TypeDesc.FLOAT);
0335: break;
0336: case Opcode.I2D:
0337: assembler.convert(TypeDesc.INT, TypeDesc.DOUBLE);
0338: break;
0339: case Opcode.L2I:
0340: assembler.convert(TypeDesc.LONG, TypeDesc.INT);
0341: break;
0342: case Opcode.L2F:
0343: assembler.convert(TypeDesc.LONG, TypeDesc.FLOAT);
0344: break;
0345: case Opcode.L2D:
0346: assembler.convert(TypeDesc.LONG, TypeDesc.DOUBLE);
0347: break;
0348: case Opcode.F2I:
0349: assembler.convert(TypeDesc.FLOAT, TypeDesc.INT);
0350: break;
0351: case Opcode.F2L:
0352: assembler.convert(TypeDesc.FLOAT, TypeDesc.LONG);
0353: break;
0354: case Opcode.F2D:
0355: assembler.convert(TypeDesc.FLOAT, TypeDesc.DOUBLE);
0356: break;
0357: case Opcode.D2I:
0358: assembler.convert(TypeDesc.DOUBLE, TypeDesc.INT);
0359: break;
0360: case Opcode.D2L:
0361: assembler.convert(TypeDesc.DOUBLE, TypeDesc.LONG);
0362: break;
0363: case Opcode.D2F:
0364: assembler.convert(TypeDesc.DOUBLE, TypeDesc.FLOAT);
0365: break;
0366: case Opcode.I2B:
0367: assembler.convert(TypeDesc.INT, TypeDesc.BYTE);
0368: break;
0369: case Opcode.I2C:
0370: assembler.convert(TypeDesc.INT, TypeDesc.CHAR);
0371: break;
0372: case Opcode.I2S:
0373: assembler.convert(TypeDesc.INT, TypeDesc.SHORT);
0374: break;
0375:
0376: case Opcode.IRETURN:
0377: case Opcode.LRETURN:
0378: case Opcode.FRETURN:
0379: case Opcode.DRETURN:
0380: case Opcode.ARETURN:
0381: case Opcode.RETURN:
0382: if (mReturnLocation != null) {
0383: assembler.branch(mReturnLocation);
0384: } else {
0385: switch (opcode) {
0386: case Opcode.IRETURN:
0387: assembler.returnValue(TypeDesc.INT);
0388: break;
0389: case Opcode.LRETURN:
0390: assembler.returnValue(TypeDesc.LONG);
0391: break;
0392: case Opcode.FRETURN:
0393: assembler.returnValue(TypeDesc.FLOAT);
0394: break;
0395: case Opcode.DRETURN:
0396: assembler.returnValue(TypeDesc.DOUBLE);
0397: break;
0398: case Opcode.ARETURN:
0399: assembler.returnValue(TypeDesc.OBJECT);
0400: break;
0401: case Opcode.RETURN:
0402: assembler.returnVoid();
0403: break;
0404: }
0405: }
0406: break;
0407:
0408: case Opcode.IALOAD:
0409: assembler.loadFromArray(TypeDesc.INT);
0410: break;
0411: case Opcode.LALOAD:
0412: assembler.loadFromArray(TypeDesc.LONG);
0413: break;
0414: case Opcode.FALOAD:
0415: assembler.loadFromArray(TypeDesc.FLOAT);
0416: break;
0417: case Opcode.DALOAD:
0418: assembler.loadFromArray(TypeDesc.DOUBLE);
0419: break;
0420: case Opcode.AALOAD:
0421: assembler.loadFromArray(TypeDesc.OBJECT);
0422: break;
0423: case Opcode.BALOAD:
0424: assembler.loadFromArray(TypeDesc.BYTE);
0425: break;
0426: case Opcode.CALOAD:
0427: assembler.loadFromArray(TypeDesc.CHAR);
0428: break;
0429: case Opcode.SALOAD:
0430: assembler.loadFromArray(TypeDesc.SHORT);
0431: break;
0432:
0433: case Opcode.IASTORE:
0434: assembler.storeToArray(TypeDesc.INT);
0435: break;
0436: case Opcode.LASTORE:
0437: assembler.storeToArray(TypeDesc.LONG);
0438: break;
0439: case Opcode.FASTORE:
0440: assembler.storeToArray(TypeDesc.FLOAT);
0441: break;
0442: case Opcode.DASTORE:
0443: assembler.storeToArray(TypeDesc.DOUBLE);
0444: break;
0445: case Opcode.AASTORE:
0446: assembler.storeToArray(TypeDesc.OBJECT);
0447: break;
0448: case Opcode.BASTORE:
0449: assembler.storeToArray(TypeDesc.BYTE);
0450: break;
0451: case Opcode.CASTORE:
0452: assembler.storeToArray(TypeDesc.CHAR);
0453: break;
0454: case Opcode.SASTORE:
0455: assembler.storeToArray(TypeDesc.SHORT);
0456: break;
0457:
0458: case Opcode.ARRAYLENGTH:
0459: assembler.arrayLength();
0460: break;
0461: case Opcode.ATHROW:
0462: assembler.throwObject();
0463: break;
0464: case Opcode.MONITORENTER:
0465: assembler.monitorEnter();
0466: break;
0467: case Opcode.MONITOREXIT:
0468: assembler.monitorExit();
0469: break;
0470:
0471: // End opcodes with no operands.
0472:
0473: // Opcodes that load a constant from the constant pool...
0474:
0475: case Opcode.LDC:
0476: case Opcode.LDC_W:
0477: case Opcode.LDC2_W:
0478: switch (opcode) {
0479: case Opcode.LDC:
0480: index = readUnsignedByte();
0481: break;
0482: case Opcode.LDC_W:
0483: case Opcode.LDC2_W:
0484: index = readUnsignedShort();
0485: break;
0486: default:
0487: index = 0;
0488: break;
0489: }
0490:
0491: try {
0492: ci = mCp.getConstant(index);
0493: } catch (IndexOutOfBoundsException e) {
0494: error(opcode, "Undefined constant at index: "
0495: + index);
0496: break;
0497: }
0498:
0499: if (ci instanceof ConstantStringInfo) {
0500: assembler.loadConstant(((ConstantStringInfo) ci)
0501: .getValue());
0502: } else if (ci instanceof ConstantIntegerInfo) {
0503: assembler.loadConstant(((ConstantIntegerInfo) ci)
0504: .getValue());
0505: } else if (ci instanceof ConstantLongInfo) {
0506: assembler.loadConstant(((ConstantLongInfo) ci)
0507: .getValue());
0508: } else if (ci instanceof ConstantFloatInfo) {
0509: assembler.loadConstant(((ConstantFloatInfo) ci)
0510: .getValue());
0511: } else if (ci instanceof ConstantDoubleInfo) {
0512: assembler.loadConstant(((ConstantDoubleInfo) ci)
0513: .getValue());
0514: } else if (ci instanceof ConstantClassInfo) {
0515: assembler.loadConstant(((ConstantClassInfo) ci)
0516: .getType());
0517: } else {
0518: error(opcode, "Invalid constant type for load: "
0519: + ci);
0520: }
0521: break;
0522:
0523: case Opcode.NEW:
0524: index = readUnsignedShort();
0525: try {
0526: ci = mCp.getConstant(index);
0527: } catch (IndexOutOfBoundsException e) {
0528: error(opcode, "Undefined constant at index: "
0529: + index);
0530: break;
0531: }
0532:
0533: if (ci instanceof ConstantClassInfo) {
0534: assembler.newObject(((ConstantClassInfo) ci)
0535: .getType());
0536: } else {
0537: error(opcode, "Invalid constant type for new: "
0538: + ci);
0539: }
0540: break;
0541: case Opcode.ANEWARRAY:
0542: index = readUnsignedShort();
0543: try {
0544: ci = mCp.getConstant(index);
0545: } catch (IndexOutOfBoundsException e) {
0546: error(opcode, "Undefined constant at index: "
0547: + index);
0548: break;
0549: }
0550:
0551: if (ci instanceof ConstantClassInfo) {
0552: type = ((ConstantClassInfo) ci).getType()
0553: .toArrayType();
0554: assembler.newObject(type);
0555: } else {
0556: error(opcode, "Invalid constant type for new: "
0557: + ci);
0558: }
0559: break;
0560: case Opcode.MULTIANEWARRAY:
0561: index = readUnsignedShort();
0562: try {
0563: ci = mCp.getConstant(index);
0564: } catch (IndexOutOfBoundsException e) {
0565: error(opcode, "Undefined constant at index: "
0566: + index);
0567: break;
0568: }
0569:
0570: int dims = readUnsignedByte();
0571: if (ci instanceof ConstantClassInfo) {
0572: type = ((ConstantClassInfo) ci).getType();
0573: assembler.newObject(type, dims);
0574: } else {
0575: error(opcode, "Invalid constant type for new: "
0576: + ci);
0577: }
0578: break;
0579:
0580: case Opcode.CHECKCAST:
0581: index = readUnsignedShort();
0582: try {
0583: ci = mCp.getConstant(index);
0584: } catch (IndexOutOfBoundsException e) {
0585: error(opcode, "Undefined constant at index: "
0586: + index);
0587: break;
0588: }
0589:
0590: if (ci instanceof ConstantClassInfo) {
0591: assembler.checkCast(((ConstantClassInfo) ci)
0592: .getType());
0593: } else {
0594: error(opcode,
0595: "Invalid constant type for checkcast: "
0596: + ci);
0597: }
0598: break;
0599: case Opcode.INSTANCEOF:
0600: index = readUnsignedShort();
0601: try {
0602: ci = mCp.getConstant(index);
0603: } catch (IndexOutOfBoundsException e) {
0604: error(opcode, "Undefined constant at index: "
0605: + index);
0606: break;
0607: }
0608:
0609: if (ci instanceof ConstantClassInfo) {
0610: assembler.instanceOf(((ConstantClassInfo) ci)
0611: .getType());
0612: } else {
0613: error(opcode,
0614: "Invalid constant type for instanceof: "
0615: + ci);
0616: }
0617: break;
0618:
0619: case Opcode.GETSTATIC:
0620: case Opcode.PUTSTATIC:
0621: case Opcode.GETFIELD:
0622: case Opcode.PUTFIELD:
0623: index = readUnsignedShort();
0624: try {
0625: ci = mCp.getConstant(index);
0626: } catch (IndexOutOfBoundsException e) {
0627: error(opcode, "Undefined constant at index: "
0628: + index);
0629: break;
0630: }
0631:
0632: if (!(ci instanceof ConstantFieldInfo)) {
0633: error(opcode,
0634: "Invalid constant type for field access: "
0635: + ci);
0636: break;
0637: }
0638:
0639: ConstantFieldInfo field = (ConstantFieldInfo) ci;
0640: String className = field.getParentClass().getType()
0641: .getFullName();
0642: if (mEnclosingClassName.equals(className)) {
0643: className = null;
0644: }
0645: String fieldName = field.getNameAndType().getName();
0646: Descriptor desc = field.getNameAndType().getType();
0647: if (!(desc instanceof TypeDesc)) {
0648: error(opcode,
0649: "Invalid descriptor for field access: "
0650: + desc);
0651: break;
0652: } else {
0653: type = (TypeDesc) desc;
0654: }
0655:
0656: // Implementation note: Although it may seem convenient if the
0657: // CodeAssembler had methods that accepted ConstantFieldInfo
0658: // objects as parameters, it would cause problems because
0659: // ConstantPools are not portable between ClassFiles.
0660:
0661: switch (opcode) {
0662: case Opcode.GETSTATIC:
0663: if (className == null) {
0664: assembler.loadStaticField(fieldName, type);
0665: } else {
0666: assembler.loadStaticField(className, fieldName,
0667: type);
0668: }
0669: break;
0670: case Opcode.PUTSTATIC:
0671: if (className == null) {
0672: assembler.storeStaticField(fieldName, type);
0673: } else {
0674: assembler.storeStaticField(className,
0675: fieldName, type);
0676: }
0677: break;
0678: case Opcode.GETFIELD:
0679: if (className == null) {
0680: assembler.loadField(fieldName, type);
0681: } else {
0682: assembler.loadField(className, fieldName, type);
0683: }
0684: break;
0685: case Opcode.PUTFIELD:
0686: if (className == null) {
0687: assembler.storeField(fieldName, type);
0688: } else {
0689: assembler
0690: .storeField(className, fieldName, type);
0691: }
0692: break;
0693: }
0694: break;
0695:
0696: case Opcode.INVOKEVIRTUAL:
0697: case Opcode.INVOKESPECIAL:
0698: case Opcode.INVOKESTATIC:
0699: case Opcode.INVOKEINTERFACE:
0700: index = readUnsignedShort();
0701: try {
0702: ci = mCp.getConstant(index);
0703: } catch (IndexOutOfBoundsException e) {
0704: error(opcode, "Undefined constant at index: "
0705: + index);
0706: break;
0707: }
0708:
0709: ConstantNameAndTypeInfo nameAndType;
0710:
0711: if (opcode == Opcode.INVOKEINTERFACE) {
0712: // Read and ignore nargs and padding byte.
0713: readShort();
0714: if (!(ci instanceof ConstantInterfaceMethodInfo)) {
0715: error(opcode,
0716: "Invalid constant type for method invocation: "
0717: + ci);
0718: break;
0719: }
0720: ConstantInterfaceMethodInfo method = (ConstantInterfaceMethodInfo) ci;
0721: className = method.getParentClass().getType()
0722: .getFullName();
0723: nameAndType = method.getNameAndType();
0724: } else {
0725: if (!(ci instanceof ConstantMethodInfo)) {
0726: error(opcode,
0727: "Invalid constant type for method invocation: "
0728: + ci);
0729: break;
0730: }
0731: ConstantMethodInfo method = (ConstantMethodInfo) ci;
0732: className = method.getParentClass().getType()
0733: .getFullName();
0734: if (mEnclosingClassName.equals(className)) {
0735: className = null;
0736: }
0737: nameAndType = method.getNameAndType();
0738: }
0739:
0740: String methodName = nameAndType.getName();
0741: desc = nameAndType.getType();
0742: if (!(desc instanceof MethodDesc)) {
0743: error(opcode,
0744: "Invalid descriptor for method invocation: "
0745: + desc);
0746: break;
0747: }
0748: TypeDesc ret = ((MethodDesc) desc).getReturnType();
0749: if (ret == TypeDesc.VOID) {
0750: ret = null;
0751: }
0752: TypeDesc[] paramTypes = ((MethodDesc) desc)
0753: .getParameterTypes();
0754: if (paramTypes.length == 0) {
0755: paramTypes = null;
0756: }
0757:
0758: switch (opcode) {
0759: case Opcode.INVOKEVIRTUAL:
0760: if (className == null) {
0761: assembler.invokeVirtual(methodName, ret,
0762: paramTypes);
0763: } else {
0764: assembler.invokeVirtual(className, methodName,
0765: ret, paramTypes);
0766: }
0767: break;
0768: case Opcode.INVOKESPECIAL:
0769: if ("<init>".equals(methodName)) {
0770: if (className == null) {
0771: assembler.invokeConstructor(paramTypes);
0772: } else {
0773: if ("<init>".equals(mMethod.getName())
0774: && className
0775: .equals(mSuperClassName)) {
0776: assembler
0777: .invokeSuperConstructor(paramTypes);
0778: } else {
0779: assembler.invokeConstructor(className,
0780: paramTypes);
0781: }
0782: }
0783: } else {
0784: if (className == null) {
0785: assembler.invokePrivate(methodName, ret,
0786: paramTypes);
0787: } else {
0788: assembler.invokeSuper(className,
0789: methodName, ret, paramTypes);
0790: }
0791: }
0792: break;
0793: case Opcode.INVOKESTATIC:
0794: if (className == null) {
0795: assembler.invokeStatic(methodName, ret,
0796: paramTypes);
0797: } else {
0798: assembler.invokeStatic(className, methodName,
0799: ret, paramTypes);
0800: }
0801: break;
0802: case Opcode.INVOKEINTERFACE:
0803: assembler.invokeInterface(className, methodName,
0804: ret, paramTypes);
0805: break;
0806: }
0807: break;
0808:
0809: // End opcodes that load a constant from the constant pool.
0810:
0811: // Opcodes that load or store local variables...
0812:
0813: case Opcode.ILOAD:
0814: case Opcode.ISTORE:
0815: case Opcode.LLOAD:
0816: case Opcode.LSTORE:
0817: case Opcode.FLOAD:
0818: case Opcode.FSTORE:
0819: case Opcode.DLOAD:
0820: case Opcode.DSTORE:
0821: case Opcode.ALOAD:
0822: case Opcode.ASTORE:
0823: case Opcode.ILOAD_0:
0824: case Opcode.ISTORE_0:
0825: case Opcode.ILOAD_1:
0826: case Opcode.ISTORE_1:
0827: case Opcode.ILOAD_2:
0828: case Opcode.ISTORE_2:
0829: case Opcode.ILOAD_3:
0830: case Opcode.ISTORE_3:
0831: case Opcode.LLOAD_0:
0832: case Opcode.LSTORE_0:
0833: case Opcode.LLOAD_1:
0834: case Opcode.LSTORE_1:
0835: case Opcode.LLOAD_2:
0836: case Opcode.LSTORE_2:
0837: case Opcode.LLOAD_3:
0838: case Opcode.LSTORE_3:
0839: case Opcode.FLOAD_0:
0840: case Opcode.FSTORE_0:
0841: case Opcode.FLOAD_1:
0842: case Opcode.FSTORE_1:
0843: case Opcode.FLOAD_2:
0844: case Opcode.FSTORE_2:
0845: case Opcode.FLOAD_3:
0846: case Opcode.FSTORE_3:
0847: case Opcode.DLOAD_0:
0848: case Opcode.DSTORE_0:
0849: case Opcode.DLOAD_1:
0850: case Opcode.DSTORE_1:
0851: case Opcode.DLOAD_2:
0852: case Opcode.DSTORE_2:
0853: case Opcode.DLOAD_3:
0854: case Opcode.DSTORE_3:
0855: case Opcode.ALOAD_0:
0856: case Opcode.ASTORE_0:
0857: case Opcode.ALOAD_1:
0858: case Opcode.ASTORE_1:
0859: case Opcode.ALOAD_2:
0860: case Opcode.ASTORE_2:
0861: case Opcode.ALOAD_3:
0862: case Opcode.ASTORE_3:
0863: switch (opcode) {
0864: case Opcode.ILOAD:
0865: case Opcode.ISTORE:
0866: index = readUnsignedByte();
0867: type = TypeDesc.INT;
0868: break;
0869: case Opcode.LLOAD:
0870: case Opcode.LSTORE:
0871: index = readUnsignedByte();
0872: type = TypeDesc.LONG;
0873: break;
0874: case Opcode.FLOAD:
0875: case Opcode.FSTORE:
0876: index = readUnsignedByte();
0877: type = TypeDesc.FLOAT;
0878: break;
0879: case Opcode.DLOAD:
0880: case Opcode.DSTORE:
0881: index = readUnsignedByte();
0882: type = TypeDesc.DOUBLE;
0883: break;
0884: case Opcode.ALOAD:
0885: case Opcode.ASTORE:
0886: index = readUnsignedByte();
0887: type = TypeDesc.OBJECT;
0888: break;
0889: case Opcode.ILOAD_0:
0890: case Opcode.ISTORE_0:
0891: index = 0;
0892: type = TypeDesc.INT;
0893: break;
0894: case Opcode.ILOAD_1:
0895: case Opcode.ISTORE_1:
0896: index = 1;
0897: type = TypeDesc.INT;
0898: break;
0899: case Opcode.ILOAD_2:
0900: case Opcode.ISTORE_2:
0901: index = 2;
0902: type = TypeDesc.INT;
0903: break;
0904: case Opcode.ILOAD_3:
0905: case Opcode.ISTORE_3:
0906: index = 3;
0907: type = TypeDesc.INT;
0908: break;
0909: case Opcode.LLOAD_0:
0910: case Opcode.LSTORE_0:
0911: index = 0;
0912: type = TypeDesc.LONG;
0913: break;
0914: case Opcode.LLOAD_1:
0915: case Opcode.LSTORE_1:
0916: index = 1;
0917: type = TypeDesc.LONG;
0918: break;
0919: case Opcode.LLOAD_2:
0920: case Opcode.LSTORE_2:
0921: index = 2;
0922: type = TypeDesc.LONG;
0923: break;
0924: case Opcode.LLOAD_3:
0925: case Opcode.LSTORE_3:
0926: index = 3;
0927: type = TypeDesc.LONG;
0928: break;
0929: case Opcode.FLOAD_0:
0930: case Opcode.FSTORE_0:
0931: index = 0;
0932: type = TypeDesc.FLOAT;
0933: break;
0934: case Opcode.FLOAD_1:
0935: case Opcode.FSTORE_1:
0936: index = 1;
0937: type = TypeDesc.FLOAT;
0938: break;
0939: case Opcode.FLOAD_2:
0940: case Opcode.FSTORE_2:
0941: index = 2;
0942: type = TypeDesc.FLOAT;
0943: break;
0944: case Opcode.FLOAD_3:
0945: case Opcode.FSTORE_3:
0946: index = 3;
0947: type = TypeDesc.FLOAT;
0948: break;
0949: case Opcode.DLOAD_0:
0950: case Opcode.DSTORE_0:
0951: index = 0;
0952: type = TypeDesc.DOUBLE;
0953: break;
0954: case Opcode.DLOAD_1:
0955: case Opcode.DSTORE_1:
0956: index = 1;
0957: type = TypeDesc.DOUBLE;
0958: break;
0959: case Opcode.DLOAD_2:
0960: case Opcode.DSTORE_2:
0961: index = 2;
0962: type = TypeDesc.DOUBLE;
0963: break;
0964: case Opcode.DLOAD_3:
0965: case Opcode.DSTORE_3:
0966: index = 3;
0967: type = TypeDesc.DOUBLE;
0968: break;
0969: case Opcode.ALOAD_0:
0970: case Opcode.ASTORE_0:
0971: index = 0;
0972: type = TypeDesc.OBJECT;
0973: break;
0974: case Opcode.ALOAD_1:
0975: case Opcode.ASTORE_1:
0976: index = 1;
0977: type = TypeDesc.OBJECT;
0978: break;
0979: case Opcode.ALOAD_2:
0980: case Opcode.ASTORE_2:
0981: index = 2;
0982: type = TypeDesc.OBJECT;
0983: break;
0984: case Opcode.ALOAD_3:
0985: case Opcode.ASTORE_3:
0986: index = 3;
0987: type = TypeDesc.OBJECT;
0988: break;
0989: default:
0990: index = 0;
0991: type = null;
0992: break;
0993: }
0994:
0995: switch (opcode) {
0996: case Opcode.ILOAD:
0997: case Opcode.LLOAD:
0998: case Opcode.FLOAD:
0999: case Opcode.DLOAD:
1000: case Opcode.ALOAD:
1001: case Opcode.ILOAD_0:
1002: case Opcode.ILOAD_1:
1003: case Opcode.ILOAD_2:
1004: case Opcode.ILOAD_3:
1005: case Opcode.LLOAD_0:
1006: case Opcode.LLOAD_1:
1007: case Opcode.LLOAD_2:
1008: case Opcode.LLOAD_3:
1009: case Opcode.FLOAD_0:
1010: case Opcode.FLOAD_1:
1011: case Opcode.FLOAD_2:
1012: case Opcode.FLOAD_3:
1013: case Opcode.DLOAD_0:
1014: case Opcode.DLOAD_1:
1015: case Opcode.DLOAD_2:
1016: case Opcode.DLOAD_3:
1017: case Opcode.ALOAD_0:
1018: case Opcode.ALOAD_1:
1019: case Opcode.ALOAD_2:
1020: case Opcode.ALOAD_3:
1021: if (index == 0 && mHasThis) {
1022: assembler.loadThis();
1023: } else {
1024: assembler.loadLocal(getLocalVariable(index,
1025: type));
1026: }
1027: break;
1028: case Opcode.ISTORE:
1029: case Opcode.LSTORE:
1030: case Opcode.FSTORE:
1031: case Opcode.DSTORE:
1032: case Opcode.ASTORE:
1033: case Opcode.ISTORE_0:
1034: case Opcode.ISTORE_1:
1035: case Opcode.ISTORE_2:
1036: case Opcode.ISTORE_3:
1037: case Opcode.LSTORE_0:
1038: case Opcode.LSTORE_1:
1039: case Opcode.LSTORE_2:
1040: case Opcode.LSTORE_3:
1041: case Opcode.FSTORE_0:
1042: case Opcode.FSTORE_1:
1043: case Opcode.FSTORE_2:
1044: case Opcode.FSTORE_3:
1045: case Opcode.DSTORE_0:
1046: case Opcode.DSTORE_1:
1047: case Opcode.DSTORE_2:
1048: case Opcode.DSTORE_3:
1049: case Opcode.ASTORE_0:
1050: case Opcode.ASTORE_1:
1051: case Opcode.ASTORE_2:
1052: case Opcode.ASTORE_3:
1053: if (index == 0 && mHasThis) {
1054: // The "this" reference just got blown away.
1055: mHasThis = false;
1056: }
1057: assembler.storeLocal(getLocalVariable(index, type));
1058: break;
1059: }
1060: break;
1061:
1062: case Opcode.RET:
1063: LocalVariable local = getLocalVariable(
1064: readUnsignedByte(), TypeDesc.OBJECT);
1065: assembler.ret(local);
1066: break;
1067:
1068: case Opcode.IINC:
1069: local = getLocalVariable(readUnsignedByte(),
1070: TypeDesc.INT);
1071: assembler.integerIncrement(local, readByte());
1072: break;
1073:
1074: // End opcodes that load or store local variables.
1075:
1076: // Opcodes that branch to another address.
1077:
1078: case Opcode.GOTO:
1079: loc = getLabel(mAddress + readShort());
1080: assembler.branch(loc);
1081: break;
1082: case Opcode.JSR:
1083: loc = getLabel(mAddress + readShort());
1084: assembler.jsr(loc);
1085: break;
1086: case Opcode.GOTO_W:
1087: loc = getLabel(mAddress + readInt());
1088: assembler.branch(loc);
1089: break;
1090: case Opcode.JSR_W:
1091: loc = getLabel(mAddress + readInt());
1092: assembler.jsr(loc);
1093: break;
1094:
1095: case Opcode.IFNULL:
1096: loc = getLabel(mAddress + readShort());
1097: assembler.ifNullBranch(loc, true);
1098: break;
1099: case Opcode.IFNONNULL:
1100: loc = getLabel(mAddress + readShort());
1101: assembler.ifNullBranch(loc, false);
1102: break;
1103:
1104: case Opcode.IF_ACMPEQ:
1105: loc = getLabel(mAddress + readShort());
1106: assembler.ifEqualBranch(loc, true);
1107: break;
1108: case Opcode.IF_ACMPNE:
1109: loc = getLabel(mAddress + readShort());
1110: assembler.ifEqualBranch(loc, false);
1111: break;
1112:
1113: case Opcode.IFEQ:
1114: case Opcode.IFNE:
1115: case Opcode.IFLT:
1116: case Opcode.IFGE:
1117: case Opcode.IFGT:
1118: case Opcode.IFLE:
1119: loc = getLabel(mAddress + readShort());
1120: String choice;
1121: switch (opcode) {
1122: case Opcode.IFEQ:
1123: choice = "==";
1124: break;
1125: case Opcode.IFNE:
1126: choice = "!=";
1127: break;
1128: case Opcode.IFLT:
1129: choice = "<";
1130: break;
1131: case Opcode.IFGE:
1132: choice = ">=";
1133: break;
1134: case Opcode.IFGT:
1135: choice = ">";
1136: break;
1137: case Opcode.IFLE:
1138: choice = "<=";
1139: break;
1140: default:
1141: choice = null;
1142: break;
1143: }
1144: assembler.ifZeroComparisonBranch(loc, choice);
1145: break;
1146:
1147: case Opcode.IF_ICMPEQ:
1148: case Opcode.IF_ICMPNE:
1149: case Opcode.IF_ICMPLT:
1150: case Opcode.IF_ICMPGE:
1151: case Opcode.IF_ICMPGT:
1152: case Opcode.IF_ICMPLE:
1153: loc = getLabel(mAddress + readShort());
1154: switch (opcode) {
1155: case Opcode.IF_ICMPEQ:
1156: choice = "==";
1157: break;
1158: case Opcode.IF_ICMPNE:
1159: choice = "!=";
1160: break;
1161: case Opcode.IF_ICMPLT:
1162: choice = "<";
1163: break;
1164: case Opcode.IF_ICMPGE:
1165: choice = ">=";
1166: break;
1167: case Opcode.IF_ICMPGT:
1168: choice = ">";
1169: break;
1170: case Opcode.IF_ICMPLE:
1171: choice = "<=";
1172: break;
1173: default:
1174: choice = null;
1175: break;
1176: }
1177: assembler.ifComparisonBranch(loc, choice);
1178: break;
1179:
1180: // End opcodes that branch to another address.
1181:
1182: // Miscellaneous opcodes...
1183:
1184: case Opcode.BIPUSH:
1185: assembler.loadConstant(readByte());
1186: break;
1187: case Opcode.SIPUSH:
1188: assembler.loadConstant(readShort());
1189: break;
1190:
1191: case Opcode.NEWARRAY:
1192: int atype = readByte();
1193: type = null;
1194: switch (atype) {
1195: case 4: // T_BOOLEAN
1196: type = TypeDesc.BOOLEAN;
1197: break;
1198: case 5: // T_CHAR
1199: type = TypeDesc.CHAR;
1200: break;
1201: case 6: // T_FLOAT
1202: type = TypeDesc.FLOAT;
1203: break;
1204: case 7: // T_DOUBLE
1205: type = TypeDesc.DOUBLE;
1206: break;
1207: case 8: // T_BYTE
1208: type = TypeDesc.BYTE;
1209: break;
1210: case 9: // T_SHORT
1211: type = TypeDesc.SHORT;
1212: break;
1213: case 10: // T_INT
1214: type = TypeDesc.INT;
1215: break;
1216: case 11: // T_LONG
1217: type = TypeDesc.LONG;
1218: break;
1219: }
1220:
1221: if (type == null) {
1222: error(opcode,
1223: "Unknown primitive type for new array: "
1224: + atype);
1225: break;
1226: }
1227:
1228: assembler.newObject(type.toArrayType());
1229: break;
1230:
1231: case Opcode.TABLESWITCH:
1232: case Opcode.LOOKUPSWITCH:
1233: int opcodeAddress = mAddress;
1234: // Read padding until address is 32 bit word aligned.
1235: while (((mAddress + 1) & 3) != 0) {
1236: ++mAddress;
1237: }
1238: Location defaultLocation = getLabel(opcodeAddress
1239: + readInt());
1240: int[] cases;
1241: Location[] locations;
1242:
1243: if (opcode == Opcode.TABLESWITCH) {
1244: int lowValue = readInt();
1245: int highValue = readInt();
1246: int caseCount = highValue - lowValue + 1;
1247: try {
1248: cases = new int[caseCount];
1249: } catch (NegativeArraySizeException e) {
1250: error(opcode,
1251: "Negative case count for switch: "
1252: + caseCount);
1253: break;
1254: }
1255: locations = new Location[caseCount];
1256: for (int i = 0; i < caseCount; i++) {
1257: cases[i] = lowValue + i;
1258: locations[i] = getLabel(opcodeAddress
1259: + readInt());
1260: }
1261: } else {
1262: int caseCount = readInt();
1263: try {
1264: cases = new int[caseCount];
1265: } catch (NegativeArraySizeException e) {
1266: error(opcode,
1267: "Negative case count for switch: "
1268: + caseCount);
1269: break;
1270: }
1271: locations = new Location[caseCount];
1272: for (int i = 0; i < caseCount; i++) {
1273: cases[i] = readInt();
1274: locations[i] = getLabel(opcodeAddress
1275: + readInt());
1276: }
1277: }
1278:
1279: assembler.switchBranch(cases, locations,
1280: defaultLocation);
1281: break;
1282:
1283: case Opcode.WIDE:
1284: opcode = mByteCodes[++mAddress];
1285: switch (opcode) {
1286:
1287: default:
1288: error(opcode, "Unknown wide instruction");
1289: break;
1290:
1291: case Opcode.ILOAD:
1292: case Opcode.ISTORE:
1293: case Opcode.LLOAD:
1294: case Opcode.LSTORE:
1295: case Opcode.FLOAD:
1296: case Opcode.FSTORE:
1297: case Opcode.DLOAD:
1298: case Opcode.DSTORE:
1299: case Opcode.ALOAD:
1300: case Opcode.ASTORE:
1301:
1302: switch (opcode) {
1303: case Opcode.ILOAD:
1304: case Opcode.ISTORE:
1305: type = TypeDesc.INT;
1306: break;
1307: case Opcode.LLOAD:
1308: case Opcode.LSTORE:
1309: type = TypeDesc.LONG;
1310: break;
1311: case Opcode.FLOAD:
1312: case Opcode.FSTORE:
1313: type = TypeDesc.FLOAT;
1314: break;
1315: case Opcode.DLOAD:
1316: case Opcode.DSTORE:
1317: type = TypeDesc.DOUBLE;
1318: break;
1319: case Opcode.ALOAD:
1320: case Opcode.ASTORE:
1321: type = TypeDesc.OBJECT;
1322: break;
1323: default:
1324: type = null;
1325: break;
1326: }
1327:
1328: index = readUnsignedShort();
1329:
1330: switch (opcode) {
1331: case Opcode.ILOAD:
1332: case Opcode.LLOAD:
1333: case Opcode.FLOAD:
1334: case Opcode.DLOAD:
1335: case Opcode.ALOAD:
1336: if (index == 0 && mHasThis) {
1337: assembler.loadThis();
1338: } else {
1339: assembler.loadLocal(getLocalVariable(index,
1340: type));
1341: }
1342: break;
1343: case Opcode.ISTORE:
1344: case Opcode.LSTORE:
1345: case Opcode.FSTORE:
1346: case Opcode.DSTORE:
1347: case Opcode.ASTORE:
1348: if (index == 0 && mHasThis) {
1349: // The "this" reference just got blown away.
1350: mHasThis = false;
1351: }
1352: assembler.storeLocal(getLocalVariable(index,
1353: type));
1354: break;
1355: }
1356: break;
1357:
1358: case Opcode.RET:
1359: local = getLocalVariable(readUnsignedShort(),
1360: TypeDesc.OBJECT);
1361: assembler.ret(local);
1362: break;
1363:
1364: case Opcode.IINC:
1365: local = getLocalVariable(readUnsignedShort(),
1366: TypeDesc.INT);
1367: assembler.integerIncrement(local, readShort());
1368: break;
1369: }
1370:
1371: break;
1372: } // end huge switch
1373: } // end for loop
1374: }
1375:
1376: /**
1377: * Invoked on disassembly errors. By default, this method does nothing.
1378: */
1379: protected void error(byte opcode, String message) {
1380: }
1381:
1382: private void gatherLabels() {
1383: mLabels = new HashMap();
1384: mCatchLocations = new HashMap(mExceptionHandlers.length * 2 + 1);
1385: Integer labelKey;
1386:
1387: // Gather labels for any exception handlers.
1388: for (int i = mExceptionHandlers.length - 1; i >= 0; i--) {
1389: ExceptionHandler handler = mExceptionHandlers[i];
1390: labelKey = new Integer(handler.getStartLocation()
1391: .getLocation());
1392: mLabels.put(labelKey, labelKey);
1393: labelKey = new Integer(handler.getEndLocation()
1394: .getLocation());
1395: mLabels.put(labelKey, labelKey);
1396: labelKey = new Integer(handler.getCatchLocation()
1397: .getLocation());
1398: List list = (List) mCatchLocations.get(labelKey);
1399: if (list == null) {
1400: list = new ArrayList(2);
1401: mCatchLocations.put(labelKey, list);
1402: }
1403: list.add(handler);
1404: }
1405:
1406: // Now gather labels that occur within byte code.
1407: for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
1408: byte opcode = mByteCodes[mAddress];
1409:
1410: switch (opcode) {
1411:
1412: default:
1413: error(opcode, "Unknown opcode: " + (opcode & 0xff));
1414: break;
1415:
1416: // Opcodes that use labels.
1417:
1418: case Opcode.GOTO:
1419: case Opcode.JSR:
1420: case Opcode.IFNULL:
1421: case Opcode.IFNONNULL:
1422: case Opcode.IF_ACMPEQ:
1423: case Opcode.IF_ACMPNE:
1424: case Opcode.IFEQ:
1425: case Opcode.IFNE:
1426: case Opcode.IFLT:
1427: case Opcode.IFGE:
1428: case Opcode.IFGT:
1429: case Opcode.IFLE:
1430: case Opcode.IF_ICMPEQ:
1431: case Opcode.IF_ICMPNE:
1432: case Opcode.IF_ICMPLT:
1433: case Opcode.IF_ICMPGE:
1434: case Opcode.IF_ICMPGT:
1435: case Opcode.IF_ICMPLE:
1436: labelKey = new Integer(mAddress + readShort());
1437: mLabels.put(labelKey, labelKey);
1438: break;
1439:
1440: case Opcode.GOTO_W:
1441: case Opcode.JSR_W:
1442: labelKey = new Integer(mAddress + readInt());
1443: mLabels.put(labelKey, labelKey);
1444: break;
1445:
1446: case Opcode.TABLESWITCH:
1447: case Opcode.LOOKUPSWITCH:
1448: int opcodeAddress = mAddress;
1449: // Read padding until address is 32 bit word aligned.
1450: while (((mAddress + 1) & 3) != 0) {
1451: ++mAddress;
1452: }
1453:
1454: // Read the default location.
1455: labelKey = new Integer(opcodeAddress + readInt());
1456: mLabels.put(labelKey, labelKey);
1457:
1458: if (opcode == Opcode.TABLESWITCH) {
1459: int lowValue = readInt();
1460: int highValue = readInt();
1461: int caseCount = highValue - lowValue + 1;
1462:
1463: for (int i = 0; i < caseCount; i++) {
1464: // Read the branch location.
1465: labelKey = new Integer(opcodeAddress
1466: + readInt());
1467: mLabels.put(labelKey, labelKey);
1468: }
1469: } else {
1470: int caseCount = readInt();
1471:
1472: for (int i = 0; i < caseCount; i++) {
1473: // Skip the case value.
1474: mAddress += 4;
1475: // Read the branch location.
1476: labelKey = new Integer(opcodeAddress
1477: + readInt());
1478: mLabels.put(labelKey, labelKey);
1479: }
1480: }
1481: break;
1482:
1483: // All other operations are skipped. The amount to skip
1484: // depends on the operand size.
1485:
1486: // Opcodes with no operands...
1487:
1488: case Opcode.NOP:
1489: case Opcode.BREAKPOINT:
1490: case Opcode.ACONST_NULL:
1491: case Opcode.ICONST_M1:
1492: case Opcode.ICONST_0:
1493: case Opcode.ICONST_1:
1494: case Opcode.ICONST_2:
1495: case Opcode.ICONST_3:
1496: case Opcode.ICONST_4:
1497: case Opcode.ICONST_5:
1498: case Opcode.LCONST_0:
1499: case Opcode.LCONST_1:
1500: case Opcode.FCONST_0:
1501: case Opcode.FCONST_1:
1502: case Opcode.FCONST_2:
1503: case Opcode.DCONST_0:
1504: case Opcode.DCONST_1:
1505: case Opcode.POP:
1506: case Opcode.POP2:
1507: case Opcode.DUP:
1508: case Opcode.DUP_X1:
1509: case Opcode.DUP_X2:
1510: case Opcode.DUP2:
1511: case Opcode.DUP2_X1:
1512: case Opcode.DUP2_X2:
1513: case Opcode.SWAP:
1514: case Opcode.IADD:
1515: case Opcode.LADD:
1516: case Opcode.FADD:
1517: case Opcode.DADD:
1518: case Opcode.ISUB:
1519: case Opcode.LSUB:
1520: case Opcode.FSUB:
1521: case Opcode.DSUB:
1522: case Opcode.IMUL:
1523: case Opcode.LMUL:
1524: case Opcode.FMUL:
1525: case Opcode.DMUL:
1526: case Opcode.IDIV:
1527: case Opcode.LDIV:
1528: case Opcode.FDIV:
1529: case Opcode.DDIV:
1530: case Opcode.IREM:
1531: case Opcode.LREM:
1532: case Opcode.FREM:
1533: case Opcode.DREM:
1534: case Opcode.INEG:
1535: case Opcode.LNEG:
1536: case Opcode.FNEG:
1537: case Opcode.DNEG:
1538: case Opcode.ISHL:
1539: case Opcode.LSHL:
1540: case Opcode.ISHR:
1541: case Opcode.LSHR:
1542: case Opcode.IUSHR:
1543: case Opcode.LUSHR:
1544: case Opcode.IAND:
1545: case Opcode.LAND:
1546: case Opcode.IOR:
1547: case Opcode.LOR:
1548: case Opcode.IXOR:
1549: case Opcode.LXOR:
1550: case Opcode.FCMPL:
1551: case Opcode.DCMPL:
1552: case Opcode.FCMPG:
1553: case Opcode.DCMPG:
1554: case Opcode.LCMP:
1555: case Opcode.I2L:
1556: case Opcode.I2F:
1557: case Opcode.I2D:
1558: case Opcode.L2I:
1559: case Opcode.L2F:
1560: case Opcode.L2D:
1561: case Opcode.F2I:
1562: case Opcode.F2L:
1563: case Opcode.F2D:
1564: case Opcode.D2I:
1565: case Opcode.D2L:
1566: case Opcode.D2F:
1567: case Opcode.I2B:
1568: case Opcode.I2C:
1569: case Opcode.I2S:
1570: case Opcode.IRETURN:
1571: case Opcode.LRETURN:
1572: case Opcode.FRETURN:
1573: case Opcode.DRETURN:
1574: case Opcode.ARETURN:
1575: case Opcode.RETURN:
1576: case Opcode.IALOAD:
1577: case Opcode.LALOAD:
1578: case Opcode.FALOAD:
1579: case Opcode.DALOAD:
1580: case Opcode.AALOAD:
1581: case Opcode.BALOAD:
1582: case Opcode.CALOAD:
1583: case Opcode.SALOAD:
1584: case Opcode.IASTORE:
1585: case Opcode.LASTORE:
1586: case Opcode.FASTORE:
1587: case Opcode.DASTORE:
1588: case Opcode.AASTORE:
1589: case Opcode.BASTORE:
1590: case Opcode.CASTORE:
1591: case Opcode.SASTORE:
1592: case Opcode.ARRAYLENGTH:
1593: case Opcode.ATHROW:
1594: case Opcode.MONITORENTER:
1595: case Opcode.MONITOREXIT:
1596: case Opcode.ILOAD_0:
1597: case Opcode.ISTORE_0:
1598: case Opcode.ILOAD_1:
1599: case Opcode.ISTORE_1:
1600: case Opcode.ILOAD_2:
1601: case Opcode.ISTORE_2:
1602: case Opcode.ILOAD_3:
1603: case Opcode.ISTORE_3:
1604: case Opcode.LLOAD_0:
1605: case Opcode.LSTORE_0:
1606: case Opcode.LLOAD_1:
1607: case Opcode.LSTORE_1:
1608: case Opcode.LLOAD_2:
1609: case Opcode.LSTORE_2:
1610: case Opcode.LLOAD_3:
1611: case Opcode.LSTORE_3:
1612: case Opcode.FLOAD_0:
1613: case Opcode.FSTORE_0:
1614: case Opcode.FLOAD_1:
1615: case Opcode.FSTORE_1:
1616: case Opcode.FLOAD_2:
1617: case Opcode.FSTORE_2:
1618: case Opcode.FLOAD_3:
1619: case Opcode.FSTORE_3:
1620: case Opcode.DLOAD_0:
1621: case Opcode.DSTORE_0:
1622: case Opcode.DLOAD_1:
1623: case Opcode.DSTORE_1:
1624: case Opcode.DLOAD_2:
1625: case Opcode.DSTORE_2:
1626: case Opcode.DLOAD_3:
1627: case Opcode.DSTORE_3:
1628: case Opcode.ALOAD_0:
1629: case Opcode.ASTORE_0:
1630: case Opcode.ALOAD_1:
1631: case Opcode.ASTORE_1:
1632: case Opcode.ALOAD_2:
1633: case Opcode.ASTORE_2:
1634: case Opcode.ALOAD_3:
1635: case Opcode.ASTORE_3:
1636: break;
1637:
1638: // Opcodes with one operand byte...
1639:
1640: case Opcode.LDC:
1641: case Opcode.ILOAD:
1642: case Opcode.ISTORE:
1643: case Opcode.LLOAD:
1644: case Opcode.LSTORE:
1645: case Opcode.FLOAD:
1646: case Opcode.FSTORE:
1647: case Opcode.DLOAD:
1648: case Opcode.DSTORE:
1649: case Opcode.ALOAD:
1650: case Opcode.ASTORE:
1651: case Opcode.RET:
1652: case Opcode.BIPUSH:
1653: case Opcode.NEWARRAY:
1654: mAddress += 1;
1655: break;
1656:
1657: // Opcodes with two operand bytes...
1658:
1659: case Opcode.LDC_W:
1660: case Opcode.LDC2_W:
1661: case Opcode.NEW:
1662: case Opcode.ANEWARRAY:
1663: case Opcode.CHECKCAST:
1664: case Opcode.INSTANCEOF:
1665: case Opcode.GETSTATIC:
1666: case Opcode.PUTSTATIC:
1667: case Opcode.GETFIELD:
1668: case Opcode.PUTFIELD:
1669: case Opcode.INVOKEVIRTUAL:
1670: case Opcode.INVOKESPECIAL:
1671: case Opcode.INVOKESTATIC:
1672: case Opcode.SIPUSH:
1673: case Opcode.IINC:
1674: mAddress += 2;
1675: break;
1676:
1677: // Opcodes with three operand bytes...
1678:
1679: case Opcode.MULTIANEWARRAY:
1680: mAddress += 3;
1681: break;
1682:
1683: // Opcodes with four operand bytes...
1684:
1685: case Opcode.INVOKEINTERFACE:
1686: mAddress += 4;
1687: break;
1688:
1689: // Wide opcode has a variable sized operand.
1690:
1691: case Opcode.WIDE:
1692: opcode = mByteCodes[++mAddress];
1693: mAddress += 2;
1694: if (opcode == Opcode.IINC) {
1695: mAddress += 2;
1696: }
1697: break;
1698: } // end huge switch
1699: } // end for loop
1700: }
1701:
1702: private int readByte() {
1703: return mByteCodes[++mAddress];
1704: }
1705:
1706: private int readUnsignedByte() {
1707: return mByteCodes[++mAddress] & 0xff;
1708: }
1709:
1710: private int readShort() {
1711: return (mByteCodes[++mAddress] << 8)
1712: | (mByteCodes[++mAddress] & 0xff);
1713: }
1714:
1715: private int readUnsignedShort() {
1716: return ((mByteCodes[++mAddress] & 0xff) << 8)
1717: | ((mByteCodes[++mAddress] & 0xff) << 0);
1718: }
1719:
1720: private int readInt() {
1721: return (mByteCodes[++mAddress] << 24)
1722: | ((mByteCodes[++mAddress] & 0xff) << 16)
1723: | ((mByteCodes[++mAddress] & 0xff) << 8)
1724: | ((mByteCodes[++mAddress] & 0xff) << 0);
1725: }
1726:
1727: private LocalVariable getLocalVariable(final int index,
1728: final TypeDesc type) {
1729: LocalVariable local;
1730:
1731: if (index >= mLocals.size()) {
1732: mLocals.setSize(index + 1);
1733: local = mAssembler.createLocalVariable(null, type);
1734: mLocals.set(index, local);
1735: return local;
1736: }
1737:
1738: Object obj = mLocals.get(index);
1739:
1740: if (obj == null) {
1741: local = mAssembler.createLocalVariable(null, type);
1742: mLocals.set(index, local);
1743: return local;
1744: }
1745:
1746: if (obj instanceof LocalVariable) {
1747: local = (LocalVariable) obj;
1748: if (compatibleType(type, local.getType())) {
1749: return local;
1750: }
1751: // Variable takes on multiple types, so convert entry to a list.
1752: List locals = new ArrayList(4);
1753: locals.add(local);
1754: local = mAssembler.createLocalVariable(null, type);
1755: locals.add(local);
1756: mLocals.set(index, locals);
1757: return local;
1758: }
1759:
1760: List locals = (List) obj;
1761: for (int i = locals.size(); --i >= 0;) {
1762: local = (LocalVariable) locals.get(i);
1763: if (compatibleType(type, local.getType())) {
1764: return local;
1765: }
1766: }
1767:
1768: local = mAssembler.createLocalVariable(null, type);
1769: locals.add(local);
1770: return local;
1771: }
1772:
1773: private boolean compatibleType(TypeDesc a, TypeDesc b) {
1774: if (a == b || (!a.isPrimitive() && !b.isPrimitive())) {
1775: return true;
1776: }
1777: if (isIntType(a) && isIntType(b)) {
1778: return true;
1779: }
1780: return false;
1781: }
1782:
1783: private boolean isIntType(TypeDesc type) {
1784: switch (type.getTypeCode()) {
1785: case TypeDesc.INT_CODE:
1786: case TypeDesc.BOOLEAN_CODE:
1787: case TypeDesc.BYTE_CODE:
1788: case TypeDesc.SHORT_CODE:
1789: case TypeDesc.CHAR_CODE:
1790: return true;
1791: }
1792: return false;
1793: }
1794:
1795: private void locateLabel() {
1796: Integer labelKey = new Integer(mAddress);
1797: Object labelValue = mLabels.get(labelKey);
1798: if (labelValue != null) {
1799: if (labelValue instanceof Label) {
1800: ((Label) labelValue).setLocation();
1801: } else {
1802: labelValue = mAssembler.createLabel().setLocation();
1803: mLabels.put(labelKey, labelValue);
1804: }
1805: }
1806:
1807: List handlers = (List) mCatchLocations.get(labelKey);
1808:
1809: if (handlers != null) {
1810: for (int i = 0; i < handlers.size(); i++) {
1811: ExceptionHandler handler = (ExceptionHandler) handlers
1812: .get(i);
1813: Label start = getLabel(handler.getStartLocation()
1814: .getLocation());
1815: Label end = getLabel(handler.getEndLocation()
1816: .getLocation());
1817: String catchClassName;
1818: if (handler.getCatchType() == null) {
1819: catchClassName = null;
1820: } else {
1821: catchClassName = handler.getCatchType().getType()
1822: .getFullName();
1823: }
1824: mAssembler.exceptionHandler(start, end, catchClassName);
1825: }
1826: }
1827: }
1828:
1829: private Label getLabel(int address) {
1830: Integer labelKey = new Integer(address);
1831: Object labelValue = mLabels.get(labelKey);
1832: // labelValue will never be null unless gatherLabels is broken.
1833: if (!(labelValue instanceof Label)) {
1834: labelValue = mAssembler.createLabel();
1835: mLabels.put(labelKey, labelValue);
1836: }
1837: return (Label) labelValue;
1838: }
1839: }
|