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 static org.mmtk.utility.Constants.*; 016 017import org.mmtk.utility.alloc.BlockAllocator; 018import org.mmtk.utility.alloc.EmbeddedMetaData; 019import org.mmtk.utility.heap.FreeListPageResource; 020import org.mmtk.utility.heap.Map; 021import org.mmtk.utility.heap.VMRequest; 022import org.mmtk.utility.Conversions; 023import org.mmtk.utility.Memory; 024 025import org.mmtk.vm.Lock; 026import org.mmtk.vm.VM; 027 028import org.vmmagic.pragma.*; 029import org.vmmagic.unboxed.*; 030 031/** 032 * Each instance of this class corresponds to one mark-sweep *space*. 033 * Each of the instance methods of this class may be called by any 034 * thread (i.e. synchronization must be explicit in any instance or 035 * class method). This contrasts with the MarkSweepLocal, where 036 * instances correspond to *plan* instances and therefore to kernel 037 * threads. Thus unlike this class, synchronization is not necessary 038 * in the instance methods of MarkSweepLocal. 039 */ 040@Uninterruptible 041public abstract class SegregatedFreeListSpace extends Space { 042 043 /**************************************************************************** 044 * 045 * Class variables 046 */ 047 048 /** 049 * 050 */ 051 protected static final boolean LAZY_SWEEP = true; 052 private static final boolean COMPACT_SIZE_CLASSES = false; 053 protected static final int MIN_CELLS = 6; 054 protected static final int MAX_CELLS = 99; // (1<<(INUSE_BITS-1))-1; 055 protected static final int MAX_CELL_SIZE = 8 << 10; 056 public static final int MAX_FREELIST_OBJECT_BYTES = MAX_CELL_SIZE; 057 058 // live bits etc 059 private static final int OBJECT_LIVE_SHIFT = LOG_MIN_ALIGNMENT; // 4 byte resolution 060 private static final int LOG_BIT_COVERAGE = OBJECT_LIVE_SHIFT; 061 private static final int LOG_LIVE_COVERAGE = LOG_BIT_COVERAGE + LOG_BITS_IN_BYTE; 062 private static final int LIVE_BYTES_PER_REGION = 1 << (EmbeddedMetaData.LOG_BYTES_IN_REGION - LOG_LIVE_COVERAGE); 063 private static final Word WORD_SHIFT_MASK = Word.one().lsh(LOG_BITS_IN_WORD).minus(Extent.one()); 064 private static final int LOG_LIVE_WORD_STRIDE = LOG_LIVE_COVERAGE + LOG_BYTES_IN_WORD; 065 private static final Extent LIVE_WORD_STRIDE = Extent.fromIntSignExtend(1 << LOG_LIVE_WORD_STRIDE); 066 private static final Word LIVE_WORD_STRIDE_MASK = LIVE_WORD_STRIDE.minus(1).toWord().not(); 067 private static final int NET_META_DATA_BYTES_PER_REGION = BlockAllocator.META_DATA_BYTES_PER_REGION + LIVE_BYTES_PER_REGION; 068 protected static final int META_DATA_PAGES_PER_REGION_WITH_BITMAP = Conversions.bytesToPages(Extent.fromIntSignExtend(NET_META_DATA_BYTES_PER_REGION)); 069 protected static final int META_DATA_PAGES_PER_REGION_NO_BITMAP = Conversions.bytesToPages(Extent.fromIntSignExtend(BlockAllocator.META_DATA_BYTES_PER_REGION)); 070 private static final Extent META_DATA_OFFSET = BlockAllocator.META_DATA_EXTENT; 071 072 073 // calculate worst case fragmentation very conservatively 074 private static final int NEW_SIZECLASS_OVERHEAD = sizeClassCount(); // one page wasted per size class 075 private static final int METADATA_OVERHEAD = META_DATA_PAGES_PER_REGION_WITH_BITMAP; // worst case scenario 076 public static final float WORST_CASE_FRAGMENTATION = 1 + ((NEW_SIZECLASS_OVERHEAD + METADATA_OVERHEAD) / (float) EmbeddedMetaData.BYTES_IN_REGION); 077 078 /**************************************************************************** 079 * 080 * Instance variables 081 */ 082 083 /** 084 * 085 */ 086 protected final Lock lock = VM.newLock("SegregatedFreeListGlobal"); 087 protected final AddressArray consumedBlockHead = AddressArray.create(sizeClassCount()); 088 protected final AddressArray flushedBlockHead = AddressArray.create(sizeClassCount()); 089 protected final AddressArray availableBlockHead = AddressArray.create(sizeClassCount()); 090 091 private final int[] cellSize = new int[sizeClassCount()]; 092 private final byte[] blockSizeClass = new byte[sizeClassCount()]; 093 private final int[] blockHeaderSize = new int[sizeClassCount()]; 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 additionalMetadata The number of meta data bytes per region for the subclass. 102 * @param vmRequest An object describing the virtual memory requested. 103 */ 104 public SegregatedFreeListSpace(String name, int additionalMetadata, VMRequest vmRequest) { 105 super(name, false, false, true, vmRequest); 106 initSizeClasses(); 107 int totalMetadata = additionalMetadata; 108 if (maintainSideBitmap()) { 109 totalMetadata += META_DATA_PAGES_PER_REGION_WITH_BITMAP; 110 } else { 111 totalMetadata += META_DATA_PAGES_PER_REGION_NO_BITMAP; 112 } 113 if (vmRequest.isDiscontiguous()) { 114 pr = new FreeListPageResource(this, totalMetadata); 115 } else { 116 pr = new FreeListPageResource(this, start, extent, totalMetadata); 117 } 118 } 119 120 /** 121 * @return whether SegregatedFreeListSpace should manage a side bitmap 122 * to keep track of live objects 123 */ 124 protected abstract boolean maintainSideBitmap(); 125 126 /** 127 * @return whether free lists need to be preserved when blocks 128 * are moved around 129 */ 130 protected abstract boolean preserveFreeList(); 131 132 /**************************************************************************** 133 * 134 * Allocation 135 */ 136 137 /** 138 * Returns a block to the global pool. 139 * 140 * @param block The block to return 141 * @param sizeClass The size class 142 */ 143 public void returnConsumedBlock(Address block, int sizeClass) { 144 returnBlock(block, sizeClass, Address.zero()); 145 } 146 147 /** 148 * Return a block to the global pool. 149 * 150 * @param block The block to return 151 * @param sizeClass The size class 152 * @param freeCell The first free cell in the block. 153 */ 154 public void returnBlock(Address block, int sizeClass, Address freeCell) { 155 if (VM.VERIFY_ASSERTIONS) { 156 VM.assertions._assert(BlockAllocator.getNext(block).isZero()); 157 } 158 if (preserveFreeList()) { 159 setFreeList(block, freeCell); 160 } 161 lock.acquire(); 162 BlockAllocator.setNext(block, consumedBlockHead.get(sizeClass)); 163 consumedBlockHead.set(sizeClass, block); 164 lock.release(); 165 } 166 167 /** 168 * Acquire a new block from the global pool to allocate into. This method 169 * with either return a non-empty free list, or zero when allocation 170 * fails. 171 * 172 * This method will populate the passed in free list for the given size 173 * class and return the address of the block. 174 * 175 * @param sizeClass The size class to allocate into 176 * @param freeList The free list to populate 177 * @return The address of the block 178 */ 179 public Address getAllocationBlock(int sizeClass, AddressArray freeList) { 180 lock.acquire(); 181 Address block; 182 while (!(block = availableBlockHead.get(sizeClass)).isZero()) { 183 availableBlockHead.set(sizeClass, BlockAllocator.getNext(block)); 184 lock.release(); 185 186 /* This block is no longer on any list */ 187 BlockAllocator.setNext(block, Address.zero()); 188 189 /* Can we allocate into this block? */ 190 Address cell = advanceToBlock(block, sizeClass); 191 if (!cell.isZero()) { 192 freeList.set(sizeClass, cell); 193 return block; 194 } 195 196 /* Block was full */ 197 lock.acquire(); 198 BlockAllocator.setNext(block, consumedBlockHead.get(sizeClass)); 199 consumedBlockHead.set(sizeClass, block); 200 } 201 lock.release(); 202 return expandSizeClass(sizeClass, freeList); 203 } 204 205 /** 206 * Expand a particular size class, allocating a new block, breaking 207 * the block into cells and placing those cells on a free list for 208 * that block. The block becomes the current head for this size 209 * class and the address of the first available cell is returned.<p> 210 * 211 * <b>This is guaranteed to return pre-zeroed cells</b> 212 * 213 * @param sizeClass The size class to be expanded 214 * @param freeList The free list to populate. 215 * @return The block that was just allocated. 216 */ 217 @Inline 218 private Address expandSizeClass(int sizeClass, AddressArray freeList) { 219 Address block = BlockAllocator.alloc(this, blockSizeClass[sizeClass]); 220 221 if (block.isZero()) { 222 return Address.zero(); 223 } 224 225 BlockAllocator.setNext(block, Address.zero()); 226 BlockAllocator.setAllClientSizeClass(block, blockSizeClass[sizeClass], (byte) sizeClass); 227 228 notifyNewBlock(block, sizeClass); 229 230 int cellExtent = cellSize[sizeClass]; 231 int blockSize = BlockAllocator.blockSize(blockSizeClass[sizeClass]); 232 int useableBlockSize = blockSize - blockHeaderSize[sizeClass]; 233 Address firstCell = block.plus(blockHeaderSize[sizeClass]); 234 Address sentinel = block.plus(blockSize); 235 236 /* pre-zero the block */ 237 VM.memory.zero(false, firstCell, Extent.fromIntZeroExtend(useableBlockSize)); 238 239 /* construct the free list */ 240 Address nextCell; 241 Address cell = firstCell; 242 while ((nextCell = cell.plus(cellExtent)).LT(sentinel)) { 243 cell.store(nextCell); 244 cell = nextCell; 245 } 246 247 /* Populate the free list */ 248 freeList.set(sizeClass, firstCell); 249 return block; 250 } 251 252 /**************************************************************************** 253 * 254 * Block management 255 */ 256 257 /** 258 * Initialize the size class data structures. 259 */ 260 private void initSizeClasses() { 261 for (int sc = 0; sc < sizeClassCount(); sc++) { 262 cellSize[sc] = getBaseCellSize(sc); 263 for (byte blk = 0; blk < BlockAllocator.BLOCK_SIZE_CLASSES; blk++) { 264 int usableBytes = BlockAllocator.blockSize(blk); 265 int cells = usableBytes / cellSize[sc]; 266 blockSizeClass[sc] = blk; 267 /* cells must start at multiple of MIN_ALIGNMENT because 268 cellSize is also supposed to be multiple, this should do 269 the trick: */ 270 blockHeaderSize[sc] = BlockAllocator.blockSize(blk) - cells * cellSize[sc]; 271 if (((usableBytes < BYTES_IN_PAGE) && (cells * 2 > MAX_CELLS)) || 272 ((usableBytes > (BYTES_IN_PAGE >> 1)) && (cells > MIN_CELLS))) 273 break; 274 } 275 } 276 } 277 278 /** 279 * Get the size class for a given number of bytes.<p> 280 * 281 * We use size classes based on a worst case internal fragmentation 282 * loss target of 1/8. In fact, across sizes from 8 bytes to 512 283 * the average worst case loss is 13.3%, giving an expected loss 284 * (assuming uniform distribution) of about 7%. We avoid using the 285 * Lea class sizes because they were so numerous and therefore 286 * liable to lead to excessive inter-class-size fragmentation.<p> 287 * 288 * This method may segregate arrays and scalars (currently it does 289 * not).<p> 290 * 291 * This method should be more intelligent and take alignment requests 292 * into consideration. The issue with this is that the block header 293 * which can be varied by subclasses can change the alignment of the 294 * cells.<p> 295 * 296 * @param bytes The number of bytes required to accommodate the object 297 * to be allocated. 298 * @return The size class capable of accommodating the allocation request. 299 */ 300 @Inline 301 public final int getSizeClass(int bytes) { 302 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((bytes > 0) && (bytes <= MAX_CELL_SIZE)); 303 304 int sz1 = bytes - 1; 305 306 if (BYTES_IN_ADDRESS == 4) { // 32-bit 307 if (COMPACT_SIZE_CLASSES) 308 return ( 309 (sz1 <= 31) ? (sz1 >> 2) : // 4 bytes apart 310 (sz1 <= 63) ? 4 + (sz1 >> 3) : // 8 bytes apart 311 (sz1 <= 95) ? 8 + (sz1 >> 4) : // 16 bytes apart 312 (sz1 <= 223) ? 14 + (sz1 >> 6) : // 64 bytes apart 313 (sz1 <= 734) ? 17 + (sz1 >> 8) : // 256 bytes apart 314 20 + (sz1 >> 10)); // 1024 bytes apart 315 else 316 return ( 317 (sz1 <= 63) ? (sz1 >> 2) : // 4 bytes apart 318 (sz1 <= 127) ? 12 + (sz1 >> 4) : // 16 bytes apart 319 (sz1 <= 255) ? 16 + (sz1 >> 5) : // 32 bytes apart 320 (sz1 <= 511) ? 20 + (sz1 >> 6) : // 64 bytes apart 321 (sz1 <= 2047) ? 26 + (sz1 >> 8) : // 256 bytes apart 322 32 + (sz1 >> 10)); // 1024 bytes apart 323 } else { // 64-bit 324 if (COMPACT_SIZE_CLASSES) 325 return ( 326 (sz1 <= 95) ? (sz1 >> 3) : // 8 bytes apart 327 (sz1 <= 127) ? 6 + (sz1 >> 4) : // 16 bytes apart 328 (sz1 <= 191) ? 10 + (sz1 >> 5) : // 32 bytes apart 329 (sz1 <= 383) ? 13 + (sz1 >> 6) : // 64 bytes apart 330 (sz1 <= 511) ? 16 + (sz1 >> 7) : // 128 bytes apart 331 (sz1 <= 1023) ? 19 + (sz1 >> 9) : // 512 bytes apart 332 20 + (sz1 >> 10)); // 1024 bytes apart 333 else 334 return ( 335 (sz1 <= 111) ? (sz1 >> 3) : // 8 bytes apart 336 (sz1 <= 223) ? 7 + (sz1 >> 4) : // 16 bytes apart 337 (sz1 <= 319) ? 14 + (sz1 >> 5) : // 32 bytes apart 338 (sz1 <= 575) ? 19 + (sz1 >> 6) : // 64 bytes apart 339 (sz1 <= 2047) ? 26 + (sz1 >> 8) : // 256 bytes apart 340 32 + (sz1 >> 10)); // 1024 bytes apart 341 } 342 } 343 344 /** 345 * Return the size of a basic cell (i.e. not including any cell 346 * header) for a given size class. 347 * 348 * @param sc The size class in question 349 * @return The size of a basic cell (i.e. not including any cell 350 * header). 351 */ 352 @Inline 353 public final int getBaseCellSize(int sc) { 354 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((sc >= 0) && (sc < sizeClassCount())); 355 356 if (BYTES_IN_ADDRESS == 4) { // 32-bit 357 if (COMPACT_SIZE_CLASSES) 358 return ((sc < 8) ? (sc + 1) << 2 : 359 (sc < 12) ? (sc - 3) << 3 : 360 (sc < 16) ? (sc - 7) << 4 : 361 (sc < 18) ? (sc - 13) << 6 : 362 (sc < 21) ? (sc - 16) << 8 : 363 (sc - 19) << 10); 364 else 365 return ((sc < 16) ? (sc + 1) << 2 : 366 (sc < 20) ? (sc - 11) << 4 : 367 (sc < 24) ? (sc - 15) << 5 : 368 (sc < 28) ? (sc - 19) << 6 : 369 (sc < 34) ? (sc - 25) << 8 : 370 (sc - 31) << 10); 371 } else { // 64-bit 372 if (COMPACT_SIZE_CLASSES) 373 return ((sc < 12) ? (sc + 1) << 3 : 374 (sc < 14) ? (sc - 5) << 4 : 375 (sc < 16) ? (sc - 9) << 5 : 376 (sc < 19) ? (sc - 12) << 6 : 377 (sc < 20) ? (sc - 15) << 7 : 378 (sc < 21) ? (sc - 18) << 9 : 379 (sc - 19) << 10); 380 else 381 return ((sc < 14) ? (sc + 1) << 3 : 382 (sc < 21) ? (sc - 6) << 4 : 383 (sc < 24) ? (sc - 13) << 5 : 384 (sc < 28) ? (sc - 18) << 6 : 385 (sc < 34) ? (sc - 25) << 8 : 386 (sc - 31) << 10); 387 } 388 } 389 390 /** 391 * @return the number of distinct size classes. 392 */ 393 @Inline 394 public static int sizeClassCount() { 395 return (COMPACT_SIZE_CLASSES) ? 28 : 40; 396 } 397 398 /**************************************************************************** 399 * 400 * Preserving (saving & restoring) free lists 401 */ 402 403 /** 404 * Prepare a block for allocation, returning a free list into the block. 405 * 406 * @param block The new block 407 * @param sizeClass The block's sizeclass. 408 * @return the head of the free list 409 */ 410 protected abstract Address advanceToBlock(Address block, int sizeClass); 411 412 /** 413 * Notify that a new block has been installed. This is to ensure that 414 * appropriate collection state can be initialized for the block 415 * 416 * @param block The new block 417 * @param sizeClass The block's sizeclass. 418 */ 419 protected void notifyNewBlock(Address block, int sizeClass) {} 420 421 /** 422 * Should the sweep reclaim the cell containing this object. Is this object 423 * live. This is only used when maintainSideBitmap is false. 424 * 425 * @param object The object to query 426 * @return {@code true} if the cell should be reclaimed 427 */ 428 protected boolean reclaimCellForObject(ObjectReference object) { 429 VM.assertions.fail("Must implement reclaimCellForObject if not maintaining side bitmap"); 430 return false; 431 } 432 433 /**************************************************************************** 434 * 435 * Metadata manipulation 436 */ 437 438 /** 439 * In the case where free lists associated with each block are 440 * preserved, get the free list for a given block. 441 * 442 * @param block The block whose free list is to be found 443 * @return The free list for this block 444 */ 445 @Inline 446 protected final Address getFreeList(Address block) { 447 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(preserveFreeList()); 448 return BlockAllocator.getFreeListMeta(block); 449 } 450 451 /** 452 * In the case where free lists associated with each block are 453 * preserved, set the free list for a given block. 454 * 455 * @param block The block whose free list is to be found 456 * @param cell The head of the free list (i.e. the first cell in the 457 * free list). 458 */ 459 @Inline 460 protected final void setFreeList(Address block, Address cell) { 461 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(preserveFreeList()); 462 BlockAllocator.setFreeListMeta(block, cell); 463 } 464 465 /**************************************************************************** 466 * 467 * Collection 468 */ 469 470 /** 471 * Clear all block marks for this space. This method is important when 472 * it is desirable to do partial collections, which man mean that block 473 * marks need to be explicitly cleared when necessary. 474 */ 475 protected final void clearAllBlockMarks() { 476 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!maintainSideBitmap()); 477 for (int sizeClass = 0; sizeClass < sizeClassCount(); sizeClass++) { 478 Extent blockSize = Extent.fromIntSignExtend(BlockAllocator.blockSize(blockSizeClass[sizeClass])); 479 /* Flushed blocks */ 480 Address block = flushedBlockHead.get(sizeClass); 481 while (!block.isZero()) { 482 Address next = BlockAllocator.getNext(block); 483 clearBlockMark(block, blockSize); 484 block = next; 485 } 486 /* Available blocks */ 487 block = consumedBlockHead.get(sizeClass); 488 while (!block.isZero()) { 489 Address next = BlockAllocator.getNext(block); 490 clearBlockMark(block, blockSize); 491 block = next; 492 } 493 } 494 } 495 496 /** 497 * Sweep all blocks for free objects. 498 * 499 * @param clearMarks should we clear block mark bits as we process. 500 */ 501 protected final void sweepConsumedBlocks(boolean clearMarks) { 502 for (int sizeClass = 0; sizeClass < sizeClassCount(); sizeClass++) { 503 Extent blockSize = Extent.fromIntSignExtend(BlockAllocator.blockSize(blockSizeClass[sizeClass])); 504 Address availableHead = Address.zero(); 505 /* Flushed blocks */ 506 Address block = flushedBlockHead.get(sizeClass); 507 flushedBlockHead.set(sizeClass, Address.zero()); 508 while (!block.isZero()) { 509 Address next = BlockAllocator.getNext(block); 510 availableHead = sweepBlock(block, sizeClass, blockSize, availableHead, clearMarks); 511 block = next; 512 } 513 /* Consumed blocks */ 514 block = consumedBlockHead.get(sizeClass); 515 consumedBlockHead.set(sizeClass, Address.zero()); 516 while (!block.isZero()) { 517 Address next = BlockAllocator.getNext(block); 518 availableHead = sweepBlock(block, sizeClass, blockSize, availableHead, clearMarks); 519 block = next; 520 } 521 /* Make blocks available */ 522 availableBlockHead.set(sizeClass, availableHead); 523 } 524 } 525 526 /** 527 * Sweeps a block, freeing it and adding to the list given by availableHead 528 * if it contains no free objects. 529 * 530 * @param block the block's address 531 * @param sizeClass the block's size class 532 * @param blockSize the block's size, in bytes 533 * @param availableHead the head of the blocks that still need to be swept 534 * @param clearMarks should we clear block mark bits as we process. 535 * @return updated head of the blocks that still need to be swept 536 */ 537 protected final Address sweepBlock(Address block, int sizeClass, Extent blockSize, Address availableHead, boolean clearMarks) { 538 boolean liveBlock = containsLiveCell(block, blockSize, clearMarks); 539 if (!liveBlock) { 540 BlockAllocator.setNext(block, Address.zero()); 541 BlockAllocator.free(this, block); 542 } else { 543 BlockAllocator.setNext(block, availableHead); 544 availableHead = block; 545 if (!LAZY_SWEEP) { 546 setFreeList(block, makeFreeList(block, sizeClass)); 547 } 548 } 549 return availableHead; 550 } 551 552 /** 553 * Eagerly consume all remaining blocks. 554 */ 555 protected final void consumeBlocks() { 556 for (int sizeClass = 0; sizeClass < sizeClassCount(); sizeClass++) { 557 while (!availableBlockHead.get(sizeClass).isZero()) { 558 Address block = availableBlockHead.get(sizeClass); 559 availableBlockHead.set(sizeClass, BlockAllocator.getNext(block)); 560 advanceToBlock(block, sizeClass); 561 BlockAllocator.setNext(block, consumedBlockHead.get(sizeClass)); 562 consumedBlockHead.set(sizeClass, block); 563 } 564 } 565 } 566 567 /** 568 * Flush all the allocation blocks to the consumed list. 569 */ 570 protected final void flushAvailableBlocks() { 571 for (int sizeClass = 0; sizeClass < sizeClassCount(); sizeClass++) { 572 flushedBlockHead.set(sizeClass, availableBlockHead.get(sizeClass)); 573 availableBlockHead.set(sizeClass, Address.zero()); 574 } 575 } 576 577 /** 578 * Does this block contain any live cells. 579 * 580 * @param block The block 581 * @param blockSize The size of the block 582 * @param clearMarks should we clear block mark bits as we process. 583 * @return {@code true} if any cells in the block are live 584 */ 585 @Inline 586 protected boolean containsLiveCell(Address block, Extent blockSize, boolean clearMarks) { 587 if (maintainSideBitmap()) { 588 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(alignToLiveStride(block).EQ(block)); 589 Address cursor = getLiveWordAddress(block); 590 Address sentinel = getLiveWordAddress(block.plus(blockSize.minus(1))); 591 while (cursor.LE(sentinel)) { 592 Word live = cursor.loadWord(); 593 if (!live.isZero()) { 594 return true; 595 } 596 cursor = cursor.plus(BYTES_IN_WORD); 597 } 598 return false; 599 } else { 600 boolean live = false; 601 Address cursor = block; 602 while (cursor.LT(block.plus(blockSize))) { 603 live |= BlockAllocator.checkBlockMeta(cursor); 604 if (clearMarks) 605 BlockAllocator.clearBlockMeta(cursor); 606 cursor = cursor.plus(1 << BlockAllocator.LOG_MIN_BLOCK); 607 } 608 return live; 609 } 610 } 611 612 613 /** 614 * Clear block marks for a block 615 * 616 * @param block The block 617 * @param blockSize The size of the block 618 */ 619 @Inline 620 protected void clearBlockMark(Address block, Extent blockSize) { 621 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!maintainSideBitmap()); 622 Address cursor = block; 623 while (cursor.LT(block.plus(blockSize))) { 624 BlockAllocator.clearBlockMeta(cursor); 625 cursor = cursor.plus(1 << BlockAllocator.LOG_MIN_BLOCK); 626 } 627 } 628 629 /** 630 * In the cell containing this object live? 631 * 632 * @param object The object 633 * @return {@code true} if the cell is live 634 */ 635 @Inline 636 protected boolean isCellLive(ObjectReference object) { 637 /* Must override if not using the side bitmap */ 638 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(maintainSideBitmap()); 639 return liveBitSet(object); 640 } 641 642 /** 643 * Use the live bits for a block to infer free cells and thus 644 * construct a free list for the block. 645 * 646 * @param block The block to be processed 647 * @param sizeClass The size class for the block 648 * @return The head of the new free list 649 */ 650 @Inline 651 protected final Address makeFreeList(Address block, int sizeClass) { 652 Extent blockSize = Extent.fromIntSignExtend(BlockAllocator.blockSize(blockSizeClass[sizeClass])); 653 Address cursor = block.plus(blockHeaderSize[sizeClass]); 654 Address lastFree = Address.zero(); 655 Address firstFree = Address.zero(); 656 Address end = block.plus(blockSize); 657 Extent cellExtent = Extent.fromIntSignExtend(cellSize[sizeClass]); 658 while (cursor.LT(end)) { 659 ObjectReference current = VM.objectModel.getObjectFromStartAddress(cursor); 660 boolean free = true; 661 if (!current.isNull()) { 662 free = !isCellLive(current); 663 } 664 if (free) { 665 if (firstFree.isZero()) { 666 firstFree = cursor; 667 } else { 668 lastFree.store(cursor); 669 } 670 Memory.zeroSmall(cursor, cellExtent); 671 lastFree = cursor; 672 } 673 cursor = cursor.plus(cellExtent); 674 } 675 return firstFree; 676 } 677 678 /** 679 * Sweeps all blocks for free objects. 680 * 681 * @param sweeper the sweeper to use 682 */ 683 public void sweepCells(Sweeper sweeper) { 684 for (int sizeClass = 0; sizeClass < sizeClassCount(); sizeClass++) { 685 Address availableHead = Address.zero(); 686 /* Flushed blocks */ 687 Address block = flushedBlockHead.get(sizeClass); 688 flushedBlockHead.set(sizeClass, Address.zero()); 689 while (!block.isZero()) { 690 Address next = BlockAllocator.getNext(block); 691 availableHead = sweepCells(sweeper, block, sizeClass, availableHead); 692 block = next; 693 } 694 /* Consumed blocks */ 695 block = consumedBlockHead.get(sizeClass); 696 consumedBlockHead.set(sizeClass, Address.zero()); 697 while (!block.isZero()) { 698 Address next = BlockAllocator.getNext(block); 699 availableHead = sweepCells(sweeper, block, sizeClass, availableHead); 700 block = next; 701 } 702 /* Make blocks available */ 703 availableBlockHead.set(sizeClass, availableHead); 704 } 705 } 706 707 /** 708 * Sweeps a block, freeing it and adding to the list given by availableHead 709 * if it contains no free objects. 710 * 711 * @param sweeper the sweeper to use 712 * @param block the block's address 713 * @param sizeClass the block's size class 714 * @param availableHead the head of the blocks that still need to be swept 715 * @return new head of the blocks that still need to be swept 716 */ 717 private Address sweepCells(Sweeper sweeper, Address block, int sizeClass, Address availableHead) { 718 boolean liveBlock = sweepCells(sweeper, block, sizeClass); 719 if (!liveBlock) { 720 BlockAllocator.setNext(block, Address.zero()); 721 BlockAllocator.free(this, block); 722 } else { 723 BlockAllocator.setNext(block, availableHead); 724 availableHead = block; 725 } 726 return availableHead; 727 } 728 729 /** 730 * Sweeps a block, freeing it and making it available if any live cells were found. 731 * if it contains no free objects.<p> 732 * 733 * This is designed to be called in parallel by multiple collector threads. 734 * 735 * @param sweeper the sweeper to use 736 */ 737 public void parallelSweepCells(Sweeper sweeper) { 738 for (int sizeClass = 0; sizeClass < sizeClassCount(); sizeClass++) { 739 Address block; 740 while (!(block = getSweepBlock(sizeClass)).isZero()) { 741 boolean liveBlock = sweepCells(sweeper, block, sizeClass); 742 if (!liveBlock) { 743 BlockAllocator.setNext(block, Address.zero()); 744 BlockAllocator.free(this, block); 745 } else { 746 lock.acquire(); 747 BlockAllocator.setNext(block, availableBlockHead.get(sizeClass)); 748 availableBlockHead.set(sizeClass, block); 749 lock.release(); 750 } 751 } 752 } 753 } 754 755 /** 756 * Get a block for a parallel sweep. 757 * 758 * @param sizeClass The size class of the block to sweep. 759 * @return The block or zero if no blocks remain to be swept. 760 */ 761 private Address getSweepBlock(int sizeClass) { 762 lock.acquire(); 763 Address block; 764 765 /* Flushed blocks */ 766 block = flushedBlockHead.get(sizeClass); 767 if (!block.isZero()) { 768 flushedBlockHead.set(sizeClass, BlockAllocator.getNext(block)); 769 lock.release(); 770 BlockAllocator.setNext(block, Address.zero()); 771 return block; 772 } 773 774 /* Consumed blocks */ 775 block = consumedBlockHead.get(sizeClass); 776 if (!block.isZero()) { 777 consumedBlockHead.set(sizeClass, BlockAllocator.getNext(block)); 778 lock.release(); 779 BlockAllocator.setNext(block, Address.zero()); 780 return block; 781 } 782 783 /* All swept! */ 784 lock.release(); 785 return Address.zero(); 786 } 787 788 @Inline 789 public boolean sweepCells(Sweeper sweeper, Address block, int sizeClass) { 790 Extent blockSize = Extent.fromIntSignExtend(BlockAllocator.blockSize(blockSizeClass[sizeClass])); 791 Address cursor = block.plus(blockHeaderSize[sizeClass]); 792 Address end = block.plus(blockSize); 793 Extent cellExtent = Extent.fromIntSignExtend(cellSize[sizeClass]); 794 boolean containsLive = false; 795 while (cursor.LT(end)) { 796 ObjectReference current = VM.objectModel.getObjectFromStartAddress(cursor); 797 boolean free = true; 798 if (!current.isNull()) { 799 free = !liveBitSet(current); 800 if (!free) { 801 free = sweeper.sweepCell(current); 802 if (free) unsyncClearLiveBit(current); 803 } 804 } 805 if (!free) { 806 containsLive = true; 807 } 808 cursor = cursor.plus(cellExtent); 809 } 810 return containsLive; 811 } 812 813 /** 814 * A callback used to perform sweeping of a free list space. 815 */ 816 @Uninterruptible 817 public abstract static class Sweeper { 818 public abstract boolean sweepCell(ObjectReference object); 819 } 820 821 /**************************************************************************** 822 * 823 * Live bit manipulation 824 */ 825 826 /** 827 * Atomically set the live bit for a given object 828 * 829 * @param object The object whose live bit is to be set. 830 * @return {@code true} if the bit was changed to true. 831 */ 832 @Inline 833 public static boolean testAndSetLiveBit(ObjectReference object) { 834 return updateLiveBit(VM.objectModel.objectStartRef(object), true, true); 835 } 836 837 /** 838 * Set the live bit for the block containing the given object 839 * 840 * @param object The object whose blocks liveness is to be set. 841 */ 842 @Inline 843 protected static void markBlock(ObjectReference object) { 844 BlockAllocator.markBlockMeta(object); 845 } 846 847 /** 848 * Set the live bit for the given block. 849 * 850 * @param block The block whose liveness is to be set. 851 */ 852 @Inline 853 protected static void markBlock(Address block) { 854 BlockAllocator.markBlockMeta(block); 855 } 856 857 /** 858 * Set the live bit for a given object, without using 859 * synchronization primitives---must only be used when contention 860 * for live bit is strictly not possible 861 * 862 * @param object The object whose live bit is to be set. 863 * @return whether the live bit was set before the update 864 */ 865 @Inline 866 public static boolean unsyncSetLiveBit(ObjectReference object) { 867 return updateLiveBit(VM.objectModel.refToAddress(object), true, false); 868 } 869 870 /** 871 * Set the live bit for a given address 872 * 873 * @param address The address whose live bit is to be set. 874 * @param set {@code true} if the bit is to be set, as opposed to cleared 875 * @param atomic {@code true} if we want to perform this operation atomically 876 * @return whether the live bit was set before the update 877 */ 878 @Inline 879 private static boolean updateLiveBit(Address address, boolean set, boolean atomic) { 880 Word oldValue, newValue; 881 Address liveWord = getLiveWordAddress(address); 882 Word mask = getMask(address, true); 883 if (atomic) { 884 do { 885 oldValue = liveWord.prepareWord(); 886 newValue = (set) ? oldValue.or(mask) : oldValue.and(mask.not()); 887 } while (!liveWord.attempt(oldValue, newValue)); 888 } else { 889 oldValue = liveWord.loadWord(); 890 liveWord.store(set ? oldValue.or(mask) : oldValue.and(mask.not())); 891 } 892 return oldValue.and(mask).NE(mask); 893 } 894 895 @Inline 896 protected static boolean liveBitSet(ObjectReference object) { 897 return liveBitSet(VM.objectModel.refToAddress(object)); 898 } 899 900 @Inline 901 protected static boolean liveBitSet(Address address) { 902 Address liveWord = getLiveWordAddress(address); 903 Word mask = getMask(address, true); 904 Word value = liveWord.loadWord(); 905 return value.and(mask).EQ(mask); 906 } 907 908 /** 909 * Clear the live bit for a given object 910 * 911 * @param object The object whose live bit is to be cleared. 912 */ 913 @Inline 914 protected static void clearLiveBit(ObjectReference object) { 915 clearLiveBit(VM.objectModel.refToAddress(object)); 916 } 917 918 /** 919 * Clear the live bit for a given address 920 * 921 * @param address The address whose live bit is to be cleared. 922 */ 923 @Inline 924 protected static void clearLiveBit(Address address) { 925 updateLiveBit(address, false, true); 926 } 927 928 /** 929 * Clear the live bit for a given object 930 * 931 * @param object The object whose live bit is to be cleared. 932 */ 933 @Inline 934 protected static void unsyncClearLiveBit(ObjectReference object) { 935 unsyncClearLiveBit(VM.objectModel.refToAddress(object)); 936 } 937 938 /** 939 * Clear the live bit for a given address 940 * 941 * @param address The address whose live bit is to be cleared. 942 */ 943 @Inline 944 protected static void unsyncClearLiveBit(Address address) { 945 updateLiveBit(address, false, false); 946 } 947 948 /** 949 * Clear all live bits for a block. 950 * 951 * @param block the block's address 952 * @param sizeClass the block's size class 953 */ 954 protected void clearLiveBits(Address block, int sizeClass) { 955 int blockSize = BlockAllocator.blockSize(blockSizeClass[sizeClass]); 956 Address cursor = getLiveWordAddress(block); 957 Address sentinel = getLiveWordAddress(block.plus(blockSize - 1)); 958 while (cursor.LE(sentinel)) { 959 cursor.store(Word.zero()); 960 cursor = cursor.plus(BYTES_IN_WORD); 961 } 962 } 963 964 protected void zeroLiveBits() { 965 Extent bytes = Extent.fromIntSignExtend(EmbeddedMetaData.BYTES_IN_REGION >> LOG_LIVE_COVERAGE); 966 if (contiguous) { 967 Address end = ((FreeListPageResource)pr).getHighWater(); 968 Address cursor = start; 969 while (cursor.LT(end)) { 970 Address metadata = EmbeddedMetaData.getMetaDataBase(cursor).plus(META_DATA_OFFSET); 971 VM.memory.zero(false, metadata, bytes); 972 cursor = cursor.plus(EmbeddedMetaData.BYTES_IN_REGION); 973 } 974 } else { 975 for (Address cursor = headDiscontiguousRegion; !cursor.isZero(); cursor = Map.getNextContiguousRegion(cursor)) { 976 Address metadata = EmbeddedMetaData.getMetaDataBase(cursor).plus(META_DATA_OFFSET); 977 VM.memory.zero(false, metadata, bytes); 978 } 979 } 980 } 981 982 /** 983 * Align an address so that it corresponds to a live word boundary. 984 * In other words, if the live bit for the given address is not the 985 * zeroth bit of a live word, round the address down such that it 986 * does. 987 * 988 * @param address The address to be aligned to a live word 989 * @return The given address, aligned down so that it corresponds to 990 * an address on a live word boundary. 991 */ 992 private static Address alignToLiveStride(Address address) { 993 return address.toWord().and(LIVE_WORD_STRIDE_MASK).toAddress(); 994 } 995 996 /** 997 * Given an address, produce a bit mask for the live table 998 * 999 * @param address The address whose live bit mask is to be established 1000 * @param set True if we want the mask for <i>setting</i> the bit, 1001 * false if we want the mask for <i>clearing</i> the bit. 1002 * @return The appropriate bit mask for object for the live table for. 1003 */ 1004 @Inline 1005 private static Word getMask(Address address, boolean set) { 1006 int shift = address.toWord().rshl(OBJECT_LIVE_SHIFT).and(WORD_SHIFT_MASK).toInt(); 1007 Word rtn = Word.one().lsh(shift); 1008 return (set) ? rtn : rtn.not(); 1009 } 1010 1011 /** 1012 * Given an address, return the address of the live word for 1013 * that address. 1014 * 1015 * @param address The address whose live word address is to be returned 1016 * @return The address of the live word for this object 1017 */ 1018 @Inline 1019 private static Address getLiveWordAddress(Address address) { 1020 Address rtn = EmbeddedMetaData.getMetaDataBase(address); 1021 return rtn.plus(META_DATA_OFFSET).plus(EmbeddedMetaData.getMetaDataOffset(address, LOG_LIVE_COVERAGE, LOG_BYTES_IN_WORD)); 1022 } 1023}