HeapBlock.cpp 76 KB

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