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     */
013    package org.mmtk.utility;
014    
015    import org.mmtk.vm.VM;
016    import org.vmmagic.pragma.Inline;
017    import org.vmmagic.pragma.Uninterruptible;
018    import org.vmmagic.unboxed.ObjectReference;
019    import 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
034    public 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      /** If this bit is set, then forwarding of this object is incomplete */
043      private static final byte BEING_FORWARDED = 2; // ...10
044      /** If this bit is set, then forwarding of this object has commenced */
045      private static final byte FORWARDED =       3; // ...11
046      /** This mask is used to reveal which state this object is in with respect to forwarding */
047      public static final byte FORWARDING_MASK =  3; // ...11
048    
049      public static final int FORWARDING_BITS = 2;
050    
051    
052      /**
053       * Either return the forwarding pointer if the object is already
054       * forwarded (or being forwarded) or write the bit pattern that
055       * indicates that the object is being forwarded
056       *
057       * @param object The object to be forwarded
058       * @return The forwarding pointer for the object if it has already
059       * been forwarded.
060       */
061      @Inline
062      public static Word attemptToForward(ObjectReference object) {
063        Word oldValue;
064        do {
065          oldValue = VM.objectModel.prepareAvailableBits(object);
066          if ((byte) (oldValue.toInt() & FORWARDING_MASK) == FORWARDED)
067            return oldValue;
068        } while (!VM.objectModel.attemptAvailableBits(object, oldValue,
069                                                      oldValue.or(Word.fromIntZeroExtend(BEING_FORWARDED))));
070        return oldValue;
071      }
072    
073      public static ObjectReference spinAndGetForwardedObject(ObjectReference object, Word statusWord) {
074        /* We must wait (spin) if the object is not yet fully forwarded */
075        while ((statusWord.toInt() & FORWARDING_MASK) == BEING_FORWARDED)
076          statusWord = VM.objectModel.readAvailableBitsWord(object);
077    
078        /* Now extract the object reference from the forwarding word and return it */
079        if ((statusWord.toInt() & FORWARDING_MASK) == FORWARDED)
080          return statusWord.and(Word.fromIntZeroExtend(FORWARDING_MASK).not()).toAddress().toObjectReference();
081        else
082          return object;
083      }
084    
085      public static ObjectReference forwardObject(ObjectReference object, int allocator) {
086        ObjectReference newObject = VM.objectModel.copy(object, allocator);
087        VM.objectModel.writeAvailableBitsWord(object, newObject.toAddress().toWord().or(Word.fromIntZeroExtend(FORWARDED)));
088        return newObject;
089      }
090    
091      /**
092       * Non-atomic write of forwarding pointer word (assumption, thread
093       * doing the set has done attempt to forward and owns the right to
094       * copy the object)
095       *
096       * @param object The object whose forwarding pointer is to be set
097       * @param ptr The forwarding pointer to be stored in the object's
098       * forwarding word
099       */
100      @Inline
101      public static void setForwardingPointer(ObjectReference object,
102                                               ObjectReference ptr) {
103        VM.objectModel.writeAvailableBitsWord(object, ptr.toAddress().toWord().or(Word.fromIntZeroExtend(FORWARDED)));
104      }
105    
106      /**
107       * Has an object been forwarded?
108       *
109       * @param object The object to be checked
110       * @return {@code true} if the object has been forwarded
111       */
112      @Inline
113      public static boolean isForwarded(ObjectReference object) {
114        return (VM.objectModel.readAvailableByte(object) & FORWARDING_MASK) == FORWARDED;
115      }
116    
117      /**
118       * Has an object been forwarded or is it being forwarded?
119       *
120       * @param object The object to be checked
121       * @return {@code true} if the object has been forwarded
122       */
123      @Inline
124      public static boolean isForwardedOrBeingForwarded(ObjectReference object) {
125        return (VM.objectModel.readAvailableByte(object) & FORWARDING_MASK) != 0;
126      }
127    
128      /**
129       * Has an object been forwarded or being forwarded?
130       *
131       * @param header The object header to be checked
132       * @return {@code true} if the object has been forwarded
133       */
134      @Inline
135      public static boolean stateIsForwardedOrBeingForwarded(Word header) {
136        return (header.toInt() & FORWARDING_MASK) != 0;
137      }
138    
139      /**
140       * Has an object been forwarded or being forwarded?
141       *
142       * @param header The object header to be checked
143       * @return {@code true} if the object has been forwarded
144       */
145      @Inline
146      public static boolean stateIsBeingForwarded(Word header) {
147        return (header.toInt() & FORWARDING_MASK) == BEING_FORWARDED;
148      }
149    
150      /**
151       * Clear the GC forwarding portion of the header for an object.
152       *
153       * @param object the object ref to the storage to be initialized
154       */
155      @Inline
156      public static void clearForwardingBits(ObjectReference object) {
157        VM.objectModel.writeAvailableByte(object, (byte) (VM.objectModel.readAvailableByte(object) & ~FORWARDING_MASK));
158      }
159    
160      @Inline
161      public static ObjectReference extractForwardingPointer(Word forwardingWord) {
162        return forwardingWord.and(Word.fromIntZeroExtend(FORWARDING_MASK).not()).toAddress().toObjectReference();
163      }
164    }