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}