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 dart_tree; | 5 library dart_tree; |
6 | 6 |
7 import '../dart2jslib.dart' as dart2js; | 7 import '../dart2jslib.dart' as dart2js; |
8 import '../elements/elements.dart'; | 8 import '../elements/elements.dart'; |
9 import '../universe/universe.dart'; | 9 import '../universe/universe.dart'; |
10 import '../ir/ir_nodes.dart' as ir; | 10 import '../ir/ir_nodes.dart' as ir; |
11 import '../dart_types.dart' show DartType, GenericType; | 11 import '../dart_types.dart' show DartType, GenericType; |
12 import '../universe/universe.dart' show Selector; | 12 import '../universe/universe.dart' show Selector; |
13 import '../ir/const_expression.dart'; | 13 import '../ir/const_expression.dart'; |
14 | 14 |
15 // The Tree language is the target of translation out of the CPS-based IR. | 15 // The Tree language is the target of translation out of the CPS-based IR. |
16 // | 16 // |
17 // The translation from CPS to Dart consists of several stages. Among the | 17 // The translation from CPS to Dart consists of several stages. Among the |
18 // stages are translation to direct style, translation out of SSA, eliminating | 18 // stages are translation to direct style, translation out of SSA, eliminating |
19 // unnecessary names, recognizing high-level control constructs. Combining | 19 // unnecessary names, recognizing high-level control constructs. Combining |
20 // these separate concerns is complicated and the constraints of the CPS-based | 20 // these separate concerns is complicated and the constraints of the CPS-based |
21 // language do not permit a multi-stage translation. | 21 // language do not permit a multi-stage translation. |
22 // | 22 // |
23 // For that reason, CPS is translated to the direct-style language Tree. | 23 // For that reason, CPS is translated to the direct-style language Tree. |
24 // Translation out of SSA, unnaming, and control-flow, as well as 'instruction | 24 // Translation out of SSA, unnaming, and control-flow, as well as 'instruction |
25 // selection' are performed on the Tree language. | 25 // selection' are performed on the Tree language. |
26 // | 26 // |
27 // In contrast to the CPS-based IR, non-primitive expressions can be named and | 27 // In contrast to the CPS-based IR, non-primitive expressions can be named and |
28 // arguments (to calls, primitives, and blocks) can be arbitrary expressions. | 28 // arguments (to calls, primitives, and blocks) can be arbitrary expressions. |
| 29 // |
| 30 // Additionally, variables are considered in scope within inner functions; |
| 31 // closure variables are thus handled directly instead of using ref cells. |
29 | 32 |
30 /** | 33 /** |
31 * The base class of all Tree nodes. | 34 * The base class of all Tree nodes. |
32 */ | 35 */ |
33 abstract class Node { | 36 abstract class Node { |
34 } | 37 } |
35 | 38 |
36 /** | 39 /** |
37 * The base class of [Expression]s. | 40 * The base class of [Expression]s. |
38 */ | 41 */ |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 int useCount = 0; | 78 int useCount = 0; |
76 | 79 |
77 /// The [LabeledStatement] or [WhileTrue] binding this label. | 80 /// The [LabeledStatement] or [WhileTrue] binding this label. |
78 JumpTarget binding; | 81 JumpTarget binding; |
79 } | 82 } |
80 | 83 |
81 /** | 84 /** |
82 * Variables are [Expression]s. | 85 * Variables are [Expression]s. |
83 */ | 86 */ |
84 class Variable extends Expression { | 87 class Variable extends Expression { |
| 88 /// Function that declares this variable. |
| 89 FunctionDefinition host; |
| 90 |
85 /// Element used for synthesizing a name for the variable. | 91 /// Element used for synthesizing a name for the variable. |
86 /// Different variables may have the same element. May be null. | 92 /// Different variables may have the same element. May be null. |
87 Element element; | 93 Element element; |
88 | 94 |
89 int readCount = 0; | 95 int readCount = 0; |
90 | 96 |
91 Variable(this.element); | 97 /// Number of places where this variable occurs as: |
| 98 /// - left-hand of an [Assign] |
| 99 /// - left-hand of a [FunctionDeclaration] |
| 100 /// - parameter in a [FunctionDefinition] |
| 101 int writeCount = 0; |
| 102 |
| 103 Variable(this.host, this.element) { |
| 104 assert(host != null); |
| 105 } |
92 | 106 |
93 accept(ExpressionVisitor visitor) => visitor.visitVariable(this); | 107 accept(ExpressionVisitor visitor) => visitor.visitVariable(this); |
94 } | 108 } |
95 | 109 |
96 /** | 110 /** |
97 * Common interface for invocations with arguments. | 111 * Common interface for invocations with arguments. |
98 */ | 112 */ |
99 abstract class Invoke { | 113 abstract class Invoke { |
100 List<Expression> get arguments; | 114 List<Expression> get arguments; |
101 Selector get selector; | 115 Selector get selector; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 | 147 |
134 accept(ExpressionVisitor visitor) => visitor.visitInvokeMethod(this); | 148 accept(ExpressionVisitor visitor) => visitor.visitInvokeMethod(this); |
135 } | 149 } |
136 | 150 |
137 class InvokeSuperMethod extends Expression implements Invoke { | 151 class InvokeSuperMethod extends Expression implements Invoke { |
138 final Selector selector; | 152 final Selector selector; |
139 final List<Expression> arguments; | 153 final List<Expression> arguments; |
140 | 154 |
141 InvokeSuperMethod(this.selector, this.arguments) ; | 155 InvokeSuperMethod(this.selector, this.arguments) ; |
142 | 156 |
143 accept(Visitor visitor) => visitor.visitInvokeSuperMethod(this); | 157 accept(ExpressionVisitor visitor) => visitor.visitInvokeSuperMethod(this); |
144 } | 158 } |
145 | 159 |
146 /** | 160 /** |
147 * Call to a factory or generative constructor. | 161 * Call to a factory or generative constructor. |
148 */ | 162 */ |
149 class InvokeConstructor extends Expression implements Invoke { | 163 class InvokeConstructor extends Expression implements Invoke { |
150 final GenericType type; | 164 final GenericType type; |
151 final FunctionElement target; | 165 final FunctionElement target; |
152 final List<Expression> arguments; | 166 final List<Expression> arguments; |
153 final Selector selector; | 167 final Selector selector; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 value = primitiveValue; | 199 value = primitiveValue; |
186 | 200 |
187 accept(ExpressionVisitor visitor) => visitor.visitConstant(this); | 201 accept(ExpressionVisitor visitor) => visitor.visitConstant(this); |
188 } | 202 } |
189 | 203 |
190 class This extends Expression { | 204 class This extends Expression { |
191 accept(ExpressionVisitor visitor) => visitor.visitThis(this); | 205 accept(ExpressionVisitor visitor) => visitor.visitThis(this); |
192 } | 206 } |
193 | 207 |
194 class ReifyTypeVar extends Expression { | 208 class ReifyTypeVar extends Expression { |
195 TypeVariableElement element; | 209 TypeVariableElement typeVariable; |
196 | 210 |
197 ReifyTypeVar(this.element); | 211 ReifyTypeVar(this.typeVariable); |
198 | 212 |
199 accept(ExpressionVisitor visitor) => visitor.visitReifyTypeVar(this); | 213 accept(ExpressionVisitor visitor) => visitor.visitReifyTypeVar(this); |
200 } | 214 } |
201 | 215 |
202 class LiteralList extends Expression { | 216 class LiteralList extends Expression { |
203 final GenericType type; | 217 final GenericType type; |
204 final List<Expression> values; | 218 final List<Expression> values; |
205 | 219 |
206 LiteralList(this.type, this.values); | 220 LiteralList(this.type, this.values); |
207 | 221 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 | 271 |
258 /// Logical negation. | 272 /// Logical negation. |
259 class Not extends Expression { | 273 class Not extends Expression { |
260 Expression operand; | 274 Expression operand; |
261 | 275 |
262 Not(this.operand); | 276 Not(this.operand); |
263 | 277 |
264 accept(ExpressionVisitor visitor) => visitor.visitNot(this); | 278 accept(ExpressionVisitor visitor) => visitor.visitNot(this); |
265 } | 279 } |
266 | 280 |
| 281 class FunctionExpression extends Expression { |
| 282 final FunctionDefinition definition; |
| 283 |
| 284 FunctionExpression(this.definition) { |
| 285 assert(definition.element.functionSignature.type.returnType.treatAsDynamic); |
| 286 } |
| 287 |
| 288 accept(ExpressionVisitor visitor) => visitor.visitFunctionExpression(this); |
| 289 } |
| 290 |
| 291 /// Declares a local function. |
| 292 /// Used for functions that may not occur in expression context due to |
| 293 /// being recursive or having a return type. |
| 294 /// The [variable] must not occur as the left-hand side of an [Assign] or |
| 295 /// any other [FunctionDeclaration]. |
| 296 class FunctionDeclaration extends Statement { |
| 297 Variable variable; |
| 298 final FunctionDefinition definition; |
| 299 Statement next; |
| 300 |
| 301 FunctionDeclaration(this.variable, this.definition, this.next) { |
| 302 ++variable.writeCount; |
| 303 } |
| 304 |
| 305 accept(StatementVisitor visitor) => visitor.visitFunctionDeclaration(this); |
| 306 } |
| 307 |
267 /// A [LabeledStatement] or [WhileTrue] or [WhileCondition]. | 308 /// A [LabeledStatement] or [WhileTrue] or [WhileCondition]. |
268 abstract class JumpTarget extends Statement { | 309 abstract class JumpTarget extends Statement { |
269 Label get label; | 310 Label get label; |
270 Statement get body; | 311 Statement get body; |
271 } | 312 } |
272 | 313 |
273 /** | 314 /** |
274 * A labeled statement. Breaks to the label within the labeled statement | 315 * A labeled statement. Breaks to the label within the labeled statement |
275 * target the successor statement. | 316 * target the successor statement. |
276 */ | 317 */ |
277 class LabeledStatement extends JumpTarget { | 318 class LabeledStatement extends JumpTarget { |
278 Statement next; | 319 Statement next; |
279 final Label label; | 320 final Label label; |
280 Statement body; | 321 Statement body; |
281 | 322 |
282 LabeledStatement(this.label, this.body, this.next) { | 323 LabeledStatement(this.label, this.body, this.next) { |
283 assert(label.binding == null); | 324 assert(label.binding == null); |
284 label.binding = this; | 325 label.binding = this; |
285 } | 326 } |
286 | 327 |
287 accept(StatementVisitor visitor) => visitor.visitLabeledStatement(this); | 328 accept(StatementVisitor visitor) => visitor.visitLabeledStatement(this); |
288 } | 329 } |
289 | 330 |
290 /// A [WhileTrue] or [WhileCondition] loop. | 331 /// A [WhileTrue] or [WhileCondition] loop. |
291 abstract class Loop extends JumpTarget { | 332 abstract class Loop extends JumpTarget { |
292 /// When a [Continue] to a loop is executed, all update expressions are | |
293 /// evaluated right-to-left before control resumes at the head of the loop. | |
294 List<Expression> get updates; | |
295 } | 333 } |
296 | 334 |
297 /** | 335 /** |
298 * A labeled while(true) loop. | 336 * A labeled while(true) loop. |
299 */ | 337 */ |
300 class WhileTrue extends Loop { | 338 class WhileTrue extends Loop { |
301 final Label label; | 339 final Label label; |
302 Statement body; | 340 Statement body; |
303 final List<Expression> updates = <Expression>[]; | |
304 | 341 |
305 WhileTrue(this.label, this.body) { | 342 WhileTrue(this.label, this.body) { |
306 assert(label.binding == null); | 343 assert(label.binding == null); |
307 label.binding = this; | 344 label.binding = this; |
308 } | 345 } |
309 | 346 |
310 Statement get next => null; | 347 Statement get next => null; |
311 void set next(Statement s) => throw 'UNREACHABLE'; | 348 void set next(Statement s) => throw 'UNREACHABLE'; |
312 | 349 |
313 accept(StatementVisitor visitor) => visitor.visitWhileTrue(this); | 350 accept(StatementVisitor visitor) => visitor.visitWhileTrue(this); |
314 } | 351 } |
315 | 352 |
316 /** | 353 /** |
317 * A while loop with a condition. If the condition is false, control resumes | 354 * A while loop with a condition. If the condition is false, control resumes |
318 * at the [next] statement. | 355 * at the [next] statement. |
319 * | 356 * |
320 * It is NOT valid to target this statement with a [Break]. | 357 * It is NOT valid to target this statement with a [Break]. |
321 * The only way to reach [next] is for the condition to evaluate to false. | 358 * The only way to reach [next] is for the condition to evaluate to false. |
322 * | 359 * |
323 * [WhileCondition] statements are introduced in the [LoopRewriter] and is | 360 * [WhileCondition] statements are introduced in the [LoopRewriter] and is |
324 * assumed not to occur before then. | 361 * assumed not to occur before then. |
325 */ | 362 */ |
326 class WhileCondition extends Loop { | 363 class WhileCondition extends Loop { |
327 final Label label; | 364 final Label label; |
328 Expression condition; | 365 Expression condition; |
329 Statement body; | 366 Statement body; |
330 Statement next; | 367 Statement next; |
331 final List<Expression> updates; | |
332 | 368 |
333 WhileCondition(this.label, this.condition, this.body, | 369 WhileCondition(this.label, this.condition, this.body, |
334 this.next, this.updates) { | 370 this.next) { |
335 assert(label.binding == null); | 371 assert(label.binding == null); |
336 label.binding = this; | 372 label.binding = this; |
337 } | 373 } |
338 | 374 |
339 accept(StatementVisitor visitor) => visitor.visitWhileCondition(this); | 375 accept(StatementVisitor visitor) => visitor.visitWhileCondition(this); |
340 } | 376 } |
341 | 377 |
342 /// A [Break] or [Continue] statement. | 378 /// A [Break] or [Continue] statement. |
343 abstract class Jump extends Statement { | 379 abstract class Jump extends Statement { |
344 Label get target; | 380 Label get target; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 * An assignments of an [Expression] to a [Variable]. | 418 * An assignments of an [Expression] to a [Variable]. |
383 * | 419 * |
384 * In contrast to the CPS-based IR, non-primitive expressions can be assigned | 420 * In contrast to the CPS-based IR, non-primitive expressions can be assigned |
385 * to variables. | 421 * to variables. |
386 */ | 422 */ |
387 class Assign extends Statement { | 423 class Assign extends Statement { |
388 Statement next; | 424 Statement next; |
389 final Variable variable; | 425 final Variable variable; |
390 Expression definition; | 426 Expression definition; |
391 | 427 |
392 Assign(this.variable, this.definition, this.next); | 428 /// If true, this declares a new copy of the closure variable. |
| 429 /// The consequences are similar to [ir.SetClosureVariable]. |
| 430 /// All uses of the variable must be nested inside the [next] statement. |
| 431 bool isDeclaration; |
| 432 |
| 433 Assign(this.variable, this.definition, this.next, |
| 434 { this.isDeclaration: false }) { |
| 435 variable.writeCount++; |
| 436 } |
393 | 437 |
394 bool get hasExactlyOneUse => variable.readCount == 1; | 438 bool get hasExactlyOneUse => variable.readCount == 1; |
395 | 439 |
396 accept(StatementVisitor visitor) => visitor.visitAssign(this); | 440 accept(StatementVisitor visitor) => visitor.visitAssign(this); |
397 } | 441 } |
398 | 442 |
399 /** | 443 /** |
400 * A return exit from the function. | 444 * A return exit from the function. |
401 * | 445 * |
402 * In contrast to the CPS-based IR, the return value is an arbitrary | 446 * In contrast to the CPS-based IR, the return value is an arbitrary |
(...skipping 30 matching lines...) Expand all Loading... |
433 class ExpressionStatement extends Statement { | 477 class ExpressionStatement extends Statement { |
434 Statement next; | 478 Statement next; |
435 Expression expression; | 479 Expression expression; |
436 | 480 |
437 ExpressionStatement(this.expression, this.next); | 481 ExpressionStatement(this.expression, this.next); |
438 | 482 |
439 accept(StatementVisitor visitor) => visitor.visitExpressionStatement(this); | 483 accept(StatementVisitor visitor) => visitor.visitExpressionStatement(this); |
440 } | 484 } |
441 | 485 |
442 class FunctionDefinition extends Node { | 486 class FunctionDefinition extends Node { |
| 487 final FunctionElement element; |
443 final List<Variable> parameters; | 488 final List<Variable> parameters; |
444 Statement body; | 489 Statement body; |
445 final List<ConstDeclaration> localConstants; | 490 final List<ConstDeclaration> localConstants; |
446 | 491 |
447 FunctionDefinition(this.parameters, this.body, this.localConstants); | 492 FunctionDefinition(this.element, this.parameters, this.body, |
| 493 this.localConstants); |
448 } | 494 } |
449 | 495 |
450 abstract class ExpressionVisitor<E> { | 496 abstract class ExpressionVisitor<E> { |
451 E visitExpression(Expression e) => e.accept(this); | 497 E visitExpression(Expression e) => e.accept(this); |
452 E visitVariable(Variable node); | 498 E visitVariable(Variable node); |
453 E visitInvokeStatic(InvokeStatic node); | 499 E visitInvokeStatic(InvokeStatic node); |
454 E visitInvokeMethod(InvokeMethod node); | 500 E visitInvokeMethod(InvokeMethod node); |
455 E visitInvokeSuperMethod(InvokeSuperMethod node); | 501 E visitInvokeSuperMethod(InvokeSuperMethod node); |
456 E visitInvokeConstructor(InvokeConstructor node); | 502 E visitInvokeConstructor(InvokeConstructor node); |
457 E visitConcatenateStrings(ConcatenateStrings node); | 503 E visitConcatenateStrings(ConcatenateStrings node); |
458 E visitConstant(Constant node); | 504 E visitConstant(Constant node); |
459 E visitThis(This node); | 505 E visitThis(This node); |
460 E visitReifyTypeVar(ReifyTypeVar node); | 506 E visitReifyTypeVar(ReifyTypeVar node); |
461 E visitConditional(Conditional node); | 507 E visitConditional(Conditional node); |
462 E visitLogicalOperator(LogicalOperator node); | 508 E visitLogicalOperator(LogicalOperator node); |
463 E visitNot(Not node); | 509 E visitNot(Not node); |
464 E visitLiteralList(LiteralList node); | 510 E visitLiteralList(LiteralList node); |
465 E visitLiteralMap(LiteralMap node); | 511 E visitLiteralMap(LiteralMap node); |
466 E visitTypeOperator(TypeOperator node); | 512 E visitTypeOperator(TypeOperator node); |
| 513 E visitFunctionExpression(FunctionExpression node); |
467 } | 514 } |
468 | 515 |
469 abstract class StatementVisitor<S> { | 516 abstract class StatementVisitor<S> { |
470 S visitStatement(Statement s) => s.accept(this); | 517 S visitStatement(Statement s) => s.accept(this); |
471 S visitLabeledStatement(LabeledStatement node); | 518 S visitLabeledStatement(LabeledStatement node); |
472 S visitAssign(Assign node); | 519 S visitAssign(Assign node); |
473 S visitReturn(Return node); | 520 S visitReturn(Return node); |
474 S visitBreak(Break node); | 521 S visitBreak(Break node); |
475 S visitContinue(Continue node); | 522 S visitContinue(Continue node); |
476 S visitIf(If node); | 523 S visitIf(If node); |
477 S visitWhileTrue(WhileTrue node); | 524 S visitWhileTrue(WhileTrue node); |
478 S visitWhileCondition(WhileCondition node); | 525 S visitWhileCondition(WhileCondition node); |
| 526 S visitFunctionDeclaration(FunctionDeclaration node); |
479 S visitExpressionStatement(ExpressionStatement node); | 527 S visitExpressionStatement(ExpressionStatement node); |
480 } | 528 } |
481 | 529 |
482 abstract class Visitor<S,E> implements ExpressionVisitor<E>, | 530 abstract class Visitor<S,E> implements ExpressionVisitor<E>, |
483 StatementVisitor<S> { | 531 StatementVisitor<S> { |
484 E visitExpression(Expression e) => e.accept(this); | 532 E visitExpression(Expression e) => e.accept(this); |
485 S visitStatement(Statement s) => s.accept(this); | 533 S visitStatement(Statement s) => s.accept(this); |
486 } | 534 } |
487 | 535 |
| 536 class RecursiveVisitor extends Visitor { |
| 537 visitFunctionDefinition(FunctionDefinition node) { |
| 538 visitStatement(node.body); |
| 539 } |
| 540 |
| 541 visitVariable(Variable node) {} |
| 542 |
| 543 visitInvokeStatic(InvokeStatic node) { |
| 544 node.arguments.forEach(visitExpression); |
| 545 } |
| 546 |
| 547 visitInvokeMethod(InvokeMethod node) { |
| 548 visitExpression(node.receiver); |
| 549 node.arguments.forEach(visitExpression); |
| 550 } |
| 551 |
| 552 visitInvokeSuperMethod(InvokeSuperMethod node) { |
| 553 node.arguments.forEach(visitExpression); |
| 554 } |
| 555 |
| 556 visitInvokeConstructor(InvokeConstructor node) { |
| 557 node.arguments.forEach(visitExpression); |
| 558 } |
| 559 |
| 560 visitConcatenateStrings(ConcatenateStrings node) { |
| 561 node.arguments.forEach(visitExpression); |
| 562 } |
| 563 |
| 564 visitConstant(Constant node) {} |
| 565 |
| 566 visitThis(This node) {} |
| 567 |
| 568 visitReifyTypeVar(ReifyTypeVar node) {} |
| 569 |
| 570 visitConditional(Conditional node) { |
| 571 visitExpression(node.condition); |
| 572 visitExpression(node.thenExpression); |
| 573 visitExpression(node.elseExpression); |
| 574 } |
| 575 |
| 576 visitLogicalOperator(LogicalOperator node) { |
| 577 visitExpression(node.left); |
| 578 visitExpression(node.right); |
| 579 } |
| 580 |
| 581 visitNot(Not node) { |
| 582 visitExpression(node.operand); |
| 583 } |
| 584 |
| 585 visitLiteralList(LiteralList node) { |
| 586 node.values.forEach(visitExpression); |
| 587 } |
| 588 |
| 589 visitLiteralMap(LiteralMap node) { |
| 590 for (int i=0; i<node.keys.length; i++) { |
| 591 visitExpression(node.keys[i]); |
| 592 visitExpression(node.values[i]); |
| 593 } |
| 594 } |
| 595 |
| 596 visitTypeOperator(TypeOperator node) { |
| 597 visitExpression(node.receiver); |
| 598 } |
| 599 |
| 600 visitFunctionExpression(FunctionExpression node) { |
| 601 visitFunctionDefinition(node.definition); |
| 602 } |
| 603 |
| 604 visitLabeledStatement(LabeledStatement node) { |
| 605 visitStatement(node.body); |
| 606 visitStatement(node.next); |
| 607 } |
| 608 |
| 609 visitAssign(Assign node) { |
| 610 visitExpression(node.definition); |
| 611 visitVariable(node.variable); |
| 612 visitStatement(node.next); |
| 613 } |
| 614 |
| 615 visitReturn(Return node) { |
| 616 visitExpression(node.value); |
| 617 } |
| 618 |
| 619 visitBreak(Break node) {} |
| 620 |
| 621 visitContinue(Continue node) {} |
| 622 |
| 623 visitIf(If node) { |
| 624 visitExpression(node.condition); |
| 625 visitStatement(node.thenStatement); |
| 626 visitStatement(node.elseStatement); |
| 627 } |
| 628 |
| 629 visitWhileTrue(WhileTrue node) { |
| 630 visitStatement(node.body); |
| 631 } |
| 632 |
| 633 visitWhileCondition(WhileCondition node) { |
| 634 visitExpression(node.condition); |
| 635 visitStatement(node.body); |
| 636 visitStatement(node.next); |
| 637 } |
| 638 |
| 639 visitFunctionDeclaration(FunctionDeclaration node) { |
| 640 visitFunctionDefinition(node.definition); |
| 641 visitStatement(node.next); |
| 642 } |
| 643 |
| 644 visitExpressionStatement(ExpressionStatement node) { |
| 645 visitExpression(node.expression); |
| 646 visitStatement(node.next); |
| 647 } |
| 648 } |
| 649 |
488 /** | 650 /** |
489 * Builder translates from CPS-based IR to direct-style Tree. | 651 * Builder translates from CPS-based IR to direct-style Tree. |
490 * | 652 * |
491 * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced | 653 * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced |
492 * non-exit continuation `Cont(v, body)` is translated into a direct-style call | 654 * non-exit continuation `Cont(v, body)` is translated into a direct-style call |
493 * whose value is bound in the continuation body: | 655 * whose value is bound in the continuation body: |
494 * | 656 * |
495 * `LetVal(v, Invoke(fun, args), body)` | 657 * `LetVal(v, Invoke(fun, args), body)` |
496 * | 658 * |
497 * and the continuation definition is eliminated. A similar translation is | 659 * and the continuation definition is eliminated. A similar translation is |
(...skipping 19 matching lines...) Expand all Loading... |
517 * particular, intermediate values and blocks used for local control flow are | 679 * particular, intermediate values and blocks used for local control flow are |
518 * still all named. | 680 * still all named. |
519 */ | 681 */ |
520 class Builder extends ir.Visitor<Node> { | 682 class Builder extends ir.Visitor<Node> { |
521 final dart2js.Compiler compiler; | 683 final dart2js.Compiler compiler; |
522 | 684 |
523 /// Maps variable/parameter elements to the Tree variables that represent it. | 685 /// Maps variable/parameter elements to the Tree variables that represent it. |
524 final Map<Element, List<Variable>> element2variables = | 686 final Map<Element, List<Variable>> element2variables = |
525 <Element,List<Variable>>{}; | 687 <Element,List<Variable>>{}; |
526 | 688 |
| 689 /// Like [element2variables], except for closure variables. Closure variables |
| 690 /// are not subject to SSA, so at most one variable is used per element. |
| 691 final Map<Element, Variable> element2closure = <Element, Variable>{}; |
| 692 |
527 // Continuations with more than one use are replaced with Tree labels. This | 693 // Continuations with more than one use are replaced with Tree labels. This |
528 // is the mapping from continuations to labels. | 694 // is the mapping from continuations to labels. |
529 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{}; | 695 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{}; |
530 | 696 |
531 FunctionDefinition function; | 697 FunctionDefinition function; |
532 ir.Continuation returnContinuation; | 698 ir.Continuation returnContinuation; |
533 | 699 |
534 /// Variable used in [buildPhiAssignments] as a temporary when swapping | 700 Builder parent; |
535 /// variables. | |
536 final Variable tempVar = new Variable(null); | |
537 | 701 |
538 Builder(this.compiler); | 702 Builder(this.compiler); |
539 | 703 |
| 704 Builder.inner(Builder parent) |
| 705 : this.parent = parent, |
| 706 compiler = parent.compiler; |
| 707 |
| 708 /// Variable used in [buildPhiAssignments] as a temporary when swapping |
| 709 /// variables. |
| 710 Variable phiTempVar; |
| 711 |
| 712 Variable getClosureVariable(Element element) { |
| 713 if (element.enclosingElement != function.element) { |
| 714 return parent.getClosureVariable(element); |
| 715 } |
| 716 Variable variable = element2closure[element]; |
| 717 if (variable == null) { |
| 718 variable = new Variable(function, element); |
| 719 element2closure[element] = variable; |
| 720 } |
| 721 return variable; |
| 722 } |
| 723 |
540 /// Obtains the variable representing the given primitive. Returns null for | 724 /// Obtains the variable representing the given primitive. Returns null for |
541 /// primitives that have no reference and do not need a variable. | 725 /// primitives that have no reference and do not need a variable. |
542 Variable getVariable(ir.Primitive primitive) { | 726 Variable getVariable(ir.Primitive primitive) { |
543 if (primitive.registerIndex == null) { | 727 if (primitive.registerIndex == null) { |
544 return null; // variable is unused | 728 return null; // variable is unused |
545 } | 729 } |
546 List<Variable> variables = element2variables[primitive.element]; | 730 List<Variable> variables = element2variables[primitive.hint]; |
547 if (variables == null) { | 731 if (variables == null) { |
548 variables = <Variable>[]; | 732 variables = <Variable>[]; |
549 element2variables[primitive.element] = variables; | 733 element2variables[primitive.hint] = variables; |
550 } | 734 } |
551 while (variables.length <= primitive.registerIndex) { | 735 while (variables.length <= primitive.registerIndex) { |
552 variables.add(new Variable(primitive.element)); | 736 variables.add(new Variable(function, primitive.hint)); |
553 } | 737 } |
554 return variables[primitive.registerIndex]; | 738 return variables[primitive.registerIndex]; |
555 } | 739 } |
556 | 740 |
557 /// Obtains a reference to the tree Variable corresponding to the IR primitive | 741 /// Obtains a reference to the tree Variable corresponding to the IR primitive |
558 /// referred to by [reference]. | 742 /// referred to by [reference]. |
559 /// This increments the reference count for the given variable, so the | 743 /// This increments the reference count for the given variable, so the |
560 /// returned expression must be used in the tree. | 744 /// returned expression must be used in the tree. |
561 Expression getVariableReference(ir.Reference reference) { | 745 Expression getVariableReference(ir.Reference reference) { |
562 Variable variable = getVariable(reference.definition); | 746 Variable variable = getVariable(reference.definition); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 } | 829 } |
646 Variable param = getVariable(parameters[i]); | 830 Variable param = getVariable(parameters[i]); |
647 Variable arg = arguments[i]; | 831 Variable arg = arguments[i]; |
648 if (param == null || param == arg) { | 832 if (param == null || param == arg) { |
649 return; // No assignment necessary. | 833 return; // No assignment necessary. |
650 } | 834 } |
651 if (assignmentSrc[i] != null) { | 835 if (assignmentSrc[i] != null) { |
652 // Cycle found; store argument in a temporary variable. | 836 // Cycle found; store argument in a temporary variable. |
653 // The temporary will then be used as right-hand side when the | 837 // The temporary will then be used as right-hand side when the |
654 // assignment gets added. | 838 // assignment gets added. |
655 if (assignmentSrc[i] != tempVar) { // Only move to temporary once. | 839 if (assignmentSrc[i] != phiTempVar) { // Only move to temporary once. |
656 assignmentSrc[i] = tempVar; | 840 assignmentSrc[i] = phiTempVar; |
657 addAssignment(tempVar, arg); | 841 addAssignment(phiTempVar, arg); |
658 } | 842 } |
659 return; | 843 return; |
660 } | 844 } |
661 assignmentSrc[i] = arg; | 845 assignmentSrc[i] = arg; |
662 List<int> paramUses = rightHand[param]; | 846 List<int> paramUses = rightHand[param]; |
663 if (paramUses != null) { | 847 if (paramUses != null) { |
664 for (int useIndex in paramUses) { | 848 for (int useIndex in paramUses) { |
665 visitAssignment(useIndex); | 849 visitAssignment(useIndex); |
666 } | 850 } |
667 } | 851 } |
668 addAssignment(param, assignmentSrc[i]); | 852 addAssignment(param, assignmentSrc[i]); |
669 done[i] = true; | 853 done[i] = true; |
670 } | 854 } |
671 | 855 |
672 for (int i = 0; i < parameters.length; i++) { | 856 for (int i = 0; i < parameters.length; i++) { |
673 if (done[i] == null) { | 857 if (done[i] == null) { |
674 visitAssignment(i); | 858 visitAssignment(i); |
675 } | 859 } |
676 } | 860 } |
677 | 861 |
678 if (first == null) { | 862 if (first == null) { |
679 first = buildRest(); | 863 first = buildRest(); |
680 } else { | 864 } else { |
681 current.next = buildRest(); | 865 current.next = buildRest(); |
682 } | 866 } |
683 return first; | 867 return first; |
684 } | 868 } |
685 | 869 |
| 870 visitNode(ir.Node node) => throw "Unhandled node: $node"; |
| 871 |
686 Expression visitFunctionDefinition(ir.FunctionDefinition node) { | 872 Expression visitFunctionDefinition(ir.FunctionDefinition node) { |
| 873 List<Variable> parameters = <Variable>[]; |
| 874 function = new FunctionDefinition(node.element, parameters, |
| 875 null, node.localConstants); |
687 returnContinuation = node.returnContinuation; | 876 returnContinuation = node.returnContinuation; |
688 List<Variable> parameters = <Variable>[]; | |
689 for (ir.Parameter p in node.parameters) { | 877 for (ir.Parameter p in node.parameters) { |
690 Variable parameter = getVariable(p); | 878 Variable parameter = getVariable(p); |
691 assert(parameter != null); | 879 assert(parameter != null); |
| 880 ++parameter.writeCount; // Being a parameter counts as a write. |
692 parameters.add(parameter); | 881 parameters.add(parameter); |
693 } | 882 } |
694 function = new FunctionDefinition(parameters, visit(node.body), | 883 phiTempVar = new Variable(function, null); |
695 node.localConstants); | 884 function.body = visit(node.body); |
696 return null; | 885 return null; |
697 } | 886 } |
698 | 887 |
699 Statement visitLetPrim(ir.LetPrim node) { | 888 Statement visitLetPrim(ir.LetPrim node) { |
700 Variable variable = getVariable(node.primitive); | 889 Variable variable = getVariable(node.primitive); |
701 return variable == null | 890 |
702 ? visit(node.body) | 891 // Don't translate unused primitives. |
703 : new Assign(variable, visit(node.primitive), visit(node.body)); | 892 if (variable == null) return visit(node.body); |
| 893 |
| 894 Node definition = visit(node.primitive); |
| 895 |
| 896 // visitPrimitive returns a Statement without successor if it cannot occur |
| 897 // in expression context (currently only the case for FunctionDeclarations). |
| 898 if (definition is Statement) { |
| 899 definition.next = visit(node.body); |
| 900 return definition; |
| 901 } else { |
| 902 return new Assign(variable, definition, visit(node.body)); |
| 903 } |
704 } | 904 } |
705 | 905 |
706 Statement visitLetCont(ir.LetCont node) { | 906 Statement visitLetCont(ir.LetCont node) { |
707 Label label; | 907 Label label; |
708 if (node.continuation.hasMultipleUses) { | 908 if (node.continuation.hasMultipleUses) { |
709 label = new Label(); | 909 label = new Label(); |
710 labels[node.continuation] = label; | 910 labels[node.continuation] = label; |
711 } | 911 } |
712 Statement body = visit(node.body); | 912 Statement body = visit(node.body); |
713 // The continuation's body is not always translated directly here because | 913 // The continuation's body is not always translated directly here because |
714 // it may have been already translated: | 914 // it may have been already translated: |
715 // * For singly-used continuations, the continuation's body is | 915 // * For singly-used continuations, the continuation's body is |
716 // translated at the site of the continuation invocation. | 916 // translated at the site of the continuation invocation. |
717 // * For recursive continuations, there is a single non-recursive | 917 // * For recursive continuations, there is a single non-recursive |
718 // invocation. The continuation's body is translated at the site | 918 // invocation. The continuation's body is translated at the site |
719 // of the non-recursive continuation invocation. | 919 // of the non-recursive continuation invocation. |
720 // See visitInvokeContinuation for the implementation. | 920 // See visitInvokeContinuation for the implementation. |
721 if (label == null || node.continuation.isRecursive) return body; | 921 if (label == null || node.continuation.isRecursive) return body; |
722 return new LabeledStatement(label, body, visit(node.continuation.body)); | 922 return new LabeledStatement(label, body, visit(node.continuation.body)); |
723 } | 923 } |
724 | 924 |
725 Statement visitInvokeStatic(ir.InvokeStatic node) { | 925 Statement visitInvokeStatic(ir.InvokeStatic node) { |
726 // Calls are translated to direct style. | 926 // Calls are translated to direct style. |
727 List<Expression> arguments = translateArguments(node.arguments); | 927 List<Expression> arguments = translateArguments(node.arguments); |
728 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); | 928 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); |
729 ir.Continuation cont = node.continuation.definition; | 929 return continueWithExpression(node.continuation, invoke); |
730 if (cont == returnContinuation) { | |
731 return new Return(invoke); | |
732 } else { | |
733 assert(cont.hasExactlyOneUse); | |
734 assert(cont.parameters.length == 1); | |
735 return buildContinuationAssignment(cont.parameters.single, invoke, | |
736 () => visit(cont.body)); | |
737 } | |
738 } | 930 } |
739 | 931 |
740 Statement visitInvokeMethod(ir.InvokeMethod node) { | 932 Statement visitInvokeMethod(ir.InvokeMethod node) { |
741 Expression receiver = getVariableReference(node.receiver); | 933 Expression receiver = getVariableReference(node.receiver); |
742 List<Expression> arguments = translateArguments(node.arguments); | 934 List<Expression> arguments = translateArguments(node.arguments); |
743 Expression invoke = new InvokeMethod(receiver, node.selector, arguments); | 935 Expression invoke = new InvokeMethod(receiver, node.selector, arguments); |
744 ir.Continuation cont = node.continuation.definition; | 936 return continueWithExpression(node.continuation, invoke); |
745 if (cont == returnContinuation) { | |
746 return new Return(invoke); | |
747 } else { | |
748 assert(cont.hasExactlyOneUse); | |
749 assert(cont.parameters.length == 1); | |
750 return buildContinuationAssignment(cont.parameters.single, invoke, | |
751 () => visit(cont.body)); | |
752 } | |
753 } | 937 } |
754 | 938 |
755 Statement visitInvokeSuperMethod(ir.InvokeSuperMethod node) { | 939 Statement visitInvokeSuperMethod(ir.InvokeSuperMethod node) { |
756 List<Expression> arguments = translateArguments(node.arguments); | 940 List<Expression> arguments = translateArguments(node.arguments); |
757 Expression invoke = new InvokeSuperMethod(node.selector, arguments); | 941 Expression invoke = new InvokeSuperMethod(node.selector, arguments); |
758 ir.Continuation cont = node.continuation.definition; | 942 return continueWithExpression(node.continuation, invoke); |
759 if (cont == returnContinuation) { | |
760 return new Return(invoke); | |
761 } else { | |
762 assert(cont.hasExactlyOneUse); | |
763 assert(cont.parameters.length == 1); | |
764 return buildContinuationAssignment(cont.parameters.single, invoke, | |
765 () => visit(cont.body)); | |
766 } | |
767 } | 943 } |
768 | 944 |
769 Statement visitConcatenateStrings(ir.ConcatenateStrings node) { | 945 Statement visitConcatenateStrings(ir.ConcatenateStrings node) { |
770 List<Expression> arguments = translateArguments(node.arguments); | 946 List<Expression> arguments = translateArguments(node.arguments); |
771 Expression concat = new ConcatenateStrings(arguments); | 947 Expression concat = new ConcatenateStrings(arguments); |
772 ir.Continuation cont = node.continuation.definition; | 948 return continueWithExpression(node.continuation, concat); |
| 949 } |
| 950 |
| 951 Statement continueWithExpression(ir.Reference continuation, |
| 952 Expression expression) { |
| 953 ir.Continuation cont = continuation.definition; |
773 if (cont == returnContinuation) { | 954 if (cont == returnContinuation) { |
774 return new Return(concat); | 955 return new Return(expression); |
775 } else { | 956 } else { |
776 assert(cont.hasExactlyOneUse); | 957 assert(cont.hasExactlyOneUse); |
777 assert(cont.parameters.length == 1); | 958 assert(cont.parameters.length == 1); |
778 return buildContinuationAssignment(cont.parameters.single, concat, | 959 return buildContinuationAssignment(cont.parameters.single, expression, |
779 () => visit(cont.body)); | 960 () => visit(cont.body)); |
780 } | 961 } |
781 } | 962 } |
782 | 963 |
| 964 Expression visitGetClosureVariable(ir.GetClosureVariable node) { |
| 965 return getClosureVariable(node.variable); |
| 966 } |
| 967 |
| 968 Statement visitSetClosureVariable(ir.SetClosureVariable node) { |
| 969 Variable variable = getClosureVariable(node.variable); |
| 970 Expression value = getVariableReference(node.value); |
| 971 return new Assign(variable, value, visit(node.body), |
| 972 isDeclaration: node.isDeclaration); |
| 973 } |
| 974 |
| 975 Statement visitDeclareFunction(ir.DeclareFunction node) { |
| 976 Variable variable = getClosureVariable(node.variable); |
| 977 FunctionDefinition function = makeSubFunction(node.definition); |
| 978 return new FunctionDeclaration(variable, function, visit(node.body)); |
| 979 } |
| 980 |
783 Statement visitAsCast(ir.AsCast node) { | 981 Statement visitAsCast(ir.AsCast node) { |
784 Expression receiver = getVariableReference(node.receiver); | 982 Expression receiver = getVariableReference(node.receiver); |
785 Expression concat = new TypeOperator(receiver, node.type, "as"); | 983 Expression concat = new TypeOperator(receiver, node.type, "as"); |
786 ir.Continuation cont = node.continuation.definition; | 984 return continueWithExpression(node.continuation, concat); |
787 if (cont == returnContinuation) { | |
788 return new Return(concat); | |
789 } else { | |
790 assert(cont.hasExactlyOneUse); | |
791 assert(cont.parameters.length == 1); | |
792 return buildContinuationAssignment(cont.parameters.single, concat, | |
793 () => visit(cont.body)); | |
794 } | |
795 } | 985 } |
796 | 986 |
797 Statement visitInvokeConstructor(ir.InvokeConstructor node) { | 987 Statement visitInvokeConstructor(ir.InvokeConstructor node) { |
798 List<Expression> arguments = translateArguments(node.arguments); | 988 List<Expression> arguments = translateArguments(node.arguments); |
799 Expression invoke = | 989 Expression invoke = |
800 new InvokeConstructor(node.type, node.target, node.selector, arguments); | 990 new InvokeConstructor(node.type, node.target, node.selector, arguments); |
801 ir.Continuation cont = node.continuation.definition; | 991 return continueWithExpression(node.continuation, invoke); |
802 if (cont == returnContinuation) { | |
803 return new Return(invoke); | |
804 } else { | |
805 assert(cont.hasExactlyOneUse); | |
806 assert(cont.parameters.length == 1); | |
807 return buildContinuationAssignment(cont.parameters.single, invoke, | |
808 () => visit(cont.body)); | |
809 } | |
810 } | 992 } |
811 | 993 |
812 Statement visitInvokeContinuation(ir.InvokeContinuation node) { | 994 Statement visitInvokeContinuation(ir.InvokeContinuation node) { |
813 // Invocations of the return continuation are translated to returns. | 995 // Invocations of the return continuation are translated to returns. |
814 // Other continuation invocations are replaced with assignments of the | 996 // Other continuation invocations are replaced with assignments of the |
815 // arguments to formal parameter variables, followed by the body if | 997 // arguments to formal parameter variables, followed by the body if |
816 // the continuation is singly reference or a break if it is multiply | 998 // the continuation is singly reference or a break if it is multiply |
817 // referenced. | 999 // referenced. |
818 ir.Continuation cont = node.continuation.definition; | 1000 ir.Continuation cont = node.continuation.definition; |
819 if (cont == returnContinuation) { | 1001 if (cont == returnContinuation) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
863 | 1045 |
864 Expression visitConstant(ir.Constant node) { | 1046 Expression visitConstant(ir.Constant node) { |
865 return new Constant(node.expression, node.value); | 1047 return new Constant(node.expression, node.value); |
866 } | 1048 } |
867 | 1049 |
868 Expression visitThis(ir.This node) { | 1050 Expression visitThis(ir.This node) { |
869 return new This(); | 1051 return new This(); |
870 } | 1052 } |
871 | 1053 |
872 Expression visitReifyTypeVar(ir.ReifyTypeVar node) { | 1054 Expression visitReifyTypeVar(ir.ReifyTypeVar node) { |
873 return new ReifyTypeVar(node.element); | 1055 return new ReifyTypeVar(node.typeVariable); |
874 } | 1056 } |
875 | 1057 |
876 Expression visitLiteralList(ir.LiteralList node) { | 1058 Expression visitLiteralList(ir.LiteralList node) { |
877 return new LiteralList( | 1059 return new LiteralList( |
878 node.type, | 1060 node.type, |
879 translateArguments(node.values)); | 1061 translateArguments(node.values)); |
880 } | 1062 } |
881 | 1063 |
882 Expression visitLiteralMap(ir.LiteralMap node) { | 1064 Expression visitLiteralMap(ir.LiteralMap node) { |
883 return new LiteralMap( | 1065 return new LiteralMap( |
884 node.type, | 1066 node.type, |
885 translateArguments(node.keys), | 1067 translateArguments(node.keys), |
886 translateArguments(node.values)); | 1068 translateArguments(node.values)); |
887 } | 1069 } |
888 | 1070 |
| 1071 FunctionDefinition makeSubFunction(ir.FunctionDefinition function) { |
| 1072 return new Builder.inner(this).build(function); |
| 1073 } |
| 1074 |
| 1075 Node visitCreateFunction(ir.CreateFunction node) { |
| 1076 FunctionDefinition def = makeSubFunction(node.definition); |
| 1077 FunctionSignature signature = node.definition.element.functionSignature; |
| 1078 bool hasReturnType = !signature.type.returnType.treatAsDynamic; |
| 1079 if (hasReturnType) { |
| 1080 // This function cannot occur in expression context. |
| 1081 // The successor will be filled in by visitLetPrim. |
| 1082 return new FunctionDeclaration(getVariable(node), def, null); |
| 1083 } else { |
| 1084 return new FunctionExpression(def); |
| 1085 } |
| 1086 } |
| 1087 |
889 Expression visitIsCheck(ir.IsCheck node) { | 1088 Expression visitIsCheck(ir.IsCheck node) { |
890 return new TypeOperator(getVariableReference(node.receiver), | 1089 return new TypeOperator(getVariableReference(node.receiver), |
891 node.type, | 1090 node.type, |
892 "is"); | 1091 "is"); |
893 } | 1092 } |
894 | 1093 |
895 Expression visitParameter(ir.Parameter node) { | 1094 Expression visitParameter(ir.Parameter node) { |
896 // Continuation parameters are not visited (continuations themselves are | 1095 // Continuation parameters are not visited (continuations themselves are |
897 // not visited yet). | 1096 // not visited yet). |
898 compiler.internalError(compiler.currentElement, 'Unexpected IR node.'); | 1097 compiler.internalError(compiler.currentElement, 'Unexpected IR node.'); |
899 return null; | 1098 return null; |
900 } | 1099 } |
901 | 1100 |
902 Expression visitContinuation(ir.Continuation node) { | 1101 Expression visitContinuation(ir.Continuation node) { |
903 // Until continuations with multiple uses are supported, they are not | 1102 // Until continuations with multiple uses are supported, they are not |
904 // visited. | 1103 // visited. |
905 compiler.internalError(compiler.currentElement, 'Unexpected IR node.'); | 1104 compiler.internalError(compiler.currentElement, 'Unexpected IR node.'); |
906 return null; | 1105 return null; |
907 } | 1106 } |
908 | 1107 |
909 Expression visitIsTrue(ir.IsTrue node) { | 1108 Expression visitIsTrue(ir.IsTrue node) { |
910 return getVariableReference(node.value); | 1109 return getVariableReference(node.value); |
911 } | 1110 } |
912 } | 1111 } |
913 | 1112 |
| 1113 /// Eliminates redundant variables and assignments that occur immediately after |
| 1114 /// parameters are declared or after a function declaration. |
| 1115 /// |
| 1116 /// These patterns arise when translating out of CPS where closure variables |
| 1117 /// live in a separate space. Since function parameters are IR primitives they |
| 1118 /// must be moved into a separate closure variable for inner functions to access |
| 1119 /// them. For example: |
| 1120 /// |
| 1121 /// foo(x) { |
| 1122 /// let v1 = ref x in BODY |
| 1123 /// } |
| 1124 /// ==> (dart_tree Builder) |
| 1125 /// foo(x) { |
| 1126 /// var v1 = x; |
| 1127 /// BODY.. |
| 1128 /// } |
| 1129 /// |
| 1130 /// This phase attempts to merge v1 and x in the example above. |
| 1131 /// A similar pattern can occur for local function declarations that are used |
| 1132 /// from closures. |
| 1133 class CopyPropagateClosureVariables extends RecursiveVisitor { |
| 1134 |
| 1135 void rewrite(FunctionDefinition definition) { |
| 1136 visitFunctionDefinition(definition); |
| 1137 } |
| 1138 |
| 1139 /// Performs the rewrite: |
| 1140 /// |
| 1141 /// foo(x) { var v0 = x; S } |
| 1142 /// ==> (move v0 into parameter) |
| 1143 /// foo(v0) { S } |
| 1144 /// ==> (change the name of v0 to be x, so we preserve the parameter name) |
| 1145 /// foo(x) { S[v0\x] } |
| 1146 /// |
| 1147 /// Condition: x cannot be used anywhere else. |
| 1148 visitFunctionDefinition(FunctionDefinition definition) { |
| 1149 while (definition.body is Assign) { |
| 1150 Assign assign = definition.body; |
| 1151 if (assign.definition is! Variable) break; |
| 1152 |
| 1153 Variable rightHand = assign.definition; |
| 1154 if (rightHand.readCount != 1) break; |
| 1155 |
| 1156 int paramIndex = definition.parameters.indexOf(rightHand); |
| 1157 if (paramIndex == -1) break; |
| 1158 |
| 1159 // A variable may not occur as a parameter more than once. |
| 1160 if (definition.parameters.contains(assign.variable)) break; |
| 1161 |
| 1162 definition.parameters[paramIndex] = assign.variable; |
| 1163 assign.variable.element = rightHand.element; |
| 1164 definition.body = assign.next; |
| 1165 } |
| 1166 |
| 1167 visitStatement(definition.body); // Visit nested function definitions. |
| 1168 } |
| 1169 |
| 1170 /// Performs the rewrite: |
| 1171 /// |
| 1172 /// int v0() { S } |
| 1173 /// foo = v0; |
| 1174 /// ==> |
| 1175 /// int foo() { S } |
| 1176 /// |
| 1177 /// Condition: v0 cannot be used anywhere else. |
| 1178 visitFunctionDeclaration(FunctionDeclaration node) { |
| 1179 Statement next = node.next; |
| 1180 if (next is Assign && |
| 1181 next.definition == node.variable && |
| 1182 node.variable.readCount == 1 && |
| 1183 next.variable.writeCount == 1) { |
| 1184 node.variable = next.variable; |
| 1185 node.next = next.next; |
| 1186 } |
| 1187 super.visitFunctionDeclaration(node); |
| 1188 } |
| 1189 |
| 1190 } |
| 1191 |
914 /** | 1192 /** |
915 * Performs the following transformations on the tree: | 1193 * Performs the following transformations on the tree: |
916 * - Assignment propagation | 1194 * - Assignment propagation |
917 * - If-to-conditional conversion | 1195 * - If-to-conditional conversion |
918 * - Flatten nested ifs | 1196 * - Flatten nested ifs |
919 * - Break inlining | 1197 * - Break inlining |
920 * - Redirect breaks | 1198 * - Redirect breaks |
921 * | 1199 * |
922 * The above transformations all eliminate statements from the tree, and may | 1200 * The above transformations all eliminate statements from the tree, and may |
923 * introduce redexes of each other. | 1201 * introduce redexes of each other. |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1116 environment.removeLast(); | 1394 environment.removeLast(); |
1117 | 1395 |
1118 return node; | 1396 return node; |
1119 } | 1397 } |
1120 | 1398 |
1121 Expression visitNot(Not node) { | 1399 Expression visitNot(Not node) { |
1122 node.operand = visitExpression(node.operand); | 1400 node.operand = visitExpression(node.operand); |
1123 return node; | 1401 return node; |
1124 } | 1402 } |
1125 | 1403 |
| 1404 Expression visitFunctionExpression(FunctionExpression node) { |
| 1405 new StatementRewriter().rewrite(node.definition); |
| 1406 return node; |
| 1407 } |
| 1408 |
| 1409 Statement visitFunctionDeclaration(FunctionDeclaration node) { |
| 1410 new StatementRewriter().rewrite(node.definition); |
| 1411 node.next = visitStatement(node.next); |
| 1412 return node; |
| 1413 } |
| 1414 |
1126 Statement visitReturn(Return node) { | 1415 Statement visitReturn(Return node) { |
1127 node.value = visitExpression(node.value); | 1416 node.value = visitExpression(node.value); |
1128 return node; | 1417 return node; |
1129 } | 1418 } |
1130 | 1419 |
1131 | 1420 |
1132 Statement visitBreak(Break node) { | 1421 Statement visitBreak(Break node) { |
1133 // Redirect through chain of breaks. | 1422 // Redirect through chain of breaks. |
1134 // Note that useCount was accounted for at visitLabeledStatement. | 1423 // Note that useCount was accounted for at visitLabeledStatement. |
1135 // Note redirect may return either a Break or Continue statement. | 1424 // Note redirect may return either a Break or Continue statement. |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1296 static Statement combineStatementsWithSubexpressions( | 1585 static Statement combineStatementsWithSubexpressions( |
1297 Statement s, | 1586 Statement s, |
1298 Statement t, | 1587 Statement t, |
1299 Expression combine(Expression s, Expression t)) { | 1588 Expression combine(Expression s, Expression t)) { |
1300 if (s is Return && t is Return) { | 1589 if (s is Return && t is Return) { |
1301 return new Return(combine(s.value, t.value)); | 1590 return new Return(combine(s.value, t.value)); |
1302 } | 1591 } |
1303 if (s is Assign && t is Assign && s.variable == t.variable) { | 1592 if (s is Assign && t is Assign && s.variable == t.variable) { |
1304 Statement next = combineStatements(s.next, t.next); | 1593 Statement next = combineStatements(s.next, t.next); |
1305 if (next != null) { | 1594 if (next != null) { |
| 1595 --t.variable.writeCount; // Two assignments become one. |
1306 return new Assign(s.variable, | 1596 return new Assign(s.variable, |
1307 combine(s.definition, t.definition), | 1597 combine(s.definition, t.definition), |
1308 next); | 1598 next); |
1309 } | 1599 } |
1310 } | 1600 } |
1311 if (s is ExpressionStatement && t is ExpressionStatement) { | 1601 if (s is ExpressionStatement && t is ExpressionStatement) { |
1312 Statement next = combineStatements(s.next, t.next); | 1602 Statement next = combineStatements(s.next, t.next); |
1313 if (next != null) { | 1603 if (next != null) { |
1314 return new ExpressionStatement(combine(s.expression, t.expression), | 1604 return new ExpressionStatement(combine(s.expression, t.expression), |
1315 next); | 1605 next); |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1459 /// L: | 1749 /// L: |
1460 /// while (E) { | 1750 /// while (E) { |
1461 /// S1 | 1751 /// S1 |
1462 /// }; | 1752 /// }; |
1463 /// S2 | 1753 /// S2 |
1464 /// | 1754 /// |
1465 /// A similar transformation is used when S2 occurs in the 'then' position. | 1755 /// A similar transformation is used when S2 occurs in the 'then' position. |
1466 /// | 1756 /// |
1467 /// Note that the above pattern needs no iteration since nested ifs | 1757 /// Note that the above pattern needs no iteration since nested ifs |
1468 /// have been collapsed previously in the [StatementRewriter] phase. | 1758 /// have been collapsed previously in the [StatementRewriter] phase. |
1469 class LoopRewriter extends StatementVisitor<Statement> { | 1759 class LoopRewriter extends RecursiveVisitor { |
1470 | 1760 |
1471 Set<Label> usedContinueLabels = new Set<Label>(); | 1761 Set<Label> usedContinueLabels = new Set<Label>(); |
1472 | 1762 |
1473 void rewrite(FunctionDefinition function) { | 1763 void rewrite(FunctionDefinition function) { |
1474 function.body = visitStatement(function.body); | 1764 function.body = visitStatement(function.body); |
1475 } | 1765 } |
1476 | 1766 |
1477 Statement visitLabeledStatement(LabeledStatement node) { | 1767 Statement visitLabeledStatement(LabeledStatement node) { |
1478 node.body = visitStatement(node.body); | 1768 node.body = visitStatement(node.body); |
1479 node.next = visitStatement(node.next); | 1769 node.next = visitStatement(node.next); |
1480 return node; | 1770 return node; |
1481 } | 1771 } |
1482 | 1772 |
1483 Statement visitAssign(Assign node) { | 1773 Statement visitAssign(Assign node) { |
| 1774 visitExpression(node.definition); |
1484 node.next = visitStatement(node.next); | 1775 node.next = visitStatement(node.next); |
1485 return node; | 1776 return node; |
1486 } | 1777 } |
1487 | 1778 |
1488 Statement visitReturn(Return node) { | 1779 Statement visitReturn(Return node) { |
| 1780 visitExpression(node.value); |
1489 return node; | 1781 return node; |
1490 } | 1782 } |
1491 | 1783 |
1492 Statement visitBreak(Break node) { | 1784 Statement visitBreak(Break node) { |
1493 return node; | 1785 return node; |
1494 } | 1786 } |
1495 | 1787 |
1496 Statement visitContinue(Continue node) { | 1788 Statement visitContinue(Continue node) { |
1497 usedContinueLabels.add(node.target); | 1789 usedContinueLabels.add(node.target); |
1498 return node; | 1790 return node; |
1499 } | 1791 } |
1500 | 1792 |
1501 Statement visitIf(If node) { | 1793 Statement visitIf(If node) { |
| 1794 visitExpression(node.condition); |
1502 node.thenStatement = visitStatement(node.thenStatement); | 1795 node.thenStatement = visitStatement(node.thenStatement); |
1503 node.elseStatement = visitStatement(node.elseStatement); | 1796 node.elseStatement = visitStatement(node.elseStatement); |
1504 return node; | 1797 return node; |
1505 } | 1798 } |
1506 | 1799 |
1507 Statement visitWhileTrue(WhileTrue node) { | 1800 Statement visitWhileTrue(WhileTrue node) { |
1508 assert(!usedContinueLabels.contains(node.label)); | 1801 assert(!usedContinueLabels.contains(node.label)); |
1509 if (node.body is If) { | 1802 if (node.body is If) { |
1510 If body = node.body; | 1803 If body = node.body; |
1511 body.thenStatement = visitStatement(body.thenStatement); | 1804 body.thenStatement = visitStatement(body.thenStatement); |
1512 bool thenHasContinue = usedContinueLabels.remove(node.label); | 1805 bool thenHasContinue = usedContinueLabels.remove(node.label); |
1513 body.elseStatement = visitStatement(body.elseStatement); | 1806 body.elseStatement = visitStatement(body.elseStatement); |
1514 bool elseHasContinue = usedContinueLabels.remove(node.label); | 1807 bool elseHasContinue = usedContinueLabels.remove(node.label); |
1515 if (thenHasContinue && !elseHasContinue) { | 1808 if (thenHasContinue && !elseHasContinue) { |
1516 node.label.binding = null; // Prepare to rebind the label. | 1809 node.label.binding = null; // Prepare to rebind the label. |
1517 return new WhileCondition( | 1810 return new WhileCondition( |
1518 node.label, | 1811 node.label, |
1519 body.condition, | 1812 body.condition, |
1520 body.thenStatement, | 1813 body.thenStatement, |
1521 body.elseStatement, | 1814 body.elseStatement); |
1522 node.updates); | |
1523 } else if (!thenHasContinue && elseHasContinue) { | 1815 } else if (!thenHasContinue && elseHasContinue) { |
1524 node.label.binding = null; | 1816 node.label.binding = null; |
1525 return new WhileCondition( | 1817 return new WhileCondition( |
1526 node.label, | 1818 node.label, |
1527 new Not(body.condition), | 1819 new Not(body.condition), |
1528 body.elseStatement, | 1820 body.elseStatement, |
1529 body.thenStatement, | 1821 body.thenStatement); |
1530 node.updates); | |
1531 } | 1822 } |
1532 } else { | 1823 } else { |
1533 node.body = visitStatement(node.body); | 1824 node.body = visitStatement(node.body); |
1534 usedContinueLabels.remove(node.label); | 1825 usedContinueLabels.remove(node.label); |
1535 } | 1826 } |
1536 return node; | 1827 return node; |
1537 } | 1828 } |
1538 | 1829 |
1539 Statement visitWhileCondition(WhileCondition node) { | 1830 Statement visitWhileCondition(WhileCondition node) { |
1540 // Note: not reachable but the implementation is trivial | 1831 // Note: not reachable but the implementation is trivial |
| 1832 visitExpression(node.condition); |
1541 node.body = visitStatement(node.body); | 1833 node.body = visitStatement(node.body); |
1542 node.next = visitStatement(node.next); | 1834 node.next = visitStatement(node.next); |
1543 return node; | 1835 return node; |
1544 } | 1836 } |
1545 | 1837 |
1546 Statement visitExpressionStatement(ExpressionStatement node) { | 1838 Statement visitExpressionStatement(ExpressionStatement node) { |
| 1839 visitExpression(node.expression); |
1547 node.next = visitStatement(node.next); | 1840 node.next = visitStatement(node.next); |
1548 // for (;;) { ... E; continue* L ... } | |
1549 // ==> | |
1550 // for(;;E) { ... continue* L ... } | |
1551 if (node.next is Continue) { | |
1552 Continue jump = node.next; | |
1553 if (jump.target.useCount == 1) { | |
1554 Loop target = jump.target.binding; | |
1555 target.updates.add(node.expression); | |
1556 return jump; // Return the continue statement. | |
1557 // NOTE: The pattern may reclick in an enclosing expression statement. | |
1558 } | |
1559 } | |
1560 return node; | 1841 return node; |
1561 } | 1842 } |
1562 | 1843 |
| 1844 Statement visitFunctionDeclaration(FunctionDeclaration node) { |
| 1845 new LoopRewriter().rewrite(node.definition); |
| 1846 node.next = visitStatement(node.next); |
| 1847 return node; |
| 1848 } |
| 1849 |
| 1850 void visitFunctionExpression(FunctionExpression node) { |
| 1851 new LoopRewriter().rewrite(node.definition); |
| 1852 } |
| 1853 |
1563 } | 1854 } |
1564 | 1855 |
1565 | 1856 |
1566 /// Rewrites logical expressions to be more compact. | 1857 /// Rewrites logical expressions to be more compact. |
1567 /// | 1858 /// |
1568 /// In this class an expression is said to occur in "boolean context" if | 1859 /// In this class an expression is said to occur in "boolean context" if |
1569 /// its result is immediately applied to boolean conversion. | 1860 /// its result is immediately applied to boolean conversion. |
1570 /// | 1861 /// |
1571 /// IF STATEMENTS: | 1862 /// IF STATEMENTS: |
1572 /// | 1863 /// |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1767 } | 2058 } |
1768 | 2059 |
1769 Expression visitThis(This node) { | 2060 Expression visitThis(This node) { |
1770 return node; | 2061 return node; |
1771 } | 2062 } |
1772 | 2063 |
1773 Expression visitReifyTypeVar(ReifyTypeVar node) { | 2064 Expression visitReifyTypeVar(ReifyTypeVar node) { |
1774 return node; | 2065 return node; |
1775 } | 2066 } |
1776 | 2067 |
| 2068 Expression visitFunctionExpression(FunctionExpression node) { |
| 2069 new LogicalRewriter().rewrite(node.definition); |
| 2070 return node; |
| 2071 } |
| 2072 |
| 2073 Statement visitFunctionDeclaration(FunctionDeclaration node) { |
| 2074 new LogicalRewriter().rewrite(node.definition); |
| 2075 node.next = visitStatement(node.next); |
| 2076 return node; |
| 2077 } |
| 2078 |
1777 Expression visitNot(Not node) { | 2079 Expression visitNot(Not node) { |
1778 return toBoolean(makeCondition(node.operand, false, liftNots: false)); | 2080 return toBoolean(makeCondition(node.operand, false, liftNots: false)); |
1779 } | 2081 } |
1780 | 2082 |
1781 Expression visitConditional(Conditional node) { | 2083 Expression visitConditional(Conditional node) { |
1782 // node.condition will be visited after the then and else parts, because its | 2084 // node.condition will be visited after the then and else parts, because its |
1783 // polarity depends on what rewrite we use. | 2085 // polarity depends on what rewrite we use. |
1784 node.thenExpression = visitExpression(node.thenExpression); | 2086 node.thenExpression = visitExpression(node.thenExpression); |
1785 node.elseExpression = visitExpression(node.elseExpression); | 2087 node.elseExpression = visitExpression(node.elseExpression); |
1786 | 2088 |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1985 } | 2287 } |
1986 } | 2288 } |
1987 | 2289 |
1988 /// Destructively updates each entry of [l] with the result of visiting it. | 2290 /// Destructively updates each entry of [l] with the result of visiting it. |
1989 void _rewriteList(List<Expression> l) { | 2291 void _rewriteList(List<Expression> l) { |
1990 for (int i = 0; i < l.length; i++) { | 2292 for (int i = 0; i < l.length; i++) { |
1991 l[i] = visitExpression(l[i]); | 2293 l[i] = visitExpression(l[i]); |
1992 } | 2294 } |
1993 } | 2295 } |
1994 } | 2296 } |
| 2297 |
OLD | NEW |