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.stickyimmix;
014
015import org.mmtk.plan.*;
016import org.mmtk.plan.immix.ImmixMutator;
017
018import org.mmtk.utility.HeaderByte;
019import org.mmtk.utility.deque.ObjectReferenceDeque;
020import org.mmtk.vm.VM;
021
022import org.vmmagic.pragma.*;
023import 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
040public class StickyImmixMutator extends ImmixMutator {
041
042  /****************************************************************************
043   * Instance fields
044   */
045
046  /**
047   *
048   */
049  private final 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}