Sfoglia il codice sorgente

fix helper call addresses

Michael Holman 9 anni fa
parent
commit
e4b5d779b7

+ 1 - 1
lib/Backend/GlobOpt.cpp

@@ -6102,7 +6102,7 @@ GlobOpt::CopyProp(IR::Opnd *opnd, IR::Instr *instr, Value *val, IR::IndirOpnd *p
             }
             IR::IntConstOpnd *intOpnd = IR::IntConstOpnd::New(constVal, opndType, instr->m_func);
 
-            GOPT_TRACE_OPND(opnd, L"Constant prop %d (value:%d)\n", intOpnd->GetImmediateValue(), intConstantValue);
+            GOPT_TRACE_OPND(opnd, L"Constant prop %d (value:%d)\n", intOpnd->GetImmediateValue(instr->m_func), intConstantValue);
             constOpnd = intOpnd;
         }
 

+ 87 - 86
lib/Backend/JnHelperMethod.cpp

@@ -18,9 +18,9 @@
 namespace IR
 {
 
-const void * const JnHelperMethodAddresses[] =
+intptr_t const JnHelperMethodAddresses[] =
 {
-#define HELPERCALL(Name, Address, Attributes) static_cast<void *>(Address),
+#define HELPERCALL(Name, Address, Attributes) reinterpret_cast<intptr_t>(Address),
 // Because of order-of-initialization problems with the vtable address static field
 // and this array, we're going to have to fill these in as we go along.
 #include "JnHelperMethodList.h"
@@ -30,10 +30,10 @@ const void * const JnHelperMethodAddresses[] =
 };
 
 #if defined(_M_IX86)
-const void * const JnHelperMethodAddresses_SSE2[] =
+intptr_t const JnHelperMethodAddresses_SSE2[] =
 {
 #define SSE2MATH
-#define HELPERCALL(Name, Address, Attributes) static_cast<void *>(Address),
+#define HELPERCALL(Name, Address, Attributes) static_cast<intptr_t>(Address),
 // Because of order-of-initialization problems with the vtable address static field
 // and this array, we're going to have to fill these in as we go along.
 #include "JnHelperMethodList.h"
@@ -42,7 +42,7 @@ const void * const JnHelperMethodAddresses_SSE2[] =
     NULL
 };
 
-const void * const*GetHelperMethods()
+intptr_t const *GetHelperMethods()
 {
     if (AutoSystemInfo::Data.SSE2Available())
     {
@@ -52,7 +52,7 @@ const void * const*GetHelperMethods()
 }
 #else
 
-const void *const*GetHelperMethods()
+intptr_t const *GetHelperMethods()
 {
     return JnHelperMethodAddresses;
 }
@@ -73,7 +73,7 @@ public:
 // Dummy global to trigger CheckJnHelperTable call at load time.
 static HelperTableCheck LoadTimeHelperTableCheck;
 
-void CheckJnHelperTable(const void * const *table)
+void CheckJnHelperTable(intptr_t const* table)
 {
     MEMORY_BASIC_INFORMATION memBuffer;
 
@@ -93,25 +93,24 @@ void CheckJnHelperTable(const void * const *table)
 }
 #endif
 
-
-static void const* const helperMethodWrappers[] = {
-    &Js::HelperMethodWrapper0,
-    &Js::HelperMethodWrapper1,
-    &Js::HelperMethodWrapper2,
-    &Js::HelperMethodWrapper3,
-    &Js::HelperMethodWrapper4,
-    &Js::HelperMethodWrapper5,
-    &Js::HelperMethodWrapper6,
-    &Js::HelperMethodWrapper7,
-    &Js::HelperMethodWrapper8,
-    &Js::HelperMethodWrapper9,
-    &Js::HelperMethodWrapper10,
-    &Js::HelperMethodWrapper11,
-    &Js::HelperMethodWrapper12,
-    &Js::HelperMethodWrapper13,
-    &Js::HelperMethodWrapper14,
-    &Js::HelperMethodWrapper15,
-    &Js::HelperMethodWrapper16,
+static intptr_t const helperMethodWrappers[] = {
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper0),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper1),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper2),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper3),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper4),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper5),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper6),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper7),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper8),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper9),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper10),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper11),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper12),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper13),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper14),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper15),
+    reinterpret_cast<intptr_t>(&Js::HelperMethodWrapper16),
 };
 
 ///----------------------------------------------------------------------------
@@ -122,8 +121,8 @@ static void const* const helperMethodWrappers[] = {
 ///     which can the address of debugger wrapper that intercept the original helper.
 ///
 ///----------------------------------------------------------------------------
-void const*
-GetMethodAddress(IR::HelperCallOpnd* opnd)
+intptr_t
+GetMethodAddress(ThreadContextInfo * context, IR::HelperCallOpnd* opnd)
 {
     Assert(opnd);
 
@@ -142,7 +141,7 @@ GetMethodAddress(IR::HelperCallOpnd* opnd)
 
         if (0 <= diagOpnd->m_argCount && diagOpnd->m_argCount <= LowererMDFinal::MaxArgumentsToHelper)
         {
-            return helperMethodWrappers[diagOpnd->m_argCount];
+            return SHIFT_ADDR(context, helperMethodWrappers[diagOpnd->m_argCount]);
         }
         else
         {
@@ -150,7 +149,7 @@ GetMethodAddress(IR::HelperCallOpnd* opnd)
         }
     }
 
-    return GetMethodOriginalAddress(opnd->m_fnHelper);
+    return GetMethodOriginalAddress(context, opnd->m_fnHelper);
 }
 
 // TODO:  Remove this define once makes it into WINNT.h
