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