| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "Backend.h"
- CodeGenNumberThreadAllocator::CodeGenNumberThreadAllocator(Recycler * recycler)
- : recycler(recycler), currentNumberSegment(nullptr), currentChunkSegment(nullptr),
- numberSegmentEnd(nullptr), currentNumberBlockEnd(nullptr), nextNumber(nullptr), chunkSegmentEnd(nullptr),
- currentChunkBlockEnd(nullptr), nextChunk(nullptr), hasNewNumberBlock(nullptr), hasNewChunkBlock(nullptr),
- pendingIntegrationNumberSegmentCount(0), pendingIntegrationChunkSegmentCount(0),
- pendingIntegrationNumberSegmentPageCount(0), pendingIntegrationChunkSegmentPageCount(0)
- {
- }
- CodeGenNumberThreadAllocator::~CodeGenNumberThreadAllocator()
- {
- pendingIntegrationNumberSegment.Clear(&NoThrowNoMemProtectHeapAllocator::Instance);
- pendingIntegrationChunkSegment.Clear(&NoThrowNoMemProtectHeapAllocator::Instance);
- pendingIntegrationNumberBlock.Clear(&NoThrowHeapAllocator::Instance);
- pendingIntegrationChunkBlock.Clear(&NoThrowHeapAllocator::Instance);
- pendingFlushNumberBlock.Clear(&NoThrowHeapAllocator::Instance);
- pendingFlushChunkBlock.Clear(&NoThrowHeapAllocator::Instance);
- pendingReferenceNumberBlock.Clear(&NoThrowHeapAllocator::Instance);
- }
- size_t
- CodeGenNumberThreadAllocator::GetNumberAllocSize()
- {
- #ifdef RECYCLER_MEMORY_VERIFY
- if (recycler->VerifyEnabled())
- {
- return HeapInfo::GetAlignedSize(AllocSizeMath::Add(sizeof(Js::JavascriptNumber) + sizeof(size_t), recycler->verifyPad));
- }
- #endif
- return HeapInfo::GetAlignedSizeNoCheck(sizeof(Js::JavascriptNumber));
- }
- size_t
- CodeGenNumberThreadAllocator::GetChunkAllocSize()
- {
- #ifdef RECYCLER_MEMORY_VERIFY
- if (recycler->VerifyEnabled())
- {
- return HeapInfo::GetAlignedSize(AllocSizeMath::Add(sizeof(CodeGenNumberChunk) + sizeof(size_t), recycler->verifyPad));
- }
- #endif
- return HeapInfo::GetAlignedSizeNoCheck(sizeof(CodeGenNumberChunk));
- }
- Js::JavascriptNumber *
- CodeGenNumberThreadAllocator::AllocNumber()
- {
- AutoCriticalSection autocs(&cs);
- size_t sizeCat = GetNumberAllocSize();
- if (nextNumber + sizeCat > currentNumberBlockEnd)
- {
- AllocNewNumberBlock();
- }
- Js::JavascriptNumber * newNumber = (Js::JavascriptNumber *)nextNumber;
- #ifdef RECYCLER_MEMORY_VERIFY
- recycler->FillCheckPad(newNumber, sizeof(Js::JavascriptNumber), sizeCat);
- #endif
- nextNumber += sizeCat;
- return newNumber;
- }
- CodeGenNumberChunk *
- CodeGenNumberThreadAllocator::AllocChunk()
- {
- AutoCriticalSection autocs(&cs);
- size_t sizeCat = GetChunkAllocSize();
- if (nextChunk + sizeCat > currentChunkBlockEnd)
- {
- AllocNewChunkBlock();
- }
- CodeGenNumberChunk * newChunk = (CodeGenNumberChunk *)nextChunk;
- #ifdef RECYCLER_MEMORY_VERIFY
- recycler->FillCheckPad(nextChunk, sizeof(CodeGenNumberChunk), sizeCat);
- #endif
- memset(newChunk, 0, sizeof(CodeGenNumberChunk));
- nextChunk += sizeCat;
- return newChunk;
- }
- void
- CodeGenNumberThreadAllocator::AllocNewNumberBlock()
- {
- Assert(cs.IsLocked());
- Assert(nextNumber + GetNumberAllocSize() > currentNumberBlockEnd);
- if (hasNewNumberBlock)
- {
- if (!pendingReferenceNumberBlock.PrependNode(&NoThrowHeapAllocator::Instance,
- currentNumberBlockEnd - BlockSize, currentNumberSegment))
- {
- Js::Throw::OutOfMemory();
- }
- hasNewNumberBlock = false;
- }
- if (currentNumberBlockEnd == numberSegmentEnd)
- {
- Assert(cs.IsLocked());
- // Reserve the segment, but not committing it
- currentNumberSegment = PageAllocator::AllocPageSegment(pendingIntegrationNumberSegment, this->recycler->GetRecyclerLeafPageAllocator(), false, true);
- if (currentNumberSegment == nullptr)
- {
- currentNumberBlockEnd = nullptr;
- numberSegmentEnd = nullptr;
- nextNumber = nullptr;
- Js::Throw::OutOfMemory();
- }
- pendingIntegrationNumberSegmentCount++;
- pendingIntegrationNumberSegmentPageCount += currentNumberSegment->GetPageCount();
- currentNumberBlockEnd = currentNumberSegment->GetAddress();
- numberSegmentEnd = currentNumberSegment->GetEndAddress();
- }
- // Commit the page.
- if (!::VirtualAlloc(currentNumberBlockEnd, BlockSize, MEM_COMMIT, PAGE_READWRITE))
- {
- Js::Throw::OutOfMemory();
- }
- nextNumber = currentNumberBlockEnd;
- currentNumberBlockEnd += BlockSize;
- hasNewNumberBlock = true;
- this->recycler->GetRecyclerLeafPageAllocator()->FillAllocPages(nextNumber, 1);
- }
- void
- CodeGenNumberThreadAllocator::AllocNewChunkBlock()
- {
- Assert(cs.IsLocked());
- Assert(nextChunk + GetChunkAllocSize() > currentChunkBlockEnd);
- if (hasNewChunkBlock)
- {
- if (!pendingFlushChunkBlock.PrependNode(&NoThrowHeapAllocator::Instance,
- currentChunkBlockEnd - BlockSize, currentChunkSegment))
- {
- Js::Throw::OutOfMemory();
- }
- // All integrated pages' object are all live initially, so don't need to rescan them
- ::ResetWriteWatch(currentChunkBlockEnd - BlockSize, BlockSize);
- pendingReferenceNumberBlock.MoveTo(&pendingFlushNumberBlock);
- hasNewChunkBlock = false;
- }
- if (currentChunkBlockEnd == chunkSegmentEnd)
- {
- Assert(cs.IsLocked());
- // Reserve the segment, but not committing it
- currentChunkSegment = PageAllocator::AllocPageSegment(pendingIntegrationChunkSegment, this->recycler->GetRecyclerPageAllocator(), false, true);
- if (currentChunkSegment == nullptr)
- {
- currentChunkBlockEnd = nullptr;
- chunkSegmentEnd = nullptr;
- nextChunk = nullptr;
- Js::Throw::OutOfMemory();
- }
- pendingIntegrationChunkSegmentCount++;
- pendingIntegrationChunkSegmentPageCount += currentChunkSegment->GetPageCount();
- currentChunkBlockEnd = currentChunkSegment->GetAddress();
- chunkSegmentEnd = currentChunkSegment->GetEndAddress();
- }
- // Commit the page.
- if (!::VirtualAlloc(currentChunkBlockEnd, BlockSize, MEM_COMMIT, PAGE_READWRITE))
- {
- Js::Throw::OutOfMemory();
- }
- nextChunk = currentChunkBlockEnd;
- currentChunkBlockEnd += BlockSize;
- hasNewChunkBlock = true;
- this->recycler->GetRecyclerLeafPageAllocator()->FillAllocPages(nextChunk, 1);
- }
- void
- CodeGenNumberThreadAllocator::Integrate()
- {
- AutoCriticalSection autocs(&cs);
- PageAllocator * leafPageAllocator = this->recycler->GetRecyclerLeafPageAllocator();
- leafPageAllocator->IntegrateSegments(pendingIntegrationNumberSegment, pendingIntegrationNumberSegmentCount, pendingIntegrationNumberSegmentPageCount);
- PageAllocator * recyclerPageAllocator = this->recycler->GetRecyclerPageAllocator();
- recyclerPageAllocator->IntegrateSegments(pendingIntegrationChunkSegment, pendingIntegrationChunkSegmentCount, pendingIntegrationChunkSegmentPageCount);
- pendingIntegrationNumberSegmentCount = 0;
- pendingIntegrationChunkSegmentCount = 0;
- pendingIntegrationNumberSegmentPageCount = 0;
- pendingIntegrationChunkSegmentPageCount = 0;
- #ifdef TRACK_ALLOC
- TrackAllocData oldAllocData = recycler->nextAllocData;
- recycler->nextAllocData.Clear();
- #endif
- while (!pendingIntegrationNumberBlock.Empty())
- {
- TRACK_ALLOC_INFO(recycler, Js::JavascriptNumber, Recycler, 0, (size_t)-1);
- BlockRecord& record = pendingIntegrationNumberBlock.Head();
- if (!recycler->IntegrateBlock<LeafBit>(record.blockAddress, record.segment, GetNumberAllocSize(), sizeof(Js::JavascriptNumber)))
- {
- Js::Throw::OutOfMemory();
- }
- pendingIntegrationNumberBlock.RemoveHead(&NoThrowHeapAllocator::Instance);
- }
- while (!pendingIntegrationChunkBlock.Empty())
- {
- // REVIEW: the above number block integration can be moved into this loop
- TRACK_ALLOC_INFO(recycler, CodeGenNumberChunk, Recycler, 0, (size_t)-1);
- BlockRecord& record = pendingIntegrationChunkBlock.Head();
- if (!recycler->IntegrateBlock<NoBit>(record.blockAddress, record.segment, GetChunkAllocSize(), sizeof(CodeGenNumberChunk)))
- {
- Js::Throw::OutOfMemory();
- }
- pendingIntegrationChunkBlock.RemoveHead(&NoThrowHeapAllocator::Instance);
- }
- #ifdef TRACK_ALLOC
- Assert(recycler->nextAllocData.IsEmpty());
- recycler->nextAllocData = oldAllocData;
- #endif
- }
- void
- CodeGenNumberThreadAllocator::FlushAllocations()
- {
- AutoCriticalSection autocs(&cs);
- pendingFlushNumberBlock.MoveTo(&pendingIntegrationNumberBlock);
- pendingFlushChunkBlock.MoveTo(&pendingIntegrationChunkBlock);
- }
- CodeGenNumberAllocator::CodeGenNumberAllocator(CodeGenNumberThreadAllocator * threadAlloc, Recycler * recycler) :
- threadAlloc(threadAlloc), recycler(recycler), chunk(nullptr), chunkTail(nullptr), currentChunkNumberCount(CodeGenNumberChunk::MaxNumberCount)
- {
- #if DBG
- finalized = false;
- #endif
- }
- // We should never call this function if we are using tagged float
- #if !FLOATVAR
- Js::JavascriptNumber *
- CodeGenNumberAllocator::Alloc()
- {
- Assert(!finalized);
- if (currentChunkNumberCount == CodeGenNumberChunk::MaxNumberCount)
- {
- CodeGenNumberChunk * newChunk = threadAlloc? threadAlloc->AllocChunk()
- : RecyclerNewStructZ(recycler, CodeGenNumberChunk);
- // Need to always put the new chunk last, as when we flush
- // pages, new chunk's page might not be full yet, and won't
- // be flushed, and we will have a broken link in the link list.
- newChunk->next = nullptr;
- if (this->chunkTail != nullptr)
- {
- this->chunkTail->next = newChunk;
- }
- else
- {
- this->chunk = newChunk;
- }
- this->chunkTail = newChunk;
- this->currentChunkNumberCount = 0;
- }
- Js::JavascriptNumber * newNumber = threadAlloc? threadAlloc->AllocNumber()
- : Js::JavascriptNumber::NewUninitialized(recycler);
- this->chunkTail->numbers[this->currentChunkNumberCount++] = newNumber;
- return newNumber;
- }
- #endif
- CodeGenNumberChunk *
- CodeGenNumberAllocator::Finalize()
- {
- Assert(!finalized);
- #if DBG
- finalized = true;
- #endif
- CodeGenNumberChunk * finalizedChunk = this->chunk;
- this->chunk = nullptr;
- this->chunkTail = nullptr;
- this->currentChunkNumberCount = 0;
- return finalizedChunk;
- }
- /* static */
- uint
- XProcNumberPageSegmentImpl::GetSizeCat()
- {
- return (uint)HeapInfo::GetAlignedSizeNoCheck(sizeof(Js::JavascriptNumber));
- }
- Js::JavascriptNumber* XProcNumberPageSegmentImpl::AllocateNumber(HANDLE hProcess, double value, Js::StaticType* numberTypeStatic, void* javascriptNumberVtbl)
- {
- XProcNumberPageSegmentImpl* tail = this;
- if (this->pageAddress != 0)
- {
- while (tail->nextSegment)
- {
- tail = (XProcNumberPageSegmentImpl*)tail->nextSegment;
- }
- if (tail->pageAddress + tail->committedEnd - tail->allocEndAddress >= GetSizeCat())
- {
- auto number = tail->allocEndAddress;
- tail->allocEndAddress += GetSizeCat();
- Js::JavascriptNumber localNumber(value, numberTypeStatic
- #if DBG
- , true
- #endif
- );
- // change vtable to the remote one
- *(void**)&localNumber = javascriptNumberVtbl;
- // initialize number by WriteProcessMemory
- SIZE_T bytesWritten;
- WriteProcessMemory(hProcess, (void*)number, &localNumber, sizeof(localNumber), &bytesWritten);
- return (Js::JavascriptNumber*) number;
- }
- // alloc blocks
- if ((void*)tail->committedEnd < tail->GetEndAddress())
- {
- Assert((unsigned int)((char*)tail->GetEndAddress() - (char*)tail->committedEnd) >= BlockSize);
- // TODO: implement guard pages (still necessary for OOP JIT?)
- auto ret = ::VirtualAllocEx(hProcess, tail->GetCommitEndAddress(), BlockSize, MEM_COMMIT, PAGE_READWRITE);
- if (!ret)
- {
- Js::Throw::OutOfMemory();
- }
- tail->committedEnd += BlockSize;
- return AllocateNumber(hProcess, value, numberTypeStatic, javascriptNumberVtbl);
- }
- }
- // alloc new segment
- void* pages = ::VirtualAllocEx(hProcess, nullptr, PageCount * AutoSystemInfo::PageSize, MEM_RESERVE, PAGE_READWRITE);
- if (pages == nullptr)
- {
- Js::Throw::OutOfMemory();
- }
- if (tail->pageAddress == 0)
- {
- tail = new (tail) XProcNumberPageSegmentImpl();
- tail->pageAddress = (intptr_t)pages;
- tail->allocStartAddress = this->pageAddress;
- tail->allocEndAddress = this->pageAddress;
- tail->nextSegment = nullptr;
- return AllocateNumber(hProcess, value, numberTypeStatic, javascriptNumberVtbl);
- }
- else
- {
- XProcNumberPageSegmentImpl* seg = (XProcNumberPageSegmentImpl*)midl_user_allocate(sizeof(XProcNumberPageSegment));
- if (seg == nullptr)
- {
- Js::Throw::OutOfMemory();
- }
- seg = new (seg) XProcNumberPageSegmentImpl();
- tail->nextSegment = seg;
- return seg->AllocateNumber(hProcess, value, numberTypeStatic, javascriptNumberVtbl);
- }
- }
- XProcNumberPageSegmentImpl::XProcNumberPageSegmentImpl()
- {
- this->blockIntegratedSize = 0;
- this->pageSegment = 0;
- }
- CodeGenNumberChunk* ::XProcNumberPageSegmentManager::RegisterSegments(XProcNumberPageSegment* segments)
- {
- Assert(segments->pageAddress && segments->allocStartAddress && segments->allocEndAddress);
- XProcNumberPageSegmentImpl* segmentImpl = (XProcNumberPageSegmentImpl*)segments;
- auto temp = segmentImpl;
- CodeGenNumberChunk* chunk = nullptr;
- int numberCount = CodeGenNumberChunk::MaxNumberCount;
- while (temp)
- {
- auto start = temp->allocStartAddress;
- if (temp->GetChunkAllocator() == nullptr)
- {
- temp->chunkAllocator = (intptr_t)HeapNew(CodeGenNumberThreadAllocator, this->recycler);
- chunkAllocators.Add(temp->GetChunkAllocator());
- }
- while (start < temp->allocEndAddress)
- {
- if (numberCount == CodeGenNumberChunk::MaxNumberCount)
- {
- auto newChunk = temp->GetChunkAllocator()->AllocChunk();
- newChunk->next = chunk;
- chunk = newChunk;
- numberCount = 0;
- }
- chunk->numbers[numberCount++] = (Js::JavascriptNumber*)start;
- start += XProcNumberPageSegmentImpl::GetSizeCat();
- }
- temp->GetChunkAllocator()->FlushAllocations();
- temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
- }
- AutoCriticalSection autoCS(&cs);
- if (this->segmentsList == nullptr)
- {
- this->segmentsList = segmentImpl;
- }
- else
- {
- temp = segmentsList;
- while (temp->nextSegment)
- {
- temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
- }
- temp->nextSegment = segmentImpl;
- }
- return chunk;
- }
- void XProcNumberPageSegmentManager::GetFreeSegment(XProcNumberPageSegment * seg)
- {
- AutoCriticalSection autoCS(&cs);
- if (segmentsList == nullptr)
- {
- new (seg) XProcNumberPageSegmentImpl();
- return;
- }
- auto temp = segmentsList;
- auto prev = &segmentsList;
- while (temp)
- {
- if (temp->allocEndAddress != temp->pageAddress + (int)(XProcNumberPageSegmentImpl::PageCount*AutoSystemInfo::PageSize)) // not full
- {
- *prev = (XProcNumberPageSegmentImpl*)temp->nextSegment;
- // remove from the list
- memcpy(seg, temp, sizeof(XProcNumberPageSegment));
- midl_user_free(temp);
- return;
- }
- prev = (XProcNumberPageSegmentImpl**)&temp->nextSegment;
- temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
- }
- }
- void XProcNumberPageSegmentManager::Integrate()
- {
- AutoCriticalSection autoCS(&cs);
- auto temp = this->segmentsList;
- auto prev = &this->segmentsList;
- while (temp)
- {
- if (temp->pageSegment == 0)
- {
- auto leafPageAllocator = recycler->GetRecyclerLeafPageAllocator();
- DListBase<PageSegment> segmentList;
- temp->pageSegment = (intptr_t)leafPageAllocator->AllocPageSegment(segmentList, leafPageAllocator,
- (void*)temp->pageAddress, XProcNumberPageSegmentImpl::PageCount, temp->committedEnd / AutoSystemInfo::PageSize);
- leafPageAllocator->IntegrateSegments(segmentList, 1, XProcNumberPageSegmentImpl::PageCount);
- this->integratedSegmentCount++;
- }
- if (!temp->GetChunkAllocator()->pendingIntegrationChunkBlock.Empty())
- {
- Assert(sizeof(CodeGenNumberChunk) == sizeof(Js::JavascriptNumber));
- unsigned int minIntegrateSize = XProcNumberPageSegmentImpl::BlockSize *CodeGenNumberChunk::MaxNumberCount;
- for (; temp->pageAddress + temp->blockIntegratedSize + minIntegrateSize < (unsigned int)temp->allocEndAddress;
- temp->blockIntegratedSize += minIntegrateSize)
- {
- TRACK_ALLOC_INFO(recycler, Js::JavascriptNumber, Recycler, 0, (size_t)-1);
- if (!recycler->IntegrateBlock<LeafBit>((char*)temp->pageAddress + temp->blockIntegratedSize, (PageSegment*)temp->pageSegment, XProcNumberPageSegmentImpl::GetSizeCat(), sizeof(Js::JavascriptNumber)))
- {
- Js::Throw::OutOfMemory();
- }
- }
- }
- temp->GetChunkAllocator()->Integrate();
- if (temp->blockIntegratedSize >= XProcNumberPageSegmentImpl::PageCount*AutoSystemInfo::PageSize)
- {
- // all pages are integrated, don't need this segment any more
- *prev = (XProcNumberPageSegmentImpl*)temp->nextSegment;
- if (chunkAllocators.Contains(temp->GetChunkAllocator()))
- {
- chunkAllocators.Remove(temp->GetChunkAllocator());
- HeapDelete(temp->GetChunkAllocator());
- }
- midl_user_free(temp);
- temp = *prev;
- }
- else
- {
- prev = (XProcNumberPageSegmentImpl**)&temp->nextSegment;
- temp = (XProcNumberPageSegmentImpl*)temp->nextSegment;
- }
- }
- }
- XProcNumberPageSegmentManager::~XProcNumberPageSegmentManager()
- {
- auto temp = segmentsList;
- while (temp)
- {
- auto next = temp->nextSegment;
- if (temp->GetChunkAllocator())
- {
- if (chunkAllocators.Contains(temp->GetChunkAllocator()))
- {
- chunkAllocators.Remove(temp->GetChunkAllocator());
- HeapDelete(temp->GetChunkAllocator());
- }
- }
- midl_user_free(temp);
- temp = (XProcNumberPageSegmentImpl*)next;
- }
- }
|