1 /* 2 * Copyright (c) 2000, 2011, 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 42 /** <P> This class encapsulates the global state of the VM; the 43 universe, object heap, interpreter, etc. It is a Singleton and 44 must be initialized with a call to initialize() before calling 45 getVM(). </P> 46 47 <P> Many auxiliary classes (i.e., most of the VMObjects) keep 48 needed field offsets in the form of static Field objects. In a 49 debugging system, the VM might be shutdown and re-initialized (on 50 a differently-configured build, i.e., 32- vs. 64-bit), and all old 51 cached state (including fields and field offsets) must be 52 flushed. </P> 53 54 <P> An Observer pattern is used to implement the initialization of 55 such classes. Each such class, in its static initializer, 56 registers an Observer with the VM class via 57 VM.registerVMInitializedObserver(). This Observer is guaranteed to 58 be notified whenever the VM is initialized (or re-initialized). To 59 implement the first-time initialization, the observer is also 60 notified when it registers itself with the VM. (For bootstrapping 61 reasons, this implies that the constructor of VM can not 62 instantiate any such objects, since VM.soleInstance will not have 63 been set yet. This is a bootstrapping issue which may have to be 64 revisited later.) </P> 65 */ 66 67 public class VM { 68 private static VM soleInstance; 69 private static List vmInitializedObservers = new ArrayList(); 70 private List vmResumedObservers = new ArrayList(); 71 private List vmSuspendedObservers = new ArrayList(); 72 private TypeDataBase db; 73 private boolean isBigEndian; 74 /** This is only present if in a debugging system */ 75 private JVMDebugger debugger; 76 private long stackBias; 77 private long logAddressSize; 78 private Universe universe; 79 private ObjectHeap heap; 80 private SymbolTable symbols; 81 private StringTable strings; 82 private SystemDictionary dict; 83 private Threads threads; 84 private ObjectSynchronizer synchronizer; 85 private JNIHandles handles; 86 private Interpreter interpreter; 87 private StubRoutines stubRoutines; 88 private Bytes bytes; 89 90 /** Flags indicating whether we are attached to a core, C1, or C2 build */ 91 private boolean usingClientCompiler; 92 private boolean usingServerCompiler; 93 /** Flag indicating whether UseTLAB is turned on */ 94 private boolean useTLAB; 95 /** alignment constants */ 96 private boolean isLP64; 97 private int bytesPerLong; 98 private int objectAlignmentInBytes; 99 private int minObjAlignmentInBytes; 100 private int logMinObjAlignmentInBytes; 101 private int heapWordSize; 102 private int heapOopSize; 103 private int oopSize; 104 /** This is only present in a non-core build */ 105 private CodeCache codeCache; 106 /** This is only present in a C1 build */ 107 private Runtime1 runtime1; 108 /** These constants come from globalDefinitions.hpp */ 109 private int invocationEntryBCI; 110 private int invalidOSREntryBCI; 111 private ReversePtrs revPtrs; 112 private VMRegImpl vmregImpl; 113 114 // System.getProperties from debuggee VM 115 private Properties sysProps; 116 117 // VM version strings come from Abstract_VM_Version class 118 private String vmRelease; 119 private String vmInternalInfo; 120 121 private Flag[] commandLineFlags; 122 private Map flagsMap; 123 124 private static Type intxType; 125 private static Type uintxType; 126 private static CIntegerType boolType; 127 private Boolean sharingEnabled; 128 private Boolean compressedOopsEnabled; 129 130 // command line flags supplied to VM - see struct Flag in globals.hpp 131 public static final class Flag { 132 private String type; 133 private String name; 134 private Address addr; 135 private String kind; 136 private int origin; 137 138 private Flag(String type, String name, Address addr, String kind, int origin) { 139 this.type = type; 140 this.name = name; 141 this.addr = addr; 142 this.kind = kind; 143 this.origin = origin; 144 } 145 146 public String getType() { 147 return type; 148 } 149 150 public String getName() { 151 return name; 152 } 153 154 public Address getAddress() { 155 return addr; 156 } 157 158 public String getKind() { 159 return kind; 160 } 161 162 public int getOrigin() { 163 return origin; 164 } 165 166 public boolean isBool() { 167 return type.equals("bool"); 168 } 169 170 public boolean getBool() { 171 if (Assert.ASSERTS_ENABLED) { 172 Assert.that(isBool(), "not a bool flag!"); 173 } 174 return addr.getCIntegerAt(0, boolType.getSize(), boolType.isUnsigned()) 175 != 0; 176 } 177 178 public boolean isIntx() { 179 return type.equals("intx"); 180 } 181 182 public long getIntx() { 183 if (Assert.ASSERTS_ENABLED) { 184 Assert.that(isIntx(), "not a intx flag!"); 185 } 186 return addr.getCIntegerAt(0, intxType.getSize(), false); 187 } 188 189 public boolean isUIntx() { 190 return type.equals("uintx"); 191 } 192 193 public long getUIntx() { 194 if (Assert.ASSERTS_ENABLED) { 195 Assert.that(isUIntx(), "not a uintx flag!"); 196 } 197 return addr.getCIntegerAt(0, uintxType.getSize(), true); 198 } 199 200 public String getValue() { 201 if (isBool()) { 202 return new Boolean(getBool()).toString(); 203 } else if (isIntx()) { 204 return new Long(getIntx()).toString(); 205 } else if (isUIntx()) { 206 return new Long(getUIntx()).toString(); 207 } else { 208 return null; 209 } 210 } 211 }; 212 213 private static void checkVMVersion(String vmRelease) { 214 if (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null) { 215 // read sa build version. 216 String versionProp = "sun.jvm.hotspot.runtime.VM.saBuildVersion"; 217 String saVersion = saProps.getProperty(versionProp); 218 if (saVersion == null) 219 throw new RuntimeException("Missing property " + versionProp); 220 221 // Strip nonproduct VM version substring (note: saVersion doesn't have it). 222 String vmVersion = vmRelease.replaceAll("(-fastdebug)|(-debug)|(-jvmg)|(-optimized)|(-profiled)",""); 223 224 if (saVersion.equals(vmVersion)) { 225 // Exact match 226 return; 227 } 228 if (saVersion.indexOf('-') == saVersion.lastIndexOf('-') && 229 vmVersion.indexOf('-') == vmVersion.lastIndexOf('-')) { 230 // Throw exception if different release versions: 231 // <major>.<minor>-b<n> 232 throw new VMVersionMismatchException(saVersion, vmRelease); 233 } else { 234 // Otherwise print warning to allow mismatch not release versions 235 // during development. 236 System.err.println("WARNING: Hotspot VM version " + vmRelease + 237 " does not match with SA version " + saVersion + 238 "." + " You may see unexpected results. "); 239 } 240 } else { 241 System.err.println("WARNING: You have disabled SA and VM version check. You may be " + 242 "using incompatible version of SA and you may see unexpected " + 243 "results."); 244 } 245 } 246 247 private static final boolean disableDerivedPrinterTableCheck; 248 private static final Properties saProps; 249 250 static { 251 saProps = new Properties(); 252 URL url = null; 253 try { 254 url = VM.class.getClassLoader().getResource("sa.properties"); 255 saProps.load(new BufferedInputStream(url.openStream())); 256 } catch (Exception e) { 257 throw new RuntimeException("Unable to load properties " + 258 (url == null ? "null" : url.toString()) + 259 ": " + e.getMessage()); 260 } 261 262 disableDerivedPrinterTableCheck = System.getProperty("sun.jvm.hotspot.runtime.VM.disableDerivedPointerTableCheck") != null; 263 } 264 265 private VM(TypeDataBase db, JVMDebugger debugger, boolean isBigEndian) { 266 this.db = db; 267 this.debugger = debugger; 268 this.isBigEndian = isBigEndian; 269 270 // Note that we don't construct universe, heap, threads, 271 // interpreter, or stubRoutines here (any more). The current 272 // initialization mechanisms require that the VM be completely set 273 // up (i.e., out of its constructor, with soleInstance assigned) 274 // before their static initializers are run. 275 276 if (db.getAddressSize() == 4) { 277 logAddressSize = 2; 278 } else if (db.getAddressSize() == 8) { 279 logAddressSize = 3; 280 } else { 281 throw new RuntimeException("Address size " + db.getAddressSize() + " not yet supported"); 282 } 283 284 // read VM version info 285 try { 286 Type vmVersion = db.lookupType("Abstract_VM_Version"); 287 Address releaseAddr = vmVersion.getAddressField("_s_vm_release").getValue(); 288 vmRelease = CStringUtilities.getString(releaseAddr); 289 Address vmInternalInfoAddr = vmVersion.getAddressField("_s_internal_vm_info_string").getValue(); 290 vmInternalInfo = CStringUtilities.getString(vmInternalInfoAddr); 291 } catch (Exception exp) { 292 throw new RuntimeException("can't determine target's VM version : " + exp.getMessage()); 293 } 294 295 checkVMVersion(vmRelease); 296 297 stackBias = db.lookupIntConstant("STACK_BIAS").intValue(); 298 invocationEntryBCI = db.lookupIntConstant("InvocationEntryBci").intValue(); 299 invalidOSREntryBCI = db.lookupIntConstant("InvalidOSREntryBci").intValue(); 300 301 // We infer the presence of C1 or C2 from a couple of fields we 302 // already have present in the type database 303 { 304 Type type = db.lookupType("methodOopDesc"); 305 if (type.getField("_from_compiled_entry", false, false) == null) { 306 // Neither C1 nor C2 is present 307 usingClientCompiler = false; 308 usingServerCompiler = false; 309 } else { 310 // Determine whether C2 is present 311 if (db.lookupType("Matcher", false) != null) { 312 usingServerCompiler = true; 313 } else { 314 usingClientCompiler = true; 315 } 316 } 317 } 318 319 useTLAB = (db.lookupIntConstant("UseTLAB").intValue() != 0); 320 321 if (debugger != null) { 322 isLP64 = debugger.getMachineDescription().isLP64(); 323 } 324 bytesPerLong = db.lookupIntConstant("BytesPerLong").intValue(); 325 heapWordSize = db.lookupIntConstant("HeapWordSize").intValue(); 326 oopSize = db.lookupIntConstant("oopSize").intValue(); 327 328 intxType = db.lookupType("intx"); 329 uintxType = db.lookupType("uintx"); 330 boolType = (CIntegerType) db.lookupType("bool"); 331 332 minObjAlignmentInBytes = getObjectAlignmentInBytes(); 333 if (minObjAlignmentInBytes == 8) { 334 logMinObjAlignmentInBytes = 3; 335 } else if (minObjAlignmentInBytes == 16) { 336 logMinObjAlignmentInBytes = 4; 337 } else { 338 throw new RuntimeException("Object alignment " + minObjAlignmentInBytes + " not yet supported"); 339 } 340 341 if (isCompressedOopsEnabled()) { 342 // Size info for oops within java objects is fixed 343 heapOopSize = (int)getIntSize(); 344 } else { 345 heapOopSize = (int)getOopSize(); 346 } 347 } 348 349 /** This could be used by a reflective runtime system */ 350 public static void initialize(TypeDataBase db, boolean isBigEndian) { 351 if (soleInstance != null) { 352 throw new RuntimeException("Attempt to initialize VM twice"); 353 } 354 soleInstance = new VM(db, null, isBigEndian); 355 for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) { 356 ((Observer) iter.next()).update(null, null); 357 } 358 } 359 360 /** This is used by the debugging system */ 361 public static void initialize(TypeDataBase db, JVMDebugger debugger) { 362 if (soleInstance != null) { 363 throw new RuntimeException("Attempt to initialize VM twice"); 364 } 365 soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian()); 366 367 for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) { 368 ((Observer) iter.next()).update(null, null); 369 } 370 371 debugger.putHeapConst(soleInstance.getHeapOopSize(), Universe.getNarrowOopBase(), 372 Universe.getNarrowOopShift()); 373 } 374 375 /** This is used by the debugging system */ 376 public static void shutdown() { 377 soleInstance = null; 378 } 379 380 /** This is used by both the debugger and any runtime system. It is 381 the basic mechanism by which classes which mimic underlying VM 382 functionality cause themselves to be initialized. The given 383 observer will be notified (with arguments (null, null)) when the 384 VM is re-initialized, as well as when it registers itself with 385 the VM. */ 386 public static void registerVMInitializedObserver(Observer o) { 387 vmInitializedObservers.add(o); 388 o.update(null, null); 389 } 390 391 /** This is the primary accessor used by both the debugger and any 392 potential runtime system */ 393 public static VM getVM() { 394 if (soleInstance == null) { 395 throw new RuntimeException("VM.initialize() was not yet called"); 396 } 397 return soleInstance; 398 } 399 400 /** This is only used by the debugging system. The given observer 401 will be notified if the underlying VM resumes execution. NOTE 402 that the given observer is not triggered if the VM is currently 403 running and therefore differs in behavior from {@link 404 #registerVMInitializedObserver} (because of the possibility of 405 race conditions if the observer is added while the VM is being 406 suspended or resumed). */ 407 public void registerVMResumedObserver(Observer o) { 408 vmResumedObservers.add(o); 409 } 410 411 /** This is only used by the debugging system. The given observer 412 will be notified if the underlying VM suspends execution. NOTE 413 that the given observer is not triggered if the VM is currently 414 suspended and therefore differs in behavior from {@link 415 #registerVMInitializedObserver} (because of the possibility of 416 race conditions if the observer is added while the VM is being 417 suspended or resumed). */ 418 public void registerVMSuspendedObserver(Observer o) { 419 vmSuspendedObservers.add(o); 420 } 421 422 /** This is only used by the debugging system. Informs all 423 registered resumption observers that the VM has been resumed. 424 The application is responsible for actually having performed the 425 resumption. No OopHandles must be used after this point, as they 426 may move in the target address space due to garbage 427 collection. */ 428 public void fireVMResumed() { 429 for (Iterator iter = vmResumedObservers.iterator(); iter.hasNext(); ) { 430 ((Observer) iter.next()).update(null, null); 431 } 432 } 433 434 /** This is only used by the debugging system. Informs all 435 registered suspension observers that the VM has been suspended. 436 The application is responsible for actually having performed the 437 suspension. Garbage collection must be forbidden at this point; 438 for example, a JPDA-level suspension is not adequate since the 439 VM thread may still be running. */ 440 public void fireVMSuspended() { 441 for (Iterator iter = vmSuspendedObservers.iterator(); iter.hasNext(); ) { 442 ((Observer) iter.next()).update(null, null); 443 } 444 } 445 446 /** Returns the OS this VM is running on. Notice that by delegating 447 to the debugger we can transparently support remote 448 debugging. */ 449 public String getOS() { 450 if (debugger != null) { 451 return debugger.getOS(); 452 } 453 return PlatformInfo.getOS(); 454 } 455 456 /** Returns the CPU this VM is running on. Notice that by delegating 457 to the debugger we can transparently support remote 458 debugging. */ 459 public String getCPU() { 460 if (debugger != null) { 461 return debugger.getCPU(); 462 } 463 return PlatformInfo.getCPU(); 464 } 465 466 public Type lookupType(String cTypeName) { 467 return db.lookupType(cTypeName); 468 } 469 470 public Integer lookupIntConstant(String name) { 471 return db.lookupIntConstant(name); 472 } 473 474 public long getAddressSize() { 475 return db.getAddressSize(); 476 } 477 478 public long getOopSize() { 479 return oopSize; 480 } 481 482 public long getLogAddressSize() { 483 return logAddressSize; 484 } 485 486 public long getIntSize() { 487 return db.getJIntType().getSize(); 488 } 489 490 /** NOTE: this offset is in BYTES in this system! */ 491 public long getStackBias() { 492 return stackBias; 493 } 494 495 /** Indicates whether the underlying machine supports the LP64 data 496 model. This is needed for conditionalizing code in a few places */ 497 public boolean isLP64() { 498 if (Assert.ASSERTS_ENABLED) { 499 Assert.that(isDebugging(), "Debugging system only for now"); 500 } 501 return isLP64; 502 } 503 504 /** Get bytes-per-long == long/double natural alignment. */ 505 public int getBytesPerLong() { 506 return bytesPerLong; 507 } 508 509 /** Get minimum object alignment in bytes. */ 510 public int getMinObjAlignmentInBytes() { 511 return minObjAlignmentInBytes; 512 } 513 public int getLogMinObjAlignmentInBytes() { 514 return logMinObjAlignmentInBytes; 515 } 516 517 public int getHeapWordSize() { 518 return heapWordSize; 519 } 520 521 public int getHeapOopSize() { 522 return heapOopSize; 523 } 524 /** Utility routine for getting data structure alignment correct */ 525 public long alignUp(long size, long alignment) { 526 return (size + alignment - 1) & ~(alignment - 1); 527 } 528 529 /** Utility routine for getting data structure alignment correct */ 530 public long alignDown(long size, long alignment) { 531 return size & ~(alignment - 1); 532 } 533 534 /** Utility routine for building an int from two "unsigned" 16-bit 535 shorts */ 536 public int buildIntFromShorts(short low, short high) { 537 return (((int) high) << 16) | (((int) low) & 0xFFFF); 538 } 539 540 /** Utility routine for building a long from two "unsigned" 32-bit 541 ints in <b>platform-dependent</b> order */ 542 public long buildLongFromIntsPD(int oneHalf, int otherHalf) { 543 if (isBigEndian) { 544 return (((long) otherHalf) << 32) | (((long) oneHalf) & 0x00000000FFFFFFFFL); 545 } else{ 546 return (((long) oneHalf) << 32) | (((long) otherHalf) & 0x00000000FFFFFFFFL); 547 } 548 } 549 550 /** Indicates whether Thread-Local Allocation Buffers are used */ 551 public boolean getUseTLAB() { 552 return useTLAB; 553 } 554 555 public TypeDataBase getTypeDataBase() { 556 return db; 557 } 558 559 public Universe getUniverse() { 560 if (universe == null) { 561 universe = new Universe(); 562 } 563 return universe; 564 } 565 566 public ObjectHeap getObjectHeap() { 567 if (heap == null) { 568 heap = new ObjectHeap(db); 569 } 570 return heap; 571 } 572 573 public SymbolTable getSymbolTable() { 574 if (symbols == null) { 575 symbols = SymbolTable.getTheTable(); 576 } 577 return symbols; 578 } 579 580 public StringTable getStringTable() { 581 if (strings == null) { 582 strings = StringTable.getTheTable(); 583 } 584 return strings; 585 } 586 587 public SystemDictionary getSystemDictionary() { 588 if (dict == null) { 589 dict = new SystemDictionary(); 590 } 591 return dict; 592 } 593 594 public Threads getThreads() { 595 if (threads == null) { 596 threads = new Threads(); 597 } 598 return threads; 599 } 600 601 public ObjectSynchronizer getObjectSynchronizer() { 602 if (synchronizer == null) { 603 synchronizer = new ObjectSynchronizer(); 604 } 605 return synchronizer; 606 } 607 608 public JNIHandles getJNIHandles() { 609 if (handles == null) { 610 handles = new JNIHandles(); 611 } 612 return handles; 613 } 614 615 public Interpreter getInterpreter() { 616 if (interpreter == null) { 617 interpreter = new Interpreter(); 618 } 619 return interpreter; 620 } 621 622 public StubRoutines getStubRoutines() { 623 if (stubRoutines == null) { 624 stubRoutines = new StubRoutines(); 625 } 626 return stubRoutines; 627 } 628 629 public VMRegImpl getVMRegImplInfo() { 630 if (vmregImpl == null) { 631 vmregImpl = new VMRegImpl(); 632 } 633 return vmregImpl; 634 } 635 636 public Bytes getBytes() { 637 if (bytes == null) { 638 bytes = new Bytes(debugger.getMachineDescription()); 639 } 640 return bytes; 641 } 642 643 /** Returns true if this is a isBigEndian, false otherwise */ 644 public boolean isBigEndian() { 645 return isBigEndian; 646 } 647 648 /** Returns true if this is a "core" build, false if either C1 or C2 649 is present */ 650 public boolean isCore() { 651 return (!(usingClientCompiler || usingServerCompiler)); 652 } 653 654 /** Returns true if this is a C1 build, false otherwise */ 655 public boolean isClientCompiler() { 656 return usingClientCompiler; 657 } 658 659 /** Returns true if this is a C2 build, false otherwise */ 660 public boolean isServerCompiler() { 661 return usingServerCompiler; 662 } 663 664 /** Returns true if C2 derived pointer table should be used, false otherwise */ 665 public boolean useDerivedPointerTable() { 666 return !disableDerivedPrinterTableCheck; 667 } 668 669 /** Returns the code cache; should not be used if is core build */ 670 public CodeCache getCodeCache() { 671 if (Assert.ASSERTS_ENABLED) { 672 Assert.that(!isCore(), "noncore builds only"); 673 } 674 if (codeCache == null) { 675 codeCache = new CodeCache(); 676 } 677 return codeCache; 678 } 679 680 /** Should only be called for C1 builds */ 681 public Runtime1 getRuntime1() { 682 if (Assert.ASSERTS_ENABLED) { 683 Assert.that(isClientCompiler(), "C1 builds only"); 684 } 685 if (runtime1 == null) { 686 runtime1 = new Runtime1(); 687 } 688 return runtime1; 689 } 690 691 /** Test to see whether we're in debugging mode (NOTE: this really 692 should not be tested by this code; currently only used in 693 StackFrameStream) */ 694 public boolean isDebugging() { 695 return (debugger != null); 696 } 697 698 /** This is only used by the debugging (i.e., non-runtime) system */ 699 public JVMDebugger getDebugger() { 700 if (debugger == null) { 701 throw new RuntimeException("Attempt to use debugger in runtime system"); 702 } 703 return debugger; 704 } 705 706 /** Indicates whether a given program counter is in Java code. This 707 includes but is not spanned by the interpreter and code cache. 708 Only used in the debugging system, for implementing 709 JavaThread.currentFrameGuess() on x86. */ 710 public boolean isJavaPCDbg(Address addr) { 711 // FIXME: this is not a complete enough set: must include areas 712 // like vtable stubs 713 return (getInterpreter().contains(addr) || 714 getCodeCache().contains(addr)); 715 } 716 717 /** FIXME: figure out where to stick this */ 718 public int getInvocationEntryBCI() { 719 return invocationEntryBCI; 720 } 721 722 /** FIXME: figure out where to stick this */ 723 public int getInvalidOSREntryBCI() { 724 return invalidOSREntryBCI; 725 } 726 727 // FIXME: figure out where to stick this 728 public boolean wizardMode() { 729 return true; 730 } 731 732 public ReversePtrs getRevPtrs() { 733 return revPtrs; 734 } 735 736 public void setRevPtrs(ReversePtrs rp) { 737 revPtrs = rp; 738 } 739 740 // returns null, if not available. 741 public String getVMRelease() { 742 return vmRelease; 743 } 744 745 // returns null, if not available. 746 public String getVMInternalInfo() { 747 return vmInternalInfo; 748 } 749 750 public boolean isSharingEnabled() { 751 if (sharingEnabled == null) { 752 Flag flag = getCommandLineFlag("UseSharedSpaces"); 753 sharingEnabled = (flag == null)? Boolean.FALSE : 754 (flag.getBool()? Boolean.TRUE: Boolean.FALSE); 755 } 756 return sharingEnabled.booleanValue(); 757 } 758 759 public boolean isCompressedOopsEnabled() { 760 if (compressedOopsEnabled == null) { 761 Flag flag = getCommandLineFlag("UseCompressedOops"); 762 compressedOopsEnabled = (flag == null) ? Boolean.FALSE: 763 (flag.getBool()? Boolean.TRUE: Boolean.FALSE); 764 } 765 return compressedOopsEnabled.booleanValue(); 766 } 767 768 public int getObjectAlignmentInBytes() { 769 if (objectAlignmentInBytes == 0) { 770 Flag flag = getCommandLineFlag("ObjectAlignmentInBytes"); 771 objectAlignmentInBytes = (flag == null) ? 8 : (int)flag.getIntx(); 772 } 773 return objectAlignmentInBytes; 774 } 775 776 // returns null, if not available. 777 public Flag[] getCommandLineFlags() { 778 if (commandLineFlags == null) { 779 readCommandLineFlags(); 780 } 781 782 return commandLineFlags; 783 } 784 785 public Flag getCommandLineFlag(String name) { 786 if (flagsMap == null) { 787 flagsMap = new HashMap(); 788 Flag[] flags = getCommandLineFlags(); 789 for (int i = 0; i < flags.length; i++) { 790 flagsMap.put(flags[i].getName(), flags[i]); 791 } 792 } 793 return (Flag) flagsMap.get(name); 794 } 795 796 private void readCommandLineFlags() { 797 // get command line flags 798 TypeDataBase db = getTypeDataBase(); 799 Type flagType = db.lookupType("Flag"); 800 int numFlags = (int) flagType.getCIntegerField("numFlags").getValue(); 801 // NOTE: last flag contains null values. 802 commandLineFlags = new Flag[numFlags - 1]; 803 804 Address flagAddr = flagType.getAddressField("flags").getValue(); 805 806 AddressField typeFld = flagType.getAddressField("type"); 807 AddressField nameFld = flagType.getAddressField("name"); 808 AddressField addrFld = flagType.getAddressField("addr"); 809 AddressField kindFld = flagType.getAddressField("kind"); 810 CIntField originFld = new CIntField(flagType.getCIntegerField("origin"), 0); 811 812 long flagSize = flagType.getSize(); // sizeof(Flag) 813 814 // NOTE: last flag contains null values. 815 for (int f = 0; f < numFlags - 1; f++) { 816 String type = CStringUtilities.getString(typeFld.getValue(flagAddr)); 817 String name = CStringUtilities.getString(nameFld.getValue(flagAddr)); 818 Address addr = addrFld.getValue(flagAddr); 819 String kind = CStringUtilities.getString(kindFld.getValue(flagAddr)); 820 int origin = (int)originFld.getValue(flagAddr); 821 commandLineFlags[f] = new Flag(type, name, addr, kind, origin); 822 flagAddr = flagAddr.addOffsetTo(flagSize); 823 } 824 825 // sort flags by name 826 Arrays.sort(commandLineFlags, new Comparator() { 827 public int compare(Object o1, Object o2) { 828 Flag f1 = (Flag) o1; 829 Flag f2 = (Flag) o2; 830 return f1.getName().compareTo(f2.getName()); 831 } 832 }); 833 } 834 835 public String getSystemProperty(String key) { 836 Properties props = getSystemProperties(); 837 return (props != null)? props.getProperty(key) : null; 838 } 839 840 public Properties getSystemProperties() { 841 if (sysProps == null) { 842 readSystemProperties(); 843 } 844 return sysProps; 845 } 846 847 private void readSystemProperties() { 848 final InstanceKlass systemKls = getSystemDictionary().getSystemKlass(); 849 systemKls.iterateStaticFields(new DefaultOopVisitor() { 850 ObjectReader objReader = new ObjectReader(); 851 public void doOop(sun.jvm.hotspot.oops.OopField field, boolean isVMField) { 852 if (field.getID().getName().equals("props")) { 853 try { 854 sysProps = (Properties) objReader.readObject(field.getValue(getObj())); 855 } catch (Exception e) { 856 e.printStackTrace(); 857 } 858 } 859 } 860 }); 861 } 862 }