diff agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children 873ec3787992
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,1162 @@
+/*
+ * Copyright 2004-2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *  
+ */
+
+// shorter names for SA packages
+
+
+// SA package name abbreviations are kept in 'sapkg' object
+// to avoid global namespace pollution
+var sapkg = new Object();
+
+sapkg.hotspot = Packages.sun.jvm.hotspot;
+sapkg.asm = sapkg.hotspot.asm;
+sapkg.bugspot = sapkg.hotspot.bugspot;
+sapkg.c1 = sapkg.hotspot.c1;
+sapkg.code = sapkg.hotspot.code;
+sapkg.compiler = sapkg.hotspot.compiler;
+
+// 'debugger' is a JavaScript keyword :-(
+// sapkg.debugger = sapkg.hotspot.debugger;
+
+sapkg.interpreter = sapkg.hotspot.interpreter;
+sapkg.livejvm = sapkg.hotspot.livejvm;
+sapkg.jdi = sapkg.hotspot.jdi;
+sapkg.memory = sapkg.hotspot.memory;
+sapkg.oops = sapkg.hotspot.oops;
+sapkg.runtime = sapkg.hotspot.runtime;
+sapkg.tools = sapkg.hotspot.tools;
+sapkg.types = sapkg.hotspot.types;
+sapkg.ui = sapkg.hotspot.ui;
+sapkg.utilities = sapkg.hotspot.utilities;
+
+// SA singletons are kept in 'sa' object
+var sa = new Object();
+sa.vm = sapkg.runtime.VM.getVM();
+sa.dbg = sa.vm.getDebugger();
+sa.cdbg = sa.dbg.CDebugger;
+sa.heap = sa.vm.universe.heap();
+sa.systemDictionary = sa.vm.systemDictionary;
+sa.sysDict = sa.systemDictionary;
+sa.symbolTable = sa.vm.symbolTable;
+sa.symTbl = sa.symbolTable;
+sa.threads = sa.vm.threads;
+sa.interpreter = sa.vm.interpreter;
+sa.typedb = sa.vm.typeDataBase;
+sa.codeCache = sa.vm.codeCache;
+// 'objHeap' is different from 'heap'!. 
+// This is SA's Oop factory and heap-walker
+sa.objHeap = sa.vm.objectHeap;
+
+// few useful global variables
+var OS = sa.vm.OS;
+var CPU = sa.vm.CPU;
+var LP64 = sa.vm.LP64;
+var isClient = sa.vm.clientCompiler;
+var isServer = sa.vm.serverCompiler;
+var isCore = sa.vm.isCore();
+var addressSize = sa.vm.addressSize;
+var oopSize = sa.vm.oopSize;
+
+// this "main" function is called immediately
+// after loading this script file
+function main(globals, jvmarg) {
+  // wrap a sun.jvm.hotspot.utilities.soql.ScriptObject
+  // object so that the properties of it can be accessed
+  // in natural object.field syntax.
+  function wrapScriptObject(so) {
+    function unwrapScriptObject(wso) {
+      var objType = typeof(wso);
+      if ((objType == 'object' ||
+           objType == 'function')
+          && "__wrapped__" in wso) {
+        return wso.__wrapped__;
+      } else {
+        return wso;
+      }
+    }
+
+    function prepareArgsArray(array) {
+      var args = new Array(array.length);
+      for (var a = 0; a < array.length; a++) {
+        var elem = array[a];
+        elem = unwrapScriptObject(elem);
+        if (typeof(elem) == 'function') {
+          args[a] = new sapkg.utilities.soql.Callable() {
+            call: function(myargs) {
+              var tmp = new Array(myargs.length);
+              for (var i = 0; i < myargs.length; i++) {
+                tmp[i] = wrapScriptObject(myargs[i]);
+              }
+              return elem.apply(this, tmp);
+            }
+          }
+        } else {
+          args[a] = elem;
+        }
+      }
+      return args;
+    }
+
+    if (so instanceof sapkg.utilities.soql.ScriptObject) {
+      return new JSAdapter() {
+        __getIds__: function() {                  
+          return so.getIds();         
+        },
+  
+        __has__ : function(name) {
+          if (typeof(name) == 'number') {
+            return so["has(int)"](name);
+          } else {
+            if (name == '__wrapped__') {
+              return true;
+            } else if (so["has(java.lang.String)"](name)) {
+              return true;
+            } else if (name.equals('toString')) {
+              return true;
+            } else {
+              return false;
+            }
+          }
+        },
+  
+        __delete__ : function(name) {
+          if (typeof(name) == 'number') {
+            return so["delete(int)"](name);
+          } else {
+            return so["delete(java.lang.String)"](name);
+          }
+        },
+  
+        __get__ : function(name) {
+          if (! this.__has__(name)) {
+            return undefined;
+          }
+          if (typeof(name) == 'number') {
+            return wrapScriptObject(so["get(int)"](name));
+          } else {
+            if (name == '__wrapped__') {
+              return so;
+            } else {
+              var value = so["get(java.lang.String)"](name);
+              if (value instanceof sapkg.utilities.soql.Callable) {
+                return function() {
+                  var args = prepareArgsArray(arguments);
+                  var r;
+                  try {
+                    r = value.call(args);
+                  } catch (e) {
+                    println("call to " + name + " failed!");
+                    throw e;
+                  }
+                  return wrapScriptObject(r);
+                }
+              } else if (name == 'toString') {
+                return function() { 
+                  return so.toString();
+                }
+              } else {
+                return wrapScriptObject(value);
+              }
+            }
+          }
+        }
+      };
+    } else {
+      return so;
+    }
+  }
+
+  // set "jvm" global variable that wraps a 
+  // sun.jvm.hotspot.utilities.soql.JSJavaVM instance
+  if (jvmarg != null) {
+    jvm = wrapScriptObject(jvmarg);
+    // expose "heap" global variable
+    heap = jvm.heap;
+  }
+
+  // expose all "function" type properties of
+  // sun.jvm.hotspot.utilitites.soql.JSJavaScriptEngine
+  // as global functions here.
+  globals = wrapScriptObject(globals);
+  for (var prop in globals) {    
+    if (typeof(globals[prop]) == 'function') {
+      this[prop] = globals[prop];
+    }    
+  }
+
+  // define "writeln" and "write" if not defined
+  if (typeof(writeln) == 'undefined') {
+    writeln = println;
+  }
+
+  if (typeof(write) == 'undefined') {
+    write = print;
+  }
+
+  // "registerCommand" function is defined if we
+  // are running as part of "CLHSDB" tool. CLHSDB
+  // tool exposes Unix-style commands. 
+
+  // if "registerCommand" function is defined
+  // then register few global functions as "commands".
+  if (typeof(registerCommand) == 'function') {
+    this.printDis = function(addr, len) {
+      if (!addr) {
+         writeln("Usage: dis address [ length ]");
+      } else {
+         dis(addr, len);
+      }
+    }
+    registerCommand("dis", "dis address [ length ]", "printDis");
+
+    this.jclass = function(name) {
+      if (typeof(name) == "string") {
+         var clazz = sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name);
+         if (clazz) {
+             writeln(clazz.getName().asString() + " @" + clazz.getHandle().toString());
+         } else {
+             writeln("class not found: " + name);
+         } 
+      } else {
+         writeln("Usage: class name");
+      }
+    }
+    registerCommand("class", "class name", "jclass");
+
+    this.jclasses = function() {
+      forEachKlass(function (clazz) {
+        writeln(clazz.getName().asString() + " @" + clazz.getHandle().toString()); 
+      });
+    }
+    registerCommand("classes", "classes", "jclasses");
+
+    this.printJDis = function(addr) {
+      if (!addr) {
+         writeln("Usage: jdis address");
+      } else {
+         jdis(addr);
+      }
+    }
+    registerCommand("jdis", "jdis address", "printJDis");
+
+    this.dclass = function(clazz, dir) {
+      if (!clazz) {
+         writeln("Usage: dumpclass { address | name } [ directory ]");
+      } else {
+         if (!dir) { dir = "."; }
+         dumpClass(clazz, dir);
+      }
+    }
+    registerCommand("dumpclass", "dumpclass { address | name } [ directory ]", "dclass");
+    registerCommand("dumpheap", "dumpheap [ file ]", "dumpHeap");
+
+    this.jseval = function(str) {
+      if (!str) {
+         writeln("Usage: jseval script");
+      } else {
+         var res = eval(str);
+         if (res) { writeln(res); }
+      }
+    }
+    registerCommand("jseval", "jseval script", "jseval");
+
+    this.jsload = function(file) {
+      if (!file) {
+         writeln("Usage: jsload file");
+      } else {
+         load(file);
+      }
+    }
+    registerCommand("jsload", "jsload file", "jsload");
+
+    this.printMem = function(addr, len) {
+      if (!addr) {
+         writeln("Usage: mem [ length ]");
+      } else {
+         mem(addr, len);
+      }
+    }
+    registerCommand("mem", "mem address [ length ]", "printMem");
+
+    this.sysProps = function() {
+      for (var i in jvm.sysProps) {
+         writeln(i + ' = ' + jvm.sysProps[i]);
+      }
+    }
+    registerCommand("sysprops", "sysprops", "sysProps");
+
+    this.printWhatis = function(addr) {
+      if (!addr) {
+         writeln("Usage: whatis address");
+      } else {
+         writeln(whatis(addr));
+      }
+    }
+    registerCommand("whatis", "whatis address", "printWhatis");
+  }  
+}
+
+// debugger functionality
+
+// string-to-Address
+function str2addr(str) {
+   return sa.dbg.parseAddress(str);
+}
+
+// number-to-Address
+if (addressSize == 4) {
+   eval("function num2addr(num) { \
+            return str2addr('0x' + java.lang.Integer.toHexString(0xffffffff & num)); \
+         }");
+} else {
+   eval("function num2addr(num) { \
+            return str2addr('0x' + java.lang.Long.toHexString(num));  \
+         }");
+}
+
+// generic any-type-to-Address
+// use this convenience function to accept address in any
+// format -- number, string or an Address instance.
+function any2addr(addr) {
+   var type = typeof(addr);
+   if (type == 'number') {
+      return num2addr(addr);
+   } else if (type == 'string') {         
+      return str2addr(addr);
+   } else {
+      return addr;
+   }
+}
+
+// Address-to-string
+function addr2str(addr) {
+   if (addr == null) {
+      return (addressSize == 4)? '0x00000000' : '0x0000000000000000';
+   } else {
+      return addr + '';
+   }
+}
+
+// Address-to-number
+function addr2num(addr) {
+   return sa.dbg.getAddressValue(addr);
+}
+
+// symbol-to-Address
+function sym2addr(dso, sym) {
+   return sa.dbg.lookup(dso, sym);
+}
+
+// returns the ClosestSymbol or null
+function closestSymbolFor(addr) {
+   if (sa.cdbg == null) {
+      // no CDebugger support, return null
+      return null;
+   } else {
+      var dso = sa.cdbg.loadObjectContainingPC(addr);
+      if (dso != null) {
+         return dso.closestSymbolToPC(addr);
+      } else {
+         return null;
+      }
+   }
+}
+
+// Address-to-symbol
+// returns nearest symbol as string if found
+// else returns address as string
+function addr2sym(addr) {
+    var sym = closestSymbolFor(addr);
+    if (sym != null)  {
+       return sym.name + '+' + sym.offset;
+    } else {
+       return addr2str(addr);
+    }
+}
+
+// read 'num' bytes at 'addr' and return an array as result.
+// returns Java byte[] type result and not a JavaScript array.
+function readBytesAt(addr, num) {
+   addr = any2addr(addr);
+   var res = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, num);
+   var i;
+   for (i = 0; i < num; i++) {
+      res[i] = addr.getJByteAt(i);
+   }
+   return res;
+}
+
+// read 'num' words at 'addr' and return an array as result.
+// returns Java long[] type result and not a JavaScript array.
+function readWordsAt(addr, num) {
+   addr = any2addr(addr);
+   var res = java.lang.reflect.Array.newInstance(java.lang.Long.TYPE, num);
+   var i;
+   for (i = 0; i < num; i++) {
+      res[i] = addr2num(addr.getAddressAt(i * addressSize));
+   }
+   return res;
+}
+
+// read the 'C' string at 'addr'
+function readCStrAt(addr) {
+   addr = any2addr(addr);
+   return sapkg.utilities.CStringUtilities.getString(addr);
+}
+
+// read the length of the 'C' string at 'addr'
+function readCStrLen(addr) {
+   addr = any2addr(addr);
+   return sapkg.utilities.CStringUtilities.getStringLength(addr);
+}
+
+// iterate through ThreadList of CDebugger
+function forEachThread(callback) {
+   if (sa.cdbg == null) {
+      // no CDebugger support
+      return;
+   } else {
+      var itr = sa.cdbg.threadList.iterator();
+      while (itr.hasNext()) {
+         if (callback(itr.next()) == false) return;
+      }
+   }
+}
+
+// read register set of a ThreadProxy as name-value pairs
+function readRegs(threadProxy) {
+   var ctx = threadProxy.context;
+   var num = ctx.numRegisters;
+   var res = new Object();
+   var i;
+   for (i = 0; i < num; i++) {
+      res[ctx.getRegisterName(i)]= addr2str(ctx.getRegisterAsAddress(i));
+   }
+   return res;
+}
+
+// print register set for a given ThreaProxy
+function regs(threadProxy) {
+   var res = readRegs(threadProxy);
+   for (i in res) {
+      writeln(i, '=', res[i]);
+   }
+}
+
+// iterate through each CFrame of a given ThreadProxy
+function forEachCFrame(threadProxy, callback) {   
+   if (sa.cdbg == null) {
+      // no CDebugger support
+      return;
+   } else {
+      var cframe = sa.cdbg.topFrameForThread(threadProxy);
+      while (cframe != null) {
+         if (callback(cframe) == false) return;
+         cframe = cframe.sender();
+      }
+   }
+}
+
+// iterate through list of load objects (DLLs, DSOs)
+function forEachLoadObject(callback) {
+   if (sa.cdbg == null) {
+      // no CDebugger support
+      return;
+   } else {
+      var itr = sa.cdbg.loadObjectList.iterator();
+      while (itr.hasNext()) {
+         if (callback(itr.next()) == false) return;
+      }
+   }
+}
+
+// print 'num' words at 'addr'
+function mem(addr, num) {
+   if (num == undefined) {
+      num = 1;
+   }
+   addr = any2addr(addr);   
+   var i;
+   for (i = 0; i < num; i++) {
+      var value = addr.getAddressAt(0);      
+      writeln(addr2sym(addr) + ':', addr2str(value)); 
+      addr = addr.addOffsetTo(addressSize);      
+   }
+   writeln();
+}
+
+// return the disassemble class for current CPU
+function disassemblerClass() {
+   var DisAsmClass;
+   if (CPU == 'x86') {
+      DisAsmClass = sapkg.asm.x86.X86Disassembler;
+   } else if (CPU == 'sparc') {
+      DisAsmClass = sapkg.asm.sparc.SPARCV9Disassembler;
+   }
+   return DisAsmClass;
+}
+
+// print native code disassembly of 'num' bytes at 'addr'
+function dis(addr, num) {
+   addr = any2addr(addr);
+   var nmethod = findNMethod(addr);
+   if (nmethod != null) {
+      // disassemble it as nmethod
+      nmethoddis(nmethod);     
+   } else {
+      // raw disassembly
+      if (num == undefined) {
+         // size of one SPARC instruction and
+         // unknown number of Intel instructions.
+         num = 4;
+      }
+      DisAsmClass = disassemblerClass();
+      if (DisAsmClass == undefined) {
+         // unsupported CPU
+         writeln(CPU + " is not yet supported!");
+         return;
+      }
+
+      var bytes = readBytesAt(addr, num);
+      var disAsm = new DisAsmClass(addr2num(addr), bytes);
+      disAsm.decode(new sapkg.asm.InstructionVisitor() {
+                      visit: function (pc, instr) {
+                         write(addr2sym(num2addr(pc)) + ':', '\t');
+                         writeln(instr.asString(pc, 
+                                 new sapkg.asm.SymbolFinder() {
+                                    getSymbolFor: function(addr) {
+                                       return addr2sym(num2addr(addr));
+                                    }
+                                 }));
+                      }
+                   });
+   }
+}
+
+// System dictionary functions
+
+// find InstanceKlass by name
+function findInstanceKlass(name) {
+   return sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name);
+}
+
+// get Java system loader (i.e., application launcher loader)
+function systemLoader() {
+   return sa.sysDict.javaSystemLoader();
+}
+
+// iterate system dictionary for each 'Klass' 
+function forEachKlass(callback) {
+   var VisitorClass = sapkg.memory.SystemDictionary.ClassVisitor;
+   var visitor = new VisitorClass() { visit: callback };
+   sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassVisitor)"](visitor);
+}
+
+// iterate system dictionary for each 'Klass' and initiating loader
+function forEachKlassAndLoader(callback) {
+   var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor;
+   var visitor = new VisitorClass() { visit: callback };
+   sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassAndLoaderVisitor)"](visitor);
+}
+
+// iterate system dictionary for each primitive array klass
+function forEachPrimArrayKlass(callback) {
+   var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor;
+   sa.sysDict.primArrayClassesDo(new VisitorClass() { visit: callback });
+}
+
+// (hotspot) symbol table functions
+
+// String-to-Symbol
+function str2sym(str) {
+   return sa.symTbl.probe(str);
+}
+
+// Symbol-to-String
+function sym2str(sym) {
+   return sym.asString();
+}
+
+// oop functions
+
+// Address-to-Oop
+function addr2oop(addr) {
+   addr = any2addr(addr);
+   return sa.objHeap.newOop(addr.addOffsetToAsOopHandle(0));
+}
+
+// Oop-to-Address
+function oop2addr(oop) {
+   return oop.handle;
+}
+
+// 'oop' to higher-level java object wrapper in which for(i in o) 
+// works by iterating java level fields and javaobject.javafield
+// syntax works.
+function oop2obj(oop) {
+   return object(addr2str(oop.handle));
+}
+
+// higher level java object wrapper to oop
+function obj2oop(obj) {
+   return addr2oop(str2addr(address(obj)));
+}
+
+// Java heap iteration
+
+// iterates Java heap for each Oop
+function forEachOop(callback) {
+   sa.objHeap.iterate(new sapkg.oops.HeapVisitor() { doObj: callback });
+}
+
+// iterates Java heap for each Oop of given 'klass'.
+// 'includeSubtypes' tells whether to include objects 
+// of subtypes of 'klass' or not
+function forEachOopOfKlass(callback, klass, includeSubtypes) {
+   if (klass == undefined) {
+       klass = findInstanceKlass("java.lang.Object");
+   }
+
+   if (includeSubtypes == undefined) {
+      includeSubtypes = true;
+   }
+   sa.objHeap.iterateObjectsOfKlass(
+        new sapkg.oops.HeapVisitor() { doObj: callback },
+        klass, includeSubtypes);
+}
+
+// code cache functions
+
+// iterates CodeCache for each 'CodeBlob'
+function forEachCodeBlob(callback) {
+   var VisitorClass = sapkg.code.CodeCacheVisitor;
+   sa.codeCache.iterate(new VisitorClass() { visit: callback });
+}
+
+// find the ClodBlob (if any) that contains given address
+function findCodeBlob(addr) {
+   addr = any2addr(addr);
+   return sa.codeCache.findBlobUnsafe(addr);
+}
+
+// find the NMethod (if any) that contains given address
+function findNMethod(addr) {
+   var codeBlob = findCodeBlob(addr);
+   return (codeBlob != null && codeBlob.isNMethod())? codeBlob : null;
+}
+
+// returns PcDesc at given address or null
+function pcDescAt(addr) {
+   addr = any2addr(addr);
+   var nmethod = findNMethod(addr);
+   return (nmethod != null)? nmethod.safepoints.get(addr) : null;
+}
+
+// helpers for nmethod disassembler
+function printScope(scopeDesc) {
+   if (scopeDesc == null) {
+      return;
+   }
+   printScope(scopeDesc.sender());
+   var method = scopeDesc.method;
+   var bci = scopeDesc.BCI;
+   var line = -1;
+   if (method.hasLineNumberTable()) {
+      line = method.getLineNumberFromBCI(bci);
+   }
+  
+   write('\t', method.externalNameAndSignature(), '@', method.handle, 'bci=' + bci);
+   if (line != -1) { 
+      write('line=' + line); 
+   }
+   writeln();
+}
+
+function printSafepointInfo(nmethod, pcDesc) {
+   var scopeDesc = nmethod.getScopeDescAt(
+                      pcDesc.getRealPC(nmethod),
+                      pcDesc.isAtCall());
+   printScope(scopeDesc);
+}
+
+// print disassembly for a given nmethod
+function nmethoddis(nmethod) {
+   var DisAsmClass = disassemblerClass();
+   if (DisAsmClass == undefined) {
+      writeln(CPU + " is not yet supported!");
+      return;
+   }
+
+   var method = nmethod.method;
+   writeln('NMethod:', method.externalNameAndSignature(), '@', method.handle);
+
+   var codeBegin = nmethod.codeBegin();
+   var codeEnd = nmethod.codeEnd();
+   var size = codeEnd.minus(codeBegin);
+   var code = readBytesAt(codeBegin, size);
+   var startPc = addr2num(codeBegin);
+   var verifiedEntryPoint = addr2num(nmethod.verifiedEntryPoint);
+   var entryPoint = addr2num(nmethod.entryPoint);
+   var interpreterEntryPoint = addr2num(nmethod.interpreterEntryPointOrNull);
+   var safepoints = nmethod.safepoints;
+   var disAsm = new DisAsmClass(startPc, code);
+   disAsm.decode(new sapkg.asm.InstructionVisitor() {
+                    visit: function(curPc, instr) {
+                       if (curPc == verifiedEntryPoint) {
+                          writeln();                                    
+                          writeln("Verified Entry Point:");
+                       }
+                       if (curPc == entryPoint) {
+                          writeln();
+                          writeln("Entry Point:");                     
+                       }
+                       if (curPc == interpreterEntryPoint) {
+                          writeln("");
+                          writeln("Interpreter Entry Point:");
+                       }
+
+                       var pcDesc = safepoints.get(num2addr(curPc));
+                       var isSafepoint = (pcDesc != null);
+                       if (isSafepoint && pcDesc.isAtCall()) {
+                          printSafepointInfo(nmethod, pcDesc);
+                       }
+
+                       write(num2addr(curPc) + ':', '\t');
+                       writeln(instr.asString(curPc, 
+                                 new sapkg.asm.SymbolFinder() {
+                                    getSymbolFor: function(addr) {
+                                       return addr2sym(num2addr(addr));
+                                    }
+                                 }));
+
+                       if (isSafepoint && !pcDesc.isAtCall()) {
+                          printSafepointInfo(nmethod, pcDesc);
+                       }
+                    }                    
+                 });
+}
+
+// bytecode interpreter functions
+
+// iterates interpreter codelets for each interpreter codelet
+function forEachInterpCodelet(callback) {
+   var stubQueue = sa.interpreter.code;
+   var stub = stubQueue.first;
+   while (stub != null) {
+      if (callback(stub) == false) return;
+      stub = stubQueue.getNext(stub);
+   }
+}
+
+// helper for bytecode disassembler
+function printExceptionTable(method) {
+   var expTbl = method.getExceptionTable();
+   var len = expTbl.getLength();
+   if (len != 0) {     
+      var i;
+      var cpool = method.constants;
+      writeln("start", '\t', "end", '\t', "handler", '\t', "exception");
+      writeln("");
+      for (i = 0; i < len; i += 4) {
+         write(expTbl.getIntAt(i), '\t', 
+               expTbl.getIntAt(i + 1), '\t', 
+               expTbl.getIntAt(i + 2), '\t');
+         var cpIndex = expTbl.getIntAt(i + 3);
+         var oop = (cpIndex == 0)? null : cpool.getObjAt(cpIndex);
+         if (oop == null) {
+            writeln("<any>");
+         } else if (oop.isSymbol()) {
+            writeln(oop.asString().replace('/', '.'));
+         } else if (oop.isKlass()) {
+            writeln(oop.name.asString().replace('/', '.'));
+         } else {
+            writeln(cpIndex);
+         }
+      }
+   }
+}
+
+// print Java bytecode disassembly
+function jdis(method) {   
+   if (method.getByteCode == undefined) {
+      // method oop may be specified by address
+      method = addr2oop(any2addr(method));
+   }
+   writeln(method, '-', method.externalNameAndSignature());
+   if (method.isNative()) {
+      writeln("native method");
+      return;
+   }
+   if (method.isAbstract()) {
+      writeln("abstract method");
+      return;
+   }
+   
+   writeln();
+   var BytecodeDisAsmClass = sapkg.interpreter.BytecodeDisassembler;
+   var disAsm = new BytecodeDisAsmClass(method);
+   var bci = 0;
+   var hasLines = method.hasLineNumberTable();
+   if (hasLines) {
+      writeln("bci", '\t', "line", '\t', "instruction");
+   } else {
+      writeln("bci", '\t', "instruction");
+   }
+   writeln("");
+   disAsm.decode(new sapkg.interpreter.BytecodeVisitor() {
+                    visit: function(bytecode) {
+                       if (hasLines) {
+                          var line = method.getLineNumberFromBCI(bci);
+                          writeln(bci, '\t', line, '\t', bytecode);
+                       } else {
+                          writeln(bci, '\t', bytecode);
+                       }
+                       bci++;
+                    }
+                 });
+
+    writeln();
+    printExceptionTable(method);
+}
+
+// Java thread
+
+// iterates each Thread
+function forEachJavaThread(callback) {
+   var threads = sa.threads;
+   var thread = threads.first();
+   while (thread != null) {
+      if (callback(thread) == false) return;
+      thread = thread.next();
+   }  
+}
+
+// iterate Frames of a given thread
+function forEachFrame(javaThread, callback) {
+   var fr = javaThread.getLastFrameDbg();
+   while (fr != null) { 
+     if (callback(fr) == false) return;
+     fr = fr.sender();
+   }
+}
+
+// iterate JavaVFrames of a given JavaThread
+function forEachVFrame(javaThread, callback) {
+   var vfr = javaThread.getLastJavaVFrameDbg();
+   while (vfr != null) {
+      if (callback(vfr) == false) return;
+      vfr = vfr.javaSender();
+   }
+}
+
+function printStackTrace(javaThread) {
+   write("Thread ");
+   javaThread.printThreadIDOn(java.lang.System.out);
+   writeln();
+   forEachVFrame(javaThread, function (vf) {
+      var method = vf.method;
+      write(' - ', method.externalNameAndSignature(), '@bci =', vf.getBCI());
+      var line = method.getLineNumberFromBCI(vf.getBCI());
+      if (line != -1) { write(', line=', line); }
+      if (vf.isCompiledFrame()) { write(" (Compiled Frame)"); }
+      if (vf.isInterpretedFrame()) { write(" (Interpreted Frame)"); }
+      writeln();
+   });
+   writeln();
+   writeln();
+}
+
+// print Java stack trace for all threads
+function where(javaThread) {
+   if (javaThread == undefined) {
+      forEachJavaThread(function (jt) { printStackTrace(jt); });
+   } else {
+      printStackTrace(javaThread);
+   }
+}
+
+// vmStructs access -- type database functions
+
+// find a VM type
+function findVMType(typeName) {
+   return sa.typedb.lookupType(typeName);
+}
+
+// iterate VM types
+function forEachVMType(callback) {
+   var itr = sa.typedb.types;
+   while (itr.hasNext()) {
+      if (callback(itr.next()) == false) return;
+   }
+}
+
+// find VM int constant
+function findVMIntConst(name) {
+   return sa.typedb.lookupIntConstant(name);
+}
+
+// find VM long constant
+function findVMLongConst(name) {
+   return sa.typedb.lookupLongConstant(name);
+}
+
+// iterate VM int constants
+function forEachVMIntConst(callback) {
+   var itr = sa.typedb.intConstants;
+   while (itr.hasNext()) {
+      if (callback(itr.next()) == false) return;
+   } 
+}
+
+// iterate VM long constants
+function forEachVMLongConst(callback) {
+   var itr = sa.typedb.longConstants;
+   while (itr.hasNext()) {
+      if (callback(itr.next()) == false) return;
+   } 
+}
+
+// returns VM Type at address
+function vmTypeof(addr) {
+   addr = any2addr(addr);
+   return sa.typedb.guessTypeForAddress(addr);
+}
+
+// does the given 'addr' points to an object of given 'type'?
+// OR any valid Type at all (if type is undefined)
+function isOfVMType(addr, type) {
+   addr = any2addr(addr);
+   if (type == undefined) {
+      return vmTypeof(addr) != null;
+   } else {
+      if (typeof(type) == 'string') {
+         type = findVMType(type);
+      } 
+      return sa.typedb.addressTypeIsEqualToType(addr, type);
+   }
+}
+
+// reads static field value
+function readVMStaticField(field) {
+   var type = field.type;
+   if (type.isCIntegerType() || type.isJavaPrimitiveType()) {
+      return field.value;
+   } else if (type.isPointerType()) {
+      return field.address;
+   } else if (type.isOopType()) {
+      return field.oopHandle;      
+   } else {
+      return field.staticFieldAddress;
+   }
+}
+
+// reads given instance field of VM object at 'addr'
+function readVMInstanceField(field, addr) {
+   var type = field.type;
+   if (type.isCIntegerType() || type.isJavaPrimitiveType()) {
+      return field.getValue(addr);
+   } else if (type.isPointerType()) {
+      return field.getAddress(addr);
+   } else if (type.isOopType()) {
+      return field.getOopHandle(addr);
+   } else {
+      return addr.addOffsetTo(field.offset);
+   }
+}
+
+// returns name-value of pairs of VM type at given address.
+// If address is unspecified, reads static fields as name-value pairs.
+function readVMType(type, addr) {
+   if (typeof(type) == 'string') {
+      type = findVMType(type);
+   }
+   if (addr != undefined) {
+      addr = any2addr(addr);
+   }
+
+   var result = new Object();
+   var staticOnly = (addr == undefined);
+   while (type != null) {
+      var itr = type.fields;
+      while (itr.hasNext()) {
+         var field = itr.next();
+         var isStatic = field.isStatic();
+         if (staticOnly && isStatic) {
+            result[field.name] = readVMStaticField(field);
+         } else if (!staticOnly && !isStatic) {
+            result[field.name] = readVMInstanceField(field, addr);
+         }
+      }
+      type = type.superclass;
+   } 
+   return result;
+}
+
+function printVMType(type, addr) {
+   if (typeof(type) == 'string') {
+      type = findVMType(type);
+   }
+   var obj = readVMType(type, addr);
+   while (type != null) {
+      var itr = type.fields;
+      while (itr.hasNext()) {
+         var field = itr.next();
+         var name = field.name;
+         var value = obj[name];
+         if (value != undefined) {
+            writeln(field.type.name, type.name + '::' + name, '=', value);
+         }
+      }
+      type = type.superclass;  
+   }
+}
+
+// define readXXX and printXXX functions for each VM struct/class Type
+tmp = new Object();
+tmp.itr = sa.typedb.types;
+while (tmp.itr.hasNext()) {
+   tmp.type = tmp.itr.next();
+   tmp.name = tmp.type.name;
+   if (tmp.type.isPointerType() || tmp.type.isOopType() ||
+      tmp.type.isCIntegerType() || tmp.type.isJavaPrimitiveType() ||
+      tmp.name.equals('address') ||
+      tmp.name.equals("<opaque>")) {
+         // ignore;
+         continue;
+   } else {
+      // some type names have ':'. replace to make it as a 
+      // JavaScript identifier
+      tmp.name = tmp.name.replace(':', '_');
+      eval("function read" + tmp.name + "(addr) {" +
+           "   return readVMType('" + tmp.name + "', addr);}"); 
+      eval("function print" + tmp.name + "(addr) {" + 
+           "   printVMType('" + tmp.name + "', addr); }");
+
+      /* FIXME: do we need this?
+      if (typeof(registerCommand) != 'undefined') {
+          var name = "print" + tmp.name;
+          registerCommand(name, name + " [address]", name);
+      }
+      */
+   }
+}
+//clean-up the temporary
+delete tmp;
+
+// VMObject factory
+
+// VM type to SA class map
+var  vmType2Class = new Object();
+
+// This is *not* exhaustive. Add more if needed.
+// code blobs
+vmType2Class["BufferBlob"] = sapkg.code.BufferBlob;
+vmType2Class["nmethod"] = sapkg.code.NMethod;
+vmType2Class["RuntimeStub"] = sapkg.code.RuntimeStub;
+vmType2Class["SafepointBlob"] = sapkg.code.SafepointBlob;
+vmType2Class["C2IAdapter"] = sapkg.code.C2IAdapter;
+vmType2Class["DeoptimizationBlob"] = sapkg.code.DeoptimizationBlob;
+vmType2Class["ExceptionBlob"] = sapkg.code.ExceptionBlob;
+vmType2Class["I2CAdapter"] = sapkg.code.I2CAdapter;
+vmType2Class["OSRAdapter"] = sapkg.code.OSRAdapter;
+vmType2Class["UncommonTrapBlob"] = sapkg.code.UncommonTrapBlob;
+vmType2Class["PCDesc"] = sapkg.code.PCDesc;
+
+// interpreter
+vmType2Class["InterpreterCodelet"] = sapkg.interpreter.InterpreterCodelet;
+
+// Java Threads
+vmType2Class["JavaThread"] = sapkg.runtime.JavaThread;
+vmType2Class["CompilerThread"] = sapkg.runtime.CompilerThread;
+vmType2Class["SurrogateLockerThread"] = sapkg.runtime.JavaThread;
+vmType2Class["DebuggerThread"] = sapkg.runtime.DebuggerThread;
+
+// gc
+vmType2Class["GenCollectedHeap"] = sapkg.memory.GenCollectedHeap;
+vmType2Class["CompactingPermGenGen"] = sapkg.memory.CompactingPermGenGen;
+vmType2Class["DefNewGeneration"] = sapkg.memory.DefNewGeneration;
+vmType2Class["TenuredGeneration"] = sapkg.memory.TenuredGeneration;
+
+// generic VMObject factory for a given address
+// This is equivalent to VirtualConstructor.
+function newVMObject(addr) {
+   addr = any2addr(addr);
+   var result = null;
+   forEachVMType(function (type) {
+                    if (isOfVMType(addr, type)) {
+                       var clazz = vmType2Class[type.name];
+                       if (clazz != undefined) {
+                          result = new clazz(addr);
+                       }
+                       return false;
+                    } else {
+                       return true;
+                    }
+                 });
+   return result;
+}
+
+function vmobj2addr(vmobj) {
+   return vmobj.address;
+}
+
+function addr2vmobj(addr) {
+   return newVMObject(addr);
+}     
+
+// Miscellaneous utilities
+
+// returns PointerLocation that describes the given pointer
+function findPtr(addr) {
+   addr = any2addr(addr);
+   return sapkg.utilities.PointerFinder.find(addr);
+}
+
+// is given address a valid Oop?
+function isOop(addr) {
+   addr = any2addr(addr);
+   var oopHandle = addr.addOffsetToAsOopHandle(0);
+   return sapkg.utilities.RobustOopDeterminator.oopLooksValid(oopHandle);
+}
+
+// returns description of given pointer as a String
+function whatis(addr) {
+   addr = any2addr(addr);
+   var ptrLoc = findPtr(addr);
+   if (ptrLoc.isUnknown()) {
+      var vmType = vmTypeof(addr);
+      if (vmType != null) {
+         return "pointer to " + vmType.name;
+      } else {
+         var sym = closestSymbolFor(addr);
+         if (sym != null) {
+            return sym.name + '+' + sym.offset;
+         } else {
+            return ptrLoc.toString();
+         }
+      }
+   } else {
+      return ptrLoc.toString();
+   }
+}