Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(799)

Side by Side Diff: pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart

Issue 1563693002: dart2js cps: Disable RHS propagation in operands to builtin operators. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Rephrase a comment Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 /// engine so it is disabled in some cases.
200 final List<bool> allowRhsPropagation = <bool>[true];
201
202 bool get isRhsPropagationAllowed => allowRhsPropagation.last;
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
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 (isRhsPropagationAllowed &&
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 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 return stmt; 460 return stmt;
461 } else { 461 } else {
462 // Expression was propagated into the successor. 462 // Expression was propagated into the successor.
463 return stmt.next; 463 return stmt.next;
464 } 464 }
465 }; 465 };
466 } 466 }
467 } 467 }
468 468
469 Expression visitAssign(Assign node) { 469 Expression visitAssign(Assign node) {
470 allowRhsPropagation.add(true);
470 node.value = visitExpression(node.value); 471 node.value = visitExpression(node.value);
472 allowRhsPropagation.removeLast();
471 // Remove assignments to variables without any uses. This can happen 473 // Remove assignments to variables without any uses. This can happen
472 // because the assignment was propagated into its use, e.g: 474 // because the assignment was propagated into its use, e.g:
473 // 475 //
474 // { x = foo(); bar(x) } ==> bar(x = foo()) ==> bar(foo()) 476 // { x = foo(); bar(x) } ==> bar(x = foo()) ==> bar(foo())
475 // 477 //
476 if (node.variable.readCount == 0) { 478 if (node.variable.readCount == 0) {
477 --node.variable.writeCount; 479 --node.variable.writeCount;
478 return node.value; 480 return node.value;
479 } 481 }
480 return node; 482 return node;
481 } 483 }
482 484
483 /// Process nodes right-to-left, the opposite of evaluation order in the case 485 /// Process nodes right-to-left, the opposite of evaluation order in the case
484 /// of argument lists.. 486 /// of argument lists..
485 void _rewriteList(List<Node> nodes) { 487 void _rewriteList(List<Node> nodes, {bool rhsPropagation: true}) {
488 allowRhsPropagation.add(rhsPropagation);
486 for (int i = nodes.length - 1; i >= 0; --i) { 489 for (int i = nodes.length - 1; i >= 0; --i) {
487 nodes[i] = visitExpression(nodes[i]); 490 nodes[i] = visitExpression(nodes[i]);
488 } 491 }
492 allowRhsPropagation.removeLast();
489 } 493 }
490 494
491 Expression visitInvokeStatic(InvokeStatic node) { 495 Expression visitInvokeStatic(InvokeStatic node) {
492 _rewriteList(node.arguments); 496 _rewriteList(node.arguments);
493 return node; 497 return node;
494 } 498 }
495 499
496 Expression visitInvokeMethod(InvokeMethod node) { 500 Expression visitInvokeMethod(InvokeMethod node) {
497 if (node.receiverIsNotNull) { 501 if (node.receiverIsNotNull) {
498 _rewriteList(node.arguments); 502 _rewriteList(node.arguments);
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
714 node.tryBody = visitStatement(node.tryBody); 718 node.tryBody = visitStatement(node.tryBody);
715 safeForInlining = saved; 719 safeForInlining = saved;
716 node.catchParameters.forEach(pushDominatingAssignment); 720 node.catchParameters.forEach(pushDominatingAssignment);
717 node.catchBody = visitStatement(node.catchBody); 721 node.catchBody = visitStatement(node.catchBody);
718 node.catchParameters.forEach(popDominatingAssignment); 722 node.catchParameters.forEach(popDominatingAssignment);
719 }); 723 });
720 return node; 724 return node;
721 } 725 }
722 726
723 Expression visitConstant(Constant node) { 727 Expression visitConstant(Constant node) {
724 if (!environment.isEmpty) { 728 if (isRhsPropagationAllowed && !environment.isEmpty) {
725 Constant constant = getRightHandConstant(environment.last); 729 Constant constant = getRightHandConstant(environment.last);
726 if (constant != null && constant.value == node.value) { 730 if (constant != null && constant.value == node.value) {
727 return visitExpression(environment.removeLast()); 731 return visitExpression(environment.removeLast());
728 } 732 }
729 } 733 }
730 return node; 734 return node;
731 } 735 }
732 736
733 Expression visitThis(This node) { 737 Expression visitThis(This node) {
734 return node; 738 return node;
(...skipping 13 matching lines...) Expand all
748 return node; 752 return node;
749 } 753 }
750 754
751 Expression visitTypeOperator(TypeOperator node) { 755 Expression visitTypeOperator(TypeOperator node) {
752 _rewriteList(node.typeArguments); 756 _rewriteList(node.typeArguments);
753 node.value = visitExpression(node.value); 757 node.value = visitExpression(node.value);
754 return node; 758 return node;
755 } 759 }
756 760
757 Expression visitSetField(SetField node) { 761 Expression visitSetField(SetField node) {
762 allowRhsPropagation.add(true);
758 node.value = visitExpression(node.value); 763 node.value = visitExpression(node.value);
759 node.object = visitExpression(node.object); 764 node.object = visitExpression(node.object);
765 allowRhsPropagation.removeLast();
760 return node; 766 return node;
761 } 767 }
762 768
763 Expression visitGetField(GetField node) { 769 Expression visitGetField(GetField node) {
764 node.object = visitExpression(node.object); 770 node.object = visitExpression(node.object);
765 return node; 771 return node;
766 } 772 }
767 773
768 Expression visitGetStatic(GetStatic node) { 774 Expression visitGetStatic(GetStatic node) {
769 return node; 775 return node;
770 } 776 }
771 777
772 Expression visitSetStatic(SetStatic node) { 778 Expression visitSetStatic(SetStatic node) {
779 allowRhsPropagation.add(true);
773 node.value = visitExpression(node.value); 780 node.value = visitExpression(node.value);
781 allowRhsPropagation.removeLast();
774 return node; 782 return node;
775 } 783 }
776 784
777 Expression visitGetTypeTestProperty(GetTypeTestProperty node) { 785 Expression visitGetTypeTestProperty(GetTypeTestProperty node) {
778 node.object = visitExpression(node.object); 786 node.object = visitExpression(node.object);
779 return node; 787 return node;
780 } 788 }
781 789
782 Expression visitCreateBox(CreateBox node) { 790 Expression visitCreateBox(CreateBox node) {
783 return node; 791 return node;
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
873 /// var y = bar(); 881 /// var y = bar();
874 /// var z = y < x; 882 /// var z = y < x;
875 /// 883 ///
876 /// ==> 884 /// ==>
877 /// 885 ///
878 /// var z = foo() > bar(); 886 /// var z = foo() > bar();
879 /// 887 ///
880 /// foo() must be evaluated before bar(), so the propagation is only possible 888 /// foo() must be evaluated before bar(), so the propagation is only possible
881 /// by commuting the operator. 889 /// by commuting the operator.
882 Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) { 890 Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
883 if (environment.isEmpty || getLeftHand(environment.last) == null) { 891 if (!environment.isEmpty && getLeftHand(environment.last) != null) {
884 // If there is no recent assignment that might propagate, so there is no 892 Variable propagatableVariable = getLeftHand(environment.last);
885 // opportunity for optimization here. 893 BuiltinOperator commuted = commuteBinaryOperator(node.operator);
886 _rewriteList(node.arguments); 894 if (commuted != null) {
887 return node; 895 // Only binary operators can commute.
888 } 896 assert(node.arguments.length == 2);
889 Variable propagatableVariable = getLeftHand(environment.last); 897 Expression left = node.arguments[0];
890 BuiltinOperator commuted = commuteBinaryOperator(node.operator); 898 if (left is VariableUse && propagatableVariable == left.variable) {
891 if (commuted != null) { 899 Expression right = node.arguments[1];
892 assert(node.arguments.length == 2); // Only binary operators can commute. 900 if (right is This ||
893 Expression left = node.arguments[0]; 901 (right is VariableUse &&
894 if (left is VariableUse && propagatableVariable == left.variable) { 902 propagatableVariable != right.variable &&
895 Expression right = node.arguments[1]; 903 !constantEnvironment.containsKey(right.variable))) {
896 if (right is This || 904 // An assignment can be propagated if we commute the operator.
897 (right is VariableUse && 905 node.operator = commuted;
898 propagatableVariable != right.variable && 906 node.arguments[0] = right;
899 !constantEnvironment.containsKey(right.variable))) { 907 node.arguments[1] = left;
900 // An assignment can be propagated if we commute the operator. 908 }
901 node.operator = commuted;
902 node.arguments[0] = right;
903 node.arguments[1] = left;
904 } 909 }
905 } 910 }
906 } 911 }
907 _rewriteList(node.arguments); 912 // Avoid code like `p == (q.f = null)`. JS operators with a constant operand
913 // can sometimes be compiled to a specialized instruction in the JS engine,
914 // so retain syntactically constant operands.
915 _rewriteList(node.arguments, rhsPropagation: false);
908 return node; 916 return node;
909 } 917 }
910 918
911 /// If [s] and [t] are similar statements we extract their subexpressions 919 /// If [s] and [t] are similar statements we extract their subexpressions
912 /// and returns a new statement of the same type using expressions combined 920 /// and returns a new statement of the same type using expressions combined
913 /// with the [combine] callback. For example: 921 /// with the [combine] callback. For example:
914 /// 922 ///
915 /// combineStatements(Return E1, Return E2) = Return combine(E1, E2) 923 /// combineStatements(Return E1, Return E2) = Return combine(E1, E2)
916 /// 924 ///
917 /// If [combine] returns E1 then the unified statement is equivalent to [s], 925 /// If [combine] returns E1 then the unified statement is equivalent to [s],
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
1308 VariableUseCallback callback; 1316 VariableUseCallback callback;
1309 1317
1310 VariableUseVisitor(this.callback); 1318 VariableUseVisitor(this.callback);
1311 1319
1312 visitVariableUse(VariableUse use) => callback(use); 1320 visitVariableUse(VariableUse use) => callback(use);
1313 1321
1314 static void visit(Expression node, VariableUseCallback callback) { 1322 static void visit(Expression node, VariableUseCallback callback) {
1315 new VariableUseVisitor(callback).visitExpression(node); 1323 new VariableUseVisitor(callback).visitExpression(node);
1316 } 1324 }
1317 } 1325 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698