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.*;
41import 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
68public 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 SymbolTable  symbols;
82  private StringTable  strings;
83  private SystemDictionary dict;
84  private ClassLoaderDataGraph cldGraph;
85  private Threads      threads;
86  private ObjectSynchronizer synchronizer;
87  private JNIHandles   handles;
88  private Interpreter  interpreter;
89  private StubRoutines stubRoutines;
90  private Bytes        bytes;
91
92  /** Flag indicating if JVMTI support is included in the build */
93  private boolean      isJvmtiSupported;
94  /** Flags indicating whether we are attached to a core, C1, or C2 build */
95  private boolean      usingClientCompiler;
96  private boolean      usingServerCompiler;
97  /** alignment constants */
98  private boolean      isLP64;
99  private int          bytesPerLong;
100  private int          bytesPerWord;
101  private int          objectAlignmentInBytes;
102  private int          minObjAlignmentInBytes;
103  private int          logMinObjAlignmentInBytes;
104  private int          heapWordSize;
105  private int          heapOopSize;
106  private int          klassPtrSize;
107  private int          oopSize;
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 Flag in globals.hpp
139  public static final class Flag {
140     private String type;
141     private String name;
142     private Address addr;
143     private int flags;
144
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
152     public String getType() {
153        return type;
154     }
155
156     public String getName() {
157        return name;
158     }
159
160     public Address getAddress() {
161        return addr;
162     }
163
164     public int getOrigin() {
165        return flags & 0xF;  // XXX can we get the mask bits from somewhere?
166     }
167
168     public boolean isBool() {
169        return type.equals("bool");
170     }
171
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
179     public boolean isInt() {
180        return type.equals("int");
181     }
182
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
190     public boolean isUInt() {
191        return type.equals("uint");
192     }
193
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
201     public boolean isIntx() {
202        return type.equals("intx");
203     }
204
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
212     public boolean isUIntx() {
213        return type.equals("uintx");
214     }
215
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
223     public boolean isSizet() {
224        return type.equals("size_t");
225     }
226
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
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
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
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
380    intType = db.lookupType("int");
381    uintType = db.lookupType("uint");
382    intxType = db.lookupType("intx");
383    uintxType = db.lookupType("uintx");
384    sizetType = db.lookupType("size_t");
385    boolType = (CIntegerType) db.lookupType("bool");
386
387    minObjAlignmentInBytes = getObjectAlignmentInBytes();
388    if (minObjAlignmentInBytes == 8) {
389      logMinObjAlignmentInBytes = 3;
390    } else if (minObjAlignmentInBytes == 16) {
391      logMinObjAlignmentInBytes = 4;
392    } else {
393      throw new RuntimeException("Object alignment " + minObjAlignmentInBytes + " not yet supported");
394    }
395
396    if (isCompressedOopsEnabled()) {
397      // Size info for oops within java objects is fixed
398      heapOopSize = (int)getIntSize();
399    } else {
400      heapOopSize = (int)getOopSize();
401    }
402
403    if (isCompressedKlassPointersEnabled()) {
404      klassPtrSize = (int)getIntSize();
405    } else {
406      klassPtrSize = (int)getOopSize(); // same as an oop
407    }
408  }
409
410  /** This could be used by a reflective runtime system */
411  public static void initialize(TypeDataBase db, boolean isBigEndian) {
412    if (soleInstance != null) {
413      throw new RuntimeException("Attempt to initialize VM twice");
414    }
415    soleInstance = new VM(db, null, isBigEndian);
416    for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) {
417      ((Observer) iter.next()).update(null, null);
418    }
419  }
420
421  /** This is used by the debugging system */
422  public static void initialize(TypeDataBase db, JVMDebugger debugger) {
423    if (soleInstance != null) {
424      // Using multiple SA Tool classes in the same process creates a call here.
425      return;
426    }
427    soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian());
428
429    for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) {
430      ((Observer) iter.next()).update(null, null);
431    }
432
433    debugger.putHeapConst(soleInstance.getHeapOopSize(), soleInstance.getKlassPtrSize(),
434                          Universe.getNarrowOopBase(), Universe.getNarrowOopShift(),
435                          Universe.getNarrowKlassBase(), Universe.getNarrowKlassShift());
436  }
437
438  /** This is used by the debugging system */
439  public static void shutdown() {
440    soleInstance = null;
441  }
442
443  /** This is used by both the debugger and any runtime system. It is
444      the basic mechanism by which classes which mimic underlying VM
445      functionality cause themselves to be initialized. The given
446      observer will be notified (with arguments (null, null)) when the
447      VM is re-initialized, as well as when it registers itself with
448      the VM. */
449  public static void registerVMInitializedObserver(Observer o) {
450    vmInitializedObservers.add(o);
451    o.update(null, null);
452  }
453
454  /** This is the primary accessor used by both the debugger and any
455      potential runtime system */
456  public static VM getVM() {
457    if (soleInstance == null) {
458      throw new RuntimeException("VM.initialize() was not yet called");
459    }
460    return soleInstance;
461  }
462
463  /** This is only used by the debugging system. The given observer
464      will be notified if the underlying VM resumes execution. NOTE
465      that the given observer is not triggered if the VM is currently
466      running and therefore differs in behavior from {@link
467      #registerVMInitializedObserver} (because of the possibility of
468      race conditions if the observer is added while the VM is being
469      suspended or resumed).  */
470  public void registerVMResumedObserver(Observer o) {
471    vmResumedObservers.add(o);
472  }
473
474  /** This is only used by the debugging system. The given observer
475      will be notified if the underlying VM suspends execution. NOTE
476      that the given observer is not triggered if the VM is currently
477      suspended and therefore differs in behavior from {@link
478      #registerVMInitializedObserver} (because of the possibility of
479      race conditions if the observer is added while the VM is being
480      suspended or resumed).  */
481  public void registerVMSuspendedObserver(Observer o) {
482    vmSuspendedObservers.add(o);
483  }
484
485  /** This is only used by the debugging system. Informs all
486      registered resumption observers that the VM has been resumed.
487      The application is responsible for actually having performed the
488      resumption. No OopHandles must be used after this point, as they
489      may move in the target address space due to garbage
490      collection. */
491  public void fireVMResumed() {
492    for (Iterator iter = vmResumedObservers.iterator(); iter.hasNext(); ) {
493      ((Observer) iter.next()).update(null, null);
494    }
495  }
496
497  /** This is only used by the debugging system. Informs all
498      registered suspension observers that the VM has been suspended.
499      The application is responsible for actually having performed the
500      suspension. Garbage collection must be forbidden at this point;
501      for example, a JPDA-level suspension is not adequate since the
502      VM thread may still be running. */
503  public void fireVMSuspended() {
504    for (Iterator iter = vmSuspendedObservers.iterator(); iter.hasNext(); ) {
505      ((Observer) iter.next()).update(null, null);
506    }
507  }
508
509  /** Returns the OS this VM is running on. Notice that by delegating
510      to the debugger we can transparently support remote
511      debugging. */
512  public String getOS() {
513    if (debugger != null) {
514      return debugger.getOS();
515    }
516    return PlatformInfo.getOS();
517  }
518
519  /** Returns the CPU this VM is running on. Notice that by delegating
520      to the debugger we can transparently support remote
521      debugging. */
522  public String getCPU() {
523    if (debugger != null) {
524      return debugger.getCPU();
525    }
526    return PlatformInfo.getCPU();
527  }
528
529  public Type lookupType(String cTypeName) {
530    return db.lookupType(cTypeName);
531  }
532
533  public Integer lookupIntConstant(String name) {
534    return db.lookupIntConstant(name);
535  }
536
537  // Convenience function for conversions
538  static public long getAddressValue(Address addr) {
539    return VM.getVM().getDebugger().getAddressValue(addr);
540  }
541
542  public long getAddressSize() {
543    return db.getAddressSize();
544  }
545
546  public long getOopSize() {
547    return oopSize;
548  }
549
550  public long getLogAddressSize() {
551    return logAddressSize;
552  }
553
554  public long getIntSize() {
555    return db.getJIntType().getSize();
556  }
557
558  /** NOTE: this offset is in BYTES in this system! */
559  public long getStackBias() {
560    return stackBias;
561  }
562
563  /** Indicates whether the underlying machine supports the LP64 data
564      model. This is needed for conditionalizing code in a few places */
565  public boolean isLP64() {
566    if (Assert.ASSERTS_ENABLED) {
567      Assert.that(isDebugging(), "Debugging system only for now");
568    }
569    return isLP64;
570  }
571
572  /** Get bytes-per-long == long/double natural alignment. */
573  public int getBytesPerLong() {
574    return bytesPerLong;
575  }
576
577  public int getBytesPerWord() {
578    return bytesPerWord;
579  }
580
581  /** Get minimum object alignment in bytes. */
582  public int getMinObjAlignmentInBytes() {
583    return minObjAlignmentInBytes;
584  }
585  public int getLogMinObjAlignmentInBytes() {
586    return logMinObjAlignmentInBytes;
587  }
588
589  public int getHeapWordSize() {
590    return heapWordSize;
591  }
592
593  public int getHeapOopSize() {
594    return heapOopSize;
595  }
596
597  public int getKlassPtrSize() {
598    return klassPtrSize;
599  }
600  /** Utility routine for getting data structure alignment correct */
601  public long alignUp(long size, long alignment) {
602    return (size + alignment - 1) & ~(alignment - 1);
603  }
604
605  /** Utility routine for getting data structure alignment correct */
606  public long alignDown(long size, long alignment) {
607    return size & ~(alignment - 1);
608  }
609
610  /** Utility routine for building an int from two "unsigned" 16-bit
611      shorts */
612  public int buildIntFromShorts(short low, short high) {
613    return (((int) high) << 16) | (((int) low) & 0xFFFF);
614  }
615
616  /** Utility routine for building a long from two "unsigned" 32-bit
617      ints in <b>platform-dependent</b> order */
618  public long buildLongFromIntsPD(int oneHalf, int otherHalf) {
619    if (isBigEndian) {
620      return (((long) otherHalf) << 32) | (((long) oneHalf) & 0x00000000FFFFFFFFL);
621    } else{
622      return (((long) oneHalf) << 32) | (((long) otherHalf) & 0x00000000FFFFFFFFL);
623    }
624  }
625
626  public TypeDataBase getTypeDataBase() {
627    return db;
628  }
629
630  public Universe    getUniverse() {
631    if (universe == null) {
632      universe = new Universe();
633    }
634    return universe;
635  }
636
637  public ObjectHeap  getObjectHeap() {
638    if (heap == null) {
639      heap = new ObjectHeap(db);
640    }
641    return heap;
642  }
643
644  public SymbolTable getSymbolTable() {
645    if (symbols == null) {
646      symbols = SymbolTable.getTheTable();
647    }
648    return symbols;
649  }
650
651  public StringTable getStringTable() {
652    if (strings == null) {
653      strings = StringTable.getTheTable();
654    }
655    return strings;
656  }
657
658  public SystemDictionary getSystemDictionary() {
659    if (dict == null) {
660      dict = new SystemDictionary();
661    }
662    return dict;
663  }
664
665  public ClassLoaderDataGraph getClassLoaderDataGraph() {
666    if (cldGraph == null) {
667      cldGraph = new ClassLoaderDataGraph();
668    }
669    return cldGraph;
670  }
671
672  public Threads     getThreads() {
673    if (threads == null) {
674      threads = new Threads();
675    }
676    return threads;
677  }
678
679  public ObjectSynchronizer getObjectSynchronizer() {
680    if (synchronizer == null) {
681      synchronizer = new ObjectSynchronizer();
682    }
683    return synchronizer;
684  }
685
686  public JNIHandles getJNIHandles() {
687    if (handles == null) {
688      handles = new JNIHandles();
689    }
690    return handles;
691  }
692
693  public Interpreter getInterpreter() {
694    if (interpreter == null) {
695      interpreter = new Interpreter();
696    }
697    return interpreter;
698  }
699
700  public StubRoutines getStubRoutines() {
701    if (stubRoutines == null) {
702      stubRoutines = new StubRoutines();
703    }
704    return stubRoutines;
705  }
706
707  public VMRegImpl getVMRegImplInfo() {
708    if (vmregImpl == null) {
709      vmregImpl = new VMRegImpl();
710    }
711    return vmregImpl;
712  }
713
714  public Bytes getBytes() {
715    if (bytes == null) {
716      bytes = new Bytes(debugger.getMachineDescription());
717    }
718    return bytes;
719  }
720
721  /** Returns true if this is a isBigEndian, false otherwise */
722  public boolean isBigEndian() {
723    return isBigEndian;
724  }
725
726  /** Returns true if JVMTI is supported, false otherwise */
727  public boolean isJvmtiSupported() {
728    return isJvmtiSupported;
729  }
730
731  /** Returns true if this is a "core" build, false if either C1 or C2
732      is present */
733  public boolean isCore() {
734    return (!(usingClientCompiler || usingServerCompiler));
735  }
736
737  /** Returns true if this is a C1 build, false otherwise */
738  public boolean isClientCompiler() {
739    return usingClientCompiler;
740  }
741
742  /** Returns true if this is a C2 build, false otherwise */
743  public boolean isServerCompiler() {
744    return usingServerCompiler;
745  }
746
747  /** Returns true if C2 derived pointer table should be used, false otherwise */
748  public boolean useDerivedPointerTable() {
749    return !disableDerivedPointerTableCheck;
750  }
751
752  /** Returns the code cache; should not be used if is core build */
753  public CodeCache getCodeCache() {
754    if (Assert.ASSERTS_ENABLED) {
755      Assert.that(!isCore(), "noncore builds only");
756    }
757    if (codeCache == null) {
758      codeCache = new CodeCache();
759    }
760    return codeCache;
761  }
762
763  /** Should only be called for C1 builds */
764  public Runtime1 getRuntime1() {
765    if (Assert.ASSERTS_ENABLED) {
766      Assert.that(isClientCompiler(), "C1 builds only");
767    }
768    if (runtime1 == null) {
769      runtime1 = new Runtime1();
770    }
771    return runtime1;
772  }
773
774  /** Test to see whether we're in debugging mode (NOTE: this really
775      should not be tested by this code; currently only used in
776      StackFrameStream) */
777  public boolean isDebugging() {
778    return (debugger != null);
779  }
780
781  /** This is only used by the debugging (i.e., non-runtime) system */
782  public JVMDebugger getDebugger() {
783    if (debugger == null) {
784      throw new RuntimeException("Attempt to use debugger in runtime system");
785    }
786    return debugger;
787  }
788
789  /** Indicates whether a given program counter is in Java code. This
790      includes but is not spanned by the interpreter and code cache.
791      Only used in the debugging system, for implementing
792      JavaThread.currentFrameGuess() on x86. */
793  public boolean isJavaPCDbg(Address addr) {
794    // FIXME: this is not a complete enough set: must include areas
795    // like vtable stubs
796    return (getInterpreter().contains(addr) ||
797            getCodeCache().contains(addr));
798  }
799
800  /** FIXME: figure out where to stick this */
801  public int getInvocationEntryBCI() {
802    return invocationEntryBCI;
803  }
804
805  // FIXME: figure out where to stick this
806  public boolean wizardMode() {
807    return true;
808  }
809
810  public ReversePtrs getRevPtrs() {
811    return revPtrs;
812  }
813
814  public void setRevPtrs(ReversePtrs rp) {
815    revPtrs = rp;
816  }
817
818  // returns null, if not available.
819  public String getVMRelease() {
820    return vmRelease;
821  }
822
823  // returns null, if not available.
824  public String getVMInternalInfo() {
825    return vmInternalInfo;
826  }
827
828  public int getReserveForAllocationPrefetch() {
829    return reserveForAllocationPrefetch;
830  }
831
832  public boolean isSharingEnabled() {
833    if (sharingEnabled == null) {
834      Flag flag = getCommandLineFlag("UseSharedSpaces");
835      sharingEnabled = (flag == null)? Boolean.FALSE :
836          (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
837    }
838    return sharingEnabled.booleanValue();
839  }
840
841  public boolean isCompressedOopsEnabled() {
842    if (compressedOopsEnabled == null) {
843        Flag flag = getCommandLineFlag("UseCompressedOops");
844        compressedOopsEnabled = (flag == null) ? Boolean.FALSE:
845             (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
846    }
847    return compressedOopsEnabled.booleanValue();
848  }
849
850  public boolean isCompressedKlassPointersEnabled() {
851    if (compressedKlassPointersEnabled == null) {
852        Flag flag = getCommandLineFlag("UseCompressedClassPointers");
853        compressedKlassPointersEnabled = (flag == null) ? Boolean.FALSE:
854             (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
855    }
856    return compressedKlassPointersEnabled.booleanValue();
857  }
858
859  public int getObjectAlignmentInBytes() {
860    if (objectAlignmentInBytes == 0) {
861        Flag flag = getCommandLineFlag("ObjectAlignmentInBytes");
862        objectAlignmentInBytes = (flag == null) ? 8 : (int)flag.getIntx();
863    }
864    return objectAlignmentInBytes;
865  }
866
867  /** Indicates whether Thread-Local Allocation Buffers are used */
868  public boolean getUseTLAB() {
869      Flag flag = getCommandLineFlag("UseTLAB");
870      return (flag == null) ? false: flag.getBool();
871  }
872
873  public boolean getCommandLineBooleanFlag(String name) {
874    Flag flag = getCommandLineFlag(name);
875    return (flag == null) ? Boolean.FALSE:
876      (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
877  }
878
879  // returns null, if not available.
880  public Flag[] getCommandLineFlags() {
881    if (commandLineFlags == null) {
882       readCommandLineFlags();
883    }
884
885    return commandLineFlags;
886  }
887
888  public Flag getCommandLineFlag(String name) {
889    if (flagsMap == null) {
890      flagsMap = new HashMap();
891      Flag[] flags = getCommandLineFlags();
892      for (int i = 0; i < flags.length; i++) {
893        flagsMap.put(flags[i].getName(), flags[i]);
894      }
895    }
896    return (Flag) flagsMap.get(name);
897  }
898
899  private void readCommandLineFlags() {
900    // get command line flags
901    TypeDataBase db = getTypeDataBase();
902    Type flagType = db.lookupType("Flag");
903    int numFlags = (int) flagType.getCIntegerField("numFlags").getValue();
904    // NOTE: last flag contains null values.
905    commandLineFlags = new Flag[numFlags - 1];
906
907    Address flagAddr = flagType.getAddressField("flags").getValue();
908
909    AddressField typeFld = flagType.getAddressField("_type");
910    AddressField nameFld = flagType.getAddressField("_name");
911    AddressField addrFld = flagType.getAddressField("_addr");
912    CIntField flagsFld = new CIntField(flagType.getCIntegerField("_flags"), 0);
913
914    long flagSize = flagType.getSize(); // sizeof(Flag)
915
916    // NOTE: last flag contains null values.
917    for (int f = 0; f < numFlags - 1; f++) {
918      String type = CStringUtilities.getString(typeFld.getValue(flagAddr));
919      String name = CStringUtilities.getString(nameFld.getValue(flagAddr));
920      Address addr = addrFld.getValue(flagAddr);
921      int flags = (int)flagsFld.getValue(flagAddr);
922      commandLineFlags[f] = new Flag(type, name, addr, flags);
923      flagAddr = flagAddr.addOffsetTo(flagSize);
924    }
925
926    // sort flags by name
927    Arrays.sort(commandLineFlags, new Comparator() {
928        public int compare(Object o1, Object o2) {
929          Flag f1 = (Flag) o1;
930          Flag f2 = (Flag) o2;
931          return f1.getName().compareTo(f2.getName());
932        }
933      });
934  }
935
936  public String getSystemProperty(String key) {
937    Properties props = getSystemProperties();
938    return (props != null)? props.getProperty(key) : null;
939  }
940
941  public Properties getSystemProperties() {
942    if (sysProps == null) {
943       readSystemProperties();
944    }
945    return sysProps;
946  }
947
948  private void readSystemProperties() {
949    final InstanceKlass systemKls = getSystemDictionary().getSystemKlass();
950    systemKls.iterateStaticFields(new DefaultOopVisitor() {
951        ObjectReader objReader = new ObjectReader();
952        public void doOop(sun.jvm.hotspot.oops.OopField field, boolean isVMField) {
953          if (field.getID().getName().equals("props")) {
954            try {
955              sysProps = (Properties) objReader.readObject(field.getValue(getObj()));
956            } catch (Exception e) {
957              e.printStackTrace();
958            }
959          }
960        }
961      });
962  }
963}
964