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      private ObjectReferenceDeque modBuffer;
048    
049      /****************************************************************************
050       *
051       * Initialization
052       */
053    
054      /**
055       * Constructor
056       */
057      public StickyMSMutator() {
058        ms = new MarkSweepLocal(StickyMS.msSpace);
059        modBuffer = new ObjectReferenceDeque("mod buf", global().modPool);
060      }
061    
062      /****************************************************************************
063       *
064       * Barriers
065       */
066    
067      /**
068       * A new reference is about to be created.  Take appropriate write
069       * barrier actions.<p>
070       *
071       * In this case, we remember the address of the source of the
072       * pointer if the new reference points into the nursery from
073       * non-nursery space.
074       *
075       * @param src The object into which the new reference will be stored
076       * @param slot The address into which the new reference will be
077       * stored.
078       * @param tgt The target of the new reference
079       * @param metaDataA A value that assists the host VM in creating a store
080       * @param metaDataB A value that assists the host VM in creating a store
081       * @param mode The mode of the store (eg putfield, putstatic etc)
082       */
083      @Inline
084      public final void objectReferenceWrite(ObjectReference src, Address slot,
085          ObjectReference tgt, Word metaDataA, Word metaDataB, int mode) {
086        if (HeaderByte.isUnlogged(src))
087          logSource(src);
088        VM.barriers.objectReferenceWrite(src, tgt, metaDataA, metaDataB, mode);
089      }
090    
091      /**
092       * A number of references are about to be copied from object
093       * <code>src</code> to object <code>dst</code> (as in an array
094       * copy).  Thus, <code>dst</code> is the mutated object.  Take
095       * appropriate write barrier actions.<p>
096       *
097       * In this case, we remember the mutated source address range and
098       * will scan that address range at GC time.
099       *
100       * @param src The source of the values to copied
101       * @param srcOffset The offset of the first source address, in
102       * bytes, relative to <code>src</code> (in principle, this could be
103       * negative).
104       * @param dst The mutated object, i.e. the destination of the copy.
105       * @param dstOffset The offset of the first destination address, in
106       * bytes relative to <code>tgt</code> (in principle, this could be
107       * negative).
108       * @param bytes The size of the region being copied, in bytes.
109       * @return True if the update was performed by the barrier, false if
110       * left to the caller (always false in this case).
111       */
112      @Inline
113      public final boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset,
114          ObjectReference dst, Offset dstOffset, int bytes) {
115        if (HeaderByte.isUnlogged(src))
116          logSource(src);
117        return false;
118      }
119    
120      /**
121       * Add an object to the modified objects buffer and mark the
122       * object has having been logged.  Since duplicate entries do
123       * not raise any correctness issues, we do <i>not</i> worry
124       * about synchronization and allow threads to race to log the
125       * object, potentially including it twice (unlike reference
126       * counting where duplicates would lead to incorrect reference
127       * counts).
128       *
129       * @param src The object to be logged
130       */
131      private void logSource(ObjectReference src) {
132        HeaderByte.markAsLogged(src);
133        modBuffer.push(src);
134      }
135    
136      /**
137       * Flush per-mutator remembered sets into the global remset pool.
138       */
139      public final void flushRememberedSets() {
140        modBuffer.flushLocal();
141        assertRemsetFlushed();
142      }
143    
144      /**
145       * Assert that the remsets have been flushed.  This is critical to
146       * correctness.  We need to maintain the invariant that remset entries
147       * do not accrue during GC.  If the host JVM generates barrier entires
148       * it is its own responsibility to ensure that they are flushed before
149       * returning to MMTk.
150       */
151      public final void assertRemsetFlushed() {
152        if (VM.VERIFY_ASSERTIONS) {
153          VM.assertions._assert(modBuffer.isFlushed());
154        }
155      }
156    
157    
158      /****************************************************************************
159       *
160       * Collection
161       */
162    
163      /**
164       * Perform a per-mutator collection phase.
165       *
166       * @param phaseId The collection phase to perform
167       * @param primary Perform any single-threaded activities using this thread.
168       */
169      @Inline
170      public final void collectionPhase(short phaseId, boolean primary) {
171        if (phaseId == StickyMS.PREPARE) {
172          flushRememberedSets();
173        }
174        if (phaseId == StickyMS.RELEASE) {
175          assertRemsetFlushed();
176        }
177    
178        if (!global().collectWholeHeap) {
179          if (phaseId == StickyMS.PREPARE) {
180            ms.prepare();
181            return;
182          }
183    
184          if (phaseId == StickyMS.RELEASE) {
185            ms.release();
186            return;
187          }
188        }
189    
190        super.collectionPhase(phaseId, primary);
191      }
192    
193    
194      /**
195       * Flush mutator context, in response to a requestMutatorFlush.
196       * Also called by the default implementation of deinitMutator.
197       */
198      @Override
199      public void flush() {
200        super.flush();
201        ms.flush();
202      }
203    
204      /****************************************************************************
205       *
206       * Miscellaneous
207       */
208    
209      /** @return The active global plan as an <code>MSGen</code> instance. */
210      @Inline
211      private static StickyMS global() {
212        return (StickyMS) VM.activePlan.global();
213      }
214    }