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 |