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

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 Nicolas' 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 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
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
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 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698