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.concurrent;
014
015import static org.mmtk.utility.Constants.*;
016
017import org.mmtk.plan.*;
018
019import org.mmtk.vm.VM;
020
021import org.vmmagic.pragma.*;
022import org.vmmagic.unboxed.*;
023
024/**
025 * This class implements <i>per-mutator thread</i> behavior
026 * and state for a simple whole-heap concurrent collector.
027 *
028 * @see Concurrent
029 * @see ConcurrentCollector
030 * @see StopTheWorldMutator
031 * @see MutatorContext
032 */
033@Uninterruptible
034public abstract class ConcurrentMutator extends SimpleMutator {
035
036  /****************************************************************************
037   * Instance fields
038   */
039
040  /**
041   *
042   */
043  public static boolean newMutatorBarrierActive = false;
044  protected volatile boolean barrierActive = false;
045
046  protected ConcurrentMutator() {
047    barrierActive = newMutatorBarrierActive;
048  }
049
050  /****************************************************************************
051   *
052   * Collection
053   */
054
055  /**
056   * Perform a per-mutator collection phase.
057   */
058  @Override
059  @Inline
060  public void collectionPhase(short phaseId, boolean primary) {
061    if (phaseId == Concurrent.SET_BARRIER_ACTIVE) {
062      barrierActive = true;
063      return;
064    }
065
066    if (phaseId == Concurrent.CLEAR_BARRIER_ACTIVE) {
067      barrierActive = false;
068      return;
069    }
070
071    if (phaseId == Concurrent.FLUSH_MUTATOR) {
072      flush();
073      return;
074    }
075
076    super.collectionPhase(phaseId, primary);
077  }
078
079  /****************************************************************************
080  *
081  * Write and read barriers.
082  */
083
084  /**
085   * {@inheritDoc}<p>
086   *
087   * <b>In this case we employ a Yuasa style snapshot barrier.</b>
088   *
089   */
090  @Inline
091  @Override
092  public void objectReferenceWrite(ObjectReference src, Address slot, ObjectReference tgt, Word metaDataA, Word metaDataB, int mode) {
093    if (barrierActive) checkAndEnqueueReference(slot.loadObjectReference());
094    VM.barriers.objectReferenceWrite(src, tgt, metaDataA, metaDataB, mode);
095  }
096
097  @Inline
098  @Override
099  public boolean objectReferenceTryCompareAndSwap(ObjectReference src, Address slot, ObjectReference old,
100                                               ObjectReference tgt, Word metaDataA, Word metaDataB, int mode) {
101    boolean result = VM.barriers.objectReferenceTryCompareAndSwap(src, old, tgt, metaDataA, metaDataB, mode);
102    if (barrierActive) checkAndEnqueueReference(old);
103    return result;
104  }
105
106  /**
107   * {@inheritDoc}
108   *
109   * @param src The source of the values to be copied
110   * @param srcOffset The offset of the first source address, in
111   * bytes, relative to <code>src</code> (in principle, this could be
112   * negative).
113   * @param dst The mutated object, i.e. the destination of the copy.
114   * @param dstOffset The offset of the first destination address, in
115   * bytes relative to <code>tgt</code> (in principle, this could be
116   * negative).
117   * @param bytes The size of the region being copied, in bytes.
118   */
119  @Inline
120  @Override
121  public boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset, ObjectReference dst, Offset dstOffset, int bytes) {
122    Address cursor = dst.toAddress().plus(dstOffset);
123    Address limit = cursor.plus(bytes);
124    while (cursor.LT(limit)) {
125      ObjectReference ref = cursor.loadObjectReference();
126      if (barrierActive) checkAndEnqueueReference(ref);
127      cursor = cursor.plus(BYTES_IN_ADDRESS);
128    }
129    return false;
130  }
131
132  @Inline
133  @Override
134  public ObjectReference javaLangReferenceReadBarrier(ObjectReference ref) {
135    if (barrierActive) checkAndEnqueueReference(ref);
136    return ref;
137  }
138
139  /**
140   * Process a reference that may require being enqueued as part of a concurrent
141   * collection.
142   *
143   * @param ref The reference to check.
144   */
145  protected abstract void checkAndEnqueueReference(ObjectReference ref);
146}