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