HeapBlock.cpp 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936
  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. #include "CommonMemoryPch.h"
  6. template <typename TBlockAttributes>
  7. SmallNormalHeapBlockT<TBlockAttributes> *
  8. HeapBlock::AsNormalBlock()
  9. {
  10. Assert(IsAnyNormalBlock());
  11. return static_cast<SmallNormalHeapBlockT<TBlockAttributes> *>(this);
  12. }
  13. template <typename TBlockAttributes>
  14. SmallLeafHeapBlockT<TBlockAttributes> *
  15. HeapBlock::AsLeafBlock()
  16. {
  17. Assert(IsLeafBlock());
  18. return static_cast<SmallLeafHeapBlockT<TBlockAttributes> *>(this);
  19. }
  20. template <typename TBlockAttributes>
  21. SmallFinalizableHeapBlockT<TBlockAttributes> *
  22. HeapBlock::AsFinalizableBlock()
  23. {
  24. Assert(IsAnyFinalizableBlock());
  25. return static_cast<SmallFinalizableHeapBlockT<TBlockAttributes> *>(this);
  26. }
  27. #ifdef RECYCLER_WRITE_BARRIER
  28. template <typename TBlockAttributes>
  29. SmallNormalWithBarrierHeapBlockT<TBlockAttributes> *
  30. HeapBlock::AsNormalWriteBarrierBlock()
  31. {
  32. Assert(IsNormalWriteBarrierBlock());
  33. return static_cast<SmallNormalWithBarrierHeapBlockT<TBlockAttributes> *>(this);
  34. }
  35. template <typename TBlockAttributes>
  36. SmallFinalizableWithBarrierHeapBlockT<TBlockAttributes> *
  37. HeapBlock::AsFinalizableWriteBarrierBlock()
  38. {
  39. Assert(IsFinalizableWriteBarrierBlock());
  40. return static_cast<SmallFinalizableWithBarrierHeapBlockT<TBlockAttributes> *>(this);
  41. }
  42. #endif
  43. void
  44. HeapBlock::SetNeedOOMRescan(Recycler * recycler)
  45. {
  46. Assert(!this->IsLeafBlock());
  47. this->needOOMRescan = true;
  48. recycler->SetNeedOOMRescan();
  49. }
  50. //========================================================================================================
  51. // SmallHeapBlock
  52. //========================================================================================================
  53. template <class TBlockAttributes>
  54. size_t
  55. SmallHeapBlockT<TBlockAttributes>::GetAllocPlusSize(uint objectCount)
  56. {
  57. // Small Heap Block Layout:
  58. // TrackerData * [objectCount] (Optional)
  59. // ObjectInfo [objectCount] (In reverse index order)
  60. // <Small*HeapBlock>
  61. size_t allocPlusSize = Math::Align<size_t>(sizeof(unsigned char) * objectCount, sizeof(size_t));
  62. #ifdef PROFILE_RECYCLER_ALLOC
  63. if (Recycler::DoProfileAllocTracker())
  64. {
  65. allocPlusSize += objectCount * sizeof(void *);
  66. }
  67. #endif
  68. return allocPlusSize;
  69. }
  70. template <class TBlockAttributes>
  71. void
  72. SmallHeapBlockT<TBlockAttributes>::ConstructorCommon(HeapBucket * bucket, ushort objectSize, ushort objectCount, HeapBlockType heapBlockType)
  73. {
  74. this->heapBucket = bucket;
  75. this->Init(objectSize, objectCount);
  76. Assert(heapBlockType < HeapBlock::HeapBlockType::SmallAllocBlockTypeCount + HeapBlock::HeapBlockType::MediumAllocBlockTypeCount);
  77. Assert(objectCount > 1 && objectCount == (this->GetPageCount() * AutoSystemInfo::PageSize) / objectSize);
  78. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  79. heapBucket->heapInfo->heapBlockCount[heapBlockType]++;
  80. #endif
  81. if (TBlockAttributes::IsSmallBlock)
  82. {
  83. Assert(heapBlockType < HeapBlockType::SmallAllocBlockTypeCount);
  84. }
  85. else
  86. {
  87. Assert(heapBlockType >= HeapBlockType::SmallAllocBlockTypeCount && heapBlockType < HeapBlockType::SmallBlockTypeCount);
  88. }
  89. DebugOnly(lastUncollectedAllocBytes = 0);
  90. }
  91. template <class TBlockAttributes>
  92. SmallHeapBlockT<TBlockAttributes>::SmallHeapBlockT(HeapBucket * bucket, ushort objectSize, ushort objectCount, HeapBlockType heapBlockType)
  93. : HeapBlock(heapBlockType),
  94. bucketIndex(HeapInfo::GetBucketIndex(objectSize)),
  95. validPointers(HeapInfo::smallAllocValidPointersMap.GetValidPointersForIndex(HeapInfo::GetBucketIndex(objectSize))),
  96. objectSize(objectSize), objectCount(objectCount)
  97. {
  98. ConstructorCommon(bucket, objectSize, objectCount, heapBlockType);
  99. }
  100. template <>
  101. SmallHeapBlockT<MediumAllocationBlockAttributes>::SmallHeapBlockT(HeapBucket * bucket, ushort objectSize, ushort objectCount, HeapBlockType heapBlockType)
  102. : HeapBlock((HeapBlockType)(heapBlockType)),
  103. bucketIndex(HeapInfo::GetMediumBucketIndex(objectSize)),
  104. validPointers(HeapInfo::mediumAllocValidPointersMap.GetValidPointersForIndex(HeapInfo::GetMediumBucketIndex(objectSize))),
  105. objectSize(objectSize), objectCount(objectCount)
  106. {
  107. ConstructorCommon(bucket, objectSize, objectCount, heapBlockType);
  108. }
  109. template <class TBlockAttributes>
  110. SmallHeapBlockT<TBlockAttributes>::~SmallHeapBlockT()
  111. {
  112. Assert((this->segment == nullptr && this->address == nullptr) ||
  113. (this->IsLeafBlock()) ||
  114. this->GetPageAllocator(heapBucket->heapInfo->recycler)->IsClosed());
  115. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  116. heapBucket->heapInfo->heapBlockCount[this->GetHeapBlockType()]--;
  117. heapBucket->heapBlockCount--;
  118. #endif
  119. }
  120. template <class TBlockAttributes>
  121. uint
  122. SmallHeapBlockT<TBlockAttributes>::GetObjectBitDeltaForBucketIndex(uint bucketIndex)
  123. {
  124. return bucketIndex + 1;
  125. }
  126. template <>
  127. uint
  128. SmallHeapBlockT<MediumAllocationBlockAttributes>::GetObjectBitDeltaForBucketIndex(uint bucketIndex)
  129. {
  130. return HeapInfo::GetObjectSizeForBucketIndex<MediumAllocationBlockAttributes>(bucketIndex) / HeapConstants::ObjectGranularity;
  131. }
  132. template <class TBlockAttributes>
  133. uint
  134. SmallHeapBlockT<TBlockAttributes>::GetPageCount() const
  135. {
  136. return TBlockAttributes::PageCount;
  137. }
  138. template <>
  139. uint
  140. SmallHeapBlockT<MediumAllocationBlockAttributes>::GetUnusablePageCount()
  141. {
  142. return ((MediumAllocationBlockAttributes::PageCount * AutoSystemInfo::PageSize) % this->objectSize) / AutoSystemInfo::PageSize;
  143. }
  144. template <>
  145. void
  146. SmallHeapBlockT<MediumAllocationBlockAttributes>::ProtectUnusablePages()
  147. {
  148. size_t count = this->GetUnusablePageCount();
  149. if (count > 0)
  150. {
  151. char* startPage = this->address + (MediumAllocationBlockAttributes::PageCount - count) * AutoSystemInfo::PageSize;
  152. DWORD oldProtect;
  153. BOOL ret = ::VirtualProtect(startPage, count * AutoSystemInfo::PageSize, PAGE_READONLY, &oldProtect);
  154. Assert(ret && oldProtect == PAGE_READWRITE);
  155. #ifdef RECYCLER_WRITE_WATCH
  156. if (!CONFIG_FLAG(ForceSoftwareWriteBarrier))
  157. {
  158. ::ResetWriteWatch(startPage, count*AutoSystemInfo::PageSize);
  159. }
  160. #endif
  161. }
  162. }
  163. template <>
  164. void
  165. SmallHeapBlockT<MediumAllocationBlockAttributes>::RestoreUnusablePages()
  166. {
  167. size_t count = this->GetUnusablePageCount();
  168. if (count > 0)
  169. {
  170. char* startPage = (char*)this->address + (MediumAllocationBlockAttributes::PageCount - count) * AutoSystemInfo::PageSize;
  171. DWORD oldProtect;
  172. BOOL ret = ::VirtualProtect(startPage, count * AutoSystemInfo::PageSize, PAGE_READWRITE, &oldProtect);
  173. #if DBG
  174. HeapBlock* block = this->heapBucket->heapInfo->recycler->heapBlockMap.GetHeapBlock(this->address);
  175. // only need to do this after the unusable page is already successfully protected
  176. // currently we don't have a flag to save that, but it should not fail after it successfully added to blockmap (see SetPage() implementation)
  177. if (block)
  178. {
  179. Assert(block == this);
  180. Assert(ret && oldProtect == PAGE_READONLY);
  181. }
  182. #endif
  183. }
  184. }
  185. template <class TBlockAttributes>
  186. void
  187. SmallHeapBlockT<TBlockAttributes>::ClearObjectInfoList()
  188. {
  189. ushort count = this->objectCount;
  190. // the object info list is prefix to the object
  191. memset(((byte *)this) - count, 0, count);
  192. }
  193. template <class TBlockAttributes>
  194. byte&
  195. SmallHeapBlockT<TBlockAttributes>::ObjectInfo(uint index)
  196. {
  197. // See SmallHeapBlockT<TBlockAttributes>::GetAllocPlusSize for layout description
  198. // the object info list is prefix to the object and in reverse index order
  199. Assert(index < this->objectCount);
  200. return *(((byte *)this) - index - 1);
  201. }
  202. template <class TBlockAttributes>
  203. ushort
  204. SmallHeapBlockT<TBlockAttributes>::GetExpectedFreeObjectCount() const
  205. {
  206. Assert(this->GetRecycler()->IsSweeping());
  207. return objectCount - markCount;
  208. }
  209. template <class TBlockAttributes>
  210. uint
  211. SmallHeapBlockT<TBlockAttributes>::GetExpectedFreeBytes() const
  212. {
  213. return GetExpectedFreeObjectCount() * objectSize;
  214. }
  215. template <class TBlockAttributes>
  216. ushort
  217. SmallHeapBlockT<TBlockAttributes>::GetExpectedSweepObjectCount() const
  218. {
  219. return GetExpectedFreeObjectCount() - freeCount;
  220. }
  221. template <class TBlockAttributes>
  222. void
  223. SmallHeapBlockT<TBlockAttributes>::Init(ushort objectSize, ushort objectCount)
  224. {
  225. Assert(objectCount != 0);
  226. Assert(TBlockAttributes::IsAlignedObjectSize(objectSize));
  227. Assert(this->next == nullptr);
  228. Assert(this->freeObjectList == nullptr);
  229. Assert(this->freeCount == 0);
  230. #if ENABLE_PARTIAL_GC
  231. this->oldFreeCount = this->lastFreeCount = this->objectCount;
  232. #else
  233. this->lastFreeCount = this->objectCount;
  234. #endif
  235. #if ENABLE_CONCURRENT_GC
  236. this->isPendingConcurrentSweep = false;
  237. #endif
  238. Assert(!this->isInAllocator);
  239. Assert(!this->isClearedFromAllocator);
  240. Assert(!this->isIntegratedBlock);
  241. }
  242. template <class TBlockAttributes>
  243. BOOL
  244. SmallHeapBlockT<TBlockAttributes>::ReassignPages(Recycler * recycler)
  245. {
  246. Assert(this->address == nullptr);
  247. Assert(this->segment == nullptr);
  248. PageSegment * segment;
  249. auto pageAllocator = this->GetPageAllocator(recycler);
  250. uint pagecount = this->GetPageCount();
  251. char * address = pageAllocator->AllocPagesPageAligned(pagecount, &segment);
  252. if (address == NULL)
  253. {
  254. return FALSE;
  255. }
  256. #if ENABLE_PARTIAL_GC
  257. recycler->autoHeap.uncollectedNewPageCount += this->GetPageCount();
  258. #endif
  259. #ifdef RECYCLER_ZERO_MEM_CHECK
  260. if (!this->IsLeafBlock()
  261. #ifdef RECYCLER_WRITE_BARRIER_ALLOC_THREAD_PAGE
  262. && !this->IsWithBarrier()
  263. #endif
  264. )
  265. {
  266. recycler->VerifyZeroFill(address, AutoSystemInfo::PageSize * this->GetPageCount());
  267. }
  268. #endif
  269. if (!this->SetPage(address, segment, recycler))
  270. {
  271. this->GetPageAllocator(recycler)->SuspendIdleDecommit();
  272. this->ReleasePages(recycler);
  273. this->GetPageAllocator(recycler)->ResumeIdleDecommit();
  274. return FALSE;
  275. }
  276. RECYCLER_PERF_COUNTER_ADD(FreeObjectSize, this->GetPageCount() * AutoSystemInfo::PageSize);
  277. RECYCLER_PERF_COUNTER_ADD(SmallHeapBlockFreeObjectSize, this->GetPageCount() * AutoSystemInfo::PageSize);
  278. return TRUE;
  279. }
  280. template <class TBlockAttributes>
  281. BOOL
  282. SmallHeapBlockT<TBlockAttributes>::SetPage(__in_ecount_pagesize char * baseAddress, PageSegment * pageSegment, Recycler * recycler)
  283. {
  284. char* address = baseAddress;
  285. Assert(HeapBlockMap32::GetLevel2Id(address) + (TBlockAttributes::PageCount - 1) < 256);
  286. this->segment = pageSegment;
  287. this->address = address;
  288. // Set up the page to have nothing is free
  289. Assert(this->freeObjectList == nullptr);
  290. Assert(this->IsFreeBitsValid());
  291. Assert(this->freeCount == 0);
  292. Assert(this->freeCount == this->GetFreeBitVector()->Count());
  293. Assert(this->objectCount == this->lastFreeCount);
  294. Assert(this->explicitFreeBits.Count() == 0);
  295. #if ENABLE_CONCURRENT_GC
  296. Assert(recycler->IsConcurrentMarkState() || !recycler->IsMarkState() || recycler->IsCollectionDisabled());
  297. #else
  298. Assert(!recycler->IsMarkState() || recycler->IsCollectionDisabled());
  299. #endif
  300. Assert(this->bucketIndex <= 0xFF);
  301. // We use the block type directly here, without the getter so that we can tell on the heap block map,
  302. // whether the block is a medium block or not
  303. if (!recycler->heapBlockMap.SetHeapBlock(this->address, this->GetPageCount() - this->GetUnusablePageCount(), this, this->heapBlockType, (byte)this->bucketIndex))
  304. {
  305. return FALSE;
  306. }
  307. // Retrieve pointer to mark bits for this block and store it locally.
  308. // Note, mark bits aren't guaranteed to exist until after we register with HBM.
  309. this->markBits = recycler->heapBlockMap.GetMarkBitVectorForPages<TBlockAttributes::BitVectorCount>(this->address);
  310. Assert(this->markBits);
  311. #if defined(_M_ARM32_OR_ARM64)
  312. // We need to ensure that the above writes to the SmallHeapBlock are visible to the background GC thread.
  313. // In particular, see Threshold 331596 -- we were seeing an old value for SmallHeapBlockT<TBlockAttributes>::markBits in ResetMarks.
  314. // which caused the bit vector Copy operation there to AV.
  315. // See also SmallHeapBlockT<TBlockAttributes>::ResetMarks.
  316. MemoryBarrier();
  317. #endif
  318. this->ProtectUnusablePages();
  319. return TRUE;
  320. }
  321. template <class TBlockAttributes>
  322. void
  323. SmallHeapBlockT<TBlockAttributes>::ReleasePages(Recycler * recycler)
  324. {
  325. Assert(recycler->collectionState != CollectionStateMark);
  326. Assert(segment != nullptr);
  327. Assert(address != nullptr);
  328. #if DBG
  329. if (this->IsLeafBlock())
  330. {
  331. RecyclerVerboseTrace(recycler->GetRecyclerFlagsTable(), _u("Releasing leaf block pages at address 0x%p\n"), address);
  332. }
  333. #endif
  334. char* address = this->address;
  335. #ifdef RECYCLER_FREE_MEM_FILL
  336. memset(address, DbgMemFill, AutoSystemInfo::PageSize * (this->GetPageCount()-this->GetUnusablePageCount()));
  337. #endif
  338. if (this->GetUnusablePageCount() > 0)
  339. {
  340. this->RestoreUnusablePages();
  341. }
  342. this->GetPageAllocator(recycler)->ReleasePages(address, this->GetPageCount(), this->GetPageSegment());
  343. this->segment = nullptr;
  344. this->address = nullptr;
  345. }
  346. #if ENABLE_BACKGROUND_PAGE_FREEING
  347. template <class TBlockAttributes>
  348. void
  349. SmallHeapBlockT<TBlockAttributes>::BackgroundReleasePagesSweep(Recycler* recycler)
  350. {
  351. recycler->heapBlockMap.ClearHeapBlock(address, this->GetPageCount() - this->GetUnusablePageCount());
  352. char* address = this->address;
  353. if (this->GetUnusablePageCount() > 0)
  354. {
  355. this->RestoreUnusablePages();
  356. }
  357. this->GetPageAllocator(recycler)->BackgroundReleasePages(address, this->GetPageCount(), this->GetPageSegment());
  358. this->address = nullptr;
  359. this->segment = nullptr;
  360. this->Reset();
  361. }
  362. #endif
  363. template <class TBlockAttributes>
  364. void
  365. SmallHeapBlockT<TBlockAttributes>::ReleasePagesShutdown(Recycler * recycler)
  366. {
  367. #if DBG
  368. if (this->IsLeafBlock())
  369. {
  370. RecyclerVerboseTrace(recycler->GetRecyclerFlagsTable(), _u("Releasing leaf block pages at address 0x%p\n"), address);
  371. }
  372. RemoveFromHeapBlockMap(recycler);
  373. // Don't release the page in shut down, the page allocator will release them faster
  374. // Leaf block's allocator need not be closed
  375. Assert(this->IsLeafBlock() || this->GetPageAllocator(recycler)->IsClosed());
  376. #endif
  377. }
  378. template <class TBlockAttributes>
  379. void
  380. SmallHeapBlockT<TBlockAttributes>::RemoveFromHeapBlockMap(Recycler* recycler)
  381. {
  382. recycler->heapBlockMap.ClearHeapBlock(address, this->GetPageCount() - this->GetUnusablePageCount());
  383. }
  384. template <class TBlockAttributes>
  385. void
  386. SmallHeapBlockT<TBlockAttributes>::ReleasePagesSweep(Recycler * recycler)
  387. {
  388. RemoveFromHeapBlockMap(recycler);
  389. ReleasePages(recycler);
  390. }
  391. template <class TBlockAttributes>
  392. void
  393. SmallHeapBlockT<TBlockAttributes>::Reset()
  394. {
  395. this->GetFreeBitVector()->ClearAll();
  396. this->freeCount = 0;
  397. this->markCount = 0;
  398. #if ENABLE_PARTIAL_GC
  399. this->oldFreeCount = this->lastFreeCount = this->objectCount;
  400. #else
  401. this->lastFreeCount = this->objectCount;
  402. #endif
  403. this->freeObjectList = nullptr;
  404. this->lastFreeObjectHead = nullptr;
  405. this->ClearObjectInfoList();
  406. this->isInAllocator = false;
  407. #if DBG || defined(RECYCLER_STATS)
  408. this->GetDebugFreeBitVector()->ClearAll();
  409. #endif
  410. #if DBG
  411. this->isClearedFromAllocator = false;
  412. this->isIntegratedBlock = false;
  413. #endif
  414. // There is no page associated with this heap block,
  415. // and therefore we should have no mark bits either
  416. this->markBits = nullptr;
  417. Assert(this->explicitFreeBits.Count() == 0);
  418. }
  419. // Map any object address to it's object index within the heap block
  420. template <class TBlockAttributes>
  421. ushort
  422. SmallHeapBlockT<TBlockAttributes>::GetAddressIndex(void * objectAddress)
  423. {
  424. Assert(objectAddress >= address && objectAddress < this->GetEndAddress());
  425. Assert(HeapInfo::IsAlignedAddress(objectAddress));
  426. Assert(HeapInfo::IsAlignedAddress(address));
  427. unsigned int offset = (unsigned int)((char*)objectAddress - address);
  428. offset = offset >> HeapConstants::ObjectAllocationShift;
  429. ushort index = validPointers.GetAddressIndex(offset);
  430. Assert(index == SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit ||
  431. index <= TBlockAttributes::MaxAddressBit);
  432. return index;
  433. }
  434. template <class TBlockAttributes>
  435. typename SmallHeapBlockT<TBlockAttributes>::SmallHeapBlockBitVector const*
  436. SmallHeapBlockT<TBlockAttributes>::GetInvalidBitVector()
  437. {
  438. return HeapInfo::GetInvalidBitVector<TBlockAttributes>(objectSize);
  439. }
  440. template <class TBlockAttributes>
  441. typename SmallHeapBlockT<TBlockAttributes>::BlockInfo const*
  442. SmallHeapBlockT<TBlockAttributes>::GetBlockInfo()
  443. {
  444. return HeapInfo::GetBlockInfo<TBlockAttributes>(objectSize);
  445. }
  446. template <class TBlockAttributes>
  447. ushort
  448. SmallHeapBlockT<TBlockAttributes>::GetInteriorAddressIndex(void * interiorAddress)
  449. {
  450. Assert(interiorAddress >= address && interiorAddress < this->GetEndAddress());
  451. Assert(HeapInfo::IsAlignedAddress(address));
  452. unsigned int offset = (unsigned int)((char*)interiorAddress - address);
  453. offset = offset >> HeapConstants::ObjectAllocationShift;
  454. ushort index = validPointers.GetInteriorAddressIndex(offset);
  455. Assert(index == SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit ||
  456. index <= TBlockAttributes::MaxAddressBit);
  457. return index;
  458. }
  459. template <class TBlockAttributes>
  460. BOOL
  461. SmallHeapBlockT<TBlockAttributes>::IsInFreeObjectList(void * objectAddress)
  462. {
  463. FreeObject * freeObject = this->freeObjectList;
  464. while (freeObject != nullptr)
  465. {
  466. if (freeObject == objectAddress)
  467. {
  468. return true;
  469. }
  470. freeObject = freeObject->GetNext();
  471. }
  472. return false;
  473. }
  474. template <class TBlockAttributes>
  475. template <typename TBlockType>
  476. bool
  477. SmallHeapBlockT<TBlockAttributes>::FindHeapObjectImpl(void* objectAddress, Recycler * recycler, FindHeapObjectFlags flags, RecyclerHeapObjectInfo& heapObject)
  478. {
  479. if (flags & FindHeapObjectFlags_AllowInterior)
  480. {
  481. objectAddress = (void*) this->GetRealAddressFromInterior(objectAddress);
  482. if (objectAddress == nullptr)
  483. {
  484. return false;
  485. }
  486. }
  487. ushort index = GetAddressIndex(objectAddress);
  488. Assert(index != SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit);
  489. if (index == SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit)
  490. {
  491. return false;
  492. }
  493. // If we have pending object, we still need to check the free bit if the caller requested the attribute to be correct
  494. bool const disableCheck = ((flags & FindHeapObjectFlags_NoFreeBitVerify) != 0) ||
  495. ((flags & FindHeapObjectFlags_VerifyFreeBitForAttribute) != 0 && !this->HasPendingDisposeObjects());
  496. if (!disableCheck)
  497. {
  498. // REVIEW: Checking if an object if free is strictly not necessary
  499. // In all case, we should have a valid object, For memory protect heap, this is just to make sure we don't
  500. // free pointers that are invalid.
  501. #if ENABLE_CONCURRENT_GC
  502. if (recycler->IsConcurrentSweepExecutingState())
  503. {
  504. // TODO: unless we know the state of the heap block, we don't know.
  505. // skip the check for now.
  506. }
  507. else
  508. #endif
  509. {
  510. if (flags & FindHeapObjectFlags_ClearedAllocators)
  511. {
  512. // Heap enum has some case where it allocates, so we can't assert
  513. Assert(((HeapBucketT<TBlockType> *)this->heapBucket)->AllocatorsAreEmpty() || recycler->isHeapEnumInProgress);
  514. }
  515. else if (this->IsInAllocator())
  516. {
  517. ((HeapBucketT<TBlockType> *)this->heapBucket)->UpdateAllocators();
  518. }
  519. // REVIEW allocation heuristics
  520. if (this->EnsureFreeBitVector()->Test(this->GetObjectBitDelta() * index))
  521. {
  522. return false;
  523. }
  524. }
  525. }
  526. byte& attributes = ObjectInfo(index);
  527. heapObject = RecyclerHeapObjectInfo(objectAddress, recycler, this, &attributes);
  528. return true;
  529. }
  530. template <class TBlockAttributes>
  531. BOOL
  532. SmallHeapBlockT<TBlockAttributes>::IsValidObject(void* objectAddress)
  533. {
  534. if (objectAddress < this->GetAddress() || objectAddress >= this->GetEndAddress())
  535. {
  536. return false;
  537. }
  538. ushort index = GetAddressIndex(objectAddress);
  539. if (index == SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit)
  540. {
  541. return false;
  542. }
  543. #if DBG
  544. return !this->GetDebugFreeBitVector()->Test(GetAddressBitIndex(objectAddress));
  545. #else
  546. return true;
  547. #endif
  548. }
  549. template <class TBlockAttributes>
  550. bool
  551. SmallHeapBlockT<TBlockAttributes>::IsInAllocator() const
  552. {
  553. return isInAllocator;
  554. }
  555. template <class TBlockAttributes>
  556. bool
  557. SmallHeapBlockT<TBlockAttributes>::HasPendingDisposeObjects()
  558. {
  559. return this->IsAnyFinalizableBlock() && this->AsFinalizableBlock<TBlockAttributes>()->HasPendingDisposeObjects();
  560. }
  561. template <class TBlockAttributes>
  562. bool
  563. SmallHeapBlockT<TBlockAttributes>::HasAnyDisposeObjects()
  564. {
  565. return this->IsAnyFinalizableBlock() && this->AsFinalizableBlock<TBlockAttributes>()->HasAnyDisposeObjects();
  566. }
  567. template <class TBlockAttributes>
  568. Recycler *
  569. SmallHeapBlockT<TBlockAttributes>::GetRecycler() const
  570. {
  571. #if DBG
  572. return this->heapBucket->heapInfo->recycler;
  573. #else
  574. return nullptr;
  575. #endif
  576. }
  577. #if DBG
  578. template <class TBlockAttributes>
  579. BOOL
  580. SmallHeapBlockT<TBlockAttributes>::IsFreeObject(void * objectAddress)
  581. {
  582. if (objectAddress < this->GetAddress() || objectAddress >= this->GetEndAddress())
  583. {
  584. return false;
  585. }
  586. ushort index = GetAddressIndex(objectAddress);
  587. if (index == SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit)
  588. {
  589. return false;
  590. }
  591. return this->GetDebugFreeBitVector()->Test(GetAddressBitIndex(objectAddress));
  592. }
  593. template <class TBlockAttributes>
  594. void
  595. SmallHeapBlockT<TBlockAttributes>::VerifyMarkBitVector()
  596. {
  597. this->GetRecycler()->heapBlockMap.template VerifyMarkCountForPages<TBlockAttributes::BitVectorCount>(this->address, TBlockAttributes::PageCount);
  598. }
  599. template <class TBlockAttributes>
  600. bool
  601. SmallHeapBlockT<TBlockAttributes>::IsClearedFromAllocator() const
  602. {
  603. return isClearedFromAllocator;
  604. }
  605. template <class TBlockAttributes>
  606. void
  607. SmallHeapBlockT<TBlockAttributes>::SetIsClearedFromAllocator(bool value)
  608. {
  609. isClearedFromAllocator = value;
  610. }
  611. #endif
  612. template <class TBlockAttributes>
  613. byte *
  614. SmallHeapBlockT<TBlockAttributes>::GetRealAddressFromInterior(void * interiorAddress)
  615. {
  616. Assert(interiorAddress >= this->address && interiorAddress < this->address + AutoSystemInfo::PageSize * this->GetPageCount());
  617. ushort index = GetInteriorAddressIndex(interiorAddress);
  618. if (index != SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit)
  619. {
  620. return (byte *)this->address + index * this->GetObjectSize();
  621. }
  622. return nullptr;
  623. }
  624. template <class TBlockAttributes>
  625. bool
  626. SmallHeapBlockT<TBlockAttributes>::TestObjectMarkedBit(void* objectAddress)
  627. {
  628. Assert(this->address != nullptr);
  629. Assert(this->segment != nullptr);
  630. uint bitIndex = GetAddressBitIndex(objectAddress);
  631. Assert(IsValidBitIndex(bitIndex));
  632. return this->GetMarkedBitVector()->Test(bitIndex) != 0;
  633. }
  634. template <class TBlockAttributes>
  635. void
  636. SmallHeapBlockT<TBlockAttributes>::SetObjectMarkedBit(void* objectAddress)
  637. {
  638. Assert(this->address != nullptr);
  639. Assert(this->segment != nullptr);
  640. uint bitIndex = GetAddressBitIndex(objectAddress);
  641. Assert(IsValidBitIndex(bitIndex));
  642. this->GetMarkedBitVector()->Set(bitIndex);
  643. }
  644. #ifdef RECYCLER_MEMORY_VERIFY
  645. template <class TBlockAttributes>
  646. void
  647. SmallHeapBlockT<TBlockAttributes>::SetExplicitFreeBitForObject(void* objectAddress)
  648. {
  649. Assert(this->address != nullptr);
  650. Assert(this->segment != nullptr);
  651. uint bitIndex = GetAddressBitIndex(objectAddress);
  652. Assert(IsValidBitIndex(bitIndex));
  653. BOOLEAN wasSet = this->explicitFreeBits.TestAndSet(bitIndex);
  654. Assert(!wasSet);
  655. }
  656. template <class TBlockAttributes>
  657. void
  658. SmallHeapBlockT<TBlockAttributes>::ClearExplicitFreeBitForObject(void* objectAddress)
  659. {
  660. Assert(this->address != nullptr);
  661. Assert(this->segment != nullptr);
  662. uint bitIndex = GetAddressBitIndex(objectAddress);
  663. Assert(IsValidBitIndex(bitIndex));
  664. BOOLEAN wasSet = this->explicitFreeBits.TestAndClear(bitIndex);
  665. Assert(wasSet);
  666. }
  667. #endif
  668. #ifdef RECYCLER_VERIFY_MARK
  669. template <class TBlockAttributes>
  670. void
  671. SmallHeapBlockT<TBlockAttributes>::VerifyMark()
  672. {
  673. Assert(!this->needOOMRescan);
  674. SmallHeapBlockBitVector * marked = this->GetMarkedBitVector();
  675. SmallHeapBlockBitVector tempFreeBits;
  676. this->BuildFreeBitVector(&tempFreeBits);
  677. SmallHeapBlockBitVector * free = &tempFreeBits;
  678. SmallHeapBlockBitVector const * invalid = this->GetInvalidBitVector();
  679. uint objectWordCount = this->GetObjectWordCount();
  680. Recycler * recycler = this->heapBucket->heapInfo->recycler;
  681. FOREACH_BITSET_IN_FIXEDBV(bitIndex, marked)
  682. {
  683. if (!free->Test(bitIndex) && !invalid->Test(bitIndex))
  684. {
  685. Assert(IsValidBitIndex(bitIndex));
  686. uint objectIndex = GetObjectIndexFromBitIndex((ushort)bitIndex);
  687. Assert((this->ObjectInfo(objectIndex) & NewTrackBit) == 0);
  688. // NOTE: We can't verify mark for software write barrier blocks, because they may have
  689. // non-pointer updates that don't trigger the write barrier, but still look like a false reference.
  690. // Thus, when we get here, we'll see a false reference that isn't marked.
  691. // Since this situation is hard to detect, just don't verify mark for write barrier blocks.
  692. // We could fix this if we had object layout info.
  693. if (!this->IsLeafBlock()
  694. #ifdef RECYCLER_WRITE_BARRIER
  695. && (!this->IsWithBarrier() || CONFIG_FLAG(ForceSoftwareWriteBarrier))
  696. #endif
  697. )
  698. {
  699. if ((ObjectInfo(objectIndex) & LeafBit) == 0)
  700. {
  701. char * objectAddress = this->address + objectIndex * objectSize;
  702. for (uint i = 0; i < objectWordCount; i++)
  703. {
  704. void* target = *(void**) objectAddress;
  705. if (recycler->VerifyMark(target))
  706. {
  707. Assert(this->wbVerifyBits.Test((BVIndex)(objectAddress - this->address) / sizeof(void*)));
  708. }
  709. objectAddress += sizeof(void *);
  710. }
  711. }
  712. }
  713. }
  714. }
  715. NEXT_BITSET_IN_FIXEDBV;
  716. }
  717. template <class TBlockAttributes>
  718. bool
  719. SmallHeapBlockT<TBlockAttributes>::VerifyMark(void * objectAddress)
  720. {
  721. // Because we mark through new object, we might have a false reference
  722. // somewhere that we have scanned before this new block is allocated
  723. // so the object will not be marked even though it looks like a reference
  724. // Can't verify when the block is new
  725. if (this->heapBucket->GetRecycler()->heapBlockMap.IsAddressInNewChunk(objectAddress))
  726. {
  727. return false;
  728. }
  729. ushort bitIndex = GetAddressBitIndex(objectAddress);
  730. bool isMarked = this->GetMarkedBitVector()->Test(bitIndex) == TRUE;
  731. #if DBG
  732. Assert(isMarked);
  733. #else
  734. if (!isMarked)
  735. {
  736. DebugBreak();
  737. }
  738. #endif
  739. return isMarked;
  740. }
  741. #endif
  742. #ifdef RECYCLER_STRESS
  743. template <class TBlockAttributes>
  744. void
  745. SmallHeapBlockT<TBlockAttributes>::InduceFalsePositive(Recycler * recycler)
  746. {
  747. // Induce a false positive mark by marking the first object on the free list, if any.
  748. // Note that if the block is in the allocator, freeObjectList is not up to date.
  749. // So we may be marking an already-allocated block, but that's okay --
  750. // we call TryMark so that normal processing (including tracked object processing, etc)
  751. // will occur just as if we had a false reference to this object previously.
  752. void * falsePositive = this->freeObjectList;
  753. if (falsePositive != nullptr)
  754. {
  755. recycler->TryMarkNonInterior(falsePositive, nullptr);
  756. }
  757. }
  758. #endif
  759. template <class TBlockAttributes>
  760. void
  761. SmallHeapBlockT<TBlockAttributes>::ClearAllAllocBytes()
  762. {
  763. #if ENABLE_PARTIAL_GC
  764. this->oldFreeCount = this->lastFreeCount = this->freeCount;
  765. #else
  766. this->lastFreeCount = this->freeCount;
  767. #endif
  768. }
  769. #if ENABLE_PARTIAL_GC
  770. template <class TBlockAttributes>
  771. bool
  772. SmallHeapBlockT<TBlockAttributes>::DoPartialReusePage(RecyclerSweep const& recyclerSweep, uint& expectFreeByteCount)
  773. {
  774. // Partial GC page reuse heuristic
  775. Assert(recyclerSweep.InPartialCollectMode());
  776. expectFreeByteCount = GetExpectedFreeBytes();
  777. // PartialCollectSmallHeapBlockReuseMinFreeBytes is calculated by dwPageSize* efficacy. If efficacy is
  778. // high (== 1), and dwPageSize % objectSize != 0, all the pages in the bucket will be partial, and that
  779. // could increase in thread sweep time.
  780. // OTOH, if the object size is really large, the calculation below will reduce the chance for a page to be
  781. // partial. we might need to watch out for that.
  782. return (expectFreeByteCount + objectSize >= recyclerSweep.GetPartialCollectSmallHeapBlockReuseMinFreeBytes());
  783. }
  784. #if DBG
  785. // do debug assert for partial block that we are not going to sweep
  786. template <class TBlockAttributes>
  787. void
  788. SmallHeapBlockT<TBlockAttributes>::SweepVerifyPartialBlock(Recycler * recycler)
  789. {
  790. Assert(!this->IsLeafBlock());
  791. // nothing in the partialHeapBlockList is sweepable
  792. Assert(GetExpectedSweepObjectCount() == 0);
  793. }
  794. #endif
  795. template <class TBlockAttributes>
  796. uint
  797. SmallHeapBlockT<TBlockAttributes>::GetAndClearUnaccountedAllocBytes()
  798. {
  799. Assert(this->lastFreeCount >= this->freeCount);
  800. const ushort currentFreeCount = this->freeCount;
  801. uint unaccountedAllocBytes = (this->lastFreeCount - currentFreeCount) * this->objectSize;
  802. this->lastFreeCount = currentFreeCount;
  803. return unaccountedAllocBytes;
  804. }
  805. template <class TBlockAttributes>
  806. void
  807. SmallHeapBlockT<TBlockAttributes>::AdjustPartialUncollectedAllocBytes(RecyclerSweep& recyclerSweep, uint const expectSweepCount)
  808. {
  809. const uint allObjectCount = this->objectCount;
  810. const ushort currentFreeCount = this->freeCount;
  811. Assert(this->lastFreeCount == currentFreeCount);
  812. uint newAllocatedCount = this->oldFreeCount - currentFreeCount;
  813. this->oldFreeCount = currentFreeCount;
  814. uint newObjectExpectSweepCount = expectSweepCount;
  815. #if ENABLE_CONCURRENT_GC
  816. if (expectSweepCount != 0 && !recyclerSweep.InPartialCollect())
  817. {
  818. // We don't know which objects that we are going sweep are old and which object are new
  819. // So just assume one way or the other by the amount of old vs. new object in the block
  820. const uint allocatedObjectCount = allObjectCount - currentFreeCount;
  821. Assert(allocatedObjectCount >= newAllocatedCount);
  822. const uint oldObjectCount = allocatedObjectCount - newAllocatedCount;
  823. if (oldObjectCount < newAllocatedCount)
  824. {
  825. // count all of the swept object as new, but don't exceed the amount we allocated
  826. if (newObjectExpectSweepCount > newAllocatedCount)
  827. {
  828. newObjectExpectSweepCount = newAllocatedCount;
  829. }
  830. }
  831. else
  832. {
  833. // count all of the swept object as old
  834. newObjectExpectSweepCount = 0;
  835. }
  836. }
  837. #endif
  838. // The page can be old, or it is full (where we set lastFreeCount to 0)
  839. // Otherwise, the newly allocated count must be bigger then the expect sweep count
  840. Assert(newAllocatedCount >= newObjectExpectSweepCount);
  841. Assert(this->lastUncollectedAllocBytes >= newObjectExpectSweepCount * this->objectSize);
  842. recyclerSweep.SubtractSweepNewObjectAllocBytes(newObjectExpectSweepCount * this->objectSize);
  843. }
  844. #endif
  845. template <class TBlockAttributes>
  846. uint
  847. SmallHeapBlockT<TBlockAttributes>::GetMarkCountForSweep()
  848. {
  849. Assert(IsFreeBitsValid());
  850. // Make a local copy of mark bits, so we don't modify the actual mark bits.
  851. SmallHeapBlockBitVector temp;
  852. temp.Copy(this->GetMarkedBitVector());
  853. // Remove any invalid bits that may have been set
  854. temp.Minus(this->GetInvalidBitVector());
  855. // Remove the mark bit for things that are still free
  856. if (this->freeCount != 0)
  857. {
  858. temp.Minus(this->GetFreeBitVector());
  859. }
  860. return temp.Count();
  861. }
  862. template <class TBlockAttributes>
  863. SweepState
  864. SmallHeapBlockT<TBlockAttributes>::Sweep(RecyclerSweep& recyclerSweep, bool queuePendingSweep, bool allocable, ushort finalizeCount, bool hasPendingDispose)
  865. {
  866. Assert(this->address != nullptr);
  867. Assert(this->segment != nullptr);
  868. #if ENABLE_CONCURRENT_GC
  869. Assert(!this->isPendingConcurrentSweep);
  870. #endif
  871. DebugOnly(VerifyMarkBitVector());
  872. if (allocable)
  873. {
  874. // This block has been allocated from since the last GC.
  875. // We need to update its free bit vector so we can use it below.
  876. Assert(freeCount == this->GetFreeBitVector()->Count());
  877. #if ENABLE_PARTIAL_GC
  878. Assert(this->lastFreeCount == 0 || this->oldFreeCount == this->lastFreeCount);
  879. #endif
  880. this->EnsureFreeBitVector();
  881. Assert(this->lastFreeCount >= this->freeCount);
  882. #if ENABLE_PARTIAL_GC
  883. Assert(this->oldFreeCount >= this->freeCount);
  884. #endif
  885. #if ENABLE_PARTIAL_GC
  886. // Accounting for partial heuristics
  887. recyclerSweep.AddUnaccountedNewObjectAllocBytes(this);
  888. #endif
  889. }
  890. Assert(this->freeCount == this->GetFreeBitVector()->Count());
  891. RECYCLER_SLOW_CHECK(CheckFreeBitVector(true));
  892. const uint localMarkCount = this->GetMarkCountForSweep();
  893. this->markCount = (ushort)localMarkCount;
  894. Assert(markCount <= objectCount - this->freeCount);
  895. const uint expectFreeCount = objectCount - localMarkCount;
  896. Assert(expectFreeCount >= this->freeCount);
  897. const uint expectSweepCount = expectFreeCount - this->freeCount;
  898. Assert(!this->IsLeafBlock() || finalizeCount == 0);
  899. Recycler * recycler = recyclerSweep.GetRecycler();
  900. RECYCLER_STATS_INC(recycler, heapBlockCount[this->GetHeapBlockType()]);
  901. #if ENABLE_PARTIAL_GC
  902. if (recyclerSweep.DoAdjustPartialHeuristics() && allocable)
  903. {
  904. this->AdjustPartialUncollectedAllocBytes(recyclerSweep, expectSweepCount);
  905. }
  906. #endif
  907. DebugOnly(this->lastUncollectedAllocBytes = 0);
  908. bool noRealObjectsMarked = (localMarkCount == 0);
  909. const bool isAllFreed = (finalizeCount == 0 && noRealObjectsMarked && !hasPendingDispose);
  910. if (isAllFreed)
  911. {
  912. recycler->NotifyFree(this);
  913. Assert(!this->HasPendingDisposeObjects());
  914. return SweepStateEmpty;
  915. }
  916. RECYCLER_STATS_ADD(recycler, heapBlockFreeByteCount[this->GetHeapBlockType()], expectFreeCount * this->objectSize);
  917. Assert(!hasPendingDispose || (this->freeCount != 0));
  918. SweepState state = SweepStateSwept;
  919. if (hasPendingDispose)
  920. {
  921. state = SweepStatePendingDispose;
  922. }
  923. if (expectSweepCount == 0)
  924. {
  925. // nothing has been freed
  926. return (this->freeCount == 0) ? SweepStateFull : state;
  927. }
  928. RECYCLER_STATS_INC(recycler, heapBlockSweptCount[this->GetHeapBlockType()]);
  929. // We need to sweep in thread if there are any finalizable object.
  930. // So that the PrepareFinalize() can be called before concurrent sweep
  931. // and other finalizer. This gives the object an opportunity before any
  932. // other script can be ran to clean up their references/states that are not
  933. // valid since we determine the object is not live any more.
  934. //
  935. // An example is the ITrackable's tracking alias. The reference to the alias
  936. // object needs to be clear so that the reference will not be given out again
  937. // in other script during concurrent sweep or finalizer called before.
  938. #if ENABLE_CONCURRENT_GC
  939. if (queuePendingSweep)
  940. {
  941. Assert(finalizeCount == 0);
  942. Assert(!this->HasPendingDisposeObjects());
  943. recyclerSweep.SetHasPendingSweepSmallHeapBlocks();
  944. RECYCLER_STATS_INC(recycler, heapBlockConcurrentSweptCount[this->GetHeapBlockType()]);
  945. // This heap block has objects that need to be swept concurrently.
  946. this->isPendingConcurrentSweep = true;
  947. return SweepStatePendingSweep;
  948. }
  949. #else
  950. Assert(!recyclerSweep.IsBackground());
  951. #endif
  952. SweepObjects<SweepMode_InThread>(recycler);
  953. if (HasPendingDisposeObjects())
  954. {
  955. Assert(finalizeCount != 0);
  956. return SweepStatePendingDispose;
  957. }
  958. // Already swept, no more work to be done. Put it back to the queue
  959. return state;
  960. }
  961. #if DBG
  962. template <class TBlockAttributes>
  963. uint
  964. SmallHeapBlockT<TBlockAttributes>::GetMarkCountOnHeapBlockMap() const
  965. {
  966. uint heapBlockMapMarkCount = 0;
  967. char* startPage = this->GetAddress();
  968. char* endPage = this->GetEndAddress();
  969. const HeapBlockMap& blockMap = this->GetRecycler()->heapBlockMap;
  970. for (char* page = startPage; page < endPage; page += AutoSystemInfo::PageSize)
  971. {
  972. heapBlockMapMarkCount += blockMap.GetPageMarkCount(page);
  973. }
  974. return heapBlockMapMarkCount;
  975. }
  976. #endif
  977. template <class TBlockAttributes>
  978. template <SweepMode mode>
  979. void
  980. SmallHeapBlockT<TBlockAttributes>::SweepObjects(Recycler * recycler)
  981. {
  982. #if ENABLE_CONCURRENT_GC
  983. Assert(mode == SweepMode_InThread || this->isPendingConcurrentSweep);
  984. Assert(mode == SweepMode_InThread || !this->IsAnyFinalizableBlock());
  985. #else
  986. Assert(mode == SweepMode_InThread);
  987. #endif
  988. Assert(this->IsFreeBitsValid());
  989. Assert(this->markCount != 0 || this->isForceSweeping || this->IsAnyFinalizableBlock());
  990. Assert(this->markCount == this->GetMarkCountForSweep());
  991. DebugOnly(VerifyMarkBitVector());
  992. SmallHeapBlockBitVector * marked = this->GetMarkedBitVector();
  993. DebugOnly(const uint expectedSweepCount = objectCount - freeCount - markCount);
  994. Assert(expectedSweepCount != 0 || this->isForceSweeping);
  995. DebugOnly(uint sweepCount = 0);
  996. const uint localSize = objectSize;
  997. const uint localObjectCount = objectCount;
  998. const char* objectAddress = address;
  999. uint objectBitDelta = this->GetObjectBitDelta();
  1000. for (uint objectIndex = 0, bitIndex = 0; objectIndex < localObjectCount; objectIndex++, bitIndex += objectBitDelta)
  1001. {
  1002. Assert(IsValidBitIndex(bitIndex));
  1003. RECYCLER_STATS_ADD(recycler, objectSweepScanCount, !isForceSweeping);
  1004. if (!marked->Test(bitIndex))
  1005. {
  1006. if (!this->GetFreeBitVector()->Test(bitIndex))
  1007. {
  1008. Assert((this->ObjectInfo(objectIndex) & ImplicitRootBit) == 0);
  1009. FreeObject* addr = (FreeObject*)objectAddress;
  1010. #if ENABLE_PARTIAL_GC && ENABLE_CONCURRENT_GC
  1011. if (mode != SweepMode_ConcurrentPartial)
  1012. #endif
  1013. {
  1014. // Don't call NotifyFree if we are doing a partial sweep.
  1015. // Since we are not actually collecting the object, we will do the NotifyFree later
  1016. // when the object is actually collected in a future Sweep.
  1017. recycler->NotifyFree((char *)addr, this->objectSize);
  1018. }
  1019. #if DBG
  1020. sweepCount++;
  1021. #endif
  1022. SweepObject<mode>(recycler, objectIndex, addr);
  1023. }
  1024. }
  1025. #if DBG
  1026. if (marked->Test(bitIndex))
  1027. {
  1028. Assert((ObjectInfo(objectIndex) & NewTrackBit) == 0);
  1029. }
  1030. #endif
  1031. objectAddress += localSize;
  1032. }
  1033. Assert(sweepCount == expectedSweepCount);
  1034. #if ENABLE_CONCURRENT_GC
  1035. this->isPendingConcurrentSweep = false;
  1036. #endif
  1037. #if ENABLE_PARTIAL_GC && ENABLE_CONCURRENT_GC
  1038. if (mode == SweepMode_ConcurrentPartial)
  1039. {
  1040. Assert(recycler->inPartialCollectMode);
  1041. // We didn't actually collect anything, so the free bit vector should still be valid.
  1042. Assert(IsFreeBitsValid());
  1043. }
  1044. else
  1045. #endif
  1046. {
  1047. // Update the free bit vector
  1048. // Need to update even if there are not swept object because finalizable object are
  1049. // consider freed but not on the free list.
  1050. ushort currentFreeCount = GetExpectedFreeObjectCount();
  1051. this->GetFreeBitVector()->OrComplimented(marked);
  1052. this->GetFreeBitVector()->Minus(this->GetInvalidBitVector());
  1053. #if ENABLE_PARTIAL_GC
  1054. this->oldFreeCount = this->lastFreeCount = this->freeCount = currentFreeCount;
  1055. #else
  1056. this->lastFreeCount = this->freeCount = currentFreeCount;
  1057. #endif
  1058. this->lastFreeObjectHead = this->freeObjectList;
  1059. }
  1060. RECYCLER_SLOW_CHECK(CheckFreeBitVector(true));
  1061. // The count of marked, non-free objects should still be the same
  1062. Assert(this->markCount == this->GetMarkCountForSweep());
  1063. }
  1064. template <class TBlockAttributes>
  1065. void
  1066. SmallHeapBlockT<TBlockAttributes>::EnqueueProcessedObject(FreeObject ** list, void* objectAddress, uint index)
  1067. {
  1068. Assert(GetAddressIndex(objectAddress) == index);
  1069. Assert(index != SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit);
  1070. Assert(this->objectCount != 1);
  1071. #if DBG || defined(RECYCLER_STATS)
  1072. if (list == &this->freeObjectList)
  1073. {
  1074. BOOL isSet = this->GetDebugFreeBitVector()->TestAndSet(GetAddressBitIndex(objectAddress));
  1075. Assert(!isSet);
  1076. }
  1077. #endif
  1078. FillFreeMemory(objectAddress, objectSize);
  1079. FreeObject * freeObject = (FreeObject *)objectAddress;
  1080. freeObject->SetNext(*list);
  1081. *list = freeObject;
  1082. #if DBG
  1083. if (CONFIG_FLAG(ForceSoftwareWriteBarrier))
  1084. {
  1085. this->WBClearBits((char*)objectAddress);
  1086. }
  1087. #endif
  1088. // clear the attributes so that when we are allocating a leaf, we don't have to set the attribute
  1089. this->ObjectInfo(index) = 0;
  1090. }
  1091. template <class TBlockAttributes>
  1092. void
  1093. SmallHeapBlockT<TBlockAttributes>::EnqueueProcessedObject(FreeObject ** list, FreeObject ** tail, void* objectAddress, uint index)
  1094. {
  1095. if (*tail == nullptr)
  1096. {
  1097. Assert(*list == nullptr);
  1098. *tail = (FreeObject *)objectAddress;
  1099. }
  1100. EnqueueProcessedObject(list, objectAddress, index);
  1101. }
  1102. //
  1103. // This method transfers the list of objects starting at list and ending
  1104. // at tail to the free list.
  1105. // In debug mode, it also makes sure that none of the objects that are
  1106. // being prepended to the free list are already free
  1107. //
  1108. template <class TBlockAttributes>
  1109. void
  1110. SmallHeapBlockT<TBlockAttributes>::TransferProcessedObjects(FreeObject * list, FreeObject * tail)
  1111. {
  1112. Assert(tail != nullptr);
  1113. Assert(list);
  1114. #if DBG || defined(RECYCLER_STATS)
  1115. // make sure that object we are transferred to the free list are not freed yet
  1116. tail->SetNext(nullptr);
  1117. FreeObject * freeObject = list;
  1118. while (freeObject != nullptr)
  1119. {
  1120. Assert(!this->IsInFreeObjectList(freeObject));
  1121. BOOL isSet = this->GetDebugFreeBitVector()->TestAndSet(GetAddressBitIndex(freeObject));
  1122. Assert(!isSet);
  1123. freeObject = freeObject->GetNext();
  1124. }
  1125. #endif
  1126. tail->SetNext(this->freeObjectList);
  1127. this->freeObjectList = list;
  1128. RECYCLER_SLOW_CHECK(this->CheckDebugFreeBitVector(true));
  1129. }
  1130. template <class TBlockAttributes>
  1131. uint
  1132. SmallHeapBlockT<TBlockAttributes>::GetAndClearLastFreeCount()
  1133. {
  1134. uint lastFreeCount = this->lastFreeCount;
  1135. this->lastFreeCount = 0;
  1136. return lastFreeCount;
  1137. }
  1138. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  1139. template <class TBlockAttributes>
  1140. void
  1141. SmallHeapBlockT<TBlockAttributes>::Check(bool expectFull, bool expectPending)
  1142. {
  1143. if (this->IsFreeBitsValid())
  1144. {
  1145. CheckFreeBitVector(false);
  1146. }
  1147. else
  1148. {
  1149. CheckDebugFreeBitVector(false);
  1150. }
  1151. Assert(expectPending == HasAnyDisposeObjects());
  1152. if (this->isInAllocator || this->isClearedFromAllocator)
  1153. {
  1154. Assert(expectFull && !expectPending);
  1155. }
  1156. else
  1157. {
  1158. Assert(expectFull == (!this->HasFreeObject() && !HasAnyDisposeObjects()));
  1159. }
  1160. }
  1161. template <class TBlockAttributes>
  1162. template <typename TBlockType>
  1163. bool
  1164. SmallHeapBlockT<TBlockAttributes>::GetFreeObjectListOnAllocatorImpl(FreeObject ** freeObjectList)
  1165. {
  1166. // not during collection, the allocator has the current info
  1167. SmallHeapBlockAllocator<TBlockType> * head =
  1168. &((HeapBucketT<TBlockType> *)this->heapBucket)->allocatorHead;
  1169. SmallHeapBlockAllocator<TBlockType> * current = head;
  1170. do
  1171. {
  1172. if (current->GetHeapBlock() == this)
  1173. {
  1174. if (current->IsFreeListAllocMode())
  1175. {
  1176. *freeObjectList = current->freeObjectList;
  1177. return true;
  1178. }
  1179. return false;
  1180. }
  1181. current = current->GetNext();
  1182. }
  1183. while (current != head);
  1184. return false;
  1185. }
  1186. template <class TBlockAttributes>
  1187. void
  1188. SmallHeapBlockT<TBlockAttributes>::CheckDebugFreeBitVector(bool isCollecting)
  1189. {
  1190. FreeObject * freeObject = this->freeObjectList;
  1191. if (!isCollecting)
  1192. {
  1193. this->GetFreeObjectListOnAllocator(&freeObject);
  1194. }
  1195. uint verifyFreeCount = 0;
  1196. while (freeObject != nullptr)
  1197. {
  1198. uint index = this->GetAddressIndex(freeObject);
  1199. Assert(index != SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit);
  1200. Assert(this->GetDebugFreeBitVector()->Test(GetAddressBitIndex(freeObject)));
  1201. verifyFreeCount++;
  1202. freeObject = freeObject->GetNext();
  1203. }
  1204. Assert(this->GetDebugFreeBitVector()->Count() == verifyFreeCount);
  1205. Assert(verifyFreeCount <= this->lastFreeCount);
  1206. }
  1207. template <class TBlockAttributes>
  1208. void
  1209. SmallHeapBlockT<TBlockAttributes>::CheckFreeBitVector(bool isCollecting)
  1210. {
  1211. // during collection, the heap block has the current info when we are verifying
  1212. if (!isCollecting)
  1213. {
  1214. FreeObject * freeObjectList;
  1215. this->GetFreeObjectListOnAllocator(&freeObjectList);
  1216. if (freeObjectList != this->freeObjectList)
  1217. {
  1218. // allocator has the current info and if we have already allocated some memory,
  1219. // the free bit vector isn't really correct, so we can't verify it.
  1220. // Just verify the debug free bit vector
  1221. this->CheckDebugFreeBitVector(false);
  1222. return;
  1223. }
  1224. }
  1225. SmallHeapBlockBitVector * free = this->GetFreeBitVector();
  1226. // Shouldn't be any invalid bits set in the free bit vector
  1227. SmallHeapBlockBitVector temp;
  1228. temp.Copy(free);
  1229. temp.And(this->GetInvalidBitVector());
  1230. Assert(temp.IsAllClear());
  1231. uint verifyFreeCount = 0;
  1232. FreeObject * freeObject = this->freeObjectList;
  1233. while (freeObject != nullptr)
  1234. {
  1235. uint bitIndex = GetAddressBitIndex(freeObject);
  1236. Assert(IsValidBitIndex(bitIndex));
  1237. Assert(this->GetDebugFreeBitVector()->Test(bitIndex));
  1238. Assert(free->Test(bitIndex));
  1239. verifyFreeCount++;
  1240. freeObject = freeObject->GetNext();
  1241. }
  1242. Assert(this->GetDebugFreeBitVector()->Count() == verifyFreeCount);
  1243. Assert(this->freeCount == this->GetFreeBitVector()->Count());
  1244. if (this->IsAnyFinalizableBlock())
  1245. {
  1246. auto finalizableBlock = this->AsFinalizableBlock<TBlockAttributes>();
  1247. // Include pending dispose objects
  1248. finalizableBlock->ForEachPendingDisposeObject([&] (uint index) {
  1249. uint bitIndex = ((uint)index) * this->GetObjectBitDelta();
  1250. Assert(IsValidBitIndex(bitIndex));
  1251. Assert(!this->GetDebugFreeBitVector()->Test(bitIndex));
  1252. Assert(free->Test(bitIndex));
  1253. verifyFreeCount++;
  1254. });
  1255. // Include disposed objects
  1256. verifyFreeCount += finalizableBlock->CheckDisposedObjectFreeBitVector();
  1257. }
  1258. Assert(verifyFreeCount == this->freeCount);
  1259. Assert(verifyFreeCount <= this->lastFreeCount);
  1260. Assert(this->IsFreeBitsValid());
  1261. }
  1262. #endif
  1263. template <class TBlockAttributes>
  1264. typename SmallHeapBlockT<TBlockAttributes>::SmallHeapBlockBitVector *
  1265. SmallHeapBlockT<TBlockAttributes>::EnsureFreeBitVector()
  1266. {
  1267. if (this->IsFreeBitsValid())
  1268. {
  1269. // the free object list hasn't change, so the free vector should be valid
  1270. RECYCLER_SLOW_CHECK(CheckFreeBitVector(true));
  1271. return this->GetFreeBitVector();
  1272. }
  1273. return BuildFreeBitVector();
  1274. }
  1275. template <class TBlockAttributes>
  1276. typename SmallHeapBlockT<TBlockAttributes>::SmallHeapBlockBitVector *
  1277. SmallHeapBlockT<TBlockAttributes>::BuildFreeBitVector()
  1278. {
  1279. SmallHeapBlockBitVector * free = this->GetFreeBitVector();
  1280. this->freeCount = this->BuildFreeBitVector(free);
  1281. this->lastFreeObjectHead = this->freeObjectList;
  1282. return free;
  1283. }
  1284. template <class TBlockAttributes>
  1285. ushort
  1286. SmallHeapBlockT<TBlockAttributes>::BuildFreeBitVector(SmallHeapBlockBitVector * free)
  1287. {
  1288. free->ClearAll();
  1289. ushort freeCount = 0;
  1290. FreeObject * freeObject = this->freeObjectList;
  1291. while (freeObject != nullptr)
  1292. {
  1293. uint bitIndex = GetAddressBitIndex(freeObject);
  1294. Assert(IsValidBitIndex(bitIndex));
  1295. Assert(this->GetDebugFreeBitVector()->Test(bitIndex));
  1296. free->Set(bitIndex);
  1297. freeCount++;
  1298. freeObject = freeObject->GetNext();
  1299. }
  1300. Assert(this->GetDebugFreeBitVector()->Count() == freeCount);
  1301. if (this->IsAnyFinalizableBlock())
  1302. {
  1303. auto finalizableBlock = this->AsFinalizableBlock<TBlockAttributes>();
  1304. // Include pending dispose objects
  1305. finalizableBlock->ForEachPendingDisposeObject([&] (uint index) {
  1306. uint bitIndex = ((uint)index) * this->GetObjectBitDelta();
  1307. Assert(IsValidBitIndex(bitIndex));
  1308. Assert(!this->GetDebugFreeBitVector()->Test(bitIndex));
  1309. free->Set(bitIndex);
  1310. freeCount++;
  1311. });
  1312. // Include disposed objects
  1313. freeCount += finalizableBlock->AddDisposedObjectFreeBitVector(free);
  1314. }
  1315. Assert(freeCount <= this->lastFreeCount);
  1316. return freeCount;
  1317. }
  1318. template <class TBlockAttributes>
  1319. void
  1320. SmallHeapBlockT<TBlockAttributes>::MarkImplicitRoots()
  1321. {
  1322. uint localObjectCount = this->GetObjectCount();
  1323. uint localObjectBitDelta = this->GetObjectBitDelta();
  1324. uint localMarkCount = 0;
  1325. SmallHeapBlockBitVector * mark = this->GetMarkedBitVector();
  1326. #if DBG
  1327. uint localObjectSize = this->GetObjectSize();
  1328. Assert(localObjectSize <= HeapConstants::MaxMediumObjectSize);
  1329. ushort markCountPerPage[TBlockAttributes::PageCount];
  1330. for (uint i = 0; i < TBlockAttributes::PageCount; i++)
  1331. {
  1332. markCountPerPage[i] = 0;
  1333. }
  1334. #endif
  1335. for (uint i = 0; i < localObjectCount; i++)
  1336. {
  1337. // REVIEW: This may include free object. It is okay to mark them and scan them
  1338. // But kind inefficient.
  1339. if (this->ObjectInfo(i) & ImplicitRootBit)
  1340. {
  1341. #if DBG
  1342. {
  1343. int index = (i * localObjectSize) / AutoSystemInfo::PageSize;
  1344. Assert(index < TBlockAttributes::PageCount);
  1345. markCountPerPage[index]++;
  1346. }
  1347. #endif
  1348. mark->Set(localObjectBitDelta * i);
  1349. localMarkCount++;
  1350. }
  1351. }
  1352. Assert(mark->Count() == localMarkCount);
  1353. this->markCount = (ushort)localMarkCount;
  1354. #if DBG
  1355. HeapBlockMap& map = this->GetRecycler()->heapBlockMap;
  1356. for (uint i = 0; i < TBlockAttributes::PageCount; i++)
  1357. {
  1358. map.SetPageMarkCount(this->address + (i * AutoSystemInfo::PageSize), markCountPerPage[i]);
  1359. }
  1360. #endif
  1361. }
  1362. template <class TBlockAttributes>
  1363. void
  1364. SmallHeapBlockT<TBlockAttributes>::EnumerateObjects(ObjectInfoBits infoBits, void (*CallBackFunction)(void * address, size_t size))
  1365. {
  1366. ForEachAllocatedObject(infoBits, [=](uint index, void * objectAddress)
  1367. {
  1368. CallBackFunction(objectAddress, this->objectSize);
  1369. });
  1370. }
  1371. template <class TBlockAttributes>
  1372. inline
  1373. void SmallHeapBlockT<TBlockAttributes>::FillFreeMemory(__in_bcount(size) void * address, size_t size)
  1374. {
  1375. #ifdef RECYCLER_MEMORY_VERIFY
  1376. if (this->heapBucket->heapInfo->recycler->VerifyEnabled())
  1377. {
  1378. memset(address, Recycler::VerifyMemFill, size);
  1379. return;
  1380. }
  1381. #endif
  1382. if (this->IsLeafBlock()
  1383. #ifdef RECYCLER_WRITE_BARRIER_ALLOC_THREAD_PAGE
  1384. || this->IsWithBarrier()
  1385. #endif
  1386. )
  1387. {
  1388. return;
  1389. }
  1390. // REVIEW: Do DbgMemFill on debug build?
  1391. #if defined(_M_IX86)
  1392. uint qwordCount = size / sizeof(uint64) ;
  1393. switch (qwordCount)
  1394. {
  1395. case 2:
  1396. ((uint64*)address)[0] = 0;
  1397. ((uint64*)address)[1] = 0;
  1398. break;
  1399. case 4:
  1400. ((uint64*)address)[0] = 0;
  1401. ((uint64*)address)[1] = 0;
  1402. ((uint64*)address)[2] = 0;
  1403. ((uint64*)address)[3] = 0;
  1404. break;
  1405. case 6:
  1406. ((uint64*)address)[0] = 0;
  1407. ((uint64*)address)[1] = 0;
  1408. ((uint64*)address)[2] = 0;
  1409. ((uint64*)address)[3] = 0;
  1410. ((uint64*)address)[4] = 0;
  1411. ((uint64*)address)[5] = 0;
  1412. break;
  1413. default:
  1414. memset(address, 0, size);
  1415. }
  1416. #else
  1417. memset(address, 0, size);
  1418. #endif
  1419. }
  1420. #ifdef RECYCLER_MEMORY_VERIFY
  1421. template <class TBlockAttributes>
  1422. void SmallHeapBlockT<TBlockAttributes>::VerifyBumpAllocated(_In_ char * bumpAllocateAddress)
  1423. {
  1424. ushort verifyFinalizeCount = 0;
  1425. Recycler * recycler = this->heapBucket->heapInfo->recycler;
  1426. char * memBlock = this->GetAddress();
  1427. for (uint i = 0; i < objectCount; i++)
  1428. {
  1429. if (memBlock >= bumpAllocateAddress)
  1430. {
  1431. Recycler::VerifyCheckFill(memBlock + sizeof(FreeObject), this->GetObjectSize() - sizeof(FreeObject));
  1432. }
  1433. else
  1434. {
  1435. recycler->VerifyCheckPad(memBlock, this->GetObjectSize());
  1436. if ((this->ObjectInfo(i) & FinalizeBit) != 0)
  1437. {
  1438. if (this->IsAnyFinalizableBlock())
  1439. {
  1440. verifyFinalizeCount++;
  1441. }
  1442. else
  1443. {
  1444. Recycler::VerifyCheck(false, _u("Non-Finalizable block should not have finalizable objects"),
  1445. this->GetAddress(), &this->ObjectInfo(i));
  1446. }
  1447. }
  1448. }
  1449. memBlock += this->GetObjectSize();
  1450. }
  1451. }
  1452. template <class TBlockAttributes>
  1453. void SmallHeapBlockT<TBlockAttributes>::Verify(bool pendingDispose)
  1454. {
  1455. ushort verifyFinalizeCount = 0;
  1456. SmallHeapBlockBitVector tempFree;
  1457. SmallHeapBlockBitVector *free = &tempFree;
  1458. SmallHeapBlockBitVector tempPending;
  1459. this->BuildFreeBitVector(free);
  1460. Recycler * recycler = this->heapBucket->heapInfo->recycler;
  1461. char * memBlock = this->GetAddress();
  1462. uint objectBitDelta = this->GetObjectBitDelta();
  1463. Recycler::VerifyCheck(!pendingDispose || this->IsAnyFinalizableBlock(),
  1464. _u("Non-finalizable block shouldn't be disposing. May have corrupted block type."),
  1465. this->GetAddress(), (void *)&this->heapBlockType);
  1466. if (HasPendingDisposeObjects())
  1467. {
  1468. Assert(pendingDispose);
  1469. // Pending object are not free yet, they don't have memory cleared.
  1470. this->AsFinalizableBlock<TBlockAttributes>()->ForEachPendingDisposeObject([&](uint index) {
  1471. uint bitIndex = ((uint)index) * this->GetObjectBitDelta();
  1472. Assert(IsValidBitIndex(bitIndex));
  1473. Assert(!this->GetDebugFreeBitVector()->Test(bitIndex));
  1474. Assert(free->Test(bitIndex));
  1475. tempPending.Set(bitIndex);
  1476. // We are a pending dispose block, so the finalize count hasn't been update yet.
  1477. // Including the pending objects in the finalize count
  1478. verifyFinalizeCount++;
  1479. });
  1480. }
  1481. for (uint i = 0; i < objectCount; i++)
  1482. {
  1483. if (free->Test(i * objectBitDelta))
  1484. {
  1485. if (!tempPending.Test(i * objectBitDelta))
  1486. {
  1487. char * nextFree = (char *)((FreeObject *)memBlock)->GetNext();
  1488. Recycler::VerifyCheck(nextFree == nullptr
  1489. || (nextFree >= address && nextFree < this->GetEndAddress()
  1490. && free->Test(GetAddressBitIndex(nextFree))),
  1491. _u("SmallHeapBlock memory written to after freed"), memBlock, memBlock);
  1492. Recycler::VerifyCheckFill(memBlock + sizeof(FreeObject), this->GetObjectSize() - sizeof(FreeObject));
  1493. }
  1494. }
  1495. else
  1496. {
  1497. if (explicitFreeBits.Test(i * objectBitDelta))
  1498. {
  1499. char * nextFree = (char *)((FreeObject *)memBlock)->GetNext();
  1500. HeapBlock* nextFreeHeapBlock = this;
  1501. if (nextFree != nullptr)
  1502. {
  1503. nextFreeHeapBlock = recycler->FindHeapBlock(nextFree);
  1504. }
  1505. Recycler::VerifyCheck(nextFree == nullptr
  1506. || (nextFree >= address && nextFree < this->GetEndAddress()
  1507. && explicitFreeBits.Test(GetAddressBitIndex(nextFree)))
  1508. || nextFreeHeapBlock->GetObjectSize(nextFree) == this->objectSize,
  1509. _u("SmallHeapBlock memory written to after freed"), memBlock, memBlock);
  1510. recycler->VerifyCheckPadExplicitFreeList(memBlock, this->GetObjectSize());
  1511. }
  1512. else
  1513. {
  1514. recycler->VerifyCheckPad(memBlock, this->GetObjectSize());
  1515. }
  1516. if ((this->ObjectInfo(i) & FinalizeBit) != 0)
  1517. {
  1518. if (this->IsAnyFinalizableBlock())
  1519. {
  1520. verifyFinalizeCount++;
  1521. }
  1522. else
  1523. {
  1524. Recycler::VerifyCheck(false, _u("Non-Finalizable block should not have finalizable objects"),
  1525. this->GetAddress(), &this->ObjectInfo(i));
  1526. }
  1527. }
  1528. }
  1529. memBlock += this->GetObjectSize();
  1530. }
  1531. if (this->IsAnyFinalizableBlock())
  1532. {
  1533. Recycler::VerifyCheck(this->AsFinalizableBlock<TBlockAttributes>()->finalizeCount == verifyFinalizeCount,
  1534. _u("SmallHeapBlock finalize count mismatch"), this->GetAddress(), &this->AsFinalizableBlock<TBlockAttributes>()->finalizeCount);
  1535. }
  1536. else
  1537. {
  1538. Assert(verifyFinalizeCount == 0);
  1539. }
  1540. }
  1541. #endif
  1542. #ifdef DUMP_FRAGMENTATION_STATS
  1543. template <class TBlockAttributes>
  1544. void
  1545. SmallHeapBlockT<TBlockAttributes>::AggregateBlockStats(HeapBucketStats& stats, bool isAllocatorBlock, FreeObject* freeObjectList, bool isBumpAllocated)
  1546. {
  1547. stats.totalBlockCount++;
  1548. ushort blockObjectCount = this->objectCount;
  1549. BVIndex blockFreeCount = this->GetFreeBitVector()->Count();
  1550. ushort blockObjectSize = this->objectSize;
  1551. if (this->segment == nullptr)
  1552. {
  1553. stats.emptyBlockCount++;
  1554. blockObjectCount = 0;
  1555. blockFreeCount = 0;
  1556. }
  1557. int objectCount = 0;
  1558. if (isBumpAllocated)
  1559. {
  1560. objectCount = ((char*) freeObjectList - this->address) / blockObjectSize;
  1561. }
  1562. else
  1563. {
  1564. objectCount = blockObjectCount;
  1565. // If this is an allocator block, remove the free objects on the allocator
  1566. // from this count. Otherwise, remove the free objects found in the free bit vector
  1567. if (freeObjectList)
  1568. {
  1569. Assert(isAllocatorBlock);
  1570. FreeObject* next = freeObjectList->GetNext();
  1571. while (next != nullptr && next != freeObjectList)
  1572. {
  1573. objectCount--;
  1574. next = next->GetNext();
  1575. }
  1576. }
  1577. else
  1578. {
  1579. objectCount -= blockFreeCount;
  1580. }
  1581. }
  1582. // If we have a block that's on the allocator, it could also be on the heap block list
  1583. // In that case, we need to make sure we don't double-count this. To do that, we take out
  1584. // the block's allocatorCount/freeCount and adjust it later when we see the block
  1585. if (isAllocatorBlock)
  1586. {
  1587. objectCount -= blockObjectCount;
  1588. objectCount += blockFreeCount;
  1589. }
  1590. // Don't count empty blocks as allocable
  1591. if (this->segment != nullptr)
  1592. {
  1593. stats.totalByteCount += AutoSystemInfo::PageSize;
  1594. }
  1595. stats.objectCount += objectCount;
  1596. stats.objectByteCount += (objectCount * blockObjectSize);
  1597. if (!isAllocatorBlock)
  1598. {
  1599. if (this->IsAnyFinalizableBlock())
  1600. {
  1601. SmallFinalizableHeapBlock* finalizableBlock = this->AsFinalizableBlock<TBlockAttributes>();
  1602. stats.finalizeBlockCount++;
  1603. stats.finalizeCount += (finalizableBlock->GetFinalizeCount());
  1604. }
  1605. }
  1606. }
  1607. #endif
  1608. #ifdef RECYCLER_PERF_COUNTERS
  1609. template <class TBlockAttributes>
  1610. void
  1611. SmallHeapBlockT<TBlockAttributes>::UpdatePerfCountersOnFree()
  1612. {
  1613. Assert(markCount == 0);
  1614. Assert(this->IsFreeBitsValid());
  1615. size_t usedCount = (objectCount - freeCount);
  1616. size_t usedBytes = usedCount * objectSize;
  1617. RECYCLER_PERF_COUNTER_SUB(SmallHeapBlockLiveObject, usedCount);
  1618. RECYCLER_PERF_COUNTER_SUB(SmallHeapBlockLiveObjectSize, usedBytes);
  1619. RECYCLER_PERF_COUNTER_SUB(SmallHeapBlockFreeObjectSize, this->GetPageCount() * AutoSystemInfo::PageSize - usedBytes);
  1620. RECYCLER_PERF_COUNTER_SUB(LiveObject, usedCount);
  1621. RECYCLER_PERF_COUNTER_SUB(LiveObjectSize, usedBytes);
  1622. RECYCLER_PERF_COUNTER_SUB(FreeObjectSize, this->GetPageCount() * AutoSystemInfo::PageSize - usedBytes);
  1623. }
  1624. #endif
  1625. #ifdef PROFILE_RECYCLER_ALLOC
  1626. template <class TBlockAttributes>
  1627. void *
  1628. SmallHeapBlockT<TBlockAttributes>::GetTrackerData(void * address)
  1629. {
  1630. Assert(Recycler::DoProfileAllocTracker());
  1631. ushort index = this->GetAddressIndex(address);
  1632. Assert(index != SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit);
  1633. return this->GetTrackerDataArray()[index];
  1634. }
  1635. template <class TBlockAttributes>
  1636. void
  1637. SmallHeapBlockT<TBlockAttributes>::SetTrackerData(void * address, void * data)
  1638. {
  1639. Assert(Recycler::DoProfileAllocTracker());
  1640. ushort index = this->GetAddressIndex(address);
  1641. Assert(index != SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit);
  1642. void* existingTrackerData = this->GetTrackerDataArray()[index];
  1643. Assert((existingTrackerData == nullptr || data == nullptr) ||
  1644. (existingTrackerData == &Recycler::TrackerData::ExplicitFreeListObjectData || data == &Recycler::TrackerData::ExplicitFreeListObjectData));
  1645. this->GetTrackerDataArray()[index] = data;
  1646. }
  1647. template <class TBlockAttributes>
  1648. void **
  1649. SmallHeapBlockT<TBlockAttributes>::GetTrackerDataArray()
  1650. {
  1651. // See SmallHeapBlockT<TBlockAttributes>::GetAllocPlusSize for layout description
  1652. return (void **)((char *)this - SmallHeapBlockT<TBlockAttributes>::GetAllocPlusSize(this->objectCount));
  1653. }
  1654. #endif
  1655. #ifdef RECYCLER_WRITE_BARRIER
  1656. template <class TBlockAttributes>
  1657. bool
  1658. SmallHeapBlockT<TBlockAttributes>::IsWithBarrier() const
  1659. {
  1660. return IsNormalWriteBarrierBlock() || IsFinalizableWriteBarrierBlock();
  1661. }
  1662. #endif
  1663. namespace Memory
  1664. {
  1665. // Instantiate the template
  1666. template class SmallHeapBlockT<SmallAllocationBlockAttributes>;
  1667. template class SmallHeapBlockT<MediumAllocationBlockAttributes>;
  1668. };
  1669. #define TBlockTypeAttributes SmallAllocationBlockAttributes
  1670. #include "SmallBlockDeclarations.inl"
  1671. #undef TBlockTypeAttributes
  1672. #define TBlockTypeAttributes MediumAllocationBlockAttributes
  1673. #include "SmallBlockDeclarations.inl"
  1674. #undef TBlockTypeAttributes