| 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 part of tree_ir.optimization; | 5 part of tree_ir.optimization; |
| 6 | 6 |
| 7 /// Rewrites logical expressions to be more compact in the Tree IR. | 7 /// Rewrites logical expressions to be more compact in the Tree IR. |
| 8 /// | 8 /// |
| 9 /// In this class an expression is said to occur in "boolean context" if | 9 /// In this class an expression is said to occur in "boolean context" if |
| 10 /// its result is immediately applied to boolean conversion. | 10 /// its result is immediately applied to boolean conversion. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 /// | 47 /// |
| 48 /// x ? y : false ==> x && y (if y is known to be a boolean) | 48 /// x ? y : false ==> x && y (if y is known to be a boolean) |
| 49 /// | 49 /// |
| 50 /// The following sequence of rewrites demonstrates the merit of these rules: | 50 /// The following sequence of rewrites demonstrates the merit of these rules: |
| 51 /// | 51 /// |
| 52 /// x ? (y ? true : false) : false | 52 /// x ? (y ? true : false) : false |
| 53 /// x ? !!y : false (double negation introduced by [toBoolean]) | 53 /// x ? !!y : false (double negation introduced by [toBoolean]) |
| 54 /// x && !!y (!!y validated by [isBooleanValued]) | 54 /// x && !!y (!!y validated by [isBooleanValued]) |
| 55 /// x && y (double negation removed by [putInBooleanContext]) | 55 /// x && y (double negation removed by [putInBooleanContext]) |
| 56 /// | 56 /// |
| 57 class LogicalRewriter extends Visitor<Statement, Expression> with PassMixin { | 57 class LogicalRewriter extends RecursiveTransformer |
| 58 implements Pass { |
| 58 String get passName => 'Logical rewriter'; | 59 String get passName => 'Logical rewriter'; |
| 59 | 60 |
| 61 @override |
| 62 void rewrite(RootNode node) { |
| 63 node.replaceEachBody(visitStatement); |
| 64 } |
| 65 |
| 60 /// Statement to be executed next by natural fallthrough. Although fallthrough | 66 /// Statement to be executed next by natural fallthrough. Although fallthrough |
| 61 /// is not introduced in this phase, we need to reason about fallthrough when | 67 /// is not introduced in this phase, we need to reason about fallthrough when |
| 62 /// evaluating the benefit of swapping the branches of an [If]. | 68 /// evaluating the benefit of swapping the branches of an [If]. |
| 63 Statement fallthrough; | 69 Statement fallthrough; |
| 64 | 70 |
| 65 void rewriteExecutableDefinition(ExecutableDefinition root) { | 71 @override |
| 66 root.body = visitStatement(root.body); | 72 void visitInnerFunction(FunctionDefinition node) { |
| 67 } | 73 new LogicalRewriter().rewrite(node); |
| 68 | |
| 69 void rewriteConstructorDefinition(ConstructorDefinition root) { | |
| 70 if (root.isAbstract) return; | |
| 71 List<Initializer> initializers = root.initializers; | |
| 72 for (int i = 0; i < initializers.length; ++i) { | |
| 73 initializers[i] = visitExpression(initializers[i]); | |
| 74 } | |
| 75 root.body = visitStatement(root.body); | |
| 76 } | |
| 77 | |
| 78 Expression visitFieldInitializer(FieldInitializer node) { | |
| 79 node.body = visitStatement(node.body); | |
| 80 return node; | |
| 81 } | |
| 82 | |
| 83 visitSuperInitializer(SuperInitializer node) { | |
| 84 List<Statement> arguments = node.arguments; | |
| 85 for (int i = 0; i < arguments.length; ++i) { | |
| 86 arguments[i] = visitStatement(arguments[i]); | |
| 87 } | |
| 88 return node; | |
| 89 } | 74 } |
| 90 | 75 |
| 91 Statement visitLabeledStatement(LabeledStatement node) { | 76 Statement visitLabeledStatement(LabeledStatement node) { |
| 92 Statement savedFallthrough = fallthrough; | 77 Statement savedFallthrough = fallthrough; |
| 93 fallthrough = node.next; | 78 fallthrough = node.next; |
| 94 node.body = visitStatement(node.body); | 79 node.body = visitStatement(node.body); |
| 95 fallthrough = savedFallthrough; | 80 fallthrough = savedFallthrough; |
| 96 node.next = visitStatement(node.next); | 81 node.next = visitStatement(node.next); |
| 97 return node; | 82 return node; |
| 98 } | 83 } |
| 99 | 84 |
| 100 Statement visitAssign(Assign node) { | |
| 101 node.value = visitExpression(node.value); | |
| 102 node.next = visitStatement(node.next); | |
| 103 return node; | |
| 104 } | |
| 105 | |
| 106 Statement visitReturn(Return node) { | |
| 107 node.value = visitExpression(node.value); | |
| 108 return node; | |
| 109 } | |
| 110 | |
| 111 Statement visitBreak(Break node) { | |
| 112 return node; | |
| 113 } | |
| 114 | |
| 115 Statement visitContinue(Continue node) { | |
| 116 return node; | |
| 117 } | |
| 118 | |
| 119 bool isFallthroughBreak(Statement node) { | 85 bool isFallthroughBreak(Statement node) { |
| 120 return node is Break && node.target.binding.next == fallthrough; | 86 return node is Break && node.target.binding.next == fallthrough; |
| 121 } | 87 } |
| 122 | 88 |
| 123 Statement visitIf(If node) { | 89 Statement visitIf(If node) { |
| 124 // If one of the branches is empty (i.e. just a fallthrough), then that | 90 // If one of the branches is empty (i.e. just a fallthrough), then that |
| 125 // branch should preferrably be the 'else' so we won't have to print it. | 91 // branch should preferrably be the 'else' so we won't have to print it. |
| 126 // In other words, we wish to perform this rewrite: | 92 // In other words, we wish to perform this rewrite: |
| 127 // if (E) {} else {S} | 93 // if (E) {} else {S} |
| 128 // ==> | 94 // ==> |
| (...skipping 24 matching lines...) Expand all Loading... |
| 153 if (!emptyElse && node.condition is Not) { | 119 if (!emptyElse && node.condition is Not) { |
| 154 node.condition = (node.condition as Not).operand; | 120 node.condition = (node.condition as Not).operand; |
| 155 Statement tmp = node.thenStatement; | 121 Statement tmp = node.thenStatement; |
| 156 node.thenStatement = node.elseStatement; | 122 node.thenStatement = node.elseStatement; |
| 157 node.elseStatement = tmp; | 123 node.elseStatement = tmp; |
| 158 } | 124 } |
| 159 | 125 |
| 160 return node; | 126 return node; |
| 161 } | 127 } |
| 162 | 128 |
| 163 Statement visitWhileTrue(WhileTrue node) { | |
| 164 node.body = visitStatement(node.body); | |
| 165 return node; | |
| 166 } | |
| 167 | |
| 168 Statement visitWhileCondition(WhileCondition node) { | 129 Statement visitWhileCondition(WhileCondition node) { |
| 169 node.condition = makeCondition(node.condition, true, liftNots: false); | 130 node.condition = makeCondition(node.condition, true, liftNots: false); |
| 170 node.body = visitStatement(node.body); | 131 node.body = visitStatement(node.body); |
| 171 node.next = visitStatement(node.next); | 132 node.next = visitStatement(node.next); |
| 172 return node; | 133 return node; |
| 173 } | 134 } |
| 174 | 135 |
| 175 Statement visitTry(Try node) { | |
| 176 node.tryBody = visitStatement(node.tryBody); | |
| 177 node.catchBody = visitStatement(node.catchBody); | |
| 178 return node; | |
| 179 } | |
| 180 | |
| 181 Statement visitExpressionStatement(ExpressionStatement node) { | |
| 182 node.expression = visitExpression(node.expression); | |
| 183 node.next = visitStatement(node.next); | |
| 184 return node; | |
| 185 } | |
| 186 | |
| 187 Expression visitVariableUse(VariableUse node) { | |
| 188 return node; | |
| 189 } | |
| 190 | |
| 191 Expression visitInvokeStatic(InvokeStatic node) { | |
| 192 _rewriteList(node.arguments); | |
| 193 return node; | |
| 194 } | |
| 195 | |
| 196 Expression visitInvokeMethod(InvokeMethod node) { | |
| 197 node.receiver = visitExpression(node.receiver); | |
| 198 _rewriteList(node.arguments); | |
| 199 return node; | |
| 200 } | |
| 201 | |
| 202 Expression visitInvokeMethodDirectly(InvokeMethodDirectly node) { | |
| 203 node.receiver = visitExpression(node.receiver); | |
| 204 _rewriteList(node.arguments); | |
| 205 return node; | |
| 206 } | |
| 207 | |
| 208 Expression visitInvokeConstructor(InvokeConstructor node) { | |
| 209 _rewriteList(node.arguments); | |
| 210 return node; | |
| 211 } | |
| 212 | |
| 213 Expression visitConcatenateStrings(ConcatenateStrings node) { | |
| 214 _rewriteList(node.arguments); | |
| 215 return node; | |
| 216 } | |
| 217 | |
| 218 Expression visitLiteralList(LiteralList node) { | |
| 219 _rewriteList(node.values); | |
| 220 return node; | |
| 221 } | |
| 222 | |
| 223 Expression visitLiteralMap(LiteralMap node) { | |
| 224 node.entries.forEach((LiteralMapEntry entry) { | |
| 225 entry.key = visitExpression(entry.key); | |
| 226 entry.value = visitExpression(entry.value); | |
| 227 }); | |
| 228 return node; | |
| 229 } | |
| 230 | |
| 231 Expression visitTypeOperator(TypeOperator node) { | |
| 232 node.receiver = visitExpression(node.receiver); | |
| 233 return node; | |
| 234 } | |
| 235 | |
| 236 Expression visitConstant(Constant node) { | |
| 237 return node; | |
| 238 } | |
| 239 | |
| 240 Expression visitThis(This node) { | |
| 241 return node; | |
| 242 } | |
| 243 | |
| 244 Expression visitReifyTypeVar(ReifyTypeVar node) { | |
| 245 return node; | |
| 246 } | |
| 247 | |
| 248 Expression visitFunctionExpression(FunctionExpression node) { | |
| 249 new LogicalRewriter().rewrite(node.definition); | |
| 250 return node; | |
| 251 } | |
| 252 | |
| 253 Statement visitFunctionDeclaration(FunctionDeclaration node) { | |
| 254 new LogicalRewriter().rewrite(node.definition); | |
| 255 node.next = visitStatement(node.next); | |
| 256 return node; | |
| 257 } | |
| 258 | |
| 259 Expression visitNot(Not node) { | 136 Expression visitNot(Not node) { |
| 260 return toBoolean(makeCondition(node.operand, false, liftNots: false)); | 137 return toBoolean(makeCondition(node.operand, false, liftNots: false)); |
| 261 } | 138 } |
| 262 | 139 |
| 263 Expression visitConditional(Conditional node) { | 140 Expression visitConditional(Conditional node) { |
| 264 // node.condition will be visited after the then and else parts, because its | 141 // node.condition will be visited after the then and else parts, because its |
| 265 // polarity depends on what rewrite we use. | 142 // polarity depends on what rewrite we use. |
| 266 node.thenExpression = visitExpression(node.thenExpression); | 143 node.thenExpression = visitExpression(node.thenExpression); |
| 267 node.elseExpression = visitExpression(node.elseExpression); | 144 node.elseExpression = visitExpression(node.elseExpression); |
| 268 | 145 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 | 192 |
| 316 return node; | 193 return node; |
| 317 } | 194 } |
| 318 | 195 |
| 319 Expression visitLogicalOperator(LogicalOperator node) { | 196 Expression visitLogicalOperator(LogicalOperator node) { |
| 320 node.left = makeCondition(node.left, true); | 197 node.left = makeCondition(node.left, true); |
| 321 node.right = makeCondition(node.right, true); | 198 node.right = makeCondition(node.right, true); |
| 322 return node; | 199 return node; |
| 323 } | 200 } |
| 324 | 201 |
| 325 Statement visitSetField(SetField node) { | |
| 326 node.object = visitExpression(node.object); | |
| 327 node.value = visitExpression(node.value); | |
| 328 node.next = visitStatement(node.next); | |
| 329 return node; | |
| 330 } | |
| 331 | |
| 332 Expression visitGetField(GetField node) { | |
| 333 node.object = visitExpression(node.object); | |
| 334 return node; | |
| 335 } | |
| 336 | |
| 337 Expression visitCreateBox(CreateBox node) { | |
| 338 return node; | |
| 339 } | |
| 340 | |
| 341 Expression visitCreateInstance(CreateInstance node) { | |
| 342 _rewriteList(node.arguments); | |
| 343 return node; | |
| 344 } | |
| 345 | |
| 346 Expression visitReifyRuntimeType(ReifyRuntimeType node) { | |
| 347 node.value = visitExpression(node.value); | |
| 348 return node; | |
| 349 } | |
| 350 | |
| 351 Expression visitReadTypeVariable(ReadTypeVariable node) { | |
| 352 node.target = visitExpression(node.target); | |
| 353 return node; | |
| 354 } | |
| 355 | |
| 356 /// True if the given expression is known to evaluate to a boolean. | 202 /// True if the given expression is known to evaluate to a boolean. |
| 357 /// This will not recursively traverse [Conditional] expressions, but if | 203 /// This will not recursively traverse [Conditional] expressions, but if |
| 358 /// applied to the result of [visitExpression] conditionals will have been | 204 /// applied to the result of [visitExpression] conditionals will have been |
| 359 /// rewritten anyway. | 205 /// rewritten anyway. |
| 360 bool isBooleanValued(Expression e) { | 206 bool isBooleanValued(Expression e) { |
| 361 return isTrue(e) || isFalse(e) || e is Not || e is LogicalOperator; | 207 return isTrue(e) || isFalse(e) || e is Not || e is LogicalOperator; |
| 362 } | 208 } |
| 363 | 209 |
| 364 /// Rewrite an expression that was originally processed in a non-boolean | 210 /// Rewrite an expression that was originally processed in a non-boolean |
| 365 /// context. | 211 /// context. |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 } | 337 } |
| 492 | 338 |
| 493 Expression makeOr(Expression e1, Expression e2, {bool liftNots: true}) { | 339 Expression makeOr(Expression e1, Expression e2, {bool liftNots: true}) { |
| 494 if (e1 is Not && e2 is Not && liftNots) { | 340 if (e1 is Not && e2 is Not && liftNots) { |
| 495 return new Not(new LogicalOperator.and(e1.operand, e2.operand)); | 341 return new Not(new LogicalOperator.and(e1.operand, e2.operand)); |
| 496 } else { | 342 } else { |
| 497 return new LogicalOperator.or(e1, e2); | 343 return new LogicalOperator.or(e1, e2); |
| 498 } | 344 } |
| 499 } | 345 } |
| 500 | 346 |
| 501 /// Destructively updates each entry of [l] with the result of visiting it. | |
| 502 void _rewriteList(List<Expression> l) { | |
| 503 for (int i = 0; i < l.length; i++) { | |
| 504 l[i] = visitExpression(l[i]); | |
| 505 } | |
| 506 } | |
| 507 | |
| 508 @override | |
| 509 Expression visitTypeExpression(TypeExpression node) { | |
| 510 _rewriteList(node.arguments); | |
| 511 return node; | |
| 512 } | |
| 513 } | 347 } |
| 514 | 348 |
| OLD | NEW |