1 /*
   2  * Copyright 2001-2005 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 
  84   // Field accessors
  85   private static CIntegerField markField;
  86 
  87   // Constants -- read from VM
  88   private static long ageBits;
  89   private static long lockBits;
  90   private static long biasedLockBits;
  91   private static long maxHashBits;
  92   private static long hashBits;
  93 
  94   private static long lockShift;
  95   private static long biasedLockShift;
  96   private static long ageShift;
  97   private static long hashShift;
  98 
  99   private static long lockMask;
 100   private static long lockMaskInPlace;
 101   private static long biasedLockMask;
 102   private static long biasedLockMaskInPlace;
 103   private static long biasedLockBitInPlace;
 104   private static long ageMask;
 105   private static long ageMaskInPlace;
 106   private static long hashMask;
 107   private static long hashMaskInPlace;
 108   private static long biasedLockAlignment; 
 109 
 110   private static long lockedValue;
 111   private static long unlockedValue;
 112   private static long monitorValue;
 113   private static long markedValue;
 114   private static long biasedLockPattern;
 115 
 116   private static long noHash;
 117 
 118   private static long noHashInPlace;
 119   private static long noLockInPlace;
 120 
 121   private static long maxAge;
 122 
 123   public Mark(Address addr) {
 124     super(addr);
 125   }
 126 
 127   public long value() {
 128     return markField.getValue(addr);
 129   }
 130 
 131   public Address valueAsAddress() {
 132     return addr.getAddressAt(markField.getOffset());
 133   }
 134 
 135   // Biased locking accessors
 136   // These must be checked by all code which calls into the
 137   // ObjectSynchoronizer and other code. The biasing is not understood
 138   // by the lower-level CAS-based locking code, although the runtime
 139   // fixes up biased locks to be compatible with it when a bias is
 140   // revoked.
 141   public boolean hasBiasPattern() {
 142     return (Bits.maskBitsLong(value(), biasedLockMaskInPlace) == biasedLockPattern);
 143   }
 144 
 145   public JavaThread biasedLocker() {
 146     Threads threads = VM.getVM().getThreads();
 147     Address addr = valueAsAddress().andWithMask(~(biasedLockMaskInPlace & ageMaskInPlace));
 148     return threads.createJavaThreadWrapper(addr);
 149   }
 150 
 151   // Indicates that the mark gas the bias bit set but that it has not
 152   // yet been biased toward a particular thread
 153   public boolean isBiasedAnonymously() {
 154     return hasBiasPattern() && (biasedLocker() == null);
 155   }
 156 
 157   // lock accessors (note that these assume lock_shift == 0)
 158   public boolean isLocked() {
 159     return (Bits.maskBitsLong(value(), lockMaskInPlace) != unlockedValue);
 160   }
 161   public boolean isUnlocked() {
 162     return (Bits.maskBitsLong(value(), biasedLockMaskInPlace) == unlockedValue);
 163   }
 164   public boolean isMarked() {
 165     return (Bits.maskBitsLong(value(), lockMaskInPlace) == markedValue);
 166   }
 167 
 168   // Special temporary state of the markOop while being inflated.
 169   // Code that looks at mark outside a lock need to take this into account.
 170   public boolean isBeingInflated() {
 171     return (value() == 0);
 172   }
 173 
 174   // Should this header be preserved during GC?
 175   public boolean mustBePreserved() {
 176      return (!isUnlocked() || !hasNoHash());
 177   }
 178 
 179   // WARNING: The following routines are used EXCLUSIVELY by 
 180   // synchronization functions. They are not really gc safe.
 181   // They must get updated if markOop layout get changed.
 182 
 183   // FIXME
 184   //  markOop set_unlocked() const {
 185   //    return markOop(value() | unlocked_value);
 186   //  }
 187   public boolean hasLocker() {
 188     return ((value() & lockMaskInPlace) == lockedValue);
 189   }
 190   public BasicLock locker() {
 191     if (Assert.ASSERTS_ENABLED) {
 192       Assert.that(hasLocker(), "check");
 193     }
 194     return new BasicLock(valueAsAddress());
 195   }
 196   public boolean hasMonitor() {
 197     return ((value() & monitorValue) != 0);
 198   }
 199   public ObjectMonitor monitor() {
 200     if (Assert.ASSERTS_ENABLED) {
 201       Assert.that(hasMonitor(), "check");
 202     }
 203     // Use xor instead of &~ to provide one extra tag-bit check.
 204     Address monAddr = valueAsAddress().xorWithMask(monitorValue);
 205     return new ObjectMonitor(monAddr);
 206   }
 207   public boolean hasDisplacedMarkHelper() {
 208     return ((value() & unlockedValue) == 0);
 209   }
 210   public Mark displacedMarkHelper() {
 211     if (Assert.ASSERTS_ENABLED) {
 212       Assert.that(hasDisplacedMarkHelper(), "check");
 213     }
 214     Address addr = valueAsAddress().andWithMask(~monitorValue);
 215     return new Mark(addr.getAddressAt(0));
 216   }
 217   // FIXME
 218   //  void set_displaced_mark_helper(markOop m) const {
 219   //    assert(has_displaced_mark_helper(), "check");
 220   //    intptr_t ptr = (value() & ~monitor_value);
 221   //    *(markOop*)ptr = m;
 222   //  }
 223   //  markOop copy_set_hash(intptr_t hash) const {
 224   //    intptr_t tmp = value() & (~hash_mask_in_place);
 225   //    tmp |= ((hash & hash_mask) << hash_shift);
 226   //    return (markOop)tmp;
 227   //  }
 228   // it is only used to be stored into BasicLock as the 
 229   // indicator that the lock is using heavyweight monitor
 230   //  static markOop unused_mark() {
 231   //    return (markOop) marked_value;
 232   //  }
 233   //  // the following two functions create the markOop to be
 234   //  // stored into object header, it encodes monitor info
 235   //  static markOop encode(BasicLock* lock) {
 236   //    return (markOop) lock;
 237   //  }
 238   //  static markOop encode(ObjectMonitor* monitor) {
 239   //    intptr_t tmp = (intptr_t) monitor;
 240   //    return (markOop) (tmp | monitor_value);
 241   //  }
 242   // used for alignment-based marking to reuse the busy state to encode pointers
 243   // (see markOop_alignment.hpp)  
 244   //  markOop clear_lock_bits() { return markOop(value() & ~lock_mask_in_place); }  
 245   //
 246   //  // age operations
 247   //  markOop set_marked()   { return markOop((value() & ~lock_mask_in_place) | marked_value); }
 248   //
 249   public int age() { return (int) Bits.maskBitsLong(value() >> ageShift, ageMask); }
 250   //  markOop set_age(int v) const {
 251   //    assert((v & ~age_mask) == 0, "shouldn't overflow age field");
 252   //    return markOop((value() & ~age_mask_in_place) | (((intptr_t)v & age_mask) << age_shift));
 253   //  }
 254   //  markOop incr_age()          const { return age() == max_age ? markOop(this) : set_age(age() + 1); }
 255 
 256   // hash operations
 257   public long hash() {     
 258     return Bits.maskBitsLong(value() >> hashShift, hashMask);
 259   }
 260   
 261   public boolean hasNoHash() { 
 262     return hash() == noHash; 
 263   }
 264 
 265   // FIXME
 266   // Prototype mark for initialization
 267   //  static markOop prototype() {
 268   //    return markOop( no_hash_in_place | no_lock_in_place );
 269   //  }
 270  
 271   // Debugging
 272   public void printOn(PrintStream tty) {
 273     if (isLocked()) {
 274       tty.print("locked(0x" +
 275                 Long.toHexString(value()) + ")->");
 276       displacedMarkHelper().printOn(tty);
 277     } else {
 278       if (Assert.ASSERTS_ENABLED) {
 279         Assert.that(isUnlocked(), "just checking");
 280       }
 281       tty.print("mark(");
 282       tty.print("hash " + Long.toHexString(hash()) + ",");
 283       tty.print("age " + age() + ")");
 284     }
 285   }
 286 
 287   // FIXME
 288   //  // Prepare address of oop for placement into mark
 289   //  inline static markOop encode_pointer_as_mark(void* p) { return markOop(p)->set_marked(); }
 290   //
 291   //  // Recover address of oop from encoded form used in mark
 292   //  inline void* decode_pointer() { return clear_lock_bits(); }
 293 }