@@ -166,7 +165,7 @@ GetMethodAddress(IR::HelperCallOpnd* opnd)
 // Import function ptr require dynamic initialization, and cause the table to be in read-write memory.
 // Additionally, all function ptrs are automatically marked as safe CFG addresses by the compiler.
 // __declspec(guard(ignore)) can be used on methods to have the compiler not mark these as valid CFG targets.
-DECLSPEC_GUARDIGNORE __declspec(noinline) void * const GetNonTableMethodAddress(JnHelperMethod helperMethod)
+DECLSPEC_GUARDIGNORE __declspec(noinline) intptr_t GetNonTableMethodAddress(ThreadContextInfo * context, JnHelperMethod helperMethod)
 {
     switch (helperMethod)
     {
@@ -174,147 +173,148 @@ DECLSPEC_GUARDIGNORE __declspec(noinline) void * const GetNonTableMethodAddress(
     //  DllImport methods
     //
 #if defined(_M_IX86)
-
+        // TODO: OOP JIT, have some way to validate that these are all loaded from CRT
     case HelperDirectMath_Acos:
-        return (double(*)(double))__libm_sse2_acos;
+        return SHIFT_CRT_ADDR(context, (double(*)(double))__libm_sse2_acos);
 
     case HelperDirectMath_Asin:
-        return (double(*)(double))__libm_sse2_asin;
+        return SHIFT_CRT_ADDR(context, (double(*)(double))__libm_sse2_asin);
 
     case HelperDirectMath_Atan:
-        return (double(*)(double))__libm_sse2_atan;
+        return SHIFT_CRT_ADDR(context, (double(*)(double))__libm_sse2_atan);
 
     case HelperDirectMath_Atan2:
-        return (double(*)(double, double))__libm_sse2_atan2;
+        return SHIFT_CRT_ADDR(context, (double(*)(double, double))__libm_sse2_atan2);
 
     case HelperDirectMath_Cos:
-        return (double(*)(double))__libm_sse2_cos;
+        return SHIFT_CRT_ADDR(context, (double(*)(double))__libm_sse2_cos);
 
     case HelperDirectMath_Exp:
-        return (double(*)(double))__libm_sse2_exp;
+        return SHIFT_CRT_ADDR(context, (double(*)(double))__libm_sse2_exp);
 
     case HelperDirectMath_Log:
-        return (double(*)(double))__libm_sse2_log;
+        return SHIFT_CRT_ADDR(context, (double(*)(double))__libm_sse2_log);
 
     case HelperDirectMath_Sin:
-        return (double(*)(double))__libm_sse2_sin;
+        return SHIFT_CRT_ADDR(context, (double(*)(double))__libm_sse2_sin);
 
     case HelperDirectMath_Tan:
-        return (double(*)(double))__libm_sse2_tan;
-#endif
-
-#ifdef _CONTROL_FLOW_GUARD
-    case HelperGuardCheckCall:
-        return __guard_check_icall_fptr;
+        return SHIFT_CRT_ADDR(context, (double(*)(double))__libm_sse2_tan);
 #endif
 
     case HelperDirectMath_FloorDb:
-        return (double(*)(double))floor;
-
-    case HelperDirectMath_FloorFlt:
-        return (float(*)(float))floor;
+        return SHIFT_CRT_ADDR(context, (double(*)(double))floor);
 
     case HelperDirectMath_CeilDb:
-        return (double(*)(double))ceil;
-
-    case HelperDirectMath_CeilFlt:
-        return (float(*)(float))ceil;
+        return SHIFT_CRT_ADDR(context, (double(*)(double))ceil);
 
     //
     // These are statically initialized to an import thunk, but let's keep them out of the table in case a new CRT changes this
     //
     case HelperMemCmp:
-        return (int(*)(void *, void *, size_t))memcmp;
+        return SHIFT_ADDR(context, (int(*)(void *, void *, size_t))memcmp);
 
     case HelperMemCpy:
-        return (int(*)(void *, void *, size_t))memcpy;
+        return SHIFT_ADDR(context, (int(*)(void *, void *, size_t))memcpy);
+
+    case HelperDirectMath_FloorFlt:
+        return SHIFT_ADDR(context, (float(*)(float))floor);
+
+    case HelperDirectMath_CeilFlt:
+        return SHIFT_ADDR(context, (float(*)(float))ceil);
 
 #if defined(_M_X64)
     case HelperDirectMath_Acos:
-        return (double(*)(double))acos;
+        return SHIFT_ADDR(context, (double(*)(double))acos);
 
     case HelperDirectMath_Asin:
-        return (double(*)(double))asin;
+        return SHIFT_ADDR(context, (double(*)(double))asin);
 
     case HelperDirectMath_Atan:
-        return (double(*)(double))atan;
+        return SHIFT_ADDR(context, (double(*)(double))atan);
 
     case HelperDirectMath_Atan2:
-        return (double(*)(double, double))atan2;
+        return SHIFT_ADDR(context, (double(*)(double, double))atan2);
 
     case HelperDirectMath_Cos:
-        return (double(*)(double))cos;
+        return SHIFT_ADDR(context, (double(*)(double))cos);
 
     case HelperDirectMath_Exp:
-        return (double(*)(double))exp;
+        return SHIFT_ADDR(context, (double(*)(double))exp);
 
     case HelperDirectMath_Log:
-        return (double(*)(double))log;
+        return SHIFT_ADDR(context, (double(*)(double))log);
 
     case HelperDirectMath_Sin:
-        return (double(*)(double))sin;
+        return SHIFT_ADDR(context, (double(*)(double))sin);
 
     case HelperDirectMath_Tan:
-        return (double(*)(double))tan;
+        return SHIFT_ADDR(context, (double(*)(double))tan);
 
 #elif defined(_M_ARM32_OR_ARM64)
     case HelperDirectMath_Acos:
-        return (double(*)(double))acos;
+        return SHIFT_ADDR(context, (double(*)(double))acos);
 
     case HelperDirectMath_Asin:
-        return (double(*)(double))asin;
+        return SHIFT_ADDR(context, (double(*)(double))asin);
 
     case HelperDirectMath_Atan:
-        return (double(*)(double))atan;
+        return SHIFT_ADDR(context, (double(*)(double))atan);
 
     case HelperDirectMath_Atan2:
-        return (double(*)(double, double))atan2;
+        return SHIFT_ADDR(context, (double(*)(double, double))atan2);
 
     case HelperDirectMath_Cos:
-        return (double(*)(double))cos;
+        return SHIFT_ADDR(context, (double(*)(double))cos);
 
     case HelperDirectMath_Exp:
-        return (double(*)(double))exp;
+        return SHIFT_ADDR(context, (double(*)(double))exp);
 
     case HelperDirectMath_Log:
-        return (double(*)(double))log;
+        return SHIFT_ADDR(context, (double(*)(double))log);
 
     case HelperDirectMath_Sin:
-        return (double(*)(double))sin;
+        return SHIFT_ADDR(context, (double(*)(double))sin);
 
     case HelperDirectMath_Tan:
-        return (double(*)(double))tan;
+        return SHIFT_ADDR(context, (double(*)(double))tan);
 #endif
 
     //
     // Methods that we don't want to get marked as CFG targets as they make unprotected calls
     //
+
+#ifdef _CONTROL_FLOW_GUARD
+    case HelperGuardCheckCall:
+        return SHIFT_ADDR(context, __guard_check_icall_fptr);
+#endif
+
     case HelperOp_TryCatch:
-        return Js::JavascriptExceptionOperators::OP_TryCatch;
+        return SHIFT_ADDR(context, Js::JavascriptExceptionOperators::OP_TryCatch);
 
     case HelperOp_TryFinally:
-        return Js::JavascriptExceptionOperators::OP_TryFinally;
+        return SHIFT_ADDR(context, Js::JavascriptExceptionOperators::OP_TryFinally);
 
     //
     // Methods that we don't want to get marked as CFG targets as they dump all registers to a controlled address
     //
     case HelperSaveAllRegistersAndBailOut:
-        return LinearScanMD::SaveAllRegistersAndBailOut;
+        return SHIFT_ADDR(context, LinearScanMD::SaveAllRegistersAndBailOut);
     case HelperSaveAllRegistersAndBranchBailOut:
-        return LinearScanMD::SaveAllRegistersAndBranchBailOut;
+        return SHIFT_ADDR(context, LinearScanMD::SaveAllRegistersAndBranchBailOut);
 
     #ifdef _M_IX86
     case HelperSaveAllRegistersNoSse2AndBailOut:
-        return LinearScanMD::SaveAllRegistersNoSse2AndBailOut;
+        return SHIFT_ADDR(context, LinearScanMD::SaveAllRegistersNoSse2AndBailOut);
     case HelperSaveAllRegistersNoSse2AndBranchBailOut:
-        return LinearScanMD::SaveAllRegistersNoSse2AndBranchBailOut;
+        return SHIFT_ADDR(context, LinearScanMD::SaveAllRegistersNoSse2AndBranchBailOut);
     #endif
 
     }
 
     Assume(UNREACHED);
 
-    return nullptr;
+    return 0;
 }
 
 ///----------------------------------------------------------------------------
@@ -325,14 +325,15 @@ DECLSPEC_GUARDIGNORE __declspec(noinline) void * const GetNonTableMethodAddress(
 ///     this one is never the intercepted by debugger helper.
 ///
 ///----------------------------------------------------------------------------
-void const * GetMethodOriginalAddress(JnHelperMethod helperMethod)
+intptr_t GetMethodOriginalAddress(ThreadContextInfo * context, JnHelperMethod helperMethod)
 {
-    const void *address = GetHelperMethods()[static_cast<WORD>(helperMethod)];
-    if (address == nullptr)
+    intptr_t address = GetHelperMethods()[static_cast<WORD>(helperMethod)];
+    if (address == 0)
     {
-        return GetNonTableMethodAddress(helperMethod);
+        return GetNonTableMethodAddress(context, helperMethod);
     }
-    return address;
+
+    return SHIFT_ADDR(context, address);
 }
 
 #if DBG_DUMP || defined(ENABLE_IR_VIEWER)

+ 4 - 4
lib/Backend/JnHelperMethod.h

@@ -32,15 +32,15 @@ enum JnHelperMethod
 class HelperCallOpnd;
 
 // Verify the table is read-only.
-void CheckJnHelperTable(const void * const *table);
+void CheckJnHelperTable(intptr_t const *table);
 
 // Return address of the helper which can be intercepted by debugger wrapper.
-void const* GetMethodAddress(HelperCallOpnd* opnd);
+intptr_t GetMethodAddress(ThreadContextInfo * context, HelperCallOpnd* opnd);
 
-void * const GetNonTableMethodAddress(JnHelperMethod helperMethod);
+intptr_t GetNonTableMethodAddress(ThreadContextInfo * context, JnHelperMethod helperMethod);
 
 // Returns the original address of the helper, this one is never the intercepted by debugger helper.
-void const* GetMethodOriginalAddress(JnHelperMethod helperMethod);
+intptr_t GetMethodOriginalAddress(ThreadContextInfo * context, JnHelperMethod helperMethod);
 
 #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
 

+ 1 - 1
lib/Backend/Lower.cpp

@@ -4935,7 +4935,7 @@ Lowerer::LowerNewScObjArray(IR::Instr *newObjInstr)
     IR::Opnd *opndSrc1 = newObjInstr->UnlinkSrc1();
     if (opndSrc1->IsImmediateOpnd())
     {
-        intptr_t length = opndSrc1->GetImmediateValue();
+        intptr_t length = opndSrc1->GetImmediateValue(m_func);
         if (length >= 0 && length <= 8)
         {
             GenerateProfiledNewScObjArrayFastPath(newObjInstr, arrayInfo, weakFuncRef, (uint32)length);

+ 4 - 4
lib/Backend/LowerMDShared.cpp

@@ -669,7 +669,7 @@ LowererMD::ChangeToHelperCall(IR::Instr * callInstr,  IR::JnHelperMethod helperM
     if (helperCallOpnd->IsDiagHelperCallOpnd())
     {
         // Load arguments for the wrapper.
-        this->LoadHelperArgument(callInstr, IR::AddrOpnd::New((Js::Var)IR::GetMethodOriginalAddress(helperMethod), IR::AddrOpndKindDynamicMisc, m_func));
+        this->LoadHelperArgument(callInstr, IR::AddrOpnd::New((Js::Var)IR::GetMethodOriginalAddress(m_func->GetThreadContextInfo(), helperMethod), IR::AddrOpndKindDynamicMisc, m_func));
         this->m_lowerer->LoadScriptContext(callInstr);
     }
     callInstr->SetSrc1(helperCallOpnd);
@@ -1192,7 +1192,7 @@ void LowererMD::ChangeToMul(IR::Instr *const instr, bool hasOverflowCheck)
             // MOV reg, imm
             temp2 = IR::RegOpnd::New(TyInt32, instr->m_func);
             instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, temp2,
-                IR::IntConstOpnd::New((IntConstType)instr->GetSrc2()->GetImmediateValue(), TyInt32, instr->m_func, true),
+                IR::IntConstOpnd::New((IntConstType)instr->GetSrc2()->GetImmediateValue(instr->m_func), TyInt32, instr->m_func, true),
                 instr->m_func));
         }
         // eax = IMUL eax, reg
@@ -1698,7 +1698,7 @@ LowererMD::Legalize(IR::Instr *const instr, bool fPostRegAlloc)
 
     // Non-MOV (second operand) immediate need to fit in DWORD for AMD64
     Assert(!instr->GetSrc2() || !instr->GetSrc2()->IsImmediateOpnd()
-        || (TySize[instr->GetSrc2()->GetType()] != 8) || Math::FitsInDWord(instr->GetSrc2()->GetImmediateValue()));
+        || (TySize[instr->GetSrc2()->GetType()] != 8) || Math::FitsInDWord(instr->GetSrc2()->GetImmediateValue(instr->m_func)));
 #endif
 }
 
