| 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, isUserDefinableOperator; | 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 '../universe/universe.dart' show SelectorKind; | 15 import '../universe/universe.dart' show SelectorKind; |
| 16 import '../util/util.dart' show Link; | 16 import '../util/util.dart' show Link; |
| 17 import '../helpers/helpers.dart'; |
| 17 | 18 |
| 18 /** | 19 /** |
| 19 * This task iterates through all resolved elements and builds [ir.Node]s. The | 20 * This task iterates through all resolved elements and builds [ir.Node]s. The |
| 20 * nodes are stored in the [nodes] map and accessible through [hasIr] and | 21 * nodes are stored in the [nodes] map and accessible through [hasIr] and |
| 21 * [getIr]. | 22 * [getIr]. |
| 22 * | 23 * |
| 23 * The functionality of the IrNodes is added gradually, therefore elements might | 24 * The functionality of the IrNodes is added gradually, therefore elements might |
| 24 * have an IR or not, depending on the language features that are used. For | 25 * have an IR or not, depending on the language features that are used. For |
| 25 * elements that do have an IR, the tree [ast.Node]s and the [Token]s are not | 26 * elements that do have an IR, the tree [ast.Node]s and the [Token]s are not |
| 26 * used in the rest of the compilation. This is ensured by setting the element's | 27 * used in the rest of the compilation. This is ensured by setting the element's |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 if (signature.optionalParameterCount > 0) return false; | 104 if (signature.optionalParameterCount > 0) return false; |
| 104 | 105 |
| 105 // TODO(kmillikin): support getters and setters and static class members. | 106 // TODO(kmillikin): support getters and setters and static class members. |
| 106 // With the current Dart Tree emitter they just require recognizing them | 107 // With the current Dart Tree emitter they just require recognizing them |
| 107 // and generating the correct syntax. | 108 // and generating the correct syntax. |
| 108 if (element.isGetter || element.isSetter) return false; | 109 if (element.isGetter || element.isSetter) return false; |
| 109 | 110 |
| 110 // TODO(lry): support native functions (also in [visitReturn]). | 111 // TODO(lry): support native functions (also in [visitReturn]). |
| 111 if (function.isNative) return false; | 112 if (function.isNative) return false; |
| 112 | 113 |
| 114 // TODO(asgerf): support syntax for redirecting factory constructors |
| 115 if (function is ConstructorElement && function.isRedirectingFactory) { |
| 116 return false; |
| 117 } |
| 118 |
| 113 return true; | 119 return true; |
| 114 } | 120 } |
| 115 | 121 |
| 116 bool get inCheckedMode { | 122 bool get inCheckedMode { |
| 117 bool result = false; | 123 bool result = false; |
| 118 assert((result = true)); | 124 assert((result = true)); |
| 119 return result; | 125 return result; |
| 120 } | 126 } |
| 121 | 127 |
| 122 SourceFile elementSourceFile(Element element) { | 128 SourceFile elementSourceFile(Element element) { |
| (...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 609 entryArguments))); | 615 entryArguments))); |
| 610 current = resultContext; | 616 current = resultContext; |
| 611 } else { | 617 } else { |
| 612 add(resultContext); | 618 add(resultContext); |
| 613 } | 619 } |
| 614 return null; | 620 return null; |
| 615 } | 621 } |
| 616 | 622 |
| 617 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { | 623 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { |
| 618 assert(isOpen); | 624 assert(isOpen); |
| 625 if (node.modifiers.isConst) { |
| 626 return giveup(node, 'Local const'); // TODO(asgerf): const vars |
| 627 } |
| 619 for (ast.Node definition in node.definitions.nodes) { | 628 for (ast.Node definition in node.definitions.nodes) { |
| 620 Element element = elements[definition]; | 629 Element element = elements[definition]; |
| 621 // Definitions are either SendSets if there is an initializer, or | 630 // Definitions are either SendSets if there is an initializer, or |
| 622 // Identifiers if there is no initializer. | 631 // Identifiers if there is no initializer. |
| 623 if (definition is ast.SendSet) { | 632 if (definition is ast.SendSet) { |
| 624 assert(!definition.arguments.isEmpty); | 633 assert(!definition.arguments.isEmpty); |
| 625 assert(definition.arguments.tail.isEmpty); | 634 assert(definition.arguments.tail.isEmpty); |
| 626 ir.Primitive initialValue = visit(definition.arguments.head); | 635 ir.Primitive initialValue = visit(definition.arguments.head); |
| 627 // In case a primitive was introduced for the initializer expression, | 636 // In case a primitive was introduced for the initializer expression, |
| 628 // use this variable element to help derive a good name for it. | 637 // use this variable element to help derive a good name for it. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 645 return null; | 654 return null; |
| 646 } | 655 } |
| 647 | 656 |
| 648 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 657 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 649 // where (C', x) = Build(e, C) | 658 // where (C', x) = Build(e, C) |
| 650 // | 659 // |
| 651 // Return without a subexpression is translated as if it were return null. | 660 // Return without a subexpression is translated as if it were return null. |
| 652 ir.Primitive visitReturn(ast.Return node) { | 661 ir.Primitive visitReturn(ast.Return node) { |
| 653 assert(isOpen); | 662 assert(isOpen); |
| 654 // TODO(lry): support native returns. | 663 // TODO(lry): support native returns. |
| 655 if (node.beginToken.value == 'native') return giveup(); | 664 if (node.beginToken.value == 'native') return giveup(node, 'Native return'); |
| 656 ir.Primitive value; | 665 ir.Primitive value; |
| 657 if (node.expression == null) { | 666 if (node.expression == null) { |
| 658 value = new ir.Constant(constantSystem.createNull()); | 667 value = new ir.Constant(constantSystem.createNull()); |
| 659 add(new ir.LetPrim(value)); | 668 add(new ir.LetPrim(value)); |
| 660 } else { | 669 } else { |
| 661 value = visit(node.expression); | 670 value = visit(node.expression); |
| 662 } | 671 } |
| 663 add(new ir.InvokeContinuation(returnContinuation, [value])); | 672 add(new ir.InvokeContinuation(returnContinuation, [value])); |
| 664 current = null; | 673 current = null; |
| 665 return null; | 674 return null; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 } | 771 } |
| 763 | 772 |
| 764 Constant getConstantForNode(ast.Node node) { | 773 Constant getConstantForNode(ast.Node node) { |
| 765 Constant constant = | 774 Constant constant = |
| 766 compiler.backend.constants.getConstantForNode(node, elements); | 775 compiler.backend.constants.getConstantForNode(node, elements); |
| 767 assert(invariant(node, constant != null, | 776 assert(invariant(node, constant != null, |
| 768 message: 'No constant computed for $node')); | 777 message: 'No constant computed for $node')); |
| 769 return constant; | 778 return constant; |
| 770 } | 779 } |
| 771 | 780 |
| 772 bool isSupportedConst(Constant constant) { | |
| 773 return const SupportedConstantVisitor().visit(constant); | |
| 774 } | |
| 775 | |
| 776 ir.Primitive visitLiteralList(ast.LiteralList node) { | 781 ir.Primitive visitLiteralList(ast.LiteralList node) { |
| 777 assert(isOpen); | 782 assert(isOpen); |
| 778 ir.Primitive result; | 783 List<ir.Primitive> values = node.elements.nodes.mapToList(visit); |
| 779 if (node.isConst) { | 784 Constant constant = node.isConst ? getConstantForNode(node) : null; |
| 780 // TODO(sigurdm): Remove when all constants are supported. | 785 GenericType type = elements.getType(node); |
| 781 Constant constant = getConstantForNode(node); | 786 ir.Primitive result = new ir.LiteralList(type, values, constant); |
| 782 if (!isSupportedConst(constant)) return giveup(); | |
| 783 result = new ir.Constant(constant); | |
| 784 } else { | |
| 785 List<ir.Primitive> values = new List<ir.Primitive>(); | |
| 786 node.elements.nodes.forEach((ast.Node node) { | |
| 787 values.add(visit(node)); | |
| 788 }); | |
| 789 result = new ir.LiteralList(values); | |
| 790 } | |
| 791 add(new ir.LetPrim(result)); | 787 add(new ir.LetPrim(result)); |
| 792 return result; | 788 return result; |
| 793 } | 789 } |
| 794 | 790 |
| 795 ir.Primitive visitLiteralMap(ast.LiteralMap node) { | 791 ir.Primitive visitLiteralMap(ast.LiteralMap node) { |
| 796 assert(isOpen); | 792 assert(isOpen); |
| 797 ir.Primitive result; | 793 List<ir.Primitive> keys = new List<ir.Primitive>(); |
| 798 if (node.isConst) { | 794 List<ir.Primitive> values = new List<ir.Primitive>(); |
| 799 // TODO(sigurdm): Remove when all constants are supported. | 795 node.entries.nodes.forEach((ast.LiteralMapEntry node) { |
| 800 Constant constant = getConstantForNode(node); | 796 keys.add(visit(node.key)); |
| 801 if (!isSupportedConst(constant)) return giveup(); | 797 values.add(visit(node.value)); |
| 802 result = new ir.Constant(constant); | 798 }); |
| 803 } else { | 799 GenericType type = elements.getType(node); |
| 804 List<ir.Primitive> keys = new List<ir.Primitive>(); | 800 Constant constant = node.isConst ? getConstantForNode(node) : null; |
| 805 List<ir.Primitive> values = new List<ir.Primitive>(); | 801 ir.Primitive result = new ir.LiteralMap(type, keys, values, constant); |
| 806 node.entries.nodes.forEach((ast.LiteralMapEntry node) { | |
| 807 keys.add(visit(node.key)); | |
| 808 values.add(visit(node.value)); | |
| 809 }); | |
| 810 result = new ir.LiteralMap(keys, values); | |
| 811 } | |
| 812 add(new ir.LetPrim(result)); | 802 add(new ir.LetPrim(result)); |
| 813 return result; | 803 return result; |
| 814 } | 804 } |
| 815 | 805 |
| 816 ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) { | 806 ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) { |
| 817 assert(isOpen); | 807 assert(isOpen); |
| 818 ir.Constant constant = new ir.Constant(getConstantForNode(node)); | 808 ir.Constant constant = new ir.Constant(getConstantForNode(node)); |
| 819 add(new ir.LetPrim(constant)); | 809 add(new ir.LetPrim(constant)); |
| 820 return constant; | 810 return constant; |
| 821 } | 811 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 848 | 838 |
| 849 ir.Primitive lookupLocal(Element element) { | 839 ir.Primitive lookupLocal(Element element) { |
| 850 int index = variableIndex[element]; | 840 int index = variableIndex[element]; |
| 851 ir.Primitive value = assignedVars[index]; | 841 ir.Primitive value = assignedVars[index]; |
| 852 return value == null ? freeVars[index] : value; | 842 return value == null ? freeVars[index] : value; |
| 853 } | 843 } |
| 854 | 844 |
| 855 // ==== Sends ==== | 845 // ==== Sends ==== |
| 856 ir.Primitive visitAssert(ast.Send node) { | 846 ir.Primitive visitAssert(ast.Send node) { |
| 857 assert(isOpen); | 847 assert(isOpen); |
| 858 return giveup(); | 848 return giveup(node, 'Assert'); |
| 859 } | 849 } |
| 860 | 850 |
| 861 ir.Primitive visitNamedArgument(ast.NamedArgument node) { | 851 ir.Primitive visitNamedArgument(ast.NamedArgument node) { |
| 862 assert(isOpen); | 852 assert(isOpen); |
| 863 return visit(node.expression); | 853 return visit(node.expression); |
| 864 } | 854 } |
| 865 | 855 |
| 866 ir.Primitive visitClosureSend(ast.Send node) { | 856 ir.Primitive visitClosureSend(ast.Send node) { |
| 867 assert(isOpen); | 857 assert(isOpen); |
| 868 Selector closureSelector = elements.getSelector(node); | 858 Selector closureSelector = elements.getSelector(node); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 888 ir.Continuation k = new ir.Continuation([v]); | 878 ir.Continuation k = new ir.Continuation([v]); |
| 889 ir.Expression invoke = | 879 ir.Expression invoke = |
| 890 new ir.InvokeMethod(closureTarget, namedCallSelector, k, arguments); | 880 new ir.InvokeMethod(closureTarget, namedCallSelector, k, arguments); |
| 891 add(new ir.LetCont(k, invoke)); | 881 add(new ir.LetCont(k, invoke)); |
| 892 return v; | 882 return v; |
| 893 } | 883 } |
| 894 | 884 |
| 895 ir.Primitive visitDynamicSend(ast.Send node) { | 885 ir.Primitive visitDynamicSend(ast.Send node) { |
| 896 assert(isOpen); | 886 assert(isOpen); |
| 897 if (node.receiver == null || node.receiver.isSuper()) { | 887 if (node.receiver == null || node.receiver.isSuper()) { |
| 898 return giveup(); | 888 return giveup(node, 'DynamicSend without receiver, or super receiver'); |
| 899 } | 889 } |
| 900 Selector selector = elements.getSelector(node); | 890 Selector selector = elements.getSelector(node); |
| 901 ir.Primitive receiver = visit(node.receiver); | 891 ir.Primitive receiver = visit(node.receiver); |
| 902 List<ir.Primitive> arguments = new List<ir.Primitive>(); | 892 List<ir.Primitive> arguments = new List<ir.Primitive>(); |
| 903 for (ast.Node n in node.arguments) { | 893 for (ast.Node n in node.arguments) { |
| 904 arguments.add(visit(n)); | 894 arguments.add(visit(n)); |
| 905 } | 895 } |
| 906 ir.Parameter v = new ir.Parameter(null); | 896 ir.Parameter v = new ir.Parameter(null); |
| 907 ir.Continuation k = new ir.Continuation([v]); | 897 ir.Continuation k = new ir.Continuation([v]); |
| 908 ir.Expression invoke = | 898 ir.Expression invoke = |
| 909 new ir.InvokeMethod(receiver, selector, k, arguments); | 899 new ir.InvokeMethod(receiver, selector, k, arguments); |
| 910 add(new ir.LetCont(k, invoke)); | 900 add(new ir.LetCont(k, invoke)); |
| 911 return v; | 901 return v; |
| 912 } | 902 } |
| 913 | 903 |
| 914 ir.Primitive visitGetterSend(ast.Send node) { | 904 ir.Primitive visitGetterSend(ast.Send node) { |
| 915 assert(isOpen); | 905 assert(isOpen); |
| 916 Element element = elements[node]; | 906 Element element = elements[node]; |
| 917 if (Elements.isLocal(element)) { | 907 if (Elements.isLocal(element)) { |
| 918 return lookupLocal(element); | 908 return lookupLocal(element); |
| 919 } else if (element == null || Elements.isInstanceField(element)) { | 909 } else if (element == null || Elements.isInstanceField(element)) { |
| 920 // TODO: Support implicit this. | 910 // TODO: Support implicit this. |
| 921 if (node.receiver == null) return giveup(); | 911 if (node.receiver == null) return giveup(node); |
| 922 | 912 |
| 923 ir.Primitive receiver = visit(node.receiver); | 913 ir.Primitive receiver = visit(node.receiver); |
| 924 ir.Parameter v = new ir.Parameter(null); | 914 ir.Parameter v = new ir.Parameter(null); |
| 925 ir.Continuation k = new ir.Continuation([v]); | 915 ir.Continuation k = new ir.Continuation([v]); |
| 926 Selector selector = elements.getSelector(node); | 916 Selector selector = elements.getSelector(node); |
| 927 assert(selector.kind == SelectorKind.GETTER); | 917 assert(selector.kind == SelectorKind.GETTER); |
| 928 ir.InvokeMethod invoke = new ir.InvokeMethod(receiver, selector, k, []); | 918 ir.InvokeMethod invoke = new ir.InvokeMethod(receiver, selector, k, []); |
| 929 add(new ir.LetCont(k, invoke)); | 919 add(new ir.LetCont(k, invoke)); |
| 930 return v; | 920 return v; |
| 931 } else if (element.isField) { | 921 } else if (element.isField) { |
| 932 ir.Parameter v = new ir.Parameter(null); | 922 ir.Parameter v = new ir.Parameter(null); |
| 933 ir.Continuation k = new ir.Continuation([v]); | 923 ir.Continuation k = new ir.Continuation([v]); |
| 934 Selector selector = elements.getSelector(node); | 924 Selector selector = elements.getSelector(node); |
| 935 assert(selector.kind == SelectorKind.GETTER); | 925 assert(selector.kind == SelectorKind.GETTER); |
| 936 ir.InvokeStatic invoke = new ir.InvokeStatic(element, selector, k, []); | 926 ir.InvokeStatic invoke = new ir.InvokeStatic(element, selector, k, []); |
| 937 add(new ir.LetCont(k, invoke)); | 927 add(new ir.LetCont(k, invoke)); |
| 938 return v; | 928 return v; |
| 929 } else if (Elements.isStaticOrTopLevelFunction(element)) { |
| 930 ir.Primitive prim = new ir.Constant(new FunctionConstant(element)); |
| 931 add(new ir.LetPrim(prim)); |
| 932 return prim; |
| 939 } else { | 933 } else { |
| 940 return giveup(); // TODO: figure out what's missing here | 934 return giveup(node); // TODO(asgerf): figure out what's missing here |
| 941 } | 935 } |
| 942 } | 936 } |
| 943 | 937 |
| 944 ir.Primitive buildNegation(ir.Primitive condition) { | 938 ir.Primitive buildNegation(ir.Primitive condition) { |
| 945 // ! e is translated as e ? false : true | 939 // ! e is translated as e ? false : true |
| 946 | 940 |
| 947 // Add a continuation parameter for the result of the expression. | 941 // Add a continuation parameter for the result of the expression. |
| 948 ir.Parameter resultParameter = new ir.Parameter(null); | 942 ir.Parameter resultParameter = new ir.Parameter(null); |
| 949 | 943 |
| 950 ir.Continuation joinContinuation = new ir.Continuation([resultParameter]); | 944 ir.Continuation joinContinuation = new ir.Continuation([resultParameter]); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1075 assert(node.receiver != null); | 1069 assert(node.receiver != null); |
| 1076 assert(node.arguments.isEmpty); | 1070 assert(node.arguments.isEmpty); |
| 1077 return buildNegation(visit(node.receiver)); | 1071 return buildNegation(visit(node.receiver)); |
| 1078 } | 1072 } |
| 1079 if (op.source == "!=") { | 1073 if (op.source == "!=") { |
| 1080 assert(node.receiver != null); | 1074 assert(node.receiver != null); |
| 1081 assert(!node.arguments.isEmpty); | 1075 assert(!node.arguments.isEmpty); |
| 1082 assert(node.arguments.tail.isEmpty); | 1076 assert(node.arguments.tail.isEmpty); |
| 1083 return buildNegation(visitDynamicSend(node)); | 1077 return buildNegation(visitDynamicSend(node)); |
| 1084 } | 1078 } |
| 1085 return giveup(); | 1079 return giveup(node); |
| 1086 } | 1080 } |
| 1087 | 1081 |
| 1088 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] | 1082 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] |
| 1089 // where (C', xs) = arguments.fold(Build, C) | 1083 // where (C', xs) = arguments.fold(Build, C) |
| 1090 ir.Primitive visitStaticSend(ast.Send node) { | 1084 ir.Primitive visitStaticSend(ast.Send node) { |
| 1091 assert(isOpen); | 1085 assert(isOpen); |
| 1092 Element element = elements[node]; | 1086 Element element = elements[node]; |
| 1093 // TODO(lry): support constructors / factory calls. | 1087 // TODO(lry): support constructors / factory calls. |
| 1094 if (element.isConstructor) return giveup(); | 1088 if (element.isConstructor) return giveup(node, 'StaticSend: constructor'); |
| 1095 // TODO(lry): support foreign functions. | 1089 // TODO(lry): support foreign functions. |
| 1096 if (element.isForeign(compiler)) return giveup(); | 1090 if (element.isForeign(compiler)) return giveup(node, 'StaticSend: foreign'); |
| 1097 // TODO(lry): for elements that could not be resolved emit code to throw a | 1091 // TODO(lry): for elements that could not be resolved emit code to throw a |
| 1098 // [NoSuchMethodError]. | 1092 // [NoSuchMethodError]. |
| 1099 if (element.isErroneous) return giveup(); | 1093 if (element.isErroneous) return giveup(node, 'StaticSend: erroneous'); |
| 1100 // TODO(lry): generate IR for object identicality. | 1094 // TODO(lry): generate IR for object identicality. |
| 1101 if (element == compiler.identicalFunction) giveup(); | 1095 if (element == compiler.identicalFunction) { |
| 1096 return giveup(node, 'StaticSend: identical'); |
| 1097 } |
| 1102 | 1098 |
| 1103 Selector selector = elements.getSelector(node); | 1099 Selector selector = elements.getSelector(node); |
| 1104 | 1100 |
| 1105 // TODO(lry): support default arguments, need support for locals. | 1101 // TODO(lry): support default arguments, need support for locals. |
| 1106 List<ir.Definition> arguments = node.arguments.mapToList(visit, | 1102 List<ir.Definition> arguments = node.arguments.mapToList(visit, |
| 1107 growable:false); | 1103 growable:false); |
| 1108 ir.Parameter v = new ir.Parameter(null); | 1104 ir.Parameter v = new ir.Parameter(null); |
| 1109 ir.Continuation k = new ir.Continuation([v]); | 1105 ir.Continuation k = new ir.Continuation([v]); |
| 1110 ir.Expression invoke = | 1106 ir.Expression invoke = |
| 1111 new ir.InvokeStatic(element, selector, k, arguments); | 1107 new ir.InvokeStatic(element, selector, k, arguments); |
| 1112 add(new ir.LetCont(k, invoke)); | 1108 add(new ir.LetCont(k, invoke)); |
| 1113 return v; | 1109 return v; |
| 1114 } | 1110 } |
| 1115 | 1111 |
| 1116 ir.Primitive visitSuperSend(ast.Send node) { | 1112 ir.Primitive visitSuperSend(ast.Send node) { |
| 1117 assert(isOpen); | 1113 assert(isOpen); |
| 1118 return giveup(); | 1114 return giveup(node, 'SuperSend'); |
| 1119 } | 1115 } |
| 1120 | 1116 |
| 1121 ir.Primitive visitTypeReferenceSend(ast.Send node) { | 1117 ir.Primitive visitTypeReferenceSend(ast.Send node) { |
| 1122 assert(isOpen); | 1118 assert(isOpen); |
| 1123 return giveup(); | 1119 if (node.argumentsNode != null) { |
| 1120 // May happen in strange, invalid code. |
| 1121 // TODO(asgerf): Generate code that throws a runtime error. |
| 1122 return giveup(node, 'TypeReferenceSend: has argument'); |
| 1123 } |
| 1124 Element element = elements[node]; |
| 1125 if (element is TypeDeclarationElement) { |
| 1126 DartType typeType = compiler.backend.typeImplementation.rawType; |
| 1127 ir.Primitive prim = |
| 1128 new ir.Constant(new TypeConstant(element.rawType, typeType)); |
| 1129 add(new ir.LetPrim(prim)); |
| 1130 return prim; |
| 1131 } else if (element.isTypeVariable) { |
| 1132 // TODO(asgerf): Introduce IR to reify type variables |
| 1133 return giveup(node, 'TypeReferenceSend: type variable'); |
| 1134 } else { |
| 1135 // TODO(asgerf): Any other cases? |
| 1136 return giveup(node); |
| 1137 } |
| 1124 } | 1138 } |
| 1125 | 1139 |
| 1126 ir.Primitive visitSendSet(ast.SendSet node) { | 1140 ir.Primitive visitSendSet(ast.SendSet node) { |
| 1127 assert(isOpen); | 1141 assert(isOpen); |
| 1128 Element element = elements[node]; | 1142 Element element = elements[node]; |
| 1129 ast.Operator op = node.assignmentOperator; | 1143 ast.Operator op = node.assignmentOperator; |
| 1130 ir.Primitive result; | 1144 ir.Primitive result; |
| 1131 ir.Primitive getter; | 1145 ir.Primitive getter; |
| 1132 if (op.source == '=') { | 1146 if (op.source == '=') { |
| 1133 if (Elements.isLocal(element)) { | 1147 if (Elements.isLocal(element)) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1146 Selector selector = elements.getSelector(node); | 1160 Selector selector = elements.getSelector(node); |
| 1147 ir.Definition arg = visit(node.arguments.head); | 1161 ir.Definition arg = visit(node.arguments.head); |
| 1148 ir.InvokeStatic invoke = | 1162 ir.InvokeStatic invoke = |
| 1149 new ir.InvokeStatic(element, selector, k, [arg]); | 1163 new ir.InvokeStatic(element, selector, k, [arg]); |
| 1150 add(new ir.LetCont(k, invoke)); | 1164 add(new ir.LetCont(k, invoke)); |
| 1151 return arg; | 1165 return arg; |
| 1152 } else if (node.receiver == null) { | 1166 } else if (node.receiver == null) { |
| 1153 // Nodes that fall in this case: | 1167 // Nodes that fall in this case: |
| 1154 // - Unresolved top-level | 1168 // - Unresolved top-level |
| 1155 // - Assignment to final variable (will not be resolved) | 1169 // - Assignment to final variable (will not be resolved) |
| 1156 return giveup(); | 1170 return giveup(node, 'SendSet: non-local, non-static, but no receiver'); |
| 1157 } else { | 1171 } else { |
| 1158 // Setter or index-setter invocation | 1172 // Setter or index-setter invocation |
| 1159 assert(node.receiver != null); | 1173 assert(node.receiver != null); |
| 1160 if (node.receiver.isSuper()) return giveup(); | 1174 if (node.receiver.isSuper()) return giveup(node, 'Super SendSet'); |
| 1161 | 1175 |
| 1162 ir.Primitive receiver = visit(node.receiver); | 1176 ir.Primitive receiver = visit(node.receiver); |
| 1163 ir.Parameter v = new ir.Parameter(null); | 1177 ir.Parameter v = new ir.Parameter(null); |
| 1164 ir.Continuation k = new ir.Continuation([v]); | 1178 ir.Continuation k = new ir.Continuation([v]); |
| 1165 Selector selector = elements.getSelector(node); | 1179 Selector selector = elements.getSelector(node); |
| 1166 assert(selector.kind == SelectorKind.SETTER || | 1180 assert(selector.kind == SelectorKind.SETTER || |
| 1167 selector.kind == SelectorKind.INDEX); | 1181 selector.kind == SelectorKind.INDEX); |
| 1168 List<ir.Definition> args = node.arguments.mapToList(visit, | 1182 List<ir.Definition> args = node.arguments.mapToList(visit, |
| 1169 growable:false); | 1183 growable:false); |
| 1170 ir.InvokeMethod invoke = | 1184 ir.InvokeMethod invoke = |
| 1171 new ir.InvokeMethod(receiver, selector, k, args); | 1185 new ir.InvokeMethod(receiver, selector, k, args); |
| 1172 add(new ir.LetCont(k, invoke)); | 1186 add(new ir.LetCont(k, invoke)); |
| 1173 return args.last; | 1187 return args.last; |
| 1174 } | 1188 } |
| 1175 } else if (ast.Operator.COMPLEX_OPERATORS.contains(op.source)) { | 1189 } else if (ast.Operator.COMPLEX_OPERATORS.contains(op.source)) { |
| 1176 Element selectorElement = elements[node.selector]; | 1190 Element selectorElement = elements[node.selector]; |
| 1177 if (selectorElement != null && !selectorElement.isAssignable) { | 1191 if (selectorElement != null && !selectorElement.isAssignable) { |
| 1178 return giveup(); | 1192 return giveup(node, 'Unresolved or non-assignable compound assignment'); |
| 1179 } | 1193 } |
| 1180 if (!Elements.isLocal(selectorElement)) return giveup(); | 1194 if (!Elements.isLocal(selectorElement)) { |
| 1195 return giveup(node, 'Non-local compound assignment'); |
| 1196 } |
| 1181 | 1197 |
| 1182 Selector selector = elements.getOperatorSelectorInComplexSendSet(node); | 1198 Selector selector = elements.getOperatorSelectorInComplexSendSet(node); |
| 1183 getter = lookupLocal(selectorElement); | 1199 getter = lookupLocal(selectorElement); |
| 1184 | 1200 |
| 1185 ir.Primitive arg; | 1201 ir.Primitive arg; |
| 1186 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) { | 1202 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) { |
| 1187 assert(node.arguments.isEmpty); | 1203 assert(node.arguments.isEmpty); |
| 1188 arg = new ir.Constant(constantSystem.createInt(1)); | 1204 arg = new ir.Constant(constantSystem.createInt(1)); |
| 1189 add(new ir.LetPrim(arg)); | 1205 add(new ir.LetPrim(arg)); |
| 1190 } else { | 1206 } else { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1210 } else { | 1226 } else { |
| 1211 compiler.internalError(node, "Unknown assignment operator ${op.source}"); | 1227 compiler.internalError(node, "Unknown assignment operator ${op.source}"); |
| 1212 return null; | 1228 return null; |
| 1213 } | 1229 } |
| 1214 } | 1230 } |
| 1215 | 1231 |
| 1216 ir.Primitive visitNewExpression(ast.NewExpression node) { | 1232 ir.Primitive visitNewExpression(ast.NewExpression node) { |
| 1217 assert(isOpen); | 1233 assert(isOpen); |
| 1218 FunctionElement element = elements[node.send]; | 1234 FunctionElement element = elements[node.send]; |
| 1219 if (Elements.isUnresolved(element)) { | 1235 if (Elements.isUnresolved(element)) { |
| 1220 return giveup(); | 1236 return giveup(node, 'NewExpression: unresolved constructor'); |
| 1221 } | 1237 } |
| 1222 Selector selector = elements.getSelector(node.send); | 1238 Selector selector = elements.getSelector(node.send); |
| 1223 ast.Node selectorNode = node.send.selector; | 1239 ast.Node selectorNode = node.send.selector; |
| 1224 GenericType type = elements.getType(node); | 1240 GenericType type = elements.getType(node); |
| 1225 List<ir.Definition> args = node.send.arguments.mapToList(visit, | 1241 List<ir.Primitive> args = |
| 1226 growable:false); | 1242 node.send.arguments.mapToList(visit, growable:false); |
| 1227 if (node.isConst) { | 1243 if (node.isConst) { |
| 1228 List<ir.Primitive> arguments = new List<ir.Primitive>(); | 1244 ir.Primitive result = new ir.InvokeConstConstructor(type, element, |
| 1229 node.send.arguments.forEach((ast.Node node) { | 1245 selector, args, getConstantForNode(node)); |
| 1230 arguments.add(visit(node)); | |
| 1231 }); | |
| 1232 ir.Primitive result = new ir.InvokeConstConstructor(type, element, selecto
r, | |
| 1233 arguments); | |
| 1234 add(new ir.LetPrim(result)); | 1246 add(new ir.LetPrim(result)); |
| 1235 return result; | 1247 return result; |
| 1236 } | 1248 } |
| 1237 ir.Parameter v = new ir.Parameter(null); | 1249 ir.Parameter v = new ir.Parameter(null); |
| 1238 ir.Continuation k = new ir.Continuation([v]); | 1250 ir.Continuation k = new ir.Continuation([v]); |
| 1239 ir.InvokeConstructor invoke = new ir.InvokeConstructor( | 1251 ir.InvokeConstructor invoke = |
| 1240 type, | 1252 new ir.InvokeConstructor(type, element,selector, k, args); |
| 1241 element, | |
| 1242 selector, | |
| 1243 k, | |
| 1244 args); | |
| 1245 add(new ir.LetCont(k, invoke)); | 1253 add(new ir.LetCont(k, invoke)); |
| 1246 return v; | 1254 return v; |
| 1247 } | 1255 } |
| 1248 | 1256 |
| 1249 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) { | 1257 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) { |
| 1250 ir.Primitive first = visit(node.first); | 1258 ir.Primitive first = visit(node.first); |
| 1251 ir.Primitive second = visit(node.second); | 1259 ir.Primitive second = visit(node.second); |
| 1252 ir.Parameter v = new ir.Parameter(null); | 1260 ir.Parameter v = new ir.Parameter(null); |
| 1253 ir.Continuation k = new ir.Continuation([v]); | 1261 ir.Continuation k = new ir.Continuation([v]); |
| 1254 ir.ConcatenateStrings concat = | 1262 ir.ConcatenateStrings concat = |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1268 } | 1276 } |
| 1269 ir.Parameter v = new ir.Parameter(null); | 1277 ir.Parameter v = new ir.Parameter(null); |
| 1270 ir.Continuation k = new ir.Continuation([v]); | 1278 ir.Continuation k = new ir.Continuation([v]); |
| 1271 ir.ConcatenateStrings concat = new ir.ConcatenateStrings(k, arguments); | 1279 ir.ConcatenateStrings concat = new ir.ConcatenateStrings(k, arguments); |
| 1272 add(new ir.LetCont(k, concat)); | 1280 add(new ir.LetCont(k, concat)); |
| 1273 return v; | 1281 return v; |
| 1274 } | 1282 } |
| 1275 | 1283 |
| 1276 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 1284 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| 1277 | 1285 |
| 1278 ir.Primitive giveup() => throw ABORT_IRNODE_BUILDER; | 1286 ir.Primitive giveup(ast.Node node, [String reason]) { |
| 1287 throw ABORT_IRNODE_BUILDER; |
| 1288 } |
| 1279 | 1289 |
| 1280 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { | 1290 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { |
| 1281 try { | 1291 try { |
| 1282 return action(); | 1292 return action(); |
| 1283 } catch(e) { | 1293 } catch(e) { |
| 1284 if (e == ABORT_IRNODE_BUILDER) return null; | 1294 if (e == ABORT_IRNODE_BUILDER) return null; |
| 1285 rethrow; | 1295 rethrow; |
| 1286 } | 1296 } |
| 1287 } | 1297 } |
| 1288 | 1298 |
| 1289 void internalError(String reason, {ast.Node node}) { | 1299 void internalError(String reason, {ast.Node node}) { |
| 1290 giveup(); | 1300 giveup(node); |
| 1291 } | 1301 } |
| 1292 } | 1302 } |
| 1293 | 1303 |
| 1294 // While we don't support all constants we need to filter out the unsupported | |
| 1295 // ones: | |
| 1296 class SupportedConstantVisitor extends ConstantVisitor<bool> { | |
| 1297 const SupportedConstantVisitor(); | |
| 1298 | |
| 1299 bool visit(Constant constant) => constant.accept(this); | |
| 1300 bool visitFunction(FunctionConstant constant) => false; | |
| 1301 bool visitNull(NullConstant constant) => true; | |
| 1302 bool visitInt(IntConstant constant) => true; | |
| 1303 bool visitDouble(DoubleConstant constant) => true; | |
| 1304 bool visitTrue(TrueConstant constant) => true; | |
| 1305 bool visitFalse(FalseConstant constant) => true; | |
| 1306 bool visitString(StringConstant constant) => true; | |
| 1307 bool visitList(ListConstant constant) { | |
| 1308 return constant.entries.every(visit); | |
| 1309 } | |
| 1310 bool visitMap(MapConstant constant) { | |
| 1311 return visit(constant.keys) && constant.values.every(visit); | |
| 1312 } | |
| 1313 bool visitConstructed(ConstructedConstant constant) => false; | |
| 1314 bool visitType(TypeConstant constant) => false; | |
| 1315 bool visitInterceptor(InterceptorConstant constant) => false; | |
| 1316 bool visitDummy(DummyConstant constant) => false; | |
| 1317 bool visitDeferred(DeferredConstant constant) => false; | |
| 1318 } | |
| 1319 | |
| OLD | NEW |