0
|
1 /*
|
|
2 * Copyright 2001-2005 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.oops;
|
|
26
|
|
27 import java.io.*;
|
|
28 import java.util.*;
|
|
29
|
|
30 import sun.jvm.hotspot.debugger.*;
|
|
31 import sun.jvm.hotspot.runtime.*;
|
|
32 import sun.jvm.hotspot.types.*;
|
|
33 import sun.jvm.hotspot.utilities.*;
|
|
34
|
|
35 /** Mark is the analogue of the VM's markOop. In this system it does
|
|
36 not subclass Oop but VMObject. For a mark on the stack, the mark's
|
|
37 address will be an Address; for a mark in the header of an object,
|
|
38 it will be an OopHandle. It is assumed in a couple of places in
|
|
39 this code that the mark is the first word in an object. */
|
|
40
|
|
41 public class Mark extends VMObject {
|
|
42 static {
|
|
43 VM.registerVMInitializedObserver(new Observer() {
|
|
44 public void update(Observable o, Object data) {
|
|
45 initialize(VM.getVM().getTypeDataBase());
|
|
46 }
|
|
47 });
|
|
48 }
|
|
49
|
|
50 private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
|
51 Type type = db.lookupType("oopDesc");
|
|
52 markField = type.getCIntegerField("_mark");
|
|
53
|
|
54 ageBits = db.lookupLongConstant("markOopDesc::age_bits").longValue();
|
|
55 lockBits = db.lookupLongConstant("markOopDesc::lock_bits").longValue();
|
|
56 biasedLockBits = db.lookupLongConstant("markOopDesc::biased_lock_bits").longValue();
|
|
57 maxHashBits = db.lookupLongConstant("markOopDesc::max_hash_bits").longValue();
|
|
58 hashBits = db.lookupLongConstant("markOopDesc::hash_bits").longValue();
|
|
59 lockShift = db.lookupLongConstant("markOopDesc::lock_shift").longValue();
|
|
60 biasedLockShift = db.lookupLongConstant("markOopDesc::biased_lock_shift").longValue();
|
|
61 ageShift = db.lookupLongConstant("markOopDesc::age_shift").longValue();
|
|
62 hashShift = db.lookupLongConstant("markOopDesc::hash_shift").longValue();
|
|
63 lockMask = db.lookupLongConstant("markOopDesc::lock_mask").longValue();
|
|
64 lockMaskInPlace = db.lookupLongConstant("markOopDesc::lock_mask_in_place").longValue();
|
|
65 biasedLockMask = db.lookupLongConstant("markOopDesc::biased_lock_mask").longValue();
|
|
66 biasedLockMaskInPlace = db.lookupLongConstant("markOopDesc::biased_lock_mask_in_place").longValue();
|
|
67 biasedLockBitInPlace = db.lookupLongConstant("markOopDesc::biased_lock_bit_in_place").longValue();
|
|
68 ageMask = db.lookupLongConstant("markOopDesc::age_mask").longValue();
|
|
69 ageMaskInPlace = db.lookupLongConstant("markOopDesc::age_mask_in_place").longValue();
|
|
70 hashMask = db.lookupLongConstant("markOopDesc::hash_mask").longValue();
|
|
71 hashMaskInPlace = db.lookupLongConstant("markOopDesc::hash_mask_in_place").longValue();
|
|
72 biasedLockAlignment = db.lookupLongConstant("markOopDesc::biased_lock_alignment").longValue();
|
|
73 lockedValue = db.lookupLongConstant("markOopDesc::locked_value").longValue();
|
|
74 unlockedValue = db.lookupLongConstant("markOopDesc::unlocked_value").longValue();
|
|
75 monitorValue = db.lookupLongConstant("markOopDesc::monitor_value").longValue();
|
|
76 markedValue = db.lookupLongConstant("markOopDesc::marked_value").longValue();
|
|
77 biasedLockPattern = db.lookupLongConstant("markOopDesc::biased_lock_pattern").longValue();
|
|
78 noHash = db.lookupLongConstant("markOopDesc::no_hash").longValue();
|
|
79 noHashInPlace = db.lookupLongConstant("markOopDesc::no_hash_in_place").longValue();
|
|
80 noLockInPlace = db.lookupLongConstant("markOopDesc::no_lock_in_place").longValue();
|
|
81 maxAge = db.lookupLongConstant("markOopDesc::max_age").longValue();
|
187
|
82
|
|
83 /* Constants in markOop used by CMS. */
|
|
84 cmsShift = db.lookupLongConstant("markOopDesc::cms_shift").longValue();
|
|
85 cmsMask = db.lookupLongConstant("markOopDesc::cms_mask").longValue();
|
|
86 sizeShift = db.lookupLongConstant("markOopDesc::size_shift").longValue();
|
0
|
87 }
|
|
88
|
|
89 // Field accessors
|
|
90 private static CIntegerField markField;
|
|
91
|
|
92 // Constants -- read from VM
|
|
93 private static long ageBits;
|
|
94 private static long lockBits;
|
|
95 private static long biasedLockBits;
|
|
96 private static long maxHashBits;
|
|
97 private static long hashBits;
|
|
98
|
|
99 private static long lockShift;
|
|
100 private static long biasedLockShift;
|
|
101 private static long ageShift;
|
|
102 private static long hashShift;
|
|
103
|
|
104 private static long lockMask;
|
|
105 private static long lockMaskInPlace;
|
|
106 private static long biasedLockMask;
|
|
107 private static long biasedLockMaskInPlace;
|
|
108 private static long biasedLockBitInPlace;
|
|
109 private static long ageMask;
|
|
110 private static long ageMaskInPlace;
|
|
111 private static long hashMask;
|
|
112 private static long hashMaskInPlace;
|
|
113 private static long biasedLockAlignment;
|
|
114
|
|
115 private static long lockedValue;
|
|
116 private static long unlockedValue;
|
|
117 private static long monitorValue;
|
|
118 private static long markedValue;
|
|
119 private static long biasedLockPattern;
|
|
120
|
|
121 private static long noHash;
|
|
122
|
|
123 private static long noHashInPlace;
|
|
124 private static long noLockInPlace;
|
|
125
|
|
126 private static long maxAge;
|
|
127
|
187
|
128 /* Constants in markOop used by CMS. */
|
|
129 private static long cmsShift;
|
|
130 private static long cmsMask;
|
|
131 private static long sizeShift;
|
|
132
|
0
|
133 public Mark(Address addr) {
|
|
134 super(addr);
|
|
135 }
|
|
136
|
|
137 public long value() {
|
|
138 return markField.getValue(addr);
|
|
139 }
|
|
140
|
|
141 public Address valueAsAddress() {
|
|
142 return addr.getAddressAt(markField.getOffset());
|
|
143 }
|
|
144
|
|
145 // Biased locking accessors
|
|
146 // These must be checked by all code which calls into the
|
|
147 // ObjectSynchoronizer and other code. The biasing is not understood
|
|
148 // by the lower-level CAS-based locking code, although the runtime
|
|
149 // fixes up biased locks to be compatible with it when a bias is
|
|
150 // revoked.
|
|
151 public boolean hasBiasPattern() {
|
|
152 return (Bits.maskBitsLong(value(), biasedLockMaskInPlace) == biasedLockPattern);
|
|
153 }
|
|
154
|
|
155 public JavaThread biasedLocker() {
|
|
156 Threads threads = VM.getVM().getThreads();
|
|
157 Address addr = valueAsAddress().andWithMask(~(biasedLockMaskInPlace & ageMaskInPlace));
|
|
158 return threads.createJavaThreadWrapper(addr);
|
|
159 }
|
|
160
|
|
161 // Indicates that the mark gas the bias bit set but that it has not
|
|
162 // yet been biased toward a particular thread
|
|
163 public boolean isBiasedAnonymously() {
|
|
164 return hasBiasPattern() && (biasedLocker() == null);
|
|
165 }
|
|
166
|
|
167 // lock accessors (note that these assume lock_shift == 0)
|
|
168 public boolean isLocked() {
|
|
169 return (Bits.maskBitsLong(value(), lockMaskInPlace) != unlockedValue);
|
|
170 }
|
|
171 public boolean isUnlocked() {
|
|
172 return (Bits.maskBitsLong(value(), biasedLockMaskInPlace) == unlockedValue);
|
|
173 }
|
|
174 public boolean isMarked() {
|
|
175 return (Bits.maskBitsLong(value(), lockMaskInPlace) == markedValue);
|
|
176 }
|
|
177
|
|
178 // Special temporary state of the markOop while being inflated.
|
|
179 // Code that looks at mark outside a lock need to take this into account.
|
|
180 public boolean isBeingInflated() {
|
|
181 return (value() == 0);
|
|
182 }
|
|
183
|
|
184 // Should this header be preserved during GC?
|
|
185 public boolean mustBePreserved() {
|
|
186 return (!isUnlocked() || !hasNoHash());
|
|
187 }
|
|
188
|
|
189 // WARNING: The following routines are used EXCLUSIVELY by
|
|
190 // synchronization functions. They are not really gc safe.
|
|
191 // They must get updated if markOop layout get changed.
|
|
192
|
|
193 // FIXME
|
|
194 // markOop set_unlocked() const {
|
|
195 // return markOop(value() | unlocked_value);
|
|
196 // }
|
|
197 public boolean hasLocker() {
|
|
198 return ((value() & lockMaskInPlace) == lockedValue);
|
|
199 }
|
|
200 public BasicLock locker() {
|
|
201 if (Assert.ASSERTS_ENABLED) {
|
|
202 Assert.that(hasLocker(), "check");
|
|
203 }
|
|
204 return new BasicLock(valueAsAddress());
|
|
205 }
|
|
206 public boolean hasMonitor() {
|
|
207 return ((value() & monitorValue) != 0);
|
|
208 }
|
|
209 public ObjectMonitor monitor() {
|
|
210 if (Assert.ASSERTS_ENABLED) {
|
|
211 Assert.that(hasMonitor(), "check");
|
|
212 }
|
|
213 // Use xor instead of &~ to provide one extra tag-bit check.
|
|
214 Address monAddr = valueAsAddress().xorWithMask(monitorValue);
|
|
215 return new ObjectMonitor(monAddr);
|
|
216 }
|
|
217 public boolean hasDisplacedMarkHelper() {
|
|
218 return ((value() & unlockedValue) == 0);
|
|
219 }
|
|
220 public Mark displacedMarkHelper() {
|
|
221 if (Assert.ASSERTS_ENABLED) {
|
|
222 Assert.that(hasDisplacedMarkHelper(), "check");
|
|
223 }
|
|
224 Address addr = valueAsAddress().andWithMask(~monitorValue);
|
|
225 return new Mark(addr.getAddressAt(0));
|
|
226 }
|
|
227 // FIXME
|
|
228 // void set_displaced_mark_helper(markOop m) const {
|
|
229 // assert(has_displaced_mark_helper(), "check");
|
|
230 // intptr_t ptr = (value() & ~monitor_value);
|
|
231 // *(markOop*)ptr = m;
|
|
232 // }
|
|
233 // markOop copy_set_hash(intptr_t hash) const {
|
|
234 // intptr_t tmp = value() & (~hash_mask_in_place);
|
|
235 // tmp |= ((hash & hash_mask) << hash_shift);
|
|
236 // return (markOop)tmp;
|
|
237 // }
|
|
238 // it is only used to be stored into BasicLock as the
|
|
239 // indicator that the lock is using heavyweight monitor
|
|
240 // static markOop unused_mark() {
|
|
241 // return (markOop) marked_value;
|
|
242 // }
|
|
243 // // the following two functions create the markOop to be
|
|
244 // // stored into object header, it encodes monitor info
|
|
245 // static markOop encode(BasicLock* lock) {
|
|
246 // return (markOop) lock;
|
|
247 // }
|
|
248 // static markOop encode(ObjectMonitor* monitor) {
|
|
249 // intptr_t tmp = (intptr_t) monitor;
|
|
250 // return (markOop) (tmp | monitor_value);
|
|
251 // }
|
|
252 // used for alignment-based marking to reuse the busy state to encode pointers
|
|
253 // (see markOop_alignment.hpp)
|
|
254 // markOop clear_lock_bits() { return markOop(value() & ~lock_mask_in_place); }
|
|
255 //
|
|
256 // // age operations
|
|
257 // markOop set_marked() { return markOop((value() & ~lock_mask_in_place) | marked_value); }
|
|
258 //
|
|
259 public int age() { return (int) Bits.maskBitsLong(value() >> ageShift, ageMask); }
|
|
260 // markOop set_age(int v) const {
|
|
261 // assert((v & ~age_mask) == 0, "shouldn't overflow age field");
|
|
262 // return markOop((value() & ~age_mask_in_place) | (((intptr_t)v & age_mask) << age_shift));
|
|
263 // }
|
|
264 // markOop incr_age() const { return age() == max_age ? markOop(this) : set_age(age() + 1); }
|
|
265
|
|
266 // hash operations
|
|
267 public long hash() {
|
|
268 return Bits.maskBitsLong(value() >> hashShift, hashMask);
|
|
269 }
|
|
270
|
|
271 public boolean hasNoHash() {
|
|
272 return hash() == noHash;
|
|
273 }
|
|
274
|
|
275 // FIXME
|
|
276 // Prototype mark for initialization
|
|
277 // static markOop prototype() {
|
|
278 // return markOop( no_hash_in_place | no_lock_in_place );
|
|
279 // }
|
|
280
|
|
281 // Debugging
|
|
282 public void printOn(PrintStream tty) {
|
|
283 if (isLocked()) {
|
|
284 tty.print("locked(0x" +
|
|
285 Long.toHexString(value()) + ")->");
|
|
286 displacedMarkHelper().printOn(tty);
|
|
287 } else {
|
|
288 if (Assert.ASSERTS_ENABLED) {
|
|
289 Assert.that(isUnlocked(), "just checking");
|
|
290 }
|
|
291 tty.print("mark(");
|
|
292 tty.print("hash " + Long.toHexString(hash()) + ",");
|
|
293 tty.print("age " + age() + ")");
|
|
294 }
|
|
295 }
|
|
296
|
|
297 // FIXME
|
|
298 // // Prepare address of oop for placement into mark
|
|
299 // inline static markOop encode_pointer_as_mark(void* p) { return markOop(p)->set_marked(); }
|
|
300 //
|
|
301 // // Recover address of oop from encoded form used in mark
|
|
302 // inline void* decode_pointer() { return clear_lock_bits(); }
|
187
|
303
|
|
304 // Copy markOop methods for CMS here.
|
|
305 public boolean isCmsFreeChunk() {
|
|
306 return isUnlocked() &&
|
|
307 (Bits.maskBitsLong(value() >> cmsShift, cmsMask) & 0x1L) == 0x1L;
|
|
308 }
|
|
309 public long getSize() { return (long)(value() >> sizeShift); }
|
0
|
310 }
|