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 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 745 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 visitMember, | 756 visitMember, |
| 757 includeBackendMembers: true, | 757 includeBackendMembers: true, |
| 758 includeSuperMembers: false); | 758 includeSuperMembers: false); |
| 759 }); | 759 }); |
| 760 | 760 |
| 761 classElement.implementation.forEachMember( | 761 classElement.implementation.forEachMember( |
| 762 visitMember, | 762 visitMember, |
| 763 includeBackendMembers: true, | 763 includeBackendMembers: true, |
| 764 includeSuperMembers: false); | 764 includeSuperMembers: false); |
| 765 | 765 |
| 766 generateIsTestsOn(classElement, (Element other) { | 766 void generateIsTest(Element other) { |
| 767 js.Expression code; | 767 js.Expression code; |
| 768 if (compiler.objectClass == other) return; | 768 if (compiler.objectClass == other) return; |
| 769 if (nativeEmitter.requiresNativeIsCheck(other)) { | 769 if (nativeEmitter.requiresNativeIsCheck(other)) { |
| 770 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); | 770 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); |
| 771 } else { | 771 } else { |
| 772 code = new js.LiteralBool(true); | 772 code = new js.LiteralBool(true); |
| 773 } | 773 } |
| 774 builder.addProperty(namer.operatorIs(other), code); | 774 builder.addProperty(namer.operatorIs(other), code); |
| 775 }); | 775 } |
| 776 | |
| 777 void generateSubstitution(Element other) { | |
| 778 RuntimeTypeInformation rti = backend.rti; | |
| 779 // TODO(karlklose): support typedefs with variables. | |
| 780 if (other.kind == ElementKind.CLASS) { | |
| 781 String substitution = rti.getSupertypeSubstitution(classElement, other, | |
| 782 alwaysGenerateFunction: true); | |
| 783 if (substitution != null) { | |
| 784 builder.addProperty(namer.substitutionName(other), | |
| 785 new js.LiteralExpression(substitution)); | |
| 786 } | |
| 787 } | |
| 788 } | |
| 789 | |
| 790 generateIsTestsOn(classElement, generateIsTest, generateSubstitution); | |
| 776 | 791 |
| 777 if (identical(classElement, compiler.objectClass) | 792 if (identical(classElement, compiler.objectClass) |
| 778 && compiler.enabledNoSuchMethod) { | 793 && compiler.enabledNoSuchMethod) { |
| 779 // Emit the noSuchMethod handlers on the Object prototype now, | 794 // Emit the noSuchMethod handlers on the Object prototype now, |
| 780 // so that the code in the dynamicFunction helper can find | 795 // so that the code in the dynamicFunction helper can find |
| 781 // them. Note that this helper is invoked before analyzing the | 796 // them. Note that this helper is invoked before analyzing the |
| 782 // full JS script. | 797 // full JS script. |
| 783 if (!nativeEmitter.handleNoSuchMethod) { | 798 if (!nativeEmitter.handleNoSuchMethod) { |
| 784 emitNoSuchMethodHandlers(builder.addProperty); | 799 emitNoSuchMethodHandlers(builder.addProperty); |
| 785 } | 800 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 798 ? js.equals | 813 ? js.equals |
| 799 : js.strictEquals; | 814 : js.strictEquals; |
| 800 builder.addProperty(name, js.fun(['receiver', 'a'], | 815 builder.addProperty(name, js.fun(['receiver', 'a'], |
| 801 js.block1(js.return_(kind(js.use('receiver'), js.use('a')))))); | 816 js.block1(js.return_(kind(js.use('receiver'), js.use('a')))))); |
| 802 } | 817 } |
| 803 } | 818 } |
| 804 | 819 |
| 805 void emitRuntimeClassesAndTests(CodeBuffer buffer) { | 820 void emitRuntimeClassesAndTests(CodeBuffer buffer) { |
| 806 JavaScriptBackend backend = compiler.backend; | 821 JavaScriptBackend backend = compiler.backend; |
| 807 RuntimeTypeInformation rti = backend.rti; | 822 RuntimeTypeInformation rti = backend.rti; |
| 808 | 823 TypeChecks typeChecks = rti.getRequiredChecks(); |
| 809 TypeChecks typeChecks = rti.computeRequiredChecks(); | |
| 810 | 824 |
| 811 bool needsHolder(ClassElement cls) { | 825 bool needsHolder(ClassElement cls) { |
| 812 return !neededClasses.contains(cls) || cls.isNative() || | 826 return !neededClasses.contains(cls) || cls.isNative() || |
| 813 rti.isJsNative(cls); | 827 rti.isJsNative(cls); |
| 814 } | 828 } |
| 815 | 829 |
| 830 /** | |
| 831 * Generates a holder object if it is needed. A holder is a JavaScript | |
| 832 * object literal with a field [builtin$cls] that contains the name of the | |
| 833 * class as a string (just like object constructors do). The is-checkes | |
|
ngeoffray
2013/01/31 08:28:08
checkes -> checks
karlklose
2013/02/01 07:36:36
Done.
| |
| 834 * for the class are are added to the holder object later. | |
| 835 */ | |
| 816 void maybeGenerateHolder(ClassElement cls) { | 836 void maybeGenerateHolder(ClassElement cls) { |
| 817 if (!needsHolder(cls)) return; | 837 if (!needsHolder(cls)) return; |
| 818 | |
| 819 String holder = namer.isolateAccess(cls); | 838 String holder = namer.isolateAccess(cls); |
| 820 String name = namer.getName(cls); | 839 String name = namer.getName(cls); |
| 821 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); | 840 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); |
| 822 for (ClassElement check in typeChecks[cls]) { | |
| 823 buffer.add(',$_${namer.operatorIs(check)}:${_}true'); | |
| 824 }; | |
| 825 buffer.add('}$N'); | 841 buffer.add('}$N'); |
| 826 } | 842 } |
| 827 | 843 |
| 828 // Create representation objects for classes that we do not have a class | 844 // Create representation objects for classes that we do not have a class |
| 829 // definition for (because they are uninstantiated or native). | 845 // definition for (because they are uninstantiated or native). |
| 830 for (ClassElement cls in rti.allArguments) { | 846 for (ClassElement cls in rti.allArguments) { |
| 831 maybeGenerateHolder(cls); | 847 maybeGenerateHolder(cls); |
| 832 } | 848 } |
| 833 | 849 |
| 834 // Add checks to the constructors of instantiated classes. | 850 // Add checks to the constructors of instantiated classes or to the created |
| 851 // holder object. | |
| 835 for (ClassElement cls in typeChecks) { | 852 for (ClassElement cls in typeChecks) { |
| 836 if (needsHolder(cls)) { | |
| 837 // We already emitted the is-checks in the object definition for this | |
| 838 // class. | |
| 839 continue; | |
| 840 } | |
| 841 String holder = namer.isolateAccess(cls); | 853 String holder = namer.isolateAccess(cls); |
| 842 for (ClassElement check in typeChecks[cls]) { | 854 for (ClassElement check in typeChecks[cls]) { |
| 843 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); | 855 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); |
| 856 String body = rti.getSupertypeSubstitution(cls, check); | |
| 857 if (body != null) { | |
| 858 buffer.add('$holder.${namer.substitutionName(check)}$_=${_}$body$N'); | |
| 859 } | |
| 844 }; | 860 }; |
| 845 } | 861 } |
| 846 } | 862 } |
| 847 | 863 |
| 848 void visitNativeMixins(ClassElement classElement, | 864 void visitNativeMixins(ClassElement classElement, |
| 849 void visit(MixinApplicationElement mixinApplication)) { | 865 void visit(MixinApplicationElement mixinApplication)) { |
| 850 if (!classElement.isNative()) return; | 866 if (!classElement.isNative()) return; |
| 851 // Use recursion to make sure to visit the superclasses before the | 867 // Use recursion to make sure to visit the superclasses before the |
| 852 // subclasses. Once we start keeping track of the emitted fields | 868 // subclasses. Once we start keeping track of the emitted fields |
| 853 // and members, we're going to want to visit these in the other | 869 // and members, we're going to want to visit these in the other |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1184 Iterable<Element> getTypedefChecksOn(DartType type) { | 1200 Iterable<Element> getTypedefChecksOn(DartType type) { |
| 1185 return checkedTypedefs.where((TypedefElement typedef) { | 1201 return checkedTypedefs.where((TypedefElement typedef) { |
| 1186 FunctionType typedefType = | 1202 FunctionType typedefType = |
| 1187 typedef.computeType(compiler).unalias(compiler); | 1203 typedef.computeType(compiler).unalias(compiler); |
| 1188 return compiler.types.isSubtype(type, typedefType); | 1204 return compiler.types.isSubtype(type, typedefType); |
| 1189 }); | 1205 }); |
| 1190 } | 1206 } |
| 1191 | 1207 |
| 1192 /** | 1208 /** |
| 1193 * Generate "is tests" for [cls]: itself, and the "is tests" for the | 1209 * Generate "is tests" for [cls]: itself, and the "is tests" for the |
| 1194 * classes it implements. We don't need to add the "is tests" of the | 1210 * classes it implements and type argument substitution functions for these |
| 1195 * super class because they will be inherited at runtime. | 1211 * tests. We don't need to add the "is tests" of the super class because |
| 1212 * they will be inherited at runtime, but we need to generate the substitution , | |
|
ngeoffray
2013/01/31 08:28:08
line too long
karlklose
2013/02/01 07:36:36
Done.
| |
| 1213 * because it may have changed. | |
|
ngeoffray
2013/01/31 08:28:08
Please provide an example.
karlklose
2013/02/01 07:36:36
Done.
| |
| 1196 */ | 1214 */ |
| 1197 void generateIsTestsOn(ClassElement cls, | 1215 void generateIsTestsOn(ClassElement cls, |
| 1198 void emitIsTest(Element element)) { | 1216 void emitIsTest(Element element), |
| 1217 void emitSubstitution(Element element)) { | |
| 1199 if (checkedClasses.contains(cls)) { | 1218 if (checkedClasses.contains(cls)) { |
| 1200 emitIsTest(cls); | 1219 emitIsTest(cls); |
| 1220 emitSubstitution(cls); | |
| 1201 } | 1221 } |
| 1202 | 1222 if (cls.superclass != null && checkedClasses.contains(cls.superclass)) { |
| 1223 // TODO(karlklose): do not regenerate it, if it has not changed. | |
| 1224 emitSubstitution(cls.superclass); | |
| 1225 } | |
| 1203 Set<Element> generated = new Set<Element>(); | 1226 Set<Element> generated = new Set<Element>(); |
| 1204 // A class that defines a [:call:] method implicitly implements | 1227 // A class that defines a [:call:] method implicitly implements |
| 1205 // [Function] and needs checks for all typedefs that are used in is-checks. | 1228 // [Function] and needs checks for all typedefs that are used in is-checks. |
| 1206 if (checkedClasses.contains(compiler.functionClass) || | 1229 if (checkedClasses.contains(compiler.functionClass) || |
| 1207 !checkedTypedefs.isEmpty) { | 1230 !checkedTypedefs.isEmpty) { |
| 1208 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); | 1231 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); |
| 1209 if (call == null) { | 1232 if (call == null) { |
| 1210 // If [cls] is a closure, it has a synthetic call operator method. | 1233 // If [cls] is a closure, it has a synthetic call operator method. |
| 1211 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); | 1234 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); |
| 1212 } | 1235 } |
| 1213 if (call != null) { | 1236 if (call != null) { |
| 1214 generateInterfacesIsTests(compiler.functionClass, | 1237 generateInterfacesIsTests(compiler.functionClass, |
| 1215 emitIsTest, | 1238 emitIsTest, |
| 1239 emitSubstitution, | |
| 1216 generated); | 1240 generated); |
| 1217 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); | 1241 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); |
| 1218 } | 1242 } |
| 1219 } | 1243 } |
| 1220 | 1244 |
| 1221 for (DartType interfaceType in cls.interfaces) { | 1245 for (DartType interfaceType in cls.interfaces) { |
| 1222 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); | 1246 generateInterfacesIsTests(interfaceType.element, emitIsTest, |
| 1247 emitSubstitution, generated); | |
| 1223 } | 1248 } |
| 1224 | 1249 |
| 1225 // For native classes, we also have to run through their mixin | 1250 // For native classes, we also have to run through their mixin |
| 1226 // applications and make sure we deal with 'is' tests correctly | 1251 // applications and make sure we deal with 'is' tests correctly |
| 1227 // for those. | 1252 // for those. |
| 1228 visitNativeMixins(cls, (MixinApplicationElement mixin) { | 1253 visitNativeMixins(cls, (MixinApplicationElement mixin) { |
| 1229 for (DartType interfaceType in mixin.interfaces) { | 1254 for (DartType interfaceType in mixin.interfaces) { |
| 1230 ClassElement interfaceElement = interfaceType.element; | 1255 ClassElement interfaceElement = interfaceType.element; |
| 1231 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); | 1256 generateInterfacesIsTests(interfaceType.element, emitIsTest, |
| 1257 emitSubstitution, generated); | |
| 1232 } | 1258 } |
| 1233 }); | 1259 }); |
| 1234 } | 1260 } |
| 1235 | 1261 |
| 1236 /** | 1262 /** |
| 1237 * Generate "is tests" where [cls] is being implemented. | 1263 * Generate "is tests" where [cls] is being implemented. |
| 1238 */ | 1264 */ |
| 1239 void generateInterfacesIsTests(ClassElement cls, | 1265 void generateInterfacesIsTests(ClassElement cls, |
| 1240 void emitIsTest(ClassElement element), | 1266 void emitIsTest(ClassElement element), |
| 1267 void emitSubstitution(ClassElement element), | |
| 1241 Set<Element> alreadyGenerated) { | 1268 Set<Element> alreadyGenerated) { |
| 1242 void tryEmitTest(ClassElement cls) { | 1269 void tryEmitTest(ClassElement check) { |
| 1243 if (!alreadyGenerated.contains(cls) && checkedClasses.contains(cls)) { | 1270 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) { |
| 1244 alreadyGenerated.add(cls); | 1271 alreadyGenerated.add(check); |
| 1245 emitIsTest(cls); | 1272 emitIsTest(check); |
| 1273 emitSubstitution(check); | |
| 1246 } | 1274 } |
| 1247 }; | 1275 }; |
| 1248 | 1276 |
| 1249 tryEmitTest(cls); | 1277 tryEmitTest(cls); |
| 1250 | 1278 |
| 1251 for (DartType interfaceType in cls.interfaces) { | 1279 for (DartType interfaceType in cls.interfaces) { |
| 1252 Element element = interfaceType.element; | 1280 Element element = interfaceType.element; |
| 1253 tryEmitTest(element); | 1281 tryEmitTest(element); |
| 1254 generateInterfacesIsTests(element, emitIsTest, alreadyGenerated); | 1282 generateInterfacesIsTests(element, emitIsTest, emitSubstitution, |
| 1283 alreadyGenerated); | |
| 1255 } | 1284 } |
| 1256 | 1285 |
| 1257 // We need to also emit "is checks" for the superclass and its supertypes. | 1286 // We need to also emit "is checks" for the superclass and its supertypes. |
| 1258 ClassElement superclass = cls.superclass; | 1287 ClassElement superclass = cls.superclass; |
| 1259 if (superclass != null) { | 1288 if (superclass != null) { |
| 1260 tryEmitTest(superclass); | 1289 tryEmitTest(superclass); |
| 1261 generateInterfacesIsTests(superclass, emitIsTest, alreadyGenerated); | 1290 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, |
| 1291 alreadyGenerated); | |
| 1262 } | 1292 } |
| 1263 } | 1293 } |
| 1264 | 1294 |
| 1265 /** | 1295 /** |
| 1266 * Return a function that returns true if its argument is a class | 1296 * Return a function that returns true if its argument is a class |
| 1267 * that needs to be emitted. | 1297 * that needs to be emitted. |
| 1268 */ | 1298 */ |
| 1269 Function computeClassFilter() { | 1299 Function computeClassFilter() { |
| 1270 Set<ClassElement> unneededClasses = new Set<ClassElement>(); | 1300 Set<ClassElement> unneededClasses = new Set<ClassElement>(); |
| 1271 // The [Bool] class is not marked as abstract, but has a factory | 1301 // The [Bool] class is not marked as abstract, but has a factory |
| (...skipping 1016 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2288 """; | 2318 """; |
| 2289 const String HOOKS_API_USAGE = """ | 2319 const String HOOKS_API_USAGE = """ |
| 2290 // The code supports the following hooks: | 2320 // The code supports the following hooks: |
| 2291 // dartPrint(message) - if this function is defined it is called | 2321 // dartPrint(message) - if this function is defined it is called |
| 2292 // instead of the Dart [print] method. | 2322 // instead of the Dart [print] method. |
| 2293 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2323 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 2294 // method will not be invoked directly. | 2324 // method will not be invoked directly. |
| 2295 // Instead, a closure that will invoke [main] is | 2325 // Instead, a closure that will invoke [main] is |
| 2296 // passed to [dartMainRunner]. | 2326 // passed to [dartMainRunner]. |
| 2297 """; | 2327 """; |
| OLD | NEW |