HeapBlock.inl 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. template <class TBlockAttributes>
  7. void
  8. SmallHeapBlockT<TBlockAttributes>::SetAttributes(void * address, unsigned char attributes)
  9. {
  10. Assert(this->address != nullptr);
  11. Assert(this->segment != nullptr);
  12. ushort index = GetAddressIndex(address);
  13. Assert(this->ObjectInfo(index) == 0);
  14. Assert(index != SmallHeapBlockT<TBlockAttributes>::InvalidAddressBit);
  15. ObjectInfo(index) = attributes;
  16. }
  17. inline
  18. IdleDecommitPageAllocator*
  19. HeapBlock::GetPageAllocator(HeapInfo * heapInfo)
  20. {
  21. switch (this->GetHeapBlockType())
  22. {
  23. case SmallLeafBlockType:
  24. case MediumLeafBlockType:
  25. return heapInfo->GetRecyclerLeafPageAllocator();
  26. case LargeBlockType:
  27. return heapInfo->GetRecyclerLargeBlockPageAllocator();
  28. #ifdef RECYCLER_WRITE_BARRIER
  29. case SmallNormalBlockWithBarrierType:
  30. case SmallFinalizableBlockWithBarrierType:
  31. case MediumNormalBlockWithBarrierType:
  32. case MediumFinalizableBlockWithBarrierType:
  33. #ifdef RECYCLER_WRITE_BARRIER_ALLOC_THREAD_PAGE
  34. return heapInfo->GetRecyclerLeafPageAllocator();
  35. #elif defined(RECYCLER_WRITE_BARRIER_ALLOC_SEPARATE_PAGE)
  36. return heapInfo->GetRecyclerWithBarrierPageAllocator();
  37. #endif
  38. #endif
  39. default:
  40. return heapInfo->GetRecyclerPageAllocator();
  41. };
  42. }
  43. template <class TBlockAttributes>
  44. IdleDecommitPageAllocator*
  45. SmallHeapBlockT<TBlockAttributes>::GetPageAllocator()
  46. {
  47. return __super::GetPageAllocator(this->heapBucket->heapInfo);
  48. }
  49. template <class TBlockAttributes>
  50. template <class Fn>
  51. void SmallHeapBlockT<TBlockAttributes>::ForEachAllocatedObject(Fn fn)
  52. {
  53. uint const objectBitDelta = this->GetObjectBitDelta();
  54. SmallHeapBlockBitVector * free = this->EnsureFreeBitVector();
  55. char * address = this->GetAddress();
  56. uint objectSize = this->GetObjectSize();
  57. for (uint i = 0; i < objectCount; i++)
  58. {
  59. if (!free->Test(i * objectBitDelta))
  60. {
  61. fn(i, address + i * objectSize);
  62. }
  63. }
  64. }
  65. template <class TBlockAttributes>
  66. template <typename Fn>
  67. void SmallHeapBlockT<TBlockAttributes>::ForEachAllocatedObject(ObjectInfoBits attributes, Fn fn)
  68. {
  69. ForEachAllocatedObject([=](uint index, void * objectAddress)
  70. {
  71. if ((ObjectInfo(index) & attributes) != 0)
  72. {
  73. fn(index, objectAddress);
  74. }
  75. });
  76. };
  77. template <class TBlockAttributes>
  78. template <typename Fn>
  79. void SmallHeapBlockT<TBlockAttributes>::ScanNewImplicitRootsBase(Fn fn)
  80. {
  81. uint const localObjectCount = this->objectCount;
  82. // NOTE: we no longer track the mark count as we mark. So this value
  83. // is basically the mark count we set during the initial implicit root scan
  84. // plus any subsequent new implicit root scan.
  85. uint localMarkCount = this->markCount;
  86. if (localMarkCount == localObjectCount)
  87. {
  88. // The block is full when we first do the initial implicit root scan
  89. // So there can't be any new implicit roots
  90. return;
  91. }
  92. #if DBG
  93. HeapBlockMap& map = this->GetRecycler()->heapBlockMap;
  94. ushort newlyMarkedCountForPage[TBlockAttributes::PageCount];
  95. for (uint i = 0; i < TBlockAttributes::PageCount; i++)
  96. {
  97. newlyMarkedCountForPage[i] = 0;
  98. }
  99. #endif
  100. uint const localObjectBitDelta = this->GetObjectBitDelta();
  101. uint const localObjectSize = this->GetObjectSize();
  102. Assert(localObjectSize <= HeapConstants::MaxMediumObjectSize);
  103. SmallHeapBlockBitVector * mark = this->GetMarkedBitVector();
  104. char * address = this->GetAddress();
  105. for (uint i = 0; i < localObjectCount; i++)
  106. {
  107. if ((this->ObjectInfo(i) & ImplicitRootBit) != 0
  108. && !mark->TestAndSet(i * localObjectBitDelta))
  109. {
  110. uint objectOffset = i * localObjectSize;
  111. localMarkCount++;
  112. #if DBG
  113. uint pageNumber = objectOffset / AutoSystemInfo::PageSize;
  114. Assert(pageNumber < TBlockAttributes::PageCount);
  115. newlyMarkedCountForPage[pageNumber]++;
  116. #endif
  117. fn(address + objectOffset, localObjectSize);
  118. }
  119. }
  120. Assert(localMarkCount <= USHRT_MAX);
  121. #if DBG
  122. // Add newly marked count
  123. for (uint i = 0; i < TBlockAttributes::PageCount; i++)
  124. {
  125. char* pageAddress = address + (AutoSystemInfo::PageSize * i);
  126. ushort oldPageMarkCount = map.GetPageMarkCount(pageAddress);
  127. map.SetPageMarkCount(pageAddress, oldPageMarkCount + newlyMarkedCountForPage[i]);
  128. }
  129. #endif
  130. this->markCount = (ushort)localMarkCount;
  131. }
  132. template <class TBlockAttributes>
  133. bool
  134. SmallHeapBlockT<TBlockAttributes>::FindImplicitRootObject(void* candidate, Recycler* recycler, RecyclerHeapObjectInfo& heapObject)
  135. {
  136. ushort index = GetAddressIndex(candidate);
  137. if (index == InvalidAddressBit)
  138. {
  139. return false;
  140. }
  141. byte& attributes = ObjectInfo(index);
  142. heapObject = RecyclerHeapObjectInfo(candidate, recycler, this, &attributes);
  143. return true;
  144. }
  145. template <bool doSpecialMark, typename Fn>
  146. bool
  147. HeapBlock::UpdateAttributesOfMarkedObjects(MarkContext * markContext, void * objectAddress, size_t objectSize, unsigned char attributes, Fn fn)
  148. {
  149. #ifdef RECYCLER_VISITED_HOST
  150. Assert(GetHeapBlockType() != HeapBlock::HeapBlockType::SmallRecyclerVisitedHostBlockType && GetHeapBlockType() != HeapBlock::HeapBlockType::MediumRecyclerVisitedHostBlockType && GetHeapBlockType() != HeapBlock::HeapBlockType::LargeBlockType);
  151. #endif
  152. bool noOOMDuringMark = true;
  153. if (attributes & TrackBit)
  154. {
  155. FinalizableObject * trackedObject = (FinalizableObject *)objectAddress;
  156. #if ENABLE_PARTIAL_GC
  157. if (!markContext->GetRecycler()->inPartialCollectMode)
  158. #endif
  159. {
  160. #if ENABLE_CONCURRENT_GC
  161. if (markContext->GetRecycler()->DoQueueTrackedObject())
  162. {
  163. if (!markContext->AddTrackedObject(trackedObject))
  164. {
  165. noOOMDuringMark = false;
  166. }
  167. }
  168. else
  169. #endif
  170. {
  171. // Process the tracked object right now
  172. markContext->MarkTrackedObject(trackedObject);
  173. }
  174. }
  175. if (noOOMDuringMark)
  176. {
  177. // Object has been successfully processed, so clear NewTrackBit
  178. attributes &= ~NewTrackBit;
  179. }
  180. else
  181. {
  182. // Set the NewTrackBit, so that the main thread will redo tracking
  183. attributes |= NewTrackBit;
  184. noOOMDuringMark = false;
  185. }
  186. fn(attributes);
  187. }
  188. // only need to scan non-leaf objects
  189. if ((attributes & LeafBit) == 0)
  190. {
  191. if (!markContext->AddMarkedObject(objectAddress, objectSize))
  192. {
  193. noOOMDuringMark = false;
  194. }
  195. }
  196. // Special mark-time behavior for finalizable objects on certain GC's
  197. if (doSpecialMark)
  198. {
  199. if (attributes & FinalizeBit)
  200. {
  201. FinalizableObject * trackedObject = (FinalizableObject *)objectAddress;
  202. trackedObject->OnMark();
  203. }
  204. }
  205. #ifdef RECYCLER_STATS
  206. RECYCLER_STATS_INTERLOCKED_INC(markContext->GetRecycler(), markData.markCount);
  207. RECYCLER_STATS_INTERLOCKED_ADD(markContext->GetRecycler(), markData.markBytes, objectSize);
  208. // Don't count track or finalize it if we still have to process it in thread because of OOM
  209. if ((attributes & (TrackBit | NewTrackBit)) != (TrackBit | NewTrackBit))
  210. {
  211. // Only count those we have queued, so we don't double count
  212. if (attributes & TrackBit)
  213. {
  214. RECYCLER_STATS_INTERLOCKED_INC(markContext->GetRecycler(), trackCount);
  215. }
  216. if (attributes & FinalizeBit)
  217. {
  218. // we counted the finalizable object here,
  219. // turn off the new bit so we don't count it again
  220. // on Rescan
  221. attributes &= ~NewFinalizeBit;
  222. fn(attributes);
  223. RECYCLER_STATS_INTERLOCKED_INC(markContext->GetRecycler(), finalizeCount);
  224. }
  225. }
  226. #endif
  227. return noOOMDuringMark;
  228. }