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 library deferred_load; | 5 library deferred_load; |
6 | 6 |
7 import 'common.dart'; | 7 import 'common.dart'; |
8 import 'common/backend_api.dart' show | 8 import 'common/backend_api.dart' show Backend; |
9 Backend; | 9 import 'common/tasks.dart' show CompilerTask; |
10 import 'common/tasks.dart' show | 10 import 'compiler.dart' show Compiler; |
11 CompilerTask; | 11 import 'constants/values.dart' |
12 import 'compiler.dart' show | 12 show |
13 Compiler; | 13 ConstantValue, |
14 import 'constants/values.dart' show | 14 ConstructedConstantValue, |
15 ConstantValue, | 15 DeferredConstantValue, |
16 ConstructedConstantValue, | 16 StringConstantValue; |
17 DeferredConstantValue, | |
18 StringConstantValue; | |
19 import 'dart_types.dart'; | 17 import 'dart_types.dart'; |
20 import 'elements/elements.dart' show | 18 import 'elements/elements.dart' |
21 AccessorElement, | 19 show |
22 AstElement, | 20 AccessorElement, |
23 ClassElement, | 21 AstElement, |
24 Element, | 22 ClassElement, |
25 ElementKind, | 23 Element, |
26 Elements, | 24 ElementKind, |
27 ExportElement, | 25 Elements, |
28 FunctionElement, | 26 ExportElement, |
29 ImportElement, | 27 FunctionElement, |
30 LibraryElement, | 28 ImportElement, |
31 LocalFunctionElement, | 29 LibraryElement, |
32 MetadataAnnotation, | 30 LocalFunctionElement, |
33 PrefixElement, | 31 MetadataAnnotation, |
34 ScopeContainerElement, | 32 PrefixElement, |
35 TypedefElement; | 33 ScopeContainerElement, |
36 import 'js_backend/js_backend.dart' show | 34 TypedefElement; |
37 JavaScriptBackend; | 35 import 'js_backend/js_backend.dart' show JavaScriptBackend; |
38 import 'resolution/resolution.dart' show | 36 import 'resolution/resolution.dart' show AnalyzableElementX; |
39 AnalyzableElementX; | 37 import 'resolution/tree_elements.dart' show TreeElements; |
40 import 'resolution/tree_elements.dart' show | |
41 TreeElements; | |
42 import 'tree/tree.dart' as ast; | 38 import 'tree/tree.dart' as ast; |
43 import 'tree/tree.dart' show | 39 import 'tree/tree.dart' |
44 Import, | 40 show |
45 LibraryTag, | 41 Import, |
46 LibraryDependency, | 42 LibraryTag, |
47 LiteralDartString, | 43 LibraryDependency, |
48 LiteralString, | 44 LiteralDartString, |
49 NewExpression, | 45 LiteralString, |
50 Node; | 46 NewExpression, |
51 import 'universe/use.dart' show | 47 Node; |
52 DynamicUse, | 48 import 'universe/use.dart' show DynamicUse, StaticUse, TypeUse, TypeUseKind; |
53 StaticUse, | 49 import 'universe/world_impact.dart' |
54 TypeUse, | 50 show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl; |
55 TypeUseKind; | 51 import 'util/setlet.dart' show Setlet; |
56 import 'universe/world_impact.dart' show | |
57 ImpactUseCase, | |
58 WorldImpact, | |
59 WorldImpactVisitorImpl; | |
60 import 'util/setlet.dart' show | |
61 Setlet; | |
62 import 'util/uri_extras.dart' as uri_extras; | 52 import 'util/uri_extras.dart' as uri_extras; |
63 import 'util/util.dart' show | 53 import 'util/util.dart' show Link, makeUnique; |
64 Link, makeUnique; | |
65 | 54 |
66 /// A "hunk" of the program that will be loaded whenever one of its [imports] | 55 /// A "hunk" of the program that will be loaded whenever one of its [imports] |
67 /// are loaded. | 56 /// are loaded. |
68 /// | 57 /// |
69 /// Elements that are only used in one deferred import, is in an OutputUnit with | 58 /// Elements that are only used in one deferred import, is in an OutputUnit with |
70 /// the deferred import as single element in the [imports] set. | 59 /// the deferred import as single element in the [imports] set. |
71 /// | 60 /// |
72 /// Whenever a deferred Element is shared between several deferred imports it is | 61 /// Whenever a deferred Element is shared between several deferred imports it is |
73 /// in an output unit with those imports in the [imports] Set. | 62 /// in an output unit with those imports in the [imports] Set. |
74 /// | 63 /// |
75 /// OutputUnits are equal if their [imports] are equal. | 64 /// OutputUnits are equal if their [imports] are equal. |
76 class OutputUnit { | 65 class OutputUnit { |
77 /// The deferred imports that will load this output unit when one of them is | 66 /// The deferred imports that will load this output unit when one of them is |
78 /// loaded. | 67 /// loaded. |
79 final Setlet<_DeferredImport> imports = new Setlet<_DeferredImport>(); | 68 final Setlet<_DeferredImport> imports = new Setlet<_DeferredImport>(); |
80 | 69 |
81 /// `true` if this output unit is for the main output file. | 70 /// `true` if this output unit is for the main output file. |
82 final bool isMainOutput; | 71 final bool isMainOutput; |
83 | 72 |
84 /// A unique name representing this [OutputUnit]. | 73 /// A unique name representing this [OutputUnit]. |
85 String name; | 74 String name; |
86 | 75 |
87 OutputUnit({this.isMainOutput: false}); | 76 OutputUnit({this.isMainOutput: false}); |
88 | 77 |
89 String toString() => "OutputUnit($name)"; | 78 String toString() => "OutputUnit($name)"; |
90 | 79 |
91 bool operator==(OutputUnit other) { | 80 bool operator ==(OutputUnit other) { |
92 return imports.length == other.imports.length && | 81 return imports.length == other.imports.length && |
93 imports.containsAll(other.imports); | 82 imports.containsAll(other.imports); |
94 } | 83 } |
95 | 84 |
96 int get hashCode { | 85 int get hashCode { |
97 int sum = 0; | 86 int sum = 0; |
98 for (_DeferredImport import in imports) { | 87 for (_DeferredImport import in imports) { |
99 sum = (sum + import.hashCode) & 0x3FFFFFFF; // Stay in 30 bit range. | 88 sum = (sum + import.hashCode) & 0x3FFFFFFF; // Stay in 30 bit range. |
100 } | 89 } |
101 return sum; | 90 return sum; |
102 } | 91 } |
103 } | 92 } |
104 | 93 |
105 /// For each deferred import, find elements and constants to be loaded when that | 94 /// For each deferred import, find elements and constants to be loaded when that |
106 /// import is loaded. Elements that are used by several deferred imports are in | 95 /// import is loaded. Elements that are used by several deferred imports are in |
107 /// shared OutputUnits. | 96 /// shared OutputUnits. |
108 class DeferredLoadTask extends CompilerTask { | 97 class DeferredLoadTask extends CompilerTask { |
109 /// The name of this task. | 98 /// The name of this task. |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 /// | 211 /// |
223 /// For example, if we have two deferred libraries `A` and `B` that both | 212 /// For example, if we have two deferred libraries `A` and `B` that both |
224 /// import a library `C`, then even though elements from `A` and `C` end up in | 213 /// import a library `C`, then even though elements from `A` and `C` end up in |
225 /// different output units, there is a non-deferred path between `A` and `C`. | 214 /// different output units, there is a non-deferred path between `A` and `C`. |
226 bool hasOnlyNonDeferredImportPaths(Element from, Element to) { | 215 bool hasOnlyNonDeferredImportPaths(Element from, Element to) { |
227 OutputUnit outputUnitFrom = outputUnitForElement(from); | 216 OutputUnit outputUnitFrom = outputUnitForElement(from); |
228 OutputUnit outputUnitTo = outputUnitForElement(to); | 217 OutputUnit outputUnitTo = outputUnitForElement(to); |
229 return outputUnitTo.imports.containsAll(outputUnitFrom.imports); | 218 return outputUnitTo.imports.containsAll(outputUnitFrom.imports); |
230 } | 219 } |
231 | 220 |
232 void registerConstantDeferredUse(DeferredConstantValue constant, | 221 void registerConstantDeferredUse( |
233 PrefixElement prefix) { | 222 DeferredConstantValue constant, PrefixElement prefix) { |
234 OutputUnit outputUnit = new OutputUnit(); | 223 OutputUnit outputUnit = new OutputUnit(); |
235 outputUnit.imports.add(new _DeclaredDeferredImport(prefix.deferredImport)); | 224 outputUnit.imports.add(new _DeclaredDeferredImport(prefix.deferredImport)); |
236 _constantToOutputUnit[constant] = outputUnit; | 225 _constantToOutputUnit[constant] = outputUnit; |
237 } | 226 } |
238 | 227 |
239 /// Answers whether [element] is explicitly deferred when referred to from | 228 /// Answers whether [element] is explicitly deferred when referred to from |
240 /// [library]. | 229 /// [library]. |
241 bool _isExplicitlyDeferred(Element element, LibraryElement library) { | 230 bool _isExplicitlyDeferred(Element element, LibraryElement library) { |
242 Iterable<ImportElement> imports = _getImports(element, library); | 231 Iterable<ImportElement> imports = _getImports(element, library); |
243 // If the element is not imported explicitly, it is implicitly imported | 232 // If the element is not imported explicitly, it is implicitly imported |
(...skipping 14 matching lines...) Expand all Loading... |
258 if (element.isAccessor) { | 247 if (element.isAccessor) { |
259 element = (element as AccessorElement).abstractField; | 248 element = (element as AccessorElement).abstractField; |
260 } | 249 } |
261 return library.getImportsFor(element); | 250 return library.getImportsFor(element); |
262 } | 251 } |
263 | 252 |
264 /// Finds all elements and constants that [element] depends directly on. | 253 /// Finds all elements and constants that [element] depends directly on. |
265 /// (not the transitive closure.) | 254 /// (not the transitive closure.) |
266 /// | 255 /// |
267 /// Adds the results to [elements] and [constants]. | 256 /// Adds the results to [elements] and [constants]. |
268 void _collectAllElementsAndConstantsResolvedFrom( | 257 void _collectAllElementsAndConstantsResolvedFrom(Element element, |
269 Element element, | 258 Set<Element> elements, Set<ConstantValue> constants, isMirrorUsage) { |
270 Set<Element> elements, | |
271 Set<ConstantValue> constants, | |
272 isMirrorUsage) { | |
273 | |
274 if (element.isMalformed) { | 259 if (element.isMalformed) { |
275 // Malformed elements are ignored. | 260 // Malformed elements are ignored. |
276 return; | 261 return; |
277 } | 262 } |
278 | 263 |
279 /// Recursively collects all the dependencies of [type]. | 264 /// Recursively collects all the dependencies of [type]. |
280 void collectTypeDependencies(DartType type) { | 265 void collectTypeDependencies(DartType type) { |
281 // TODO(het): we would like to separate out types that are only needed for | 266 // TODO(het): we would like to separate out types that are only needed for |
282 // rti from types that are needed for their members. | 267 // rti from types that are needed for their members. |
283 if (type is GenericType) { | 268 if (type is GenericType) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 AstElement analyzableElement = element.analyzableElement.declaration; | 305 AstElement analyzableElement = element.analyzableElement.declaration; |
321 if (!compiler.enqueuer.resolution.hasBeenProcessed(analyzableElement)) { | 306 if (!compiler.enqueuer.resolution.hasBeenProcessed(analyzableElement)) { |
322 return; | 307 return; |
323 } | 308 } |
324 | 309 |
325 WorldImpact worldImpact = | 310 WorldImpact worldImpact = |
326 compiler.resolution.getWorldImpact(analyzableElement); | 311 compiler.resolution.getWorldImpact(analyzableElement); |
327 compiler.impactStrategy.visitImpact( | 312 compiler.impactStrategy.visitImpact( |
328 analyzableElement, | 313 analyzableElement, |
329 worldImpact, | 314 worldImpact, |
330 new WorldImpactVisitorImpl( | 315 new WorldImpactVisitorImpl(visitStaticUse: (StaticUse staticUse) { |
331 visitStaticUse: (StaticUse staticUse) { | 316 elements.add(staticUse.element); |
332 elements.add(staticUse.element); | 317 }, visitTypeUse: (TypeUse typeUse) { |
333 }, | 318 DartType type = typeUse.type; |
334 visitTypeUse: (TypeUse typeUse) { | 319 switch (typeUse.kind) { |
335 DartType type = typeUse.type; | 320 case TypeUseKind.TYPE_LITERAL: |
336 switch (typeUse.kind) { | 321 if (type.isTypedef || type.isInterfaceType) { |
337 case TypeUseKind.TYPE_LITERAL: | 322 elements.add(type.element); |
338 if (type.isTypedef || type.isInterfaceType) { | |
339 elements.add(type.element); | |
340 } | |
341 break; | |
342 case TypeUseKind.INSTANTIATION: | |
343 case TypeUseKind.IS_CHECK: | |
344 case TypeUseKind.AS_CAST: | |
345 case TypeUseKind.CATCH_TYPE: | |
346 collectTypeDependencies(type); | |
347 break; | |
348 case TypeUseKind.CHECKED_MODE_CHECK: | |
349 if (compiler.options.enableTypeAssertions) { | |
350 collectTypeDependencies(type); | |
351 } | |
352 break; | |
353 } | 323 } |
354 }), | 324 break; |
355 IMPACT_USE); | 325 case TypeUseKind.INSTANTIATION: |
| 326 case TypeUseKind.IS_CHECK: |
| 327 case TypeUseKind.AS_CAST: |
| 328 case TypeUseKind.CATCH_TYPE: |
| 329 collectTypeDependencies(type); |
| 330 break; |
| 331 case TypeUseKind.CHECKED_MODE_CHECK: |
| 332 if (compiler.options.enableTypeAssertions) { |
| 333 collectTypeDependencies(type); |
| 334 } |
| 335 break; |
| 336 } |
| 337 }), |
| 338 IMPACT_USE); |
356 | 339 |
357 TreeElements treeElements = analyzableElement.resolvedAst.elements; | 340 TreeElements treeElements = analyzableElement.resolvedAst.elements; |
358 assert(treeElements != null); | 341 assert(treeElements != null); |
359 | 342 |
360 treeElements.forEachConstantNode((Node node, _) { | 343 treeElements.forEachConstantNode((Node node, _) { |
361 // Explicitly depend on the backend constants. | 344 // Explicitly depend on the backend constants. |
362 ConstantValue value = | 345 ConstantValue value = |
363 backend.constants.getConstantValueForNode(node, treeElements); | 346 backend.constants.getConstantValueForNode(node, treeElements); |
364 if (value != null) { | 347 if (value != null) { |
365 // TODO(johnniwinther): Assert that all constants have values when | 348 // TODO(johnniwinther): Assert that all constants have values when |
(...skipping 30 matching lines...) Expand all Loading... |
396 ClassElement cls = element.declaration; | 379 ClassElement cls = element.declaration; |
397 cls.forEachLocalMember(addLiveInstanceMember); | 380 cls.forEachLocalMember(addLiveInstanceMember); |
398 if (cls.implementation != cls) { | 381 if (cls.implementation != cls) { |
399 // TODO(ahe): Why doesn't ClassElement.forEachLocalMember do this? | 382 // TODO(ahe): Why doesn't ClassElement.forEachLocalMember do this? |
400 cls.implementation.forEachLocalMember(addLiveInstanceMember); | 383 cls.implementation.forEachLocalMember(addLiveInstanceMember); |
401 } | 384 } |
402 for (var type in cls.implementation.allSupertypes) { | 385 for (var type in cls.implementation.allSupertypes) { |
403 elements.add(type.element.implementation); | 386 elements.add(type.element.implementation); |
404 } | 387 } |
405 elements.add(cls.implementation); | 388 elements.add(cls.implementation); |
406 } else if (Elements.isStaticOrTopLevel(element) || | 389 } else if (Elements.isStaticOrTopLevel(element) || element.isConstructor) { |
407 element.isConstructor) { | |
408 elements.add(element); | 390 elements.add(element); |
409 collectDependencies(element); | 391 collectDependencies(element); |
410 } | 392 } |
411 if (element.isGenerativeConstructor) { | 393 if (element.isGenerativeConstructor) { |
412 // When instantiating a class, we record a reference to the | 394 // When instantiating a class, we record a reference to the |
413 // constructor, not the class itself. We must add all the | 395 // constructor, not the class itself. We must add all the |
414 // instance members of the constructor's class. | 396 // instance members of the constructor's class. |
415 ClassElement implementation = | 397 ClassElement implementation = element.enclosingClass.implementation; |
416 element.enclosingClass.implementation; | |
417 _collectAllElementsAndConstantsResolvedFrom( | 398 _collectAllElementsAndConstantsResolvedFrom( |
418 implementation, elements, constants, isMirrorUsage); | 399 implementation, elements, constants, isMirrorUsage); |
419 } | 400 } |
420 | 401 |
421 // Other elements, in particular instance members, are ignored as | 402 // Other elements, in particular instance members, are ignored as |
422 // they are processed as part of the class. | 403 // they are processed as part of the class. |
423 } | 404 } |
424 | 405 |
425 /// Returns the transitive closure of all libraries that are imported | 406 /// Returns the transitive closure of all libraries that are imported |
426 /// from root without DeferredLibrary annotations. | 407 /// from root without DeferredLibrary annotations. |
(...skipping 23 matching lines...) Expand all Loading... |
450 if (library.isPatched) { | 431 if (library.isPatched) { |
451 iterateTags(library.implementation); | 432 iterateTags(library.implementation); |
452 } | 433 } |
453 } | 434 } |
454 traverseLibrary(root); | 435 traverseLibrary(root); |
455 result.add(compiler.coreLibrary); | 436 result.add(compiler.coreLibrary); |
456 return result; | 437 return result; |
457 } | 438 } |
458 | 439 |
459 /// Add all dependencies of [constant] to the mapping of [import]. | 440 /// Add all dependencies of [constant] to the mapping of [import]. |
460 void _mapConstantDependencies(ConstantValue constant, | 441 void _mapConstantDependencies( |
461 _DeferredImport import) { | 442 ConstantValue constant, _DeferredImport import) { |
462 Set<ConstantValue> constants = _constantsDeferredBy.putIfAbsent(import, | 443 Set<ConstantValue> constants = _constantsDeferredBy.putIfAbsent( |
463 () => new Set<ConstantValue>()); | 444 import, () => new Set<ConstantValue>()); |
464 if (constants.contains(constant)) return; | 445 if (constants.contains(constant)) return; |
465 constants.add(constant); | 446 constants.add(constant); |
466 if (constant is ConstructedConstantValue) { | 447 if (constant is ConstructedConstantValue) { |
467 _mapDependencies(element: constant.type.element, import: import); | 448 _mapDependencies(element: constant.type.element, import: import); |
468 } | 449 } |
469 constant.getDependencies().forEach((ConstantValue dependency) { | 450 constant.getDependencies().forEach((ConstantValue dependency) { |
470 _mapConstantDependencies(dependency, import); | 451 _mapConstantDependencies(dependency, import); |
471 }); | 452 }); |
472 } | 453 } |
473 | 454 |
474 /// Recursively traverses the graph of dependencies from one of [element] | 455 /// Recursively traverses the graph of dependencies from one of [element] |
475 /// or [constant], mapping deferred imports to each dependency it needs in the | 456 /// or [constant], mapping deferred imports to each dependency it needs in the |
476 /// sets [_importedDeferredBy] and [_constantsDeferredBy]. | 457 /// sets [_importedDeferredBy] and [_constantsDeferredBy]. |
477 /// Only one of [element] and [constant] should be given. | 458 /// Only one of [element] and [constant] should be given. |
478 void _mapDependencies({Element element, | 459 void _mapDependencies( |
479 _DeferredImport import, | 460 {Element element, _DeferredImport import, isMirrorUsage: false}) { |
480 isMirrorUsage: false}) { | 461 Set<Element> elements = |
481 | 462 _importedDeferredBy.putIfAbsent(import, () => new Set<Element>()); |
482 Set<Element> elements = _importedDeferredBy.putIfAbsent(import, | |
483 () => new Set<Element>()); | |
484 | |
485 | 463 |
486 Set<Element> dependentElements = new Set<Element>(); | 464 Set<Element> dependentElements = new Set<Element>(); |
487 Set<ConstantValue> dependentConstants = new Set<ConstantValue>(); | 465 Set<ConstantValue> dependentConstants = new Set<ConstantValue>(); |
488 | 466 |
489 LibraryElement library; | 467 LibraryElement library; |
490 | 468 |
491 if (element != null) { | 469 if (element != null) { |
492 // Only process elements once, unless we are doing dependencies due to | 470 // Only process elements once, unless we are doing dependencies due to |
493 // mirrors, which are added in additional traversals. | 471 // mirrors, which are added in additional traversals. |
494 if (!isMirrorUsage && elements.contains(element)) return; | 472 if (!isMirrorUsage && elements.contains(element)) return; |
495 // Anything used directly by main will be loaded from the start | 473 // Anything used directly by main will be loaded from the start |
496 // We do not need to traverse it again. | 474 // We do not need to traverse it again. |
497 if (import != _fakeMainImport && _mainElements.contains(element)) return; | 475 if (import != _fakeMainImport && _mainElements.contains(element)) return; |
498 elements.add(element); | 476 elements.add(element); |
499 | 477 |
500 | |
501 // This call can modify [dependentElements] and [dependentConstants]. | 478 // This call can modify [dependentElements] and [dependentConstants]. |
502 _collectAllElementsAndConstantsResolvedFrom( | 479 _collectAllElementsAndConstantsResolvedFrom( |
503 element, dependentElements, dependentConstants, isMirrorUsage); | 480 element, dependentElements, dependentConstants, isMirrorUsage); |
504 | 481 |
505 library = element.library; | 482 library = element.library; |
506 } | 483 } |
507 | 484 |
508 for (Element dependency in dependentElements) { | 485 for (Element dependency in dependentElements) { |
509 if (_isExplicitlyDeferred(dependency, library)) { | 486 if (_isExplicitlyDeferred(dependency, library)) { |
510 for (ImportElement deferredImport in _getImports(dependency, library)) { | 487 for (ImportElement deferredImport in _getImports(dependency, library)) { |
511 _mapDependencies(element: dependency, | 488 _mapDependencies( |
| 489 element: dependency, |
512 import: new _DeclaredDeferredImport(deferredImport)); | 490 import: new _DeclaredDeferredImport(deferredImport)); |
513 } | 491 } |
514 } else { | 492 } else { |
515 _mapDependencies(element: dependency, import: import); | 493 _mapDependencies(element: dependency, import: import); |
516 } | 494 } |
517 } | 495 } |
518 | 496 |
519 for (ConstantValue dependency in dependentConstants) { | 497 for (ConstantValue dependency in dependentConstants) { |
520 if (dependency is DeferredConstantValue) { | 498 if (dependency is DeferredConstantValue) { |
521 _mapConstantDependencies(dependency, | 499 _mapConstantDependencies(dependency, |
522 new _DeclaredDeferredImport(dependency.prefix.deferredImport)); | 500 new _DeclaredDeferredImport(dependency.prefix.deferredImport)); |
523 } else { | 501 } else { |
524 _mapConstantDependencies(dependency, import); | 502 _mapConstantDependencies(dependency, import); |
525 } | 503 } |
526 } | 504 } |
527 } | 505 } |
528 | 506 |
529 /// Adds extra dependencies coming from mirror usage. | 507 /// Adds extra dependencies coming from mirror usage. |
530 /// | 508 /// |
531 /// The elements are added with [_mapDependencies]. | 509 /// The elements are added with [_mapDependencies]. |
532 void _addMirrorElements() { | 510 void _addMirrorElements() { |
533 void mapDependenciesIfResolved(Element element, | 511 void mapDependenciesIfResolved( |
534 _DeferredImport deferredImport) { | 512 Element element, _DeferredImport deferredImport) { |
535 // If an element is the target of a MirrorsUsed annotation but never used | 513 // If an element is the target of a MirrorsUsed annotation but never used |
536 // It will not be resolved, and we should not call isNeededForReflection. | 514 // It will not be resolved, and we should not call isNeededForReflection. |
537 // TODO(sigurdm): Unresolved elements should just answer false when | 515 // TODO(sigurdm): Unresolved elements should just answer false when |
538 // asked isNeededForReflection. Instead an internal error is triggered. | 516 // asked isNeededForReflection. Instead an internal error is triggered. |
539 // So we have to filter them out here. | 517 // So we have to filter them out here. |
540 if (element is AnalyzableElementX && !element.hasTreeElements) return; | 518 if (element is AnalyzableElementX && !element.hasTreeElements) return; |
541 if (compiler.backend.isAccessibleByReflection(element)) { | 519 if (compiler.backend.isAccessibleByReflection(element)) { |
542 _mapDependencies( | 520 _mapDependencies( |
543 element: element, import: deferredImport, isMirrorUsage: true); | 521 element: element, import: deferredImport, isMirrorUsage: true); |
544 } | 522 } |
(...skipping 16 matching lines...) Expand all Loading... |
561 } | 539 } |
562 } | 540 } |
563 | 541 |
564 processMetadata(library); | 542 processMetadata(library); |
565 library.imports.forEach(processMetadata); | 543 library.imports.forEach(processMetadata); |
566 library.exports.forEach(processMetadata); | 544 library.exports.forEach(processMetadata); |
567 } | 545 } |
568 | 546 |
569 for (_DeferredImport deferredImport in _allDeferredImports.keys) { | 547 for (_DeferredImport deferredImport in _allDeferredImports.keys) { |
570 LibraryElement deferredLibrary = _allDeferredImports[deferredImport]; | 548 LibraryElement deferredLibrary = _allDeferredImports[deferredImport]; |
571 for (LibraryElement library in | 549 for (LibraryElement library |
572 _nonDeferredReachableLibraries(deferredLibrary)) { | 550 in _nonDeferredReachableLibraries(deferredLibrary)) { |
573 handleLibrary(library, deferredImport); | 551 handleLibrary(library, deferredImport); |
574 } | 552 } |
575 } | 553 } |
576 } | 554 } |
577 | 555 |
578 /// Computes a unique string for the name field for each outputUnit. | 556 /// Computes a unique string for the name field for each outputUnit. |
579 /// | 557 /// |
580 /// Also sets up the [hunksToLoad] mapping. | 558 /// Also sets up the [hunksToLoad] mapping. |
581 void _assignNamesToOutputUnits(Set<OutputUnit> allOutputUnits) { | 559 void _assignNamesToOutputUnits(Set<OutputUnit> allOutputUnits) { |
582 Set<String> usedImportNames = new Set<String>(); | 560 Set<String> usedImportNames = new Set<String>(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
635 allOutputUnits.add(mainOutputUnit); | 613 allOutputUnits.add(mainOutputUnit); |
636 return; | 614 return; |
637 } | 615 } |
638 if (main == null) return; | 616 if (main == null) return; |
639 LibraryElement mainLibrary = main.library; | 617 LibraryElement mainLibrary = main.library; |
640 _importedDeferredBy = new Map<_DeferredImport, Set<Element>>(); | 618 _importedDeferredBy = new Map<_DeferredImport, Set<Element>>(); |
641 _constantsDeferredBy = new Map<_DeferredImport, Set<ConstantValue>>(); | 619 _constantsDeferredBy = new Map<_DeferredImport, Set<ConstantValue>>(); |
642 _importedDeferredBy[_fakeMainImport] = _mainElements; | 620 _importedDeferredBy[_fakeMainImport] = _mainElements; |
643 | 621 |
644 measureElement(mainLibrary, () { | 622 measureElement(mainLibrary, () { |
645 | |
646 // Starting from main, traverse the program and find all dependencies. | 623 // Starting from main, traverse the program and find all dependencies. |
647 _mapDependencies(element: compiler.mainFunction, import: _fakeMainImport); | 624 _mapDependencies(element: compiler.mainFunction, import: _fakeMainImport); |
648 | 625 |
649 // Also add "global" dependencies to the main OutputUnit. These are | 626 // Also add "global" dependencies to the main OutputUnit. These are |
650 // things that the backend needs but cannot associate with a particular | 627 // things that the backend needs but cannot associate with a particular |
651 // element, for example, startRootIsolate. This set also contains | 628 // element, for example, startRootIsolate. This set also contains |
652 // elements for which we lack precise information. | 629 // elements for which we lack precise information. |
653 for (Element element in compiler.globalDependencies.otherDependencies) { | 630 for (Element element in compiler.globalDependencies.otherDependencies) { |
654 _mapDependencies(element: element, import: _fakeMainImport); | 631 _mapDependencies(element: element, import: _fakeMainImport); |
655 } | 632 } |
(...skipping 13 matching lines...) Expand all Loading... |
669 // all deferred imports mapped to this element. Same for constants. | 646 // all deferred imports mapped to this element. Same for constants. |
670 for (_DeferredImport import in _importedDeferredBy.keys) { | 647 for (_DeferredImport import in _importedDeferredBy.keys) { |
671 for (Element element in _importedDeferredBy[import]) { | 648 for (Element element in _importedDeferredBy[import]) { |
672 // Only one file should be loaded when the program starts, so make | 649 // Only one file should be loaded when the program starts, so make |
673 // sure that only one OutputUnit is created for [fakeMainImport]. | 650 // sure that only one OutputUnit is created for [fakeMainImport]. |
674 if (import == _fakeMainImport) { | 651 if (import == _fakeMainImport) { |
675 elementToOutputUnitBuilder[element] = mainOutputUnit; | 652 elementToOutputUnitBuilder[element] = mainOutputUnit; |
676 } else { | 653 } else { |
677 elementToOutputUnitBuilder | 654 elementToOutputUnitBuilder |
678 .putIfAbsent(element, () => new OutputUnit()) | 655 .putIfAbsent(element, () => new OutputUnit()) |
679 .imports.add(import); | 656 .imports |
| 657 .add(import); |
680 } | 658 } |
681 } | 659 } |
682 } | 660 } |
683 for (_DeferredImport import in _constantsDeferredBy.keys) { | 661 for (_DeferredImport import in _constantsDeferredBy.keys) { |
684 for (ConstantValue constant in _constantsDeferredBy[import]) { | 662 for (ConstantValue constant in _constantsDeferredBy[import]) { |
685 // Only one file should be loaded when the program starts, so make | 663 // Only one file should be loaded when the program starts, so make |
686 // sure that only one OutputUnit is created for [fakeMainImport]. | 664 // sure that only one OutputUnit is created for [fakeMainImport]. |
687 if (import == _fakeMainImport) { | 665 if (import == _fakeMainImport) { |
688 constantToOutputUnitBuilder[constant] = mainOutputUnit; | 666 constantToOutputUnitBuilder[constant] = mainOutputUnit; |
689 } else { | 667 } else { |
690 constantToOutputUnitBuilder | 668 constantToOutputUnitBuilder |
691 .putIfAbsent(constant, () => new OutputUnit()) | 669 .putIfAbsent(constant, () => new OutputUnit()) |
692 .imports.add(import); | 670 .imports |
| 671 .add(import); |
693 } | 672 } |
694 } | 673 } |
695 } | 674 } |
696 | 675 |
697 // Release maps; | 676 // Release maps; |
698 _importedDeferredBy = null; | 677 _importedDeferredBy = null; |
699 _constantsDeferredBy = null; | 678 _constantsDeferredBy = null; |
700 | 679 |
701 // Find all the output units elements/constants have been mapped to, and | 680 // Find all the output units elements/constants have been mapped to, and |
702 // canonicalize them. | 681 // canonicalize them. |
703 elementToOutputUnitBuilder.forEach( | 682 elementToOutputUnitBuilder |
704 (Element element, OutputUnit outputUnit) { | 683 .forEach((Element element, OutputUnit outputUnit) { |
705 OutputUnit representative = allOutputUnits.lookup(outputUnit); | 684 OutputUnit representative = allOutputUnits.lookup(outputUnit); |
706 if (representative == null) { | 685 if (representative == null) { |
707 representative = outputUnit; | 686 representative = outputUnit; |
708 allOutputUnits.add(representative); | 687 allOutputUnits.add(representative); |
709 } | 688 } |
710 _elementToOutputUnit[element] = representative; | 689 _elementToOutputUnit[element] = representative; |
711 }); | 690 }); |
712 constantToOutputUnitBuilder.forEach( | 691 constantToOutputUnitBuilder |
713 (ConstantValue constant, OutputUnit outputUnit) { | 692 .forEach((ConstantValue constant, OutputUnit outputUnit) { |
714 OutputUnit representative = allOutputUnits.lookup(outputUnit); | 693 OutputUnit representative = allOutputUnits.lookup(outputUnit); |
715 if (representative == null) { | 694 if (representative == null) { |
716 representative = outputUnit; | 695 representative = outputUnit; |
717 allOutputUnits.add(representative); | 696 allOutputUnits.add(representative); |
718 } | 697 } |
719 _constantToOutputUnit[constant] = representative; | 698 _constantToOutputUnit[constant] = representative; |
720 }); | 699 }); |
721 | 700 |
722 // Generate a unique name for each OutputUnit. | 701 // Generate a unique name for each OutputUnit. |
723 _assignNamesToOutputUnits(allOutputUnits); | 702 _assignNamesToOutputUnits(allOutputUnits); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
761 for (ImportElement import in library.imports) { | 740 for (ImportElement import in library.imports) { |
762 /// Give an error if the old annotation-based syntax has been used. | 741 /// Give an error if the old annotation-based syntax has been used. |
763 List<MetadataAnnotation> metadataList = import.metadata; | 742 List<MetadataAnnotation> metadataList = import.metadata; |
764 if (metadataList != null) { | 743 if (metadataList != null) { |
765 for (MetadataAnnotation metadata in metadataList) { | 744 for (MetadataAnnotation metadata in metadataList) { |
766 metadata.ensureResolved(compiler.resolution); | 745 metadata.ensureResolved(compiler.resolution); |
767 ConstantValue value = | 746 ConstantValue value = |
768 compiler.constants.getConstantValue(metadata.constant); | 747 compiler.constants.getConstantValue(metadata.constant); |
769 Element element = value.getType(compiler.coreTypes).element; | 748 Element element = value.getType(compiler.coreTypes).element; |
770 if (element == deferredLibraryClass) { | 749 if (element == deferredLibraryClass) { |
771 reporter.reportErrorMessage( | 750 reporter.reportErrorMessage( |
772 import, MessageKind.DEFERRED_OLD_SYNTAX); | 751 import, MessageKind.DEFERRED_OLD_SYNTAX); |
773 } | 752 } |
774 } | 753 } |
775 } | 754 } |
776 | 755 |
777 String prefix = (import.prefix != null) | 756 String prefix = (import.prefix != null) ? import.prefix.name : null; |
778 ? import.prefix.name | |
779 : null; | |
780 // The last import we saw with the same prefix. | 757 // The last import we saw with the same prefix. |
781 ImportElement previousDeferredImport = prefixDeferredImport[prefix]; | 758 ImportElement previousDeferredImport = prefixDeferredImport[prefix]; |
782 if (import.isDeferred) { | 759 if (import.isDeferred) { |
783 _DeferredImport key = new _DeclaredDeferredImport(import); | 760 _DeferredImport key = new _DeclaredDeferredImport(import); |
784 LibraryElement importedLibrary = import.importedLibrary; | 761 LibraryElement importedLibrary = import.importedLibrary; |
785 _allDeferredImports[key] = importedLibrary; | 762 _allDeferredImports[key] = importedLibrary; |
786 | 763 |
787 if (prefix == null) { | 764 if (prefix == null) { |
788 reporter.reportErrorMessage( | 765 reporter.reportErrorMessage( |
789 import, | 766 import, MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX); |
790 MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX); | |
791 } else { | 767 } else { |
792 prefixDeferredImport[prefix] = import; | 768 prefixDeferredImport[prefix] = import; |
793 _deferredImportDescriptions[key] = | 769 _deferredImportDescriptions[key] = |
794 new ImportDescription(import, library, compiler); | 770 new ImportDescription(import, library, compiler); |
795 } | 771 } |
796 isProgramSplit = true; | 772 isProgramSplit = true; |
797 lastDeferred = import; | 773 lastDeferred = import; |
798 } | 774 } |
799 if (prefix != null) { | 775 if (prefix != null) { |
800 if (previousDeferredImport != null || | 776 if (previousDeferredImport != null || |
801 (import.isDeferred && usedPrefixes.contains(prefix))) { | 777 (import.isDeferred && usedPrefixes.contains(prefix))) { |
802 ImportElement failingImport = (previousDeferredImport != null) | 778 ImportElement failingImport = (previousDeferredImport != null) |
803 ? previousDeferredImport | 779 ? previousDeferredImport |
804 : import; | 780 : import; |
805 reporter.reportErrorMessage( | 781 reporter.reportErrorMessage(failingImport.prefix, |
806 failingImport.prefix, | |
807 MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX); | 782 MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX); |
808 } | 783 } |
809 usedPrefixes.add(prefix); | 784 usedPrefixes.add(prefix); |
810 } | 785 } |
811 } | 786 } |
812 }); | 787 }); |
813 } | 788 } |
814 if (isProgramSplit) { | 789 if (isProgramSplit) { |
815 isProgramSplit = compiler.backend.enableDeferredLoadingIfSupported( | 790 isProgramSplit = compiler.backend.enableDeferredLoadingIfSupported( |
816 lastDeferred, compiler.globalDependencies); | 791 lastDeferred, compiler.globalDependencies); |
817 } | 792 } |
818 } | 793 } |
819 | 794 |
820 /// If [send] is a static send with a deferred element, returns the | 795 /// If [send] is a static send with a deferred element, returns the |
821 /// [PrefixElement] that the first prefix of the send resolves to. | 796 /// [PrefixElement] that the first prefix of the send resolves to. |
822 /// Otherwise returns null. | 797 /// Otherwise returns null. |
823 /// | 798 /// |
824 /// Precondition: send must be static. | 799 /// Precondition: send must be static. |
825 /// | 800 /// |
826 /// Example: | 801 /// Example: |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
886 /// - <prefix> is the `as` prefix used for a given deferred import. | 861 /// - <prefix> is the `as` prefix used for a given deferred import. |
887 /// - <list of files> is a list of the filenames the must be loaded when that | 862 /// - <list of files> is a list of the filenames the must be loaded when that |
888 /// import is loaded. | 863 /// import is loaded. |
889 Map<String, Map<String, dynamic>> computeDeferredMap() { | 864 Map<String, Map<String, dynamic>> computeDeferredMap() { |
890 JavaScriptBackend backend = compiler.backend; | 865 JavaScriptBackend backend = compiler.backend; |
891 Map<String, Map<String, dynamic>> mapping = | 866 Map<String, Map<String, dynamic>> mapping = |
892 new Map<String, Map<String, dynamic>>(); | 867 new Map<String, Map<String, dynamic>>(); |
893 _deferredImportDescriptions.keys.forEach((_DeferredImport import) { | 868 _deferredImportDescriptions.keys.forEach((_DeferredImport import) { |
894 List<OutputUnit> outputUnits = hunksToLoad[importDeferName[import]]; | 869 List<OutputUnit> outputUnits = hunksToLoad[importDeferName[import]]; |
895 ImportDescription description = _deferredImportDescriptions[import]; | 870 ImportDescription description = _deferredImportDescriptions[import]; |
896 Map<String, dynamic> libraryMap = | 871 Map<String, dynamic> libraryMap = mapping.putIfAbsent( |
897 mapping.putIfAbsent(description.importingUri, | 872 description.importingUri, |
898 () => <String, dynamic>{"name": description.importingLibraryName, | 873 () => <String, dynamic>{ |
899 "imports": <String, List<String>>{}}); | 874 "name": description.importingLibraryName, |
| 875 "imports": <String, List<String>>{} |
| 876 }); |
900 | 877 |
901 libraryMap["imports"][importDeferName[import]] = outputUnits.map( | 878 libraryMap["imports"][importDeferName[import]] = |
902 (OutputUnit outputUnit) { | 879 outputUnits.map((OutputUnit outputUnit) { |
903 return backend.deferredPartFileName(outputUnit.name); | 880 return backend.deferredPartFileName(outputUnit.name); |
904 }).toList(); | 881 }).toList(); |
905 }); | 882 }); |
906 return mapping; | 883 return mapping; |
907 } | 884 } |
908 | 885 |
909 /// Creates a textual representation of the output unit content. | 886 /// Creates a textual representation of the output unit content. |
910 String dump() { | 887 String dump() { |
911 Map<OutputUnit, List<String>> elementMap = <OutputUnit, List<String>>{}; | 888 Map<OutputUnit, List<String>> elementMap = <OutputUnit, List<String>>{}; |
912 Map<OutputUnit, List<String>> constantMap = | 889 Map<OutputUnit, List<String>> constantMap = <OutputUnit, List<String>>{}; |
913 <OutputUnit, List<String>>{}; | |
914 _elementToOutputUnit.forEach((Element element, OutputUnit output) { | 890 _elementToOutputUnit.forEach((Element element, OutputUnit output) { |
915 elementMap.putIfAbsent(output, () => <String>[]).add('$element'); | 891 elementMap.putIfAbsent(output, () => <String>[]).add('$element'); |
916 }); | 892 }); |
917 _constantToOutputUnit.forEach((ConstantValue value, OutputUnit output) { | 893 _constantToOutputUnit.forEach((ConstantValue value, OutputUnit output) { |
918 constantMap.putIfAbsent(output, () => <String>[]) | 894 constantMap |
| 895 .putIfAbsent(output, () => <String>[]) |
919 .add(value.toStructuredString()); | 896 .add(value.toStructuredString()); |
920 }); | 897 }); |
921 | 898 |
922 StringBuffer sb = new StringBuffer(); | 899 StringBuffer sb = new StringBuffer(); |
923 for (OutputUnit outputUnit in allOutputUnits) { | 900 for (OutputUnit outputUnit in allOutputUnits) { |
924 sb.write(outputUnit.name); | 901 sb.write(outputUnit.name); |
925 List<String> elements = elementMap[outputUnit]; | 902 List<String> elements = elementMap[outputUnit]; |
926 if (elements != null) { | 903 if (elements != null) { |
927 sb.write('\n elements:'); | 904 sb.write('\n elements:'); |
928 for (String element in elements..sort()) { | 905 for (String element in elements..sort()) { |
929 sb.write('\n $element'); | 906 sb.write('\n $element'); |
930 } | 907 } |
931 } | 908 } |
932 List<String> constants = constantMap[outputUnit]; | 909 List<String> constants = constantMap[outputUnit]; |
933 if (constants != null) { | 910 if (constants != null) { |
934 sb.write('\n constants:'); | 911 sb.write('\n constants:'); |
935 for (String value in constants..sort()) { | 912 for (String value in constants..sort()) { |
936 sb.write('\n $value'); | 913 sb.write('\n $value'); |
937 } | 914 } |
938 } | 915 } |
939 } | 916 } |
940 return sb.toString(); | 917 return sb.toString(); |
941 } | 918 } |
942 | |
943 } | 919 } |
944 | 920 |
945 class ImportDescription { | 921 class ImportDescription { |
946 /// Relative uri to the importing library. | 922 /// Relative uri to the importing library. |
947 final String importingUri; | 923 final String importingUri; |
| 924 |
948 /// The prefix this import is imported as. | 925 /// The prefix this import is imported as. |
949 final String prefix; | 926 final String prefix; |
950 final LibraryElement _importingLibrary; | 927 final LibraryElement _importingLibrary; |
951 | 928 |
952 ImportDescription(ImportElement import, | 929 ImportDescription( |
953 LibraryElement importingLibrary, | 930 ImportElement import, LibraryElement importingLibrary, Compiler compiler) |
954 Compiler compiler) | 931 : importingUri = uri_extras.relativize(compiler.mainApp.canonicalUri, |
955 : importingUri = uri_extras.relativize( | 932 importingLibrary.canonicalUri, false), |
956 compiler.mainApp.canonicalUri, | |
957 importingLibrary.canonicalUri, false), | |
958 prefix = import.prefix.name, | 933 prefix = import.prefix.name, |
959 _importingLibrary = importingLibrary; | 934 _importingLibrary = importingLibrary; |
960 | 935 |
961 String get importingLibraryName { | 936 String get importingLibraryName { |
962 return _importingLibrary.hasLibraryName | 937 return _importingLibrary.hasLibraryName |
963 ? _importingLibrary.libraryName : "<unnamed>"; | 938 ? _importingLibrary.libraryName |
| 939 : "<unnamed>"; |
964 } | 940 } |
965 } | 941 } |
966 | 942 |
967 /// A node in the deferred import graph. | 943 /// A node in the deferred import graph. |
968 /// | 944 /// |
969 /// This class serves as the root node; the 'import' of the main library. | 945 /// This class serves as the root node; the 'import' of the main library. |
970 class _DeferredImport { | 946 class _DeferredImport { |
971 const _DeferredImport(); | 947 const _DeferredImport(); |
972 | 948 |
973 /// Computes a suggestive name for this import. | 949 /// Computes a suggestive name for this import. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1012 return result; | 988 return result; |
1013 } | 989 } |
1014 | 990 |
1015 bool operator ==(other) { | 991 bool operator ==(other) { |
1016 if (other is! _DeclaredDeferredImport) return false; | 992 if (other is! _DeclaredDeferredImport) return false; |
1017 return declaration == other.declaration; | 993 return declaration == other.declaration; |
1018 } | 994 } |
1019 | 995 |
1020 int get hashCode => declaration.hashCode * 17; | 996 int get hashCode => declaration.hashCode * 17; |
1021 } | 997 } |
OLD | NEW |