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:async'; | 7 import 'dart:async'; |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
9 | 9 |
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/java_engine.dart'; | 12 import 'package:analyzer/src/generated/java_engine.dart'; |
13 import 'package:analyzer/src/generated/source.dart'; | 13 import 'package:analyzer/src/generated/source.dart'; |
14 import 'package:analyzer/src/generated/utilities_collection.dart'; | 14 import 'package:analyzer/src/generated/utilities_collection.dart'; |
15 import 'package:analyzer/src/generated/utilities_general.dart'; | |
16 import 'package:analyzer/src/task/model.dart'; | 15 import 'package:analyzer/src/task/model.dart'; |
17 import 'package:analyzer/task/model.dart'; | 16 import 'package:analyzer/task/model.dart'; |
18 | 17 |
19 /** | 18 /** |
20 * Return `true` if the given [target] is a priority one. | 19 * Return `true` if the given [target] is a priority one. |
21 */ | 20 */ |
22 typedef bool IsPriorityAnalysisTarget(AnalysisTarget target); | 21 typedef bool IsPriorityAnalysisTarget(AnalysisTarget target); |
23 | 22 |
24 /** | 23 /** |
25 * An LRU cache of results produced by analysis. | 24 * An LRU cache of results produced by analysis. |
26 */ | 25 */ |
27 class AnalysisCache { | 26 class AnalysisCache { |
28 /** | 27 /** |
29 * A flag used to control whether trace information should be produced when | 28 * A flag used to control whether trace information should be produced when |
30 * the content of the cache is modified. | 29 * the content of the cache is modified. |
31 */ | 30 */ |
32 static bool _TRACE_CHANGES = false; | 31 static bool _TRACE_CHANGES = false; |
33 | 32 |
34 /** | 33 /** |
35 * An array containing the partitions of which this cache is comprised. | 34 * An array containing the partitions of which this cache is comprised. |
36 */ | 35 */ |
37 final List<CachePartition> _partitions; | 36 final List<CachePartition> _partitions; |
38 | 37 |
39 /** | 38 /** |
40 * The [StreamController] reporting [InvalidatedResult]s. | 39 * The [StreamController] reporting [InvalidatedResult]s. |
41 */ | 40 */ |
42 final StreamController<InvalidatedResult> _onResultInvalidated = | 41 final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated = |
43 new StreamController<InvalidatedResult>.broadcast(sync: true); | 42 new ReentrantSynchronousStream<InvalidatedResult>(); |
44 | 43 |
45 /** | 44 /** |
46 * Initialize a newly created cache to have the given [partitions]. The | 45 * Initialize a newly created cache to have the given [partitions]. The |
47 * partitions will be searched in the order in which they appear in the array, | 46 * partitions will be searched in the order in which they appear in the array, |
48 * so the most specific partition (usually an [SdkCachePartition]) should be | 47 * so the most specific partition (usually an [SdkCachePartition]) should be |
49 * first and the most general (usually a [UniversalCachePartition]) last. | 48 * first and the most general (usually a [UniversalCachePartition]) last. |
50 */ | 49 */ |
51 AnalysisCache(this._partitions) { | 50 AnalysisCache(this._partitions) { |
52 for (CachePartition partition in _partitions) { | 51 for (CachePartition partition in _partitions) { |
53 partition.onResultInvalidated.listen((InvalidatedResult event) { | 52 partition.onResultInvalidated.listen((InvalidatedResult event) { |
54 _onResultInvalidated.add(event); | 53 onResultInvalidated.add(event); |
55 }); | 54 }); |
56 } | 55 } |
57 } | 56 } |
58 | 57 |
59 /** | |
60 * Return the stream that is notified when a value is invalidated. | |
61 */ | |
62 Stream<InvalidatedResult> get onResultInvalidated => | |
63 _onResultInvalidated.stream; | |
64 | |
65 // TODO(brianwilkerson) Implement or delete this. | 58 // TODO(brianwilkerson) Implement or delete this. |
66 // /** | 59 // /** |
67 // * Return information about each of the partitions in this cache. | 60 // * Return information about each of the partitions in this cache. |
68 // */ | 61 // */ |
69 // List<AnalysisContextStatistics_PartitionData> get partitionData { | 62 // List<AnalysisContextStatistics_PartitionData> get partitionData { |
70 // int count = _partitions.length; | 63 // int count = _partitions.length; |
71 // List<AnalysisContextStatistics_PartitionData> data = | 64 // List<AnalysisContextStatistics_PartitionData> data = |
72 // new List<AnalysisContextStatistics_PartitionData>(count); | 65 // new List<AnalysisContextStatistics_PartitionData>(count); |
73 // for (int i = 0; i < count; i++) { | 66 // for (int i = 0; i < count; i++) { |
74 // CachePartition partition = _partitions[i]; | 67 // CachePartition partition = _partitions[i]; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 Object getValue(AnalysisTarget target, ResultDescriptor result) { | 159 Object getValue(AnalysisTarget target, ResultDescriptor result) { |
167 CacheEntry entry = get(target); | 160 CacheEntry entry = get(target); |
168 if (entry == null) { | 161 if (entry == null) { |
169 return result.defaultValue; | 162 return result.defaultValue; |
170 } | 163 } |
171 return entry.getValue(result); | 164 return entry.getValue(result); |
172 } | 165 } |
173 | 166 |
174 /** | 167 /** |
175 * Return an iterator returning all of the map entries mapping targets to | 168 * Return an iterator returning all of the map entries mapping targets to |
176 * cache entries. | 169 * cache entries. If the [context] is not `null`, then only entries that are |
| 170 * owned by the given context will be returned. |
177 */ | 171 */ |
178 MapIterator<AnalysisTarget, CacheEntry> iterator() { | 172 MapIterator<AnalysisTarget, CacheEntry> iterator( |
179 int count = _partitions.length; | 173 {InternalAnalysisContext context: null}) { |
180 List<Map<AnalysisTarget, CacheEntry>> maps = | 174 List<Map<AnalysisTarget, CacheEntry>> maps = |
181 new List<Map<AnalysisTarget, CacheEntry>>(count); | 175 <Map<AnalysisTarget, CacheEntry>>[]; |
182 for (int i = 0; i < count; i++) { | 176 for (CachePartition partition in _partitions) { |
183 maps[i] = _partitions[i].map; | 177 if (context == null || partition.context == context) { |
| 178 maps.add(partition.map); |
| 179 } |
184 } | 180 } |
185 return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps); | 181 return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps); |
186 } | 182 } |
187 | 183 |
188 /** | 184 /** |
189 * Puts the given [entry] into the cache. | 185 * Puts the given [entry] into the cache. |
190 */ | 186 */ |
191 void put(CacheEntry entry) { | 187 void put(CacheEntry entry) { |
192 AnalysisTarget target = entry.target; | 188 AnalysisTarget target = entry.target; |
193 entry.fixExceptionState(); | 189 entry.fixExceptionState(); |
(...skipping 15 matching lines...) Expand all Loading... |
209 partition.put(entry); | 205 partition.put(entry); |
210 return; | 206 return; |
211 } | 207 } |
212 } | 208 } |
213 // TODO(brianwilkerson) Handle the case where no partition was found, | 209 // TODO(brianwilkerson) Handle the case where no partition was found, |
214 // possibly by throwing an exception. | 210 // possibly by throwing an exception. |
215 } | 211 } |
216 | 212 |
217 /** | 213 /** |
218 * Remove all information related to the given [target] from this cache. | 214 * Remove all information related to the given [target] from this cache. |
| 215 * Return the entry associated with the target, or `null` if there was cache |
| 216 * entry for the target. |
219 */ | 217 */ |
220 void remove(AnalysisTarget target) { | 218 CacheEntry remove(AnalysisTarget target) { |
221 int count = _partitions.length; | 219 int count = _partitions.length; |
222 for (int i = 0; i < count; i++) { | 220 for (int i = 0; i < count; i++) { |
223 CachePartition partition = _partitions[i]; | 221 CachePartition partition = _partitions[i]; |
224 if (partition.isResponsibleFor(target)) { | 222 if (partition.isResponsibleFor(target)) { |
225 if (_TRACE_CHANGES) { | 223 if (_TRACE_CHANGES) { |
226 AnalysisEngine.instance.logger | 224 AnalysisEngine.instance.logger |
227 .logInformation('Removed the cache entry for $target.'); | 225 .logInformation('Removed the cache entry for $target.'); |
228 } | 226 } |
229 partition.remove(target); | 227 return partition.remove(target); |
230 return; | |
231 } | 228 } |
232 } | 229 } |
| 230 return null; |
233 } | 231 } |
234 | 232 |
235 /** | 233 /** |
236 * Return the number of targets that are mapped to cache entries. | 234 * Return the number of targets that are mapped to cache entries. |
237 */ | 235 */ |
238 int size() { | 236 int size() { |
239 int size = 0; | 237 int size = 0; |
240 int count = _partitions.length; | 238 int count = _partitions.length; |
241 for (int i = 0; i < count; i++) { | 239 for (int i = 0; i < count; i++) { |
242 size += _partitions[i].size(); | 240 size += _partitions[i].size(); |
243 } | 241 } |
244 return size; | 242 return size; |
245 } | 243 } |
246 } | 244 } |
247 | 245 |
248 /** | 246 /** |
249 * The information cached by an analysis context about an individual target. | 247 * The information cached by an analysis context about an individual target. |
250 */ | 248 */ |
251 class CacheEntry { | 249 class CacheEntry { |
252 /** | 250 /** |
253 * The index of the flag indicating whether the source was explicitly added to | 251 * The index of the flag indicating whether the source was explicitly added to |
254 * the context or whether the source was implicitly added because it was | 252 * the context or whether the source was implicitly added because it was |
255 * referenced by another source. | 253 * referenced by another source. |
256 */ | 254 */ |
257 static int _EXPLICITLY_ADDED_FLAG = 0; | 255 static int _EXPLICITLY_ADDED_FLAG = 0; |
258 | 256 |
259 /** | 257 /** |
| 258 * The next invalidation process identifier. |
| 259 */ |
| 260 static int nextInvalidateId = 0; |
| 261 |
| 262 /** |
260 * The target this entry is about. | 263 * The target this entry is about. |
261 */ | 264 */ |
262 final AnalysisTarget target; | 265 final AnalysisTarget target; |
263 | 266 |
264 /** | 267 /** |
265 * The partition that is responsible for this entry. | 268 * The partition that is responsible for this entry. |
266 */ | 269 */ |
267 CachePartition _partition; | 270 CachePartition _partition; |
268 | 271 |
269 /** | 272 /** |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 if (state == CacheState.ERROR) { | 441 if (state == CacheState.ERROR) { |
439 throw new ArgumentError('use setErrorState() to set the state to ERROR'); | 442 throw new ArgumentError('use setErrorState() to set the state to ERROR'); |
440 } | 443 } |
441 if (state == CacheState.VALID) { | 444 if (state == CacheState.VALID) { |
442 throw new ArgumentError('use setValue() to set the state to VALID'); | 445 throw new ArgumentError('use setValue() to set the state to VALID'); |
443 } | 446 } |
444 _validateStateChange(descriptor, state); | 447 _validateStateChange(descriptor, state); |
445 if (state == CacheState.INVALID) { | 448 if (state == CacheState.INVALID) { |
446 ResultData data = _resultMap[descriptor]; | 449 ResultData data = _resultMap[descriptor]; |
447 if (data != null) { | 450 if (data != null) { |
448 _invalidate(descriptor, delta); | 451 _invalidate(nextInvalidateId++, descriptor, delta, 0); |
449 } | 452 } |
450 } else { | 453 } else { |
451 ResultData data = getResultData(descriptor); | 454 ResultData data = getResultData(descriptor); |
452 data.state = state; | 455 data.state = state; |
453 if (state != CacheState.IN_PROCESS) { | 456 if (state != CacheState.IN_PROCESS) { |
454 // | 457 // |
455 // If the state is in-process, we can leave the current value in the | 458 // If the state is in-process, we can leave the current value in the |
456 // cache for any 'get' methods to access. | 459 // cache for any 'get' methods to access. |
457 // | 460 // |
458 data.value = descriptor.defaultValue; | 461 data.value = descriptor.defaultValue; |
459 } | 462 } |
460 } | 463 } |
461 } | 464 } |
462 | 465 |
463 /** | 466 /** |
464 * Set the value of the result represented by the given [descriptor] to the | 467 * Set the value of the result represented by the given [descriptor] to the |
465 * given [value]. | 468 * given [value]. |
466 */ | 469 */ |
467 /*<V>*/ void setValue(ResultDescriptor /*<V>*/ descriptor, dynamic /*V*/ | 470 /*<V>*/ void setValue( |
468 value, List<TargetedResult> dependedOn) { | 471 ResultDescriptor /*<V>*/ descriptor, |
| 472 dynamic /*V*/ |
| 473 value, |
| 474 List<TargetedResult> dependedOn) { |
469 // { | 475 // { |
470 // String valueStr = '$value'; | 476 // String valueStr = '$value'; |
471 // if (valueStr.length > 20) { | 477 // if (valueStr.length > 20) { |
472 // valueStr = valueStr.substring(0, 20) + '...'; | 478 // valueStr = valueStr.substring(0, 20) + '...'; |
473 // } | 479 // } |
474 // valueStr = valueStr.replaceAll('\n', '\\n'); | 480 // valueStr = valueStr.replaceAll('\n', '\\n'); |
475 // print( | 481 // print( |
476 // 'setValue $descriptor for $target value=$valueStr deps=$dependedOn')
; | 482 // 'setValue $descriptor for $target value=$valueStr deps=$dependedOn')
; |
477 // } | 483 // } |
478 _validateStateChange(descriptor, CacheState.VALID); | 484 _validateStateChange(descriptor, CacheState.VALID); |
479 TargetedResult thisResult = new TargetedResult(target, descriptor); | 485 TargetedResult thisResult = new TargetedResult(target, descriptor); |
480 if (_partition != null) { | 486 if (_partition != null) { |
481 _partition.resultStored(thisResult, value); | 487 _partition.resultStored(thisResult, value); |
482 } | 488 } |
483 ResultData data = getResultData(descriptor); | 489 ResultData data = getResultData(descriptor); |
484 _setDependedOnResults(data, thisResult, dependedOn); | 490 _setDependedOnResults(data, thisResult, dependedOn); |
485 data.state = CacheState.VALID; | 491 data.state = CacheState.VALID; |
486 data.value = value == null ? descriptor.defaultValue : value; | 492 data.value = value == null ? descriptor.defaultValue : value; |
487 } | 493 } |
488 | 494 |
489 /** | 495 /** |
490 * Set the value of the result represented by the given [descriptor] to the | 496 * Set the value of the result represented by the given [descriptor] to the |
491 * given [value], keep its dependency, invalidate all the dependent result. | 497 * given [value], keep its dependency, invalidate all the dependent result. |
492 */ | 498 */ |
493 void setValueIncremental(ResultDescriptor descriptor, dynamic value) { | 499 void setValueIncremental( |
| 500 ResultDescriptor descriptor, dynamic value, bool invalidateDependent) { |
494 ResultData data = getResultData(descriptor); | 501 ResultData data = getResultData(descriptor); |
495 List<TargetedResult> dependedOn = data.dependedOnResults; | 502 data.state = CacheState.VALID; |
496 _invalidate(descriptor, null); | 503 data.value = value; |
497 setValue(descriptor, value, dependedOn); | 504 if (invalidateDependent) { |
| 505 _invalidateDependentResults(nextInvalidateId++, data, null, 0); |
| 506 } |
498 } | 507 } |
499 | 508 |
500 @override | 509 @override |
501 String toString() { | 510 String toString() { |
502 StringBuffer buffer = new StringBuffer(); | 511 StringBuffer buffer = new StringBuffer(); |
503 _writeOn(buffer); | 512 _writeOn(buffer); |
504 return buffer.toString(); | 513 return buffer.toString(); |
505 } | 514 } |
506 | 515 |
507 /** | 516 /** |
508 * Return the value of the flag with the given [index]. | 517 * Return the value of the flag with the given [index]. |
509 */ | 518 */ |
510 bool _getFlag(int index) => BooleanArray.get(_flags, index); | 519 bool _getFlag(int index) => BooleanArray.get(_flags, index); |
511 | 520 |
512 /** | 521 /** |
513 * Invalidate the result represented by the given [descriptor] and propagate | 522 * Invalidate the result represented by the given [descriptor] and propagate |
514 * invalidation to other results that depend on it. | 523 * invalidation to other results that depend on it. |
515 */ | 524 */ |
516 void _invalidate(ResultDescriptor descriptor, Delta delta) { | 525 void _invalidate( |
| 526 int id, ResultDescriptor descriptor, Delta delta, int level) { |
| 527 ResultData thisData = _resultMap[descriptor]; |
| 528 if (thisData == null) { |
| 529 return; |
| 530 } |
| 531 // Stop if already validated. |
| 532 if (delta != null) { |
| 533 if (thisData.invalidateId == id) { |
| 534 return; |
| 535 } |
| 536 thisData.invalidateId = id; |
| 537 } |
| 538 // Ask the delta to validate. |
517 DeltaResult deltaResult = null; | 539 DeltaResult deltaResult = null; |
518 if (delta != null) { | 540 if (delta != null) { |
519 deltaResult = delta.validate(_partition.context, target, descriptor); | 541 deltaResult = delta.validate(_partition.context, target, descriptor); |
520 if (deltaResult == DeltaResult.STOP) { | 542 if (deltaResult == DeltaResult.STOP) { |
521 // print('not-invalidate $descriptor for $target'); | |
522 return; | 543 return; |
523 } | 544 } |
524 } | 545 } |
525 // print('invalidate $descriptor for $target'); | 546 if (deltaResult == DeltaResult.INVALIDATE_NO_DELTA) { |
526 ResultData thisData; | 547 delta = null; |
527 if (deltaResult == null || deltaResult == DeltaResult.INVALIDATE) { | |
528 thisData = _resultMap.remove(descriptor); | |
529 } | 548 } |
530 if (deltaResult == DeltaResult.KEEP_CONTINUE) { | 549 if (deltaResult == null || |
531 thisData = _resultMap[descriptor]; | 550 deltaResult == DeltaResult.INVALIDATE || |
532 } | 551 deltaResult == DeltaResult.INVALIDATE_NO_DELTA) { |
533 if (thisData == null) { | 552 _resultMap.remove(descriptor); |
534 return; | 553 // { |
| 554 // String indent = ' ' * level; |
| 555 // print('[$id]$indent invalidate $descriptor for $target'); |
| 556 // } |
535 } | 557 } |
536 // Stop depending on other results. | 558 // Stop depending on other results. |
537 TargetedResult thisResult = new TargetedResult(target, descriptor); | 559 TargetedResult thisResult = new TargetedResult(target, descriptor); |
538 for (TargetedResult dependedOnResult in thisData.dependedOnResults) { | 560 for (TargetedResult dependedOnResult in thisData.dependedOnResults) { |
539 ResultData data = _partition._getDataFor(dependedOnResult); | 561 ResultData data = _partition._getDataFor(dependedOnResult); |
540 if (data != null) { | 562 if (data != null && deltaResult != DeltaResult.KEEP_CONTINUE) { |
541 data.dependentResults.remove(thisResult); | 563 data.dependentResults.remove(thisResult); |
542 } | 564 } |
543 } | 565 } |
544 // Invalidate results that depend on this result. | 566 // Invalidate results that depend on this result. |
545 List<TargetedResult> dependentResults = thisData.dependentResults.toList(); | 567 _invalidateDependentResults(id, thisData, delta, level + 1); |
546 for (TargetedResult dependentResult in dependentResults) { | |
547 CacheEntry entry = _partition.get(dependentResult.target); | |
548 if (entry != null) { | |
549 entry._invalidate(dependentResult.result, delta); | |
550 } | |
551 } | |
552 // If empty, remove the entry altogether. | 568 // If empty, remove the entry altogether. |
553 if (_resultMap.isEmpty) { | 569 if (_resultMap.isEmpty) { |
554 _partition._targetMap.remove(target); | 570 _partition._targetMap.remove(target); |
555 _partition._removeIfSource(target); | 571 _partition._removeIfSource(target); |
556 } | 572 } |
557 // Notify controller. | 573 // Notify controller. |
558 _partition._onResultInvalidated | 574 _partition.onResultInvalidated |
559 .add(new InvalidatedResult(this, descriptor)); | 575 .add(new InvalidatedResult(this, descriptor, thisData.value)); |
560 } | 576 } |
561 | 577 |
562 /** | 578 /** |
563 * Invalidates all the results of this entry, with propagation. | 579 * Invalidates all the results of this entry, with propagation. |
564 */ | 580 */ |
565 void _invalidateAll() { | 581 void _invalidateAll() { |
566 List<ResultDescriptor> results = _resultMap.keys.toList(); | 582 List<ResultDescriptor> results = _resultMap.keys.toList(); |
567 for (ResultDescriptor result in results) { | 583 for (ResultDescriptor result in results) { |
568 _invalidate(result, null); | 584 _invalidate(nextInvalidateId++, result, null, 0); |
569 } | 585 } |
570 } | 586 } |
571 | 587 |
| 588 /** |
| 589 * Invalidate results that depend on [thisData]. |
| 590 */ |
| 591 void _invalidateDependentResults( |
| 592 int id, ResultData thisData, Delta delta, int level) { |
| 593 List<TargetedResult> dependentResults = thisData.dependentResults.toList(); |
| 594 for (TargetedResult dependentResult in dependentResults) { |
| 595 CacheEntry entry = _partition.get(dependentResult.target); |
| 596 if (entry != null) { |
| 597 entry._invalidate(id, dependentResult.result, delta, level); |
| 598 } |
| 599 } |
| 600 } |
| 601 |
572 /** | 602 /** |
573 * Set the [dependedOn] on which this result depends. | 603 * Set the [dependedOn] on which this result depends. |
574 */ | 604 */ |
575 void _setDependedOnResults(ResultData thisData, TargetedResult thisResult, | 605 void _setDependedOnResults(ResultData thisData, TargetedResult thisResult, |
576 List<TargetedResult> dependedOn) { | 606 List<TargetedResult> dependedOn) { |
577 thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) { | 607 thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) { |
578 ResultData data = _partition._getDataFor(dependedOnResult); | 608 ResultData data = _partition._getDataFor(dependedOnResult); |
579 if (data != null) { | 609 if (data != null) { |
580 data.dependentResults.remove(thisResult); | 610 data.dependentResults.remove(thisResult); |
581 } | 611 } |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
796 | 826 |
797 /** | 827 /** |
798 * A table mapping caching policies to the cache flush managers. | 828 * A table mapping caching policies to the cache flush managers. |
799 */ | 829 */ |
800 final HashMap<ResultCachingPolicy, CacheFlushManager> _flushManagerMap = | 830 final HashMap<ResultCachingPolicy, CacheFlushManager> _flushManagerMap = |
801 new HashMap<ResultCachingPolicy, CacheFlushManager>(); | 831 new HashMap<ResultCachingPolicy, CacheFlushManager>(); |
802 | 832 |
803 /** | 833 /** |
804 * The [StreamController] reporting [InvalidatedResult]s. | 834 * The [StreamController] reporting [InvalidatedResult]s. |
805 */ | 835 */ |
806 final StreamController<InvalidatedResult> _onResultInvalidated = | 836 final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated = |
807 new StreamController<InvalidatedResult>.broadcast(sync: true); | 837 new ReentrantSynchronousStream<InvalidatedResult>(); |
808 | 838 |
809 /** | 839 /** |
810 * A table mapping the targets belonging to this partition to the information | 840 * A table mapping the targets belonging to this partition to the information |
811 * known about those targets. | 841 * known about those targets. |
812 */ | 842 */ |
813 HashMap<AnalysisTarget, CacheEntry> _targetMap = | 843 HashMap<AnalysisTarget, CacheEntry> _targetMap = |
814 new HashMap<AnalysisTarget, CacheEntry>(); | 844 new HashMap<AnalysisTarget, CacheEntry>(); |
815 | 845 |
816 /** | 846 /** |
817 * A set of the [Source] targets. | 847 * A set of the [Source] targets. |
(...skipping 14 matching lines...) Expand all Loading... |
832 /** | 862 /** |
833 * Return a table mapping the targets known to the context to the information | 863 * Return a table mapping the targets known to the context to the information |
834 * known about the target. | 864 * known about the target. |
835 * | 865 * |
836 * <b>Note:</b> This method is only visible for use by [AnalysisCache] and | 866 * <b>Note:</b> This method is only visible for use by [AnalysisCache] and |
837 * should not be used for any other purpose. | 867 * should not be used for any other purpose. |
838 */ | 868 */ |
839 Map<AnalysisTarget, CacheEntry> get map => _targetMap; | 869 Map<AnalysisTarget, CacheEntry> get map => _targetMap; |
840 | 870 |
841 /** | 871 /** |
842 * Return the stream that is notified when a value is invalidated. | |
843 */ | |
844 Stream<InvalidatedResult> get onResultInvalidated => | |
845 _onResultInvalidated.stream; | |
846 | |
847 /** | |
848 * Notifies the partition that the client is going to stop using it. | 872 * Notifies the partition that the client is going to stop using it. |
849 */ | 873 */ |
850 void dispose() { | 874 void dispose() { |
851 for (CacheEntry entry in _targetMap.values) { | 875 for (CacheEntry entry in _targetMap.values) { |
852 entry.dispose(); | 876 entry.dispose(); |
853 } | 877 } |
854 _targetMap.clear(); | 878 _targetMap.clear(); |
855 } | 879 } |
856 | 880 |
857 /** | 881 /** |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
889 throw new StateError( | 913 throw new StateError( |
890 'The entry for $target is already in ${entry._partition}'); | 914 'The entry for $target is already in ${entry._partition}'); |
891 } | 915 } |
892 entry._partition = this; | 916 entry._partition = this; |
893 entry.fixExceptionState(); | 917 entry.fixExceptionState(); |
894 _targetMap[target] = entry; | 918 _targetMap[target] = entry; |
895 _addIfSource(target); | 919 _addIfSource(target); |
896 } | 920 } |
897 | 921 |
898 /** | 922 /** |
899 * Remove all information related to the given [target] from this cache. | 923 * Remove all information related to the given [target] from this partition. |
| 924 * Return the entry associated with the target, or `null` if there was cache |
| 925 * entry for the target. |
900 */ | 926 */ |
901 void remove(AnalysisTarget target) { | 927 CacheEntry remove(AnalysisTarget target) { |
902 for (CacheFlushManager flushManager in _flushManagerMap.values) { | 928 for (CacheFlushManager flushManager in _flushManagerMap.values) { |
903 flushManager.targetRemoved(target); | 929 flushManager.targetRemoved(target); |
904 } | 930 } |
905 CacheEntry entry = _targetMap.remove(target); | 931 CacheEntry entry = _targetMap.remove(target); |
906 if (entry != null) { | 932 if (entry != null) { |
907 entry._invalidateAll(); | 933 entry._invalidateAll(); |
908 } | 934 } |
909 _removeIfSource(target); | 935 _removeIfSource(target); |
| 936 return entry; |
910 } | 937 } |
911 | 938 |
912 /** | 939 /** |
913 * Records that a value of the result described by the given [descriptor] | 940 * Records that a value of the result described by the given [descriptor] |
914 * for the given [target] was just read from the cache. | 941 * for the given [target] was just read from the cache. |
915 */ | 942 */ |
916 void resultAccessed(AnalysisTarget target, ResultDescriptor descriptor) { | 943 void resultAccessed(AnalysisTarget target, ResultDescriptor descriptor) { |
917 CacheFlushManager flushManager = _getFlushManager(descriptor); | 944 CacheFlushManager flushManager = _getFlushManager(descriptor); |
918 TargetedResult result = new TargetedResult(target, descriptor); | 945 TargetedResult result = new TargetedResult(target, descriptor); |
919 flushManager.resultAccessed(result); | 946 flushManager.resultAccessed(result); |
(...skipping 21 matching lines...) Expand all Loading... |
941 * Return the number of targets that are mapped to cache entries. | 968 * Return the number of targets that are mapped to cache entries. |
942 */ | 969 */ |
943 int size() => _targetMap.length; | 970 int size() => _targetMap.length; |
944 | 971 |
945 /** | 972 /** |
946 * If the given [target] is a [Source], adds it to [_sources]. | 973 * If the given [target] is a [Source], adds it to [_sources]. |
947 */ | 974 */ |
948 void _addIfSource(AnalysisTarget target) { | 975 void _addIfSource(AnalysisTarget target) { |
949 if (target is Source) { | 976 if (target is Source) { |
950 _sources.add(target); | 977 _sources.add(target); |
951 { | 978 String fullName = target.fullName; |
952 String fullName = target.fullName; | 979 _pathToSources.putIfAbsent(fullName, () => <Source>[]).add(target); |
953 _pathToSources.putIfAbsent(fullName, () => <Source>[]).add(target); | |
954 } | |
955 } | 980 } |
956 } | 981 } |
957 | 982 |
958 ResultData _getDataFor(TargetedResult result) { | 983 ResultData _getDataFor(TargetedResult result) { |
959 CacheEntry entry = context.analysisCache.get(result.target); | 984 CacheEntry entry = context.analysisCache.get(result.target); |
960 return entry != null ? entry._resultMap[result.result] : null; | 985 return entry != null ? entry._resultMap[result.result] : null; |
961 } | 986 } |
962 | 987 |
963 /** | 988 /** |
964 * Return the [CacheFlushManager] for the given [descriptor], not `null`. | 989 * Return the [CacheFlushManager] for the given [descriptor], not `null`. |
965 */ | 990 */ |
966 CacheFlushManager _getFlushManager(ResultDescriptor descriptor) { | 991 CacheFlushManager _getFlushManager(ResultDescriptor descriptor) { |
967 ResultCachingPolicy policy = descriptor.cachingPolicy; | 992 ResultCachingPolicy policy = descriptor.cachingPolicy; |
968 if (identical(policy, DEFAULT_CACHING_POLICY)) { | 993 if (identical(policy, DEFAULT_CACHING_POLICY)) { |
969 return UnlimitedCacheFlushManager.INSTANCE; | 994 return UnlimitedCacheFlushManager.INSTANCE; |
970 } | 995 } |
971 CacheFlushManager manager = _flushManagerMap[policy]; | 996 CacheFlushManager manager = _flushManagerMap[policy]; |
972 if (manager == null) { | 997 if (manager == null) { |
973 manager = new CacheFlushManager(policy, _isPriorityAnalysisTarget); | 998 manager = new CacheFlushManager(policy, _isPriorityAnalysisTarget); |
974 _flushManagerMap[policy] = manager; | 999 _flushManagerMap[policy] = manager; |
975 } | 1000 } |
976 return manager; | 1001 return manager; |
977 } | 1002 } |
978 | 1003 |
979 bool _isPriorityAnalysisTarget(AnalysisTarget target) { | 1004 bool _isPriorityAnalysisTarget(AnalysisTarget target) { |
980 return context.priorityTargets.contains(target); | 1005 return context.priorityTargets.contains(target); |
981 } | 1006 } |
982 | 1007 |
983 /** | 1008 /** |
984 * If the given [target] is a [Source], removes it from [_sources]. | 1009 * If the given [target] is a [Source], remove it from the list of [_sources]. |
985 */ | 1010 */ |
986 void _removeIfSource(AnalysisTarget target) { | 1011 void _removeIfSource(AnalysisTarget target) { |
987 if (target is Source) { | 1012 if (target is Source) { |
988 _sources.remove(target); | 1013 _sources.remove(target); |
989 { | 1014 String fullName = target.fullName; |
990 String fullName = target.fullName; | 1015 List<Source> sources = _pathToSources[fullName]; |
991 List<Source> sources = _pathToSources[fullName]; | 1016 if (sources != null) { |
992 if (sources != null) { | 1017 sources.remove(target); |
993 sources.remove(target); | 1018 if (sources.isEmpty) { |
994 if (sources.isEmpty) { | 1019 _pathToSources.remove(fullName); |
995 _pathToSources.remove(fullName); | |
996 } | |
997 } | 1020 } |
998 } | 1021 } |
999 } | 1022 } |
1000 } | 1023 } |
1001 } | 1024 } |
1002 | 1025 |
1003 /** | 1026 /** |
1004 * The description for a change. | 1027 * The description for a change. |
1005 */ | 1028 */ |
1006 class Delta { | 1029 class Delta { |
1007 final Source source; | 1030 final Source source; |
1008 | 1031 |
1009 Delta(this.source); | 1032 Delta(this.source); |
1010 | 1033 |
1011 /** | 1034 /** |
1012 * Check whether this delta affects the result described by the given | 1035 * Check whether this delta affects the result described by the given |
1013 * [descriptor] and [target]. | 1036 * [descriptor] and [target]. |
1014 */ | 1037 */ |
1015 DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target, | 1038 DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target, |
1016 ResultDescriptor descriptor) { | 1039 ResultDescriptor descriptor) { |
1017 return DeltaResult.INVALIDATE; | 1040 return DeltaResult.INVALIDATE; |
1018 } | 1041 } |
1019 } | 1042 } |
1020 | 1043 |
1021 /** | 1044 /** |
1022 * The possible results of validating analysis results againt a [Delta]. | 1045 * The possible results of validating analysis results againt a [Delta]. |
1023 */ | 1046 */ |
1024 enum DeltaResult { INVALIDATE, KEEP_CONTINUE, STOP } | 1047 enum DeltaResult { |
| 1048 /** |
| 1049 * Invalidate this result and continue visiting dependent results |
| 1050 * with this [Delta]. |
| 1051 */ |
| 1052 INVALIDATE, |
| 1053 |
| 1054 /** |
| 1055 * Invalidate this result and stop using this [Delta], so unconditionally |
| 1056 * invalidate all the dependent results. |
| 1057 */ |
| 1058 INVALIDATE_NO_DELTA, |
| 1059 |
| 1060 /** |
| 1061 * Keep this result and continue validating dependent results |
| 1062 * with this [Delta]. |
| 1063 */ |
| 1064 KEEP_CONTINUE, |
| 1065 |
| 1066 /** |
| 1067 * Keep this result and stop visiting results that depend on this one. |
| 1068 */ |
| 1069 STOP |
| 1070 } |
1025 | 1071 |
1026 /** | 1072 /** |
1027 * [InvalidatedResult] describes an invalidated result. | 1073 * [InvalidatedResult] describes an invalidated result. |
1028 */ | 1074 */ |
1029 class InvalidatedResult { | 1075 class InvalidatedResult { |
1030 /** | 1076 /** |
1031 * The target in which the result was invalidated. | 1077 * The target in which the result was invalidated. |
1032 */ | 1078 */ |
1033 final CacheEntry entry; | 1079 final CacheEntry entry; |
1034 | 1080 |
1035 /** | 1081 /** |
1036 * The descriptor of the result which was invalidated. | 1082 * The descriptor of the result which was invalidated. |
1037 */ | 1083 */ |
1038 final ResultDescriptor descriptor; | 1084 final ResultDescriptor descriptor; |
1039 | 1085 |
1040 InvalidatedResult(this.entry, this.descriptor); | 1086 /** |
| 1087 * The value of the result which was invalidated. |
| 1088 */ |
| 1089 final Object value; |
| 1090 |
| 1091 InvalidatedResult(this.entry, this.descriptor, this.value); |
1041 | 1092 |
1042 @override | 1093 @override |
1043 String toString() => '$descriptor of ${entry.target}'; | 1094 String toString() => '$descriptor of ${entry.target}'; |
1044 } | 1095 } |
1045 | 1096 |
1046 /** | 1097 /** |
| 1098 * A Stream-like interface, which broadcasts events synchronously. |
| 1099 * If a second event is fired while delivering a first event, then the second |
| 1100 * event will be delivered first, and then delivering of the first will be |
| 1101 * continued. |
| 1102 */ |
| 1103 class ReentrantSynchronousStream<T> { |
| 1104 final List<Function> listeners = <Function>[]; |
| 1105 |
| 1106 /** |
| 1107 * Send the given [event] to the stream. |
| 1108 */ |
| 1109 void add(T event) { |
| 1110 List<Function> listeners = this.listeners.toList(); |
| 1111 for (Function listener in listeners) { |
| 1112 listener(event); |
| 1113 } |
| 1114 } |
| 1115 |
| 1116 /** |
| 1117 * Listen for the events in this stream. |
| 1118 * Note that if the [listener] fires a new event, then the [listener] will be |
| 1119 * invoked again before returning from the [add] invocation. |
| 1120 */ |
| 1121 void listen(void listener(T event)) { |
| 1122 listeners.add(listener); |
| 1123 } |
| 1124 } |
| 1125 |
| 1126 /** |
1047 * The data about a single analysis result that is stored in a [CacheEntry]. | 1127 * The data about a single analysis result that is stored in a [CacheEntry]. |
1048 */ | 1128 */ |
1049 // TODO(brianwilkerson) Consider making this a generic class so that the value | 1129 // TODO(brianwilkerson) Consider making this a generic class so that the value |
1050 // can be typed. | 1130 // can be typed. |
1051 class ResultData { | 1131 class ResultData { |
1052 /** | 1132 /** |
1053 * The [ResultDescriptor] this result is for. | 1133 * The [ResultDescriptor] this result is for. |
1054 */ | 1134 */ |
1055 final ResultDescriptor descriptor; | 1135 final ResultDescriptor descriptor; |
1056 | 1136 |
1057 /** | 1137 /** |
1058 * The state of the cached value. | 1138 * The state of the cached value. |
1059 */ | 1139 */ |
1060 CacheState state; | 1140 CacheState state; |
1061 | 1141 |
1062 /** | 1142 /** |
1063 * The value being cached, or the default value for the result if there is no | 1143 * The value being cached, or the default value for the result if there is no |
1064 * value (for example, when the [state] is [CacheState.INVALID]). | 1144 * value (for example, when the [state] is [CacheState.INVALID]). |
1065 */ | 1145 */ |
1066 Object value; | 1146 Object value; |
1067 | 1147 |
1068 /** | 1148 /** |
| 1149 * The identifier of the invalidation process that most recently checked |
| 1150 * this value. If it is the same as the current invalidation identifier, |
| 1151 * then there is no reason to check it (and its subtree again). |
| 1152 */ |
| 1153 int invalidateId = -1; |
| 1154 |
| 1155 /** |
1069 * A list of the results on which this result depends. | 1156 * A list of the results on which this result depends. |
1070 */ | 1157 */ |
1071 List<TargetedResult> dependedOnResults = <TargetedResult>[]; | 1158 List<TargetedResult> dependedOnResults = <TargetedResult>[]; |
1072 | 1159 |
1073 /** | 1160 /** |
1074 * A list of the results that depend on this result. | 1161 * A list of the results that depend on this result. |
1075 */ | 1162 */ |
1076 Set<TargetedResult> dependentResults = new Set<TargetedResult>(); | 1163 Set<TargetedResult> dependentResults = new Set<TargetedResult>(); |
1077 | 1164 |
1078 /** | 1165 /** |
(...skipping 28 matching lines...) Expand all Loading... |
1107 bool isResponsibleFor(AnalysisTarget target) { | 1194 bool isResponsibleFor(AnalysisTarget target) { |
1108 if (target is AnalysisContextTarget) { | 1195 if (target is AnalysisContextTarget) { |
1109 return true; | 1196 return true; |
1110 } | 1197 } |
1111 Source source = target.source; | 1198 Source source = target.source; |
1112 return source != null && source.isInSystemLibrary; | 1199 return source != null && source.isInSystemLibrary; |
1113 } | 1200 } |
1114 } | 1201 } |
1115 | 1202 |
1116 /** | 1203 /** |
1117 * A specification of a specific result computed for a specific target. | |
1118 */ | |
1119 class TargetedResult { | |
1120 /** | |
1121 * An empty list of results. | |
1122 */ | |
1123 static final List<TargetedResult> EMPTY_LIST = const <TargetedResult>[]; | |
1124 | |
1125 /** | |
1126 * The target with which the result is associated. | |
1127 */ | |
1128 final AnalysisTarget target; | |
1129 | |
1130 /** | |
1131 * The result associated with the target. | |
1132 */ | |
1133 final ResultDescriptor result; | |
1134 | |
1135 /** | |
1136 * Initialize a new targeted result. | |
1137 */ | |
1138 TargetedResult(this.target, this.result); | |
1139 | |
1140 @override | |
1141 int get hashCode { | |
1142 return JenkinsSmiHash.combine(target.hashCode, result.hashCode); | |
1143 } | |
1144 | |
1145 @override | |
1146 bool operator ==(other) { | |
1147 return other is TargetedResult && | |
1148 other.target == target && | |
1149 other.result == result; | |
1150 } | |
1151 | |
1152 @override | |
1153 String toString() => '$result for $target'; | |
1154 } | |
1155 | |
1156 /** | |
1157 * A cache partition that contains all targets not contained in other partitions
. | 1204 * A cache partition that contains all targets not contained in other partitions
. |
1158 */ | 1205 */ |
1159 class UniversalCachePartition extends CachePartition { | 1206 class UniversalCachePartition extends CachePartition { |
1160 /** | 1207 /** |
1161 * Initialize a newly created cache partition, belonging to the given | 1208 * Initialize a newly created cache partition, belonging to the given |
1162 * [context]. | 1209 * [context]. |
1163 */ | 1210 */ |
1164 UniversalCachePartition(InternalAnalysisContext context) : super(context); | 1211 UniversalCachePartition(InternalAnalysisContext context) : super(context); |
1165 | 1212 |
1166 @override | 1213 @override |
(...skipping 12 matching lines...) Expand all Loading... |
1179 void resultAccessed(TargetedResult result) {} | 1226 void resultAccessed(TargetedResult result) {} |
1180 | 1227 |
1181 @override | 1228 @override |
1182 List<TargetedResult> resultStored(TargetedResult newResult, newValue) { | 1229 List<TargetedResult> resultStored(TargetedResult newResult, newValue) { |
1183 return TargetedResult.EMPTY_LIST; | 1230 return TargetedResult.EMPTY_LIST; |
1184 } | 1231 } |
1185 | 1232 |
1186 @override | 1233 @override |
1187 void targetRemoved(AnalysisTarget target) {} | 1234 void targetRemoved(AnalysisTarget target) {} |
1188 } | 1235 } |
OLD | NEW |