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