LargeHeapBlock.h 12 KB

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