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