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;
014
015import static org.mmtk.utility.Constants.*;
016
017import org.mmtk.plan.Plan;
018import org.mmtk.plan.TransitiveClosure;
019import org.mmtk.utility.heap.MonotonePageResource;
020import org.mmtk.utility.heap.VMRequest;
021import org.mmtk.utility.HeaderByte;
022
023import org.mmtk.vm.VM;
024
025import org.vmmagic.unboxed.*;
026import org.vmmagic.pragma.*;
027
028/**
029 * This class implements tracing for a simple immortal collection
030 * policy.  Under this policy all that is required is for the
031 * "collector" to propagate marks in a liveness trace.  It does not
032 * actually collect.  This class does not hold any state, all methods
033 * are static.
034 */
035@Uninterruptible public final class ImmortalSpace extends Space {
036
037  /****************************************************************************
038   *
039   * Class variables
040   */
041
042  /**
043   *
044   */
045  static final byte GC_MARK_BIT_MASK = 1;
046  private static final int META_DATA_PAGES_PER_REGION = CARD_META_PAGES_PER_REGION;
047
048  /****************************************************************************
049   *
050   * Instance variables
051   */
052
053  /**
054   *
055   */
056  private byte markState = 0; // when GC off, the initialization value
057
058  /****************************************************************************
059   *
060   * Initialization
061   */
062
063  /**
064   * The caller specifies the region of virtual memory to be used for
065   * this space.  If this region conflicts with an existing space,
066   * then the constructor will fail.
067   *
068   * @param name The name of this space (used when printing error messages etc)
069   * @param vmRequest An object describing the virtual memory requested.
070   */
071  public ImmortalSpace(String name, VMRequest vmRequest) {
072    this(name, true, vmRequest);
073  }
074
075  /**
076   * The caller specifies the region of virtual memory to be used for
077   * this space.  If this region conflicts with an existing space,
078   * then the constructor will fail.
079   *
080   * @param name The name of this space (used when printing error messages etc)
081   * @param zeroed if true, allocations return zeroed memory.
082   * @param vmRequest An object describing the virtual memory requested.
083   */
084  public ImmortalSpace(String name, boolean zeroed, VMRequest vmRequest) {
085    super(name, false, true, zeroed, vmRequest);
086    if (vmRequest.isDiscontiguous()) {
087      pr = new MonotonePageResource(this, META_DATA_PAGES_PER_REGION);
088    } else {
089      pr = new MonotonePageResource(this, start, extent, META_DATA_PAGES_PER_REGION);
090    }
091  }
092
093  /** @return the current mark state */
094  @Inline
095  public Word getMarkState() {
096    return Word.fromIntZeroExtend(markState);
097  }
098
099  /****************************************************************************
100   *
101   * Object header manipulations
102   */
103
104  /**
105   * Initialize the object header post-allocation.  We need to set the mark state
106   * correctly and set the logged bit if necessary.
107   *
108   * @param object The newly allocated object instance whose header we are initializing
109   */
110  public void initializeHeader(ObjectReference object) {
111    byte oldValue = VM.objectModel.readAvailableByte(object);
112    byte newValue = (byte) ((oldValue & GC_MARK_BIT_MASK) | markState);
113    if (HeaderByte.NEEDS_UNLOGGED_BIT) newValue |= HeaderByte.UNLOGGED_BIT;
114    VM.objectModel.writeAvailableByte(object, newValue);
115  }
116
117  /**
118   * Used to mark boot image objects during a parallel scan of objects during GC.
119   *
120   * @param object the object to mark
121   * @param value the mark value
122   * @return {@code true} if marking was done.
123   */
124  @Inline
125  private static boolean testAndMark(ObjectReference object, byte value) {
126    Word oldValue;
127    do {
128      oldValue = VM.objectModel.prepareAvailableBits(object);
129      byte markBit = (byte) (oldValue.toInt() & GC_MARK_BIT_MASK);
130      if (markBit == value) return false;
131    } while (!VM.objectModel.attemptAvailableBits(object, oldValue,
132        oldValue.xor(Word.fromIntZeroExtend(GC_MARK_BIT_MASK))));
133    return true;
134  }
135
136  /**
137   * Trace a reference to an object under an immortal collection
138   * policy.  If the object is not already marked, enqueue the object
139   * for subsequent processing. The object is marked as (an atomic)
140   * side-effect of checking whether already marked.
141   *
142   * @param trace The trace being conducted.
143   * @param object The object to be traced.
144   */
145  @Override
146  @Inline
147  public ObjectReference traceObject(TransitiveClosure trace, ObjectReference object) {
148    if (testAndMark(object, markState))
149      trace.processNode(object);
150    return object;
151  }
152
153  /**
154   * Prepare for a new collection increment.  For the immortal
155   * collector we must flip the state of the mark bit between
156   * collections.
157   */
158  public void prepare() {
159    markState = (byte) (GC_MARK_BIT_MASK - markState);
160  }
161
162  public void release() {}
163
164  /**
165   * Release an allocated page or pages.  In this case we do nothing
166   * because we only release pages enmasse.
167   *
168   * @param start The address of the start of the page or pages
169   */
170  @Override
171  @Inline
172  public void release(Address start) {
173    if (VM.VERIFY_ASSERTIONS)
174      VM.assertions._assert(false); // this policy only releases pages enmasse
175  }
176
177  @Override
178  @Inline
179  public boolean isLive(ObjectReference object) {
180    return true;
181  }
182
183  /**
184   * Returns if the object in question is currently thought to be reachable.
185   * This is done by comparing the mark bit to the current mark state. For the
186   * immortal collector reachable and live are different, making this method
187   * necessary.
188   *
189   * @param object The address of an object in immortal space to test
190   * @return <code>true</code> if <code>ref</code> may be a reachable object (e.g., having
191   *         the current mark state).  While all immortal objects are live,
192   *         some may be unreachable.
193   */
194  @Override
195  public boolean isReachable(ObjectReference object) {
196    if (Plan.SCAN_BOOT_IMAGE && this == Plan.vmSpace)
197      return true;  // ignore boot image "reachabilty" if we're not tracing it
198    else
199      return (VM.objectModel.readAvailableByte(object) & GC_MARK_BIT_MASK) == markState;
200  }
201}