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 part of dart2js; | 5 part of dart2js; |
6 | 6 |
7 /** | 7 /** |
8 * The [ConstantHandler] keeps track of compile-time constants, | 8 * The [ConstantHandler] keeps track of compile-time constants, |
9 * initializations of global and static fields, and default values of | 9 * initializations of global and static fields, and default values of |
10 * optional parameters. | 10 * optional parameters. |
(...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
682 } | 682 } |
683 | 683 |
684 Send send = node.send; | 684 Send send = node.send; |
685 FunctionElement constructor = elements[send]; | 685 FunctionElement constructor = elements[send]; |
686 // TODO(ahe): This is nasty: we must eagerly analyze the | 686 // TODO(ahe): This is nasty: we must eagerly analyze the |
687 // constructor to ensure the redirectionTarget has been computed | 687 // constructor to ensure the redirectionTarget has been computed |
688 // correctly. Find a way to avoid this. | 688 // correctly. Find a way to avoid this. |
689 compiler.analyzeElement(constructor.declaration); | 689 compiler.analyzeElement(constructor.declaration); |
690 | 690 |
691 InterfaceType type = elements.getType(node); | 691 InterfaceType type = elements.getType(node); |
692 if ( constructor.isRedirectingFactory) { | 692 if (constructor.isRedirectingFactory) { |
693 type = constructor.computeTargetType(compiler, type); | 693 type = constructor.computeTargetType(compiler, type); |
694 } | 694 } |
695 | 695 |
696 constructor = constructor.redirectionTarget; | 696 constructor = constructor.redirectionTarget; |
697 ClassElement classElement = constructor.getEnclosingClass(); | 697 ClassElement classElement = constructor.getEnclosingClass(); |
698 // The constructor must be an implementation to ensure that field | 698 // The constructor must be an implementation to ensure that field |
699 // initializers are handled correctly. | 699 // initializers are handled correctly. |
700 constructor = constructor.implementation; | 700 constructor = constructor.implementation; |
701 assert(invariant(node, constructor.isImplementation)); | 701 assert(invariant(node, constructor.isImplementation)); |
702 | 702 |
703 Selector selector = elements.getSelector(send); | 703 Selector selector = elements.getSelector(send); |
704 List<Constant> arguments = evaluateArgumentsToConstructor( | 704 List<Constant> arguments = evaluateArgumentsToConstructor( |
705 node, selector, send.arguments, constructor); | 705 node, selector, send.arguments, constructor); |
706 ConstructorEvaluator evaluator = | 706 ConstructorEvaluator evaluator = |
707 new ConstructorEvaluator(node, constructor, handler, compiler); | 707 new ConstructorEvaluator(constructor, handler, compiler); |
708 evaluator.evaluateConstructorFieldValues(arguments); | 708 evaluator.evaluateConstructorFieldValues(arguments); |
709 List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); | 709 List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); |
710 | 710 |
711 handler.registerInstantiatedType(type, elements); | 711 handler.registerInstantiatedType(type, elements); |
712 Constant constant = new ConstructedConstant(type, jsNewArguments); | 712 Constant constant = new ConstructedConstant(type, jsNewArguments); |
713 handler.registerCompileTimeConstant(constant, elements); | 713 handler.registerCompileTimeConstant(constant, elements); |
714 return constant; | 714 return constant; |
715 } | 715 } |
716 | 716 |
717 Constant visitParenthesizedExpression(ParenthesizedExpression node) { | 717 Constant visitParenthesizedExpression(ParenthesizedExpression node) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
754 class ConstructorEvaluator extends CompileTimeConstantEvaluator { | 754 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
755 final FunctionElement constructor; | 755 final FunctionElement constructor; |
756 final Map<Element, Constant> definitions; | 756 final Map<Element, Constant> definitions; |
757 final Map<Element, Constant> fieldValues; | 757 final Map<Element, Constant> fieldValues; |
758 | 758 |
759 /** | 759 /** |
760 * Documentation wanted -- johnniwinther | 760 * Documentation wanted -- johnniwinther |
761 * | 761 * |
762 * Invariant: [constructor] must be an implementation element. | 762 * Invariant: [constructor] must be an implementation element. |
763 */ | 763 */ |
764 ConstructorEvaluator(Node node, | 764 ConstructorEvaluator(FunctionElement constructor, |
765 FunctionElement constructor, | |
766 ConstantHandler handler, | 765 ConstantHandler handler, |
767 Compiler compiler) | 766 Compiler compiler) |
768 : this.constructor = constructor, | 767 : this.constructor = constructor, |
769 this.definitions = new Map<Element, Constant>(), | 768 this.definitions = new Map<Element, Constant>(), |
770 this.fieldValues = new Map<Element, Constant>(), | 769 this.fieldValues = new Map<Element, Constant>(), |
771 super(handler, | 770 super(handler, |
772 compiler.resolver.resolveMethodElement(constructor.declaration), | 771 compiler.resolver.resolveMethodElement(constructor.declaration), |
773 compiler, | 772 compiler, |
774 isConst: true) { | 773 isConst: true) { |
775 assert(invariant(node, constructor.isImplementation)); | 774 assert(invariant(constructor, constructor.isImplementation)); |
776 } | 775 } |
777 | 776 |
778 Constant visitSend(Send send) { | 777 Constant visitSend(Send send) { |
779 Element element = elements[send]; | 778 Element element = elements[send]; |
780 if (Elements.isLocal(element)) { | 779 if (Elements.isLocal(element)) { |
781 Constant constant = definitions[element]; | 780 Constant constant = definitions[element]; |
782 if (constant == null) { | 781 if (constant == null) { |
783 compiler.internalError("Local variable without value", node: send); | 782 compiler.internalError("Local variable without value", node: send); |
784 } | 783 } |
785 return constant; | 784 return constant; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
821 Node node = parameter.parseNode(compiler); | 820 Node node = parameter.parseNode(compiler); |
822 potentiallyCheckType(node, parameter, argument); | 821 potentiallyCheckType(node, parameter, argument); |
823 definitions[parameter] = argument; | 822 definitions[parameter] = argument; |
824 if (parameter.kind == ElementKind.FIELD_PARAMETER) { | 823 if (parameter.kind == ElementKind.FIELD_PARAMETER) { |
825 FieldParameterElement fieldParameterElement = parameter; | 824 FieldParameterElement fieldParameterElement = parameter; |
826 updateFieldValue(node, fieldParameterElement.fieldElement, argument); | 825 updateFieldValue(node, fieldParameterElement.fieldElement, argument); |
827 } | 826 } |
828 }); | 827 }); |
829 } | 828 } |
830 | 829 |
831 void evaluateSuperOrRedirectSend(Node currentNode, | 830 void evaluateSuperOrRedirectSend(List<Constant> compiledArguments, |
832 Selector selector, | |
833 Link<Node> arguments, | |
834 FunctionElement targetConstructor) { | 831 FunctionElement targetConstructor) { |
835 List<Constant> compiledArguments = evaluateArgumentsToConstructor( | |
836 currentNode, selector, arguments, targetConstructor); | |
837 | |
838 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 832 ConstructorEvaluator evaluator = new ConstructorEvaluator( |
839 currentNode, targetConstructor, handler, compiler); | 833 targetConstructor, handler, compiler); |
840 evaluator.evaluateConstructorFieldValues(compiledArguments); | 834 evaluator.evaluateConstructorFieldValues(compiledArguments); |
841 // Copy over the fieldValues from the super/redirect-constructor. | 835 // Copy over the fieldValues from the super/redirect-constructor. |
842 // No need to go through [updateFieldValue] because the | 836 // No need to go through [updateFieldValue] because the |
843 // assignments have already been checked in checked mode. | 837 // assignments have already been checked in checked mode. |
844 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); | 838 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); |
845 } | 839 } |
846 | 840 |
847 /** | 841 /** |
848 * Runs through the initializers of the given [constructor] and updates | 842 * Runs through the initializers of the given [constructor] and updates |
849 * the [fieldValues] map. | 843 * the [fieldValues] map. |
850 */ | 844 */ |
851 void evaluateConstructorInitializers() { | 845 void evaluateConstructorInitializers() { |
| 846 if (constructor.isSynthesized) { |
| 847 List<Constant> compiledArguments = <Constant>[]; |
| 848 |
| 849 Function compileArgument = (element) => definitions[element]; |
| 850 Function compileConstant = handler.compileConstant; |
| 851 FunctionElement target = constructor.targetConstructor.implementation; |
| 852 Selector.addForwardingElementArgumentsToList(constructor, |
| 853 compiledArguments, |
| 854 target, |
| 855 compileArgument, |
| 856 compileConstant, |
| 857 compiler); |
| 858 evaluateSuperOrRedirectSend(compiledArguments, target); |
| 859 return; |
| 860 } |
852 FunctionExpression functionNode = constructor.parseNode(compiler); | 861 FunctionExpression functionNode = constructor.parseNode(compiler); |
853 NodeList initializerList = functionNode.initializers; | 862 NodeList initializerList = functionNode.initializers; |
854 | 863 |
855 bool foundSuperOrRedirect = false; | 864 bool foundSuperOrRedirect = false; |
856 | 865 |
857 if (initializerList != null) { | 866 if (initializerList != null) { |
858 for (Link<Node> link = initializerList.nodes; | 867 for (Link<Node> link = initializerList.nodes; |
859 !link.isEmpty; | 868 !link.isEmpty; |
860 link = link.tail) { | 869 link = link.tail) { |
861 assert(link.head is Send); | 870 assert(link.head is Send); |
862 if (link.head is !SendSet) { | 871 if (link.head is !SendSet) { |
863 // A super initializer or constructor redirection. | 872 // A super initializer or constructor redirection. |
864 Send call = link.head; | 873 Send call = link.head; |
865 FunctionElement targetConstructor = elements[call]; | 874 FunctionElement target = elements[call]; |
866 Selector selector = elements.getSelector(call); | 875 List<Constant> compiledArguments = evaluateArgumentsToConstructor( |
867 Link<Node> arguments = call.arguments; | 876 call, elements.getSelector(call), call.arguments, target); |
868 evaluateSuperOrRedirectSend( | 877 evaluateSuperOrRedirectSend(compiledArguments, target); |
869 call, selector, arguments, targetConstructor); | |
870 foundSuperOrRedirect = true; | 878 foundSuperOrRedirect = true; |
871 } else { | 879 } else { |
872 // A field initializer. | 880 // A field initializer. |
873 SendSet init = link.head; | 881 SendSet init = link.head; |
874 Link<Node> initArguments = init.arguments; | 882 Link<Node> initArguments = init.arguments; |
875 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); | 883 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); |
876 Constant fieldValue = evaluate(initArguments.head); | 884 Constant fieldValue = evaluate(initArguments.head); |
877 updateFieldValue(init, elements[init], fieldValue); | 885 updateFieldValue(init, elements[init], fieldValue); |
878 } | 886 } |
879 } | 887 } |
(...skipping 10 matching lines...) Expand all Loading... |
890 | 898 |
891 Selector selector = | 899 Selector selector = |
892 new Selector.callDefaultConstructor(enclosingClass.getLibrary()); | 900 new Selector.callDefaultConstructor(enclosingClass.getLibrary()); |
893 | 901 |
894 FunctionElement targetConstructor = | 902 FunctionElement targetConstructor = |
895 superClass.lookupConstructor(selector); | 903 superClass.lookupConstructor(selector); |
896 if (targetConstructor == null) { | 904 if (targetConstructor == null) { |
897 compiler.internalError("no default constructor available", | 905 compiler.internalError("no default constructor available", |
898 node: functionNode); | 906 node: functionNode); |
899 } | 907 } |
900 | 908 List<Constant> compiledArguments = evaluateArgumentsToConstructor( |
901 evaluateSuperOrRedirectSend(functionNode, | 909 functionNode, selector, const Link<Node>(), targetConstructor); |
902 selector, | 910 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor); |
903 const Link<Node>(), | |
904 targetConstructor); | |
905 } | 911 } |
906 } | 912 } |
907 } | 913 } |
908 | 914 |
909 /** | 915 /** |
910 * Simulates the execution of the [constructor] with the given | 916 * Simulates the execution of the [constructor] with the given |
911 * [arguments] to obtain the field values that need to be passed to the | 917 * [arguments] to obtain the field values that need to be passed to the |
912 * native JavaScript constructor. | 918 * native JavaScript constructor. |
913 */ | 919 */ |
914 void evaluateConstructorFieldValues(List<Constant> arguments) { | 920 void evaluateConstructorFieldValues(List<Constant> arguments) { |
(...skipping 11 matching lines...) Expand all Loading... |
926 if (fieldValue == null) { | 932 if (fieldValue == null) { |
927 // Use the default value. | 933 // Use the default value. |
928 fieldValue = handler.compileConstant(field); | 934 fieldValue = handler.compileConstant(field); |
929 } | 935 } |
930 jsNewArguments.add(fieldValue); | 936 jsNewArguments.add(fieldValue); |
931 }, | 937 }, |
932 includeSuperAndInjectedMembers: true); | 938 includeSuperAndInjectedMembers: true); |
933 return jsNewArguments; | 939 return jsNewArguments; |
934 } | 940 } |
935 } | 941 } |
OLD | NEW |