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 */
013 package org.mmtk.plan.stickyms;
014
015 import org.mmtk.plan.*;
016 import org.mmtk.plan.marksweep.MSMutator;
017 import org.mmtk.policy.MarkSweepLocal;
018
019 import org.mmtk.utility.HeaderByte;
020 import org.mmtk.utility.deque.ObjectReferenceDeque;
021 import org.mmtk.vm.VM;
022
023 import org.vmmagic.pragma.*;
024 import 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
041 public class StickyMSMutator extends MSMutator {
042
043 /****************************************************************************
044 * Instance fields
045 */
046
047 private ObjectReferenceDeque modBuffer;
048
049 /****************************************************************************
050 *
051 * Initialization
052 */
053
054 /**
055 * Constructor
056 */
057 public StickyMSMutator() {
058 ms = new MarkSweepLocal(StickyMS.msSpace);
059 modBuffer = new ObjectReferenceDeque("mod buf", global().modPool);
060 }
061
062 /****************************************************************************
063 *
064 * Barriers
065 */
066
067 /**
068 * A new reference is about to be created. Take appropriate write
069 * barrier actions.<p>
070 *
071 * In this case, we remember the address of the source of the
072 * pointer if the new reference points into the nursery from
073 * non-nursery space.
074 *
075 * @param src The object into which the new reference will be stored
076 * @param slot The address into which the new reference will be
077 * stored.
078 * @param tgt The target of the new reference
079 * @param metaDataA A value that assists the host VM in creating a store
080 * @param metaDataB A value that assists the host VM in creating a store
081 * @param mode The mode of the store (eg putfield, putstatic etc)
082 */
083 @Inline
084 public final void objectReferenceWrite(ObjectReference src, Address slot,
085 ObjectReference tgt, Word metaDataA, Word metaDataB, int mode) {
086 if (HeaderByte.isUnlogged(src))
087 logSource(src);
088 VM.barriers.objectReferenceWrite(src, tgt, metaDataA, metaDataB, mode);
089 }
090
091 /**
092 * A number of references are about to be copied from object
093 * <code>src</code> to object <code>dst</code> (as in an array
094 * copy). Thus, <code>dst</code> is the mutated object. Take
095 * appropriate write barrier actions.<p>
096 *
097 * In this case, we remember the mutated source address range and
098 * will scan that address range at GC time.
099 *
100 * @param src The source of the values to copied
101 * @param srcOffset The offset of the first source address, in
102 * bytes, relative to <code>src</code> (in principle, this could be
103 * negative).
104 * @param dst The mutated object, i.e. the destination of the copy.
105 * @param dstOffset The offset of the first destination address, in
106 * bytes relative to <code>tgt</code> (in principle, this could be
107 * negative).
108 * @param bytes The size of the region being copied, in bytes.
109 * @return True if the update was performed by the barrier, false if
110 * left to the caller (always false in this case).
111 */
112 @Inline
113 public final boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset,
114 ObjectReference dst, Offset dstOffset, int bytes) {
115 if (HeaderByte.isUnlogged(src))
116 logSource(src);
117 return false;
118 }
119
120 /**
121 * Add an object to the modified objects buffer and mark the
122 * object has having been logged. Since duplicate entries do
123 * not raise any correctness issues, we do <i>not</i> worry
124 * about synchronization and allow threads to race to log the
125 * object, potentially including it twice (unlike reference
126 * counting where duplicates would lead to incorrect reference
127 * counts).
128 *
129 * @param src The object to be logged
130 */
131 private void logSource(ObjectReference src) {
132 HeaderByte.markAsLogged(src);
133 modBuffer.push(src);
134 }
135
136 /**
137 * Flush per-mutator remembered sets into the global remset pool.
138 */
139 public final void flushRememberedSets() {
140 modBuffer.flushLocal();
141 assertRemsetFlushed();
142 }
143
144 /**
145 * Assert that the remsets have been flushed. This is critical to
146 * correctness. We need to maintain the invariant that remset entries
147 * do not accrue during GC. If the host JVM generates barrier entires
148 * it is its own responsibility to ensure that they are flushed before
149 * returning to MMTk.
150 */
151 public final void assertRemsetFlushed() {
152 if (VM.VERIFY_ASSERTIONS) {
153 VM.assertions._assert(modBuffer.isFlushed());
154 }
155 }
156
157
158 /****************************************************************************
159 *
160 * Collection
161 */
162
163 /**
164 * Perform a per-mutator collection phase.
165 *
166 * @param phaseId The collection phase to perform
167 * @param primary Perform any single-threaded activities using this thread.
168 */
169 @Inline
170 public final void collectionPhase(short phaseId, boolean primary) {
171 if (phaseId == StickyMS.PREPARE) {
172 flushRememberedSets();
173 }
174 if (phaseId == StickyMS.RELEASE) {
175 assertRemsetFlushed();
176 }
177
178 if (!global().collectWholeHeap) {
179 if (phaseId == StickyMS.PREPARE) {
180 ms.prepare();
181 return;
182 }
183
184 if (phaseId == StickyMS.RELEASE) {
185 ms.release();
186 return;
187 }
188 }
189
190 super.collectionPhase(phaseId, primary);
191 }
192
193
194 /**
195 * Flush mutator context, in response to a requestMutatorFlush.
196 * Also called by the default implementation of deinitMutator.
197 */
198 @Override
199 public void flush() {
200 super.flush();
201 ms.flush();
202 }
203
204 /****************************************************************************
205 *
206 * Miscellaneous
207 */
208
209 /** @return The active global plan as an <code>MSGen</code> instance. */
210 @Inline
211 private static StickyMS global() {
212 return (StickyMS) VM.activePlan.global();
213 }
214 }