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