Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,27 @@ private static void InitInstantiatedClass(MethodTable* mt, MethodDesc* methodDes
else
InitClassSlow(pMT);
}

[DebuggerHidden]
[UnmanagedCallersOnly]
internal static void CallClassConstructor(void* cctor, void* instantiatingArg, Exception* pException)
{
try
{
if (instantiatingArg == null)
{
((delegate*<void>)cctor)();
}
else
{
// Explicitly pass the instantiating argument as a regular argument to match the ABI of a non-instantiating stub.
((delegate*<void*, void>)cctor)(instantiatingArg);
}
}
catch (Exception ex)
{
*pException = ex;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,19 @@ internal static unsafe void CallToString(object* pObj, string* pResult, Exceptio
*pException = ex;
}
}

[UnmanagedCallersOnly]
internal static unsafe void CallDefaultConstructor(object* pObj, delegate*<object, void> pCtor, Exception* pException)
{
try
{
pCtor(*pObj);
}
catch (Exception ex)
{
*pException = ex;
}
}
}
// Helper class to assist with unsafe pinning of arbitrary objects.
// It's used by VM code.
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/md/datablob.inl
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,11 @@ void
DataBlob::Clear()
{
m_cbSize = 0;
#ifndef TARGET_WASM
// For debugging purposes let's put invalid non-NULL pointer here
// Emscripten doesn't handle this case well in memcpy, so don't do it for WASM target.
INDEBUG_MD(m_pbData = const_pbBadFood);
#endif // !TARGET_WASM
} // DataBlob::Clear

#undef const_pbBadFood
Expand Down
57 changes: 4 additions & 53 deletions src/coreclr/vm/callhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
#include "common.h"
#include "dbginterface.h"

// To include declaration of "AppDomainTransitionExceptionFilter"
#include "excep.h"
#include "invokeutil.h"
#include "argdestination.h"

Expand Down Expand Up @@ -110,40 +108,6 @@ void CallDescrWorker(CallDescrData * pCallDescrData)
}
#endif // !defined(HOST_64BIT) && defined(_DEBUG)

void DispatchCallDebuggerWrapper(
CallDescrData * pCallDescrData,
BOOL fCriticalCall
)
{
// Use static contracts b/c we have SEH.
STATIC_CONTRACT_THROWS;
STATIC_CONTRACT_GC_TRIGGERS;
STATIC_CONTRACT_MODE_COOPERATIVE;

struct Param : NotifyOfCHFFilterWrapperParam
{
CallDescrData * pCallDescrData;
BOOL fCriticalCall;
} param;

param.pFrame = NULL;
param.pCallDescrData = pCallDescrData;
param.fCriticalCall = fCriticalCall;

PAL_TRY(Param *, pParam, &param)
{
CallDescrWorkerWithHandler(
pParam->pCallDescrData,
pParam->fCriticalCall);
}
PAL_EXCEPT_FILTER(AppDomainTransitionExceptionFilter)
{
// Should never reach here b/c handler should always continue search.
_ASSERTE(!"Unreachable");
}
PAL_ENDTRY
}

#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64)
void CopyReturnedFpStructFromRegisters(void* dest, UINT64 returnRegs[2], FpStructInRegistersInfo info,
bool handleGcRefs)
Expand Down Expand Up @@ -180,7 +144,7 @@ void* DispatchCallSimple(
SIZE_T *pSrc,
DWORD numStackSlotsToCopy,
PCODE pTargetAddress,
DWORD dwDispatchCallSimpleFlags)
BOOL fCriticalCall)
{
CONTRACTL
{
Expand Down Expand Up @@ -232,16 +196,7 @@ void* DispatchCallSimple(
}
#endif // TARGET_WASM

if ((dwDispatchCallSimpleFlags & DispatchCallSimple_CatchHandlerFoundNotification) != 0)
{
DispatchCallDebuggerWrapper(
&callDescrData,
dwDispatchCallSimpleFlags & DispatchCallSimple_CriticalCall);
}
else
{
CallDescrWorkerWithHandler(&callDescrData, dwDispatchCallSimpleFlags & DispatchCallSimple_CriticalCall);
}
CallDescrWorkerWithHandler(&callDescrData, fCriticalCall);

return *(void **)(&callDescrData.returnValue);
}
Expand Down Expand Up @@ -606,13 +561,9 @@ void CallDefaultConstructor(OBJECTREF ref)

MethodDesc *pMD = pMT->GetDefaultConstructor();

PREPARE_NONVIRTUAL_CALLSITE_USING_METHODDESC(pMD);
DECLARE_ARGHOLDER_ARRAY(CtorArgs, 1);
CtorArgs[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(ref);
UnmanagedCallersOnlyCaller defaultCtorInvoker{METHOD__RUNTIME_HELPERS__CALL_DEFAULT_CONSTRUCTOR};

// Call the ctor...
CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE;
CALL_MANAGED_METHOD_NORET(CtorArgs);
defaultCtorInvoker.InvokeThrowing(&ref, pMD->GetSingleCallableAddrOfCode());

GCPROTECT_END ();
}
35 changes: 4 additions & 31 deletions src/coreclr/vm/callhelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ void* DispatchCallSimple(
SIZE_T *pSrc,
DWORD numStackSlotsToCopy,
PCODE pTargetAddress,
DWORD dwDispatchCallSimpleFlags);
BOOL fCriticalCall);

