sa-jdi

tatic ");
    }
    if (acc.isAbstract()) {
      buf.append("abstract ");
    } else if (acc.isFinal()) {
      buf.append("final ");
    }
    if (acc.isStrict()) {
      buf.append("strict ");
    }
    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('/', '.'));
    
    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.getHandle().toString());
    return buf.toString();
  }
  
  protected String genBaseHref()
  {
    return "";
  }
  
  protected String genKlassHref(InstanceKlass klass)
  {
    return genBaseHref() + "klass=" + klass.getHandle();
  }
  
  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 ");
    }
    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(')');
    
    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.getHandle().toString());
    return buf.toString();
  }
  
  protected String genMethodHref(Method m)
  {
    return genBaseHref() + "method=" + m.getHandle();
  }
  
  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");
    
    int length = cpool.getLength();
    for (int index = 1; index < length; index++)
    {
      buf.beginTag("tr");
      buf.cell(Integer.toString(index));
      
      int ctag = cpool.getTags().getByteAt(index);
      switch (ctag)
      {
      case 3: 
        buf.cell("JVM_CONSTANT_Integer");
        buf.cell(Integer.toString(cpool.getIntAt(index)));
        break;
      case 4: 
        buf.cell("JVM_CONSTANT_Float");
        buf.cell(Float.toString(cpool.getFloatAt(index)));
        break;
      case 5: 
        buf.cell("JVM_CONSTANT_Long");
        buf.cell(Long.toString(cpool.getLongAt(index)));
        
        index++;
        break;
      case 6: 
        buf.cell("JVM_CONSTANT_Double");
        buf.cell(Double.toString(cpool.getDoubleAt(index)));
        
        index++;
        break;
      case 100: 
        buf.cell("JVM_CONSTANT_UnresolvedClass");
        buf.cell(cpool.getSymbolAt(index).asString());
        break;
      case 104: 
        buf.cell("JVM_CONSTANT_UnresolvedClassInError");
        buf.cell(cpool.getSymbolAt(index).asString());
        break;
      case 7: 
        buf.cell("JVM_CONSTANT_Class");
        Klass klass = (Klass)cpool.getObjAt(index);
        if ((klass instanceof InstanceKlass)) {
          buf.cell(genKlassLink((InstanceKlass)klass));
        } else {
          buf.cell(klass.getName().asString().replace('/', '.'));
        }
        break;
      case 102: 
        buf.cell("JVM_CONSTANT_UnresolvedString");
        buf.cell("\"" + escapeHTMLSpecialChars(cpool.getSymbolAt(index).asString()) + "\"");
        
        break;
      case 1: 
        buf.cell("JVM_CONSTANT_Utf8");
        buf.cell("\"" + escapeHTMLSpecialChars(cpool.getSymbolAt(index).asString()) + "\"");
        
        break;
      case 8: 
        buf.cell("JVM_CONSTANT_String");
        buf.cell("\"" + escapeHTMLSpecialChars(OopUtilities.stringOopToString(cpool.getObjAt(index))) + "\"");
        
        break;
      case 9: 
        buf.cell("JVM_CONSTANT_Fieldref");
        buf.cell(genLowHighShort(cpool.getIntAt(index)));
        break;
      case 10: 
        buf.cell("JVM_CONSTANT_Methodref");
        buf.cell(genLowHighShort(cpool.getIntAt(index)));
        break;
      case 11: 
        buf.cell("JVM_CONSTANT_InterfaceMethodref");
        buf.cell(genLowHighShort(cpool.getIntAt(index)));
        break;
      case 12: 
        buf.cell("JVM_CONSTANT_NameAndType");
        buf.cell(genLowHighShort(cpool.getIntAt(index)));
        break;
      case 101: 
        buf.cell("JVM_CONSTANT_ClassIndex");
        buf.cell(Integer.toString(cpool.getIntAt(index)));
        break;
      case 103: 
        buf.cell("JVM_CONSTANT_StringIndex");
        buf.cell(Integer.toString(cpool.getIntAt(index)));
        break;
      case 15: 
        buf.cell("JVM_CONSTANT_MethodHandle");
        buf.cell(genLowHighShort(cpool.getIntAt(index)));
        break;
      case 16: 
        buf.cell("JVM_CONSTANT_MethodType");
        buf.cell(Integer.toString(cpool.getIntAt(index)));
        break;
      case 17: 
      case 18: 
        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.getHandle();
  }
  
  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.getHandle().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();
          Oop obj = cpool.getObjAt(cpIndex);
          if ((obj instanceof Symbol)) {
            buf.li(((Symbol)obj).asString().replace('/', '.'));
          } else {
            buf.li(genKlassLink((InstanceKlass)obj));
          }
        }
        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 during bytecode processing");
            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;
            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())
            {
              Oop oop = ldc.getKlass();
              if ((oop instanceof Klass))
              {
                buf.append("<a href='");
                buf.append(genKlassHref((InstanceKlass)oop));
                buf.append("'>");
                buf.append(instrStr);
                buf.append("</a>");
              }
              else
              {
                buf.append(instrStr);
              }
            }
            else
            {
              buf.append(instrStr);
            }
          }
          else
          {
            buf.append(instrStr);
          }
          buf.endTag("td");
          buf.endTag("tr");
        }
        
        public void epilogue()
        {
          buf.endTable();
        }
      });
      TypeArray exceptionTable = method.getExceptionTable();
      
      int numEntries = (int)exceptionTable.getLength() / 4;
      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 += 4)
        {
          buf.beginTag("tr");
          buf.cell(Integer.toString(exceptionTable.getIntAt(e)));
          buf.cell(Integer.toString(exceptionTable.getIntAt(e + 1)));
          buf.cell(Integer.toString(exceptionTable.getIntAt(e + 2)));
          short cpIndex = (short)exceptionTable.getIntAt(e + 3);
          Oop obj = cpIndex == 0 ? null : cpool.getObjAt(cpIndex);
          if (obj == null) {
            buf.cell("Any");
          } else if ((obj instanceof Symbol)) {
            buf.cell(((Symbol)obj).asString().replace('/', '.'));
          } else {
            buf.cell(genKlassLink((InstanceKlass)obj));
          }
          buf.endTag("tr");
        }
        buf.endTable();
      }
      buf.h3("Constant Pool");
      buf.append(genConstantPoolLink(cpool));
      buf.genHTMLEpilogue();
      return buf.toString();
    }
    catch (Exception exp)
    {
      return genHTMLErrorMessage(exp);
    }
  }
  
  protected Disassembler createDisassembler(long startPc, byte[] code)
  {
    return getCPUHelper().createDisassembler(startPc, code);
  }
  
  protected SymbolFinder createSymbolFinder()
  {
    return new DummySymbolFinder();
  }
  
  public String genHTMLForAddress(String addrStr)
  {
    return genHTML(parseAddress(addrStr));
  }
  
  public String genHTML(sun.jvm.hotspot.debugger.Address pc)
  {
    CodeBlob blob = null;
    try
    {
      blob = VM.getVM().getCodeCache().findBlobUnsafe(pc);
    }
    catch (Exception exp) {}
    if (blob != null)
    {
      if ((blob instanceof NMethod)) {
        return genHTML((NMethod)blob);
      }
      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);
    }
    if (VM.getVM().getCodeCache().contains(pc)) {
      return "Unknown location in the CodeCache: " + pc;
    }
    try
    {
      Oop obj = getOopAtAddress(pc);
      if (obj != null)
      {
        if ((obj instanceof Method)) {
          return genHTML((Method)obj);
        }
        if ((obj instanceof InstanceKlass)) {
          return genHTML((InstanceKlass)obj);
        }
        if ((obj instanceof ConstantPool)) {
          return genHTML((ConstantPool)obj);
        }
      }
    }
    catch (Exception exp) {}
    return genHTMLForRawDisassembly(pc, null);
  }
  
  protected byte[] readBuffer(sun.jvm.hotspot.debugger.Address addr, int size)
  {
    byte[] buf = new byte[size];
    for (int b = 0; b < size; b++) {
      buf[b] = addr.getJByteAt(b);
    }
    return buf;
  }
  
  public String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address startPc, int size)
  {
    try
    {
      return genHTMLForRawDisassembly(startPc, null, readBuffer(startPc, size));
    }
    catch (Exception exp)
    {
      return genHTMLErrorMessage(exp);
    }
  }
  
  protected String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address startPc, String prevPCs)
  {
    try
    {
      return genHTMLForRawDisassembly(startPc, prevPCs, readBuffer(startPc, 200));
    }
    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(long currentPc, sun.jvm.hotspot.asm.Address addr)
  {
    String href = null;
    if ((addr instanceof PCRelativeAddress))
    {
      PCRelativeAddress pcRelAddr = (PCRelativeAddress)addr;
      href = genPCHref(currentPc + pcRelAddr.getDisplacement());
    }
    else if ((addr instanceof DirectAddress))
    {
      href = genPCHref(((DirectAddress)addr).getValue());
    }
    return href;
  }
  
  class RawCodeVisitor
    implements InstructionVisitor
  {
    private int instrSize = 0;
    private HTMLGenerator.Formatter buf;
    private SymbolFinder symFinder = createSymbolFinder();
    
    RawCodeVisitor(HTMLGenerator.Formatter buf)
    {
      this.buf = buf;
    }
    
    public int getInstructionSize()
    {
      return instrSize;
    }
    
    public void prologue() {}
    
    public void visit(long currentPc, Instruction instr)
    {
      String href = null;
      if (instr.isCall())
      {
        CallInstruction call = (CallInstruction)instr;
        sun.jvm.hotspot.asm.Address addr = call.getBranchDestination();
        href = genPCHref(currentPc, addr);
      }
      instrSize += instr.getSize();
      buf.append("0x");
      buf.append(Long.toHexString(currentPc));
      buf.append(':');
      buf.append(tab);
      if (href != null) {
        buf.link(href, instr.asString(currentPc, symFinder));
      } else {
        buf.append(instr.asString(currentPc, symFinder));
      }
      buf.br();
    }
    
    public void epilogue() {}
  }
  
  protected String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address addr, String prevPCs, byte[] code)
  {
    try
    {
      long startPc = addressToLong(addr);
      Disassembler disasm = createDisassembler(startPc, code);
      Formatter buf = new Formatter(genHTML);
      buf.genHTMLPrologue("Disassembly @0x" + Long.toHexString(startPc));
      if ((prevPCs != null) && (genHTML))
      {
        buf.beginTag("p");
        buf.link(genMultPCHref(prevPCs), "show previous code ..");
        buf.endTag("p");
      }
      buf.h3("Code");
      RawCodeVisitor visitor = new RawCodeVisitor(buf);
      disasm.decode(visitor);
      if (genHTML) {
        buf.beginTag("p");
      }
      Formatter tmpBuf = new Formatter(genHTML);
      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, PCDesc pcDesc)
  {
    ScopeDesc sd = nm.getScopeDescAt(pcDesc.getRealPC(nm));
    Formatter buf = new Formatter(genHTML);
    Formatter tabs = new Formatter(genHTML);
    tabs.append(tab + tab + tab);
    
    buf.beginTag("pre");
    genScope(buf, tabs, sd);
    
    tabs = new Formatter(genHTML);
    tabs.append(tab + tab + tab);
    
    genScObjInfo(buf, tabs, sd);
    buf.endTag("pre");
    
    buf.append(genOopMapInfo(nm, pcDesc));
    
    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);
      if ((obj instanceof InstanceKlass))
      {
        InstanceKlass kls = (InstanceKlass)obj;
        buf.append(" " + kls.getName().asString() + "={");
        int flen = ov.fieldsSize();
        
        TypeArray klfields = kls.getFields();
        int klen = (int)klfields.getLength();
        
        ConstantPool cp = kls.getConstants();
        int findex = 0;
        for (int index = 0; index < klen; index += InstanceKlass.NEXT_OFFSET)
        {
          int accsFlags = klfields.getShortAt(index + InstanceKlass.ACCESS_FLAGS_OFFSET);
          int nameIndex = klfields.getShortAt(index + InstanceKlass.NAME_INDEX_OFFSET);
          AccessFlags access = new AccessFlags(accsFlags);
          if (!access.isStatic())
          {
            ScopeValue svf = ov.getFieldAt(findex++);
            String fstr = scopeValueAsString(sd, svf);
            Symbol f_name = cp.getSymbolAt(nameIndex);
            buf.append(" [" + f_name.asString() + " :" + index + "]=(#" + fstr + ")");
          }
        }
        buf.append(" }");
      }
      else
      {
        buf.append(" ");
        int flen = ov.fieldsSize();
        if ((obj instanceof TypeArrayKlass))
        {
          TypeArrayKlass kls = (TypeArrayKlass)obj;
          buf.append(kls.getElementTypeName() + "[" + flen + "]");
        }
        else if ((obj instanceof ObjArrayKlass))
        {
          ObjArrayKlass kls = (ObjArrayKlass)obj;
          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();
          for (;;)
          {
            ndim--;
            if (ndim <= 0) {
              break;
            }
            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);
    
    buf.beginTable(0);
    
    Object omvIterator = new Object()
    {
      final HTMLGenerator.Formatter iterate(OopMapStream oms, String type, boolean printContentReg)
      {
        HTMLGenerator.Formatter tmpBuf = new HTMLGenerator.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)
          {
            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 HTMLGenerator.Formatter(genHTML);
      }
    };
    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() <= 0L)) {
      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)
      {
        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)
      {
        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(NMethod nmethod)
  {
    try
    {
      Formatter buf = new Formatter(genHTML);
      buf.genHTMLPrologue(genNMethodTitle(nmethod));
      buf.h3("Method");
      buf.append(genMethodAndKlassLink(nmethod.getMethod()));
      
      buf.h3("Compiled Code");
      sun.jvm.hotspot.debugger.Address instsBegin = nmethod.instsBegin();
      sun.jvm.hotspot.debugger.Address instsEnd = nmethod.instsEnd();
      int instsSize = nmethod.instsSize();
      long startPc = addressToLong(instsBegin);
      byte[] code = new byte[instsSize];
      for (int i = 0; i < code.length; i++) {
        code[i] = instsBegin.getJByteAt(i);
      }
      final long verifiedEntryPoint = addressToLong(nmethod.getVerifiedEntryPoint());
      final long entryPoint = addressToLong(nmethod.getEntryPoint());
      final Map safepoints = nmethod.getSafepoints();
      
      final SymbolFinder symFinder = createSymbolFinder();
      Disassembler disasm = createDisassembler(startPc, code);
      
      disasm.decode(new InstructionVisitor()
      {
        public void prologue() {}
        
        public void visit(long currentPc, Instruction instr)
        {
          String href = null;
          if (instr.isCall())
          {
            CallInstruction call = (CallInstruction)instr;
            sun.jvm.hotspot.asm.Address addr = call.getBranchDestination();
            href = genPCHref(currentPc, addr);
          }
          if (currentPc == verifiedEntryPoint)
          {
            entryPoint.bold("Verified Entry Point");entryPoint.br();
          }
          if (currentPc == safepoints)
          {
            entryPoint.bold(">Entry Point");entryPoint.br();
          }
          PCDesc pcDesc = (PCDesc)symFinder.get(longToAddress(currentPc));
          if (pcDesc != null) {
            entryPoint.append(genSafepointInfo(val$nmethod, pcDesc));
          }
          entryPoint.append("0x");
          entryPoint.append(Long.toHexString(currentPc));
          entryPoint.append(':');
          entryPoint.append(tab);
          if (href != null) {
            entryPoint.link(href, instr.asString(currentPc, val$symFinder));
          } else {
            entryPoint.append(instr.asString(currentPc, val$symFinder));
          }
          entryPoint.br();
        }
        
        public void epilogue() {}
      });
      sun.jvm.hotspot.debugger.Address stubBegin = nmethod.stubBegin();
      if (stubBegin != null)
      {
        sun.jvm.hotspot.debugger.Address stubEnd = nmethod.stubEnd();
        buf.h3("Stub");
        long stubStartPc = addressToLong(stubBegin);
        long stubEndPc = addressToLong(stubEnd);
        int range = (int)(stubEndPc - stubStartPc);
        byte[] stubCode = readBuffer(stubBegin, range);
        Disassembler disasm2 = createDisassembler(stubStartPc, stubCode);
        disasm2.decode(new InstructionVisitor()
        {
          public void prologue() {}
          
          public void visit(long currentPc, Instruction instr)
          {
            String href = null;
            if (instr.isCall())
            {
              CallInstruction call = (CallInstruction)instr;
              sun.jvm.hotspot.asm.Address addr = call.getBranchDestination();
              href = genPCHref(currentPc, addr);
            }
            if (currentPc == verifiedEntryPoint)
            {
              entryPoint.bold("Verified Entry Point");entryPoint.br();
            }
            if (currentPc == safepoints)
            {
              entryPoint.bold(">Entry Point");entryPoint.br();
            }
            PCDesc pcDesc = (PCDesc)symFinder.get(longToAddress(currentPc));
            if (pcDesc != null) {
              entryPoint.append(genSafepointInfo(val$nmethod, pcDesc));
            }
            entryPoint.append("0x");
            entryPoint.append(Long.toHexString(currentPc));
            entryPoint.append(':');
            entryPoint.append(tab);
            if (href != null) {
              entryPoint.link(href, instr.asString(currentPc, val$symFinder));
            } else {
              entryPoint.append(instr.asString(currentPc, val$symFinder));
            }
            entryPoint.br();
          }
     
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

Further reading...

For more information on Java 1.5 Tiger, you may find Java 1.5 Tiger, A developer's Notebook by D. Flanagan and B. McLaughlin from O'Reilly of interest.

New!JAR listings


Copyright 2006-2019. Infinite Loop Ltd