blob: 91993feea8c07842c101498b3c36be5992c4a260 [file] [log] [blame]
/*
* 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></html>");
}
void genHTMLPrologue() {
if (html) append("<html><body>");
}
void genHTMLPrologue(String title) {
if (html) {
append("<html><head><title>");
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 = "&nbsp;&nbsp;";
tab = "&nbsp;&nbsp;&nbsp;&nbsp;";
} 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("&lt;");
break;
case '>':
buf.append("&gt;");
break;
case '&':
buf.append("&amp;");
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;
}
}
}