@@ -8686,7 +8686,7 @@ void LowererMD::GenerateFastInlineBuiltInCall(IR::Instr* instr, IR::JnHelperMeth
 #else
             // s1 = MOV helperAddr
             IR::RegOpnd* s1 = IR::RegOpnd::New(TyMachReg, this->m_func);
-            IR::AddrOpnd* helperAddr = IR::AddrOpnd::New((Js::Var)IR::GetMethodOriginalAddress(helperMethod), IR::AddrOpndKind::AddrOpndKindDynamicMisc, this->m_func);
+            IR::AddrOpnd* helperAddr = IR::AddrOpnd::New((Js::Var)IR::GetMethodOriginalAddress(m_func->GetThreadContextInfo(), helperMethod), IR::AddrOpndKind::AddrOpndKindDynamicMisc, this->m_func);
             IR::Instr* mov = IR::Instr::New(Js::OpCode::MOV, s1, helperAddr, this->m_func);
             instr->InsertBefore(mov);
 

+ 8 - 2
lib/Backend/NativeCodeGenerator.cpp

@@ -2944,7 +2944,10 @@ NativeCodeGenerator::FreeNativeCodeGenAllocation(void* address)
 {
     if(this->backgroundAllocators)
     {
-        this->backgroundAllocators->emitBufferManager.FreeAllocation(address);
+        ThreadContext * context = this->scriptContext->GetThreadContext();
+        context->m_codeGenManager.FreeAllocation(context->GetRemoteThreadContextAddr(), (intptr_t)address);
+        // TODO: OOP JIT, add following condition back in case we are in-proc
+        // this->backgroundAllocators->emitBufferManager.FreeAllocation(address);
     }
 }
 
@@ -2962,8 +2965,11 @@ NativeCodeGenerator::QueueFreeNativeCodeGenAllocation(void* address)
     ThreadContext::GetContextForCurrentThread()->SetValidCallTargetForCFG(address, false);
 
     // The foreground allocators may have been used
-    if(this->foregroundAllocators && this->foregroundAllocators->emitBufferManager.FreeAllocation(address))
+    ThreadContext * context = this->scriptContext->GetThreadContext();
+    if(this->foregroundAllocators && context->m_codeGenManager.FreeAllocation(context->GetRemoteThreadContextAddr(), (intptr_t)address))
     {
+        // TODO: OOP JIT, add following condition back in case we are in-proc
+        //if(this->foregroundAllocators->emitBufferManager.FreeAllocation(address)
         return;
     }
 

+ 2 - 2
lib/Backend/Opnd.cpp

@@ -340,7 +340,7 @@ Opnd::GetStackSym() const
 }
 
 intptr_t
