| File: CodeGen\StateMachineStateDebugInfo.cs | Web Access |
| Project: src\roslyn\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis) |
// 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. using System; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.Emit; namespace Microsoft.CodeAnalysis.CodeGen; internal readonly struct StateMachineStateDebugInfo(int syntaxOffset, AwaitDebugId awaitId, StateMachineState stateNumber) { public readonly int SyntaxOffset = syntaxOffset; public readonly AwaitDebugId AwaitId = awaitId; public readonly StateMachineState StateNumber = stateNumber; } /// <summary> /// Debug information maintained for each state machine. /// Facilitates mapping of state machine states from a compilation to the previous one (or to a metadata baseline) during EnC. /// </summary> internal readonly struct StateMachineStatesDebugInfo { public readonly ImmutableArray<StateMachineStateDebugInfo> States; /// <summary> /// The number of the first state that has not been used in any of the previous versions of the state machine, /// or null if we are not generating EnC delta. /// /// For 1st generation EnC delta, this is calculated by examining the <see cref="EditAndContinueMethodDebugInformation.StateMachineStates"/> stored in the baseline metadata. /// For subsequent generations, the number is updated to account for newly generated states in that generation. /// </summary> public readonly StateMachineState? FirstUnusedIncreasingStateMachineState; /// <summary> /// The number of the first state that has not been used in any of the previous versions of the state machine, /// or null if we are not generating EnC delta, or the state machine has no decreasing states. /// /// For 1st generation EnC delta, this is calculated by examining the <see cref="EditAndContinueMethodDebugInformation.StateMachineStates"/> stored in the baseline metadata. /// For subsequent generations, the number is updated to account for newly generated states in that generation. /// </summary> public readonly StateMachineState? FirstUnusedDecreasingStateMachineState; private StateMachineStatesDebugInfo(ImmutableArray<StateMachineStateDebugInfo> states, StateMachineState? firstUnusedIncreasingStateMachineState, StateMachineState? firstUnusedDecreasingStateMachineState) { States = states; FirstUnusedIncreasingStateMachineState = firstUnusedIncreasingStateMachineState; FirstUnusedDecreasingStateMachineState = firstUnusedDecreasingStateMachineState; } public static StateMachineStatesDebugInfo Create(VariableSlotAllocator? variableSlotAllocator, ImmutableArray<StateMachineStateDebugInfo> stateInfos) { StateMachineState? firstUnusedIncreasingStateMachineState = null, firstUnusedDecreasingStateMachineState = null; if (variableSlotAllocator != null) { // We start with first unused state numbers from the previous generation and update them based on states generated in the current one. firstUnusedIncreasingStateMachineState = variableSlotAllocator.GetFirstUnusedStateMachineState(increasing: true); firstUnusedDecreasingStateMachineState = variableSlotAllocator.GetFirstUnusedStateMachineState(increasing: false); if (!stateInfos.IsDefaultOrEmpty) { // The current method is a state machine and has some resumable/finalization states. // Update the first unused states based on the highest resumable (positive numbers) and lowest finalization (negative numbers) of this method. var maxState = stateInfos.Max(info => info.StateNumber) + 1; var minState = stateInfos.Min(info => info.StateNumber) - 1; firstUnusedIncreasingStateMachineState = (firstUnusedIncreasingStateMachineState != null) ? (StateMachineState)Math.Max((int)firstUnusedIncreasingStateMachineState.Value, (int)maxState) : maxState; if (minState < 0) { firstUnusedDecreasingStateMachineState = (firstUnusedDecreasingStateMachineState != null) ? (StateMachineState)Math.Min((int)firstUnusedDecreasingStateMachineState.Value, (int)minState) : minState; } } } return new StateMachineStatesDebugInfo( stateInfos, firstUnusedIncreasingStateMachineState, firstUnusedDecreasingStateMachineState); } }