| 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 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 AnalysisTarget target, ResultDescriptor result) { | 161 AnalysisTarget target, ResultDescriptor result) { |
| 162 CacheEntry entry = context.getCacheEntry(target); | 162 CacheEntry entry = context.getCacheEntry(target); |
| 163 CacheState state = entry.getState(result); | 163 CacheState state = entry.getState(result); |
| 164 if (state == CacheState.VALID || | 164 if (state == CacheState.VALID || |
| 165 state == CacheState.ERROR || | 165 state == CacheState.ERROR || |
| 166 state == CacheState.IN_PROCESS) { | 166 state == CacheState.IN_PROCESS) { |
| 167 return null; | 167 return null; |
| 168 } | 168 } |
| 169 TaskDescriptor taskDescriptor = taskManager.findTask(target, result); | 169 TaskDescriptor taskDescriptor = taskManager.findTask(target, result); |
| 170 try { | 170 try { |
| 171 WorkItem workItem = new WorkItem(context, target, taskDescriptor, result); | 171 WorkItem workItem = |
| 172 new WorkItem(context, target, taskDescriptor, result, null); |
| 172 return new WorkOrder(taskManager, workItem); | 173 return new WorkOrder(taskManager, workItem); |
| 173 } catch (exception, stackTrace) { | 174 } catch (exception, stackTrace) { |
| 174 throw new AnalysisException( | 175 throw new AnalysisException( |
| 175 'Could not create work order (target = $target; taskDescriptor = $task
Descriptor; result = $result)', | 176 'Could not create work order (target = $target; taskDescriptor = $task
Descriptor; result = $result)', |
| 176 new CaughtException(exception, stackTrace)); | 177 new CaughtException(exception, stackTrace)); |
| 177 } | 178 } |
| 178 } | 179 } |
| 179 | 180 |
| 180 /** | 181 /** |
| 181 * Create a work order that will produce the required analysis results for | 182 * Create a work order that will produce the required analysis results for |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 * A description of the task to be performed. | 544 * A description of the task to be performed. |
| 544 */ | 545 */ |
| 545 final TaskDescriptor descriptor; | 546 final TaskDescriptor descriptor; |
| 546 | 547 |
| 547 /** | 548 /** |
| 548 * The [ResultDescriptor] which was led to this work item being spawned. | 549 * The [ResultDescriptor] which was led to this work item being spawned. |
| 549 */ | 550 */ |
| 550 final ResultDescriptor spawningResult; | 551 final ResultDescriptor spawningResult; |
| 551 | 552 |
| 552 /** | 553 /** |
| 554 * The work order that this item is part of, may be `null`. |
| 555 */ |
| 556 WorkOrder workOrder; |
| 557 |
| 558 /** |
| 553 * An iterator used to iterate over the descriptors of the inputs to the task, | 559 * An iterator used to iterate over the descriptors of the inputs to the task, |
| 554 * or `null` if all of the inputs have been collected and the task can be | 560 * or `null` if all of the inputs have been collected and the task can be |
| 555 * created. | 561 * created. |
| 556 */ | 562 */ |
| 557 TaskInputBuilder builder; | 563 TaskInputBuilder builder; |
| 558 | 564 |
| 559 /** | 565 /** |
| 560 * The [TargetedResult]s outputs of this task depends on. | 566 * The [TargetedResult]s outputs of this task depends on. |
| 561 */ | 567 */ |
| 562 final HashSet<TargetedResult> inputTargetedResults = | 568 final HashSet<TargetedResult> inputTargetedResults = |
| (...skipping 17 matching lines...) Expand all Loading... |
| 580 * the set of [WorkItem]s contained in the cycle (if there are overlapping | 586 * the set of [WorkItem]s contained in the cycle (if there are overlapping |
| 581 * cycles, this is the set of all [WorkItem]s in the entire strongly | 587 * cycles, this is the set of all [WorkItem]s in the entire strongly |
| 582 * connected component). Otherwise, `null`. | 588 * connected component). Otherwise, `null`. |
| 583 */ | 589 */ |
| 584 List<WorkItem> dependencyCycle; | 590 List<WorkItem> dependencyCycle; |
| 585 | 591 |
| 586 /** | 592 /** |
| 587 * Initialize a newly created work item to compute the inputs for the task | 593 * Initialize a newly created work item to compute the inputs for the task |
| 588 * described by the given descriptor. | 594 * described by the given descriptor. |
| 589 */ | 595 */ |
| 590 WorkItem(this.context, this.target, this.descriptor, this.spawningResult) { | 596 WorkItem(this.context, this.target, this.descriptor, this.spawningResult, |
| 597 this.workOrder) { |
| 591 AnalysisTarget actualTarget = | 598 AnalysisTarget actualTarget = |
| 592 identical(target, AnalysisContextTarget.request) | 599 identical(target, AnalysisContextTarget.request) |
| 593 ? new AnalysisContextTarget(context) | 600 ? new AnalysisContextTarget(context) |
| 594 : target; | 601 : target; |
| 595 Map<String, TaskInput> inputDescriptors = | 602 Map<String, TaskInput> inputDescriptors = |
| 596 descriptor.createTaskInputs(actualTarget); | 603 descriptor.createTaskInputs(actualTarget); |
| 597 builder = new TopLevelTaskInputBuilder(inputDescriptors); | 604 builder = new TopLevelTaskInputBuilder(inputDescriptors); |
| 598 if (!builder.moveNext()) { | 605 if (!builder.moveNext()) { |
| 599 builder = null; | 606 builder = null; |
| 600 } | 607 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 * returned if some of the inputs cannot be computed and the task cannot be | 646 * returned if some of the inputs cannot be computed and the task cannot be |
| 640 * performed. Callers can differentiate between these cases by checking the | 647 * performed. Callers can differentiate between these cases by checking the |
| 641 * [exception] field. If the field is `null`, then the task can be performed; | 648 * [exception] field. If the field is `null`, then the task can be performed; |
| 642 * if the field is non-`null` then the task cannot be performed and all of the | 649 * if the field is non-`null` then the task cannot be performed and all of the |
| 643 * tasks' results should be marked as being in ERROR. | 650 * tasks' results should be marked as being in ERROR. |
| 644 */ | 651 */ |
| 645 WorkItem gatherInputs(TaskManager taskManager, List<WorkItem> skipInputs) { | 652 WorkItem gatherInputs(TaskManager taskManager, List<WorkItem> skipInputs) { |
| 646 while (builder != null) { | 653 while (builder != null) { |
| 647 AnalysisTarget inputTarget = builder.currentTarget; | 654 AnalysisTarget inputTarget = builder.currentTarget; |
| 648 ResultDescriptor inputResult = builder.currentResult; | 655 ResultDescriptor inputResult = builder.currentResult; |
| 656 |
| 657 // TODO(scheglov) record information to debug |
| 658 // https://github.com/dart-lang/sdk/issues/24939 |
| 659 if (inputTarget == null || inputResult == null) { |
| 660 try { |
| 661 String message = |
| 662 'Invalid input descriptor ($inputTarget, $inputResult) for $this'; |
| 663 if (workOrder != null) { |
| 664 message += '\nPath:\n' + workOrder.workItems.join('|\n'); |
| 665 } |
| 666 throw new AnalysisException(message); |
| 667 } catch (exception, stackTrace) { |
| 668 this.exception = new CaughtException(exception, stackTrace); |
| 669 AnalysisEngine.instance.logger |
| 670 .logError('Task failed: $this', this.exception); |
| 671 } |
| 672 return null; |
| 673 } |
| 674 |
| 649 inputTargetedResults.add(new TargetedResult(inputTarget, inputResult)); | 675 inputTargetedResults.add(new TargetedResult(inputTarget, inputResult)); |
| 650 CacheEntry inputEntry = context.getCacheEntry(inputTarget); | 676 CacheEntry inputEntry = context.getCacheEntry(inputTarget); |
| 651 CacheState inputState = inputEntry.getState(inputResult); | 677 CacheState inputState = inputEntry.getState(inputResult); |
| 652 if (skipInputs.any((WorkItem item) => | 678 if (skipInputs.any((WorkItem item) => |
| 653 item.target == inputTarget && item.spawningResult == inputResult)) { | 679 item.target == inputTarget && item.spawningResult == inputResult)) { |
| 654 // This input is being skipped due to a circular dependency. Tell the | 680 // This input is being skipped due to a circular dependency. Tell the |
| 655 // builder that it's not available so we can move on to other inputs. | 681 // builder that it's not available so we can move on to other inputs. |
| 656 builder.currentValueNotAvailable(); | 682 builder.currentValueNotAvailable(); |
| 657 } else if (inputState == CacheState.ERROR) { | 683 } else if (inputState == CacheState.ERROR) { |
| 658 exception = inputEntry.exception; | 684 exception = inputEntry.exception; |
| 659 return null; | 685 return null; |
| 660 } else if (inputState == CacheState.IN_PROCESS) { | 686 } else if (inputState == CacheState.IN_PROCESS) { |
| 661 // | 687 // |
| 662 // TODO(brianwilkerson) Implement this case. | 688 // TODO(brianwilkerson) Implement this case. |
| 663 // | 689 // |
| 664 // One possibility would be to return a WorkItem that would perform a | 690 // One possibility would be to return a WorkItem that would perform a |
| 665 // no-op task in order to cause us to come back to this work item on the | 691 // no-op task in order to cause us to come back to this work item on the |
| 666 // next iteration. It would be more efficient, in general, to push this | 692 // next iteration. It would be more efficient, in general, to push this |
| 667 // input onto a waiting list and proceed to the next input so that work | 693 // input onto a waiting list and proceed to the next input so that work |
| 668 // could proceed, but given that the only result that can currently be | 694 // could proceed, but given that the only result that can currently be |
| 669 // IN_PROCESS is CONTENT, I don't know that it's worth the extra effort | 695 // IN_PROCESS is CONTENT, I don't know that it's worth the extra effort |
| 670 // to implement the general solution at this point. | 696 // to implement the general solution at this point. |
| 671 // | 697 // |
| 672 throw new UnimplementedError(); | 698 throw new UnimplementedError(); |
| 673 } else if (inputState != CacheState.VALID) { | 699 } else if (inputState != CacheState.VALID) { |
| 674 try { | 700 try { |
| 675 TaskDescriptor descriptor = | 701 TaskDescriptor descriptor = |
| 676 taskManager.findTask(inputTarget, inputResult); | 702 taskManager.findTask(inputTarget, inputResult); |
| 677 return new WorkItem(context, inputTarget, descriptor, inputResult); | 703 return new WorkItem( |
| 704 context, inputTarget, descriptor, inputResult, workOrder); |
| 678 } on AnalysisException catch (exception, stackTrace) { | 705 } on AnalysisException catch (exception, stackTrace) { |
| 679 this.exception = new CaughtException(exception, stackTrace); | 706 this.exception = new CaughtException(exception, stackTrace); |
| 680 return null; | 707 return null; |
| 681 } | 708 } |
| 682 } else { | 709 } else { |
| 683 builder.currentValue = inputEntry.getValue(inputResult); | 710 builder.currentValue = inputEntry.getValue(inputResult); |
| 684 if (builder.flushOnAccess) { | 711 if (builder.flushOnAccess) { |
| 685 inputEntry.setState(inputResult, CacheState.FLUSHED); | 712 inputEntry.setState(inputResult, CacheState.FLUSHED); |
| 686 } | 713 } |
| 687 } | 714 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 715 * | 742 * |
| 716 * Null if the [_dependencyWalker] hasn't been used yet. | 743 * Null if the [_dependencyWalker] hasn't been used yet. |
| 717 */ | 744 */ |
| 718 List<WorkItem> currentItems; | 745 List<WorkItem> currentItems; |
| 719 | 746 |
| 720 /** | 747 /** |
| 721 * Initialize a newly created work order to compute the result described by | 748 * Initialize a newly created work order to compute the result described by |
| 722 * the given work item. | 749 * the given work item. |
| 723 */ | 750 */ |
| 724 WorkOrder(TaskManager taskManager, WorkItem item) | 751 WorkOrder(TaskManager taskManager, WorkItem item) |
| 725 : _dependencyWalker = new _WorkOrderDependencyWalker(taskManager, item); | 752 : _dependencyWalker = new _WorkOrderDependencyWalker(taskManager, item) { |
| 753 item.workOrder = this; |
| 754 } |
| 726 | 755 |
| 727 @override | 756 @override |
| 728 WorkItem get current { | 757 WorkItem get current { |
| 729 if (currentItems == null) { | 758 if (currentItems == null) { |
| 730 return null; | 759 return null; |
| 731 } else { | 760 } else { |
| 732 return currentItems.last; | 761 return currentItems.last; |
| 733 } | 762 } |
| 734 } | 763 } |
| 735 | 764 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 775 final TaskManager taskManager; | 804 final TaskManager taskManager; |
| 776 | 805 |
| 777 _WorkOrderDependencyWalker(this.taskManager, WorkItem startingNode) | 806 _WorkOrderDependencyWalker(this.taskManager, WorkItem startingNode) |
| 778 : super(startingNode); | 807 : super(startingNode); |
| 779 | 808 |
| 780 @override | 809 @override |
| 781 WorkItem getNextInput(WorkItem node, List<WorkItem> skipInputs) { | 810 WorkItem getNextInput(WorkItem node, List<WorkItem> skipInputs) { |
| 782 return node.gatherInputs(taskManager, skipInputs); | 811 return node.gatherInputs(taskManager, skipInputs); |
| 783 } | 812 } |
| 784 } | 813 } |
| OLD | NEW |