1/* 2 * Copyright (C) 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "BAssert.h" 27#include "BeginTag.h" 28#include "LargeChunk.h" 29#include "Deallocator.h" 30#include "Heap.h" 31#include "Inline.h" 32#include "PerProcess.h" 33#include "SmallChunk.h" 34#include <algorithm> 35#include <sys/mman.h> 36 37using namespace std; 38 39namespace bmalloc { 40 41Deallocator::Deallocator() 42 : m_objectLog() 43 , m_smallLineCaches() 44 , m_mediumLineCache() 45{ 46} 47 48Deallocator::~Deallocator() 49{ 50 scavenge(); 51} 52 53void Deallocator::scavenge() 54{ 55 processObjectLog(); 56 57 std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex()); 58 Heap* heap = PerProcess<Heap>::getFastCase(); 59 60 for (auto& smallLineCache : m_smallLineCaches) { 61 while (smallLineCache.size()) 62 heap->deallocateSmallLine(lock, smallLineCache.pop()); 63 } 64 while (m_mediumLineCache.size()) 65 heap->deallocateMediumLine(lock, m_mediumLineCache.pop()); 66} 67 68void Deallocator::deallocateLarge(void* object) 69{ 70 std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex()); 71 PerProcess<Heap>::getFastCase()->deallocateLarge(lock, object); 72} 73 74void Deallocator::deallocateXLarge(void* object) 75{ 76 std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex()); 77 PerProcess<Heap>::getFastCase()->deallocateXLarge(lock, object); 78} 79 80void Deallocator::processObjectLog() 81{ 82 std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex()); 83 84 for (auto object : m_objectLog) { 85 if (isSmall(object)) { 86 SmallLine* line = SmallLine::get(object); 87 if (!line->deref(lock)) 88 continue; 89 deallocateSmallLine(lock, line); 90 } else { 91 BASSERT(isSmallOrMedium(object)); 92 MediumLine* line = MediumLine::get(object); 93 if (!line->deref(lock)) 94 continue; 95 deallocateMediumLine(lock, line); 96 } 97 } 98 99 m_objectLog.clear(); 100} 101 102void Deallocator::deallocateSlowCase(void* object) 103{ 104 BASSERT(!deallocateFastCase(object)); 105 106 if (!object) 107 return; 108 109 if (isSmallOrMedium(object)) { 110 processObjectLog(); 111 m_objectLog.push(object); 112 return; 113 } 114 115 BeginTag* beginTag = LargeChunk::beginTag(object); 116 if (!beginTag->isXLarge()) 117 return deallocateLarge(object); 118 119 return deallocateXLarge(object); 120} 121 122void Deallocator::deallocateSmallLine(std::lock_guard<StaticMutex>& lock, SmallLine* line) 123{ 124 SmallLineCache& smallLineCache = m_smallLineCaches[SmallPage::get(line)->smallSizeClass()]; 125 if (smallLineCache.size() == smallLineCache.capacity()) 126 return PerProcess<Heap>::getFastCase()->deallocateSmallLine(lock, line); 127 128 smallLineCache.push(line); 129} 130 131SmallLine* Deallocator::allocateSmallLine(size_t smallSizeClass) 132{ 133 SmallLineCache& smallLineCache = m_smallLineCaches[smallSizeClass]; 134 if (!smallLineCache.size()) { 135 std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex()); 136 Heap* heap = PerProcess<Heap>::getFastCase(); 137 138 while (smallLineCache.size() != smallLineCache.capacity()) 139 smallLineCache.push(heap->allocateSmallLine(lock, smallSizeClass)); 140 } 141 142 return smallLineCache.pop(); 143} 144 145void Deallocator::deallocateMediumLine(std::lock_guard<StaticMutex>& lock, MediumLine* line) 146{ 147 if (m_mediumLineCache.size() == m_mediumLineCache.capacity()) 148 return PerProcess<Heap>::getFastCase()->deallocateMediumLine(lock, line); 149 150 m_mediumLineCache.push(line); 151} 152 153MediumLine* Deallocator::allocateMediumLine() 154{ 155 if (!m_mediumLineCache.size()) { 156 std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex()); 157 Heap* heap = PerProcess<Heap>::getFastCase(); 158 159 while (m_mediumLineCache.size() != m_mediumLineCache.capacity()) 160 m_mediumLineCache.push(heap->allocateMediumLine(lock)); 161 } 162 163 return m_mediumLineCache.pop(); 164} 165 166} // namespace bmalloc 167