-Opnd::GetImmediateValue()
+Opnd::GetImmediateValue(Func* func)
 {
     switch (this->GetKind())
     {
@@ -351,7 +351,7 @@ Opnd::GetImmediateValue()
         return (intptr_t)this->AsAddrOpnd()->m_address;
 
     case OpndKindHelperCall:
-        return (intptr_t)IR::GetMethodAddress(this->AsHelperCallOpnd());
+        return (intptr_t)IR::GetMethodAddress(func->GetThreadContextInfo(), this->AsHelperCallOpnd());
 
     default:
         AssertMsg(UNREACHED, "Unexpected immediate opnd kind");

+ 1 - 1
lib/Backend/Opnd.h

@@ -201,7 +201,7 @@ public:
     bool                IsWriteBarrierTriggerableValue();
     void                SetIsDead(const bool isDead = true)   { this->m_isDead = isDead; }
     bool                GetIsDead()   { return this->m_isDead; }
-    intptr_t            GetImmediateValue();
+    intptr_t            GetImmediateValue(Func * func);
     BailoutConstantValue GetConstValue();
     bool                GetIsJITOptimizedReg() const { return m_isJITOptimizedReg; }
     void                SetIsJITOptimizedReg(bool value) { Assert(!value || !this->IsIndirOpnd()); m_isJITOptimizedReg = value; }

+ 58 - 25
lib/Backend/ThreadContextInfo.cpp

@@ -12,140 +12,143 @@ ThreadContextInfo::ThreadContextInfo(ThreadContextData * data) :
             PageAllocator::DefaultLowMaxFreePageCount :
             PageAllocator::DefaultMaxFreePageCount),
     m_codeGenAlloc(&m_policyManager, nullptr, (HANDLE)data->processHandle),
-    m_isAllJITCodeInPreReservedRegion(true)
+    m_isAllJITCodeInPreReservedRegion(true),
+    m_jitChakraBaseAddress((intptr_t)GetModuleHandle(L"Chakra.dll")), // TODO: OOP JIT, don't hardcode name
+    m_jitCRTBaseAddress((intptr_t)GetModuleHandle(UCrtC99MathApis::LibraryName)),
+    m_delayLoadWinCoreProcessThreads()
 {
 }
 
 intptr_t
 ThreadContextInfo::GetNullFrameDisplayAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::NullFrameDisplay) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::NullFrameDisplay);
 }
 
 intptr_t
 ThreadContextInfo::GetStrictNullFrameDisplayAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::StrictNullFrameDisplay) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::StrictNullFrameDisplay);
 }
 
 intptr_t
 ThreadContextInfo::GetAbsDoubleCstAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::AbsDoubleCst) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::AbsDoubleCst);
 }
 
 intptr_t
 ThreadContextInfo::GetAbsFloatCstAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::AbsFloatCst) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::AbsFloatCst);
 }
 
 intptr_t
 ThreadContextInfo::GetMaskNegFloatAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::MaskNegFloat) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::MaskNegFloat);
 }
 
 intptr_t
 ThreadContextInfo::GetMaskNegDoubleAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::MaskNegDouble) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::MaskNegDouble);
 }
 
 intptr_t
 ThreadContextInfo::GetUIntConvertConstAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::UIntConvertConst) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::UIntConvertConst);
 }
 
 intptr_t
 ThreadContextInfo::GetUint8ClampedArraySetItemAddr() const
 {
-    return reinterpret_cast<intptr_t>((BOOL(*)(Js::Uint8ClampedArray * arr, uint32 index, Js::Var value))&Js::Uint8ClampedArray::DirectSetItem) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, (BOOL(*)(Js::Uint8ClampedArray * arr, uint32 index, Js::Var value))&Js::Uint8ClampedArray::DirectSetItem);
 }
 
 intptr_t
 ThreadContextInfo::GetConstructorCacheDefaultInstanceAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::ConstructorCache::DefaultInstance) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::ConstructorCache::DefaultInstance);
 }
 
 intptr_t
 ThreadContextInfo::GetJavascriptObjectNewInstanceAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptObject::EntryInfo::NewInstance) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptObject::EntryInfo::NewInstance);
 }
 
 intptr_t
 ThreadContextInfo::GetDoubleOnePointZeroAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::ONE_POINT_ZERO) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::ONE_POINT_ZERO);
 }
 
 intptr_t
 ThreadContextInfo::GetDoublePointFiveAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::k_PointFive) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::k_PointFive);
 }
 
 intptr_t
 ThreadContextInfo::GetFloatPointFiveAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::k_Float32PointFive) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Float32PointFive);
 }
 
 intptr_t
 ThreadContextInfo::GetDoubleNegPointFiveAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::k_NegPointFive) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::k_NegPointFive);
 }
 
 intptr_t
 ThreadContextInfo::GetFloatNegPointFiveAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::k_Float32NegPointFive) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Float32NegPointFive);
 }
 
 intptr_t
 ThreadContextInfo::GetDoubleTwoToFractionAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::k_TwoToFraction) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::k_TwoToFraction);
 }
 
 intptr_t
 ThreadContextInfo::GetFloatTwoToFractionAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::k_Float32TwoToFraction) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Float32TwoToFraction);
 }
 
 intptr_t
 ThreadContextInfo::GetDoubleNegTwoToFractionAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::k_NegTwoToFraction) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::k_NegTwoToFraction);
 }
 
 intptr_t
 ThreadContextInfo::GetFloatNegTwoToFractionAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::k_Float32NegTwoToFraction) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Float32NegTwoToFraction);
 }
 
 intptr_t
 ThreadContextInfo::GetDoubleZeroAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::k_Zero) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Zero);
 }
 
 intptr_t
 ThreadContextInfo::GetFloatZeroAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNumber::k_Float32Zero) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNumber::k_Float32Zero);
 }
 
 intptr_t
 ThreadContextInfo::GetNativeFloatArrayMissingItemAddr() const
 {
-    return reinterpret_cast<intptr_t>(&Js::JavascriptNativeFloatArray::MissingItem) - GetBaseAddressDifference();
+    return SHIFT_ADDR(this, &Js::JavascriptNativeFloatArray::MissingItem);
 }
 
 intptr_t
