| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |