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