BlockAllocator.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /*
  2. * Copyright (C) 2012 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. AND ITS CONTRIBUTORS ``AS IS''
  14. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  15. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
  17. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  23. * THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #ifndef BlockAllocator_h
  26. #define BlockAllocator_h
  27. #include "HeapBlock.h"
  28. #include "Region.h"
  29. #include <wtf/DoublyLinkedList.h>
  30. #include <wtf/Forward.h>
  31. #include <wtf/PageAllocationAligned.h>
  32. #include <wtf/TCSpinLock.h>
  33. #include <wtf/Threading.h>
  34. namespace JSC {
  35. class BlockAllocator;
  36. class CopiedBlock;
  37. class CopyWorkListSegment;
  38. class HandleBlock;
  39. class VM;
  40. class MarkStackSegment;
  41. class MarkedBlock;
  42. class WeakBlock;
  43. // Simple allocator to reduce VM cost by holding onto blocks of memory for
  44. // short periods of time and then freeing them on a secondary thread.
  45. class BlockAllocator {
  46. public:
  47. BlockAllocator();
  48. ~BlockAllocator();
  49. template <typename T> DeadBlock* allocate();
  50. DeadBlock* allocateCustomSize(size_t blockSize, size_t blockAlignment);
  51. template <typename T> void deallocate(T*);
  52. template <typename T> void deallocateCustomSize(T*);
  53. private:
  54. void waitForRelativeTimeWhileHoldingLock(double relative);
  55. void waitForRelativeTime(double relative);
  56. void blockFreeingThreadMain();
  57. static void blockFreeingThreadStartFunc(void* heap);
  58. struct RegionSet {
  59. RegionSet(size_t blockSize)
  60. : m_numberOfPartialRegions(0)
  61. , m_blockSize(blockSize)
  62. {
  63. }
  64. bool isEmpty() const
  65. {
  66. return m_fullRegions.isEmpty() && m_partialRegions.isEmpty();
  67. }
  68. DoublyLinkedList<Region> m_fullRegions;
  69. DoublyLinkedList<Region> m_partialRegions;
  70. size_t m_numberOfPartialRegions;
  71. size_t m_blockSize;
  72. };
  73. DeadBlock* tryAllocateFromRegion(RegionSet&, DoublyLinkedList<Region>&, size_t&);
  74. bool allRegionSetsAreEmpty() const;
  75. void releaseFreeRegions();
  76. template <typename T> RegionSet& regionSetFor();
  77. SuperRegion m_superRegion;
  78. RegionSet m_copiedRegionSet;
  79. RegionSet m_markedRegionSet;
  80. // WeakBlocks and MarkStackSegments use the same RegionSet since they're the same size.
  81. RegionSet m_fourKBBlockRegionSet;
  82. RegionSet m_workListRegionSet;
  83. DoublyLinkedList<Region> m_emptyRegions;
  84. size_t m_numberOfEmptyRegions;
  85. bool m_isCurrentlyAllocating;
  86. bool m_blockFreeingThreadShouldQuit;
  87. SpinLock m_regionLock;
  88. Mutex m_emptyRegionConditionLock;
  89. ThreadCondition m_emptyRegionCondition;
  90. ThreadIdentifier m_blockFreeingThread;
  91. };
  92. inline DeadBlock* BlockAllocator::tryAllocateFromRegion(RegionSet& set, DoublyLinkedList<Region>& regions, size_t& numberOfRegions)
  93. {
  94. if (numberOfRegions) {
  95. ASSERT(!regions.isEmpty());
  96. Region* region = regions.head();
  97. ASSERT(!region->isFull());
  98. if (region->isEmpty()) {
  99. ASSERT(region == m_emptyRegions.head());
  100. m_numberOfEmptyRegions--;
  101. set.m_numberOfPartialRegions++;
  102. region = m_emptyRegions.removeHead()->reset(set.m_blockSize);
  103. set.m_partialRegions.push(region);
  104. }
  105. DeadBlock* block = region->allocate();
  106. if (region->isFull()) {
  107. set.m_numberOfPartialRegions--;
  108. set.m_fullRegions.push(set.m_partialRegions.removeHead());
  109. }
  110. return block;
  111. }
  112. return 0;
  113. }
  114. template<typename T>
  115. inline DeadBlock* BlockAllocator::allocate()
  116. {
  117. RegionSet& set = regionSetFor<T>();
  118. DeadBlock* block;
  119. m_isCurrentlyAllocating = true;
  120. {
  121. SpinLockHolder locker(&m_regionLock);
  122. if ((block = tryAllocateFromRegion(set, set.m_partialRegions, set.m_numberOfPartialRegions)))
  123. return block;
  124. if ((block = tryAllocateFromRegion(set, m_emptyRegions, m_numberOfEmptyRegions)))
  125. return block;
  126. }
  127. Region* newRegion = Region::create(&m_superRegion, T::blockSize);
  128. SpinLockHolder locker(&m_regionLock);
  129. m_emptyRegions.push(newRegion);
  130. m_numberOfEmptyRegions++;
  131. block = tryAllocateFromRegion(set, m_emptyRegions, m_numberOfEmptyRegions);
  132. ASSERT(block);
  133. return block;
  134. }
  135. inline DeadBlock* BlockAllocator::allocateCustomSize(size_t blockSize, size_t blockAlignment)
  136. {
  137. size_t realSize = WTF::roundUpToMultipleOf(blockAlignment, blockSize);
  138. Region* newRegion = Region::createCustomSize(&m_superRegion, realSize, blockAlignment);
  139. DeadBlock* block = newRegion->allocate();
  140. ASSERT(block);
  141. return block;
  142. }
  143. template<typename T>
  144. inline void BlockAllocator::deallocate(T* block)
  145. {
  146. RegionSet& set = regionSetFor<T>();
  147. bool shouldWakeBlockFreeingThread = false;
  148. {
  149. SpinLockHolder locker(&m_regionLock);
  150. Region* region = block->region();
  151. ASSERT(!region->isEmpty());
  152. if (region->isFull())
  153. set.m_fullRegions.remove(region);
  154. else {
  155. set.m_partialRegions.remove(region);
  156. set.m_numberOfPartialRegions--;
  157. }
  158. region->deallocate(block);
  159. if (region->isEmpty()) {
  160. m_emptyRegions.push(region);
  161. shouldWakeBlockFreeingThread = !m_numberOfEmptyRegions;
  162. m_numberOfEmptyRegions++;
  163. } else {
  164. set.m_partialRegions.push(region);
  165. set.m_numberOfPartialRegions++;
  166. }
  167. }
  168. if (shouldWakeBlockFreeingThread) {
  169. MutexLocker mutexLocker(m_emptyRegionConditionLock);
  170. m_emptyRegionCondition.signal();
  171. }
  172. }
  173. template<typename T>
  174. inline void BlockAllocator::deallocateCustomSize(T* block)
  175. {
  176. Region* region = block->region();
  177. ASSERT(region->isCustomSize());
  178. region->deallocate(block);
  179. region->destroy();
  180. }
  181. template <>
  182. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<CopiedBlock>()
  183. {
  184. return m_copiedRegionSet;
  185. }
  186. template <>
  187. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<MarkedBlock>()
  188. {
  189. return m_markedRegionSet;
  190. }
  191. template <>
  192. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<WeakBlock>()
  193. {
  194. return m_fourKBBlockRegionSet;
  195. }
  196. template <>
  197. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<MarkStackSegment>()
  198. {
  199. return m_fourKBBlockRegionSet;
  200. }
  201. template <>
  202. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<CopyWorkListSegment>()
  203. {
  204. return m_workListRegionSet;
  205. }
  206. template <>
  207. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HandleBlock>()
  208. {
  209. return m_fourKBBlockRegionSet;
  210. }
  211. template <>
  212. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<CopiedBlock> >()
  213. {
  214. return m_copiedRegionSet;
  215. }
  216. template <>
  217. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<MarkedBlock> >()
  218. {
  219. return m_markedRegionSet;
  220. }
  221. template <>
  222. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<WeakBlock> >()
  223. {
  224. return m_fourKBBlockRegionSet;
  225. }
  226. template <>
  227. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<MarkStackSegment> >()
  228. {
  229. return m_fourKBBlockRegionSet;
  230. }
  231. template <>
  232. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<CopyWorkListSegment> >()
  233. {
  234. return m_workListRegionSet;
  235. }
  236. template <>
  237. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<HandleBlock> >()
  238. {
  239. return m_fourKBBlockRegionSet;
  240. }
  241. template <typename T>
  242. inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor()
  243. {
  244. RELEASE_ASSERT_NOT_REACHED();
  245. return *(RegionSet*)0;
  246. }
  247. } // namespace JSC
  248. #endif // BlockAllocator_h