HeapBucket.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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. bool hasSetupVerifyListConsistencyData;
  21. SmallHeapBlockT<TBlockAttributes> * nextAllocableBlockHead;
  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 GetSizeCat() const;
  59. uint GetBucketIndex() const;
  60. uint GetMediumBucketIndex() const;
  61. template <typename TBlockType>
  62. static void EnumerateObjects(TBlockType * heapBlockList, ObjectInfoBits infoBits, void(*CallBackFunction)(void * address, size_t size));
  63. protected:
  64. HeapInfo * heapInfo;
  65. uint sizeCat;
  66. #if ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP
  67. bool allocationsStartedDuringConcurrentSweep;
  68. bool concurrentSweepAllocationsThresholdExceeded;
  69. #endif
  70. #if defined(RECYCLER_SLOW_CHECK_ENABLED) || ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP
  71. uint32 heapBlockCount;
  72. uint32 newHeapBlockCount; // count of heap bock that is in the heap info and not in the heap bucket yet
  73. #endif
  74. #if defined(RECYCLER_SLOW_CHECK_ENABLED)
  75. uint32 emptyHeapBlockCount;
  76. #endif
  77. #ifdef RECYCLER_PAGE_HEAP
  78. protected:
  79. bool isPageHeapEnabled;
  80. public:
  81. inline bool IsPageHeapEnabled(ObjectInfoBits attributes) const
  82. {
  83. // LargeHeapBlock does not support TrackBit today
  84. return isPageHeapEnabled && ((attributes & ClientTrackableObjectBits) == 0);
  85. }
  86. #endif
  87. #if ENABLE_MEM_STATS
  88. protected:
  89. HeapBucketStats memStats; // mem stats per bucket
  90. public:
  91. const HeapBucketStats& GetMemStats() const { return memStats; }
  92. template <typename TBlockType>
  93. void PreAggregateBucketStats(TBlockType* heapBlock)
  94. {
  95. Assert(heapBlock->heapBucket == this);
  96. memStats.PreAggregate();
  97. heapBlock->AggregateBlockStats(memStats);
  98. }
  99. void AggregateBucketStats()
  100. {
  101. memStats.BeginAggregate(); // Begin aggregate, clear if needed
  102. }
  103. #endif
  104. Recycler * GetRecycler() const;
  105. bool AllocationsStartedDuringConcurrentSweep() const;
  106. #if ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP
  107. bool ConcurrentSweepAllocationsThresholdExceeded() const;
  108. bool DoTwoPassConcurrentSweepPreCheck();
  109. #endif
  110. template <typename TBlockType>
  111. friend class SmallHeapBlockAllocator;
  112. template <typename TBlockAttributes>
  113. friend class SmallHeapBlockT;
  114. template <typename TBlockAttributes>
  115. friend class SmallFinalizableHeapBlockT;
  116. #ifdef RECYCLER_VISITED_HOST
  117. template <typename TBlockAttributes>
  118. friend class SmallRecyclerVisitedHostHeapBlockT;
  119. #endif
  120. friend class LargeHeapBlock;
  121. #ifdef RECYCLER_WRITE_BARRIER
  122. template <typename TBlockAttributes>
  123. friend class SmallFinalizableWithBarrierHeapBlockT;
  124. template <typename TBlockAttributes>
  125. friend class SmallNormalWithBarrierHeapBlockT;
  126. #endif
  127. };
  128. template <typename TBlockType>
  129. class HeapBucketT : public HeapBucket
  130. {
  131. typedef SmallHeapBlockAllocator<TBlockType> TBlockAllocatorType;
  132. public:
  133. HeapBucketT();
  134. ~HeapBucketT();
  135. bool IntegrateBlock(char * blockAddress, PageSegment * segment, Recycler * recycler);
  136. template <ObjectInfoBits attributes, bool nothrow>
  137. inline char * RealAlloc(Recycler * recycler, size_t sizeCat, size_t size);
  138. #ifdef RECYCLER_PAGE_HEAP
  139. char * PageHeapAlloc(Recycler * recycler, DECLSPEC_GUARD_OVERFLOW size_t sizeCat, size_t size, ObjectInfoBits attributes, PageHeapMode mode, bool nothrow);
  140. #endif
  141. void ExplicitFree(void* object, size_t sizeCat);
  142. char * SnailAlloc(Recycler * recycler, TBlockAllocatorType * allocator, DECLSPEC_GUARD_OVERFLOW size_t sizeCat, size_t size, ObjectInfoBits attributes, bool nothrow);
  143. void ResetMarks(ResetMarkFlags flags);
  144. void ScanNewImplicitRoots(Recycler * recycler);
  145. #if ENABLE_MEM_STATS
  146. void AggregateBucketStats();
  147. #endif
  148. uint Rescan(Recycler * recycler, RescanFlags flags);
  149. #if ENABLE_CONCURRENT_GC
  150. void MergeNewHeapBlock(TBlockType * heapBlock);
  151. void PrepareSweep();
  152. void SetupBackgroundSweep(RecyclerSweep& recyclerSweep);
  153. #endif
  154. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  155. friend class ::ScriptMemoryDumper;
  156. #endif
  157. static bool IsAnyFinalizableBucket()
  158. {
  159. return IsFinalizableBucket
  160. #ifdef RECYCLER_WRITE_BARRIER
  161. || IsFinalizableWriteBarrierBucket
  162. #endif
  163. ;
  164. }
  165. TBlockAllocatorType * GetAllocator() { return &allocatorHead;}
  166. static unsigned int GetAllocatorHeadOffset() { return offsetof(HeapBucketT<TBlockType>, allocatorHead); }
  167. protected:
  168. static bool const IsLeafBucket = TBlockType::RequiredAttributes == LeafBit;
  169. // Not all objects in the recycler visited host heap block are finalizable, but we still require finalizable semantics
  170. static bool const IsFinalizableBucket = TBlockType::RequiredAttributes == FinalizeBit
  171. #ifdef RECYCLER_VISITED_HOST
  172. || ((TBlockType::RequiredAttributes & RecyclerVisitedHostBit) == (RecyclerVisitedHostBit))
  173. #endif
  174. ;
  175. static bool const IsNormalBucket = TBlockType::RequiredAttributes == NoBit;
  176. #ifdef RECYCLER_WRITE_BARRIER
  177. static bool const IsWriteBarrierBucket = TBlockType::RequiredAttributes == WithBarrierBit;
  178. static bool const IsFinalizableWriteBarrierBucket = TBlockType::RequiredAttributes == FinalizableWithBarrierBit;
  179. #endif
  180. void Initialize(HeapInfo * heapInfo, DECLSPEC_GUARD_OVERFLOW uint sizeCat);
  181. void AppendAllocableHeapBlockList(TBlockType * list);
  182. #if ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP
  183. void EnsureAllocableHeapBlockList();
  184. void FinishSweepPrep(RecyclerSweep& recyclerSweep);
  185. void FinishConcurrentSweepPass1(RecyclerSweep& recyclerSweep);
  186. void FinishConcurrentSweep();
  187. #endif
  188. void DeleteHeapBlockList(TBlockType * list);
  189. static void DeleteEmptyHeapBlockList(TBlockType * list);
  190. static void DeleteHeapBlockList(TBlockType * list, Recycler * recycler);
  191. #if ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP && SUPPORT_WIN32_SLIST
  192. static bool PushHeapBlockToSList(PSLIST_HEADER list, TBlockType * heapBlock);
  193. static TBlockType * PopHeapBlockFromSList(PSLIST_HEADER list);
  194. static ushort QueryDepthInterlockedSList(PSLIST_HEADER list);
  195. static void FlushInterlockedSList(PSLIST_HEADER list);
  196. #endif
  197. // Small allocators
  198. void UpdateAllocators();
  199. void ClearAllocators();
  200. void AddAllocator(TBlockAllocatorType * allocator);
  201. void RemoveAllocator(TBlockAllocatorType * allocator);
  202. static void ClearAllocator(TBlockAllocatorType * allocator);
  203. template <class Fn> void ForEachAllocator(Fn fn);
  204. // Allocations
  205. char * TryAllocFromNewHeapBlock(Recycler * recycler, TBlockAllocatorType * allocator, DECLSPEC_GUARD_OVERFLOW size_t sizeCat, size_t size, ObjectInfoBits attributes);
  206. char * TryAlloc(Recycler * recycler, TBlockAllocatorType * allocator, DECLSPEC_GUARD_OVERFLOW size_t sizeCat, ObjectInfoBits attributes);
  207. TBlockType * CreateHeapBlock(Recycler * recycler);
  208. TBlockType * GetUnusedHeapBlock();
  209. void FreeHeapBlock(TBlockType * heapBlock);
  210. // GC
  211. void SweepBucket(RecyclerSweep& recyclerSweep);
  212. template <typename Fn>
  213. void SweepBucket(RecyclerSweep& recyclerSweep, Fn sweepFn);
  214. #if ENABLE_CONCURRENT_GC && ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP
  215. void PrepareForAllocationsDuringConcurrentSweep(TBlockType * &currentHeapBlockList);
  216. void StartAllocationDuringConcurrentSweep();
  217. void ResumeNormalAllocationAfterConcurrentSweep(TBlockType * newNextAllocableBlockHead = nullptr);
  218. #endif
  219. bool AllowAllocationsDuringConcurrentSweep();
  220. void StopAllocationBeforeSweep();
  221. void StartAllocationAfterSweep();
  222. bool IsAllocationStopped() const;
  223. void SweepHeapBlockList(RecyclerSweep& recyclerSweep, TBlockType * heapBlockList, bool allocable);
  224. #if ENABLE_PARTIAL_GC
  225. bool DoQueuePendingSweep(Recycler * recycler);
  226. bool DoPartialReuseSweep(Recycler * recycler);
  227. #endif
  228. // Partial/Concurrent GC
  229. void EnumerateObjects(ObjectInfoBits infoBits, void (*CallBackFunction)(void * address, size_t size));
  230. void AssertCheckHeapBlockNotInAnyList(TBlockType * heapBlock);
  231. #if DBG
  232. bool AllocatorsAreEmpty() const;
  233. bool HasPendingDisposeHeapBlocks() const;
  234. static void VerifyBlockConsistencyInList(TBlockType * heapBlock, RecyclerVerifyListConsistencyData& recyclerSweep);
  235. static void VerifyBlockConsistencyInList(TBlockType * heapBlock, RecyclerVerifyListConsistencyData const& recyclerSweep, SweepState state);
  236. #endif
  237. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  238. // TODO-REFACTOR: This really should be virtual
  239. size_t GetNonEmptyHeapBlockCount(bool checkCount) const;
  240. size_t GetEmptyHeapBlockCount() const;
  241. #endif
  242. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  243. size_t Check(bool checkCount = true);
  244. void VerifyHeapBlockCount(bool background);
  245. #endif
  246. #ifdef RECYCLER_MEMORY_VERIFY
  247. void Verify();
  248. #endif
  249. #ifdef RECYCLER_VERIFY_MARK
  250. void VerifyMark();
  251. #endif
  252. TBlockAllocatorType allocatorHead;
  253. TBlockType * nextAllocableBlockHead;
  254. TBlockType * emptyBlockList; // list of blocks that is empty and has it's page freed
  255. TBlockType * fullBlockList; // list of blocks that are fully allocated
  256. TBlockType * heapBlockList; // list of blocks that has free objects
  257. #if ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP
  258. #if SUPPORT_WIN32_SLIST
  259. PSLIST_HEADER allocableHeapBlockListHead;
  260. TBlockType * lastKnownNextAllocableBlockHead;
  261. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  262. // This lock is needed only in the debug mode while we verify block counts. Not needed otherwise, as this list is never accessed concurrently.
  263. // Items are added to it by the allocator when allocations are allowed during concurrent sweep. The list is drained during the next sweep while
  264. // allocation are stopped.
  265. mutable CriticalSection debugSweepableHeapBlockListLock;
  266. #endif
  267. // This is the list of blocks that we allocated from during concurrent sweep. These blocks will eventually get processed during the next sweep and either go into
  268. // the fullBlockList.
  269. TBlockType * sweepableHeapBlockList;
  270. #endif
  271. #endif
  272. FreeObject* explicitFreeList; // List of objects that have been explicitly freed
  273. TBlockAllocatorType * lastExplicitFreeListAllocator;
  274. #ifdef RECYCLER_PAGE_HEAP
  275. SmallHeapBlock* explicitFreeLockBlockList; // List of heap blocks which have been locked upon explicit free
  276. #endif
  277. bool isAllocationStopped; // whether the bucket has it's allocations stopped
  278. template <class TBlockAttributes>
  279. friend class HeapBucketGroup;
  280. friend class HeapInfo;
  281. friend TBlockType;
  282. template <class TBucketAttributes>
  283. friend class SmallHeapBlockT;
  284. friend class RecyclerSweep;
  285. };
  286. template <typename TBlockType>
  287. void
  288. HeapBucket::EnumerateObjects(TBlockType * heapBlockList, ObjectInfoBits infoBits, void (*CallBackFunction)(void * address, size_t size))
  289. {
  290. HeapBlockList::ForEach(heapBlockList, [=](TBlockType * heapBlock)
  291. {
  292. heapBlock->EnumerateObjects(infoBits, CallBackFunction);
  293. });
  294. }
  295. template <typename TBlockType>
  296. template <typename Fn>
  297. void
  298. HeapBucketT<TBlockType>::SweepBucket(RecyclerSweep& recyclerSweep, Fn sweepFn)
  299. {
  300. this->SweepBucket(recyclerSweep);
  301. // Continue to sweep other list from derived class
  302. sweepFn(recyclerSweep);
  303. #if ENABLE_PARTIAL_GC
  304. if (!this->DoPartialReuseSweep(recyclerSweep.GetRecycler()))
  305. #endif
  306. {
  307. #if ENABLE_CONCURRENT_GC
  308. // We should only queue up pending sweep if we are doing partial collect
  309. Assert(recyclerSweep.GetPendingSweepBlockList(this) == nullptr);
  310. #if ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP && SUPPORT_WIN32_SLIST
  311. if (!this->AllocationsStartedDuringConcurrentSweep())
  312. #endif
  313. #endif
  314. {
  315. // Every thing is swept immediately in non partial collect, so we can allocate
  316. // from the heap block list now
  317. StartAllocationAfterSweep();
  318. }
  319. }
  320. RECYCLER_SLOW_CHECK(this->VerifyHeapBlockCount(recyclerSweep.IsBackground()));
  321. }
  322. }