--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,310 @@
+/*
+ * 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); }
+}