blob: a164542a7ad181becac8342b8ebbc3e83a1319aa [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeBasePch.h"
#if ENABLE_NATIVE_CODEGEN
#include "CodeGenAllocators.h"
#include "ServerThreadContext.h"
#endif
ThreadContextInfo::ThreadContextInfo() :
m_isAllJITCodeInPreReservedRegion(true),
m_isClosed(false)
{
for (int i = 0; i <= WellKnownHostType_Last; ++i)
{
wellKnownHostTypeIds[i] = Js::TypeIds_Undefined;
}
}
#if ENABLE_NATIVE_CODEGEN
intptr_t
ThreadContextInfo::GetNullFrameDisplayAddr() const
{
return SHIFT_ADDR(this, &Js::NullFrameDisplay);
}
intptr_t
ThreadContextInfo::GetStrictNullFrameDisplayAddr() const
{
return SHIFT_ADDR(this, &Js::StrictNullFrameDisplay);
}
intptr_t
ThreadContextInfo::GetAbsDoubleCstAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::AbsDoubleCst);
}
intptr_t
ThreadContextInfo::GetAbsFloatCstAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::AbsFloatCst);
}
intptr_t ThreadContextInfo::GetSgnFloatBitCst() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::SgnFloatBitCst);
}
intptr_t ThreadContextInfo::GetSgnDoubleBitCst() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::SgnDoubleBitCst);
}
intptr_t
ThreadContextInfo::GetMaskNegFloatAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::MaskNegFloat);
}
intptr_t
ThreadContextInfo::GetMaskNegDoubleAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::MaskNegDouble);
}
intptr_t
ThreadContextInfo::GetUIntConvertConstAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::UIntConvertConst);
}
intptr_t
ThreadContextInfo::GetUInt64ConvertConstAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::UInt64ConvertConst);
}
intptr_t
ThreadContextInfo::GetUint8ClampedArraySetItemAddr() const
{
return SHIFT_ADDR(this, (BOOL(*)(Js::Uint8ClampedArray * arr, uint32 index, Js::Var value))&Js::Uint8ClampedArray::DirectSetItem);
}
intptr_t
ThreadContextInfo::GetConstructorCacheDefaultInstanceAddr() const
{
return SHIFT_ADDR(this, &Js::ConstructorCache::DefaultInstance);
}
intptr_t
ThreadContextInfo::GetJavascriptObjectNewInstanceAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptObject::EntryInfo::NewInstance);
}
intptr_t
ThreadContextInfo::GetJavascriptArrayNewInstanceAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptArray::EntryInfo::NewInstance);
}
intptr_t
ThreadContextInfo::GetDoubleOnePointZeroAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::ONE_POINT_ZERO);
}
intptr_t
ThreadContextInfo::GetDoublePointFiveAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_PointFive);
}
intptr_t
ThreadContextInfo::GetFloatPointFiveAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Float32PointFive);
}
intptr_t
ThreadContextInfo::GetDoubleNegPointFiveAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_NegPointFive);
}
intptr_t
ThreadContextInfo::GetFloatNegPointFiveAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Float32NegPointFive);
}
intptr_t
ThreadContextInfo::GetDoubleNegOneAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_NegOne);
}
intptr_t
ThreadContextInfo::GetDoubleTwoToFractionAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_TwoToFraction);
}
intptr_t
ThreadContextInfo::GetFloatTwoToFractionAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Float32TwoToFraction);
}
intptr_t
ThreadContextInfo::GetDoubleNegTwoToFractionAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_NegTwoToFraction);
}
intptr_t
ThreadContextInfo::GetDoubleNaNAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Nan);
}
intptr_t
ThreadContextInfo::GetDoubleUintMaxPlusOneAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_UintMaxPlusOne);
}
intptr_t
ThreadContextInfo::GetDoubleIntMaxPlusOneAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_IntMaxPlusOne);
}
intptr_t
ThreadContextInfo::GetDoubleIntMinMinusOneAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_MinIntMinusOne);
}
intptr_t
ThreadContextInfo::GetFloatNaNAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Nan32);
}
intptr_t
ThreadContextInfo::GetFloatNegTwoToFractionAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Float32NegTwoToFraction);
}
intptr_t
ThreadContextInfo::GetDoubleZeroAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Zero);
}
intptr_t
ThreadContextInfo::GetFloatZeroAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Float32Zero);
}
intptr_t
ThreadContextInfo::GetNativeFloatArrayMissingItemAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNativeFloatArray::MissingItem);
}
intptr_t
ThreadContextInfo::GetExponentMaskAddr() const
{
return SHIFT_ADDR(this, &Js::Constants::ExponentMask);
}
intptr_t
ThreadContextInfo::GetMantissaMaskAddr() const
{
return SHIFT_ADDR(this, &Js::Constants::MantissaMask);
}
#if _M_IX86 || _M_AMD64
intptr_t
ThreadContextInfo::GetX86AbsMaskF4Addr() const
{
return SHIFT_ADDR(this, &X86_ABS_MASK_F4);
}
intptr_t
ThreadContextInfo::GetX86AbsMaskD2Addr() const
{
return SHIFT_ADDR(this, &X86_ABS_MASK_D2);
}
intptr_t
ThreadContextInfo::GetX86NegMaskF4Addr() const
{
return SHIFT_ADDR(this, &X86_NEG_MASK_F4);
}
intptr_t
ThreadContextInfo::GetX86NegMaskD2Addr() const
{
return SHIFT_ADDR(this, &X86_NEG_MASK_D2);
}
intptr_t
ThreadContextInfo::GetX86AllNegOnesAddr() const
{
return SHIFT_ADDR(this, &X86_ALL_NEG_ONES);
}
intptr_t
ThreadContextInfo::GetX86AllNegOnesF4Addr() const
{
return SHIFT_ADDR(this, &X86_ALL_NEG_ONES_F4);
}
intptr_t
ThreadContextInfo::GetX86AllZerosAddr() const
{
return SHIFT_ADDR(this, &X86_ALL_ZEROS);
}
intptr_t
ThreadContextInfo::GetX86AllOnesF4Addr() const
{
return SHIFT_ADDR(this, &X86_ALL_ONES_F4);
}
intptr_t
ThreadContextInfo::GetX86LowBytesMaskAddr() const
{
return SHIFT_ADDR(this, &X86_LOWBYTES_MASK);
}
intptr_t
ThreadContextInfo::GetX86HighBytesMaskAddr() const
{
return SHIFT_ADDR(this, &X86_HIGHBYTES_MASK);
}
intptr_t
ThreadContextInfo::GetX86DoubleWordSignBitsAddr() const
{
return SHIFT_ADDR(this, &X86_DWORD_SIGNBITS);
}
intptr_t
ThreadContextInfo::GetX86WordSignBitsAddr() const
{
return SHIFT_ADDR(this, &X86_WORD_SIGNBITS);
}
intptr_t
ThreadContextInfo::GetX86ByteSignBitsAddr() const
{
return SHIFT_ADDR(this, &X86_BYTE_SIGNBITS);
}
intptr_t
ThreadContextInfo::GetX86TwoPower32F4Addr() const
{
return SHIFT_ADDR(this, &X86_TWO_32_F4);
}
intptr_t
ThreadContextInfo::GetX86TwoPower31F4Addr() const
{
return SHIFT_ADDR(this, &X86_TWO_31_F4);
}
intptr_t
ThreadContextInfo::GetX86TwoPower31I4Addr() const
{
return SHIFT_ADDR(this, &X86_TWO_31_I4);
}
intptr_t
ThreadContextInfo::GetX86NegTwoPower31F4Addr() const
{
return SHIFT_ADDR(this, &X86_NEG_TWO_31_F4);
}
intptr_t
ThreadContextInfo::GetX86FourLanesMaskAddr(uint8 minorityLane) const
{
return SHIFT_ADDR(this, &X86_4LANES_MASKS[minorityLane]);
}
intptr_t
ThreadContextInfo::GetDoubleIntMinAddr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::DOUBLE_INT_MIN);
}
intptr_t
ThreadContextInfo::GetDoubleTwoTo31Addr() const
{
return SHIFT_ADDR(this, &Js::JavascriptNumber::DOUBLE_TWO_TO_31);
}
#endif
intptr_t
ThreadContextInfo::GetStringReplaceNameAddr() const
{
return SHIFT_ADDR(this, Js::Constants::StringReplace);
}
intptr_t
ThreadContextInfo::GetStringMatchNameAddr() const
{
return SHIFT_ADDR(this, Js::Constants::StringMatch);
}
#endif
bool
ThreadContextInfo::IsAllJITCodeInPreReservedRegion() const
{
return m_isAllJITCodeInPreReservedRegion;
}
void
ThreadContextInfo::ResetIsAllJITCodeInPreReservedRegion()
{
m_isAllJITCodeInPreReservedRegion = false;
}
#ifdef ENABLE_GLOBALIZATION
#if defined(_CONTROL_FLOW_GUARD)
Js::DelayLoadWinCoreProcessThreads *
ThreadContextInfo::GetWinCoreProcessThreads()
{
m_delayLoadWinCoreProcessThreads.EnsureFromSystemDirOnly();
return &m_delayLoadWinCoreProcessThreads;
}
Js::DelayLoadWinCoreMemory *
ThreadContextInfo::GetWinCoreMemoryLibrary()
{
m_delayLoadWinCoreMemoryLibrary.EnsureFromSystemDirOnly();
return &m_delayLoadWinCoreMemoryLibrary;
}
#endif
bool
ThreadContextInfo::IsCFGEnabled()
{
#if defined(_CONTROL_FLOW_GUARD)
PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY CfgPolicy;
m_delayLoadWinCoreProcessThreads.EnsureFromSystemDirOnly();
BOOL isGetMitigationPolicySucceeded = m_delayLoadWinCoreProcessThreads.GetMitigationPolicyForProcess(
this->GetProcessHandle(),
ProcessControlFlowGuardPolicy,
&CfgPolicy,
sizeof(CfgPolicy));
Assert(isGetMitigationPolicySucceeded || !AutoSystemInfo::Data.IsCFGEnabled());
return CfgPolicy.EnableControlFlowGuard && AutoSystemInfo::Data.IsCFGEnabled();
#else
return false;
#endif // _CONTROL_FLOW_GUARD
}
#endif // ENABLE_GLOBALIZATION
//Masking bits according to AutoSystemInfo::PageSize
#define PAGE_START_ADDR(address) ((size_t)(address) & ~(size_t)(AutoSystemInfo::PageSize - 1))
#define IS_16BYTE_ALIGNED(address) (((size_t)(address) & 0xF) == 0)
#define OFFSET_ADDR_WITHIN_PAGE(address) ((size_t)(address) & (AutoSystemInfo::PageSize - 1))
void
ThreadContextInfo::SetValidCallTargetForCFG(PVOID callTargetAddress, bool isSetValid)
{
#ifdef _CONTROL_FLOW_GUARD
if (IsCFGEnabled())
{
AssertMsg(IS_16BYTE_ALIGNED(callTargetAddress), "callTargetAddress is not 16-byte page aligned?");
// If SetProcessValidCallTargets is not allowed by global policy (e.g.
// OOP JIT is in use in the client), then generate a fast fail
// exception as state has been corrupted and attempt is being made to
// illegally call SetProcessValidCallTargets.
if (!GlobalSecurityPolicy::IsSetProcessValidCallTargetsAllowed())
{
RaiseFailFastException(nullptr, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
}
PVOID startAddressOfPage = (PVOID)(PAGE_START_ADDR(callTargetAddress));
size_t codeOffset = OFFSET_ADDR_WITHIN_PAGE(callTargetAddress);
CFG_CALL_TARGET_INFO callTargetInfo[1];
callTargetInfo[0].Offset = codeOffset;
callTargetInfo[0].Flags = (isSetValid ? CFG_CALL_TARGET_VALID : 0);
AssertMsg((size_t)callTargetAddress - (size_t)startAddressOfPage <= AutoSystemInfo::PageSize - 1, "Only last bits corresponding to PageSize should be masked");
AssertMsg((size_t)startAddressOfPage + (size_t)codeOffset == (size_t)callTargetAddress, "Wrong masking of address?");
BOOL isCallTargetRegistrationSucceed = GetWinCoreMemoryLibrary()->SetProcessCallTargets(GetProcessHandle(), startAddressOfPage, AutoSystemInfo::PageSize, 1, callTargetInfo);
if (!isCallTargetRegistrationSucceed)
{
if (GetLastError() == ERROR_COMMITMENT_LIMIT)
{
//Throw OOM, if there is not enough virtual memory for paging (required for CFG BitMap)
Js::Throw::OutOfMemory();
}
else
{
Js::Throw::InternalError();
}
}
#if DBG
if (isSetValid && !JITManager::GetJITManager()->IsOOPJITEnabled())
{
_guard_check_icall((uintptr_t)callTargetAddress);
}
if (PHASE_TRACE1(Js::CFGPhase))
{
if (!isSetValid)
{
Output::Print(_u("DEREGISTER:"));
}
Output::Print(_u("CFGRegistration: StartAddr: 0x%p , Offset: 0x%x, TargetAddr: 0x%x \n"), (char*)startAddressOfPage, callTargetInfo[0].Offset, ((size_t)startAddressOfPage + (size_t)callTargetInfo[0].Offset));
Output::Flush();
}
#endif
}
#endif // _CONTROL_FLOW_GUARD
}
bool
ThreadContextInfo::IsClosed()
{
return m_isClosed;
}
intptr_t SHIFT_ADDR(const ThreadContextInfo*const context, intptr_t address)
{
#if ENABLE_OOP_NATIVE_CODEGEN
Assert(AutoSystemInfo::Data.IsJscriptModulePointer((void*)address));
ptrdiff_t diff = 0;
if (JITManager::GetJITManager()->IsJITServer())
{
diff = ((ServerThreadContext*)context)->GetChakraBaseAddressDifference();
}
else
{
diff = ((ThreadContext*)context)->GetChakraBaseAddressDifference();
}
return (intptr_t)address + diff;
#else
return address;
#endif
}
intptr_t SHIFT_CRT_ADDR(const ThreadContextInfo*const context, intptr_t address)
{
#if ENABLE_OOP_NATIVE_CODEGEN
if (AutoSystemInfo::Data.IsJscriptModulePointer((void*)address))
{
// the function is compiled to chakra.dll, or statically linked to crt
return SHIFT_ADDR(context, address);
}
ptrdiff_t diff = 0;
if (JITManager::GetJITManager()->IsJITServer())
{
diff = ((ServerThreadContext*)context)->GetCRTBaseAddressDifference();
}
else
{
diff = ((ThreadContext*)context)->GetCRTBaseAddressDifference();
}
return (intptr_t)address + diff;
#else
return address;
#endif
}