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.refcount;
014
015 import org.mmtk.plan.StopTheWorldMutator;
016 import org.mmtk.plan.refcount.backuptrace.BTSweepImmortalScanner;
017 import org.mmtk.policy.ExplicitFreeListLocal;
018 import org.mmtk.policy.ExplicitFreeListSpace;
019 import org.mmtk.policy.LargeObjectLocal;
020 import org.mmtk.policy.Space;
021 import org.mmtk.utility.alloc.Allocator;
022 import org.mmtk.utility.deque.ObjectReferenceDeque;
023 import org.mmtk.vm.VM;
024
025 import org.vmmagic.pragma.*;
026 import org.vmmagic.unboxed.*;
027
028 /**
029 * This class implements the mutator context for a simple reference counting collector.
030 */
031 @Uninterruptible
032 public class RCBaseMutator extends StopTheWorldMutator {
033
034 /************************************************************************
035 * Instance fields
036 */
037 private final ExplicitFreeListLocal rc;
038 private final LargeObjectLocal rclos;
039 private final ObjectReferenceDeque modBuffer;
040 private final RCDecBuffer decBuffer;
041 private final BTSweepImmortalScanner btSweepImmortal;
042
043 /************************************************************************
044 *
045 * Initialization
046 */
047
048 /**
049 * Constructor. One instance is created per physical processor.
050 */
051 public RCBaseMutator() {
052 rc = new ExplicitFreeListLocal(RCBase.rcSpace);
053 rclos = new LargeObjectLocal(RCBase.rcloSpace);
054 modBuffer = new ObjectReferenceDeque("mod", global().modPool);
055 decBuffer = new RCDecBuffer(global().decPool);
056 btSweepImmortal = new BTSweepImmortalScanner();
057 }
058
059 /****************************************************************************
060 *
061 * Mutator-time allocation
062 */
063
064 /**
065 * Allocate memory for an object.
066 *
067 * @param bytes The number of bytes required for the object.
068 * @param align Required alignment for the object.
069 * @param offset Offset associated with the alignment.
070 * @param allocator The allocator associated with this request.
071 * @param site Allocation site
072 * @return The address of the newly allocated memory.
073 */
074 @Inline
075 public Address alloc(int bytes, int align, int offset, int allocator, int site) {
076 switch (allocator) {
077 case RCBase.ALLOC_DEFAULT:
078 case RCBase.ALLOC_NON_MOVING:
079 case RCBase.ALLOC_CODE:
080 return rc.alloc(bytes, align, offset);
081 case RCBase.ALLOC_LOS:
082 case RCBase.ALLOC_PRIMITIVE_LOS:
083 case RCBase.ALLOC_LARGE_CODE:
084 return rclos.alloc(bytes, align, offset);
085 case RCBase.ALLOC_IMMORTAL:
086 return super.alloc(bytes, align, offset, allocator, site);
087 default:
088 VM.assertions.fail("Allocator not understood by RC");
089 return Address.zero();
090 }
091 }
092
093 /**
094 * Perform post-allocation actions. For many allocators none are
095 * required.
096 *
097 * @param ref The newly allocated object
098 * @param typeRef the type reference for the instance being created
099 * @param bytes The size of the space to be allocated (in bytes)
100 * @param allocator The allocator number to be used for this allocation
101 */
102 @Inline
103 public void postAlloc(ObjectReference ref, ObjectReference typeRef, int bytes, int allocator) {
104 switch (allocator) {
105 case RCBase.ALLOC_DEFAULT:
106 case RCBase.ALLOC_NON_MOVING:
107 modBuffer.push(ref);
108 case RCBase.ALLOC_CODE:
109 decBuffer.push(ref);
110 RCHeader.initializeHeader(ref, true);
111 ExplicitFreeListSpace.unsyncSetLiveBit(ref);
112 break;
113 case RCBase.ALLOC_LOS:
114 modBuffer.push(ref);
115 case RCBase.ALLOC_PRIMITIVE_LOS:
116 case RCBase.ALLOC_LARGE_CODE:
117 decBuffer.push(ref);
118 RCHeader.initializeHeader(ref, true);
119 RCBase.rcloSpace.initializeHeader(ref, true);
120 return;
121 case RCBase.ALLOC_IMMORTAL:
122 modBuffer.push(ref);
123 decBuffer.push(ref);
124 RCHeader.initializeHeader(ref, true);
125 return;
126 default:
127 VM.assertions.fail("Allocator not understood by RC");
128 return;
129 }
130 }
131
132 /**
133 * Return the allocator instance associated with a space
134 * <code>space</code>, for this plan instance.
135 *
136 * @param space The space for which the allocator instance is desired.
137 * @return The allocator instance associated with this plan instance
138 * which is allocating into <code>space</code>, or <code>null</code>
139 * if no appropriate allocator can be established.
140 */
141 public Allocator getAllocatorFromSpace(Space space) {
142 if (space == RCBase.rcSpace) return rc;
143 if (space == RCBase.rcloSpace) return rclos;
144
145 return super.getAllocatorFromSpace(space);
146 }
147
148 /****************************************************************************
149 *
150 * Collection
151 */
152
153 /**
154 * Perform a per-mutator collection phase.
155 *
156 * @param phaseId The collection phase to perform
157 * @param primary perform any single-threaded local activities.
158 */
159 public void collectionPhase(short phaseId, boolean primary) {
160 if (phaseId == RCBase.PREPARE) {
161 rc.prepare();
162 return;
163 }
164
165 if (phaseId == RCBase.PROCESS_MODBUFFER) {
166 modBuffer.flushLocal();
167 return;
168 }
169
170 if (phaseId == RCBase.PROCESS_DECBUFFER) {
171 decBuffer.flushLocal();
172 return;
173 }
174
175 if (phaseId == RCBase.RELEASE) {
176 if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
177 immortal.linearScan(btSweepImmortal);
178 }
179 rc.release();
180 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(modBuffer.isEmpty());
181 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(decBuffer.isEmpty());
182 return;
183 }
184
185 super.collectionPhase(phaseId, primary);
186 }
187
188 /**
189 * Flush per-mutator remembered sets into the global remset pool.
190 */
191 public final void flushRememberedSets() {
192 decBuffer.flushLocal();
193 modBuffer.flushLocal();
194 assertRemsetsFlushed();
195 }
196
197 /**
198 * Assert that the remsets have been flushed. This is critical to
199 * correctness. We need to maintain the invariant that remset entries
200 * do not accrue during GC. If the host JVM generates barrier entires
201 * it is its own responsibility to ensure that they are flushed before
202 * returning to MMTk.
203 */
204 public final void assertRemsetsFlushed() {
205 if (VM.VERIFY_ASSERTIONS) {
206 VM.assertions._assert(decBuffer.isFlushed());
207 VM.assertions._assert(modBuffer.isFlushed());
208 }
209 }
210
211 /**
212 * Flush mutator context, in response to a requestMutatorFlush.
213 * Also called by the default implementation of deinitMutator.
214 */
215 @Override
216 public void flush() {
217 super.flush();
218 rc.flush();
219 }
220
221 /****************************************************************************
222 *
223 * Write barriers.
224 */
225
226 /**
227 * A new reference is about to be created. Take appropriate write
228 * barrier actions.<p>
229 *
230 * <b>By default do nothing, override if appropriate.</b>
231 *
232 * @param src The object into which the new reference will be stored
233 * @param slot The address into which the new reference will be
234 * stored.
235 * @param tgt The target of the new reference
236 * @param metaDataA A value that assists the host VM in creating a store
237 * @param metaDataB A value that assists the host VM in creating a store
238 * @param mode The context in which the store occurred
239 */
240 @Inline
241 public void objectReferenceWrite(ObjectReference src, Address slot,
242 ObjectReference tgt, Word metaDataA,
243 Word metaDataB, int mode) {
244 if (RCHeader.logRequired(src)) {
245 coalescingWriteBarrierSlow(src);
246 }
247 VM.barriers.objectReferenceWrite(src,tgt,metaDataA, metaDataB, mode);
248 }
249
250 /**
251 * Attempt to atomically exchange the value in the given slot
252 * with the passed replacement value. If a new reference is
253 * created, we must then take appropriate write barrier actions.<p>
254 *
255 * <b>By default do nothing, override if appropriate.</b>
256 *
257 * @param src The object into which the new reference will be stored
258 * @param slot The address into which the new reference will be
259 * stored.
260 * @param old The old reference to be swapped out
261 * @param tgt The target of the new reference
262 * @param metaDataA A value that assists the host VM in creating a store
263 * @param metaDataB A value that assists the host VM in creating a store
264 * @param mode The context in which the store occured
265 * @return True if the swap was successful.
266 */
267 @Inline
268 public boolean objectReferenceTryCompareAndSwap(ObjectReference src, Address slot,
269 ObjectReference old, ObjectReference tgt, Word metaDataA,
270 Word metaDataB, int mode) {
271 if (RCHeader.logRequired(src)) {
272 coalescingWriteBarrierSlow(src);
273 }
274 return VM.barriers.objectReferenceTryCompareAndSwap(src,old,tgt,metaDataA,metaDataB,mode);
275 }
276
277 /**
278 * A number of references are about to be copied from object
279 * <code>src</code> to object <code>dst</code> (as in an array
280 * copy). Thus, <code>dst</code> is the mutated object. Take
281 * appropriate write barrier actions.<p>
282 *
283 * @param src The source of the values to be copied
284 * @param srcOffset The offset of the first source address, in
285 * bytes, relative to <code>src</code> (in principle, this could be
286 * negative).
287 * @param dst The mutated object, i.e. the destination of the copy.
288 * @param dstOffset The offset of the first destination address, in
289 * bytes relative to <code>tgt</code> (in principle, this could be
290 * negative).
291 * @param bytes The size of the region being copied, in bytes.
292 * @return True if the update was performed by the barrier, false if
293 * left to the caller (always false in this case).
294 */
295 @Inline
296 public boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset,
297 ObjectReference dst, Offset dstOffset, int bytes) {
298 if (RCHeader.logRequired(dst)) {
299 coalescingWriteBarrierSlow(dst);
300 }
301 return false;
302 }
303
304 /**
305 * Slow path of the coalescing write barrier.
306 *
307 * <p> Attempt to log the source object. If successful in racing for
308 * the log bit, push an entry into the modified buffer and add a
309 * decrement buffer entry for each referent object (in the RC space)
310 * before setting the header bit to indicate that it has finished
311 * logging (allowing others in the race to continue).
312 *
313 * @param srcObj The object being mutated
314 */
315 @NoInline
316 private void coalescingWriteBarrierSlow(ObjectReference srcObj) {
317 if (RCHeader.attemptToLog(srcObj)) {
318 modBuffer.push(srcObj);
319 decBuffer.processChildren(srcObj);
320 RCHeader.makeLogged(srcObj);
321 }
322 }
323
324 /****************************************************************************
325 *
326 * Miscellaneous
327 */
328
329 /** @return The active global plan as an <code>RC</code> instance. */
330 @Inline
331 private static RCBase global() {
332 return (RCBase) VM.activePlan.global();
333 }
334 }