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     */
013    package org.mmtk.plan;
014    
015    import org.mmtk.policy.Space;
016    import org.mmtk.utility.Constants;
017    import org.mmtk.utility.Log;
018    import org.mmtk.utility.options.*;
019    import org.mmtk.utility.statistics.Timer;
020    import org.mmtk.vm.VM;
021    
022    import 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
037    public abstract class Simple extends Plan implements Constants {
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 PRECOPY             = Phase.createSimple("precopy");
052      public static final short PREPARE_STACKS      = Phase.createSimple("prepare-stacks", null);
053      public static final short STACK_ROOTS         = Phase.createSimple("stacks");
054      public static final short ROOTS               = Phase.createSimple("root");
055      public static final short CLOSURE             = Phase.createSimple("closure", scanTime);
056      public static final short SOFT_REFS           = Phase.createSimple("soft-ref", refTypeTime);
057      public static final short WEAK_REFS           = Phase.createSimple("weak-ref", refTypeTime);
058      public static final short FINALIZABLE         = Phase.createSimple("finalize", finalizeTime);
059      public static final short WEAK_TRACK_REFS     = Phase.createSimple("weak-track-ref", refTypeTime);
060      public static final short PHANTOM_REFS        = Phase.createSimple("phantom-ref", refTypeTime);
061      public static final short FORWARD             = Phase.createSimple("forward");
062      public static final short FORWARD_REFS        = Phase.createSimple("forward-ref", refTypeTime);
063      public static final short FORWARD_FINALIZABLE = Phase.createSimple("forward-finalize", finalizeTime);
064      public static final short RELEASE             = Phase.createSimple("release");
065      public static final short COMPLETE            = Phase.createSimple("complete", null);
066    
067      /* Sanity placeholder */
068      public static final short PRE_SANITY_PLACEHOLDER  = Phase.createSimple("pre-sanity-placeholder", null);
069      public static final short POST_SANITY_PLACEHOLDER = Phase.createSimple("post-sanity-placeholder", null);
070    
071      /* Sanity phases */
072      public static final short SANITY_SET_PREGC    = Phase.createSimple("sanity-setpre", null);
073      public static final short SANITY_SET_POSTGC   = Phase.createSimple("sanity-setpost", null);
074      public static final short SANITY_PREPARE      = Phase.createSimple("sanity-prepare", null);
075      public static final short SANITY_ROOTS        = Phase.createSimple("sanity-roots", null);
076      public static final short SANITY_COPY_ROOTS   = Phase.createSimple("sanity-copy-roots", null);
077      public static final short SANITY_BUILD_TABLE  = Phase.createSimple("sanity-build-table", null);
078      public static final short SANITY_CHECK_TABLE  = Phase.createSimple("sanity-check-table", null);
079      public static final short SANITY_RELEASE      = Phase.createSimple("sanity-release", null);
080    
081      // CHECKSTYLE:OFF
082    
083      /** Ensure stacks are ready to be scanned */
084      protected static final short prepareStacks = Phase.createComplex("prepare-stacks", null,
085          Phase.scheduleCollector  (PREPARE_STACKS),
086          Phase.scheduleMutator    (PREPARE_STACKS),
087          Phase.scheduleGlobal     (PREPARE_STACKS));
088    
089      /** Trace and set up a sanity table */
090      protected static final short sanityBuildPhase = Phase.createComplex("sanity-build", null,
091          Phase.scheduleGlobal     (SANITY_PREPARE),
092          Phase.scheduleCollector  (SANITY_PREPARE),
093          Phase.scheduleComplex    (prepareStacks),
094          Phase.scheduleCollector  (SANITY_ROOTS),
095          Phase.scheduleGlobal     (SANITY_ROOTS),
096          Phase.scheduleCollector  (SANITY_COPY_ROOTS),
097          Phase.scheduleGlobal     (SANITY_BUILD_TABLE));
098    
099      /** Validate a sanity table */
100      protected static final short sanityCheckPhase = Phase.createComplex("sanity-check", null,
101          Phase.scheduleGlobal     (SANITY_CHECK_TABLE),
102          Phase.scheduleCollector  (SANITY_RELEASE),
103          Phase.scheduleGlobal     (SANITY_RELEASE));
104    
105      /** Start the collection, including preparation for any collected spaces. */
106      protected static final short initPhase = Phase.createComplex("init",
107          Phase.scheduleGlobal     (SET_COLLECTION_KIND),
108          Phase.scheduleGlobal     (INITIATE),
109          Phase.schedulePlaceholder(PRE_SANITY_PLACEHOLDER));
110    
111      /**
112       * Perform the initial determination of liveness from the roots.
113       */
114      protected static final short rootClosurePhase = Phase.createComplex("initial-closure", null,
115          Phase.scheduleMutator    (PREPARE),
116          Phase.scheduleGlobal     (PREPARE),
117          Phase.scheduleCollector  (PREPARE),
118          Phase.scheduleComplex    (prepareStacks),
119          Phase.scheduleCollector  (PRECOPY),
120          Phase.scheduleCollector  (STACK_ROOTS),
121          Phase.scheduleCollector  (ROOTS),
122          Phase.scheduleGlobal     (ROOTS),
123          Phase.scheduleGlobal     (CLOSURE),
124          Phase.scheduleCollector  (CLOSURE));
125    
126      /**
127       * Complete closure including reference types and finalizable objects.
128       */
129      protected static final short refTypeClosurePhase = Phase.createComplex("refType-closure", null,
130          Phase.scheduleCollector  (SOFT_REFS),
131          Phase.scheduleGlobal     (CLOSURE),
132          Phase.scheduleCollector  (CLOSURE),
133          Phase.scheduleCollector  (WEAK_REFS),
134          Phase.scheduleCollector  (FINALIZABLE),
135          Phase.scheduleGlobal     (CLOSURE),
136          Phase.scheduleCollector  (CLOSURE),
137          Phase.schedulePlaceholder(WEAK_TRACK_REFS),
138          Phase.scheduleCollector  (PHANTOM_REFS));
139    
140      /**
141       * Ensure that all references in the system are correct.
142       */
143      protected static final short forwardPhase = Phase.createComplex("forward-all", null,
144          /* Finish up */
145          Phase.schedulePlaceholder(FORWARD),
146          Phase.scheduleCollector  (FORWARD_REFS),
147          Phase.scheduleCollector  (FORWARD_FINALIZABLE));
148    
149      /**
150       * Complete closure including reference types and finalizable objects.
151       */
152      protected static final short completeClosurePhase = Phase.createComplex("release", null,
153          Phase.scheduleMutator    (RELEASE),
154          Phase.scheduleCollector  (RELEASE),
155          Phase.scheduleGlobal     (RELEASE));
156    
157    
158      /**
159       * The collection scheme - this is a small tree of complex phases.
160       */
161      protected static final short finishPhase = Phase.createComplex("finish",
162          Phase.schedulePlaceholder(POST_SANITY_PLACEHOLDER),
163          Phase.scheduleCollector  (COMPLETE),
164          Phase.scheduleGlobal     (COMPLETE));
165    
166      /**
167       * This is the phase that is executed to perform a collection.
168       */
169      public short collection = Phase.createComplex("collection", null,
170          Phase.scheduleComplex(initPhase),
171          Phase.scheduleComplex(rootClosurePhase),
172          Phase.scheduleComplex(refTypeClosurePhase),
173          Phase.scheduleComplex(forwardPhase),
174          Phase.scheduleComplex(completeClosurePhase),
175          Phase.scheduleComplex(finishPhase));
176    
177      // CHECKSTYLE:ON
178    
179      /**
180       * The current collection attempt.
181       */
182      protected int collectionAttempt;
183    
184      /****************************************************************************
185       * Collection
186       */
187    
188      /**
189       * Perform a (global) collection phase.
190       *
191       * @param phaseId The unique of the phase to perform.
192       */
193      @Inline
194      public void collectionPhase(short phaseId) {
195        if (phaseId == SET_COLLECTION_KIND) {
196          requiredAtStart = getPagesRequired();
197          collectionAttempt = VM.collection.maximumCollectionAttempt();
198          emergencyCollection = lastCollectionWasExhaustive() && collectionAttempt > 1;
199          if (collectionAttempt > MAX_COLLECTION_ATTEMPTS) {
200            VM.assertions.fail("Too many collection attempts. Suspect plan is not setting FullHeap flag");
201          }
202          if (emergencyCollection) {
203            if (Options.verbose.getValue() >= 1) Log.write("[Emergency]");
204            forceFullHeapCollection();
205          }
206          return;
207        }
208    
209        if (phaseId == INITIATE) {
210          setGCStatus(GC_PREPARE);
211          return;
212        }
213    
214        if (phaseId == PREPARE_STACKS) {
215          stacksPrepared = true;
216          return;
217        }
218    
219        if (phaseId == PREPARE) {
220          loSpace.prepare(true);
221          nonMovingSpace.prepare(true);
222          if (USE_CODE_SPACE) {
223            smallCodeSpace.prepare(true);
224            largeCodeSpace.prepare(true);
225          }
226          immortalSpace.prepare();
227          VM.memory.globalPrepareVMSpace();
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          Space.clearAllAllocationFailed();
252          awaitingAsyncCollection = false;
253          return;
254        }
255    
256        if (Options.sanityCheck.getValue() && sanityChecker.collectionPhase(phaseId)) {
257          return;
258        }
259    
260        Log.write("Global phase "); Log.write(Phase.getName(phaseId));
261        Log.writeln(" not handled.");
262        VM.assertions.fail("Global phase not handled!");
263      }
264    
265      /**
266       * Replace a scheduled phase. Used for example to replace a placeholder.
267       *
268       * @param oldScheduledPhase The scheduled phase to replace.
269       * @param newScheduledPhase The new scheduled phase.
270       */
271      public void replacePhase(int oldScheduledPhase, int newScheduledPhase) {
272        ComplexPhase cp = (ComplexPhase)Phase.getPhase(collection);
273        cp.replacePhase(oldScheduledPhase, newScheduledPhase);
274      }
275    
276      /**
277       * Replace a placeholder phase.
278       *
279       * @param placeHolderPhase The placeholder phase
280       * @param newScheduledPhase The new scheduled phase.
281       */
282      public void replacePlaceholderPhase(short placeHolderPhase, int newScheduledPhase) {
283        ComplexPhase cp = (ComplexPhase)Phase.getPhase(collection);
284        cp.replacePhase(Phase.schedulePlaceholder(placeHolderPhase), newScheduledPhase);
285      }
286    }