Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(237)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 12018015: Implement substitution for type variables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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.
ngeoffray 2013/01/30 13:06:00 Is there a description of the "holder object"? Cou
karlklose 2013/01/30 15:37:18 I added a short description comment to the mabeGen
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) {
ngeoffray 2013/01/30 13:06:00 Why is that necessary now?
karlklose 2013/01/30 15:37:18 It is not, good catch. Removed.
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');
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
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)) {
ngeoffray 2013/01/30 13:06:00 Please add a comment here, and/or update the one l
karlklose 2013/01/30 15:37:18 Done.
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
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 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698