Skip to content

Commit 6e7001c

Browse files
authored
Add two new stages to prepare for our new custom type marshalling design. (#70598)
1 parent ab998cc commit 6e7001c

File tree

8 files changed

+198
-140
lines changed

8 files changed

+198
-140
lines changed

src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,18 +146,20 @@ public BlockSyntax GeneratePInvokeBody(string dllImportName)
146146
var tryStatements = new List<StatementSyntax>();
147147
tryStatements.AddRange(statements.Marshal);
148148

149-
var invokeStatement = statements.InvokeStatement;
149+
BlockSyntax fixedBlock = Block(statements.PinnedMarshal);
150150
if (_setLastError)
151151
{
152152
StatementSyntax clearLastError = MarshallerHelpers.CreateClearLastSystemErrorStatement(SuccessErrorCode);
153153

154154
StatementSyntax getLastError = MarshallerHelpers.CreateGetLastSystemErrorStatement(LastErrorIdentifier);
155155

156-
invokeStatement = Block(clearLastError, invokeStatement, getLastError);
156+
fixedBlock = fixedBlock.AddStatements(clearLastError, statements.InvokeStatement, getLastError);
157157
}
158-
invokeStatement = statements.Pin.NestFixedStatements(invokeStatement);
159-
160-
tryStatements.Add(invokeStatement);
158+
else
159+
{
160+
fixedBlock = fixedBlock.AddStatements(statements.InvokeStatement);
161+
}
162+
tryStatements.Add(statements.Pin.NestFixedStatements(fixedBlock));
161163
// <invokeSucceeded> = true;
162164
if (!statements.GuaranteedUnmarshal.IsEmpty)
163165
{
@@ -166,7 +168,7 @@ public BlockSyntax GeneratePInvokeBody(string dllImportName)
166168
LiteralExpression(SyntaxKind.TrueLiteralExpression))));
167169
}
168170

169-
tryStatements.AddRange(statements.KeepAlive);
171+
tryStatements.AddRange(statements.NotifyForSuccessfulInvoke);
170172
tryStatements.AddRange(statements.Unmarshal);
171173

172174
List<StatementSyntax> allStatements = setupStatements;

src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/GeneratedStatements.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ public struct GeneratedStatements
1818
public ImmutableArray<StatementSyntax> Setup { get; init; }
1919
public ImmutableArray<StatementSyntax> Marshal { get; init; }
2020
public ImmutableArray<FixedStatementSyntax> Pin { get; init; }
21+
public ImmutableArray<StatementSyntax> PinnedMarshal { get; init; }
2122
public StatementSyntax InvokeStatement { get; init; }
2223
public ImmutableArray<StatementSyntax> Unmarshal { get; init; }
23-
public ImmutableArray<StatementSyntax> KeepAlive { get; init; }
24+
public ImmutableArray<StatementSyntax> NotifyForSuccessfulInvoke { get; init; }
2425
public ImmutableArray<StatementSyntax> GuaranteedUnmarshal { get; init; }
2526
public ImmutableArray<StatementSyntax> Cleanup { get; init; }
2627

@@ -31,9 +32,11 @@ public static GeneratedStatements Create(BoundGenerators marshallers, StubCodeCo
3132
Setup = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.Setup }),
3233
Marshal = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.Marshal }),
3334
Pin = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.Pin }).Cast<FixedStatementSyntax>().ToImmutableArray(),
35+
PinnedMarshal = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.PinnedMarshal }),
3436
InvokeStatement = GenerateStatementForNativeInvoke(marshallers, context with { CurrentStage = StubCodeContext.Stage.Invoke }, expressionToInvoke),
35-
Unmarshal = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.Unmarshal }),
36-
KeepAlive = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.KeepAlive }),
37+
Unmarshal = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.UnmarshalCapture })
38+
.AddRange(GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.Unmarshal })),
39+
NotifyForSuccessfulInvoke = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.NotifyForSuccessfulInvoke }),
3740
GuaranteedUnmarshal = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.GuaranteedUnmarshal }),
3841
Cleanup = GenerateStatementsForStubContext(marshallers, context with { CurrentStage = StubCodeContext.Stage.Cleanup }),
3942
};
@@ -48,7 +51,7 @@ private static ImmutableArray<StatementSyntax> GenerateStatementsForStubContext(
4851
statementsToUpdate.AddRange(retStatements);
4952
}
5053

51-
if (context.CurrentStage is StubCodeContext.Stage.Unmarshal or StubCodeContext.Stage.GuaranteedUnmarshal)
54+
if (context.CurrentStage is StubCodeContext.Stage.UnmarshalCapture or StubCodeContext.Stage.Unmarshal or StubCodeContext.Stage.GuaranteedUnmarshal)
5255
{
5356
// For Unmarshal and GuaranteedUnmarshal stages, use the topologically sorted
5457
// marshaller list to generate the marshalling statements
@@ -113,10 +116,12 @@ private static SyntaxTriviaList GenerateStageTrivia(StubCodeContext.Stage stage)
113116
StubCodeContext.Stage.Setup => "Perform required setup.",
114117
StubCodeContext.Stage.Marshal => "Convert managed data to native data.",
115118
StubCodeContext.Stage.Pin => "Pin data in preparation for calling the P/Invoke.",
119+
StubCodeContext.Stage.PinnedMarshal => "Convert managed data to native data that requires the managed data to be pinned.",
116120
StubCodeContext.Stage.Invoke => "Call the P/Invoke.",
121+
StubCodeContext.Stage.UnmarshalCapture => "Capture the native data into marshaller instances in case conversion to managed data throws an exception.",
117122
StubCodeContext.Stage.Unmarshal => "Convert native data to managed data.",
118123
StubCodeContext.Stage.Cleanup => "Perform required cleanup.",
119-
StubCodeContext.Stage.KeepAlive => "Keep alive any managed objects that need to stay alive across the call.",
124+
StubCodeContext.Stage.NotifyForSuccessfulInvoke => "Keep alive any managed objects that need to stay alive across the call.",
120125
StubCodeContext.Stage.GuaranteedUnmarshal => "Convert native data to managed data even in the case of an exception during the non-cleanup phases.",
121126
_ => throw new ArgumentOutOfRangeException(nameof(stage))
122127
};

