| 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); |
| 381 data.state = CacheState.ERROR; | 406 TargetedResult thisResult = new TargetedResult(_target, descriptor); |
| 382 data.value = descriptor.defaultValue; | 407 data.invalidate(_cache, thisResult, CacheState.ERROR); |
| 383 } | 408 } |
| 384 } | 409 } |
| 385 | 410 |
| 386 /** | 411 /** |
| 387 * Set the state of the result represented by the given [descriptor] to the | 412 * Set the state of the result represented by the given [descriptor] to the |
| 388 * given [state]. | 413 * given [state]. |
| 389 */ | 414 */ |
| 390 void setState(ResultDescriptor descriptor, CacheState state) { | 415 void setState(ResultDescriptor descriptor, CacheState state) { |
| 391 if (state == CacheState.ERROR) { | 416 if (state == CacheState.ERROR) { |
| 392 throw new ArgumentError('use setErrorState() to set the state to ERROR'); | 417 throw new ArgumentError('use setErrorState() to set the state to ERROR'); |
| 393 } | 418 } |
| 394 if (state == CacheState.VALID) { | 419 if (state == CacheState.VALID) { |
| 395 throw new ArgumentError('use setValue() to set the state to VALID'); | 420 throw new ArgumentError('use setValue() to set the state to VALID'); |
| 396 } | 421 } |
| 397 _validateStateChange(descriptor, state); | 422 _validateStateChange(descriptor, state); |
| 398 if (state == CacheState.INVALID) { | 423 if (state == CacheState.INVALID) { |
| 399 _resultMap.remove(descriptor); | 424 ResultData data = _resultMap[descriptor]; |
| 425 if (data != null) { |
| 426 TargetedResult thisResult = new TargetedResult(_target, descriptor); |
| 427 data.invalidate(_cache, thisResult, CacheState.INVALID); |
| 428 } |
| 400 } else { | 429 } else { |
| 401 ResultData data = _getResultData(descriptor); | 430 ResultData data = _getResultData(descriptor); |
| 402 data.state = state; | 431 data.state = state; |
| 403 if (state != CacheState.IN_PROCESS) { | 432 if (state != CacheState.IN_PROCESS) { |
| 404 // | 433 // |
| 405 // If the state is in-process, we can leave the current value in the | 434 // If the state is in-process, we can leave the current value in the |
| 406 // cache for any 'get' methods to access. | 435 // cache for any 'get' methods to access. |
| 407 // | 436 // |
| 408 data.value = descriptor.defaultValue; | 437 data.value = descriptor.defaultValue; |
| 409 } | 438 } |
| 410 } | 439 } |
| 411 } | 440 } |
| 412 | 441 |
| 413 /** | 442 /** |
| 414 * Set the value of the result represented by the given [descriptor] to the | 443 * Set the value of the result represented by the given [descriptor] to the |
| 415 * given [value]. | 444 * given [value]. |
| 416 */ | 445 */ |
| 417 /*<V>*/ void setValue(ResultDescriptor /*<V>*/ descriptor, dynamic /*V*/ | 446 /*<V>*/ void setValue(ResultDescriptor /*<V>*/ descriptor, dynamic /*V*/ |
| 418 value) { | 447 value, List<TargetedResult> dependedOn) { |
| 419 _validateStateChange(descriptor, CacheState.VALID); | 448 _validateStateChange(descriptor, CacheState.VALID); |
| 420 ResultData data = _getResultData(descriptor); | 449 ResultData data = _getResultData(descriptor); |
| 450 { |
| 451 TargetedResult thisResult = new TargetedResult(_target, descriptor); |
| 452 data.invalidate(_cache, thisResult, CacheState.INVALID); |
| 453 data.setDependedOnResults(_cache, thisResult, dependedOn); |
| 454 } |
| 421 data.state = CacheState.VALID; | 455 data.state = CacheState.VALID; |
| 422 data.value = value == null ? descriptor.defaultValue : value; | 456 data.value = value == null ? descriptor.defaultValue : value; |
| 423 } | 457 } |
| 424 | 458 |
| 425 @override | 459 @override |
| 426 String toString() { | 460 String toString() { |
| 427 StringBuffer buffer = new StringBuffer(); | 461 StringBuffer buffer = new StringBuffer(); |
| 428 _writeOn(buffer); | 462 _writeOn(buffer); |
| 429 return buffer.toString(); | 463 return buffer.toString(); |
| 430 } | 464 } |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 764 } | 798 } |
| 765 } | 799 } |
| 766 | 800 |
| 767 /** | 801 /** |
| 768 * The data about a single analysis result that is stored in a [CacheEntry]. | 802 * The data about a single analysis result that is stored in a [CacheEntry]. |
| 769 */ | 803 */ |
| 770 // TODO(brianwilkerson) Consider making this a generic class so that the value | 804 // TODO(brianwilkerson) Consider making this a generic class so that the value |
| 771 // can be typed. | 805 // can be typed. |
| 772 class ResultData { | 806 class ResultData { |
| 773 /** | 807 /** |
| 808 * The [ResultDescriptor] this result is for. |
| 809 */ |
| 810 final ResultDescriptor descriptor; |
| 811 |
| 812 /** |
| 774 * The state of the cached value. | 813 * The state of the cached value. |
| 775 */ | 814 */ |
| 776 CacheState state; | 815 CacheState state; |
| 777 | 816 |
| 778 /** | 817 /** |
| 779 * The value being cached, or the default value for the result if there is no | 818 * 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]). | 819 * value (for example, when the [state] is [CacheState.INVALID]). |
| 781 */ | 820 */ |
| 782 Object value; | 821 Object value; |
| 783 | 822 |
| 784 /** | 823 /** |
| 824 * A list of the results on which this result depends. |
| 825 */ |
| 826 List<TargetedResult> dependedOnResults = <TargetedResult>[]; |
| 827 |
| 828 /** |
| 829 * A list of the results that depend on this result. |
| 830 */ |
| 831 List<TargetedResult> dependentResults = <TargetedResult>[]; |
| 832 |
| 833 /** |
| 785 * Initialize a newly created result holder to represent the value of data | 834 * Initialize a newly created result holder to represent the value of data |
| 786 * described by the given [descriptor]. | 835 * described by the given [descriptor]. |
| 787 */ | 836 */ |
| 788 ResultData(ResultDescriptor descriptor) { | 837 ResultData(this.descriptor) { |
| 789 state = CacheState.INVALID; | 838 state = CacheState.INVALID; |
| 790 value = descriptor.defaultValue; | 839 value = descriptor.defaultValue; |
| 791 } | 840 } |
| 841 |
| 842 /** |
| 843 * Add the given [result] to the list of dependent results. |
| 844 */ |
| 845 void addDependentResult(TargetedResult result) { |
| 846 dependentResults.add(result); |
| 847 } |
| 848 |
| 849 /** |
| 850 * Invalidate this [ResultData] that corresponds to [thisResult] and |
| 851 * propagate invalidation to the results that depend on this one. |
| 852 */ |
| 853 void invalidate( |
| 854 AnalysisCache cache, TargetedResult thisResult, CacheState newState) { |
| 855 // Invalidate this result. |
| 856 state = newState; |
| 857 value = descriptor.defaultValue; |
| 858 // Stop depending on other results. |
| 859 List<TargetedResult> dependedOnResults = this.dependedOnResults; |
| 860 this.dependedOnResults = <TargetedResult>[]; |
| 861 dependedOnResults.forEach((TargetedResult dependedOnResult) { |
| 862 ResultData data = cache._getDataFor(dependedOnResult); |
| 863 data.removeDependentResult(thisResult); |
| 864 }); |
| 865 // Invalidate results that depend on this result. |
| 866 List<TargetedResult> dependentResults = this.dependentResults; |
| 867 this.dependentResults = <TargetedResult>[]; |
| 868 dependentResults.forEach((TargetedResult dependentResult) { |
| 869 ResultData data = cache._getDataFor(dependentResult); |
| 870 data.invalidate(cache, dependentResult, newState); |
| 871 }); |
| 872 } |
| 873 |
| 874 /** |
| 875 * Remove the given [result] from the list of dependent results. |
| 876 */ |
| 877 void removeDependentResult(TargetedResult result) { |
| 878 dependentResults.remove(result); |
| 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 |