HeapBucket.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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. template <typename TBlockType>
  61. static void EnumerateObjects(TBlockType * heapBlockList, ObjectInfoBits infoBits, void(*CallBackFunction)(void * address, size_t size));
  62. protected:
  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. inline 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 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. static unsigned int GetAllocatorHeadOffset() { return offsetof(HeapBucketT<TBlockType>, allocatorHead); }
  127. protected:
  128. static bool const IsLeafBucket = TBlockType::RequiredAttributes == LeafBit;
  129. static bool const IsFinalizableBucket = TBlockType::RequiredAttributes == FinalizeBit;
  130. static bool const IsNormalBucket = TBlockType::RequiredAttributes == NoBit;
  131. #ifdef RECYCLER_WRITE_BARRIER
  132. static bool const IsWriteBarrierBucket = TBlockType::RequiredAttributes == WithBarrierBit;
  133. static bool const IsFinalizableWriteBarrierBucket = TBlockType::RequiredAttributes == FinalizableWithBarrierBit;
  134. #endif
  135. void Initialize(HeapInfo * heapInfo, DECLSPEC_GUARD_OVERFLOW uint sizeCat);
  136. void AppendAllocableHeapBlockList(TBlockType * list);
  137. void DeleteHeapBlockList(TBlockType * list);
  138. static void DeleteEmptyHeapBlockList(TBlockType * list);
  139. static void DeleteHeapBlockList(TBlockType * list, Recycler * recycler);
  140. // Small allocators
  141. void UpdateAllocators();
  142. void ClearAllocators();
  143. void AddAllocator(TBlockAllocatorType * allocator);
  144. void RemoveAllocator(TBlockAllocatorType * allocator);
  145. static void ClearAllocator(TBlockAllocatorType * allocator);
  146. template <class Fn> void ForEachAllocator(Fn fn);
  147. // Allocations
  148. char * TryAllocFromNewHeapBlock(Recycler * recycler, TBlockAllocatorType * allocator, DECLSPEC_GUARD_OVERFLOW size_t sizeCat, size_t size, ObjectInfoBits attributes);
  149. char * TryAlloc(Recycler * recycler, TBlockAllocatorType * allocator, DECLSPEC_GUARD_OVERFLOW size_t sizeCat, ObjectInfoBits attributes);
  150. TBlockType * CreateHeapBlock(Recycler * recycler);
  151. TBlockType * GetUnusedHeapBlock();
  152. void FreeHeapBlock(TBlockType * heapBlock);
  153. // GC
  154. void SweepBucket(RecyclerSweep& recyclerSweep);
  155. template <typename Fn>
  156. void SweepBucket(RecyclerSweep& recyclerSweep, Fn sweepFn);
  157. void StopAllocationBeforeSweep();
  158. void StartAllocationAfterSweep();
  159. #if DBG
  160. bool IsAllocationStopped() const;
  161. #endif
  162. void SweepHeapBlockList(RecyclerSweep& recyclerSweep, TBlockType * heapBlockList, bool allocable);
  163. #if ENABLE_PARTIAL_GC
  164. bool DoQueuePendingSweep(Recycler * recycler);
  165. bool DoPartialReuseSweep(Recycler * recycler);
  166. #endif
  167. // Partial/Concurrent GC
  168. void EnumerateObjects(ObjectInfoBits infoBits, void (*CallBackFunction)(void * address, size_t size));
  169. #if DBG
  170. bool AllocatorsAreEmpty() const;
  171. bool HasPendingDisposeHeapBlocks() const;
  172. static void VerifyBlockConsistencyInList(TBlockType * heapBlock, RecyclerVerifyListConsistencyData& recyclerSweep);
  173. static void VerifyBlockConsistencyInList(TBlockType * heapBlock, RecyclerVerifyListConsistencyData const& recyclerSweep, SweepState state);
  174. #endif
  175. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  176. // TODO-REFACTOR: This really should be virtual
  177. size_t GetNonEmptyHeapBlockCount(bool checkCount) const;
  178. size_t GetEmptyHeapBlockCount() const;
  179. #endif
  180. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  181. size_t Check(bool checkCount = true);
  182. void VerifyHeapBlockCount(bool background);
  183. #endif
  184. #ifdef RECYCLER_MEMORY_VERIFY
  185. void Verify();
  186. #endif
  187. #ifdef RECYCLER_VERIFY_MARK
  188. void VerifyMark();
  189. #endif
  190. TBlockAllocatorType allocatorHead;
  191. TBlockType * nextAllocableBlockHead;
  192. TBlockType * emptyBlockList; // list of blocks that is empty and has it's page freed
  193. TBlockType * fullBlockList; // list of blocks that are fully allocated
  194. TBlockType * heapBlockList; // list of blocks that has free objects
  195. FreeObject* explicitFreeList; // List of objects that have been explicitly freed
  196. TBlockAllocatorType * lastExplicitFreeListAllocator;
  197. #ifdef RECYCLER_PAGE_HEAP
  198. SmallHeapBlock* explicitFreeLockBlockList; // List of heap blocks which have been locked upon explicit free
  199. #endif
  200. #if DBG
  201. bool isAllocationStopped; // whether the bucket is the middle of sweeping, not including partial sweeping
  202. #endif
  203. template <class TBlockAttributes>
  204. friend class HeapBucketGroup;
  205. friend class HeapInfo;
  206. friend TBlockType;
  207. template <class TBucketAttributes>
  208. friend class SmallHeapBlockT;
  209. friend class RecyclerSweep;
  210. };
  211. template <typename TBlockType>
  212. void
  213. HeapBucket::EnumerateObjects(TBlockType * heapBlockList, ObjectInfoBits infoBits, void (*CallBackFunction)(void * address, size_t size))
  214. {
  215. HeapBlockList::ForEach(heapBlockList, [=](TBlockType * heapBlock)
  216. {
  217. heapBlock->EnumerateObjects(infoBits, CallBackFunction);
  218. });
  219. }
  220. template <typename TBlockType>
  221. template <typename Fn>
  222. void
  223. HeapBucketT<TBlockType>::SweepBucket(RecyclerSweep& recyclerSweep, Fn sweepFn)
  224. {
  225. this->SweepBucket(recyclerSweep);
  226. // Continue to sweep other list from derived class
  227. sweepFn(recyclerSweep);
  228. #if ENABLE_PARTIAL_GC
  229. if (!this->DoPartialReuseSweep(recyclerSweep.GetRecycler()))
  230. #endif
  231. {
  232. #if ENABLE_CONCURRENT_GC
  233. // We should only queue up pending sweep if we are doing partial collect
  234. Assert(recyclerSweep.GetPendingSweepBlockList(this) == nullptr);
  235. #endif
  236. // Every thing is swept immediately in non partial collect, so we can allocate
  237. // from the heap block list now
  238. StartAllocationAfterSweep();
  239. }
  240. RECYCLER_SLOW_CHECK(this->VerifyHeapBlockCount(recyclerSweep.IsBackground()));
  241. }
  242. }