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