diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/ToolBox/superpmi/superpmi-shared/lwmlist.h index 8aca1b1634b83..b400fbab0b29a 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/lwmlist.h @@ -132,7 +132,6 @@ LWM(GetTypeForPrimitiveValueClass, DWORDLONG, DWORD) LWM(GetTypeForPrimitiveNumericClass, DWORDLONG, DWORD) LWM(GetUnboxedEntry, DWORDLONG, DLD); LWM(GetUnBoxHelper, DWORDLONG, DWORD) -LWM(GetUnmanagedCallConv, DWORDLONG, DWORD) LWM(GetVarArgsHandle, GetVarArgsHandleValue, DLDL) LWM(GetVars, DWORDLONG, Agnostic_GetVars) DENSELWM(HandleException, DWORD) @@ -149,12 +148,13 @@ LWM(IsValidToken, DLD, DWORD) LWM(IsValueClass, DWORDLONG, DWORD) LWM(MergeClasses, DLDL, DWORDLONG) LWM(IsMoreSpecificType, DLDL, DWORD) -LWM(PInvokeMarshalingRequired, PInvokeMarshalingRequiredValue, DWORD) +LWM(PInvokeMarshalingRequired, MethodOrSigInfoValue, DWORD) LWM(ResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, ResolveTokenValue) LWM(ResolveVirtualMethod, Agnostic_ResolveVirtualMethodKey, Agnostic_ResolveVirtualMethodResult) LWM(TryResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, TryResolveTokenValue) LWM(SatisfiesClassConstraints, DWORDLONG, DWORD) LWM(SatisfiesMethodConstraints, DLDL, DWORD) +LWM(GetUnmanagedCallConv, MethodOrSigInfoValue, DD) #undef LWM diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp index 00d88a6b10a66..cc859f22a8a0f 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp @@ -1624,35 +1624,6 @@ bool MethodContext::repIsIntrinsicType(CORINFO_CLASS_HANDLE cls) return result; } -void MethodContext::recGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CorInfoUnmanagedCallConv result) -{ - if (GetUnmanagedCallConv == nullptr) - GetUnmanagedCallConv = new LightWeightMap(); - - GetUnmanagedCallConv->Add((DWORDLONG)method, result); - DEBUG_REC(dmpGetUnmanagedCallConv((DWORDLONG)method, (DWORD)result)); -} -void MethodContext::dmpGetUnmanagedCallConv(DWORDLONG key, DWORD result) -{ - printf("GetUnmanagedCallConv key ftn-%016llX, value res-%u", key, result); -} -CorInfoUnmanagedCallConv MethodContext::repGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method) -{ - if ((GetUnmanagedCallConv == nullptr) || (GetUnmanagedCallConv->GetIndex((DWORDLONG)method) == -1)) - { -#ifdef sparseMC - LogDebug("Sparse - repGetUnmanagedCallConv returning CORINFO_UNMANAGED_CALLCONV_STDCALL"); - return CORINFO_UNMANAGED_CALLCONV_STDCALL; -#else - LogException(EXCEPTIONCODE_MC, "Found a null GetUnmanagedCallConv. Probably missing a fatTrigger for %016llX.", - (DWORDLONG)method); -#endif - } - CorInfoUnmanagedCallConv result = (CorInfoUnmanagedCallConv)GetUnmanagedCallConv->Get((DWORDLONG)method); - DEBUG_REP(dmpGetUnmanagedCallConv((DWORDLONG)method, (DWORD)result)); - return result; -} - void MethodContext::recAsCorInfoType(CORINFO_CLASS_HANDLE cls, CorInfoType result) { if (AsCorInfoType == nullptr) @@ -3086,7 +3057,7 @@ void MethodContext::recResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info key.context = (DWORDLONG)info->context; Agnostic_ResolveVirtualMethodResult result; result.returnValue = returnValue; - result.devirtualizedMethod = (DWORDLONG)info->devirtualizedMethod; + result.devirtualizedMethod = (DWORDLONG)info->devirtualizedMethod; result.requiresInstMethodTableArg = info->requiresInstMethodTableArg; result.exactContext = (DWORDLONG)info->exactContext; ResolveVirtualMethod->Add(key, result); @@ -3771,10 +3742,10 @@ void MethodContext::recPInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, bool result) { if (PInvokeMarshalingRequired == nullptr) - PInvokeMarshalingRequired = new LightWeightMap(); + PInvokeMarshalingRequired = new LightWeightMap(); - PInvokeMarshalingRequiredValue key; - ZeroMemory(&key, sizeof(PInvokeMarshalingRequiredValue)); // We use the input structs as a key and use memcmp to + MethodOrSigInfoValue key; + ZeroMemory(&key, sizeof(MethodOrSigInfoValue)); // We use the input structs as a key and use memcmp to // compare.. so we need to zero out padding too key.method = (DWORDLONG)method; @@ -3785,7 +3756,7 @@ void MethodContext::recPInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, PInvokeMarshalingRequired->Add(key, (DWORD)result); DEBUG_REC(dmpPInvokeMarshalingRequired(key, (DWORD)result)); } -void MethodContext::dmpPInvokeMarshalingRequired(const PInvokeMarshalingRequiredValue& key, DWORD value) +void MethodContext::dmpPInvokeMarshalingRequired(const MethodOrSigInfoValue& key, DWORD value) { printf("PInvokeMarshalingRequired key mth-%016llX scp-%016llX sig-%u, value res-%u", key.method, key.scope, key.pSig_Index, value); @@ -3796,9 +3767,9 @@ bool MethodContext::repPInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, C if (PInvokeMarshalingRequired == nullptr) // so when we replay checked on free, we throw from lwm return TRUE; // TODO-Cleanup: hackish... - PInvokeMarshalingRequiredValue key; - ZeroMemory(&key, sizeof(PInvokeMarshalingRequiredValue)); // We use the input structs as a key and use memcmp to - // compare.. so we need to zero out padding too + MethodOrSigInfoValue key; + ZeroMemory(&key, sizeof(MethodOrSigInfoValue)); // We use the input structs as a key and use memcmp to + // compare.. so we need to zero out padding too key.method = (DWORDLONG)method; key.pSig_Index = (DWORD)PInvokeMarshalingRequired->Contains((unsigned char*)callSiteSig->pSig, callSiteSig->cbSig); @@ -3810,6 +3781,60 @@ bool MethodContext::repPInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, C return value; } +void MethodContext::recGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* callSiteSig, + CorInfoCallConvExtension result, + bool suppressGCTransitionResult) +{ + if (GetUnmanagedCallConv == nullptr) + GetUnmanagedCallConv = new LightWeightMap(); + + MethodOrSigInfoValue key; + ZeroMemory(&key, sizeof(MethodOrSigInfoValue)); // We use the input structs as a key and use memcmp to + // compare.. so we need to zero out padding too + + key.method = (DWORDLONG)method; + key.pSig_Index = (DWORD)PInvokeMarshalingRequired->AddBuffer((unsigned char*)callSiteSig->pSig, callSiteSig->cbSig); + key.cbSig = (DWORD)callSiteSig->cbSig; + key.scope = (DWORDLONG)callSiteSig->scope; + + GetUnmanagedCallConv->Add(key, { (DWORD)result, (DWORD)suppressGCTransitionResult }); + DEBUG_REC(dmpGetUnmanagedCallConv(key, { (DWORD)result, (DWORD)suppressGCTransitionResult })); +} +void MethodContext::dmpGetUnmanagedCallConv(const MethodOrSigInfoValue& key, DD value) +{ + printf("GetUnmanagedCallConv key mth-%016llX scp-%016llX sig-%u, value res-%u,%u", key.method, key.scope, + key.pSig_Index, value.A, value.B); +} +// Note the jit interface implementation seems to only care about scope and pSig from callSiteSig +CorInfoCallConvExtension MethodContext::repGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition) +{ + if (GetUnmanagedCallConv == nullptr) + { +#ifdef sparseMC + LogDebug("Sparse - repGetUnmanagedCallConv returning CorInfoCallConvExtension::Managed"); + return CorInfoCallConvExtension::Managed; +#else + LogException(EXCEPTIONCODE_MC, "Found a null GetUnmGetUnmanagedCallConvanagedCallConv. Probably missing a fatTrigger for %016llX.", + (DWORDLONG)method); +#endif + } + + MethodOrSigInfoValue key; + ZeroMemory(&key, sizeof(MethodOrSigInfoValue)); // We use the input structs as a key and use memcmp to + // compare.. so we need to zero out padding too + + key.method = (DWORDLONG)method; + key.pSig_Index = (DWORD)GetUnmanagedCallConv->Contains((unsigned char*)callSiteSig->pSig, callSiteSig->cbSig); + key.cbSig = (DWORD)callSiteSig->cbSig; + key.scope = (DWORDLONG)callSiteSig->scope; + + DD value = GetUnmanagedCallConv->Get(key); + DEBUG_REP(dmpGetUnmanagedCallConv(key, value)); + *pSuppressGCTransition = value.B != 0; + return (CorInfoCallConvExtension)value.A; +} + void MethodContext::recFindSig(CORINFO_MODULE_HANDLE module, unsigned sigTOK, CORINFO_CONTEXT_HANDLE context, @@ -5290,7 +5315,7 @@ void MethodContext::recGetLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLAS } void MethodContext::dmpGetLikelyClass(const Agnostic_GetLikelyClass& key, const Agnostic_GetLikelyClassResult& value) { - printf("GetLikelyClass key ftn-%016llX base-%016llX il-%u, class-%016llX likelihood-%u numberOfClasses-%u", + printf("GetLikelyClass key ftn-%016llX base-%016llX il-%u, class-%016llX likelihood-%u numberOfClasses-%u", key.ftnHnd, key.baseHnd, key.ilOffset, value.classHnd, value.likelihood, value.numberOfClasses); } CORINFO_CLASS_HANDLE MethodContext::repGetLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, UINT32* pLikelihood, UINT32* pNumberOfClasses) diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h index 1678a1069447a..666c771830adc 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h @@ -318,7 +318,7 @@ class MethodContext DWORD sigTOK; DWORDLONG context; }; - struct PInvokeMarshalingRequiredValue + struct MethodOrSigInfoValue { DWORDLONG method; DWORD pSig_Index; @@ -730,10 +730,6 @@ class MethodContext void dmpGetIntrinsicID(DWORDLONG key, DD value); CorInfoIntrinsics repGetIntrinsicID(CORINFO_METHOD_HANDLE method, bool* pMustExpand); - void recGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CorInfoUnmanagedCallConv result); - void dmpGetUnmanagedCallConv(DWORDLONG key, DWORD result); - CorInfoUnmanagedCallConv repGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method); - void recAsCorInfoType(CORINFO_CLASS_HANDLE cls, CorInfoType result); void dmpAsCorInfoType(DWORDLONG key, DWORD value); CorInfoType repAsCorInfoType(CORINFO_CLASS_HANDLE cls); @@ -1003,9 +999,13 @@ class MethodContext CORINFO_CLASS_HANDLE repEmbedClassHandle(CORINFO_CLASS_HANDLE handle, void** ppIndirection); void recPInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool result); - void dmpPInvokeMarshalingRequired(const PInvokeMarshalingRequiredValue& key, DWORD value); + void dmpPInvokeMarshalingRequired(const MethodOrSigInfoValue& key, DWORD value); bool repPInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig); + void recGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, CorInfoCallConvExtension result, bool suppressGCTransitionResult); + void dmpGetUnmanagedCallConv(const MethodOrSigInfoValue& key, DD value); + CorInfoCallConvExtension repGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition); + void recFindSig(CORINFO_MODULE_HANDLE module, unsigned sigTOK, CORINFO_CONTEXT_HANDLE context, diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 90462003479c5..b001578311c6c 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -289,12 +289,15 @@ bool interceptor_ICJI::isIntrinsicType(CORINFO_CLASS_HANDLE classHnd) return temp; } -// return the unmanaged calling convention for a PInvoke -CorInfoUnmanagedCallConv interceptor_ICJI::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method) +// return the entry point calling convention for any of the following +// - a P/Invoke +// - a method marked with UnmanagedCallersOnly +// - a function pointer with the CORINFO_CALLCONV_UNMANAGED calling convention. +CorInfoCallConvExtension interceptor_ICJI::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition) { mc->cr->AddCall("getUnmanagedCallConv"); - CorInfoUnmanagedCallConv temp = original_ICorJitInfo->getUnmanagedCallConv(method); - mc->recGetUnmanagedCallConv(method, temp); + CorInfoCallConvExtension temp = original_ICorJitInfo->getUnmanagedCallConv(method, callSiteSig, pSuppressGCTransition); + mc->recGetUnmanagedCallConv(method, callSiteSig, temp, *pSuppressGCTransition); return temp; } @@ -2046,7 +2049,7 @@ HRESULT interceptor_ICJI::getMethodBlockCounts(CORINFO_METHOD_HANDLE ftnHnd, // Get the likely implementing class for a virtual call or interface call made by ftnHnd // at the indicated IL offset. baseHnd is the interface class or base class for the method -// being called. +// being called. CORINFO_CLASS_HANDLE interceptor_ICJI::getLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp index bb32bdf36a393..359a4bf55523c 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -162,11 +162,13 @@ bool interceptor_ICJI::isIntrinsicType( return original_ICorJitInfo->isIntrinsicType(classHnd); } -CorInfoUnmanagedCallConv interceptor_ICJI::getUnmanagedCallConv( - CORINFO_METHOD_HANDLE method) +CorInfoCallConvExtension interceptor_ICJI::getUnmanagedCallConv( + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* callSiteSig, + bool* pSuppressGCTransition) { mcs->AddCall("getUnmanagedCallConv"); - return original_ICorJitInfo->getUnmanagedCallConv(method); + return original_ICorJitInfo->getUnmanagedCallConv(method, callSiteSig, pSuppressGCTransition); } bool interceptor_ICJI::pInvokeMarshalingRequired( diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp index 64c3e0e9e8580..22c019ab80c4e 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -144,10 +144,12 @@ bool interceptor_ICJI::isIntrinsicType( return original_ICorJitInfo->isIntrinsicType(classHnd); } -CorInfoUnmanagedCallConv interceptor_ICJI::getUnmanagedCallConv( - CORINFO_METHOD_HANDLE method) +CorInfoCallConvExtension interceptor_ICJI::getUnmanagedCallConv( + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* callSiteSig, + bool* pSuppressGCTransition) { - return original_ICorJitInfo->getUnmanagedCallConv(method); + return original_ICorJitInfo->getUnmanagedCallConv(method, callSiteSig, pSuppressGCTransition); } bool interceptor_ICJI::pInvokeMarshalingRequired( diff --git a/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp index 0bbbd1f0e2532..c210e18798516 100644 --- a/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp @@ -218,11 +218,14 @@ bool MyICJI::isIntrinsicType(CORINFO_CLASS_HANDLE classHnd) return jitInstance->mc->repIsIntrinsicType(classHnd) ? true : false; } -// return the unmanaged calling convention for a PInvoke -CorInfoUnmanagedCallConv MyICJI::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method) +// return the entry point calling convention for any of the following +// - a P/Invoke +// - a method marked with UnmanagedCallersOnly +// - a function pointer with the CORINFO_CALLCONV_UNMANAGED calling convention. +CorInfoCallConvExtension MyICJI::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition) { jitInstance->mc->cr->AddCall("getUnmanagedCallConv"); - return jitInstance->mc->repGetUnmanagedCallConv(method); + return jitInstance->mc->repGetUnmanagedCallConv(method, callSiteSig, pSuppressGCTransition); } // return if any marshaling is required for PInvoke methods. Note that @@ -1803,7 +1806,7 @@ HRESULT MyICJI::getMethodBlockCounts(CORINFO_METHOD_HANDLE ftnHnd, // Get the likely implementing class for a virtual call or interface call made by ftnHnd // at the indicated IL offset. baseHnd is the interface class or base class for the method -// being called. +// being called. CORINFO_CLASS_HANDLE MyICJI::getLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, diff --git a/src/coreclr/debug/daccess/nidump.cpp b/src/coreclr/debug/daccess/nidump.cpp index e59fc9195954f..0cfa3951ba5ee 100644 --- a/src/coreclr/debug/daccess/nidump.cpp +++ b/src/coreclr/debug/daccess/nidump.cpp @@ -7350,7 +7350,6 @@ static NativeImageDumper::EnumMnemonics g_NDirectFlags[] = NDF_ENTRY(kStdCall), NDF_ENTRY(kThisCall), NDF_ENTRY(kIsQCall), - NDF_ENTRY(kStdCallWithRetBuf), #undef NDF_ENTRY }; NativeImageDumper::EnumMnemonics NativeImageDumper::s_IMDFlags[] = diff --git a/src/coreclr/inc/corhdr.h b/src/coreclr/inc/corhdr.h index c410f4026de6f..fd3dc4735de5f 100644 --- a/src/coreclr/inc/corhdr.h +++ b/src/coreclr/inc/corhdr.h @@ -954,11 +954,21 @@ typedef enum CorSerializationType // Calling convention flags. // +typedef enum CorUnmanagedCallingConvention +{ + IMAGE_CEE_UNMANAGED_CALLCONV_C = 0x1, + IMAGE_CEE_UNMANAGED_CALLCONV_STDCALL = 0x2, + IMAGE_CEE_UNMANAGED_CALLCONV_THISCALL = 0x3, + IMAGE_CEE_UNMANAGED_CALLCONV_FASTCALL = 0x4, +} CorUnmanagedCallingConvention; typedef enum CorCallingConvention { IMAGE_CEE_CS_CALLCONV_DEFAULT = 0x0, - + IMAGE_CEE_CS_CALLCONV_C = IMAGE_CEE_UNMANAGED_CALLCONV_C, + IMAGE_CEE_CS_CALLCONV_STDCALL = IMAGE_CEE_UNMANAGED_CALLCONV_STDCALL, + IMAGE_CEE_CS_CALLCONV_THISCALL = IMAGE_CEE_UNMANAGED_CALLCONV_THISCALL, + IMAGE_CEE_CS_CALLCONV_FASTCALL = IMAGE_CEE_UNMANAGED_CALLCONV_FASTCALL, IMAGE_CEE_CS_CALLCONV_VARARG = 0x5, IMAGE_CEE_CS_CALLCONV_FIELD = 0x6, IMAGE_CEE_CS_CALLCONV_LOCAL_SIG = 0x7, @@ -979,20 +989,6 @@ typedef enum CorCallingConvention #define IMAGE_CEE_CS_CALLCONV_INSTANTIATION IMAGE_CEE_CS_CALLCONV_GENERICINST -typedef enum CorUnmanagedCallingConvention -{ - IMAGE_CEE_UNMANAGED_CALLCONV_C = 0x1, - IMAGE_CEE_UNMANAGED_CALLCONV_STDCALL = 0x2, - IMAGE_CEE_UNMANAGED_CALLCONV_THISCALL = 0x3, - IMAGE_CEE_UNMANAGED_CALLCONV_FASTCALL = 0x4, - - IMAGE_CEE_CS_CALLCONV_C = IMAGE_CEE_UNMANAGED_CALLCONV_C, - IMAGE_CEE_CS_CALLCONV_STDCALL = IMAGE_CEE_UNMANAGED_CALLCONV_STDCALL, - IMAGE_CEE_CS_CALLCONV_THISCALL = IMAGE_CEE_UNMANAGED_CALLCONV_THISCALL, - IMAGE_CEE_CS_CALLCONV_FASTCALL = IMAGE_CEE_UNMANAGED_CALLCONV_FASTCALL, - -} CorUnmanagedCallingConvention; - typedef enum CorArgType { diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 9992adfdb21a1..815b5ac39f68a 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -669,10 +669,11 @@ enum CorInfoCallConv // These correspond to CorCallingConvention CORINFO_CALLCONV_DEFAULT = 0x0, - CORINFO_CALLCONV_C = 0x1, - CORINFO_CALLCONV_STDCALL = 0x2, - CORINFO_CALLCONV_THISCALL = 0x3, - CORINFO_CALLCONV_FASTCALL = 0x4, + // Instead of using the below values, use the CorInfoCallConvExtension enum for unmanaged calling conventions. + // CORINFO_CALLCONV_C = 0x1, + // CORINFO_CALLCONV_STDCALL = 0x2, + // CORINFO_CALLCONV_THISCALL = 0x3, + // CORINFO_CALLCONV_FASTCALL = 0x4, CORINFO_CALLCONV_VARARG = 0x5, CORINFO_CALLCONV_FIELD = 0x6, CORINFO_CALLCONV_LOCAL_SIG = 0x7, @@ -687,34 +688,29 @@ enum CorInfoCallConv CORINFO_CALLCONV_PARAMTYPE = 0x80, // Passed last. Same as CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG }; -#ifdef UNIX_X86_ABI -inline bool IsCallerPop(CorInfoCallConv callConv) -{ - unsigned int umask = CORINFO_CALLCONV_STDCALL - | CORINFO_CALLCONV_THISCALL - | CORINFO_CALLCONV_FASTCALL; - - return !(callConv & umask); -} -#endif // UNIX_X86_ABI - // Represents the calling conventions supported with the extensible calling convention syntax // as well as the original metadata-encoded calling conventions. -enum CorInfoUnmanagedCallConv -{ - // These correspond to CorUnmanagedCallingConvention - CORINFO_UNMANAGED_CALLCONV_UNKNOWN, - CORINFO_UNMANAGED_CALLCONV_C, - CORINFO_UNMANAGED_CALLCONV_STDCALL, - CORINFO_UNMANAGED_CALLCONV_THISCALL, - CORINFO_UNMANAGED_CALLCONV_FASTCALL +enum class CorInfoCallConvExtension +{ + Managed, + C, + Stdcall, + Thiscall, + Fastcall // New calling conventions supported with the extensible calling convention encoding go here. }; +#ifdef UNIX_X86_ABI +inline bool IsCallerPop(CorInfoCallConvExtension callConv) +{ + return callConv == CorInfoCallConvExtension::Managed || callConv == CorInfoCallConvExtension::C; +} +#endif // UNIX_X86_ABI + // Determines whether or not this calling convention is an instance method calling convention. -inline bool callConvIsInstanceMethodCallConv(CorInfoUnmanagedCallConv callConv) +inline bool callConvIsInstanceMethodCallConv(CorInfoCallConvExtension callConv) { - return callConv == CORINFO_UNMANAGED_CALLCONV_THISCALL; + return callConv == CorInfoCallConvExtension::Thiscall; } // These are returned from getMethodOptions @@ -2080,9 +2076,14 @@ class ICorStaticInfo CORINFO_CLASS_HANDLE classHnd ) { return false; } - // return the unmanaged calling convention for a PInvoke - virtual CorInfoUnmanagedCallConv getUnmanagedCallConv( - CORINFO_METHOD_HANDLE method + // return the entry point calling convention for any of the following + // - a P/Invoke + // - a method marked with UnmanagedCallersOnly + // - a function pointer with the CORINFO_CALLCONV_UNMANAGED calling convention. + virtual CorInfoCallConvExtension getUnmanagedCallConv( + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* callSiteSig, + bool* pSuppressGCTransition /* OUT */ ) = 0; // return if any marshaling is required for PInvoke methods. Note that diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 18bfd92a2c2fc..7a07ae42f6f66 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -99,8 +99,10 @@ CorInfoIntrinsics getIntrinsicID( bool isIntrinsicType( CORINFO_CLASS_HANDLE classHnd) override; -CorInfoUnmanagedCallConv getUnmanagedCallConv( - CORINFO_METHOD_HANDLE method) override; +CorInfoCallConvExtension getUnmanagedCallConv( + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* callSiteSig, + bool* pSuppressGCTransition) override; bool pInvokeMarshalingRequired( CORINFO_METHOD_HANDLE method, diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 88eb44da50c80..1ed1452b15379 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -25,11 +25,11 @@ // ////////////////////////////////////////////////////////////////////////////////////////////////////////// -constexpr GUID JITEEVersionIdentifier = { /* 790de1e5-1426-4ecf-939c-2cd60445c219 */ - 0x790de1e5, - 0x1426, - 0x4ecf, - { 0x93, 0x9c, 0x2c, 0xd6, 0x4, 0x45, 0xc2, 0x19 } +constexpr GUID JITEEVersionIdentifier = { /* {a7bb194e-4e7c-4850-af12-ea9f30ea5a13} */ + 0xa7bb194e, + 0x4e7c, + 0x4850, + {0xaf, 0x12, 0xea, 0x9f, 0x30, 0xea, 0x5a, 0x13} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp index fb10358a4129f..0788bc6af4e3c 100644 --- a/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp +++ b/src/coreclr/jit/ICorJitInfo_API_wrapper.hpp @@ -191,11 +191,13 @@ bool WrapICorJitInfo::isIntrinsicType( return temp; } -CorInfoUnmanagedCallConv WrapICorJitInfo::getUnmanagedCallConv( - CORINFO_METHOD_HANDLE method) +CorInfoCallConvExtension WrapICorJitInfo::getUnmanagedCallConv( + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* callSiteSig, + bool* pSuppressGCTransition) { API_ENTER(getUnmanagedCallConv); - CorInfoUnmanagedCallConv temp = wrapHnd->getUnmanagedCallConv(method); + CorInfoCallConvExtension temp = wrapHnd->getUnmanagedCallConv(method, callSiteSig, pSuppressGCTransition); API_LEAVE(getUnmanagedCallConv); return temp; } diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 3613312f75fcb..fb3065e24d043 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -8933,7 +8933,7 @@ void CodeGen::genFnEpilog(BasicBlock* block) fCalleePop = false; #ifdef UNIX_X86_ABI - if (IsCallerPop(compiler->info.compMethodInfo->args.callConv)) + if (IsCallerPop(compiler->info.compCallConv)) fCalleePop = false; #endif // UNIX_X86_ABI @@ -11534,8 +11534,7 @@ void CodeGen::genReturn(GenTree* treeNode) } else // we must have a struct return type { - CorInfoCallConvExtension callConv = - compiler->compMethodInfoGetEntrypointCallConv(compiler->info.compMethodInfo); + CorInfoCallConvExtension callConv = compiler->info.compCallConv; retTypeDesc.InitializeStructReturnType(compiler, compiler->info.compMethodInfo->args.retTypeClass, callConv); @@ -11663,9 +11662,7 @@ void CodeGen::genStructReturn(GenTree* treeNode) if (actualOp1->OperIs(GT_LCL_VAR)) { varDsc = compiler->lvaGetDesc(actualOp1->AsLclVar()->GetLclNum()); - retTypeDesc.InitializeStructReturnType(compiler, varDsc->GetStructHnd(), - compiler->compMethodInfoGetEntrypointCallConv( - compiler->info.compMethodInfo)); + retTypeDesc.InitializeStructReturnType(compiler, varDsc->GetStructHnd(), compiler->info.compCallConv); assert(varDsc->lvIsMultiRegRet); } else @@ -11828,8 +11825,8 @@ void CodeGen::genMultiRegStoreToLocal(GenTreeLclVar* lclNode) } for (unsigned i = 0; i < regCount; ++i) { - regNumber reg = genConsumeReg(op1, i); - var_types type = actualOp1->GetRegTypeByIndex(i); + regNumber reg = genConsumeReg(op1, i); + var_types srcType = actualOp1->GetRegTypeByIndex(i); // genConsumeReg will return the valid register, either from the COPY // or from the original source. assert(reg != REG_NA); @@ -11839,14 +11836,14 @@ void CodeGen::genMultiRegStoreToLocal(GenTreeLclVar* lclNode) regNumber varReg = lclNode->GetRegByIndex(i); unsigned fieldLclNum = varDsc->lvFieldLclStart + i; LclVarDsc* fieldVarDsc = compiler->lvaGetDesc(fieldLclNum); - var_types type = fieldVarDsc->TypeGet(); if (varReg != REG_NA) { - hasRegs = true; + var_types destType = fieldVarDsc->TypeGet(); + hasRegs = true; if (varReg != reg) { // We may need a cross register-file copy here. - inst_RV_RV(ins_Copy(reg, type), varReg, reg, type); + inst_RV_RV(ins_Copy(reg, destType), varReg, reg, destType); } fieldVarDsc->SetRegNum(varReg); } @@ -11858,15 +11855,15 @@ void CodeGen::genMultiRegStoreToLocal(GenTreeLclVar* lclNode) { if (!lclNode->AsLclVar()->IsLastUse(i)) { - GetEmitter()->emitIns_S_R(ins_Store(type), emitTypeSize(type), reg, fieldLclNum, 0); + GetEmitter()->emitIns_S_R(ins_Store(srcType), emitTypeSize(srcType), reg, fieldLclNum, 0); } } fieldVarDsc->SetRegNum(varReg); } else { - GetEmitter()->emitIns_S_R(ins_Store(type), emitTypeSize(type), reg, lclNum, offset); - offset += genTypeSize(type); + GetEmitter()->emitIns_S_R(ins_Store(srcType), emitTypeSize(srcType), reg, lclNum, offset); + offset += genTypeSize(srcType); } } diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 6f1ba9ab9bb8b..648a11223c2e8 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -141,8 +141,7 @@ void CodeGen::genEmitGSCookieCheck(bool pushReg) else // we must have a struct return type { retTypeDesc.InitializeStructReturnType(compiler, compiler->info.compMethodInfo->args.retTypeClass, - compiler->compMethodInfoGetEntrypointCallConv( - compiler->info.compMethodInfo)); + compiler->info.compCallConv); } const unsigned regCount = retTypeDesc.GetReturnRegCount(); diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 4642388b574e4..171bebb45e72b 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -2055,22 +2055,6 @@ unsigned Compiler::compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd) return sigSize; } -CorInfoCallConvExtension Compiler::compMethodInfoGetEntrypointCallConv(CORINFO_METHOD_INFO* mthInfo) -{ - CorInfoCallConv callConv = mthInfo->args.getCallConv(); - if (callConv == CORINFO_CALLCONV_DEFAULT || callConv == CORINFO_CALLCONV_VARARG) - { - // Both the default and the varargs calling conventions represent a managed callconv. - return CorInfoCallConvExtension::Managed; - } - - static_assert_no_msg((unsigned)CorInfoCallConvExtension::C == (unsigned)CORINFO_CALLCONV_C); - static_assert_no_msg((unsigned)CorInfoCallConvExtension::Stdcall == (unsigned)CORINFO_CALLCONV_STDCALL); - static_assert_no_msg((unsigned)CorInfoCallConvExtension::Thiscall == (unsigned)CORINFO_CALLCONV_THISCALL); - - return (CorInfoCallConvExtension)callConv; -} - #ifdef DEBUG static bool DidComponentUnitTests = false; @@ -2586,6 +2570,7 @@ void Compiler::compInitOptions(JitFlags* jitFlags) assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_PROF_ENTERLEAVE)); assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_EnC)); assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_INFO)); + assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_REVERSE_PINVOKE)); } opts.jitFlags = jitFlags; @@ -6108,21 +6093,28 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, info.compHasNextCallRetAddr = false; + if (opts.IsReversePInvoke()) + { + bool unused; + info.compCallConv = info.compCompHnd->getUnmanagedCallConv(methodInfo->ftn, nullptr, &unused); + } + else + { + info.compCallConv = CorInfoCallConvExtension::Managed; + } + + info.compIsVarArgs = false; + switch (methodInfo->args.getCallConv()) { - case CORINFO_CALLCONV_VARARG: case CORINFO_CALLCONV_NATIVEVARARG: + case CORINFO_CALLCONV_VARARG: info.compIsVarArgs = true; break; - case CORINFO_CALLCONV_C: - case CORINFO_CALLCONV_STDCALL: - case CORINFO_CALLCONV_THISCALL: - case CORINFO_CALLCONV_DEFAULT: - info.compIsVarArgs = false; - break; default: - BADCODE("bad calling convention"); + break; } + info.compRetNativeType = info.compRetType = JITtype2varType(methodInfo->args.retType); info.compUnmanagedCallCountWithGCTransition = 0; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index aa4d63b23a3ed..67c6e0e582e0b 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3849,7 +3849,7 @@ class Compiler CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(CORINFO_METHOD_HANDLE specialIntrinsicHandle); - bool impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo); + bool impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo, CorInfoCallConvExtension callConv); GenTree* impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HANDLE retClsHnd); @@ -9308,6 +9308,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX unsigned compUnmanagedCallCountWithGCTransition; // count of unmanaged calls with GC transition. + CorInfoCallConvExtension compCallConv; // The entry-point calling convention for this method. + unsigned compLvFrameListRoot; // lclNum for the Frame root unsigned compXcptnsCount; // Number of exception-handling clauses read in the method's IL. // You should generally use compHndBBtabCount instead: it is the @@ -9387,7 +9389,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // to be returned in x0. CLANG_FORMAT_COMMENT_ANCHOR; #if defined(TARGET_WINDOWS) && defined(TARGET_ARM64) - auto callConv = compMethodInfoGetEntrypointCallConv(info.compMethodInfo); + auto callConv = info.compCallConv; if (callConvIsInstanceMethodCallConv(callConv)) { return (info.compRetBuffArg != BAD_VAR_NUM); @@ -9593,8 +9595,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // size of the type these describe. unsigned compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd); - // Gets the calling convention the method's entry point should have. - CorInfoCallConvExtension compMethodInfoGetEntrypointCallConv(CORINFO_METHOD_INFO* mthInfo); + // Returns true if the method being compiled has a return buffer. + bool compHasRetBuffArg(); #ifdef DEBUG // Components used by the compiler may write unit test suites, and diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index f22c4cde83f81..46c4e75cdfbc1 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -23497,6 +23497,7 @@ void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* inlineRe compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_PROF_ENTERLEAVE); compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_DEBUG_EnC); compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_DEBUG_INFO); + compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_REVERSE_PINVOKE); compileFlagsForInlinee.Set(JitFlags::JIT_FLAG_SKIP_VERIFICATION); diff --git a/src/coreclr/jit/gcencode.cpp b/src/coreclr/jit/gcencode.cpp index b8228fe6ce024..bfe9dbe3ee918 100644 --- a/src/coreclr/jit/gcencode.cpp +++ b/src/coreclr/jit/gcencode.cpp @@ -50,9 +50,7 @@ ReturnKind GCInfo::getReturnKind() case TYP_STRUCT: { CORINFO_CLASS_HANDLE structType = compiler->info.compMethodInfo->args.retTypeClass; - var_types retType = - compiler->getReturnTypeForStruct(structType, compiler->compMethodInfoGetEntrypointCallConv( - compiler->info.compMethodInfo)); + var_types retType = compiler->getReturnTypeForStruct(structType, compiler->info.compCallConv); switch (retType) { diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 20fcdfa90e347..ff6556dab12b6 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1319,7 +1319,6 @@ GenTree* Compiler::impAssignStructPtr(GenTree* destAddr, // The argument list has already been reversed. // Insert the return buffer as the last node so it will be pushed on to the stack last // as required by the native ABI. - assert(srcCall->gtCallType == CT_INDIRECT); GenTreeCall::Use* lastArg = srcCall->gtCallArgs; if (lastArg == nullptr) { @@ -7024,7 +7023,7 @@ bool Compiler::impCanPInvokeInlineCallSite(BasicBlock* block) void Compiler::impCheckForPInvokeCall( GenTreeCall* call, CORINFO_METHOD_HANDLE methHnd, CORINFO_SIG_INFO* sig, unsigned mflags, BasicBlock* block) { - CorInfoUnmanagedCallConv unmanagedCallConv; + CorInfoCallConvExtension unmanagedCallConv; // If VM flagged it as Pinvoke, flag the call node accordingly if ((mflags & CORINFO_FLG_PINVOKE) != 0) @@ -7032,11 +7031,7 @@ void Compiler::impCheckForPInvokeCall( call->gtCallMoreFlags |= GTF_CALL_M_PINVOKE; } - if ((sig->flags & CORINFO_SIGFLAG_SUPPRESS_GC_TRANSITION) != 0) - { - call->gtCallMoreFlags |= GTF_CALL_M_SUPPRESS_GC_TRANSITION; - } - + bool suppressGCTransition = false; if (methHnd) { if ((mflags & CORINFO_FLG_PINVOKE) == 0) @@ -7044,26 +7039,27 @@ void Compiler::impCheckForPInvokeCall( return; } - unmanagedCallConv = info.compCompHnd->getUnmanagedCallConv(methHnd); + unmanagedCallConv = info.compCompHnd->getUnmanagedCallConv(methHnd, nullptr, &suppressGCTransition); } else { - CorInfoCallConv callConv = CorInfoCallConv(sig->callConv & CORINFO_CALLCONV_MASK); - if (callConv == CORINFO_CALLCONV_NATIVEVARARG) + if (sig->getCallConv() == CORINFO_CALLCONV_DEFAULT || sig->getCallConv() == CORINFO_CALLCONV_VARARG) { - // Used by the IL Stubs. - callConv = CORINFO_CALLCONV_C; + return; } - static_assert_no_msg((unsigned)CORINFO_CALLCONV_C == (unsigned)CORINFO_UNMANAGED_CALLCONV_C); - static_assert_no_msg((unsigned)CORINFO_CALLCONV_STDCALL == (unsigned)CORINFO_UNMANAGED_CALLCONV_STDCALL); - static_assert_no_msg((unsigned)CORINFO_CALLCONV_THISCALL == (unsigned)CORINFO_UNMANAGED_CALLCONV_THISCALL); - unmanagedCallConv = CorInfoUnmanagedCallConv(callConv); + + unmanagedCallConv = info.compCompHnd->getUnmanagedCallConv(nullptr, sig, &suppressGCTransition); assert(!call->gtCallCookie); } - if (unmanagedCallConv != CORINFO_UNMANAGED_CALLCONV_C && unmanagedCallConv != CORINFO_UNMANAGED_CALLCONV_STDCALL && - unmanagedCallConv != CORINFO_UNMANAGED_CALLCONV_THISCALL) + if (suppressGCTransition) + { + call->gtCallMoreFlags |= GTF_CALL_M_SUPPRESS_GC_TRANSITION; + } + + if (unmanagedCallConv != CorInfoCallConvExtension::C && unmanagedCallConv != CorInfoCallConvExtension::Stdcall && + unmanagedCallConv != CorInfoCallConvExtension::Thiscall) { return; } @@ -7119,24 +7115,20 @@ void Compiler::impCheckForPInvokeCall( JITLOG((LL_INFO1000000, "\nInline a CALLI PINVOKE call from method %s", info.compFullName)); - static_assert_no_msg((unsigned)CorInfoCallConvExtension::C == (unsigned)CORINFO_UNMANAGED_CALLCONV_C); - static_assert_no_msg((unsigned)CorInfoCallConvExtension::Stdcall == (unsigned)CORINFO_UNMANAGED_CALLCONV_STDCALL); - static_assert_no_msg((unsigned)CorInfoCallConvExtension::Thiscall == (unsigned)CORINFO_UNMANAGED_CALLCONV_THISCALL); - call->gtFlags |= GTF_CALL_UNMANAGED; - call->unmgdCallConv = CorInfoCallConvExtension(unmanagedCallConv); + call->unmgdCallConv = unmanagedCallConv; if (!call->IsSuppressGCTransition()) { info.compUnmanagedCallCountWithGCTransition++; } // AMD64 convention is same for native and managed - if (unmanagedCallConv == CORINFO_UNMANAGED_CALLCONV_C) + if (unmanagedCallConv == CorInfoCallConvExtension::C) { call->gtFlags |= GTF_CALL_POP_ARGS; } - if (unmanagedCallConv == CORINFO_UNMANAGED_CALLCONV_THISCALL) + if (unmanagedCallConv == CorInfoCallConvExtension::Thiscall) { call->gtCallMoreFlags |= GTF_CALL_M_UNMGD_THISCALL; } @@ -8409,12 +8401,6 @@ var_types Compiler::impImportCall(OPCODE opcode, } #endif // !FEATURE_VARARG -#ifdef UNIX_X86_ABI - // On Unix x86 we usually use caller-cleaned convention. - if (!call->AsCall()->IsUnmanaged() && IsCallerPop(sig->callConv)) - call->gtFlags |= GTF_CALL_POP_ARGS; -#endif // UNIX_X86_ABI - if ((sig->callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_VARARG || (sig->callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_NATIVEVARARG) { @@ -8490,6 +8476,12 @@ var_types Compiler::impImportCall(OPCODE opcode, impCheckForPInvokeCall(call->AsCall(), methHnd, sig, mflags, block); } +#ifdef UNIX_X86_ABI + // On Unix x86 we use caller-cleaned convention. + if ((call->gtFlags & GTF_CALL_UNMANAGED) == 0) + call->gtFlags |= GTF_CALL_POP_ARGS; +#endif // UNIX_X86_ABI + if (call->gtFlags & GTF_CALL_UNMANAGED) { // We set up the unmanaged call by linking the frame, disabling GC, etc @@ -8506,10 +8498,8 @@ var_types Compiler::impImportCall(OPCODE opcode, goto DONE; } - else if ((opcode == CEE_CALLI) && (((sig->callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_STDCALL) || - ((sig->callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_C) || - ((sig->callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_THISCALL) || - ((sig->callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_FASTCALL))) + else if ((opcode == CEE_CALLI) && ((sig->callConv & CORINFO_CALLCONV_MASK) != CORINFO_CALLCONV_DEFAULT) && + ((sig->callConv & CORINFO_CALLCONV_MASK) != CORINFO_CALLCONV_VARARG)) { if (!info.compCompHnd->canGetCookieForPInvokeCalliSig(sig)) { @@ -8911,9 +8901,8 @@ var_types Compiler::impImportCall(OPCODE opcode, // a small-typed return value is responsible for normalizing the return val if (canTailCall && - !impTailCallRetTypeCompatible(info.compRetType, info.compMethodInfo->args.retTypeClass, - compMethodInfoGetEntrypointCallConv(info.compMethodInfo), callRetTyp, - sig->retTypeClass, call->AsCall()->GetUnmanagedCallConv())) + !impTailCallRetTypeCompatible(info.compRetType, info.compMethodInfo->args.retTypeClass, info.compCallConv, + callRetTyp, sig->retTypeClass, call->AsCall()->GetUnmanagedCallConv())) { canTailCall = false; szCanTailCallFailReason = "Return types are not tail call compatible"; @@ -9256,7 +9245,7 @@ var_types Compiler::impImportCall(OPCODE opcode, #pragma warning(pop) #endif -bool Compiler::impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo) +bool Compiler::impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo, CorInfoCallConvExtension callConv) { CorInfoType corType = methInfo->args.retType; @@ -9265,9 +9254,7 @@ bool Compiler::impMethodInfo_hasRetBuffArg(CORINFO_METHOD_INFO* methInfo) // We have some kind of STRUCT being returned structPassingKind howToReturnStruct = SPK_Unknown; - var_types returnType = - getReturnTypeForStruct(methInfo->args.retTypeClass, compMethodInfoGetEntrypointCallConv(methInfo), - &howToReturnStruct); + var_types returnType = getReturnTypeForStruct(methInfo->args.retTypeClass, callConv, &howToReturnStruct); if (howToReturnStruct == SPK_ByReference) { @@ -16982,8 +16969,7 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode) noway_assert(info.compRetBuffArg == BAD_VAR_NUM); // adjust the type away from struct to integral // and no normalizing - op2 = impFixupStructReturnType(op2, retClsHnd, - compMethodInfoGetEntrypointCallConv(info.compMethodInfo)); + op2 = impFixupStructReturnType(op2, retClsHnd, info.compCallConv); } else { @@ -17183,8 +17169,7 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode) // Same as !IsHfa but just don't bother with impAssignStructPtr. #else // defined(UNIX_AMD64_ABI) ReturnTypeDesc retTypeDesc; - retTypeDesc.InitializeStructReturnType(this, retClsHnd, - compMethodInfoGetEntrypointCallConv(info.compMethodInfo)); + retTypeDesc.InitializeStructReturnType(this, retClsHnd, info.compCallConv); unsigned retRegCount = retTypeDesc.GetReturnRegCount(); if (retRegCount != 0) @@ -17218,8 +17203,7 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode) else #elif defined(TARGET_ARM64) ReturnTypeDesc retTypeDesc; - retTypeDesc.InitializeStructReturnType(this, retClsHnd, - compMethodInfoGetEntrypointCallConv(info.compMethodInfo)); + retTypeDesc.InitializeStructReturnType(this, retClsHnd, info.compCallConv); unsigned retRegCount = retTypeDesc.GetReturnRegCount(); if (retRegCount != 0) @@ -17243,8 +17227,7 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode) else #elif defined(TARGET_X86) ReturnTypeDesc retTypeDesc; - retTypeDesc.InitializeStructReturnType(this, retClsHnd, - compMethodInfoGetEntrypointCallConv(info.compMethodInfo)); + retTypeDesc.InitializeStructReturnType(this, retClsHnd, info.compCallConv); unsigned retRegCount = retTypeDesc.GetReturnRegCount(); if (retRegCount != 0) @@ -17333,7 +17316,7 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode) #if defined(TARGET_WINDOWS) && defined(TARGET_ARM64) // On ARM64, the native instance calling convention variant // requires the implicit ByRef to be explicitly returned. - else if (callConvIsInstanceMethodCallConv(compMethodInfoGetEntrypointCallConv(info.compMethodInfo))) + else if (callConvIsInstanceMethodCallConv(info.compCallConv)) { op1 = gtNewOperNode(GT_RETURN, TYP_BYREF, gtNewLclvNode(info.compRetBuffArg, TYP_BYREF)); } @@ -17352,7 +17335,7 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode) // Also on System V AMD64 the multireg structs returns are also left as structs. noway_assert(info.compRetNativeType != TYP_STRUCT); #endif - op2 = impFixupStructReturnType(op2, retClsHnd, compMethodInfoGetEntrypointCallConv(info.compMethodInfo)); + op2 = impFixupStructReturnType(op2, retClsHnd, info.compCallConv); // return op2 var_types returnType; if (compDoOldStructRetyping()) @@ -19471,7 +19454,8 @@ void Compiler::impInlineInitVars(InlineInfo* pInlineInfo) InlLclVarInfo* lclVarInfo = pInlineInfo->lclVarInfo; InlineResult* inlineResult = pInlineInfo->inlineResult; - const bool hasRetBuffArg = impMethodInfo_hasRetBuffArg(methInfo); + // Inlined methods always use the managed calling convention + const bool hasRetBuffArg = impMethodInfo_hasRetBuffArg(methInfo, CorInfoCallConvExtension::Managed); /* init the argument stuct */ diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 4d8230187e284..49a2879a4a2bd 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -135,7 +135,7 @@ void Compiler::lvaInitTypeRef() // Are we returning a struct using a return buffer argument? // - const bool hasRetBuffArg = impMethodInfo_hasRetBuffArg(info.compMethodInfo); + const bool hasRetBuffArg = impMethodInfo_hasRetBuffArg(info.compMethodInfo, info.compCallConv); // Possibly change the compRetNativeType from TYP_STRUCT to a "primitive" type // when we are returning a struct by value and it fits in one register @@ -145,9 +145,7 @@ void Compiler::lvaInitTypeRef() CORINFO_CLASS_HANDLE retClsHnd = info.compMethodInfo->args.retTypeClass; Compiler::structPassingKind howToReturnStruct; - var_types returnType = - getReturnTypeForStruct(retClsHnd, compMethodInfoGetEntrypointCallConv(info.compMethodInfo), - &howToReturnStruct); + var_types returnType = getReturnTypeForStruct(retClsHnd, info.compCallConv, &howToReturnStruct); // We can safely widen the return type for enclosed structs. if ((howToReturnStruct == SPK_PrimitiveType) || (howToReturnStruct == SPK_EnclosingType)) @@ -353,7 +351,7 @@ void Compiler::lvaInitArgs(InitVarDscInfo* varDscInfo) unsigned numUserArgsToSkip = 0; unsigned numUserArgs = info.compMethodInfo->args.numArgs; #if defined(TARGET_WINDOWS) && !defined(TARGET_ARM) - if (callConvIsInstanceMethodCallConv(compMethodInfoGetEntrypointCallConv(info.compMethodInfo))) + if (callConvIsInstanceMethodCallConv(info.compCallConv)) { // If we are a native instance method, handle the first user arg // (the unmanaged this parameter) and then handle the hidden @@ -505,7 +503,7 @@ void Compiler::lvaInitThisPtr(InitVarDscInfo* varDscInfo) void Compiler::lvaInitRetBuffArg(InitVarDscInfo* varDscInfo, bool useFixedRetBufReg) { LclVarDsc* varDsc = varDscInfo->varDsc; - bool hasRetBuffArg = impMethodInfo_hasRetBuffArg(info.compMethodInfo); + bool hasRetBuffArg = impMethodInfo_hasRetBuffArg(info.compMethodInfo, info.compCallConv); // These two should always match noway_assert(hasRetBuffArg == varDscInfo->hasRetBufArg); @@ -5349,7 +5347,7 @@ void Compiler::lvaAssignVirtualFrameOffsetsToArgs() // the this parameter comes before the hidden return buffer parameter. // So, we want to process the native "this" parameter before we process // the native return buffer parameter. - if (callConvIsInstanceMethodCallConv(compMethodInfoGetEntrypointCallConv(info.compMethodInfo))) + if (callConvIsInstanceMethodCallConv(info.compCallConv)) { noway_assert(lvaTable[lclNum].lvIsRegArg); #ifndef TARGET_X86 diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 176eac0d15a99..d7488c8522875 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3016,9 +3016,7 @@ void Lowering::LowerRet(GenTreeUnOp* ret) ReturnTypeDesc retTypeDesc; LclVarDsc* varDsc = nullptr; varDsc = comp->lvaGetDesc(retVal->AsLclVar()->GetLclNum()); - retTypeDesc.InitializeStructReturnType(comp, varDsc->GetStructHnd(), - comp->compMethodInfoGetEntrypointCallConv( - comp->info.compMethodInfo)); + retTypeDesc.InitializeStructReturnType(comp, varDsc->GetStructHnd(), comp->info.compCallConv); if (retTypeDesc.GetReturnRegCount() > 1) { CheckMultiRegLclVar(retVal->AsLclVar(), &retTypeDesc); diff --git a/src/coreclr/jit/lsrabuild.cpp b/src/coreclr/jit/lsrabuild.cpp index a0cbf2d5f24a9..ac383e5123185 100644 --- a/src/coreclr/jit/lsrabuild.cpp +++ b/src/coreclr/jit/lsrabuild.cpp @@ -3507,8 +3507,7 @@ int LinearScan::BuildReturn(GenTree* tree) LclVarDsc* varDsc = compiler->lvaGetDesc(op1->AsLclVar()->GetLclNum()); ReturnTypeDesc retTypeDesc; retTypeDesc.InitializeStructReturnType(compiler, varDsc->GetStructHnd(), - compiler->compMethodInfoGetEntrypointCallConv( - compiler->info.compMethodInfo)); + compiler->info.compCallConv); pRetTypeDesc = &retTypeDesc; assert(compiler->lvaGetDesc(op1->AsLclVar()->GetLclNum())->lvFieldCnt == retTypeDesc.GetReturnRegCount()); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 3b7b08ae65b2e..3f167b19dd739 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -6831,8 +6831,7 @@ bool Compiler::fgCanFastTailCall(GenTreeCall* callee, const char** failReason) if (callee->IsTailPrefixedCall()) { var_types retType = (compDoOldStructRetyping() ? info.compRetNativeType : info.compRetType); - assert(impTailCallRetTypeCompatible(retType, info.compMethodInfo->args.retTypeClass, - compMethodInfoGetEntrypointCallConv(info.compMethodInfo), + assert(impTailCallRetTypeCompatible(retType, info.compMethodInfo->args.retTypeClass, info.compCallConv, (var_types)callee->gtReturnType, callee->gtRetClsHnd, callee->GetUnmanagedCallConv())); } diff --git a/src/coreclr/jit/target.h b/src/coreclr/jit/target.h index 5d3e7ad96d14c..633f5dc34d22b 100644 --- a/src/coreclr/jit/target.h +++ b/src/coreclr/jit/target.h @@ -2027,24 +2027,6 @@ typedef target_ssize_t cnsval_ssize_t; typedef target_size_t cnsval_size_t; #endif -// Represents the calling conventions supported with the extensible calling convention syntax -// as well as the original metadata-encoded calling conventions. -enum class CorInfoCallConvExtension -{ - Managed, - C, - Stdcall, - Thiscall, - Fastcall - // New calling conventions supported with the extensible calling convention encoding go here. -}; - -// Determines whether or not this calling convention is an instance method calling convention. -inline bool callConvIsInstanceMethodCallConv(CorInfoCallConvExtension callConv) -{ - return callConv == CorInfoCallConvExtension::Thiscall; -} - /*****************************************************************************/ #endif // TARGET_H_ /*****************************************************************************/ diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs index 2326320e34eb4..5808db5f534f7 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoBase.cs @@ -276,12 +276,12 @@ static byte _isIntrinsicType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLA } [UnmanagedCallersOnly] - static CorInfoUnmanagedCallConv _getUnmanagedCallConv(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method) + static CorInfoCallConvExtension _getUnmanagedCallConv(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition) { var _this = GetThis(thisHandle); try { - return _this.getUnmanagedCallConv(method); + return _this.getUnmanagedCallConv(method, callSiteSig, ref *pSuppressGCTransition); } catch (Exception ex) { @@ -2556,7 +2556,7 @@ static IntPtr GetUnmanagedCallbacks() callbacks[15] = (delegate* unmanaged)&_expandRawHandleIntrinsic; callbacks[16] = (delegate* unmanaged)&_getIntrinsicID; callbacks[17] = (delegate* unmanaged)&_isIntrinsicType; - callbacks[18] = (delegate* unmanaged)&_getUnmanagedCallConv; + callbacks[18] = (delegate* unmanaged)&_getUnmanagedCallConv; callbacks[19] = (delegate* unmanaged)&_pInvokeMarshalingRequired; callbacks[20] = (delegate* unmanaged)&_satisfiesMethodConstraints; callbacks[21] = (delegate* unmanaged)&_isCompatibleDelegate; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index b31079430320b..c88f858afacfd 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3,9 +3,11 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Text; +using System.Reflection.Metadata; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; @@ -474,7 +476,7 @@ private bool Get_CORINFO_METHOD_INFO(MethodDesc method, MethodIL methodIL, CORIN methodInfo->options |= CorInfoOptions.CORINFO_GENERICS_CTXT_FROM_METHODTABLE; } methodInfo->regionKind = CorInfoRegionKind.CORINFO_REGION_NONE; - Get_CORINFO_SIG_INFO(method, &methodInfo->args); + Get_CORINFO_SIG_INFO(method, sig: &methodInfo->args); Get_CORINFO_SIG_INFO(methodIL.GetLocals(), &methodInfo->locals); return true; @@ -484,11 +486,6 @@ private void Get_CORINFO_SIG_INFO(MethodDesc method, CORINFO_SIG_INFO* sig, bool { Get_CORINFO_SIG_INFO(method.Signature, sig); - if (method.IsPInvoke && method.IsSuppressGCTransition()) - { - sig->flags |= CorInfoSigInfoFlags.CORINFO_SIGFLAG_SUPPRESS_GC_TRANSITION; - } - // Does the method have a hidden parameter? bool hasHiddenParameter = !suppressHiddenArgument && method.RequiresInstArg(); @@ -522,9 +519,52 @@ private void Get_CORINFO_SIG_INFO(MethodDesc method, CORINFO_SIG_INFO* sig, bool } } - private bool TryGetUnmanagedCallingConventionFromModOpt(MethodSignature signature, out CorInfoCallConv callConv) + private CorInfoCallConvExtension GetUnmanagedCallingConventionFromAttribute(CustomAttributeValue unmanagedCallersOnlyAttribute) + { + CorInfoCallConvExtension callConv = (CorInfoCallConvExtension)PlatformDefaultUnmanagedCallingConvention(); + + ImmutableArray> callConvArray = default; + foreach (var arg in unmanagedCallersOnlyAttribute.NamedArguments) + { + if (arg.Name == "CallConvs") + { + callConvArray = (ImmutableArray>)arg.Value; + } + } + + // No calling convention was specified in the attribute, so return the default. + if (callConvArray.IsDefault) + { + return callConv; + } + + bool found = false; + foreach (CustomAttributeTypedArgument type in callConvArray) + { + if (!(type.Value is DefType defType)) + continue; + + if (defType.Namespace != "System.Runtime.CompilerServices") + continue; + + CorInfoCallConvExtension? callConvLocal = GetCallingConventionForCallConvType(defType); + + if (callConvLocal.HasValue) + { + // Error if there are multiple recognized calling conventions + if (found) + ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramMultipleCallConv, MethodBeingCompiled); + + callConv = callConvLocal.Value; + found = true; + } + } + return callConv; + } + + private bool TryGetUnmanagedCallingConventionFromModOpt(MethodSignature signature, out CorInfoCallConvExtension callConv) { - callConv = CorInfoCallConv.CORINFO_CALLCONV_UNMANAGED; + callConv = CorInfoCallConvExtension.Managed; if (!signature.HasEmbeddedSignatureData || signature.GetEmbeddedSignatureData() == null) return false; @@ -545,22 +585,14 @@ private bool TryGetUnmanagedCallingConventionFromModOpt(MethodSignature signatur if (defType.Namespace != "System.Runtime.CompilerServices") continue; - // Look for a recognized calling convention in metadata. - CorInfoCallConv? callConvLocal = defType.Name switch - { - "CallConvCdecl" => CorInfoCallConv.CORINFO_CALLCONV_C, - "CallConvStdcall" => CorInfoCallConv.CORINFO_CALLCONV_STDCALL, - "CallConvFastcall" => CorInfoCallConv.CORINFO_CALLCONV_FASTCALL, - "CallConvThiscall" => CorInfoCallConv.CORINFO_CALLCONV_THISCALL, - _ => null - }; + CorInfoCallConvExtension? callConvLocal = GetCallingConventionForCallConvType(defType); if (callConvLocal.HasValue) { // Error if there are multiple recognized calling conventions if (found) ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramMultipleCallConv, MethodBeingCompiled); - + callConv = callConvLocal.Value; found = true; } @@ -569,6 +601,17 @@ private bool TryGetUnmanagedCallingConventionFromModOpt(MethodSignature signatur return found; } + private static CorInfoCallConvExtension? GetCallingConventionForCallConvType(DefType defType) => + // Look for a recognized calling convention in metadata. + defType.Name switch + { + "CallConvCdecl" => CorInfoCallConvExtension.C, + "CallConvStdcall" => CorInfoCallConvExtension.Stdcall, + "CallConvFastcall" => CorInfoCallConvExtension.Fastcall, + "CallConvThiscall" => CorInfoCallConvExtension.Thiscall, + _ => null + }; + private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* sig) { sig->callConv = (CorInfoCallConv)(signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask); @@ -579,19 +622,6 @@ private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* s if (!signature.IsStatic) sig->callConv |= CorInfoCallConv.CORINFO_CALLCONV_HASTHIS; - // Unmanaged calling convention indicates modopt should be read - if (sig->callConv == CorInfoCallConv.CORINFO_CALLCONV_UNMANAGED) - { - if (TryGetUnmanagedCallingConventionFromModOpt(signature, out CorInfoCallConv callConvMaybe)) - { - sig->callConv = callConvMaybe; - } - else - { - sig->callConv = (CorInfoCallConv)PlatformDefaultUnmanagedCallingConvention(); - } - } - TypeDesc returnType = signature.ReturnType; CorInfoType corInfoRetType = asCorInfoType(signature.ReturnType, &sig->retTypeClass); @@ -611,7 +641,7 @@ private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* s sig->pSig = (byte*)ObjectToHandle(signature); sig->cbSig = 0; // Not used by the JIT - sig->scope = null; // Not used by the JIT + sig->scope = null; sig->token = 0; // Not used by the JIT } @@ -664,7 +694,7 @@ private CorInfoType asCorInfoType(TypeDesc type, out TypeDesc typeIfNotPrimitive typeIfNotPrimitive = null; return CorInfoType.CORINFO_TYPE_PTR; } - + typeIfNotPrimitive = type; if (type.IsByRef) @@ -877,7 +907,7 @@ private void getMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CO } } - Get_CORINFO_SIG_INFO(method, sig); + Get_CORINFO_SIG_INFO(method, sig: sig); } private bool getMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info) @@ -1025,19 +1055,86 @@ private MethodSignatureFlags PlatformDefaultUnmanagedCallingConvention() MethodSignatureFlags.UnmanagedCallingConventionStdCall : MethodSignatureFlags.UnmanagedCallingConventionCdecl; } - private CorInfoUnmanagedCallConv getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method) + private CorInfoCallConvExtension getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* sig, ref bool pSuppressGCTransition) { - MethodSignatureFlags unmanagedCallConv = HandleToObject(method).GetPInvokeMethodMetadata().Flags.UnmanagedCallingConvention; + pSuppressGCTransition = false; + + if (method != null) + { + MethodDesc methodDesc = HandleToObject(method); + CorInfoCallConvExtension callConv = GetUnmanagedCallConv(HandleToObject(method), out pSuppressGCTransition); + return callConv; + } + else + { + Debug.Assert(sig != null); - if (unmanagedCallConv == MethodSignatureFlags.None) - unmanagedCallConv = PlatformDefaultUnmanagedCallingConvention(); + CorInfoCallConvExtension callConv = GetUnmanagedCallConv((MethodSignature)HandleToObject((IntPtr)sig->pSig), out pSuppressGCTransition); + if (sig->flags.HasFlag(CorInfoSigInfoFlags.CORINFO_SIGFLAG_SUPPRESS_GC_TRANSITION)) + { + pSuppressGCTransition = true; + } + return callConv; + } + } + private CorInfoCallConvExtension GetUnmanagedCallConv(MethodDesc methodDesc, out bool suppressGCTransition) + { + suppressGCTransition = false; + MethodSignatureFlags callConv = methodDesc.Signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask; + if (callConv == MethodSignatureFlags.None) + { + if (methodDesc.IsPInvoke) + { + suppressGCTransition = methodDesc.IsSuppressGCTransition(); + MethodSignatureFlags unmanagedCallConv = methodDesc.GetPInvokeMethodMetadata().Flags.UnmanagedCallingConvention; - // Verify that it is safe to convert MethodSignatureFlags.UnmanagedCallingConvention to CorInfoUnmanagedCallConv via a simple cast - Debug.Assert((int)CorInfoUnmanagedCallConv.CORINFO_UNMANAGED_CALLCONV_C == (int)MethodSignatureFlags.UnmanagedCallingConventionCdecl); - Debug.Assert((int)CorInfoUnmanagedCallConv.CORINFO_UNMANAGED_CALLCONV_STDCALL == (int)MethodSignatureFlags.UnmanagedCallingConventionStdCall); - Debug.Assert((int)CorInfoUnmanagedCallConv.CORINFO_UNMANAGED_CALLCONV_THISCALL == (int)MethodSignatureFlags.UnmanagedCallingConventionThisCall); + if (unmanagedCallConv == MethodSignatureFlags.None) + unmanagedCallConv = PlatformDefaultUnmanagedCallingConvention(); - return (CorInfoUnmanagedCallConv)unmanagedCallConv; + // Verify that it is safe to convert MethodSignatureFlags.UnmanagedCallingConvention to CorInfoCallConvExtension via a simple cast + Debug.Assert((int)CorInfoCallConvExtension.C == (int)MethodSignatureFlags.UnmanagedCallingConventionCdecl); + Debug.Assert((int)CorInfoCallConvExtension.Stdcall == (int)MethodSignatureFlags.UnmanagedCallingConventionStdCall); + Debug.Assert((int)CorInfoCallConvExtension.Thiscall == (int)MethodSignatureFlags.UnmanagedCallingConventionThisCall); + + return (CorInfoCallConvExtension)unmanagedCallConv; + } + else + { + Debug.Assert(methodDesc.IsUnmanagedCallersOnly); + CustomAttributeValue unmanagedCallersOnlyAttribute = ((EcmaMethod)methodDesc).GetDecodedCustomAttribute("System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute").Value; + return GetUnmanagedCallingConventionFromAttribute(unmanagedCallersOnlyAttribute); + } + } + return GetUnmanagedCallConv(methodDesc.Signature, out suppressGCTransition); + } + + private CorInfoCallConvExtension GetUnmanagedCallConv(MethodSignature signature, out bool suppressGCTransition) + { + suppressGCTransition = false; + switch (signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask) + { + case MethodSignatureFlags.None: + ThrowHelper.ThrowInvalidProgramException(); + return CorInfoCallConvExtension.Managed; + case MethodSignatureFlags.UnmanagedCallingConventionCdecl: + return CorInfoCallConvExtension.C; + case MethodSignatureFlags.UnmanagedCallingConventionStdCall: + return CorInfoCallConvExtension.Stdcall; + case MethodSignatureFlags.UnmanagedCallingConventionThisCall: + return CorInfoCallConvExtension.Thiscall; + case MethodSignatureFlags.UnmanagedCallingConvention: + if (TryGetUnmanagedCallingConventionFromModOpt(signature, out CorInfoCallConvExtension callConvMaybe)) + { + return callConvMaybe; + } + else + { + return (CorInfoCallConvExtension)PlatformDefaultUnmanagedCallingConvention(); + } + default: + ThrowHelper.ThrowInvalidProgramException(); + return CorInfoCallConvExtension.Managed; + } } private bool satisfiesMethodConstraints(CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method) @@ -1287,9 +1384,6 @@ private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEX Get_CORINFO_SIG_INFO(methodSig, sig); - // CORINFO_CALLCONV_UNMANAGED is handled by Get_CORINFO_SIG_INFO - Debug.Assert(sig->callConv != CorInfoCallConv.CORINFO_CALLCONV_UNMANAGED); - // TODO: Replace this with a public mechanism to mark calli with SuppressGCTransition once it becomes available. if (methodIL is PInvokeILStubMethodIL stubIL) { @@ -1314,7 +1408,7 @@ private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEX private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) { var methodIL = (MethodIL)HandleToObject((IntPtr)module); - Get_CORINFO_SIG_INFO(((MethodDesc)methodIL.GetObject((int)methTOK)), sig); + Get_CORINFO_SIG_INFO(((MethodDesc)methodIL.GetObject((int)methTOK)), sig: sig); } private CORINFO_CLASS_STRUCT_* getTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken) @@ -1645,7 +1739,7 @@ static bool ShouldAlign8(DefType type) { if (field.IsStatic) continue; - + instanceFields++; if (field.FieldType == doubleType) @@ -2998,7 +3092,7 @@ private ref ArrayBuilder findRelocBlock(BlockType blockType, out int length = _roData.Length; return ref _roDataRelocs; default: - throw new NotImplementedException("Arbitrary relocs"); + throw new NotImplementedException("Arbitrary relocs"); } } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index d6eab1344394b..66b04f6996b94 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -63,7 +63,7 @@ public struct CORINFO_JUST_MY_CODE_HANDLE_ public struct CORINFO_VarArgInfo { } - + public struct PatchpointInfo { } @@ -314,10 +314,11 @@ public enum CorInfoCallConv // These correspond to CorCallingConvention CORINFO_CALLCONV_DEFAULT = 0x0, - CORINFO_CALLCONV_C = 0x1, - CORINFO_CALLCONV_STDCALL = 0x2, - CORINFO_CALLCONV_THISCALL = 0x3, - CORINFO_CALLCONV_FASTCALL = 0x4, + // Instead of using the below values, use the CorInfoCallConvExtension enum for unmanaged calling conventions. + // CORINFO_CALLCONV_C = 0x1, + // CORINFO_CALLCONV_STDCALL = 0x2, + // CORINFO_CALLCONV_THISCALL = 0x3, + // CORINFO_CALLCONV_FASTCALL = 0x4, CORINFO_CALLCONV_VARARG = 0x5, CORINFO_CALLCONV_FIELD = 0x6, CORINFO_CALLCONV_LOCAL_SIG = 0x7, @@ -332,15 +333,16 @@ public enum CorInfoCallConv CORINFO_CALLCONV_PARAMTYPE = 0x80, // Passed last. Same as CORINFO_GENERICS_CTXT_FROM_PARAMTYPEARG } - public enum CorInfoUnmanagedCallConv + // Represents the calling conventions supported with the extensible calling convention syntax + // as well as the original metadata-encoded calling conventions. + enum CorInfoCallConvExtension { - // These correspond to CorUnmanagedCallingConvention - - CORINFO_UNMANAGED_CALLCONV_UNKNOWN, - CORINFO_UNMANAGED_CALLCONV_C, - CORINFO_UNMANAGED_CALLCONV_STDCALL, - CORINFO_UNMANAGED_CALLCONV_THISCALL, - CORINFO_UNMANAGED_CALLCONV_FASTCALL + Managed, + C, + Stdcall, + Thiscall, + Fastcall + // New calling conventions supported with the extensible calling convention encoding go here. } public enum CORINFO_CALLINFO_FLAGS diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index f83c4924ca240..46a18235a7cc9 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -1,18 +1,18 @@ ; Licensed to the .NET Foundation under one or more agreements. ; The .NET Foundation licenses this file to you under the MIT license. ; -; Thunk generator input file for generating the thunks from the C++ version of the -; jit interface to COM, into managed, and from COM to C++. +; Thunk generator input file for generating the thunks from the C++ version of the +; jit interface to COM, into managed, and from COM to C++. ; -; The format of this file is as follows. +; The format of this file is as follows. ; There are NORMALTYPES, RETURNTYPES, and FUNCTIONS regions -; In the NORMALTYPES/RETURNTYPES region, each type is described. If a type is +; In the NORMALTYPES/RETURNTYPES region, each type is described. If a type is ; described in the NORMALTYPES section, but isn't described in the RETURNTYPES section ; then the NORMALTYPES description can be used for a return value. ; ; TYPES have three fields ; ThunkDescriptionType,ManagedType,NativeType,NativeType2 -; If either ManagedType, NativeType, or NativeType2 are missing, then that form is replaced with ThunkDescriptionType. +; If either ManagedType, NativeType, or NativeType2 are missing, then that form is replaced with ThunkDescriptionType. ; NativeType is used for representing the type in headers which do not include the PAL and corinfo.h ; NativeType2 is used for representing the type in headers that are fully integrated with the PAL ; This feature allows reduction in type for enums and other types where the same type can be used in managed an native @@ -24,12 +24,12 @@ ; PointerToIntPointer,int**,int** ; ; Following the TYPES sections, there is the FUNCTIONS section -; Each function that is to be part of the interface is written here. The format is basically the C++ format +; Each function that is to be part of the interface is written here. The format is basically the C++ format ; without support for inline comments or sal annotations. ; ; Also, note that an empty line is ignored, and a line that begins with a ; is ignored. ; -; If the boilerplate around the individual functions needs adjustment, edit the thunk generator source code, and +; If the boilerplate around the individual functions needs adjustment, edit the thunk generator source code, and ; rebuild with rebuildthunkgen.cmd in the the ThunkGenerator subdir, then rebuildthunks.cmd ; If this file is editted, rebuild with gen.cmd -- DO NOT RUN from within a razzle window. ; @@ -123,7 +123,7 @@ CorInfoTailCall,,int CorInfoType,,int CorInfoHFAElemType,,int CorInfoTypeWithMod,,int -CorInfoUnmanagedCallConv,,int +CorInfoCallConvExtension,,int InfoAccessType,,int CORINFO_LOOKUP_KIND CORINFO_ACCESS_FLAGS,,int @@ -176,7 +176,7 @@ FUNCTIONS void expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_GENERICHANDLE_RESULT * pResult); CorInfoIntrinsics getIntrinsicID( CORINFO_METHOD_HANDLE method , BoolStar pMustExpand); bool isIntrinsicType( CORINFO_CLASS_HANDLE classHnd ); - CorInfoUnmanagedCallConv getUnmanagedCallConv( CORINFO_METHOD_HANDLE method ); + CorInfoCallConvExtension getUnmanagedCallConv( CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition); bool pInvokeMarshalingRequired( CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig ); bool satisfiesMethodConstraints( CORINFO_CLASS_HANDLE parent, CORINFO_METHOD_HANDLE method ); bool isCompatibleDelegate( CORINFO_CLASS_HANDLE objCls, CORINFO_CLASS_HANDLE methodParentCls, CORINFO_METHOD_HANDLE method, CORINFO_CLASS_HANDLE delegateCls, bool *pfIsOpenDelegate ); diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface.h b/src/coreclr/tools/aot/jitinterface/jitinterface.h index e7a9609b6e456..1d94c382277e5 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface.h @@ -28,7 +28,7 @@ struct JitInterfaceCallbacks void (* expandRawHandleIntrinsic)(void * thisHandle, CorInfoExceptionClass** ppException, void* pResolvedToken, void* pResult); int (* getIntrinsicID)(void * thisHandle, CorInfoExceptionClass** ppException, void* method, bool* pMustExpand); bool (* isIntrinsicType)(void * thisHandle, CorInfoExceptionClass** ppException, void* classHnd); - int (* getUnmanagedCallConv)(void * thisHandle, CorInfoExceptionClass** ppException, void* method); + int (* getUnmanagedCallConv)(void * thisHandle, CorInfoExceptionClass** ppException, void* method, void* callSiteSig, bool* pSuppressGCTransition); bool (* pInvokeMarshalingRequired)(void * thisHandle, CorInfoExceptionClass** ppException, void* method, void* callSiteSig); bool (* satisfiesMethodConstraints)(void * thisHandle, CorInfoExceptionClass** ppException, void* parent, void* method); bool (* isCompatibleDelegate)(void * thisHandle, CorInfoExceptionClass** ppException, void* objCls, void* methodParentCls, void* method, void* delegateCls, bool* pfIsOpenDelegate); @@ -376,10 +376,12 @@ class JitInterfaceWrapper } virtual int getUnmanagedCallConv( - void* method) + void* method, + void* callSiteSig, + bool* pSuppressGCTransition) { CorInfoExceptionClass* pException = nullptr; - int temp = _callbacks->getUnmanagedCallConv(_thisHandle, &pException, method); + int temp = _callbacks->getUnmanagedCallConv(_thisHandle, &pException, method, callSiteSig, pSuppressGCTransition); if (pException != nullptr) throw pException; return temp; } diff --git a/src/coreclr/vm/amd64/cgencpu.h b/src/coreclr/vm/amd64/cgencpu.h index 0115cf7acb668..c7ecc88d2c4d2 100644 --- a/src/coreclr/vm/amd64/cgencpu.h +++ b/src/coreclr/vm/amd64/cgencpu.h @@ -419,20 +419,6 @@ extern "C" void getFPReturn(int fpSize, INT64 *retval); struct ComToManagedExRecord; // defined in cgencpu.cpp -inline BOOL IsUnmanagedValueTypeReturnedByRef(UINT sizeofvaluetype) -{ - LIMITED_METHOD_CONTRACT; - - if (sizeofvaluetype > ENREGISTERED_RETURNTYPE_MAXSIZE) - { - return TRUE; - } - else - { - return FALSE; - } -} - #include struct DECLSPEC_ALIGN(8) UMEntryThunkCode { diff --git a/src/coreclr/vm/arm/cgencpu.h b/src/coreclr/vm/arm/cgencpu.h index 51cb67acba0de..3739f4ce5dc66 100644 --- a/src/coreclr/vm/arm/cgencpu.h +++ b/src/coreclr/vm/arm/cgencpu.h @@ -929,17 +929,6 @@ class StubLinkerCPU : public StubLinker extern "C" void SinglecastDelegateInvokeStub(); -// SEH info forward declarations - -inline BOOL IsUnmanagedValueTypeReturnedByRef(UINT sizeofvaluetype) -{ - LIMITED_METHOD_CONTRACT; - - // structure that dont fit in the machine-word size are returned - // by reference. - return (sizeofvaluetype > 4); -} - #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4359) // Prevent "warning C4359: 'UMEntryThunkCode': Alignment specifier is less than actual alignment (8), and will be ignored." in crossbitness scenario diff --git a/src/coreclr/vm/arm64/cgencpu.h b/src/coreclr/vm/arm64/cgencpu.h index d8b4281073afb..b28ac4d99c9fe 100644 --- a/src/coreclr/vm/arm64/cgencpu.h +++ b/src/coreclr/vm/arm64/cgencpu.h @@ -338,15 +338,6 @@ inline PCODE decodeBackToBackJump(PCODE pBuffer) return decodeJump(pBuffer); } -// SEH info forward declarations - -inline BOOL IsUnmanagedValueTypeReturnedByRef(UINT sizeofvaluetype) -{ - // ARM64TODO: Does this need to care about HFA. It does not for ARM32 - return (sizeofvaluetype > ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE); -} - - //---------------------------------------------------------------------- struct IntReg diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 4cae3832604f3..187a344b85422 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -1598,7 +1598,7 @@ void NDirectStubLinker::SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL f { // The JIT has to use a different calling convention for unmanaged vararg targets on 64-bit and ARM: // any float values must be duplicated in the corresponding general-purpose registers. - uNativeCallingConv = CORINFO_CALLCONV_NATIVEVARARG; + uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_NATIVEVARARG; } else #endif // !TARGET_X86 @@ -1606,17 +1606,17 @@ void NDirectStubLinker::SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL f switch (unmngCallConv) { case pmCallConvCdecl: - uNativeCallingConv = CORINFO_CALLCONV_C; + uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_C; break; case pmCallConvStdcall: - uNativeCallingConv = CORINFO_CALLCONV_STDCALL; + uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_STDCALL; break; case pmCallConvThiscall: - uNativeCallingConv = CORINFO_CALLCONV_THISCALL; + uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_THISCALL; break; default: _ASSERTE(!"Invalid calling convention."); - uNativeCallingConv = CORINFO_CALLCONV_STDCALL; + uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_STDCALL; break; } } @@ -2980,7 +2980,7 @@ namespace HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(pModule, pSig, cSig, &callConvMaybe, errorResID); if (hr != S_OK) return hr; - + if (!TryConvertCallConvValueToPInvokeCallConv(callConvMaybe, pPinvokeMapOut)) return S_FALSE; @@ -3228,18 +3228,7 @@ BOOL NDirect::MarshalingRequired( return TRUE; } #endif - - // return value is fine as long as it can be normalized to an integer - if (i == 0) - { - CorElementType normalizedType = hndArgType.GetInternalCorElementType(); - if (normalizedType == ELEMENT_TYPE_VALUETYPE) - { - // it is a structure even after normalization - return TRUE; - } - } - else + if (i > 0) { dwStackSize += StackElemSize(hndArgType.GetSize()); } @@ -3677,35 +3666,6 @@ static void CreateNDirectStubWorker(StubState* pss, } } - if (marshalType == MarshalInfo::MARSHAL_TYPE_DATE || - marshalType == MarshalInfo::MARSHAL_TYPE_CURRENCY || - marshalType == MarshalInfo::MARSHAL_TYPE_ARRAYWITHOFFSET || - marshalType == MarshalInfo::MARSHAL_TYPE_HANDLEREF || - marshalType == MarshalInfo::MARSHAL_TYPE_ARGITERATOR -#ifdef FEATURE_COMINTEROP - || marshalType == MarshalInfo::MARSHAL_TYPE_OLECOLOR -#endif // FEATURE_COMINTEROP - ) - { - // These are special non-blittable types returned by-ref in managed, - // but marshaled as primitive values returned by-value in unmanaged. - } - else - { - // This is an ordinary value type - see if it is returned by-ref. - TypeHandle retType = msig.GetRetTypeHandleThrowing(); - if (retType.IsValueType() && !retType.IsEnum() && IsUnmanagedValueTypeReturnedByRef(retType.MakeNativeValueType().GetSize())) - { - nativeStackSize += sizeof(LPVOID); - } -#if defined(TARGET_WINDOWS) && !defined(TARGET_ARM) - else if (fThisCall && !retType.IsEnum()) - { - nativeStackSize += sizeof(LPVOID); - } -#endif - } - if (SF_IsHRESULTSwapping(dwStubFlags)) { if (msig.GetReturnType() != ELEMENT_TYPE_VOID) @@ -4241,27 +4201,6 @@ void NDirect::PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSi pNMD->ndirect.m_pszEntrypointName.SetValueMaybeNull(szEntryPointName); } -#ifdef TARGET_X86 - if (ndirectflags & NDirectMethodDesc::kStdCall) - { - // Compute the kStdCallWithRetBuf flag which is needed at link time for entry point mangling. - MetaSig msig(pNMD); - ArgIterator argit(&msig); - if (argit.HasRetBuffArg()) - { - MethodTable *pRetMT = msig.GetRetTypeHandleThrowing().AsMethodTable(); - // The System.DateTime type itself technically doesn't have a native representation, - // so we have to special-case it here. - // If a type doesn't have a native representation, we won't set this flag. - // We'll throw an exception later when setting up the marshalling. - if (pRetMT != CoreLibBinder::GetClass(CLASS__DATE_TIME) && pRetMT->HasLayout() && IsUnmanagedValueTypeReturnedByRef(pRetMT->GetNativeSize())) - { - ndirectflags |= NDirectMethodDesc::kStdCallWithRetBuf; - } - } - } -#endif // TARGET_X86 - // Call this exactly ONCE per thread. Do not publish incomplete prestub flags // or you will introduce a race condition. pNMD->InterlockedSetNDirectFlags(ndirectflags); @@ -6222,7 +6161,7 @@ namespace #if defined(TARGET_LINUX) if (g_coreclr_embedded) { - // this matches exactly the names in Interop.Libraries.cs + // this matches exactly the names in Interop.Libraries.cs static const LPCWSTR toRedirect[] = { W("libSystem.Native"), W("libSystem.Net.Security.Native"), diff --git a/src/coreclr/vm/dllimportcallback.cpp b/src/coreclr/vm/dllimportcallback.cpp index 2a5c72510f04b..1a50a5e7c9898 100644 --- a/src/coreclr/vm/dllimportcallback.cpp +++ b/src/coreclr/vm/dllimportcallback.cpp @@ -655,128 +655,6 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo, pcpusl->X86EmitNearJump(pEnableRejoin); } -namespace -{ - // Templated function to compute if a char string begins with a constant string. - template - bool BeginsWith(ULONG s1Len, const char* s1, const char (&s2)[S2LEN]) - { - WRAPPER_NO_CONTRACT; - - ULONG s2Len = (ULONG)S2LEN - 1; // Remove null - if (s1Len < s2Len) - return false; - - return (0 == strncmp(s1, s2, s2Len)); - } -} - -VOID UMThunkMarshInfo::SetUpForUnmanagedCallersOnly() -{ - STANDARD_VM_CONTRACT; - - MethodDesc* pMD = GetMethod(); - _ASSERTE(pMD != NULL && pMD->HasUnmanagedCallersOnlyAttribute()); - - // Validate usage - COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(pMD); - - BYTE* pData = NULL; - LONG cData = 0; - - bool nativeCallableInternalData = false; - HRESULT hr = pMD->GetCustomAttribute(WellKnownAttribute::UnmanagedCallersOnly, (const VOID **)(&pData), (ULONG *)&cData); - if (hr == S_FALSE) - { - hr = pMD->GetCustomAttribute(WellKnownAttribute::NativeCallableInternal, (const VOID **)(&pData), (ULONG *)&cData); - nativeCallableInternalData = SUCCEEDED(hr); - } - - IfFailThrow(hr); - - _ASSERTE(cData > 0); - - CustomAttributeParser ca(pData, cData); - - // UnmanagedCallersOnly and NativeCallableInternal each - // have optional named arguments. - CaNamedArg namedArgs[2]; - - // For the UnmanagedCallersOnly scenario. - CaType caCallConvs; - - // Define attribute specific optional named properties - if (nativeCallableInternalData) - { - namedArgs[0].InitI4FieldEnum("CallingConvention", "System.Runtime.InteropServices.CallingConvention", (ULONG)(CorPinvokeMap)0); - } - else - { - caCallConvs.Init(SERIALIZATION_TYPE_SZARRAY, SERIALIZATION_TYPE_TYPE, SERIALIZATION_TYPE_UNDEFINED, NULL, 0); - namedArgs[0].Init("CallConvs", SERIALIZATION_TYPE_SZARRAY, caCallConvs); - } - - // Define common optional named properties - CaTypeCtor caEntryPoint(SERIALIZATION_TYPE_STRING); - namedArgs[1].Init("EntryPoint", SERIALIZATION_TYPE_STRING, caEntryPoint); - - InlineFactory, 4> caValueArrayFactory; - DomainAssembly* domainAssembly = pMD->GetLoaderModule()->GetDomainAssembly(); - IfFailThrow(Attribute::ParseAttributeArgumentValues( - pData, - cData, - &caValueArrayFactory, - NULL, - 0, - namedArgs, - lengthof(namedArgs), - domainAssembly)); - - // If the value isn't defined, then return without setting anything. - if (namedArgs[0].val.type.tag == SERIALIZATION_TYPE_UNDEFINED) - return; - - CorPinvokeMap callConvLocal = (CorPinvokeMap)0; - if (nativeCallableInternalData) - { - callConvLocal = (CorPinvokeMap)(namedArgs[0].val.u4 << 8); - } - else - { - // Set WinAPI as the default - callConvLocal = CorPinvokeMap::pmCallConvWinapi; - - CaValue* arrayOfTypes = &namedArgs[0].val; - for (ULONG i = 0; i < arrayOfTypes->arr.length; i++) - { - CaValue& typeNameValue = arrayOfTypes->arr[i]; - - // According to ECMA-335, type name strings are UTF-8. Since we are - // looking for type names that are equivalent in ASCII and UTF-8, - // using a const char constant is acceptable. Type name strings are - // in Fully Qualified form, so we include the ',' delimiter. - if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvCdecl,")) - { - callConvLocal = CorPinvokeMap::pmCallConvCdecl; - } - else if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvStdcall,")) - { - callConvLocal = CorPinvokeMap::pmCallConvStdcall; - } - else if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvFastcall,")) - { - callConvLocal = CorPinvokeMap::pmCallConvFastcall; - } - else if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvThiscall,")) - { - callConvLocal = CorPinvokeMap::pmCallConvThiscall; - } - } - } - - m_callConv = (UINT16)callConvLocal; -} - // Compiles an unmanaged to managed thunk for the given signature. Stub *UMThunkMarshInfo::CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStaticSigInfo* pSigInfo, MetaSig *pMetaSig, BOOL fNoStub) { @@ -1348,7 +1226,11 @@ VOID UMThunkMarshInfo::RunTimeInit() if (pMD != NULL && pMD->HasUnmanagedCallersOnlyAttribute()) { - SetUpForUnmanagedCallersOnly(); + CorPinvokeMap callConv; + if (TryGetCallingConventionFromUnmanagedCallersOnly(pMD, &callConv)) + { + m_callConv = (UINT16)callConv; + } } #endif // TARGET_X86 && !FEATURE_STUBS_AS_IL @@ -1612,4 +1494,124 @@ void STDCALL LogUMTransition(UMEntryThunk* thunk) } #endif +namespace +{ + // Templated function to compute if a char string begins with a constant string. + template + bool BeginsWith(ULONG s1Len, const char* s1, const char (&s2)[S2LEN]) + { + WRAPPER_NO_CONTRACT; + + ULONG s2Len = (ULONG)S2LEN - 1; // Remove null + if (s1Len < s2Len) + return false; + + return (0 == strncmp(s1, s2, s2Len)); + } +} + +bool TryGetCallingConventionFromUnmanagedCallersOnly(MethodDesc* pMD, CorPinvokeMap* pCallConv) +{ + STANDARD_VM_CONTRACT; + _ASSERTE(pMD != NULL && pMD->HasUnmanagedCallersOnlyAttribute()); + + // Validate usage + COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(pMD); + + BYTE* pData = NULL; + LONG cData = 0; + + bool nativeCallableInternalData = false; + HRESULT hr = pMD->GetCustomAttribute(WellKnownAttribute::UnmanagedCallersOnly, (const VOID **)(&pData), (ULONG *)&cData); + if (hr == S_FALSE) + { + hr = pMD->GetCustomAttribute(WellKnownAttribute::NativeCallableInternal, (const VOID **)(&pData), (ULONG *)&cData); + nativeCallableInternalData = SUCCEEDED(hr); + } + + IfFailThrow(hr); + + _ASSERTE(cData > 0); + + CustomAttributeParser ca(pData, cData); + + // UnmanagedCallersOnly and NativeCallableInternal each + // have optional named arguments. + CaNamedArg namedArgs[2]; + + // For the UnmanagedCallersOnly scenario. + CaType caCallConvs; + + // Define attribute specific optional named properties + if (nativeCallableInternalData) + { + namedArgs[0].InitI4FieldEnum("CallingConvention", "System.Runtime.InteropServices.CallingConvention", (ULONG)(CorPinvokeMap)0); + namedArgs[0].InitI4FieldEnum("CallingConvention", "System.Runtime.InteropServices.CallingConvention", (ULONG)(CorPinvokeMap)0); + } + else + { + caCallConvs.Init(SERIALIZATION_TYPE_SZARRAY, SERIALIZATION_TYPE_TYPE, SERIALIZATION_TYPE_UNDEFINED, NULL, 0); + namedArgs[0].Init("CallConvs", SERIALIZATION_TYPE_SZARRAY, caCallConvs); + } + + // Define common optional named properties + CaTypeCtor caEntryPoint(SERIALIZATION_TYPE_STRING); + namedArgs[1].Init("EntryPoint", SERIALIZATION_TYPE_STRING, caEntryPoint); + + InlineFactory, 4> caValueArrayFactory; + DomainAssembly* domainAssembly = pMD->GetLoaderModule()->GetDomainAssembly(); + IfFailThrow(Attribute::ParseAttributeArgumentValues( + pData, + cData, + &caValueArrayFactory, + NULL, + 0, + namedArgs, + lengthof(namedArgs), + domainAssembly)); + + // If the value isn't defined, then return without setting anything. + if (namedArgs[0].val.type.tag == SERIALIZATION_TYPE_UNDEFINED) + return false; + + CorPinvokeMap callConvLocal = (CorPinvokeMap)0; + if (nativeCallableInternalData) + { + callConvLocal = (CorPinvokeMap)(namedArgs[0].val.u4 << 8); + } + else + { + // Set WinAPI as the default + callConvLocal = CorPinvokeMap::pmCallConvWinapi; + + CaValue* arrayOfTypes = &namedArgs[0].val; + for (ULONG i = 0; i < arrayOfTypes->arr.length; i++) + { + CaValue& typeNameValue = arrayOfTypes->arr[i]; + + // According to ECMA-335, type name strings are UTF-8. Since we are + // looking for type names that are equivalent in ASCII and UTF-8, + // using a const char constant is acceptable. Type name strings are + // in Fully Qualified form, so we include the ',' delimiter. + if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvCdecl,")) + { + callConvLocal = CorPinvokeMap::pmCallConvCdecl; + } + else if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvStdcall,")) + { + callConvLocal = CorPinvokeMap::pmCallConvStdcall; + } + else if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvFastcall,")) + { + callConvLocal = CorPinvokeMap::pmCallConvFastcall; + } + else if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvThiscall,")) + { + callConvLocal = CorPinvokeMap::pmCallConvThiscall; + } + } + } + *pCallConv = callConvLocal; + return true; +} #endif // CROSSGEN_COMPILE diff --git a/src/coreclr/vm/dllimportcallback.h b/src/coreclr/vm/dllimportcallback.h index 1bdb5d5cbebd3..f0628da5b4fd0 100644 --- a/src/coreclr/vm/dllimportcallback.h +++ b/src/coreclr/vm/dllimportcallback.h @@ -177,8 +177,6 @@ class UMThunkMarshInfo VOID SetupArguments(char *pSrc, ArgumentRegisters *pArgRegs, char *pDst); #else private: - VOID SetUpForUnmanagedCallersOnly(); - // Compiles an unmanaged to managed thunk for the given signature. The thunk // will call the stub or, if fNoStub == TRUE, directly the managed target. Stub *CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStaticSigInfo* pSigInfo, MetaSig *pMetaSig, BOOL fNoStub); @@ -529,6 +527,8 @@ EXCEPTION_HANDLER_DECL(UMThunkPrestubHandler); #endif // TARGET_X86 && !FEATURE_STUBS_AS_IL +bool TryGetCallingConventionFromUnmanagedCallersOnly(MethodDesc* pMD, CorPinvokeMap* pCallConv); + extern "C" void TheUMEntryPrestub(void); extern "C" PCODE TheUMEntryPrestubWorker(UMEntryThunk * pUMEntryThunk); diff --git a/src/coreclr/vm/i386/cgencpu.h b/src/coreclr/vm/i386/cgencpu.h index 0fb8b70deb22f..7a0ef55aec80a 100644 --- a/src/coreclr/vm/i386/cgencpu.h +++ b/src/coreclr/vm/i386/cgencpu.h @@ -453,21 +453,6 @@ EXTERN_C void __stdcall getFPReturn(int fpSize, INT64 *pretval); // SEH info forward declarations -inline BOOL IsUnmanagedValueTypeReturnedByRef(UINT sizeofvaluetype) -{ - LIMITED_METHOD_CONTRACT; - -#ifndef UNIX_X86_ABI - // odd-sized small structures are not - // enregistered e.g. struct { char a,b,c; } - return (sizeofvaluetype > 8) || - (sizeofvaluetype & (sizeofvaluetype - 1)); // check that the size is power of two -#else - // For UNIX_X86_ABI, we always return the value type by reference regardless of its size - return true; -#endif -} - #include struct DECLSPEC_ALIGN(4) UMEntryThunkCode { diff --git a/src/coreclr/vm/interpreter.cpp b/src/coreclr/vm/interpreter.cpp index 5fd9830b00f43..325aaf4590b9e 100644 --- a/src/coreclr/vm/interpreter.cpp +++ b/src/coreclr/vm/interpreter.cpp @@ -384,20 +384,20 @@ void InterpreterMethodInfo::InitArgInfo(CEEInfo* comp, CORINFO_METHOD_INFO* meth } break; - case CORINFO_CALLCONV_C: - NYI_INTERP("InterpreterMethodInfo::InitArgInfo -- CORINFO_CALLCONV_C"); + case IMAGE_CEE_CS_CALLCONV_C: + NYI_INTERP("InterpreterMethodInfo::InitArgInfo -- IMAGE_CEE_CS_CALLCONV_C"); break; - case CORINFO_CALLCONV_STDCALL: - NYI_INTERP("InterpreterMethodInfo::InitArgInfo -- CORINFO_CALLCONV_STDCALL"); + case IMAGE_CEE_CS_CALLCONV_STDCALL: + NYI_INTERP("InterpreterMethodInfo::InitArgInfo -- IMAGE_CEE_CS_CALLCONV_STDCALL"); break; - case CORINFO_CALLCONV_THISCALL: - NYI_INTERP("InterpreterMethodInfo::InitArgInfo -- CORINFO_CALLCONV_THISCALL"); + case IMAGE_CEE_CS_CALLCONV_THISCALL: + NYI_INTERP("InterpreterMethodInfo::InitArgInfo -- IMAGE_CEE_CS_CALLCONV_THISCALL"); break; - case CORINFO_CALLCONV_FASTCALL: - NYI_INTERP("InterpreterMethodInfo::InitArgInfo -- CORINFO_CALLCONV_FASTCALL"); + case IMAGE_CEE_CS_CALLCONV_FASTCALL: + NYI_INTERP("InterpreterMethodInfo::InitArgInfo -- IMAGE_CEE_CS_CALLCONV_FASTCALL"); break; case CORINFO_CALLCONV_FIELD: @@ -1261,20 +1261,20 @@ CorJitResult Interpreter::GenerateInterpreterStub(CEEInfo* comp, } break; - case CORINFO_CALLCONV_C: - NYI_INTERP("GenerateInterpreterStub -- CORINFO_CALLCONV_C"); + case IMAGE_CEE_CS_CALLCONV_C: + NYI_INTERP("GenerateInterpreterStub -- IMAGE_CEE_CS_CALLCONV_C"); break; - case CORINFO_CALLCONV_STDCALL: - NYI_INTERP("GenerateInterpreterStub -- CORINFO_CALLCONV_STDCALL"); + case IMAGE_CEE_CS_CALLCONV_STDCALL: + NYI_INTERP("GenerateInterpreterStub -- IMAGE_CEE_CS_CALLCONV_STDCALL"); break; - case CORINFO_CALLCONV_THISCALL: - NYI_INTERP("GenerateInterpreterStub -- CORINFO_CALLCONV_THISCALL"); + case IMAGE_CEE_CS_CALLCONV_THISCALL: + NYI_INTERP("GenerateInterpreterStub -- IMAGE_CEE_CS_CALLCONV_THISCALL"); break; - case CORINFO_CALLCONV_FASTCALL: - NYI_INTERP("GenerateInterpreterStub -- CORINFO_CALLCONV_FASTCALL"); + case IMAGE_CEE_CS_CALLCONV_FASTCALL: + NYI_INTERP("GenerateInterpreterStub -- IMAGE_CEE_CS_CALLCONV_FASTCALL"); break; case CORINFO_CALLCONV_FIELD: diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 579259d000c6e..10a1d5c5b7eab 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -24,6 +24,7 @@ #include "float.h" // for isnan #include "dbginterface.h" #include "dllimport.h" +#include "dllimportcallback.h" #include "gcheaputilities.h" #include "comdelegate.h" #include "corprof.h" @@ -451,29 +452,16 @@ CEEInfo::ConvToJitSig( DWORD cbSig, CORINFO_MODULE_HANDLE scopeHnd, mdToken token, - CORINFO_SIG_INFO * sigRet, - MethodDesc * pContextMD, - bool localSig, - TypeHandle contextType) + SigTypeContext* typeContext, + ConvToJitSigFlags flags, + CORINFO_SIG_INFO * sigRet) { CONTRACTL { THROWS; GC_TRIGGERS; } CONTRACTL_END; - SigTypeContext typeContext; - uint32_t sigRetFlags = 0; - if (pContextMD) - { - SigTypeContext::InitTypeContext(pContextMD, contextType, &typeContext); - if (pContextMD->ShouldSuppressGCTransition()) - sigRetFlags |= CORINFO_SIGFLAG_SUPPRESS_GC_TRANSITION; - } - else - { - SigTypeContext::InitTypeContext(contextType, &typeContext); - } static_assert_no_msg(CORINFO_CALLCONV_DEFAULT == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_DEFAULT); static_assert_no_msg(CORINFO_CALLCONV_VARARG == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_VARARG); @@ -488,14 +476,14 @@ CEEInfo::ConvToJitSig( sigRet->retTypeSigClass = 0; sigRet->scope = scopeHnd; sigRet->token = token; - sigRet->sigInst.classInst = (CORINFO_CLASS_HANDLE *) typeContext.m_classInst.GetRawArgs(); - sigRet->sigInst.classInstCount = (unsigned) typeContext.m_classInst.GetNumArgs(); - sigRet->sigInst.methInst = (CORINFO_CLASS_HANDLE *) typeContext.m_methodInst.GetRawArgs(); - sigRet->sigInst.methInstCount = (unsigned) typeContext.m_methodInst.GetNumArgs(); + sigRet->sigInst.classInst = (CORINFO_CLASS_HANDLE *) typeContext->m_classInst.GetRawArgs(); + sigRet->sigInst.classInstCount = (unsigned) typeContext->m_classInst.GetNumArgs(); + sigRet->sigInst.methInst = (CORINFO_CLASS_HANDLE *) typeContext->m_methodInst.GetRawArgs(); + sigRet->sigInst.methInstCount = (unsigned) typeContext->m_methodInst.GetNumArgs(); SigPointer sig(pSig, cbSig); - if (!localSig) + if ((flags & CONV_TO_JITSIG_FLAGS_LOCALSIG) == 0) { // This is a method signature which includes calling convention, return type, // arguments, etc @@ -516,30 +504,6 @@ CEEInfo::ConvToJitSig( } #endif // defined(TARGET_UNIX) || defined(TARGET_ARM) - // Unmanaged calling convention indicates modopt should be read - if (sigRet->callConv == CORINFO_CALLCONV_UNMANAGED) - { - static_assert_no_msg(CORINFO_CALLCONV_C == (CorInfoCallConv)IMAGE_CEE_UNMANAGED_CALLCONV_C); - static_assert_no_msg(CORINFO_CALLCONV_STDCALL == (CorInfoCallConv)IMAGE_CEE_UNMANAGED_CALLCONV_STDCALL); - static_assert_no_msg(CORINFO_CALLCONV_THISCALL == (CorInfoCallConv)IMAGE_CEE_UNMANAGED_CALLCONV_THISCALL); - static_assert_no_msg(CORINFO_CALLCONV_FASTCALL == (CorInfoCallConv)IMAGE_CEE_UNMANAGED_CALLCONV_FASTCALL); - - CorUnmanagedCallingConvention callConvMaybe; - UINT errorResID; - HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(module, pSig, cbSig, &callConvMaybe, &errorResID); - if (FAILED(hr)) - COMPlusThrowHR(hr, errorResID); - - if (hr == S_OK) - { - sigRet->callConv = (CorInfoCallConv)callConvMaybe; - } - else - { - sigRet->callConv = (CorInfoCallConv)MetaSig::GetDefaultUnmanagedCallingConvention(); - } - } - // Skip number of type arguments if (sigRet->callConv & IMAGE_CEE_CS_CALLCONV_GENERIC) IfFailThrow(sig.GetData(NULL)); @@ -551,11 +515,11 @@ CEEInfo::ConvToJitSig( sigRet->numArgs = (unsigned short) numArgs; - CorElementType type = sig.PeekElemTypeClosed(module, &typeContext); + CorElementType type = sig.PeekElemTypeClosed(module, typeContext); if (!CorTypeInfo::IsPrimitiveType(type)) { - typeHnd = sig.GetTypeHandleThrowing(module, &typeContext); + typeHnd = sig.GetTypeHandleThrowing(module, typeContext); _ASSERTE(!typeHnd.IsNull()); // I believe it doesn't make any diff. if this is @@ -600,8 +564,6 @@ CEEInfo::ConvToJitSig( sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr(); } - _ASSERTE(sigRet->callConv != CORINFO_CALLCONV_UNMANAGED); - // Set computed flags sigRet->flags = sigRetFlags; @@ -1882,15 +1844,17 @@ CEEInfo::findCallSiteSig( } } + SigTypeContext typeContext; + GetTypeContext(context, &typeContext); + CEEInfo::ConvToJitSig( pSig, cbSig, scopeHnd, sigMethTok, - sigRet, - GetMethodFromContext(context), - false, - GetTypeFromContext(context)); + &typeContext, + CONV_TO_JITSIG_FLAGS_NONE, + sigRet); EE_TO_JIT_TRANSITION(); } // CEEInfo::findCallSiteSig @@ -1931,15 +1895,17 @@ CEEInfo::findSig( &pSig)); } + SigTypeContext typeContext; + GetTypeContext(context, &typeContext); + CEEInfo::ConvToJitSig( pSig, cbSig, scopeHnd, sigTok, - sigRet, - GetMethodFromContext(context), - false, - GetTypeFromContext(context)); + &typeContext, + CONV_TO_JITSIG_FLAGS_NONE, + sigRet); EE_TO_JIT_TRANSITION(); } // CEEInfo::findSig @@ -7760,6 +7726,8 @@ getMethodInfoHelper( DWORD cbSig = 0; ftn->GetSig(&pSig, &cbSig); + SigTypeContext context(ftn); + /* Fetch the method signature */ // Type parameters in the signature should be instantiated according to the // class/method/array instantiation of ftnHnd @@ -7768,9 +7736,9 @@ getMethodInfoHelper( cbSig, GetScopeHandle(ftn), mdTokenNil, - &methInfo->args, - ftn, - false); + &context, + CEEInfo::CONV_TO_JITSIG_FLAGS_NONE, + &methInfo->args); // Shared generic or static per-inst methods and shared methods on generic structs // take an extra argument representing their instantiation @@ -7787,9 +7755,9 @@ getMethodInfoHelper( cbLocalSig, GetScopeHandle(ftn), mdTokenNil, - &methInfo->locals, - ftn, - true); + &context, + CEEInfo::CONV_TO_JITSIG_FLAGS_LOCALSIG, + &methInfo->locals); } // getMethodInfoHelper @@ -8622,6 +8590,8 @@ CEEInfo::getMethodSigInternal( DWORD cbSig = 0; ftn->GetSig(&pSig, &cbSig); + SigTypeContext context(ftn, (TypeHandle)owner); + // Type parameters in the signature are instantiated // according to the class/method/array instantiation of ftnHnd and owner CEEInfo::ConvToJitSig( @@ -8629,10 +8599,9 @@ CEEInfo::getMethodSigInternal( cbSig, GetScopeHandle(ftn), mdTokenNil, - sigRet, - ftn, - false, - (TypeHandle)owner); + &context, + CONV_TO_JITSIG_FLAGS_NONE, + sigRet); //@GENERICS: // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation @@ -8921,7 +8890,7 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) return false; } - // For generic interface methods we must have context to + // For generic interface methods we must have context to // safely devirtualize. if (info->context != nullptr) { @@ -9804,10 +9773,149 @@ CorInfoHFAElemType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass) return result; } +namespace +{ + CorInfoCallConvExtension getUnmanagedCallConvForSig(Module* mod, PCCOR_SIGNATURE pSig, DWORD cbSig, bool* pSuppressGCTransition) + { + SigParser parser(pSig, cbSig); + ULONG rawCallConv; + if (FAILED(parser.GetCallingConv(&rawCallConv))) + { + COMPlusThrowHR(COR_E_BADIMAGEFORMAT); + } + switch ((CorCallingConvention)rawCallConv) + { + case IMAGE_CEE_CS_CALLCONV_DEFAULT: + _ASSERTE_MSG(false, "bad callconv"); + return CorInfoCallConvExtension::Managed; + case IMAGE_CEE_CS_CALLCONV_C: + return CorInfoCallConvExtension::C; + case IMAGE_CEE_CS_CALLCONV_STDCALL: + return CorInfoCallConvExtension::Stdcall; + case IMAGE_CEE_CS_CALLCONV_THISCALL: + return CorInfoCallConvExtension::Thiscall; + case IMAGE_CEE_CS_CALLCONV_FASTCALL: + return CorInfoCallConvExtension::Fastcall; + case IMAGE_CEE_CS_CALLCONV_UNMANAGED: + { + CorUnmanagedCallingConvention callConvMaybe; + UINT errorResID; + HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(mod, pSig, cbSig, &callConvMaybe, &errorResID); + if (FAILED(hr)) + COMPlusThrowHR(hr, errorResID); + + if (hr == S_OK) + { + return (CorInfoCallConvExtension)callConvMaybe; + } + else + { + return (CorInfoCallConvExtension)MetaSig::GetDefaultUnmanagedCallingConvention(); + } + } + case IMAGE_CEE_CS_CALLCONV_NATIVEVARARG: + return CorInfoCallConvExtension::C; + default: + _ASSERTE_MSG(false, "bad callconv"); + return CorInfoCallConvExtension::Managed; + } + } + + CorInfoCallConvExtension getUnmanagedCallConvForMethod(MethodDesc* pMD, bool* pSuppressGCTransition) + { + ULONG methodCallConv; + PCCOR_SIGNATURE pSig; + DWORD cbSig; + pMD->GetSig(&pSig, &cbSig); + if (FAILED(SigParser(pSig, cbSig).GetCallingConv(&methodCallConv))) + { + COMPlusThrowHR(COR_E_BADIMAGEFORMAT); + } + + if (methodCallConv == CORINFO_CALLCONV_DEFAULT || methodCallConv == CORINFO_CALLCONV_VARARG) + { + _ASSERTE(pMD->IsNDirect() || pMD->HasUnmanagedCallersOnlyAttribute()); + if (pMD->IsNDirect()) + { + if (pSuppressGCTransition) + { + *pSuppressGCTransition = pMD->ShouldSuppressGCTransition(); + } + + PInvokeStaticSigInfo sigInfo(pMD, PInvokeStaticSigInfo::NO_THROW_ON_ERROR); + switch (sigInfo.GetCallConv()) + { + case pmCallConvCdecl: + return CorInfoCallConvExtension::C; + break; + case pmCallConvStdcall: + return CorInfoCallConvExtension::Stdcall; + break; + case pmCallConvThiscall: + return CorInfoCallConvExtension::Thiscall; + break; + case pmCallConvFastcall: + return CorInfoCallConvExtension::Fastcall; + break; + default: + _ASSERTE_MSG(false, "bad callconv"); + return CorInfoCallConvExtension::Managed; + break; + } + } + else + { +#ifdef CROSSGEN_COMPILE + _ASSERTE_MSG(false, "UnmanagedCallersOnly methods are not supported in crossgen and should be rejected before getting here."); + return CorInfoCallConvExtension::Managed; +#else + CorPinvokeMap unmanagedCallConv; + if (TryGetCallingConventionFromUnmanagedCallersOnly(pMD, &unmanagedCallConv)) + { + if (methodCallConv == IMAGE_CEE_CS_CALLCONV_VARARG) + { + return CorInfoCallConvExtension::C; + } + switch (unmanagedCallConv) + { + case pmCallConvWinapi: + return (CorInfoCallConvExtension)MetaSig::GetDefaultUnmanagedCallingConvention(); + break; + case pmCallConvCdecl: + return CorInfoCallConvExtension::C; + break; + case pmCallConvStdcall: + return CorInfoCallConvExtension::Stdcall; + break; + case pmCallConvThiscall: + return CorInfoCallConvExtension::Thiscall; + break; + case pmCallConvFastcall: + return CorInfoCallConvExtension::Fastcall; + break; + default: + _ASSERTE_MSG(false, "bad callconv"); + break; + } + } + return (CorInfoCallConvExtension)MetaSig::GetDefaultUnmanagedCallingConvention(); +#endif // CROSSGEN_COMPILE + } + } + else + { + return getUnmanagedCallConvForSig(pMD->GetModule(), pSig, cbSig, pSuppressGCTransition); + } + } +} + /*********************************************************************/ - // return the unmanaged calling convention for a PInvoke -CorInfoUnmanagedCallConv CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method) + // return the entry point calling convention for any of the following + // - a P/Invoke + // - a method marked with UnmanagedCallersOnly + // - a function pointer with the CORINFO_CALLCONV_UNMANAGED calling convention. +CorInfoCallConvExtension CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition) { CONTRACTL { THROWS; @@ -9815,48 +9923,28 @@ CorInfoUnmanagedCallConv CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE met MODE_PREEMPTIVE; } CONTRACTL_END; - CorInfoUnmanagedCallConv result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN; + CorInfoCallConvExtension callConv = CorInfoCallConvExtension::Managed; JIT_TO_EE_TRANSITION(); - MethodDesc* pMD = NULL; - pMD = GetMethod(method); - _ASSERTE(pMD->IsNDirect()); - -#ifdef TARGET_X86 - EX_TRY + if (pSuppressGCTransition) { - PInvokeStaticSigInfo sigInfo(pMD, PInvokeStaticSigInfo::NO_THROW_ON_ERROR); + *pSuppressGCTransition = false; + } - switch (sigInfo.GetCallConv()) { - case pmCallConvCdecl: - result = CORINFO_UNMANAGED_CALLCONV_C; - break; - case pmCallConvStdcall: - result = CORINFO_UNMANAGED_CALLCONV_STDCALL; - break; - case pmCallConvThiscall: - result = CORINFO_UNMANAGED_CALLCONV_THISCALL; - break; - default: - result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN; - } + if (method) + { + callConv = getUnmanagedCallConvForMethod(GetMethod(method), pSuppressGCTransition); } - EX_CATCH + else { - result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN; + _ASSERTE(callSiteSig != nullptr); + callConv = getUnmanagedCallConvForSig(GetModule(callSiteSig->scope), callSiteSig->pSig, callSiteSig->cbSig, pSuppressGCTransition); } - EX_END_CATCH(SwallowAllExceptions) -#else // !TARGET_X86 - // - // we have only one calling convention - // - result = CORINFO_UNMANAGED_CALLCONV_STDCALL; -#endif // !TARGET_X86 EE_TO_JIT_TRANSITION(); - return result; + return callConv; } /*********************************************************************/ @@ -11951,7 +12039,7 @@ HRESULT CEEJitInfo::getMethodBlockCounts ( #endif EE_TO_JIT_TRANSITION(); - + return hr; } @@ -12740,7 +12828,7 @@ CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHO #ifdef FEATURE_PGO // Instrument, if - // + // // * We're writing pgo data and we're jitting at Tier0. // * Tiered PGO is enabled and we're jitting at Tier0. // @@ -12764,7 +12852,7 @@ CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHO { flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBOPT); } - + #endif return flags; @@ -13887,7 +13975,7 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, // Verification failures are failfast events DefineFullyQualifiedNameForClassW(); SString fatalErrorString; - fatalErrorString.Printf(W("Verify_TypeLayout '%s' failed to verify type layout"), + fatalErrorString.Printf(W("Verify_TypeLayout '%s' failed to verify type layout"), GetFullyQualifiedNameForClassW(pMT)); #ifdef _DEBUG @@ -13940,7 +14028,7 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, } DWORD actualBaseOffset = 0; - if (!pField->IsStatic() && + if (!pField->IsStatic() && pEnclosingMT->GetParentMethodTable() != NULL && !pEnclosingMT->IsValueType()) { @@ -13954,7 +14042,7 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, SString ssFieldName(SString::Utf8, pField->GetName()); SString fatalErrorString; - fatalErrorString.Printf(W("Verify_FieldOffset '%s.%s' Field offset %d!=%d(actual) || baseOffset %d!=%d(actual)"), + fatalErrorString.Printf(W("Verify_FieldOffset '%s.%s' Field offset %d!=%d(actual) || baseOffset %d!=%d(actual)"), GetFullyQualifiedNameForClassW(pEnclosingMT), ssFieldName.GetUnicode(), fieldOffset, diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 78edf6f3a1d63..8b681c4818e57 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -61,7 +61,6 @@ bool SigInfoFlagsAreValid (CORINFO_SIG_INFO *sig) LIMITED_METHOD_CONTRACT; return !(sig->flags & ~( CORINFO_SIGFLAG_IS_LOCAL_SIG | CORINFO_SIGFLAG_IL_STUB - | CORINFO_SIGFLAG_SUPPRESS_GC_TRANSITION )); } @@ -541,6 +540,12 @@ class CEEInfo : public ICorJitInfo public: + enum ConvToJitSigFlags : int + { + CONV_TO_JITSIG_FLAGS_NONE = 0x0, + CONV_TO_JITSIG_FLAGS_LOCALSIG = 0x1, + }; + //@GENERICS: // The method handle is used to instantiate method and class type parameters // It's also used to determine whether an extra dictionary parameter is required @@ -551,10 +556,9 @@ class CEEInfo : public ICorJitInfo DWORD cbSig, CORINFO_MODULE_HANDLE scopeHnd, mdToken token, - CORINFO_SIG_INFO * sigRet, - MethodDesc * context, - bool localSig, - TypeHandle owner = TypeHandle()); + SigTypeContext* context, + ConvToJitSigFlags flags, + CORINFO_SIG_INFO * sigRet); MethodDesc * GetMethodForSecurity(CORINFO_METHOD_HANDLE callerHandle); diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp index ed6f44e7426ce..1daa37156640c 100644 --- a/src/coreclr/vm/method.cpp +++ b/src/coreclr/vm/method.cpp @@ -5314,12 +5314,6 @@ FARPROC NDirectMethodDesc::FindEntryPointWithMangling(NATIVE_LIBRARY_HANDLE hMod UINT16 numParamBytesMangle = GetStackArgumentSize(); - if (IsStdCallWithRetBuf()) - { - _ASSERTE(numParamBytesMangle >= sizeof(LPVOID)); - numParamBytesMangle -= (UINT16)sizeof(LPVOID); - } - sprintf_s(szProbedEntrypointName + probedEntrypointNameLength, dstbufsize - probedEntrypointNameLength + 1, "@%lu", (ULONG)numParamBytesMangle); pFunc = GetProcAddress(hMod, szProbedEntrypointName); } diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 28c6935212df7..ee1e68567f6ef 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -2963,8 +2963,6 @@ class NDirectMethodDesc : public MethodDesc #if defined(TARGET_X86) // Size of outgoing arguments (on stack). Note that in order to get the @n stdcall name decoration, - // it may be necessary to subtract 4 as the hidden large structure pointer parameter does not count. - // See code:kStdCallWithRetBuf WORD m_cbStackArgumentSize; #endif // defined(TARGET_X86) @@ -3014,9 +3012,6 @@ class NDirectMethodDesc : public MethodDesc kIsQCall = 0x1000, kDefaultDllImportSearchPathsStatus = 0x2000, // either method has custom attribute or not. - - kStdCallWithRetBuf = 0x8000, // Call returns large structure, only valid if kStdCall is also set - }; // Resolve the import to the NDirect target and set it on the NDirectMethodDesc. @@ -3161,13 +3156,6 @@ class NDirectMethodDesc : public MethodDesc return (ndirect.m_DefaultDllImportSearchPathsAttributeValue & 0x2) != 0; } - BOOL IsStdCallWithRetBuf() const - { - LIMITED_METHOD_DAC_CONTRACT; - - return (ndirect.m_wFlags & kStdCallWithRetBuf) != 0; - } - PTR_NDirectWriteableData GetWriteableData() const { LIMITED_METHOD_DAC_CONTRACT; diff --git a/src/coreclr/zap/zapinfo.cpp b/src/coreclr/zap/zapinfo.cpp index 431e57ac06da8..557367c31c844 100644 --- a/src/coreclr/zap/zapinfo.cpp +++ b/src/coreclr/zap/zapinfo.cpp @@ -400,6 +400,13 @@ void ZapInfo::CompileMethod() m_zapper->Info(W("Compiling method %s\n"), m_currentMethodName.GetUnicode()); } + if (GetCompileInfo()->IsUnmanagedCallersOnlyMethod(m_currentMethodHandle)) + { + if (m_zapper->m_pOpt->m_verbose) + m_zapper->Warning(W("ReadyToRun: Methods with UnmanagedCallersOnlyAttribute not implemented\n")); + ThrowHR(E_NOTIMPL); + } + m_currentMethodInfo = CORINFO_METHOD_INFO(); if (!getMethodInfo(m_currentMethodHandle, &m_currentMethodInfo)) { @@ -474,15 +481,6 @@ void ZapInfo::CompileMethod() } #endif -#ifdef TARGET_X86 - if (GetCompileInfo()->IsUnmanagedCallersOnlyMethod(m_currentMethodHandle)) - { - if (m_zapper->m_pOpt->m_verbose) - m_zapper->Warning(W("ReadyToRun: Methods with UnmanagedCallersOnlyAttribute not implemented\n")); - ThrowHR(E_NOTIMPL); - } -#endif // TARGET_X86 - if (m_pImage->m_stats) { m_pImage->m_stats->m_methods++; @@ -2208,7 +2206,7 @@ DWORD FilterNamedIntrinsicMethodAttribs(ZapInfo* pZapInfo, DWORD attribs, CORINF } #else fTreatAsRegularMethodCall |= !fIsPlatformHWIntrinsic && fIsHWIntrinsic; -#endif +#endif if (fIsPlatformHWIntrinsic) { @@ -4032,9 +4030,9 @@ bool ZapInfo::isIntrinsicType(CORINFO_CLASS_HANDLE classHnd) return m_pEEJitInfo->isIntrinsicType(classHnd); } -CorInfoUnmanagedCallConv ZapInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method) +CorInfoCallConvExtension ZapInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig, bool* pSuppressGCTransition) { - return m_pEEJitInfo->getUnmanagedCallConv(method); + return m_pEEJitInfo->getUnmanagedCallConv(method, sig, pSuppressGCTransition); } bool ZapInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, diff --git a/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallTest.cs b/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallTest.cs index 66d40546e91b3..31719e8d7aed8 100644 --- a/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallTest.cs +++ b/src/tests/Interop/PInvoke/Miscellaneous/ThisCall/ThisCallTest.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.Text; using TestLibrary; +using System.Runtime.CompilerServices; unsafe class ThisCallNative { @@ -86,6 +87,10 @@ public static int Main(string[] args) Test4ByteHFAReverse(); Test4ByteNonHFAReverse(); TestEnumReverse(); + Test8ByteHFAUnmanagedCallersOnly(); + Test4ByteHFAUnmanagedCallersOnly(); + Test4ByteNonHFAUnmanagedCallersOnly(); + TestEnumUnmanagedCallersOnly(); } catch (System.Exception ex) { @@ -164,6 +169,38 @@ private static void TestEnumReverse() Assert.AreEqual(c.dummy, result); } + private static void Test8ByteHFAUnmanagedCallersOnly() + { + ThisCallNative.C c = CreateCWithUnmanagedCallersOnlyVTable(2.0f, 3.0f); + ThisCallNative.SizeF result = ThisCallNative.GetSizeFromManaged(&c); + + Assert.AreEqual(c.width, result.width); + Assert.AreEqual(c.height, result.height); + } + + private static void Test4ByteHFAUnmanagedCallersOnly() + { + ThisCallNative.C c = CreateCWithUnmanagedCallersOnlyVTable(2.0f, 3.0f); + ThisCallNative.Width result = ThisCallNative.GetWidthFromManaged(&c); + + Assert.AreEqual(c.width, result.width); + } + + private static void Test4ByteNonHFAUnmanagedCallersOnly() + { + ThisCallNative.C c = CreateCWithUnmanagedCallersOnlyVTable(2.0f, 3.0f); + ThisCallNative.IntWrapper result = ThisCallNative.GetHeightAsIntFromManaged(&c); + + Assert.AreEqual((int)c.height, result.i); + } + + private static void TestEnumUnmanagedCallersOnly() + { + ThisCallNative.C c = CreateCWithUnmanagedCallersOnlyVTable(2.0f, 3.0f); + ThisCallNative.E result = ThisCallNative.GetEFromManaged(&c); + + Assert.AreEqual(c.dummy, result); + } private static ThisCallNative.C CreateCWithManagedVTable(float width, float height) { @@ -176,6 +213,17 @@ private static ThisCallNative.C CreateCWithManagedVTable(float width, float heig }; } + private static ThisCallNative.C CreateCWithUnmanagedCallersOnlyVTable(float width, float height) + { + return new ThisCallNative.C + { + vtable = UnmanagedCallersOnlyVtable, + dummy = ThisCallNative.E.Value, + width = width, + height = height + }; + } + private static ThisCallNative.C.VtableLayout* managedVtable; private static ThisCallNative.C.VtableLayout* ManagedVtable @@ -197,4 +245,56 @@ private static ThisCallNative.C.VtableLayout* ManagedVtable return managedVtable; } } + + private static ThisCallNative.C.VtableLayout* unmanagedCallersOnlyVtable; + + private static ThisCallNative.C.VtableLayout* UnmanagedCallersOnlyVtable + { + get + { + if (unmanagedCallersOnlyVtable == null) + { + unmanagedCallersOnlyVtable = (ThisCallNative.C.VtableLayout*)Marshal.AllocHGlobal(sizeof(ThisCallNative.C.VtableLayout)); + unmanagedCallersOnlyVtable->getSize = (IntPtr)(delegate* unmanaged[Thiscall])&GetSize; + unmanagedCallersOnlyVtable->getWidth = (IntPtr)(delegate* unmanaged[Thiscall])&GetWidth; + unmanagedCallersOnlyVtable->getHeightAsInt = (IntPtr)(delegate* unmanaged[Thiscall])&GetHeightAsInt; + unmanagedCallersOnlyVtable->getE = (IntPtr)(delegate* unmanaged[Thiscall])&GetE; + } + return unmanagedCallersOnlyVtable; + } + } + + [UnmanagedCallersOnly(CallConvs = new [] {typeof(CallConvThiscall)})] + private static ThisCallNative.SizeF GetSize(ThisCallNative.C* c) + { + return new ThisCallNative.SizeF + { + width = c->width, + height = c->height + }; + } + + [UnmanagedCallersOnly(CallConvs = new [] {typeof(CallConvThiscall)})] + private static ThisCallNative.Width GetWidth(ThisCallNative.C* c) + { + return new ThisCallNative.Width + { + width = c->width + }; + } + + [UnmanagedCallersOnly(CallConvs = new [] {typeof(CallConvThiscall)})] + private static ThisCallNative.IntWrapper GetHeightAsInt(ThisCallNative.C* c) + { + return new ThisCallNative.IntWrapper + { + i = (int)c->height + }; + } + + [UnmanagedCallersOnly(CallConvs = new [] {typeof(CallConvThiscall)})] + private static ThisCallNative.E GetE(ThisCallNative.C* c) + { + return c->dummy; + } }