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