1 /* 2 * Copyright (c) 2001, 2023, 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 }