Skip to content

Commit

Permalink
Prepare ComInterfaceGenerator for going into the public API (#83894)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkoritzinsky authored Apr 3, 2023
1 parent e6226e6 commit b2f421f
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M
ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.UnmanagedToManaged),
typeKeyOwner,
new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()),
ParseTypeName(TypeNames.ComWrappersUnwrapper));
ComInterfaceDispatchMarshallingInfo.Instance);
}

private static Diagnostic? GetDiagnosticIfInvalidTypeForGeneration(InterfaceDeclarationSyntax syntax, INamedTypeSymbol type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ internal static class ComInterfaceGeneratorHelpers

generatorFactory = new ManagedHResultExceptionMarshallerFactory(generatorFactory, direction);

generatorFactory = new NativeToManagedThisMarshallerFactory(generatorFactory);
generatorFactory = new ComInterfaceDispatchMarshallerFactory(generatorFactory);

generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ internal sealed record IncrementalMethodStubGenerationContext(
MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion)> UnmanagedToManagedGeneratorFactory,
ManagedTypeInfo TypeKeyOwner,
SequenceEqualImmutableArray<Diagnostic> Diagnostics,
TypeSyntax UnwrapperSyntax) : GeneratedMethodContextBase(TypeKeyOwner, Diagnostics);
MarshallingInfo ManagedThisMarshallingInfo) : GeneratedMethodContextBase(TypeKeyOwner, Diagnostics);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

namespace Microsoft.Interop
{
internal sealed record ComInterfaceDispatchMarshallingInfo : MarshallingInfo
{
public static readonly ComInterfaceDispatchMarshallingInfo Instance = new();
}

internal sealed class ComInterfaceDispatchMarshallerFactory : IMarshallingGeneratorFactory
{
private readonly IMarshallingGeneratorFactory _inner;
public ComInterfaceDispatchMarshallerFactory(IMarshallingGeneratorFactory inner)
{
_inner = inner;
}

public IMarshallingGenerator Create(TypePositionInfo info, StubCodeContext context)
=> info.MarshallingAttributeInfo is ComInterfaceDispatchMarshallingInfo ? new Marshaller() : _inner.Create(info, context);

private sealed class Marshaller : IMarshallingGenerator
{
public ManagedTypeInfo AsNativeType(TypePositionInfo info) =>
new PointerTypeInfo(
$"{TypeNames.System_Runtime_InteropServices_ComWrappers_ComInterfaceDispatch}*",
$"{TypeNames.System_Runtime_InteropServices_ComWrappers_ComInterfaceDispatch}*",
IsFunctionPointer: false);
public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeContext context)
{
if (context.CurrentStage != StubCodeContext.Stage.Unmarshal)
{
yield break;
}

var (managed, native) = context.GetIdentifiers(info);

// <managed> = ComWrappers.ComInterfaceDispatch.GetInstance<<managedType>>(<native>);
yield return ExpressionStatement(
AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
IdentifierName(managed),
InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
ParseName(TypeNames.System_Runtime_InteropServices_ComWrappers_ComInterfaceDispatch),
GenericName(
Identifier("GetInstance"),
TypeArgumentList(SingletonSeparatedList(info.ManagedType.Syntax)))),
ArgumentList(
SingletonSeparatedList(
Argument(
IdentifierName(native)))))));
}

public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) => SignatureBehavior.NativeType;
public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) => ValueBoundaryBehavior.NativeIdentifier;
public bool IsSupported(TargetFramework target, Version version)
=> target == TargetFramework.Net && version >= new Version(5, 0);
public bool SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, StubCodeContext context) => false;
public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) => true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,26 @@

