blob: 796ac85675caa91315056a68023cbc2b4adde141 [file] [log] [blame]
/*
* Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package sun.jvm.hotspot.oops;
import java.io.*;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;
/** Mark is the analogue of the VM's markOop. In this system it does
not subclass Oop but VMObject. For a mark on the stack, the mark's
address will be an Address; for a mark in the header of an object,
it will be an OopHandle. It is assumed in a couple of places in
this code that the mark is the first word in an object. */
public class Mark extends VMObject {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
Type type = db.lookupType("oopDesc");
markField = type.getCIntegerField("_mark");
ageBits = db.lookupLongConstant("markOopDesc::age_bits").longValue();
lockBits = db.lookupLongConstant("markOopDesc::lock_bits").longValue();
biasedLockBits = db.lookupLongConstant("markOopDesc::biased_lock_bits").longValue();
maxHashBits = db.lookupLongConstant("markOopDesc::max_hash_bits").longValue();
hashBits = db.lookupLongConstant("markOopDesc::hash_bits").longValue();
lockShift = db.lookupLongConstant("markOopDesc::lock_shift").longValue();
biasedLockShift = db.lookupLongConstant("markOopDesc::biased_lock_shift").longValue();
ageShift = db.lookupLongConstant("markOopDesc::age_shift").longValue();
hashShift = db.lookupLongConstant("markOopDesc::hash_shift").longValue();
lockMask = db.lookupLongConstant("markOopDesc::lock_mask").longValue();
lockMaskInPlace = db.lookupLongConstant("markOopDesc::lock_mask_in_place").longValue();
biasedLockMask = db.lookupLongConstant("markOopDesc::biased_lock_mask").longValue();
biasedLockMaskInPlace = db.lookupLongConstant("markOopDesc::biased_lock_mask_in_place").longValue();
biasedLockBitInPlace = db.lookupLongConstant("markOopDesc::biased_lock_bit_in_place").longValue();
ageMask = db.lookupLongConstant("markOopDesc::age_mask").longValue();
ageMaskInPlace = db.lookupLongConstant("markOopDesc::age_mask_in_place").longValue();
hashMask = db.lookupLongConstant("markOopDesc::hash_mask").longValue();
hashMaskInPlace = db.lookupLongConstant("markOopDesc::hash_mask_in_place").longValue();
biasedLockAlignment = db.lookupLongConstant("markOopDesc::biased_lock_alignment").longValue();
lockedValue = db.lookupLongConstant("markOopDesc::locked_value").longValue();
unlockedValue = db.lookupLongConstant("markOopDesc::unlocked_value").longValue();
monitorValue = db.lookupLongConstant("markOopDesc::monitor_value").longValue();
markedValue = db.lookupLongConstant("markOopDesc::marked_value").longValue();
biasedLockPattern = db.lookupLongConstant("markOopDesc::biased_lock_pattern").longValue();
noHash = db.lookupLongConstant("markOopDesc::no_hash").longValue();
noHashInPlace = db.lookupLongConstant("markOopDesc::no_hash_in_place").longValue();
noLockInPlace = db.lookupLongConstant("markOopDesc::no_lock_in_place").longValue();
maxAge = db.lookupLongConstant("markOopDesc::max_age").longValue();
/* Constants in markOop used by CMS. */
cmsShift = db.lookupLongConstant("markOopDesc::cms_shift").longValue();
cmsMask = db.lookupLongConstant("markOopDesc::cms_mask").longValue();
sizeShift = db.lookupLongConstant("markOopDesc::size_shift").longValue();
}
// Field accessors
private static CIntegerField markField;
// Constants -- read from VM
private static long ageBits;
private static long lockBits;
private static long biasedLockBits;
private static long maxHashBits;
private static long hashBits;
private static long lockShift;
private static long biasedLockShift;
private static long ageShift;
private static long hashShift;
private static long lockMask;
private static long lockMaskInPlace;
private static long biasedLockMask;
private static long biasedLockMaskInPlace;
private static long biasedLockBitInPlace;
private static long ageMask;
private static long ageMaskInPlace;
private static long hashMask;
private static long hashMaskInPlace;
private static long biasedLockAlignment;
private static long lockedValue;
private static long unlockedValue;
private static long monitorValue;
private static long markedValue;
private static long biasedLockPattern;
private static long noHash;
private static long noHashInPlace;
private static long noLockInPlace;
private static long maxAge;
/* Constants in markOop used by CMS. */
private static long cmsShift;
private static long cmsMask;
private static long sizeShift;
public Mark(Address addr) {
super(addr);
}
public long value() {
return markField.getValue(addr);
}
public Address valueAsAddress() {
return addr.getAddressAt(markField.getOffset());
}
// Biased locking accessors
// These must be checked by all code which calls into the
// ObjectSynchoronizer and other code. The biasing is not understood
// by the lower-level CAS-based locking code, although the runtime
// fixes up biased locks to be compatible with it when a bias is
// revoked.
public boolean hasBiasPattern() {
return (Bits.maskBitsLong(value(), biasedLockMaskInPlace) == biasedLockPattern);
}
public JavaThread biasedLocker() {
Threads threads = VM.getVM().getThreads();
Address addr = valueAsAddress().andWithMask(~(biasedLockMaskInPlace & ageMaskInPlace));
return threads.createJavaThreadWrapper(addr);
}
// Indicates that the mark gas the bias bit set but that it has not
// yet been biased toward a particular thread
public boolean isBiasedAnonymously() {
return hasBiasPattern() && (biasedLocker() == null);
}
// lock accessors (note that these assume lock_shift == 0)
public boolean isLocked() {
return (Bits.maskBitsLong(value(), lockMaskInPlace) != unlockedValue);
}
public boolean isUnlocked() {
return (Bits.maskBitsLong(value(), biasedLockMaskInPlace) == unlockedValue);
}
public boolean isMarked() {
return (Bits.maskBitsLong(value(), lockMaskInPlace) == markedValue);
}
// Special temporary state of the markOop while being inflated.
// Code that looks at mark outside a lock need to take this into account.
public boolean isBeingInflated() {
return (value() == 0);
}
// Should this header be preserved during GC?
public boolean mustBePreserved() {
return (!isUnlocked() || !hasNoHash());
}
// WARNING: The following routines are used EXCLUSIVELY by
// synchronization functions. They are not really gc safe.
// They must get updated if markOop layout get changed.
// FIXME
// markOop set_unlocked() const {
// return markOop(value() | unlocked_value);
// }
public boolean hasLocker() {
return ((value() & lockMaskInPlace) == lockedValue);
}
public BasicLock locker() {
if (Assert.ASSERTS_ENABLED) {
Assert.that(hasLocker(), "check");
}
return new BasicLock(valueAsAddress());
}
public boolean hasMonitor() {
return ((value() & monitorValue) != 0);
}
public ObjectMonitor monitor() {
if (Assert.ASSERTS_ENABLED) {
Assert.that(hasMonitor(), "check");
}
// Use xor instead of &~ to provide one extra tag-bit check.
Address monAddr = valueAsAddress().xorWithMask(monitorValue);
return new ObjectMonitor(monAddr);
}
public boolean hasDisplacedMarkHelper() {
return ((value() & unlockedValue) == 0);
}
public Mark displacedMarkHelper() {
if (Assert.ASSERTS_ENABLED) {
Assert.that(hasDisplacedMarkHelper(), "check");
}
Address addr = valueAsAddress().andWithMask(~monitorValue);
return new Mark(addr.getAddressAt(0));
}
// FIXME
// void set_displaced_mark_helper(markOop m) const {
// assert(has_displaced_mark_helper(), "check");
// intptr_t ptr = (value() & ~monitor_value);
// *(markOop*)ptr = m;
// }
// markOop copy_set_hash(intptr_t hash) const {
// intptr_t tmp = value() & (~hash_mask_in_place);
// tmp |= ((hash & hash_mask) << hash_shift);
// return (markOop)tmp;
// }
// it is only used to be stored into BasicLock as the
// indicator that the lock is using heavyweight monitor
// static markOop unused_mark() {
// return (markOop) marked_value;
// }
// // the following two functions create the markOop to be
// // stored into object header, it encodes monitor info
// static markOop encode(BasicLock* lock) {
// return (markOop) lock;
// }
// static markOop encode(ObjectMonitor* monitor) {
// intptr_t tmp = (intptr_t) monitor;
// return (markOop) (tmp | monitor_value);
// }
// used for alignment-based marking to reuse the busy state to encode pointers
// (see markOop_alignment.hpp)
// markOop clear_lock_bits() { return markOop(value() & ~lock_mask_in_place); }
//
// // age operations
// markOop set_marked() { return markOop((value() & ~lock_mask_in_place) | marked_value); }
//
public int age() { return (int) Bits.maskBitsLong(value() >> ageShift, ageMask); }
// markOop set_age(int v) const {
// assert((v & ~age_mask) == 0, "shouldn't overflow age field");
// return markOop((value() & ~age_mask_in_place) | (((intptr_t)v & age_mask) << age_shift));
// }
// markOop incr_age() const { return age() == max_age ? markOop(this) : set_age(age() + 1); }
// hash operations
public long hash() {
return Bits.maskBitsLong(value() >> hashShift, hashMask);
}
public boolean hasNoHash() {
return hash() == noHash;
}
// FIXME
// Prototype mark for initialization
// static markOop prototype() {
// return markOop( no_hash_in_place | no_lock_in_place );
// }
// Debugging
public void printOn(PrintStream tty) {
if (isLocked()) {
tty.print("locked(0x" +
Long.toHexString(value()) + ")->");
displacedMarkHelper().printOn(tty);
} else {
if (Assert.ASSERTS_ENABLED) {
Assert.that(isUnlocked(), "just checking");
}
tty.print("mark(");
tty.print("hash " + Long.toHexString(hash()) + ",");
tty.print("age " + age() + ")");
}
}
// FIXME
// // Prepare address of oop for placement into mark
// inline static markOop encode_pointer_as_mark(void* p) { return markOop(p)->set_marked(); }
//
// // Recover address of oop from encoded form used in mark
// inline void* decode_pointer() { return clear_lock_bits(); }
// Copy markOop methods for CMS here.
public boolean isCmsFreeChunk() {
return isUnlocked() &&
(Bits.maskBitsLong(value() >> cmsShift, cmsMask) & 0x1L) == 0x1L;
}
public long getSize() { return (long)(value() >> sizeShift); }
}