# JavaScript interface to Hotspot Serviceability Agent

Serviceability Agent (SA) provides Java API and tools to diagnose HotSpot Virtual Machine and Java apps running on it. SA is a snapshot debugger -- can be used to observe state of a frozen java process or java core dump.

## Existing SA APIs

There are two application programmer interfaces (APIs) for SA:

1. Private java API
  This tries to mimic hotspot VM's internal C++ classes and methods. Because VM data structures are a moving target, this API can never be 'stable'! Besides, to use SA's private API knowledge of HotSpot code base is essential.
2. SA-JDI -- Java Debugger Interface read-only subset API
  This is read-only subset of JDI (Java Debugger Interface) This is a standardized interface to get java level state of a java process or java core dump. While this interface is useful, this misses parts of java level state from target process or core such as
  - heap walking interface -- only objects traceable to static variables (of classes) and local variables of stack frames can be accessed.
  - re-constructing .class from debuggee are missing.
  - re-constructing object mirrors for Java objects of the debuggee.

## SA Scripting interface

Traditionally, platform debuggers such as dbx, gdb and Solaris mdb (Module Debugger), provide a scripting language interface. Scripting language interface provides easy-to-use, dynamically typed interface to access data structures from debuggee. dbx and mdb even allow user to write C/C++ modules to extend the scripting language commands.

SA provides SOQL - Simple Object Query Language -- a SQL-like query language to access Java heap as an object database. SA's main GUI (HSDB) also exposes scripting interface of underlying debugger such as dbx, windbg. But to use this interface, user has to learn scripting interface of multiple debugger back-ends such as dbx, windbg. And these scripting interfaces are 'raw' in the sense that no java state is exposed -- only C/C++ state of VM is exposed. Higher level SA services are not available through scripting interface.

jsdb -- JavaScript Debugger attempts to provide JavaScript interface to SA. jsdb provides

- high-level hotspot (and SA) independent scripting interface
- low-level SA-aware scripting interface.

## High level interface (Java State)

jsdb is a command line JavaScript shell based on Mozilla's Rhino JavaScript Engine. This command line utility attaches to Java process or core file or remote debug server and waits for user input. This shell supports the following global functions and objects in addition to the standard JavaScript functions and objects:

### jdsb globals

Function/Variable | Description
--- | ---
address(jobject) | function that returns the address of the Java object as a string
| classof(jobject) | function that returns the JavaScript object that represents class object of the Java object | dumpClass(jclass,[dir]) | function that writes .class for the given Java Class. Optionally (second arg) accepts the directory where the .class has to be written. | help() | function that prints help message for global functions and objects
identityHash(jobject) | function that returns the identity hashCode of the Java object
mirror(jobject) | function that returns a local mirror of the Java object.
load([file1, file2,...]) | function that loads zero or more JavaScript file(s). With no arguments, reads for JavaScript code.
object(string) | function that converts a string address into Java object
owner(jobject) | function that returns the owner thread of this monitor or null
sizeof(jobject) | function that returns the size of Java object in bytes
staticof(jclass, field) | function that returns the value of given field of the given Java class
print(expr1, expr2,...) | function that prints zero or more JavaScript expressions after converting those as strings
println(expr1, expr2..) | function that same as print, but prints a newline at the end
read([prompt]) | function that reads a single line from standard input
quit() | function that quits the interactive load call as well as the shell
jvm | variable -- a JavaScript object that represents the target jvm that is being debugged

### jvm object

jvm object supports the following read-only properties.

Property name | Description
--- | ---
threads | array of Java threads from the debuggee
heap | object representing the heap of the debuggee
type | string value that is either "Server" or "Client" or "Core" -- the flavour of debuggee VM
bootClassPath | string value of bootclasspath of the debuggee
cpu | string value of cpu on which the debuggee runs/ran
sysProps | name-value pairs (JavaScript associative array) of Java System properties of the debuggee
addressSize | int value -- 32 for 32 bit debuggee, 64 for 64 bit debuggee
os | string value of OS on which the debuggee runs/ran
buildInfo | internal build info string from debuggee
flags | name-value pairs (JavaScript associative array) of JVM command line flags of the debuggee
classPath | string value of classpath of the debuggee
userDir | string value of user.dir System property of the debuggee

### heap object

heap object represents Java heap of the debuggee VM

