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.*;
016    import org.mmtk.plan.marksweep.MSMutator;
017    import org.mmtk.policy.MarkSweepLocal;
018    
019    import org.mmtk.utility.HeaderByte;
020    import org.mmtk.utility.deque.ObjectReferenceDeque;
021    import org.mmtk.vm.VM;
022    
023    import org.vmmagic.pragma.*;
024    import org.vmmagic.unboxed.*;
025    
026    /**
027     * This class implements <i>per-mutator thread</i> behavior
028     * and state for the <i>StickyMS</i> plan, which implements a
029     * generational mark-sweep collector.<p>
030     *
031     * Specifically, this class defines <i>MS</i> mutator-time allocation
032     * and per-mutator thread collection semantics (flushing and restoring
033     * per-mutator allocator state).<p>
034     * *
035     * @see StickyMS
036     * @see StickyMSCollector
037     * @see MutatorContext
038     * @see Phase
039     */
040    @Uninterruptible
041    public class StickyMSMutator extends MSMutator {
042    
043      /****************************************************************************
044       * Instance fields
045       */
046    
047      /**
048       *
049       */
050      private ObjectReferenceDeque modBuffer;
051    
052      /****************************************************************************
053       *
054       * Initialization
055       */
056    
057      /**
058       * Constructor
059       */
060      public StickyMSMutator() {
061        ms = new MarkSweepLocal(StickyMS.msSpace);
062        modBuffer = new ObjectReferenceDeque("mod buf", global().modPool);
063      }
064    
065      /****************************************************************************
066       *
067       * Barriers
068       */
069    
070      /**
071       * {@inheritDoc}<p>
072       *
073       * In this case, we remember the address of the source of the
074       * pointer if the new reference points into the nursery from
075       * non-nursery space.
076       */
077      @Override
078      @Inline
079      public final void objectReferenceWrite(ObjectReference src, Address slot,
080          ObjectReference tgt, Word metaDataA, Word metaDataB, int mode) {
081        if (HeaderByte.isUnlogged(src))
082          logSource(src);
083        VM.barriers.objectReferenceWrite(src, tgt, metaDataA, metaDataB, mode);
084      }
085    
086      /**
087       * {@inheritDoc}<p>
088       *
089       * In this case, we remember the mutated source address range and
090       * will scan that address range at GC time.
091       */
092      @Override
093      @Inline
094      public final boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset,
095          ObjectReference dst, Offset dstOffset, int bytes) {
096        if (HeaderByte.isUnlogged(src))
097          logSource(src);
098        return false;
099      }
100    
101      @Override
102      @Inline
103      public boolean objectReferenceTryCompareAndSwap(ObjectReference src, Address slot,
104                                                   ObjectReference old, ObjectReference tgt, Word metaDataA,
105                                                   Word metaDataB, int mode) {
106        if (HeaderByte.isUnlogged(src))
107          logSource(src);
108        return VM.barriers.objectReferenceTryCompareAndSwap(src,old,tgt,metaDataA,metaDataB,mode);
109      }
110    
111    
112      /**
113       * Add an object to the modified objects buffer and mark the
114       * object has having been logged.  Since duplicate entries do
115       * not raise any correctness issues, we do <i>not</i> worry
116       * about synchronization and allow threads to race to log the
117       * object, potentially including it twice (unlike reference
118       * counting where duplicates would lead to incorrect reference
119       * counts).
120       *
121       * @param src The object to be logged
122       */
123      private void logSource(ObjectReference src) {
124        HeaderByte.markAsLogged(src);
125        modBuffer.push(src);
126      }
127    
128      @Override
129      public final void flushRememberedSets() {
130        modBuffer.flushLocal();
131        assertRemsetFlushed();
132      }
133    
134      /**
135       * Assert that the remsets have been flushed.  This is critical to
136       * correctness.  We need to maintain the invariant that remset entries
137       * do not accrue during GC.  If the host JVM generates barrier entires
138       * it is its own responsibility to ensure that they are flushed before
139       * returning to MMTk.
140       */
141      public final void assertRemsetFlushed() {
142        if (VM.VERIFY_ASSERTIONS) {
143          VM.assertions._assert(modBuffer.isFlushed());
144        }
145      }
146    
147    
148      /****************************************************************************
149       *
150       * Collection
151       */
152    
153      /**
154       * {@inheritDoc}
155       */
156      @Override
157      @Inline
158      public final void collectionPhase(short phaseId, boolean primary) {
159        if (phaseId == StickyMS.PREPARE) {
160          flushRememberedSets();
161        }
162        if (phaseId == StickyMS.RELEASE) {
163          assertRemsetFlushed();
164        }
165    
166        if (!global().collectWholeHeap) {
167          if (phaseId == StickyMS.PREPARE) {
168            ms.prepare();
169            return;
170          }
171    
172          if (phaseId == StickyMS.RELEASE) {
173            ms.release();
174            return;
175          }
176        }
177    
178        super.collectionPhase(phaseId, primary);
179      }
180    
181    
182      @Override
183      public void flush() {
184        super.flush();
185        ms.flush();
186      }
187    
188      /****************************************************************************
189       *
190       * Miscellaneous
191       */
192    
193      /** @return The active global plan as an <code>MSGen</code> instance. */
194      @Inline
195      private static StickyMS global() {
196        return (StickyMS) VM.activePlan.global();
197      }
198    }