Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EnC: Allow adding/removing await expressions and yield statements #61356

Merged
merged 14 commits into from
May 31, 2022
Merged
4 changes: 2 additions & 2 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@
<MicrosoftDiagnosticsRuntimeVersion>0.8.31-beta</MicrosoftDiagnosticsRuntimeVersion>
<MicrosoftDiagnosticsTracingTraceEventVersion>1.0.35</MicrosoftDiagnosticsTracingTraceEventVersion>
<MicrosoftDiaSymReaderVersion>1.4.0</MicrosoftDiaSymReaderVersion>
<MicrosoftDiaSymReaderConverterVersion>1.1.0-beta2-21528-01</MicrosoftDiaSymReaderConverterVersion>
<MicrosoftDiaSymReaderConverterXmlVersion>1.1.0-beta2-21528-01</MicrosoftDiaSymReaderConverterXmlVersion>
<MicrosoftDiaSymReaderConverterVersion>1.1.0-beta2-22273-03</MicrosoftDiaSymReaderConverterVersion>
<MicrosoftDiaSymReaderConverterXmlVersion>1.1.0-beta2-22273-03</MicrosoftDiaSymReaderConverterXmlVersion>
<MicrosoftDiaSymReaderNativeVersion>17.0.0-beta1.21524.1</MicrosoftDiaSymReaderNativeVersion>
<MicrosoftDiaSymReaderPortablePdbVersion>1.7.0-beta-21528-01</MicrosoftDiaSymReaderPortablePdbVersion>
<MicrosoftExtensionsLoggingVersion>5.0.0</MicrosoftExtensionsLoggingVersion>
Expand Down
32 changes: 24 additions & 8 deletions src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul
VariableSlotAllocator lazyVariableSlotAllocator = null;
var lambdaDebugInfoBuilder = ArrayBuilder<LambdaDebugInfo>.GetInstance();
var closureDebugInfoBuilder = ArrayBuilder<ClosureDebugInfo>.GetInstance();
var stateMachineStateDebugInfoBuilder = ArrayBuilder<StateMachineStateDebugInfo>.GetInstance();
StateMachineTypeSymbol stateMachineTypeOpt = null;
const int methodOrdinal = -1;

Expand All @@ -280,16 +281,19 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul
ref lazyVariableSlotAllocator,
lambdaDebugInfoBuilder,
closureDebugInfoBuilder,
stateMachineStateDebugInfoBuilder,
out stateMachineTypeOpt);

Debug.Assert((object)lazyVariableSlotAllocator == null);
Debug.Assert((object)stateMachineTypeOpt == null);
Debug.Assert(dynamicAnalysisSpans.IsEmpty);
Debug.Assert(lambdaDebugInfoBuilder.IsEmpty());
Debug.Assert(closureDebugInfoBuilder.IsEmpty());
Debug.Assert(stateMachineStateDebugInfoBuilder.IsEmpty());

lambdaDebugInfoBuilder.Free();
closureDebugInfoBuilder.Free();
stateMachineStateDebugInfoBuilder.Free();

if (emitMethodBodies)
{
Expand All @@ -300,6 +304,7 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul
loweredBody,
ImmutableArray<LambdaDebugInfo>.Empty,
ImmutableArray<ClosureDebugInfo>.Empty,
ImmutableArray<StateMachineStateDebugInfo>.Empty,
stateMachineTypeOpt: null,
variableSlotAllocatorOpt: null,
diagnostics: diagnostics,
Expand Down Expand Up @@ -698,6 +703,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
return;
}

