View Javadoc
1   /*
2    * Copyright (c) 2000, 2013, 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  package sun.jvm.hotspot.runtime;
26  
27  import java.io.*;
28  import java.net.*;
29  import java.util.*;
30  import java.util.regex.*;
31  import sun.jvm.hotspot.code.*;
32  import sun.jvm.hotspot.c1.*;
33  import sun.jvm.hotspot.code.*;
34  import sun.jvm.hotspot.debugger.*;
35  import sun.jvm.hotspot.interpreter.*;
36  import sun.jvm.hotspot.memory.*;
37  import sun.jvm.hotspot.oops.*;
38  import sun.jvm.hotspot.types.*;
39  import sun.jvm.hotspot.utilities.*;
40  import sun.jvm.hotspot.runtime.*;
41  
42  /** <P> This class encapsulates the global state of the VM; the
43      universe, object heap, interpreter, etc. It is a Singleton and
44      must be initialized with a call to initialize() before calling
45      getVM(). </P>
46  
47      <P> Many auxiliary classes (i.e., most of the VMObjects) keep
48      needed field offsets in the form of static Field objects. In a
49      debugging system, the VM might be shutdown and re-initialized (on
50      a differently-configured build, i.e., 32- vs. 64-bit), and all old
51      cached state (including fields and field offsets) must be
52      flushed. </P>
53  
54      <P> An Observer pattern is used to implement the initialization of
55      such classes. Each such class, in its static initializer,
56      registers an Observer with the VM class via
57      VM.registerVMInitializedObserver(). This Observer is guaranteed to
58      be notified whenever the VM is initialized (or re-initialized). To
59      implement the first-time initialization, the observer is also
60      notified when it registers itself with the VM. (For bootstrapping
61      reasons, this implies that the constructor of VM can not
62      instantiate any such objects, since VM.soleInstance will not have
63      been set yet. This is a bootstrapping issue which may have to be
64      revisited later.) </P>
65  */
66  
67  public class VM {
68    private static VM    soleInstance;
69    private static List  vmInitializedObservers = new ArrayList();
70    private List         vmResumedObservers   = new ArrayList();
71    private List         vmSuspendedObservers = new ArrayList();
72    private TypeDataBase db;
73    private boolean      isBigEndian;
74    /** This is only present if in a debugging system */
75    private JVMDebugger  debugger;
76    private long         stackBias;
77    private long         logAddressSize;
78    private Universe     universe;
79    private ObjectHeap   heap;
80    private SymbolTable  symbols;
81    private StringTable  strings;
82    private SystemDictionary dict;
83    private Threads      threads;
84    private ObjectSynchronizer synchronizer;
85    private JNIHandles   handles;
86    private Interpreter  interpreter;
87    private StubRoutines stubRoutines;
88    private Bytes        bytes;
89  
90    /** Flags indicating whether we are attached to a core, C1, or C2 build */
91    private boolean      usingClientCompiler;
92    private boolean      usingServerCompiler;
93    /** alignment constants */
94    private boolean      isLP64;
95    private int          bytesPerLong;
96    private int          bytesPerWord;
97    private int          objectAlignmentInBytes;
98    private int          minObjAlignmentInBytes;
99    private int          logMinObjAlignmentInBytes;
100   private int          heapWordSize;
101   private int          heapOopSize;
102   private int          klassPtrSize;
103   private int          oopSize;
104   /** This is only present in a non-core build */
105   private CodeCache    codeCache;
106   /** This is only present in a C1 build */
107   private Runtime1     runtime1;
108   /** These constants come from globalDefinitions.hpp */
109   private int          invocationEntryBCI;
110   private int          invalidOSREntryBCI;
111   private ReversePtrs  revPtrs;
112   private VMRegImpl    vmregImpl;
113   private int          reserveForAllocationPrefetch;
114 
115   // System.getProperties from debuggee VM
116   private Properties   sysProps;
117 
118   // VM version strings come from Abstract_VM_Version class
119   private String       vmRelease;
120   private String       vmInternalInfo;
121 
122   private Flag[] commandLineFlags;
123   private Map flagsMap;
124 
125   private static Type intxType;
126   private static Type uintxType;
127   private static CIntegerType boolType;
128   private Boolean sharingEnabled;
129   private Boolean compressedOopsEnabled;
130   private Boolean compressedKlassPointersEnabled;
131 
132   // command line flags supplied to VM - see struct Flag in globals.hpp
133   public static final class Flag {
134      private String type;
135      private String name;
136      private Address addr;
137      private int flags;
138 
139      private Flag(String type, String name, Address addr, int flags) {
140         this.type = type;
141         this.name = name;
142         this.addr = addr;
143         this.flags = flags;
144      }
145 
146      public String getType() {
147         return type;
148      }
149 
150      public String getName() {
151         return name;
152      }
153 
154      public Address getAddress() {
155         return addr;
156      }
157 
158      public int getOrigin() {
159         return flags & 0xF;  // XXX can we get the mask bits from somewhere?
160      }
161 
162      public boolean isBool() {
163         return type.equals("bool");
164      }
165 
166      public boolean getBool() {
167         if (Assert.ASSERTS_ENABLED) {
168            Assert.that(isBool(), "not a bool flag!");
169         }
170         return addr.getCIntegerAt(0, boolType.getSize(), boolType.isUnsigned()) != 0;
171      }
172 
173      public boolean isIntx() {
174         return type.equals("intx");
175      }
176 
177      public long getIntx() {
178         if (Assert.ASSERTS_ENABLED) {
179            Assert.that(isIntx(), "not a intx flag!");
180         }
181         return addr.getCIntegerAt(0, intxType.getSize(), false);
182      }
183 
184      public boolean isUIntx() {
185         return type.equals("uintx");
186      }
187 
188      public long getUIntx() {
189         if (Assert.ASSERTS_ENABLED) {
190            Assert.that(isUIntx(), "not a uintx flag!");
191         }
192         return addr.getCIntegerAt(0, uintxType.getSize(), true);
193      }
194 
195      public String getValue() {
196         if (isBool()) {
197            return new Boolean(getBool()).toString();
198         } else if (isIntx()) {
199            return new Long(getIntx()).toString();
200         } else if (isUIntx()) {
201            return new Long(getUIntx()).toString();
202         } else {
203            return null;
204         }
205      }
206   };
207 
208   private static void checkVMVersion(String vmRelease) {
209      if (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null) {
210         // read sa build version.
211         String versionProp = "sun.jvm.hotspot.runtime.VM.saBuildVersion";
212         String saVersion = saProps.getProperty(versionProp);
213         if (saVersion == null)
214            throw new RuntimeException("Missing property " + versionProp);
215 
216         // Strip nonproduct VM version substring (note: saVersion doesn't have it).
217         String vmVersion = vmRelease.replaceAll("(-fastdebug)|(-debug)|(-jvmg)|(-optimized)|(-profiled)","");
218 
219         if (saVersion.equals(vmVersion)) {
220            // Exact match
221            return;
222         }
223         if (saVersion.indexOf('-') == saVersion.lastIndexOf('-') &&
224             vmVersion.indexOf('-') == vmVersion.lastIndexOf('-')) {
225            // Throw exception if different release versions:
226            // <major>.<minor>-b<n>
227            throw new VMVersionMismatchException(saVersion, vmRelease);
228         } else {
229            // Otherwise print warning to allow mismatch not release versions
230            // during development.
231            System.err.println("WARNING: Hotspot VM version " + vmRelease +
232                               " does not match with SA version " + saVersion +
233                               "." + " You may see unexpected results. ");
234         }
235      } else {
236         System.err.println("WARNING: You have disabled SA and VM version check. You may be "  +
237                            "using incompatible version of SA and you may see unexpected " +
238                            "results.");
239      }
240   }
241 
242   private static final boolean disableDerivedPointerTableCheck;
243   private static final Properties saProps;
244 
245   static {
246      saProps = new Properties();
247      URL url = null;
248      try {
249        url = VM.class.getClassLoader().getResource("sa.properties");
250        saProps.load(new BufferedInputStream(url.openStream()));
251      } catch (Exception e) {
252        System.err.println("Unable to load properties  " +
253                                   (url == null ? "null" : url.toString()) +
254                                   ": " + e.getMessage());
255      }
256 
257      disableDerivedPointerTableCheck = System.getProperty("sun.jvm.hotspot.runtime.VM.disableDerivedPointerTableCheck") != null;
258   }
259 
260   private VM(TypeDataBase db, JVMDebugger debugger, boolean isBigEndian) {
261     this.db          = db;
262     this.debugger    = debugger;
263     this.isBigEndian = isBigEndian;
264 
265     // Note that we don't construct universe, heap, threads,
266     // interpreter, or stubRoutines here (any more).  The current
267     // initialization mechanisms require that the VM be completely set
268     // up (i.e., out of its constructor, with soleInstance assigned)
269     // before their static initializers are run.
270 
271     if (db.getAddressSize() == 4) {
272       logAddressSize = 2;
273     } else if (db.getAddressSize() == 8) {
274       logAddressSize = 3;
275     } else {
276       throw new RuntimeException("Address size " + db.getAddressSize() + " not yet supported");
277     }
278 
279     // read VM version info
280     try {
281        Type vmVersion = db.lookupType("Abstract_VM_Version");
282        Address releaseAddr = vmVersion.getAddressField("_s_vm_release").getValue();
283        vmRelease = CStringUtilities.getString(releaseAddr);
284        Address vmInternalInfoAddr = vmVersion.getAddressField("_s_internal_vm_info_string").getValue();
285        vmInternalInfo = CStringUtilities.getString(vmInternalInfoAddr);
286 
287        CIntegerType intType = (CIntegerType) db.lookupType("int");
288        CIntegerField reserveForAllocationPrefetchField = vmVersion.getCIntegerField("_reserve_for_allocation_prefetch");
289        reserveForAllocationPrefetch = (int)reserveForAllocationPrefetchField.getCInteger(intType);
290     } catch (Exception exp) {
291        throw new RuntimeException("can't determine target's VM version : " + exp.getMessage());
292     }
293 
294     checkVMVersion(vmRelease);
295 
296     stackBias    = db.lookupIntConstant("STACK_BIAS").intValue();
297     invocationEntryBCI = db.lookupIntConstant("InvocationEntryBci").intValue();
298     invalidOSREntryBCI = db.lookupIntConstant("InvalidOSREntryBci").intValue();
299 
300     // We infer the presence of C1 or C2 from a couple of fields we
301     // already have present in the type database
302     {
303       Type type = db.lookupType("Method");
304       if (type.getField("_from_compiled_entry", false, false) == null) {
305         // Neither C1 nor C2 is present
306         usingClientCompiler = false;
307         usingServerCompiler = false;
308       } else {
309         // Determine whether C2 is present
310         if (db.lookupType("Matcher", false) != null) {
311           usingServerCompiler = true;
312         } else {
313           usingClientCompiler = true;
314         }
315       }
316     }
317 
318     if (debugger != null) {
319       isLP64 = debugger.getMachineDescription().isLP64();
320     }
321     bytesPerLong = db.lookupIntConstant("BytesPerLong").intValue();
322     bytesPerWord = db.lookupIntConstant("BytesPerWord").intValue();
323     heapWordSize = db.lookupIntConstant("HeapWordSize").intValue();
324     oopSize  = db.lookupIntConstant("oopSize").intValue();
325 
326     intxType = db.lookupType("intx");
327     uintxType = db.lookupType("uintx");
328     boolType = (CIntegerType) db.lookupType("bool");
329 
330     minObjAlignmentInBytes = getObjectAlignmentInBytes();
331     if (minObjAlignmentInBytes == 8) {
332       logMinObjAlignmentInBytes = 3;
333     } else if (minObjAlignmentInBytes == 16) {
334       logMinObjAlignmentInBytes = 4;
335     } else {
336       throw new RuntimeException("Object alignment " + minObjAlignmentInBytes + " not yet supported");
337     }
338 
339     if (isCompressedOopsEnabled()) {
340       // Size info for oops within java objects is fixed
341       heapOopSize = (int)getIntSize();
342     } else {
343       heapOopSize = (int)getOopSize();
344     }
345 
346     if (isCompressedKlassPointersEnabled()) {
347       klassPtrSize = (int)getIntSize();
348     } else {
349       klassPtrSize = (int)getOopSize(); // same as an oop
350     }
351   }
352 
353   /** This could be used by a reflective runtime system */
354   public static void initialize(TypeDataBase db, boolean isBigEndian) {
355     if (soleInstance != null) {
356       throw new RuntimeException("Attempt to initialize VM twice");
357     }
358     soleInstance = new VM(db, null, isBigEndian);
359     for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) {
360       ((Observer) iter.next()).update(null, null);
361     }
362   }
363 
364   /** This is used by the debugging system */
365   public static void initialize(TypeDataBase db, JVMDebugger debugger) {
366     if (soleInstance != null) {
367       // Using multiple SA Tool classes in the same process creates a call here.
368       return;
369     }
370     soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian());
371 
372     for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) {
373       ((Observer) iter.next()).update(null, null);
374     }
375 
376     debugger.putHeapConst(soleInstance.getHeapOopSize(), soleInstance.getKlassPtrSize(),
377                           Universe.getNarrowOopBase(), Universe.getNarrowOopShift(),
378                           Universe.getNarrowKlassBase(), Universe.getNarrowKlassShift());
379   }
380 
381   /** This is used by the debugging system */
382   public static void shutdown() {
383     soleInstance = null;
384   }
385 
386   /** This is used by both the debugger and any runtime system. It is
387       the basic mechanism by which classes which mimic underlying VM
388       functionality cause themselves to be initialized. The given
389       observer will be notified (with arguments (null, null)) when the
390       VM is re-initialized, as well as when it registers itself with
391       the VM. */
392   public static void registerVMInitializedObserver(Observer o) {
393     vmInitializedObservers.add(o);
394     o.update(null, null);
395   }
396 
397   /** This is the primary accessor used by both the debugger and any
398       potential runtime system */
399   public static VM getVM() {
400     if (soleInstance == null) {
401       throw new RuntimeException("VM.initialize() was not yet called");
402     }
403     return soleInstance;
404   }
405 
406   /** This is only used by the debugging system. The given observer
407       will be notified if the underlying VM resumes execution. NOTE
408       that the given observer is not triggered if the VM is currently
409       running and therefore differs in behavior from {@link
410       #registerVMInitializedObserver} (because of the possibility of
411       race conditions if the observer is added while the VM is being
412       suspended or resumed).  */
413   public void registerVMResumedObserver(Observer o) {
414     vmResumedObservers.add(o);
415   }
416 
417   /** This is only used by the debugging system. The given observer
418       will be notified if the underlying VM suspends execution. NOTE
419       that the given observer is not triggered if the VM is currently
420       suspended and therefore differs in behavior from {@link
421       #registerVMInitializedObserver} (because of the possibility of
422       race conditions if the observer is added while the VM is being
423       suspended or resumed).  */
424   public void registerVMSuspendedObserver(Observer o) {
425     vmSuspendedObservers.add(o);
426   }
427 
428   /** This is only used by the debugging system. Informs all
429       registered resumption observers that the VM has been resumed.
430       The application is responsible for actually having performed the
431       resumption. No OopHandles must be used after this point, as they
432       may move in the target address space due to garbage
433       collection. */
434   public void fireVMResumed() {
435     for (Iterator iter = vmResumedObservers.iterator(); iter.hasNext(); ) {
436       ((Observer) iter.next()).update(null, null);
437     }
438   }
439 
440   /** This is only used by the debugging system. Informs all
441       registered suspension observers that the VM has been suspended.
442       The application is responsible for actually having performed the
443       suspension. Garbage collection must be forbidden at this point;
444       for example, a JPDA-level suspension is not adequate since the
445       VM thread may still be running. */
446   public void fireVMSuspended() {
447     for (Iterator iter = vmSuspendedObservers.iterator(); iter.hasNext(); ) {
448       ((Observer) iter.next()).update(null, null);
449     }
450   }
451 
452   /** Returns the OS this VM is running on. Notice that by delegating
453       to the debugger we can transparently support remote
454       debugging. */
455   public String getOS() {
456     if (debugger != null) {
457       return debugger.getOS();
458     }
459     return PlatformInfo.getOS();
460   }
461 
462   /** Returns the CPU this VM is running on. Notice that by delegating
463       to the debugger we can transparently support remote
464       debugging. */
465   public String getCPU() {
466     if (debugger != null) {
467       return debugger.getCPU();
468     }
469     return PlatformInfo.getCPU();
470   }
471 
472   public Type lookupType(String cTypeName) {
473     return db.lookupType(cTypeName);
474   }
475 
476   public Integer lookupIntConstant(String name) {
477     return db.lookupIntConstant(name);
478   }
479 
480   // Convenience function for conversions
481   static public long getAddressValue(Address addr) {
482     return VM.getVM().getDebugger().getAddressValue(addr);
483   }
484 
485   public long getAddressSize() {
486     return db.getAddressSize();
487   }
488 
489   public long getOopSize() {
490     return oopSize;
491   }
492 
493   public long getLogAddressSize() {
494     return logAddressSize;
495   }
496 
497   public long getIntSize() {
498     return db.getJIntType().getSize();
499   }
500 
501   /** NOTE: this offset is in BYTES in this system! */
502   public long getStackBias() {
503     return stackBias;
504   }
505 
506   /** Indicates whether the underlying machine supports the LP64 data
507       model. This is needed for conditionalizing code in a few places */
508   public boolean isLP64() {
509     if (Assert.ASSERTS_ENABLED) {
510       Assert.that(isDebugging(), "Debugging system only for now");
511     }
512     return isLP64;
513   }
514 
515   /** Get bytes-per-long == long/double natural alignment. */
516   public int getBytesPerLong() {
517     return bytesPerLong;
518   }
519 
520   public int getBytesPerWord() {
521     return bytesPerWord;
522   }
523 
524   /** Get minimum object alignment in bytes. */
525   public int getMinObjAlignmentInBytes() {
526     return minObjAlignmentInBytes;
527   }
528   public int getLogMinObjAlignmentInBytes() {
529     return logMinObjAlignmentInBytes;
530   }
531 
532   public int getHeapWordSize() {
533     return heapWordSize;
534   }
535 
536   public int getHeapOopSize() {
537     return heapOopSize;
538   }
539 
540   public int getKlassPtrSize() {
541     return klassPtrSize;
542   }
543   /** Utility routine for getting data structure alignment correct */
544   public long alignUp(long size, long alignment) {
545     return (size + alignment - 1) & ~(alignment - 1);
546   }
547 
548   /** Utility routine for getting data structure alignment correct */
549   public long alignDown(long size, long alignment) {
550     return size & ~(alignment - 1);
551   }
552 
553   /** Utility routine for building an int from two "unsigned" 16-bit
554       shorts */
555   public int buildIntFromShorts(short low, short high) {
556     return (((int) high) << 16) | (((int) low) & 0xFFFF);
557   }
558 
559   /** Utility routine for building a long from two "unsigned" 32-bit
560       ints in <b>platform-dependent</b> order */
561   public long buildLongFromIntsPD(int oneHalf, int otherHalf) {
562     if (isBigEndian) {
563       return (((long) otherHalf) << 32) | (((long) oneHalf) & 0x00000000FFFFFFFFL);
564     } else{
565       return (((long) oneHalf) << 32) | (((long) otherHalf) & 0x00000000FFFFFFFFL);
566     }
567   }
568 
569   public TypeDataBase getTypeDataBase() {
570     return db;
571   }
572 
573   public Universe    getUniverse() {
574     if (universe == null) {
575       universe = new Universe();
576     }
577     return universe;
578   }
579 
580   public ObjectHeap  getObjectHeap() {
581     if (heap == null) {
582       heap = new ObjectHeap(db);
583     }
584     return heap;
585   }
586 
587   public SymbolTable getSymbolTable() {
588     if (symbols == null) {
589       symbols = SymbolTable.getTheTable();
590     }
591     return symbols;
592   }
593 
594   public StringTable getStringTable() {
595     if (strings == null) {
596       strings = StringTable.getTheTable();
597     }
598     return strings;
599   }
600 
601   public SystemDictionary getSystemDictionary() {
602     if (dict == null) {
603       dict = new SystemDictionary();
604     }
605     return dict;
606   }
607 
608   public Threads     getThreads() {
609     if (threads == null) {
610       threads = new Threads();
611     }
612     return threads;
613   }
614 
615   public ObjectSynchronizer getObjectSynchronizer() {
616     if (synchronizer == null) {
617       synchronizer = new ObjectSynchronizer();
618     }
619     return synchronizer;
620   }
621 
622   public JNIHandles getJNIHandles() {
623     if (handles == null) {
624       handles = new JNIHandles();
625     }
626     return handles;
627   }
628 
629   public Interpreter getInterpreter() {
630     if (interpreter == null) {
631       interpreter = new Interpreter();
632     }
633     return interpreter;
634   }
635 
636   public StubRoutines getStubRoutines() {
637     if (stubRoutines == null) {
638       stubRoutines = new StubRoutines();
639     }
640     return stubRoutines;
641   }
642 
643   public VMRegImpl getVMRegImplInfo() {
644     if (vmregImpl == null) {
645       vmregImpl = new VMRegImpl();
646     }
647     return vmregImpl;
648   }
649 
650   public Bytes getBytes() {
651     if (bytes == null) {
652       bytes = new Bytes(debugger.getMachineDescription());
653     }
654     return bytes;
655   }
656 
657   /** Returns true if this is a isBigEndian, false otherwise */
658   public boolean isBigEndian() {
659     return isBigEndian;
660   }
661 
662   /** Returns true if this is a "core" build, false if either C1 or C2
663       is present */
664   public boolean isCore() {
665     return (!(usingClientCompiler || usingServerCompiler));
666   }
667 
668   /** Returns true if this is a C1 build, false otherwise */
669   public boolean isClientCompiler() {
670     return usingClientCompiler;
671   }
672 
673   /** Returns true if this is a C2 build, false otherwise */
674   public boolean isServerCompiler() {
675     return usingServerCompiler;
676   }
677 
678   /** Returns true if C2 derived pointer table should be used, false otherwise */
679   public boolean useDerivedPointerTable() {
680     return !disableDerivedPointerTableCheck;
681   }
682 
683   /** Returns the code cache; should not be used if is core build */
684   public CodeCache getCodeCache() {
685     if (Assert.ASSERTS_ENABLED) {
686       Assert.that(!isCore(), "noncore builds only");
687     }
688     if (codeCache == null) {
689       codeCache = new CodeCache();
690     }
691     return codeCache;
692   }
693 
694   /** Should only be called for C1 builds */
695   public Runtime1 getRuntime1() {
696     if (Assert.ASSERTS_ENABLED) {
697       Assert.that(isClientCompiler(), "C1 builds only");
698     }
699     if (runtime1 == null) {
700       runtime1 = new Runtime1();
701     }
702     return runtime1;
703   }
704 
705   /** Test to see whether we're in debugging mode (NOTE: this really
706       should not be tested by this code; currently only used in
707       StackFrameStream) */
708   public boolean isDebugging() {
709     return (debugger != null);
710   }
711 
712   /** This is only used by the debugging (i.e., non-runtime) system */
713   public JVMDebugger getDebugger() {
714     if (debugger == null) {
715       throw new RuntimeException("Attempt to use debugger in runtime system");
716     }
717     return debugger;
718   }
719 
720   /** Indicates whether a given program counter is in Java code. This
721       includes but is not spanned by the interpreter and code cache.
722       Only used in the debugging system, for implementing
723       JavaThread.currentFrameGuess() on x86. */
724   public boolean isJavaPCDbg(Address addr) {
725     // FIXME: this is not a complete enough set: must include areas
726     // like vtable stubs
727     return (getInterpreter().contains(addr) ||
728             getCodeCache().contains(addr));
729   }
730 
731   /** FIXME: figure out where to stick this */
732   public int getInvocationEntryBCI() {
733     return invocationEntryBCI;
734   }
735 
736   /** FIXME: figure out where to stick this */
737   public int getInvalidOSREntryBCI() {
738     return invalidOSREntryBCI;
739   }
740 
741   // FIXME: figure out where to stick this
742   public boolean wizardMode() {
743     return true;
744   }
745 
746   public ReversePtrs getRevPtrs() {
747     return revPtrs;
748   }
749 
750   public void setRevPtrs(ReversePtrs rp) {
751     revPtrs = rp;
752   }
753 
754   // returns null, if not available.
755   public String getVMRelease() {
756     return vmRelease;
757   }
758 
759   // returns null, if not available.
760   public String getVMInternalInfo() {
761     return vmInternalInfo;
762   }
763 
764   public int getReserveForAllocationPrefetch() {
765     return reserveForAllocationPrefetch;
766   }
767 
768   public boolean isSharingEnabled() {
769     if (sharingEnabled == null) {
770       Flag flag = getCommandLineFlag("UseSharedSpaces");
771       sharingEnabled = (flag == null)? Boolean.FALSE :
772           (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
773     }
774     return sharingEnabled.booleanValue();
775   }
776 
777   public boolean isCompressedOopsEnabled() {
778     if (compressedOopsEnabled == null) {
779         Flag flag = getCommandLineFlag("UseCompressedOops");
780         compressedOopsEnabled = (flag == null) ? Boolean.FALSE:
781              (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
782     }
783     return compressedOopsEnabled.booleanValue();
784   }
785 
786   public boolean isCompressedKlassPointersEnabled() {
787     if (compressedKlassPointersEnabled == null) {
788         Flag flag = getCommandLineFlag("UseCompressedClassPointers");
789         compressedKlassPointersEnabled = (flag == null) ? Boolean.FALSE:
790              (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
791     }
792     return compressedKlassPointersEnabled.booleanValue();
793   }
794 
795   public int getObjectAlignmentInBytes() {
796     if (objectAlignmentInBytes == 0) {
797         Flag flag = getCommandLineFlag("ObjectAlignmentInBytes");
798         objectAlignmentInBytes = (flag == null) ? 8 : (int)flag.getIntx();
799     }
800     return objectAlignmentInBytes;
801   }
802 
803   /** Indicates whether Thread-Local Allocation Buffers are used */
804   public boolean getUseTLAB() {
805       Flag flag = getCommandLineFlag("UseTLAB");
806       return (flag == null) ? false: flag.getBool();
807   }
808 
809   // returns null, if not available.
810   public Flag[] getCommandLineFlags() {
811     if (commandLineFlags == null) {
812        readCommandLineFlags();
813     }
814 
815     return commandLineFlags;
816   }
817 
818   public Flag getCommandLineFlag(String name) {
819     if (flagsMap == null) {
820       flagsMap = new HashMap();
821       Flag[] flags = getCommandLineFlags();
822       for (int i = 0; i < flags.length; i++) {
823         flagsMap.put(flags[i].getName(), flags[i]);
824       }
825     }
826     return (Flag) flagsMap.get(name);
827   }
828 
829   private void readCommandLineFlags() {
830     // get command line flags
831     TypeDataBase db = getTypeDataBase();
832     Type flagType = db.lookupType("Flag");
833     int numFlags = (int) flagType.getCIntegerField("numFlags").getValue();
834     // NOTE: last flag contains null values.
835     commandLineFlags = new Flag[numFlags - 1];
836 
837     Address flagAddr = flagType.getAddressField("flags").getValue();
838 
839     AddressField typeFld = flagType.getAddressField("_type");
840     AddressField nameFld = flagType.getAddressField("_name");
841     AddressField addrFld = flagType.getAddressField("_addr");
842     CIntField flagsFld = new CIntField(flagType.getCIntegerField("_flags"), 0);
843 
844     long flagSize = flagType.getSize(); // sizeof(Flag)
845 
846     // NOTE: last flag contains null values.
847     for (int f = 0; f < numFlags - 1; f++) {
848       String type = CStringUtilities.getString(typeFld.getValue(flagAddr));
849       String name = CStringUtilities.getString(nameFld.getValue(flagAddr));
850       Address addr = addrFld.getValue(flagAddr);
851       int flags = (int)flagsFld.getValue(flagAddr);
852       commandLineFlags[f] = new Flag(type, name, addr, flags);
853       flagAddr = flagAddr.addOffsetTo(flagSize);
854     }
855 
856     // sort flags by name
857     Arrays.sort(commandLineFlags, new Comparator() {
858         public int compare(Object o1, Object o2) {
859           Flag f1 = (Flag) o1;
860           Flag f2 = (Flag) o2;
861           return f1.getName().compareTo(f2.getName());
862         }
863       });
864   }
865 
866   public String getSystemProperty(String key) {
867     Properties props = getSystemProperties();
868     return (props != null)? props.getProperty(key) : null;
869   }
870 
871   public Properties getSystemProperties() {
872     if (sysProps == null) {
873        readSystemProperties();
874     }
875     return sysProps;
876   }
877 
878   private void readSystemProperties() {
879     final InstanceKlass systemKls = getSystemDictionary().getSystemKlass();
880     systemKls.iterateStaticFields(new DefaultOopVisitor() {
881         ObjectReader objReader = new ObjectReader();
882         public void doOop(sun.jvm.hotspot.oops.OopField field, boolean isVMField) {
883           if (field.getID().getName().equals("props")) {
884             try {
885               sysProps = (Properties) objReader.readObject(field.getValue(getObj()));
886             } catch (Exception e) {
887               e.printStackTrace();
888             }
889           }
890         }
891       });
892   }
893 }