Chromium Code Reviews| 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:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/src/generated/ast.dart'; | 9 import 'package:analyzer/src/generated/ast.dart'; |
| 10 import 'package:analyzer/src/generated/engine.dart' | 10 import 'package:analyzer/src/generated/engine.dart' |
| 11 show AnalysisEngine, CacheState, InternalAnalysisContext, RetentionPriority; | 11 show AnalysisEngine, CacheState, InternalAnalysisContext, RetentionPriority; |
| 12 import 'package:analyzer/src/generated/html.dart'; | 12 import 'package:analyzer/src/generated/html.dart'; |
| 13 import 'package:analyzer/src/generated/java_engine.dart'; | 13 import 'package:analyzer/src/generated/java_engine.dart'; |
| 14 import 'package:analyzer/src/generated/source.dart'; | 14 import 'package:analyzer/src/generated/source.dart'; |
| 15 import 'package:analyzer/src/generated/utilities_collection.dart'; | 15 import 'package:analyzer/src/generated/utilities_collection.dart'; |
| 16 import 'package:analyzer/src/generated/utilities_general.dart'; | |
| 16 import 'package:analyzer/task/model.dart'; | 17 import 'package:analyzer/task/model.dart'; |
| 17 | 18 |
| 18 /** | 19 /** |
| 19 * An LRU cache of results produced by analysis. | 20 * An LRU cache of results produced by analysis. |
| 20 */ | 21 */ |
| 21 class AnalysisCache { | 22 class AnalysisCache { |
| 22 /** | 23 /** |
| 23 * A flag used to control whether trace information should be produced when | 24 * A flag used to control whether trace information should be produced when |
| 24 * the content of the cache is modified. | 25 * the content of the cache is modified. |
| 25 */ | 26 */ |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 127 for (int i = 0; i < count; i++) { | 128 for (int i = 0; i < count; i++) { |
| 128 maps[i] = _partitions[i].map; | 129 maps[i] = _partitions[i].map; |
| 129 } | 130 } |
| 130 return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps); | 131 return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps); |
| 131 } | 132 } |
| 132 | 133 |
| 133 /** | 134 /** |
| 134 * Associate the given [entry] with the given [target]. | 135 * Associate the given [entry] with the given [target]. |
| 135 */ | 136 */ |
| 136 void put(AnalysisTarget target, CacheEntry entry) { | 137 void put(AnalysisTarget target, CacheEntry entry) { |
| 138 entry._cache = this; | |
| 139 entry._target = target; | |
| 137 entry.fixExceptionState(); | 140 entry.fixExceptionState(); |
| 138 int count = _partitions.length; | 141 int count = _partitions.length; |
| 139 for (int i = 0; i < count; i++) { | 142 for (int i = 0; i < count; i++) { |
| 140 if (_partitions[i].contains(target)) { | 143 if (_partitions[i].contains(target)) { |
| 141 if (_TRACE_CHANGES) { | 144 if (_TRACE_CHANGES) { |
| 142 CacheEntry oldEntry = _partitions[i].get(target); | 145 CacheEntry oldEntry = _partitions[i].get(target); |
| 143 if (oldEntry == null) { | 146 if (oldEntry == null) { |
| 144 AnalysisEngine.instance.logger | 147 AnalysisEngine.instance.logger |
| 145 .logInformation('Added a cache entry for $target.'); | 148 .logInformation('Added a cache entry for $target.'); |
| 146 } else { | 149 } else { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 206 */ | 209 */ |
| 207 void storedAst(AnalysisTarget target) { | 210 void storedAst(AnalysisTarget target) { |
| 208 int count = _partitions.length; | 211 int count = _partitions.length; |
| 209 for (int i = 0; i < count; i++) { | 212 for (int i = 0; i < count; i++) { |
| 210 if (_partitions[i].contains(target)) { | 213 if (_partitions[i].contains(target)) { |
| 211 _partitions[i].storedAst(target); | 214 _partitions[i].storedAst(target); |
| 212 return; | 215 return; |
| 213 } | 216 } |
| 214 } | 217 } |
| 215 } | 218 } |
| 219 | |
| 220 ResultData _getDataFor(TargetedResult result) { | |
| 221 AnalysisTarget target = result.target; | |
| 222 int count = _partitions.length; | |
| 223 for (int i = 0; i < count; i++) { | |
| 224 if (_partitions[i].contains(target)) { | |
| 225 CacheEntry entry = _partitions[i].get(target); | |
| 226 return entry._getResultData(result.result); | |
| 227 } | |
| 228 } | |
| 229 return null; | |
| 230 } | |
| 216 } | 231 } |
| 217 | 232 |
| 218 /** | 233 /** |
| 219 * The information cached by an analysis context about an individual target. | 234 * The information cached by an analysis context about an individual target. |
| 220 */ | 235 */ |
| 221 class CacheEntry { | 236 class CacheEntry { |
| 222 /** | 237 /** |
| 223 * The index of the flag indicating whether the source was explicitly added to | 238 * The index of the flag indicating whether the source was explicitly added to |
| 224 * the context or whether the source was implicitly added because it was | 239 * the context or whether the source was implicitly added because it was |
| 225 * referenced by another source. | 240 * referenced by another source. |
| 226 */ | 241 */ |
| 227 static int _EXPLICITLY_ADDED_FLAG = 0; | 242 static int _EXPLICITLY_ADDED_FLAG = 0; |
| 228 | 243 |
| 229 /** | 244 /** |
| 245 * The cache that contains this entry. | |
| 246 */ | |
| 247 AnalysisCache _cache; | |
| 248 | |
| 249 /** | |
| 250 * The target this entry is about. | |
| 251 */ | |
| 252 AnalysisTarget _target; | |
| 253 | |
| 254 /** | |
| 230 * The most recent time at which the state of the target matched the state | 255 * The most recent time at which the state of the target matched the state |
| 231 * represented by this entry. | 256 * represented by this entry. |
| 232 */ | 257 */ |
| 233 int modificationTime = 0; | 258 int modificationTime = 0; |
| 234 | 259 |
| 235 /** | 260 /** |
| 236 * The exception that caused one or more values to have a state of | 261 * The exception that caused one or more values to have a state of |
| 237 * [CacheState.ERROR]. | 262 * [CacheState.ERROR]. |
| 238 */ | 263 */ |
| 239 CaughtException _exception; | 264 CaughtException _exception; |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 356 getState(descriptor) == CacheState.INVALID; | 381 getState(descriptor) == CacheState.INVALID; |
| 357 | 382 |
| 358 /** | 383 /** |
| 359 * Return `true` if the state of the result represented by the given | 384 * Return `true` if the state of the result represented by the given |
| 360 * [descriptor] is [CacheState.VALID]. | 385 * [descriptor] is [CacheState.VALID]. |
| 361 */ | 386 */ |
| 362 bool isValid(ResultDescriptor descriptor) => | 387 bool isValid(ResultDescriptor descriptor) => |
| 363 getState(descriptor) == CacheState.VALID; | 388 getState(descriptor) == CacheState.VALID; |
| 364 | 389 |
| 365 /** | 390 /** |
| 366 * Set the [CacheState.ERROR] state for given [descriptors], their values to | 391 * For each of the given [descriptors], set their states to |
| 367 * the corresponding default values, and remember the [exception] that caused | 392 * [CacheState.ERROR], their values to the corresponding default values, and |
| 368 * this state. | 393 * remember the [exception] that caused this state. |
| 369 */ | 394 */ |
| 370 void setErrorState( | 395 void setErrorState( |
| 371 CaughtException exception, List<ResultDescriptor> descriptors) { | 396 CaughtException exception, List<ResultDescriptor> descriptors) { |
| 372 if (descriptors == null || descriptors.isEmpty) { | 397 if (descriptors == null || descriptors.isEmpty) { |
| 373 throw new ArgumentError('at least one descriptor is expected'); | 398 throw new ArgumentError('at least one descriptor is expected'); |
| 374 } | 399 } |
| 375 if (exception == null) { | 400 if (exception == null) { |
| 376 throw new ArgumentError('an exception is expected'); | 401 throw new ArgumentError('an exception is expected'); |
| 377 } | 402 } |
| 378 this._exception = exception; | 403 this._exception = exception; |
| 379 for (ResultDescriptor descriptor in descriptors) { | 404 for (ResultDescriptor descriptor in descriptors) { |
| 380 ResultData data = _getResultData(descriptor); | 405 ResultData data = _getResultData(descriptor); |
| 406 data._invalidate(_cache, new TargetedResult(_target, descriptor)); | |
| 381 data.state = CacheState.ERROR; | 407 data.state = CacheState.ERROR; |
| 382 data.value = descriptor.defaultValue; | 408 data.value = descriptor.defaultValue; |
| 383 } | 409 } |
| 384 } | 410 } |
| 385 | 411 |
| 386 /** | 412 /** |
| 387 * Set the state of the result represented by the given [descriptor] to the | 413 * Set the state of the result represented by the given [descriptor] to the |
| 388 * given [state]. | 414 * given [state]. |
| 389 */ | 415 */ |
| 390 void setState(ResultDescriptor descriptor, CacheState state) { | 416 void setState(ResultDescriptor descriptor, CacheState state) { |
| 391 if (state == CacheState.ERROR) { | 417 if (state == CacheState.ERROR) { |
| 392 throw new ArgumentError('use setErrorState() to set the state to ERROR'); | 418 throw new ArgumentError('use setErrorState() to set the state to ERROR'); |
| 393 } | 419 } |
| 394 if (state == CacheState.VALID) { | 420 if (state == CacheState.VALID) { |
| 395 throw new ArgumentError('use setValue() to set the state to VALID'); | 421 throw new ArgumentError('use setValue() to set the state to VALID'); |
| 396 } | 422 } |
| 397 _validateStateChange(descriptor, state); | 423 _validateStateChange(descriptor, state); |
| 398 if (state == CacheState.INVALID) { | 424 if (state == CacheState.INVALID) { |
| 399 _resultMap.remove(descriptor); | 425 ResultData data = _resultMap[descriptor]; |
| 426 if (data != null) { | |
| 427 TargetedResult thisResult = new TargetedResult(_target, descriptor); | |
| 428 data._invalidate(_cache, thisResult); | |
| 429 } | |
| 400 } else { | 430 } else { |
| 401 ResultData data = _getResultData(descriptor); | 431 ResultData data = _getResultData(descriptor); |
| 402 data.state = state; | 432 data.state = state; |
| 403 if (state != CacheState.IN_PROCESS) { | 433 if (state != CacheState.IN_PROCESS) { |
| 404 // | 434 // |
| 405 // If the state is in-process, we can leave the current value in the | 435 // If the state is in-process, we can leave the current value in the |
| 406 // cache for any 'get' methods to access. | 436 // cache for any 'get' methods to access. |
| 407 // | 437 // |
| 408 data.value = descriptor.defaultValue; | 438 data.value = descriptor.defaultValue; |
| 409 } | 439 } |
| 410 } | 440 } |
| 411 } | 441 } |
| 412 | 442 |
| 413 /** | 443 /** |
| 414 * Set the value of the result represented by the given [descriptor] to the | 444 * Set the value of the result represented by the given [descriptor] to the |
| 415 * given [value]. | 445 * given [value]. |
| 416 */ | 446 */ |
| 417 /*<V>*/ void setValue(ResultDescriptor /*<V>*/ descriptor, dynamic /*V*/ | 447 /*<V>*/ void setValue(ResultDescriptor /*<V>*/ descriptor, dynamic /*V*/ |
| 418 value) { | 448 value, List<TargetedResult> dependedOn) { |
| 419 _validateStateChange(descriptor, CacheState.VALID); | 449 _validateStateChange(descriptor, CacheState.VALID); |
| 420 ResultData data = _getResultData(descriptor); | 450 ResultData data = _getResultData(descriptor); |
| 451 { | |
| 452 TargetedResult thisResult = new TargetedResult(_target, descriptor); | |
| 453 data._invalidate(_cache, thisResult); | |
| 454 data._setDependedOnResults(_cache, thisResult, dependedOn); | |
| 455 } | |
| 421 data.state = CacheState.VALID; | 456 data.state = CacheState.VALID; |
| 422 data.value = value == null ? descriptor.defaultValue : value; | 457 data.value = value == null ? descriptor.defaultValue : value; |
| 423 } | 458 } |
| 424 | 459 |
| 425 @override | 460 @override |
| 426 String toString() { | 461 String toString() { |
| 427 StringBuffer buffer = new StringBuffer(); | 462 StringBuffer buffer = new StringBuffer(); |
| 428 _writeOn(buffer); | 463 _writeOn(buffer); |
| 429 return buffer.toString(); | 464 return buffer.toString(); |
| 430 } | 465 } |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 764 } | 799 } |
| 765 } | 800 } |
| 766 | 801 |
| 767 /** | 802 /** |
| 768 * The data about a single analysis result that is stored in a [CacheEntry]. | 803 * The data about a single analysis result that is stored in a [CacheEntry]. |
| 769 */ | 804 */ |
| 770 // TODO(brianwilkerson) Consider making this a generic class so that the value | 805 // TODO(brianwilkerson) Consider making this a generic class so that the value |
| 771 // can be typed. | 806 // can be typed. |
| 772 class ResultData { | 807 class ResultData { |
| 773 /** | 808 /** |
| 809 * The [ResultDescriptor] this result is for. | |
| 810 */ | |
| 811 final ResultDescriptor descriptor; | |
| 812 | |
| 813 /** | |
| 774 * The state of the cached value. | 814 * The state of the cached value. |
| 775 */ | 815 */ |
| 776 CacheState state; | 816 CacheState state; |
| 777 | 817 |
| 778 /** | 818 /** |
| 779 * The value being cached, or the default value for the result if there is no | 819 * The value being cached, or the default value for the result if there is no |
| 780 * value (for example, when the [state] is [CacheState.INVALID]). | 820 * value (for example, when the [state] is [CacheState.INVALID]). |
| 781 */ | 821 */ |
| 782 Object value; | 822 Object value; |
| 783 | 823 |
| 784 /** | 824 /** |
| 825 * A list of the results on which this result depends. | |
| 826 */ | |
| 827 List<TargetedResult> _dependedOnResults = <TargetedResult>[]; | |
| 828 | |
| 829 /** | |
| 830 * A list of the results that depend on this result. | |
| 831 */ | |
| 832 List<TargetedResult> _dependentResults = <TargetedResult>[]; | |
| 833 | |
| 834 /** | |
| 785 * Initialize a newly created result holder to represent the value of data | 835 * Initialize a newly created result holder to represent the value of data |
| 786 * described by the given [descriptor]. | 836 * described by the given [descriptor]. |
| 787 */ | 837 */ |
| 788 ResultData(ResultDescriptor descriptor) { | 838 ResultData(this.descriptor) { |
| 789 state = CacheState.INVALID; | 839 state = CacheState.INVALID; |
| 790 value = descriptor.defaultValue; | 840 value = descriptor.defaultValue; |
| 791 } | 841 } |
| 842 | |
| 843 /** | |
| 844 * Add the given [result] to the list of dependent results. | |
| 845 */ | |
| 846 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
| |
| 847 _dependentResults.add(result); | |
| 848 } | |
| 849 | |
| 850 /** | |
| 851 * Remove the given [result] from the list of dependent results. | |
| 852 */ | |
| 853 void _removeDependentResult(TargetedResult result) { | |
| 854 _dependentResults.remove(result); | |
| 855 } | |
| 856 | |
| 857 /** | |
| 858 * Invalidate this [ResultData] that corresponds to [thisResult] and | |
| 859 * propagate invalidation to the results that depend on this one. | |
| 860 */ | |
| 861 void _invalidate(AnalysisCache cache, TargetedResult thisResult) { | |
| 862 // Invalidate this result. | |
| 863 state = CacheState.INVALID; | |
| 864 value = descriptor.defaultValue; | |
| 865 // Stop depending on other results. | |
| 866 List<TargetedResult> dependedOnResults = _dependedOnResults; | |
| 867 _dependedOnResults = <TargetedResult>[]; | |
| 868 dependedOnResults.forEach((TargetedResult dependedOnResult) { | |
| 869 ResultData data = cache._getDataFor(dependedOnResult); | |
| 870 data._removeDependentResult(thisResult); | |
| 871 }); | |
| 872 // Invalidate results that depend on this result. | |
| 873 List<TargetedResult> dependentResults = _dependentResults; | |
| 874 _dependentResults = <TargetedResult>[]; | |
| 875 dependentResults.forEach((TargetedResult dependentResult) { | |
| 876 ResultData data = cache._getDataFor(dependentResult); | |
| 877 data._invalidate(cache, dependentResult); | |
| 878 }); | |
| 879 } | |
| 880 | |
| 881 /** | |
| 882 * Set the [dependedOn] on which this result depends. | |
| 883 */ | |
| 884 void _setDependedOnResults(AnalysisCache cache, TargetedResult thisResult, | |
| 885 List<TargetedResult> dependedOn) { | |
| 886 _dependedOnResults.forEach((TargetedResult dependedOnResult) { | |
| 887 ResultData data = cache._getDataFor(dependedOnResult); | |
| 888 data._removeDependentResult(thisResult); | |
| 889 }); | |
| 890 _dependedOnResults = dependedOn; | |
| 891 _dependedOnResults.forEach((TargetedResult dependentResult) { | |
| 892 ResultData data = cache._getDataFor(dependentResult); | |
| 893 data._addDependentResult(thisResult); | |
| 894 }); | |
| 895 } | |
| 792 } | 896 } |
| 793 | 897 |
| 794 /** | 898 /** |
| 795 * A cache partition that contains all of the targets in the SDK. | 899 * A cache partition that contains all of the targets in the SDK. |
| 796 */ | 900 */ |
| 797 class SdkCachePartition extends CachePartition { | 901 class SdkCachePartition extends CachePartition { |
| 798 /** | 902 /** |
| 799 * Initialize a newly created cache partition, belonging to the given | 903 * Initialize a newly created cache partition, belonging to the given |
| 800 * [context]. The partition will maintain at most [maxCacheSize] AST | 904 * [context]. The partition will maintain at most [maxCacheSize] AST |
| 801 * structures in the cache. | 905 * structures in the cache. |
| 802 */ | 906 */ |
| 803 SdkCachePartition(InternalAnalysisContext context, int maxCacheSize) | 907 SdkCachePartition(InternalAnalysisContext context, int maxCacheSize) |
| 804 : super(context, maxCacheSize, DefaultRetentionPolicy.POLICY); | 908 : super(context, maxCacheSize, DefaultRetentionPolicy.POLICY); |
| 805 | 909 |
| 806 @override | 910 @override |
| 807 bool contains(AnalysisTarget target) { | 911 bool contains(AnalysisTarget target) { |
| 808 Source source = target.source; | 912 Source source = target.source; |
| 809 return source != null && source.isInSystemLibrary; | 913 return source != null && source.isInSystemLibrary; |
| 810 } | 914 } |
| 811 } | 915 } |
| 812 | 916 |
| 813 /** | 917 /** |
| 918 * A specification of a specific result computed for a specific target. | |
| 919 */ | |
| 920 class TargetedResult { | |
| 921 /** | |
| 922 * An empty list of results. | |
| 923 */ | |
| 924 static final List<TargetedResult> EMPTY_LIST = const <TargetedResult>[]; | |
| 925 | |
| 926 /** | |
| 927 * The target with which the result is associated. | |
| 928 */ | |
| 929 final AnalysisTarget target; | |
| 930 | |
| 931 /** | |
| 932 * The result associated with the target. | |
| 933 */ | |
| 934 final ResultDescriptor result; | |
| 935 | |
| 936 /** | |
| 937 * Initialize a new targeted result. | |
| 938 */ | |
| 939 TargetedResult(this.target, this.result); | |
| 940 | |
| 941 @override | |
| 942 int get hashCode { | |
| 943 return JenkinsSmiHash.combine(target.hashCode, result.hashCode); | |
| 944 } | |
| 945 | |
| 946 @override | |
| 947 bool operator ==(other) { | |
| 948 return other is TargetedResult && | |
| 949 other.target == target && | |
| 950 other.result == result; | |
| 951 } | |
| 952 | |
| 953 @override | |
| 954 String toString() => '$result for $target'; | |
| 955 } | |
| 956 | |
| 957 /** | |
| 814 * A cache partition that contains all targets not contained in other partitions . | 958 * A cache partition that contains all targets not contained in other partitions . |
| 815 */ | 959 */ |
| 816 class UniversalCachePartition extends CachePartition { | 960 class UniversalCachePartition extends CachePartition { |
| 817 /** | 961 /** |
| 818 * Initialize a newly created cache partition, belonging to the given | 962 * Initialize a newly created cache partition, belonging to the given |
| 819 * [context]. The partition will maintain at most [maxCacheSize] AST | 963 * [context]. The partition will maintain at most [maxCacheSize] AST |
| 820 * structures in the cache, using the [retentionPolicy] to determine which | 964 * structures in the cache, using the [retentionPolicy] to determine which |
| 821 * AST structures to flush. | 965 * AST structures to flush. |
| 822 */ | 966 */ |
| 823 UniversalCachePartition(InternalAnalysisContext context, int maxCacheSize, | 967 UniversalCachePartition(InternalAnalysisContext context, int maxCacheSize, |
| 824 CacheRetentionPolicy retentionPolicy) | 968 CacheRetentionPolicy retentionPolicy) |
| 825 : super(context, maxCacheSize, retentionPolicy); | 969 : super(context, maxCacheSize, retentionPolicy); |
| 826 | 970 |
| 827 @override | 971 @override |
| 828 bool contains(AnalysisTarget target) => true; | 972 bool contains(AnalysisTarget target) => true; |
| 829 } | 973 } |
| OLD | NEW |