1 /*
   2  * Copyright (c) 2000, 2022, 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   /** Utility routine for building a long from two "unsigned" 32-bit
 731       ints in <b>platform-dependent</b> order */
 732   public long buildLongFromIntsPD(int oneHalf, int otherHalf) {
 733     if (isBigEndian) {
 734       return (((long) otherHalf) << 32) | (((long) oneHalf) & 0x00000000FFFFFFFFL);
 735     } else{
 736       return (((long) oneHalf) << 32) | (((long) otherHalf) & 0x00000000FFFFFFFFL);
 737     }
 738   }
 739 
 740   public TypeDataBase getTypeDataBase() {
 741     return db;
 742   }
 743 
 744   public Universe    getUniverse() {
 745     if (universe == null) {
 746       universe = new Universe();
 747     }
 748     return universe;
 749   }
 750 
 751   public ObjectHeap  getObjectHeap() {
 752     if (heap == null) {
 753       heap = new ObjectHeap(db);
 754     }
 755     return heap;
 756   }
 757 
 758   public SystemDictionary getSystemDictionary() {
 759     if (dict == null) {
 760       dict = new SystemDictionary();
 761     }
 762     return dict;
 763   }
 764 
 765   public ClassLoaderDataGraph getClassLoaderDataGraph() {
 766     if (cldGraph == null) {
 767       cldGraph = new ClassLoaderDataGraph();
 768     }
 769     return cldGraph;
 770   }
 771 
 772   public Threads     getThreads() {
 773     if (threads == null) {
 774       threads = new Threads();
 775     }
 776     return threads;
 777   }
 778 
 779   public ObjectSynchronizer getObjectSynchronizer() {
 780     if (synchronizer == null) {
 781       synchronizer = new ObjectSynchronizer();
 782     }
 783     return synchronizer;
 784   }
 785 
 786   public JNIHandles getJNIHandles() {
 787     if (handles == null) {
 788       handles = new JNIHandles();
 789     }
 790     return handles;
 791   }
 792 
 793   public Interpreter getInterpreter() {
 794     if (interpreter == null) {
 795       interpreter = new Interpreter();
 796     }
 797     return interpreter;
 798   }
 799 
 800   public StubRoutines getStubRoutines() {
 801     if (stubRoutines == null) {
 802       stubRoutines = new StubRoutines();
 803     }
 804     return stubRoutines;
 805   }
 806 
 807   public VMRegImpl getVMRegImplInfo() {
 808     if (vmregImpl == null) {
 809       vmregImpl = new VMRegImpl();
 810     }
 811     return vmregImpl;
 812   }
 813 
 814   public FileMapInfo getFileMapInfo() {
 815     if (!isSharingEnabled()) {
 816       return null;
 817     }
 818     if (fileMapInfo == null) {
 819       fileMapInfo = new FileMapInfo();
 820     }
 821     return fileMapInfo;
 822   }
 823 
 824   public Bytes getBytes() {
 825     if (bytes == null) {
 826       bytes = new Bytes(debugger.getMachineDescription());
 827     }
 828     return bytes;
 829   }
 830 
 831   /** Returns true if this is a isBigEndian, false otherwise */
 832   public boolean isBigEndian() {
 833     return isBigEndian;
 834   }
 835 
 836   /** Returns true if JVMTI is supported, false otherwise */
 837   public boolean isJvmtiSupported() {
 838     return isJvmtiSupported;
 839   }
 840 
 841   /** Returns true if this is a "core" build, false if either C1 or C2
 842       is present */
 843   public boolean isCore() {
 844     return (!(usingClientCompiler || usingServerCompiler));
 845   }
 846 
 847   /** Returns true if this is a C1 build, false otherwise */
 848   public boolean isClientCompiler() {
 849     return usingClientCompiler;
 850   }
 851 
 852   /** Returns true if this is a C2 build, false otherwise */
 853   public boolean isServerCompiler() {
 854     return usingServerCompiler;
 855   }
 856 
 857   /** Returns true if C2 derived pointer table should be used, false otherwise */
 858   public boolean useDerivedPointerTable() {
 859     return !disableDerivedPointerTableCheck;
 860   }
 861 
 862   /** Returns the code cache; should not be used if is core build */
 863   public CodeCache getCodeCache() {
 864     if (Assert.ASSERTS_ENABLED) {
 865       Assert.that(!isCore(), "noncore builds only");
 866     }
 867     if (codeCache == null) {
 868       codeCache = new CodeCache();
 869     }
 870     return codeCache;
 871   }
 872 
 873   /** Should only be called for C1 builds */
 874   public Runtime1 getRuntime1() {
 875     if (Assert.ASSERTS_ENABLED) {
 876       Assert.that(isClientCompiler(), "C1 builds only");
 877     }
 878     if (runtime1 == null) {
 879       runtime1 = new Runtime1();
 880     }
 881     return runtime1;
 882   }
 883 
 884   /** Test to see whether we're in debugging mode (NOTE: this really
 885       should not be tested by this code; currently only used in
 886       StackFrameStream) */
 887   public boolean isDebugging() {
 888     return (debugger != null);
 889   }
 890 
 891   /** This is only used by the debugging (i.e., non-runtime) system */
 892   public JVMDebugger getDebugger() {
 893     if (debugger == null) {
 894       throw new RuntimeException("Attempt to use debugger in runtime system");
 895     }
 896     return debugger;
 897   }
 898 
 899   /** Indicates whether a given program counter is in Java code. This
 900       includes but is not spanned by the interpreter and code cache.
 901       Only used in the debugging system, for implementing
 902       JavaThread.currentFrameGuess() on x86. */
 903   public boolean isJavaPCDbg(Address addr) {
 904     // FIXME: this is not a complete enough set: must include areas
 905     // like vtable stubs
 906     return (getInterpreter().contains(addr) ||
 907             getCodeCache().contains(addr));
 908   }
 909 
 910   /** FIXME: figure out where to stick this */
 911   public int getInvocationEntryBCI() {
 912     return invocationEntryBCI;
 913   }
 914 
 915   // FIXME: figure out where to stick this
 916   public boolean wizardMode() {
 917     return true;
 918   }
 919 
 920   public ReversePtrs getRevPtrs() {
 921     return revPtrs;
 922   }
 923 
 924   public void setRevPtrs(ReversePtrs rp) {
 925     revPtrs = rp;
 926   }
 927 
 928   // returns null, if not available.
 929   public String getVMRelease() {
 930     return vmRelease;
 931   }
 932 
 933   // returns null, if not available.
 934   public String getVMInternalInfo() {
 935     return vmInternalInfo;
 936   }
 937 
 938   public int getReserveForAllocationPrefetch() {
 939     return reserveForAllocationPrefetch;
 940   }
 941 
 942   public boolean isSharingEnabled() {
 943     if (sharingEnabled == null) {
 944         Address address = VM.getVM().getDebugger().lookup(null, "UseSharedSpaces");
 945         if (address == null && getOS().equals("win32")) {
 946             // On Win32 symbols are prefixed with the dll name. So look for
 947             // UseSharedSpaces as a symbol in jvm.dll.
 948             address = VM.getVM().getDebugger().lookup(null, "jvm!UseSharedSpaces");
 949         }
 950         sharingEnabled = address.getJBooleanAt(0);
 951     }
 952     return sharingEnabled.booleanValue();
 953   }
 954 
 955   public boolean isCompressedOopsEnabled() {
 956     if (compressedOopsEnabled == null) {
 957         Flag flag = getCommandLineFlag("UseCompressedOops");
 958         compressedOopsEnabled = (flag == null) ? Boolean.FALSE:
 959              (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 960     }
 961     return compressedOopsEnabled.booleanValue();
 962   }
 963 
 964   public boolean isCompressedKlassPointersEnabled() {
 965     if (compressedKlassPointersEnabled == null) {
 966         Flag flag = getCommandLineFlag("UseCompressedClassPointers");
 967         compressedKlassPointersEnabled = (flag == null) ? Boolean.FALSE:
 968              (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 969     }
 970     return compressedKlassPointersEnabled.booleanValue();
 971   }
 972 
 973   public int getObjectAlignmentInBytes() {
 974     if (objectAlignmentInBytes == 0) {
 975         Flag flag = getCommandLineFlag("ObjectAlignmentInBytes");
 976         objectAlignmentInBytes = (flag == null) ? 8 : (int)flag.getInt();
 977     }
 978     return objectAlignmentInBytes;
 979   }
 980 
 981   /** Indicates whether Thread-Local Allocation Buffers are used */
 982   public boolean getUseTLAB() {
 983       Flag flag = getCommandLineFlag("UseTLAB");
 984       return (flag == null) ? false: flag.getBool();
 985   }
 986 
 987   public boolean getCommandLineBooleanFlag(String name) {
 988     Flag flag = getCommandLineFlag(name);
 989     return (flag == null) ? Boolean.FALSE:
 990       (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 991   }
 992 
 993   // returns null, if not available.
 994   public Flag[] getCommandLineFlags() {
 995     if (commandLineFlags == null) {
 996        readCommandLineFlags();
 997     }
 998 
 999     return commandLineFlags;
1000   }
1001 
1002   public Flag getCommandLineFlag(String name) {
1003     if (flagsMap == null) {
1004       flagsMap = new HashMap<>();
1005       Flag[] flags = getCommandLineFlags();
1006       for (int i = 0; i < flags.length; i++) {
1007         flagsMap.put(flags[i].getName(), flags[i]);
1008       }
1009     }
1010     return flagsMap.get(name);
1011   }
1012 
1013   private static final String cmdFlagTypes[] = {
1014     "bool",
1015     "int",
1016     "uint",
1017     "intx",
1018     "uintx",
1019     "uint64_t",
1020     "size_t",
1021     "double",
1022     "ccstr",
1023     "ccstrlist"
1024   };
1025 
1026   private String getFlagTypeAsString(int typeIndex) {
1027     if (0 <= typeIndex && typeIndex < cmdFlagTypes.length) {
1028       return cmdFlagTypes[typeIndex];
1029     } else {
1030       return "unknown";
1031     }
1032   }
1033 
1034   private void readCommandLineFlags() {
1035     // get command line flags
1036     TypeDataBase db = getTypeDataBase();
1037     Type flagType = db.lookupType("JVMFlag");
1038     int numFlags = (int) flagType.getCIntegerField("numFlags").getValue();
1039     // NOTE: last flag contains null values.
1040     commandLineFlags = new Flag[numFlags - 1];
1041 
1042     Address flagAddr = flagType.getAddressField("flags").getValue();
1043     CIntField typeFld = new CIntField(flagType.getCIntegerField("_type"), 0);
1044     AddressField nameFld = flagType.getAddressField("_name");
1045     AddressField addrFld = flagType.getAddressField("_addr");
1046     CIntField flagsFld = new CIntField(flagType.getCIntegerField("_flags"), 0);
1047 
1048     long flagSize = flagType.getSize(); // sizeof(Flag)
1049 
1050     // NOTE: last flag contains null values.
1051     for (int f = 0; f < numFlags - 1; f++) {
1052       int typeIndex = (int)typeFld.getValue(flagAddr);
1053       String type = getFlagTypeAsString(typeIndex);
1054       String name = CStringUtilities.getString(nameFld.getValue(flagAddr));
1055       Address addr = addrFld.getValue(flagAddr);
1056       int flags = (int)flagsFld.getValue(flagAddr);
1057       commandLineFlags[f] = new Flag(type, name, addr, flags);
1058       flagAddr = flagAddr.addOffsetTo(flagSize);
1059     }
1060 
1061     // sort flags by name
1062     Arrays.sort(commandLineFlags, new Comparator<>() {
1063         public int compare(Flag f1, Flag f2) {
1064           return f1.getName().compareTo(f2.getName());
1065         }
1066       });
1067   }
1068 
1069   public String getSystemProperty(String key) {
1070     Properties props = getSystemProperties();
1071     return (props != null)? props.getProperty(key) : null;
1072   }
1073 
1074   public Properties getSystemProperties() {
1075     if (sysProps == null) {
1076        readSystemProperties();
1077     }
1078     return sysProps;
1079   }
1080 
1081   private void readSystemProperties() {
1082     final InstanceKlass systemKls = getSystemDictionary().getSystemKlass();
1083     systemKls.iterateStaticFields(new DefaultOopVisitor() {
1084         ObjectReader objReader = new ObjectReader();
1085         public void doOop(sun.jvm.hotspot.oops.OopField field, boolean isVMField) {
1086           if (field.getID().getName().equals("props")) {
1087             try {
1088               sysProps = (Properties) objReader.readObject(field.getValue(getObj()));
1089             } catch (Exception e) {
1090               e.printStackTrace();
1091             }
1092           }
1093         }
1094       });
1095   }
1096 }