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; 014 015 import org.mmtk.plan.Plan; 016 import org.mmtk.vm.VM; 017 018 import 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 094 public final class GenericFreeList extends BaseGenericFreeList implements Constants { 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() { return table; } 178 int getHeads() { return heads; } 179 180 /** 181 * Initialize a unit as a sentinel 182 * 183 * @param unit The unit to be initialized 184 */ 185 @Override 186 protected void setSentinel(int unit) { 187 setLoEntry(unit, NEXT_MASK & unit); 188 setHiEntry(unit, PREV_MASK & unit); 189 } 190 191 /** 192 * Get the size of a lump of units 193 * 194 * @param unit The first unit in the lump of units 195 * @return The size of the lump of units 196 */ 197 @Override 198 protected int getSize(int unit) { 199 if ((getHiEntry(unit) & MULTI_MASK) == MULTI_MASK) 200 return (getHiEntry(unit + 1) & SIZE_MASK); 201 else 202 return 1; 203 } 204 205 /** 206 * Set the size of lump of units 207 * 208 * @param unit The first unit in the lump of units 209 * @param size The size of the lump of units 210 */ 211 @Override 212 protected void setSize(int unit, int size) { 213 if (size > 1) { 214 setHiEntry(unit, getHiEntry(unit) | MULTI_MASK); 215 setHiEntry(unit + 1, MULTI_MASK | size); 216 setHiEntry(unit + size - 1, MULTI_MASK | size); 217 } else 218 setHiEntry(unit, getHiEntry(unit) & ~MULTI_MASK); 219 } 220 221 /** 222 * Establish whether a lump of units is free 223 * 224 * @param unit The first or last unit in the lump 225 * @return {@code true} if the lump is free 226 */ 227 @Override 228 protected boolean getFree(int unit) { 229 return ((getLoEntry(unit) & FREE_MASK) == FREE_MASK); 230 } 231 232 /** 233 * Set the "free" flag for a lump of units (both the first and last 234 * units in the lump are set. 235 * 236 * @param unit The first unit in the lump 237 * @param isFree {@code true} if the lump is to be marked as free 238 */ 239 @Override 240 protected void setFree(int unit, boolean isFree) { 241 int size; 242 if (isFree) { 243 setLoEntry(unit, getLoEntry(unit) | FREE_MASK); 244 if ((size = getSize(unit)) > 1) 245 setLoEntry(unit + size - 1, getLoEntry(unit + size - 1) | FREE_MASK); 246 } else { 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 } 251 } 252 253 /** 254 * Get the next lump in the doubly linked free list 255 * 256 * @param unit The index of the first unit in the current lump 257 * @return The index of the first unit of the next lump of units in the list 258 */ 259 @Override 260 protected int getNext(int unit) { 261 int next = getHiEntry(unit) & NEXT_MASK; 262 return (next <= MAX_UNITS) ? next : head; 263 } 264 265 /** 266 * Set the next lump in the doubly linked free list 267 * 268 * @param unit The index of the first unit in the lump to be set 269 * @param next The value to be set. 270 */ 271 @Override 272 protected void setNext(int unit, int next) { 273 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((next >= -heads) && (next <= MAX_UNITS)); 274 int oldValue = getHiEntry(unit); 275 int newValue = (oldValue & ~NEXT_MASK) | (next & NEXT_MASK); 276 setHiEntry(unit, newValue); 277 } 278 279 /** 280 * Get the previous lump in the doubly linked free list 281 * 282 * @param unit The index of the first unit in the current lump 283 * @return The index of the first unit of the previous lump of units 284 * in the list 285 */ 286 @Override 287 protected int getPrev(int unit) { 288 int prev = getLoEntry(unit) & PREV_MASK; 289 return (prev <= MAX_UNITS) ? prev : head; 290 } 291 292 /** 293 * Set the previous lump in the doubly linked free list 294 * 295 * @param unit The index of the first unit in the lump to be set 296 * @param prev The value to be set. 297 */ 298 @Override 299 protected void setPrev(int unit, int prev) { 300 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((prev >= -heads) && (prev <= MAX_UNITS)); 301 int oldValue = getLoEntry(unit); 302 int newValue = (oldValue & ~PREV_MASK) | (prev & PREV_MASK); 303 setLoEntry(unit, newValue); 304 } 305 306 /** 307 * Set the uncoalescable bit associated with this unit. 308 * This ensures this unit cannot be coalesced with units below 309 * it. 310 * 311 * @param unit The unit whose uncoalescable bit is to be set 312 */ 313 public void setUncoalescable(int unit) { 314 setLoEntry(unit, getLoEntry(unit) | COALESC_MASK); 315 } 316 317 /** 318 * Clear the uncoalescable bit associated with this unit. 319 * This allows this unit to be coalesced with units below 320 * it. 321 * 322 * @param unit The unit whose uncoalescable bit is to be cleared 323 */ 324 public void clearUncoalescable(int unit) { 325 setLoEntry(unit, getLoEntry(unit) & ~COALESC_MASK); 326 } 327 328 /** 329 * Return true if this unit may be coalesced with the unit below it. 330 * 331 * @param unit The unit in question 332 * @return {@code true} if this unit may be coalesced with the unit below it. 333 */ 334 @Override 335 public boolean isCoalescable(int unit) { 336 return (getLoEntry(unit) & COALESC_MASK) == 0; 337 } 338 339 /** 340 * Get the lump to the "left" of the current lump (i.e. "above" it) 341 * 342 * @param unit The index of the first unit in the lump in question 343 * @return The index of the first unit in the lump to the 344 * "left"/"above" the lump in question. 345 */ 346 @Override 347 protected int getLeft(int unit) { 348 if ((getHiEntry(unit - 1) & MULTI_MASK) == MULTI_MASK) 349 return unit - (getHiEntry(unit - 1) & SIZE_MASK); 350 else 351 return unit - 1; 352 } 353 354 355 /** 356 * Get the contents of an entry 357 * 358 * @param unit The index of the unit 359 * @return The contents of the unit 360 */ 361 private int getLoEntry(int unit) { 362 return table[(unit + heads) << 1]; 363 } 364 private int getHiEntry(int unit) { 365 return table[((unit + heads) << 1) + 1]; 366 } 367 368 /** 369 * Set the contents of an entry 370 * 371 * @param unit The index of the unit 372 * @param value The contents of the unit 373 */ 374 private void setLoEntry(int unit, int value) { 375 table[(unit + heads) << 1] = value; 376 } 377 private void setHiEntry(int unit, int value) { 378 table[((unit + heads) << 1) + 1] = value; 379 } 380 381 private static final int TOTAL_BITS = 32; 382 private static final int UNIT_BITS = (TOTAL_BITS - 2); 383 public static final int MAX_UNITS = (int) (((((long) 1) << UNIT_BITS) - 1) - MAX_HEADS - 1); 384 private static final int NEXT_MASK = (int) ((((long) 1) << UNIT_BITS) - 1); 385 private static final int PREV_MASK = (int) ((((long) 1) << UNIT_BITS) - 1); 386 private static final int FREE_MASK = 1 << (TOTAL_BITS - 1); 387 private static final int MULTI_MASK = 1 << (TOTAL_BITS - 1); 388 private static final int COALESC_MASK = 1 << (TOTAL_BITS - 2); 389 private static final int SIZE_MASK = (int) ((((long) 1) << UNIT_BITS) - 1); 390 391 private int[] table; 392 private final GenericFreeList parent; 393 }