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