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