| 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'; |
| 11 import 'package:analyzer/src/generated/engine.dart' | 11 import 'package:analyzer/src/generated/engine.dart' |
| 12 hide AnalysisTask, AnalysisContextImpl; | 12 hide AnalysisTask, AnalysisContextImpl, WorkManager; |
| 13 import 'package:analyzer/src/generated/java_engine.dart'; | 13 import 'package:analyzer/src/generated/java_engine.dart'; |
| 14 import 'package:analyzer/src/generated/resolver.dart'; | 14 import 'package:analyzer/src/generated/resolver.dart'; |
| 15 import 'package:analyzer/src/generated/utilities_general.dart'; | 15 import 'package:analyzer/src/generated/utilities_general.dart'; |
| 16 import 'package:analyzer/src/task/inputs.dart'; | 16 import 'package:analyzer/src/task/inputs.dart'; |
| 17 import 'package:analyzer/src/task/manager.dart'; | 17 import 'package:analyzer/src/task/manager.dart'; |
| 18 import 'package:analyzer/task/model.dart'; | 18 import 'package:analyzer/task/model.dart'; |
| 19 | 19 |
| 20 final PerformanceTag workOrderMoveNextPerfTag = | 20 final PerformanceTag workOrderMoveNextPerfTag = |
| 21 new PerformanceTag('WorkOrder.moveNext'); | 21 new PerformanceTag('WorkOrder.moveNext'); |
| 22 | 22 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 37 final List<WorkManager> workManagers; | 37 final List<WorkManager> workManagers; |
| 38 | 38 |
| 39 /** | 39 /** |
| 40 * The context in which analysis is to be performed. | 40 * The context in which analysis is to be performed. |
| 41 */ | 41 */ |
| 42 final InternalAnalysisContext context; | 42 final InternalAnalysisContext context; |
| 43 | 43 |
| 44 /** | 44 /** |
| 45 * The map of [ComputedResult] controllers. | 45 * The map of [ComputedResult] controllers. |
| 46 */ | 46 */ |
| 47 final Map<ResultDescriptor, StreamController<ComputedResult>> resultComputedCo
ntrollers = | 47 final Map<ResultDescriptor, |
| 48 StreamController<ComputedResult>> resultComputedControllers = |
| 48 <ResultDescriptor, StreamController<ComputedResult>>{}; | 49 <ResultDescriptor, StreamController<ComputedResult>>{}; |
| 49 | 50 |
| 50 /** | 51 /** |
| 51 * The work order that was previously computed but that has not yet been | 52 * The work order that was previously computed but that has not yet been |
| 52 * completed. | 53 * completed. |
| 53 */ | 54 */ |
| 54 WorkOrder currentWorkOrder; | 55 WorkOrder currentWorkOrder; |
| 55 | 56 |
| 56 /** | 57 /** |
| 57 * Indicates whether any tasks are currently being performed (or building | 58 * Indicates whether any tasks are currently being performed (or building |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 * [target]. Return the last [AnalysisTask] that was performed. | 95 * [target]. Return the last [AnalysisTask] that was performed. |
| 95 */ | 96 */ |
| 96 AnalysisTask computeResult(AnalysisTarget target, ResultDescriptor result) { | 97 AnalysisTask computeResult(AnalysisTarget target, ResultDescriptor result) { |
| 97 assert(!isTaskRunning); | 98 assert(!isTaskRunning); |
| 98 try { | 99 try { |
| 99 isTaskRunning = true; | 100 isTaskRunning = true; |
| 100 AnalysisTask task; | 101 AnalysisTask task; |
| 101 WorkOrder workOrder = createWorkOrderForResult(target, result); | 102 WorkOrder workOrder = createWorkOrderForResult(target, result); |
| 102 if (workOrder != null) { | 103 if (workOrder != null) { |
| 103 while (workOrder.moveNext()) { | 104 while (workOrder.moveNext()) { |
| 105 // AnalysisTask previousTask = task; |
| 106 // String message = workOrder.current.toString(); |
| 104 task = performWorkItem(workOrder.current); | 107 task = performWorkItem(workOrder.current); |
| 108 // if (task == null) { |
| 109 // throw new AnalysisException(message, previousTask.caughtException)
; |
| 110 // } |
| 105 } | 111 } |
| 106 } | 112 } |
| 107 return task; | 113 return task; |
| 108 } finally { | 114 } finally { |
| 109 isTaskRunning = false; | 115 isTaskRunning = false; |
| 110 } | 116 } |
| 111 } | 117 } |
| 112 | 118 |
| 113 /** | 119 /** |
| 114 * Return the work order describing the work that should be getting worked on, | 120 * Return the work order describing the work that should be getting worked on, |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 } | 196 } |
| 191 } | 197 } |
| 192 return null; | 198 return null; |
| 193 } | 199 } |
| 194 | 200 |
| 195 /** | 201 /** |
| 196 * Return the stream that is notified when a new value for the given | 202 * Return the stream that is notified when a new value for the given |
| 197 * [descriptor] is computed. | 203 * [descriptor] is computed. |
| 198 */ | 204 */ |
| 199 Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor) { | 205 Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor) { |
| 200 return resultComputedControllers.putIfAbsent(descriptor, () => | 206 return resultComputedControllers |
| 201 new StreamController<ComputedResult>.broadcast(sync: true)).stream; | 207 .putIfAbsent(descriptor, |
| 208 () => new StreamController<ComputedResult>.broadcast(sync: true)) |
| 209 .stream; |
| 202 } | 210 } |
| 203 | 211 |
| 204 /** | 212 /** |
| 205 * Perform the next analysis task, and return `true` if there is more work to | 213 * Perform the next analysis task, and return `true` if there is more work to |
| 206 * be done in order to compute all of the required analysis information. | 214 * be done in order to compute all of the required analysis information. |
| 207 */ | 215 */ |
| 208 bool performAnalysisTask() { | 216 bool performAnalysisTask() { |
| 209 // | 217 // |
| 210 // TODO(brianwilkerson) This implementaiton does not allow us to prioritize | 218 // TODO(brianwilkerson) This implementaiton does not allow us to prioritize |
| 211 // work across contexts. What we need is a way for an external client to ask | 219 // work across contexts. What we need is a way for an external client to ask |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 * the set of [WorkItem]s contained in the cycle (if there are overlapping | 477 * the set of [WorkItem]s contained in the cycle (if there are overlapping |
| 470 * cycles, this is the set of all [WorkItem]s in the entire strongly | 478 * cycles, this is the set of all [WorkItem]s in the entire strongly |
| 471 * connected component). Otherwise, `null`. | 479 * connected component). Otherwise, `null`. |
| 472 */ | 480 */ |
| 473 final List<WorkItem> dependencyCycle; | 481 final List<WorkItem> dependencyCycle; |
| 474 | 482 |
| 475 /** | 483 /** |
| 476 * Initialize a newly created exception to represent a failed attempt to | 484 * Initialize a newly created exception to represent a failed attempt to |
| 477 * perform the given [task] due to the given [dependencyCycle]. | 485 * perform the given [task] due to the given [dependencyCycle]. |
| 478 */ | 486 */ |
| 479 InfiniteTaskLoopException(AnalysisTask task, this.dependencyCycle) : super( | 487 InfiniteTaskLoopException(AnalysisTask task, this.dependencyCycle) |
| 480 'Infinite loop while performing task ${task.descriptor.name} for ${tas
k.target}'); | 488 : super( |
| 489 'Infinite loop while performing task ${task.descriptor.name} for ${t
ask.target}'); |
| 481 } | 490 } |
| 482 | 491 |
| 483 /** | 492 /** |
| 484 * Object used by CycleAwareDependencyWalker to report a single strongly | 493 * Object used by CycleAwareDependencyWalker to report a single strongly |
| 485 * connected component of nodes. | 494 * connected component of nodes. |
| 486 */ | 495 */ |
| 487 class StronglyConnectedComponent<Node> { | 496 class StronglyConnectedComponent<Node> { |
| 488 /** | 497 /** |
| 489 * The nodes contained in the strongly connected component. | 498 * The nodes contained in the strongly connected component. |
| 490 */ | 499 */ |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 558 * cycles, this is the set of all [WorkItem]s in the entire strongly | 567 * cycles, this is the set of all [WorkItem]s in the entire strongly |
| 559 * connected component). Otherwise, `null`. | 568 * connected component). Otherwise, `null`. |
| 560 */ | 569 */ |
| 561 List<WorkItem> dependencyCycle; | 570 List<WorkItem> dependencyCycle; |
| 562 | 571 |
| 563 /** | 572 /** |
| 564 * Initialize a newly created work item to compute the inputs for the task | 573 * Initialize a newly created work item to compute the inputs for the task |
| 565 * described by the given descriptor. | 574 * described by the given descriptor. |
| 566 */ | 575 */ |
| 567 WorkItem(this.context, this.target, this.descriptor, this.spawningResult) { | 576 WorkItem(this.context, this.target, this.descriptor, this.spawningResult) { |
| 568 AnalysisTarget actualTarget = identical( | 577 AnalysisTarget actualTarget = |
| 569 target, AnalysisContextTarget.request) | 578 identical(target, AnalysisContextTarget.request) |
| 570 ? new AnalysisContextTarget(context) | 579 ? new AnalysisContextTarget(context) |
| 571 : target; | 580 : target; |
| 572 Map<String, TaskInput> inputDescriptors = | 581 Map<String, TaskInput> inputDescriptors = |
| 573 descriptor.createTaskInputs(actualTarget); | 582 descriptor.createTaskInputs(actualTarget); |
| 574 builder = new TopLevelTaskInputBuilder(inputDescriptors); | 583 builder = new TopLevelTaskInputBuilder(inputDescriptors); |
| 575 if (!builder.moveNext()) { | 584 if (!builder.moveNext()) { |
| 576 builder = null; | 585 builder = null; |
| 577 } | 586 } |
| 578 inputs = new HashMap<String, dynamic>(); | 587 inputs = new HashMap<String, dynamic>(); |
| 579 } | 588 } |
| 580 | 589 |
| 581 @override | 590 @override |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 try { | 660 try { |
| 652 TaskDescriptor descriptor = | 661 TaskDescriptor descriptor = |
| 653 taskManager.findTask(inputTarget, inputResult); | 662 taskManager.findTask(inputTarget, inputResult); |
| 654 return new WorkItem(context, inputTarget, descriptor, inputResult); | 663 return new WorkItem(context, inputTarget, descriptor, inputResult); |
| 655 } on AnalysisException catch (exception, stackTrace) { | 664 } on AnalysisException catch (exception, stackTrace) { |
| 656 this.exception = new CaughtException(exception, stackTrace); | 665 this.exception = new CaughtException(exception, stackTrace); |
| 657 return null; | 666 return null; |
| 658 } | 667 } |
| 659 } else { | 668 } else { |
| 660 builder.currentValue = inputEntry.getValue(inputResult); | 669 builder.currentValue = inputEntry.getValue(inputResult); |
| 670 if (builder.flushOnAccess) { |
| 671 inputEntry.setState(inputResult, CacheState.FLUSHED); |
| 672 } |
| 661 } | 673 } |
| 662 if (!builder.moveNext()) { | 674 if (!builder.moveNext()) { |
| 663 inputs = builder.inputValue; | 675 inputs = builder.inputValue; |
| 664 builder = null; | 676 builder = null; |
| 665 } | 677 } |
| 666 } | 678 } |
| 667 return null; | 679 return null; |
| 668 } | 680 } |
| 669 | 681 |
| 670 @override | 682 @override |
| 671 String toString() => 'Run $descriptor on $target'; | 683 String toString() => 'Run $descriptor on $target'; |
| 672 } | 684 } |
| 673 | 685 |
| 674 /** | 686 /** |
| 675 * [AnalysisDriver] uses [WorkManager]s to select results to compute. | |
| 676 * | |
| 677 * They know specific of the targets and results they care about, | |
| 678 * so they can request analysis results in optimal order. | |
| 679 */ | |
| 680 abstract class WorkManager { | |
| 681 /** | |
| 682 * Notifies the managers that the given set of priority [targets] was set. | |
| 683 */ | |
| 684 void applyPriorityTargets(List<AnalysisTarget> targets); | |
| 685 | |
| 686 /** | |
| 687 * Return the next [TargetedResult] that this work manager wants to be | |
| 688 * computed, or `null` if this manager doesn't need any new results. | |
| 689 */ | |
| 690 TargetedResult getNextResult(); | |
| 691 | |
| 692 /** | |
| 693 * Return the priority if the next work order this work manager want to be | |
| 694 * computed. The [AnalysisDriver] will perform the work order with | |
| 695 * the highest priority. | |
| 696 * | |
| 697 * Even if the returned value is [WorkOrderPriority.NONE], it still does not | |
| 698 * guarantee that [getNextResult] will return not `null`. | |
| 699 */ | |
| 700 WorkOrderPriority getNextResultPriority(); | |
| 701 | |
| 702 /** | |
| 703 * Notifies the manager that the given [outputs] were produced for | |
| 704 * the given [target]. | |
| 705 */ | |
| 706 void resultsComputed( | |
| 707 AnalysisTarget target, Map<ResultDescriptor, dynamic> outputs); | |
| 708 } | |
| 709 | |
| 710 /** | |
| 711 * A description of the work to be done to compute a desired analysis result. | 687 * A description of the work to be done to compute a desired analysis result. |
| 712 * The class implements a lazy depth-first traversal of the work item's input. | 688 * The class implements a lazy depth-first traversal of the work item's input. |
| 713 */ | 689 */ |
| 714 class WorkOrder implements Iterator<WorkItem> { | 690 class WorkOrder implements Iterator<WorkItem> { |
| 715 /** | 691 /** |
| 716 * The dependency walker which is being used to determine what work to do | 692 * The dependency walker which is being used to determine what work to do |
| 717 * next. | 693 * next. |
| 718 */ | 694 */ |
| 719 final _WorkOrderDependencyWalker _dependencyWalker; | 695 final _WorkOrderDependencyWalker _dependencyWalker; |
| 720 | 696 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 767 } else { | 743 } else { |
| 768 assert(currentItems.length == 1); | 744 assert(currentItems.length == 1); |
| 769 } | 745 } |
| 770 return true; | 746 return true; |
| 771 } | 747 } |
| 772 }); | 748 }); |
| 773 } | 749 } |
| 774 } | 750 } |
| 775 | 751 |
| 776 /** | 752 /** |
| 777 * The priorities of work orders returned by [WorkManager]s. | |
| 778 */ | |
| 779 enum WorkOrderPriority { | |
| 780 /** | |
| 781 * Responding to an user's action. | |
| 782 */ | |
| 783 INTERACTIVE, | |
| 784 | |
| 785 /** | |
| 786 * Computing information for priority sources. | |
| 787 */ | |
| 788 PRIORITY, | |
| 789 | |
| 790 /** | |
| 791 * A work should be done, but without any special urgency. | |
| 792 */ | |
| 793 NORMAL, | |
| 794 | |
| 795 /** | |
| 796 * Nothing to do. | |
| 797 */ | |
| 798 NONE | |
| 799 } | |
| 800 | |
| 801 /** | |
| 802 * Specilaization of [CycleAwareDependencyWalker] for use by [WorkOrder]. | 753 * Specilaization of [CycleAwareDependencyWalker] for use by [WorkOrder]. |
| 803 */ | 754 */ |
| 804 class _WorkOrderDependencyWalker extends CycleAwareDependencyWalker<WorkItem> { | 755 class _WorkOrderDependencyWalker extends CycleAwareDependencyWalker<WorkItem> { |
| 805 /** | 756 /** |
| 806 * The task manager used to build work items. | 757 * The task manager used to build work items. |
| 807 */ | 758 */ |
| 808 final TaskManager taskManager; | 759 final TaskManager taskManager; |
| 809 | 760 |
| 810 _WorkOrderDependencyWalker(this.taskManager, WorkItem startingNode) | 761 _WorkOrderDependencyWalker(this.taskManager, WorkItem startingNode) |
| 811 : super(startingNode); | 762 : super(startingNode); |
| 812 | 763 |
| 813 @override | 764 @override |
| 814 WorkItem getNextInput(WorkItem node, List<WorkItem> skipInputs) { | 765 WorkItem getNextInput(WorkItem node, List<WorkItem> skipInputs) { |
| 815 return node.gatherInputs(taskManager, skipInputs); | 766 return node.gatherInputs(taskManager, skipInputs); |
| 816 } | 767 } |
| 817 } | 768 } |
| OLD | NEW |