comparison agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java @ 0:a61af66fc99e jdk7-b24

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