HeapBucket.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. namespace Memory
  7. {
  8. // a size bucket in the heap for small object
  9. class HeapInfo;
  10. class RecyclerSweep;
  11. #if DBG
  12. template <class TBlockAttributes>
  13. class GenericRecyclerVerifyListConsistencyData
  14. {
  15. public:
  16. GenericRecyclerVerifyListConsistencyData() {};
  17. // Temporary data for Sweep list consistency checks
  18. bool expectFull;
  19. bool expectDispose;
  20. SmallHeapBlockT<TBlockAttributes> * nextAllocableBlockHead;
  21. bool hasSetupVerifyListConsistencyData;
  22. template <typename TBlockAttributes>
  23. void SetupVerifyListConsistencyData(SmallHeapBlockT<TBlockAttributes>* block, bool expectFull, bool expectDispose)
  24. {
  25. this->nextAllocableBlockHead = block;
  26. this->expectFull = expectFull;
  27. this->expectDispose = expectDispose;
  28. this->hasSetupVerifyListConsistencyData = true;
  29. }
  30. };
  31. class RecyclerVerifyListConsistencyData
  32. {
  33. public:
  34. RecyclerVerifyListConsistencyData() {};
  35. void SetupVerifyListConsistencyDataForSmallBlock(SmallHeapBlock* block, bool expectFull, bool expectDispose)
  36. {
  37. this->smallBlockVerifyListConsistencyData.nextAllocableBlockHead = block;
  38. this->smallBlockVerifyListConsistencyData.expectFull = expectFull;
  39. this->smallBlockVerifyListConsistencyData.expectDispose = expectDispose;
  40. this->smallBlockVerifyListConsistencyData.hasSetupVerifyListConsistencyData = true;
  41. }
  42. void SetupVerifyListConsistencyDataForMediumBlock(MediumHeapBlock* block, bool expectFull, bool expectDispose)
  43. {
  44. this->mediumBlockVerifyListConsistencyData.nextAllocableBlockHead = block;
  45. this->mediumBlockVerifyListConsistencyData.expectFull = expectFull;
  46. this->mediumBlockVerifyListConsistencyData.expectDispose = expectDispose;
  47. this->mediumBlockVerifyListConsistencyData.hasSetupVerifyListConsistencyData = true;
  48. }
  49. GenericRecyclerVerifyListConsistencyData<SmallAllocationBlockAttributes> smallBlockVerifyListConsistencyData;
  50. GenericRecyclerVerifyListConsistencyData<MediumAllocationBlockAttributes> mediumBlockVerifyListConsistencyData;
  51. };
  52. #endif
  53. // NOTE: HeapBucket can't have vtable, because we allocate them inline with recycler with custom initializer
  54. class HeapBucket
  55. {
  56. public:
  57. HeapBucket();
  58. uint GetBucketIndex() const;
  59. uint GetMediumBucketIndex() const;
  60. protected:
  61. template <typename TBlockType>
  62. static void EnumerateObjects(TBlockType * heapBlockList, ObjectInfoBits infoBits, void (*CallBackFunction)(void * address, size_t size));
  63. HeapInfo * heapInfo;
  64. uint sizeCat;
  65. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  66. size_t heapBlockCount;
  67. size_t newHeapBlockCount; // count of heap bock that is in the heap info and not in the heap bucket yet
  68. size_t emptyHeapBlockCount;
  69. #endif
  70. #ifdef RECYCLER_PAGE_HEAP
  71. bool isPageHeapEnabled;
  72. public:
  73. bool IsPageHeapEnabled(ObjectInfoBits attributes) const
  74. {
  75. // LargeHeapBlock does not support TrackBit today
  76. return isPageHeapEnabled && ((attributes & ClientTrackableObjectBits) == 0);
  77. }
  78. #endif
  79. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  80. Recycler * GetRecycler() const;
  81. #endif
  82. template <typename TBlockType>
  83. friend class SmallHeapBlockAllocator;
  84. template <typename TBlockAttributes>
  85. friend class SmallHeapBlockT;
  86. template <typename TBlockAttributes>
  87. friend class SmallFinalizableHeapBlockT;
  88. friend class LargeHeapBlock;
  89. #ifdef RECYCLER_WRITE_BARRIER
  90. template <typename TBlockAttributes>
  91. friend class SmallFinalizableWithBarrierHeapBlockT;
  92. template <typename TBlockAttributes>
  93. friend class SmallNormalWithBarrierHeapBlockT;
  94. #endif
  95. };
  96. template <typename TBlockType>
  97. class HeapBucketT : public HeapBucket
  98. {
  99. typedef typename SmallHeapBlockAllocator<TBlockType> TBlockAllocatorType;
  100. public:
  101. HeapBucketT();
  102. ~HeapBucketT();
  103. bool IntegrateBlock(char * blockAddress, PageSegment * segment, Recycler * recycler);
  104. template <ObjectInfoBits attributes, bool nothrow>
  105. __inline char * RealAlloc(Recycler * recycler, size_t sizeCat, size_t size);
  106. #ifdef RECYCLER_PAGE_HEAP
  107. char * PageHeapAlloc(Recycler * recycler, __declspec(guard(overflow)) size_t sizeCat, size_t size, ObjectInfoBits attributes, PageHeapMode mode, bool nothrow);
  108. #endif
  109. void ExplicitFree(void* object, size_t sizeCat);
  110. char * SnailAlloc(Recycler * recycler, TBlockAllocatorType * allocator, __declspec(guard(overflow)) size_t sizeCat, size_t size, ObjectInfoBits attributes, bool nothrow);
  111. void ResetMarks(ResetMarkFlags flags);
  112. void ScanNewImplicitRoots(Recycler * recycler);
  113. #ifdef DUMP_FRAGMENTATION_STATS
  114. void AggregateBucketStats(HeapBucketStats& stats);
  115. #endif
  116. uint Rescan(Recycler * recycler, RescanFlags flags);
  117. #if ENABLE_CONCURRENT_GC
  118. void MergeNewHeapBlock(TBlockType * heapBlock);
  119. void PrepareSweep();
  120. void SetupBackgroundSweep(RecyclerSweep& recyclerSweep);
  121. #endif
  122. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  123. friend class ScriptMemoryDumper;
  124. #endif
  125. TBlockAllocatorType * GetAllocator() { return &allocatorHead;}
  126. protected:
  127. static bool const IsLeafBucket = TBlockType::RequiredAttributes == LeafBit;
  128. static bool const IsFinalizableBucket = TBlockType::RequiredAttributes == FinalizeBit;
  129. static bool const IsNormalBucket = TBlockType::RequiredAttributes == NoBit;
  130. #ifdef RECYCLER_WRITE_BARRIER
  131. static bool const IsWriteBarrierBucket = TBlockType::RequiredAttributes == WithBarrierBit;
  132. static bool const IsFinalizableWriteBarrierBucket = TBlockType::RequiredAttributes == FinalizableWithBarrierBit;
  133. #endif
  134. void Initialize(HeapInfo * heapInfo, __declspec(guard(overflow)) uint sizeCat);
  135. void AppendAllocableHeapBlockList(TBlockType * list);
  136. void DeleteHeapBlockList(TBlockType * list);
  137. static void DeleteEmptyHeapBlockList(TBlockType * list);
  138. static void DeleteHeapBlockList(TBlockType * list, Recycler * recycler);
  139. // Small allocators
  140. void UpdateAllocators();
  141. void ClearAllocators();
  142. void AddAllocator(TBlockAllocatorType * allocator);
  143. void RemoveAllocator(TBlockAllocatorType * allocator);
  144. static void ClearAllocator(TBlockAllocatorType * allocator);
  145. template <class Fn> void ForEachAllocator(Fn fn);
  146. // Allocations
  147. char * TryAllocFromNewHeapBlock(Recycler * recycler, TBlockAllocatorType * allocator, __declspec(guard(overflow)) size_t sizeCat, size_t size, ObjectInfoBits attributes);
  148. char * TryAlloc(Recycler * recycler, TBlockAllocatorType * allocator, __declspec(guard(overflow)) size_t sizeCat, ObjectInfoBits attributes);
  149. TBlockType * CreateHeapBlock(Recycler * recycler);
  150. TBlockType * GetUnusedHeapBlock();
  151. void FreeHeapBlock(TBlockType * heapBlock);
  152. // GC
  153. void SweepBucket(RecyclerSweep& recyclerSweep);
  154. template <typename Fn>
  155. void SweepBucket(RecyclerSweep& recyclerSweep, Fn sweepFn);
  156. void StopAllocationBeforeSweep();
  157. void StartAllocationAfterSweep();
  158. #if DBG
  159. bool IsAllocationStopped() const;
  160. #endif
  161. void SweepHeapBlockList(RecyclerSweep& recyclerSweep, TBlockType * heapBlockList, bool allocable);
  162. #if ENABLE_PARTIAL_GC
  163. bool DoQueuePendingSweep(Recycler * recycler);
  164. bool DoPartialReuseSweep(Recycler * recycler);
  165. #endif
  166. // Partial/Concurrent GC
  167. void EnumerateObjects(ObjectInfoBits infoBits, void (*CallBackFunction)(void * address, size_t size));
  168. #if DBG
  169. bool AllocatorsAreEmpty() const;
  170. bool HasPendingDisposeHeapBlocks() const;
  171. static void VerifyBlockConsistencyInList(TBlockType * heapBlock, RecyclerVerifyListConsistencyData& recyclerSweep);
  172. static void VerifyBlockConsistencyInList(TBlockType * heapBlock, RecyclerVerifyListConsistencyData const& recyclerSweep, SweepState state);
  173. #endif
  174. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  175. // TODO-REFACTOR: This really should be virtual
  176. size_t GetNonEmptyHeapBlockCount(bool checkCount) const;
  177. size_t GetEmptyHeapBlockCount() const;
  178. #endif
  179. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  180. size_t Check(bool checkCount = true);
  181. void VerifyHeapBlockCount(bool background);
  182. #endif
  183. #ifdef RECYCLER_MEMORY_VERIFY
  184. void Verify();
  185. #endif
  186. #ifdef RECYCLER_VERIFY_MARK
  187. void VerifyMark();
  188. #endif
  189. TBlockAllocatorType allocatorHead;
  190. TBlockType * nextAllocableBlockHead;
  191. TBlockType * emptyBlockList; // list of blocks that is empty and has it's page freed
  192. TBlockType * fullBlockList; // list of blocks that are fully allocated
  193. TBlockType * heapBlockList; // list of blocks that has free objects
  194. FreeObject* explicitFreeList; // List of objects that have been explicitly freed
  195. TBlockAllocatorType * lastExplicitFreeListAllocator;
  196. #ifdef RECYCLER_PAGE_HEAP
  197. SmallHeapBlock* explicitFreeLockBlockList; // List of heap blocks which have been locked upon explicit free
  198. #endif
  199. #if DBG
  200. bool isAllocationStopped; // whether the bucket is the middle of sweeping, not including partial sweeping
  201. #endif
  202. template <class TBlockAttributes>
  203. friend class HeapBucketGroup;
  204. friend class HeapInfo;
  205. friend typename TBlockType;
  206. template <class TBucketAttributes>
  207. friend class SmallHeapBlockT;
  208. friend class RecyclerSweep;
  209. };
  210. template <typename TBlockType>
  211. void
  212. HeapBucket::EnumerateObjects(TBlockType * heapBlockList, ObjectInfoBits infoBits, void (*CallBackFunction)(void * address, size_t size))
  213. {
  214. HeapBlockList::ForEach(heapBlockList, [=](TBlockType * heapBlock)
  215. {
  216. heapBlock->EnumerateObjects(infoBits, CallBackFunction);
  217. });
  218. }
  219. template <typename TBlockType>
  220. template <typename Fn>
  221. void
  222. HeapBucketT<TBlockType>::SweepBucket(RecyclerSweep& recyclerSweep, Fn sweepFn)
  223. {
  224. this->SweepBucket(recyclerSweep);
  225. // Continue to sweep other list from derived class
  226. sweepFn(recyclerSweep);
  227. #if ENABLE_PARTIAL_GC
  228. if (!this->DoPartialReuseSweep(recyclerSweep.GetRecycler()))
  229. #endif
  230. {
  231. #if ENABLE_CONCURRENT_GC
  232. // We should only queue up pending sweep if we are doing partial collect
  233. Assert(recyclerSweep.GetPendingSweepBlockList(this) == nullptr);
  234. #endif
  235. // Every thing is swept immediately in non partial collect, so we can allocate
  236. // from the heap block list now
  237. StartAllocationAfterSweep();
  238. }
  239. RECYCLER_SLOW_CHECK(this->VerifyHeapBlockCount(recyclerSweep.IsBackground()));
  240. }
  241. }