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

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: Regenerate checks if necessary. 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, {bool emitNull: false}) {
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 } else if (emitNull) {
787 builder.addProperty(namer.substitutionName(other),
788 new js.LiteralNull());
789 }
790 }
791 }
792
793 generateIsTestsOn(classElement, generateIsTest, generateSubstitution);
776 794
777 if (identical(classElement, compiler.objectClass) 795 if (identical(classElement, compiler.objectClass)
778 && compiler.enabledNoSuchMethod) { 796 && compiler.enabledNoSuchMethod) {
779 // Emit the noSuchMethod handlers on the Object prototype now, 797 // Emit the noSuchMethod handlers on the Object prototype now,
780 // so that the code in the dynamicFunction helper can find 798 // so that the code in the dynamicFunction helper can find
781 // them. Note that this helper is invoked before analyzing the 799 // them. Note that this helper is invoked before analyzing the
782 // full JS script. 800 // full JS script.
783 if (!nativeEmitter.handleNoSuchMethod) { 801 if (!nativeEmitter.handleNoSuchMethod) {
784 emitNoSuchMethodHandlers(builder.addProperty); 802 emitNoSuchMethodHandlers(builder.addProperty);
785 } 803 }
(...skipping 12 matching lines...) Expand all
798 ? js.equals 816 ? js.equals
799 : js.strictEquals; 817 : js.strictEquals;
800 builder.addProperty(name, js.fun(['receiver', 'a'], 818 builder.addProperty(name, js.fun(['receiver', 'a'],
801 js.block1(js.return_(kind(js.use('receiver'), js.use('a')))))); 819 js.block1(js.return_(kind(js.use('receiver'), js.use('a'))))));
802 } 820 }
803 } 821 }
804 822
805 void emitRuntimeClassesAndTests(CodeBuffer buffer) { 823 void emitRuntimeClassesAndTests(CodeBuffer buffer) {
806 JavaScriptBackend backend = compiler.backend; 824 JavaScriptBackend backend = compiler.backend;
807 RuntimeTypeInformation rti = backend.rti; 825 RuntimeTypeInformation rti = backend.rti;
808 826 TypeChecks typeChecks = rti.getRequiredChecks();
809 TypeChecks typeChecks = rti.computeRequiredChecks();
810 827
811 bool needsHolder(ClassElement cls) { 828 bool needsHolder(ClassElement cls) {
812 return !neededClasses.contains(cls) || cls.isNative() || 829 return !neededClasses.contains(cls) || cls.isNative() ||
813 rti.isJsNative(cls); 830 rti.isJsNative(cls);
814 } 831 }
815 832
833 /**
834 * Generates a holder object if it is needed. A holder is a JavaScript
835 * object literal with a field [builtin$cls] that contains the name of the
836 * class as a string (just like object constructors do). The is-checks for
837 * the class are are added to the holder object later.
838 */
816 void maybeGenerateHolder(ClassElement cls) { 839 void maybeGenerateHolder(ClassElement cls) {
817 if (!needsHolder(cls)) return; 840 if (!needsHolder(cls)) return;
818
819 String holder = namer.isolateAccess(cls); 841 String holder = namer.isolateAccess(cls);
820 String name = namer.getName(cls); 842 String name = namer.getName(cls);
821 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); 843 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'); 844 buffer.add('}$N');
826 } 845 }
827 846
828 // Create representation objects for classes that we do not have a class 847 // Create representation objects for classes that we do not have a class
829 // definition for (because they are uninstantiated or native). 848 // definition for (because they are uninstantiated or native).
830 for (ClassElement cls in rti.allArguments) { 849 for (ClassElement cls in rti.allArguments) {
831 maybeGenerateHolder(cls); 850 maybeGenerateHolder(cls);
832 } 851 }
833 852
834 // Add checks to the constructors of instantiated classes. 853 // Add checks to the constructors of instantiated classes or to the created
854 // holder object.
835 for (ClassElement cls in typeChecks) { 855 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); 856 String holder = namer.isolateAccess(cls);
842 for (ClassElement check in typeChecks[cls]) { 857 for (ClassElement check in typeChecks[cls]) {
843 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); 858 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N');
859 String body = rti.getSupertypeSubstitution(cls, check);
860 if (body != null) {
861 buffer.add('$holder.${namer.substitutionName(check)}$_=${_}$body$N');
862 }
844 }; 863 };
845 } 864 }
846 } 865 }
847 866
848 void visitNativeMixins(ClassElement classElement, 867 void visitNativeMixins(ClassElement classElement,
849 void visit(MixinApplicationElement mixinApplication)) { 868 void visit(MixinApplicationElement mixinApplication)) {
850 if (!classElement.isNative()) return; 869 if (!classElement.isNative()) return;
851 // Use recursion to make sure to visit the superclasses before the 870 // Use recursion to make sure to visit the superclasses before the
852 // subclasses. Once we start keeping track of the emitted fields 871 // subclasses. Once we start keeping track of the emitted fields
853 // and members, we're going to want to visit these in the other 872 // 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) { 1203 Iterable<Element> getTypedefChecksOn(DartType type) {
1185 return checkedTypedefs.where((TypedefElement typedef) { 1204 return checkedTypedefs.where((TypedefElement typedef) {
1186 FunctionType typedefType = 1205 FunctionType typedefType =
1187 typedef.computeType(compiler).unalias(compiler); 1206 typedef.computeType(compiler).unalias(compiler);
1188 return compiler.types.isSubtype(type, typedefType); 1207 return compiler.types.isSubtype(type, typedefType);
1189 }); 1208 });
1190 } 1209 }
1191 1210
1192 /** 1211 /**
1193 * Generate "is tests" for [cls]: itself, and the "is tests" for the 1212 * 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 1213 * classes it implements and type argument substitution functions for these
1195 * super class because they will be inherited at runtime. 1214 * tests. We don't need to add the "is tests" of the super class because
1215 * they will be inherited at runtime, but we may need to generate the
1216 * substitutions, because they may have changed.
1196 */ 1217 */
1197 void generateIsTestsOn(ClassElement cls, 1218 void generateIsTestsOn(ClassElement cls,
1198 void emitIsTest(Element element)) { 1219 void emitIsTest(Element element),
1220 void emitSubstitution(Element element, {emitNull})) {
1199 if (checkedClasses.contains(cls)) { 1221 if (checkedClasses.contains(cls)) {
1200 emitIsTest(cls); 1222 emitIsTest(cls);
1223 emitSubstitution(cls);
1224 }
1225
1226 JavaScriptBackend jsBackend = compiler.backend;
1227 RuntimeTypeInformation rti = jsBackend.rti;
1228 ClassElement superclass = cls.superclass;
1229
1230 bool haveSameTypeVariables(ClassElement a, ClassElement b) {
1231 if (a.isClosure()) return true;
1232 return a.typeVariables == b.typeVariables;
1233 }
1234
1235 if (superclass != null && superclass != compiler.objectClass &&
1236 !haveSameTypeVariables(cls, superclass)) {
1237 // We cannot inherit the generated substitutions, because the type
1238 // variable layout for this class is different. Instead we generate
1239 // substitutions for all checks and make emitSubstitution a NOP for the
1240 // rest of this function.
1241 for (ClassElement check in checkedClasses) {
1242 for (DartType supertype in cls.allSupertypes) {
1243 if (supertype.element == check) {
1244 // Generate substitution. If no substitution is necessary, emit
1245 // [:null:] to overwrite a (possibly) existing substitution from the
1246 // super classes.
1247 emitSubstitution(check, emitNull: true);
1248 }
1249 }
1250 }
1251 emitSubstitution = (_) => {};
1201 } 1252 }
1202 1253
1203 Set<Element> generated = new Set<Element>(); 1254 Set<Element> generated = new Set<Element>();
1204 // A class that defines a [:call:] method implicitly implements 1255 // A class that defines a [:call:] method implicitly implements
1205 // [Function] and needs checks for all typedefs that are used in is-checks. 1256 // [Function] and needs checks for all typedefs that are used in is-checks.
1206 if (checkedClasses.contains(compiler.functionClass) || 1257 if (checkedClasses.contains(compiler.functionClass) ||
1207 !checkedTypedefs.isEmpty) { 1258 !checkedTypedefs.isEmpty) {
1208 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); 1259 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME);
1209 if (call == null) { 1260 if (call == null) {
1210 // If [cls] is a closure, it has a synthetic call operator method. 1261 // If [cls] is a closure, it has a synthetic call operator method.
1211 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); 1262 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME);
1212 } 1263 }
1213 if (call != null) { 1264 if (call != null) {
1214 generateInterfacesIsTests(compiler.functionClass, 1265 generateInterfacesIsTests(compiler.functionClass,
1215 emitIsTest, 1266 emitIsTest,
1267 emitSubstitution,
1216 generated); 1268 generated);
1217 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); 1269 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest);
1218 } 1270 }
1219 } 1271 }
1220 1272
1221 for (DartType interfaceType in cls.interfaces) { 1273 for (DartType interfaceType in cls.interfaces) {
1222 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); 1274 generateInterfacesIsTests(interfaceType.element, emitIsTest,
1275 emitSubstitution, generated);
1223 } 1276 }
1224 1277
1225 // For native classes, we also have to run through their mixin 1278 // For native classes, we also have to run through their mixin
1226 // applications and make sure we deal with 'is' tests correctly 1279 // applications and make sure we deal with 'is' tests correctly
1227 // for those. 1280 // for those.
1228 visitNativeMixins(cls, (MixinApplicationElement mixin) { 1281 visitNativeMixins(cls, (MixinApplicationElement mixin) {
1229 for (DartType interfaceType in mixin.interfaces) { 1282 for (DartType interfaceType in mixin.interfaces) {
1230 ClassElement interfaceElement = interfaceType.element; 1283 ClassElement interfaceElement = interfaceType.element;
1231 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); 1284 generateInterfacesIsTests(interfaceType.element, emitIsTest,
1285 emitSubstitution, generated);
1232 } 1286 }
1233 }); 1287 });
1234 } 1288 }
1235 1289
1236 /** 1290 /**
1237 * Generate "is tests" where [cls] is being implemented. 1291 * Generate "is tests" where [cls] is being implemented.
1238 */ 1292 */
1239 void generateInterfacesIsTests(ClassElement cls, 1293 void generateInterfacesIsTests(ClassElement cls,
1240 void emitIsTest(ClassElement element), 1294 void emitIsTest(ClassElement element),
1295 void emitSubstitution(ClassElement element),
1241 Set<Element> alreadyGenerated) { 1296 Set<Element> alreadyGenerated) {
1242 void tryEmitTest(ClassElement cls) { 1297 void tryEmitTest(ClassElement check) {
1243 if (!alreadyGenerated.contains(cls) && checkedClasses.contains(cls)) { 1298 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) {
1244 alreadyGenerated.add(cls); 1299 alreadyGenerated.add(check);
1245 emitIsTest(cls); 1300 emitIsTest(check);
1301 emitSubstitution(check);
1246 } 1302 }
1247 }; 1303 };
1248 1304
1249 tryEmitTest(cls); 1305 tryEmitTest(cls);
1250 1306
1251 for (DartType interfaceType in cls.interfaces) { 1307 for (DartType interfaceType in cls.interfaces) {
1252 Element element = interfaceType.element; 1308 Element element = interfaceType.element;
1253 tryEmitTest(element); 1309 tryEmitTest(element);
1254 generateInterfacesIsTests(element, emitIsTest, alreadyGenerated); 1310 generateInterfacesIsTests(element, emitIsTest, emitSubstitution,
1311 alreadyGenerated);
1255 } 1312 }
1256 1313
1257 // We need to also emit "is checks" for the superclass and its supertypes. 1314 // We need to also emit "is checks" for the superclass and its supertypes.
1258 ClassElement superclass = cls.superclass; 1315 ClassElement superclass = cls.superclass;
1259 if (superclass != null) { 1316 if (superclass != null) {
1260 tryEmitTest(superclass); 1317 tryEmitTest(superclass);
1261 generateInterfacesIsTests(superclass, emitIsTest, alreadyGenerated); 1318 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution,
1319 alreadyGenerated);
1262 } 1320 }
1263 } 1321 }
1264 1322
1265 /** 1323 /**
1266 * Return a function that returns true if its argument is a class 1324 * Return a function that returns true if its argument is a class
1267 * that needs to be emitted. 1325 * that needs to be emitted.
1268 */ 1326 */
1269 Function computeClassFilter() { 1327 Function computeClassFilter() {
1270 Set<ClassElement> unneededClasses = new Set<ClassElement>(); 1328 Set<ClassElement> unneededClasses = new Set<ClassElement>();
1271 // The [Bool] class is not marked as abstract, but has a factory 1329 // 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 """; 2346 """;
2289 const String HOOKS_API_USAGE = """ 2347 const String HOOKS_API_USAGE = """
2290 // The code supports the following hooks: 2348 // The code supports the following hooks:
2291 // dartPrint(message) - if this function is defined it is called 2349 // dartPrint(message) - if this function is defined it is called
2292 // instead of the Dart [print] method. 2350 // instead of the Dart [print] method.
2293 // dartMainRunner(main) - if this function is defined, the Dart [main] 2351 // dartMainRunner(main) - if this function is defined, the Dart [main]
2294 // method will not be invoked directly. 2352 // method will not be invoked directly.
2295 // Instead, a closure that will invoke [main] is 2353 // Instead, a closure that will invoke [main] is
2296 // passed to [dartMainRunner]. 2354 // passed to [dartMainRunner].
2297 """; 2355 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698