summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSung Yoon Whang <suwhang@microsoft.com>2018-02-03 15:58:22 -0800
committerGitHub <noreply@github.com>2018-02-03 15:58:22 -0800
commitc247f5bffa563820fe8db6fa14b42024c57c540f (patch)
treeabfbf9d4e88979b94f69a66befcbed2bb05115d9 /src
parent72a6196896b335a5737ad1eeb042fcef8ca98239 (diff)
downloadcoreclr-c247f5bffa563820fe8db6fa14b42024c57c540f.tar.gz
coreclr-c247f5bffa563820fe8db6fa14b42024c57c540f.tar.bz2
coreclr-c247f5bffa563820fe8db6fa14b42024c57c540f.zip
Fix failfast stacktrace (#15895)
* attempt to fix stacktrace getting printed twice * Fix some default parameter issues, and wrong commit from last commit * Fix build errors, switch call from Debug.Assert to new FailFast FCall * Fix signature to allow more types of exception title * cleanup * Addressing comments from PR * More PR comments * remove useless using * Address comments on GC hole and few naming changes
Diffstat (limited to 'src')
-rw-r--r--src/classlibnative/bcltype/system.cpp46
-rw-r--r--src/classlibnative/bcltype/system.h3
-rw-r--r--src/inc/vptr_list.h1
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Debug.Unix.cs4
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Debug.cs27
-rw-r--r--src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs3
-rw-r--r--src/mscorlib/src/System/Diagnostics/Debug.Windows.cs4
-rw-r--r--src/mscorlib/src/System/Environment.cs3
-rw-r--r--src/vm/crossgencompile.cpp2
-rw-r--r--src/vm/ecalllist.h1
-rw-r--r--src/vm/eepolicy.cpp25
-rw-r--r--src/vm/eepolicy.h7
-rw-r--r--src/vm/fcall.h12
-rw-r--r--src/vm/frames.h73
-rw-r--r--src/vm/metasig.h1
15 files changed, 185 insertions, 27 deletions
diff --git a/src/classlibnative/bcltype/system.cpp b/src/classlibnative/bcltype/system.cpp
index bb06ceceeb..fdb04169ac 100644
--- a/src/classlibnative/bcltype/system.cpp
+++ b/src/classlibnative/bcltype/system.cpp
@@ -377,7 +377,7 @@ WCHAR g_szFailFastBuffer[256];
// This is the common code for FailFast processing that is wrapped by the two
// FailFast FCalls below.
-void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExceptionForWatsonBucketing, UINT_PTR retAddress, UINT exitCode)
+void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExceptionForWatsonBucketing, UINT_PTR retAddress, UINT exitCode, STRINGREF refErrorSourceString)
{
CONTRACTL
{
@@ -391,6 +391,7 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
{
STRINGREF refMesgString;
EXCEPTIONREF refExceptionForWatsonBucketing;
+ STRINGREF refErrorSourceString;
} gc;
ZeroMemory(&gc, sizeof(gc));
@@ -398,6 +399,7 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
gc.refMesgString = refMesgString;
gc.refExceptionForWatsonBucketing = refExceptionForWatsonBucketing;
+ gc.refErrorSourceString = refErrorSourceString;
// Managed code injected FailFast maps onto the unmanaged version
// (EEPolicy::HandleFatalError) in the following manner: the exit code is
@@ -423,6 +425,20 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
WCHAR *pszMessage = NULL;
DWORD cchMessage = (gc.refMesgString == NULL) ? 0 : gc.refMesgString->GetStringLength();
+ WCHAR * errorSourceString = NULL;
+
+ if (gc.refErrorSourceString != NULL)
+ {
+ DWORD cchErrorSource = gc.refErrorSourceString->GetStringLength();
+ errorSourceString = new (nothrow) WCHAR[cchErrorSource + 1];
+
+ if (errorSourceString != NULL)
+ {
+ memcpyNoGCRefs(errorSourceString, gc.refErrorSourceString->GetBuffer(), cchErrorSource * sizeof(WCHAR));
+ errorSourceString[cchErrorSource] = W('\0');
+ }
+ }
+
if (cchMessage < FAIL_FAST_STATIC_BUFFER_LENGTH)
{
pszMessage = g_szFailFastBuffer;
@@ -483,7 +499,7 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
if (gc.refExceptionForWatsonBucketing != NULL)
pThread->SetLastThrownObject(gc.refExceptionForWatsonBucketing);
- EEPolicy::HandleFatalError(exitCode, retAddress, pszMessage);
+ EEPolicy::HandleFatalError(exitCode, retAddress, pszMessage, NULL, errorSourceString);
GCPROTECT_END();
}
@@ -502,7 +518,7 @@ FCIMPL1(VOID, SystemNative::FailFast, StringObject* refMessageUNSAFE)
UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
// Call the actual worker to perform failfast
- GenericFailFast(refMessage, NULL, retaddr, COR_E_FAILFAST);
+ GenericFailFast(refMessage, NULL, retaddr, COR_E_FAILFAST, NULL);
HELPER_METHOD_FRAME_END();
}
@@ -520,7 +536,7 @@ FCIMPL2(VOID, SystemNative::FailFastWithExitCode, StringObject* refMessageUNSAFE
UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
// Call the actual worker to perform failfast
- GenericFailFast(refMessage, NULL, retaddr, exitCode);
+ GenericFailFast(refMessage, NULL, retaddr, exitCode, NULL);
HELPER_METHOD_FRAME_END();
}
@@ -539,7 +555,27 @@ FCIMPL2(VOID, SystemNative::FailFastWithException, StringObject* refMessageUNSAF
UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
// Call the actual worker to perform failfast
- GenericFailFast(refMessage, refException, retaddr, COR_E_FAILFAST);
+ GenericFailFast(refMessage, refException, retaddr, COR_E_FAILFAST, NULL);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(VOID, SystemNative::FailFastWithExceptionAndSource, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE, StringObject* errorSourceUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ STRINGREF refMessage = (STRINGREF)refMessageUNSAFE;
+ EXCEPTIONREF refException = (EXCEPTIONREF)refExceptionUNSAFE;
+ STRINGREF errorSource = (STRINGREF)errorSourceUNSAFE;
+
+ HELPER_METHOD_FRAME_BEGIN_3(refMessage, refException, errorSource);
+
+ // The HelperMethodFrame knows how to get the return address.
+ UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
+
+ // Call the actual worker to perform failfast
+ GenericFailFast(refMessage, refException, retaddr, COR_E_FAILFAST, errorSource);
HELPER_METHOD_FRAME_END();
}
diff --git a/src/classlibnative/bcltype/system.h b/src/classlibnative/bcltype/system.h
index 87dde89bcd..6a489bae62 100644
--- a/src/classlibnative/bcltype/system.h
+++ b/src/classlibnative/bcltype/system.h
@@ -55,6 +55,7 @@ public:
static FCDECL1(VOID, FailFast, StringObject* refMessageUNSAFE);
static FCDECL2(VOID, FailFastWithExitCode, StringObject* refMessageUNSAFE, UINT exitCode);
static FCDECL2(VOID, FailFastWithException, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE);
+ static FCDECL3(VOID, FailFastWithExceptionAndSource, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE, StringObject* errorSourceUNSAFE);
static FCDECL0(StringObject*, _GetModuleFileName);
static FCDECL0(StringObject*, GetRuntimeDirectory);
@@ -75,7 +76,7 @@ public:
private:
// Common processing code for FailFast
- static void GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExceptionForWatsonBucketing, UINT_PTR retAddress, UINT exitCode);
+ static void GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExceptionForWatsonBucketing, UINT_PTR retAddress, UINT exitCode, STRINGREF errorSource);
};
/* static */
diff --git a/src/inc/vptr_list.h b/src/inc/vptr_list.h
index ce38156af6..7b7b5f0eb4 100644
--- a/src/inc/vptr_list.h
+++ b/src/inc/vptr_list.h
@@ -72,6 +72,7 @@ VPTR_CLASS(GCFrame)
VPTR_CLASS(HelperMethodFrame)
VPTR_CLASS(HelperMethodFrame_1OBJ)
VPTR_CLASS(HelperMethodFrame_2OBJ)
+VPTR_CLASS(HelperMethodFrame_3OBJ)
VPTR_CLASS(HelperMethodFrame_PROTECTOBJ)
#ifdef FEATURE_HIJACK
VPTR_CLASS(HijackFrame)
diff --git a/src/mscorlib/shared/System/Diagnostics/Debug.Unix.cs b/src/mscorlib/shared/System/Diagnostics/Debug.Unix.cs
index 495f2f713c..0554581baa 100644
--- a/src/mscorlib/shared/System/Diagnostics/Debug.Unix.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Debug.Unix.cs
@@ -10,7 +10,7 @@ namespace System.Diagnostics
{
private static readonly bool s_shouldWriteToStdErr = Environment.GetEnvironmentVariable("COMPlus_DebugWriteToStdErr") == "1";
- private static void ShowAssertDialog(string stackTrace, string message, string detailMessage)
+ private static void ShowDialog(string stackTrace, string message, string detailMessage, string errorSource)
{
if (Debugger.IsAttached)
{
@@ -22,7 +22,7 @@ namespace System.Diagnostics
// Fail in order to avoid anyone catching an exception and masking
// an assert failure.
var ex = new DebugAssertException(message, detailMessage, stackTrace);
- Environment.FailFast(ex.Message, ex);
+ Environment.FailFast(ex.Message, ex, errorSource);
}
}
diff --git a/src/mscorlib/shared/System/Diagnostics/Debug.cs b/src/mscorlib/shared/System/Diagnostics/Debug.cs
index 5178f7f5c5..3a297387e9 100644
--- a/src/mscorlib/shared/System/Diagnostics/Debug.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Debug.cs
@@ -4,6 +4,8 @@
// Do not remove this, it is needed to retain calls to these conditional methods in release builds
#define DEBUG
+using System.Diagnostics.Contracts;
+using System.Runtime.CompilerServices;
namespace System.Diagnostics
{
@@ -91,18 +93,34 @@ namespace System.Diagnostics
if (!condition)
{
string stackTrace;
-
try
{
- stackTrace = Internal.Runtime.Augments.EnvironmentAugments.StackTrace;
+ stackTrace = new StackTrace(0, true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal);
}
catch
{
stackTrace = "";
}
+ WriteLine(FormatAssert(stackTrace, message, detailMessage));
+ s_ShowDialog(stackTrace, message, detailMessage, "Assertion Failed");
+ }
+ }
+ internal static void ContractFailure(bool condition, string message, string detailMessage, string failureKindMessage)
+ {
+ if (!condition)
+ {
+ string stackTrace;
+ try
+ {
+ stackTrace = new StackTrace(0, true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal);
+ }
+ catch
+ {
+ stackTrace = "";
+ }
WriteLine(FormatAssert(stackTrace, message, detailMessage));
- s_ShowAssertDialog(stackTrace, message, detailMessage);
+ s_ShowDialog(stackTrace, message, detailMessage, SR.GetResourceString(failureKindMessage));
}
}
@@ -315,7 +333,8 @@ namespace System.Diagnostics
}
// internal and not readonly so that the tests can swap this out.
- internal static Action<string, string, string> s_ShowAssertDialog = ShowAssertDialog;
+ internal static Action<string, string, string, string> s_ShowDialog = ShowDialog;
+
internal static Action<string> s_WriteCore = WriteCore;
}
}
diff --git a/src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs b/src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs
index 45cb9bb869..7b74b01dca 100644
--- a/src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs
+++ b/src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs
@@ -317,8 +317,7 @@ namespace System.Runtime.CompilerServices
displayMessage = GetDisplayMessage(kind, userMessage, conditionText);
}
- // TODO: https://github.com/dotnet/coreclr/issues/14867
- System.Diagnostics.Debug.Fail(displayMessage);
+ System.Diagnostics.Debug.ContractFailure(false, displayMessage, string.Empty, GetResourceNameForFailure(kind));
}
private static String GetResourceNameForFailure(ContractFailureKind failureKind)
diff --git a/src/mscorlib/src/System/Diagnostics/Debug.Windows.cs b/src/mscorlib/src/System/Diagnostics/Debug.Windows.cs
index 483bf51015..e1992b49bf 100644
--- a/src/mscorlib/src/System/Diagnostics/Debug.Windows.cs
+++ b/src/mscorlib/src/System/Diagnostics/Debug.Windows.cs
@@ -6,7 +6,7 @@ namespace System.Diagnostics
{
public static partial class Debug
{
- private static void ShowAssertDialog(string stackTrace, string message, string detailMessage)
+ private static void ShowDialog(string stackTrace, string message, string detailMessage, string errorSource)
{
if (Debugger.IsAttached)
{
@@ -18,7 +18,7 @@ namespace System.Diagnostics
// Fail in order to avoid anyone catching an exception and masking
// an assert failure.
var ex = new DebugAssertException(message, detailMessage, stackTrace);
- Environment.FailFast(ex.Message, ex);
+ Environment.FailFast(ex.Message, ex, errorSource);
}
}
diff --git a/src/mscorlib/src/System/Environment.cs b/src/mscorlib/src/System/Environment.cs
index 78ec2a0164..a4d5aece63 100644
--- a/src/mscorlib/src/System/Environment.cs
+++ b/src/mscorlib/src/System/Environment.cs
@@ -115,6 +115,9 @@ namespace System
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern void FailFast(String message, Exception exception);
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public static extern void FailFast(String message, Exception exception, String errorMessage);
+
#if FEATURE_WIN32_REGISTRY
// This is only used by RegistryKey on Windows.
public static String ExpandEnvironmentVariables(String name)
diff --git a/src/vm/crossgencompile.cpp b/src/vm/crossgencompile.cpp
index 4cb2b5a06d..b94800d38b 100644
--- a/src/vm/crossgencompile.cpp
+++ b/src/vm/crossgencompile.cpp
@@ -384,7 +384,7 @@ extern "C" UINT_PTR STDCALL GetCurrentIP()
return 0;
}
-void EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo)
+void EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource)
{
fprintf(stderr, "Fatal error: %08x\n", exitCode);
ExitProcess(exitCode);
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index b9706bb755..51c13accb2 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -164,6 +164,7 @@ FCFuncStart(gEnvironmentFuncs)
#endif // FEATURE_COMINTEROP
FCFuncElementSig("FailFast", &gsig_SM_Str_RetVoid, SystemNative::FailFast)
FCFuncElementSig("FailFast", &gsig_SM_Str_Exception_RetVoid, SystemNative::FailFastWithException)
+ FCFuncElementSig("FailFast", &gsig_SM_Str_Exception_Str_RetVoid, SystemNative::FailFastWithExceptionAndSource)
FCFuncEnd()
FCFuncStart(gRuntimeEnvironmentFuncs)
diff --git a/src/vm/eepolicy.cpp b/src/vm/eepolicy.cpp
index db47e3fa27..06c3741b73 100644
--- a/src/vm/eepolicy.cpp
+++ b/src/vm/eepolicy.cpp
@@ -1176,18 +1176,27 @@ inline void LogCallstackForLogWorker()
// Return Value:
// None
//
-inline void DoLogForFailFastException(LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo)
+inline void DoLogForFailFastException(LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource)
{
WRAPPER_NO_CONTRACT;
Thread *pThread = GetThread();
EX_TRY
{
- PrintToStdErrA("FailFast: ");
+ if (errorSource == NULL)
+ {
+ PrintToStdErrA("FailFast:");
+ }
+ else
+ {
+ PrintToStdErrW((WCHAR*)errorSource);
+ }
+
+ PrintToStdErrA("\n");
PrintToStdErrW((WCHAR*)pszMessage);
PrintToStdErrA("\n");
- if (pThread)
+ if (pThread && errorSource == NULL)
{
PrintToStdErrA("\n");
LogCallstackForLogWorker();
@@ -1203,7 +1212,7 @@ inline void DoLogForFailFastException(LPCWSTR pszMessage, PEXCEPTION_POINTERS pE
// Log an error to the event log if possible, then throw up a dialog box.
//
-void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo)
+void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource)
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_TRIGGERS;
@@ -1214,7 +1223,7 @@ void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage
// Log FailFast exception to StdErr
if (exitCode == (UINT)COR_E_FAILFAST)
{
- DoLogForFailFastException(pszMessage, pExceptionInfo);
+ DoLogForFailFastException(pszMessage, pExceptionInfo, errorSource);
}
if(ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, FailFast))
@@ -1469,7 +1478,7 @@ void DECLSPEC_NORETURN EEPolicy::HandleFatalStackOverflow(EXCEPTION_POINTERS *pE
UNREACHABLE();
}
-void DECLSPEC_NORETURN EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage /* = NULL */, PEXCEPTION_POINTERS pExceptionInfo /* = NULL */)
+void DECLSPEC_NORETURN EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage /* = NULL */, PEXCEPTION_POINTERS pExceptionInfo /* = NULL */, LPCWSTR errorSource /* = NULL */)
{
WRAPPER_NO_CONTRACT;
@@ -1519,11 +1528,11 @@ void DECLSPEC_NORETURN EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR addres
switch (GetEEPolicy()->GetActionOnFailure(FAIL_FatalRuntime))
{
case eRudeExitProcess:
- LogFatalError(exitCode, address, pszMessage, pExceptionInfo);
+ LogFatalError(exitCode, address, pszMessage, pExceptionInfo, errorSource);
SafeExitProcess(exitCode, TRUE);
break;
case eDisableRuntime:
- LogFatalError(exitCode, address, pszMessage, pExceptionInfo);
+ LogFatalError(exitCode, address, pszMessage, pExceptionInfo, errorSource);
DisableRuntime(SCA_ExitProcessWhenShutdownComplete);
break;
default:
diff --git a/src/vm/eepolicy.h b/src/vm/eepolicy.h
index 4d61feef83..a757956a11 100644
--- a/src/vm/eepolicy.h
+++ b/src/vm/eepolicy.h
@@ -124,7 +124,7 @@ public:
static void HandleExitProcess(ShutdownCompleteAction sca = SCA_ExitProcessWhenShutdownComplete);
- static void DECLSPEC_NORETURN HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pMessage=NULL, PEXCEPTION_POINTERS pExceptionInfo= NULL);
+ static void DECLSPEC_NORETURN HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pMessage=NULL, PEXCEPTION_POINTERS pExceptionInfo= NULL, LPCWSTR errorSource=NULL);
static void DECLSPEC_NORETURN HandleFatalStackOverflow(EXCEPTION_POINTERS *pException, BOOL fSkipDebugger = FALSE);
@@ -147,7 +147,7 @@ private:
BOOL IsValidActionForFailure(EClrFailure failure, EPolicyAction action);
EPolicyAction GetFinalAction(EPolicyAction action, Thread *pThread);
- static void LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pMessage, PEXCEPTION_POINTERS pExceptionInfo);
+ static void LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource);
// IMPORTANT NOTE: only the following two functions should be calling ExitProcessViaShim.
// - CorHost2::ExitProcess
@@ -188,4 +188,7 @@ extern ULONGLONG GetObjFinalizeStartTime();
// FailFast with specific error code and exception details
#define EEPOLICY_HANDLE_FATAL_ERROR_USING_EXCEPTION_INFO(_exitcode, _pExceptionInfo) EEPolicy::HandleFatalError(_exitcode, GetCurrentIP(), NULL, _pExceptionInfo);
+// Failfast with specific error code, exception details, and debug info
+#define EEPOLICY_HANDLE_FATAL_ERROR_USING_EXCEPTION_AND_DEBUG_INFO(_exitcode, _pExceptionInfo, _isDebug) EEPolicy::HandleFatalError(_exitcode, GetCurrentIP(), NULL, _pExceptionInfo, _isDebug);
+
#endif // EEPOLICY_H_
diff --git a/src/vm/fcall.h b/src/vm/fcall.h
index c3f026bccb..c50c6edbd7 100644
--- a/src/vm/fcall.h
+++ b/src/vm/fcall.h
@@ -653,6 +653,18 @@ LPVOID __FCThrowArgument(LPVOID me, enum RuntimeExceptionKind reKind, LPCWSTR ar
#define HELPER_METHOD_FRAME_BEGIN_2(arg1, arg2) HELPER_METHOD_FRAME_BEGIN_ATTRIB_2(Frame::FRAME_ATTR_NONE, arg1, arg2)
+#define HELPER_METHOD_FRAME_BEGIN_ATTRIB_3(attribs, arg1, arg2, arg3) \
+ static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
+ static_assert(sizeof(arg2) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
+ static_assert(sizeof(arg3) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
+ HELPER_METHOD_FRAME_BEGIN_EX( \
+ return, \
+ HELPER_FRAME_DECL(3)(HELPER_FRAME_ARGS(attribs), \
+ (OBJECTREF*) &arg1, (OBJECTREF*) &arg2, (OBJECTREF*) &arg3), \
+ HELPER_METHOD_POLL(),TRUE)
+
+#define HELPER_METHOD_FRAME_BEGIN_3(arg1, arg2, arg3) HELPER_METHOD_FRAME_BEGIN_ATTRIB_3(Frame::FRAME_ATTR_NONE, arg1, arg2, arg3)
+
#define HELPER_METHOD_FRAME_BEGIN_PROTECT(gc) \
HELPER_METHOD_FRAME_BEGIN_EX( \
return, \
diff --git a/src/vm/frames.h b/src/vm/frames.h
index 2ee197d38c..66520a849c 100644
--- a/src/vm/frames.h
+++ b/src/vm/frames.h
@@ -60,6 +60,8 @@
// | |
// + +-HelperMethodFrame_2OBJ- reports additional object references
// | |
+// + +-HelperMethodFrame_3OBJ- reports additional object references
+// | |
// + +-HelperMethodFrame_PROTECTOBJ - reports additional object references
// |
// +-TransitionFrame - this abstract frame represents a transition from
@@ -215,6 +217,7 @@ FRAME_TYPE_NAME(FuncEvalFrame)
FRAME_TYPE_NAME(HelperMethodFrame)
FRAME_TYPE_NAME(HelperMethodFrame_1OBJ)
FRAME_TYPE_NAME(HelperMethodFrame_2OBJ)
+FRAME_TYPE_NAME(HelperMethodFrame_3OBJ)
FRAME_TYPE_NAME(HelperMethodFrame_PROTECTOBJ)
FRAME_ABSTRACT_TYPE_NAME(FramedMethodFrame)
FRAME_TYPE_NAME(SecureDelegateFrame)
@@ -1549,6 +1552,72 @@ private:
DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_2OBJ)
};
+//-----------------------------------------------------------------------------
+// HelperMethodFrame_3OBJ
+//-----------------------------------------------------------------------------
+
+class HelperMethodFrame_3OBJ : public HelperMethodFrame
+{
+ VPTR_VTABLE_CLASS(HelperMethodFrame_3OBJ, HelperMethodFrame)
+
+public:
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ HelperMethodFrame_3OBJ(
+ void* fCallFtnEntry,
+ unsigned attribs,
+ OBJECTREF* aGCPtr1,
+ OBJECTREF* aGCPtr2,
+ OBJECTREF* aGCPtr3)
+ : HelperMethodFrame(fCallFtnEntry, attribs)
+ {
+ LIMITED_METHOD_CONTRACT;
+ gcPtrs[0] = aGCPtr1;
+ gcPtrs[1] = aGCPtr2;
+ gcPtrs[2] = aGCPtr3;
+ INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
+ INDEBUG(Thread::ObjectRefProtected(aGCPtr2);)
+ INDEBUG(Thread::ObjectRefProtected(aGCPtr3);)
+ INDEBUG((*aGCPtr1).Validate();)
+ INDEBUG((*aGCPtr2).Validate();)
+ INDEBUG((*aGCPtr3).Validate();)
+ }
+#endif
+
+ virtual void GcScanRoots(promote_func *fn, ScanContext* sc)
+ {
+ WRAPPER_NO_CONTRACT;
+ DoPromote(fn, sc, gcPtrs[0], FALSE);
+ DoPromote(fn, sc, gcPtrs[1], FALSE);
+ DoPromote(fn, sc, gcPtrs[2], FALSE);
+ HelperMethodFrame::GcScanRoots(fn, sc);
+ }
+
+#ifdef _DEBUG
+#ifndef DACCESS_COMPILE
+ void Pop()
+ {
+ WRAPPER_NO_CONTRACT;
+ HelperMethodFrame::Pop();
+ Thread::ObjectRefNew(gcPtrs[0]);
+ Thread::ObjectRefNew(gcPtrs[1]);
+ Thread::ObjectRefNew(gcPtrs[2]);
+ }
+#endif // DACCESS_COMPILE
+
+ BOOL Protects(OBJECTREF *ppORef)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1] || ppORef == gcPtrs[2]) ? TRUE : FALSE;
+ }
+#endif
+
+private:
+ PTR_OBJECTREF gcPtrs[3];
+
+ // Keep as last entry in class
+ DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_3OBJ)
+};
+
//-----------------------------------------------------------------------------
// HelperMethodFrame_PROTECTOBJ
@@ -3423,6 +3492,10 @@ public:
FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1, OBJECTREF * aGCPtr2) :
m_frame(fCallFtnEntry, attribs, aGCPtr1, aGCPtr2) { WRAPPER_NO_CONTRACT; }
+ // HelperMethodFrame_3OBJ
+ FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1, OBJECTREF * aGCPtr2, OBJECTREF * aGCPtr3) :
+ m_frame(fCallFtnEntry, attribs, aGCPtr1, aGCPtr2, aGCPtr3) { WRAPPER_NO_CONTRACT; }
+
// HelperMethodFrame_PROTECTOBJ
FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs) :
m_frame(fCallFtnEntry, attribs, pObjRefs, numObjRefs) { WRAPPER_NO_CONTRACT; }
diff --git a/src/vm/metasig.h b/src/vm/metasig.h
index 5218eb78d2..47dd024bde 100644
--- a/src/vm/metasig.h
+++ b/src/vm/metasig.h
@@ -560,6 +560,7 @@ DEFINE_METASIG(SM(Obj_Bool_RetVoid, j F, v))
DEFINE_METASIG(SM(Str_RetVoid, s, v))
DEFINE_METASIG(SM(Str_Uint_RetVoid, s K, v))
DEFINE_METASIG_T(SM(Str_Exception_RetVoid, s C(EXCEPTION), v))
+DEFINE_METASIG_T(SM(Str_Exception_Str_RetVoid, s C(EXCEPTION) s, v))
// fields - e.g.:
// DEFINE_METASIG(Fld(PtrVoid, P(v)))