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 
  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 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 }