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 |