| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |