Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.

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

namespace Microsoft.Interop.JavaScript
{
Expand Down Expand Up @@ -61,13 +61,13 @@ public BlockSyntax GenerateJSExportBody()
{
StatementSyntax invoke = InvokeSyntax();
GeneratedStatements statements = GeneratedStatements.Create(_marshallers, _context);
bool shouldInitializeVariables = !statements.GuaranteedUnmarshal.IsEmpty || !statements.Cleanup.IsEmpty;
bool shouldInitializeVariables = !statements.GuaranteedUnmarshal.IsEmpty || !statements.CleanupCallerAllocated.IsEmpty || !statements.CleanupCalleeAllocated.IsEmpty;
VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForUnmanagedToManaged(_marshallers, _context, shouldInitializeVariables);

var setupStatements = new List<StatementSyntax>();
SetupSyntax(setupStatements);

if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
setupStatements.Add(MarshallerHelpers.Declare(PredefinedType(Token(SyntaxKind.BoolKeyword)), InvokeSucceededIdentifier, initializeToDefault: true));
}
Expand All @@ -81,7 +81,7 @@ public BlockSyntax GenerateJSExportBody()

tryStatements.Add(invoke);

if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
tryStatements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
IdentifierName(InvokeSucceededIdentifier),
Expand All @@ -94,12 +94,12 @@ public BlockSyntax GenerateJSExportBody()

List<StatementSyntax> allStatements = setupStatements;
List<StatementSyntax> finallyStatements = new List<StatementSyntax>();
if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
finallyStatements.Add(IfStatement(IdentifierName(InvokeSucceededIdentifier), Block(statements.GuaranteedUnmarshal)));
finallyStatements.Add(IfStatement(IdentifierName(InvokeSucceededIdentifier), Block(statements.GuaranteedUnmarshal.Concat(statements.CleanupCalleeAllocated))));
}

finallyStatements.AddRange(statements.Cleanup);
finallyStatements.AddRange(statements.CleanupCallerAllocated);
if (finallyStatements.Count > 0)
{
allStatements.Add(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ public BlockSyntax GenerateJSImportBody()
{
StatementSyntax invoke = InvokeSyntax();
GeneratedStatements statements = GeneratedStatements.Create(_marshallers, _context);
bool shouldInitializeVariables = !statements.GuaranteedUnmarshal.IsEmpty || !statements.Cleanup.IsEmpty;
bool shouldInitializeVariables = !statements.GuaranteedUnmarshal.IsEmpty || !statements.CleanupCallerAllocated.IsEmpty || !statements.CleanupCalleeAllocated.IsEmpty;
VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForManagedToUnmanaged(_marshallers, _context, shouldInitializeVariables);

var setupStatements = new List<StatementSyntax>();
BindSyntax(setupStatements);
SetupSyntax(setupStatements);

if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
setupStatements.Add(MarshallerHelpers.Declare(PredefinedType(Token(SyntaxKind.BoolKeyword)), InvokeSucceededIdentifier, initializeToDefault: true));
}
Expand All @@ -88,7 +88,7 @@ public BlockSyntax GenerateJSImportBody()
tryStatements.AddRange(statements.PinnedMarshal);

tryStatements.Add(invoke);
if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
tryStatements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
IdentifierName(InvokeSucceededIdentifier),
Expand All @@ -100,12 +100,12 @@ public BlockSyntax GenerateJSImportBody()

List<StatementSyntax> allStatements = setupStatements;
List<StatementSyntax> finallyStatements = new List<StatementSyntax>();
if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
finallyStatements.Add(IfStatement(IdentifierName(InvokeSucceededIdentifier), Block(statements.GuaranteedUnmarshal)));
finallyStatements.Add(IfStatement(IdentifierName(InvokeSucceededIdentifier), Block(statements.GuaranteedUnmarshal.Concat(statements.CleanupCalleeAllocated))));
}

finallyStatements.AddRange(statements.Cleanup);
finallyStatements.AddRange(statements.CleanupCallerAllocated);
if (finallyStatements.Count > 0)
{
// Add try-finally block if there are any statements in the finally block
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public BlockSyntax GenerateStubBody(int index, ImmutableArray<FunctionPointerUnm
BracketedArgumentList(SingletonSeparatedList(
Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(index)))))),
callConv));
bool shouldInitializeVariables = !statements.GuaranteedUnmarshal.IsEmpty || !statements.Cleanup.IsEmpty;
bool shouldInitializeVariables = !statements.GuaranteedUnmarshal.IsEmpty || !statements.CleanupCallerAllocated.IsEmpty || !statements.CleanupCalleeAllocated.IsEmpty;
VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForManagedToUnmanaged(_marshallers, _context, shouldInitializeVariables);

if (_setLastError)
Expand All @@ -143,7 +143,7 @@ public BlockSyntax GenerateStubBody(int index, ImmutableArray<FunctionPointerUnm
initializeToDefault: false));
}

if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
setupStatements.Add(MarshallerHelpers.Declare(PredefinedType(Token(SyntaxKind.BoolKeyword)), InvokeSucceededIdentifier, initializeToDefault: true));
}
Expand Down Expand Up @@ -174,7 +174,7 @@ public BlockSyntax GenerateStubBody(int index, ImmutableArray<FunctionPointerUnm
tryStatements.AddRange(statements.NotifyForSuccessfulInvoke);

// <invokeSucceeded> = true;
if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
tryStatements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
IdentifierName(InvokeSucceededIdentifier),
Expand All @@ -197,12 +197,12 @@ public BlockSyntax GenerateStubBody(int index, ImmutableArray<FunctionPointerUnm

List<StatementSyntax> allStatements = setupStatements;
List<StatementSyntax> finallyStatements = new List<StatementSyntax>();
if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
finallyStatements.Add(IfStatement(IdentifierName(InvokeSucceededIdentifier), Block(statements.GuaranteedUnmarshal)));
finallyStatements.Add(IfStatement(IdentifierName(InvokeSucceededIdentifier), Block(statements.GuaranteedUnmarshal.Concat(statements.CleanupCalleeAllocated))));
}

finallyStatements.AddRange(statements.Cleanup);
finallyStatements.AddRange(statements.CleanupCallerAllocated);
if (finallyStatements.Count > 0)
{
// Add try-finally block if there are any statements in the finally block
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
Expand Down Expand Up @@ -52,9 +53,11 @@ public BlockSyntax GenerateStubBody(ExpressionSyntax methodToInvoke)
_marshallers,
_context,
methodToInvoke);
Debug.Assert(statements.CleanupCalleeAllocated.IsEmpty);

bool shouldInitializeVariables =
!statements.GuaranteedUnmarshal.IsEmpty
|| !statements.Cleanup.IsEmpty
|| !statements.CleanupCallerAllocated.IsEmpty
|| !statements.ManagedExceptionCatchClauses.IsEmpty;
VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForUnmanagedToManaged(_marshallers, _context, shouldInitializeVariables);

Expand All @@ -77,7 +80,7 @@ public BlockSyntax GenerateStubBody(ExpressionSyntax methodToInvoke)

SyntaxList<CatchClauseSyntax> catchClauses = List(statements.ManagedExceptionCatchClauses);

finallyStatements.AddRange(statements.Cleanup);
finallyStatements.AddRange(statements.CleanupCallerAllocated);
if (finallyStatements.Count > 0)
{
allStatements.Add(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp;
Expand Down Expand Up @@ -107,7 +108,7 @@ public PInvokeStubCodeGenerator(
public BlockSyntax GeneratePInvokeBody(string dllImportName)
{
GeneratedStatements statements = GeneratedStatements.Create(_marshallers, _context, IdentifierName(dllImportName));
bool shouldInitializeVariables = !statements.GuaranteedUnmarshal.IsEmpty || !statements.Cleanup.IsEmpty;
bool shouldInitializeVariables = !statements.GuaranteedUnmarshal.IsEmpty || !statements.CleanupCallerAllocated.IsEmpty || !statements.CleanupCalleeAllocated.IsEmpty;
VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForManagedToUnmanaged(_marshallers, _context, shouldInitializeVariables);

var setupStatements = new List<StatementSyntax>();
Expand All @@ -121,7 +122,7 @@ public BlockSyntax GeneratePInvokeBody(string dllImportName)
initializeToDefault: false));
}

if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
setupStatements.Add(MarshallerHelpers.Declare(PredefinedType(Token(SyntaxKind.BoolKeyword)), InvokeSucceededIdentifier, initializeToDefault: true));
}
Expand All @@ -148,7 +149,7 @@ public BlockSyntax GeneratePInvokeBody(string dllImportName)
}
tryStatements.Add(statements.Pin.NestFixedStatements(fixedBlock));
// <invokeSucceeded> = true;
if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
tryStatements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
IdentifierName(InvokeSucceededIdentifier),
Expand All @@ -160,12 +161,12 @@ public BlockSyntax GeneratePInvokeBody(string dllImportName)

List<StatementSyntax> allStatements = setupStatements;
List<StatementSyntax> finallyStatements = new List<StatementSyntax>();
if (!statements.GuaranteedUnmarshal.IsEmpty)
if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty))
{
finallyStatements.Add(IfStatement(IdentifierName(InvokeSucceededIdentifier), Block(statements.GuaranteedUnmarshal)));
finallyStatements.Add(IfStatement(IdentifierName(InvokeSucceededIdentifier), Block(statements.GuaranteedUnmarshal.Concat(statements.CleanupCalleeAllocated))));
}