@@ -208,8 +211,38 @@ ThreadContextInfo::GetRuntimeChakraBaseAddress() const
     return static_cast<intptr_t>(m_threadContextData.chakraBaseAddress);
 }
 
+intptr_t
+ThreadContextInfo::GetRuntimeCRTBaseAddress() const
+{
+    return static_cast<intptr_t>(m_threadContextData.crtBaseAddress);
+}
+
 ptrdiff_t
-ThreadContextInfo::GetBaseAddressDifference() const
+ThreadContextInfo::GetChakraBaseAddressDifference() const
 {
-    return m_localChakraBaseAddress - GetRuntimeChakraBaseAddress();
+    return m_jitChakraBaseAddress - GetRuntimeChakraBaseAddress();
+}
+
+ptrdiff_t
+ThreadContextInfo::GetCRTBaseAddressDifference() const
+{
+    return m_jitCRTBaseAddress - GetRuntimeCRTBaseAddress();
+}
+
+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
 }

+ 14 - 2
lib/Backend/ThreadContextInfo.h

@@ -47,16 +47,28 @@ public:
     void ResetIsAllJITCodeInPreReservedRegion();
     bool IsAllJITCodeInPreReservedRegion() const;
 
+    ptrdiff_t GetChakraBaseAddressDifference() const;
+    ptrdiff_t GetCRTBaseAddressDifference() const;
+
+    bool IsCFGEnabled();
 private:
     intptr_t GetRuntimeChakraBaseAddress() const;
