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