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 }