-    ptrdiff_t GetBaseAddressDifference() const;
+    intptr_t GetRuntimeCRTBaseAddress() const;
 
+    Js::DelayLoadWinCoreProcessThreads m_delayLoadWinCoreProcessThreads;
     PageAllocator m_pageAlloc;
     AllocationPolicyManager m_policyManager;
     CodeGenAllocators m_codeGenAlloc;
 
     ThreadContextData m_threadContextData;
 
-    intptr_t m_localChakraBaseAddress;
+    intptr_t m_jitChakraBaseAddress;
+    intptr_t m_jitCRTBaseAddress;
     bool m_isAllJITCodeInPreReservedRegion;
 };
+
+#define SHIFT_ADDR(context, address) \
+    (intptr_t)address - context->GetChakraBaseAddressDifference()
+
+#define SHIFT_CRT_ADDR(context, address) \
+    (intptr_t)address - context->GetCRTBaseAddressDifference()

+ 3 - 3
lib/Backend/amd64/EncoderMD.cpp

@@ -493,7 +493,7 @@ intConst:
 
     case IR::OpndKindHelperCall:
         AssertMsg(this->GetOpndSize(opnd) == 8, "HelperCall opnd must be 64 bit");
-        value = (size_t)IR::GetMethodAddress(opnd->AsHelperCallOpnd());
+        value = (size_t)IR::GetMethodAddress(m_func->GetThreadContextInfo(), opnd->AsHelperCallOpnd());
         break;
 
     case IR::OpndKindIndir:
