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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 87 | 87 |
| 88 /** | 88 /** |
| 89 * Raw ClassElement symbols occuring in is-checks and type assertions. If the | 89 * Raw ClassElement symbols occuring in is-checks and type assertions. If the |
| 90 * program contains parameterized checks `x is Set<int>` and | 90 * program contains parameterized checks `x is Set<int>` and |
| 91 * `x is Set<String>` then the ClassElement `Set` will occur once in | 91 * `x is Set<String>` then the ClassElement `Set` will occur once in |
| 92 * [checkedClasses]. | 92 * [checkedClasses]. |
| 93 */ | 93 */ |
| 94 Set<ClassElement> checkedClasses; | 94 Set<ClassElement> checkedClasses; |
| 95 | 95 |
| 96 /** | 96 /** |
| 97 * Set of JS native classes (or 'Object') that need a [:$nativeCheck:] method, | |
| 98 * because they could be used as a type argument in an is-check. | |
| 99 * | |
| 100 * For example, in the following program, the class int needs a native check | |
| 101 * to correctly match integers in the is-check: | |
| 102 * class Check<T> { foo(o) => o is T; } | |
| 103 * main() => new Check<int>().foo(3); | |
| 104 */ | |
| 105 Set<ClassElement> requiredNativeChecks; | |
| 106 | |
| 107 /** | |
| 97 * Raw Typedef symbols occuring in is-checks and type assertions. If the | 108 * Raw Typedef symbols occuring in is-checks and type assertions. If the |
| 98 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement | 109 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement |
| 99 * `F` will occur once in [checkedTypedefs]. | 110 * `F` will occur once in [checkedTypedefs]. |
| 100 */ | 111 */ |
| 101 Set<TypedefElement> checkedTypedefs; | 112 Set<TypedefElement> checkedTypedefs; |
| 102 | 113 |
| 103 final bool generateSourceMap; | 114 final bool generateSourceMap; |
| 104 | 115 |
| 105 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap) | 116 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap) |
| 106 : boundClosureBuffer = new CodeBuffer(), | 117 : boundClosureBuffer = new CodeBuffer(), |
| 107 mainBuffer = new CodeBuffer(), | 118 mainBuffer = new CodeBuffer(), |
| 108 this.namer = namer, | 119 this.namer = namer, |
| 109 boundClosureCache = new Map<int, String>(), | 120 boundClosureCache = new Map<int, String>(), |
| 110 interceptorClosureCache = new Map<int, String>(), | 121 interceptorClosureCache = new Map<int, String>(), |
| 111 constantEmitter = new ConstantEmitter(compiler, namer), | 122 constantEmitter = new ConstantEmitter(compiler, namer), |
| 112 super(compiler) { | 123 super(compiler) { |
| 113 nativeEmitter = new NativeEmitter(this); | 124 nativeEmitter = new NativeEmitter(this); |
| 114 } | 125 } |
| 115 | 126 |
| 116 void computeRequiredTypeChecks() { | 127 void computeRequiredTypeChecks() { |
| 117 assert(checkedClasses == null); | 128 assert(checkedClasses == null && |
| 129 checkedTypedefs == null && | |
| 130 requiredNativeChecks == null); | |
| 131 | |
| 132 // Compute type arguments of classes that potentially use their type | |
| 133 // variables in is-checks and compute the (small) set of classes that | |
| 134 // need native check methods (consult the documentation of | |
| 135 // [requiredNativeChecks] for more information). | |
| 136 requiredNativeChecks = new Set<ClassElement>(); | |
| 137 Link<ClassElement> classes = compiler.world.classesUsingTypeVariableTests; | |
| 138 if (!classes.isEmpty) { | |
| 139 // Find all instantiated types that are a supertype of a class that uses | |
|
ngeoffray
2013/02/18 09:27:58
supertype -> subtype?
karlklose
2013/02/18 16:02:01
Done.
| |
| 140 // one of its type arguments in an is-check and add the arguments to the | |
| 141 // set of is-checks. | |
| 142 for (DartType type in compiler.codegenWorld.instantiatedTypes) { | |
| 143 if (type.kind != TypeKind.INTERFACE) continue; | |
| 144 InterfaceType classType = type; | |
| 145 for (classes = compiler.world.classesUsingTypeVariableTests; | |
|
ngeoffray
2013/02/18 09:27:58
Shouldn't that be in codegenWorld as well?
karlklose
2013/02/18 16:02:01
This is in the shared world. I am not sure it is w
ngeoffray
2013/02/19 09:00:41
Why not? The codegen world will have less or equal
karlklose
2013/02/19 12:39:28
Moved to the backend.
| |
| 146 !classes.isEmpty; | |
| 147 classes = classes.tail) { | |
| 148 // We need the type as instance of its superclass anyway, so we just | |
| 149 // try to compute the substitution; if the result is [:null:], the | |
| 150 // classes are not related. | |
| 151 InterfaceType instance = classType.asInstanceOf(classes.head); | |
| 152 if (instance == null) continue; | |
| 153 Link<DartType> typeArguments = instance.typeArguments; | |
| 154 for (DartType argument in typeArguments) { | |
| 155 Element element = argument.element; | |
| 156 JavaScriptBackend backend = compiler.backend; | |
| 157 if (backend.rti.needsNativeCheck(element)) { | |
| 158 requiredNativeChecks.add(element); | |
| 159 } | |
| 160 compiler.codegenWorld.isChecks.add(argument); | |
| 161 } | |
| 162 } | |
| 163 } | |
| 164 } | |
| 165 | |
| 118 checkedClasses = new Set<ClassElement>(); | 166 checkedClasses = new Set<ClassElement>(); |
| 119 checkedTypedefs = new Set<TypedefElement>(); | 167 checkedTypedefs = new Set<TypedefElement>(); |
| 120 compiler.codegenWorld.isChecks.forEach((DartType t) { | 168 compiler.codegenWorld.isChecks.forEach((DartType t) { |
| 121 if (t is InterfaceType) { | 169 if (t is InterfaceType) { |
| 122 checkedClasses.add(t.element); | 170 checkedClasses.add(t.element); |
| 123 } else if (t is TypedefType) { | 171 } else if (t is TypedefType) { |
| 124 checkedTypedefs.add(t.element); | 172 checkedTypedefs.add(t.element); |
| 125 } | 173 } |
| 126 }); | 174 }); |
| 127 } | 175 } |
| (...skipping 654 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 782 includeSuperMembers: false); | 830 includeSuperMembers: false); |
| 783 }); | 831 }); |
| 784 | 832 |
| 785 classElement.implementation.forEachMember( | 833 classElement.implementation.forEachMember( |
| 786 visitMember, | 834 visitMember, |
| 787 includeBackendMembers: true, | 835 includeBackendMembers: true, |
| 788 includeSuperMembers: false); | 836 includeSuperMembers: false); |
| 789 | 837 |
| 790 void generateIsTest(Element other) { | 838 void generateIsTest(Element other) { |
| 791 js.Expression code; | 839 js.Expression code; |
| 792 if (compiler.objectClass == other) return; | 840 if (other == compiler.objectClass && classElement != other) return; |
|
ngeoffray
2013/02/18 09:27:58
Why this change? It looks like you're getting rid
karlklose
2013/02/18 16:02:01
We may need the $isObject flag on objects now, whe
ngeoffray
2013/02/19 09:00:41
So why did you remove it in the new version of the
| |
| 793 if (nativeEmitter.requiresNativeIsCheck(other)) { | 841 if (nativeEmitter.requiresNativeIsCheck(other)) { |
| 794 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); | 842 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); |
| 795 } else { | 843 } else { |
| 796 code = new js.LiteralBool(true); | 844 code = new js.LiteralBool(true); |
| 797 } | 845 } |
| 798 builder.addProperty(namer.operatorIs(other), code); | 846 builder.addProperty(namer.operatorIs(other), code); |
| 799 } | 847 } |
| 800 | 848 |
| 801 void generateSubstitution(Element other, {bool emitNull: false}) { | 849 void generateSubstitution(Element other, {bool emitNull: false}) { |
| 802 RuntimeTypeInformation rti = backend.rti; | 850 RuntimeTypeInformation rti = backend.rti; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 844 String name = backend.namer.publicInstanceMethodNameByArity( | 892 String name = backend.namer.publicInstanceMethodNameByArity( |
| 845 const SourceString('=='), 1); | 893 const SourceString('=='), 1); |
| 846 Function kind = (classElement == backend.jsNullClass) | 894 Function kind = (classElement == backend.jsNullClass) |
| 847 ? js.equals | 895 ? js.equals |
| 848 : js.strictEquals; | 896 : js.strictEquals; |
| 849 builder.addProperty(name, js.fun(['receiver', 'a'], | 897 builder.addProperty(name, js.fun(['receiver', 'a'], |
| 850 js.block1(js.return_(kind(js.use('receiver'), js.use('a')))))); | 898 js.block1(js.return_(kind(js.use('receiver'), js.use('a')))))); |
| 851 } | 899 } |
| 852 } | 900 } |
| 853 | 901 |
| 854 void emitRuntimeClassesAndTests(CodeBuffer buffer) { | 902 void emitRuntimeClassesAndTests(CodeBuffer buffer) { |
|
ngeoffray
2013/02/18 09:27:58
should that be called emitRuntimeTypesAndTests? Wh
karlklose
2013/02/18 16:02:01
Initially I called the holder object runtime-class
ngeoffray
2013/02/19 09:00:41
+1
| |
| 855 JavaScriptBackend backend = compiler.backend; | 903 JavaScriptBackend backend = compiler.backend; |
| 856 RuntimeTypeInformation rti = backend.rti; | 904 RuntimeTypeInformation rti = backend.rti; |
| 857 TypeChecks typeChecks = rti.getRequiredChecks(); | 905 TypeChecks typeChecks = rti.getRequiredChecks(); |
| 858 | 906 |
| 859 bool needsHolder(ClassElement cls) { | 907 bool needsHolder(ClassElement cls) { |
| 860 return !neededClasses.contains(cls) || cls.isNative() || | 908 return !neededClasses.contains(cls) || cls.isNative() || |
| 861 rti.isJsNative(cls); | 909 rti.isJsNative(cls); |
| 862 } | 910 } |
| 863 | 911 |
| 864 /** | 912 /** |
| 865 * Generates a holder object if it is needed. A holder is a JavaScript | 913 * Generates a holder object if it is needed. A holder is a JavaScript |
| 866 * object literal with a field [builtin$cls] that contains the name of the | 914 * object literal with a field [builtin$cls] that contains the name of the |
| 867 * class as a string (just like object constructors do). The is-checks for | 915 * class as a string (just like object constructors do). The is-checks for |
| 868 * the class are are added to the holder object later. | 916 * the class are are added to the holder object later. |
| 869 */ | 917 */ |
| 870 void maybeGenerateHolder(ClassElement cls) { | 918 void maybeGenerateHolder(ClassElement cls) { |
| 871 if (!needsHolder(cls)) return; | 919 if (!needsHolder(cls)) return; |
| 872 String holder = namer.isolateAccess(cls); | 920 String holder = namer.isolateAccess(cls); |
| 873 String name = namer.getName(cls); | 921 String name = namer.getName(cls); |
| 874 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); | 922 buffer.add("$holder$_=$_{builtin\$cls:$_'$name'}$N"); |
| 875 buffer.add('}$N'); | |
| 876 } | 923 } |
| 877 | 924 |
| 878 // Create representation objects for classes that we do not have a class | 925 // Create representation objects for classes that we do not have a class |
| 879 // definition for (because they are uninstantiated or native). | 926 // definition for (because they are uninstantiated or native). |
| 880 for (ClassElement cls in rti.allArguments) { | 927 for (ClassElement cls in rti.allArguments) { |
| 881 maybeGenerateHolder(cls); | 928 maybeGenerateHolder(cls); |
| 882 } | 929 } |
| 883 | 930 |
| 884 // Add checks to the constructors of instantiated classes or to the created | 931 // Add checks to the constructors of instantiated classes or to the created |
| 885 // holder object. | 932 // holder object. |
| 886 for (ClassElement cls in typeChecks) { | 933 for (ClassElement cls in typeChecks) { |
| 887 String holder = namer.isolateAccess(cls); | 934 String holder = namer.isolateAccess(cls); |
| 888 for (ClassElement check in typeChecks[cls]) { | 935 for (ClassElement check in typeChecks[cls]) { |
| 889 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); | 936 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); |
| 890 String body = rti.getSupertypeSubstitution(cls, check); | 937 String body = rti.getSupertypeSubstitution(cls, check); |
| 891 if (body != null) { | 938 if (body != null) { |
| 892 buffer.add('$holder.${namer.substitutionName(check)}$_=${_}$body$N'); | 939 buffer.add('$holder.${namer.substitutionName(check)}$_=${_}$body$N'); |
| 893 } | 940 } |
| 894 }; | 941 }; |
| 895 } | 942 } |
| 943 | |
| 944 // Emit native check methods for the class representations of native types | |
| 945 // that could be used in an is-check against a type variable. | |
| 946 requiredNativeChecks.forEach((ClassElement cls) { | |
| 947 js.Expression nativeCheck = rti.getNativeCheck(cls); | |
| 948 String holder = namer.isolateAccess(cls); | |
| 949 buffer.add('$holder.${rti.getNativeCheckName()}$_=$_'); | |
| 950 buffer.addBuffer(js.prettyPrint(nativeCheck, compiler)); | |
| 951 buffer.add('$N'); | |
| 952 }); | |
| 896 } | 953 } |
| 897 | 954 |
| 898 void visitNativeMixins(ClassElement classElement, | 955 void visitNativeMixins(ClassElement classElement, |
| 899 void visit(MixinApplicationElement mixinApplication)) { | 956 void visit(MixinApplicationElement mixinApplication)) { |
| 900 if (!classElement.isNative()) return; | 957 if (!classElement.isNative()) return; |
| 901 // Use recursion to make sure to visit the superclasses before the | 958 // Use recursion to make sure to visit the superclasses before the |
| 902 // subclasses. Once we start keeping track of the emitted fields | 959 // subclasses. Once we start keeping track of the emitted fields |
| 903 // and members, we're going to want to visit these in the other | 960 // and members, we're going to want to visit these in the other |
| 904 // order so we get the most specialized definition first. | 961 // order so we get the most specialized definition first. |
| 905 void recurse(ClassElement cls) { | 962 void recurse(ClassElement cls) { |
| (...skipping 1529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2435 """; | 2492 """; |
| 2436 const String HOOKS_API_USAGE = """ | 2493 const String HOOKS_API_USAGE = """ |
| 2437 // The code supports the following hooks: | 2494 // The code supports the following hooks: |
| 2438 // dartPrint(message) - if this function is defined it is called | 2495 // dartPrint(message) - if this function is defined it is called |
| 2439 // instead of the Dart [print] method. | 2496 // instead of the Dart [print] method. |
| 2440 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2497 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 2441 // method will not be invoked directly. | 2498 // method will not be invoked directly. |
| 2442 // Instead, a closure that will invoke [main] is | 2499 // Instead, a closure that will invoke [main] is |
| 2443 // passed to [dartMainRunner]. | 2500 // passed to [dartMainRunner]. |
| 2444 """; | 2501 """; |
| OLD | NEW |