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.generational;
014
015import org.mmtk.plan.*;
016import org.mmtk.policy.CopyLocal;
017import org.mmtk.policy.Space;
018import org.mmtk.utility.HeaderByte;
019import org.mmtk.utility.deque.*;
020import org.mmtk.utility.alloc.Allocator;
021import org.mmtk.utility.statistics.Stats;
022import org.mmtk.vm.VM;
023import static org.mmtk.plan.generational.Gen.USE_OBJECT_BARRIER_FOR_AASTORE;
024import static org.mmtk.plan.generational.Gen.USE_OBJECT_BARRIER_FOR_PUTFIELD;
025import static org.mmtk.utility.Constants.*;
026
027import org.vmmagic.pragma.*;
028import org.vmmagic.unboxed.*;
029
030/**
031 * This abstract class implements <i>per-mutator thread</i> behavior
032 * and state for <i>generational copying collectors</i>.<p>
033 *
034 * Specifically, this class defines mutator-time allocation into the nursery;
035 * write barrier semantics, and per-mutator thread collection semantics
036 * (flushing and restoring per-mutator allocator and remset state).
037 *
038 * @see Gen
039 * @see GenCollector
040 * @see StopTheWorldMutator
041 * @see MutatorContext
042 */
043@Uninterruptible public class GenMutator extends StopTheWorldMutator {
044
045  /*****************************************************************************
046   *
047   * Instance fields
048   */
049
050  /**
051   *
052   */
053  protected final CopyLocal nursery = new CopyLocal(Gen.nurserySpace);
054
055  private final ObjectReferenceDeque modbuf;    /* remember modified scalars */
056  protected final WriteBuffer remset;           /* remember modified array fields */
057  protected final AddressPairDeque arrayRemset; /* remember modified array ranges */
058
059  /****************************************************************************
060   *
061   * Initialization
062   */
063
064  /**
065   * Constructor<p>
066   *
067   * Note that each mutator is a producer of remsets, while each
068   * collector is a consumer.  The <code>GenCollector</code> class
069   * is responsible for construction of the consumer.
070   * @see GenCollector
071   */
072  public GenMutator() {
073    modbuf = new ObjectReferenceDeque("modbuf", global().modbufPool);
074    remset = new WriteBuffer(global().remsetPool);
075    arrayRemset = new AddressPairDeque(global().arrayRemsetPool);
076  }
077
078  /****************************************************************************
079   *
080   * Mutator-time allocation
081   */
082
083  /**
084   * {@inheritDoc}
085   */
086  @Override
087  @Inline
088  public Address alloc(int bytes, int align, int offset, int allocator, int site) {
089    if (allocator == Gen.ALLOC_NURSERY) {
090      if (Stats.GATHER_MARK_CONS_STATS) Gen.nurseryCons.inc(bytes);
091      return nursery.alloc(bytes, align, offset);
092    }
093    return super.alloc(bytes, align, offset, allocator, site);
094  }
095
096  @Override
097  @Inline
098  public void postAlloc(ObjectReference ref, ObjectReference typeRef,
099      int bytes, int allocator) {
100    if (allocator != Gen.ALLOC_NURSERY) {
101      super.postAlloc(ref, typeRef, bytes, allocator);
102    }
103  }
104
105  @Override
106  public Allocator getAllocatorFromSpace(Space space) {
107    if (space == Gen.nurserySpace) return nursery;
108    return super.getAllocatorFromSpace(space);
109  }
110
111  /****************************************************************************
112   *
113   * Barriers
114   */
115
116  /**
117   * Perform the write barrier fast path, which may involve remembering
118   * a reference if necessary.
119   *
120   * @param src The object into which the new reference will be stored
121   * @param slot The address into which the new reference will be
122   * stored.
123   * @param tgt The target of the new reference
124   * @param mode The mode of the store (eg putfield, putstatic etc)
125   */
126  @Inline
127  private void fastPath(ObjectReference src, Address slot, ObjectReference tgt, int mode) {
128    if (Gen.GATHER_WRITE_BARRIER_STATS) Gen.wbFast.inc();
129    if ((mode == ARRAY_ELEMENT && USE_OBJECT_BARRIER_FOR_AASTORE) ||
130        (mode == INSTANCE_FIELD && USE_OBJECT_BARRIER_FOR_PUTFIELD)) {
131      if (HeaderByte.isUnlogged(src)) {
132        if (Gen.GATHER_WRITE_BARRIER_STATS) Gen.wbSlow.inc();
133        HeaderByte.markAsLogged(src);
134        modbuf.insert(src);
135      }
136    } else {
137      if (!Gen.inNursery(slot) && Gen.inNursery(tgt)) {
138        if (Gen.GATHER_WRITE_BARRIER_STATS) Gen.wbSlow.inc();
139        remset.insert(slot);
140      }
141    }
142  }
143
144  /**
145   * {@inheritDoc}<p>
146   *
147   * In this case, we remember the address of the source of the
148   * pointer if the new reference points into the nursery from
149   * non-nursery space.
150   */
151  @Override
152  @Inline
153  public final void objectReferenceWrite(ObjectReference src, Address slot,
154      ObjectReference tgt, Word metaDataA,
155      Word metaDataB, int mode) {
156    fastPath(src, slot, tgt, mode);
157    VM.barriers.objectReferenceWrite(src, tgt, metaDataA, metaDataB, mode);
158  }
159
160
161  /**
162   * Perform the root write barrier fast path, which may involve remembering
163   * a reference if necessary.
164   *
165   * @param slot The address into which the new reference will be
166   * stored.
167   * @param tgt The target of the new reference
168   */
169  @Inline
170  private void fastPath(Address slot, ObjectReference tgt) {
171    if (Gen.GATHER_WRITE_BARRIER_STATS) Gen.wbFast.inc();
172    if (Gen.inNursery(tgt)) {
173      if (Gen.GATHER_WRITE_BARRIER_STATS) Gen.wbSlow.inc();
174      remset.insert(slot);
175    }
176  }
177
178  /**
179   * {@inheritDoc}<p>
180   *
181   * In this case, we remember the address of the source of the
182   * pointer if the new reference points into the nursery from
183   * non-nursery space.
184   */
185  @Override
186  @Inline
187  public final void objectReferenceNonHeapWrite(Address slot, ObjectReference tgt,
188      Word metaDataA, Word metaDataB) {
189    fastPath(slot, tgt);
190    VM.barriers.objectReferenceNonHeapWrite(slot, tgt, metaDataA, metaDataB);
191  }
192
193  /**
194   * {@inheritDoc}<p>
195   *
196   * In this case, we remember the address of the source of the
197   * pointer if the new reference points into the nursery from
198   * non-nursery space.
199   */
200  @Override
201  @Inline
202  public boolean objectReferenceTryCompareAndSwap(ObjectReference src, Address slot, ObjectReference old, ObjectReference tgt,
203      Word metaDataA, Word metaDataB, int mode) {
204    boolean result = VM.barriers.objectReferenceTryCompareAndSwap(src, old, tgt, metaDataA, metaDataB, mode);
205    if (result)
206      fastPath(src, slot, tgt, mode);
207    return result;
208  }
209
210  /**
211   * {@inheritDoc}<p>
212   *
213   * In this case, we remember the mutated source address range and
214   * will scan that address range at GC time.
215   */
216  @Inline
217  @Override
218  public final boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset, ObjectReference dst, Offset dstOffset, int bytes) {
219    if (!Gen.inNursery(dst)) {
220      Address start = dst.toAddress().plus(dstOffset);
221      arrayRemset.insert(start, start.plus(bytes));
222    }
223    return false;
224  }
225
226  @Override
227  public final void flushRememberedSets() {
228    modbuf.flushLocal();
229    remset.flushLocal();
230    arrayRemset.flushLocal();
231    assertRemsetsFlushed();
232  }
233
234  @Override
235  public final void assertRemsetsFlushed() {
236    if (VM.VERIFY_ASSERTIONS) {
237      VM.assertions._assert(modbuf.isFlushed());
238      VM.assertions._assert(remset.isFlushed());
239      VM.assertions._assert(arrayRemset.isFlushed());
240    }
241  }
242
243  /****************************************************************************
244   *
245   * Collection
246   */
247
248  /**
249   * {@inheritDoc}
250   */
251  @Override
252  @NoInline
253  public void collectionPhase(short phaseId, boolean primary) {
254
255    if (phaseId == Gen.PREPARE) {
256      nursery.reset();
257      if (global().traceFullHeap()) {
258        super.collectionPhase(phaseId, primary);
259        modbuf.flushLocal();
260        remset.flushLocal();
261        arrayRemset.flushLocal();
262      } else {
263        flushRememberedSets();
264      }
265      return;
266    }
267
268    if (phaseId == Gen.RELEASE) {
269      if (global().traceFullHeap()) {
270        super.collectionPhase(phaseId, primary);
271      }
272      assertRemsetsFlushed();
273      return;
274    }
275
276    super.collectionPhase(phaseId, primary);
277  }
278
279  /****************************************************************************
280   *
281   * Miscellaneous
282   */
283
284  /** @return The active global plan as a <code>Gen</code> instance. */
285  @Inline
286  private static Gen global() {
287    return (Gen) VM.activePlan.global();
288  }
289}