@@ -815,7 +815,7 @@ EncoderMD::Encode(IR::Instr *instr, BYTE *pc, BYTE* beginCodeAddress)
             if (opr2->IsImmediateOpnd())
             {
                 Assert(instr->m_opcode == Js::OpCode::MOV);
-                if (instrSize == 8 && !instr->isInlineeEntryInstr && Math::FitsInDWord(opr2->GetImmediateValue()))
+                if (instrSize == 8 && !instr->isInlineeEntryInstr && Math::FitsInDWord(opr2->GetImmediateValue(instr->m_func)))
                 {
                     // Better off using the C7 encoding as it will sign extend
                     continue;
@@ -1233,7 +1233,7 @@ EncoderMD::Encode(IR::Instr *instr, BYTE *pc, BYTE* beginCodeAddress)
             uint valueImm = 0;
             if (src2 &&src2->IsIntConstOpnd())
             {
-                valueImm = (uint)src2->AsIntConstOpnd()->GetImmediateValue();
+                valueImm = (uint)src2->AsIntConstOpnd()->GetImmediateValue(instr->m_func);
             }
             else
             {

+ 1 - 1
lib/Backend/amd64/PeepsMD.cpp

@@ -57,7 +57,7 @@ PeepsMD::PeepAssign(IR::Instr *instr)
     IR::Opnd* src = instr->GetSrc1();
     if(dst->IsRegOpnd() && instr->m_opcode == Js::OpCode::MOV)
     {
-        if (src->IsImmediateOpnd() && src->GetImmediateValue() == 0)
+        if (src->IsImmediateOpnd() && src->GetImmediateValue(instr->m_func) == 0)
         {
             Assert(instr->GetSrc2() == NULL);
 

+ 10 - 10
lib/Backend/arm/EncoderMD.cpp

@@ -242,7 +242,7 @@ InstructionType EncoderMD::CanonicalizeMov(IR::Instr * instr)
         return InstructionType::Thumb;
     }
 
-    IntConstType immed = srcOpnd->GetImmediateValue();
+    IntConstType immed = srcOpnd->GetImmediateValue(instr->m_func);
     if (IS_LOWREG(dstOpnd->GetReg()) &&
         IS_CONST_UINT8(immed))
     {
@@ -383,7 +383,7 @@ InstructionType EncoderMD::CanonicalizeAdd(IR::Instr * instr)
     }
     else
     {
-        immed = src2->GetImmediateValue();
+        immed = src2->GetImmediateValue(instr->m_func);
 
         // Check for rm = ADD SP, uint8:00
         if (IS_LOWREG(instr->GetDst()->AsRegOpnd()->GetReg()))
@@ -424,10 +424,10 @@ InstructionType EncoderMD::CanonicalizeSub(IR::Instr * instr)
 
         // The instr is definitely wide. Let the opcode indicate that if we're using the uint12 form.
         // Note that the uint12 form can't set the status bits.
-        if (!src2->IsRegOpnd() && !this->CanEncodeModConst12(src2->GetImmediateValue()))
+        if (!src2->IsRegOpnd() && !this->CanEncodeModConst12(src2->GetImmediateValue(instr->m_func)))
         {
             Assert(instr->m_opcode != Js::OpCode::SUBS);
-            Assert(IS_CONST_UINT12(src2->GetImmediateValue()));
+            Assert(IS_CONST_UINT12(src2->GetImmediateValue(instr->m_func)));
             instr->m_opcode = Js::OpCode::SUBW;
         }
 
@@ -455,7 +455,7 @@ bool EncoderMD::IsWideAddSub(IR::Instr * instr)
         {
             return true;
         }
-        immed = src2->GetImmediateValue();
+        immed = src2->GetImmediateValue(instr->m_func);
         return ((immed & 3) != 0) || !IS_CONST_UINT7(immed >> 2);
     }
     else
@@ -473,7 +473,7 @@ bool EncoderMD::IsWideAddSub(IR::Instr * instr)
         }
         else
         {
-            immed = src2->GetImmediateValue();
+            immed = src2->GetImmediateValue(instr->m_func);
             return dst->IsSameReg(src1) ? !IS_CONST_UINT8(immed) : !IS_CONST_UINT3(immed);
         }
     }
@@ -535,7 +535,7 @@ InstructionType EncoderMD::CmpEncodeType(IR::Instr * instr)
     }
 
     if (IS_LOWREG(instr->GetSrc1()->AsRegOpnd()->GetReg()) &&
-        IS_CONST_UINT8(src2->GetImmediateValue()))
+        IS_CONST_UINT8(src2->GetImmediateValue(instr->m_func)))
     {
         return InstructionType::Thumb;
     }
@@ -638,7 +638,7 @@ InstructionType EncoderMD::ShiftEncodeType(IR::Instr * instr)
     }
     else
     {
-        Assert(IS_CONST_UINT5(src2->GetImmediateValue()));
+        Assert(IS_CONST_UINT5(src2->GetImmediateValue(instr->m_func)));
         return IS_LOWREG(src1->GetReg()) ? InstructionType::Thumb : InstructionType::Thumb2;
     }
 }
