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