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

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

Issue 1839863005: Clean up trivial cycle detection logic. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 months 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/analyzer/test/src/summary/summary_common.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 939 matching lines...) Expand 10 before | Expand all | Expand 10 after
950 // freshly visited. 950 // freshly visited.
951 int index = 1; 951 int index = 1;
952 952
953 // Stack of nodes which have been seen so far and whose strongly 953 // Stack of nodes which have been seen so far and whose strongly
954 // connected component is still being determined. Nodes are only 954 // connected component is still being determined. Nodes are only
955 // popped off the stack when they are evaluated, so sometimes the 955 // popped off the stack when they are evaluated, so sometimes the
956 // stack contains nodes that were visited after the current node. 956 // stack contains nodes that were visited after the current node.
957 List<NodeType> stack = <NodeType>[]; 957 List<NodeType> stack = <NodeType>[];
958 958
959 void strongConnect(NodeType node) { 959 void strongConnect(NodeType node) {
960 bool hasTrivialCycle = false;
961
960 // Assign the current node an index and add it to the stack. We 962 // Assign the current node an index and add it to the stack. We
961 // haven't seen any of its dependencies yet, so set its lowLink 963 // haven't seen any of its dependencies yet, so set its lowLink
962 // to its index, indicating that so far it is the only node in 964 // to its index, indicating that so far it is the only node in
963 // its strongly connected component. 965 // its strongly connected component.
964 node.index = node.lowLink = index++; 966 node.index = node.lowLink = index++;
965 stack.add(node); 967 stack.add(node);
966 968
967 // Consider the node's dependencies one at a time. 969 // Consider the node's dependencies one at a time.
968 for (NodeType dependency in node.dependencies) { 970 for (NodeType dependency in node.dependencies) {
969 // If the dependency has already been evaluated, it can't be 971 // If the dependency has already been evaluated, it can't be
970 // part of this node's strongly connected component, so we can 972 // part of this node's strongly connected component, so we can
971 // skip it. 973 // skip it.
972 if (dependency.isEvaluated) { 974 if (dependency.isEvaluated) {
973 continue; 975 continue;
974 } 976 }
975 if (dependency.index == 0) { 977 if (identical(node, dependency)) {
978 // If a node includes itself as a dependency, there is no need to
979 // explore the dependency further.
980 hasTrivialCycle = true;
981 } else if (dependency.index == 0) {
976 // The dependency hasn't been seen yet, so recurse on it. 982 // The dependency hasn't been seen yet, so recurse on it.
977 strongConnect(dependency); 983 strongConnect(dependency);
978 // If the dependency's lowLink refers to a node that was 984 // If the dependency's lowLink refers to a node that was
979 // visited before the current node, that means that the 985 // visited before the current node, that means that the
980 // current node, the dependency, and the node referred to by 986 // current node, the dependency, and the node referred to by
981 // the dependency's lowLink are all part of the same 987 // the dependency's lowLink are all part of the same
982 // strongly connected component, so we need to update the 988 // strongly connected component, so we need to update the
983 // current node's lowLink accordingly. 989 // current node's lowLink accordingly.
984 if (dependency.lowLink < node.lowLink) { 990 if (dependency.lowLink < node.lowLink) {
985 node.lowLink = dependency.lowLink; 991 node.lowLink = dependency.lowLink;
986 } 992 }
987 } else { 993 } else {
988 // The dependency has already been seen, so it is part of 994 // The dependency has already been seen, so it is part of
989 // the current node's strongly connected component. If it 995 // the current node's strongly connected component. If it
990 // was visited earlier than the current node's lowLink, then 996 // was visited earlier than the current node's lowLink, then
991 // it is a new addition to the current node's strongly 997 // it is a new addition to the current node's strongly
992 // connected component, so we need to update the current 998 // connected component, so we need to update the current
993 // node's lowLink accordingly. 999 // node's lowLink accordingly.
994 if (dependency.index < node.lowLink) { 1000 if (dependency.index < node.lowLink) {
995 node.lowLink = dependency.index; 1001 node.lowLink = dependency.index;
996 } 1002 }
997 } 1003 }
998 } 1004 }
999 1005
1000 // If the current node's lowLink is the same as its index, then 1006 // If the current node's lowLink is the same as its index, then
1001 // we have finished visiting a strongly connected component, so 1007 // we have finished visiting a strongly connected component, so
1002 // pop the stack and evaluate it before moving on. 1008 // pop the stack and evaluate it before moving on.
1003 if (node.lowLink == node.index) { 1009 if (node.lowLink == node.index) {
1004 // In the case where the strongly connected component has only 1010 // The strongly connected component has only one node. If there is a
1005 // one node, determine whether there is a trivial cycle or 1011 // cycle, it's a trivial one.
1006 // not.
1007 //
1008 // TODO(paulberry): could we figure this out in the for-loop
1009 // above and save some effort?
1010 if (identical(stack.last, node)) { 1012 if (identical(stack.last, node)) {
1011 stack.removeLast(); 1013 stack.removeLast();
1012 if (_hasTrivialScc(node)) { 1014 if (hasTrivialCycle) {
1013 evaluateScc(<NodeType>[node]); 1015 evaluateScc(<NodeType>[node]);
1014 } else { 1016 } else {
1015 evaluate(node); 1017 evaluate(node);
1016 } 1018 }
1017 } else { 1019 } else {
1018 // There are multiple nodes in the strongly connected 1020 // There are multiple nodes in the strongly connected
1019 // component. 1021 // component.
1020 List<NodeType> scc = <NodeType>[]; 1022 List<NodeType> scc = <NodeType>[];
1021 while (true) { 1023 while (true) {
1022 NodeType otherNode = stack.removeLast(); 1024 NodeType otherNode = stack.removeLast();
1023 scc.add(otherNode); 1025 scc.add(otherNode);
1024 if (identical(otherNode, node)) { 1026 if (identical(otherNode, node)) {
1025 break; 1027 break;
1026 } 1028 }
1027 } 1029 }
1028 evaluateScc(scc); 1030 evaluateScc(scc);
1029 } 1031 }
1030 } 1032 }
1031 } 1033 }
1032 1034
1033 // Kick off the algorithm starting with the starting point. 1035 // Kick off the algorithm starting with the starting point.
1034 strongConnect(startingPoint); 1036 strongConnect(startingPoint);
1035 } 1037 }
1036
1037 /**
1038 * The given [node] is in a strongly connected component of size 1.
1039 * Determine if it contains a trivial cycle (i.e. depends on
1040 * itself).
1041 */
1042 bool _hasTrivialScc(NodeType node) {
1043 for (NodeType dependency in node.dependencies) {
1044 if (identical(dependency, node)) {
1045 return true;
1046 }
1047 }
1048 return false;
1049 }
1050 } 1038 }
1051 1039
1052 /** 1040 /**
1053 * Representation of the dynamic type during linking. 1041 * Representation of the dynamic type during linking.
1054 */ 1042 */
1055 class DynamicTypeForLink extends DartTypeForLink { 1043 class DynamicTypeForLink extends DartTypeForLink {
1056 /** 1044 /**
1057 * Singleton instance of the dynamic type. 1045 * Singleton instance of the dynamic type.
1058 */ 1046 */
1059 static const DynamicTypeForLink instance = const DynamicTypeForLink._(); 1047 static const DynamicTypeForLink instance = const DynamicTypeForLink._();
(...skipping 569 matching lines...) Expand 10 before | Expand all | Expand 10 after
1629 1617
1630 /** 1618 /**
1631 * Throw away any information produced by a previous call to [link]. 1619 * Throw away any information produced by a previous call to [link].
1632 */ 1620 */
1633 void unlink() { 1621 void unlink() {
1634 for (LibraryElementInBuildUnit library in _librariesInBuildUnit) { 1622 for (LibraryElementInBuildUnit library in _librariesInBuildUnit) {
1635 library.unlink(); 1623 library.unlink();
1636 } 1624 }
1637 } 1625 }
1638 } 1626 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/src/summary/summary_common.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698