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));