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 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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, |
| 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 List<Constant> evaluateConstructorArguments(Send send, |
| 937 void assignArgumentsToParameters( | 937 FunctionElement constructor) { |
| 938 FunctionParameters parameters, | 938 FunctionParameters parameters = constructor.computeParameters(compiler); |
| 939 Map<Element, Constant> constructorDefinitions, | 939 if (send.arguments.isEmpty() && parameters.parameterCount == 0) { |
| 940 Map<Element, Constant> fieldValues) { | 940 return const <Constant>[]; |
| 941 Send send = node.send; | 941 } |
| 942 if (send.arguments.isEmpty() && parameters.parameterCount == 0) return; | 942 List<Constant> arguments = <Constant>[]; |
| 943 List<Constant> arguments = <Constant>[]; | 943 Selector selector = elements.getSelector(send); |
| 944 Selector selector = elements.getSelector(send); | |
| 945 | 944 |
| 946 Function compileArgument = evaluate; | 945 Function compileArgument = (x) => evaluate(x); |
| 947 Function compileConstant = constantHandler.compileVariable; | 946 Function compileConstant = (x) => compiler.compileVariable(x); |
|
ahe
2012/03/23 10:56:15
What is up with this? Is there a VM bug? I have no
| |
| 948 bool succeeded = selector.addSendArgumentsToList( | 947 bool succeeded = selector.addSendArgumentsToList( |
| 949 send, arguments, parameters, compileArgument, compileConstant); | 948 send, arguments, parameters, compileArgument, compileConstant); |
| 950 if (!succeeded) error(node); | 949 if (!succeeded) error(send); |
| 950 return arguments; | |
| 951 } | |
| 951 | 952 |
| 952 int index = 0; | 953 void assignConstructorArgumentsToParameters( |
| 953 parameters.forEachParameter((Element parameter) { | 954 FunctionElement constructor, List<Constant> arguments, |
| 954 Constant argument = arguments[index++]; | 955 Map<Element, Constant> fieldValues) { |
| 955 constructorDefinitions[parameter] = argument; | 956 // Assign arguments to parameters. |
| 956 if (parameter.kind == ElementKind.FIELD_PARAMETER) { | 957 FunctionParameters parameters = constructor.computeParameters(compiler); |
| 957 FieldParameterElement fieldParameterElement = parameter; | 958 int index = 0; |
| 958 fieldValues[fieldParameterElement.fieldElement] = argument; | 959 parameters.forEachParameter((Element parameter) { |
| 959 } | 960 Constant argument = arguments[index++]; |
| 960 }); | 961 definitions[parameter] = argument; |
| 962 if (parameter.kind == ElementKind.FIELD_PARAMETER) { | |
| 963 FieldParameterElement fieldParameterElement = parameter; | |
| 964 fieldValues[fieldParameterElement.fieldElement] = argument; | |
| 965 } | |
| 966 }); | |
| 967 } | |
| 968 | |
| 969 void evaluateConstructorInitializers( | |
| 970 FunctionElement constructor, | |
| 971 Set<FunctionElement> executedConstructors, | |
| 972 Map<Element, Constant> fieldValues) { | |
| 973 | |
| 974 void evaluateSuperOrRedirectSend(FunctionElement targetConstructor, | |
| 975 List<Constant> targetArguments) { | |
| 976 compiler.withCurrentElement(targetConstructor, () { | |
| 977 evaluateConstructorFieldValues( | |
| 978 targetConstructor, targetArguments, executedConstructors, | |
| 979 fieldValues); | |
| 980 }); | |
| 961 } | 981 } |
| 962 | 982 |
| 963 void compileInitializers(Link<Node> initializers, | 983 FunctionExpression functionNode = constructor.parseNode(compiler); |
| 964 CompileTimeConstantEvaluator evaluator, | 984 NodeList initializerList = functionNode.initializers; |
| 965 TreeElements constructorElements, | 985 |
| 966 Map<Element, Constant> constructorDefinitions, | 986 bool foundSuperOrRedirect = false; |
| 967 Map<Element, Constant> fieldValues) { | 987 |
| 968 for (Link<Node> link = initializers; !link.isEmpty(); link = link.tail) { | 988 if (initializerList !== null) { |
| 989 for (Link<Node> link = initializerList.nodes; | |
| 990 !link.isEmpty(); | |
| 991 link = link.tail) { | |
| 969 assert(link.head is Send); | 992 assert(link.head is Send); |
| 970 if (link.head is !SendSet) { | 993 if (link.head is !SendSet) { |
| 971 // A super initializer or constructor redirection. | 994 // A super initializer or constructor redirection. |
| 972 Send call = link.head; | 995 Send call = link.head; |
| 973 assert(Initializers.isSuperConstructorCall(call) || | 996 FunctionElement targetConstructor = elements[call]; |
| 974 Initializers.isConstructorRedirect(call)); | 997 List<Constant> targetArguments = |
| 975 compiler.unimplemented("ConstantHandler with this or super", | 998 evaluateConstructorArguments(call, targetConstructor); |
| 976 node: call); | 999 evaluateSuperOrRedirectSend(targetConstructor, targetArguments); |
| 1000 foundSuperOrRedirect = true; | |
| 977 } else { | 1001 } else { |
| 978 // A field initializer. | 1002 // A field initializer. |
| 979 SendSet init = link.head; | 1003 SendSet init = link.head; |
| 980 Link<Node> arguments = init.arguments; | 1004 Link<Node> initArguments = init.arguments; |
| 981 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); | 1005 assert(!initArguments.isEmpty() && initArguments.tail.isEmpty()); |
| 982 Constant fieldValue = evaluator.evaluate(arguments.head); | 1006 Constant fieldValue = evaluate(initArguments.head); |
| 983 fieldValues[constructorElements[init]] = fieldValue; | 1007 fieldValues[elements[init]] = fieldValue; |
| 984 } | 1008 } |
| 985 } | 1009 } |
| 986 } | 1010 } |
| 987 | 1011 |
| 1012 if (!foundSuperOrRedirect) { | |
| 1013 // No super initializer found. Try to find the default constructor if | |
| 1014 // the class is not Object. | |
| 1015 ClassElement enclosingClass = constructor.enclosingElement; | |
| 1016 ClassElement superClass = enclosingClass.superclass; | |
| 1017 if (enclosingClass != compiler.objectClass) { | |
| 1018 assert(superClass !== null); | |
| 1019 assert(superClass.isResolved); | |
| 1020 FunctionElement targetConstructor = | |
| 1021 superClass.lookupConstructor(superClass.name); | |
| 1022 if (targetConstructor === null) { | |
| 1023 compiler.internalError("no default constructor available"); | |
| 1024 } | |
| 1025 evaluateSuperOrRedirectSend(targetConstructor, const <Constant>[]); | |
| 1026 } | |
| 1027 } | |
| 1028 } | |
| 1029 | |
| 1030 void evaluateConstructorFieldValues(FunctionElement constructor, | |
| 1031 List<Constant> arguments, | |
| 1032 Set<FunctionElement> executedConstructors, | |
| 1033 Map<Element, Constant> fieldValues) { | |
| 1034 compiler.withCurrentElement(constructor, () { | |
| 1035 if (executedConstructors.contains(constructor)) { | |
| 1036 MessageKind kind = MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE; | |
| 1037 compiler.reportError(constructor.parseNode(compiler), | |
| 1038 new CompileTimeConstantError(kind, const [])); | |
| 1039 } | |
| 1040 executedConstructors.add(constructor); | |
| 1041 | |
| 1042 TreeElements constructorElements = | |
| 1043 compiler.resolver.resolveMethodElement(constructor); | |
| 1044 CompileTimeConstantEvaluator evaluator = | |
| 1045 new CompileTimeConstantEvaluator.insideConstructor( | |
| 1046 constantHandler, constructorElements, compiler); | |
| 1047 | |
| 1048 evaluator.assignConstructorArgumentsToParameters( | |
| 1049 constructor, arguments, fieldValues); | |
| 1050 evaluator.evaluateConstructorInitializers( | |
| 1051 constructor, executedConstructors, fieldValues); | |
| 1052 }); | |
| 1053 } | |
| 1054 | |
| 1055 Constant visitNewExpression(NewExpression node) { | |
| 988 List<Constant> buildJsNewArguments(ClassElement classElement, | 1056 List<Constant> buildJsNewArguments(ClassElement classElement, |
| 989 Map<Element, Constant> fieldValues) { | 1057 Map<Element, Constant> fieldValues) { |
| 990 List<Constant> jsNewArguments = <Constant>[]; | 1058 List<Constant> jsNewArguments = <Constant>[]; |
| 991 for (Element member in classElement.members) { | 1059 // TODO(floitsch): share this code with the emitter, so that we don't |
| 992 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { | 1060 // need to care about the order of fields here. |
| 993 Constant fieldValue = fieldValues[member]; | 1061 while (classElement != compiler.objectClass) { |
| 994 if (fieldValue === null) { | 1062 for (Element member in classElement.members) { |
| 995 // Use the default value. | 1063 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { |
| 996 fieldValue = constantHandler.compileVariable(member); | 1064 Constant fieldValue = fieldValues[member]; |
| 1065 if (fieldValue === null) { | |
| 1066 // Use the default value. | |
| 1067 fieldValue = constantHandler.compileVariable(member); | |
| 1068 } | |
| 1069 jsNewArguments.add(fieldValue); | |
| 997 } | 1070 } |
| 998 jsNewArguments.add(fieldValue); | |
| 999 } | 1071 } |
| 1000 } | 1072 classElement = classElement.superclass; |
| 1001 if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) { | 1073 } |
| 1002 compiler.unimplemented("ConstantHandler with super", node: node); | |
| 1003 } | |
| 1004 return jsNewArguments; | 1074 return jsNewArguments; |
| 1005 } | 1075 } |
| 1006 | 1076 |
| 1007 if (!node.isConst()) error(node); | 1077 if (!node.isConst()) error(node); |
| 1008 | 1078 |
| 1009 FunctionElement constructor = elements[node.send]; | 1079 FunctionElement constructor = elements[node.send]; |
| 1010 TreeElements constructorElements = | 1080 ClassElement classElement = constructor.enclosingElement; |
| 1011 compiler.resolver.resolveMethodElement(constructor); | 1081 if (classElement.isInterface()) { |
| 1012 if (constructor != constructor.defaultImplementation) { | 1082 compiler.resolver.resolveMethodElement(constructor); |
| 1013 constructor = constructor.defaultImplementation; | 1083 constructor = constructor.defaultImplementation; |
| 1014 constructorElements = | 1084 classElement = constructor.enclosingElement; |
| 1015 compiler.resolver.resolveMethodElement(constructor); | |
| 1016 } | 1085 } |
| 1017 | 1086 |
| 1018 List<Constant> jsNewArguments; | 1087 List<Constant> jsNewArguments; |
| 1019 ClassElement classElement = constructor.enclosingElement; | |
| 1020 compiler.withCurrentElement(constructor, () { | 1088 compiler.withCurrentElement(constructor, () { |
| 1021 FunctionExpression functionNode = constructor.parseNode(compiler); | 1089 // We use a set to avoid cyclic redirection constructors. |
| 1022 NodeList initializerList = functionNode.initializers; | 1090 Set<FunctionElement> executedConstructors = new Set<FunctionElement>(); |
| 1023 FunctionParameters parameters = constructor.computeParameters(compiler); | |
| 1024 | |
| 1025 Map<Element, Constant> fieldValues = new Map<Element, Constant>(); | 1091 Map<Element, Constant> fieldValues = new Map<Element, Constant>(); |
| 1026 Map<Element, Constant> constructorDefinitions = | 1092 List<Constant> arguments = |
| 1027 new Map<Element, Constant>(); | 1093 evaluateConstructorArguments(node.send, constructor); |
| 1028 | 1094 evaluateConstructorFieldValues( |
| 1029 assignArgumentsToParameters(parameters, constructorDefinitions, | 1095 constructor, arguments, executedConstructors, fieldValues); |
| 1030 fieldValues); | |
| 1031 CompileTimeConstantEvaluator initializerEvaluator = | |
| 1032 new CompileTimeConstantEvaluator.insideConstructor( | |
| 1033 constantHandler, constructorElements, compiler, | |
| 1034 constructorDefinitions); | |
| 1035 if (initializerList !== null) { | |
| 1036 Link<Node> initializers = functionNode.initializers.nodes; | |
| 1037 compileInitializers(initializers, | |
| 1038 initializerEvaluator, | |
| 1039 constructorElements, | |
| 1040 constructorDefinitions, | |
| 1041 fieldValues); | |
| 1042 } | |
| 1043 jsNewArguments = buildJsNewArguments(classElement, fieldValues); | 1096 jsNewArguments = buildJsNewArguments(classElement, fieldValues); |
| 1044 }); | 1097 }); |
| 1045 | 1098 |
| 1046 | |
| 1047 compiler.registerInstantiatedClass(classElement); | 1099 compiler.registerInstantiatedClass(classElement); |
| 1048 // TODO(floitsch): take generic types into account. | 1100 // TODO(floitsch): take generic types into account. |
| 1049 Type type = classElement.computeType(compiler); | 1101 Type type = classElement.computeType(compiler); |
| 1050 Constant constant = new ConstructedConstant(type, jsNewArguments); | 1102 Constant constant = new ConstructedConstant(type, jsNewArguments); |
| 1051 constantHandler.registerCompileTimeConstant(constant); | 1103 constantHandler.registerCompileTimeConstant(constant); |
| 1052 return constant; | 1104 return constant; |
| 1053 } | 1105 } |
| 1054 | 1106 |
| 1055 error(Node node) { | 1107 error(Node node) { |
| 1056 // TODO(floitsch): get the list of constants that are currently compiled | 1108 // TODO(floitsch): get the list of constants that are currently compiled |
| 1057 // and present some kind of stack-trace. | 1109 // and present some kind of stack-trace. |
| 1058 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 1110 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 1059 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); | 1111 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| 1060 } | 1112 } |
| 1061 } | 1113 } |
| OLD | NEW |