Expose a hosting interface for the JIT.
authorPat Gavlin <pagavlin@microsoft.com>
Tue, 23 Feb 2016 21:53:32 +0000 (13:53 -0800)
committerPat Gavlin <pagavlin@microsoft.com>
Tue, 23 Feb 2016 21:53:32 +0000 (13:53 -0800)
This is the first significant step towards removing the JIT's dependence on utilcode.
This change introduces a new interface, `ICorJitHost`, that allows functionality that
would usually be provided by the OS to be overridden by the program that is hosting
the JIT. At the moment, this is limited to memory allocation and configuration value
(e.g. environment variable) access. If the JIT exports a function named `jitStartup`,
an instance of the `ICorJitHost` must be provided via that function before the first
call to `getJit`.

The VM and other implementors of the JIT interface have been updated accordingly.
Most implementors should use the common implementation of `ICorJitHost` (cleverly
named `JitHost`) in utilcode which respects the CLR's hosting policy.

Note that this change does not update RyuJIT (or any other JITs) to use any of the
functionality exposed by `ICorJitHost`; that work is left for future changes.

[tfs-changeset: 1578176]

Commit migrated from https://github.com/dotnet/coreclr/commit/dfd6ab2348b4b151bb90d3bd7deb6a7304bbafac

22 files changed:
src/coreclr/src/inc/corinfo.h
src/coreclr/src/inc/corjit.h
src/coreclr/src/inc/corjithost.h [new file with mode: 0644]
src/coreclr/src/inc/jithost.h [new file with mode: 0644]
src/coreclr/src/jit/ClrJit.exports
src/coreclr/src/jit/dll/clrjit.def
src/coreclr/src/jit/ee_il_dll.cpp
src/coreclr/src/jit/jitpch.h
src/coreclr/src/jit/protojit/protojit.def
src/coreclr/src/utilcode/CMakeLists.txt
src/coreclr/src/utilcode/UtilCode.vcproj
src/coreclr/src/utilcode/UtilCode.vcxproj
src/coreclr/src/utilcode/jithost.cpp [new file with mode: 0644]
src/coreclr/src/utilcode/utilcode.settings.targets
src/coreclr/src/vm/codeman.cpp
src/coreclr/src/vm/codeman.h
src/coreclr/src/vm/jitinterface.cpp
src/coreclr/src/vm/jitinterface.h
src/coreclr/src/zap/common.h
src/coreclr/src/zap/zapinfo.cpp
src/coreclr/src/zap/zapinfo.h
src/coreclr/src/zap/zapper.cpp

index 5616e71..d6a497a 100644 (file)
@@ -231,11 +231,11 @@ TODO: Talk about initializing strutures before use
 #if COR_JIT_EE_VERSION > 460
 
 // Update this one
-SELECTANY const GUID JITEEVersionIdentifier = { /* 13accf3d-12d7-4fd4-bc65-d73578b1a474 */
-    0x13accf3d,
-    0x12d7,
-    0x4fd4,
-    { 0xbc, 0x65, 0xd7, 0x35, 0x78, 0xb1, 0xa4, 0x74 }
+SELECTANY const GUID JITEEVersionIdentifier = { /* 35ef98ab-fd22-4ccc-8ddb-b1156a7d94f3 */
+    0x35ef98ab,
+    0xfd22,
+    0x4ccc,
+    { 0x8d, 0xdb, 0xb1, 0x15, 0x6a, 0x7d, 0x94, 0xf3 }
 };
 
 #else
@@ -2758,33 +2758,6 @@ public:
         /* OUT */   SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr
         ) = 0;
 
-    /*************************************************************************/
-    //
-    // Configuration values - Allows querying of the CLR configuration.
-    //
-    /*************************************************************************/
-
-    //  Return an integer ConfigValue if any.
-    //
-    virtual int getIntConfigValue(
-        const wchar_t *name, 
-        int defaultValue
-        ) = 0;
-
-    //  Return a string ConfigValue if any.
-    //
-    virtual wchar_t *getStringConfigValue(
-        const wchar_t *name
-        ) = 0;
-
-    // Free a string ConfigValue returned by the runtime.
-    // JITs using the getStringConfigValue query are required
-    // to return the string values to the runtime for deletion.
-    // this avoid leaking the memory in the JIT.
-    virtual void freeStringConfigValue(
-        __in_z wchar_t *value
-        ) = 0;
-
 #endif // COR_JIT_EE_VERSION
 
 };
