public void VisitNode(JSFunctionExpression fn)
        {
            // Create a new visitor for nested function expressions
            if (Stack.OfType<JSFunctionExpression>().Skip(1).FirstOrDefault() != null) {
                bool eliminated = false;

                do {
                    var nested = new EliminateSingleUseTemporaries(TypeSystem, fn.AllVariables, FunctionSource);
                    nested.Visit(fn);
                    eliminated = nested.EliminatedVariables.Count > 0;
                } while (eliminated);

                return;
            }

            var nullList = new List<int>();
            FirstPass = FunctionSource.GetFirstPass(fn.Identifier);
            if (FirstPass == null)
                throw new InvalidOperationException();

            VisitChildren(fn);

            foreach (var v in fn.AllVariables.Values.ToArray()) {
                if (v.IsThis || v.IsParameter)
                    continue;

                var valueType = v.GetExpectedType(TypeSystem);
                if (ILBlockTranslator.IsIgnoredType(valueType))
                    continue;

                var assignments = (from a in FirstPass.Assignments where v.Equals(a.Target) select a).ToArray();
                var accesses = (from a in FirstPass.Accesses where v.Equals(a.Source) select a).ToArray();

                if (FirstPass.VariablesPassedByRef.Contains(v.Name)) {
                    if (TraceLevel >= 2)
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is passed by reference.", v));

                    continue;
                }

                if (assignments.FirstOrDefault() == null) {
                    if (accesses.Length == 0) {
                        if (TraceLevel >= 1)
                            Debug.WriteLine(String.Format("Eliminating {0} because it is never used.", v));

                        EliminatedVariables.Add(v);
                        EliminateVariable(fn, v, new JSEliminatedVariable(v));
                    } else {
                        if (TraceLevel >= 2)
                            Debug.WriteLine(String.Format("Never found an initial assignment for {0}.", v));
                    }

                    continue;
                }

                if ((from a in accesses where a.IsControlFlow select a).FirstOrDefault() != null) {
                    if (TraceLevel >= 2)
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it participates in control flow.", v));

                    continue;
                }

                /*
                if ((from a in FirstPass.Assignments where v.Equals(a.Target) && a.IsConversion select a).FirstOrDefault() != null) {
                    if (TraceLevel >= 2)
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it undergoes type conversion.", v));

                    continue;
                }
                 */

                if (assignments.Length > 1) {
                    if (TraceLevel >= 2)
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is reassigned.", v));

                    continue;
                }

                var copies = (from a in FirstPass.Assignments where v.Equals(a.SourceVariable) select a).ToArray();
                if ((copies.Length + accesses.Length) > 1) {
                    if (TraceLevel >= 2)
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is used multiple times.", v));

                    continue;
                }

                var replacement = assignments.First().NewValue;
                if (replacement.AllChildrenRecursive.Contains(v)) {
                    if (TraceLevel >= 2)
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it contains a self-reference.", v));

                    continue;
                }

                if (!IsEffectivelyConstant(v, replacement)) {
                    if (TraceLevel >= 2)
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is not a constant expression.", v));

                    continue;
                }

                if (TraceLevel >= 1)
                    Debug.WriteLine(String.Format("Eliminating {0} <- {1}", v, replacement));

                var transferDataTo = replacement as JSVariable;
                if (transferDataTo != null) {
                    foreach (var access in accesses) {
                        FirstPass.Accesses.Remove(access);
                        FirstPass.Accesses.Add(new FunctionAnalysis1stPass.Access(
                            access.StatementIndex, access.NodeIndex,
                            transferDataTo, access.IsControlFlow
                        ));
                    }

                    foreach (var assignment in assignments) {
                        FirstPass.Assignments.Remove(assignment);
                        FirstPass.Assignments.Add(new FunctionAnalysis1stPass.Assignment(
                            assignment.StatementIndex, assignment.NodeIndex,
                            transferDataTo, assignment.NewValue, assignment.Operator,
                            assignment.TargetType, assignment.SourceType

                       ));
                    }
                }

                FirstPass.Assignments.RemoveAll((a) => v.Equals(a.Target));
                FirstPass.Accesses.RemoveAll((a) => v.Equals(a.Source));

                EliminatedVariables.Add(v);

                EliminateVariable(fn, v, replacement);
            }
        }