src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,13 @@ private IMarshallingGenerator CreateCustomNativeTypeMarshaller(TypePositionInfo
212212
{
213213
return CreateNativeCollectionMarshaller(info, context, collectionMarshallingInfo, marshallingStrategy);
214214
}
215-
216-
if (marshalInfo.NativeValueType is not null)
215+
else if (marshalInfo.NativeValueType is not null)
217216
{
218-
marshallingStrategy = DecorateWithTwoStageMarshallingStrategy(marshalInfo, marshallingStrategy);
217+
marshallingStrategy = new CustomNativeTypeWithToFromNativeValueMarshalling(marshallingStrategy, marshalInfo.NativeValueType.Syntax);
218+
if (marshalInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.NativeType) && marshalInfo.MarshallingFeatures.HasFlag(CustomTypeMarshallerFeatures.TwoStageMarshalling))
219+
{
220+
marshallingStrategy = new PinnableMarshallerTypeMarshalling(marshallingStrategy);
221+
}
219222
}
220223

221224
IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false);
@@ -283,18 +286,6 @@ private static void ValidateCustomNativeTypeMarshallingSupported(TypePositionInf
283286
}
284287
}
285288

286-
private static ICustomNativeTypeMarshallingStrategy DecorateWithTwoStageMarshallingStrategy(NativeMarshallingAttributeInfo marshalInfo, ICustomNativeTypeMarshallingStrategy nativeTypeMarshaller)
287-
{
288-
TypeSyntax nativeValueTypeSyntax = marshalInfo.NativeValueType!.Syntax;
289-
290-
if (marshalInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.NativeType) && marshalInfo.MarshallingFeatures.HasFlag(CustomTypeMarshallerFeatures.TwoStageMarshalling))
291-
{
292-
return new PinnableMarshallerTypeMarshalling(nativeTypeMarshaller, nativeValueTypeSyntax);
293-
}
294-
295-
return new CustomNativeTypeWithToFromNativeValueMarshalling(nativeTypeMarshaller, nativeValueTypeSyntax);
296-
}
297-
298289
private IMarshallingGenerator CreateNativeCollectionMarshaller(
299290
TypePositionInfo info,
300291
StubCodeContext context,
@@ -324,10 +315,10 @@ private IMarshallingGenerator CreateNativeCollectionMarshaller(
324315
marshallingStrategy = new LinearCollectionWithNonBlittableElementsMarshalling(marshallingStrategy, elementMarshaller, elementInfo, numElementsExpression);
325316
}
326317

327-
// Explicitly insert the Value property handling here (before numElements handling) so that the numElements handling will be emitted before the Value property handling in unmarshalling.
328-
if (collectionInfo.NativeValueType is not null)
318+
marshallingStrategy = new CustomNativeTypeWithToFromNativeValueMarshalling(marshallingStrategy, collectionInfo.NativeValueType.Syntax);
319+
if (collectionInfo.PinningFeatures.HasFlag(CustomTypeMarshallerPinning.NativeType) && collectionInfo.MarshallingFeatures.HasFlag(CustomTypeMarshallerFeatures.TwoStageMarshalling))
329320
{
330-
marshallingStrategy = DecorateWithTwoStageMarshallingStrategy(collectionInfo, marshallingStrategy);
321+
marshallingStrategy = new PinnableMarshallerTypeMarshalling(marshallingStrategy);
331322
}
332323

333324
TypeSyntax nativeElementType = elementMarshaller.AsNativeType(elementInfo);

src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeCont
6363
return _nativeTypeMarshaller.GeneratePinStatements(info, context);
6464
}
6565
break;
66+
case StubCodeContext.Stage.PinnedMarshal:
67+
if (!info.IsManagedReturnPosition && info.RefKind != RefKind.Out)
68+
{
69+
return _nativeTypeMarshaller.GeneratePinnedMarshalStatements(info, context);
70+
}
71+
break;
72+
case StubCodeContext.Stage.UnmarshalCapture:
73+
if (info.IsManagedReturnPosition || (info.IsByRef && info.RefKind != RefKind.In))
74+
{
75+
return _nativeTypeMarshaller.GenerateUnmarshalCaptureStatements(info, context);
76+
}
77+
break;
6678
case StubCodeContext.Stage.Unmarshal:
6779
if (info.IsManagedReturnPosition || (info.IsByRef && info.RefKind != RefKind.In)
6880
|| (_enableByValueContentsMarshalling && !info.IsByRef && info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out)))

src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeCont
8787
LiteralExpression(SyntaxKind.NullLiteralExpression))));
8888
}
8989
break;
90-
case StubCodeContext.Stage.KeepAlive:
90+
case StubCodeContext.Stage.NotifyForSuccessfulInvoke:
9191
if (info.RefKind != RefKind.Out)
9292
{
9393
yield return ExpressionStatement(

0 commit comments

Comments
 (0)