LargeHeapBucket.cpp 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153
  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. //=====================================================================================================
  7. // Initialization
  8. //=====================================================================================================
  9. LargeHeapBucket::~LargeHeapBucket()
  10. {
  11. Recycler* recycler = this->heapInfo->recycler;
  12. HeapInfo* autoHeap = this->heapInfo;
  13. ForEachEditingLargeHeapBlock([recycler, autoHeap](LargeHeapBlock * heapBlock)
  14. {
  15. heapBlock->ReleasePagesShutdown(recycler);
  16. LargeHeapBlock::Delete(heapBlock);
  17. RECYCLER_SLOW_CHECK(autoHeap->heapBlockCount[HeapBlock::HeapBlockType::LargeBlockType]--);
  18. });
  19. }
  20. void
  21. LargeHeapBucket::Initialize(HeapInfo * heapInfo, uint sizeCat, bool supportFreeList)
  22. {
  23. this->heapInfo = heapInfo;
  24. this->sizeCat = sizeCat;
  25. #ifdef RECYCLER_PAGE_HEAP
  26. this->isPageHeapEnabled = heapInfo->IsPageHeapEnabledForBlock<LargeAllocationBlockAttributes>(sizeCat);
  27. #endif
  28. this->supportFreeList = supportFreeList;
  29. }
  30. //=====================================================================================================
  31. // Allocation
  32. //=====================================================================================================
  33. char *
  34. LargeHeapBucket::TryAllocFromNewHeapBlock(Recycler * recycler, size_t sizeCat, size_t size, ObjectInfoBits attributes, bool nothrow)
  35. {
  36. Assert((attributes & InternalObjectInfoBitMask) == attributes);
  37. #ifdef RECYCLER_PAGE_HEAP
  38. if (IsPageHeapEnabled(attributes))
  39. {
  40. return this->PageHeapAlloc(recycler, sizeCat, size, attributes, this->heapInfo->pageHeapMode, true);
  41. }
  42. #endif
  43. LargeHeapBlock * heapBlock = AddLargeHeapBlock(sizeCat, nothrow);
  44. if (heapBlock == nullptr)
  45. {
  46. return nullptr;
  47. }
  48. char * memBlock = heapBlock->Alloc(sizeCat, attributes);
  49. Assert(memBlock != nullptr);
  50. return memBlock;
  51. }
  52. char *
  53. LargeHeapBucket::SnailAlloc(Recycler * recycler, size_t sizeCat, size_t size, ObjectInfoBits attributes, bool nothrow)
  54. {
  55. char * memBlock;
  56. Assert((attributes & InternalObjectInfoBitMask) == attributes);
  57. // No free memory, try to collect with allocated bytes and time heuristic, and concurrently
  58. #if ENABLE_CONCURRENT_GC
  59. BOOL collected = recycler->disableCollectOnAllocationHeuristics ? recycler->FinishConcurrent<FinishConcurrentOnAllocation>() :
  60. recycler->CollectNow<CollectOnAllocation>();
  61. #else
  62. BOOL collected = recycler->disableCollectOnAllocationHeuristics ? FALSE : recycler->CollectNow<CollectOnAllocation>();
  63. #endif
  64. if (!collected)
  65. {
  66. memBlock = TryAllocFromNewHeapBlock(recycler, sizeCat, size, attributes, nothrow);
  67. if (memBlock != nullptr)
  68. {
  69. return memBlock;
  70. }
  71. // Can't even allocate a new block, we need force a collection and
  72. // allocate some free memory, add a new heap block again, or throw out of memory
  73. AllocationVerboseTrace(recycler->GetRecyclerFlagsTable(), _u("LargeHeapBucket::AddLargeHeapBlock failed, forcing in-thread collection\n"));
  74. recycler->CollectNow<CollectNowForceInThread>();
  75. }
  76. memBlock = TryAlloc(recycler, sizeCat, attributes);
  77. if (memBlock != nullptr)
  78. {
  79. return memBlock;
  80. }
  81. memBlock = TryAllocFromNewHeapBlock(recycler, sizeCat, size, attributes, nothrow);
  82. if (memBlock != nullptr)
  83. {
  84. return memBlock;
  85. }
  86. if (nothrow == false)
  87. {
  88. // Can't add a heap block, we are out of memory
  89. // Since nothrow is false, we can throw right here
  90. recycler->OutOfMemory();
  91. }
  92. return nullptr;
  93. }
  94. #ifdef RECYCLER_PAGE_HEAP
  95. char*
  96. LargeHeapBucket::PageHeapAlloc(Recycler * recycler, size_t sizeCat, size_t size, ObjectInfoBits attributes, PageHeapMode mode, bool nothrow)
  97. {
  98. auto throwOrReturn = [&](char* memBlock) ->char*
  99. {
  100. if (memBlock==nullptr && !nothrow)
  101. {
  102. recycler->OutOfMemory();
  103. }
  104. return memBlock;
  105. };
  106. PageHeapData* pageHeapData = NoMemProtectHeapNewNoThrowZ(PageHeapData);
  107. if (pageHeapData == nullptr)
  108. {
  109. return throwOrReturn(nullptr);
  110. }
  111. if (size < sizeof(void*))
  112. {
  113. attributes = (ObjectInfoBits)(attributes | LeafBit);
  114. }
  115. #ifdef RECYCLER_MEMORY_VERIFY
  116. if (recycler->VerifyEnabled())
  117. {
  118. // with recycler verify enabled, it uses the unaligned bytes
  119. size = sizeCat;
  120. }
  121. #endif
  122. size_t pageCount = LargeHeapBlock::GetPagesNeeded(size, false);
  123. Assert(pageCount != 0);
  124. size_t actualPageCount = pageCount + 1; // 1 for guard page
  125. auto pageAllocator = heapInfo->GetRecyclerLargeBlockPageAllocator();
  126. Segment * segment;
  127. char * baseAddress = pageAllocator->Alloc(&actualPageCount, &segment);
  128. Assert((size_t)baseAddress%AutoSystemInfo::PageSize == 0);
  129. if (baseAddress == nullptr)
  130. {
  131. NoMemProtectHeapDelete(pageHeapData);
  132. return throwOrReturn(nullptr);
  133. }
  134. size_t guardPageCount = actualPageCount - pageCount; // pageAllocator can return more than asked pages
  135. char* headerAddress = nullptr;
  136. char* guardPageAddress = nullptr;
  137. size_t sizeWithHeader = size + sizeof(LargeObjectHeader);
  138. pageHeapData->pageHeapMode = heapInfo->pageHeapMode;
  139. if (pageHeapData->pageHeapMode == PageHeapMode::PageHeapModeBlockStart)
  140. {
  141. headerAddress = baseAddress + AutoSystemInfo::PageSize * guardPageCount;
  142. guardPageAddress = baseAddress;
  143. pageHeapData->paddingBytes = 0;
  144. pageHeapData->unusedBytes = (AutoSystemInfo::PageSize - (sizeWithHeader%AutoSystemInfo::PageSize)) % AutoSystemInfo::PageSize;
  145. pageHeapData->objectPageAddr = headerAddress;
  146. }
  147. else if (pageHeapData->pageHeapMode == PageHeapMode::PageHeapModeBlockEnd)
  148. {
  149. pageHeapData->unusedBytes = (HeapConstants::ObjectGranularity - (sizeWithHeader%HeapConstants::ObjectGranularity)) % HeapConstants::ObjectGranularity;
  150. pageHeapData->paddingBytes = (ushort)((AutoSystemInfo::PageSize - pageHeapData->unusedBytes - sizeWithHeader%AutoSystemInfo::PageSize) % AutoSystemInfo::PageSize);
  151. Assert(pageHeapData->paddingBytes%HeapConstants::ObjectGranularity == 0);
  152. headerAddress = baseAddress + pageHeapData->paddingBytes;
  153. guardPageAddress = baseAddress + pageCount * AutoSystemInfo::PageSize;
  154. pageHeapData->objectPageAddr = baseAddress;
  155. }
  156. else
  157. {
  158. AnalysisAssert(false);
  159. }
  160. LargeHeapBlock * heapBlock = LargeHeapBlock::New(headerAddress, pageCount, segment, 1, this);
  161. if (!heapBlock)
  162. {
  163. pageAllocator->SuspendIdleDecommit();
  164. pageAllocator->Release(baseAddress, actualPageCount, segment);
  165. pageAllocator->ResumeIdleDecommit();
  166. NoMemProtectHeapDelete(pageHeapData);
  167. return throwOrReturn(nullptr);
  168. }
  169. // adjust the addressEnd
  170. if (pageHeapData->pageHeapMode == PageHeapMode::PageHeapModeBlockStart)
  171. {
  172. heapBlock->addressEnd = baseAddress + AutoSystemInfo::PageSize * actualPageCount;
  173. }
  174. else
  175. {
  176. heapBlock->addressEnd = baseAddress + AutoSystemInfo::PageSize * pageCount;
  177. }
  178. pageHeapData->actualPageCount = (uint)actualPageCount;
  179. pageHeapData->guardPageAddress = guardPageAddress;
  180. heapBlock->heapInfo = this->heapInfo;
  181. heapBlock->pageHeapData = pageHeapData;
  182. bool decommitGuardPage = true;
  183. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  184. decommitGuardPage = this->GetRecycler()->GetRecyclerFlagsTable().PageHeapDecommitGuardPage;
  185. #if defined(RECYCLER_NO_PAGE_REUSE)
  186. decommitGuardPage |= heapBlock->GetPageAllocator(heapInfo)->IsPageReuseDisabled();
  187. #endif
  188. #endif
  189. if (decommitGuardPage)
  190. {
  191. #pragma prefast(suppress:6250, "Calling 'VirtualFree' without the MEM_RELEASE flag might free memory but not address descriptors (VADs).")
  192. if (VirtualFree(guardPageAddress, AutoSystemInfo::PageSize * guardPageCount, MEM_DECOMMIT))
  193. {
  194. pageHeapData->isGuardPageDecommitted = true;
  195. }
  196. else
  197. {
  198. Js::Throw::FatalInternalError();
  199. }
  200. }
  201. else
  202. {
  203. DWORD oldProtect;
  204. if (VirtualProtect(guardPageAddress, AutoSystemInfo::PageSize * guardPageCount, PAGE_NOACCESS, &oldProtect))
  205. {
  206. pageHeapData->isGuardPageDecommitted = false;
  207. }
  208. else
  209. {
  210. Js::Throw::FatalInternalError();
  211. }
  212. }
  213. pageHeapData->objectAddress = heapBlock->Alloc(size, attributes);
  214. Assert(pageHeapData->objectAddress != nullptr);
  215. if (!pageHeapData->objectAddress)
  216. {
  217. pageAllocator->SuspendIdleDecommit();
  218. heapBlock->ReleasePages(recycler);
  219. pageAllocator->ResumeIdleDecommit();
  220. LargeHeapBlock::Delete(heapBlock);
  221. return throwOrReturn(nullptr);
  222. }
  223. pageHeapData->objectEndAddr = pageHeapData->objectAddress + size;
  224. // fill pattern before set pageHeapMode, so background scan stack may verify the pattern
  225. memset(pageHeapData->objectPageAddr, PageHeapMemFill, pageHeapData->paddingBytes);
  226. memset(pageHeapData->objectAddress + size, PageHeapMemFill, pageHeapData->unusedBytes);
  227. if (!recycler->heapBlockMap.SetHeapBlock(headerAddress, pageCount, heapBlock, HeapBlock::HeapBlockType::LargeBlockType, 0))
  228. {
  229. pageAllocator->SuspendIdleDecommit();
  230. heapBlock->ReleasePages(recycler);
  231. pageAllocator->ResumeIdleDecommit();
  232. LargeHeapBlock::Delete(heapBlock);
  233. return throwOrReturn(nullptr);
  234. }
  235. heapBlock->SetNextBlock(this->largePageHeapBlockList);
  236. this->largePageHeapBlockList = heapBlock;
  237. #if ENABLE_PARTIAL_GC
  238. recycler->autoHeap.uncollectedNewPageCount += pageCount;
  239. #endif
  240. RECYCLER_SLOW_CHECK(this->heapInfo->heapBlockCount[HeapBlock::HeapBlockType::LargeBlockType]++);
  241. RECYCLER_PERF_COUNTER_ADD(FreeObjectSize, heapBlock->GetPageCount() * AutoSystemInfo::PageSize);
  242. #ifdef STACK_BACK_TRACE
  243. if (recycler->ShouldCapturePageHeapAllocStack())
  244. {
  245. heapBlock->CapturePageHeapAllocStack();
  246. }
  247. #endif
  248. return throwOrReturn(pageHeapData->objectAddress);
  249. }
  250. #endif
  251. LargeHeapBlock*
  252. LargeHeapBucket::AddLargeHeapBlock(size_t size, bool nothrow)
  253. {
  254. Recycler* recycler = this->heapInfo->recycler;
  255. Segment * segment;
  256. size_t pageCount = LargeHeapBlock::GetPagesNeeded(size, this->supportFreeList);
  257. if (pageCount == 0)
  258. {
  259. if (nothrow == false)
  260. {
  261. // overflow
  262. // Since nothrow is false here, it's okay to throw
  263. recycler->OutOfMemory();
  264. }
  265. return nullptr;
  266. }
  267. char * address = nullptr;
  268. size_t realPageCount = pageCount;
  269. address = heapInfo->GetRecyclerLargeBlockPageAllocator()->Alloc(&realPageCount, &segment);
  270. pageCount = realPageCount;
  271. if (address == nullptr)
  272. {
  273. return nullptr;
  274. }
  275. #ifdef RECYCLER_ZERO_MEM_CHECK
  276. recycler->VerifyZeroFill(address, pageCount * AutoSystemInfo::PageSize);
  277. #endif
  278. uint objectCount = LargeHeapBlock::GetMaxLargeObjectCount(pageCount, size);
  279. LargeHeapBlock * heapBlock = LargeHeapBlock::New(address, pageCount, segment, objectCount, this);
  280. #if DBG
  281. LargeAllocationVerboseTrace(recycler->GetRecyclerFlagsTable(), _u("Allocated new large heap block 0x%p for sizeCat 0x%x\n"), heapBlock, sizeCat);
  282. #endif
  283. #ifdef ENABLE_JS_ETW
  284. #if ENABLE_DEBUG_CONFIG_OPTIONS
  285. if (segment->GetPageCount() > heapInfo->GetRecyclerLargeBlockPageAllocator()->GetMaxAllocPageCount())
  286. {
  287. JS_ETW_INTERNAL(EventWriteJSCRIPT_INTERNAL_RECYCLER_EXTRALARGE_OBJECT_ALLOC(size));
  288. }
  289. #endif
  290. #endif
  291. if (!heapBlock)
  292. {
  293. heapInfo->GetRecyclerLargeBlockPageAllocator()->SuspendIdleDecommit();
  294. heapInfo->GetRecyclerLargeBlockPageAllocator()->Release(address, pageCount, segment);
  295. heapInfo->GetRecyclerLargeBlockPageAllocator()->ResumeIdleDecommit();
  296. return nullptr;
  297. }
  298. #if ENABLE_PARTIAL_GC
  299. recycler->autoHeap.uncollectedNewPageCount += pageCount;
  300. #endif
  301. RECYCLER_SLOW_CHECK(this->heapInfo->heapBlockCount[HeapBlock::HeapBlockType::LargeBlockType]++);
  302. heapBlock->heapInfo = this->heapInfo;
  303. heapBlock->lastCollectAllocCount = 0;
  304. Assert(recycler->collectionState != CollectionStateMark);
  305. if (!recycler->heapBlockMap.SetHeapBlock(address, pageCount, heapBlock, HeapBlock::HeapBlockType::LargeBlockType, 0))
  306. {
  307. heapInfo->GetRecyclerLargeBlockPageAllocator()->SuspendIdleDecommit();
  308. heapBlock->ReleasePages(recycler);
  309. heapInfo->GetRecyclerLargeBlockPageAllocator()->ResumeIdleDecommit();
  310. LargeHeapBlock::Delete(heapBlock);
  311. RECYCLER_SLOW_CHECK(this->heapInfo->heapBlockCount[HeapBlock::HeapBlockType::LargeBlockType]--);
  312. return nullptr;
  313. }
  314. heapBlock->SetNextBlock(this->largeBlockList);
  315. this->largeBlockList = heapBlock;
  316. RECYCLER_PERF_COUNTER_ADD(FreeObjectSize, heapBlock->GetPageCount() * AutoSystemInfo::PageSize);
  317. return heapBlock;
  318. }
  319. char *
  320. LargeHeapBucket::TryAllocFromFreeList(Recycler * recycler, size_t sizeCat, ObjectInfoBits attributes)
  321. {
  322. Assert((attributes & InternalObjectInfoBitMask) == attributes);
  323. LargeHeapBlockFreeList* freeListEntry = this->freeList;
  324. // Walk through the free list, find the first entry that can fit our desired size
  325. while (freeListEntry)
  326. {
  327. LargeHeapBlock* heapBlock = freeListEntry->heapBlock;
  328. char * memBlock = heapBlock->TryAllocFromFreeList(sizeCat, attributes);
  329. if (memBlock)
  330. {
  331. // Don't need to verify zero fill here since we will do it in LargeHeapBucket::Alloc
  332. return memBlock;
  333. }
  334. else
  335. {
  336. #if DBG
  337. LargeAllocationVerboseTrace(recycler->GetRecyclerFlagsTable(), _u("Unable to allocate object of size 0x%x from freelist\n"), sizeCat);
  338. #endif
  339. }
  340. freeListEntry = freeListEntry->next;
  341. }
  342. return nullptr;
  343. }
  344. char *
  345. LargeHeapBucket::TryAllocFromExplicitFreeList(Recycler * recycler, size_t sizeCat, ObjectInfoBits attributes)
  346. {
  347. Assert((attributes & InternalObjectInfoBitMask) == attributes);
  348. FreeObject * currFreeObject = this->explicitFreeList;
  349. FreeObject * prevFreeObject = nullptr;
  350. while (currFreeObject != nullptr)
  351. {
  352. char * memBlock = (char *)currFreeObject;
  353. LargeObjectHeader * header = LargeHeapBlock::GetHeaderFromAddress(memBlock);
  354. Assert(header->isExplicitFreed);
  355. Assert(HeapInfo::GetMediumObjectAlignedSizeNoCheck(header->objectSize) == this->sizeCat);
  356. if (header->objectSize < sizeCat)
  357. {
  358. prevFreeObject = currFreeObject;
  359. currFreeObject = currFreeObject->GetNext();
  360. continue;
  361. }
  362. DebugOnly(header->isExplicitFreed = false);
  363. if (prevFreeObject)
  364. {
  365. prevFreeObject->SetNext(currFreeObject->GetNext());
  366. }
  367. else
  368. {
  369. this->explicitFreeList = currFreeObject->GetNext();
  370. }
  371. #ifdef RECYCLER_MEMORY_VERIFY
  372. HeapBlock* heapBlockVerify = recycler->FindHeapBlock(memBlock);
  373. Assert(heapBlockVerify != nullptr);
  374. Assert(heapBlockVerify->IsLargeHeapBlock());
  375. LargeHeapBlock * largeHeapBlock = (LargeHeapBlock *)heapBlockVerify;
  376. LargeObjectHeader * dbgHeader;
  377. Assert(largeHeapBlock->GetObjectHeader(memBlock, &dbgHeader));
  378. Assert(dbgHeader == header);
  379. ((FreeObject *)memBlock)->DebugFillNext();
  380. #endif
  381. #ifdef RECYCLER_ZERO_MEM_CHECK
  382. // TODO: large heap block doesn't separate leaf object on to different page allocator.
  383. // so all the memory should still be zeroed.
  384. memset(memBlock, 0, sizeof(FreeObject));
  385. #endif
  386. header->SetAttributes(recycler->Cookie, (attributes & StoredObjectInfoBitMask));
  387. if ((attributes & ObjectInfoBits::FinalizeBit) != 0)
  388. {
  389. LargeHeapBlock* heapBlock = (LargeHeapBlock *)recycler->FindHeapBlock(memBlock);
  390. heapBlock->finalizeCount++;
  391. #ifdef RECYCLER_FINALIZE_CHECK
  392. heapInfo->liveFinalizableObjectCount++;
  393. heapInfo->newFinalizableObjectCount++;
  394. #endif
  395. }
  396. return memBlock;
  397. }
  398. return nullptr;
  399. }
  400. //=====================================================================================================
  401. // Free
  402. //=====================================================================================================
  403. void
  404. LargeHeapBucket::ExplicitFree(void * object, size_t sizeCat)
  405. {
  406. Assert(HeapInfo::GetMediumObjectAlignedSizeNoCheck(sizeCat) == this->sizeCat);
  407. LargeObjectHeader * header = LargeHeapBlock::GetHeaderFromAddress(object);
  408. Assert(header->GetAttributes(this->heapInfo->recycler->Cookie) == ObjectInfoBits::NoBit || header->GetAttributes(this->heapInfo->recycler->Cookie) == ObjectInfoBits::LeafBit);
  409. Assert(!header->isExplicitFreed);
  410. DebugOnly(header->isExplicitFreed = true);
  411. Assert(header->objectSize >= sizeCat);
  412. #if DBG
  413. HeapBlock* heapBlock = this->GetRecycler()->FindHeapBlock(object);
  414. Assert(heapBlock != nullptr);
  415. Assert(heapBlock->IsLargeHeapBlock());
  416. LargeHeapBlock * largeHeapBlock = (LargeHeapBlock *)heapBlock;
  417. LargeObjectHeader * dbgHeader;
  418. Assert(largeHeapBlock->GetObjectHeader(object, &dbgHeader));
  419. Assert(dbgHeader == header);
  420. #endif
  421. FreeObject * freeObject = (FreeObject *)object;
  422. freeObject->SetNext(this->explicitFreeList);
  423. this->explicitFreeList = freeObject;
  424. header->SetAttributes(this->heapInfo->recycler->Cookie, ObjectInfoBits::LeafBit); // We can stop scanning it now.
  425. }
  426. //=====================================================================================================
  427. // Collections
  428. //=====================================================================================================
  429. void
  430. LargeHeapBucket::ResetMarks(ResetMarkFlags flags)
  431. {
  432. Recycler* recycler = this->heapInfo->recycler;
  433. HeapBlockList::ForEach(largeBlockList, [flags, recycler](LargeHeapBlock * heapBlock)
  434. {
  435. heapBlock->ResetMarks(flags, recycler);
  436. });
  437. #ifdef RECYCLER_PAGE_HEAP
  438. HeapBlockList::ForEach(largePageHeapBlockList, [flags, recycler](LargeHeapBlock * heapBlock)
  439. {
  440. heapBlock->ResetMarks(flags, recycler);
  441. });
  442. #endif
  443. HeapBlockList::ForEach(fullLargeBlockList, [flags, recycler](LargeHeapBlock * heapBlock)
  444. {
  445. heapBlock->ResetMarks(flags, recycler);
  446. });
  447. HeapBlockList::ForEach(pendingDisposeLargeBlockList, [flags, recycler](LargeHeapBlock * heapBlock)
  448. {
  449. heapBlock->ResetMarks(flags, recycler);
  450. });
  451. #if ENABLE_CONCURRENT_GC
  452. Assert(pendingSweepLargeBlockList == nullptr);
  453. #endif
  454. }
  455. void
  456. LargeHeapBucket::ScanInitialImplicitRoots(Recycler * recycler)
  457. {
  458. HeapBlockList::ForEach(largeBlockList, [recycler](LargeHeapBlock * heapBlock)
  459. {
  460. heapBlock->ScanInitialImplicitRoots(recycler);
  461. });
  462. #ifdef RECYCLER_PAGE_HEAP
  463. HeapBlockList::ForEach(largePageHeapBlockList, [recycler](LargeHeapBlock * heapBlock)
  464. {
  465. heapBlock->ScanInitialImplicitRoots(recycler);
  466. });
  467. #endif
  468. HeapBlockList::ForEach(fullLargeBlockList, [recycler](LargeHeapBlock * heapBlock)
  469. {
  470. heapBlock->ScanInitialImplicitRoots(recycler);
  471. });
  472. HeapBlockList::ForEach(pendingDisposeLargeBlockList, [recycler](LargeHeapBlock * heapBlock)
  473. {
  474. heapBlock->ScanInitialImplicitRoots(recycler);
  475. });
  476. #if ENABLE_CONCURRENT_GC
  477. Assert(pendingSweepLargeBlockList == nullptr);
  478. #endif
  479. }
  480. void
  481. LargeHeapBucket::ScanNewImplicitRoots(Recycler * recycler)
  482. {
  483. HeapBlockList::ForEach(largeBlockList, [recycler](LargeHeapBlock * heapBlock)
  484. {
  485. heapBlock->ScanNewImplicitRoots(recycler);
  486. });
  487. #ifdef RECYCLER_PAGE_HEAP
  488. HeapBlockList::ForEach(largePageHeapBlockList, [recycler](LargeHeapBlock * heapBlock)
  489. {
  490. heapBlock->ScanNewImplicitRoots(recycler);
  491. });
  492. #endif
  493. HeapBlockList::ForEach(fullLargeBlockList, [recycler](LargeHeapBlock * heapBlock)
  494. {
  495. heapBlock->ScanNewImplicitRoots(recycler);
  496. });
  497. HeapBlockList::ForEach(pendingDisposeLargeBlockList, [recycler](LargeHeapBlock * heapBlock)
  498. {
  499. heapBlock->ScanNewImplicitRoots(recycler);
  500. });
  501. #if ENABLE_CONCURRENT_GC
  502. Assert(pendingSweepLargeBlockList == nullptr);
  503. #endif
  504. }
  505. //=====================================================================================================
  506. // Sweep
  507. //=====================================================================================================
  508. #pragma region Sweep
  509. void
  510. LargeHeapBucket::Sweep(RecyclerSweep& recyclerSweep)
  511. {
  512. #if ENABLE_CONCURRENT_GC
  513. // CONCURRENT-TODO: large buckets are not swept in the background currently.
  514. #if ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP
  515. Assert(!recyclerSweep.GetRecycler()->IsConcurrentExecutingState() && !recyclerSweep.GetRecycler()->IsConcurrentSweepState());
  516. #else
  517. Assert(!recyclerSweep.GetRecycler()->IsConcurrentExecutingState());
  518. #endif
  519. #endif
  520. LargeHeapBlock * currentLargeObjectBlocks = largeBlockList;
  521. #ifdef RECYCLER_PAGE_HEAP
  522. LargeHeapBlock * currentLargePageHeapObjectBlocks = largePageHeapBlockList;
  523. #endif
  524. LargeHeapBlock * currentFullLargeObjectBlocks = fullLargeBlockList;
  525. LargeHeapBlock * currentDisposeLargeBlockList = pendingDisposeLargeBlockList;
  526. this->largeBlockList = nullptr;
  527. #ifdef RECYCLER_PAGE_HEAP
  528. this->largePageHeapBlockList = nullptr;
  529. #endif
  530. this->fullLargeBlockList = nullptr;
  531. // Clear the free list before sweep
  532. // We'll reconstruct the free list during sweep
  533. if (this->supportFreeList)
  534. {
  535. #if DBG
  536. LargeAllocationVerboseTrace(recyclerSweep.GetRecycler()->GetRecyclerFlagsTable(), _u("Resetting free list for 0x%x bucket\n"), this->sizeCat);
  537. #endif
  538. this->freeList = nullptr;
  539. this->explicitFreeList = nullptr;
  540. }
  541. #if ENABLE_CONCURRENT_GC
  542. Assert(this->pendingSweepLargeBlockList == nullptr);
  543. #endif
  544. SweepLargeHeapBlockList(recyclerSweep, currentLargeObjectBlocks);
  545. #ifdef RECYCLER_PAGE_HEAP
  546. SweepLargeHeapBlockList(recyclerSweep, currentLargePageHeapObjectBlocks);
  547. #endif
  548. SweepLargeHeapBlockList(recyclerSweep, currentFullLargeObjectBlocks);
  549. SweepLargeHeapBlockList(recyclerSweep, currentDisposeLargeBlockList);
  550. }
  551. void
  552. LargeHeapBucket::SweepLargeHeapBlockList(RecyclerSweep& recyclerSweep, LargeHeapBlock * heapBlockList)
  553. {
  554. Recycler * recycler = recyclerSweep.GetRecycler();
  555. HeapBlockList::ForEachEditing(heapBlockList, [this, &recyclerSweep, recycler](LargeHeapBlock * heapBlock)
  556. {
  557. this->UnregisterFreeList(heapBlock->GetFreeList());
  558. // CONCURRENT-TODO: Allow large block to be sweep in the background
  559. SweepState state = heapBlock->Sweep(recyclerSweep, false);
  560. // If the block is already in the pending dispose list (re-entrant GC scenario), do nothing, leave it there
  561. if (heapBlock->IsInPendingDisposeList()) return;
  562. switch (state)
  563. {
  564. case SweepStateEmpty:
  565. heapBlock->ReleasePagesSweep(recycler);
  566. LargeHeapBlock::Delete(heapBlock);
  567. RECYCLER_SLOW_CHECK(this->heapInfo->heapBlockCount[HeapBlock::HeapBlockType::LargeBlockType]--);
  568. break;
  569. case SweepStateFull:
  570. heapBlock->SetNextBlock(this->fullLargeBlockList);
  571. this->fullLargeBlockList = heapBlock;
  572. break;
  573. case SweepStateSwept:
  574. if (supportFreeList)
  575. {
  576. ConstructFreelist(heapBlock);
  577. }
  578. else
  579. {
  580. ReinsertLargeHeapBlock(heapBlock);
  581. }
  582. break;
  583. case SweepStatePendingDispose:
  584. Assert(!recyclerSweep.IsBackground());
  585. Assert(!this->heapInfo->hasPendingTransferDisposedObjects);
  586. heapBlock->SetNextBlock(this->pendingDisposeLargeBlockList);
  587. this->pendingDisposeLargeBlockList = heapBlock;
  588. heapBlock->SetIsInPendingDisposeList(true);
  589. #if DBG
  590. heapBlock->SetHasDisposeBeenCalled(false);
  591. #endif
  592. recycler->hasDisposableObject = true;
  593. break;
  594. #if ENABLE_CONCURRENT_GC
  595. case SweepStatePendingSweep:
  596. heapBlock->SetNextBlock(this->pendingSweepLargeBlockList);
  597. this->pendingSweepLargeBlockList = heapBlock;
  598. break;
  599. #endif
  600. }
  601. });
  602. }
  603. void
  604. LargeHeapBucket::ReinsertLargeHeapBlock(LargeHeapBlock * heapBlock)
  605. {
  606. Assert(!heapBlock->hasPartialFreeObjects);
  607. Assert(!heapBlock->IsInPendingDisposeList());
  608. if (this->largeBlockList != nullptr && heapBlock->GetFreeSize() > this->largeBlockList->GetFreeSize())
  609. {
  610. heapBlock->SetNextBlock(this->largeBlockList->GetNextBlock());
  611. this->largeBlockList->SetNextBlock(this->fullLargeBlockList);
  612. this->fullLargeBlockList = this->largeBlockList;
  613. this->largeBlockList = heapBlock;
  614. }
  615. else
  616. {
  617. heapBlock->SetNextBlock(this->fullLargeBlockList);
  618. this->fullLargeBlockList = heapBlock;
  619. }
  620. }
  621. void
  622. LargeHeapBucket::RegisterFreeList(LargeHeapBlockFreeList* freeList)
  623. {
  624. Assert(freeList->next == nullptr);
  625. Assert(freeList->previous == nullptr);
  626. LargeHeapBlockFreeList* head = this->freeList;
  627. if (head)
  628. {
  629. head->previous = freeList;
  630. }
  631. freeList->next = head;
  632. this->freeList = freeList;
  633. }
  634. void
  635. LargeHeapBucket::UnregisterFreeList(LargeHeapBlockFreeList* freeList)
  636. {
  637. LargeHeapBlockFreeList* next = freeList->next;
  638. LargeHeapBlockFreeList* previous = freeList->previous;
  639. if (previous)
  640. {
  641. previous->next = next;
  642. }
  643. if (next)
  644. {
  645. next->previous = previous;
  646. }
  647. freeList->next = nullptr;
  648. freeList->previous = nullptr;
  649. if (freeList == this->freeList)
  650. {
  651. this->freeList = next;
  652. }
  653. }
  654. void
  655. LargeHeapBucket::ConstructFreelist(LargeHeapBlock * heapBlock)
  656. {
  657. Assert(!heapBlock->hasPartialFreeObjects);
  658. Assert(!heapBlock->IsInPendingDisposeList());
  659. // The free list is the only way we reuse heap block entries
  660. // so if the heap block is allocated from directly, it'll not
  661. // invalidate the free list
  662. LargeHeapBlockFreeList* freeList = heapBlock->GetFreeList();
  663. Assert(freeList);
  664. if (freeList->entries)
  665. {
  666. this->RegisterFreeList(freeList);
  667. #if DBG
  668. LargeAllocationVerboseTrace(this->GetRecycler()->GetRecyclerFlagsTable(), _u("Free list created for 0x%x bucket\n"), this->sizeCat);
  669. #endif
  670. }
  671. ReinsertLargeHeapBlock(heapBlock);
  672. }
  673. #pragma endregion
  674. size_t
  675. LargeHeapBucket::Rescan(LargeHeapBlock * list, Recycler * recycler, bool isPartialSwept, RescanFlags flags)
  676. {
  677. size_t scannedPageCount = 0;
  678. HeapBlockList::ForEach(list, [recycler, isPartialSwept, flags, &scannedPageCount](LargeHeapBlock * heapBlock)
  679. {
  680. scannedPageCount += heapBlock->Rescan(recycler, isPartialSwept, flags);
  681. });
  682. return scannedPageCount;
  683. }
  684. size_t
  685. LargeHeapBucket::Rescan(RescanFlags flags)
  686. {
  687. #if ENABLE_CONCURRENT_GC
  688. Assert(pendingSweepLargeBlockList == nullptr);
  689. #endif
  690. size_t scannedPageCount = 0;
  691. Recycler* recycler = this->heapInfo->recycler;
  692. scannedPageCount += LargeHeapBucket::Rescan(largeBlockList, recycler, false, flags);
  693. #ifdef RECYCLER_PAGE_HEAP
  694. scannedPageCount += LargeHeapBucket::Rescan(largePageHeapBlockList, recycler, false, flags);
  695. #endif
  696. scannedPageCount += LargeHeapBucket::Rescan(fullLargeBlockList, recycler, false, flags);
  697. scannedPageCount += LargeHeapBucket::Rescan(pendingDisposeLargeBlockList, recycler, true, flags);
  698. #if ENABLE_PARTIAL_GC && ENABLE_CONCURRENT_GC
  699. Assert(recycler->inPartialCollectMode || partialSweptLargeBlockList == nullptr);
  700. if (recycler->inPartialCollectMode)
  701. {
  702. scannedPageCount += LargeHeapBucket::Rescan(partialSweptLargeBlockList, recycler, true, flags);
  703. }
  704. #endif
  705. return scannedPageCount;
  706. }
  707. #if ENABLE_PARTIAL_GC || ENABLE_CONCURRENT_GC
  708. void
  709. LargeHeapBucket::SweepPendingObjects(RecyclerSweep& recyclerSweep)
  710. {
  711. #if ENABLE_CONCURRENT_GC
  712. if (recyclerSweep.IsBackground())
  713. {
  714. Recycler * recycler = recyclerSweep.GetRecycler();
  715. #if ENABLE_PARTIAL_GC
  716. if (recycler->inPartialCollectMode)
  717. {
  718. HeapBlockList::ForEach(this->pendingSweepLargeBlockList, [recycler](LargeHeapBlock * heapBlock)
  719. {
  720. // Page heap blocks are never swept concurrently
  721. heapBlock->SweepObjects<SweepMode_ConcurrentPartial>(recycler);
  722. });
  723. }
  724. else
  725. #endif
  726. {
  727. HeapBlockList::ForEach(this->pendingSweepLargeBlockList, [recycler](LargeHeapBlock * heapBlock)
  728. {
  729. // Page heap blocks are never swept concurrently
  730. heapBlock->SweepObjects<SweepMode_Concurrent>(recycler);
  731. });
  732. }
  733. }
  734. else
  735. {
  736. Assert(this->pendingSweepLargeBlockList == nullptr);
  737. }
  738. #endif
  739. }
  740. #if ENABLE_PARTIAL_GC
  741. #if ENABLE_CONCURRENT_GC
  742. void
  743. LargeHeapBucket::ConcurrentPartialTransferSweptObjects(RecyclerSweep& recyclerSweep)
  744. {
  745. Assert(recyclerSweep.InPartialCollectMode());
  746. Assert(!recyclerSweep.IsBackground());
  747. RECYCLER_SLOW_CHECK(this->VerifyLargeHeapBlockCount());
  748. LargeHeapBlock * list = this->pendingSweepLargeBlockList;
  749. this->pendingSweepLargeBlockList = nullptr;
  750. HeapBlockList::ForEachEditing(list, [this](LargeHeapBlock * heapBlock)
  751. {
  752. // GC-REVIEW: We could maybe reuse the large objects
  753. heapBlock->PartialTransferSweptObjects();
  754. heapBlock->SetNextBlock(this->partialSweptLargeBlockList);
  755. this->partialSweptLargeBlockList = heapBlock;
  756. });
  757. RECYCLER_SLOW_CHECK(this->VerifyLargeHeapBlockCount());
  758. }
  759. #endif
  760. void
  761. LargeHeapBucket::FinishPartialCollect(RecyclerSweep * recyclerSweep)
  762. {
  763. #if ENABLE_CONCURRENT_GC
  764. Recycler* recycler = this->heapInfo->recycler;
  765. if (recyclerSweep && recyclerSweep->IsBackground())
  766. {
  767. // Leave it in the partialSweptLargeBlockList if we are processing it in the background
  768. // ConcurrentTransferSweptObjects will put it back.
  769. HeapBlockList::ForEachEditing(partialSweptLargeBlockList, [this, recycler](LargeHeapBlock * heapBlock)
  770. {
  771. heapBlock->FinishPartialCollect(recycler);
  772. });
  773. }
  774. else
  775. {
  776. HeapBlockList::ForEachEditing(partialSweptLargeBlockList, [this, recycler](LargeHeapBlock * heapBlock)
  777. {
  778. heapBlock->FinishPartialCollect(recycler);
  779. this->ReinsertLargeHeapBlock(heapBlock);
  780. });
  781. this->partialSweptLargeBlockList = nullptr;
  782. }
  783. #endif
  784. }
  785. #endif
  786. #if ENABLE_CONCURRENT_GC
  787. void
  788. LargeHeapBucket::ConcurrentTransferSweptObjects(RecyclerSweep& recyclerSweep)
  789. {
  790. #if ENABLE_PARTIAL_GC
  791. Assert(!recyclerSweep.InPartialCollectMode());
  792. #endif
  793. Assert(!recyclerSweep.IsBackground());
  794. HeapBlockList::ForEachEditing(this->pendingSweepLargeBlockList, [this](LargeHeapBlock * heapBlock)
  795. {
  796. heapBlock->TransferSweptObjects();
  797. ReinsertLargeHeapBlock(heapBlock);
  798. });
  799. this->pendingSweepLargeBlockList = nullptr;
  800. #if ENABLE_PARTIAL_GC
  801. // If we did a background finish partial collect, we have left the partialSweptLargeBlockList
  802. // there because can't reinsert the heap block in the background, do it here now.
  803. HeapBlockList::ForEachEditing(this->partialSweptLargeBlockList, [this](LargeHeapBlock * heapBlock)
  804. {
  805. ReinsertLargeHeapBlock(heapBlock);
  806. });
  807. this->partialSweptLargeBlockList = nullptr;
  808. #endif
  809. }
  810. #endif
  811. #endif
  812. void
  813. LargeHeapBucket::FinalizeAllObjects()
  814. {
  815. ForEachLargeHeapBlock([](LargeHeapBlock * heapBlock) { heapBlock->FinalizeAllObjects(); });
  816. }
  817. void
  818. LargeHeapBucket::Finalize(Recycler * recycler, LargeHeapBlock * heapBlockList)
  819. {
  820. HeapBlockList::ForEachEditing(heapBlockList, [recycler](LargeHeapBlock * heapBlock)
  821. {
  822. heapBlock->FinalizeObjects(recycler);
  823. });
  824. }
  825. void
  826. LargeHeapBucket::Finalize()
  827. {
  828. Recycler* recycler = this->heapInfo->recycler;
  829. // Finalize any free objects in the non-filled large heap blocks
  830. Finalize(recycler, largeBlockList);
  831. #ifdef RECYCLER_PAGE_HEAP
  832. Finalize(recycler, largePageHeapBlockList);
  833. #endif
  834. // Finalize any free objects in the filled large heap blocks
  835. Finalize(recycler, fullLargeBlockList);
  836. // Finalize any free objects in the large heap blocks which have objects pending dispose
  837. // This is to handle the case where if during dispose, a GC is triggered, we might have
  838. // found more objects to free. These objects might reside in a block that was moved to the
  839. // pendingDisposeLargeBlockList during the outer GC. So we need to walk through this list
  840. // again and finalize any objects that need to be finalized. If we don't, they would
  841. // not get finalized
  842. Finalize(recycler, pendingDisposeLargeBlockList);
  843. }
  844. void
  845. LargeHeapBucket::DisposeObjects()
  846. {
  847. Recycler * recycler = this->heapInfo->recycler;
  848. HeapBlockList::ForEach(this->pendingDisposeLargeBlockList, [recycler](LargeHeapBlock * heapBlock)
  849. {
  850. heapBlock->DisposeObjects(recycler);
  851. });
  852. }
  853. void
  854. LargeHeapBucket::TransferDisposedObjects()
  855. {
  856. #if ENABLE_CONCURRENT_GC
  857. Recycler * recycler = this->heapInfo->recycler;
  858. #if ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP
  859. Assert(!recycler->IsConcurrentExecutingState() && !recycler->IsConcurrentSweepState());
  860. #else
  861. Assert(!recycler->IsConcurrentExecutingState());
  862. #endif
  863. #endif
  864. HeapBlockList::ForEachEditing(this->pendingDisposeLargeBlockList, [this](LargeHeapBlock * heapBlock)
  865. {
  866. /* GC-TODO: large heap block doesn't support free list yet */
  867. heapBlock->SetIsInPendingDisposeList(false);
  868. ReinsertLargeHeapBlock(heapBlock);
  869. });
  870. this->pendingDisposeLargeBlockList = nullptr;
  871. }
  872. void
  873. LargeHeapBucket::EnumerateObjects(ObjectInfoBits infoBits, void (*CallBackFunction)(void * address, size_t size))
  874. {
  875. HeapBucket::EnumerateObjects(largeBlockList, infoBits, CallBackFunction);
  876. #ifdef RECYCLER_PAGE_HEAP
  877. HeapBucket::EnumerateObjects(largePageHeapBlockList, infoBits, CallBackFunction);
  878. #endif
  879. HeapBucket::EnumerateObjects(fullLargeBlockList, infoBits, CallBackFunction);
  880. // Pending dispose large block list need not be null
  881. // When we enumerate over this list, anything that has been swept/finalized won't be
  882. // enumerated since it needs to have the object header for enumeration
  883. // and we set the header to null upon sweep/finalize
  884. HeapBucket::EnumerateObjects(pendingDisposeLargeBlockList, infoBits, CallBackFunction);
  885. #if ENABLE_CONCURRENT_GC
  886. Assert(this->pendingSweepLargeBlockList == nullptr);
  887. #if ENABLE_PARTIAL_GC
  888. HeapBucket::EnumerateObjects(partialSweptLargeBlockList, infoBits, CallBackFunction);
  889. #endif
  890. #endif
  891. }
  892. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  893. size_t
  894. LargeHeapBucket::GetLargeHeapBlockCount(bool checkCount) const
  895. {
  896. size_t currentLargeHeapBlockCount = HeapBlockList::Count(fullLargeBlockList);
  897. currentLargeHeapBlockCount += HeapBlockList::Count(largeBlockList);
  898. #ifdef RECYCLER_PAGE_HEAP
  899. currentLargeHeapBlockCount += HeapBlockList::Count(largePageHeapBlockList);
  900. #endif
  901. currentLargeHeapBlockCount += HeapBlockList::Count(pendingDisposeLargeBlockList);
  902. #if ENABLE_CONCURRENT_GC
  903. currentLargeHeapBlockCount += HeapBlockList::Count(pendingSweepLargeBlockList);
  904. #if ENABLE_PARTIAL_GC
  905. currentLargeHeapBlockCount += HeapBlockList::Count(partialSweptLargeBlockList);
  906. #endif
  907. #endif
  908. return currentLargeHeapBlockCount;
  909. }
  910. #endif
  911. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  912. size_t
  913. LargeHeapBucket::Check()
  914. {
  915. size_t currentLargeHeapBlockCount = Check(false, false, largeBlockList);
  916. #ifdef RECYCLER_PAGE_HEAP
  917. currentLargeHeapBlockCount += Check(true, false, largePageHeapBlockList);
  918. #endif
  919. currentLargeHeapBlockCount += Check(true, false, fullLargeBlockList);
  920. #if ENABLE_CONCURRENT_GC
  921. Assert(pendingSweepLargeBlockList == nullptr);
  922. #if ENABLE_PARTIAL_GC
  923. currentLargeHeapBlockCount += Check(false, false, partialSweptLargeBlockList);
  924. #endif
  925. #endif
  926. currentLargeHeapBlockCount += Check(false, true, pendingDisposeLargeBlockList);
  927. return currentLargeHeapBlockCount;
  928. }
  929. template <typename TBlockType>
  930. size_t
  931. LargeHeapBucket::Check(bool expectFull, bool expectPending, TBlockType * list, TBlockType * tail)
  932. {
  933. size_t heapBlockCount = 0;
  934. HeapBlockList::ForEach(list, tail, [&heapBlockCount, expectFull, expectPending](TBlockType * heapBlock)
  935. {
  936. heapBlock->Check(expectFull, expectPending);
  937. heapBlockCount++;
  938. });
  939. return heapBlockCount;
  940. }
  941. template size_t LargeHeapBucket::Check<LargeHeapBlock>(bool expectFull, bool expectPending, LargeHeapBlock * list, LargeHeapBlock * tail);
  942. void
  943. LargeHeapBucket::VerifyLargeHeapBlockCount()
  944. {
  945. GetLargeHeapBlockCount(true);
  946. }
  947. #endif
  948. #ifdef RECYCLER_MEMORY_VERIFY
  949. void
  950. LargeHeapBucket::Verify()
  951. {
  952. Recycler * recycler = this->heapInfo->recycler;
  953. HeapBlockList::ForEach(largeBlockList, [recycler](LargeHeapBlock * largeHeapBlock)
  954. {
  955. largeHeapBlock->Verify(recycler);
  956. });
  957. #ifdef RECYCLER_PAGE_HEAP
  958. HeapBlockList::ForEach(largePageHeapBlockList, [recycler](LargeHeapBlock * largeHeapBlock)
  959. {
  960. largeHeapBlock->Verify(recycler);
  961. });
  962. #endif
  963. HeapBlockList::ForEach(fullLargeBlockList, [recycler](LargeHeapBlock * largeHeapBlock)
  964. {
  965. largeHeapBlock->Verify(recycler);
  966. });
  967. HeapBlockList::ForEach(pendingDisposeLargeBlockList, [recycler](LargeHeapBlock * largeHeapBlock)
  968. {
  969. largeHeapBlock->Verify(recycler);
  970. });
  971. }
  972. #endif
  973. #ifdef RECYCLER_VERIFY_MARK
  974. void
  975. LargeHeapBucket::VerifyMark()
  976. {
  977. HeapBlockList::ForEach(largeBlockList, [](LargeHeapBlock * largeHeapBlock)
  978. {
  979. largeHeapBlock->VerifyMark();
  980. });
  981. HeapBlockList::ForEach(fullLargeBlockList, [](LargeHeapBlock * largeHeapBlock)
  982. {
  983. largeHeapBlock->VerifyMark();
  984. });
  985. HeapBlockList::ForEach(pendingDisposeLargeBlockList, [](LargeHeapBlock * largeHeapBlock)
  986. {
  987. largeHeapBlock->VerifyMark();
  988. });
  989. }
  990. #endif
  991. #if ENABLE_MEM_STATS
  992. void
  993. LargeHeapBucket::AggregateBucketStats()
  994. {
  995. HeapBucket::AggregateBucketStats(); // call super
  996. auto blockStatsAggregator = [this](LargeHeapBlock* largeHeapBlock) {
  997. largeHeapBlock->AggregateBlockStats(this->memStats);
  998. };
  999. HeapBlockList::ForEach(largeBlockList, blockStatsAggregator);
  1000. HeapBlockList::ForEach(fullLargeBlockList, blockStatsAggregator);
  1001. HeapBlockList::ForEach(pendingDisposeLargeBlockList, blockStatsAggregator);
  1002. #if ENABLE_CONCURRENT_GC
  1003. HeapBlockList::ForEach(pendingSweepLargeBlockList, blockStatsAggregator);
  1004. #if ENABLE_PARTIAL_GC
  1005. HeapBlockList::ForEach(partialSweptLargeBlockList, blockStatsAggregator);
  1006. #endif
  1007. #endif
  1008. }
  1009. #endif