| 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.task.driver; | 5 library analyzer.src.task.driver; |
| 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/context/cache.dart'; | 10 import 'package:analyzer/src/context/cache.dart'; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 * compute. | 37 * compute. |
| 38 */ | 38 */ |
| 39 final List<WorkManager> workManagers; | 39 final List<WorkManager> workManagers; |
| 40 | 40 |
| 41 /** | 41 /** |
| 42 * The context in which analysis is to be performed. | 42 * The context in which analysis is to be performed. |
| 43 */ | 43 */ |
| 44 final InternalAnalysisContext context; | 44 final InternalAnalysisContext context; |
| 45 | 45 |
| 46 /** | 46 /** |
| 47 * The alternative source of analysis results. | |
| 48 */ | |
| 49 ResultProvider resultProvider; | |
| 50 | |
| 51 /** | |
| 52 * The map of [ComputedResult] controllers. | 47 * The map of [ComputedResult] controllers. |
| 53 */ | 48 */ |
| 54 final Map<ResultDescriptor, StreamController<ComputedResult>> | 49 final Map<ResultDescriptor, StreamController<ComputedResult>> |
| 55 resultComputedControllers = | 50 resultComputedControllers = |
| 56 <ResultDescriptor, StreamController<ComputedResult>>{}; | 51 <ResultDescriptor, StreamController<ComputedResult>>{}; |
| 57 | 52 |
| 58 /** | 53 /** |
| 59 * The work order that was previously computed but that has not yet been | 54 * The work order that was previously computed but that has not yet been |
| 60 * completed. | 55 * completed. |
| 61 */ | 56 */ |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 AnalysisTarget target, ResultDescriptor result) { | 160 AnalysisTarget target, ResultDescriptor result) { |
| 166 CacheEntry entry = context.getCacheEntry(target); | 161 CacheEntry entry = context.getCacheEntry(target); |
| 167 CacheState state = entry.getState(result); | 162 CacheState state = entry.getState(result); |
| 168 if (state == CacheState.VALID || | 163 if (state == CacheState.VALID || |
| 169 state == CacheState.ERROR || | 164 state == CacheState.ERROR || |
| 170 state == CacheState.IN_PROCESS) { | 165 state == CacheState.IN_PROCESS) { |
| 171 return null; | 166 return null; |
| 172 } | 167 } |
| 173 TaskDescriptor taskDescriptor = taskManager.findTask(target, result); | 168 TaskDescriptor taskDescriptor = taskManager.findTask(target, result); |
| 174 try { | 169 try { |
| 175 WorkItem workItem = new WorkItem( | 170 WorkItem workItem = |
| 176 context, resultProvider, target, taskDescriptor, result, 0, null); | 171 new WorkItem(context, target, taskDescriptor, result, 0, null); |
| 177 return new WorkOrder(taskManager, workItem); | 172 return new WorkOrder(taskManager, workItem); |
| 178 } catch (exception, stackTrace) { | 173 } catch (exception, stackTrace) { |
| 179 throw new AnalysisException( | 174 throw new AnalysisException( |
| 180 'Could not create work order (target = $target; taskDescriptor = $task
Descriptor; result = $result)', | 175 'Could not create work order (target = $target; taskDescriptor = $task
Descriptor; result = $result)', |
| 181 new CaughtException(exception, stackTrace)); | 176 new CaughtException(exception, stackTrace)); |
| 182 } | 177 } |
| 183 } | 178 } |
| 184 | 179 |
| 185 /** | 180 /** |
| 186 * Create a work order that will produce the required analysis results for | 181 * Create a work order that will produce the required analysis results for |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 502 * Initialize a newly created exception to represent a failed attempt to | 497 * Initialize a newly created exception to represent a failed attempt to |
| 503 * perform the given [task] due to the given [dependencyCycle]. | 498 * perform the given [task] due to the given [dependencyCycle]. |
| 504 */ | 499 */ |
| 505 InfiniteTaskLoopException(AnalysisTask task, this.dependencyCycle, | 500 InfiniteTaskLoopException(AnalysisTask task, this.dependencyCycle, |
| 506 [this.cyclicPath]) | 501 [this.cyclicPath]) |
| 507 : super( | 502 : super( |
| 508 'Infinite loop while performing task ${task.descriptor.name} for ${t
ask.target}'); | 503 'Infinite loop while performing task ${task.descriptor.name} for ${t
ask.target}'); |
| 509 } | 504 } |
| 510 | 505 |
| 511 /** | 506 /** |
| 512 * The object used by [WorkItem] to get values without using tasks. | |
| 513 */ | |
| 514 abstract class ResultProvider { | |
| 515 /** | |
| 516 * [WorkItem] calls this method when the [result] of the [entry] is | |
| 517 * [CacheState.INVALID], so it is about to schedule its computation. | |
| 518 * | |
| 519 * If the provider knows how to provide the value, it sets the value into | |
| 520 * the [entry] with all required dependencies, and returns `true`. | |
| 521 * | |
| 522 * Otherwise, it returns `false` to indicate that the [WorkItem] should | |
| 523 * compute the value. | |
| 524 */ | |
| 525 bool provideResult(InternalAnalysisContext context, CacheEntry entry, | |
| 526 ResultDescriptor result); | |
| 527 } | |
| 528 | |
| 529 /** | |
| 530 * Object used by [CycleAwareDependencyWalker] to report a single strongly | 507 * Object used by [CycleAwareDependencyWalker] to report a single strongly |
| 531 * connected component of nodes. | 508 * connected component of nodes. |
| 532 */ | 509 */ |
| 533 class StronglyConnectedComponent<Node> { | 510 class StronglyConnectedComponent<Node> { |
| 534 /** | 511 /** |
| 535 * The nodes contained in the strongly connected component. | 512 * The nodes contained in the strongly connected component. |
| 536 */ | 513 */ |
| 537 final List<Node> nodes; | 514 final List<Node> nodes; |
| 538 | 515 |
| 539 /** | 516 /** |
| (...skipping 11 matching lines...) Expand all Loading... |
| 551 * A description of a single analysis task that can be performed to advance | 528 * A description of a single analysis task that can be performed to advance |
| 552 * analysis. | 529 * analysis. |
| 553 */ | 530 */ |
| 554 class WorkItem { | 531 class WorkItem { |
| 555 /** | 532 /** |
| 556 * The context in which the task will be performed. | 533 * The context in which the task will be performed. |
| 557 */ | 534 */ |
| 558 final InternalAnalysisContext context; | 535 final InternalAnalysisContext context; |
| 559 | 536 |
| 560 /** | 537 /** |
| 561 * The alternative source of analysis results. | |
| 562 */ | |
| 563 final ResultProvider resultProvider; | |
| 564 | |
| 565 /** | |
| 566 * The target for which a task is to be performed. | 538 * The target for which a task is to be performed. |
| 567 */ | 539 */ |
| 568 final AnalysisTarget target; | 540 final AnalysisTarget target; |
| 569 | 541 |
| 570 /** | 542 /** |
| 571 * A description of the task to be performed. | 543 * A description of the task to be performed. |
| 572 */ | 544 */ |
| 573 final TaskDescriptor descriptor; | 545 final TaskDescriptor descriptor; |
| 574 | 546 |
| 575 /** | 547 /** |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 * the set of [WorkItem]s contained in the cycle (if there are overlapping | 590 * the set of [WorkItem]s contained in the cycle (if there are overlapping |
| 619 * cycles, this is the set of all [WorkItem]s in the entire strongly | 591 * cycles, this is the set of all [WorkItem]s in the entire strongly |
| 620 * connected component). Otherwise, `null`. | 592 * connected component). Otherwise, `null`. |
| 621 */ | 593 */ |
| 622 List<WorkItem> dependencyCycle; | 594 List<WorkItem> dependencyCycle; |
| 623 | 595 |
| 624 /** | 596 /** |
| 625 * Initialize a newly created work item to compute the inputs for the task | 597 * Initialize a newly created work item to compute the inputs for the task |
| 626 * described by the given descriptor. | 598 * described by the given descriptor. |
| 627 */ | 599 */ |
| 628 WorkItem(this.context, this.resultProvider, this.target, this.descriptor, | 600 WorkItem(this.context, this.target, this.descriptor, this.spawningResult, |
| 629 this.spawningResult, this.level, this.workOrder) { | 601 this.level, this.workOrder) { |
| 630 AnalysisTarget actualTarget = | 602 AnalysisTarget actualTarget = |
| 631 identical(target, AnalysisContextTarget.request) | 603 identical(target, AnalysisContextTarget.request) |
| 632 ? new AnalysisContextTarget(context) | 604 ? new AnalysisContextTarget(context) |
| 633 : target; | 605 : target; |
| 634 // print('${'\t' * level}$spawningResult of $actualTarget'); | 606 // print('${'\t' * level}$spawningResult of $actualTarget'); |
| 635 Map<String, TaskInput> inputDescriptors = | 607 Map<String, TaskInput> inputDescriptors = |
| 636 descriptor.createTaskInputs(actualTarget); | 608 descriptor.createTaskInputs(actualTarget); |
| 637 builder = new TopLevelTaskInputBuilder(inputDescriptors); | 609 builder = new TopLevelTaskInputBuilder(inputDescriptors); |
| 638 if (!builder.moveNext()) { | 610 if (!builder.moveNext()) { |
| 639 builder = null; | 611 builder = null; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 723 // One possibility would be to return a WorkItem that would perform a | 695 // One possibility would be to return a WorkItem that would perform a |
| 724 // no-op task in order to cause us to come back to this work item on the | 696 // no-op task in order to cause us to come back to this work item on the |
| 725 // next iteration. It would be more efficient, in general, to push this | 697 // next iteration. It would be more efficient, in general, to push this |
| 726 // input onto a waiting list and proceed to the next input so that work | 698 // input onto a waiting list and proceed to the next input so that work |
| 727 // could proceed, but given that the only result that can currently be | 699 // could proceed, but given that the only result that can currently be |
| 728 // IN_PROCESS is CONTENT, I don't know that it's worth the extra effort | 700 // IN_PROCESS is CONTENT, I don't know that it's worth the extra effort |
| 729 // to implement the general solution at this point. | 701 // to implement the general solution at this point. |
| 730 // | 702 // |
| 731 throw new UnimplementedError(); | 703 throw new UnimplementedError(); |
| 732 } else if (inputState != CacheState.VALID) { | 704 } else if (inputState != CacheState.VALID) { |
| 733 if (resultProvider != null && | 705 if (context.aboutToComputeResult(inputEntry, inputResult)) { |
| 734 resultProvider.provideResult(context, inputEntry, inputResult)) { | |
| 735 inputState = CacheState.VALID; | 706 inputState = CacheState.VALID; |
| 736 builder.currentValue = inputEntry.getValue(inputResult); | 707 builder.currentValue = inputEntry.getValue(inputResult); |
| 737 } else { | 708 } else { |
| 738 try { | 709 try { |
| 739 TaskDescriptor descriptor = | 710 TaskDescriptor descriptor = |
| 740 taskManager.findTask(inputTarget, inputResult); | 711 taskManager.findTask(inputTarget, inputResult); |
| 741 return new WorkItem(context, resultProvider, inputTarget, | 712 return new WorkItem(context, inputTarget, descriptor, inputResult, |
| 742 descriptor, inputResult, level + 1, workOrder); | 713 level + 1, workOrder); |
| 743 } on AnalysisException catch (exception, stackTrace) { | 714 } on AnalysisException catch (exception, stackTrace) { |
| 744 this.exception = new CaughtException(exception, stackTrace); | 715 this.exception = new CaughtException(exception, stackTrace); |
| 745 return null; | 716 return null; |
| 746 } | 717 } |
| 747 } | 718 } |
| 748 } else { | 719 } else { |
| 749 builder.currentValue = inputEntry.getValue(inputResult); | 720 builder.currentValue = inputEntry.getValue(inputResult); |
| 750 if (builder.flushOnAccess) { | 721 if (builder.flushOnAccess) { |
| 751 inputEntry.setState(inputResult, CacheState.FLUSHED); | 722 inputEntry.setState(inputResult, CacheState.FLUSHED); |
| 752 } | 723 } |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 843 final TaskManager taskManager; | 814 final TaskManager taskManager; |
| 844 | 815 |
| 845 _WorkOrderDependencyWalker(this.taskManager, WorkItem startingNode) | 816 _WorkOrderDependencyWalker(this.taskManager, WorkItem startingNode) |
| 846 : super(startingNode); | 817 : super(startingNode); |
| 847 | 818 |
| 848 @override | 819 @override |
| 849 WorkItem getNextInput(WorkItem node, List<WorkItem> skipInputs) { | 820 WorkItem getNextInput(WorkItem node, List<WorkItem> skipInputs) { |
| 850 return node.gatherInputs(taskManager, skipInputs); | 821 return node.gatherInputs(taskManager, skipInputs); |
| 851 } | 822 } |
| 852 } | 823 } |
| OLD | NEW |