| 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 'ir_nodes.dart' as ir; | 7 import 'ir_nodes.dart' as ir; |
| 8 import '../elements/elements.dart'; | 8 import '../elements/elements.dart'; |
| 9 import '../dart2jslib.dart'; | 9 import '../dart2jslib.dart'; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| 11 import '../source_file.dart'; | 11 import '../source_file.dart'; |
| 12 import '../tree/tree.dart' as ast; | 12 import '../tree/tree.dart' as ast; |
| 13 import '../scanner/scannerlib.dart' show Token; | 13 import '../scanner/scannerlib.dart' show Token, isUserDefinableOperator; |
| 14 import '../dart_backend/dart_backend.dart' show DartBackend; | 14 import '../dart_backend/dart_backend.dart' show DartBackend; |
| 15 import 'ir_pickler.dart' show Unpickler, IrConstantPool; | 15 import 'ir_pickler.dart' show Unpickler, IrConstantPool; |
| 16 import '../universe/universe.dart' show SelectorKind; |
| 16 | 17 |
| 17 /** | 18 /** |
| 18 * This task iterates through all resolved elements and builds [ir.Node]s. The | 19 * This task iterates through all resolved elements and builds [ir.Node]s. The |
| 19 * nodes are stored in the [nodes] map and accessible through [hasIr] and | 20 * nodes are stored in the [nodes] map and accessible through [hasIr] and |
| 20 * [getIr]. | 21 * [getIr]. |
| 21 * | 22 * |
| 22 * The functionality of the IrNodes is added gradually, therefore elements might | 23 * The functionality of the IrNodes is added gradually, therefore elements might |
| 23 * have an IR or not, depending on the language features that are used. For | 24 * have an IR or not, depending on the language features that are used. For |
| 24 * elements that do have an IR, the tree [ast.Node]s and the [Token]s are not | 25 * elements that do have an IR, the tree [ast.Node]s and the [Token]s are not |
| 25 * used in the rest of the compilation. This is ensured by setting the element's | 26 * used in the rest of the compilation. This is ensured by setting the element's |
| (...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 571 } | 572 } |
| 572 | 573 |
| 573 | 574 |
| 574 ir.Primitive visitLiteralNull(ast.LiteralNull node) { | 575 ir.Primitive visitLiteralNull(ast.LiteralNull node) { |
| 575 assert(isOpen); | 576 assert(isOpen); |
| 576 ir.Constant constant = new ir.Constant(constantSystem.createNull()); | 577 ir.Constant constant = new ir.Constant(constantSystem.createNull()); |
| 577 add(new ir.LetPrim(constant)); | 578 add(new ir.LetPrim(constant)); |
| 578 return constant; | 579 return constant; |
| 579 } | 580 } |
| 580 | 581 |
| 581 // TODO(kmillikin): other literals. Strings require quoting and escaping | 582 ir.Primitive visitLiteralString(ast.LiteralString node) { |
| 582 // in the Dart backend. | 583 assert(isOpen); |
| 583 // LiteralString | 584 ir.Constant constant = |
| 585 new ir.Constant(constantSystem.createString(node.dartString)); |
| 586 add(new ir.LetPrim(constant)); |
| 587 return constant; |
| 588 } |
| 589 |
| 590 // TODO(kmillikin): other literals. |
| 584 // LiteralList | 591 // LiteralList |
| 585 // LiteralMap | 592 // LiteralMap |
| 586 // LiteralMapEntry | 593 // LiteralMapEntry |
| 587 // LiteralSymbol | 594 // LiteralSymbol |
| 588 | 595 |
| 589 ir.Primitive visitParenthesizedExpression( | 596 ir.Primitive visitParenthesizedExpression( |
| 590 ast.ParenthesizedExpression node) { | 597 ast.ParenthesizedExpression node) { |
| 591 assert(isOpen); | 598 assert(isOpen); |
| 592 return visit(node.expression); | 599 return visit(node.expression); |
| 593 } | 600 } |
| 594 | 601 |
| 595 // ==== Sends ==== | 602 // ==== Sends ==== |
| 596 ir.Primitive visitAssert(ast.Send node) { | 603 ir.Primitive visitAssert(ast.Send node) { |
| 597 assert(isOpen); | 604 assert(isOpen); |
| 598 return giveup(); | 605 return giveup(); |
| 599 } | 606 } |
| 600 | 607 |
| 601 ir.Primitive visitClosureSend(ast.Send node) { | 608 ir.Primitive visitClosureSend(ast.Send node) { |
| 602 assert(isOpen); | 609 assert(isOpen); |
| 603 return giveup(); | 610 return giveup(); |
| 604 } | 611 } |
| 605 | 612 |
| 606 ir.Primitive visitDynamicSend(ast.Send node) { | 613 ir.Primitive visitDynamicSend(ast.Send node) { |
| 607 assert(isOpen); | 614 assert(isOpen); |
| 608 return giveup(); | 615 if (node.receiver == null || node.receiver.isSuper()) { |
| 616 return giveup(); |
| 617 } |
| 618 Selector selector = elements.getSelector(node); |
| 619 ir.Primitive receiver = visit(node.receiver); |
| 620 List arguments = node.arguments.toList(growable:false) |
| 621 .map(visit).toList(growable:false); |
| 622 ir.Parameter v = new ir.Parameter(null); |
| 623 ir.Continuation k = new ir.Continuation([v]); |
| 624 ir.Expression invoke = |
| 625 new ir.InvokeMethod(receiver, selector, k, arguments); |
| 626 add(new ir.LetCont(k, invoke)); |
| 627 return v; |
| 609 } | 628 } |
| 610 | 629 |
| 611 ir.Primitive visitGetterSend(ast.Send node) { | 630 ir.Primitive visitGetterSend(ast.Send node) { |
| 612 assert(isOpen); | 631 assert(isOpen); |
| 613 Element element = elements[node]; | 632 Element element = elements[node]; |
| 614 if (!Elements.isLocal(element)) return giveup(); | 633 if (Elements.isLocal(element)) { |
| 615 int index = variableIndex[element]; | 634 int index = variableIndex[element]; |
| 616 ir.Primitive value = assignedVars[index]; | 635 ir.Primitive value = assignedVars[index]; |
| 617 return value == null ? freeVars[index] : value; | 636 return value == null ? freeVars[index] : value; |
| 637 } else if (Elements.isInstanceField(element)) { |
| 638 ir.Primitive receiver = visit(node.receiver); |
| 639 ir.Parameter v = new ir.Parameter(null); |
| 640 ir.Continuation k = new ir.Continuation([v]); |
| 641 Selector selector = elements.getSelector(node); |
| 642 assert(selector.kind == SelectorKind.GETTER); |
| 643 ir.InvokeMethod invoke = new ir.InvokeMethod(receiver, selector, k, []); |
| 644 add(new ir.LetCont(k, invoke)); |
| 645 return v; |
| 646 } else { |
| 647 // TODO(asgerf): static and top-level |
| 648 // NOTE: Index-getters are OperatorSends, not GetterSends |
| 649 return giveup(); |
| 650 } |
| 618 } | 651 } |
| 619 | 652 |
| 620 ir.Primitive visitOperatorSend(ast.Send node) { | 653 ir.Primitive visitOperatorSend(ast.Send node) { |
| 621 assert(isOpen); | 654 ast.Operator selectorNode = node.selector; |
| 622 return giveup(); | 655 if (!isUserDefinableOperator(selectorNode.source)) { |
| 656 return giveup(); |
| 657 } else { |
| 658 return visitDynamicSend(node); |
| 659 } |
| 623 } | 660 } |
| 624 | 661 |
| 625 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] | 662 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] |
| 626 // where (C', xs) = arguments.fold(Build, C) | 663 // where (C', xs) = arguments.fold(Build, C) |
| 627 ir.Primitive visitStaticSend(ast.Send node) { | 664 ir.Primitive visitStaticSend(ast.Send node) { |
| 628 assert(isOpen); | 665 assert(isOpen); |
| 629 Element element = elements[node]; | 666 Element element = elements[node]; |
| 630 // TODO(lry): support static fields. (separate IR instruction?) | 667 // TODO(lry): support static fields. (separate IR instruction?) |
| 631 if (element.isField || element.isGetter) return giveup(); | 668 if (element.isField || element.isGetter) return giveup(); |
| 632 // TODO(kmillikin): support static setters. | 669 // TODO(kmillikin): support static setters. |
| 633 if (element.isSetter) return giveup(); | 670 if (element.isSetter) return giveup(); |
| 634 // TODO(lry): support constructors / factory calls. | 671 // TODO(lry): support constructors / factory calls. |
| 635 if (element.isConstructor) return giveup(); | 672 if (element.isConstructor) return giveup(); |
| 636 // TODO(lry): support foreign functions. | 673 // TODO(lry): support foreign functions. |
| 637 if (element.isForeign(compiler)) return giveup(); | 674 if (element.isForeign(compiler)) return giveup(); |
| 638 // TODO(lry): for elements that could not be resolved emit code to throw a | 675 // TODO(lry): for elements that could not be resolved emit code to throw a |
| 639 // [NoSuchMethodError]. | 676 // [NoSuchMethodError]. |
| 640 if (element.isErroneous) return giveup(); | 677 if (element.isErroneous) return giveup(); |
| 641 // TODO(lry): generate IR for object identicality. | 678 // TODO(lry): generate IR for object identicality. |
| 642 if (element == compiler.identicalFunction) giveup(); | 679 if (element == compiler.identicalFunction) giveup(); |
| 643 | 680 |
| 644 Selector selector = elements.getSelector(node); | 681 Selector selector = elements.getSelector(node); |
| 645 // TODO(lry): support named arguments | 682 // TODO(lry): support named arguments |
| 646 if (selector.namedArgumentCount != 0) return giveup(); | 683 if (selector.namedArgumentCount != 0) return giveup(); |
| 647 | 684 |
| 648 // TODO(kmillikin): support a receiver: A.m(). | 685 // TODO(kmillikin): support a receiver: A.m(). |
| 649 if (node.receiver != null) return giveup(); | 686 if (node.receiver != null) return giveup(); |
| 650 | 687 |
| 651 List arguments = []; | |
| 652 // TODO(lry): support default arguments, need support for locals. | 688 // TODO(lry): support default arguments, need support for locals. |
| 653 bool succeeded = selector.addArgumentsToList( | 689 List<ir.Definition> arguments = node.arguments.toList(growable:false) |
| 654 node.arguments, arguments, element.implementation, visit, | 690 .map(visit).toList(growable:false); |
| 655 (node) => giveup(), compiler); | |
| 656 if (!succeeded) { | |
| 657 // TODO(lry): generate code to throw a [WrongArgumentCountError]. | |
| 658 return giveup(); | |
| 659 } | |
| 660 ir.Parameter v = new ir.Parameter(null); | 691 ir.Parameter v = new ir.Parameter(null); |
| 661 ir.Continuation k = new ir.Continuation([v]); | 692 ir.Continuation k = new ir.Continuation([v]); |
| 662 ir.Expression invoke = | 693 ir.Expression invoke = |
| 663 new ir.InvokeStatic(element, selector, k, arguments); | 694 new ir.InvokeStatic(element, selector, k, arguments); |
| 664 add(new ir.LetCont(k, invoke)); | 695 add(new ir.LetCont(k, invoke)); |
| 665 return v; | 696 return v; |
| 666 } | 697 } |
| 667 | 698 |
| 668 ir.Primitive visitSuperSend(ast.Send node) { | 699 ir.Primitive visitSuperSend(ast.Send node) { |
| 669 assert(isOpen); | 700 assert(isOpen); |
| 670 return giveup(); | 701 return giveup(); |
| 671 } | 702 } |
| 672 | 703 |
| 673 ir.Primitive visitTypeReferenceSend(ast.Send node) { | 704 ir.Primitive visitTypeReferenceSend(ast.Send node) { |
| 674 assert(isOpen); | 705 assert(isOpen); |
| 675 return giveup(); | 706 return giveup(); |
| 676 } | 707 } |
| 677 | 708 |
| 678 ir.Primitive visitSendSet(ast.SendSet node) { | 709 ir.Primitive visitSendSet(ast.SendSet node) { |
| 679 assert(isOpen); | 710 assert(isOpen); |
| 680 Element element = elements[node]; | 711 Element element = elements[node]; |
| 681 if (!Elements.isLocal(element)) return giveup(); | |
| 682 if (node.assignmentOperator.source != '=') return giveup(); | 712 if (node.assignmentOperator.source != '=') return giveup(); |
| 683 // Exactly one argument expected for a simple assignment. | 713 if (Elements.isLocal(element)) { |
| 684 assert(!node.arguments.isEmpty); | 714 // Exactly one argument expected for a simple assignment. |
| 685 assert(node.arguments.tail.isEmpty); | 715 assert(!node.arguments.isEmpty); |
| 686 ir.Primitive result = visit(node.arguments.head); | 716 assert(node.arguments.tail.isEmpty); |
| 687 assignedVars[variableIndex[element]] = result; | 717 ir.Primitive result = visit(node.arguments.head); |
| 688 return result; | 718 assignedVars[variableIndex[element]] = result; |
| 719 return result; |
| 720 } else if (Elements.isStaticOrTopLevel(element)) { |
| 721 // TODO(asgerf): static and top-level |
| 722 return giveup(); |
| 723 } else if (node.receiver == null) { |
| 724 // Nodes that fall in this case: |
| 725 // - Unresolved top-level |
| 726 // - Assignment to final variable (will not be resolved) |
| 727 return giveup(); |
| 728 } else { |
| 729 // Setter or index-setter invocation |
| 730 assert(node.receiver != null); |
| 731 if (node.receiver.isSuper()) return giveup(); |
| 732 |
| 733 ir.Primitive receiver = visit(node.receiver); |
| 734 ir.Parameter v = new ir.Parameter(null); |
| 735 ir.Continuation k = new ir.Continuation([v]); |
| 736 Selector selector = elements.getSelector(node); |
| 737 assert(selector.kind == SelectorKind.SETTER || |
| 738 selector.kind == SelectorKind.INDEX); |
| 739 List<ir.Definition> args = node.arguments.toList(growable:false) |
| 740 .map(visit).toList(growable:false); |
| 741 ir.InvokeMethod invoke = new ir.InvokeMethod(receiver, selector, k, args); |
| 742 add(new ir.LetCont(k, invoke)); |
| 743 return args.last; |
| 744 } |
| 745 } |
| 746 |
| 747 ir.Primitive visitNewExpression(ast.NewExpression node) { |
| 748 if (node.isConst) { |
| 749 return giveup(); // TODO(asgerf): Const constructor call. |
| 750 } |
| 751 FunctionElement element = elements[node.send]; |
| 752 if (Elements.isUnresolved(element)) { |
| 753 return giveup(); |
| 754 } |
| 755 ast.Node selector = node.send.selector; |
| 756 GenericType type = elements.getType(node); |
| 757 ir.Parameter v = new ir.Parameter(null); |
| 758 ir.Continuation k = new ir.Continuation([v]); |
| 759 List<ir.Definition> args = node.send.arguments.toList(growable:false) |
| 760 .map(visit).toList(growable:false); |
| 761 ir.InvokeConstructor invoke = new ir.InvokeConstructor( |
| 762 type, |
| 763 element, |
| 764 k, |
| 765 args); |
| 766 add(new ir.LetCont(k, invoke)); |
| 767 return v; |
| 689 } | 768 } |
| 690 | 769 |
| 691 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 770 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| 692 | 771 |
| 693 ir.Primitive giveup() => throw ABORT_IRNODE_BUILDER; | 772 ir.Primitive giveup() => throw ABORT_IRNODE_BUILDER; |
| 694 | 773 |
| 695 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { | 774 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { |
| 696 try { | 775 try { |
| 697 return action(); | 776 return action(); |
| 698 } catch(e) { | 777 } catch(e) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 711 bool visit(DartType type, Null _) => type.accept(this, null); | 790 bool visit(DartType type, Null _) => type.accept(this, null); |
| 712 | 791 |
| 713 bool visitType(DartType type, Null _) => false; | 792 bool visitType(DartType type, Null _) => false; |
| 714 | 793 |
| 715 bool visitVoidType(VoidType type, Null _) => true; | 794 bool visitVoidType(VoidType type, Null _) => true; |
| 716 | 795 |
| 717 // Currently, InterfaceType and TypedefType are supported so long as they | 796 // Currently, InterfaceType and TypedefType are supported so long as they |
| 718 // do not have type parameters. They are subclasses of GenericType. | 797 // do not have type parameters. They are subclasses of GenericType. |
| 719 bool visitGenericType(GenericType type, Null _) => !type.isGeneric; | 798 bool visitGenericType(GenericType type, Null _) => !type.isGeneric; |
| 720 } | 799 } |
| OLD | NEW |