void free(ExecutablePool::Allocation allocation)
    {
        void* pointer = allocation.base();
        size_t size = allocation.size();

        ASSERT(!!m_allocation);
        // Call release to report to the operating system that this
        // memory is no longer in use, and need not be paged out.
        ASSERT(isWithinVMPool(pointer, size));
        release(pointer, size);

        // Common-sized allocations are stored in the m_commonSizedAllocations
        // vector; all other freed chunks are added to m_freeList.
        if (size == m_commonSize)
            m_commonSizedAllocations.append(pointer);
        else
            addToFreeList(new FreeListEntry(pointer, size));

        // Do some housekeeping.  Every time we reach a point that
        // 16MB of allocations have been freed, sweep m_freeList
        // coalescing any neighboring fragments.
        m_countFreedSinceLastCoalesce += size;
        if (m_countFreedSinceLastCoalesce >= COALESCE_LIMIT) {
            m_countFreedSinceLastCoalesce = 0;
            coalesceFreeSpace();
        }
    }
    void* alloc(size_t size)
    {
        void* result;

        // Freed allocations of the common size are not stored back into the main
        // m_freeList, but are instead stored in a separate vector.  If the request
        // is for a common sized allocation, check this list.
        if ((size == m_commonSize) && m_commonSizedAllocations.size()) {
            result = m_commonSizedAllocations.last();
            m_commonSizedAllocations.removeLast();
        } else {
            // Serach m_freeList for a suitable sized chunk to allocate memory from.
            FreeListEntry* entry = m_freeList.search(size, m_freeList.GREATER_EQUAL);

            // This would be bad news.
            if (!entry) {
                // Errk!  Lets take a last-ditch desparation attempt at defragmentation...
                coalesceFreeSpace();
                // Did that free up a large enough chunk?
                entry = m_freeList.search(size, m_freeList.GREATER_EQUAL);
                // No?...  *BOOM!*
                if (!entry)
                    CRASH();
            }
            ASSERT(entry->size != m_commonSize);

            // Remove the entry from m_freeList.  But! -
            // Each entry in the tree may represent a chain of multiple chunks of the
            // same size, and we only want to remove one on them.  So, if this entry
            // does have a chain, just remove the first-but-one item from the chain.
            if (FreeListEntry* next = entry->nextEntry) {
                // We're going to leave 'entry' in the tree; remove 'next' from its chain.
                entry->nextEntry = next->nextEntry;
                next->nextEntry = 0;
                entry = next;
            } else
                m_freeList.remove(entry->size);

            // Whoo!, we have a result!
            ASSERT(entry->size >= size);
            result = entry->pointer;

            // If the allocation exactly fits the chunk we found in the,
            // m_freeList then the FreeListEntry node is no longer needed.
            if (entry->size == size)
                delete entry;
            else {
                // There is memory left over, and it is not of the common size.
                // We can reuse the existing FreeListEntry node to add this back
                // into m_freeList.
                entry->pointer = (void*)((intptr_t)entry->pointer + size);
                entry->size -= size;
                addToFreeList(entry);
            }
        }

        // Call reuse to report to the operating system that this memory is in use.
        ASSERT(isWithinVMPool(result, size));
        reuse(result, size);
        return result;
    }