From: Sung Yoon Whang Date: Sat, 3 Feb 2018 23:58:22 +0000 (-0800) Subject: Fix failfast stacktrace (#15895) X-Git-Tag: accepted/tizen/unified/20190422.045933~3085 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c247f5bffa563820fe8db6fa14b42024c57c540f;p=platform%2Fupstream%2Fcoreclr.git 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 --- diff --git a/src/classlibnative/bcltype/system.cpp b/src/classlibnative/bcltype/system.cpp index bb06cec..fdb0416 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 87dde89..6a489ba 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 ce38156..7b7b5f0 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 495f2f7..0554581 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 5178f7f..3a29738 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 s_ShowAssertDialog = ShowAssertDialog; + internal static Action s_ShowDialog = ShowDialog; + internal static Action s_WriteCore = WriteCore; } } diff --git a/src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs b/src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs index 45cb9bb..7b74b01 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 483bf51..e1992b4 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 78ec2a0..a4d5aec 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 4cb2b5a..b94800d 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 b9706bb..51c13ac 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 db47e3f..06c3741 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 4d61fee..a757956 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 c3f026b..c50c6ed 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 2ee197d..66520a8 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 5218eb7..47dd024 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)))