forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUnmanagedToManagedStubGenerator.cs
More file actions
108 lines (90 loc) · 4.77 KB
/
Copy pathUnmanagedToManagedStubGenerator.cs
File metadata and controls
108 lines (90 loc) · 4.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// 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 Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace Microsoft.Interop
{
internal sealed class UnmanagedToManagedStubGenerator
{
private const string ReturnIdentifier = "__retVal";
private readonly BoundGenerators _marshallers;
private readonly NativeToManagedStubCodeContext _context;
public UnmanagedToManagedStubGenerator(
TargetFramework targetFramework,
Version targetFrameworkVersion,
ImmutableArray<TypePositionInfo> argTypes,
GeneratorDiagnosticsBag diagnosticsBag,
IMarshallingGeneratorFactory generatorFactory)
{
_context = new NativeToManagedStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier);
_marshallers = BoundGenerators.Create(argTypes, generatorFactory, _context, new Forwarder(), out var bindingDiagnostics);
diagnosticsBag.ReportGeneratorDiagnostics(bindingDiagnostics);
if (_marshallers.NativeReturnMarshaller.Generator.UsesNativeIdentifier(_marshallers.NativeReturnMarshaller.TypeInfo, _context))
{
// If we need a different native return identifier, then recreate the context with the correct identifier before we generate any code.
_context = new NativeToManagedStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, $"{ReturnIdentifier}{StubCodeContext.GeneratedNativeIdentifierSuffix}");
}
}
/// <summary>
/// Generate the method body of the unmanaged-to-managed ComWrappers-based method stub.
/// </summary>
/// <param name="methodToInvoke">Name of the method on the managed type to invoke</param>
/// <returns>Method body of the stub</returns>
/// <remarks>
/// The generated code assumes it will be in an unsafe context.
/// </remarks>
public BlockSyntax GenerateStubBody(ExpressionSyntax methodToInvoke)
{
List<StatementSyntax> setupStatements = new();
GeneratedStatements statements = GeneratedStatements.Create(
_marshallers,
_context,
methodToInvoke);
bool shouldInitializeVariables =
!statements.GuaranteedUnmarshal.IsEmpty
|| !statements.Cleanup.IsEmpty
|| !statements.ManagedExceptionCatchClauses.IsEmpty;
VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForUnmanagedToManaged(_marshallers, _context, shouldInitializeVariables);
setupStatements.AddRange(declarations.Initializations);
setupStatements.AddRange(declarations.Variables);
setupStatements.AddRange(statements.Setup);
List<StatementSyntax> tryStatements = new();
tryStatements.AddRange(statements.GuaranteedUnmarshal);
tryStatements.AddRange(statements.Unmarshal);
tryStatements.Add(statements.InvokeStatement);
tryStatements.AddRange(statements.NotifyForSuccessfulInvoke);
tryStatements.AddRange(statements.PinnedMarshal);
tryStatements.AddRange(statements.Marshal);
List<StatementSyntax> allStatements = setupStatements;
List<StatementSyntax> finallyStatements = new();
SyntaxList<CatchClauseSyntax> catchClauses = List(statements.ManagedExceptionCatchClauses);
finallyStatements.AddRange(statements.Cleanup);
if (finallyStatements.Count > 0)
{
allStatements.Add(
TryStatement(Block(tryStatements), catchClauses, FinallyClause(Block(finallyStatements))));
}
else if (catchClauses.Count > 0)
{
allStatements.Add(
TryStatement(Block(tryStatements), catchClauses, @finally: null));
}
else
{
allStatements.AddRange(tryStatements);
}
// Return
if (!_marshallers.IsUnmanagedVoidReturn)
allStatements.Add(ReturnStatement(IdentifierName(_context.GetIdentifiers(_marshallers.NativeReturnMarshaller.TypeInfo).native)));
return Block(allStatements);
}
public (ParameterListSyntax ParameterList, TypeSyntax ReturnType, AttributeListSyntax? ReturnTypeAttributes) GenerateAbiMethodSignatureData()
{
return _marshallers.GenerateTargetMethodSignatureData(_context);
}
}
}