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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 |
184 bool _hasComputedNeeds = false; | 188 bool _hasComputedNeeds = false; |
185 | 189 |
186 bool _hasCapturedCompilerState = false; | 190 bool _hasCapturedCompilerState = false; |
187 | 191 |
192 Token _entryUnitTokens; | |
193 | |
194 SourceFile _entrySourceFile; | |
Johnni Winther
2014/12/19 12:17:33
What is the semantics of this?
ahe
2014/12/19 13:35:45
Done.
| |
195 | |
188 LibraryUpdater( | 196 LibraryUpdater( |
189 this.compiler, | 197 this.compiler, |
190 this.inputProvider, | 198 this.inputProvider, |
191 this.logTime, | 199 this.logTime, |
192 this.logVerbose, | 200 this.logVerbose, |
193 this._context) { | 201 this._context) { |
194 // TODO(ahe): Would like to remove this from the constructor. However, the | 202 // TODO(ahe): Would like to remove this from the constructor. However, the |
195 // state must be captured before calling [reuseCompiler]. | 203 // state must be captured before calling [reuseCompiler]. |
196 // Proper solution might be: [reuseCompiler] should not clear the sets that | 204 // Proper solution might be: [reuseCompiler] should not clear the sets that |
197 // are captured in [IncrementalCompilerContext._captureState]. | 205 // are captured in [IncrementalCompilerContext._captureState]. |
(...skipping 28 matching lines...) Expand all Loading... | |
226 return new Future.value(true); | 234 return new Future.value(true); |
227 } | 235 } |
228 return _haveTagsChanged(library).then((bool haveTagsChanged) { | 236 return _haveTagsChanged(library).then((bool haveTagsChanged) { |
229 if (haveTagsChanged) { | 237 if (haveTagsChanged) { |
230 cannotReuse( | 238 cannotReuse( |
231 library, | 239 library, |
232 "Changes to library, import, export, or part declarations not" | 240 "Changes to library, import, export, or part declarations not" |
233 " supported."); | 241 " supported."); |
234 return true; | 242 return true; |
235 } | 243 } |
244 | |
245 bool isChanged = false; | |
246 List<Future<Script>> futureScripts = <Future<Script>>[]; | |
247 | |
236 for (CompilationUnitElementX unit in library.compilationUnits) { | 248 for (CompilationUnitElementX unit in library.compilationUnits) { |
237 Uri uri = unit.script.resourceUri; | 249 Uri uri = unit.script.resourceUri; |
238 if (_context._uriHasUpdate(uri)) { | 250 if (_context._uriHasUpdate(uri)) { |
239 if (!library.compilationUnits.tail.isEmpty) { | 251 isChanged = true; |
240 // TODO(ahe): Remove this restriction. | 252 futureScripts.add(_updatedScript(unit.script, library)); |
241 cannotReuse( | 253 } else { |
242 library, | 254 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 } | 255 } |
251 } | 256 } |
252 | 257 |
253 logTime("Reusing $library, source didn't change."); | 258 if (!isChanged) { |
254 // Source code of [library] wasn't changed. | 259 logTime("Reusing $library, source didn't change."); |
255 return true; | 260 return true; |
261 } | |
262 | |
263 return Future.wait(futureScripts).then( | |
264 (List<Script> scripts) => canReuseLibrary(library, scripts)); | |
265 }); | |
266 } | |
267 | |
268 Future<Script> _updatedScript(Script before, LibraryElementX library) { | |
269 if (before == library.entryCompilationUnit.script && | |
270 _entrySourceFile != null) { | |
271 return new Future.value(before.copyWithFile(_entrySourceFile)); | |
272 } | |
273 | |
274 return _readUri(before.resourceUri).then((bytes) { | |
275 String filename = before.file.filename; | |
276 SourceFile sourceFile = bytes is String | |
277 ? new StringSourceFile(filename, bytes) | |
278 : new CachingUtf8BytesSourceFile(filename, bytes); | |
279 return before.copyWithFile(sourceFile); | |
256 }); | 280 }); |
257 } | 281 } |
258 | 282 |
259 Future<bool> _haveTagsChanged(LibraryElement library) { | 283 Future<bool> _haveTagsChanged(LibraryElement library) { |
260 Uri uri = library.entryCompilationUnit.script.resourceUri; | 284 Script before = library.entryCompilationUnit.script; |
261 if (!_context._uriHasUpdate(uri)) { | 285 if (!_context._uriHasUpdate(before.resourceUri)) { |
262 // The entry compilation unit hasn't been updated. So the tags aren't | 286 // The entry compilation unit hasn't been updated. So the tags aren't |
263 // changed. | 287 // changed. |
264 return new Future<bool>.value(false); | 288 return new Future<bool>.value(false); |
265 } | 289 } |
266 | 290 |
267 return _readUri(uri).then((bytes) { | 291 return _updatedScript(before, library).then((Script script) { |
268 String filename = '$uri'; | 292 _entrySourceFile = script.file; |
269 SourceFile sourceFile = bytes is String | 293 Token token = new Scanner(_entrySourceFile).tokenize(); |
270 ? new StringSourceFile(filename, bytes) | 294 _entryUnitTokens = 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]). | 295 // Using two parsers to only create the nodes we want ([LibraryTag]). |
274 Parser parser = new Parser(new Listener()); | 296 Parser parser = new Parser(new Listener()); |
275 NodeListener listener = new NodeListener( | 297 NodeListener listener = new NodeListener( |
276 compiler, library.entryCompilationUnit); | 298 compiler, library.entryCompilationUnit); |
277 Parser nodeParser = new Parser(listener); | 299 Parser nodeParser = new Parser(listener); |
278 Iterator<LibraryTag> tags = library.tags.iterator; | 300 Iterator<LibraryTag> tags = library.tags.iterator; |
279 while (token.kind != EOF_TOKEN) { | 301 while (token.kind != EOF_TOKEN) { |
280 token = parser.parseMetadataStar(token); | 302 token = parser.parseMetadataStar(token); |
281 if (parser.optional('library', token) || | 303 if (parser.optional('library', token) || |
282 parser.optional('import', token) || | 304 parser.optional('import', token) || |
(...skipping 23 matching lines...) Expand all Loading... | |
306 if (compiler == null) return; | 328 if (compiler == null) return; |
307 | 329 |
308 if (_hasCapturedCompilerState) return; | 330 if (_hasCapturedCompilerState) return; |
309 _context._captureState(compiler); | 331 _context._captureState(compiler); |
310 _hasCapturedCompilerState = true; | 332 _hasCapturedCompilerState = true; |
311 } | 333 } |
312 | 334 |
313 /// Returns true if [library] can be reused. | 335 /// Returns true if [library] can be reused. |
314 /// | 336 /// |
315 /// This methods also computes the [updates] (patches) needed to have | 337 /// This methods also computes the [updates] (patches) needed to have |
316 /// [library] reflect the modifications in [bytes]. | 338 /// [library] reflect the modifications in [scripts]. |
317 bool canReuseLibrary(LibraryElement library, bytes) { | 339 bool canReuseLibrary(LibraryElement library, List<Script> scripts) { |
318 logTime('Attempting to reuse ${library}.'); | 340 logTime('Attempting to reuse ${library}.'); |
319 String newSource = bytes is String ? bytes : UTF8.decode(bytes); | |
320 logTime('Decoded UTF8'); | |
321 | 341 |
322 Uri uri = library.entryCompilationUnit.script.resourceUri; | 342 Uri entryUri = library.entryCompilationUnit.script.resourceUri; |
323 Script sourceScript = new Script( | 343 Script entryScript = |
324 uri, uri, new StringSourceFile('$uri', newSource)); | 344 scripts.singleWhere((Script script) => script.resourceUri == entryUri); |
325 var dartPrivacyIsBroken = compiler.libraryLoader; | 345 LibraryElement newLibrary = |
326 LibraryElement newLibrary = dartPrivacyIsBroken.createLibrarySync( | 346 new LibraryElementX(entryScript, library.canonicalUri); |
327 null, sourceScript, uri); | 347 if (_entryUnitTokens != null) { |
348 compiler.dietParser.dietParse( | |
349 newLibrary.entryCompilationUnit, _entryUnitTokens); | |
350 } else { | |
351 compiler.scanner.scanLibrary(newLibrary); | |
352 } | |
353 | |
354 TagState tagState = new TagState(); | |
355 for (LibraryTag tag in newLibrary.tags) { | |
356 if (tag.isImport) { | |
357 tagState.checkTag(TagState.IMPORT_OR_EXPORT, tag, compiler); | |
358 } else if (tag.isExport) { | |
359 tagState.checkTag(TagState.IMPORT_OR_EXPORT, tag, compiler); | |
360 } else if (tag.isLibraryName) { | |
361 tagState.checkTag(TagState.LIBRARY, tag, compiler); | |
362 if (newLibrary.libraryTag == null) { | |
363 // Use the first if there are multiple (which is reported as an | |
364 // error in [TagState.checkTag]). | |
365 newLibrary.libraryTag = tag; | |
366 } | |
367 } else if (tag.isPart) { | |
368 tagState.checkTag(TagState.PART, tag, compiler); | |
369 } | |
370 } | |
371 | |
372 // TODO(ahe): Process tags using TagState, not | |
373 // LibraryLoaderTask.processLibraryTags. | |
374 Link<CompilationUnitElement> units = library.compilationUnits; | |
375 for (Script script in scripts) { | |
376 CompilationUnitElementX unit = units.head; | |
377 units = units.tail; | |
378 if (script != entryScript) { | |
379 // TODO(ahe): Copied form library_loader. | |
Johnni Winther
2014/12/19 12:17:33
'form' -> 'from'
ahe
2014/12/19 13:35:45
Done.
| |
380 CompilationUnitElement newUnit = | |
381 new CompilationUnitElementX(script, newLibrary); | |
382 compiler.withCurrentElement(newUnit, () { | |
383 compiler.scanner.scan(newUnit); | |
384 if (unit.partTag == null) { | |
385 compiler.reportError(unit, MessageKind.MISSING_PART_OF_TAG); | |
386 } | |
387 }); | |
388 } | |
389 } | |
390 | |
328 logTime('New library synthesized.'); | 391 logTime('New library synthesized.'); |
329 return canReuseScopeContainerElement(library, newLibrary); | 392 return canReuseScopeContainerElement(library, newLibrary); |
330 } | 393 } |
331 | 394 |
332 bool cannotReuse(context, String message) { | 395 bool cannotReuse(context, String message) { |
333 _failedUpdates.add(new FailedUpdate(context, message)); | 396 _failedUpdates.add(new FailedUpdate(context, message)); |
334 logVerbose(message); | 397 logVerbose(message); |
335 return false; | 398 return false; |
336 } | 399 } |
337 | 400 |
(...skipping 1064 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1402 List<String> computeFields(ClassElement cls) { | 1465 List<String> computeFields(ClassElement cls) { |
1403 // TODO(ahe): Rewrite for new emitter. | 1466 // TODO(ahe): Rewrite for new emitter. |
1404 ClassBuilder builder = new ClassBuilder(cls, namer); | 1467 ClassBuilder builder = new ClassBuilder(cls, namer); |
1405 classEmitter.emitFields(cls, builder); | 1468 classEmitter.emitFields(cls, builder); |
1406 return builder.fields; | 1469 return builder.fields; |
1407 } | 1470 } |
1408 } | 1471 } |
1409 | 1472 |
1410 // TODO(ahe): Remove this method. | 1473 // TODO(ahe): Remove this method. |
1411 NO_WARN(x) => x; | 1474 NO_WARN(x) => x; |
OLD | NEW |