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