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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart

Issue 366853007: dart2dart: Support for inner functions in new IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: SVN rebase Created 6 years, 5 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 | Annotate | Revision Log
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 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698