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

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

Issue 12210142: Implement is-checks against type variables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix computation of classes that need rti. 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 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
92 92
93 /** 93 /**
94 * Raw ClassElement symbols occuring in is-checks and type assertions. If the 94 * Raw ClassElement symbols occuring in is-checks and type assertions. If the
95 * program contains parameterized checks `x is Set<int>` and 95 * program contains parameterized checks `x is Set<int>` and
96 * `x is Set<String>` then the ClassElement `Set` will occur once in 96 * `x is Set<String>` then the ClassElement `Set` will occur once in
97 * [checkedClasses]. 97 * [checkedClasses].
98 */ 98 */
99 Set<ClassElement> checkedClasses; 99 Set<ClassElement> checkedClasses;
100 100
101 /** 101 /**
102 * Set of JS native classes (or 'Object') that need a [:$nativeCheck:] method,
103 * because they could be used as a type argument in an is-check.
104 *
105 * For example, in the following program, the class int needs a native check
106 * to correctly match integers in the is-check:
107 * class Check<T> { foo(o) => o is T; }
108 * main() => new Check<int>().foo(3);
109 */
110 Set<ClassElement> requiredNativeChecks;
111
112 /**
102 * Raw Typedef symbols occuring in is-checks and type assertions. If the 113 * Raw Typedef symbols occuring in is-checks and type assertions. If the
103 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement 114 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement
104 * `F` will occur once in [checkedTypedefs]. 115 * `F` will occur once in [checkedTypedefs].
105 */ 116 */
106 Set<TypedefElement> checkedTypedefs; 117 Set<TypedefElement> checkedTypedefs;
107 118
108 final bool generateSourceMap; 119 final bool generateSourceMap;
109 120
110 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap) 121 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap)
111 : boundClosureBuffer = new CodeBuffer(), 122 : boundClosureBuffer = new CodeBuffer(),
112 mainBuffer = new CodeBuffer(), 123 mainBuffer = new CodeBuffer(),
113 this.namer = namer, 124 this.namer = namer,
114 boundClosureCache = new Map<int, String>(), 125 boundClosureCache = new Map<int, String>(),
115 interceptorClosureCache = new Map<int, String>(), 126 interceptorClosureCache = new Map<int, String>(),
116 constantEmitter = new ConstantEmitter(compiler, namer), 127 constantEmitter = new ConstantEmitter(compiler, namer),
117 super(compiler) { 128 super(compiler) {
118 nativeEmitter = new NativeEmitter(this); 129 nativeEmitter = new NativeEmitter(this);
119 } 130 }
120 131
121 void computeRequiredTypeChecks() { 132 void computeRequiredTypeChecks() {
122 assert(checkedClasses == null); 133 assert(checkedClasses == null &&
134 checkedTypedefs == null &&
135 requiredNativeChecks == null);
136
137 // Compute type arguments of classes that potentially use their type
138 // variables in is-checks and compute the (small) set of classes that
139 // need native check methods (consult the documentation of
140 // [requiredNativeChecks] for more information).
141 requiredNativeChecks = new Set<ClassElement>();
142 Iterable<ClassElement> classes = backend.classesUsingTypeVariableTests;
143 if (!classes.isEmpty) {
144 // Find all instantiated types that are a subtype of a class that uses
145 // one of its type arguments in an is-check and add the arguments to the
146 // set of is-checks.
ngeoffray 2013/02/21 10:26:18 We have a [subtypes] set in the world. Couldn't yo
karlklose 2013/02/21 14:48:44 No, we want to have the instantiated types to now
147 for (DartType type in compiler.codegenWorld.instantiatedTypes) {
148 if (type.kind != TypeKind.INTERFACE) continue;
149 InterfaceType classType = type;
150 for (ClassElement cls in classes) {
151 // We need the type as instance of its superclass anyway, so we just
152 // try to compute the substitution; if the result is [:null:], the
153 // classes are not related.
154 InterfaceType instance = classType.asInstanceOf(cls);
155 if (instance == null) continue;
156 Link<DartType> typeArguments = instance.typeArguments;
157 for (DartType argument in typeArguments) {
158 Element element = argument.element;
159 JavaScriptBackend backend = compiler.backend;
160 if (backend.rti.needsNativeCheck(element)) {
161 requiredNativeChecks.add(element);
162 }
163 compiler.codegenWorld.isChecks.add(argument);
164 }
165 }
166 }
167 }
168
123 checkedClasses = new Set<ClassElement>(); 169 checkedClasses = new Set<ClassElement>();
124 checkedTypedefs = new Set<TypedefElement>(); 170 checkedTypedefs = new Set<TypedefElement>();
125 compiler.codegenWorld.isChecks.forEach((DartType t) { 171 compiler.codegenWorld.isChecks.forEach((DartType t) {
126 if (t is InterfaceType) { 172 if (t is InterfaceType) {
127 checkedClasses.add(t.element); 173 checkedClasses.add(t.element);
128 } else if (t is TypedefType) { 174 } else if (t is TypedefType) {
129 checkedTypedefs.add(t.element); 175 checkedTypedefs.add(t.element);
130 } 176 }
131 }); 177 });
132 } 178 }
(...skipping 935 matching lines...) Expand 10 before | Expand all | Expand 10 after
1068 includeSuperMembers: false); 1114 includeSuperMembers: false);
1069 }); 1115 });
1070 1116
1071 classElement.implementation.forEachMember( 1117 classElement.implementation.forEachMember(
1072 visitMember, 1118 visitMember,
1073 includeBackendMembers: true, 1119 includeBackendMembers: true,
1074 includeSuperMembers: false); 1120 includeSuperMembers: false);
1075 1121
1076 void generateIsTest(Element other) { 1122 void generateIsTest(Element other) {
1077 jsAst.Expression code; 1123 jsAst.Expression code;
1078 if (compiler.objectClass == other) return; 1124 if (other == compiler.objectClass) return;
1079 if (nativeEmitter.requiresNativeIsCheck(other)) { 1125 if (nativeEmitter.requiresNativeIsCheck(other)) {
1080 code = js.fun([], [js.return_(true)]); 1126 code = js.fun([], [js.return_(true)]);
1081 } else { 1127 } else {
1082 code = new jsAst.LiteralBool(true); 1128 code = new jsAst.LiteralBool(true);
1083 } 1129 }
1084 builder.addProperty(namer.operatorIs(other), code); 1130 builder.addProperty(namer.operatorIs(other), code);
1085 } 1131 }
1086 1132
1087 void generateSubstitution(Element other, {bool emitNull: false}) { 1133 void generateSubstitution(Element other, {bool emitNull: false}) {
1088 RuntimeTypeInformation rti = backend.rti; 1134 RuntimeTypeInformation rti = backend.rti;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1129 String name = backend.namer.publicInstanceMethodNameByArity( 1175 String name = backend.namer.publicInstanceMethodNameByArity(
1130 const SourceString('=='), 1); 1176 const SourceString('=='), 1);
1131 Function kind = (classElement == backend.jsNullClass) 1177 Function kind = (classElement == backend.jsNullClass)
1132 ? js.equals 1178 ? js.equals
1133 : js.strictEquals; 1179 : js.strictEquals;
1134 builder.addProperty(name, js.fun(['receiver', 'a'], 1180 builder.addProperty(name, js.fun(['receiver', 'a'],
1135 js.block(js.return_(kind(js['receiver'], js['a']))))); 1181 js.block(js.return_(kind(js['receiver'], js['a'])))));
1136 } 1182 }
1137 } 1183 }
1138 1184
1139 void emitRuntimeClassesAndTests(CodeBuffer buffer) { 1185 void emitRuntimeTypeSupport(CodeBuffer buffer) {
1140 RuntimeTypeInformation rti = backend.rti; 1186 RuntimeTypeInformation rti = backend.rti;
1141 TypeChecks typeChecks = rti.getRequiredChecks(); 1187 TypeChecks typeChecks = rti.getRequiredChecks();
1142 1188
1143 bool needsHolder(ClassElement cls) { 1189 bool needsHolder(ClassElement cls) {
1144 return !neededClasses.contains(cls) || cls.isNative() || 1190 return !neededClasses.contains(cls) || cls.isNative() ||
1145 rti.isJsNative(cls); 1191 rti.isJsNative(cls);
1146 } 1192 }
1147 1193
1148 /** 1194 /**
1149 * Generates a holder object if it is needed. A holder is a JavaScript 1195 * Generates a holder object if it is needed. A holder is a JavaScript
1150 * object literal with a field [builtin$cls] that contains the name of the 1196 * object literal with a field [builtin$cls] that contains the name of the
1151 * class as a string (just like object constructors do). The is-checks for 1197 * class as a string (just like object constructors do). The is-checks for
1152 * the class are are added to the holder object later. 1198 * the class are are added to the holder object later.
1153 */ 1199 */
1154 void maybeGenerateHolder(ClassElement cls) { 1200 void maybeGenerateHolder(ClassElement cls) {
1155 if (!needsHolder(cls)) return; 1201 if (!needsHolder(cls)) return;
1156 String holder = namer.isolateAccess(cls); 1202 String holder = namer.isolateAccess(cls);
1157 String name = namer.getName(cls); 1203 String name = namer.getName(cls);
1158 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); 1204 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'}$N");
1159 buffer.add('}$N');
1160 } 1205 }
1161 1206
1162 // Create representation objects for classes that we do not have a class 1207 // Create representation objects for classes that we do not have a class
1163 // definition for (because they are uninstantiated or native). 1208 // definition for (because they are uninstantiated or native).
1164 for (ClassElement cls in rti.allArguments) { 1209 for (ClassElement cls in rti.allArguments) {
1165 maybeGenerateHolder(cls); 1210 maybeGenerateHolder(cls);
1166 } 1211 }
1167 1212
1168 // Add checks to the constructors of instantiated classes or to the created 1213 // Add checks to the constructors of instantiated classes or to the created
1169 // holder object. 1214 // holder object.
1170 for (ClassElement cls in typeChecks) { 1215 for (ClassElement cls in typeChecks) {
1171 String holder = namer.isolateAccess(cls); 1216 String holder = namer.isolateAccess(cls);
1172 for (ClassElement check in typeChecks[cls]) { 1217 for (ClassElement check in typeChecks[cls]) {
1173 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); 1218 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N');
1174 String body = rti.getSupertypeSubstitution(cls, check); 1219 String body = rti.getSupertypeSubstitution(cls, check);
1175 if (body != null) { 1220 if (body != null) {
1176 buffer.add('$holder.${namer.substitutionName(check)}$_=${_}$body$N'); 1221 buffer.add('$holder.${namer.substitutionName(check)}$_=${_}$body$N');
1177 } 1222 }
1178 }; 1223 };
1179 } 1224 }
1225
1226 // Emit native check methods for the class representations of native types
1227 // that could be used in an is-check against a type variable.
1228 requiredNativeChecks.forEach((ClassElement cls) {
1229 jsAst.Expression nativeCheck = rti.getNativeCheck(cls);
1230 String holder = namer.isolateAccess(cls);
1231 buffer.add('$holder.${namer.getNativeCheckName()}$_=$_');
1232 buffer.addBuffer(jsAst.prettyPrint(nativeCheck, compiler));
1233 buffer.add('$N');
1234 });
1180 } 1235 }
1181 1236
1182 void visitNativeMixins(ClassElement classElement, 1237 void visitNativeMixins(ClassElement classElement,
1183 void visit(MixinApplicationElement mixinApplication)) { 1238 void visit(MixinApplicationElement mixinApplication)) {
1184 if (!classElement.isNative()) return; 1239 if (!classElement.isNative()) return;
1185 // Use recursion to make sure to visit the superclasses before the 1240 // Use recursion to make sure to visit the superclasses before the
1186 // subclasses. Once we start keeping track of the emitted fields 1241 // subclasses. Once we start keeping track of the emitted fields
1187 // and members, we're going to want to visit these in the other 1242 // and members, we're going to want to visit these in the other
1188 // order so we get the most specialized definition first. 1243 // order so we get the most specialized definition first.
1189 void recurse(ClassElement cls) { 1244 void recurse(ClassElement cls) {
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after
1558 // substitutions for all checks and make emitSubstitution a NOP for the 1613 // substitutions for all checks and make emitSubstitution a NOP for the
1559 // rest of this function. 1614 // rest of this function.
1560 Set<ClassElement> emitted = new Set<ClassElement>(); 1615 Set<ClassElement> emitted = new Set<ClassElement>();
1561 // TODO(karlklose): move the computation of these checks to 1616 // TODO(karlklose): move the computation of these checks to
1562 // RuntimeTypeInformation. 1617 // RuntimeTypeInformation.
1563 if (compiler.world.needsRti(cls)) { 1618 if (compiler.world.needsRti(cls)) {
1564 emitSubstitution(superclass, emitNull: true); 1619 emitSubstitution(superclass, emitNull: true);
1565 emitted.add(superclass); 1620 emitted.add(superclass);
1566 } 1621 }
1567 for (DartType supertype in cls.allSupertypes) { 1622 for (DartType supertype in cls.allSupertypes) {
1623 ClassElement superclass = supertype.element;
1624 if (backend.classesUsingTypeVariableTests.contains(superclass)) {
1625 emitSubstitution(superclass, emitNull: true);
1626 emitted.add(superclass);
1627 }
1568 for (ClassElement check in checkedClasses) { 1628 for (ClassElement check in checkedClasses) {
1569 if (supertype.element == check && !emitted.contains(check)) { 1629 if (supertype.element == check && !emitted.contains(check)) {
1570 // Generate substitution. If no substitution is necessary, emit 1630 // Generate substitution. If no substitution is necessary, emit
1571 // [:null:] to overwrite a (possibly) existing substitution from the 1631 // [:null:] to overwrite a (possibly) existing substitution from the
1572 // super classes. 1632 // super classes.
1573 emitSubstitution(check, emitNull: true); 1633 emitSubstitution(check, emitNull: true);
1574 emitted.add(check); 1634 emitted.add(check);
1575 } 1635 }
1576 } 1636 }
1577 } 1637 }
(...skipping 1018 matching lines...) Expand 10 before | Expand all | Expand 10 after
2596 'var $isolateProperties$_=$_$isolatePropertiesName$N'); 2656 'var $isolateProperties$_=$_$isolatePropertiesName$N');
2597 emitClasses(mainBuffer); 2657 emitClasses(mainBuffer);
2598 mainBuffer.add(boundClosureBuffer); 2658 mainBuffer.add(boundClosureBuffer);
2599 // Clear the buffer, so that we can reuse it for the native classes. 2659 // Clear the buffer, so that we can reuse it for the native classes.
2600 boundClosureBuffer.clear(); 2660 boundClosureBuffer.clear();
2601 emitStaticFunctions(mainBuffer); 2661 emitStaticFunctions(mainBuffer);
2602 emitStaticFunctionGetters(mainBuffer); 2662 emitStaticFunctionGetters(mainBuffer);
2603 // We need to finish the classes before we construct compile time 2663 // We need to finish the classes before we construct compile time
2604 // constants. 2664 // constants.
2605 emitFinishClassesInvocationIfNecessary(mainBuffer); 2665 emitFinishClassesInvocationIfNecessary(mainBuffer);
2606 emitRuntimeClassesAndTests(mainBuffer); 2666 emitRuntimeTypeSupport(mainBuffer);
2607 emitCompileTimeConstants(mainBuffer); 2667 emitCompileTimeConstants(mainBuffer);
2608 // Static field initializations require the classes and compile-time 2668 // Static field initializations require the classes and compile-time
2609 // constants to be set up. 2669 // constants to be set up.
2610 emitStaticNonFinalFieldInitializations(mainBuffer); 2670 emitStaticNonFinalFieldInitializations(mainBuffer);
2611 emitOneShotInterceptors(mainBuffer); 2671 emitOneShotInterceptors(mainBuffer);
2612 emitGetInterceptorMethods(mainBuffer); 2672 emitGetInterceptorMethods(mainBuffer);
2613 emitLazilyInitializedStaticFields(mainBuffer); 2673 emitLazilyInitializedStaticFields(mainBuffer);
2614 2674
2615 isolateProperties = isolatePropertiesName; 2675 isolateProperties = isolatePropertiesName;
2616 // The following code should not use the short-hand for the 2676 // The following code should not use the short-hand for the
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
2676 """; 2736 """;
2677 const String HOOKS_API_USAGE = """ 2737 const String HOOKS_API_USAGE = """
2678 // The code supports the following hooks: 2738 // The code supports the following hooks:
2679 // dartPrint(message) - if this function is defined it is called 2739 // dartPrint(message) - if this function is defined it is called
2680 // instead of the Dart [print] method. 2740 // instead of the Dart [print] method.
2681 // dartMainRunner(main) - if this function is defined, the Dart [main] 2741 // dartMainRunner(main) - if this function is defined, the Dart [main]
2682 // method will not be invoked directly. 2742 // method will not be invoked directly.
2683 // Instead, a closure that will invoke [main] is 2743 // Instead, a closure that will invoke [main] is
2684 // passed to [dartMainRunner]. 2744 // passed to [dartMainRunner].
2685 """; 2745 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698