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      /**
047       *
048       */
049      private ObjectReferenceDeque modBuffer;
050    
051      /****************************************************************************
052       *
053       * Initialization
054       */
055    
056      /**
057       * Constructor
058       */
059      public StickyImmixMutator() {
060        super();
061        modBuffer = new ObjectReferenceDeque("mod buf", global().modPool);
062      }
063    
064      /****************************************************************************
065       *
066       * Barriers
067       */
068    
069      /**
070       * {@inheritDoc}<p>
071       *
072       * In this case, we remember the address of the source of the
073       * pointer if the new reference points into the nursery from
074       * non-nursery space.
075       */
076      @Override
077      @Inline
078      public final void objectReferenceWrite(ObjectReference src, Address slot,
079          ObjectReference tgt, Word metaDataA, Word metaDataB, int mode) {
080        if (HeaderByte.isUnlogged(src))
081          logSource(src);
082        VM.barriers.objectReferenceWrite(src, tgt, metaDataA, metaDataB, mode);
083      }
084    
085      /**
086       * {@inheritDoc}<p>
087       *
088       * In this case, we remember the mutated source address range and
089       * will scan that address range at GC time.
090       *
091       * @param src The source of the values to copied
092       * @param srcOffset The offset of the first source address, in
093       * bytes, relative to <code>src</code> (in principle, this could be
094       * negative).
095       * @param dst The mutated object, i.e. the destination of the copy.
096       * @param dstOffset The offset of the first destination address, in
097       * bytes relative to <code>tgt</code> (in principle, this could be
098       * negative).
099       * @param bytes The size of the region being copied, in bytes.
100       * @return True if the update was performed by the barrier, false if
101       * left to the caller (always false in this case).
102       */
103      @Override
104      @Inline
105      public final boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset,
106          ObjectReference dst, Offset dstOffset, int bytes) {
107        if (HeaderByte.isUnlogged(src))
108          logSource(src);
109        return false;
110      }
111    
112      @Override
113      @Inline
114      public boolean objectReferenceTryCompareAndSwap(ObjectReference src, Address slot,
115                                                   ObjectReference old, ObjectReference tgt, Word metaDataA,
116                                                   Word metaDataB, int mode) {
117        if (HeaderByte.isUnlogged(src))
118          logSource(src);
119        return VM.barriers.objectReferenceTryCompareAndSwap(src,old,tgt,metaDataA,metaDataB,mode);
120      }
121    
122      /**
123       * Add an object to the modified objects buffer and mark the
124       * object has having been logged.  Since duplicate entries do
125       * not raise any correctness issues, we do <i>not</i> worry
126       * about synchronization and allow threads to race to log the
127       * object, potentially including it twice (unlike reference
128       * counting where duplicates would lead to incorrect reference
129       * counts).
130       *
131       * @param src The object to be logged
132       */
133      private void logSource(ObjectReference src) {
134        HeaderByte.markAsLogged(src);
135        modBuffer.push(src);
136      }
137    
138      @Override
139      public final void flushRememberedSets() {
140        modBuffer.flushLocal();
141        assertRemsetFlushed();
142      }
143    
144      public final void assertRemsetFlushed() {
145        if (VM.VERIFY_ASSERTIONS) {
146          VM.assertions._assert(modBuffer.isFlushed());
147        }
148      }
149    
150    
151      /****************************************************************************
152       *
153       * Collection
154       */
155    
156      /**
157       * {@inheritDoc}
158       */
159      @Override
160      @Inline
161      public final void collectionPhase(short phaseId, boolean primary) {
162        if (phaseId == StickyImmix.PREPARE) {
163          flushRememberedSets();
164        }
165        if (phaseId == StickyImmix.RELEASE) {
166          assertRemsetFlushed();
167        }
168    
169        if (!global().collectWholeHeap) {
170          if (phaseId == StickyImmix.PREPARE) {
171            immix.prepare();
172            return;
173          }
174    
175          if (phaseId == StickyImmix.RELEASE) {
176            immix.release();
177            return;
178          }
179        }
180    
181        super.collectionPhase(phaseId, primary);
182      }
183    
184      /****************************************************************************
185       *
186       * Miscellaneous
187       */
188    
189      /** @return The active global plan as an <code>MSGen</code> instance. */
190      @Inline
191      private static StickyImmix global() {
192        return (StickyImmix) VM.activePlan.global();
193      }
194    }