| 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 dart2js_incremental.library_updater; | 5 library dart2js_incremental.library_updater; |
| 6 | 6 |
| 7 import 'dart:async' show | 7 import 'dart:async' show |
| 8 Future; | 8 Future; |
| 9 | 9 |
| 10 import 'dart:convert' show | 10 import 'dart:convert' show |
| 11 UTF8; | 11 UTF8; |
| 12 | 12 |
| 13 import 'package:compiler/compiler.dart' as api; | 13 import 'package:compiler/compiler.dart' as api; |
| 14 | 14 |
| 15 import 'package:compiler/src/dart2jslib.dart' show | 15 import 'package:compiler/src/dart2jslib.dart' show |
| 16 Compiler, | 16 Compiler, |
| 17 EnqueueTask, | 17 EnqueueTask, |
| 18 Script; | 18 Script; |
| 19 | 19 |
| 20 import 'package:compiler/src/elements/elements.dart' show | 20 import 'package:compiler/src/elements/elements.dart' show |
| 21 ClassElement, | 21 ClassElement, |
| 22 Element, | 22 Element, |
| 23 FunctionElement, | 23 FunctionElement, |
| 24 LibraryElement, | 24 LibraryElement, |
| 25 STATE_NOT_STARTED, | 25 STATE_NOT_STARTED, |
| 26 ScopeContainerElement; | 26 ScopeContainerElement; |
| 27 | 27 |
| 28 import 'package:compiler/src/scanner/scannerlib.dart' show | 28 import 'package:compiler/src/scanner/scannerlib.dart' show |
| 29 EOF_TOKEN, | 29 EOF_TOKEN, |
| 30 Listener, |
| 31 NodeListener, |
| 32 Parser, |
| 30 PartialClassElement, | 33 PartialClassElement, |
| 31 PartialElement, | 34 PartialElement, |
| 32 PartialFieldList, | 35 PartialFieldList, |
| 33 PartialFunctionElement, | 36 PartialFunctionElement, |
| 37 Scanner, |
| 34 Token; | 38 Token; |
| 35 | 39 |
| 36 import 'package:compiler/src/source_file.dart' show | 40 import 'package:compiler/src/source_file.dart' show |
| 41 CachingUtf8BytesSourceFile, |
| 42 SourceFile, |
| 37 StringSourceFile; | 43 StringSourceFile; |
| 38 | 44 |
| 39 import 'package:compiler/src/tree/tree.dart' show | 45 import 'package:compiler/src/tree/tree.dart' show |
| 40 ClassNode, | 46 ClassNode, |
| 41 FunctionExpression, | 47 FunctionExpression, |
| 42 NodeList; | 48 LibraryTag, |
| 49 NodeList, |
| 50 Part, |
| 51 StringNode, |
| 52 unparse; |
| 43 | 53 |
| 44 import 'package:compiler/src/js/js.dart' show | 54 import 'package:compiler/src/js/js.dart' show |
| 45 js; | 55 js; |
| 46 | 56 |
| 47 import 'package:compiler/src/js/js.dart' as jsAst; | 57 import 'package:compiler/src/js/js.dart' as jsAst; |
| 48 | 58 |
| 49 import 'package:compiler/src/js_emitter/js_emitter.dart' show | 59 import 'package:compiler/src/js_emitter/js_emitter.dart' show |
| 50 ClassBuilder, | 60 ClassBuilder, |
| 51 ClassEmitter, | 61 ClassEmitter, |
| 52 CodeEmitterTask, | 62 CodeEmitterTask, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 77 Selector; | 87 Selector; |
| 78 | 88 |
| 79 import 'package:compiler/src/constants/values.dart' show | 89 import 'package:compiler/src/constants/values.dart' show |
| 80 ConstantValue; | 90 ConstantValue; |
| 81 | 91 |
| 82 import 'diff.dart' show | 92 import 'diff.dart' show |
| 83 Difference, | 93 Difference, |
| 84 computeDifference; | 94 computeDifference; |
| 85 | 95 |
| 86 import 'dart2js_incremental.dart' show | 96 import 'dart2js_incremental.dart' show |
| 97 IncrementalCompilationFailed, |
| 87 IncrementalCompiler; | 98 IncrementalCompiler; |
| 88 | 99 |
| 89 typedef void Logger(message); | 100 typedef void Logger(message); |
| 90 | 101 |
| 91 typedef bool Reuser( | 102 typedef bool Reuser( |
| 92 Token diffToken, | 103 Token diffToken, |
| 93 PartialElement before, | 104 PartialElement before, |
| 94 PartialElement after); | 105 PartialElement after); |
| 95 | 106 |
| 96 class FailedUpdate { | 107 class FailedUpdate { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 | 172 |
| 162 final Set<ElementX> _elementsToInvalidate = new Set<ElementX>(); | 173 final Set<ElementX> _elementsToInvalidate = new Set<ElementX>(); |
| 163 | 174 |
| 164 final Set<ElementX> _removedElements = new Set<ElementX>(); | 175 final Set<ElementX> _removedElements = new Set<ElementX>(); |
| 165 | 176 |
| 166 final Set<ClassElementX> _classesWithSchemaChanges = | 177 final Set<ClassElementX> _classesWithSchemaChanges = |
| 167 new Set<ClassElementX>(); | 178 new Set<ClassElementX>(); |
| 168 | 179 |
| 169 final IncrementalCompilerContext _context; | 180 final IncrementalCompilerContext _context; |
| 170 | 181 |
| 182 final Map<Uri, Future> _sources = <Uri, Future>{}; |
| 183 |
| 171 bool _hasComputedNeeds = false; | 184 bool _hasComputedNeeds = false; |
| 172 | 185 |
| 173 bool _hasCapturedCompilerState = false; | 186 bool _hasCapturedCompilerState = false; |
| 174 | 187 |
| 175 LibraryUpdater( | 188 LibraryUpdater( |
| 176 this.compiler, | 189 this.compiler, |
| 177 this.inputProvider, | 190 this.inputProvider, |
| 178 this.logTime, | 191 this.logTime, |
| 179 this.logVerbose, | 192 this.logVerbose, |
| 180 this._context) { | 193 this._context) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 205 bool get failed => !_failedUpdates.isEmpty; | 218 bool get failed => !_failedUpdates.isEmpty; |
| 206 | 219 |
| 207 /// Used as tear-off passed to [LibraryLoaderTask.resetAsync]. | 220 /// Used as tear-off passed to [LibraryLoaderTask.resetAsync]. |
| 208 Future<bool> reuseLibrary(LibraryElement library) { | 221 Future<bool> reuseLibrary(LibraryElement library) { |
| 209 _ensureCompilerStateCaptured(); | 222 _ensureCompilerStateCaptured(); |
| 210 assert(compiler != null); | 223 assert(compiler != null); |
| 211 if (library.isPlatformLibrary) { | 224 if (library.isPlatformLibrary) { |
| 212 logTime('Reusing $library (assumed read-only).'); | 225 logTime('Reusing $library (assumed read-only).'); |
| 213 return new Future.value(true); | 226 return new Future.value(true); |
| 214 } | 227 } |
| 215 for (CompilationUnitElementX unit in library.compilationUnits) { | 228 return _haveTagsChanged(library).then((bool haveTagsChanged) { |
| 216 Uri uri = unit.script.resourceUri; | 229 if (haveTagsChanged) { |
| 217 if (_context._uriHasUpdate(uri)) { | 230 cannotReuse( |
| 218 if (!library.compilationUnits.tail.isEmpty) { | 231 library, |
| 219 // TODO(ahe): Remove this restriction. | 232 "Changes to library, import, export, or part declarations not" |
| 220 cannotReuse(library, "Multiple compilation units not supported."); | 233 " supported."); |
| 221 return new Future.value(true); | 234 return true; |
| 235 } |
| 236 for (CompilationUnitElementX unit in library.compilationUnits) { |
| 237 Uri uri = unit.script.resourceUri; |
| 238 if (_context._uriHasUpdate(uri)) { |
| 239 if (!library.compilationUnits.tail.isEmpty) { |
| 240 // TODO(ahe): Remove this restriction. |
| 241 cannotReuse( |
| 242 library, |
| 243 "Multiple compilation units not supported" |
| 244 " (${library.compilationUnits})."); |
| 245 return true; |
| 246 } |
| 247 return _readUri(uri).then((bytes) { |
| 248 return canReuseLibrary(library, bytes); |
| 249 }); |
| 222 } | 250 } |
| 223 return inputProvider(uri).then((bytes) { | |
| 224 return canReuseLibrary(library, bytes); | |
| 225 }); | |
| 226 } | 251 } |
| 252 |
| 253 logTime("Reusing $library, source didn't change."); |
| 254 // Source code of [library] wasn't changed. |
| 255 return true; |
| 256 }); |
| 257 } |
| 258 |
| 259 Future<bool> _haveTagsChanged(LibraryElement library) { |
| 260 Uri uri = library.entryCompilationUnit.script.resourceUri; |
| 261 if (!_context._uriHasUpdate(uri)) { |
| 262 // The entry compilation unit hasn't been updated. So the tags aren't |
| 263 // changed. |
| 264 return new Future<bool>.value(false); |
| 227 } | 265 } |
| 228 | 266 |
| 229 logTime("Reusing $library, source didn't change."); | 267 return _readUri(uri).then((bytes) { |
| 230 // Source code of [library] wasn't changed. | 268 String filename = '$uri'; |
| 231 return new Future.value(true); | 269 SourceFile sourceFile = bytes is String |
| 270 ? new StringSourceFile(filename, bytes) |
| 271 : new CachingUtf8BytesSourceFile(filename, bytes); |
| 272 Token token = new Scanner(sourceFile).tokenize(); |
| 273 // Using two parsers to only create the nodes we want ([LibraryTag]). |
| 274 Parser parser = new Parser(new Listener()); |
| 275 NodeListener listener = new NodeListener( |
| 276 compiler, library.entryCompilationUnit); |
| 277 Parser nodeParser = new Parser(listener); |
| 278 Iterator<LibraryTag> tags = library.tags.iterator; |
| 279 while (token.kind != EOF_TOKEN) { |
| 280 token = parser.parseMetadataStar(token); |
| 281 if (parser.optional('library', token) || |
| 282 parser.optional('import', token) || |
| 283 parser.optional('export', token) || |
| 284 parser.optional('part', token)) { |
| 285 if (!tags.moveNext()) return true; |
| 286 token = nodeParser.parseTopLevelDeclaration(token); |
| 287 LibraryTag tag = listener.popNode(); |
| 288 assert(listener.nodes.isEmpty); |
| 289 if (unparse(tags.current) != unparse(tag)) { |
| 290 return true; |
| 291 } |
| 292 } else { |
| 293 break; |
| 294 } |
| 295 } |
| 296 return tags.moveNext(); |
| 297 }); |
| 298 } |
| 299 |
| 300 Future _readUri(Uri uri) { |
| 301 return _sources.putIfAbsent(uri, () => inputProvider(uri)); |
| 232 } | 302 } |
| 233 | 303 |
| 234 void _ensureCompilerStateCaptured() { | 304 void _ensureCompilerStateCaptured() { |
| 235 // TODO(ahe): [compiler] shouldn't be null, remove the following line. | 305 // TODO(ahe): [compiler] shouldn't be null, remove the following line. |
| 236 if (compiler == null) return; | 306 if (compiler == null) return; |
| 237 | 307 |
| 238 if (_hasCapturedCompilerState) return; | 308 if (_hasCapturedCompilerState) return; |
| 239 _context._captureState(compiler); | 309 _context._captureState(compiler); |
| 240 _hasCapturedCompilerState = true; | 310 _hasCapturedCompilerState = true; |
| 241 } | 311 } |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 } | 646 } |
| 577 | 647 |
| 578 /// Apply the collected [updates]. Return a list of elements that needs to be | 648 /// Apply the collected [updates]. Return a list of elements that needs to be |
| 579 /// recompiled after applying the updates. Any elements removed as a | 649 /// recompiled after applying the updates. Any elements removed as a |
| 580 /// consequence of applying the patches are added to [removals] if provided. | 650 /// consequence of applying the patches are added to [removals] if provided. |
| 581 List<Element> applyUpdates([List<Update> removals]) { | 651 List<Element> applyUpdates([List<Update> removals]) { |
| 582 for (Update update in updates) { | 652 for (Update update in updates) { |
| 583 update.captureState(); | 653 update.captureState(); |
| 584 } | 654 } |
| 585 if (!_failedUpdates.isEmpty) { | 655 if (!_failedUpdates.isEmpty) { |
| 586 throw new StateError( | 656 throw new IncrementalCompilationFailed(_failedUpdates.join('\n\n')); |
| 587 "Can't compute update.\n\n${_failedUpdates.join('\n\n')}"); | |
| 588 } | 657 } |
| 589 for (ElementX element in _elementsToInvalidate) { | 658 for (ElementX element in _elementsToInvalidate) { |
| 590 compiler.forgetElement(element); | 659 compiler.forgetElement(element); |
| 591 element.reuseElement(); | 660 element.reuseElement(); |
| 592 } | 661 } |
| 593 List<Element> elementsToInvalidate = <Element>[]; | 662 List<Element> elementsToInvalidate = <Element>[]; |
| 594 for (ElementX element in _elementsToInvalidate) { | 663 for (ElementX element in _elementsToInvalidate) { |
| 595 if (!_removedElements.contains(element)) { | 664 if (!_removedElements.contains(element)) { |
| 596 elementsToInvalidate.add(element); | 665 elementsToInvalidate.add(element); |
| 597 } | 666 } |
| (...skipping 735 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1333 List<String> computeFields(ClassElement cls) { | 1402 List<String> computeFields(ClassElement cls) { |
| 1334 // TODO(ahe): Rewrite for new emitter. | 1403 // TODO(ahe): Rewrite for new emitter. |
| 1335 ClassBuilder builder = new ClassBuilder(cls, namer); | 1404 ClassBuilder builder = new ClassBuilder(cls, namer); |
| 1336 classEmitter.emitFields(cls, builder); | 1405 classEmitter.emitFields(cls, builder); |
| 1337 return builder.fields; | 1406 return builder.fields; |
| 1338 } | 1407 } |
| 1339 } | 1408 } |
| 1340 | 1409 |
| 1341 // TODO(ahe): Remove this method. | 1410 // TODO(ahe): Remove this method. |
| 1342 NO_WARN(x) => x; | 1411 NO_WARN(x) => x; |
| OLD | NEW |