var stateMachineStateDebugInfoBuilder = ArrayBuilder<StateMachineStateDebugInfo>.GetInstance();
var oldImportChain = compilationState.CurrentImportChain;
try
{
Expand Down Expand Up @@ -727,13 +733,13 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
{
// Local functions can be iterators as well as be async (lambdas can only be async), so we need to lower both iterators and async
IteratorStateMachine iteratorStateMachine;
BoundStatement loweredBody = IteratorRewriter.Rewrite(methodWithBody.Body, method, methodOrdinal, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out iteratorStateMachine);
BoundStatement loweredBody = IteratorRewriter.Rewrite(methodWithBody.Body, method, methodOrdinal, stateMachineStateDebugInfoBuilder, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out iteratorStateMachine);
StateMachineTypeSymbol stateMachine = iteratorStateMachine;

if (!loweredBody.HasErrors)
{
AsyncStateMachine asyncStateMachine;
loweredBody = AsyncRewriter.Rewrite(loweredBody, method, methodOrdinal, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out asyncStateMachine);
loweredBody = AsyncRewriter.Rewrite(loweredBody, method, methodOrdinal, stateMachineStateDebugInfoBuilder, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out asyncStateMachine);

Debug.Assert((object)iteratorStateMachine == null || (object)asyncStateMachine == null);
stateMachine = stateMachine ?? asyncStateMachine;
Expand All @@ -751,6 +757,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
loweredBody,
ImmutableArray<LambdaDebugInfo>.Empty,
ImmutableArray<ClosureDebugInfo>.Empty,
stateMachineStateDebugInfoBuilder.ToImmutable(),
stateMachine,
variableSlotAllocatorOpt,
diagnosticsThisMethod,
Expand Down Expand Up @@ -784,11 +791,14 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
{
Debug.Assert(emittedBody is null);
}

stateMachineStateDebugInfoBuilder.Clear();
}
}
finally
{
compilationState.CurrentImportChain = oldImportChain;
stateMachineStateDebugInfoBuilder.Free();
}
}

Expand Down Expand Up @@ -868,6 +878,7 @@ private void CompileFieldLikeEventAccessor(SourceEventSymbol eventSymbol, bool i
boundBody,
ImmutableArray<LambdaDebugInfo>.Empty,
ImmutableArray<ClosureDebugInfo>.Empty,
ImmutableArray<StateMachineStateDebugInfo>.Empty,
stateMachineTypeOpt: null,
variableSlotAllocatorOpt: null,
diagnostics: diagnosticsThisMethod,
Expand Down Expand Up @@ -1185,6 +1196,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax &&
StateMachineTypeSymbol stateMachineTypeOpt = null;
var lambdaDebugInfoBuilder = ArrayBuilder<LambdaDebugInfo>.GetInstance();
var closureDebugInfoBuilder = ArrayBuilder<ClosureDebugInfo>.GetInstance();
var stateMachineStateDebugInfoBuilder = ArrayBuilder<StateMachineStateDebugInfo>.GetInstance();
BoundStatement loweredBodyOpt = null;

try
Expand All @@ -1204,6 +1216,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax &&
ref lazyVariableSlotAllocator,
lambdaDebugInfoBuilder,
closureDebugInfoBuilder,
stateMachineStateDebugInfoBuilder,
out stateMachineTypeOpt);

Debug.Assert(loweredBodyOpt != null);
Expand Down Expand Up @@ -1256,6 +1269,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax &&
ref lazyVariableSlotAllocator,
lambdaDebugInfoBuilder,
closureDebugInfoBuilder,
stateMachineStateDebugInfoBuilder,
out initializerStateMachineTypeOpt);

