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 js_backend; | 5 part of js_backend; |
6 | 6 |
7 typedef void Recompile(Element element); | 7 typedef void Recompile(Element element); |
8 | 8 |
9 class ReturnInfo { | 9 class ReturnInfo { |
10 HType returnType; | 10 HType returnType; |
(...skipping 858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
869 compiler.jsInvocationMirrorClass.computeType(compiler)); | 869 compiler.jsInvocationMirrorClass.computeType(compiler)); |
870 argumentTypes.registerDynamicInvocation(types, new Selector.noSuchMethod()); | 870 argumentTypes.registerDynamicInvocation(types, new Selector.noSuchMethod()); |
871 } | 871 } |
872 | 872 |
873 void registerInstantiatedClass(ClassElement cls, Enqueuer enqueuer) { | 873 void registerInstantiatedClass(ClassElement cls, Enqueuer enqueuer) { |
874 if (!seenAnyClass) { | 874 if (!seenAnyClass) { |
875 initializeInterceptorElements(); | 875 initializeInterceptorElements(); |
876 initializeNoSuchMethod(); | 876 initializeNoSuchMethod(); |
877 seenAnyClass = true; | 877 seenAnyClass = true; |
878 } | 878 } |
879 | |
880 // Register any helper that will be needed by the backend. | |
881 if (enqueuer.isResolutionQueue) { | |
882 if (cls == compiler.intClass | |
883 || cls == compiler.doubleClass | |
884 || cls == compiler.numClass) { | |
885 // The backend will try to optimize number operations and use the | |
886 // `iae` helper directly. | |
887 enqueuer.registerStaticUse( | |
888 compiler.findHelper(const SourceString('iae'))); | |
889 } else if (cls == compiler.listClass | |
890 ||cls == compiler.stringClass) { | |
kasperl
2013/02/18 10:31:52
||cls -> cls
ngeoffray
2013/02/18 11:32:18
Done.
| |
891 // The backend will try to optimize array and string access and use the | |
892 // `ioore` and `iae` helpers directly. | |
893 enqueuer.registerStaticUse( | |
894 compiler.findHelper(const SourceString('ioore'))); | |
895 enqueuer.registerStaticUse( | |
896 compiler.findHelper(const SourceString('iae'))); | |
897 } else if (cls == compiler.functionClass) { | |
898 enqueuer.registerInstantiatedClass(compiler.closureClass); | |
899 } else if (cls == compiler.mapClass) { | |
900 // The backend will use a literal list to initialize the entries | |
901 // of the map. | |
902 enqueuer.registerInstantiatedClass(compiler.listClass); | |
903 enqueuer.registerInstantiatedClass(compiler.mapLiteralClass); | |
904 enqueueInResolution(getMapMaker()); | |
905 } | |
906 } | |
879 ClassElement result = null; | 907 ClassElement result = null; |
880 if (cls == compiler.stringClass) { | 908 if (cls == compiler.stringClass) { |
881 addInterceptors(jsStringClass, enqueuer); | 909 addInterceptors(jsStringClass, enqueuer); |
882 } else if (cls == compiler.listClass) { | 910 } else if (cls == compiler.listClass) { |
883 addInterceptors(jsArrayClass, enqueuer); | 911 addInterceptors(jsArrayClass, enqueuer); |
884 // The backend will try to optimize array access and use the | |
885 // `ioore` and `iae` helpers directly. | |
886 if (enqueuer.isResolutionQueue) { | |
887 enqueuer.registerStaticUse( | |
888 compiler.findHelper(const SourceString('ioore'))); | |
889 enqueuer.registerStaticUse( | |
890 compiler.findHelper(const SourceString('iae'))); | |
891 } | |
892 } else if (cls == compiler.intClass) { | 912 } else if (cls == compiler.intClass) { |
893 addInterceptors(jsIntClass, enqueuer); | 913 addInterceptors(jsIntClass, enqueuer); |
894 addInterceptors(jsNumberClass, enqueuer); | 914 addInterceptors(jsNumberClass, enqueuer); |
895 } else if (cls == compiler.doubleClass) { | 915 } else if (cls == compiler.doubleClass) { |
896 addInterceptors(jsDoubleClass, enqueuer); | 916 addInterceptors(jsDoubleClass, enqueuer); |
897 addInterceptors(jsNumberClass, enqueuer); | 917 addInterceptors(jsNumberClass, enqueuer); |
898 } else if (cls == compiler.functionClass) { | 918 } else if (cls == compiler.functionClass) { |
899 addInterceptors(jsFunctionClass, enqueuer); | 919 addInterceptors(jsFunctionClass, enqueuer); |
900 } else if (cls == compiler.boolClass) { | 920 } else if (cls == compiler.boolClass) { |
901 addInterceptors(jsBoolClass, enqueuer); | 921 addInterceptors(jsBoolClass, enqueuer); |
902 } else if (cls == compiler.nullClass) { | 922 } else if (cls == compiler.nullClass) { |
903 addInterceptors(jsNullClass, enqueuer); | 923 addInterceptors(jsNullClass, enqueuer); |
904 } else if (cls == compiler.numClass) { | 924 } else if (cls == compiler.numClass) { |
905 addInterceptors(jsIntClass, enqueuer); | 925 addInterceptors(jsIntClass, enqueuer); |
906 addInterceptors(jsDoubleClass, enqueuer); | 926 addInterceptors(jsDoubleClass, enqueuer); |
907 addInterceptors(jsNumberClass, enqueuer); | 927 addInterceptors(jsNumberClass, enqueuer); |
908 } else if (cls == compiler.mapClass) { | 928 } else if (cls == compiler.mapClass) { |
909 // The backend will use a literal list to initialize the entries | 929 } |
910 // of the map. | 930 |
911 if (enqueuer.isResolutionQueue) { | 931 if (compiler.enableTypeAssertions) { |
912 enqueuer.registerInstantiatedClass(compiler.listClass); | 932 // We need to register is checks for assignments to fields. |
913 enqueuer.registerInstantiatedClass(compiler.mapLiteralClass); | 933 cls.forEachLocalMember((Element member) { |
914 } | 934 if (!member.isInstanceMember() || !member.isField()) return; |
935 DartType type = member.computeType(compiler); | |
936 enqueuer.registerIsCheck(type); | |
937 }); | |
915 } | 938 } |
916 } | 939 } |
917 | 940 |
918 Element get cyclicThrowHelper { | |
919 return compiler.findHelper(const SourceString("throwCyclicInit")); | |
920 } | |
921 | |
922 JavaScriptItemCompilationContext createItemCompilationContext() { | 941 JavaScriptItemCompilationContext createItemCompilationContext() { |
923 return new JavaScriptItemCompilationContext(); | 942 return new JavaScriptItemCompilationContext(); |
924 } | 943 } |
925 | 944 |
926 void enqueueHelpers(ResolutionEnqueuer world) { | 945 void enqueueHelpers(ResolutionEnqueuer world) { |
927 enqueueAllTopLevelFunctions(compiler.jsHelperLibrary, world); | |
928 | |
929 jsIndexingBehaviorInterface = | 946 jsIndexingBehaviorInterface = |
930 compiler.findHelper(const SourceString('JavaScriptIndexingBehavior')); | 947 compiler.findHelper(const SourceString('JavaScriptIndexingBehavior')); |
931 if (jsIndexingBehaviorInterface != null) { | 948 if (jsIndexingBehaviorInterface != null) { |
932 world.registerIsCheck(jsIndexingBehaviorInterface.computeType(compiler)); | 949 world.registerIsCheck(jsIndexingBehaviorInterface.computeType(compiler)); |
933 } | 950 } |
934 | 951 |
935 for (var helper in [const SourceString('Closure'), | 952 if (compiler.enableTypeAssertions) { |
936 const SourceString('ConstantMap'), | 953 // Unconditionally register the helper that checks if the |
937 const SourceString('ConstantProtoMap')]) { | 954 // expression in an if/while/for is a boolean. TODO(ngeoffray): |
kasperl
2013/02/18 10:31:52
Put the TODO on the next line in a "fresh" comment
ngeoffray
2013/02/18 11:32:18
Done.
| |
938 var e = compiler.findHelper(helper); | 955 // Should we have the resolver register those instead? |
939 if (e != null) world.registerInstantiatedClass(e); | 956 Element e = |
957 compiler.findHelper(const SourceString('boolConversionCheck')); | |
958 if (e != null) world.addToWorkList(e); | |
940 } | 959 } |
941 } | 960 } |
942 | 961 |
962 void registerStringInterpolation() { | |
963 enqueueInResolution(getStringInterpolationHelper()); | |
964 } | |
965 | |
966 void registerCatchStatement() { | |
967 enqueueInResolution(getExceptionUnwrapper()); | |
968 } | |
969 | |
970 void registerThrow() { | |
971 enqueueInResolution(getThrowHelper()); | |
972 } | |
973 | |
974 void registerLazyField() { | |
975 enqueueInResolution(getCyclicThrowHelper()); | |
976 } | |
977 | |
978 void registerTypeLiteral() { | |
979 enqueueInResolution(getCreateRuntimeType()); | |
980 } | |
981 | |
982 void registerStackTraceInCatch() { | |
983 enqueueInResolution(getTraceFromException()); | |
984 } | |
985 | |
986 void registerRuntimeType() { | |
987 enqueueInResolution(getSetRuntimeTypeInfo()); | |
988 enqueueInResolution(getGetRuntimeTypeInfo()); | |
989 enqueueInResolution(getGetRuntimeTypeArgument()); | |
990 } | |
991 | |
992 void registerIsCheck(DartType type, Enqueuer world) { | |
993 if (!type.isRaw) { | |
994 enqueueInResolution(getSetRuntimeTypeInfo()); | |
995 enqueueInResolution(getGetRuntimeTypeInfo()); | |
996 enqueueInResolution(getGetRuntimeTypeArgument()); | |
997 enqueueInResolution(getCheckArguments()); | |
998 } | |
999 if (compiler.enableTypeAssertions) { | |
kasperl
2013/02/18 10:31:52
Add a comment that explains why we need to registe
ngeoffray
2013/02/18 11:32:18
Done.
| |
1000 SourceString helperName = getCheckedModeHelper(type); | |
1001 Element e = compiler.findHelper(helperName); | |
1002 world.addToWorkList(e); | |
1003 // We also need the native variant of the check (for DOM types). | |
1004 helperName = nativeNames[helperName.stringValue]; | |
1005 if (helperName != null) { | |
1006 e = compiler.findHelper(helperName); | |
1007 world.addToWorkList(e); | |
1008 } | |
1009 } | |
1010 } | |
1011 | |
1012 void registerAsCheck(DartType type) { | |
1013 SourceString checkedHelperName = getCheckedModeHelper(type); | |
1014 SourceString helperName = castNames[checkedHelperName.stringValue]; | |
1015 Element e = compiler.findHelper(helperName); | |
1016 enqueueInResolution(e); | |
1017 // We also need the native variant of the check (for DOM types). | |
1018 checkedHelperName = nativeNames[checkedHelperName.stringValue]; | |
1019 if (checkedHelperName != null) { | |
1020 helperName = castNames[checkedHelperName.stringValue]; | |
1021 Element e = compiler.findHelper(helperName); | |
1022 enqueueInResolution(e); | |
1023 } | |
1024 } | |
1025 | |
1026 void registerThrowNoSuchMethod() { | |
1027 enqueueInResolution(getThrowNoSuchMethod()); | |
1028 } | |
1029 | |
1030 void registerThrowRuntimeError() { | |
1031 enqueueInResolution(getThrowRuntimeError()); | |
1032 } | |
1033 | |
1034 void registerAbstractClassInstantiation() { | |
1035 enqueueInResolution(getThrowAbstractClassInstantiationError()); | |
1036 } | |
1037 | |
1038 void registerFallThroughError() { | |
1039 enqueueInResolution(getFallThroughError()); | |
1040 } | |
1041 | |
1042 void registerSuperNoSuchMethod() { | |
1043 enqueueInResolution(getCreateInvocationMirror()); | |
1044 } | |
1045 | |
1046 void enqueueInResolution(Element e) { | |
1047 if (e != null) compiler.enqueuer.resolution.addToWorkList(e); | |
1048 } | |
1049 | |
1050 void registerConstantMap() { | |
1051 Element e = compiler.findHelper(const SourceString('ConstantMap')); | |
1052 if (e != null) compiler.enqueuer.resolution.registerInstantiatedClass(e); | |
1053 e = compiler.findHelper(const SourceString('ConstantProtoMap')); | |
1054 if (e != null) compiler.enqueuer.resolution.registerInstantiatedClass(e); | |
1055 } | |
1056 | |
943 void codegen(CodegenWorkItem work) { | 1057 void codegen(CodegenWorkItem work) { |
944 Element element = work.element; | 1058 Element element = work.element; |
945 if (element.kind.category == ElementCategory.VARIABLE) { | 1059 if (element.kind.category == ElementCategory.VARIABLE) { |
946 Constant initialValue = compiler.constantHandler.compileWorkItem(work); | 1060 Constant initialValue = compiler.constantHandler.compileWorkItem(work); |
947 if (initialValue != null) { | 1061 if (initialValue != null) { |
948 return; | 1062 return; |
949 } else { | 1063 } else { |
950 // If the constant-handler was not able to produce a result we have to | 1064 // If the constant-handler was not able to produce a result we have to |
951 // go through the builder (below) to generate the lazy initializer for | 1065 // go through the builder (below) to generate the lazy initializer for |
952 // the static variable. | 1066 // the static variable. |
953 // We also need to register the use of the cyclic-error helper. | 1067 // We also need to register the use of the cyclic-error helper. |
954 compiler.enqueuer.codegen.registerStaticUse(cyclicThrowHelper); | 1068 compiler.enqueuer.codegen.registerStaticUse(getCyclicThrowHelper()); |
kasperl
2013/02/18 10:31:52
Use registerLazyField instead of all this and remo
ngeoffray
2013/02/18 11:32:18
This is at the codegen level, so I cannot call reg
| |
955 } | 1069 } |
956 } | 1070 } |
957 | 1071 |
958 HGraph graph = builder.build(work); | 1072 HGraph graph = builder.build(work); |
959 optimizer.optimize(work, graph, false); | 1073 optimizer.optimize(work, graph, false); |
960 if (work.allowSpeculativeOptimization | 1074 if (work.allowSpeculativeOptimization |
961 && optimizer.trySpeculativeOptimizations(work, graph)) { | 1075 && optimizer.trySpeculativeOptimizations(work, graph)) { |
962 jsAst.Expression code = generator.generateBailoutMethod(work, graph); | 1076 jsAst.Expression code = generator.generateBailoutMethod(work, graph); |
963 generatedBailoutCode[element] = code; | 1077 generatedBailoutCode[element] = code; |
964 optimizer.prepareForSpeculativeOptimizations(work, graph); | 1078 optimizer.prepareForSpeculativeOptimizations(work, graph); |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1187 ? const SourceString('listSuperNativeTypeCheck') | 1301 ? const SourceString('listSuperNativeTypeCheck') |
1188 : const SourceString('listSuperTypeCheck'); | 1302 : const SourceString('listSuperTypeCheck'); |
1189 } else { | 1303 } else { |
1190 return nativeCheck | 1304 return nativeCheck |
1191 ? const SourceString('callTypeCheck') | 1305 ? const SourceString('callTypeCheck') |
1192 : const SourceString('propertyTypeCheck'); | 1306 : const SourceString('propertyTypeCheck'); |
1193 } | 1307 } |
1194 } | 1308 } |
1195 } | 1309 } |
1196 | 1310 |
1311 Map<String, SourceString> nativeNames = const <String, SourceString> { | |
1312 'stringSuperTypeCheck': | |
1313 const SourceString('stringSuperNativeTypeCheck'), | |
1314 'numberOrStringSuperTypeCheck': | |
1315 const SourceString('numberOrStringSuperNativeTypeCheck'), | |
1316 'listSuperTypeCheck': | |
1317 const SourceString('listSuperNativeTypeCheck'), | |
1318 'propertyTypeCheck': | |
1319 const SourceString('callTypeCheck') | |
1320 }; | |
1321 | |
1322 Map<String, SourceString> castNames = const <String, SourceString> { | |
1323 "stringTypeCheck": | |
1324 const SourceString("stringTypeCast"), | |
1325 "doubleTypeCheck": | |
1326 const SourceString("doubleTypeCast"), | |
1327 "numTypeCheck": | |
1328 const SourceString("numTypeCast"), | |
1329 "boolTypeCheck": | |
1330 const SourceString("boolTypeCast"), | |
1331 "functionTypeCheck": | |
1332 const SourceString("functionTypeCast"), | |
1333 "intTypeCheck": | |
1334 const SourceString("intTypeCast"), | |
1335 "numberOrStringSuperNativeTypeCheck": | |
1336 const SourceString("numberOrStringSuperNativeTypeCast"), | |
1337 "numberOrStringSuperTypeCheck": | |
1338 const SourceString("numberOrStringSuperTypeCast"), | |
1339 "stringSuperNativeTypeCheck": | |
1340 const SourceString("stringSuperNativeTypeCast"), | |
1341 "stringSuperTypeCheck": | |
1342 const SourceString("stringSuperTypeCast"), | |
1343 "listTypeCheck": | |
1344 const SourceString("listTypeCast"), | |
1345 "listSuperNativeTypeCheck": | |
1346 const SourceString("listSuperNativeTypeCast"), | |
1347 "listSuperTypeCheck": | |
1348 const SourceString("listSuperTypeCast"), | |
1349 "callTypeCheck": | |
1350 const SourceString("callTypeCast"), | |
1351 "propertyTypeCheck": | |
1352 const SourceString("propertyTypeCast"), | |
1353 // TODO(johnniwinther): Add a malformedTypeCast which produces a TypeError | |
1354 // with another message. | |
1355 "malformedTypeCheck": | |
1356 const SourceString("malformedTypeCheck") | |
1357 }; | |
1358 | |
1197 void dumpInferredTypes() { | 1359 void dumpInferredTypes() { |
1198 print("Inferred argument types:"); | 1360 print("Inferred argument types:"); |
1199 print("------------------------"); | 1361 print("------------------------"); |
1200 argumentTypes.dump(); | 1362 argumentTypes.dump(); |
1201 print(""); | 1363 print(""); |
1202 print("Inferred return types:"); | 1364 print("Inferred return types:"); |
1203 print("----------------------"); | 1365 print("----------------------"); |
1204 dumpReturnTypes(); | 1366 dumpReturnTypes(); |
1205 print(""); | 1367 print(""); |
1206 print("Inferred field types:"); | 1368 print("Inferred field types:"); |
(...skipping 13 matching lines...) Expand all Loading... | |
1220 Element getThrowMalformedSubtypeError() { | 1382 Element getThrowMalformedSubtypeError() { |
1221 return compiler.findHelper( | 1383 return compiler.findHelper( |
1222 const SourceString('throwMalformedSubtypeError')); | 1384 const SourceString('throwMalformedSubtypeError')); |
1223 } | 1385 } |
1224 | 1386 |
1225 Element getThrowAbstractClassInstantiationError() { | 1387 Element getThrowAbstractClassInstantiationError() { |
1226 return compiler.findHelper( | 1388 return compiler.findHelper( |
1227 const SourceString('throwAbstractClassInstantiationError')); | 1389 const SourceString('throwAbstractClassInstantiationError')); |
1228 } | 1390 } |
1229 | 1391 |
1392 Element getStringInterpolationHelper() { | |
1393 return compiler.findHelper(const SourceString('S')); | |
1394 } | |
1395 | |
1396 Element getThrowHelper() { | |
1397 return compiler.findHelper(const SourceString(r'$throw')); | |
1398 } | |
1399 | |
1230 Element getClosureConverter() { | 1400 Element getClosureConverter() { |
1231 return compiler.findHelper(const SourceString('convertDartClosureToJS')); | 1401 return compiler.findHelper(const SourceString('convertDartClosureToJS')); |
1232 } | 1402 } |
1233 | 1403 |
1234 Element getTraceFromException() { | 1404 Element getTraceFromException() { |
1235 return compiler.findHelper(const SourceString('getTraceFromException')); | 1405 return compiler.findHelper(const SourceString('getTraceFromException')); |
1236 } | 1406 } |
1237 | 1407 |
1238 Element getMapMaker() { | 1408 Element getMapMaker() { |
1239 return compiler.findHelper(const SourceString('makeLiteralMap')); | 1409 return compiler.findHelper(const SourceString('makeLiteralMap')); |
1240 } | 1410 } |
1241 | 1411 |
1242 Element getSetRuntimeTypeInfo() { | 1412 Element getSetRuntimeTypeInfo() { |
1243 return compiler.findHelper(const SourceString('setRuntimeTypeInfo')); | 1413 return compiler.findHelper(const SourceString('setRuntimeTypeInfo')); |
1244 } | 1414 } |
1245 | 1415 |
1246 Element getGetRuntimeTypeInfo() { | 1416 Element getGetRuntimeTypeInfo() { |
1247 return compiler.findHelper(const SourceString('getRuntimeTypeInfo')); | 1417 return compiler.findHelper(const SourceString('getRuntimeTypeInfo')); |
1248 } | 1418 } |
1249 | 1419 |
1250 Element getGetRuntimeTypeArgument() { | 1420 Element getGetRuntimeTypeArgument() { |
1251 return compiler.findHelper(const SourceString('getRuntimeTypeArgument')); | 1421 return compiler.findHelper(const SourceString('getRuntimeTypeArgument')); |
1252 } | 1422 } |
1253 | 1423 |
1424 Element getCheckArguments() { | |
1425 return compiler.findHelper(const SourceString('checkArguments')); | |
1426 } | |
1427 | |
1428 Element getThrowNoSuchMethod() { | |
1429 return compiler.findHelper(const SourceString('throwNoSuchMethod')); | |
1430 } | |
1431 | |
1432 Element getCreateRuntimeType() { | |
1433 return compiler.findHelper(const SourceString('createRuntimeType')); | |
1434 } | |
1435 | |
1436 Element getFallThroughError() { | |
1437 return compiler.findHelper(const SourceString("getFallThroughError")); | |
1438 } | |
1439 | |
1440 Element getCreateInvocationMirror() { | |
1441 return compiler.findHelper(Compiler.CREATE_INVOCATION_MIRROR); | |
1442 } | |
1443 | |
1444 Element getCyclicThrowHelper() { | |
1445 return compiler.findHelper(const SourceString("throwCyclicInit")); | |
1446 } | |
1447 | |
1254 /** | 1448 /** |
1255 * Remove [element] from the set of generated code, and put it back | 1449 * Remove [element] from the set of generated code, and put it back |
1256 * into the worklist. | 1450 * into the worklist. |
1257 * | 1451 * |
1258 * Invariant: [element] must be a declaration element. | 1452 * Invariant: [element] must be a declaration element. |
1259 */ | 1453 */ |
1260 void eagerRecompile(Element element) { | 1454 void eagerRecompile(Element element) { |
1261 assert(invariant(element, element.isDeclaration)); | 1455 assert(invariant(element, element.isDeclaration)); |
1262 generatedCode.remove(element); | 1456 generatedCode.remove(element); |
1263 generatedBailoutCode.remove(element); | 1457 generatedBailoutCode.remove(element); |
1264 compiler.enqueuer.codegen.addToWorkList(element); | 1458 compiler.enqueuer.codegen.addToWorkList(element); |
1265 } | 1459 } |
1266 } | 1460 } |
OLD | NEW |