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.policy.immix;
014
015import org.mmtk.utility.ForwardingWord;
016import org.mmtk.utility.HeaderByte;
017import org.mmtk.vm.VM;
018import org.vmmagic.pragma.Inline;
019import org.vmmagic.pragma.Uninterruptible;
020import org.vmmagic.unboxed.ObjectReference;
021
022@Uninterruptible
023public 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 state the mark state
173   * @param increment If {@code true}, then return the incremented value else return the decremented value
174   * @return the mark state incremented or decremented by one.
175   */
176  static byte deltaMarkState(byte state, boolean increment) {
177    byte rtn = state;
178    do {
179      rtn = (byte) (increment ? rtn + MARK_INCREMENT : rtn - MARK_INCREMENT);
180      rtn &= MARK_MASK;
181      } while (rtn < MARK_BASE_VALUE);
182    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(rtn != state);
183    return rtn;
184  }
185}