CodeGenNumberAllocator.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  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 "Backend.h"
  6. #if !FLOATVAR
  7. CodeGenNumberThreadAllocator::CodeGenNumberThreadAllocator(Recycler * recycler)
  8. : recycler(recycler), currentNumberSegment(nullptr), currentChunkSegment(nullptr),
  9. numberSegmentEnd(nullptr), currentNumberBlockEnd(nullptr), nextNumber(nullptr), chunkSegmentEnd(nullptr),
  10. currentChunkBlockEnd(nullptr), nextChunk(nullptr), hasNewNumberBlock(nullptr), hasNewChunkBlock(nullptr),
  11. pendingIntegrationNumberSegmentCount(0), pendingIntegrationChunkSegmentCount(0),
  12. pendingIntegrationNumberSegmentPageCount(0), pendingIntegrationChunkSegmentPageCount(0)
  13. {
  14. }
  15. CodeGenNumberThreadAllocator::~CodeGenNumberThreadAllocator()
  16. {
  17. pendingIntegrationNumberSegment.Clear(&NoThrowNoMemProtectHeapAllocator::Instance);
  18. pendingIntegrationChunkSegment.Clear(&NoThrowNoMemProtectHeapAllocator::Instance);
  19. pendingIntegrationNumberBlock.Clear(&NoThrowHeapAllocator::Instance);
  20. pendingIntegrationChunkBlock.Clear(&NoThrowHeapAllocator::Instance);
  21. pendingFlushNumberBlock.Clear(&NoThrowHeapAllocator::Instance);
  22. pendingFlushChunkBlock.Clear(&NoThrowHeapAllocator::Instance);
  23. pendingReferenceNumberBlock.Clear(&NoThrowHeapAllocator::Instance);
  24. }
  25. size_t
  26. CodeGenNumberThreadAllocator::GetNumberAllocSize()
  27. {
  28. #ifdef RECYCLER_MEMORY_VERIFY
  29. if (recycler->VerifyEnabled())
  30. {
  31. return HeapInfo::GetAlignedSize(AllocSizeMath::Add(sizeof(Js::JavascriptNumber) + sizeof(size_t), recycler->verifyPad));
  32. }
  33. #endif
  34. return HeapInfo::GetAlignedSizeNoCheck(sizeof(Js::JavascriptNumber));
  35. }
  36. size_t
  37. CodeGenNumberThreadAllocator::GetChunkAllocSize()
  38. {
  39. #ifdef RECYCLER_MEMORY_VERIFY
  40. if (recycler->VerifyEnabled())
  41. {
  42. return HeapInfo::GetAlignedSize(AllocSizeMath::Add(sizeof(CodeGenNumberChunk) + sizeof(size_t), recycler->verifyPad));
  43. }
  44. #endif
  45. return HeapInfo::GetAlignedSizeNoCheck(sizeof(CodeGenNumberChunk));
  46. }
  47. Js::JavascriptNumber *
  48. CodeGenNumberThreadAllocator::AllocNumber()
  49. {
  50. AutoCriticalSection autocs(&cs);
  51. size_t sizeCat = GetNumberAllocSize();
  52. if (nextNumber + sizeCat > currentNumberBlockEnd)
  53. {
  54. AllocNewNumberBlock();
  55. }
  56. Js::JavascriptNumber * newNumber = (Js::JavascriptNumber *)nextNumber;
  57. #ifdef RECYCLER_MEMORY_VERIFY
  58. recycler->FillCheckPad(newNumber, sizeof(Js::JavascriptNumber), sizeCat);
  59. #endif
  60. nextNumber += sizeCat;
  61. return newNumber;
  62. }
  63. CodeGenNumberChunk *
  64. CodeGenNumberThreadAllocator::AllocChunk()
  65. {
  66. AutoCriticalSection autocs(&cs);
  67. size_t sizeCat = GetChunkAllocSize();
  68. if (nextChunk + sizeCat > currentChunkBlockEnd)
  69. {
  70. AllocNewChunkBlock();
  71. }
  72. CodeGenNumberChunk * newChunk = (CodeGenNumberChunk *)nextChunk;
  73. #ifdef RECYCLER_MEMORY_VERIFY
  74. recycler->FillCheckPad(nextChunk, sizeof(CodeGenNumberChunk), sizeCat);
  75. #endif
  76. memset(newChunk, 0, sizeof(CodeGenNumberChunk));
  77. nextChunk += sizeCat;
  78. return newChunk;
  79. }
  80. void
  81. CodeGenNumberThreadAllocator::AllocNewNumberBlock()
  82. {
  83. Assert(cs.IsLocked());
  84. Assert(nextNumber + GetNumberAllocSize() > currentNumberBlockEnd);
  85. if (hasNewNumberBlock)
  86. {
  87. if (!pendingReferenceNumberBlock.PrependNode(&NoThrowHeapAllocator::Instance,
  88. currentNumberBlockEnd - BlockSize, currentNumberSegment))
  89. {
  90. Js::Throw::OutOfMemory();
  91. }
  92. hasNewNumberBlock = false;
  93. }
  94. if (currentNumberBlockEnd == numberSegmentEnd)
  95. {
  96. Assert(cs.IsLocked());
  97. // Reserve the segment, but not committing it
  98. currentNumberSegment = PageAllocator::AllocPageSegment(pendingIntegrationNumberSegment, this->recycler->GetDefaultHeapInfo()->GetRecyclerLeafPageAllocator(), false, true, false);
  99. if (currentNumberSegment == nullptr)
  100. {
  101. currentNumberBlockEnd = nullptr;
  102. numberSegmentEnd = nullptr;
  103. nextNumber = nullptr;
  104. Js::Throw::OutOfMemory();
  105. }
  106. pendingIntegrationNumberSegmentCount++;
  107. pendingIntegrationNumberSegmentPageCount += currentNumberSegment->GetPageCount();
  108. currentNumberBlockEnd = currentNumberSegment->GetAddress();
  109. numberSegmentEnd = currentNumberSegment->GetEndAddress();
  110. }
  111. // Commit the page.
  112. if (!::VirtualAlloc(currentNumberBlockEnd, BlockSize, MEM_COMMIT, PAGE_READWRITE))
  113. {
  114. Js::Throw::OutOfMemory();
  115. }
  116. nextNumber = currentNumberBlockEnd;
  117. currentNumberBlockEnd += BlockSize;
  118. hasNewNumberBlock = true;
  119. this->recycler->GetDefaultHeapInfo()->GetRecyclerLeafPageAllocator()->FillAllocPages(nextNumber, 1);
  120. }
  121. void
  122. CodeGenNumberThreadAllocator::AllocNewChunkBlock()
  123. {
  124. Assert(cs.IsLocked());
  125. Assert(nextChunk + GetChunkAllocSize() > currentChunkBlockEnd);
  126. if (hasNewChunkBlock)
  127. {
  128. if (!pendingFlushChunkBlock.PrependNode(&NoThrowHeapAllocator::Instance,
  129. currentChunkBlockEnd - BlockSize, currentChunkSegment))
  130. {
  131. Js::Throw::OutOfMemory();
  132. }
  133. // All integrated pages' object are all live initially, so don't need to rescan them
  134. // todo: SWB: need to allocate number with write barrier pages
  135. ::ResetWriteWatch(currentChunkBlockEnd - BlockSize, BlockSize);
  136. pendingReferenceNumberBlock.MoveTo(&pendingFlushNumberBlock);
  137. hasNewChunkBlock = false;
  138. }
  139. if (currentChunkBlockEnd == chunkSegmentEnd)
  140. {
  141. Assert(cs.IsLocked());
  142. // Reserve the segment, but not committing it
  143. currentChunkSegment = PageAllocator::AllocPageSegment(pendingIntegrationChunkSegment, this->recycler->GetDefaultHeapInfo()->GetRecyclerPageAllocator(), false, true, false);
  144. if (currentChunkSegment == nullptr)
  145. {
  146. currentChunkBlockEnd = nullptr;
  147. chunkSegmentEnd = nullptr;
  148. nextChunk = nullptr;
  149. Js::Throw::OutOfMemory();
  150. }
  151. pendingIntegrationChunkSegmentCount++;
  152. pendingIntegrationChunkSegmentPageCount += currentChunkSegment->GetPageCount();
  153. currentChunkBlockEnd = currentChunkSegment->GetAddress();
  154. chunkSegmentEnd = currentChunkSegment->GetEndAddress();
  155. }
  156. // Commit the page.
  157. if (!::VirtualAlloc(currentChunkBlockEnd, BlockSize, MEM_COMMIT, PAGE_READWRITE))
  158. {
  159. Js::Throw::OutOfMemory();
  160. }
  161. nextChunk = currentChunkBlockEnd;
  162. currentChunkBlockEnd += BlockSize;
  163. hasNewChunkBlock = true;
  164. this->recycler->GetDefaultHeapInfo()->GetRecyclerLeafPageAllocator()->FillAllocPages(nextChunk, 1);
  165. }
  166. void
  167. CodeGenNumberThreadAllocator::Integrate()
  168. {
  169. AutoCriticalSection autocs(&cs);
  170. PageAllocator * leafPageAllocator = this->recycler->GetDefaultHeapInfo()->GetRecyclerLeafPageAllocator();
  171. leafPageAllocator->IntegrateSegments(pendingIntegrationNumberSegment, pendingIntegrationNumberSegmentCount, pendingIntegrationNumberSegmentPageCount);
  172. PageAllocator * recyclerPageAllocator = this->recycler->GetDefaultHeapInfo()->GetRecyclerPageAllocator();
  173. recyclerPageAllocator->IntegrateSegments(pendingIntegrationChunkSegment, pendingIntegrationChunkSegmentCount, pendingIntegrationChunkSegmentPageCount);
  174. pendingIntegrationNumberSegmentCount = 0;
  175. pendingIntegrationChunkSegmentCount = 0;
  176. pendingIntegrationNumberSegmentPageCount = 0;
  177. pendingIntegrationChunkSegmentPageCount = 0;
  178. #ifdef TRACK_ALLOC
  179. TrackAllocData oldAllocData = recycler->nextAllocData;
  180. recycler->nextAllocData.Clear();
  181. #endif
  182. while (!pendingIntegrationNumberBlock.Empty())
  183. {
  184. TRACK_ALLOC_INFO(recycler, Js::JavascriptNumber, Recycler, 0, (size_t)-1);
  185. BlockRecord& record = pendingIntegrationNumberBlock.Head();
  186. if (!recycler->IntegrateBlock<LeafBit>(record.blockAddress, record.segment, GetNumberAllocSize(), sizeof(Js::JavascriptNumber)))
  187. {
  188. Js::Throw::OutOfMemory();
  189. }
  190. pendingIntegrationNumberBlock.RemoveHead(&NoThrowHeapAllocator::Instance);
  191. }
  192. while (!pendingIntegrationChunkBlock.Empty())
  193. {
  194. // REVIEW: the above number block integration can be moved into this loop
  195. TRACK_ALLOC_INFO(recycler, CodeGenNumberChunk, Recycler, 0, (size_t)-1);
  196. BlockRecord& record = pendingIntegrationChunkBlock.Head();
  197. if (!recycler->IntegrateBlock<NoBit>(record.blockAddress, record.segment, GetChunkAllocSize(), sizeof(CodeGenNumberChunk)))
  198. {
  199. Js::Throw::OutOfMemory();
  200. }
  201. #if DBG && GLOBAL_ENABLE_WRITE_BARRIER
  202. if (CONFIG_FLAG(ForceSoftwareWriteBarrier) && CONFIG_FLAG(RecyclerVerifyMark))
  203. {
  204. Recycler::WBSetBitRange(record.blockAddress, BlockSize / sizeof(void*));
  205. }
  206. #endif
  207. pendingIntegrationChunkBlock.RemoveHead(&NoThrowHeapAllocator::Instance);
  208. }
  209. #ifdef TRACK_ALLOC
  210. Assert(recycler->nextAllocData.IsEmpty());
  211. recycler->nextAllocData = oldAllocData;
  212. #endif
  213. }
  214. void
  215. CodeGenNumberThreadAllocator::FlushAllocations()
  216. {
  217. AutoCriticalSection autocs(&cs);
  218. pendingFlushNumberBlock.MoveTo(&pendingIntegrationNumberBlock);
  219. pendingFlushChunkBlock.MoveTo(&pendingIntegrationChunkBlock);
  220. }
  221. CodeGenNumberAllocator::CodeGenNumberAllocator(CodeGenNumberThreadAllocator * threadAlloc, Recycler * recycler) :
  222. threadAlloc(threadAlloc), recycler(recycler), chunk(nullptr), chunkTail(nullptr), currentChunkNumberCount(CodeGenNumberChunk::MaxNumberCount)
  223. {
  224. #if DBG
  225. finalized = false;
  226. #endif
  227. }
  228. // We should never call this function if we are using tagged float
  229. Js::JavascriptNumber *
  230. CodeGenNumberAllocator::Alloc()
  231. {
  232. Assert(!finalized);
  233. if (currentChunkNumberCount == CodeGenNumberChunk::MaxNumberCount)
  234. {
  235. CodeGenNumberChunk * newChunk = threadAlloc? threadAlloc->AllocChunk()
  236. : RecyclerNewStructZ(recycler, CodeGenNumberChunk);
  237. // Need to always put the new chunk last, as when we flush
  238. // pages, new chunk's page might not be full yet, and won't
  239. // be flushed, and we will have a broken link in the link list.
  240. newChunk->next = nullptr;
  241. if (this->chunkTail != nullptr)
  242. {
  243. this->chunkTail->next = newChunk;
  244. }
  245. else
  246. {
  247. this->chunk = newChunk;
  248. }
  249. this->chunkTail = newChunk;
  250. this->currentChunkNumberCount = 0;
  251. }
  252. Js::JavascriptNumber * newNumber = threadAlloc? threadAlloc->AllocNumber()
  253. : Js::JavascriptNumber::NewUninitialized(recycler);
  254. this->chunkTail->numbers[this->currentChunkNumberCount++] = newNumber;
  255. return newNumber;
  256. }
  257. CodeGenNumberChunk *
  258. CodeGenNumberAllocator::Finalize()
  259. {
  260. Assert(!finalized);
  261. #if DBG
  262. finalized = true;
  263. #endif
  264. CodeGenNumberChunk * finalizedChunk = this->chunk;
  265. this->chunk = nullptr;
  266. this->chunkTail = nullptr;
  267. this->currentChunkNumberCount = 0;
  268. return finalizedChunk;
  269. }
  270. uint XProcNumberPageSegmentImpl::sizeCat = sizeof(Js::JavascriptNumber);
  271. Js::JavascriptNumber* XProcNumberPageSegmentImpl::AllocateNumber(Func* func, double value)
  272. {
  273. HANDLE hProcess = func->GetThreadContextInfo()->GetProcessHandle();
  274. XProcNumberPageSegmentImpl* tail = this;
  275. if (this->pageAddress != 0)
  276. {
  277. while (tail->nextSegment)
  278. {
  279. tail = (XProcNumberPageSegmentImpl*)tail->nextSegment;
  280. }
  281. if (tail->pageAddress + tail->committedEnd - tail->allocEndAddress >= sizeCat)
  282. {
  283. auto number = tail->allocEndAddress;
  284. tail->allocEndAddress += sizeCat;
  285. #if DBG
  286. Js::JavascriptNumber localNumber(value, (Js::StaticType*)func->GetScriptContextInfo()->GetNumberTypeStaticAddr(), true);
  287. #else
  288. Js::JavascriptNumber localNumber(value, (Js::StaticType*)func->GetScriptContextInfo()->GetNumberTypeStaticAddr());
  289. #endif
  290. Js::JavascriptNumber* pLocalNumber = &localNumber;
  291. #ifdef RECYCLER_MEMORY_VERIFY
  292. if (func->GetScriptContextInfo()->IsRecyclerVerifyEnabled())
  293. {
  294. pLocalNumber = (Js::JavascriptNumber*)alloca(sizeCat);
  295. memset(pLocalNumber, Recycler::VerifyMemFill, sizeCat);
  296. Recycler::FillPadNoCheck(pLocalNumber, sizeof(Js::JavascriptNumber), sizeCat, false);
  297. pLocalNumber = new (pLocalNumber) Js::JavascriptNumber(localNumber);
  298. }
  299. #else
  300. Assert(sizeCat == sizeof(Js::JavascriptNumber));
  301. __analysis_assume(sizeCat == sizeof(Js::JavascriptNumber));
  302. #endif
  303. // change vtable to the remote one
  304. *(void**)pLocalNumber = (void*)func->GetScriptContextInfo()->GetVTableAddress(VTableValue::VtableJavascriptNumber);
  305. // initialize number by WriteProcessMemory
  306. if (!WriteProcessMemory(hProcess, (void*)number, pLocalNumber, sizeCat, NULL))
  307. {
  308. MemoryOperationLastError::RecordLastError();
  309. Js::Throw::OutOfMemory();
  310. }
  311. return (Js::JavascriptNumber*) number;
  312. }
  313. // alloc blocks
  314. if (tail->GetCommitEndAddress() < tail->GetEndAddress())
  315. {
  316. Assert((unsigned int)((char*)tail->GetEndAddress() - (char*)tail->GetCommitEndAddress()) >= BlockSize);
  317. // TODO: implement guard pages (still necessary for OOP JIT?)
  318. LPVOID addr = ::VirtualAllocEx(hProcess, tail->GetCommitEndAddress(), BlockSize, MEM_COMMIT, PAGE_READWRITE);
  319. if (addr == nullptr)
  320. {
  321. MemoryOperationLastError::RecordLastError();
  322. Js::Throw::OutOfMemory();
  323. }
  324. tail->committedEnd += BlockSize;
  325. return AllocateNumber(func, value);
  326. }
  327. }
  328. // alloc new segment
  329. void* pages = ::VirtualAllocEx(hProcess, nullptr, PageCount * AutoSystemInfo::PageSize, MEM_RESERVE, PAGE_READWRITE);
  330. if (pages == nullptr)
  331. {
  332. MemoryOperationLastError::RecordLastError();
  333. Js::Throw::OutOfMemory();
  334. }
  335. if (tail->pageAddress == 0)
  336. {
  337. tail->pageAddress = (intptr_t)pages;
  338. tail->allocStartAddress = this->pageAddress;
  339. tail->allocEndAddress = this->pageAddress;
  340. tail->nextSegment = nullptr;
  341. return AllocateNumber(func, value);
  342. }
  343. else
  344. {
  345. XProcNumberPageSegmentImpl* seg = (XProcNumberPageSegmentImpl*)midl_user_allocate(sizeof(XProcNumberPageSegment));
  346. if (seg == nullptr)
  347. {
  348. Js::Throw::OutOfMemory();
  349. }
  350. seg = new (seg) XProcNumberPageSegmentImpl();
  351. tail->nextSegment = seg;
  352. return seg->AllocateNumber(func, value);
  353. }
  354. }
  355. XProcNumberPageSegmentImpl::XProcNumberPageSegmentImpl()
  356. {
  357. memset(this, 0, sizeof(XProcNumberPageSegment));
  358. }
  359. void XProcNumberPageSegmentImpl::Initialize(bool recyclerVerifyEnabled, uint recyclerVerifyPad)
  360. {
  361. uint allocSize = (uint)sizeof(Js::JavascriptNumber);
  362. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  363. allocSize += Js::Configuration::Global.flags.NumberAllocPlusSize;
  364. #endif
  365. #ifdef RECYCLER_MEMORY_VERIFY
  366. // TODO: share same pad size with main process
  367. if (recyclerVerifyEnabled)
  368. {
  369. uint padAllocSize = (uint)AllocSizeMath::Add(sizeof(Js::JavascriptNumber) + sizeof(size_t), recyclerVerifyPad);
  370. allocSize = padAllocSize < allocSize ? allocSize : padAllocSize;
  371. }
  372. #endif
  373. allocSize = (uint)HeapInfo::GetAlignedSizeNoCheck(allocSize);
  374. if (BlockSize%allocSize != 0)
  375. {
  376. // align allocation sizeCat to be 2^n to make integration easier
  377. allocSize = BlockSize / (1 << (Math::Log2((size_t)BlockSize / allocSize)));
  378. }
  379. sizeCat = allocSize;
  380. }
  381. Field(Js::JavascriptNumber*)* ::XProcNumberPageSegmentManager::RegisterSegments(XProcNumberPageSegment* segments)
  382. {
  383. Assert(segments->pageAddress && segments->allocStartAddress && segments->allocEndAddress);
  384. XProcNumberPageSegmentImpl* segmentImpl = (XProcNumberPageSegmentImpl*)segments;
  385. XProcNumberPageSegmentImpl* temp = segmentImpl;
  386. size_t totalCount = 0;
  387. while (temp)
  388. {
  389. totalCount += (temp->allocEndAddress - temp->allocStartAddress) / XProcNumberPageSegmentImpl::sizeCat;
  390. temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
  391. }
  392. Field(Js::JavascriptNumber*)* numbers = RecyclerNewArray(this->recycler, Field(Js::JavascriptNumber*), totalCount);
  393. temp = segmentImpl;
  394. int count = 0;
  395. while (temp)
  396. {
  397. while (temp->allocStartAddress < temp->allocEndAddress)
  398. {
  399. numbers[count] = (Js::JavascriptNumber*)temp->allocStartAddress;
  400. count++;
  401. temp->allocStartAddress += XProcNumberPageSegmentImpl::sizeCat;
  402. }
  403. temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
  404. }
  405. AutoCriticalSection autoCS(&cs);
  406. if (this->segmentsList == nullptr)
  407. {
  408. this->segmentsList = segmentImpl;
  409. }
  410. else
  411. {
  412. temp = segmentsList;
  413. while (temp->nextSegment)
  414. {
  415. temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
  416. }
  417. temp->nextSegment = segmentImpl;
  418. }
  419. return numbers;
  420. }
  421. XProcNumberPageSegment * XProcNumberPageSegmentManager::GetFreeSegment(Memory::ArenaAllocator* alloc)
  422. {
  423. AutoCriticalSection autoCS(&cs);
  424. auto temp = segmentsList;
  425. auto prev = &segmentsList;
  426. while (temp)
  427. {
  428. if (temp->allocEndAddress != temp->pageAddress + (int)(XProcNumberPageSegmentImpl::PageCount*AutoSystemInfo::PageSize)) // not full
  429. {
  430. *prev = (XProcNumberPageSegmentImpl*)temp->nextSegment;
  431. // remove from the list
  432. XProcNumberPageSegment * seg = (XProcNumberPageSegment *)AnewStructZ(alloc, XProcNumberPageSegmentImpl);
  433. temp->nextSegment = 0;
  434. memcpy(seg, temp, sizeof(XProcNumberPageSegment));
  435. midl_user_free(temp);
  436. return seg;
  437. }
  438. prev = (XProcNumberPageSegmentImpl**)&temp->nextSegment;
  439. temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
  440. }
  441. return nullptr;
  442. }
  443. void XProcNumberPageSegmentManager::Integrate()
  444. {
  445. AutoCriticalSection autoCS(&cs);
  446. auto temp = this->segmentsList;
  447. auto prev = &this->segmentsList;
  448. while (temp)
  449. {
  450. if((uintptr_t)temp->allocEndAddress - (uintptr_t)temp->pageAddress > temp->blockIntegratedSize + XProcNumberPageSegmentImpl::BlockSize)
  451. {
  452. if (temp->pageSegment == 0)
  453. {
  454. auto leafPageAllocator = recycler->GetDefaultHeapInfo()->GetRecyclerLeafPageAllocator();
  455. DListBase<PageSegment> segmentList;
  456. temp->pageSegment = (intptr_t)leafPageAllocator->AllocPageSegment(segmentList, leafPageAllocator,
  457. (void*)temp->pageAddress, XProcNumberPageSegmentImpl::PageCount, temp->committedEnd / AutoSystemInfo::PageSize, false);
  458. if (temp->pageSegment)
  459. {
  460. leafPageAllocator->IntegrateSegments(segmentList, 1, XProcNumberPageSegmentImpl::PageCount);
  461. this->integratedSegmentCount++;
  462. }
  463. }
  464. if (temp->pageSegment)
  465. {
  466. unsigned int minIntegrateSize = XProcNumberPageSegmentImpl::BlockSize;
  467. for (; temp->pageAddress + temp->blockIntegratedSize + minIntegrateSize < (unsigned int)temp->allocEndAddress;
  468. temp->blockIntegratedSize += minIntegrateSize)
  469. {
  470. TRACK_ALLOC_INFO(recycler, Js::JavascriptNumber, Recycler, 0, (size_t)-1);
  471. if (!recycler->IntegrateBlock<LeafBit>((char*)temp->pageAddress + temp->blockIntegratedSize,
  472. (PageSegment*)temp->pageSegment, XProcNumberPageSegmentImpl::sizeCat, sizeof(Js::JavascriptNumber)))
  473. {
  474. Js::Throw::OutOfMemory();
  475. }
  476. }
  477. if ((uintptr_t)temp->allocEndAddress + XProcNumberPageSegmentImpl::sizeCat
  478. > (uintptr_t)temp->pageAddress + XProcNumberPageSegmentImpl::PageCount*AutoSystemInfo::PageSize)
  479. {
  480. *prev = (XProcNumberPageSegmentImpl*)temp->nextSegment;
  481. midl_user_free(temp);
  482. temp = *prev;
  483. continue;
  484. }
  485. }
  486. }
  487. temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
  488. }
  489. }
  490. XProcNumberPageSegmentManager::XProcNumberPageSegmentManager(Recycler* recycler)
  491. :segmentsList(nullptr), recycler(recycler), integratedSegmentCount(0)
  492. {
  493. #ifdef RECYCLER_MEMORY_VERIFY
  494. XProcNumberPageSegmentImpl::Initialize(recycler->VerifyEnabled() == TRUE, recycler->GetVerifyPad());
  495. #else
  496. XProcNumberPageSegmentImpl::Initialize(false, 0);
  497. #endif
  498. }
  499. XProcNumberPageSegmentManager::~XProcNumberPageSegmentManager()
  500. {
  501. auto temp = segmentsList;
  502. while (temp)
  503. {
  504. auto next = temp->nextSegment;
  505. midl_user_free(temp);
  506. temp = (XProcNumberPageSegmentImpl*)next;
  507. }
  508. }
  509. #endif