diff --git a/src/coreclr/inc/corhdr.h b/src/coreclr/inc/corhdr.h index fd3dc4735de5f..75f91be3ed0c9 100644 --- a/src/coreclr/inc/corhdr.h +++ b/src/coreclr/inc/corhdr.h @@ -1873,6 +1873,7 @@ typedef enum LoadHintEnum #define CMOD_CALLCONV_NAME_STDCALL "CallConvStdcall" #define CMOD_CALLCONV_NAME_THISCALL "CallConvThiscall" #define CMOD_CALLCONV_NAME_FASTCALL "CallConvFastcall" +#define CMOD_CALLCONV_NAME_SUPPRESSGCTRANSITION "CallConvSuppressGCTransition" #endif // MACROS_NOT_SUPPORTED diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 815b5ac39f68a..8bd277c27dc9f 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1065,7 +1065,7 @@ enum CorInfoSigInfoFlags { CORINFO_SIGFLAG_IS_LOCAL_SIG = 0x01, CORINFO_SIGFLAG_IL_STUB = 0x02, - CORINFO_SIGFLAG_SUPPRESS_GC_TRANSITION = 0x04, + // unused = 0x04, CORINFO_SIGFLAG_FAT_CALL = 0x08, }; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index c88f858afacfd..486ef28bc093e 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -562,8 +562,9 @@ private CorInfoCallConvExtension GetUnmanagedCallingConventionFromAttribute(Cust return callConv; } - private bool TryGetUnmanagedCallingConventionFromModOpt(MethodSignature signature, out CorInfoCallConvExtension callConv) + private bool TryGetUnmanagedCallingConventionFromModOpt(MethodSignature signature, out CorInfoCallConvExtension callConv, out bool suppressGCTransition) { + suppressGCTransition = false; callConv = CorInfoCallConvExtension.Managed; if (!signature.HasEmbeddedSignatureData || signature.GetEmbeddedSignatureData() == null) return false; @@ -585,6 +586,12 @@ private bool TryGetUnmanagedCallingConventionFromModOpt(MethodSignature signatur if (defType.Namespace != "System.Runtime.CompilerServices") continue; + if (defType.Name == "CallConvSuppressGCTransition") + { + suppressGCTransition = true; + continue; + } + CorInfoCallConvExtension? callConvLocal = GetCallingConventionForCallConvType(defType); if (callConvLocal.HasValue) @@ -1070,10 +1077,6 @@ private CorInfoCallConvExtension getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* me Debug.Assert(sig != null); CorInfoCallConvExtension callConv = GetUnmanagedCallConv((MethodSignature)HandleToObject((IntPtr)sig->pSig), out pSuppressGCTransition); - if (sig->flags.HasFlag(CorInfoSigInfoFlags.CORINFO_SIGFLAG_SUPPRESS_GC_TRANSITION)) - { - pSuppressGCTransition = true; - } return callConv; } } @@ -1123,7 +1126,7 @@ private CorInfoCallConvExtension GetUnmanagedCallConv(MethodSignature signature, case MethodSignatureFlags.UnmanagedCallingConventionThisCall: return CorInfoCallConvExtension.Thiscall; case MethodSignatureFlags.UnmanagedCallingConvention: - if (TryGetUnmanagedCallingConventionFromModOpt(signature, out CorInfoCallConvExtension callConvMaybe)) + if (TryGetUnmanagedCallingConventionFromModOpt(signature, out CorInfoCallConvExtension callConvMaybe, out suppressGCTransition)) { return callConvMaybe; } @@ -1384,16 +1387,6 @@ private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEX Get_CORINFO_SIG_INFO(methodSig, sig); - // TODO: Replace this with a public mechanism to mark calli with SuppressGCTransition once it becomes available. - if (methodIL is PInvokeILStubMethodIL stubIL) - { - var method = stubIL.OwningMethod; - if (method.IsPInvoke && method.IsSuppressGCTransition()) - { - sig->flags |= CorInfoSigInfoFlags.CORINFO_SIGFLAG_SUPPRESS_GC_TRANSITION; - } - } - #if !READYTORUN // Check whether we need to report this as a fat pointer call if (_compilation.IsFatPointerCandidate(methodIL.OwningMethod, methodSig)) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 07d29f4b8030b..79768f5fbdb9e 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -370,7 +370,7 @@ public enum CorInfoSigInfoFlags : byte { CORINFO_SIGFLAG_IS_LOCAL_SIG = 0x01, CORINFO_SIGFLAG_IL_STUB = 0x02, - CORINFO_SIGFLAG_SUPPRESS_GC_TRANSITION = 0x04, + // unused = 0x04, CORINFO_SIGFLAG_FAT_CALL = 0x08, }; diff --git a/src/coreclr/vm/array.cpp b/src/coreclr/vm/array.cpp index 767c2ccb0b02a..7b57038c0805c 100644 --- a/src/coreclr/vm/array.cpp +++ b/src/coreclr/vm/array.cpp @@ -417,7 +417,7 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy pMT->SetParentMethodTable(pParentClass); - // Method tables for arrays of generic type parameters are needed for type analysis. + // Method tables for arrays of generic type parameters are needed for type analysis. // No instances will be created, so we can use 0 as element size. DWORD dwComponentSize = CorTypeInfo::IsGenericVariable(elemType) ? 0 : @@ -751,7 +751,7 @@ class ArrayOpLinker : public ILStubLinker public: ArrayOpLinker(ArrayMethodDesc * pMD) - : ILStubLinker(pMD->GetModule(), pMD->GetSignature(), &m_emptyContext, pMD, TRUE, TRUE, FALSE) + : ILStubLinker(pMD->GetModule(), pMD->GetSignature(), &m_emptyContext, pMD, (ILStubLinkerFlags)(ILSTUB_LINKER_FLAG_STUB_HAS_THIS | ILSTUB_LINKER_FLAG_TARGET_HAS_THIS)) { m_pCode = NewCodeStream(kDispatch); m_pMD = pMD; diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index f57b85009abdc..d484cb134644c 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2190,7 +2190,7 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) BOOL fReturnVal = !sig.IsReturnTypeVoid(); SigTypeContext emptyContext; - ILStubLinker sl(pMD->GetModule(), pMD->GetSignature(), &emptyContext, pMD, TRUE, TRUE, FALSE); + ILStubLinker sl(pMD->GetModule(), pMD->GetSignature(), &emptyContext, pMD, (ILStubLinkerFlags)(ILSTUB_LINKER_FLAG_STUB_HAS_THIS | ILSTUB_LINKER_FLAG_TARGET_HAS_THIS)); ILCodeStream *pCode = sl.NewCodeStream(ILStubLinker::kDispatch); @@ -2374,7 +2374,7 @@ PCODE COMDelegate::GetWrapperInvoke(MethodDesc* pMD) BOOL fReturnVal = !sig.IsReturnTypeVoid(); SigTypeContext emptyContext; - ILStubLinker sl(pMD->GetModule(), pMD->GetSignature(), &emptyContext, pMD, TRUE, TRUE, FALSE); + ILStubLinker sl(pMD->GetModule(), pMD->GetSignature(), &emptyContext, pMD, (ILStubLinkerFlags)(ILSTUB_LINKER_FLAG_STUB_HAS_THIS | ILSTUB_LINKER_FLAG_TARGET_HAS_THIS)); ILCodeStream *pCode = sl.NewCodeStream(ILStubLinker::kDispatch); diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index bf1b815cf238c..b34222a093905 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -767,6 +767,12 @@ DEFINE_CLASS(RUNTIME_WRAPPED_EXCEPTION, CompilerServices, RuntimeWrappedExcept DEFINE_METHOD(RUNTIME_WRAPPED_EXCEPTION, OBJ_CTOR, .ctor, IM_Obj_RetVoid) DEFINE_FIELD(RUNTIME_WRAPPED_EXCEPTION, WRAPPED_EXCEPTION, _wrappedException) +DEFINE_CLASS(CALLCONV_CDECL, CompilerServices, CallConvCdecl) +DEFINE_CLASS(CALLCONV_STDCALL, CompilerServices, CallConvStdcall) +DEFINE_CLASS(CALLCONV_THISCALL, CompilerServices, CallConvThiscall) +DEFINE_CLASS(CALLCONV_FASTCALL, CompilerServices, CallConvFastcall) +DEFINE_CLASS(CALLCONV_SUPPRESSGCTRANSITION, CompilerServices, CallConvSuppressGCTransition) + DEFINE_CLASS_U(Interop, SafeHandle, SafeHandle) DEFINE_FIELD_U(handle, SafeHandle, m_handle) DEFINE_FIELD_U(_state, SafeHandle, m_state) diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index a2f029487d923..02e5e23ba1aaa 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -256,12 +256,10 @@ class ILStubState : public StubState Module* pStubModule, const Signature &signature, SigTypeContext* pTypeContext, - BOOL fTargetHasThis, - BOOL fStubHasThis, DWORD dwStubFlags, int iLCIDParamIdx, MethodDesc* pTargetMD) - : m_slIL(dwStubFlags, pStubModule, signature, pTypeContext, pTargetMD, iLCIDParamIdx, fTargetHasThis, fStubHasThis) + : m_slIL(dwStubFlags, pStubModule, signature, pTypeContext, pTargetMD, iLCIDParamIdx) { STANDARD_VM_CONTRACT; @@ -1221,8 +1219,6 @@ class StructMarshal_ILStubState : public ILStubState pMT->GetModule(), signature, pTypeContext, - FALSE, - FALSE, dwStubFlags, -1 /* We have no LCID parameter */, nullptr), @@ -1349,9 +1345,7 @@ class PInvoke_ILStubState : public ILStubState pStubModule, signature, pTypeContext, - TargetHasThis(dwStubFlags), - StubHasThis(dwStubFlags), - dwStubFlags, + UpdateStubFlags(dwStubFlags, pTargetMD), iLCIDParamIdx, pTargetMD) { @@ -1371,6 +1365,23 @@ class PInvoke_ILStubState : public ILStubState } private: + static DWORD UpdateStubFlags(DWORD dwStubFlags, MethodDesc* pTargetMD) + { + if (TargetHasThis(dwStubFlags)) + { + dwStubFlags |= NDIRECTSTUB_FL_TARGET_HAS_THIS; + } + if (StubHasThis(dwStubFlags)) + { + dwStubFlags |= NDIRECTSTUB_FL_STUB_HAS_THIS; + } + if (TargetSuppressGCTransition(dwStubFlags, pTargetMD)) + { + dwStubFlags |= NDIRECTSTUB_FL_SUPPRESSGCTRANSITION; + } + return dwStubFlags; + } + static BOOL TargetHasThis(DWORD dwStubFlags) { // @@ -1389,6 +1400,11 @@ class PInvoke_ILStubState : public ILStubState // return SF_IsForwardDelegateStub(dwStubFlags); } + + static BOOL TargetSuppressGCTransition(DWORD dwStubFlags, MethodDesc* pTargetMD) + { + return SF_IsForwardStub(dwStubFlags) && pTargetMD && pTargetMD->ShouldSuppressGCTransition(); + } }; #ifdef FEATURE_COMINTEROP @@ -1402,9 +1418,7 @@ class CLRToCOM_ILStubState : public ILStubState pStubModule, signature, pTypeContext, - TRUE, - TRUE, - dwStubFlags, + dwStubFlags | NDIRECTSTUB_FL_STUB_HAS_THIS | NDIRECTSTUB_FL_TARGET_HAS_THIS, iLCIDParamIdx, pTargetMD) { @@ -1470,9 +1484,7 @@ class COMToCLR_ILStubState : public ILStubState pStubModule, signature, pTypeContext, - TRUE, - TRUE, - dwStubFlags, + dwStubFlags | NDIRECTSTUB_FL_STUB_HAS_THIS | NDIRECTSTUB_FL_TARGET_HAS_THIS, iLCIDParamIdx, pTargetMD) { @@ -1531,6 +1543,31 @@ class COMToCLRFieldAccess_ILStubState : public COMToCLR_ILStubState }; #endif // FEATURE_COMINTEROP +ILStubLinkerFlags GetILStubLinkerFlagsForNDirectStubFlags(NDirectStubFlags flags) +{ + DWORD result = ILSTUB_LINKER_FLAG_NONE; + if (!SF_IsCOMStub(flags)) + { + result |= ILSTUB_LINKER_FLAG_NDIRECT; + } + if (SF_IsReverseStub(flags)) + { + result |= ILSTUB_LINKER_FLAG_REVERSE; + } + if (flags & NDIRECTSTUB_FL_SUPPRESSGCTRANSITION) + { + result |= ILSTUB_LINKER_FLAG_SUPPRESSGCTRANSITION; + } + if (flags & NDIRECTSTUB_FL_STUB_HAS_THIS) + { + result |= ILSTUB_LINKER_FLAG_STUB_HAS_THIS; + } + if (flags & NDIRECTSTUB_FL_TARGET_HAS_THIS) + { + result |= ILSTUB_LINKER_FLAG_TARGET_HAS_THIS; + } + return (ILStubLinkerFlags)result; +} NDirectStubLinker::NDirectStubLinker( DWORD dwStubFlags, @@ -1538,17 +1575,15 @@ NDirectStubLinker::NDirectStubLinker( const Signature &signature, SigTypeContext *pTypeContext, MethodDesc* pTargetMD, - int iLCIDParamIdx, - BOOL fTargetHasThis, - BOOL fStubHasThis) - : ILStubLinker(pModule, signature, pTypeContext, pTargetMD, fTargetHasThis, fStubHasThis, !SF_IsCOMStub(dwStubFlags), SF_IsReverseStub(dwStubFlags)), + int iLCIDParamIdx) + : ILStubLinker(pModule, signature, pTypeContext, pTargetMD, GetILStubLinkerFlagsForNDirectStubFlags((NDirectStubFlags)dwStubFlags)), m_pCleanupFinallyBeginLabel(NULL), m_pCleanupFinallyEndLabel(NULL), m_pSkipExceptionCleanupLabel(NULL), m_fHasCleanupCode(FALSE), m_fHasExceptionCleanupCode(FALSE), m_fCleanupWorkListIsSetup(FALSE), - m_targetHasThis(fTargetHasThis), + m_targetHasThis((dwStubFlags & NDIRECTSTUB_FL_TARGET_HAS_THIS) != 0), m_dwThreadLocalNum(-1), m_dwCleanupWorkListLocalNum(-1), m_dwRetValLocalNum(-1), @@ -2548,13 +2583,7 @@ void PInvokeStaticSigInfo::PreInit(MethodDesc* pMD) PInvokeStaticSigInfo::PInvokeStaticSigInfo( MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName) { - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; + STANDARD_VM_CONTRACT; DllImportInit(pMD, pLibName, pEntryPointName); @@ -2565,10 +2594,7 @@ PInvokeStaticSigInfo::PInvokeStaticSigInfo(MethodDesc* pMD, ThrowOnError throwOn { CONTRACTL { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - + STANDARD_VM_CHECK; PRECONDITION(CheckPointer(pMD)); } CONTRACTL_END; @@ -2666,9 +2692,7 @@ PInvokeStaticSigInfo::PInvokeStaticSigInfo( { CONTRACTL { - THROWS; - GC_NOTRIGGER; - MODE_ANY; + STANDARD_VM_CHECK; PRECONDITION(CheckPointer(pModule)); } @@ -2686,9 +2710,7 @@ void PInvokeStaticSigInfo::DllImportInit(MethodDesc* pMD, LPCUTF8 *ppLibName, LP { CONTRACTL { - THROWS; - GC_NOTRIGGER; - MODE_ANY; + STANDARD_VM_CHECK; PRECONDITION(CheckPointer(pMD)); @@ -2968,16 +2990,11 @@ namespace _Out_ CorPinvokeMap *pPinvokeMapOut, _Out_ UINT *errorResID) { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END + STANDARD_VM_CONTRACT; CorUnmanagedCallingConvention callConvMaybe; - HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(pModule, pSig, cSig, &callConvMaybe, errorResID); + bool suppressGCTransition; + HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(GetScopeHandle(pModule), pSig, cSig, &callConvMaybe, &suppressGCTransition, errorResID); if (hr != S_OK) return hr; @@ -2990,13 +3007,7 @@ namespace void PInvokeStaticSigInfo::InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg) { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END + STANDARD_VM_CONTRACT; // Convert WinAPI methods to either StdCall or CDecl based on if they are varargs or not. if (callConv == pmCallConvWinapi) @@ -6714,7 +6725,8 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD) { CorUnmanagedCallingConvention callConvMaybe; UINT errorResID; - HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(pVASigCookie->pModule, signature.GetRawSig(), signature.GetRawSigLen(), &callConvMaybe, &errorResID); + bool suppressGCTransition = false; + HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(GetScopeHandle(pVASigCookie->pModule), signature.GetRawSig(), signature.GetRawSigLen(), &callConvMaybe, &suppressGCTransition, &errorResID); if (FAILED(hr)) COMPlusThrowHR(hr, errorResID); @@ -6726,6 +6738,11 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD) { callConv = MetaSig::GetDefaultUnmanagedCallingConvention(); } + + if (suppressGCTransition) + { + dwStubFlags |= NDIRECTSTUB_FL_SUPPRESSGCTRANSITION; + } } if (!TryConvertCallConvValueToPInvokeCallConv(callConv, &unmgdCallConv)) diff --git a/src/coreclr/vm/dllimport.h b/src/coreclr/vm/dllimport.h index ba2b20d13b387..0cb2fadcb7e08 100644 --- a/src/coreclr/vm/dllimport.h +++ b/src/coreclr/vm/dllimport.h @@ -150,15 +150,16 @@ enum NDirectStubFlags #ifdef FEATURE_COMINTEROP NDIRECTSTUB_FL_FIELDGETTER = 0x00002000, // COM->CLR field getter NDIRECTSTUB_FL_FIELDSETTER = 0x00004000, // COM->CLR field setter - // unused = 0x00008000, - // unused = 0x00010000, - // unused = 0x00020000, +#endif // FEATURE_COMINTEROP + NDIRECTSTUB_FL_SUPPRESSGCTRANSITION = 0x00008000, + NDIRECTSTUB_FL_STUB_HAS_THIS = 0x00010000, + NDIRECTSTUB_FL_TARGET_HAS_THIS = 0x00020000, + // unused = 0x00040000, // unused = 0x00080000, // unused = 0x00100000, // unused = 0x00200000, // unused = 0x00400000, // unused = 0x00800000, -#endif // FEATURE_COMINTEROP // internal flags -- these won't ever show up in an NDirectStubHashBlob // unused = 0x10000000, @@ -443,9 +444,7 @@ class NDirectStubLinker : public ILStubLinker const Signature &signature, SigTypeContext *pTypeContext, MethodDesc* pTargetMD, - int iLCIDParamIdx, - BOOL fTargetHasThis, - BOOL fStubHasThis); + int iLCIDParamIdx); void SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL fIsVarArg); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index c6529e036f21a..0d60059283a3d 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9775,8 +9775,10 @@ CorInfoHFAElemType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass) namespace { - CorInfoCallConvExtension getUnmanagedCallConvForSig(Module* mod, PCCOR_SIGNATURE pSig, DWORD cbSig, bool* pSuppressGCTransition) + CorInfoCallConvExtension getUnmanagedCallConvForSig(CORINFO_MODULE_HANDLE mod, PCCOR_SIGNATURE pSig, DWORD cbSig, bool* pSuppressGCTransition) { + STANDARD_VM_CONTRACT; + SigParser parser(pSig, cbSig); ULONG rawCallConv; if (FAILED(parser.GetCallingConv(&rawCallConv))) @@ -9800,7 +9802,8 @@ namespace { CorUnmanagedCallingConvention callConvMaybe; UINT errorResID; - HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(mod, pSig, cbSig, &callConvMaybe, &errorResID); + HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(mod, pSig, cbSig, &callConvMaybe, pSuppressGCTransition, &errorResID); + if (FAILED(hr)) COMPlusThrowHR(hr, errorResID); @@ -9823,6 +9826,8 @@ namespace CorInfoCallConvExtension getUnmanagedCallConvForMethod(MethodDesc* pMD, bool* pSuppressGCTransition) { + STANDARD_VM_CONTRACT; + ULONG methodCallConv; PCCOR_SIGNATURE pSig; DWORD cbSig; @@ -9904,7 +9909,7 @@ namespace } else { - return getUnmanagedCallConvForSig(pMD->GetModule(), pSig, cbSig, pSuppressGCTransition); + return getUnmanagedCallConvForSig(GetScopeHandle(pMD->GetModule()), pSig, cbSig, pSuppressGCTransition); } } } @@ -9939,7 +9944,7 @@ CorInfoCallConvExtension CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE met else { _ASSERTE(callSiteSig != nullptr); - callConv = getUnmanagedCallConvForSig(GetModule(callSiteSig->scope), callSiteSig->pSig, callSiteSig->cbSig, pSuppressGCTransition); + callConv = getUnmanagedCallConvForSig(callSiteSig->scope, callSiteSig->pSig, callSiteSig->cbSig, pSuppressGCTransition); } EE_TO_JIT_TRANSITION(); diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 52875ca35639b..4a13ad212c29b 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -1557,10 +1557,7 @@ Stub * CreateUnboxingILStubForSharedGenericValueTypeMethods(MethodDesc* pTargetM pTargetMD->GetSignature(), &typeContext, pTargetMD, - TRUE, // fTargetHasThis - TRUE, // fStubHasThis - FALSE // fIsNDirectStub - ); + (ILStubLinkerFlags)(ILSTUB_LINKER_FLAG_STUB_HAS_THIS | ILSTUB_LINKER_FLAG_TARGET_HAS_THIS)); ILCodeStream *pCode = sl.NewCodeStream(ILStubLinker::kDispatch); @@ -1660,14 +1657,13 @@ Stub * CreateInstantiatingILStub(MethodDesc* pTargetMD, void* pHiddenArg) } MetaSig msig(pTargetMD); - ILStubLinker sl(pTargetMD->GetModule(), pTargetMD->GetSignature(), &typeContext, pTargetMD, - msig.HasThis(), // fTargetHasThis - msig.HasThis(), // fStubHasThis - FALSE // fIsNDirectStub + msig.HasThis() + ? (ILStubLinkerFlags)(ILSTUB_LINKER_FLAG_STUB_HAS_THIS | ILSTUB_LINKER_FLAG_TARGET_HAS_THIS) + : (ILStubLinkerFlags)ILSTUB_LINKER_FLAG_NONE ); ILCodeStream *pCode = sl.NewCodeStream(ILStubLinker::kDispatch); diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp index 34f2c6c614e0a..3f26bc8c87ac1 100644 --- a/src/coreclr/vm/siginfo.cpp +++ b/src/coreclr/vm/siginfo.cpp @@ -5248,14 +5248,7 @@ namespace _Out_ LPCSTR *namespaceOut, _Out_ LPCSTR *nameOut) { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - FORBID_FAULT; - MODE_ANY; - } - CONTRACTL_END + STANDARD_VM_CONTRACT; IMDInternalImport *pInternalImport = pModule->GetMDImport(); if (TypeFromToken(token) == mdtTypeDef) @@ -5277,34 +5270,84 @@ namespace return S_OK; } + + HRESULT GetNameOfTypeRefOrDef( + _In_ DynamicResolver *pResolver, + _In_ mdToken token, + _Out_ LPCSTR *namespaceOut, + _Out_ LPCSTR *nameOut) + { + STANDARD_VM_CONTRACT; + + TypeHandle type; + MethodDesc* pMD; + FieldDesc* pFD; + + pResolver->ResolveToken(token, &type, &pMD, &pFD); + + _ASSERTE(!type.IsNull()); + + *nameOut = type.GetMethodTable()->GetFullyQualifiedNameInfo(namespaceOut); + + return S_OK; + } + + HRESULT GetNameOfTypeRefOrDef( + _In_ CORINFO_MODULE_HANDLE pModule, + _In_ mdToken token, + _Out_ LPCSTR *namespaceOut, + _Out_ LPCSTR *nameOut) + { + STANDARD_VM_CONTRACT; + + if (IsDynamicScope(pModule)) + { + return GetNameOfTypeRefOrDef(GetDynamicResolver(pModule), token, namespaceOut, nameOut); + } + else + { + return GetNameOfTypeRefOrDef(GetModule(pModule), token, namespaceOut, nameOut); + } + } } + //---------------------------------------------------------- // Returns the unmanaged calling convention. //---------------------------------------------------------- /*static*/ HRESULT MetaSig::TryGetUnmanagedCallingConventionFromModOpt( - _In_ Module *pModule, + _In_ CORINFO_MODULE_HANDLE pModule, _In_ PCCOR_SIGNATURE pSig, _In_ ULONG cSig, _Out_ CorUnmanagedCallingConvention *callConvOut, + _Out_ bool* suppressGCTransitionOut, _Out_ UINT *errorResID) { CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - FORBID_FAULT; - MODE_ANY; + STANDARD_VM_CHECK; PRECONDITION(callConvOut != NULL); + PRECONDITION(suppressGCTransitionOut != NULL); PRECONDITION(errorResID != NULL); } CONTRACTL_END + *suppressGCTransitionOut = false; + HRESULT hr; + // Instantiations aren't relevant here - MetaSig msig(pSig, cSig, pModule, NULL); - PCCOR_SIGNATURE pWalk = msig.m_pRetType.GetPtr(); + SigPointer sigPtr(pSig, cSig); + ULONG sigCallConv = 0; + IfFailRet(sigPtr.GetCallingConvInfo(&sigCallConv)); // call conv + if (sigCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC) + { + IfFailRet(sigPtr.GetData(NULL)); // type param count + } + IfFailRet(sigPtr.GetData(NULL)); // arg count + + PCCOR_SIGNATURE pWalk = sigPtr.GetPtr(); _ASSERTE(pWalk <= pSig + cSig); *callConvOut = (CorUnmanagedCallingConvention)0; @@ -5336,6 +5379,12 @@ MetaSig::TryGetUnmanagedCallingConventionFromModOpt( if (::strcmp(typeNamespace, CMOD_CALLCONV_NAMESPACE) != 0) continue; + if (::strcmp(typeName, CMOD_CALLCONV_NAME_SUPPRESSGCTRANSITION) == 0) + { + *suppressGCTransitionOut = true; + continue; + } + const struct { LPCSTR name; CorUnmanagedCallingConvention value; diff --git a/src/coreclr/vm/siginfo.hpp b/src/coreclr/vm/siginfo.hpp index c2f68e1dd755b..276a26bbe77fd 100644 --- a/src/coreclr/vm/siginfo.hpp +++ b/src/coreclr/vm/siginfo.hpp @@ -15,6 +15,7 @@ #include "sigparser.h" #include "zapsig.h" #include "threads.h" +#include "corinfo.h" #include "eecontract.h" #include "typectxt.h" @@ -790,10 +791,11 @@ class MetaSig // than one calling convention specified) //---------------------------------------------------------- static HRESULT TryGetUnmanagedCallingConventionFromModOpt( - _In_ Module *pModule, + _In_ CORINFO_MODULE_HANDLE pModule, _In_ PCCOR_SIGNATURE pSig, _In_ ULONG cSig, _Out_ CorUnmanagedCallingConvention *callConvOut, + _Out_ bool* suppressGCTransitionOut, _Out_ UINT *errorResID); static CorUnmanagedCallingConvention GetDefaultUnmanagedCallingConvention() diff --git a/src/coreclr/vm/stubgen.cpp b/src/coreclr/vm/stubgen.cpp index cee3cbe9f025e..7016b8c2920a8 100644 --- a/src/coreclr/vm/stubgen.cpp +++ b/src/coreclr/vm/stubgen.cpp @@ -2060,6 +2060,7 @@ FunctionSigBuilder::FunctionSigBuilder() : m_callingConv(IMAGE_CEE_CS_CALLCONV_DEFAULT) { STANDARD_VM_CONTRACT; + m_qbCallConvModOpts.Init(); m_qbReturnSig.ReSizeThrows(1); *(CorElementType *)m_qbReturnSig.Ptr() = ELEMENT_TYPE_VOID; } @@ -2075,7 +2076,7 @@ void FunctionSigBuilder::SetReturnType(LocalDesc* pLoc) CONTRACTL_END; m_qbReturnSig.ReSizeThrows(pLoc->cbType); - memcpyNoGCRefs(m_qbReturnSig.Ptr(), pLoc->ElementType, pLoc->cbType); + memcpyNoGCRefs((BYTE*)m_qbReturnSig.Ptr(), pLoc->ElementType, pLoc->cbType); size_t i = 0; @@ -2160,6 +2161,22 @@ void FunctionSigBuilder::SetSig(PCCOR_SIGNATURE pSig, DWORD cSig) m_pbSigCursor += cbSigLen; } +//-------------------------------------------------------------------------------------- +// + +void +FunctionSigBuilder::AddCallConvModOpt(mdToken token) +{ + LIMITED_METHOD_CONTRACT; + _ASSERTE(TypeFromToken(token) == mdtTypeDef || TypeFromToken(token) == mdtTypeRef); + + int temp; + ULONG len = CorSigCompressToken(token, &temp); + m_qbCallConvModOpts.ReSizeThrows(m_qbCallConvModOpts.Size() + 1 + len); + SET_UNALIGNED_PTR((BYTE*)m_qbCallConvModOpts.Ptr() + m_qbCallConvModOpts.Size() - len - 1, (BYTE)ELEMENT_TYPE_CMOD_OPT); + memcpyNoGCRefs((BYTE*)m_qbCallConvModOpts.Ptr() + m_qbCallConvModOpts.Size() - len, &temp, len); +} + //--------------------------------------------------------------------------------------- // DWORD @@ -2171,11 +2188,14 @@ FunctionSigBuilder::GetSigSize() DWORD cbEncodedLen = CorSigCompressData(m_nItems, temp); SIZE_T cbEncodedRetType = m_qbReturnSig.Size(); + SIZE_T cbEncodedCallConv = m_qbCallConvModOpts.Size(); + CONSISTENCY_CHECK(cbEncodedRetType > 0); S_UINT32 cbSigSize = S_UINT32(1) + // calling convention S_UINT32(cbEncodedLen) + // encoded number of args + S_UINT32(cbEncodedCallConv) + // encoded callconv modopts S_UINT32(cbEncodedRetType) + // encoded return type S_UINT32(m_cbSig) + // types S_UINT32(1); // ELEMENT_TYPE_END @@ -2195,12 +2215,13 @@ FunctionSigBuilder::GetSig( { STANDARD_VM_CONTRACT; BYTE tempLen[4]; - size_t cbEncodedLen = CorSigCompressData(m_nItems, tempLen); - size_t cbEncodedRetType = m_qbReturnSig.Size(); + size_t cbEncodedLen = CorSigCompressData(m_nItems, tempLen); + size_t cbEncodedCallConv = m_qbCallConvModOpts.Size(); + size_t cbEncodedRetType = m_qbReturnSig.Size(); CONSISTENCY_CHECK(cbEncodedRetType > 0); - _ASSERTE((1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1) == GetSigSize()); + _ASSERTE((1 + cbEncodedLen + cbEncodedCallConv + cbEncodedRetType + m_cbSig + 1) == GetSigSize()); if ((1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1) <= cbBuffer) { @@ -2211,6 +2232,9 @@ FunctionSigBuilder::GetSig( memcpyNoGCRefs(pbCursor, tempLen, cbEncodedLen); pbCursor += cbEncodedLen; + memcpyNoGCRefs(pbCursor, m_qbCallConvModOpts.Ptr(), m_qbCallConvModOpts.Size()); + pbCursor += m_qbCallConvModOpts.Size(); + memcpyNoGCRefs(pbCursor, m_qbReturnSig.Ptr(), m_qbReturnSig.Size()); pbCursor += m_qbReturnSig.Size(); @@ -2315,9 +2339,28 @@ static BOOL SigHasVoidReturnType(const Signature &signature) return (ELEMENT_TYPE_VOID == retType); } +static PTR_MethodTable GetModOptTypeForCallConv(CorUnmanagedCallingConvention callConv) +{ + switch(callConv) + { + case IMAGE_CEE_UNMANAGED_CALLCONV_C: + return CoreLibBinder::GetClass(CLASS__CALLCONV_CDECL); + break; + case IMAGE_CEE_UNMANAGED_CALLCONV_STDCALL: + return CoreLibBinder::GetClass(CLASS__CALLCONV_STDCALL); + break; + case IMAGE_CEE_UNMANAGED_CALLCONV_THISCALL: + return CoreLibBinder::GetClass(CLASS__CALLCONV_THISCALL); + break; + case IMAGE_CEE_UNMANAGED_CALLCONV_FASTCALL: + return CoreLibBinder::GetClass(CLASS__CALLCONV_FASTCALL); + break; + default: + return NULL; + } +} -ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, SigTypeContext *pTypeContext, MethodDesc *pMD, - BOOL fTargetHasThis, BOOL fStubHasThis, BOOL fIsNDirectStub, BOOL fIsReverseStub) : +ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, SigTypeContext *pTypeContext, MethodDesc *pMD, ILStubLinkerFlags flags) : m_pCodeStreamList(NULL), m_stubSig(signature), m_pTypeContext(pTypeContext), @@ -2325,7 +2368,7 @@ ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, S m_pStubSigModule(pStubSigModule), m_pLabelList(NULL), m_StubHasVoidReturnType(FALSE), - m_fIsReverseStub(fIsReverseStub), + m_fIsReverseStub((flags & ILSTUB_LINKER_FLAG_REVERSE) != 0), m_iTargetStackDelta(0), m_cbCurrentCompressedSigLen(1), m_nLocals(0), @@ -2341,6 +2384,11 @@ ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, S CONTRACTL_END m_managedSigPtr = signature.CreateSigPointer(); + if ((flags & ILSTUB_LINKER_FLAG_SUPPRESSGCTRANSITION) != 0) + { + m_nativeFnSigBuilder.AddCallConvModOpt(GetToken(CoreLibBinder::GetClass(CLASS__CALLCONV_SUPPRESSGCTRANSITION))); + m_nativeFnSigBuilder.SetCallingConv(IMAGE_CEE_CS_CALLCONV_UNMANAGED); + } if (!signature.IsEmpty()) { // Until told otherwise, assume that the stub has the same return type as the signature. @@ -2355,10 +2403,7 @@ ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, S ULONG uStubCallingConvInfo; IfFailThrow(m_managedSigPtr.GetCallingConvInfo(&uStubCallingConvInfo)); - if (fStubHasThis) - { - m_fHasThis = true; - } + m_fHasThis = (flags & ILSTUB_LINKER_FLAG_STUB_HAS_THIS) != 0; // // If target calling convention was specified, use it instead. @@ -2392,7 +2437,7 @@ ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, S // convention to be vararg for non-PInvoke stubs, so we just use // the default callconv. // - if (!fIsNDirectStub) + if ((flags & ILSTUB_LINKER_FLAG_NDIRECT) == 0) uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_DEFAULT; else uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_NATIVEVARARG; @@ -2402,18 +2447,38 @@ ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, S uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_DEFAULT; } - if (fTargetHasThis && !fIsNDirectStub) + if ((flags & (ILSTUB_LINKER_FLAG_TARGET_HAS_THIS | ILSTUB_LINKER_FLAG_NDIRECT)) == ILSTUB_LINKER_FLAG_TARGET_HAS_THIS) { // ndirect native sig never has a 'this' pointer uNativeCallingConv |= IMAGE_CEE_CS_CALLCONV_HASTHIS; } - if (fTargetHasThis && !fIsReverseStub) + if ((flags & (ILSTUB_LINKER_FLAG_TARGET_HAS_THIS | ILSTUB_LINKER_FLAG_REVERSE)) == ILSTUB_LINKER_FLAG_TARGET_HAS_THIS) { m_iTargetStackDelta--; } - m_nativeFnSigBuilder.SetCallingConv((CorCallingConvention)uNativeCallingConv); + if (m_nativeFnSigBuilder.GetCallingConv() == IMAGE_CEE_CS_CALLCONV_UNMANAGED) + { + switch((CorUnmanagedCallingConvention)uNativeCallingConv) + { + case IMAGE_CEE_UNMANAGED_CALLCONV_C: + case IMAGE_CEE_UNMANAGED_CALLCONV_STDCALL: + case IMAGE_CEE_UNMANAGED_CALLCONV_THISCALL: + case IMAGE_CEE_UNMANAGED_CALLCONV_FASTCALL: + m_nativeFnSigBuilder.AddCallConvModOpt(GetToken(GetModOptTypeForCallConv((CorUnmanagedCallingConvention)uNativeCallingConv))); + break; + default: + // If the calling convention isn't one of the unmanaged calling conventions + // and we've already decided that we need to emit the Unmanaged calling convention in metadata, + // let the code that builds the stub set the calling convention. + break; + } + } + else + { + m_nativeFnSigBuilder.SetCallingConv((CorCallingConvention)uNativeCallingConv); + } if (uStubCallingConvInfo & IMAGE_CEE_CS_CALLCONV_GENERIC) IfFailThrow(m_managedSigPtr.GetData(NULL)); // skip number of type parameters @@ -2423,7 +2488,7 @@ ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, S // If we are a reverse stub, then the target signature called in the stub // is the managed signature. In that case, we calculate the target IL stack delta // here from the managed signature. - if (fIsReverseStub) + if ((flags & ILSTUB_LINKER_FLAG_REVERSE) != 0) { // As per ECMA 335, the max number of parameters is 0x1FFFFFFF (see section 11.23.2), which fits in a 32-bit signed integer // So this cast is safe. @@ -2678,7 +2743,15 @@ void ILStubLinker::SetStubTargetCallingConv(CorCallingConvention uNativeCallingC { LIMITED_METHOD_CONTRACT; CorCallingConvention originalCallingConvention = m_nativeFnSigBuilder.GetCallingConv(); - m_nativeFnSigBuilder.SetCallingConv(uNativeCallingConv); + if (originalCallingConvention == IMAGE_CEE_CS_CALLCONV_UNMANAGED) + { + m_nativeFnSigBuilder.AddCallConvModOpt(GetToken(GetModOptTypeForCallConv((CorUnmanagedCallingConvention)uNativeCallingConv))); + } + else + { + m_nativeFnSigBuilder.SetCallingConv(uNativeCallingConv); + } + if (!m_fIsReverseStub) { if ( (originalCallingConvention & CORINFO_CALLCONV_HASTHIS) && !(uNativeCallingConv & CORINFO_CALLCONV_HASTHIS)) diff --git a/src/coreclr/vm/stubgen.h b/src/coreclr/vm/stubgen.h index 66ca74ab67d6f..18f6d609ca99c 100644 --- a/src/coreclr/vm/stubgen.h +++ b/src/coreclr/vm/stubgen.h @@ -234,6 +234,8 @@ class FunctionSigBuilder : protected StubSigBuilder m_callingConv = callingConv; } + void AddCallConvModOpt(mdToken token); + CorCallingConvention GetCallingConv() { LIMITED_METHOD_CONTRACT; @@ -266,6 +268,7 @@ class FunctionSigBuilder : protected StubSigBuilder protected: CorCallingConvention m_callingConv; CQuickBytes m_qbReturnSig; + CQuickBytes m_qbCallConvModOpts; }; // class FunctionSigBuilder #endif // DACCESS_COMPILE @@ -451,6 +454,17 @@ struct ILStubEHClauseBuilder DWORD typeToken; }; + +enum ILStubLinkerFlags +{ + ILSTUB_LINKER_FLAG_NONE = 0x00, + ILSTUB_LINKER_FLAG_TARGET_HAS_THIS = 0x01, + ILSTUB_LINKER_FLAG_STUB_HAS_THIS = 0x02, + ILSTUB_LINKER_FLAG_NDIRECT = 0x04, + ILSTUB_LINKER_FLAG_REVERSE = 0x08, + ILSTUB_LINKER_FLAG_SUPPRESSGCTRANSITION = 0x10, +}; + //--------------------------------------------------------------------------------------- // class ILStubLinker @@ -460,8 +474,7 @@ class ILStubLinker public: - ILStubLinker(Module* pModule, const Signature &signature, SigTypeContext *pTypeContext, MethodDesc *pMD, - BOOL fTargetHasThis, BOOL fStubHasThis, BOOL fIsNDirectStub = FALSE, BOOL fIsReverseStub = FALSE); + ILStubLinker(Module* pModule, const Signature &signature, SigTypeContext *pTypeContext, MethodDesc *pMD, ILStubLinkerFlags flags); ~ILStubLinker(); void GenerateCode(BYTE* pbBuffer, size_t cbBufferSize); diff --git a/src/coreclr/vm/tailcallhelp.cpp b/src/coreclr/vm/tailcallhelp.cpp index 7dcb8dd10a809..7a96e28227527 100644 --- a/src/coreclr/vm/tailcallhelp.cpp +++ b/src/coreclr/vm/tailcallhelp.cpp @@ -24,7 +24,7 @@ FCIMPL2(void*, TailCallHelp::AllocTailCallArgBuffer, INT32 size, void* gcDesc) _ASSERTE(size >= 0); void* result = GetThread()->GetTailCallTls()->AllocArgBuffer(size, gcDesc); - + if (result == NULL) FCThrow(kOutOfMemoryException); @@ -341,8 +341,7 @@ MethodDesc* TailCallHelp::CreateStoreArgsStub(TailCallInfo& info) Signature(pSig, cbSig), &emptyCtx, NULL, - FALSE, - FALSE); + ILSTUB_LINKER_FLAG_NONE); ILCodeStream* pCode = sl.NewCodeStream(ILStubLinker::kDispatch); @@ -462,8 +461,7 @@ MethodDesc* TailCallHelp::CreateCallTargetStub(const TailCallInfo& info) Signature(pSig, cbSig), &emptyCtx, NULL, - FALSE, - FALSE); + ILSTUB_LINKER_FLAG_NONE); ILCodeStream* pCode = sl.NewCodeStream(ILStubLinker::kDispatch); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs index 26fa5f68ea6cf..56b0a53930f0a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CallingConventions.cs @@ -15,6 +15,21 @@ public class CallConvStdcall { public CallConvStdcall() { } } + + /// + /// Indicates that a method should suppress the GC transition as part of the calling convention. + /// + /// + /// The describes the effects + /// of suppressing the GC transition on a native call. + /// + public class CallConvSuppressGCTransition + { + /// + /// Initializes a new instance of the class. + /// + public CallConvSuppressGCTransition() { } + } public class CallConvThiscall { public CallConvThiscall() { } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index c84c3499cc8b7..2282fe560d7d6 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -9132,6 +9132,10 @@ public partial class CallConvStdcall { public CallConvStdcall() { } } + public class CallConvSuppressGCTransition + { + public CallConvSuppressGCTransition() { } + } public partial class CallConvThiscall { public CallConvThiscall() { } diff --git a/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionNative.cpp b/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionNative.cpp index 322bc4797668c..703df8a85208a 100644 --- a/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionNative.cpp +++ b/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionNative.cpp @@ -13,7 +13,7 @@ namespace } extern "C" -BOOL DLL_EXPORT NextUInt(/* out */ uint32_t *n) +BOOL DLL_EXPORT STDMETHODVCALLTYPE NextUInt(/* out */ uint32_t *n) { if (n == nullptr) return FALSE; diff --git a/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionTest.cs b/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionTest.cs index 7cdc08a4e033d..c9a1a721aa3fa 100644 --- a/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionTest.cs +++ b/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionTest.cs @@ -8,29 +8,33 @@ using System.Runtime.InteropServices; using TestLibrary; -static class SuppressGCTransitionNative +unsafe static class SuppressGCTransitionNative { - [DllImport(nameof(SuppressGCTransitionNative), EntryPoint = "NextUInt")] + [DllImport(nameof(SuppressGCTransitionNative), CallingConvention=CallingConvention.Cdecl, EntryPoint = "NextUInt")] [SuppressGCTransition] public static extern unsafe int NextUInt_Inline_NoGCTransition(int* n); - [DllImport(nameof(SuppressGCTransitionNative), EntryPoint = "NextUInt")] + [DllImport(nameof(SuppressGCTransitionNative), CallingConvention=CallingConvention.Cdecl, EntryPoint = "NextUInt")] public static extern unsafe int NextUInt_Inline_GCTransition(int* n); - [DllImport(nameof(SuppressGCTransitionNative), EntryPoint = "NextUInt")] + [DllImport(nameof(SuppressGCTransitionNative), CallingConvention=CallingConvention.Cdecl, EntryPoint = "NextUInt")] [SuppressGCTransition] public static extern unsafe bool NextUInt_NoInline_NoGCTransition(int* n); - [DllImport(nameof(SuppressGCTransitionNative), EntryPoint = "NextUInt")] + [DllImport(nameof(SuppressGCTransitionNative), CallingConvention=CallingConvention.Cdecl, EntryPoint = "NextUInt")] public static extern unsafe bool NextUInt_NoInline_GCTransition(int* n); + private static IntPtr nativeLibrary; + public static IntPtr GetNextUIntFunctionPointer() { - IntPtr mod = GetNativeLibrary(); + if (nativeLibrary == IntPtr.Zero) + { + nativeLibrary = GetNativeLibrary(); + } IntPtr fptr; - if (NativeLibrary.TryGetExport(mod, "NextUInt", out fptr) - || NativeLibrary.TryGetExport(mod, "_NextUInt@4", out fptr)) + if (NativeLibrary.TryGetExport(nativeLibrary, "NextUInt", out fptr)) { return fptr; } @@ -38,6 +42,18 @@ public static IntPtr GetNextUIntFunctionPointer() throw new Exception($"Failed to find native export"); } + public static delegate* unmanaged[Cdecl] GetNextUIntFunctionPointer_Inline_GCTransition() + => (delegate* unmanaged[Cdecl])GetNextUIntFunctionPointer(); + + public static delegate* unmanaged[Cdecl, SuppressGCTransition] GetNextUIntFunctionPointer_Inline_NoGCTransition() + => (delegate* unmanaged[Cdecl, SuppressGCTransition])GetNextUIntFunctionPointer(); + + public static delegate* unmanaged[Cdecl] GetNextUIntFunctionPointer_NoInline_GCTransition() + => (delegate* unmanaged[Cdecl])GetNextUIntFunctionPointer(); + + public static delegate* unmanaged[Cdecl, SuppressGCTransition] GetNextUIntFunctionPointer_NoInline_NoGCTransition() + => (delegate* unmanaged[Cdecl, SuppressGCTransition])GetNextUIntFunctionPointer(); + private static IntPtr GetNativeLibrary() { var libNames = new [] @@ -130,6 +146,43 @@ private static int Mixed_TightLoop(int expected) Assert.AreEqual(expected + count, n); return n + 1; } + [MethodImpl(MethodImplOptions.NoInlining)] + private static int Inline_NoGCTransition_FunctionPointer(int expected) + { + Console.WriteLine($"{nameof(Inline_NoGCTransition)} ({expected}) ..."); + int n; + SuppressGCTransitionNative.GetNextUIntFunctionPointer_Inline_NoGCTransition()(&n); + Assert.AreEqual(expected, n); + return n + 1; + } + [MethodImpl(MethodImplOptions.NoInlining)] + private static int Inline_GCTransition_FunctionPointer(int expected) + { + Console.WriteLine($"{nameof(Inline_GCTransition)} ({expected}) ..."); + int n; + SuppressGCTransitionNative.GetNextUIntFunctionPointer_Inline_GCTransition()(&n); + Assert.AreEqual(expected, n); + return n + 1; + } + [MethodImpl(MethodImplOptions.NoInlining)] + private static int NoInline_NoGCTransition_FunctionPointer(int expected) + { + Console.WriteLine($"{nameof(NoInline_NoGCTransition)} ({expected}) ..."); + int n; + SuppressGCTransitionNative.GetNextUIntFunctionPointer_NoInline_NoGCTransition()(&n); + Assert.AreEqual(expected, n); + return n + 1; + } + [MethodImpl(MethodImplOptions.NoInlining)] + private static int NoInline_GCTransition_FunctionPointer(int expected) + { + Console.WriteLine($"{nameof(NoInline_GCTransition)} ({expected}) ..."); + int n; + SuppressGCTransitionNative.GetNextUIntFunctionPointer_NoInline_GCTransition()(&n); + Assert.AreEqual(expected, n); + return n + 1; + } + [MethodImpl(MethodImplOptions.NoInlining)] private static int CallAsFunctionPointer(int expected) { @@ -158,6 +211,10 @@ public static int Main() n = NoInline_GCTransition(n); n = Mixed(n); n = Mixed_TightLoop(n); + n = Inline_NoGCTransition_FunctionPointer(n); + n = Inline_GCTransition_FunctionPointer(n); + n = NoInline_NoGCTransition_FunctionPointer(n); + n = NoInline_GCTransition_FunctionPointer(n); n = CallAsFunctionPointer(n); } catch (Exception e) diff --git a/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionUtil.il b/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionUtil.il index 4bbc7aabfd186..51a852f749155 100644 --- a/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionUtil.il +++ b/src/tests/Interop/PInvoke/Attributes/SuppressGCTransition/SuppressGCTransitionUtil.il @@ -9,7 +9,7 @@ .class public auto ansi beforefieldinit FunctionPointer extends [System.Runtime]System.Object { - .method hidebysig specialname rtspecialname + .method hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 @@ -24,7 +24,7 @@ .maxstack 8 ldarg.1 ldarg.0 - calli unmanaged stdcall int32 (int32*) + calli unmanaged cdecl int32 (int32*) ret } } diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 8ca9fb726a436..571f3a46e0c68 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -140,8 +140,8 @@ https://github.com/dotnet/runtime/issues/12166 - - https://github.com/dotnet/runtime/issues/46175 + + https://github.com/dotnet/runtime/issues/46175 @@ -2456,6 +2456,9 @@ needs triage + + https://github.com/dotnet/runtime/issues/46451 +