summaryrefslogtreecommitdiff
path: root/src/vm
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-05-06 23:43:46 -0700
committerJan Kotas <jkotas@microsoft.com>2015-05-07 12:03:00 -0700
commit484a2cf0b0c4e304a5093ec26e07fe41f8896c3c (patch)
tree348b56df4cdb235bb87ba9bc9118711c8db13bfd /src/vm
parentc6efc7047edb38075310cfef8ea28b91717b8108 (diff)
downloadcoreclr-484a2cf0b0c4e304a5093ec26e07fe41f8896c3c.tar.gz
coreclr-484a2cf0b0c4e304a5093ec26e07fe41f8896c3c.tar.bz2
coreclr-484a2cf0b0c4e304a5093ec26e07fe41f8896c3c.zip
Merge changes from parent branch
[tfs-changeset: 1466545]
Diffstat (limited to 'src/vm')
-rw-r--r--src/vm/ClrEtwAll.man84
-rw-r--r--src/vm/appdomain.hpp3
-rw-r--r--src/vm/assembly.cpp51
-rw-r--r--src/vm/assembly.hpp4
-rw-r--r--src/vm/ceeload.cpp10
-rw-r--r--src/vm/clrtracelogging.cpp41
-rw-r--r--src/vm/codeman.cpp2
-rw-r--r--src/vm/compile.cpp19
-rw-r--r--src/vm/coreassemblyspec.cpp2
-rw-r--r--src/vm/crossgen/wks_crossgen.nativeproj4
-rw-r--r--src/vm/domainfile.cpp7
-rw-r--r--src/vm/dwreport.cpp98
-rw-r--r--src/vm/eetwain.cpp51
-rw-r--r--src/vm/eventtrace.cpp139
-rw-r--r--src/vm/exceptionhandling.cpp53
-rw-r--r--src/vm/exceptionhandling.h9
-rw-r--r--src/vm/gcenv.cpp108
-rw-r--r--src/vm/i386/excepx86.cpp14
-rw-r--r--src/vm/i386/stublinkerx86.cpp8
-rw-r--r--src/vm/methodtablebuilder.cpp14
-rw-r--r--src/vm/pefile.cpp20
-rw-r--r--src/vm/pefile.h1
-rw-r--r--src/vm/pefile.inl22
-rw-r--r--src/vm/peimage.cpp9
-rw-r--r--src/vm/stackwalk.cpp27
-rw-r--r--src/vm/stackwalk.h13
-rw-r--r--src/vm/threaddebugblockinginfo.cpp7
-rw-r--r--src/vm/threads.cpp15
-rw-r--r--src/vm/threads.h2
-rw-r--r--src/vm/vm.settings1
-rw-r--r--src/vm/wks/wks.targets3
31 files changed, 766 insertions, 75 deletions
diff --git a/src/vm/ClrEtwAll.man b/src/vm/ClrEtwAll.man
index ea3c4da935..71b7346878 100644
--- a/src/vm/ClrEtwAll.man
+++ b/src/vm/ClrEtwAll.man
@@ -71,6 +71,8 @@
message="$(string.RuntimePublisher.ThreadTransferKeywordMessage)" symbol="CLR_THREADTRANSFER_KEYWORD"/>
<keyword name="DebuggerKeyword" mask="0x100000000"
message="$(string.RuntimePublisher.DebuggerKeywordMessage)" symbol="CLR_DEBUGGER_KEYWORD" />
+ <keyword name="MonitoringKeyword" mask="0x200000000"
+ message="$(string.RuntimePublisher.MonitoringKeywordMessage)" symbol="CLR_MONITORING_KEYWORD" />
</keywords>
<!--Tasks-->
<tasks>
@@ -163,7 +165,28 @@
</opcodes>
</task>
- <task name="Contention" symbol="CLR_CONTENTION_TASK"
+ <task name="ExceptionCatch" symbol="CLR_EXCEPTION_CATCH_TASK"
+ value="27" eventGUID="{5BBF9499-1715-4658-88DC-AFD7690A8711}"
+ message="$(string.RuntimePublisher.ExceptionCatchTaskMessage)">
+ <opcodes>
+ </opcodes>
+ </task>
+
+ <task name="ExceptionFinally" symbol="CLR_EXCEPTION_FINALLY_TASK"
+ value="28" eventGUID="{9565BC31-300F-4EA2-A532-30BCE9A14199}"
+ message="$(string.RuntimePublisher.ExceptionFinallyTaskMessage)">
+ <opcodes>
+ </opcodes>
+ </task>
+
+ <task name="ExceptionFilter" symbol="CLR_EXCEPTION_FILTER_TASK"
+ value="29" eventGUID="{72E72606-BB71-4290-A242-D5F36CE5312E}"
+ message="$(string.RuntimePublisher.ExceptionFilterTaskMessage)">
+ <opcodes>
+ </opcodes>
+ </task>
+
+ <task name="Contention" symbol="CLR_CONTENTION_TASK"
value="8" eventGUID="{561410f5-a138-4ab3-945e-516483cddfbc}"
message="$(string.RuntimePublisher.ContentionTaskMessage)">
<opcodes>
@@ -339,6 +362,7 @@
<opcodes>
</opcodes>
</task>
+ <!--Next available ID is 30-->
</tasks>
<!--Maps-->
<maps>
@@ -1326,6 +1350,21 @@
</UserData>
</template>
+ <template tid="ExceptionHandling">
+ <data name="EntryEIP" inType="win:UInt64" outType="win:HexInt64" />
+ <data name="MethodID" inType="win:UInt64" outType="win:HexInt64" />
+ <data name="MethodName" inType="win:UnicodeString" />
+ <data name="ClrInstanceID" inType="win:UInt16" />
+ <UserData>
+ <ExceptionHandling xmlns="myNs">
+ <EntryEIP> %1 </EntryEIP>
+ <MethodID> %2 </MethodID>
+ <MethodName> %3 </MethodName>
+ <ClrInstanceID> %4 </ClrInstanceID>
+ </ExceptionHandling>
+ </UserData>
+ </template>
+
<template tid="Contention">
<data name="ContentionFlags" inType="win:UInt8" map="ContentionFlagsMap" />
<data name="ClrInstanceID" inType="win:UInt16" />
@@ -2660,10 +2699,45 @@
symbol="ExceptionThrown" message="$(string.RuntimePublisher.ExceptionExceptionThrownEventMessage)"/>
<event value="80" version="1" level="win:Error" template="Exception"
- keywords ="ExceptionKeyword" opcode="win:Start"
+ keywords ="ExceptionKeyword MonitoringKeyword" opcode="win:Start"
task="Exception"
symbol="ExceptionThrown_V1" message="$(string.RuntimePublisher.ExceptionExceptionThrown_V1EventMessage)"/>
+ <event value="250" version="0" level="win:Informational" template="ExceptionHandling"
+ keywords ="ExceptionKeyword" opcode="win:Start"
+ task="ExceptionCatch"
+ symbol="ExceptionCatchStart" message="$(string.RuntimePublisher.ExceptionExceptionHandlingEventMessage)"/>
+
+ <event value="251" version="0" level="win:Informational"
+ keywords ="ExceptionKeyword" opcode="win:Stop"
+ task="ExceptionCatch"
+ symbol="ExceptionCatchStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/>
+
+ <event value="252" version="0" level="win:Informational" template="ExceptionHandling"
+ keywords ="ExceptionKeyword" opcode="win:Start"
+ task="ExceptionFinally"
+ symbol="ExceptionFinallyStart" message="$(string.RuntimePublisher.ExceptionExceptionHandlingEventMessage)"/>
+
+ <event value="253" version="0" level="win:Informational"
+ keywords ="ExceptionKeyword" opcode="win:Stop"
+ task="ExceptionFinally"
+ symbol="ExceptionFinallyStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/>
+
+ <event value="254" version="0" level="win:Informational" template="ExceptionHandling"
+ keywords ="ExceptionKeyword" opcode="win:Start"
+ task="ExceptionFilter"
+ symbol="ExceptionFilterStart" message="$(string.RuntimePublisher.ExceptionExceptionHandlingEventMessage)"/>
+
+ <event value="255" version="0" level="win:Informational"
+ keywords ="ExceptionKeyword" opcode="win:Stop"
+ task="ExceptionFilter"
+ symbol="ExceptionFilterStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/>
+
+ <event value="256" version="0" level="win:Informational"
+ keywords ="ExceptionKeyword" opcode="win:Stop"
+ task="Exception"
+ symbol="ExceptionThrownStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/>
+
<!-- CLR Contention events -->
<event value="81" version="0" level="win:Informational"
opcode="win:Start"
@@ -6118,6 +6192,8 @@
<string id="RuntimePublisher.ThreadRunningEventMessage" value="ID=%1;%nClrInstanceID=%s" />
<string id="RuntimePublisher.ExceptionExceptionThrownEventMessage" value="NONE" />
<string id="RuntimePublisher.ExceptionExceptionThrown_V1EventMessage" value="ExceptionType=%1;%nExceptionMessage=%2;%nExceptionEIP=%3;%nExceptionHRESULT=%4;%nExceptionFlags=%5;%nClrInstanceID=%6" />
+ <string id="RuntimePublisher.ExceptionExceptionHandlingEventMessage" value="EntryEIP=%1;%nMethodID=%2;%nMethodName=%3;%nClrInstanceID=%4" />
+ <string id="RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage" value="NONE" />
<string id="RuntimePublisher.ContentionStartEventMessage" value="NONE" />
<string id="RuntimePublisher.ContentionStart_V1EventMessage" value="ContentionFlags=%1;%nClrInstanceID=%2"/>
<string id="RuntimePublisher.ContentionStopEventMessage" value="ContentionFlags=%1;%nClrInstanceID=%2"/>
@@ -6321,6 +6397,9 @@
<string id="RuntimePublisher.ThreadPoolWorkerThreadRetirementTaskMessage" value="ThreadPoolWorkerThreadRetirement" />
<string id="RuntimePublisher.ThreadPoolWorkerThreadAdjustmentTaskMessage" value="ThreadPoolWorkerThreadAdjustment" />
<string id="RuntimePublisher.ExceptionTaskMessage" value="Exception" />
+ <string id="RuntimePublisher.ExceptionCatchTaskMessage" value="ExceptionCatch" />
+ <string id="RuntimePublisher.ExceptionFinallyTaskMessage" value="ExceptionFinally" />
+ <string id="RuntimePublisher.ExceptionFilterTaskMessage" value="ExceptionFilter" />
<string id="RuntimePublisher.ContentionTaskMessage" value="Contention" />
<string id="RuntimePublisher.MethodTaskMessage" value="Method" />
<string id="RuntimePublisher.LoaderTaskMessage" value="Loader" />
@@ -6609,6 +6688,7 @@
<string id="RuntimePublisher.GCHandleKeywordMessage" value="GCHandle" />
<string id="RuntimePublisher.ThreadTransferKeywordMessage" value="ThreadTransfer" />
<string id="RuntimePublisher.DebuggerKeywordMessage" value="Debugger" />
+ <string id="RuntimePublisher.MonitoringKeywordMessage" value="Monitoring" />
<string id="RundownPublisher.LoaderKeywordMessage" value="Loader" />
<string id="RundownPublisher.JitKeywordMessage" value="Jit" />
<string id="RundownPublisher.JittedMethodILToNativeMapRundownKeywordMessage" value="JittedMethodILToNativeMapRundown" />
diff --git a/src/vm/appdomain.hpp b/src/vm/appdomain.hpp
index a48cafbac9..4be9dcc4b1 100644
--- a/src/vm/appdomain.hpp
+++ b/src/vm/appdomain.hpp
@@ -2032,6 +2032,7 @@ public:
#ifndef FEATURE_CORECLR
inline BOOL AppDomainManagerSetFromConfig();
Assembly *GetAppDomainManagerEntryAssembly();
+ void ComputeTargetFrameworkName();
#endif // FEATURE_CORECLR
#if defined(FEATURE_CORECLR) && defined(FEATURE_COMINTEROP)
@@ -4520,7 +4521,7 @@ public:
#endif // DACCESS_COMPILE
#ifndef FEATURE_CORECLR
- static void ExecuteMainMethod(HMODULE hMod, __in_opt LPWSTR path = NULL);
+ static void ExecuteMainMethod(HMODULE hMod, __in_opt LPWSTR path = NULL);
#endif
static void ActivateApplication(int *pReturnValue);
diff --git a/src/vm/assembly.cpp b/src/vm/assembly.cpp
index 3c41c45ddb..ba65f13bfa 100644
--- a/src/vm/assembly.cpp
+++ b/src/vm/assembly.cpp
@@ -73,6 +73,10 @@
#include "eventmsg.h"
#endif
+#ifdef FEATURE_TRACELOGGING
+#include "clrtracelogging.h"
+#endif // FEATURE_TRACELOGGING
+
// Define these macro's to do strict validation for jit lock and class init entry leaks.
// This defines determine if the asserts that verify for these leaks are defined or not.
@@ -179,6 +183,43 @@ Assembly::Assembly(BaseDomain *pDomain, PEAssembly* pFile, DebuggerAssemblyContr
// which is used in AssemblyBuilder.InitManifestModule
#define REFEMIT_MANIFEST_MODULE_NAME W("RefEmit_InMemoryManifestModule")
+
+#ifdef FEATURE_TRACELOGGING
+//----------------------------------------------------------------------------------------------
+// Reads and logs the TargetFramework attribute for an assembly. For example: [assembly: TargetFramework(".NETFramework,Version=v4.0")]
+//----------------------------------------------------------------------------------------------
+void Assembly::TelemetryLogTargetFrameworkAttribute()
+{
+ const BYTE *pbAttr; // Custom attribute data as a BYTE*.
+ ULONG cbAttr; // Size of custom attribute data.
+ HRESULT hr = GetManifestImport()->GetCustomAttributeByName(GetManifestToken(), TARGET_FRAMEWORK_TYPE, (const void**)&pbAttr, &cbAttr);
+ bool dataLogged = false;
+ if (hr == S_OK)
+ {
+ CustomAttributeParser cap(pbAttr, cbAttr);
+ LPCUTF8 lpTargetFramework;
+ ULONG cbTargetFramework;
+ if (SUCCEEDED(cap.ValidateProlog()))
+ {
+ if (SUCCEEDED(cap.GetString(&lpTargetFramework, &cbTargetFramework)))
+ {
+ if ((lpTargetFramework != NULL) && (cbTargetFramework != 0))
+ {
+ SString s(SString::Utf8, lpTargetFramework, cbTargetFramework);
+ CLRTraceLog::Logger::LogTargetFrameworkAttribute(s.GetUnicode(), GetSimpleName());
+ dataLogged = true;
+ }
+ }
+ }
+ }
+ if (!dataLogged)
+ {
+ CLRTraceLog::Logger::LogTargetFrameworkAttribute(L"", GetSimpleName());
+ }
+}
+
+#endif // FEATURE_TRACELOGGING
+
//----------------------------------------------------------------------------------------------
// Does most Assembly initialization tasks. It can assume the ctor has already run
// and the assembly is safely destructable. Whether this function throws or succeeds,
@@ -252,6 +293,13 @@ void Assembly::Init(AllocMemTracker *pamTracker, LoaderAllocator *pLoaderAllocat
ReportAssemblyUse();
#endif
+#ifdef FEATURE_TRACELOGGING
+
+ TelemetryLogTargetFrameworkAttribute();
+
+#endif // FEATURE_TRACELOGGING
+
+
// Check for the special System.Numerics.Vectors assembly.
// If we encounter a non-trusted assembly by this name, we will simply not recognize any of its
// methods as intrinsics.
@@ -2610,7 +2658,7 @@ INT32 Assembly::ExecuteMainMethod(PTRARRAYREF *stringArgs)
INJECT_FAULT(COMPlusThrowOM());
}
CONTRACTL_END;
-
+
// reset the error code for std C
errno=0;
@@ -2662,7 +2710,6 @@ INT32 Assembly::ExecuteMainMethod(PTRARRAYREF *stringArgs)
AppDomain * pDomain = pThread->GetDomain();
pDomain->SetRootAssembly(pMeth->GetAssembly());
#endif
-
hr = RunMain(pMeth, 1, &iRetVal, stringArgs);
}
}
diff --git a/src/vm/assembly.hpp b/src/vm/assembly.hpp
index 812efb3c2b..1fdc655c02 100644
--- a/src/vm/assembly.hpp
+++ b/src/vm/assembly.hpp
@@ -126,6 +126,10 @@ public:
Assembly(BaseDomain *pDomain, PEAssembly *pFile, DebuggerAssemblyControlFlags debuggerFlags, BOOL fIsCollectible);
void Init(AllocMemTracker *pamTracker, LoaderAllocator *pLoaderAllocator);
+#if defined(FEATURE_TRACELOGGING)
+ void TelemetryLogTargetFrameworkAttribute();
+#endif // FEATURE_TRACELOGGING
+
void StartUnload();
void Terminate( BOOL signalProfiler = TRUE );
diff --git a/src/vm/ceeload.cpp b/src/vm/ceeload.cpp
index f5bf61c270..b379d94365 100644
--- a/src/vm/ceeload.cpp
+++ b/src/vm/ceeload.cpp
@@ -3756,7 +3756,7 @@ void Module::FreeClassTables()
if (!th.IsTypeDesc())
{
MethodTable *pMT = th.AsMethodTable();
- if (pMT->HasCCWTemplate())
+ if (pMT->HasCCWTemplate() && (!pMT->IsZapped() || pMT->GetZapModule() == this))
{
// code:MethodTable::GetComCallWrapperTemplate() may go through canonical methodtable indirection cell.
// The module load could be aborted before completing code:FILE_LOAD_EAGER_FIXUPS phase that's responsible
@@ -3786,7 +3786,7 @@ void Module::FreeClassTables()
if (!th.IsTypeDesc())
{
MethodTable * pMT = th.AsMethodTable();
- if (pMT->IsCanonicalMethodTable())
+ if (pMT->IsCanonicalMethodTable() && (!pMT->IsZapped() || pMT->GetZapModule() == this))
pMT->GetClass()->Destruct(pMT);
}
}
@@ -6502,6 +6502,12 @@ mdTypeRef Module::LookupTypeRefByMethodTable(MethodTable *pMT)
#ifdef FEATURE_READYTORUN_COMPILER
if (IsReadyToRunCompilation())
{
+ if (pMT->GetClass()->IsEquivalentType())
+ {
+ GetSvcLogger()->Log(W("ReadyToRun: Type reference to equivalent type cannot be encoded\n"));
+ ThrowHR(E_NOTIMPL);
+ }
+
// FUTURE: Encoding of new cross-module references for ReadyToRun
// This warning is hit for recursive cross-module inlining. It is commented out to avoid noise.
// GetSvcLogger()->Log(W("ReadyToRun: Type reference outside of current version bubble cannot be encoded\n"));
diff --git a/src/vm/clrtracelogging.cpp b/src/vm/clrtracelogging.cpp
new file mode 100644
index 0000000000..089e1c43f7
--- /dev/null
+++ b/src/vm/clrtracelogging.cpp
@@ -0,0 +1,41 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+//*****************************************************************************
+// clrttracelogging.cpp
+// Telemetry Logging for clr.dll
+//
+//*****************************************************************************
+
+#include "common.h"
+#include "clrtracelogging.h"
+#include "TraceLoggingProvider.h"
+#include "MicrosoftTelemetry.h"
+
+TRACELOGGING_DEFINE_PROVIDER(g_hClrProvider, CLR_PROVIDER_NAME, CLR_PROVIDER_ID, TraceLoggingOptionMicrosoftTelemetry());
+
+// Used for initialization and deconstruction.
+static CLRTraceLog::Provider g_clrTraceProvider(g_hClrProvider);
+
+//--- CLRTraceLogProvider
+
+// static
+void CLRTraceLog::Logger::LogTargetFrameworkAttribute(LPCWSTR targetFrameworkAttribute, const char * assemblyName)
+{
+ STANDARD_VM_CONTRACT;
+
+ EX_TRY
+ {
+ TraceLoggingWrite(g_hClrProvider,"CLR.AssemblyInfo",
+ TraceLoggingWideString(targetFrameworkAttribute, "TARGET_FRAMEWORK_ATTRIBUTE"),
+ TraceLoggingString(assemblyName, "ASSEMBLY_NAME"),
+ TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY));
+ }
+ EX_CATCH{}
+ EX_END_CATCH(SwallowAllExceptions)
+
+}
+//--- CLRTraceLog
+
diff --git a/src/vm/codeman.cpp b/src/vm/codeman.cpp
index dc6937f269..922dbcb7b8 100644
--- a/src/vm/codeman.cpp
+++ b/src/vm/codeman.cpp
@@ -1521,7 +1521,7 @@ BOOL EEJitManager::LoadJIT()
//
// See the document "RyuJIT Compatibility Fallback Specification.docx" for details.
- bool fUseRyuJit = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_UseRyuJit) == 1); // uncached access, since this code is run no more than one time
+ bool fUseRyuJit = UseRyuJit();
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
diff --git a/src/vm/compile.cpp b/src/vm/compile.cpp
index 7d7892b3c7..d77a285a04 100644
--- a/src/vm/compile.cpp
+++ b/src/vm/compile.cpp
@@ -1033,7 +1033,7 @@ HRESULT CEECompileInfo::SetCompilationTarget(CORINFO_ASSEMBLY_HANDLE assembl
mscorlib.InitializeSpec(SystemDomain::SystemFile());
GetAppDomain()->BindAssemblySpec(&mscorlib,TRUE,FALSE);
- if (!SystemDomain::SystemFile()->HasNativeImage())
+ if (!IsReadyToRunCompilation() && !SystemDomain::SystemFile()->HasNativeImage())
{
if (!CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenAllowMscorlibSoftbind))
{
@@ -2527,6 +2527,11 @@ BOOL CEECompileInfo::NeedsTypeLayoutCheck(CORINFO_CLASS_HANDLE classHnd)
if (!pMT->IsValueType())
return FALSE;
+ // Skip this check for equivalent types. Equivalent types are used for interop that ensures
+ // matching layout.
+ if (pMT->GetClass()->IsEquivalentType())
+ return FALSE;
+
return !pMT->IsLayoutFixedInCurrentVersionBubble();
}
@@ -8191,4 +8196,16 @@ HRESULT CompilationDomain::SetPlatformWinmdPaths(LPCWSTR pwzPlatformWinmdPaths)
}
#endif // CROSSGEN_COMPILE
+#if defined(_TARGET_AMD64_) && !defined(FEATURE_CORECLR)
+bool UseRyuJit()
+{
+#ifdef CROSSGEN_COMPILE
+ return true;
+#else
+ static ConfigDWORD useRyuJitValue;
+ return useRyuJitValue.val(CLRConfig::INTERNAL_UseRyuJit) == 1 || IsNgenOffline();
+#endif
+}
+#endif
+
#endif // FEATURE_PREJIT
diff --git a/src/vm/coreassemblyspec.cpp b/src/vm/coreassemblyspec.cpp
index be3d2841ed..238e359561 100644
--- a/src/vm/coreassemblyspec.cpp
+++ b/src/vm/coreassemblyspec.cpp
@@ -618,7 +618,7 @@ VOID AssemblySpec::Bind(AppDomain *pAppDomain,
{
SString sSimpleName(SString::Utf8, m_pAssemblyName);
- fNativeImage = pAppDomain->ToCompilationDomain()->IsInHardBindList(sSimpleName);
+ fNativeImage = !IsReadyToRunCompilation() && pAppDomain->ToCompilationDomain()->IsInHardBindList(sSimpleName);
SString sFileName(sSimpleName, fNativeImage ? W(".ni.dll") : W(".dll"));
diff --git a/src/vm/crossgen/wks_crossgen.nativeproj b/src/vm/crossgen/wks_crossgen.nativeproj
index a688b49304..205f2e2c95 100644
--- a/src/vm/crossgen/wks_crossgen.nativeproj
+++ b/src/vm/crossgen/wks_crossgen.nativeproj
@@ -157,7 +157,9 @@
<CppCompile Include="$(VmSourcesDir)\CrossgenRoParseTypeName.cpp" Condition="'$(FeatureCominterop)' == 'true'"/>
<CppCompile Include="$(VmSourcesDir)\CrossgenRoResolveNamespace.cpp" Condition="'$(FeatureCominterop)' == 'true'"/>
</ItemGroup>
-
+ <ItemGroup>
+ <CppCompile Condition="'$(FeatureTraceLogging)' == 'true'" Include="$(VmSourcesDir)\clrtracelogging.cpp" />
+ </ItemGroup>
<Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\vm\vm.targets" />
</Project>
diff --git a/src/vm/domainfile.cpp b/src/vm/domainfile.cpp
index 5423ebe63f..a558ee3900 100644
--- a/src/vm/domainfile.cpp
+++ b/src/vm/domainfile.cpp
@@ -3365,6 +3365,13 @@ void DomainAssembly::GetCurrentVersionInfo(CORCOMPILE_VERSION_INFO *pNativeVersi
pNativeVersionInfo->wConfigFlags |= CORCOMPILE_CONFIG_INSTRUMENTATION_NONE;
}
+#if defined(_TARGET_AMD64_) && !defined(FEATURE_CORECLR)
+ if (UseRyuJit())
+ {
+ pNativeVersionInfo->wCodegenFlags |= CORCOMPILE_CODEGEN_USE_RYUJIT;
+ }
+#endif
+
GetTimeStampsForNativeImage(pNativeVersionInfo);
// Store signature of source assembly.
diff --git a/src/vm/dwreport.cpp b/src/vm/dwreport.cpp
index 210e08240c..ccf41ea953 100644
--- a/src/vm/dwreport.cpp
+++ b/src/vm/dwreport.cpp
@@ -2776,52 +2776,71 @@ DWORD WINAPI DoFaultReportWorkerCallback(LPVOID pParam)
}
EX_END_CATCH(SwallowAllExceptions);
}
-
- SetupThread();
-
- GCX_COOP();
- if (pData->pThread != NULL && pExceptionInfo != NULL &&
- pExceptionInfo->ContextRecord == NULL &&
- pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW &&
- pExceptionInfo->ExceptionRecord->ExceptionAddress == 0)
+ // The purpose of the loop below is to avoid deadlocks during the abnormal process termination.
+ // We will try to acquire the lock for 100 times to see whether we can successfully grap it. If we
+ // can, then we can setup the thread and report the fault without worrying about the deadlock.
+ // Otherwise we won't report the fault. It's still possible that we can enter the critical section
+ // and report the fault without having deadlocks after this spin, but compared to the risky of
+ // having deadlock, we still prefer not to report the fault if we can't get the lock after spin.
+ BOOL isThreadSetup = false;
+ for (int i = 0; i < 100; i++)
+ {
+ if (ThreadStore::CanAcquireLock())
+ {
+ SetupThread();
+ isThreadSetup = true;
+ break;
+ }
+ __SwitchToThread(30, CALLER_LIMITS_SPINNING);
+ }
+
+ if (isThreadSetup)
{
- // In the case of a soft SO on a managed thread, we set the ExceptionAddress to one of the following
- //
- // 1. The first method on the stack that is in a non-system module.
- // 2. Failing that, the first method on the stack that is in a system module
+ GCX_COOP();
+
+ if (pData->pThread != NULL && pExceptionInfo != NULL &&
+ pExceptionInfo->ContextRecord == NULL &&
+ pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW &&
+ pExceptionInfo->ExceptionRecord->ExceptionAddress == 0)
+ {
+ // In the case of a soft SO on a managed thread, we set the ExceptionAddress to one of the following
+ //
+ // 1. The first method on the stack that is in a non-system module.
+ // 2. Failing that, the first method on the stack that is in a system module
- CONTEXT ContextRecord;
- memset(&ContextRecord, 0, sizeof(CONTEXT));
+ CONTEXT ContextRecord;
+ memset(&ContextRecord, 0, sizeof(CONTEXT));
- ExceptionInfo.ContextRecord = &ContextRecord; // To display the "Send" button, dw20 wants a non-NULL pointer
- ExceptionRecord = *(pExceptionInfo->ExceptionRecord);
- ExceptionInfo.ExceptionRecord = &ExceptionRecord;
- pExceptionInfo = &ExceptionInfo;
+ ExceptionInfo.ContextRecord = &ContextRecord; // To display the "Send" button, dw20 wants a non-NULL pointer
+ ExceptionRecord = *(pExceptionInfo->ExceptionRecord);
+ ExceptionInfo.ExceptionRecord = &ExceptionRecord;
+ pExceptionInfo = &ExceptionInfo;
- WatsonSOExceptionAddress WatsonExceptionAddresses;
+ WatsonSOExceptionAddress WatsonExceptionAddresses;
- pData->pThread->StackWalkFrames(
- WatsonSOStackCrawlCallback,
- &WatsonExceptionAddresses,
- FUNCTIONSONLY|ALLOW_ASYNC_STACK_WALK);
+ pData->pThread->StackWalkFrames(
+ WatsonSOStackCrawlCallback,
+ &WatsonExceptionAddresses,
+ FUNCTIONSONLY|ALLOW_ASYNC_STACK_WALK);
- if (WatsonExceptionAddresses.m_UserMethod != NULL)
- {
- pExceptionInfo->ExceptionRecord->ExceptionAddress = WatsonExceptionAddresses.m_UserMethod;
- }
- else if (WatsonExceptionAddresses.m_SystemMethod != NULL)
- {
- pExceptionInfo->ExceptionRecord->ExceptionAddress = WatsonExceptionAddresses.m_SystemMethod;
- }
+ if (WatsonExceptionAddresses.m_UserMethod != NULL)
+ {
+ pExceptionInfo->ExceptionRecord->ExceptionAddress = WatsonExceptionAddresses.m_UserMethod;
+ }
+ else if (WatsonExceptionAddresses.m_SystemMethod != NULL)
+ {
+ pExceptionInfo->ExceptionRecord->ExceptionAddress = WatsonExceptionAddresses.m_SystemMethod;
+ }
- }
+ }
- pData->result = DoFaultReportWorker(
- pExceptionInfo,
- pData->tore,
- pData->pThread,
- pData->dwThreadID);
+ pData->result = DoFaultReportWorker(
+ pExceptionInfo,
+ pData->tore,
+ pData->pThread,
+ pData->dwThreadID);
+ }
return 0;
@@ -3162,6 +3181,11 @@ FaultReportResult DoFaultReport( // Was Watson attempted, successful?
GCX_PREEMP();
if (!g_pDebugInterface ||
+ // When GC is in progress and current thread is either a GC thread or a managed
+ // thread under Coop mode, this will let the new generated DoFaultReportCallBack
+ // thread trigger a deadlock. So in this case, we should directly abort the fault
+ // report to avoid the deadlock.
+ ((IsGCThread() || pThread->PreemptiveGCDisabled()) && GCHeap::IsGCInProgress()) ||
FAILED(g_pDebugInterface->RequestFavor(DoFaultReportFavorWorker, pData)))
{
// If we can't initialize the debugger helper thread or we are running on the debugger helper
diff --git a/src/vm/eetwain.cpp b/src/vm/eetwain.cpp
index 84b267e806..5df7b6305a 100644
--- a/src/vm/eetwain.cpp
+++ b/src/vm/eetwain.cpp
@@ -4090,7 +4090,8 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pContext,
EECodeInfo *pCodeInfo,
unsigned flags,
GCEnumCallback pCallBack,
- LPVOID hCallBack)
+ LPVOID hCallBack,
+ DWORD relOffsetOverride)
{
CONTRACTL {
NOTHROW;
@@ -4731,7 +4732,8 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
EECodeInfo *pCodeInfo,
unsigned flags,
GCEnumCallback pCallBack,
- LPVOID hCallBack)
+ LPVOID hCallBack,
+ DWORD relOffsetOverride)
{
CONTRACTL {
NOTHROW;
@@ -4796,13 +4798,13 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
#ifdef USE_GC_INFO_DECODER
/* If we are not in the active method, we are currently pointing
- * to the return address; at the return address stack variables
- * can become dead if the call is the last instruction of a try block
- * and the return address is the jump around the catch block. Therefore
- * we simply assume an offset inside of call instruction.
- * NOTE: The GcInfoDecoder depends on this; if you change it, you must
- * revisit the GcInfoEncoder/Decoder
- */
+ * to the return address; at the return address stack variables
+ * can become dead if the call is the last instruction of a try block
+ * and the return address is the jump around the catch block. Therefore
+ * we simply assume an offset inside of call instruction.
+ * NOTE: The GcInfoDecoder depends on this; if you change it, you must
+ * revisit the GcInfoEncoder/Decoder
+ */
if (!(flags & ExecutionAborted))
{
@@ -4827,6 +4829,34 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
methodName, curOffs));
}
}
+
+ // Check if we have been given an override value for relOffset
+ if (relOffsetOverride != NO_OVERRIDE_OFFSET)
+ {
+ // We've been given an override offset for GC Info
+#ifdef _DEBUG
+ GcInfoDecoder _gcInfoDecoder(
+ gcInfoAddr,
+ DECODE_CODE_LENGTH,
+ 0
+ );
+
+ // We only use override offset for wantsReportOnlyLeaf
+ _ASSERTE(_gcInfoDecoder.WantsReportOnlyLeaf());
+#endif // _DEBUG
+
+ curOffs = relOffsetOverride;
+
+#ifdef _TARGET_ARM_
+ // On ARM, the low-order bit of an instruction pointer indicates Thumb vs. ARM mode.
+ // Mask this off; all instructions are two-byte aligned.
+ curOffs &= (~THUMB_CODE);
+#endif // _TARGET_ARM_
+
+ LOG((LF_GCINFO, LL_INFO1000, "Adjusted GC reporting offset to provided override offset. Now reporting GC refs for %s at offset %04x.\n",
+ methodName, curOffs));
+ }
+
#endif // USE_GC_INFO_DECODER
#if defined(WIN64EXCEPTIONS) // funclets
@@ -4948,7 +4978,8 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pContext,
EECodeInfo *pCodeInfo,
unsigned flags,
GCEnumCallback pCallBack,
- LPVOID hCallBack)
+ LPVOID hCallBack,
+ DWORD relOffsetOverride)
{
PORTABILITY_ASSERT("EECodeManager::EnumGcRefs is not implemented on this platform.");
return false;
diff --git a/src/vm/eventtrace.cpp b/src/vm/eventtrace.cpp
index c55c378005..dab4436923 100644
--- a/src/vm/eventtrace.cpp
+++ b/src/vm/eventtrace.cpp
@@ -4599,6 +4599,145 @@ VOID ETW::ExceptionLog::ExceptionThrown(CrawlFrame *pCf, BOOL bIsReThrownExcept
} EX_CATCH { } EX_END_CATCH(SwallowAllExceptions);
}
+
+VOID ETW::ExceptionLog::ExceptionThrownEnd()
+{
+ CONTRACTL{
+ NOTHROW;
+ GC_NOTRIGGER;
+ } CONTRACTL_END;
+
+ if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionThrownStop))
+ {
+ return;
+ }
+
+ FireEtwExceptionThrownStop();
+}
+
+/****************************************************************************/
+/* This is called by the runtime when an exception is handled by the runtime */
+/****************************************************************************/
+VOID ETW::ExceptionLog::ExceptionCatchBegin(MethodDesc * pMethodDesc, PVOID pEntryEIP)
+{
+ CONTRACTL{
+ NOTHROW;
+ GC_NOTRIGGER;
+ } CONTRACTL_END;
+
+ if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionCatchStart))
+ {
+ return;
+ }
+
+ EX_TRY
+ {
+ SString methodName;
+ pMethodDesc->GetFullMethodInfo(methodName);
+
+ FireEtwExceptionCatchStart((uint64_t)pEntryEIP,
+ (uint64_t)pMethodDesc,
+ methodName.GetUnicode(),
+ GetClrInstanceId());
+
+ } EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
+}
+
+VOID ETW::ExceptionLog::ExceptionCatchEnd()
+{
+ CONTRACTL{
+ NOTHROW;
+ GC_NOTRIGGER;
+ } CONTRACTL_END;
+
+ if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionCatchStop))
+ {
+ return;
+ }
+
+ FireEtwExceptionCatchStop();
+}
+
+VOID ETW::ExceptionLog::ExceptionFinallyBegin(MethodDesc * pMethodDesc, PVOID pEntryEIP)
+{
+ CONTRACTL{
+ NOTHROW;
+ GC_NOTRIGGER;
+ } CONTRACTL_END;
+
+ if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionFinallyStart))
+ {
+ return;
+ }
+
+ EX_TRY
+ {
+ SString methodName;
+ pMethodDesc->GetFullMethodInfo(methodName);
+
+ FireEtwExceptionFinallyStart((uint64_t)pEntryEIP,
+ (uint64_t)pMethodDesc,
+ methodName.GetUnicode(),
+ GetClrInstanceId());
+
+ } EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
+}
+
+VOID ETW::ExceptionLog::ExceptionFinallyEnd()
+{
+ CONTRACTL{
+ NOTHROW;
+ GC_NOTRIGGER;
+ } CONTRACTL_END;
+
+ if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionFinallyStop))
+ {
+ return;
+ }
+
+ FireEtwExceptionFinallyStop();
+}
+
+VOID ETW::ExceptionLog::ExceptionFilterBegin(MethodDesc * pMethodDesc, PVOID pEntryEIP)
+{
+ CONTRACTL{
+ NOTHROW;
+ GC_NOTRIGGER;
+ } CONTRACTL_END;
+
+ if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionFilterStart))
+ {
+ return;
+ }
+
+ EX_TRY
+ {
+ SString methodName;
+ pMethodDesc->GetFullMethodInfo(methodName);
+
+ FireEtwExceptionFilterStart((uint64_t)pEntryEIP,
+ (uint64_t)pMethodDesc,
+ methodName.GetUnicode(),
+ GetClrInstanceId());
+
+ } EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
+}
+
+VOID ETW::ExceptionLog::ExceptionFilterEnd()
+{
+ CONTRACTL{
+ NOTHROW;
+ GC_NOTRIGGER;
+ } CONTRACTL_END;
+
+ if (!ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ExceptionFilterStop))
+ {
+ return;
+ }
+
+ FireEtwExceptionFilterStop();
+}
+
/****************************************************************************/
/* This is called by the runtime when a domain is loaded */
/****************************************************************************/
diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp
index 02f60915c4..37f1369c5d 100644
--- a/src/vm/exceptionhandling.cpp
+++ b/src/vm/exceptionhandling.cpp
@@ -2053,6 +2053,13 @@ bool ExceptionTracker::HandleNestedExceptionEscape(StackFrame sf, bool fIsFirstP
if (!fIsFirstPass)
{
+
+ // During unwind, at each frame we collapse exception trackers only once i.e. there cannot be multiple
+ // exception trackers that are collapsed at each frame. Store the information of collapsed exception
+ // tracker in current tracker to be able to find the parent frame when nested exception escapes.
+ m_csfEHClauseOfCollapsedTracker = m_pPrevNestedInfo->m_EHClauseInfo.GetCallerStackFrameForEHClause();
+ m_EnclosingClauseInfoOfCollapsedTracker = m_pPrevNestedInfo->m_EnclosingClauseInfoForGCReporting;
+
EH_LOG((LL_INFO100, " - removing previous tracker\n"));
ExceptionTracker* pTrackerToFree = m_pPrevNestedInfo;
@@ -3258,6 +3265,19 @@ DWORD_PTR ExceptionTracker::CallHandler(
this->m_EHClauseInfo.SetManagedCodeEntered(TRUE);
this->m_EHClauseInfo.SetCallerStackFrame(csfFunclet);
+ switch(funcletType)
+ {
+ case EHFuncletType::Filter:
+ ETW::ExceptionLog::ExceptionFilterBegin(pMD, (PVOID)uHandlerStartPC);
+ break;
+ case EHFuncletType::FaultFinally:
+ ETW::ExceptionLog::ExceptionFinallyBegin(pMD, (PVOID)uHandlerStartPC);
+ break;
+ case EHFuncletType::Catch:
+ ETW::ExceptionLog::ExceptionCatchBegin(pMD, (PVOID)uHandlerStartPC);
+ break;
+ }
+
#if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
// Invoke the funclet. We pass throwable only when invoking the catch block.
// Since the actual caller of the funclet is the assembly helper, pass the reference
@@ -3297,6 +3317,20 @@ DWORD_PTR ExceptionTracker::CallHandler(
dwResumePC = pfnHandler(sf.SP, OBJECTREFToObject(throwable));
#endif // _TARGET_ARM_
+ switch(funcletType)
+ {
+ case EHFuncletType::Filter:
+ ETW::ExceptionLog::ExceptionFilterEnd();
+ break;
+ case EHFuncletType::FaultFinally:
+ ETW::ExceptionLog::ExceptionFinallyEnd();
+ break;
+ case EHFuncletType::Catch:
+ ETW::ExceptionLog::ExceptionCatchEnd();
+ ETW::ExceptionLog::ExceptionThrownEnd();
+ break;
+ }
+
this->m_EHClauseInfo.SetManagedCodeEntered(FALSE);
END_SO_TOLERANT_CODE;
@@ -6213,7 +6247,11 @@ bool ExceptionTracker::HasFrameBeenUnwoundByAnyActiveException(CrawlFrame * pCF)
// For case (2) above, sfLastUnwoundEstbalisherFrame would be the same as the managed frame's SP (or upper bound)
//
// For these scenarios, the frame is considered unwound.
- if (GetRegdisplaySP(pCF->GetRegisterSet()) == sfUpperBound.SP)
+
+ // For most cases which satisfy above condition GetRegdisplaySP(pCF->GetRegisterSet()) will be equal to sfUpperBound.SP.
+ // However, frames where Sp is modified after prolog ( eg. localloc) this might not be the case. For those scenarios,
+ // we need to check if sfUpperBound.SP is in between GetRegdisplaySP(pCF->GetRegisterSet()) & callerSp.
+ if (GetRegdisplaySP(pCF->GetRegisterSet()) <= sfUpperBound.SP && sfUpperBound < csfToCheck)
{
if (csfToCheck == sfCurrentEstablisherFrame)
{
@@ -6605,7 +6643,7 @@ StackFrame ExceptionTracker::FindParentStackFrameHelper(CrawlFrame* pCF,
// Since the current frame is a non-filter funclet, determine if its caller is the same one
// as was saved against the exception tracker before the funclet was invoked in ExceptionTracker::CallHandler.
CallerStackFrame csfFunclet = pCurrentTracker->m_EHClauseInfo.GetCallerStackFrameForEHClause();
- if (csfCurrent == csfFunclet)
+ if (csfCurrent == csfFunclet)
{
// The EnclosingClauseCallerSP is initialized in ExceptionTracker::ProcessManagedCallFrame, just before
// invoking the funclets. Basically, we are using the SP of the caller of the frame containing the funclet
@@ -6636,6 +6674,17 @@ StackFrame ExceptionTracker::FindParentStackFrameHelper(CrawlFrame* pCF,
break;
}
+ // Check if this tracker was collapsed with another tracker and if caller of funclet clause for collapsed exception tracker matches.
+ else if (fForGCReporting && !(pCurrentTracker->m_csfEHClauseOfCollapsedTracker.IsNull()) && csfCurrent == pCurrentTracker->m_csfEHClauseOfCollapsedTracker)
+ {
+ EnclosingClauseInfo srcEnclosingClause = pCurrentTracker->m_EnclosingClauseInfoOfCollapsedTracker;
+ sfResult = (StackFrame)(CallerStackFrame(srcEnclosingClause.GetEnclosingClauseCallerSP()));
+
+ _ASSERTE(!sfResult.IsNull());
+
+ break;
+
+ }
}
lExit: ;
diff --git a/src/vm/exceptionhandling.h b/src/vm/exceptionhandling.h
index 72db3576a3..0f9e962ffe 100644
--- a/src/vm/exceptionhandling.h
+++ b/src/vm/exceptionhandling.h
@@ -108,6 +108,7 @@ public:
m_sfLastUnwoundEstablisherFrame.Clear();
m_pInitialExplicitFrame = NULL;
m_pLimitFrame = NULL;
+ m_csfEHClauseOfCollapsedTracker.Clear();
}
ExceptionTracker(DWORD_PTR dwExceptionPc,
@@ -166,6 +167,7 @@ public:
m_sfCurrentEstablisherFrame.Clear();
m_sfLastUnwoundEstablisherFrame.Clear();
m_pInitialExplicitFrame = NULL;
+ m_csfEHClauseOfCollapsedTracker.Clear();
}
~ExceptionTracker()
@@ -500,6 +502,11 @@ public:
return m_uCatchToCallPC;
}
+ EE_ILEXCEPTION_CLAUSE GetEHClauseForCatch()
+ {
+ return m_ClauseForCatch;
+ }
+
// Returns the topmost frame seen during the first pass.
StackFrame GetTopmostStackFrameFromFirstPass()
{
@@ -757,6 +764,8 @@ private: ;
StackFrame m_sfCurrentEstablisherFrame;
StackFrame m_sfLastUnwoundEstablisherFrame;
PTR_Frame m_pInitialExplicitFrame;
+ CallerStackFrame m_csfEHClauseOfCollapsedTracker;
+ EnclosingClauseInfo m_EnclosingClauseInfoOfCollapsedTracker;
};
#if defined(WIN64EXCEPTIONS)
diff --git a/src/vm/gcenv.cpp b/src/vm/gcenv.cpp
index 68eee622f5..ea7d634ecf 100644
--- a/src/vm/gcenv.cpp
+++ b/src/vm/gcenv.cpp
@@ -146,6 +146,74 @@ inline bool SafeToReportGenericParamContext(CrawlFrame* pCF)
return true;
}
+#if defined(WIN64EXCEPTIONS)
+
+struct FindFirstInterruptiblePointState
+{
+ unsigned offs;
+ unsigned endOffs;
+ unsigned returnOffs;
+};
+
+bool FindFirstInterruptiblePointStateCB(
+ UINT32 startOffset,
+ UINT32 stopOffset,
+ LPVOID hCallback)
+{
+ FindFirstInterruptiblePointState* pState = (FindFirstInterruptiblePointState*)hCallback;
+
+ _ASSERTE(startOffset < stopOffset);
+ _ASSERTE(pState->offs < pState->endOffs);
+
+ if (stopOffset <= pState->offs)
+ {
+ // The range ends before the requested offset.
+ return false;
+ }
+
+ // The offset is in the range.
+ if (startOffset <= pState->offs &&
+ pState->offs < stopOffset)
+ {
+ pState->returnOffs = pState->offs;
+ return true;
+ }
+
+ // The range is completely after the desired offset. We use the range start offset, if
+ // it comes before the given endOffs. We assume that the callback is called with ranges
+ // in increasing order, so earlier ones are reported before later ones. That is, if we
+ // get to this case, it will be the closest interruptible range after the requested
+ // offset.
+
+ _ASSERTE(pState->offs < startOffset);
+ if (startOffset < pState->endOffs)
+ {
+ pState->returnOffs = startOffset;
+ return true;
+ }
+
+ return false;
+}
+
+// Find the first interruptible point in the range [offs .. endOffs) (the beginning of the range is inclusive,
+// the end is exclusive). Return -1 if no such point exists.
+unsigned FindFirstInterruptiblePoint(CrawlFrame* pCF, unsigned offs, unsigned endOffs)
+{
+ PTR_BYTE gcInfoAddr = dac_cast<PTR_BYTE>(pCF->GetCodeInfo()->GetGCInfo());
+ GcInfoDecoder gcInfoDecoder(gcInfoAddr, DECODE_FOR_RANGES_CALLBACK, 0);
+
+ FindFirstInterruptiblePointState state;
+ state.offs = offs;
+ state.endOffs = endOffs;
+ state.returnOffs = -1;
+
+ gcInfoDecoder.EnumerateInterruptibleRanges(&FindFirstInterruptiblePointStateCB, &state);
+
+ return state.returnOffs;
+}
+
+#endif // WIN64EXCEPTIONS
+
//-----------------------------------------------------------------------------
StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData)
{
@@ -209,15 +277,47 @@ StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData)
pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
#endif // _DEBUG
-#if 0
- printf("Scanning Frame for method %s\n", pMD->m_pszDebugMethodName);
-#endif // _DEBUG
+ DWORD relOffsetOverride = NO_OVERRIDE_OFFSET;
+#if defined(WIN64EXCEPTIONS)
+ if (pCF->ShouldParentToFuncletUseUnwindTargetLocationForGCReporting())
+ {
+ PTR_BYTE gcInfoAddr = dac_cast<PTR_BYTE>(pCF->GetCodeInfo()->GetGCInfo());
+ GcInfoDecoder _gcInfoDecoder(
+ gcInfoAddr,
+ DECODE_CODE_LENGTH,
+ 0
+ );
+
+ if(_gcInfoDecoder.WantsReportOnlyLeaf())
+ {
+ // We're in a special case of unwinding from a funclet, and resuming execution in
+ // another catch funclet associated with same parent function. We need to report roots.
+ // Reporting at the original throw site gives incorrect liveness information. We choose to
+ // report the liveness information at the first interruptible instruction of the catch funclet
+ // that we are going to execute. We also only report stack slots, since no registers can be
+ // live at the first instruction of a handler, except the catch object, which the VM protects
+ // specially. If the catch funclet has not interruptible point, we fall back and just report
+ // what we used to: at the original throw instruction. This might lead to bad GC behavior
+ // if the liveness is not correct.
+ const EE_ILEXCEPTION_CLAUSE& ehClauseForCatch = pCF->GetEHClauseForCatch();
+ relOffsetOverride = FindFirstInterruptiblePoint(pCF, ehClauseForCatch.HandlerStartPC,
+ ehClauseForCatch.HandlerEndPC);
+ _ASSERTE(relOffsetOverride != NO_OVERRIDE_OFFSET);
+
+ STRESS_LOG3(LF_GCROOTS, LL_INFO1000, "Setting override offset = %u for method %pM ControlPC = %p\n",
+ relOffsetOverride, pMD, GetControlPC(pCF->GetRegisterSet()));
+ }
+
+ }
+#endif // WIN64EXCEPTIONS
pCM->EnumGcRefs(pCF->GetRegisterSet(),
pCF->GetCodeInfo(),
flags,
GcEnumObject,
- pData);
+ pData,
+ relOffsetOverride);
+
}
else
{
diff --git a/src/vm/i386/excepx86.cpp b/src/vm/i386/excepx86.cpp
index ca7a18d8c3..6bf26a4790 100644
--- a/src/vm/i386/excepx86.cpp
+++ b/src/vm/i386/excepx86.cpp
@@ -1945,6 +1945,9 @@ LPVOID STDCALL COMPlusEndCatch(LPVOID ebp, DWORD ebx, DWORD edi, DWORD esi, LPVO
STATIC_CONTRACT_MODE_COOPERATIVE;
STATIC_CONTRACT_SO_INTOLERANT;
+ ETW::ExceptionLog::ExceptionCatchEnd();
+ ETW::ExceptionLog::ExceptionThrownEnd();
+
void* esp = COMPlusEndCatchWorker(GetThread());
// We are going to resume at a handler nesting level whose esp is dEsp. Pop off any SEH records below it. This
@@ -3324,6 +3327,8 @@ void ResumeAtJitEH(CrawlFrame* pCf,
// that the handle for the current ExInfo has been freed has been delivered
pExInfo->m_EHClauseInfo.SetManagedCodeEntered(TRUE);
+ ETW::ExceptionLog::ExceptionCatchBegin(pCf->GetCodeInfo()->GetMethodDesc(), (PVOID)pCf->GetCodeInfo()->GetStartAddress());
+
ResumeAtJitEHHelper(&context);
UNREACHABLE_MSG("Should never return from ResumeAtJitEHHelper!");
@@ -3394,8 +3399,13 @@ int CallJitEHFilter(CrawlFrame* pCf, BYTE* startPC, EE_ILEXCEPTION_CLAUSE *EHCla
// returning from UnwindFrames.
FrameWithCookie<ExceptionFilterFrame> exceptionFilterFrame(pShadowSP);
+
+ ETW::ExceptionLog::ExceptionFilterBegin(pCf->GetCodeInfo()->GetMethodDesc(), (PVOID)pCf->GetCodeInfo()->GetStartAddress());
+
retVal = CallJitEHFilterWorker(pShadowSP, &context);
+ ETW::ExceptionLog::ExceptionFilterEnd();
+
exceptionFilterFrame.Pop();
return retVal;
@@ -3421,8 +3431,12 @@ void CallJitEHFinally(CrawlFrame* pCf, BYTE* startPC, EE_ILEXCEPTION_CLAUSE *EHC
*pFinallyEnd = EHClausePtr->HandlerEndPC;
}
+ ETW::ExceptionLog::ExceptionFinallyBegin(pCf->GetCodeInfo()->GetMethodDesc(), (PVOID)pCf->GetCodeInfo()->GetStartAddress());
+
CallJitEHFinallyHelper(pShadowSP, &context);
+ ETW::ExceptionLog::ExceptionFinallyEnd();
+
//
// Update the registers using new context
//
diff --git a/src/vm/i386/stublinkerx86.cpp b/src/vm/i386/stublinkerx86.cpp
index eb744615eb..e42f7d792f 100644
--- a/src/vm/i386/stublinkerx86.cpp
+++ b/src/vm/i386/stublinkerx86.cpp
@@ -5076,14 +5076,14 @@ VOID StubLinkerCPU::EmitArrayOpStub(const ArrayOpScript* pArrayOpScript)
X86EmitOp(0x8b, kEAX, kValueReg, 0 AMD64_ARG(k64BitOp)); // mov EAX, [kValueReg] ; possibly trashes kValueReg
// cmp EAX, [ESI/R10+m_ElementType]
- X86_64BitOperands();
- X86EmitOp(0x3b, kEAX, kArrayMTReg, MethodTable::GetOffsetOfArrayElementTypeHandle());
+
+ X86EmitOp(0x3b, kEAX, kArrayMTReg, MethodTable::GetOffsetOfArrayElementTypeHandle() AMD64_ARG(k64BitOp));
X86EmitCondJump(CheckPassed, X86CondCode::kJZ); // Exact match is OK
X86EmitRegLoad(kEAX, (UINT_PTR)g_pObjectClass); // mov EAX, g_pObjectMethodTable
// cmp EAX, [ESI/R10+m_ElementType]
- X86_64BitOperands();
- X86EmitOp(0x3b, kEAX, kArrayMTReg, MethodTable::GetOffsetOfArrayElementTypeHandle());
+
+ X86EmitOp(0x3b, kEAX, kArrayMTReg, MethodTable::GetOffsetOfArrayElementTypeHandle() AMD64_ARG(k64BitOp));
X86EmitCondJump(CheckPassed, X86CondCode::kJZ); // Assigning to array of object is OK
// Try to call the fast helper first ( ObjIsInstanceOfNoGC ).
diff --git a/src/vm/methodtablebuilder.cpp b/src/vm/methodtablebuilder.cpp
index 02846290f1..e1d2dbb2e5 100644
--- a/src/vm/methodtablebuilder.cpp
+++ b/src/vm/methodtablebuilder.cpp
@@ -11807,11 +11807,15 @@ BOOL MethodTableBuilder::NeedsAlignedBaseOffset()
if (IsValueClass())
return FALSE;
- // READYTORUN: TODO: This logic is not correct when NGen image depends on ReadyToRun image. In this case,
- // GetModule()->IsReadyToRun() flag is going to be false at NGen time, but it is going to be true at runtime.
- // Thus, the offsets between the two cases are going to be different.
- if (!(IsReadyToRunCompilation() || GetModule()->IsReadyToRun()))
- return FALSE;
+ // Always use the ReadyToRun field layout algorithm if the source IL image was ReadyToRun, independent on
+ // whether ReadyToRun is actually enabled for the module. It is required to allow mixing and matching
+ // ReadyToRun images with NGen.
+ if (!GetModule()->GetFile()->IsILImageReadyToRun())
+ {
+ // Always use ReadyToRun field layout algorithm to produce ReadyToRun images
+ if (!IsReadyToRunCompilation())
+ return FALSE;
+ }
MethodTable * pParentMT = GetParentMethodTable();
diff --git a/src/vm/pefile.cpp b/src/vm/pefile.cpp
index 815071c486..658d7f5ca6 100644
--- a/src/vm/pefile.cpp
+++ b/src/vm/pefile.cpp
@@ -1948,6 +1948,13 @@ static BOOL RuntimeVerifyNativeImageTimestamps(const CORCOMPILE_VERSION_INFO *in
if (hMod == NULL)
{
+ // Unless this is an NGen worker process, we don't want to load JIT compiler just to do a timestamp check.
+ // In an ideal case, all assemblies have native images, and JIT compiler never needs to be loaded at runtime.
+ // Loading JIT compiler just to check its timestamp would reduce the benefits of have native images.
+ // Since CLR and JIT are intended to be serviced together, the possibility of accidentally using native
+ // images created by an older JIT is very small, and is deemed an acceptable risk.
+ // Note that when multiple JIT compilers are used (e.g., clrjit.dll and compatjit.dll on x64 in .NET 4.6),
+ // they must all be in the same patch family.
if (!IsCompilationProcess())
continue;
@@ -2160,6 +2167,19 @@ BOOL RuntimeVerifyNativeImageVersion(const CORCOMPILE_VERSION_INFO *info, Loggab
}
#endif // CROSSGEN_COMPILE
+#if defined(_TARGET_AMD64_) && !defined(FEATURE_CORECLR)
+ //
+ // Check the right JIT compiler
+ //
+
+ bool nativeImageBuiltWithRyuJit = ((info->wCodegenFlags & CORCOMPILE_CODEGEN_USE_RYUJIT) != 0);
+ if (UseRyuJit() != nativeImageBuiltWithRyuJit)
+ {
+ RuntimeVerifyLog(LL_ERROR, pLogAsm, W("JIT compiler used to generate native image doesn't match current JIT compiler."));
+ return FALSE;
+ }
+#endif
+
//
// The zap is up to date.
//
diff --git a/src/vm/pefile.h b/src/vm/pefile.h
index 8f8a5f3588..4a64d9aec0 100644
--- a/src/vm/pefile.h
+++ b/src/vm/pefile.h
@@ -303,6 +303,7 @@ public:
BOOL HasSecurityDirectory();
BOOL IsIbcOptimized();
+ BOOL IsILImageReadyToRun();
WORD GetSubsystem();
mdToken GetEntryPointToken(
#ifdef _DEBUG
diff --git a/src/vm/pefile.inl b/src/vm/pefile.inl
index d43d2b7ca2..07d42d5859 100644
--- a/src/vm/pefile.inl
+++ b/src/vm/pefile.inl
@@ -772,6 +772,28 @@ inline BOOL PEFile::IsIbcOptimized()
return FALSE;
}
+inline BOOL PEFile::IsILImageReadyToRun()
+{
+ WRAPPER_NO_CONTRACT;
+
+#ifdef FEATURE_PREJIT
+ if (IsNativeLoaded())
+ {
+ CONSISTENCY_CHECK(HasNativeImage());
+
+ return GetLoadedNative()->GetNativeILHasReadyToRunHeader();
+ }
+ else
+#endif // FEATURE_PREJIT
+ if (HasOpenedILimage())
+ {
+ return GetLoadedIL()->HasReadyToRunHeader();
+ }
+ else
+ {
+ return FALSE;
+ }
+}
inline WORD PEFile::GetSubsystem()
{
diff --git a/src/vm/peimage.cpp b/src/vm/peimage.cpp
index 66f89db6e0..705f165d00 100644
--- a/src/vm/peimage.cpp
+++ b/src/vm/peimage.cpp
@@ -1547,7 +1547,14 @@ PTR_PEImageLayout PEImage::GetLayoutInternal(DWORD imageLayoutMask,DWORD flags)
SetLayout(IMAGE_FLAT,pFlatLayout);
pLoadLayout = new ConvertedImageLayout(pFlatLayout);
}
-#endif
+#ifdef FEATURE_READYTORUN
+ else if (ReadyToRunInfo::IsReadyToRunEnabled() && IsFile())
+ {
+ pLoadLayout = PEImageLayout::Load(this, FALSE, FALSE);
+ }
+#endif // FEATURE_READYTORUN
+
+#endif // FEATURE_CORECLR
if (pLoadLayout != NULL)
{
diff --git a/src/vm/stackwalk.cpp b/src/vm/stackwalk.cpp
index d39ce06ef4..3301dec092 100644
--- a/src/vm/stackwalk.cpp
+++ b/src/vm/stackwalk.cpp
@@ -1510,6 +1510,7 @@ void StackFrameIterator::ResetCrawlFrame()
m_crawl.isFilterFunclet = false;
m_crawl.isFilterFuncletCached = false;
m_crawl.fShouldParentToFuncletSkipReportingGCReferences = false;
+ m_crawl.fShouldParentFrameUseUnwindTargetPCforGCReporting = false;
#endif // WIN64EXCEPTIONS
m_crawl.pThread = this->m_pThread;
@@ -1669,6 +1670,10 @@ StackWalkAction StackFrameIterator::Filter(void)
// CrawlFrame
m_crawl.fShouldCrawlframeReportGCReferences = true;
+ // By default, assume that parent frame is going to report GC references from
+ // the actual location reported by the stack walk.
+ m_crawl.fShouldParentFrameUseUnwindTargetPCforGCReporting = false;
+
if (!m_sfParent.IsNull())
{
// we are now skipping frames to get to the funclet's parent
@@ -1887,7 +1892,7 @@ ProcessFuncletsForGCReporting:
_ASSERTE(m_fDidFuncletReportGCReferences);
m_fDidFuncletReportGCReferences = false;
-
+
STRESS_LOG0(LF_GCROOTS, LL_INFO100, "Unwound funclet will skip reporting references\n");
}
}
@@ -1913,6 +1918,9 @@ ProcessFuncletsForGCReporting:
if (m_sfParent.IsMaxVal() ||
ExceptionTracker::IsUnwoundToTargetParentFrame(&m_crawl, m_sfParent))
{
+ // Reset flag as we have reached target method frame so no more skipping required
+ fSkippingFunclet = false;
+
// We've finished skipping as told. Now check again.
if ((m_fProcessIntermediaryNonFilterFunclet == true) || (m_fProcessNonFilterFunclet == true))
@@ -1997,6 +2005,23 @@ ProcessFuncletsForGCReporting:
// now that we've found the parent that will report roots reset our state.
m_fDidFuncletReportGCReferences = true;
+
+ // After funclet gets unwound parent will begin to report gc references. Reporting GC references
+ // using the IP of throw in parent method can crash application. Parent could have locals objects
+ // which might not have been reported by funclet as live and would have already been collected
+ // when funclet was on stack. Now if parent starts using IP of throw to report gc references it
+ // would report garbage values as live objects. So instead parent can use the IP of the resume
+ // address of catch funclet to report live GC references.
+ m_crawl.fShouldParentFrameUseUnwindTargetPCforGCReporting = true;
+ // Store catch clause info. Helps retrieve IP of resume address.
+ m_crawl.ehClauseForCatch = pTracker->GetEHClauseForCatch();
+
+ STRESS_LOG3(LF_GCROOTS, LL_INFO100,
+ "STACKWALK: Parent of funclet which didn't report GC roots is handling an exception at 0x%p"
+ "(EH handler range [%x, %x) ), so we need to specially report roots to ensure variables alive"
+ " in its handler stay live.\n",
+ pTracker->GetCatchToCallPC(), m_crawl.ehClauseForCatch.HandlerStartPC,
+ m_crawl.ehClauseForCatch.HandlerEndPC);
}
else if (!m_crawl.IsFunclet())
{
diff --git a/src/vm/stackwalk.h b/src/vm/stackwalk.h
index 7fd882d3b6..d92cb9e374 100644
--- a/src/vm/stackwalk.h
+++ b/src/vm/stackwalk.h
@@ -405,6 +405,17 @@ public:
return fShouldCrawlframeReportGCReferences;
}
+
+ bool ShouldParentToFuncletUseUnwindTargetLocationForGCReporting()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return fShouldParentFrameUseUnwindTargetPCforGCReporting;
+ }
+
+ const EE_ILEXCEPTION_CLAUSE& GetEHClauseForCatch()
+ {
+ return ehClauseForCatch;
+ }
#endif // WIN64EXCEPTIONS
@@ -452,6 +463,8 @@ private:
bool isFilterFuncletCached;
bool fShouldParentToFuncletSkipReportingGCReferences;
bool fShouldCrawlframeReportGCReferences;
+ bool fShouldParentFrameUseUnwindTargetPCforGCReporting;
+ EE_ILEXCEPTION_CLAUSE ehClauseForCatch;
#endif //WIN64EXCEPTIONS
Thread* pThread;
diff --git a/src/vm/threaddebugblockinginfo.cpp b/src/vm/threaddebugblockinginfo.cpp
index a77c69b457..6ff0bab3e7 100644
--- a/src/vm/threaddebugblockinginfo.cpp
+++ b/src/vm/threaddebugblockinginfo.cpp
@@ -82,10 +82,17 @@ m_pThread(pThread)
#endif //DACCESS_COMPILE
// Holder destructor pops a blocking item off the blocking info stack
+// NOTE: optimizations are disabled to work around a codegen bug on x86
#ifndef DACCESS_COMPILE
+#ifdef _TARGET_X86_
+#pragma optimize( "", off )
+#endif // _TARGET_X86_
DebugBlockingItemHolder::~DebugBlockingItemHolder()
{
LIMITED_METHOD_CONTRACT;
m_pThread->DebugBlockingInfo.PopBlockingItem();
}
+#ifdef _TARGET_X86_
+#pragma optimize( "", on )
+#endif // _TARGET_X86_
#endif //DACCESS_COMPILE
diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp
index 3fc78f1e8a..87ad9bc1f2 100644
--- a/src/vm/threads.cpp
+++ b/src/vm/threads.cpp
@@ -6309,6 +6309,21 @@ void ThreadStore::AddThread(Thread *newThread, BOOL bRequiresTSL)
}
}
+// this function is just desgined to avoid deadlocks during abnormal process termination, and should not be used for any other purpose
+BOOL ThreadStore::CanAcquireLock()
+{
+ WRAPPER_NO_CONTRACT;
+#ifdef FEATURE_INCLUDE_ALL_INTERFACES
+ if (!s_pThreadStore->m_Crst.IsOSCritSec())
+ {
+ return true;
+ }
+ else
+#endif
+ {
+ return (s_pThreadStore->m_Crst.m_criticalsection.LockCount == -1 || (size_t)s_pThreadStore->m_Crst.m_criticalsection.OwningThread == (size_t)GetCurrentThreadId());
+ }
+}
// Whenever one of the components of OtherThreadsComplete() has changed in the
// correct direction, see whether we can now shutdown the EE because only background
diff --git a/src/vm/threads.h b/src/vm/threads.h
index b77c33bdda..28c593c103 100644
--- a/src/vm/threads.h
+++ b/src/vm/threads.h
@@ -5683,6 +5683,8 @@ public:
// RemoveThread finds the thread in the ThreadStore and discards it.
static BOOL RemoveThread(Thread *target);
+ static BOOL CanAcquireLock();
+
// Transfer a thread from the unstarted to the started list.
// WARNING : only GC calls this with bRequiresTSL set to FALSE.
static void TransferStartedThread(Thread *target, BOOL bRequiresTSL=TRUE);
diff --git a/src/vm/vm.settings b/src/vm/vm.settings
index 5e7ac72cbe..b4799d1b37 100644
--- a/src/vm/vm.settings
+++ b/src/vm/vm.settings
@@ -26,6 +26,7 @@
$(ClrSrcDirectory)\debug\inc\dump;
$(ClrSrcDirectory)\zap;
$(ClrSrcDirectory)\strongname\inc;
+ $(ClrSrcDirectory)\TraceLog;
$(ClrSrcDirectory)\gc
</UserIncludes>
diff --git a/src/vm/wks/wks.targets b/src/vm/wks/wks.targets
index 55b404c0e7..5f2770b267 100644
--- a/src/vm/wks/wks.targets
+++ b/src/vm/wks/wks.targets
@@ -383,4 +383,7 @@
<AssembleArm64 Include="$(IntermediateOutputDirectory)\PInvokeStubs.i" />
<AssembleArm64 Include="$(IntermediateOutputDirectory)\crtHelpers.i" />
</ItemGroup>
+ <ItemGroup>
+ <CppCompile Condition="'$(FeatureTraceLogging)' == 'true'" Include="$(VmSourcesDir)\clrtracelogging.cpp" />
+ </ItemGroup>
</Project>