processedInitializers.LoweredInitializers = lowered;
Expand Down Expand Up @@ -1316,6 +1330,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax &&
boundBody,
lambdaDebugInfoBuilder.ToImmutable(),
closureDebugInfoBuilder.ToImmutable(),
stateMachineStateDebugInfoBuilder.ToImmutable(),
stateMachineTypeOpt,
lazyVariableSlotAllocator,
diagsForCurrentMethod,
Expand All @@ -1336,6 +1351,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax &&
{
lambdaDebugInfoBuilder.Free();
closureDebugInfoBuilder.Free();
stateMachineStateDebugInfoBuilder.Free();
}
}
finally
Expand All @@ -1359,6 +1375,7 @@ internal static BoundStatement LowerBodyOrInitializer(
ref VariableSlotAllocator lazyVariableSlotAllocator,
ArrayBuilder<LambdaDebugInfo> lambdaDebugInfoBuilder,
ArrayBuilder<ClosureDebugInfo> closureDebugInfoBuilder,
ArrayBuilder<StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder,
out StateMachineTypeSymbol stateMachineTypeOpt)
{
Debug.Assert(compilationState.ModuleBuilderOpt != null);
Expand Down Expand Up @@ -1413,10 +1430,7 @@ internal static BoundStatement LowerBodyOrInitializer(
return loweredBody;
}

if (lazyVariableSlotAllocator == null)
{
lazyVariableSlotAllocator = compilationState.ModuleBuilderOpt.TryCreateVariableSlotAllocator(method, method, diagnostics.DiagnosticBag);
}
lazyVariableSlotAllocator ??= compilationState.ModuleBuilderOpt.TryCreateVariableSlotAllocator(method, method, diagnostics.DiagnosticBag);

BoundStatement bodyWithoutLambdas = loweredBody;
if (sawLambdas || sawLocalFunctions)
Expand All @@ -1441,15 +1455,15 @@ internal static BoundStatement LowerBodyOrInitializer(
return bodyWithoutLambdas;
}

BoundStatement bodyWithoutIterators = IteratorRewriter.Rewrite(bodyWithoutLambdas, method, methodOrdinal, lazyVariableSlotAllocator, compilationState, diagnostics,
BoundStatement bodyWithoutIterators = IteratorRewriter.Rewrite(bodyWithoutLambdas, method, methodOrdinal, stateMachineStateDebugInfoBuilder, lazyVariableSlotAllocator, compilationState, diagnostics,
out IteratorStateMachine iteratorStateMachine);

if (bodyWithoutIterators.HasErrors)
{
return bodyWithoutIterators;
}

BoundStatement bodyWithoutAsync = AsyncRewriter.Rewrite(bodyWithoutIterators, method, methodOrdinal, lazyVariableSlotAllocator, compilationState, diagnostics,
BoundStatement bodyWithoutAsync = AsyncRewriter.Rewrite(bodyWithoutIterators, method, methodOrdinal, stateMachineStateDebugInfoBuilder, lazyVariableSlotAllocator, compilationState, diagnostics,
out AsyncStateMachine asyncStateMachine);

Debug.Assert((object)iteratorStateMachine == null || (object)asyncStateMachine == null);
Expand All @@ -1474,6 +1488,7 @@ private static MethodBody GenerateMethodBody(
BoundStatement block,
ImmutableArray<LambdaDebugInfo> lambdaDebugInfo,
ImmutableArray<ClosureDebugInfo> closureDebugInfo,
ImmutableArray<StateMachineStateDebugInfo> stateMachineStateDebugInfos,
StateMachineTypeSymbol stateMachineTypeOpt,
VariableSlotAllocator variableSlotAllocatorOpt,
BindingDiagnosticBag diagnostics,
Expand Down Expand Up @@ -1623,6 +1638,7 @@ private static MethodBody GenerateMethodBody(
stateMachineHoistedLocalScopes,
stateMachineHoistedLocalSlots,
stateMachineAwaiterSlots,
StateMachineStatesDebugInfo.Create(variableSlotAllocatorOpt, stateMachineStateDebugInfos),
moveNextBodyDebugInfoOpt,
dynamicAnalysisDataOpt);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,17 +192,8 @@ protected override ImmutableArray<EncLocalInfo> GetLocalSlotMapFromMetadata(Stan
return result;
}

protected override ITypeSymbolInternal? TryGetStateMachineType(EntityHandle methodHandle)
{
string typeName;
if (_metadataDecoder.Module.HasStringValuedAttribute(methodHandle, AttributeDescription.AsyncStateMachineAttribute, out typeName) ||
_metadataDecoder.Module.HasStringValuedAttribute(methodHandle, AttributeDescription.IteratorStateMachineAttribute, out typeName))
{
return _metadataDecoder.GetTypeSymbolForSerializedType(typeName);
}

return null;
}
protected override ITypeSymbolInternal? TryGetStateMachineType(MethodDefinitionHandle methodHandle)
=> _metadataDecoder.Module.HasStateMachineAttribute(methodHandle, out var typeName) ? _metadataDecoder.GetTypeSymbolForSerializedType(typeName) : null;
tmat marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Match local declarations to names to generate a map from
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,7 @@ public override BoundNode VisitTryStatement(BoundTryStatement node)
var tryStatementSyntax = node.Syntax;
// If you add a syntax kind to the assertion below, please also ensure
// that the scenario has been tested with Edit-and-Continue.
Debug.Assert(
tryStatementSyntax.IsKind(SyntaxKind.TryStatement) ||
tryStatementSyntax.IsKind(SyntaxKind.UsingStatement) ||
tryStatementSyntax.IsKind(SyntaxKind.ForEachStatement) ||
tryStatementSyntax.IsKind(SyntaxKind.ForEachVariableStatement) ||
tryStatementSyntax.IsKind(SyntaxKind.LocalDeclarationStatement) ||
tryStatementSyntax.IsKind(SyntaxKind.LockStatement));
Debug.Assert(SyntaxBindingUtilities.BindsToTryStatement(tryStatementSyntax));

BoundStatement finalizedRegion;
BoundBlock rewrittenFinally;
Expand Down Expand Up @@ -711,7 +705,7 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen

private AwaitFinallyFrame PushFrame(BoundTryStatement statement)
{
var newFrame = new AwaitFinallyFrame(_currentAwaitFinallyFrame, _analysis.Labels(statement), (StatementSyntax)statement.Syntax);
var newFrame = new AwaitFinallyFrame(_currentAwaitFinallyFrame, _analysis.Labels(statement), statement.Syntax);
_currentAwaitFinallyFrame = newFrame;
return newFrame;
}
Expand Down Expand Up @@ -890,7 +884,7 @@ private sealed class AwaitFinallyFrame
public readonly HashSet<LabelSymbol> LabelsOpt;

// the try or using-await statement the frame is associated with
private readonly StatementSyntax _statementSyntaxOpt;
tmat marked this conversation as resolved.
Show resolved Hide resolved
private readonly SyntaxNode _syntaxOpt;

// proxy labels for branches leaving the frame.
// we build this on demand once we encounter leaving branches.
Expand All @@ -909,20 +903,16 @@ public AwaitFinallyFrame()
// root frame
}

public AwaitFinallyFrame(AwaitFinallyFrame parent, HashSet<LabelSymbol> labelsOpt, StatementSyntax statementSyntax)
public AwaitFinallyFrame(AwaitFinallyFrame parent, HashSet<LabelSymbol> labelsOpt, SyntaxNode syntax)
{
Debug.Assert(parent != null);
Debug.Assert(statementSyntax != null);
Debug.Assert(syntax != null);

Debug.Assert(statementSyntax.Kind() == SyntaxKind.TryStatement ||
(statementSyntax.Kind() == SyntaxKind.UsingStatement && ((UsingStatementSyntax)statementSyntax).AwaitKeyword != default) ||
(statementSyntax.Kind() == SyntaxKind.ForEachStatement && ((CommonForEachStatementSyntax)statementSyntax).AwaitKeyword != default) ||
(statementSyntax.Kind() == SyntaxKind.ForEachVariableStatement && ((CommonForEachStatementSyntax)statementSyntax).AwaitKeyword != default) ||
(statementSyntax.Kind() == SyntaxKind.LocalDeclarationStatement && ((LocalDeclarationStatementSyntax)statementSyntax).AwaitKeyword != default));
Debug.Assert(SyntaxBindingUtilities.BindsToTryStatement(syntax));

this.ParentOpt = parent;
this.LabelsOpt = labelsOpt;
_statementSyntaxOpt = statementSyntax;
_syntaxOpt = syntax;
}

public bool IsRoot()
Expand Down Expand Up @@ -983,8 +973,8 @@ public LabelSymbol ProxyReturnIfNeeded(
returnValue = this.returnValue;
if (returnValue == null)
{
Debug.Assert(_statementSyntaxOpt != null);
this.returnValue = returnValue = new SynthesizedLocal(containingMethod, TypeWithAnnotations.Create(valueOpt.Type), SynthesizedLocalKind.AsyncMethodReturnValue, _statementSyntaxOpt);
Debug.Assert(_syntaxOpt != null);
this.returnValue = returnValue = new SynthesizedLocal(containingMethod, TypeWithAnnotations.Create(valueOpt.Type), SynthesizedLocalKind.AsyncMethodReturnValue, _syntaxOpt);
}
}

Expand Down
Loading