未验证 提交 a3a106f4 编写于 作者: E Elinor Fung 提交者: GitHub

Stop requiring bidirectional support for MarshalMode.Default (#71977)

上级 5ab41751
......@@ -62,14 +62,6 @@ public static class MarshalUsingProperties
public const string ConstantElementCount = nameof(ConstantElementCount);
}
[Flags]
private enum MarshallingDirection
{
ManagedToUnmanaged = 0x1,
UnmanagedToManaged = 0x2,
Bidirectional = ManagedToUnmanaged | UnmanagedToManaged
}
public static bool IsLinearCollectionEntryPoint(INamedTypeSymbol entryPointType)
{
return entryPointType.IsGenericType
......@@ -114,7 +106,8 @@ public static bool HasEntryPointMarshallerAttribute(ITypeSymbol entryPointType)
return false;
// We expect a callback for getting the element marshalling info when handling linear collection marshalling
Debug.Assert(!isLinearCollectionMarshalling || getMarshallingInfoForElement is not null);
if (isLinearCollectionMarshalling && getMarshallingInfoForElement is null)
return false;
Dictionary<MarshalMode, CustomTypeMarshallerData> modes = new();
......@@ -127,7 +120,12 @@ public static bool HasEntryPointMarshallerAttribute(ITypeSymbol entryPointType)
// We don't report a diagnostic here since Roslyn will report a diagnostic anyway.
continue;
}
Debug.Assert(attr.ConstructorArguments.Length == 3);
if (attr.ConstructorArguments.Length != 3)
{
Debug.WriteLine($"{attr} has {attr.ConstructorArguments.Length} constructor arguments - expected 3");
continue;
}
// Verify the defined marshaller is for the managed type.
ITypeSymbol? managedTypeOnAttr = attr.ConstructorArguments[0].Value as ITypeSymbol;
......@@ -175,33 +173,9 @@ public static bool HasEntryPointMarshallerAttribute(ITypeSymbol entryPointType)
marshallerType = currentType;
}
// TODO: We can probably get rid of MarshallingDirection and just use MarshalMode instead
MarshallingDirection direction = marshalMode switch
{
MarshalMode.Default
=> MarshallingDirection.Bidirectional,
MarshalMode.ManagedToUnmanagedIn
or MarshalMode.UnmanagedToManagedOut
or MarshalMode.ElementIn
=> MarshallingDirection.ManagedToUnmanaged,
MarshalMode.ManagedToUnmanagedOut
or MarshalMode.UnmanagedToManagedIn
or MarshalMode.ElementOut
=> MarshallingDirection.UnmanagedToManaged,
MarshalMode.ManagedToUnmanagedRef
or MarshalMode.UnmanagedToManagedRef
or MarshalMode.ElementRef
=> MarshallingDirection.Bidirectional,
_ => throw new UnreachableException()
};
// TODO: Report invalid shape for mode
// Skip checking for bidirectional support for Default mode - always take / store marshaller data
CustomTypeMarshallerData? data = GetMarshallerDataForType(marshallerType, direction, managedType, isLinearCollectionMarshalling, compilation, getMarshallingInfoForElement);
CustomTypeMarshallerData? data = GetMarshallerDataForType(marshallerType, marshalMode, managedType, isLinearCollectionMarshalling, compilation, getMarshallingInfoForElement);
// TODO: Should we fire a diagnostic for duplicated modes or just take the last one?
if (data is null
......@@ -338,7 +312,7 @@ public static (AttributeData? attribute, INamedTypeSymbol? entryType) GetDefault
private static CustomTypeMarshallerData? GetMarshallerDataForType(
ITypeSymbol marshallerType,
MarshallingDirection direction,
MarshalMode mode,
ITypeSymbol managedType,
bool isLinearCollectionMarshaller,
Compilation compilation,
......@@ -346,24 +320,42 @@ public static (AttributeData? attribute, INamedTypeSymbol? entryType) GetDefault
{
if (marshallerType is { IsStatic: true, TypeKind: TypeKind.Class })
{
return GetStatelessMarshallerDataForType(marshallerType, direction, managedType, isLinearCollectionMarshaller, compilation, getMarshallingInfo);
return GetStatelessMarshallerDataForType(marshallerType, mode, managedType, isLinearCollectionMarshaller, compilation, getMarshallingInfo);
}
if (marshallerType.IsValueType)
{
return GetStatefulMarshallerDataForType(marshallerType, direction, managedType, isLinearCollectionMarshaller, compilation, getMarshallingInfo);
return GetStatefulMarshallerDataForType(marshallerType, mode, managedType, isLinearCollectionMarshaller, compilation, getMarshallingInfo);
}
return null;
}
private static CustomTypeMarshallerData? GetStatelessMarshallerDataForType(ITypeSymbol marshallerType, MarshallingDirection direction, ITypeSymbol managedType, bool isLinearCollectionMarshaller, Compilation compilation, Func<ITypeSymbol, MarshallingInfo>? getMarshallingInfo)
private static bool ModeUsesManagedToUnmanagedShape(MarshalMode mode)
=> mode is MarshalMode.Default
or MarshalMode.ManagedToUnmanagedIn
or MarshalMode.UnmanagedToManagedOut
or MarshalMode.ElementIn
or MarshalMode.ManagedToUnmanagedRef
or MarshalMode.UnmanagedToManagedRef
or MarshalMode.ElementRef;
private static bool ModeUsesUnmanagedToManagedShape(MarshalMode mode)
=> mode is MarshalMode.Default
or MarshalMode.ManagedToUnmanagedOut
or MarshalMode.UnmanagedToManagedIn
or MarshalMode.ElementOut
or MarshalMode.ManagedToUnmanagedRef
or MarshalMode.UnmanagedToManagedRef
or MarshalMode.ElementRef;
private static CustomTypeMarshallerData? GetStatelessMarshallerDataForType(ITypeSymbol marshallerType, MarshalMode mode, ITypeSymbol managedType, bool isLinearCollectionMarshaller, Compilation compilation, Func<ITypeSymbol, MarshallingInfo>? getMarshallingInfo)
{
(MarshallerShape shape, StatelessMarshallerShapeHelper.MarshallerMethods methods) = StatelessMarshallerShapeHelper.GetShapeForType(marshallerType, managedType, isLinearCollectionMarshaller, compilation);
ITypeSymbol? collectionElementType = null;
ITypeSymbol? nativeType = null;
if (direction.HasFlag(MarshallingDirection.ManagedToUnmanaged))
if (ModeUsesManagedToUnmanagedShape(mode))
{
if (!shape.HasFlag(MarshallerShape.CallerAllocatedBuffer) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
if (mode != MarshalMode.Default && !shape.HasFlag(MarshallerShape.CallerAllocatedBuffer) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
return null;
if (isLinearCollectionMarshaller)
......@@ -383,9 +375,10 @@ public static (AttributeData? attribute, INamedTypeSymbol? entryType) GetDefault
}
}
if (direction.HasFlag(MarshallingDirection.UnmanagedToManaged))
if (ModeUsesUnmanagedToManagedShape(mode))
{
if (!shape.HasFlag(MarshallerShape.GuaranteedUnmarshal) && !shape.HasFlag(MarshallerShape.ToManaged))
// Unmanaged to managed requires ToManaged either with or without guaranteed unmarshal
if (mode != MarshalMode.Default && !shape.HasFlag(MarshallerShape.GuaranteedUnmarshal) && !shape.HasFlag(MarshallerShape.ToManaged))
return null;
if (isLinearCollectionMarshaller)
......@@ -411,7 +404,7 @@ public static (AttributeData? attribute, INamedTypeSymbol? entryType) GetDefault
}
// Bidirectional requires ToUnmanaged without the caller-allocated buffer
if (direction.HasFlag(MarshallingDirection.Bidirectional) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
if (mode != MarshalMode.Default && ModeUsesManagedToUnmanagedShape(mode) && ModeUsesUnmanagedToManagedShape(mode) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
return null;
if (nativeType is null)
......@@ -444,7 +437,7 @@ public static (AttributeData? attribute, INamedTypeSymbol? entryType) GetDefault
private static CustomTypeMarshallerData? GetStatefulMarshallerDataForType(
ITypeSymbol marshallerType,
MarshallingDirection direction,
MarshalMode mode,
ITypeSymbol managedType,
bool isLinearCollectionMarshaller,
Compilation compilation,
......@@ -454,9 +447,10 @@ public static (AttributeData? attribute, INamedTypeSymbol? entryType) GetDefault
ITypeSymbol? nativeType = null;
ITypeSymbol? collectionElementType = null;
if (direction.HasFlag(MarshallingDirection.ManagedToUnmanaged))
if (ModeUsesManagedToUnmanagedShape(mode))
{
if (!shape.HasFlag(MarshallerShape.CallerAllocatedBuffer) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
// Managed to unmanaged requires ToUnmanaged either with or without the caller-allocated buffer
if (mode != MarshalMode.Default && !shape.HasFlag(MarshallerShape.CallerAllocatedBuffer) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
return null;
if (methods.ToUnmanaged is not null)
......@@ -471,17 +465,18 @@ public static (AttributeData? attribute, INamedTypeSymbol? entryType) GetDefault
}
}
if (nativeType is null && direction.HasFlag(MarshallingDirection.UnmanagedToManaged))
if (ModeUsesUnmanagedToManagedShape(mode))
{
if (!shape.HasFlag(MarshallerShape.GuaranteedUnmarshal) && !shape.HasFlag(MarshallerShape.ToManaged))
// Unmanaged to managed requires ToManaged either with or without guaranteed unmarshal
if (mode != MarshalMode.Default && !shape.HasFlag(MarshallerShape.GuaranteedUnmarshal) && !shape.HasFlag(MarshallerShape.ToManaged))
return null;
if (methods.FromUnmanaged is not null)
if (methods.FromUnmanaged is not null && nativeType is null)
{
nativeType = methods.FromUnmanaged.Parameters[0].Type;
}
if (isLinearCollectionMarshaller)
if (isLinearCollectionMarshaller && collectionElementType is null)
{
// Element type is the type parameter of the Span returned by GetManagedValuesDestination
collectionElementType = ((INamedTypeSymbol)methods.ManagedValuesDestination.ReturnType).TypeArguments[0];
......@@ -489,7 +484,7 @@ public static (AttributeData? attribute, INamedTypeSymbol? entryType) GetDefault
}
// Bidirectional requires ToUnmanaged without the caller-allocated buffer
if (direction.HasFlag(MarshallingDirection.Bidirectional) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
if (mode != MarshalMode.Default && ModeUsesManagedToUnmanagedShape(mode) && ModeUsesUnmanagedToManagedShape(mode) && !shape.HasFlag(MarshallerShape.ToUnmanaged))
return null;
if (nativeType is null)
......
......@@ -751,6 +751,16 @@ public struct Native { }
}
";
public static string Ref = @"
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedRef, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
public static Native ConvertToUnmanaged(S s) => default;
public static S ConvertToManaged(Native n) => default;
}
";
public static string Default = @"
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller
{
......@@ -760,7 +770,7 @@ public struct Native { }
public static S ConvertToManaged(Native n) => default;
}
";
public static string RefBuffer = @"
public static string InOutBuffer = @"
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(Marshaller))]
public static class Marshaller
......@@ -772,7 +782,7 @@ public struct Native { }
public static S ConvertToManaged(Native n) => default;
}
";
public static string RefOptionalBuffer = @"
public static string DefaultOptionalBuffer = @"
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller
{
......@@ -784,7 +794,24 @@ public struct Native { }
public static S ConvertToManaged(Native n) => default;
}
";
private static string DefaultIn = @"
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
public static Native ConvertToUnmanaged(S s) => default;
}
";
private static string DefaultOut = @"
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
public static S ConvertToManaged(Native n) => default;
}
";
public static string ManagedToNativeOnlyOutParameter => BasicParameterWithByRefModifier("out", "S")
+ NonBlittableUserDefinedType()
+ In;
......@@ -815,30 +842,47 @@ public struct Native { }
public static string ParametersAndModifiers = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling)
+ NonBlittableUserDefinedType(defineNativeMarshalling: true)
+ Ref;
+ Default;
public static string MarshalUsingParametersAndModifiers = MarshalUsingParametersAndModifiers("S", "Marshaller")
+ NonBlittableUserDefinedType(defineNativeMarshalling: false)
+ Ref;
+ Default;
public static string ByValueInParameter => BasicParameterByValue("S")
+ NonBlittableUserDefinedType()
+ In;
public static string StackallocByValueInParameter => BasicParameterByValue("S")
+ NonBlittableUserDefinedType()
+ InBuffer;
public static string PinByValueInParameter => BasicParameterByValue("S")
+ NonBlittableUserDefinedType()
+ InPinnable;
public static string StackallocParametersAndModifiersNoRef = BasicParametersAndModifiersNoRef("S")
+ NonBlittableUserDefinedType()
+ RefBuffer;
+ InOutBuffer;
public static string RefParameter = BasicParameterWithByRefModifier("ref", "S")
+ NonBlittableUserDefinedType()
+ Ref;
public static string StackallocOnlyRefParameter = BasicParameterWithByRefModifier("ref", "S")
+ NonBlittableUserDefinedType()
+ RefBuffer;
+ InOutBuffer;
public static string OptionalStackallocParametersAndModifiers = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling)
+ NonBlittableUserDefinedType()
+ RefOptionalBuffer;
+ DefaultOptionalBuffer;
public static string DefaultModeByValueInParameter => BasicParameterByValue("S")
+ NonBlittableUserDefinedType()
+ DefaultIn;
public static string DefaultModeReturnValue => BasicReturnType("S")
+ NonBlittableUserDefinedType()
+ DefaultOut;
}
public static class Stateful
......@@ -926,6 +970,21 @@ public struct M
}
";
public static string Ref = @"
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedRef, typeof(M))]
public static class Marshaller
{
public struct Native { }
public struct M
{
public void FromManaged(S s) {}
public Native ToUnmanaged() => default;
public void FromUnmanaged(Native n) {}
public S ToManaged() => default;
}
}
";
public static string Default = @"
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller
{
......@@ -940,7 +999,7 @@ public struct M
}
}
";
public static string RefWithFree = @"
public static string DefaultWithFree = @"
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller
{
......@@ -956,7 +1015,7 @@ public struct M
}
}
";
public static string RefWithOnInvoked = @"
public static string DefaultWithOnInvoked = @"
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller
{
......@@ -972,7 +1031,7 @@ public struct M
}
}
";
public static string RefBuffer = @"
public static string InOutBuffer = @"
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(M))]
public static class Marshaller
......@@ -989,13 +1048,12 @@ public struct M
}
}
";
public static string RefOptionalBuffer = @"
public static string DefaultOptionalBuffer = @"
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller
{
public struct Native { }
public struct M
{
public const int BufferSize = 0x100;
......@@ -1006,6 +1064,32 @@ public struct M
public S ToManaged() => default;
}
}
";
private static string DefaultIn = @"
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller
{
public struct Native { }
public struct M
{
public void FromManaged(S s) {}
public Native ToUnmanaged() => default;
}
}
";
private static string DefaultOut = @"
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller
{
public struct Native { }
public struct M
{
public void FromUnmanaged(Native n) {}
public S ToManaged() => default;
}
}
";
public static string ManagedToNativeOnlyOutParameter => BasicParameterWithByRefModifier("out", "S")
+ NonBlittableUserDefinedType()
......@@ -1037,41 +1121,59 @@ public struct M
public static string ParametersAndModifiers = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling)
+ NonBlittableUserDefinedType(defineNativeMarshalling: true)
+ Ref;
+ Default;
public static string ParametersAndModifiersWithFree = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling)
+ NonBlittableUserDefinedType(defineNativeMarshalling: true)
+ RefWithFree;
+ DefaultWithFree;
public static string ParametersAndModifiersWithOnInvoked = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling)
+ NonBlittableUserDefinedType(defineNativeMarshalling: true)
+ RefWithOnInvoked;
+ DefaultWithOnInvoked;
public static string MarshalUsingParametersAndModifiers = MarshalUsingParametersAndModifiers("S", "Marshaller")
+ NonBlittableUserDefinedType(defineNativeMarshalling: false)
+ Ref;
+ Default;
public static string ByValueInParameter => BasicParameterByValue("S")
+ NonBlittableUserDefinedType()
+ In;
public static string StackallocByValueInParameter => BasicParameterByValue("S")
+ NonBlittableUserDefinedType()
+ InBuffer;
public static string PinByValueInParameter => BasicParameterByValue("S")
+ NonBlittableUserDefinedType()
+ InStatelessPinnable;
public static string MarshallerPinByValueInParameter => BasicParameterByValue("S")
+ NonBlittableUserDefinedType()
+ InPinnable;
public static string StackallocParametersAndModifiersNoRef = BasicParametersAndModifiersNoRef("S")
+ NonBlittableUserDefinedType()
+ RefBuffer;
+ InOutBuffer;
public static string RefParameter = BasicParameterWithByRefModifier("ref", "S")
+ NonBlittableUserDefinedType()
+ Ref;
public static string StackallocOnlyRefParameter = BasicParameterWithByRefModifier("ref", "S")
+ NonBlittableUserDefinedType()
+ RefBuffer;
+ InOutBuffer;
public static string OptionalStackallocParametersAndModifiers = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling)
+ NonBlittableUserDefinedType()
+ RefOptionalBuffer;
+ DefaultOptionalBuffer;
public static string DefaultModeByValueInParameter => BasicParameterByValue("S")
+ NonBlittableUserDefinedType()
+ DefaultIn;
public static string DefaultModeReturnValue => BasicReturnType("S")
+ NonBlittableUserDefinedType()
+ DefaultOut;
}
}
......
......@@ -182,10 +182,14 @@ public static IEnumerable<object[]> CodeSnippetsToCompile()
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedFinallyOnlyOutParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedOnlyReturnValue };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedFinallyOnlyReturnValue };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateless.ByValueInParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateless.PinByValueInParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateless.StackallocByValueInParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateless.RefParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateless.StackallocParametersAndModifiersNoRef };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateless.OptionalStackallocParametersAndModifiers };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateless.DefaultModeByValueInParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateless.DefaultModeReturnValue };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.ParametersAndModifiers };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.ParametersAndModifiersWithFree };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.ParametersAndModifiersWithOnInvoked };
......@@ -194,11 +198,15 @@ public static IEnumerable<object[]> CodeSnippetsToCompile()
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedFinallyOnlyOutParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedOnlyReturnValue };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedFinallyOnlyReturnValue };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.ByValueInParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.StackallocByValueInParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.PinByValueInParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.MarshallerPinByValueInParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.RefParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.StackallocParametersAndModifiersNoRef };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.OptionalStackallocParametersAndModifiers };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.DefaultModeByValueInParameter };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling.Stateful.DefaultModeReturnValue };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.ParametersAndModifiers };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.StackallocParametersAndModifiersNoRef };
yield return new[] { ID(), CodeSnippets.CustomStructMarshalling_V1.StackallocTwoStageParametersAndModifiersNoRef };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册