| 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 /** | 7 /** |
| 8 * A function element that represents a closure call. The signature is copied | 8 * A function element that represents a closure call. The signature is copied |
| 9 * from the given element. | 9 * from the given element. |
| 10 */ | 10 */ |
| (...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 769 visitMember, | 769 visitMember, |
| 770 includeBackendMembers: true, | 770 includeBackendMembers: true, |
| 771 includeSuperMembers: false); | 771 includeSuperMembers: false); |
| 772 }); | 772 }); |
| 773 | 773 |
| 774 classElement.implementation.forEachMember( | 774 classElement.implementation.forEachMember( |
| 775 visitMember, | 775 visitMember, |
| 776 includeBackendMembers: true, | 776 includeBackendMembers: true, |
| 777 includeSuperMembers: false); | 777 includeSuperMembers: false); |
| 778 | 778 |
| 779 generateIsTestsOn(classElement, (Element other) { | 779 void generateIsTest(Element other) { |
| 780 js.Expression code; | 780 js.Expression code; |
| 781 if (compiler.objectClass == other) return; | 781 if (compiler.objectClass == other) return; |
| 782 if (nativeEmitter.requiresNativeIsCheck(other)) { | 782 if (nativeEmitter.requiresNativeIsCheck(other)) { |
| 783 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); | 783 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); |
| 784 } else { | 784 } else { |
| 785 code = new js.LiteralBool(true); | 785 code = new js.LiteralBool(true); |
| 786 } | 786 } |
| 787 builder.addProperty(namer.operatorIs(other), code); | 787 builder.addProperty(namer.operatorIs(other), code); |
| 788 }); | 788 } |
| 789 |
| 790 void generateSubstitution(Element other, {bool emitNull: false}) { |
| 791 RuntimeTypeInformation rti = backend.rti; |
| 792 // TODO(karlklose): support typedefs with variables. |
| 793 js.Expression expression; |
| 794 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); |
| 795 if (other.kind == ElementKind.CLASS) { |
| 796 String substitution = rti.getSupertypeSubstitution(classElement, other, |
| 797 alwaysGenerateFunction: true); |
| 798 if (substitution != null) { |
| 799 expression = new js.LiteralExpression(substitution); |
| 800 } else if (emitNull || needsNativeCheck) { |
| 801 expression = new js.LiteralNull(); |
| 802 } |
| 803 } |
| 804 if (expression != null) { |
| 805 if (needsNativeCheck) { |
| 806 expression = |
| 807 new js.Fun([], new js.Block([new js.Return(expression)])); |
| 808 } |
| 809 builder.addProperty(namer.substitutionName(other), expression); |
| 810 } |
| 811 } |
| 812 |
| 813 generateIsTestsOn(classElement, generateIsTest, generateSubstitution); |
| 789 | 814 |
| 790 if (identical(classElement, compiler.objectClass) | 815 if (identical(classElement, compiler.objectClass) |
| 791 && compiler.enabledNoSuchMethod) { | 816 && compiler.enabledNoSuchMethod) { |
| 792 // Emit the noSuchMethod handlers on the Object prototype now, | 817 // Emit the noSuchMethod handlers on the Object prototype now, |
| 793 // so that the code in the dynamicFunction helper can find | 818 // so that the code in the dynamicFunction helper can find |
| 794 // them. Note that this helper is invoked before analyzing the | 819 // them. Note that this helper is invoked before analyzing the |
| 795 // full JS script. | 820 // full JS script. |
| 796 if (!nativeEmitter.handleNoSuchMethod) { | 821 if (!nativeEmitter.handleNoSuchMethod) { |
| 797 emitNoSuchMethodHandlers(builder.addProperty); | 822 emitNoSuchMethodHandlers(builder.addProperty); |
| 798 } | 823 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 811 ? js.equals | 836 ? js.equals |
| 812 : js.strictEquals; | 837 : js.strictEquals; |
| 813 builder.addProperty(name, js.fun(['receiver', 'a'], | 838 builder.addProperty(name, js.fun(['receiver', 'a'], |
| 814 js.block1(js.return_(kind(js.use('receiver'), js.use('a')))))); | 839 js.block1(js.return_(kind(js.use('receiver'), js.use('a')))))); |
| 815 } | 840 } |
| 816 } | 841 } |
| 817 | 842 |
| 818 void emitRuntimeClassesAndTests(CodeBuffer buffer) { | 843 void emitRuntimeClassesAndTests(CodeBuffer buffer) { |
| 819 JavaScriptBackend backend = compiler.backend; | 844 JavaScriptBackend backend = compiler.backend; |
| 820 RuntimeTypeInformation rti = backend.rti; | 845 RuntimeTypeInformation rti = backend.rti; |
| 821 | 846 TypeChecks typeChecks = rti.getRequiredChecks(); |
| 822 TypeChecks typeChecks = rti.computeRequiredChecks(); | |
| 823 | 847 |
| 824 bool needsHolder(ClassElement cls) { | 848 bool needsHolder(ClassElement cls) { |
| 825 return !neededClasses.contains(cls) || cls.isNative() || | 849 return !neededClasses.contains(cls) || cls.isNative() || |
| 826 rti.isJsNative(cls); | 850 rti.isJsNative(cls); |
| 827 } | 851 } |
| 828 | 852 |
| 853 /** |
| 854 * Generates a holder object if it is needed. A holder is a JavaScript |
| 855 * object literal with a field [builtin$cls] that contains the name of the |
| 856 * class as a string (just like object constructors do). The is-checks for |
| 857 * the class are are added to the holder object later. |
| 858 */ |
| 829 void maybeGenerateHolder(ClassElement cls) { | 859 void maybeGenerateHolder(ClassElement cls) { |
| 830 if (!needsHolder(cls)) return; | 860 if (!needsHolder(cls)) return; |
| 831 | |
| 832 String holder = namer.isolateAccess(cls); | 861 String holder = namer.isolateAccess(cls); |
| 833 String name = namer.getName(cls); | 862 String name = namer.getName(cls); |
| 834 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); | 863 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); |
| 835 for (ClassElement check in typeChecks[cls]) { | |
| 836 buffer.add(',$_${namer.operatorIs(check)}:${_}true'); | |
| 837 }; | |
| 838 buffer.add('}$N'); | 864 buffer.add('}$N'); |
| 839 } | 865 } |
| 840 | 866 |
| 841 // Create representation objects for classes that we do not have a class | 867 // Create representation objects for classes that we do not have a class |
| 842 // definition for (because they are uninstantiated or native). | 868 // definition for (because they are uninstantiated or native). |
| 843 for (ClassElement cls in rti.allArguments) { | 869 for (ClassElement cls in rti.allArguments) { |
| 844 maybeGenerateHolder(cls); | 870 maybeGenerateHolder(cls); |
| 845 } | 871 } |
| 846 | 872 |
| 847 // Add checks to the constructors of instantiated classes. | 873 // Add checks to the constructors of instantiated classes or to the created |
| 874 // holder object. |
| 848 for (ClassElement cls in typeChecks) { | 875 for (ClassElement cls in typeChecks) { |
| 849 if (needsHolder(cls)) { | |
| 850 // We already emitted the is-checks in the object definition for this | |
| 851 // class. | |
| 852 continue; | |
| 853 } | |
| 854 String holder = namer.isolateAccess(cls); | 876 String holder = namer.isolateAccess(cls); |
| 855 for (ClassElement check in typeChecks[cls]) { | 877 for (ClassElement check in typeChecks[cls]) { |
| 856 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); | 878 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); |
| 879 String body = rti.getSupertypeSubstitution(cls, check); |
| 880 if (body != null) { |
| 881 buffer.add('$holder.${namer.substitutionName(check)}$_=${_}$body$N'); |
| 882 } |
| 857 }; | 883 }; |
| 858 } | 884 } |
| 859 } | 885 } |
| 860 | 886 |
| 861 void visitNativeMixins(ClassElement classElement, | 887 void visitNativeMixins(ClassElement classElement, |
| 862 void visit(MixinApplicationElement mixinApplication)) { | 888 void visit(MixinApplicationElement mixinApplication)) { |
| 863 if (!classElement.isNative()) return; | 889 if (!classElement.isNative()) return; |
| 864 // Use recursion to make sure to visit the superclasses before the | 890 // Use recursion to make sure to visit the superclasses before the |
| 865 // subclasses. Once we start keeping track of the emitted fields | 891 // subclasses. Once we start keeping track of the emitted fields |
| 866 // and members, we're going to want to visit these in the other | 892 // and members, we're going to want to visit these in the other |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1213 FunctionType typedefType = | 1239 FunctionType typedefType = |
| 1214 typedef.computeType(compiler).unalias(compiler); | 1240 typedef.computeType(compiler).unalias(compiler); |
| 1215 return compiler.types.isSubtype(type, typedefType); | 1241 return compiler.types.isSubtype(type, typedefType); |
| 1216 } | 1242 } |
| 1217 return checkedTypedefs.where(isSubtype).toList() | 1243 return checkedTypedefs.where(isSubtype).toList() |
| 1218 ..sort(Elements.compareByPosition); | 1244 ..sort(Elements.compareByPosition); |
| 1219 } | 1245 } |
| 1220 | 1246 |
| 1221 /** | 1247 /** |
| 1222 * Generate "is tests" for [cls]: itself, and the "is tests" for the | 1248 * Generate "is tests" for [cls]: itself, and the "is tests" for the |
| 1223 * classes it implements. We don't need to add the "is tests" of the | 1249 * classes it implements and type argument substitution functions for these |
| 1224 * super class because they will be inherited at runtime. | 1250 * tests. We don't need to add the "is tests" of the super class because |
| 1251 * they will be inherited at runtime, but we may need to generate the |
| 1252 * substitutions, because they may have changed. |
| 1225 */ | 1253 */ |
| 1226 void generateIsTestsOn(ClassElement cls, | 1254 void generateIsTestsOn(ClassElement cls, |
| 1227 void emitIsTest(Element element)) { | 1255 void emitIsTest(Element element), |
| 1256 void emitSubstitution(Element element, {emitNull})) { |
| 1228 if (checkedClasses.contains(cls)) { | 1257 if (checkedClasses.contains(cls)) { |
| 1229 emitIsTest(cls); | 1258 emitIsTest(cls); |
| 1259 emitSubstitution(cls); |
| 1260 } |
| 1261 |
| 1262 JavaScriptBackend jsBackend = compiler.backend; |
| 1263 RuntimeTypeInformation rti = jsBackend.rti; |
| 1264 ClassElement superclass = cls.superclass; |
| 1265 |
| 1266 bool haveSameTypeVariables(ClassElement a, ClassElement b) { |
| 1267 if (a.isClosure()) return true; |
| 1268 return a.typeVariables == b.typeVariables; |
| 1269 } |
| 1270 |
| 1271 if (superclass != null && superclass != compiler.objectClass && |
| 1272 !haveSameTypeVariables(cls, superclass)) { |
| 1273 // We cannot inherit the generated substitutions, because the type |
| 1274 // variable layout for this class is different. Instead we generate |
| 1275 // substitutions for all checks and make emitSubstitution a NOP for the |
| 1276 // rest of this function. |
| 1277 for (ClassElement check in checkedClasses) { |
| 1278 for (DartType supertype in cls.allSupertypes) { |
| 1279 if (supertype.element == check) { |
| 1280 // Generate substitution. If no substitution is necessary, emit |
| 1281 // [:null:] to overwrite a (possibly) existing substitution from the |
| 1282 // super classes. |
| 1283 emitSubstitution(check, emitNull: true); |
| 1284 } |
| 1285 } |
| 1286 } |
| 1287 void emitNothing(_, {emitNull}) {}; |
| 1288 emitSubstitution = emitNothing; |
| 1230 } | 1289 } |
| 1231 | 1290 |
| 1232 Set<Element> generated = new Set<Element>(); | 1291 Set<Element> generated = new Set<Element>(); |
| 1233 // A class that defines a [:call:] method implicitly implements | 1292 // A class that defines a [:call:] method implicitly implements |
| 1234 // [Function] and needs checks for all typedefs that are used in is-checks. | 1293 // [Function] and needs checks for all typedefs that are used in is-checks. |
| 1235 if (checkedClasses.contains(compiler.functionClass) || | 1294 if (checkedClasses.contains(compiler.functionClass) || |
| 1236 !checkedTypedefs.isEmpty) { | 1295 !checkedTypedefs.isEmpty) { |
| 1237 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); | 1296 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); |
| 1238 if (call == null) { | 1297 if (call == null) { |
| 1239 // If [cls] is a closure, it has a synthetic call operator method. | 1298 // If [cls] is a closure, it has a synthetic call operator method. |
| 1240 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); | 1299 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); |
| 1241 } | 1300 } |
| 1242 if (call != null) { | 1301 if (call != null) { |
| 1243 generateInterfacesIsTests(compiler.functionClass, | 1302 generateInterfacesIsTests(compiler.functionClass, |
| 1244 emitIsTest, | 1303 emitIsTest, |
| 1304 emitSubstitution, |
| 1245 generated); | 1305 generated); |
| 1246 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); | 1306 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); |
| 1247 } | 1307 } |
| 1248 } | 1308 } |
| 1249 | 1309 |
| 1250 for (DartType interfaceType in cls.interfaces) { | 1310 for (DartType interfaceType in cls.interfaces) { |
| 1251 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); | 1311 generateInterfacesIsTests(interfaceType.element, emitIsTest, |
| 1312 emitSubstitution, generated); |
| 1252 } | 1313 } |
| 1253 | 1314 |
| 1254 // For native classes, we also have to run through their mixin | 1315 // For native classes, we also have to run through their mixin |
| 1255 // applications and make sure we deal with 'is' tests correctly | 1316 // applications and make sure we deal with 'is' tests correctly |
| 1256 // for those. | 1317 // for those. |
| 1257 visitNativeMixins(cls, (MixinApplicationElement mixin) { | 1318 visitNativeMixins(cls, (MixinApplicationElement mixin) { |
| 1258 for (DartType interfaceType in mixin.interfaces) { | 1319 for (DartType interfaceType in mixin.interfaces) { |
| 1259 ClassElement interfaceElement = interfaceType.element; | 1320 ClassElement interfaceElement = interfaceType.element; |
| 1260 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); | 1321 generateInterfacesIsTests(interfaceType.element, emitIsTest, |
| 1322 emitSubstitution, generated); |
| 1261 } | 1323 } |
| 1262 }); | 1324 }); |
| 1263 } | 1325 } |
| 1264 | 1326 |
| 1265 /** | 1327 /** |
| 1266 * Generate "is tests" where [cls] is being implemented. | 1328 * Generate "is tests" where [cls] is being implemented. |
| 1267 */ | 1329 */ |
| 1268 void generateInterfacesIsTests(ClassElement cls, | 1330 void generateInterfacesIsTests(ClassElement cls, |
| 1269 void emitIsTest(ClassElement element), | 1331 void emitIsTest(ClassElement element), |
| 1332 void emitSubstitution(ClassElement element), |
| 1270 Set<Element> alreadyGenerated) { | 1333 Set<Element> alreadyGenerated) { |
| 1271 void tryEmitTest(ClassElement cls) { | 1334 void tryEmitTest(ClassElement check) { |
| 1272 if (!alreadyGenerated.contains(cls) && checkedClasses.contains(cls)) { | 1335 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) { |
| 1273 alreadyGenerated.add(cls); | 1336 alreadyGenerated.add(check); |
| 1274 emitIsTest(cls); | 1337 emitIsTest(check); |
| 1338 emitSubstitution(check); |
| 1275 } | 1339 } |
| 1276 }; | 1340 }; |
| 1277 | 1341 |
| 1278 tryEmitTest(cls); | 1342 tryEmitTest(cls); |
| 1279 | 1343 |
| 1280 for (DartType interfaceType in cls.interfaces) { | 1344 for (DartType interfaceType in cls.interfaces) { |
| 1281 Element element = interfaceType.element; | 1345 Element element = interfaceType.element; |
| 1282 tryEmitTest(element); | 1346 tryEmitTest(element); |
| 1283 generateInterfacesIsTests(element, emitIsTest, alreadyGenerated); | 1347 generateInterfacesIsTests(element, emitIsTest, emitSubstitution, |
| 1348 alreadyGenerated); |
| 1284 } | 1349 } |
| 1285 | 1350 |
| 1286 // We need to also emit "is checks" for the superclass and its supertypes. | 1351 // We need to also emit "is checks" for the superclass and its supertypes. |
| 1287 ClassElement superclass = cls.superclass; | 1352 ClassElement superclass = cls.superclass; |
| 1288 if (superclass != null) { | 1353 if (superclass != null) { |
| 1289 tryEmitTest(superclass); | 1354 tryEmitTest(superclass); |
| 1290 generateInterfacesIsTests(superclass, emitIsTest, alreadyGenerated); | 1355 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, |
| 1356 alreadyGenerated); |
| 1291 } | 1357 } |
| 1292 } | 1358 } |
| 1293 | 1359 |
| 1294 /** | 1360 /** |
| 1295 * Return a function that returns true if its argument is a class | 1361 * Return a function that returns true if its argument is a class |
| 1296 * that needs to be emitted. | 1362 * that needs to be emitted. |
| 1297 */ | 1363 */ |
| 1298 Function computeClassFilter() { | 1364 Function computeClassFilter() { |
| 1299 Set<ClassElement> unneededClasses = new Set<ClassElement>(); | 1365 Set<ClassElement> unneededClasses = new Set<ClassElement>(); |
| 1300 // The [Bool] class is not marked as abstract, but has a factory | 1366 // The [Bool] class is not marked as abstract, but has a factory |
| (...skipping 1049 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2350 """; | 2416 """; |
| 2351 const String HOOKS_API_USAGE = """ | 2417 const String HOOKS_API_USAGE = """ |
| 2352 // The code supports the following hooks: | 2418 // The code supports the following hooks: |
| 2353 // dartPrint(message) - if this function is defined it is called | 2419 // dartPrint(message) - if this function is defined it is called |
| 2354 // instead of the Dart [print] method. | 2420 // instead of the Dart [print] method. |
| 2355 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2421 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 2356 // method will not be invoked directly. | 2422 // method will not be invoked directly. |
| 2357 // Instead, a closure that will invoke [main] is | 2423 // Instead, a closure that will invoke [main] is |
| 2358 // passed to [dartMainRunner]. | 2424 // passed to [dartMainRunner]. |
| 2359 """; | 2425 """; |
| OLD | NEW |