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