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