1 /*
2 * Copyright 2002-2008 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 = " ";
177 tab = " ";
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("<");
220 break;
221 case '>':
222 buf.append(">");
223 break;
224 case '&':
225 buf.append("&");
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.NARROWOOP_VALUE);
1081 buf.append(omvIterator.iterate(oms, "Oop:", 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.NARROWOOP) {
1139 buf.append("narrowoop");
1140 } else if (type == Location.Type.INT_IN_LONG) {
1141 buf.append("int");
1142 } else if (type == Location.Type.LNG) {
1143 buf.append("long");
1144 } else if (type == Location.Type.FLOAT_IN_DBL) {
1145 buf.append("float");
1146 } else if (type == Location.Type.DBL) {
1147 buf.append("double");
1148 } else if (type == Location.Type.ADDR) {
1149 buf.append("address");
1150 } else if (type == Location.Type.INVALID) {
1151 buf.append("invalid");
1152 }
1153 }
1154 return buf.toString();
1155 }
1156
1157 private String scopeValueAsString(ScopeValue sv) {
1158 Formatter buf = new Formatter(genHTML);
1159 if (sv.isConstantInt()) {
1160 buf.append("int ");
1161 ConstantIntValue intValue = (ConstantIntValue) sv;
1162 buf.append(Integer.toString(intValue.getValue()));
1163 } else if (sv.isConstantLong()) {
1164 buf.append("long ");
1165 ConstantLongValue longValue = (ConstantLongValue) sv;
1166 buf.append(Long.toString(longValue.getValue()));
1167 buf.append("L");
1168 } else if (sv.isConstantDouble()) {
1169 buf.append("double ");
1170 ConstantDoubleValue dblValue = (ConstantDoubleValue) sv;
1171 buf.append(Double.toString(dblValue.getValue()));
1172 buf.append("D");
1173 } else if (sv.isConstantOop()) {
1174 buf.append("oop ");
1175 ConstantOopReadValue oopValue = (ConstantOopReadValue) sv;
1176 OopHandle oopHandle = oopValue.getValue();
1177 if (oopHandle != null) {
1178 buf.append(oopHandle.toString());
1179 } else {
1180 buf.append("null");
1181 }
1182 } else if (sv.isLocation()) {
1183 LocationValue lvalue = (LocationValue) sv;
1184 Location loc = lvalue.getLocation();
1185 if (loc != null) {
1186 buf.append(locationAsString(loc));
1187 } else {
1188 buf.append("null");
1189 }
1190 }
1191 return buf.toString();
1192 }
1193
1194 protected String genHTMLForScopeValues(ScopeDesc sd, boolean locals, List values) {
1195 int length = values.size();
1196 Formatter buf = new Formatter(genHTML);
1197 buf.append(locals? "locals " : "expressions ");
1198 for (int i = 0; i < length; i++) {
1199 ScopeValue sv = (ScopeValue) values.get(i);
1200 if (sv == null) {
1201 continue;
1202 }
1203 buf.append('(');
1204 if (locals) {
1205 Symbol name = sd.getMethod().getLocalVariableName(sd.getBCI(), i);
1206 if (name != null) {
1207 buf.append("'");
1208 buf.append(name.asString());
1209 buf.append('\'');
1210 } else {
1211 buf.append("[");
1212 buf.append(Integer.toString(i));
1213 buf.append(']');
1214 }
1215 } else {
1216 buf.append("[");
1217 buf.append(Integer.toString(i));
1218 buf.append(']');
1219 }
1220
1221 buf.append(", ");
1222 buf.append(scopeValueAsString(sv));
1223 buf.append(") ");
1224 }
1225
1226 return buf.toString();
1227 }
1228
1229 protected String genHTMLForLocals(ScopeDesc sd, List locals) {
1230 return genHTMLForScopeValues(sd, true, locals);
1231 }
1232
1233 protected String genHTMLForExpressions(ScopeDesc sd, List expressions) {
1234 return genHTMLForScopeValues(sd, false, expressions);
1235 }
1236
1237 protected String genHTMLForMonitors(ScopeDesc sd, List monitors) {
1238 int length = monitors.size();
1239 Formatter buf = new Formatter(genHTML);
1240 buf.append("monitors ");
1241 for (int i = 0; i < length; i++) {
1242 MonitorValue mv = (MonitorValue) monitors.get(i);
1243 if (mv == null) {
1244 continue;
1245 }
1246 buf.append("(owner = ");
1247 ScopeValue owner = mv.owner();
1248 if (owner != null) {
1249 buf.append(scopeValueAsString(owner));
1250 } else {
1251 buf.append("null");
1252 }
1253 buf.append(", lock = ");
1254
1255 Location loc = mv.basicLock();
1256 if (loc != null) {
1257 buf.append(locationAsString(loc));
1258 } else {
1259 buf.append("null");
1260 }
1261 buf.append(") ");
1262 }
1263 return buf.toString();
1264 }
1265
1266 public String genHTML(final NMethod nmethod) {
1267 try {
1268 final Formatter buf = new Formatter(genHTML);
1269 buf.genHTMLPrologue(genNMethodTitle(nmethod));
1270 buf.h3("Method");
1271 buf.append(genMethodAndKlassLink(nmethod.getMethod()));
1272
1273 buf.h3("Compiled Code");
1274 sun.jvm.hotspot.debugger.Address codeBegin = nmethod.codeBegin();
1275 sun.jvm.hotspot.debugger.Address codeEnd = nmethod.codeEnd();
1276 final int codeSize = (int)codeEnd.minus(codeBegin);
1277 final long startPc = addressToLong(codeBegin);
1278 final byte[] code = new byte[codeSize];
1279 for (int i=0; i < code.length; i++)
1280 code[i] = codeBegin.getJByteAt(i);
1281
1282 final long verifiedEntryPoint = addressToLong(nmethod.getVerifiedEntryPoint());
1283 final long entryPoint = addressToLong(nmethod.getEntryPoint());
1284 final Map safepoints = nmethod.getSafepoints();
1285
1286 final SymbolFinder symFinder = createSymbolFinder();
1287 final Disassembler disasm = createDisassembler(startPc, code);
1288 class NMethodVisitor implements InstructionVisitor {
1289 boolean prevWasCall;
1290 public void prologue() {
1291 prevWasCall = false;
1292 }
1293
1294 public void visit(long currentPc, Instruction instr) {
1295 String href = null;
1296 if (instr.isCall()) {
1297 CallInstruction call = (CallInstruction) instr;
1298 sun.jvm.hotspot.asm.Address addr = call.getBranchDestination();
1299 href = genPCHref(currentPc, addr);
1300 }
1301
1302 if (currentPc == verifiedEntryPoint) {
1303 buf.bold("Verified Entry Point"); buf.br();
1304 }
1305 if (currentPc == entryPoint) {
1306 buf.bold(">Entry Point"); buf.br();
1307 }
1308
1309 PCDesc pcDesc = (PCDesc) safepoints.get(longToAddress(currentPc));
1310
1311 boolean isSafepoint = (pcDesc != null);
1312 if (isSafepoint && prevWasCall) {
1313 buf.append(genSafepointInfo(nmethod, pcDesc));
1314 }
1315
1316 buf.append("0x");
1317 buf.append(Long.toHexString(currentPc));
1318 buf.append(':');
1319 buf.append(tab);
1320
1321 if (href != null) {
1322 buf.link(href, instr.asString(currentPc, symFinder));
1323 } else {
1324 buf.append(instr.asString(currentPc, symFinder));
1325 }
1326
1327 if (isSafepoint && !prevWasCall) {
1328 buf.append(genSafepointInfo(nmethod, pcDesc));
1329 }
1330
1331 buf.br();
1332 prevWasCall = instr.isCall();
1333 }
1334
1335 public void epilogue() {
1336 }
1337 };
1338
1339 disasm.decode(new NMethodVisitor());
1340
1341 sun.jvm.hotspot.debugger.Address stubBegin = nmethod.stubBegin();
1342 if (stubBegin != null) {
1343 sun.jvm.hotspot.debugger.Address stubEnd = nmethod.stubEnd();
1344 buf.h3("Stub");
1345 long stubStartPc = addressToLong(stubBegin);
1346 long stubEndPc = addressToLong(stubEnd);
1347 int range = (int) (stubEndPc - stubStartPc);
1348 byte[] stubCode = readBuffer(stubBegin, range);
1349 Disassembler disasm2 = createDisassembler(stubStartPc, stubCode);
1350 disasm2.decode(new NMethodVisitor());
1351 }
1352 buf.genHTMLEpilogue();
1353 return buf.toString();
1354 } catch (Exception exp) {
1355 return genHTMLErrorMessage(exp);
1356 }
1357 }
1358
1359 public String genHTML(final CodeBlob blob) {
1360 try {
1361 final Formatter buf = new Formatter(genHTML);
1362 buf.genHTMLPrologue(genCodeBlobTitle(blob));
1363 buf.h3("CodeBlob");
1364
1365 buf.h3("Compiled Code");
1366 final sun.jvm.hotspot.debugger.Address codeBegin = blob.instructionsBegin();
1367 final int codeSize = blob.getInstructionsSize();
1368 final long startPc = addressToLong(codeBegin);
1369 final byte[] code = new byte[codeSize];
1370 for (int i=0; i < code.length; i++)
1371 code[i] = codeBegin.getJByteAt(i);
1372
1373 final SymbolFinder symFinder = createSymbolFinder();
1374 final Disassembler disasm = createDisassembler(startPc, code);
1375 class CodeBlobVisitor implements InstructionVisitor {
1376 OopMapSet maps;
1377 OopMap curMap;
1378 int curMapIndex;
1379 long curMapOffset;
1380 public void prologue() {
1381 maps = blob.getOopMaps();
1382 if (maps != null && (maps.getSize() > 0)) {
1383 curMap = maps.getMapAt(0);
1384 if (curMap != null) {
1385 curMapOffset = curMap.getOffset();
1386 }
1387 }
1388 }
1389
1390 public void visit(long currentPc, Instruction instr) {
1391 String href = null;
1392 if (instr.isCall()) {
1393 CallInstruction call = (CallInstruction) instr;
1394 sun.jvm.hotspot.asm.Address addr = call.getBranchDestination();
1395 href = genPCHref(currentPc, addr);
1396 }
1397
1398 buf.append("0x");
1399 buf.append(Long.toHexString(currentPc));
1400 buf.append(':');
1401 buf.append(tab);
1402
1403 if (href != null) {
1404 buf.link(href, instr.asString(currentPc, symFinder));
1405 } else {
1406 buf.append(instr.asString(currentPc, symFinder));
1407 }
1408 buf.br();
1409
1410 // See whether we have an oop map at this PC
1411 if (curMap != null) {
1412 long curOffset = currentPc - startPc;
1413 if (curOffset == curMapOffset) {
1414 buf.append(genOopMapInfo(curMap));
1415 if (++curMapIndex >= maps.getSize()) {
1416 curMap = null;
1417 } else {
1418 curMap = maps.getMapAt(curMapIndex);
1419 if (curMap != null) {
1420 curMapOffset = curMap.getOffset();
1421 }
1422 }
1423 }
1424 }
1425 }
1426
1427 public void epilogue() {
1428 }
1429 };
1430
1431 disasm.decode(new CodeBlobVisitor());
1432
1433 buf.genHTMLEpilogue();
1434 return buf.toString();
1435 } catch (Exception exp) {
1436 return genHTMLErrorMessage(exp);
1437 }
1438 }
1439
1440 protected String genInterpreterCodeletTitle(InterpreterCodelet codelet) {
1441 Formatter buf = new Formatter(genHTML);
1442 buf.append("Interpreter codelet [");
1443 buf.append(codelet.codeBegin().toString());
1444 buf.append(',');
1445 buf.append(codelet.codeEnd().toString());
1446 buf.append(") - ");
1447 buf.append(codelet.getDescription());
1448 return buf.toString();
1449 }
1450
1451 protected String genInterpreterCodeletLinkPageHref(StubQueue stubq) {
1452 return genBaseHref() + "interp_codelets";
1453 }
1454
1455 public String genInterpreterCodeletLinksPage() {
1456 Formatter buf = new Formatter(genHTML);
1457 buf.genHTMLPrologue("Interpreter Codelets");
1458 buf.beginTag("ul");
1459
1460 Interpreter interp = VM.getVM().getInterpreter();
1461 StubQueue code = interp.getCode();
1462 InterpreterCodelet stub = (InterpreterCodelet) code.getFirst();
1463 while (stub != null) {
1464 buf.beginTag("li");
1465 sun.jvm.hotspot.debugger.Address addr = stub.codeBegin();
1466 buf.link(genPCHref(addressToLong(addr)), stub.getDescription() + " @" + addr);
1467 buf.endTag("li");
1468 stub = (InterpreterCodelet) code.getNext(stub);
1469 }
1470
1471 buf.endTag("ul");
1472 buf.genHTMLEpilogue();
1473 return buf.toString();
1474 }
1475
1476 public String genHTML(InterpreterCodelet codelet) {
1477 Formatter buf = new Formatter(genHTML);
1478 buf.genHTMLPrologue(genInterpreterCodeletTitle(codelet));
1479 Interpreter interp = VM.getVM().getInterpreter();
1480 StubQueue stubq = interp.getCode();
1481
1482 if (genHTML) {
1483 buf.beginTag("h3");
1484 buf.link(genInterpreterCodeletLinkPageHref(stubq), "View links for all codelets");
1485 buf.endTag("h3");
1486 buf.br();
1487 }
1488
1489 Stub prev = stubq.getPrev(codelet);
1490 if (prev != null) {
1491 if (genHTML) {
1492 buf.beginTag("h3");
1493 buf.link(genPCHref(addressToLong(prev.codeBegin())), "View Previous Codelet");
1494 buf.endTag("h3");
1495 buf.br();
1496 } else {
1497 buf.h3("Previous Codelet = 0x" + Long.toHexString(addressToLong(prev.codeBegin())));
1498 }
1499 }
1500
1501 buf.h3("Code");
1502 long stubStartPc = addressToLong(codelet.codeBegin());
1503 long stubEndPc = addressToLong(codelet.codeEnd());
1504 int range = (int) (stubEndPc - stubStartPc);
1505 byte[] stubCode = readBuffer(codelet.codeBegin(), range);
1506 Disassembler disasm = createDisassembler(stubStartPc, stubCode);
1507 disasm.decode(new RawCodeVisitor(buf));
1508
1509
1510 Stub next = stubq.getNext(codelet);
1511 if (next != null) {
1512 if (genHTML) {
1513 buf.beginTag("h3");
1514 buf.link(genPCHref(addressToLong(next.codeBegin())), "View Next Codelet");
1515 buf.endTag("h3");
1516 } else {
1517 buf.h3("Next Codelet = 0x" + Long.toHexString(addressToLong(next.codeBegin())));
1518 }
1519 }
1520
1521 buf.genHTMLEpilogue();
1522 return buf.toString();
1523 }
1524
1525 protected String genDumpKlassesTitle(InstanceKlass[] klasses) {
1526 return (klasses.length == 1) ? "Create .class for this class"
1527 : "Create .class for all classes";
1528 }
1529
1530 protected String genDumpKlassesHref(InstanceKlass[] klasses) {
1531 StringBuffer buf = new StringBuffer(genBaseHref());
1532 buf.append("jcore_multiple=");
1533 for (int k = 0; k < klasses.length; k++) {
1534 buf.append(klasses[k].getHandle().toString());
1535 buf.append(',');
1536 }
1537 return buf.toString();
1538 }
1539
1540 protected String genDumpKlassesLink(InstanceKlass[] klasses) {
1541 if (!genHTML) return "";
1542
1543 Formatter buf = new Formatter(genHTML);
1544 buf.link(genDumpKlassesHref(klasses), genDumpKlassesTitle(klasses));
1545 return buf.toString();
1546 }
1547
1548 public String genHTMLForKlassNames(InstanceKlass[] klasses) {
1549 try {
1550 Formatter buf = new Formatter(genHTML);
1551 buf.genHTMLPrologue();
1552 buf.h3(genDumpKlassesLink(klasses));
1553
1554 buf.append(genHTMLListForKlassNames(klasses));
1555 buf.genHTMLEpilogue();
1556 return buf.toString();
1557 } catch (Exception exp) {
1558 return genHTMLErrorMessage(exp);
1559 }
1560 }
1561
1562 protected String genHTMLListForKlassNames(InstanceKlass[] klasses) {
1563 final Formatter buf = new Formatter(genHTML);
1564 buf.beginTable(0);
1565 for (int i = 0; i < klasses.length; i++) {
1566 InstanceKlass ik = klasses[i];
1567 buf.beginTag("tr");
1568 buf.cell(genKlassLink(ik));
1569 buf.endTag("tr");
1570 }
1571
1572 buf.endTable();
1573 return buf.toString();
1574 }
1575
1576 public String genHTMLForMethodNames(InstanceKlass klass) {
1577 try {
1578 Formatter buf = new Formatter(genHTML);
1579 buf.genHTMLPrologue();
1580 buf.append(genHTMLListForMethods(klass));
1581 buf.genHTMLEpilogue();
1582 return buf.toString();
1583 } catch (Exception exp) {
1584 return genHTMLErrorMessage(exp);
1585 }
1586 }
1587
1588 protected String genHTMLListForMethods(InstanceKlass klass) {
1589 Formatter buf = new Formatter(genHTML);
1590 ObjArray methods = klass.getMethods();
1591 int numMethods = (int) methods.getLength();
1592 if (numMethods != 0) {
1593 buf.h3("Methods");
1594 buf.beginTag("ul");
1595 for (int m = 0; m < numMethods; m++) {
1596 Method mtd = (Method) methods.getObjAt(m);
1597 buf.li(genMethodLink(mtd) + ";");
1598 }
1599 buf.endTag("ul");
1600 }
1601 return buf.toString();
1602 }
1603
1604 protected String genHTMLListForInterfaces(InstanceKlass klass) {
1605 try {
1606 Formatter buf = new Formatter(genHTML);
1607 ObjArray interfaces = klass.getLocalInterfaces();
1608 int numInterfaces = (int) interfaces.getLength();
1609 if (numInterfaces != 0) {
1610 buf.h3("Interfaces");
1611 buf.beginTag("ul");
1612 for (int i = 0; i < numInterfaces; i++) {
1613 InstanceKlass inf = (InstanceKlass) interfaces.getObjAt(i);
1614 buf.li(genKlassLink(inf));
1615 }
1616 buf.endTag("ul");
1617 }
1618 return buf.toString();
1619 } catch (Exception exp) {
1620 return genHTMLErrorMessage(exp);
1621 }
1622 }
1623
1624 protected String genFieldModifierString(AccessFlags acc) {
1625 Formatter buf = new Formatter(genHTML);
1626 if (acc.isPrivate()) {
1627 buf.append("private ");
1628 } else if (acc.isProtected()) {
1629 buf.append("protected ");
1630 } else if (acc.isPublic()) {
1631 buf.append("public ");
1632 }
1633
1634 if (acc.isStatic()) {
1635 buf.append("static ");
1636 }
1637
1638 if (acc.isFinal()) {
1639 buf.append("final ");
1640 }
1641 if (acc.isVolatile()) {
1642 buf.append("volatile ");
1643 }
1644 if (acc.isTransient()) {
1645 buf.append("transient ");
1646 }
1647
1648 // javac generated flags
1649 if (acc.isSynthetic()) {
1650 buf.append("[synthetic] ");
1651 }
1652 return buf.toString();
1653 }
1654
1655 public String genHTMLForFieldNames(InstanceKlass klass) {
1656 try {
1657 Formatter buf = new Formatter(genHTML);
1658 buf.genHTMLPrologue();
1659 buf.append(genHTMLListForFields(klass));
1660 buf.genHTMLEpilogue();
1661 return buf.toString();
1662 } catch (Exception exp) {
1663 return genHTMLErrorMessage(exp);
1664 }
1665 }
1666
1667 protected String genHTMLListForFields(InstanceKlass klass) {
1668 Formatter buf = new Formatter(genHTML);
1669 TypeArray fields = klass.getFields();
1670 int numFields = (int) fields.getLength();
1671 ConstantPool cp = klass.getConstants();
1672 if (numFields != 0) {
1673 buf.h3("Fields");
1674 buf.beginList();
1675 for (int f = 0; f < numFields; f += InstanceKlass.NEXT_OFFSET) {
1676 int nameIndex = fields.getShortAt(f + InstanceKlass.NAME_INDEX_OFFSET);
1677 int sigIndex = fields.getShortAt(f + InstanceKlass.SIGNATURE_INDEX_OFFSET);
1678 int genSigIndex = fields.getShortAt(f + InstanceKlass.GENERIC_SIGNATURE_INDEX_OFFSET);
1679 Symbol f_name = cp.getSymbolAt(nameIndex);
1680 Symbol f_sig = cp.getSymbolAt(sigIndex);
1681 Symbol f_genSig = (genSigIndex != 0)? cp.getSymbolAt(genSigIndex) : null;
1682 AccessFlags acc = new AccessFlags(fields.getShortAt(f + InstanceKlass.ACCESS_FLAGS_OFFSET));
1683
1684 buf.beginTag("li");
1685 buf.append(genFieldModifierString(acc));
1686 buf.append(' ');
1687 Formatter sigBuf = new Formatter(genHTML);
1688 new SignatureConverter(f_sig, sigBuf.getBuffer()).dispatchField();
1689 buf.append(sigBuf.toString().replace('/', '.'));
1690 buf.append(' ');
1691 buf.append(f_name.asString());
1692 buf.append(';');
1693 // is it generic?
1694 if (f_genSig != null) {
1695 buf.append(" [signature ");
1696 buf.append(escapeHTMLSpecialChars(f_genSig.asString()));
1697 buf.append("] ");
1698 }
1699 buf.endTag("li");
1700 }
1701 buf.endList();
1702 }
1703 return buf.toString();
1704 }
1705
1706 protected String genKlassHierarchyHref(InstanceKlass klass) {
1707 return genBaseHref() + "hierarchy=" + klass.getHandle();
1708 }
1709
1710 protected String genKlassHierarchyTitle(InstanceKlass klass) {
1711 Formatter buf = new Formatter(genHTML);
1712 buf.append("Class Hierarchy of ");
1713 buf.append(genKlassTitle(klass));
1714 return buf.toString();
1715 }
1716
1717 protected String genKlassHierarchyLink(InstanceKlass klass) {
1718 Formatter buf = new Formatter(genHTML);
1719 buf.link(genKlassHierarchyHref(klass), genKlassHierarchyTitle(klass));
1720 return buf.toString();
1721 }
1722
1723 protected String genHTMLListForSubKlasses(InstanceKlass klass) {
1724 Formatter buf = new Formatter(genHTML);
1725 Klass subklass = klass.getSubklassKlass();
1726 if (subklass != null) {
1727 buf.beginList();
1728 while (subklass != null) {
1729 if (subklass instanceof InstanceKlass) {
1730 buf.li(genKlassLink((InstanceKlass)subklass));
1731 }
1732 subklass = subklass.getNextSiblingKlass();
1733 }
1734 buf.endList();
1735 }
1736 return buf.toString();
1737 }
1738
1739 public String genHTMLForKlassHierarchy(InstanceKlass klass) {
1740 Formatter buf = new Formatter(genHTML);
1741 buf.genHTMLPrologue(genKlassHierarchyTitle(klass));
1742
1743
1744 buf.beginTag("pre");
1745 buf.append(genKlassLink(klass));
1746 buf.br();
1747 StringBuffer tabs = new StringBuffer(tab);
1748 InstanceKlass superKlass = klass;
1749 while ( (superKlass = (InstanceKlass) superKlass.getSuper()) != null ) {
1750 buf.append(tabs);
1751 buf.append(genKlassLink(superKlass));
1752 tabs.append(tab);
1753 buf.br();
1754 }
1755 buf.endTag("pre");
1756
1757 // generate subklass list
1758 Klass subklass = klass.getSubklassKlass();
1759 if (subklass != null) {
1760 buf.h3("Direct Subclasses");
1761 buf.append(genHTMLListForSubKlasses(klass));
1762 }
1763
1764 buf.genHTMLEpilogue();
1765 return buf.toString();
1766 }
1767
1768 protected String genDumpKlassHref(InstanceKlass klass) {
1769 return genBaseHref() + "jcore=" + klass.getHandle();
1770 }
1771
1772 protected String genDumpKlassLink(InstanceKlass klass) {
1773 if (!genHTML) return "";
1774
1775 Formatter buf = new Formatter(genHTML);
1776 buf.link(genDumpKlassHref(klass), "Create .class File");
1777 return buf.toString();
1778 }
1779
1780 public String genHTML(InstanceKlass klass) {
1781 Formatter buf = new Formatter(genHTML);
1782 buf.genHTMLPrologue(genKlassTitle(klass));
1783 InstanceKlass superKlass = (InstanceKlass) klass.getSuper();
1784
1785 if (genHTML) {
1786 // super class tree and subclass list
1787 buf.beginTag("h3");
1788 buf.link(genKlassHierarchyHref(klass), "View Class Hierarchy");
1789 buf.endTag("h3");
1790 }
1791
1792 // jcore - create .class link
1793 buf.h3(genDumpKlassLink(klass));
1794
1795 // super class
1796 if (superKlass != null) {
1797 buf.h3("Super Class");
1798 buf.append(genKlassLink(superKlass));
1799 }
1800
1801 // interfaces
1802 buf.append(genHTMLListForInterfaces(klass));
1803
1804 // fields
1805 buf.append(genHTMLListForFields(klass));
1806
1807 // methods
1808 buf.append(genHTMLListForMethods(klass));
1809
1810 // constant pool link
1811 buf.h3("Constant Pool");
1812 buf.append(genConstantPoolLink(klass.getConstants()));
1813
1814 buf.genHTMLEpilogue();
1815 return buf.toString();
1816 }
1817
1818 protected sun.jvm.hotspot.debugger.Address parseAddress(String address) {
1819 VM vm = VM.getVM();
1820 sun.jvm.hotspot.debugger.Address addr = vm.getDebugger().parseAddress(address);
1821 return addr;
1822 }
1823
1824 protected long addressToLong(sun.jvm.hotspot.debugger.Address addr) {
1825 return VM.getVM().getDebugger().getAddressValue(addr);
1826 }
1827
1828 protected sun.jvm.hotspot.debugger.Address longToAddress(long addr) {
1829 return parseAddress("0x" + Long.toHexString(addr));
1830 }
1831
1832 protected Oop getOopAtAddress(sun.jvm.hotspot.debugger.Address addr) {
1833 OopHandle oopHandle = addr.addOffsetToAsOopHandle(0);
1834 return VM.getVM().getObjectHeap().newOop(oopHandle);
1835 }
1836
1837 protected Oop getOopAtAddress(String address) {
1838 sun.jvm.hotspot.debugger.Address addr = parseAddress(address);
1839 return getOopAtAddress(addr);
1840 }
1841
1842 private void dumpKlass(InstanceKlass kls) throws IOException {
1843 String klassName = kls.getName().asString();
1844 klassName = klassName.replace('/', File.separatorChar);
1845 int index = klassName.lastIndexOf(File.separatorChar);
1846 File dir = null;
1847 if (index != -1) {
1848 String dirName = klassName.substring(0, index);
1849 dir = new File(DUMP_KLASS_OUTPUT_DIR, dirName);
1850 } else {
1851 dir = new File(DUMP_KLASS_OUTPUT_DIR);
1852 }
1853
1854 dir.mkdirs();
1855 File f = new File(dir, klassName.substring(klassName.lastIndexOf(File.separatorChar) + 1)
1856 + ".class");
1857 f.createNewFile();
1858 FileOutputStream fis = new FileOutputStream(f);
1859 ClassWriter cw = new ClassWriter(kls, fis);
1860 cw.write();
1861 }
1862
1863 public String genDumpKlass(InstanceKlass kls) {
1864 try {
1865 dumpKlass(kls);
1866 Formatter buf = new Formatter(genHTML);
1867 buf.genHTMLPrologue(genKlassTitle(kls));
1868 buf.append(".class created for ");
1869 buf.append(genKlassLink(kls));
1870 buf.genHTMLEpilogue();
1871 return buf.toString();
1872 } catch(IOException exp) {
1873 return genHTMLErrorMessage(exp);
1874 }
1875 }
1876
1877 protected String genJavaStackTraceTitle(JavaThread thread) {
1878 Formatter buf = new Formatter(genHTML);
1879 buf.append("Java Stack Trace for ");
1880 buf.append(thread.getThreadName());
1881 return buf.toString();
1882 }
1883
1884 public String genHTMLForJavaStackTrace(JavaThread thread) {
1885 Formatter buf = new Formatter(genHTML);
1886 buf.genHTMLPrologue(genJavaStackTraceTitle(thread));
1887
1888 buf.append("Thread state = ");
1889 buf.append(thread.getThreadState().toString());
1890 buf.br();
1891 buf.beginTag("pre");
1892 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
1893 Method method = vf.getMethod();
1894 buf.append(" - ");
1895 buf.append(genMethodLink(method));
1896 buf.append(" @bci = " + vf.getBCI());
1897
1898 int lineNumber = method.getLineNumberFromBCI(vf.getBCI());
1899 if (lineNumber != -1) {
1900 buf.append(", line = ");
1901 buf.append(lineNumber);
1902 }
1903
1904 sun.jvm.hotspot.debugger.Address pc = vf.getFrame().getPC();
1905 if (pc != null) {
1906 buf.append(", pc = ");
1907 buf.link(genPCHref(addressToLong(pc)), pc.toString());
1908 }
1909
1910 if (vf.isCompiledFrame()) {
1911 buf.append(" (Compiled");
1912 }
1913 else if (vf.isInterpretedFrame()) {
1914 buf.append(" (Interpreted");
1915 }
1916
1917 if (vf.mayBeImpreciseDbg()) {
1918 buf.append("; information may be imprecise");
1919 }
1920 buf.append(")");
1921 buf.br();
1922 }
1923
1924 buf.endTag("pre");
1925 buf.genHTMLEpilogue();
1926 return buf.toString();
1927 }
1928
1929 public String genHTMLForHyperlink(String href) {
1930 if (href.startsWith("klass=")) {
1931 href = href.substring(href.indexOf('=') + 1);
1932 Oop obj = getOopAtAddress(href);
1933 if (Assert.ASSERTS_ENABLED) {
1934 Assert.that(obj instanceof InstanceKlass, "class= href with improper InstanceKlass!");
1935 }
1936 return genHTML((InstanceKlass) obj);
1937 } else if (href.startsWith("method=")) {
1938 href = href.substring(href.indexOf('=') + 1);
1939 Oop obj = getOopAtAddress(href);
1940 if (Assert.ASSERTS_ENABLED) {
1941 Assert.that(obj instanceof Method, "method= href with improper Method!");
1942 }
1943 return genHTML((Method) obj);
1944 } else if (href.startsWith("nmethod=")) {
1945 String addr = href.substring(href.indexOf('=') + 1);
1946 Object obj = VMObjectFactory.newObject(NMethod.class, parseAddress(addr));
1947 if (Assert.ASSERTS_ENABLED) {
1948 Assert.that(obj instanceof NMethod, "nmethod= href with improper NMethod!");
1949 }
1950 return genHTML((NMethod) obj);
1951 } else if (href.startsWith("pc=")) {
1952 String address = href.substring(href.indexOf('=') + 1);
1953 return genHTML(parseAddress(address));
1954 } else if (href.startsWith("pc_multiple=")) {
1955 int indexOfComma = href.indexOf(',');
1956 if (indexOfComma == -1) {
1957 String firstPC = href.substring(href.indexOf('=') + 1);
1958 return genHTMLForRawDisassembly(parseAddress(firstPC), null);
1959 } else {
1960 String firstPC = href.substring(href.indexOf('=') + 1, indexOfComma);
1961 return genHTMLForRawDisassembly(parseAddress(firstPC), href.substring(indexOfComma + 1));
1962 }
1963 } else if (href.startsWith("interp_codelets")) {
1964 return genInterpreterCodeletLinksPage();
1965 } else if (href.startsWith("hierarchy=")) {
1966 href = href.substring(href.indexOf('=') + 1);
1967 Oop obj = getOopAtAddress(href);
1968 if (Assert.ASSERTS_ENABLED) {
1969 Assert.that(obj instanceof InstanceKlass, "class= href with improper InstanceKlass!");
1970 }
1971 return genHTMLForKlassHierarchy((InstanceKlass) obj);
1972 } else if (href.startsWith("cpool=")) {
1973 href = href.substring(href.indexOf('=') + 1);
1974 Oop obj = getOopAtAddress(href);
1975 if (Assert.ASSERTS_ENABLED) {
1976 Assert.that(obj instanceof ConstantPool, "cpool= href with improper ConstantPool!");
1977 }
1978 return genHTML((ConstantPool) obj);
1979 } else if (href.startsWith("jcore=")) {
1980 href = href.substring(href.indexOf('=') + 1);
1981 Oop obj = getOopAtAddress(href);
1982 if (Assert.ASSERTS_ENABLED) {
1983 Assert.that(obj instanceof InstanceKlass, "jcore= href with improper InstanceKlass!");
1984 }
1985 return genDumpKlass((InstanceKlass) obj);
1986 } else if (href.startsWith("jcore_multiple=")) {
1987 href = href.substring(href.indexOf('=') + 1);
1988 Formatter buf = new Formatter(genHTML);
1989 buf.genHTMLPrologue();
1990 StringTokenizer st = new StringTokenizer(href, ",");
1991 while (st.hasMoreTokens()) {
1992 Oop obj = getOopAtAddress(st.nextToken());
1993 if (Assert.ASSERTS_ENABLED) {
1994 Assert.that(obj instanceof InstanceKlass, "jcore_multiple= href with improper InstanceKlass!");
1995 }
1996
1997 InstanceKlass kls = (InstanceKlass) obj;
1998 try {
1999 dumpKlass(kls);
2000 buf.append(".class created for ");
2001 buf.append(genKlassLink(kls));
2002 } catch(Exception exp) {
2003 buf.bold("can't .class for " +
2004 genKlassTitle(kls) +
2005 " : " +
2006 exp.getMessage());
2007 }
2008 buf.br();
2009 }
2010
2011 buf.genHTMLEpilogue();
2012 return buf.toString();
2013 } else {
2014 if (Assert.ASSERTS_ENABLED) {
2015 Assert.that(false, "unknown href link!");
2016 }
2017 return null;
2018 }
2019 }
2020 }