RecyclerPageAllocator.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. RecyclerPageAllocator::RecyclerPageAllocator(HeapInfo * heapInfo, AllocationPolicyManager * policyManager,
  7. Js::ConfigFlagsTable& flagTable, uint maxFreePageCount, uint maxAllocPageCount, bool enableWriteBarrier)
  8. : IdleDecommitPageAllocator(policyManager,
  9. PageAllocatorType_Recycler,
  10. flagTable,
  11. 0, maxFreePageCount,
  12. true,
  13. #if ENABLE_BACKGROUND_PAGE_ZEROING
  14. &zeroPageQueue,
  15. #endif
  16. maxAllocPageCount,
  17. enableWriteBarrier
  18. )
  19. {
  20. this->heapInfo = heapInfo;
  21. }
  22. bool RecyclerPageAllocator::IsMemProtectMode()
  23. {
  24. return heapInfo->GetRecycler()->IsMemProtectMode();
  25. }
  26. #if ENABLE_CONCURRENT_GC
  27. #ifdef RECYCLER_WRITE_WATCH
  28. void
  29. RecyclerPageAllocator::EnableWriteWatch()
  30. {
  31. Assert(segments.Empty());
  32. Assert(fullSegments.Empty());
  33. Assert(emptySegments.Empty());
  34. Assert(decommitSegments.Empty());
  35. Assert(largeSegments.Empty());
  36. allocFlags = MEM_WRITE_WATCH;
  37. }
  38. bool
  39. RecyclerPageAllocator::ResetWriteWatch()
  40. {
  41. if (!IsWriteWatchEnabled())
  42. {
  43. return false;
  44. }
  45. GCETW(GC_RESETWRITEWATCH_START, (this));
  46. SuspendIdleDecommit();
  47. bool success = true;
  48. // Only reset write watch on allocated pages
  49. if (!ResetWriteWatch(&segments) ||
  50. !ResetWriteWatch(&decommitSegments) ||
  51. !ResetAllWriteWatch(&fullSegments) ||
  52. !ResetAllWriteWatch(&largeSegments))
  53. {
  54. allocFlags = 0;
  55. success = false;
  56. }
  57. ResumeIdleDecommit();
  58. GCETW(GC_RESETWRITEWATCH_STOP, (this));
  59. return success;
  60. }
  61. bool
  62. RecyclerPageAllocator::ResetWriteWatch(DListBase<PageSegment> * segmentList)
  63. {
  64. DListBase<PageSegment>::Iterator i(segmentList);
  65. while (i.Next())
  66. {
  67. PageSegment& segment = i.Data();
  68. size_t pageCount = segment.GetAvailablePageCount();
  69. Assert(pageCount <= MAXUINT32);
  70. PageSegment::PageBitVector unallocPages = segment.GetUnAllocatedPages();
  71. for (uint index = 0u; index < pageCount; index++)
  72. {
  73. if (unallocPages.Test(index))
  74. {
  75. continue;
  76. }
  77. char * address = segment.GetAddress() + index * AutoSystemInfo::PageSize;
  78. if (::ResetWriteWatch(address, AutoSystemInfo::PageSize) != 0)
  79. {
  80. #if DBG_DUMP
  81. Output::Print(_u("ResetWriteWatch failed for %p\n"), address);
  82. Output::Flush();
  83. #endif
  84. // shouldn't happen
  85. Assert(false);
  86. return false;
  87. }
  88. }
  89. }
  90. return true;
  91. }
  92. template <typename T>
  93. bool
  94. RecyclerPageAllocator::ResetAllWriteWatch(DListBase<T> * segmentList)
  95. {
  96. typename DListBase<T>::Iterator i(segmentList);
  97. while (i.Next())
  98. {
  99. T& segment = i.Data();
  100. if (::ResetWriteWatch(segment.GetAddress(), segment.GetPageCount() * AutoSystemInfo::PageSize ) != 0)
  101. {
  102. #if DBG_DUMP
  103. Output::Print(_u("ResetWriteWatch failed for %p\n"), segment.GetAddress());
  104. Output::Flush();
  105. #endif
  106. // shouldn't happen
  107. Assert(false);
  108. return false;
  109. }
  110. }
  111. return true;
  112. }
  113. #endif
  114. #ifdef RECYCLER_WRITE_WATCH
  115. #if DBG
  116. size_t
  117. RecyclerPageAllocator::GetWriteWatchPageCount()
  118. {
  119. if (allocFlags != MEM_WRITE_WATCH)
  120. {
  121. return 0;
  122. }
  123. SuspendIdleDecommit();
  124. // Only reset write watch on allocated pages
  125. size_t count = GetWriteWatchPageCount(&segments)
  126. + GetWriteWatchPageCount(&decommitSegments)
  127. + GetAllWriteWatchPageCount(&fullSegments)
  128. + GetAllWriteWatchPageCount(&largeSegments);
  129. ResumeIdleDecommit();
  130. return count;
  131. }
  132. size_t
  133. RecyclerPageAllocator::GetWriteWatchPageCount(DListBase<PageSegment> * segmentList)
  134. {
  135. size_t totalCount = 0;
  136. DListBase<PageSegment>::Iterator i(segmentList);
  137. while (i.Next())
  138. {
  139. PageSegment& segment = i.Data();
  140. size_t pageCount = segment.GetAvailablePageCount();
  141. Assert(pageCount <= MAXUINT32);
  142. PageSegment::PageBitVector unallocPages = segment.GetUnAllocatedPages();
  143. for (uint index = 0u; index < pageCount; index++)
  144. {
  145. if (unallocPages.Test(index))
  146. {
  147. continue;
  148. }
  149. char * address = segment.GetAddress() + index * AutoSystemInfo::PageSize;
  150. void * written;
  151. ULONG_PTR count = 0;
  152. DWORD pageSize = AutoSystemInfo::PageSize;
  153. if (::GetWriteWatch(0, address, AutoSystemInfo::PageSize, &written, &count, &pageSize) == 0)
  154. {
  155. #if DBG_DUMP
  156. Output::Print(_u("GetWriteWatch failed for %p\n"), segment.GetAddress());
  157. Output::Flush();
  158. #endif
  159. // shouldn't happen
  160. Assert(false);
  161. }
  162. else
  163. {
  164. Assert(count <= 1);
  165. Assert(pageSize == AutoSystemInfo::PageSize);
  166. Assert(count == 0 || written == address);
  167. totalCount += count;
  168. }
  169. }
  170. }
  171. return totalCount;
  172. }
  173. template <typename T>
  174. size_t
  175. RecyclerPageAllocator::GetAllWriteWatchPageCount(DListBase<T> * segmentList)
  176. {
  177. size_t totalCount = 0;
  178. _TYPENAME DListBase<T>::Iterator it(segmentList);
  179. while (it.Next())
  180. {
  181. T& segment = it.Data();
  182. for (uint i = 0; i < segment.GetPageCount(); i++)
  183. {
  184. void * address = segment.GetAddress() + i * AutoSystemInfo::PageSize;
  185. void * written;
  186. ULONG_PTR count = 0;
  187. DWORD pageSize = AutoSystemInfo::PageSize;
  188. if (::GetWriteWatch(0, address, AutoSystemInfo::PageSize, &written, &count, &pageSize) == 0)
  189. {
  190. #if DBG_DUMP
  191. Output::Print(_u("GetWriteWatch failed for %p\n"), segment.GetAddress());
  192. Output::Flush();
  193. #endif
  194. // shouldn't happen
  195. Assert(false);
  196. }
  197. else
  198. {
  199. Assert(count <= 1);
  200. Assert(pageSize == AutoSystemInfo::PageSize);
  201. Assert(count == 0 || written == address);
  202. totalCount += count;
  203. }
  204. }
  205. }
  206. return totalCount;
  207. }
  208. #endif
  209. #endif
  210. #endif