1/*
2 * Copyright (c) 2001, 2008, 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
25package sun.jvm.hotspot.oops;
26
27import java.io.*;
28import java.util.*;
29
30import sun.jvm.hotspot.debugger.*;
31import sun.jvm.hotspot.runtime.*;
32import sun.jvm.hotspot.types.*;
33import 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
41public 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();
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();
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
128  /* Constants in markOop used by CMS. */
129  private static long cmsShift;
130  private static long cmsMask;
131  private static long sizeShift;
132
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(); }
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); }
310}
311