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.policy; 014 015import org.mmtk.plan.TransitiveClosure; 016import org.mmtk.utility.heap.*; 017import org.mmtk.utility.options.Options; 018import org.mmtk.utility.options.MarkSweepMarkBits; 019import org.mmtk.utility.options.EagerCompleteSweep; 020import org.mmtk.utility.HeaderByte; 021 022import org.mmtk.vm.VM; 023 024import org.vmmagic.pragma.*; 025import org.vmmagic.unboxed.*; 026 027/** 028 * Each instance of this class corresponds to one mark-sweep *space*. 029 * Each of the instance methods of this class may be called by any 030 * thread (i.e. synchronization must be explicit in any instance or 031 * class method). This contrasts with the MarkSweepLocal, where 032 * instances correspond to *plan* instances and therefore to kernel 033 * threads. Thus unlike this class, synchronization is not necessary 034 * in the instance methods of MarkSweepLocal. 035 */ 036@Uninterruptible 037public final class MarkSweepSpace extends SegregatedFreeListSpace { 038 039 /**************************************************************************** 040 * 041 * Class variables 042 */ 043 044 /** 045 * Select between using mark bits in a side bitmap, or mark bits 046 * in the headers of object (or other sub-class scheme), and a single 047 * mark bit per block. 048 */ 049 public static final boolean HEADER_MARK_BITS = VM.config.HEADER_MARK_BITS; 050 /** highest bit bits we may use */ 051 private static final int AVAILABLE_LOCAL_BITS = 8 - HeaderByte.USED_GLOBAL_BITS; 052 053 /* mark bits */ 054 private static final int COUNT_BASE = 0; 055 056 public static final int DEFAULT_MARKCOUNT_BITS = 4; 057 public static final int MAX_MARKCOUNT_BITS = AVAILABLE_LOCAL_BITS - COUNT_BASE; 058 private static final byte MARK_COUNT_INCREMENT = (byte) (1 << COUNT_BASE); 059 private static final byte MARK_COUNT_MASK = (byte) (((1 << MAX_MARKCOUNT_BITS) - 1) << COUNT_BASE); 060 061 private static final boolean EAGER_MARK_CLEAR = HeaderByte.NEEDS_UNLOGGED_BIT; 062 063 /* header requirements */ 064 public static final int LOCAL_GC_BITS_REQUIRED = MAX_MARKCOUNT_BITS; 065 public static final int GLOBAL_GC_BITS_REQUIRED = 0; 066 public static final int GC_HEADER_WORDS_REQUIRED = 0; 067 068 069 /**************************************************************************** 070 * 071 * Instance variables 072 */ 073 074 /** 075 * 076 */ 077 private byte markState = 1; 078 private byte allocState = 0; 079 private boolean inMSCollection; 080 private static final boolean usingStickyMarkBits = VM.activePlan.constraints().needsLogBitInHeader(); /* are sticky mark bits in use? */ 081 private boolean isAgeSegregated = false; /* is this space a nursery space? */ 082 private boolean isAllocAsMarked = false; 083 084 /**************************************************************************** 085 * 086 * Initialization 087 */ 088 089 static { 090 Options.markSweepMarkBits = new MarkSweepMarkBits(); 091 Options.eagerCompleteSweep = new EagerCompleteSweep(); 092 } 093 094 /** 095 * The caller specifies the region of virtual memory to be used for 096 * this space. If this region conflicts with an existing space, 097 * then the constructor will fail. 098 * 099 * @param name The name of this space (used when printing error messages etc) 100 * @param vmRequest An object describing the virtual memory requested. 101 */ 102 public MarkSweepSpace(String name, VMRequest vmRequest) { 103 super(name, 0, vmRequest); 104 if (usingStickyMarkBits) allocState |= HeaderByte.UNLOGGED_BIT; 105 } 106 107 /** 108 * This instance will be age-segregated using the sticky mark bits 109 * algorithm. Perform appropriate initialization 110 */ 111 public void makeAgeSegregatedSpace() { 112 /* we must be using sticky mark bits */ 113 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(usingStickyMarkBits); 114 allocState &= ~HeaderByte.UNLOGGED_BIT; /* clear the unlogged bit for nursery allocs */ 115 isAgeSegregated = true; 116 } 117 118 /** 119 * Should SegregatedFreeListSpace manage a side bitmap to keep track of live objects? 120 */ 121 @Override 122 @Inline 123 protected boolean maintainSideBitmap() { 124 return !HEADER_MARK_BITS; 125 } 126 127 @Override 128 @Inline 129 protected boolean preserveFreeList() { 130 return !LAZY_SWEEP; 131 } 132 133 /**************************************************************************** 134 * 135 * Allocation 136 */ 137 138 /** 139 * Prepare the next block in the free block list for use by the free 140 * list allocator. In the case of lazy sweeping this involves 141 * sweeping the available cells. <b>The sweeping operation must 142 * ensure that cells are pre-zeroed</b>, as this method must return 143 * pre-zeroed cells. 144 * 145 * @param block The block to be prepared for use 146 * @param sizeClass The size class of the block 147 * @return The address of the first pre-zeroed cell in the free list 148 * for this block, or zero if there are no available cells. 149 */ 150 @Override 151 protected Address advanceToBlock(Address block, int sizeClass) { 152 if (HEADER_MARK_BITS) { 153 if (inMSCollection) markBlock(block); 154 } 155 156 if (LAZY_SWEEP) { 157 return makeFreeList(block, sizeClass); 158 } else { 159 return getFreeList(block); 160 } 161 } 162 163 /** 164 * {@inheritDoc}<p> 165 * 166 * This is to ensure that appropriate collection state can be initialized 167 * for the block. 168 */ 169 @Override 170 protected void notifyNewBlock(Address block, int sizeClass) { 171 if (HEADER_MARK_BITS) { 172 if (inMSCollection) markBlock(block); 173 } 174 } 175 176 /**************************************************************************** 177 * 178 * Collection 179 */ 180 181 /** 182 * Prepare for a new collection increment. For the mark-sweep 183 * collector we must flip the state of the mark bit between 184 * collections. 185 * 186 * @param gcWholeMS True if we are going to collect the whole marksweep space 187 */ 188 public void prepare(boolean gcWholeMS) { 189 if (HEADER_MARK_BITS && Options.eagerCompleteSweep.getValue()) { 190 consumeBlocks(); 191 } else { 192 flushAvailableBlocks(); 193 } 194 if (HEADER_MARK_BITS) { 195 if (gcWholeMS) { 196 allocState = markState; 197 if (usingStickyMarkBits && !isAgeSegregated) /* if true, we allocate as "mature", not nursery */ 198 allocState |= HeaderByte.UNLOGGED_BIT; 199 markState = deltaMarkState(true); 200 if (EAGER_MARK_CLEAR) 201 clearAllBlockMarks(); 202 } 203 } else { 204 zeroLiveBits(); 205 } 206 inMSCollection = true; 207 } 208 209 /** 210 * A new collection increment has completed. For the mark-sweep 211 * collector this means we can perform the sweep phase. 212 */ 213 public void release() { 214 sweepConsumedBlocks(!EAGER_MARK_CLEAR); 215 inMSCollection = false; 216 } 217 218 /** 219 * Release an allocated page or pages 220 * 221 * @param start The address of the start of the page or pages 222 */ 223 @Override 224 @Inline 225 public void release(Address start) { 226 ((FreeListPageResource) pr).releasePages(start); 227 } 228 229 /** 230 * Should the sweep reclaim the cell containing this object. Is this object 231 * live. This is only used when maintainSideBitmap is false. 232 * 233 * @param object The object to query 234 * @return True if the cell should be reclaimed 235 */ 236 @Override 237 @Inline 238 protected boolean isCellLive(ObjectReference object) { 239 if (!HEADER_MARK_BITS) { 240 return super.isCellLive(object); 241 } 242 return testMarkState(object); 243 } 244 245 /**************************************************************************** 246 * 247 * Object processing and tracing 248 */ 249 250 /** 251 * Trace a reference to an object under a mark sweep collection 252 * policy. If the object header is not already marked, mark the 253 * object in either the bitmap or by moving it off the treadmill, 254 * and enqueue the object for subsequent processing. The object is 255 * marked as (an atomic) side-effect of checking whether already 256 * marked. 257 * 258 * @param object The object to be traced. 259 * @return The object (there is no object forwarding in this 260 * collector, so we always return the same object: this could be a 261 * void method but for compliance to a more general interface). 262 */ 263 @Override 264 @Inline 265 public ObjectReference traceObject(TransitiveClosure trace, ObjectReference object) { 266 if (HEADER_MARK_BITS) { 267 if (testAndMark(object)) { 268 markBlock(object); 269 trace.processNode(object); 270 } 271 } else { 272 if (testAndSetLiveBit(object)) { 273 trace.processNode(object); 274 } 275 } 276 return object; 277 } 278 279 /** 280 * @return {@code true} if this object is known to be live (i.e. it is marked) 281 */ 282 @Override 283 @Inline 284 public boolean isLive(ObjectReference object) { 285 if (HEADER_MARK_BITS) { 286 return testMarkState(object); 287 } else { 288 return liveBitSet(object); 289 } 290 } 291 292 /** 293 * Get the previous mark state. 294 * 295 * @return The previous mark state. 296 */ 297 @Inline 298 public byte getPreviousMarkState() { 299 return deltaMarkState(false); 300 } 301 302 /** 303 * Return the mark state incremented or decremented by one. 304 * 305 * @param increment If true, then return the incremented value else return the decremented value 306 * @return the mark state incremented or decremented by one. 307 */ 308 private byte deltaMarkState(boolean increment) { 309 byte mask = (byte) (((1 << Options.markSweepMarkBits.getValue()) - 1) << COUNT_BASE); 310 byte rtn = (byte) (increment ? markState + MARK_COUNT_INCREMENT : markState - MARK_COUNT_INCREMENT); 311 rtn &= mask; 312 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((markState & ~MARK_COUNT_MASK) == 0); 313 return rtn; 314 } 315 316 /**************************************************************************** 317 * 318 * Header manipulation 319 */ 320 321 /** 322 * Perform any required post allocation initialization 323 * 324 * @param object the object ref to the storage to be initialized 325 */ 326 @Inline 327 public void postAlloc(ObjectReference object) { 328 initializeHeader(object, true); 329 } 330 331 /** 332 * Perform any required post copy (i.e. in-GC allocation) initialization. 333 * This is relevant (for example) when MS is used as the mature space in 334 * a copying GC. 335 * 336 * @param object the object ref to the storage to be initialized 337 * @param majorGC Is this copy happening during a major gc? 338 */ 339 @Inline 340 public void postCopy(ObjectReference object, boolean majorGC) { 341 initializeHeader(object, false); 342 if (!HEADER_MARK_BITS) { 343 testAndSetLiveBit(object); 344 } 345 } 346 347 /** 348 * Perform any required initialization of the GC portion of the header. 349 * 350 * @param object the object ref to the storage to be initialized 351 * @param alloc is this initialization occuring due to (initial) allocation 352 * (true) or due to copying (false)? 353 */ 354 @Inline 355 public void initializeHeader(ObjectReference object, boolean alloc) { 356 if (HEADER_MARK_BITS) { 357 byte oldValue = VM.objectModel.readAvailableByte(object); 358 byte newValue = (byte) ((oldValue & ~MARK_COUNT_MASK) | (alloc && !isAllocAsMarked ? allocState : markState)); 359 VM.objectModel.writeAvailableByte(object, newValue); 360 } else if (HeaderByte.NEEDS_UNLOGGED_BIT) 361 HeaderByte.markAsUnlogged(object); 362 } 363 364 /** 365 * Atomically attempt to set the mark bit of an object. 366 * 367 * @param object The object whose mark bit is to be set 368 * @return {@code true} if successful, {@code false} if the mark 369 * bit was already set 370 */ 371 @Inline 372 private boolean testAndMark(ObjectReference object) { 373 byte oldValue, markBits, newValue; 374 oldValue = VM.objectModel.readAvailableByte(object); 375 markBits = (byte) (oldValue & MARK_COUNT_MASK); 376 if (markBits == markState) return false; 377 newValue = (byte)((oldValue & ~MARK_COUNT_MASK) | markState); 378 if (HeaderByte.NEEDS_UNLOGGED_BIT) newValue |= HeaderByte.UNLOGGED_BIT; 379 VM.objectModel.writeAvailableByte(object, newValue); 380 return true; 381 } 382 383 /** 384 * Return true if the mark count for an object has the given value. 385 * 386 * @param object The object whose mark bit is to be tested 387 * @return <code>true</code> if the mark bit for the object is set. 388 */ 389 @Inline 390 private boolean testMarkState(ObjectReference object) { 391 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((markState & ~MARK_COUNT_MASK) == 0); 392 return (VM.objectModel.readAvailableByte(object) & MARK_COUNT_MASK) == markState; 393 } 394 395 public void makeAllocAsMarked() { 396 isAllocAsMarked = true; 397 } 398}