| 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 'dart2jslib.dart' show | 7 import 'dart2jslib.dart' show |
| 8 Backend, | 8 Backend, |
| 9 Compiler, | 9 Compiler, |
| 10 CompilerTask, | 10 CompilerTask, |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 for (MetadataAnnotation metadata in metadataList) { | 237 for (MetadataAnnotation metadata in metadataList) { |
| 238 metadata.ensureResolved(compiler); | 238 metadata.ensureResolved(compiler); |
| 239 Element element = metadata.value.computeType(compiler).element; | 239 Element element = metadata.value.computeType(compiler).element; |
| 240 if (element == deferredLibraryClass) { | 240 if (element == deferredLibraryClass) { |
| 241 _allDeferredImports[import] = library.getLibraryFromTag(import); | 241 _allDeferredImports[import] = library.getLibraryFromTag(import); |
| 242 // On encountering a deferred library without a prefix we report an | 242 // On encountering a deferred library without a prefix we report an |
| 243 // error, but continue the compilation to possibly give more | 243 // error, but continue the compilation to possibly give more |
| 244 // information. Therefore it is neccessary to check if there is a prefix | 244 // information. Therefore it is neccessary to check if there is a prefix |
| 245 // here. | 245 // here. |
| 246 Element maybePrefix = library.find(import.prefix.toString()); | 246 Element maybePrefix = library.find(import.prefix.toString()); |
| 247 if (maybePrefix != null && maybePrefix.isPrefix()) { | 247 if (maybePrefix != null && maybePrefix.isPrefix) { |
| 248 PrefixElement prefix = maybePrefix; | 248 PrefixElement prefix = maybePrefix; |
| 249 prefix.markAsDeferred(import); | 249 prefix.markAsDeferred(import); |
| 250 } | 250 } |
| 251 } | 251 } |
| 252 } | 252 } |
| 253 } | 253 } |
| 254 | 254 |
| 255 /// Answers whether [element] is explicitly deferred when referred to from | 255 /// Answers whether [element] is explicitly deferred when referred to from |
| 256 /// [library]. | 256 /// [library]. |
| 257 bool _isExplicitlyDeferred(Element element, LibraryElement library) { | 257 bool _isExplicitlyDeferred(Element element, LibraryElement library) { |
| 258 Link<Import> imports = _getImports(element, library); | 258 Link<Import> imports = _getImports(element, library); |
| 259 // If the element is not imported explicitly, it is implicitly imported | 259 // If the element is not imported explicitly, it is implicitly imported |
| 260 // not deferred. | 260 // not deferred. |
| 261 if (imports.isEmpty) return false; | 261 if (imports.isEmpty) return false; |
| 262 // An element could potentially be loaded by several imports. If all of them | 262 // An element could potentially be loaded by several imports. If all of them |
| 263 // is explicitly deferred, we say the element is explicitly deferred. | 263 // is explicitly deferred, we say the element is explicitly deferred. |
| 264 // TODO(sigurdm): We might want to give a warning if the imports do not | 264 // TODO(sigurdm): We might want to give a warning if the imports do not |
| 265 // agree. | 265 // agree. |
| 266 return imports.every(_isImportDeferred); | 266 return imports.every(_isImportDeferred); |
| 267 } | 267 } |
| 268 | 268 |
| 269 /// Returns a [Link] of every [Import] that imports [element] into [library]. | 269 /// Returns a [Link] of every [Import] that imports [element] into [library]. |
| 270 Link<Import> _getImports(Element element, LibraryElement library) { | 270 Link<Import> _getImports(Element element, LibraryElement library) { |
| 271 if (element.isMember()) { | 271 if (element.isMember) { |
| 272 element = element.getEnclosingClass(); | 272 element = element.enclosingClass; |
| 273 } | 273 } |
| 274 if (element.isAccessor()) { | 274 if (element.isAccessor) { |
| 275 element = (element as FunctionElement).abstractField; | 275 element = (element as FunctionElement).abstractField; |
| 276 } | 276 } |
| 277 return library.getImportsFor(element); | 277 return library.getImportsFor(element); |
| 278 } | 278 } |
| 279 | 279 |
| 280 /// Replaces the imports of [outputUnit] with those in | 280 /// Replaces the imports of [outputUnit] with those in |
| 281 /// [replacementImports]. Because mainOutputUnit has a special handling we | 281 /// [replacementImports]. Because mainOutputUnit has a special handling we |
| 282 /// create a new outputUnit instead, and update the mapping from the | 282 /// create a new outputUnit instead, and update the mapping from the |
| 283 /// dependency to its outputUnit. | 283 /// dependency to its outputUnit. |
| 284 void _replaceOutputUnitImports(dynamic dependency, | 284 void _replaceOutputUnitImports(dynamic dependency, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 301 /// | 301 /// |
| 302 /// The collected dependent elements and constants are are added to | 302 /// The collected dependent elements and constants are are added to |
| 303 /// [elementDependencies] and [constantDependencies] respectively. | 303 /// [elementDependencies] and [constantDependencies] respectively. |
| 304 void _collectDependencies(Element element, | 304 void _collectDependencies(Element element, |
| 305 Set<Element> elementDependencies, | 305 Set<Element> elementDependencies, |
| 306 Set<Constant> constantDependencies) { | 306 Set<Constant> constantDependencies) { |
| 307 TreeElements elements = | 307 TreeElements elements = |
| 308 compiler.enqueuer.resolution.getCachedElements(element); | 308 compiler.enqueuer.resolution.getCachedElements(element); |
| 309 if (elements == null) return; | 309 if (elements == null) return; |
| 310 for (Element dependency in elements.allElements) { | 310 for (Element dependency in elements.allElements) { |
| 311 if (Elements.isLocal(dependency) && !dependency.isFunction()) continue; | 311 if (Elements.isLocal(dependency) && !dependency.isFunction) continue; |
| 312 if (Elements.isUnresolved(dependency)) continue; | 312 if (Elements.isUnresolved(dependency)) continue; |
| 313 if (dependency.isStatement()) continue; | 313 if (dependency.isStatement) continue; |
| 314 elementDependencies.add(dependency); | 314 elementDependencies.add(dependency); |
| 315 } | 315 } |
| 316 elements.forEachConstantNode((Node n, _) { | 316 elements.forEachConstantNode((Node n, _) { |
| 317 // Explicitly depend on the backend constants. | 317 // Explicitly depend on the backend constants. |
| 318 constantDependencies.add( | 318 constantDependencies.add( |
| 319 backend.constants.getConstantForNode(n, elements)); | 319 backend.constants.getConstantForNode(n, elements)); |
| 320 }); | 320 }); |
| 321 elementDependencies.addAll(elements.otherDependencies); | 321 elementDependencies.addAll(elements.otherDependencies); |
| 322 } | 322 } |
| 323 | 323 |
| 324 /// Finds all elements and constants that [element] depends directly on. | 324 /// Finds all elements and constants that [element] depends directly on. |
| 325 /// (not the transitive closure.) | 325 /// (not the transitive closure.) |
| 326 /// | 326 /// |
| 327 /// Adds the results to [elements] and [constants]. | 327 /// Adds the results to [elements] and [constants]. |
| 328 void _collectAllElementsAndConstantsResolvedFrom(Element element, | 328 void _collectAllElementsAndConstantsResolvedFrom(Element element, |
| 329 Set<Element> elements, | 329 Set<Element> elements, |
| 330 Set<Constant> constants) { | 330 Set<Constant> constants) { |
| 331 // TODO(sigurdm): How is metadata on a patch-class handled? | 331 // TODO(sigurdm): How is metadata on a patch-class handled? |
| 332 for (MetadataAnnotation metadata in element.metadata) { | 332 for (MetadataAnnotation metadata in element.metadata) { |
| 333 Constant constant = backend.constants.getConstantForMetadata(metadata); | 333 Constant constant = backend.constants.getConstantForMetadata(metadata); |
| 334 if (constant != null) { | 334 if (constant != null) { |
| 335 constants.add(constant); | 335 constants.add(constant); |
| 336 elements.add(constant.computeType(compiler).element); | 336 elements.add(constant.computeType(compiler).element); |
| 337 } | 337 } |
| 338 } | 338 } |
| 339 if (element.isClass()) { | 339 if (element.isClass) { |
| 340 // If we see a class, add everything its instance members refer | 340 // If we see a class, add everything its instance members refer |
| 341 // to. Static members are not relevant. | 341 // to. Static members are not relevant. |
| 342 ClassElement cls = element.declaration; | 342 ClassElement cls = element.declaration; |
| 343 cls.forEachLocalMember((Element e) { | 343 cls.forEachLocalMember((Element e) { |
| 344 if (!e.isInstanceMember()) return; | 344 if (!e.isInstanceMember) return; |
| 345 _collectDependencies(e.implementation, elements, constants); | 345 _collectDependencies(e.implementation, elements, constants); |
| 346 }); | 346 }); |
| 347 if (cls.implementation != cls) { | 347 if (cls.implementation != cls) { |
| 348 // TODO(ahe): Why doesn't ClassElement.forEachLocalMember do this? | 348 // TODO(ahe): Why doesn't ClassElement.forEachLocalMember do this? |
| 349 cls.implementation.forEachLocalMember((Element e) { | 349 cls.implementation.forEachLocalMember((Element e) { |
| 350 if (!e.isInstanceMember()) return; | 350 if (!e.isInstanceMember) return; |
| 351 _collectDependencies(e.implementation, elements, constants); | 351 _collectDependencies(e.implementation, elements, constants); |
| 352 }); | 352 }); |
| 353 } | 353 } |
| 354 for (var type in cls.implementation.allSupertypes) { | 354 for (var type in cls.implementation.allSupertypes) { |
| 355 elements.add(type.element.implementation); | 355 elements.add(type.element.implementation); |
| 356 } | 356 } |
| 357 elements.add(cls.implementation); | 357 elements.add(cls.implementation); |
| 358 } else if (Elements.isStaticOrTopLevel(element) || | 358 } else if (Elements.isStaticOrTopLevel(element) || |
| 359 element.isConstructor()) { | 359 element.isConstructor) { |
| 360 _collectDependencies(element, elements, constants); | 360 _collectDependencies(element, elements, constants); |
| 361 } | 361 } |
| 362 if (element.isGenerativeConstructor()) { | 362 if (element.isGenerativeConstructor) { |
| 363 // When instantiating a class, we record a reference to the | 363 // When instantiating a class, we record a reference to the |
| 364 // constructor, not the class itself. We must add all the | 364 // constructor, not the class itself. We must add all the |
| 365 // instance members of the constructor's class. | 365 // instance members of the constructor's class. |
| 366 ClassElement implementation = | 366 ClassElement implementation = |
| 367 element.getEnclosingClass().implementation; | 367 element.enclosingClass.implementation; |
| 368 _collectAllElementsAndConstantsResolvedFrom( | 368 _collectAllElementsAndConstantsResolvedFrom( |
| 369 implementation, elements, constants); | 369 implementation, elements, constants); |
| 370 } | 370 } |
| 371 | 371 |
| 372 // Other elements, in particular instance members, are ignored as | 372 // Other elements, in particular instance members, are ignored as |
| 373 // they are processed as part of the class. | 373 // they are processed as part of the class. |
| 374 } | 374 } |
| 375 | 375 |
| 376 /// Returns the transitive closure of all libraries that are imported | 376 /// Returns the transitive closure of all libraries that are imported |
| 377 /// from root without DeferredLibrary annotations. | 377 /// from root without DeferredLibrary annotations. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 | 412 |
| 413 // Here we modify [_importedDeferredBy]. | 413 // Here we modify [_importedDeferredBy]. |
| 414 elements.add(element); | 414 elements.add(element); |
| 415 | 415 |
| 416 Set<Element> dependentElements = new Set<Element>(); | 416 Set<Element> dependentElements = new Set<Element>(); |
| 417 | 417 |
| 418 // This call can modify [_importedDeferredBy] and [_constantsDeferredBy]. | 418 // This call can modify [_importedDeferredBy] and [_constantsDeferredBy]. |
| 419 _collectAllElementsAndConstantsResolvedFrom( | 419 _collectAllElementsAndConstantsResolvedFrom( |
| 420 element, dependentElements, constants); | 420 element, dependentElements, constants); |
| 421 | 421 |
| 422 LibraryElement library = element.getLibrary(); | 422 LibraryElement library = element.library; |
| 423 for (Element dependency in dependentElements) { | 423 for (Element dependency in dependentElements) { |
| 424 if (_isExplicitlyDeferred(dependency, library)) { | 424 if (_isExplicitlyDeferred(dependency, library)) { |
| 425 for (Import deferredImport in _getImports(dependency, library)) { | 425 for (Import deferredImport in _getImports(dependency, library)) { |
| 426 _mapDependencies(dependency, deferredImport); | 426 _mapDependencies(dependency, deferredImport); |
| 427 }; | 427 }; |
| 428 } else { | 428 } else { |
| 429 _mapDependencies(dependency, import); | 429 _mapDependencies(dependency, import); |
| 430 } | 430 } |
| 431 } | 431 } |
| 432 } | 432 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 // class will not be resolved. We just skip it. | 478 // class will not be resolved. We just skip it. |
| 479 if (element is ClassElement &&!element.isResolved) { | 479 if (element is ClassElement &&!element.isResolved) { |
| 480 return; | 480 return; |
| 481 } | 481 } |
| 482 _mapDependencies(element, deferredImport); | 482 _mapDependencies(element, deferredImport); |
| 483 } | 483 } |
| 484 | 484 |
| 485 for (MirrorUsage usage in mirrorUsages) { | 485 for (MirrorUsage usage in mirrorUsages) { |
| 486 if (usage.targets != null) { | 486 if (usage.targets != null) { |
| 487 for (Element dependency in usage.targets) { | 487 for (Element dependency in usage.targets) { |
| 488 if (dependency.isLibrary()) { | 488 if (dependency.isLibrary) { |
| 489 LibraryElement library = dependency; | 489 LibraryElement library = dependency; |
| 490 library.forEachLocalMember(mapDependenciesIfResolved); | 490 library.forEachLocalMember(mapDependenciesIfResolved); |
| 491 } else { | 491 } else { |
| 492 mapDependenciesIfResolved(dependency); | 492 mapDependenciesIfResolved(dependency); |
| 493 } | 493 } |
| 494 } | 494 } |
| 495 } | 495 } |
| 496 if (usage.metaTargets != null) { | 496 if (usage.metaTargets != null) { |
| 497 for (Element dependency in usage.metaTargets) { | 497 for (Element dependency in usage.metaTargets) { |
| 498 _mapDependencies(dependency, deferredImport); | 498 _mapDependencies(dependency, deferredImport); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 690 } | 690 } |
| 691 } | 691 } |
| 692 } | 692 } |
| 693 | 693 |
| 694 void onResolutionComplete(FunctionElement main) { | 694 void onResolutionComplete(FunctionElement main) { |
| 695 if (!splitProgram) { | 695 if (!splitProgram) { |
| 696 allOutputUnits.add(mainOutputUnit); | 696 allOutputUnits.add(mainOutputUnit); |
| 697 return; | 697 return; |
| 698 } | 698 } |
| 699 if (main == null) return; | 699 if (main == null) return; |
| 700 LibraryElement mainLibrary = main.getLibrary(); | 700 LibraryElement mainLibrary = main.library; |
| 701 _importedDeferredBy = new Map<Import, Set<Element>>(); | 701 _importedDeferredBy = new Map<Import, Set<Element>>(); |
| 702 _constantsDeferredBy = new Map<Import, Set<Constant>>(); | 702 _constantsDeferredBy = new Map<Import, Set<Constant>>(); |
| 703 _importedDeferredBy[_fakeMainImport] = _mainElements; | 703 _importedDeferredBy[_fakeMainImport] = _mainElements; |
| 704 | 704 |
| 705 measureElement(mainLibrary, () { | 705 measureElement(mainLibrary, () { |
| 706 | 706 |
| 707 // Starting from main, traverse the program and find all dependencies. | 707 // Starting from main, traverse the program and find all dependencies. |
| 708 _mapDependencies(compiler.mainFunction, _fakeMainImport); | 708 _mapDependencies(compiler.mainFunction, _fakeMainImport); |
| 709 | 709 |
| 710 // Also add "global" dependencies to the main OutputUnit. These are | 710 // Also add "global" dependencies to the main OutputUnit. These are |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 /// | 848 /// |
| 849 /// Returns null for a.loadLibrary() (the special | 849 /// Returns null for a.loadLibrary() (the special |
| 850 /// function loadLibrary is not deferred). And returns the PrefixElement for | 850 /// function loadLibrary is not deferred). And returns the PrefixElement for |
| 851 /// a.run() and a.foo. | 851 /// a.run() and a.foo. |
| 852 /// a.loadLibrary.toString() and a.foo.method() are dynamic sends - and | 852 /// a.loadLibrary.toString() and a.foo.method() are dynamic sends - and |
| 853 /// this functions should not be called on them. | 853 /// this functions should not be called on them. |
| 854 PrefixElement deferredPrefixElement(ast.Send send, TreeElements elements) { | 854 PrefixElement deferredPrefixElement(ast.Send send, TreeElements elements) { |
| 855 Element element = elements[send]; | 855 Element element = elements[send]; |
| 856 // The DeferredLoaderGetter is not deferred, therefore we do not return the | 856 // The DeferredLoaderGetter is not deferred, therefore we do not return the |
| 857 // prefix. | 857 // prefix. |
| 858 if (element != null && element.isDeferredLoaderGetter()) return null; | 858 if (element != null && element.isDeferredLoaderGetter) return null; |
| 859 | 859 |
| 860 ast.Node firstNode(ast.Node node) { | 860 ast.Node firstNode(ast.Node node) { |
| 861 if (node is! ast.Send) { | 861 if (node is! ast.Send) { |
| 862 return node; | 862 return node; |
| 863 } else { | 863 } else { |
| 864 ast.Send send = node; | 864 ast.Send send = node; |
| 865 ast.Node receiver = send.receiver; | 865 ast.Node receiver = send.receiver; |
| 866 ast.Node receiverFirst = firstNode(receiver); | 866 ast.Node receiverFirst = firstNode(receiver); |
| 867 if (receiverFirst != null) { | 867 if (receiverFirst != null) { |
| 868 return receiverFirst; | 868 return receiverFirst; |
| 869 } else { | 869 } else { |
| 870 return firstNode(send.selector); | 870 return firstNode(send.selector); |
| 871 } | 871 } |
| 872 } | 872 } |
| 873 } | 873 } |
| 874 ast.Node first = firstNode(send); | 874 ast.Node first = firstNode(send); |
| 875 ast.Node identifier = first.asIdentifier(); | 875 ast.Node identifier = first.asIdentifier(); |
| 876 if (identifier == null) return null; | 876 if (identifier == null) return null; |
| 877 Element maybePrefix = elements[identifier]; | 877 Element maybePrefix = elements[identifier]; |
| 878 if (maybePrefix != null && maybePrefix.isPrefix()) { | 878 if (maybePrefix != null && maybePrefix.isPrefix) { |
| 879 PrefixElement prefixElement = maybePrefix; | 879 PrefixElement prefixElement = maybePrefix; |
| 880 if (prefixElement.isDeferred) { | 880 if (prefixElement.isDeferred) { |
| 881 return prefixElement; | 881 return prefixElement; |
| 882 } | 882 } |
| 883 } | 883 } |
| 884 return null; | 884 return null; |
| 885 } | 885 } |
| 886 } | 886 } |
| OLD | NEW |