Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(377)

Side by Side Diff: pkg/analyzer/lib/src/dart/analysis/driver.dart

Issue 2450283003: Try to load the existing unlinked bundle by the content hash. (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:collection'; 6 import 'dart:collection';
7 import 'dart:convert'; 7 import 'dart:convert';
8 8
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart'; 10 import 'package:analyzer/dart/ast/token.dart';
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 continue; 228 continue;
229 } 229 }
230 230
231 // TODO(scheglov) analyze requested files 231 // TODO(scheglov) analyze requested files
232 232
233 // Analyze a priority file. 233 // Analyze a priority file.
234 if (_priorityFiles.isNotEmpty) { 234 if (_priorityFiles.isNotEmpty) {
235 bool analyzed = false; 235 bool analyzed = false;
236 for (String path in _priorityFiles) { 236 for (String path in _priorityFiles) {
237 if (_filesToAnalyze.remove(path)) { 237 if (_filesToAnalyze.remove(path)) {
238 _File file = _fileForPath(path);
239 AnalysisResult result = 238 AnalysisResult result =
240 _computeAnalysisResult(file, withUnit: true); 239 _computeAnalysisResult(path, withUnit: true);
241 yield result; 240 yield result;
242 break; 241 break;
243 } 242 }
244 } 243 }
245 // Repeat the processing loop. 244 // Repeat the processing loop.
246 if (analyzed) { 245 if (analyzed) {
247 _hasWork.notify(); 246 _hasWork.notify();
248 continue; 247 continue;
249 } 248 }
250 } 249 }
251 250
252 // Analyze a general file. 251 // Analyze a general file.
253 if (_filesToAnalyze.isNotEmpty) { 252 if (_filesToAnalyze.isNotEmpty) {
254 String path = _removeFirst(_filesToAnalyze); 253 String path = _removeFirst(_filesToAnalyze);
255 _File file = _fileForPath(path); 254 AnalysisResult result = _computeAnalysisResult(path, withUnit: false);
256 AnalysisResult result = _computeAnalysisResult(file, withUnit: false);
257 yield result; 255 yield result;
258 // Repeat the processing loop. 256 // Repeat the processing loop.
259 _hasWork.notify(); 257 _hasWork.notify();
260 continue; 258 continue;
261 } 259 }
262 260
263 // There is nothing to do. 261 // There is nothing to do.
264 analysisSection.exit(); 262 analysisSection.exit();
265 analysisSection = null; 263 analysisSection = null;
266 } 264 }
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 * add [UnlinkedUnit] with wrong URI. 357 * add [UnlinkedUnit] with wrong URI.
360 * 358 *
361 * We need to clean this up. 359 * We need to clean this up.
362 */ 360 */
363 void _addToStoreUnlinked( 361 void _addToStoreUnlinked(
364 SummaryDataStore store, String uri, UnlinkedUnit unlinked) { 362 SummaryDataStore store, String uri, UnlinkedUnit unlinked) {
365 store.unlinkedMap[uri] = unlinked; 363 store.unlinkedMap[uri] = unlinked;
366 } 364 }
367 365
368 /** 366 /**
369 * Compute the [AnalysisResult] for the [file]. 367 * Return the cached or newly computed analysis result of the file with the
368 * given [path].
370 * 369 *
371 * The result will have the fully resolved unit only if [withUnit] is `true`. 370 * The result will have the fully resolved unit and will always be newly
371 * compute only if [withUnit] is `true`.
372 */ 372 */
373 AnalysisResult _computeAnalysisResult(_File file, {bool withUnit: false}) { 373 AnalysisResult _computeAnalysisResult(String path, {bool withUnit: false}) {
374 // If we don't need to the fully resolved unit, check for a cached result. 374 Source source = _sourceForPath(path);
375
376 // If we don't need the fully resolved unit, check for the cached result.
375 if (!withUnit) { 377 if (!withUnit) {
376 AnalysisResult result = _getCachedAnalysisResult(file); 378 _File file = new _File.forLinking(this, source);
379 // Prepare the key for the cached result.
380 String key = _getResolvedUnitKey(file);
381 if (key == null) {
382 _logger.run('Compute the dependency hash for $source', () {
383 _createLibraryContext(file);
384 key = _getResolvedUnitKey(file);
385 });
386 }
387 // Check for the cached result.
388 AnalysisResult result = _getCachedAnalysisResult(file, key);
377 if (result != null) { 389 if (result != null) {
378 return result; 390 return result;
379 } 391 }
380 } 392 }
381 393
382 // We need the fully resolved unit, or the result is not cached. 394 // We need the fully resolved unit, or the result is not cached.
383 return _logger.run('Compute analysis result for $file', () { 395 return _logger.run('Compute analysis result for $source', () {
396 // Still no result, compute and store it.
397 _File file = new _File.forResolution(this, source);
384 _LibraryContext libraryContext = _createLibraryContext(file); 398 _LibraryContext libraryContext = _createLibraryContext(file);
385
386 // We recomputed the dependency hash, and we might have a cached result.
387 if (!withUnit) {
388 AnalysisResult result = _getCachedAnalysisResult(file);
389 if (result != null) {
390 _logger.writeln('Return the cached analysis result.');
391 return result;
392 }
393 }
394
395 // Still no result, compute and store it.
396 AnalysisContext analysisContext = _createAnalysisContext(libraryContext); 399 AnalysisContext analysisContext = _createAnalysisContext(libraryContext);
397 try { 400 try {
398 analysisContext.setContents(file.source, file.content); 401 analysisContext.setContents(file.source, file.content);
399 // TODO(scheglov) Add support for parts. 402 // TODO(scheglov) Add support for parts.
400 CompilationUnit resolvedUnit = 403 CompilationUnit resolvedUnit =
401 analysisContext.resolveCompilationUnit2(file.source, file.source); 404 analysisContext.resolveCompilationUnit2(file.source, file.source);
402 List<AnalysisError> errors = analysisContext.computeErrors(file.source); 405 List<AnalysisError> errors = analysisContext.computeErrors(file.source);
403 406
404 // Store the result into the cache. 407 // Store the result into the cache.
405 { 408 {
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 PackageBundle linked = new PackageBundle.fromBuffer(bytes); 555 PackageBundle linked = new PackageBundle.fromBuffer(bytes);
553 _addToStoreLinked(store, uri, linked.linkedLibraries.single); 556 _addToStoreLinked(store, uri, linked.linkedLibraries.single);
554 _byteStore.put(key, bytes); 557 _byteStore.put(key, bytes);
555 }); 558 });
556 559
557 return new _LibraryContext(libraryFile, libraryNode, store); 560 return new _LibraryContext(libraryFile, libraryNode, store);
558 }); 561 });
559 } 562 }
560 563
561 /** 564 /**
562 * Return the [_File] for the given [path] in [_sourceFactory]. 565 * If we know the result [key] for the [file], try to load the analysis
566 * result from the cache. Return `null` if not found.
563 */ 567 */
564 _File _fileForPath(String path) { 568 AnalysisResult _getCachedAnalysisResult(_File file, String key) {
565 Source fileSource = _resourceProvider.getFile(path).createSource(); 569 List<int> bytes = _byteStore.get(key);
566 Uri uri = _sourceFactory.restoreUri(fileSource); 570 if (bytes != null) {
567 Source source = _resourceProvider.getFile(path).createSource(uri); 571 var unit = new AnalysisDriverResolvedUnit.fromBuffer(bytes);
568 return new _File.forResolution(this, source); 572 List<AnalysisError> errors = unit.errors
569 } 573 .map((error) => new AnalysisError.forValues(
570 574 file.source,
571 /** 575 error.offset,
572 * If we know the dependency signature for the [file], try to load the 576 error.length,
573 * analysis result from the cache. Return `null` if not found. 577 ErrorCode.byUniqueName(error.uniqueName),
574 */ 578 error.message,
575 AnalysisResult _getCachedAnalysisResult(_File file) { 579 error.correction))
576 String key = _getResolvedUnitKey(file); 580 .toList();
577 if (key != null) { 581 return new AnalysisResult(
578 List<int> bytes = _byteStore.get(key); 582 file.path, file.uri, null, file.contentHash, null, errors);
579 if (bytes != null) {
580 var unit = new AnalysisDriverResolvedUnit.fromBuffer(bytes);
581 List<AnalysisError> errors = unit.errors
582 .map((error) => new AnalysisError.forValues(
583 file.source,
584 error.offset,
585 error.length,
586 ErrorCode.byUniqueName(error.uniqueName),
587 error.message,
588 error.correction))
589 .toList();
590 return new AnalysisResult(
591 file.path, file.uri, null, file.contentHash, null, errors);
592 }
593 } 583 }
594 return null; 584 return null;
595 } 585 }
596 586
597 /** 587 /**
598 * Return the key to store fully resolved results for the [file] into the 588 * Return the key to store fully resolved results for the [file] into the
599 * cache. Return `null` if the dependency signature is not known yet. 589 * cache. Return `null` if the dependency signature is not known yet.
600 */ 590 */
601 String _getResolvedUnitKey(_File file) { 591 String _getResolvedUnitKey(_File file) {
602 String dependencyHash = _dependencySignatureMap[file.uri]; 592 String dependencyHash = _dependencySignatureMap[file.uri];
603 if (dependencyHash != null) { 593 if (dependencyHash != null) {
604 ApiSignature signature = new ApiSignature(); 594 ApiSignature signature = new ApiSignature();
605 signature.addString(dependencyHash); 595 signature.addString(dependencyHash);
606 signature.addString(file.contentHash); 596 signature.addString(file.contentHash);
607 return '${signature.toHex()}.resolved'; 597 return '${signature.toHex()}.resolved';
608 } 598 }
609 return null; 599 return null;
610 } 600 }
611 601
612 /** 602 /**
603 * Return the [Source] for the given [path] in [_sourceFactory].
604 */
605 Source _sourceForPath(String path) {
606 Source fileSource = _resourceProvider.getFile(path).createSource();
607 Uri uri = _sourceFactory.restoreUri(fileSource);
608 return _resourceProvider.getFile(path).createSource(uri);
609 }
610
611 /**
613 * Verify the API signature for the file with the given [path], and decide 612 * Verify the API signature for the file with the given [path], and decide
614 * which linked libraries should be invalidated, and files reanalyzed. 613 * which linked libraries should be invalidated, and files reanalyzed.
615 * 614 *
616 * TODO(scheglov) I see that adding a local var changes (full) API signature. 615 * TODO(scheglov) I see that adding a local var changes (full) API signature.
617 */ 616 */
618 void _verifyApiSignatureOfChangedFile(String path) { 617 void _verifyApiSignatureOfChangedFile(String path) {
619 _logger.run('Verify API signature of $path', () { 618 _logger.run('Verify API signature of $path', () {
620 String oldSignature = _fileApiSignatureMap[path]; 619 String oldSignature = _fileApiSignatureMap[path];
621 // Compute the new API signature. 620 // Compute the new API signature.
622 // _File.forResolution() also updates the content hash in the cache. 621 // _File.forResolution() also updates the content hash in the cache.
623 _File newFile = _fileForPath(path); 622 Source source = _sourceForPath(path);
623 _File newFile = new _File.forResolution(this, source);
624 String newSignature = newFile.unlinked.apiSignature; 624 String newSignature = newFile.unlinked.apiSignature;
625 // If the old API signature is not null, then the file was used to 625 // If the old API signature is not null, then the file was used to
626 // compute at least one dependency signature. If the new API signature 626 // compute at least one dependency signature. If the new API signature
627 // is different, then potentially all dependency signatures and 627 // is different, then potentially all dependency signatures and
628 // resolution results are invalid. 628 // resolution results are invalid.
629 if (oldSignature != null && oldSignature != newSignature) { 629 if (oldSignature != null && oldSignature != newSignature) {
630 _logger.writeln('API signatures mismatch found for $newFile'); 630 _logger.writeln('API signatures mismatch found for $newFile');
631 _dependencySignatureMap.clear(); 631 _dependencySignatureMap.clear();
632 _filesToAnalyze.addAll(_explicitFiles); 632 _filesToAnalyze.addAll(_explicitFiles);
633 } 633 }
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
809 /** 809 /**
810 * The unlinked bundle, not `null`. 810 * The unlinked bundle, not `null`.
811 */ 811 */
812 final PackageBundle unlinked; 812 final PackageBundle unlinked;
813 813
814 /** 814 /**
815 * The unresolved unit, not `null` if this file is for resolution. 815 * The unresolved unit, not `null` if this file is for resolution.
816 */ 816 */
817 final CompilationUnit unit; 817 final CompilationUnit unit;
818 818
819 factory _File.forLinking(AnalysisDriver driver, Source source) { 819 /**
820 // If we have enough cached information, use it. 820 * Return the file with consistent [content] and [contentHash].
821 String contentHash = driver._fileContentHashMap[source.fullName]; 821 */
822 if (contentHash != null) { 822 factory _File.forContent(AnalysisDriver driver, Source source) {
823 String key = '$contentHash.unlinked';
824 List<int> bytes = driver._byteStore.get(key);
825 if (bytes != null) {
826 PackageBundle unlinked = new PackageBundle.fromBuffer(bytes);
827 return new _File._(driver, source, null, contentHash, unlinked, null);
828 }
829 }
830 // Otherwise, read the source, parse and build a new unlinked bundle.
831 return new _File.forResolution(driver, source);
832 }
833
834 factory _File.forResolution(AnalysisDriver driver, Source source) {
835 String path = source.fullName; 823 String path = source.fullName;
836 // Read the content. 824 // Read the content.
837 String content; 825 String content;
838 try { 826 try {
839 content = driver._contentCache.getContents(source); 827 content = driver._contentCache.getContents(source);
840 content ??= source.contents.data; 828 content ??= source.contents.data;
841 } catch (_) { 829 } catch (_) {
842 content = ''; 830 content = '';
843 // TODO(scheglov) We fail to report URI_DOES_NOT_EXIST. 831 // TODO(scheglov) We fail to report URI_DOES_NOT_EXIST.
844 // On one hand we need to provide an unlinked bundle to prevent 832 // On one hand we need to provide an unlinked bundle to prevent
845 // analysis context from reading the file (we want it to work 833 // analysis context from reading the file (we want it to work
846 // hermetically and handle one one file at a time). OTOH, 834 // hermetically and handle one one file at a time). OTOH,
847 // ResynthesizerResultProvider happily reports that any source in the 835 // ResynthesizerResultProvider happily reports that any source in the
848 // SummaryDataStore has MODIFICATION_TIME `0`. We need to return `-1` 836 // SummaryDataStore has MODIFICATION_TIME `0`. We need to return `-1`
849 // for missing files. Maybe add this feature to SummaryDataStore? 837 // for missing files. Maybe add this feature to SummaryDataStore?
850 } 838 }
851 // Compute the content hash. 839 // Compute the content hash.
852 List<int> textBytes = UTF8.encode(content); 840 List<int> textBytes = UTF8.encode(content);
853 List<int> hashBytes = md5.convert(textBytes).bytes; 841 List<int> hashBytes = md5.convert(textBytes).bytes;
854 String contentHash = hex.encode(hashBytes); 842 String contentHash = hex.encode(hashBytes);
855 driver._fileContentHashMap[path] = contentHash; 843 driver._fileContentHashMap[path] = contentHash;
844 // Return information about the file content.
845 return new _File._(driver, source, content, contentHash, null, null);
846 }
847
848 factory _File.forLinking(AnalysisDriver driver, Source source) {
849 String path = source.fullName;
850 String contentHash = driver._fileContentHashMap[path];
851 // If we don't have the file content hash, compute it.
852 if (contentHash == null) {
853 _File file = new _File.forContent(driver, source);
854 contentHash = file.contentHash;
855 }
856 // If we have the cached unlinked bundle, use it.
857 {
858 String key = '$contentHash.unlinked';
859 List<int> bytes = driver._byteStore.get(key);
860 if (bytes != null) {
861 PackageBundle unlinked = new PackageBundle.fromBuffer(bytes);
862 driver._fileApiSignatureMap[path] = unlinked.apiSignature;
863 return new _File._(driver, source, null, contentHash, unlinked, null);
864 }
865 }
866 // Otherwise, read the source, parse and build a new unlinked bundle.
867 return new _File.forResolution(driver, source);
868 }
869
870 factory _File.forResolution(AnalysisDriver driver, Source source) {
871 _File file = new _File.forContent(driver, source);
872 String path = file.path;
873 String content = file.content;
874 String contentHash = file.contentHash;
856 // Parse the unit. 875 // Parse the unit.
857 CompilationUnit unit = _parse(driver, source, content); 876 CompilationUnit unit = _parse(driver, source, content);
858 // Prepare the unlinked bundle. 877 // Prepare the unlinked bundle.
859 PackageBundle unlinked; 878 PackageBundle unlinked;
860 { 879 {
861 String key = '$contentHash.unlinked'; 880 String key = '$contentHash.unlinked';
862 List<int> bytes = driver._byteStore.get(key); 881 List<int> bytes = driver._byteStore.get(key);
863 if (bytes == null) { 882 if (bytes == null) {
864 driver._logger.run('Create unlinked for $path', () { 883 driver._logger.run('Create unlinked for $path', () {
865 UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit); 884 UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
866 PackageBundleAssembler assembler = new PackageBundleAssembler(); 885 PackageBundleAssembler assembler = new PackageBundleAssembler();
867 assembler.addUnlinkedUnitWithHash( 886 assembler.addUnlinkedUnitWithHash(
868 source.uri.toString(), unlinkedUnit, contentHash); 887 source.uri.toString(), unlinkedUnit, contentHash);
869 bytes = assembler.assemble().toBuffer(); 888 bytes = assembler.assemble().toBuffer();
870 driver._byteStore.put(key, bytes); 889 driver._byteStore.put(key, bytes);
871 }); 890 });
872 } 891 }
873 unlinked = new PackageBundle.fromBuffer(bytes); 892 unlinked = new PackageBundle.fromBuffer(bytes);
874 driver._fileApiSignatureMap[path] = unlinked.apiSignature; 893 driver._fileApiSignatureMap[path] = unlinked.apiSignature;
875 } 894 }
876 // Update the current file state. 895 // Return the full file.
877 return new _File._(driver, source, content, contentHash, unlinked, unit); 896 return new _File._(driver, source, content, contentHash, unlinked, unit);
878 } 897 }
879 898
880 _File._(this.driver, this.source, this.content, this.contentHash, 899 _File._(this.driver, this.source, this.content, this.contentHash,
881 this.unlinked, this.unit); 900 this.unlinked, this.unit);
882 901
883 String get path => source.fullName; 902 String get path => source.fullName;
884 903
885 Uri get uri => source.uri; 904 Uri get uri => source.uri;
886 905
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
1082 } 1101 }
1083 } 1102 }
1084 for (UnlinkedExportPublic export in unit.publicNamespace.exports) { 1103 for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
1085 referenced.exported.add(export.uri); 1104 referenced.exported.add(export.uri);
1086 } 1105 }
1087 return referenced; 1106 return referenced;
1088 } 1107 }
1089 1108
1090 _ReferencedUris._(); 1109 _ReferencedUris._();
1091 } 1110 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698