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

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

Issue 12218007: Implement substitution for type variables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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 758 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 visitMember, 769 visitMember,
770 includeBackendMembers: true, 770 includeBackendMembers: true,
771 includeSuperMembers: false); 771 includeSuperMembers: false);
772 }); 772 });
773 773
774 classElement.implementation.forEachMember( 774 classElement.implementation.forEachMember(
775 visitMember, 775 visitMember,
776 includeBackendMembers: true, 776 includeBackendMembers: true,
777 includeSuperMembers: false); 777 includeSuperMembers: false);
778 778
779 generateIsTestsOn(classElement, (Element other) { 779 void generateIsTest(Element other) {
780 js.Expression code; 780 js.Expression code;
781 if (compiler.objectClass == other) return; 781 if (compiler.objectClass == other) return;
782 if (nativeEmitter.requiresNativeIsCheck(other)) { 782 if (nativeEmitter.requiresNativeIsCheck(other)) {
783 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); 783 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true))));
784 } else { 784 } else {
785 code = new js.LiteralBool(true); 785 code = new js.LiteralBool(true);
786 } 786 }
787 builder.addProperty(namer.operatorIs(other), code); 787 builder.addProperty(namer.operatorIs(other), code);
788 }); 788 }
789
790 void generateSubstitution(Element other, {bool emitNull: false}) {
791 RuntimeTypeInformation rti = backend.rti;
792 // TODO(karlklose): support typedefs with variables.
793 js.Expression expression;
794 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other);
795 if (other.kind == ElementKind.CLASS) {
796 String substitution = rti.getSupertypeSubstitution(classElement, other,
797 alwaysGenerateFunction: true);
798 if (substitution != null) {
799 expression = new js.LiteralExpression(substitution);
800 } else if (emitNull || needsNativeCheck) {
801 expression = new js.LiteralNull();
802 }
803 }
804 if (expression != null) {
805 if (needsNativeCheck) {
806 expression =
807 new js.Fun([], new js.Block([new js.Return(expression)]));
808 }
809 builder.addProperty(namer.substitutionName(other), expression);
810 }
811 }
812
813 generateIsTestsOn(classElement, generateIsTest, generateSubstitution);
789 814
790 if (identical(classElement, compiler.objectClass) 815 if (identical(classElement, compiler.objectClass)
791 && compiler.enabledNoSuchMethod) { 816 && compiler.enabledNoSuchMethod) {
792 // Emit the noSuchMethod handlers on the Object prototype now, 817 // Emit the noSuchMethod handlers on the Object prototype now,
793 // so that the code in the dynamicFunction helper can find 818 // so that the code in the dynamicFunction helper can find
794 // them. Note that this helper is invoked before analyzing the 819 // them. Note that this helper is invoked before analyzing the
795 // full JS script. 820 // full JS script.
796 if (!nativeEmitter.handleNoSuchMethod) { 821 if (!nativeEmitter.handleNoSuchMethod) {
797 emitNoSuchMethodHandlers(builder.addProperty); 822 emitNoSuchMethodHandlers(builder.addProperty);
798 } 823 }
(...skipping 12 matching lines...) Expand all
811 ? js.equals 836 ? js.equals
812 : js.strictEquals; 837 : js.strictEquals;
813 builder.addProperty(name, js.fun(['receiver', 'a'], 838 builder.addProperty(name, js.fun(['receiver', 'a'],
814 js.block1(js.return_(kind(js.use('receiver'), js.use('a')))))); 839 js.block1(js.return_(kind(js.use('receiver'), js.use('a'))))));
815 } 840 }
816 } 841 }
817 842
818 void emitRuntimeClassesAndTests(CodeBuffer buffer) { 843 void emitRuntimeClassesAndTests(CodeBuffer buffer) {
819 JavaScriptBackend backend = compiler.backend; 844 JavaScriptBackend backend = compiler.backend;
820 RuntimeTypeInformation rti = backend.rti; 845 RuntimeTypeInformation rti = backend.rti;
821 846 TypeChecks typeChecks = rti.getRequiredChecks();
822 TypeChecks typeChecks = rti.computeRequiredChecks();
823 847
824 bool needsHolder(ClassElement cls) { 848 bool needsHolder(ClassElement cls) {
825 return !neededClasses.contains(cls) || cls.isNative() || 849 return !neededClasses.contains(cls) || cls.isNative() ||
826 rti.isJsNative(cls); 850 rti.isJsNative(cls);
827 } 851 }
828 852
853 /**
854 * Generates a holder object if it is needed. A holder is a JavaScript
855 * object literal with a field [builtin$cls] that contains the name of the
856 * class as a string (just like object constructors do). The is-checks for
857 * the class are are added to the holder object later.
858 */
829 void maybeGenerateHolder(ClassElement cls) { 859 void maybeGenerateHolder(ClassElement cls) {
830 if (!needsHolder(cls)) return; 860 if (!needsHolder(cls)) return;
831
832 String holder = namer.isolateAccess(cls); 861 String holder = namer.isolateAccess(cls);
833 String name = namer.getName(cls); 862 String name = namer.getName(cls);
834 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); 863 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'");
835 for (ClassElement check in typeChecks[cls]) {
836 buffer.add(',$_${namer.operatorIs(check)}:${_}true');
837 };
838 buffer.add('}$N'); 864 buffer.add('}$N');
839 } 865 }
840 866
841 // Create representation objects for classes that we do not have a class 867 // Create representation objects for classes that we do not have a class
842 // definition for (because they are uninstantiated or native). 868 // definition for (because they are uninstantiated or native).
843 for (ClassElement cls in rti.allArguments) { 869 for (ClassElement cls in rti.allArguments) {
844 maybeGenerateHolder(cls); 870 maybeGenerateHolder(cls);
845 } 871 }
846 872
847 // Add checks to the constructors of instantiated classes. 873 // Add checks to the constructors of instantiated classes or to the created
874 // holder object.
848 for (ClassElement cls in typeChecks) { 875 for (ClassElement cls in typeChecks) {
849 if (needsHolder(cls)) {
850 // We already emitted the is-checks in the object definition for this
851 // class.
852 continue;
853 }
854 String holder = namer.isolateAccess(cls); 876 String holder = namer.isolateAccess(cls);
855 for (ClassElement check in typeChecks[cls]) { 877 for (ClassElement check in typeChecks[cls]) {
856 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); 878 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N');
879 String body = rti.getSupertypeSubstitution(cls, check);
880 if (body != null) {
881 buffer.add('$holder.${namer.substitutionName(check)}$_=${_}$body$N');
882 }
857 }; 883 };
858 } 884 }
859 } 885 }
860 886
861 void visitNativeMixins(ClassElement classElement, 887 void visitNativeMixins(ClassElement classElement,
862 void visit(MixinApplicationElement mixinApplication)) { 888 void visit(MixinApplicationElement mixinApplication)) {
863 if (!classElement.isNative()) return; 889 if (!classElement.isNative()) return;
864 // Use recursion to make sure to visit the superclasses before the 890 // Use recursion to make sure to visit the superclasses before the
865 // subclasses. Once we start keeping track of the emitted fields 891 // subclasses. Once we start keeping track of the emitted fields
866 // and members, we're going to want to visit these in the other 892 // and members, we're going to want to visit these in the other
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after
1213 FunctionType typedefType = 1239 FunctionType typedefType =
1214 typedef.computeType(compiler).unalias(compiler); 1240 typedef.computeType(compiler).unalias(compiler);
1215 return compiler.types.isSubtype(type, typedefType); 1241 return compiler.types.isSubtype(type, typedefType);
1216 } 1242 }
1217 return checkedTypedefs.where(isSubtype).toList() 1243 return checkedTypedefs.where(isSubtype).toList()
1218 ..sort(Elements.compareByPosition); 1244 ..sort(Elements.compareByPosition);
1219 } 1245 }
1220 1246
1221 /** 1247 /**
1222 * Generate "is tests" for [cls]: itself, and the "is tests" for the 1248 * Generate "is tests" for [cls]: itself, and the "is tests" for the
1223 * classes it implements. We don't need to add the "is tests" of the 1249 * classes it implements and type argument substitution functions for these
1224 * super class because they will be inherited at runtime. 1250 * tests. We don't need to add the "is tests" of the super class because
1251 * they will be inherited at runtime, but we may need to generate the
1252 * substitutions, because they may have changed.
1225 */ 1253 */
1226 void generateIsTestsOn(ClassElement cls, 1254 void generateIsTestsOn(ClassElement cls,
1227 void emitIsTest(Element element)) { 1255 void emitIsTest(Element element),
1256 void emitSubstitution(Element element, {emitNull})) {
1228 if (checkedClasses.contains(cls)) { 1257 if (checkedClasses.contains(cls)) {
1229 emitIsTest(cls); 1258 emitIsTest(cls);
1259 emitSubstitution(cls);
1260 }
1261
1262 JavaScriptBackend jsBackend = compiler.backend;
1263 RuntimeTypeInformation rti = jsBackend.rti;
1264 ClassElement superclass = cls.superclass;
1265
1266 bool haveSameTypeVariables(ClassElement a, ClassElement b) {
1267 if (a.isClosure()) return true;
1268 return a.typeVariables == b.typeVariables;
1269 }
1270
1271 if (superclass != null && superclass != compiler.objectClass &&
1272 !haveSameTypeVariables(cls, superclass)) {
1273 // We cannot inherit the generated substitutions, because the type
1274 // variable layout for this class is different. Instead we generate
1275 // substitutions for all checks and make emitSubstitution a NOP for the
1276 // rest of this function.
1277 for (ClassElement check in checkedClasses) {
1278 for (DartType supertype in cls.allSupertypes) {
1279 if (supertype.element == check) {
1280 // Generate substitution. If no substitution is necessary, emit
1281 // [:null:] to overwrite a (possibly) existing substitution from the
1282 // super classes.
1283 emitSubstitution(check, emitNull: true);
1284 }
1285 }
1286 }
1287 void emitNothing(_, {emitNull}) {};
1288 emitSubstitution = emitNothing;
1230 } 1289 }
1231 1290
1232 Set<Element> generated = new Set<Element>(); 1291 Set<Element> generated = new Set<Element>();
1233 // A class that defines a [:call:] method implicitly implements 1292 // A class that defines a [:call:] method implicitly implements
1234 // [Function] and needs checks for all typedefs that are used in is-checks. 1293 // [Function] and needs checks for all typedefs that are used in is-checks.
1235 if (checkedClasses.contains(compiler.functionClass) || 1294 if (checkedClasses.contains(compiler.functionClass) ||
1236 !checkedTypedefs.isEmpty) { 1295 !checkedTypedefs.isEmpty) {
1237 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); 1296 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME);
1238 if (call == null) { 1297 if (call == null) {
1239 // If [cls] is a closure, it has a synthetic call operator method. 1298 // If [cls] is a closure, it has a synthetic call operator method.
1240 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); 1299 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME);
1241 } 1300 }
1242 if (call != null) { 1301 if (call != null) {
1243 generateInterfacesIsTests(compiler.functionClass, 1302 generateInterfacesIsTests(compiler.functionClass,
1244 emitIsTest, 1303 emitIsTest,
1304 emitSubstitution,
1245 generated); 1305 generated);
1246 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); 1306 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest);
1247 } 1307 }
1248 } 1308 }
1249 1309
1250 for (DartType interfaceType in cls.interfaces) { 1310 for (DartType interfaceType in cls.interfaces) {
1251 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); 1311 generateInterfacesIsTests(interfaceType.element, emitIsTest,
1312 emitSubstitution, generated);
1252 } 1313 }
1253 1314
1254 // For native classes, we also have to run through their mixin 1315 // For native classes, we also have to run through their mixin
1255 // applications and make sure we deal with 'is' tests correctly 1316 // applications and make sure we deal with 'is' tests correctly
1256 // for those. 1317 // for those.
1257 visitNativeMixins(cls, (MixinApplicationElement mixin) { 1318 visitNativeMixins(cls, (MixinApplicationElement mixin) {
1258 for (DartType interfaceType in mixin.interfaces) { 1319 for (DartType interfaceType in mixin.interfaces) {
1259 ClassElement interfaceElement = interfaceType.element; 1320 ClassElement interfaceElement = interfaceType.element;
1260 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); 1321 generateInterfacesIsTests(interfaceType.element, emitIsTest,
1322 emitSubstitution, generated);
1261 } 1323 }
1262 }); 1324 });
1263 } 1325 }
1264 1326
1265 /** 1327 /**
1266 * Generate "is tests" where [cls] is being implemented. 1328 * Generate "is tests" where [cls] is being implemented.
1267 */ 1329 */
1268 void generateInterfacesIsTests(ClassElement cls, 1330 void generateInterfacesIsTests(ClassElement cls,
1269 void emitIsTest(ClassElement element), 1331 void emitIsTest(ClassElement element),
1332 void emitSubstitution(ClassElement element),
1270 Set<Element> alreadyGenerated) { 1333 Set<Element> alreadyGenerated) {
1271 void tryEmitTest(ClassElement cls) { 1334 void tryEmitTest(ClassElement check) {
1272 if (!alreadyGenerated.contains(cls) && checkedClasses.contains(cls)) { 1335 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) {
1273 alreadyGenerated.add(cls); 1336 alreadyGenerated.add(check);
1274 emitIsTest(cls); 1337 emitIsTest(check);
1338 emitSubstitution(check);
1275 } 1339 }
1276 }; 1340 };
1277 1341
1278 tryEmitTest(cls); 1342 tryEmitTest(cls);
1279 1343
1280 for (DartType interfaceType in cls.interfaces) { 1344 for (DartType interfaceType in cls.interfaces) {
1281 Element element = interfaceType.element; 1345 Element element = interfaceType.element;
1282 tryEmitTest(element); 1346 tryEmitTest(element);
1283 generateInterfacesIsTests(element, emitIsTest, alreadyGenerated); 1347 generateInterfacesIsTests(element, emitIsTest, emitSubstitution,
1348 alreadyGenerated);
1284 } 1349 }
1285 1350
1286 // We need to also emit "is checks" for the superclass and its supertypes. 1351 // We need to also emit "is checks" for the superclass and its supertypes.
1287 ClassElement superclass = cls.superclass; 1352 ClassElement superclass = cls.superclass;
1288 if (superclass != null) { 1353 if (superclass != null) {
1289 tryEmitTest(superclass); 1354 tryEmitTest(superclass);
1290 generateInterfacesIsTests(superclass, emitIsTest, alreadyGenerated); 1355 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution,
1356 alreadyGenerated);
1291 } 1357 }
1292 } 1358 }
1293 1359
1294 /** 1360 /**
1295 * Return a function that returns true if its argument is a class 1361 * Return a function that returns true if its argument is a class
1296 * that needs to be emitted. 1362 * that needs to be emitted.
1297 */ 1363 */
1298 Function computeClassFilter() { 1364 Function computeClassFilter() {
1299 Set<ClassElement> unneededClasses = new Set<ClassElement>(); 1365 Set<ClassElement> unneededClasses = new Set<ClassElement>();
1300 // The [Bool] class is not marked as abstract, but has a factory 1366 // The [Bool] class is not marked as abstract, but has a factory
(...skipping 1049 matching lines...) Expand 10 before | Expand all | Expand 10 after
2350 """; 2416 """;
2351 const String HOOKS_API_USAGE = """ 2417 const String HOOKS_API_USAGE = """
2352 // The code supports the following hooks: 2418 // The code supports the following hooks:
2353 // dartPrint(message) - if this function is defined it is called 2419 // dartPrint(message) - if this function is defined it is called
2354 // instead of the Dart [print] method. 2420 // instead of the Dart [print] method.
2355 // dartMainRunner(main) - if this function is defined, the Dart [main] 2421 // dartMainRunner(main) - if this function is defined, the Dart [main]
2356 // method will not be invoked directly. 2422 // method will not be invoked directly.
2357 // Instead, a closure that will invoke [main] is 2423 // Instead, a closure that will invoke [main] is
2358 // passed to [dartMainRunner]. 2424 // passed to [dartMainRunner].
2359 """; 2425 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698