[NotNull] private static IReadOnlyDictionary <IBasicBlock, IMutableBasicBlock> CloneVertices(
            [NotNull] this IControlFlowGraph input,
            IMutableControlFlowGraph output,
            [NotNull] Func <IBasicBlock, bool> keep,
            [CanBeNull] Action <IBasicBlock, IMutableBasicBlock> copy = null
            )
        {
            // Clone vertices (without edges)
            var replacements = new Dictionary <IBasicBlock, IMutableBasicBlock>();

            foreach (var vertex in input.Vertices.Where(keep))
            {
                var r = output.CreateNewBlock(vertex.Type, vertex.LineNumber, vertex.ID);
                replacements.Add(vertex, r);

                if (copy != null)
                {
                    copy(vertex, r);
                }
                else
                {
                    foreach (var stmt in vertex.Statements)
                    {
                        r.Add(stmt);
                    }
                }
            }

            return(replacements);
        }
Exemple #2
0
        private IMutableBasicBlock GetLineEntryBlock(IMutableControlFlowGraph cfg, int lineNumber)
        {
            if (!_lineStartBlocks.TryGetValue(lineNumber, out var block))
            {
                block = cfg.CreateNewBlock(BasicBlockType.LineStart, lineNumber);
                _lineStartBlocks.Add(lineNumber, block);
            }

            return(block);
        }
Exemple #3
0
        /// <summary>
        /// Convert a statement list into basic blocks. Return the final block that was created if it needs to be connected to the next block
        /// </summary>
        /// <param name="cfg"></param>
        /// <param name="statements"></param>
        /// <param name="lineNumber"></param>
        /// <param name="entry"></param>
        /// <returns>(entry_block!, exit_block?)</returns>
        private (IMutableBasicBlock, IMutableBasicBlock) HandleStatementList(IMutableControlFlowGraph cfg, StatementList statements, int lineNumber, IMutableBasicBlock entry)
        {
            var block = cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber);

            cfg.CreateEdge(entry, block, EdgeType.Continue);

            foreach (var stmt in statements.Statements)
            {
                if (stmt is Goto @goto)
                {
                    HandleGoto(cfg, @goto, block, lineNumber);

                    // Create a new block which is _not_ linked to the previous (because we just unconditionally jumped away)
                    block = cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber);
                }
                else if (stmt is If @if)
                {
                    block.Add(new Conditional(@if.Condition));

                    // Convert true and false branches into blocks
                    var(enTrue, exTrue) = HandleStatementList(cfg, @if.TrueBranch, lineNumber, cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber));
                    var(enFals, exFals) = HandleStatementList(cfg, @if.FalseBranch, lineNumber, cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber));

                    // Create edges from conditional to two branches
                    cfg.CreateEdge(block, enTrue, EdgeType.ConditionalTrue);
                    cfg.CreateEdge(block, enFals, EdgeType.ConditionalFalse);

                    // Link the exit blocks (if they're not null) to the next block
                    block = cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber);
                    if (exTrue != null)
                    {
                        cfg.CreateEdge(exTrue, block, EdgeType.Continue);
                    }
                    if (exFals != null)
                    {
                        cfg.CreateEdge(exFals, block, EdgeType.Continue);
                    }
                }
                else if (stmt is EmptyStatement)
                {
                    // ignore empty statements, they (obviously) don't do anything
                    // ReSharper disable once RedundantJumpStatement
                    continue;
                }
                else
                {
                    // Add to block with fallthrough to next line if it can error
                    block.Add(stmt);
                    if (stmt.CanRuntimeError)
                    {
                        AddFallthrough(cfg, block, lineNumber, EdgeType.RuntimeError);

                        var b2 = cfg.CreateNewBlock(BasicBlockType.Basic, block.LineNumber);
                        cfg.CreateEdge(block, b2, EdgeType.Continue);
                        block = b2;
                    }
                }
            }

            return(entry, block);
        }