Example #2
0
        public void VisitNode(JSFunctionExpression fn)
        {
            // Create a new visitor for nested function expressions
            if (Stack.OfType <JSFunctionExpression>().Skip(1).FirstOrDefault() != null)
            {
                bool eliminated = false;

                do
                {
                    var nested = new EliminateSingleUseTemporaries(TypeSystem, fn.AllVariables, FunctionSource);
                    nested.Visit(fn);
                    eliminated = nested.EliminatedVariables.Count > 0;
                } while (eliminated);

                return;
            }

            var nullList = new List <int>();

            FirstPass = FunctionSource.GetFirstPass(fn.Method.QualifiedIdentifier);
            if (FirstPass == null)
            {
                throw new InvalidOperationException(String.Format(
                                                        "No first pass static analysis data for method '{0}'",
                                                        fn.Method.QualifiedIdentifier
                                                        ));
            }

            VisitChildren(fn);

            foreach (var v in fn.AllVariables.Values.ToArray())
            {
                if (v.IsThis || v.IsParameter)
                {
                    continue;
                }

                var valueType = v.GetActualType(TypeSystem);
                if (TypeUtil.IsIgnoredType(valueType))
                {
                    continue;
                }

                var assignments = (from a in FirstPass.Assignments where v.Equals(a.Target) select a).ToArray();
                var accesses    = (from a in FirstPass.Accesses where v.Equals(a.Source) select a).ToArray();
                var invocations = (from i in FirstPass.Invocations where v.Name == i.ThisVariable select i).ToArray();

                if (FirstPass.VariablesPassedByRef.Contains(v.Name))
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is passed by reference.", v));
                    }

                    continue;
                }

                if (assignments.FirstOrDefault() == null)
                {
                    if (accesses.Length == 0)
                    {
                        if (TraceLevel >= 1)
                        {
                            Debug.WriteLine(String.Format("Eliminating {0} because it is never used.", v));
                        }

                        EliminatedVariables.Add(v);
                        EliminateVariable(fn, v, new JSEliminatedVariable(v), fn.Method.QualifiedIdentifier);
                    }
                    else
                    {
                        if (TraceLevel >= 2)
                        {
                            Debug.WriteLine(String.Format("Never found an initial assignment for {0}.", v));
                        }
                    }

                    continue;
                }

                if (invocations.Length > 0)
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; methods are invoked on it.", v));
                    }

                    continue;
                }

                if ((from a in accesses where a.IsControlFlow select a).FirstOrDefault() != null)
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it participates in control flow.", v));
                    }

                    continue;
                }

                if (assignments.Length > 1)
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is reassigned.", v));
                    }

                    continue;
                }

                var copies = (from a in FirstPass.Assignments where v.Equals(a.SourceVariable) select a).ToArray();
                if ((copies.Length + accesses.Length) > 1)
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is used multiple times.", v));
                    }

                    continue;
                }

                var replacement = assignments.First().NewValue;
                if (replacement.SelfAndChildrenRecursive.Contains(v))
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it contains a self-reference.", v));
                    }

                    continue;
                }

                if (!IsEffectivelyConstant(v, replacement))
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is not a constant expression.", v));
                    }

                    continue;
                }

                if (TraceLevel >= 1)
                {
                    Debug.WriteLine(String.Format("Eliminating {0} <- {1}", v, replacement));
                }

                var transferDataTo = replacement as JSVariable;
                if (transferDataTo != null)
                {
                    foreach (var access in accesses)
                    {
                        FirstPass.Accesses.Remove(access);
                        FirstPass.Accesses.Add(new FunctionAnalysis1stPass.Access(
                                                   access.ParentNodeIndices, access.StatementIndex, access.NodeIndex,
                                                   transferDataTo, access.IsControlFlow
                                                   ));
                    }

                    foreach (var assignment in assignments)
                    {
                        FirstPass.Assignments.Remove(assignment);
                        FirstPass.Assignments.Add(new FunctionAnalysis1stPass.Assignment(
                                                      assignment.ParentNodeIndices, assignment.StatementIndex, assignment.NodeIndex,
                                                      transferDataTo, assignment.NewValue, assignment.Operator,
                                                      assignment.TargetType, assignment.SourceType
                                                      ));
                    }

                    foreach (var invocation in invocations)
                    {
                        FirstPass.Invocations.Remove(invocation);
                        FirstPass.Invocations.Add(new FunctionAnalysis1stPass.Invocation(
                                                      invocation.ParentNodeIndices, invocation.StatementIndex, invocation.NodeIndex,
                                                      transferDataTo, invocation.Method, invocation.Variables
                                                      ));
                    }
                }

                FirstPass.Assignments.RemoveAll((a) => v.Equals(a.Target));
                FirstPass.Accesses.RemoveAll((a) => v.Equals(a.Source));

                EliminatedVariables.Add(v);

                EliminateVariable(fn, v, replacement, fn.Method.QualifiedIdentifier);
            }
        }
Example #3
0
        private void OptimizeFunction(
            SpecialIdentifiers si, HashSet<string> parameterNames,
            Dictionary<string, JSVariable> variables, JSFunctionExpression function
        )
        {
            // Run elimination repeatedly, since eliminating one variable may make it possible to eliminate others
            if (EliminateTemporaries) {
                bool eliminated;
                do {
                    var visitor = new EliminateSingleUseTemporaries(
                        si.TypeSystem, variables, FunctionCache
                    );
                    visitor.Visit(function);
                    eliminated = visitor.EliminatedVariables.Count > 0;
                } while (eliminated);
            }

            new EmulateStructAssignment(
                si.TypeSystem,
                FunctionCache,
                si.CLR,
                OptimizeStructCopies
            ).Visit(function);

            new IntroduceVariableDeclarations(
                variables,
                TypeInfoProvider
            ).Visit(function);

            new IntroduceVariableReferences(
                si.JSIL,
                variables,
                parameterNames
            ).Visit(function);

            if (SimplifyLoops)
                new SimplifyLoops(
                    si.TypeSystem
                ).Visit(function);

            // Temporary elimination makes it possible to simplify more operators, so do it last
            if (SimplifyOperators)
                new SimplifyOperators(
                    si.JSIL, si.JS, si.TypeSystem
                ).Visit(function);

            new IntroduceEnumCasts(
                si.TypeSystem
            ).Visit(function);
        }