namespace Microsoft.Interop
{
internal sealed record NativeThisInfo(TypeSyntax UnwrapperType) : MarshallingInfo;
internal sealed record ObjectUnwrapperInfo(TypeSyntax UnwrapperType) : MarshallingInfo;

internal sealed class NativeToManagedThisMarshallerFactory : IMarshallingGeneratorFactory
internal sealed class ObjectUnwrapperMarshallerFactory : IMarshallingGeneratorFactory
{
private readonly IMarshallingGeneratorFactory _inner;
public NativeToManagedThisMarshallerFactory(IMarshallingGeneratorFactory inner)
public ObjectUnwrapperMarshallerFactory(IMarshallingGeneratorFactory inner)
{
_inner = inner;
}

public IMarshallingGenerator Create(TypePositionInfo info, StubCodeContext context)
=> info.MarshallingAttributeInfo is NativeThisInfo ? new Marshaller() : _inner.Create(info, context);
=> info.MarshallingAttributeInfo is ObjectUnwrapperInfo ? new Marshaller() : _inner.Create(info, context);

private sealed class Marshaller : IMarshallingGenerator
{
public ManagedTypeInfo AsNativeType(TypePositionInfo info) => new PointerTypeInfo("void*", "void*", false);
public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeContext context)
{
Debug.Assert(info.MarshallingAttributeInfo is NativeThisInfo);
TypeSyntax unwrapperType = ((NativeThisInfo)info.MarshallingAttributeInfo).UnwrapperType;
Debug.Assert(info.MarshallingAttributeInfo is ObjectUnwrapperInfo);
TypeSyntax unwrapperType = ((ObjectUnwrapperInfo)info.MarshallingAttributeInfo).UnwrapperType;
if (context.CurrentStage != StubCodeContext.Stage.Unmarshal)
{
yield break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ private static ImmutableArray<TypePositionInfo> AddImplicitElementInfos(Incremen

var elements = ImmutableArray.CreateBuilder<TypePositionInfo>(originalElements.Length + 2);

elements.Add(new TypePositionInfo(methodStub.TypeKeyOwner, new NativeThisInfo(methodStub.UnwrapperSyntax))
elements.Add(new TypePositionInfo(methodStub.TypeKeyOwner, methodStub.ManagedThisMarshallingInfo)
{
InstanceIdentifier = ThisParameterIdentifier,
NativeIndex = 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,11 +337,11 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M
new SequenceEqualImmutableArray<FunctionPointerUnmanagedCallingConventionSyntax>(callConv, SyntaxEquivalentComparer.Instance),
VirtualMethodIndexData.From(virtualMethodIndexData),
exceptionMarshallingInfo,
ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.ManagedToUnmanaged),
ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.UnmanagedToManaged),
VtableIndexStubGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.ManagedToUnmanaged),
VtableIndexStubGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.UnmanagedToManaged),
interfaceType,
new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()),
unwrapperSyntax);
new ObjectUnwrapperInfo(unwrapperSyntax));
}

private static MarshallingInfo CreateExceptionMarshallingInfo(AttributeData virtualMethodIndexAttr, ISymbol symbol, Compilation compilation, GeneratorDiagnostics diagnostics, VirtualMethodIndexCompilationData virtualMethodIndexData)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;

namespace Microsoft.Interop
{
internal static class VtableIndexStubGeneratorHelpers
{
public static MarshallingGeneratorFactoryKey<(TargetFramework, Version)> CreateGeneratorFactory(StubEnvironment env, MarshalDirection direction)
{
IMarshallingGeneratorFactory generatorFactory;

// If we're in a "supported" scenario, then emit a diagnostic as our final fallback.
generatorFactory = new UnsupportedMarshallingFactory();

generatorFactory = new NoMarshallingInfoErrorMarshallingFactory(generatorFactory);

// The presence of System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute is tied to TFM,
// so we use TFM in the generator factory key instead of the Compilation as the compilation changes on every keystroke.
IAssemblySymbol coreLibraryAssembly = env.Compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly;
ITypeSymbol? disabledRuntimeMarshallingAttributeType = coreLibraryAssembly.GetTypeByMetadataName(TypeNames.System_Runtime_CompilerServices_DisableRuntimeMarshallingAttribute);
bool runtimeMarshallingDisabled = disabledRuntimeMarshallingAttributeType is not null
&& env.Compilation.Assembly.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, disabledRuntimeMarshallingAttributeType));

// Since the char type can go into the P/Invoke signature here, we can only use it when
// runtime marshalling is disabled.
generatorFactory = new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: runtimeMarshallingDisabled);

