| 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 part of dart2js; | 5 library dart2js.library_loader; |
| 6 |
| 7 import 'dart:async'; |
| 8 import 'dart2jslib.dart' |
| 9 show Compiler, |
| 10 CompilerTask, |
| 11 MessageKind, |
| 12 Script, |
| 13 invariant; |
| 14 import 'elements/elements.dart' |
| 15 show CompilationUnitElement, |
| 16 Element, |
| 17 LibraryElement, |
| 18 PrefixElement; |
| 19 import 'elements/modelx.dart' |
| 20 show CompilationUnitElementX, |
| 21 DeferredLoaderGetterElementX, |
| 22 ErroneousElementX, |
| 23 LibraryElementX, |
| 24 PrefixElementX; |
| 25 import 'helpers/helpers.dart'; |
| 26 import 'native_handler.dart' as native; |
| 27 import 'tree/tree.dart'; |
| 28 import 'util/util.dart' show Link, LinkBuilder; |
| 6 | 29 |
| 7 /** | 30 /** |
| 8 * [CompilerTask] for loading libraries and setting up the import/export scopes. | 31 * [CompilerTask] for loading libraries and setting up the import/export scopes. |
| 9 * | 32 * |
| 10 * The library loader uses four different kinds of URIs in different parts of | 33 * The library loader uses four different kinds of URIs in different parts of |
| 11 * the loading process. | 34 * the loading process. |
| 12 * | 35 * |
| 13 * ## User URI ## | 36 * ## User URI ## |
| 14 * | 37 * |
| 15 * A 'user URI' is a URI provided by the user in code and as the main entry URI | 38 * A 'user URI' is a URI provided by the user in code and as the main entry URI |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 * The distinction between readable URI and resource URI is necessary to ensure | 113 * The distinction between readable URI and resource URI is necessary to ensure |
| 91 * that these imports | 114 * that these imports |
| 92 * | 115 * |
| 93 * import 'package:foo.dart' as a; | 116 * import 'package:foo.dart' as a; |
| 94 * import 'packages/foo.dart' as b; | 117 * import 'packages/foo.dart' as b; |
| 95 * | 118 * |
| 96 * do _not_ resolve to the same library when the package root URI happens to | 119 * do _not_ resolve to the same library when the package root URI happens to |
| 97 * point to the 'packages' folder. | 120 * point to the 'packages' folder. |
| 98 * | 121 * |
| 99 */ | 122 */ |
| 100 abstract class LibraryLoader extends CompilerTask { | 123 abstract class LibraryLoaderTask implements CompilerTask { |
| 101 LibraryLoader(Compiler compiler) : super(compiler); | 124 factory LibraryLoaderTask(Compiler compiler) = _LibraryLoaderTask; |
| 102 | 125 |
| 103 /** | 126 /** |
| 104 * Loads the library specified by the [resolvedUri] and returns its | 127 * Loads the library specified by the [resolvedUri] and returns its |
| 105 * [LibraryElement]. | 128 * [LibraryElement]. |
| 106 * | 129 * |
| 107 * If the library is not already loaded, the method creates the | 130 * If the library is not already loaded, the method creates the |
| 108 * [LibraryElement] for the library and computes the import/export scope, | 131 * [LibraryElement] for the library and computes the import/export scope, |
| 109 * loading and computing the import/export scopes of all required libraries in | 132 * loading and computing the import/export scopes of all required libraries in |
| 110 * the process. The method handles cyclic dependency between libraries. | 133 * the process. The method handles cyclic dependency between libraries. |
| 111 * | |
| 112 * This is the main entry point for [LibraryLoader]. | |
| 113 */ | 134 */ |
| 114 Future<LibraryElement> loadLibrary(Uri resolvedUri); | 135 Future<LibraryElement> loadLibrary(Uri resolvedUri); |
| 115 | 136 |
| 116 // TODO(johnniwinther): Remove this when patches don't need special parsing. | 137 /// Reset the library loader task to prepare for compilation. This is used |
| 117 Future registerLibraryFromTag(LibraryDependencyHandler handler, | 138 /// for incremental compilation. |
| 118 LibraryElement library, | 139 void reset(); |
| 119 LibraryDependency tag); | 140 |
| 141 /// Reuse [library] from a previous compilation. This is used for incremental |
| 142 /// compilation. |
| 143 void reuseLibrary(LibraryElement library); |
| 144 } |
| 145 |
| 146 /// Handle for creating synthesized/patch libraries during library loading. |
| 147 abstract class LibraryLoader { |
| 148 /// This method must be called when a new synthesized/patch library has been |
| 149 /// created to ensure that [library] will part of library dependency graph |
| 150 /// used for computing import/export scopes. |
| 151 void registerNewLibrary(LibraryElement library); |
| 152 |
| 153 /// This method must be called when a new synthesized/patch library has been |
| 154 /// scanned in order to process the library tags in [library] and thus handle |
| 155 /// imports/exports/parts in the synthesized/patch library. |
| 156 Future processLibraryTags(LibraryElement library); |
| 120 } | 157 } |
| 121 | 158 |
| 122 /** | 159 /** |
| 123 * [CombinatorFilter] is a succinct representation of a list of combinators from | 160 * [CombinatorFilter] is a succinct representation of a list of combinators from |
| 124 * a library dependency tag. | 161 * a library dependency tag. |
| 125 */ | 162 */ |
| 126 class CombinatorFilter { | 163 class CombinatorFilter { |
| 127 const CombinatorFilter(); | 164 const CombinatorFilter(); |
| 128 | 165 |
| 129 /** | 166 /** |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 HideFilter(this.excludedNames); | 235 HideFilter(this.excludedNames); |
| 199 | 236 |
| 200 bool exclude(Element element) => excludedNames.contains(element.name); | 237 bool exclude(Element element) => excludedNames.contains(element.name); |
| 201 } | 238 } |
| 202 | 239 |
| 203 /** | 240 /** |
| 204 * Implementation class for [LibraryLoader]. The distinction between | 241 * Implementation class for [LibraryLoader]. The distinction between |
| 205 * [LibraryLoader] and [LibraryLoaderTask] is made to hide internal members from | 242 * [LibraryLoader] and [LibraryLoaderTask] is made to hide internal members from |
| 206 * the [LibraryLoader] interface. | 243 * the [LibraryLoader] interface. |
| 207 */ | 244 */ |
| 208 class LibraryLoaderTask extends LibraryLoader { | 245 class _LibraryLoaderTask extends CompilerTask implements LibraryLoaderTask { |
| 209 LibraryLoaderTask(Compiler compiler) : super(compiler); | 246 _LibraryLoaderTask(Compiler compiler) : super(compiler); |
| 210 String get name => 'LibraryLoader'; | 247 String get name => 'LibraryLoader'; |
| 211 | 248 |
| 212 final Map<Uri, LibraryElement> libraryResourceUriMap = | 249 final Map<Uri, LibraryElement> libraryResourceUriMap = |
| 213 new Map<Uri, LibraryElement>(); | 250 new Map<Uri, LibraryElement>(); |
| 214 final Map<String, LibraryElement> libraryNames = | 251 final Map<String, LibraryElement> libraryNames = |
| 215 new Map<String, LibraryElement>(); | 252 new Map<String, LibraryElement>(); |
| 216 | 253 |
| 217 LibraryDependencyHandler currentHandler; | 254 LibraryDependencyHandler currentHandler; |
| 218 | 255 |
| 256 void reset() { |
| 257 assert(currentHandler == null); |
| 258 libraryResourceUriMap.clear(); |
| 259 libraryNames.clear(); |
| 260 } |
| 261 |
| 262 void reuseLibrary(LibraryElement library) { |
| 263 String name = library.getLibraryOrScriptName(); |
| 264 Uri resourceUri = library.entryCompilationUnit.script.resourceUri; |
| 265 libraryResourceUriMap[resourceUri] = library; |
| 266 libraryNames[name] = library; |
| 267 } |
| 268 |
| 219 Future<LibraryElement> loadLibrary(Uri resolvedUri) { | 269 Future<LibraryElement> loadLibrary(Uri resolvedUri) { |
| 220 return measure(() { | 270 return measure(() { |
| 221 assert(currentHandler == null); | 271 assert(currentHandler == null); |
| 222 // TODO(johnniwinther): Ensure that currentHandler correctly encloses the | 272 // TODO(johnniwinther): Ensure that currentHandler correctly encloses the |
| 223 // loading of a library cluster. | 273 // loading of a library cluster. |
| 224 currentHandler = new LibraryDependencyHandler(compiler); | 274 currentHandler = new LibraryDependencyHandler(this); |
| 225 return createLibrary(currentHandler, null, resolvedUri) | 275 return createLibrary(currentHandler, null, resolvedUri) |
| 226 .then((LibraryElement library) { | 276 .then((LibraryElement library) { |
| 227 return compiler.withCurrentElement(library, () { | 277 return compiler.withCurrentElement(library, () { |
| 228 return measure(() { | 278 return measure(() { |
| 229 currentHandler.computeExports(); | 279 currentHandler.computeExports(); |
| 230 Map<Uri, LibraryElement> loadedLibraries = <Uri, LibraryElement>{}; | 280 Map<Uri, LibraryElement> loadedLibraries = <Uri, LibraryElement>{}; |
| 231 currentHandler.loadedLibraries.forEach( | 281 currentHandler.loadedLibraries.forEach( |
| 232 (LibraryElement loadedLibrary) { | 282 (LibraryElement loadedLibrary) { |
| 233 loadedLibraries[loadedLibrary.canonicalUri] = loadedLibrary; | 283 loadedLibraries[loadedLibrary.canonicalUri] = loadedLibrary; |
| 234 }); | 284 }); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 263 MessageKind.GENERIC, {'text': 'Error: Out of order.'}); | 313 MessageKind.GENERIC, {'text': 'Error: Out of order.'}); |
| 264 return tagState; | 314 return tagState; |
| 265 } | 315 } |
| 266 return TagState.NEXT[value]; | 316 return TagState.NEXT[value]; |
| 267 } | 317 } |
| 268 | 318 |
| 269 bool importsDartCore = false; | 319 bool importsDartCore = false; |
| 270 var libraryDependencies = new LinkBuilder<LibraryDependency>(); | 320 var libraryDependencies = new LinkBuilder<LibraryDependency>(); |
| 271 Uri base = library.entryCompilationUnit.script.readableUri; | 321 Uri base = library.entryCompilationUnit.script.readableUri; |
| 272 | 322 |
| 273 // TODO(rnystrom): Remove .toList() here if #11523 is fixed. | 323 // TODO(johnniwinther): Reverse the tag list on access and cache the result. |
| 274 return Future.forEach(library.tags.reverse().toList(), (LibraryTag tag) { | 324 return Future.forEach(library.tags.reverse().toList(), (LibraryTag tag) { |
| 275 return compiler.withCurrentElement(library, () { | 325 return compiler.withCurrentElement(library, () { |
| 276 if (tag.isImport) { | 326 if (tag.isImport) { |
| 277 Import import = tag; | 327 Import import = tag; |
| 278 tagState = checkTag(TagState.IMPORT_OR_EXPORT, import); | 328 tagState = checkTag(TagState.IMPORT_OR_EXPORT, import); |
| 279 if (import.uri.dartString.slowToString() == 'dart:core') { | 329 if (import.uri.dartString.slowToString() == 'dart:core') { |
| 280 importsDartCore = true; | 330 importsDartCore = true; |
| 281 } | 331 } |
| 282 libraryDependencies.addLast(import); | 332 libraryDependencies.addLast(import); |
| 283 } else if (tag.isExport) { | 333 } else if (tag.isExport) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 294 Part part = tag; | 344 Part part = tag; |
| 295 StringNode uri = part.uri; | 345 StringNode uri = part.uri; |
| 296 Uri resolvedUri = base.resolve(uri.dartString.slowToString()); | 346 Uri resolvedUri = base.resolve(uri.dartString.slowToString()); |
| 297 tagState = checkTag(TagState.SOURCE, part); | 347 tagState = checkTag(TagState.SOURCE, part); |
| 298 return scanPart(part, resolvedUri, library); | 348 return scanPart(part, resolvedUri, library); |
| 299 } else { | 349 } else { |
| 300 compiler.internalError(tag, "Unhandled library tag."); | 350 compiler.internalError(tag, "Unhandled library tag."); |
| 301 } | 351 } |
| 302 }); | 352 }); |
| 303 }).then((_) { | 353 }).then((_) { |
| 304 // TODO(johnniwinther): Move callback to after patching. | 354 return compiler.onLibraryScanned(library, handler); |
| 305 compiler.onLibraryScanned(library); | 355 }).then((_) { |
| 306 return compiler.withCurrentElement(library, () { | 356 return compiler.withCurrentElement(library, () { |
| 307 checkDuplicatedLibraryName(library); | 357 checkDuplicatedLibraryName(library); |
| 308 // Apply patch, if any. | 358 |
| 309 if (library.isPlatformLibrary) { | |
| 310 return patchDartLibrary(handler, library, library.canonicalUri.path); | |
| 311 } | |
| 312 }); | |
| 313 }).then((_) { | |
| 314 return compiler.withCurrentElement(library, () { | |
| 315 // Import dart:core if not already imported. | 359 // Import dart:core if not already imported. |
| 316 if (!importsDartCore && !isDartCore(library.canonicalUri)) { | 360 if (!importsDartCore && !isDartCore(library.canonicalUri)) { |
| 317 return loadCoreLibrary(handler).then((LibraryElement coreLibrary) { | 361 return loadCoreLibrary(handler).then((LibraryElement coreLibrary) { |
| 318 handler.registerDependency(library, null, coreLibrary); | 362 handler.registerDependency(library, null, coreLibrary); |
| 319 }); | 363 }); |
| 320 } | 364 } |
| 321 }); | 365 }); |
| 322 }).then((_) { | 366 }).then((_) { |
| 323 // TODO(rnystrom): Remove .toList() here if #11523 is fixed. | |
| 324 return Future.forEach(libraryDependencies.toLink().toList(), (tag) { | 367 return Future.forEach(libraryDependencies.toLink().toList(), (tag) { |
| 325 return compiler.withCurrentElement(library, () { | 368 return compiler.withCurrentElement(library, () { |
| 326 return registerLibraryFromTag(handler, library, tag); | 369 return registerLibraryFromTag(handler, library, tag); |
| 327 }); | 370 }); |
| 328 }); | 371 }); |
| 329 }); | 372 }); |
| 330 } | 373 } |
| 331 | 374 |
| 332 void checkDuplicatedLibraryName(LibraryElement library) { | 375 void checkDuplicatedLibraryName(LibraryElement library) { |
| 333 Uri resourceUri = library.entryCompilationUnit.script.resourceUri; | 376 Uri resourceUri = library.entryCompilationUnit.script.resourceUri; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 return new Future.value(compiler.coreLibrary); | 422 return new Future.value(compiler.coreLibrary); |
| 380 } | 423 } |
| 381 | 424 |
| 382 Uri coreUri = new Uri(scheme: 'dart', path: 'core'); | 425 Uri coreUri = new Uri(scheme: 'dart', path: 'core'); |
| 383 return createLibrary(handler, null, coreUri).then((LibraryElement library) { | 426 return createLibrary(handler, null, coreUri).then((LibraryElement library) { |
| 384 compiler.coreLibrary = library; | 427 compiler.coreLibrary = library; |
| 385 return library; | 428 return library; |
| 386 }); | 429 }); |
| 387 } | 430 } |
| 388 | 431 |
| 389 Future patchDartLibrary(LibraryDependencyHandler handler, | |
| 390 LibraryElement library, | |
| 391 String dartLibraryPath) { | |
| 392 if (library.isPatched) return new Future.value(); | |
| 393 Uri patchUri = compiler.resolvePatchUri(dartLibraryPath); | |
| 394 if (patchUri == null) return new Future.value(); | |
| 395 | |
| 396 return compiler.patchParser.patchLibrary(handler, patchUri, library); | |
| 397 } | |
| 398 | |
| 399 /** | 432 /** |
| 400 * Handle a part tag in the scope of [library]. The [resolvedUri] given is | 433 * Handle a part tag in the scope of [library]. The [resolvedUri] given is |
| 401 * used as is, any URI resolution should be done beforehand. | 434 * used as is, any URI resolution should be done beforehand. |
| 402 */ | 435 */ |
| 403 Future scanPart(Part part, Uri resolvedUri, LibraryElement library) { | 436 Future scanPart(Part part, Uri resolvedUri, LibraryElement library) { |
| 404 if (!resolvedUri.isAbsolute) throw new ArgumentError(resolvedUri); | 437 if (!resolvedUri.isAbsolute) throw new ArgumentError(resolvedUri); |
| 405 Uri readableUri = compiler.translateResolvedUri(library, resolvedUri, part); | 438 Uri readableUri = compiler.translateResolvedUri(library, resolvedUri, part); |
| 406 if (readableUri == null) return new Future.value(); | 439 if (readableUri == null) return new Future.value(); |
| 407 return compiler.withCurrentElement(library, () { | 440 return compiler.withCurrentElement(library, () { |
| 408 return compiler.readScript(part, readableUri). | 441 return compiler.readScript(part, readableUri). |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 LibraryElement library = compiler.libraries[resolvedUri.toString()]; | 491 LibraryElement library = compiler.libraries[resolvedUri.toString()]; |
| 459 if (library != null) { | 492 if (library != null) { |
| 460 return new Future.value(library); | 493 return new Future.value(library); |
| 461 } | 494 } |
| 462 return compiler.withCurrentElement(importingLibrary, () { | 495 return compiler.withCurrentElement(importingLibrary, () { |
| 463 return compiler.readScript(node, readableUri) | 496 return compiler.readScript(node, readableUri) |
| 464 .then((Script script) { | 497 .then((Script script) { |
| 465 if (script == null) return null; | 498 if (script == null) return null; |
| 466 LibraryElement element = new LibraryElementX(script, resolvedUri); | 499 LibraryElement element = new LibraryElementX(script, resolvedUri); |
| 467 compiler.withCurrentElement(element, () { | 500 compiler.withCurrentElement(element, () { |
| 468 compiler.onLibraryCreated(element); | |
| 469 handler.registerNewLibrary(element); | 501 handler.registerNewLibrary(element); |
| 470 native.maybeEnableNative(compiler, element); | 502 native.maybeEnableNative(compiler, element); |
| 471 compiler.libraries[resolvedUri.toString()] = element; | 503 compiler.libraries[resolvedUri.toString()] = element; |
| 472 compiler.scanner.scanLibrary(element); | 504 compiler.scanner.scanLibrary(element); |
| 473 }); | 505 }); |
| 474 return processLibraryTags(handler, element).then((_) { | 506 return processLibraryTags(handler, element).then((_) { |
| 475 compiler.withCurrentElement(element, () { | 507 compiler.withCurrentElement(element, () { |
| 476 handler.registerLibraryExports(element); | 508 handler.registerLibraryExports(element); |
| 477 }); | 509 }); |
| 478 return element; | 510 return element; |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 800 } | 832 } |
| 801 | 833 |
| 802 /** | 834 /** |
| 803 * Helper class used for computing the possibly cyclic import/export scopes of | 835 * Helper class used for computing the possibly cyclic import/export scopes of |
| 804 * a set of libraries. | 836 * a set of libraries. |
| 805 * | 837 * |
| 806 * This class is used by [ScannerTask.scanLibrary] to collect all newly loaded | 838 * This class is used by [ScannerTask.scanLibrary] to collect all newly loaded |
| 807 * libraries and to compute their import/export scopes through a fixed-point | 839 * libraries and to compute their import/export scopes through a fixed-point |
| 808 * algorithm. | 840 * algorithm. |
| 809 */ | 841 */ |
| 810 class LibraryDependencyHandler { | 842 class LibraryDependencyHandler implements LibraryLoader { |
| 811 final Compiler compiler; | 843 final _LibraryLoaderTask task; |
| 812 | 844 |
| 813 /** | 845 /** |
| 814 * Newly loaded libraries and their corresponding node in the library | 846 * Newly loaded libraries and their corresponding node in the library |
| 815 * dependency graph. Libraries that have already been fully loaded are not | 847 * dependency graph. Libraries that have already been fully loaded are not |
| 816 * part of the dependency graph of this handler since their export scopes have | 848 * part of the dependency graph of this handler since their export scopes have |
| 817 * already been computed. | 849 * already been computed. |
| 818 */ | 850 */ |
| 819 Map<LibraryElement, LibraryDependencyNode> nodeMap = | 851 Map<LibraryElement, LibraryDependencyNode> nodeMap = |
| 820 new Map<LibraryElement, LibraryDependencyNode>(); | 852 new Map<LibraryElement, LibraryDependencyNode>(); |
| 821 | 853 |
| 822 LibraryDependencyHandler(Compiler this.compiler); | 854 LibraryDependencyHandler(this.task); |
| 855 |
| 856 Compiler get compiler => task.compiler; |
| 823 | 857 |
| 824 /// The libraries loaded with this handler. | 858 /// The libraries loaded with this handler. |
| 825 Iterable<LibraryElement> get loadedLibraries => nodeMap.keys; | 859 Iterable<LibraryElement> get loadedLibraries => nodeMap.keys; |
| 826 | 860 |
| 827 /** | 861 /** |
| 828 * Performs a fixed-point computation on the export scopes of all registered | 862 * Performs a fixed-point computation on the export scopes of all registered |
| 829 * libraries and creates the import/export of the libraries based on the | 863 * libraries and creates the import/export of the libraries based on the |
| 830 * fixed-point. | 864 * fixed-point. |
| 831 */ | 865 */ |
| 832 void computeExports() { | 866 void computeExports() { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 901 message: "$library has not been registered")); | 935 message: "$library has not been registered")); |
| 902 importingNode.registerImportDependency(tag, loadedLibrary); | 936 importingNode.registerImportDependency(tag, loadedLibrary); |
| 903 } | 937 } |
| 904 } | 938 } |
| 905 | 939 |
| 906 /** | 940 /** |
| 907 * Registers [library] for the processing of its import/export scope. | 941 * Registers [library] for the processing of its import/export scope. |
| 908 */ | 942 */ |
| 909 void registerNewLibrary(LibraryElement library) { | 943 void registerNewLibrary(LibraryElement library) { |
| 910 nodeMap[library] = new LibraryDependencyNode(library); | 944 nodeMap[library] = new LibraryDependencyNode(library); |
| 945 compiler.onLibraryCreated(library); |
| 911 } | 946 } |
| 912 | 947 |
| 913 /** | 948 /** |
| 914 * Registers all top-level entities of [library] as starting point for the | 949 * Registers all top-level entities of [library] as starting point for the |
| 915 * fixed-point computation of the import/export scopes. | 950 * fixed-point computation of the import/export scopes. |
| 916 */ | 951 */ |
| 917 void registerLibraryExports(LibraryElement library) { | 952 void registerLibraryExports(LibraryElement library) { |
| 918 nodeMap[library].registerInitialExports(); | 953 nodeMap[library].registerInitialExports(); |
| 919 } | 954 } |
| 955 |
| 956 Future processLibraryTags(LibraryElement library) { |
| 957 return task.processLibraryTags(this, library); |
| 958 } |
| 920 } | 959 } |
| OLD | NEW |