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 CompilationUnitElement, |
22 Element, | 23 Element, |
23 FunctionElement, | 24 FunctionElement, |
24 LibraryElement, | 25 LibraryElement, |
25 STATE_NOT_STARTED, | 26 STATE_NOT_STARTED, |
26 ScopeContainerElement; | 27 ScopeContainerElement; |
27 | 28 |
28 import 'package:compiler/src/scanner/scannerlib.dart' show | 29 import 'package:compiler/src/scanner/scannerlib.dart' show |
29 EOF_TOKEN, | 30 EOF_TOKEN, |
30 Listener, | 31 Listener, |
31 NodeListener, | 32 NodeListener, |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 ElementX, | 83 ElementX, |
83 FieldElementX, | 84 FieldElementX, |
84 LibraryElementX; | 85 LibraryElementX; |
85 | 86 |
86 import 'package:compiler/src/universe/universe.dart' show | 87 import 'package:compiler/src/universe/universe.dart' show |
87 Selector; | 88 Selector; |
88 | 89 |
89 import 'package:compiler/src/constants/values.dart' show | 90 import 'package:compiler/src/constants/values.dart' show |
90 ConstantValue; | 91 ConstantValue; |
91 | 92 |
| 93 import 'package:compiler/src/library_loader.dart' show |
| 94 TagState; |
| 95 |
92 import 'diff.dart' show | 96 import 'diff.dart' show |
93 Difference, | 97 Difference, |
94 computeDifference; | 98 computeDifference; |
95 | 99 |
96 import 'dart2js_incremental.dart' show | 100 import 'dart2js_incremental.dart' show |
97 IncrementalCompilationFailed, | 101 IncrementalCompilationFailed, |
98 IncrementalCompiler; | 102 IncrementalCompiler; |
99 | 103 |
100 typedef void Logger(message); | 104 typedef void Logger(message); |
101 | 105 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 | 178 |
175 final Set<ElementX> _removedElements = new Set<ElementX>(); | 179 final Set<ElementX> _removedElements = new Set<ElementX>(); |
176 | 180 |
177 final Set<ClassElementX> _classesWithSchemaChanges = | 181 final Set<ClassElementX> _classesWithSchemaChanges = |
178 new Set<ClassElementX>(); | 182 new Set<ClassElementX>(); |
179 | 183 |
180 final IncrementalCompilerContext _context; | 184 final IncrementalCompilerContext _context; |
181 | 185 |
182 final Map<Uri, Future> _sources = <Uri, Future>{}; | 186 final Map<Uri, Future> _sources = <Uri, Future>{}; |
183 | 187 |
| 188 /// Cached tokens of entry compilation units. |
| 189 final Map<LibraryElementX, Token> _entryUnitTokens = |
| 190 <LibraryElementX, Token>{}; |
| 191 |
| 192 /// Cached source files for entry compilation units. |
| 193 final Map<LibraryElementX, SourceFile> _entrySourceFiles = |
| 194 <LibraryElementX, SourceFile>{}; |
| 195 |
184 bool _hasComputedNeeds = false; | 196 bool _hasComputedNeeds = false; |
185 | 197 |
186 bool _hasCapturedCompilerState = false; | 198 bool _hasCapturedCompilerState = false; |
187 | 199 |
188 LibraryUpdater( | 200 LibraryUpdater( |
189 this.compiler, | 201 this.compiler, |
190 this.inputProvider, | 202 this.inputProvider, |
191 this.logTime, | 203 this.logTime, |
192 this.logVerbose, | 204 this.logVerbose, |
193 this._context) { | 205 this._context) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 return new Future.value(true); | 238 return new Future.value(true); |
227 } | 239 } |
228 return _haveTagsChanged(library).then((bool haveTagsChanged) { | 240 return _haveTagsChanged(library).then((bool haveTagsChanged) { |
229 if (haveTagsChanged) { | 241 if (haveTagsChanged) { |
230 cannotReuse( | 242 cannotReuse( |
231 library, | 243 library, |
232 "Changes to library, import, export, or part declarations not" | 244 "Changes to library, import, export, or part declarations not" |
233 " supported."); | 245 " supported."); |
234 return true; | 246 return true; |
235 } | 247 } |
| 248 |
| 249 bool isChanged = false; |
| 250 List<Future<Script>> futureScripts = <Future<Script>>[]; |
| 251 |
236 for (CompilationUnitElementX unit in library.compilationUnits) { | 252 for (CompilationUnitElementX unit in library.compilationUnits) { |
237 Uri uri = unit.script.resourceUri; | 253 Uri uri = unit.script.resourceUri; |
238 if (_context._uriHasUpdate(uri)) { | 254 if (_context._uriHasUpdate(uri)) { |
239 if (!library.compilationUnits.tail.isEmpty) { | 255 isChanged = true; |
240 // TODO(ahe): Remove this restriction. | 256 futureScripts.add(_updatedScript(unit.script, library)); |
241 cannotReuse( | 257 } else { |
242 library, | 258 futureScripts.add(new Future.value(unit.script)); |
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 }); | |
250 } | 259 } |
251 } | 260 } |
252 | 261 |
253 logTime("Reusing $library, source didn't change."); | 262 if (!isChanged) { |
254 // Source code of [library] wasn't changed. | 263 logTime("Reusing $library, source didn't change."); |
255 return true; | 264 return true; |
| 265 } |
| 266 |
| 267 return Future.wait(futureScripts).then( |
| 268 (List<Script> scripts) => canReuseLibrary(library, scripts)); |
| 269 }).whenComplete(() => _cleanUp(library)); |
| 270 } |
| 271 |
| 272 void _cleanUp(LibraryElementX library) { |
| 273 _entryUnitTokens.remove(library); |
| 274 _entrySourceFiles.remove(library); |
| 275 } |
| 276 |
| 277 Future<Script> _updatedScript(Script before, LibraryElementX library) { |
| 278 if (before == library.entryCompilationUnit.script && |
| 279 _entrySourceFiles.containsKey(library)) { |
| 280 return new Future.value(before.copyWithFile(_entrySourceFiles[library])); |
| 281 } |
| 282 |
| 283 return _readUri(before.resourceUri).then((bytes) { |
| 284 String filename = before.file.filename; |
| 285 SourceFile sourceFile = bytes is String |
| 286 ? new StringSourceFile(filename, bytes) |
| 287 : new CachingUtf8BytesSourceFile(filename, bytes); |
| 288 return before.copyWithFile(sourceFile); |
256 }); | 289 }); |
257 } | 290 } |
258 | 291 |
259 Future<bool> _haveTagsChanged(LibraryElement library) { | 292 Future<bool> _haveTagsChanged(LibraryElement library) { |
260 Uri uri = library.entryCompilationUnit.script.resourceUri; | 293 Script before = library.entryCompilationUnit.script; |
261 if (!_context._uriHasUpdate(uri)) { | 294 if (!_context._uriHasUpdate(before.resourceUri)) { |
262 // The entry compilation unit hasn't been updated. So the tags aren't | 295 // The entry compilation unit hasn't been updated. So the tags aren't |
263 // changed. | 296 // changed. |
264 return new Future<bool>.value(false); | 297 return new Future<bool>.value(false); |
265 } | 298 } |
266 | 299 |
267 return _readUri(uri).then((bytes) { | 300 return _updatedScript(before, library).then((Script script) { |
268 String filename = '$uri'; | 301 _entrySourceFiles[library] = script.file; |
269 SourceFile sourceFile = bytes is String | 302 Token token = new Scanner(_entrySourceFiles[library]).tokenize(); |
270 ? new StringSourceFile(filename, bytes) | 303 _entryUnitTokens[library] = token; |
271 : new CachingUtf8BytesSourceFile(filename, bytes); | |
272 Token token = new Scanner(sourceFile).tokenize(); | |
273 // Using two parsers to only create the nodes we want ([LibraryTag]). | 304 // Using two parsers to only create the nodes we want ([LibraryTag]). |
274 Parser parser = new Parser(new Listener()); | 305 Parser parser = new Parser(new Listener()); |
275 NodeListener listener = new NodeListener( | 306 NodeListener listener = new NodeListener( |
276 compiler, library.entryCompilationUnit); | 307 compiler, library.entryCompilationUnit); |
277 Parser nodeParser = new Parser(listener); | 308 Parser nodeParser = new Parser(listener); |
278 Iterator<LibraryTag> tags = library.tags.iterator; | 309 Iterator<LibraryTag> tags = library.tags.iterator; |
279 while (token.kind != EOF_TOKEN) { | 310 while (token.kind != EOF_TOKEN) { |
280 token = parser.parseMetadataStar(token); | 311 token = parser.parseMetadataStar(token); |
281 if (parser.optional('library', token) || | 312 if (parser.optional('library', token) || |
282 parser.optional('import', token) || | 313 parser.optional('import', token) || |
(...skipping 23 matching lines...) Expand all Loading... |
306 if (compiler == null) return; | 337 if (compiler == null) return; |
307 | 338 |
308 if (_hasCapturedCompilerState) return; | 339 if (_hasCapturedCompilerState) return; |
309 _context._captureState(compiler); | 340 _context._captureState(compiler); |
310 _hasCapturedCompilerState = true; | 341 _hasCapturedCompilerState = true; |
311 } | 342 } |
312 | 343 |
313 /// Returns true if [library] can be reused. | 344 /// Returns true if [library] can be reused. |
314 /// | 345 /// |
315 /// This methods also computes the [updates] (patches) needed to have | 346 /// This methods also computes the [updates] (patches) needed to have |
316 /// [library] reflect the modifications in [bytes]. | 347 /// [library] reflect the modifications in [scripts]. |
317 bool canReuseLibrary(LibraryElement library, bytes) { | 348 bool canReuseLibrary(LibraryElement library, List<Script> scripts) { |
318 logTime('Attempting to reuse ${library}.'); | 349 logTime('Attempting to reuse ${library}.'); |
319 String newSource = bytes is String ? bytes : UTF8.decode(bytes); | |
320 logTime('Decoded UTF8'); | |
321 | 350 |
322 Uri uri = library.entryCompilationUnit.script.resourceUri; | 351 Uri entryUri = library.entryCompilationUnit.script.resourceUri; |
323 Script sourceScript = new Script( | 352 Script entryScript = |
324 uri, uri, new StringSourceFile('$uri', newSource)); | 353 scripts.singleWhere((Script script) => script.resourceUri == entryUri); |
325 var dartPrivacyIsBroken = compiler.libraryLoader; | 354 LibraryElement newLibrary = |
326 LibraryElement newLibrary = dartPrivacyIsBroken.createLibrarySync( | 355 new LibraryElementX(entryScript, library.canonicalUri); |
327 null, sourceScript, uri); | 356 if (_entryUnitTokens.containsKey(library)) { |
| 357 compiler.dietParser.dietParse( |
| 358 newLibrary.entryCompilationUnit, _entryUnitTokens[library]); |
| 359 } else { |
| 360 compiler.scanner.scanLibrary(newLibrary); |
| 361 } |
| 362 |
| 363 TagState tagState = new TagState(); |
| 364 for (LibraryTag tag in newLibrary.tags) { |
| 365 if (tag.isImport) { |
| 366 tagState.checkTag(TagState.IMPORT_OR_EXPORT, tag, compiler); |
| 367 } else if (tag.isExport) { |
| 368 tagState.checkTag(TagState.IMPORT_OR_EXPORT, tag, compiler); |
| 369 } else if (tag.isLibraryName) { |
| 370 tagState.checkTag(TagState.LIBRARY, tag, compiler); |
| 371 if (newLibrary.libraryTag == null) { |
| 372 // Use the first if there are multiple (which is reported as an |
| 373 // error in [TagState.checkTag]). |
| 374 newLibrary.libraryTag = tag; |
| 375 } |
| 376 } else if (tag.isPart) { |
| 377 tagState.checkTag(TagState.PART, tag, compiler); |
| 378 } |
| 379 } |
| 380 |
| 381 // TODO(ahe): Process tags using TagState, not |
| 382 // LibraryLoaderTask.processLibraryTags. |
| 383 Link<CompilationUnitElement> units = library.compilationUnits; |
| 384 for (Script script in scripts) { |
| 385 CompilationUnitElementX unit = units.head; |
| 386 units = units.tail; |
| 387 if (script != entryScript) { |
| 388 // TODO(ahe): Copied from library_loader. |
| 389 CompilationUnitElement newUnit = |
| 390 new CompilationUnitElementX(script, newLibrary); |
| 391 compiler.withCurrentElement(newUnit, () { |
| 392 compiler.scanner.scan(newUnit); |
| 393 if (unit.partTag == null) { |
| 394 compiler.reportError(unit, MessageKind.MISSING_PART_OF_TAG); |
| 395 } |
| 396 }); |
| 397 } |
| 398 } |
| 399 |
328 logTime('New library synthesized.'); | 400 logTime('New library synthesized.'); |
329 return canReuseScopeContainerElement(library, newLibrary); | 401 return canReuseScopeContainerElement(library, newLibrary); |
330 } | 402 } |
331 | 403 |
332 bool cannotReuse(context, String message) { | 404 bool cannotReuse(context, String message) { |
333 _failedUpdates.add(new FailedUpdate(context, message)); | 405 _failedUpdates.add(new FailedUpdate(context, message)); |
334 logVerbose(message); | 406 logVerbose(message); |
335 return false; | 407 return false; |
336 } | 408 } |
337 | 409 |
(...skipping 1064 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1402 List<String> computeFields(ClassElement cls) { | 1474 List<String> computeFields(ClassElement cls) { |
1403 // TODO(ahe): Rewrite for new emitter. | 1475 // TODO(ahe): Rewrite for new emitter. |
1404 ClassBuilder builder = new ClassBuilder(cls, namer); | 1476 ClassBuilder builder = new ClassBuilder(cls, namer); |
1405 classEmitter.emitFields(cls, builder); | 1477 classEmitter.emitFields(cls, builder); |
1406 return builder.fields; | 1478 return builder.fields; |
1407 } | 1479 } |
1408 } | 1480 } |
1409 | 1481 |
1410 // TODO(ahe): Remove this method. | 1482 // TODO(ahe): Remove this method. |
1411 NO_WARN(x) => x; | 1483 NO_WARN(x) => x; |
OLD | NEW |