finallyStatements.AddRange(statements.Cleanup);
finallyStatements.AddRange(statements.CleanupCallerAllocated);
if (finallyStatements.Count > 0)
{
// Add try-finally block if there are any statements in the finally block
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public struct GeneratedStatements
public ImmutableArray<StatementSyntax> Unmarshal { get; init; }
public ImmutableArray<StatementSyntax> NotifyForSuccessfulInvoke { get; init; }
public ImmutableArray<StatementSyntax> GuaranteedUnmarshal { get; init; }
public ImmutableArray<StatementSyntax> Cleanup { get; init; }
public ImmutableArray<StatementSyntax> CleanupCallerAllocated { get; init; }
public ImmutableArray<StatementSyntax> CleanupCalleeAllocated { get; init; }

public ImmutableArray<CatchClauseSyntax> ManagedExceptionCatchClauses { get; init; }

Expand All @@ -38,7 +39,8 @@ public static GeneratedStatements Create(BoundGenerators marshallers, StubCodeCo
.AddRange(GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.Unmarshal })),
NotifyForSuccessfulInvoke = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.NotifyForSuccessfulInvoke }),
GuaranteedUnmarshal = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.GuaranteedUnmarshal }),
Cleanup = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.Cleanup }),
CleanupCallerAllocated = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.CleanupCallerAllocated }),
CleanupCalleeAllocated = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.CleanupCalleeAllocated }),
ManagedExceptionCatchClauses = GenerateCatchClauseForManagedException(marshallers, context)
};
}
Expand Down Expand Up @@ -182,7 +184,8 @@ private static SyntaxTriviaList GenerateStageTrivia(StubCodeContext.Stage stage)
StubCodeContext.Stage.Invoke => "Call the P/Invoke.",
StubCodeContext.Stage.UnmarshalCapture => "Capture the native data into marshaller instances in case conversion to managed data throws an exception.",
StubCodeContext.Stage.Unmarshal => "Convert native data to managed data.",
StubCodeContext.Stage.Cleanup => "Perform required cleanup.",
StubCodeContext.Stage.CleanupCallerAllocated => "Perform cleanup of caller allocated resources.",
StubCodeContext.Stage.CleanupCalleeAllocated => "Perform cleanup of callee allocated resources.",
StubCodeContext.Stage.NotifyForSuccessfulInvoke => "Keep alive any managed objects that need to stay alive across the call.",
StubCodeContext.Stage.GuaranteedUnmarshal => "Convert native data to managed data even in the case of an exception during the non-cleanup phases.",
_ => throw new ArgumentOutOfRangeException(nameof(stage))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeCont
return _nativeTypeMarshaller.GenerateGuaranteedUnmarshalStatements(info, context);
}
break;
case StubCodeContext.Stage.Cleanup:
case StubCodeContext.Stage.CleanupCallerAllocated when GetCleanupStage(info, context) is StubCodeContext.Stage.CleanupCallerAllocated:
return _nativeTypeMarshaller.GenerateCleanupStatements(info, context);
case StubCodeContext.Stage.CleanupCalleeAllocated when GetCleanupStage(info, context) is StubCodeContext.Stage.CleanupCalleeAllocated:
return _nativeTypeMarshaller.GenerateCleanupStatements(info, context);
default:
break;
Expand All @@ -115,6 +117,20 @@ private bool ShouldGenerateByValueOutMarshalling(TypePositionInfo info, StubCode
&& !_isPinned;
}

/// <summary>
/// Returns which stage cleanup should be performed for the parameter.
/// </summary>
private static StubCodeContext.Stage GetCleanupStage(TypePositionInfo info, StubCodeContext context)
{
if (context.Direction is MarshalDirection.UnmanagedToManaged)
return StubCodeContext.Stage.CleanupCallerAllocated;

if (MarshallerHelpers.GetMarshalDirection(info, context) is MarshalDirection.UnmanagedToManaged)
return StubCodeContext.Stage.CleanupCalleeAllocated;

return StubCodeContext.Stage.CleanupCallerAllocated;
}

public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context)
{
return _nativeTypeMarshaller.UsesNativeIdentifier(info, context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,8 @@ public override StatementSyntax GenerateElementCleanupStatement(TypePositionInfo
indexConstraintName,
_elementInfo,
_elementMarshaller,
StubCodeContext.Stage.Cleanup);
StubCodeContext.Stage.CleanupCallerAllocated,
StubCodeContext.Stage.CleanupCalleeAllocated);

if (contentsCleanupStatements.IsKind(SyntaxKind.EmptyStatement))
{
Expand Down Expand Up @@ -543,7 +544,8 @@ public override StatementSyntax GenerateUnmanagedToManagedByValueOutMarshalState
new FreeAlwaysOwnedOriginalValueGenerator(_elementMarshaller),
StubCodeContext.Stage.Marshal,
StubCodeContext.Stage.PinnedMarshal,
StubCodeContext.Stage.Cleanup));
StubCodeContext.Stage.CleanupCallerAllocated,
StubCodeContext.Stage.CleanupCalleeAllocated));
}

private static List<StatementSyntax> GenerateElementStages(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeCont
IdentifierName(newHandleObjectIdentifier)))));
}
break;
case StubCodeContext.Stage.Cleanup:
case StubCodeContext.Stage.CleanupCallerAllocated:
if (!info.IsManagedReturnPosition && (!info.IsByRef || info.RefKind == RefKind.In))
{
yield return IfStatement(
Expand Down
Loading