alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (HTMLGenerator.java)

This example Java source code file (HTMLGenerator.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

constantpool, exception, formatter, htmldisassembler, instanceklass, interpreter, list, method, nmethod, oopmapstream, scopevalue, string, stringbuffer, symbol, util

The HTMLGenerator.java Java example source code

/*
 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

package sun.jvm.hotspot.ui.classbrowser;

import java.io.*;
import java.util.*;
import sun.jvm.hotspot.asm.*;
import sun.jvm.hotspot.code.*;
import sun.jvm.hotspot.compiler.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.interpreter.*;
import sun.jvm.hotspot.memory.*;
import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.tools.jcore.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;

public class HTMLGenerator implements /* imports */ ClassConstants {
    static class Formatter {
        boolean html;
        StringBuffer buf = new StringBuffer();

        Formatter(boolean h) {
            html = h;
        }

        void append(String s) {
            buf.append(s);
        }

        void append(int s) {
            buf.append(s);
        }

        void append(char s) {
            buf.append(s);
        }

        void append(StringBuffer s) {
            buf.append(s);
        }

        void append(Formatter s) {
            buf.append(s);
        }

        StringBuffer getBuffer() {
            return buf;
        }

        public String toString() {
            return buf.toString();
        }

        void wrap(String tag, String text) {
            wrap(tag, tag, text);
        }
        void wrap(String before, String after, String text) {
            beginTag(before);
            append(text);
            endTag(after);
        }

        // header tags
        void h1(String s) { nl(); wrap("h1", s); nl(); }
        void h2(String s) { nl(); wrap("h2", s); nl(); }
        void h3(String s) { nl(); wrap("h3", s); nl(); }
        void h4(String s) { nl(); wrap("h4", s); nl(); }

        // list tags
        void beginList()  { beginTag("ul"); nl(); }
        void endList()    { endTag("ul"); nl();   }
        void beginListItem() { beginTag("li"); }
        void endListItem()   { endTag("li"); nl();   }
        void li(String s) { wrap("li", s); nl();  }

        // table tags
        void beginTable(int border) {
            beginTag("table border='" + border + "'");
        }
        void cell(String s) { wrap("td", s); }
        void headerCell(String s) { wrap("th", s); }
        void endTable() { endTag("table"); }

        void link(String href, String text) {
            wrap("a href='" + href + "'", "a", text);
        }
        void beginTag(String s) {
            if (html) { append("<"); append(s); append(">"); }
        }
        void endTag(String s) {
            if (html) {
               append("</"); append(s); append(">");
            } else {
               if (s.equals("table") || s.equals("tr")) {
                  nl();
               }
               if (s.equals("td") || s.equals("th")) {
                  append(" ");
               }
            }
        }
        void bold(String s) {
            wrap("b", s);
        }

        void nl() {
            if (!html) buf.append("\n");
        }

        void br() {
            if (html) append("<br>");
            else      append("\n");
        }
        void genEmptyHTML() {
            if (html) append("<html>");
        }

        void genHTMLPrologue() {
            if (html) append("<html>");
        }

        void genHTMLPrologue(String title) {
            if (html) {
                append("<html>");
                append(title);
                append("</title></head>");
                append("<body>");
            }
            h2(title);
        }
        void genHTMLEpilogue() {
            if (html) append("</body></html>");
        }

    }

   private static final String DUMP_KLASS_OUTPUT_DIR = ".";
   private static final int NATIVE_CODE_SIZE = 200;
   private final String spaces;
   private final String tab;

   private boolean genHTML = true;

   public HTMLGenerator() {
       this(true);
   }

   public HTMLGenerator(boolean html) {
       genHTML = html;
       if (html) {
           spaces = "  ";
           tab = "    ";
       } else {
           spaces = "  ";
           tab = "    ";
       }
   }

   protected String escapeHTMLSpecialChars(String value) {
      if (!genHTML) return value;

      Formatter buf = new Formatter(genHTML);
      int len = value.length();
      for (int i=0; i < len; i++) {
         char c = value.charAt(i);
         switch (c) {
            case '<':
               buf.append("<");
               break;
            case '>':
               buf.append(">");
               break;
            case '&':
               buf.append("&");
               break;
            default:
               buf.append(c);
               break;
         }
      }
      return buf.toString();
   }

   public String genHTMLForMessage(String message) {
      Formatter buf = new Formatter(genHTML);
      buf.genHTMLPrologue(message);
      buf.genHTMLEpilogue();
      return buf.toString();
   }

   public String genHTMLErrorMessage(Exception exp) {
      exp.printStackTrace();
      return genHTMLForMessage(exp.getClass().getName() + " : " + exp.getMessage());
   }

   public String genHTMLForWait(String message) {
      Formatter buf = new Formatter(genHTML);
      buf.genHTMLPrologue("Please wait ..");
      buf.h2(message);
      return buf.toString();
   }

   protected String genKlassTitle(InstanceKlass klass) {
      Formatter buf = new Formatter(genHTML);
      AccessFlags acc = klass.getAccessFlagsObj();
      if (acc.isPublic()) {
         buf.append("public ");
      } else if (acc.isProtected()) {
         buf.append("protected ");
      } else if (acc.isPrivate()) {
         buf.append("private ");
      }

      if (acc.isStatic()) {
         buf.append("static ");
      }

      if (acc.isAbstract() ) {
         buf.append("abstract ");
      } else if (acc.isFinal()) {
         buf.append("final ");
      }

      if (acc.isStrict()) {
         buf.append("strict ");
      }

      // javac generated flags
      if (acc.isEnum()) {
         buf.append("[enum] ");
      }
      if (acc.isSynthetic()) {
         buf.append("[synthetic] ");
      }

      if (klass.isInterface()) {
         buf.append("interface");
      } else {
         buf.append("class");
      }

      buf.append(' ');
      buf.append(klass.getName().asString().replace('/', '.'));
      // is it generic?
      Symbol genSig = klass.getGenericSignature();
      if (genSig != null) {
         buf.append(" [signature ");
         buf.append(escapeHTMLSpecialChars(genSig.asString()));
         buf.append("] ");
      } else {
         buf.append(' ');
      }
      buf.append('@');
      buf.append(klass.getAddress().toString());
      return buf.toString();
   }

   protected String genBaseHref() {
      return "";
   }

   protected String genKlassHref(InstanceKlass klass) {
      return genBaseHref() + "klass=" + klass.getAddress();
   }

   protected String genKlassLink(InstanceKlass klass) {
      Formatter buf = new Formatter(genHTML);
      buf.link(genKlassHref(klass), genKlassTitle(klass));
      return buf.toString();
   }

   protected String genMethodModifierString(AccessFlags acc) {
      Formatter buf = new Formatter(genHTML);
      if (acc.isPrivate()) {
         buf.append("private ");
      } else if (acc.isProtected()) {
         buf.append("protected ");
      } else if (acc.isPublic()) {
         buf.append("public ");
      }

      if (acc.isStatic()) {
         buf.append("static ");
      } else if (acc.isAbstract() ) {
         buf.append("abstract ");
      } else if (acc.isFinal()) {
         buf.append("final ");
      }

       if (acc.isNative()) {
         buf.append("native ");
      }

      if (acc.isStrict()) {
         buf.append("strict ");
      }

      if (acc.isSynchronized()) {
         buf.append("synchronized ");
      }

      // javac generated flags
      if (acc.isBridge()) {
         buf.append("[bridge] ");
      }

      if (acc.isSynthetic()) {
         buf.append("[synthetic] ");
      }

      if (acc.isVarArgs()) {
         buf.append("[varargs] ");
      }

      return buf.toString();
   }

   protected String genMethodNameAndSignature(Method method) {
      Formatter buf = new Formatter(genHTML);
      buf.append(genMethodModifierString(method.getAccessFlagsObj()));
      Symbol sig = method.getSignature();
      new SignatureConverter(sig, buf.getBuffer()).iterateReturntype();
      buf.append(" ");
      String methodName = method.getName().asString();
      buf.append(escapeHTMLSpecialChars(methodName));
      buf.append('(');
      new SignatureConverter(sig, buf.getBuffer()).iterateParameters();
      buf.append(')');
      // is it generic?
      Symbol genSig = method.getGenericSignature();
      if (genSig != null) {
         buf.append(" [signature ");
         buf.append(escapeHTMLSpecialChars(genSig.asString()));
         buf.append("] ");
      }
      return buf.toString().replace('/', '.');
   }

   protected String genMethodTitle(Method method) {
      Formatter buf = new Formatter(genHTML);
      buf.append(genMethodNameAndSignature(method));
      buf.append(' ');
      buf.append('@');
      buf.append(method.getAddress().toString());
      return buf.toString();
   }

   protected String genMethodHref(Method m) {
      return genBaseHref() + "method=" + m.getAddress();
   }

   protected String genMethodLink(Method m) {
      Formatter buf = new Formatter(genHTML);
      buf.link(genMethodHref(m), genMethodTitle(m));
      return buf.toString();
   }

   protected String genMethodAndKlassLink(Method m) {
      Formatter buf = new Formatter(genHTML);
      buf.append(genMethodLink(m));
      buf.append(" of ");
      buf.append(genKlassLink((InstanceKlass) m.getMethodHolder()));
      return buf.toString();
   }

   protected String genNMethodHref(NMethod nm) {
      return genBaseHref() + "nmethod=" + nm.getAddress();
   }

   public String genNMethodTitle(NMethod nmethod) {
      Formatter buf = new Formatter(genHTML);
      Method m = nmethod.getMethod();

      buf.append("Disassembly for compiled method [");
      buf.append(genMethodTitle(m));
      buf.append(" ] ");
      buf.append('@');
      buf.append(nmethod.getAddress().toString());
      return buf.toString();
   }

   protected String genNMethodLink(NMethod nm) {
      Formatter buf = new Formatter(genHTML);
      buf.link(genNMethodHref(nm), genNMethodTitle(nm));
      return buf.toString();
   }

   public String genCodeBlobTitle(CodeBlob blob) {
      Formatter buf = new Formatter(genHTML);
      buf.append("Disassembly for code blob " + blob.getName() + " [");
      buf.append(blob.getClass().getName());
      buf.append(" ] @");
      buf.append(blob.getAddress().toString());
      return buf.toString();
   }

   protected BytecodeDisassembler createBytecodeDisassembler(Method m) {
      return new BytecodeDisassembler(m);
   }

   private String genLowHighShort(int val) {
      Formatter buf = new Formatter(genHTML);
      buf.append('#');
      buf.append(Integer.toString(val & 0xFFFF));
      buf.append(" #");
      buf.append(Integer.toString((val >> 16) & 0xFFFF));
      return buf.toString();
   }

   private String genListOfShort(short[] values) {
      if (values == null || values.length == 0)  return "";
      Formatter buf = new Formatter(genHTML);
      buf.append('[');
      for (int i = 0; i < values.length; i++) {
          if (i > 0)  buf.append(' ');
          buf.append('#');
          buf.append(Integer.toString(values[i]));
      }
      buf.append(']');
      return buf.toString();
   }

   protected String genHTMLTableForConstantPool(ConstantPool cpool) {
      Formatter buf = new Formatter(genHTML);
      buf.beginTable(1);

      buf.beginTag("tr");
      buf.headerCell("Index");
      buf.headerCell("Constant Type");
      buf.headerCell("Constant Value");
      buf.endTag("tr");

      final int length = (int) cpool.getLength();
      // zero'th pool entry is always invalid. ignore it.
      for (int index = 1; index < length; index++) {
         buf.beginTag("tr");
         buf.cell(Integer.toString(index));

         int ctag = (int) cpool.getTags().at((int) index);
         switch (ctag) {
            case JVM_CONSTANT_Integer:
               buf.cell("JVM_CONSTANT_Integer");
               buf.cell(Integer.toString(cpool.getIntAt(index)));
               break;

            case JVM_CONSTANT_Float:
               buf.cell("JVM_CONSTANT_Float");
               buf.cell(Float.toString(cpool.getFloatAt(index)));
               break;

            case JVM_CONSTANT_Long:
               buf.cell("JVM_CONSTANT_Long");
               buf.cell(Long.toString(cpool.getLongAt(index)));
               // long entries occupy two slots
               index++;
               break;

            case JVM_CONSTANT_Double:
               buf.cell("JVM_CONSTANT_Double");
               buf.cell(Double.toString(cpool.getDoubleAt(index)));
               // double entries occupy two slots
               index++;
               break;

            case JVM_CONSTANT_UnresolvedClass:
               buf.cell("JVM_CONSTANT_UnresolvedClass");
               buf.cell(cpool.getKlassNameAt(index).asString());
               break;

            case JVM_CONSTANT_UnresolvedClassInError:
               buf.cell("JVM_CONSTANT_UnresolvedClassInError");
               buf.cell(cpool.getSymbolAt(index).asString());
               break;

            case JVM_CONSTANT_Class:
               buf.cell("JVM_CONSTANT_Class");
               Klass klass = (Klass) cpool.getKlassAt(index);
               if (klass instanceof InstanceKlass) {
                  buf.cell(genKlassLink((InstanceKlass) klass));
               } else {
                  buf.cell(klass.getName().asString().replace('/', '.'));
               }
               break;

            case JVM_CONSTANT_Utf8:
               buf.cell("JVM_CONSTANT_Utf8");
               buf.cell("\"" +
                 escapeHTMLSpecialChars(cpool.getSymbolAt(index).asString()) +
                 "\"");
               break;

            case JVM_CONSTANT_String:
               buf.cell("JVM_CONSTANT_String");
               buf.cell("\"" +
                        escapeHTMLSpecialChars(cpool.getUnresolvedStringAt(index).asString()) + "\"");
               break;

            case JVM_CONSTANT_Fieldref:
               buf.cell("JVM_CONSTANT_Fieldref");
               buf.cell(genLowHighShort(cpool.getIntAt(index)));
               break;

            case JVM_CONSTANT_Methodref:
               buf.cell("JVM_CONSTANT_Methodref");
               buf.cell(genLowHighShort(cpool.getIntAt(index)));
               break;

            case JVM_CONSTANT_InterfaceMethodref:
               buf.cell("JVM_CONSTANT_InterfaceMethodref");
               buf.cell(genLowHighShort(cpool.getIntAt(index)));
               break;

            case JVM_CONSTANT_NameAndType:
               buf.cell("JVM_CONSTANT_NameAndType");
               buf.cell(genLowHighShort(cpool.getIntAt(index)));
               break;

            case JVM_CONSTANT_ClassIndex:
               buf.cell("JVM_CONSTANT_ClassIndex");
               buf.cell(Integer.toString(cpool.getIntAt(index)));
               break;

            case JVM_CONSTANT_StringIndex:
               buf.cell("JVM_CONSTANT_StringIndex");
               buf.cell(Integer.toString(cpool.getIntAt(index)));
               break;

            case JVM_CONSTANT_MethodHandle:
               buf.cell("JVM_CONSTANT_MethodHandle");
               buf.cell(genLowHighShort(cpool.getIntAt(index)));
               break;

            case JVM_CONSTANT_MethodType:
               buf.cell("JVM_CONSTANT_MethodType");
               buf.cell(Integer.toString(cpool.getIntAt(index)));
               break;

            case JVM_CONSTANT_InvokeDynamic:
               buf.cell("JVM_CONSTANT_InvokeDynamic");
               buf.cell(genLowHighShort(cpool.getIntAt(index)) +
                        genListOfShort(cpool.getBootstrapSpecifierAt(index)));
               break;

            default:
               throw new InternalError("unknown tag: " + ctag);
         }

         buf.endTag("tr");
      }

      buf.endTable();
      return buf.toString();
   }

   public String genHTML(ConstantPool cpool) {
      try {
         Formatter buf = new Formatter(genHTML);
         buf.genHTMLPrologue(genConstantPoolTitle(cpool));
         buf.h3("Holder Class");
         buf.append(genKlassLink((InstanceKlass) cpool.getPoolHolder()));
         buf.h3("Constants");
         buf.append(genHTMLTableForConstantPool(cpool));
         buf.genHTMLEpilogue();
         return buf.toString();
      } catch (Exception exp) {
         return genHTMLErrorMessage(exp);
      }
   }

   protected String genConstantPoolHref(ConstantPool cpool) {
      return genBaseHref() + "cpool=" + cpool.getAddress();
   }

   protected String genConstantPoolTitle(ConstantPool cpool) {
      Formatter buf = new Formatter(genHTML);
      buf.append("Constant Pool of [");
      buf.append(genKlassTitle((InstanceKlass) cpool.getPoolHolder()));
      buf.append("] @");
      buf.append(cpool.getAddress().toString());
      return buf.toString();
   }

   protected String genConstantPoolLink(ConstantPool cpool) {
      Formatter buf = new Formatter(genHTML);
      buf.link(genConstantPoolHref(cpool), genConstantPoolTitle(cpool));
      return buf.toString();
   }

   public String genHTML(Method method) {
      try {
         final Formatter buf = new Formatter(genHTML);
         buf.genHTMLPrologue(genMethodTitle(method));

         buf.h3("Holder Class");
         buf.append(genKlassLink((InstanceKlass) method.getMethodHolder()));

         NMethod nmethod = method.getNativeMethod();
         if (nmethod != null) {
            buf.h3("Compiled Code");
            buf.append(genNMethodLink(nmethod));
         }

         boolean hasThrows = method.hasCheckedExceptions();
         ConstantPool cpool = ((InstanceKlass) method.getMethodHolder()).getConstants();
         if (hasThrows) {
            buf.h3("Checked Exception(s)");
            CheckedExceptionElement[] exceptions = method.getCheckedExceptions();
            buf.beginTag("ul");
            for (int exp = 0; exp < exceptions.length; exp++) {
               short cpIndex = (short) exceptions[exp].getClassCPIndex();
               ConstantPool.CPSlot obj = cpool.getSlotAt(cpIndex);
               if (obj.isUnresolved()) {
                 buf.li((obj.getSymbol()).asString().replace('/', '.'));
               } else {
                 buf.li(genKlassLink((InstanceKlass)obj.getKlass()));
               }
            }
            buf.endTag("ul");
         }

         if (method.isNative() || method.isAbstract()) {
           buf.genHTMLEpilogue();
           return buf.toString();
         }

         buf.h3("Bytecode");
         BytecodeDisassembler disasm = createBytecodeDisassembler(method);
         final boolean hasLineNumbers = method.hasLineNumberTable();
         disasm.decode(new BytecodeVisitor() {
                          private Method method;
                          public void prologue(Method m) {
                             method = m;
                             buf.beginTable(0);
                             buf.beginTag("tr");
                             if (hasLineNumbers) {
                                buf.headerCell("line");
                             }
                             buf.headerCell("bci" + spaces);
                             buf.headerCell("bytecode");
                             buf.endTag("tr");
                          }

                          public void visit(Bytecode instr) {
                             int curBci = instr.bci();
                             buf.beginTag("tr");
                             if (hasLineNumbers) {
                                int lineNumber = method.getLineNumberFromBCI(curBci);
                                buf.cell(Integer.toString(lineNumber) + spaces);
                             }
                             buf.cell(Integer.toString(curBci) + spaces);

                             buf.beginTag("td");
                             String instrStr = null;
                             try {
                                 instrStr = escapeHTMLSpecialChars(instr.toString());
                             } catch (RuntimeException re) {
                                 buf.append("exception while printing " + instr.getBytecodeName());
                                 buf.endTag("td");
                                 buf.endTag("tr");
                                 re.printStackTrace();
                                 return;
                             }

                             if (instr instanceof BytecodeNew) {
                                BytecodeNew newBytecode = (BytecodeNew) instr;
                                InstanceKlass klass = newBytecode.getNewKlass();
                                if (klass != null) {
                                    buf.link(genKlassHref(klass), instrStr);
                                } else {
                                    buf.append(instrStr);
                                }
                             } else if(instr instanceof BytecodeInvoke) {
                                BytecodeInvoke invokeBytecode = (BytecodeInvoke) instr;
                                Method m = invokeBytecode.getInvokedMethod();
                                if (m != null) {
                                   buf.link(genMethodHref(m), instrStr);
                                   buf.append(" of ");
                                   InstanceKlass klass = (InstanceKlass) m.getMethodHolder();
                                   buf.link(genKlassHref(klass), genKlassTitle(klass));
                                } else {
                                   buf.append(instrStr);
                                }
                             } else if (instr instanceof BytecodeGetPut) {
                                BytecodeGetPut getPut = (BytecodeGetPut) instr;
                                sun.jvm.hotspot.oops.Field f = getPut.getField();
                                buf.append(instrStr);
                                if (f != null) {
                                   InstanceKlass klass = f.getFieldHolder();
                                   buf.append(" of ");
                                   buf.link(genKlassHref(klass), genKlassTitle(klass));
                                }
                             } else if (instr instanceof BytecodeLoadConstant) {
                                BytecodeLoadConstant ldc = (BytecodeLoadConstant) instr;
                                if (ldc.isKlassConstant()) {
                                   Object oop = ldc.getKlass();
                                   if (oop instanceof InstanceKlass) {
                                      buf.append("<a href='");
                                      buf.append(genKlassHref((InstanceKlass) oop));
                                      buf.append("'>");
                                      buf.append(instrStr);
                                      buf.append("</a>");
                                   } else {
                                      // unresolved klass literal
                                      buf.append(instrStr);
                                   }
                                } else {
                                   // not a klass literal
                                   buf.append(instrStr);
                                }
                             } else {
                                buf.append(instrStr);
                             }
                             buf.endTag("td");
                             buf.endTag("tr");
                          }

                          public void epilogue() {
                             buf.endTable();
                          }
                       });

         // display exception table for this method
         boolean hasException = method.hasExceptionTable();
         if (hasException) {
            ExceptionTableElement[] exceptionTable = method.getExceptionTable();
            int numEntries = exceptionTable.length;
            if (numEntries != 0) {
               buf.h4("Exception Table");
               buf.beginTable(1);
               buf.beginTag("tr");
               buf.headerCell("start bci");
               buf.headerCell("end bci");
               buf.headerCell("handler bci");
               buf.headerCell("catch type");
               buf.endTag("tr");

               for (int e = 0; e < numEntries; e ++) {
                  buf.beginTag("tr");
                  buf.cell(Integer.toString(exceptionTable[e].getStartPC()));
                  buf.cell(Integer.toString(exceptionTable[e].getEndPC()));
                  buf.cell(Integer.toString(exceptionTable[e].getHandlerPC()));
                  short cpIndex = (short) exceptionTable[e].getCatchTypeIndex();
                  ConstantPool.CPSlot obj = cpIndex == 0? null : cpool.getSlotAt(cpIndex);
                  if (obj == null) {
                     buf.cell("Any");
                  } else if (obj.isUnresolved()) {
                     buf.cell(obj.getSymbol().asString().replace('/', '.'));
                  } else {
                    buf.cell(genKlassLink((InstanceKlass)obj.getKlass()));
                  }
                  buf.endTag("tr");
               }

               buf.endTable();
            }
         }

         // display constant pool hyperlink
         buf.h3("Constant Pool");
         buf.append(genConstantPoolLink(cpool));
         buf.genHTMLEpilogue();
         return buf.toString();
      } catch (Exception exp) {
         return genHTMLErrorMessage(exp);
      }
   }

   protected SymbolFinder createSymbolFinder() {
      return new DummySymbolFinder();
   }

   // genHTML for a given address. Address may be a PC or
   // Method* or Klass*.

   public String genHTMLForAddress(String addrStr) {
      return genHTML(parseAddress(addrStr));
   }

   public String genHTML(sun.jvm.hotspot.debugger.Address pc) {
      CodeBlob blob = null;

      try {
         blob = (CodeBlob)VM.getVM().getCodeCache().findBlobUnsafe(pc);
      } catch (Exception exp) {
         // ignore
      }

      if (blob != null) {
         if (blob instanceof NMethod) {
            return genHTML((NMethod)blob);
         } else {
            // may be interpreter code.
            Interpreter interp = VM.getVM().getInterpreter();
            if (interp.contains(pc)) {
               InterpreterCodelet codelet = interp.getCodeletContaining(pc);
               if (codelet == null) {
                  return "Unknown location in the Interpreter: " + pc;
               }
               return genHTML(codelet);
            }
            return genHTML(blob);
         }
      } else if (VM.getVM().getCodeCache().contains(pc)) {
         return "Unknown location in the CodeCache: " + pc;
      }

      // did not find nmethod.
      // try Method*, Klass* and ConstantPool*.
      try {
        Metadata obj = Metadata.instantiateWrapperFor(pc);
         if (obj != null) {
            if (obj instanceof Method) {
               return genHTML((Method) obj);
            } else if (obj instanceof InstanceKlass) {
               return genHTML((InstanceKlass) obj);
            } else if (obj instanceof ConstantPool) {
               return genHTML((ConstantPool) obj);
            }
         }
      } catch (Exception exp) {
        exp.printStackTrace();
         // ignore
      }

      // didn't find any. do raw disassembly.
      return genHTMLForRawDisassembly(pc, null);
   }

   public String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address startPc, int size) {
      try {
         return genHTMLForRawDisassembly(startPc, size, null);
      } catch (Exception exp) {
         return genHTMLErrorMessage(exp);
      }
   }

   protected String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address startPc,
                                             String prevPCs) {
      try {
         return genHTMLForRawDisassembly(startPc, NATIVE_CODE_SIZE, prevPCs);
      } catch (Exception exp) {
         return genHTMLErrorMessage(exp);
      }
   }

   protected String genPCHref(long targetPc) {
      return genBaseHref() + "pc=0x" + Long.toHexString(targetPc);
   }

   protected String genMultPCHref(String pcs) {
      StringBuffer buf = new StringBuffer(genBaseHref());
      buf.append("pc_multiple=");
      buf.append(pcs);
      return buf.toString();
   }

   protected String genPCHref(Address addr) {
      return genPCHref(addressToLong(addr));
   }

   class HTMLDisassembler implements InstructionVisitor {
      private int instrSize = 0;
      private Formatter buf;
      private SymbolFinder symFinder = createSymbolFinder();
      private long pc;
      private OopMapSet oms;
      private CodeBlob blob;
      private NMethod nmethod;

      HTMLDisassembler(Formatter buf, CodeBlob blob) {
         this.buf = buf;
         this.blob = blob;
         if (blob != null) {
            if (blob instanceof NMethod) {
               nmethod = (NMethod)blob;
            }
            oms = blob.getOopMaps();
         }
      }

      public int getInstructionSize() {
         return  instrSize;
      }

      public void prologue() {
      }

      public void beginInstruction(long currentPc) {
         pc = currentPc;

         sun.jvm.hotspot.debugger.Address adr = longToAddress(pc);
         if (nmethod != null) {
            if (adr.equals(nmethod.getEntryPoint()))             print("[Entry Point]\n");
            if (adr.equals(nmethod.getVerifiedEntryPoint()))     print("[Verified Entry Point]\n");
            if (adr.equals(nmethod.exceptionBegin()))            print("[Exception Handler]\n");
            if (adr.equals(nmethod.stubBegin()) &&
                !nmethod.stubBegin().equals(nmethod.stubEnd()))  print("[Stub Code]\n");
            // if (adr.equals(nmethod.constsBegin()))               print("[Constants]\n");
         }

         buf.append(adr.toString());
         buf.append(':');
         buf.append(tab);
      }

      public void printAddress(long address) {
         sun.jvm.hotspot.debugger.Address addr = longToAddress(address);
         if (VM.getVM().getCodeCache().contains(addr)) {
            buf.link(genPCHref(address), addr.toString());
         } else {
            buf.append(addr.toString());
         }
      }

      public void print(String s) {
         buf.append(s);
      }

      public void endInstruction(long endPc) {
         instrSize += endPc - pc;
         if (genHTML) buf.br();

         if (nmethod != null) {
            ScopeDesc sd = nmethod.scope_desc_in(pc, endPc);
            if (sd != null) {
               buf.br();
               buf.append(genSafepointInfo(nmethod, sd));
            }
         }

         if (oms != null) {
            long base = addressToLong(blob.codeBegin());
            for (int i = 0, imax = (int)oms.getSize(); i < imax; i++) {
               OopMap om = oms.getMapAt(i);
               long omspc = base + om.getOffset();
               if (omspc > pc) {
                  if (omspc <= endPc) {
                     buf.br();
                     buf.append(genOopMapInfo(om));
                     // st.move_to(column);
                     // visitor.print("; ");
                        // om.print_on(st);
                  }
                  break;
               }
            }
         }
         // follow each complete insn by a nice newline
         buf.br();
      }

      public void epilogue() {
      }
   };

   protected String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address addr,
                                             int size,
                                             String prevPCs) {
      try {
         final Formatter buf = new Formatter(genHTML);
         buf.genHTMLPrologue("Disassembly @ " + addr);

         if (prevPCs != null && genHTML) {
             buf.beginTag("p");
             buf.link(genMultPCHref(prevPCs), "show previous code ..");
             buf.endTag("p");
         }


         buf.h3("Code");
         HTMLDisassembler visitor = new HTMLDisassembler(buf, null);
         Disassembler.decode(visitor, null, addr, addr.addOffsetTo(size));

         if (genHTML) buf.beginTag("p");
         Formatter tmpBuf = new Formatter(genHTML);
         long startPc = addressToLong(addr);
         tmpBuf.append("0x");
         tmpBuf.append(Long.toHexString(startPc + visitor.getInstructionSize()).toString());
         tmpBuf.append(",0x");
         tmpBuf.append(Long.toHexString(startPc));
         if (prevPCs != null) {
            tmpBuf.append(',');
            tmpBuf.append(prevPCs);
         }
         if (genHTML) {
             buf.link(genMultPCHref(tmpBuf.toString()), "show more code ..");
             buf.endTag("p");
         }

         buf.genHTMLEpilogue();
         return buf.toString();
      } catch (Exception exp) {
         return genHTMLErrorMessage(exp);
      }
   }

   protected String genSafepointInfo(NMethod nm, ScopeDesc sd) {
       Formatter buf = new Formatter(genHTML);
       Formatter tabs = new Formatter(genHTML);
       tabs.append(tab + tab + tab); // Initial indent for debug info

       buf.beginTag("pre");
       genScope(buf, tabs, sd);

       // Reset indent for scalar replaced objects
       tabs = new Formatter(genHTML);
       tabs.append(tab + tab + tab); // Initial indent for debug info

       genScObjInfo(buf, tabs, sd);
       buf.endTag("pre");

       return buf.toString();
   }

    protected void genScope(Formatter buf, Formatter tabs, ScopeDesc sd) {
        if (sd == null) {
            return;
        }

        genScope(buf, tabs, sd.sender());

        buf.append(tabs);
        Method m = sd.getMethod();
        buf.append(genMethodAndKlassLink(m));
        int bci = sd.getBCI();
        buf.append(" @ bci = ");
        buf.append(Integer.toString(bci));

        int line = m.getLineNumberFromBCI(bci);
        if (line != -1) {
            buf.append(", line = ");
            buf.append(Integer.toString(line));
        }

        List locals = sd.getLocals();
        if (locals != null) {
            buf.br();
            buf.append(tabs);
            buf.append(genHTMLForLocals(sd, locals));
        }

        List expressions = sd.getExpressions();
        if (expressions != null) {
            buf.br();
            buf.append(tabs);
            buf.append(genHTMLForExpressions(sd, expressions));
        }

        List monitors = sd.getMonitors();
        if (monitors != null) {
            buf.br();
            buf.append(tabs);
            buf.append(genHTMLForMonitors(sd, monitors));
        }

        buf.br();
        tabs.append(tab);
    }

    protected void genScObjInfo(Formatter buf, Formatter tabs, ScopeDesc sd) {
        if (sd == null) {
            return;
        }

        List objects = sd.getObjects();
        if (objects == null) {
            return;
        }
        int length = objects.size();
        for (int i = 0; i < length; i++) {
            buf.append(tabs);
            ObjectValue ov = (ObjectValue)objects.get(i);
            buf.append("ScObj" + i);
            ScopeValue sv = ov.getKlass();
            if (Assert.ASSERTS_ENABLED) {
                Assert.that(sv.isConstantOop(), "scalar replaced object klass must be constant oop");
            }
            ConstantOopReadValue klv = (ConstantOopReadValue)sv;
            OopHandle klHandle = klv.getValue();
            if (Assert.ASSERTS_ENABLED) {
                Assert.that(klHandle != null, "scalar replaced object klass must be not NULL");
            }
            Oop obj = VM.getVM().getObjectHeap().newOop(klHandle);
            // Obj is a Java mirror
            Klass klass = java_lang_Class.asKlass(obj);
            if (klass instanceof InstanceKlass) {
                InstanceKlass kls = (InstanceKlass) klass;
                buf.append(" " + kls.getName().asString() + "={");
                int flen = ov.fieldsSize();

                U2Array klfields = kls.getFields();
                int klen = (int) klfields.length();
                int findex = 0;
                for (int index = 0; index < klen; index++) {
                    int accsFlags = kls.getFieldAccessFlags(index);
                    Symbol f_name = kls.getFieldName(index);
                    AccessFlags access = new AccessFlags(accsFlags);
                    if (!access.isStatic()) {
                        ScopeValue svf = ov.getFieldAt(findex++);
                        String    fstr = scopeValueAsString(sd, svf);
                        buf.append(" [" + f_name.asString() + " :"+ index + "]=(#" + fstr + ")");
                    }
                }
                buf.append(" }");
            } else {
                buf.append(" ");
                int flen = ov.fieldsSize();
                if (klass instanceof TypeArrayKlass) {
                    TypeArrayKlass kls = (TypeArrayKlass) klass;
                    buf.append(kls.getElementTypeName() + "[" + flen + "]");
                } else if (klass instanceof ObjArrayKlass) {
                    ObjArrayKlass kls = (ObjArrayKlass) klass;
                    Klass elobj = kls.getBottomKlass();
                    if (elobj instanceof InstanceKlass) {
                        buf.append(elobj.getName().asString());
                    } else if (elobj instanceof TypeArrayKlass) {
                        TypeArrayKlass elkls = (TypeArrayKlass) elobj;
                        buf.append(elkls.getElementTypeName());
                    } else {
                        if (Assert.ASSERTS_ENABLED) {
                            Assert.that(false, "unknown scalar replaced object klass!");
                        }
                    }
                    buf.append("[" + flen + "]");
                    int ndim = (int) kls.getDimension();
                    while (--ndim > 0) {
                        buf.append("[]");
                    }
                } else {
                    if (Assert.ASSERTS_ENABLED) {
                        Assert.that(false, "unknown scalar replaced object klass!");
                    }
                }
                buf.append("={");
                for (int findex = 0; findex < flen; findex++) {
                    ScopeValue svf = ov.getFieldAt(findex);
                    String fstr = scopeValueAsString(sd, svf);
                    buf.append(" [" + findex + "]=(#" + fstr + ")");
                }
                buf.append(" }");
            }
            buf.br();
        }
    }

   protected String genHTMLForOopMap(OopMap map) {
      final int stack0 = VMRegImpl.getStack0().getValue();
      Formatter buf = new Formatter(genHTML);

      final class OopMapValueIterator {
         final Formatter iterate(OopMapStream oms, String type, boolean printContentReg) {
            Formatter tmpBuf = new Formatter(genHTML);
            boolean found = false;
            tmpBuf.beginTag("tr");
            tmpBuf.beginTag("td");
            tmpBuf.append(type);
            for (; ! oms.isDone(); oms.next()) {
               OopMapValue omv = oms.getCurrent();
               if (omv == null) {
                  continue;
               }
               found = true;
               VMReg vmReg = omv.getReg();
               int reg = vmReg.getValue();
               if (reg < stack0) {
                  tmpBuf.append(VMRegImpl.getRegisterName(reg));
               } else {
                  tmpBuf.append('[');
                  tmpBuf.append(Integer.toString((reg - stack0) * 4));
                  tmpBuf.append(']');
               }
               if (printContentReg) {
                  tmpBuf.append(" = ");
                  VMReg vmContentReg = omv.getContentReg();
                  int contentReg = vmContentReg.getValue();
                  if (contentReg < stack0) {
                     tmpBuf.append(VMRegImpl.getRegisterName(contentReg));
                  } else {
                     tmpBuf.append('[');
                     tmpBuf.append(Integer.toString((contentReg - stack0) * 4));
                     tmpBuf.append(']');
                  }
               }
               tmpBuf.append(spaces);
            }
            tmpBuf.endTag("td");
            tmpBuf.endTag("tr");
            return found ? tmpBuf : new Formatter(genHTML);
         }
      }

      buf.beginTable(0);

      OopMapValueIterator omvIterator = new OopMapValueIterator();
      OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.OOP_VALUE);
      buf.append(omvIterator.iterate(oms, "Oops:", false));

      oms = new OopMapStream(map, OopMapValue.OopTypes.NARROWOOP_VALUE);
      buf.append(omvIterator.iterate(oms, "NarrowOops:", false));

      oms = new OopMapStream(map, OopMapValue.OopTypes.VALUE_VALUE);
      buf.append(omvIterator.iterate(oms, "Values:", false));

      oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE);
      buf.append(omvIterator.iterate(oms, "Callee saved:",  true));

      oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE);
      buf.append(omvIterator.iterate(oms, "Derived oops:", true));

      buf.endTag("table");
      return buf.toString();
   }


   protected String genOopMapInfo(NMethod nmethod, PCDesc pcDesc) {
      OopMapSet mapSet = nmethod.getOopMaps();
      if (mapSet == null || (mapSet.getSize() <= 0))
        return "";
      int pcOffset = pcDesc.getPCOffset();
      OopMap map = mapSet.findMapAtOffset(pcOffset, VM.getVM().isDebugging());
      if (map == null) {
         throw new IllegalArgumentException("no oopmap at safepoint!");
      }

      return genOopMapInfo(map);
   }

   protected String genOopMapInfo(OopMap map) {
     Formatter buf = new Formatter(genHTML);
     buf.beginTag("pre");
     buf.append("OopMap: ");
     buf.br();
     buf.append(genHTMLForOopMap(map));
     buf.endTag("pre");

     return buf.toString();
   }

   protected String locationAsString(Location loc) {
      Formatter buf = new Formatter(genHTML);
      if (loc.isIllegal()) {
         buf.append("illegal");
      } else {
         Location.Where  w  = loc.getWhere();
         Location.Type type = loc.getType();

         if (w == Location.Where.ON_STACK) {
            buf.append("stack[" + loc.getStackOffset() + "]");
         } else if (w == Location.Where.IN_REGISTER) {
            boolean isFloat = (type == Location.Type.FLOAT_IN_DBL ||
                               type == Location.Type.DBL);
            int regNum = loc.getRegisterNumber();
            VMReg vmReg = new VMReg(regNum);
            buf.append(VMRegImpl.getRegisterName(vmReg.getValue()));
         }

         buf.append(", ");
         if (type == Location.Type.NORMAL) {
            buf.append("normal");
         } else if (type == Location.Type.OOP) {
            buf.append("oop");
         } else if (type == Location.Type.NARROWOOP) {
            buf.append("narrowoop");
         } else if (type == Location.Type.INT_IN_LONG) {
            buf.append("int");
         } else if (type == Location.Type.LNG) {
            buf.append("long");
         } else if (type == Location.Type.FLOAT_IN_DBL) {
            buf.append("float");
         } else if (type == Location.Type.DBL) {
            buf.append("double");
         } else if (type == Location.Type.ADDR) {
            buf.append("address");
         } else if (type == Location.Type.INVALID) {
            buf.append("invalid");
         }
      }
      return buf.toString();
   }

   private String scopeValueAsString(ScopeDesc sd, ScopeValue sv) {
      Formatter buf = new Formatter(genHTML);
      if (sv.isConstantInt()) {
         buf.append("int ");
         ConstantIntValue intValue = (ConstantIntValue) sv;
         buf.append(Integer.toString(intValue.getValue()));
      } else if (sv.isConstantLong()) {
         buf.append("long ");
         ConstantLongValue longValue = (ConstantLongValue) sv;
         buf.append(Long.toString(longValue.getValue()));
         buf.append("L");
      } else if (sv.isConstantDouble()) {
         buf.append("double ");
         ConstantDoubleValue dblValue = (ConstantDoubleValue) sv;
         buf.append(Double.toString(dblValue.getValue()));
         buf.append("D");
      } else if (sv.isConstantOop()) {
         buf.append("oop ");
         ConstantOopReadValue oopValue = (ConstantOopReadValue) sv;
         OopHandle oopHandle = oopValue.getValue();
         if (oopHandle != null) {
            buf.append(oopHandle.toString());
         } else {
            buf.append("null");
         }
      } else if (sv.isLocation()) {
         LocationValue lvalue = (LocationValue) sv;
         Location loc = lvalue.getLocation();
         if (loc != null) {
            buf.append(locationAsString(loc));
         } else {
            buf.append("null");
         }
      } else if (sv.isObject()) {
         ObjectValue ov = (ObjectValue)sv;
         buf.append("#ScObj" + sd.getObjects().indexOf(ov));
      } else {
         buf.append("unknown scope value " + sv);
      }
      return buf.toString();
   }

   protected String genHTMLForScopeValues(ScopeDesc sd, boolean locals, List values) {
      int length = values.size();
      Formatter buf = new Formatter(genHTML);
      buf.append(locals? "locals " : "expressions ");
      for (int i = 0; i < length; i++) {
         ScopeValue sv = (ScopeValue) values.get(i);
         if (sv == null) {
            continue;
         }
         buf.append('(');
         if (locals) {
            Symbol name = sd.getMethod().getLocalVariableName(sd.getBCI(), i);
            if (name != null) {
               buf.append("'");
               buf.append(name.asString());
               buf.append('\'');
            } else {
               buf.append("[");
               buf.append(Integer.toString(i));
               buf.append(']');
            }
         } else {
            buf.append("[");
            buf.append(Integer.toString(i));
            buf.append(']');
         }

         buf.append(", ");
         buf.append(scopeValueAsString(sd, sv));
         buf.append(") ");
      }

      return buf.toString();
   }

   protected String genHTMLForLocals(ScopeDesc sd, List locals) {
      return genHTMLForScopeValues(sd, true, locals);
   }

   protected String genHTMLForExpressions(ScopeDesc sd, List expressions) {
      return genHTMLForScopeValues(sd, false, expressions);
   }

   protected String genHTMLForMonitors(ScopeDesc sd, List monitors) {
      int length = monitors.size();
      Formatter buf = new Formatter(genHTML);
      buf.append("monitors ");
      for (int i = 0; i < length; i++) {
         MonitorValue mv = (MonitorValue) monitors.get(i);
         if (mv == null) {
            continue;
         }
         buf.append("(owner = ");
         ScopeValue owner = mv.owner();
         if (owner != null) {
            buf.append(scopeValueAsString(sd, owner));
         } else {
            buf.append("null");
         }
         buf.append(", lock = ");

         Location loc = mv.basicLock();
         if (loc != null) {
            buf.append(locationAsString(loc));
         } else {
            buf.append("null");
         }
         buf.append(") ");
      }
      return buf.toString();
   }

   public String genHTML(final NMethod nmethod) {
      try {
         final Formatter buf = new Formatter(genHTML);
         buf.genHTMLPrologue(genNMethodTitle(nmethod));
         buf.h3("Method");
         buf.append(genMethodAndKlassLink(nmethod.getMethod()));

         buf.h3("Compiled Code");
         Disassembler.decode(new HTMLDisassembler(buf, nmethod), nmethod);
         buf.genHTMLEpilogue();
         return buf.toString();
      } catch (Exception exp) {
         return genHTMLErrorMessage(exp);
      }
   }

  public String genHTML(final CodeBlob blob) {
      try {
         final Formatter buf = new Formatter(genHTML);
         buf.genHTMLPrologue(genCodeBlobTitle(blob));
         buf.h3("CodeBlob");

         buf.h3("Compiled Code");
         Disassembler.decode(new HTMLDisassembler(buf, blob), blob);

         buf.genHTMLEpilogue();
         return buf.toString();
      } catch (Exception exp) {
         return genHTMLErrorMessage(exp);
      }
   }

   protected String genInterpreterCodeletTitle(InterpreterCodelet codelet) {
      Formatter buf = new Formatter(genHTML);
      buf.append("Interpreter codelet [");
      buf.append(codelet.codeBegin().toString());
      buf.append(',');
      buf.append(codelet.codeEnd().toString());
      buf.append(") - ");
      buf.append(codelet.getDescription());
      return buf.toString();
   }

   protected String genInterpreterCodeletLinkPageHref(StubQueue stubq) {
      return genBaseHref() + "interp_codelets";
   }

   public String genInterpreterCodeletLinksPage() {
      Formatter buf = new Formatter(genHTML);
      buf.genHTMLPrologue("Interpreter Codelets");
      buf.beginTag("ul");

      Interpreter interp = VM.getVM().getInterpreter();
      StubQueue code = interp.getCode();
      InterpreterCodelet stub = (InterpreterCodelet) code.getFirst();
      while (stub != null) {
         buf.beginTag("li");
         sun.jvm.hotspot.debugger.Address addr = stub.codeBegin();
         buf.link(genPCHref(addressToLong(addr)), stub.getDescription() + " @" + addr);
         buf.endTag("li");
         stub = (InterpreterCodelet) code.getNext(stub);
      }

      buf.endTag("ul");
      buf.genHTMLEpilogue();
      return buf.toString();
   }

   public String genHTML(InterpreterCodelet codelet) {
      Formatter buf = new Formatter(genHTML);
      buf.genHTMLPrologue(genInterpreterCodeletTitle(codelet));
      Interpreter interp = VM.getVM().getInterpreter();
      StubQueue stubq = interp.getCode();

      if (genHTML) {
         buf.beginTag("h3");
         buf.link(genInterpreterCodeletLinkPageHref(stubq), "View links for all codelets");
         buf.endTag("h3");
         buf.br();
      }

      Stub prev = stubq.getPrev(codelet);
      if (prev != null) {
         if (genHTML) {
            buf.beginTag("h3");
            buf.link(genPCHref(addressToLong(prev.codeBegin())), "View Previous Codelet");
            buf.endTag("h3");
            buf.br();
         } else {
            buf.h3("Previous Codelet = 0x" + Long.toHexString(addressToLong(prev.codeBegin())));
         }
      }

      buf.h3("Code");
      Disassembler.decode(new HTMLDisassembler(buf, null), null,
                          codelet.codeBegin(), codelet.codeEnd());

      Stub next = stubq.getNext(codelet);
      if (next != null) {
         if (genHTML) {
            buf.beginTag("h3");
            buf.link(genPCHref(addressToLong(next.codeBegin())), "View Next Codelet");
            buf.endTag("h3");
         } else {
            buf.h3("Next Codelet = 0x" + Long.toHexString(addressToLong(next.codeBegin())));
         }
      }

      buf.genHTMLEpilogue();
      return buf.toString();
   }

   protected String genDumpKlassesTitle(InstanceKlass[] klasses) {
      return (klasses.length == 1) ? "Create .class for this class"
                                   : "Create .class for all classes";
   }

   protected String genDumpKlassesHref(InstanceKlass[] klasses) {
      StringBuffer buf = new StringBuffer(genBaseHref());
      buf.append("jcore_multiple=");
      for (int k = 0; k < klasses.length; k++) {
         buf.append(klasses[k].getAddress().toString());
         buf.append(',');
      }
      return buf.toString();
   }

   protected String genDumpKlassesLink(InstanceKlass[] klasses) {
      if (!genHTML) return "";

      Formatter buf = new Formatter(genHTML);
      buf.link(genDumpKlassesHref(klasses), genDumpKlassesTitle(klasses));
      return buf.toString();
   }

   public String genHTMLForKlassNames(InstanceKlass[] klasses) {
      try {
         Formatter buf = new Formatter(genHTML);
         buf.genHTMLPrologue();
         buf.h3(genDumpKlassesLink(klasses));

         buf.append(genHTMLListForKlassNames(klasses));
         buf.genHTMLEpilogue();
         return buf.toString();
      } catch (Exception exp) {
         return genHTMLErrorMessage(exp);
      }
   }

   protected String genHTMLListForKlassNames(InstanceKlass[] klasses) {
      final Formatter buf = new Formatter(genHTML);
      buf.beginTable(0);
      for (int i = 0; i < klasses.length; i++) {
         InstanceKlass ik = klasses[i];
         buf.beginTag("tr");
         buf.cell(genKlassLink(ik));
         buf.endTag("tr");
      }

      buf.endTable();
      return buf.toString();
   }

   public String genHTMLForMethodNames(InstanceKlass klass) {
      try {
         Formatter buf = new Formatter(genHTML);
         buf.genHTMLPrologue();
         buf.append(genHTMLListForMethods(klass));
         buf.genHTMLEpilogue();
         return buf.toString();
      } catch (Exception exp) {
         return genHTMLErrorMessage(exp);
      }
   }

   protected String genHTMLListForMethods(InstanceKlass klass) {
      Formatter buf = new Formatter(genHTML);
      MethodArray methods = klass.getMethods();
      int numMethods = methods.length();
      if (numMethods != 0) {
         buf.h3("Methods");
         buf.beginTag("ul");
         for (int m = 0; m < numMethods; m++) {
            Method mtd = methods.at(m);
            buf.li(genMethodLink(mtd) + ";");
         }
         buf.endTag("ul");
      }
      return buf.toString();
   }

   protected String genHTMLListForInterfaces(InstanceKlass klass) {
      try {
         Formatter buf = new Formatter(genHTML);
         KlassArray interfaces = klass.getLocalInterfaces();
         int numInterfaces = interfaces.length();
         if (numInterfaces != 0) {
            buf.h3("Interfaces");
            buf.beginTag("ul");
            for (int i = 0; i < numInterfaces; i++) {
               InstanceKlass inf = (InstanceKlass) interfaces.getAt(i);
               buf.li(genKlassLink(inf));
            }
            buf.endTag("ul");
         }
         return buf.toString();
      } catch (Exception exp) {
         return genHTMLErrorMessage(exp);
      }
   }

   protected String genFieldModifierString(AccessFlags acc) {
      Formatter buf = new Formatter(genHTML);
      if (acc.isPrivate()) {
         buf.append("private ");
      } else if (acc.isProtected()) {
         buf.append("protected ");
      } else if (acc.isPublic()) {
         buf.append("public ");
      }

      if (acc.isStatic()) {
         buf.append("static ");
      }

      if (acc.isFinal()) {
         buf.append("final ");
      }
      if (acc.isVolatile()) {
         buf.append("volatile ");
      }
      if (acc.isTransient()) {
         buf.append("transient ");
      }

      // javac generated flags
      if (acc.isSynthetic()) {
         buf.append("[synthetic] ");
      }
      return buf.toString();
   }

   public String genHTMLForFieldNames(InstanceKlass klass) {
      try {
         Formatter buf = new Formatter(genHTML);
         buf.genHTMLPrologue();
         buf.append(genHTMLListForFields(klass));
         buf.genHTMLEpilogue();
         return buf.toString();
      } catch (Exception exp) {
         return genHTMLErrorMessage(exp);
      }
   }

   protected String genHTMLListForFields(InstanceKlass klass) {
      Formatter buf = new Formatter(genHTML);
      U2Array fields = klass.getFields();
      int numFields = klass.getAllFieldsCount();
      if (numFields != 0) {
         buf.h3("Fields");
         buf.beginList();
         for (int f = 0; f < numFields; f++) {
           sun.jvm.hotspot.oops.Field field = klass.getFieldByIndex(f);
           String f_name = ((NamedFieldIdentifier)field.getID()).getName();
           Symbol f_sig  = field.getSignature();
           Symbol f_genSig = field.getGenericSignature();
           AccessFlags acc = field.getAccessFlagsObj();

           buf.beginListItem();
           buf.append(genFieldModifierString(acc));
           buf.append(' ');
           Formatter sigBuf = new Formatter(genHTML);
           new SignatureConverter(f_sig, sigBuf.getBuffer()).dispatchField();
           buf.append(sigBuf.toString().replace('/', '.'));
           buf.append(' ');
           buf.append(f_name);
           buf.append(';');
           // is it generic?
           if (f_genSig != null) {
              buf.append(" [signature ");
              buf.append(escapeHTMLSpecialChars(f_genSig.asString()));
              buf.append("] ");
           }
           buf.append(" (offset = " + field.getOffset() + ")");
           buf.endListItem();
         }
         buf.endList();
      }
      return buf.toString();
   }

   protected String genKlassHierarchyHref(InstanceKlass klass) {
      return genBaseHref() + "hierarchy=" + klass.getAddress();
   }

   protected String genKlassHierarchyTitle(InstanceKlass klass) {
      Formatter buf = new Formatter(genHTML);
      buf.append("Class Hierarchy of ");
      buf.append(genKlassTitle(klass));
      return buf.toString();
   }

   protected String genKlassHierarchyLink(InstanceKlass klass) {
      Formatter buf = new Formatter(genHTML);
      buf.link(genKlassHierarchyHref(klass), genKlassHierarchyTitle(klass));
      return buf.toString();
   }

   protected String genHTMLListForSubKlasses(InstanceKlass klass) {
      Formatter buf = new Formatter(genHTML);
      Klass subklass = klass.getSubklassKlass();
      if (subklass != null) {
         buf.beginList();
         while (subklass != null) {
            if (subklass instanceof InstanceKlass) {
               buf.li(genKlassLink((InstanceKlass)subklass));
            }
            subklass = subklass.getNextSiblingKlass();
         }
         buf.endList();
      }
      return buf.toString();
   }

   public String genHTMLForKlassHierarchy(InstanceKlass klass) {
      Formatter buf = new Formatter(genHTML);
      buf.genHTMLPrologue(genKlassHierarchyTitle(klass));


      buf.beginTag("pre");
      buf.append(genKlassLink(klass));
      buf.br();
      StringBuffer tabs = new StringBuffer(tab);
      InstanceKlass superKlass = klass;
      while ( (superKlass = (InstanceKlass) superKlass.getSuper()) != null ) {
         buf.append(tabs);
         buf.append(genKlassLink(superKlass));
         tabs.append(tab);
         buf.br();
      }
      buf.endTag("pre");

      // generate subklass list
      Klass subklass = klass.getSubklassKlass();
      if (subklass != null) {
         buf.h3("Direct Subclasses");
         buf.append(genHTMLListForSubKlasses(klass));
      }

      buf.genHTMLEpilogue();
      return buf.toString();
   }

   protected String genDumpKlassHref(InstanceKlass klass) {
      return genBaseHref() + "jcore=" + klass.getAddress();
   }

   protected String genDumpKlassLink(InstanceKlass klass) {
      if (!genHTML) return "";

      Formatter buf = new Formatter(genHTML);
      buf.link(genDumpKlassHref(klass), "Create .class File");
      return buf.toString();
   }

   public String genHTML(InstanceKlass klass) {
      Formatter buf = new Formatter(genHTML);
      buf.genHTMLPrologue(genKlassTitle(klass));
      InstanceKlass superKlass = (InstanceKlass) klass.getSuper();

      if (genHTML) {
          // super class tree and subclass list
          buf.beginTag("h3");
          buf.link(genKlassHierarchyHref(klass), "View Class Hierarchy");
          buf.endTag("h3");
      }

      // jcore - create .class link
      buf.h3(genDumpKlassLink(klass));

      // super class
      if (superKlass != null) {
         buf.h3("Super Class");
         buf.append(genKlassLink(superKlass));
      }

      // interfaces
      buf.append(genHTMLListForInterfaces(klass));

      // fields
      buf.append(genHTMLListForFields(klass));

      // methods
      buf.append(genHTMLListForMethods(klass));

      // constant pool link
      buf.h3("Constant Pool");
      buf.append(genConstantPoolLink(klass.getConstants()));

      buf.genHTMLEpilogue();
      return buf.toString();
   }

   protected sun.jvm.hotspot.debugger.Address parseAddress(String address) {
      VM vm = VM.getVM();
      sun.jvm.hotspot.debugger.Address addr = vm.getDebugger().parseAddress(address);
      return addr;
   }

   protected long addressToLong(sun.jvm.hotspot.debugger.Address addr) {
      return VM.getVM().getDebugger().getAddressValue(addr);
   }

   protected sun.jvm.hotspot.debugger.Address longToAddress(long addr) {
      return parseAddress("0x" + Long.toHexString(addr));
   }

   protected Oop getOopAtAddress(sun.jvm.hotspot.debugger.Address addr) {
      OopHandle oopHandle = addr.addOffsetToAsOopHandle(0);
      return VM.getVM().getObjectHeap().newOop(oopHandle);
   }

   protected Oop getOopAtAddress(String address) {
      sun.jvm.hotspot.debugger.Address addr = parseAddress(address);
      return getOopAtAddress(addr);
   }

   protected Klass getKlassAtAddress(String address) {
      sun.jvm.hotspot.debugger.Address addr = parseAddress(address);
      return (Klass)Metadata.instantiateWrapperFor(addr);
   }

   protected Method getMethodAtAddress(String address) {
      sun.jvm.hotspot.debugger.Address addr = parseAddress(address);
      return (Method)Metadata.instantiateWrapperFor(addr);
   }

   protected ConstantPool getConstantPoolAtAddress(String address) {
      sun.jvm.hotspot.debugger.Address addr = parseAddress(address);
      return (ConstantPool) Metadata.instantiateWrapperFor(addr);
   }

   private void dumpKlass(InstanceKlass kls) throws IOException {
      String klassName = kls.getName().asString();
      klassName = klassName.replace('/', File.separatorChar);
      int index = klassName.lastIndexOf(File.separatorChar);
      File dir = null;
      if (index != -1) {
        String dirName = klassName.substring(0, index);
        dir =  new File(DUMP_KLASS_OUTPUT_DIR,  dirName);
      } else {
        dir = new File(DUMP_KLASS_OUTPUT_DIR);
      }

      dir.mkdirs();
      File f = new File(dir, klassName.substring(klassName.lastIndexOf(File.separatorChar) + 1)
                              + ".class");
      f.createNewFile();
      FileOutputStream fis = new FileOutputStream(f);
      ClassWriter cw = new ClassWriter(kls, fis);
      cw.write();
   }

   public String genDumpKlass(InstanceKlass kls) {
      try {
         dumpKlass(kls);
         Formatter buf = new Formatter(genHTML);
         buf.genHTMLPrologue(genKlassTitle(kls));
         buf.append(".class created for ");
         buf.append(genKlassLink(kls));
         buf.genHTMLEpilogue();
         return buf.toString();
      } catch(IOException exp) {
         return genHTMLErrorMessage(exp);
      }
   }

   protected String genJavaStackTraceTitle(JavaThread thread) {
      Formatter buf = new Formatter(genHTML);
      buf.append("Java Stack Trace for ");
      buf.append(thread.getThreadName());
      return buf.toString();
   }

   public String genHTMLForJavaStackTrace(JavaThread thread) {
      Formatter buf = new Formatter(genHTML);
      buf.genHTMLPrologue(genJavaStackTraceTitle(thread));

      buf.append("Thread state = ");
      buf.append(thread.getThreadState().toString());
      buf.br();
      buf.beginTag("pre");
      for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
         Method method = vf.getMethod();
         buf.append(" - ");
         buf.append(genMethodLink(method));
         buf.append(" @bci = " + vf.getBCI());

         int lineNumber = method.getLineNumberFromBCI(vf.getBCI());
         if (lineNumber != -1) {
            buf.append(", line = ");
            buf.append(lineNumber);
         }

         sun.jvm.hotspot.debugger.Address pc = vf.getFrame().getPC();
         if (pc != null) {
            buf.append(", pc = ");
            buf.link(genPCHref(addressToLong(pc)), pc.toString());
         }

         if (vf.isCompiledFrame()) {
            buf.append(" (Compiled");
         }
         else if (vf.isInterpretedFrame()) {
            buf.append(" (Interpreted");
         }

         if (vf.mayBeImpreciseDbg()) {
            buf.append("; information may be imprecise");
         }
         buf.append(")");
         buf.br();
      }

      buf.endTag("pre");
      buf.genHTMLEpilogue();
      return buf.toString();
   }

   public String genHTMLForHyperlink(String href) {
      if (href.startsWith("klass=")) {
         href = href.substring(href.indexOf('=') + 1);
         Klass k = getKlassAtAddress(href);
         if (Assert.ASSERTS_ENABLED) {
            Assert.that(k instanceof InstanceKlass, "class= href with improper InstanceKlass!");
         }
         return genHTML((InstanceKlass) k);
      } else if (href.startsWith("method=")) {
         href = href.substring(href.indexOf('=') + 1);
         Method obj = getMethodAtAddress(href);
         if (Assert.ASSERTS_ENABLED) {
            Assert.that(obj instanceof Method, "method= href with improper Method!");
         }
         return genHTML(obj);
      } else if (href.startsWith("nmethod=")) {
         String addr = href.substring(href.indexOf('=') + 1);
         Object obj = VMObjectFactory.newObject(NMethod.class, parseAddress(addr));
         if (Assert.ASSERTS_ENABLED) {
            Assert.that(obj instanceof NMethod, "nmethod= href with improper NMethod!");
         }
         return genHTML((NMethod) obj);
      } else if (href.startsWith("pc=")) {
         String address = href.substring(href.indexOf('=') + 1);
         return genHTML(parseAddress(address));
      } else if (href.startsWith("pc_multiple=")) {
         int indexOfComma = href.indexOf(',');
         if (indexOfComma == -1) {
            String firstPC = href.substring(href.indexOf('=') + 1);
            return genHTMLForRawDisassembly(parseAddress(firstPC), null);
         } else {
            String firstPC = href.substring(href.indexOf('=') + 1, indexOfComma);
            return genHTMLForRawDisassembly(parseAddress(firstPC), href.substring(indexOfComma + 1));
         }
      } else if (href.startsWith("interp_codelets")) {
         return genInterpreterCodeletLinksPage();
      } else if (href.startsWith("hierarchy=")) {
         href = href.substring(href.indexOf('=') + 1);
         Klass obj = getKlassAtAddress(href);
         if (Assert.ASSERTS_ENABLED) {
            Assert.that(obj instanceof InstanceKlass, "class= href with improper InstanceKlass!");
         }
         return genHTMLForKlassHierarchy((InstanceKlass) obj);
      } else if (href.startsWith("cpool=")) {
         href = href.substring(href.indexOf('=') + 1);
         ConstantPool obj = getConstantPoolAtAddress(href);
         if (Assert.ASSERTS_ENABLED) {
            Assert.that(obj instanceof ConstantPool, "cpool= href with improper ConstantPool!");
         }
         return genHTML(obj);
      } else if (href.startsWith("jcore=")) {
         href = href.substring(href.indexOf('=') + 1);
         Klass obj = getKlassAtAddress(href);
         if (Assert.ASSERTS_ENABLED) {
            Assert.that(obj instanceof InstanceKlass, "jcore= href with improper InstanceKlass!");
         }
         return genDumpKlass((InstanceKlass) obj);
      } else if (href.startsWith("jcore_multiple=")) {
         href = href.substring(href.indexOf('=') + 1);
         Formatter buf = new Formatter(genHTML);
         buf.genHTMLPrologue();
         StringTokenizer st = new StringTokenizer(href, ",");
         while (st.hasMoreTokens()) {
            Klass obj = getKlassAtAddress(st.nextToken());
            if (Assert.ASSERTS_ENABLED) {
               Assert.that(obj instanceof InstanceKlass, "jcore_multiple= href with improper InstanceKlass!");
            }

            InstanceKlass kls = (InstanceKlass) obj;
            try {
               dumpKlass(kls);
               buf.append(".class created for ");
               buf.append(genKlassLink(kls));
            } catch(Exception exp) {
               buf.bold("can't .class for " +
                        genKlassTitle(kls) +
                        " : " +
                        exp.getMessage());
            }
            buf.br();
         }

         buf.genHTMLEpilogue();
         return buf.toString();
      } else {
         if (Assert.ASSERTS_ENABLED) {
            Assert.that(false, "unknown href link!");
         }
         return null;
      }
   }
}
</pre>
<div id="after_source_code">
<h2>Other Java examples (source code examples)</h2>
<p>Here is a short list of links related to this Java HTMLGenerator.java source code file:</p>
<ul>
  <li><a href="/java/jwarehouse"><img src="/images/scw/find.png" border="0"> The search page</a></li>
  <li><a href="index.shtml"><img src="/images/scw/folder.png" border="0"> Other Java source code examples at this package level</a></li>
  <li><a href="/java/jwarehouse/about.shtml"><img src="/images/scw/information.png" border="0"> Click here to learn more about this project</a></li>
