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