1 /*
2 * Copyright (c) 2001, 2024, 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 maxHashBits = db.lookupLongConstant("markWord::max_hash_bits").longValue();
53 hashBits = db.lookupLongConstant("markWord::hash_bits").longValue();
54 hashCtrlBits = db.lookupLongConstant("markWord::hashctrl_bits").longValue();
55 lockShift = db.lookupLongConstant("markWord::lock_shift").longValue();
56 ageShift = db.lookupLongConstant("markWord::age_shift").longValue();
57 hashShift = db.lookupLongConstant("markWord::hash_shift").longValue();
58 hashCtrlShift = db.lookupLongConstant("markWord::hashctrl_shift").longValue();
59 if (VM.getVM().isLP64()) {
60 klassShift = db.lookupLongConstant("markWord::klass_shift").longValue();
61 }
62 lockMask = db.lookupLongConstant("markWord::lock_mask").longValue();
63 lockMaskInPlace = db.lookupLongConstant("markWord::lock_mask_in_place").longValue();
64 ageMask = db.lookupLongConstant("markWord::age_mask").longValue();
65 ageMaskInPlace = db.lookupLongConstant("markWord::age_mask_in_place").longValue();
66 hashMask = db.lookupLongConstant("markWord::hash_mask").longValue();
67 hashMaskInPlace = db.lookupLongConstant("markWord::hash_mask_in_place").longValue();
68 hashCtrlMask = db.lookupLongConstant("markWord::hashctrl_mask").longValue();
69 hashCtrlMaskInPlace = db.lookupLongConstant("markWord::hashctrl_mask_in_place").longValue();
70 hashCtrlHashedMaskInPlace = db.lookupLongConstant("markWord::hashctrl_hashed_mask_in_place").longValue();
71 hashCtrlExpandedMaskInPlace = db.lookupLongConstant("markWord::hashctrl_expanded_mask_in_place").longValue();
72 lockedValue = db.lookupLongConstant("markWord::locked_value").longValue();
73 unlockedValue = db.lookupLongConstant("markWord::unlocked_value").longValue();
74 monitorValue = db.lookupLongConstant("markWord::monitor_value").longValue();
75 markedValue = db.lookupLongConstant("markWord::marked_value").longValue();
76 noHash = db.lookupLongConstant("markWord::no_hash").longValue();
77 noHashInPlace = db.lookupLongConstant("markWord::no_hash_in_place").longValue();
78 noLockInPlace = db.lookupLongConstant("markWord::no_lock_in_place").longValue();
79 maxAge = db.lookupLongConstant("markWord::max_age").longValue();
80 }
81
82 // Field accessors
83 private static CIntegerField markField;
84
85 // Constants -- read from VM
86 private static long ageBits;
87 private static long lockBits;
88 private static long maxHashBits;
89 private static long hashBits;
90 private static long hashCtrlBits;
91
92 private static long lockShift;
93 private static long ageShift;
94 private static long hashShift;
95 private static long hashCtrlShift;
96 private static long klassShift;
97
98 private static long lockMask;
99 private static long lockMaskInPlace;
100 private static long ageMask;
101 private static long ageMaskInPlace;
102 private static long hashMask;
103 private static long hashMaskInPlace;
104 private static long hashCtrlMask;
105 private static long hashCtrlMaskInPlace;
106 private static long hashCtrlHashedMaskInPlace;
107 private static long hashCtrlExpandedMaskInPlace;
108
109 private static long lockedValue;
110 private static long unlockedValue;
111 private static long monitorValue;
112 private static long markedValue;
113
114 private static long noHash;
115
116 private static long noHashInPlace;
117 private static long noLockInPlace;
118
119 private static long maxAge;
120
121 public static long getKlassShift() {
122 return klassShift;
123 }
124
125 public Mark(Address addr) {
126 super(addr);
127 }
128
129 public long value() {
130 return markField.getValue(addr);
131 }
132
133 public Address valueAsAddress() {
134 return addr.getAddressAt(markField.getOffset());
135 }
136
137 // lock accessors (note that these assume lock_shift == 0)
138 public boolean isLocked() {
139 return (Bits.maskBitsLong(value(), lockMaskInPlace) != unlockedValue);
140 }
141 public boolean isUnlocked() {
142 return (Bits.maskBitsLong(value(), lockMaskInPlace) == unlockedValue);
143 }
144 public boolean isMarked() {
145 return (Bits.maskBitsLong(value(), lockMaskInPlace) == markedValue);
146 }
147
148 // Special temporary state of the markWord while being inflated.
149 // Code that looks at mark outside a lock need to take this into account.
150 public boolean isBeingInflated() {
151 return (value() == 0);
152 }
153
154 // Should this header be preserved during GC?
155 public boolean mustBePreserved() {
156 return (!isUnlocked() || !hasNoHash());
157 }
158
159 // WARNING: The following routines are used EXCLUSIVELY by
160 // synchronization functions. They are not really gc safe.
161 // They must get updated if markWord layout get changed.
162
163 public boolean hasLocker() {
164 return ((value() & lockMaskInPlace) == lockedValue);
165 }
166 public BasicLock locker() {
167 if (Assert.ASSERTS_ENABLED) {
168 Assert.that(hasLocker(), "check");
169 }
170 return new BasicLock(valueAsAddress());
171 }
172 public boolean hasMonitor() {
173 return ((value() & monitorValue) != 0);
174 }
175 public ObjectMonitor monitor() {
176 if (Assert.ASSERTS_ENABLED) {
177 Assert.that(hasMonitor(), "check");
178 }
179 if (VM.getVM().getCommandLineFlag("UseObjectMonitorTable").getBool()) {
180 Iterator it = ObjectSynchronizer.objectMonitorIterator();
181 while (it != null && it.hasNext()) {
182 ObjectMonitor mon = (ObjectMonitor)it.next();
183 if (getAddress().equals(mon.object())) {
184 return mon;
185 }
186 }
187 return null;
188 }
189 // Use xor instead of &~ to provide one extra tag-bit check.
190 Address monAddr = valueAsAddress().xorWithMask(monitorValue);
191 return new ObjectMonitor(monAddr);
192 }
193 public boolean hasDisplacedMarkHelper() {
194 return ((value() & unlockedValue) == 0);
195 }
196 public Mark displacedMarkHelper() {
197 if (Assert.ASSERTS_ENABLED) {
198 Assert.that(hasDisplacedMarkHelper(), "check");
199 }
200 Address addr = valueAsAddress().andWithMask(~monitorValue);
201 return new Mark(addr.getAddressAt(0));
202 }
203 public int age() { return (int) Bits.maskBitsLong(value() >> ageShift, ageMask); }
204
205 // hash operations
206 public long hash() {
207 if (VM.getVM().isCompactObjectHeadersEnabled()) {
208 System.exit(-23);
209 throw new RuntimeException("Compact I-Hash not yet implemented");
210 } else {
211 return Bits.maskBitsLong(value() >> hashShift, hashMask);
212 }
213 }
214
215 public boolean hasNoHash() {
216 return hash() == noHash;
217 }
218
219 public boolean isExpanded() {
220 assert(VM.getVM().isCompactObjectHeadersEnabled());
221 return Bits.maskBitsLong(value(), hashCtrlExpandedMaskInPlace) != 0;
222 }
223
224 public Klass getKlass() {
225 assert(VM.getVM().isCompactObjectHeadersEnabled());
226 return (Klass)Metadata.instantiateWrapperFor(addr.getCompKlassAddressAt(0));
227 }
228
229 // Debugging
230 public void printOn(PrintStream tty) {
231 if (isLocked()) {
232 tty.print("locked(0x" +
233 Long.toHexString(value()) + ")->");
234 displacedMarkHelper().printOn(tty);
235 } else {
236 if (Assert.ASSERTS_ENABLED) {
237 Assert.that(isUnlocked(), "just checking");
238 }
239 tty.print("mark(");
240 tty.print("hash " + Long.toHexString(hash()) + ",");
241 tty.print("age " + age() + ")");
242 }
243 }
244
245 public long getSize() { return (long)value(); }
246 }