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