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 library native; | 5 library native; |
6 | 6 |
7 import 'dart:collection' show Queue; | 7 import 'dart:collection' show Queue; |
8 import 'dart2jslib.dart' hide SourceString; | 8 import 'dart2jslib.dart' hide SourceString; |
9 import 'dart_types.dart'; | 9 import 'dart_types.dart'; |
10 import 'elements/elements.dart'; | 10 import 'elements/elements.dart'; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
79 * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses]. | 79 * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses]. |
80 */ | 80 */ |
81 final Set<ClassElement> nativeClasses = new Set<ClassElement>(); | 81 final Set<ClassElement> nativeClasses = new Set<ClassElement>(); |
82 | 82 |
83 final Set<ClassElement> registeredClasses = new Set<ClassElement>(); | 83 final Set<ClassElement> registeredClasses = new Set<ClassElement>(); |
84 final Set<ClassElement> pendingClasses = new Set<ClassElement>(); | 84 final Set<ClassElement> pendingClasses = new Set<ClassElement>(); |
85 final Set<ClassElement> unusedClasses = new Set<ClassElement>(); | 85 final Set<ClassElement> unusedClasses = new Set<ClassElement>(); |
86 | 86 |
87 bool hasInstantiatedNativeClasses() => !registeredClasses.isEmpty; | 87 bool hasInstantiatedNativeClasses() => !registeredClasses.isEmpty; |
88 | 88 |
89 final Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>(); | |
90 | |
91 final Map<ClassElement, Set<ClassElement>> nonNativeSubclasses = | |
92 new Map<ClassElement, Set<ClassElement>>(); | |
93 | |
89 /** | 94 /** |
90 * Records matched constraints ([SpecialType] or [DartType]). Once a type | 95 * Records matched constraints ([SpecialType] or [DartType]). Once a type |
91 * constraint has been matched, there is no need to match it again. | 96 * constraint has been matched, there is no need to match it again. |
92 */ | 97 */ |
93 final Set matchedTypeConstraints = new Set(); | 98 final Set matchedTypeConstraints = new Set(); |
94 | 99 |
95 /// Pending actions. Classes in [pendingClasses] have action thunks in | 100 /// Pending actions. Classes in [pendingClasses] have action thunks in |
96 /// [queue] to register the class. | 101 /// [queue] to register the class. |
97 final queue = new Queue(); | 102 final queue = new Queue(); |
98 bool flushing = false; | 103 bool flushing = false; |
99 | 104 |
100 /// Maps JS foreign calls to their computed native behavior. | 105 /// Maps JS foreign calls to their computed native behavior. |
101 final Map<Node, NativeBehavior> nativeBehaviors = | 106 final Map<Node, NativeBehavior> nativeBehaviors = |
102 new Map<Node, NativeBehavior>(); | 107 new Map<Node, NativeBehavior>(); |
103 | 108 |
104 final Enqueuer world; | 109 final Enqueuer world; |
105 final Compiler compiler; | 110 final Compiler compiler; |
106 final bool enableLiveTypeAnalysis; | 111 final bool enableLiveTypeAnalysis; |
107 | 112 |
108 ClassElement _annotationCreatesClass; | 113 ClassElement _annotationCreatesClass; |
109 ClassElement _annotationReturnsClass; | 114 ClassElement _annotationReturnsClass; |
110 ClassElement _annotationJsNameClass; | 115 ClassElement _annotationJsNameClass; |
111 | 116 |
112 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. | 117 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. |
113 NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis); | 118 NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis); |
114 | 119 |
115 void processNativeClasses(Iterable<LibraryElement> libraries) { | 120 void processNativeClasses(Iterable<LibraryElement> libraries) { |
116 libraries.forEach(processNativeClassesInLibrary); | 121 libraries.forEach(processNativeClassesInLibrary); |
117 processNativeClassesInLibrary(compiler.isolateHelperLibrary); | 122 processNativeClassesInLibrary(compiler.isolateHelperLibrary); |
123 | |
124 processSubclassesOfNativeClasses(libraries); | |
125 | |
118 if (!enableLiveTypeAnalysis) { | 126 if (!enableLiveTypeAnalysis) { |
119 nativeClasses.forEach((c) => enqueueClass(c, 'forced')); | 127 nativeClasses.forEach((c) => enqueueClass(c, 'forced')); |
120 flushQueue(); | 128 flushQueue(); |
121 } | 129 } |
122 } | 130 } |
123 | 131 |
124 void processNativeClassesInLibrary(LibraryElement library) { | 132 void processNativeClassesInLibrary(LibraryElement library) { |
125 // Use implementation to ensure the inclusion of injected members. | 133 // Use implementation to ensure the inclusion of injected members. |
126 library.implementation.forEachLocalMember((Element element) { | 134 library.implementation.forEachLocalMember((Element element) { |
127 if (element.isClass() && element.isNative()) { | 135 if (element.isClass() && element.isNative()) { |
128 processNativeClass(element); | 136 processNativeClass(element); |
129 } | 137 } |
130 }); | 138 }); |
131 } | 139 } |
132 | 140 |
133 void processNativeClass(ClassElement classElement) { | 141 void processNativeClass(ClassElement classElement) { |
134 nativeClasses.add(classElement); | 142 nativeClasses.add(classElement); |
135 unusedClasses.add(classElement); | 143 unusedClasses.add(classElement); |
136 // Resolve class to ensure the class has valid inheritance info. | 144 // Resolve class to ensure the class has valid inheritance info. |
137 classElement.ensureResolved(compiler); | 145 classElement.ensureResolved(compiler); |
138 } | 146 } |
139 | 147 |
148 void processSubclassesOfNativeClasses(Iterable<LibraryElement> libraries) { | |
149 // class B extends foo.A {} | |
ahe
2013/08/13 18:31:47
This comment is weird.
sra1
2013/08/14 04:36:47
Done.
| |
150 | |
151 var potentialExtends = new Map<SourceString, Set<ClassElement>>(); | |
152 | |
153 libraries.forEach((library) { | |
154 library.implementation.forEachLocalMember((element) { | |
155 if (element.isClass()) { | |
156 SourceString name = element.name; | |
157 SourceString extendsName = findExtendsNameOfClass(element); | |
158 if (extendsName != null) { | |
159 Set<ClassElement> potentialSubclasses = | |
160 potentialExtends.putIfAbsent( | |
161 extendsName, | |
162 () => new Set<ClassElement>()); | |
163 potentialSubclasses.add(element); | |
164 } | |
165 } | |
166 }); | |
167 }); | |
168 | |
169 ClassElement nativeSuperclassOf(ClassElement classElement) { | |
170 if (classElement.isNative()) return classElement; | |
171 if (classElement.superclass == null) return null; | |
172 return nativeSuperclassOf(classElement.superclass); | |
ahe
2013/08/13 18:31:47
How does this cope with cycles in the inheritance
sra1
2013/08/14 04:36:47
Called after resolving.
ahe
2013/08/14 10:52:47
Sorry, I forgot we had solved this problem.
| |
173 } | |
174 | |
175 void walkPotentialSubclasses(ClassElement element) { | |
176 if (nativeClassesAndSubclasses.contains(element)) return; | |
177 //print('Force resolve $element'); | |
ahe
2013/08/13 18:31:47
Remove comment.
sra1
2013/08/14 04:36:47
Done.
| |
178 element.ensureResolved(compiler); | |
179 ClassElement nativeSuperclass = nativeSuperclassOf(element); | |
180 if (nativeSuperclass != null) { | |
181 nativeClassesAndSubclasses.add(element); | |
182 if (!element.isNative()) { | |
183 nonNativeSubclasses.putIfAbsent(nativeSuperclass, | |
184 () => new Set<ClassElement>()) | |
185 .add(element); | |
186 } | |
187 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; | |
188 if (potentialSubclasses != null) { | |
189 potentialSubclasses.forEach(walkPotentialSubclasses); | |
190 } | |
191 } | |
192 } | |
193 | |
194 nativeClasses.forEach(walkPotentialSubclasses); | |
195 | |
196 // print(nativeClassesAndSubclasses); | |
197 | |
198 nativeClasses.addAll(nativeClassesAndSubclasses); | |
199 unusedClasses.addAll(nativeClassesAndSubclasses); | |
200 | |
201 // NEXT: make subclassed classes use different register function; add in a | |
ahe
2013/08/13 18:31:47
We normally use // TODO(username): ...
sra1
2013/08/14 04:36:47
Removed, since it is done.
| |
202 // hook that the DOM runtime can use. | |
203 } | |
204 | |
205 /** | |
206 * Returns the source string of the class named in the extends clause, or | |
207 * `null` if there is no extends clause. | |
208 */ | |
209 SourceString findExtendsNameOfClass(ClassElement classElement) { | |
ahe
2013/08/13 18:31:47
I'm concerned about this method, and I would reall
| |
210 // "class B extends A ... {}" --> "A" | |
211 // "class B extends foo.A ... {}" --> "A" | |
212 // "class B<T> extends foo.A<T,T> with M1, M2 ... {}" --> "A" | |
213 | |
214 // We want to avoid calling classElement.parseNode on every class. Doing so | |
215 // will slightly increase parse time and size and cause compiler errors and | |
216 // warnings to me emitted in more unused code. | |
217 | |
218 // An alternative to this code is to extend the API of ClassElement to | |
219 // expose the name of the extended element. | |
220 | |
221 // Pattern match the above cases in the token stream. | |
222 // [abstract] class X extends [id.]* id | |
223 | |
224 Token skipTypeParameters(Token token) { | |
ahe
2013/08/13 18:31:47
This should be:
BeginGroupToken beginGroupTok
| |
225 for (;;) { | |
226 token = token.next; | |
227 if (token.stringValue == '>') return token.next; | |
228 if (token.stringValue == '<') return skipTypeParameters(token); | |
229 } | |
230 } | |
231 | |
232 SourceString scanForExtendsName(Token token) { | |
233 if (token.stringValue == 'abstract') token = token.next; | |
ahe
2013/08/13 18:31:47
You need to use identical, not ==. Otherwise, you
sra1
2013/08/14 04:36:47
What guarantees they are the same instance of Stri
ahe
2013/08/14 10:52:47
That is guaranteed by the language specification (
| |
234 if (token.stringValue != 'class') return null; | |
ahe
2013/08/13 18:31:47
Ditto.
| |
235 token = token.next; | |
236 if (!token.isIdentifier()) return null; | |
237 token = token.next; | |
238 // class F<X extends B<X>> extends ... | |
239 if (token.stringValue == '<') { | |
ahe
2013/08/13 18:31:47
Ditto.
| |
240 token = skipTypeParameters(token); | |
241 } | |
242 if (token.stringValue != 'extends') return null; | |
ahe
2013/08/13 18:31:47
Ditto.
| |
243 token = token.next; | |
244 Token id = token; | |
245 for (;;) { | |
ahe
2013/08/13 18:31:47
As a general rule, infinite loops on user data is
sra1
2013/08/14 04:36:47
Done.
| |
246 token = token.next; | |
247 if (token.stringValue != '.') break; | |
ahe
2013/08/13 18:31:47
identical.
| |
248 token = token.next; | |
249 if (!token.isIdentifier()) return null; | |
250 id = token; | |
251 } | |
252 // Should be at '{', 'with', 'implements', '<' or 'native'. | |
253 return id.value; | |
254 } | |
255 | |
256 return compiler.withCurrentElement(classElement, () { | |
257 return scanForExtendsName(classElement.position()); | |
258 }); | |
259 } | |
260 | |
140 ClassElement get annotationCreatesClass { | 261 ClassElement get annotationCreatesClass { |
141 findAnnotationClasses(); | 262 findAnnotationClasses(); |
142 return _annotationCreatesClass; | 263 return _annotationCreatesClass; |
143 } | 264 } |
144 | 265 |
145 ClassElement get annotationReturnsClass { | 266 ClassElement get annotationReturnsClass { |
146 findAnnotationClasses(); | 267 findAnnotationClasses(); |
147 return _annotationReturnsClass; | 268 return _annotationReturnsClass; |
148 } | 269 } |
149 | 270 |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
378 staticUse(name) => world.registerStaticUse(compiler.findHelper(name)); | 499 staticUse(name) => world.registerStaticUse(compiler.findHelper(name)); |
379 | 500 |
380 staticUse(const SourceString('dynamicFunction')); | 501 staticUse(const SourceString('dynamicFunction')); |
381 staticUse(const SourceString('dynamicSetMetadata')); | 502 staticUse(const SourceString('dynamicSetMetadata')); |
382 staticUse(const SourceString('defineProperty')); | 503 staticUse(const SourceString('defineProperty')); |
383 staticUse(const SourceString('toStringForNativeObject')); | 504 staticUse(const SourceString('toStringForNativeObject')); |
384 staticUse(const SourceString('hashCodeForNativeObject')); | 505 staticUse(const SourceString('hashCodeForNativeObject')); |
385 staticUse(const SourceString('convertDartClosureToJS')); | 506 staticUse(const SourceString('convertDartClosureToJS')); |
386 staticUse(const SourceString('defineNativeMethods')); | 507 staticUse(const SourceString('defineNativeMethods')); |
387 staticUse(const SourceString('defineNativeMethodsNonleaf')); | 508 staticUse(const SourceString('defineNativeMethodsNonleaf')); |
509 staticUse(const SourceString('defineNativeMethodsExtended')); | |
388 // TODO(9577): Registering `defineNativeMethodsFinish` seems redundant with | 510 // TODO(9577): Registering `defineNativeMethodsFinish` seems redundant with |
389 // respect to the registering in the backend. When the backend registering | 511 // respect to the registering in the backend. When the backend registering |
390 // is removed as part of fixing Issue 9577, this can be the sole place | 512 // is removed as part of fixing Issue 9577, this can be the sole place |
391 // registering this methods. | 513 // registering this methods. |
392 staticUse(const SourceString('defineNativeMethodsFinish')); | 514 staticUse(const SourceString('defineNativeMethodsFinish')); |
393 | 515 |
394 addNativeExceptions(); | 516 addNativeExceptions(); |
395 } | 517 } |
396 | 518 |
397 addNativeExceptions() { | 519 addNativeExceptions() { |
(...skipping 618 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1016 'native "..." syntax is restricted to functions with zero parameters', | 1138 'native "..." syntax is restricted to functions with zero parameters', |
1017 node: nativeBody); | 1139 node: nativeBody); |
1018 } | 1140 } |
1019 LiteralString jsCode = nativeBody.asLiteralString(); | 1141 LiteralString jsCode = nativeBody.asLiteralString(); |
1020 builder.push(new HForeign.statement( | 1142 builder.push(new HForeign.statement( |
1021 new js.LiteralStatement(jsCode.dartString.slowToString()), | 1143 new js.LiteralStatement(jsCode.dartString.slowToString()), |
1022 <HInstruction>[], | 1144 <HInstruction>[], |
1023 new SideEffects())); | 1145 new SideEffects())); |
1024 } | 1146 } |
1025 } | 1147 } |
OLD | NEW |