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.stickyimmix;
014    
015    import org.mmtk.plan.TransitiveClosure;
016    import org.mmtk.plan.immix.Immix;
017    import org.mmtk.policy.Space;
018    import org.mmtk.utility.Log;
019    import org.mmtk.utility.deque.SharedDeque;
020    import org.mmtk.utility.options.Options;
021    import org.mmtk.utility.statistics.BooleanCounter;
022    import org.mmtk.utility.statistics.Stats;
023    
024    import 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.<p>
054     */
055    @Uninterruptible
056    public 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    }