index 561e4b1..32ceac6 100644 (file)
@@ -320,9 +320,16 @@ enum CheckedWriteBarrierKinds {
 };
 #endif
 
+#if COR_JIT_EE_VERSION > 460
+
+#include "corjithost.h"
+
+extern "C" void __stdcall jitStartup(ICorJitHost* host);
+
+#endif
+
 class ICorJitCompiler;
 class ICorJitInfo;
-
 struct IEEMemoryManager;
 
 extern "C" ICorJitCompiler* __stdcall getJit();
diff --git a/src/coreclr/src/inc/corjithost.h b/src/coreclr/src/inc/corjithost.h
new file mode 100644 (file)
index 0000000..8242fab
--- /dev/null
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __CORJITHOST_H__
+#define __CORJITHOST_H__
+
+// ICorJitHost
+//
+// ICorJitHost provides the interface that the JIT uses to access some functionality that
+// would normally be provided by the operating system. This is intended to allow for
+// host-specific policies re: memory allocation, configuration value access, etc. It is
+// expected that the `ICorJitHost` value provided to `jitStartup` lives at least as
+// long as the JIT itself.
+class ICorJitHost
+{
+public:
+    // Allocate memory of the given size in bytes. All bytes of the returned block
+    // must be initialized to zero. If `usePageAllocator` is true, the implementation
+    // should use an allocator that deals in OS pages if one exists.
+    virtual void* allocateMemory(size_t size, bool usePageAllocator = false) = 0;
+
+    // Frees memory previous obtained by a call to `ICorJitHost::allocateMemory`. The
+    // value of the `usePageAllocator` parameter must match the value that was
+    // provided to the call to used to allocate the memory.
+    virtual void freeMemory(void* block, bool usePageAllocator = false) = 0;
+
+    // Return an integer config value for the given key, if any exists.
+    virtual int getIntConfigValue(
+        const wchar_t* name, 
+        int defaultValue
+        ) = 0;
+
+    // Return a string config value for the given key, if any exists.
+    virtual const wchar_t* getStringConfigValue(
+        const wchar_t* name
+        ) = 0;
+
+    // Free a string ConfigValue returned by the runtime.
+    // JITs using the getStringConfigValue query are required
+    // to return the string values to the runtime for deletion.
+    // This avoids leaking the memory in the JIT.
+    virtual void freeStringConfigValue(
+        const wchar_t* value
+        ) = 0;
+};
+
+#endif
diff --git a/src/coreclr/src/inc/jithost.h b/src/coreclr/src/inc/jithost.h
new file mode 100644 (file)
index 0000000..73ad334
--- /dev/null
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __JITHOST_H__
+#define __JITHOST_H__
+
+// Common implementation of ICorJitHost that respects CLR host policies.
+class JitHost : public ICorJitHost
+{
+private:
+    static JitHost theJitHost;
+
+    JitHost() {}
+    JitHost(const JitHost& other) = delete;
+    JitHost& operator=(const JitHost& other) = delete;
+
+public:
+    virtual void* allocateMemory(size_t size, bool usePageAllocator);
+    virtual void freeMemory(void* block, bool usePageAllocator);
+    virtual int getIntConfigValue(const wchar_t* name, int defaultValue);
+    virtual const wchar_t* getStringConfigValue(const wchar_t* name);
+    virtual void freeStringConfigValue(const wchar_t* value);
+
+    static ICorJitHost* getJitHost();
+};
+
+#endif // __JITHOST_H__
index 73a6ba1..1603af7 100644 (file)
@@ -3,4 +3,5 @@
 ; See the LICENSE file in the project root for more information.
 EXPORTS
     getJit
-    sxsJitStartup
\ No newline at end of file
+    jitStartup
+    sxsJitStartup
index f32f875..f0da62d 100644 (file)
@@ -19,8 +19,10 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 #endif
 #include "emit.h"
 
+
 /*****************************************************************************/
 
+static ICorJitHost* g_jitHost = nullptr;
 static CILJit* ILJitter = 0;        // The one and only JITTER I return
 #ifndef FEATURE_MERGE_JIT_AND_ENGINE
 HINSTANCE g_hInst = NULL;
