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

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: Merge and fixes for review comments. 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
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/context/context.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
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
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/context/context.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698