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.policy.immix;
014    
015    import org.mmtk.utility.ForwardingWord;
016    import org.mmtk.utility.HeaderByte;
017    import org.mmtk.vm.VM;
018    import org.vmmagic.pragma.Inline;
019    import org.vmmagic.pragma.Uninterruptible;
020    import org.vmmagic.unboxed.ObjectReference;
021    
022    @Uninterruptible
023    public class ObjectHeader {
024      /** number of header bits we may use */
025      static final int AVAILABLE_LOCAL_BITS = 8 - HeaderByte.USED_GLOBAL_BITS;
026    
027      /* header requirements */
028      public static final int LOCAL_GC_BITS_REQUIRED = AVAILABLE_LOCAL_BITS;
029      public static final int GLOBAL_GC_BITS_REQUIRED = 0;
030      public static final int GC_HEADER_WORDS_REQUIRED = 0;
031    
032      /* local status bits */
033      static final byte NEW_OBJECT_MARK = 0; // using zero means no need for explicit initialization on allocation
034    
035      public static final int PINNED_BIT_NUMBER = ForwardingWord.FORWARDING_BITS;
036      public static final byte PINNED_BIT = 1<<PINNED_BIT_NUMBER;
037    
038      private static final int STRADDLE_BIT_NUMBER = PINNED_BIT_NUMBER + 1;
039      public static final byte STRADDLE_BIT = 1<<STRADDLE_BIT_NUMBER;
040    
041      /* mark bits */
042      private static final int  MARK_BASE = STRADDLE_BIT_NUMBER+1;
043      static final int  MAX_MARKCOUNT_BITS = AVAILABLE_LOCAL_BITS-MARK_BASE;
044      private static final byte MARK_INCREMENT = 1<<MARK_BASE;
045      public static final byte MARK_MASK = (byte) (((1<<MAX_MARKCOUNT_BITS)-1)<<MARK_BASE);
046      private static final byte MARK_AND_FORWARDING_MASK = (byte) (MARK_MASK | ForwardingWord.FORWARDING_MASK);
047      public static final byte MARK_BASE_VALUE = MARK_INCREMENT;
048    
049    
050      /****************************************************************************
051       *
052       * Marking
053       */
054    
055      /**
056       * Non-atomically test and set the mark bit of an object.  Return true
057       * if successful, false if the mark bit was already set.
058       *
059       * @param object The object whose mark bit is to be written
060       * @param markState The value to which the mark bits will be set
061       */
062      static byte testAndMark(ObjectReference object, byte markState) {
063        byte oldValue, newValue, oldMarkState;
064    
065        oldValue = VM.objectModel.readAvailableByte(object);
066        oldMarkState = (byte) (oldValue & MARK_MASK);
067        if (oldMarkState != markState) {
068          newValue = (byte) ((oldValue & ~MARK_MASK) | markState);
069          if (HeaderByte.NEEDS_UNLOGGED_BIT)
070            newValue |= HeaderByte.UNLOGGED_BIT;
071          VM.objectModel.writeAvailableByte(object, newValue);
072        }
073        return oldMarkState;
074      }
075    
076      static void setMarkStateUnlogAndUnlock(ObjectReference object, byte originalHeaderByte, byte markState) {
077        byte oldValue = originalHeaderByte;
078        byte newValue = (byte) ((oldValue & ~MARK_AND_FORWARDING_MASK) | markState);
079        if (HeaderByte.NEEDS_UNLOGGED_BIT)
080          newValue |= HeaderByte.UNLOGGED_BIT;
081        VM.objectModel.writeAvailableByte(object, newValue);
082        if (VM.VERIFY_ASSERTIONS)
083          VM.assertions._assert((oldValue & MARK_MASK) != markState);
084      }
085    
086      /**
087       * Return true if the mark count for an object has the given value.
088       *
089       * @param object The object whose mark bit is to be tested
090       * @param value The value against which the mark bit will be tested
091       * @return True if the mark bit for the object has the given value.
092       */
093      static boolean testMarkState(ObjectReference object, byte value) {
094        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((value & MARK_MASK) == value);
095        return (VM.objectModel.readAvailableByte(object) & MARK_MASK) == value;
096       }
097    
098      static boolean testMarkState(byte forwardingWord, byte value) {
099        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((value & MARK_MASK) == value);
100        return (forwardingWord & MARK_MASK) == value;
101      }
102    
103      static boolean isNewObject(ObjectReference object) {
104        return (VM.objectModel.readAvailableByte(object) & MARK_AND_FORWARDING_MASK) == NEW_OBJECT_MARK;
105      }
106    
107      static boolean isMatureObject(ObjectReference object) {
108        byte status = (byte) (VM.objectModel.readAvailableByte(object) & MARK_AND_FORWARDING_MASK);
109        boolean unforwarded = (status & ForwardingWord.FORWARDING_MASK) == 0;
110        boolean newObj = (status == NEW_OBJECT_MARK);
111        return unforwarded && !newObj;
112      }
113    
114      @Inline
115      static void markAsStraddling(ObjectReference object) {
116        byte old = VM.objectModel.readAvailableByte(object);
117        VM.objectModel.writeAvailableByte(object, (byte) (old | STRADDLE_BIT));
118      }
119    
120      @Inline
121      static boolean isStraddlingObject(ObjectReference object) {
122        return (VM.objectModel.readAvailableByte(object) & STRADDLE_BIT) == STRADDLE_BIT;
123      }
124    
125      @Inline
126      public static void pinObject(ObjectReference object) {
127        byte old = VM.objectModel.readAvailableByte(object);
128        VM.objectModel.writeAvailableByte(object, (byte) (old | PINNED_BIT));
129      }
130    
131      @Inline
132      static boolean isPinnedObject(ObjectReference object) {
133        return (VM.objectModel.readAvailableByte(object) & PINNED_BIT) == PINNED_BIT;
134      }
135    
136      /**
137       * Write the allocState into the mark state fields of an object non-atomically.
138       * This is appropriate for collection time initialization.
139       *
140       * @param object The object whose mark state is to be written
141       * @param markState TODO: what am I?
142       * @param straddle TODO: what am I?
143       */
144      static void writeMarkState(ObjectReference object, byte markState, boolean straddle) {
145        byte oldValue = VM.objectModel.readAvailableByte(object);
146        byte markValue = markState;
147        byte newValue = (byte) (oldValue & ~MARK_AND_FORWARDING_MASK);
148        if (HeaderByte.NEEDS_UNLOGGED_BIT)
149          newValue |= HeaderByte.UNLOGGED_BIT;
150        newValue |= markValue;
151        if (straddle)
152          newValue |= STRADDLE_BIT;
153        VM.objectModel.writeAvailableByte(object, newValue);
154      }
155    
156      static void returnToPriorStateAndEnsureUnlogged(ObjectReference object, byte status) {
157        if (HeaderByte.NEEDS_UNLOGGED_BIT) status |= HeaderByte.UNLOGGED_BIT;
158        VM.objectModel.writeAvailableByte(object, status);
159      }
160    
161      /**
162       * Return the mark state incremented or decremented by one.
163       *
164       * @param increment If true, then return the incremented value else return the decremented value
165       * @return the mark state incremented or decremented by one.
166       */
167      static byte deltaMarkState(byte state, boolean increment) {
168        byte rtn = state;
169        do {
170          rtn = (byte) (increment ? rtn + MARK_INCREMENT : rtn - MARK_INCREMENT);
171          rtn &= MARK_MASK;
172          } while (rtn < MARK_BASE_VALUE);
173        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(rtn != state);
174        return rtn;
175      }
176    }