//------------------------------------------------------------------------------------------------------- // 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" #include "NativeEntryPointData.h" #include "JitTransferData.h" JITOutput::JITOutput(JITOutputIDL * outputData) : m_outputData(outputData), m_inProcAlloc(nullptr), m_func(nullptr) { } void JITOutput::SetHasJITStackClosure() { m_outputData->hasJittedStackClosure = true; } void JITOutput::SetVarSlotsOffset(int32 offset) { m_outputData->localVarSlotsOffset = offset; } void JITOutput::SetVarChangedOffset(int32 offset) { m_outputData->localVarChangedOffset = offset; } void JITOutput::SetHasBailoutInstr(bool val) { m_outputData->hasBailoutInstr = val; } void JITOutput::SetArgUsedForBranch(uint8 param) { Assert(param > 0); Assert(param < Js::Constants::MaximumArgumentCountForConstantArgumentInlining); m_outputData->argUsedForBranch |= (1 << (param - 1)); } void JITOutput::SetFrameHeight(uint val) { m_outputData->frameHeight = val; } void JITOutput::RecordThrowMap(Js::ThrowMapEntry * throwMap, uint mapCount) { m_outputData->throwMapOffset = NativeCodeData::GetDataTotalOffset(throwMap); m_outputData->throwMapCount = mapCount; } bool JITOutput::IsTrackCompoundedIntOverflowDisabled() const { return m_outputData->disableTrackCompoundedIntOverflow != FALSE; } bool JITOutput::IsArrayCheckHoistDisabled() const { return m_outputData->disableArrayCheckHoist != FALSE; } bool JITOutput::IsStackArgOptDisabled() const { return m_outputData->disableStackArgOpt != FALSE; } bool JITOutput::IsSwitchOptDisabled() const { return m_outputData->disableSwitchOpt != FALSE; } bool JITOutput::IsAggressiveIntTypeSpecDisabled() const { return m_outputData->disableAggressiveIntTypeSpec != FALSE; } uint16 JITOutput::GetArgUsedForBranch() const { return m_outputData->argUsedForBranch; } intptr_t JITOutput::GetCodeAddress() const { return (intptr_t)m_outputData->codeAddress; } void JITOutput::SetCodeAddress(intptr_t addr) { m_outputData->codeAddress = addr; } size_t JITOutput::GetCodeSize() const { return (size_t)m_outputData->codeSize; } ushort JITOutput::GetPdataCount() const { return m_outputData->pdataCount; } ushort JITOutput::GetXdataSize() const { return m_outputData->xdataSize; } EmitBufferAllocation * JITOutput::RecordInProcNativeCodeSize(Func *func, uint32 bytes, ushort pdataCount, ushort xdataSize) { m_func = func; #if defined(_M_ARM32_OR_ARM64) bool canAllocInPreReservedHeapPageSegment = false; #else bool canAllocInPreReservedHeapPageSegment = m_func->CanAllocInPreReservedHeapPageSegment(); #endif BYTE *buffer = nullptr; m_inProcAlloc = m_func->GetInProcCodeGenAllocators()->emitBufferManager.AllocateBuffer(bytes, &buffer, pdataCount, xdataSize, canAllocInPreReservedHeapPageSegment, true); if (buffer == nullptr) { Js::Throw::OutOfMemory(); } m_outputData->codeAddress = (intptr_t)buffer; m_outputData->codeSize = bytes; m_outputData->pdataCount = pdataCount; m_outputData->xdataSize = xdataSize; m_outputData->isInPrereservedRegion = m_inProcAlloc->inPrereservedRegion; return m_inProcAlloc; } #if ENABLE_OOP_NATIVE_CODEGEN EmitBufferAllocation * JITOutput::RecordOOPNativeCodeSize(Func *func, uint32 bytes, ushort pdataCount, ushort xdataSize) { m_func = func; #if defined(_M_ARM32_OR_ARM64) bool canAllocInPreReservedHeapPageSegment = false; #else bool canAllocInPreReservedHeapPageSegment = m_func->CanAllocInPreReservedHeapPageSegment(); #endif BYTE *buffer = nullptr; m_oopAlloc = m_func->GetOOPCodeGenAllocators()->emitBufferManager.AllocateBuffer(bytes, &buffer, pdataCount, xdataSize, canAllocInPreReservedHeapPageSegment, true); if (buffer == nullptr) { Js::Throw::OutOfMemory(); } m_outputData->codeAddress = (intptr_t)buffer; m_outputData->codeSize = bytes; m_outputData->pdataCount = pdataCount; m_outputData->xdataSize = xdataSize; m_outputData->isInPrereservedRegion = m_oopAlloc->inPrereservedRegion; return m_oopAlloc; } #endif void JITOutput::RecordNativeCode(const BYTE* sourceBuffer, BYTE* localCodeAddress) { #if ENABLE_OOP_NATIVE_CODEGEN if (JITManager::GetJITManager()->IsJITServer()) { RecordNativeCode(sourceBuffer, localCodeAddress, m_oopAlloc, m_func->GetOOPCodeGenAllocators()); } else #endif { RecordNativeCode(sourceBuffer, localCodeAddress, m_inProcAlloc, m_func->GetInProcCodeGenAllocators()); } } template void JITOutput::RecordNativeCode(const BYTE* sourceBuffer, BYTE* localCodeAddress, TEmitBufferAllocation allocation, TCodeGenAllocators codeGenAllocators) { Assert(m_outputData->codeAddress == (intptr_t)allocation->allocation->address); if (!codeGenAllocators->emitBufferManager.CommitBuffer(allocation, allocation->bytesCommitted, localCodeAddress, m_outputData->codeSize, sourceBuffer)) { Js::Throw::OutOfMemory(); } #if DBG_DUMP if (m_func->IsLoopBody()) { codeGenAllocators->emitBufferManager.totalBytesLoopBody += m_outputData->codeSize; } #endif } void JITOutput::RecordInlineeFrameOffsetsInfo(unsigned int offsetsArrayOffset, unsigned int offsetsArrayCount) { m_outputData->inlineeFrameOffsetArrayOffset = offsetsArrayOffset; m_outputData->inlineeFrameOffsetArrayCount = offsetsArrayCount; } #if TARGET_64 void JITOutput::RecordUnwindInfo(BYTE *unwindInfo, size_t size, BYTE * xdataAddr, BYTE* localXdataAddr) { Assert(XDATA_SIZE >= size); memcpy_s(localXdataAddr, XDATA_SIZE, unwindInfo, size); m_outputData->xdataAddr = (intptr_t)xdataAddr; } #elif _M_ARM size_t JITOutput::RecordUnwindInfo(size_t offset, const BYTE *unwindInfo, size_t size, BYTE * xdataAddr) { BYTE *xdataFinal = xdataAddr + offset; Assert(xdataFinal); Assert(((ULONG_PTR)xdataFinal & 0x3) == 0); // 4 byte aligned memcpy_s(xdataFinal, size, unwindInfo, size); return (size_t)xdataFinal; } void JITOutput::RecordXData(BYTE * xdata) { m_outputData->xdataOffset = NativeCodeData::GetDataTotalOffset(xdata); } #endif void JITOutput::FinalizeNativeCode() { CustomHeap::Allocation * allocation = GetAllocation(); #if ENABLE_OOP_NATIVE_CODEGEN if (JITManager::GetJITManager()->IsJITServer()) { m_func->GetOOPCodeGenAllocators()->emitBufferManager.CompletePreviousAllocation(m_oopAlloc); #if defined(_CONTROL_FLOW_GUARD) && !defined(_M_ARM) if (!m_func->IsLoopBody() && CONFIG_FLAG(UseJITTrampoline)) { allocation->thunkAddress = m_func->GetOOPThreadContext()->GetJITThunkEmitter()->CreateThunk(m_outputData->codeAddress); } #endif } else #endif { m_func->GetInProcCodeGenAllocators()->emitBufferManager.CompletePreviousAllocation(m_inProcAlloc); m_func->GetInProcJITEntryPointInfo()->GetInProcNativeEntryPointData()->SetNativeCodeData(m_func->GetNativeCodeDataAllocator()->Finalize()); m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->SetRawData(m_func->GetTransferDataAllocator()->Finalize()); #if !FLOATVAR CodeGenNumberChunk * numberChunks = m_func->GetNumberAllocator()->Finalize(); m_func->GetInProcJITEntryPointInfo()->GetInProcNativeEntryPointData()->SetNumberChunks(numberChunks); #endif #if defined(_CONTROL_FLOW_GUARD) && !defined(_M_ARM) if (!m_func->IsLoopBody() && CONFIG_FLAG(UseJITTrampoline)) { allocation->thunkAddress = m_func->GetInProcThreadContext()->GetJITThunkEmitter()->CreateThunk(m_outputData->codeAddress); } #endif } m_outputData->thunkAddress = allocation->thunkAddress; if (!allocation->thunkAddress && CONFIG_FLAG(OOPCFGRegistration)) { PVOID callTarget = (PVOID)m_outputData->codeAddress; #if ENABLE_OOP_NATIVE_CODEGEN if (JITManager::GetJITManager()->IsJITServer()) { m_func->GetOOPCodeGenAllocators()->emitBufferManager.SetValidCallTarget(m_oopAlloc, callTarget, true); } else #endif { m_func->GetInProcCodeGenAllocators()->emitBufferManager.SetValidCallTarget(m_inProcAlloc, callTarget, true); } } } CustomHeap::Allocation * JITOutput::GetAllocation() const { #if ENABLE_OOP_NATIVE_CODEGEN if (JITManager::GetJITManager()->IsJITServer()) { return m_oopAlloc->allocation; } #endif return m_inProcAlloc->allocation; } JITOutputIDL * JITOutput::GetOutputData() { return m_outputData; }