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.plan.stickyimmix;
014
015import org.mmtk.plan.TransitiveClosure;
016import org.mmtk.plan.immix.Immix;
017import org.mmtk.policy.Space;
018import org.mmtk.utility.Log;
019import org.mmtk.utility.deque.SharedDeque;
020import org.mmtk.utility.options.Options;
021import org.mmtk.utility.statistics.BooleanCounter;
022import org.mmtk.utility.statistics.Stats;
023
024import org.vmmagic.pragma.*;
025
026/**
027 * This class implements the global state of a simple sticky mark bits collector,
028 * based on an immix collector.  The sticky mark bits algorithm is
029 * due to Demmers et al. (http://doi.acm.org/10.1145/96709.96735), and allows
030 * generational collection to be performed in a non-moving heap by overloading
031 * the role of mark bits to also indicate whether an object is new (nursery) or
032 * not.  Thus nursery objects are identified by a bit in their header, not by
033 * where they lie within the address space.  While Demmers et al. did their work
034 * in a conservative collector, here we have an exact collector, so we can use
035 * a regular write barrier, and don't need to use page protection etc.<p>
036 *
037 * See the PLDI'08 paper by Blackburn and McKinley for a description
038 * of the algorithm: http://doi.acm.org/10.1145/1375581.1375586<p>
039 *
040 * All plans make a clear distinction between <i>global</i> and
041 * <i>thread-local</i> activities, and divides global and local state
042 * into separate class hierarchies.  Global activities must be
043 * synchronized, whereas no synchronization is required for
044 * thread-local activities.  There is a single instance of Plan (or the
045 * appropriate sub-class), and a 1:1 mapping of PlanLocal to "kernel
046 * threads" (aka CPUs or in Jikes RVM, Processors).  Thus instance
047 * methods of PlanLocal allow fast, unsychronized access to functions such as
048 * allocation and collection.<p>
049 *
050 * The global instance defines and manages static resources
051 * (such as memory and virtual memory resources).  This mapping of threads to
052 * instances is crucial to understanding the correctness and
053 * performance properties of MMTk plans.
054 */
055@Uninterruptible
056public class StickyImmix extends Immix {
057
058  /****************************************************************************
059   * Constants
060   */
061
062  /** If true, then new PLOS objects are collected at each nursery GC */
063  static final boolean NURSERY_COLLECT_PLOS = true;
064  /** If true then we only do full heap GCs---so we're like MarkSweep (+ write barrier) */
065  static final boolean MAJOR_GC_ONLY = false;
066  /** estimated collection yield */
067  protected static final float SURVIVAL_ESTIMATE = (float) 0.8;
068
069  public static int SCAN_NURSERY = 2;
070
071  /****************************************************************************
072   * Class variables
073   */
074
075  /**
076   * TODO: this field is unused, somebody with MMTk knowledge needs to look at it
077   */
078  private static int lastCommittedImmixPages = 0;
079
080  /* statistics */
081  public static BooleanCounter fullHeap = new BooleanCounter("majorGC", true, true);
082
083  /****************************************************************************
084   * Instance variables
085   */
086
087  /** Remset pool */
088  public final SharedDeque modPool = new SharedDeque("msgen mod objects", metaDataSpace, 1);
089
090  /**
091   * Constructor.
092   *
093   */
094  public StickyImmix() {
095    collectWholeHeap = nextGCWholeHeap = false;
096  }
097
098  /*****************************************************************************
099   *
100   * Collection
101   */
102
103  /**
104   * A user-triggered GC has been initiated.
105   */
106  public void userTriggeredGC() {
107    nextGCWholeHeap |= Options.fullHeapSystemGC.getValue();
108  }
109
110  @Override
111  public void forceFullHeapCollection() {
112    nextGCWholeHeap = true;
113  }
114
115  @Inline
116  @Override
117  public final void collectionPhase(short phaseId) {
118
119    if (phaseId == SET_COLLECTION_KIND) {
120      super.collectionPhase(phaseId);
121      collectWholeHeap = requiresFullHeapCollection();
122      if (Stats.gatheringStats() && collectWholeHeap) fullHeap.set();
123      return;
124    }
125
126    if (!collectWholeHeap && phaseId == PREPARE) {
127      immixTrace.prepare();
128      immixSpace.prepare(false);
129      return;
130    }
131
132    if (phaseId == RELEASE) {
133      if (collectWholeHeap) {
134        super.collectionPhase(RELEASE);
135      } else {
136        immixTrace.release();
137        lastGCWasDefrag = immixSpace.release(false);
138      }
139      modPool.reset();
140      lastCommittedImmixPages = immixSpace.committedPages();
141      nextGCWholeHeap = (getPagesAvail() < Options.nurserySize.getMinNursery());
142      return;
143    }
144
145    super.collectionPhase(phaseId);
146  }
147
148  /*****************************************************************************
149   *
150   * Accounting
151   */
152
153  /**
154   * {@inheritDoc}
155   */
156  @Override
157  public final boolean collectionRequired(boolean spaceFull, Space space) {
158    boolean nurseryFull = immixSpace.getPagesAllocated() > Options.nurserySize.getMaxNursery();
159    if (spaceFull && space != immixSpace) nextGCWholeHeap = true;
160    return super.collectionRequired(spaceFull, space) || nurseryFull;
161  }
162
163  /**
164   * Determine whether this GC should be a full heap collection.
165   *
166   * @return True if this GC should be a full heap collection.
167   */
168  protected boolean requiresFullHeapCollection() {
169    if (userTriggeredCollection && Options.fullHeapSystemGC.getValue()) {
170      return true;
171    }
172
173    if (nextGCWholeHeap || collectionAttempt > 1) {
174      // Forces full heap collection
175      return true;
176    }
177
178    return false;
179  }
180
181  @Override
182  public int getCollectionReserve() {
183    return super.getCollectionReserve() + immixSpace.defragHeadroomPages();
184  }
185
186  /**
187   * {@inheritDoc}
188   * In this class we prefix the output
189   * indicating whether the collection was full heap or not.
190   */
191  @Override
192  public void printPreStats() {
193    if ((Options.verbose.getValue() >= 1) && (collectWholeHeap))
194      Log.write("[Full heap]");
195    super.printPreStats();
196  }
197
198  @Override
199  public final boolean isCurrentGCNursery() {
200    return !collectWholeHeap;
201  }
202
203  public final boolean isLastGCFull() {
204    return collectWholeHeap;
205  }
206
207  @Override
208  @Interruptible
209  protected void registerSpecializedMethods() {
210    TransitiveClosure.registerSpecializedScan(SCAN_NURSERY, StickyImmixNurseryTraceLocal.class);
211    super.registerSpecializedMethods();
212  }
213}