1/*
2 * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25// shorter names for SA packages
26
27
28// SA package name abbreviations are kept in 'sapkg' object
29// to avoid global namespace pollution
30var sapkg = new Object();
31
32sapkg.hotspot = Packages.sun.jvm.hotspot;
33sapkg.asm = sapkg.hotspot.asm;
34sapkg.c1 = sapkg.hotspot.c1;
35sapkg.code = sapkg.hotspot.code;
36sapkg.compiler = sapkg.hotspot.compiler;
37
38// 'debugger' is a JavaScript keyword, but ES5 relaxes the
39// restriction of using keywords as property name
40sapkg.debugger = sapkg.hotspot.debugger;
41
42sapkg.interpreter = sapkg.hotspot.interpreter;
43sapkg.jdi = sapkg.hotspot.jdi;
44sapkg.memory = sapkg.hotspot.memory;
45sapkg.oops = sapkg.hotspot.oops;
46sapkg.runtime = sapkg.hotspot.runtime;
47sapkg.tools = sapkg.hotspot.tools;
48sapkg.types = sapkg.hotspot.types;
49sapkg.ui = sapkg.hotspot.ui;
50sapkg.utilities = sapkg.hotspot.utilities;
51
52// SA singletons are kept in 'sa' object
53var sa = new Object();
54sa.vm = sapkg.runtime.VM.getVM();
55sa.dbg = sa.vm.getDebugger();
56sa.cdbg = sa.dbg.CDebugger;
57sa.heap = sa.vm.universe.heap();
58sa.systemDictionary = sa.vm.systemDictionary;
59sa.sysDict = sa.systemDictionary;
60sa.symbolTable = sa.vm.symbolTable;
61sa.symTbl = sa.symbolTable;
62sa.threads = sa.vm.threads;
63sa.interpreter = sa.vm.interpreter;
64sa.typedb = sa.vm.typeDataBase;
65sa.codeCache = sa.vm.codeCache;
66// 'objHeap' is different from 'heap'!.
67// This is SA's Oop factory and heap-walker
68sa.objHeap = sa.vm.objectHeap;
69
70// few useful global variables
71var OS = sa.vm.OS;
72var CPU = sa.vm.CPU;
73var LP64 = sa.vm.LP64;
74var isClient = sa.vm.clientCompiler;
75var isServer = sa.vm.serverCompiler;
76var isCore = sa.vm.isCore();
77var addressSize = sa.vm.addressSize;
78var oopSize = sa.vm.oopSize;
79
80// this "main" function is called immediately
81// after loading this script file
82function main(globals, jvmarg) {
83  // wrap a sun.jvm.hotspot.utilities.soql.ScriptObject
84  // object so that the properties of it can be accessed
85  // in natural object.field syntax.
86  function wrapScriptObject(so) {
87    function unwrapScriptObject(wso) {
88      var objType = typeof(wso);
89      if ((objType == 'object' ||
90           objType == 'function')
91          && "__wrapped__" in wso) {
92        return wso.__wrapped__;
93      } else {
94        return wso;
95      }
96    }
97
98    function prepareArgsArray(array) {
99      var args = new Array(array.length);
100      for (var a = 0; a < array.length; a++) {
101        var elem = array[a];
102        elem = unwrapScriptObject(elem);
103        if (typeof(elem) == 'function') {
104          args[a] = new sapkg.utilities.soql.Callable() {
105            call: function(myargs) {
106              var tmp = new Array(myargs.length);
107              for (var i = 0; i < myargs.length; i++) {
108                tmp[i] = wrapScriptObject(myargs[i]);
109              }
110              return elem.apply(this, tmp);
111            }
112          }
113        } else {
114          args[a] = elem;
115        }
116      }
117      return args;
118    }
119
120    // Handle __has__ specially to avoid metacircularity problems
121    // when called from __get__.
122    // Calling
123    //   this.__has__(name)
124    // will in turn call
125    //   this.__call__('__has__', name)
126    // which is not handled below
127    function __has__(name) {
128      if (typeof(name) == 'number') {
129        return so["has(int)"](name);
130      } else {
131        if (name == '__wrapped__') {
132          return true;
133        } else if (so["has(java.lang.String)"](name)) {
134          return true;
135        } else if (name.equals('toString')) {
136          return true;
137        } else {
138          return false;
139        }
140      }
141    }
142
143    if (so instanceof sapkg.utilities.soql.ScriptObject) {
144      return new JSAdapter() {
145        __getIds__: function() {
146          return so.getIds();
147        },
148
149        __has__ : __has__,
150
151        __delete__ : function(name) {
152          if (typeof(name) == 'number') {
153            return so["delete(int)"](name);
154          } else {
155            return so["delete(java.lang.String)"](name);
156          }
157        },
158
159        __get__ : function(name) {
160	      // don't call this.__has__(name); see comments above function __has__
161          if (! __has__.call(this, name)) {
162            return undefined;
163          }
164          if (typeof(name) == 'number') {
165            return wrapScriptObject(so["get(int)"](name));
166          } else {
167            if (name == '__wrapped__') {
168              return so;
169            } else {
170              var value = so["get(java.lang.String)"](name);
171              if (value instanceof sapkg.utilities.soql.Callable) {
172                return function() {
173                  var args = prepareArgsArray(arguments);
174                  var r;
175                  try {
176                    r = value.call(Java.to(args, 'java.lang.Object[]'));
177                  } catch (e) {
178                    println("call to " + name + " failed!");
179                    throw e;
180                  }
181                  return wrapScriptObject(r);
182                }
183              } else if (name == 'toString') {
184                return function() {
185                  return so.toString();
186                }
187              } else {
188                return wrapScriptObject(value);
189              }
190            }
191          }
192        }
193      };
194    } else {
195      return so;
196    }
197  }
198
199  // set "jvm" global variable that wraps a
200  // sun.jvm.hotspot.utilities.soql.JSJavaVM instance
201  if (jvmarg != null) {
202    jvm = wrapScriptObject(jvmarg);
203    // expose "heap" global variable
204    heap = jvm.heap;
205  }
206
207  // expose all "function" type properties of
208  // sun.jvm.hotspot.utilitites.soql.JSJavaScriptEngine
209  // as global functions here.
210  globals = wrapScriptObject(globals);
211  for (var prop in globals) {
212    if (typeof(globals[prop]) == 'function') {
213      this[prop] = globals[prop];
214    }
215  }
216
217  // define "writeln" and "write" if not defined
218  if (typeof(println) == 'undefined') {
219    println = function (str) {
220      java.lang.System.out.println(String(str));
221    }
222  }
223
224  if (typeof(print) == 'undefined') {
225    print = function (str) {
226      java.lang.System.out.print(String(str));
227    }
228  }
229
230  if (typeof(writeln) == 'undefined') {
231    writeln = println;
232  }
233
234  if (typeof(write) == 'undefined') {
235    write = print;
236  }
237
238  // "registerCommand" function is defined if we
239  // are running as part of "CLHSDB" tool. CLHSDB
240  // tool exposes Unix-style commands.
241
242  // if "registerCommand" function is defined
243  // then register few global functions as "commands".
244  if (typeof(registerCommand) == 'function') {
245    this.jclass = function(name) {
246      if (typeof(name) == "string") {
247         var clazz = sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name);
248         if (clazz) {
249             writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString());
250         } else {
251             writeln("class not found: " + name);
252         }
253      } else {
254         writeln("Usage: class name");
255      }
256    }
257    registerCommand("class", "class name", "jclass");
258
259    this.jclasses = function() {
260      forEachKlass(function (clazz) {
261        writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString());
262      });
263    }
264    registerCommand("classes", "classes", "jclasses");
265
266    this.dclass = function(clazz, dir) {
267      if (!clazz) {
268         writeln("Usage: dumpclass { address | name } [ directory ]");
269      } else {
270         if (!dir) { dir = "."; }
271         dumpClass(clazz, dir);
272      }
273    }
274    registerCommand("dumpclass", "dumpclass { address | name } [ directory ]", "dclass");
275    registerCommand("dumpheap", "dumpheap [ file ]", "dumpHeap");
276
277    this.jseval = function(str) {
278      if (!str) {
279         writeln("Usage: jseval script");
280      } else {
281         var res = eval(str);
282         if (res) { writeln(res); }
283      }
284    }
285    registerCommand("jseval", "jseval script", "jseval");
286
287    this.jsload = function(file) {
288      if (!file) {
289         writeln("Usage: jsload file");
290      } else {
291         load(file);
292      }
293    }
294    registerCommand("jsload", "jsload file", "jsload");
295
296    this.printMem = function(addr, len) {
297      if (!addr) {
298         writeln("Usage: mem [ length ]");
299      } else {
300         mem(addr, len);
301      }
302    }
303    registerCommand("mem", "mem address [ length ]", "printMem");
304
305    this.sysProps = function() {
306      for (var i in jvm.sysProps) {
307         writeln(i + ' = ' + jvm.sysProps[i]);
308      }
309    }
310    registerCommand("sysprops", "sysprops", "sysProps");
311
312    this.printWhatis = function(addr) {
313      if (!addr) {
314         writeln("Usage: whatis address");
315      } else {
316         writeln(whatis(addr));
317      }
318    }
319    registerCommand("whatis", "whatis address", "printWhatis");
320  }
321}
322
323// debugger functionality
324
325// string-to-Address
326function str2addr(str) {
327   return sa.dbg.parseAddress(str);
328}
329
330// number-to-Address
331if (addressSize == 4) {
332   eval("function num2addr(num) { \
333            return str2addr('0x' + java.lang.Integer.toHexString(0xffffffff & num)); \
334         }");
335} else {
336   eval("function num2addr(num) { \
337            return str2addr('0x' + java.lang.Long.toHexString(num));  \
338         }");
339}
340
341// generic any-type-to-Address
342// use this convenience function to accept address in any
343// format -- number, string or an Address instance.
344function any2addr(addr) {
345   var type = typeof(addr);
346   if (type == 'number') {
347      return num2addr(addr);
348   } else if (type == 'string') {
349      return str2addr(addr);
350   } else {
351      return addr;
352   }
353}
354
355// Address-to-string
356function addr2str(addr) {
357   if (addr == null) {
358      return (addressSize == 4)? '0x00000000' : '0x0000000000000000';
359   } else {
360      return addr + '';
361   }
362}
363
364// Address-to-number
365function addr2num(addr) {
366   return sa.dbg.getAddressValue(addr);
367}
368
369// symbol-to-Address
370function sym2addr(dso, sym) {
371   return sa.dbg.lookup(dso, sym);
372}
373
374function loadObjectContainingPC(addr) {
375    if (sa.cdbg == null) {
376      // no CDebugger support, return null
377      return null;
378    }
379
380    return  sa.cdbg.loadObjectContainingPC(addr);
381}
382
383// returns the ClosestSymbol or null
384function closestSymbolFor(addr) {
385    var dso = loadObjectContainingPC(addr);
386    if (dso != null) {
387      return dso.closestSymbolToPC(addr);
388    }
389
390    return null;
391}
392
393// Address-to-symbol
394// returns nearest symbol as string if found
395// else returns address as string
396function addr2sym(addr) {
397    var sym = closestSymbolFor(addr);
398    if (sym != null)  {
399       return sym.name + '+' + sym.offset;
400    } else {
401       return addr2str(addr);
402    }
403}
404
405// read 'num' words at 'addr' and return an array as result.
406// returns Java long[] type result and not a JavaScript array.
407function readWordsAt(addr, num) {
408   addr = any2addr(addr);
409   var res = java.lang.reflect.Array.newInstance(java.lang.Long.TYPE, num);
410   var i;
411   for (i = 0; i < num; i++) {
412      res[i] = addr2num(addr.getAddressAt(i * addressSize));
413   }
414   return res;
415}
416
417// read the 'C' string at 'addr'
418function readCStrAt(addr) {
419   addr = any2addr(addr);
420   return sapkg.utilities.CStringUtilities.getString(addr);
421}
422
423// read the length of the 'C' string at 'addr'
424function readCStrLen(addr) {
425   addr = any2addr(addr);
426   return sapkg.utilities.CStringUtilities.getStringLength(addr);
427}
428
429// iterate through ThreadList of CDebugger
430function forEachThread(callback) {
431   if (sa.cdbg == null) {
432      // no CDebugger support
433      return;
434   } else {
435      var itr = sa.cdbg.threadList.iterator();
436      while (itr.hasNext()) {
437         if (callback(itr.next()) == false) return;
438      }
439   }
440}
441
442// read register set of a ThreadProxy as name-value pairs
443function readRegs(threadProxy) {
444   var ctx = threadProxy.context;
445   var num = ctx.numRegisters;
446   var res = new Object();
447   var i;
448   for (i = 0; i < num; i++) {
449      res[ctx.getRegisterName(i)]= addr2str(ctx.getRegisterAsAddress(i));
450   }
451   return res;
452}
453
454// print register set for a given ThreaProxy
455function regs(threadProxy) {
456   var res = readRegs(threadProxy);
457   for (i in res) {
458      writeln(i, '=', res[i]);
459   }
460}
461
462// iterate through each CFrame of a given ThreadProxy
463function forEachCFrame(threadProxy, callback) {
464   if (sa.cdbg == null) {
465      // no CDebugger support
466      return;
467   } else {
468      var cframe = sa.cdbg.topFrameForThread(threadProxy);
469      while (cframe != null) {
470         if (callback(cframe) == false) return;
471         cframe = cframe.sender();
472      }
473   }
474}
475
476// iterate through list of load objects (DLLs, DSOs)
477function forEachLoadObject(callback) {
478   if (sa.cdbg == null) {
479      // no CDebugger support
480      return;
481   } else {
482      var itr = sa.cdbg.loadObjectList.iterator();
483      while (itr.hasNext()) {
484         if (callback(itr.next()) == false) return;
485      }
486   }
487}
488
489// print 'num' words at 'addr'
490function mem(addr, num) {
491   if (num == undefined) {
492      num = 1;
493   }
494   addr = any2addr(addr);
495   var i;
496   for (i = 0; i < num; i++) {
497      var value = addr.getAddressAt(0);
498      writeln(addr2sym(addr) + ':', addr2str(value));
499      addr = addr.addOffsetTo(addressSize);
500   }
501   writeln();
502}
503
504// System dictionary functions
505
506// find InstanceKlass by name
507function findInstanceKlass(name) {
508   return sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name);
509}
510
511// get Java system loader (i.e., application launcher loader)
512function systemLoader() {
513   return sa.sysDict.javaSystemLoader();
514}
515
516// iterate system dictionary for each 'Klass'
517function forEachKlass(callback) {
518   var VisitorClass = sapkg.memory.SystemDictionary.ClassVisitor;
519   var visitor = new VisitorClass() { visit: callback };
520   sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassVisitor)"](visitor);
521}
522
523// iterate system dictionary for each 'Klass' and initiating loader
524function forEachKlassAndLoader(callback) {
525   var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor;
526   var visitor = new VisitorClass() { visit: callback };
527   sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassAndLoaderVisitor)"](visitor);
528}
529
530// iterate system dictionary for each primitive array klass
531function forEachPrimArrayKlass(callback) {
532   var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor;
533   sa.sysDict.primArrayClassesDo(new VisitorClass() { visit: callback });
534}
535
536// 'oop' to higher-level java object wrapper in which for(i in o)
537// works by iterating java level fields and javaobject.javafield
538// syntax works.
539function oop2obj(oop) {
540   return object(addr2str(oop.handle));
541}
542
543// higher level java object wrapper to oop
544function obj2oop(obj) {
545   return addr2oop(str2addr(address(obj)));
546}
547
548// Java heap iteration
549
550// iterates Java heap for each Oop
551function forEachOop(callback) {
552   function empty() { }
553   sa.objHeap.iterate(new sapkg.oops.HeapVisitor() {
554       prologue: empty,
555       doObj: callback,
556       epilogue: empty
557   });
558}
559
560// iterates Java heap for each Oop of given 'klass'.
561// 'includeSubtypes' tells whether to include objects
562// of subtypes of 'klass' or not
563function forEachOopOfKlass(callback, klass, includeSubtypes) {
564   if (klass == undefined) {
565       klass = findInstanceKlass("java.lang.Object");
566   }
567
568   if (includeSubtypes == undefined) {
569      includeSubtypes = true;
570   }
571
572   function empty() { }
573   sa.objHeap.iterateObjectsOfKlass(
574        new sapkg.oops.HeapVisitor() {
575            prologue: empty,
576            doObj: callback,
577            epilogue: empty
578        },
579        klass, includeSubtypes);
580}
581
582// Java thread
583
584// iterates each Thread
585function forEachJavaThread(callback) {
586   var threads = sa.threads;
587   var thread = threads.first();
588   while (thread != null) {
589      if (callback(thread) == false) return;
590      thread = thread.next();
591   }
592}
593
594// iterate Frames of a given thread
595function forEachFrame(javaThread, callback) {
596   var fr = javaThread.getLastFrameDbg();
597   while (fr != null) {
598     if (callback(fr) == false) return;
599     fr = fr.sender();
600   }
601}
602
603// iterate JavaVFrames of a given JavaThread
604function forEachVFrame(javaThread, callback) {
605   var vfr = javaThread.getLastJavaVFrameDbg();
606   while (vfr != null) {
607      if (callback(vfr) == false) return;
608      vfr = vfr.javaSender();
609   }
610}
611
612function printStackTrace(javaThread) {
613   write("Thread ");
614   javaThread.printThreadIDOn(java.lang.System.out);
615   writeln();
616   forEachVFrame(javaThread, function (vf) {
617      var method = vf.method;
618      write(' - ', method.externalNameAndSignature(), '@bci =', vf.getBCI());
619      var line = method.getLineNumberFromBCI(vf.getBCI());
620      if (line != -1) { write(', line=', line); }
621      if (vf.isCompiledFrame()) { write(" (Compiled Frame)"); }
622      if (vf.isInterpretedFrame()) { write(" (Interpreted Frame)"); }
623      writeln();
624   });
625   writeln();
626   writeln();
627}
628
629// print Java stack trace for all threads
630function where(javaThread) {
631   if (javaThread == undefined) {
632      forEachJavaThread(function (jt) { printStackTrace(jt); });
633   } else {
634      printStackTrace(javaThread);
635   }
636}
637
638// vmStructs access -- type database functions
639
640// find a VM type
641function findVMType(typeName) {
642   return sa.typedb.lookupType(typeName);
643}
644
645// iterate VM types
646function forEachVMType(callback) {
647   var itr = sa.typedb.types;
648   while (itr.hasNext()) {
649      if (callback(itr.next()) == false) return;
650   }
651}
652
653// find VM int constant
654function findVMIntConst(name) {
655   return sa.typedb.lookupIntConstant(name);
656}
657
658// find VM long constant
659function findVMLongConst(name) {
660   return sa.typedb.lookupLongConstant(name);
661}
662
663// iterate VM int constants
664function forEachVMIntConst(callback) {
665   var itr = sa.typedb.intConstants;
666   while (itr.hasNext()) {
667      if (callback(itr.next()) == false) return;
668   }
669}
670
671// iterate VM long constants
672function forEachVMLongConst(callback) {
673   var itr = sa.typedb.longConstants;
674   while (itr.hasNext()) {
675      if (callback(itr.next()) == false) return;
676   }
677}
678
679// returns VM Type at address
680function vmTypeof(addr) {
681   addr = any2addr(addr);
682   return sa.typedb.guessTypeForAddress(addr);
683}
684
685// does the given 'addr' points to an object of given 'type'?
686// OR any valid Type at all (if type is undefined)
687function isOfVMType(addr, type) {
688   addr = any2addr(addr);
689   if (type == undefined) {
690      return vmTypeof(addr) != null;
691   } else {
692      if (typeof(type) == 'string') {
693         type = findVMType(type);
694      }
695      return sa.typedb.addressTypeIsEqualToType(addr, type);
696   }
697}
698
699// reads static field value
700function readVMStaticField(field) {
701   var type = field.type;
702   if (type.isCIntegerType() || type.isJavaPrimitiveType()) {
703      return field.value;
704   } else if (type.isPointerType()) {
705      return field.address;
706   } else if (type.isOopType()) {
707      return field.oopHandle;
708   } else {
709      return field.staticFieldAddress;
710   }
711}
712
713// reads given instance field of VM object at 'addr'
714function readVMInstanceField(field, addr) {
715   var type = field.type;
716   if (type.isCIntegerType() || type.isJavaPrimitiveType()) {
717      return field.getValue(addr);
718   } else if (type.isPointerType()) {
719      return field.getAddress(addr);
720   } else if (type.isOopType()) {
721      return field.getOopHandle(addr);
722   } else {
723      return addr.addOffsetTo(field.offset);
724   }
725}
726
727// returns name-value of pairs of VM type at given address.
728// If address is unspecified, reads static fields as name-value pairs.
729function readVMType(type, addr) {
730   if (typeof(type) == 'string') {
731      type = findVMType(type);
732   }
733   if (addr != undefined) {
734      addr = any2addr(addr);
735   }
736
737   var result = new Object();
738   var staticOnly = (addr == undefined);
739   while (type != null) {
740      var itr = type.fields;
741      while (itr.hasNext()) {
742         var field = itr.next();
743         var isStatic = field.isStatic();
744         if (staticOnly && isStatic) {
745            result[field.name] = readVMStaticField(field);
746         } else if (!staticOnly && !isStatic) {
747            result[field.name] = readVMInstanceField(field, addr);
748         }
749      }
750      type = type.superclass;
751   }
752   return result;
753}
754
755function printVMType(type, addr) {
756   if (typeof(type) == 'string') {
757      type = findVMType(type);
758   }
759   var obj = readVMType(type, addr);
760   while (type != null) {
761      var itr = type.fields;
762      while (itr.hasNext()) {
763         var field = itr.next();
764         var name = field.name;
765         var value = obj[name];
766         if (value != undefined) {
767            writeln(field.type.name, type.name + '::' + name, '=', value);
768         }
769      }
770      type = type.superclass;
771   }
772}
773
774// define readXXX and printXXX functions for each VM struct/class Type
775tmp = new Object();
776tmp.itr = sa.typedb.types;
777while (tmp.itr.hasNext()) {
778   tmp.type = tmp.itr.next();
779   tmp.name = tmp.type.name;
780   if (tmp.type.isPointerType() || tmp.type.isOopType() ||
781      tmp.type.isCIntegerType() || tmp.type.isJavaPrimitiveType() ||
782      tmp.name.equals('address') ||
783      tmp.name.equals("<opaque>")) {
784         // ignore;
785         continue;
786   } else {
787      // some type names have ':', '<', '>', '*', ' '. replace to make it as a
788      // JavaScript identifier
789      tmp.name = ("" + tmp.name).replace(/[:<>* ]/g, '_');
790      eval("function read" + tmp.name + "(addr) {" +
791           "   return readVMType('" + tmp.name + "', addr);}");
792      eval("function print" + tmp.name + "(addr) {" +
793           "   printVMType('" + tmp.name + "', addr); }");
794
795      /* FIXME: do we need this?
796      if (typeof(registerCommand) != 'undefined') {
797          var name = "print" + tmp.name;
798          registerCommand(name, name + " [address]", name);
799      }
800      */
801   }
802}
803//clean-up the temporary
804delete tmp;
805
806// VMObject factory
807
808// VM type to SA class map
809var  vmType2Class = new Object();
810
811// C2 only classes
812try{
813  vmType2Class["ExceptionBlob"] = sapkg.code.ExceptionBlob;
814  vmType2Class["UncommonTrapBlob"] = sapkg.code.UncommonTrapBlob;
815} catch(e) {
816  // Ignore exception. C2 specific objects might be not
817  // available in client VM
818}
819
820
821// This is *not* exhaustive. Add more if needed.
822// code blobs
823vmType2Class["BufferBlob"] = sapkg.code.BufferBlob;
824vmType2Class["nmethod"] = sapkg.code.NMethod;
825vmType2Class["RuntimeStub"] = sapkg.code.RuntimeStub;
826vmType2Class["SafepointBlob"] = sapkg.code.SafepointBlob;
827vmType2Class["C2IAdapter"] = sapkg.code.C2IAdapter;
828vmType2Class["DeoptimizationBlob"] = sapkg.code.DeoptimizationBlob;
829vmType2Class["I2CAdapter"] = sapkg.code.I2CAdapter;
830vmType2Class["OSRAdapter"] = sapkg.code.OSRAdapter;
831vmType2Class["PCDesc"] = sapkg.code.PCDesc;
832
833// interpreter
834vmType2Class["InterpreterCodelet"] = sapkg.interpreter.InterpreterCodelet;
835
836// Java Threads
837vmType2Class["JavaThread"] = sapkg.runtime.JavaThread;
838vmType2Class["CompilerThread"] = sapkg.runtime.CompilerThread;
839vmType2Class["CodeCacheSweeperThread"] = sapkg.runtime.CodeCacheSweeperThread;
840vmType2Class["DebuggerThread"] = sapkg.runtime.DebuggerThread;
841
842// gc
843vmType2Class["GenCollectedHeap"] = sapkg.memory.GenCollectedHeap;
844vmType2Class["DefNewGeneration"] = sapkg.memory.DefNewGeneration;
845vmType2Class["TenuredGeneration"] = sapkg.memory.TenuredGeneration;
846
847// generic VMObject factory for a given address
848// This is equivalent to VirtualConstructor.
849function newVMObject(addr) {
850   addr = any2addr(addr);
851   var result = null;
852   forEachVMType(function (type) {
853                    if (isOfVMType(addr, type)) {
854                       var clazz = vmType2Class[type.name];
855                       if (clazz != undefined) {
856                          result = new clazz(addr);
857                       }
858                       return false;
859                    } else {
860                       return true;
861                    }
862                 });
863   return result;
864}
865
866function vmobj2addr(vmobj) {
867   return vmobj.address;
868}
869
870function addr2vmobj(addr) {
871   return newVMObject(addr);
872}
873
874// Miscellaneous utilities
875
876// returns PointerLocation that describes the given pointer
877function findPtr(addr) {
878   addr = any2addr(addr);
879   return sapkg.utilities.PointerFinder.find(addr);
880}
881
882// is given address a valid Oop?
883function isOop(addr) {
884   addr = any2addr(addr);
885   var oopHandle = addr.addOffsetToAsOopHandle(0);
886   return sapkg.utilities.RobustOopDeterminator.oopLooksValid(oopHandle);
887}
888
889// returns description of given pointer as a String
890function whatis(addr) {
891  addr = any2addr(addr);
892  var ptrLoc = findPtr(addr);
893  if (!ptrLoc.isUnknown()) {
894    return ptrLoc.toString();
895  }
896
897  var vmType = vmTypeof(addr);
898  if (vmType != null) {
899    return "pointer to " + vmType.name;
900  }
901
902  var dso = loadObjectContainingPC(addr);
903  if (dso == null) {
904    return ptrLoc.toString();
905  }
906
907  var sym = dso.closestSymbolToPC(addr);
908  if (sym != null) {
909    return sym.name + '+' + sym.offset;
910  }
911
912  var s = dso.getName();
913  var p = s.lastIndexOf("/");
914  var base = dso.getBase();
915  return s.substring(p+1, s.length) + '+' + addr.minus(base);
916}
917