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.refcount;
014
015import org.mmtk.plan.StopTheWorldMutator;
016import org.mmtk.plan.refcount.backuptrace.BTSweepImmortalScanner;
017import org.mmtk.policy.ExplicitFreeListLocal;
018import org.mmtk.policy.ExplicitFreeListSpace;
019import org.mmtk.policy.LargeObjectLocal;
020import org.mmtk.policy.Space;
021import org.mmtk.utility.alloc.Allocator;
022import org.mmtk.utility.deque.ObjectReferenceDeque;
023import org.mmtk.vm.VM;
024
025import org.vmmagic.pragma.*;
026import org.vmmagic.unboxed.*;
027
028/**
029 * This class implements the mutator context for a reference counting collector.
030 * See Shahriyar et al for details of and rationale for the optimizations used
031 * here (http://dx.doi.org/10.1145/2258996.2259008).  See Chapter 4 of
032 * Daniel Frampton's PhD thesis for details of and rationale for the cycle
033 * collection strategy used by this collector.
034 */
035@Uninterruptible
036public class RCBaseMutator extends StopTheWorldMutator {
037
038  /************************************************************************
039   * Instance fields
040   */
041
042  /**
043   *
044   */
045  private final ExplicitFreeListLocal rc;
046  private final LargeObjectLocal rclos;
047  private final ObjectReferenceDeque modBuffer;
048  private final RCDecBuffer decBuffer;
049  private final BTSweepImmortalScanner btSweepImmortal;
050
051  /************************************************************************
052   *
053   * Initialization
054   */
055
056  /**
057   * Constructor. One instance is created per physical processor.
058   */
059  public RCBaseMutator() {
060    rc = new ExplicitFreeListLocal(RCBase.rcSpace);
061    rclos = new LargeObjectLocal(RCBase.rcloSpace);
062    modBuffer = new ObjectReferenceDeque("mod", global().modPool);
063    decBuffer = new RCDecBuffer(global().decPool);
064    btSweepImmortal = new BTSweepImmortalScanner();
065  }
066
067  /****************************************************************************
068   *
069   * Mutator-time allocation
070   */
071
072  /**
073   * {@inheritDoc}
074   */
075  @Override
076  @Inline
077  public Address alloc(int bytes, int align, int offset, int allocator, int site) {
078    switch (allocator) {
079      case RCBase.ALLOC_DEFAULT:
080      case RCBase.ALLOC_NON_MOVING:
081      case RCBase.ALLOC_CODE:
082        return rc.alloc(bytes, align, offset);
083      case RCBase.ALLOC_LOS:
084      case RCBase.ALLOC_PRIMITIVE_LOS:
085      case RCBase.ALLOC_LARGE_CODE:
086        return rclos.alloc(bytes, align, offset);
087      case RCBase.ALLOC_IMMORTAL:
088        return super.alloc(bytes, align, offset, allocator, site);
089      default:
090        VM.assertions.fail("Allocator not understood by RC");
091        return Address.zero();
092    }
093  }
094
095  @Override
096  @Inline
097  public void postAlloc(ObjectReference ref, ObjectReference typeRef, int bytes, int allocator) {
098    switch (allocator) {
099    case RCBase.ALLOC_DEFAULT:
100    case RCBase.ALLOC_NON_MOVING:
101      if (RCBase.BUILD_FOR_GENRC) modBuffer.push(ref);
102    case RCBase.ALLOC_CODE:
103      if (RCBase.BUILD_FOR_GENRC) {
104        decBuffer.push(ref);
105        RCHeader.initializeHeader(ref, true);
106        ExplicitFreeListSpace.unsyncSetLiveBit(ref);
107      }
108      break;
109    case RCBase.ALLOC_LOS:
110      if (RCBase.BUILD_FOR_GENRC) modBuffer.push(ref);
111    case RCBase.ALLOC_PRIMITIVE_LOS:
112    case RCBase.ALLOC_LARGE_CODE:
113      decBuffer.push(ref);
114      if (RCBase.BUILD_FOR_GENRC) RCHeader.initializeHeader(ref, true);
115      RCBase.rcloSpace.initializeHeader(ref, true);
116      return;
117    case RCBase.ALLOC_IMMORTAL:
118      if (RCBase.BUILD_FOR_GENRC) modBuffer.push(ref);
119      decBuffer.push(ref);
120      if (RCBase.BUILD_FOR_GENRC) RCHeader.initializeHeader(ref, true);
121      return;
122    default:
123      VM.assertions.fail("Allocator not understood by RC");
124      return;
125    }
126  }
127
128  @Override
129  public Allocator getAllocatorFromSpace(Space space) {
130    if (space == RCBase.rcSpace) return rc;
131    if (space == RCBase.rcloSpace) return rclos;
132    return super.getAllocatorFromSpace(space);
133  }
134
135  /****************************************************************************
136   *
137   * Collection
138   */
139
140
141  /**
142   * {@inheritDoc}
143   */
144  @Override
145  public void collectionPhase(short phaseId, boolean primary) {
146    if (phaseId == RCBase.PREPARE) {
147      rc.prepare();
148      return;
149    }
150
151    if (phaseId == RCBase.PROCESS_MODBUFFER) {
152      modBuffer.flushLocal();
153      return;
154    }
155
156    if (phaseId == RCBase.PROCESS_DECBUFFER) {
157      decBuffer.flushLocal();
158      return;
159    }
160
161    if (phaseId == RCBase.RELEASE) {
162      if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
163        immortal.linearScan(btSweepImmortal);
164      }
165      rc.release();
166      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(modBuffer.isEmpty());
167      if (!RCBase.BUILD_FOR_GENRC) {
168        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(decBuffer.isEmpty());
169      }
170      return;
171    }
172
173    super.collectionPhase(phaseId, primary);
174  }
175
176  @Override
177  public final void flushRememberedSets() {
178    decBuffer.flushLocal();
179    modBuffer.flushLocal();
180    assertRemsetsFlushed();
181  }
182
183  @Override
184  public final void assertRemsetsFlushed() {
185    if (VM.VERIFY_ASSERTIONS) {
186      VM.assertions._assert(decBuffer.isFlushed());
187      VM.assertions._assert(modBuffer.isFlushed());
188    }
189  }
190
191  @Override
192  public void flush() {
193    super.flush();
194    rc.flush();
195  }
196
197  /****************************************************************************
198   *
199   * Write barriers.
200   */
201
202  /**
203   * {@inheritDoc}
204   */
205  @Override
206  @Inline
207  public void objectReferenceWrite(ObjectReference src, Address slot,
208                           ObjectReference tgt, Word metaDataA,
209                           Word metaDataB, int mode) {
210    if (RCHeader.logRequired(src)) {
211      coalescingWriteBarrierSlow(src);
212    }
213    VM.barriers.objectReferenceWrite(src,tgt,metaDataA, metaDataB, mode);
214  }
215
216  @Override
217  @Inline
218  public boolean objectReferenceTryCompareAndSwap(ObjectReference src, Address slot,
219                                               ObjectReference old, ObjectReference tgt, Word metaDataA,
220                                               Word metaDataB, int mode) {
221    if (RCHeader.logRequired(src)) {
222      coalescingWriteBarrierSlow(src);
223    }
224    return VM.barriers.objectReferenceTryCompareAndSwap(src,old,tgt,metaDataA,metaDataB,mode);
225  }
226
227  /**
228   * {@inheritDoc}
229   *
230   * @param src The source of the values to be copied
231   * @param srcOffset The offset of the first source address, in
232   * bytes, relative to <code>src</code> (in principle, this could be
233   * negative).
234   * @param dst The mutated object, i.e. the destination of the copy.
235   * @param dstOffset The offset of the first destination address, in
236   * bytes relative to <code>tgt</code> (in principle, this could be
237   * negative).
238   * @param bytes The size of the region being copied, in bytes.
239   * @return True if the update was performed by the barrier, false if
240   * left to the caller (always false in this case).
241   */
242  @Override
243  @Inline
244  public boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset,
245                              ObjectReference dst, Offset dstOffset, int bytes) {
246    if (RCHeader.logRequired(dst)) {
247      coalescingWriteBarrierSlow(dst);
248    }
249    return false;
250  }
251
252  /**
253   * Slow path of the coalescing write barrier.
254   *
255   * <p> Attempt to log the source object. If successful in racing for
256   * the log bit, push an entry into the modified buffer and add a
257   * decrement buffer entry for each referent object (in the RC space)
258   * before setting the header bit to indicate that it has finished
259   * logging (allowing others in the race to continue).
260   *
261   * @param srcObj The object being mutated
262   */
263  @NoInline
264  private void coalescingWriteBarrierSlow(ObjectReference srcObj) {
265    if (RCHeader.attemptToLog(srcObj)) {
266      modBuffer.push(srcObj);
267      decBuffer.processChildren(srcObj);
268      RCHeader.makeLogged(srcObj);
269    }
270  }
271
272  /****************************************************************************
273   *
274   * Miscellaneous
275   */
276
277  /** @return The active global plan as an <code>RC</code> instance. */
278  @Inline
279  private static RCBase global() {
280    return (RCBase) VM.activePlan.global();
281  }
282}