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

Side by Side Diff: pkg/analyzer/lib/src/summary/link.dart

Issue 2554973002: Move dependency walker logic to front end. (Closed)
Patch Set: Created 4 years 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
« no previous file with comments | « no previous file | pkg/front_end/lib/src/dependency_walker.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) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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 /** 5 /**
6 * This library is capable of producing linked summaries from unlinked 6 * This library is capable of producing linked summaries from unlinked
7 * ones (or prelinked ones). It functions by building a miniature 7 * ones (or prelinked ones). It functions by building a miniature
8 * element model to represent the contents of the summaries, and then 8 * element model to represent the contents of the summaries, and then
9 * scanning the element model to gather linked information and adding 9 * scanning the element model to gather linked information and adding
10 * it to the summary data structures. 10 * it to the summary data structures.
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 import 'package:analyzer/src/dart/element/element.dart'; 65 import 'package:analyzer/src/dart/element/element.dart';
66 import 'package:analyzer/src/dart/element/type.dart'; 66 import 'package:analyzer/src/dart/element/type.dart';
67 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart'; 67 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
68 import 'package:analyzer/src/generated/engine.dart'; 68 import 'package:analyzer/src/generated/engine.dart';
69 import 'package:analyzer/src/generated/resolver.dart'; 69 import 'package:analyzer/src/generated/resolver.dart';
70 import 'package:analyzer/src/generated/utilities_dart.dart'; 70 import 'package:analyzer/src/generated/utilities_dart.dart';
71 import 'package:analyzer/src/summary/format.dart'; 71 import 'package:analyzer/src/summary/format.dart';
72 import 'package:analyzer/src/summary/idl.dart'; 72 import 'package:analyzer/src/summary/idl.dart';
73 import 'package:analyzer/src/summary/prelink.dart'; 73 import 'package:analyzer/src/summary/prelink.dart';
74 import 'package:analyzer/src/task/strong_mode.dart'; 74 import 'package:analyzer/src/task/strong_mode.dart';
75 import 'package:front_end/src/dependency_walker.dart';
75 76
76 bool isIncrementOrDecrement(UnlinkedExprAssignOperator operator) { 77 bool isIncrementOrDecrement(UnlinkedExprAssignOperator operator) {
77 switch (operator) { 78 switch (operator) {
78 case UnlinkedExprAssignOperator.prefixDecrement: 79 case UnlinkedExprAssignOperator.prefixDecrement:
79 case UnlinkedExprAssignOperator.prefixIncrement: 80 case UnlinkedExprAssignOperator.prefixIncrement:
80 case UnlinkedExprAssignOperator.postfixDecrement: 81 case UnlinkedExprAssignOperator.postfixDecrement:
81 case UnlinkedExprAssignOperator.postfixIncrement: 82 case UnlinkedExprAssignOperator.postfixIncrement:
82 return true; 83 return true;
83 default: 84 default:
84 return false; 85 return false;
(...skipping 1660 matching lines...) Expand 10 before | Expand all | Expand 10 after
1745 AnalysisOptionsForLink get analysisOptions => _linker.analysisOptions; 1746 AnalysisOptionsForLink get analysisOptions => _linker.analysisOptions;
1746 1747
1747 @override 1748 @override
1748 TypeSystem get typeSystem => _linker.typeSystem; 1749 TypeSystem get typeSystem => _linker.typeSystem;
1749 1750
1750 @override 1751 @override
1751 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); 1752 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
1752 } 1753 }
1753 1754
1754 /** 1755 /**
1755 * An instance of [DependencyWalker] contains the core algorithms for
1756 * walking a dependency graph and evaluating nodes in a safe order.
1757 */
1758 abstract class DependencyWalker<NodeType extends Node<NodeType>> {
1759 /**
1760 * Called by [walk] to evaluate a single non-cyclical node, after
1761 * all that node's dependencies have been evaluated.
1762 */
1763 void evaluate(NodeType v);
1764
1765 /**
1766 * Called by [walk] to evaluate a strongly connected component
1767 * containing one or more nodes. All dependencies of the strongly
1768 * connected component have been evaluated.
1769 */
1770 void evaluateScc(List<NodeType> scc);
1771
1772 /**
1773 * Walk the dependency graph starting at [startingPoint], finding
1774 * strongly connected components and evaluating them in a safe order
1775 * by calling [evaluate] and [evaluateScc].
1776 *
1777 * This is an implementation of Tarjan's strongly connected
1778 * components algorithm
1779 * (https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_alg orithm).
1780 */
1781 void walk(NodeType startingPoint) {
1782 // TODO(paulberry): consider rewriting in a non-recursive way so
1783 // that long dependency chains don't cause stack overflow.
1784
1785 // TODO(paulberry): in the event that an exception occurs during
1786 // the walk, restore the state of the [Node] data structures so
1787 // that further evaluation will be safe.
1788
1789 // The index which will be assigned to the next node that is
1790 // freshly visited.
1791 int index = 1;
1792
1793 // Stack of nodes which have been seen so far and whose strongly
1794 // connected component is still being determined. Nodes are only
1795 // popped off the stack when they are evaluated, so sometimes the
1796 // stack contains nodes that were visited after the current node.
1797 List<NodeType> stack = <NodeType>[];
1798
1799 void strongConnect(NodeType node) {
1800 bool hasTrivialCycle = false;
1801
1802 // Assign the current node an index and add it to the stack. We
1803 // haven't seen any of its dependencies yet, so set its lowLink
1804 // to its index, indicating that so far it is the only node in
1805 // its strongly connected component.
1806 node.index = node.lowLink = index++;
1807 stack.add(node);
1808
1809 // Consider the node's dependencies one at a time.
1810 for (NodeType dependency in node.dependencies) {
1811 // If the dependency has already been evaluated, it can't be
1812 // part of this node's strongly connected component, so we can
1813 // skip it.
1814 if (dependency.isEvaluated) {
1815 continue;
1816 }
1817 if (identical(node, dependency)) {
1818 // If a node includes itself as a dependency, there is no need to
1819 // explore the dependency further.
1820 hasTrivialCycle = true;
1821 } else if (dependency.index == 0) {
1822 // The dependency hasn't been seen yet, so recurse on it.
1823 strongConnect(dependency);
1824 // If the dependency's lowLink refers to a node that was
1825 // visited before the current node, that means that the
1826 // current node, the dependency, and the node referred to by
1827 // the dependency's lowLink are all part of the same
1828 // strongly connected component, so we need to update the
1829 // current node's lowLink accordingly.
1830 if (dependency.lowLink < node.lowLink) {
1831 node.lowLink = dependency.lowLink;
1832 }
1833 } else {
1834 // The dependency has already been seen, so it is part of
1835 // the current node's strongly connected component. If it
1836 // was visited earlier than the current node's lowLink, then
1837 // it is a new addition to the current node's strongly
1838 // connected component, so we need to update the current
1839 // node's lowLink accordingly.
1840 if (dependency.index < node.lowLink) {
1841 node.lowLink = dependency.index;
1842 }
1843 }
1844 }
1845
1846 // If the current node's lowLink is the same as its index, then
1847 // we have finished visiting a strongly connected component, so
1848 // pop the stack and evaluate it before moving on.
1849 if (node.lowLink == node.index) {
1850 // The strongly connected component has only one node. If there is a
1851 // cycle, it's a trivial one.
1852 if (identical(stack.last, node)) {
1853 stack.removeLast();
1854 if (hasTrivialCycle) {
1855 evaluateScc(<NodeType>[node]);
1856 } else {
1857 evaluate(node);
1858 }
1859 } else {
1860 // There are multiple nodes in the strongly connected
1861 // component.
1862 List<NodeType> scc = <NodeType>[];
1863 while (true) {
1864 NodeType otherNode = stack.removeLast();
1865 scc.add(otherNode);
1866 if (identical(otherNode, node)) {
1867 break;
1868 }
1869 }
1870 evaluateScc(scc);
1871 }
1872 }
1873 }
1874
1875 // Kick off the algorithm starting with the starting point.
1876 strongConnect(startingPoint);
1877 }
1878 }
1879
1880 /**
1881 * Base class for executable elements resynthesized from a summary during 1756 * Base class for executable elements resynthesized from a summary during
1882 * linking. 1757 * linking.
1883 */ 1758 */
1884 abstract class ExecutableElementForLink extends Object 1759 abstract class ExecutableElementForLink extends Object
1885 with TypeParameterizedElementMixin, ParameterParentElementForLink 1760 with TypeParameterizedElementMixin, ParameterParentElementForLink
1886 implements ExecutableElementImpl { 1761 implements ExecutableElementImpl {
1887 /** 1762 /**
1888 * The unlinked representation of the method in the summary. 1763 * The unlinked representation of the method in the summary.
1889 */ 1764 */
1890 final UnlinkedExecutable _unlinkedExecutable; 1765 final UnlinkedExecutable _unlinkedExecutable;
(...skipping 1958 matching lines...) Expand 10 before | Expand all | Expand 10 after
3849 } 3724 }
3850 3725
3851 @override 3726 @override
3852 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); 3727 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
3853 3728
3854 @override 3729 @override
3855 String toString() => '$enclosingElement.$name'; 3730 String toString() => '$enclosingElement.$name';
3856 } 3731 }
3857 3732
3858 /** 3733 /**
3859 * Instances of [Node] represent nodes in a dependency graph. The
3860 * type parameter, [NodeType], is the derived type (this affords some
3861 * extra type safety by making it difficult to accidentally construct
3862 * bridges between unrelated dependency graphs).
3863 */
3864 abstract class Node<NodeType> {
3865 /**
3866 * Index used by Tarjan's strongly connected components algorithm.
3867 * Zero means the node has not been visited yet; a nonzero value
3868 * counts the order in which the node was visited.
3869 */
3870 int index = 0;
3871
3872 /**
3873 * Low link used by Tarjan's strongly connected components
3874 * algorithm. This represents the smallest [index] of all the nodes
3875 * in the strongly connected component to which this node belongs.
3876 */
3877 int lowLink = 0;
3878
3879 List<NodeType> _dependencies;
3880
3881 /**
3882 * Retrieve the dependencies of this node.
3883 */
3884 List<NodeType> get dependencies => _dependencies ??= computeDependencies();
3885
3886 /**
3887 * Indicates whether this node has been evaluated yet.
3888 */
3889 bool get isEvaluated;
3890
3891 /**
3892 * Compute the dependencies of this node.
3893 */
3894 List<NodeType> computeDependencies();
3895 }
3896
3897 /**
3898 * Element used for references that result from trying to access a non-static 3734 * Element used for references that result from trying to access a non-static
3899 * member of an element that is not a container (e.g. accessing the "length" 3735 * member of an element that is not a container (e.g. accessing the "length"
3900 * property of a constant). 3736 * property of a constant).
3901 * 3737 *
3902 * Accesses to a chain of non-static members separated by '.' are andled by 3738 * Accesses to a chain of non-static members separated by '.' are andled by
3903 * creating a [NonstaticMemberElementForLink] that points to another 3739 * creating a [NonstaticMemberElementForLink] that points to another
3904 * [NonstaticMemberElementForLink], to whatever nesting level is necessary. 3740 * [NonstaticMemberElementForLink], to whatever nesting level is necessary.
3905 */ 3741 */
3906 class NonstaticMemberElementForLink extends Object 3742 class NonstaticMemberElementForLink extends Object
3907 with ReferenceableElementForLink { 3743 with ReferenceableElementForLink {
(...skipping 1204 matching lines...) Expand 10 before | Expand all | Expand 10 after
5112 * there are no type parameters in scope. 4948 * there are no type parameters in scope.
5113 */ 4949 */
5114 TypeParameterizedElementMixin get _typeParameterContext; 4950 TypeParameterizedElementMixin get _typeParameterContext;
5115 4951
5116 @override 4952 @override
5117 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); 4953 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
5118 4954
5119 @override 4955 @override
5120 String toString() => '$enclosingElement.$name'; 4956 String toString() => '$enclosingElement.$name';
5121 } 4957 }
OLDNEW
« no previous file with comments | « no previous file | pkg/front_end/lib/src/dependency_walker.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698