OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token; | |
6 import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN; | |
7 | |
8 import '../common.dart'; | 5 import '../common.dart'; |
9 import '../common/backend_api.dart'; | 6 import '../common/backend_api.dart'; |
10 import '../common/resolution.dart' show Resolution; | 7 import '../common/resolution.dart' show Resolution; |
11 import '../compiler.dart' show Compiler; | 8 import '../compiler.dart' show Compiler; |
12 import '../common_elements.dart' show CommonElements; | 9 import '../common_elements.dart' show CommonElements; |
13 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
14 import '../elements/entities.dart'; | 11 import '../elements/entities.dart'; |
15 import '../elements/resolution_types.dart'; | 12 import '../elements/resolution_types.dart'; |
16 import '../elements/types.dart'; | 13 import '../elements/types.dart'; |
17 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 14 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
18 import '../js_backend/backend_usage.dart' show BackendUsageBuilder; | 15 import '../js_backend/backend_usage.dart' show BackendUsageBuilder; |
19 import '../js_backend/js_backend.dart'; | 16 import '../js_backend/js_backend.dart'; |
20 import '../js_backend/native_data.dart' show NativeBasicData, NativeData; | 17 import '../js_backend/native_data.dart' show NativeBasicData, NativeData; |
21 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; | 18 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; |
22 import '../universe/use.dart' show StaticUse, TypeUse; | 19 import '../universe/use.dart' show StaticUse, TypeUse; |
23 import '../universe/world_impact.dart' | 20 import '../universe/world_impact.dart' |
24 show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl; | 21 show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl; |
25 import 'behavior.dart'; | 22 import 'behavior.dart'; |
| 23 import 'resolver.dart' show NativeClassResolver; |
26 | 24 |
27 /** | 25 /** |
28 * This could be an abstract class but we use it as a stub for the dart_backend. | 26 * This could be an abstract class but we use it as a stub for the dart_backend. |
29 */ | 27 */ |
30 class NativeEnqueuer { | 28 class NativeEnqueuer { |
31 /// Called when a [type] has been instantiated natively. | 29 /// Called when a [type] has been instantiated natively. |
32 void onInstantiatedType(InterfaceType type) {} | 30 void onInstantiatedType(InterfaceType type) {} |
33 | 31 |
34 /// Initial entry point to native enqueuer. | 32 /// Initial entry point to native enqueuer. |
35 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) => | 33 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) => |
(...skipping 23 matching lines...) Expand all Loading... |
59 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. | 57 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. |
60 NativeEnqueuerBase(this._compiler, this.enableLiveTypeAnalysis); | 58 NativeEnqueuerBase(this._compiler, this.enableLiveTypeAnalysis); |
61 | 59 |
62 JavaScriptBackend get _backend => _compiler.backend; | 60 JavaScriptBackend get _backend => _compiler.backend; |
63 BackendHelpers get _helpers => _backend.helpers; | 61 BackendHelpers get _helpers => _backend.helpers; |
64 Resolution get _resolution => _compiler.resolution; | 62 Resolution get _resolution => _compiler.resolution; |
65 | 63 |
66 DiagnosticReporter get _reporter => _compiler.reporter; | 64 DiagnosticReporter get _reporter => _compiler.reporter; |
67 CommonElements get _commonElements => _compiler.commonElements; | 65 CommonElements get _commonElements => _compiler.commonElements; |
68 | 66 |
69 NativeBasicData get _nativeBasicData => _backend.nativeBasicData; | |
70 | |
71 BackendClasses get _backendClasses => _backend.backendClasses; | 67 BackendClasses get _backendClasses => _backend.backendClasses; |
72 | 68 |
73 void onInstantiatedType(InterfaceType type) { | 69 void onInstantiatedType(InterfaceType type) { |
74 if (_unusedClasses.remove(type.element)) { | 70 if (_unusedClasses.remove(type.element)) { |
75 _registeredClasses.add(type.element); | 71 _registeredClasses.add(type.element); |
76 } | 72 } |
77 } | 73 } |
78 | 74 |
79 /// Register [classes] as natively instantiated in [impactBuilder]. | 75 /// Register [classes] as natively instantiated in [impactBuilder]. |
80 void _registerTypeUses( | 76 void _registerTypeUses( |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 // TODO(sra): Annotate exception classes in dart:html. | 176 // TODO(sra): Annotate exception classes in dart:html. |
181 String name = classElement.name; | 177 String name = classElement.name; |
182 if (name.contains('Exception')) return true; | 178 if (name.contains('Exception')) return true; |
183 if (name.contains('Error')) return true; | 179 if (name.contains('Error')) return true; |
184 return false; | 180 return false; |
185 }); | 181 }); |
186 } | 182 } |
187 } | 183 } |
188 | 184 |
189 class NativeResolutionEnqueuer extends NativeEnqueuerBase { | 185 class NativeResolutionEnqueuer extends NativeEnqueuerBase { |
| 186 final NativeClassResolver _nativeClassResolver; |
| 187 |
190 /// The set of all native classes. Each native class is in [nativeClasses] | 188 /// The set of all native classes. Each native class is in [nativeClasses] |
191 /// and exactly one of [unusedClasses] and [registeredClasses]. | 189 /// and exactly one of [unusedClasses] and [registeredClasses]. |
192 final Set<ClassElement> _nativeClasses = new Set<ClassElement>(); | 190 final Set<ClassElement> _nativeClasses = new Set<ClassElement>(); |
193 | 191 |
194 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); | 192 NativeResolutionEnqueuer(Compiler compiler, this._nativeClassResolver) |
195 | |
196 NativeResolutionEnqueuer(Compiler compiler) | |
197 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); | 193 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); |
198 | 194 |
199 BackendUsageBuilder get _backendUsageBuilder => _backend.backendUsageBuilder; | 195 BackendUsageBuilder get _backendUsageBuilder => _backend.backendUsageBuilder; |
200 | 196 |
201 void _registerBackendUse(FunctionEntity element) { | 197 void _registerBackendUse(FunctionEntity element) { |
202 _backendUsageBuilder.registerBackendFunctionUse(element); | 198 _backendUsageBuilder.registerBackendFunctionUse(element); |
203 _backendUsageBuilder.registerGlobalFunctionDependency(element); | 199 _backendUsageBuilder.registerGlobalFunctionDependency(element); |
204 } | 200 } |
205 | 201 |
206 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { | 202 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { |
207 WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); | 203 WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); |
208 Set<ClassElement> nativeClasses = new Set<ClassElement>(); | 204 Set<ClassElement> nativeClasses = |
209 libraries.forEach((l) => _processNativeClassesInLibrary(l, nativeClasses)); | 205 _nativeClassResolver.computeNativeClasses(libraries); |
210 if (_helpers.isolateHelperLibrary != null) { | |
211 _processNativeClassesInLibrary( | |
212 _helpers.isolateHelperLibrary, nativeClasses); | |
213 } | |
214 _processSubclassesOfNativeClasses(libraries, nativeClasses); | |
215 _nativeClasses.addAll(nativeClasses); | 206 _nativeClasses.addAll(nativeClasses); |
216 _unusedClasses.addAll(nativeClasses); | 207 _unusedClasses.addAll(nativeClasses); |
217 if (!enableLiveTypeAnalysis) { | 208 if (!enableLiveTypeAnalysis) { |
218 _registerTypeUses(impactBuilder, _nativeClasses, 'forced'); | 209 _registerTypeUses(impactBuilder, _nativeClasses, 'forced'); |
219 } | 210 } |
220 return impactBuilder; | 211 return impactBuilder; |
221 } | 212 } |
222 | 213 |
223 void _processNativeClassesInLibrary( | |
224 LibraryElement library, Set<ClassElement> nativeClasses) { | |
225 // Use implementation to ensure the inclusion of injected members. | |
226 library.implementation.forEachLocalMember((Element element) { | |
227 if (element.isClass) { | |
228 ClassElement cls = element; | |
229 if (_nativeBasicData.isNativeClass(cls)) { | |
230 _processNativeClass(element, nativeClasses); | |
231 } | |
232 } | |
233 }); | |
234 } | |
235 | |
236 void _processNativeClass( | |
237 ClassElement classElement, Set<ClassElement> nativeClasses) { | |
238 nativeClasses.add(classElement); | |
239 // Resolve class to ensure the class has valid inheritance info. | |
240 classElement.ensureResolved(_resolution); | |
241 // Js Interop interfaces do not have tags. | |
242 if (_nativeBasicData.isJsInteropClass(classElement)) return; | |
243 // Since we map from dispatch tags to classes, a dispatch tag must be used | |
244 // on only one native class. | |
245 for (String tag in _nativeBasicData.getNativeTagsOfClass(classElement)) { | |
246 ClassElement owner = tagOwner[tag]; | |
247 if (owner != null) { | |
248 if (owner != classElement) { | |
249 _reporter.internalError( | |
250 classElement, "Tag '$tag' already in use by '${owner.name}'"); | |
251 } | |
252 } else { | |
253 tagOwner[tag] = classElement; | |
254 } | |
255 } | |
256 } | |
257 | |
258 void _processSubclassesOfNativeClasses( | |
259 Iterable<LibraryElement> libraries, Set<ClassElement> nativeClasses) { | |
260 Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>(); | |
261 // Collect potential subclasses, e.g. | |
262 // | |
263 // class B extends foo.A {} | |
264 // | |
265 // String "A" has a potential subclass B. | |
266 | |
267 var potentialExtends = new Map<String, Set<ClassElement>>(); | |
268 | |
269 libraries.forEach((library) { | |
270 library.implementation.forEachLocalMember((element) { | |
271 if (element.isClass) { | |
272 String extendsName = _findExtendsNameOfClass(element); | |
273 if (extendsName != null) { | |
274 Set<ClassElement> potentialSubclasses = potentialExtends | |
275 .putIfAbsent(extendsName, () => new Set<ClassElement>()); | |
276 potentialSubclasses.add(element); | |
277 } | |
278 } | |
279 }); | |
280 }); | |
281 | |
282 // Resolve all the native classes and any classes that might extend them in | |
283 // [potentialExtends], and then check that the properly resolved class is in | |
284 // fact a subclass of a native class. | |
285 | |
286 ClassElement nativeSuperclassOf(ClassElement classElement) { | |
287 if (_nativeBasicData.isNativeClass(classElement)) return classElement; | |
288 if (classElement.superclass == null) return null; | |
289 return nativeSuperclassOf(classElement.superclass); | |
290 } | |
291 | |
292 void walkPotentialSubclasses(ClassElement element) { | |
293 if (nativeClassesAndSubclasses.contains(element)) return; | |
294 element.ensureResolved(_resolution); | |
295 ClassElement nativeSuperclass = nativeSuperclassOf(element); | |
296 if (nativeSuperclass != null) { | |
297 nativeClassesAndSubclasses.add(element); | |
298 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; | |
299 if (potentialSubclasses != null) { | |
300 potentialSubclasses.forEach(walkPotentialSubclasses); | |
301 } | |
302 } | |
303 } | |
304 | |
305 nativeClasses.forEach(walkPotentialSubclasses); | |
306 nativeClasses.addAll(nativeClassesAndSubclasses); | |
307 } | |
308 | |
309 /** | |
310 * Returns the source string of the class named in the extends clause, or | |
311 * `null` if there is no extends clause. | |
312 */ | |
313 String _findExtendsNameOfClass(ClassElement classElement) { | |
314 if (classElement.isResolved) { | |
315 ClassElement superClass = classElement.superclass; | |
316 while (superClass != null) { | |
317 if (!superClass.isUnnamedMixinApplication) { | |
318 return superClass.name; | |
319 } | |
320 superClass = superClass.superclass; | |
321 } | |
322 return null; | |
323 } | |
324 | |
325 // "class B extends A ... {}" --> "A" | |
326 // "class B extends foo.A ... {}" --> "A" | |
327 // "class B<T> extends foo.A<T,T> with M1, M2 ... {}" --> "A" | |
328 | |
329 // We want to avoid calling classElement.parseNode on every class. Doing so | |
330 // will slightly increase parse time and size and cause compiler errors and | |
331 // warnings to me emitted in more unused code. | |
332 | |
333 // An alternative to this code is to extend the API of ClassElement to | |
334 // expose the name of the extended element. | |
335 | |
336 // Pattern match the above cases in the token stream. | |
337 // [abstract] class X extends [id.]* id | |
338 | |
339 Token skipTypeParameters(Token token) { | |
340 BeginGroupToken beginGroupToken = token; | |
341 Token endToken = beginGroupToken.endGroup; | |
342 return endToken.next; | |
343 //for (;;) { | |
344 // token = token.next; | |
345 // if (token.stringValue == '>') return token.next; | |
346 // if (token.stringValue == '<') return skipTypeParameters(token); | |
347 //} | |
348 } | |
349 | |
350 String scanForExtendsName(Token token) { | |
351 if (token.stringValue == 'abstract') token = token.next; | |
352 if (token.stringValue != 'class') return null; | |
353 token = token.next; | |
354 if (!token.isIdentifier()) return null; | |
355 token = token.next; | |
356 // class F<X extends B<X>> extends ... | |
357 if (token.stringValue == '<') { | |
358 token = skipTypeParameters(token); | |
359 } | |
360 if (token.stringValue != 'extends') return null; | |
361 token = token.next; | |
362 Token id = token; | |
363 while (token.kind != Tokens.EOF_TOKEN) { | |
364 token = token.next; | |
365 if (token.stringValue != '.') break; | |
366 token = token.next; | |
367 if (!token.isIdentifier()) return null; | |
368 id = token; | |
369 } | |
370 // Should be at '{', 'with', 'implements', '<' or 'native'. | |
371 return id.lexeme; | |
372 } | |
373 | |
374 return _reporter.withCurrentElement(classElement, () { | |
375 return scanForExtendsName(classElement.position); | |
376 }); | |
377 } | |
378 | |
379 void logSummary(log(message)) { | 214 void logSummary(log(message)) { |
380 log('Resolved ${_registeredClasses.length} native elements used, ' | 215 log('Resolved ${_registeredClasses.length} native elements used, ' |
381 '${_unusedClasses.length} native elements dead.'); | 216 '${_unusedClasses.length} native elements dead.'); |
382 } | 217 } |
383 } | 218 } |
384 | 219 |
385 class NativeCodegenEnqueuer extends NativeEnqueuerBase { | 220 class NativeCodegenEnqueuer extends NativeEnqueuerBase { |
386 final CodeEmitterTask emitter; | 221 final CodeEmitterTask _emitter; |
387 | 222 |
388 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); | 223 final Set<ClassElement> _doneAddSubtypes = new Set<ClassElement>(); |
389 | 224 |
390 final NativeResolutionEnqueuer _resolutionEnqueuer; | 225 final NativeResolutionEnqueuer _resolutionEnqueuer; |
391 | 226 |
392 NativeCodegenEnqueuer( | 227 NativeCodegenEnqueuer( |
393 Compiler compiler, this.emitter, this._resolutionEnqueuer) | 228 Compiler compiler, this._emitter, this._resolutionEnqueuer) |
394 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis) {} | 229 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis) {} |
395 | 230 |
396 NativeData get _nativeData => _backend.nativeData; | 231 NativeData get _nativeData => _backend.nativeData; |
397 | 232 |
398 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { | 233 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { |
399 WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); | 234 WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); |
400 _unusedClasses.addAll(_resolutionEnqueuer._nativeClasses); | 235 _unusedClasses.addAll(_resolutionEnqueuer._nativeClasses); |
401 | 236 |
402 if (!enableLiveTypeAnalysis) { | 237 if (!enableLiveTypeAnalysis) { |
403 _registerTypeUses( | 238 _registerTypeUses( |
(...skipping 14 matching lines...) Expand all Loading... |
418 return impactBuilder; | 253 return impactBuilder; |
419 } | 254 } |
420 | 255 |
421 void _registerTypeUses( | 256 void _registerTypeUses( |
422 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) { | 257 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) { |
423 super._registerTypeUses(impactBuilder, classes, cause); | 258 super._registerTypeUses(impactBuilder, classes, cause); |
424 | 259 |
425 for (ClassElement classElement in classes) { | 260 for (ClassElement classElement in classes) { |
426 // Add the information that this class is a subtype of its supertypes. The | 261 // Add the information that this class is a subtype of its supertypes. The |
427 // code emitter and the ssa builder use that information. | 262 // code emitter and the ssa builder use that information. |
428 _addSubtypes(classElement, emitter.nativeEmitter); | 263 _addSubtypes(classElement, _emitter.nativeEmitter); |
429 } | 264 } |
430 } | 265 } |
431 | 266 |
432 void _addSubtypes(ClassElement cls, NativeEmitter emitter) { | 267 void _addSubtypes(ClassElement cls, NativeEmitter emitter) { |
433 if (!_nativeData.isNativeClass(cls)) return; | 268 if (!_nativeData.isNativeClass(cls)) return; |
434 if (doneAddSubtypes.contains(cls)) return; | 269 if (_doneAddSubtypes.contains(cls)) return; |
435 doneAddSubtypes.add(cls); | 270 _doneAddSubtypes.add(cls); |
436 | 271 |
437 // Walk the superclass chain since classes on the superclass chain might not | 272 // Walk the superclass chain since classes on the superclass chain might not |
438 // be instantiated (abstract or simply unused). | 273 // be instantiated (abstract or simply unused). |
439 _addSubtypes(cls.superclass, emitter); | 274 _addSubtypes(cls.superclass, emitter); |
440 | 275 |
441 for (ResolutionInterfaceType type in cls.allSupertypes) { | 276 for (ResolutionInterfaceType type in cls.allSupertypes) { |
442 List<ClassEntity> subtypes = | 277 List<ClassEntity> subtypes = |
443 emitter.subtypes.putIfAbsent(type.element, () => <ClassEntity>[]); | 278 emitter.subtypes.putIfAbsent(type.element, () => <ClassEntity>[]); |
444 subtypes.add(cls); | 279 subtypes.add(cls); |
445 } | 280 } |
(...skipping 10 matching lines...) Expand all Loading... |
456 List<ClassEntity> directSubtypes = | 291 List<ClassEntity> directSubtypes = |
457 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassEntity>[]); | 292 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassEntity>[]); |
458 directSubtypes.add(cls); | 293 directSubtypes.add(cls); |
459 } | 294 } |
460 | 295 |
461 void logSummary(log(message)) { | 296 void logSummary(log(message)) { |
462 log('Compiled ${_registeredClasses.length} native classes, ' | 297 log('Compiled ${_registeredClasses.length} native classes, ' |
463 '${_unusedClasses.length} native classes omitted.'); | 298 '${_unusedClasses.length} native classes omitted.'); |
464 } | 299 } |
465 } | 300 } |
OLD | NEW |