#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64)
// Copy structs returned according to floating-point calling convention from 'returnRegs' containing struct fields
Expand Down Expand Up @@ -499,12 +499,6 @@ enum EEToManagedCallFlags
/* Macros that provide abstraction to the usage of DispatchCallSimple */
/***********************************************************************/

enum DispatchCallSimpleFlags
{
DispatchCallSimple_CriticalCall = 0x0001,
DispatchCallSimple_CatchHandlerFoundNotification = 0x0002,
};

#define ARGHOLDER_TYPE LPVOID
#define OBJECTREF_TO_ARGHOLDER(x) (LPVOID)OBJECTREFToObject(x)
#define STRINGREF_TO_ARGHOLDER(x) (LPVOID)STRINGREFToObject(x)
Expand All @@ -514,7 +508,7 @@ enum DispatchCallSimpleFlags

#define INIT_VARIABLES(count) \
DWORD __numArgs = count; \
DWORD __dwDispatchCallSimpleFlags = 0; \
BOOL __criticalDispatchCall = FALSE; \

#define PREPARE_NONVIRTUAL_CALLSITE(id) \
static PCODE s_pAddr##id = 0; \
Expand All @@ -527,39 +521,18 @@ enum DispatchCallSimpleFlags
VolatileStore(&s_pAddr##id, __pSlot); \
}

#define PREPARE_VIRTUAL_CALLSITE(id, objref) \
MethodDesc *__pMeth = CoreLibBinder::GetMethod(id); \
PCODE __pSlot = __pMeth->GetCallTarget(&objref);

#define PREPARE_VIRTUAL_CALLSITE_USING_METHODDESC(pMD, objref) \
PCODE __pSlot = pMD->GetCallTarget(&objref);

#define PREPARE_NONVIRTUAL_CALLSITE_USING_METHODDESC(pMD) \
PCODE __pSlot = (pMD)->GetSingleCallableAddrOfCode();

#define PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pCode) \
PCODE __pSlot = pCode;

#define CRITICAL_CALLSITE \
__dwDispatchCallSimpleFlags |= DispatchCallSimple_CriticalCall;

// This flag should be used for callsites that catch exception up the stack inside the VM. The most common causes are
// such as END_DOMAIN_TRANSITION or EX_CATCH. Catching exceptions in the managed code is properly instrumented and
// does not need this notification.
//
// The notification is what enables both the managed 'unhandled exception' dialog and the 'user unhandled' dialog when
// JMC is turned on. Many things that VS puts up the unhandled exception dialog for are actually cases where the native
// exception was caught, for example catching exceptions at the thread base. JMC requires further accuracy - in that case
// VS is checking to see if an exception escaped particular ranges of managed code frames.
#define CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE \
__dwDispatchCallSimpleFlags |= DispatchCallSimple_CatchHandlerFoundNotification;
__criticalDispatchCall = TRUE;

#define PERFORM_CALL \
void * __retval = NULL; \
__retval = DispatchCallSimple(__pArgs, \
__numStackSlotsToCopy, \
__pSlot, \
__dwDispatchCallSimpleFlags);\
__criticalDispatchCall); \

#ifdef CALLDESCR_ARGREGS

