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}