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