File: CodeGen\ResumableStateMachineStateAllocator.vb
Web Access
Project: src\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