InteropGenerationOptions interopGenerationOptions = new(UseMarshalType: true);
generatorFactory = new MarshalAsMarshallingGeneratorFactory(interopGenerationOptions, generatorFactory);

IMarshallingGeneratorFactory elementFactory = new AttributedMarshallingModelGeneratorFactory(
// Since the char type in an array will not be part of the P/Invoke signature, we can
// use the regular blittable marshaller in all cases.
new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: true),
new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ElementIn, MarshalMode.ElementRef, MarshalMode.ElementOut));
// We don't need to include the later generator factories for collection elements
// as the later generator factories only apply to parameters.
generatorFactory = new AttributedMarshallingModelGeneratorFactory(
generatorFactory,
elementFactory,
new AttributedMarshallingModelOptions(
runtimeMarshallingDisabled,
direction == MarshalDirection.ManagedToUnmanaged
? MarshalMode.ManagedToUnmanagedIn
: MarshalMode.UnmanagedToManagedOut,
direction == MarshalDirection.ManagedToUnmanaged
? MarshalMode.ManagedToUnmanagedRef
: MarshalMode.UnmanagedToManagedRef,
direction == MarshalDirection.ManagedToUnmanaged
? MarshalMode.ManagedToUnmanagedOut
: MarshalMode.UnmanagedToManagedIn));

generatorFactory = new ObjectUnwrapperMarshallerFactory(generatorFactory);

generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory);

return MarshallingGeneratorFactoryKey.Create((env.TargetFramework, env.TargetFrameworkVersion), generatorFactory);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,12 @@ internal static MarshallingInfo CreateSpecificMarshallingInfo(ManagedTypeInfo un
{
return unmanagedReturnType switch
{
SpecialTypeInfo(_, _, SpecialType.System_Void) => CreateWellKnownComExceptionMarshallingData($"{TypeNames.SwallowExceptionMarshaller}", unmanagedReturnType),
SpecialTypeInfo(_, _, SpecialType.System_Int32) => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionHResultMarshaller}<int>", unmanagedReturnType),
SpecialTypeInfo(_, _, SpecialType.System_UInt32) => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionHResultMarshaller}<uint>", unmanagedReturnType),
SpecialTypeInfo(_, _, SpecialType.System_Single) => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionNaNMarshaller}<float>", unmanagedReturnType),
SpecialTypeInfo(_, _, SpecialType.System_Double) => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionNaNMarshaller}<double>", unmanagedReturnType),
_ => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionDefaultMarshaller}<{MarshallerHelpers.GetCompatibleGenericTypeParameterSyntax(SyntaxFactory.ParseTypeName(unmanagedReturnType.FullTypeName))}>", unmanagedReturnType),
SpecialTypeInfo(_, _, SpecialType.System_Void) => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsVoidMarshaller}", unmanagedReturnType),
SpecialTypeInfo(_, _, SpecialType.System_Int32) => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsHResultMarshaller}<int>", unmanagedReturnType),
SpecialTypeInfo(_, _, SpecialType.System_UInt32) => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsHResultMarshaller}<uint>", unmanagedReturnType),
SpecialTypeInfo(_, _, SpecialType.System_Single) => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsNaNMarshaller}<float>", unmanagedReturnType),
SpecialTypeInfo(_, _, SpecialType.System_Double) => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsNaNMarshaller}<double>", unmanagedReturnType),
_ => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsDefaultMarshaller}<{MarshallerHelpers.GetCompatibleGenericTypeParameterSyntax(SyntaxFactory.ParseTypeName(unmanagedReturnType.FullTypeName))}>", unmanagedReturnType),
};

