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 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
036 public 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 }