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