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