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

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

Issue 312793002: dart2dart: Preserve variable names throughout the IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Removed Definition.binding Created 6 years, 6 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 show Element, FunctionElement, FunctionSignature, ParameterElement, 9 show Element, FunctionElement, FunctionSignature, ParameterElement,
10 ClassElement; 10 ClassElement;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 int breakCount = 0; 76 int breakCount = 0;
77 77
78 /// The [LabeledStatement] binding this label. 78 /// The [LabeledStatement] binding this label.
79 LabeledStatement binding; 79 LabeledStatement binding;
80 } 80 }
81 81
82 /** 82 /**
83 * Variables are [Expression]s. 83 * Variables are [Expression]s.
84 */ 84 */
85 class Variable extends Expression { 85 class Variable extends Expression {
86 // A counter used to generate names. The counter is reset to 0 for each 86 /// Element used for synthesizing a name for the variable.
87 // function emitted. 87 /// Different variables may have the same element. May be null.
88 static int counter = 0; 88 Element element;
89 static String _newName() => 'v${counter++}';
90 89
91 Element element; 90 int readCount = 0;
92 String cachedName; 91 int writeCount = 0;
Kevin Millikin (Google) 2014/06/10 11:33:01 Other than incrementing and decrementing, we do no
asgerf 2014/06/10 12:22:23 Right.
93
94 String get name {
95 if (cachedName != null) return cachedName;
96 return cachedName = ((element == null) ? _newName() : element.name);
97 }
98 92
99 Variable(this.element); 93 Variable(this.element);
100 94
101 accept(Visitor visitor) => visitor.visitVariable(this); 95 accept(Visitor visitor) => visitor.visitVariable(this);
102 } 96 }
103 97
104 /** 98 /**
105 * Common interface for invocations with arguments. 99 * Common interface for invocations with arguments.
106 */ 100 */
107 abstract class Invoke { 101 abstract class Invoke {
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 /** 258 /**
265 * An assignments of an [Expression] to a [Variable]. 259 * An assignments of an [Expression] to a [Variable].
266 * 260 *
267 * In contrast to the CPS-based IR, non-primitive expressions can be assigned 261 * In contrast to the CPS-based IR, non-primitive expressions can be assigned
268 * to variables. 262 * to variables.
269 */ 263 */
270 class Assign extends Statement { 264 class Assign extends Statement {
271 Statement next; 265 Statement next;
272 final Variable variable; 266 final Variable variable;
273 Expression definition; 267 Expression definition;
274 final bool hasExactlyOneUse;
275 268
276 Assign(this.variable, this.definition, this.next, this.hasExactlyOneUse); 269 Assign(this.variable, this.definition, this.next) {
270 ++variable.writeCount;
271 }
272
273 bool get hasExactlyOneUse => variable.readCount == 1;
277 274
278 accept(Visitor visitor) => visitor.visitAssign(this); 275 accept(Visitor visitor) => visitor.visitAssign(this);
279 } 276 }
280 277
281 /** 278 /**
282 * A return exit from the function. 279 * A return exit from the function.
283 * 280 *
284 * In contrast to the CPS-based IR, the return value is an arbitrary 281 * In contrast to the CPS-based IR, the return value is an arbitrary
285 * expression. 282 * expression.
286 */ 283 */
287 class Return extends Statement { 284 class Return extends Statement {
288 /// Should not be null. Use [Constant] with [NullConstant] for void returns. 285 /// Should not be null. Use [Constant] with [NullConstant] for void returns.
289 Expression value; 286 Expression value;
290 287
291 Statement get next => null; 288 Statement get next => null;
292 void set next(Statement s) => throw 'UNREACHABLE'; 289 void set next(Statement s) => throw 'UNREACHABLE';
293 290
294 Return(this.value); 291 Return(this.value);
295 292
296 accept(Visitor visitor) => visitor.visitReturn(this); 293 accept(Visitor visitor) => visitor.visitReturn(this);
297 } 294 }
298 295
299 /** 296 /**
300 * A break from an enclosing [LabeledStatement]. The break targets the 297 * A break from an enclosing [LabeledStatement]. The break targets the
301 * labeled statement's successor statement. 298 * labeled statement's successor statement.
302 */ 299 */
303 class Break extends Statement { 300 class Break extends Statement {
304 Label _target; 301 Label target;
305
306 Label get target => _target;
307 void set target(Label newTarget) {
308 ++newTarget.breakCount;
309 --_target.breakCount;
310 _target = newTarget;
311 }
312 302
313 Statement get next => null; 303 Statement get next => null;
314 void set next(Statement s) => throw 'UNREACHABLE'; 304 void set next(Statement s) => throw 'UNREACHABLE';
315 305
316 Break(this._target) { 306 Break(this.target) {
317 ++target.breakCount; 307 ++target.breakCount;
318 } 308 }
319 309
320 accept(Visitor visitor) => visitor.visitBreak(this); 310 accept(Visitor visitor) => visitor.visitBreak(this);
321 } 311 }
322 312
323 /** 313 /**
324 * A continue to an enclosing [While] loop. The continue targets the 314 * A continue to an enclosing [While] loop. The continue targets the
325 * loop's body. 315 * loop's body.
326 */ 316 */
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
437 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree 427 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree
438 * control-flow recognition. 428 * control-flow recognition.
439 * 429 *
440 * Otherwise, the output of Builder looks very much like the input. In 430 * Otherwise, the output of Builder looks very much like the input. In
441 * particular, intermediate values and blocks used for local control flow are 431 * particular, intermediate values and blocks used for local control flow are
442 * still all named. 432 * still all named.
443 */ 433 */
444 class Builder extends ir.Visitor<Node> { 434 class Builder extends ir.Visitor<Node> {
445 final dart2js.Compiler compiler; 435 final dart2js.Compiler compiler;
446 436
447 // Uses of IR primitives are replaced with Tree variables. This is the 437 /// Maps variable/parameter elements to the Tree variables that represent it.
448 // mapping from primitives to variables. 438 final Map<Element, List<Variable>> element2variables =
449 final Map<ir.Primitive, Variable> variables = <ir.Primitive, Variable>{}; 439 <Element,List<Variable>>{};
450 440
451 // Continuations with more than one use are replaced with Tree labels. This 441 // Continuations with more than one use are replaced with Tree labels. This
452 // is the mapping from continuations to labels. 442 // is the mapping from continuations to labels.
453 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{}; 443 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{};
454 444
455 FunctionDefinition function; 445 FunctionDefinition function;
456 ir.Continuation returnContinuation; 446 ir.Continuation returnContinuation;
457 447
458 Builder(this.compiler); 448 Builder(this.compiler);
459 449
450 /// Obtains the variable representing the given primitive. Returns null for
451 /// primitives that have no reference and do not need a variable.
452 Variable getVariable(ir.Primitive primitive) {
453 if (primitive.registerIndex == null) {
454 return null; // variable is unused
455 }
456 List<Variable> variables = element2variables[primitive.element];
457 if (variables == null) {
458 variables = <Variable>[];
459 element2variables[primitive.element] = variables;
460 }
461 while (variables.length <= primitive.registerIndex) {
462 variables.add(new Variable(primitive.element));
463 }
464 return variables[primitive.registerIndex];
465 }
466
467 /// Obtains a reference to the tree Variable corresponding to the IR primitive
468 /// referred to by [reference].
469 /// This increments the reference count for the given variable, so the
470 /// returned expression must be used in the tree.
471 Expression getVariableReference(ir.Reference reference) {
472 Variable variable = getVariable(reference.definition);
473 if (variable == null) {
474 compiler.internalError(
475 compiler.currentElement,
476 "Reference to ${reference.definition} has no register");
477 }
478 ++variable.readCount;
479 return variable;
480 }
481
460 FunctionDefinition build(ir.FunctionDefinition node) { 482 FunctionDefinition build(ir.FunctionDefinition node) {
483 new ir.RegisterAllocator().visit(node);
461 visit(node); 484 visit(node);
462 return function; 485 return function;
463 } 486 }
464 487
465 List<Expression> translateArguments(List<ir.Reference> args) { 488 List<Expression> translateArguments(List<ir.Reference> args) {
466 return new List<Expression>.generate(args.length, 489 return new List<Expression>.generate(args.length,
467 (int index) => variables[args[index].definition]); 490 (int index) => getVariableReference(args[index]));
468 } 491 }
469 492
470 Statement buildParameterAssignments( 493 Statement buildParameterAssignments(
471 List<ir.Parameter> parameters, 494 List<ir.Parameter> parameters,
472 List<Expression> arguments, 495 List<Expression> arguments,
473 Statement buildRest()) { 496 Statement buildRest()) {
474 assert(parameters.length == arguments.length); 497 assert(parameters.length == arguments.length);
475 Statement first, current; 498 Statement first, current;
476 for (int i = 0; i < parameters.length; ++i) { 499 for (int i = 0; i < parameters.length; ++i) {
500 Expression argument = arguments[i];
477 ir.Parameter parameter = parameters[i]; 501 ir.Parameter parameter = parameters[i];
478 Statement assignment; 502 Statement assignment;
479 if (parameter.hasAtLeastOneUse) { 503 Variable variable = getVariable(parameter);
480 assignment = new Assign(variables[parameter], arguments[i], null, 504 if (variable == null || variable == arguments[i]) {
481 parameter.hasExactlyOneUse); 505 if (argument is Variable) {
506 assignment = null; // ignore pure expression
Kevin Millikin (Google) 2014/06/10 11:33:01 => // Ignore pure expression. // Kill unused arg
asgerf 2014/06/10 12:22:23 Done.
507 --argument.readCount; // kill unused argument
508 } else {
509 assignment = new ExpressionStatement(argument, null);
510 }
482 } else { 511 } else {
483 assignment = new ExpressionStatement(arguments[i], null); 512 assignment = new Assign(variable, argument, null);
484 } 513 }
485 514
486 if (first == null) { 515 if (assignment != null) {
487 current = first = assignment; 516 if (first == null) {
488 } else { 517 current = first = assignment;
489 current = current.next = assignment; 518 } else {
519 current = current.next = assignment;
520 }
490 } 521 }
491 } 522 }
492 523
493 if (first == null) { 524 if (first == null) {
494 first = buildRest(); 525 first = buildRest();
495 } else { 526 } else {
496 current.next = buildRest(); 527 current.next = buildRest();
497 } 528 }
498 return first; 529 return first;
499 } 530 }
500 531
501 Expression visitFunctionDefinition(ir.FunctionDefinition node) { 532 Expression visitFunctionDefinition(ir.FunctionDefinition node) {
502 returnContinuation = node.returnContinuation; 533 returnContinuation = node.returnContinuation;
503 List<Variable> parameters = <Variable>[]; 534 List<Variable> parameters = <Variable>[];
504 for (ir.Parameter p in node.parameters) { 535 for (ir.Parameter p in node.parameters) {
505 Variable parameter = new Variable(p.element); 536 Variable parameter = getVariable(p);
537 assert(parameter != null);
506 parameters.add(parameter); 538 parameters.add(parameter);
507 variables[p] = parameter;
508 } 539 }
509 function = new FunctionDefinition(parameters, visit(node.body)); 540 function = new FunctionDefinition(parameters, visit(node.body));
510 return null; 541 return null;
511 } 542 }
512 543
513 Statement visitLetPrim(ir.LetPrim node) { 544 Statement visitLetPrim(ir.LetPrim node) {
514 // LetPrim is translated to LetVal. 545 // LetPrim is translated to Assign.
515 Expression definition = visit(node.primitive); 546 Expression definition = visit(node.primitive);
516 if (node.primitive.hasAtLeastOneUse) { 547 Variable variable = getVariable(node.primitive);
517 Variable variable = new Variable(null); 548 if (variable != null) { // variable is null if primitive is unused
Kevin Millikin (Google) 2014/06/10 11:33:01 ==> // Variable ... unused.
asgerf 2014/06/10 12:22:23 Done.
518 variables[node.primitive] = variable; 549 return new Assign(variable, definition, node.body.accept(this));
Kevin Millikin (Google) 2014/06/10 11:33:01 visit(node.body)
asgerf 2014/06/10 12:22:23 Done.
519 return new Assign(variable, definition, visit(node.body),
520 node.primitive.hasExactlyOneUse);
521 } else if (node.primitive is ir.Constant) { 550 } else if (node.primitive is ir.Constant) {
522 // TODO(kmillikin): Implement more systematic treatment of pure CPS 551 // TODO(kmillikin): Implement more systematic treatment of pure CPS
523 // values (e.g., as part of a shrinking reductions pass). 552 // values (e.g., as part of a shrinking reductions pass).
524 return visit(node.body); 553 return visit(node.body);
525 } else { 554 } else {
526 return new ExpressionStatement(definition, visit(node.body)); 555 return new ExpressionStatement(definition, visit(node.body));
527 } 556 }
528 } 557 }
529 558
530 Statement visitLetCont(ir.LetCont node) { 559 Statement visitLetCont(ir.LetCont node) {
531 Label label; 560 Label label;
532 if (node.continuation.hasMultipleUses) { 561 if (node.continuation.hasMultipleUses) {
533 label = new Label(); 562 label = new Label();
534 labels[node.continuation] = label; 563 labels[node.continuation] = label;
535 } 564 }
536 node.continuation.parameters.forEach((p) {
537 if (p.hasAtLeastOneUse) variables[p] = new Variable(null);
538 });
539 Statement body = visit(node.body); 565 Statement body = visit(node.body);
540 // The continuation's body is not always translated directly here because 566 // The continuation's body is not always translated directly here because
541 // it may have been already translated: 567 // it may have been already translated:
542 // * For singly-used continuations, the continuation's body is 568 // * For singly-used continuations, the continuation's body is
543 // translated at the site of the continuation invocation. 569 // translated at the site of the continuation invocation.
544 // * For recursive continuations, there is a single non-recursive 570 // * For recursive continuations, there is a single non-recursive
545 // invocation. The continuation's body is translated at the site 571 // invocation. The continuation's body is translated at the site
546 // of the non-recursive continuation invocation. 572 // of the non-recursive continuation invocation.
547 // See visitInvokeContinuation for the implementation. 573 // See visitInvokeContinuation for the implementation.
548 if (label == null || node.continuation.isRecursive) return body; 574 if (label == null || node.continuation.isRecursive) return body;
549 return new LabeledStatement(label, body, visit(node.continuation.body)); 575 return new LabeledStatement(label, body, visit(node.continuation.body));
550 } 576 }
551 577
552 Statement visitInvokeStatic(ir.InvokeStatic node) { 578 Statement visitInvokeStatic(ir.InvokeStatic node) {
553 // Calls are translated to direct style. 579 // Calls are translated to direct style.
554 List<Expression> arguments = translateArguments(node.arguments); 580 List<Expression> arguments = translateArguments(node.arguments);
555 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); 581 Expression invoke = new InvokeStatic(node.target, node.selector, arguments);
556 ir.Continuation cont = node.continuation.definition; 582 ir.Continuation cont = node.continuation.definition;
557 if (cont == returnContinuation) { 583 if (cont == returnContinuation) {
558 return new Return(invoke); 584 return new Return(invoke);
559 } else { 585 } else {
560 assert(cont.hasExactlyOneUse); 586 assert(cont.hasExactlyOneUse);
561 assert(cont.parameters.length == 1); 587 assert(cont.parameters.length == 1);
562 return buildParameterAssignments(cont.parameters, [invoke], 588 return buildParameterAssignments(cont.parameters, [invoke],
563 () => visit(cont.body)); 589 () => visit(cont.body));
564 } 590 }
565 } 591 }
566 592
567 Statement visitInvokeMethod(ir.InvokeMethod node) { 593 Statement visitInvokeMethod(ir.InvokeMethod node) {
568 Variable receiver = variables[node.receiver.definition]; 594 Expression receiver = getVariableReference(node.receiver);
569 List<Expression> arguments = translateArguments(node.arguments); 595 List<Expression> arguments = translateArguments(node.arguments);
570 Expression invoke = new InvokeMethod(receiver, node.selector, arguments); 596 Expression invoke = new InvokeMethod(receiver, node.selector, arguments);
571 ir.Continuation cont = node.continuation.definition; 597 ir.Continuation cont = node.continuation.definition;
572 if (cont == returnContinuation) { 598 if (cont == returnContinuation) {
573 return new Return(invoke); 599 return new Return(invoke);
574 } else { 600 } else {
575 assert(cont.hasExactlyOneUse); 601 assert(cont.hasExactlyOneUse);
576 assert(cont.parameters.length == 1); 602 assert(cont.parameters.length == 1);
577 return buildParameterAssignments(cont.parameters, [invoke], 603 return buildParameterAssignments(cont.parameters, [invoke],
578 () => visit(cont.body)); 604 () => visit(cont.body));
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 636
611 Statement visitInvokeContinuation(ir.InvokeContinuation node) { 637 Statement visitInvokeContinuation(ir.InvokeContinuation node) {
612 // Invocations of the return continuation are translated to returns. 638 // Invocations of the return continuation are translated to returns.
613 // Other continuation invocations are replaced with assignments of the 639 // Other continuation invocations are replaced with assignments of the
614 // arguments to formal parameter variables, followed by the body if 640 // arguments to formal parameter variables, followed by the body if
615 // the continuation is singly reference or a break if it is multiply 641 // the continuation is singly reference or a break if it is multiply
616 // referenced. 642 // referenced.
617 ir.Continuation cont = node.continuation.definition; 643 ir.Continuation cont = node.continuation.definition;
618 if (cont == returnContinuation) { 644 if (cont == returnContinuation) {
619 assert(node.arguments.length == 1); 645 assert(node.arguments.length == 1);
620 return new Return(variables[node.arguments[0].definition]); 646 return new Return(getVariableReference(node.arguments[0]));
621 } else { 647 } else {
622 List<Expression> arguments = translateArguments(node.arguments); 648 List<Expression> arguments = translateArguments(node.arguments);
623 return buildParameterAssignments(cont.parameters, arguments, 649 return buildParameterAssignments(cont.parameters, arguments,
624 () { 650 () {
625 // Translate invocations of recursive and non-recursive 651 // Translate invocations of recursive and non-recursive
626 // continuations differently. 652 // continuations differently.
627 // * Non-recursive continuations 653 // * Non-recursive continuations
628 // - If there is one use, translate the continuation body 654 // - If there is one use, translate the continuation body
629 // inline at the invocation site. 655 // inline at the invocation site.
630 // - If there are multiple uses, translate to Break. 656 // - If there are multiple uses, translate to Break.
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 } 713 }
688 714
689 Expression visitContinuation(ir.Continuation node) { 715 Expression visitContinuation(ir.Continuation node) {
690 // Until continuations with multiple uses are supported, they are not 716 // Until continuations with multiple uses are supported, they are not
691 // visited. 717 // visited.
692 compiler.internalError(compiler.currentElement, 'Unexpected IR node.'); 718 compiler.internalError(compiler.currentElement, 'Unexpected IR node.');
693 return null; 719 return null;
694 } 720 }
695 721
696 Expression visitIsTrue(ir.IsTrue node) { 722 Expression visitIsTrue(ir.IsTrue node) {
697 return variables[node.value.definition]; 723 return getVariableReference(node.value);
698 } 724 }
699 } 725 }
700 726
701 /** 727 /**
702 * Performs the following transformations on the tree: 728 * Performs the following transformations on the tree:
703 * - Assignment propagation 729 * - Assignment propagation
704 * - If-to-conditional conversion 730 * - If-to-conditional conversion
705 * - Flatten nested ifs 731 * - Flatten nested ifs
706 * - Break inlining 732 * - Break inlining
707 * - Redirect breaks 733 * - Redirect breaks
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
933 959
934 Statement visitLabeledStatement(LabeledStatement node) { 960 Statement visitLabeledStatement(LabeledStatement node) {
935 if (node.next is Break) { 961 if (node.next is Break) {
936 // Eliminate label if next is just a break statement 962 // Eliminate label if next is just a break statement
937 // Breaks to this label are redirected to the outer label. 963 // Breaks to this label are redirected to the outer label.
938 // Note that breakCount for the two labels is updated proactively here 964 // Note that breakCount for the two labels is updated proactively here
939 // so breaks can reliably tell if they should inline their target. 965 // so breaks can reliably tell if they should inline their target.
940 Break next = node.next; 966 Break next = node.next;
941 Label newTarget = redirect(next.target); 967 Label newTarget = redirect(next.target);
942 labelRedirects[node.label] = newTarget; 968 labelRedirects[node.label] = newTarget;
943 newTarget.breakCount += node.label.breakCount; 969 newTarget.breakCount += node.label.breakCount - 1;
944 node.label.breakCount = 0; 970 node.label.breakCount = 0;
945 Statement result = visitStatement(node.body); 971 Statement result = visitStatement(node.body);
946 labelRedirects.remove(node.label); // Save some space. 972 labelRedirects.remove(node.label); // Save some space.
947 return result; 973 return result;
948 } 974 }
949 975
950 node.body = visitStatement(node.body); 976 node.body = visitStatement(node.body);
951 977
952 if (node.label.breakCount == 0) { 978 if (node.label.breakCount == 0) {
953 // Eliminate the label if next was inlined at a break 979 // Eliminate the label if next was inlined at a break
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1058 static Statement combineStatementsWithSubexpressions( 1084 static Statement combineStatementsWithSubexpressions(
1059 Statement s, 1085 Statement s,
1060 Statement t, 1086 Statement t,
1061 Expression combine(Expression s, Expression t)) { 1087 Expression combine(Expression s, Expression t)) {
1062 if (s is Return && t is Return) { 1088 if (s is Return && t is Return) {
1063 return new Return(combine(s.value, t.value)); 1089 return new Return(combine(s.value, t.value));
1064 } 1090 }
1065 if (s is Assign && t is Assign && s.variable == t.variable) { 1091 if (s is Assign && t is Assign && s.variable == t.variable) {
1066 Statement next = combineStatements(s.next, t.next); 1092 Statement next = combineStatements(s.next, t.next);
1067 if (next != null) { 1093 if (next != null) {
1094 --t.variable.writeCount; // Two assignments become one
1068 return new Assign(s.variable, 1095 return new Assign(s.variable,
1069 combine(s.definition, t.definition), 1096 combine(s.definition, t.definition),
1070 next, 1097 next);
1071 s.hasExactlyOneUse);
1072 } 1098 }
1073 } 1099 }
1074 if (s is ExpressionStatement && t is ExpressionStatement) { 1100 if (s is ExpressionStatement && t is ExpressionStatement) {
1075 Statement next = combineStatements(s.next, t.next); 1101 Statement next = combineStatements(s.next, t.next);
1076 if (next != null) { 1102 if (next != null) {
1077 return new ExpressionStatement(combine(s.expression, t.expression), 1103 return new ExpressionStatement(combine(s.expression, t.expression),
1078 next); 1104 next);
1079 } 1105 }
1080 } 1106 }
1081 return null; 1107 return null;
1082 } 1108 }
1083 1109
1084 /// Returns a statement equivalent to both [s] and [t], or null if [s] and 1110 /// Returns a statement equivalent to both [s] and [t], or null if [s] and
1085 /// [t] are incompatible. 1111 /// [t] are incompatible.
1086 /// If non-null is returned, the caller MUST discard [s] and [t] and use 1112 /// If non-null is returned, the caller MUST discard [s] and [t] and use
1087 /// the returned statement instead. 1113 /// the returned statement instead.
1088 /// If two breaks are combined, the label's break counter will be decremented. 1114 /// If two breaks are combined, the label's break counter will be decremented.
1089 static Statement combineStatements(Statement s, Statement t) { 1115 static Statement combineStatements(Statement s, Statement t) {
1090 if (s is Break && t is Break && s.target == t.target) { 1116 if (s is Break && t is Break && s.target == t.target) {
1091 --t.target.breakCount; // Two breaks become one. 1117 --t.target.breakCount; // Two breaks become one.
1092 return s; 1118 return s;
1093 } 1119 }
1094 if (s is Return && t is Return && equivalentExpressions(s.value, t.value)) { 1120 if (s is Return && t is Return) {
1095 return s; 1121 Expression e = combineExpressions(s.value, t.value);
1122 if (e != null) {
1123 return new Return(e);
1124 }
1096 } 1125 }
1097 return null; 1126 return null;
1098 } 1127 }
1099 1128
1100 /// True if the two expressions both syntactically and semantically 1129 /// Returns an expression equivalent to both [e1] and [e2].
1101 /// equivalent. 1130 /// If non-null is returned, the caller must discard [e1] and [e2] and use
1102 static bool equivalentExpressions(Expression e1, Expression e2) { 1131 /// the resulting expression in the tree.
1103 if (e1 == e2) { // Detect same variable reference 1132 static Expression combineExpressions(Expression e1, Expression e2) {
1104 // TODO(asgerf): This might turn the variable into a single-use, 1133 if (e1 is Variable && e1 == e2) {
1105 // but we currently don't discover this. 1134 --e1.readCount; // Two references become one.
1106 return true; 1135 return e1;
1107 } 1136 }
1108 if (e1 is Constant && e2 is Constant) { 1137 if (e1 is Constant && e2 is Constant && e1.value == e2.value) {
1109 return e1.value == e2.value; 1138 return e1;
1110 } 1139 }
1111 return false; 1140 return null;
1112 } 1141 }
1113 1142
1114 /// Try to collapse nested ifs using && and || expressions. 1143 /// Try to collapse nested ifs using && and || expressions.
1115 /// For example: 1144 /// For example:
1116 /// 1145 ///
1117 /// if (E1) { if (E2) S else break L } else break L 1146 /// if (E1) { if (E2) S else break L } else break L
1118 /// ==> 1147 /// ==>
1119 /// if (E1 && E2) S else break L 1148 /// if (E1 && E2) S else break L
1120 /// 1149 ///
1121 /// [branch1] and [branch2] control the position of the S statement. 1150 /// [branch1] and [branch2] control the position of the S statement.
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after
1602 } 1631 }
1603 } 1632 }
1604 1633
1605 /// Destructively updates each entry of [l] with the result of visiting it. 1634 /// Destructively updates each entry of [l] with the result of visiting it.
1606 void _rewriteList(List<Expression> l) { 1635 void _rewriteList(List<Expression> l) {
1607 for (int i = 0; i < l.length; i++) { 1636 for (int i = 0; i < l.length; i++) {
1608 l[i] = visitExpression(l[i]); 1637 l[i] = visitExpression(l[i]);
1609 } 1638 }
1610 } 1639 }
1611 } 1640 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698