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

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

Issue 1121963002: Record dependencies and invalidate results. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 7 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 | Annotate | Revision Log
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: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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/context/context.dart » ('j') | pkg/analyzer/test/src/context/abstract_context_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698