/// <summary>
        /// Removes unassigned declared variables and replaces use sites by default expressions.
        /// </summary>
        /// <param name="block">The block to remove unassigned variables from.</param>
        /// <returns>The result of removing unassigned variables.</returns>
        /// <example>
        ///   <code>{ int x, int y; x = 1; x + y; }</code>
        ///   becomes
        ///   <code>{ int x; x = 1; x + default(int); }</code>
        /// </example>
        private BlockExpression RemoveUnassignedVariables(BlockExpression block)
        {
            var oldVariables = block.Variables;

            // REVIEW: This does a lot of repeated scanning of the same child nodes.
            //         We could consider storing these results for later reuse.

            if (oldVariables.Count > 0)
            {
                var analyzer = new AssignmentAnalyzer(oldVariables);

                analyzer.Visit(block.Expressions);

                var unassigned = analyzer.Unassigned;

                if (unassigned.Count > 0)
                {
                    var subst = new VariableDefaultValueSubstitutor(unassigned);

                    var newExpressions = subst.Visit(block.Expressions);

                    //
                    // NB: The introduction of default values can yield more optimization
                    //     opportunities, so we visit the child expressions again.
                    //
                    var optExpressions = Visit(newExpressions);

                    if (oldVariables.Count == unassigned.Count)
                    {
                        return(block.Update(variables: null, optExpressions));
                    }
                    else
                    {
                        var newVariables = new ParameterExpression[oldVariables.Count - unassigned.Count];

                        for (int i = 0, j = 0, n = oldVariables.Count; i < n; i++)
                        {
                            var variable = oldVariables[i];

                            if (!unassigned.Contains(variable))
                            {
                                newVariables[j++] = variable;
                            }
                        }

                        return(block.Update(newVariables, optExpressions));
                    }
                }
            }

            return(block);
        }
        protected override Expression VisitBlock(BlockExpression node)
        {
            if (CanOptimize(node))
            {
                return FlattenBlocks(node);
            }

            var variables = VisitAndConvert(node.Variables, nameof(VisitBlock));
            var expressions = VisitSequence(node.Expressions);

            return node.Update(variables, expressions);
        }
        /// <summary>
        /// Removes unused declared variables from the specified block.
        /// </summary>
        /// <param name="block">The block to remove unused declared variables from.</param>
        /// <returns>The result of removing unused variables.</returns>
        /// <example>
        ///   <code>{ int x, int y; x + 1; }</code>
        ///   becomes
        ///   <code>{ int x; x + 1; }</code>
        /// </example>
        private static BlockExpression RemoveUnusedVariables(BlockExpression block)
        {
            var variables = block.Variables;

            var n = variables.Count;

            if (n > 0)
            {
                // REVIEW: This does a lot of repeated scanning of the same child nodes.
                //         We could consider storing these results for later reuse.

                var finder = new FreeVariableFinder();

                finder.Visit(block.Expressions);

                var freeVariables = finder.FreeVariables;

                var remainingVariables = default(List <ParameterExpression>);

                for (var i = 0; i < n; i++)
                {
                    var variable = variables[i];

                    if (!freeVariables.Contains(variable))
                    {
                        if (remainingVariables == null)
                        {
                            remainingVariables = new List <ParameterExpression>(n);

                            for (var j = 0; j < i; j++)
                            {
                                remainingVariables.Add(variables[j]);
                            }
                        }
                    }
                    else
                    {
                        remainingVariables?.Add(variable);
                    }
                }

                if (remainingVariables != null)
                {
                    return(block.Update(remainingVariables, block.Expressions));
                }
            }

            return(block);
        }
        /// <summary>
        /// Removes pure statements from the specified <paramref name="block"/> expression.
        /// </summary>
        /// <param name="block">The block to remove pure statements from.</param>
        /// <returns>The result of removing pure statements.</returns>
        /// <example>
        ///   <code>{ ; x; F(); 42; G(); }</code>
        ///   becomes
        ///   <code>{ F(); G(); }</code>
        /// </example>
        private Expression RemovePureStatements(BlockExpression block)
        {
            var oldExpressions = block.Expressions;
            var newExpressions = default(List <Expression>);

            var count = oldExpressions.Count;

            for (int i = 0, n = count - 1; i < n; i++)
            {
                var expr = block.Expressions[i];

                if (IsPure(expr))
                {
                    if (newExpressions == null)
                    {
                        newExpressions = new List <Expression>(n);

                        for (var j = 0; j < i; j++)
                        {
                            newExpressions.Add(oldExpressions[j]);
                        }
                    }
                }
                else if (newExpressions != null)
                {
                    newExpressions.Add(expr);
                }
            }

            if (newExpressions == null)
            {
                return(block);
            }
            else if (newExpressions.Count == 0)
            {
                return(ChangeType(oldExpressions[count - 1], block.Type));
            }
            else
            {
                newExpressions.Add(oldExpressions[count - 1]);

                return(block.Update(block.Variables, newExpressions));
            }
        }
