diff options
Diffstat (limited to 'src/vm/codeman.cpp')
-rw-r--r-- | src/vm/codeman.cpp | 158 |
1 files changed, 104 insertions, 54 deletions
diff --git a/src/vm/codeman.cpp b/src/vm/codeman.cpp index 89084dbe85..98f0e53d3d 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" @@ -1183,6 +1187,7 @@ EEJitManager::EEJitManager() // CRST_TAKEN_DURING_SHUTDOWN - We take this lock during shutdown if ETW is on (to do rundown) m_CodeHeapCritSec( CrstSingleUseLock, CrstFlags(CRST_UNSAFE_ANYMODE|CRST_DEBUGGER_THREAD|CRST_TAKEN_DURING_SHUTDOWN)), + m_CPUCompileFlags(), m_EHClauseCritSec( CrstSingleUseLock ) { CONTRACTL { @@ -1196,41 +1201,34 @@ 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; m_AltJITRequired = false; #endif - m_dwCPUCompileFlags = 0; - m_cleanupList = NULL; } -#if defined(_TARGET_AMD64_) -extern "C" DWORD __stdcall getcpuid(DWORD arg, unsigned char result[16]); -extern "C" DWORD __stdcall xmmYmmStateSupport(); +#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) bool DoesOSSupportAVX() { + LIMITED_METHOD_CONTRACT; + #ifndef FEATURE_PAL // On Windows we have an api(GetEnabledXStateFeatures) to check if AVX is supported typedef DWORD64 (WINAPI *PGETENABLEDXSTATEFEATURES)(); PGETENABLEDXSTATEFEATURES pfnGetEnabledXStateFeatures = NULL; - // Probe ApiSet first - HMODULE hMod = WszLoadLibraryEx(W("api-ms-win-core-xstate-l2-1-0.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - - if (hMod == NULL) - { - // On older OS's where apiset is not present probe kernel32 - hMod = WszLoadLibraryEx(WINDOWS_KERNEL32_DLLNAME_W, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); - if(hMod = NULL) - return FALSE; - } + HMODULE hMod = WszLoadLibraryEx(WINDOWS_KERNEL32_DLLNAME_W, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if(hMod = NULL) + return FALSE; pfnGetEnabledXStateFeatures = (PGETENABLEDXSTATEFEATURES)GetProcAddress(hMod, "GetEnabledXStateFeatures"); @@ -1249,7 +1247,7 @@ bool DoesOSSupportAVX() return TRUE; } -#endif // defined(_TARGET_AMD64_) +#endif // defined(_TARGET_X86_) || defined(_TARGET_AMD64_) void EEJitManager::SetCpuInfo() { @@ -1259,7 +1257,7 @@ void EEJitManager::SetCpuInfo() // NOTE: This function needs to be kept in sync with Zapper::CompileAssembly() // - DWORD dwCPUCompileFlags = 0; + CORJIT_FLAGS CPUCompileFlags; #if defined(_TARGET_X86_) // NOTE: if you're adding any flags here, you probably should also be doing it @@ -1270,7 +1268,7 @@ void EEJitManager::SetCpuInfo() switch (CPU_X86_FAMILY(cpuInfo.dwCPUType)) { case CPU_X86_PENTIUM_4: - dwCPUCompileFlags |= CORJIT_FLG_TARGET_P4; + CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_TARGET_P4); break; default: break; @@ -1278,15 +1276,17 @@ void EEJitManager::SetCpuInfo() if (CPU_X86_USE_CMOV(cpuInfo.dwFeatures)) { - dwCPUCompileFlags |= CORJIT_FLG_USE_CMOV | - CORJIT_FLG_USE_FCOMI; + CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_CMOV); + CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_FCOMI); } if (CPU_X86_USE_SSE2(cpuInfo.dwFeatures)) { - dwCPUCompileFlags |= CORJIT_FLG_USE_SSE2; + CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE2); } -#elif defined(_TARGET_AMD64_) +#endif // _TARGET_X86_ + +#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) unsigned char buffer[16]; DWORD maxCpuId = getcpuid(0, buffer); if (maxCpuId >= 0) @@ -1295,17 +1295,17 @@ void EEJitManager::SetCpuInfo() // It returns the resulting eax in buffer[0-3], ebx in buffer[4-7], ecx in buffer[8-11], // and edx in buffer[12-15]. // We will set the following flags: - // CORJIT_FLG_USE_SSE3_4 if the following feature bits are set (input EAX of 1) + // CORJIT_FLAG_USE_SSE3_4 if the following feature bits are set (input EAX of 1) // SSE3 - ECX bit 0 (buffer[8] & 0x01) // SSSE3 - ECX bit 9 (buffer[9] & 0x02) // SSE4.1 - ECX bit 19 (buffer[10] & 0x08) // SSE4.2 - ECX bit 20 (buffer[10] & 0x10) - // CORJIT_FLG_USE_AVX if the following feature bits are set (input EAX of 1), and xmmYmmStateSupport returns 1: + // CORJIT_FLAG_USE_AVX if the following feature bits are set (input EAX of 1), and xmmYmmStateSupport returns 1: // OSXSAVE - ECX bit 27 (buffer[11] & 0x08) // AVX - ECX bit 28 (buffer[11] & 0x10) - // CORJIT_FLG_USE_AVX2 if the following feature bit is set (input EAX of 0x07 and input ECX of 0): + // CORJIT_FLAG_USE_AVX2 if the following feature bit is set (input EAX of 0x07 and input ECX of 0): // AVX2 - EBX bit 5 (buffer[4] & 0x20) - // CORJIT_FLG_USE_AVX_512 is not currently set, but defined so that it can be used in future without + // CORJIT_FLAG_USE_AVX_512 is not currently set, but defined so that it can be used in future without // synchronously updating VM and JIT. (void) getcpuid(1, buffer); // If SSE2 is not enabled, there is no point in checking the rest. @@ -1318,7 +1318,7 @@ void EEJitManager::SetCpuInfo() ((buffer[10] & 0x08) != 0) && // SSE4.1 ((buffer[10] & 0x10) != 0)) // SSE4.2 { - dwCPUCompileFlags |= CORJIT_FLG_USE_SSE3_4; + CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_SSE3_4); } if ((buffer[11] & 0x18) == 0x18) { @@ -1326,13 +1326,13 @@ void EEJitManager::SetCpuInfo() { if (xmmYmmStateSupport() == 1) { - dwCPUCompileFlags |= CORJIT_FLG_USE_AVX; + CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX); if (maxCpuId >= 0x07) { (void) getcpuid(0x07, buffer); if ((buffer[4] & 0x20) != 0) { - dwCPUCompileFlags |= CORJIT_FLG_USE_AVX2; + CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX2); } } } @@ -1341,13 +1341,13 @@ void EEJitManager::SetCpuInfo() static ConfigDWORD fFeatureSIMD; if (fFeatureSIMD.val(CLRConfig::EXTERNAL_FeatureSIMD) != 0) { - dwCPUCompileFlags |= CORJIT_FLG_FEATURE_SIMD; + CPUCompileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_FEATURE_SIMD); } } } -#endif // defined(_TARGET_AMD64_) +#endif // defined(_TARGET_X86_) || defined(_TARGET_AMD64_) - m_dwCPUCompileFlags = dwCPUCompileFlags; + m_CPUCompileFlags = CPUCompileFlags; } // Define some data that we can use to get a better idea of what happened when we get a Watson dump that indicates the JIT failed to load. @@ -1356,7 +1356,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 +1432,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 +1624,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 +1633,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 +1655,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 +1678,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; @@ -1689,7 +1711,7 @@ BOOL EEJitManager::LoadJIT() { // Now, load the compat jit and initialize it. - LPWSTR pwzJitName = MAKEDLLNAME_W(L"compatjit"); + LPCWSTR pwzJitName = MAKEDLLNAME_W(W("compatjit")); // Note: if the compatjit fails to load, we ignore it, and continue to use the main JIT for // everything. You can imagine a policy where if the user requests the compatjit, and we fail @@ -1702,10 +1724,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 @@ -3397,7 +3422,7 @@ void ExecutionManager::CleanupCodeHeaps() } CONTRACTL_END; - _ASSERTE (g_fProcessDetach || (GCHeap::IsGCInProgress() && ::IsGCThread())); + _ASSERTE (g_fProcessDetach || (GCHeapUtilities::IsGCInProgress() && ::IsGCThread())); GetEEJitManager()->CleanupCodeHeaps(); } @@ -3411,7 +3436,17 @@ void EEJitManager::CleanupCodeHeaps() } CONTRACTL_END; - _ASSERTE (g_fProcessDetach || (GCHeap::IsGCInProgress() && ::IsGCThread())); + _ASSERTE (g_fProcessDetach || (GCHeapUtilities::IsGCInProgress() && ::IsGCThread())); + + // Quick out, don't even take the lock if we have not cleanup to do. + // This is important because ETW takes the CodeHeapLock when it is doing + // rundown, and if there are many JIT compiled methods, this can take a while. + // Because cleanup is called synchronously before a GC, this means GCs get + // blocked while ETW is doing rundown. By not taking the lock we avoid + // this stall most of the time since cleanup is rare, and ETW rundown is rare + // the likelihood of both is very very rare. + if (m_cleanupList == NULL) + return; CrstHolder ch(&m_CodeHeapCritSec); @@ -4359,7 +4394,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 @@ -4451,7 +4501,7 @@ RangeSection* ExecutionManager::GetRangeSection(TADDR addr) // Unless we are on an MP system with many cpus // where this sort of caching actually diminishes scaling during server GC // due to many processors writing to a common location - if (g_SystemInfo.dwNumberOfProcessors < 4 || !GCHeap::IsServerHeap() || !GCHeap::IsGCInProgress()) + if (g_SystemInfo.dwNumberOfProcessors < 4 || !GCHeapUtilities::IsServerHeap() || !GCHeapUtilities::IsGCInProgress()) pHead->pLastUsed = pLast; #endif @@ -6104,12 +6154,12 @@ __forceinline bool Nirvana_PrintMethodDescWorker(__in_ecount(iBuffer) char * szB if (*pNamespace != 0) { - if(FAILED(StringCchPrintfA(szBuffer, iBuffer, "%s.%s.%s", pNamespace, pClassName, pSigString))) + if (_snprintf_s(szBuffer, iBuffer, _TRUNCATE, "%s.%s.%s", pNamespace, pClassName, pSigString) == -1) return false; } else { - if(FAILED(StringCchPrintfA(szBuffer, iBuffer, "%s.%s", pClassName, pSigString))) + if (_snprintf_s(szBuffer, iBuffer, _TRUNCATE, "%s.%s", pClassName, pSigString) == -1) return false; } |