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

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: Restore comment. 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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698