PagePool.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. // PagePool caches freed pages in a pool for reuse, and more importantly,
  6. // defers freeing them until ReleaseFreePages is called.
  7. // This allows us to free the pages when we know it is multi-thread safe to do so,
  8. // e.g. after all parallel marking is completed.
  9. namespace Memory
  10. {
  11. class PagePoolPage
  12. {
  13. private:
  14. PageAllocator * pageAllocator;
  15. PageSegment * pageSegment;
  16. bool isReserved;
  17. public:
  18. static PagePoolPage * New(PageAllocator * pageAllocator, bool isReserved = false)
  19. {
  20. PageSegment * pageSegment;
  21. PagePoolPage * newPage = (PagePoolPage *)pageAllocator->AllocPages(1, &pageSegment);
  22. if (newPage == nullptr)
  23. {
  24. return nullptr;
  25. }
  26. newPage->pageAllocator = pageAllocator;
  27. newPage->pageSegment = pageSegment;
  28. newPage->isReserved = isReserved;
  29. return newPage;
  30. }
  31. void Free()
  32. {
  33. this->pageAllocator->ReleasePages(this, 1, this->pageSegment);
  34. }
  35. bool IsReserved()
  36. {
  37. return isReserved;
  38. }
  39. };
  40. class PagePool
  41. {
  42. private:
  43. class PagePoolFreePage : public PagePoolPage
  44. {
  45. public:
  46. PagePoolFreePage * nextFreePage;
  47. };
  48. PageAllocator pageAllocator;
  49. PagePoolFreePage * freePageList;
  50. // List of pre-allocated pages that are
  51. // freed only when the page pool is destroyed
  52. PagePoolFreePage * reservedPageList;
  53. public:
  54. PagePool(Js::ConfigFlagsTable& flagsTable) :
  55. pageAllocator(NULL, flagsTable, PageAllocatorType_GCThread,
  56. PageAllocator::DefaultMaxFreePageCount, false,
  57. #if ENABLE_BACKGROUND_PAGE_ZEROING
  58. nullptr,
  59. #endif
  60. PageAllocator::DefaultMaxAllocPageCount, 0, true),
  61. freePageList(nullptr),
  62. reservedPageList(nullptr)
  63. {
  64. }
  65. void ReservePages(uint reservedPageCount)
  66. {
  67. for (uint i = 0; i < reservedPageCount; i++)
  68. {
  69. PagePoolPage* page = PagePoolPage::New(&pageAllocator, true);
  70. if (page == nullptr)
  71. {
  72. Js::Throw::OutOfMemory();
  73. }
  74. FreeReservedPage(page);
  75. }
  76. }
  77. ~PagePool()
  78. {
  79. Assert(freePageList == nullptr);
  80. if (reservedPageList != nullptr)
  81. {
  82. while (reservedPageList != nullptr)
  83. {
  84. PagePoolFreePage * page = reservedPageList;
  85. Assert(page->IsReserved());
  86. reservedPageList = reservedPageList->nextFreePage;
  87. page->Free();
  88. }
  89. }
  90. }
  91. PageAllocator * GetPageAllocator() { return &this->pageAllocator; }
  92. PagePoolPage * GetPage(bool useReservedPages = false)
  93. {
  94. if (freePageList != nullptr)
  95. {
  96. PagePoolPage * page = freePageList;
  97. freePageList = freePageList->nextFreePage;
  98. Assert(!page->IsReserved());
  99. return page;
  100. }
  101. if (useReservedPages && reservedPageList != nullptr)
  102. {
  103. PagePoolPage * page = reservedPageList;
  104. reservedPageList = reservedPageList->nextFreePage;
  105. Assert(page->IsReserved());
  106. return page;
  107. }
  108. return PagePoolPage::New(&pageAllocator);
  109. }
  110. void FreePage(PagePoolPage * page)
  111. {
  112. PagePoolFreePage * freePage = (PagePoolFreePage *)page;
  113. if (freePage->IsReserved())
  114. {
  115. return FreeReservedPage(page);
  116. }
  117. freePage->nextFreePage = freePageList;
  118. freePageList = freePage;
  119. }
  120. void ReleaseFreePages()
  121. {
  122. while (freePageList != nullptr)
  123. {
  124. PagePoolFreePage * page = freePageList;
  125. Assert(!page->IsReserved());
  126. freePageList = freePageList->nextFreePage;
  127. page->Free();
  128. }
  129. }
  130. void Decommit()
  131. {
  132. pageAllocator.DecommitNow();
  133. }
  134. #if DBG
  135. bool IsEmpty() const { return (freePageList == nullptr); }
  136. #endif
  137. private:
  138. void FreeReservedPage(PagePoolPage * page)
  139. {
  140. Assert(page->IsReserved());
  141. PagePoolFreePage * freePage = (PagePoolFreePage *)page;
  142. freePage->nextFreePage = reservedPageList;
  143. reservedPageList = freePage;
  144. }
  145. };
  146. }