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.utility.alloc;
014
015import org.mmtk.policy.SegregatedFreeListSpace;
016
017import org.mmtk.vm.VM;
018
019import org.vmmagic.pragma.*;
020import org.vmmagic.unboxed.*;
021
022/**
023 * This abstract class implements a simple segregated free list.<p>
024 *
025 * See: Wilson, Johnstone, Neely and Boles "Dynamic Storage
026 * Allocation: A Survey and Critical Review", IWMM 1995, for an
027 * overview of free list allocation and the various implementation
028 * strategies, including segregated free lists.<p>
029 *
030 * We maintain a number of size classes, each size class having a free
031 * list of available objects of that size (the list may be empty).  We
032 * call the storage elements "cells".  Cells reside within chunks of
033 * memory called "blocks".  All cells in a given block are of the same
034 * size (i.e. blocks are homogeneous with respect to size class).
035 * Each block maintains its own free list (free cells within that
036 * block).  For each size class a list of blocks is maintained, one of
037 * which will serve the role of the current free list.  When the free
038 * list on the current block is exhausted, the next block for that
039 * size class becomes the current block and its free list is used.  If
040 * there are no more blocks the a new block is allocated.
041 */
042@Uninterruptible
043public abstract class SegregatedFreeListLocal<S extends SegregatedFreeListSpace> extends SegregatedFreeList<S> {
044
045  /****************************************************************************
046   *
047   * Class variables
048   */
049
050  /****************************************************************************
051   *
052   * Instance variables
053   */
054
055  /**
056   *
057   */
058  protected final AddressArray currentBlock;
059
060  /****************************************************************************
061   *
062   * Initialization
063   */
064
065  /**
066   * Constructor
067   *
068   * @param space The space with which this allocator will be associated
069   */
070  public SegregatedFreeListLocal(S space) {
071    super(space);
072    this.currentBlock = AddressArray.create(SegregatedFreeListSpace.sizeClassCount());
073  }
074
075  /****************************************************************************
076   *
077   * Allocation
078   */
079
080  /**
081   * Allocate <code>bytes</code> contiguous bytes of non-zeroed
082   * memory.  First check if the fast path works.  This is needed
083   * since this method may be called in the context when the fast
084   * version was NOT just called.  If this fails, it will try finding
085   * another block with a non-empty free list, or allocating a new
086   * block.<p>
087   *
088   * This code should be relatively infrequently executed, so it is
089   * forced out of line to reduce pressure on the compilation of the
090   * core alloc routine.<p>
091   *
092   * Precondition: None<p>
093   *
094   * Postconditions: A new cell has been allocated (not zeroed), and
095   * the block containing the cell has been placed on the appropriate
096   * free list data structures.  The free list itself is not updated
097   * (the caller must do so).<p>
098   *
099   * @param bytes The size of the object to occupy this space, in bytes.
100   * @param offset The alignment offset.
101   * @param align The requested alignment.
102   * @return The address of the first word or zero on failure.
103   */
104  @Override
105  @NoInline
106  public final Address allocSlowOnce(int bytes, int align, int offset) {
107    // Did a collection occur and provide a free cell?
108    bytes = getMaximumAlignedSize(bytes, align);
109    int sizeClass = space.getSizeClass(bytes);
110    Address cell = freeList.get(sizeClass);
111
112    if (cell.isZero()) {
113      Address block = currentBlock.get(sizeClass);
114      if (!block.isZero()) {
115        // Return the block if we currently own one
116        space.returnConsumedBlock(block, sizeClass);
117        currentBlock.set(sizeClass, Address.zero());
118      }
119
120      // Get a new block for allocation, if returned, it is guaranteed to have a free cell
121      block = space.getAllocationBlock(sizeClass, freeList);
122
123      if (!block.isZero()) {
124        // We have a new current block and free list.
125        currentBlock.set(sizeClass, block);
126        cell = freeList.get(sizeClass);
127        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!cell.isZero());
128      } else {
129        // Allocation Failure
130        return Address.zero();
131      }
132    }
133
134    freeList.set(sizeClass, cell.loadAddress());
135    /* Clear the free list link */
136    cell.store(Address.zero());
137    return alignAllocation(cell, align, offset);
138  }
139
140  /****************************************************************************
141   *
142   * Preserving (saving & restoring) free lists
143   */
144
145  /**
146   * Zero all of the current free list pointers, and refresh the
147   * <code>currentBlock</code> values, so instead of the free list
148   * pointing to free cells, it points to the block containing the
149   * free cells.  Then the free lists for each cell can be
150   * reestablished during GC.  If the free lists are being preserved
151   * on a per-block basis (eager mark-sweep and reference counting),
152   * then free lists are remembered for each block.
153   */
154  public final void flush() {
155    for (int sizeClass = 0; sizeClass < SegregatedFreeListSpace.sizeClassCount(); sizeClass++) {
156      Address block = currentBlock.get(sizeClass);
157      if (!block.isZero()) {
158        Address cell = freeList.get(sizeClass);
159        space.returnBlock(block, sizeClass, cell);
160        currentBlock.set(sizeClass, Address.zero());
161        freeList.set(sizeClass, Address.zero());
162      }
163    }
164  }
165}