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