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); } }
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); } }
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); }