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;
014
015 import org.mmtk.policy.Space;
016 import org.mmtk.utility.Constants;
017 import org.mmtk.utility.Log;
018 import org.mmtk.utility.alloc.Allocator;
019 import org.mmtk.utility.options.*;
020 import org.mmtk.utility.statistics.Timer;
021 import org.mmtk.vm.VM;
022
023 import org.vmmagic.pragma.*;
024
025 /**
026 * This abstract class implements the core functionality for
027 * simple collectors.<p>
028 *
029 * This class defines the collection phases, and provides base
030 * level implementations of them. Subclasses should provide
031 * implementations for the spaces that they introduce, and
032 * delegate up the class hierarchy.<p>
033 *
034 * For details of the split between global and thread-local operations
035 * @see org.mmtk.plan.Plan
036 */
037 @Uninterruptible
038 public abstract class Simple extends Plan implements Constants {
039 /****************************************************************************
040 * Constants
041 */
042
043 /* Shared Timers */
044 private static final Timer refTypeTime = new Timer("refType", false, true);
045 private static final Timer scanTime = new Timer("scan", false, true);
046 private static final Timer finalizeTime = new Timer("finalize", false, true);
047
048 /* Phases */
049 public static final short SET_COLLECTION_KIND = Phase.createSimple("set-collection-kind", null);
050 public static final short INITIATE = Phase.createSimple("initiate", null);
051 public static final short PREPARE = Phase.createSimple("prepare");
052 public static final short PREPARE_STACKS = Phase.createSimple("prepare-stacks", null);
053 public static final short STACK_ROOTS = Phase.createSimple("stacks");
054 public static final short ROOTS = Phase.createSimple("root");
055 public static final short CLOSURE = Phase.createSimple("closure", scanTime);
056 public static final short SOFT_REFS = Phase.createSimple("soft-ref", refTypeTime);
057 public static final short WEAK_REFS = Phase.createSimple("weak-ref", refTypeTime);
058 public static final short FINALIZABLE = Phase.createSimple("finalize", finalizeTime);
059 public static final short WEAK_TRACK_REFS = Phase.createSimple("weak-track-ref", refTypeTime);
060 public static final short PHANTOM_REFS = Phase.createSimple("phantom-ref", refTypeTime);
061 public static final short FORWARD = Phase.createSimple("forward");
062 public static final short FORWARD_REFS = Phase.createSimple("forward-ref", refTypeTime);
063 public static final short FORWARD_FINALIZABLE = Phase.createSimple("forward-finalize", finalizeTime);
064 public static final short RELEASE = Phase.createSimple("release");
065 public static final short COMPLETE = Phase.createSimple("complete", null);
066
067 /* Sanity placeholder */
068 public static final short PRE_SANITY_PLACEHOLDER = Phase.createSimple("pre-sanity-placeholder", null);
069 public static final short POST_SANITY_PLACEHOLDER = Phase.createSimple("post-sanity-placeholder", null);
070
071 /* Sanity phases */
072 public static final short SANITY_SET_PREGC = Phase.createSimple("sanity-setpre", null);
073 public static final short SANITY_SET_POSTGC = Phase.createSimple("sanity-setpost", null);
074 public static final short SANITY_PREPARE = Phase.createSimple("sanity-prepare", null);
075 public static final short SANITY_ROOTS = Phase.createSimple("sanity-roots", null);
076 public static final short SANITY_COPY_ROOTS = Phase.createSimple("sanity-copy-roots", null);
077 public static final short SANITY_BUILD_TABLE = Phase.createSimple("sanity-build-table", null);
078 public static final short SANITY_CHECK_TABLE = Phase.createSimple("sanity-check-table", null);
079 public static final short SANITY_RELEASE = Phase.createSimple("sanity-release", null);
080
081 // CHECKSTYLE:OFF
082
083 /** Ensure stacks are ready to be scanned */
084 protected static final short prepareStacks = Phase.createComplex("prepare-stacks", null,
085 Phase.scheduleMutator (PREPARE_STACKS),
086 Phase.scheduleGlobal (PREPARE_STACKS));
087
088 /** Trace and set up a sanity table */
089 protected static final short sanityBuildPhase = Phase.createComplex("sanity-build", null,
090 Phase.scheduleGlobal (SANITY_PREPARE),
091 Phase.scheduleCollector (SANITY_PREPARE),
092 Phase.scheduleComplex (prepareStacks),
093 Phase.scheduleCollector (SANITY_ROOTS),
094 Phase.scheduleGlobal (SANITY_ROOTS),
095 Phase.scheduleCollector (SANITY_COPY_ROOTS),
096 Phase.scheduleGlobal (SANITY_BUILD_TABLE));
097
098 /** Validate a sanity table */
099 protected static final short sanityCheckPhase = Phase.createComplex("sanity-check", null,
100 Phase.scheduleGlobal (SANITY_CHECK_TABLE),
101 Phase.scheduleCollector (SANITY_RELEASE),
102 Phase.scheduleGlobal (SANITY_RELEASE));
103
104 /** Start the collection, including preparation for any collected spaces. */
105 protected static final short initPhase = Phase.createComplex("init",
106 Phase.scheduleGlobal (SET_COLLECTION_KIND),
107 Phase.scheduleGlobal (INITIATE),
108 Phase.schedulePlaceholder(PRE_SANITY_PLACEHOLDER));
109
110 /**
111 * Perform the initial determination of liveness from the roots.
112 */
113 protected static final short rootClosurePhase = Phase.createComplex("initial-closure", null,
114 Phase.scheduleMutator (PREPARE),
115 Phase.scheduleGlobal (PREPARE),
116 Phase.scheduleCollector (PREPARE),
117 Phase.scheduleComplex (prepareStacks),
118 Phase.scheduleCollector (STACK_ROOTS),
119 Phase.scheduleGlobal (STACK_ROOTS),
120 Phase.scheduleCollector (ROOTS),
121 Phase.scheduleGlobal (ROOTS),
122 Phase.scheduleGlobal (CLOSURE),
123 Phase.scheduleCollector (CLOSURE));
124
125 /**
126 * Complete closure including reference types and finalizable objects.
127 */
128 protected static final short refTypeClosurePhase = Phase.createComplex("refType-closure", null,
129 Phase.scheduleCollector (SOFT_REFS),
130 Phase.scheduleGlobal (CLOSURE),
131 Phase.scheduleCollector (CLOSURE),
132 Phase.scheduleCollector (WEAK_REFS),
133 Phase.scheduleCollector (FINALIZABLE),
134 Phase.scheduleGlobal (CLOSURE),
135 Phase.scheduleCollector (CLOSURE),
136 Phase.schedulePlaceholder(WEAK_TRACK_REFS),
137 Phase.scheduleCollector (PHANTOM_REFS));
138
139 /**
140 * Ensure that all references in the system are correct.
141 */
142 protected static final short forwardPhase = Phase.createComplex("forward-all", null,
143 /* Finish up */
144 Phase.schedulePlaceholder(FORWARD),
145 Phase.scheduleCollector (FORWARD_REFS),
146 Phase.scheduleCollector (FORWARD_FINALIZABLE));
147
148 /**
149 * Complete closure including reference types and finalizable objects.
150 */
151 protected static final short completeClosurePhase = Phase.createComplex("release", null,
152 Phase.scheduleMutator (RELEASE),
153 Phase.scheduleCollector (RELEASE),
154 Phase.scheduleGlobal (RELEASE));
155
156
157 /**
158 * The collection scheme - this is a small tree of complex phases.
159 */
160 protected static final short finishPhase = Phase.createComplex("finish",
161 Phase.schedulePlaceholder(POST_SANITY_PLACEHOLDER),
162 Phase.scheduleCollector (COMPLETE),
163 Phase.scheduleGlobal (COMPLETE));
164
165 /**
166 * This is the phase that is executed to perform a collection.
167 */
168 public short collection = Phase.createComplex("collection", null,
169 Phase.scheduleComplex(initPhase),
170 Phase.scheduleComplex(rootClosurePhase),
171 Phase.scheduleComplex(refTypeClosurePhase),
172 Phase.scheduleComplex(forwardPhase),
173 Phase.scheduleComplex(completeClosurePhase),
174 Phase.scheduleComplex(finishPhase));
175
176 // CHECKSTYLE:ON
177
178 /**
179 * The current collection attempt.
180 */
181 protected int collectionAttempt;
182
183 /****************************************************************************
184 * Collection
185 */
186
187 /**
188 * {@inheritDoc}
189 */
190 @Override
191 @Inline
192 public void collectionPhase(short phaseId) {
193 if (phaseId == SET_COLLECTION_KIND) {
194 collectionAttempt = Plan.isUserTriggeredCollection() ? 1 : Allocator.determineCollectionAttempts();
195 emergencyCollection = !Plan.isInternalTriggeredCollection() &&
196 lastCollectionWasExhaustive() && collectionAttempt > 1;
197 if (emergencyCollection) {
198 if (Options.verbose.getValue() >= 1) Log.write("[Emergency]");
199 forceFullHeapCollection();
200 }
201 return;
202 }
203
204 if (phaseId == INITIATE) {
205 setGCStatus(GC_PREPARE);
206 return;
207 }
208
209 if (phaseId == PREPARE_STACKS) {
210 stacksPrepared = true;
211 return;
212 }
213
214 if (phaseId == PREPARE) {
215 loSpace.prepare(true);
216 nonMovingSpace.prepare(true);
217 if (USE_CODE_SPACE) {
218 smallCodeSpace.prepare(true);
219 largeCodeSpace.prepare(true);
220 }
221 immortalSpace.prepare();
222 VM.memory.globalPrepareVMSpace();
223 return;
224 }
225
226 if (phaseId == STACK_ROOTS) {
227 VM.scanning.notifyInitialThreadScanComplete();
228 setGCStatus(GC_PROPER);
229 return;
230 }
231
232 if (phaseId == ROOTS) {
233 VM.scanning.resetThreadCounter();
234 setGCStatus(GC_PROPER);
235 return;
236 }
237
238 if (phaseId == RELEASE) {
239 loSpace.release(true);
240 nonMovingSpace.release();
241 if (USE_CODE_SPACE) {
242 smallCodeSpace.release();
243 largeCodeSpace.release(true);
244 }
245 immortalSpace.release();
246 VM.memory.globalReleaseVMSpace();
247 return;
248 }
249
250 if (phaseId == COMPLETE) {
251 setGCStatus(NOT_IN_GC);
252 return;
253 }
254
255 if (Options.sanityCheck.getValue() && sanityChecker.collectionPhase(phaseId)) {
256 return;
257 }
258
259 Log.write("Global phase "); Log.write(Phase.getName(phaseId));
260 Log.writeln(" not handled.");
261 VM.assertions.fail("Global phase not handled!");
262 }
263
264 /**
265 * Update the nursery zeroing approach based on option settings.
266 *
267 * @param nurserySpace The space to apply the changes to.
268 */
269 protected void switchNurseryZeroingApproach(Space nurserySpace) {
270 if (Options.nurseryZeroing.getConcurrent()) {
271 if (Options.nurseryZeroing.getAdaptive() &&
272 (VM.collection.getActiveThreads() >= VM.collection.getDefaultThreads())) {
273 // Many (non-daemon) threads, so we revert to bulk zeroing.
274 nurserySpace.skipConcurrentZeroing();
275 } else {
276 nurserySpace.triggerConcurrentZeroing();
277 }
278 }
279 }
280
281 /**
282 * {@inheritDoc}
283 * Used for example to replace a placeholder.
284 */
285 @Override
286 public void replacePhase(int oldScheduledPhase, int newScheduledPhase) {
287 ComplexPhase cp = (ComplexPhase)Phase.getPhase(collection);
288 cp.replacePhase(oldScheduledPhase, newScheduledPhase);
289 }
290
291 /**
292 * Replace a placeholder phase.
293 *
294 * @param placeHolderPhase The placeholder phase
295 * @param newScheduledPhase The new scheduled phase.
296 */
297 public void replacePlaceholderPhase(short placeHolderPhase, int newScheduledPhase) {
298 ComplexPhase cp = (ComplexPhase)Phase.getPhase(collection);
299 cp.replacePhase(Phase.schedulePlaceholder(placeHolderPhase), newScheduledPhase);
300 }
301 }