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 | |
| 811 bool needsHolder(ClassElement cls) { | 824 bool needsHolder(ClassElement cls) { |
| 812 return !neededClasses.contains(cls) || cls.isNative() || | 825 return !neededClasses.contains(cls) || cls.isNative() || |
| 813 rti.isJsNative(cls); | 826 rti.isJsNative(cls); |
| 814 } | 827 } |
| 815 | |
| 816 void maybeGenerateHolder(ClassElement cls) { | 828 void maybeGenerateHolder(ClassElement cls) { |
| 817 if (!needsHolder(cls)) return; | 829 if (!needsHolder(cls)) return; |
| 818 | |
| 819 String holder = namer.isolateAccess(cls); | 830 String holder = namer.isolateAccess(cls); |
| 820 String name = namer.getName(cls); | 831 String name = namer.getName(cls); |
| 821 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); | 832 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'); | 833 buffer.add('}$N'); |
| 826 } | 834 } |
| 827 | 835 |
| 828 // Create representation objects for classes that we do not have a class | 836 // Create representation objects for classes that we do not have a class |
| 829 // definition for (because they are uninstantiated or native). | 837 // definition for (because they are uninstantiated or native). |
| 830 for (ClassElement cls in rti.allArguments) { | 838 for (ClassElement cls in rti.allArguments) { |
| 831 maybeGenerateHolder(cls); | 839 maybeGenerateHolder(cls); |
| 832 } | 840 } |
| 833 | 841 |
| 834 // Add checks to the constructors of instantiated classes. | 842 // Add checks to the constructors of instantiated classes or to the created |
| 843 // holder object. | |
| 835 for (ClassElement cls in typeChecks) { | 844 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); | 845 String holder = namer.isolateAccess(cls); |
| 842 for (ClassElement check in typeChecks[cls]) { | 846 for (ClassElement check in typeChecks[cls]) { |
| 847 if (check == compiler.dynamicClass) { | |
| 848 continue; | |
| 849 } | |
| 843 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); | 850 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); |
| 851 String body = rti.getSupertypeSubstitution(cls, check); | |
| 852 if (body != null) { | |
| 853 buffer.add('$holder.${namer.substitutionName(check)}$_=${_}$body$N'); | |
|
kasperl
2013/01/29 15:02:34
Isn't it a little bit dangerous to manipulate (add
karlklose
2013/01/30 12:01:19
I am using the name as returned by the namer, the
| |
| 854 } | |
| 844 }; | 855 }; |
| 845 } | 856 } |
| 846 } | 857 } |
| 847 | 858 |
| 848 void visitNativeMixins(ClassElement classElement, | 859 void visitNativeMixins(ClassElement classElement, |
| 849 void visit(MixinApplicationElement mixinApplication)) { | 860 void visit(MixinApplicationElement mixinApplication)) { |
| 850 if (!classElement.isNative()) return; | 861 if (!classElement.isNative()) return; |
| 851 // Use recursion to make sure to visit the superclasses before the | 862 // Use recursion to make sure to visit the superclasses before the |
| 852 // subclasses. Once we start keeping track of the emitted fields | 863 // subclasses. Once we start keeping track of the emitted fields |
| 853 // and members, we're going to want to visit these in the other | 864 // and members, we're going to want to visit these in the other |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1188 return compiler.types.isSubtype(type, typedefType); | 1199 return compiler.types.isSubtype(type, typedefType); |
| 1189 }); | 1200 }); |
| 1190 } | 1201 } |
| 1191 | 1202 |
| 1192 /** | 1203 /** |
| 1193 * Generate "is tests" for [cls]: itself, and the "is tests" for the | 1204 * 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 | 1205 * classes it implements. We don't need to add the "is tests" of the |
| 1195 * super class because they will be inherited at runtime. | 1206 * super class because they will be inherited at runtime. |
| 1196 */ | 1207 */ |
| 1197 void generateIsTestsOn(ClassElement cls, | 1208 void generateIsTestsOn(ClassElement cls, |
| 1198 void emitIsTest(Element element)) { | 1209 void emitIsTest(Element element), |
| 1210 void emitSubstitution(Element element)) { | |
| 1199 if (checkedClasses.contains(cls)) { | 1211 if (checkedClasses.contains(cls)) { |
| 1200 emitIsTest(cls); | 1212 emitIsTest(cls); |
| 1213 emitSubstitution(cls); | |
| 1201 } | 1214 } |
| 1202 | 1215 if (cls.superclass != null && checkedClasses.contains(cls.superclass)) { |
| 1216 emitSubstitution(cls.superclass); | |
| 1217 } | |
| 1203 Set<Element> generated = new Set<Element>(); | 1218 Set<Element> generated = new Set<Element>(); |
| 1204 // A class that defines a [:call:] method implicitly implements | 1219 // A class that defines a [:call:] method implicitly implements |
| 1205 // [Function] and needs checks for all typedefs that are used in is-checks. | 1220 // [Function] and needs checks for all typedefs that are used in is-checks. |
| 1206 if (checkedClasses.contains(compiler.functionClass) || | 1221 if (checkedClasses.contains(compiler.functionClass) || |
| 1207 !checkedTypedefs.isEmpty) { | 1222 !checkedTypedefs.isEmpty) { |
| 1208 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); | 1223 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); |
| 1209 if (call == null) { | 1224 if (call == null) { |
| 1210 // If [cls] is a closure, it has a synthetic call operator method. | 1225 // If [cls] is a closure, it has a synthetic call operator method. |
| 1211 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); | 1226 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); |
| 1212 } | 1227 } |
| 1213 if (call != null) { | 1228 if (call != null) { |
| 1214 generateInterfacesIsTests(compiler.functionClass, | 1229 generateInterfacesIsTests(compiler.functionClass, |
| 1215 emitIsTest, | 1230 emitIsTest, |
| 1231 emitSubstitution, | |
| 1216 generated); | 1232 generated); |
| 1217 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); | 1233 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); |
| 1218 } | 1234 } |
| 1219 } | 1235 } |
| 1220 | 1236 |
| 1221 for (DartType interfaceType in cls.interfaces) { | 1237 for (DartType interfaceType in cls.interfaces) { |
| 1222 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); | 1238 generateInterfacesIsTests(interfaceType.element, emitIsTest, |
| 1239 emitSubstitution, generated); | |
| 1223 } | 1240 } |
| 1224 | 1241 |
| 1225 // For native classes, we also have to run through their mixin | 1242 // For native classes, we also have to run through their mixin |
| 1226 // applications and make sure we deal with 'is' tests correctly | 1243 // applications and make sure we deal with 'is' tests correctly |
| 1227 // for those. | 1244 // for those. |
| 1228 visitNativeMixins(cls, (MixinApplicationElement mixin) { | 1245 visitNativeMixins(cls, (MixinApplicationElement mixin) { |
| 1229 for (DartType interfaceType in mixin.interfaces) { | 1246 for (DartType interfaceType in mixin.interfaces) { |
| 1230 ClassElement interfaceElement = interfaceType.element; | 1247 ClassElement interfaceElement = interfaceType.element; |
| 1231 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); | 1248 generateInterfacesIsTests(interfaceType.element, emitIsTest, |
| 1249 emitSubstitution, generated); | |
| 1232 } | 1250 } |
| 1233 }); | 1251 }); |
| 1234 } | 1252 } |
| 1235 | 1253 |
| 1236 /** | 1254 /** |
| 1237 * Generate "is tests" where [cls] is being implemented. | 1255 * Generate "is tests" where [cls] is being implemented. |
| 1238 */ | 1256 */ |
| 1239 void generateInterfacesIsTests(ClassElement cls, | 1257 void generateInterfacesIsTests(ClassElement cls, |
| 1240 void emitIsTest(ClassElement element), | 1258 void emitIsTest(ClassElement element), |
| 1259 void emitSubstitution(ClassElement element), | |
| 1241 Set<Element> alreadyGenerated) { | 1260 Set<Element> alreadyGenerated) { |
| 1242 void tryEmitTest(ClassElement cls) { | 1261 void tryEmitTest(ClassElement check) { |
| 1243 if (!alreadyGenerated.contains(cls) && checkedClasses.contains(cls)) { | 1262 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) { |
| 1244 alreadyGenerated.add(cls); | 1263 alreadyGenerated.add(check); |
| 1245 emitIsTest(cls); | 1264 emitIsTest(check); |
| 1265 emitSubstitution(check); | |
| 1246 } | 1266 } |
| 1247 }; | 1267 }; |
| 1248 | 1268 |
| 1249 tryEmitTest(cls); | 1269 tryEmitTest(cls); |
| 1250 | 1270 |
| 1251 for (DartType interfaceType in cls.interfaces) { | 1271 for (DartType interfaceType in cls.interfaces) { |
| 1252 Element element = interfaceType.element; | 1272 Element element = interfaceType.element; |
| 1253 tryEmitTest(element); | 1273 tryEmitTest(element); |
| 1254 generateInterfacesIsTests(element, emitIsTest, alreadyGenerated); | 1274 generateInterfacesIsTests(element, emitIsTest, emitSubstitution, |
| 1275 alreadyGenerated); | |
| 1255 } | 1276 } |
| 1256 | 1277 |
| 1257 // We need to also emit "is checks" for the superclass and its supertypes. | 1278 // We need to also emit "is checks" for the superclass and its supertypes. |
| 1258 ClassElement superclass = cls.superclass; | 1279 ClassElement superclass = cls.superclass; |
| 1259 if (superclass != null) { | 1280 if (superclass != null) { |
| 1260 tryEmitTest(superclass); | 1281 tryEmitTest(superclass); |
| 1261 generateInterfacesIsTests(superclass, emitIsTest, alreadyGenerated); | 1282 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, |
| 1283 alreadyGenerated); | |
| 1262 } | 1284 } |
| 1263 } | 1285 } |
| 1264 | 1286 |
| 1265 /** | 1287 /** |
| 1266 * Return a function that returns true if its argument is a class | 1288 * Return a function that returns true if its argument is a class |
| 1267 * that needs to be emitted. | 1289 * that needs to be emitted. |
| 1268 */ | 1290 */ |
| 1269 Function computeClassFilter() { | 1291 Function computeClassFilter() { |
| 1270 Set<ClassElement> unneededClasses = new Set<ClassElement>(); | 1292 Set<ClassElement> unneededClasses = new Set<ClassElement>(); |
| 1271 // The [Bool] class is not marked as abstract, but has a factory | 1293 // 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 """; | 2310 """; |
| 2289 const String HOOKS_API_USAGE = """ | 2311 const String HOOKS_API_USAGE = """ |
| 2290 // The code supports the following hooks: | 2312 // The code supports the following hooks: |
| 2291 // dartPrint(message) - if this function is defined it is called | 2313 // dartPrint(message) - if this function is defined it is called |
| 2292 // instead of the Dart [print] method. | 2314 // instead of the Dart [print] method. |
| 2293 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2315 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 2294 // method will not be invoked directly. | 2316 // method will not be invoked directly. |
| 2295 // Instead, a closure that will invoke [main] is | 2317 // Instead, a closure that will invoke [main] is |
| 2296 // passed to [dartMainRunner]. | 2318 // passed to [dartMainRunner]. |
| 2297 """; | 2319 """; |
| OLD | NEW |