From 1cb5adf9a0b46560e433d63af902ffd0c9b2a74e Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Tue, 19 Aug 2025 02:06:08 -0700
Subject: [PATCH 1/4] Throttle finalization a bit when doing GC stress.
---
src/coreclr/vm/finalizerthread.cpp | 41 +++++++++++++++---------------
1 file changed, 20 insertions(+), 21 deletions(-)
diff --git a/src/coreclr/vm/finalizerthread.cpp b/src/coreclr/vm/finalizerthread.cpp
index 0ad3d680bcd8bc..e091fb39d3b187 100644
--- a/src/coreclr/vm/finalizerthread.cpp
+++ b/src/coreclr/vm/finalizerthread.cpp
@@ -176,6 +176,26 @@ OBJECTREF FinalizerThread::GetNextFinalizableObject()
if (fQuitFinalizer)
return NULL;
+#ifdef _DEBUG
+ if (g_pConfig->GetGCStressLevel() > 1)
+ {
+ // Throttle finalizing to one item per msec, or so, when running GC stress.
+ // This is to prevent cases where finalizers rearm themselves and
+ // do allocations or whatever else that triggers GC under stress.
+ // As a result couple of such things can occupy finalizer loop continuously
+ // while rearming and finalizing the same objects, which adds little
+ // to the coverage, but makes everything else move slower.
+ // NOTE: under GC stress most allocations of finalizable objects
+ // would trigger a GC, thus 1 item/msec should not be too slow for
+ // regular not re-arming finalizables.
+ GetFinalizerThread()->m_GCOnTransitionsOK = FALSE;
+ GetFinalizerThread()->EnablePreemptiveGC();
+ ClrSleepEx(1, false);
+ GetFinalizerThread()->DisablePreemptiveGC();
+ GetFinalizerThread()->m_GCOnTransitionsOK = TRUE;
+ }
+#endif //_DEBUG
+
OBJECTREF obj = ObjectToOBJECTREF(GCHeapUtilities::GetGCHeap()->GetNextFinalizable());
if (obj == NULL)
return NULL;
@@ -432,27 +452,6 @@ VOID FinalizerThread::FinalizerThreadWorker(void *args)
GetFinalizerThread()->DisablePreemptiveGC();
-#ifdef _DEBUG
- // workaround. make finalization very lazy for gcstress 3 or 4.
- // only do finalization if the system is quiescent
- if (g_pConfig->GetGCStressLevel() > 1)
- {
- size_t last_gc_count;
- DWORD dwSwitchCount = 0;
-
- do
- {
- last_gc_count = GCHeapUtilities::GetGCHeap()->CollectionCount(0);
- GetFinalizerThread()->m_GCOnTransitionsOK = FALSE;
- GetFinalizerThread()->EnablePreemptiveGC();
- __SwitchToThread (0, ++dwSwitchCount);
- GetFinalizerThread()->DisablePreemptiveGC();
- // If no GCs happened, then we assume we are quiescent
- GetFinalizerThread()->m_GCOnTransitionsOK = TRUE;
- } while (GCHeapUtilities::GetGCHeap()->CollectionCount(0) - last_gc_count > 0);
- }
-#endif //_DEBUG
-
// we might want to do some extra work on the finalizer thread
// check and do it
if (HaveExtraWorkForFinalizer())
From 446901e7777fdc22ce7807a9777bad9216ccf3d6 Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Fri, 22 Aug 2025 17:07:11 -0700
Subject: [PATCH 2/4] fix indentation
---
src/coreclr/vm/finalizerthread.cpp | 34 +++++++++++++++---------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/src/coreclr/vm/finalizerthread.cpp b/src/coreclr/vm/finalizerthread.cpp
index e091fb39d3b187..ef5949ec055404 100644
--- a/src/coreclr/vm/finalizerthread.cpp
+++ b/src/coreclr/vm/finalizerthread.cpp
@@ -177,23 +177,23 @@ OBJECTREF FinalizerThread::GetNextFinalizableObject()
return NULL;
#ifdef _DEBUG
- if (g_pConfig->GetGCStressLevel() > 1)
- {
- // Throttle finalizing to one item per msec, or so, when running GC stress.
- // This is to prevent cases where finalizers rearm themselves and
- // do allocations or whatever else that triggers GC under stress.
- // As a result couple of such things can occupy finalizer loop continuously
- // while rearming and finalizing the same objects, which adds little
- // to the coverage, but makes everything else move slower.
- // NOTE: under GC stress most allocations of finalizable objects
- // would trigger a GC, thus 1 item/msec should not be too slow for
- // regular not re-arming finalizables.
- GetFinalizerThread()->m_GCOnTransitionsOK = FALSE;
- GetFinalizerThread()->EnablePreemptiveGC();
- ClrSleepEx(1, false);
- GetFinalizerThread()->DisablePreemptiveGC();
- GetFinalizerThread()->m_GCOnTransitionsOK = TRUE;
- }
+ if (g_pConfig->GetGCStressLevel() > 1)
+ {
+ // Throttle finalizing to one item per msec, or so, when running GC stress.
+ // This is to prevent cases where finalizers rearm themselves and
+ // do allocations or whatever else that triggers GC under stress.
+ // As a result couple of such things can occupy finalizer loop continuously
+ // while rearming and finalizing the same objects, which adds little
+ // to the coverage, but makes everything else move slower.
+ // NOTE: under GC stress most allocations of finalizable objects
+ // would trigger a GC, thus 1 item/msec should not be too slow for
+ // regular not re-arming finalizables.
+ GetFinalizerThread()->m_GCOnTransitionsOK = FALSE;
+ GetFinalizerThread()->EnablePreemptiveGC();
+ ClrSleepEx(1, false);
+ GetFinalizerThread()->DisablePreemptiveGC();
+ GetFinalizerThread()->m_GCOnTransitionsOK = TRUE;
+ }
#endif //_DEBUG
OBJECTREF obj = ObjectToOBJECTREF(GCHeapUtilities::GetGCHeap()->GetNextFinalizable());
From 54c95af8cfe599d8afc795c83723a8e4dc64d65b Mon Sep 17 00:00:00 2001
From: Jan Kotas
Date: Fri, 22 Aug 2025 19:57:39 -0700
Subject: [PATCH 3/4] Fix GCStress regression
GCStress is not able to find the original version of the code for PInvoke stubs after #117901. We need to compensate
for the MethodDesc adjustment done for PInvoke stubs when storing the original version of the code during GC stress.
---
src/coreclr/vm/prestub.cpp | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp
index d1f5d7d9415b2e..eba82b409c3ce5 100644
--- a/src/coreclr/vm/prestub.cpp
+++ b/src/coreclr/vm/prestub.cpp
@@ -947,7 +947,24 @@ PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, COR_ILMETHOD_
return pOtherCode;
}
- SetupGcCoverage(pConfig->GetCodeVersion(), (BYTE*)pCode);
+ NativeCodeVersion nativeCodeVersion = pConfig->GetCodeVersion();
+
+ if (IsILStub())
+ {
+ CodeHeader* pHdr = (CodeHeader*)(pCode - sizeof(CodeHeader));
+ MethodDesc* pActualMethodDesc = pHdr->GetMethodDesc();
+
+ if (pActualMethodDesc != this)
+ {
+ // Compensate for PInvoke MethodDesc adjustment done in EECodeGenManager::AllocCode.
+ // The GC stress instrumentation must save the non-instrumented version of the code
+ // on MethodDesc that matches CodeHeader so that it can be retrieved later.
+ _ASSERTE(pActualMethodDesc->IsPInvoke());
+ nativeCodeVersion = NativeCodeVersion(pActualMethodDesc);
+ }
+ }
+
+ SetupGcCoverage(nativeCodeVersion, (BYTE*)pCode);
}
#endif // HAVE_GCCOVER
From 7ac3c79dc90e70257ab908cf191f2285c64b05a7 Mon Sep 17 00:00:00 2001
From: Jan Kotas
Date: Sat, 23 Aug 2025 01:14:41 -0700
Subject: [PATCH 4/4] Partial revert of #117901 for vararg stubs
Interop marshalling of varargs needs MethodDesc calling convention to support ldftn . It is not possible to smugle the target MethodDesc* via vararg cookie in this case.
---
src/coreclr/vm/amd64/PInvokeStubs.asm | 3 +-
src/coreclr/vm/amd64/pinvokestubs.S | 3 +-
src/coreclr/vm/ceeload.cpp | 13 ++------
src/coreclr/vm/ceeload.h | 5 ++--
src/coreclr/vm/cgensys.h | 2 +-
src/coreclr/vm/dllimport.cpp | 18 ++++++-----
src/coreclr/vm/i386/asmhelpers.S | 3 +-
src/coreclr/vm/i386/asmhelpers.asm | 5 ++--
src/coreclr/vm/ilstubcache.cpp | 22 ++++++++++----
src/coreclr/vm/jitinterface.cpp | 8 +----
src/coreclr/vm/method.cpp | 10 +++++--
src/coreclr/vm/method.hpp | 43 +++++++++++++++++++--------
src/coreclr/vm/stubmgr.cpp | 42 +++++++++++++++-----------
13 files changed, 106 insertions(+), 71 deletions(-)
diff --git a/src/coreclr/vm/amd64/PInvokeStubs.asm b/src/coreclr/vm/amd64/PInvokeStubs.asm
index c334774b443f02..9913dbd3c53f5b 100644
--- a/src/coreclr/vm/amd64/PInvokeStubs.asm
+++ b/src/coreclr/vm/amd64/PInvokeStubs.asm
@@ -113,10 +113,11 @@ NESTED_ENTRY VarargPInvokeGenILStub, _TEXT
mov r13, PINVOKE_CALLI_SIGTOKEN_REGISTER
;
- ; VarargPInvokeStubWorker(TransitionBlock* pTransitionBlock, VASigCookie* pVASigCookie)
+ ; VarargPInvokeStubWorker(TransitionBlock * pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD)
;
lea rcx, [rsp + __PWTB_TransitionBlock] ; pTransitionBlock*
mov rdx, PINVOKE_CALLI_SIGTOKEN_REGISTER ; pVASigCookie
+ mov r8, METHODDESC_REGISTER ; pMD
call VarargPInvokeStubWorker
;
diff --git a/src/coreclr/vm/amd64/pinvokestubs.S b/src/coreclr/vm/amd64/pinvokestubs.S
index 79ec380f288d46..49bc602afee105 100644
--- a/src/coreclr/vm/amd64/pinvokestubs.S
+++ b/src/coreclr/vm/amd64/pinvokestubs.S
@@ -109,10 +109,11 @@ NESTED_ENTRY VarargPInvokeGenILStub, _TEXT, NoHandler
mov r13, PINVOKE_CALLI_SIGTOKEN_REGISTER
//
- // VarargPInvokeStubWorker(TransitionBlock* pTransitionBlock, VASigCookie* pVASigCookie)
+ // VarargPInvokeStubWorker(TransitionBlock * pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD)
//
lea rdi, [rsp + __PWTB_TransitionBlock] // pTransitionBlock*
mov rsi, PINVOKE_CALLI_SIGTOKEN_REGISTER // pVASigCookie
+ mov rdx, METHODDESC_REGISTER // pMD
call C_FUNC(VarargPInvokeStubWorker)
//
diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp
index c2049b36910136..2c7ff8c5e5d642 100644
--- a/src/coreclr/vm/ceeload.cpp
+++ b/src/coreclr/vm/ceeload.cpp
@@ -4197,13 +4197,12 @@ static bool MethodSignatureContainsGenericVariables(SigParser& sp)
//==========================================================================
// Enregisters a VASig.
//==========================================================================
-VASigCookie *Module::GetVASigCookie(Signature vaSignature, MethodDesc* pMD, const SigTypeContext* typeContext)
+VASigCookie *Module::GetVASigCookie(Signature vaSignature, const SigTypeContext* typeContext)
{
CONTRACT(VASigCookie*)
{
INSTANCE_CHECK;
STANDARD_VM_CHECK;
- PRECONDITION(pMD == NULL || pMD->IsPInvoke()); // Only PInvoke methods are embedded in VASig cookies.
POSTCONDITION(CheckPointer(RETVAL));
INJECT_FAULT(COMPlusThrowOM());
}
@@ -4236,17 +4235,16 @@ VASigCookie *Module::GetVASigCookie(Signature vaSignature, MethodDesc* pMD, cons
#endif
}
- VASigCookie *pCookie = GetVASigCookieWorker(this, pLoaderModule, pMD, vaSignature, typeContext);
+ VASigCookie *pCookie = GetVASigCookieWorker(this, pLoaderModule, vaSignature, typeContext);
RETURN pCookie;
}
-VASigCookie *Module::GetVASigCookieWorker(Module* pDefiningModule, Module* pLoaderModule, MethodDesc* pMD, Signature vaSignature, const SigTypeContext* typeContext)
+VASigCookie *Module::GetVASigCookieWorker(Module* pDefiningModule, Module* pLoaderModule, Signature vaSignature, const SigTypeContext* typeContext)
{
CONTRACT(VASigCookie*)
{
STANDARD_VM_CHECK;
- PRECONDITION(pMD == NULL || pMD->IsPInvoke());
POSTCONDITION(CheckPointer(RETVAL));
INJECT_FAULT(COMPlusThrowOM());
}
@@ -4263,10 +4261,6 @@ VASigCookie *Module::GetVASigCookieWorker(Module* pDefiningModule, Module* pLoad
{
VASigCookie* cookieMaybe = &pBlock->m_cookies[i];
- // Check if the cookie targets the same MethodDesc.
- if (cookieMaybe->pMethodDesc != pMD)
- continue;
-
// Check if the cookie has the same signature.
if (cookieMaybe->signature.GetRawSig() == vaSignature.GetRawSig())
{
@@ -4355,7 +4349,6 @@ VASigCookie *Module::GetVASigCookieWorker(Module* pDefiningModule, Module* pLoad
// Now, fill in the new cookie (assuming we had enough memory to create one.)
pCookie->pModule = pDefiningModule;
pCookie->pPInvokeILStub = (PCODE)NULL;
- pCookie->pMethodDesc = pMD;
pCookie->sizeOfArgs = sizeOfArgs;
pCookie->signature = vaSignature;
pCookie->pLoaderModule = pLoaderModule;
diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h
index 758fb21026fc40..4659203b0811b5 100644
--- a/src/coreclr/vm/ceeload.h
+++ b/src/coreclr/vm/ceeload.h
@@ -345,7 +345,6 @@ struct VASigCookie
// so please keep this field first
unsigned sizeOfArgs; // size of argument list
Volatile pPInvokeILStub; // will be use if target is PInvoke (tag == 0)
- PTR_MethodDesc pMethodDesc; // Only non-null if this is a PInvoke method
PTR_Module pModule;
PTR_Module pLoaderModule;
Signature signature;
@@ -1398,9 +1397,9 @@ class Module : public ModuleBase
void NotifyEtwLoadFinished(HRESULT hr);
// Enregisters a VASig.
- VASigCookie *GetVASigCookie(Signature vaSignature, MethodDesc* pMD, const SigTypeContext* typeContext);
+ VASigCookie *GetVASigCookie(Signature vaSignature, const SigTypeContext* typeContext);
private:
- static VASigCookie *GetVASigCookieWorker(Module* pDefiningModule, Module* pLoaderModule, MethodDesc* pMD, Signature vaSignature, const SigTypeContext* typeContext);
+ static VASigCookie *GetVASigCookieWorker(Module* pDefiningModule, Module* pLoaderModule, Signature vaSignature, const SigTypeContext* typeContext);
public:
#ifndef DACCESS_COMPILE
diff --git a/src/coreclr/vm/cgensys.h b/src/coreclr/vm/cgensys.h
index 2e8a6b1a93a161..580e563cb26808 100644
--- a/src/coreclr/vm/cgensys.h
+++ b/src/coreclr/vm/cgensys.h
@@ -50,7 +50,7 @@ enum class CallerGCMode
// Non-CPU-specific helper functions called by the CPU-dependent code
extern "C" PCODE STDCALL PreStubWorker(TransitionBlock * pTransitionBlock, MethodDesc * pMD);
-extern "C" void STDCALL VarargPInvokeStubWorker(TransitionBlock* pTransitionBlock, VASigCookie* pVASigCookie);
+extern "C" void STDCALL VarargPInvokeStubWorker(TransitionBlock* pTransitionBlock, VASigCookie* pVASigCookie, MethodDesc* pMD);
extern "C" void STDCALL VarargPInvokeStub(void);
extern "C" void STDCALL VarargPInvokeStub_RetBuffArg(void);
diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp
index b3be7f1e4e5b8e..00badfce6afc1f 100644
--- a/src/coreclr/vm/dllimport.cpp
+++ b/src/coreclr/vm/dllimport.cpp
@@ -231,7 +231,7 @@ static bool IsSharedStubScenario(DWORD dwStubFlags)
return false;
}
- if (SF_IsForwardPInvokeStub(dwStubFlags) && !SF_IsCALLIStub(dwStubFlags))
+ if (SF_IsForwardPInvokeStub(dwStubFlags) && !SF_IsCALLIStub(dwStubFlags) && !SF_IsVarArgStub(dwStubFlags))
{
return false;
}
@@ -857,9 +857,9 @@ class ILStubState : public StubState
// don't use the secret parameter.
}
else if (SF_IsForwardPInvokeStub(m_dwStubFlags)
- && !SF_IsCALLIStub(m_dwStubFlags))
+ && !SF_IsCALLIStub(m_dwStubFlags) && !SF_IsVarArgStub(m_dwStubFlags))
{
- // Forward stubs (i.e., PInvokes) don't use the secret parameter
+ // Regular PInvokes don't use the secret parameter
}
else
{
@@ -2168,6 +2168,13 @@ void PInvokeStubLinker::DoPInvoke(ILCodeStream *pcsEmit, DWORD dwStubFlags, Meth
pcsEmit->EmitSHR_UN();
#endif // TARGET_64BIT
}
+ else if (SF_IsVarArgStub(dwStubFlags)) // vararg P/Invoke
+ {
+ EmitLoadStubContext(pcsEmit, dwStubFlags);
+ pcsEmit->EmitLDC(offsetof(PInvokeMethodDesc, m_pPInvokeTarget));
+ pcsEmit->EmitADD();
+ pcsEmit->EmitLDIND_I();
+ }
else // forward P/Invoke
{
_ASSERTE(pMD->IsPInvoke());
@@ -6088,7 +6095,7 @@ static void GetILStubForCalli(VASigCookie* pVASigCookie, MethodDesc* pMD)
UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
}
-EXTERN_C void STDCALL VarargPInvokeStubWorker(TransitionBlock* pTransitionBlock, VASigCookie* pVASigCookie)
+EXTERN_C void STDCALL VarargPInvokeStubWorker(TransitionBlock* pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD)
{
PreserveLastErrorHolder preserveLastError;
@@ -6103,9 +6110,6 @@ EXTERN_C void STDCALL VarargPInvokeStubWorker(TransitionBlock* pTransitionBlock,
Thread::ObjectRefFlush(CURRENT_THREAD);
#endif
- MethodDesc* pMD = pVASigCookie->pMethodDesc;
- _ASSERTE(pMD != NULL);
-
PrestubMethodFrame frame(pTransitionBlock, pMD);
PrestubMethodFrame * pFrame = &frame;
diff --git a/src/coreclr/vm/i386/asmhelpers.S b/src/coreclr/vm/i386/asmhelpers.S
index a7dd7f2bf0adfc..634a6aaaf5d088 100644
--- a/src/coreclr/vm/i386/asmhelpers.S
+++ b/src/coreclr/vm/i386/asmhelpers.S
@@ -384,6 +384,7 @@ LOCAL_LABEL(GoCallVarargWorker):
// save pMD
push eax
+ push eax // pMD
push dword ptr [esi + 4*7] // pVaSigCookie
push esi // pTransitionBlock
@@ -1087,4 +1088,4 @@ LEAF_ENTRY IL_Rethrow, _TEXT
STUB_EPILOG
ret 4
-LEAF_END IL_Rethrow
\ No newline at end of file
+LEAF_END IL_Rethrow
diff --git a/src/coreclr/vm/i386/asmhelpers.asm b/src/coreclr/vm/i386/asmhelpers.asm
index fbbd8de5d12fbd..798fefe9f564a4 100644
--- a/src/coreclr/vm/i386/asmhelpers.asm
+++ b/src/coreclr/vm/i386/asmhelpers.asm
@@ -46,7 +46,7 @@ endif ; FEATURE_EH_FUNCLETS
EXTERN __alloca_probe:PROC
EXTERN _PInvokeImportWorker@4:PROC
-EXTERN _VarargPInvokeStubWorker@8:PROC
+EXTERN _VarargPInvokeStubWorker@12:PROC
EXTERN _GenericPInvokeCalliStubWorker@12:PROC
EXTERN _PreStubWorker@8:PROC
@@ -930,10 +930,11 @@ GoCallVarargWorker:
; save pMD
push eax
+ push eax ; pMD
push dword ptr [esi + 4*7] ; pVaSigCookie
push esi ; pTransitionBlock
- call _VarargPInvokeStubWorker@8
+ call _VarargPInvokeStubWorker@12
; restore pMD
pop eax
diff --git a/src/coreclr/vm/ilstubcache.cpp b/src/coreclr/vm/ilstubcache.cpp
index a5558713e17ee9..13f6891133f56a 100644
--- a/src/coreclr/vm/ilstubcache.cpp
+++ b/src/coreclr/vm/ilstubcache.cpp
@@ -118,9 +118,12 @@ namespace
switch (type)
{
- case DynamicMethodDesc::StubCLRToNativeInterop: return "IL_STUB_PInvoke";
+ case DynamicMethodDesc::StubPInvoke:
+ case DynamicMethodDesc::StubPInvokeDelegate:
+ case DynamicMethodDesc::StubPInvokeCalli:
+ case DynamicMethodDesc::StubPInvokeVarArg: return "IL_STUB_PInvoke";
+ case DynamicMethodDesc::StubReversePInvoke: return "IL_STUB_ReversePInvoke";
case DynamicMethodDesc::StubCLRToCOMInterop: return "IL_STUB_CLRtoCOM";
- case DynamicMethodDesc::StubNativeToCLRInterop: return "IL_STUB_ReversePInvoke";
case DynamicMethodDesc::StubCOMToCLRInterop: return "IL_STUB_COMtoCLR";
case DynamicMethodDesc::StubStructMarshalInterop: return "IL_STUB_StructMarshal";
case DynamicMethodDesc::StubArrayOp: return "IL_STUB_Array";
@@ -304,19 +307,26 @@ MethodDesc* ILStubCache::CreateNewMethodDesc(LoaderHeap* pCreationHeap, MethodTa
// mark certain types of stub MDs with random flags so ILStubManager recognizes them
if (SF_IsReverseStub(dwStubFlags))
{
- pMD->SetILStubType(DynamicMethodDesc::StubNativeToCLRInterop);
+ pMD->SetILStubType(DynamicMethodDesc::StubReversePInvoke);
}
else
{
if (SF_IsDelegateStub(dwStubFlags))
{
- pMD->SetFlags(DynamicMethodDesc::FlagIsDelegate);
+ pMD->SetILStubType(DynamicMethodDesc::StubPInvokeDelegate);
}
else if (SF_IsCALLIStub(dwStubFlags))
{
- pMD->SetFlags(DynamicMethodDesc::FlagIsCALLI);
+ pMD->SetILStubType(DynamicMethodDesc::StubPInvokeCalli);
+ }
+ else if (SF_IsVarArgStub(dwStubFlags))
+ {
+ pMD->SetILStubType(DynamicMethodDesc::StubPInvokeVarArg);
+ }
+ else
+ {
+ pMD->SetILStubType(DynamicMethodDesc::StubPInvoke);
}
- pMD->SetILStubType(DynamicMethodDesc::StubCLRToNativeInterop);
}
}
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index da018369afecf0..f7a238c5ce7373 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -6166,13 +6166,7 @@ CORINFO_VARARGS_HANDLE CEEInfo::getVarArgsHandle(CORINFO_SIG_INFO *sig,
Instantiation methodInst = Instantiation((TypeHandle*) sig->sigInst.methInst, sig->sigInst.methInstCount);
SigTypeContext typeContext = SigTypeContext(classInst, methodInst);
- MethodDesc* pMD = GetMethod(methHnd);
- if (pMD != NULL && !pMD->IsPInvoke())
- {
- pMD = NULL;
- }
-
- result = CORINFO_VARARGS_HANDLE(module->GetVASigCookie(Signature(sig->pSig, sig->cbSig), pMD, &typeContext));
+ result = CORINFO_VARARGS_HANDLE(module->GetVASigCookie(Signature(sig->pSig, sig->cbSig), &typeContext));
EE_TO_JIT_TRANSITION();
diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp
index 2511b537097e0c..56c14a77e67c99 100644
--- a/src/coreclr/vm/method.cpp
+++ b/src/coreclr/vm/method.cpp
@@ -2462,7 +2462,7 @@ MethodImpl *MethodDesc::GetMethodImpl()
#ifndef DACCESS_COMPILE
//*******************************************************************************
-BOOL MethodDesc::RequiresMDContextArg() const
+BOOL MethodDesc::RequiresMDContextArg()
{
LIMITED_METHOD_CONTRACT;
@@ -2470,6 +2470,12 @@ BOOL MethodDesc::RequiresMDContextArg() const
if (IsCLRToCOMCall())
return TRUE;
+ // Interop marshalling of vararg needs MethodDesc calling convention
+ // to support ldftn . It is not possible
+ // to smugle the MethodDesc* via vararg cookie in this case.
+ if (IsPInvoke() && IsVarArg())
+ return TRUE;
+
return FALSE;
}
@@ -3497,7 +3503,7 @@ BOOL MethodDesc::HasUnmanagedCallersOnlyAttribute()
{
// Stubs generated for being called from native code are equivalent to
// managed methods marked with UnmanagedCallersOnly.
- return AsDynamicMethodDesc()->GetILStubType() == DynamicMethodDesc::StubNativeToCLRInterop;
+ return AsDynamicMethodDesc()->GetILStubType() == DynamicMethodDesc::StubReversePInvoke;
}
HRESULT hr = GetCustomAttribute(
diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp
index a46c5a09e444ad..e697cf526fc507 100644
--- a/src/coreclr/vm/method.hpp
+++ b/src/coreclr/vm/method.hpp
@@ -1720,7 +1720,7 @@ class MethodDesc
// The stub produced by prestub requires method desc to be passed
// in dedicated register.
// See HasMDContextArg() for the related stub version.
- BOOL RequiresMDContextArg() const;
+ BOOL RequiresMDContextArg();
// Returns true if the method has to have stable entrypoint always.
BOOL RequiresStableEntryPoint();
@@ -2703,9 +2703,12 @@ class DynamicMethodDesc : public StoredSigMethodDesc
enum ILStubType : DWORD
{
StubNotSet = 0,
- StubCLRToNativeInterop,
+ StubPInvoke,
+ StubPInvokeDelegate,
+ StubPInvokeCalli,
+ StubPInvokeVarArg,
+ StubReversePInvoke,
StubCLRToCOMInterop,
- StubNativeToCLRInterop,
StubCOMToCLRInterop,
StubStructMarshalInterop,
StubArrayOp,
@@ -2738,8 +2741,8 @@ class DynamicMethodDesc : public StoredSigMethodDesc
FlagRequiresCOM = 0x00002000,
FlagIsLCGMethod = 0x00004000,
FlagIsILStub = 0x00008000,
- FlagIsDelegate = 0x00010000,
- FlagIsCALLI = 0x00020000,
+ // unused = 0x00010000,
+ // unused = 0x00020000,
FlagMask = 0x0003f800,
StackArgSizeMask = 0xfffc0000, // native stack arg size for IL stubs
ILStubTypeMask = ~(FlagMask | StackArgSizeMask)
@@ -2833,7 +2836,7 @@ class DynamicMethodDesc : public StoredSigMethodDesc
LIMITED_METHOD_DAC_CONTRACT;
_ASSERTE(IsILStub());
ILStubType type = GetILStubType();
- return type == StubCOMToCLRInterop || type == StubNativeToCLRInterop;
+ return type == StubCOMToCLRInterop || type == StubReversePInvoke;
}
bool IsStepThroughStub() const
@@ -2855,21 +2858,37 @@ class DynamicMethodDesc : public StoredSigMethodDesc
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(IsILStub());
- return !HasFlags(FlagStatic) && GetILStubType() == StubCLRToCOMInterop;
+ return GetILStubType() == StubCLRToCOMInterop;
}
bool IsCOMToCLRStub() const
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(IsILStub());
- return !HasFlags(FlagStatic) && GetILStubType() == StubCOMToCLRInterop;
+ return GetILStubType() == StubCOMToCLRInterop;
}
bool IsPInvokeStub() const
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(IsILStub());
- return HasFlags(FlagStatic)
- && !HasFlags(FlagIsCALLI | FlagIsDelegate)
- && GetILStubType() == StubCLRToNativeInterop;
+ return GetILStubType() == StubPInvoke;
+ }
+ bool IsPInvokeDelegateStub() const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(IsILStub());
+ return GetILStubType() == StubPInvokeDelegate;
+ }
+ bool IsPInvokeCalliStub() const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(IsILStub());
+ return GetILStubType() == StubPInvokeCalli;
+ }
+ bool IsPInvokeVarArgStub() const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(IsILStub());
+ return GetILStubType() == StubPInvokeVarArg;
}
bool IsMulticastStub() const
@@ -2910,7 +2929,7 @@ class DynamicMethodDesc : public StoredSigMethodDesc
bool HasMDContextArg() const
{
LIMITED_METHOD_CONTRACT;
- return IsCLRToCOMStub();
+ return IsCLRToCOMStub() || IsPInvokeVarArgStub();
}
//
diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp
index c612b6f8abddd6..f225baea1cba9f 100644
--- a/src/coreclr/vm/stubmgr.cpp
+++ b/src/coreclr/vm/stubmgr.cpp
@@ -1752,7 +1752,7 @@ BOOL ILStubManager::TraceManager(Thread *thread,
}
trace->InitForManaged(target);
}
- else if (pStubMD->HasFlags(DynamicMethodDesc::FlagIsDelegate))
+ else if (pStubMD->IsPInvokeDelegateStub())
{
// This is forward delegate P/Invoke stub, the argument is undefined
DelegateObject *pDel = (DelegateObject *)pThis;
@@ -1761,7 +1761,7 @@ BOOL ILStubManager::TraceManager(Thread *thread,
LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Forward delegate P/Invoke case %p\n", target));
trace->InitForUnmanaged(target);
}
- else if (pStubMD->HasFlags(DynamicMethodDesc::FlagIsCALLI))
+ else if (pStubMD->IsPInvokeCalliStub())
{
// This is unmanaged CALLI stub, the argument is the target
target = (PCODE)arg;
@@ -1796,18 +1796,30 @@ BOOL ILStubManager::TraceManager(Thread *thread,
MethodDesc *pMD = (MethodDesc *)arg;
-#ifdef FEATURE_COMINTEROP
- LOG((LF_CORDB, LL_INFO1000, "ILSM::TraceManager: Stub is CLR-to-COM\n"));
- _ASSERTE(pMD->IsCLRToCOMCall());
- CLRToCOMCallMethodDesc *pCMD = (CLRToCOMCallMethodDesc *)pMD;
- _ASSERTE(!pCMD->IsStatic() && !pCMD->IsCtor() && "Static methods and constructors are not supported for built-in classic COM");
-
- if (pThis != NULL)
+ // This is either vararg PInvoke or a CLR-to-COM call, the argument is MD
+ if (pMD->IsPInvoke())
{
- target = GetCOMTarget(pThis, pCMD->m_pCLRToCOMCallInfo);
- LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: CLR-to-COM case %p\n", target));
+ PInvokeMethodDesc* pNMD = reinterpret_cast(pMD);
+ _ASSERTE_IMPL(!pNMD->PInvokeTargetIsImportThunk());
+ target = (PCODE)pNMD->GetPInvokeTarget();
+ LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Forward P/Invoke case 0x%p\n", target));
trace->InitForUnmanaged(target);
}
+#ifdef FEATURE_COMINTEROP
+ else
+ {
+ LOG((LF_CORDB, LL_INFO1000, "ILSM::TraceManager: Stub is CLR-to-COM\n"));
+ _ASSERTE(pMD->IsCLRToCOMCall());
+ CLRToCOMCallMethodDesc *pCMD = (CLRToCOMCallMethodDesc *)pMD;
+ _ASSERTE(!pCMD->IsStatic() && !pCMD->IsCtor() && "Static methods and constructors are not supported for built-in classic COM");
+
+ if (pThis != NULL)
+ {
+ target = GetCOMTarget(pThis, pCMD->m_pCLRToCOMCallInfo);
+ LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: CLR-to-COM case %p\n", target));
+ trace->InitForUnmanaged(target);
+ }
+ }
#endif // FEATURE_COMINTEROP
}
else if (pStubMD->IsDelegateInvokeMethodStub())
@@ -1950,13 +1962,7 @@ BOOL InteropDispatchStubManager::TraceManager(Thread *thread,
LOG((LF_CORDB, LL_INFO10000, "IDSM::TraceManager: Skipping on arm64-macOS\n"));
return FALSE;
#else
- TADDR firstArg = StubManagerHelpers::GetFirstArg(pContext);
- _ASSERTE(firstArg != (TADDR)NULL);
-
- VASigCookie* vaSigCookie = (VASigCookie*)firstArg;
- PInvokeMethodDesc* pNMD = reinterpret_cast(vaSigCookie->pMethodDesc);
- _ASSERTE(pNMD != NULL);
- _ASSERTE(pNMD->IsPInvoke());
+ PInvokeMethodDesc *pNMD = (PInvokeMethodDesc *)arg;
PCODE target = (PCODE)pNMD->GetPInvokeTarget();
LOG((LF_CORDB, LL_INFO10000, "IDSM::TraceManager: Vararg P/Invoke case %p\n", target));