Exemple #5
0
            protected override Expression VisitBlock(BlockExpression node)
            {
                if (node.Variables.Count > 0)
                {
                    _environment.Push(node.Variables);
                }

                //
                // Expressions execute top-to-bottom. Any branches will be taken care of by visits to Label, Goto,
                // Conditional, Try, or Loop expressions, so we can just proceed in order.
                //
                var expressions = Visit(node.Expressions);

                if (node.Variables.Count > 0)
                {
                    _environment.Pop();
                }

                return(node.Update(node.Variables, expressions));
            }
 protected override Expression VisitBlock(BlockExpression node)
 {
     var exprs = node.Expressions.SelectMany(e => new Expression[] { _log(Expression.Constant("S" + _n++)), Visit(e) }).ToList();
     return node.Update(node.Variables, exprs);
 }
        /// <summary>
        /// Flattens nested blocks to reduce the nesting level.
        /// </summary>
        /// <param name="block">The block to flatten.</param>
        /// <returns>The result of flattening nested blocks.</returns>
        /// <example>
        ///   <code>{ int x; { int y; x + y; } }</code>
        ///   becomes
        ///   <code>{ int x, int y; x + y; }</code>
        /// </example>
        private Expression FlattenBlocks(BlockExpression block)
        {
            var allVariables = default(HashSet <ParameterExpression>);
            var variableList = default(List <ParameterExpression>);

            var current = block;

            //
            // NB: This optimization is only safe for blocks with single expressions in
            //     them because we're flattening declaration scopes. In a block has more
            //     than one expression, this could result in changing bindings:
            //
            //     { int x; { int y; x + y; } y; } -> { int x, int y; x + y; y }
            //
            //     In this example, the binding of expression `y` in the outer block has
            //     changed due to scope merging. If only a single child block expression
            //     exists, this can't occur.
            //
            // CONSIDER: There are more cases where flattening blocks is safe to do, but
            //           these may require more analysis steps. Nested blocks without any
            //           variables or local branches could be merged into the parent.
            //

            while (current.Expressions.Count == 1 && current.Expressions[0].NodeType == ExpressionType.Block)
            {
                var variables = current.Variables;

                if (variables.Count > 0)
                {
                    if (allVariables == null)
                    {
                        allVariables = new HashSet <ParameterExpression>();
                        variableList = new List <ParameterExpression>();
                    }

                    foreach (var variable in variables)
                    {
                        if (allVariables.Add(variable))
                        {
                            variableList.Add(variable);
                        }
                    }
                }

                current = (BlockExpression)current.Expressions[0];
            }

            if (current != block)
            {
                IEnumerable <ParameterExpression> variables;

                if (variableList == null)
                {
                    variables = current.Variables;
                }
                else
                {
                    if (current.Variables.Count > 0)
                    {
                        foreach (var variable in current.Variables)
                        {
                            if (allVariables.Add(variable))
                            {
                                variableList.Add(variable);
                            }
                        }
                    }

                    variables = variableList;
                }

                var expressions = current.Expressions;

                block = block.Update(variables, expressions);
            }

            if (block.Variables.Count == 0 && block.Expressions.Count == 1)
            {
                return(ChangeType(block.Expressions[0], block.Type));
            }

            return(block);
        }
Exemple #8
0
        private static BlockExpression Update(BlockExpression node)
        {
            // Tests the call of Update to Expression.Block factories.

            var res = node.Update(node.Variables, node.Expressions.ToArray());

            Assert.NotSame(node, res);

            return res;
        }