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