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

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

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 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
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 350 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 return visitor.wasFound; 361 return visitor.wasFound;
362 } 362 }
363 363
364 /// Returns true if [exp] has no side effects and has a constant value within 364 /// Returns true if [exp] has no side effects and has a constant value within
365 /// any given activation of the enclosing method. 365 /// any given activation of the enclosing method.
366 bool isEffectivelyConstant(Expression exp) { 366 bool isEffectivelyConstant(Expression exp) {
367 // TODO(asgerf): Can be made more aggressive e.g. by checking conditional 367 // TODO(asgerf): Can be made more aggressive e.g. by checking conditional
368 // expressions recursively. Determine if that is a valuable optimization 368 // expressions recursively. Determine if that is a valuable optimization
369 // and/or if it is better handled at the CPS level. 369 // and/or if it is better handled at the CPS level.
370 return exp is Constant || 370 return exp is Constant ||
371 exp is This || 371 exp is This ||
372 exp is CreateInvocationMirror || 372 exp is CreateInvocationMirror ||
373 exp is CreateInstance || 373 exp is CreateInstance ||
374 exp is CreateBox || 374 exp is CreateBox ||
375 exp is TypeExpression || 375 exp is TypeExpression ||
376 exp is GetStatic && exp.element.isFunction || 376 exp is GetStatic && exp.element.isFunction ||
377 exp is Interceptor || 377 exp is Interceptor ||
378 exp is ApplyBuiltinOperator || 378 exp is ApplyBuiltinOperator ||
379 exp is VariableUse && constantEnvironment.containsKey(exp.variable); 379 exp is VariableUse && constantEnvironment.containsKey(exp.variable);
380 } 380 }
381 381
382 /// True if [node] is an assignment that can be propagated as a constant. 382 /// True if [node] is an assignment that can be propagated as a constant.
383 bool isEffectivelyConstantAssignment(Expression node) { 383 bool isEffectivelyConstantAssignment(Expression node) {
384 return node is Assign && 384 return node is Assign &&
385 node.variable.writeCount == 1 && 385 node.variable.writeCount == 1 &&
386 isEffectivelyConstant(node.value); 386 isEffectivelyConstant(node.value);
387 } 387 }
388 388
389 Statement visitExpressionStatement(ExpressionStatement inputNode) { 389 Statement visitExpressionStatement(ExpressionStatement inputNode) {
390 // Analyze chains of expression statements. 390 // Analyze chains of expression statements.
391 // To avoid deep recursion, [processExpressionStatement] returns a callback 391 // To avoid deep recursion, [processExpressionStatement] returns a callback
392 // to invoke after its successor node has been processed. 392 // to invoke after its successor node has been processed.
393 // These callbacks are stored in a list and invoked in reverse at the end. 393 // These callbacks are stored in a list and invoked in reverse at the end.
394 List<Function> stack = []; 394 List<Function> stack = [];
395 Statement node = inputNode; 395 Statement node = inputNode;
396 while (node is ExpressionStatement) { 396 while (node is ExpressionStatement) {
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
673 node.elseStatement = visitStatement(node.elseStatement); 673 node.elseStatement = visitStatement(node.elseStatement);
674 }); 674 });
675 675
676 node.condition = visitExpression(node.condition); 676 node.condition = visitExpression(node.condition);
677 677
678 inEmptyEnvironment(() { 678 inEmptyEnvironment(() {
679 tryCollapseIf(node); 679 tryCollapseIf(node);
680 }); 680 });
681 681
682 Statement reduced = combineStatementsInBranches( 682 Statement reduced = combineStatementsInBranches(
683 node.thenStatement, 683 node.thenStatement, node.elseStatement, node.condition);
684 node.elseStatement,
685 node.condition);
686 if (reduced != null) { 684 if (reduced != null) {
687 return reduced; 685 return reduced;
688 } 686 }
689 687
690 return node; 688 return node;
691 } 689 }
692 690
693 Statement visitWhileTrue(WhileTrue node) { 691 Statement visitWhileTrue(WhileTrue node) {
694 // Do not propagate assignments into loops. Doing so is not safe for 692 // Do not propagate assignments into loops. Doing so is not safe for
695 // variables modified in the loop (the initial value will be propagated). 693 // variables modified in the loop (the initial value will be propagated).
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
739 } 737 }
740 738
741 Expression visitTypeOperator(TypeOperator node) { 739 Expression visitTypeOperator(TypeOperator node) {
742 _rewriteList(node.typeArguments); 740 _rewriteList(node.typeArguments);
743 node.value = visitExpression(node.value); 741 node.value = visitExpression(node.value);
744 return node; 742 return node;
745 } 743 }
746 744
747 bool isCompoundableBuiltin(Expression e) { 745 bool isCompoundableBuiltin(Expression e) {
748 return e is ApplyBuiltinOperator && 746 return e is ApplyBuiltinOperator &&
749 e.arguments.length >= 2 && 747 e.arguments.length >= 2 &&
750 isCompoundableOperator(e.operator); 748 isCompoundableOperator(e.operator);
751 } 749 }
752 750
753 /// Converts a compoundable operator application into the right-hand side for 751 /// Converts a compoundable operator application into the right-hand side for
754 /// use in a compound assignment, discarding the left-hand value. 752 /// use in a compound assignment, discarding the left-hand value.
755 /// 753 ///
756 /// For example, for `x + y + z` it returns `y + z`. 754 /// For example, for `x + y + z` it returns `y + z`.
757 Expression contractCompoundableBuiltin(ApplyBuiltinOperator e) { 755 Expression contractCompoundableBuiltin(ApplyBuiltinOperator e) {
758 assert(isCompoundableBuiltin(e)); 756 assert(isCompoundableBuiltin(e));
759 if (e.arguments.length > 2) { 757 if (e.arguments.length > 2) {
760 assert(e.operator == BuiltinOperator.StringConcatenate); 758 assert(e.operator == BuiltinOperator.StringConcatenate);
761 return new ApplyBuiltinOperator( 759 return new ApplyBuiltinOperator(
762 e.operator, 760 e.operator, e.arguments.skip(1).toList(), e.sourceInformation);
763 e.arguments.skip(1).toList(),
764 e.sourceInformation);
765 } else { 761 } else {
766 return e.arguments[1]; 762 return e.arguments[1];
767 } 763 }
768 } 764 }
769 765
770 void destroyVariableUse(VariableUse node) { 766 void destroyVariableUse(VariableUse node) {
771 --node.variable.readCount; 767 --node.variable.readCount;
772 } 768 }
773 769
774 Expression visitSetField(SetField node) { 770 Expression visitSetField(SetField node) {
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
907 } 903 }
908 } 904 }
909 905
910 /// If [operator] is a commutable binary operator, returns the commuted 906 /// If [operator] is a commutable binary operator, returns the commuted
911 /// operator, possibly the operator itself, otherwise returns `null`. 907 /// operator, possibly the operator itself, otherwise returns `null`.
912 BuiltinOperator commuteBinaryOperator(BuiltinOperator operator) { 908 BuiltinOperator commuteBinaryOperator(BuiltinOperator operator) {
913 if (isSymmetricOperator(operator)) { 909 if (isSymmetricOperator(operator)) {
914 // Symmetric operators are their own commutes. 910 // Symmetric operators are their own commutes.
915 return operator; 911 return operator;
916 } 912 }
917 switch(operator) { 913 switch (operator) {
918 case BuiltinOperator.NumLt: return BuiltinOperator.NumGt; 914 case BuiltinOperator.NumLt:
919 case BuiltinOperator.NumLe: return BuiltinOperator.NumGe; 915 return BuiltinOperator.NumGt;
920 case BuiltinOperator.NumGt: return BuiltinOperator.NumLt; 916 case BuiltinOperator.NumLe:
921 case BuiltinOperator.NumGe: return BuiltinOperator.NumLe; 917 return BuiltinOperator.NumGe;
922 default: return null; 918 case BuiltinOperator.NumGt:
919 return BuiltinOperator.NumLt;
920 case BuiltinOperator.NumGe:
921 return BuiltinOperator.NumLe;
922 default:
923 return null;
923 } 924 }
924 } 925 }
925 926
926 /// Built-in binary operators are commuted when it is safe and can enable an 927 /// Built-in binary operators are commuted when it is safe and can enable an
927 /// assignment propagation. For example: 928 /// assignment propagation. For example:
928 /// 929 ///
929 /// var x = foo(); 930 /// var x = foo();
930 /// var y = bar(); 931 /// var y = bar();
931 /// var z = y < x; 932 /// var z = y < x;
932 /// 933 ///
933 /// ==> 934 /// ==>
934 /// 935 ///
935 /// var z = foo() > bar(); 936 /// var z = foo() > bar();
936 /// 937 ///
937 /// foo() must be evaluated before bar(), so the propagation is only possible 938 /// foo() must be evaluated before bar(), so the propagation is only possible
938 /// by commuting the operator. 939 /// by commuting the operator.
939 Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) { 940 Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
940 if (!environment.isEmpty && getLeftHand(environment.last) != null) { 941 if (!environment.isEmpty && getLeftHand(environment.last) != null) {
941 Variable propagatableVariable = getLeftHand(environment.last); 942 Variable propagatableVariable = getLeftHand(environment.last);
942 BuiltinOperator commuted = commuteBinaryOperator(node.operator); 943 BuiltinOperator commuted = commuteBinaryOperator(node.operator);
943 if (commuted != null) { 944 if (commuted != null) {
944 // Only binary operators can commute. 945 // Only binary operators can commute.
945 assert(node.arguments.length == 2); 946 assert(node.arguments.length == 2);
946 Expression left = node.arguments[0]; 947 Expression left = node.arguments[0];
947 if (left is VariableUse && propagatableVariable == left.variable) { 948 if (left is VariableUse && propagatableVariable == left.variable) {
948 Expression right = node.arguments[1]; 949 Expression right = node.arguments[1];
949 if (right is This || 950 if (right is This ||
950 (right is VariableUse && 951 (right is VariableUse &&
951 propagatableVariable != right.variable && 952 propagatableVariable != right.variable &&
952 !constantEnvironment.containsKey(right.variable))) { 953 !constantEnvironment.containsKey(right.variable))) {
953 // An assignment can be propagated if we commute the operator. 954 // An assignment can be propagated if we commute the operator.
954 node.operator = commuted; 955 node.operator = commuted;
955 node.arguments[0] = right; 956 node.arguments[0] = right;
956 node.arguments[1] = left; 957 node.arguments[1] = left;
957 } 958 }
958 } 959 }
959 } 960 }
960 } 961 }
961 // Avoid code like `p == (q.f = null)`. JS operators with a constant operand 962 // Avoid code like `p == (q.f = null)`. JS operators with a constant operand
962 // can sometimes be compiled to a specialized instruction in the JS engine, 963 // can sometimes be compiled to a specialized instruction in the JS engine,
(...skipping 12 matching lines...) Expand all
975 /// and if [combine] returns E2 the unified statement is equivalence to [t]. 976 /// and if [combine] returns E2 the unified statement is equivalence to [t].
976 /// 977 ///
977 /// It is guaranteed that no side effects occur between the beginning of the 978 /// It is guaranteed that no side effects occur between the beginning of the
978 /// statement and the position of the combined expression. 979 /// statement and the position of the combined expression.
979 /// 980 ///
980 /// Returns null if the statements are too different. 981 /// Returns null if the statements are too different.
981 /// 982 ///
982 /// If non-null is returned, the caller MUST discard [s] and [t] and use 983 /// If non-null is returned, the caller MUST discard [s] and [t] and use
983 /// the returned statement instead. 984 /// the returned statement instead.
984 Statement combineStatementsInBranches( 985 Statement combineStatementsInBranches(
985 Statement s, 986 Statement s, Statement t, Expression condition) {
986 Statement t,
987 Expression condition) {
988 if (s is Return && t is Return) { 987 if (s is Return && t is Return) {
989 return new Return(new Conditional(condition, s.value, t.value)); 988 return new Return(new Conditional(condition, s.value, t.value));
990 } 989 }
991 if (s is ExpressionStatement && t is ExpressionStatement) { 990 if (s is ExpressionStatement && t is ExpressionStatement) {
992 // Combine the two expressions and the two successor statements. 991 // Combine the two expressions and the two successor statements.
993 // 992 //
994 // C ? {E1 ; S1} : {E2 ; S2} 993 // C ? {E1 ; S1} : {E2 ; S2}
995 // ==> 994 // ==>
996 // (C ? E1 : E2) : combine(S1, S2) 995 // (C ? E1 : E2) : combine(S1, S2)
997 // 996 //
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1042 /// expression if something better can be done. 1041 /// expression if something better can be done.
1043 /// 1042 ///
1044 /// In particular, assignments will be merged as follows: 1043 /// In particular, assignments will be merged as follows:
1045 /// 1044 ///
1046 /// C ? (v = E1) : (v = E2) 1045 /// C ? (v = E1) : (v = E2)
1047 /// ==> 1046 /// ==>
1048 /// v = C ? E1 : E2 1047 /// v = C ? E1 : E2
1049 /// 1048 ///
1050 /// The latter form is more compact and can also be inlined. 1049 /// The latter form is more compact and can also be inlined.
1051 CombinedExpressions combineAsConditional( 1050 CombinedExpressions combineAsConditional(
1052 Expression s, 1051 Expression s, Expression t, Expression condition) {
1053 Expression t,
1054 Expression condition) {
1055 if (s is Assign && t is Assign && s.variable == t.variable) { 1052 if (s is Assign && t is Assign && s.variable == t.variable) {
1056 Expression values = new Conditional(condition, s.value, t.value); 1053 Expression values = new Conditional(condition, s.value, t.value);
1057 return new CombinedAssigns(s, t, new CombinedExpressions(values)); 1054 return new CombinedAssigns(s, t, new CombinedExpressions(values));
1058 } 1055 }
1059 return new CombinedExpressions(new Conditional(condition, s, t)); 1056 return new CombinedExpressions(new Conditional(condition, s, t));
1060 } 1057 }
1061 1058
1062 /// Returns a statement equivalent to both [s] and [t], or null if [s] and 1059 /// Returns a statement equivalent to both [s] and [t], or null if [s] and
1063 /// [t] are incompatible. 1060 /// [t] are incompatible.
1064 /// If non-null is returned, the caller MUST discard [s] and [t] and use 1061 /// If non-null is returned, the caller MUST discard [s] and [t] and use
(...skipping 11 matching lines...) Expand all
1076 } 1073 }
1077 if (s is Continue && t is Continue && s.target == t.target) { 1074 if (s is Continue && t is Continue && s.target == t.target) {
1078 --t.target.useCount; // Two continues become one. 1075 --t.target.useCount; // Two continues become one.
1079 return s; 1076 return s;
1080 } 1077 }
1081 if (s is Return && t is Return) { 1078 if (s is Return && t is Return) {
1082 CombinedExpressions values = combineExpressions(s.value, t.value); 1079 CombinedExpressions values = combineExpressions(s.value, t.value);
1083 if (values != null) { 1080 if (values != null) {
1084 // TODO(johnniwinther): Handle multiple source informations. 1081 // TODO(johnniwinther): Handle multiple source informations.
1085 SourceInformation sourceInformation = s.sourceInformation != null 1082 SourceInformation sourceInformation = s.sourceInformation != null
1086 ? s.sourceInformation : t.sourceInformation; 1083 ? s.sourceInformation
1084 : t.sourceInformation;
1087 return new Return(values.combined, 1085 return new Return(values.combined,
1088 sourceInformation: sourceInformation); 1086 sourceInformation: sourceInformation);
1089 } 1087 }
1090 } 1088 }
1091 if (s is ExpressionStatement && t is ExpressionStatement) { 1089 if (s is ExpressionStatement && t is ExpressionStatement) {
1092 CombinedExpressions values = 1090 CombinedExpressions values =
1093 combineExpressions(s.expression, t.expression); 1091 combineExpressions(s.expression, t.expression);
1094 if (values == null) return null; 1092 if (values == null) return null;
1095 environment.add(values.combined); 1093 environment.add(values.combined);
1096 Variable leftHand = getLeftHand(values.combined); 1094 Variable leftHand = getLeftHand(values.combined);
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
1220 return polarity ? node.thenStatement : node.elseStatement; 1218 return polarity ? node.thenStatement : node.elseStatement;
1221 } 1219 }
1222 1220
1223 void handleForeignCode(ForeignCode node) { 1221 void handleForeignCode(ForeignCode node) {
1224 // Some arguments will get inserted in a JS code template. The arguments 1222 // Some arguments will get inserted in a JS code template. The arguments
1225 // will not always be evaluated (e.g. the second placeholder in the template 1223 // will not always be evaluated (e.g. the second placeholder in the template
1226 // '# && #'). 1224 // '# && #').
1227 bool isNullable(int position) => node.nullableArguments[position]; 1225 bool isNullable(int position) => node.nullableArguments[position];
1228 1226
1229 int safeArguments = 1227 int safeArguments =
1230 PlaceholderSafetyAnalysis.analyze(node.codeTemplate.ast, isNullable); 1228 PlaceholderSafetyAnalysis.analyze(node.codeTemplate.ast, isNullable);
1231 inEmptyEnvironment(() { 1229 inEmptyEnvironment(() {
1232 for (int i = node.arguments.length - 1; i >= safeArguments; --i) { 1230 for (int i = node.arguments.length - 1; i >= safeArguments; --i) {
1233 node.arguments[i] = visitExpression(node.arguments[i]); 1231 node.arguments[i] = visitExpression(node.arguments[i]);
1234 } 1232 }
1235 }); 1233 });
1236 for (int i = safeArguments - 1; i >= 0; --i) { 1234 for (int i = safeArguments - 1; i >= 0; --i) {
1237 node.arguments[i] = visitExpression(node.arguments[i]); 1235 node.arguments[i] = visitExpression(node.arguments[i]);
1238 } 1236 }
1239 } 1237 }
1240 1238
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
1384 } 1382 }
1385 1383
1386 /// Decrement the reference count for [e] if it is a variable use. 1384 /// Decrement the reference count for [e] if it is a variable use.
1387 void destroyPrimaryExpression(Expression e) { 1385 void destroyPrimaryExpression(Expression e) {
1388 if (e is VariableUse) { 1386 if (e is VariableUse) {
1389 --e.variable.readCount; 1387 --e.variable.readCount;
1390 } else { 1388 } else {
1391 assert(e is This); 1389 assert(e is This);
1392 } 1390 }
1393 } 1391 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698