| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 class Interceptors { | 5 class Interceptors { |
| 6 Compiler compiler; | 6 Compiler compiler; |
| 7 Interceptors(Compiler this.compiler); | 7 Interceptors(Compiler this.compiler); |
| 8 | 8 |
| 9 SourceString mapOperatorToMethodName(Operator op) { | 9 SourceString mapOperatorToMethodName(Operator op) { |
| 10 String name = op.source.stringValue; | 10 String name = op.source.stringValue; |
| (...skipping 785 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 796 TreeElements treeElements = | 796 TreeElements treeElements = |
| 797 compiler.resolver.resolveMethodElement(constructor); | 797 compiler.resolver.resolveMethodElement(constructor); |
| 798 compiler.enqueue(new WorkItem.toCodegen(bodyElement, treeElements)); | 798 compiler.enqueue(new WorkItem.toCodegen(bodyElement, treeElements)); |
| 799 classElement.backendMembers = | 799 classElement.backendMembers = |
| 800 classElement.backendMembers.prepend(bodyElement); | 800 classElement.backendMembers.prepend(bodyElement); |
| 801 } | 801 } |
| 802 assert(bodyElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY); | 802 assert(bodyElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY); |
| 803 return bodyElement; | 803 return bodyElement; |
| 804 } | 804 } |
| 805 | 805 |
| 806 void inlineSuperOrRedirect(FunctionElement constructor, |
| 807 Selector selector, |
| 808 Link<Node> arguments, |
| 809 List<FunctionElement> constructors, |
| 810 Map<Element, HInstruction> fieldValues) { |
| 811 constructors.addLast(constructor); |
| 812 |
| 813 List<HInstruction> compiledArguments = new List<HInstruction>(); |
| 814 bool succeeded = addStaticSendArgumentsToList(selector, |
| 815 arguments, |
| 816 constructor, |
| 817 compiledArguments); |
| 818 if (!succeeded) { |
| 819 // Non-matching super and redirects are compile-time errors and thus |
| 820 // checked by the resolver. |
| 821 compiler.internalError( |
| 822 "Parameters and arguments didn't match for super/redirect call", |
| 823 element: constructor); |
| 824 } |
| 825 |
| 826 int index = 0; |
| 827 FunctionParameters parameters = constructor.computeParameters(compiler); |
| 828 parameters.forEachParameter((Element parameter) { |
| 829 HInstruction argument = compiledArguments[index++]; |
| 830 localsHandler.updateLocal(parameter, argument); |
| 831 // Don't forget to update the field, if the parameter is of the |
| 832 // form [:this.x:]. |
| 833 if (parameter.kind == ElementKind.FIELD_PARAMETER) { |
| 834 FieldParameterElement fieldParameterElement = parameter; |
| 835 fieldValues[fieldParameterElement.fieldElement] = argument; |
| 836 } |
| 837 }); |
| 838 |
| 839 // Build the initializers in the context of the new constructor. |
| 840 TreeElements oldElements = elements; |
| 841 elements = compiler.resolver.resolveMethodElement(constructor); |
| 842 buildInitializers(constructor, constructors, fieldValues); |
| 843 elements = oldElements; |
| 844 } |
| 806 /** | 845 /** |
| 807 * Run through the initializers and inline all field initializers. Recursively | 846 * Run through the initializers and inline all field initializers. Recursively |
| 808 * inlines super initializers. | 847 * inlines super initializers. |
| 809 * | 848 * |
| 810 * The constructors of the inlined initializers is added to [constructors] | 849 * The constructors of the inlined initializers is added to [constructors] |
| 811 * with sub constructors having a lower index than super constructors. | 850 * with sub constructors having a lower index than super constructors. |
| 812 */ | 851 */ |
| 813 void inlineInitializers(FunctionElement constructor, | 852 void buildInitializers(FunctionElement constructor, |
| 814 List<FunctionElement> constructors, | 853 List<FunctionElement> constructors, |
| 815 Map<Element, HInstruction> fieldValues) { | 854 Map<Element, HInstruction> fieldValues) { |
| 816 TreeElements oldElements = elements; | |
| 817 constructors.addLast(constructor); | |
| 818 bool initializedSuper = false; | |
| 819 elements = compiler.resolver.resolveMethodElement(constructor); | |
| 820 FunctionExpression functionNode = constructor.parseNode(compiler); | 855 FunctionExpression functionNode = constructor.parseNode(compiler); |
| 821 | 856 |
| 857 bool foundSuperOrRedirect = false; |
| 858 |
| 822 if (functionNode.initializers !== null) { | 859 if (functionNode.initializers !== null) { |
| 823 Link<Node> initializers = functionNode.initializers.nodes; | 860 Link<Node> initializers = functionNode.initializers.nodes; |
| 824 for (Link<Node> link = initializers; !link.isEmpty(); link = link.tail) { | 861 for (Link<Node> link = initializers; !link.isEmpty(); link = link.tail) { |
| 825 assert(link.head is Send); | 862 assert(link.head is Send); |
| 826 if (link.head is !SendSet) { | 863 if (link.head is !SendSet) { |
| 827 // A super initializer or constructor redirection. | 864 // A super initializer or constructor redirection. |
| 828 Send call = link.head; | 865 Send call = link.head; |
| 829 assert(Initializers.isSuperConstructorCall(call) || | 866 assert(Initializers.isSuperConstructorCall(call) || |
| 830 Initializers.isConstructorRedirect(call)); | 867 Initializers.isConstructorRedirect(call)); |
| 831 FunctionElement nextConstructor = elements[call]; | 868 FunctionElement target = elements[call]; |
| 832 // Visit arguments and map the corresponding parameter value to | 869 Selector selector = elements.getSelector(call); |
| 833 // the resulting HInstruction value. | 870 Link<Node> arguments = call.arguments; |
| 834 List<HInstruction> arguments = new List<HInstruction>(); | 871 inlineSuperOrRedirect(target, selector, arguments, constructors, |
| 835 addStaticSendArgumentsToList(call, nextConstructor, arguments); | 872 fieldValues); |
| 836 int index = 0; | 873 foundSuperOrRedirect = true; |
| 837 FunctionParameters parameters = | |
| 838 nextConstructor.computeParameters(compiler); | |
| 839 parameters.forEachParameter((Element parameter) { | |
| 840 HInstruction argument = arguments[index++]; | |
| 841 localsHandler.updateLocal(parameter, argument); | |
| 842 // Don't forget to update the field, if the parameter is of the | |
| 843 // form [:this.x:]. | |
| 844 if (parameter.kind == ElementKind.FIELD_PARAMETER) { | |
| 845 FieldParameterElement fieldParameterElement = parameter; | |
| 846 fieldValues[fieldParameterElement.fieldElement] = argument; | |
| 847 } | |
| 848 }); | |
| 849 inlineInitializers(nextConstructor, constructors, fieldValues); | |
| 850 initializedSuper = true; | |
| 851 } else { | 874 } else { |
| 852 // A field initializer. | 875 // A field initializer. |
| 853 SendSet init = link.head; | 876 SendSet init = link.head; |
| 854 Link<Node> arguments = init.arguments; | 877 Link<Node> arguments = init.arguments; |
| 855 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); | 878 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); |
| 856 visit(arguments.head); | 879 visit(arguments.head); |
| 857 fieldValues[elements[init]] = pop(); | 880 fieldValues[elements[init]] = pop(); |
| 858 } | 881 } |
| 859 } | 882 } |
| 860 } | 883 } |
| 861 | 884 |
| 862 if (!initializedSuper) { | 885 if (!foundSuperOrRedirect) { |
| 863 // No super initializer found. Try to find the default constructor if | 886 // No super initializer found. Try to find the default constructor if |
| 864 // the class is not Object. | 887 // the class is not Object. |
| 865 ClassElement enclosingClass = constructor.enclosingElement; | 888 ClassElement enclosingClass = constructor.enclosingElement; |
| 866 ClassElement superClass = enclosingClass.superclass; | 889 ClassElement superClass = enclosingClass.superclass; |
| 867 if (enclosingClass != compiler.objectClass) { | 890 if (enclosingClass != compiler.objectClass) { |
| 868 assert(superClass !== null); | 891 assert(superClass !== null); |
| 869 assert(superClass.isResolved); | 892 assert(superClass.isResolved); |
| 870 FunctionElement nextConstructor = | 893 FunctionElement target = superClass.lookupConstructor(superClass.name); |
| 871 superClass.lookupConstructor(superClass.name); | 894 if (target === null) { |
| 872 if (nextConstructor === null) { | |
| 873 compiler.internalError("no default constructor available"); | 895 compiler.internalError("no default constructor available"); |
| 874 } | 896 } |
| 875 inlineInitializers(nextConstructor, constructors, fieldValues); | 897 inlineSuperOrRedirect(target, |
| 898 Selector.INVOCATION_0, |
| 899 const EmptyLink<Node>(), |
| 900 constructors, |
| 901 fieldValues); |
| 876 } | 902 } |
| 877 } | 903 } |
| 878 | |
| 879 elements = oldElements; | |
| 880 } | 904 } |
| 881 | 905 |
| 882 /** | 906 /** |
| 883 * Build the factory function corresponding to the constructor | 907 * Build the factory function corresponding to the constructor |
| 884 * [functionElement]: | 908 * [functionElement]: |
| 885 * - Initialize fields with the values of the field initializers of the | 909 * - Initialize fields with the values of the field initializers of the |
| 886 * current constructor and super constructors or constructors redirected | 910 * current constructor and super constructors or constructors redirected |
| 887 * to, starting from the current constructor. | 911 * to, starting from the current constructor. |
| 888 * - Call the the constructor bodies, starting from the constructor(s) in the | 912 * - Call the the constructor bodies, starting from the constructor(s) in the |
| 889 * super class(es). | 913 * super class(es). |
| (...skipping 15 matching lines...) Expand all Loading... |
| 905 // If the [element] is a field-parameter (such as [:this.x:] then | 929 // If the [element] is a field-parameter (such as [:this.x:] then |
| 906 // initialize the field element with its value. | 930 // initialize the field element with its value. |
| 907 FieldParameterElement fieldParameterElement = element; | 931 FieldParameterElement fieldParameterElement = element; |
| 908 HInstruction parameterValue = localsHandler.readLocal(element); | 932 HInstruction parameterValue = localsHandler.readLocal(element); |
| 909 fieldValues[fieldParameterElement.fieldElement] = parameterValue; | 933 fieldValues[fieldParameterElement.fieldElement] = parameterValue; |
| 910 } | 934 } |
| 911 }); | 935 }); |
| 912 | 936 |
| 913 final Map<FunctionElement, TreeElements> constructorElements = | 937 final Map<FunctionElement, TreeElements> constructorElements = |
| 914 compiler.resolver.constructorElements; | 938 compiler.resolver.constructorElements; |
| 915 List<FunctionElement> constructors = new List<FunctionElement>(); | 939 List<FunctionElement> constructors = <FunctionElement>[functionElement]; |
| 916 | 940 |
| 917 // Analyze the constructor and all referenced constructors and collect | 941 // Analyze the constructor and all referenced constructors and collect |
| 918 // initializers and constructor bodies. | 942 // initializers and constructor bodies. |
| 919 inlineInitializers(functionElement, constructors, fieldValues); | 943 buildInitializers(functionElement, constructors, fieldValues); |
| 920 | 944 |
| 921 // Call the JavaScript constructor with the fields as argument. | 945 // Call the JavaScript constructor with the fields as argument. |
| 922 List<HInstruction> constructorArguments = <HInstruction>[]; | 946 List<HInstruction> constructorArguments = <HInstruction>[]; |
| 923 classElement.forEachInstanceField( | 947 classElement.forEachInstanceField( |
| 924 includeBackendMembers: true, | 948 includeBackendMembers: true, |
| 925 includeSuperMembers: true, | 949 includeSuperMembers: true, |
| 926 f: (ClassElement enclosingClass, Element member) { | 950 f: (ClassElement enclosingClass, Element member) { |
| 927 HInstruction value = fieldValues[member]; | 951 HInstruction value = fieldValues[member]; |
| 928 if (value === null) { | 952 if (value === null) { |
| 929 // The field has no value in the initializer list. Initialize it | 953 // The field has no value in the initializer list. Initialize it |
| (...skipping 841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1771 // Iterate through the named arguments to add them to the list | 1795 // Iterate through the named arguments to add them to the list |
| 1772 // of instructions, in an order that can be shared with | 1796 // of instructions, in an order that can be shared with |
| 1773 // selectors with the same named arguments. | 1797 // selectors with the same named arguments. |
| 1774 List<SourceString> orderedNames = selector.getOrderedNamedArguments(); | 1798 List<SourceString> orderedNames = selector.getOrderedNamedArguments(); |
| 1775 for (SourceString name in orderedNames) { | 1799 for (SourceString name in orderedNames) { |
| 1776 list.add(instructions[name]); | 1800 list.add(instructions[name]); |
| 1777 } | 1801 } |
| 1778 } | 1802 } |
| 1779 } | 1803 } |
| 1780 | 1804 |
| 1781 void addStaticSendArgumentsToList(Send node, | 1805 /** |
| 1806 * Returns true if the arguments were compatible with the function signature. |
| 1807 */ |
| 1808 bool addStaticSendArgumentsToList(Selector selector, |
| 1809 Link<Node> arguments, |
| 1782 FunctionElement element, | 1810 FunctionElement element, |
| 1783 List<HInstruction> list) { | 1811 List<HInstruction> list) { |
| 1784 HInstruction compileArgument(Node argument) { | 1812 HInstruction compileArgument(Node argument) { |
| 1785 visit(argument); | 1813 visit(argument); |
| 1786 return pop(); | 1814 return pop(); |
| 1787 } | 1815 } |
| 1788 | 1816 |
| 1789 HInstruction compileConstant(Element constantElement) { | 1817 HInstruction compileConstant(Element constantElement) { |
| 1790 Constant constant = compiler.compileVariable(constantElement); | 1818 Constant constant = compiler.compileVariable(constantElement); |
| 1791 return graph.addConstant(constant); | 1819 return graph.addConstant(constant); |
| 1792 } | 1820 } |
| 1793 | 1821 |
| 1794 Selector selector = elements.getSelector(node); | |
| 1795 FunctionParameters parameters = element.computeParameters(compiler); | 1822 FunctionParameters parameters = element.computeParameters(compiler); |
| 1796 bool succeeded = selector.addSendArgumentsToList(node, list, parameters, | 1823 return selector.addArgumentsToList(arguments, list, parameters, |
| 1797 compileArgument, | 1824 compileArgument, compileConstant); |
| 1798 compileConstant); | |
| 1799 if (!succeeded) { | |
| 1800 // TODO(ngeoffray): Match the VM behavior and throw an | |
| 1801 // exception at runtime. | |
| 1802 compiler.cancel('Unimplemented non-matching static call', node: node); | |
| 1803 } | |
| 1804 } | 1825 } |
| 1805 | 1826 |
| 1806 void addGenericSendArgumentsToList(Link<Node> link, List<HInstruction> list) { | 1827 void addGenericSendArgumentsToList(Link<Node> link, List<HInstruction> list) { |
| 1807 for (; !link.isEmpty(); link = link.tail) { | 1828 for (; !link.isEmpty(); link = link.tail) { |
| 1808 visit(link.head); | 1829 visit(link.head); |
| 1809 list.add(pop()); | 1830 list.add(pop()); |
| 1810 } | 1831 } |
| 1811 } | 1832 } |
| 1812 | 1833 |
| 1813 visitDynamicSend(Send node) { | 1834 visitDynamicSend(Send node) { |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2059 push(new HInvokeSuper(const Selector(SelectorKind.INVOCATION, 2), | 2080 push(new HInvokeSuper(const Selector(SelectorKind.INVOCATION, 2), |
| 2060 inputs)); | 2081 inputs)); |
| 2061 return; | 2082 return; |
| 2062 } | 2083 } |
| 2063 HInstruction target = new HStatic(element); | 2084 HInstruction target = new HStatic(element); |
| 2064 HInstruction context = localsHandler.readThis(); | 2085 HInstruction context = localsHandler.readThis(); |
| 2065 add(target); | 2086 add(target); |
| 2066 var inputs = <HInstruction>[target, context]; | 2087 var inputs = <HInstruction>[target, context]; |
| 2067 if (element.kind == ElementKind.FUNCTION || | 2088 if (element.kind == ElementKind.FUNCTION || |
| 2068 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | 2089 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
| 2069 addStaticSendArgumentsToList(node, element, inputs); | 2090 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 2091 element, inputs); |
| 2092 if (!succeeded) { |
| 2093 // TODO(ngeoffray): Match the VM behavior and throw an |
| 2094 // exception at runtime. |
| 2095 compiler.cancel('Unimplemented non-matching static call', node); |
| 2096 } |
| 2070 push(new HInvokeSuper(selector, inputs)); | 2097 push(new HInvokeSuper(selector, inputs)); |
| 2071 } else { | 2098 } else { |
| 2072 target = new HInvokeSuper(Selector.GETTER, inputs); | 2099 target = new HInvokeSuper(Selector.GETTER, inputs); |
| 2073 add(target); | 2100 add(target); |
| 2074 inputs = <HInstruction>[target]; | 2101 inputs = <HInstruction>[target]; |
| 2075 addDynamicSendArgumentsToList(node, inputs); | 2102 addDynamicSendArgumentsToList(node, inputs); |
| 2076 push(new HInvokeClosure(selector, inputs)); | 2103 push(new HInvokeClosure(selector, inputs)); |
| 2077 } | 2104 } |
| 2078 } | 2105 } |
| 2079 | 2106 |
| 2080 visitStaticSend(Send node) { | 2107 visitStaticSend(Send node) { |
| 2081 Selector selector = elements.getSelector(node); | 2108 Selector selector = elements.getSelector(node); |
| 2082 Element element = elements[node]; | 2109 Element element = elements[node]; |
| 2083 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR) { | 2110 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR) { |
| 2084 compiler.resolver.resolveMethodElement(element); | 2111 compiler.resolver.resolveMethodElement(element); |
| 2085 FunctionElement functionElement = element; | 2112 FunctionElement functionElement = element; |
| 2086 element = functionElement.defaultImplementation; | 2113 element = functionElement.defaultImplementation; |
| 2087 } | 2114 } |
| 2088 HInstruction target = new HStatic(element); | 2115 HInstruction target = new HStatic(element); |
| 2089 add(target); | 2116 add(target); |
| 2090 var inputs = <HInstruction>[]; | 2117 var inputs = <HInstruction>[]; |
| 2091 inputs.add(target); | 2118 inputs.add(target); |
| 2092 if (element.kind == ElementKind.FUNCTION || | 2119 if (element.kind == ElementKind.FUNCTION || |
| 2093 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | 2120 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
| 2094 addStaticSendArgumentsToList(node, element, inputs); | 2121 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 2122 element, inputs); |
| 2123 if (!succeeded) { |
| 2124 // TODO(ngeoffray): Match the VM behavior and throw an |
| 2125 // exception at runtime. |
| 2126 compiler.cancel('Unimplemented non-matching static call', node: node); |
| 2127 } |
| 2095 push(new HInvokeStatic(selector, inputs)); | 2128 push(new HInvokeStatic(selector, inputs)); |
| 2096 } else { | 2129 } else { |
| 2097 if (element.kind == ElementKind.GETTER) { | 2130 if (element.kind == ElementKind.GETTER) { |
| 2098 target = new HInvokeStatic(Selector.GETTER, inputs); | 2131 target = new HInvokeStatic(Selector.GETTER, inputs); |
| 2099 add(target); | 2132 add(target); |
| 2100 inputs = <HInstruction>[target]; | 2133 inputs = <HInstruction>[target]; |
| 2101 } | 2134 } |
| 2102 addDynamicSendArgumentsToList(node, inputs); | 2135 addDynamicSendArgumentsToList(node, inputs); |
| 2103 push(new HInvokeClosure(selector, inputs)); | 2136 push(new HInvokeClosure(selector, inputs)); |
| 2104 } | 2137 } |
| (...skipping 935 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3040 false, | 3073 false, |
| 3041 <HInstruction>[target, input])); | 3074 <HInstruction>[target, input])); |
| 3042 return builder.pop(); | 3075 return builder.pop(); |
| 3043 } | 3076 } |
| 3044 | 3077 |
| 3045 HInstruction result() { | 3078 HInstruction result() { |
| 3046 flushLiterals(); | 3079 flushLiterals(); |
| 3047 return prefix; | 3080 return prefix; |
| 3048 } | 3081 } |
| 3049 } | 3082 } |
| OLD | NEW |