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

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

Powered by Google App Engine
This is Rietveld 408576698