1 /*
   2  * Copyright (c) 2000, 2021, 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          objectAlignmentInBytes;
 102   private int          minObjAlignmentInBytes;
 103   private int          logMinObjAlignmentInBytes;
 104   private int          heapWordSize;
 105   private int          heapOopSize;
 106   private int          klassPtrSize;
 107   private int          oopSize;
 108   /** -XX flags (value origin) */
 109   public static int    Flags_DEFAULT;
 110   public static int    Flags_COMMAND_LINE;
 111   public static int    Flags_ENVIRON_VAR;
 112   public static int    Flags_CONFIG_FILE;
 113   public static int    Flags_MANAGEMENT;
 114   public static int    Flags_ERGONOMIC;
 115   public static int    Flags_ATTACH_ON_DEMAND;
 116   public static int    Flags_INTERNAL;
 117   public static int    Flags_JIMAGE_RESOURCE;
 118   private static int   Flags_VALUE_ORIGIN_MASK;
 119   private static int   Flags_WAS_SET_ON_COMMAND_LINE;
 120   /** This is only present in a non-core build */
 121   private CodeCache    codeCache;
 122   /** This is only present in a C1 build */
 123   private Runtime1     runtime1;
 124   /** These constants come from globalDefinitions.hpp */
 125   private int          invocationEntryBCI;
 126   private ReversePtrs  revPtrs;
 127   private VMRegImpl    vmregImpl;
 128   private int          reserveForAllocationPrefetch;
 129 
 130   // System.getProperties from debuggee VM
 131   private Properties   sysProps;
 132 
 133   // VM version strings come from Abstract_VM_Version class
 134   private String       vmRelease;
 135   private String       vmInternalInfo;
 136 
 137   private Flag[] commandLineFlags;
 138   private Map<String, Flag> flagsMap;
 139 
 140   private static Type intType;
 141   private static Type uintType;
 142   private static Type intxType;
 143   private static Type uintxType;
 144   private static Type sizetType;
 145   private static Type uint64tType;
 146   private static CIntegerType boolType;
 147   private Boolean sharingEnabled;
 148   private Boolean compressedOopsEnabled;
 149   private Boolean compressedKlassPointersEnabled;
 150 
 151   // command line flags supplied to VM - see struct JVMFlag in jvmFlag.hpp
 152   public static final class Flag {
 153      private String type;
 154      private String name;
 155      private Address addr;
 156      private int flags;
 157 
 158      private Flag(String type, String name, Address addr, int flags) {
 159         this.type = type;
 160         this.name = name;
 161         this.addr = addr;
 162         this.flags = flags;
 163      }
 164 
 165      public String getType() {
 166         return type;
 167      }
 168 
 169      public String getName() {
 170         return name;
 171      }
 172 
 173      public Address getAddress() {
 174         return addr;
 175      }
 176 
 177      public int getOrigin() {
 178         return flags & Flags_VALUE_ORIGIN_MASK;
 179      }
 180 
 181      // See JVMFlag::print_origin() in HotSpot
 182      public String getOriginString() {
 183         var origin = flags & Flags_VALUE_ORIGIN_MASK;
 184         if (origin == Flags_DEFAULT) {
 185             return "default";
 186         } else if (origin == Flags_COMMAND_LINE) {
 187             return "command line";
 188         } else if (origin == Flags_ENVIRON_VAR) {
 189             return "environment";
 190         } else if (origin == Flags_CONFIG_FILE) {
 191             return "config file";
 192         } else if (origin == Flags_MANAGEMENT) {
 193             return "management";
 194         } else if (origin == Flags_ERGONOMIC) {
 195             String result = "";
 196             if ((flags & Flags_WAS_SET_ON_COMMAND_LINE) == Flags_WAS_SET_ON_COMMAND_LINE) {
 197                 result = "command line, ";
 198             }
 199             return result + "ergonomic";
 200         } else if (origin == Flags_ATTACH_ON_DEMAND) {
 201             return "attach";
 202         } else if (origin == Flags_INTERNAL) {
 203             return "internal";
 204         } else if (origin == Flags_JIMAGE_RESOURCE) {
 205             return "jimage";
 206         } else {
 207             throw new IllegalStateException(
 208                 "Unknown flag origin " + origin + " is detected in " + name);
 209         }
 210      }
 211 
 212      public boolean isBool() {
 213         return type.equals("bool");
 214      }
 215 
 216      public boolean getBool() {
 217         if (Assert.ASSERTS_ENABLED) {
 218            Assert.that(isBool(), "not a bool flag!");
 219         }
 220         return addr.getCIntegerAt(0, boolType.getSize(), boolType.isUnsigned()) != 0;
 221      }
 222 
 223      public boolean isInt() {
 224         return type.equals("int");
 225      }
 226 
 227      public long getInt() {
 228         if (Assert.ASSERTS_ENABLED) {
 229            Assert.that(isInt(), "not an int flag!");
 230         }
 231         return addr.getCIntegerAt(0, intType.getSize(), false);
 232      }
 233 
 234      public boolean isUInt() {
 235         return type.equals("uint");
 236      }
 237 
 238      public long getUInt() {
 239         if (Assert.ASSERTS_ENABLED) {
 240            Assert.that(isUInt(), "not a uint flag!");
 241         }
 242         return addr.getCIntegerAt(0, uintType.getSize(), false);
 243      }
 244 
 245      public boolean isIntx() {
 246         return type.equals("intx");
 247      }
 248 
 249      public long getIntx() {
 250         if (Assert.ASSERTS_ENABLED) {
 251            Assert.that(isIntx(), "not an intx flag!");
 252         }
 253         return addr.getCIntegerAt(0, intxType.getSize(), false);
 254      }
 255 
 256      public boolean isUIntx() {
 257         return type.equals("uintx");
 258      }
 259 
 260      public long getUIntx() {
 261         if (Assert.ASSERTS_ENABLED) {
 262            Assert.that(isUIntx(), "not a uintx flag!");
 263         }
 264         return addr.getCIntegerAt(0, uintxType.getSize(), true);
 265      }
 266 
 267      public boolean isSizet() {
 268         return type.equals("size_t");
 269      }
 270 
 271      public long getSizet() {
 272         if (Assert.ASSERTS_ENABLED) {
 273            Assert.that(isSizet(), "not a size_t flag!");
 274         }
 275         return addr.getCIntegerAt(0, sizetType.getSize(), true);
 276      }
 277 
 278      public boolean isCcstr() {
 279         return type.equals("ccstr");
 280      }
 281 
 282      public String getCcstr() {
 283         if (Assert.ASSERTS_ENABLED) {
 284            Assert.that(isCcstr(), "not a ccstr flag!");
 285         }
 286         return CStringUtilities.getString(addr.getAddressAt(0));
 287      }
 288 
 289      public boolean isCcstrlist() {
 290         return type.equals("ccstrlist");
 291      }
 292 
 293      public String getCcstrlist() {
 294         if (Assert.ASSERTS_ENABLED) {
 295            Assert.that(isCcstrlist(), "not a ccstrlist flag!");
 296         }
 297         return CStringUtilities.getString(addr.getAddressAt(0));
 298      }
 299 
 300      public boolean isDouble() {
 301         return type.equals("double");
 302      }
 303 
 304      public double getDouble() {
 305         if (Assert.ASSERTS_ENABLED) {
 306            Assert.that(isDouble(), "not a double flag!");
 307         }
 308         return addr.getJDoubleAt(0);
 309      }
 310 
 311      public boolean isUint64t() {
 312         return type.equals("uint64_t");
 313      }
 314 
 315      public long getUint64t() {
 316         if (Assert.ASSERTS_ENABLED) {
 317            Assert.that(isUint64t(), "not an uint64_t flag!");
 318         }
 319         return addr.getCIntegerAt(0, uint64tType.getSize(), true);
 320      }
 321 
 322      public String getValue() {
 323         if (isBool()) {
 324            return Boolean.toString(getBool());
 325         } else if (isInt()) {
 326            return Long.toString(getInt());
 327         } else if (isUInt()) {
 328            return Long.toString(getUInt());
 329         } else if (isIntx()) {
 330            return Long.toString(getIntx());
 331         } else if (isUIntx()) {
 332            return Long.toUnsignedString(getUIntx());
 333         } else if (isSizet()) {
 334            return Long.toUnsignedString(getSizet());
 335         } else if (isCcstr()) {
 336            var str = getCcstr();
 337            if (str != null) {
 338                str = "\"" + str + "\"";
 339            }
 340            return str;
 341         } else if (isCcstrlist()) {
 342            var str = getCcstrlist();
 343            if (str != null) {
 344                str = "\"" + str + "\"";
 345            }
 346            return str;
 347         } else if (isDouble()) {
 348            return Double.toString(getDouble());
 349         } else if (isUint64t()) {
 350            return Long.toUnsignedString(getUint64t());
 351         } else {
 352            throw new WrongTypeException("Unknown type: " + type + " (" + name + ")");
 353         }
 354      }
 355   };
 356 
 357   private static void checkVMVersion(String vmRelease) {
 358      if (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null) {
 359         // read sa build version.
 360         String versionProp = "sun.jvm.hotspot.runtime.VM.saBuildVersion";
 361         String saVersion = saProps.getProperty(versionProp);
 362         if (saVersion == null)
 363            throw new RuntimeException("Missing property " + versionProp);
 364 
 365         // Strip nonproduct VM version substring (note: saVersion doesn't have it).
 366         String vmVersion = vmRelease.replaceAll("(-fastdebug)|(-debug)|(-jvmg)|(-optimized)|(-profiled)","");
 367 
 368         if (saVersion.equals(vmVersion)) {
 369            // Exact match
 370            return;
 371         }
 372         if (saVersion.indexOf('-') == saVersion.lastIndexOf('-') &&
 373             vmVersion.indexOf('-') == vmVersion.lastIndexOf('-')) {
 374            // Throw exception if different release versions:
 375            // <major>.<minor>-b<n>
 376            throw new VMVersionMismatchException(saVersion, vmRelease);
 377         } else {
 378            // Otherwise print warning to allow mismatch not release versions
 379            // during development.
 380            System.err.println("WARNING: Hotspot VM version " + vmRelease +
 381                               " does not match with SA version " + saVersion +
 382                               "." + " You may see unexpected results. ");
 383         }
 384      } else {
 385         System.err.println("WARNING: You have disabled SA and VM version check. You may be "  +
 386                            "using incompatible version of SA and you may see unexpected " +
 387                            "results.");
 388      }
 389   }
 390 
 391   private static final boolean disableDerivedPointerTableCheck;
 392   private static final Properties saProps;
 393 
 394   static {
 395      saProps = new Properties();
 396      URL url = null;
 397      try {
 398        saProps.load(VM.class.getResourceAsStream("/sa.properties"));
 399      } catch (Exception e) {
 400        System.err.println("Unable to load properties  " +
 401                                   (url == null ? "null" : url.toString()) +
 402                                   ": " + e.getMessage());
 403      }
 404 
 405      disableDerivedPointerTableCheck = System.getProperty("sun.jvm.hotspot.runtime.VM.disableDerivedPointerTableCheck") != null;
 406   }
 407 
 408   private VM(TypeDataBase db, JVMDebugger debugger, boolean isBigEndian) {
 409     this.db          = db;
 410     this.debugger    = debugger;
 411     this.isBigEndian = isBigEndian;
 412 
 413     // Note that we don't construct universe, heap, threads,
 414     // interpreter, or stubRoutines here (any more).  The current
 415     // initialization mechanisms require that the VM be completely set
 416     // up (i.e., out of its constructor, with soleInstance assigned)
 417     // before their static initializers are run.
 418 
 419     if (db.getAddressSize() == 4) {
 420       logAddressSize = 2;
 421     } else if (db.getAddressSize() == 8) {
 422       logAddressSize = 3;
 423     } else {
 424       throw new RuntimeException("Address size " + db.getAddressSize() + " not yet supported");
 425     }
 426 
 427     // read VM version info
 428     try {
 429        Type vmVersion = db.lookupType("Abstract_VM_Version");
 430        Address releaseAddr = vmVersion.getAddressField("_s_vm_release").getValue();
 431        vmRelease = CStringUtilities.getString(releaseAddr);
 432        Address vmInternalInfoAddr = vmVersion.getAddressField("_s_internal_vm_info_string").getValue();
 433        vmInternalInfo = CStringUtilities.getString(vmInternalInfoAddr);
 434 
 435        Type threadLocalAllocBuffer = db.lookupType("ThreadLocalAllocBuffer");
 436        CIntegerType intType = (CIntegerType) db.lookupType("int");
 437        CIntegerField reserveForAllocationPrefetchField = threadLocalAllocBuffer.getCIntegerField("_reserve_for_allocation_prefetch");
 438        reserveForAllocationPrefetch = (int)reserveForAllocationPrefetchField.getCInteger(intType);
 439     } catch (Exception exp) {
 440        throw new RuntimeException("can't determine target's VM version : " + exp.getMessage());
 441     }
 442 
 443     checkVMVersion(vmRelease);
 444 
 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("JVMFlagOrigin::DEFAULT").intValue();
 482     Flags_COMMAND_LINE = db.lookupIntConstant("JVMFlagOrigin::COMMAND_LINE").intValue();
 483     Flags_ENVIRON_VAR = db.lookupIntConstant("JVMFlagOrigin::ENVIRON_VAR").intValue();
 484     Flags_CONFIG_FILE = db.lookupIntConstant("JVMFlagOrigin::CONFIG_FILE").intValue();
 485     Flags_MANAGEMENT = db.lookupIntConstant("JVMFlagOrigin::MANAGEMENT").intValue();
 486     Flags_ERGONOMIC = db.lookupIntConstant("JVMFlagOrigin::ERGONOMIC").intValue();
 487     Flags_ATTACH_ON_DEMAND = db.lookupIntConstant("JVMFlagOrigin::ATTACH_ON_DEMAND").intValue();
 488     Flags_INTERNAL = db.lookupIntConstant("JVMFlagOrigin::INTERNAL").intValue();
 489     Flags_JIMAGE_RESOURCE = db.lookupIntConstant("JVMFlagOrigin::JIMAGE_RESOURCE").intValue();
 490     Flags_VALUE_ORIGIN_MASK = db.lookupIntConstant("JVMFlag::VALUE_ORIGIN_MASK").intValue();
 491     Flags_WAS_SET_ON_COMMAND_LINE = db.lookupIntConstant("JVMFlag::WAS_SET_ON_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 & (minObjAlignmentInBytes - 1)) != 0) {
 504       throw new RuntimeException("Object alignment " + minObjAlignmentInBytes + " is not power of two");
 505     }
 506 
 507     logMinObjAlignmentInBytes = Integer.numberOfTrailingZeros(minObjAlignmentInBytes);
 508 
 509     if (isCompressedOopsEnabled()) {
 510       // Size info for oops within java objects is fixed
 511       heapOopSize = (int)getIntSize();
 512     } else {
 513       heapOopSize = (int)getOopSize();
 514     }
 515 
 516     if (isCompressedKlassPointersEnabled()) {
 517       klassPtrSize = (int)getIntSize();
 518     } else {
 519       klassPtrSize = (int)getOopSize(); // same as an oop
 520     }
 521   }
 522 
 523   /** This could be used by a reflective runtime system */
 524   public static void initialize(TypeDataBase db, boolean isBigEndian) {
 525     if (soleInstance != null) {
 526       throw new RuntimeException("Attempt to initialize VM twice");
 527     }
 528     soleInstance = new VM(db, null, isBigEndian);
 529     for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) {
 530       ((Observer) iter.next()).update(null, null);
 531     }
 532   }
 533 
 534   /** This is used by the debugging system */
 535   public static void initialize(TypeDataBase db, JVMDebugger debugger) {
 536     if (soleInstance != null) {
 537       // Using multiple SA Tool classes in the same process creates a call here.
 538       return;
 539     }
 540     soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian());
 541 
 542     for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) {
 543       ((Observer) iter.next()).update(null, null);
 544     }
 545 
 546     debugger.putHeapConst(soleInstance.getHeapOopSize(), soleInstance.getKlassPtrSize(),
 547                           CompressedOops.getBase(), CompressedOops.getShift(),
 548                           CompressedKlassPointers.getBase(), CompressedKlassPointers.getShift());
 549   }
 550 
 551   /** This is used by the debugging system */
 552   public static void shutdown() {
 553     soleInstance = null;
 554   }
 555 
 556   /** This is used by both the debugger and any runtime system. It is
 557       the basic mechanism by which classes which mimic underlying VM
 558       functionality cause themselves to be initialized. The given
 559       observer will be notified (with arguments (null, null)) when the
 560       VM is re-initialized, as well as when it registers itself with
 561       the VM. */
 562   public static void registerVMInitializedObserver(Observer o) {
 563     vmInitializedObservers.add(o);
 564     o.update(null, null);
 565   }
 566 
 567   /** This is the primary accessor used by both the debugger and any
 568       potential runtime system */
 569   public static VM getVM() {
 570     if (soleInstance == null) {
 571       throw new RuntimeException("VM.initialize() was not yet called");
 572     }
 573     return soleInstance;
 574   }
 575 
 576   /** This is only used by the debugging system. The given observer
 577       will be notified if the underlying VM resumes execution. NOTE
 578       that the given observer is not triggered if the VM is currently
 579       running and therefore differs in behavior from {@link
 580       #registerVMInitializedObserver} (because of the possibility of
 581       race conditions if the observer is added while the VM is being
 582       suspended or resumed).  */
 583   public void registerVMResumedObserver(Observer o) {
 584     vmResumedObservers.add(o);
 585   }
 586 
 587   /** This is only used by the debugging system. The given observer
 588       will be notified if the underlying VM suspends execution. NOTE
 589       that the given observer is not triggered if the VM is currently
 590       suspended and therefore differs in behavior from {@link
 591       #registerVMInitializedObserver} (because of the possibility of
 592       race conditions if the observer is added while the VM is being
 593       suspended or resumed).  */
 594   public void registerVMSuspendedObserver(Observer o) {
 595     vmSuspendedObservers.add(o);
 596   }
 597 
 598   /** This is only used by the debugging system. Informs all
 599       registered resumption observers that the VM has been resumed.
 600       The application is responsible for actually having performed the
 601       resumption. No OopHandles must be used after this point, as they
 602       may move in the target address space due to garbage
 603       collection. */
 604   public void fireVMResumed() {
 605     for (Iterator iter = vmResumedObservers.iterator(); iter.hasNext(); ) {
 606       ((Observer) iter.next()).update(null, null);
 607     }
 608   }
 609 
 610   /** This is only used by the debugging system. Informs all
 611       registered suspension observers that the VM has been suspended.
 612       The application is responsible for actually having performed the
 613       suspension. Garbage collection must be forbidden at this point;
 614       for example, a JPDA-level suspension is not adequate since the
 615       VM thread may still be running. */
 616   public void fireVMSuspended() {
 617     for (Iterator iter = vmSuspendedObservers.iterator(); iter.hasNext(); ) {
 618       ((Observer) iter.next()).update(null, null);
 619     }
 620   }
 621 
 622   /** Returns the OS this VM is running on. Notice that by delegating
 623       to the debugger we can transparently support remote
 624       debugging. */
 625   public String getOS() {
 626     if (debugger != null) {
 627       return debugger.getOS();
 628     }
 629     return PlatformInfo.getOS();
 630   }
 631 
 632   /** Returns the CPU this VM is running on. Notice that by delegating
 633       to the debugger we can transparently support remote
 634       debugging. */
 635   public String getCPU() {
 636     if (debugger != null) {
 637       return debugger.getCPU();
 638     }
 639     return PlatformInfo.getCPU();
 640   }
 641 
 642   public Type lookupType(String cTypeName) {
 643     return db.lookupType(cTypeName);
 644   }
 645 
 646   public Integer lookupIntConstant(String name) {
 647     return db.lookupIntConstant(name);
 648   }
 649 
 650   // Convenience function for conversions
 651   static public long getAddressValue(Address addr) {
 652     return VM.getVM().getDebugger().getAddressValue(addr);
 653   }
 654 
 655   public long getAddressSize() {
 656     return db.getAddressSize();
 657   }
 658 
 659   public long getOopSize() {
 660     return oopSize;
 661   }
 662 
 663   public long getLogAddressSize() {
 664     return logAddressSize;
 665   }
 666 
 667   public long getIntSize() {
 668     return db.getJIntType().getSize();
 669   }
 670 
 671   /** Indicates whether the underlying machine supports the LP64 data
 672       model. This is needed for conditionalizing code in a few places */
 673   public boolean isLP64() {
 674     if (Assert.ASSERTS_ENABLED) {
 675       Assert.that(isDebugging(), "Debugging system only for now");
 676     }
 677     return isLP64;
 678   }
 679 
 680   /** Get bytes-per-long == long/double natural alignment. */
 681   public int getBytesPerLong() {
 682     return bytesPerLong;
 683   }
 684 
 685   public int getBytesPerWord() {
 686     return bytesPerWord;
 687   }
 688 
 689   /** Get minimum object alignment in bytes. */
 690   public int getMinObjAlignmentInBytes() {
 691     return minObjAlignmentInBytes;
 692   }
 693   public int getLogMinObjAlignmentInBytes() {
 694     return logMinObjAlignmentInBytes;
 695   }
 696 
 697   public int getHeapWordSize() {
 698     return heapWordSize;
 699   }
 700 
 701   public int getHeapOopSize() {
 702     return heapOopSize;
 703   }
 704 
 705   public int getKlassPtrSize() {
 706     return klassPtrSize;
 707   }
 708   /** Utility routine for getting data structure alignment correct */
 709   public long alignUp(long size, long alignment) {
 710     return (size + alignment - 1) & ~(alignment - 1);
 711   }
 712 
 713   /** Utility routine for getting data structure alignment correct */
 714   public long alignDown(long size, long alignment) {
 715     return size & ~(alignment - 1);
 716   }
 717 
 718   /** Utility routine for building an int from two "unsigned" 16-bit
 719       shorts */
 720   public int buildIntFromShorts(short low, short high) {
 721     return (((int) high) << 16) | (((int) low) & 0xFFFF);
 722   }
 723 
 724   /** Utility routine for building a long from two "unsigned" 32-bit
 725       ints in <b>platform-dependent</b> order */
 726   public long buildLongFromIntsPD(int oneHalf, int otherHalf) {
 727     if (isBigEndian) {
 728       return (((long) otherHalf) << 32) | (((long) oneHalf) & 0x00000000FFFFFFFFL);
 729     } else{
 730       return (((long) oneHalf) << 32) | (((long) otherHalf) & 0x00000000FFFFFFFFL);
 731     }
 732   }
 733 
 734   public TypeDataBase getTypeDataBase() {
 735     return db;
 736   }
 737 
 738   public Universe    getUniverse() {
 739     if (universe == null) {
 740       universe = new Universe();
 741     }
 742     return universe;
 743   }
 744 
 745   public ObjectHeap  getObjectHeap() {
 746     if (heap == null) {
 747       heap = new ObjectHeap(db);
 748     }
 749     return heap;
 750   }
 751 
 752   public SystemDictionary getSystemDictionary() {
 753     if (dict == null) {
 754       dict = new SystemDictionary();
 755     }
 756     return dict;
 757   }
 758 
 759   public ClassLoaderDataGraph getClassLoaderDataGraph() {
 760     if (cldGraph == null) {
 761       cldGraph = new ClassLoaderDataGraph();
 762     }
 763     return cldGraph;
 764   }
 765 
 766   public Threads     getThreads() {
 767     if (threads == null) {
 768       threads = new Threads();
 769     }
 770     return threads;
 771   }
 772 
 773   public ObjectSynchronizer getObjectSynchronizer() {
 774     if (synchronizer == null) {
 775       synchronizer = new ObjectSynchronizer();
 776     }
 777     return synchronizer;
 778   }
 779 
 780   public JNIHandles getJNIHandles() {
 781     if (handles == null) {
 782       handles = new JNIHandles();
 783     }
 784     return handles;
 785   }
 786 
 787   public Interpreter getInterpreter() {
 788     if (interpreter == null) {
 789       interpreter = new Interpreter();
 790     }
 791     return interpreter;
 792   }
 793 
 794   public StubRoutines getStubRoutines() {
 795     if (stubRoutines == null) {
 796       stubRoutines = new StubRoutines();
 797     }
 798     return stubRoutines;
 799   }
 800 
 801   public VMRegImpl getVMRegImplInfo() {
 802     if (vmregImpl == null) {
 803       vmregImpl = new VMRegImpl();
 804     }
 805     return vmregImpl;
 806   }
 807 
 808   public FileMapInfo getFileMapInfo() {
 809     if (!isSharingEnabled()) {
 810       return null;
 811     }
 812     if (fileMapInfo == null) {
 813       fileMapInfo = new FileMapInfo();
 814     }
 815     return fileMapInfo;
 816   }
 817 
 818   public Bytes getBytes() {
 819     if (bytes == null) {
 820       bytes = new Bytes(debugger.getMachineDescription());
 821     }
 822     return bytes;
 823   }
 824 
 825   /** Returns true if this is a isBigEndian, false otherwise */
 826   public boolean isBigEndian() {
 827     return isBigEndian;
 828   }
 829 
 830   /** Returns true if JVMTI is supported, false otherwise */
 831   public boolean isJvmtiSupported() {
 832     return isJvmtiSupported;
 833   }
 834 
 835   /** Returns true if this is a "core" build, false if either C1 or C2
 836       is present */
 837   public boolean isCore() {
 838     return (!(usingClientCompiler || usingServerCompiler));
 839   }
 840 
 841   /** Returns true if this is a C1 build, false otherwise */
 842   public boolean isClientCompiler() {
 843     return usingClientCompiler;
 844   }
 845 
 846   /** Returns true if this is a C2 build, false otherwise */
 847   public boolean isServerCompiler() {
 848     return usingServerCompiler;
 849   }
 850 
 851   /** Returns true if C2 derived pointer table should be used, false otherwise */
 852   public boolean useDerivedPointerTable() {
 853     return !disableDerivedPointerTableCheck;
 854   }
 855 
 856   /** Returns the code cache; should not be used if is core build */
 857   public CodeCache getCodeCache() {
 858     if (Assert.ASSERTS_ENABLED) {
 859       Assert.that(!isCore(), "noncore builds only");
 860     }
 861     if (codeCache == null) {
 862       codeCache = new CodeCache();
 863     }
 864     return codeCache;
 865   }
 866 
 867   /** Should only be called for C1 builds */
 868   public Runtime1 getRuntime1() {
 869     if (Assert.ASSERTS_ENABLED) {
 870       Assert.that(isClientCompiler(), "C1 builds only");
 871     }
 872     if (runtime1 == null) {
 873       runtime1 = new Runtime1();
 874     }
 875     return runtime1;
 876   }
 877 
 878   /** Test to see whether we're in debugging mode (NOTE: this really
 879       should not be tested by this code; currently only used in
 880       StackFrameStream) */
 881   public boolean isDebugging() {
 882     return (debugger != null);
 883   }
 884 
 885   /** This is only used by the debugging (i.e., non-runtime) system */
 886   public JVMDebugger getDebugger() {
 887     if (debugger == null) {
 888       throw new RuntimeException("Attempt to use debugger in runtime system");
 889     }
 890     return debugger;
 891   }
 892 
 893   /** Indicates whether a given program counter is in Java code. This
 894       includes but is not spanned by the interpreter and code cache.
 895       Only used in the debugging system, for implementing
 896       JavaThread.currentFrameGuess() on x86. */
 897   public boolean isJavaPCDbg(Address addr) {
 898     // FIXME: this is not a complete enough set: must include areas
 899     // like vtable stubs
 900     return (getInterpreter().contains(addr) ||
 901             getCodeCache().contains(addr));
 902   }
 903 
 904   /** FIXME: figure out where to stick this */
 905   public int getInvocationEntryBCI() {
 906     return invocationEntryBCI;
 907   }
 908 
 909   // FIXME: figure out where to stick this
 910   public boolean wizardMode() {
 911     return true;
 912   }
 913 
 914   public ReversePtrs getRevPtrs() {
 915     return revPtrs;
 916   }
 917 
 918   public void setRevPtrs(ReversePtrs rp) {
 919     revPtrs = rp;
 920   }
 921 
 922   // returns null, if not available.
 923   public String getVMRelease() {
 924     return vmRelease;
 925   }
 926 
 927   // returns null, if not available.
 928   public String getVMInternalInfo() {
 929     return vmInternalInfo;
 930   }
 931 
 932   public int getReserveForAllocationPrefetch() {
 933     return reserveForAllocationPrefetch;
 934   }
 935 
 936   public boolean isSharingEnabled() {
 937     if (sharingEnabled == null) {
 938       Flag flag = getCommandLineFlag("UseSharedSpaces");
 939       sharingEnabled = (flag == null)? Boolean.FALSE :
 940           (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 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.getIntx();
 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 (Flag) 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 }