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