| 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 library dart2js.compile_time_constant_evaluator; | 5 library dart2js.compile_time_constant_evaluator; |
| 6 | 6 |
| 7 import 'common/resolution.dart' show Resolution; | 7 import 'common/resolution.dart' show Resolution; |
| 8 import 'common/tasks.dart' show CompilerTask, Measurer; | 8 import 'common/tasks.dart' show CompilerTask, Measurer; |
| 9 import 'common.dart'; | 9 import 'common.dart'; |
| 10 import 'compiler.dart' show Compiler; | 10 import 'compiler.dart' show Compiler; |
| (...skipping 946 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 957 node, callStructure, arguments, implementation, | 957 node, callStructure, arguments, implementation, |
| 958 compileArgument: (node) => concreteArgumentMap[node]); | 958 compileArgument: (node) => concreteArgumentMap[node]); |
| 959 concreteArguments = concreteArgumentMap.values.toList(); | 959 concreteArguments = concreteArgumentMap.values.toList(); |
| 960 } else { | 960 } else { |
| 961 assert(normalizedArguments != null); | 961 assert(normalizedArguments != null); |
| 962 concreteArguments = normalizedArguments; | 962 concreteArguments = normalizedArguments; |
| 963 } | 963 } |
| 964 if (constructor.isFromEnvironmentConstructor) { | 964 if (constructor.isFromEnvironmentConstructor) { |
| 965 return createFromEnvironmentConstant(node, constructedType, constructor, | 965 return createFromEnvironmentConstant(node, constructedType, constructor, |
| 966 callStructure, normalizedArguments, concreteArguments); | 966 callStructure, normalizedArguments, concreteArguments); |
| 967 } else if (compiler.serialization.isDeserialized(constructor)) { |
| 968 ConstructedConstantExpression expression = |
| 969 new ConstructedConstantExpression(type, constructor, callStructure, |
| 970 concreteArguments.map((c) => c.expression).toList()); |
| 971 return new AstConstant( |
| 972 context, |
| 973 node, |
| 974 expression, |
| 975 expression.evaluate( |
| 976 new _CompilerEnvironment(compiler), constantSystem)); |
| 967 } else { | 977 } else { |
| 968 return makeConstructedConstant( | 978 return makeConstructedConstant( |
| 969 compiler, | 979 compiler, |
| 970 handler, | 980 handler, |
| 971 context, | 981 context, |
| 972 node, | 982 node, |
| 973 type, | 983 type, |
| 974 constructor, | 984 constructor, |
| 975 constructedType, | 985 constructedType, |
| 976 implementation, | 986 implementation, |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1081 Element context, | 1091 Element context, |
| 1082 Node node, | 1092 Node node, |
| 1083 InterfaceType type, | 1093 InterfaceType type, |
| 1084 ConstructorElement constructor, | 1094 ConstructorElement constructor, |
| 1085 InterfaceType constructedType, | 1095 InterfaceType constructedType, |
| 1086 ConstructorElement target, | 1096 ConstructorElement target, |
| 1087 CallStructure callStructure, | 1097 CallStructure callStructure, |
| 1088 List<AstConstant> concreteArguments, | 1098 List<AstConstant> concreteArguments, |
| 1089 List<AstConstant> normalizedArguments) { | 1099 List<AstConstant> normalizedArguments) { |
| 1090 if (target.isRedirectingFactory) { | 1100 if (target.isRedirectingFactory) { |
| 1091 // This happens is case of cyclic redirection. | 1101 // This happens in case of cyclic redirection. |
| 1092 assert(invariant(node, compiler.compilationFailed, | 1102 assert(invariant(node, compiler.compilationFailed, |
| 1093 message: "makeConstructedConstant can only be called with the " | 1103 message: "makeConstructedConstant can only be called with the " |
| 1094 "effective target: $constructor")); | 1104 "effective target: $constructor")); |
| 1095 return new ErroneousAstConstant(context, node); | 1105 return new ErroneousAstConstant(context, node); |
| 1096 } | 1106 } |
| 1097 assert(invariant( | 1107 assert(invariant( |
| 1098 node, | 1108 node, |
| 1099 callStructure.signatureApplies(constructor.functionSignature) || | 1109 callStructure.signatureApplies(constructor.functionSignature) || |
| 1100 compiler.compilationFailed, | 1110 compiler.compilationFailed, |
| 1101 message: "Call structure $callStructure does not apply to constructor " | 1111 message: "Call structure $callStructure does not apply to constructor " |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1155 final ConstructorElement constructor; | 1165 final ConstructorElement constructor; |
| 1156 final Map<Element, AstConstant> definitions; | 1166 final Map<Element, AstConstant> definitions; |
| 1157 final Map<Element, AstConstant> fieldValues; | 1167 final Map<Element, AstConstant> fieldValues; |
| 1158 final ResolvedAst resolvedAst; | 1168 final ResolvedAst resolvedAst; |
| 1159 | 1169 |
| 1160 /** | 1170 /** |
| 1161 * Documentation wanted -- johnniwinther | 1171 * Documentation wanted -- johnniwinther |
| 1162 * | 1172 * |
| 1163 * Invariant: [constructor] must be an implementation element. | 1173 * Invariant: [constructor] must be an implementation element. |
| 1164 */ | 1174 */ |
| 1165 ConstructorEvaluator(InterfaceType this.constructedType, | 1175 ConstructorEvaluator( |
| 1166 FunctionElement constructor, ConstantCompiler handler, Compiler compiler) | 1176 InterfaceType this.constructedType, |
| 1177 ConstructorElement constructor, |
| 1178 ConstantCompiler handler, |
| 1179 Compiler compiler) |
| 1167 : this.constructor = constructor, | 1180 : this.constructor = constructor, |
| 1168 this.definitions = new Map<Element, AstConstant>(), | 1181 this.definitions = new Map<Element, AstConstant>(), |
| 1169 this.fieldValues = new Map<Element, AstConstant>(), | 1182 this.fieldValues = new Map<Element, AstConstant>(), |
| 1170 this.resolvedAst = | 1183 this.resolvedAst = |
| 1171 compiler.resolution.computeResolvedAst(constructor.declaration), | 1184 compiler.resolution.computeResolvedAst(constructor.declaration), |
| 1172 super(handler, null, compiler, isConst: true) { | 1185 super(handler, null, compiler, isConst: true) { |
| 1173 assert(invariant(constructor, constructor.isImplementation)); | 1186 assert(invariant(constructor, constructor.isImplementation)); |
| 1174 } | 1187 } |
| 1175 | 1188 |
| 1176 @override | 1189 @override |
| 1190 Element get context => resolvedAst.element; |
| 1191 |
| 1192 @override |
| 1177 TreeElements get elements => resolvedAst.elements; | 1193 TreeElements get elements => resolvedAst.elements; |
| 1178 | 1194 |
| 1179 AstConstant visitSend(Send send) { | 1195 AstConstant visitSend(Send send) { |
| 1180 Element element = elements[send]; | 1196 Element element = elements[send]; |
| 1181 if (Elements.isLocal(element)) { | 1197 if (Elements.isLocal(element)) { |
| 1182 AstConstant constant = definitions[element]; | 1198 AstConstant constant = definitions[element]; |
| 1183 if (constant == null) { | 1199 if (constant == null) { |
| 1184 reporter.internalError(send, "Local variable without value."); | 1200 reporter.internalError(send, "Local variable without value."); |
| 1185 } | 1201 } |
| 1186 return constant; | 1202 return constant; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1226 if (compiler.options.enableInitializingFormalAccess) { | 1242 if (compiler.options.enableInitializingFormalAccess) { |
| 1227 definitions[parameter] = argument; | 1243 definitions[parameter] = argument; |
| 1228 } | 1244 } |
| 1229 } else { | 1245 } else { |
| 1230 potentiallyCheckType(parameter, argument); | 1246 potentiallyCheckType(parameter, argument); |
| 1231 definitions[parameter] = argument; | 1247 definitions[parameter] = argument; |
| 1232 } | 1248 } |
| 1233 }); | 1249 }); |
| 1234 } | 1250 } |
| 1235 | 1251 |
| 1236 void evaluateSuperOrRedirectSend( | 1252 void evaluateSuperOrRedirectSend(List<AstConstant> compiledArguments, |
| 1237 List<AstConstant> compiledArguments, FunctionElement targetConstructor) { | 1253 CallStructure callStructure, ConstructorElement targetConstructor) { |
| 1238 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 1254 InterfaceType type = |
| 1239 constructedType.asInstanceOf(targetConstructor.enclosingClass), | 1255 constructedType.asInstanceOf(targetConstructor.enclosingClass); |
| 1240 targetConstructor, | 1256 if (compiler.serialization.isDeserialized(targetConstructor)) { |
| 1241 handler, | 1257 List<ConstantExpression> arguments = |
| 1242 compiler); | 1258 compiledArguments.map((c) => c.expression).toList(); |
| 1243 evaluator.evaluateConstructorFieldValues(compiledArguments); | 1259 ConstructedConstantExpression expression = |
| 1244 // Copy over the fieldValues from the super/redirect-constructor. | 1260 new ConstructedConstantExpression( |
| 1245 // No need to go through [updateFieldValue] because the | 1261 type, targetConstructor, callStructure, arguments); |
| 1246 // assignments have already been checked in checked mode. | 1262 |
| 1247 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); | 1263 Map<FieldElement, ConstantExpression> fields = |
| 1264 expression.computeInstanceFields(); |
| 1265 fields.forEach((FieldElement field, ConstantExpression expression) { |
| 1266 ConstantValue value = expression.evaluate( |
| 1267 new _CompilerEnvironment(compiler), constantSystem); |
| 1268 fieldValues[field] = new AstConstant(context, null, expression, value); |
| 1269 }); |
| 1270 } else { |
| 1271 ConstructorEvaluator evaluator = |
| 1272 new ConstructorEvaluator(type, targetConstructor, handler, compiler); |
| 1273 evaluator.evaluateConstructorFieldValues(compiledArguments); |
| 1274 // Copy over the fieldValues from the super/redirect-constructor. |
| 1275 // No need to go through [updateFieldValue] because the |
| 1276 // assignments have already been checked in checked mode. |
| 1277 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); |
| 1278 } |
| 1248 } | 1279 } |
| 1249 | 1280 |
| 1250 /** | 1281 /** |
| 1251 * Runs through the initializers of the given [constructor] and updates | 1282 * Runs through the initializers of the given [constructor] and updates |
| 1252 * the [fieldValues] map. | 1283 * the [fieldValues] map. |
| 1253 */ | 1284 */ |
| 1254 void evaluateConstructorInitializers() { | 1285 void evaluateConstructorInitializers() { |
| 1255 ResolvedAst resolvedAst = constructor.resolvedAst; | 1286 ResolvedAst resolvedAst = constructor.resolvedAst; |
| 1256 if (resolvedAst.kind != ResolvedAstKind.PARSED) { | 1287 if (resolvedAst.kind != ResolvedAstKind.PARSED) { |
| 1257 List<AstConstant> compiledArguments = <AstConstant>[]; | 1288 List<AstConstant> compiledArguments = <AstConstant>[]; |
| 1258 | 1289 |
| 1259 Function compileArgument = (element) => definitions[element]; | 1290 Function compileArgument = (element) => definitions[element]; |
| 1260 Function compileConstant = handler.compileConstant; | 1291 Function compileConstant = handler.compileConstant; |
| 1261 FunctionElement target = constructor.definingConstructor.implementation; | 1292 FunctionElement target = constructor.definingConstructor.implementation; |
| 1262 CallStructure.addForwardingElementArgumentsToList(constructor, | 1293 CallStructure.addForwardingElementArgumentsToList(constructor, |
| 1263 compiledArguments, target, compileArgument, compileConstant); | 1294 compiledArguments, target, compileArgument, compileConstant); |
| 1264 evaluateSuperOrRedirectSend(compiledArguments, target); | 1295 CallStructure callStructure = |
| 1296 new CallStructure.fromSignature(target.functionSignature); |
| 1297 evaluateSuperOrRedirectSend(compiledArguments, callStructure, target); |
| 1265 return; | 1298 return; |
| 1266 } | 1299 } |
| 1267 FunctionExpression functionNode = resolvedAst.node; | 1300 FunctionExpression functionNode = resolvedAst.node; |
| 1268 NodeList initializerList = functionNode.initializers; | 1301 NodeList initializerList = functionNode.initializers; |
| 1269 | 1302 |
| 1270 bool foundSuperOrRedirect = false; | 1303 bool foundSuperOrRedirect = false; |
| 1271 | 1304 |
| 1272 if (initializerList != null) { | 1305 if (initializerList != null) { |
| 1273 for (Link<Node> link = initializerList.nodes; | 1306 for (Link<Node> link = initializerList.nodes; |
| 1274 !link.isEmpty; | 1307 !link.isEmpty; |
| 1275 link = link.tail) { | 1308 link = link.tail) { |
| 1276 assert(link.head is Send); | 1309 assert(link.head is Send); |
| 1277 if (link.head is! SendSet) { | 1310 if (link.head is! SendSet) { |
| 1278 // A super initializer or constructor redirection. | 1311 // A super initializer or constructor redirection. |
| 1279 Send call = link.head; | 1312 Send call = link.head; |
| 1280 FunctionElement target = elements[call]; | 1313 FunctionElement target = elements[call]; |
| 1281 if (!target.isMalformed) { | 1314 if (!target.isMalformed) { |
| 1315 CallStructure callStructure = |
| 1316 elements.getSelector(call).callStructure; |
| 1282 List<AstConstant> compiledArguments = | 1317 List<AstConstant> compiledArguments = |
| 1283 evaluateArgumentsToConstructor( | 1318 evaluateArgumentsToConstructor( |
| 1284 call, | 1319 call, callStructure, call.arguments, target, |
| 1285 elements.getSelector(call).callStructure, | |
| 1286 call.arguments, | |
| 1287 target, | |
| 1288 compileArgument: evaluateConstant); | 1320 compileArgument: evaluateConstant); |
| 1289 evaluateSuperOrRedirectSend(compiledArguments, target); | 1321 evaluateSuperOrRedirectSend( |
| 1322 compiledArguments, callStructure, target); |
| 1290 } | 1323 } |
| 1291 foundSuperOrRedirect = true; | 1324 foundSuperOrRedirect = true; |
| 1292 } else { | 1325 } else { |
| 1293 // A field initializer. | 1326 // A field initializer. |
| 1294 SendSet init = link.head; | 1327 SendSet init = link.head; |
| 1295 Link<Node> initArguments = init.arguments; | 1328 Link<Node> initArguments = init.arguments; |
| 1296 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); | 1329 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); |
| 1297 AstConstant fieldValue = evaluate(initArguments.head); | 1330 AstConstant fieldValue = evaluate(initArguments.head); |
| 1298 updateFieldValue(init, elements[init], fieldValue); | 1331 updateFieldValue(init, elements[init], fieldValue); |
| 1299 } | 1332 } |
| 1300 } | 1333 } |
| 1301 } | 1334 } |
| 1302 | 1335 |
| 1303 if (!foundSuperOrRedirect) { | 1336 if (!foundSuperOrRedirect) { |
| 1304 // No super initializer found. Try to find the default constructor if | 1337 // No super initializer found. Try to find the default constructor if |
| 1305 // the class is not Object. | 1338 // the class is not Object. |
| 1306 ClassElement enclosingClass = constructor.enclosingClass; | 1339 ClassElement enclosingClass = constructor.enclosingClass; |
| 1307 ClassElement superClass = enclosingClass.superclass; | 1340 ClassElement superClass = enclosingClass.superclass; |
| 1308 if (!enclosingClass.isObject) { | 1341 if (!enclosingClass.isObject) { |
| 1309 assert(superClass != null); | 1342 assert(superClass != null); |
| 1310 assert(superClass.isResolved); | 1343 assert(superClass.isResolved); |
| 1311 | 1344 |
| 1312 FunctionElement targetConstructor = | 1345 FunctionElement targetConstructor = |
| 1313 superClass.lookupDefaultConstructor(); | 1346 superClass.lookupDefaultConstructor(); |
| 1314 // If we do not find a default constructor, an error was reported | 1347 // If we do not find a default constructor, an error was reported |
| 1315 // already and compilation will fail anyway. So just ignore that case. | 1348 // already and compilation will fail anyway. So just ignore that case. |
| 1316 if (targetConstructor != null) { | 1349 if (targetConstructor != null) { |
| 1350 CallStructure callStructure = CallStructure.NO_ARGS; |
| 1317 List<AstConstant> compiledArguments = evaluateArgumentsToConstructor( | 1351 List<AstConstant> compiledArguments = evaluateArgumentsToConstructor( |
| 1318 functionNode, | 1352 functionNode, |
| 1319 CallStructure.NO_ARGS, | 1353 callStructure, |
| 1320 const Link<Node>(), | 1354 const Link<Node>(), |
| 1321 targetConstructor); | 1355 targetConstructor); |
| 1322 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor); | 1356 evaluateSuperOrRedirectSend( |
| 1357 compiledArguments, callStructure, targetConstructor); |
| 1323 } | 1358 } |
| 1324 } | 1359 } |
| 1325 } | 1360 } |
| 1326 } | 1361 } |
| 1327 | 1362 |
| 1328 /** | 1363 /** |
| 1329 * Simulates the execution of the [constructor] with the given | 1364 * Simulates the execution of the [constructor] with the given |
| 1330 * [arguments] to obtain the field values that need to be passed to the | 1365 * [arguments] to obtain the field values that need to be passed to the |
| 1331 * native JavaScript constructor. | 1366 * native JavaScript constructor. |
| 1332 */ | 1367 */ |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1409 class _CompilerEnvironment implements Environment { | 1444 class _CompilerEnvironment implements Environment { |
| 1410 final Compiler compiler; | 1445 final Compiler compiler; |
| 1411 | 1446 |
| 1412 _CompilerEnvironment(this.compiler); | 1447 _CompilerEnvironment(this.compiler); |
| 1413 | 1448 |
| 1414 @override | 1449 @override |
| 1415 String readFromEnvironment(String name) { | 1450 String readFromEnvironment(String name) { |
| 1416 return compiler.fromEnvironment(name); | 1451 return compiler.fromEnvironment(name); |
| 1417 } | 1452 } |
| 1418 } | 1453 } |
| OLD | NEW |