1 /*
   2  * Copyright (c) 2000, 2023, 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 import sun.jvm.hotspot.utilities.Observable;
  43 import sun.jvm.hotspot.utilities.Observer;
  44 
  45 /** <P> This class encapsulates the global state of the VM; the
  46     universe, object heap, interpreter, etc. It is a Singleton and
  47     must be initialized with a call to initialize() before calling
  48     getVM(). </P>
  49 
  50     <P> Many auxiliary classes (i.e., most of the VMObjects) keep
  51     needed field offsets in the form of static Field objects. In a
  52     debugging system, the VM might be shutdown and re-initialized (on
  53     a differently-configured build, i.e., 32- vs. 64-bit), and all old
  54     cached state (including fields and field offsets) must be
  55     flushed. </P>
  56 
  57     <P> An Observer pattern is used to implement the initialization of
  58     such classes. Each such class, in its static initializer,
  59     registers an Observer with the VM class via
  60     VM.registerVMInitializedObserver(). This Observer is guaranteed to
  61     be notified whenever the VM is initialized (or re-initialized). To
  62     implement the first-time initialization, the observer is also
  63     notified when it registers itself with the VM. (For bootstrapping
  64     reasons, this implies that the constructor of VM can not
  65     instantiate any such objects, since VM.soleInstance will not have
  66     been set yet. This is a bootstrapping issue which may have to be
  67     revisited later.) </P>
  68 */
  69 
  70 public class VM {
  71   private static VM    soleInstance;
  72   private static List<Observer> vmInitializedObservers = new ArrayList<>();
  73   private List<Observer> vmResumedObservers   = new ArrayList<>();
  74   private List<Observer> vmSuspendedObservers = new ArrayList<>();
  75   private TypeDataBase db;
  76   private boolean      isBigEndian;
  77   /** This is only present if in a debugging system */
  78   private JVMDebugger  debugger;
  79   private long         logAddressSize;
  80   private Universe     universe;
  81   private ObjectHeap   heap;
  82   private SystemDictionary dict;
  83   private ClassLoaderDataGraph cldGraph;
  84   private Threads      threads;
  85   private ObjectSynchronizer synchronizer;
  86   private JNIHandles   handles;
  87   private Interpreter  interpreter;
  88   private StubRoutines stubRoutines;
  89   private FileMapInfo  fileMapInfo;
  90   private Bytes        bytes;
  91 
  92   /** Flag indicating if JVMTI support is included in the build */
  93   private boolean      isJvmtiSupported;
  94   /** Flags indicating whether we are attached to a core, C1, or C2 build */
  95   private boolean      usingClientCompiler;
  96   private boolean      usingServerCompiler;
  97   /** alignment constants */
  98   private boolean      isLP64;
  99   private int          bytesPerLong;
 100   private int          bytesPerWord;
 101   private int          logBytesPerWord;
 102   private int          objectAlignmentInBytes;
 103   private int          minObjAlignmentInBytes;
 104   private int          logMinObjAlignmentInBytes;
 105   private int          heapWordSize;
 106   private int          heapOopSize;
 107   private int          klassPtrSize;
 108   private int          oopSize;
 109   /** -XX flags (value origin) */
 110   public static int    Flags_DEFAULT;
 111   public static int    Flags_COMMAND_LINE;
 112   public static int    Flags_ENVIRON_VAR;
 113   public static int    Flags_CONFIG_FILE;
 114   public static int    Flags_MANAGEMENT;
 115   public static int    Flags_ERGONOMIC;
 116   public static int    Flags_ATTACH_ON_DEMAND;
 117   public static int    Flags_INTERNAL;
 118   public static int    Flags_JIMAGE_RESOURCE;
 119   private static int   Flags_VALUE_ORIGIN_MASK;
 120   private static int   Flags_WAS_SET_ON_COMMAND_LINE;
 121   /** This is only present in a non-core build */
 122   private CodeCache    codeCache;
 123   /** This is only present in a C1 build */
 124   private Runtime1     runtime1;
 125   /** These constants come from globalDefinitions.hpp */
 126   private int          invocationEntryBCI;
 127   private ReversePtrs  revPtrs;
 128   private VMRegImpl    vmregImpl;
 129   private int          reserveForAllocationPrefetch;
 130 
 131   // System.getProperties from debuggee VM
 132   private Properties   sysProps;
 133 
 134   // VM version strings come from Abstract_VM_Version class
 135   private String       vmRelease;
 136   private String       vmInternalInfo;
 137 
 138   private Flag[] commandLineFlags;
 139   private Map<String, Flag> flagsMap;
 140 
 141   private static Type intType;
 142   private static Type uintType;
 143   private static Type intxType;
 144   private static Type uintxType;
 145   private static Type sizetType;
 146   private static Type uint64tType;
 147   private static CIntegerType boolType;
 148   private Boolean sharingEnabled;
 149   private Boolean compressedOopsEnabled;
 150   private Boolean compressedKlassPointersEnabled;
 151 
 152   // command line flags supplied to VM - see struct JVMFlag in jvmFlag.hpp
 153   public static final class Flag {
 154      private String type;
 155      private String name;
 156      private Address addr;
 157      private int flags;
 158 
 159      private Flag(String type, String name, Address addr, int flags) {
 160         this.type = type;
 161         this.name = name;
 162         this.addr = addr;
 163         this.flags = flags;
 164      }
 165 
 166      public String getType() {
 167         return type;
 168      }
 169 
 170      public String getName() {
 171         return name;
 172      }
 173 
 174      public Address getAddress() {
 175         return addr;
 176      }
 177 
 178      public int getOrigin() {
 179         return flags & Flags_VALUE_ORIGIN_MASK;
 180      }
 181 
 182      // See JVMFlag::print_origin() in HotSpot
 183      public String getOriginString() {
 184         var origin = flags & Flags_VALUE_ORIGIN_MASK;
 185         if (origin == Flags_DEFAULT) {
 186             return "default";
 187         } else if (origin == Flags_COMMAND_LINE) {
 188             return "command line";
 189         } else if (origin == Flags_ENVIRON_VAR) {
 190             return "environment";
 191         } else if (origin == Flags_CONFIG_FILE) {
 192             return "config file";
 193         } else if (origin == Flags_MANAGEMENT) {
 194             return "management";
 195         } else if (origin == Flags_ERGONOMIC) {
 196             String result = "";
 197             if ((flags & Flags_WAS_SET_ON_COMMAND_LINE) == Flags_WAS_SET_ON_COMMAND_LINE) {
 198                 result = "command line, ";
 199             }
 200             return result + "ergonomic";
 201         } else if (origin == Flags_ATTACH_ON_DEMAND) {
 202             return "attach";
 203         } else if (origin == Flags_INTERNAL) {
 204             return "internal";
 205         } else if (origin == Flags_JIMAGE_RESOURCE) {
 206             return "jimage";
 207         } else {
 208             throw new IllegalStateException(
 209                 "Unknown flag origin " + origin + " is detected in " + name);
 210         }
 211      }
 212 
 213      public boolean isBool() {
 214         return type.equals("bool");
 215      }
 216 
 217      public boolean getBool() {
 218         if (Assert.ASSERTS_ENABLED) {
 219            Assert.that(isBool(), "not a bool flag!");
 220         }
 221         return addr.getCIntegerAt(0, boolType.getSize(), boolType.isUnsigned()) != 0;
 222      }
 223 
 224      public boolean isInt() {
 225         return type.equals("int");
 226      }
 227 
 228      public long getInt() {
 229         if (Assert.ASSERTS_ENABLED) {
 230            Assert.that(isInt(), "not an int flag!");
 231         }
 232         return addr.getCIntegerAt(0, intType.getSize(), false);
 233      }
 234 
 235      public boolean isUInt() {
 236         return type.equals("uint");
 237      }
 238 
 239      public long getUInt() {
 240         if (Assert.ASSERTS_ENABLED) {
 241            Assert.that(isUInt(), "not a uint flag!");
 242         }
 243         return addr.getCIntegerAt(0, uintType.getSize(), false);
 244      }
 245 
 246      public boolean isIntx() {
 247         return type.equals("intx");
 248      }
 249 
 250      public long getIntx() {
 251         if (Assert.ASSERTS_ENABLED) {
 252            Assert.that(isIntx(), "not an intx flag!");
 253         }
 254         return addr.getCIntegerAt(0, intxType.getSize(), false);
 255      }
 256 
 257      public boolean isUIntx() {
 258         return type.equals("uintx");
 259      }
 260 
 261      public long getUIntx() {
 262         if (Assert.ASSERTS_ENABLED) {
 263            Assert.that(isUIntx(), "not a uintx flag!");
 264         }
 265         return addr.getCIntegerAt(0, uintxType.getSize(), true);
 266      }
 267 
 268      public boolean isSizet() {
 269         return type.equals("size_t");
 270      }
 271 
 272      public long getSizet() {
 273         if (Assert.ASSERTS_ENABLED) {
 274            Assert.that(isSizet(), "not a size_t flag!");
 275         }
 276         return addr.getCIntegerAt(0, sizetType.getSize(), true);
 277      }
 278 
 279      public boolean isCcstr() {
 280         return type.equals("ccstr");
 281      }
 282 
 283      public String getCcstr() {
 284         if (Assert.ASSERTS_ENABLED) {
 285            Assert.that(isCcstr(), "not a ccstr flag!");
 286         }
 287         return CStringUtilities.getString(addr.getAddressAt(0));
 288      }
 289 
 290      public boolean isCcstrlist() {
 291         return type.equals("ccstrlist");
 292      }
 293 
 294      public String getCcstrlist() {
 295         if (Assert.ASSERTS_ENABLED) {
 296            Assert.that(isCcstrlist(), "not a ccstrlist flag!");
 297         }
 298         return CStringUtilities.getString(addr.getAddressAt(0));
 299      }
 300 
 301      public boolean isDouble() {
 302         return type.equals("double");
 303      }
 304 
 305      public double getDouble() {
 306         if (Assert.ASSERTS_ENABLED) {
 307            Assert.that(isDouble(), "not a double flag!");
 308         }
 309         return addr.getJDoubleAt(0);
 310      }
 311 
 312      public boolean isUint64t() {
 313         return type.equals("uint64_t");
 314      }
 315 
 316      public long getUint64t() {
 317         if (Assert.ASSERTS_ENABLED) {
 318            Assert.that(isUint64t(), "not an uint64_t flag!");
 319         }
 320         return addr.getCIntegerAt(0, uint64tType.getSize(), true);
 321      }
 322 
 323      public String getValue() {
 324         if (isBool()) {
 325            return Boolean.toString(getBool());
 326         } else if (isInt()) {
 327            return Long.toString(getInt());
 328         } else if (isUInt()) {
 329            return Long.toString(getUInt());
 330         } else if (isIntx()) {
 331            return Long.toString(getIntx());
 332         } else if (isUIntx()) {
 333            return Long.toUnsignedString(getUIntx());
 334         } else if (isSizet()) {
 335            return Long.toUnsignedString(getSizet());
 336         } else if (isCcstr()) {
 337            var str = getCcstr();
 338            if (str != null) {
 339                str = "\"" + str + "\"";
 340            }
 341            return str;
 342         } else if (isCcstrlist()) {
 343            var str = getCcstrlist();
 344            if (str != null) {
 345                str = "\"" + str + "\"";
 346            }
 347            return str;
 348         } else if (isDouble()) {
 349            return Double.toString(getDouble());
 350         } else if (isUint64t()) {
 351            return Long.toUnsignedString(getUint64t());
 352         } else {
 353            throw new WrongTypeException("Unknown type: " + type + " (" + name + ")");
 354         }
 355      }
 356   };
 357 
 358   private static void checkVMVersion(String vmRelease) {
 359      if (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null) {
 360         // read sa build version.
 361         String versionProp = "sun.jvm.hotspot.runtime.VM.saBuildVersion";
 362         String versionPropVal = saProps.getProperty(versionProp);
 363         if (versionPropVal == null) {
 364            throw new RuntimeException("Missing property " + versionProp);
 365         }
 366 
 367         var saVersion = Runtime.Version.parse(versionPropVal);
 368         var vmVersion = Runtime.Version.parse(vmRelease);
 369 
 370         if (saVersion.equals(vmVersion)) {
 371            // Exact match
 372            return;
 373         }
 374         if (!saVersion.equalsIgnoreOptional(vmVersion)) {
 375            // Throw exception if different release versions:
 376            // <version>+<build>
 377            throw new VMVersionMismatchException(saVersion, vmVersion);
 378         } else {
 379            // Otherwise print warning to allow mismatch not release versions
 380            // during development.
 381            System.err.println("WARNING: Hotspot VM version " + vmVersion +
 382                               " does not match with SA version " + saVersion +
 383                               "." + " You may see unexpected results. ");
 384         }
 385      } else {
 386         System.err.println("WARNING: You have disabled SA and VM version check. You may be "  +
 387                            "using incompatible version of SA and you may see unexpected " +
 388                            "results.");
 389      }
 390   }
 391 
 392   private static final boolean disableDerivedPointerTableCheck;
 393   private static final Properties saProps;
 394 
 395   static {
 396      saProps = new Properties();
 397      URL url = null;
 398      try {
 399        saProps.load(VM.class.getResourceAsStream("/sa.properties"));
 400      } catch (Exception e) {
 401        System.err.println("Unable to load properties  " +
 402                                   (url == null ? "null" : url.toString()) +
 403                                   ": " + e.getMessage());
 404      }
 405 
 406      disableDerivedPointerTableCheck = System.getProperty("sun.jvm.hotspot.runtime.VM.disableDerivedPointerTableCheck") != null;
 407   }
 408 
 409   private VM(TypeDataBase db, JVMDebugger debugger, boolean isBigEndian) {
 410     this.db          = db;
 411     this.debugger    = debugger;
 412     this.isBigEndian = isBigEndian;
 413 
 414     // Note that we don't construct universe, heap, threads,
 415     // interpreter, or stubRoutines here (any more).  The current
 416     // initialization mechanisms require that the VM be completely set
 417     // up (i.e., out of its constructor, with soleInstance assigned)
 418     // before their static initializers are run.
 419 
 420     if (db.getAddressSize() == 4) {
 421       logAddressSize = 2;
 422     } else if (db.getAddressSize() == 8) {
 423       logAddressSize = 3;
 424     } else {
 425       throw new RuntimeException("Address size " + db.getAddressSize() + " not yet supported");
 426     }
 427 
 428     // read VM version info
 429     try {
 430        Type vmVersion = db.lookupType("Abstract_VM_Version");
 431        Address releaseAddr = vmVersion.getAddressField("_s_vm_release").getValue();
 432        vmRelease = CStringUtilities.getString(releaseAddr);
 433        Address vmInternalInfoAddr = vmVersion.getAddressField("_s_internal_vm_info_string").getValue();
 434        vmInternalInfo = CStringUtilities.getString(vmInternalInfoAddr);
 435 
 436        Type threadLocalAllocBuffer = db.lookupType("ThreadLocalAllocBuffer");
 437        CIntegerType intType = (CIntegerType) db.lookupType("int");
 438        CIntegerField reserveForAllocationPrefetchField = threadLocalAllocBuffer.getCIntegerField("_reserve_for_allocation_prefetch");
 439        reserveForAllocationPrefetch = (int)reserveForAllocationPrefetchField.getCInteger(intType);
 440     } catch (Exception exp) {
 441        throw new RuntimeException("can't determine target's VM version : " + exp.getMessage());
 442     }
 443 
 444     checkVMVersion(vmRelease);
 445 
 446     invocationEntryBCI = db.lookupIntConstant("InvocationEntryBci").intValue();
 447 
 448     // We infer the presence of JVMTI from the presence of the InstanceKlass::_breakpoints field.
 449     {
 450       Type type = db.lookupType("InstanceKlass");
 451       if (type.getField("_breakpoints", false, false) == null) {
 452         isJvmtiSupported = false;
 453       } else {
 454         isJvmtiSupported = true;
 455       }
 456     }
 457 
 458     // We infer the presence of C1 or C2 from a couple of fields we
 459     // already have present in the type database
 460     {
 461       Type type = db.lookupType("Method");
 462       if (type.getField("_from_compiled_entry", false, false) == null) {
 463         // Neither C1 nor C2 is present
 464         usingClientCompiler = false;
 465         usingServerCompiler = false;
 466       } else {
 467         // Determine whether C2 is present
 468         if (db.lookupType("Matcher", false) != null) {
 469           usingServerCompiler = true;
 470         } else {
 471           usingClientCompiler = true;
 472         }
 473       }
 474     }
 475 
 476     if (debugger != null) {
 477       isLP64 = debugger.getMachineDescription().isLP64();
 478     }
 479     bytesPerLong = db.lookupIntConstant("BytesPerLong").intValue();
 480     bytesPerWord = db.lookupIntConstant("BytesPerWord").intValue();
 481     logBytesPerWord = db.lookupIntConstant("LogBytesPerWord").intValue();
 482     heapWordSize = db.lookupIntConstant("HeapWordSize").intValue();
 483     Flags_DEFAULT = db.lookupIntConstant("JVMFlagOrigin::DEFAULT").intValue();
 484     Flags_COMMAND_LINE = db.lookupIntConstant("JVMFlagOrigin::COMMAND_LINE").intValue();
 485     Flags_ENVIRON_VAR = db.lookupIntConstant("JVMFlagOrigin::ENVIRON_VAR").intValue();
 486     Flags_CONFIG_FILE = db.lookupIntConstant("JVMFlagOrigin::CONFIG_FILE").intValue();
 487     Flags_MANAGEMENT = db.lookupIntConstant("JVMFlagOrigin::MANAGEMENT").intValue();
 488     Flags_ERGONOMIC = db.lookupIntConstant("JVMFlagOrigin::ERGONOMIC").intValue();
 489     Flags_ATTACH_ON_DEMAND = db.lookupIntConstant("JVMFlagOrigin::ATTACH_ON_DEMAND").intValue();
 490     Flags_INTERNAL = db.lookupIntConstant("JVMFlagOrigin::INTERNAL").intValue();
 491     Flags_JIMAGE_RESOURCE = db.lookupIntConstant("JVMFlagOrigin::JIMAGE_RESOURCE").intValue();
 492     Flags_VALUE_ORIGIN_MASK = db.lookupIntConstant("JVMFlag::VALUE_ORIGIN_MASK").intValue();
 493     Flags_WAS_SET_ON_COMMAND_LINE = db.lookupIntConstant("JVMFlag::WAS_SET_ON_COMMAND_LINE").intValue();
 494     oopSize  = db.lookupIntConstant("oopSize").intValue();
 495 
 496     intType = db.lookupType("int");
 497     uintType = db.lookupType("uint");
 498     intxType = db.lookupType("intx");
 499     uintxType = db.lookupType("uintx");
 500     sizetType = db.lookupType("size_t");
 501     uint64tType = db.lookupType("uint64_t");
 502     boolType = (CIntegerType) db.lookupType("bool");
 503 
 504     minObjAlignmentInBytes = getObjectAlignmentInBytes();
 505     if ((minObjAlignmentInBytes & (minObjAlignmentInBytes - 1)) != 0) {
 506       throw new RuntimeException("Object alignment " + minObjAlignmentInBytes + " is not power of two");
 507     }
 508 
 509     logMinObjAlignmentInBytes = Integer.numberOfTrailingZeros(minObjAlignmentInBytes);
 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   public static 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   /** Indicates whether the underlying machine supports the LP64 data
 674       model. This is needed for conditionalizing code in a few places */
 675   public boolean isLP64() {
 676     if (Assert.ASSERTS_ENABLED) {
 677       Assert.that(isDebugging(), "Debugging system only for now");
 678     }
 679     return isLP64;
 680   }
 681 
 682   /** Get bytes-per-long == long/double natural alignment. */
 683   public int getBytesPerLong() {
 684     return bytesPerLong;
 685   }
 686 
 687   public int getBytesPerWord() {
 688     return bytesPerWord;
 689   }
 690 
 691   public int getLogBytesPerWord() {
 692     return logBytesPerWord;
 693   }
 694 
 695   /** Get minimum object alignment in bytes. */
 696   public int getMinObjAlignmentInBytes() {
 697     return minObjAlignmentInBytes;
 698   }
 699   public int getLogMinObjAlignmentInBytes() {
 700     return logMinObjAlignmentInBytes;
 701   }
 702 
 703   public int getHeapWordSize() {
 704     return heapWordSize;
 705   }
 706 
 707   public int getHeapOopSize() {
 708     return heapOopSize;
 709   }
 710 
 711   public int getKlassPtrSize() {
 712     return klassPtrSize;
 713   }
 714   /** Utility routine for getting data structure alignment correct */
 715   public long alignUp(long size, long alignment) {
 716     return (size + alignment - 1) & ~(alignment - 1);
 717   }
 718 
 719   /** Utility routine for getting data structure alignment correct */
 720   public long alignDown(long size, long alignment) {
 721     return size & ~(alignment - 1);
 722   }
 723 
 724   /** Utility routine for building an int from two "unsigned" 16-bit
 725       shorts */
 726   public int buildIntFromShorts(short low, short high) {
 727     return (((int) high) << 16) | (((int) low) & 0xFFFF);
 728   }
 729 
 730   public TypeDataBase getTypeDataBase() {
 731     return db;
 732   }
 733 
 734   public Universe    getUniverse() {
 735     if (universe == null) {
 736       universe = new Universe();
 737     }
 738     return universe;
 739   }
 740 
 741   public ObjectHeap  getObjectHeap() {
 742     if (heap == null) {
 743       heap = new ObjectHeap(db);
 744     }
 745     return heap;
 746   }
 747 
 748   public SystemDictionary getSystemDictionary() {
 749     if (dict == null) {
 750       dict = new SystemDictionary();
 751     }
 752     return dict;
 753   }
 754 
 755   public ClassLoaderDataGraph getClassLoaderDataGraph() {
 756     if (cldGraph == null) {
 757       cldGraph = new ClassLoaderDataGraph();
 758     }
 759     return cldGraph;
 760   }
 761 
 762   public Threads     getThreads() {
 763     if (threads == null) {
 764       threads = new Threads();
 765     }
 766     return threads;
 767   }
 768 
 769   public ObjectSynchronizer getObjectSynchronizer() {
 770     if (synchronizer == null) {
 771       synchronizer = new ObjectSynchronizer();
 772     }
 773     return synchronizer;
 774   }
 775 
 776   public JNIHandles getJNIHandles() {
 777     if (handles == null) {
 778       handles = new JNIHandles();
 779     }
 780     return handles;
 781   }
 782 
 783   public Interpreter getInterpreter() {
 784     if (interpreter == null) {
 785       interpreter = new Interpreter();
 786     }
 787     return interpreter;
 788   }
 789 
 790   public StubRoutines getStubRoutines() {
 791     if (stubRoutines == null) {
 792       stubRoutines = new StubRoutines();
 793     }
 794     return stubRoutines;
 795   }
 796 
 797   public VMRegImpl getVMRegImplInfo() {
 798     if (vmregImpl == null) {
 799       vmregImpl = new VMRegImpl();
 800     }
 801     return vmregImpl;
 802   }
 803 
 804   public FileMapInfo getFileMapInfo() {
 805     if (!isSharingEnabled()) {
 806       return null;
 807     }
 808     if (fileMapInfo == null) {
 809       fileMapInfo = new FileMapInfo();
 810     }
 811     return fileMapInfo;
 812   }
 813 
 814   public Bytes getBytes() {
 815     if (bytes == null) {
 816       bytes = new Bytes(debugger.getMachineDescription());
 817     }
 818     return bytes;
 819   }
 820 
 821   /** Returns true if this is a isBigEndian, false otherwise */
 822   public boolean isBigEndian() {
 823     return isBigEndian;
 824   }
 825 
 826   /** Returns true if JVMTI is supported, false otherwise */
 827   public boolean isJvmtiSupported() {
 828     return isJvmtiSupported;
 829   }
 830 
 831   /** Returns true if this is a "core" build, false if either C1 or C2
 832       is present */
 833   public boolean isCore() {
 834     return (!(usingClientCompiler || usingServerCompiler));
 835   }
 836 
 837   /** Returns true if this is a C1 build, false otherwise */
 838   public boolean isClientCompiler() {
 839     return usingClientCompiler;
 840   }
 841 
 842   /** Returns true if this is a C2 build, false otherwise */
 843   public boolean isServerCompiler() {
 844     return usingServerCompiler;
 845   }
 846 
 847   /** Returns true if C2 derived pointer table should be used, false otherwise */
 848   public boolean useDerivedPointerTable() {
 849     return !disableDerivedPointerTableCheck;
 850   }
 851 
 852   /** Returns the code cache; should not be used if is core build */
 853   public CodeCache getCodeCache() {
 854     if (Assert.ASSERTS_ENABLED) {
 855       Assert.that(!isCore(), "noncore builds only");
 856     }
 857     if (codeCache == null) {
 858       codeCache = new CodeCache();
 859     }
 860     return codeCache;
 861   }
 862 
 863   /** Should only be called for C1 builds */
 864   public Runtime1 getRuntime1() {
 865     if (Assert.ASSERTS_ENABLED) {
 866       Assert.that(isClientCompiler(), "C1 builds only");
 867     }
 868     if (runtime1 == null) {
 869       runtime1 = new Runtime1();
 870     }
 871     return runtime1;
 872   }
 873 
 874   /** Test to see whether we're in debugging mode (NOTE: this really
 875       should not be tested by this code; currently only used in
 876       StackFrameStream) */
 877   public boolean isDebugging() {
 878     return (debugger != null);
 879   }
 880 
 881   /** This is only used by the debugging (i.e., non-runtime) system */
 882   public JVMDebugger getDebugger() {
 883     if (debugger == null) {
 884       throw new RuntimeException("Attempt to use debugger in runtime system");
 885     }
 886     return debugger;
 887   }
 888 
 889   /** Indicates whether a given program counter is in Java code. This
 890       includes but is not spanned by the interpreter and code cache.
 891       Only used in the debugging system, for implementing
 892       JavaThread.currentFrameGuess() on x86. */
 893   public boolean isJavaPCDbg(Address addr) {
 894     // FIXME: this is not a complete enough set: must include areas
 895     // like vtable stubs
 896     return (getInterpreter().contains(addr) ||
 897             getCodeCache().contains(addr));
 898   }
 899 
 900   /** FIXME: figure out where to stick this */
 901   public int getInvocationEntryBCI() {
 902     return invocationEntryBCI;
 903   }
 904 
 905   // FIXME: figure out where to stick this
 906   public boolean wizardMode() {
 907     return true;
 908   }
 909 
 910   public ReversePtrs getRevPtrs() {
 911     return revPtrs;
 912   }
 913 
 914   public void setRevPtrs(ReversePtrs rp) {
 915     revPtrs = rp;
 916   }
 917 
 918   // returns null, if not available.
 919   public String getVMRelease() {
 920     return vmRelease;
 921   }
 922 
 923   // returns null, if not available.
 924   public String getVMInternalInfo() {
 925     return vmInternalInfo;
 926   }
 927 
 928   public int getReserveForAllocationPrefetch() {
 929     return reserveForAllocationPrefetch;
 930   }
 931 
 932   public boolean isSharingEnabled() {
 933     if (sharingEnabled == null) {
 934         Address address = VM.getVM().getDebugger().lookup(null, "UseSharedSpaces");
 935         if (address == null && getOS().equals("win32")) {
 936             // On Win32 symbols are prefixed with the dll name. So look for
 937             // UseSharedSpaces as a symbol in jvm.dll.
 938             address = VM.getVM().getDebugger().lookup(null, "jvm!UseSharedSpaces");
 939         }
 940         sharingEnabled = address.getJBooleanAt(0);
 941     }
 942     return sharingEnabled.booleanValue();
 943   }
 944 
 945   public boolean isCompressedOopsEnabled() {
 946     if (compressedOopsEnabled == null) {
 947         Flag flag = getCommandLineFlag("UseCompressedOops");
 948         compressedOopsEnabled = (flag == null) ? Boolean.FALSE:
 949              (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 950     }
 951     return compressedOopsEnabled.booleanValue();
 952   }
 953 
 954   public boolean isCompressedKlassPointersEnabled() {
 955     if (compressedKlassPointersEnabled == null) {
 956         Flag flag = getCommandLineFlag("UseCompressedClassPointers");
 957         compressedKlassPointersEnabled = (flag == null) ? Boolean.FALSE:
 958              (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 959     }
 960     return compressedKlassPointersEnabled.booleanValue();
 961   }
 962 
 963   public int getObjectAlignmentInBytes() {
 964     if (objectAlignmentInBytes == 0) {
 965         Flag flag = getCommandLineFlag("ObjectAlignmentInBytes");
 966         objectAlignmentInBytes = (flag == null) ? 8 : (int)flag.getInt();
 967     }
 968     return objectAlignmentInBytes;
 969   }
 970 
 971   /** Indicates whether Thread-Local Allocation Buffers are used */
 972   public boolean getUseTLAB() {
 973       Flag flag = getCommandLineFlag("UseTLAB");
 974       return (flag == null) ? false: flag.getBool();
 975   }
 976 
 977   public boolean getCommandLineBooleanFlag(String name) {
 978     Flag flag = getCommandLineFlag(name);
 979     return (flag == null) ? Boolean.FALSE:
 980       (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 981   }
 982 
 983   // returns null, if not available.
 984   public Flag[] getCommandLineFlags() {
 985     if (commandLineFlags == null) {
 986        readCommandLineFlags();
 987     }
 988 
 989     return commandLineFlags;
 990   }
 991 
 992   public Flag getCommandLineFlag(String name) {
 993     if (flagsMap == null) {
 994       flagsMap = new HashMap<>();
 995       Flag[] flags = getCommandLineFlags();
 996       for (int i = 0; i < flags.length; i++) {
 997         flagsMap.put(flags[i].getName(), flags[i]);
 998       }
 999     }
1000     return flagsMap.get(name);
1001   }
1002 
1003   private static final String cmdFlagTypes[] = {
1004     "bool",
1005     "int",
1006     "uint",
1007     "intx",
1008     "uintx",
1009     "uint64_t",
1010     "size_t",
1011     "double",
1012     "ccstr",
1013     "ccstrlist"
1014   };
1015 
1016   private String getFlagTypeAsString(int typeIndex) {
1017     if (0 <= typeIndex && typeIndex < cmdFlagTypes.length) {
1018       return cmdFlagTypes[typeIndex];
1019     } else {
1020       return "unknown";
1021     }
1022   }
1023 
1024   private void readCommandLineFlags() {
1025     // get command line flags
1026     TypeDataBase db = getTypeDataBase();
1027     Type flagType = db.lookupType("JVMFlag");
1028     int numFlags = (int) flagType.getCIntegerField("numFlags").getValue();
1029     // NOTE: last flag contains null values.
1030     commandLineFlags = new Flag[numFlags - 1];
1031 
1032     Address flagAddr = flagType.getAddressField("flags").getValue();
1033     CIntField typeFld = new CIntField(flagType.getCIntegerField("_type"), 0);
1034     AddressField nameFld = flagType.getAddressField("_name");
1035     AddressField addrFld = flagType.getAddressField("_addr");
1036     CIntField flagsFld = new CIntField(flagType.getCIntegerField("_flags"), 0);
1037 
1038     long flagSize = flagType.getSize(); // sizeof(Flag)
1039 
1040     // NOTE: last flag contains null values.
1041     for (int f = 0; f < numFlags - 1; f++) {
1042       int typeIndex = (int)typeFld.getValue(flagAddr);
1043       String type = getFlagTypeAsString(typeIndex);
1044       String name = CStringUtilities.getString(nameFld.getValue(flagAddr));
1045       Address addr = addrFld.getValue(flagAddr);
1046       int flags = (int)flagsFld.getValue(flagAddr);
1047       commandLineFlags[f] = new Flag(type, name, addr, flags);
1048       flagAddr = flagAddr.addOffsetTo(flagSize);
1049     }
1050 
1051     // sort flags by name
1052     Arrays.sort(commandLineFlags, new Comparator<>() {
1053         public int compare(Flag f1, Flag f2) {
1054           return f1.getName().compareTo(f2.getName());
1055         }
1056       });
1057   }
1058 
1059   public String getSystemProperty(String key) {
1060     Properties props = getSystemProperties();
1061     return (props != null)? props.getProperty(key) : null;
1062   }
1063 
1064   public Properties getSystemProperties() {
1065     if (sysProps == null) {
1066        readSystemProperties();
1067     }
1068     return sysProps;
1069   }
1070 
1071   private void readSystemProperties() {
1072     final InstanceKlass systemKls = getSystemDictionary().getSystemKlass();
1073     systemKls.iterateStaticFields(new DefaultOopVisitor() {
1074         ObjectReader objReader = new ObjectReader();
1075         public void doOop(sun.jvm.hotspot.oops.OopField field, boolean isVMField) {
1076           if (field.getID().getName().equals("props")) {
1077             try {
1078               sysProps = (Properties) objReader.readObject(field.getValue(getObj()));
1079             } catch (Exception e) {
1080               e.printStackTrace();
1081             }
1082           }
1083         }
1084       });
1085   }
1086 }