Mercurial > hg > truffle
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 = " "; | |
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.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 } |