| 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); |
| 136 } |
| 115 | 137 |
| 116 // TODO(johnniwinther): Remove this when patches don't need special parsing. | 138 /// Handle for creating synthesized/patch libraries during library loading. |
| 117 Future registerLibraryFromTag(LibraryDependencyHandler handler, | 139 abstract class LibraryLoader { |
| 118 LibraryElement library, | 140 /// This method must be called when a new synthesized/patch library has been |
| 119 LibraryDependency tag); | 141 /// created to ensure that [library] will part of library dependency graph |
| 142 /// used for computing import/export scopes. |
| 143 void registerNewLibrary(LibraryElement library); |
| 144 |
| 145 /// This method must be called when a new synthesized/patch library has been |
| 146 /// scanned in order to process the library tags in [library] and thus handle |
| 147 /// imports/exports/parts in the synthesized/patch library. |
| 148 Future processLibraryTags(LibraryElement library); |
| 120 } | 149 } |
| 121 | 150 |
| 122 /** | 151 /** |
| 123 * [CombinatorFilter] is a succinct representation of a list of combinators from | 152 * [CombinatorFilter] is a succinct representation of a list of combinators from |
| 124 * a library dependency tag. | 153 * a library dependency tag. |
| 125 */ | 154 */ |
| 126 class CombinatorFilter { | 155 class CombinatorFilter { |
| 127 const CombinatorFilter(); | 156 const CombinatorFilter(); |
| 128 | 157 |
| 129 /** | 158 /** |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 HideFilter(this.excludedNames); | 227 HideFilter(this.excludedNames); |
| 199 | 228 |
| 200 bool exclude(Element element) => excludedNames.contains(element.name); | 229 bool exclude(Element element) => excludedNames.contains(element.name); |
| 201 } | 230 } |
| 202 | 231 |
| 203 /** | 232 /** |
| 204 * Implementation class for [LibraryLoader]. The distinction between | 233 * Implementation class for [LibraryLoader]. The distinction between |
| 205 * [LibraryLoader] and [LibraryLoaderTask] is made to hide internal members from | 234 * [LibraryLoader] and [LibraryLoaderTask] is made to hide internal members from |
| 206 * the [LibraryLoader] interface. | 235 * the [LibraryLoader] interface. |
| 207 */ | 236 */ |
| 208 class LibraryLoaderTask extends LibraryLoader { | 237 class _LibraryLoaderTask extends CompilerTask implements LibraryLoaderTask { |
| 209 LibraryLoaderTask(Compiler compiler) : super(compiler); | 238 _LibraryLoaderTask(Compiler compiler) : super(compiler); |
| 210 String get name => 'LibraryLoader'; | 239 String get name => 'LibraryLoader'; |
| 211 | 240 |
| 212 final Map<Uri, LibraryElement> libraryResourceUriMap = | 241 final Map<Uri, LibraryElement> libraryResourceUriMap = |
| 213 new Map<Uri, LibraryElement>(); | 242 new Map<Uri, LibraryElement>(); |
| 214 final Map<String, LibraryElement> libraryNames = | 243 final Map<String, LibraryElement> libraryNames = |
| 215 new Map<String, LibraryElement>(); | 244 new Map<String, LibraryElement>(); |
| 216 | 245 |
| 217 LibraryDependencyHandler currentHandler; | 246 LibraryDependencyHandler currentHandler; |
| 218 | 247 |
| 219 Future<LibraryElement> loadLibrary(Uri resolvedUri) { | 248 Future<LibraryElement> loadLibrary(Uri resolvedUri) { |
| 220 return measure(() { | 249 return measure(() { |
| 221 assert(currentHandler == null); | 250 assert(currentHandler == null); |
| 222 // TODO(johnniwinther): Ensure that currentHandler correctly encloses the | 251 // TODO(johnniwinther): Ensure that currentHandler correctly encloses the |
| 223 // loading of a library cluster. | 252 // loading of a library cluster. |
| 224 currentHandler = new LibraryDependencyHandler(compiler); | 253 currentHandler = new LibraryDependencyHandler(this); |
| 225 return createLibrary(currentHandler, null, resolvedUri) | 254 return createLibrary(currentHandler, null, resolvedUri) |
| 226 .then((LibraryElement library) { | 255 .then((LibraryElement library) { |
| 227 return compiler.withCurrentElement(library, () { | 256 return compiler.withCurrentElement(library, () { |
| 228 return measure(() { | 257 return measure(() { |
| 229 currentHandler.computeExports(); | 258 currentHandler.computeExports(); |
| 230 Map<Uri, LibraryElement> loadedLibraries = <Uri, LibraryElement>{}; | 259 Map<Uri, LibraryElement> loadedLibraries = <Uri, LibraryElement>{}; |
| 231 currentHandler.loadedLibraries.forEach( | 260 currentHandler.loadedLibraries.forEach( |
| 232 (LibraryElement loadedLibrary) { | 261 (LibraryElement loadedLibrary) { |
| 233 loadedLibraries[loadedLibrary.canonicalUri] = loadedLibrary; | 262 loadedLibraries[loadedLibrary.canonicalUri] = loadedLibrary; |
| 234 }); | 263 }); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 263 MessageKind.GENERIC, {'text': 'Error: Out of order.'}); | 292 MessageKind.GENERIC, {'text': 'Error: Out of order.'}); |
| 264 return tagState; | 293 return tagState; |
| 265 } | 294 } |
| 266 return TagState.NEXT[value]; | 295 return TagState.NEXT[value]; |
| 267 } | 296 } |
| 268 | 297 |
| 269 bool importsDartCore = false; | 298 bool importsDartCore = false; |
| 270 var libraryDependencies = new LinkBuilder<LibraryDependency>(); | 299 var libraryDependencies = new LinkBuilder<LibraryDependency>(); |
| 271 Uri base = library.entryCompilationUnit.script.readableUri; | 300 Uri base = library.entryCompilationUnit.script.readableUri; |
| 272 | 301 |
| 273 // TODO(rnystrom): Remove .toList() here if #11523 is fixed. | 302 // TODO(johnniwinther): Reverse the tag list on access and cache the result. |
| 274 return Future.forEach(library.tags.reverse().toList(), (LibraryTag tag) { | 303 return Future.forEach(library.tags.reverse().toList(), (LibraryTag tag) { |
| 275 return compiler.withCurrentElement(library, () { | 304 return compiler.withCurrentElement(library, () { |
| 276 if (tag.isImport) { | 305 if (tag.isImport) { |
| 277 Import import = tag; | 306 Import import = tag; |
| 278 tagState = checkTag(TagState.IMPORT_OR_EXPORT, import); | 307 tagState = checkTag(TagState.IMPORT_OR_EXPORT, import); |
| 279 if (import.uri.dartString.slowToString() == 'dart:core') { | 308 if (import.uri.dartString.slowToString() == 'dart:core') { |
| 280 importsDartCore = true; | 309 importsDartCore = true; |
| 281 } | 310 } |
| 282 libraryDependencies.addLast(import); | 311 libraryDependencies.addLast(import); |
| 283 } else if (tag.isExport) { | 312 } else if (tag.isExport) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 294 Part part = tag; | 323 Part part = tag; |
| 295 StringNode uri = part.uri; | 324 StringNode uri = part.uri; |
| 296 Uri resolvedUri = base.resolve(uri.dartString.slowToString()); | 325 Uri resolvedUri = base.resolve(uri.dartString.slowToString()); |
| 297 tagState = checkTag(TagState.SOURCE, part); | 326 tagState = checkTag(TagState.SOURCE, part); |
| 298 return scanPart(part, resolvedUri, library); | 327 return scanPart(part, resolvedUri, library); |
| 299 } else { | 328 } else { |
| 300 compiler.internalError(tag, "Unhandled library tag."); | 329 compiler.internalError(tag, "Unhandled library tag."); |
| 301 } | 330 } |
| 302 }); | 331 }); |
| 303 }).then((_) { | 332 }).then((_) { |
| 304 // TODO(johnniwinther): Move callback to after patching. | 333 return compiler.onLibraryScanned(library, handler); |
| 305 compiler.onLibraryScanned(library); | 334 }).then((_) { |
| 306 return compiler.withCurrentElement(library, () { | 335 return compiler.withCurrentElement(library, () { |
| 307 checkDuplicatedLibraryName(library); | 336 checkDuplicatedLibraryName(library); |
| 308 // Apply patch, if any. | 337 |
| 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. | 338 // Import dart:core if not already imported. |
| 316 if (!importsDartCore && !isDartCore(library.canonicalUri)) { | 339 if (!importsDartCore && !isDartCore(library.canonicalUri)) { |
| 317 return loadCoreLibrary(handler).then((LibraryElement coreLibrary) { | 340 return loadCoreLibrary(handler).then((LibraryElement coreLibrary) { |
| 318 handler.registerDependency(library, null, coreLibrary); | 341 handler.registerDependency(library, null, coreLibrary); |
| 319 }); | 342 }); |
| 320 } | 343 } |
| 321 }); | 344 }); |
| 322 }).then((_) { | 345 }).then((_) { |
| 323 // TODO(rnystrom): Remove .toList() here if #11523 is fixed. | |
| 324 return Future.forEach(libraryDependencies.toLink().toList(), (tag) { | 346 return Future.forEach(libraryDependencies.toLink().toList(), (tag) { |
| 325 return compiler.withCurrentElement(library, () { | 347 return compiler.withCurrentElement(library, () { |
| 326 return registerLibraryFromTag(handler, library, tag); | 348 return registerLibraryFromTag(handler, library, tag); |
| 327 }); | 349 }); |
| 328 }); | 350 }); |
| 329 }); | 351 }); |
| 330 } | 352 } |
| 331 | 353 |
| 332 void checkDuplicatedLibraryName(LibraryElement library) { | 354 void checkDuplicatedLibraryName(LibraryElement library) { |
| 333 Uri resourceUri = library.entryCompilationUnit.script.resourceUri; | 355 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); | 401 return new Future.value(compiler.coreLibrary); |
| 380 } | 402 } |
| 381 | 403 |
| 382 Uri coreUri = new Uri(scheme: 'dart', path: 'core'); | 404 Uri coreUri = new Uri(scheme: 'dart', path: 'core'); |
| 383 return createLibrary(handler, null, coreUri).then((LibraryElement library) { | 405 return createLibrary(handler, null, coreUri).then((LibraryElement library) { |
| 384 compiler.coreLibrary = library; | 406 compiler.coreLibrary = library; |
| 385 return library; | 407 return library; |
| 386 }); | 408 }); |
| 387 } | 409 } |
| 388 | 410 |
| 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 /** | 411 /** |
| 400 * Handle a part tag in the scope of [library]. The [resolvedUri] given is | 412 * Handle a part tag in the scope of [library]. The [resolvedUri] given is |
| 401 * used as is, any URI resolution should be done beforehand. | 413 * used as is, any URI resolution should be done beforehand. |
| 402 */ | 414 */ |
| 403 Future scanPart(Part part, Uri resolvedUri, LibraryElement library) { | 415 Future scanPart(Part part, Uri resolvedUri, LibraryElement library) { |
| 404 if (!resolvedUri.isAbsolute) throw new ArgumentError(resolvedUri); | 416 if (!resolvedUri.isAbsolute) throw new ArgumentError(resolvedUri); |
| 405 Uri readableUri = compiler.translateResolvedUri(library, resolvedUri, part); | 417 Uri readableUri = compiler.translateResolvedUri(library, resolvedUri, part); |
| 406 if (readableUri == null) return new Future.value(); | 418 if (readableUri == null) return new Future.value(); |
| 407 return compiler.withCurrentElement(library, () { | 419 return compiler.withCurrentElement(library, () { |
| 408 return compiler.readScript(part, readableUri). | 420 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()]; | 470 LibraryElement library = compiler.libraries[resolvedUri.toString()]; |
| 459 if (library != null) { | 471 if (library != null) { |
| 460 return new Future.value(library); | 472 return new Future.value(library); |
| 461 } | 473 } |
| 462 return compiler.withCurrentElement(importingLibrary, () { | 474 return compiler.withCurrentElement(importingLibrary, () { |
| 463 return compiler.readScript(node, readableUri) | 475 return compiler.readScript(node, readableUri) |
| 464 .then((Script script) { | 476 .then((Script script) { |
| 465 if (script == null) return null; | 477 if (script == null) return null; |
| 466 LibraryElement element = new LibraryElementX(script, resolvedUri); | 478 LibraryElement element = new LibraryElementX(script, resolvedUri); |
| 467 compiler.withCurrentElement(element, () { | 479 compiler.withCurrentElement(element, () { |
| 468 compiler.onLibraryCreated(element); | |
| 469 handler.registerNewLibrary(element); | 480 handler.registerNewLibrary(element); |
| 470 native.maybeEnableNative(compiler, element); | 481 native.maybeEnableNative(compiler, element); |
| 471 compiler.libraries[resolvedUri.toString()] = element; | 482 compiler.libraries[resolvedUri.toString()] = element; |
| 472 compiler.scanner.scanLibrary(element); | 483 compiler.scanner.scanLibrary(element); |
| 473 }); | 484 }); |
| 474 return processLibraryTags(handler, element).then((_) { | 485 return processLibraryTags(handler, element).then((_) { |
| 475 compiler.withCurrentElement(element, () { | 486 compiler.withCurrentElement(element, () { |
| 476 handler.registerLibraryExports(element); | 487 handler.registerLibraryExports(element); |
| 477 }); | 488 }); |
| 478 return element; | 489 return element; |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 800 } | 811 } |
| 801 | 812 |
| 802 /** | 813 /** |
| 803 * Helper class used for computing the possibly cyclic import/export scopes of | 814 * Helper class used for computing the possibly cyclic import/export scopes of |
| 804 * a set of libraries. | 815 * a set of libraries. |
| 805 * | 816 * |
| 806 * This class is used by [ScannerTask.scanLibrary] to collect all newly loaded | 817 * 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 | 818 * libraries and to compute their import/export scopes through a fixed-point |
| 808 * algorithm. | 819 * algorithm. |
| 809 */ | 820 */ |
| 810 class LibraryDependencyHandler { | 821 class LibraryDependencyHandler implements LibraryLoader { |
| 811 final Compiler compiler; | 822 final _LibraryLoaderTask task; |
| 812 | 823 |
| 813 /** | 824 /** |
| 814 * Newly loaded libraries and their corresponding node in the library | 825 * Newly loaded libraries and their corresponding node in the library |
| 815 * dependency graph. Libraries that have already been fully loaded are not | 826 * 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 | 827 * part of the dependency graph of this handler since their export scopes have |
| 817 * already been computed. | 828 * already been computed. |
| 818 */ | 829 */ |
| 819 Map<LibraryElement, LibraryDependencyNode> nodeMap = | 830 Map<LibraryElement, LibraryDependencyNode> nodeMap = |
| 820 new Map<LibraryElement, LibraryDependencyNode>(); | 831 new Map<LibraryElement, LibraryDependencyNode>(); |
| 821 | 832 |
| 822 LibraryDependencyHandler(Compiler this.compiler); | 833 LibraryDependencyHandler(this.task); |
| 834 |
| 835 Compiler get compiler => task.compiler; |
| 823 | 836 |
| 824 /// The libraries loaded with this handler. | 837 /// The libraries loaded with this handler. |
| 825 Iterable<LibraryElement> get loadedLibraries => nodeMap.keys; | 838 Iterable<LibraryElement> get loadedLibraries => nodeMap.keys; |
| 826 | 839 |
| 827 /** | 840 /** |
| 828 * Performs a fixed-point computation on the export scopes of all registered | 841 * 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 | 842 * libraries and creates the import/export of the libraries based on the |
| 830 * fixed-point. | 843 * fixed-point. |
| 831 */ | 844 */ |
| 832 void computeExports() { | 845 void computeExports() { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 901 message: "$library has not been registered")); | 914 message: "$library has not been registered")); |
| 902 importingNode.registerImportDependency(tag, loadedLibrary); | 915 importingNode.registerImportDependency(tag, loadedLibrary); |
| 903 } | 916 } |
| 904 } | 917 } |
| 905 | 918 |
| 906 /** | 919 /** |
| 907 * Registers [library] for the processing of its import/export scope. | 920 * Registers [library] for the processing of its import/export scope. |
| 908 */ | 921 */ |
| 909 void registerNewLibrary(LibraryElement library) { | 922 void registerNewLibrary(LibraryElement library) { |
| 910 nodeMap[library] = new LibraryDependencyNode(library); | 923 nodeMap[library] = new LibraryDependencyNode(library); |
| 924 compiler.onLibraryCreated(library); |
| 911 } | 925 } |
| 912 | 926 |
| 913 /** | 927 /** |
| 914 * Registers all top-level entities of [library] as starting point for the | 928 * Registers all top-level entities of [library] as starting point for the |
| 915 * fixed-point computation of the import/export scopes. | 929 * fixed-point computation of the import/export scopes. |
| 916 */ | 930 */ |
| 917 void registerLibraryExports(LibraryElement library) { | 931 void registerLibraryExports(LibraryElement library) { |
| 918 nodeMap[library].registerInitialExports(); | 932 nodeMap[library].registerInitialExports(); |
| 919 } | 933 } |
| 934 |
| 935 Future processLibraryTags(LibraryElement library) { |
| 936 return task.processLibraryTags(this, library); |
| 937 } |
| 920 } | 938 } |
| OLD | NEW |