KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > cojen > classfile > AssemblyStylePrinter


1 /*
2  * Copyright 2004 Brian S O'Neill
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.cojen.classfile;
18
19 import java.io.PrintWriter JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Arrays JavaDoc;
22 import java.util.Comparator JavaDoc;
23 import java.util.Date JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28
29 import org.cojen.classfile.attribute.Annotation;
30 import org.cojen.classfile.attribute.CodeAttr;
31 import org.cojen.classfile.attribute.SignatureAttr;
32 import org.cojen.classfile.constant.ConstantClassInfo;
33 import org.cojen.classfile.constant.ConstantDoubleInfo;
34 import org.cojen.classfile.constant.ConstantFieldInfo;
35 import org.cojen.classfile.constant.ConstantFloatInfo;
36 import org.cojen.classfile.constant.ConstantIntegerInfo;
37 import org.cojen.classfile.constant.ConstantInterfaceMethodInfo;
38 import org.cojen.classfile.constant.ConstantLongInfo;
39 import org.cojen.classfile.constant.ConstantMethodInfo;
40 import org.cojen.classfile.constant.ConstantNameAndTypeInfo;
41 import org.cojen.classfile.constant.ConstantStringInfo;
42 import org.cojen.classfile.constant.ConstantUTFInfo;
43
44 /**
45  * Disassembles a ClassFile into a pseudo Java assembly language format.
46  *
47  * @author Brian S O'Neill
48  */

