comparison agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children ba764ed4b6f2
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
1 /*
2 * Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
24
25 package sun.jvm.hotspot.ui.classbrowser;
26
27 import java.io.*;
28 import java.util.*;
29 import sun.jvm.hotspot.asm.*;
30 import sun.jvm.hotspot.asm.sparc.*;
31 import sun.jvm.hotspot.asm.x86.*;
32 import sun.jvm.hotspot.asm.ia64.*;
33 import sun.jvm.hotspot.code.*;
34 import sun.jvm.hotspot.compiler.*;
35 import sun.jvm.hotspot.debugger.*;
36 import sun.jvm.hotspot.interpreter.*;
37 import sun.jvm.hotspot.memory.*;
38 import sun.jvm.hotspot.oops.*;
39 import sun.jvm.hotspot.runtime.*;
40 import sun.jvm.hotspot.tools.jcore.*;
41 import sun.jvm.hotspot.types.*;
42 import sun.jvm.hotspot.utilities.*;
43
44 public class HTMLGenerator implements /* imports */ ClassConstants {
45 static class Formatter {
46 boolean html;
47 StringBuffer buf = new StringBuffer();
48
49 Formatter(boolean h) {
50 html = h;
51 }
52
53 void append(String s) {
54 buf.append(s);
55 }
56
57 void append(int s) {
58 buf.append(s);
59 }
60
61 void append(char s) {
62 buf.append(s);
63 }
64
65 void append(StringBuffer s) {
66 buf.append(s);
67 }
68
69 void append(Formatter s) {
70 buf.append(s);
71 }
72
73 StringBuffer getBuffer() {
74 return buf;
75 }
76
77 public String toString() {
78 return buf.toString();
79 }
80
81 void wrap(String tag, String text) {
82 wrap(tag, tag, text);
83 }
84 void wrap(String before, String after, String text) {
85 beginTag(before);
86 append(text);
87 endTag(after);
88 }
89
90 // header tags
91 void h1(String s) { nl(); wrap("h1", s); nl(); }
92 void h2(String s) { nl(); wrap("h2", s); nl(); }
93 void h3(String s) { nl(); wrap("h3", s); nl(); }
94 void h4(String s) { nl(); wrap("h4", s); nl(); }
95
96 // list tags
97 void beginList() { beginTag("ul"); nl(); }
98 void li(String s) { wrap("li", s); nl(); }
99 void endList() { endTag("ul"); nl(); }
100
101 // table tags
102 void beginTable(int border) {
103 beginTag("table border='" + border + "'");
104 }
105 void cell(String s) { wrap("td", s); }
106 void headerCell(String s) { wrap("th", s); }
107 void endTable() { endTag("table"); }
108
109 void link(String href, String text) {
110 wrap("a href='" + href + "'", "a", text);
111 }
112 void beginTag(String s) {
113 if (html) { append("<"); append(s); append(">"); }
114 }
115 void endTag(String s) {
116 if (html) {
117 append("</"); append(s); append(">");
118 } else {
119 if (s.equals("table") || s.equals("tr")) {
120 nl();
121 }
122 if (s.equals("td") || s.equals("th")) {
123 append(" ");
124 }
125 }
126 }
127 void bold(String s) {
128 wrap("b", s);
129 }
130
131 void nl() {
132 if (!html) buf.append("\n");
133 }
134
135 void br() {
136 if (html) append("<br>");
137 else append("\n");
138 }
139 void genEmptyHTML() {
140 if (html) append("<html></html>");
141 }
142
143 void genHTMLPrologue() {
144 if (html) append("<html><body>");
145 }
146
147 void genHTMLPrologue(String title) {
148 if (html) {
149 append("<html><head><title>");
150 append(title);
151 append("</title></head>");
152 append("<body>");
153 }
154 h2(title);
155 }
156 void genHTMLEpilogue() {
157 if (html) append("</body></html>");
158 }
159
160 }
161
162 private static final String DUMP_KLASS_OUTPUT_DIR = ".";
163 private static final int NATIVE_CODE_SIZE = 200;
164 private final String spaces;
165 private final String tab;
166
167 private boolean genHTML = true;
168
169 public HTMLGenerator() {
170 this(true);
171 }
172
173 public HTMLGenerator(boolean html) {
174 genHTML = html;
175 if (html) {
176 spaces = "&nbsp;&nbsp;";
177 tab = "&nbsp;&nbsp;&nbsp;&nbsp;";
178 } else {
179 spaces = " ";
180 tab = " ";
181 }
182 }
183
184 private static CPUHelper cpuHelper;
185 static {
186 VM.registerVMInitializedObserver(new Observer() {
187 public void update(Observable o, Object data) {
188 initialize();
189 }
190 });
191 }
192
193 private static synchronized void initialize() {
194 String cpu = VM.getVM().getCPU();
195 if (cpu.equals("sparc")) {
196 cpuHelper = new SPARCHelper();
197 } else if (cpu.equals("x86")) {
198 cpuHelper = new X86Helper();
199 } else if (cpu.equals("ia64")) {
200 cpuHelper = new IA64Helper();
201 } else {
202 throw new RuntimeException("cpu '" + cpu + "' is not yet supported!");
203 }
204 }
205
206 protected static synchronized CPUHelper getCPUHelper() {
207 return cpuHelper;
208 }
209
210 protected String escapeHTMLSpecialChars(String value) {
211 if (!genHTML) return value;
212
213 Formatter buf = new Formatter(genHTML);
214 int len = value.length();
215 for (int i=0; i < len; i++) {
216 char c = value.charAt(i);
217 switch (c) {
218 case '<':
219 buf.append("&lt;");
220 break;
221 case '>':
222 buf.append("&gt;");
223 break;
224 case '&':
225 buf.append("&amp;");
226 break;
227 default:
228 buf.append(c);
229 break;
230 }
231 }
232 return buf.toString();
233 }
234
235 public String genHTMLForMessage(String message) {
236 Formatter buf = new Formatter(genHTML);
237 buf.genHTMLPrologue(message);
238 buf.genHTMLEpilogue();
239 return buf.toString();
240 }
241
242 public String genHTMLErrorMessage(Exception exp) {
243 exp.printStackTrace();
244 return genHTMLForMessage(exp.getClass().getName() + " : " + exp.getMessage());
245 }
246
247 public String genHTMLForWait(String message) {
248 Formatter buf = new Formatter(genHTML);
249 buf.genHTMLPrologue("Please wait ..");
250 buf.h2(message);
251 return buf.toString();
252 }
253
254 protected String genKlassTitle(InstanceKlass klass) {
255 Formatter buf = new Formatter(genHTML);
256 AccessFlags acc = klass.getAccessFlagsObj();
257 if (acc.isPublic()) {
258 buf.append("public ");
259 } else if (acc.isProtected()) {
260 buf.append("protected ");
261 } else if (acc.isPrivate()) {
262 buf.append("private ");
263 }
264
265 if (acc.isStatic()) {
266 buf.append("static ");
267 }
268
269 if (acc.isAbstract() ) {
270 buf.append("abstract ");
271 } else if (acc.isFinal()) {
272 buf.append("final ");
273 }
274
275 if (acc.isStrict()) {
276 buf.append("strict ");
277 }
278
279 // javac generated flags
280 if (acc.isEnum()) {
281 buf.append("[enum] ");
282 }
283 if (acc.isSynthetic()) {
284 buf.append("[synthetic] ");
285 }
286
287 if (klass.isInterface()) {
288 buf.append("interface");
289 } else {
290 buf.append("class");
291 }
292
293 buf.append(' ');
294 buf.append(klass.getName().asString().replace('/', '.'));
295 // is it generic?
296 Symbol genSig = klass.getGenericSignature();
297 if (genSig != null) {
298 buf.append(" [signature ");
299 buf.append(escapeHTMLSpecialChars(genSig.asString()));
300 buf.append("] ");
301 } else {
302 buf.append(' ');
303 }
304 buf.append('@');
305 buf.append(klass.getHandle().toString());
306 return buf.toString();
307 }
308
309 protected String genBaseHref() {
310 return "";
311 }
312
313 protected String genKlassHref(InstanceKlass klass) {
314 return genBaseHref() + "klass=" + klass.getHandle();
315 }
316
317 protected String genKlassLink(InstanceKlass klass) {
318 Formatter buf = new Formatter(genHTML);
319 buf.link(genKlassHref(klass), genKlassTitle(klass));
320 return buf.toString();
321 }
322
323 protected String genMethodModifierString(AccessFlags acc) {
324 Formatter buf = new Formatter(genHTML);
325 if (acc.isPrivate()) {
326 buf.append("private ");
327 } else if (acc.isProtected()) {
328 buf.append("protected ");
329 } else if (acc.isPublic()) {
330 buf.append("public ");
331 }
332
333 if (acc.isStatic()) {
334 buf.append("static ");
335 } else if (acc.isAbstract() ) {
336 buf.append("abstract ");
337 } else if (acc.isFinal()) {
338 buf.append("final ");
339 }
340
341 if (acc.isNative()) {
342 buf.append("native ");
343 }
344
345 if (acc.isStrict()) {
346 buf.append("strict ");
347 }
348
349 if (acc.isSynchronized()) {
350 buf.append("synchronized ");
351 }
352
353 // javac generated flags
354 if (acc.isBridge()) {
355 buf.append("[bridge] ");
356 }
357
358 if (acc.isSynthetic()) {
359 buf.append("[synthetic] ");
360 }
361
362 if (acc.isVarArgs()) {
363 buf.append("[varargs] ");
364 }
365
366 return buf.toString();
367 }
368
369 protected String genMethodNameAndSignature(Method method) {
370 Formatter buf = new Formatter(genHTML);
371 buf.append(genMethodModifierString(method.getAccessFlagsObj()));
372 Symbol sig = method.getSignature();
373 new SignatureConverter(sig, buf.getBuffer()).iterateReturntype();
374 buf.append(" ");
375 String methodName = method.getName().asString();
376 buf.append(escapeHTMLSpecialChars(methodName));
377 buf.append('(');
378 new SignatureConverter(sig, buf.getBuffer()).iterateParameters();
379 buf.append(')');
380 // is it generic?
381 Symbol genSig = method.getGenericSignature();
382 if (genSig != null) {
383 buf.append(" [signature ");
384 buf.append(escapeHTMLSpecialChars(genSig.asString()));
385 buf.append("] ");
386 }
387 return buf.toString().replace('/', '.');
388 }
389
390 protected String genMethodTitle(Method method) {
391 Formatter buf = new Formatter(genHTML);
392 buf.append(genMethodNameAndSignature(method));
393 buf.append(' ');
394 buf.append('@');
395 buf.append(method.getHandle().toString());
396 return buf.toString();
397 }
398
399 protected String genMethodHref(Method m) {
400 return genBaseHref() + "method=" + m.getHandle();
401 }
402
403 protected String genMethodLink(Method m) {
404 Formatter buf = new Formatter(genHTML);
405 buf.link(genMethodHref(m), genMethodTitle(m));
406 return buf.toString();
407 }
408
409 protected String genMethodAndKlassLink(Method m) {
410 Formatter buf = new Formatter(genHTML);
411 buf.append(genMethodLink(m));
412 buf.append(" of ");
413 buf.append(genKlassLink((InstanceKlass) m.getMethodHolder()));
414 return buf.toString();
415 }
416
417 protected String genNMethodHref(NMethod nm) {
418 return genBaseHref() + "nmethod=" + nm.getAddress();
419 }
420
421 public String genNMethodTitle(NMethod nmethod) {
422 Formatter buf = new Formatter(genHTML);
423 Method m = nmethod.getMethod();
424
425 buf.append("Disassembly for compiled method [");
426 buf.append(genMethodTitle(m));
427 buf.append(" ] ");
428 buf.append('@');
429 buf.append(nmethod.getAddress().toString());
430 return buf.toString();
431 }
432
433 protected String genNMethodLink(NMethod nm) {
434 Formatter buf = new Formatter(genHTML);
435 buf.link(genNMethodHref(nm), genNMethodTitle(nm));
436 return buf.toString();
437 }
438
439 public String genCodeBlobTitle(CodeBlob blob) {
440 Formatter buf = new Formatter(genHTML);
441 buf.append("Disassembly for code blob " + blob.getName() + " [");
442 buf.append(blob.getClass().getName());
443 buf.append(" ] @");
444 buf.append(blob.getAddress().toString());
445 return buf.toString();
446 }
447
448 protected BytecodeDisassembler createBytecodeDisassembler(Method m) {
449 return new BytecodeDisassembler(m);
450 }
451
452 private String genLowHighShort(int val) {
453 Formatter buf = new Formatter(genHTML);
454 buf.append('#');
455 buf.append(Integer.toString(val & 0xFFFF));
456 buf.append(" #");
457 buf.append(Integer.toString((val >> 16) & 0xFFFF));
458 return buf.toString();
459 }
460
461 protected String genHTMLTableForConstantPool(ConstantPool cpool) {
462 Formatter buf = new Formatter(genHTML);
463 buf.beginTable(1);
464
465 buf.beginTag("tr");
466 buf.headerCell("Index");
467 buf.headerCell("Constant Type");
468 buf.headerCell("Constant Value");
469 buf.endTag("tr");
470
471 final int length = (int) cpool.getLength();
472 // zero'th pool entry is always invalid. ignore it.
473 for (int index = 1; index < length; index++) {
474 buf.beginTag("tr");
475 buf.cell(Integer.toString(index));
476
477 int ctag = (int) cpool.getTags().getByteAt((int) index);
478 switch (ctag) {
479 case JVM_CONSTANT_Integer:
480 buf.cell("JVM_CONSTANT_Integer");
481 buf.cell(Integer.toString(cpool.getIntAt(index)));
482 break;
483
484 case JVM_CONSTANT_Float:
485 buf.cell("JVM_CONSTANT_Float");
486 buf.cell(Float.toString(cpool.getFloatAt(index)));
487 break;
488
489 case JVM_CONSTANT_Long:
490 buf.cell("JVM_CONSTANT_Long");
491 buf.cell(Long.toString(cpool.getLongAt(index)));
492 // long entries occupy two slots
493 index++;
494 break;
495
496 case JVM_CONSTANT_Double:
497 buf.cell("JVM_CONSTANT_Double");
498 buf.cell(Double.toString(cpool.getDoubleAt(index)));
499 // double entries occupy two slots
500 index++;
501 break;
502
503 case JVM_CONSTANT_UnresolvedClass:
504 buf.cell("JVM_CONSTANT_UnresolvedClass");
505 buf.cell(cpool.getSymbolAt(index).asString());
506 break;
507
508 case JVM_CONSTANT_Class:
509 buf.cell("JVM_CONSTANT_Class");
510 Klass klass = (Klass) cpool.getObjAt(index);
511 if (klass instanceof InstanceKlass) {
512 buf.cell(genKlassLink((InstanceKlass) klass));
513 } else {
514 buf.cell(klass.getName().asString().replace('/', '.'));
515 }
516 break;
517
518 case JVM_CONSTANT_UnresolvedString:
519 buf.cell("JVM_CONSTANT_UnresolvedString");
520 buf.cell("\"" +
521 escapeHTMLSpecialChars(cpool.getSymbolAt(index).asString()) +
522 "\"");
523 break;
524
525 case JVM_CONSTANT_Utf8:
526 buf.cell("JVM_CONSTANT_Utf8");
527 buf.cell("\"" +
528 escapeHTMLSpecialChars(cpool.getSymbolAt(index).asString()) +
529 "\"");
530 break;
531
532 case JVM_CONSTANT_String:
533 buf.cell("JVM_CONSTANT_String");
534 buf.cell("\"" +
535 escapeHTMLSpecialChars(OopUtilities.stringOopToString(cpool.getObjAt(index))) + "\"");
536 break;
537
538 case JVM_CONSTANT_Fieldref:
539 buf.cell("JVM_CONSTANT_Fieldref");
540 buf.cell(genLowHighShort(cpool.getIntAt(index)));
541 break;
542
543 case JVM_CONSTANT_Methodref:
544 buf.cell("JVM_CONSTANT_Methodref");
545 buf.cell(genLowHighShort(cpool.getIntAt(index)));
546 break;
547
548 case JVM_CONSTANT_InterfaceMethodref:
549 buf.cell("JVM_CONSTANT_InterfaceMethodref");
550 buf.cell(genLowHighShort(cpool.getIntAt(index)));
551 break;
552
553 case JVM_CONSTANT_NameAndType:
554 buf.cell("JVM_CONSTANT_NameAndType");
555 buf.cell(genLowHighShort(cpool.getIntAt(index)));
556 break;
557
558 case JVM_CONSTANT_ClassIndex:
559 buf.cell("JVM_CONSTANT_ClassIndex");
560 buf.cell(Integer.toString(cpool.getIntAt(index)));
561 break;
562
563 case JVM_CONSTANT_StringIndex:
564 buf.cell("JVM_CONSTANT_StringIndex");
565 buf.cell(Integer.toString(cpool.getIntAt(index)));
566 break;
567 }
568
569 buf.endTag("tr");
570 }
571
572 buf.endTable();
573 return buf.toString();
574 }
575
576 public String genHTML(ConstantPool cpool) {
577 try {
578 Formatter buf = new Formatter(genHTML);
579 buf.genHTMLPrologue(genConstantPoolTitle(cpool));
580 buf.h3("Holder Class");
581 buf.append(genKlassLink((InstanceKlass) cpool.getPoolHolder()));
582 buf.h3("Constants");
583 buf.append(genHTMLTableForConstantPool(cpool));
584 buf.genHTMLEpilogue();
585 return buf.toString();
586 } catch (Exception exp) {
587 return genHTMLErrorMessage(exp);
588 }
589 }
590
591 protected String genConstantPoolHref(ConstantPool cpool) {
592 return genBaseHref() + "cpool=" + cpool.getHandle();
593 }
594
595 protected String genConstantPoolTitle(ConstantPool cpool) {
596 Formatter buf = new Formatter(genHTML);
597 buf.append("Constant Pool of [");
598 buf.append(genKlassTitle((InstanceKlass) cpool.getPoolHolder()));
599 buf.append("] @");
600 buf.append(cpool.getHandle().toString());
601 return buf.toString();
602 }
603
604 protected String genConstantPoolLink(ConstantPool cpool) {
605 Formatter buf = new Formatter(genHTML);
606 buf.link(genConstantPoolHref(cpool), genConstantPoolTitle(cpool));
607 return buf.toString();
608 }
609
610 public String genHTML(Method method) {
611 try {
612 final Formatter buf = new Formatter(genHTML);
613 buf.genHTMLPrologue(genMethodTitle(method));
614
615 buf.h3("Holder Class");
616 buf.append(genKlassLink((InstanceKlass) method.getMethodHolder()));
617
618 NMethod nmethod = method.getNativeMethod();
619 if (nmethod != null) {
620 buf.h3("Compiled Code");
621 buf.append(genNMethodLink(nmethod));
622 }
623
624 boolean hasThrows = method.hasCheckedExceptions();
625 ConstantPool cpool = ((InstanceKlass) method.getMethodHolder()).getConstants();
626 if (hasThrows) {
627 buf.h3("Checked Exception(s)");
628 CheckedExceptionElement[] exceptions = method.getCheckedExceptions();
629 buf.beginTag("ul");
630 for (int exp = 0; exp < exceptions.length; exp++) {
631 short cpIndex = (short) exceptions[exp].getClassCPIndex();
632 Oop obj = cpool.getObjAt(cpIndex);
633 if (obj instanceof Symbol) {
634 buf.li(((Symbol)obj).asString().replace('/', '.'));
635 } else {
636 buf.li(genKlassLink((InstanceKlass)obj));
637 }
638 }
639 buf.endTag("ul");
640 }
641
642 if (method.isNative() || method.isAbstract()) {
643 buf.genHTMLEpilogue();
644 return buf.toString();
645 }
646
647 buf.h3("Bytecode");
648 BytecodeDisassembler disasm = createBytecodeDisassembler(method);
649 final boolean hasLineNumbers = method.hasLineNumberTable();
650 disasm.decode(new BytecodeVisitor() {
651 private Method method;
652 public void prologue(Method m) {
653 method = m;
654 buf.beginTable(0);
655 buf.beginTag("tr");
656 if (hasLineNumbers) {
657 buf.headerCell("line");
658 }
659 buf.headerCell("bci" + spaces);
660 buf.headerCell("bytecode");
661 buf.endTag("tr");
662 }
663
664 public void visit(Bytecode instr) {
665 int curBci = instr.bci();
666 buf.beginTag("tr");
667 if (hasLineNumbers) {
668 int lineNumber = method.getLineNumberFromBCI(curBci);
669 buf.cell(Integer.toString(lineNumber) + spaces);
670 }
671 buf.cell(Integer.toString(curBci) + spaces);
672
673 buf.beginTag("td");
674 String instrStr = escapeHTMLSpecialChars(instr.toString());
675
676 if (instr instanceof BytecodeNew) {
677 BytecodeNew newBytecode = (BytecodeNew) instr;
678 InstanceKlass klass = newBytecode.getNewKlass();
679 if (klass != null) {
680 buf.link(genKlassHref(klass), instrStr);
681 } else {
682 buf.append(instrStr);
683 }
684 } else if(instr instanceof BytecodeInvoke) {
685 BytecodeInvoke invokeBytecode = (BytecodeInvoke) instr;
686 Method m = invokeBytecode.getInvokedMethod();
687 if (m != null) {
688 buf.link(genMethodHref(m), instrStr);
689 buf.append(" of ");
690 InstanceKlass klass = (InstanceKlass) m.getMethodHolder();
691 buf.link(genKlassHref(klass), genKlassTitle(klass));
692 } else {
693 buf.append(instrStr);
694 }
695 } else if (instr instanceof BytecodeGetPut) {
696 BytecodeGetPut getPut = (BytecodeGetPut) instr;
697 sun.jvm.hotspot.oops.Field f = getPut.getField();
698 buf.append(instrStr);
699 if (f != null) {
700 InstanceKlass klass = f.getFieldHolder();
701 buf.append(" of ");
702 buf.link(genKlassHref(klass), genKlassTitle(klass));
703 }
704 } else if (instr instanceof BytecodeLoadConstant) {
705 BytecodeLoadConstant ldc = (BytecodeLoadConstant) instr;
706 if (ldc.isKlassConstant()) {
707 Oop oop = ldc.getKlass();
708 if (oop instanceof Klass) {
709 buf.append("<a href='");
710 buf.append(genKlassHref((InstanceKlass) oop));
711 buf.append("'>");
712 buf.append(instrStr);
713 buf.append("</a>");
714 } else {
715 // unresolved klass literal
716 buf.append(instrStr);
717 }
718 } else {
719 // not a klass literal
720 buf.append(instrStr);
721 }
722 } else {
723 buf.append(instrStr);
724 }
725 buf.endTag("td");
726 buf.endTag("tr");
727 }
728
729 public void epilogue() {
730 buf.endTable();
731 }
732 });
733
734 // display exception table for this method
735 TypeArray exceptionTable = method.getExceptionTable();
736 // exception table is 4 tuple array of shorts
737 int numEntries = (int)exceptionTable.getLength() / 4;
738 if (numEntries != 0) {
739 buf.h4("Exception Table");
740 buf.beginTable(1);
741 buf.beginTag("tr");
742 buf.headerCell("start bci");
743 buf.headerCell("end bci");
744 buf.headerCell("handler bci");
745 buf.headerCell("catch type");
746 buf.endTag("tr");
747
748 for (int e = 0; e < numEntries; e += 4) {
749 buf.beginTag("tr");
750 buf.cell(Integer.toString(exceptionTable.getIntAt(e)));
751 buf.cell(Integer.toString(exceptionTable.getIntAt(e + 1)));
752 buf.cell(Integer.toString(exceptionTable.getIntAt(e + 2)));
753 short cpIndex = (short) exceptionTable.getIntAt(e + 3);
754 Oop obj = cpIndex == 0? null : cpool.getObjAt(cpIndex);
755 if (obj == null) {
756 buf.cell("Any");
757 } else if (obj instanceof Symbol) {
758 buf.cell(((Symbol)obj).asString().replace('/', '.'));
759 } else {
760 buf.cell(genKlassLink((InstanceKlass)obj));
761 }
762 buf.endTag("tr");
763 }
764
765 buf.endTable();
766 }
767
768 // display constant pool hyperlink
769 buf.h3("Constant Pool");
770 buf.append(genConstantPoolLink(cpool));
771 buf.genHTMLEpilogue();
772 return buf.toString();
773 } catch (Exception exp) {
774 return genHTMLErrorMessage(exp);
775 }
776 }
777
778 protected Disassembler createDisassembler(long startPc, byte[] code) {
779 return getCPUHelper().createDisassembler(startPc, code);
780 }
781
782 protected SymbolFinder createSymbolFinder() {
783 return new DummySymbolFinder();
784 }
785
786 // genHTML for a given address. Address may be a PC or
787 // methodOop or klassOop.
788
789 public String genHTMLForAddress(String addrStr) {
790 return genHTML(parseAddress(addrStr));
791 }
792
793 public String genHTML(sun.jvm.hotspot.debugger.Address pc) {
794 CodeBlob blob = null;
795
796 try {
797 blob = (CodeBlob)VM.getVM().getCodeCache().findBlobUnsafe(pc);
798 } catch (Exception exp) {
799 // ignore
800 }
801
802 if (blob != null) {
803 if (blob instanceof NMethod) {
804 return genHTML((NMethod)blob);
805 } else {
806 // may be interpreter code.
807 Interpreter interp = VM.getVM().getInterpreter();
808 if (interp.contains(pc)) {
809 InterpreterCodelet codelet = interp.getCodeletContaining(pc);
810 return genHTML(codelet);
811 }
812 return genHTML(blob);
813 }
814 } else if (VM.getVM().getCodeCache().contains(pc)) {
815 return "Unknown location in the CodeCache: " + pc;
816 }
817
818 // did not find nmethod.
819 // try methodOop, klassOop and constantPoolOop.
820 try {
821 Oop obj = getOopAtAddress(pc);
822 if (obj != null) {
823 if (obj instanceof Method) {
824 return genHTML((Method) obj);
825 } else if (obj instanceof InstanceKlass) {
826 return genHTML((InstanceKlass) obj);
827 } else if (obj instanceof ConstantPool) {
828 return genHTML((ConstantPool) obj);
829 }
830 }
831 } catch (Exception exp) {
832 // ignore
833 }
834
835 // didn't find any. do raw disassembly.
836 return genHTMLForRawDisassembly(pc, null);
837 }
838
839 protected byte[] readBuffer(sun.jvm.hotspot.debugger.Address addr, int size) {
840 byte[] buf = new byte[size];
841 for (int b = 0; b < size; b++) {
842 buf[b] = (byte) addr.getJByteAt(b);
843 }
844 return buf;
845 }
846
847 public String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address startPc, int size) {
848 try {
849 return genHTMLForRawDisassembly(startPc, null, readBuffer(startPc, size));
850 } catch (Exception exp) {
851 return genHTMLErrorMessage(exp);
852 }
853 }
854
855 protected String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address startPc,
856 String prevPCs) {
857 try {
858 return genHTMLForRawDisassembly(startPc, prevPCs, readBuffer(startPc, NATIVE_CODE_SIZE));
859 } catch (Exception exp) {
860 return genHTMLErrorMessage(exp);
861 }
862 }
863
864 protected String genPCHref(long targetPc) {
865 return genBaseHref() + "pc=0x" + Long.toHexString(targetPc);
866 }
867
868 protected String genMultPCHref(String pcs) {
869 StringBuffer buf = new StringBuffer(genBaseHref());
870 buf.append("pc_multiple=");
871 buf.append(pcs);
872 return buf.toString();
873 }
874
875 protected String genPCHref(long currentPc, sun.jvm.hotspot.asm.Address addr) {
876 String href = null;
877 if (addr instanceof PCRelativeAddress) {
878 PCRelativeAddress pcRelAddr = (PCRelativeAddress) addr;
879 href = genPCHref(currentPc + pcRelAddr.getDisplacement());
880 } else if(addr instanceof DirectAddress) {
881 href = genPCHref(((DirectAddress) addr).getValue());
882 }
883
884 return href;
885 }
886
887 class RawCodeVisitor implements InstructionVisitor {
888 private int instrSize = 0;
889 private Formatter buf;
890 private SymbolFinder symFinder = createSymbolFinder();
891
892 RawCodeVisitor(Formatter buf) {
893 this.buf = buf;
894 }
895
896 public int getInstructionSize() {
897 return instrSize;
898 }
899
900 public void prologue() {
901 }
902
903 public void visit(long currentPc, Instruction instr) {
904 String href = null;
905 if (instr.isCall()) {
906 CallInstruction call = (CallInstruction) instr;
907 sun.jvm.hotspot.asm.Address addr = call.getBranchDestination();
908 href = genPCHref(currentPc, addr);
909 }
910
911 instrSize += instr.getSize();
912 buf.append("0x");
913 buf.append(Long.toHexString(currentPc));
914 buf.append(':');
915 buf.append(tab);
916
917 if (href != null) {
918 buf.link(href, instr.asString(currentPc, symFinder));
919 } else {
920 buf.append(instr.asString(currentPc, symFinder));
921 }
922 buf.br();
923 }
924
925 public void epilogue() {
926 }
927 };
928
929 protected String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address addr,
930 String prevPCs,
931 byte[] code) {
932 try {
933 long startPc = addressToLong(addr);
934 Disassembler disasm = createDisassembler(startPc, code);
935 final Formatter buf = new Formatter(genHTML);
936 buf.genHTMLPrologue("Disassembly @0x" + Long.toHexString(startPc));
937
938 if (prevPCs != null && genHTML) {
939 buf.beginTag("p");
940 buf.link(genMultPCHref(prevPCs), "show previous code ..");
941 buf.endTag("p");
942 }
943
944
945 buf.h3("Code");
946 RawCodeVisitor visitor = new RawCodeVisitor(buf);
947 disasm.decode(visitor);
948
949 if (genHTML) buf.beginTag("p");
950 Formatter tmpBuf = new Formatter(genHTML);
951 tmpBuf.append("0x");
952 tmpBuf.append(Long.toHexString(startPc + visitor.getInstructionSize()).toString());
953 tmpBuf.append(",0x");
954 tmpBuf.append(Long.toHexString(startPc));
955 if (prevPCs != null) {
956 tmpBuf.append(',');
957 tmpBuf.append(prevPCs);
958 }
959 if (genHTML) {
960 buf.link(genMultPCHref(tmpBuf.toString()), "show more code ..");
961 buf.endTag("p");
962 }
963
964 buf.genHTMLEpilogue();
965 return buf.toString();
966 } catch (Exception exp) {
967 return genHTMLErrorMessage(exp);
968 }
969 }
970
971 protected String genSafepointInfo(NMethod nm, PCDesc pcDesc) {
972 ScopeDesc sd = nm.getScopeDescAt(pcDesc.getRealPC(nm));
973 Formatter buf = new Formatter(genHTML);
974 Formatter tabs = new Formatter(genHTML);
975
976 buf.beginTag("pre");
977 genScope(buf, tabs, sd);
978 buf.endTag("pre");
979 buf.append(genOopMapInfo(nm, pcDesc));
980
981 return buf.toString();
982 }
983
984 protected void genScope(Formatter buf, Formatter tabs, ScopeDesc sd) {
985 if (sd == null) {
986 return;
987 }
988
989 genScope(buf, tabs, sd.sender());
990
991 buf.append(tabs);
992 Method m = sd.getMethod();
993 buf.append(genMethodAndKlassLink(m));
994 int bci = sd.getBCI();
995 buf.append(" @ bci = ");
996 buf.append(Integer.toString(bci));
997
998 int line = m.getLineNumberFromBCI(bci);
999 if (line != -1) {
1000 buf.append(", line = ");
1001 buf.append(Integer.toString(line));
1002 }
1003
1004 List locals = sd.getLocals();
1005 if (locals != null) {
1006 buf.br();
1007 buf.append(tabs);
1008 buf.append(genHTMLForLocals(sd, locals));
1009 }
1010
1011 List expressions = sd.getExpressions();
1012 if (expressions != null) {
1013 buf.br();
1014 buf.append(tabs);
1015 buf.append(genHTMLForExpressions(sd, expressions));
1016 }
1017
1018 List monitors = sd.getMonitors();
1019 if (monitors != null) {
1020 buf.br();
1021 buf.append(tabs);
1022 buf.append(genHTMLForMonitors(sd, monitors));
1023 }
1024
1025 tabs.append(tab);
1026 buf.br();
1027 }
1028
1029 protected String genHTMLForOopMap(OopMap map) {
1030 final int stack0 = VMRegImpl.getStack0().getValue();
1031 Formatter buf = new Formatter(genHTML);
1032
1033 final class OopMapValueIterator {
1034 final Formatter iterate(OopMapStream oms, String type, boolean printContentReg) {
1035 Formatter tmpBuf = new Formatter(genHTML);
1036 boolean found = false;
1037 tmpBuf.beginTag("tr");
1038 tmpBuf.beginTag("td");
1039 tmpBuf.append(type);
1040 tmpBuf.endTag("td");
1041 tmpBuf.endTag("tr");
1042 for (; ! oms.isDone(); oms.next()) {
1043 OopMapValue omv = oms.getCurrent();
1044 if (omv == null) {
1045 continue;
1046 }
1047 found = true;
1048 VMReg vmReg = omv.getReg();
1049 int reg = vmReg.getValue();
1050 if (reg < stack0) {
1051 tmpBuf.append(VMRegImpl.getRegisterName(vmReg.getValue()));
1052 } else {
1053 tmpBuf.append('[');
1054 tmpBuf.append(Integer.toString((reg - stack0) * 4));
1055 tmpBuf.append(']');
1056 }
1057 if (printContentReg) {
1058 tmpBuf.append(" = ");
1059 VMReg vmContentReg = omv.getContentReg();
1060 int contentReg = vmContentReg.getValue();
1061 tmpBuf.append(VMRegImpl.getRegisterName(vmContentReg.getValue()));
1062 }
1063 tmpBuf.append(spaces);
1064 }
1065 tmpBuf.endTag("td");
1066 tmpBuf.endTag("tr");
1067 return found ? tmpBuf : new Formatter(genHTML);
1068 }
1069 }
1070
1071 buf.beginTable(0);
1072
1073 OopMapValueIterator omvIterator = new OopMapValueIterator();
1074 OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.OOP_VALUE);
1075 buf.append(omvIterator.iterate(oms, "Oop:", false));
1076
1077 oms = new OopMapStream(map, OopMapValue.OopTypes.VALUE_VALUE);
1078 buf.append(omvIterator.iterate(oms, "Value:", false));
1079
1080 oms = new OopMapStream(map, OopMapValue.OopTypes.DEAD_VALUE);
1081 buf.append(omvIterator.iterate(oms, "Dead:", false));
1082
1083 oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE);
1084 buf.append(omvIterator.iterate(oms, "Callee saved:", true));
1085
1086 oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE);
1087 buf.append(omvIterator.iterate(oms, "Derived oop:", true));
1088
1089 buf.endTag("table");
1090 return buf.toString();
1091 }
1092
1093
1094 protected String genOopMapInfo(NMethod nmethod, PCDesc pcDesc) {
1095 OopMapSet mapSet = nmethod.getOopMaps();
1096 int pcOffset = pcDesc.getPCOffset();
1097 OopMap map = mapSet.findMapAtOffset(pcOffset, VM.getVM().isDebugging());
1098 if (map == null) {
1099 throw new IllegalArgumentException("no oopmap at safepoint!");
1100 }
1101
1102 return genOopMapInfo(map);
1103 }
1104
1105 protected String genOopMapInfo(OopMap map) {
1106 Formatter buf = new Formatter(genHTML);
1107 buf.beginTag("pre");
1108 buf.append("OopMap: ");
1109 buf.append(genHTMLForOopMap(map));
1110 buf.endTag("pre");
1111
1112 return buf.toString();
1113 }
1114
1115 protected String locationAsString(Location loc) {
1116 Formatter buf = new Formatter(genHTML);
1117 if (loc.isIllegal()) {
1118 buf.append("illegal");
1119 } else {
1120 Location.Where w = loc.getWhere();
1121 Location.Type type = loc.getType();
1122
1123 if (w == Location.Where.ON_STACK) {
1124 buf.append("stack[" + loc.getStackOffset() + "]");
1125 } else if (w == Location.Where.IN_REGISTER) {
1126 boolean isFloat = (type == Location.Type.FLOAT_IN_DBL ||
1127 type == Location.Type.DBL);
1128 int regNum = loc.getRegisterNumber();
1129 VMReg vmReg = new VMReg(regNum);
1130 buf.append(VMRegImpl.getRegisterName(vmReg.getValue()));
1131 }
1132
1133 buf.append(", ");
1134 if (type == Location.Type.NORMAL) {
1135 buf.append("normal");
1136 } else if (type == Location.Type.OOP) {
1137 buf.append("oop");
1138 } else if (type == Location.Type.INT_IN_LONG) {
1139 buf.append("int");
1140 } else if (type == Location.Type.LNG) {
1141 buf.append("long");
1142 } else if (type == Location.Type.FLOAT_IN_DBL) {
1143 buf.append("float");
1144 } else if (type == Location.Type.DBL) {
1145 buf.append("double");
1146 } else if (type == Location.Type.ADDR) {
1147 buf.append("address");
1148 } else if (type == Location.Type.INVALID) {
1149 buf.append("invalid");
1150 }
1151 }
1152 return buf.toString();
1153 }
1154
1155 private String scopeValueAsString(ScopeValue sv) {
1156 Formatter buf = new Formatter(genHTML);
1157 if (sv.isConstantInt()) {
1158 buf.append("int ");
1159 ConstantIntValue intValue = (ConstantIntValue) sv;
1160 buf.append(Integer.toString(intValue.getValue()));
1161 } else if (sv.isConstantLong()) {
1162 buf.append("long ");
1163 ConstantLongValue longValue = (ConstantLongValue) sv;
1164 buf.append(Long.toString(longValue.getValue()));
1165 buf.append("L");
1166 } else if (sv.isConstantDouble()) {
1167 buf.append("double ");
1168 ConstantDoubleValue dblValue = (ConstantDoubleValue) sv;
1169 buf.append(Double.toString(dblValue.getValue()));
1170 buf.append("D");
1171 } else if (sv.isConstantOop()) {
1172 buf.append("oop ");
1173 ConstantOopReadValue oopValue = (ConstantOopReadValue) sv;
1174 OopHandle oopHandle = oopValue.getValue();
1175 if (oopHandle != null) {
1176 buf.append(oopHandle.toString());
1177 } else {
1178 buf.append("null");
1179 }
1180 } else if (sv.isLocation()) {
1181 LocationValue lvalue = (LocationValue) sv;
1182 Location loc = lvalue.getLocation();
1183 if (loc != null) {
1184 buf.append(locationAsString(loc));
1185 } else {
1186 buf.append("null");
1187 }
1188 }
1189 return buf.toString();
1190 }
1191
1192 protected String genHTMLForScopeValues(ScopeDesc sd, boolean locals, List values) {
1193 int length = values.size();
1194 Formatter buf = new Formatter(genHTML);
1195 buf.append(locals? "locals " : "expressions ");
1196 for (int i = 0; i < length; i++) {
1197 ScopeValue sv = (ScopeValue) values.get(i);
1198 if (sv == null) {
1199 continue;
1200 }
1201 buf.append('(');
1202 if (locals) {
1203 Symbol name = sd.getMethod().getLocalVariableName(sd.getBCI(), i);
1204 if (name != null) {
1205 buf.append("'");
1206 buf.append(name.asString());
1207 buf.append('\'');
1208 } else {
1209 buf.append("[");
1210 buf.append(Integer.toString(i));
1211 buf.append(']');
1212 }
1213 } else {
1214 buf.append("[");
1215 buf.append(Integer.toString(i));
1216 buf.append(']');
1217 }
1218
1219 buf.append(", ");
1220 buf.append(scopeValueAsString(sv));
1221 buf.append(") ");
1222 }
1223
1224 return buf.toString();
1225 }
1226
1227 protected String genHTMLForLocals(ScopeDesc sd, List locals) {
1228 return genHTMLForScopeValues(sd, true, locals);
1229 }
1230
1231 protected String genHTMLForExpressions(ScopeDesc sd, List expressions) {
1232 return genHTMLForScopeValues(sd, false, expressions);
1233 }
1234
1235 protected String genHTMLForMonitors(ScopeDesc sd, List monitors) {
1236 int length = monitors.size();
1237 Formatter buf = new Formatter(genHTML);
1238 buf.append("monitors ");
1239 for (int i = 0; i < length; i++) {
1240 MonitorValue mv = (MonitorValue) monitors.get(i);
1241 if (mv == null) {
1242 continue;
1243 }
1244 buf.append("(owner = ");
1245 ScopeValue owner = mv.owner();
1246 if (owner != null) {
1247 buf.append(scopeValueAsString(owner));
1248 } else {
1249 buf.append("null");
1250 }
1251 buf.append(", lock = ");
1252
1253 Location loc = mv.basicLock();
1254 if (loc != null) {
1255 buf.append(locationAsString(loc));
1256 } else {
1257 buf.append("null");
1258 }
1259 buf.append(") ");
1260 }
1261 return buf.toString();
1262 }
1263
1264 public String genHTML(final NMethod nmethod) {
1265 try {
1266 final Formatter buf = new Formatter(genHTML);
1267 buf.genHTMLPrologue(genNMethodTitle(nmethod));
1268 buf.h3("Method");
1269 buf.append(genMethodAndKlassLink(nmethod.getMethod()));
1270
1271 buf.h3("Compiled Code");
1272 sun.jvm.hotspot.debugger.Address codeBegin = nmethod.codeBegin();
1273 sun.jvm.hotspot.debugger.Address codeEnd = nmethod.codeEnd();
1274 final int codeSize = (int)codeEnd.minus(codeBegin);
1275 final long startPc = addressToLong(codeBegin);
1276 final byte[] code = new byte[codeSize];
1277 for (int i=0; i < code.length; i++)
1278 code[i] = codeBegin.getJByteAt(i);
1279
1280 final long verifiedEntryPoint = addressToLong(nmethod.getVerifiedEntryPoint());
1281 final long entryPoint = addressToLong(nmethod.getEntryPoint());
1282 final Map safepoints = nmethod.getSafepoints();
1283
1284 final SymbolFinder symFinder = createSymbolFinder();
1285 final Disassembler disasm = createDisassembler(startPc, code);
1286 class NMethodVisitor implements InstructionVisitor {
1287 boolean prevWasCall;
1288 public void prologue() {
1289 prevWasCall = false;
1290 }
1291
1292 public void visit(long currentPc, Instruction instr) {
1293 String href = null;
1294 if (instr.isCall()) {
1295 CallInstruction call = (CallInstruction) instr;
1296 sun.jvm.hotspot.asm.Address addr = call.getBranchDestination();
1297 href = genPCHref(currentPc, addr);
1298 }
1299
1300 if (currentPc == verifiedEntryPoint) {
1301 buf.bold("Verified Entry Point"); buf.br();
1302 }
1303 if (currentPc == entryPoint) {
1304 buf.bold(">Entry Point"); buf.br();
1305 }
1306
1307 PCDesc pcDesc = (PCDesc) safepoints.get(longToAddress(currentPc));
1308
1309 boolean isSafepoint = (pcDesc != null);
1310 if (isSafepoint && prevWasCall) {
1311 buf.append(genSafepointInfo(nmethod, pcDesc));
1312 }
1313
1314 buf.append("0x");
1315 buf.append(Long.toHexString(currentPc));
1316 buf.append(':');
1317 buf.append(tab);
1318
1319 if (href != null) {
1320 buf.link(href, instr.asString(currentPc, symFinder));
1321 } else {
1322 buf.append(instr.asString(currentPc, symFinder));
1323 }
1324
1325 if (isSafepoint && !prevWasCall) {
1326 buf.append(genSafepointInfo(nmethod, pcDesc));
1327 }
1328
1329 buf.br();
1330 prevWasCall = instr.isCall();
1331 }
1332
1333 public void epilogue() {
1334 }
1335 };
1336
1337 disasm.decode(new NMethodVisitor());
1338
1339 sun.jvm.hotspot.debugger.Address stubBegin = nmethod.stubBegin();
1340 if (stubBegin != null) {
1341 sun.jvm.hotspot.debugger.Address stubEnd = nmethod.stubEnd();
1342 buf.h3("Stub");
1343 long stubStartPc = addressToLong(stubBegin);
1344 long stubEndPc = addressToLong(stubEnd);
1345 int range = (int) (stubEndPc - stubStartPc);
1346 byte[] stubCode = readBuffer(stubBegin, range);
1347 Disassembler disasm2 = createDisassembler(stubStartPc, stubCode);
1348 disasm2.decode(new NMethodVisitor());
1349 }
1350 buf.genHTMLEpilogue();
1351 return buf.toString();
1352 } catch (Exception exp) {
1353 return genHTMLErrorMessage(exp);
1354 }
1355 }
1356
1357 public String genHTML(final CodeBlob blob) {
1358 try {
1359 final Formatter buf = new Formatter(genHTML);
1360 buf.genHTMLPrologue(genCodeBlobTitle(blob));
1361 buf.h3("CodeBlob");
1362
1363 buf.h3("Compiled Code");
1364 final sun.jvm.hotspot.debugger.Address codeBegin = blob.instructionsBegin();
1365 final int codeSize = blob.getInstructionsSize();
1366 final long startPc = addressToLong(codeBegin);
1367 final byte[] code = new byte[codeSize];
1368 for (int i=0; i < code.length; i++)
1369 code[i] = codeBegin.getJByteAt(i);
1370
1371 final SymbolFinder symFinder = createSymbolFinder();
1372 final Disassembler disasm = createDisassembler(startPc, code);
1373 class CodeBlobVisitor implements InstructionVisitor {
1374 OopMapSet maps;
1375 OopMap curMap;
1376 int curMapIndex;
1377 long curMapOffset;
1378 public void prologue() {
1379 maps = blob.getOopMaps();
1380 if (maps != null && (maps.getSize() > 0)) {
1381 curMap = maps.getMapAt(0);
1382 if (curMap != null) {
1383 curMapOffset = curMap.getOffset();
1384 }
1385 }
1386 }
1387
1388 public void visit(long currentPc, Instruction instr) {
1389 String href = null;
1390 if (instr.isCall()) {
1391 CallInstruction call = (CallInstruction) instr;
1392 sun.jvm.hotspot.asm.Address addr = call.getBranchDestination();
1393 href = genPCHref(currentPc, addr);
1394 }
1395
1396 buf.append("0x");
1397 buf.append(Long.toHexString(currentPc));
1398 buf.append(':');
1399 buf.append(tab);
1400
1401 if (href != null) {
1402 buf.link(href, instr.asString(currentPc, symFinder));
1403 } else {
1404 buf.append(instr.asString(currentPc, symFinder));
1405 }
1406 buf.br();
1407
1408 // See whether we have an oop map at this PC
1409 if (curMap != null) {
1410 long curOffset = currentPc - startPc;
1411 if (curOffset == curMapOffset) {
1412 buf.append(genOopMapInfo(curMap));
1413 if (++curMapIndex >= maps.getSize()) {
1414 curMap = null;
1415 } else {
1416 curMap = maps.getMapAt(curMapIndex);
1417 if (curMap != null) {
1418 curMapOffset = curMap.getOffset();
1419 }
1420 }
1421 }
1422 }
1423 }
1424
1425 public void epilogue() {
1426 }
1427 };
1428
1429 disasm.decode(new CodeBlobVisitor());
1430
1431 buf.genHTMLEpilogue();
1432 return buf.toString();
1433 } catch (Exception exp) {
1434 return genHTMLErrorMessage(exp);
1435 }
1436 }
1437
1438 protected String genInterpreterCodeletTitle(InterpreterCodelet codelet) {
1439 Formatter buf = new Formatter(genHTML);
1440 buf.append("Interpreter codelet [");
1441 buf.append(codelet.codeBegin().toString());
1442 buf.append(',');
1443 buf.append(codelet.codeEnd().toString());
1444 buf.append(") - ");
1445 buf.append(codelet.getDescription());
1446 return buf.toString();
1447 }
1448
1449 protected String genInterpreterCodeletLinkPageHref(StubQueue stubq) {
1450 return genBaseHref() + "interp_codelets";
1451 }
1452
1453 public String genInterpreterCodeletLinksPage() {
1454 Formatter buf = new Formatter(genHTML);
1455 buf.genHTMLPrologue("Interpreter Codelets");
1456 buf.beginTag("ul");
1457
1458 Interpreter interp = VM.getVM().getInterpreter();
1459 StubQueue code = interp.getCode();
1460 InterpreterCodelet stub = (InterpreterCodelet) code.getFirst();
1461 while (stub != null) {
1462 buf.beginTag("li");
1463 sun.jvm.hotspot.debugger.Address addr = stub.codeBegin();
1464 buf.link(genPCHref(addressToLong(addr)), stub.getDescription() + " @" + addr);
1465 buf.endTag("li");
1466 stub = (InterpreterCodelet) code.getNext(stub);
1467 }
1468
1469 buf.endTag("ul");
1470 buf.genHTMLEpilogue();
1471 return buf.toString();
1472 }
1473
1474 public String genHTML(InterpreterCodelet codelet) {
1475 Formatter buf = new Formatter(genHTML);
1476 buf.genHTMLPrologue(genInterpreterCodeletTitle(codelet));
1477 Interpreter interp = VM.getVM().getInterpreter();
1478 StubQueue stubq = interp.getCode();
1479
1480 if (genHTML) {
1481 buf.beginTag("h3");
1482 buf.link(genInterpreterCodeletLinkPageHref(stubq), "View links for all codelets");
1483 buf.endTag("h3");
1484 buf.br();
1485 }
1486
1487 Stub prev = stubq.getPrev(codelet);
1488 if (prev != null) {
1489 if (genHTML) {
1490 buf.beginTag("h3");
1491 buf.link(genPCHref(addressToLong(prev.codeBegin())), "View Previous Codelet");
1492 buf.endTag("h3");
1493 buf.br();
1494 } else {
1495 buf.h3("Previous Codelet = 0x" + Long.toHexString(addressToLong(prev.codeBegin())));
1496 }
1497 }
1498
1499 buf.h3("Code");
1500 long stubStartPc = addressToLong(codelet.codeBegin());
1501 long stubEndPc = addressToLong(codelet.codeEnd());
1502 int range = (int) (stubEndPc - stubStartPc);
1503 byte[] stubCode = readBuffer(codelet.codeBegin(), range);
1504 Disassembler disasm = createDisassembler(stubStartPc, stubCode);
1505 disasm.decode(new RawCodeVisitor(buf));
1506
1507
1508 Stub next = stubq.getNext(codelet);
1509 if (next != null) {
1510 if (genHTML) {
1511 buf.beginTag("h3");
1512 buf.link(genPCHref(addressToLong(next.codeBegin())), "View Next Codelet");
1513 buf.endTag("h3");
1514 } else {
1515 buf.h3("Next Codelet = 0x" + Long.toHexString(addressToLong(next.codeBegin())));
1516 }
1517 }
1518
1519 buf.genHTMLEpilogue();
1520 return buf.toString();
1521 }
1522
1523 protected String genDumpKlassesTitle(InstanceKlass[] klasses) {
1524 return (klasses.length == 1) ? "Create .class for this class"
1525 : "Create .class for all classes";
1526 }
1527
1528 protected String genDumpKlassesHref(InstanceKlass[] klasses) {
1529 StringBuffer buf = new StringBuffer(genBaseHref());
1530 buf.append("jcore_multiple=");
1531 for (int k = 0; k < klasses.length; k++) {
1532 buf.append(klasses[k].getHandle().toString());
1533 buf.append(',');
1534 }
1535 return buf.toString();
1536 }
1537
1538 protected String genDumpKlassesLink(InstanceKlass[] klasses) {
1539 if (!genHTML) return "";
1540
1541 Formatter buf = new Formatter(genHTML);
1542 buf.link(genDumpKlassesHref(klasses), genDumpKlassesTitle(klasses));
1543 return buf.toString();
1544 }
1545
1546 public String genHTMLForKlassNames(InstanceKlass[] klasses) {
1547 try {
1548 Formatter buf = new Formatter(genHTML);
1549 buf.genHTMLPrologue();
1550 buf.h3(genDumpKlassesLink(klasses));
1551
1552 buf.append(genHTMLListForKlassNames(klasses));
1553 buf.genHTMLEpilogue();
1554 return buf.toString();
1555 } catch (Exception exp) {
1556 return genHTMLErrorMessage(exp);
1557 }
1558 }
1559
1560 protected String genHTMLListForKlassNames(InstanceKlass[] klasses) {
1561 final Formatter buf = new Formatter(genHTML);
1562 buf.beginTable(0);
1563 for (int i = 0; i < klasses.length; i++) {
1564 InstanceKlass ik = klasses[i];
1565 buf.beginTag("tr");
1566 buf.cell(genKlassLink(ik));
1567 buf.endTag("tr");
1568 }
1569
1570 buf.endTable();
1571 return buf.toString();
1572 }
1573
1574 public String genHTMLForMethodNames(InstanceKlass klass) {
1575 try {
1576 Formatter buf = new Formatter(genHTML);
1577 buf.genHTMLPrologue();
1578 buf.append(genHTMLListForMethods(klass));
1579 buf.genHTMLEpilogue();
1580 return buf.toString();
1581 } catch (Exception exp) {
1582 return genHTMLErrorMessage(exp);
1583 }
1584 }
1585
1586 protected String genHTMLListForMethods(InstanceKlass klass) {
1587 Formatter buf = new Formatter(genHTML);
1588 ObjArray methods = klass.getMethods();
1589 int numMethods = (int) methods.getLength();
1590 if (numMethods != 0) {
1591 buf.h3("Methods");
1592 buf.beginTag("ul");
1593 for (int m = 0; m < numMethods; m++) {
1594 Method mtd = (Method) methods.getObjAt(m);
1595 buf.li(genMethodLink(mtd) + ";");
1596 }
1597 buf.endTag("ul");
1598 }
1599 return buf.toString();
1600 }
1601
1602 protected String genHTMLListForInterfaces(InstanceKlass klass) {
1603 try {
1604 Formatter buf = new Formatter(genHTML);
1605 ObjArray interfaces = klass.getLocalInterfaces();
1606 int numInterfaces = (int) interfaces.getLength();
1607 if (numInterfaces != 0) {
1608 buf.h3("Interfaces");
1609 buf.beginTag("ul");
1610 for (int i = 0; i < numInterfaces; i++) {
1611 InstanceKlass inf = (InstanceKlass) interfaces.getObjAt(i);
1612 buf.li(genKlassLink(inf));
1613 }
1614 buf.endTag("ul");
1615 }
1616 return buf.toString();
1617 } catch (Exception exp) {
1618 return genHTMLErrorMessage(exp);
1619 }
1620 }
1621
1622 protected String genFieldModifierString(AccessFlags acc) {
1623 Formatter buf = new Formatter(genHTML);
1624 if (acc.isPrivate()) {
1625 buf.append("private ");
1626 } else if (acc.isProtected()) {
1627 buf.append("protected ");
1628 } else if (acc.isPublic()) {
1629 buf.append("public ");
1630 }
1631
1632 if (acc.isStatic()) {
1633 buf.append("static ");
1634 }
1635
1636 if (acc.isFinal()) {
1637 buf.append("final ");
1638 }
1639 if (acc.isVolatile()) {
1640 buf.append("volatile ");
1641 }
1642 if (acc.isTransient()) {
1643 buf.append("transient ");
1644 }
1645
1646 // javac generated flags
1647 if (acc.isSynthetic()) {
1648 buf.append("[synthetic] ");
1649 }
1650 return buf.toString();
1651 }
1652
1653 public String genHTMLForFieldNames(InstanceKlass klass) {
1654 try {
1655 Formatter buf = new Formatter(genHTML);
1656 buf.genHTMLPrologue();
1657 buf.append(genHTMLListForFields(klass));
1658 buf.genHTMLEpilogue();
1659 return buf.toString();
1660 } catch (Exception exp) {
1661 return genHTMLErrorMessage(exp);
1662 }
1663 }
1664
1665 protected String genHTMLListForFields(InstanceKlass klass) {
1666 Formatter buf = new Formatter(genHTML);
1667 TypeArray fields = klass.getFields();
1668 int numFields = (int) fields.getLength();
1669 ConstantPool cp = klass.getConstants();
1670 if (numFields != 0) {
1671 buf.h3("Fields");
1672 buf.beginList();
1673 for (int f = 0; f < numFields; f += InstanceKlass.NEXT_OFFSET) {
1674 int nameIndex = fields.getShortAt(f + InstanceKlass.NAME_INDEX_OFFSET);
1675 int sigIndex = fields.getShortAt(f + InstanceKlass.SIGNATURE_INDEX_OFFSET);
1676 int genSigIndex = fields.getShortAt(f + InstanceKlass.GENERIC_SIGNATURE_INDEX_OFFSET);
1677 Symbol f_name = cp.getSymbolAt(nameIndex);
1678 Symbol f_sig = cp.getSymbolAt(sigIndex);
1679 Symbol f_genSig = (genSigIndex != 0)? cp.getSymbolAt(genSigIndex) : null;
1680 AccessFlags acc = new AccessFlags(fields.getShortAt(f + InstanceKlass.ACCESS_FLAGS_OFFSET));
1681
1682 buf.beginTag("li");
1683 buf.append(genFieldModifierString(acc));
1684 buf.append(' ');
1685 Formatter sigBuf = new Formatter(genHTML);
1686 new SignatureConverter(f_sig, sigBuf.getBuffer()).dispatchField();
1687 buf.append(sigBuf.toString().replace('/', '.'));
1688 buf.append(' ');
1689 buf.append(f_name.asString());
1690 buf.append(';');
1691 // is it generic?
1692 if (f_genSig != null) {
1693 buf.append(" [signature ");
1694 buf.append(escapeHTMLSpecialChars(f_genSig.asString()));
1695 buf.append("] ");
1696 }
1697 buf.endTag("li");
1698 }
1699 buf.endList();
1700 }
1701 return buf.toString();
1702 }
1703
1704 protected String genKlassHierarchyHref(InstanceKlass klass) {
1705 return genBaseHref() + "hierarchy=" + klass.getHandle();
1706 }
1707
1708 protected String genKlassHierarchyTitle(InstanceKlass klass) {
1709 Formatter buf = new Formatter(genHTML);
1710 buf.append("Class Hierarchy of ");
1711 buf.append(genKlassTitle(klass));
1712 return buf.toString();
1713 }
1714
1715 protected String genKlassHierarchyLink(InstanceKlass klass) {
1716 Formatter buf = new Formatter(genHTML);
1717 buf.link(genKlassHierarchyHref(klass), genKlassHierarchyTitle(klass));
1718 return buf.toString();
1719 }
1720
1721 protected String genHTMLListForSubKlasses(InstanceKlass klass) {
1722 Formatter buf = new Formatter(genHTML);
1723 Klass subklass = klass.getSubklassKlass();
1724 if (subklass != null) {
1725 buf.beginList();
1726 while (subklass != null) {
1727 if (subklass instanceof InstanceKlass) {
1728 buf.li(genKlassLink((InstanceKlass)subklass));
1729 }
1730 subklass = subklass.getNextSiblingKlass();
1731 }
1732 buf.endList();
1733 }
1734 return buf.toString();
1735 }
1736
1737 public String genHTMLForKlassHierarchy(InstanceKlass klass) {
1738 Formatter buf = new Formatter(genHTML);
1739 buf.genHTMLPrologue(genKlassHierarchyTitle(klass));
1740
1741
1742 buf.beginTag("pre");
1743 buf.append(genKlassLink(klass));
1744 buf.br();
1745 StringBuffer tabs = new StringBuffer(tab);
1746 InstanceKlass superKlass = klass;
1747 while ( (superKlass = (InstanceKlass) superKlass.getSuper()) != null ) {
1748 buf.append(tabs);
1749 buf.append(genKlassLink(superKlass));
1750 tabs.append(tab);
1751 buf.br();
1752 }
1753 buf.endTag("pre");
1754
1755 // generate subklass list
1756 Klass subklass = klass.getSubklassKlass();
1757 if (subklass != null) {
1758 buf.h3("Direct Subclasses");
1759 buf.append(genHTMLListForSubKlasses(klass));
1760 }
1761
1762 buf.genHTMLEpilogue();
1763 return buf.toString();
1764 }
1765
1766 protected String genDumpKlassHref(InstanceKlass klass) {
1767 return genBaseHref() + "jcore=" + klass.getHandle();
1768 }
1769
1770 protected String genDumpKlassLink(InstanceKlass klass) {
1771 if (!genHTML) return "";
1772
1773 Formatter buf = new Formatter(genHTML);
1774 buf.link(genDumpKlassHref(klass), "Create .class File");
1775 return buf.toString();
1776 }
1777
1778 public String genHTML(InstanceKlass klass) {
1779 Formatter buf = new Formatter(genHTML);
1780 buf.genHTMLPrologue(genKlassTitle(klass));
1781 InstanceKlass superKlass = (InstanceKlass) klass.getSuper();
1782
1783 if (genHTML) {
1784 // super class tree and subclass list
1785 buf.beginTag("h3");
1786 buf.link(genKlassHierarchyHref(klass), "View Class Hierarchy");
1787 buf.endTag("h3");
1788 }
1789
1790 // jcore - create .class link
1791 buf.h3(genDumpKlassLink(klass));
1792
1793 // super class
1794 if (superKlass != null) {
1795 buf.h3("Super Class");
1796 buf.append(genKlassLink(superKlass));
1797 }
1798
1799 // interfaces
1800 buf.append(genHTMLListForInterfaces(klass));
1801
1802 // fields
1803 buf.append(genHTMLListForFields(klass));
1804
1805 // methods
1806 buf.append(genHTMLListForMethods(klass));
1807
1808 // constant pool link
1809 buf.h3("Constant Pool");
1810 buf.append(genConstantPoolLink(klass.getConstants()));
1811
1812 buf.genHTMLEpilogue();
1813 return buf.toString();
1814 }
1815
1816 protected sun.jvm.hotspot.debugger.Address parseAddress(String address) {
1817 VM vm = VM.getVM();
1818 sun.jvm.hotspot.debugger.Address addr = vm.getDebugger().parseAddress(address);
1819 return addr;
1820 }
1821
1822 protected long addressToLong(sun.jvm.hotspot.debugger.Address addr) {
1823 return VM.getVM().getDebugger().getAddressValue(addr);
1824 }
1825
1826 protected sun.jvm.hotspot.debugger.Address longToAddress(long addr) {
1827 return parseAddress("0x" + Long.toHexString(addr));
1828 }
1829
1830 protected Oop getOopAtAddress(sun.jvm.hotspot.debugger.Address addr) {
1831 OopHandle oopHandle = addr.addOffsetToAsOopHandle(0);
1832 return VM.getVM().getObjectHeap().newOop(oopHandle);
1833 }
1834
1835 protected Oop getOopAtAddress(String address) {
1836 sun.jvm.hotspot.debugger.Address addr = parseAddress(address);
1837 return getOopAtAddress(addr);
1838 }
1839
1840 private void dumpKlass(InstanceKlass kls) throws IOException {
1841 String klassName = kls.getName().asString();
1842 klassName = klassName.replace('/', File.separatorChar);
1843 int index = klassName.lastIndexOf(File.separatorChar);
1844 File dir = null;
1845 if (index != -1) {
1846 String dirName = klassName.substring(0, index);
1847 dir = new File(DUMP_KLASS_OUTPUT_DIR, dirName);
1848 } else {
1849 dir = new File(DUMP_KLASS_OUTPUT_DIR);
1850 }
1851
1852 dir.mkdirs();
1853 File f = new File(dir, klassName.substring(klassName.lastIndexOf(File.separatorChar) + 1)
1854 + ".class");
1855 f.createNewFile();
1856 FileOutputStream fis = new FileOutputStream(f);
1857 ClassWriter cw = new ClassWriter(kls, fis);
1858 cw.write();
1859 }
1860
1861 public String genDumpKlass(InstanceKlass kls) {
1862 try {
1863 dumpKlass(kls);
1864 Formatter buf = new Formatter(genHTML);
1865 buf.genHTMLPrologue(genKlassTitle(kls));
1866 buf.append(".class created for ");
1867 buf.append(genKlassLink(kls));
1868 buf.genHTMLEpilogue();
1869 return buf.toString();
1870 } catch(IOException exp) {
1871 return genHTMLErrorMessage(exp);
1872 }
1873 }
1874
1875 protected String genJavaStackTraceTitle(JavaThread thread) {
1876 Formatter buf = new Formatter(genHTML);
1877 buf.append("Java Stack Trace for ");
1878 buf.append(thread.getThreadName());
1879 return buf.toString();
1880 }
1881
1882 public String genHTMLForJavaStackTrace(JavaThread thread) {
1883 Formatter buf = new Formatter(genHTML);
1884 buf.genHTMLPrologue(genJavaStackTraceTitle(thread));
1885
1886 buf.append("Thread state = ");
1887 buf.append(thread.getThreadState().toString());
1888 buf.br();
1889 buf.beginTag("pre");
1890 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
1891 Method method = vf.getMethod();
1892 buf.append(" - ");
1893 buf.append(genMethodLink(method));
1894 buf.append(" @bci = " + vf.getBCI());
1895
1896 int lineNumber = method.getLineNumberFromBCI(vf.getBCI());
1897 if (lineNumber != -1) {
1898 buf.append(", line = ");
1899 buf.append(lineNumber);
1900 }
1901
1902 sun.jvm.hotspot.debugger.Address pc = vf.getFrame().getPC();
1903 if (pc != null) {
1904 buf.append(", pc = ");
1905 buf.link(genPCHref(addressToLong(pc)), pc.toString());
1906 }
1907
1908 if (vf.isCompiledFrame()) {
1909 buf.append(" (Compiled");
1910 }
1911 else if (vf.isInterpretedFrame()) {
1912 buf.append(" (Interpreted");
1913 }
1914
1915 if (vf.mayBeImpreciseDbg()) {
1916 buf.append("; information may be imprecise");
1917 }
1918 buf.append(")");
1919 buf.br();
1920 }
1921
1922 buf.endTag("pre");
1923 buf.genHTMLEpilogue();
1924 return buf.toString();
1925 }
1926
1927 public String genHTMLForHyperlink(String href) {
1928 if (href.startsWith("klass=")) {
1929 href = href.substring(href.indexOf('=') + 1);
1930 Oop obj = getOopAtAddress(href);
1931 if (Assert.ASSERTS_ENABLED) {
1932 Assert.that(obj instanceof InstanceKlass, "class= href with improper InstanceKlass!");
1933 }
1934 return genHTML((InstanceKlass) obj);
1935 } else if (href.startsWith("method=")) {
1936 href = href.substring(href.indexOf('=') + 1);
1937 Oop obj = getOopAtAddress(href);
1938 if (Assert.ASSERTS_ENABLED) {
1939 Assert.that(obj instanceof Method, "method= href with improper Method!");
1940 }
1941 return genHTML((Method) obj);
1942 } else if (href.startsWith("nmethod=")) {
1943 String addr = href.substring(href.indexOf('=') + 1);
1944 Object obj = VMObjectFactory.newObject(NMethod.class, parseAddress(addr));
1945 if (Assert.ASSERTS_ENABLED) {
1946 Assert.that(obj instanceof NMethod, "nmethod= href with improper NMethod!");
1947 }
1948 return genHTML((NMethod) obj);
1949 } else if (href.startsWith("pc=")) {
1950 String address = href.substring(href.indexOf('=') + 1);
1951 return genHTML(parseAddress(address));
1952 } else if (href.startsWith("pc_multiple=")) {
1953 int indexOfComma = href.indexOf(',');
1954 if (indexOfComma == -1) {
1955 String firstPC = href.substring(href.indexOf('=') + 1);
1956 return genHTMLForRawDisassembly(parseAddress(firstPC), null);
1957 } else {
1958 String firstPC = href.substring(href.indexOf('=') + 1, indexOfComma);
1959 return genHTMLForRawDisassembly(parseAddress(firstPC), href.substring(indexOfComma + 1));
1960 }
1961 } else if (href.startsWith("interp_codelets")) {
1962 return genInterpreterCodeletLinksPage();
1963 } else if (href.startsWith("hierarchy=")) {
1964 href = href.substring(href.indexOf('=') + 1);
1965 Oop obj = getOopAtAddress(href);
1966 if (Assert.ASSERTS_ENABLED) {
1967 Assert.that(obj instanceof InstanceKlass, "class= href with improper InstanceKlass!");
1968 }
1969 return genHTMLForKlassHierarchy((InstanceKlass) obj);
1970 } else if (href.startsWith("cpool=")) {
1971 href = href.substring(href.indexOf('=') + 1);
1972 Oop obj = getOopAtAddress(href);
1973 if (Assert.ASSERTS_ENABLED) {
1974 Assert.that(obj instanceof ConstantPool, "cpool= href with improper ConstantPool!");
1975 }
1976 return genHTML((ConstantPool) obj);
1977 } else if (href.startsWith("jcore=")) {
1978 href = href.substring(href.indexOf('=') + 1);
1979 Oop obj = getOopAtAddress(href);
1980 if (Assert.ASSERTS_ENABLED) {
1981 Assert.that(obj instanceof InstanceKlass, "jcore= href with improper InstanceKlass!");
1982 }
1983 return genDumpKlass((InstanceKlass) obj);
1984 } else if (href.startsWith("jcore_multiple=")) {
1985 href = href.substring(href.indexOf('=') + 1);
1986 Formatter buf = new Formatter(genHTML);
1987 buf.genHTMLPrologue();
1988 StringTokenizer st = new StringTokenizer(href, ",");
1989 while (st.hasMoreTokens()) {
1990 Oop obj = getOopAtAddress(st.nextToken());
1991 if (Assert.ASSERTS_ENABLED) {
1992 Assert.that(obj instanceof InstanceKlass, "jcore_multiple= href with improper InstanceKlass!");
1993 }
1994
1995 InstanceKlass kls = (InstanceKlass) obj;
1996 try {
1997 dumpKlass(kls);
1998 buf.append(".class created for ");
1999 buf.append(genKlassLink(kls));
2000 } catch(Exception exp) {
2001 buf.bold("can't .class for " +
2002 genKlassTitle(kls) +
2003 " : " +
2004 exp.getMessage());
2005 }
2006 buf.br();
2007 }
2008
2009 buf.genHTMLEpilogue();
2010 return buf.toString();
2011 } else {
2012 if (Assert.ASSERTS_ENABLED) {
2013 Assert.that(false, "unknown href link!");
2014 }
2015 return null;
2016 }
2017 }
2018 }