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