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