001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.mmtk.utility;
014
015import org.mmtk.vm.VM;
016import org.vmmagic.pragma.Inline;
017import org.vmmagic.pragma.Uninterruptible;
018import org.vmmagic.unboxed.ObjectReference;
019import org.vmmagic.unboxed.Word;
020
021/**
022 * This class provides generic support for object forwarding, which is specific
023 * to a few policies that support copying.  The broad idea is two-fold: 1) the
024 * two low-order bits of the GC byte (which are also the two low-order bits of
025 * the header word) are used to indicate whether an object has been forwarded
026 * or is being forwarded, and 2) if an object has been forwarded then the entire
027 * header word of the dead object is used to store a pointer to the forwarded
028 * pointer.   This is a standard implementation of forwarding.<p>
029 *
030 * The two lowest order bits are used for object forwarding because forwarding
031 * generally must steal the unused two low order bits of the forwarding pointer.
032 */
033@Uninterruptible
034public class ForwardingWord {
035  /*
036   *  The forwarding process uses three states to deal with a GC race:
037   *  1.      !FORWARDED: Unforwarded
038   *  2. BEING_FORWARDED: Being forwarded (forwarding is underway)
039   *  3.       FORWARDED: Forwarded
040   */
041
042  /**
043   * If this bit pattern is set, the forwarding of this object has not been
044   * triggered yet.
045   */
046  private static final byte FORWARDING_NOT_TRIGGERED_YET = 0; // ...00
047  /** If this bit is set, then forwarding of this object is incomplete */
048  private static final byte BEING_FORWARDED = 2; // ...10
049  /** If this bit is set, then forwarding of this object has commenced */
050  private static final byte FORWARDED =       3; // ...11
051  /** This mask is used to reveal which state this object is in with respect to forwarding */
052  public static final byte FORWARDING_MASK =  3; // ...11
053
054  public static final int FORWARDING_BITS = 2;
055
056
057  /**
058   * Either return the forwarding pointer if the object is already
059   * forwarded (or being forwarded) or write the bit pattern that
060   * indicates that the object is being forwarded
061   *
062   * @param object The object to be forwarded
063   * @return The forwarding pointer for the object if it has already
064   * been forwarded.
065   */
066  @Inline
067  public static Word attemptToForward(ObjectReference object) {
068    Word oldValue;
069    do {
070      oldValue = VM.objectModel.prepareAvailableBits(object);
071      if ((byte) (oldValue.toInt() & FORWARDING_MASK) != FORWARDING_NOT_TRIGGERED_YET)
072        return oldValue;
073    } while (!VM.objectModel.attemptAvailableBits(object, oldValue,
074                                                  oldValue.or(Word.fromIntZeroExtend(BEING_FORWARDED))));
075    return oldValue;
076  }
077
078  public static ObjectReference spinAndGetForwardedObject(ObjectReference object, Word statusWord) {
079    /* We must wait (spin) if the object is not yet fully forwarded */
080    while ((statusWord.toInt() & FORWARDING_MASK) == BEING_FORWARDED)
081      statusWord = VM.objectModel.readAvailableBitsWord(object);
082
083    /* Now extract the object reference from the forwarding word and return it */
084    if ((statusWord.toInt() & FORWARDING_MASK) == FORWARDED)
085      return statusWord.and(Word.fromIntZeroExtend(FORWARDING_MASK).not()).toAddress().toObjectReference();
086    else
087      return object;
088  }
089
090  public static ObjectReference forwardObject(ObjectReference object, int allocator) {
091    ObjectReference newObject = VM.objectModel.copy(object, allocator);
092    VM.objectModel.writeAvailableBitsWord(object, newObject.toAddress().toWord().or(Word.fromIntZeroExtend(FORWARDED)));
093    return newObject;
094  }
095
096  /**
097   * Non-atomic write of forwarding pointer word (assumption, thread
098   * doing the set has done attempt to forward and owns the right to
099   * copy the object)
100   *
101   * @param object The object whose forwarding pointer is to be set
102   * @param ptr The forwarding pointer to be stored in the object's
103   * forwarding word
104   */
105  @Inline
106  public static void setForwardingPointer(ObjectReference object,
107                                           ObjectReference ptr) {
108    VM.objectModel.writeAvailableBitsWord(object, ptr.toAddress().toWord().or(Word.fromIntZeroExtend(FORWARDED)));
109  }
110
111  /**
112   * Has an object been forwarded?
113   *
114   * @param object The object to be checked
115   * @return {@code true} if the object has been forwarded
116   */
117  @Inline
118  public static boolean isForwarded(ObjectReference object) {
119    return (VM.objectModel.readAvailableByte(object) & FORWARDING_MASK) == FORWARDED;
120  }
121
122  /**
123   * Has an object been forwarded or is it being forwarded?
124   *
125   * @param object The object to be checked
126   * @return {@code true} if the object has been forwarded
127   */
128  @Inline
129  public static boolean isForwardedOrBeingForwarded(ObjectReference object) {
130    return (VM.objectModel.readAvailableByte(object) & FORWARDING_MASK) != 0;
131  }
132
133  /**
134   * Has an object been forwarded or being forwarded?
135   *
136   * @param header The object header to be checked
137   * @return {@code true} if the object has been forwarded
138   */
139  @Inline
140  public static boolean stateIsForwardedOrBeingForwarded(Word header) {
141    return (header.toInt() & FORWARDING_MASK) != 0;
142  }
143
144  /**
145   * Has an object been forwarded or being forwarded?
146   *
147   * @param header The object header to be checked
148   * @return {@code true} if the object has been forwarded
149   */
150  @Inline
151  public static boolean stateIsBeingForwarded(Word header) {
152    return (header.toInt() & FORWARDING_MASK) == BEING_FORWARDED;
153  }
154
155  /**
156   * Clear the GC forwarding portion of the header for an object.
157   *
158   * @param object the object ref to the storage to be initialized
159   */
160  @Inline
161  public static void clearForwardingBits(ObjectReference object) {
162    VM.objectModel.writeAvailableByte(object, (byte) (VM.objectModel.readAvailableByte(object) & ~FORWARDING_MASK));
163  }
164
165  @Inline
166  public static ObjectReference extractForwardingPointer(Word forwardingWord) {
167    return forwardingWord.and(Word.fromIntZeroExtend(FORWARDING_MASK).not()).toAddress().toObjectReference();
168  }
169}