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 */
013package org.mmtk.plan.stickyms;
014
015import org.mmtk.plan.*;
016import org.mmtk.plan.marksweep.MSMutator;
017import org.mmtk.policy.MarkSweepLocal;
018
019import org.mmtk.utility.HeaderByte;
020import org.mmtk.utility.deque.ObjectReferenceDeque;
021import org.mmtk.vm.VM;
022
023import org.vmmagic.pragma.*;
024import 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
041public class StickyMSMutator extends MSMutator {
042
043  /****************************************************************************
044   * Instance fields
045   */
046
047  /**
048   *
049   */
050  private final 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}