-
Notifications
You must be signed in to change notification settings - Fork 127
Expand file tree
/
Copy pathInteropMethodRewriter.ManagedParameter.cs
More file actions
120 lines (108 loc) · 5.77 KB
/
Copy pathInteropMethodRewriter.ManagedParameter.cs
File metadata and controls
120 lines (108 loc) · 5.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
109
110
111
112
113
114
115
116
117
118
119
120
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using AsmResolver.DotNet;
using AsmResolver.DotNet.Code.Cil;
using AsmResolver.DotNet.Collections;
using AsmResolver.DotNet.Signatures;
using AsmResolver.PE.DotNet.Cil;
using WindowsRuntime.Generator;
using WindowsRuntime.InteropGenerator.Errors;
using WindowsRuntime.InteropGenerator.Generation;
using WindowsRuntime.InteropGenerator.References;
using WindowsRuntime.InteropGenerator.Resolvers;
using static AsmResolver.PE.DotNet.Cil.CilOpCodes;
#pragma warning disable CS8620 // TODO: remove once Roslyn bug is fixed
namespace WindowsRuntime.InteropGenerator.Rewriters;
/// <summary>
/// A factory to rewrite interop method definitons, and add marshalling code as needed.
/// </summary>
internal static partial class InteropMethodRewriter
{
/// <summary>
/// Contains the logic for marshalling managed parameters (i.e. parameters that are passed to managed methods).
/// </summary>
public static class ManagedParameter
{
/// <summary>
/// Performs two-pass code generation on a target method to marshal an unmanaged parameter.
/// </summary>
/// <param name="parameterType">The parameter type that needs to be marshalled.</param>
/// <param name="method">The target method to perform two-pass code generation on.</param>
/// <param name="marker">The target IL instruction to replace with the right set of specialized instructions.</param>
/// <param name="parameterIndex">The index of the parameter to marshal.</param>
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <param name="emitState">The emit state for this invocation.</param>
public static void RewriteMethod(
TypeSignature parameterType,
MethodDefinition method,
CilInstruction marker,
int parameterIndex,
InteropReferences interopReferences,
InteropGeneratorEmitState emitState)
{
// Validate that we do have some IL body for the input method (this should always be the case)
if (method.CilMethodBody is not CilMethodBody body)
{
throw WellKnownInteropExceptions.MethodRewriteMissingBodyError(method);
}
// If we didn't find the marker, it means the target method is either invalid
if (!body.Instructions.ReferenceContains(marker))
{
throw WellKnownInteropExceptions.MethodRewriteMarkerInstructionNotFoundError(marker, method);
}
// Validate that the target parameter index is in range
if ((uint)parameterIndex >= method.Parameters.Count)
{
throw WellKnownInteropExceptions.MethodRewriteParameterIndexNotValidError(parameterIndex, method);
}
Parameter source = method.Parameters[parameterIndex];
// Validate that the ABI type matches
if (!SignatureComparer.IgnoreVersion.Equals(source.ParameterType, parameterType.GetAbiType(interopReferences)))
{
throw WellKnownInteropExceptions.MethodRewriteSourceParameterTypeMismatchError(source.ParameterType, parameterType, method);
}
// See comments in the marshalling code for 'ManagedValue' for additional details on the code below.
// The two are identical, the only difference is this method also loads the parameters on the stack.
if (parameterType.IsValueType)
{
if (parameterType.IsBlittable(interopReferences))
{
body.Instructions.ReferenceReplaceRange(marker, CilInstruction.CreateLdarg(parameterIndex));
}
else if (parameterType.IsConstructedNullableValueType(interopReferences))
{
InteropMarshallerType marshallerType = InteropMarshallerTypeResolver.GetMarshallerType(parameterType, interopReferences, emitState);
body.Instructions.ReferenceReplaceRange(marker, [
CilInstruction.CreateLdarg(parameterIndex),
new CilInstruction(Call, marshallerType.UnboxToManaged())]);
}
else if (SignatureComparer.IgnoreVersion.Equals(parameterType, interopReferences.ReadOnlySpanChar))
{
body.Instructions.ReferenceReplaceRange(marker, [
CilInstruction.CreateLdarg(parameterIndex),
new CilInstruction(Call, interopReferences.HStringMarshallerConvertToManagedUnsafe)]);
}
else
{
InteropMarshallerType marshallerType = InteropMarshallerTypeResolver.GetMarshallerType(parameterType, interopReferences, emitState);
body.Instructions.ReferenceReplaceRange(marker, [
CilInstruction.CreateLdarg(parameterIndex),
new CilInstruction(Call, marshallerType.ConvertToManaged())]);
}
}
else if (parameterType.IsTypeOfString())
{
body.Instructions.ReferenceReplaceRange(marker, [
CilInstruction.CreateLdarg(parameterIndex),
new CilInstruction(Call, interopReferences.HStringMarshallerConvertToManaged)]);
}
else
{
InteropMarshallerType marshallerType = InteropMarshallerTypeResolver.GetMarshallerType(parameterType, interopReferences, emitState);
body.Instructions.ReferenceReplaceRange(marker, [
CilInstruction.CreateLdarg(parameterIndex),
new CilInstruction(Call, marshallerType.ConvertToManaged())]);
}
}
}
}