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) &amp;
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 *           &gt;--------  +-+-+-----------+-----------+
071 *   single free unit    |1|0|   prev    |   next    |
072 *           &gt;--------  +-+-+-----------+-----------+
073 *   single used unit    |0|0|                       |
074 *           &gt;--------  +-+-+-----------------------+
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}