Chromium Code Reviews| Index: pkg/analyzer/lib/src/context/cache.dart |
| diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart |
| index 67e71bc411172cfeda68b4a9388778bccb8f3fa5..e21fe5d7c008862836cdb4648028f7240aaecefa 100644 |
| --- a/pkg/analyzer/lib/src/context/cache.dart |
| +++ b/pkg/analyzer/lib/src/context/cache.dart |
| @@ -13,6 +13,7 @@ import 'package:analyzer/src/generated/html.dart'; |
| import 'package:analyzer/src/generated/java_engine.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/generated/utilities_collection.dart'; |
| +import 'package:analyzer/src/generated/utilities_general.dart'; |
| import 'package:analyzer/task/model.dart'; |
| /** |
| @@ -134,6 +135,8 @@ class AnalysisCache { |
| * Associate the given [entry] with the given [target]. |
| */ |
| void put(AnalysisTarget target, CacheEntry entry) { |
| + entry._cache = this; |
| + entry._target = target; |
| entry.fixExceptionState(); |
| int count = _partitions.length; |
| for (int i = 0; i < count; i++) { |
| @@ -213,6 +216,18 @@ class AnalysisCache { |
| } |
| } |
| } |
| + |
| + ResultData _getDataFor(TargetedResult result) { |
| + AnalysisTarget target = result.target; |
| + int count = _partitions.length; |
| + for (int i = 0; i < count; i++) { |
| + if (_partitions[i].contains(target)) { |
| + CacheEntry entry = _partitions[i].get(target); |
| + return entry._getResultData(result.result); |
| + } |
| + } |
| + return null; |
| + } |
| } |
| /** |
| @@ -227,6 +242,16 @@ class CacheEntry { |
| static int _EXPLICITLY_ADDED_FLAG = 0; |
| /** |
| + * The cache that contains this entry. |
| + */ |
| + AnalysisCache _cache; |
| + |
| + /** |
| + * The target this entry is about. |
| + */ |
| + AnalysisTarget _target; |
| + |
| + /** |
| * The most recent time at which the state of the target matched the state |
| * represented by this entry. |
| */ |
| @@ -363,9 +388,9 @@ class CacheEntry { |
| getState(descriptor) == CacheState.VALID; |
| /** |
| - * Set the [CacheState.ERROR] state for given [descriptors], their values to |
| - * the corresponding default values, and remember the [exception] that caused |
| - * this state. |
| + * For each of the given [descriptors], set their states to |
| + * [CacheState.ERROR], their values to the corresponding default values, and |
| + * remember the [exception] that caused this state. |
| */ |
| void setErrorState( |
| CaughtException exception, List<ResultDescriptor> descriptors) { |
| @@ -378,6 +403,7 @@ class CacheEntry { |
| this._exception = exception; |
| for (ResultDescriptor descriptor in descriptors) { |
| ResultData data = _getResultData(descriptor); |
| + data._invalidate(_cache, new TargetedResult(_target, descriptor)); |
| data.state = CacheState.ERROR; |
| data.value = descriptor.defaultValue; |
| } |
| @@ -396,7 +422,11 @@ class CacheEntry { |
| } |
| _validateStateChange(descriptor, state); |
| if (state == CacheState.INVALID) { |
| - _resultMap.remove(descriptor); |
| + ResultData data = _resultMap[descriptor]; |
| + if (data != null) { |
| + TargetedResult thisResult = new TargetedResult(_target, descriptor); |
| + data._invalidate(_cache, thisResult); |
| + } |
| } else { |
| ResultData data = _getResultData(descriptor); |
| data.state = state; |
| @@ -415,9 +445,14 @@ class CacheEntry { |
| * given [value]. |
| */ |
| /*<V>*/ void setValue(ResultDescriptor /*<V>*/ descriptor, dynamic /*V*/ |
| - value) { |
| + value, List<TargetedResult> dependedOn) { |
| _validateStateChange(descriptor, CacheState.VALID); |
| ResultData data = _getResultData(descriptor); |
| + { |
| + TargetedResult thisResult = new TargetedResult(_target, descriptor); |
| + data._invalidate(_cache, thisResult); |
| + data._setDependedOnResults(_cache, thisResult, dependedOn); |
| + } |
| data.state = CacheState.VALID; |
| data.value = value == null ? descriptor.defaultValue : value; |
| } |
| @@ -771,6 +806,11 @@ class DefaultRetentionPolicy implements CacheRetentionPolicy { |
| // can be typed. |
| class ResultData { |
| /** |
| + * The [ResultDescriptor] this result is for. |
| + */ |
| + final ResultDescriptor descriptor; |
| + |
| + /** |
| * The state of the cached value. |
| */ |
| CacheState state; |
| @@ -782,12 +822,76 @@ class ResultData { |
| Object value; |
| /** |
| + * A list of the results on which this result depends. |
| + */ |
| + List<TargetedResult> _dependedOnResults = <TargetedResult>[]; |
| + |
| + /** |
| + * A list of the results that depend on this result. |
| + */ |
| + List<TargetedResult> _dependentResults = <TargetedResult>[]; |
| + |
| + /** |
| * Initialize a newly created result holder to represent the value of data |
| * described by the given [descriptor]. |
| */ |
| - ResultData(ResultDescriptor descriptor) { |
| + ResultData(this.descriptor) { |
| + state = CacheState.INVALID; |
| + value = descriptor.defaultValue; |
| + } |
| + |
| + /** |
| + * Add the given [result] to the list of dependent results. |
| + */ |
| + void _addDependentResult(TargetedResult result) { |
|
Brian Wilkerson
2015/05/03 15:35:32
I don't understand why we would make these private
scheglov
2015/05/03 20:26:28
No, you're right.
I will make these new methods an
|
| + _dependentResults.add(result); |
| + } |
| + |
| + /** |
| + * Remove the given [result] from the list of dependent results. |
| + */ |
| + void _removeDependentResult(TargetedResult result) { |
| + _dependentResults.remove(result); |
| + } |
| + |
| + /** |
| + * Invalidate this [ResultData] that corresponds to [thisResult] and |
| + * propagate invalidation to the results that depend on this one. |
| + */ |
| + void _invalidate(AnalysisCache cache, TargetedResult thisResult) { |
| + // Invalidate this result. |
| state = CacheState.INVALID; |
| value = descriptor.defaultValue; |
| + // Stop depending on other results. |
| + List<TargetedResult> dependedOnResults = _dependedOnResults; |
| + _dependedOnResults = <TargetedResult>[]; |
| + dependedOnResults.forEach((TargetedResult dependedOnResult) { |
| + ResultData data = cache._getDataFor(dependedOnResult); |
| + data._removeDependentResult(thisResult); |
| + }); |
| + // Invalidate results that depend on this result. |
| + List<TargetedResult> dependentResults = _dependentResults; |
| + _dependentResults = <TargetedResult>[]; |
| + dependentResults.forEach((TargetedResult dependentResult) { |
| + ResultData data = cache._getDataFor(dependentResult); |
| + data._invalidate(cache, dependentResult); |
| + }); |
| + } |
| + |
| + /** |
| + * Set the [dependedOn] on which this result depends. |
| + */ |
| + void _setDependedOnResults(AnalysisCache cache, TargetedResult thisResult, |
| + List<TargetedResult> dependedOn) { |
| + _dependedOnResults.forEach((TargetedResult dependedOnResult) { |
| + ResultData data = cache._getDataFor(dependedOnResult); |
| + data._removeDependentResult(thisResult); |
| + }); |
| + _dependedOnResults = dependedOn; |
| + _dependedOnResults.forEach((TargetedResult dependentResult) { |
| + ResultData data = cache._getDataFor(dependentResult); |
| + data._addDependentResult(thisResult); |
| + }); |
| } |
| } |
| @@ -811,6 +915,46 @@ class SdkCachePartition extends CachePartition { |
| } |
| /** |
| + * A specification of a specific result computed for a specific target. |
| + */ |
| +class TargetedResult { |
| + /** |
| + * An empty list of results. |
| + */ |
| + static final List<TargetedResult> EMPTY_LIST = const <TargetedResult>[]; |
| + |
| + /** |
| + * The target with which the result is associated. |
| + */ |
| + final AnalysisTarget target; |
| + |
| + /** |
| + * The result associated with the target. |
| + */ |
| + final ResultDescriptor result; |
| + |
| + /** |
| + * Initialize a new targeted result. |
| + */ |
| + TargetedResult(this.target, this.result); |
| + |
| + @override |
| + int get hashCode { |
| + return JenkinsSmiHash.combine(target.hashCode, result.hashCode); |
| + } |
| + |
| + @override |
| + bool operator ==(other) { |
| + return other is TargetedResult && |
| + other.target == target && |
| + other.result == result; |
| + } |
| + |
| + @override |
| + String toString() => '$result for $target'; |
| +} |
| + |
| +/** |
| * A cache partition that contains all targets not contained in other partitions. |
| */ |
| class UniversalCachePartition extends CachePartition { |