@@ -45,8 +47,11 @@ JitOptions jitOpts =
 
 /*****************************************************************************/
 
-void jitStartup()
+extern "C"
+void __stdcall jitStartup(ICorJitHost* jitHost)
 {
+    g_jitHost = jitHost;
+
 #ifdef FEATURE_TRACELOGGING
     JitTelemetry::NotifyDllProcessAttach();
 #endif
@@ -61,13 +66,16 @@ void jitShutdown()
 #endif
 }
 
+
 /*****************************************************************************
  *  jitOnDllProcessAttach() called by DllMain() when jit.dll is loaded
  */
 
 void jitOnDllProcessAttach()
 {
-    jitStartup();
+#if COR_JIT_EE_VERSION <= 460
+    jitStartup(JitHost::getJitHost());
+#endif
 }
 
 /*****************************************************************************
@@ -79,7 +87,6 @@ void jitOnDllProcessDetach()
     jitShutdown();
 }
 
-
 #ifndef FEATURE_MERGE_JIT_AND_ENGINE
 
 extern "C"
@@ -139,9 +146,6 @@ ICorJitCompiler* __stdcall getJit()
     if (ILJitter == 0)
     {
         ILJitter = new (CILJitSingleton) CILJit();
-#ifdef FEATURE_MERGE_JIT_AND_ENGINE
-        jitStartup();
-#endif
     }
     return(ILJitter);
 }
index 7c333a7..a3c7e24 100644 (file)
 #include <cstdlib>
 #include <intrin.h>
 
+#if COR_JIT_EE_VERSION <= 460
+#include "corjithost.h"
+#include "jithost.h"
+#endif
 #include "jit.h"
 #include "iallocator.h"
 #include "hashbv.h"
index 73a6ba1..1603af7 100644 (file)
@@ -3,4 +3,5 @@
 ; See the LICENSE file in the project root for more information.
 EXPORTS
     getJit
-    sxsJitStartup
\ No newline at end of file
+    jitStartup
+    sxsJitStartup
index 9aeb243..001205a 100644 (file)
@@ -61,6 +61,7 @@ set(UTILCODE_COMMON_SOURCES
   pedecoder.cpp
   winfix.cpp
   longfilepathwrappers.cpp 
+  jithost.cpp
 )
 
 # These source file do not yet compile on Linux.
index d43c2a0..c125164 100644 (file)
                        RelativePath=".\longfilepathwrappers.cpp"
                        >
                </File>
+               <File
+                       RelativePath=".\jithost.cpp"
+                       >
+               </File>
        </Files>
        <Globals>
        </Globals>
index b0cca8d..54afef7 100644 (file)
     <ClCompile Include="UTSEM.cpp" />
     <ClCompile Include="winfix.cpp" />
     <ClCompile Include="longfilepathwrappers.cpp" />
+    <ClCompile Include="jithost.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="hostimpl.h" />
diff --git a/src/coreclr/src/utilcode/jithost.cpp b/src/coreclr/src/utilcode/jithost.cpp
new file mode 100644 (file)
index 0000000..88479de
--- /dev/null
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "utilcode.h"
+#include "corjit.h"
+#include "jithost.h"
+
+void* JitHost::allocateMemory(size_t size, bool usePageAllocator)
+{
+    WRAPPER_NO_CONTRACT;
+
+    if (usePageAllocator)
+    {
+        return GetEEMemoryManager()->ClrVirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
+    }
+    else
+    {
+        return ClrAllocInProcessHeap(0, S_SIZE_T(size));
+    }
+}
+
+void JitHost::freeMemory(void* block, bool usePageAllocator)
+{
+    WRAPPER_NO_CONTRACT;
+
+    if (usePageAllocator)
+    {
+        GetEEMemoryManager()->ClrVirtualFree(block, 0, MEM_RELEASE);
+    }
+    else
+    {
+        ClrFreeInProcessHeap(0, block);
+    }
+}
+
+int JitHost::getIntConfigValue(const wchar_t* name, int defaultValue)
+{
+    WRAPPER_NO_CONTRACT;
+
+    // Translate JIT call into runtime configuration query
+    CLRConfig::ConfigDWORDInfo info{ name, defaultValue, CLRConfig::REGUTIL_default };
+
+    // Perform a CLRConfig look up on behalf of the JIT.
+    return CLRConfig::GetConfigValue(info);
+}
+
+const wchar_t* JitHost::getStringConfigValue(const wchar_t* name)
+{
+    WRAPPER_NO_CONTRACT;
+
+    // Translate JIT call into runtime configuration query
+    CLRConfig::ConfigStringInfo info{ name, CLRConfig::REGUTIL_default };
+
+    // Perform a CLRConfig look up on behalf of the JIT.
+    return CLRConfig::GetConfigValue(info);
+}
+
+void JitHost::freeStringConfigValue(const wchar_t* value)
+{
+    WRAPPER_NO_CONTRACT;
+
+    CLRConfig::FreeConfigString(const_cast<wchar_t*>(value));
+}
+
+JitHost JitHost::theJitHost;
+ICorJitHost* JitHost::getJitHost()
+{
+    STATIC_CONTRACT_SO_TOLERANT;
+    STATIC_CONTRACT_GC_NOTRIGGER;
+    STATIC_CONTRACT_NOTHROW;
+    STATIC_CONTRACT_CANNOT_TAKE_LOCK;
+
+    return &theJitHost;
+}
index 690000d..7c11fd5 100644 (file)
         <CppCompile Include="$(UtilCodeSrcDir)\SecurityUtil.cpp" />
 
         <CppCompile Include="$(UtilCodeSrcDir)\AppXUtil.cpp" Condition="'$(FeatureAppX)' == 'true'"/>
+
+        <CppCompile Include="$(UtilCodeSrcDir)\jithost.cpp" />
     </ItemGroup>   
 </Project>
index 4f99539..eb6a976 100644 (file)
@@ -9,6 +9,7 @@
 #include "common.h"
 #include "jitinterface.h"
 #include "corjit.h"
+#include "jithost.h"
 #include "eetwain.h"
 #include "eeconfig.h"
 #include "excep.h"
@@ -1332,6 +1333,8 @@ enum JIT_LOAD_STATUS
     JIT_LOAD_STATUS_DONE_LOAD,                         // LoadLibrary of the JIT dll succeeded.
     JIT_LOAD_STATUS_DONE_GET_SXSJITSTARTUP,            // GetProcAddress for "sxsJitStartup" succeeded.
     JIT_LOAD_STATUS_DONE_CALL_SXSJITSTARTUP,           // Calling sxsJitStartup() succeeded.
+    JIT_LOAD_STATUS_DONE_GET_JITSTARTUP,               // GetProcAddress for "jitStartup" succeeded.
+    JIT_LOAD_STATUS_DONE_CALL_JITSTARTUP,              // Calling jitStartup() succeeded.
     JIT_LOAD_STATUS_DONE_GET_GETJIT,                   // GetProcAddress for "getJit" succeeded.
     JIT_LOAD_STATUS_DONE_CALL_GETJIT,                  // Calling getJit() succeeded.
     JIT_LOAD_STATUS_DONE_CALL_GETVERSIONIDENTIFIER,    // Calling ICorJitCompiler::getVersionIdentifier() succeeded.
@@ -1427,6 +1430,18 @@ static void LoadAndInitializeJIT(LPCWSTR pwzJitName, OUT HINSTANCE* phJit, OUT I
 
                 pJitLoadData->jld_status = JIT_LOAD_STATUS_DONE_CALL_SXSJITSTARTUP;
 
+                typedef void (__stdcall* pjitStartup)(ICorJitHost*);
+                pjitStartup jitStartupFn = (pjitStartup) GetProcAddress(*phJit, "jitStartup");
+
+                if (jitStartupFn)
+                {
+                    pJitLoadData->jld_status = JIT_LOAD_STATUS_DONE_GET_JITSTARTUP;
+
+                    (*jitStartupFn)(JitHost::getJitHost());
+
+                    pJitLoadData->jld_status = JIT_LOAD_STATUS_DONE_CALL_JITSTARTUP;
+                }
+
                 typedef ICorJitCompiler* (__stdcall* pGetJitFn)();
                 pGetJitFn getJitFn = (pGetJitFn) GetProcAddress(*phJit, "getJit");
 
@@ -1490,6 +1505,7 @@ static void LoadAndInitializeJIT(LPCWSTR pwzJitName, OUT HINSTANCE* phJit, OUT I
 }
 
 #ifdef FEATURE_MERGE_JIT_AND_ENGINE
+EXTERN_C void __stdcall jitStartup(ICorJitHost* host);
 EXTERN_C ICorJitCompiler* __stdcall getJit();
 #endif // FEATURE_MERGE_JIT_AND_ENGINE
 
@@ -1517,11 +1533,11 @@ BOOL EEJitManager::LoadJIT()
 
 #ifdef FEATURE_MERGE_JIT_AND_ENGINE
 
-    typedef ICorJitCompiler* (__stdcall* pGetJitFn)();
-    pGetJitFn getJitFn = (pGetJitFn) getJit;
     EX_TRY
     {
-        newJitCompiler = (*getJitFn)();
+        jitStartup(JitHost::getJitHost());
+
+        newJitCompiler = getJit();
 
         // We don't need to call getVersionIdentifier(), since the JIT is linked together with the VM.
     }
index 71a86bf..3f10aba 100644 (file)
@@ -836,7 +836,7 @@ private:
 
 /*****************************************************************************/
 
