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.generational;
014
015 import org.mmtk.plan.*;
016 import org.mmtk.policy.CopySpace;
017 import org.mmtk.policy.Space;
018
019 import org.mmtk.utility.deque.*;
020 import org.mmtk.utility.heap.Map;
021 import org.mmtk.utility.heap.VMRequest;
022 import org.mmtk.utility.Log;
023 import org.mmtk.utility.options.Options;
024 import org.mmtk.utility.sanitychecker.SanityChecker;
025 import org.mmtk.utility.statistics.*;
026
027 import org.mmtk.vm.VM;
028
029 import org.vmmagic.pragma.*;
030 import org.vmmagic.unboxed.*;
031
032 /**
033 * This abstract class implements the core functionality of generic
034 * two-generation copying collectors. Nursery collections occur when
035 * either the heap is full or the nursery is full. The nursery size
036 * is determined by an optional command line argument. If undefined,
037 * the nursery size is "infinite", so nursery collections only occur
038 * when the heap is full (this is known as a flexible-sized nursery
039 * collector). Thus both fixed and flexible nursery sizes are
040 * supported. Full heap collections occur when the nursery size has
041 * dropped to a statically defined threshold,
042 * <code>NURSERY_THRESHOLD</code><p>
043 *
044 * See also Plan.java for general comments on local vs global plan
045 * classes.
046 */
047 @Uninterruptible
048 public abstract class Gen extends StopTheWorld {
049
050 /*****************************************************************************
051 *
052 * Constants
053 */
054
055 /**
056 *
057 */
058 public static final float DEFAULT_PRETENURE_THRESHOLD_FRACTION = 0.5f; // if object is bigger than this fraction of nursery, pretenure to LOS
059 protected static final float SURVIVAL_ESTIMATE = 0.8f; // est yield
060 protected static final float MATURE_FRACTION = 0.5f; // est yield
061 private static final float WORST_CASE_COPY_EXPANSION = 1.5f; // worst case for addition of one word overhead due to address based hashing
062 public static final boolean IGNORE_REMSETS = false;
063 public static final boolean USE_NON_HEAP_OBJECT_REFERENCE_WRITE_BARRIER = false;
064 public static final boolean USE_OBJECT_BARRIER_FOR_AASTORE = false; // choose between slot and object barriers
065 public static final boolean USE_OBJECT_BARRIER_FOR_PUTFIELD = false; // choose between slot and object barriers
066 public static final boolean USE_OBJECT_BARRIER = USE_OBJECT_BARRIER_FOR_AASTORE || USE_OBJECT_BARRIER_FOR_PUTFIELD;
067
068 /** Fraction of available virtual memory to give to the nursery (if contiguous) */
069 protected static final float NURSERY_VM_FRACTION = 0.15f;
070
071 /** Switch between a contiguous and discontiguous nursery (experimental) */
072 static final boolean USE_DISCONTIGUOUS_NURSERY = false;
073
074 // Allocators
075 public static final int ALLOC_NURSERY = ALLOC_DEFAULT;
076 public static final int ALLOC_MATURE = StopTheWorld.ALLOCATORS + 1;
077 public static final int ALLOC_MATURE_MINORGC = StopTheWorld.ALLOCATORS + 2;
078 public static final int ALLOC_MATURE_MAJORGC = StopTheWorld.ALLOCATORS + 3;
079
080 public static final int SCAN_NURSERY = 0;
081 public static final int SCAN_MATURE = 1;
082
083 /*****************************************************************************
084 *
085 * Class fields
086 */
087
088 /**
089 *
090 */
091
092 /* Statistics */
093 protected static final BooleanCounter fullHeap = new BooleanCounter("majorGC", true, true);
094 private static final Timer fullHeapTime = new Timer("majorGCTime", false, true);
095 protected static final EventCounter wbFast;
096 protected static final EventCounter wbSlow;
097 public static final SizeCounter nurseryMark;
098 public static final SizeCounter nurseryCons;
099
100 /* The nursery space is where all new objects are allocated by default */
101 private static final VMRequest vmRequest = USE_DISCONTIGUOUS_NURSERY ? VMRequest.create() : VMRequest.create(NURSERY_VM_FRACTION, true);
102 public static final CopySpace nurserySpace = new CopySpace("nursery", false, vmRequest);
103
104 public static final int NURSERY = nurserySpace.getDescriptor();
105 private static final Address NURSERY_START = nurserySpace.getStart();
106
107 /*****************************************************************************
108 *
109 * Instance fields
110 */
111
112 /* status fields */
113
114 /**
115 *
116 */
117 public boolean gcFullHeap = false;
118 public boolean nextGCFullHeap = false;
119
120 /* The trace object */
121 public final Trace nurseryTrace = new Trace(metaDataSpace);
122
123 /**
124 * Remset pools
125 */
126
127 /**
128 *
129 */
130 public final SharedDeque modbufPool = new SharedDeque("modBufs",metaDataSpace, 1);
131 public final SharedDeque remsetPool = new SharedDeque("remSets",metaDataSpace, 1);
132 public final SharedDeque arrayRemsetPool = new SharedDeque("arrayRemSets",metaDataSpace, 2);
133
134 /*
135 * Class initializer
136 */
137 static {
138 if (GATHER_WRITE_BARRIER_STATS) {
139 wbFast = new EventCounter("wbFast");
140 wbSlow = new EventCounter("wbSlow");
141 } else {
142 wbFast = null;
143 wbSlow = null;
144 }
145 if (Stats.GATHER_MARK_CONS_STATS) {
146 nurseryMark = new SizeCounter("nurseryMark", true, true);
147 nurseryCons = new SizeCounter("nurseryCons", true, true);
148 } else {
149 nurseryMark = null;
150 nurseryCons = null;
151 }
152 }
153
154 /*****************************************************************************
155 *
156 * Collection
157 */
158
159 /**
160 * {@inheritDoc}
161 */
162 @Override
163 public void forceFullHeapCollection() {
164 nextGCFullHeap = true;
165 }
166
167 @Override
168 @NoInline
169 public void collectionPhase(short phaseId) {
170 if (phaseId == SET_COLLECTION_KIND) {
171 super.collectionPhase(phaseId);
172 gcFullHeap = requiresFullHeapCollection();
173 return;
174 }
175
176 if (phaseId == PREPARE) {
177 nurserySpace.prepare(true);
178 if (traceFullHeap()){
179 if (gcFullHeap) {
180 if (Stats.gatheringStats()) fullHeap.set();
181 fullHeapTime.start();
182 }
183 super.collectionPhase(phaseId);
184
185 // we can throw away the remsets (but not modbuf) for a full heap GC
186 remsetPool.clearDeque(1);
187 arrayRemsetPool.clearDeque(2);
188 }
189 return;
190 }
191
192 if (phaseId == CLOSURE) {
193 if (!traceFullHeap()) {
194 nurseryTrace.prepare();
195 }
196 return;
197 }
198
199 if (phaseId == RELEASE) {
200 nurserySpace.release();
201 switchNurseryZeroingApproach(nurserySpace);
202 modbufPool.clearDeque(1);
203 remsetPool.clearDeque(1);
204 arrayRemsetPool.clearDeque(2);
205 if (!traceFullHeap()) {
206 nurseryTrace.release();
207 } else {
208 super.collectionPhase(phaseId);
209 if (gcFullHeap) fullHeapTime.stop();
210 }
211 nextGCFullHeap = (getPagesAvail() < Options.nurserySize.getMinNursery());
212 return;
213 }
214
215 super.collectionPhase(phaseId);
216 }
217
218 @Override
219 public final boolean collectionRequired(boolean spaceFull, Space space) {
220 int availableNurseryPages = Options.nurserySize.getMaxNursery() - nurserySpace.reservedPages();
221
222 /* periodically recalculate nursery pretenure threshold */
223 Plan.pretenureThreshold = (int) ((availableNurseryPages<<LOG_BYTES_IN_PAGE) * Options.pretenureThresholdFraction.getValue());
224
225 if (availableNurseryPages <= 0) {
226 return true;
227 }
228
229 if (virtualMemoryExhausted()) {
230 return true;
231 }
232
233 if (spaceFull && space != nurserySpace) {
234 nextGCFullHeap = true;
235 }
236
237 return super.collectionRequired(spaceFull, space);
238 }
239
240 /**
241 * Determine if this GC should be a full heap collection.
242 *
243 * @return <code>true</code> is this GC should be a full heap collection.
244 */
245 protected boolean requiresFullHeapCollection() {
246 if (userTriggeredCollection && Options.fullHeapSystemGC.getValue()) {
247 return true;
248 }
249
250 if (nextGCFullHeap || collectionAttempt > 1) {
251 // Forces full heap collection
252 return true;
253 }
254
255 if (virtualMemoryExhausted()) {
256 return true;
257 }
258
259 return false;
260 }
261
262 /**
263 * Independent of how many pages remain in the page budget (a function of
264 * heap size), we must ensure we never exhaust virtual memory. Therefore
265 * we must never let the nursery grow to the extent that it can't be
266 * copied into the mature space.
267 *
268 * @return {@code true} if the nursery has grown to the extent that it may not be
269 * able to be copied into the mature space.
270 */
271 private boolean virtualMemoryExhausted() {
272 return ((int)(getCollectionReserve() * WORST_CASE_COPY_EXPANSION)) >= getMaturePhysicalPagesAvail();
273 }
274
275 /*****************************************************************************
276 *
277 * Correctness
278 */
279
280 /*****************************************************************************
281 *
282 * Accounting
283 */
284
285 /**
286 * {@inheritDoc}
287 * Simply add the nursery's contribution to that of
288 * the superclass.
289 */
290 @Override
291 public int getPagesUsed() {
292 return (nurserySpace.reservedPages() + super.getPagesUsed());
293 }
294
295 /**
296 * Return the number of pages available for allocation, <i>assuming
297 * all future allocation is to the nursery</i>.
298 *
299 * @return The number of pages available for allocation, <i>assuming
300 * all future allocation is to the nursery</i>.
301 */
302 @Override
303 public int getPagesAvail() {
304 return super.getPagesAvail() >> 1;
305 }
306
307 /**
308 * Return the number of pages reserved for collection.
309 */
310 @Override
311 public int getCollectionReserve() {
312 return nurserySpace.reservedPages() + super.getCollectionReserve();
313 }
314
315 /**
316 * Return the number of pages available for allocation into the mature
317 * space.
318 *
319 * @return The number of pages available for allocation into the mature
320 * space.
321 */
322 public abstract int getMaturePhysicalPagesAvail();
323
324 /*****************************************************************************
325 *
326 * Miscellaneous
327 */
328
329 /**
330 * Return {@code true} if the address resides within the nursery
331 *
332 * @param addr The object to be tested
333 * @return {@code true} if the address resides within the nursery
334 */
335 @Inline
336 static boolean inNursery(Address addr) {
337 if (USE_DISCONTIGUOUS_NURSERY)
338 return Map.getDescriptorForAddress(addr) == NURSERY;
339 else
340 return addr.GE(NURSERY_START);
341 }
342
343 /**
344 * Return {@code true} if the object resides within the nursery
345 *
346 * @param obj The object to be tested
347 * @return {@code true} if the object resides within the nursery
348 */
349 @Inline
350 static boolean inNursery(ObjectReference obj) {
351 return inNursery(obj.toAddress());
352 }
353
354 /**
355 * @return Does the mature space do copying ?
356 */
357 protected boolean copyMature() {
358 return false;
359 }
360
361 /**
362 * Print pre-collection statistics. In this class we prefix the output
363 * indicating whether the collection was full heap or not.
364 */
365 @Override
366 public void printPreStats() {
367 if ((Options.verbose.getValue() >= 1) && (gcFullHeap))
368 Log.write("[Full heap]");
369 super.printPreStats();
370 }
371
372 /**
373 * Accessor method to allow the generic generational code in Gen.java
374 * to access the mature space.
375 *
376 * @return The mature space, set by each subclass of <code>Gen</code>.
377 */
378 protected abstract Space activeMatureSpace();
379
380 /**
381 * @return {@code true} if we should trace the whole heap during collection. True if
382 * we're ignoring remsets or if we're doing a full heap GC.
383 */
384 public final boolean traceFullHeap() {
385 return IGNORE_REMSETS || gcFullHeap;
386 }
387
388 @Override
389 public final boolean isCurrentGCNursery() {
390 return !(IGNORE_REMSETS || gcFullHeap);
391 }
392
393 @Override
394 public final boolean lastCollectionFullHeap() {
395 return gcFullHeap;
396 }
397
398 @Override
399 public boolean willNeverMove(ObjectReference object) {
400 if (Space.isInSpace(NURSERY, object))
401 return false;
402 return super.willNeverMove(object);
403 }
404
405 @Override
406 public int sanityExpectedRC(ObjectReference object, int sanityRootRC) {
407 Space space = Space.getSpaceForObject(object);
408
409 // Nursery
410 if (space == Gen.nurserySpace) {
411 return SanityChecker.DEAD;
412 }
413
414 // Immortal spaces
415 if (space == Gen.immortalSpace || space == Gen.vmSpace) {
416 return space.isReachable(object) ? SanityChecker.ALIVE : SanityChecker.DEAD;
417 }
418
419 // Mature space (nursery collection)
420 if (VM.activePlan.global().isCurrentGCNursery()) {
421 return SanityChecker.UNSURE;
422 }
423
424 // Mature space (full heap collection)
425 return space.isReachable(object) ? SanityChecker.ALIVE : SanityChecker.DEAD;
426 }
427
428 @Override
429 @Interruptible
430 protected void registerSpecializedMethods() {
431 TransitiveClosure.registerSpecializedScan(SCAN_NURSERY, GenNurseryTraceLocal.class);
432 super.registerSpecializedMethods();
433 }
434
435 @Interruptible
436 @Override
437 public void fullyBooted() {
438 super.fullyBooted();
439 nurserySpace.setZeroingApproach(Options.nurseryZeroing.getNonTemporal(), Options.nurseryZeroing.getConcurrent());
440 }
441 }