49 class AssemblyStylePrinter implements DisassemblyTool.Printer {
50     private ClassFile mClassFile;
51     private ConstantPool mCp;
52     private PrintWriter JavaDoc mOut;
53
54     private byte[] mByteCodes;
55     // Current address being decompiled.
56
private int mAddress;
57
58     // Maps Integer address keys to String labels.
59
private Map JavaDoc mLabels;
60
61     private ExceptionHandler[] mExceptionHandlers;
62
63     // Maps Integer catch locations to Lists of ExceptionHandler objects.
64
private Map JavaDoc mCatchLocations;
65
66     public AssemblyStylePrinter() {
67     }
68
69     public void disassemble(ClassFile cf, PrintWriter JavaDoc out) {
70         disassemble(cf, out, "");
71     }
72
73     private void disassemble(ClassFile cf, PrintWriter JavaDoc out, String JavaDoc indent) {
74         mClassFile = cf;
75         mCp = cf.getConstantPool();
76         mOut = out;
77
78         if (indent.length() == 0 || mClassFile.getSourceFile() != null ||
79             mClassFile.isDeprecated() || mClassFile.isSynthetic()) {
80
81             println(indent, "/**");
82
83             boolean addBreak = false;
84
85             if (indent.length() == 0) {
86                 print(indent, " * Disassembled on ");
87                 print(new Date JavaDoc());
88                 println(".");
89                 addBreak = true;
90             }
91
92             if (indent.length() == 0 && mClassFile.getTarget() != null) {
93                 if (addBreak) {
94                     println(indent, " * ");
95                     addBreak = false;
96                 }
97                 print(indent, " * @target ");
98                 println(CodeAssemblerPrinter.escape(mClassFile.getTarget()));
99             }
100
101             if (mClassFile.getSourceFile() != null) {
102                 if (addBreak) {
103                     println(indent, " * ");
104                     addBreak = false;
105                 }
106                 print(indent, " * @source ");
107                 println(CodeAssemblerPrinter.escape(mClassFile.getSourceFile()));
108             }
109
110             if (mClassFile.isInnerClass()) {
111                 if (addBreak) {
112                     println(indent, " * ");
113                     addBreak = false;
114                 }
115                 if (mClassFile.getInnerClassName() == null) {
116                     println(indent, " * @anonymous");
117                 } else {
118                     print(indent, " * @name ");
119                     println(CodeAssemblerPrinter.escape(mClassFile.getInnerClassName()));
120                 }
121             }
122
123             if (mClassFile.isDeprecated()) {
124                 if (addBreak) {
125                     println(indent, " * ");
126                     addBreak = false;
127                 }
128                 println(indent, " * @deprecated");
129             }
130
131             if (mClassFile.isSynthetic()) {
132                 if (addBreak) {
133                     println(indent, " * ");
134                     addBreak = false;
135                 }
136                 println(indent, " * @synthetic");
137             }
138
139             // TODO: Just testing
140
SignatureAttr sig = mClassFile.getSignatureAttr();
141             if (sig != null) {
142                 if (addBreak) {
143                     println(indent, " * ");
144                     addBreak = false;
145                 }
146                 println(indent, " * @signature " + sig.getSignature().getValue());
147             }
148
149             println(indent, " */");
150         }
151
152         disassemble(indent, mClassFile.getRuntimeVisibleAnnotations());
153         disassemble(indent, mClassFile.getRuntimeInvisibleAnnotations());
154
155         print(indent);
156
157         disassemble(mClassFile.getModifiers());
158         boolean isInterface = mClassFile.getModifiers().isInterface();
159         if (!isInterface) {
160             print("class ");
161         }
162         print(mClassFile.getClassName());
163
164         if (mClassFile.getSuperClassName() != null) {
165             print(" extends ");
166             print(mClassFile.getSuperClassName());
167         }
168
169         String JavaDoc innerIndent = indent + " ";
170
171         String JavaDoc[] interfaces = mClassFile.getInterfaces();
172         if (interfaces.length == 0) {
173             println(" {");
174         } else {
175             println();
176             for (int i=0; i<interfaces.length; i++) {
177                 if (i == 0) {
178                     print(innerIndent, "implements ");
179                 } else {
180                     println(",");
181                     print(innerIndent, " ");
182                 }
183                 print(interfaces[i]);
184             }
185             println();
186             println(indent, "{");
187         }
188
189         FieldInfo[] fields = mClassFile.getFields();
190         MethodInfo[] methods = mClassFile.getMethods();
191         MethodInfo[] ctors = mClassFile.getConstructors();
192         MethodInfo init = mClassFile.getInitializer();
193
194         Object JavaDoc[] members = new Object JavaDoc[fields.length + methods.length +
195                                      ctors.length + ((init == null) ? 0 : 1)];
196
197         int m = 0;
198
199         for (int i=0; i<fields.length; i++) {
200             members[m++] = fields[i];
201         }
202
203         for (int i=0; i<methods.length; i++) {
204             members[m++] = methods[i];
205         }
206
207         for (int i=0; i<ctors.length; i++) {
208             members[m++] = ctors[i];
209         }
210
211         if (init != null) {
212             members[m++] = init;
213         }
214
215         sortMembers(members);
216
217         for (int i=0; i<members.length; i++) {
218             if (i > 0) {
219                 println();
220             }
221             if (members[i] instanceof FieldInfo) {
222                 disassemble(innerIndent, (FieldInfo)members[i]);
223             } else {
224                 disassemble(innerIndent, (MethodInfo)members[i]);
225             }
226         }
227
228         mByteCodes = null;
229         mLabels = null;
230         mExceptionHandlers = null;
231         mCatchLocations = null;
232
233         ClassFile[] innerClasses = mClassFile.getInnerClasses();
234
235         for (int i=0; i<innerClasses.length; i++) {
236             if (i > 0 || members.length > 0) {
237                 println();
238             }
239             AssemblyStylePrinter printer = new AssemblyStylePrinter();
240             printer.disassemble(innerClasses[i], mOut, innerIndent);
241         }
242
243         println(indent, "}");
244
245         mOut.flush();
246         mOut = null;
247     }
248
249     private void disassemble(String JavaDoc indent, FieldInfo field) {
250         SignatureAttr sig = field.getSignatureAttr();
251         if (field.isDeprecated() || field.isSynthetic() || sig != null) {
252             println(indent, "/**");
253             if (field.isDeprecated()) {
254                 println(indent, " * @deprecated");
255             }
256             if (field.isSynthetic()) {
257                 println(indent, " * @synthetic");
258             }
259             if (sig != null) {
260                 println(indent, " * @signature " + sig.getSignature().getValue());
261             }
262             println(indent, " */");
263         }
264
265         disassemble(indent, field.getRuntimeVisibleAnnotations());
266         disassemble(indent, field.getRuntimeInvisibleAnnotations());
267
268         print(indent);
269         disassemble(field.getModifiers());
270         disassemble(field.getType());
271         print(" ");
272         print(field.getName());
273         ConstantInfo constant = field.getConstantValue();
274         if (constant != null) {
275             print(" = ");
276             disassemble(constant);
277         }
278         println(";");
279     }
280
281     private void disassemble(String JavaDoc indent, MethodInfo method) {
282         SignatureAttr sig = method.getSignatureAttr();
283         if (method.isDeprecated() || method.isSynthetic() || sig != null) {
284             println(indent, "/**");
285             if (method.isDeprecated()) {
286                 println(indent, " * @deprecated");
287             }
288             if (method.isSynthetic()) {
289                 println(indent, " * @synthetic");
290             }
291             if (sig != null) {
292                 println(indent, " * @signature " + sig.getSignature().getValue());
293             }
294             println(indent, " */");
295         }
296
297         disassemble(indent, method.getRuntimeVisibleAnnotations());
298         disassemble(indent, method.getRuntimeInvisibleAnnotations());
299
300         print(indent);
301
302         MethodDesc md = method.getMethodDescriptor();
303
304         if ("<clinit>".equals(method.getName()) &&
305             md.getReturnType() == TypeDesc.VOID &&
306             md.getParameterCount() == 0 &&
307             (method.getModifiers().isStatic()) &&
308             (!method.getModifiers().isAbstract()) &&
309             method.getExceptions().length == 0) {
310
311             // Static initializer.
312
print("static");
313         } else {
314             Modifiers modifiers = method.getModifiers();
315             boolean varargs = modifiers.isVarArgs();
316             if (varargs) {
317                 // Don't display the modifier.
318
modifiers = modifiers.toVarArgs(false);
319             }
320             disassemble(modifiers);
321             print(md.toMethodSignature(method.getName(), varargs));
322         }
323
324         CodeAttr code = method.getCodeAttr();
325
326         TypeDesc[] exceptions = method.getExceptions();
327         if (exceptions.length == 0) {
328             if (code == null) {
329                 println(";");
330             } else {
331                 println(" {");
332             }
333         } else {
334             println();
335             for (int i=0; i<exceptions.length; i++) {
336                 if (i == 0) {
337                     print(indent + " ", "throws ");
338                 } else {
339                     println(",");
340                     print(indent + " ", " ");
341                 }
342                 print(exceptions[i].getFullName());
343             }
344             if (code == null) {
345                 println(";");
346             } else {
347                 println();
348                 println(indent, "{");
349             }
350         }
351
352         if (code != null) {
353             disassemble(indent + " ", code);
354             println(indent, "}");
355         }
356     }
357
358     private void disassemble(Modifiers modifiers) {
359         print(modifiers);
360         if (modifiers.getBitmask() != 0) {
361             print(" ");
362         }
363     }
364
365     private void disassemble(ConstantInfo constant) {
366         disassemble(constant, false);
367     }
368
369     private void disassemble(ConstantInfo constant, boolean showClassLiteral) {
370         if (constant instanceof ConstantStringInfo) {
371             print("\"");
372             String JavaDoc value = ((ConstantStringInfo)constant).getValue();
373             print(CodeAssemblerPrinter.escape(value));
374             print("\"");
375         } else if (constant instanceof ConstantIntegerInfo) {
376             print(String.valueOf(((ConstantIntegerInfo)constant).getValue()));
377         } else if (constant instanceof ConstantLongInfo) {
378             print(String.valueOf(((ConstantLongInfo)constant).getValue()));
379             print("L");
380         } else if (constant instanceof ConstantFloatInfo) {
381             float value = ((ConstantFloatInfo)constant).getValue();
382             if (value != value) {
383                 print("0.0f/0.0f");
384             } else if (value == Float.NEGATIVE_INFINITY) {
385                 print("-1.0f/0.0f");
386             } else if (value == Float.POSITIVE_INFINITY) {
387                 print("1.0f/0.0f");
388             } else {
389                 print(String.valueOf(value));
390                 print("f");
391             }
392         } else if (constant instanceof ConstantDoubleInfo) {
393             double value = ((ConstantDoubleInfo)constant).getValue();
394             if (value != value) {
395                 print("0.0d/0.0d");
396             } else if (value == Float.NEGATIVE_INFINITY) {
397                 print("-1.0d/0.0d");
398             } else if (value == Float.POSITIVE_INFINITY) {
399                 print("1.0d/0.0d");
400             } else {
401                 print(String.valueOf(value));
402                 print("d");
403             }
404         } else if (constant instanceof ConstantClassInfo) {
405             ConstantClassInfo cci = (ConstantClassInfo)constant;
406             disassemble(cci.getType());
407             if (showClassLiteral) {
408                 print(".class");
409             }
410         } else if (constant instanceof ConstantUTFInfo) {
411             print("\"");
412             String JavaDoc value = ((ConstantUTFInfo)constant).getValue();
413             print(CodeAssemblerPrinter.escape(value));
414             print("\"");
415         } else {
416             print(constant);
417         }
418     }
419
420     private void disassemble(TypeDesc type) {
421         print(type.getFullName());
422     }
423
424     private void disassemble(String JavaDoc indent, Annotation[] annotations) {
425         for (int i=0; i<annotations.length; i++) {
426             print(indent);
427             disassemble(indent, annotations[i]);
428             println();
429         }
430     }
431
432     private void disassemble(String JavaDoc indent, Annotation ann) {
433         print("@");
434         print(ann.getType().getFullName());
435         Map JavaDoc mvMap = ann.getMemberValues();
436         if (mvMap.size() == 0) {
437             return;
438         }
439         print("(");
440         Iterator JavaDoc it = mvMap.entrySet().iterator();
441         int ordinal = 0;
442         while (it.hasNext()) {
443             if (ordinal++ > 0) {
444                 print(", ");
445             }
446             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)it.next();
447             String JavaDoc name = (String JavaDoc)entry.getKey();
448             if (!"value".equals(name)) {
449                 print(name);
450                 print("=");
451             }
452             disassemble(indent, (Annotation.MemberValue)entry.getValue());
453         }
454         print(")");
455     }
456
457     private void disassemble(String JavaDoc indent, Annotation.MemberValue mv) {
458         Object JavaDoc value = mv.getValue();
459         switch (mv.getTag()) {
460         default:
461             print("?");
462             break;
463         case Annotation.MEMBER_TAG_BOOLEAN:
464             ConstantIntegerInfo ci = (ConstantIntegerInfo)value;
465             print(ci.getValue() == 0 ? "false" : "true");
466             break;
467         case Annotation.MEMBER_TAG_BYTE:
468         case Annotation.MEMBER_TAG_SHORT:
469         case Annotation.MEMBER_TAG_INT:
470         case Annotation.MEMBER_TAG_LONG:
471         case Annotation.MEMBER_TAG_FLOAT:
472         case Annotation.MEMBER_TAG_DOUBLE:
473         case Annotation.MEMBER_TAG_STRING:
474         case Annotation.MEMBER_TAG_CLASS:
475             disassemble((ConstantInfo)value, true);
476             break;
477         case Annotation.MEMBER_TAG_CHAR: {
478             print("'");
479             char c = (char) ((ConstantIntegerInfo)value).getValue();
480             print(CodeAssemblerPrinter.escape(String.valueOf(c), true));
481             print("'");
482             break;
483         }
484         case Annotation.MEMBER_TAG_ENUM:
485             Annotation.EnumConstValue ecv = (Annotation.EnumConstValue)value;
486             print(TypeDesc.forDescriptor(ecv.getTypeName().getValue()).getFullName());
487             print(".");
488             print(ecv.getConstName().getValue());
489             break;
490         case Annotation.MEMBER_TAG_ANNOTATION:
491             disassemble(indent, (Annotation)value);
492             break;
493         case Annotation.MEMBER_TAG_ARRAY:
494             Annotation.MemberValue[] mvs = (Annotation.MemberValue[])value;
495
496             String JavaDoc originalIndent = indent;
497             boolean multiLine = false;
498             if (mvs.length > 0) {
499                 if (mvs.length > 4 ||
500                     (mvs.length > 1 && mvs[0].getTag() == Annotation.MEMBER_TAG_ENUM) ||
501                     mvs[0].getTag() == Annotation.MEMBER_TAG_ARRAY ||
502                     mvs[0].getTag() == Annotation.MEMBER_TAG_ANNOTATION) {
503
504                     multiLine = true;
505                     indent = indent + " ";
506                 }
507             }
508
509             if (multiLine || mvs.length != 1) {
510                 print("{");
511                 if (multiLine) {
512                     println();
513                 }
514             }
515             
516             for (int j=0; j<mvs.length; j++) {
517                 if (multiLine) {
518                     print(indent);
519                 }
520                 disassemble(indent, mvs[j]);
521                 if (j + 1 < mvs.length) {
522                     print(",");
523                     if (!multiLine) {
524                         print(" ");
525                     }
526                 }
527                 if (multiLine) {
528                     println();
529                 }
530             }
531             
532             indent = originalIndent;
533
534             if (multiLine || mvs.length != 1) {
535                 if (multiLine) {
536                     print(indent);
537                 }
538                 print("}");
539             }
540             
541             break;
542         }
543     }
544
545     private void disassemble(String JavaDoc indent, CodeAttr code) {
546         CodeBuffer buffer = code.getCodeBuffer();
547         mExceptionHandlers = buffer.getExceptionHandlers();
548         print(indent);
549         print("// max stack: ");
550         println(String.valueOf(buffer.getMaxStackDepth()));
551         print(indent);
552         print("// max locals: ");
553         println(String.valueOf(buffer.getMaxLocals()));
554
555         mByteCodes = buffer.getByteCodes();
556
557         gatherLabels();
558
559         Location currentLoc = new Location() {
560             public int getLocation() {
561                 return mAddress;
562             }
563
564             public int compareTo(Object JavaDoc obj) {
565                 if (this == obj) {
566                     return 0;
567                 }
568                 Location other = (Location)obj;
569                 
570                 int loca = getLocation();
571                 int locb = other.getLocation();
572                 
573                 if (loca < locb) {
574                     return -1;
575                 } else if (loca > locb) {
576                     return 1;
577                 } else {
578                     return 0;
579                 }
580             }
581         };
582
583         int currentLine = -1;
584
585         for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
586             int nextLine = code.getLineNumber(currentLoc);
587             if (nextLine != currentLine) {
588                 if ((currentLine = nextLine) >= 0) {
589                     println(indent, "// line " + currentLine);
590                 }
591             }
592
593             // Check if a label needs to be created and/or located.
594
locateLabel(indent);
595
596             byte opcode = mByteCodes[mAddress];
597
598             String JavaDoc mnemonic;
599             try {
600                 mnemonic = Opcode.getMnemonic(opcode);
601             } catch (IllegalArgumentException JavaDoc e) {
602                 mnemonic = String.valueOf(opcode & 0xff);
603             }
604
605             print(indent, mnemonic);
606             
607             switch (opcode) {
608                 
609             default:
610                 break;
611
612                 // Opcodes with no operands...
613

614             case Opcode.NOP:
615             case Opcode.BREAKPOINT:
616             case Opcode.ACONST_NULL:
617             case Opcode.ICONST_M1:
618             case Opcode.ICONST_0:
619             case Opcode.ICONST_1:
620             case Opcode.ICONST_2:
621             case Opcode.ICONST_3:
622             case Opcode.ICONST_4:
623             case Opcode.ICONST_5:
624             case Opcode.LCONST_0:
625             case Opcode.LCONST_1:
626             case Opcode.FCONST_0:
627             case Opcode.FCONST_1:
628             case Opcode.FCONST_2:
629             case Opcode.DCONST_0:
630             case Opcode.DCONST_1:
631             case Opcode.POP:
632             case Opcode.POP2:
633             case Opcode.DUP:
634             case Opcode.DUP_X1:
635             case Opcode.DUP_X2:
636             case Opcode.DUP2:
637             case Opcode.DUP2_X1:
638             case Opcode.DUP2_X2:
639             case Opcode.SWAP:
640             case Opcode.IADD: case Opcode.LADD:
641             case Opcode.FADD: case Opcode.DADD:
642             case Opcode.ISUB: case Opcode.LSUB:
643             case Opcode.FSUB: case Opcode.DSUB:
644             case Opcode.IMUL: case Opcode.LMUL:
645             case Opcode.FMUL: case Opcode.DMUL:
646             case Opcode.IDIV: case Opcode.LDIV:
647             case Opcode.FDIV: case Opcode.DDIV:
648             case Opcode.IREM: case Opcode.LREM:
649             case Opcode.FREM: case Opcode.DREM:
650             case Opcode.INEG: case Opcode.LNEG:
651             case Opcode.FNEG: case Opcode.DNEG:
652             case Opcode.ISHL: case Opcode.LSHL:
653             case Opcode.ISHR: case Opcode.LSHR:
654             case Opcode.IUSHR: case Opcode.LUSHR:
655             case Opcode.IAND: case Opcode.LAND:
656             case Opcode.IOR: case Opcode.LOR:
657             case Opcode.IXOR: case Opcode.LXOR:
658             case Opcode.FCMPL: case Opcode.DCMPL:
659             case Opcode.FCMPG: case Opcode.DCMPG:
660             case Opcode.LCMP:
661             case Opcode.I2L:
662             case Opcode.I2F:
663             case Opcode.I2D:
664             case Opcode.L2I:
665             case Opcode.L2F:
666             case Opcode.L2D:
667             case Opcode.F2I:
668             case Opcode.F2L:
669             case Opcode.F2D:
670             case Opcode.D2I:
671             case Opcode.D2L:
672             case Opcode.D2F:
673             case Opcode.I2B:
674             case Opcode.I2C:
675             case Opcode.I2S:
676             case Opcode.IRETURN:
677             case Opcode.LRETURN:
678             case Opcode.FRETURN:
679             case Opcode.DRETURN:
680             case Opcode.ARETURN:
681             case Opcode.RETURN:
682             case Opcode.IALOAD:
683             case Opcode.LALOAD:
684             case Opcode.FALOAD:
685             case Opcode.DALOAD:
686             case Opcode.AALOAD:
687             case Opcode.BALOAD:
688             case Opcode.CALOAD:
689             case Opcode.SALOAD:
690             case Opcode.IASTORE:
691             case Opcode.LASTORE:
692             case Opcode.FASTORE:
693             case Opcode.DASTORE:
694             case Opcode.AASTORE:
695             case Opcode.BASTORE:
696             case Opcode.CASTORE:
697             case Opcode.SASTORE:
698             case Opcode.ARRAYLENGTH:
699             case Opcode.ATHROW:
700             case Opcode.MONITORENTER:
701             case Opcode.MONITOREXIT:
702             case Opcode.ILOAD_0: case Opcode.ISTORE_0:
703             case Opcode.ILOAD_1: case Opcode.ISTORE_1:
704             case Opcode.ILOAD_2: case Opcode.ISTORE_2:
705             case Opcode.ILOAD_3: case Opcode.ISTORE_3:
706             case Opcode.LLOAD_0: case Opcode.LSTORE_0:
707             case Opcode.LLOAD_1: case Opcode.LSTORE_1:
708             case Opcode.LLOAD_2: case Opcode.LSTORE_2:
709             case Opcode.LLOAD_3: case Opcode.LSTORE_3:
710             case Opcode.FLOAD_0: case Opcode.FSTORE_0:
711             case Opcode.FLOAD_1: case Opcode.FSTORE_1:
712             case Opcode.FLOAD_2: case Opcode.FSTORE_2:
713             case Opcode.FLOAD_3: case Opcode.FSTORE_3:
714             case Opcode.DLOAD_0: case Opcode.DSTORE_0:
715             case Opcode.DLOAD_1: case Opcode.DSTORE_1:
716             case Opcode.DLOAD_2: case Opcode.DSTORE_2:
717             case Opcode.DLOAD_3: case Opcode.DSTORE_3:
718             case Opcode.ALOAD_0: case Opcode.ASTORE_0:
719             case Opcode.ALOAD_1: case Opcode.ASTORE_1:
720             case Opcode.ALOAD_2: case Opcode.ASTORE_2:
721             case Opcode.ALOAD_3: case Opcode.ASTORE_3:
722                 println();
723                 continue;
724
725                 // End opcodes with no operands.
726
}
727
728             // Space to separate operands.
729
print(" ");
730
731             int index;
732             ConstantInfo constant;
733
734             switch (opcode) {
735             default:
736                 break;
737
738                 // Opcodes that load a constant from the constant pool...
739

740             case Opcode.LDC:
741             case Opcode.LDC_W:
742             case Opcode.LDC2_W:
743                 switch (opcode) {
744                 case Opcode.LDC:
745                     index = readUnsignedByte();
746                     break;
747                 case Opcode.LDC_W:
748                 case Opcode.LDC2_W:
749                     index = readUnsignedShort();
750                     break;
751                 default:
752                     index = 0;
753                     break;
754                 }
755
756                 disassemble(getConstant(index), true);
757                 break;
758
759             case Opcode.NEW:
760             case Opcode.ANEWARRAY:
761             case Opcode.CHECKCAST:
762             case Opcode.INSTANCEOF:
763                 constant = getConstant(readUnsignedShort());
764                 if (constant instanceof ConstantClassInfo) {
765                     disassemble(constant);
766                 } else {
767                     print(constant);
768                 }
769                 break;
770             case Opcode.MULTIANEWARRAY:
771                 constant = getConstant(readUnsignedShort());
772                 int dims = readUnsignedByte();
773                 if (constant instanceof ConstantClassInfo) {
774                     disassemble(constant);
775                 } else {
776                     print(constant);
777                 }
778                 print(" ");
779                 print(String.valueOf(dims));
780                 break;
781
782             case Opcode.GETSTATIC:
783             case Opcode.PUTSTATIC:
784             case Opcode.GETFIELD:
785             case Opcode.PUTFIELD:
786                 constant = getConstant(readUnsignedShort());
787                 if (constant instanceof ConstantFieldInfo) {
788                     ConstantFieldInfo field = (ConstantFieldInfo)constant;
789                     Descriptor type = field.getNameAndType().getType();
790                     if (type instanceof TypeDesc) {
791                         disassemble((TypeDesc)type);
792                     } else {
793                         print(type);
794                     }
795                     print(" ");
796                     print(field.getParentClass().getType().getFullName());
797                     print(".");
798                     print(field.getNameAndType().getName());
799                 } else {
800                     print(constant);
801                 }
802                 break;
803
804             case Opcode.INVOKEVIRTUAL:
805             case Opcode.INVOKESPECIAL:
806             case Opcode.INVOKESTATIC:
807             case Opcode.INVOKEINTERFACE:
808                 constant = getConstant(readUnsignedShort());
809
810                 String JavaDoc className;
811                 ConstantNameAndTypeInfo nameAndType;
812
813                 if (opcode == Opcode.INVOKEINTERFACE) {
814                     // Read and ignore nargs and padding byte.
815
readShort();
816                     if (!(constant instanceof ConstantInterfaceMethodInfo)) {
817                         print(constant);
818                         break;
819                     }
820                     ConstantInterfaceMethodInfo method =
821                         (ConstantInterfaceMethodInfo)constant;
822                     className =
823                         method.getParentClass().getType().getFullName();
824                     nameAndType = method.getNameAndType();
825                 } else {
826                     if (!(constant instanceof ConstantMethodInfo)) {
827                         print(constant);
828                         break;
829                     }
830                     ConstantMethodInfo method = (ConstantMethodInfo)constant;
831                     className =
832                         method.getParentClass().getType().getFullName();
833                     nameAndType = method.getNameAndType();
834                 }
835
836                 Descriptor type = nameAndType.getType();
837                 if (!(type instanceof MethodDesc)) {
838                     print(type);
839                     break;
840                 }
841                 disassemble(((MethodDesc)type).getReturnType());
842                 print(" ");
843                 print(className);
844                 print(".");
845                 print(nameAndType.getName());
846
847                 print("(");
848                 TypeDesc[] params = ((MethodDesc)type).getParameterTypes();
849                 for (int i=0; i<params.length; i++) {
850                     if (i > 0) {
851                         print(", ");
852                     }
853                     disassemble(params[i]);
854                 }
855                 print(")");
856                 break;
857
858                 // End opcodes that load a constant from the constant pool.
859

860                 // Opcodes that load or store local variables...
861

862             case Opcode.ILOAD: case Opcode.ISTORE:
863             case Opcode.LLOAD: case Opcode.LSTORE:
864             case Opcode.FLOAD: case Opcode.FSTORE:
865             case Opcode.DLOAD: case Opcode.DSTORE:
866             case Opcode.ALOAD: case Opcode.ASTORE:
867             case Opcode.RET:
868                 print(String.valueOf(readUnsignedByte()));
869                 break;
870             case Opcode.IINC:
871                 print(String.valueOf(readUnsignedByte()));
872                 print(" ");
873                 int incValue = readByte();
874                 if (incValue >= 0) {
875                     print("+");
876                 }
877                 print(String.valueOf(incValue));
878                 break;
879
880                 // End opcodes that load or store local variables.
881

882                 // Opcodes that branch to another address.
883
case Opcode.GOTO:
884             case Opcode.JSR:
885             case Opcode.IFNULL:
886             case Opcode.IFNONNULL:
887             case Opcode.IF_ACMPEQ:
888             case Opcode.IF_ACMPNE:
889             case Opcode.IFEQ:
890             case Opcode.IFNE:
891             case Opcode.IFLT:
892             case Opcode.IFGE:
893             case Opcode.IFGT:
894             case Opcode.IFLE:
895             case Opcode.IF_ICMPEQ:
896             case Opcode.IF_ICMPNE:
897             case Opcode.IF_ICMPLT:
898             case Opcode.IF_ICMPGE:
899             case Opcode.IF_ICMPGT:
900             case Opcode.IF_ICMPLE:
901                 print(getLabel(mAddress + readShort()));
902                 break;
903             case Opcode.GOTO_W:
904             case Opcode.JSR_W:
905                 print(getLabel(mAddress + readInt()));
906                 break;
907
908                 // End opcodes that branch to another address.
909

910                 // Miscellaneous opcodes...
911
case Opcode.BIPUSH:
912                 int value = readByte();
913                 print(String.valueOf(value));
914                 printCharLiteral(value);
915                 break;
916             case Opcode.SIPUSH:
917                 value = readShort();
918                 print(String.valueOf(value));
919                 printCharLiteral(value);
920                 break;
921
922             case Opcode.NEWARRAY:
923                 int atype = readByte();
924                 switch (atype) {
925                 case 4: // T_BOOLEAN
926
print("boolean");
927                     break;
928                 case 5: // T_CHAR
929
print("char");
930                     break;
931                 case 6: // T_FLOAT
932
print("float");
933                     break;
934                 case 7: // T_DOUBLE
935
print("double");
936                     break;
937                 case 8: // T_BYTE
938
print("byte");
939                     break;
940                 case 9: // T_SHORT
941
print("short");
942                     break;
943                 case 10: // T_INT
944
print("int");
945                     break;
946                 case 11: // T_LONG
947
print("long");
948                     break;
949                 default:
950                     print("T_" + atype);
951                     break;
952                 }
953                 break;
954
955             case Opcode.TABLESWITCH:
956             case Opcode.LOOKUPSWITCH:
957                 int opcodeAddress = mAddress;
958                 // Read padding until address is 32 bit word aligned.
959
while (((mAddress + 1) & 3) != 0) {
960                     ++mAddress;
961                 }
962                 String JavaDoc defaultLocation = getLabel(opcodeAddress + readInt());
963                 int[] cases;
964                 String JavaDoc[] locations;
965                 
966                 if (opcode == Opcode.TABLESWITCH) {
967                     int lowValue = readInt();
968                     int highValue = readInt();
969                     int caseCount = highValue - lowValue + 1;
970                     print("// " + caseCount + " cases");
971                     try {
972                         cases = new int[caseCount];
973                     } catch (NegativeArraySizeException JavaDoc e) {
974                         break;
975                     }
976                     locations = new String JavaDoc[caseCount];
977                     for (int i=0; i<caseCount; i++) {
978                         cases[i] = lowValue + i;
979                         locations[i] = getLabel(opcodeAddress + readInt());
980                     }
981                 } else {
982                     int caseCount = readInt();
983                     print("// " + caseCount + " cases");
984                     try {
985                         cases = new int[caseCount];
986                     } catch (NegativeArraySizeException JavaDoc e) {
987                         break;
988                     }
989                     locations = new String JavaDoc[caseCount];
990                     for (int i=0; i<caseCount; i++) {
991                         cases[i] = readInt();
992                         locations[i] = getLabel(opcodeAddress + readInt());
993                     }
994                 }
995
996                 println();
997
998                 print(indent, " default: goto ");
999                 println(defaultLocation);
1000
1001                String JavaDoc prefix = indent + " " + "case ";
1002                for (int i=0; i<cases.length; i++) {
1003                    print(prefix + cases[i]);
1004                    print(": goto ");
1005                    print(locations[i]);
1006                    printCharLiteral(cases[i]);
1007                    println();
1008                }
1009
1010                break;
1011
1012            case Opcode.WIDE:
1013                opcode = mByteCodes[++mAddress];
1014                print(Opcode.getMnemonic(opcode));
1015                print(" ");
1016
1017                switch (opcode) {
1018
1019                default:
1020                    break;
1021
1022                case Opcode.ILOAD: case Opcode.ISTORE:
1023                case Opcode.LLOAD: case Opcode.LSTORE:
1024                case Opcode.FLOAD: case Opcode.FSTORE:
1025                case Opcode.DLOAD: case Opcode.DSTORE:
1026                case Opcode.ALOAD: case Opcode.ASTORE:
1027                case Opcode.RET:
1028                    print(String.valueOf(readUnsignedShort()));
1029                    break;
1030                case Opcode.IINC:
1031                    print(String.valueOf(readUnsignedShort()));
1032                    print(" ");
1033                    incValue = readShort();
1034                    if (incValue >= 0) {
1035                        print("+");
1036                    }
1037                    print(String.valueOf(incValue));
1038                    break;
1039                }
1040
1041                break;
1042            } // end huge switch
1043

1044            println();
1045        } // end for loop
1046
}
1047
1048    private void gatherLabels() {
1049        mLabels = new HashMap JavaDoc();
1050        mCatchLocations = new HashMap JavaDoc(mExceptionHandlers.length * 2 + 1);
1051
1052        // Gather labels for any exception handlers.
1053
for (int i = mExceptionHandlers.length - 1; i >= 0; i--) {
1054            ExceptionHandler handler = mExceptionHandlers[i];
1055            createLabel(new Integer JavaDoc(handler.getStartLocation().getLocation()));
1056            createLabel(new Integer JavaDoc(handler.getEndLocation().getLocation()));
1057            Integer JavaDoc labelKey =
1058                new Integer JavaDoc(handler.getCatchLocation().getLocation());
1059            createLabel(labelKey);
1060            List JavaDoc list = (List JavaDoc)mCatchLocations.get(labelKey);
1061            if (list == null) {
1062                list = new ArrayList JavaDoc(2);
1063                mCatchLocations.put(labelKey, list);
1064            }
1065            list.add(handler);
1066        }
1067
1068        // Now gather labels that occur within byte code.
1069
for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
1070            byte opcode = mByteCodes[mAddress];
1071
1072            switch (opcode) {
1073
1074            default:
1075                break;
1076
1077                // Opcodes that use labels.
1078

1079            case Opcode.GOTO:
1080            case Opcode.JSR:
1081            case Opcode.IFNULL:
1082            case Opcode.IFNONNULL:
1083            case Opcode.IF_ACMPEQ:
1084            case Opcode.IF_ACMPNE:
1085            case Opcode.IFEQ:
1086            case Opcode.IFNE:
1087            case Opcode.IFLT:
1088            case Opcode.IFGE:
1089            case Opcode.IFGT:
1090            case Opcode.IFLE:
1091            case Opcode.IF_ICMPEQ:
1092            case Opcode.IF_ICMPNE:
1093            case Opcode.IF_ICMPLT:
1094            case Opcode.IF_ICMPGE:
1095            case Opcode.IF_ICMPGT:
1096            case Opcode.IF_ICMPLE:
1097                createLabel(new Integer JavaDoc(mAddress + readShort()));
1098                break;
1099
1100            case Opcode.GOTO_W:
1101            case Opcode.JSR_W:
1102                createLabel(new Integer JavaDoc(mAddress + readInt()));
1103                break;
1104
1105            case Opcode.TABLESWITCH:
1106            case Opcode.LOOKUPSWITCH:
1107                int opcodeAddress = mAddress;
1108                // Read padding until address is 32 bit word aligned.
1109
while (((mAddress + 1) & 3) != 0) {
1110                    ++mAddress;
1111                }
1112                
1113                // Read the default location.
1114

1115
1116                createLabel(new Integer JavaDoc(opcodeAddress + readInt()));
1117                
1118                if (opcode == Opcode.TABLESWITCH) {
1119                    int lowValue = readInt();
1120                    int highValue = readInt();
1121                    int caseCount = highValue - lowValue + 1;
1122
1123                    for (int i=0; i<caseCount; i++) {
1124                        // Read the branch location.
1125
createLabel(new Integer JavaDoc(opcodeAddress + readInt()));
1126                    }
1127                } else {
1128                    int caseCount = readInt();
1129
1130                    for (int i=0; i<caseCount; i++) {
1131                        // Skip the case value.
1132
mAddress += 4;
1133                        // Read the branch location.
1134
createLabel(new Integer JavaDoc(opcodeAddress + readInt()));
1135                    }
1136                }
1137                break;
1138
1139                // All other operations are skipped. The amount to skip
1140
// depends on the operand size.
1141

1142                // Opcodes with no operands...
1143

1144            case Opcode.NOP:
1145            case Opcode.BREAKPOINT:
1146            case Opcode.ACONST_NULL:
1147            case Opcode.ICONST_M1:
1148            case Opcode.ICONST_0:
1149            case Opcode.ICONST_1:
1150            case Opcode.ICONST_2:
1151            case Opcode.ICONST_3:
1152            case Opcode.ICONST_4:
1153            case Opcode.ICONST_5:
1154            case Opcode.LCONST_0:
1155            case Opcode.LCONST_1:
1156            case Opcode.FCONST_0:
1157            case Opcode.FCONST_1:
1158            case Opcode.FCONST_2:
1159            case Opcode.DCONST_0:
1160            case Opcode.DCONST_1:
1161            case Opcode.POP:
1162            case Opcode.POP2:
1163            case Opcode.DUP:
1164            case Opcode.DUP_X1:
1165            case Opcode.DUP_X2:
1166            case Opcode.DUP2:
1167            case Opcode.DUP2_X1:
1168            case Opcode.DUP2_X2:
1169            case Opcode.SWAP:
1170            case Opcode.IADD: case Opcode.LADD:
1171            case Opcode.FADD: case Opcode.DADD:
1172            case Opcode.ISUB: case Opcode.LSUB:
1173            case Opcode.FSUB: case Opcode.DSUB:
1174            case Opcode.IMUL: case Opcode.LMUL:
1175            case Opcode.FMUL: case Opcode.DMUL:
1176            case Opcode.IDIV: case Opcode.LDIV:
1177            case Opcode.FDIV: case Opcode.DDIV:
1178            case Opcode.IREM: case Opcode.LREM:
1179            case Opcode.FREM: case Opcode.DREM:
1180            case Opcode.INEG: case Opcode.LNEG:
1181            case Opcode.FNEG: case Opcode.DNEG:
1182            case Opcode.ISHL: case Opcode.LSHL:
1183            case Opcode.ISHR: case Opcode.LSHR:
1184            case Opcode.IUSHR: case Opcode.LUSHR:
1185            case Opcode.IAND: case Opcode.LAND:
1186            case Opcode.IOR: case Opcode.LOR:
1187            case Opcode.IXOR: case Opcode.LXOR:
1188            case Opcode.FCMPL: case Opcode.DCMPL:
1189            case Opcode.FCMPG: case Opcode.DCMPG:
1190            case Opcode.LCMP:
1191            case Opcode.I2L:
1192            case Opcode.I2F:
1193            case Opcode.I2D:
1194            case Opcode.L2I:
1195            case Opcode.L2F:
1196            case Opcode.L2D:
1197            case Opcode.F2I:
1198            case Opcode.F2L:
1199            case Opcode.F2D:
1200            case Opcode.D2I:
1201            case Opcode.D2L:
1202            case Opcode.D2F:
1203            case Opcode.I2B:
1204            case Opcode.I2C:
1205            case Opcode.I2S:
1206            case Opcode.IRETURN:
1207            case Opcode.LRETURN:
1208            case Opcode.FRETURN:
1209            case Opcode.DRETURN:
1210            case Opcode.ARETURN:
1211            case Opcode.RETURN:
1212            case Opcode.IALOAD:
1213            case Opcode.LALOAD:
1214            case Opcode.FALOAD:
1215            case Opcode.DALOAD:
1216            case Opcode.AALOAD:
1217            case Opcode.BALOAD:
1218            case Opcode.CALOAD:
1219            case Opcode.SALOAD:
1220            case Opcode.IASTORE:
1221            case Opcode.LASTORE:
1222            case Opcode.FASTORE:
1223            case Opcode.DASTORE:
1224            case Opcode.AASTORE:
1225            case Opcode.BASTORE:
1226            case Opcode.CASTORE:
1227            case Opcode.SASTORE:
1228            case Opcode.ARRAYLENGTH:
1229            case Opcode.ATHROW:
1230            case Opcode.MONITORENTER:
1231            case Opcode.MONITOREXIT:
1232            case Opcode.ILOAD_0: case Opcode.ISTORE_0:
1233            case Opcode.ILOAD_1: case Opcode.ISTORE_1:
1234            case Opcode.ILOAD_2: case Opcode.ISTORE_2:
1235            case Opcode.ILOAD_3: case Opcode.ISTORE_3:
1236            case Opcode.LLOAD_0: case Opcode.LSTORE_0:
1237            case Opcode.LLOAD_1: case Opcode.LSTORE_1:
1238            case Opcode.LLOAD_2: case Opcode.LSTORE_2:
1239            case Opcode.LLOAD_3: case Opcode.LSTORE_3:
1240            case Opcode.FLOAD_0: case Opcode.FSTORE_0:
1241            case Opcode.FLOAD_1: case Opcode.FSTORE_1:
1242            case Opcode.FLOAD_2: case Opcode.FSTORE_2:
1243            case Opcode.FLOAD_3: case Opcode.FSTORE_3:
1244            case Opcode.DLOAD_0: case Opcode.DSTORE_0:
1245            case Opcode.DLOAD_1: case Opcode.DSTORE_1:
1246            case Opcode.DLOAD_2: case Opcode.DSTORE_2:
1247            case Opcode.DLOAD_3: case Opcode.DSTORE_3:
1248            case Opcode.ALOAD_0: case Opcode.ASTORE_0:
1249            case Opcode.ALOAD_1: case Opcode.ASTORE_1:
1250            case Opcode.ALOAD_2: case Opcode.ASTORE_2:
1251            case Opcode.ALOAD_3: case Opcode.ASTORE_3:
1252                break;
1253
1254                // Opcodes with one operand byte...
1255

1256            case Opcode.LDC:
1257            case Opcode.ILOAD: case Opcode.ISTORE:
1258            case Opcode.LLOAD: case Opcode.LSTORE:
1259            case Opcode.FLOAD: case Opcode.FSTORE:
1260            case Opcode.DLOAD: case Opcode.DSTORE:
1261            case Opcode.ALOAD: case Opcode.ASTORE:
1262            case Opcode.RET:
1263            case Opcode.IINC:
1264            case Opcode.BIPUSH:
1265            case Opcode.NEWARRAY:
1266                mAddress += 1;
1267                break;
1268
1269                // Opcodes with two operand bytes...
1270

1271            case Opcode.LDC_W:
1272            case Opcode.LDC2_W:
1273            case Opcode.NEW:
1274            case Opcode.ANEWARRAY:
1275            case Opcode.CHECKCAST:
1276            case Opcode.INSTANCEOF:
1277            case Opcode.GETSTATIC:
1278            case Opcode.PUTSTATIC:
1279            case Opcode.GETFIELD:
1280            case Opcode.PUTFIELD:
1281            case Opcode.INVOKEVIRTUAL:
1282            case Opcode.INVOKESPECIAL:
1283            case Opcode.INVOKESTATIC:
1284            case Opcode.SIPUSH:
1285                mAddress += 2;
1286                break;
1287
1288                // Opcodes with three operand bytes...
1289

1290            case Opcode.MULTIANEWARRAY:
1291                mAddress += 3;
1292                break;
1293
1294                // Opcodes with four operand bytes...
1295

1296            case Opcode.INVOKEINTERFACE:
1297                mAddress += 4;
1298                break;
1299
1300                // Wide opcode has a variable sized operand.
1301

1302            case Opcode.WIDE:
1303                opcode = mByteCodes[++mAddress];
1304                mAddress += 2;
1305                if (opcode == Opcode.IINC) {
1306                    mAddress += 2;
1307                }
1308                break;
1309            } // end huge switch
1310
} // end for loop
1311

