| File: Lowering\IteratorRewriter\IteratorMethodToStateMachineRewriter.IteratorFinallyFrame.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using Microsoft.CodeAnalysis.CSharp.Symbols; using System.Collections.Generic; using System.Diagnostics; namespace Microsoft.CodeAnalysis.CSharp { internal partial class IteratorMethodToStateMachineRewriter { // storage of various information about a given try/finally frame private sealed class IteratorFinallyFrame { // finalize state of this frame. This is the state we should be in when we are "between real states" public readonly StateMachineState finalizeState; // Enclosing frame. Root frame does not have parent. public readonly IteratorFinallyFrame parent; // Finally handler function. We must run this when logically leaving the frame. Root does not have a handler. public readonly IteratorFinallyMethodSymbol handler; // All states encountered in nested frames mapped to corresponding finally frames. // This is enough information to restore Try/Finally tree structure in Dispose and dispatch any valid state // into a corresponding try. // NOTE: union of all values in this map gives all nested frames. public Dictionary<StateMachineState, IteratorFinallyFrame> knownStates; // labels within this frame (branching to these labels does not go through finally). public readonly HashSet<LabelSymbol> labels; // proxy labels for branches leaving the frame. // we build this on demand once we encounter leaving branches. // subsequent leaves to an already proxied label redirected to the proxy. // At the proxy label we will execute finally and forward the control flow // to the actual destination. (which could be proxied again in the parent) public Dictionary<LabelSymbol, LabelSymbol> proxyLabels; public IteratorFinallyFrame( IteratorFinallyFrame parent, StateMachineState finalizeState, IteratorFinallyMethodSymbol handler, HashSet<LabelSymbol> labels) { Debug.Assert(parent != null, "non root frame must have a parent"); Debug.Assert((object)handler != null, "non root frame must have a handler"); this.parent = parent; this.finalizeState = finalizeState; this.handler = handler; this.labels = labels; } public IteratorFinallyFrame() { this.finalizeState = StateMachineState.NotStartedOrRunningState; } public bool IsRoot() { return this.parent == null; } public void AddState(StateMachineState state) { if (parent != null) { parent.AddState(state, this); } } // Notifies all parents about the state recursively. // All parents need to know states they recursively contain and what // immediate child can handle every particular state. private void AddState(StateMachineState state, IteratorFinallyFrame innerHandler) { var knownStates = this.knownStates; if (knownStates == null) { this.knownStates = knownStates = new Dictionary<StateMachineState, IteratorFinallyFrame>(); } knownStates.Add(state, innerHandler); if (parent != null) { // Present ourselves to the parent as responsible for a handling a state. parent.AddState(state, this); } } // returns a proxy for a label if branch must be hijacked to run finally // otherwise returns same label back public LabelSymbol ProxyLabelIfNeeded(LabelSymbol label) { // no need to proxy a label in the current frame or when we are at the root if (this.IsRoot() || (labels != null && labels.Contains(label))) { return label; } var proxyLabels = this.proxyLabels; if (proxyLabels == null) { this.proxyLabels = proxyLabels = new Dictionary<LabelSymbol, LabelSymbol>(); } LabelSymbol proxy; if (!proxyLabels.TryGetValue(label, out proxy)) { proxy = new GeneratedLabelSymbol("proxy" + label.Name); proxyLabels.Add(label, proxy); } return proxy; } } } }