INLINE void Allocator::refillAllocator(BumpAllocator& allocator, size_t sizeClass) { BumpRangeCache& bumpRangeCache = m_bumpRangeCaches[sizeClass]; if (!bumpRangeCache.size()) return refillAllocatorSlowCase(allocator, sizeClass); return allocator.refill(bumpRangeCache.pop()); }
void Heap::allocateMediumBumpRanges(std::lock_guard<StaticMutex>& lock, size_t sizeClass, BumpAllocator& allocator, BumpRangeCache& rangeCache) { MediumPage* page = allocateMediumPage(lock, sizeClass); BASSERT(!rangeCache.size()); MediumLine* lines = page->begin(); // Due to overlap from the previous line, the last line in the page may not be able to fit any objects. size_t end = MediumPage::lineCount; if (!m_mediumLineMetadata[sizeClass][MediumPage::lineCount - 1].objectCount) --end; // Find a free line. for (size_t lineNumber = 0; lineNumber < end; ++lineNumber) { if (lines[lineNumber].refCount(lock)) continue; // In a fragmented page, some free ranges might not fit in the cache. if (rangeCache.size() == rangeCache.capacity()) { m_mediumPagesWithFreeLines[sizeClass].push(page); return; } LineMetadata& lineMetadata = m_mediumLineMetadata[sizeClass][lineNumber]; char* begin = lines[lineNumber].begin() + lineMetadata.startOffset; unsigned short objectCount = lineMetadata.objectCount; lines[lineNumber].ref(lock, lineMetadata.objectCount); page->ref(lock); // Merge with subsequent free lines. while (++lineNumber < end) { if (lines[lineNumber].refCount(lock)) break; LineMetadata& lineMetadata = m_mediumLineMetadata[sizeClass][lineNumber]; objectCount += lineMetadata.objectCount; lines[lineNumber].ref(lock, lineMetadata.objectCount); page->ref(lock); } if (!allocator.canAllocate()) allocator.refill({ begin, objectCount }); else rangeCache.push({ begin, objectCount }); } }
bool BumpAllocatorTest() { bool ok = true; BumpAllocator alloc; { alloc.setup(1024 + sizeof(size_t) * 4, 1); void * a = alloc.alloc(512); ok = ok && a != NULL; void * b = alloc.alloc(256); ok = ok && b != NULL; void * c = alloc.alloc(256); ok = ok && c != NULL; ok = ok && alloc.amount_free() == sizeof(size_t); //fprintf(stderr, "Checking free = 0 : %d\n", ok); alloc.free(c); #ifdef USE_BUILTIN_ATOMICS_FOR_ALLOCATOR ok = ok && alloc.amount_free() == 256 + sizeof(size_t) * 2; //fprintf(stderr, "Checking free = 256 : %d\n", ok); void * d = alloc.alloc(128); (void)d; ok = ok && alloc.amount_free() == 128 + sizeof(size_t); //fprintf(stderr, "Checking free = 128 : %d\n", ok); #endif void * e = alloc.alloc(256); ok = ok && e == NULL; //fprintf(stderr, "Checking too much allocated = NULL: %d", ok); alloc.teardown(); alloc.setup(128 + sizeof(size_t) * 2, 1); a = alloc.alloc(127); b = alloc.alloc(2); c = alloc.alloc(1); ok = ok && b == NULL; //fprintf(stderr, "Checking new too much allocated = NULL : %d\n", ok); ok = ok && alloc.amount_free() == 0; } alloc.teardown(); { alloc.setup(1024 + sizeof(size_t) * 8, 16); void * a = alloc.alloc(512); ok = ok && a != NULL; void * b = alloc.alloc(256); ok = ok && b != NULL; void * c = alloc.alloc(256); ok = ok && c != NULL; ok = ok && alloc.amount_free() == sizeof(size_t) * 2; //fprintf(stderr, "Checking free = 0 : %d\n", ok); alloc.free(c); #ifdef USE_BUILTIN_ATOMICS_FOR_ALLOCATOR ok = ok && alloc.amount_free() == 256 + sizeof(size_t) * 4; //fprintf(stderr, "Checking free = 256 : %d\n", ok); void * d = alloc.alloc(128); (void) d; ok = ok && alloc.amount_free() == 128 + sizeof(size_t) * 2; //fprintf(stderr, "Checking free = 128 : %d\n", ok); #endif void * e = alloc.alloc(256); ok = ok && e == NULL; //fprintf(stderr, "Checking too much allocated = NULL: %d", ok); alloc.teardown(); } //fprintf(stderr, "Checking free = 0 : %d\n", ok); return ok; }