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