1 /*
2 * Copyright (c) 2001, 2020, 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.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 import sun.jvm.hotspot.utilities.Observable;
35 import sun.jvm.hotspot.utilities.Observer;
36
37 public class Mark extends VMObject {
38 static {
39 VM.registerVMInitializedObserver(new Observer() {
40 public void update(Observable o, Object data) {
41 initialize(VM.getVM().getTypeDataBase());
42 }
43 });
44 }
45
46 private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
47 Type type = db.lookupType("oopDesc");
48 markField = type.getCIntegerField("_mark");
49
50 ageBits = db.lookupLongConstant("markWord::age_bits").longValue();
51 lockBits = db.lookupLongConstant("markWord::lock_bits").longValue();
52 biasedLockBits = db.lookupLongConstant("markWord::biased_lock_bits").longValue();
53 maxHashBits = db.lookupLongConstant("markWord::max_hash_bits").longValue();
54 hashBits = db.lookupLongConstant("markWord::hash_bits").longValue();
55 hashBitsCompact = db.lookupLongConstant("markWord::hash_bits_compact").longValue();
56 lockShift = db.lookupLongConstant("markWord::lock_shift").longValue();
57 biasedLockShift = db.lookupLongConstant("markWord::biased_lock_shift").longValue();
58 ageShift = db.lookupLongConstant("markWord::age_shift").longValue();
59 hashShift = db.lookupLongConstant("markWord::hash_shift").longValue();
60 hashShiftCompact = db.lookupLongConstant("markWord::hash_shift_compact").longValue();
61 if (VM.getVM().isLP64()) {
62 klassShift = db.lookupLongConstant("markWord::klass_shift").longValue();
63 }
64 lockMask = db.lookupLongConstant("markWord::lock_mask").longValue();
65 lockMaskInPlace = db.lookupLongConstant("markWord::lock_mask_in_place").longValue();
66 biasedLockMask = db.lookupLongConstant("markWord::biased_lock_mask").longValue();
67 biasedLockMaskInPlace = db.lookupLongConstant("markWord::biased_lock_mask_in_place").longValue();
68 biasedLockBitInPlace = db.lookupLongConstant("markWord::biased_lock_bit_in_place").longValue();
69 ageMask = db.lookupLongConstant("markWord::age_mask").longValue();
70 ageMaskInPlace = db.lookupLongConstant("markWord::age_mask_in_place").longValue();
71 hashMask = db.lookupLongConstant("markWord::hash_mask").longValue();
72 hashMaskInPlace = db.lookupLongConstant("markWord::hash_mask_in_place").longValue();
73 hashMaskCompact = db.lookupLongConstant("markWord::hash_mask_compact").longValue();
74 hashMaskCompactInPlace = db.lookupLongConstant("markWord::hash_mask_compact_in_place").longValue();
75 biasedLockAlignment = db.lookupLongConstant("markWord::biased_lock_alignment").longValue();
76 lockedValue = db.lookupLongConstant("markWord::locked_value").longValue();
77 unlockedValue = db.lookupLongConstant("markWord::unlocked_value").longValue();
78 monitorValue = db.lookupLongConstant("markWord::monitor_value").longValue();
79 markedValue = db.lookupLongConstant("markWord::marked_value").longValue();
80 biasedLockPattern = db.lookupLongConstant("markWord::biased_lock_pattern").longValue();
81 noHash = db.lookupLongConstant("markWord::no_hash").longValue();
82 noHashInPlace = db.lookupLongConstant("markWord::no_hash_in_place").longValue();
83 noLockInPlace = db.lookupLongConstant("markWord::no_lock_in_place").longValue();
84 maxAge = db.lookupLongConstant("markWord::max_age").longValue();
85 }
86
87 // Field accessors
88 private static CIntegerField markField;
89
90 // Constants -- read from VM
91 private static long ageBits;
92 private static long lockBits;
93 private static long biasedLockBits;
94 private static long maxHashBits;
95 private static long hashBits;
96 private static long hashBitsCompact;
97
98 private static long lockShift;
99 private static long biasedLockShift;
100 private static long ageShift;
101 private static long hashShift;
102 private static long hashShiftCompact;
103 private static long klassShift;
104
105 private static long lockMask;
106 private static long lockMaskInPlace;
107 private static long biasedLockMask;
108 private static long biasedLockMaskInPlace;
109 private static long biasedLockBitInPlace;
110 private static long ageMask;
111 private static long ageMaskInPlace;
112 private static long hashMask;
113 private static long hashMaskInPlace;
114 private static long hashMaskCompact;
115 private static long hashMaskCompactInPlace;
116 private static long biasedLockAlignment;
117
118 private static long lockedValue;
119 private static long unlockedValue;
120 private static long monitorValue;
121 private static long markedValue;
122 private static long biasedLockPattern;
123
124 private static long noHash;
125
126 private static long noHashInPlace;
127 private static long noLockInPlace;
128
129 private static long maxAge;
130
131 /* Constants in markWord used by CMS. */
132 private static long cmsShift;
133 private static long cmsMask;
134 private static long sizeShift;
135
136 public static long getKlassShift() {
137 return klassShift;
138 }
139
140 public Mark(Address addr) {
141 super(addr);
142 }
143
144 public long value() {
145 return markField.getValue(addr);
146 }
147
148 public Address valueAsAddress() {
149 return addr.getAddressAt(markField.getOffset());
150 }
151
152 // Biased locking accessors
153 // These must be checked by all code which calls into the
154 // ObjectSynchoronizer and other code. The biasing is not understood
155 // by the lower-level CAS-based locking code, although the runtime
156 // fixes up biased locks to be compatible with it when a bias is
157 // revoked.
158 public boolean hasBiasPattern() {
159 return (Bits.maskBitsLong(value(), biasedLockMaskInPlace) == biasedLockPattern);
160 }
161
162 public JavaThread biasedLocker() {
163 Threads threads = VM.getVM().getThreads();
164 Address addr = valueAsAddress().andWithMask(~(biasedLockMaskInPlace & ageMaskInPlace));
165 return threads.createJavaThreadWrapper(addr);
166 }
167
168 // Indicates that the mark gas the bias bit set but that it has not
169 // yet been biased toward a particular thread
170 public boolean isBiasedAnonymously() {
171 return hasBiasPattern() && (biasedLocker() == null);
172 }
173
174 // lock accessors (note that these assume lock_shift == 0)
175 public boolean isLocked() {
176 return (Bits.maskBitsLong(value(), lockMaskInPlace) != unlockedValue);
177 }
178 public boolean isUnlocked() {
179 return (Bits.maskBitsLong(value(), biasedLockMaskInPlace) == unlockedValue);
180 }
181 public boolean isMarked() {
182 return (Bits.maskBitsLong(value(), lockMaskInPlace) == markedValue);
183 }
184
185 // Special temporary state of the markWord while being inflated.
186 // Code that looks at mark outside a lock need to take this into account.
187 public boolean isBeingInflated() {
188 return (value() == 0);
189 }
190
191 // Should this header be preserved during GC?
192 public boolean mustBePreserved() {
193 return (!isUnlocked() || !hasNoHash());
194 }
195
196 // WARNING: The following routines are used EXCLUSIVELY by
197 // synchronization functions. They are not really gc safe.
198 // They must get updated if markWord layout get changed.
199
200 public boolean hasLocker() {
201 return ((value() & lockMaskInPlace) == lockedValue);
202 }
203 public BasicLock locker() {
204 if (Assert.ASSERTS_ENABLED) {
205 Assert.that(hasLocker(), "check");
206 }
207 return new BasicLock(valueAsAddress());
208 }
209 public boolean hasMonitor() {
210 return ((value() & monitorValue) != 0);
211 }
212 public ObjectMonitor monitor() {
213 if (Assert.ASSERTS_ENABLED) {
214 Assert.that(hasMonitor(), "check");
215 }
216 // Use xor instead of &~ to provide one extra tag-bit check.
217 Address monAddr = valueAsAddress().xorWithMask(monitorValue);
218 return new ObjectMonitor(monAddr);
219 }
220 public boolean hasDisplacedMarkHelper() {
221 return ((value() & unlockedValue) == 0);
222 }
223 public Mark displacedMarkHelper() {
224 if (Assert.ASSERTS_ENABLED) {
225 Assert.that(hasDisplacedMarkHelper(), "check");
226 }
227 Address addr = valueAsAddress().andWithMask(~monitorValue);
228 return new Mark(addr.getAddressAt(0));
229 }
230 public int age() { return (int) Bits.maskBitsLong(value() >> ageShift, ageMask); }
231
232 // hash operations
233 public long hash() {
234 if (VM.getVM().isCompactObjectHeadersEnabled()) {
235 return Bits.maskBitsLong(value() >> hashShiftCompact, hashMaskCompact);
236 } else {
237 return Bits.maskBitsLong(value() >> hashShift, hashMask);
238 }
239 }
240
241 public boolean hasNoHash() {
242 return hash() == noHash;
243 }
244
245 public Klass getKlass() {
246 assert(VM.getVM().isCompactObjectHeadersEnabled());
247 assert(!hasMonitor());
248 return (Klass)Metadata.instantiateWrapperFor(addr.getCompKlassAddressAt(0));
249 }
250
251 // Debugging
252 public void printOn(PrintStream tty) {
253 if (isLocked()) {
254 tty.print("locked(0x" +
255 Long.toHexString(value()) + ")->");
256 displacedMarkHelper().printOn(tty);
257 } else {
258 if (Assert.ASSERTS_ENABLED) {
259 Assert.that(isUnlocked(), "just checking");
260 }
261 tty.print("mark(");
262 tty.print("hash " + Long.toHexString(hash()) + ",");
263 tty.print("age " + age() + ")");
264 }
265 }
266
267 public long getSize() { return (long)(value() >> sizeShift); }
268 }