Function or property name | Description
--- | ---
capacity | byte size of capacity of the heap
used | byte size of used portion (of live objects) of the heap
forEachObject(func, [class], [include subtypes -- true|false]) | This function accepts a callback function 'func' and optionally class name and boolean arguments. This function calls the callback for each Java object in the debuggee's heap. The optional class argument may be used to receive objects of given class only. The third arguments specifies whether to include objects of subtype of given class [or interface] or not. The default value of class is "java.lang.Object" and and that of the third argument is true. i.e., by default all objects are included.
forEachClass(func, [initiating loader -- true|false]) | This function accepts a callback function 'func'. This function iterates through the classes of the debuggee and calls the callback for each class. The second parameter tells whether to pass initiating loader to the iterator callback or not.

### Accessing Java objects and arrays in script

From a given Java object, we can access all fields of the Java object by usual '.' operator. i.e., if you got a Java object called 'o' of type java.lang.Thread from debuggee, you can access 'stackSize' field by o.stackSize syntax. Similarly, length of Java array objects can be accessed by length property. And array indexing follows usual syntax. i.e., n'th element of array 'a' is accessed by a[n].

### jvm.threads array

This is a JavaScript array of Java threads of the debuggee. As usual, 'length' property tells the number of threads and individual threads may be accessed by index operator -- i.e, jvm.threads[0] returns the first thread.

### thread object

In addition to the fields of java.lang.Thread (or subclass) fields, thread objects have two additional properties.

- frames -- array of stack frame objects
- monitors -- array of monitor objects owned by the thread

### stack frame object

Property name | Description
--- | ---
| thisObject | Object representing 'this' of the current frame [will be null for static methods]
locals | name-value pairs of local variables [JavaScript associative array]
line | Java source line number at which the frame is executing
bci | byte code index of the bytecode that the frame is executing
thread | thread to which this frame belongs
method | Java method that the frame is executing

### method object

method object represents a Java method of debuggee

Property name | Description
--- | ---
isStatic | boolean - true for static methods and false for non-static methods
isSynchronized | boolean - true for synchronized methods and false for non-synchronized methods
isNative | boolean - true for native methods and false for non-native methods
isProtected | boolean - true for protected methods and false for non-protected methods
isPrivate | boolean - true for private methods and false for non-private methods
isSynthetic | boolean - true for Javac generated synthetic methods and false for non-synthetic methods
isPackagePrivate | boolean - true for package-private methods and false for non-package-private methods
isPublic | boolean - true for public methods and false for non-public methods
holder | an object that represents Class that contains this method
signature | string -- signature of this method
isObsolete | boolean - true for obsolete (hotswapped) methods and false for non-obsolete methods
isStrict | boolean - true for strictfp methods and false for non-strictfp methods
isFinal | boolean - true for final methods and false for non-final methods
name | string - name of this method

### class object

A class object represents loaded Java class in debuggee VM. This represents java.lang.Class instance in the debuggee. This is type of return value of classof global function. Also, method.holder property and field.holder are of this type.

Property name | Description
--- | ---
name | name of this class
superClass | class object representing super class of this class
isArrayClass | boolean -- is the current class an array class?
isStatic | boolean -- is the current class static or not
isInterface | boolean -- is the current class an interface
isAbstract | boolean -- is the current class abstract or not
isProtected | boolean -- is the current class protected or not
isPrivate | boolean -- is the current class private or not
isPackagePrivate | boolean -- is the current class package private or not
isSynthetic | boolean -- is the current class synthetic or not
classLoader | object that represents ClassLoader object that loaded the current class
fields | array of static and instance fields of the current class
protectionDomain | protection domain to which current class belongs
isPublic | boolean -- is the current class public or not
signers | array of signers for current class
sourceFile | string -- name of the source file for current class
interfaces | array -- interfaces implemented by current class
isStrict | boolean -- is the current class strictfp or not
methods | array of methods (static and instance) of the current class
isFinal | boolean -- is the current class final or not
statics | name-value pairs (JavaScript associate array) of static fields of the current class

### field object

field represents a static or instance field of some class in debuggee

Property name | Description
--- | ---
isStatic | boolean -- is this field a static field?
holder | class that owns this field
signature | string signature of this field
isProtected | boolean - is this field a protected field or not?
isPrivate | boolean - is this field a private field or not?
isSynthetic | boolean - is this javac generated synthetic field or not?
isPackagePrivate | boolean - is this field a package private field or not?
isTransient | boolean - is this field a transient field or not?
isFinal | boolean - is this field final or not?
name | string - name of this field
isPublic | boolean - is this field public or not?

