Skip to content
Merged
6 changes: 6 additions & 0 deletions src/coreclr/inc/eetwain.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ virtual BOOL LeaveFinally(GCInfoToken gcInfoToken,
virtual void LeaveCatch(GCInfoToken gcInfoToken,
unsigned offset,
PCONTEXT pCtx)=0;
#else // FEATURE_EH_FUNCLETS
virtual DWORD_PTR CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilter) = 0;
#endif // FEATURE_EH_FUNCLETS

#ifdef FEATURE_REMAP_FUNCTION
Expand Down Expand Up @@ -569,6 +571,8 @@ virtual BOOL LeaveFinally(GCInfoToken gcInfoToken,
virtual void LeaveCatch(GCInfoToken gcInfoToken,
unsigned offset,
PCONTEXT pCtx);
#else // FEATURE_EH_FUNCLETS
virtual DWORD_PTR CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilter);
#endif // FEATURE_EH_FUNCLETS

#ifdef FEATURE_REMAP_FUNCTION
Expand Down Expand Up @@ -795,6 +799,8 @@ virtual void LeaveCatch(GCInfoToken gcInfoToken,
// Interpreter-TODO: Implement this if needed
_ASSERTE(FALSE);
}
#else // FEATURE_EH_FUNCLETS
virtual DWORD_PTR CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilter);
#endif // FEATURE_EH_FUNCLETS

#ifdef FEATURE_REMAP_FUNCTION
Expand Down
162 changes: 161 additions & 1 deletion src/coreclr/vm/eetwain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "interpexec.h"
#endif // FEATURE_INTERPRETER

#include "exinfo.h"

#ifdef TARGET_X86