</ul>
</div>
</td>
</tr>
</table>
</div>
</div>

<div style="padding-top: 1em; width: 310px; margin-left: auto; margin-right: auto; table {border-collapse: collapse; border: none;}; tr {border-collapse: collapse; border: none; text-align: center;};">
<table width="100%" cellspacing="0" cellpadding="0">
  <tr>
      <td colspan="2" style="border-collapse: collapse; border: none; text-align: center;};">
        <em>... this post is sponsored by my books ...</em>
      </td>
  </tr>
  <tr>
      <td width="150" style="border-collapse: collapse; border: none; text-align: center;};">
        <a href="https://kbhr.co/ckbk-v2"><img
           src="/images/books/scala-cookbook-v2-cover-220h.jpg"
           title="The Scala Cookbook, by Alvin Alexander" height="220" />
           <br /><span style="opacity: 0.4;">#1 New Release!</span></a>
      </td>
      <td width="150" style="border-collapse: collapse; border: none; text-align: center; padding-left: 8px;">
        <a href="http://kbhr.co/fps-book"><img
           src="/images/books/functional-programming-simplified-small.jpg"
           title="Functional Programming, Simplified, by Alvin Alexander"
           height="220" />
           <br /><span style="opacity: 0.4;">FP Best Seller</span></a>
      </td>
  </tr>