### Initialization Script

jsdb engine looks for initialization script file named jsdb.js in user's home directory. If found, it loads just after attaching to debuggee but before printing prompt for user's input. User can assume that s/he can access debuggee VM state during initialization script.

### Sample scripts

Semantics and knowledge of application classes (for eg. AppServer's classes) would be needed to create app specific scripts. The following script samples are app-independent and provide a flavour of kind of scripts that can be written.

#### Script to print system properties of JVM

    jvm.sysProps.toString()

#### Script to print JVM command line flags

    jvm.flags.toString()

#### Script to print class-wise histogram of objects

    // associate array to hold histogram
    var histo;
    function func(obj) {
        var classname = classof(obj).name;
        if (histo[classname] == undefined) {
           // first time we are visiting this class type
           histo[classname] = 1;
        } else {
           histo[classname]++;
        }
    }

    // iterate through java heap calling 'func' for each object
    jvm.heap.forEachObject(func);

    // print the histogram
    for (i in histo) {
       println('number of instances of ', i, ' = ', histo[i]);
    }

#### Script to print stack trace of all Java threads

    function printStackTrace(t) {
        println(t.name);
        println('');
        for (i in t.frames) {
           println(t.frames[i]);
        }
        println('');
    }

    // walk through the list of threads and call printStackTrace
    // for each thread
    for (o in jvm.threads) {
        printStackTrace(jvm.threads[o]);
    }

#### Script to re-construct .class files for all non-bootstrap classes

    function dump(cl) {
       if (!cl.isArrayClass  && cl.classLoader != null) {
          // not an array class and a non-bootstrap class
          // create .class files in e:\tmp dir
          dumpClass(cl, "e:\\tmp);
       } else {
          println("skipping bootstrap class ", cl.name);
       }
    }

    // walk thru heap and call callback for each java.lang.Class instance
    jvm.heap.forEachObject(dump, "java.lang.Class");

#### Script to print paths of all java.io.File's currently accessed

    function printFile(f) {
       // construct a mirror java.io.File here and
       // print absolute path here
       println(mirror(f).getAbsolutePath());
    }

    jvm.heap.forEachObject(printFile, "java.io.File");

#### Script to print static fields of java.lang.Thread class

    var threadClass = classof("java.lang.Thread");
    for (i in threadClass.statics) {
      println(i, '=', threadClass.statics[i]);
    }

### Low level interface (VM State)

Low level jsdb interface works by JavaScript-to-Java (previously known as "LiveConnect") interface provided by Rhino JavaScript engine.

## sapkg object

This object provides short names for SA package names. For eg. instead of writing Packages.sun.jvm.hotspot.memory, we can write sapkg.memory.

## sa object

This object contains all SA singleton objects such as VM, Universe, SymbolTable, SystemDictionary, ObjectHeap, CollectedHeap, Debugger, CDebugger (if available), Interpreter, TypeDataBase and Threads. For eg. to access SymbolTable of Java debuggee, we can use sa.symbolTable. User can execute the following code to get fields of this object.

    for (i in sa) {
      println(i);
    }

#### Heap Iterators

forEachOop(callback)
  calls a callback function for each Oop in Java heap
forEachOopOfKlass(callback, klass, [includeSubtypes])
  calls a callback function for each Oop of a give Klass type Optinally, third argument can specify whether to include subtype Oops or not.

#### System Dictionary Access

forEachKlass(callback)
  calls a callback function for each Klass in Java heap
forEachKlassAndLoader(callback)
  calls callback with Klass and initiating loader (Oop) for System dictionary entry.
forEachPrimArrayKlass(callback)
  calls callback with Klass and initiating loader (Oop) for each primitive array Klass in the system.
findInstanceKlass(name)
  finds the first instance klass with given name from System dictionary

#### Thread, Frame Iterators

forEachJavaThread(callback)
  calls callback for each Java Thread
forEachFrame(javaThread, callback)
  calls callback for each Frame of a given JavaThread
forEachVFrame(javaThread, callback)
  calls callback for each JavaVFrame of a given JavaThread
forEachThread(callback)
  calls callback for each (native) ThreadProxy (obtained by CDebugger.getThreadList)
forEachCFrame(threadProxy, callback)
  calls callback for each CFrame of a given ThreadProxy object

#### Code blobs, Interpreter codelets

forEachCodeBlob(callback)
  calls callback with each code blob in code cache
findCodeBlob(address)
  finds the code blob, if any, that contains the given address. Returns null, on failure.
findNMethod(address)
  finds the NMethod that contains given address.
pcDescAt(addr)
  returns PCDesc at given address or null.
forEachInterpCodelet(callbacl)
  calls callback with each Interpreter codelet

#### VM structs, constants

forEachType(callback)
  calls callback for each Type in VM's type database
forEachVMIntConst(callback)
  calls callback for each named integer constant. passes name as argument.
forEachVMLongConst(callback)
  calls callback for each named long constant. passes name as argument.
findVMType(name)
  finds a VM type by name. returns null if no known Type of given name exists in type database.
findVMIntConst(name)
  finds an integer constant in type data base by name.
findVMLongConst(name)
  finds an long constant in type data base by name.
vmTypeof(addr)
  returns VM type of object at 'addr' if any. Else, returns null.
isOfVMType(addr, type)
  returns whether object at 'addr' is of VM type 'type' or not.
printVMType(type, addr)
  prints 'addr' as VM object of type 'type'
printXXX(addr)
  For each VM type, these functions are defined. For eg. there is printUniverse, printSystemDictionary etc. are available. Without 'addr' being passed static fields are printed. With 'addr' param being passed, instance fields are printed.

#### Low level debugger facilities

num2addr(number)
  converts a (long) number to SA Address instance
str2addr(string)
  converts a given hex string to SA Address instance
any2addr(any)
  Takes a number or a string or an Address and returns an Address instance. For other types, returns 'undefined'
addr2str(addr)
  converts a given Address instance to a hex string
addr2num(addr)
  converts a given Address instance to a (long) number
sym2addr(library, symbol)
  returns Address of a given symbol in a given library (shared object or DLL) Example: sym2addr('jvm.dll', 'JNI_CreateJavaVM')
addr2sym(addr)
  Returns nearest symbol to a given address (if any). If no such symbol is found, returns the given address as a string.
readBytesAt(addr, num)
  returns 'num' bytes at 'addr' as a Java byte[]
readWordsAt(addr, num)
  returns 'num' words at 'addr' as a Java long[]
readCStrAt(addr)
  returns 'C' String at given address
readCStrLen(addr)
  returns the length of the 'C' String at given address
readRegs(threadProxy)
  returns register set (of Thread Context) of a given thread specified by threadProxy. return value is an associate array having name-value pairs of registers.
regs(threadProxy)
  prints register set of a given thread.
mem(addr, [num])
  prints 'num' words (address size) at 'addr'. Prints nearest symbol for address, if found.
dis(addr, [num])
  prints native code disassembly of 'num' bytes at given address 'addr'. Default value of 'num' is 4. This automatically detects whether the given address inside a nmethod. If so, it prints safepoint info, entry points , method signature etc. of the nmethod.
jdis(method [or addr])
  prints Java bytecode disassembly for given method Oop or address of a method Oop.
nmethoddis(nmethod)
  prints disassembly of given nmethod object. Note that you don't have to call this directly instead use 'dis'.
where
  prints Java stack trace for all Java threads

#### Miscellaneous

addr2oop(addr)
  converts a given address to a Oop object
oop2addr(oop)
  returns address of a given Oop object
isOfVMType(addr, type)
  returns whether the given 'addr' points to a (C++) VM object of specified type. type may be specified by SA Type object or string name of the type.
newVMObject(addr)
  returns instance of SA object for a given address (similar to SA VirtualConstructor interface).
vmobj2addr(vmobject)
  returns Address represented by a given SA VMObject
addr2vmobj(addr)
  same as newVMObject(addr)
whatis(addr)
  returns string description of given address (using SA FindPointer and guess type API).
isOop(addr)
  returns whether a given address is a valid Oop address or not

#### Moving b/w jsdb low level and high level interfaces

Java objects of debuggee are represented by different script wrappers in high level interface. In the low-level interface these are instances of SA Oop class or its' subclass. To move b/w low-level and high-level interfaces the following functions may be used

oop2obj(oop)
  converts a given Oop object to a high-level wrapper object
obj2oop(obj)
  converts a jsdb high level wrapper to underlying Oop instance

### JavaScript tips

- to know properties, functions of any object, use the script

      for(i in object) { println(i); }

- to view the source code of any function, just type the name of function in jsdb prompt
- to view global functions, properties, run

      for(i in this) { println(i); }