Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 dart2js.ir_builder; | 5 library dart2js.ir_builder; |
| 6 | 6 |
| 7 import '../constants/expressions.dart'; | 7 import '../constants/expressions.dart'; |
| 8 import '../constants/values.dart' show PrimitiveConstantValue; | 8 import '../constants/values.dart' show PrimitiveConstantValue; |
| 9 import '../dart_backend/dart_backend.dart' show DartBackend; | 9 import '../dart_backend/dart_backend.dart' show DartBackend; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| (...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 488 Iterable<JumpCollector> collectors) { | 488 Iterable<JumpCollector> collectors) { |
| 489 assert(isOpen); | 489 assert(isOpen); |
| 490 for (JumpCollector collector in collectors) { | 490 for (JumpCollector collector in collectors) { |
| 491 if (target == collector.target) { | 491 if (target == collector.target) { |
| 492 collector.addJump(this); | 492 collector.addJump(this); |
| 493 return true; | 493 return true; |
| 494 } | 494 } |
| 495 } | 495 } |
| 496 return false; | 496 return false; |
| 497 } | 497 } |
| 498 | |
|
Johnni Winther
2014/10/17 11:37:40
These are moved/adapted from IrBuilderVisitor.
| |
| 499 /// Create a negation of [condition]. | |
| 500 ir.Primitive buildNegation(ir.Primitive condition) { | |
| 501 // ! e is translated as e ? false : true | |
| 502 | |
| 503 // Add a continuation parameter for the result of the expression. | |
| 504 ir.Parameter resultParameter = new ir.Parameter(null); | |
| 505 | |
| 506 ir.Continuation joinContinuation = new ir.Continuation([resultParameter]); | |
| 507 ir.Continuation thenContinuation = new ir.Continuation([]); | |
| 508 ir.Continuation elseContinuation = new ir.Continuation([]); | |
| 509 | |
| 510 ir.Constant trueConstant = | |
| 511 makePrimConst(state.constantSystem.createBool(true)); | |
| 512 ir.Constant falseConstant = | |
| 513 makePrimConst(state.constantSystem.createBool(false)); | |
| 514 | |
| 515 thenContinuation.body = new ir.LetPrim(falseConstant) | |
| 516 ..plug(new ir.InvokeContinuation(joinContinuation, [falseConstant])); | |
| 517 elseContinuation.body = new ir.LetPrim(trueConstant) | |
| 518 ..plug(new ir.InvokeContinuation(joinContinuation, [trueConstant])); | |
| 519 | |
| 520 add(new ir.LetCont(joinContinuation, | |
| 521 new ir.LetCont(thenContinuation, | |
| 522 new ir.LetCont(elseContinuation, | |
| 523 new ir.Branch(new ir.IsTrue(condition), | |
| 524 thenContinuation, | |
| 525 elseContinuation))))); | |
| 526 return resultParameter; | |
| 527 } | |
| 528 | |
| 529 /// Create a lazy and/or expression. [leftValue] is the value of the left | |
| 530 /// operand and [buildRightValue] is called to process the value of the right | |
| 531 /// operand in the context of its own [IrBuilder]. | |
| 532 ir.Primitive buildLogicalOperator( | |
| 533 ir.Primitive leftValue, | |
| 534 ir.Primitive buildRightValue(IrBuilder builder), | |
| 535 {bool isLazyOr: false}) { | |
| 536 // e0 && e1 is translated as if e0 ? (e1 == true) : false. | |
| 537 // e0 || e1 is translated as if e0 ? true : (e1 == true). | |
| 538 // The translation must convert both e0 and e1 to booleans and handle | |
| 539 // local variable assignments in e1. | |
| 540 | |
| 541 IrBuilder rightBuilder = new IrBuilder.delimited(this); | |
| 542 ir.Primitive rightValue = buildRightValue(rightBuilder); | |
| 543 // A dummy empty target for the branch on the left subexpression branch. | |
| 544 // This enables using the same infrastructure for join-point continuations | |
| 545 // as in visitIf and visitConditional. It will hold a definition of the | |
| 546 // appropriate constant and an invocation of the join-point continuation. | |
| 547 IrBuilder emptyBuilder = new IrBuilder.delimited(this); | |
| 548 // Dummy empty targets for right true and right false. They hold | |
| 549 // definitions of the appropriate constant and an invocation of the | |
| 550 // join-point continuation. | |
| 551 IrBuilder rightTrueBuilder = new IrBuilder.delimited(rightBuilder); | |
| 552 IrBuilder rightFalseBuilder = new IrBuilder.delimited(rightBuilder); | |
| 553 | |
| 554 // If we don't evaluate the right subexpression, the value of the whole | |
| 555 // expression is this constant. | |
| 556 ir.Constant leftBool = emptyBuilder.makePrimConst( | |
| 557 emptyBuilder.state.constantSystem.createBool(isLazyOr)); | |
| 558 // If we do evaluate the right subexpression, the value of the expression | |
| 559 // is a true or false constant. | |
| 560 ir.Constant rightTrue = rightTrueBuilder.makePrimConst( | |
| 561 rightTrueBuilder.state.constantSystem.createBool(true)); | |
| 562 ir.Constant rightFalse = rightFalseBuilder.makePrimConst( | |
| 563 rightFalseBuilder.state.constantSystem.createBool(false)); | |
| 564 emptyBuilder.add(new ir.LetPrim(leftBool)); | |
| 565 rightTrueBuilder.add(new ir.LetPrim(rightTrue)); | |
| 566 rightFalseBuilder.add(new ir.LetPrim(rightFalse)); | |
| 567 | |
| 568 // Treat the result values as named values in the environment, so they | |
| 569 // will be treated as arguments to the join-point continuation. | |
| 570 assert(environment.length == emptyBuilder.environment.length); | |
| 571 assert(environment.length == rightTrueBuilder.environment.length); | |
| 572 assert(environment.length == rightFalseBuilder.environment.length); | |
| 573 emptyBuilder.environment.extend(null, leftBool); | |
| 574 rightTrueBuilder.environment.extend(null, rightTrue); | |
| 575 rightFalseBuilder.environment.extend(null, rightFalse); | |
| 576 | |
| 577 // Wire up two continuations for the left subexpression, two continuations | |
| 578 // for the right subexpression, and a three-way join continuation. | |
| 579 JumpCollector jumps = new JumpCollector(null); | |
| 580 jumps.addJump(emptyBuilder); | |
| 581 jumps.addJump(rightTrueBuilder); | |
| 582 jumps.addJump(rightFalseBuilder); | |
| 583 ir.Continuation joinContinuation = | |
| 584 createJoin(environment.length + 1, jumps); | |
| 585 ir.Continuation leftTrueContinuation = new ir.Continuation([]); | |
| 586 ir.Continuation leftFalseContinuation = new ir.Continuation([]); | |
| 587 ir.Continuation rightTrueContinuation = new ir.Continuation([]); | |
| 588 ir.Continuation rightFalseContinuation = new ir.Continuation([]); | |
| 589 rightTrueContinuation.body = rightTrueBuilder._root; | |
| 590 rightFalseContinuation.body = rightFalseBuilder._root; | |
| 591 // The right subexpression has two continuations. | |
| 592 rightBuilder.add( | |
| 593 new ir.LetCont(rightTrueContinuation, | |
| 594 new ir.LetCont(rightFalseContinuation, | |
| 595 new ir.Branch(new ir.IsTrue(rightValue), | |
| 596 rightTrueContinuation, | |
| 597 rightFalseContinuation)))); | |
| 598 // Depending on the operator, the left subexpression's continuations are | |
| 599 // either the right subexpression or an invocation of the join-point | |
| 600 // continuation. | |
| 601 if (isLazyOr) { | |
| 602 leftTrueContinuation.body = emptyBuilder._root; | |
| 603 leftFalseContinuation.body = rightBuilder._root; | |
| 604 } else { | |
| 605 leftTrueContinuation.body = rightBuilder._root; | |
| 606 leftFalseContinuation.body = emptyBuilder._root; | |
| 607 } | |
| 608 | |
| 609 add(new ir.LetCont(joinContinuation, | |
| 610 new ir.LetCont(leftTrueContinuation, | |
| 611 new ir.LetCont(leftFalseContinuation, | |
| 612 new ir.Branch(new ir.IsTrue(leftValue), | |
| 613 leftTrueContinuation, | |
| 614 leftFalseContinuation))))); | |
| 615 // There is always a join parameter for the result value, because it | |
| 616 // is different on at least two paths. | |
| 617 return joinContinuation.parameters.last; | |
| 618 } | |
| 619 | |
| 620 /// Create a non-recursive join-point continuation. | |
| 621 /// | |
| 622 /// Given the environment length at the join point and a list of | |
| 623 /// jumps that should reach the join point, create a join-point | |
| 624 /// continuation. The join-point continuation has a parameter for each | |
| 625 /// variable that has different values reaching on different paths. | |
| 626 /// | |
| 627 /// The jumps are uninitialized [ir.InvokeContinuation] expressions. | |
| 628 /// They are filled in with the target continuation and appropriate | |
| 629 /// arguments. | |
| 630 /// | |
| 631 /// As a side effect, the environment of this builder is updated to include | |
| 632 /// the join-point continuation parameters. | |
| 633 ir.Continuation createJoin(int environmentLength, JumpCollector jumps) { | |
| 634 assert(jumps.length >= 2); | |
| 635 | |
| 636 // Compute which values are identical on all paths reaching the join. | |
| 637 // Handle the common case of a pair of contexts efficiently. | |
| 638 Environment first = jumps.environments[0]; | |
| 639 Environment second = jumps.environments[1]; | |
| 640 assert(environmentLength <= first.length); | |
| 641 assert(environmentLength <= second.length); | |
| 642 assert(first.sameDomain(environmentLength, second)); | |
| 643 // A running count of the join-point parameters. | |
| 644 int parameterCount = 0; | |
| 645 // The null elements of common correspond to required parameters of the | |
| 646 // join-point continuation. | |
| 647 List<ir.Primitive> common = | |
| 648 new List<ir.Primitive>.generate(environmentLength, | |
| 649 (i) { | |
| 650 ir.Primitive candidate = first[i]; | |
| 651 if (second[i] == candidate) { | |
| 652 return candidate; | |
| 653 } else { | |
| 654 ++parameterCount; | |
| 655 return null; | |
| 656 } | |
| 657 }); | |
| 658 // If there is already a parameter for each variable, the other | |
| 659 // environments do not need to be considered. | |
| 660 if (parameterCount < environmentLength) { | |
| 661 for (int i = 0; i < environmentLength; ++i) { | |
| 662 ir.Primitive candidate = common[i]; | |
| 663 if (candidate == null) continue; | |
| 664 for (Environment current in jumps.environments.skip(2)) { | |
| 665 assert(environmentLength <= current.length); | |
| 666 assert(first.sameDomain(environmentLength, current)); | |
| 667 if (candidate != current[i]) { | |
| 668 common[i] = null; | |
| 669 ++parameterCount; | |
| 670 break; | |
| 671 } | |
| 672 } | |
| 673 if (parameterCount >= environmentLength) break; | |
| 674 } | |
| 675 } | |
| 676 | |
| 677 // Create the join point continuation. | |
| 678 List<ir.Parameter> parameters = <ir.Parameter>[]; | |
| 679 parameters.length = parameterCount; | |
| 680 int index = 0; | |
| 681 for (int i = 0; i < environmentLength; ++i) { | |
| 682 if (common[i] == null) { | |
| 683 parameters[index++] = new ir.Parameter(first.index2variable[i]); | |
| 684 } | |
| 685 } | |
| 686 assert(index == parameterCount); | |
| 687 ir.Continuation join = new ir.Continuation(parameters); | |
| 688 | |
| 689 // Fill in all the continuation invocations. | |
| 690 for (int i = 0; i < jumps.length; ++i) { | |
| 691 Environment currentEnvironment = jumps.environments[i]; | |
| 692 ir.InvokeContinuation invoke = jumps.invocations[i]; | |
| 693 // Sharing this.environment with one of the invocations will not do | |
| 694 // the right thing (this.environment has already been mutated). | |
| 695 List<ir.Reference> arguments = <ir.Reference>[]; | |
| 696 arguments.length = parameterCount; | |
| 697 int index = 0; | |
| 698 for (int i = 0; i < environmentLength; ++i) { | |
| 699 if (common[i] == null) { | |
| 700 arguments[index++] = new ir.Reference(currentEnvironment[i]); | |
| 701 } | |
| 702 } | |
| 703 invoke.continuation = new ir.Reference(join); | |
| 704 invoke.arguments = arguments; | |
| 705 } | |
| 706 | |
| 707 // Mutate this.environment to be the environment at the join point. Do | |
| 708 // this after adding the continuation invocations, because this.environment | |
| 709 // might be collected by the jump collector and so the old environment | |
| 710 // values are needed for the continuation invocation. | |
| 711 // | |
| 712 // Iterate to environment.length because environmentLength includes values | |
| 713 // outside the environment which are 'phantom' variables used for the | |
| 714 // values of expressions like &&, ||, and ?:. | |
| 715 index = 0; | |
| 716 for (int i = 0; i < environment.length; ++i) { | |
| 717 if (common[i] == null) { | |
| 718 environment.index2value[i] = parameters[index++]; | |
| 719 } | |
| 720 } | |
| 721 | |
| 722 return join; | |
| 723 } | |
| 498 } | 724 } |
| OLD | NEW |