@@ -1050,7 +1050,7 @@ EncoderMD::GenerateEncoding(IR::Instr* instr, IFORM iform, BYTE *pc, int32 size,
 
                 case STEP_CONSTANT:
                     Assert(opn->IsImmediateOpnd());
-                    constant = opn->GetImmediateValue();
+                    constant = opn->GetImmediateValue(instr->m_func);
                     constantValid = true;
                     continue;
 
@@ -1527,7 +1527,7 @@ EncoderMD::GenerateEncoding(IR::Instr* instr, IFORM iform, BYTE *pc, int32 size,
                     else
                     {
                         Assert(opn->IsImmediateOpnd());
-                        offset = opn->GetImmediateValue();
+                        offset = opn->GetImmediateValue(instr->m_func);
                     }
                     encode = this->EncodeT2Offset(encode, instr, offset, bitOffset);
                     continue;

+ 1 - 1
lib/Backend/arm/LegalizeMD.cpp

@@ -167,7 +167,7 @@ void LegalizeMD::LegalizeSrc(IR::Instr * instr, IR::Opnd * opnd, uint opndNum, b
     case IR::OpndKindAddr:
     case IR::OpndKindHelperCall:
     case IR::OpndKindIntConst:
-        immed = opnd->GetImmediateValue();
+        immed = opnd->GetImmediateValue(instr->m_func);
         LegalizeImmed(instr, opnd, opndNum, immed, forms, fPostRegAlloc);
         break;
 

+ 1 - 1
lib/Backend/arm/LowerMD.cpp

@@ -6830,7 +6830,7 @@ bool LowererMD::GenerateFastCharAt(Js::BuiltinFunction index, IR::Opnd *dst, IR:
     }
 
     // Bail out if index a constant and is less than zero.
-    if (srcIndex->IsImmediateOpnd() && srcIndex->GetImmediateValue() < 0)
+    if (srcIndex->IsImmediateOpnd() && srcIndex->GetImmediateValue(instr->m_func) < 0)
     {
         instr = IR::BranchInstr::New(Js::OpCode::B, labelHelper, this->m_func);
         insertInstr->InsertBefore(instr);

+ 1 - 1
lib/Backend/i386/EncoderMD.cpp

@@ -1197,7 +1197,7 @@ modrm:
             uint valueImm = 0;
             if (src2 &&src2->IsIntConstOpnd())
             {
-                valueImm = src2->AsIntConstOpnd()->GetImmediateValue();
+                valueImm = src2->AsIntConstOpnd()->GetImmediateValue(instr->m_func);
             }
             else
             {

+ 1 - 1
lib/Common/BackendApi.h

@@ -27,7 +27,7 @@ class NativeCodeGenerator;
 class ThreadContext;
 struct CodeGenWorkItem;
 class NativeCodeData;
-
+class ThreadContextInfo;
 class StackSym;
 class Func;
 struct InlinedFrameLayout;

+ 19 - 0
lib/JITClient/JITManager.cpp

@@ -266,6 +266,25 @@ JITManager::CleanupScriptContext(
     return hr;
 }
 
+HRESULT
+JITManager::FreeAllocation(
+    __in intptr_t threadContextInfoAddress,
+    __in intptr_t address)
+{
+    HRESULT hr = E_FAIL;
+    RpcTryExcept
+    {
+        hr = ClientFreeAllocation(m_rpcBindingHandle, threadContextInfoAddress, address);
+    }
+        RpcExcept(1)
+    {
+        hr = HRESULT_FROM_WIN32(RpcExceptionCode());
+    }
+    RpcEndExcept;
+
+    return hr;
+}
+
 HRESULT
 JITManager::RemoteCodeGenCall(
     __in CodeGenWorkItemJITData *workItemData,

+ 4 - 0
lib/JITClient/JITManager.h

@@ -26,6 +26,10 @@ public:
     HRESULT CleanupScriptContext(
         __in intptr_t scriptContextInfoAddress);
 
+    HRESULT FreeAllocation(
+        __in intptr_t threadContextInfoAddress,
+        __in intptr_t address);
+
     HRESULT RemoteCodeGenCall(
         __in CodeGenWorkItemJITData *workItemData,
         __in ProfileData * profileData,

+ 6 - 0
lib/JITIDL/ChakraJIT.idl

@@ -92,6 +92,7 @@ typedef struct ThreadContextData
 {
     __int3264 processHandle;
     __int3264 chakraBaseAddress;
+    __int3264 crtBaseAddress;
     __int3264 threadStackLimitAddr;
     __int3264 scriptStackLimit;
     boolean isThreadBound;
@@ -236,6 +237,11 @@ interface IChakraJIT
         [in] handle_t binding,
         [in] __int3264 scriptContextInfoAddress);
 
+    HRESULT FreeAllocation(
+        [in] handle_t binding,
+        [in] __int3264 threadContextInfoAddress,
+        [in] __int3264 address);
+
     HRESULT RemoteCodeGen(
         [in] handle_t binding,
         [in] __int3264 threadContextInfoAddress,

+ 11 - 0
lib/JITServer/JITServer.cpp

@@ -135,6 +135,17 @@ ServerCleanupScriptContext(
     return S_OK;
 }
 
+HRESULT
+ServerFreeAllocation(
+    /* [in] */ handle_t binding,
+    /* [in] */ __int3264 threadContextInfo,
+    /* [in] */ __int3264 address)
+{
+    ThreadContextInfo * context = reinterpret_cast<ThreadContextInfo*>(threadContextInfo);
+    bool succeeded = context->GetCodeGenAllocators()->emitBufferManager.FreeAllocation((void*)address);
+    return succeeded ? S_OK : E_FAIL;
+}
+
 HRESULT
 ServerRemoteCodeGen(
     /* [in] */ handle_t binding,

+ 2 - 0
lib/Runtime/Base/ThreadContext.h

@@ -524,7 +524,9 @@ public:
             Js::Throw::InternalError();
         }
         contextData.processHandle = (intptr_t)targetHandle;
+        // TODO: OOP JIT, use more generic method for getting name, e.g. in case of ChakraTest.dll
         contextData.chakraBaseAddress = (intptr_t)GetModuleHandle(L"Chakra.dll");
+        contextData.crtBaseAddress = (intptr_t)GetModuleHandle(UCrtC99MathApis::LibraryName);
         contextData.threadStackLimitAddr = reinterpret_cast<intptr_t>(GetAddressOfStackLimitForCurrentThread());
         contextData.scriptStackLimit = reinterpret_cast<size_t>(GetScriptStackLimit());
         contextData.isThreadBound = GetIsThreadBound();

+ 2 - 0
lib/Runtime/Library/MathLibrary.cpp

@@ -10,6 +10,8 @@
 #pragma intrinsic(_mm_round_sd)
 #endif
 
+const LPCWSTR UCrtC99MathApis::LibraryName = L"api-ms-win-crt-math-l1-1-0.dll";
+
 void UCrtC99MathApis::Ensure()
 {
     if (m_isInit)

+ 3 - 1
lib/Runtime/Library/MathLibrary.h

@@ -21,10 +21,12 @@ private:
     void Ensure();
 
 public:
+    static const LPCWSTR LibraryName;
+
     UCrtC99MathApis() : m_pfnlog2(nullptr), m_pfnlog1p(nullptr), m_pfnexpm1(nullptr), m_pfnacosh(nullptr), m_pfnasinh(nullptr), m_pfnatanh(nullptr), m_pfntrunc(nullptr), m_pfncbrt(nullptr) { }
     virtual ~UCrtC99MathApis() { }
 
-    virtual LPCWSTR GetLibraryName() const override { return L"api-ms-win-crt-math-l1-1-0.dll"; }
+    virtual LPCWSTR GetLibraryName() const override { return LibraryName; }
 
     bool IsAvailable() { Ensure(); return DelayLoadLibrary::IsAvailable(); }