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 == 8) {
 504       logMinObjAlignmentInBytes = 3;
 505     } else if (minObjAlignmentInBytes == 16) {
 506       logMinObjAlignmentInBytes = 4;
 507     } else {
 508       throw new RuntimeException("Object alignment " + minObjAlignmentInBytes + " not yet supported");
 509     }
 510 
 511     if (isCompressedOopsEnabled()) {
 512       // Size info for oops within java objects is fixed
 513       heapOopSize = (int)getIntSize();
 514     } else {
 515       heapOopSize = (int)getOopSize();
 516     }
 517 
 518     if (isCompressedKlassPointersEnabled()) {
 519       klassPtrSize = (int)getIntSize();
 520     } else {
 521       klassPtrSize = (int)getOopSize(); // same as an oop
 522     }
 523   }
 524 
 525   /** This could be used by a reflective runtime system */
 526   public static void initialize(TypeDataBase db, boolean isBigEndian) {
 527     if (soleInstance != null) {
 528       throw new RuntimeException("Attempt to initialize VM twice");
 529     }
 530     soleInstance = new VM(db, null, isBigEndian);
 531     for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) {
 532       ((Observer) iter.next()).update(null, null);
 533     }
 534   }
 535 
 536   /** This is used by the debugging system */
 537   public static void initialize(TypeDataBase db, JVMDebugger debugger) {
 538     if (soleInstance != null) {
 539       // Using multiple SA Tool classes in the same process creates a call here.
 540       return;
 541     }
 542     soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian());
 543 
 544     for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) {
 545       ((Observer) iter.next()).update(null, null);
 546     }
 547 
 548     debugger.putHeapConst(soleInstance.getHeapOopSize(), soleInstance.getKlassPtrSize(),
 549                           CompressedOops.getBase(), CompressedOops.getShift(),
 550                           CompressedKlassPointers.getBase(), CompressedKlassPointers.getShift());
 551   }
 552 
 553   /** This is used by the debugging system */
 554   public static void shutdown() {
 555     soleInstance = null;
 556   }
 557 
 558   /** This is used by both the debugger and any runtime system. It is
 559       the basic mechanism by which classes which mimic underlying VM
 560       functionality cause themselves to be initialized. The given
 561       observer will be notified (with arguments (null, null)) when the
 562       VM is re-initialized, as well as when it registers itself with
 563       the VM. */
 564   public static void registerVMInitializedObserver(Observer o) {
 565     vmInitializedObservers.add(o);
 566     o.update(null, null);
 567   }
 568 
 569   /** This is the primary accessor used by both the debugger and any
 570       potential runtime system */
 571   public static VM getVM() {
 572     if (soleInstance == null) {
 573       throw new RuntimeException("VM.initialize() was not yet called");
 574     }
 575     return soleInstance;
 576   }
 577 
 578   /** This is only used by the debugging system. The given observer
 579       will be notified if the underlying VM resumes execution. NOTE
 580       that the given observer is not triggered if the VM is currently
 581       running and therefore differs in behavior from {@link
 582       #registerVMInitializedObserver} (because of the possibility of
 583       race conditions if the observer is added while the VM is being
 584       suspended or resumed).  */
 585   public void registerVMResumedObserver(Observer o) {
 586     vmResumedObservers.add(o);
 587   }
 588 
 589   /** This is only used by the debugging system. The given observer
 590       will be notified if the underlying VM suspends execution. NOTE
 591       that the given observer is not triggered if the VM is currently
 592       suspended and therefore differs in behavior from {@link
 593       #registerVMInitializedObserver} (because of the possibility of
 594       race conditions if the observer is added while the VM is being
 595       suspended or resumed).  */
 596   public void registerVMSuspendedObserver(Observer o) {
 597     vmSuspendedObservers.add(o);
 598   }
 599 
 600   /** This is only used by the debugging system. Informs all
 601       registered resumption observers that the VM has been resumed.
 602       The application is responsible for actually having performed the
 603       resumption. No OopHandles must be used after this point, as they
 604       may move in the target address space due to garbage
 605       collection. */
 606   public void fireVMResumed() {
 607     for (Iterator iter = vmResumedObservers.iterator(); iter.hasNext(); ) {
 608       ((Observer) iter.next()).update(null, null);
 609     }
 610   }
 611 
 612   /** This is only used by the debugging system. Informs all
 613       registered suspension observers that the VM has been suspended.
 614       The application is responsible for actually having performed the
 615       suspension. Garbage collection must be forbidden at this point;
 616       for example, a JPDA-level suspension is not adequate since the
 617       VM thread may still be running. */
 618   public void fireVMSuspended() {
 619     for (Iterator iter = vmSuspendedObservers.iterator(); iter.hasNext(); ) {
 620       ((Observer) iter.next()).update(null, null);
 621     }
 622   }
 623 
 624   /** Returns the OS this VM is running on. Notice that by delegating
 625       to the debugger we can transparently support remote
 626       debugging. */
 627   public String getOS() {
 628     if (debugger != null) {
 629       return debugger.getOS();
 630     }
 631     return PlatformInfo.getOS();
 632   }
 633 
 634   /** Returns the CPU this VM is running on. Notice that by delegating
 635       to the debugger we can transparently support remote
 636       debugging. */
 637   public String getCPU() {
 638     if (debugger != null) {
 639       return debugger.getCPU();
 640     }
 641     return PlatformInfo.getCPU();
 642   }
 643 
 644   public Type lookupType(String cTypeName) {
 645     return db.lookupType(cTypeName);
 646   }
 647 
 648   public Integer lookupIntConstant(String name) {
 649     return db.lookupIntConstant(name);
 650   }
 651 
 652   // Convenience function for conversions
 653   static public long getAddressValue(Address addr) {
 654     return VM.getVM().getDebugger().getAddressValue(addr);
 655   }
 656 
 657   public long getAddressSize() {
 658     return db.getAddressSize();
 659   }
 660 
 661   public long getOopSize() {
 662     return oopSize;
 663   }
 664 
 665   public long getLogAddressSize() {
 666     return logAddressSize;
 667   }
 668 
 669   public long getIntSize() {
 670     return db.getJIntType().getSize();
 671   }
 672 
 673   /** Indicates whether the underlying machine supports the LP64 data
 674       model. This is needed for conditionalizing code in a few places */
 675   public boolean isLP64() {
 676     if (Assert.ASSERTS_ENABLED) {
 677       Assert.that(isDebugging(), "Debugging system only for now");
 678     }
 679     return isLP64;
 680   }
 681 
 682   /** Get bytes-per-long == long/double natural alignment. */
 683   public int getBytesPerLong() {
 684     return bytesPerLong;
 685   }
 686 
 687   public int getBytesPerWord() {
 688     return bytesPerWord;
 689   }
 690 
 691   /** Get minimum object alignment in bytes. */
 692   public int getMinObjAlignmentInBytes() {
 693     return minObjAlignmentInBytes;
 694   }
 695   public int getLogMinObjAlignmentInBytes() {
 696     return logMinObjAlignmentInBytes;
 697   }
 698 
 699   public int getHeapWordSize() {
 700     return heapWordSize;
 701   }
 702 
 703   public int getHeapOopSize() {
 704     return heapOopSize;
 705   }
 706 
 707   public int getKlassPtrSize() {
 708     return klassPtrSize;
 709   }
 710   /** Utility routine for getting data structure alignment correct */
 711   public long alignUp(long size, long alignment) {
 712     return (size + alignment - 1) & ~(alignment - 1);
 713   }
 714 
 715   /** Utility routine for getting data structure alignment correct */
 716   public long alignDown(long size, long alignment) {
 717     return size & ~(alignment - 1);
 718   }
 719 
 720   /** Utility routine for building an int from two "unsigned" 16-bit
 721       shorts */
 722   public int buildIntFromShorts(short low, short high) {
 723     return (((int) high) << 16) | (((int) low) & 0xFFFF);
 724   }
 725 
 726   /** Utility routine for building a long from two "unsigned" 32-bit
 727       ints in <b>platform-dependent</b> order */
 728   public long buildLongFromIntsPD(int oneHalf, int otherHalf) {
 729     if (isBigEndian) {
 730       return (((long) otherHalf) << 32) | (((long) oneHalf) & 0x00000000FFFFFFFFL);
 731     } else{
 732       return (((long) oneHalf) << 32) | (((long) otherHalf) & 0x00000000FFFFFFFFL);
 733     }
 734   }
 735 
 736   public TypeDataBase getTypeDataBase() {
 737     return db;
 738   }
 739 
 740   public Universe    getUniverse() {
 741     if (universe == null) {
 742       universe = new Universe();
 743     }
 744     return universe;
 745   }
 746 
 747   public ObjectHeap  getObjectHeap() {
 748     if (heap == null) {
 749       heap = new ObjectHeap(db);
 750     }
 751     return heap;
 752   }
 753 
 754   public SystemDictionary getSystemDictionary() {
 755     if (dict == null) {
 756       dict = new SystemDictionary();
 757     }
 758     return dict;
 759   }
 760 
 761   public ClassLoaderDataGraph getClassLoaderDataGraph() {
 762     if (cldGraph == null) {
 763       cldGraph = new ClassLoaderDataGraph();
 764     }
 765     return cldGraph;
 766   }
 767 
 768   public Threads     getThreads() {
 769     if (threads == null) {
 770       threads = new Threads();
 771     }
 772     return threads;
 773   }
 774 
 775   public ObjectSynchronizer getObjectSynchronizer() {
 776     if (synchronizer == null) {
 777       synchronizer = new ObjectSynchronizer();
 778     }
 779     return synchronizer;
 780   }
 781 
 782   public JNIHandles getJNIHandles() {
 783     if (handles == null) {
 784       handles = new JNIHandles();
 785     }
 786     return handles;
 787   }
 788 
 789   public Interpreter getInterpreter() {
 790     if (interpreter == null) {
 791       interpreter = new Interpreter();
 792     }
 793     return interpreter;
 794   }
 795 
 796   public StubRoutines getStubRoutines() {
 797     if (stubRoutines == null) {
 798       stubRoutines = new StubRoutines();
 799     }
 800     return stubRoutines;
 801   }
 802 
 803   public VMRegImpl getVMRegImplInfo() {
 804     if (vmregImpl == null) {
 805       vmregImpl = new VMRegImpl();
 806     }
 807     return vmregImpl;
 808   }
 809 
 810   public FileMapInfo getFileMapInfo() {
 811     if (!isSharingEnabled()) {
 812       return null;
 813     }
 814     if (fileMapInfo == null) {
 815       fileMapInfo = new FileMapInfo();
 816     }
 817     return fileMapInfo;
 818   }
 819 
 820   public Bytes getBytes() {
 821     if (bytes == null) {
 822       bytes = new Bytes(debugger.getMachineDescription());
 823     }
 824     return bytes;
 825   }
 826 
 827   /** Returns true if this is a isBigEndian, false otherwise */
 828   public boolean isBigEndian() {
 829     return isBigEndian;
 830   }
 831 
 832   /** Returns true if JVMTI is supported, false otherwise */
 833   public boolean isJvmtiSupported() {
 834     return isJvmtiSupported;
 835   }
 836 
 837   /** Returns true if this is a "core" build, false if either C1 or C2
 838       is present */
 839   public boolean isCore() {
 840     return (!(usingClientCompiler || usingServerCompiler));
 841   }
 842 
 843   /** Returns true if this is a C1 build, false otherwise */
 844   public boolean isClientCompiler() {
 845     return usingClientCompiler;
 846   }
 847 
 848   /** Returns true if this is a C2 build, false otherwise */
 849   public boolean isServerCompiler() {
 850     return usingServerCompiler;
 851   }
 852 
 853   /** Returns true if C2 derived pointer table should be used, false otherwise */
 854   public boolean useDerivedPointerTable() {
 855     return !disableDerivedPointerTableCheck;
 856   }
 857 
 858   /** Returns the code cache; should not be used if is core build */
 859   public CodeCache getCodeCache() {
 860     if (Assert.ASSERTS_ENABLED) {
 861       Assert.that(!isCore(), "noncore builds only");
 862     }
 863     if (codeCache == null) {
 864       codeCache = new CodeCache();
 865     }
 866     return codeCache;
 867   }
 868 
 869   /** Should only be called for C1 builds */
 870   public Runtime1 getRuntime1() {
 871     if (Assert.ASSERTS_ENABLED) {
 872       Assert.that(isClientCompiler(), "C1 builds only");
 873     }
 874     if (runtime1 == null) {
 875       runtime1 = new Runtime1();
 876     }
 877     return runtime1;
 878   }
 879 
 880   /** Test to see whether we're in debugging mode (NOTE: this really
 881       should not be tested by this code; currently only used in
 882       StackFrameStream) */
 883   public boolean isDebugging() {
 884     return (debugger != null);
 885   }
 886 
 887   /** This is only used by the debugging (i.e., non-runtime) system */
 888   public JVMDebugger getDebugger() {
 889     if (debugger == null) {
 890       throw new RuntimeException("Attempt to use debugger in runtime system");
 891     }
 892     return debugger;
 893   }
 894 
 895   /** Indicates whether a given program counter is in Java code. This
 896       includes but is not spanned by the interpreter and code cache.
 897       Only used in the debugging system, for implementing
 898       JavaThread.currentFrameGuess() on x86. */
 899   public boolean isJavaPCDbg(Address addr) {
 900     // FIXME: this is not a complete enough set: must include areas
 901     // like vtable stubs
 902     return (getInterpreter().contains(addr) ||
 903             getCodeCache().contains(addr));
 904   }
 905 
 906   /** FIXME: figure out where to stick this */
 907   public int getInvocationEntryBCI() {
 908     return invocationEntryBCI;
 909   }
 910 
 911   // FIXME: figure out where to stick this
 912   public boolean wizardMode() {
 913     return true;
 914   }
 915 
 916   public ReversePtrs getRevPtrs() {
 917     return revPtrs;
 918   }
 919 
 920   public void setRevPtrs(ReversePtrs rp) {
 921     revPtrs = rp;
 922   }
 923 
 924   // returns null, if not available.
 925   public String getVMRelease() {
 926     return vmRelease;
 927   }
 928 
 929   // returns null, if not available.
 930   public String getVMInternalInfo() {
 931     return vmInternalInfo;
 932   }
 933 
 934   public int getReserveForAllocationPrefetch() {
 935     return reserveForAllocationPrefetch;
 936   }
 937 
 938   public boolean isSharingEnabled() {
 939     if (sharingEnabled == null) {
 940       Flag flag = getCommandLineFlag("UseSharedSpaces");
 941       sharingEnabled = (flag == null)? Boolean.FALSE :
 942           (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 943     }
 944     return sharingEnabled.booleanValue();
 945   }
 946 
 947   public boolean isCompressedOopsEnabled() {
 948     if (compressedOopsEnabled == null) {
 949         Flag flag = getCommandLineFlag("UseCompressedOops");
 950         compressedOopsEnabled = (flag == null) ? Boolean.FALSE:
 951              (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 952     }
 953     return compressedOopsEnabled.booleanValue();
 954   }
 955 
 956   public boolean isCompressedKlassPointersEnabled() {
 957     if (compressedKlassPointersEnabled == null) {
 958         Flag flag = getCommandLineFlag("UseCompressedClassPointers");
 959         compressedKlassPointersEnabled = (flag == null) ? Boolean.FALSE:
 960              (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 961     }
 962     return compressedKlassPointersEnabled.booleanValue();
 963   }
 964 
 965   public int getObjectAlignmentInBytes() {
 966     if (objectAlignmentInBytes == 0) {
 967         Flag flag = getCommandLineFlag("ObjectAlignmentInBytes");
 968         objectAlignmentInBytes = (flag == null) ? 8 : (int)flag.getIntx();
 969     }
 970     return objectAlignmentInBytes;
 971   }
 972 
 973   /** Indicates whether Thread-Local Allocation Buffers are used */
 974   public boolean getUseTLAB() {
 975       Flag flag = getCommandLineFlag("UseTLAB");
 976       return (flag == null) ? false: flag.getBool();
 977   }
 978 
 979   public boolean getCommandLineBooleanFlag(String name) {
 980     Flag flag = getCommandLineFlag(name);
 981     return (flag == null) ? Boolean.FALSE:
 982       (flag.getBool()? Boolean.TRUE: Boolean.FALSE);
 983   }
 984 
 985   // returns null, if not available.
 986   public Flag[] getCommandLineFlags() {
 987     if (commandLineFlags == null) {
 988        readCommandLineFlags();
 989     }
 990 
 991     return commandLineFlags;
 992   }
 993 
 994   public Flag getCommandLineFlag(String name) {
 995     if (flagsMap == null) {
 996       flagsMap = new HashMap<>();
 997       Flag[] flags = getCommandLineFlags();
 998       for (int i = 0; i < flags.length; i++) {
 999         flagsMap.put(flags[i].getName(), flags[i]);
1000       }
1001     }
1002     return (Flag) flagsMap.get(name);
1003   }
1004 
1005   private static final String cmdFlagTypes[] = {
1006     "bool",
1007     "int",
1008     "uint",
1009     "intx",
1010     "uintx",
1011     "uint64_t",
1012     "size_t",
1013     "double",
1014     "ccstr",
1015     "ccstrlist"
1016   };
1017 
1018   private String getFlagTypeAsString(int typeIndex) {
1019     if (0 <= typeIndex && typeIndex < cmdFlagTypes.length) {
1020       return cmdFlagTypes[typeIndex];
1021     } else {
1022       return "unknown";
1023     }
1024   }
1025 
1026   private void readCommandLineFlags() {
1027     // get command line flags
1028     TypeDataBase db = getTypeDataBase();
1029     Type flagType = db.lookupType("JVMFlag");
1030     int numFlags = (int) flagType.getCIntegerField("numFlags").getValue();
1031     // NOTE: last flag contains null values.
1032     commandLineFlags = new Flag[numFlags - 1];
1033 
1034     Address flagAddr = flagType.getAddressField("flags").getValue();
1035     CIntField typeFld = new CIntField(flagType.getCIntegerField("_type"), 0);
1036     AddressField nameFld = flagType.getAddressField("_name");
1037     AddressField addrFld = flagType.getAddressField("_addr");
1038     CIntField flagsFld = new CIntField(flagType.getCIntegerField("_flags"), 0);
1039 
1040     long flagSize = flagType.getSize(); // sizeof(Flag)
1041 
1042     // NOTE: last flag contains null values.
1043     for (int f = 0; f < numFlags - 1; f++) {
1044       int typeIndex = (int)typeFld.getValue(flagAddr);
1045       String type = getFlagTypeAsString(typeIndex);
1046       String name = CStringUtilities.getString(nameFld.getValue(flagAddr));
1047       Address addr = addrFld.getValue(flagAddr);
1048       int flags = (int)flagsFld.getValue(flagAddr);
1049       commandLineFlags[f] = new Flag(type, name, addr, flags);
1050       flagAddr = flagAddr.addOffsetTo(flagSize);
1051     }
1052 
1053     // sort flags by name
1054     Arrays.sort(commandLineFlags, new Comparator<>() {
1055         public int compare(Flag f1, Flag f2) {
1056           return f1.getName().compareTo(f2.getName());
1057         }
1058       });
1059   }
1060 
1061   public String getSystemProperty(String key) {
1062     Properties props = getSystemProperties();
1063     return (props != null)? props.getProperty(key) : null;
1064   }
1065 
1066   public Properties getSystemProperties() {
1067     if (sysProps == null) {
1068        readSystemProperties();
1069     }
1070     return sysProps;
1071   }
1072 
1073   private void readSystemProperties() {
1074     final InstanceKlass systemKls = getSystemDictionary().getSystemKlass();
1075     systemKls.iterateStaticFields(new DefaultOopVisitor() {
1076         ObjectReader objReader = new ObjectReader();
1077         public void doOop(sun.jvm.hotspot.oops.OopField field, boolean isVMField) {
1078           if (field.getID().getName().equals("props")) {
1079             try {
1080               sysProps = (Properties) objReader.readObject(field.getValue(getObj()));
1081             } catch (Exception e) {
1082               e.printStackTrace();
1083             }
1084           }
1085         }
1086       });
1087   }
1088 }