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; 014 015import org.mmtk.plan.Plan; 016import org.mmtk.vm.VM; 017 018import org.vmmagic.pragma.*; 019 020/** 021 * This is a very simple, generic malloc-free allocator. It works 022 * abstractly, in "units", which the user may associate with some 023 * other allocatable resource (e.g. heap blocks). The user issues 024 * requests for N units and the allocator returns the index of the 025 * first of a contiguous set of N units or fails, returning -1. The 026 * user frees the block of N units by calling <code>free()</code> with 027 * the index of the first unit as the argument.<p> 028 * 029 * Properties/Constraints:<ul> 030 * <li> The allocator consumes one word per allocatable unit (plus 031 * a fixed overhead of about 128 words).</li> 032 * <li> The allocator can only deal with MAX_UNITS units (see below for 033 * the value).</li> 034 * </ul> 035 * 036 * The basic data structure used by the algorithm is a large table, 037 * with one word per allocatable unit. Each word is used in a 038 * number of different ways, some combination of "undefined" (32), 039 * "free/used" (1), "multi/single" (1), "prev" (15), "next" (15) & 040 * "size" (15) where field sizes in bits are in parenthesis. 041 * <pre> 042 * +-+-+-----------+-----------+ 043 * |f|m| prev | next/size | 044 * +-+-+-----------+-----------+ 045 * 046 * - single free unit: "free", "single", "prev", "next" 047 * - single used unit: "used", "single" 048 * - contiguous free units 049 * . first unit: "free", "multi", "prev", "next" 050 * . second unit: "free", "multi", "size" 051 * . last unit: "free", "multi", "size" 052 * - contiguous used units 053 * . first unit: "used", "multi", "prev", "next" 054 * . second unit: "used", "multi", "size" 055 * . last unit: "used", "multi", "size" 056 * - any other unit: undefined 057 * 058 * +-+-+-----------+-----------+ 059 * top sentinel |0|0| tail | head | [-1] 060 * +-+-+-----------+-----------+ 061 * .... 062 * /-------- +-+-+-----------+-----------+ 063 * | |1|1| prev | next | [j] 064 * | +-+-+-----------+-----------+ 065 * | |1|1| | size | [j+1] 066 * free multi +-+-+-----------+-----------+ 067 * unit block | ... | ... 068 * | +-+-+-----------+-----------+ 069 * | |1|1| | size | 070 * >-------- +-+-+-----------+-----------+ 071 * single free unit |1|0| prev | next | 072 * >-------- +-+-+-----------+-----------+ 073 * single used unit |0|0| | 074 * >-------- +-+-+-----------------------+ 075 * | |0|1| | 076 * | +-+-+-----------+-----------+ 077 * | |0|1| | size | 078 * used multi +-+-+-----------+-----------+ 079 * unit block | ... | 080 * | +-+-+-----------+-----------+ 081 * | |0|1| | size | 082 * \-------- +-+-+-----------+-----------+ 083 * .... 084 * +-+-+-----------------------+ 085 * bottom sentinel |0|0| | [N] 086 * +-+-+-----------------------+ 087 * </pre> 088 * The sentinels serve as guards against out of range coalescing 089 * because they both appear as "used" blocks and so will never 090 * coalesce. The top sentinel also serves as the head and tail of 091 * the doubly linked list of free blocks. 092 */ 093@Uninterruptible 094public final class GenericFreeList extends BaseGenericFreeList { 095 096 /**************************************************************************** 097 * 098 * Public instance methods 099 */ 100 101 /** 102 * Constructor 103 * 104 * @param units The number of allocatable units for this free list 105 */ 106 public GenericFreeList(int units) { 107 this(units, units); 108 } 109 110 /** 111 * Constructor 112 * 113 * @param units The number of allocatable units for this free list 114 * @param grain Units are allocated such that they will never cross this granularity boundary 115 */ 116 public GenericFreeList(int units, int grain) { 117 this(units, grain, 1); 118 } 119 120 /** 121 * Constructor 122 * 123 * @param units The number of allocatable units for this free list 124 * @param grain Units are allocated such that they will never cross this granularity boundary 125 * @param heads The number of free lists which will share this instance 126 */ 127 public GenericFreeList(int units, int grain, int heads) { 128 this.parent = null; 129 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(units <= MAX_UNITS && heads <= MAX_HEADS); 130 this.heads = heads; 131 head = -1; 132 133 // allocate the data structure, including space for top & bottom sentinels 134 table = new int[(units + 1 + heads) << 1]; 135 initializeHeap(units, grain); 136 } 137 138 /** 139 * Resize the free list for a parent free list. 140 * This must not be called dynamically (ie not after bootstrap). 141 * 142 * @param units The number of allocatable units for this free list 143 * @param grain Units are allocated such that they will never cross this granularity boundary 144 */ 145 @Interruptible 146 public void resizeFreeList(int units, int grain) { 147 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(parent == null && !Plan.isInitialized()); 148 table = new int[(units + 1 + heads) << 1]; 149 initializeHeap(units, grain); 150 } 151 152 /** 153 * Resize the free list for a child free list. 154 * This must not be called dynamically (ie not after bootstrap). 155 */ 156 @Interruptible 157 public void resizeFreeList() { 158 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(parent != null && !Plan.isInitialized()); 159 table = parent.getTable(); 160 } 161 162 /** 163 * Constructor 164 * 165 * @param parent The parent, owning the data structures this instance will share 166 * @param ordinal The ordinal number of this child 167 */ 168 public GenericFreeList(GenericFreeList parent, int ordinal) { 169 this.parent = parent; 170 this.table = parent.getTable(); 171 this.heads = parent.getHeads(); 172 this.head = -(1 + ordinal); 173 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(-this.head <= this.heads); 174 } 175 176 /* Getter */ 177 int[] getTable() { 178 return table; 179 } 180 int getHeads() { 181 return heads; 182 } 183 184 /** 185 * Initialize a unit as a sentinel 186 * 187 * @param unit The unit to be initialized 188 */ 189 @Override 190 protected void setSentinel(int unit) { 191 setLoEntry(unit, NEXT_MASK & unit); 192 setHiEntry(unit, PREV_MASK & unit); 193 } 194 195 /** 196 * Get the size of a lump of units 197 * 198 * @param unit The first unit in the lump of units 199 * @return The size of the lump of units 200 */ 201 @Override 202 protected int getSize(int unit) { 203 if ((getHiEntry(unit) & MULTI_MASK) == MULTI_MASK) 204 return (getHiEntry(unit + 1) & SIZE_MASK); 205 else 206 return 1; 207 } 208 209 /** 210 * Set the size of lump of units 211 * 212 * @param unit The first unit in the lump of units 213 * @param size The size of the lump of units 214 */ 215 @Override 216 protected void setSize(int unit, int size) { 217 if (size > 1) { 218 setHiEntry(unit, getHiEntry(unit) | MULTI_MASK); 219 setHiEntry(unit + 1, MULTI_MASK | size); 220 setHiEntry(unit + size - 1, MULTI_MASK | size); 221 } else 222 setHiEntry(unit, getHiEntry(unit) & ~MULTI_MASK); 223 } 224 225 /** 226 * Establish whether a lump of units is free 227 * 228 * @param unit The first or last unit in the lump 229 * @return {@code true} if the lump is free 230 */ 231 @Override 232 protected boolean getFree(int unit) { 233 return ((getLoEntry(unit) & FREE_MASK) == FREE_MASK); 234 } 235 236 /** 237 * Set the "free" flag for a lump of units (both the first and last 238 * units in the lump are set. 239 * 240 * @param unit The first unit in the lump 241 * @param isFree {@code true} if the lump is to be marked as free 242 */ 243 @Override 244 protected void setFree(int unit, boolean isFree) { 245 int size; 246 if (isFree) { 247 setLoEntry(unit, getLoEntry(unit) | FREE_MASK); 248 if ((size = getSize(unit)) > 1) 249 setLoEntry(unit + size - 1, getLoEntry(unit + size - 1) | FREE_MASK); 250 } else { 251 setLoEntry(unit, getLoEntry(unit) & ~FREE_MASK); 252 if ((size = getSize(unit)) > 1) 253 setLoEntry(unit + size - 1, getLoEntry(unit + size - 1) & ~FREE_MASK); 254 } 255 } 256 257 /** 258 * Get the next lump in the doubly linked free list 259 * 260 * @param unit The index of the first unit in the current lump 261 * @return The index of the first unit of the next lump of units in the list 262 */ 263 @Override 264 protected int getNext(int unit) { 265 int next = getHiEntry(unit) & NEXT_MASK; 266 return (next <= MAX_UNITS) ? next : head; 267 } 268 269 /** 270 * Set the next lump in the doubly linked free list 271 * 272 * @param unit The index of the first unit in the lump to be set 273 * @param next The value to be set. 274 */ 275 @Override 276 protected void setNext(int unit, int next) { 277 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((next >= -heads) && (next <= MAX_UNITS)); 278 int oldValue = getHiEntry(unit); 279 int newValue = (oldValue & ~NEXT_MASK) | (next & NEXT_MASK); 280 setHiEntry(unit, newValue); 281 } 282 283 /** 284 * Get the previous lump in the doubly linked free list 285 * 286 * @param unit The index of the first unit in the current lump 287 * @return The index of the first unit of the previous lump of units 288 * in the list 289 */ 290 @Override 291 protected int getPrev(int unit) { 292 int prev = getLoEntry(unit) & PREV_MASK; 293 return (prev <= MAX_UNITS) ? prev : head; 294 } 295 296 /** 297 * Set the previous lump in the doubly linked free list 298 * 299 * @param unit The index of the first unit in the lump to be set 300 * @param prev The value to be set. 301 */ 302 @Override 303 protected void setPrev(int unit, int prev) { 304 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((prev >= -heads) && (prev <= MAX_UNITS)); 305 int oldValue = getLoEntry(unit); 306 int newValue = (oldValue & ~PREV_MASK) | (prev & PREV_MASK); 307 setLoEntry(unit, newValue); 308 } 309 310 /** 311 * Set the uncoalescable bit associated with this unit. 312 * This ensures this unit cannot be coalesced with units below 313 * it. 314 * 315 * @param unit The unit whose uncoalescable bit is to be set 316 */ 317 public void setUncoalescable(int unit) { 318 setLoEntry(unit, getLoEntry(unit) | COALESC_MASK); 319 } 320 321 /** 322 * Clear the uncoalescable bit associated with this unit. 323 * This allows this unit to be coalesced with units below 324 * it. 325 * 326 * @param unit The unit whose uncoalescable bit is to be cleared 327 */ 328 public void clearUncoalescable(int unit) { 329 setLoEntry(unit, getLoEntry(unit) & ~COALESC_MASK); 330 } 331 332 /** 333 * Return true if this unit may be coalesced with the unit below it. 334 * 335 * @param unit The unit in question 336 * @return {@code true} if this unit may be coalesced with the unit below it. 337 */ 338 @Override 339 public boolean isCoalescable(int unit) { 340 return (getLoEntry(unit) & COALESC_MASK) == 0; 341 } 342 343 /** 344 * Get the lump to the "left" of the current lump (i.e. "above" it) 345 * 346 * @param unit The index of the first unit in the lump in question 347 * @return The index of the first unit in the lump to the 348 * "left"/"above" the lump in question. 349 */ 350 @Override 351 protected int getLeft(int unit) { 352 if ((getHiEntry(unit - 1) & MULTI_MASK) == MULTI_MASK) 353 return unit - (getHiEntry(unit - 1) & SIZE_MASK); 354 else 355 return unit - 1; 356 } 357 358 359 /** 360 * Get the contents of an entry 361 * 362 * @param unit The index of the unit 363 * @return The contents of the unit 364 */ 365 private int getLoEntry(int unit) { 366 return table[(unit + heads) << 1]; 367 } 368 private int getHiEntry(int unit) { 369 return table[((unit + heads) << 1) + 1]; 370 } 371 372 /** 373 * Set the contents of an entry 374 * 375 * @param unit The index of the unit 376 * @param value The contents of the unit 377 */ 378 private void setLoEntry(int unit, int value) { 379 table[(unit + heads) << 1] = value; 380 } 381 private void setHiEntry(int unit, int value) { 382 table[((unit + heads) << 1) + 1] = value; 383 } 384 385 private static final int TOTAL_BITS = 32; 386 private static final int UNIT_BITS = (TOTAL_BITS - 2); 387 public static final int MAX_UNITS = (int) (((((long) 1) << UNIT_BITS) - 1) - MAX_HEADS - 1); 388 private static final int NEXT_MASK = (int) ((((long) 1) << UNIT_BITS) - 1); 389 private static final int PREV_MASK = (int) ((((long) 1) << UNIT_BITS) - 1); 390 private static final int FREE_MASK = 1 << (TOTAL_BITS - 1); 391 private static final int MULTI_MASK = 1 << (TOTAL_BITS - 1); 392 private static final int COALESC_MASK = 1 << (TOTAL_BITS - 2); 393 private static final int SIZE_MASK = (int) ((((long) 1) << UNIT_BITS) - 1); 394 395 private int[] table; 396 private final GenericFreeList parent; 397}