-class EEJitManager :public IJitManager
+class EEJitManager : public IJitManager
 {
 #ifdef DACCESS_COMPILE
     friend class ClrDataAccess;
index d04d978..54c9043 100644 (file)
@@ -13436,100 +13436,6 @@ void CEEInfo::GetProfilingHandle(BOOL                      *pbHookFunction,
     UNREACHABLE();      // only called on derived class.
 }
 
-// Allow access to CLRConfig environment variables from the JIT with
-// out exposing CLR internals. 
-// 
-// Args:
-//     name         - String name being queried for.
-//     defaultValue - Default integer value to return if no value is found.
-//
-// Returns:
-//     Raw string from environment variable.  Caller owns the string.
-//
-int CEEInfo::getIntConfigValue(
-    const wchar_t *name,  int defaultValue
-    )
-{
-    CONTRACTL{
-        SO_TOLERANT;
-        THROWS;
-        GC_TRIGGERS;
-        MODE_PREEMPTIVE;
-    } CONTRACTL_END;
-
-    DWORD ret = defaultValue;
-
-    JIT_TO_EE_TRANSITION();
-
-    // Translate JIT call into runtime configuration query
-    CLRConfig::ConfigDWORDInfo info{ name, defaultValue, CLRConfig::REGUTIL_default };
-
-    // Perform a CLRConfig look up on behalf of the JIT.
-    ret = CLRConfig::GetConfigValue(info);
-
-    EE_TO_JIT_TRANSITION();
-
-    return ret;
-}
-
-// Allow access to CLRConfig environment variables from the JIT with
-// out exposing CLR internals. 
-// 
-// Args:
-//     name - String name being queried for.
-//
-// Returns:
-//     Raw string from environment variable.  Caller owns the string.
-//
-wchar_t *CEEInfo::getStringConfigValue(
-    const wchar_t *name
-    )
-{
-    CONTRACTL{
-        SO_TOLERANT;
-        THROWS;
-        GC_TRIGGERS;
-        MODE_PREEMPTIVE;
-    } CONTRACTL_END;
-
-    wchar_t * returnStr = nullptr;
-
-    JIT_TO_EE_TRANSITION();
-
-    // Translate JIT call into runtime configuration query
-    CLRConfig::ConfigStringInfo info{ name, CLRConfig::REGUTIL_default };
-
-    // Perform a CLRConfig look up on behalf of the JIT.
-    returnStr = CLRConfig::GetConfigValue(info);
-
-    EE_TO_JIT_TRANSITION();
-
-    return returnStr;
-}
-
-// Free runtime allocated CLRConfig strings requrested by the JIT.
-//
-// Args:
-//    value - String to be freed.
-//
-void CEEInfo::freeStringConfigValue(
-    wchar_t *value
-    )
-{
-    CONTRACTL{
-        SO_TOLERANT;
-        THROWS;
-        GC_TRIGGERS;
-        MODE_PREEMPTIVE;
-    } CONTRACTL_END;
-
-    JIT_TO_EE_TRANSITION();
-
-    CLRConfig::FreeConfigString(value);
-
-    EE_TO_JIT_TRANSITION();
-}
-
 #endif // !DACCESS_COMPILE
 
 EECodeInfo::EECodeInfo()
index ce2c7de..215ceda 100644 (file)
@@ -1055,19 +1055,6 @@ public:
 
     DWORD getExpectedTargetArchitecture();
 
-    int getIntConfigValue(
-        const wchar_t *name,
-        int defaultValue
-        );
-
-    wchar_t *getStringConfigValue(
-        const wchar_t *name
-        );
-
-    void freeStringConfigValue(
-        __in_z wchar_t *value
-        );
-
     CEEInfo(MethodDesc * fd = NULL, bool fVerifyOnly = false) :
         m_pOverride(NULL),
         m_pMethodBeingCompiled(fd),
index 44bb274..95655fd 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "utilcode.h"
 #include "corjit.h"
+#include "jithost.h"
 #include "corcompile.h"
 #include "iceefilegen.h"
 #ifdef FEATURE_FUSION
index d6862f2..0b9d0a6 100644 (file)
@@ -3838,34 +3838,3 @@ BOOL ZapInfo::CurrentMethodHasProfileData()
     ICorJitInfo::ProfileBuffer * profileBuffer;
     return SUCCEEDED(getBBProfileData(m_currentMethodHandle, &size, &profileBuffer, NULL));
 }