1312        Integer JavaDoc[] keys = new Integer JavaDoc[mLabels.size()];
1313        mLabels.keySet().toArray(keys);
1314        Arrays.sort(keys);
1315        for (int i=0; i<keys.length; i++) {
1316            mLabels.put(keys[i], "L" + (i + 1) + '_' + keys[i]);
1317        }
1318    }
1319
1320    private void createLabel(Integer JavaDoc labelKey) {
1321        mLabels.put(labelKey, labelKey);
1322    }
1323
1324    private ConstantInfo getConstant(int index) {
1325        try {
1326            return mCp.getConstant(index);
1327        } catch (IndexOutOfBoundsException JavaDoc e) {
1328            return null;
1329        }
1330    }
1331
1332    private String JavaDoc getLabel(int address) {
1333        Object JavaDoc label = mLabels.get(new Integer JavaDoc(address));
1334        if (label == null || (!(label instanceof String JavaDoc))) {
1335            return "L?_" + address;
1336        } else {
1337            return (String JavaDoc)label;
1338        }
1339    }
1340
1341    private void locateLabel(String JavaDoc indent) {
1342        Integer JavaDoc labelKey = new Integer JavaDoc(mAddress);
1343        Object JavaDoc labelValue = mLabels.get(labelKey);
1344
1345        if (labelValue == null) {
1346            return;
1347        }
1348
1349        int len = indent.length() - 4;
1350        if (len > 0) {
1351            print(indent.substring(0, len));
1352        }
1353
1354        print(labelValue);
1355        println(":");
1356
1357        List JavaDoc handlers = (List JavaDoc)mCatchLocations.get(labelKey);
1358
1359        if (handlers != null) {
1360            for (int i=0; i<handlers.size(); i++) {
1361                ExceptionHandler handler = (ExceptionHandler)handlers.get(i);
1362                print(indent, "try (");
1363                print(getLabel(handler.getStartLocation().getLocation()));
1364                print("..");
1365                print(getLabel(handler.getEndLocation().getLocation()));
1366                print(") catch (");
1367                if (handler.getCatchType() == null) {
1368                    print("...");
1369                } else {
1370                    disassemble(handler.getCatchType());
1371                }
1372                println(")");
1373            }
1374        }
1375    }
1376
1377    private int readByte() {
1378        return mByteCodes[++mAddress];
1379    }
1380
1381    private int readUnsignedByte() {
1382        return mByteCodes[++mAddress] & 0xff;
1383    }
1384
1385    private int readShort() {
1386        return (mByteCodes[++mAddress] << 8) | (mByteCodes[++mAddress] & 0xff);
1387    }
1388
1389    private int readUnsignedShort() {
1390        return
1391            ((mByteCodes[++mAddress] & 0xff) << 8) |
1392            ((mByteCodes[++mAddress] & 0xff) << 0);
1393    }
1394
1395    private int readInt() {
1396        return
1397            (mByteCodes[++mAddress] << 24) |
1398            ((mByteCodes[++mAddress] & 0xff) << 16) |
1399            ((mByteCodes[++mAddress] & 0xff) << 8) |
1400            ((mByteCodes[++mAddress] & 0xff) << 0);
1401    }
1402
1403    private void print(Object JavaDoc text) {
1404        mOut.print(text);
1405    }
1406
1407    private void println(Object JavaDoc text) {
1408        mOut.println(text);
1409    }
1410
1411    private void print(String JavaDoc indent, Object JavaDoc text) {
1412        mOut.print(indent);
1413        mOut.print(text);
1414    }
1415
1416    private void println(String JavaDoc indent, Object JavaDoc text) {
1417        mOut.print(indent);
1418        mOut.println(text);
1419    }
1420
1421    private void println() {
1422        mOut.println();
1423    }
1424
1425    private void printCharLiteral(int value) {
1426        if (value >= 0 && value <= 65535) {
1427            int type = Character.getType((char)value);
1428            switch (type) {
1429            case Character.UPPERCASE_LETTER:
1430            case Character.LOWERCASE_LETTER:
1431            case Character.TITLECASE_LETTER:
1432            case Character.MODIFIER_LETTER:
1433            case Character.OTHER_LETTER:
1434            case Character.NON_SPACING_MARK:
1435            case Character.ENCLOSING_MARK:
1436            case Character.COMBINING_SPACING_MARK:
1437            case Character.DECIMAL_DIGIT_NUMBER:
1438            case Character.LETTER_NUMBER:
1439            case Character.OTHER_NUMBER:
1440            case Character.DASH_PUNCTUATION:
1441            case Character.START_PUNCTUATION:
1442            case Character.END_PUNCTUATION:
1443            case Character.CONNECTOR_PUNCTUATION:
1444            case Character.OTHER_PUNCTUATION:
1445            case Character.MATH_SYMBOL:
1446            case Character.CURRENCY_SYMBOL:
1447            case Character.MODIFIER_SYMBOL:
1448            case Character.OTHER_SYMBOL:
1449                print(" // '");
1450                print(String.valueOf((char)value));
1451                print("'");
1452            }
1453        }
1454    }
1455
1456    private void sortMembers(Object JavaDoc[] members) {
1457        Arrays.sort(members, new MemberComparator());
1458    }
1459
1460    /**
1461     * Orders members in this canonical sequence:
1462     *
1463     * - statics
1464     * - fields
1465     * - initializer
1466     * - methods
1467     * - non-statics
1468     * - fields
1469     * - constructors
1470     * - methods
1471     *
1472     * Fields, constructors, and methods are sorted:
1473     * - public
1474     * - final
1475     * - non-final
1476     * - transient
1477     * - protected
1478     * - final
1479     * - non-final
1480     * - transient
1481     * - package
1482     * - final
1483     * - non-final
1484     * - transient
1485     * - private
1486     * - final
1487     * - non-final
1488     * - transient
1489     */

