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