-
-int ZapInfo::getIntConfigValue(const wchar_t *name, int defaultValue)
-{
-    int ret;
-
-    // Translate JIT call into runtime configuration query
-    CLRConfig::ConfigDWORDInfo info{name, defaultValue, CLRConfig::REGUTIL_default};
-
-    // Perform a CLRConfig look up on behalf of the JIT.
-    ret = CLRConfig::GetConfigValue(info);
-
-    return ret;
-}
-
-wchar_t *ZapInfo::getStringConfigValue(const wchar_t *name)
-{
-    wchar_t *returnStr = nullptr;
-
-    // Translate JIT call into runtime configuration query
-    CLRConfig::ConfigStringInfo info { name, CLRConfig::REGUTIL_default };
-
-    // Perform a CLRConfig look up on behalf of the JIT.
-    returnStr = CLRConfig::GetConfigValue(info);
-
-    return returnStr;
-}
-
-void ZapInfo::freeStringConfigValue(wchar_t *value)
-{
-    CLRConfig::FreeConfigString(value);
-}
index dab1b29..bb1c110 100644 (file)
@@ -693,12 +693,6 @@ public:
     void HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers);
     void ThrowExceptionForJitResult(HRESULT result);
     void ThrowExceptionForHelper(const CORINFO_HELPER_DESC * throwHelper);
