blob: 8a275a145d5b00a470f01b380d44aaa12dcd26d4 [file] [log] [blame]
/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.mmtk.policy.immix;
import org.mmtk.plan.Plan;
import org.mmtk.vm.VM;
import org.vmmagic.pragma.Inline;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.unboxed.ObjectReference;
import org.vmmagic.unboxed.Word;
@Uninterruptible
public class ObjectHeader {
/** number of header bits we may use */
static final int MAX_BITS = 8;
/* header requirements */
public static final int LOCAL_GC_BITS_REQUIRED = MAX_BITS;
public static final int GLOBAL_GC_BITS_REQUIRED = 0;
public static final int GC_HEADER_WORDS_REQUIRED = 0;
/* stolen bits */
static final Word NEW_OBJECT_MARK = Word.fromIntZeroExtend(0); // using zero means no need for explicit initialization on allocation
private static final Word BEING_FORWARDED = Word.fromIntZeroExtend(2); // second bit indicates an object is in the process of being forwarded
private static final Word FORWARDED = Word.fromIntZeroExtend(3); // second bit indicates an object is in the process of being forwarded
private static final Word FORWARDING_MASK = Word.fromIntZeroExtend(3);
private static final int UNLOGGED_BIT_NUMBER = 3;
public static final Word UNLOGGED_BIT = Word.one().lsh(UNLOGGED_BIT_NUMBER);
public static final Word LOG_SET_MASK = UNLOGGED_BIT;
private static final int STOLEN_LO_BITS = UNLOGGED_BIT_NUMBER + 1; // both used for forwarding, also the all zero state is used to represent new objects
private static final int STOLEN_HI_BITS = 2;
static final int MAX_MARKCOUNT_BITS = MAX_BITS-(STOLEN_LO_BITS+STOLEN_HI_BITS);
private static final int FIRST_STOLEN_HI_BIT_NUMBER = STOLEN_LO_BITS + MAX_MARKCOUNT_BITS;
public static final int PINNED_BIT_NUMBER = FIRST_STOLEN_HI_BIT_NUMBER;
public static final Word PINNED_BIT = Word.one().lsh(PINNED_BIT_NUMBER);
private static final int STRADDLE_BIT_NUMBER = PINNED_BIT_NUMBER + 1;
public static final Word STRADDLE_BIT = Word.one().lsh(STRADDLE_BIT_NUMBER);
/* mark bits */
private static final int MARK_BASE = STOLEN_LO_BITS;
private static final Word MARK_INCREMENT = Word.one().lsh(MARK_BASE);
public static final Word MARK_MASK = Word.one().lsh(MAX_MARKCOUNT_BITS).minus(Word.one()).lsh(MARK_BASE);
public static final Word MARK_AND_LOG_BITS_MASK = Word.one().lsh(MAX_BITS-STOLEN_HI_BITS).minus(Word.one());
public static final Word MARK_BITS_MASK = MARK_AND_LOG_BITS_MASK.xor(UNLOGGED_BIT);
public static final Word MARK_BASE_VALUE = MARK_INCREMENT;
/****************************************************************************
*
* Marking
*/
/**
* Non-atomically test and set the mark bit of an object. Return true
* if successful, false if the mark bit was already set.
*
* @param object The object whose mark bit is to be written
* @param markState The value to which the mark bits will be set
*/
static Word testAndMark(ObjectReference object, Word markState) {
int oldValue, newValue, oldMarkState;
oldValue = VM.objectModel.readAvailableByte(object);
oldMarkState = oldValue & MARK_AND_LOG_BITS_MASK.toInt();
if (oldMarkState != markState.toInt()) {
newValue = (oldValue & ~MARK_AND_LOG_BITS_MASK.toInt()) | markState.toInt();
VM.objectModel.writeAvailableByte(object, (byte) newValue);
}
return Word.fromIntZeroExtend(oldMarkState);
}
static void setMarkStateUnlogAndUnlock(ObjectReference object, Word originalForwardingWord, Word markState) {
Word markValue = Plan.NEEDS_LOG_BIT_IN_HEADER ? markState.or(ObjectHeader.UNLOGGED_BIT) : markState;
int oldValue = originalForwardingWord.toInt();
int newValue = (oldValue & (MARK_AND_LOG_BITS_MASK.or(FORWARDING_MASK)).not().toInt()) | markValue.toInt();
VM.objectModel.writeAvailableByte(object, (byte) newValue);
if (VM.VERIFY_ASSERTIONS)
VM.assertions._assert((oldValue & MARK_AND_LOG_BITS_MASK.toInt()) != markValue.toInt());
}
/**
* Return true if the mark count for an object has the given value.
*
* @param object The object whose mark bit is to be tested
* @param value The value against which the mark bit will be tested
* @return True if the mark bit for the object has the given value.
*/
static boolean testMarkState(ObjectReference object, Word value) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(value.and(MARK_MASK).EQ(value));
return testMarkState(VM.objectModel.readAvailableBitsWord(object), value);
}
static boolean testMarkState(Word forwardingWord, Word value) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(value.and(MARK_MASK).EQ(value));
return forwardingWord.and(MARK_MASK).EQ(value);
}
static boolean isNewObject(ObjectReference object) {
Word markBits = VM.objectModel.readAvailableBitsWord(object).and(MARK_AND_LOG_BITS_MASK);
return markBits.EQ(NEW_OBJECT_MARK);
}
static boolean isMatureObject(ObjectReference object) {
Word markBits = VM.objectModel.readAvailableBitsWord(object).and(MARK_AND_LOG_BITS_MASK);
boolean unforwarded = markBits.and(FORWARDING_MASK).isZero();
boolean newObj = markBits.EQ(NEW_OBJECT_MARK);
return unforwarded && !newObj;
}
@Inline
static void markAsStraddling(ObjectReference object) {
Word old = VM.objectModel.readAvailableBitsWord(object);
VM.objectModel.writeAvailableBitsWord(object, old.or(STRADDLE_BIT));
}
@Inline
static boolean isStraddlingObject(ObjectReference object) {
return isStraddleBitSet(VM.objectModel.readAvailableBitsWord(object));
}
@Inline
private static boolean isStraddleBitSet(Word header) {
return header.and(STRADDLE_BIT).EQ(STRADDLE_BIT);
}
@Inline
static boolean isUnloggedObject(ObjectReference object) {
return isUnloggedBitSet(VM.objectModel.readAvailableBitsWord(object));
}
@Inline
static boolean isUnloggedBitSet(Word header) {
return header.and(UNLOGGED_BIT).EQ(UNLOGGED_BIT);
}
@Inline
public static void pinObject(ObjectReference object) {
byte header = VM.objectModel.readAvailableByte(object);
VM.objectModel.writeAvailableByte(object, (byte)(header | PINNED_BIT.toInt()));
}
@Inline
static boolean isPinnedObject(ObjectReference object) {
return isPinnedBitSet(VM.objectModel.readAvailableBitsWord(object));
}
@Inline
private static boolean isPinnedBitSet(Word header) {
return header.and(PINNED_BIT).EQ(PINNED_BIT);
}
/**
* Write the allocState into the mark state fields of an object non-atomically.
* This is appropriate for collection time initialization.
*
* @param object The object whose mark state is to be written
* @param markState TODO: what am I?
* @param straddle TODO: what am I?
*/
static void writeMarkState(ObjectReference object, Word markState, boolean straddle) {
Word oldValue = VM.objectModel.readAvailableBitsWord(object);
Word markValue = Plan.NEEDS_LOG_BIT_IN_HEADER ? markState.or(ObjectHeader.UNLOGGED_BIT) : markState;
Word newValue = oldValue.and(MARK_AND_LOG_BITS_MASK.not()).or(markValue);
if (straddle)
newValue = newValue.or(STRADDLE_BIT);
VM.objectModel.writeAvailableBitsWord(object, newValue);
}
/****************************************************************************
*
* Forwarding
*/
/**
* Either return the forwarding pointer if the object is already
* forwarded (or being forwarded) or write the bit pattern that
* indicates that the object is being forwarded
*
* @param object The object to be forwarded
* @return The forwarding pointer for the object if it has already
* been forwarded.
*/
static Word attemptToBeForwarder(ObjectReference object) {
Word oldValue;
do {
oldValue = VM.objectModel.prepareAvailableBits(object);
if (oldValue.and(FORWARDING_MASK).EQ(FORWARDED))
return oldValue;
} while (!VM.objectModel.attemptAvailableBits(object, oldValue, oldValue.or(BEING_FORWARDED)));
return oldValue;
}
static ObjectReference forwardObject(ObjectReference object, int allocator) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!isPinnedObject(object));
ObjectReference newObject = VM.objectModel.copy(object, allocator);
VM.objectModel.writeAvailableBitsWord(object, newObject.toAddress().toWord().or(FORWARDED));
return newObject;
}
static void setForwardingWordAndEnsureUnlogged(ObjectReference object, Word forwardingWord) {
if (Plan.NEEDS_LOG_BIT_IN_HEADER) forwardingWord = forwardingWord.or(UNLOGGED_BIT);
VM.objectModel.writeAvailableBitsWord(object, forwardingWord);
}
static boolean isForwardedOrBeingForwarded(ObjectReference object) {
return isForwardedOrBeingForwarded(VM.objectModel.readAvailableBitsWord(object));
}
static boolean isForwardedOrBeingForwarded(Word forwardingWord) {
return !forwardingWord.and(FORWARDING_MASK).isZero();
}
static ObjectReference spinAndGetForwardedObject(ObjectReference object, Word forwardingWord) {
/* We must wait (spin) if the object is not yet fully forwarded */
while (forwardingWord.and(FORWARDING_MASK).EQ(BEING_FORWARDED))
forwardingWord = VM.objectModel.readAvailableBitsWord(object);
/* Now extract the object reference from the forwarding word and return it */
if (forwardingWord.and(FORWARDING_MASK).EQ(FORWARDED))
return forwardingWord.and(FORWARDING_MASK.not()).toAddress().toObjectReference();
else
return object;
}
/**
* Return the mark state incremented or decremented by one.
*
* @param increment If true, then return the incremented value else return the decremented value
* @return the mark state incremented or decremented by one.
*/
static Word deltaMarkState(Word state, boolean increment) {
Word rtn = state;
do {
rtn = increment ? rtn.plus(MARK_INCREMENT) : rtn.minus(MARK_INCREMENT);
rtn = rtn.and(MARK_MASK);
} while (rtn.LT(MARK_BASE_VALUE));
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(rtn.NE(state));
return rtn;
}
}