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.
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.
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.
052     */
053    @Uninterruptible
054    public class StickyMS extends MS {
055    
056      /****************************************************************************
057       * Constants
058       */
059      /** If true, then new PLOS objects are collected at each nursery GC */
060      static final boolean NURSERY_COLLECT_PLOS = true;
061      /** If true then we only do full heap GCs---so we're like MarkSweep (+ write barrier) */
062      static final boolean MAJOR_GC_ONLY = false;
063    
064      /****************************************************************************
065       * Class variables
066       */
067    
068      public static int SCAN_NURSERY = 1;
069    
070      /****************************************************************************
071       * Instance variables
072       */
073      /* status fields */
074      /** will the next collection collect the whole heap? */
075      public boolean nextGCWholeHeap = false;
076      /** will this collection collect the whole heap */
077      public boolean collectWholeHeap = nextGCWholeHeap;
078    
079      /* Remset pool */
080      public final SharedDeque modPool = new SharedDeque("msgen mod objects", metaDataSpace, 1);
081    
082      /****************************************************************************
083       * Static initialization
084       */
085      {
086        msSpace.makeAgeSegregatedSpace();  /* this space is to be collected generationally */
087      }
088    
089      /*****************************************************************************
090       *
091       * Collection
092       */
093    
094      /**
095       * A user-triggered GC has been initiated.
096       */
097      public void userTriggeredGC() {
098        nextGCWholeHeap |= Options.fullHeapSystemGC.getValue();
099      }
100    
101      /**
102       * Force the next collection to be full heap.
103       */
104      @Override
105      public void forceFullHeapCollection() {
106        nextGCWholeHeap = true;
107      }
108    
109      /**
110       * Perform a (global) collection phase.
111       *
112       * @param phaseId Collection phase to execute.
113       */
114      @Inline
115      @Override
116      public final void collectionPhase(short phaseId) {
117    
118        if (phaseId == INITIATE) {
119          collectWholeHeap = MAJOR_GC_ONLY || emergencyCollection || nextGCWholeHeap;
120          nextGCWholeHeap = false;
121          super.collectionPhase(phaseId);
122          return;
123        }
124    
125        if (!collectWholeHeap) {
126          if (phaseId == PREPARE) {
127            msTrace.prepare();
128            msSpace.prepare(false);
129            return;
130          }
131    
132          if (phaseId == RELEASE) {
133            msTrace.release();
134            msSpace.release();
135            modPool.reset();
136            nextGCWholeHeap = (getPagesAvail() < Options.nurserySize.getMinNursery());
137            return;
138          }
139        }
140    
141        super.collectionPhase(phaseId);
142      }
143    
144      /*****************************************************************************
145       *
146       * Accounting
147       */
148    
149      /**
150       * Print pre-collection statistics. In this class we prefix the output
151       * indicating whether the collection was full heap or not.
152       */
153      @Override
154      public void printPreStats() {
155        if ((Options.verbose.getValue() >= 1) && (collectWholeHeap))
156          Log.write("[Full heap]");
157        super.printPreStats();
158      }
159    
160      /**
161       * @return Is current GC only collecting objects allocated since last GC.
162       */
163      public final boolean isCurrentGCNursery() {
164        return !collectWholeHeap;
165      }
166    
167      /**
168       * @return Is last GC a full collection?
169       */
170      public final boolean isLastGCFull() {
171        return collectWholeHeap;
172      }
173    
174      /**
175       * Return the expected reference count. For non-reference counting
176       * collectors this becomes a true/false relationship.
177       * @param object The object to check.
178       * @param sanityRootRC The number of root references to the object.
179       *
180       * @return The expected (root excluded) reference count.
181       */
182      public int sanityExpectedRC(ObjectReference object, int sanityRootRC) {
183        Space space = Space.getSpaceForObject(object);
184    
185        // Immortal spaces
186        if (space == StickyMS.immortalSpace || space == StickyMS.vmSpace) {
187          return space.isReachable(object) ? SanityChecker.ALIVE : SanityChecker.DEAD;
188        }
189    
190        // Mature space (nursery collection)
191        if (VM.activePlan.global().isCurrentGCNursery() && space != StickyMS.msSpace) {
192          return SanityChecker.UNSURE;
193        }
194    
195        return super.sanityExpectedRC(object, sanityRootRC);
196      }
197    
198      /**
199       * Register specialized methods.
200       */
201      @Interruptible
202      protected void registerSpecializedMethods() {
203        TransitiveClosure.registerSpecializedScan(SCAN_NURSERY, StickyMSNurseryTraceLocal.class);
204        super.registerSpecializedMethods();
205      }
206    }