0
|
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 }
|