Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart_tree; | 5 library dart_tree; |
| 6 | 6 |
| 7 import '../dart2jslib.dart' as dart2js; | 7 import '../dart2jslib.dart' as dart2js; |
| 8 import '../elements/elements.dart' | 8 import '../elements/elements.dart' |
| 9 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |