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