Chromium Code Reviews| 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 assert(succeeded); | |
|
ngeoffray
2012/04/16 12:24:02
Please add a comment why this is an assert and not
floitsch
2012/04/16 14:23:14
changed to internal error.
| |
| 819 | |
| 820 int index = 0; | |
| 821 FunctionParameters parameters = constructor.computeParameters(compiler); | |
| 822 parameters.forEachParameter((Element parameter) { | |
| 823 HInstruction argument = compiledArguments[index++]; | |
| 824 localsHandler.updateLocal(parameter, argument); | |
| 825 // Don't forget to update the field, if the parameter is of the | |
| 826 // form [:this.x:]. | |
| 827 if (parameter.kind == ElementKind.FIELD_PARAMETER) { | |
| 828 FieldParameterElement fieldParameterElement = parameter; | |
| 829 fieldValues[fieldParameterElement.fieldElement] = argument; | |
| 830 } | |
| 831 }); | |
| 832 | |
| 833 // Build the initializers in the context of the new constructor. | |
| 834 TreeElements oldElements = elements; | |
| 835 elements = compiler.resolver.resolveMethodElement(constructor); | |
| 836 buildInitializers(constructor, constructors, fieldValues); | |
| 837 elements = oldElements; | |
| 838 return true; | |
| 839 } | |
| 806 /** | 840 /** |
| 807 * Run through the initializers and inline all field initializers. Recursively | 841 * Run through the initializers and inline all field initializers. Recursively |
| 808 * inlines super initializers. | 842 * inlines super initializers. |
| 809 * | 843 * |
| 810 * The constructors of the inlined initializers is added to [constructors] | 844 * The constructors of the inlined initializers is added to [constructors] |
| 811 * with sub constructors having a lower index than super constructors. | 845 * with sub constructors having a lower index than super constructors. |
| 812 */ | 846 */ |
| 813 void inlineInitializers(FunctionElement constructor, | 847 void buildInitializers(FunctionElement constructor, |
| 814 List<FunctionElement> constructors, | 848 List<FunctionElement> constructors, |
| 815 Map<Element, HInstruction> fieldValues) { | 849 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); | 850 FunctionExpression functionNode = constructor.parseNode(compiler); |
| 821 | 851 |
| 852 bool foundSuperOrRedirect = false; | |
| 853 | |
| 822 if (functionNode.initializers !== null) { | 854 if (functionNode.initializers !== null) { |
| 823 Link<Node> initializers = functionNode.initializers.nodes; | 855 Link<Node> initializers = functionNode.initializers.nodes; |
| 824 for (Link<Node> link = initializers; !link.isEmpty(); link = link.tail) { | 856 for (Link<Node> link = initializers; !link.isEmpty(); link = link.tail) { |
| 825 assert(link.head is Send); | 857 assert(link.head is Send); |
| 826 if (link.head is !SendSet) { | 858 if (link.head is !SendSet) { |
| 827 // A super initializer or constructor redirection. | 859 // A super initializer or constructor redirection. |
| 828 Send call = link.head; | 860 Send call = link.head; |
| 829 assert(Initializers.isSuperConstructorCall(call) || | 861 assert(Initializers.isSuperConstructorCall(call) || |
| 830 Initializers.isConstructorRedirect(call)); | 862 Initializers.isConstructorRedirect(call)); |
| 831 FunctionElement nextConstructor = elements[call]; | 863 FunctionElement target = elements[call]; |
| 832 // Visit arguments and map the corresponding parameter value to | 864 Selector selector = elements.getSelector(call); |
| 833 // the resulting HInstruction value. | 865 Link<Node> arguments = call.arguments; |
| 834 List<HInstruction> arguments = new List<HInstruction>(); | 866 inlineSuperOrRedirect(target, selector, arguments, constructors, |
| 835 addStaticSendArgumentsToList(call, nextConstructor, arguments); | 867 fieldValues); |
| 836 int index = 0; | 868 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 { | 869 } else { |
| 852 // A field initializer. | 870 // A field initializer. |
| 853 SendSet init = link.head; | 871 SendSet init = link.head; |
| 854 Link<Node> arguments = init.arguments; | 872 Link<Node> arguments = init.arguments; |
| 855 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); | 873 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); |
| 856 visit(arguments.head); | 874 visit(arguments.head); |
| 857 fieldValues[elements[init]] = pop(); | 875 fieldValues[elements[init]] = pop(); |
| 858 } | 876 } |
| 859 } | 877 } |
| 860 } | 878 } |
| 861 | 879 |
| 862 if (!initializedSuper) { | 880 if (!foundSuperOrRedirect) { |
| 863 // No super initializer found. Try to find the default constructor if | 881 // No super initializer found. Try to find the default constructor if |
| 864 // the class is not Object. | 882 // the class is not Object. |
| 865 ClassElement enclosingClass = constructor.enclosingElement; | 883 ClassElement enclosingClass = constructor.enclosingElement; |
| 866 ClassElement superClass = enclosingClass.superclass; | 884 ClassElement superClass = enclosingClass.superclass; |
| 867 if (enclosingClass != compiler.objectClass) { | 885 if (enclosingClass != compiler.objectClass) { |
| 868 assert(superClass !== null); | 886 assert(superClass !== null); |
| 869 assert(superClass.isResolved); | 887 assert(superClass.isResolved); |
| 870 FunctionElement nextConstructor = | 888 FunctionElement target = superClass.lookupConstructor(superClass.name); |
| 871 superClass.lookupConstructor(superClass.name); | 889 if (target === null) { |
| 872 if (nextConstructor === null) { | |
| 873 compiler.internalError("no default constructor available"); | 890 compiler.internalError("no default constructor available"); |
|
ngeoffray
2012/04/16 12:24:02
Could you also update the resolver to report the '
floitsch
2012/04/16 14:23:14
The resolver does the right thing now.
| |
| 874 } | 891 } |
| 875 inlineInitializers(nextConstructor, constructors, fieldValues); | 892 inlineSuperOrRedirect(target, |
| 893 Selector.INVOCATION_0, | |
| 894 const EmptyLink<Node>(), | |
| 895 constructors, | |
| 896 fieldValues); | |
| 876 } | 897 } |
| 877 } | 898 } |
| 878 | |
| 879 elements = oldElements; | |
| 880 } | 899 } |
| 881 | 900 |
| 882 /** | 901 /** |
| 883 * Build the factory function corresponding to the constructor | 902 * Build the factory function corresponding to the constructor |
| 884 * [functionElement]: | 903 * [functionElement]: |
| 885 * - Initialize fields with the values of the field initializers of the | 904 * - Initialize fields with the values of the field initializers of the |
| 886 * current constructor and super constructors or constructors redirected | 905 * current constructor and super constructors or constructors redirected |
| 887 * to, starting from the current constructor. | 906 * to, starting from the current constructor. |
| 888 * - Call the the constructor bodies, starting from the constructor(s) in the | 907 * - Call the the constructor bodies, starting from the constructor(s) in the |
| 889 * super class(es). | 908 * super class(es). |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 905 // If the [element] is a field-parameter (such as [:this.x:] then | 924 // If the [element] is a field-parameter (such as [:this.x:] then |
| 906 // initialize the field element with its value. | 925 // initialize the field element with its value. |
| 907 FieldParameterElement fieldParameterElement = element; | 926 FieldParameterElement fieldParameterElement = element; |
| 908 HInstruction parameterValue = localsHandler.readLocal(element); | 927 HInstruction parameterValue = localsHandler.readLocal(element); |
| 909 fieldValues[fieldParameterElement.fieldElement] = parameterValue; | 928 fieldValues[fieldParameterElement.fieldElement] = parameterValue; |
| 910 } | 929 } |
| 911 }); | 930 }); |
| 912 | 931 |
| 913 final Map<FunctionElement, TreeElements> constructorElements = | 932 final Map<FunctionElement, TreeElements> constructorElements = |
| 914 compiler.resolver.constructorElements; | 933 compiler.resolver.constructorElements; |
| 915 List<FunctionElement> constructors = new List<FunctionElement>(); | 934 List<FunctionElement> constructors = <FunctionElement>[functionElement]; |
| 916 | 935 |
| 917 // Analyze the constructor and all referenced constructors and collect | 936 // Analyze the constructor and all referenced constructors and collect |
| 918 // initializers and constructor bodies. | 937 // initializers and constructor bodies. |
| 919 inlineInitializers(functionElement, constructors, fieldValues); | 938 buildInitializers(functionElement, constructors, fieldValues); |
| 920 | 939 |
| 921 // Call the JavaScript constructor with the fields as argument. | 940 // Call the JavaScript constructor with the fields as argument. |
| 922 List<HInstruction> constructorArguments = <HInstruction>[]; | 941 List<HInstruction> constructorArguments = <HInstruction>[]; |
| 923 classElement.forEachInstanceField( | 942 classElement.forEachInstanceField( |
| 924 includeBackendMembers: true, | 943 includeBackendMembers: true, |
| 925 includeSuperMembers: true, | 944 includeSuperMembers: true, |
| 926 f: (ClassElement enclosingClass, Element member) { | 945 f: (ClassElement enclosingClass, Element member) { |
| 927 HInstruction value = fieldValues[member]; | 946 HInstruction value = fieldValues[member]; |
| 928 if (value === null) { | 947 if (value === null) { |
| 929 // The field has no value in the initializer list. Initialize it | 948 // The field has no value in the initializer list. Initialize it |
| (...skipping 837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1767 // Iterate through the named arguments to add them to the list | 1786 // Iterate through the named arguments to add them to the list |
| 1768 // of instructions, in an order that can be shared with | 1787 // of instructions, in an order that can be shared with |
| 1769 // selectors with the same named arguments. | 1788 // selectors with the same named arguments. |
| 1770 List<SourceString> orderedNames = selector.getOrderedNamedArguments(); | 1789 List<SourceString> orderedNames = selector.getOrderedNamedArguments(); |
| 1771 for (SourceString name in orderedNames) { | 1790 for (SourceString name in orderedNames) { |
| 1772 list.add(instructions[name]); | 1791 list.add(instructions[name]); |
| 1773 } | 1792 } |
| 1774 } | 1793 } |
| 1775 } | 1794 } |
| 1776 | 1795 |
| 1777 void addStaticSendArgumentsToList(Send node, | 1796 /** |
| 1797 * Returns true if the arguments were compatible with the function signature. | |
| 1798 */ | |
| 1799 bool addStaticSendArgumentsToList(Selector selector, | |
| 1800 Link<Node> arguments, | |
| 1778 FunctionElement element, | 1801 FunctionElement element, |
| 1779 List<HInstruction> list) { | 1802 List<HInstruction> list) { |
| 1780 HInstruction compileArgument(Node argument) { | 1803 HInstruction compileArgument(Node argument) { |
| 1781 visit(argument); | 1804 visit(argument); |
| 1782 return pop(); | 1805 return pop(); |
| 1783 } | 1806 } |
| 1784 | 1807 |
| 1785 HInstruction compileConstant(Element constantElement) { | 1808 HInstruction compileConstant(Element constantElement) { |
| 1786 Constant constant = compiler.compileVariable(constantElement); | 1809 Constant constant = compiler.compileVariable(constantElement); |
| 1787 return graph.addConstant(constant); | 1810 return graph.addConstant(constant); |
| 1788 } | 1811 } |
| 1789 | 1812 |
| 1790 Selector selector = elements.getSelector(node); | |
| 1791 FunctionParameters parameters = element.computeParameters(compiler); | 1813 FunctionParameters parameters = element.computeParameters(compiler); |
| 1792 bool succeeded = selector.addSendArgumentsToList(node, list, parameters, | 1814 return selector.addArgumentsToList(arguments, list, parameters, |
| 1793 compileArgument, | 1815 compileArgument, compileConstant); |
| 1794 compileConstant); | |
| 1795 if (!succeeded) { | |
| 1796 // TODO(ngeoffray): Match the VM behavior and throw an | |
| 1797 // exception at runtime. | |
| 1798 compiler.cancel('Unimplemented non-matching static call', node: node); | |
| 1799 } | |
| 1800 } | 1816 } |
| 1801 | 1817 |
| 1802 void addGenericSendArgumentsToList(Link<Node> link, List<HInstruction> list) { | 1818 void addGenericSendArgumentsToList(Link<Node> link, List<HInstruction> list) { |
| 1803 for (; !link.isEmpty(); link = link.tail) { | 1819 for (; !link.isEmpty(); link = link.tail) { |
| 1804 visit(link.head); | 1820 visit(link.head); |
| 1805 list.add(pop()); | 1821 list.add(pop()); |
| 1806 } | 1822 } |
| 1807 } | 1823 } |
| 1808 | 1824 |
| 1809 visitDynamicSend(Send node) { | 1825 visitDynamicSend(Send node) { |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2054 push(new HInvokeSuper(const Selector(SelectorKind.INVOCATION, 2), | 2070 push(new HInvokeSuper(const Selector(SelectorKind.INVOCATION, 2), |
| 2055 inputs)); | 2071 inputs)); |
| 2056 return; | 2072 return; |
| 2057 } | 2073 } |
| 2058 HInstruction target = new HStatic(element); | 2074 HInstruction target = new HStatic(element); |
| 2059 HInstruction context = localsHandler.readThis(); | 2075 HInstruction context = localsHandler.readThis(); |
| 2060 add(target); | 2076 add(target); |
| 2061 var inputs = <HInstruction>[target, context]; | 2077 var inputs = <HInstruction>[target, context]; |
| 2062 if (element.kind == ElementKind.FUNCTION || | 2078 if (element.kind == ElementKind.FUNCTION || |
| 2063 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | 2079 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
| 2064 addStaticSendArgumentsToList(node, element, inputs); | 2080 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 2081 element, inputs); | |
| 2082 if (!succeeded) { | |
| 2083 // TODO(ngeoffray): Match the VM behavior and throw an | |
| 2084 // exception at runtime. | |
| 2085 compiler.cancel('Unimplemented non-matching static call', node); | |
| 2086 } | |
| 2065 push(new HInvokeSuper(selector, inputs)); | 2087 push(new HInvokeSuper(selector, inputs)); |
| 2066 } else { | 2088 } else { |
| 2067 target = new HInvokeSuper(Selector.GETTER, inputs); | 2089 target = new HInvokeSuper(Selector.GETTER, inputs); |
| 2068 add(target); | 2090 add(target); |
| 2069 inputs = <HInstruction>[target]; | 2091 inputs = <HInstruction>[target]; |
| 2070 addDynamicSendArgumentsToList(node, inputs); | 2092 addDynamicSendArgumentsToList(node, inputs); |
| 2071 push(new HInvokeClosure(selector, inputs)); | 2093 push(new HInvokeClosure(selector, inputs)); |
| 2072 } | 2094 } |
| 2073 } | 2095 } |
| 2074 | 2096 |
| 2075 visitStaticSend(Send node) { | 2097 visitStaticSend(Send node) { |
| 2076 Selector selector = elements.getSelector(node); | 2098 Selector selector = elements.getSelector(node); |
| 2077 Element element = elements[node]; | 2099 Element element = elements[node]; |
| 2078 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR) { | 2100 if (element.kind === ElementKind.GENERATIVE_CONSTRUCTOR) { |
| 2079 compiler.resolver.resolveMethodElement(element); | 2101 compiler.resolver.resolveMethodElement(element); |
| 2080 FunctionElement functionElement = element; | 2102 FunctionElement functionElement = element; |
| 2081 element = functionElement.defaultImplementation; | 2103 element = functionElement.defaultImplementation; |
| 2082 } | 2104 } |
| 2083 HInstruction target = new HStatic(element); | 2105 HInstruction target = new HStatic(element); |
| 2084 add(target); | 2106 add(target); |
| 2085 var inputs = <HInstruction>[]; | 2107 var inputs = <HInstruction>[]; |
| 2086 inputs.add(target); | 2108 inputs.add(target); |
| 2087 if (element.kind == ElementKind.FUNCTION || | 2109 if (element.kind == ElementKind.FUNCTION || |
| 2088 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | 2110 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
| 2089 addStaticSendArgumentsToList(node, element, inputs); | 2111 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 2112 element, inputs); | |
| 2113 if (!succeeded) { | |
| 2114 // TODO(ngeoffray): Match the VM behavior and throw an | |
| 2115 // exception at runtime. | |
| 2116 compiler.cancel('Unimplemented non-matching static call', node: node); | |
| 2117 } | |
| 2090 push(new HInvokeStatic(selector, inputs)); | 2118 push(new HInvokeStatic(selector, inputs)); |
| 2091 } else { | 2119 } else { |
| 2092 if (element.kind == ElementKind.GETTER) { | 2120 if (element.kind == ElementKind.GETTER) { |
| 2093 target = new HInvokeStatic(Selector.GETTER, inputs); | 2121 target = new HInvokeStatic(Selector.GETTER, inputs); |
| 2094 add(target); | 2122 add(target); |
| 2095 inputs = <HInstruction>[target]; | 2123 inputs = <HInstruction>[target]; |
| 2096 } | 2124 } |
| 2097 addDynamicSendArgumentsToList(node, inputs); | 2125 addDynamicSendArgumentsToList(node, inputs); |
| 2098 push(new HInvokeClosure(selector, inputs)); | 2126 push(new HInvokeClosure(selector, inputs)); |
| 2099 } | 2127 } |
| (...skipping 924 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3024 false, | 3052 false, |
| 3025 <HInstruction>[target, input])); | 3053 <HInstruction>[target, input])); |
| 3026 return builder.pop(); | 3054 return builder.pop(); |
| 3027 } | 3055 } |
| 3028 | 3056 |
| 3029 HInstruction result() { | 3057 HInstruction result() { |
| 3030 flushLiterals(); | 3058 flushLiterals(); |
| 3031 return prefix; | 3059 return prefix; |
| 3032 } | 3060 } |
| 3033 } | 3061 } |
| OLD | NEW |