未验证 提交 3a21f960 编写于 作者: J Jackson Schuster 提交者: GitHub

Discard lastIndexMarshalled variable if it is not otherwise used (#88060)

Tracks the last index marshalled in the interop generators to ensure we don't cleanup any unmarshalled elements. It discards the "last index marshalled" variable if it is unused in the cleanup stage.
上级 672ff9b9
......@@ -134,7 +134,6 @@ public BlockSyntax GenerateStubBody(int index, ImmutableArray<FunctionPointerUnm
bool shouldInitializeVariables = !statements.GuaranteedUnmarshal.IsEmpty || !statements.Cleanup.IsEmpty;
VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForManagedToUnmanaged(_marshallers, _context, shouldInitializeVariables);
if (_setLastError)
{
// Declare variable for last error
......@@ -225,7 +224,7 @@ public BlockSyntax GenerateStubBody(int index, ImmutableArray<FunctionPointerUnm
if (!_marshallers.IsManagedVoidReturn)
allStatements.Add(ReturnStatement(IdentifierName(_context.GetIdentifiers(_marshallers.ManagedReturnMarshaller.TypeInfo).managed)));
return Block(allStatements);
return Block(allStatements.Where(s => s is not EmptyStatementSyntax));
}
private ParenthesizedExpressionSyntax CreateFunctionPointerExpression(
......
......@@ -369,7 +369,7 @@ private ResolvedGenerator CreateCustomNativeTypeMarshaller(TypePositionInfo info
marshallingStrategy = new StatefulCallerAllocatedBufferMarshalling(marshallingStrategy, marshallerTypeSyntax, bufferElementTypeSyntax);
}
FreeStrategy freeStrategy = GetFreeStrategy(info, context);
var freeStrategy = GetFreeStrategy(info, context);
IElementsMarshallingCollectionSource collectionSource = new StatefulLinearCollectionSource();
ElementsMarshalling elementsMarshalling = CreateElementsMarshalling(marshallerData, elementInfo, elementMarshaller, unmanagedElementType, collectionSource);
......@@ -394,7 +394,7 @@ private ResolvedGenerator CreateCustomNativeTypeMarshaller(TypePositionInfo info
{
marshallingStrategy = new StatelessLinearCollectionSpaceAllocator(marshallerTypeSyntax, nativeType, marshallerData.Shape, numElementsExpression);
FreeStrategy freeStrategy = GetFreeStrategy(info, context);
var freeStrategy = GetFreeStrategy(info, context);
IElementsMarshallingCollectionSource collectionSource = new StatelessLinearCollectionSource(marshallerTypeSyntax);
if (freeStrategy == FreeStrategy.FreeOriginal)
......@@ -404,7 +404,7 @@ private ResolvedGenerator CreateCustomNativeTypeMarshaller(TypePositionInfo info
ElementsMarshalling elementsMarshalling = CreateElementsMarshalling(marshallerData, elementInfo, elementMarshaller, unmanagedElementType, collectionSource);
marshallingStrategy = new StatelessLinearCollectionMarshalling(marshallingStrategy, elementsMarshalling, nativeType, marshallerData.Shape, freeStrategy != FreeStrategy.NoFree);
marshallingStrategy = new StatelessLinearCollectionMarshalling(marshallingStrategy, elementsMarshalling, nativeType, marshallerData.Shape, numElementsExpression, freeStrategy != FreeStrategy.NoFree);
if (marshallerData.Shape.HasFlag(MarshallerShape.CallerAllocatedBuffer))
{
......
// 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 Microsoft.CodeAnalysis;
......@@ -38,17 +37,18 @@ public StatementSyntax GenerateClearManagedSource(TypePositionInfo info, StubCod
CollectionSource.GetUnmanagedValuesDestination(info, context),
IdentifierName("Clear"))));
}
public StatementSyntax GenerateClearUnmanagedValuesSource(TypePositionInfo info, StubCodeContext context)
public StatementSyntax GenerateClearManagedValuesDestination(TypePositionInfo info, StubCodeContext context)
{
// <GetUnmanagedValuesSource>.Clear();
return ExpressionStatement(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
CollectionSource.GetUnmanagedValuesSource(info, context),
CollectionSource.GetManagedValuesDestination(info, context),
IdentifierName("Clear"))));
}
public abstract StatementSyntax GenerateSetupStatement(TypePositionInfo info, StubCodeContext context);
public abstract StatementSyntax GenerateUnmanagedToManagedByValueOutMarshalStatement(TypePositionInfo info, StubCodeContext context);
public abstract StatementSyntax GenerateMarshalStatement(TypePositionInfo info, StubCodeContext context);
public abstract StatementSyntax GenerateManagedToUnmanagedByValueOutUnmarshalStatement(TypePositionInfo info, StubCodeContext context);
......@@ -99,7 +99,7 @@ internal sealed class BlittableElementsMarshalling : ElementsMarshalling
private readonly TypeSyntax _unmanagedElementType;
public BlittableElementsMarshalling(TypeSyntax managedElementType, TypeSyntax unmanagedElementType, IElementsMarshallingCollectionSource collectionSource)
:base(collectionSource)
: base(collectionSource)
{
_managedElementType = managedElementType;
_unmanagedElementType = unmanagedElementType;
......@@ -237,6 +237,7 @@ private ExpressionSyntax CastToManagedIfNecessary(ExpressionSyntax expression)
}
public override StatementSyntax GenerateElementCleanupStatement(TypePositionInfo info, StubCodeContext context) => EmptyStatement();
public override StatementSyntax GenerateSetupStatement(TypePositionInfo info, StubCodeContext context) => EmptyStatement();
}
/// <summary>
......@@ -253,7 +254,7 @@ internal sealed class NonBlittableElementsMarshalling : ElementsMarshalling
IMarshallingGenerator elementMarshaller,
TypePositionInfo elementInfo,
IElementsMarshallingCollectionSource collectionSource)
:base(collectionSource)
: base(collectionSource)
{
_unmanagedElementType = unmanagedElementType;
_elementMarshaller = elementMarshaller;
......@@ -267,8 +268,10 @@ public override StatementSyntax GenerateMarshalStatement(TypePositionInfo info,
// ReadOnlySpan<T> <managedSpan> = <GetManagedValuesSource>
// Span<TUnmanagedElement> <nativeSpan> = <GetUnmanagedValuesDestination>
// <if multidimensional collection> <nativeSpan>.Clear()
// << marshal contents >>
return Block(
var statements = new List<StatementSyntax>()
{
LocalDeclarationStatement(VariableDeclaration(
GenericName(
Identifier(TypeNames.System_ReadOnlySpan),
......@@ -285,14 +288,27 @@ public override StatementSyntax GenerateMarshalStatement(TypePositionInfo info,
VariableDeclarator(
Identifier(nativeSpanIdentifier))
.WithInitializer(EqualsValueClause(
CollectionSource.GetUnmanagedValuesDestination(info, context)))))),
GenerateContentsMarshallingStatement(
CollectionSource.GetUnmanagedValuesDestination(info, context))))))
};
// If it is a multidimensional array, we will just clear each allocated span.
if (ShouldCleanUpAllElements(info, context))
{
// <nativeSpanIdentifier>.Clear()
statements.Add(ExpressionStatement(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(nativeSpanIdentifier),
IdentifierName("Clear")))));
}
statements.Add(GenerateContentsMarshallingStatement(
info,
context,
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(MarshallerHelpers.GetManagedSpanIdentifier(info, context)),
IdentifierName("Length")),
_elementInfo, _elementMarshaller, StubCodeContext.Stage.Marshal));
_elementInfo, _elementMarshaller, StubCodeContext.Stage.Marshal));
return Block(statements);
}
public override StatementSyntax GenerateUnmarshalStatement(TypePositionInfo info, StubCodeContext context)
......@@ -408,14 +424,34 @@ public override StatementSyntax GenerateManagedToUnmanagedByValueOutUnmarshalSta
public override StatementSyntax GenerateElementCleanupStatement(TypePositionInfo info, StubCodeContext context)
{
string nativeSpanIdentifier = MarshallerHelpers.GetNativeSpanIdentifier(info, context);
StatementSyntax contentsCleanupStatements = GenerateContentsMarshallingStatement(info, context,
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(MarshallerHelpers.GetNativeSpanIdentifier(info, context)),
IdentifierName("Length")),
_elementInfo, _elementMarshaller, StubCodeContext.Stage.Cleanup);
ExpressionSyntax indexConstraintName;
if (!UsesLastIndexMarshalled(info, context))
{
indexConstraintName = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(nativeSpanIdentifier),
IdentifierName("Length"));
}
else
{
indexConstraintName = IdentifierName(MarshallerHelpers.GetLastIndexMarshalledIdentifier(info, context));
}
StatementSyntax contentsCleanupStatements = GenerateContentsMarshallingStatement(
info,
context,
indexConstraintName,
_elementInfo,
_elementMarshaller,
StubCodeContext.Stage.Cleanup);
if (contentsCleanupStatements.IsKind(SyntaxKind.EmptyStatement))
{
if (UsesLastIndexMarshalled(info, context))
{
return ExpressionStatement(
AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
IdentifierName("_"),
IdentifierName(MarshallerHelpers.GetLastIndexMarshalledIdentifier(info, context))));
}
return EmptyStatement();
}
......@@ -510,23 +546,25 @@ public override StatementSyntax GenerateUnmanagedToManagedByValueOutMarshalState
StubCodeContext.Stage.PinnedMarshal,
StubCodeContext.Stage.Cleanup));
}
private static StatementSyntax GenerateContentsMarshallingStatement(
private static List<StatementSyntax> GenerateElementStages(
TypePositionInfo info,
StubCodeContext context,
ExpressionSyntax lengthExpression,
TypePositionInfo elementInfo,
IMarshallingGenerator elementMarshaller,
TypePositionInfo elementInfo,
out LinearCollectionElementMarshallingCodeContext elementSetupSubContext,
out TypePositionInfo localElementInfo,
params StubCodeContext.Stage[] stagesToGeneratePerElement)
{
string managedSpanIdentifier = MarshallerHelpers.GetManagedSpanIdentifier(info, context);
string nativeSpanIdentifier = MarshallerHelpers.GetNativeSpanIdentifier(info, context);
var elementSetupSubContext = new LinearCollectionElementMarshallingCodeContext(
elementSetupSubContext = new LinearCollectionElementMarshallingCodeContext(
StubCodeContext.Stage.Setup,
managedSpanIdentifier,
nativeSpanIdentifier,
context);
TypePositionInfo localElementInfo = elementInfo with
localElementInfo = elementInfo with
{
InstanceIdentifier = info.InstanceIdentifier,
RefKind = info.IsByRef ? info.RefKind : info.ByValueContentsMarshalKind.GetRefKindForByValueContentsKind(),
......@@ -540,6 +578,18 @@ public override StatementSyntax GenerateUnmanagedToManagedByValueOutMarshalState
var elementSubContext = elementSetupSubContext with { CurrentStage = stage };
elementStatements.AddRange(elementMarshaller.Generate(localElementInfo, elementSubContext));
}
return elementStatements;
}
private static StatementSyntax GenerateContentsMarshallingStatement(
TypePositionInfo info,
StubCodeContext context,
ExpressionSyntax lengthExpression,
TypePositionInfo elementInfo,
IMarshallingGenerator elementMarshaller,
params StubCodeContext.Stage[] stagesToGeneratePerElement)
{
var elementStatements = GenerateElementStages(info, context, elementMarshaller, elementInfo, out var elementSetupSubContext, out var localElementInfo, stagesToGeneratePerElement);
if (elementStatements.Count != 0)
{
......@@ -554,11 +604,56 @@ public override StatementSyntax GenerateUnmanagedToManagedByValueOutMarshalState
}
// Iterate through the elements of the native collection to marshal them
return MarshallerHelpers.GetForLoop(lengthExpression, elementSetupSubContext.IndexerIdentifier)
var forLoop = MarshallerHelpers.GetForLoop(lengthExpression, elementSetupSubContext.IndexerIdentifier)
.WithStatement(marshallingStatement);
// If we're tracking LastIndexMarshalled, increment that each iteration as well.
if (UsesLastIndexMarshalled(info, context) && stagesToGeneratePerElement.Contains(StubCodeContext.Stage.Marshal))
{
forLoop = forLoop.AddIncrementors(
PrefixUnaryExpression(SyntaxKind.PreIncrementExpression,
IdentifierName(MarshallerHelpers.GetLastIndexMarshalledIdentifier(info, context))));
}
return forLoop;
}
return EmptyStatement();
}
private static bool UsesLastIndexMarshalled(TypePositionInfo info, StubCodeContext context)
{
bool shouldCleanupAllElements = ShouldCleanUpAllElements(info, context);
if (shouldCleanupAllElements)
{
return false;
}
bool onlyUnmarshals = MarshallerHelpers.GetMarshalDirection(info, context) == MarshalDirection.UnmanagedToManaged;
if (onlyUnmarshals)
{
return false;
}
bool usesLastIndexMarshalled = !shouldCleanupAllElements && !onlyUnmarshals;
return usesLastIndexMarshalled;
}
private static bool ShouldCleanUpAllElements(TypePositionInfo info, StubCodeContext context)
{
_ = info;
_ = context;
// AdditionalTemporaryStateLivesAcrossStages implies that it is an outer collection
// Out parameters means that the contents are created by the P/Invoke and assumed to have successfully created all elements
return !context.AdditionalTemporaryStateLivesAcrossStages || info.ByValueContentsMarshalKind == ByValueContentsMarshalKind.Out || info.RefKind == RefKind.Out;
}
public override StatementSyntax GenerateSetupStatement(TypePositionInfo info, StubCodeContext context)
=> UsesLastIndexMarshalled(info, context)
? LocalDeclarationStatement(
VariableDeclaration(
PredefinedType(Token(SyntaxKind.IntKeyword)),
SingletonSeparatedList(
VariableDeclarator(
Identifier(MarshallerHelpers.GetLastIndexMarshalledIdentifier(info, context)),
null,
EqualsValueClause(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0)))))))
: EmptyStatement();
}
}
// 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 Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Linq;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace Microsoft.Interop
......@@ -147,6 +146,11 @@ public static string GetNumElementsIdentifier(TypePositionInfo info, StubCodeCon
return context.GetAdditionalIdentifier(info, "numElements");
}
public static string GetLastIndexMarshalledIdentifier(TypePositionInfo info, StubCodeContext context)
{
return context.GetAdditionalIdentifier(info, "lastIndexMarshalled");
}
internal static bool CanUseCallerAllocatedBuffer(TypePositionInfo info, StubCodeContext context)
{
return context.SingleFrameSpansNativeContext && (!info.IsByRef || info.RefKind == RefKind.In);
......
// 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 Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
......@@ -433,6 +431,12 @@ public IEnumerable<StatementSyntax> GenerateSetupStatements(TypePositionInfo inf
PredefinedType(Token(SyntaxKind.IntKeyword)),
SingletonSeparatedList(
VariableDeclarator(numElementsIdentifier))));
var elementsSetup = _elementsMarshalling.GenerateSetupStatement(info, context);
if (elementsSetup is not EmptyStatementSyntax)
{
yield return elementsSetup;
}
// Use the numElements local to ensure the compiler doesn't give errors for using an uninitialized variable.
// The value will never be used unless it has been initialized, so this is safe.
yield return MarshallerHelpers.SkipInitOrDefaultInit(
......@@ -456,7 +460,7 @@ public IEnumerable<StatementSyntax> GenerateUnmarshalStatements(TypePositionInfo
{
// If the parameter is marshalled by-value [Out], then we don't marshal the contents of the collection.
// We do clear the span, so that if the invoke target doesn't fill it, we aren't left with undefined content.
yield return _elementsMarshalling.GenerateClearUnmanagedValuesSource(info, context);
yield return _elementsMarshalling.GenerateClearManagedValuesDestination(info, context);
yield break;
}
......
......@@ -3,8 +3,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
......@@ -318,7 +316,21 @@ public ManagedTypeInfo AsNativeType(TypePositionInfo info)
return _unmanagedType;
}
public IEnumerable<StatementSyntax> GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) => Array.Empty<StatementSyntax>();
public IEnumerable<StatementSyntax> GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context)
{
if (MarshallerHelpers.GetMarshalDirection(info, context) == MarshalDirection.ManagedToUnmanaged)
{
yield return EmptyStatement();
yield break;
}
string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);
yield return ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName(numElementsIdentifier),
_numElementsExpression));
}
public IEnumerable<StatementSyntax> GenerateGuaranteedUnmarshalStatements(TypePositionInfo info, StubCodeContext context)
{
......@@ -521,6 +533,7 @@ internal sealed class StatelessLinearCollectionMarshalling : ICustomTypeMarshall
private readonly ElementsMarshalling _elementsMarshalling;
private readonly ManagedTypeInfo _unmanagedType;
private readonly MarshallerShape _shape;
private readonly ExpressionSyntax _numElementsExpression;
private readonly bool _cleanupElementsAndSpace;
public StatelessLinearCollectionMarshalling(
......@@ -528,12 +541,14 @@ internal sealed class StatelessLinearCollectionMarshalling : ICustomTypeMarshall
ElementsMarshalling elementsMarshalling,
ManagedTypeInfo unmanagedType,
MarshallerShape shape,
ExpressionSyntax numElementsExpression,
bool cleanupElementsAndSpace)
{
_spaceMarshallingStrategy = spaceMarshallingStrategy;
_elementsMarshalling = elementsMarshalling;
_unmanagedType = unmanagedType;
_shape = shape;
_numElementsExpression = numElementsExpression;
_cleanupElementsAndSpace = cleanupElementsAndSpace;
}
......@@ -545,11 +560,20 @@ public IEnumerable<StatementSyntax> GenerateCleanupStatements(TypePositionInfo i
{
yield break;
}
StatementSyntax elementCleanup = _elementsMarshalling.GenerateElementCleanupStatement(info, context);
if (!elementCleanup.IsKind(SyntaxKind.EmptyStatement))
{
// If we don't have the numElements variable still available from unmarshal or marshal stage, we need to reassign that again
if (!context.AdditionalTemporaryStateLivesAcrossStages)
{
string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);
yield return ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName(numElementsIdentifier),
_numElementsExpression));
}
yield return elementCleanup;
}
......@@ -594,7 +618,16 @@ public IEnumerable<StatementSyntax> GenerateMarshalStatements(TypePositionInfo i
public IEnumerable<StatementSyntax> GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context) => _spaceMarshallingStrategy.GeneratePinnedMarshalStatements(info, context);
public IEnumerable<StatementSyntax> GeneratePinStatements(TypePositionInfo info, StubCodeContext context) => _spaceMarshallingStrategy.GeneratePinStatements(info, context);
public IEnumerable<StatementSyntax> GenerateSetupStatements(TypePositionInfo info, StubCodeContext context) => _spaceMarshallingStrategy.GenerateSetupStatements(info, context);
public IEnumerable<StatementSyntax> GenerateSetupStatements(TypePositionInfo info, StubCodeContext context)
{
foreach (var s in _spaceMarshallingStrategy.GenerateSetupStatements(info, context))
yield return s;
var elementsSetup = _elementsMarshalling.GenerateSetupStatement(info, context);
if (elementsSetup is not EmptyStatementSyntax)
{
yield return elementsSetup;
}
}
public IEnumerable<StatementSyntax> GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) => Array.Empty<StatementSyntax>();
......@@ -612,7 +645,7 @@ public IEnumerable<StatementSyntax> GenerateUnmarshalStatements(TypePositionInfo
{
// If the parameter is marshalled by-value [Out], then we don't marshal the contents of the collection.
// We do clear the span, so that if the invoke target doesn't fill it, we aren't left with undefined content.
yield return _elementsMarshalling.GenerateClearUnmanagedValuesSource(info, context);
yield return _elementsMarshalling.GenerateClearManagedValuesDestination(info, context);
yield break;
}
......
// 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.Collections.Immutable;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
......@@ -65,7 +61,7 @@ static void AppendVariableDeclarations(ImmutableArray<LocalDeclarationStatementS
statementsToUpdate.Add(MarshallerHelpers.Declare(
marshaller.TypeInfo.ManagedType.Syntax,
managed,
false));
initializeToDefault));
}
// Declare variable with native type for parameter or return value
......
......@@ -4,15 +4,21 @@
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ReferencesNativeExports>true</ReferencesNativeExports>
<EnableLibraryImportGenerator>true</EnableLibraryImportGenerator>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<!-- Declare InteropCompilerGeneratedFilesOutputPath to put generated files in a single repo to easily view diffs -->
<CompilerGeneratedFilesOutputPath Condition="'$(InteropCompilerGeneratedFilesOutputPath)' == ''">$(OutputPath)\Generated</CompilerGeneratedFilesOutputPath>
<CompilerGeneratedFilesOutputPath Condition="'$(InteropCompilerGeneratedFilesOutputPath)' != ''">$(InteropCompilerGeneratedFilesOutputPath)\ComInterfaceGenerator.Tests</CompilerGeneratedFilesOutputPath>
<EnableDefaultItems>true</EnableDefaultItems>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(CommonPath)DisableRuntimeMarshalling.cs" Link="Common\DisableRuntimeMarshalling.cs" />
<Compile Include="..\TestAssets\SharedTypes\ComInterfaces\*.cs" Link="ComInterfaces\%(FileName).cs" />
<Compile Include="..\TestAssets\SharedTypes\ComInterfaces\**\*.cs" Link="ComInterfaces\%(RecursiveDir)\%(FileName).cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\gen\ComInterfaceGenerator\ComInterfaceGenerator.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
<ProjectReference Include="..\Ancillary.Interop\Ancillary.Interop.csproj" />
<ProjectReference Include="..\TestAssets\NativeExports\NativeExports.csproj" />
<ProjectReference Include="..\TestAssets\SharedTypes\SharedTypes.csproj" />
......
......@@ -2,12 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Runtime.InteropServices.Marshalling;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using SharedTypes.ComInterfaces;
using SharedTypes.ComInterfaces.MarshallingFails;
using Xunit;
using static ComInterfaceGenerator.Tests.ComInterfaces;
using System.Collections.Generic;
namespace ComInterfaceGenerator.Tests
{
......@@ -105,6 +105,62 @@ public void ICollectionMarshallingFails()
obj.Set(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 })
);
}
[ActiveIssue("https://github.com/dotnet/runtime/issues/88111")]
[Fact]
public void IJaggedArrayMarshallingFails()
{
var obj = CreateWrapper<IJaggedIntArrayMarshallingFailsImpl, IJaggedIntArrayMarshallingFails>();
Assert.Throws<ArgumentException>(() =>
_ = obj.Get(out _, out _)
);
var array = new int[][] { new int[] { 1, 2, 3 }, new int[] { 4, 5, }, new int[] { 6, 7, 8, 9 } };
var length = 3;
var widths = new int[] { 3, 2, 4 };
Assert.Throws<ArgumentException>(() =>
obj.Set(array, widths, length)
);
}
[Fact]
public void IStringArrayMarshallingFails()
{
var obj = CreateWrapper<IStringArrayMarshallingFailsImpl, IStringArrayMarshallingFails>();
var strings = IStringArrayMarshallingFailsImpl.StartingStrings;
// All of these will marshal either to COM or the CCW will marshal on the return
Assert.Throws<ArgumentException>(() =>
{
obj.Param(strings);
});
Assert.Throws<ArgumentException>(() =>
{
obj.RefParam(ref strings);
});
Assert.Throws<ArgumentException>(() =>
{
obj.InParam(in strings);
});
Assert.Throws<ArgumentException>(() =>
{
obj.OutParam(out strings);
});
// https://github.com/dotnet/runtime/issues/87845
//Assert.Throws<ArgumentException>(() =>
//{
// obj.ByValueOutParam(strings);
//});
Assert.Throws<ArgumentException>(() =>
{
obj.ByValueInOutParam(strings);
});
Assert.Throws<ArgumentException>(() =>
{
_ = obj.ReturnValue();
});
}
}
public static partial class ComInterfaces
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SharedTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Text;
using SharedTypes;
using Xunit;
namespace LibraryImportGenerator.IntegrationTests
......@@ -30,7 +28,7 @@ public partial class Arrays
public static partial void Duplicate([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref int[] values, int numValues);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array")]
[return:MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
[return: MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
public static partial int[] CreateRange(int start, int end, out int numValues);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "create_range_array_out")]
......@@ -59,7 +57,7 @@ public partial class Arrays
public static partial void ReverseStrings_Out([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] strArray, out int numElements, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 1)] out string[] res);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes")]
[return:MarshalAs(UnmanagedType.LPArray, SizeConst = sizeof(long))]
[return: MarshalAs(UnmanagedType.LPArray, SizeConst = sizeof(long))]
public static partial byte[] GetLongBytes(long l);
[LibraryImport(NativeExportsNE_Binary, EntryPoint = "append_int_to_array")]
......@@ -285,7 +283,7 @@ public unsafe void PointerArray_Return()
private static string[] GetStringArray()
{
return new []
return new[]
{
"ABCdef 123$%^",
"\uD83C\uDF5C !! \uD83C\uDF5C !!",
......@@ -362,11 +360,11 @@ public void ConstantSizeArray()
[Fact]
public void DynamicSizedArrayWithConstantComponent()
{
var array = new [] { 1, 5, 79, 165, 32, 3 };
var array = new[] { 1, 5, 79, 165, 32, 3 };
int newValue = 42;
var newArray = array;
NativeExportsNE.Arrays.Append(ref newArray, array.Length, newValue);
Assert.Equal(array.Concat(new [] { newValue }), newArray);
Assert.Equal(array.Concat(new[] { newValue }), newArray);
}
[Fact]
......
......@@ -5,6 +5,10 @@
<EnableLibraryImportGenerator>true</EnableLibraryImportGenerator>
<IncludeLibraryImportGeneratorSources>false</IncludeLibraryImportGeneratorSources>
<ReferencesNativeExports>true</ReferencesNativeExports>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<!-- Declare InteropCompilerGeneratedFilesOutputPath to put generated files in a single repo to easily view diffs -->
<CompilerGeneratedFilesOutputPath Condition="'$(InteropCompilerGeneratedFilesOutputPath)' == ''">$(OutputPath)\Generated</CompilerGeneratedFilesOutputPath>
<CompilerGeneratedFilesOutputPath Condition="'$(InteropCompilerGeneratedFilesOutputPath)' != ''">$(InteropCompilerGeneratedFilesOutputPath)\LibraryImportGenerator.Tests</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SharedTypes;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using static SharedTypes.BoolStructMarshaller;
using SharedTypes;
namespace NativeExports
{
......@@ -128,6 +127,27 @@ public static byte FillRange([DNNE.C99Type("struct int_struct_wrapper*")] IntStr
return 1;
}
[UnmanagedCallersOnly(EntryPoint = "fill_range_array_2d")]
[DNNE.C99DeclCode("struct int_struct_wrapper;")]
public static byte FillRange2D([DNNE.C99Type("struct int_struct_wrapper**")] IntStructWrapperNative** numValues, int length, int* widths, int start)
{
if (numValues == null)
{
return 0;
}
for (int i = 0; i < length; i++)
{
numValues[i] = (IntStructWrapperNative*)Marshal.AllocCoTaskMem(sizeof(IntStructWrapperNative) * widths[i]);
for (int j = 0; j < widths[i]; j++, start++)
{
numValues[i][j] = new IntStructWrapperNative { value = start };
}
}
return 1;
}
[UnmanagedCallersOnly(EntryPoint = "double_values")]
[DNNE.C99DeclCode("struct int_struct_wrapper { int value; };")]
public static void DoubleValues([DNNE.C99Type("struct int_struct_wrapper*")] IntStructWrapperNative* numValues, int length)
......@@ -291,6 +311,25 @@ public static byte AndBoolStructsIn([DNNE.C99Type("struct bool_struct**")] BoolS
}
}
[UnmanagedCallersOnly(EntryPoint = "negate_bool_struct_array_ref_2d")]
[DNNE.C99DeclCode("struct bool_struct;")]
public static void NegateBoolStructsRef2D(
[DNNE.C99Type("struct bool_struct**")] BoolStructMarshaller.BoolStructNative*** array,
int length,
int* widths)
{
for (int i = 0; i < length; i++)
{
for (int j = 0; j < widths[i]; j++)
{
BoolStructMarshaller.BoolStructNative boolStruct = *(array[i][j]);
(*array)[i][j].b1 = (byte)(boolStruct.b1 != 0 ? 0 : 1);
(*array)[i][j].b2 = (byte)(boolStruct.b2 != 0 ? 0 : 1);
(*array)[i][j].b3 = (byte)(boolStruct.b3 != 0 ? 0 : 1);
}
}
}
[UnmanagedCallersOnly(EntryPoint = "negate_bool_struct_array_out")]
[DNNE.C99DeclCode("struct bool_struct;")]
public static void NegateBoolStructsOut(
......@@ -301,6 +340,21 @@ public static byte AndBoolStructsIn([DNNE.C99Type("struct bool_struct**")] BoolS
*outArray = NegateBoolStructsImpl(array, length);
}
[UnmanagedCallersOnly(EntryPoint = "negate_bool_struct_array_out_2d")]
[DNNE.C99DeclCode("struct bool_struct;")]
public static void NegateBoolStructsOut2D(
[DNNE.C99Type("struct bool_struct**")] BoolStructMarshaller.BoolStructNative** array,
int length,
int* widths,
[DNNE.C99Type("struct bool_struct***")] BoolStructMarshaller.BoolStructNative*** outArray)
{
*outArray = (BoolStructMarshaller.BoolStructNative**)Marshal.AllocCoTaskMem(sizeof(BoolStructMarshaller.BoolStructNative**) * length);
for (int i = 0; i < length; i++)
{
(*outArray)[i] = NegateBoolStructsImpl(array[i], widths[i]);
}
}
[UnmanagedCallersOnly(EntryPoint = "negate_bool_struct_array_return")]
[DNNE.C99DeclCode("struct bool_struct;")]
[return: DNNE.C99Type("struct bool_struct*")]
......
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
......@@ -19,7 +19,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\TestAssets\SharedTypes\ComInterfaces\*.cs" Link="ComInterfaceGenerator\ComInterfaces\%(FileName).cs" />
<Compile Include="..\..\TestAssets\SharedTypes\ComInterfaces\**\*.cs" Link="ComInterfaceGenerator\ComInterfaces\%(RecursiveDir)\%(FileName).cs" />
<Compile Include="$(CommonPath)DisableRuntimeMarshalling.cs" Link="Common\DisableRuntimeMarshalling.cs" />
</ItemGroup>
......
// 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.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
namespace SharedTypes.ComInterfaces.MarshallingFails
{
/// <summary>
/// Has methods that marshal a string array in different ways
/// </summary>
[GeneratedComInterface(StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshallingFails))]
[Guid("BE11C211-76D5-496F-A117-82F5D13208F7")]
internal partial interface IStringArrayMarshallingFails
{
public void Param([MarshalUsing(ConstantElementCount = 10)] string[] value);
public void InParam([MarshalUsing(ConstantElementCount = 10)] in string[] value);
public void RefParam([MarshalUsing(ConstantElementCount = 10)] ref string[] value);
public void OutParam([MarshalUsing(ConstantElementCount = 10)] out string[] value);
public void ByValueOutParam([MarshalUsing(ConstantElementCount = 10)][Out] string[] value);
public void ByValueInOutParam([MarshalUsing(ConstantElementCount = 10)][In, Out] string[] value);
[return: MarshalUsing(ConstantElementCount = 10)]
public string[] ReturnValue();
}
/// <summary>
/// Implements IStringArrayMarshallingFails.
/// </summary>
[GeneratedComClass]
internal partial class IStringArrayMarshallingFailsImpl : IStringArrayMarshallingFails
{
public static string[] StartingStrings { get; } = new string[] { "Hello", "World", "Lorem", "Ipsum", "Dolor", "Sample", "Text", ".Net", "Interop", "string" };
private string[] _strings = StartingStrings;
public void ByValueInOutParam([In, MarshalUsing(ConstantElementCount = 10), Out] string[] value) => value[0] = _strings[0];
public void ByValueOutParam([MarshalUsing(ConstantElementCount = 10), Out] string[] value) => value = _strings;
public void InParam([MarshalUsing(ConstantElementCount = 10)] in string[] value) => value[0] = _strings[0];
public void OutParam([MarshalUsing(ConstantElementCount = 10)] out string[] value) => value = _strings;
public void Param([MarshalUsing(ConstantElementCount = 10)] string[] value) => value[0] = _strings[0];
public void RefParam([MarshalUsing(ConstantElementCount = 10)] ref string[] value) => value[0] = _strings[0];
[return: MarshalUsing(ConstantElementCount = 10)]
public string[] ReturnValue() => _strings;
}
/// <summary>
/// Marshals and unmarshals elements of string arrays, throwing an exception instead of marshalling the element number <see cref="ThrowOnNthMarshalledElement"/>
/// </summary>
[CustomMarshaller(typeof(string), MarshalMode.ElementIn, typeof(StringMarshallingFails))]
[CustomMarshaller(typeof(string), MarshalMode.ElementOut, typeof(StringMarshallingFails))]
[CustomMarshaller(typeof(string), MarshalMode.ElementRef, typeof(StringMarshallingFails))]
internal static unsafe class StringMarshallingFails
{
static int _marshalledCount = 0;
const int ThrowOnNthMarshalledElement = 4;
public static nint ConvertToUnmanaged(string managed)
{
if (++_marshalledCount == ThrowOnNthMarshalledElement)
{
_marshalledCount = 0;
throw new ArgumentException("This marshaller throws on the Nth element marshalled where N = " + ThrowOnNthMarshalledElement);
}
return (nint)Utf8StringMarshaller.ConvertToUnmanaged(managed);
}
public static string ConvertToManaged(nint unmanaged)
{
return Utf8StringMarshaller.ConvertToManaged((byte*)unmanaged);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册