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 '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) return giveup(node); // TODO(asgerf): const vars | |
| 619 for (ast.Node definition in node.definitions.nodes) { | 626 for (ast.Node definition in node.definitions.nodes) { |
| 620 Element element = elements[definition]; | 627 Element element = elements[definition]; |
| 621 // Definitions are either SendSets if there is an initializer, or | 628 // Definitions are either SendSets if there is an initializer, or |
| 622 // Identifiers if there is no initializer. | 629 // Identifiers if there is no initializer. |
| 623 if (definition is ast.SendSet) { | 630 if (definition is ast.SendSet) { |
| 624 assert(!definition.arguments.isEmpty); | 631 assert(!definition.arguments.isEmpty); |
| 625 assert(definition.arguments.tail.isEmpty); | 632 assert(definition.arguments.tail.isEmpty); |
| 626 ir.Primitive initialValue = visit(definition.arguments.head); | 633 ir.Primitive initialValue = visit(definition.arguments.head); |
| 627 // In case a primitive was introduced for the initializer expression, | 634 // In case a primitive was introduced for the initializer expression, |
| 628 // use this variable element to help derive a good name for it. | 635 // use this variable element to help derive a good name for it. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 645 return null; | 652 return null; |
| 646 } | 653 } |
| 647 | 654 |
| 648 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 655 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 649 // where (C', x) = Build(e, C) | 656 // where (C', x) = Build(e, C) |
| 650 // | 657 // |
| 651 // Return without a subexpression is translated as if it were return null. | 658 // Return without a subexpression is translated as if it were return null. |
| 652 ir.Primitive visitReturn(ast.Return node) { | 659 ir.Primitive visitReturn(ast.Return node) { |
| 653 assert(isOpen); | 660 assert(isOpen); |
| 654 // TODO(lry): support native returns. | 661 // TODO(lry): support native returns. |
| 655 if (node.beginToken.value == 'native') return giveup(); | 662 if (node.beginToken.value == 'native') return giveup(node); |
| 656 ir.Primitive value; | 663 ir.Primitive value; |
| 657 if (node.expression == null) { | 664 if (node.expression == null) { |
| 658 value = new ir.Constant(constantSystem.createNull()); | 665 value = new ir.Constant(constantSystem.createNull()); |
| 659 add(new ir.LetPrim(value)); | 666 add(new ir.LetPrim(value)); |
| 660 } else { | 667 } else { |
| 661 value = visit(node.expression); | 668 value = visit(node.expression); |
| 662 } | 669 } |
| 663 add(new ir.InvokeContinuation(returnContinuation, [value])); | 670 add(new ir.InvokeContinuation(returnContinuation, [value])); |
| 664 current = null; | 671 current = null; |
| 665 return null; | 672 return null; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 762 } | 769 } |
| 763 | 770 |
| 764 Constant getConstantForNode(ast.Node node) { | 771 Constant getConstantForNode(ast.Node node) { |
| 765 Constant constant = | 772 Constant constant = |
| 766 compiler.backend.constants.getConstantForNode(node, elements); | 773 compiler.backend.constants.getConstantForNode(node, elements); |
| 767 assert(invariant(node, constant != null, | 774 assert(invariant(node, constant != null, |
| 768 message: 'No constant computed for $node')); | 775 message: 'No constant computed for $node')); |
| 769 return constant; | 776 return constant; |
| 770 } | 777 } |
| 771 | 778 |
| 772 bool isSupportedConst(Constant constant) { | |
| 773 return const SupportedConstantVisitor().visit(constant); | |
| 774 } | |
| 775 | |
| 776 ir.Primitive visitLiteralList(ast.LiteralList node) { | 779 ir.Primitive visitLiteralList(ast.LiteralList node) { |
| 777 assert(isOpen); | 780 assert(isOpen); |
| 778 ir.Primitive result; | 781 List<ir.Primitive> values = node.elements.nodes.mapToList(visit); |
| 779 if (node.isConst) { | 782 Constant constant = node.isConst ? getConstantForNode(node) : null; |
| 780 // TODO(sigurdm): Remove when all constants are supported. | 783 GenericType type = elements.getType(node); |
| 781 Constant constant = getConstantForNode(node); | 784 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)); | 785 add(new ir.LetPrim(result)); |
| 792 return result; | 786 return result; |
| 793 } | 787 } |
| 794 | 788 |
| 795 ir.Primitive visitLiteralMap(ast.LiteralMap node) { | 789 ir.Primitive visitLiteralMap(ast.LiteralMap node) { |
| 796 assert(isOpen); | 790 assert(isOpen); |
| 797 ir.Primitive result; | 791 List<ir.Primitive> keys = new List<ir.Primitive>(); |
| 798 if (node.isConst) { | 792 List<ir.Primitive> values = new List<ir.Primitive>(); |
| 799 // TODO(sigurdm): Remove when all constants are supported. | 793 node.entries.nodes.forEach((ast.LiteralMapEntry node) { |
| 800 Constant constant = getConstantForNode(node); | 794 keys.add(visit(node.key)); |
| 801 if (!isSupportedConst(constant)) return giveup(); | 795 values.add(visit(node.value)); |
| 802 result = new ir.Constant(constant); | 796 }); |
| 803 } else { | 797 GenericType type = elements.getType(node); |
| 804 List<ir.Primitive> keys = new List<ir.Primitive>(); | 798 Constant constant = node.isConst ? getConstantForNode(node) : null; |
| 805 List<ir.Primitive> values = new List<ir.Primitive>(); | 799 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)); | 800 add(new ir.LetPrim(result)); |
| 813 return result; | 801 return result; |
| 814 } | 802 } |
| 815 | 803 |
| 816 ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) { | 804 ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) { |
| 817 assert(isOpen); | 805 assert(isOpen); |
| 818 ir.Constant constant = new ir.Constant(getConstantForNode(node)); | 806 ir.Constant constant = new ir.Constant(getConstantForNode(node)); |
| 819 add(new ir.LetPrim(constant)); | 807 add(new ir.LetPrim(constant)); |
| 820 return constant; | 808 return constant; |
| 821 } | 809 } |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 848 | 836 |
| 849 ir.Primitive lookupLocal(Element element) { | 837 ir.Primitive lookupLocal(Element element) { |
| 850 int index = variableIndex[element]; | 838 int index = variableIndex[element]; |
| 851 ir.Primitive value = assignedVars[index]; | 839 ir.Primitive value = assignedVars[index]; |
| 852 return value == null ? freeVars[index] : value; | 840 return value == null ? freeVars[index] : value; |
| 853 } | 841 } |
| 854 | 842 |
| 855 // ==== Sends ==== | 843 // ==== Sends ==== |
| 856 ir.Primitive visitAssert(ast.Send node) { | 844 ir.Primitive visitAssert(ast.Send node) { |
| 857 assert(isOpen); | 845 assert(isOpen); |
| 858 return giveup(); | 846 return giveup(node); |
| 859 } | 847 } |
| 860 | 848 |
| 861 ir.Primitive visitNamedArgument(ast.NamedArgument node) { | 849 ir.Primitive visitNamedArgument(ast.NamedArgument node) { |
| 862 assert(isOpen); | 850 assert(isOpen); |
| 863 return visit(node.expression); | 851 return visit(node.expression); |
| 864 } | 852 } |
| 865 | 853 |
| 866 ir.Primitive visitClosureSend(ast.Send node) { | 854 ir.Primitive visitClosureSend(ast.Send node) { |
| 867 assert(isOpen); | 855 assert(isOpen); |
| 868 Selector closureSelector = elements.getSelector(node); | 856 Selector closureSelector = elements.getSelector(node); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 888 ir.Continuation k = new ir.Continuation([v]); | 876 ir.Continuation k = new ir.Continuation([v]); |
| 889 ir.Expression invoke = | 877 ir.Expression invoke = |
| 890 new ir.InvokeMethod(closureTarget, namedCallSelector, k, arguments); | 878 new ir.InvokeMethod(closureTarget, namedCallSelector, k, arguments); |
| 891 add(new ir.LetCont(k, invoke)); | 879 add(new ir.LetCont(k, invoke)); |
| 892 return v; | 880 return v; |
| 893 } | 881 } |
| 894 | 882 |
| 895 ir.Primitive visitDynamicSend(ast.Send node) { | 883 ir.Primitive visitDynamicSend(ast.Send node) { |
| 896 assert(isOpen); | 884 assert(isOpen); |
| 897 if (node.receiver == null || node.receiver.isSuper()) { | 885 if (node.receiver == null || node.receiver.isSuper()) { |
| 898 return giveup(); | 886 return giveup(node); |
| 899 } | 887 } |
| 900 Selector selector = elements.getSelector(node); | 888 Selector selector = elements.getSelector(node); |
| 901 ir.Primitive receiver = visit(node.receiver); | 889 ir.Primitive receiver = visit(node.receiver); |
| 902 List<ir.Primitive> arguments = new List<ir.Primitive>(); | 890 List<ir.Primitive> arguments = new List<ir.Primitive>(); |
| 903 for (ast.Node n in node.arguments) { | 891 for (ast.Node n in node.arguments) { |
| 904 arguments.add(visit(n)); | 892 arguments.add(visit(n)); |
| 905 } | 893 } |
| 906 ir.Parameter v = new ir.Parameter(null); | 894 ir.Parameter v = new ir.Parameter(null); |
| 907 ir.Continuation k = new ir.Continuation([v]); | 895 ir.Continuation k = new ir.Continuation([v]); |
| 908 ir.Expression invoke = | 896 ir.Expression invoke = |
| 909 new ir.InvokeMethod(receiver, selector, k, arguments); | 897 new ir.InvokeMethod(receiver, selector, k, arguments); |
| 910 add(new ir.LetCont(k, invoke)); | 898 add(new ir.LetCont(k, invoke)); |
| 911 return v; | 899 return v; |
| 912 } | 900 } |
| 913 | 901 |
| 914 ir.Primitive visitGetterSend(ast.Send node) { | 902 ir.Primitive visitGetterSend(ast.Send node) { |
| 915 assert(isOpen); | 903 assert(isOpen); |
| 916 Element element = elements[node]; | 904 Element element = elements[node]; |
| 917 if (Elements.isLocal(element)) { | 905 if (Elements.isLocal(element)) { |
| 918 return lookupLocal(element); | 906 return lookupLocal(element); |
| 919 } else if (element == null || Elements.isInstanceField(element)) { | 907 } else if (element == null || Elements.isInstanceField(element)) { |
| 920 // TODO: Support implicit this. | 908 // TODO: Support implicit this. |
| 921 if (node.receiver == null) return giveup(); | 909 if (node.receiver == null) return giveup(node); |
| 922 | 910 |
| 923 ir.Primitive receiver = visit(node.receiver); | 911 ir.Primitive receiver = visit(node.receiver); |
| 924 ir.Parameter v = new ir.Parameter(null); | 912 ir.Parameter v = new ir.Parameter(null); |
| 925 ir.Continuation k = new ir.Continuation([v]); | 913 ir.Continuation k = new ir.Continuation([v]); |
| 926 Selector selector = elements.getSelector(node); | 914 Selector selector = elements.getSelector(node); |
| 927 assert(selector.kind == SelectorKind.GETTER); | 915 assert(selector.kind == SelectorKind.GETTER); |
| 928 ir.InvokeMethod invoke = new ir.InvokeMethod(receiver, selector, k, []); | 916 ir.InvokeMethod invoke = new ir.InvokeMethod(receiver, selector, k, []); |
| 929 add(new ir.LetCont(k, invoke)); | 917 add(new ir.LetCont(k, invoke)); |
| 930 return v; | 918 return v; |
| 931 } else if (element.isField) { | 919 } else if (element.isField) { |
| 932 ir.Parameter v = new ir.Parameter(null); | 920 ir.Parameter v = new ir.Parameter(null); |
| 933 ir.Continuation k = new ir.Continuation([v]); | 921 ir.Continuation k = new ir.Continuation([v]); |
| 934 Selector selector = elements.getSelector(node); | 922 Selector selector = elements.getSelector(node); |
| 935 assert(selector.kind == SelectorKind.GETTER); | 923 assert(selector.kind == SelectorKind.GETTER); |
| 936 ir.InvokeStatic invoke = new ir.InvokeStatic(element, selector, k, []); | 924 ir.InvokeStatic invoke = new ir.InvokeStatic(element, selector, k, []); |
| 937 add(new ir.LetCont(k, invoke)); | 925 add(new ir.LetCont(k, invoke)); |
| 938 return v; | 926 return v; |
| 927 } else if (Elements.isStaticOrTopLevelFunction(element)) { | |
| 928 ir.Primitive prim = new ir.Constant(new FunctionConstant(element)); | |
| 929 add(new ir.LetPrim(prim)); | |
| 930 return prim; | |
| 939 } else { | 931 } else { |
| 940 return giveup(); // TODO: figure out what's missing here | 932 return giveup(node); // TODO(asgerf): figure out what's missing here |
| 941 } | 933 } |
| 942 } | 934 } |
| 943 | 935 |
| 944 ir.Primitive translateLogicalOperator(ast.Operator op, | 936 ir.Primitive translateLogicalOperator(ast.Operator op, |
| 945 ast.Expression left, | 937 ast.Expression left, |
| 946 ast.Expression right) { | 938 ast.Expression right) { |
| 947 // e0 && e1 is translated as if e0 ? (e1 == true) : false. | 939 // e0 && e1 is translated as if e0 ? (e1 == true) : false. |
| 948 // e0 || e1 is translated as if e0 ? true : (e1 == true). | 940 // e0 || e1 is translated as if e0 ? true : (e1 == true). |
| 949 // The translation must convert both e0 and e1 to booleans and handle | 941 // The translation must convert both e0 and e1 to booleans and handle |
| 950 // local variable assignments in e1. | 942 // local variable assignments in e1. |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1035 ast.Operator op = node.selector; | 1027 ast.Operator op = node.selector; |
| 1036 if (isUserDefinableOperator(op.source)) { | 1028 if (isUserDefinableOperator(op.source)) { |
| 1037 return visitDynamicSend(node); | 1029 return visitDynamicSend(node); |
| 1038 } | 1030 } |
| 1039 if (op.source == '&&' || op.source == '||') { | 1031 if (op.source == '&&' || op.source == '||') { |
| 1040 assert(node.receiver != null); | 1032 assert(node.receiver != null); |
| 1041 assert(!node.arguments.isEmpty); | 1033 assert(!node.arguments.isEmpty); |
| 1042 assert(node.arguments.tail.isEmpty); | 1034 assert(node.arguments.tail.isEmpty); |
| 1043 return translateLogicalOperator(op, node.receiver, node.arguments.head); | 1035 return translateLogicalOperator(op, node.receiver, node.arguments.head); |
| 1044 } | 1036 } |
| 1045 return giveup(); | 1037 return giveup(node); |
| 1046 } | 1038 } |
| 1047 | 1039 |
| 1048 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] | 1040 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] |
| 1049 // where (C', xs) = arguments.fold(Build, C) | 1041 // where (C', xs) = arguments.fold(Build, C) |
| 1050 ir.Primitive visitStaticSend(ast.Send node) { | 1042 ir.Primitive visitStaticSend(ast.Send node) { |
| 1051 assert(isOpen); | 1043 assert(isOpen); |
| 1052 Element element = elements[node]; | 1044 Element element = elements[node]; |
| 1053 // TODO(lry): support constructors / factory calls. | 1045 // TODO(lry): support constructors / factory calls. |
| 1054 if (element.isConstructor) return giveup(); | 1046 if (element.isConstructor) return giveup(node); |
| 1055 // TODO(lry): support foreign functions. | 1047 // TODO(lry): support foreign functions. |
| 1056 if (element.isForeign(compiler)) return giveup(); | 1048 if (element.isForeign(compiler)) return giveup(node); |
| 1057 // TODO(lry): for elements that could not be resolved emit code to throw a | 1049 // TODO(lry): for elements that could not be resolved emit code to throw a |
| 1058 // [NoSuchMethodError]. | 1050 // [NoSuchMethodError]. |
| 1059 if (element.isErroneous) return giveup(); | 1051 if (element.isErroneous) return giveup(node); |
| 1060 // TODO(lry): generate IR for object identicality. | 1052 // TODO(lry): generate IR for object identicality. |
| 1061 if (element == compiler.identicalFunction) giveup(); | 1053 if (element == compiler.identicalFunction) giveup(node); |
| 1062 | 1054 |
| 1063 Selector selector = elements.getSelector(node); | 1055 Selector selector = elements.getSelector(node); |
| 1064 | 1056 |
| 1065 // TODO(lry): support default arguments, need support for locals. | 1057 // TODO(lry): support default arguments, need support for locals. |
| 1066 List<ir.Definition> arguments = node.arguments.mapToList(visit, | 1058 List<ir.Definition> arguments = node.arguments.mapToList(visit, |
| 1067 growable:false); | 1059 growable:false); |
| 1068 ir.Parameter v = new ir.Parameter(null); | 1060 ir.Parameter v = new ir.Parameter(null); |
| 1069 ir.Continuation k = new ir.Continuation([v]); | 1061 ir.Continuation k = new ir.Continuation([v]); |
| 1070 ir.Expression invoke = | 1062 ir.Expression invoke = |
| 1071 new ir.InvokeStatic(element, selector, k, arguments); | 1063 new ir.InvokeStatic(element, selector, k, arguments); |
| 1072 add(new ir.LetCont(k, invoke)); | 1064 add(new ir.LetCont(k, invoke)); |
| 1073 return v; | 1065 return v; |
| 1074 } | 1066 } |
| 1075 | 1067 |
| 1076 ir.Primitive visitSuperSend(ast.Send node) { | 1068 ir.Primitive visitSuperSend(ast.Send node) { |
| 1077 assert(isOpen); | 1069 assert(isOpen); |
| 1078 return giveup(); | 1070 return giveup(node); |
| 1079 } | 1071 } |
| 1080 | 1072 |
| 1081 ir.Primitive visitTypeReferenceSend(ast.Send node) { | 1073 ir.Primitive visitTypeReferenceSend(ast.Send node) { |
| 1082 assert(isOpen); | 1074 assert(isOpen); |
| 1083 return giveup(); | 1075 if (node.argumentsNode != null) { |
| 1076 // May happen in strange, invalid code. | |
| 1077 // TODO(asgerf): Generate code that throws a runtime error. | |
| 1078 return giveup(node); | |
| 1079 } | |
| 1080 Element element = elements[node]; | |
| 1081 if (element is TypeDeclarationElement) { | |
| 1082 DartType typeType = compiler.backend.typeImplementation.rawType; | |
| 1083 ir.Primitive prim = | |
| 1084 new ir.Constant(new TypeConstant(element.rawType, typeType)); | |
| 1085 add(new ir.LetPrim(prim)); | |
| 1086 return prim; | |
| 1087 } else if (element.isTypeVariable) { | |
| 1088 // TODO(asgerf): Introduce IR to reify type variables | |
| 1089 return giveup(node); | |
| 1090 } else { | |
| 1091 // TODO(asgerf): Any other cases? | |
| 1092 return giveup(node); | |
| 1093 } | |
| 1084 } | 1094 } |
| 1085 | 1095 |
| 1086 ir.Primitive visitSendSet(ast.SendSet node) { | 1096 ir.Primitive visitSendSet(ast.SendSet node) { |
| 1087 assert(isOpen); | 1097 assert(isOpen); |
| 1088 Element element = elements[node]; | 1098 Element element = elements[node]; |
| 1089 ast.Operator op = node.assignmentOperator; | 1099 ast.Operator op = node.assignmentOperator; |
| 1090 ir.Primitive result; | 1100 ir.Primitive result; |
| 1091 ir.Primitive getter; | 1101 ir.Primitive getter; |
| 1092 if (op.source == '=') { | 1102 if (op.source == '=') { |
| 1093 if (Elements.isLocal(element)) { | 1103 if (Elements.isLocal(element)) { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1106 Selector selector = elements.getSelector(node); | 1116 Selector selector = elements.getSelector(node); |
| 1107 ir.Definition arg = visit(node.arguments.head); | 1117 ir.Definition arg = visit(node.arguments.head); |
| 1108 ir.InvokeStatic invoke = | 1118 ir.InvokeStatic invoke = |
| 1109 new ir.InvokeStatic(element, selector, k, [arg]); | 1119 new ir.InvokeStatic(element, selector, k, [arg]); |
| 1110 add(new ir.LetCont(k, invoke)); | 1120 add(new ir.LetCont(k, invoke)); |
| 1111 return arg; | 1121 return arg; |
| 1112 } else if (node.receiver == null) { | 1122 } else if (node.receiver == null) { |
| 1113 // Nodes that fall in this case: | 1123 // Nodes that fall in this case: |
| 1114 // - Unresolved top-level | 1124 // - Unresolved top-level |
| 1115 // - Assignment to final variable (will not be resolved) | 1125 // - Assignment to final variable (will not be resolved) |
| 1116 return giveup(); | 1126 return giveup(node); |
| 1117 } else { | 1127 } else { |
| 1118 // Setter or index-setter invocation | 1128 // Setter or index-setter invocation |
| 1119 assert(node.receiver != null); | 1129 assert(node.receiver != null); |
| 1120 if (node.receiver.isSuper()) return giveup(); | 1130 if (node.receiver.isSuper()) return giveup(node); |
| 1121 | 1131 |
| 1122 ir.Primitive receiver = visit(node.receiver); | 1132 ir.Primitive receiver = visit(node.receiver); |
| 1123 ir.Parameter v = new ir.Parameter(null); | 1133 ir.Parameter v = new ir.Parameter(null); |
| 1124 ir.Continuation k = new ir.Continuation([v]); | 1134 ir.Continuation k = new ir.Continuation([v]); |
| 1125 Selector selector = elements.getSelector(node); | 1135 Selector selector = elements.getSelector(node); |
| 1126 assert(selector.kind == SelectorKind.SETTER || | 1136 assert(selector.kind == SelectorKind.SETTER || |
| 1127 selector.kind == SelectorKind.INDEX); | 1137 selector.kind == SelectorKind.INDEX); |
| 1128 List<ir.Definition> args = node.arguments.mapToList(visit, | 1138 List<ir.Definition> args = node.arguments.mapToList(visit, |
| 1129 growable:false); | 1139 growable:false); |
| 1130 ir.InvokeMethod invoke = | 1140 ir.InvokeMethod invoke = |
| 1131 new ir.InvokeMethod(receiver, selector, k, args); | 1141 new ir.InvokeMethod(receiver, selector, k, args); |
| 1132 add(new ir.LetCont(k, invoke)); | 1142 add(new ir.LetCont(k, invoke)); |
| 1133 return args.last; | 1143 return args.last; |
| 1134 } | 1144 } |
| 1135 } else if (ast.Operator.COMPLEX_OPERATORS.contains(op.source)) { | 1145 } else if (ast.Operator.COMPLEX_OPERATORS.contains(op.source)) { |
| 1136 Element selectorElement = elements[node.selector]; | 1146 Element selectorElement = elements[node.selector]; |
| 1137 if (selectorElement != null && !selectorElement.isAssignable) { | 1147 if (selectorElement != null && !selectorElement.isAssignable) { |
| 1138 return giveup(); | 1148 return giveup(node); |
| 1139 } | 1149 } |
| 1140 if (!Elements.isLocal(selectorElement)) return giveup(); | 1150 if (!Elements.isLocal(selectorElement)) return giveup(node); |
| 1141 | 1151 |
| 1142 Selector selector = elements.getOperatorSelectorInComplexSendSet(node); | 1152 Selector selector = elements.getOperatorSelectorInComplexSendSet(node); |
| 1143 getter = lookupLocal(selectorElement); | 1153 getter = lookupLocal(selectorElement); |
| 1144 | 1154 |
| 1145 ir.Primitive arg; | 1155 ir.Primitive arg; |
| 1146 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) { | 1156 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) { |
| 1147 assert(node.arguments.isEmpty); | 1157 assert(node.arguments.isEmpty); |
| 1148 arg = new ir.Constant(constantSystem.createInt(1)); | 1158 arg = new ir.Constant(constantSystem.createInt(1)); |
| 1149 add(new ir.LetPrim(arg)); | 1159 add(new ir.LetPrim(arg)); |
| 1150 } else { | 1160 } else { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 1170 } else { | 1180 } else { |
| 1171 compiler.internalError(node, "Unknown assignment operator ${op.source}"); | 1181 compiler.internalError(node, "Unknown assignment operator ${op.source}"); |
| 1172 return null; | 1182 return null; |
| 1173 } | 1183 } |
| 1174 } | 1184 } |
| 1175 | 1185 |
| 1176 ir.Primitive visitNewExpression(ast.NewExpression node) { | 1186 ir.Primitive visitNewExpression(ast.NewExpression node) { |
| 1177 assert(isOpen); | 1187 assert(isOpen); |
| 1178 FunctionElement element = elements[node.send]; | 1188 FunctionElement element = elements[node.send]; |
| 1179 if (Elements.isUnresolved(element)) { | 1189 if (Elements.isUnresolved(element)) { |
| 1180 return giveup(); | 1190 return giveup(node); |
| 1181 } | 1191 } |
| 1182 Selector selector = elements.getSelector(node.send); | 1192 Selector selector = elements.getSelector(node.send); |
| 1183 ast.Node selectorNode = node.send.selector; | 1193 ast.Node selectorNode = node.send.selector; |
| 1184 GenericType type = elements.getType(node); | 1194 GenericType type = elements.getType(node); |
| 1185 List<ir.Definition> args = node.send.arguments.mapToList(visit, | 1195 List<ir.Primitive> args = |
| 1186 growable:false); | 1196 node.send.arguments.mapToList(visit, growable:false); |
| 1187 if (node.isConst) { | 1197 if (node.isConst) { |
| 1188 List<ir.Primitive> arguments = new List<ir.Primitive>(); | 1198 ir.Primitive result = new ir.InvokeConstConstructor(type, element, |
| 1189 node.send.arguments.forEach((ast.Node node) { | 1199 selector, args, getConstantForNode(node)); |
| 1190 arguments.add(visit(node)); | |
| 1191 }); | |
| 1192 ir.Primitive result = new ir.InvokeConstConstructor(type, element, selecto r, | |
| 1193 arguments); | |
| 1194 add(new ir.LetPrim(result)); | 1200 add(new ir.LetPrim(result)); |
| 1195 return result; | 1201 return result; |
| 1196 } | 1202 } |
| 1197 ir.Parameter v = new ir.Parameter(null); | 1203 ir.Parameter v = new ir.Parameter(null); |
| 1198 ir.Continuation k = new ir.Continuation([v]); | 1204 ir.Continuation k = new ir.Continuation([v]); |
| 1199 ir.InvokeConstructor invoke = new ir.InvokeConstructor( | 1205 ir.InvokeConstructor invoke = |
| 1200 type, | 1206 new ir.InvokeConstructor(type, element,selector, k, args); |
| 1201 element, | |
| 1202 selector, | |
| 1203 k, | |
| 1204 args); | |
| 1205 add(new ir.LetCont(k, invoke)); | 1207 add(new ir.LetCont(k, invoke)); |
| 1206 return v; | 1208 return v; |
| 1207 } | 1209 } |
| 1208 | 1210 |
| 1209 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) { | 1211 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) { |
| 1210 ir.Primitive first = visit(node.first); | 1212 ir.Primitive first = visit(node.first); |
| 1211 ir.Primitive second = visit(node.second); | 1213 ir.Primitive second = visit(node.second); |
| 1212 ir.Parameter v = new ir.Parameter(null); | 1214 ir.Parameter v = new ir.Parameter(null); |
| 1213 ir.Continuation k = new ir.Continuation([v]); | 1215 ir.Continuation k = new ir.Continuation([v]); |
| 1214 ir.ConcatenateStrings concat = | 1216 ir.ConcatenateStrings concat = |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1228 } | 1230 } |
| 1229 ir.Parameter v = new ir.Parameter(null); | 1231 ir.Parameter v = new ir.Parameter(null); |
| 1230 ir.Continuation k = new ir.Continuation([v]); | 1232 ir.Continuation k = new ir.Continuation([v]); |
| 1231 ir.ConcatenateStrings concat = new ir.ConcatenateStrings(k, arguments); | 1233 ir.ConcatenateStrings concat = new ir.ConcatenateStrings(k, arguments); |
| 1232 add(new ir.LetCont(k, concat)); | 1234 add(new ir.LetCont(k, concat)); |
| 1233 return v; | 1235 return v; |
| 1234 } | 1236 } |
| 1235 | 1237 |
| 1236 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 1238 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| 1237 | 1239 |
| 1238 ir.Primitive giveup() => throw ABORT_IRNODE_BUILDER; | 1240 ir.Primitive giveup(ast.Node node) { |
| 1241 throw ABORT_IRNODE_BUILDER; | |
| 1242 } | |
|
asgerf
2014/06/20 15:02:10
I find myself adding and removing the node paramet
sigurdm
2014/06/23 07:22:20
Yes! And maybe we can even add an optional "reason
Kevin Millikin (Google)
2014/06/23 08:03:06
Yes, please.
| |
| 1239 | 1243 |
| 1240 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { | 1244 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { |
| 1241 try { | 1245 try { |
| 1242 return action(); | 1246 return action(); |
| 1243 } catch(e) { | 1247 } catch(e) { |
| 1244 if (e == ABORT_IRNODE_BUILDER) return null; | 1248 if (e == ABORT_IRNODE_BUILDER) return null; |
| 1245 rethrow; | 1249 rethrow; |
| 1246 } | 1250 } |
| 1247 } | 1251 } |
| 1248 | 1252 |
| 1249 void internalError(String reason, {ast.Node node}) { | 1253 void internalError(String reason, {ast.Node node}) { |
| 1250 giveup(); | 1254 giveup(node); |
| 1251 } | 1255 } |
| 1252 } | 1256 } |
| 1253 | 1257 |
| 1254 // While we don't support all constants we need to filter out the unsupported | |
| 1255 // ones: | |
| 1256 class SupportedConstantVisitor extends ConstantVisitor<bool> { | |
| 1257 const SupportedConstantVisitor(); | |
| 1258 | |
| 1259 bool visit(Constant constant) => constant.accept(this); | |
| 1260 bool visitFunction(FunctionConstant constant) => false; | |
| 1261 bool visitNull(NullConstant constant) => true; | |
| 1262 bool visitInt(IntConstant constant) => true; | |
| 1263 bool visitDouble(DoubleConstant constant) => true; | |
| 1264 bool visitTrue(TrueConstant constant) => true; | |
| 1265 bool visitFalse(FalseConstant constant) => true; | |
| 1266 bool visitString(StringConstant constant) => true; | |
| 1267 bool visitList(ListConstant constant) { | |
| 1268 return constant.entries.every(visit); | |
| 1269 } | |
| 1270 bool visitMap(MapConstant constant) { | |
| 1271 return visit(constant.keys) && constant.values.every(visit); | |
| 1272 } | |
| 1273 bool visitConstructed(ConstructedConstant constant) => false; | |
| 1274 bool visitType(TypeConstant constant) => false; | |
| 1275 bool visitInterceptor(InterceptorConstant constant) => false; | |
| 1276 bool visitDummy(DummyConstant constant) => false; | |
| 1277 bool visitDeferred(DeferredConstant constant) => false; | |
| 1278 } | |
| 1279 | |
| OLD | NEW |