/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.mmtk.utility; import org.mmtk.plan.Plan; import org.mmtk.vm.VM; import org.vmmagic.pragma.*; /** * This is a very simple, generic malloc-free allocator. It works * abstractly, in "units", which the user may associate with some * other allocatable resource (e.g. heap blocks). The user issues * requests for N units and the allocator returns the index of the * first of a contiguous set of N units or fails, returning -1. The * user frees the block of N units by calling <code>free()</code> with * the index of the first unit as the argument.<p> * * Properties/Constraints:<ul> * <li> The allocator consumes one word per allocatable unit (plus * a fixed overhead of about 128 words).</li> * <li> The allocator can only deal with MAX_UNITS units (see below for * the value).</li> * </ul> * * The basic data structure used by the algorithm is a large table, * with one word per allocatable unit. Each word is used in a * number of different ways, some combination of "undefined" (32), * "free/used" (1), "multi/single" (1), "prev" (15), "next" (15) & * "size" (15) where field sizes in bits are in parenthesis. * <pre> * +-+-+-----------+-----------+ * |f|m| prev | next/size | * +-+-+-----------+-----------+ * * - single free unit: "free", "single", "prev", "next" * - single used unit: "used", "single" * - contiguous free units * . first unit: "free", "multi", "prev", "next" * . second unit: "free", "multi", "size" * . last unit: "free", "multi", "size" * - contiguous used units * . first unit: "used", "multi", "prev", "next" * . second unit: "used", "multi", "size" * . last unit: "used", "multi", "size" * - any other unit: undefined * * +-+-+-----------+-----------+ * top sentinel |0|0| tail | head | [-1] * +-+-+-----------+-----------+ * .... * /-------- +-+-+-----------+-----------+ * | |1|1| prev | next | [j] * | +-+-+-----------+-----------+ * | |1|1| | size | [j+1] * free multi +-+-+-----------+-----------+ * unit block | ... | ... * | +-+-+-----------+-----------+ * | |1|1| | size | * >-------- +-+-+-----------+-----------+ * single free unit |1|0| prev | next | * >-------- +-+-+-----------+-----------+ * single used unit |0|0| | * >-------- +-+-+-----------------------+ * | |0|1| | * | +-+-+-----------+-----------+ * | |0|1| | size | * used multi +-+-+-----------+-----------+ * unit block | ... | * | +-+-+-----------+-----------+ * | |0|1| | size | * \-------- +-+-+-----------+-----------+ * .... * +-+-+-----------------------+ * bottom sentinel |0|0| | [N] * +-+-+-----------------------+ * </pre> * The sentinels serve as guards against out of range coalescing * because they both appear as "used" blocks and so will never * coalesce. The top sentinel also serves as the head and tail of * the doubly linked list of free blocks. */ @Uninterruptible public final class IntArrayFreeList extends GenericFreeList { /**************************************************************************** * * Public instance methods */ /** * Constructor * * @param units The number of allocatable units for this free list */ public IntArrayFreeList(int units) { this(units, units); } /** * Constructor * * @param units The number of allocatable units for this free list * @param grain Units are allocated such that they will never cross this granularity boundary */ public IntArrayFreeList(int units, int grain) { this(units, grain, 1); } /** * Constructor * * @param units The number of allocatable units for this free list * @param grain Units are allocated such that they will never cross this granularity boundary * @param heads The number of free lists which will share this instance */ public IntArrayFreeList(int units, int grain, int heads) { this.parent = null; if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(units <= MAX_UNITS && heads <= MAX_HEADS); this.heads = heads; head = -1; // allocate the data structure, including space for top & bottom sentinels table = new int[(units + 1 + heads) << 1]; initializeHeap(units, grain); } /** * Resize the free list for a parent free list. * This must not be called dynamically (ie not after bootstrap). * * @param units The number of allocatable units for this free list * @param grain Units are allocated such that they will never cross this granularity boundary */ @Override @Interruptible public void resizeFreeList(int units, int grain) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(parent == null && !Plan.isInitialized()); table = new int[(units + 1 + heads) << 1]; initializeHeap(units, grain); } /** * Resize the free list for a child free list. * This must not be called dynamically (ie not after bootstrap). */ @Override @Interruptible public void resizeFreeList() { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(parent != null && !Plan.isInitialized()); table = parent.getTable(); } /** * Constructor * * @param parent The parent, owning the data structures this instance will share * @param ordinal The ordinal number of this child */ public IntArrayFreeList(IntArrayFreeList parent, int ordinal) { this.parent = parent; this.table = parent.getTable(); this.heads = parent.getHeads(); this.head = -(1 + ordinal); if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(-this.head <= this.heads); } /* Getter */ int[] getTable() { return table; } int getHeads() { return heads; } @Override protected int getEntry(int index) { return table[index]; } @Override protected void setEntry(int index, int value) { table[index] = value; } /** * Print the entire list (for debugging purposes) */ @Override public void dbgPrintDetail() { Log.writeln("--vvv-- Free List --vvv--"); for (int i = -heads; i <= table.length / 2 - heads - 1; i++) { dbgPrintEntry(i); } Log.writeln("--^^^-- Free List --^^^--"); } @Override public void dbgPrintSummary() { // Nothing to do } private int[] table; private final IntArrayFreeList parent; }