HeapBlock.h 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  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. class ScriptMemoryDumper;
  6. namespace Memory
  7. {
  8. #ifdef RECYCLER_PAGE_HEAP
  9. enum class PageHeapBlockTypeFilter;
  10. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  11. #define PageHeapVerboseTrace(flags, ...) \
  12. if (flags.Verbose && flags.Trace.IsEnabled(Js::PageHeapPhase)) \
  13. { \
  14. Output::Print(__VA_ARGS__); \
  15. }
  16. #define PageHeapTrace(flags, ...) \
  17. if (flags.Trace.IsEnabled(Js::PageHeapPhase)) \
  18. { \
  19. Output::Print(__VA_ARGS__); \
  20. }
  21. #else
  22. #define PageHeapVerboseTrace(...)
  23. #define PageHeapTrace(...)
  24. #endif
  25. #else
  26. #define PageHeapVerboseTrace(...)
  27. #define PageHeapTrace(...)
  28. #endif
  29. class Recycler;
  30. class HeapBucket;
  31. template <typename TBlockType> class HeapBucketT;
  32. class RecyclerSweep;
  33. class MarkContext;
  34. #ifdef DUMP_FRAGMENTATION_STATS
  35. struct HeapBucketStats
  36. {
  37. uint totalBlockCount;
  38. uint emptyBlockCount;
  39. uint finalizeBlockCount;
  40. uint objectCount;
  41. uint finalizeCount;
  42. uint objectByteCount;
  43. uint totalByteCount;
  44. };
  45. #endif
  46. #if defined(PROFILE_RECYCLER_ALLOC) || defined(RECYCLER_MEMORY_VERIFY) || defined(MEMSPECT_TRACKING) || defined(RECYCLER_PERF_COUNTERS) || defined(ETW_MEMORY_TRACKING)
  47. #define RECYCLER_TRACK_NATIVE_ALLOCATED_OBJECTS
  48. #endif
  49. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  50. #define RECYCLER_SLOW_CHECK(x) x
  51. #define RECYCLER_SLOW_CHECK_IF(cond, x) if (cond) { x; }
  52. #else
  53. #define RECYCLER_SLOW_CHECK(x)
  54. #define RECYCLER_SLOW_CHECK_IF(cond, x)
  55. #endif
  56. // ObjectInfoBits is unsigned short, but only the lower byte is stored as the object attribute
  57. // The upper bits are used to pass other information about allocation (e.g. NoDisposeBit)
  58. //
  59. enum ObjectInfoBits : unsigned short
  60. {
  61. // Bits that are actually stored in ObjectInfo
  62. NoBit = 0x00, // assume an allocation is not leaf unless LeafBit is specified.
  63. FinalizeBit = 0x80, // Indicates that the object has a finalizer
  64. PendingDisposeBit = 0x40, // Indicates that the object is pending dispose
  65. LeafBit = 0x20, // Indicates that the object is a leaf-object (objects without this bit need to be scanned)
  66. TrackBit = 0x10, // Indicates that the object is a TrackableObject
  67. ImplicitRootBit = 0x08,
  68. NewTrackBit = 0x04, // Tracked object is newly allocated and hasn't been process by concurrent GC
  69. MemoryProfilerOldObjectBit = 0x02,
  70. EnumClass_1_Bit = 0x01, // This can be extended to add more enumerable classes (if we still have bits left)
  71. // Mask for above bits
  72. StoredObjectInfoBitMask = 0xFF,
  73. // Bits that implied by the block type, and thus don't need to be stored (for small blocks)
  74. // Note, LeafBit is used in finalizable blocks, thus is not always implied by the block type
  75. // GC-TODO: FinalizeBit doesn't need to be stored since we have separate bucket for them.
  76. // We can move it the upper byte.
  77. #ifdef RECYCLER_WRITE_BARRIER
  78. WithBarrierBit = 0x0100,
  79. #endif
  80. // Mask for above bits
  81. InternalObjectInfoBitMask = 0x01FF,
  82. // Bits that only affect allocation behavior, not mark/sweep/etc
  83. ClientTrackedBit = 0x0200, // This allocation is client tracked
  84. TraceBit = 0x0400,
  85. // Additional definitions based on above
  86. #ifdef RECYCLER_STATS
  87. NewFinalizeBit = NewTrackBit, // Use to detect if the background thread has counted the finalizable object in stats
  88. #else
  89. NewFinalizeBit = 0x00,
  90. #endif
  91. #ifdef RECYCLER_WRITE_BARRIER
  92. FinalizableWithBarrierBit = WithBarrierBit | FinalizeBit,
  93. #endif
  94. // Allocation bits
  95. FinalizableLeafBits = NewFinalizeBit | FinalizeBit | LeafBit,
  96. FinalizableObjectBits = NewFinalizeBit | FinalizeBit ,
  97. #ifdef RECYCLER_WRITE_BARRIER
  98. FinalizableWithBarrierObjectBits = NewFinalizeBit | FinalizableWithBarrierBit,
  99. #endif
  100. ClientFinalizableObjectBits = NewFinalizeBit | ClientTrackedBit | FinalizeBit,
  101. ClientTrackableLeafBits = NewTrackBit | ClientTrackedBit | TrackBit | FinalizeBit | LeafBit,
  102. ClientTrackableObjectBits = NewTrackBit | ClientTrackedBit | TrackBit | FinalizeBit,
  103. #ifdef RECYCLER_WRITE_BARRIER
  104. ClientTrackableObjectWithBarrierBits = ClientTrackableObjectBits | WithBarrierBit,
  105. ClientFinalizableObjectWithBarrierBits = ClientFinalizableObjectBits | WithBarrierBit,
  106. #endif
  107. WeakReferenceEntryBits = LeafBit,
  108. ImplicitRootLeafBits = LeafBit | ImplicitRootBit,
  109. // Pending dispose objects should have LeafBit set and no others
  110. PendingDisposeObjectBits = PendingDisposeBit | LeafBit,
  111. #ifdef RECYCLER_WRITE_BARRIER
  112. GetBlockTypeBitMask = FinalizeBit | LeafBit | WithBarrierBit,
  113. #else
  114. GetBlockTypeBitMask = FinalizeBit | LeafBit,
  115. #endif
  116. CollectionBitMask = LeafBit | FinalizeBit | TrackBit | NewTrackBit, // Bits relevant to collection
  117. EnumClassMask = EnumClass_1_Bit,
  118. };
  119. enum ResetMarkFlags
  120. {
  121. ResetMarkFlags_None = 0x0,
  122. ResetMarkFlags_Background = 0x1,
  123. ResetMarkFlags_ScanImplicitRoot = 0x2,
  124. // For in thread GC
  125. ResetMarkFlags_InThread = ResetMarkFlags_None,
  126. ResetMarkFlags_InThreadImplicitRoots = ResetMarkFlags_None | ResetMarkFlags_ScanImplicitRoot,
  127. // For background GC
  128. ResetMarkFlags_InBackgroundThread = ResetMarkFlags_Background,
  129. ResetMarkFlags_InBackgroundThreadImplicitRoots = ResetMarkFlags_Background | ResetMarkFlags_ScanImplicitRoot,
  130. // For blocking synchronized GC
  131. ResetMarkFlags_Synchronized = ResetMarkFlags_None,
  132. ResetMarkFlags_SynchronizedImplicitRoots = ResetMarkFlags_None | ResetMarkFlags_ScanImplicitRoot,
  133. // For heap enumeration
  134. ResetMarkFlags_HeapEnumeration = ResetMarkFlags_None,
  135. };
  136. enum RescanFlags
  137. {
  138. RescanFlags_None = 0x0,
  139. RescanFlags_ResetWriteWatch = 0x1
  140. };
  141. enum FindHeapObjectFlags
  142. {
  143. FindHeapObjectFlags_NoFlags = 0x0,
  144. FindHeapObjectFlags_ClearedAllocators = 0x1, // Assumes that the allocator is already cleared
  145. FindHeapObjectFlags_VerifyFreeBitForAttribute = 0x2, // Don't recompute the free bit vector if there is no pending objects, the attributes will always be correct
  146. FindHeapObjectFlags_NoFreeBitVerify = 0x4, // No checking whether the address is free or not.
  147. FindHeapObjectFlags_AllowInterior = 0x8, // Allow finding heap objects for interior pointers.
  148. };
  149. template <class TBlockAttributes> class SmallNormalHeapBlockT;
  150. template <class TBlockAttributes> class SmallLeafHeapBlockT;
  151. template <class TBlockAttributes> class SmallFinalizableHeapBlockT;
  152. #ifdef RECYCLER_WRITE_BARRIER
  153. template <class TBlockAttributes> class SmallNormalWithBarrierHeapBlockT;
  154. template <class TBlockAttributes> class SmallFinalizableWithBarrierHeapBlockT;
  155. #define EXPLICIT_INSTANTIATE_WITH_SMALL_HEAP_BLOCK_TYPE(TemplateType) \
  156. template class TemplateType<Memory::SmallNormalHeapBlock>; \
  157. template class TemplateType<Memory::SmallLeafHeapBlock>; \
  158. template class TemplateType<Memory::SmallFinalizableHeapBlock>; \
  159. template class TemplateType<Memory::SmallNormalWithBarrierHeapBlock>; \
  160. template class TemplateType<Memory::SmallFinalizableWithBarrierHeapBlock>; \
  161. template class TemplateType<Memory::MediumNormalHeapBlock>; \
  162. template class TemplateType<Memory::MediumLeafHeapBlock>; \
  163. template class TemplateType<Memory::MediumFinalizableHeapBlock>; \
  164. template class TemplateType<Memory::MediumNormalWithBarrierHeapBlock>; \
  165. template class TemplateType<Memory::MediumFinalizableWithBarrierHeapBlock>; \
  166. #else
  167. #define EXPLICIT_INSTANTIATE_WITH_SMALL_HEAP_BLOCK_TYPE(TemplateType) \
  168. template class TemplateType<Memory::SmallNormalHeapBlock>; \
  169. template class TemplateType<Memory::SmallLeafHeapBlock>; \
  170. template class TemplateType<Memory::SmallFinalizableHeapBlock>; \
  171. template class TemplateType<Memory::MediumNormalHeapBlock>; \
  172. template class TemplateType<Memory::MediumLeafHeapBlock>; \
  173. template class TemplateType<Memory::MediumFinalizableHeapBlock>; \
  174. #endif
  175. class RecyclerHeapObjectInfo;
  176. class HeapBlock
  177. {
  178. public:
  179. enum HeapBlockType : byte
  180. {
  181. FreeBlockType = 0, // Only used in HeapBlockMap. Actual HeapBlock structures should never have this.
  182. SmallNormalBlockType = 1,
  183. SmallLeafBlockType = 2,
  184. SmallFinalizableBlockType = 3,
  185. #ifdef RECYCLER_WRITE_BARRIER
  186. SmallNormalBlockWithBarrierType = 4,
  187. SmallFinalizableBlockWithBarrierType = 5,
  188. #endif
  189. MediumNormalBlockType = 6,
  190. MediumLeafBlockType = 7,
  191. MediumFinalizableBlockType = 8,
  192. #ifdef RECYCLER_WRITE_BARRIER
  193. MediumNormalBlockWithBarrierType = 9,
  194. MediumFinalizableBlockWithBarrierType = 10,
  195. #endif
  196. LargeBlockType = 11,
  197. SmallAllocBlockTypeCount = 6, // Actual number of types for blocks containing small allocations
  198. MediumAllocBlockTypeCount = 5, // Actual number of types for blocks containing medium allocations
  199. SmallBlockTypeCount = 11, // Distinct block types independent of allocation size using SmallHeapBlockT
  200. BlockTypeCount = 12,
  201. };
  202. bool IsNormalBlock() const { return this->GetHeapBlockType() == SmallNormalBlockType || this->GetHeapBlockType() == MediumNormalBlockType; }
  203. bool IsLeafBlock() const { return this->GetHeapBlockType() == SmallLeafBlockType || this->GetHeapBlockType() == MediumLeafBlockType; }
  204. bool IsFinalizableBlock() const { return this->GetHeapBlockType() == SmallFinalizableBlockType || this->GetHeapBlockType() == MediumFinalizableBlockType; }
  205. #ifdef RECYCLER_WRITE_BARRIER
  206. bool IsAnyNormalBlock() const { return IsNormalBlock() || IsNormalWriteBarrierBlock(); }
  207. bool IsAnyFinalizableBlock() const { return IsFinalizableBlock() || IsFinalizableWriteBarrierBlock(); }
  208. bool IsNormalWriteBarrierBlock() const { return this->GetHeapBlockType() == SmallNormalBlockWithBarrierType || this->GetHeapBlockType() == MediumNormalBlockWithBarrierType; }
  209. bool IsFinalizableWriteBarrierBlock() const { return this->GetHeapBlockType() == SmallFinalizableBlockWithBarrierType || this->GetHeapBlockType() == MediumFinalizableBlockWithBarrierType; }
  210. #else
  211. bool IsAnyFinalizableBlock() const { return IsFinalizableBlock(); }
  212. bool IsAnyNormalBlock() const { return IsNormalBlock(); }
  213. #endif
  214. bool IsLargeHeapBlock() const { return this->GetHeapBlockType() == LargeBlockType; }
  215. char * GetAddress() const { return address; }
  216. Segment * GetSegment() const { return segment; }
  217. template <typename TBlockAttributes>
  218. SmallNormalHeapBlockT<TBlockAttributes> * AsNormalBlock();
  219. template <typename TBlockAttributes>
  220. SmallLeafHeapBlockT<TBlockAttributes> * AsLeafBlock();
  221. template <typename TBlockAttributes>
  222. SmallFinalizableHeapBlockT<TBlockAttributes> * AsFinalizableBlock();
  223. #ifdef RECYCLER_WRITE_BARRIER
  224. template <typename TBlockAttributes>
  225. SmallNormalWithBarrierHeapBlockT<TBlockAttributes> * AsNormalWriteBarrierBlock();
  226. template <typename TBlockAttributes>
  227. SmallFinalizableWithBarrierHeapBlockT<TBlockAttributes> * AsFinalizableWriteBarrierBlock();
  228. #endif
  229. protected:
  230. char * address;
  231. Segment * segment;
  232. HeapBlockType const heapBlockType;
  233. bool needOOMRescan; // Set if we OOMed while marking a particular object
  234. #if ENABLE_CONCURRENT_GC
  235. bool isPendingConcurrentSweep;
  236. #endif
  237. public:
  238. template <bool doSpecialMark, typename Fn>
  239. bool UpdateAttributesOfMarkedObjects(MarkContext * markContext, void * objectAddress, size_t objectSize, unsigned char attributes, Fn fn);
  240. void SetNeedOOMRescan(Recycler * recycler);
  241. public:
  242. HeapBlock(HeapBlockType heapBlockType) :
  243. heapBlockType(heapBlockType),
  244. needOOMRescan(false)
  245. {
  246. Assert(GetHeapBlockType() <= HeapBlock::HeapBlockType::BlockTypeCount);
  247. }
  248. HeapBlockType const GetHeapBlockType() const
  249. {
  250. return (heapBlockType);
  251. }
  252. IdleDecommitPageAllocator* GetPageAllocator(Recycler* recycler);
  253. bool GetAndClearNeedOOMRescan()
  254. {
  255. if (this->needOOMRescan)
  256. {
  257. this->needOOMRescan = false;
  258. return true;
  259. }
  260. return false;
  261. }
  262. #if DBG
  263. #if GLOBAL_ENABLE_WRITE_BARRIER
  264. virtual void WBSetBit(char* addr) = 0;
  265. virtual void WBSetBitRange(char* addr, uint count) = 0;
  266. virtual void WBClearBit(char* addr) = 0;
  267. virtual void WBVerifyBitIsSet(char* addr) = 0;
  268. virtual void WBClearObject(char* addr) = 0;
  269. #endif
  270. static void PrintVerifyMarkFailure(Recycler* recycler, char* objectAddress, char* target);
  271. #endif
  272. #if DBG
  273. virtual BOOL IsFreeObject(void* objectAddress) = 0;
  274. #endif
  275. virtual BOOL IsValidObject(void* objectAddress) = 0;
  276. virtual byte* GetRealAddressFromInterior(void* interiorAddress) = 0;
  277. virtual size_t GetObjectSize(void* object) = 0;
  278. virtual bool FindHeapObject(void* objectAddress, Recycler * recycler, FindHeapObjectFlags flags, RecyclerHeapObjectInfo& heapObject) = 0;
  279. virtual bool TestObjectMarkedBit(void* objectAddress) = 0;
  280. virtual void SetObjectMarkedBit(void* objectAddress) = 0;
  281. #ifdef RECYCLER_VERIFY_MARK
  282. virtual bool VerifyMark(void * objectAddress, void * target) = 0;
  283. #endif
  284. #ifdef PROFILE_RECYCLER_ALLOC
  285. virtual void * GetTrackerData(void * address) = 0;
  286. virtual void SetTrackerData(void * address, void * data) = 0;
  287. #endif
  288. #if DBG || defined(RECYCLER_STATS) || defined(RECYCLER_PAGE_HEAP)
  289. bool isForceSweeping;
  290. #endif
  291. #ifdef RECYCLER_PERF_COUNTERS
  292. virtual void UpdatePerfCountersOnFree() = 0;
  293. #endif
  294. };
  295. enum SweepMode
  296. {
  297. SweepMode_InThread,
  298. #if ENABLE_CONCURRENT_GC
  299. SweepMode_Concurrent,
  300. #if ENABLE_PARTIAL_GC
  301. SweepMode_ConcurrentPartial
  302. #endif
  303. #endif
  304. };
  305. // enum indicating the result of a sweep
  306. enum SweepState
  307. {
  308. SweepStateEmpty, // the block is completely empty and can be released
  309. SweepStateSwept, // the block is partially allocated, no object needs to be swept or finalized
  310. SweepStateFull, // the block is full, no object needs to be swept or finalized
  311. SweepStatePendingDispose, // the block has object that needs to be finalized
  312. #if ENABLE_CONCURRENT_GC
  313. SweepStatePendingSweep, // the block has object that needs to be swept
  314. #endif
  315. };
  316. template <class TBlockAttributes>
  317. class ValidPointers
  318. {
  319. public:
  320. ValidPointers(ushort const * validPointers);
  321. ushort GetInteriorAddressIndex(uint index) const;
  322. ushort GetAddressIndex(uint index) const;
  323. private:
  324. ushort const * validPointers;
  325. };
  326. template <class TBlockAttributes>
  327. class SmallHeapBlockT : public HeapBlock
  328. {
  329. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  330. friend class ::ScriptMemoryDumper;
  331. #endif
  332. template <typename TBlockType>
  333. friend class SmallHeapBlockAllocator;
  334. friend class HeapInfo;
  335. friend class RecyclerSweep;
  336. template <typename TBlockType>
  337. friend class SmallNormalHeapBucketBase;
  338. public:
  339. static const ushort InvalidAddressBit = 0xFFFF;
  340. typedef BVStatic<TBlockAttributes::BitVectorCount> SmallHeapBlockBitVector;
  341. struct BlockInfo
  342. {
  343. ushort lastObjectIndexOnPage;
  344. ushort pageObjectCount;
  345. };
  346. bool FindImplicitRootObject(void* candidate, Recycler* recycler, RecyclerHeapObjectInfo& heapObject);
  347. SmallHeapBlockT* next;
  348. FreeObject* freeObjectList;
  349. FreeObject* lastFreeObjectHead;
  350. ValidPointers<TBlockAttributes> validPointers;
  351. HeapBucket * heapBucket;
  352. // Review: Should GetBucketIndex return a short instead of an int?
  353. const uint bucketIndex;
  354. const ushort objectSize; // size in bytes
  355. const ushort objectCount;
  356. ushort freeCount;
  357. ushort lastFreeCount;
  358. ushort markCount;
  359. #if ENABLE_PARTIAL_GC
  360. ushort oldFreeCount;
  361. #endif
  362. bool isInAllocator;
  363. #if DBG
  364. bool isClearedFromAllocator;
  365. bool isIntegratedBlock;
  366. uint lastUncollectedAllocBytes;
  367. #endif
  368. SmallHeapBlockBitVector* markBits;
  369. SmallHeapBlockBitVector freeBits;
  370. #if DBG
  371. // TODO: (leish)(swb) move this to the block header if memory pressure on chk build is a problem
  372. // this causes 1/64 more memory usage on x64 or 1/32 more on x86
  373. BVStatic<TBlockAttributes::PageCount * AutoSystemInfo::PageSize / sizeof(void*)> wbVerifyBits;
  374. #endif
  375. #if DBG || defined(RECYCLER_STATS)
  376. SmallHeapBlockBitVector debugFreeBits;
  377. #endif
  378. #ifdef RECYCLER_MEMORY_VERIFY
  379. SmallHeapBlockBitVector explicitFreeBits;
  380. #endif
  381. bool IsFreeBitsValid() const
  382. {
  383. return this->freeObjectList == this->lastFreeObjectHead;
  384. }
  385. PageSegment * GetPageSegment() const { return (PageSegment *)GetSegment(); }
  386. public:
  387. ~SmallHeapBlockT();
  388. void ProtectUnusablePages() {}
  389. void RestoreUnusablePages() {}
  390. #if DBG && GLOBAL_ENABLE_WRITE_BARRIER
  391. virtual void WBVerifyBitIsSet(char* addr) override
  392. {
  393. uint index = (uint)(addr - this->address) / sizeof(void*);
  394. if (!wbVerifyBits.Test(index)) // TODO: (leish)(swb) need interlocked? seems not
  395. {
  396. PrintVerifyMarkFailure(this->GetRecycler(), addr, *(char**)addr);
  397. }
  398. }
  399. virtual void WBSetBit(char* addr) override
  400. {
  401. uint index = (uint)(addr - this->address) / sizeof(void*);
  402. wbVerifyBits.TestAndSetInterlocked(index);
  403. }
  404. virtual void WBSetBitRange(char* addr, uint count) override
  405. {
  406. uint index = (uint)(addr - this->address) / sizeof(void*);
  407. for (uint i = 0; i < count; i++)
  408. {
  409. wbVerifyBits.TestAndSetInterlocked(index + i);
  410. }
  411. }
  412. virtual void WBClearBit(char* addr) override
  413. {
  414. uint index = (uint)(addr - this->address) / sizeof(void*);
  415. wbVerifyBits.TestAndClearInterlocked(index);
  416. }
  417. virtual void WBClearObject(char* addr) override
  418. {
  419. Assert((uint)(addr - this->address) % this->objectSize == 0);
  420. uint index = (uint)(addr - this->address) / sizeof(void*);
  421. uint count = (uint)(this->objectSize / sizeof(void*));
  422. for (uint i = 0; i < count; i++)
  423. {
  424. wbVerifyBits.TestAndClearInterlocked(index + i);
  425. }
  426. }
  427. #endif
  428. uint GetUnusablePageCount()
  429. {
  430. return 0;
  431. }
  432. #ifdef RECYCLER_WRITE_BARRIER
  433. bool IsWithBarrier() const;
  434. #endif
  435. void RemoveFromHeapBlockMap(Recycler* recycler);
  436. char* GetAddress() const { return address; }
  437. char * GetEndAddress() const { return address + (this->GetPageCount() * AutoSystemInfo::PageSize); }
  438. uint GetObjectWordCount() const { return this->objectSize / sizeof(void *); }
  439. uint GetPageCount() const;
  440. template<bool checkPageHeap=true>
  441. bool HasFreeObject() const
  442. {
  443. return freeObjectList != nullptr;
  444. }
  445. bool IsInAllocator() const;
  446. bool HasPendingDisposeObjects();
  447. bool HasAnyDisposeObjects();
  448. #if DBG
  449. void VerifyMarkBitVector();
  450. bool IsClearedFromAllocator() const;
  451. void SetIsClearedFromAllocator(bool value);
  452. void SetIsIntegratedBlock() { this->isIntegratedBlock = true; }
  453. #endif
  454. #ifdef RECYCLER_MEMORY_VERIFY
  455. void SetExplicitFreeBitForObject(void* object);
  456. void ClearExplicitFreeBitForObject(void* object);
  457. #endif
  458. #ifdef RECYCLER_STRESS
  459. void InduceFalsePositive(Recycler * recycler);
  460. #endif
  461. #ifdef DUMP_FRAGMENTATION_STATS
  462. void AggregateBlockStats(HeapBucketStats& stats, bool isAllocatorBlock = false, FreeObject* freeObjectList = nullptr, bool isBumpAllocated = false);
  463. #endif
  464. /*
  465. * Quick description of the bit vectors
  466. *
  467. * The free bit vector is created by EnsureFreeBitVector. It's created by walking through the free list
  468. * for the heap block and setting the corresponding bit indices in the bit vector.
  469. *
  470. * The mark bit vector is more complicated. In most cases, it represents the objects that are alive (marked)
  471. * + the objects the are free (i.e in the free list). This is so that when we sweep, we don't bother sweeping over objects
  472. * that are already in the free list, we sweep over objects that were allocated and no longer alive since the last GC.
  473. * However, during rescan, the mark bit vector represents the objects that are actually alive. We set the marked bit
  474. * vector to this state before calling RescanObjects, so that we scan through only the objects that are actually alive.
  475. * This means that we don't rescan newly allocated objects during rescan, because rescan doesn't change add new mark bits.
  476. * Instead, these objects are marked after rescan during in-thread mark if they're actually alive.
  477. */
  478. SmallHeapBlockBitVector * GetMarkedBitVector() { return markBits; }
  479. SmallHeapBlockBitVector * GetFreeBitVector() { return &freeBits; }
  480. SmallHeapBlockBitVector const * GetInvalidBitVector();
  481. BlockInfo const * GetBlockInfo();
  482. ushort GetObjectBitDelta();
  483. static uint GetObjectBitDeltaForBucketIndex(uint bucketIndex);
  484. static char* GetBlockStartAddress(char* address)
  485. {
  486. uintptr_t mask = ~((TBlockAttributes::PageCount * AutoSystemInfo::PageSize) - 1);
  487. return (char*)((uintptr_t)address & mask);
  488. }
  489. bool IsValidBitIndex(uint bitIndex)
  490. {
  491. Assert(bitIndex < TBlockAttributes::BitVectorCount);
  492. return bitIndex % GetObjectBitDelta() == 0;
  493. }
  494. void MarkImplicitRoots();
  495. void SetNextBlock(SmallHeapBlockT * next) { this->next=next; }
  496. SmallHeapBlockT * GetNextBlock() const { return next; }
  497. uint GetObjectSize() const { return objectSize; }
  498. uint GetObjectCount() const { return objectCount; }
  499. uint GetMarkedCount() const { return markCount; }
  500. // Valid during sweep time
  501. ushort GetExpectedFreeObjectCount() const;
  502. uint GetExpectedFreeBytes() const;
  503. ushort GetExpectedSweepObjectCount() const;
  504. #if DBG || defined(RECYCLER_STATS)
  505. SmallHeapBlockBitVector * GetDebugFreeBitVector() { return &debugFreeBits; }
  506. #endif
  507. #if DBG
  508. virtual BOOL IsFreeObject(void* objectAddress) override;
  509. #endif
  510. virtual BOOL IsValidObject(void* objectAddress) override;
  511. byte* GetRealAddressFromInterior(void* interiorAddress) override sealed;
  512. bool TestObjectMarkedBit(void* objectAddress) override sealed;
  513. void SetObjectMarkedBit(void* objectAddress) override;
  514. virtual size_t GetObjectSize(void* object) override { return objectSize; }
  515. uint GetMarkCountForSweep();
  516. SweepState Sweep(RecyclerSweep& recyclerSweep, bool queuePendingSweep, bool allocable, ushort finalizeCount = 0, bool hasPendingDispose = false);
  517. template <SweepMode mode>
  518. void SweepObjects(Recycler * recycler);
  519. uint GetAndClearLastFreeCount();
  520. void ClearAllAllocBytes(); // Reset all unaccounted alloc bytes and the new alloc count
  521. #if ENABLE_PARTIAL_GC
  522. uint GetAndClearUnaccountedAllocBytes();
  523. void AdjustPartialUncollectedAllocBytes(RecyclerSweep& recyclerSweep, uint const expectSweepCount);
  524. bool DoPartialReusePage(RecyclerSweep const& recyclerSweep, uint& expectFreeByteCount);
  525. #if DBG || defined(RECYCLER_STATS)
  526. void SweepVerifyPartialBlock(Recycler * recycler);
  527. #endif
  528. #endif
  529. void TransferProcessedObjects(FreeObject * list, FreeObject * tail);
  530. BOOL ReassignPages(Recycler * recycler);
  531. BOOL SetPage(__in_ecount_pagesize char * baseAddress, PageSegment * pageSegment, Recycler * recycler);
  532. void ReleasePages(Recycler * recycler);
  533. void ReleasePagesSweep(Recycler * recycler);
  534. void ReleasePagesShutdown(Recycler * recycler);
  535. #if ENABLE_BACKGROUND_PAGE_FREEING
  536. void BackgroundReleasePagesSweep(Recycler* recycler);
  537. #endif
  538. void Reset();
  539. void EnumerateObjects(ObjectInfoBits infoBits, void (*CallBackFunction)(void * address, size_t size));
  540. bool IsImplicitRoot(uint objectIndex)
  541. {
  542. return (this->ObjectInfo(objectIndex) & ImplicitRootBit) != 0;
  543. }
  544. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  545. void Check(bool expectFull, bool expectPending);
  546. #endif
  547. #ifdef RECYCLER_MEMORY_VERIFY
  548. void Verify(bool pendingDispose = false);
  549. void VerifyBumpAllocated(_In_ char * bumpAllocatedAddres);
  550. #endif
  551. #ifdef RECYCLER_VERIFY_MARK
  552. void VerifyMark();
  553. virtual bool VerifyMark(void * objectAddress, void * target) override;
  554. #endif
  555. #ifdef RECYCLER_PERF_COUNTERS
  556. virtual void UpdatePerfCountersOnFree() override sealed;
  557. #endif
  558. #ifdef PROFILE_RECYCLER_ALLOC
  559. virtual void * GetTrackerData(void * address) override;
  560. virtual void SetTrackerData(void * address, void * data) override;
  561. #endif
  562. static ushort GetAddressBitIndex(void * objectAddress);
  563. static void * GetRealAddressFromInterior(void * objectAddress, uint objectSize, byte bucketIndex);
  564. protected:
  565. static size_t GetAllocPlusSize(uint objectCount);
  566. inline void SetAttributes(void * address, unsigned char attributes);
  567. SmallHeapBlockT(HeapBucket * bucket, ushort objectSize, ushort objectCount, HeapBlockType heapBlockType);
  568. ushort GetAddressIndex(void * objectAddress);
  569. ushort GetInteriorAddressIndex(void * interiorAddress);
  570. ushort GetObjectIndexFromBitIndex(ushort bitIndex);
  571. template <SweepMode mode>
  572. void SweepObject(Recycler * recycler, uint index, void * addr);
  573. void EnqueueProcessedObject(FreeObject **list, void * objectAddress, uint index);
  574. void EnqueueProcessedObject(FreeObject **list, FreeObject ** tail, void * objectAddress, uint index);
  575. #ifdef RECYCLER_SLOW_CHECK_ENABLED
  576. template <typename TBlockType>
  577. bool GetFreeObjectListOnAllocatorImpl(FreeObject ** freeObjectList);
  578. virtual bool GetFreeObjectListOnAllocator(FreeObject ** freeObjectList) = 0;
  579. void CheckDebugFreeBitVector(bool isCollecting);
  580. void CheckFreeBitVector(bool isCollecting);
  581. #endif
  582. SmallHeapBlockBitVector * EnsureFreeBitVector();
  583. SmallHeapBlockBitVector * BuildFreeBitVector();
  584. ushort BuildFreeBitVector(SmallHeapBlockBitVector * bv);
  585. BOOL IsInFreeObjectList(void * objectAddress);
  586. void ClearObjectInfoList();
  587. byte& ObjectInfo(uint index);
  588. inline void FillFreeMemory(__in_bcount(size) void * address, size_t size);
  589. template <typename TBlockType>
  590. bool FindHeapObjectImpl(void* objectAddress, Recycler * recycler, FindHeapObjectFlags flags, RecyclerHeapObjectInfo& heapObject);
  591. protected:
  592. void Init(ushort objectSize, ushort objectCount);
  593. void ConstructorCommon(HeapBucket * bucket, ushort objectSize, ushort objectCount, HeapBlockType heapBlockType);
  594. template <typename Fn>
  595. void ForEachAllocatedObject(Fn fn);
  596. template <typename Fn>
  597. void ForEachAllocatedObject(ObjectInfoBits attributes, Fn fn);
  598. template <typename Fn>
  599. void ScanNewImplicitRootsBase(Fn fn);
  600. // This is public for code readability but this
  601. // returns a value only on debug builds. On retail builds
  602. // this returns null
  603. Recycler * GetRecycler() const;
  604. #if DBG
  605. uint GetMarkCountOnHeapBlockMap() const;
  606. #endif
  607. private:
  608. #ifdef PROFILE_RECYCLER_ALLOC
  609. void ** GetTrackerDataArray();
  610. #endif
  611. };
  612. // Forward declare specializations
  613. template<>
  614. SmallHeapBlockT<MediumAllocationBlockAttributes>::SmallHeapBlockT(HeapBucket * bucket, ushort objectSize, ushort objectCount, HeapBlockType heapBlockType);
  615. template <>
  616. uint
  617. SmallHeapBlockT<MediumAllocationBlockAttributes>::GetObjectBitDeltaForBucketIndex(uint bucketIndex);
  618. template <>
  619. uint
  620. SmallHeapBlockT<MediumAllocationBlockAttributes>::GetUnusablePageCount();
  621. template <>
  622. void
  623. SmallHeapBlockT<MediumAllocationBlockAttributes>::ProtectUnusablePages();
  624. template <>
  625. void
  626. SmallHeapBlockT<MediumAllocationBlockAttributes>::RestoreUnusablePages();
  627. // Declare the class templates
  628. typedef SmallHeapBlockT<SmallAllocationBlockAttributes> SmallHeapBlock;
  629. typedef SmallHeapBlockT<MediumAllocationBlockAttributes> MediumHeapBlock;
  630. extern template class SmallHeapBlockT<SmallAllocationBlockAttributes>;
  631. extern template class SmallHeapBlockT<MediumAllocationBlockAttributes>;
  632. extern template class ValidPointers<SmallAllocationBlockAttributes>;
  633. extern template class ValidPointers<MediumAllocationBlockAttributes>;
  634. class HeapBlockList
  635. {
  636. public:
  637. template <typename TBlockType, typename Fn>
  638. static void ForEach(TBlockType * list, Fn fn)
  639. {
  640. ForEach<TBlockType, Fn>(list, nullptr, fn);
  641. }
  642. template <typename TBlockType, typename Fn>
  643. static void ForEach(TBlockType * list, TBlockType * tail, Fn fn)
  644. {
  645. TBlockType * heapBlock = list;
  646. while (heapBlock != tail)
  647. {
  648. fn(heapBlock);
  649. heapBlock = heapBlock->GetNextBlock();
  650. }
  651. }
  652. template <typename TBlockType, typename Fn>
  653. static void ForEachEditing(TBlockType * list, Fn fn)
  654. {
  655. ForEachEditing<TBlockType, Fn>(list, nullptr, fn);
  656. };
  657. template <typename TBlockType, typename Fn>
  658. static void ForEachEditing(TBlockType * list, TBlockType * tail, Fn fn)
  659. {
  660. TBlockType * heapBlock = list;
  661. while (heapBlock != tail)
  662. {
  663. TBlockType * nextBlock = heapBlock->GetNextBlock();
  664. fn(heapBlock);
  665. heapBlock = nextBlock;
  666. }
  667. };
  668. template <typename TBlockType>
  669. static size_t Count(TBlockType * list)
  670. {
  671. size_t currentHeapBlockCount = 0;
  672. HeapBlockList::ForEach(list, [&currentHeapBlockCount](TBlockType * heapBlock)
  673. {
  674. currentHeapBlockCount++;
  675. });
  676. return currentHeapBlockCount;
  677. };
  678. template <typename TBlockType>
  679. static TBlockType * Tail(TBlockType * list)
  680. {
  681. TBlockType * tail = nullptr;
  682. HeapBlockList::ForEach(list, [&tail](TBlockType * heapBlock)
  683. {
  684. tail = heapBlock;
  685. });
  686. return tail;
  687. }
  688. #if DBG
  689. template <typename TBlockType>
  690. static bool Contains(TBlockType * block, TBlockType * list, TBlockType * tail = nullptr)
  691. {
  692. TBlockType * heapBlock = list;
  693. while (heapBlock != tail)
  694. {
  695. if (heapBlock == block)
  696. {
  697. return true;
  698. }
  699. heapBlock = heapBlock->GetNextBlock();
  700. }
  701. return false;
  702. }
  703. #endif
  704. };
  705. }