summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBruce Forstall <brucefo@microsoft.com>2016-10-04 15:12:46 -0700
committerBruce Forstall <brucefo@microsoft.com>2016-10-06 11:43:49 -0700
commitc47362766e24ab4a7195fa1fb851d254c7b84373 (patch)
treece2b2230f63b387856c81c026b4dbcef589020bb /src
parent920bf1330d0148fc5a277d7ea18f4b7c95c89258 (diff)
downloadcoreclr-c47362766e24ab4a7195fa1fb851d254c7b84373.tar.gz
coreclr-c47362766e24ab4a7195fa1fb851d254c7b84373.tar.bz2
coreclr-c47362766e24ab4a7195fa1fb851d254c7b84373.zip
Enable legacy JIT fallback for CoreCLR on Windows x86
This is to support the eventual case where RyuJIT/x86 becomes the default x86 JIT, but we support fallback to the older, legacy JIT32/x86 (which will be renamed compatjit.dll). This uses the same mechanism that was built for .NET 4.6 when RyuJIT/x64 was shipped, and allowed fallback to JIT64 as compatjit.dll. However, we use a different configuration name to avoid conflicting with the .NET 4.6 COMPlus_useLegacy name (and unintentionally causing users to fall back to JIT64 with their .NET 4.6 apps). The COMPlus variable is COMPlus_UseWindowsX86CoreLegacyJit=1. For the dotnet.exe host, you can set `"System.JIT.UseWindowsX86CoreLegacyJit": true` in the "configProperties" section of the app.runtimeconfig.json file. There is a new COMPlus_RequireLegacyJit=1 option to aid testing JIT fallback.
Diffstat (limited to 'src')
-rw-r--r--src/inc/clrconfigvalues.h6
-rw-r--r--src/vm/codeman.cpp78
-rw-r--r--src/vm/codeman.h8
-rw-r--r--src/vm/jitinterface.cpp7
4 files changed, 82 insertions, 17 deletions
diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h
index 1bd04197f5..3e166da9cb 100644
--- a/src/inc/clrconfigvalues.h
+++ b/src/inc/clrconfigvalues.h
@@ -477,6 +477,12 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_UseLegacyJit, W("useLegacyJit"), 0, "Set to 1
RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_DisableNativeImageLoadList, W("DisableNativeImageLoadList"), "Refuse to load native images corresponding to one of the assemblies on this semicolon-delimited list of assembly names.", CLRConfig::REGUTIL_default)
#endif
+#if defined(FEATURE_CORECLR) && defined(_TARGET_X86_)
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_UseWindowsX86CoreLegacyJit, W("UseWindowsX86CoreLegacyJit"), 0, "Set to 1 to do all JITing with compatjit.dll. Only applicable to Windows x86 .NET Core.")
+#endif
+
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_RequireLegacyJit, W("RequireLegacyJit"), 0, "Set to 1 to require the use of legacy JIT (via COMPlus_useLegacyJit=1 or COMPlus_UseWindowsX86CoreLegacyJit=1).")
+
CONFIG_STRING_INFO_EX(INTERNAL_JitValNumCSE, W("JitValNumCSE"), "Enables ValNum CSE for the specified methods", CLRConfig::REGUTIL_default)
CONFIG_STRING_INFO_EX(INTERNAL_JitLexicalCSE, W("JitLexicalCSE"), "Enables Lexical CSE for the specified methods", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO_EX(INTERNAL_JitNoCSE, W("JitNoCSE"), 0, "", CLRConfig::REGUTIL_default)
diff --git a/src/vm/codeman.cpp b/src/vm/codeman.cpp
index 88bfd58e93..444dcf4fef 100644
--- a/src/vm/codeman.cpp
+++ b/src/vm/codeman.cpp
@@ -31,6 +31,10 @@
#include "debuginfostore.h"
#include "strsafe.h"
+#ifdef FEATURE_CORECLR
+#include "configuration.h"
+#endif
+
#ifdef _WIN64
#define CHECK_DUPLICATED_STRUCT_LAYOUTS
#include "../debug/daccess/fntableaccess.h"
@@ -1196,9 +1200,11 @@ EEJitManager::EEJitManager()
#ifdef _TARGET_AMD64_
m_pEmergencyJumpStubReserveList = NULL;
#endif
-#ifdef _TARGET_AMD64_
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
m_JITCompilerOther = NULL;
#endif
+ m_fLegacyJitUsed = FALSE;
+
#ifdef ALLOW_SXS_JIT
m_alternateJit = NULL;
m_AltJITCompiler = NULL;
@@ -1356,7 +1362,7 @@ void EEJitManager::SetCpuInfo()
enum JIT_LOAD_JIT_ID
{
JIT_LOAD_MAIN = 500, // The "main" JIT. Normally, this is named "clrjit.dll". Start at a number that is somewhat uncommon (i.e., not zero or 1) to help distinguish from garbage, in process dumps.
- JIT_LOAD_LEGACY, // The "legacy" JIT. Normally, this is named "compatjit.dll" (aka, JIT64). This only applies to AMD64.
+ JIT_LOAD_LEGACY, // The "legacy" JIT. Normally, this is named "compatjit.dll". This applies to AMD64 on Windows desktop, or x86 on Windows .NET Core.
JIT_LOAD_ALTJIT // An "altjit". By default, named "protojit.dll". Used both internally, as well as externally for JIT CTP builds.
};
@@ -1432,33 +1438,43 @@ static void LoadAndInitializeJIT(LPCWSTR pwzJitName, OUT HINSTANCE* phJit, OUT I
#ifdef FEATURE_CORECLR
PathString CoreClrFolderHolder;
extern HINSTANCE g_hThisInst;
+ bool havePath = false;
#if !defined(FEATURE_MERGE_JIT_AND_ENGINE)
if (g_CLRJITPath != nullptr)
{
- // If we have been asked to load a specific JIT binary, load it.
+ // If we have been asked to load a specific JIT binary, load from that path.
+ // The main JIT load will use exactly that name because pwzJitName will have
+ // been computed as the last component of g_CLRJITPath by ExecutionManager::GetJitName().
+ // Non-primary JIT names (such as compatjit or altjit) will be loaded from the
+ // same directory.
+ // (Ideally, g_CLRJITPath would just be the JIT path without the filename component,
+ // but that's not how the JIT_PATH variable was originally defined.)
CoreClrFolderHolder.Set(g_CLRJITPath);
+ havePath = true;
}
else
#endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE)
if (WszGetModuleFileName(g_hThisInst, CoreClrFolderHolder))
{
// Load JIT from next to CoreCLR binary
+ havePath = true;
+ }
+
+ if (havePath && !CoreClrFolderHolder.IsEmpty())
+ {
SString::Iterator iter = CoreClrFolderHolder.End();
BOOL findSep = CoreClrFolderHolder.FindBack(iter, DIRECTORY_SEPARATOR_CHAR_W);
if (findSep)
{
SString sJitName(pwzJitName);
CoreClrFolderHolder.Replace(iter + 1, CoreClrFolderHolder.End() - (iter + 1), sJitName);
- }
- }
- if (!CoreClrFolderHolder.IsEmpty())
- {
- *phJit = CLRLoadLibrary(CoreClrFolderHolder.GetUnicode());
- if (*phJit != NULL)
- {
- hr = S_OK;
+ *phJit = CLRLoadLibrary(CoreClrFolderHolder.GetUnicode());
+ if (*phJit != NULL)
+ {
+ hr = S_OK;
+ }
}
}
@@ -1614,7 +1630,7 @@ BOOL EEJitManager::LoadJIT()
#else // !FEATURE_MERGE_JIT_AND_ENGINE
m_JITCompiler = NULL;
-#ifdef _TARGET_AMD64_
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
m_JITCompilerOther = NULL;
#endif
@@ -1623,8 +1639,8 @@ BOOL EEJitManager::LoadJIT()
// Set as a courtesy to code:CorCompileGetRuntimeDll
s_ngenCompilerDll = m_JITCompiler;
-
-#if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE) && !defined(FEATURE_CORECLR)
+
+#if (defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE) && !defined(FEATURE_CORECLR)) || (defined(_TARGET_X86_) && defined(FEATURE_CORECLR))
// If COMPlus_UseLegacyJit=1, then we fall back to compatjit.dll.
//
// This fallback mechanism was introduced for Visual Studio "14" Preview, when JIT64 (the legacy JIT) was replaced with
@@ -1645,8 +1661,16 @@ BOOL EEJitManager::LoadJIT()
// is set, we also must use JIT64 for all NGEN compilations as well.
//
// See the document "RyuJIT Compatibility Fallback Specification.docx" for details.
+ //
+ // For .NET Core 1.2, RyuJIT for x86 is the primary jit (clrjit.dll) and JIT32 for x86 is the fallback, legacy JIT (compatjit.dll).
+ // Thus, the COMPlus_useLegacyJit=1 mechanism has been enabled for x86 CoreCLR. This scenario does not have the UseRyuJIT
+ // registry key, nor the AppX binder mode.
+#if defined(FEATURE_CORECLR)
+ bool fUseRyuJit = true;
+#else
bool fUseRyuJit = UseRyuJit();
+#endif
if ((!IsCompilationProcess() || !fUseRyuJit) && // Use RyuJIT for all NGEN, unless we're falling back to JIT64 for everything.
(newJitCompiler != nullptr)) // the main JIT must successfully load before we try loading the fallback JIT
@@ -1660,7 +1684,11 @@ BOOL EEJitManager::LoadJIT()
if (!fUsingCompatJit)
{
+#if defined(FEATURE_CORECLR)
+ DWORD useLegacyJit = Configuration::GetKnobBooleanValue(W("System.JIT.UseWindowsX86CoreLegacyJit"), CLRConfig::EXTERNAL_UseWindowsX86CoreLegacyJit);
+#else
DWORD useLegacyJit = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_UseLegacyJit); // uncached access, since this code is run no more than one time
+#endif
if (useLegacyJit == 1)
{
fUsingCompatJit = TRUE;
@@ -1702,10 +1730,13 @@ BOOL EEJitManager::LoadJIT()
// Tell the main JIT to fall back to the "fallback" JIT compiler, in case some
// obfuscator tries to directly call the main JIT's getJit() function.
newJitCompiler->setRealJit(fallbackICorJitCompiler);
+
+ // Now, the compat JIT will be used.
+ m_fLegacyJitUsed = TRUE;
}
}
}
-#endif // defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE) && !defined(FEATURE_CORECLR)
+#endif // (defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE) && !defined(FEATURE_CORECLR)) || (defined(_TARGET_X86_) && defined(FEATURE_CORECLR))
#endif // !FEATURE_MERGE_JIT_AND_ENGINE
@@ -4359,7 +4390,22 @@ LPCWSTR ExecutionManager::GetJitName()
LPCWSTR pwzJitName = NULL;
-#if !defined(FEATURE_CORECLR)
+#if defined(FEATURE_CORECLR)
+#if !defined(CROSSGEN_COMPILE)
+ if (g_CLRJITPath != nullptr)
+ {
+ const wchar_t* p = wcsrchr(g_CLRJITPath, DIRECTORY_SEPARATOR_CHAR_W);
+ if (p != nullptr)
+ {
+ pwzJitName = p + 1; // Return just the filename, not the directory name
+ }
+ else
+ {
+ pwzJitName = g_CLRJITPath;
+ }
+ }
+#endif // !defined(CROSSGEN_COMPILE)
+#else // !FEATURE_CORECLR
// Try to obtain a name for the jit library from the env. variable
IfFailThrow(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitName, const_cast<LPWSTR *>(&pwzJitName)));
#endif // !FEATURE_CORECLR
diff --git a/src/vm/codeman.h b/src/vm/codeman.h
index aaf1be8bbf..f4e04b8c67 100644
--- a/src/vm/codeman.h
+++ b/src/vm/codeman.h
@@ -1193,10 +1193,16 @@ public:
public:
ICorJitCompiler * m_jit;
HINSTANCE m_JITCompiler;
-#ifdef _TARGET_AMD64_
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
HINSTANCE m_JITCompilerOther; // Stores the handle of the legacy JIT, if one is loaded.
#endif
+ // TRUE if the legacy/compat JIT was loaded successfully and will be used.
+ // This is available in all builds so if COMPlus_RequireLegacyJit=1 is set in a test,
+ // the test will fail in any build where the legacy JIT is not loaded, even if legacy
+ // fallback is not available in that build. This prevents unexpected silent successes.
+ BOOL m_fLegacyJitUsed;
+
#ifdef ALLOW_SXS_JIT
//put these at the end so that we don't mess up the offsets in the DAC.
ICorJitCompiler * m_alternateJit;
diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
index 2d28a1b37a..c39f9b31fd 100644
--- a/src/vm/jitinterface.cpp
+++ b/src/vm/jitinterface.cpp
@@ -12415,6 +12415,13 @@ PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* ILHeader,
EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
#endif // ALLOW_SXS_JIT
}
+
+ // If no compatjit wasn't used, but the user (normally a test case) requires that one is used, then fail.
+ // This is analogous to ZapRequire.
+ if (!jitMgr->m_fLegacyJitUsed && (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_RequireLegacyJit) == 1))
+ {
+ EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to use legacy JIT compiler with RequireLegacyJit set"));
+ }
#endif // CROSSGEN_COMPILE
#ifdef _DEBUG