HeapInfo.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  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. namespace Memory
  6. {
  7. class HeapInfo
  8. {
  9. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  10. friend class ScriptMemoryDumper;
  11. #endif
  12. public:
  13. HeapInfo();
  14. ~HeapInfo();
  15. void Initialize(Recycler * recycler
  16. #ifdef RECYCLER_PAGE_HEAP
  17. , PageHeapMode pageheapmode = PageHeapMode::PageHeapModeOff
  18. , bool captureAllocCallStack = false
  19. , bool captureFreeCallStack = false
  20. #endif
  21. );
  22. #if defined(PROFILE_RECYCLER_ALLOC) || defined(RECYCLER_MEMORY_VERIFY) || defined(MEMSPECT_TRACKING) || defined(ETW_MEMORY_TRACKING)
  23. void Initialize(Recycler * recycler, void(*trackNativeAllocCallBack)(Recycler *, void *, size_t)
  24. #ifdef RECYCLER_PAGE_HEAP
  25. , PageHeapMode pageheapmode = PageHeapMode::PageHeapModeOff
  26. , bool captureAllocCallStack = false
  27. , bool captureFreeCallStack = false
  28. #endif
  29. );
  30. #endif
  31. void ResetMarks(ResetMarkFlags flags);
  32. void EnumerateObjects(ObjectInfoBits infoBits, void(*CallBackFunction)(void * address, size_t size));
  33. #ifdef RECYCLER_PAGE_HEAP
  34. bool IsPageHeapEnabled() const{ return isPageHeapEnabled; }
  35. static size_t RoundObjectSize(size_t objectSize)
  36. {
  37. // triming off the tail part which is not a pointer
  38. return objectSize - (objectSize % sizeof(void*));
  39. }
  40. template <typename TBlockAttributes>
  41. bool IsPageHeapEnabledForBlock(const size_t objectSize);
  42. #else
  43. const bool IsPageHeapEnabled() const{ return false; }
  44. #endif
  45. #ifdef DUMP_FRAGMENTATION_STATS
  46. void DumpFragmentationStats();
  47. #endif
  48. template <ObjectInfoBits attributes, bool nothrow>
  49. char * MediumAlloc(Recycler * recycler, size_t sizeCat, size_t size);
  50. // Small allocator
  51. template <ObjectInfoBits attributes, bool nothrow>
  52. char * RealAlloc(Recycler * recycler, size_t sizeCat, size_t size);
  53. template <ObjectInfoBits attributes>
  54. bool IntegrateBlock(char * blockAddress, PageSegment * segment, Recycler * recycler, size_t sizeCat);
  55. template <typename SmallHeapBlockAllocatorType>
  56. void AddSmallAllocator(SmallHeapBlockAllocatorType * allocator, size_t sizeCat);
  57. template <typename SmallHeapBlockAllocatorType>
  58. void RemoveSmallAllocator(SmallHeapBlockAllocatorType * allocator, size_t sizeCat);
  59. template <ObjectInfoBits attributes, typename SmallHeapBlockAllocatorType>
  60. char * SmallAllocatorAlloc(Recycler * recycler, SmallHeapBlockAllocatorType * allocator, size_t sizeCat, size_t size);
  61. // collection functions
  62. void ScanInitialImplicitRoots();
  63. void ScanNewImplicitRoots();
  64. size_t Rescan(RescanFlags flags);
  65. #if ENABLE_PARTIAL_GC || ENABLE_CONCURRENT_GC
  66. void SweepPendingObjects(RecyclerSweep& recyclerSweep);
  67. #endif
  68. void Sweep(RecyclerSweep& recyclerSweep, bool concurrent);
  69. template <ObjectInfoBits attributes>
  70. void FreeSmallObject(void* object, size_t bytes);
  71. template <ObjectInfoBits attributes>
  72. void FreeMediumObject(void* object, size_t bytes);
  73. #if ENABLE_PARTIAL_GC
  74. void SweepPartialReusePages(RecyclerSweep& recyclerSweep);
  75. void FinishPartialCollect(RecyclerSweep * recyclerSweep);
  76. #endif
  77. #if ENABLE_CONCURRENT_GC
  78. void PrepareSweep();
  79. void TransferPendingHeapBlocks(RecyclerSweep& recyclerSweep);
  80. void ConcurrentTransferSweptObjects(RecyclerSweep& recyclerSweep);
  81. #if ENABLE_PARTIAL_GC
  82. void ConcurrentPartialTransferSweptObjects(RecyclerSweep& recyclerSweep);
  83. #endif
  84. #endif
  85. void DisposeObjects();
  86. void TransferDisposedObjects();
  87. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  88. void Check();
  89. template <typename TBlockType>
  90. static size_t Check(bool expectFull, bool expectPending, TBlockType * list, TBlockType * tail = nullptr);
  91. void VerifySmallHeapBlockCount();
  92. void VerifyLargeHeapBlockCount();
  93. #endif
  94. #ifdef RECYCLER_MEMORY_VERIFY
  95. void Verify();
  96. #endif
  97. #ifdef RECYCLER_VERIFY_MARK
  98. void VerifyMark();
  99. #endif
  100. public:
  101. static bool IsSmallObject(size_t nBytes) { return nBytes <= HeapConstants::MaxSmallObjectSize; }
  102. static bool IsMediumObject(size_t nBytes)
  103. {
  104. #ifdef BUCKETIZE_MEDIUM_ALLOCATIONS
  105. return nBytes > HeapConstants::MaxSmallObjectSize && nBytes <= HeapConstants::MaxMediumObjectSize;
  106. #else
  107. return false;
  108. #endif
  109. }
  110. static bool IsSmallBlockAllocation(size_t nBytes)
  111. {
  112. #if SMALLBLOCK_MEDIUM_ALLOC
  113. return HeapInfo::IsSmallObject(nBytes) || HeapInfo::IsMediumObject(nBytes);
  114. #else
  115. return HeapInfo::IsSmallObject(nBytes);
  116. #endif
  117. }
  118. static bool IsLargeObject(size_t nBytes)
  119. {
  120. #ifdef BUCKETIZE_MEDIUM_ALLOCATIONS
  121. return nBytes > HeapConstants::MaxMediumObjectSize;
  122. #else
  123. return nBytes > HeapConstants::MaxSmallObjectSize;
  124. #endif
  125. }
  126. static BOOL IsAlignedSize(size_t sizeCat) { return (sizeCat != 0) && (0 == (sizeCat & HeapInfo::ObjectAlignmentMask)); }
  127. static BOOL IsAlignedSmallObjectSize(size_t sizeCat) { return (sizeCat != 0) && (HeapInfo::IsSmallObject(sizeCat) && (0 == (sizeCat & HeapInfo::ObjectAlignmentMask))); }
  128. static BOOL IsAlignedMediumObjectSize(size_t sizeCat) { return (sizeCat != 0) && (HeapInfo::IsMediumObject(sizeCat) && (0 == (sizeCat & HeapInfo::ObjectAlignmentMask))); }
  129. static size_t GetAlignedSize(size_t size) { return AllocSizeMath::Align(size, HeapConstants::ObjectGranularity); }
  130. static size_t GetAlignedSizeNoCheck(size_t size) { return Math::Align<size_t>(size, HeapConstants::ObjectGranularity); }
  131. #ifdef BUCKETIZE_MEDIUM_ALLOCATIONS
  132. static size_t GetMediumObjectAlignedSize(size_t size) { return AllocSizeMath::Align(size, HeapConstants::MediumObjectGranularity); }
  133. static size_t GetMediumObjectAlignedSizeNoCheck(size_t size) { return Math::Align<size_t>(size, HeapConstants::MediumObjectGranularity); }
  134. #endif
  135. static uint GetBucketIndex(size_t sizeCat) { Assert(IsAlignedSmallObjectSize(sizeCat)); return (uint)(sizeCat >> HeapConstants::ObjectAllocationShift) - 1; }
  136. template <typename TBlockAttributes>
  137. static uint GetObjectSizeForBucketIndex(uint bucketIndex) { return (bucketIndex + 1) << HeapConstants::ObjectAllocationShift; }
  138. #ifdef BUCKETIZE_MEDIUM_ALLOCATIONS
  139. static uint GetMediumBucketIndex(size_t sizeCat) { Assert(IsAlignedMediumObjectSize(sizeCat)); return (uint)((sizeCat - HeapConstants::MaxSmallObjectSize - 1) / HeapConstants::MediumObjectGranularity); }
  140. template <>
  141. static uint GetObjectSizeForBucketIndex<MediumAllocationBlockAttributes>(uint bucketIndex)
  142. {
  143. Assert(IsMediumObject(HeapConstants::MaxSmallObjectSize + ((bucketIndex + 1) * HeapConstants::MediumObjectGranularity)));
  144. return HeapConstants::MaxSmallObjectSize + ((bucketIndex + 1) * HeapConstants::MediumObjectGranularity);
  145. }
  146. #endif
  147. static BOOL IsAlignedAddress(void * address) { return (0 == (((size_t)address) & HeapInfo::ObjectAlignmentMask)); }
  148. private:
  149. template <ObjectInfoBits attributes>
  150. typename SmallHeapBlockType<attributes, SmallAllocationBlockAttributes>::BucketType& GetBucket(size_t sizeCat);
  151. void SweepBuckets(RecyclerSweep& recyclerSweep, bool concurrent);
  152. #ifdef BUCKETIZE_MEDIUM_ALLOCATIONS
  153. #if SMALLBLOCK_MEDIUM_ALLOC
  154. template <ObjectInfoBits attributes>
  155. typename SmallHeapBlockType<attributes, MediumAllocationBlockAttributes>::BucketType& GetMediumBucket(size_t sizeCat);
  156. #else
  157. LargeHeapBucket& GetMediumBucket(size_t sizeCat);
  158. #endif
  159. #endif
  160. LargeHeapBlock * AddLargeHeapBlock(size_t pageCount);
  161. template <typename TBlockType>
  162. void AppendNewHeapBlock(TBlockType * heapBlock, HeapBucketT<TBlockType> * heapBucket)
  163. {
  164. TBlockType *& list = this->GetNewHeapBlockList<TBlockType>(heapBucket);
  165. heapBlock->SetNextBlock(list);
  166. list = heapBlock;
  167. }
  168. #if ENABLE_CONCURRENT_GC
  169. template <typename TBlockType> TBlockType *& GetNewHeapBlockList(HeapBucketT<TBlockType> * heapBucket);
  170. template <>
  171. SmallLeafHeapBlock *& GetNewHeapBlockList<SmallLeafHeapBlock>(HeapBucketT<SmallLeafHeapBlock> * heapBucket)
  172. {
  173. return this->newLeafHeapBlockList;
  174. }
  175. template <>
  176. SmallNormalHeapBlock *& GetNewHeapBlockList<SmallNormalHeapBlock>(HeapBucketT<SmallNormalHeapBlock> * heapBucket)
  177. {
  178. return this->newNormalHeapBlockList;
  179. }
  180. template <>
  181. SmallFinalizableHeapBlock *& GetNewHeapBlockList<SmallFinalizableHeapBlock>(HeapBucketT<SmallFinalizableHeapBlock> * heapBucket)
  182. {
  183. // Even though we don't concurrent sweep finalizable heap block, the background thread may
  184. // find some partial swept block to be reused, thus modifying the heapBlockList in the background
  185. // so new block can't go into heapBlockList
  186. return this->newFinalizableHeapBlockList;
  187. }
  188. #ifdef RECYCLER_WRITE_BARRIER
  189. template <>
  190. SmallNormalWithBarrierHeapBlock *& GetNewHeapBlockList<SmallNormalWithBarrierHeapBlock>(HeapBucketT<SmallNormalWithBarrierHeapBlock> * heapBucket)
  191. {
  192. return this->newNormalWithBarrierHeapBlockList;
  193. }
  194. template <>
  195. SmallFinalizableWithBarrierHeapBlock *& GetNewHeapBlockList<SmallFinalizableWithBarrierHeapBlock>(HeapBucketT<SmallFinalizableWithBarrierHeapBlock> * heapBucket)
  196. {
  197. return this->newFinalizableWithBarrierHeapBlockList;
  198. }
  199. #endif
  200. template <>
  201. MediumLeafHeapBlock *& GetNewHeapBlockList<MediumLeafHeapBlock>(HeapBucketT<MediumLeafHeapBlock> * heapBucket)
  202. {
  203. return this->newMediumLeafHeapBlockList;
  204. }
  205. template <>
  206. MediumNormalHeapBlock *& GetNewHeapBlockList<MediumNormalHeapBlock>(HeapBucketT<MediumNormalHeapBlock> * heapBucket)
  207. {
  208. return this->newMediumNormalHeapBlockList;
  209. }
  210. template <>
  211. MediumFinalizableHeapBlock *& GetNewHeapBlockList<MediumFinalizableHeapBlock>(HeapBucketT<MediumFinalizableHeapBlock> * heapBucket)
  212. {
  213. // Even though we don't concurrent sweep finalizable heap block, the background thread may
  214. // find some partial swept block to be reused, thus modifying the heapBlockList in the background
  215. // so new block can't go into heapBlockList
  216. return this->newMediumFinalizableHeapBlockList;
  217. }
  218. #ifdef RECYCLER_WRITE_BARRIER
  219. template <>
  220. MediumNormalWithBarrierHeapBlock *& GetNewHeapBlockList<MediumNormalWithBarrierHeapBlock>(HeapBucketT<MediumNormalWithBarrierHeapBlock> * heapBucket)
  221. {
  222. return this->newMediumNormalWithBarrierHeapBlockList;
  223. }
  224. template <>
  225. MediumFinalizableWithBarrierHeapBlock *& GetNewHeapBlockList<MediumFinalizableWithBarrierHeapBlock>(HeapBucketT<MediumFinalizableWithBarrierHeapBlock> * heapBucket)
  226. {
  227. return this->newMediumFinalizableWithBarrierHeapBlockList;
  228. }
  229. #endif
  230. void SetupBackgroundSweep(RecyclerSweep& recyclerSweep);
  231. #else
  232. template <typename TBlockType> TBlockType *& GetNewHeapBlockList(HeapBucketT<TBlockType> * heapBucket)
  233. {
  234. return heapBucket->heapBlockList;
  235. }
  236. #endif
  237. void SweepSmallNonFinalizable(RecyclerSweep& recyclerSweep);
  238. void SweepLargeNonFinalizable(RecyclerSweep& recyclerSweep);
  239. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  240. size_t GetSmallHeapBlockCount(bool checkCount = false) const;
  241. size_t GetLargeHeapBlockCount(bool checkCount = false) const;
  242. #endif
  243. #if DBG
  244. bool AllocatorsAreEmpty();
  245. #endif
  246. private:
  247. template <typename TBlockAttributes>
  248. class ValidPointersMap
  249. {
  250. #define USE_STATIC_VPM 1 // Disable to force generation at runtime
  251. private:
  252. static const uint rowSize = TBlockAttributes::MaxSmallObjectCount * 2;
  253. typedef ushort ValidPointersMapRow[rowSize];
  254. typedef ValidPointersMapRow ValidPointersMapTable[TBlockAttributes::BucketCount];
  255. typedef typename SmallHeapBlockT<TBlockAttributes>::SmallHeapBlockBitVector InvalidBitsTable[TBlockAttributes::BucketCount];
  256. typedef typename SmallHeapBlockT<TBlockAttributes>::BlockInfo BlockInfoMapRow[TBlockAttributes::PageCount];
  257. typedef BlockInfoMapRow BlockInfoMapTable[TBlockAttributes::BucketCount];
  258. // Architecture-dependent initialization done in ValidPointersMap/vpm.(32b|64b).h
  259. #if USE_STATIC_VPM
  260. static const
  261. #endif
  262. ValidPointersMapTable validPointersBuffer;
  263. #if USE_STATIC_VPM
  264. static const
  265. #endif
  266. BlockInfoMapTable blockInfoBuffer;
  267. #if USE_STATIC_VPM
  268. static const BVUnit invalidBitsData[TBlockAttributes::BucketCount][SmallHeapBlockT<TBlockAttributes>::SmallHeapBlockBitVector::wordCount];
  269. static const InvalidBitsTable * const invalidBitsBuffers;
  270. #endif
  271. public:
  272. #if !USE_STATIC_VPM
  273. InvalidBitsTable invalidBitsBuffers;
  274. ValidPointersMap() { GenerateValidPointersMap(validPointersBuffer, invalidBitsBuffers, blockInfoBuffer); }
  275. #endif
  276. static void GenerateValidPointersMap(ValidPointersMapTable& validTable, InvalidBitsTable& invalidTable, BlockInfoMapTable& blockInfoTable);
  277. const ValidPointers<TBlockAttributes> GetValidPointersForIndex(uint index) const;
  278. const typename SmallHeapBlockT<TBlockAttributes>::SmallHeapBlockBitVector * GetInvalidBitVector(uint index) const;
  279. const typename SmallHeapBlockT<TBlockAttributes>::BlockInfo * GetBlockInfo(uint index) const;
  280. static HRESULT GenerateValidPointersMapHeader(LPCWSTR vpmFullPath);
  281. static HRESULT GenerateValidPointersMapForBlockType(FILE* file);
  282. };
  283. static ValidPointersMap<SmallAllocationBlockAttributes> smallAllocValidPointersMap;
  284. static ValidPointersMap<MediumAllocationBlockAttributes> mediumAllocValidPointersMap;
  285. public:
  286. static HRESULT GenerateValidPointersMapHeader(LPCWSTR vpmFullPath)
  287. {
  288. return smallAllocValidPointersMap.GenerateValidPointersMapHeader(vpmFullPath);
  289. }
  290. template <typename TBlockAttributes>
  291. static typename SmallHeapBlockT<TBlockAttributes>::SmallHeapBlockBitVector const * GetInvalidBitVector(uint objectSize)
  292. {
  293. return smallAllocValidPointersMap.GetInvalidBitVector(GetBucketIndex(objectSize));
  294. }
  295. template <typename TBlockAttributes>
  296. static typename SmallHeapBlockT<TBlockAttributes>::SmallHeapBlockBitVector const * GetInvalidBitVectorForBucket(uint bucketIndex)
  297. {
  298. return smallAllocValidPointersMap.GetInvalidBitVector(bucketIndex);
  299. }
  300. template <typename TBlockAttributes>
  301. static typename ValidPointers<TBlockAttributes> const GetValidPointersMapForBucket(uint bucketIndex)
  302. {
  303. return smallAllocValidPointersMap.GetValidPointersForIndex(bucketIndex);
  304. }
  305. template <>
  306. static typename SmallHeapBlockT<MediumAllocationBlockAttributes>::SmallHeapBlockBitVector const * GetInvalidBitVector<MediumAllocationBlockAttributes>(uint objectSize)
  307. {
  308. return mediumAllocValidPointersMap.GetInvalidBitVector(GetMediumBucketIndex(objectSize));
  309. }
  310. template <>
  311. static typename SmallHeapBlockT<MediumAllocationBlockAttributes>::SmallHeapBlockBitVector const * GetInvalidBitVectorForBucket<MediumAllocationBlockAttributes>(uint bucketIndex)
  312. {
  313. return mediumAllocValidPointersMap.GetInvalidBitVector(bucketIndex);
  314. }
  315. template <>
  316. static typename ValidPointers<MediumAllocationBlockAttributes> const GetValidPointersMapForBucket<MediumAllocationBlockAttributes>(uint bucketIndex)
  317. {
  318. return mediumAllocValidPointersMap.GetValidPointersForIndex(bucketIndex);
  319. }
  320. Recycler* GetRecycler(){ return recycler; }
  321. template <typename TBlockAttributes>
  322. static typename SmallHeapBlockT<TBlockAttributes>::BlockInfo const * GetBlockInfo(uint objectSize)
  323. {
  324. return smallAllocValidPointersMap.GetBlockInfo(GetBucketIndex(objectSize));
  325. }
  326. template <>
  327. static typename SmallHeapBlockT<MediumAllocationBlockAttributes>::BlockInfo const * GetBlockInfo<MediumAllocationBlockAttributes>(uint objectSize)
  328. {
  329. return mediumAllocValidPointersMap.GetBlockInfo(GetMediumBucketIndex(objectSize));
  330. }
  331. private:
  332. size_t uncollectedAllocBytes;
  333. size_t lastUncollectedAllocBytes;
  334. size_t uncollectedExternalBytes;
  335. uint pendingZeroPageCount;
  336. #if ENABLE_PARTIAL_GC
  337. size_t uncollectedNewPageCount;
  338. size_t unusedPartialCollectFreeBytes;
  339. #endif
  340. Recycler * recycler;
  341. #if ENABLE_CONCURRENT_GC
  342. SmallLeafHeapBlock * newLeafHeapBlockList;
  343. SmallNormalHeapBlock * newNormalHeapBlockList;
  344. SmallFinalizableHeapBlock * newFinalizableHeapBlockList;
  345. #ifdef RECYCLER_WRITE_BARRIER
  346. SmallNormalWithBarrierHeapBlock * newNormalWithBarrierHeapBlockList;
  347. SmallFinalizableWithBarrierHeapBlock * newFinalizableWithBarrierHeapBlockList;
  348. #endif
  349. #endif
  350. #if ENABLE_CONCURRENT_GC
  351. MediumLeafHeapBlock * newMediumLeafHeapBlockList;
  352. MediumNormalHeapBlock * newMediumNormalHeapBlockList;
  353. MediumFinalizableHeapBlock * newMediumFinalizableHeapBlockList;
  354. #ifdef RECYCLER_WRITE_BARRIER
  355. MediumNormalWithBarrierHeapBlock * newMediumNormalWithBarrierHeapBlockList;
  356. MediumFinalizableWithBarrierHeapBlock * newMediumFinalizableWithBarrierHeapBlockList;
  357. #endif
  358. #endif
  359. #ifdef RECYCLER_PAGE_HEAP
  360. PageHeapMode pageHeapMode;
  361. bool isPageHeapEnabled;
  362. BVStatic<HeapConstants::BucketCount> smallBlockPageHeapBucketFilter;
  363. BVStatic<HeapConstants::MediumBucketCount> mediumBlockPageHeapBucketFilter;
  364. bool captureAllocCallStack;
  365. bool captureFreeCallStack;
  366. PageHeapBlockTypeFilter pageHeapBlockType;
  367. #endif
  368. HeapBucketGroup<SmallAllocationBlockAttributes> heapBuckets[HeapConstants::BucketCount];
  369. #ifdef BUCKETIZE_MEDIUM_ALLOCATIONS
  370. #if SMALLBLOCK_MEDIUM_ALLOC
  371. HeapBucketGroup<MediumAllocationBlockAttributes> mediumHeapBuckets[HeapConstants::MediumBucketCount];
  372. #else
  373. LargeHeapBucket mediumHeapBuckets[HeapConstants::MediumBucketCount];
  374. #endif
  375. #endif
  376. LargeHeapBucket largeObjectBucket;
  377. static const size_t ObjectAlignmentMask = HeapConstants::ObjectGranularity - 1; // 0xF
  378. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  379. size_t heapBlockCount[HeapBlock::BlockTypeCount];
  380. #endif
  381. #ifdef RECYCLER_FINALIZE_CHECK
  382. size_t liveFinalizableObjectCount;
  383. size_t newFinalizableObjectCount;
  384. size_t pendingDisposableObjectCount;
  385. void VerifyFinalize();
  386. #endif
  387. friend class Recycler;
  388. friend class HeapBucket;
  389. friend class HeapBlockMap32;
  390. friend class LargeHeapBucket;
  391. template <typename TBlockType>
  392. friend class HeapBucketT;
  393. template <typename TBlockType>
  394. friend class SmallHeapBlockAllocator;
  395. template <typename TBlockAttributes>
  396. friend class SmallFinalizableHeapBucketT;
  397. template <typename TBlockAttributes>
  398. friend class SmallLeafHeapBucketBaseT;
  399. template <typename TBlockAttributes>
  400. friend class SmallHeapBlockT;
  401. template <typename TBlockAttributes>
  402. friend class SmallLeafHeapBlockT;
  403. template <typename TBlockAttributes>
  404. friend class SmallFinalizableHeapBlockT;
  405. friend class LargeHeapBlock;
  406. friend class RecyclerSweep;
  407. };
  408. template <ObjectInfoBits attributes>
  409. typename SmallHeapBlockType<attributes, SmallAllocationBlockAttributes>::BucketType&
  410. HeapInfo::GetBucket(size_t sizeCat)
  411. {
  412. uint bucket = HeapInfo::GetBucketIndex(sizeCat);
  413. return this->heapBuckets[bucket].GetBucket<attributes>();
  414. }
  415. #ifdef BUCKETIZE_MEDIUM_ALLOCATIONS
  416. #if SMALLBLOCK_MEDIUM_ALLOC
  417. template <ObjectInfoBits attributes>
  418. typename SmallHeapBlockType<attributes, MediumAllocationBlockAttributes>::BucketType&
  419. HeapInfo::GetMediumBucket(size_t sizeCat)
  420. {
  421. uint bucket = HeapInfo::GetMediumBucketIndex(sizeCat);
  422. return this->mediumHeapBuckets[bucket].GetBucket<attributes>();
  423. }
  424. #else
  425. LargeHeapBucket&
  426. HeapInfo::GetMediumBucket(size_t sizeCat)
  427. {
  428. uint bucket = HeapInfo::GetMediumBucketIndex(sizeCat);
  429. return this->mediumHeapBuckets[bucket];
  430. }
  431. #endif
  432. #endif
  433. template <ObjectInfoBits attributes, bool nothrow>
  434. __inline char *
  435. HeapInfo::RealAlloc(Recycler * recycler, size_t sizeCat, size_t size)
  436. {
  437. Assert(HeapInfo::IsAlignedSmallObjectSize(sizeCat));
  438. auto& bucket = this->GetBucket<(ObjectInfoBits)(attributes & GetBlockTypeBitMask)>(sizeCat);
  439. return bucket.RealAlloc<attributes, nothrow>(recycler, sizeCat, size);
  440. }
  441. #if defined(BUCKETIZE_MEDIUM_ALLOCATIONS)
  442. #if SMALLBLOCK_MEDIUM_ALLOC
  443. template <ObjectInfoBits attributes, bool nothrow>
  444. __inline char *
  445. HeapInfo::MediumAlloc(Recycler * recycler, size_t sizeCat, size_t size)
  446. {
  447. auto& bucket = this->GetMediumBucket<(ObjectInfoBits)(attributes & GetBlockTypeBitMask)>(sizeCat);
  448. return bucket.RealAlloc<attributes, nothrow>(recycler, sizeCat, size);
  449. }
  450. #else
  451. template <ObjectInfoBits attributes, bool nothrow>
  452. __forceinline char *
  453. HeapInfo::MediumAlloc(Recycler * recycler, size_t sizeCat)
  454. {
  455. Assert(HeapInfo::IsAlignedMediumObjectSize(sizeCat));
  456. return this->GetMediumBucket<attributes>(sizeCat).Alloc<attributes, nothrow>(recycler, sizeCat);
  457. }
  458. #endif
  459. #endif
  460. template <ObjectInfoBits attributes>
  461. __inline void
  462. HeapInfo::FreeSmallObject(void* object, size_t sizeCat)
  463. {
  464. Assert(HeapInfo::IsAlignedSmallObjectSize(sizeCat));
  465. return this->GetBucket<(ObjectInfoBits)(attributes & GetBlockTypeBitMask)>(sizeCat).ExplicitFree(object, sizeCat);
  466. }
  467. template <ObjectInfoBits attributes>
  468. __inline void
  469. HeapInfo::FreeMediumObject(void* object, size_t sizeCat)
  470. {
  471. Assert(HeapInfo::IsAlignedMediumObjectSize(sizeCat));
  472. return this->GetMediumBucket<(ObjectInfoBits)(attributes & GetBlockTypeBitMask)>(sizeCat).ExplicitFree(object, sizeCat);
  473. }
  474. template <ObjectInfoBits attributes>
  475. bool
  476. HeapInfo::IntegrateBlock(char * blockAddress, PageSegment * segment, Recycler * recycler, size_t sizeCat)
  477. {
  478. // We only support no bit and leaf bit right now, where we don't need to set the object info in either case
  479. CompileAssert(attributes == NoBit || attributes == LeafBit);
  480. Assert(HeapInfo::IsAlignedSmallObjectSize(sizeCat));
  481. return this->GetBucket<(ObjectInfoBits)(attributes & GetBlockTypeBitMask)>(sizeCat).IntegrateBlock(blockAddress, segment, recycler);
  482. }
  483. template <typename SmallHeapBlockAllocatorType>
  484. void
  485. HeapInfo::AddSmallAllocator(SmallHeapBlockAllocatorType * allocator, size_t sizeCat)
  486. {
  487. Assert(HeapInfo::IsAlignedSmallObjectSize(sizeCat));
  488. this->GetBucket<SmallHeapBlockAllocatorType::BlockType::RequiredAttributes>(sizeCat).AddAllocator(allocator);
  489. }
  490. template <typename SmallHeapBlockAllocatorType>
  491. void
  492. HeapInfo::RemoveSmallAllocator(SmallHeapBlockAllocatorType * allocator, size_t sizeCat)
  493. {
  494. Assert(HeapInfo::IsAlignedSmallObjectSize(sizeCat));
  495. this->GetBucket<SmallHeapBlockAllocatorType::BlockType::RequiredAttributes>(sizeCat).RemoveAllocator(allocator);
  496. }
  497. template <ObjectInfoBits attributes, typename SmallHeapBlockAllocatorType>
  498. char *
  499. HeapInfo::SmallAllocatorAlloc(Recycler * recycler, SmallHeapBlockAllocatorType * allocator, size_t sizeCat, size_t size)
  500. {
  501. Assert(HeapInfo::IsAlignedSmallObjectSize(sizeCat));
  502. CompileAssert((attributes & SmallHeapBlockAllocatorType::BlockType::RequiredAttributes) == SmallHeapBlockAllocatorType::BlockType::RequiredAttributes);
  503. auto& bucket = this->GetBucket<SmallHeapBlockAllocatorType::BlockType::RequiredAttributes>(sizeCat);
  504. // For now, SmallAllocatorAlloc is always throwing- but it's pretty easy to switch it if it's needed
  505. return bucket.SnailAlloc(recycler, allocator, sizeCat, size, attributes, /* nothrow = */ false);
  506. }
  507. extern template class HeapInfo::ValidPointersMap<SmallAllocationBlockAttributes>;
  508. extern template class HeapInfo::ValidPointersMap<MediumAllocationBlockAttributes>;
  509. }