BasicBlock.cs 5.4 KB
Newer Older
1 2
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

3
using System;
4
using System.Collections.Immutable;
5 6
using System.Diagnostics;
using System.Linq;
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
using Microsoft.CodeAnalysis.PooledObjects;

namespace Microsoft.CodeAnalysis.Operations
{
    /// <summary>
    /// PROTOTYPE(dataflow): Add documentation
    /// </summary>
    public enum BasicBlockKind
    {
        Entry,
        Exit,
        Block
    }

    /// <summary>
    /// PROTOTYPE(dataflow): Add documentation
    /// PROTOTYPE(dataflow): We need to figure out how to split it into a builder and 
    ///                      a public immutable type.
    /// </summary>
    public sealed class BasicBlock
    {
        private readonly ImmutableArray<IOperation>.Builder _statements;
        private readonly ImmutableHashSet<BasicBlock>.Builder _predecessors;
30
        internal (IOperation Value, Branch Branch) InternalNext;
31
        internal (IOperation Condition, bool JumpIfTrue, Branch Branch) InternalConditional;
32 33 34 35 36 37 38 39 40 41 42 43 44 45

        public BasicBlock(BasicBlockKind kind)
        {
            Kind = kind;
            _statements = ImmutableArray.CreateBuilder<IOperation>();
            _predecessors = ImmutableHashSet.CreateBuilder<BasicBlock>();
        }

        public BasicBlockKind Kind { get; private set; }
        public ImmutableArray<IOperation> Statements => _statements.ToImmutable();

        /// <summary>
        /// PROTOTYPE(dataflow): Tuple is temporary return type, we probably should use special structure instead.
        /// </summary>
46
        public (IOperation Condition, bool JumpIfTrue, Branch Branch) Conditional => InternalConditional;
47 48 49 50

        /// <summary>
        /// PROTOTYPE(dataflow): During CR there was a suggestion to use different name - "Successor".
        /// </summary>
51
        public (IOperation Value, Branch Branch) Next => InternalNext;
52 53 54

        public ImmutableHashSet<BasicBlock> Predecessors => _predecessors.ToImmutable();

55 56
        public int Ordinal { get; internal set; } = -1;

57 58
        public bool IsReachable { get; internal set; } = false;

59 60 61 62 63
        /// <summary>
        /// Enclosing region
        /// </summary>
        public ControlFlowGraph.Region Region { get; internal set; }

64 65 66 67 68
        internal void AddStatement(IOperation statement)
        {
            _statements.Add(statement);
        }

69 70 71 72 73 74 75 76 77 78
        internal void AddStatements(ImmutableArray<IOperation> statements)
        {
            _statements.AddRange(statements);
        }

        internal void RemoveStatements()
        {
            _statements.Clear();
        }

79 80 81 82 83 84 85 86 87
        internal void AddPredecessor(BasicBlock block)
        {
            _predecessors.Add(block);
        }

        internal void RemovePredecessor(BasicBlock block)
        {
            _predecessors.Remove(block);
        }
88

89
        public enum BranchKind
90
        {
91 92 93 94 95 96 97
            None,
            Regular,
            Return,
            StructuredExceptionHandling,
            ProgramTermination,
            Throw,
            ReThrow,
98 99 100 101 102 103
        }

        public struct Branch
        {
            private ImmutableArray<ControlFlowGraph.Region> _lazyFinallyRegions;

104
            public BranchKind Kind { get; internal set; }
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
            public BasicBlock Destination { get; internal set; }

            /// <summary>
            /// What regions are exited (from inner most to outer most) if this branch is taken.
            /// </summary>
            public ImmutableArray<ControlFlowGraph.Region> LeavingRegions { get; internal set; }

            /// <summary>
            /// What regions are entered (from outer most to inner most) if this branch is taken.
            /// </summary>
            public ImmutableArray<ControlFlowGraph.Region> EnteringRegions { get; internal set; }

            /// <summary>
            /// The finally regions the control goes through if the branch is taken
            /// </summary>
            public ImmutableArray<ControlFlowGraph.Region> FinallyRegions
            {
                get
                {
                    if (_lazyFinallyRegions.IsDefault)
                    {
                        ArrayBuilder<ControlFlowGraph.Region> builder = null;
                        ImmutableArray<ControlFlowGraph.Region> leavingRegions = LeavingRegions;
                        int stopAt = leavingRegions.Length - 1;
                        for (int i = 0; i < stopAt; i++)
                        {
                            if (leavingRegions[i].Kind == ControlFlowGraph.RegionKind.Try && leavingRegions[i+1].Kind == ControlFlowGraph.RegionKind.TryAndFinally)
                            {
                                if (builder == null)
                                {
                                    builder = ArrayBuilder<ControlFlowGraph.Region>.GetInstance();
                                }

                                builder.Add(leavingRegions[i + 1].Regions.Last());
139
                                Debug.Assert(builder.Last().Kind == ControlFlowGraph.RegionKind.Finally);
140 141 142 143 144 145 146 147 148 149 150 151
                            }
                        }

                        var result = builder == null ? ImmutableArray<ControlFlowGraph.Region>.Empty : builder.ToImmutableAndFree();

                        ImmutableInterlocked.InterlockedInitialize(ref _lazyFinallyRegions, result);
                    }

                    return _lazyFinallyRegions;
                }
            }
        }
152 153
    }
}