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

Side by Side Diff: pkg/analyzer/lib/src/context/cache.dart

Issue 2008133002: Fix cross-partition dependency handling (issue 26466) (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 months 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 analyzer.src.context.cache; 5 library analyzer.src.context.cache;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 9
10 import 'package:analyzer/src/dart/element/element.dart' 10 import 'package:analyzer/src/dart/element/element.dart'
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 <ReentrantSynchronousStreamSubscription>[]; 47 <ReentrantSynchronousStreamSubscription>[];
48 48
49 /** 49 /**
50 * Initialize a newly created cache to have the given [_partitions]. The 50 * Initialize a newly created cache to have the given [_partitions]. The
51 * partitions will be searched in the order in which they appear in the array, 51 * partitions will be searched in the order in which they appear in the array,
52 * so the most specific partition (usually an [SdkCachePartition]) should be 52 * so the most specific partition (usually an [SdkCachePartition]) should be
53 * first and the most general (usually a [UniversalCachePartition]) last. 53 * first and the most general (usually a [UniversalCachePartition]) last.
54 */ 54 */
55 AnalysisCache(this._partitions) { 55 AnalysisCache(this._partitions) {
56 for (CachePartition partition in _partitions) { 56 for (CachePartition partition in _partitions) {
57 partition.containingCaches.add(this);
57 ReentrantSynchronousStreamSubscription<InvalidatedResult> subscription = 58 ReentrantSynchronousStreamSubscription<InvalidatedResult> subscription =
58 partition.onResultInvalidated.listen((InvalidatedResult event) { 59 partition.onResultInvalidated.listen((InvalidatedResult event) {
59 onResultInvalidated.add(event); 60 onResultInvalidated.add(event);
60 }); 61 });
61 onResultInvalidatedPartitionSubscriptions.add(subscription); 62 onResultInvalidatedPartitionSubscriptions.add(subscription);
62 } 63 }
63 } 64 }
64 65
65 /** 66 /**
66 * Return an iterator returning all of the [Source] targets. 67 * Return an iterator returning all of the [Source] targets.
(...skipping 22 matching lines...) Expand all
89 // } 90 // }
90 91
91 /** 92 /**
92 * Free any allocated resources and references. 93 * Free any allocated resources and references.
93 */ 94 */
94 void dispose() { 95 void dispose() {
95 for (ReentrantSynchronousStreamSubscription subscription 96 for (ReentrantSynchronousStreamSubscription subscription
96 in onResultInvalidatedPartitionSubscriptions) { 97 in onResultInvalidatedPartitionSubscriptions) {
97 subscription.cancel(); 98 subscription.cancel();
98 } 99 }
100 for (CachePartition partition in _partitions) {
101 partition.containingCaches.remove(this);
102 }
99 } 103 }
100 104
101 /** 105 /**
102 * Return the entry associated with the given [target]. 106 * Return the entry associated with the given [target].
103 */ 107 */
104 CacheEntry get(AnalysisTarget target) { 108 CacheEntry get(AnalysisTarget target) {
105 int count = _partitions.length; 109 int count = _partitions.length;
106 for (int i = 0; i < count; i++) { 110 for (int i = 0; i < count; i++) {
107 CachePartition partition = _partitions[i]; 111 CachePartition partition = _partitions[i];
108 if (partition.isResponsibleFor(target)) { 112 if (partition.isResponsibleFor(target)) {
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 /** 346 /**
343 * Return a list of result descriptors for results whose state is not 347 * Return a list of result descriptors for results whose state is not
344 * [CacheState.INVALID]. 348 * [CacheState.INVALID].
345 */ 349 */
346 List<ResultDescriptor> get nonInvalidResults => _resultMap.keys.toList(); 350 List<ResultDescriptor> get nonInvalidResults => _resultMap.keys.toList();
347 351
348 /** 352 /**
349 * Notifies the entry that the client is going to stop using it. 353 * Notifies the entry that the client is going to stop using it.
350 */ 354 */
351 void dispose() { 355 void dispose() {
352 _resultMap.forEach((descriptor, data) { 356 _resultMap.forEach((ResultDescriptor descriptor, ResultData data) {
353 TargetedResult result = new TargetedResult(target, descriptor); 357 TargetedResult result = new TargetedResult(target, descriptor);
354 for (TargetedResult dependedOnResult in data.dependedOnResults) { 358 for (TargetedResult dependedOnResult in data.dependedOnResults) {
355 ResultData dependedOnData = _partition._getDataFor(dependedOnResult); 359 for (AnalysisCache cache in _partition.containingCaches) {
356 if (dependedOnData != null) { 360 CacheEntry entry = cache.get(dependedOnResult.target);
357 dependedOnData.dependentResults.remove(result); 361 if (entry != null) {
362 ResultData data =
363 entry.getResultDataOrNull(dependedOnResult.result);
364 if (data != null) {
365 data.dependentResults.remove(result);
366 }
367 }
358 } 368 }
359 } 369 }
360 }); 370 });
361 _resultMap.clear(); 371 _resultMap.clear();
362 AnalysisTarget oldTarget = target; 372 AnalysisTarget oldTarget = target;
363 if (oldTarget is ElementImpl) { 373 if (oldTarget is ElementImpl) {
364 oldTarget.setModifier(Modifier.CACHE_KEY, false); 374 oldTarget.setModifier(Modifier.CACHE_KEY, false);
365 } 375 }
366 } 376 }
367 377
368 /** 378 /**
369 * Fix the state of the [exception] to match the current state of the entry. 379 * Fix the state of the [exception] to match the current state of the entry.
370 */ 380 */
371 void fixExceptionState() { 381 void fixExceptionState() {
372 if (!hasErrorState()) { 382 if (!hasErrorState()) {
373 _exception = null; 383 _exception = null;
374 } 384 }
375 } 385 }
376 386
377 /** 387 /**
378 * Look up the [ResultData] of [descriptor], or add a new one if it isn't 388 * Return the result data associated with the [descriptor], creating one if it
379 * there. 389 * isn't there.
380 */ 390 */
381 ResultData getResultData(ResultDescriptor descriptor) { 391 ResultData getResultData(ResultDescriptor descriptor) {
382 return _resultMap.putIfAbsent(descriptor, () => new ResultData(descriptor)); 392 return _resultMap.putIfAbsent(descriptor, () => new ResultData(descriptor));
383 } 393 }
384 394
385 /** 395 /**
396 * Return the result data associated with the [descriptor], or `null` if there
397 * is no data currently associated with the descriptor.
398 */
399 ResultData getResultDataOrNull(ResultDescriptor descriptor) =>
400 _resultMap[descriptor];
401
402 /**
386 * Return the state of the result represented by the given [descriptor]. 403 * Return the state of the result represented by the given [descriptor].
387 */ 404 */
388 CacheState getState(ResultDescriptor descriptor) { 405 CacheState getState(ResultDescriptor descriptor) {
389 ResultData data = _resultMap[descriptor]; 406 ResultData data = _resultMap[descriptor];
390 if (data == null) { 407 if (data == null) {
391 return CacheState.INVALID; 408 return CacheState.INVALID;
392 } 409 }
393 return data.state; 410 return data.state;
394 } 411 }
395 412
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 if (deltaResult == null || 594 if (deltaResult == null ||
578 deltaResult == DeltaResult.INVALIDATE || 595 deltaResult == DeltaResult.INVALIDATE ||
579 deltaResult == DeltaResult.INVALIDATE_NO_DELTA) { 596 deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
580 _resultMap.remove(descriptor); 597 _resultMap.remove(descriptor);
581 // { 598 // {
582 // String indent = ' ' * level; 599 // String indent = ' ' * level;
583 // print('[$id]$indent invalidate $descriptor for $target'); 600 // print('[$id]$indent invalidate $descriptor for $target');
584 // } 601 // }
585 } 602 }
586 // Stop depending on other results. 603 // Stop depending on other results.
587 TargetedResult thisResult = new TargetedResult(target, descriptor); 604 if (deltaResult != DeltaResult.KEEP_CONTINUE) {
588 for (TargetedResult dependedOnResult in thisData.dependedOnResults) { 605 TargetedResult thisResult = new TargetedResult(target, descriptor);
589 ResultData data = _partition._getDataFor(dependedOnResult); 606 for (TargetedResult dependedOnResult in thisData.dependedOnResults) {
590 if (data != null && deltaResult != DeltaResult.KEEP_CONTINUE) { 607 for (AnalysisCache cache in _partition.containingCaches) {
591 data.dependentResults.remove(thisResult); 608 CacheEntry entry = cache.get(dependedOnResult.target);
609 if (entry != null) {
610 ResultData data =
611 entry.getResultDataOrNull(dependedOnResult.result);
612 if (data != null) {
613 data.dependentResults.remove(thisResult);
614 }
615 }
616 }
592 } 617 }
593 } 618 }
594 // Invalidate results that depend on this result. 619 // Invalidate results that depend on this result.
595 _invalidateDependentResults(id, thisData, delta, level + 1); 620 _invalidateDependentResults(id, thisData, delta, level + 1);
596 // If empty and not explicitly added, remove the entry altogether. 621 // If empty and not explicitly added, remove the entry altogether.
597 if (_resultMap.isEmpty && !explicitlyAdded) { 622 if (_resultMap.isEmpty && !explicitlyAdded) {
598 CacheEntry entry = _partition.entryMap.remove(target); 623 CacheEntry entry = _partition.entryMap.remove(target);
599 if (entry != null) { 624 if (entry != null) {
600 entry.dispose(); 625 entry.dispose();
601 } 626 }
(...skipping 12 matching lines...) Expand all
614 for (ResultDescriptor result in results) { 639 for (ResultDescriptor result in results) {
615 _invalidate(nextInvalidateId++, result, null, 0); 640 _invalidate(nextInvalidateId++, result, null, 0);
616 } 641 }
617 } 642 }
618 643
619 /** 644 /**
620 * Invalidate results that depend on [thisData]. 645 * Invalidate results that depend on [thisData].
621 */ 646 */
622 void _invalidateDependentResults( 647 void _invalidateDependentResults(
623 int id, ResultData thisData, Delta delta, int level) { 648 int id, ResultData thisData, Delta delta, int level) {
649 // It is necessary to copy the results to a list to avoid a concurrent
650 // modification of the set of dependent results.
624 List<TargetedResult> dependentResults = thisData.dependentResults.toList(); 651 List<TargetedResult> dependentResults = thisData.dependentResults.toList();
625 for (TargetedResult dependentResult in dependentResults) { 652 for (TargetedResult dependentResult in dependentResults) {
626 CacheEntry entry = _partition.get(dependentResult.target); 653 for (AnalysisCache cache in _partition.containingCaches) {
627 if (entry != null) { 654 CacheEntry entry = cache.get(dependentResult.target);
628 entry._invalidate(id, dependentResult.result, delta, level); 655 if (entry != null) {
656 entry._invalidate(id, dependentResult.result, delta, level);
657 }
629 } 658 }
630 } 659 }
631 } 660 }
632 661
633 /** 662 /**
634 * If the given `target` is an element, mark it as being a cache key. 663 * If the given `target` is an element, mark it as being a cache key.
635 */ 664 */
636 void _markAsCacheKey(AnalysisTarget target) { 665 void _markAsCacheKey(AnalysisTarget target) {
637 if (target is ElementImpl) { 666 if (target is ElementImpl) {
638 target.setModifier(Modifier.CACHE_KEY, true); 667 target.setModifier(Modifier.CACHE_KEY, true);
639 } 668 }
640 } 669 }
641 670
642 /** 671 /**
643 * Set the [dependedOn] on which this result depends. 672 * Set the [dependedOn] on which this result depends.
644 */ 673 */
645 void _setDependedOnResults(ResultData thisData, TargetedResult thisResult, 674 void _setDependedOnResults(ResultData thisData, TargetedResult thisResult,
646 List<TargetedResult> dependedOn) { 675 List<TargetedResult> dependedOn) {
647 thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) { 676 thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) {
648 ResultData data = _partition._getDataFor(dependedOnResult); 677 for (AnalysisCache cache in _partition.containingCaches) {
649 if (data != null) { 678 CacheEntry entry = cache.get(dependedOnResult.target);
650 data.dependentResults.remove(thisResult); 679 if (entry != null) {
680 ResultData data = entry.getResultDataOrNull(dependedOnResult.result);
681 if (data != null) {
682 data.dependentResults.remove(thisResult);
683 }
684 }
651 } 685 }
652 }); 686 });
653 thisData.dependedOnResults = dependedOn; 687 thisData.dependedOnResults = dependedOn;
654 thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) { 688 thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) {
655 ResultData data = _partition._getDataFor(dependedOnResult); 689 for (AnalysisCache cache in _partition.containingCaches) {
656 if (data != null) { 690 CacheEntry entry = cache.get(dependedOnResult.target);
657 data.dependentResults.add(thisResult); 691 if (entry != null) {
692 ResultData data = entry.getResultDataOrNull(dependedOnResult.result);
693 if (data != null) {
694 data.dependentResults.add(thisResult);
695 }
696 }
658 } 697 }
659 }); 698 });
660 } 699 }
661 700
662 /** 701 /**
663 * Set states of the given and dependent results to [CacheState.ERROR] and 702 * Set states of the given and dependent results to [CacheState.ERROR] and
664 * their values to the corresponding default values 703 * their values to the corresponding default values
665 */ 704 */
666 void _setErrorState(ResultDescriptor descriptor, CaughtException exception) { 705 void _setErrorState(ResultDescriptor descriptor, CaughtException exception) {
667 ResultData thisData = getResultData(descriptor); 706 ResultData thisData = getResultData(descriptor);
668 // Set the error state. 707 // Set the error state.
669 _exception = exception; 708 _exception = exception;
670 thisData.state = CacheState.ERROR; 709 thisData.state = CacheState.ERROR;
671 thisData.value = descriptor.defaultValue; 710 thisData.value = descriptor.defaultValue;
672 // Propagate the error state. 711 // Propagate the error state.
673 thisData.dependentResults.forEach((TargetedResult dependentResult) { 712 thisData.dependentResults.forEach((TargetedResult dependentResult) {
674 CacheEntry entry = _partition.get(dependentResult.target); 713 for (AnalysisCache cache in _partition.containingCaches) {
675 entry._setErrorState(dependentResult.result, exception); 714 CacheEntry entry = cache.get(dependentResult.target);
715 if (entry != null) {
716 entry._setErrorState(dependentResult.result, exception);
717 }
718 }
676 }); 719 });
677 } 720 }
678 721
679 /** 722 /**
680 * Set the value of the flag with the given [index] to the given [value]. 723 * Set the value of the flag with the given [index] to the given [value].
681 */ 724 */
682 void _setFlag(int index, bool value) { 725 void _setFlag(int index, bool value) {
683 _flags = BooleanArray.set(_flags, index, value); 726 _flags = BooleanArray.set(_flags, index, value);
684 } 727 }
685 728
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
858 * A single partition in an LRU cache of information related to analysis. 901 * A single partition in an LRU cache of information related to analysis.
859 */ 902 */
860 abstract class CachePartition { 903 abstract class CachePartition {
861 /** 904 /**
862 * The context that owns this partition. Multiple contexts can reference a 905 * The context that owns this partition. Multiple contexts can reference a
863 * partition, but only one context can own it. 906 * partition, but only one context can own it.
864 */ 907 */
865 final InternalAnalysisContext context; 908 final InternalAnalysisContext context;
866 909
867 /** 910 /**
911 * A list of the caches that contain this partition. This includes the cache
912 * associated with the context that owns this partition.
913 */
914 final List<AnalysisCache> containingCaches = <AnalysisCache>[];
915
916 /**
868 * A table mapping caching policies to the cache flush managers. 917 * A table mapping caching policies to the cache flush managers.
869 */ 918 */
870 final HashMap<ResultCachingPolicy, CacheFlushManager> _flushManagerMap = 919 final HashMap<ResultCachingPolicy, CacheFlushManager> _flushManagerMap =
871 new HashMap<ResultCachingPolicy, CacheFlushManager>(); 920 new HashMap<ResultCachingPolicy, CacheFlushManager>();
872 921
873 /** 922 /**
874 * The [StreamController] reporting [InvalidatedResult]s. 923 * The [StreamController] reporting [InvalidatedResult]s.
875 */ 924 */
876 final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated = 925 final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
877 new ReentrantSynchronousStream<InvalidatedResult>(); 926 new ReentrantSynchronousStream<InvalidatedResult>();
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
1006 * If the given [target] is a [Source], adds it to [sources]. 1055 * If the given [target] is a [Source], adds it to [sources].
1007 */ 1056 */
1008 void _addIfSource(AnalysisTarget target) { 1057 void _addIfSource(AnalysisTarget target) {
1009 if (target is Source) { 1058 if (target is Source) {
1010 sources.add(target); 1059 sources.add(target);
1011 String fullName = target.fullName; 1060 String fullName = target.fullName;
1012 pathToSource.putIfAbsent(fullName, () => <Source>[]).add(target); 1061 pathToSource.putIfAbsent(fullName, () => <Source>[]).add(target);
1013 } 1062 }
1014 } 1063 }
1015 1064
1016 ResultData _getDataFor(TargetedResult result) {
1017 CacheEntry entry = context.analysisCache.get(result.target);
1018 return entry != null ? entry._resultMap[result.result] : null;
1019 }
1020
1021 /** 1065 /**
1022 * Return the [CacheFlushManager] for the given [descriptor], not `null`. 1066 * Return the [CacheFlushManager] for the given [descriptor], not `null`.
1023 */ 1067 */
1024 CacheFlushManager _getFlushManager(ResultDescriptor descriptor) { 1068 CacheFlushManager _getFlushManager(ResultDescriptor descriptor) {
1025 ResultCachingPolicy policy = descriptor.cachingPolicy; 1069 ResultCachingPolicy policy = descriptor.cachingPolicy;
1026 if (identical(policy, DEFAULT_CACHING_POLICY)) { 1070 if (identical(policy, DEFAULT_CACHING_POLICY)) {
1027 return UnlimitedCacheFlushManager.INSTANCE; 1071 return UnlimitedCacheFlushManager.INSTANCE;
1028 } 1072 }
1029 CacheFlushManager manager = _flushManagerMap[policy]; 1073 CacheFlushManager manager = _flushManagerMap[policy];
1030 if (manager == null) { 1074 if (manager == null) {
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
1279 void resultAccessed(TargetedResult result) {} 1323 void resultAccessed(TargetedResult result) {}
1280 1324
1281 @override 1325 @override
1282 List<TargetedResult> resultStored(TargetedResult newResult, newValue) { 1326 List<TargetedResult> resultStored(TargetedResult newResult, newValue) {
1283 return TargetedResult.EMPTY_LIST; 1327 return TargetedResult.EMPTY_LIST;
1284 } 1328 }
1285 1329
1286 @override 1330 @override
1287 void targetRemoved(AnalysisTarget target) {} 1331 void targetRemoved(AnalysisTarget target) {}
1288 } 1332 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/context/context.dart » ('j') | pkg/analyzer/lib/src/context/context.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698