// NOTE: enabling compiler optimizations, even for debug builds.
Expand All @@ -37,6 +39,8 @@ void promoteVarArgs(PTR_BYTE argsStart, PTR_VASigCookie varArgSig, GCCONTEXT* ct

#include "argdestination.h"

#include "exceptionhandling.h"

#ifndef DACCESS_COMPILE
#ifndef FEATURE_EH_FUNCLETS

Expand Down Expand Up @@ -2124,7 +2128,163 @@ void EECodeManager::LeaveCatch(GCInfoToken gcInfoToken,

return;
}
#else // !FEATURE_EH_FUNCLETS

#ifndef TARGET_WASM

#ifdef USE_FUNCLET_CALL_HELPER
// This is an assembly helper that enables us to call into EH funclets.
EXTERN_C DWORD_PTR STDCALL CallEHFunclet(Object *pThrowable, UINT_PTR pFuncletToInvoke, UINT_PTR *pFirstNonVolReg, UINT_PTR *pFuncletCallerSP);

// This is an assembly helper that enables us to call into EH filter funclets.
EXTERN_C DWORD_PTR STDCALL CallEHFilterFunclet(Object *pThrowable, TADDR CallerSP, UINT_PTR pFuncletToInvoke, UINT_PTR *pFuncletCallerSP);

typedef DWORD_PTR (HandlerFn)(UINT_PTR uStackFrame, Object* pExceptionObj);

static inline UINT_PTR CastHandlerFn(HandlerFn *pfnHandler)
{
#ifdef TARGET_ARM
return DataPointerToThumbCode<UINT_PTR, HandlerFn *>(pfnHandler);
#else
return (UINT_PTR)pfnHandler;
#endif
}

static inline UINT_PTR *GetFirstNonVolatileRegisterAddress(PCONTEXT pContextRecord)
{
#if defined(TARGET_ARM)
return (UINT_PTR*)&(pContextRecord->R4);
#elif defined(TARGET_ARM64)
return (UINT_PTR*)&(pContextRecord->X19);
#elif defined(TARGET_LOONGARCH64)
return (UINT_PTR*)&(pContextRecord->S0);
#elif defined(TARGET_X86)
return (UINT_PTR*)&(pContextRecord->Edi);
#elif defined(TARGET_RISCV64)
return (UINT_PTR*)&(pContextRecord->Fp);
#else
PORTABILITY_ASSERT("GetFirstNonVolatileRegisterAddress");
return NULL;
#endif
}

static inline TADDR GetFrameRestoreBase(PCONTEXT pContextRecord)
{
#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
return GetSP(pContextRecord);
#elif defined(TARGET_X86)
return pContextRecord->Ebp;
#else
PORTABILITY_ASSERT("GetFrameRestoreBase");
return NULL;
#endif
}

#endif // USE_FUNCLET_CALL_HELPER

typedef DWORD_PTR (HandlerFn)(UINT_PTR uStackFrame, Object* pExceptionObj);
static UINT_PTR GetEstablisherFrame(REGDISPLAY* pvRegDisplay, ExInfo* exInfo)
{
#ifdef HOST_AMD64
_ASSERTE(exInfo->m_frameIter.m_crawl.GetRegisterSet() == pvRegDisplay);
if (exInfo->m_frameIter.m_crawl.GetCodeInfo()->HasFrameRegister())
{
ULONG frameOffset = exInfo->m_frameIter.m_crawl.GetCodeInfo()->GetFrameOffsetFromUnwindInfo();
return pvRegDisplay->pCurrentContext->Rbp - 16 * frameOffset;
}
else
{
return pvRegDisplay->SP;
}
#elif defined(HOST_ARM64)
return pvRegDisplay->SP;
#elif defined(HOST_ARM)
return pvRegDisplay->SP;
#elif defined(HOST_X86)
return pvRegDisplay->SP;
#elif defined(HOST_RISCV64)
return pvRegDisplay->SP;
#elif defined(HOST_LOONGARCH64)
return pvRegDisplay->SP;
#endif
}

#endif // TARGET_WASM

// Call catch, finally or filter funclet.
// Return value:
// * Catch funclet: address to resume at after the catch returns
// * Finally funclet: unused
// * Filter funclet: result of the filter funclet (EXCEPTION_CONTINUE_SEARCH (0) or EXCEPTION_EXECUTE_HANDLER (1))
//
// NOTE: This function must be prevented from calling the actual funclet via a tail call to ensure
// that the m_csfEHClause is really set to what is a SP of the caller frame of the funclet. The
// StackFrameIterator relies on this.
#ifdef _MSC_VER
#pragma optimize("", off)
#else
__attribute__((disable_tail_calls))
#endif
DWORD_PTR EECodeManager::CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilterFunclet)
{
DWORD_PTR dwResult = 0;
#ifdef TARGET_WASM
_ASSERTE(!"CallFunclet for WASM not implemented yet");
#else
HandlerFn* pfnHandler = (HandlerFn*)pHandler;

pExInfo->m_csfEHClause = CallerStackFrame((UINT_PTR)GetCurrentSP());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this line be in the #else of #ifdef USE_FUNCLET_CALL_HELPER?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(It would be nice to update x64 to use the asm helper too at some point, so we should keep all workarounds related to that under the !asm helper ifdef.

Switching x64 to asm helper should improve code size of the EH codegen and remove unnecessary differences between architectures.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pExInfo->m_csfEHClause = CallerStackFrame((UINT_PTR)GetCurrentSP());


#ifdef USE_FUNCLET_CALL_HELPER
// Since the actual caller of the funclet is the assembly helper, pass the reference
// to the CallerStackFrame instance so that it can be updated.
CallerStackFrame* pCallerStackFrame = &pExInfo->m_csfEHClause;
UINT_PTR *pFuncletCallerSP = &(pCallerStackFrame->SP);

if (isFilterFunclet)
{
// For invoking IL filter funclet, we pass the CallerSP to the funclet using which
// it will retrieve the framepointer for accessing the locals in the parent
// method.
dwResult = CallEHFilterFunclet(OBJECTREFToObject(throwable),
#ifdef USE_CURRENT_CONTEXT_IN_FILTER
GetFrameRestoreBase(pRD->pCurrentContext),
#else
GetFrameRestoreBase(pRD->pCallerContext),
#endif
CastHandlerFn(pfnHandler),
pFuncletCallerSP);
}
else
{
dwResult = CallEHFunclet(OBJECTREFToObject(throwable),
CastHandlerFn(pfnHandler),
GetFirstNonVolatileRegisterAddress(pRD->pCurrentContext),
pFuncletCallerSP);
}
#else
UINT_PTR establisherFrame = GetEstablisherFrame(pRD, pExInfo);
dwResult = pfnHandler(establisherFrame, OBJECTREFToObject(throwable));
#endif

#endif // TARGET_WASM
return dwResult;
}
#ifdef _MSC_VER
#pragma optimize("", on)
#endif

#ifdef FEATURE_INTERPRETER
DWORD_PTR InterpreterCodeManager::CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilter)
{
// Interpreter-TODO: implement calling the funclet in the intepreted code
_ASSERTE(FALSE);
return 0;
}
#endif // FEATURE_INTERPRETER

#endif // !FEATURE_EH_FUNCLETS

#endif // #ifndef DACCESS_COMPILE

#ifdef DACCESS_COMPILE
Expand Down Expand Up @@ -2400,4 +2560,4 @@ size_t InterpreterCodeManager::GetFunctionSize(GCInfoToken gcInfoToken)
return 0;
}

#endif // FEATURE_INTERPRETER
#endif // FEATURE_INTERPRETER
Loading
Loading