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;
014
015import org.mmtk.policy.Space;
016import org.mmtk.utility.Log;
017import org.mmtk.utility.alloc.Allocator;
018import org.mmtk.utility.options.*;
019import org.mmtk.utility.statistics.Timer;
020import org.mmtk.vm.VM;
021
022import org.vmmagic.pragma.*;
023
024/**
025 * This abstract class implements the core functionality for
026 * simple collectors.<p>
027 *
028 * This class defines the collection phases, and provides base
029 * level implementations of them.  Subclasses should provide
030 * implementations for the spaces that they introduce, and
031 * delegate up the class hierarchy.<p>
032 *
033 * For details of the split between global and thread-local operations
034 * @see org.mmtk.plan.Plan
035 */
036@Uninterruptible
037public abstract class Simple extends Plan {
038  /****************************************************************************
039   * Constants
040   */
041
042  /* Shared Timers */
043  private static final Timer refTypeTime = new Timer("refType", false, true);
044  private static final Timer scanTime = new Timer("scan", false, true);
045  private static final Timer finalizeTime = new Timer("finalize", false, true);
046
047  /* Phases */
048  public static final short SET_COLLECTION_KIND = Phase.createSimple("set-collection-kind", null);
049  public static final short INITIATE            = Phase.createSimple("initiate", null);
050  public static final short PREPARE             = Phase.createSimple("prepare");
051  public static final short PREPARE_STACKS      = Phase.createSimple("prepare-stacks", null);
052  public static final short STACK_ROOTS         = Phase.createSimple("stacks");
053  public static final short ROOTS               = Phase.createSimple("root");
054  public static final short CLOSURE             = Phase.createSimple("closure", scanTime);
055  public static final short SOFT_REFS           = Phase.createSimple("soft-ref", refTypeTime);
056  public static final short WEAK_REFS           = Phase.createSimple("weak-ref", refTypeTime);
057  public static final short FINALIZABLE         = Phase.createSimple("finalize", finalizeTime);
058  public static final short WEAK_TRACK_REFS     = Phase.createSimple("weak-track-ref", refTypeTime);
059  public static final short PHANTOM_REFS        = Phase.createSimple("phantom-ref", refTypeTime);
060  public static final short FORWARD             = Phase.createSimple("forward");
061  public static final short FORWARD_REFS        = Phase.createSimple("forward-ref", refTypeTime);
062  public static final short FORWARD_FINALIZABLE = Phase.createSimple("forward-finalize", finalizeTime);
063  public static final short RELEASE             = Phase.createSimple("release");
064  public static final short COMPLETE            = Phase.createSimple("complete", null);
065
066  /* Sanity placeholder */
067  public static final short PRE_SANITY_PLACEHOLDER  = Phase.createSimple("pre-sanity-placeholder", null);
068  public static final short POST_SANITY_PLACEHOLDER = Phase.createSimple("post-sanity-placeholder", null);
069
070  /* Sanity phases */
071  public static final short SANITY_SET_PREGC    = Phase.createSimple("sanity-setpre", null);
072  public static final short SANITY_SET_POSTGC   = Phase.createSimple("sanity-setpost", null);
073  public static final short SANITY_PREPARE      = Phase.createSimple("sanity-prepare", null);
074  public static final short SANITY_ROOTS        = Phase.createSimple("sanity-roots", null);
075  public static final short SANITY_COPY_ROOTS   = Phase.createSimple("sanity-copy-roots", null);
076  public static final short SANITY_BUILD_TABLE  = Phase.createSimple("sanity-build-table", null);
077  public static final short SANITY_CHECK_TABLE  = Phase.createSimple("sanity-check-table", null);
078  public static final short SANITY_RELEASE      = Phase.createSimple("sanity-release", null);
079
080  // CHECKSTYLE:OFF
081
082  /** Ensure stacks are ready to be scanned */
083  protected static final short prepareStacks = Phase.createComplex("prepare-stacks", null,
084      Phase.scheduleMutator    (PREPARE_STACKS),
085      Phase.scheduleGlobal     (PREPARE_STACKS));
086
087  /** Trace and set up a sanity table */
088  protected static final short sanityBuildPhase = Phase.createComplex("sanity-build", null,
089      Phase.scheduleGlobal     (SANITY_PREPARE),
090      Phase.scheduleCollector  (SANITY_PREPARE),
091      Phase.scheduleComplex    (prepareStacks),
092      Phase.scheduleCollector  (SANITY_ROOTS),
093      Phase.scheduleGlobal     (SANITY_ROOTS),
094      Phase.scheduleCollector  (SANITY_COPY_ROOTS),
095      Phase.scheduleGlobal     (SANITY_BUILD_TABLE));
096
097  /** Validate a sanity table */
098  protected static final short sanityCheckPhase = Phase.createComplex("sanity-check", null,
099      Phase.scheduleGlobal     (SANITY_CHECK_TABLE),
100      Phase.scheduleCollector  (SANITY_RELEASE),
101      Phase.scheduleGlobal     (SANITY_RELEASE));
102
103  /** Start the collection, including preparation for any collected spaces. */
104  protected static final short initPhase = Phase.createComplex("init",
105      Phase.scheduleGlobal     (SET_COLLECTION_KIND),
106      Phase.scheduleGlobal     (INITIATE),
107      Phase.schedulePlaceholder(PRE_SANITY_PLACEHOLDER));
108
109  /**
110   * Perform the initial determination of liveness from the roots.
111   */
112  protected static final short rootClosurePhase = Phase.createComplex("initial-closure", null,
113      Phase.scheduleMutator    (PREPARE),
114      Phase.scheduleGlobal     (PREPARE),
115      Phase.scheduleCollector  (PREPARE),
116      Phase.scheduleComplex    (prepareStacks),
117      Phase.scheduleCollector  (STACK_ROOTS),
118      Phase.scheduleGlobal     (STACK_ROOTS),
119      Phase.scheduleCollector  (ROOTS),
120      Phase.scheduleGlobal     (ROOTS),
121      Phase.scheduleGlobal     (CLOSURE),
122      Phase.scheduleCollector  (CLOSURE));
123
124  /**
125   * Complete closure including reference types and finalizable objects.
126   */
127  protected static final short refTypeClosurePhase = Phase.createComplex("refType-closure", null,
128      Phase.scheduleCollector  (SOFT_REFS),
129      Phase.scheduleGlobal     (CLOSURE),
130      Phase.scheduleCollector  (CLOSURE),
131      Phase.scheduleCollector  (WEAK_REFS),
132      Phase.scheduleCollector  (FINALIZABLE),
133      Phase.scheduleGlobal     (CLOSURE),
134      Phase.scheduleCollector  (CLOSURE),
135      Phase.schedulePlaceholder(WEAK_TRACK_REFS),
136      Phase.scheduleCollector  (PHANTOM_REFS));
137
138  /**
139   * Ensure that all references in the system are correct.
140   */
141  protected static final short forwardPhase = Phase.createComplex("forward-all", null,
142      /* Finish up */
143      Phase.schedulePlaceholder(FORWARD),
144      Phase.scheduleCollector  (FORWARD_REFS),
145      Phase.scheduleCollector  (FORWARD_FINALIZABLE));
146
147  /**
148   * Complete closure including reference types and finalizable objects.
149   */
150  protected static final short completeClosurePhase = Phase.createComplex("release", null,
151      Phase.scheduleMutator    (RELEASE),
152      Phase.scheduleCollector  (RELEASE),
153      Phase.scheduleGlobal     (RELEASE));
154
155
156  /**
157   * The collection scheme - this is a small tree of complex phases.
158   */
159  protected static final short finishPhase = Phase.createComplex("finish",
160      Phase.schedulePlaceholder(POST_SANITY_PLACEHOLDER),
161      Phase.scheduleCollector  (COMPLETE),
162      Phase.scheduleGlobal     (COMPLETE));
163
164  /**
165   * This is the phase that is executed to perform a collection.
166   */
167  public short collection = Phase.createComplex("collection", null,
168      Phase.scheduleComplex(initPhase),
169      Phase.scheduleComplex(rootClosurePhase),
170      Phase.scheduleComplex(refTypeClosurePhase),
171      Phase.scheduleComplex(forwardPhase),
172      Phase.scheduleComplex(completeClosurePhase),
173      Phase.scheduleComplex(finishPhase));
174
175  // CHECKSTYLE:ON
176
177  /**
178   * The current collection attempt.
179   */
180  protected int collectionAttempt;
181
182  /****************************************************************************
183   * Collection
184   */
185
186  /**
187   * {@inheritDoc}
188   */
189  @Override
190  @Inline
191  public void collectionPhase(short phaseId) {
192    if (phaseId == SET_COLLECTION_KIND) {
193      collectionAttempt = Plan.isUserTriggeredCollection() ? 1 : Allocator.determineCollectionAttempts();
194      emergencyCollection = !Plan.isInternalTriggeredCollection() &&
195          lastCollectionWasExhaustive() && collectionAttempt > 1;
196      if (emergencyCollection) {
197        if (Options.verbose.getValue() >= 1) Log.write("[Emergency]");
198        forceFullHeapCollection();
199      }
200      return;
201    }
202
203    if (phaseId == INITIATE) {
204      setGCStatus(GC_PREPARE);
205      return;
206    }
207
208    if (phaseId == PREPARE_STACKS) {
209      stacksPrepared = true;
210      return;
211    }
212
213    if (phaseId == PREPARE) {
214      loSpace.prepare(true);
215      nonMovingSpace.prepare(true);
216      if (USE_CODE_SPACE) {
217        smallCodeSpace.prepare(true);
218        largeCodeSpace.prepare(true);
219      }
220      immortalSpace.prepare();
221      VM.memory.globalPrepareVMSpace();
222      return;
223    }
224
225    if (phaseId == STACK_ROOTS) {
226      VM.scanning.notifyInitialThreadScanComplete(false);
227      setGCStatus(GC_PROPER);
228      return;
229    }
230
231    if (phaseId == ROOTS) {
232      VM.scanning.resetThreadCounter();
233      setGCStatus(GC_PROPER);
234      return;
235    }
236
237    if (phaseId == RELEASE) {
238      loSpace.release(true);
239      nonMovingSpace.release();
240      if (USE_CODE_SPACE) {
241        smallCodeSpace.release();
242        largeCodeSpace.release(true);
243      }
244      immortalSpace.release();
245      VM.memory.globalReleaseVMSpace();
246      return;
247    }
248
249    if (phaseId == COMPLETE) {
250      setGCStatus(NOT_IN_GC);
251      return;
252    }
253
254    if (Options.sanityCheck.getValue() && sanityChecker.collectionPhase(phaseId)) {
255      return;
256    }
257
258    Log.write("Global phase "); Log.write(Phase.getName(phaseId));
259    Log.writeln(" not handled.");
260    VM.assertions.fail("Global phase not handled!");
261  }
262
263  /**
264   * Update the nursery zeroing approach based on option settings.
265   *
266   * @param nurserySpace The space to apply the changes to.
267   */
268  protected void switchNurseryZeroingApproach(Space nurserySpace) {
269    if (Options.nurseryZeroing.getConcurrent()) {
270      if (Options.nurseryZeroing.getAdaptive() &&
271          (VM.collection.getActiveThreads() >= VM.collection.getDefaultThreads())) {
272        // Many (non-daemon) threads, so we revert to bulk zeroing.
273        nurserySpace.skipConcurrentZeroing();
274      } else {
275        nurserySpace.triggerConcurrentZeroing();
276      }
277    }
278  }
279
280  /**
281   * {@inheritDoc}
282   * Used for example to replace a placeholder.
283   */
284  @Override
285  public void replacePhase(int oldScheduledPhase, int newScheduledPhase) {
286    ComplexPhase cp = (ComplexPhase)Phase.getPhase(collection);
287    cp.replacePhase(oldScheduledPhase, newScheduledPhase);
288  }
289
290  /**
291   * Replace a placeholder phase.
292   *
293   * @param placeHolderPhase The placeholder phase
294   * @param newScheduledPhase The new scheduled phase.
295   */
296  public void replacePlaceholderPhase(short placeHolderPhase, int newScheduledPhase) {
297    ComplexPhase cp = (ComplexPhase)Phase.getPhase(collection);
298    cp.replacePhase(Phase.schedulePlaceholder(placeHolderPhase), newScheduledPhase);
299  }
300}