Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 """; |
| OLD | NEW |