Expand Down
7 changes: 2 additions & 5 deletions src/coreclr/vm/cominterfacemarshaler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,9 @@ void COMInterfaceMarshaler::CreateObjectRef(BOOL fDuplicate, OBJECTREF *pComObj,
MethodDesc *pCtorMD = m_typeHandle.GetMethodTable()->GetDefaultConstructor();
if (pCtorMD)
{
PREPARE_NONVIRTUAL_CALLSITE_USING_METHODDESC(pCtorMD);
DECLARE_ARGHOLDER_ARRAY(CtorArgs, 1);
CtorArgs[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(*pComObj);
UnmanagedCallersOnlyCaller defaultCtorInvoker{METHOD__RUNTIME_HELPERS__CALL_DEFAULT_CONSTRUCTOR};

// Call the ctor...
CALL_MANAGED_METHOD_NORET(CtorArgs);
defaultCtorInvoker.InvokeThrowing(pComObj, pCtorMD->GetSingleCallableAddrOfCode());
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ DEFINE_METHOD(RUNTIME_HELPERS, COPY_CONSTRUCT, CopyConstruct, NoSig
DEFINE_METHOD(RUNTIME_HELPERS, SET_NEXT_CALL_GENERIC_CONTEXT, SetNextCallGenericContext, NoSig)
DEFINE_METHOD(RUNTIME_HELPERS, SET_NEXT_CALL_ASYNC_CONTINUATION, SetNextCallAsyncContinuation, NoSig)
DEFINE_METHOD(RUNTIME_HELPERS, CALL_TO_STRING, CallToString, SM_PtrObj_PtrStr_PtrException_RetVoid)
DEFINE_METHOD(RUNTIME_HELPERS, CALL_DEFAULT_CONSTRUCTOR, CallDefaultConstructor, NoSig)

DEFINE_CLASS(ASYNC_HELPERS, CompilerServices, AsyncHelpers)
DEFINE_METHOD(ASYNC_HELPERS, ALLOC_CONTINUATION, AllocContinuation, NoSig)
Expand Down Expand Up @@ -1311,6 +1312,7 @@ DEFINE_METHOD(GENERICSHELPERS, CLASSWITHSLOTANDMODULE, ClassWithSlotAndModule, N
DEFINE_CLASS(INITHELPERS, CompilerServices, InitHelpers)
DEFINE_METHOD(INITHELPERS, INITCLASS, InitClass, NoSig)
DEFINE_METHOD(INITHELPERS, INITINSTANTIATEDCLASS, InitInstantiatedClass, NoSig)
DEFINE_METHOD(INITHELPERS, CALLCLASSCONSTRUCTOR, CallClassConstructor, SM_PtrVoid_PtrVoid_PtrException_RetVoid)

DEFINE_CLASS(STATICSHELPERS, CompilerServices, StaticsHelpers)
DEFINE_METHOD(STATICSHELPERS, GET_NONGC_STATIC, GetNonGCStaticBase, NoSig)
Expand Down
86 changes: 5 additions & 81 deletions src/coreclr/vm/excep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4929,7 +4929,7 @@ LPVOID COMPlusCheckForAbort(UINT_PTR uTryCatchResumeAddress)
// we should maintain the original exception point's bucket details.
if (pUEWatsonBucketTracker->RetrieveWatsonBucketIp() != NULL)
{
_ASSERTE(pUEWatsonBucketTracker->CapturedForThreadAbort() || pUEWatsonBucketTracker->CapturedAtADTransition());
_ASSERTE(pUEWatsonBucketTracker->CapturedForThreadAbort());
fClearUEWatsonBucketTracker = FALSE;
}
#ifdef _DEBUG
Expand Down Expand Up @@ -6948,57 +6948,6 @@ LONG NotifyOfCHFFilterWrapper(
return ret;
} // LONG NotifyOfCHFFilterWrapper()

// This filter will be used process exceptions escaping out of AD transition boundaries
// that are not at the base of the managed thread. Those are handled in ThreadBaseRedirectingFilter.
// This will be invoked when an exception is going unhandled from the called AppDomain.
//
// This can be used to do last moment work before the exception gets caught by the EX_CATCH setup
// at the AD transition point.
LONG AppDomainTransitionExceptionFilter(
EXCEPTION_POINTERS *pExceptionInfo, // the pExceptionInfo passed to a filter function.
PVOID pParam)
{
// Ideally, we would be NOTHROW here. However, NotifyOfCHFFilterWrapper calls into
// NotifyOfCHFFilter that is THROWS. Thus, to prevent contract violation,
// we abide by the rules and be THROWS.
//
// Same rationale for GC_TRIGGERS as well.
CONTRACTL
{
GC_TRIGGERS;
MODE_ANY;
THROWS;
}
CONTRACTL_END;

ULONG ret = EXCEPTION_CONTINUE_SEARCH;

// First, call into NotifyOfCHFFilterWrapper
ret = NotifyOfCHFFilterWrapper(pExceptionInfo, pParam);

#ifndef TARGET_UNIX
// Setup the watson bucketing details if the escaping
// exception is preallocated.
if (SetupWatsonBucketsForEscapingPreallocatedExceptions())
{
// Set the flag that these were captured at AD Transition
DEBUG_STMT(GetThread()->GetExceptionState()->GetUEWatsonBucketTracker()->SetCapturedAtADTransition());
}

// Attempt to capture buckets for non-preallocated exceptions just before the AppDomain transition boundary
{
GCX_COOP();
OBJECTREF oThrowable = GetThread()->GetThrowable();
if ((oThrowable != NULL) && (CLRException::IsPreallocatedExceptionObject(oThrowable) == FALSE))
{
SetupWatsonBucketsForNonPreallocatedExceptions();
}
}
#endif // !TARGET_UNIX

return ret;
} // LONG AppDomainTransitionExceptionFilter()

// This filter will be used process exceptions escaping out of dynamic reflection invocation as
// unhandled and will eventually be caught in the VM to be made as inner exception of
// TargetInvocationException that will be thrown from the VM.
Expand Down Expand Up @@ -7911,25 +7860,7 @@ PTR_EHWatsonBucketTracker GetWatsonBucketTrackerForPreallocatedException(OBJECTR
doValidation:
_ASSERTE(pWBTracker != NULL);

// Incase of an OOM, we may not have an IP in the Watson bucket tracker. A scenario
// would be default domain calling to AD 2 that calls into AD 3.
//
// AD 3 has an exception that is represented by a preallocated exception object. The
// exception goes unhandled and reaches AD2/AD3 transition boundary. The bucketing details
// from AD3 are copied to UETracker and once the exception is reraised in AD2, we will
// enter SetupInitialThrowBucketingDetails to copy the bucketing details to the active
// exception tracker.
//
// This copy operation could fail due to OOM and the active exception tracker in AD 2,
// for the preallocated exception object, will not have any bucketing details. If the
// exception remains unhandled in AD 2, then just before it reaches DefDomain/AD2 boundary,
// we will attempt to capture the bucketing details in AppDomainTransitionExceptionFilter,
// that will bring us here.
//
// In such a case, the active exception tracker will not have any bucket details for the
// preallocated exception. In such a case, if the IP does not exist, we will return NULL
// indicating that we couldnt find the Watson bucket tracker, since returning a tracker
// that does not have any bucketing details will be of no use to the caller.
// In case of an OOM, we may not have an IP in the Watson bucket tracker.
if (pWBTracker->RetrieveWatsonBucketIp() != NULL)
{
// Check if the buckets exist or not..
Expand Down Expand Up @@ -8321,11 +8252,6 @@ void SetupInitialThrowBucketDetails(UINT_PTR adjustedIp)

// If we are here, then this was a new exception raised
// from outside the managed EH clauses (fault/finally/catch).
//
// The throwable *may* have the bucketing details already
// if this exception was raised when it was crossing over
// an AD transition boundary. Those are stored in UE watson bucket
// tracker by AppDomainTransitionExceptionFilter.
if (fIsPreallocatedException)
{
PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = pExState->GetUEWatsonBucketTracker();
Expand All @@ -8351,10 +8277,8 @@ void SetupInitialThrowBucketDetails(UINT_PTR adjustedIp)
}
}
#endif // _DEBUG
// These should have been captured at AD transition OR
// could be bucketing details of preallocated [rude] thread abort exception.
_ASSERTE(pUEWatsonBucketTracker->CapturedAtADTransition() ||
((fIsThreadAbortException || fIsPreallocatedOOMExceptionForTA) && pUEWatsonBucketTracker->CapturedForThreadAbort()));
// These could be bucketing details of preallocated [rude] thread abort exception.
_ASSERTE((fIsThreadAbortException || fIsPreallocatedOOMExceptionForTA) && pUEWatsonBucketTracker->CapturedForThreadAbort());

if (!fIsThreadAbortException)
{
Expand Down Expand Up @@ -8440,7 +8364,7 @@ void SetupInitialThrowBucketDetails(UINT_PTR adjustedIp)
if (ip != NULL)
{
// Confirm that we had the buckets captured for thread abort
_ASSERTE(pUEWatsonBucketTracker->CapturedForThreadAbort() || pUEWatsonBucketTracker->CapturedAtADTransition());
_ASSERTE(pUEWatsonBucketTracker->CapturedForThreadAbort());

if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() != NULL)
{
Expand Down
5 changes: 0 additions & 5 deletions src/coreclr/vm/excep.h
Original file line number Diff line number Diff line change
Expand Up @@ -647,11 +647,6 @@ inline void CopyOSContext(T_CONTEXT* pDest, T_CONTEXT* pSrc)

void SaveCurrentExceptionInfo(PEXCEPTION_RECORD pRecord, PT_CONTEXT pContext);

// See implementation for detailed comments in excep.cpp
LONG AppDomainTransitionExceptionFilter(
EXCEPTION_POINTERS *pExceptionInfo, // the pExceptionInfo passed to a filter function.
PVOID pParam);

// See implementation for detailed comments in excep.cpp
LONG ReflectionInvocationExceptionFilter(
EXCEPTION_POINTERS *pExceptionInfo, // the pExceptionInfo passed to a filter function.
Expand Down
Loading
Loading