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