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.stickyms;
014    
015    import org.mmtk.plan.TransitiveClosure;
016    import org.mmtk.plan.marksweep.MS;
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.sanitychecker.SanityChecker;
022    import org.mmtk.vm.VM;
023    
024    import org.vmmagic.pragma.*;
025    import 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.<p>
052     */
053    @Uninterruptible
054    public 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    }