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; }