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 protected byte[] readBuffer(sun.jvm.hotspot.debugger.Address addr, int size) { 807 byte[] buf = new byte[size]; 808 for (int b = 0; b < size; b++) { 809 buf[b] = (byte) addr.getJByteAt(b); 810 } 811 return buf; 812 } 813 814 public String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address startPc, int size) { 815 try { 816 return genHTMLForRawDisassembly(startPc, null, readBuffer(startPc, size)); 817 } catch (Exception exp) { 818 return genHTMLErrorMessage(exp); 819 } 820 } 821 822 protected String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address startPc, 823 String prevPCs) { 824 try { 825 return genHTMLForRawDisassembly(startPc, prevPCs, readBuffer(startPc, NATIVE_CODE_SIZE)); 826 } catch (Exception exp) { 827 return genHTMLErrorMessage(exp); 828 } 829 } 830 831 protected String genPCHref(long targetPc) { 832 return genBaseHref() + "pc=0x" + Long.toHexString(targetPc); 833 } 834 835 protected String genMultPCHref(String pcs) { 836 StringBuffer buf = new StringBuffer(genBaseHref()); 837 buf.append("pc_multiple="); 838 buf.append(pcs); 839 return buf.toString(); 840 } 841 842 protected String genPCHref(Address addr) { 843 return genPCHref(addressToLong(addr)); 844 } 845 846 class HTMLDisassembler implements InstructionVisitor { 847 private int instrSize = 0; 848 private Formatter buf; 849 private SymbolFinder symFinder = createSymbolFinder(); 850 private long pc; 851 private OopMapSet oms; 852 private CodeBlob blob; 853 private NMethod nmethod; 854 855 HTMLDisassembler(Formatter buf, CodeBlob blob) { 856 this.buf = buf; 857 this.blob = blob; 858 if (blob != null) { 859 if (blob instanceof NMethod) { 860 nmethod = (NMethod)blob; 861 } 862 oms = blob.getOopMaps(); 863 } 864 } 865 866 public int getInstructionSize() { 867 return instrSize; 868 } 869 870 public void prologue() { 871 } 872 873 public void beginInstruction(long currentPc) { 874 pc = currentPc; 875 876 if (nmethod != null) { 877 if (pc == addressToLong(nmethod.getEntryPoint())) print("[Entry Point]\n"); 878 if (pc == addressToLong(nmethod.getVerifiedEntryPoint())) print("[Verified Entry Point]\n"); 879 if (pc == addressToLong(nmethod.exceptionBegin())) print("[Exception Handler]\n"); 880 if (pc == addressToLong(nmethod.stubBegin())) print("[Stub Code]\n"); 881 // if (p == addressToLong(nmethod.getConstsBegin())) print("[Constants]\n"); 882 } 883 884 buf.append("0x"); 885 buf.append(Long.toHexString(currentPc)); 886 buf.append(':'); 887 buf.append(tab); 888 } 889 890 public void printAddress(long address) { 891 Address addr = longToAddress(address); 892 if (VM.getVM().getCodeCache().contains(addr)) { 893 buf.link(genPCHref(address), addr.toString()); 894 } else { 895 buf.append(addr.toString()); 896 } 897 } 898 899 public void print(String s) { 900 buf.append(s); 901 } 902 903 public void endInstruction(long endPc) { 904 instrSize += endPc - pc; 905 if (genHTML) buf.br(); 906 907 if (nmethod != null) { 908 ScopeDesc sd = nmethod.scope_desc_in(pc, endPc); 909 if (sd != null) { 910 buf.br(); 911 buf.append(genSafepointInfo(nmethod, sd)); 912 } 913 } 914 915 if (oms != null) { 916 long base = addressToLong(nmethod.instructionsBegin()); 917 for (int i = 0, imax = (int)oms.getSize(); i < imax; i++) { 918 OopMap om = oms.getMapAt(i); 919 long omspc = base + om.getOffset(); 920 if (omspc > pc) { 921 if (omspc <= endPc) { 922 buf.br(); 923 buf.append(genOopMapInfo(om)); 924 // st.move_to(column); 925 // visitor.print("; "); 926 // om.print_on(st); 927 } 928 break; 929 } 930 } 931 } 932 } 933 934 public void epilogue() { 935 } 936 }; 937 938 protected String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address addr, 939 String prevPCs, 940 byte[] code) { 941 try { 942 final Formatter buf = new Formatter(genHTML); 943 buf.genHTMLPrologue("Disassembly @ " + addr); 944 945 if (prevPCs != null && genHTML) { 946 buf.beginTag("p"); 947 buf.link(genMultPCHref(prevPCs), "show previous code .."); 948 buf.endTag("p"); 949 } 950 951 952 buf.h3("Code"); 953 HTMLDisassembler visitor = new HTMLDisassembler(buf, null); 954 Disassembler.decode(visitor, null, addr, addr.addOffsetTo(code.length)); 955 956 if (genHTML) buf.beginTag("p"); 957 Formatter tmpBuf = new Formatter(genHTML); 958 long startPc = addressToLong(addr); 959 tmpBuf.append("0x"); 960 tmpBuf.append(Long.toHexString(startPc + visitor.getInstructionSize()).toString()); 961 tmpBuf.append(",0x"); 962 tmpBuf.append(Long.toHexString(startPc)); 963 if (prevPCs != null) { 964 tmpBuf.append(','); 965 tmpBuf.append(prevPCs); 966 } 967 if (genHTML) { 968 buf.link(genMultPCHref(tmpBuf.toString()), "show more code .."); 969 buf.endTag("p"); 970 } 971 972 buf.genHTMLEpilogue(); 973 return buf.toString(); 974 } catch (Exception exp) { 975 return genHTMLErrorMessage(exp); 976 } 977 } 978 979 protected String genSafepointInfo(NMethod nm, ScopeDesc sd) { 980 Formatter buf = new Formatter(genHTML); 981 Formatter tabs = new Formatter(genHTML); 982 983 buf.beginTag("pre"); 984 genScope(buf, tabs, sd); 985 buf.endTag("pre"); 986 987 return buf.toString(); 988 } 989 990 protected void genScope(Formatter buf, Formatter tabs, ScopeDesc sd) { 991 if (sd == null) { 992 return; 993 } 994 995 genScope(buf, tabs, sd.sender()); 996 997 buf.append(tabs); 998 Method m = sd.getMethod(); 999 buf.append(genMethodAndKlassLink(m)); 1000 int bci = sd.getBCI(); 1001 buf.append(" @ bci = "); 1002 buf.append(Integer.toString(bci)); 1003 1004 int line = m.getLineNumberFromBCI(bci); 1005 if (line != -1) { 1006 buf.append(", line = "); 1007 buf.append(Integer.toString(line)); 1008 } 1009 1010 List locals = sd.getLocals(); 1011 if (locals != null) { 1012 buf.br(); 1013 buf.append(tabs); 1014 buf.append(genHTMLForLocals(sd, locals)); 1015 } 1016 1017 List expressions = sd.getExpressions(); 1018 if (expressions != null) { 1019 buf.br(); 1020 buf.append(tabs); 1021 buf.append(genHTMLForExpressions(sd, expressions)); 1022 } 1023 1024 List monitors = sd.getMonitors(); 1025 if (monitors != null) { 1026 buf.br(); 1027 buf.append(tabs); 1028 buf.append(genHTMLForMonitors(sd, monitors)); 1029 } 1030 1031 tabs.append(tab); 1032 buf.br(); 1033 } 1034 1035 protected String genHTMLForOopMap(OopMap map) { 1036 final int stack0 = VMRegImpl.getStack0().getValue(); 1037 Formatter buf = new Formatter(genHTML); 1038 1039 final class OopMapValueIterator { 1040 final Formatter iterate(OopMapStream oms, String type, boolean printContentReg) { 1041 Formatter tmpBuf = new Formatter(genHTML); 1042 boolean found = false; 1043 tmpBuf.beginTag("tr"); 1044 tmpBuf.beginTag("td"); 1045 tmpBuf.append(type); 1046 tmpBuf.endTag("td"); 1047 tmpBuf.endTag("tr"); 1048 for (; ! oms.isDone(); oms.next()) { 1049 OopMapValue omv = oms.getCurrent(); 1050 if (omv == null) { 1051 continue; 1052 } 1053 found = true; 1054 VMReg vmReg = omv.getReg(); 1055 int reg = vmReg.getValue(); 1056 if (reg < stack0) { 1057 tmpBuf.append(VMRegImpl.getRegisterName(vmReg.getValue())); 1058 } else { 1059 tmpBuf.append('['); 1060 tmpBuf.append(Integer.toString((reg - stack0) * 4)); 1061 tmpBuf.append(']'); 1062 } 1063 if (printContentReg) { 1064 tmpBuf.append(" = "); 1065 VMReg vmContentReg = omv.getContentReg(); 1066 int contentReg = vmContentReg.getValue(); 1067 tmpBuf.append(VMRegImpl.getRegisterName(vmContentReg.getValue())); 1068 } 1069 tmpBuf.append(spaces); 1070 } 1071 tmpBuf.endTag("td"); 1072 tmpBuf.endTag("tr"); 1073 return found ? tmpBuf : new Formatter(genHTML); 1074 } 1075 } 1076 1077 buf.beginTable(0); 1078 1079 OopMapValueIterator omvIterator = new OopMapValueIterator(); 1080 OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.OOP_VALUE); 1081 buf.append(omvIterator.iterate(oms, "Oop:", false)); 1082 1083 oms = new OopMapStream(map, OopMapValue.OopTypes.VALUE_VALUE); 1084 buf.append(omvIterator.iterate(oms, "Value:", false)); 1085 1086 oms = new OopMapStream(map, OopMapValue.OopTypes.NARROWOOP_VALUE); 1087 buf.append(omvIterator.iterate(oms, "NarrowOop:", false)); 1088 1089 oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); 1090 buf.append(omvIterator.iterate(oms, "Callee saved:", true)); 1091 1092 oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE); 1093 buf.append(omvIterator.iterate(oms, "Derived oop:", true)); 1094 1095 buf.endTag("table"); 1096 return buf.toString(); 1097 } 1098 1099 1100 protected String genOopMapInfo(NMethod nmethod, PCDesc pcDesc) { 1101 OopMapSet mapSet = nmethod.getOopMaps(); 1102 int pcOffset = pcDesc.getPCOffset(); 1103 OopMap map = mapSet.findMapAtOffset(pcOffset, VM.getVM().isDebugging()); 1104 if (map == null) { 1105 throw new IllegalArgumentException("no oopmap at safepoint!"); 1106 } 1107 1108 return genOopMapInfo(map); 1109 } 1110 1111 protected String genOopMapInfo(OopMap map) { 1112 Formatter buf = new Formatter(genHTML); 1113 buf.beginTag("pre"); 1114 buf.append("OopMap: "); 1115 buf.append(genHTMLForOopMap(map)); 1116 buf.endTag("pre"); 1117 1118 return buf.toString(); 1119 } 1120 1121 protected String locationAsString(Location loc) { 1122 Formatter buf = new Formatter(genHTML); 1123 if (loc.isIllegal()) { 1124 buf.append("illegal"); 1125 } else { 1126 Location.Where w = loc.getWhere(); 1127 Location.Type type = loc.getType(); 1128 1129 if (w == Location.Where.ON_STACK) { 1130 buf.append("stack[" + loc.getStackOffset() + "]"); 1131 } else if (w == Location.Where.IN_REGISTER) { 1132 boolean isFloat = (type == Location.Type.FLOAT_IN_DBL || 1133 type == Location.Type.DBL); 1134 int regNum = loc.getRegisterNumber(); 1135 VMReg vmReg = new VMReg(regNum); 1136 buf.append(VMRegImpl.getRegisterName(vmReg.getValue())); 1137 } 1138 1139 buf.append(", "); 1140 if (type == Location.Type.NORMAL) { 1141 buf.append("normal"); 1142 } else if (type == Location.Type.OOP) { 1143 buf.append("oop"); 1144 } else if (type == Location.Type.NARROWOOP) { 1145 buf.append("narrowoop"); 1146 } else if (type == Location.Type.INT_IN_LONG) { 1147 buf.append("int"); 1148 } else if (type == Location.Type.LNG) { 1149 buf.append("long"); 1150 } else if (type == Location.Type.FLOAT_IN_DBL) { 1151 buf.append("float"); 1152 } else if (type == Location.Type.DBL) { 1153 buf.append("double"); 1154 } else if (type == Location.Type.ADDR) { 1155 buf.append("address"); 1156 } else if (type == Location.Type.INVALID) { 1157 buf.append("invalid"); 1158 } 1159 } 1160 return buf.toString(); 1161 } 1162 1163 private String scopeValueAsString(ScopeValue sv) { 1164 Formatter buf = new Formatter(genHTML); 1165 if (sv.isConstantInt()) { 1166 buf.append("int "); 1167 ConstantIntValue intValue = (ConstantIntValue) sv; 1168 buf.append(Integer.toString(intValue.getValue())); 1169 } else if (sv.isConstantLong()) { 1170 buf.append("long "); 1171 ConstantLongValue longValue = (ConstantLongValue) sv; 1172 buf.append(Long.toString(longValue.getValue())); 1173 buf.append("L"); 1174 } else if (sv.isConstantDouble()) { 1175 buf.append("double "); 1176 ConstantDoubleValue dblValue = (ConstantDoubleValue) sv; 1177 buf.append(Double.toString(dblValue.getValue())); 1178 buf.append("D"); 1179 } else if (sv.isConstantOop()) { 1180 buf.append("oop "); 1181 ConstantOopReadValue oopValue = (ConstantOopReadValue) sv; 1182 OopHandle oopHandle = oopValue.getValue(); 1183 if (oopHandle != null) { 1184 buf.append(oopHandle.toString()); 1185 } else { 1186 buf.append("null"); 1187 } 1188 } else if (sv.isLocation()) { 1189 LocationValue lvalue = (LocationValue) sv; 1190 Location loc = lvalue.getLocation(); 1191 if (loc != null) { 1192 buf.append(locationAsString(loc)); 1193 } else { 1194 buf.append("null"); 1195 } 1196 } 1197 return buf.toString(); 1198 } 1199 1200 protected String genHTMLForScopeValues(ScopeDesc sd, boolean locals, List values) { 1201 int length = values.size(); 1202 Formatter buf = new Formatter(genHTML); 1203 buf.append(locals? "locals " : "expressions "); 1204 for (int i = 0; i < length; i++) { 1205 ScopeValue sv = (ScopeValue) values.get(i); 1206 if (sv == null) { 1207 continue; 1208 } 1209 buf.append('('); 1210 if (locals) { 1211 Symbol name = sd.getMethod().getLocalVariableName(sd.getBCI(), i); 1212 if (name != null) { 1213 buf.append("'"); 1214 buf.append(name.asString()); 1215 buf.append('\''); 1216 } else { 1217 buf.append("["); 1218 buf.append(Integer.toString(i)); 1219 buf.append(']'); 1220 } 1221 } else { 1222 buf.append("["); 1223 buf.append(Integer.toString(i)); 1224 buf.append(']'); 1225 } 1226 1227 buf.append(", "); 1228 buf.append(scopeValueAsString(sv)); 1229 buf.append(") "); 1230 } 1231 1232 return buf.toString(); 1233 } 1234 1235 protected String genHTMLForLocals(ScopeDesc sd, List locals) { 1236 return genHTMLForScopeValues(sd, true, locals); 1237 } 1238 1239 protected String genHTMLForExpressions(ScopeDesc sd, List expressions) { 1240 return genHTMLForScopeValues(sd, false, expressions); 1241 } 1242 1243 protected String genHTMLForMonitors(ScopeDesc sd, List monitors) { 1244 int length = monitors.size(); 1245 Formatter buf = new Formatter(genHTML); 1246 buf.append("monitors "); 1247 for (int i = 0; i < length; i++) { 1248 MonitorValue mv = (MonitorValue) monitors.get(i); 1249 if (mv == null) { 1250 continue; 1251 } 1252 buf.append("(owner = "); 1253 ScopeValue owner = mv.owner(); 1254 if (owner != null) { 1255 buf.append(scopeValueAsString(owner)); 1256 } else { 1257 buf.append("null"); 1258 } 1259 buf.append(", lock = "); 1260 1261 Location loc = mv.basicLock(); 1262 if (loc != null) { 1263 buf.append(locationAsString(loc)); 1264 } else { 1265 buf.append("null"); 1266 } 1267 buf.append(") "); 1268 } 1269 return buf.toString(); 1270 } 1271 1272 public String genHTML(final NMethod nmethod) { 1273 try { 1274 final Formatter buf = new Formatter(genHTML); 1275 buf.genHTMLPrologue(genNMethodTitle(nmethod)); 1276 buf.h3("Method"); 1277 buf.append(genMethodAndKlassLink(nmethod.getMethod())); 1278 1279 buf.h3("Compiled Code"); 1280 Disassembler.decode(new HTMLDisassembler(buf, nmethod), nmethod); 1281 buf.genHTMLEpilogue(); 1282 return buf.toString(); 1283 } catch (Exception exp) { 1284 return genHTMLErrorMessage(exp); 1285 } 1286 } 1287 1288 public String genHTML(final CodeBlob blob) { 1289 try { 1290 final Formatter buf = new Formatter(genHTML); 1291 buf.genHTMLPrologue(genCodeBlobTitle(blob)); 1292 buf.h3("CodeBlob"); 1293 1294 buf.h3("Compiled Code"); 1295 Disassembler.decode(new HTMLDisassembler(buf, blob), blob); 1296 1297 buf.genHTMLEpilogue(); 1298 return buf.toString(); 1299 } catch (Exception exp) { 1300 return genHTMLErrorMessage(exp); 1301 } 1302 } 1303 1304 protected String genInterpreterCodeletTitle(InterpreterCodelet codelet) { 1305 Formatter buf = new Formatter(genHTML); 1306 buf.append("Interpreter codelet ["); 1307 buf.append(codelet.codeBegin().toString()); 1308 buf.append(','); 1309 buf.append(codelet.codeEnd().toString()); 1310 buf.append(") - "); 1311 buf.append(codelet.getDescription()); 1312 return buf.toString(); 1313 } 1314 1315 protected String genInterpreterCodeletLinkPageHref(StubQueue stubq) { 1316 return genBaseHref() + "interp_codelets"; 1317 } 1318 1319 public String genInterpreterCodeletLinksPage() { 1320 Formatter buf = new Formatter(genHTML); 1321 buf.genHTMLPrologue("Interpreter Codelets"); 1322 buf.beginTag("ul"); 1323 1324 Interpreter interp = VM.getVM().getInterpreter(); 1325 StubQueue code = interp.getCode(); 1326 InterpreterCodelet stub = (InterpreterCodelet) code.getFirst(); 1327 while (stub != null) { 1328 buf.beginTag("li"); 1329 sun.jvm.hotspot.debugger.Address addr = stub.codeBegin(); 1330 buf.link(genPCHref(addressToLong(addr)), stub.getDescription() + " @" + addr); 1331 buf.endTag("li"); 1332 stub = (InterpreterCodelet) code.getNext(stub); 1333 } 1334 1335 buf.endTag("ul"); 1336 buf.genHTMLEpilogue(); 1337 return buf.toString(); 1338 } 1339 1340 public String genHTML(InterpreterCodelet codelet) { 1341 Formatter buf = new Formatter(genHTML); 1342 buf.genHTMLPrologue(genInterpreterCodeletTitle(codelet)); 1343 Interpreter interp = VM.getVM().getInterpreter(); 1344 StubQueue stubq = interp.getCode(); 1345 1346 if (genHTML) { 1347 buf.beginTag("h3"); 1348 buf.link(genInterpreterCodeletLinkPageHref(stubq), "View links for all codelets"); 1349 buf.endTag("h3"); 1350 buf.br(); 1351 } 1352 1353 Stub prev = stubq.getPrev(codelet); 1354 if (prev != null) { 1355 if (genHTML) { 1356 buf.beginTag("h3"); 1357 buf.link(genPCHref(addressToLong(prev.codeBegin())), "View Previous Codelet"); 1358 buf.endTag("h3"); 1359 buf.br(); 1360 } else { 1361 buf.h3("Previous Codelet = 0x" + Long.toHexString(addressToLong(prev.codeBegin()))); 1362 } 1363 } 1364 1365 buf.h3("Code"); 1366 Disassembler.decode(new HTMLDisassembler(buf, null), null, 1367 codelet.codeBegin(), codelet.codeEnd()); 1368 1369 Stub next = stubq.getNext(codelet); 1370 if (next != null) { 1371 if (genHTML) { 1372 buf.beginTag("h3"); 1373 buf.link(genPCHref(addressToLong(next.codeBegin())), "View Next Codelet"); 1374 buf.endTag("h3"); 1375 } else { 1376 buf.h3("Next Codelet = 0x" + Long.toHexString(addressToLong(next.codeBegin()))); 1377 } 1378 } 1379 1380 buf.genHTMLEpilogue(); 1381 return buf.toString(); 1382 } 1383 1384 protected String genDumpKlassesTitle(InstanceKlass[] klasses) { 1385 return (klasses.length == 1) ? "Create .class for this class" 1386 : "Create .class for all classes"; 1387 } 1388 1389 protected String genDumpKlassesHref(InstanceKlass[] klasses) { 1390 StringBuffer buf = new StringBuffer(genBaseHref()); 1391 buf.append("jcore_multiple="); 1392 for (int k = 0; k < klasses.length; k++) { 1393 buf.append(klasses[k].getHandle().toString()); 1394 buf.append(','); 1395 } 1396 return buf.toString(); 1397 } 1398 1399 protected String genDumpKlassesLink(InstanceKlass[] klasses) { 1400 if (!genHTML) return ""; 1401 1402 Formatter buf = new Formatter(genHTML); 1403 buf.link(genDumpKlassesHref(klasses), genDumpKlassesTitle(klasses)); 1404 return buf.toString(); 1405 } 1406 1407 public String genHTMLForKlassNames(InstanceKlass[] klasses) { 1408 try { 1409 Formatter buf = new Formatter(genHTML); 1410 buf.genHTMLPrologue(); 1411 buf.h3(genDumpKlassesLink(klasses)); 1412 1413 buf.append(genHTMLListForKlassNames(klasses)); 1414 buf.genHTMLEpilogue(); 1415 return buf.toString(); 1416 } catch (Exception exp) { 1417 return genHTMLErrorMessage(exp); 1418 } 1419 } 1420 1421 protected String genHTMLListForKlassNames(InstanceKlass[] klasses) { 1422 final Formatter buf = new Formatter(genHTML); 1423 buf.beginTable(0); 1424 for (int i = 0; i < klasses.length; i++) { 1425 InstanceKlass ik = klasses[i]; 1426 buf.beginTag("tr"); 1427 buf.cell(genKlassLink(ik)); 1428 buf.endTag("tr"); 1429 } 1430 1431 buf.endTable(); 1432 return buf.toString(); 1433 } 1434 1435 public String genHTMLForMethodNames(InstanceKlass klass) { 1436 try { 1437 Formatter buf = new Formatter(genHTML); 1438 buf.genHTMLPrologue(); 1439 buf.append(genHTMLListForMethods(klass)); 1440 buf.genHTMLEpilogue(); 1441 return buf.toString(); 1442 } catch (Exception exp) { 1443 return genHTMLErrorMessage(exp); 1444 } 1445 } 1446 1447 protected String genHTMLListForMethods(InstanceKlass klass) { 1448 Formatter buf = new Formatter(genHTML); 1449 ObjArray methods = klass.getMethods(); 1450 int numMethods = (int) methods.getLength(); 1451 if (numMethods != 0) { 1452 buf.h3("Methods"); 1453 buf.beginTag("ul"); 1454 for (int m = 0; m < numMethods; m++) { 1455 Method mtd = (Method) methods.getObjAt(m); 1456 buf.li(genMethodLink(mtd) + ";"); 1457 } 1458 buf.endTag("ul"); 1459 } 1460 return buf.toString(); 1461 } 1462 1463 protected String genHTMLListForInterfaces(InstanceKlass klass) { 1464 try { 1465 Formatter buf = new Formatter(genHTML); 1466 ObjArray interfaces = klass.getLocalInterfaces(); 1467 int numInterfaces = (int) interfaces.getLength(); 1468 if (numInterfaces != 0) { 1469 buf.h3("Interfaces"); 1470 buf.beginTag("ul"); 1471 for (int i = 0; i < numInterfaces; i++) { 1472 InstanceKlass inf = (InstanceKlass) interfaces.getObjAt(i); 1473 buf.li(genKlassLink(inf)); 1474 } 1475 buf.endTag("ul"); 1476 } 1477 return buf.toString(); 1478 } catch (Exception exp) { 1479 return genHTMLErrorMessage(exp); 1480 } 1481 } 1482 1483 protected String genFieldModifierString(AccessFlags acc) { 1484 Formatter buf = new Formatter(genHTML); 1485 if (acc.isPrivate()) { 1486 buf.append("private "); 1487 } else if (acc.isProtected()) { 1488 buf.append("protected "); 1489 } else if (acc.isPublic()) { 1490 buf.append("public "); 1491 } 1492 1493 if (acc.isStatic()) { 1494 buf.append("static "); 1495 } 1496 1497 if (acc.isFinal()) { 1498 buf.append("final "); 1499 } 1500 if (acc.isVolatile()) { 1501 buf.append("volatile "); 1502 } 1503 if (acc.isTransient()) { 1504 buf.append("transient "); 1505 } 1506 1507 // javac generated flags 1508 if (acc.isSynthetic()) { 1509 buf.append("[synthetic] "); 1510 } 1511 return buf.toString(); 1512 } 1513 1514 public String genHTMLForFieldNames(InstanceKlass klass) { 1515 try { 1516 Formatter buf = new Formatter(genHTML); 1517 buf.genHTMLPrologue(); 1518 buf.append(genHTMLListForFields(klass)); 1519 buf.genHTMLEpilogue(); 1520 return buf.toString(); 1521 } catch (Exception exp) { 1522 return genHTMLErrorMessage(exp); 1523 } 1524 } 1525 1526 protected String genHTMLListForFields(InstanceKlass klass) { 1527 Formatter buf = new Formatter(genHTML); 1528 TypeArray fields = klass.getFields(); 1529 int numFields = (int) fields.getLength(); 1530 ConstantPool cp = klass.getConstants(); 1531 if (numFields != 0) { 1532 buf.h3("Fields"); 1533 buf.beginList(); 1534 for (int f = 0; f < numFields; f += InstanceKlass.NEXT_OFFSET) { 1535 int nameIndex = fields.getShortAt(f + InstanceKlass.NAME_INDEX_OFFSET); 1536 int sigIndex = fields.getShortAt(f + InstanceKlass.SIGNATURE_INDEX_OFFSET); 1537 int genSigIndex = fields.getShortAt(f + InstanceKlass.GENERIC_SIGNATURE_INDEX_OFFSET); 1538 Symbol f_name = cp.getSymbolAt(nameIndex); 1539 Symbol f_sig = cp.getSymbolAt(sigIndex); 1540 Symbol f_genSig = (genSigIndex != 0)? cp.getSymbolAt(genSigIndex) : null; 1541 AccessFlags acc = new AccessFlags(fields.getShortAt(f + InstanceKlass.ACCESS_FLAGS_OFFSET)); 1542 1543 buf.beginTag("li"); 1544 buf.append(genFieldModifierString(acc)); 1545 buf.append(' '); 1546 Formatter sigBuf = new Formatter(genHTML); 1547 new SignatureConverter(f_sig, sigBuf.getBuffer()).dispatchField(); 1548 buf.append(sigBuf.toString().replace('/', '.')); 1549 buf.append(' '); 1550 buf.append(f_name.asString()); 1551 buf.append(';'); 1552 // is it generic? 1553 if (f_genSig != null) { 1554 buf.append(" [signature "); 1555 buf.append(escapeHTMLSpecialChars(f_genSig.asString())); 1556 buf.append("] "); 1557 } 1558 buf.endTag("li"); 1559 } 1560 buf.endList(); 1561 } 1562 return buf.toString(); 1563 } 1564 1565 protected String genKlassHierarchyHref(InstanceKlass klass) { 1566 return genBaseHref() + "hierarchy=" + klass.getHandle(); 1567 } 1568 1569 protected String genKlassHierarchyTitle(InstanceKlass klass) { 1570 Formatter buf = new Formatter(genHTML); 1571 buf.append("Class Hierarchy of "); 1572 buf.append(genKlassTitle(klass)); 1573 return buf.toString(); 1574 } 1575 1576 protected String genKlassHierarchyLink(InstanceKlass klass) { 1577 Formatter buf = new Formatter(genHTML); 1578 buf.link(genKlassHierarchyHref(klass), genKlassHierarchyTitle(klass)); 1579 return buf.toString(); 1580 } 1581 1582 protected String genHTMLListForSubKlasses(InstanceKlass klass) { 1583 Formatter buf = new Formatter(genHTML); 1584 Klass subklass = klass.getSubklassKlass(); 1585 if (subklass != null) { 1586 buf.beginList(); 1587 while (subklass != null) { 1588 if (subklass instanceof InstanceKlass) { 1589 buf.li(genKlassLink((InstanceKlass)subklass)); 1590 } 1591 subklass = subklass.getNextSiblingKlass(); 1592 } 1593 buf.endList(); 1594 } 1595 return buf.toString(); 1596 } 1597 1598 public String genHTMLForKlassHierarchy(InstanceKlass klass) { 1599 Formatter buf = new Formatter(genHTML); 1600 buf.genHTMLPrologue(genKlassHierarchyTitle(klass)); 1601 1602 1603 buf.beginTag("pre"); 1604 buf.append(genKlassLink(klass)); 1605 buf.br(); 1606 StringBuffer tabs = new StringBuffer(tab); 1607 InstanceKlass superKlass = klass; 1608 while ( (superKlass = (InstanceKlass) superKlass.getSuper()) != null ) { 1609 buf.append(tabs); 1610 buf.append(genKlassLink(superKlass)); 1611 tabs.append(tab); 1612 buf.br(); 1613 } 1614 buf.endTag("pre"); 1615 1616 // generate subklass list 1617 Klass subklass = klass.getSubklassKlass(); 1618 if (subklass != null) { 1619 buf.h3("Direct Subclasses"); 1620 buf.append(genHTMLListForSubKlasses(klass)); 1621 } 1622 1623 buf.genHTMLEpilogue(); 1624 return buf.toString(); 1625 } 1626 1627 protected String genDumpKlassHref(InstanceKlass klass) { 1628 return genBaseHref() + "jcore=" + klass.getHandle(); 1629 } 1630 1631 protected String genDumpKlassLink(InstanceKlass klass) { 1632 if (!genHTML) return ""; 1633 1634 Formatter buf = new Formatter(genHTML); 1635 buf.link(genDumpKlassHref(klass), "Create .class File"); 1636 return buf.toString(); 1637 } 1638 1639 public String genHTML(InstanceKlass klass) { 1640 Formatter buf = new Formatter(genHTML); 1641 buf.genHTMLPrologue(genKlassTitle(klass)); 1642 InstanceKlass superKlass = (InstanceKlass) klass.getSuper(); 1643 1644 if (genHTML) { 1645 // super class tree and subclass list 1646 buf.beginTag("h3"); 1647 buf.link(genKlassHierarchyHref(klass), "View Class Hierarchy"); 1648 buf.endTag("h3"); 1649 } 1650 1651 // jcore - create .class link 1652 buf.h3(genDumpKlassLink(klass)); 1653 1654 // super class 1655 if (superKlass != null) { 1656 buf.h3("Super Class"); 1657 buf.append(genKlassLink(superKlass)); 1658 } 1659 1660 // interfaces 1661 buf.append(genHTMLListForInterfaces(klass)); 1662 1663 // fields 1664 buf.append(genHTMLListForFields(klass)); 1665 1666 // methods 1667 buf.append(genHTMLListForMethods(klass)); 1668 1669 // constant pool link 1670 buf.h3("Constant Pool"); 1671 buf.append(genConstantPoolLink(klass.getConstants())); 1672 1673 buf.genHTMLEpilogue(); 1674 return buf.toString(); 1675 } 1676 1677 protected sun.jvm.hotspot.debugger.Address parseAddress(String address) { 1678 VM vm = VM.getVM(); 1679 sun.jvm.hotspot.debugger.Address addr = vm.getDebugger().parseAddress(address); 1680 return addr; 1681 } 1682 1683 protected long addressToLong(sun.jvm.hotspot.debugger.Address addr) { 1684 return VM.getVM().getDebugger().getAddressValue(addr); 1685 } 1686 1687 protected sun.jvm.hotspot.debugger.Address longToAddress(long addr) { 1688 return parseAddress("0x" + Long.toHexString(addr)); 1689 } 1690 1691 protected Oop getOopAtAddress(sun.jvm.hotspot.debugger.Address addr) { 1692 OopHandle oopHandle = addr.addOffsetToAsOopHandle(0); 1693 return VM.getVM().getObjectHeap().newOop(oopHandle); 1694 } 1695 1696 protected Oop getOopAtAddress(String address) { 1697 sun.jvm.hotspot.debugger.Address addr = parseAddress(address); 1698 return getOopAtAddress(addr); 1699 } 1700 1701 private void dumpKlass(InstanceKlass kls) throws IOException { 1702 String klassName = kls.getName().asString(); 1703 klassName = klassName.replace('/', File.separatorChar); 1704 int index = klassName.lastIndexOf(File.separatorChar); 1705 File dir = null; 1706 if (index != -1) { 1707 String dirName = klassName.substring(0, index); 1708 dir = new File(DUMP_KLASS_OUTPUT_DIR, dirName); 1709 } else { 1710 dir = new File(DUMP_KLASS_OUTPUT_DIR); 1711 } 1712 1713 dir.mkdirs(); 1714 File f = new File(dir, klassName.substring(klassName.lastIndexOf(File.separatorChar) + 1) 1715 + ".class"); 1716 f.createNewFile(); 1717 FileOutputStream fis = new FileOutputStream(f); 1718 ClassWriter cw = new ClassWriter(kls, fis); 1719 cw.write(); 1720 } 1721 1722 public String genDumpKlass(InstanceKlass kls) { 1723 try { 1724 dumpKlass(kls); 1725 Formatter buf = new Formatter(genHTML); 1726 buf.genHTMLPrologue(genKlassTitle(kls)); 1727 buf.append(".class created for "); 1728 buf.append(genKlassLink(kls)); 1729 buf.genHTMLEpilogue(); 1730 return buf.toString(); 1731 } catch(IOException exp) { 1732 return genHTMLErrorMessage(exp); 1733 } 1734 } 1735 1736 protected String genJavaStackTraceTitle(JavaThread thread) { 1737 Formatter buf = new Formatter(genHTML); 1738 buf.append("Java Stack Trace for "); 1739 buf.append(thread.getThreadName()); 1740 return buf.toString(); 1741 } 1742 1743 public String genHTMLForJavaStackTrace(JavaThread thread) { 1744 Formatter buf = new Formatter(genHTML); 1745 buf.genHTMLPrologue(genJavaStackTraceTitle(thread)); 1746 1747 buf.append("Thread state = "); 1748 buf.append(thread.getThreadState().toString()); 1749 buf.br(); 1750 buf.beginTag("pre"); 1751 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { 1752 Method method = vf.getMethod(); 1753 buf.append(" - "); 1754 buf.append(genMethodLink(method)); 1755 buf.append(" @bci = " + vf.getBCI()); 1756 1757 int lineNumber = method.getLineNumberFromBCI(vf.getBCI()); 1758 if (lineNumber != -1) { 1759 buf.append(", line = "); 1760 buf.append(lineNumber); 1761 } 1762 1763 sun.jvm.hotspot.debugger.Address pc = vf.getFrame().getPC(); 1764 if (pc != null) { 1765 buf.append(", pc = "); 1766 buf.link(genPCHref(addressToLong(pc)), pc.toString()); 1767 } 1768 1769 if (vf.isCompiledFrame()) { 1770 buf.append(" (Compiled"); 1771 } 1772 else if (vf.isInterpretedFrame()) { 1773 buf.append(" (Interpreted"); 1774 } 1775 1776 if (vf.mayBeImpreciseDbg()) { 1777 buf.append("; information may be imprecise"); 1778 } 1779 buf.append(")"); 1780 buf.br(); 1781 } 1782 1783 buf.endTag("pre"); 1784 buf.genHTMLEpilogue(); 1785 return buf.toString(); 1786 } 1787 1788 public String genHTMLForHyperlink(String href) { 1789 if (href.startsWith("klass=")) { 1790 href = href.substring(href.indexOf('=') + 1); 1791 Oop obj = getOopAtAddress(href); 1792 if (Assert.ASSERTS_ENABLED) { 1793 Assert.that(obj instanceof InstanceKlass, "class= href with improper InstanceKlass!"); 1794 } 1795 return genHTML((InstanceKlass) obj); 1796 } else if (href.startsWith("method=")) { 1797 href = href.substring(href.indexOf('=') + 1); 1798 Oop obj = getOopAtAddress(href); 1799 if (Assert.ASSERTS_ENABLED) { 1800 Assert.that(obj instanceof Method, "method= href with improper Method!"); 1801 } 1802 return genHTML((Method) obj); 1803 } else if (href.startsWith("nmethod=")) { 1804 String addr = href.substring(href.indexOf('=') + 1); 1805 Object obj = VMObjectFactory.newObject(NMethod.class, parseAddress(addr)); 1806 if (Assert.ASSERTS_ENABLED) { 1807 Assert.that(obj instanceof NMethod, "nmethod= href with improper NMethod!"); 1808 } 1809 return genHTML((NMethod) obj); 1810 } else if (href.startsWith("pc=")) { 1811 String address = href.substring(href.indexOf('=') + 1); 1812 return genHTML(parseAddress(address)); 1813 } else if (href.startsWith("pc_multiple=")) { 1814 int indexOfComma = href.indexOf(','); 1815 if (indexOfComma == -1) { 1816 String firstPC = href.substring(href.indexOf('=') + 1); 1817 return genHTMLForRawDisassembly(parseAddress(firstPC), null); 1818 } else { 1819 String firstPC = href.substring(href.indexOf('=') + 1, indexOfComma); 1820 return genHTMLForRawDisassembly(parseAddress(firstPC), href.substring(indexOfComma + 1)); 1821 } 1822 } else if (href.startsWith("interp_codelets")) { 1823 return genInterpreterCodeletLinksPage(); 1824 } else if (href.startsWith("hierarchy=")) { 1825 href = href.substring(href.indexOf('=') + 1); 1826 Oop obj = getOopAtAddress(href); 1827 if (Assert.ASSERTS_ENABLED) { 1828 Assert.that(obj instanceof InstanceKlass, "class= href with improper InstanceKlass!"); 1829 } 1830 return genHTMLForKlassHierarchy((InstanceKlass) obj); 1831 } else if (href.startsWith("cpool=")) { 1832 href = href.substring(href.indexOf('=') + 1); 1833 Oop obj = getOopAtAddress(href); 1834 if (Assert.ASSERTS_ENABLED) { 1835 Assert.that(obj instanceof ConstantPool, "cpool= href with improper ConstantPool!"); 1836 } 1837 return genHTML((ConstantPool) obj); 1838 } else if (href.startsWith("jcore=")) { 1839 href = href.substring(href.indexOf('=') + 1); 1840 Oop obj = getOopAtAddress(href); 1841 if (Assert.ASSERTS_ENABLED) { 1842 Assert.that(obj instanceof InstanceKlass, "jcore= href with improper InstanceKlass!"); 1843 } 1844 return genDumpKlass((InstanceKlass) obj); 1845 } else if (href.startsWith("jcore_multiple=")) { 1846 href = href.substring(href.indexOf('=') + 1); 1847 Formatter buf = new Formatter(genHTML); 1848 buf.genHTMLPrologue(); 1849 StringTokenizer st = new StringTokenizer(href, ","); 1850 while (st.hasMoreTokens()) { 1851 Oop obj = getOopAtAddress(st.nextToken()); 1852 if (Assert.ASSERTS_ENABLED) { 1853 Assert.that(obj instanceof InstanceKlass, "jcore_multiple= href with improper InstanceKlass!"); 1854 } 1855 1856 InstanceKlass kls = (InstanceKlass) obj; 1857 try { 1858 dumpKlass(kls); 1859 buf.append(".class created for "); 1860 buf.append(genKlassLink(kls)); 1861 } catch(Exception exp) { 1862 buf.bold("can't .class for " + 1863 genKlassTitle(kls) + 1864 " : " + 1865 exp.getMessage()); 1866 } 1867 buf.br(); 1868 } 1869 1870 buf.genHTMLEpilogue(); 1871 return buf.toString(); 1872 } else { 1873 if (Assert.ASSERTS_ENABLED) { 1874 Assert.that(false, "unknown href link!"); 1875 } 1876 return null; 1877 } 1878 } 1879 }