</table>
<p> </p>
</div>


<div id="whats_new">
<h2>new blog posts</h2>
<div id="whats_new_list">
<ul>
<li><a class="whats_new_link" href="/personal/mindfulness-purposes-motivations-why-be-mindful">The purposes of mindfulness (or, why bother being mindful, and motivation)</a></li>
<li><a class="whats_new_link" href="/scala/how-use-startsWith-tests-match-case-expression">Scala: How to use startsWith tests in match/case expression</a></li>
<li><a class="whats_new_link" href="/personal/ram-dass-glossary-terms-maharaji-yoga">A glossary of terms related to Ram Dass, Maharaj-ji, yoga, Zen, Buddhism, and more</a></li>
<br/>
<li><a class="whats_new_link" href="/java/how-round-double-float-two-decimal-places-format-output">Java: How to round a double (or float) to two decimal places? (formatting output)</a></li>
<li><a class="whats_new_link" href="/photos/free-advanced-scala-3-video-training-course">My free '''Advanced Scala 3''' video training course</a></li>
<li><a class="whats_new_link" href="/misc/free-online-scala-functional-programming-video-training-courses">My free online Scala and FP video training courses</a></li>
<br/>
<li><a class="whats_new_link" href="/misc/ziverge-on-demand-team-extension-service-scala-rust-ai">Ziverge'''s On-Demand Team Extension Service</a></li>
<li><a class="whats_new_link" href="/personal/ram-dass-best-books-rankings-recommendations-maharaj-ji-spirituality">What are Ram Dass'''s best books (recommendations, ranked)</a></li>
<li><a class="whats_new_link" href="/misc/song-mad-as-a-hatter-larkin-poe-schizophrenia-dementia">Mad As a Hatter, by Larkin Poe</a></li>
<br/>
<br/>
</div>
</ul>
</div>


<p> </p>

<p align="center"><font color="#000000" size="2"
face="Verdana,Arial">Copyright 1998-2021 Alvin Alexander, alvinalexander.com<br/>
All Rights Reserved.<br/>
<br/>
A percentage of advertising revenue from<br/>
pages under the <a href="/java/jwarehouse">/java/jwarehouse</a> 
URI on this website is<br/>
paid back to open source projects.</p>


<script>
shuffle(books);
var div = document.getElementById("leftcol");
var pre = '<div style="margin: 0; padding-right: 1.6em"><h2 align="center">favorite books</h2>';
var post = '</div>';
if (adblock) {
  var str = books.slice(0,3).join(" ");
  div.insertAdjacentHTML('beforeend', pre + str + post);
} else {
  var str = books.slice(0,1).join(" ");
  div.insertAdjacentHTML('beforeend', pre + str + post);
}
</script>



<p style="padding-bottom: 80px;"> </p>


</body>