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.stickyms;
014
015import org.mmtk.plan.TransitiveClosure;
016import org.mmtk.plan.marksweep.MS;
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.sanitychecker.SanityChecker;
022import org.mmtk.vm.VM;
023
024import org.vmmagic.pragma.*;
025import org.vmmagic.unboxed.ObjectReference;
026
027/**
028 * This class implements the global state of a simple sticky mark bits collector,
029 * based a simple on mark-sweep collector.  The sticky mark bits algorithm is
030 * due to Demmers et al. (http://doi.acm.org/10.1145/96709.96735), and allows
031 * generational collection to be performed in a non-moving heap by overloading
032 * the role of mark bits to also indicate whether an object is new (nursery) or
033 * not.  Thus nursery objects are identified by a bit in their header, not by
034 * where they lie within the address space.  While Demmers et al. did their work
035 * in a conservative collector, here we have an exact collector, so we can use
036 * a regular write barrier, and don't need to use page protection etc.<p>
037 *
038 * All plans make a clear distinction between <i>global</i> and
039 * <i>thread-local</i> activities, and divides global and local state
040 * into separate class hierarchies.  Global activities must be
041 * synchronized, whereas no synchronization is required for
042 * thread-local activities.  There is a single instance of Plan (or the
043 * appropriate sub-class), and a 1:1 mapping of PlanLocal to "kernel
044 * threads" (aka CPUs or in Jikes RVM, Processors).  Thus instance
045 * methods of PlanLocal allow fast, unsychronized access to functions such as
046 * allocation and collection.<p>
047 *
048 * The global instance defines and manages static resources
049 * (such as memory and virtual memory resources).  This mapping of threads to
050 * instances is crucial to understanding the correctness and
051 * performance properties of MMTk plans.
052 */
053@Uninterruptible
054public class StickyMS extends MS {
055
056  /****************************************************************************
057   * Constants
058   */
059
060  /** If {@code true}, then new PLOS objects are collected at each nursery GC */
061  static final boolean NURSERY_COLLECT_PLOS = true;
062  /** If {@code true} then we only do full heap GCs---so we're like MarkSweep (+ write barrier) */
063  static final boolean MAJOR_GC_ONLY = false;
064
065  /****************************************************************************
066   * Class variables
067   */
068
069  /**
070   *
071   */
072  public static int SCAN_NURSERY = 1;
073
074  /****************************************************************************
075   * Instance variables
076   */
077
078  /* status fields */
079
080  /** will the next collection collect the whole heap? */
081  public boolean nextGCWholeHeap = false;
082  /** will this collection collect the whole heap */
083  public boolean collectWholeHeap = nextGCWholeHeap;
084
085  /** Remset pool */
086  public final SharedDeque modPool = new SharedDeque("msgen mod objects", metaDataSpace, 1);
087
088  /****************************************************************************
089   * Static initialization
090   */
091  {
092    msSpace.makeAgeSegregatedSpace();  /* this space is to be collected generationally */
093  }
094
095  /*****************************************************************************
096   *
097   * Collection
098   */
099
100  /**
101   * A user-triggered GC has been initiated.
102   */
103  public void userTriggeredGC() {
104    nextGCWholeHeap |= Options.fullHeapSystemGC.getValue();
105  }
106
107  @Override
108  public void forceFullHeapCollection() {
109    nextGCWholeHeap = true;
110  }
111
112  @Inline
113  @Override
114  public final void collectionPhase(short phaseId) {
115
116    if (phaseId == INITIATE) {
117      collectWholeHeap = MAJOR_GC_ONLY || emergencyCollection || nextGCWholeHeap;
118      nextGCWholeHeap = false;
119      super.collectionPhase(phaseId);
120      return;
121    }
122
123    if (!collectWholeHeap) {
124      if (phaseId == PREPARE) {
125        msTrace.prepare();
126        msSpace.prepare(false);
127        return;
128      }
129
130      if (phaseId == RELEASE) {
131        msTrace.release();
132        msSpace.release();
133        modPool.reset();
134        nextGCWholeHeap = (getPagesAvail() < Options.nurserySize.getMinNursery());
135        return;
136      }
137    }
138
139    super.collectionPhase(phaseId);
140  }
141
142  /*****************************************************************************
143   *
144   * Accounting
145   */
146
147  /**
148   * {@inheritDoc}
149   * In this class we prefix the output
150   * indicating whether the collection was full heap or not.
151   */
152  @Override
153  public void printPreStats() {
154    if ((Options.verbose.getValue() >= 1) && (collectWholeHeap))
155      Log.write("[Full heap]");
156    super.printPreStats();
157  }
158
159  @Override
160  public final boolean isCurrentGCNursery() {
161    return !collectWholeHeap;
162  }
163
164  /**
165   * @return Is last GC a full collection?
166   */
167  public final boolean isLastGCFull() {
168    return collectWholeHeap;
169  }
170
171  @Override
172  public int sanityExpectedRC(ObjectReference object, int sanityRootRC) {
173    Space space = Space.getSpaceForObject(object);
174
175    // Immortal spaces
176    if (space == StickyMS.immortalSpace || space == StickyMS.vmSpace) {
177      return space.isReachable(object) ? SanityChecker.ALIVE : SanityChecker.DEAD;
178    }
179
180    // Mature space (nursery collection)
181    if (VM.activePlan.global().isCurrentGCNursery() && space != StickyMS.msSpace) {
182      return SanityChecker.UNSURE;
183    }
184
185    return super.sanityExpectedRC(object, sanityRootRC);
186  }
187
188  @Override
189  @Interruptible
190  protected void registerSpecializedMethods() {
191    TransitiveClosure.registerSpecializedScan(SCAN_NURSERY, StickyMSNurseryTraceLocal.class);
192    super.registerSpecializedMethods();
193  }
194}