| File: CodeGen\ResumableStateMachineStateAllocator.vb | Web Access |
| Project: src\roslyn\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic) |
' 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. Imports System Imports System.Diagnostics Imports Microsoft.CodeAnalysis.CodeGen Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic ''' <summary> ''' Allocates resumable states, i.e. states that resume execution of the state machine after await expression or yield return. ''' </summary> Friend NotInheritable Class ResumableStateMachineStateAllocator Private ReadOnly _slotAllocator As VariableSlotAllocator Private ReadOnly _increasing As Boolean Private ReadOnly _firstState As StateMachineState ''' <summary> ''' The number of the next generated resumable state (i.e. state that resumes execution of the state machine after await expression or yield return). ''' </summary> Private _nextState As StateMachineState #If DEBUG Then ''' <summary> ''' EnC support: states in this state machine that were matched to states of the previous generation state machine. ''' </summary> Private _matchedStates As BitVector = BitVector.Empty #End If ''' <summary> ''' EnC support: number of states in this state machine that match states of the previous generation state machine. ''' </summary> Private _matchedStateCount As Integer Public Sub New(slotAllocator As VariableSlotAllocator, firstState As StateMachineState, increasing As Boolean) _increasing = increasing _slotAllocator = slotAllocator _matchedStateCount = 0 _firstState = firstState _nextState = If(slotAllocator?.GetFirstUnusedStateMachineState(increasing), firstState) End Sub Public Function AllocateState(awaitOrYieldReturnSyntax As SyntaxNode) As StateMachineState Debug.Assert(SyntaxBindingUtilities.BindsToResumableStateMachineState(awaitOrYieldReturnSyntax)) Dim direction = If(_increasing, +1, -1) Dim state As StateMachineState If _slotAllocator?.TryGetPreviousStateMachineState(awaitOrYieldReturnSyntax, awaitId:=Nothing, state) = True Then #If DEBUG Then ' two states of the new state machine should not match the same state of the previous machine Debug.Assert(Not _matchedStates(state * direction)) _matchedStates(state * direction) = True #End If _matchedStateCount += 1 Else state = _nextState _nextState = CType(_nextState + direction, StateMachineState) End If Return state End Function ''' <summary> ''' True if any of the states generated for any previous state machine has not been allocated in this version. ''' </summary> Public ReadOnly Property HasMissingStates As Boolean Get Return _matchedStateCount < If(_slotAllocator?.GetFirstUnusedStateMachineState(_increasing), _firstState) - _firstState End Get End Property Public Function GenerateThrowMissingStateDispatch(f As SyntheticBoundNodeFactory, cachedState As BoundExpression, errorCode As HotReloadExceptionCode) As BoundStatement Debug.Assert(f.CompilationState IsNot Nothing) Debug.Assert(f.CompilationState.ModuleBuilderOpt IsNot Nothing) If Not HasMissingStates Then Return Nothing End If Return f.If( f.Binary( If(_increasing, BinaryOperatorKind.GreaterThanOrEqual, BinaryOperatorKind.LessThanOrEqual), f.SpecialType(SpecialType.System_Boolean), cachedState, f.Literal(_firstState)), f.Throw( f.[New]( DirectCast(f.CompilationState.ModuleBuilderOpt.GetOrCreateHotReloadExceptionConstructorDefinition(), MethodSymbol), f.StringLiteral(ConstantValue.Create(errorCode.GetExceptionMessage())), f.Literal(errorCode.GetExceptionCodeValue())))) End Function End Class End Namespace