From a7e3ee4f594ea4925bded595cdbd21ba69ab9603 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 8 Jan 2024 15:29:37 -0800 Subject: [PATCH 01/15] Parse CallConvSwift in CoreCLR --- src/coreclr/inc/corhdr.h | 1 + src/coreclr/inc/corinfo.h | 3 ++- src/coreclr/vm/callconvbuilder.cpp | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/coreclr/inc/corhdr.h b/src/coreclr/inc/corhdr.h index 5c645000ce87d6..3f67b33da9162a 100644 --- a/src/coreclr/inc/corhdr.h +++ b/src/coreclr/inc/corhdr.h @@ -1715,6 +1715,7 @@ typedef enum LoadHintEnum #define CMOD_CALLCONV_NAME_STDCALL "CallConvStdcall" #define CMOD_CALLCONV_NAME_THISCALL "CallConvThiscall" #define CMOD_CALLCONV_NAME_FASTCALL "CallConvFastcall" +#define CMOD_CALLCONV_NAME_SWIFT "CallConvSwift" #define CMOD_CALLCONV_NAME_SUPPRESSGCTRANSITION "CallConvSuppressGCTransition" #define CMOD_CALLCONV_NAME_MEMBERFUNCTION "CallConvMemberFunction" diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index e957885418ca7b..7c9db074608a2a 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -772,7 +772,8 @@ enum class CorInfoCallConvExtension // New calling conventions supported with the extensible calling convention encoding go here. CMemberFunction, StdcallMemberFunction, - FastcallMemberFunction + FastcallMemberFunction, + Swift }; #ifdef TARGET_X86 diff --git a/src/coreclr/vm/callconvbuilder.cpp b/src/coreclr/vm/callconvbuilder.cpp index 0ba5934c9f9a7b..20f95f12224105 100644 --- a/src/coreclr/vm/callconvbuilder.cpp +++ b/src/coreclr/vm/callconvbuilder.cpp @@ -53,7 +53,8 @@ namespace BASE_CALL_CONV(CMOD_CALLCONV_NAME_CDECL, C) \ BASE_CALL_CONV(CMOD_CALLCONV_NAME_STDCALL, Stdcall) \ BASE_CALL_CONV(CMOD_CALLCONV_NAME_THISCALL, Thiscall) \ - BASE_CALL_CONV(CMOD_CALLCONV_NAME_FASTCALL, Fastcall) + BASE_CALL_CONV(CMOD_CALLCONV_NAME_FASTCALL, Fastcall) \ + BASE_CALL_CONV(CMOD_CALLCONV_NAME_SWIFT, Swift) #define DECLARE_MOD_CALL_CONVS \ CALL_CONV_MODIFIER(CMOD_CALLCONV_NAME_SUPPRESSGCTRANSITION, CALL_CONV_MOD_SUPPRESSGCTRANSITION) \ @@ -176,6 +177,8 @@ namespace return CorInfoCallConvExtension::FastcallMemberFunction; case CorInfoCallConvExtension::Thiscall: return CorInfoCallConvExtension::Thiscall; + case CorInfoCallConvExtension::Swift: + return CorInfoCallConvExtension::Swift; default: _ASSERTE("Calling convention is not an unmanaged base calling convention."); return baseCallConv; From 8027343ef54964b8b737a727c76eb11c1ce1a20e Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 8 Jan 2024 16:44:03 -0800 Subject: [PATCH 02/15] Disallow structs in CallConvSwift signatures in CoreCLR --- src/coreclr/dlls/mscorrc/mscorrc.rc | 1 + src/coreclr/dlls/mscorrc/resource.h | 1 + src/coreclr/vm/dllimport.cpp | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/src/coreclr/dlls/mscorrc/mscorrc.rc b/src/coreclr/dlls/mscorrc/mscorrc.rc index 0765484c1ee112..abd7bbb51790b1 100644 --- a/src/coreclr/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/dlls/mscorrc/mscorrc.rc @@ -171,6 +171,7 @@ BEGIN IDS_EE_NDIRECT_DISABLEDMARSHAL_LCID "The LCIDConversionAttribute is not supported when runtime marshalling is disabled." IDS_EE_NDIRECT_DISABLEDMARSHAL_PRESERVESIG "Setting PreserveSig to false for a P/Invoke is not supported when runtime marshalling is disabled." IDS_EE_NDIRECT_DISABLEDMARSHAL_VARARGS "Using a variable argument list in a P/Invoke is not supported when runtime marshalling is disabled." + IDS_EE_NDIRECT_SWIFT_VALUETYPE "Passing non-primitive value types to a P/Invoke with the Swift calling convention is unsupported." IDS_EE_CLASS_CONSTRAINTS_VIOLATION "GenericArguments[%1], '%2', on '%3' violates the constraint of type parameter '%4'." IDS_EE_METHOD_CONSTRAINTS_VIOLATION "Method %1.%2: type argument '%3' violates the constraint of type parameter '%4'." IDS_EE_NOSYNCHRONIZED "Synchronized attribute cannot be used with this method type." diff --git a/src/coreclr/dlls/mscorrc/resource.h b/src/coreclr/dlls/mscorrc/resource.h index 1a1466b854a0a8..703de89cdb132c 100644 --- a/src/coreclr/dlls/mscorrc/resource.h +++ b/src/coreclr/dlls/mscorrc/resource.h @@ -567,3 +567,4 @@ #define IDS_EE_NDIRECT_DISABLEDMARSHAL_LCID 0x264E #define IDS_EE_NDIRECT_DISABLEDMARSHAL_PRESERVESIG 0x264F #define IDS_EE_NDIRECT_DISABLEDMARSHAL_VARARGS 0x2650 +#define IDS_EE_NDIRECT_SWIFT_VALUETYPE 0x2651 diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 5dbea392d6b2a4..9ab06734ec60cd 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -3343,6 +3343,15 @@ BOOL NDirect::MarshalingRequired( return TRUE; } + if (callConv == CorInfoCallConvExtension::Swift && !hndArgType.IsEnum()) + { + // Swift has a very complicated struct lowering algorithm that would be prohibitively expensive to implement in RyuJIT. + // Instead, we implement it in the projection layer. The runtime and JIT should only see pre-lowered, LLVM-IR-equivalent + // signatures. + // Require marshalling here so we can easily throw an exception during IL Stub generation. + return TRUE; + } + if (i > 0) { const bool isValueType = true; @@ -4336,6 +4345,24 @@ static void CreateNDirectStubAccessMetadata( COMPlusThrow(kInvalidProgramException, VLDTR_E_FMD_PINVOKENOTSTATIC); } } + + if (unmgdCallConv == CorInfoCallConvExtension::Swift) + { + // Swift has a very complicated lowering algorithm for structs. The .NET JIT does not support it, + // so throw an exception here if we encounter a signature that uses any value types. + if (msig.GetReturnTypeNormalized() == ELEMENT_TYPE_VALUETYPE) + { + COMPlusThrow(kNotSupportedException, IDS_EE_NDIRECT_SWIFT_VALUETYPE); + } + + for (int i = 0; i < (*pNumArgs); i++) + { + if (msig.NextArgNormalized() == ELEMENT_TYPE_VALUETYPE) + { + COMPlusThrow(kNotSupportedException, IDS_EE_NDIRECT_SWIFT_VALUETYPE); + } + } + } } namespace From e056d69de7cb45773cf2afc1f416e23de32ec171 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 8 Jan 2024 16:48:39 -0800 Subject: [PATCH 03/15] Parse the Swift calling convention in the managed type system --- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 3 +++ .../Common/TypeSystem/Interop/UnmanagedCallingConventions.cs | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index cadc58a7014516..1b38b50cf30ab8 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1590,6 +1590,9 @@ private static CorInfoCallConvExtension ToCorInfoCallConvExtension(UnmanagedCall case UnmanagedCallingConventions.Fastcall: result = CorInfoCallConvExtension.Fastcall; break; + case UnmanagedCallingConventions.Swift: + result = CorInfoCallConvExtension.Swift; + break; default: ThrowHelper.ThrowInvalidProgramException(); result = CorInfoCallConvExtension.Managed; // unreachable diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs b/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs index 5ba886b68c265b..5db9fb87cc7ee2 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs @@ -40,7 +40,7 @@ public enum UnmanagedCallingConventions // Unmanaged = 0x00000009, - this one is always translated to cdecl/stdcall // The ones higher than 0xF are defined by the type system - // There are no such calling conventions yet. + Swift = 0x00000010 } public static class CallingConventionExtensions @@ -181,6 +181,7 @@ private static UnmanagedCallingConventions AccumulateCallingConventions(Unmanage "CallConvThiscall" => UnmanagedCallingConventions.Thiscall, "CallConvSuppressGCTransition" => UnmanagedCallingConventions.IsSuppressGcTransition, "CallConvMemberFunction" => UnmanagedCallingConventions.IsMemberFunction, + "CallConvSwift" => UnmanagedCallingConventions.Swift, _ => null }; From d667148ed0903d20252f902da8edd7357c00037c Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 8 Jan 2024 17:26:47 -0800 Subject: [PATCH 04/15] Add same validation as in CoreCLR in the correct places in crossgen2 and ILC --- .../TypeSystem/IL/Stubs/PInvokeILEmitter.cs | 21 ++++++++++++ .../Interop/UnmanagedCallingConventions.cs | 21 ++++++++++++ .../Interop/IL/Marshaller.ReadyToRun.cs | 34 +++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs index e9d7adc4ad0e72..57466742a9ccfd 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs @@ -20,6 +20,7 @@ public struct PInvokeILEmitter private readonly PInvokeILEmitterConfiguration _pInvokeILEmitterConfiguration; private readonly PInvokeMetadata _pInvokeMetadata; private readonly PInvokeFlags _flags; + private readonly UnmanagedCallingConventions _callingConvention; private readonly InteropStateManager _interopStateManager; private PInvokeILEmitter(MethodDesc targetMethod, PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration, InteropStateManager interopStateManager) @@ -38,10 +39,17 @@ private PInvokeILEmitter(MethodDesc targetMethod, PInvokeILEmitterConfiguration if (_targetMethod is DelegateMarshallingMethodThunk delegateMethod) { _flags = ((EcmaType)delegateMethod.DelegateType.GetTypeDefinition()).GetDelegatePInvokeFlags(); + _callingConvention = delegateMethod.DelegateType.GetDelegateCallingConventions(); + } + else if (targetMethod is CalliMarshallingMethodThunk calliMethod) + { + _flags = _pInvokeMetadata.Flags; + _callingConvention = calliMethod.TargetSignature.GetStandaloneMethodSignatureCallingConventions(); } else { _flags = _pInvokeMetadata.Flags; + _callingConvention = _targetMethod.GetPInvokeMethodCallingConventions(); } _marshallers = InitializeMarshallers(targetMethod, interopStateManager, _flags); } @@ -380,6 +388,19 @@ private PInvokeILStubMethodIL EmitIL() if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "LCIDConversionAttribute")) throw new NotSupportedException(); + if (_callingConvention == UnmanagedCallingConventions.Swift) + { + // Swift calling convention has strict rules about value types that the JIT does not implement. + // Throw an exception if we encounter a value type that is not a primitive (and as such needs this lowering logic applied). + foreach (var marshaller in _marshallers) + { + if (marshaller.ManagedType is { IsValueType: true, IsEnum: false, IsPrimitive: false }) + { + throw new NotSupportedException(); + } + } + } + PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream marshallingCodestream = pInvokeILCodeStreams.MarshallingCodeStream; diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs b/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs index 5db9fb87cc7ee2..d0d4aa172fc81d 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs @@ -135,6 +135,27 @@ public static UnmanagedCallingConventions GetPInvokeMethodCallingConventions(thi return result; } + public static UnmanagedCallingConventions GetDelegateCallingConventions(this TypeDesc delegateType) + { + Debug.Assert(delegateType.IsDelegate); + + if (delegateType is not EcmaType ecmaDelegate) + { + return GetPlatformDefaultUnmanagedCallingConvention(delegateType.Context); + } + + MethodSignatureFlags unmanagedCallConv = ecmaDelegate.GetDelegatePInvokeFlags().UnmanagedCallingConvention; + if (unmanagedCallConv != MethodSignatureFlags.None) + { + Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionCdecl == (int)UnmanagedCallingConventions.Cdecl + && (int)MethodSignatureFlags.UnmanagedCallingConventionStdCall == (int)UnmanagedCallingConventions.Stdcall + && (int)MethodSignatureFlags.UnmanagedCallingConventionThisCall == (int)UnmanagedCallingConventions.Thiscall); + return (UnmanagedCallingConventions)unmanagedCallConv; + } + + return GetPlatformDefaultUnmanagedCallingConvention(delegateType.Context); + } + private static UnmanagedCallingConventions GetUnmanagedCallingConventionFromAttribute(CustomAttributeValue attributeWithCallConvsArray, TypeSystemContext context) { ImmutableArray> callConvArray = default; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs index 33fd2eb6fba480..7c853b0b816155 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs @@ -120,6 +120,23 @@ public static bool IsMarshallingRequired(MethodDesc targetMethod) if (MarshalHelpers.ShouldCheckForPendingException(targetMethod.Context.Target, metadata)) return true; + if (targetMethod.GetPInvokeMethodCallingConventions() == UnmanagedCallingConventions.Swift) + { + // Swift calling convention has strict rules about value types that the JIT does not implement. + // Skip stub generation of Swift methods with value types to allow an exception at runtime. + if (targetMethod.Signature.ReturnType is { IsValueType: true, IsEnum: false, IsPrimitive: false }) + { + return true; + } + foreach (var param in targetMethod.Signature) + { + if (param is { IsValueType: true, IsEnum: false, IsPrimitive: false }) + { + return true; + } + } + } + var marshallers = GetMarshallersForMethod(targetMethod); for (int i = 0; i < marshallers.Length; i++) { @@ -132,6 +149,23 @@ public static bool IsMarshallingRequired(MethodDesc targetMethod) public static bool IsMarshallingRequired(MethodSignature methodSig, ParameterMetadata[] paramMetadata, ModuleDesc moduleContext) { + if (methodSig.GetStandaloneMethodSignatureCallingConventions() == UnmanagedCallingConventions.Swift) + { + // Swift calling convention has strict rules about value types that the JIT does not implement. + // Skip stub generation of Swift methods with value types to allow an exception at runtime. + if (methodSig.ReturnType is { IsValueType: true, IsEnum: false, IsPrimitive: false }) + { + return true; + } + foreach (var param in methodSig) + { + if (param is { IsValueType: true, IsEnum: false, IsPrimitive: false }) + { + return true; + } + } + } + Marshaller[] marshallers = GetMarshallersForSignature(methodSig, paramMetadata, moduleContext); for (int i = 0; i < marshallers.Length; i++) { From db1abd02f50c23a6600d4b761d704a57fdc75ea7 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 19 Jan 2024 14:31:48 -0800 Subject: [PATCH 05/15] Update managed type system to check for vector types and allow them --- .../Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs | 3 ++- .../Interop/IL/Marshaller.ReadyToRun.cs | 14 ++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs index 57466742a9ccfd..2dfab275675042 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs @@ -394,7 +394,8 @@ private PInvokeILStubMethodIL EmitIL() // Throw an exception if we encounter a value type that is not a primitive (and as such needs this lowering logic applied). foreach (var marshaller in _marshallers) { - if (marshaller.ManagedType is { IsValueType: true, IsEnum: false, IsPrimitive: false }) + if (marshaller.ManagedType is DefType { IsValueType: true, IsEnum: false, IsPrimitive: false } paramType + && !VectorFieldLayoutAlgorithm.IsVectorType(paramType)) { throw new NotSupportedException(); } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs index 7c853b0b816155..6f4a838aba3e49 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs @@ -124,13 +124,10 @@ public static bool IsMarshallingRequired(MethodDesc targetMethod) { // Swift calling convention has strict rules about value types that the JIT does not implement. // Skip stub generation of Swift methods with value types to allow an exception at runtime. - if (targetMethod.Signature.ReturnType is { IsValueType: true, IsEnum: false, IsPrimitive: false }) - { - return true; - } foreach (var param in targetMethod.Signature) { - if (param is { IsValueType: true, IsEnum: false, IsPrimitive: false }) + if (param is DefType { IsValueType: true, IsEnum: false, IsPrimitive: false } defType + && !VectorFieldLayoutAlgorithm.IsVectorType(paramType)) { return true; } @@ -153,13 +150,10 @@ public static bool IsMarshallingRequired(MethodSignature methodSig, ParameterMet { // Swift calling convention has strict rules about value types that the JIT does not implement. // Skip stub generation of Swift methods with value types to allow an exception at runtime. - if (methodSig.ReturnType is { IsValueType: true, IsEnum: false, IsPrimitive: false }) - { - return true; - } foreach (var param in methodSig) { - if (param is { IsValueType: true, IsEnum: false, IsPrimitive: false }) + if (param is DefType { IsValueType: true, IsEnum: false, IsPrimitive: false } defType + && !VectorFieldLayoutAlgorithm.IsVectorType(paramType)) { return true; } From 9b642c075d3ce498af554e3e42ba475fce9e6740 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 19 Jan 2024 15:01:01 -0800 Subject: [PATCH 06/15] Mark Swift register types as Intrinsic --- .../src/System/Runtime/InteropServices/Swift/SwiftTypes.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftTypes.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftTypes.cs index a07be15ad44cac..13803374073b81 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftTypes.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Swift/SwiftTypes.cs @@ -1,5 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.CompilerServices; namespace System.Runtime.InteropServices.Swift { @@ -19,7 +20,8 @@ namespace System.Runtime.InteropServices.Swift /// /// /// - [CLSCompliantAttribute(false)] + [CLSCompliant(false)] + [Intrinsic] public readonly unsafe struct SwiftSelf { /// @@ -52,7 +54,8 @@ public SwiftSelf(void* value) /// /// /// - [CLSCompliantAttribute(false)] + [CLSCompliant(false)] + [Intrinsic] public readonly unsafe struct SwiftError { /// From ebe34e086a35ee727a673fd4e1c7edab135ce6c1 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 19 Jan 2024 15:40:24 -0800 Subject: [PATCH 07/15] Allow vector types and SwiftSelf as parameter types for CallConvSwift signatures --- .../tools/Common/JitInterface/CorInfoTypes.cs | 3 +- .../TypeSystem/IL/Stubs/PInvokeILEmitter.cs | 4 +- .../TypeSystem/Interop/IL/MarshalHelpers.cs | 19 ++++++++ .../Interop/IL/Marshaller.ReadyToRun.cs | 8 ++-- src/coreclr/vm/dllimport.cpp | 44 ++++++++++++++++--- 5 files changed, 65 insertions(+), 13 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 394a7a4bbac91b..00414e6192d492 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -392,7 +392,8 @@ public enum CorInfoCallConvExtension // New calling conventions supported with the extensible calling convention encoding go here. CMemberFunction, StdcallMemberFunction, - FastcallMemberFunction + FastcallMemberFunction, + Swift } public enum CORINFO_CALLINFO_FLAGS diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs index 2dfab275675042..438881ebae8ba2 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs @@ -394,8 +394,8 @@ private PInvokeILStubMethodIL EmitIL() // Throw an exception if we encounter a value type that is not a primitive (and as such needs this lowering logic applied). foreach (var marshaller in _marshallers) { - if (marshaller.ManagedType is DefType { IsValueType: true, IsEnum: false, IsPrimitive: false } paramType - && !VectorFieldLayoutAlgorithm.IsVectorType(paramType)) + if (marshaller.ManagedType is { IsValueType: true, IsEnum: false, IsPrimitive: false } param + && !MarshalHelpers.IsSwiftIntrinsicValueType(param)) { throw new NotSupportedException(); } diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs index 7b0cf61350ab7d..d17e65ad5f2d34 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs @@ -4,6 +4,7 @@ using System; using Debug = System.Diagnostics.Debug; using System.Runtime.InteropServices.ObjectiveC; +using ILCompiler; using Internal.TypeSystem.Ecma; namespace Internal.TypeSystem.Interop @@ -971,5 +972,23 @@ public static bool IsRuntimeMarshallingEnabled(ModuleDesc module) { return module.Assembly is not EcmaAssembly assembly || !assembly.HasAssemblyCustomAttribute("System.Runtime.CompilerServices", "DisableRuntimeMarshallingAttribute"); } + + public static bool IsSwiftIntrinsicValueType(TypeDesc type) + { + Debug.Assert(type.IsValueType && !type.IsPrimitive && !type.IsEnum); + if (!type.IsIntrinsic) + return false; + + if (type is not DefType defType) + return false; + + if (VectorFieldLayoutAlgorithm.IsVectorType(defType)) + return true; + + if (defType is { Namespace: "System.Runtime.InteropServices.Swift", Name: "SwiftSelf" }) + return true; + + return false; + } } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs index 6f4a838aba3e49..700e4cede98946 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs @@ -126,8 +126,8 @@ public static bool IsMarshallingRequired(MethodDesc targetMethod) // Skip stub generation of Swift methods with value types to allow an exception at runtime. foreach (var param in targetMethod.Signature) { - if (param is DefType { IsValueType: true, IsEnum: false, IsPrimitive: false } defType - && !VectorFieldLayoutAlgorithm.IsVectorType(paramType)) + if (param is { IsValueType: true, IsEnum: false, IsPrimitive: false } + && !MarshalHelpers.IsSwiftIntrinsicValueType(param)) { return true; } @@ -152,8 +152,8 @@ public static bool IsMarshallingRequired(MethodSignature methodSig, ParameterMet // Skip stub generation of Swift methods with value types to allow an exception at runtime. foreach (var param in methodSig) { - if (param is DefType { IsValueType: true, IsEnum: false, IsPrimitive: false } defType - && !VectorFieldLayoutAlgorithm.IsVectorType(paramType)) + if (param is { IsValueType: true, IsEnum: false, IsPrimitive: false } + && !MarshalHelpers.IsSwiftIntrinsicValueType(param)) { return true; } diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 9ab06734ec60cd..3a30adf12f96ed 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -3167,6 +3167,40 @@ HRESULT NDirect::HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken t return S_FALSE; } +namespace +{ + bool IsSwiftIntrinsicValueType(TypeHandle hnd) + { + STANDARD_VM_CONTRACT; + + _ASSERTE(hnd.IsValueType()); + MethodTable* pMT = hnd.GetMethodTable(); + if (!pMT->IsIntrinsicType()) + return false; + + LPCUTF8 namespaceName; + LPCUTF8 className = pMT->GetFullyQualifiedNameInfo(&namespaceName); + + // We treat the .NET vector types as projections of the Swift SIMD intrinsic types. + if ((strcmp(className, "Vector512`1") == 0) || (strcmp(className, "Vector256`1") == 0) || + (strcmp(className, "Vector128`1") == 0) || (strcmp(className, "Vector64`1") == 0)) + { + _ASSERTE(strcmp(namespaceName, "System.Runtime.Intrinsics") == 0); + return true; + } + + // The SwiftSelf type is an intrinsic type that represents the Swift self register. + if (strcmp(className, "SwiftSelf") == 0) + { + _ASSERTE(strcmp(namespaceName, "System.Runtime.InteropServices.Swift") == 0); + return true; + } + + // We don't need to treat the SwiftError type as an intrinsic here as it should always be passed + // as a SwiftError* parameter. + return false; + } +} // Either MD or signature & module must be given. /*static*/ @@ -3349,7 +3383,7 @@ BOOL NDirect::MarshalingRequired( // Instead, we implement it in the projection layer. The runtime and JIT should only see pre-lowered, LLVM-IR-equivalent // signatures. // Require marshalling here so we can easily throw an exception during IL Stub generation. - return TRUE; + return !IsSwiftIntrinsicValueType(hndArgType); } if (i > 0) @@ -4350,14 +4384,12 @@ static void CreateNDirectStubAccessMetadata( { // Swift has a very complicated lowering algorithm for structs. The .NET JIT does not support it, // so throw an exception here if we encounter a signature that uses any value types. - if (msig.GetReturnTypeNormalized() == ELEMENT_TYPE_VALUETYPE) - { - COMPlusThrow(kNotSupportedException, IDS_EE_NDIRECT_SWIFT_VALUETYPE); - } for (int i = 0; i < (*pNumArgs); i++) { - if (msig.NextArgNormalized() == ELEMENT_TYPE_VALUETYPE) + TypeHandle hnd; + if (msig.NextArgNormalized(&hnd) == ELEMENT_TYPE_VALUETYPE + && !IsSwiftIntrinsicValueType(hnd)) { COMPlusThrow(kNotSupportedException, IDS_EE_NDIRECT_SWIFT_VALUETYPE); } From e873f64862c6772cdf366da354015ae7eea38c91 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 22 Jan 2024 15:27:07 -0800 Subject: [PATCH 08/15] Make new overload of IsMarshallingRequired for UCO scenarios (where the calling convention isn't in the method signature) --- .../tools/Common/JitInterface/CorInfoImpl.cs | 2 +- .../Interop/IL/Marshaller.ReadyToRun.cs | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 1b38b50cf30ab8..c3f59cff76d24b 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -4102,7 +4102,7 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) #if READYTORUN // TODO: enable this check in full AOT - if (Marshaller.IsMarshallingRequired(this.MethodBeingCompiled.Signature, Array.Empty(), ((MetadataType)this.MethodBeingCompiled.OwningType).Module)) // Only blittable arguments + if (Marshaller.IsMarshallingRequired(this.MethodBeingCompiled.Signature, ((MetadataType)this.MethodBeingCompiled.OwningType).Module, this.MethodBeingCompiled.GetUnmanagedCallersOnlyMethodCallingConventions())) // Only blittable arguments { ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramNonBlittableTypes, this.MethodBeingCompiled); } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs index 700e4cede98946..32c5a8d0880b02 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs @@ -144,6 +144,32 @@ public static bool IsMarshallingRequired(MethodDesc targetMethod) return false; } + public static bool IsMarshallingRequired(MethodSignature methodSig, ModuleDesc moduleContext, UnmanagedCallingConventions callingConvention) + { + if (callingConvention == UnmanagedCallingConventions.Swift) + { + // Swift calling convention has strict rules about value types that the JIT does not implement. + // Skip stub generation of Swift methods with value types to allow an exception at runtime. + foreach (var param in methodSig) + { + if (param is { IsValueType: true, IsEnum: false, IsPrimitive: false } + && !MarshalHelpers.IsSwiftIntrinsicValueType(param)) + { + return true; + } + } + } + + Marshaller[] marshallers = GetMarshallersForSignature(methodSig, Array.Empty(), moduleContext); + for (int i = 0; i < marshallers.Length; i++) + { + if (marshallers[i].IsMarshallingRequired()) + return true; + } + + return false; + } + public static bool IsMarshallingRequired(MethodSignature methodSig, ParameterMetadata[] paramMetadata, ModuleDesc moduleContext) { if (methodSig.GetStandaloneMethodSignatureCallingConventions() == UnmanagedCallingConventions.Swift) From de1f23a6ecd818488b9da5d6be104cb06095de0f Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 23 Jan 2024 11:20:39 -0800 Subject: [PATCH 09/15] Qualify name --- .../ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs index 32c5a8d0880b02..37ae2a6f6788c3 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs @@ -160,7 +160,7 @@ public static bool IsMarshallingRequired(MethodSignature methodSig, ModuleDesc m } } - Marshaller[] marshallers = GetMarshallersForSignature(methodSig, Array.Empty(), moduleContext); + Marshaller[] marshallers = GetMarshallersForSignature(methodSig, System.Array.Empty(), moduleContext); for (int i = 0; i < marshallers.Length; i++) { if (marshallers[i].IsMarshallingRequired()) From 2ac4812e652bca9ce943ede8d3f6de641cc286b5 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 25 Jan 2024 13:34:39 -0800 Subject: [PATCH 10/15] Remove struct blocking as we will not block structs any more as the RyuJIT and the type systems will handle lowering --- .../TypeSystem/IL/Stubs/PInvokeILEmitter.cs | 22 ------- .../TypeSystem/Interop/IL/MarshalHelpers.cs | 18 ------ .../Interop/IL/Marshaller.ReadyToRun.cs | 42 ------------- src/coreclr/vm/dllimport.cpp | 60 ------------------- 4 files changed, 142 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs index 438881ebae8ba2..e9d7adc4ad0e72 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/PInvokeILEmitter.cs @@ -20,7 +20,6 @@ public struct PInvokeILEmitter private readonly PInvokeILEmitterConfiguration _pInvokeILEmitterConfiguration; private readonly PInvokeMetadata _pInvokeMetadata; private readonly PInvokeFlags _flags; - private readonly UnmanagedCallingConventions _callingConvention; private readonly InteropStateManager _interopStateManager; private PInvokeILEmitter(MethodDesc targetMethod, PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration, InteropStateManager interopStateManager) @@ -39,17 +38,10 @@ private PInvokeILEmitter(MethodDesc targetMethod, PInvokeILEmitterConfiguration if (_targetMethod is DelegateMarshallingMethodThunk delegateMethod) { _flags = ((EcmaType)delegateMethod.DelegateType.GetTypeDefinition()).GetDelegatePInvokeFlags(); - _callingConvention = delegateMethod.DelegateType.GetDelegateCallingConventions(); - } - else if (targetMethod is CalliMarshallingMethodThunk calliMethod) - { - _flags = _pInvokeMetadata.Flags; - _callingConvention = calliMethod.TargetSignature.GetStandaloneMethodSignatureCallingConventions(); } else { _flags = _pInvokeMetadata.Flags; - _callingConvention = _targetMethod.GetPInvokeMethodCallingConventions(); } _marshallers = InitializeMarshallers(targetMethod, interopStateManager, _flags); } @@ -388,20 +380,6 @@ private PInvokeILStubMethodIL EmitIL() if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "LCIDConversionAttribute")) throw new NotSupportedException(); - if (_callingConvention == UnmanagedCallingConventions.Swift) - { - // Swift calling convention has strict rules about value types that the JIT does not implement. - // Throw an exception if we encounter a value type that is not a primitive (and as such needs this lowering logic applied). - foreach (var marshaller in _marshallers) - { - if (marshaller.ManagedType is { IsValueType: true, IsEnum: false, IsPrimitive: false } param - && !MarshalHelpers.IsSwiftIntrinsicValueType(param)) - { - throw new NotSupportedException(); - } - } - } - PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream marshallingCodestream = pInvokeILCodeStreams.MarshallingCodeStream; diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs index d17e65ad5f2d34..92286ad9563ee4 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs @@ -972,23 +972,5 @@ public static bool IsRuntimeMarshallingEnabled(ModuleDesc module) { return module.Assembly is not EcmaAssembly assembly || !assembly.HasAssemblyCustomAttribute("System.Runtime.CompilerServices", "DisableRuntimeMarshallingAttribute"); } - - public static bool IsSwiftIntrinsicValueType(TypeDesc type) - { - Debug.Assert(type.IsValueType && !type.IsPrimitive && !type.IsEnum); - if (!type.IsIntrinsic) - return false; - - if (type is not DefType defType) - return false; - - if (VectorFieldLayoutAlgorithm.IsVectorType(defType)) - return true; - - if (defType is { Namespace: "System.Runtime.InteropServices.Swift", Name: "SwiftSelf" }) - return true; - - return false; - } } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs index 32c5a8d0880b02..98a0f38d50c6cd 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Interop/IL/Marshaller.ReadyToRun.cs @@ -120,20 +120,6 @@ public static bool IsMarshallingRequired(MethodDesc targetMethod) if (MarshalHelpers.ShouldCheckForPendingException(targetMethod.Context.Target, metadata)) return true; - if (targetMethod.GetPInvokeMethodCallingConventions() == UnmanagedCallingConventions.Swift) - { - // Swift calling convention has strict rules about value types that the JIT does not implement. - // Skip stub generation of Swift methods with value types to allow an exception at runtime. - foreach (var param in targetMethod.Signature) - { - if (param is { IsValueType: true, IsEnum: false, IsPrimitive: false } - && !MarshalHelpers.IsSwiftIntrinsicValueType(param)) - { - return true; - } - } - } - var marshallers = GetMarshallersForMethod(targetMethod); for (int i = 0; i < marshallers.Length; i++) { @@ -146,20 +132,6 @@ public static bool IsMarshallingRequired(MethodDesc targetMethod) public static bool IsMarshallingRequired(MethodSignature methodSig, ModuleDesc moduleContext, UnmanagedCallingConventions callingConvention) { - if (callingConvention == UnmanagedCallingConventions.Swift) - { - // Swift calling convention has strict rules about value types that the JIT does not implement. - // Skip stub generation of Swift methods with value types to allow an exception at runtime. - foreach (var param in methodSig) - { - if (param is { IsValueType: true, IsEnum: false, IsPrimitive: false } - && !MarshalHelpers.IsSwiftIntrinsicValueType(param)) - { - return true; - } - } - } - Marshaller[] marshallers = GetMarshallersForSignature(methodSig, Array.Empty(), moduleContext); for (int i = 0; i < marshallers.Length; i++) { @@ -172,20 +144,6 @@ public static bool IsMarshallingRequired(MethodSignature methodSig, ModuleDesc m public static bool IsMarshallingRequired(MethodSignature methodSig, ParameterMetadata[] paramMetadata, ModuleDesc moduleContext) { - if (methodSig.GetStandaloneMethodSignatureCallingConventions() == UnmanagedCallingConventions.Swift) - { - // Swift calling convention has strict rules about value types that the JIT does not implement. - // Skip stub generation of Swift methods with value types to allow an exception at runtime. - foreach (var param in methodSig) - { - if (param is { IsValueType: true, IsEnum: false, IsPrimitive: false } - && !MarshalHelpers.IsSwiftIntrinsicValueType(param)) - { - return true; - } - } - } - Marshaller[] marshallers = GetMarshallersForSignature(methodSig, paramMetadata, moduleContext); for (int i = 0; i < marshallers.Length; i++) { diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 3a30adf12f96ed..c7084060ce7d71 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -3167,41 +3167,6 @@ HRESULT NDirect::HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken t return S_FALSE; } -namespace -{ - bool IsSwiftIntrinsicValueType(TypeHandle hnd) - { - STANDARD_VM_CONTRACT; - - _ASSERTE(hnd.IsValueType()); - MethodTable* pMT = hnd.GetMethodTable(); - if (!pMT->IsIntrinsicType()) - return false; - - LPCUTF8 namespaceName; - LPCUTF8 className = pMT->GetFullyQualifiedNameInfo(&namespaceName); - - // We treat the .NET vector types as projections of the Swift SIMD intrinsic types. - if ((strcmp(className, "Vector512`1") == 0) || (strcmp(className, "Vector256`1") == 0) || - (strcmp(className, "Vector128`1") == 0) || (strcmp(className, "Vector64`1") == 0)) - { - _ASSERTE(strcmp(namespaceName, "System.Runtime.Intrinsics") == 0); - return true; - } - - // The SwiftSelf type is an intrinsic type that represents the Swift self register. - if (strcmp(className, "SwiftSelf") == 0) - { - _ASSERTE(strcmp(namespaceName, "System.Runtime.InteropServices.Swift") == 0); - return true; - } - - // We don't need to treat the SwiftError type as an intrinsic here as it should always be passed - // as a SwiftError* parameter. - return false; - } -} - // Either MD or signature & module must be given. /*static*/ BOOL NDirect::MarshalingRequired( @@ -3377,15 +3342,6 @@ BOOL NDirect::MarshalingRequired( return TRUE; } - if (callConv == CorInfoCallConvExtension::Swift && !hndArgType.IsEnum()) - { - // Swift has a very complicated struct lowering algorithm that would be prohibitively expensive to implement in RyuJIT. - // Instead, we implement it in the projection layer. The runtime and JIT should only see pre-lowered, LLVM-IR-equivalent - // signatures. - // Require marshalling here so we can easily throw an exception during IL Stub generation. - return !IsSwiftIntrinsicValueType(hndArgType); - } - if (i > 0) { const bool isValueType = true; @@ -4379,22 +4335,6 @@ static void CreateNDirectStubAccessMetadata( COMPlusThrow(kInvalidProgramException, VLDTR_E_FMD_PINVOKENOTSTATIC); } } - - if (unmgdCallConv == CorInfoCallConvExtension::Swift) - { - // Swift has a very complicated lowering algorithm for structs. The .NET JIT does not support it, - // so throw an exception here if we encounter a signature that uses any value types. - - for (int i = 0; i < (*pNumArgs); i++) - { - TypeHandle hnd; - if (msig.NextArgNormalized(&hnd) == ELEMENT_TYPE_VALUETYPE - && !IsSwiftIntrinsicValueType(hnd)) - { - COMPlusThrow(kNotSupportedException, IDS_EE_NDIRECT_SWIFT_VALUETYPE); - } - } - } } namespace From 0e9934bce5032c378169abeb87d766c6e10a1af0 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 25 Jan 2024 13:37:01 -0800 Subject: [PATCH 11/15] Remove now-unused error message --- src/coreclr/dlls/mscorrc/mscorrc.rc | 1 - src/coreclr/dlls/mscorrc/resource.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/coreclr/dlls/mscorrc/mscorrc.rc b/src/coreclr/dlls/mscorrc/mscorrc.rc index abd7bbb51790b1..0765484c1ee112 100644 --- a/src/coreclr/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/dlls/mscorrc/mscorrc.rc @@ -171,7 +171,6 @@ BEGIN IDS_EE_NDIRECT_DISABLEDMARSHAL_LCID "The LCIDConversionAttribute is not supported when runtime marshalling is disabled." IDS_EE_NDIRECT_DISABLEDMARSHAL_PRESERVESIG "Setting PreserveSig to false for a P/Invoke is not supported when runtime marshalling is disabled." IDS_EE_NDIRECT_DISABLEDMARSHAL_VARARGS "Using a variable argument list in a P/Invoke is not supported when runtime marshalling is disabled." - IDS_EE_NDIRECT_SWIFT_VALUETYPE "Passing non-primitive value types to a P/Invoke with the Swift calling convention is unsupported." IDS_EE_CLASS_CONSTRAINTS_VIOLATION "GenericArguments[%1], '%2', on '%3' violates the constraint of type parameter '%4'." IDS_EE_METHOD_CONSTRAINTS_VIOLATION "Method %1.%2: type argument '%3' violates the constraint of type parameter '%4'." IDS_EE_NOSYNCHRONIZED "Synchronized attribute cannot be used with this method type." diff --git a/src/coreclr/dlls/mscorrc/resource.h b/src/coreclr/dlls/mscorrc/resource.h index 703de89cdb132c..1a1466b854a0a8 100644 --- a/src/coreclr/dlls/mscorrc/resource.h +++ b/src/coreclr/dlls/mscorrc/resource.h @@ -567,4 +567,3 @@ #define IDS_EE_NDIRECT_DISABLEDMARSHAL_LCID 0x264E #define IDS_EE_NDIRECT_DISABLEDMARSHAL_PRESERVESIG 0x264F #define IDS_EE_NDIRECT_DISABLEDMARSHAL_VARARGS 0x2650 -#define IDS_EE_NDIRECT_SWIFT_VALUETYPE 0x2651 From 82764a10c85e72b46dadd0355e2c2982d6f7230d Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 26 Jan 2024 12:14:50 -0800 Subject: [PATCH 12/15] Update src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs --- src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs index 92286ad9563ee4..7b0cf61350ab7d 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs @@ -4,7 +4,6 @@ using System; using Debug = System.Diagnostics.Debug; using System.Runtime.InteropServices.ObjectiveC; -using ILCompiler; using Internal.TypeSystem.Ecma; namespace Internal.TypeSystem.Interop From b115352687e81fe4dd32f0408d306089136c09e1 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 29 Jan 2024 14:02:43 -0800 Subject: [PATCH 13/15] Update EncodeAsEmbeddedSignatureData --- .../Common/TypeSystem/Interop/UnmanagedCallingConventions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs b/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs index d0d4aa172fc81d..21572e5ef62479 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs @@ -240,6 +240,7 @@ public static EmbeddedSignatureData[] EncodeAsEmbeddedSignatureData(this Unmanag UnmanagedCallingConventions.Stdcall => "CallConvStdcall", UnmanagedCallingConventions.Fastcall => "CallConvFastcall", UnmanagedCallingConventions.Thiscall => "CallConvThiscall", + UnmanagedCallingConventions.Swift => "CallConvSwift", _ => throw new InvalidProgramException() }); } From 4bea8a57545c144b5ea3d623f180f48436818092 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 29 Jan 2024 15:54:19 -0800 Subject: [PATCH 14/15] Fix one place where we didn't flow through the calling convention and ensure that the JIT/VM bail out on Swift callconv functions as of now. --- src/coreclr/jit/importercalls.cpp | 3 ++- src/coreclr/vm/corelib.h | 1 + src/coreclr/vm/dllimport.cpp | 3 ++- src/coreclr/vm/stubgen.cpp | 3 +++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index ff087f04e4b0e9..c4454530ca1529 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -5592,7 +5592,8 @@ void Compiler::impCheckForPInvokeCall( // return here without inlining the native call. if (unmanagedCallConv == CorInfoCallConvExtension::Managed || unmanagedCallConv == CorInfoCallConvExtension::Fastcall || - unmanagedCallConv == CorInfoCallConvExtension::FastcallMemberFunction) + unmanagedCallConv == CorInfoCallConvExtension::FastcallMemberFunction || + unmanagedCallConv == CorInfoCallConvExtension::Swift) { return; } diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 2fc34d04372c5e..6b926cce40a08e 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -749,6 +749,7 @@ DEFINE_CLASS(CALLCONV_THISCALL, CompilerServices, CallConvThi DEFINE_CLASS(CALLCONV_FASTCALL, CompilerServices, CallConvFastcall) DEFINE_CLASS(CALLCONV_SUPPRESSGCTRANSITION, CompilerServices, CallConvSuppressGCTransition) DEFINE_CLASS(CALLCONV_MEMBERFUNCTION, CompilerServices, CallConvMemberFunction) +DEFINE_CLASS(CALLCONV_SWIFT, CompilerServices, CallConvSwift) DEFINE_CLASS_U(Interop, SafeHandle, SafeHandle) DEFINE_FIELD_U(_ctorStackTrace, SafeHandle, m_ctorStackTrace) diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index c7084060ce7d71..28c3a3422e5884 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -4256,7 +4256,8 @@ static void CreateNDirectStubAccessMetadata( { if (unmgdCallConv == CorInfoCallConvExtension::Managed || unmgdCallConv == CorInfoCallConvExtension::Fastcall || - unmgdCallConv == CorInfoCallConvExtension::FastcallMemberFunction) + unmgdCallConv == CorInfoCallConvExtension::FastcallMemberFunction || + unmgdCallConv == CorInfoCallConvExtension::Swift) { COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV); } diff --git a/src/coreclr/vm/stubgen.cpp b/src/coreclr/vm/stubgen.cpp index 78e7fb621c90d5..5f18e8f5d9123f 100644 --- a/src/coreclr/vm/stubgen.cpp +++ b/src/coreclr/vm/stubgen.cpp @@ -2819,6 +2819,9 @@ void ILStubLinker::SetStubTargetCallingConv(CorInfoCallConvExtension callConv) m_nativeFnSigBuilder.AddCallConvModOpt(GetToken(CoreLibBinder::GetClass(CLASS__CALLCONV_FASTCALL))); m_nativeFnSigBuilder.AddCallConvModOpt(GetToken(CoreLibBinder::GetClass(CLASS__CALLCONV_MEMBERFUNCTION))); break; + case CorInfoCallConvExtension::Swift: + m_nativeFnSigBuilder.AddCallConvModOpt(GetToken(CoreLibBinder::GetClass(CLASS__CALLCONV_SWIFT))); + break; default: _ASSERTE("Unknown calling convention. Unable to encode it in the native function pointer signature."); break; From 1b8eb2c76347275eed0d1b81b1c77dbc478e5740 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 30 Jan 2024 11:33:13 -0800 Subject: [PATCH 15/15] Flip branch logic --- .../Interop/UnmanagedCallingConventions.cs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs b/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs index 21572e5ef62479..98cdb658a42248 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/UnmanagedCallingConventions.cs @@ -139,18 +139,16 @@ public static UnmanagedCallingConventions GetDelegateCallingConventions(this Typ { Debug.Assert(delegateType.IsDelegate); - if (delegateType is not EcmaType ecmaDelegate) + if (delegateType is EcmaType ecmaDelegate) { - return GetPlatformDefaultUnmanagedCallingConvention(delegateType.Context); - } - - MethodSignatureFlags unmanagedCallConv = ecmaDelegate.GetDelegatePInvokeFlags().UnmanagedCallingConvention; - if (unmanagedCallConv != MethodSignatureFlags.None) - { - Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionCdecl == (int)UnmanagedCallingConventions.Cdecl - && (int)MethodSignatureFlags.UnmanagedCallingConventionStdCall == (int)UnmanagedCallingConventions.Stdcall - && (int)MethodSignatureFlags.UnmanagedCallingConventionThisCall == (int)UnmanagedCallingConventions.Thiscall); - return (UnmanagedCallingConventions)unmanagedCallConv; + MethodSignatureFlags unmanagedCallConv = ecmaDelegate.GetDelegatePInvokeFlags().UnmanagedCallingConvention; + if (unmanagedCallConv != MethodSignatureFlags.None) + { + Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionCdecl == (int)UnmanagedCallingConventions.Cdecl + && (int)MethodSignatureFlags.UnmanagedCallingConventionStdCall == (int)UnmanagedCallingConventions.Stdcall + && (int)MethodSignatureFlags.UnmanagedCallingConventionThisCall == (int)UnmanagedCallingConventions.Thiscall); + return (UnmanagedCallingConventions)unmanagedCallConv; + } } return GetPlatformDefaultUnmanagedCallingConvention(delegateType.Context);