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