LargeHeapBlock.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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. #if defined(_M_X64_OR_ARM64)
  7. #define UINT_PAD_64BIT(x) uint x
  8. #else
  9. #define UINT_PAD_64BIT(x)
  10. #endif
  11. namespace Memory
  12. {
  13. struct LargeObjectHeader
  14. {
  15. uint objectIndex;
  16. UINT_PAD_64BIT(unused1);
  17. size_t objectSize;
  18. private:
  19. LargeObjectHeader * next;
  20. // xxxxxxxxyyyyyyyy, where xxxxxxxx = attributes field, yyyyyyyy = checksum field
  21. #if LARGEHEAPBLOCK_ENCODING
  22. ushort attributesAndChecksum;
  23. #else
  24. unsigned char attributes;
  25. unsigned char unused2;
  26. #endif
  27. public:
  28. bool markOnOOMRescan:1;
  29. #if DBG
  30. bool isExplicitFreed:1;
  31. bool isPageHeapFillVerified:1;
  32. #endif
  33. UINT_PAD_64BIT(unused4);
  34. void *GetAddress();
  35. #ifdef LARGEHEAPBLOCK_ENCODING
  36. unsigned char CalculateCheckSum(LargeObjectHeader* next, unsigned char attributes);
  37. LargeObjectHeader* EncodeNext(uint cookie, LargeObjectHeader* next);
  38. ushort EncodeAttributesAndChecksum(uint cookie, ushort attributesWithChecksum);
  39. LargeObjectHeader* DecodeNext(uint cookie, LargeObjectHeader* next);
  40. ushort DecodeAttributesAndChecksum(uint cookie);
  41. #else
  42. unsigned char * GetAttributesPtr();
  43. #endif
  44. void SetNext(uint cookie, LargeObjectHeader* next);
  45. LargeObjectHeader * GetNext(uint cookie);
  46. void SetAttributes(uint cookie, unsigned char attributes);
  47. unsigned char GetAttributes(uint cookie);
  48. };
  49. #if defined(_M_X64_OR_ARM64)
  50. static_assert(sizeof(LargeObjectHeader) == 0x20, "Incorrect LargeObjectHeader size");
  51. #else
  52. static_assert(sizeof(LargeObjectHeader) == 0x10, "Incorrect LargeObjectHeader size");
  53. #endif
  54. class LargeHeapBlock;
  55. class LargeHeapBucket;
  56. struct LargeHeapBlockFreeListEntry
  57. {
  58. uint headerIndex;
  59. size_t objectSize;
  60. LargeHeapBlock* heapBlock;
  61. LargeHeapBlockFreeListEntry* next;
  62. };
  63. struct LargeHeapBlockFreeList
  64. {
  65. public:
  66. LargeHeapBlockFreeList(LargeHeapBlock* heapBlock):
  67. previous(nullptr),
  68. next(nullptr),
  69. entries(nullptr),
  70. heapBlock(heapBlock)
  71. {
  72. }
  73. LargeHeapBlockFreeList* previous;
  74. LargeHeapBlockFreeList* next;
  75. LargeHeapBlockFreeListEntry* entries;
  76. LargeHeapBlock* heapBlock;
  77. };
  78. // CONSIDER: Templatizing this so that we don't have free list support if we don't need it
  79. class LargeHeapBlock sealed : public HeapBlock
  80. {
  81. public:
  82. Recycler * GetRecycler() const;
  83. #if DBG
  84. virtual BOOL IsFreeObject(void* objectAddress) override;
  85. #endif
  86. virtual BOOL IsValidObject(void* objectAddress) override;
  87. void Mark(void* objectAddress, MarkContext * markContext);
  88. virtual byte* GetRealAddressFromInterior(void* interiorAddress) override;
  89. bool TestObjectMarkedBit(void* objectAddress) override;
  90. void SetObjectMarkedBit(void* objectAddress) override;
  91. bool FindHeapObject(void* objectAddress, Recycler * recycler, FindHeapObjectFlags flags, RecyclerHeapObjectInfo& heapObject) override;
  92. virtual size_t GetObjectSize(void* object) override;
  93. bool FindImplicitRootObject(void* objectAddress, Recycler * recycler, RecyclerHeapObjectInfo& heapObject);
  94. size_t GetPageCount() const { return pageCount; }
  95. LargeHeapBlock * GetNextBlock() { return next; }
  96. void SetNextBlock(LargeHeapBlock * next) { this->next = next; }
  97. size_t GetFreeSize() const { return addressEnd - allocAddressEnd; }
  98. static LargeHeapBlock * New(__in char * address, __declspec(guard(overflow)) size_t pageCount, Segment * segment, __declspec(guard(overflow)) uint objectCount, LargeHeapBucket* bucket);
  99. static void Delete(LargeHeapBlock * heapBlock);
  100. bool IsInPendingDisposeList() { return isInPendingDisposeList; }
  101. void SetIsInPendingDisposeList(bool isInPendingDisposeList) { this->isInPendingDisposeList = isInPendingDisposeList; }
  102. #if DBG
  103. void SetHasDisposeBeenCalled(bool hasDisposeBeenCalled) { this->hasDisposeBeenCalled = hasDisposeBeenCalled; }
  104. #endif
  105. LargeHeapBlockFreeList* GetFreeList() { return &this->freeList; }
  106. ~LargeHeapBlock();
  107. size_t Rescan(Recycler* recycler, bool isPartialSwept, RescanFlags flags);
  108. #if ENABLE_PARTIAL_GC && ENABLE_CONCURRENT_GC
  109. void PartialTransferSweptObjects();
  110. void FinishPartialCollect(Recycler * recycler);
  111. #endif
  112. #ifdef RECYCLER_PAGE_HEAP
  113. void VerifyPageHeapPattern();
  114. #endif
  115. void ReleasePages(Recycler * recycler);
  116. void ReleasePagesSweep(Recycler * recycler);
  117. void ReleasePagesShutdown(Recycler * recycler);
  118. void ResetMarks(ResetMarkFlags flags, Recycler* recycler);
  119. void ScanInitialImplicitRoots(Recycler * recycler);
  120. void ScanNewImplicitRoots(Recycler * recycler);
  121. SweepState Sweep(RecyclerSweep& recyclerSweep, bool queuePendingSweep);
  122. template <SweepMode mode>
  123. void SweepObjects(Recycler * recycler);
  124. bool TransferSweptObjects();
  125. void DisposeObjects(Recycler * recycler);
  126. void FinalizeObjects(Recycler* recycler);
  127. void FinalizeAllObjects();
  128. char* GetBeginAddress() const { return address; }
  129. char* GetEndAddress() const { return addressEnd; }
  130. char * Alloc(__declspec(guard(overflow)) size_t size, ObjectInfoBits attributes);
  131. char * TryAllocFromFreeList(__declspec(guard(overflow)) size_t size, ObjectInfoBits attributes);
  132. static size_t GetPagesNeeded(__declspec(guard(overflow)) size_t size, bool multiplyRequest);
  133. static uint GetMaxLargeObjectCount(size_t pageCount, size_t firstAllocationSize);
  134. void EnumerateObjects(ObjectInfoBits infoBits, void (*CallBackFunction)(void * address, size_t size));
  135. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  136. void Check(bool expectFull, bool expectPending);
  137. #endif
  138. #ifdef RECYCLER_MEMORY_VERIFY
  139. void Verify(Recycler * recycler);
  140. #endif
  141. #ifdef RECYCLER_VERIFY_MARK
  142. void VerifyMark();
  143. virtual void VerifyMark(void * objectAddress) override;
  144. #endif
  145. #ifdef RECYCLER_PERF_COUNTERS
  146. virtual void UpdatePerfCountersOnFree() override;
  147. #endif
  148. #ifdef PROFILE_RECYCLER_ALLOC
  149. virtual void * GetTrackerData(void * address) override;
  150. virtual void SetTrackerData(void * address, void * data) override;
  151. #endif
  152. private:
  153. friend class LargeHeapBucket;
  154. #ifdef RECYCLER_MEMORY_VERIFY
  155. friend class Recycler;
  156. #endif
  157. LargeHeapBlock(__in char * address, __declspec(guard(overflow)) size_t pageCount, Segment * segment, __declspec(guard(overflow)) uint objectCount, LargeHeapBucket* bucket);
  158. static LargeObjectHeader * GetHeaderFromAddress(void * address);
  159. LargeObjectHeader * GetHeader(void * address);
  160. LargeObjectHeader ** HeaderList();
  161. LargeObjectHeader * GetHeader(uint index)
  162. {
  163. Assert(index < this->allocCount);
  164. LargeObjectHeader * header = this->HeaderList()[index];
  165. #if ENABLE_PARTIAL_GC && ENABLE_CONCURRENT_GC
  166. if (IsPartialSweptHeader(header))
  167. {
  168. return nullptr;
  169. }
  170. #endif
  171. return header;
  172. }
  173. uint GetMarkCount();
  174. bool GetObjectHeader(void* objectAddress, LargeObjectHeader** ppHeader);
  175. BOOL IsNewHeapBlock() const { return lastCollectAllocCount == 0; }
  176. static size_t GetAllocPlusSize(__declspec(guard(overflow)) uint objectCount);
  177. char * AllocFreeListEntry(__declspec(guard(overflow)) size_t size, ObjectInfoBits attributes, LargeHeapBlockFreeListEntry* entry);
  178. #if ENABLE_CONCURRENT_GC
  179. bool RescanOnePage(Recycler * recycler, DWORD const writeWatchFlags);
  180. size_t RescanMultiPage(Recycler * recycler, DWORD const writeWatchFlags);
  181. #else
  182. bool RescanOnePage(Recycler * recycler);
  183. size_t RescanMultiPage(Recycler * recycler);
  184. #endif
  185. template <SweepMode>
  186. void SweepObject(Recycler * recycler, LargeObjectHeader * header);
  187. bool TrimObject(Recycler* recycler, LargeObjectHeader* header, size_t sizeOfObject, bool needSuspend = false);
  188. void FinalizeObject(Recycler* recycler, LargeObjectHeader* header);
  189. void FillFreeMemory(Recycler * recycler, __in_bcount(size) void * address, size_t size);
  190. #if ENABLE_PARTIAL_GC && ENABLE_CONCURRENT_GC
  191. bool IsPartialSweptHeader(LargeObjectHeader * header) const
  192. {
  193. Assert(this->hasPartialFreeObjects || (((size_t)header & PartialFreeBit) != PartialFreeBit));
  194. return ((size_t)header & PartialFreeBit) == PartialFreeBit;
  195. }
  196. static const size_t PartialFreeBit = 0x1;
  197. #endif
  198. size_t pageCount;
  199. size_t actualPageCount;
  200. // The number of allocations that have occurred from this heap block
  201. // This only increases, never decreases. Instead, we rely on the mark/weakRef/finalize counts
  202. // to determine if an object has been freed or not. So when we alloc, we keep alloc'ing
  203. // from the last allocation even if there are holes in the large heap block. If we free an object,
  204. // we simply set its header to null. But otherwise, we simply constantly keep increasing allocCount
  205. // till the heap block is full.
  206. uint allocCount;
  207. // Maximum number of objects that can be fit into this heap block
  208. // This is based on the fact that the largest small object size is 1024
  209. // So the smallest large object size is 1025. We can calculate the max object count
  210. // as follows. The total size available to us is the pageCount * pageSize.
  211. // When we allocate the large heap block, it's to fit a large object. So the amount
  212. // of space remaining is totalSize - sizeOfLargeObject - sizeOfLargeObjectHeader
  213. // So the max number of objects this heap block can support is remainingSize / maxSmallObjectSize + 1
  214. // where 1 is the initial object that was used to create the heap block
  215. uint objectCount;
  216. char * allocAddressEnd;
  217. char * addressEnd;
  218. LargeHeapBlock* next;
  219. LargeObjectHeader * pendingDisposeObject;
  220. LargeHeapBucket* bucket;
  221. LargeHeapBlockFreeList freeList;
  222. uint lastCollectAllocCount;
  223. uint finalizeCount;
  224. bool isInPendingDisposeList;
  225. #ifdef RECYCLER_PAGE_HEAP
  226. PageHeapMode pageHeapMode;
  227. char* guardPageAddress;
  228. StackBackTrace* pageHeapAllocStack;
  229. StackBackTrace* pageHeapFreeStack;
  230. public:
  231. __inline bool InPageHeapMode() const { return pageHeapMode != PageHeapMode::PageHeapModeOff; }
  232. void CapturePageHeapAllocStack();
  233. void CapturePageHeapFreeStack();
  234. const static StackBackTrace* s_StackTraceAllocFailed;
  235. #endif
  236. #if DBG
  237. bool hasDisposeBeenCalled;
  238. bool hasPartialFreeObjects;
  239. uint expectedSweepCount;
  240. // The following get set if an object is swept and we freed its pages
  241. bool hadTrimmed;
  242. #endif
  243. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  244. friend class ScriptMemoryDumper;
  245. #endif
  246. friend class HeapInfo;
  247. HeapInfo * heapInfo;
  248. #ifdef PROFILE_RECYCLER_ALLOC
  249. void ** GetTrackerDataArray();
  250. #endif
  251. };
  252. }