File: Lowering\LocalRewriter\LocalRewriter_DoLoop.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.Collections.Immutable
Imports System.Diagnostics
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports TypeKind = Microsoft.CodeAnalysis.TypeKind
 
Namespace Microsoft.CodeAnalysis.VisualBasic
    Partial Friend NotInheritable Class LocalRewriter
        Public Overrides Function VisitDoLoopStatement(node As BoundDoLoopStatement) As BoundNode
            Debug.Assert(node IsNot Nothing)
 
            If node.ConditionOpt IsNot Nothing Then
                If node.ConditionIsTop Then
                    Return VisitTopConditionLoop(node)
                Else
                    Return VisitBottomConditionLoop(node)
                End If
            End If
 
            Return VisitInfiniteLoop(node)
        End Function
 
        Private Function VisitTopConditionLoop(node As BoundDoLoopStatement) As BoundNode
            Debug.Assert(node.ConditionOpt IsNot Nothing AndAlso node.ConditionIsTop)
 
            Dim generateUnstructuredExceptionHandlingResumeCode As Boolean = ShouldGenerateUnstructuredExceptionHandlingResumeCode(node)
 
            Dim loopResumeLabel As BoundLabelStatement = Nothing
            Dim conditionResumeTarget As ImmutableArray(Of BoundStatement) = Nothing
 
            If generateUnstructuredExceptionHandlingResumeCode Then
                loopResumeLabel = RegisterUnstructuredExceptionHandlingNonThrowingResumeTarget(node.Syntax)
                conditionResumeTarget = RegisterUnstructuredExceptionHandlingResumeTarget(node.Syntax, canThrow:=True)
            End If
 
            Dim rewrittenBody = DirectCast(Visit(node.Body), BoundStatement)
 
            Dim afterBodyResumeLabel As BoundLabelStatement = Nothing
 
            If generateUnstructuredExceptionHandlingResumeCode Then
                afterBodyResumeLabel = RegisterUnstructuredExceptionHandlingNonThrowingResumeTarget(node.Syntax)
            End If
 
            Dim syntax = DirectCast(node.Syntax, DoLoopBlockSyntax)
 
            Return RewriteWhileStatement(node,
                                         VisitExpressionNode(node.ConditionOpt),
                                         rewrittenBody,
                                         node.ContinueLabel,
                                         node.ExitLabel,
                                         Not node.ConditionIsUntil,
                                         loopResumeLabel,
                                         conditionResumeTarget,
                                         afterBodyResumeLabel)
        End Function
 
        Private Function VisitBottomConditionLoop(node As BoundDoLoopStatement) As BoundNode
            Debug.Assert(node.ConditionOpt IsNot Nothing AndAlso Not node.ConditionIsTop)
 
            Dim syntax = DirectCast(node.Syntax, DoLoopBlockSyntax)
 
            Dim generateUnstructuredExceptionHandlingResumeCode As Boolean = ShouldGenerateUnstructuredExceptionHandlingResumeCode(node)
 
            Dim doResumeLabel As BoundLabelStatement = Nothing
 
            If generateUnstructuredExceptionHandlingResumeCode Then
                doResumeLabel = RegisterUnstructuredExceptionHandlingNonThrowingResumeTarget(syntax.DoStatement)
            End If
 
            Dim startLabel = GenerateLabel("start")
            Dim start As BoundStatement = New BoundLabelStatement(syntax.DoStatement, startLabel)
 
            If doResumeLabel IsNot Nothing Then
                start = Concat(doResumeLabel, start)
            End If
 
            Dim rewrittenBody = DirectCast(Visit(node.Body), BoundStatement)
 
            Dim instrument = Me.Instrument(node)
            If instrument AndAlso syntax.LoopStatement IsNot Nothing Then
                rewrittenBody = Concat(rewrittenBody, _instrumenterOpt.InstrumentDoLoopEpilogue(node, Nothing))
            End If
 
            Dim conditionResumeTarget As ImmutableArray(Of BoundStatement) = Nothing
 
            If generateUnstructuredExceptionHandlingResumeCode Then
                conditionResumeTarget = RegisterUnstructuredExceptionHandlingResumeTarget(node.Syntax, canThrow:=True)
            End If
 
            Dim rewrittenBottomCondition = VisitExpressionNode(node.ConditionOpt)
 
            ' Do 
            '    body
            ' Loop [While|Until condition]
            '
            ' becomes
            '
            ' start:
            ' body
            ' continue:
            ' {GotoIfTrue|False condition start}
            ' exit:
 
            ' EnC: We need to insert a hidden sequence point to handle function remapping in case 
            ' the containing method is edited while methods invoked in the condition are being executed.
            If rewrittenBottomCondition IsNot Nothing AndAlso instrument Then
                rewrittenBottomCondition = _instrumenterOpt.InstrumentDoLoopStatementCondition(node, rewrittenBottomCondition, _currentMethodOrLambda)
            End If
 
            Dim ifConditionGotoStart As BoundStatement = New BoundConditionalGoto(
                syntax.DoStatement,
                rewrittenBottomCondition,
                jumpIfTrue:=Not node.ConditionIsUntil,
                label:=startLabel)
 
            If Not conditionResumeTarget.IsDefaultOrEmpty Then
                ifConditionGotoStart = New BoundStatementList(ifConditionGotoStart.Syntax, conditionResumeTarget.Add(ifConditionGotoStart))
            End If
 
            If instrument Then
                Return New BoundStatementList(node.Syntax, ImmutableArray.Create(
                        start,
                        _instrumenterOpt.InstrumentDoLoopStatementEntryOrConditionalGotoStart(node, Nothing),
                        rewrittenBody,
                        New BoundLabelStatement(syntax.DoStatement, node.ContinueLabel),
                        ifConditionGotoStart,
                        New BoundLabelStatement(syntax.DoStatement, node.ExitLabel)
                    ))
            End If
 
            Return New BoundStatementList(node.Syntax, ImmutableArray.Create(
                    start,
                    rewrittenBody,
                    New BoundLabelStatement(node.Syntax, node.ContinueLabel),
                    ifConditionGotoStart,
                    New BoundLabelStatement(node.Syntax, node.ExitLabel)
                ))
 
        End Function
 
        Private Function VisitInfiniteLoop(node As BoundDoLoopStatement) As BoundNode
            Debug.Assert(node.ConditionOpt Is Nothing)
 
            Dim syntax = DirectCast(node.Syntax, DoLoopBlockSyntax)
 
            Dim generateUnstructuredExceptionHandlingResumeCode As Boolean = ShouldGenerateUnstructuredExceptionHandlingResumeCode(node)
 
            Dim doResumeLabel As BoundLabelStatement = Nothing
 
            If generateUnstructuredExceptionHandlingResumeCode Then
                doResumeLabel = RegisterUnstructuredExceptionHandlingNonThrowingResumeTarget(syntax.DoStatement)
            End If
 
            Dim startLabel = GenerateLabel("start")
            Dim start As BoundStatement = New BoundLabelStatement(syntax.DoStatement, startLabel)
 
            If doResumeLabel IsNot Nothing Then
                start = Concat(doResumeLabel, start)
            End If
 
            Dim rewrittenBody = DirectCast(Visit(node.Body), BoundStatement)
 
            Dim loopResumeLabel As BoundStatement = Nothing
 
            If generateUnstructuredExceptionHandlingResumeCode Then
                loopResumeLabel = RegisterUnstructuredExceptionHandlingNonThrowingResumeTarget(syntax)
            End If
 
            Dim instrument = Me.Instrument(node)
            If instrument AndAlso syntax.LoopStatement IsNot Nothing Then
                loopResumeLabel = _instrumenterOpt.InstrumentDoLoopEpilogue(node, loopResumeLabel)
            End If
 
            rewrittenBody = Concat(rewrittenBody, loopResumeLabel)
 
            ' Do
            '    body
            ' Loop
            '
            ' becomes
            '
            ' start:
            ' body
            ' continue:
            ' {Goto start}
            ' exit:
 
            If instrument Then
                Return New BoundStatementList(syntax, ImmutableArray.Create(
                        start,
                        _instrumenterOpt.InstrumentDoLoopStatementEntryOrConditionalGotoStart(node, Nothing),
                        rewrittenBody,
                        New BoundLabelStatement(syntax.DoStatement, node.ContinueLabel),
                        New BoundGotoStatement(syntax.DoStatement, startLabel, Nothing),
                        New BoundLabelStatement(syntax.DoStatement, node.ExitLabel)
                    ))
            End If
 
            Return New BoundStatementList(syntax, ImmutableArray.Create(
                start,
                rewrittenBody,
                New BoundLabelStatement(node.Syntax, node.ContinueLabel),
                New BoundGotoStatement(node.Syntax, startLabel, Nothing),
                New BoundLabelStatement(node.Syntax, node.ExitLabel)
            ))
 
        End Function
 
    End Class
End Namespace