protected void EliminateVariable(JSNode context, JSVariable variable, JSExpression replaceWith, QualifiedMemberIdentifier method) { { var replacer = new VariableEliminator( variable, JSChangeTypeExpression.New(replaceWith, variable.GetActualType(TypeSystem), TypeSystem) ); replacer.Visit(context); } { var replacer = new VariableEliminator(variable, replaceWith); var assignments = (from a in FirstPass.Assignments where variable.Equals(a.NewValue) || a.NewValue.SelfAndChildrenRecursive.Any(variable.Equals) select a).ToArray(); foreach (var a in assignments) { if (!variable.Equals(a.NewValue)) { replacer.Visit(a.NewValue); } } } Variables.Remove(variable.Identifier); FunctionSource.InvalidateFirstPass(method); }
protected void EliminateVariable(JSNode context, JSVariable variable, JSExpression replaceWith, QualifiedMemberIdentifier method) { { var replacer = new VariableEliminator( variable, JSChangeTypeExpression.New(replaceWith, TypeSystem, variable.GetActualType(TypeSystem)) ); replacer.Visit(context); } { var replacer = new VariableEliminator(variable, replaceWith); var assignments = (from a in FirstPass.Assignments where variable.Equals(a.NewValue) || a.NewValue.SelfAndChildrenRecursive.Any((_n) => variable.Equals(_n)) select a).ToArray(); foreach (var a in assignments) { if (variable.Equals(a.NewValue)) { FirstPass.Assignments.Remove(a); FirstPass.Assignments.Add( new FunctionAnalysis1stPass.Assignment( a.ParentNodeIndices, a.StatementIndex, a.NodeIndex, a.Target, replaceWith, a.Operator, a.TargetType, a.SourceType ) ); } else { replacer.Visit(a.NewValue); } } } Variables.Remove(variable.Identifier); FunctionSource.InvalidateFirstPass(method); }
public void VisitNode(JSVariable variable) { if (CurrentName == "FunctionSignature") { // In argument list return; } if (Variable.Equals(variable)) { ParentNode.ReplaceChild(variable, Replacement); } else { VisitChildren(variable); } }
protected bool IsEffectivelyConstant(JSVariable target, JSExpression source) { if ((source == null) || (source.IsNull)) { return(false); } // Can't eliminate struct temporaries, since that might eliminate some implied copies. if (TypeUtil.IsStruct(target.Type)) { return(false); } // Handle special cases where our interpretation of 'constant' needs to be more flexible { var ie = source as JSIndexerExpression; if (ie != null) { if ( IsEffectivelyConstant(target, ie.Target) && IsEffectivelyConstant(target, ie.Index) ) { return(true); } } } { var ae = source as JSArrayExpression; if ( (ae != null) && (from av in ae.Values select IsEffectivelyConstant(target, av)).All((b) => b) ) { return(true); } } { var de = source as JSDotExpressionBase; if ( (de != null) && IsEffectivelyConstant(target, de.Target) && IsEffectivelyConstant(target, de.Member) ) { return(true); } } { var ie = source as JSInvocationExpression; if ( (ie != null) && ie.ConstantIfArgumentsAre && IsEffectivelyConstant(target, ie.ThisReference) && ie.Arguments.All((a) => IsEffectivelyConstant(target, a)) ) { return(true); } if ((ie != null) && (ie.JSMethod != null)) { var sa = FunctionSource.GetSecondPass(ie.JSMethod); if (sa != null) { if (sa.IsPure) { if (ie.Arguments.All((a) => IsEffectivelyConstant(target, a))) { return(true); } else { return(false); } } } } } if ((source is JSUnaryOperatorExpression) || (source is JSBinaryOperatorExpression)) { if (source.Children.OfType <JSExpression>().All((_v) => IsEffectivelyConstant(target, _v))) { return(true); } } if (source.IsConstant) { return(true); } // Try to find a spot between the source variable's assignments where all of our // copies and accesses can fit. If we find one, our variable is effectively constant. var v = source as JSVariable; if (v != null) { var assignments = (from a in FirstPass.Assignments where v.Equals(a.Target) select a).ToArray(); if (assignments.Length < 1) { return(v.IsParameter); } var targetAssignments = (from a in FirstPass.Assignments where v.Equals(a.Target) select a).ToArray(); if (targetAssignments.Length < 1) { return(false); } var targetAccesses = (from a in FirstPass.Accesses where target.Equals(a.Source) select a).ToArray(); if (targetAccesses.Length < 1) { return(false); } var targetFirstAssigned = targetAssignments.FirstOrDefault(); var targetLastAssigned = targetAssignments.LastOrDefault(); var targetFirstAccessed = targetAccesses.FirstOrDefault(); var targetLastAccessed = targetAccesses.LastOrDefault(); bool foundAssignmentSlot = false; for (int i = 0, c = assignments.Length; i < c; i++) { int assignment = assignments[i].StatementIndex, nextAssignment = int.MaxValue; if (i < c - 1) { nextAssignment = assignments[i + 1].StatementIndex; } if ( (targetFirstAssigned.StatementIndex >= assignment) && (targetFirstAssigned.StatementIndex < nextAssignment) && (targetFirstAccessed.StatementIndex >= assignment) && (targetLastAccessed.StatementIndex <= nextAssignment) ) { foundAssignmentSlot = true; break; } } if (!foundAssignmentSlot) { return(false); } return(true); } return(false); }
public void VisitNode(JSWhileLoop whileLoop) { JSVariable initVariable = null, lastVariable = null; JSBinaryOperator initOperator = null; JSExpression initValue = null; var prevEStmt = PreviousSibling as JSExpressionStatement; var prevVDS = PreviousSibling as JSVariableDeclarationStatement; if (prevEStmt != null) { var boe = prevEStmt.Expression as JSBinaryOperatorExpression; if ( (boe != null) && (boe.Operator is JSAssignmentOperator) && (boe.Left is JSVariable) ) { initVariable = (JSVariable)boe.Left; initOperator = boe.Operator; initValue = boe.Right; } } else if (prevVDS != null) { var decl = prevVDS.Declarations.FirstOrDefault( (d) => !d.IsNull ); if (decl != null) { initVariable = (JSVariable)decl.Left; initOperator = decl.Operator; initValue = decl.Right; } } var lastStatement = whileLoop.Statements.LastOrDefault(); while ((lastStatement != null) && (lastStatement.GetType() == typeof(JSBlockStatement))) { lastStatement = ((JSBlockStatement)lastStatement).Statements.LastOrDefault(); } var lastExpressionStatement = lastStatement as JSExpressionStatement; if (lastExpressionStatement != null) { var lastUoe = lastExpressionStatement.Expression as JSUnaryOperatorExpression; var lastBoe = lastExpressionStatement.Expression as JSBinaryOperatorExpression; if ((lastUoe != null) && (lastUoe.Operator is JSUnaryMutationOperator)) { lastVariable = lastUoe.Expression as JSVariable; } else if ((lastBoe != null) && (lastBoe.Operator is JSAssignmentOperator)) { lastVariable = lastBoe.Left as JSVariable; if ( (lastVariable != null) && !lastBoe.Right.SelfAndChildrenRecursive.Any( (n) => lastVariable.Equals(n) ) ) { lastVariable = null; } } } var lastIfStatement = lastStatement as JSIfStatement; if ( (lastIfStatement != null) && whileLoop.Condition is JSBooleanLiteral && ((JSBooleanLiteral)whileLoop.Condition).Value ) { var innerStatement = lastIfStatement.TrueClause; while (innerStatement is JSBlockStatement) { var bs = (JSBlockStatement)innerStatement; if (bs.Statements.Count != 1) { innerStatement = null; break; } innerStatement = bs.Statements[0]; } var eStmt = innerStatement as JSExpressionStatement; if (eStmt != null) { var breakExpr = eStmt.Expression as JSBreakExpression; if ((breakExpr != null) && (breakExpr.TargetLoop == whileLoop.Index)) { whileLoop.ReplaceChildRecursive(lastIfStatement, new JSNullStatement()); var doLoop = new JSDoLoop( new JSUnaryOperatorExpression(JSOperator.LogicalNot, lastIfStatement.Condition, TypeSystem.Boolean), whileLoop.Statements.ToArray() ); doLoop.Index = whileLoop.Index; ParentNode.ReplaceChild(whileLoop, doLoop); VisitChildren(doLoop); return; } } } bool cantBeFor = false; if ((initVariable != null) && (lastVariable != null) && !initVariable.Equals(lastVariable) ) { cantBeFor = true; } else if ((initVariable ?? lastVariable) == null) { cantBeFor = true; } else if (!whileLoop.Condition.SelfAndChildrenRecursive.Any( (n) => (initVariable ?? lastVariable).Equals(n) )) { cantBeFor = true; } else if ( !PostSwitchTransform && ( (lastStatement is JSSwitchStatement) || (lastStatement is JSLabelGroupStatement) ) ) { cantBeFor = true; } if (!cantBeFor) { JSStatement initializer = null, increment = null; if (initVariable != null) { initializer = PreviousSibling as JSStatement; ParentNode.ReplaceChild(PreviousSibling, new JSNullStatement()); } if (lastVariable != null) { increment = lastExpressionStatement; whileLoop.ReplaceChildRecursive(lastExpressionStatement, new JSNullStatement()); } var forLoop = new JSForLoop( initializer, whileLoop.Condition, increment, whileLoop.Statements.ToArray() ); forLoop.Index = whileLoop.Index; ParentNode.ReplaceChild(whileLoop, forLoop); VisitChildren(forLoop); } else { VisitChildren(whileLoop); } }
protected bool IsEffectivelyConstant(JSVariable target, JSExpression source) { if ((source == null) || (source.IsNull)) { return(false); } // Can't eliminate struct temporaries, since that might eliminate some implied copies. if (TypeUtil.IsStruct(target.IdentifierType)) { return(false); } // Handle special cases where our interpretation of 'constant' needs to be more flexible { var ie = source as JSIndexerExpression; if (ie != null) { if ( IsEffectivelyConstant(target, ie.Target) && IsEffectivelyConstant(target, ie.Index) ) { return(true); } } } { var ae = source as JSArrayExpression; if ( (ae != null) && (from av in ae.Values select IsEffectivelyConstant(target, av)).All((b) => b) ) { return(true); } } { var de = source as JSDotExpressionBase; if ( (de != null) && IsEffectivelyConstant(target, de.Target) && IsEffectivelyConstant(target, de.Member) ) { var pa = source as JSPropertyAccess; if (pa != null) { // Property accesses must not be treated as constant since they call functions // TODO: Use static analysis information to figure out whether the accessor is pure/has state dependencies return(false); } return(true); } } { var ie = source as JSInvocationExpression; if ( (ie != null) && ie.ConstantIfArgumentsAre && IsEffectivelyConstant(target, ie.ThisReference) && ie.Arguments.All((a) => IsEffectivelyConstant(target, a)) ) { return(true); } if ((ie != null) && (ie.JSMethod != null)) { var sa = GetSecondPass(ie.JSMethod); if (sa != null) { if (sa.IsPure) { if (ie.Arguments.All((a) => IsEffectivelyConstant(target, a))) { return(true); } else { return(false); } } } } } if ((source is JSUnaryOperatorExpression) || (source is JSBinaryOperatorExpression)) { if (source.Children.OfType <JSExpression>().All((_v) => IsEffectivelyConstant(target, _v))) { return(true); } } if (source.IsConstant) { return(true); } // Try to find a spot between the source variable's assignments where all of our // copies and accesses can fit. If we find one, our variable is effectively constant. // FIXME: I think this section might be fundamentally flawed. Do let me know if you agree. :) var v = source as JSVariable; if (v != null) { // Ensure that we never treat a local variable as constant if functions we call allow it to escape // or modify it, because that can completely invalidate our purity analysis. if (VariablesExemptedFromEffectivelyConstantStatus.Contains(v.Identifier)) { return(false); } var sourceAssignments = (from a in FirstPass.Assignments where v.Equals(a.Target) select a).ToArray(); if (sourceAssignments.Length < 1) { return(v.IsParameter); } var sourceAccesses = (from a in FirstPass.Accesses where v.Equals(a.Source) select a).ToArray(); if (sourceAccesses.Length < 1) { return(false); } var targetAssignmentIndices = (from a in FirstPass.Assignments where target.Equals(a.Target) select a.StatementIndex); var targetAccessIndices = (from a in FirstPass.Accesses where target.Equals(a.Source) select a.StatementIndex).ToArray(); var targetUseIndices = targetAccessIndices.Concat(targetAssignmentIndices).ToArray(); if (sourceAssignments.Length == 1) { if (targetAccessIndices.All((tai) => tai > sourceAssignments[0].StatementIndex)) { return(true); } } var sourceFirstAssigned = sourceAssignments.First(); var sourceLastAssigned = sourceAssignments.Last(); var sourceFirstAccessed = sourceAccesses.First(); var sourceLastAccessed = sourceAccesses.Last(); bool foundAssignmentSlot = false; for (int i = 0, c = targetUseIndices.Length; i < c; i++) { int assignment = targetUseIndices[i], nextAssignment = int.MaxValue; if (i < c - 1) { nextAssignment = targetUseIndices[i + 1]; } if ( (sourceFirstAssigned.StatementIndex >= assignment) && (sourceLastAssigned.StatementIndex < nextAssignment) && (sourceFirstAccessed.StatementIndex >= assignment) && (sourceLastAccessed.StatementIndex <= nextAssignment) ) { if (TraceLevel >= 5) { Console.WriteLine("Found assignment slot for {0} <- {1} between {2} and {3}", target, source, assignment, nextAssignment); } foundAssignmentSlot = true; break; } } if (!foundAssignmentSlot) { return(false); } return(true); } return(false); }