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.io.PrintWriter;
0020: import java.util.ArrayList;
0021: import java.util.Arrays;
0022: import java.util.Comparator;
0023: import java.util.Date;
0024: import java.util.HashMap;
0025: import java.util.Iterator;
0026: import java.util.List;
0027: import java.util.Map;
0028:
0029: import org.cojen.classfile.attribute.Annotation;
0030: import org.cojen.classfile.attribute.CodeAttr;
0031: import org.cojen.classfile.attribute.SignatureAttr;
0032: import org.cojen.classfile.constant.ConstantClassInfo;
0033: import org.cojen.classfile.constant.ConstantDoubleInfo;
0034: import org.cojen.classfile.constant.ConstantFieldInfo;
0035: import org.cojen.classfile.constant.ConstantFloatInfo;
0036: import org.cojen.classfile.constant.ConstantIntegerInfo;
0037: import org.cojen.classfile.constant.ConstantInterfaceMethodInfo;
0038: import org.cojen.classfile.constant.ConstantLongInfo;
0039: import org.cojen.classfile.constant.ConstantMethodInfo;
0040: import org.cojen.classfile.constant.ConstantNameAndTypeInfo;
0041: import org.cojen.classfile.constant.ConstantStringInfo;
0042: import org.cojen.classfile.constant.ConstantUTFInfo;
0043:
0044: /**
0045: * Disassembles a ClassFile into a pseudo Java assembly language format.
0046: *
0047: * @author Brian S O'Neill
0048: */
0049: class AssemblyStylePrinter implements DisassemblyTool.Printer {
0050: private ClassFile mClassFile;
0051: private ConstantPool mCp;
0052: private PrintWriter mOut;
0053:
0054: private byte[] mByteCodes;
0055: // Current address being decompiled.
0056: private int mAddress;
0057:
0058: // Maps Integer address keys to String labels.
0059: private Map mLabels;
0060:
0061: private ExceptionHandler[] mExceptionHandlers;
0062:
0063: // Maps Integer catch locations to Lists of ExceptionHandler objects.
0064: private Map mCatchLocations;
0065:
0066: public AssemblyStylePrinter() {
0067: }
0068:
0069: public void disassemble(ClassFile cf, PrintWriter out) {
0070: disassemble(cf, out, "");
0071: }
0072:
0073: private void disassemble(ClassFile cf, PrintWriter out,
0074: String indent) {
0075: mClassFile = cf;
0076: mCp = cf.getConstantPool();
0077: mOut = out;
0078:
0079: if (indent.length() == 0 || mClassFile.getSourceFile() != null
0080: || mClassFile.isDeprecated()
0081: || mClassFile.isSynthetic()) {
0082:
0083: println(indent, "/**");
0084:
0085: boolean addBreak = false;
0086:
0087: if (indent.length() == 0) {
0088: print(indent, " * Disassembled on ");
0089: print(new Date());
0090: println(".");
0091: addBreak = true;
0092: }
0093:
0094: if (indent.length() == 0 && mClassFile.getTarget() != null) {
0095: if (addBreak) {
0096: println(indent, " * ");
0097: addBreak = false;
0098: }
0099: print(indent, " * @target ");
0100: println(CodeAssemblerPrinter.escape(mClassFile
0101: .getTarget()));
0102: }
0103:
0104: if (mClassFile.getSourceFile() != null) {
0105: if (addBreak) {
0106: println(indent, " * ");
0107: addBreak = false;
0108: }
0109: print(indent, " * @source ");
0110: println(CodeAssemblerPrinter.escape(mClassFile
0111: .getSourceFile()));
0112: }
0113:
0114: if (mClassFile.isInnerClass()) {
0115: if (addBreak) {
0116: println(indent, " * ");
0117: addBreak = false;
0118: }
0119: if (mClassFile.getInnerClassName() == null) {
0120: println(indent, " * @anonymous");
0121: } else {
0122: print(indent, " * @name ");
0123: println(CodeAssemblerPrinter.escape(mClassFile
0124: .getInnerClassName()));
0125: }
0126: }
0127:
0128: if (mClassFile.isDeprecated()) {
0129: if (addBreak) {
0130: println(indent, " * ");
0131: addBreak = false;
0132: }
0133: println(indent, " * @deprecated");
0134: }
0135:
0136: if (mClassFile.isSynthetic()) {
0137: if (addBreak) {
0138: println(indent, " * ");
0139: addBreak = false;
0140: }
0141: println(indent, " * @synthetic");
0142: }
0143:
0144: // TODO: Just testing
0145: SignatureAttr sig = mClassFile.getSignatureAttr();
0146: if (sig != null) {
0147: if (addBreak) {
0148: println(indent, " * ");
0149: addBreak = false;
0150: }
0151: println(indent, " * @signature "
0152: + sig.getSignature().getValue());
0153: }
0154:
0155: println(indent, " */");
0156: }
0157:
0158: disassemble(indent, mClassFile.getRuntimeVisibleAnnotations());
0159: disassemble(indent, mClassFile.getRuntimeInvisibleAnnotations());
0160:
0161: print(indent);
0162:
0163: disassemble(mClassFile.getModifiers());
0164: boolean isInterface = mClassFile.getModifiers().isInterface();
0165: if (!isInterface) {
0166: print("class ");
0167: }
0168: print(mClassFile.getClassName());
0169:
0170: if (mClassFile.getSuperClassName() != null) {
0171: print(" extends ");
0172: print(mClassFile.getSuperClassName());
0173: }
0174:
0175: String innerIndent = indent + " ";
0176:
0177: String[] interfaces = mClassFile.getInterfaces();
0178: if (interfaces.length == 0) {
0179: println(" {");
0180: } else {
0181: println();
0182: for (int i = 0; i < interfaces.length; i++) {
0183: if (i == 0) {
0184: print(innerIndent, "implements ");
0185: } else {
0186: println(",");
0187: print(innerIndent, " ");
0188: }
0189: print(interfaces[i]);
0190: }
0191: println();
0192: println(indent, "{");
0193: }
0194:
0195: FieldInfo[] fields = mClassFile.getFields();
0196: MethodInfo[] methods = mClassFile.getMethods();
0197: MethodInfo[] ctors = mClassFile.getConstructors();
0198: MethodInfo init = mClassFile.getInitializer();
0199:
0200: Object[] members = new Object[fields.length + methods.length
0201: + ctors.length + ((init == null) ? 0 : 1)];
0202:
0203: int m = 0;
0204:
0205: for (int i = 0; i < fields.length; i++) {
0206: members[m++] = fields[i];
0207: }
0208:
0209: for (int i = 0; i < methods.length; i++) {
0210: members[m++] = methods[i];
0211: }
0212:
0213: for (int i = 0; i < ctors.length; i++) {
0214: members[m++] = ctors[i];
0215: }
0216:
0217: if (init != null) {
0218: members[m++] = init;
0219: }
0220:
0221: sortMembers(members);
0222:
0223: for (int i = 0; i < members.length; i++) {
0224: if (i > 0) {
0225: println();
0226: }
0227: if (members[i] instanceof FieldInfo) {
0228: disassemble(innerIndent, (FieldInfo) members[i]);
0229: } else {
0230: disassemble(innerIndent, (MethodInfo) members[i]);
0231: }
0232: }
0233:
0234: mByteCodes = null;
0235: mLabels = null;
0236: mExceptionHandlers = null;
0237: mCatchLocations = null;
0238:
0239: ClassFile[] innerClasses = mClassFile.getInnerClasses();
0240:
0241: for (int i = 0; i < innerClasses.length; i++) {
0242: if (i > 0 || members.length > 0) {
0243: println();
0244: }
0245: AssemblyStylePrinter printer = new AssemblyStylePrinter();
0246: printer.disassemble(innerClasses[i], mOut, innerIndent);
0247: }
0248:
0249: println(indent, "}");
0250:
0251: mOut.flush();
0252: mOut = null;
0253: }
0254:
0255: private void disassemble(String indent, FieldInfo field) {
0256: SignatureAttr sig = field.getSignatureAttr();
0257: if (field.isDeprecated() || field.isSynthetic() || sig != null) {
0258: println(indent, "/**");
0259: if (field.isDeprecated()) {
0260: println(indent, " * @deprecated");
0261: }
0262: if (field.isSynthetic()) {
0263: println(indent, " * @synthetic");
0264: }
0265: if (sig != null) {
0266: println(indent, " * @signature "
0267: + sig.getSignature().getValue());
0268: }
0269: println(indent, " */");
0270: }
0271:
0272: disassemble(indent, field.getRuntimeVisibleAnnotations());
0273: disassemble(indent, field.getRuntimeInvisibleAnnotations());
0274:
0275: print(indent);
0276: disassemble(field.getModifiers());
0277: disassemble(field.getType());
0278: print(" ");
0279: print(field.getName());
0280: ConstantInfo constant = field.getConstantValue();
0281: if (constant != null) {
0282: print(" = ");
0283: disassemble(constant);
0284: }
0285: println(";");
0286: }
0287:
0288: private void disassemble(String indent, MethodInfo method) {
0289: SignatureAttr sig = method.getSignatureAttr();
0290: if (method.isDeprecated() || method.isSynthetic()
0291: || sig != null) {
0292: println(indent, "/**");
0293: if (method.isDeprecated()) {
0294: println(indent, " * @deprecated");
0295: }
0296: if (method.isSynthetic()) {
0297: println(indent, " * @synthetic");
0298: }
0299: if (sig != null) {
0300: println(indent, " * @signature "
0301: + sig.getSignature().getValue());
0302: }
0303: println(indent, " */");
0304: }
0305:
0306: disassemble(indent, method.getRuntimeVisibleAnnotations());
0307: disassemble(indent, method.getRuntimeInvisibleAnnotations());
0308:
0309: print(indent);
0310:
0311: MethodDesc md = method.getMethodDescriptor();
0312:
0313: if ("<clinit>".equals(method.getName())
0314: && md.getReturnType() == TypeDesc.VOID
0315: && md.getParameterCount() == 0
0316: && (method.getModifiers().isStatic())
0317: && (!method.getModifiers().isAbstract())
0318: && method.getExceptions().length == 0) {
0319:
0320: // Static initializer.
0321: print("static");
0322: } else {
0323: Modifiers modifiers = method.getModifiers();
0324: boolean varargs = modifiers.isVarArgs();
0325: if (varargs) {
0326: // Don't display the modifier.
0327: modifiers = modifiers.toVarArgs(false);
0328: }
0329: disassemble(modifiers);
0330: print(md.toMethodSignature(method.getName(), varargs));
0331: }
0332:
0333: CodeAttr code = method.getCodeAttr();
0334:
0335: TypeDesc[] exceptions = method.getExceptions();
0336: if (exceptions.length == 0) {
0337: if (code == null) {
0338: println(";");
0339: } else {
0340: println(" {");
0341: }
0342: } else {
0343: println();
0344: for (int i = 0; i < exceptions.length; i++) {
0345: if (i == 0) {
0346: print(indent + " ", "throws ");
0347: } else {
0348: println(",");
0349: print(indent + " ", " ");
0350: }
0351: print(exceptions[i].getFullName());
0352: }
0353: if (code == null) {
0354: println(";");
0355: } else {
0356: println();
0357: println(indent, "{");
0358: }
0359: }
0360:
0361: if (code != null) {
0362: disassemble(indent + " ", code);
0363: println(indent, "}");
0364: }
0365: }
0366:
0367: private void disassemble(Modifiers modifiers) {
0368: print(modifiers);
0369: if (modifiers.getBitmask() != 0) {
0370: print(" ");
0371: }
0372: }
0373:
0374: private void disassemble(ConstantInfo constant) {
0375: disassemble(constant, false);
0376: }
0377:
0378: private void disassemble(ConstantInfo constant,
0379: boolean showClassLiteral) {
0380: if (constant instanceof ConstantStringInfo) {
0381: print("\"");
0382: String value = ((ConstantStringInfo) constant).getValue();
0383: print(CodeAssemblerPrinter.escape(value));
0384: print("\"");
0385: } else if (constant instanceof ConstantIntegerInfo) {
0386: print(String.valueOf(((ConstantIntegerInfo) constant)
0387: .getValue()));
0388: } else if (constant instanceof ConstantLongInfo) {
0389: print(String.valueOf(((ConstantLongInfo) constant)
0390: .getValue()));
0391: print("L");
0392: } else if (constant instanceof ConstantFloatInfo) {
0393: float value = ((ConstantFloatInfo) constant).getValue();
0394: if (value != value) {
0395: print("0.0f/0.0f");
0396: } else if (value == Float.NEGATIVE_INFINITY) {
0397: print("-1.0f/0.0f");
0398: } else if (value == Float.POSITIVE_INFINITY) {
0399: print("1.0f/0.0f");
0400: } else {
0401: print(String.valueOf(value));
0402: print("f");
0403: }
0404: } else if (constant instanceof ConstantDoubleInfo) {
0405: double value = ((ConstantDoubleInfo) constant).getValue();
0406: if (value != value) {
0407: print("0.0d/0.0d");
0408: } else if (value == Float.NEGATIVE_INFINITY) {
0409: print("-1.0d/0.0d");
0410: } else if (value == Float.POSITIVE_INFINITY) {
0411: print("1.0d/0.0d");
0412: } else {
0413: print(String.valueOf(value));
0414: print("d");
0415: }
0416: } else if (constant instanceof ConstantClassInfo) {
0417: ConstantClassInfo cci = (ConstantClassInfo) constant;
0418: disassemble(cci.getType());
0419: if (showClassLiteral) {
0420: print(".class");
0421: }
0422: } else if (constant instanceof ConstantUTFInfo) {
0423: print("\"");
0424: String value = ((ConstantUTFInfo) constant).getValue();
0425: print(CodeAssemblerPrinter.escape(value));
0426: print("\"");
0427: } else {
0428: print(constant);
0429: }
0430: }
0431:
0432: private void disassemble(TypeDesc type) {
0433: print(type.getFullName());
0434: }
0435:
0436: private void disassemble(String indent, Annotation[] annotations) {
0437: for (int i = 0; i < annotations.length; i++) {
0438: print(indent);
0439: disassemble(indent, annotations[i]);
0440: println();
0441: }
0442: }
0443:
0444: private void disassemble(String indent, Annotation ann) {
0445: print("@");
0446: print(ann.getType().getFullName());
0447: Map mvMap = ann.getMemberValues();
0448: if (mvMap.size() == 0) {
0449: return;
0450: }
0451: print("(");
0452: Iterator it = mvMap.entrySet().iterator();
0453: int ordinal = 0;
0454: while (it.hasNext()) {
0455: if (ordinal++ > 0) {
0456: print(", ");
0457: }
0458: Map.Entry entry = (Map.Entry) it.next();
0459: String name = (String) entry.getKey();
0460: if (!"value".equals(name)) {
0461: print(name);
0462: print("=");
0463: }
0464: disassemble(indent, (Annotation.MemberValue) entry
0465: .getValue());
0466: }
0467: print(")");
0468: }
0469:
0470: private void disassemble(String indent, Annotation.MemberValue mv) {
0471: Object value = mv.getValue();
0472: switch (mv.getTag()) {
0473: default:
0474: print("?");
0475: break;
0476: case Annotation.MEMBER_TAG_BOOLEAN:
0477: ConstantIntegerInfo ci = (ConstantIntegerInfo) value;
0478: print(ci.getValue() == 0 ? "false" : "true");
0479: break;
0480: case Annotation.MEMBER_TAG_BYTE:
0481: case Annotation.MEMBER_TAG_SHORT:
0482: case Annotation.MEMBER_TAG_INT:
0483: case Annotation.MEMBER_TAG_LONG:
0484: case Annotation.MEMBER_TAG_FLOAT:
0485: case Annotation.MEMBER_TAG_DOUBLE:
0486: case Annotation.MEMBER_TAG_STRING:
0487: case Annotation.MEMBER_TAG_CLASS:
0488: disassemble((ConstantInfo) value, true);
0489: break;
0490: case Annotation.MEMBER_TAG_CHAR: {
0491: print("'");
0492: char c = (char) ((ConstantIntegerInfo) value).getValue();
0493: print(CodeAssemblerPrinter.escape(String.valueOf(c), true));
0494: print("'");
0495: break;
0496: }
0497: case Annotation.MEMBER_TAG_ENUM:
0498: Annotation.EnumConstValue ecv = (Annotation.EnumConstValue) value;
0499: print(TypeDesc.forDescriptor(ecv.getTypeName().getValue())
0500: .getFullName());
0501: print(".");
0502: print(ecv.getConstName().getValue());
0503: break;
0504: case Annotation.MEMBER_TAG_ANNOTATION:
0505: disassemble(indent, (Annotation) value);
0506: break;
0507: case Annotation.MEMBER_TAG_ARRAY:
0508: Annotation.MemberValue[] mvs = (Annotation.MemberValue[]) value;
0509:
0510: String originalIndent = indent;
0511: boolean multiLine = false;
0512: if (mvs.length > 0) {
0513: if (mvs.length > 4
0514: || (mvs.length > 1 && mvs[0].getTag() == Annotation.MEMBER_TAG_ENUM)
0515: || mvs[0].getTag() == Annotation.MEMBER_TAG_ARRAY
0516: || mvs[0].getTag() == Annotation.MEMBER_TAG_ANNOTATION) {
0517:
0518: multiLine = true;
0519: indent = indent + " ";
0520: }
0521: }
0522:
0523: if (multiLine || mvs.length != 1) {
0524: print("{");
0525: if (multiLine) {
0526: println();
0527: }
0528: }
0529:
0530: for (int j = 0; j < mvs.length; j++) {
0531: if (multiLine) {
0532: print(indent);
0533: }
0534: disassemble(indent, mvs[j]);
0535: if (j + 1 < mvs.length) {
0536: print(",");
0537: if (!multiLine) {
0538: print(" ");
0539: }
0540: }
0541: if (multiLine) {
0542: println();
0543: }
0544: }
0545:
0546: indent = originalIndent;
0547:
0548: if (multiLine || mvs.length != 1) {
0549: if (multiLine) {
0550: print(indent);
0551: }
0552: print("}");
0553: }
0554:
0555: break;
0556: }
0557: }
0558:
0559: private void disassemble(String indent, CodeAttr code) {
0560: CodeBuffer buffer = code.getCodeBuffer();
0561: mExceptionHandlers = buffer.getExceptionHandlers();
0562: print(indent);
0563: print("// max stack: ");
0564: println(String.valueOf(buffer.getMaxStackDepth()));
0565: print(indent);
0566: print("// max locals: ");
0567: println(String.valueOf(buffer.getMaxLocals()));
0568:
0569: mByteCodes = buffer.getByteCodes();
0570:
0571: gatherLabels();
0572:
0573: Location currentLoc = new Location() {
0574: public int getLocation() {
0575: return mAddress;
0576: }
0577:
0578: public int compareTo(Object obj) {
0579: if (this == obj) {
0580: return 0;
0581: }
0582: Location other = (Location) obj;
0583:
0584: int loca = getLocation();
0585: int locb = other.getLocation();
0586:
0587: if (loca < locb) {
0588: return -1;
0589: } else if (loca > locb) {
0590: return 1;
0591: } else {
0592: return 0;
0593: }
0594: }
0595: };
0596:
0597: int currentLine = -1;
0598:
0599: for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
0600: int nextLine = code.getLineNumber(currentLoc);
0601: if (nextLine != currentLine) {
0602: if ((currentLine = nextLine) >= 0) {
0603: println(indent, "// line " + currentLine);
0604: }
0605: }
0606:
0607: // Check if a label needs to be created and/or located.
0608: locateLabel(indent);
0609:
0610: byte opcode = mByteCodes[mAddress];
0611:
0612: String mnemonic;
0613: try {
0614: mnemonic = Opcode.getMnemonic(opcode);
0615: } catch (IllegalArgumentException e) {
0616: mnemonic = String.valueOf(opcode & 0xff);
0617: }
0618:
0619: print(indent, mnemonic);
0620:
0621: switch (opcode) {
0622:
0623: default:
0624: break;
0625:
0626: // Opcodes with no operands...
0627:
0628: case Opcode.NOP:
0629: case Opcode.BREAKPOINT:
0630: case Opcode.ACONST_NULL:
0631: case Opcode.ICONST_M1:
0632: case Opcode.ICONST_0:
0633: case Opcode.ICONST_1:
0634: case Opcode.ICONST_2:
0635: case Opcode.ICONST_3:
0636: case Opcode.ICONST_4:
0637: case Opcode.ICONST_5:
0638: case Opcode.LCONST_0:
0639: case Opcode.LCONST_1:
0640: case Opcode.FCONST_0:
0641: case Opcode.FCONST_1:
0642: case Opcode.FCONST_2:
0643: case Opcode.DCONST_0:
0644: case Opcode.DCONST_1:
0645: case Opcode.POP:
0646: case Opcode.POP2:
0647: case Opcode.DUP:
0648: case Opcode.DUP_X1:
0649: case Opcode.DUP_X2:
0650: case Opcode.DUP2:
0651: case Opcode.DUP2_X1:
0652: case Opcode.DUP2_X2:
0653: case Opcode.SWAP:
0654: case Opcode.IADD:
0655: case Opcode.LADD:
0656: case Opcode.FADD:
0657: case Opcode.DADD:
0658: case Opcode.ISUB:
0659: case Opcode.LSUB:
0660: case Opcode.FSUB:
0661: case Opcode.DSUB:
0662: case Opcode.IMUL:
0663: case Opcode.LMUL:
0664: case Opcode.FMUL:
0665: case Opcode.DMUL:
0666: case Opcode.IDIV:
0667: case Opcode.LDIV:
0668: case Opcode.FDIV:
0669: case Opcode.DDIV:
0670: case Opcode.IREM:
0671: case Opcode.LREM:
0672: case Opcode.FREM:
0673: case Opcode.DREM:
0674: case Opcode.INEG:
0675: case Opcode.LNEG:
0676: case Opcode.FNEG:
0677: case Opcode.DNEG:
0678: case Opcode.ISHL:
0679: case Opcode.LSHL:
0680: case Opcode.ISHR:
0681: case Opcode.LSHR:
0682: case Opcode.IUSHR:
0683: case Opcode.LUSHR:
0684: case Opcode.IAND:
0685: case Opcode.LAND:
0686: case Opcode.IOR:
0687: case Opcode.LOR:
0688: case Opcode.IXOR:
0689: case Opcode.LXOR:
0690: case Opcode.FCMPL:
0691: case Opcode.DCMPL:
0692: case Opcode.FCMPG:
0693: case Opcode.DCMPG:
0694: case Opcode.LCMP:
0695: case Opcode.I2L:
0696: case Opcode.I2F:
0697: case Opcode.I2D:
0698: case Opcode.L2I:
0699: case Opcode.L2F:
0700: case Opcode.L2D:
0701: case Opcode.F2I:
0702: case Opcode.F2L:
0703: case Opcode.F2D:
0704: case Opcode.D2I:
0705: case Opcode.D2L:
0706: case Opcode.D2F:
0707: case Opcode.I2B:
0708: case Opcode.I2C:
0709: case Opcode.I2S:
0710: case Opcode.IRETURN:
0711: case Opcode.LRETURN:
0712: case Opcode.FRETURN:
0713: case Opcode.DRETURN:
0714: case Opcode.ARETURN:
0715: case Opcode.RETURN:
0716: case Opcode.IALOAD:
0717: case Opcode.LALOAD:
0718: case Opcode.FALOAD:
0719: case Opcode.DALOAD:
0720: case Opcode.AALOAD:
0721: case Opcode.BALOAD:
0722: case Opcode.CALOAD:
0723: case Opcode.SALOAD:
0724: case Opcode.IASTORE:
0725: case Opcode.LASTORE:
0726: case Opcode.FASTORE:
0727: case Opcode.DASTORE:
0728: case Opcode.AASTORE:
0729: case Opcode.BASTORE:
0730: case Opcode.CASTORE:
0731: case Opcode.SASTORE:
0732: case Opcode.ARRAYLENGTH:
0733: case Opcode.ATHROW:
0734: case Opcode.MONITORENTER:
0735: case Opcode.MONITOREXIT:
0736: case Opcode.ILOAD_0:
0737: case Opcode.ISTORE_0:
0738: case Opcode.ILOAD_1:
0739: case Opcode.ISTORE_1:
0740: case Opcode.ILOAD_2:
0741: case Opcode.ISTORE_2:
0742: case Opcode.ILOAD_3:
0743: case Opcode.ISTORE_3:
0744: case Opcode.LLOAD_0:
0745: case Opcode.LSTORE_0:
0746: case Opcode.LLOAD_1:
0747: case Opcode.LSTORE_1:
0748: case Opcode.LLOAD_2:
0749: case Opcode.LSTORE_2:
0750: case Opcode.LLOAD_3:
0751: case Opcode.LSTORE_3:
0752: case Opcode.FLOAD_0:
0753: case Opcode.FSTORE_0:
0754: case Opcode.FLOAD_1:
0755: case Opcode.FSTORE_1:
0756: case Opcode.FLOAD_2:
0757: case Opcode.FSTORE_2:
0758: case Opcode.FLOAD_3:
0759: case Opcode.FSTORE_3:
0760: case Opcode.DLOAD_0:
0761: case Opcode.DSTORE_0:
0762: case Opcode.DLOAD_1:
0763: case Opcode.DSTORE_1:
0764: case Opcode.DLOAD_2:
0765: case Opcode.DSTORE_2:
0766: case Opcode.DLOAD_3:
0767: case Opcode.DSTORE_3:
0768: case Opcode.ALOAD_0:
0769: case Opcode.ASTORE_0:
0770: case Opcode.ALOAD_1:
0771: case Opcode.ASTORE_1:
0772: case Opcode.ALOAD_2:
0773: case Opcode.ASTORE_2:
0774: case Opcode.ALOAD_3:
0775: case Opcode.ASTORE_3:
0776: println();
0777: continue;
0778:
0779: // End opcodes with no operands.
0780: }
0781:
0782: // Space to separate operands.
0783: print(" ");
0784:
0785: int index;
0786: ConstantInfo constant;
0787:
0788: switch (opcode) {
0789: default:
0790: break;
0791:
0792: // Opcodes that load a constant from the constant pool...
0793:
0794: case Opcode.LDC:
0795: case Opcode.LDC_W:
0796: case Opcode.LDC2_W:
0797: switch (opcode) {
0798: case Opcode.LDC:
0799: index = readUnsignedByte();
0800: break;
0801: case Opcode.LDC_W:
0802: case Opcode.LDC2_W:
0803: index = readUnsignedShort();
0804: break;
0805: default:
0806: index = 0;
0807: break;
0808: }
0809:
0810: disassemble(getConstant(index), true);
0811: break;
0812:
0813: case Opcode.NEW:
0814: case Opcode.ANEWARRAY:
0815: case Opcode.CHECKCAST:
0816: case Opcode.INSTANCEOF:
0817: constant = getConstant(readUnsignedShort());
0818: if (constant instanceof ConstantClassInfo) {
0819: disassemble(constant);
0820: } else {
0821: print(constant);
0822: }
0823: break;
0824: case Opcode.MULTIANEWARRAY:
0825: constant = getConstant(readUnsignedShort());
0826: int dims = readUnsignedByte();
0827: if (constant instanceof ConstantClassInfo) {
0828: disassemble(constant);
0829: } else {
0830: print(constant);
0831: }
0832: print(" ");
0833: print(String.valueOf(dims));
0834: break;
0835:
0836: case Opcode.GETSTATIC:
0837: case Opcode.PUTSTATIC:
0838: case Opcode.GETFIELD:
0839: case Opcode.PUTFIELD:
0840: constant = getConstant(readUnsignedShort());
0841: if (constant instanceof ConstantFieldInfo) {
0842: ConstantFieldInfo field = (ConstantFieldInfo) constant;
0843: Descriptor type = field.getNameAndType().getType();
0844: if (type instanceof TypeDesc) {
0845: disassemble((TypeDesc) type);
0846: } else {
0847: print(type);
0848: }
0849: print(" ");
0850: print(field.getParentClass().getType()
0851: .getFullName());
0852: print(".");
0853: print(field.getNameAndType().getName());
0854: } else {
0855: print(constant);
0856: }
0857: break;
0858:
0859: case Opcode.INVOKEVIRTUAL:
0860: case Opcode.INVOKESPECIAL:
0861: case Opcode.INVOKESTATIC:
0862: case Opcode.INVOKEINTERFACE:
0863: constant = getConstant(readUnsignedShort());
0864:
0865: String className;
0866: ConstantNameAndTypeInfo nameAndType;
0867:
0868: if (opcode == Opcode.INVOKEINTERFACE) {
0869: // Read and ignore nargs and padding byte.
0870: readShort();
0871: if (!(constant instanceof ConstantInterfaceMethodInfo)) {
0872: print(constant);
0873: break;
0874: }
0875: ConstantInterfaceMethodInfo method = (ConstantInterfaceMethodInfo) constant;
0876: className = method.getParentClass().getType()
0877: .getFullName();
0878: nameAndType = method.getNameAndType();
0879: } else {
0880: if (!(constant instanceof ConstantMethodInfo)) {
0881: print(constant);
0882: break;
0883: }
0884: ConstantMethodInfo method = (ConstantMethodInfo) constant;
0885: className = method.getParentClass().getType()
0886: .getFullName();
0887: nameAndType = method.getNameAndType();
0888: }
0889:
0890: Descriptor type = nameAndType.getType();
0891: if (!(type instanceof MethodDesc)) {
0892: print(type);
0893: break;
0894: }
0895: disassemble(((MethodDesc) type).getReturnType());
0896: print(" ");
0897: print(className);
0898: print(".");
0899: print(nameAndType.getName());
0900:
0901: print("(");
0902: TypeDesc[] params = ((MethodDesc) type)
0903: .getParameterTypes();
0904: for (int i = 0; i < params.length; i++) {
0905: if (i > 0) {
0906: print(", ");
0907: }
0908: disassemble(params[i]);
0909: }
0910: print(")");
0911: break;
0912:
0913: // End opcodes that load a constant from the constant pool.
0914:
0915: // Opcodes that load or store local variables...
0916:
0917: case Opcode.ILOAD:
0918: case Opcode.ISTORE:
0919: case Opcode.LLOAD:
0920: case Opcode.LSTORE:
0921: case Opcode.FLOAD:
0922: case Opcode.FSTORE:
0923: case Opcode.DLOAD:
0924: case Opcode.DSTORE:
0925: case Opcode.ALOAD:
0926: case Opcode.ASTORE:
0927: case Opcode.RET:
0928: print(String.valueOf(readUnsignedByte()));
0929: break;
0930: case Opcode.IINC:
0931: print(String.valueOf(readUnsignedByte()));
0932: print(" ");
0933: int incValue = readByte();
0934: if (incValue >= 0) {
0935: print("+");
0936: }
0937: print(String.valueOf(incValue));
0938: break;
0939:
0940: // End opcodes that load or store local variables.
0941:
0942: // Opcodes that branch to another address.
0943: case Opcode.GOTO:
0944: case Opcode.JSR:
0945: case Opcode.IFNULL:
0946: case Opcode.IFNONNULL:
0947: case Opcode.IF_ACMPEQ:
0948: case Opcode.IF_ACMPNE:
0949: case Opcode.IFEQ:
0950: case Opcode.IFNE:
0951: case Opcode.IFLT:
0952: case Opcode.IFGE:
0953: case Opcode.IFGT:
0954: case Opcode.IFLE:
0955: case Opcode.IF_ICMPEQ:
0956: case Opcode.IF_ICMPNE:
0957: case Opcode.IF_ICMPLT:
0958: case Opcode.IF_ICMPGE:
0959: case Opcode.IF_ICMPGT:
0960: case Opcode.IF_ICMPLE:
0961: print(getLabel(mAddress + readShort()));
0962: break;
0963: case Opcode.GOTO_W:
0964: case Opcode.JSR_W:
0965: print(getLabel(mAddress + readInt()));
0966: break;
0967:
0968: // End opcodes that branch to another address.
0969:
0970: // Miscellaneous opcodes...
0971: case Opcode.BIPUSH:
0972: int value = readByte();
0973: print(String.valueOf(value));
0974: printCharLiteral(value);
0975: break;
0976: case Opcode.SIPUSH:
0977: value = readShort();
0978: print(String.valueOf(value));
0979: printCharLiteral(value);
0980: break;
0981:
0982: case Opcode.NEWARRAY:
0983: int atype = readByte();
0984: switch (atype) {
0985: case 4: // T_BOOLEAN
0986: print("boolean");
0987: break;
0988: case 5: // T_CHAR
0989: print("char");
0990: break;
0991: case 6: // T_FLOAT
0992: print("float");
0993: break;
0994: case 7: // T_DOUBLE
0995: print("double");
0996: break;
0997: case 8: // T_BYTE
0998: print("byte");
0999: break;
1000: case 9: // T_SHORT
1001: print("short");
1002: break;
1003: case 10: // T_INT
1004: print("int");
1005: break;
1006: case 11: // T_LONG
1007: print("long");
1008: break;
1009: default:
1010: print("T_" + atype);
1011: break;
1012: }
1013: break;
1014:
1015: case Opcode.TABLESWITCH:
1016: case Opcode.LOOKUPSWITCH:
1017: int opcodeAddress = mAddress;
1018: // Read padding until address is 32 bit word aligned.
1019: while (((mAddress + 1) & 3) != 0) {
1020: ++mAddress;
1021: }
1022: String defaultLocation = getLabel(opcodeAddress
1023: + readInt());
1024: int[] cases;
1025: String[] locations;
1026:
1027: if (opcode == Opcode.TABLESWITCH) {
1028: int lowValue = readInt();
1029: int highValue = readInt();
1030: int caseCount = highValue - lowValue + 1;
1031: print("// " + caseCount + " cases");
1032: try {
1033: cases = new int[caseCount];
1034: } catch (NegativeArraySizeException e) {
1035: break;
1036: }
1037: locations = new String[caseCount];
1038: for (int i = 0; i < caseCount; i++) {
1039: cases[i] = lowValue + i;
1040: locations[i] = getLabel(opcodeAddress
1041: + readInt());
1042: }
1043: } else {
1044: int caseCount = readInt();
1045: print("// " + caseCount + " cases");
1046: try {
1047: cases = new int[caseCount];
1048: } catch (NegativeArraySizeException e) {
1049: break;
1050: }
1051: locations = new String[caseCount];
1052: for (int i = 0; i < caseCount; i++) {
1053: cases[i] = readInt();
1054: locations[i] = getLabel(opcodeAddress
1055: + readInt());
1056: }
1057: }
1058:
1059: println();
1060:
1061: print(indent, " default: goto ");
1062: println(defaultLocation);
1063:
1064: String prefix = indent + " " + "case ";
1065: for (int i = 0; i < cases.length; i++) {
1066: print(prefix + cases[i]);
1067: print(": goto ");
1068: print(locations[i]);
1069: printCharLiteral(cases[i]);
1070: println();
1071: }
1072:
1073: break;
1074:
1075: case Opcode.WIDE:
1076: opcode = mByteCodes[++mAddress];
1077: print(Opcode.getMnemonic(opcode));
1078: print(" ");
1079:
1080: switch (opcode) {
1081:
1082: default:
1083: break;
1084:
1085: case Opcode.ILOAD:
1086: case Opcode.ISTORE:
1087: case Opcode.LLOAD:
1088: case Opcode.LSTORE:
1089: case Opcode.FLOAD:
1090: case Opcode.FSTORE:
1091: case Opcode.DLOAD:
1092: case Opcode.DSTORE:
1093: case Opcode.ALOAD:
1094: case Opcode.ASTORE:
1095: case Opcode.RET:
1096: print(String.valueOf(readUnsignedShort()));
1097: break;
1098: case Opcode.IINC:
1099: print(String.valueOf(readUnsignedShort()));
1100: print(" ");
1101: incValue = readShort();
1102: if (incValue >= 0) {
1103: print("+");
1104: }
1105: print(String.valueOf(incValue));
1106: break;
1107: }
1108:
1109: break;
1110: } // end huge switch
1111:
1112: println();
1113: } // end for loop
1114: }
1115:
1116: private void gatherLabels() {
1117: mLabels = new HashMap();
1118: mCatchLocations = new HashMap(mExceptionHandlers.length * 2 + 1);
1119:
1120: // Gather labels for any exception handlers.
1121: for (int i = mExceptionHandlers.length - 1; i >= 0; i--) {
1122: ExceptionHandler handler = mExceptionHandlers[i];
1123: createLabel(new Integer(handler.getStartLocation()
1124: .getLocation()));
1125: createLabel(new Integer(handler.getEndLocation()
1126: .getLocation()));
1127: Integer labelKey = new Integer(handler.getCatchLocation()
1128: .getLocation());
1129: createLabel(labelKey);
1130: List list = (List) mCatchLocations.get(labelKey);
1131: if (list == null) {
1132: list = new ArrayList(2);
1133: mCatchLocations.put(labelKey, list);
1134: }
1135: list.add(handler);
1136: }
1137:
1138: // Now gather labels that occur within byte code.
1139: for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
1140: byte opcode = mByteCodes[mAddress];
1141:
1142: switch (opcode) {
1143:
1144: default:
1145: break;
1146:
1147: // Opcodes that use labels.
1148:
1149: case Opcode.GOTO:
1150: case Opcode.JSR:
1151: case Opcode.IFNULL:
1152: case Opcode.IFNONNULL:
1153: case Opcode.IF_ACMPEQ:
1154: case Opcode.IF_ACMPNE:
1155: case Opcode.IFEQ:
1156: case Opcode.IFNE:
1157: case Opcode.IFLT:
1158: case Opcode.IFGE:
1159: case Opcode.IFGT:
1160: case Opcode.IFLE:
1161: case Opcode.IF_ICMPEQ:
1162: case Opcode.IF_ICMPNE:
1163: case Opcode.IF_ICMPLT:
1164: case Opcode.IF_ICMPGE:
1165: case Opcode.IF_ICMPGT:
1166: case Opcode.IF_ICMPLE:
1167: createLabel(new Integer(mAddress + readShort()));
1168: break;
1169:
1170: case Opcode.GOTO_W:
1171: case Opcode.JSR_W:
1172: createLabel(new Integer(mAddress + readInt()));
1173: break;
1174:
1175: case Opcode.TABLESWITCH:
1176: case Opcode.LOOKUPSWITCH:
1177: int opcodeAddress = mAddress;
1178: // Read padding until address is 32 bit word aligned.
1179: while (((mAddress + 1) & 3) != 0) {
1180: ++mAddress;
1181: }
1182:
1183: // Read the default location.
1184:
1185: createLabel(new Integer(opcodeAddress + readInt()));
1186:
1187: if (opcode == Opcode.TABLESWITCH) {
1188: int lowValue = readInt();
1189: int highValue = readInt();
1190: int caseCount = highValue - lowValue + 1;
1191:
1192: for (int i = 0; i < caseCount; i++) {
1193: // Read the branch location.
1194: createLabel(new Integer(opcodeAddress
1195: + readInt()));
1196: }
1197: } else {
1198: int caseCount = readInt();
1199:
1200: for (int i = 0; i < caseCount; i++) {
1201: // Skip the case value.
1202: mAddress += 4;
1203: // Read the branch location.
1204: createLabel(new Integer(opcodeAddress
1205: + readInt()));
1206: }
1207: }
1208: break;
1209:
1210: // All other operations are skipped. The amount to skip
1211: // depends on the operand size.
1212:
1213: // Opcodes with no operands...
1214:
1215: case Opcode.NOP:
1216: case Opcode.BREAKPOINT:
1217: case Opcode.ACONST_NULL:
1218: case Opcode.ICONST_M1:
1219: case Opcode.ICONST_0:
1220: case Opcode.ICONST_1:
1221: case Opcode.ICONST_2:
1222: case Opcode.ICONST_3:
1223: case Opcode.ICONST_4:
1224: case Opcode.ICONST_5:
1225: case Opcode.LCONST_0:
1226: case Opcode.LCONST_1:
1227: case Opcode.FCONST_0:
1228: case Opcode.FCONST_1:
1229: case Opcode.FCONST_2:
1230: case Opcode.DCONST_0:
1231: case Opcode.DCONST_1:
1232: case Opcode.POP:
1233: case Opcode.POP2:
1234: case Opcode.DUP:
1235: case Opcode.DUP_X1:
1236: case Opcode.DUP_X2:
1237: case Opcode.DUP2:
1238: case Opcode.DUP2_X1:
1239: case Opcode.DUP2_X2:
1240: case Opcode.SWAP:
1241: case Opcode.IADD:
1242: case Opcode.LADD:
1243: case Opcode.FADD:
1244: case Opcode.DADD:
1245: case Opcode.ISUB:
1246: case Opcode.LSUB:
1247: case Opcode.FSUB:
1248: case Opcode.DSUB:
1249: case Opcode.IMUL:
1250: case Opcode.LMUL:
1251: case Opcode.FMUL:
1252: case Opcode.DMUL:
1253: case Opcode.IDIV:
1254: case Opcode.LDIV:
1255: case Opcode.FDIV:
1256: case Opcode.DDIV:
1257: case Opcode.IREM:
1258: case Opcode.LREM:
1259: case Opcode.FREM:
1260: case Opcode.DREM:
1261: case Opcode.INEG:
1262: case Opcode.LNEG:
1263: case Opcode.FNEG:
1264: case Opcode.DNEG:
1265: case Opcode.ISHL:
1266: case Opcode.LSHL:
1267: case Opcode.ISHR:
1268: case Opcode.LSHR:
1269: case Opcode.IUSHR:
1270: case Opcode.LUSHR:
1271: case Opcode.IAND:
1272: case Opcode.LAND:
1273: case Opcode.IOR:
1274: case Opcode.LOR:
1275: case Opcode.IXOR:
1276: case Opcode.LXOR:
1277: case Opcode.FCMPL:
1278: case Opcode.DCMPL:
1279: case Opcode.FCMPG:
1280: case Opcode.DCMPG:
1281: case Opcode.LCMP:
1282: case Opcode.I2L:
1283: case Opcode.I2F:
1284: case Opcode.I2D:
1285: case Opcode.L2I:
1286: case Opcode.L2F:
1287: case Opcode.L2D:
1288: case Opcode.F2I:
1289: case Opcode.F2L:
1290: case Opcode.F2D:
1291: case Opcode.D2I:
1292: case Opcode.D2L:
1293: case Opcode.D2F:
1294: case Opcode.I2B:
1295: case Opcode.I2C:
1296: case Opcode.I2S:
1297: case Opcode.IRETURN:
1298: case Opcode.LRETURN:
1299: case Opcode.FRETURN:
1300: case Opcode.DRETURN:
1301: case Opcode.ARETURN:
1302: case Opcode.RETURN:
1303: case Opcode.IALOAD:
1304: case Opcode.LALOAD:
1305: case Opcode.FALOAD:
1306: case Opcode.DALOAD:
1307: case Opcode.AALOAD:
1308: case Opcode.BALOAD:
1309: case Opcode.CALOAD:
1310: case Opcode.SALOAD:
1311: case Opcode.IASTORE:
1312: case Opcode.LASTORE:
1313: case Opcode.FASTORE:
1314: case Opcode.DASTORE:
1315: case Opcode.AASTORE:
1316: case Opcode.BASTORE:
1317: case Opcode.CASTORE:
1318: case Opcode.SASTORE:
1319: case Opcode.ARRAYLENGTH:
1320: case Opcode.ATHROW:
1321: case Opcode.MONITORENTER:
1322: case Opcode.MONITOREXIT:
1323: case Opcode.ILOAD_0:
1324: case Opcode.ISTORE_0:
1325: case Opcode.ILOAD_1:
1326: case Opcode.ISTORE_1:
1327: case Opcode.ILOAD_2:
1328: case Opcode.ISTORE_2:
1329: case Opcode.ILOAD_3:
1330: case Opcode.ISTORE_3:
1331: case Opcode.LLOAD_0:
1332: case Opcode.LSTORE_0:
1333: case Opcode.LLOAD_1:
1334: case Opcode.LSTORE_1:
1335: case Opcode.LLOAD_2:
1336: case Opcode.LSTORE_2:
1337: case Opcode.LLOAD_3:
1338: case Opcode.LSTORE_3:
1339: case Opcode.FLOAD_0:
1340: case Opcode.FSTORE_0:
1341: case Opcode.FLOAD_1:
1342: case Opcode.FSTORE_1:
1343: case Opcode.FLOAD_2:
1344: case Opcode.FSTORE_2:
1345: case Opcode.FLOAD_3:
1346: case Opcode.FSTORE_3:
1347: case Opcode.DLOAD_0:
1348: case Opcode.DSTORE_0:
1349: case Opcode.DLOAD_1:
1350: case Opcode.DSTORE_1:
1351: case Opcode.DLOAD_2:
1352: case Opcode.DSTORE_2:
1353: case Opcode.DLOAD_3:
1354: case Opcode.DSTORE_3:
1355: case Opcode.ALOAD_0:
1356: case Opcode.ASTORE_0:
1357: case Opcode.ALOAD_1:
1358: case Opcode.ASTORE_1:
1359: case Opcode.ALOAD_2:
1360: case Opcode.ASTORE_2:
1361: case Opcode.ALOAD_3:
1362: case Opcode.ASTORE_3:
1363: break;
1364:
1365: // Opcodes with one operand byte...
1366:
1367: case Opcode.LDC:
1368: case Opcode.ILOAD:
1369: case Opcode.ISTORE:
1370: case Opcode.LLOAD:
1371: case Opcode.LSTORE:
1372: case Opcode.FLOAD:
1373: case Opcode.FSTORE:
1374: case Opcode.DLOAD:
1375: case Opcode.DSTORE:
1376: case Opcode.ALOAD:
1377: case Opcode.ASTORE:
1378: case Opcode.RET:
1379: case Opcode.IINC:
1380: case Opcode.BIPUSH:
1381: case Opcode.NEWARRAY:
1382: mAddress += 1;
1383: break;
1384:
1385: // Opcodes with two operand bytes...
1386:
1387: case Opcode.LDC_W:
1388: case Opcode.LDC2_W:
1389: case Opcode.NEW:
1390: case Opcode.ANEWARRAY:
1391: case Opcode.CHECKCAST:
1392: case Opcode.INSTANCEOF:
1393: case Opcode.GETSTATIC:
1394: case Opcode.PUTSTATIC:
1395: case Opcode.GETFIELD:
1396: case Opcode.PUTFIELD:
1397: case Opcode.INVOKEVIRTUAL:
1398: case Opcode.INVOKESPECIAL:
1399: case Opcode.INVOKESTATIC:
1400: case Opcode.SIPUSH:
1401: mAddress += 2;
1402: break;
1403:
1404: // Opcodes with three operand bytes...
1405:
1406: case Opcode.MULTIANEWARRAY:
1407: mAddress += 3;
1408: break;
1409:
1410: // Opcodes with four operand bytes...
1411:
1412: case Opcode.INVOKEINTERFACE:
1413: mAddress += 4;
1414: break;
1415:
1416: // Wide opcode has a variable sized operand.
1417:
1418: case Opcode.WIDE:
1419: opcode = mByteCodes[++mAddress];
1420: mAddress += 2;
1421: if (opcode == Opcode.IINC) {
1422: mAddress += 2;
1423: }
1424: break;
1425: } // end huge switch
1426: } // end for loop
1427:
1428: Integer[] keys = new Integer[mLabels.size()];
1429: mLabels.keySet().toArray(keys);
1430: Arrays.sort(keys);
1431: for (int i = 0; i < keys.length; i++) {
1432: mLabels.put(keys[i], "L" + (i + 1) + '_' + keys[i]);
1433: }
1434: }
1435:
1436: private void createLabel(Integer labelKey) {
1437: mLabels.put(labelKey, labelKey);
1438: }
1439:
1440: private ConstantInfo getConstant(int index) {
1441: try {
1442: return mCp.getConstant(index);
1443: } catch (IndexOutOfBoundsException e) {
1444: return null;
1445: }
1446: }
1447:
1448: private String getLabel(int address) {
1449: Object label = mLabels.get(new Integer(address));
1450: if (label == null || (!(label instanceof String))) {
1451: return "L?_" + address;
1452: } else {
1453: return (String) label;
1454: }
1455: }
1456:
1457: private void locateLabel(String indent) {
1458: Integer labelKey = new Integer(mAddress);
1459: Object labelValue = mLabels.get(labelKey);
1460:
1461: if (labelValue == null) {
1462: return;
1463: }
1464:
1465: int len = indent.length() - 4;
1466: if (len > 0) {
1467: print(indent.substring(0, len));
1468: }
1469:
1470: print(labelValue);
1471: println(":");
1472:
1473: List handlers = (List) mCatchLocations.get(labelKey);
1474:
1475: if (handlers != null) {
1476: for (int i = 0; i < handlers.size(); i++) {
1477: ExceptionHandler handler = (ExceptionHandler) handlers
1478: .get(i);
1479: print(indent, "try (");
1480: print(getLabel(handler.getStartLocation().getLocation()));
1481: print("..");
1482: print(getLabel(handler.getEndLocation().getLocation()));
1483: print(") catch (");
1484: if (handler.getCatchType() == null) {
1485: print("...");
1486: } else {
1487: disassemble(handler.getCatchType());
1488: }
1489: println(")");
1490: }
1491: }
1492: }
1493:
1494: private int readByte() {
1495: return mByteCodes[++mAddress];
1496: }
1497:
1498: private int readUnsignedByte() {
1499: return mByteCodes[++mAddress] & 0xff;
1500: }
1501:
1502: private int readShort() {
1503: return (mByteCodes[++mAddress] << 8)
1504: | (mByteCodes[++mAddress] & 0xff);
1505: }
1506:
1507: private int readUnsignedShort() {
1508: return ((mByteCodes[++mAddress] & 0xff) << 8)
1509: | ((mByteCodes[++mAddress] & 0xff) << 0);
1510: }
1511:
1512: private int readInt() {
1513: return (mByteCodes[++mAddress] << 24)
1514: | ((mByteCodes[++mAddress] & 0xff) << 16)
1515: | ((mByteCodes[++mAddress] & 0xff) << 8)
1516: | ((mByteCodes[++mAddress] & 0xff) << 0);
1517: }
1518:
1519: private void print(Object text) {
1520: mOut.print(text);
1521: }
1522:
1523: private void println(Object text) {
1524: mOut.println(text);
1525: }
1526:
1527: private void print(String indent, Object text) {
1528: mOut.print(indent);
1529: mOut.print(text);
1530: }
1531:
1532: private void println(String indent, Object text) {
1533: mOut.print(indent);
1534: mOut.println(text);
1535: }
1536:
1537: private void println() {
1538: mOut.println();
1539: }
1540:
1541: private void printCharLiteral(int value) {
1542: if (value >= 0 && value <= 65535) {
1543: int type = Character.getType((char) value);
1544: switch (type) {
1545: case Character.UPPERCASE_LETTER:
1546: case Character.LOWERCASE_LETTER:
1547: case Character.TITLECASE_LETTER:
1548: case Character.MODIFIER_LETTER:
1549: case Character.OTHER_LETTER:
1550: case Character.NON_SPACING_MARK:
1551: case Character.ENCLOSING_MARK:
1552: case Character.COMBINING_SPACING_MARK:
1553: case Character.DECIMAL_DIGIT_NUMBER:
1554: case Character.LETTER_NUMBER:
1555: case Character.OTHER_NUMBER:
1556: case Character.DASH_PUNCTUATION:
1557: case Character.START_PUNCTUATION:
1558: case Character.END_PUNCTUATION:
1559: case Character.CONNECTOR_PUNCTUATION:
1560: case Character.OTHER_PUNCTUATION:
1561: case Character.MATH_SYMBOL:
1562: case Character.CURRENCY_SYMBOL:
1563: case Character.MODIFIER_SYMBOL:
1564: case Character.OTHER_SYMBOL:
1565: print(" // '");
1566: print(String.valueOf((char) value));
1567: print("'");
1568: }
1569: }
1570: }
1571:
1572: private void sortMembers(Object[] members) {
1573: Arrays.sort(members, new MemberComparator());
1574: }
1575:
1576: /**
1577: * Orders members in this canonical sequence:
1578: *
1579: * - statics
1580: * - fields
1581: * - initializer
1582: * - methods
1583: * - non-statics
1584: * - fields
1585: * - constructors
1586: * - methods
1587: *
1588: * Fields, constructors, and methods are sorted:
1589: * - public
1590: * - final
1591: * - non-final
1592: * - transient
1593: * - protected
1594: * - final
1595: * - non-final
1596: * - transient
1597: * - package
1598: * - final
1599: * - non-final
1600: * - transient
1601: * - private
1602: * - final
1603: * - non-final
1604: * - transient
1605: */
1606: private class MemberComparator implements Comparator {
1607: public int compare(Object a, Object b) {
1608: Modifiers aFlags, bFlags;
1609:
1610: if (a instanceof FieldInfo) {
1611: aFlags = ((FieldInfo) a).getModifiers();
1612: } else {
1613: aFlags = ((MethodInfo) a).getModifiers();
1614: }
1615:
1616: if (b instanceof FieldInfo) {
1617: bFlags = ((FieldInfo) b).getModifiers();
1618: } else {
1619: bFlags = ((MethodInfo) b).getModifiers();
1620: }
1621:
1622: // static before non-static
1623: if (aFlags.isStatic()) {
1624: if (!bFlags.isStatic()) {
1625: return -1;
1626: }
1627: } else {
1628: if (bFlags.isStatic()) {
1629: return 1;
1630: }
1631: }
1632:
1633: // fields before methods
1634: if (a instanceof FieldInfo) {
1635: if (b instanceof MethodInfo) {
1636: return -1;
1637: }
1638: } else {
1639: if (!(b instanceof MethodInfo)) {
1640: return 1;
1641: }
1642:
1643: // initializers and constructors before regular methods
1644: String aName = ((MethodInfo) a).getName();
1645: String bName = ((MethodInfo) b).getName();
1646:
1647: if ("<init>".equals(aName) || "<clinit>".equals(aName)) {
1648: if ("<init>".equals(bName)
1649: || "<clinit>".equals(bName)) {
1650: } else {
1651: return -1;
1652: }
1653: } else {
1654: if ("<init>".equals(bName)
1655: || "<clinit>".equals(bName)) {
1656: return 1;
1657: }
1658: }
1659: }
1660:
1661: // public, protected, package, private order
1662: int aValue, bValue;
1663: if (aFlags.isPublic()) {
1664: aValue = 0;
1665: } else if (aFlags.isProtected()) {
1666: aValue = 4;
1667: } else if (!aFlags.isPrivate()) {
1668: aValue = 8;
1669: } else {
1670: aValue = 12;
1671: }
1672:
1673: if (bFlags.isPublic()) {
1674: bValue = 0;
1675: } else if (bFlags.isProtected()) {
1676: bValue = 4;
1677: } else if (!bFlags.isPrivate()) {
1678: bValue = 8;
1679: } else {
1680: bValue = 12;
1681: }
1682:
1683: // final before non-final
1684: aValue += (aFlags.isFinal()) ? 0 : 2;
1685: bValue += (bFlags.isFinal()) ? 0 : 2;
1686:
1687: // transient after non-transient
1688: aValue += (aFlags.isTransient()) ? 1 : 0;
1689: bValue += (bFlags.isTransient()) ? 1 : 0;
1690:
1691: if (aValue < bValue) {
1692: return -1;
1693: } else if (aValue > bValue) {
1694: return 1;
1695: }
1696:
1697: return 0;
1698: }
1699: }
1700: }
|