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 static org.mmtk.utility.Constants.*; 016 017import org.mmtk.policy.Space; 018import org.mmtk.utility.*; 019 020import org.mmtk.vm.VM; 021 022import org.vmmagic.pragma.*; 023import org.vmmagic.unboxed.*; 024 025/** 026 * This class implements "block" data structures of various sizes.<p> 027 * 028 * Blocks are a non-shared (thread-local) coarse-grained unit of 029 * storage. Blocks are available in power-of-two sizes.<p> 030 * 031 * Virtual memory space is taken from a VM resource, and pages 032 * consumed by blocks are accounted for by a memory resource. 033 */ 034@Uninterruptible 035public final class BlockAllocator { 036 /**************************************************************************** 037 * 038 * Class variables 039 */ 040 041 /** 042 * 043 */ 044 045 // block freelist 046 public static final int LOG_MIN_BLOCK = 12; // 4K bytes 047 public static final int LOG_MAX_BLOCK = 15; // 32K bytes 048 public static final byte MAX_BLOCK_SIZE_CLASS = LOG_MAX_BLOCK - LOG_MIN_BLOCK; 049 public static final int BLOCK_SIZE_CLASSES = MAX_BLOCK_SIZE_CLASS + 1; 050 051 // metadata 052 private static final Offset NEXT_OFFSET = Offset.zero(); 053 private static final Offset BMD_OFFSET = NEXT_OFFSET.plus(BYTES_IN_ADDRESS); 054 private static final Offset CSC_OFFSET = BMD_OFFSET.plus(1); 055 private static final Offset IU_OFFSET = CSC_OFFSET.plus(1); 056 private static final Offset FL_META_OFFSET = IU_OFFSET.plus(BYTES_IN_SHORT); 057 private static final byte BLOCK_SC_MASK = 0xf; // lower 4 bits 058 private static final int BLOCK_PAGE_OFFSET_SHIFT = 4; // higher 4 bits 059 private static final int MAX_BLOCK_PAGE_OFFSET = (1 << 4) - 1; // 4 bits 060 private static final int LOG_BYTES_IN_BLOCK_META = LOG_BYTES_IN_ADDRESS + 2; 061 private static final int LOG_BYTE_COVERAGE = LOG_MIN_BLOCK - LOG_BYTES_IN_BLOCK_META; 062 063 public static final int META_DATA_BYTES_PER_REGION = 1 << (EmbeddedMetaData.LOG_BYTES_IN_REGION - LOG_BYTE_COVERAGE); 064 public static final Extent META_DATA_EXTENT = Extent.fromIntSignExtend(META_DATA_BYTES_PER_REGION); 065 066 /**************************************************************************** 067 * 068 * Allocation & freeing 069 */ 070 071 /** 072 * Allocate a block, returning the address of the first usable byte 073 * in the block. 074 * 075 * @param space the space to request the memory from 076 * @param blockSizeClass The size class for the block to be allocated. 077 * @return The address of the first usable byte in the block, or 078 * zero on failure. 079 */ 080 public static Address alloc(Space space, int blockSizeClass) { 081 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((blockSizeClass >= 0) && (blockSizeClass <= MAX_BLOCK_SIZE_CLASS)); 082 int pages = pagesForSizeClass(blockSizeClass); 083 Address result = space.acquire(pages); 084 if (!result.isZero()) { 085 setBlkSizeMetaData(result, (byte) blockSizeClass); 086 } 087 return result; 088 } 089 090 /** 091 * Free a block. If the block is a sub-page block and the page is 092 * not completely free, then the block is added to the free list. 093 * Otherwise the block is returned to the virtual memory resource. 094 * 095 * @param space the space that contains the block 096 * @param block The address of the block to be freed 097 */ 098 public static void free(Space space, Address block) { 099 space.release(block); 100 } 101 102 /** 103 * Return the size in bytes of a block of a given size class 104 * 105 * @param blockSizeClass The size class in question 106 * @return The size in bytes of a block of this size class 107 */ 108 @Inline 109 public static int blockSize(int blockSizeClass) { 110 return 1 << (LOG_MIN_BLOCK + blockSizeClass); 111 } 112 113 /** 114 * Return the number of pages required when allocating space for 115 * this size class. 116 * 117 * @param blockSizeClass The size class in question 118 * @return The number of pages required when allocating a block (or 119 * blocks) of this size class. 120 */ 121 @Inline 122 private static int pagesForSizeClass(int blockSizeClass) { 123 return 1 << (LOG_MIN_BLOCK + blockSizeClass - LOG_BYTES_IN_PAGE); 124 } 125 126 /**************************************************************************** 127 * 128 * Block meta-data manipulation 129 */ 130 131 /** 132 * Set the <i>block size class</i> meta data field for a given 133 * address (all blocks on a given page are homogeneous with respect 134 * to block size class). 135 * 136 * @param block The address of interest 137 * @param sc The value to which this field is to be set 138 */ 139 @Inline 140 private static void setBlkSizeMetaData(Address block, byte sc) { 141 if (VM.VERIFY_ASSERTIONS) { 142 VM.assertions._assert(block.EQ(Conversions.pageAlign(block))); 143 VM.assertions._assert(pagesForSizeClass(sc) - 1 <= MAX_BLOCK_PAGE_OFFSET); 144 } 145 Address address = block; 146 for (int i = 0; i < pagesForSizeClass(sc); i++) { 147 byte value = (byte) ((i << BLOCK_PAGE_OFFSET_SHIFT) | sc); 148 getMetaAddress(address).store(value, BMD_OFFSET); 149 if (VM.VERIFY_ASSERTIONS) { 150 VM.assertions._assert(getBlkStart(address).EQ(block)); 151 VM.assertions._assert(getBlkSizeClass(address) == sc); 152 } 153 address = address.plus(1 << VM.LOG_BYTES_IN_PAGE); 154 } 155 } 156 157 /** 158 * Get the <i>block size class</i> meta data field for a given page 159 * (all blocks on a given page are homogeneous with respect to block 160 * size class). 161 * 162 * @param address The address of interest 163 * @return The size class field for the block containing the given address 164 */ 165 @Inline 166 private static byte getBlkSizeClass(Address address) { 167 address = Conversions.pageAlign(address); 168 byte rtn = (byte) (getMetaAddress(address).loadByte(BMD_OFFSET) & BLOCK_SC_MASK); 169 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(rtn >= 0 && rtn <= MAX_BLOCK_SIZE_CLASS); 170 return rtn; 171 } 172 173 /** 174 * Get the <i>address of the start of a block size class</i> a given page 175 * within the block. 176 * 177 * @param address The address of interest 178 * @return The address of the block containing the address 179 */ 180 @Inline 181 public static Address getBlkStart(Address address) { 182 address = Conversions.pageAlign(address); 183 byte offset = (byte) (getMetaAddress(address).loadByte(BMD_OFFSET) >>> BLOCK_PAGE_OFFSET_SHIFT); 184 return address.minus(offset << LOG_BYTES_IN_PAGE); 185 } 186 187 /** 188 * Set the <i>client size class</i> meta data field for a given 189 * address (all blocks on a given page are homogeneous with respect 190 * to block size class). 191 * 192 * @param block The address of interest 193 * @param blocksc the block's size class 194 * @param sc The value to which this field is to be set 195 */ 196 @Inline 197 public static void setAllClientSizeClass(Address block, int blocksc, byte sc) { 198 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(block.EQ(Conversions.pageAlign(block))); 199 Address address = block; 200 for (int i = 0; i < pagesForSizeClass(blocksc); i++) { 201 getMetaAddress(address).store(sc, CSC_OFFSET); 202 address = address.plus(1 << VM.LOG_BYTES_IN_PAGE); 203 } 204 } 205 206 /** 207 * Get the <i>client size class</i> meta data field for a given page 208 * (all blocks on a given page are homogeneous with respect to block 209 * size class). 210 * 211 * @param address The address of interest 212 * @return The size class field for the block containing the given address 213 */ 214 @Inline 215 public static byte getClientSizeClass(Address address) { 216 address = Conversions.pageAlign(address); 217 byte rtn = getMetaAddress(address).loadByte(CSC_OFFSET); 218 return rtn; 219 } 220 221 /** 222 * Set the free list meta data field for a given address (this is 223 * per-block meta data that is stored along with the block metadata 224 * but not used by the block allocator). 225 * 226 * @param address The address of interest 227 * @param value The value to which this field is to be set 228 */ 229 @Inline 230 public static void setFreeListMeta(Address address, Address value) { 231 getMetaAddress(address).plus(FL_META_OFFSET).store(value); 232 } 233 234 /** 235 * Get the free list meta data field for a given address (this is 236 * per-block meta data that is stored along with the block metadata 237 * but not used by the block allocator). 238 * 239 * @param address The address of interest 240 * @return The free list meta data field for the block containing 241 * the given address 242 */ 243 @Inline 244 public static Address getFreeListMeta(Address address) { 245 return getMetaAddress(address).plus(FL_META_OFFSET).loadAddress(); 246 } 247 248 /** 249 * Set the <i>prev</i> meta data field for a given address 250 * 251 * @param address The address of interest 252 * @param prev The value to which this field is to be set 253 */ 254 @Inline 255 public static void setNext(Address address, Address prev) { 256 getMetaAddress(address, NEXT_OFFSET).store(prev); 257 } 258 259 /** 260 * Get the <i>prev</i> meta data field for a given address 261 * 262 * @param address The address of interest 263 * @return The prev field for the block containing the given address 264 */ 265 @Inline 266 public static Address getNext(Address address) { 267 return getMetaAddress(address, NEXT_OFFSET).loadAddress(); 268 } 269 270 /** 271 * Get the address of some metadata given the address for which the 272 * metadata is required and the offset into the metadata that is of 273 * interest. 274 * 275 * @param address The address for which the metadata is required 276 * @return The address of the specified meta data 277 */ 278 @Inline 279 private static Address getMetaAddress(Address address) { 280 return getMetaAddress(address, Offset.zero()); 281 } 282 283 /** 284 * Get the address of some metadata given the address for which the 285 * metadata is required and the offset into the metadata that is of 286 * interest. 287 * 288 * @param address The address for which the metadata is required 289 * @param offset The offset (in bytes) into the metadata block (eg 290 * for the prev pointer, or next pointer) 291 * @return The address of the specified meta data 292 */ 293 @Inline 294 private static Address getMetaAddress(Address address, Offset offset) { 295 return EmbeddedMetaData.getMetaDataBase(address).plus( 296 EmbeddedMetaData.getMetaDataOffset(address, LOG_BYTE_COVERAGE, LOG_BYTES_IN_BLOCK_META)).plus(offset); 297 } 298 299 /**************************************************************************** 300 * 301 * Block marking 302 */ 303 304 /** 305 * Marks the metadata for this block. 306 * 307 * @param ref the block's reference 308 */ 309 @Inline 310 public static void markBlockMeta(ObjectReference ref) { 311 getMetaAddress(VM.objectModel.refToAddress(ref)).plus(FL_META_OFFSET).store(Word.one()); 312 } 313 314 /** 315 * Mark the metadata for this block. 316 * 317 * @param block The block address 318 */ 319 @Inline 320 public static void markBlockMeta(Address block) { 321 getMetaAddress(block).plus(FL_META_OFFSET).store(Word.one()); 322 } 323 324 /** 325 * Return true if the metadata for this block was set. 326 * 327 * @param block The block address 328 * @return value of the meta data. 329 */ 330 @Inline 331 public static boolean checkBlockMeta(Address block) { 332 return getMetaAddress(block).plus(FL_META_OFFSET).loadWord().EQ(Word.one()); 333 } 334 335 /** 336 * Clear the metadata for this block 337 * 338 * @param block The block address 339 */ 340 @Inline 341 public static void clearBlockMeta(Address block) { 342 getMetaAddress(block).plus(FL_META_OFFSET).store(Word.zero()); 343 } 344}