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.StopTheWorld;
017 import org.mmtk.plan.Trace;
018 import org.mmtk.plan.refcount.backuptrace.BTFreeLargeObjectSweeper;
019 import org.mmtk.plan.refcount.backuptrace.BTScanLargeObjectSweeper;
020 import org.mmtk.plan.refcount.backuptrace.BTSweeper;
021 import org.mmtk.policy.ExplicitFreeListSpace;
022 import org.mmtk.policy.ExplicitLargeObjectSpace;
023 import org.mmtk.policy.Space;
024 import org.mmtk.utility.Log;
025 import org.mmtk.utility.alloc.LinearScan;
026 import org.mmtk.utility.deque.SharedDeque;
027 import org.mmtk.utility.heap.VMRequest;
028 import org.mmtk.utility.options.Options;
029 import org.mmtk.utility.sanitychecker.SanityChecker;
030 import org.mmtk.vm.VM;
031
032 import org.vmmagic.pragma.*;
033 import org.vmmagic.unboxed.ObjectReference;
034
035 /**
036 * This class implements the global state of a a simple reference counting collector.
037 */
038 @Uninterruptible
039 public class RCBase extends StopTheWorld {
040 public static final short PROCESS_OLDROOTBUFFER = Phase.createSimple("old-root");
041 public static final short PROCESS_NEWROOTBUFFER = Phase.createSimple("new-root");
042 public static final short PROCESS_MODBUFFER = Phase.createSimple("mods");
043 public static final short PROCESS_DECBUFFER = Phase.createSimple("decs");
044
045 /** Is cycle collection enabled? */
046 public static final boolean CC_ENABLED = true;
047 /** Force full cycle collection at each GC? */
048 public static final boolean CC_FORCE_FULL = false;
049 /** Use backup tracing for cycle collection (currently the only option) */
050 public static final boolean CC_BACKUP_TRACE = true;
051
052 public static boolean performCycleCollection;
053 public static final short BT_CLOSURE = Phase.createSimple("closure-bt");
054
055 // CHECKSTYLE:OFF
056
057 /**
058 * Reference counting specific collection steps.
059 */
060 protected static final short refCountCollectionPhase = Phase.createComplex("release", null,
061 Phase.scheduleGlobal (PROCESS_OLDROOTBUFFER),
062 Phase.scheduleCollector (PROCESS_OLDROOTBUFFER),
063 Phase.scheduleGlobal (PROCESS_NEWROOTBUFFER),
064 Phase.scheduleCollector (PROCESS_NEWROOTBUFFER),
065 Phase.scheduleMutator (PROCESS_DECBUFFER),
066 Phase.scheduleGlobal (PROCESS_DECBUFFER),
067 Phase.scheduleCollector (PROCESS_DECBUFFER),
068 Phase.scheduleGlobal (BT_CLOSURE),
069 Phase.scheduleCollector (BT_CLOSURE));
070
071 /**
072 * Perform the initial determination of liveness from the roots.
073 */
074 protected static final short rootClosurePhase = Phase.createComplex("initial-closure", null,
075 Phase.scheduleMutator (PREPARE),
076 Phase.scheduleGlobal (PREPARE),
077 Phase.scheduleCollector (PREPARE),
078 Phase.scheduleComplex (prepareStacks),
079 Phase.scheduleCollector (PRECOPY),
080 Phase.scheduleCollector (STACK_ROOTS),
081 Phase.scheduleCollector (ROOTS),
082 Phase.scheduleGlobal (ROOTS),
083 Phase.scheduleMutator (PROCESS_MODBUFFER),
084 Phase.scheduleGlobal (PROCESS_MODBUFFER),
085 Phase.scheduleCollector (PROCESS_MODBUFFER),
086 Phase.scheduleGlobal (CLOSURE),
087 Phase.scheduleCollector (CLOSURE));
088
089 /**
090 * This is the phase that is executed to perform a collection.
091 */
092 public short collection = Phase.createComplex("collection", null,
093 Phase.scheduleComplex(initPhase),
094 Phase.scheduleComplex(rootClosurePhase),
095 Phase.scheduleComplex(refCountCollectionPhase),
096 Phase.scheduleComplex(completeClosurePhase),
097 Phase.scheduleComplex(finishPhase));
098
099 // CHECKSTYLE:ON
100
101 /*****************************************************************************
102 *
103 * Class fields
104 */
105 public static final ExplicitFreeListSpace rcSpace = new ExplicitFreeListSpace("rc", DEFAULT_POLL_FREQUENCY, VMRequest.create());
106 public static final ExplicitLargeObjectSpace rcloSpace = new ExplicitLargeObjectSpace("rclos", DEFAULT_POLL_FREQUENCY, VMRequest.create());
107
108 public static final int REF_COUNT = rcSpace.getDescriptor();
109 public static final int REF_COUNT_LOS = rcloSpace.getDescriptor();
110
111 public final SharedDeque modPool = new SharedDeque("mod", metaDataSpace, 1);
112 public final SharedDeque decPool = new SharedDeque("dec", metaDataSpace, 1);
113 public final SharedDeque newRootPool = new SharedDeque("newRoot", metaDataSpace, 1);
114 public final SharedDeque oldRootPool = new SharedDeque("oldRoot", metaDataSpace, 1);
115
116 /*****************************************************************************
117 *
118 * Instance fields
119 */
120 public final Trace rootTrace;
121 public final Trace backupTrace;
122 private final BTSweeper rcSweeper;
123 private final BTScanLargeObjectSweeper loScanSweeper;
124 private final BTFreeLargeObjectSweeper loFreeSweeper;
125
126 /**
127 * Constructor
128 */
129 public RCBase() {
130 Options.noReferenceTypes.setDefaultValue(true);
131 Options.noFinalizer.setDefaultValue(true);
132
133 rootTrace = new Trace(metaDataSpace);
134 backupTrace = new Trace(metaDataSpace);
135 rcSweeper = new BTSweeper();
136 loScanSweeper = new BTScanLargeObjectSweeper();
137 loFreeSweeper = new BTFreeLargeObjectSweeper();
138 }
139
140 /**
141 * The boot method is called early in the boot process before any
142 * allocation.
143 */
144 @Interruptible
145 public void postBoot() {
146 super.postBoot();
147
148 if (!Options.noReferenceTypes.getValue()) {
149 VM.assertions.fail("Reference Types are not supported by RC");
150 }
151 if (!Options.noFinalizer.getValue()) {
152 VM.assertions.fail("Finalizers are not supported by RC");
153 }
154 }
155
156 /*****************************************************************************
157 *
158 * Collection
159 */
160
161 public static final boolean isRCObject(ObjectReference object) {
162 return !object.isNull() && !Space.isInSpace(VM_SPACE, object);
163 }
164
165 /**
166 * @return Whether last GC is a full GC.
167 */
168 public boolean lastCollectionFullHeap() {
169 return performCycleCollection;
170 }
171
172 /**
173 * Perform a (global) collection phase.
174 *
175 * @param phaseId Collection phase
176 */
177 public void collectionPhase(short phaseId) {
178 if (phaseId == SET_COLLECTION_KIND) {
179 super.collectionPhase(phaseId);
180 if (CC_ENABLED) {
181 performCycleCollection = (collectionAttempt > 1) || emergencyCollection || CC_FORCE_FULL;
182 if (performCycleCollection && Options.verbose.getValue() > 0) Log.write(" [CC] ");
183 }
184 return;
185 }
186
187 if (phaseId == PREPARE) {
188 VM.finalizableProcessor.clear();
189 VM.weakReferences.clear();
190 VM.softReferences.clear();
191 VM.phantomReferences.clear();
192 rootTrace.prepare();
193 rcSpace.prepare();
194 if (CC_BACKUP_TRACE && performCycleCollection) {
195 backupTrace.prepare();
196 }
197 return;
198 }
199
200 if (phaseId == CLOSURE) {
201 rootTrace.prepare();
202 return;
203 }
204
205 if (phaseId == BT_CLOSURE) {
206 if (CC_BACKUP_TRACE && performCycleCollection) {
207 backupTrace.prepare();
208 }
209 return;
210 }
211
212 if (phaseId == PROCESS_OLDROOTBUFFER) {
213 oldRootPool.prepare();
214 return;
215 }
216
217 if (phaseId == PROCESS_NEWROOTBUFFER) {
218 newRootPool.prepare();
219 return;
220 }
221
222
223 if (phaseId == PROCESS_MODBUFFER) {
224 modPool.prepare();
225 return;
226 }
227
228 if (phaseId == PROCESS_DECBUFFER) {
229 decPool.prepare();
230 return;
231 }
232
233 if (phaseId == RELEASE) {
234 rootTrace.release();
235 if (CC_BACKUP_TRACE && performCycleCollection) {
236 backupTrace.release();
237 rcSpace.sweepCells(rcSweeper);
238 rcloSpace.sweep(loScanSweeper);
239 rcloSpace.sweep(loFreeSweeper);
240 } else {
241 rcSpace.release();
242 }
243 return;
244 }
245
246 super.collectionPhase(phaseId);
247 }
248
249 /*****************************************************************************
250 *
251 * Accounting
252 */
253
254 /**
255 * Return the number of pages used given the pending
256 * allocation.
257 *
258 * @return The number of pages reserved given the pending
259 * allocation, excluding space reserved for copying.
260 */
261 public int getPagesUsed() {
262 return (rcSpace.reservedPages() + rcloSpace.reservedPages() + super.getPagesUsed());
263 }
264
265 /**
266 * Perform a linear scan across all objects in the heap to check for leaks.
267 */
268 public void sanityLinearScan(LinearScan scan) {
269 //rcSpace.linearScan(scan);
270 }
271
272 /**
273 * Return the expected reference count. For non-reference counting
274 * collectors this becomes a true/false relationship.
275 *
276 * @param object The object to check.
277 * @param sanityRootRC The number of root references to the object.
278 * @return The expected (root excluded) reference count.
279 */
280 public int sanityExpectedRC(ObjectReference object, int sanityRootRC) {
281 if (RCBase.isRCObject(object)) {
282 int fullRC = RCHeader.getRC(object);
283 if (fullRC == 0) {
284 return SanityChecker.DEAD;
285 }
286 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(fullRC >= sanityRootRC);
287 return fullRC - sanityRootRC;
288 }
289 return SanityChecker.ALIVE;
290 }
291
292 /**
293 * Register specialized methods.
294 */
295 @Interruptible
296 protected void registerSpecializedMethods() {
297 super.registerSpecializedMethods();
298 }
299 }