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.Phase;
016 import org.mmtk.plan.StopTheWorldCollector;
017 import org.mmtk.plan.TraceLocal;
018 import org.mmtk.plan.TransitiveClosure;
019 import org.mmtk.plan.refcount.backuptrace.BTTraceLocal;
020 import org.mmtk.policy.Space;
021 import org.mmtk.policy.ExplicitFreeListSpace;
022 import org.mmtk.utility.deque.ObjectReferenceDeque;
023 import org.mmtk.vm.VM;
024 import org.vmmagic.pragma.Inline;
025 import org.vmmagic.pragma.Uninterruptible;
026 import org.vmmagic.unboxed.ObjectReference;
027
028 /**
029 * This class implements the collector 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 abstract class RCBaseCollector extends StopTheWorldCollector {
037
038 /************************************************************************
039 * Initialization
040 */
041
042 /**
043 *
044 */
045 protected final ObjectReferenceDeque newRootBuffer;
046 private final BTTraceLocal backupTrace;
047 private final ObjectReferenceDeque modBuffer;
048 private final ObjectReferenceDeque oldRootBuffer;
049 private final RCDecBuffer decBuffer;
050 private final RCZero zero;
051
052 /**
053 * Constructor.
054 */
055 public RCBaseCollector() {
056 newRootBuffer = new ObjectReferenceDeque("new-root", global().newRootPool);
057 oldRootBuffer = new ObjectReferenceDeque("old-root", global().oldRootPool);
058 modBuffer = new ObjectReferenceDeque("mod buf", global().modPool);
059 decBuffer = new RCDecBuffer(global().decPool);
060 backupTrace = new BTTraceLocal(global().backupTrace);
061 zero = new RCZero();
062 }
063
064 /**
065 * Get the modified processor to use.
066 */
067 protected abstract TransitiveClosure getModifiedProcessor();
068
069 /**
070 * Get the root trace to use.
071 */
072 protected abstract TraceLocal getRootTrace();
073
074 /****************************************************************************
075 *
076 * Collection
077 */
078
079 /**
080 * {@inheritDoc}
081 */
082 @Override
083 public void collect() {
084 if (RCBase.BUILD_FOR_GENRC) Phase.beginNewPhaseStack(Phase.scheduleComplex(global().genRCCollection));
085 else Phase.beginNewPhaseStack(Phase.scheduleComplex(global().refCountCollection));
086 }
087
088 @Override
089 public void collectionPhase(short phaseId, boolean primary) {
090 if (phaseId == RCBase.PREPARE) {
091 getRootTrace().prepare();
092 if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) backupTrace.prepare();
093 return;
094 }
095
096 if (phaseId == RCBase.CLOSURE) {
097 getRootTrace().completeTrace();
098 newRootBuffer.flushLocal();
099 return;
100 }
101
102 if (phaseId == RCBase.BT_CLOSURE) {
103 if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
104 backupTrace.completeTrace();
105 }
106 return;
107 }
108
109 if (phaseId == RCBase.PROCESS_OLDROOTBUFFER) {
110 if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) return;
111 ObjectReference current;
112 while(!(current = oldRootBuffer.pop()).isNull()) {
113 decBuffer.push(current);
114 }
115 return;
116 }
117
118 if (phaseId == RCBase.PROCESS_NEWROOTBUFFER) {
119 ObjectReference current;
120 if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
121 while(!(current = newRootBuffer.pop()).isNull()) {
122 if (RCHeader.testAndMark(current)) {
123 if (RCBase.BUILD_FOR_GENRC) {
124 RCHeader.initRC(current);
125 } else {
126 if (RCHeader.initRC(current) == RCHeader.INC_NEW) {
127 modBuffer.push(current);
128 }
129 }
130 backupTrace.processNode(current);
131 } else {
132 if (RCBase.BUILD_FOR_GENRC) {
133 RCHeader.incRC(current);
134 } else {
135 if (RCHeader.incRC(current) == RCHeader.INC_NEW) {
136 modBuffer.push(current);
137 }
138 }
139 }
140 }
141 if (!RCBase.BUILD_FOR_GENRC) modBuffer.flushLocal();
142 return;
143 }
144 while(!(current = newRootBuffer.pop()).isNull()) {
145 if (RCBase.BUILD_FOR_GENRC) {
146 RCHeader.incRC(current);
147 } else {
148 if (RCHeader.incRC(current) == RCHeader.INC_NEW) {
149 modBuffer.push(current);
150 }
151 }
152 oldRootBuffer.push(current);
153 }
154 oldRootBuffer.flushLocal();
155 if (!RCBase.BUILD_FOR_GENRC) modBuffer.flushLocal();
156 return;
157 }
158
159 if (phaseId == RCBase.PROCESS_MODBUFFER) {
160 ObjectReference current;
161 while(!(current = modBuffer.pop()).isNull()) {
162 RCHeader.makeUnlogged(current);
163 if (!RCBase.BUILD_FOR_GENRC) {
164 if (Space.isInSpace(RCBase.REF_COUNT, current)) {
165 ExplicitFreeListSpace.testAndSetLiveBit(current);
166 }
167 }
168 VM.scanning.scanObject(getModifiedProcessor(), current);
169 }
170 return;
171 }
172
173 if (phaseId == RCBase.PROCESS_DECBUFFER) {
174 ObjectReference current;
175 if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
176 if (!RCBase.BUILD_FOR_GENRC) {
177 while(!(current = decBuffer.pop()).isNull()) {
178 if (RCHeader.isNew(current)) {
179 if (Space.isInSpace(RCBase.REF_COUNT, current)) {
180 RCBase.rcSpace.free(current);
181 } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) {
182 RCBase.rcloSpace.free(current);
183 } else if (Space.isInSpace(RCBase.IMMORTAL, current)) {
184 VM.scanning.scanObject(zero, current);
185 }
186 }
187 }
188 }
189 return;
190 }
191 while(!(current = decBuffer.pop()).isNull()) {
192 if (RCBase.BUILD_FOR_GENRC) {
193 if (RCHeader.decRC(current) == RCHeader.DEC_KILL) {
194 decBuffer.processChildren(current);
195 if (Space.isInSpace(RCBase.REF_COUNT, current)) {
196 RCBase.rcSpace.free(current);
197 } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) {
198 RCBase.rcloSpace.free(current);
199 } else if (Space.isInSpace(RCBase.IMMORTAL, current)) {
200 VM.scanning.scanObject(zero, current);
201 }
202 }
203 } else {
204 if (RCHeader.isNew(current)) {
205 if (Space.isInSpace(RCBase.REF_COUNT, current)) {
206 RCBase.rcSpace.free(current);
207 } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) {
208 RCBase.rcloSpace.free(current);
209 } else if (Space.isInSpace(RCBase.IMMORTAL, current)) {
210 VM.scanning.scanObject(zero, current);
211 }
212 } else {
213 if (RCHeader.decRC(current) == RCHeader.DEC_KILL) {
214 decBuffer.processChildren(current);
215 if (Space.isInSpace(RCBase.REF_COUNT, current)) {
216 RCBase.rcSpace.free(current);
217 } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) {
218 RCBase.rcloSpace.free(current);
219 } else if (Space.isInSpace(RCBase.IMMORTAL, current)) {
220 VM.scanning.scanObject(zero, current);
221 }
222 }
223 }
224 }
225 }
226 return;
227 }
228
229 if (phaseId == RCBase.RELEASE) {
230 if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
231 backupTrace.release();
232 global().oldRootPool.clearDeque(1);
233 if (RCBase.BUILD_FOR_GENRC) global().decPool.clearDeque(1);
234 }
235 getRootTrace().release();
236 if (VM.VERIFY_ASSERTIONS) {
237 VM.assertions._assert(newRootBuffer.isEmpty());
238 VM.assertions._assert(modBuffer.isEmpty());
239 VM.assertions._assert(decBuffer.isEmpty());
240 }
241 return;
242 }
243
244 super.collectionPhase(phaseId, primary);
245 }
246
247 /****************************************************************************
248 *
249 * Miscellaneous
250 */
251
252 /** @return The active global plan as an <code>RC</code> instance. */
253 @Inline
254 protected static RCBase global() {
255 return (RCBase) VM.activePlan.global();
256 }
257
258 @Override
259 public final TraceLocal getCurrentTrace() {
260 return getRootTrace();
261 }
262
263 /** @return The current modBuffer instance. */
264 @Inline
265 public final ObjectReferenceDeque getModBuffer() {
266 return modBuffer;
267 }
268 }