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