static NativeMarshallingAttributeInfo CreateWellKnownComExceptionMarshallingData(string marshallerName, ManagedTypeInfo unmanagedType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ public static class TypeNames
public const string BStrStringMarshaller = "System.Runtime.InteropServices.Marshalling.BStrStringMarshaller";
public const string Utf16StringMarshaller = "System.Runtime.InteropServices.Marshalling.Utf16StringMarshaller";
public const string Utf8StringMarshaller = "System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller";
public const string SwallowExceptionMarshaller = "System.Runtime.InteropServices.Marshalling.SwallowExceptionMarshaller";
public const string ExceptionHResultMarshaller = "System.Runtime.InteropServices.Marshalling.ExceptionHResultMarshaller";
public const string ExceptionNaNMarshaller = "System.Runtime.InteropServices.Marshalling.ExceptionNaNMarshaller";
public const string ExceptionDefaultMarshaller = "System.Runtime.InteropServices.Marshalling.ExceptionDefaultMarshaller";
public const string ExceptionAsVoidMarshaller = "System.Runtime.InteropServices.Marshalling.ExceptionAsVoidMarshaller";
public const string ExceptionAsHResultMarshaller = "System.Runtime.InteropServices.Marshalling.ExceptionAsHResultMarshaller";
public const string ExceptionAsNaNMarshaller = "System.Runtime.InteropServices.Marshalling.ExceptionAsNaNMarshaller";
public const string ExceptionAsDefaultMarshaller = "System.Runtime.InteropServices.Marshalling.ExceptionAsDefaultMarshaller";

public const string LCIDConversionAttribute = "System.Runtime.InteropServices.LCIDConversionAttribute";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ namespace System.Runtime.InteropServices.Marshalling
/// Converts the exception to the default value of the unmanaged type.
/// </summary>
/// <typeparam name="T">The unmanaged type</typeparam>
[CustomMarshaller(typeof(Exception), MarshalMode.UnmanagedToManagedOut, typeof(ExceptionDefaultMarshaller<>))]
public static class ExceptionDefaultMarshaller<T>
[CustomMarshaller(typeof(Exception), MarshalMode.UnmanagedToManagedOut, typeof(ExceptionAsDefaultMarshaller<>))]
public static class ExceptionAsDefaultMarshaller<T>
where T : unmanaged
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ namespace System.Runtime.InteropServices.Marshalling
/// We can skip the exposing the exception marshallers if we decide to not expose the VTable source generator.
/// In that case, we'd hard-code the implementations of these marshallers into the COM source generator.
/// </remarks>
[CustomMarshaller(typeof(Exception), MarshalMode.UnmanagedToManagedOut, typeof(ExceptionHResultMarshaller<>))]
public static class ExceptionHResultMarshaller<T>
[CustomMarshaller(typeof(Exception), MarshalMode.UnmanagedToManagedOut, typeof(ExceptionAsHResultMarshaller<>))]
public static class ExceptionAsHResultMarshaller<T>
where T : unmanaged, INumber<T>
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ namespace System.Runtime.InteropServices.Marshalling
/// Converts all exceptions to <see cref="T.NaN"/>.
/// </summary>
/// <typeparam name="T">The unmanaged type to return the <c>NaN</c> value for.</typeparam>
[CustomMarshaller(typeof(Exception), MarshalMode.UnmanagedToManagedOut, typeof(ExceptionNaNMarshaller<>))]
public static class ExceptionNaNMarshaller<T>
[CustomMarshaller(typeof(Exception), MarshalMode.UnmanagedToManagedOut, typeof(ExceptionAsNaNMarshaller<>))]
public static class ExceptionAsNaNMarshaller<T>
where T : unmanaged, IFloatingPointIeee754<T>
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ namespace System.Runtime.InteropServices.Marshalling
/// <summary>
/// Marshaller that swallows the exception.
/// </summary>
[CustomMarshaller(typeof(Exception), MarshalMode.UnmanagedToManagedOut, typeof(SwallowExceptionMarshaller))]
public static class SwallowExceptionMarshaller
[CustomMarshaller(typeof(Exception), MarshalMode.UnmanagedToManagedOut, typeof(ExceptionAsVoidMarshaller))]
public static class ExceptionAsVoidMarshaller
{
/// <summary>
/// Swallow the exception and return nothing.
Expand Down
Loading

0 comments on commit b2f421f

Please sign in to comment.