1490    private class MemberComparator implements Comparator JavaDoc {
1491        public int compare(Object JavaDoc a, Object JavaDoc b) {
1492            Modifiers aFlags, bFlags;
1493
1494            if (a instanceof FieldInfo) {
1495                aFlags = ((FieldInfo)a).getModifiers();
1496            } else {
1497                aFlags = ((MethodInfo)a).getModifiers();
1498            }
1499
1500            if (b instanceof FieldInfo) {
1501                bFlags = ((FieldInfo)b).getModifiers();
1502            } else {
1503                bFlags = ((MethodInfo)b).getModifiers();
1504            }
1505
1506            // static before non-static
1507
if (aFlags.isStatic()) {
1508                if (!bFlags.isStatic()) {
1509                    return -1;
1510                }
1511            } else {
1512                if (bFlags.isStatic()) {
1513                    return 1;
1514                }
1515            }
1516
1517            // fields before methods
1518
if (a instanceof FieldInfo) {
1519                if (b instanceof MethodInfo) {
1520                    return -1;
1521                }
1522            } else {
1523                if (!(b instanceof MethodInfo)) {
1524                    return 1;
1525                }
1526
1527                // initializers and constructors before regular methods
1528
String JavaDoc aName = ((MethodInfo)a).getName();
1529                String JavaDoc bName = ((MethodInfo)b).getName();
1530                
1531                if ("<init>".equals(aName) || "<clinit>".equals(aName)) {
1532                    if ("<init>".equals(bName) || "<clinit>".equals(bName)) {
1533                    } else {
1534                        return -1;
1535                    }
1536                } else {
1537                    if ("<init>".equals(bName) || "<clinit>".equals(bName)) {
1538                        return 1;
1539                    }
1540                }
1541            }
1542
1543            // public, protected, package, private order
1544
int aValue, bValue;
1545            if (aFlags.isPublic()) {
1546                aValue = 0;
1547            } else if (aFlags.isProtected()) {
1548                aValue = 4;
1549            } else if (!aFlags.isPrivate()) {
1550                aValue = 8;
1551            } else {
1552                aValue = 12;
1553            }
1554
1555            if (bFlags.isPublic()) {
1556                bValue = 0;
1557            } else if (bFlags.isProtected()) {
1558                bValue = 4;
1559            } else if (!bFlags.isPrivate()) {
1560                bValue = 8;
1561            } else {
1562                bValue = 12;
1563            }
1564
1565            // final before non-final
1566
aValue += (aFlags.isFinal()) ? 0 : 2;
1567            bValue += (bFlags.isFinal()) ? 0 : 2;
1568
1569            // transient after non-transient
1570
aValue += (aFlags.isTransient()) ? 1 : 0;
1571            bValue += (bFlags.isTransient()) ? 1 : 0;
1572
1573            if (aValue < bValue) {
1574                return -1;
1575            } else if (aValue > bValue) {
1576                return 1;
1577            }
1578
1579            return 0;
1580        }
1581    }
1582}
1583
Popular Tags