| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659 |
- //-------------------------------------------------------------------------------------------------------
- // 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"
- //----------------------------------------------------------------------------
- // EmitBufferManager::EmitBufferManager
- // Constructor
- //----------------------------------------------------------------------------
- template <typename TAlloc, typename TPreReservedAlloc, typename SyncObject>
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::EmitBufferManager(ArenaAllocator * allocator, CustomHeap::CodePageAllocators<TAlloc, TPreReservedAlloc> * codePageAllocators,
- Js::ScriptContext * scriptContext, ThreadContextInfo * threadContext, LPCWSTR name, HANDLE processHandle) :
- allocationHeap(allocator, codePageAllocators, processHandle),
- allocator(allocator),
- allocations(nullptr),
- scriptContext(scriptContext),
- threadContext(threadContext),
- processHandle(processHandle)
- {
- #if DBG_DUMP
- this->totalBytesCode = 0;
- this->totalBytesLoopBody = 0;
- this->totalBytesAlignment = 0;
- this->totalBytesCommitted = 0;
- this->totalBytesReserved = 0;
- this->name = name;
- #endif
- }
- //----------------------------------------------------------------------------
- // EmitBufferManager::~EmitBufferManager()
- // Free up all the VirtualAlloced memory
- //----------------------------------------------------------------------------
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::~EmitBufferManager()
- {
- Clear();
- }
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- void
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::Decommit()
- {
- FreeAllocations(false);
- }
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- void
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::Clear()
- {
- FreeAllocations(true);
- }
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- void
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::FreeAllocations(bool release)
- {
- #if PDATA_ENABLED && defined(_WIN32)
- DelayDeletingFunctionTable::Clear();
- #endif
- AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
- #if DBG_DUMP
- if (!release && PHASE_STATS1(Js::EmitterPhase))
- {
- this->DumpAndResetStats(Js::Configuration::Global.flags.Filename);
- }
- #endif
- TEmitBufferAllocation * allocation = this->allocations;
- while (allocation != nullptr)
- {
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- if(CONFIG_FLAG(CheckEmitBufferPermissions))
- {
- CheckBufferPermissions(allocation);
- }
- #endif
- if (release)
- {
- this->allocationHeap.Free(allocation->allocation);
- }
- else if ((scriptContext != nullptr) && allocation->recorded)
- {
- // In case of ThunkEmitter the script context would be null and we don't want to track that as code size.
- this->scriptContext->GetThreadContext()->SubCodeSize(allocation->bytesCommitted);
- allocation->recorded = false;
- }
- allocation = allocation->nextAllocation;
- }
- if (release)
- {
- this->allocations = nullptr;
- }
- else
- {
- this->allocationHeap.DecommitAll();
- }
- }
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::IsInHeap(__in void* address)
- {
- AutoRealOrFakeCriticalSection<SyncObject> autocs(&this->criticalSection);
- return this->allocationHeap.IsInHeap(address);
- }
- template <typename TAlloc, typename TPreReservedAlloc>
- class AutoCustomHeapPointer
- {
- public:
- AutoCustomHeapPointer(CustomHeap::Heap<TAlloc, TPreReservedAlloc> * allocationHeap, CustomHeap::Allocation* heapAllocation) :
- _allocationHeap(allocationHeap),
- _heapAllocation(heapAllocation)
- {
- }
- ~AutoCustomHeapPointer()
- {
- if (_heapAllocation)
- {
- _allocationHeap->Free(_heapAllocation);
- }
- }
- CustomHeap::Allocation* Detach()
- {
- CustomHeap::Allocation* allocation = _heapAllocation;
- Assert(allocation != nullptr);
- _heapAllocation = nullptr;
- return allocation;
- }
- private:
- CustomHeap::Allocation* _heapAllocation;
- CustomHeap::Heap<TAlloc, TPreReservedAlloc>* _allocationHeap;
- };
- //----------------------------------------------------------------------------
- // EmitBufferManager::NewAllocation
- // Create a new allocation
- //----------------------------------------------------------------------------
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- EmitBufferAllocation<TAlloc, TPreReservedAlloc> *
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::NewAllocation(size_t bytes, ushort pdataCount, ushort xdataSize, bool canAllocInPreReservedHeapPageSegment, bool isAnyJittedCode)
- {
- FAULTINJECT_MEMORY_THROW(_u("JIT"), bytes);
- Assert(this->criticalSection.IsLocked());
- bool isAllJITCodeInPreReservedRegion = true;
- CustomHeap::Allocation* heapAllocation = this->allocationHeap.Alloc(bytes, pdataCount, xdataSize, canAllocInPreReservedHeapPageSegment, isAnyJittedCode, &isAllJITCodeInPreReservedRegion);
- if (heapAllocation == nullptr)
- {
- if (!JITManager::GetJITManager()->IsJITServer())
- {
- // This is used in interpreter scenario, thus we need to try to recover memory, if possible.
- // Can't simply throw as in JIT scenario, for which throw is what we want in order to give more mem to interpreter.
- JsUtil::ExternalApi::RecoverUnusedMemory();
- heapAllocation = this->allocationHeap.Alloc(bytes, pdataCount, xdataSize, canAllocInPreReservedHeapPageSegment, isAnyJittedCode, &isAllJITCodeInPreReservedRegion);
- }
- }
- if (heapAllocation == nullptr)
- {
- Js::Throw::OutOfMemory();
- }
- #if DBG
- heapAllocation->isAllocationUsed = true;
- #endif
- AutoCustomHeapPointer<TAlloc, TPreReservedAlloc> allocatedMemory(&this->allocationHeap, heapAllocation);
- VerboseHeapTrace(_u("New allocation: 0x%p, size: %p\n"), heapAllocation->address, heapAllocation->size);
- TEmitBufferAllocation * allocation = AnewStruct(this->allocator, TEmitBufferAllocation);
- allocation->bytesCommitted = heapAllocation->size;
- allocation->allocation = allocatedMemory.Detach();
- allocation->bytesUsed = 0;
- allocation->nextAllocation = this->allocations;
- allocation->recorded = false;
- allocation->inPrereservedRegion = isAllJITCodeInPreReservedRegion;
- this->allocations = allocation;
- #if DBG_DUMP
- this->totalBytesCommitted += heapAllocation->size;
- #endif
- return allocation;
- }
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- void
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::SetValidCallTarget(TEmitBufferAllocation* allocation, void* callTarget, bool isValid)
- {
- #if _M_ARM
- callTarget = (void*)((uintptr_t)callTarget | 0x1); // add the thumb bit back, so we CFG-unregister the actual call target
- #endif
- if (!JITManager::GetJITManager()->IsJITServer())
- {
- this->threadContext->SetValidCallTargetForCFG(callTarget, isValid);
- }
- #if ENABLE_OOP_NATIVE_CODEGEN
- else if (CONFIG_FLAG(OOPCFGRegistration))
- {
- void* segment = allocation->allocation->IsLargeAllocation()
- ? allocation->allocation->largeObjectAllocation.segment
- : allocation->allocation->page->segment;
- HANDLE fileHandle = nullptr;
- PVOID baseAddress = nullptr;
- bool found = false;
- if (this->allocationHeap.IsPreReservedSegment(segment))
- {
- found = ((SegmentBase<TPreReservedAlloc>*)segment)->GetAllocator()->GetVirtualAllocator()->GetFileInfo(callTarget, &fileHandle, &baseAddress);
- }
- else
- {
- found = ((SegmentBase<TAlloc>*)segment)->GetAllocator()->GetVirtualAllocator()->GetFileInfo(callTarget, &fileHandle, &baseAddress);
- }
- AssertOrFailFast(found);
- this->threadContext->SetValidCallTargetFile(callTarget, fileHandle, baseAddress, isValid);
- }
- #endif
- }
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- bool
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::FreeAllocation(void* address)
- {
- #if PDATA_ENABLED && defined(_WIN32)
- DelayDeletingFunctionTable::Clear();
- #endif
- AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
- #if _M_ARM
- address = (void*)((uintptr_t)address & ~0x1); // clear the thumb bit
- #endif
- TEmitBufferAllocation* previous = nullptr;
- TEmitBufferAllocation* allocation = allocations;
- while(allocation != nullptr)
- {
- if (address == allocation->allocation->address)
- {
- if (previous == nullptr)
- {
- this->allocations = allocation->nextAllocation;
- }
- else
- {
- previous->nextAllocation = allocation->nextAllocation;
- }
- if ((scriptContext != nullptr) && allocation->recorded)
- {
- this->scriptContext->GetThreadContext()->SubCodeSize(allocation->bytesCommitted);
- }
- #if defined(_CONTROL_FLOW_GUARD) && !defined(_M_ARM)
- if (allocation->allocation->thunkAddress)
- {
- if (JITManager::GetJITManager()->IsJITServer())
- {
- ((ServerThreadContext*)this->threadContext)->GetJITThunkEmitter()->FreeThunk(allocation->allocation->thunkAddress);
- }
- else
- {
- ((ThreadContext*)this->threadContext)->GetJITThunkEmitter()->FreeThunk(allocation->allocation->thunkAddress);
- }
- }
- else
- #endif
- {
- SetValidCallTarget(allocation, address, false);
- }
- VerboseHeapTrace(_u("Freeing 0x%p, allocation: 0x%p\n"), address, allocation->allocation->address);
- this->allocationHeap.Free(allocation->allocation);
- this->allocator->Free(allocation, sizeof(TEmitBufferAllocation));
- return true;
- }
- previous = allocation;
- allocation = allocation->nextAllocation;
- }
- return false;
- }
- //----------------------------------------------------------------------------
- // EmitBufferManager::FinalizeAllocation
- // Fill the rest of the buffer (length given by allocation->BytesFree()) with debugger breakpoints.
- //----------------------------------------------------------------------------
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::FinalizeAllocation(TEmitBufferAllocation *allocation, BYTE * dstBuffer)
- {
- Assert(this->criticalSection.IsLocked());
- DWORD bytes = allocation->BytesFree();
- if(bytes > 0)
- {
- BYTE* buffer = nullptr;
- this->GetBuffer(allocation, bytes, &buffer);
- if (!this->CommitBuffer(allocation, allocation->bytesCommitted, dstBuffer, 0, /*sourceBuffer=*/ nullptr, /*alignPad=*/ bytes))
- {
- return false;
- }
- #if DBG_DUMP
- this->totalBytesCode -= bytes;
- #endif
- }
- return true;
- }
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- EmitBufferAllocation<TAlloc, TPreReservedAlloc>*
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::GetBuffer(TEmitBufferAllocation *allocation, __in size_t bytes, __deref_bcount(bytes) BYTE** ppBuffer)
- {
- Assert(this->criticalSection.IsLocked());
- Assert(allocation->BytesFree() >= bytes);
- // In case of ThunkEmitter the script context would be null and we don't want to track that as code size.
- if (scriptContext && !allocation->recorded)
- {
- this->scriptContext->GetThreadContext()->AddCodeSize(allocation->bytesCommitted);
- allocation->recorded = true;
- }
- // The codegen buffer is beyond the alignment section - hence, we pass this pointer.
- *ppBuffer = allocation->GetUnused();
- return allocation;
- }
- //----------------------------------------------------------------------------
- // EmitBufferManager::Allocate
- // Allocates an executable buffer with a certain alignment
- // NOTE: This buffer is not readable or writable. Use CommitBuffer
- // to modify this buffer one page at a time.
- //----------------------------------------------------------------------------
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- EmitBufferAllocation<TAlloc, TPreReservedAlloc>*
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::AllocateBuffer(__in size_t bytes, __deref_bcount(bytes) BYTE** ppBuffer, ushort pdataCount /*=0*/, ushort xdataSize /*=0*/, bool canAllocInPreReservedHeapPageSegment /*=false*/,
- bool isAnyJittedCode /* = false*/)
- {
- AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
- Assert(ppBuffer != nullptr);
- TEmitBufferAllocation * allocation = this->NewAllocation(bytes, pdataCount, xdataSize, canAllocInPreReservedHeapPageSegment, isAnyJittedCode);
- GetBuffer(allocation, bytes, ppBuffer);
- #if DBG
- MEMORY_BASIC_INFORMATION memBasicInfo;
- size_t resultBytes = VirtualQueryEx(this->processHandle, allocation->allocation->address, &memBasicInfo, sizeof(memBasicInfo));
- Assert(resultBytes == 0 || memBasicInfo.Protect == PAGE_EXECUTE_READ);
- #endif
- return allocation;
- }
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CheckCommitFaultInjection()
- {
- if (Js::Configuration::Global.flags.ForceOOMOnEBCommit == 0)
- {
- return false;
- }
- commitCount++;
- if (Js::Configuration::Global.flags.ForceOOMOnEBCommit == -1)
- {
- Output::Print(_u("Commit count: %d\n"), commitCount);
- }
- else if (commitCount == Js::Configuration::Global.flags.ForceOOMOnEBCommit)
- {
- return true;
- }
- return false;
- }
- #endif
- #if DBG
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::IsBufferExecuteReadOnly(TEmitBufferAllocation * allocation)
- {
- AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
- MEMORY_BASIC_INFORMATION memBasicInfo;
- size_t resultBytes = VirtualQuery(allocation->allocation->address, &memBasicInfo, sizeof(memBasicInfo));
- return resultBytes != 0 && memBasicInfo.Protect == PAGE_EXECUTE_READ;
- }
- #endif
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::ProtectBufferWithExecuteReadWriteForInterpreter(TEmitBufferAllocation* allocation)
- {
- Assert(this->criticalSection.IsLocked());
- Assert(allocation != nullptr);
- return (this->allocationHeap.ProtectAllocationWithExecuteReadWrite(allocation->allocation) == TRUE);
- }
- // Returns true if we successfully commit the buffer
- // Returns false if we OOM
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CommitBufferForInterpreter(TEmitBufferAllocation* allocation, _In_reads_bytes_(bufferSize) BYTE* pBuffer, _In_ size_t bufferSize)
- {
- Assert(this->criticalSection.IsLocked());
- Assert(allocation != nullptr);
- allocation->bytesUsed += bufferSize;
- #ifdef DEBUG
- this->totalBytesCode += bufferSize;
- #endif
- VerboseHeapTrace(_u("Setting execute permissions on 0x%p, allocation: 0x%p\n"), pBuffer, allocation->allocation->address);
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- if (CheckCommitFaultInjection())
- {
- return false;
- }
- #endif
- if (!JITManager::GetJITManager()->IsJITServer() && !this->allocationHeap.ProtectAllocationWithExecuteReadOnly(allocation->allocation))
- {
- return false;
- }
- if (!FlushInstructionCache(this->processHandle, pBuffer, bufferSize))
- {
- return false;
- }
- return true;
- }
- //----------------------------------------------------------------------------
- // EmitBufferManager::CommitBuffer
- // Aligns the buffer with DEBUG instructions.
- // Copies contents of source buffer to the destination buffer - at max of one page at a time.
- // This ensures that only 1 page is writable at any point of time.
- // Commit a buffer from the last AllocateBuffer call that is filled.
- //
- // Skips over the initial allocation->GetBytesUsed() bytes of destBuffer. Then, fills in `alignPad` bytes with debug breakpoint instructions,
- // copies `bytes` bytes from sourceBuffer, and finally fills in the rest of destBuffer with debug breakpoint instructions.
- //----------------------------------------------------------------------------
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- bool
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CommitBuffer(TEmitBufferAllocation* allocation, __in const size_t destBufferBytes, __out_bcount(destBufferBytes) BYTE* destBuffer, __in size_t bytes, __in_bcount(bytes) const BYTE* sourceBuffer, __in DWORD alignPad)
- {
- AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
- Assert(destBuffer != nullptr);
- Assert(allocation != nullptr);
- // The size of destBuffer is actually given by allocation->bytesCommitted, but due to a bug in some versions of PREFast, we can't refer to allocation->bytesCommitted in the
- // SAL annotation on destBuffer above. We've informed the PREFast maintainers, but we'll have to use destBufferBytes as a workaround until their fix makes it to Jenkins.
- Assert(destBufferBytes == allocation->bytesCommitted);
-
- // Must have at least enough room in destBuffer for the initial skipped bytes plus the bytes we're going to write.
- AnalysisAssert(allocation->bytesUsed + bytes + alignPad <= destBufferBytes);
- BYTE *currentDestBuffer = destBuffer + allocation->GetBytesUsed();
- char *bufferToFlush = allocation->allocation->address + allocation->GetBytesUsed();
- Assert(allocation->BytesFree() >= bytes + alignPad);
- size_t bytesLeft = bytes + alignPad;
- size_t sizeToFlush = bytesLeft;
- // Copy the contents and set the alignment pad
- while(bytesLeft != 0)
- {
- // currentDestBuffer must still point to somewhere in the interior of destBuffer.
- AnalysisAssert(destBuffer <= currentDestBuffer);
- AnalysisAssert(currentDestBuffer < destBuffer + destBufferBytes);
- DWORD spaceInCurrentPage = AutoSystemInfo::PageSize - ((size_t)currentDestBuffer & (AutoSystemInfo::PageSize - 1));
- size_t bytesToChange = bytesLeft > spaceInCurrentPage ? spaceInCurrentPage : bytesLeft;
- // Buffer and the bytes that are marked RWX - these will eventually be marked as 'EXCEUTE' only.
- BYTE* readWriteBuffer = currentDestBuffer;
- size_t readWriteBytes = bytesToChange;
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- if (CheckCommitFaultInjection())
- {
- return false;
- }
- #endif
- if (!JITManager::GetJITManager()->IsJITServer() && !this->allocationHeap.ProtectAllocationWithExecuteReadWrite(allocation->allocation, (char*)readWriteBuffer))
- {
- return false;
- }
- // Pad with debug-breakpoint instructions up to alignBytes or the end of the current page, whichever is less.
- if (alignPad != 0)
- {
- DWORD alignBytes = alignPad < spaceInCurrentPage ? alignPad : spaceInCurrentPage;
- CustomHeap::FillDebugBreak(currentDestBuffer, alignBytes);
- alignPad -= alignBytes;
- currentDestBuffer += alignBytes;
- allocation->bytesUsed += alignBytes;
- bytesLeft -= alignBytes;
- bytesToChange -= alignBytes;
- #if DBG_DUMP
- this->totalBytesAlignment += alignBytes;
- #endif
- }
- // If there are bytes still left to be copied then we should do the copy, but only through the end of the current page.
- if(bytesToChange > 0)
- {
- AssertMsg(alignPad == 0, "If we are copying right now - we should be done with setting alignment.");
- const DWORD bufferBytesFree(allocation->BytesFree());
- // Use <= here instead of < to allow this memcopy to fill up the rest of destBuffer. If we do, then FinalizeAllocation,
- // called below, determines that no additional padding is necessary based on the values in `allocation'.
- AnalysisAssert(currentDestBuffer + bufferBytesFree <= destBuffer + destBufferBytes);
- memcpy_s(currentDestBuffer, bufferBytesFree, sourceBuffer, bytesToChange);
- currentDestBuffer += bytesToChange;
- sourceBuffer += bytesToChange;
- allocation->bytesUsed += bytesToChange;
- bytesLeft -= bytesToChange;
- }
- Assert(readWriteBuffer + readWriteBytes == currentDestBuffer);
- if (!JITManager::GetJITManager()->IsJITServer() && !this->allocationHeap.ProtectAllocationWithExecuteReadOnly(allocation->allocation, (char*)readWriteBuffer))
- {
- return false;
- }
- }
- if (!FlushInstructionCache(this->processHandle, bufferToFlush, sizeToFlush))
- {
- return false;
- }
- #if DBG_DUMP
- this->totalBytesCode += bytes;
- #endif
- //Finish the current EmitBufferAllocation by filling out the rest of destBuffer with debug breakpoint instructions.
- return FinalizeAllocation(allocation, destBuffer);
- }
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- void
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CompletePreviousAllocation(TEmitBufferAllocation* allocation)
- {
- AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
- if (allocation != nullptr)
- {
- allocation->bytesUsed = allocation->bytesCommitted;
- }
- }
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- void
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CheckBufferPermissions(TEmitBufferAllocation *allocation)
- {
- AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);
- if(allocation->bytesCommitted == 0)
- return;
- MEMORY_BASIC_INFORMATION memInfo;
- BYTE *buffer = (BYTE*) allocation->allocation->address;
- SIZE_T size = allocation->bytesCommitted;
- while(1)
- {
- SIZE_T result = VirtualQuery(buffer, &memInfo, sizeof(memInfo));
- if(result == 0)
- {
- // VirtualQuery failed. This is not an expected condition, but it would be benign for the purposes of this check. Seems
- // to occur occasionally on process shutdown.
- break;
- }
- else if(memInfo.Protect == PAGE_EXECUTE_READWRITE)
- {
- Output::Print(_u("ERROR: Found PAGE_EXECUTE_READWRITE page!\n"));
- #ifdef DEBUG
- AssertMsg(FALSE, "Page was marked PAGE_EXECUTE_READWRITE");
- #else
- Fatal();
- #endif
- }
- // Figure out if we need to continue the query. The returned size might be larger than the size we requested,
- // for instance if more pages were allocated directly afterward, with the same permissions.
- if(memInfo.RegionSize >= size)
- {
- break;
- }
- // recalculate size for next iteration
- buffer += memInfo.RegionSize;
- size -= memInfo.RegionSize;
- if(size <= 0)
- {
- AssertMsg(FALSE, "Last VirtualQuery left us with unmatched regions");
- break;
- }
- }
- }
- #endif
- #if DBG_DUMP
- template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
- void
- EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::DumpAndResetStats(char16 const * filename)
- {
- if (this->totalBytesCommitted != 0)
- {
- size_t wasted = this->totalBytesCommitted - this->totalBytesCode - this->totalBytesAlignment;
- Output::Print(_u("Stats for %s: %s \n"), name, filename);
- Output::Print(_u(" Total code size : %10d (%6.2f%% of committed)\n"), this->totalBytesCode,
- (float)this->totalBytesCode * 100 / this->totalBytesCommitted);
- Output::Print(_u(" Total LoopBody code : %10d\n"), this->totalBytesLoopBody);
- Output::Print(_u(" Total alignment size : %10d (%6.2f%% of committed)\n"), this->totalBytesAlignment,
- (float)this->totalBytesAlignment * 100 / this->totalBytesCommitted);
- Output::Print(_u(" Total wasted size : %10d (%6.2f%% of committed)\n"), wasted,
- (float)wasted * 100 / this->totalBytesCommitted);
- Output::Print(_u(" Total committed size : %10d (%6.2f%% of reserved)\n"), this->totalBytesCommitted,
- (float)this->totalBytesCommitted * 100 / this->totalBytesReserved);
- Output::Print(_u(" Total reserved size : %10d\n"), this->totalBytesReserved);
- }
- this->totalBytesCode = 0;
- this->totalBytesLoopBody = 0;
- this->totalBytesAlignment = 0;
- this->totalBytesCommitted = 0;
- this->totalBytesReserved = 0;
- }
- #endif
- template class EmitBufferManager<VirtualAllocWrapper, PreReservedVirtualAllocWrapper, FakeCriticalSection>;
- template class EmitBufferManager<VirtualAllocWrapper, PreReservedVirtualAllocWrapper, CriticalSection>;
- #if ENABLE_OOP_NATIVE_CODEGEN
- template class EmitBufferManager<SectionAllocWrapper, PreReservedSectionAllocWrapper, FakeCriticalSection>;
- template class EmitBufferManager<SectionAllocWrapper, PreReservedSectionAllocWrapper, CriticalSection>;
- #endif
|