blob: 6771b2b314ab8e4b6a1f4b41cb4b8d59b5642f88 [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.utility;
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;
/**
* This class provides generic support for object forwarding, which is specific
* to a few policies that support copying. The broad idea is two-fold: 1) the
* two low-order bits of the GC byte (which are also the two low-order bits of
* the header word) are used to indicate whether an object has been forwarded
* or is being forwarded, and 2) if an object has been forwarded then the entire
* header word of the dead object is used to store a pointer to the forwarded
* pointer. This is a standard implementation of forwarding.<p>
*
* The two lowest order bits are used for object forwarding because forwarding
* generally must steal the unused two low order bits of the forwarding pointer.
*/
@Uninterruptible
public class ForwardingWord {
/*
* The forwarding process uses three states to deal with a GC race:
* 1. !FORWARDED: Unforwarded
* 2. BEING_FORWARDED: Being forwarded (forwarding is underway)
* 3. FORWARDED: Forwarded
*/
/** If this bit is set, then forwarding of this object is incomplete */
private static final byte BEING_FORWARDED = 2; // ...10
/** If this bit is set, then forwarding of this object has commenced */
private static final byte FORWARDED = 3; // ...11
/** This mask is used to reveal which state this object is in with respect to forwarding */
public static final byte FORWARDING_MASK = 3; // ...11
public static final int FORWARDING_BITS = 2;
/**
* 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.
*/
@Inline
public static Word attemptToForward(ObjectReference object) {
Word oldValue;
do {
oldValue = VM.objectModel.prepareAvailableBits(object);
if ((byte) (oldValue.toInt() & FORWARDING_MASK) == FORWARDED)
return oldValue;
} while (!VM.objectModel.attemptAvailableBits(object, oldValue,
oldValue.or(Word.fromIntZeroExtend(BEING_FORWARDED))));
return oldValue;
}
public static ObjectReference spinAndGetForwardedObject(ObjectReference object, Word statusWord) {
/* We must wait (spin) if the object is not yet fully forwarded */
while ((statusWord.toInt() & FORWARDING_MASK) == BEING_FORWARDED)
statusWord = VM.objectModel.readAvailableBitsWord(object);
/* Now extract the object reference from the forwarding word and return it */
if ((statusWord.toInt() & FORWARDING_MASK) == FORWARDED)
return statusWord.and(Word.fromIntZeroExtend(FORWARDING_MASK).not()).toAddress().toObjectReference();
else
return object;
}
public static ObjectReference forwardObject(ObjectReference object, int allocator) {
ObjectReference newObject = VM.objectModel.copy(object, allocator);
VM.objectModel.writeAvailableBitsWord(object, newObject.toAddress().toWord().or(Word.fromIntZeroExtend(FORWARDED)));
return newObject;
}
/**
* Non-atomic write of forwarding pointer word (assumption, thread
* doing the set has done attempt to forward and owns the right to
* copy the object)
*
* @param object The object whose forwarding pointer is to be set
* @param ptr The forwarding pointer to be stored in the object's
* forwarding word
*/
@Inline
public static void setForwardingPointer(ObjectReference object,
ObjectReference ptr) {
VM.objectModel.writeAvailableBitsWord(object, ptr.toAddress().toWord().or(Word.fromIntZeroExtend(FORWARDED)));
}
/**
* Has an object been forwarded?
*
* @param object The object to be checked
* @return True if the object has been forwarded
*/
@Inline
public static boolean isForwarded(ObjectReference object) {
return (VM.objectModel.readAvailableByte(object) & FORWARDING_MASK) == FORWARDED;
}
/**
* Has an object been forwarded or is it being forwarded?
*
* @param object The object to be checked
* @return True if the object has been forwarded
*/
@Inline
public static boolean isForwardedOrBeingForwarded(ObjectReference object) {
return (VM.objectModel.readAvailableByte(object) & FORWARDING_MASK) != 0;
}
/**
* Has an object been forwarded or being forwarded?
*
* @param object The object to be checked
* @return True if the object has been forwarded
*/
@Inline
public static boolean stateIsForwardedOrBeingForwarded(Word header) {
return (header.toInt() & FORWARDING_MASK) != 0;
}
/**
* Has an object been forwarded or being forwarded?
*
* @param object The object to be checked
* @return True if the object has been forwarded
*/
@Inline
public static boolean stateIsBeingForwarded(Word header) {
return (header.toInt() & FORWARDING_MASK) == BEING_FORWARDED;
}
/**
* Clear the GC forwarding portion of the header for an object.
*
* @param object the object ref to the storage to be initialized
*/
@Inline
public static void clearForwardingBits(ObjectReference object) {
VM.objectModel.writeAvailableByte(object, (byte) (VM.objectModel.readAvailableByte(object) & ~FORWARDING_MASK));
}
@Inline
public static ObjectReference extractForwardingPointer(Word forwardingWord) {
return forwardingWord.and(Word.fromIntZeroExtend(FORWARDING_MASK).not()).toAddress().toObjectReference();
}
}