|
' 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.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 Integer
''' <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, 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, message As String) As BoundStatement
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](
f.WellKnownMember(Of MethodSymbol)(WellKnownMember.System_InvalidOperationException__ctorString),
f.StringLiteral(ConstantValue.Create(message)))))
End Function
End Class
End Namespace
|