1 /*
   2  * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.runtime;
  26 
  27 import java.io.*;
  28 import java.net.*;
  29 import java.util.*;
  30 import java.util.regex.*;
  31 import sun.jvm.hotspot.code.*;
  32 import sun.jvm.hotspot.c1.*;
  33 import sun.jvm.hotspot.code.*;
  34 import sun.jvm.hotspot.debugger.*;
  35 import sun.jvm.hotspot.interpreter.*;
  36 import sun.jvm.hotspot.memory.*;
  37 import sun.jvm.hotspot.oops.*;
  38 import sun.jvm.hotspot.types.*;
  39 import sun.jvm.hotspot.utilities.*;
  40 import sun.jvm.hotspot.runtime.*;
  41 
  42 /** <P> This class encapsulates the global state of the VM; the
  43     universe, object heap, interpreter, etc. It is a Singleton and
  44     must be initialized with a call to initialize() before calling
  45     getVM(). </P>
  46 
  47     <P> Many auxiliary classes (i.e., most of the VMObjects) keep
  48     needed field offsets in the form of static Field objects. In a
  49     debugging system, the VM might be shutdown and re-initialized (on
  50     a differently-configured build, i.e., 32- vs. 64-bit), and all old
  51     cached state (including fields and field offsets) must be
  52     flushed. </P>
  53 
  54     <P> An Observer pattern is used to implement the initialization of
  55     such classes. Each such class, in its static initializer,
  56     registers an Observer with the VM class via
  57     VM.registerVMInitializedObserver(). This Observer is guaranteed to
  58     be notified whenever the VM is initialized (or re-initialized). To
  59     implement the first-time initialization, the observer is also
  60     notified when it registers itself with the VM. (For bootstrapping
  61     reasons, this implies that the constructor of VM can not
  62     instantiate any such objects, since VM.soleInstance will not have
  63     been set yet. This is a bootstrapping issue which may have to be
  64     revisited later.) </P>
  65 */
  66 
  67 public class VM {
  68   private static VM    soleInstance;
  69   private static List  vmInitializedObservers = new ArrayList();
  70   private List         vmResumedObservers   = new ArrayList();
  71   private List         vmSuspendedObservers = new ArrayList();
  72   private TypeDataBase db;
  73   private boolean      isBigEndian;
  74   /** This is only present if in a debugging system */
  75   private JVMDebugger  debugger;
  76   private long         stackBias;
  77   private long         logAddressSize;
  78   private Universe     universe;
  79   private ObjectHeap   heap;
  80   private SymbolTable  symbols;
  81   private StringTable  strings;
  82   private SystemDictionary dict;
  83   private Threads      threads;
  84   private ObjectSynchronizer synchronizer;
  85   private JNIHandles   handles;
  86   private Interpreter  interpreter;
  87   private StubRoutines stubRoutines;
  88   private Bytes        bytes;
  89 
  90   private RicochetBlob ricochetBlob;
  91 
  92   /** Flags indicating whether we are attached to a core, C1, or C2 build */
  93   private boolean      usingClientCompiler;
  94   private boolean      usingServerCompiler;
  95   /** Flag indicating whether UseTLAB is turned on */
  96   private boolean      useTLAB;
  97   /** alignment constants */
  98   private boolean      isLP64;
  99   private int          bytesPerLong;
 100   private int          objectAlignmentInBytes;
 101   private int          minObjAlignmentInBytes;
 102   private int          logMinObjAlignmentInBytes;
 103   private int          heapWordSize;
 104   private int          heapOopSize;
 105   private int          oopSize;
 106   /** This is only present in a non-core build */
 107   private CodeCache    codeCache;
 108   /** This is only present in a C1 build */
 109   private Runtime1     runtime1;
 110   /** These constants come from globalDefinitions.hpp */
 111   private int          invocationEntryBCI;
 112   private int          invalidOSREntryBCI;
 113   private ReversePtrs  revPtrs;
 114   private VMRegImpl    vmregImpl;
 115 
 116   // System.getProperties from debuggee VM
 117   private Properties   sysProps;
 118 
 119   // VM version strings come from Abstract_VM_Version class
 120   private String       vmRelease;
 121   private String       vmInternalInfo;
 122 
 123   private Flag[] commandLineFlags;
 124   private Map flagsMap;
 125 
 126   private static Type intxType;
 127   private static Type uintxType;
 128   private static CIntegerType boolType;
 129   private Boolean sharingEnabled;
 130   private Boolean compressedOopsEnabled;
 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 disableDerivedPrinterTableCheck;
 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        throw new RuntimeException("Unable to load properties  " +
 260                                   (url == null ? "null" : url.toString()) +
 261                                   ": " + e.getMessage());
 262      }
 263 
 264      disableDerivedPrinterTableCheck = 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     } catch (Exception exp) {
 294        throw new RuntimeException("can't determine target's VM version : " + exp.getMessage());
 295     }
 296 
 297     checkVMVersion(vmRelease);
 298 
 299     stackBias    = db.lookupIntConstant("STACK_BIAS").intValue();
 300     invocationEntryBCI = db.lookupIntConstant("InvocationEntryBci").intValue();
 301     invalidOSREntryBCI = db.lookupIntConstant("InvalidOSREntryBci").intValue();
 302 
 303     // We infer the presence of C1 or C2 from a couple of fields we
 304     // already have present in the type database
 305     {
 306       Type type = db.lookupType("methodOopDesc");
 307       if (type.getField("_from_compiled_entry", false, false) == null) {
 308         // Neither C1 nor C2 is present
 309         usingClientCompiler = false;
 310         usingServerCompiler = false;
 311       } else {
 312         // Determine whether C2 is present
 313         if (db.lookupType("Matcher", false) != null) {
 314           usingServerCompiler = true;
 315         } else {
 316           usingClientCompiler = true;
 317         }
 318       }
 319     }
 320 
 321     useTLAB = (db.lookupIntConstant("UseTLAB").intValue() != 0);
 322 
 323     if (debugger != null) {
 324       isLP64 = debugger.getMachineDescription().isLP64();
 325     }
 326     bytesPerLong = db.lookupIntConstant("BytesPerLong").intValue();
 327     heapWordSize = db.lookupIntConstant("HeapWordSize").intValue();
 328     oopSize  = db.lookupIntConstant("oopSize").intValue();
 329 
 330     intxType = db.lookupType("intx");
 331     uintxType = db.lookupType("uintx");
 332     boolType = (CIntegerType) db.lookupType("bool");
 333 
 334     minObjAlignmentInBytes = getObjectAlignmentInBytes();
 335     if (minObjAlignmentInBytes == 8) {
 336       logMinObjAlignmentInBytes = 3;
 337     } else if (minObjAlignmentInBytes == 16) {
 338       logMinObjAlignmentInBytes = 4;
 339     } else {
 340       throw new RuntimeException("Object alignment " + minObjAlignmentInBytes + " not yet supported");
 341     }
 342 
 343     if (isCompressedOopsEnabled()) {
 344       // Size info for oops within java objects is fixed
 345       heapOopSize = (int)getIntSize();
 346     } else {
 347       heapOopSize = (int)getOopSize();
 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       throw new RuntimeException("Attempt to initialize VM twice");
 366     }
 367     soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian());
 368 
 369     for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) {
 370       ((Observer) iter.next()).update(null, null);
 371     }
 372 
 373     debugger.putHeapConst(soleInstance.getHeapOopSize(), Universe.getNarrowOopBase(),
 374                           Universe.getNarrowOopShift());
 375   }
 376 
 377   /** This is used by the debugging system */
 378   public static void shutdown() {
 379     soleInstance = null;
 380   }
 381 
 382   /** This is used by both the debugger and any runtime system. It is
 383       the basic mechanism by which classes which mimic underlying VM
 384       functionality cause themselves to be initialized. The given
 385       observer will be notified (with arguments (null, null)) when the
 386       VM is re-initialized, as well as when it registers itself with
 387       the VM. */
 388   public static void registerVMInitializedObserver(Observer o) {
 389     vmInitializedObservers.add(o);
 390     o.update(null, null);
 391   }
 392 
 393   /** This is the primary accessor used by both the debugger and any
 394       potential runtime system */
 395   public static VM getVM() {
 396     if (soleInstance == null) {
 397       throw new RuntimeException("VM.initialize() was not yet called");
 398     }
 399     return soleInstance;
 400   }
 401 
 402   /** This is only used by the debugging system. The given observer
 403       will be notified if the underlying VM resumes execution. NOTE
 404       that the given observer is not triggered if the VM is currently
 405       running and therefore differs in behavior from {@link
 406       #registerVMInitializedObserver} (because of the possibility of
 407       race conditions if the observer is added while the VM is being
 408       suspended or resumed).  */
 409   public void registerVMResumedObserver(Observer o) {
 410     vmResumedObservers.add(o);
 411   }
 412 
 413   /** This is only used by the debugging system. The given observer
 414       will be notified if the underlying VM suspends execution. NOTE
 415       that the given observer is not triggered if the VM is currently
 416       suspended 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 registerVMSuspendedObserver(Observer o) {
 421     vmSuspendedObservers.add(o);
 422   }
 423 
 424   /** This is only used by the debugging system. Informs all
 425       registered resumption observers that the VM has been resumed.
 426       The application is responsible for actually having performed the
 427       resumption. No OopHandles must be used after this point, as they
 428       may move in the target address space due to garbage
 429       collection. */
 430   public void fireVMResumed() {
 431     for (Iterator iter = vmResumedObservers.iterator(); iter.hasNext(); ) {
 432       ((Observer) iter.next()).update(null, null);
 433     }
 434   }
 435 
 436   /** This is only used by the debugging system. Informs all
 437       registered suspension observers that the VM has been suspended.
 438       The application is responsible for actually having performed the
 439       suspension. Garbage collection must be forbidden at this point;
 440       for example, a JPDA-level suspension is not adequate since the
 441       VM thread may still be running. */
 442   public void fireVMSuspended() {
 443     for (Iterator iter = vmSuspendedObservers.iterator(); iter.hasNext(); ) {
 444       ((Observer) iter.next()).update(null, null);
 445     }
 446   }
 447 
 448   /** Returns the OS this VM is running on. Notice that by delegating
 449       to the debugger we can transparently support remote
 450       debugging. */
 451   public String getOS() {
 452     if (debugger != null) {
 453       return debugger.getOS();
 454     }
 455     return PlatformInfo.getOS();
 456   }
 457 
 458   /** Returns the CPU this VM is running on. Notice that by delegating
 459       to the debugger we can transparently support remote
 460       debugging. */
 461   public String getCPU() {
 462     if (debugger != null) {
 463       return debugger.getCPU();
 464     }
 465     return PlatformInfo.getCPU();
 466   }
 467 
 468   public Type lookupType(String cTypeName) {
 469     return db.lookupType(cTypeName);
 470   }
 471 
 472   public Integer lookupIntConstant(String name) {
 473     return db.lookupIntConstant(name);
 474   }
 475 
 476   public long getAddressSize() {
 477     return db.getAddressSize();
 478   }
 479 
 480   public long getOopSize() {
 481     return oopSize;
 482   }
 483 
 484   public long getLogAddressSize() {
 485     return logAddressSize;
 486   }
 487 
 488   public long getIntSize() {
 489     return db.getJIntType().getSize();
 490   }
 491 
 492   /** NOTE: this offset is in BYTES in this system! */
 493   public long getStackBias() {
 494     return stackBias;
 495   }
 496 
 497   /** Indicates whether the underlying machine supports the LP64 data
 498       model. This is needed for conditionalizing code in a few places */
 499   public boolean isLP64() {
 500     if (Assert.ASSERTS_ENABLED) {
 501       Assert.that(isDebugging(), "Debugging system only for now");
 502     }
 503     return isLP64;
 504   }
 505 
 506   /** Get bytes-per-long == long/double natural alignment. */
 507   public int getBytesPerLong() {
 508     return bytesPerLong;
 509   }
 510 
 511   /** Get minimum object alignment in bytes. */
 512   public int getMinObjAlignmentInBytes() {
 513     return minObjAlignmentInBytes;
 514   }
 515   public int getLogMinObjAlignmentInBytes() {
 516     return logMinObjAlignmentInBytes;
 517   }
 518 
 519   public int getHeapWordSize() {
 520     return heapWordSize;
 521   }
 522 
 523   public int getHeapOopSize() {
 524     return heapOopSize;
 525   }
 526   /** Utility routine for getting data structure alignment correct */
 527   public long alignUp(long size, long alignment) {
 528     return (size + alignment - 1) & ~(alignment - 1);
 529   }
 530 
 531   /** Utility routine for getting data structure alignment correct */
 532   public long alignDown(long size, long alignment) {
 533     return size & ~(alignment - 1);
 534   }
 535 
 536   /** Utility routine for building an int from two "unsigned" 16-bit
 537       shorts */
 538   public int buildIntFromShorts(short low, short high) {
 539     return (((int) high) << 16) | (((int) low) & 0xFFFF);
 540   }
 541 
 542   /** Utility routine for building a long from two "unsigned" 32-bit
 543       ints in <b>platform-dependent</b> order */
 544   public long buildLongFromIntsPD(int oneHalf, int otherHalf) {
 545     if (isBigEndian) {
 546       return (((long) otherHalf) << 32) | (((long) oneHalf) & 0x00000000FFFFFFFFL);
 547     } else{
 548       return (((long) oneHalf) << 32) | (((long) otherHalf) & 0x00000000FFFFFFFFL);
 549     }
 550   }
 551 
 552   /** Indicates whether Thread-Local Allocation Buffers are used */
 553   public boolean getUseTLAB() {
 554     return useTLAB;
 555   }
 556 
 557   public TypeDataBase getTypeDataBase() {
 558     return db;
 559   }
 560 
 561   public Universe    getUniverse() {
 562     if (universe == null) {
 563       universe = new Universe();
 564     }
 565     return universe;
 566   }
 567 
 568   public ObjectHeap  getObjectHeap() {
 569     if (heap == null) {
 570       heap = new ObjectHeap(db);
 571     }
 572     return heap;
 573   }
 574 
 575   public SymbolTable getSymbolTable() {
 576     if (symbols == null) {
 577       symbols = SymbolTable.getTheTable();
 578     }
 579     return symbols;
 580   }
 581 
 582   public StringTable getStringTable() {
 583     if (strings == null) {
 584       strings = StringTable.getTheTable();
 585     }
 586     return strings;
 587   }
 588 
 589   public SystemDictionary getSystemDictionary() {
 590     if (dict == null) {
 591       dict = new SystemDictionary();
 592     }
 593     return dict;
 594   }
 595 
 596   public Threads     getThreads() {
 597     if (threads == null) {
 598       threads = new Threads();
 599     }
 600     return threads;
 601   }
 602 
 603   public ObjectSynchronizer getObjectSynchronizer() {
 604     if (synchronizer == null) {
 605       synchronizer = new ObjectSynchronizer();
 606     }
 607     return synchronizer;
 608   }
 609 
 610   public JNIHandles getJNIHandles() {
 611     if (handles == null) {
 612       handles = new JNIHandles();
 613     }
 614     return handles;
 615   }
 616 
 617   public Interpreter getInterpreter() {
 618     if (interpreter == null) {
 619       interpreter = new Interpreter();
 620     }
 621     return interpreter;
 622   }
 623 
 624   public StubRoutines getStubRoutines() {
 625     if (stubRoutines == null) {
 626       stubRoutines = new StubRoutines();
 627     }
 628     return stubRoutines;
 629   }
 630 
 631   public RicochetBlob ricochetBlob() {
 632     if (ricochetBlob == null) {
 633       Type ricochetType  = db.lookupType("SharedRuntime");
 634       AddressField ricochetBlobAddress = ricochetType.getAddressField("_ricochet_blob");
 635       Address addr = ricochetBlobAddress.getValue();
 636       if (addr != null) {
 637         ricochetBlob = new RicochetBlob(addr);
 638       }
 639     }
 640     return ricochetBlob;
 641   }
 642 
 643   public VMRegImpl getVMRegImplInfo() {
 644     if (vmregImpl == null) {
 645       vmregImpl = new VMRegImpl();
 646     }
 647     return vmregImpl;
 648   }
 649 
 650   public Bytes getBytes() {
 651     if (bytes == null) {
 652       bytes = new Bytes(debugger.getMachineDescription());
 653     }
 654     return bytes;
 655   }
 656 
 657   /** Returns true if this is a isBigEndian, false otherwise */
 658   public boolean isBigEndian() {
 659     return isBigEndian;
 660   }
 661 
 662   /** Returns true if this is a "core" build, false if either C1 or C2
 663       is present */
 664   public boolean isCore() {
 665     return (!(usingClientCompiler || usingServerCompiler));
 666   }
 667 
 668   /** Returns true if this is a C1 build, false otherwise */
 669   public boolean isClientCompiler() {
 670     return usingClientCompiler;
 671   }
 672 
 673   /** Returns true if this is a C2 build, false otherwise */
 674   public boolean isServerCompiler() {
 675     return usingServerCompiler;
 676   }
 677 
 678   /** Returns true if C2 derived pointer table should be used, false otherwise */
 679   public boolean useDerivedPointerTable() {
 680     return !disableDerivedPrinterTableCheck;
 681   }
 682 
 683   /** Returns the code cache; should not be used if is core build */
 684   public CodeCache getCodeCache() {
 685     if (Assert.ASSERTS_ENABLED) {
 686       Assert.that(!isCore(), "noncore builds only");
 687     }
 688     if (codeCache == null) {
 689       codeCache = new CodeCache();
 690     }
 691     return codeCache;
 692   }
 693 
 694   /** Should only be called for C1 builds */
 695   public Runtime1 getRuntime1() {
 696     if (Assert.ASSERTS_ENABLED) {
 697       Assert.that(isClientCompiler(), "C1 builds only");
 698     }
 699     if (runtime1 == null) {
 700       runtime1 = new Runtime1();
 701     }
 702     return runtime1;
 703   }
 704 
 705   /** Test to see whether we're in debugging mode (NOTE: this really
 706       should not be tested by this code; currently only used in
 707       StackFrameStream) */
 708   public boolean isDebugging() {
 709     return (debugger != null);
 710   }
 711 
 712   /** This is only used by the debugging (i.e., non-runtime) system */
 713   public JVMDebugger getDebugger() {
 714     if (debugger == null) {
 715       throw new RuntimeException("Attempt to use debugger in runtime system");
 716     }
 717     return debugger;
 718   }
 719 
 720   /** Indicates whether a given program counter is in Java code. This
 721       includes but is not spanned by the interpreter and code cache.
 722       Only used in the debugging system, for implementing
 723       JavaThread.currentFrameGuess() on x86. */
 724   public boolean isJavaPCDbg(Address addr) {
 725     // FIXME: this is not a complete enough set: must include areas
 726     // like vtable stubs
 727     return (getInterpreter().contains(addr) ||
 728             getCodeCache().contains(addr));
 729   }
 730 
 731   /** FIXME: figure out where to stick this */
 732   public int getInvocationEntryBCI() {
 733     return invocationEntryBCI;
 734   }
 735 
 736   /** FIXME: figure out where to stick this */
 737   public int getInvalidOSREntryBCI() {
 738     return invalidOSREntryBCI;
 739   }
 740 
 741   // FIXME: figure out where to stick this
 742   public boolean wizardMode() {
 743     return true;
 744   }
 745 
 746   public ReversePtrs getRevPtrs() {
 747     return revPtrs;
 748   }
 749 
 750   public void setRevPtrs(ReversePtrs rp) {
 751     revPtrs = rp;
 752   }
 753 
 754   // returns null, if not available.
 755   public String getVMRelease() {
 756     return vmRelease;
 757   }
 758 
 759   // returns null, if not available.
 760   public String getVMInternalInfo() {
 761     return vmInternalInfo;
 762   }
 763 
 764   public boolean isSharingEnabled() {
 765     if (sharingEnabled == null) {
 766       Flag flag = getCommandLineFlag("UseSharedSpaces");
 767       sharingEnabled = (flag == null)? Boolean.FALSE :
 768           (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 769     }
 770     return sharingEnabled.booleanValue();
 771   }
 772 
 773   public boolean isCompressedOopsEnabled() {
 774     if (compressedOopsEnabled == null) {
 775         Flag flag = getCommandLineFlag("UseCompressedOops");
 776         compressedOopsEnabled = (flag == null) ? Boolean.FALSE:
 777              (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 778     }
 779     return compressedOopsEnabled.booleanValue();
 780   }
 781 
 782   public int getObjectAlignmentInBytes() {
 783     if (objectAlignmentInBytes == 0) {
 784         Flag flag = getCommandLineFlag("ObjectAlignmentInBytes");
 785         objectAlignmentInBytes = (flag == null) ? 8 : (int)flag.getIntx();
 786     }
 787     return objectAlignmentInBytes;
 788   }
 789 
 790   // returns null, if not available.
 791   public Flag[] getCommandLineFlags() {
 792     if (commandLineFlags == null) {
 793        readCommandLineFlags();
 794     }
 795 
 796     return commandLineFlags;
 797   }
 798 
 799   public Flag getCommandLineFlag(String name) {
 800     if (flagsMap == null) {
 801       flagsMap = new HashMap();
 802       Flag[] flags = getCommandLineFlags();
 803       for (int i = 0; i < flags.length; i++) {
 804         flagsMap.put(flags[i].getName(), flags[i]);
 805       }
 806     }
 807     return (Flag) flagsMap.get(name);
 808   }
 809 
 810   private void readCommandLineFlags() {
 811     // get command line flags
 812     TypeDataBase db = getTypeDataBase();
 813     Type flagType = db.lookupType("Flag");
 814     int numFlags = (int) flagType.getCIntegerField("numFlags").getValue();
 815     // NOTE: last flag contains null values.
 816     commandLineFlags = new Flag[numFlags - 1];
 817 
 818     Address flagAddr = flagType.getAddressField("flags").getValue();
 819 
 820     AddressField typeFld = flagType.getAddressField("type");
 821     AddressField nameFld = flagType.getAddressField("name");
 822     AddressField addrFld = flagType.getAddressField("addr");
 823     AddressField kindFld = flagType.getAddressField("kind");
 824     CIntField originFld = new CIntField(flagType.getCIntegerField("origin"), 0);
 825 
 826     long flagSize = flagType.getSize(); // sizeof(Flag)
 827 
 828     // NOTE: last flag contains null values.
 829     for (int f = 0; f < numFlags - 1; f++) {
 830       String type = CStringUtilities.getString(typeFld.getValue(flagAddr));
 831       String name = CStringUtilities.getString(nameFld.getValue(flagAddr));
 832       Address addr = addrFld.getValue(flagAddr);
 833       String kind = CStringUtilities.getString(kindFld.getValue(flagAddr));
 834       int origin = (int)originFld.getValue(flagAddr);
 835       commandLineFlags[f] = new Flag(type, name, addr, kind, origin);
 836       flagAddr = flagAddr.addOffsetTo(flagSize);
 837     }
 838 
 839     // sort flags by name
 840     Arrays.sort(commandLineFlags, new Comparator() {
 841         public int compare(Object o1, Object o2) {
 842           Flag f1 = (Flag) o1;
 843           Flag f2 = (Flag) o2;
 844           return f1.getName().compareTo(f2.getName());
 845         }
 846       });
 847   }
 848 
 849   public String getSystemProperty(String key) {
 850     Properties props = getSystemProperties();
 851     return (props != null)? props.getProperty(key) : null;
 852   }
 853 
 854   public Properties getSystemProperties() {
 855     if (sysProps == null) {
 856        readSystemProperties();
 857     }
 858     return sysProps;
 859   }
 860 
 861   private void readSystemProperties() {
 862     final InstanceKlass systemKls = getSystemDictionary().getSystemKlass();
 863     systemKls.iterateStaticFields(new DefaultOopVisitor() {
 864         ObjectReader objReader = new ObjectReader();
 865         public void doOop(sun.jvm.hotspot.oops.OopField field, boolean isVMField) {
 866           if (field.getID().getName().equals("props")) {
 867             try {
 868               sysProps = (Properties) objReader.readObject(field.getValue(getObj()));
 869             } catch (Exception e) {
 870               e.printStackTrace();
 871             }
 872           }
 873         }
 874       });
 875   }
 876 }