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