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) { | |
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. |
938 var e = compiler.findHelper(helper); | 955 // TODO(ngeoffray): 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 // [registerIsCheck] is also called for checked mode checks, so we | |
1000 // need to register checked mode helpers. | |
1001 if (compiler.enableTypeAssertions) { | |
1002 SourceString helperName = getCheckedModeHelper(type); | |
1003 Element e = compiler.findHelper(helperName); | |
1004 if (e != null) world.addToWorkList(e); | |
1005 // We also need the native variant of the check (for DOM types). | |
1006 helperName = nativeNames[helperName.stringValue]; | |
1007 if (helperName != null) { | |
1008 e = compiler.findHelper(helperName); | |
1009 if (e != null) world.addToWorkList(e); | |
1010 } | |
1011 } | |
1012 } | |
1013 | |
1014 void registerAsCheck(DartType type) { | |
1015 SourceString checkedHelperName = getCheckedModeHelper(type); | |
1016 SourceString helperName = castNames[checkedHelperName.stringValue]; | |
1017 Element e = compiler.findHelper(helperName); | |
1018 enqueueInResolution(e); | |
1019 // We also need the native variant of the check (for DOM types). | |
1020 checkedHelperName = nativeNames[checkedHelperName.stringValue]; | |
1021 if (checkedHelperName != null) { | |
1022 helperName = castNames[checkedHelperName.stringValue]; | |
1023 Element e = compiler.findHelper(helperName); | |
1024 enqueueInResolution(e); | |
1025 } | |
1026 } | |
1027 | |
1028 void registerThrowNoSuchMethod() { | |
1029 enqueueInResolution(getThrowNoSuchMethod()); | |
1030 } | |
1031 | |
1032 void registerThrowRuntimeError() { | |
1033 enqueueInResolution(getThrowRuntimeError()); | |
1034 } | |
1035 | |
1036 void registerAbstractClassInstantiation() { | |
1037 enqueueInResolution(getThrowAbstractClassInstantiationError()); | |
1038 } | |
1039 | |
1040 void registerFallThroughError() { | |
1041 enqueueInResolution(getFallThroughError()); | |
1042 } | |
1043 | |
1044 void registerSuperNoSuchMethod() { | |
1045 enqueueInResolution(getCreateInvocationMirror()); | |
1046 } | |
1047 | |
1048 void enqueueInResolution(Element e) { | |
1049 if (e != null) compiler.enqueuer.resolution.addToWorkList(e); | |
1050 } | |
1051 | |
1052 void registerConstantMap() { | |
1053 Element e = compiler.findHelper(const SourceString('ConstantMap')); | |
1054 if (e != null) compiler.enqueuer.resolution.registerInstantiatedClass(e); | |
1055 e = compiler.findHelper(const SourceString('ConstantProtoMap')); | |
1056 if (e != null) compiler.enqueuer.resolution.registerInstantiatedClass(e); | |
1057 } | |
1058 | |
943 void codegen(CodegenWorkItem work) { | 1059 void codegen(CodegenWorkItem work) { |
944 Element element = work.element; | 1060 Element element = work.element; |
945 if (element.kind.category == ElementCategory.VARIABLE) { | 1061 if (element.kind.category == ElementCategory.VARIABLE) { |
946 Constant initialValue = compiler.constantHandler.compileWorkItem(work); | 1062 Constant initialValue = compiler.constantHandler.compileWorkItem(work); |
947 if (initialValue != null) { | 1063 if (initialValue != null) { |
948 return; | 1064 return; |
949 } else { | 1065 } else { |
950 // If the constant-handler was not able to produce a result we have to | 1066 // 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 | 1067 // go through the builder (below) to generate the lazy initializer for |
952 // the static variable. | 1068 // the static variable. |
953 // We also need to register the use of the cyclic-error helper. | 1069 // We also need to register the use of the cyclic-error helper. |
954 compiler.enqueuer.codegen.registerStaticUse(cyclicThrowHelper); | 1070 compiler.enqueuer.codegen.registerStaticUse(getCyclicThrowHelper()); |
955 } | 1071 } |
956 } | 1072 } |
957 | 1073 |
958 HGraph graph = builder.build(work); | 1074 HGraph graph = builder.build(work); |
959 optimizer.optimize(work, graph, false); | 1075 optimizer.optimize(work, graph, false); |
960 if (work.allowSpeculativeOptimization | 1076 if (work.allowSpeculativeOptimization |
961 && optimizer.trySpeculativeOptimizations(work, graph)) { | 1077 && optimizer.trySpeculativeOptimizations(work, graph)) { |
962 jsAst.Expression code = generator.generateBailoutMethod(work, graph); | 1078 jsAst.Expression code = generator.generateBailoutMethod(work, graph); |
963 generatedBailoutCode[element] = code; | 1079 generatedBailoutCode[element] = code; |
964 optimizer.prepareForSpeculativeOptimizations(work, graph); | 1080 optimizer.prepareForSpeculativeOptimizations(work, graph); |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1187 ? const SourceString('listSuperNativeTypeCheck') | 1303 ? const SourceString('listSuperNativeTypeCheck') |
1188 : const SourceString('listSuperTypeCheck'); | 1304 : const SourceString('listSuperTypeCheck'); |
1189 } else { | 1305 } else { |
1190 return nativeCheck | 1306 return nativeCheck |
1191 ? const SourceString('callTypeCheck') | 1307 ? const SourceString('callTypeCheck') |
1192 : const SourceString('propertyTypeCheck'); | 1308 : const SourceString('propertyTypeCheck'); |
1193 } | 1309 } |
1194 } | 1310 } |
1195 } | 1311 } |
1196 | 1312 |
1313 Map<String, SourceString> nativeNames = const <String, SourceString> { | |
ahe
2013/02/18 12:38:04
Document this.
| |
1314 'stringSuperTypeCheck': | |
1315 const SourceString('stringSuperNativeTypeCheck'), | |
1316 'numberOrStringSuperTypeCheck': | |
1317 const SourceString('numberOrStringSuperNativeTypeCheck'), | |
1318 'listSuperTypeCheck': | |
1319 const SourceString('listSuperNativeTypeCheck'), | |
1320 'propertyTypeCheck': | |
1321 const SourceString('callTypeCheck') | |
1322 }; | |
1323 | |
1324 Map<String, SourceString> castNames = const <String, SourceString> { | |
ahe
2013/02/18 12:38:04
Ditto.
| |
1325 "stringTypeCheck": | |
1326 const SourceString("stringTypeCast"), | |
1327 "doubleTypeCheck": | |
1328 const SourceString("doubleTypeCast"), | |
1329 "numTypeCheck": | |
1330 const SourceString("numTypeCast"), | |
1331 "boolTypeCheck": | |
1332 const SourceString("boolTypeCast"), | |
1333 "functionTypeCheck": | |
1334 const SourceString("functionTypeCast"), | |
1335 "intTypeCheck": | |
1336 const SourceString("intTypeCast"), | |
1337 "numberOrStringSuperNativeTypeCheck": | |
1338 const SourceString("numberOrStringSuperNativeTypeCast"), | |
1339 "numberOrStringSuperTypeCheck": | |
1340 const SourceString("numberOrStringSuperTypeCast"), | |
1341 "stringSuperNativeTypeCheck": | |
1342 const SourceString("stringSuperNativeTypeCast"), | |
1343 "stringSuperTypeCheck": | |
1344 const SourceString("stringSuperTypeCast"), | |
1345 "listTypeCheck": | |
1346 const SourceString("listTypeCast"), | |
1347 "listSuperNativeTypeCheck": | |
1348 const SourceString("listSuperNativeTypeCast"), | |
1349 "listSuperTypeCheck": | |
1350 const SourceString("listSuperTypeCast"), | |
1351 "callTypeCheck": | |
1352 const SourceString("callTypeCast"), | |
1353 "propertyTypeCheck": | |
1354 const SourceString("propertyTypeCast"), | |
1355 // TODO(johnniwinther): Add a malformedTypeCast which produces a TypeError | |
1356 // with another message. | |
1357 "malformedTypeCheck": | |
1358 const SourceString("malformedTypeCheck") | |
1359 }; | |
1360 | |
1197 void dumpInferredTypes() { | 1361 void dumpInferredTypes() { |
1198 print("Inferred argument types:"); | 1362 print("Inferred argument types:"); |
1199 print("------------------------"); | 1363 print("------------------------"); |
1200 argumentTypes.dump(); | 1364 argumentTypes.dump(); |
1201 print(""); | 1365 print(""); |
1202 print("Inferred return types:"); | 1366 print("Inferred return types:"); |
1203 print("----------------------"); | 1367 print("----------------------"); |
1204 dumpReturnTypes(); | 1368 dumpReturnTypes(); |
1205 print(""); | 1369 print(""); |
1206 print("Inferred field types:"); | 1370 print("Inferred field types:"); |
(...skipping 13 matching lines...) Expand all Loading... | |
1220 Element getThrowMalformedSubtypeError() { | 1384 Element getThrowMalformedSubtypeError() { |
1221 return compiler.findHelper( | 1385 return compiler.findHelper( |
1222 const SourceString('throwMalformedSubtypeError')); | 1386 const SourceString('throwMalformedSubtypeError')); |
1223 } | 1387 } |
1224 | 1388 |
1225 Element getThrowAbstractClassInstantiationError() { | 1389 Element getThrowAbstractClassInstantiationError() { |
1226 return compiler.findHelper( | 1390 return compiler.findHelper( |
1227 const SourceString('throwAbstractClassInstantiationError')); | 1391 const SourceString('throwAbstractClassInstantiationError')); |
1228 } | 1392 } |
1229 | 1393 |
1394 Element getStringInterpolationHelper() { | |
1395 return compiler.findHelper(const SourceString('S')); | |
1396 } | |
1397 | |
1398 Element getThrowHelper() { | |
1399 return compiler.findHelper(const SourceString(r'$throw')); | |
1400 } | |
1401 | |
1230 Element getClosureConverter() { | 1402 Element getClosureConverter() { |
1231 return compiler.findHelper(const SourceString('convertDartClosureToJS')); | 1403 return compiler.findHelper(const SourceString('convertDartClosureToJS')); |
1232 } | 1404 } |
1233 | 1405 |
1234 Element getTraceFromException() { | 1406 Element getTraceFromException() { |
1235 return compiler.findHelper(const SourceString('getTraceFromException')); | 1407 return compiler.findHelper(const SourceString('getTraceFromException')); |
1236 } | 1408 } |
1237 | 1409 |
1238 Element getMapMaker() { | 1410 Element getMapMaker() { |
1239 return compiler.findHelper(const SourceString('makeLiteralMap')); | 1411 return compiler.findHelper(const SourceString('makeLiteralMap')); |
1240 } | 1412 } |
1241 | 1413 |
1242 Element getSetRuntimeTypeInfo() { | 1414 Element getSetRuntimeTypeInfo() { |
1243 return compiler.findHelper(const SourceString('setRuntimeTypeInfo')); | 1415 return compiler.findHelper(const SourceString('setRuntimeTypeInfo')); |
1244 } | 1416 } |
1245 | 1417 |
1246 Element getGetRuntimeTypeInfo() { | 1418 Element getGetRuntimeTypeInfo() { |
1247 return compiler.findHelper(const SourceString('getRuntimeTypeInfo')); | 1419 return compiler.findHelper(const SourceString('getRuntimeTypeInfo')); |
1248 } | 1420 } |
1249 | 1421 |
1250 Element getGetRuntimeTypeArgument() { | 1422 Element getGetRuntimeTypeArgument() { |
1251 return compiler.findHelper(const SourceString('getRuntimeTypeArgument')); | 1423 return compiler.findHelper(const SourceString('getRuntimeTypeArgument')); |
1252 } | 1424 } |
1253 | 1425 |
1426 Element getCheckArguments() { | |
1427 return compiler.findHelper(const SourceString('checkArguments')); | |
1428 } | |
1429 | |
1430 Element getThrowNoSuchMethod() { | |
1431 return compiler.findHelper(const SourceString('throwNoSuchMethod')); | |
1432 } | |
1433 | |
1434 Element getCreateRuntimeType() { | |
1435 return compiler.findHelper(const SourceString('createRuntimeType')); | |
1436 } | |
1437 | |
1438 Element getFallThroughError() { | |
1439 return compiler.findHelper(const SourceString("getFallThroughError")); | |
1440 } | |
1441 | |
1442 Element getCreateInvocationMirror() { | |
1443 return compiler.findHelper(Compiler.CREATE_INVOCATION_MIRROR); | |
1444 } | |
1445 | |
1446 Element getCyclicThrowHelper() { | |
1447 return compiler.findHelper(const SourceString("throwCyclicInit")); | |
1448 } | |
1449 | |
1254 /** | 1450 /** |
1255 * Remove [element] from the set of generated code, and put it back | 1451 * Remove [element] from the set of generated code, and put it back |
1256 * into the worklist. | 1452 * into the worklist. |
1257 * | 1453 * |
1258 * Invariant: [element] must be a declaration element. | 1454 * Invariant: [element] must be a declaration element. |
1259 */ | 1455 */ |
1260 void eagerRecompile(Element element) { | 1456 void eagerRecompile(Element element) { |
1261 assert(invariant(element, element.isDeclaration)); | 1457 assert(invariant(element, element.isDeclaration)); |
1262 generatedCode.remove(element); | 1458 generatedCode.remove(element); |
1263 generatedBailoutCode.remove(element); | 1459 generatedBailoutCode.remove(element); |
1264 compiler.enqueuer.codegen.addToWorkList(element); | 1460 compiler.enqueuer.codegen.addToWorkList(element); |
1265 } | 1461 } |
1266 } | 1462 } |
OLD | NEW |