1 /*
   2  * Copyright 2001-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any 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 }