View Javadoc
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  
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  
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  
41  public 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 }