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

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: 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 element;
87 // function emitted. 87 int index;
sigurdm 2014/06/04 07:51:56 Maybe have a comment explaining what the index ind
asgerf 2014/06/04 09:40:51 It was an akward field to have in the first place,
88 static int counter = 0;
89 static String _newName() => 'v${counter++}';
90 88
91 Element element; 89 int readCount = 0;
92 String cachedName; 90 int writeCount = 0;
93 91
94 String get name { 92 Variable(this.element, this.index);
95 if (cachedName != null) return cachedName;
96 return cachedName = ((element == null) ? _newName() : element.name);
97 }
98
99 Variable(this.element);
100 93
101 accept(Visitor visitor) => visitor.visitVariable(this); 94 accept(Visitor visitor) => visitor.visitVariable(this);
102 } 95 }
103 96
104 /** 97 /**
105 * Common interface for invocations with arguments. 98 * Common interface for invocations with arguments.
106 */ 99 */
107 abstract class Invoke { 100 abstract class Invoke {
108 List<Expression> get arguments; 101 List<Expression> get arguments;
109 Selector get selector; 102 Selector get selector;
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 /** 244 /**
252 * An assignments of an [Expression] to a [Variable]. 245 * An assignments of an [Expression] to a [Variable].
253 * 246 *
254 * In contrast to the CPS-based IR, non-primitive expressions can be assigned 247 * In contrast to the CPS-based IR, non-primitive expressions can be assigned
255 * to variables. 248 * to variables.
256 */ 249 */
257 class Assign extends Statement { 250 class Assign extends Statement {
258 Statement next; 251 Statement next;
259 final Variable variable; 252 final Variable variable;
260 Expression definition; 253 Expression definition;
261 final bool hasExactlyOneUse;
262 254
263 Assign(this.variable, this.definition, this.next, this.hasExactlyOneUse); 255 Assign(this.variable, this.definition, this.next) {
256 ++variable.writeCount;
257 }
258
259 bool get hasExactlyOneUse => variable.readCount == 1;
264 260
265 accept(Visitor visitor) => visitor.visitAssign(this); 261 accept(Visitor visitor) => visitor.visitAssign(this);
266 } 262 }
267 263
268 /** 264 /**
269 * A return exit from the function. 265 * A return exit from the function.
270 * 266 *
271 * In contrast to the CPS-based IR, the return value is an arbitrary 267 * In contrast to the CPS-based IR, the return value is an arbitrary
272 * expression. 268 * expression.
273 */ 269 */
274 class Return extends Statement { 270 class Return extends Statement {
275 /// Should not be null. Use [Constant] with [NullConstant] for void returns. 271 /// Should not be null. Use [Constant] with [NullConstant] for void returns.
276 Expression value; 272 Expression value;
277 273
278 Statement get next => null; 274 Statement get next => null;
279 void set next(Statement s) => throw 'UNREACHABLE'; 275 void set next(Statement s) => throw 'UNREACHABLE';
280 276
281 Return(this.value); 277 Return(this.value);
282 278
283 accept(Visitor visitor) => visitor.visitReturn(this); 279 accept(Visitor visitor) => visitor.visitReturn(this);
284 } 280 }
285 281
286 /** 282 /**
287 * A break from an enclosing [LabeledStatement]. The break targets the 283 * A break from an enclosing [LabeledStatement]. The break targets the
288 * labeled statement's successor statement. 284 * labeled statement's successor statement.
289 */ 285 */
290 class Break extends Statement { 286 class Break extends Statement {
291 Label _target; 287 Label target;
292
293 Label get target => _target;
294 void set target(Label newTarget) {
295 ++newTarget.breakCount;
296 --_target.breakCount;
297 _target = newTarget;
298 }
299 288
300 Statement get next => null; 289 Statement get next => null;
301 void set next(Statement s) => throw 'UNREACHABLE'; 290 void set next(Statement s) => throw 'UNREACHABLE';
302 291
303 Break(this._target) { 292 Break(this.target) {
304 ++target.breakCount; 293 ++target.breakCount;
305 } 294 }
306 295
307 accept(Visitor visitor) => visitor.visitBreak(this); 296 accept(Visitor visitor) => visitor.visitBreak(this);
308 } 297 }
309 298
310 /** 299 /**
311 * A continue to an enclosing [While] loop. The continue targets the 300 * A continue to an enclosing [While] loop. The continue targets the
312 * loop's body. 301 * loop's body.
313 */ 302 */
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree 412 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree
424 * control-flow recognition. 413 * control-flow recognition.
425 * 414 *
426 * Otherwise, the output of Builder looks very much like the input. In 415 * Otherwise, the output of Builder looks very much like the input. In
427 * particular, intermediate values and blocks used for local control flow are 416 * particular, intermediate values and blocks used for local control flow are
428 * still all named. 417 * still all named.
429 */ 418 */
430 class Builder extends ir.Visitor<Node> { 419 class Builder extends ir.Visitor<Node> {
431 final dart2js.Compiler compiler; 420 final dart2js.Compiler compiler;
432 421
433 // Uses of IR primitives are replaced with Tree variables. This is the 422 /// Maps variable/parameter elements to the Tree variables that represent it.
434 // mapping from primitives to variables. 423 final Map<Element, List<Variable>> element2variables = <Element,List>{};
sigurdm 2014/06/04 07:51:56 Is there a reason not to use <Element, List<Variab
asgerf 2014/06/04 09:40:51 No, fixed it.
435 final Map<ir.Primitive, Variable> variables = <ir.Primitive, Variable>{};
436 424
437 // Continuations with more than one use are replaced with Tree labels. This 425 // Continuations with more than one use are replaced with Tree labels. This
438 // is the mapping from continuations to labels. 426 // is the mapping from continuations to labels.
439 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{}; 427 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{};
440 428
441 FunctionDefinition function; 429 FunctionDefinition function;
442 ir.Continuation returnContinuation; 430 ir.Continuation returnContinuation;
443 431
444 Builder(this.compiler); 432 Builder(this.compiler);
445 433
434 /// Obtains the variable representing the given primitive. Returns null for
435 /// primitives that have no reference and do not need a variable.
436 Variable getVariable(ir.Primitive primitive) {
437 if (primitive.registerIndex == null) {
438 return null; // variable is unused
439 }
440 List<Variable> variables = element2variables[primitive.element];
441 if (variables == null) {
442 variables = <Variable>[];
443 element2variables[primitive.element] = variables;
444 }
445 while (variables.length <= primitive.registerIndex) {
446 variables.add(new Variable(primitive.element, variables.length));
447 }
448 return variables[primitive.registerIndex];
449 }
450
451 /// Obtains a reference to the tree Variable corresponding to the IR primitive
452 /// referred to by [reference].
453 /// This increments the reference count for the given variable, so the
454 /// returned expression must be used in the tree.
455 Expression getVariableReference(ir.Reference reference) {
456 Variable variable = getVariable(reference.definition);
457 if (variable == null) {
458 compiler.internalError(
459 compiler.currentElement,
460 "Reference to ${reference.definition} has no register");
461 }
462 ++variable.readCount;
463 return variable;
464 }
465
446 FunctionDefinition build(ir.FunctionDefinition node) { 466 FunctionDefinition build(ir.FunctionDefinition node) {
467 new ir.RegisterAllocator().visit(node);
447 visit(node); 468 visit(node);
448 return function; 469 return function;
449 } 470 }
450 471
451 List<Expression> translateArguments(List<ir.Reference> args) { 472 List<Expression> translateArguments(List<ir.Reference> args) {
452 return new List<Expression>.generate(args.length, 473 return new List<Expression>.generate(args.length,
453 (int index) => variables[args[index].definition]); 474 (int index) => getVariableReference(args[index]));
454 } 475 }
455 476
456 Statement buildParameterAssignments( 477 Statement buildParameterAssignments(
457 List<ir.Parameter> parameters, 478 List<ir.Parameter> parameters,
458 List<Expression> arguments, 479 List<Expression> arguments,
459 Statement buildRest()) { 480 Statement buildRest()) {
460 assert(parameters.length == arguments.length); 481 assert(parameters.length == arguments.length);
461 Statement first, current; 482 Statement first, current;
462 for (int i = 0; i < parameters.length; ++i) { 483 for (int i = 0; i < parameters.length; ++i) {
484 Expression argument = arguments[i];
463 ir.Parameter parameter = parameters[i]; 485 ir.Parameter parameter = parameters[i];
464 Statement assignment; 486 Statement assignment;
465 if (parameter.hasAtLeastOneUse) { 487 Variable variable = getVariable(parameter);
466 assignment = new Assign(variables[parameter], arguments[i], null, 488 if (variable == null || variable == arguments[i]) {
467 parameter.hasExactlyOneUse); 489 if (argument is Variable) {
490 assignment = null; // ignore pure expression
491 --argument.readCount; // kill unused argument
492 } else {
493 assignment = new ExpressionStatement(argument, null);
494 }
468 } else { 495 } else {
469 assignment = new ExpressionStatement(arguments[i], null); 496 assignment = new Assign(variable, argument, null);
470 } 497 }
471 498
472 if (first == null) { 499 if (assignment != null) {
473 current = first = assignment; 500 if (first == null) {
474 } else { 501 current = first = assignment;
475 current = current.next = assignment; 502 } else {
503 current = current.next = assignment;
504 }
476 } 505 }
477 } 506 }
478 507
479 if (first == null) { 508 if (first == null) {
480 first = buildRest(); 509 first = buildRest();
481 } else { 510 } else {
482 current.next = buildRest(); 511 current.next = buildRest();
483 } 512 }
484 return first; 513 return first;
485 } 514 }
486 515
487 Expression visitFunctionDefinition(ir.FunctionDefinition node) { 516 Expression visitFunctionDefinition(ir.FunctionDefinition node) {
488 returnContinuation = node.returnContinuation; 517 returnContinuation = node.returnContinuation;
489 List<Variable> parameters = <Variable>[]; 518 List<Variable> parameters = <Variable>[];
490 for (ir.Parameter p in node.parameters) { 519 for (ir.Parameter p in node.parameters) {
491 Variable parameter = new Variable(p.element); 520 Variable parameter = getVariable(p);
521 assert(parameter != null);
492 parameters.add(parameter); 522 parameters.add(parameter);
493 variables[p] = parameter;
494 } 523 }
495 function = new FunctionDefinition(parameters, visit(node.body)); 524 function = new FunctionDefinition(parameters, visit(node.body));
496 return null; 525 return null;
497 } 526 }
498 527
499 Statement visitLetPrim(ir.LetPrim node) { 528 Statement visitLetPrim(ir.LetPrim node) {
500 // LetPrim is translated to LetVal. 529 // LetPrim is translated to Assign.
501 Expression definition = visit(node.primitive); 530 Expression definition = visit(node.primitive);
502 if (node.primitive.hasAtLeastOneUse) { 531 Variable variable = getVariable(node.primitive);
503 Variable variable = new Variable(null); 532 if (variable != null) { // variable is null if primitive is unused
504 variables[node.primitive] = variable; 533 return new Assign(variable, definition, node.body.accept(this));
505 return new Assign(variable, definition, visit(node.body),
506 node.primitive.hasExactlyOneUse);
507 } else if (node.primitive is ir.Constant) { 534 } else if (node.primitive is ir.Constant) {
508 // TODO(kmillikin): Implement more systematic treatment of pure CPS 535 // TODO(kmillikin): Implement more systematic treatment of pure CPS
509 // values (e.g., as part of a shrinking reductions pass). 536 // values (e.g., as part of a shrinking reductions pass).
510 return visit(node.body); 537 return visit(node.body);
511 } else { 538 } else {
512 return new ExpressionStatement(definition, visit(node.body)); 539 return new ExpressionStatement(definition, visit(node.body));
513 } 540 }
514 } 541 }
515 542
516 Statement visitLetCont(ir.LetCont node) { 543 Statement visitLetCont(ir.LetCont node) {
517 Label label; 544 Label label;
518 if (node.continuation.hasMultipleUses) { 545 if (node.continuation.hasMultipleUses) {
519 label = new Label(); 546 label = new Label();
520 labels[node.continuation] = label; 547 labels[node.continuation] = label;
521 } 548 }
522 node.continuation.parameters.forEach((p) {
523 if (p.hasAtLeastOneUse) variables[p] = new Variable(null);
524 });
525 Statement body = visit(node.body); 549 Statement body = visit(node.body);
526 // The continuation's body is not always translated directly here because 550 // The continuation's body is not always translated directly here because
527 // it may have been already translated: 551 // it may have been already translated:
528 // * For singly-used continuations, the continuation's body is 552 // * For singly-used continuations, the continuation's body is
529 // translated at the site of the continuation invocation. 553 // translated at the site of the continuation invocation.
530 // * For recursive continuations, there is a single non-recursive 554 // * For recursive continuations, there is a single non-recursive
531 // invocation. The continuation's body is translated at the site 555 // invocation. The continuation's body is translated at the site
532 // of the non-recursive continuation invocation. 556 // of the non-recursive continuation invocation.
533 // See visitInvokeContinuation for the implementation. 557 // See visitInvokeContinuation for the implementation.
534 if (label == null || node.continuation.isRecursive) return body; 558 if (label == null || node.continuation.isRecursive) return body;
535 return new LabeledStatement(label, body, visit(node.continuation.body)); 559 return new LabeledStatement(label, body, visit(node.continuation.body));
536 } 560 }
537 561
538 Statement visitInvokeStatic(ir.InvokeStatic node) { 562 Statement visitInvokeStatic(ir.InvokeStatic node) {
539 // Calls are translated to direct style. 563 // Calls are translated to direct style.
540 List<Expression> arguments = translateArguments(node.arguments); 564 List<Expression> arguments = translateArguments(node.arguments);
541 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); 565 Expression invoke = new InvokeStatic(node.target, node.selector, arguments);
542 ir.Continuation cont = node.continuation.definition; 566 ir.Continuation cont = node.continuation.definition;
543 if (cont == returnContinuation) { 567 if (cont == returnContinuation) {
544 return new Return(invoke); 568 return new Return(invoke);
545 } else { 569 } else {
546 assert(cont.hasExactlyOneUse); 570 assert(cont.hasExactlyOneUse);
547 assert(cont.parameters.length == 1); 571 assert(cont.parameters.length == 1);
548 return buildParameterAssignments(cont.parameters, [invoke], 572 return buildParameterAssignments(cont.parameters, [invoke],
549 () => visit(cont.body)); 573 () => visit(cont.body));
550 } 574 }
551 } 575 }
552 576
553 Statement visitInvokeMethod(ir.InvokeMethod node) { 577 Statement visitInvokeMethod(ir.InvokeMethod node) {
554 Variable receiver = variables[node.receiver.definition]; 578 Expression receiver = getVariableReference(node.receiver);
555 List<Expression> arguments = translateArguments(node.arguments); 579 List<Expression> arguments = translateArguments(node.arguments);
556 Expression invoke = new InvokeMethod(receiver, node.selector, arguments); 580 Expression invoke = new InvokeMethod(receiver, node.selector, arguments);
557 ir.Continuation cont = node.continuation.definition; 581 ir.Continuation cont = node.continuation.definition;
558 if (cont == returnContinuation) { 582 if (cont == returnContinuation) {
559 return new Return(invoke); 583 return new Return(invoke);
560 } else { 584 } else {
561 assert(cont.hasExactlyOneUse); 585 assert(cont.hasExactlyOneUse);
562 assert(cont.parameters.length == 1); 586 assert(cont.parameters.length == 1);
563 return buildParameterAssignments(cont.parameters, [invoke], 587 return buildParameterAssignments(cont.parameters, [invoke],
564 () => visit(cont.body)); 588 () => visit(cont.body));
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 620
597 Statement visitInvokeContinuation(ir.InvokeContinuation node) { 621 Statement visitInvokeContinuation(ir.InvokeContinuation node) {
598 // Invocations of the return continuation are translated to returns. 622 // Invocations of the return continuation are translated to returns.
599 // Other continuation invocations are replaced with assignments of the 623 // Other continuation invocations are replaced with assignments of the
600 // arguments to formal parameter variables, followed by the body if 624 // arguments to formal parameter variables, followed by the body if
601 // the continuation is singly reference or a break if it is multiply 625 // the continuation is singly reference or a break if it is multiply
602 // referenced. 626 // referenced.
603 ir.Continuation cont = node.continuation.definition; 627 ir.Continuation cont = node.continuation.definition;
604 if (cont == returnContinuation) { 628 if (cont == returnContinuation) {
605 assert(node.arguments.length == 1); 629 assert(node.arguments.length == 1);
606 return new Return(variables[node.arguments[0].definition]); 630 return new Return(getVariableReference(node.arguments[0]));
607 } else { 631 } else {
608 List<Expression> arguments = translateArguments(node.arguments); 632 List<Expression> arguments = translateArguments(node.arguments);
609 return buildParameterAssignments(cont.parameters, arguments, 633 return buildParameterAssignments(cont.parameters, arguments,
610 () { 634 () {
611 // Translate invocations of recursive and non-recursive 635 // Translate invocations of recursive and non-recursive
612 // continuations differently. 636 // continuations differently.
613 // * Non-recursive continuations 637 // * Non-recursive continuations
614 // - If there is one use, translate the continuation body 638 // - If there is one use, translate the continuation body
615 // inline at the invocation site. 639 // inline at the invocation site.
616 // - If there are multiple uses, translate to Break. 640 // - If there are multiple uses, translate to Break.
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 } 692 }
669 693
670 Expression visitContinuation(ir.Continuation node) { 694 Expression visitContinuation(ir.Continuation node) {
671 // Until continuations with multiple uses are supported, they are not 695 // Until continuations with multiple uses are supported, they are not
672 // visited. 696 // visited.
673 compiler.internalError(compiler.currentElement, 'Unexpected IR node.'); 697 compiler.internalError(compiler.currentElement, 'Unexpected IR node.');
674 return null; 698 return null;
675 } 699 }
676 700
677 Expression visitIsTrue(ir.IsTrue node) { 701 Expression visitIsTrue(ir.IsTrue node) {
678 return variables[node.value.definition]; 702 return getVariableReference(node.value);
679 } 703 }
680 } 704 }
681 705
682 /** 706 /**
683 * Performs the following transformations on the tree: 707 * Performs the following transformations on the tree:
684 * - Assignment propagation 708 * - Assignment propagation
685 * - If-to-conditional conversion 709 * - If-to-conditional conversion
686 * - Flatten nested ifs 710 * - Flatten nested ifs
687 * - Break inlining 711 * - Break inlining
688 * - Redirect breaks 712 * - Redirect breaks
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after
907 931
908 Statement visitLabeledStatement(LabeledStatement node) { 932 Statement visitLabeledStatement(LabeledStatement node) {
909 if (node.next is Break) { 933 if (node.next is Break) {
910 // Eliminate label if next is just a break statement 934 // Eliminate label if next is just a break statement
911 // Breaks to this label are redirected to the outer label. 935 // Breaks to this label are redirected to the outer label.
912 // Note that breakCount for the two labels is updated proactively here 936 // Note that breakCount for the two labels is updated proactively here
913 // so breaks can reliably tell if they should inline their target. 937 // so breaks can reliably tell if they should inline their target.
914 Break next = node.next; 938 Break next = node.next;
915 Label newTarget = redirect(next.target); 939 Label newTarget = redirect(next.target);
916 labelRedirects[node.label] = newTarget; 940 labelRedirects[node.label] = newTarget;
917 newTarget.breakCount += node.label.breakCount; 941 newTarget.breakCount += node.label.breakCount - 1;
918 node.label.breakCount = 0; 942 node.label.breakCount = 0;
919 Statement result = visitStatement(node.body); 943 Statement result = visitStatement(node.body);
920 labelRedirects.remove(node.label); // Save some space. 944 labelRedirects.remove(node.label); // Save some space.
921 return result; 945 return result;
922 } 946 }
923 947
924 node.body = visitStatement(node.body); 948 node.body = visitStatement(node.body);
925 949
926 if (node.label.breakCount == 0) { 950 if (node.label.breakCount == 0) {
927 // Eliminate the label if next was inlined at a break 951 // Eliminate the label if next was inlined at a break
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1032 static Statement combineStatementsWithSubexpressions( 1056 static Statement combineStatementsWithSubexpressions(
1033 Statement s, 1057 Statement s,
1034 Statement t, 1058 Statement t,
1035 Expression combine(Expression s, Expression t)) { 1059 Expression combine(Expression s, Expression t)) {
1036 if (s is Return && t is Return) { 1060 if (s is Return && t is Return) {
1037 return new Return(combine(s.value, t.value)); 1061 return new Return(combine(s.value, t.value));
1038 } 1062 }
1039 if (s is Assign && t is Assign && s.variable == t.variable) { 1063 if (s is Assign && t is Assign && s.variable == t.variable) {
1040 Statement next = combineStatements(s.next, t.next); 1064 Statement next = combineStatements(s.next, t.next);
1041 if (next != null) { 1065 if (next != null) {
1066 --t.variable.writeCount; // Two assignments become one
1042 return new Assign(s.variable, 1067 return new Assign(s.variable,
1043 combine(s.definition, t.definition), 1068 combine(s.definition, t.definition),
1044 next, 1069 next);
1045 s.hasExactlyOneUse);
1046 } 1070 }
1047 } 1071 }
1048 if (s is ExpressionStatement && t is ExpressionStatement) { 1072 if (s is ExpressionStatement && t is ExpressionStatement) {
1049 Statement next = combineStatements(s.next, t.next); 1073 Statement next = combineStatements(s.next, t.next);
1050 if (next != null) { 1074 if (next != null) {
1051 return new ExpressionStatement(combine(s.expression, t.expression), 1075 return new ExpressionStatement(combine(s.expression, t.expression),
1052 next); 1076 next);
1053 } 1077 }
1054 } 1078 }
1055 return null; 1079 return null;
1056 } 1080 }
1057 1081
1058 /// Returns a statement equivalent to both [s] and [t], or null if [s] and 1082 /// Returns a statement equivalent to both [s] and [t], or null if [s] and
1059 /// [t] are incompatible. 1083 /// [t] are incompatible.
1060 /// If non-null is returned, the caller MUST discard [s] and [t] and use 1084 /// If non-null is returned, the caller MUST discard [s] and [t] and use
1061 /// the returned statement instead. 1085 /// the returned statement instead.
1062 /// If two breaks are combined, the label's break counter will be decremented. 1086 /// If two breaks are combined, the label's break counter will be decremented.
1063 static Statement combineStatements(Statement s, Statement t) { 1087 static Statement combineStatements(Statement s, Statement t) {
1064 if (s is Break && t is Break && s.target == t.target) { 1088 if (s is Break && t is Break && s.target == t.target) {
1065 --t.target.breakCount; // Two breaks become one. 1089 --t.target.breakCount; // Two breaks become one.
1066 return s; 1090 return s;
1067 } 1091 }
1068 if (s is Return && t is Return && equivalentExpressions(s.value, t.value)) { 1092 if (s is Return && t is Return) {
1069 return s; 1093 Expression e = combineExpressions(s.value, t.value);
1094 if (e != null) {
1095 return new Return(e);
1096 }
1070 } 1097 }
1071 return null; 1098 return null;
1072 } 1099 }
1073 1100
1074 /// True if the two expressions both syntactically and semantically 1101 /// Returns an expression equivalent to both [e1] and [e2].
1075 /// equivalent. 1102 /// If non-null is returned, the caller must discard [e1] and [e2] and use
1076 static bool equivalentExpressions(Expression e1, Expression e2) { 1103 /// the resulting expression in the tree.
1077 if (e1 == e2) { // Detect same variable reference 1104 static Expression combineExpressions(Expression e1, Expression e2) {
1078 // TODO(asgerf): This might turn the variable into a single-use, 1105 if (e1 is Variable && e1 == e2) {
1079 // but we currently don't discover this. 1106 --e1.readCount; // Two references become one.
1080 return true; 1107 return e1;
1081 } 1108 }
1082 if (e1 is Constant && e2 is Constant) { 1109 if (e1 is Constant && e2 is Constant && e1.value == e2.value) {
1083 return e1.value == e2.value; 1110 return e1;
1084 } 1111 }
1085 return false; 1112 return null;
1086 } 1113 }
1087 1114
1088 /// Try to collapse nested ifs using && and || expressions. 1115 /// Try to collapse nested ifs using && and || expressions.
1089 /// For example: 1116 /// For example:
1090 /// 1117 ///
1091 /// if (E1) { if (E2) S else break L } else break L 1118 /// if (E1) { if (E2) S else break L } else break L
1092 /// ==> 1119 /// ==>
1093 /// if (E1 && E2) S else break L 1120 /// if (E1 && E2) S else break L
1094 /// 1121 ///
1095 /// [branch1] and [branch2] control the position of the S statement. 1122 /// [branch1] and [branch2] control the position of the S statement.
(...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after
1571 } 1598 }
1572 } 1599 }
1573 1600
1574 /// Destructively updates each entry of [l] with the result of visiting it. 1601 /// Destructively updates each entry of [l] with the result of visiting it.
1575 void _rewriteList(List<Expression> l) { 1602 void _rewriteList(List<Expression> l) {
1576 for (int i = 0; i < l.length; i++) { 1603 for (int i = 0; i < l.length; i++) {
1577 l[i] = visitExpression(l[i]); 1604 l[i] = visitExpression(l[i]);
1578 } 1605 }
1579 } 1606 }
1580 } 1607 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698