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 Constant implements Hashable { | 5 class Constant implements Hashable { |
| 6 const Constant(); | 6 const Constant(); |
| 7 | 7 |
| 8 bool isNull() => false; | 8 bool isNull() => false; |
| 9 bool isBool() => false; | 9 bool isBool() => false; |
| 10 bool isTrue() => false; | 10 bool isTrue() => false; |
| (...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 674 class CompileTimeConstantEvaluator extends AbstractVisitor { | 674 class CompileTimeConstantEvaluator extends AbstractVisitor { |
| 675 final ConstantHandler constantHandler; | 675 final ConstantHandler constantHandler; |
| 676 final TreeElements elements; | 676 final TreeElements elements; |
| 677 final Compiler compiler; | 677 final Compiler compiler; |
| 678 final Map<Element, Constant> definitions = null; | 678 final Map<Element, Constant> definitions = null; |
| 679 | 679 |
| 680 CompileTimeConstantEvaluator(this.constantHandler, | 680 CompileTimeConstantEvaluator(this.constantHandler, |
| 681 this.elements, | 681 this.elements, |
| 682 this.compiler); | 682 this.compiler); |
| 683 | 683 |
| 684 CompileTimeConstantEvaluator.insideConstructor(this.constantHandler, | 684 CompileTimeConstantEvaluator.insideConstructor(this.constantHandler, |
|
ngeoffray
2012/03/26 07:38:31
Because you can fetch constantHandler from the com
floitsch
2012/03/27 00:52:50
Done.
| |
| 685 this.elements, | 685 this.elements, |
| 686 this.compiler, | 686 this.compiler) |
| 687 this.definitions); | 687 : definitions = new Map<Element, Constant>(); |
| 688 | 688 |
| 689 bool insideConstructor() => definitions !== null; | 689 bool insideConstructor() => definitions !== null; |
| 690 | 690 |
| 691 Constant evaluate(Node node) { | 691 Constant evaluate(Node node) { |
| 692 return node.accept(this); | 692 return node.accept(this); |
| 693 } | 693 } |
| 694 | 694 |
| 695 visitNode(Node node) { | 695 visitNode(Node node) { |
| 696 compiler.unimplemented("CompileTimeConstantEvaluator", node: node); | 696 compiler.unimplemented("CompileTimeConstantEvaluator", node: node); |
| 697 } | 697 } |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 926 if (folded === null) error(send); | 926 if (folded === null) error(send); |
| 927 return folded; | 927 return folded; |
| 928 } | 928 } |
| 929 return super.visitSend(send); | 929 return super.visitSend(send); |
| 930 } | 930 } |
| 931 | 931 |
| 932 visitSendSet(SendSet node) { | 932 visitSendSet(SendSet node) { |
| 933 error(node); | 933 error(node); |
| 934 } | 934 } |
| 935 | 935 |
| 936 Constant visitNewExpression(NewExpression node) { | 936 /** Returns the list of constants that are passed to the constructor. */ |
| 937 Element currentElement = compiler.currentElement; | 937 List<Constant> evaluateConstructorArguments(Send send, |
| 938 FunctionElement constructor) { | |
| 939 FunctionParameters parameters = constructor.computeParameters(compiler); | |
| 940 if (send.arguments.isEmpty() && parameters.parameterCount == 0) { | |
|
ngeoffray
2012/03/26 07:38:31
Is that premature optimization? I would really get
ahe
2012/03/26 08:03:25
Note that these kind of hacks are not necessary if
floitsch
2012/03/27 00:52:50
Done.
| |
| 941 return const <Constant>[]; | |
| 942 } | |
| 943 List<Constant> arguments = <Constant>[]; | |
| 944 Selector selector = elements.getSelector(send); | |
| 938 | 945 |
| 939 void assignArgumentsToParameters( | 946 Function compileArgument = evaluate; |
|
floitsch
2012/03/23 23:15:57
The VM has/had a bug here (see previous uploads),
floitsch
2012/03/27 00:52:50
Fix has been committed.
| |
| 940 FunctionParameters parameters, | 947 Function compileConstant = compiler.compileVariable; |
| 941 Map<Element, Constant> constructorDefinitions, | 948 bool succeeded = selector.addSendArgumentsToList( |
| 942 Map<Element, Constant> fieldValues) { | 949 send, arguments, parameters, compileArgument, compileConstant); |
| 943 Send send = node.send; | 950 if (!succeeded) error(send); |
| 944 if (send.arguments.isEmpty() && parameters.parameterCount == 0) return; | 951 return arguments; |
| 945 List<Constant> arguments = <Constant>[]; | 952 } |
| 946 Selector selector = elements.getSelector(send); | |
| 947 | 953 |
| 948 Function compileArgument = evaluate; | 954 /** |
| 949 Function compileConstant = constantHandler.compileVariable; | 955 * Given the arguments (a list of constants) assigns the to the parameters, |
|
ngeoffray
2012/03/26 07:38:31
the to the -> ?
floitsch
2012/03/27 00:52:50
Done.
| |
| 950 bool succeeded = selector.addSendArgumentsToList( | 956 * updating the definitions map. If the constructor has field-initializer |
| 951 send, arguments, parameters, compileArgument, compileConstant); | 957 * parameters (like [:this.x:]), also updates the [fieldValues] map. |
| 952 if (!succeeded) error(node); | 958 */ |
| 959 void assignConstructorArgumentsToParameters( | |
| 960 FunctionElement constructor, List<Constant> arguments, | |
|
ngeoffray
2012/03/26 07:38:31
one argument per line please
floitsch
2012/03/27 00:52:50
Done.
| |
| 961 Map<Element, Constant> fieldValues) { | |
| 962 // Assign arguments to parameters. | |
| 963 FunctionParameters parameters = constructor.computeParameters(compiler); | |
| 964 int index = 0; | |
| 965 parameters.forEachParameter((Element parameter) { | |
| 966 Constant argument = arguments[index++]; | |
| 967 definitions[parameter] = argument; | |
| 968 if (parameter.kind == ElementKind.FIELD_PARAMETER) { | |
| 969 FieldParameterElement fieldParameterElement = parameter; | |
| 970 fieldValues[fieldParameterElement.fieldElement] = argument; | |
| 971 } | |
| 972 }); | |
| 973 } | |
| 953 | 974 |
| 954 int index = 0; | 975 /** |
| 955 parameters.forEachParameter((Element parameter) { | 976 * Runs through the initializers of the given [constructor] and updates |
| 956 Constant argument = arguments[index++]; | 977 * the [fieldValues] map. |
| 957 constructorDefinitions[parameter] = argument; | 978 * |
| 958 if (parameter.kind == ElementKind.FIELD_PARAMETER) { | 979 * The [executedConstructors] set is used to detect cycles in redirection |
| 959 FieldParameterElement fieldParameterElement = parameter; | 980 * constructors. |
| 960 fieldValues[fieldParameterElement.fieldElement] = argument; | 981 */ |
| 961 } | 982 void evaluateConstructorInitializers( |
| 962 }); | 983 FunctionElement constructor, |
| 984 Set<FunctionElement> executedConstructors, | |
| 985 Map<Element, Constant> fieldValues) { | |
| 986 | |
| 987 void evaluateSuperOrRedirectSend(FunctionElement targetConstructor, | |
| 988 List<Constant> targetArguments) { | |
| 989 compiler.withCurrentElement(targetConstructor, () { | |
| 990 evaluateConstructorFieldValues( | |
| 991 targetConstructor, targetArguments, executedConstructors, | |
| 992 fieldValues); | |
| 993 }); | |
| 963 } | 994 } |
| 964 | 995 |
| 965 void compileInitializers(Link<Node> initializers, | 996 FunctionExpression functionNode = constructor.parseNode(compiler); |
| 966 CompileTimeConstantEvaluator evaluator, | 997 NodeList initializerList = functionNode.initializers; |
| 967 TreeElements constructorElements, | 998 |
| 968 Map<Element, Constant> constructorDefinitions, | 999 bool foundSuperOrRedirect = false; |
| 969 Map<Element, Constant> fieldValues) { | 1000 |
| 970 for (Link<Node> link = initializers; !link.isEmpty(); link = link.tail) { | 1001 if (initializerList !== null) { |
| 1002 for (Link<Node> link = initializerList.nodes; | |
| 1003 !link.isEmpty(); | |
| 1004 link = link.tail) { | |
| 971 assert(link.head is Send); | 1005 assert(link.head is Send); |
| 972 if (link.head is !SendSet) { | 1006 if (link.head is !SendSet) { |
| 973 // A super initializer or constructor redirection. | 1007 // A super initializer or constructor redirection. |
| 974 Send call = link.head; | 1008 Send call = link.head; |
| 975 assert(Initializers.isSuperConstructorCall(call) || | 1009 FunctionElement targetConstructor = elements[call]; |
| 976 Initializers.isConstructorRedirect(call)); | 1010 List<Constant> targetArguments = |
| 977 compiler.unimplemented("ConstantHandler with this or super", | 1011 evaluateConstructorArguments(call, targetConstructor); |
| 978 node: call); | 1012 evaluateSuperOrRedirectSend(targetConstructor, targetArguments); |
| 1013 foundSuperOrRedirect = true; | |
| 979 } else { | 1014 } else { |
| 980 // A field initializer. | 1015 // A field initializer. |
| 981 SendSet init = link.head; | 1016 SendSet init = link.head; |
| 982 Link<Node> arguments = init.arguments; | 1017 Link<Node> initArguments = init.arguments; |
| 983 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); | 1018 assert(!initArguments.isEmpty() && initArguments.tail.isEmpty()); |
| 984 Constant fieldValue = evaluator.evaluate(arguments.head); | 1019 Constant fieldValue = evaluate(initArguments.head); |
| 985 fieldValues[constructorElements[init]] = fieldValue; | 1020 fieldValues[elements[init]] = fieldValue; |
| 986 } | 1021 } |
| 987 } | 1022 } |
| 988 } | 1023 } |
| 989 | 1024 |
| 1025 if (!foundSuperOrRedirect) { | |
| 1026 // No super initializer found. Try to find the default constructor if | |
| 1027 // the class is not Object. | |
| 1028 ClassElement enclosingClass = constructor.enclosingElement; | |
| 1029 ClassElement superClass = enclosingClass.superclass; | |
| 1030 if (enclosingClass != compiler.objectClass) { | |
| 1031 assert(superClass !== null); | |
| 1032 assert(superClass.isResolved); | |
| 1033 FunctionElement targetConstructor = | |
| 1034 superClass.lookupConstructor(superClass.name); | |
| 1035 if (targetConstructor === null) { | |
| 1036 compiler.internalError("no default constructor available"); | |
| 1037 } | |
| 1038 evaluateSuperOrRedirectSend(targetConstructor, const <Constant>[]); | |
| 1039 } | |
| 1040 } | |
| 1041 } | |
| 1042 | |
| 1043 /** | |
| 1044 * Simulates the execution of the given [constructor] with the given | |
| 1045 * [arguments] to obtain the field values that need to be passed to the | |
| 1046 * native JavaScript constructor. | |
| 1047 * | |
| 1048 * The [executedConstructors] set is used to detect cycles in redirection | |
| 1049 * constructors. | |
|
ngeoffray
2012/03/26 07:38:31
Having to also check it here is quite annoying. We
floitsch
2012/03/27 00:52:50
You are right. This is already handled by the reso
| |
| 1050 */ | |
| 1051 void evaluateConstructorFieldValues(FunctionElement constructor, | |
| 1052 List<Constant> arguments, | |
| 1053 Set<FunctionElement> executedConstructors, | |
| 1054 Map<Element, Constant> fieldValues) { | |
| 1055 compiler.withCurrentElement(constructor, () { | |
| 1056 if (executedConstructors.contains(constructor)) { | |
| 1057 MessageKind kind = MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE; | |
| 1058 compiler.reportError(constructor.parseNode(compiler), | |
| 1059 new CompileTimeConstantError(kind, const [])); | |
| 1060 } | |
| 1061 executedConstructors.add(constructor); | |
| 1062 | |
| 1063 TreeElements constructorElements = | |
| 1064 compiler.resolver.resolveMethodElement(constructor); | |
| 1065 CompileTimeConstantEvaluator evaluator = | |
| 1066 new CompileTimeConstantEvaluator.insideConstructor( | |
| 1067 constantHandler, constructorElements, compiler); | |
| 1068 | |
| 1069 evaluator.assignConstructorArgumentsToParameters( | |
| 1070 constructor, arguments, fieldValues); | |
| 1071 evaluator.evaluateConstructorInitializers( | |
| 1072 constructor, executedConstructors, fieldValues); | |
| 1073 }); | |
| 1074 } | |
| 1075 | |
| 1076 Constant visitNewExpression(NewExpression node) { | |
| 990 List<Constant> buildJsNewArguments(ClassElement classElement, | 1077 List<Constant> buildJsNewArguments(ClassElement classElement, |
| 991 Map<Element, Constant> fieldValues) { | 1078 Map<Element, Constant> fieldValues) { |
|
ngeoffray
2012/03/26 07:38:31
I think it would be easier to read if this functio
floitsch
2012/03/27 00:52:50
Done.
| |
| 992 List<Constant> jsNewArguments = <Constant>[]; | 1079 List<Constant> jsNewArguments = <Constant>[]; |
| 993 for (Element member in classElement.members) { | 1080 // TODO(floitsch): share this code with the emitter, so that we don't |
| 994 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { | 1081 // need to care about the order of fields here. |
| 995 Constant fieldValue = fieldValues[member]; | 1082 while (classElement != compiler.objectClass) { |
| 996 if (fieldValue === null) { | 1083 for (Element member in classElement.members) { |
| 997 // Use the default value. | 1084 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { |
| 998 fieldValue = constantHandler.compileVariable(member); | 1085 Constant fieldValue = fieldValues[member]; |
| 1086 if (fieldValue === null) { | |
| 1087 // Use the default value. | |
| 1088 fieldValue = constantHandler.compileVariable(member); | |
| 1089 } | |
| 1090 jsNewArguments.add(fieldValue); | |
| 999 } | 1091 } |
| 1000 jsNewArguments.add(fieldValue); | |
| 1001 } | 1092 } |
| 1002 } | 1093 classElement = classElement.superclass; |
| 1003 if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) { | 1094 } |
| 1004 compiler.withCurrentElement(currentElement, () { | |
| 1005 compiler.unimplemented("ConstantHandler with super", node: node); | |
| 1006 }); | |
| 1007 } | |
| 1008 return jsNewArguments; | 1095 return jsNewArguments; |
| 1009 } | 1096 } |
| 1010 | 1097 |
| 1011 if (!node.isConst()) error(node); | 1098 if (!node.isConst()) error(node); |
| 1012 | 1099 |
| 1013 FunctionElement constructor = elements[node.send]; | 1100 FunctionElement constructor = elements[node.send]; |
| 1014 TreeElements constructorElements = | 1101 ClassElement classElement = constructor.enclosingElement; |
| 1015 compiler.resolver.resolveMethodElement(constructor); | 1102 if (classElement.isInterface()) { |
| 1016 if (constructor != constructor.defaultImplementation) { | 1103 compiler.resolver.resolveMethodElement(constructor); |
| 1017 constructor = constructor.defaultImplementation; | 1104 constructor = constructor.defaultImplementation; |
| 1018 constructorElements = | 1105 classElement = constructor.enclosingElement; |
| 1019 compiler.resolver.resolveMethodElement(constructor); | |
| 1020 } | 1106 } |
| 1021 | 1107 |
| 1022 List<Constant> jsNewArguments; | 1108 List<Constant> jsNewArguments; |
| 1023 ClassElement classElement = constructor.enclosingElement; | |
| 1024 compiler.withCurrentElement(constructor, () { | 1109 compiler.withCurrentElement(constructor, () { |
| 1025 FunctionExpression functionNode = constructor.parseNode(compiler); | 1110 // We use a set to detect cycles in redirection constructors. |
| 1026 NodeList initializerList = functionNode.initializers; | 1111 Set<FunctionElement> executedConstructors = new Set<FunctionElement>(); |
| 1027 FunctionParameters parameters = constructor.computeParameters(compiler); | |
| 1028 | |
| 1029 Map<Element, Constant> fieldValues = new Map<Element, Constant>(); | 1112 Map<Element, Constant> fieldValues = new Map<Element, Constant>(); |
|
ngeoffray
2012/03/26 07:38:31
Would it make sense to have an abstraction for a c
floitsch
2012/03/27 00:52:50
Made ConstructorEvaluator a subclass.
| |
| 1030 Map<Element, Constant> constructorDefinitions = | 1113 List<Constant> arguments = |
| 1031 new Map<Element, Constant>(); | 1114 evaluateConstructorArguments(node.send, constructor); |
| 1032 | 1115 evaluateConstructorFieldValues( |
| 1033 assignArgumentsToParameters(parameters, constructorDefinitions, | 1116 constructor, arguments, executedConstructors, fieldValues); |
| 1034 fieldValues); | |
| 1035 CompileTimeConstantEvaluator initializerEvaluator = | |
| 1036 new CompileTimeConstantEvaluator.insideConstructor( | |
| 1037 constantHandler, constructorElements, compiler, | |
| 1038 constructorDefinitions); | |
| 1039 if (initializerList !== null) { | |
| 1040 Link<Node> initializers = functionNode.initializers.nodes; | |
| 1041 compileInitializers(initializers, | |
| 1042 initializerEvaluator, | |
| 1043 constructorElements, | |
| 1044 constructorDefinitions, | |
| 1045 fieldValues); | |
| 1046 } | |
| 1047 jsNewArguments = buildJsNewArguments(classElement, fieldValues); | 1117 jsNewArguments = buildJsNewArguments(classElement, fieldValues); |
| 1048 }); | 1118 }); |
| 1049 | 1119 |
| 1050 | |
| 1051 compiler.registerInstantiatedClass(classElement); | 1120 compiler.registerInstantiatedClass(classElement); |
| 1052 // TODO(floitsch): take generic types into account. | 1121 // TODO(floitsch): take generic types into account. |
| 1053 Type type = classElement.computeType(compiler); | 1122 Type type = classElement.computeType(compiler); |
| 1054 Constant constant = new ConstructedConstant(type, jsNewArguments); | 1123 Constant constant = new ConstructedConstant(type, jsNewArguments); |
| 1055 constantHandler.registerCompileTimeConstant(constant); | 1124 constantHandler.registerCompileTimeConstant(constant); |
| 1056 return constant; | 1125 return constant; |
| 1057 } | 1126 } |
| 1058 | 1127 |
| 1059 error(Node node) { | 1128 error(Node node) { |
| 1060 // TODO(floitsch): get the list of constants that are currently compiled | 1129 // TODO(floitsch): get the list of constants that are currently compiled |
| 1061 // and present some kind of stack-trace. | 1130 // and present some kind of stack-trace. |
| 1062 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 1131 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 1063 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); | 1132 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| 1064 } | 1133 } |
| 1065 } | 1134 } |
| OLD | NEW |