Chromium Code Reviews| Index: dart/pkg/dart2js_incremental/lib/library_updater.dart |
| diff --git a/dart/pkg/dart2js_incremental/lib/library_updater.dart b/dart/pkg/dart2js_incremental/lib/library_updater.dart |
| index 14034c6ddfe50679935c8651c0ed0e6255226a61..7478f76f7a5d4a45a57e6c637c8b8f50231cfcbe 100644 |
| --- a/dart/pkg/dart2js_incremental/lib/library_updater.dart |
| +++ b/dart/pkg/dart2js_incremental/lib/library_updater.dart |
| @@ -19,6 +19,7 @@ import 'package:compiler/src/dart2jslib.dart' show |
| import 'package:compiler/src/elements/elements.dart' show |
| ClassElement, |
| + CompilationUnitElement, |
| Element, |
| FunctionElement, |
| LibraryElement, |
| @@ -89,6 +90,9 @@ import 'package:compiler/src/universe/universe.dart' show |
| import 'package:compiler/src/constants/values.dart' show |
| ConstantValue; |
| +import 'package:compiler/src/library_loader.dart' show |
| + TagState; |
| + |
| import 'diff.dart' show |
| Difference, |
| computeDifference; |
| @@ -185,6 +189,10 @@ class LibraryUpdater extends JsFeatures { |
| bool _hasCapturedCompilerState = false; |
| + Token _entryUnitTokens; |
| + |
| + SourceFile _entrySourceFile; |
|
Johnni Winther
2014/12/19 12:17:33
What is the semantics of this?
ahe
2014/12/19 13:35:45
Done.
|
| + |
| LibraryUpdater( |
| this.compiler, |
| this.inputProvider, |
| @@ -233,43 +241,57 @@ class LibraryUpdater extends JsFeatures { |
| " supported."); |
| return true; |
| } |
| + |
| + bool isChanged = false; |
| + List<Future<Script>> futureScripts = <Future<Script>>[]; |
| + |
| for (CompilationUnitElementX unit in library.compilationUnits) { |
| Uri uri = unit.script.resourceUri; |
| if (_context._uriHasUpdate(uri)) { |
| - if (!library.compilationUnits.tail.isEmpty) { |
| - // TODO(ahe): Remove this restriction. |
| - cannotReuse( |
| - library, |
| - "Multiple compilation units not supported" |
| - " (${library.compilationUnits})."); |
| - return true; |
| - } |
| - return _readUri(uri).then((bytes) { |
| - return canReuseLibrary(library, bytes); |
| - }); |
| + isChanged = true; |
| + futureScripts.add(_updatedScript(unit.script, library)); |
| + } else { |
| + futureScripts.add(new Future.value(unit.script)); |
| } |
| } |
| - logTime("Reusing $library, source didn't change."); |
| - // Source code of [library] wasn't changed. |
| - return true; |
| + if (!isChanged) { |
| + logTime("Reusing $library, source didn't change."); |
| + return true; |
| + } |
| + |
| + return Future.wait(futureScripts).then( |
| + (List<Script> scripts) => canReuseLibrary(library, scripts)); |
| + }); |
| + } |
| + |
| + Future<Script> _updatedScript(Script before, LibraryElementX library) { |
| + if (before == library.entryCompilationUnit.script && |
| + _entrySourceFile != null) { |
| + return new Future.value(before.copyWithFile(_entrySourceFile)); |
| + } |
| + |
| + return _readUri(before.resourceUri).then((bytes) { |
| + String filename = before.file.filename; |
| + SourceFile sourceFile = bytes is String |
| + ? new StringSourceFile(filename, bytes) |
| + : new CachingUtf8BytesSourceFile(filename, bytes); |
| + return before.copyWithFile(sourceFile); |
| }); |
| } |
| Future<bool> _haveTagsChanged(LibraryElement library) { |
| - Uri uri = library.entryCompilationUnit.script.resourceUri; |
| - if (!_context._uriHasUpdate(uri)) { |
| + Script before = library.entryCompilationUnit.script; |
| + if (!_context._uriHasUpdate(before.resourceUri)) { |
| // The entry compilation unit hasn't been updated. So the tags aren't |
| // changed. |
| return new Future<bool>.value(false); |
| } |
| - return _readUri(uri).then((bytes) { |
| - String filename = '$uri'; |
| - SourceFile sourceFile = bytes is String |
| - ? new StringSourceFile(filename, bytes) |
| - : new CachingUtf8BytesSourceFile(filename, bytes); |
| - Token token = new Scanner(sourceFile).tokenize(); |
| + return _updatedScript(before, library).then((Script script) { |
| + _entrySourceFile = script.file; |
| + Token token = new Scanner(_entrySourceFile).tokenize(); |
| + _entryUnitTokens = token; |
| // Using two parsers to only create the nodes we want ([LibraryTag]). |
| Parser parser = new Parser(new Listener()); |
| NodeListener listener = new NodeListener( |
| @@ -313,18 +335,59 @@ class LibraryUpdater extends JsFeatures { |
| /// Returns true if [library] can be reused. |
| /// |
| /// This methods also computes the [updates] (patches) needed to have |
| - /// [library] reflect the modifications in [bytes]. |
| - bool canReuseLibrary(LibraryElement library, bytes) { |
| + /// [library] reflect the modifications in [scripts]. |
| + bool canReuseLibrary(LibraryElement library, List<Script> scripts) { |
| logTime('Attempting to reuse ${library}.'); |
| - String newSource = bytes is String ? bytes : UTF8.decode(bytes); |
| - logTime('Decoded UTF8'); |
| - |
| - Uri uri = library.entryCompilationUnit.script.resourceUri; |
| - Script sourceScript = new Script( |
| - uri, uri, new StringSourceFile('$uri', newSource)); |
| - var dartPrivacyIsBroken = compiler.libraryLoader; |
| - LibraryElement newLibrary = dartPrivacyIsBroken.createLibrarySync( |
| - null, sourceScript, uri); |
| + |
| + Uri entryUri = library.entryCompilationUnit.script.resourceUri; |
| + Script entryScript = |
| + scripts.singleWhere((Script script) => script.resourceUri == entryUri); |
| + LibraryElement newLibrary = |
| + new LibraryElementX(entryScript, library.canonicalUri); |
| + if (_entryUnitTokens != null) { |
| + compiler.dietParser.dietParse( |
| + newLibrary.entryCompilationUnit, _entryUnitTokens); |
| + } else { |
| + compiler.scanner.scanLibrary(newLibrary); |
| + } |
| + |
| + TagState tagState = new TagState(); |
| + for (LibraryTag tag in newLibrary.tags) { |
| + if (tag.isImport) { |
| + tagState.checkTag(TagState.IMPORT_OR_EXPORT, tag, compiler); |
| + } else if (tag.isExport) { |
| + tagState.checkTag(TagState.IMPORT_OR_EXPORT, tag, compiler); |
| + } else if (tag.isLibraryName) { |
| + tagState.checkTag(TagState.LIBRARY, tag, compiler); |
| + if (newLibrary.libraryTag == null) { |
| + // Use the first if there are multiple (which is reported as an |
| + // error in [TagState.checkTag]). |
| + newLibrary.libraryTag = tag; |
| + } |
| + } else if (tag.isPart) { |
| + tagState.checkTag(TagState.PART, tag, compiler); |
| + } |
| + } |
| + |
| + // TODO(ahe): Process tags using TagState, not |
| + // LibraryLoaderTask.processLibraryTags. |
| + Link<CompilationUnitElement> units = library.compilationUnits; |
| + for (Script script in scripts) { |
| + CompilationUnitElementX unit = units.head; |
| + units = units.tail; |
| + if (script != entryScript) { |
| + // TODO(ahe): Copied form library_loader. |
|
Johnni Winther
2014/12/19 12:17:33
'form' -> 'from'
ahe
2014/12/19 13:35:45
Done.
|
| + CompilationUnitElement newUnit = |
| + new CompilationUnitElementX(script, newLibrary); |
| + compiler.withCurrentElement(newUnit, () { |
| + compiler.scanner.scan(newUnit); |
| + if (unit.partTag == null) { |
| + compiler.reportError(unit, MessageKind.MISSING_PART_OF_TAG); |
| + } |
| + }); |
| + } |
| + } |
| + |
| logTime('New library synthesized.'); |
| return canReuseScopeContainerElement(library, newLibrary); |
| } |