-
-    int getIntConfigValue(const wchar_t *name, int defaultValue);
-
-    wchar_t *getStringConfigValue(const wchar_t *name);
-
-    void freeStringConfigValue(__in_z wchar_t *value);
 };
 
 #endif // __ZAPINFO_H__
index 6d559d3..77bb114 100644 (file)
@@ -772,6 +772,13 @@ void Zapper::LoadAndInitializeJITForNgen(LPCWSTR pwzJitName, OUT HINSTANCE* phJi
     (*sxsJitStartupFn) (cccallbacks);
 #endif
 
+    typedef void (__stdcall* pJitStartup)(ICorJitHost* host);
+    pJitStartup jitStartupFn = (pJitStartup)GetProcAddress(*phJit, "jitStartup");
+    if (jitStartupFn != nullptr)
+    {
+        jitStartupFn(JitHost::getJitHost());
+    }
+
     //get the appropriate compiler interface
     typedef ICorJitCompiler* (__stdcall* pGetJitFn)();
     pGetJitFn getJitFn = (pGetJitFn) GetProcAddress(*phJit, "getJit");
@@ -882,6 +889,7 @@ void Zapper::InitEE(BOOL fForceDebug, BOOL fForceProfile, BOOL fForceInstrument)
     //
 
 #ifdef FEATURE_MERGE_JIT_AND_ENGINE
+    jitStartup(JitHost::getJitHost());
     m_pJitCompiler = getJit();
 
     if (m_pJitCompiler == NULL)