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
+