Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library tree_ir.optimization.statement_rewriter; | 5 library tree_ir.optimization.statement_rewriter; |
| 6 | 6 |
| 7 import 'optimization.dart' show Pass; | 7 import 'optimization.dart' show Pass; |
| 8 import '../tree_ir_nodes.dart'; | 8 import '../tree_ir_nodes.dart'; |
| 9 import '../../io/source_information.dart'; | 9 import '../../io/source_information.dart'; |
| 10 import '../../elements/elements.dart'; | 10 import '../../elements/elements.dart'; |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 160 /// Assignments with constant right-hand sides (see [isEffectivelyConstant]) | 160 /// Assignments with constant right-hand sides (see [isEffectivelyConstant]) |
| 161 /// are not considered impure and are put in [constantEnvironment] instead. | 161 /// are not considered impure and are put in [constantEnvironment] instead. |
| 162 /// | 162 /// |
| 163 /// Except for [Conditional]s, expressions in the environment have | 163 /// Except for [Conditional]s, expressions in the environment have |
| 164 /// not been processed, and all their subexpressions must therefore be | 164 /// not been processed, and all their subexpressions must therefore be |
| 165 /// variables uses. | 165 /// variables uses. |
| 166 List<Expression> environment = <Expression>[]; | 166 List<Expression> environment = <Expression>[]; |
| 167 | 167 |
| 168 /// Binding environment for variables that are assigned to effectively | 168 /// Binding environment for variables that are assigned to effectively |
| 169 /// constant expressions (see [isEffectivelyConstant]). | 169 /// constant expressions (see [isEffectivelyConstant]). |
| 170 Map<Variable, Expression> constantEnvironment; | 170 Map<Variable, Expression> constantEnvironment = <Variable, Expression>{}; |
| 171 | 171 |
| 172 /// Substitution map for labels. Any break to a label L should be substituted | 172 /// Substitution map for labels. Any break to a label L should be substituted |
| 173 /// for a break to L' if L maps to L'. | 173 /// for a break to L' if L maps to L'. |
| 174 Map<Label, Jump> labelRedirects = <Label, Jump>{}; | 174 Map<Label, Jump> labelRedirects = <Label, Jump>{}; |
| 175 | 175 |
| 176 /// Number of uses of the given variable that are still unseen. | 176 /// Number of uses of the given variable that are still unseen. |
| 177 /// Used to detect the first use of a variable (since we do backwards | 177 /// Used to detect the first use of a variable (since we do backwards |
| 178 /// traversal, the first use is the last one seen). | 178 /// traversal, the first use is the last one seen). |
| 179 Map<Variable, int> unseenUses = <Variable, int>{}; | 179 Map<Variable, int> unseenUses = <Variable, int>{}; |
| 180 | 180 |
| 181 /// Number of assignments to a given variable that dominate the current | 181 /// Number of assignments to a given variable that dominate the current |
| 182 /// position. | 182 /// position. |
| 183 /// | 183 /// |
| 184 /// Pure expressions will not be inlined if it uses a variable with more than | 184 /// Pure expressions will not be inlined if it uses a variable with more than |
| 185 /// one dominating assignment, because the reaching definition of the used | 185 /// one dominating assignment, because the reaching definition of the used |
| 186 /// variable might have changed since it was put in the environment. | 186 /// variable might have changed since it was put in the environment. |
| 187 final Map<Variable, int> dominatingAssignments = <Variable, int>{}; | 187 final Map<Variable, int> dominatingAssignments = <Variable, int>{}; |
| 188 | 188 |
| 189 /// Rewriter for methods. | |
| 190 StatementRewriter() : constantEnvironment = <Variable, Expression>{}; | |
| 191 | |
| 192 /// Rewriter for nested functions. | |
| 193 StatementRewriter.nested(StatementRewriter parent) | |
| 194 : constantEnvironment = parent.constantEnvironment, | |
| 195 unseenUses = parent.unseenUses; | |
| 196 | |
|
asgerf
2016/01/06 00:18:41
Drive-by cleanup
| |
| 197 /// A set of labels that can be safely inlined at their use. | 189 /// A set of labels that can be safely inlined at their use. |
| 198 /// | 190 /// |
| 199 /// The successor statements for labeled statements that have only one break | 191 /// The successor statements for labeled statements that have only one break |
| 200 /// from them are normally rewritten inline at the site of the break. This | 192 /// from them are normally rewritten inline at the site of the break. This |
| 201 /// is not safe if the code would be moved inside the scope of an exception | 193 /// is not safe if the code would be moved inside the scope of an exception |
| 202 /// handler (i.e., if the code would be moved into a try from outside it). | 194 /// handler (i.e., if the code would be moved into a try from outside it). |
| 203 Set<Label> safeForInlining = new Set<Label>(); | 195 Set<Label> safeForInlining = new Set<Label>(); |
| 204 | 196 |
| 197 /// If the top element is true, assignments of form "x = CONST" may be | |
| 198 /// propagated into a following occurence of CONST. This may confuse the JS | |
| 199 /// runtime so it is disabled in some cases. | |
|
sra1
2016/01/06 00:41:06
'engine' rather than 'runtime'.
asgerf
2016/01/06 15:43:31
Done.
| |
| 200 List<bool> allowRhsPropagation = <bool>[true]; | |
|
sra1
2016/01/06 00:41:06
I assume it was too nasty to thread through as an
asgerf
2016/01/06 15:43:31
Yeah.
| |
| 201 | |
| 202 bool get isAllowingRhsPropagation => allowRhsPropagation.last; | |
|
sra1
2016/01/06 00:41:06
Maybe rename to isRhsPropagationAllowed.
('are you
asgerf
2016/01/06 15:43:31
Done.
| |
| 203 | |
| 205 /// Returns the redirect target of [jump] or [jump] itself if it should not | 204 /// Returns the redirect target of [jump] or [jump] itself if it should not |
| 206 /// be redirected. | 205 /// be redirected. |
| 207 Jump redirect(Jump jump) { | 206 Jump redirect(Jump jump) { |
| 208 Jump newJump = labelRedirects[jump.target]; | 207 Jump newJump = labelRedirects[jump.target]; |
| 209 return newJump != null ? newJump : jump; | 208 return newJump != null ? newJump : jump; |
| 210 } | 209 } |
| 211 | 210 |
| 212 void inEmptyEnvironment(void action(), {bool keepConstants: true}) { | 211 void inEmptyEnvironment(void action(), {bool keepConstants: true}) { |
| 213 List oldEnvironment = environment; | 212 List oldEnvironment = environment; |
| 214 Map oldConstantEnvironment = constantEnvironment; | 213 Map oldConstantEnvironment = constantEnvironment; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 320 return visitExpression(binding); | 319 return visitExpression(binding); |
| 321 } | 320 } |
| 322 | 321 |
| 323 // Is the most recently evaluated impure expression known to have the | 322 // Is the most recently evaluated impure expression known to have the |
| 324 // value of this variable? | 323 // value of this variable? |
| 325 // | 324 // |
| 326 // If so, we can replace this use with the impure expression, e.g: | 325 // If so, we can replace this use with the impure expression, e.g: |
| 327 // | 326 // |
| 328 // { E.foo = x; bar(x) } ==> bar(E.foo = x) | 327 // { E.foo = x; bar(x) } ==> bar(E.foo = x) |
| 329 // | 328 // |
| 330 if (getRightHandVariable(binding) == node.variable) { | 329 if (isAllowingRhsPropagation && |
| 330 getRightHandVariable(binding) == node.variable) { | |
| 331 environment.removeLast(); | 331 environment.removeLast(); |
| 332 --node.variable.readCount; | 332 --node.variable.readCount; |
| 333 return visitExpression(binding); | 333 return visitExpression(binding); |
| 334 } | 334 } |
| 335 } | 335 } |
| 336 | 336 |
| 337 // If the definition could not be propagated, leave the variable use. | 337 // If the definition could not be propagated, leave the variable use. |
| 338 return node; | 338 return node; |
| 339 } | 339 } |
| 340 | 340 |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 475 // | 475 // |
| 476 if (node.variable.readCount == 0) { | 476 if (node.variable.readCount == 0) { |
| 477 --node.variable.writeCount; | 477 --node.variable.writeCount; |
| 478 return node.value; | 478 return node.value; |
| 479 } | 479 } |
| 480 return node; | 480 return node; |
| 481 } | 481 } |
| 482 | 482 |
| 483 /// Process nodes right-to-left, the opposite of evaluation order in the case | 483 /// Process nodes right-to-left, the opposite of evaluation order in the case |
| 484 /// of argument lists.. | 484 /// of argument lists.. |
| 485 void _rewriteList(List<Node> nodes) { | 485 void _rewriteList(List<Node> nodes, {bool rhsPropagation: true}) { |
| 486 allowRhsPropagation.add(rhsPropagation); | |
| 486 for (int i = nodes.length - 1; i >= 0; --i) { | 487 for (int i = nodes.length - 1; i >= 0; --i) { |
| 487 nodes[i] = visitExpression(nodes[i]); | 488 nodes[i] = visitExpression(nodes[i]); |
| 488 } | 489 } |
| 490 allowRhsPropagation.removeLast(); | |
| 489 } | 491 } |
| 490 | 492 |
| 491 Expression visitInvokeStatic(InvokeStatic node) { | 493 Expression visitInvokeStatic(InvokeStatic node) { |
| 492 _rewriteList(node.arguments); | 494 _rewriteList(node.arguments); |
| 493 return node; | 495 return node; |
| 494 } | 496 } |
| 495 | 497 |
| 496 Expression visitInvokeMethod(InvokeMethod node) { | 498 Expression visitInvokeMethod(InvokeMethod node) { |
| 497 if (node.receiverIsNotNull) { | 499 if (node.receiverIsNotNull) { |
| 498 _rewriteList(node.arguments); | 500 _rewriteList(node.arguments); |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 714 node.tryBody = visitStatement(node.tryBody); | 716 node.tryBody = visitStatement(node.tryBody); |
| 715 safeForInlining = saved; | 717 safeForInlining = saved; |
| 716 node.catchParameters.forEach(pushDominatingAssignment); | 718 node.catchParameters.forEach(pushDominatingAssignment); |
| 717 node.catchBody = visitStatement(node.catchBody); | 719 node.catchBody = visitStatement(node.catchBody); |
| 718 node.catchParameters.forEach(popDominatingAssignment); | 720 node.catchParameters.forEach(popDominatingAssignment); |
| 719 }); | 721 }); |
| 720 return node; | 722 return node; |
| 721 } | 723 } |
| 722 | 724 |
| 723 Expression visitConstant(Constant node) { | 725 Expression visitConstant(Constant node) { |
| 724 if (!environment.isEmpty) { | 726 if (isAllowingRhsPropagation && !environment.isEmpty) { |
| 725 Constant constant = getRightHandConstant(environment.last); | 727 Constant constant = getRightHandConstant(environment.last); |
| 726 if (constant != null && constant.value == node.value) { | 728 if (constant != null && constant.value == node.value) { |
| 727 return visitExpression(environment.removeLast()); | 729 return visitExpression(environment.removeLast()); |
| 728 } | 730 } |
| 729 } | 731 } |
| 730 return node; | 732 return node; |
| 731 } | 733 } |
| 732 | 734 |
| 733 Expression visitThis(This node) { | 735 Expression visitThis(This node) { |
| 734 return node; | 736 return node; |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 873 /// var y = bar(); | 875 /// var y = bar(); |
| 874 /// var z = y < x; | 876 /// var z = y < x; |
| 875 /// | 877 /// |
| 876 /// ==> | 878 /// ==> |
| 877 /// | 879 /// |
| 878 /// var z = foo() > bar(); | 880 /// var z = foo() > bar(); |
| 879 /// | 881 /// |
| 880 /// foo() must be evaluated before bar(), so the propagation is only possible | 882 /// foo() must be evaluated before bar(), so the propagation is only possible |
| 881 /// by commuting the operator. | 883 /// by commuting the operator. |
| 882 Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) { | 884 Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) { |
| 883 if (environment.isEmpty || getLeftHand(environment.last) == null) { | 885 if (!environment.isEmpty && getLeftHand(environment.last) != null) { |
| 884 // If there is no recent assignment that might propagate, so there is no | 886 Variable propagatableVariable = getLeftHand(environment.last); |
| 885 // opportunity for optimization here. | 887 BuiltinOperator commuted = commuteBinaryOperator(node.operator); |
| 886 _rewriteList(node.arguments); | 888 if (commuted != null) { |
| 887 return node; | 889 // Only binary operators can commute. |
| 888 } | 890 assert(node.arguments.length == 2); |
| 889 Variable propagatableVariable = getLeftHand(environment.last); | 891 Expression left = node.arguments[0]; |
| 890 BuiltinOperator commuted = commuteBinaryOperator(node.operator); | 892 if (left is VariableUse && propagatableVariable == left.variable) { |
| 891 if (commuted != null) { | 893 Expression right = node.arguments[1]; |
| 892 assert(node.arguments.length == 2); // Only binary operators can commute. | 894 if (right is This || |
| 893 Expression left = node.arguments[0]; | 895 (right is VariableUse && |
| 894 if (left is VariableUse && propagatableVariable == left.variable) { | 896 propagatableVariable != right.variable && |
| 895 Expression right = node.arguments[1]; | 897 !constantEnvironment.containsKey(right.variable))) { |
| 896 if (right is This || | 898 // An assignment can be propagated if we commute the operator. |
| 897 (right is VariableUse && | 899 node.operator = commuted; |
| 898 propagatableVariable != right.variable && | 900 node.arguments[0] = right; |
| 899 !constantEnvironment.containsKey(right.variable))) { | 901 node.arguments[1] = left; |
| 900 // An assignment can be propagated if we commute the operator. | 902 } |
| 901 node.operator = commuted; | |
| 902 node.arguments[0] = right; | |
| 903 node.arguments[1] = left; | |
| 904 } | 903 } |
| 905 } | 904 } |
| 906 } | 905 } |
| 907 _rewriteList(node.arguments); | 906 _rewriteList(node.arguments, rhsPropagation: false); |
|
sra1
2016/01/06 00:41:06
Add a comment why rhsPropagation is false.
if
asgerf
2016/01/06 15:43:31
Done.
| |
| 908 return node; | 907 return node; |
| 909 } | 908 } |
| 910 | 909 |
| 911 /// If [s] and [t] are similar statements we extract their subexpressions | 910 /// If [s] and [t] are similar statements we extract their subexpressions |
| 912 /// and returns a new statement of the same type using expressions combined | 911 /// and returns a new statement of the same type using expressions combined |
| 913 /// with the [combine] callback. For example: | 912 /// with the [combine] callback. For example: |
| 914 /// | 913 /// |
| 915 /// combineStatements(Return E1, Return E2) = Return combine(E1, E2) | 914 /// combineStatements(Return E1, Return E2) = Return combine(E1, E2) |
| 916 /// | 915 /// |
| 917 /// If [combine] returns E1 then the unified statement is equivalent to [s], | 916 /// If [combine] returns E1 then the unified statement is equivalent to [s], |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1308 VariableUseCallback callback; | 1307 VariableUseCallback callback; |
| 1309 | 1308 |
| 1310 VariableUseVisitor(this.callback); | 1309 VariableUseVisitor(this.callback); |
| 1311 | 1310 |
| 1312 visitVariableUse(VariableUse use) => callback(use); | 1311 visitVariableUse(VariableUse use) => callback(use); |
| 1313 | 1312 |
| 1314 static void visit(Expression node, VariableUseCallback callback) { | 1313 static void visit(Expression node, VariableUseCallback callback) { |
| 1315 new VariableUseVisitor(callback).visitExpression(node); | 1314 new VariableUseVisitor(callback).visitExpression(node); |
| 1316 } | 1315 } |
| 1317 } | 1316 } |
| OLD | NEW |