Skip to content
This repository has been archived by the owner on Aug 11, 2021. It is now read-only.

Commit

Permalink
include fields in verify_deps, refactor graph dfs
Browse files Browse the repository at this point in the history
BUG=
R=sigmund@google.com

Review URL: https://codereview.chromium.org//1412903002 .
  • Loading branch information
harryterkelsen committed Oct 19, 2015
1 parent a6bdb61 commit 0eb54e7
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 29 deletions.
4 changes: 2 additions & 2 deletions bin/function_size_analysis.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ showCodeDistribution(AllInfo info,
// Compute a graph from the dependencies in [info].
Graph<Info> graph = graphFromInfo(info);

// Compute the strongest connected components and calculate their size.
// Compute the strongly connected components and calculate their size.
var components = graph.computeTopologicalSort();
print('total elements: ${graph.nodes.length}');
print('total strongest connected components: ${components.length}');
print('total strongly connected components: ${components.length}');
var maxS = 0;
var totalCount = graph.nodeCount;
var minS = totalCount;
Expand Down
19 changes: 6 additions & 13 deletions bin/verify_deps.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,20 @@ Future main(List<String> args) async {
var entrypoint = info.program.entrypoint;
var reachables = findReachable(graph, entrypoint);

var unreachables = info.functions.where((func) => !reachables.contains(func));
var functionsAndFields = []..addAll(info.functions)..addAll(info.fields);
var unreachables =
functionsAndFields.where((func) => !reachables.contains(func));
if (unreachables.isNotEmpty) {
unreachables.forEach(print);
unreachables.forEach((x) => print(longName(x)));
exit(1);
} else {
print('all elements are reachable from the entrypoint');
}
}

/// Finds the set of nodes reachable from [start] in [graph].
Set<Info> findReachable(Graph<Info> graph, Info start) {
var visited = new Set<Info>();
var stack = <Info>[start];
while (stack.isNotEmpty) {
var next = stack.removeLast();
visited.add(next);
stack.addAll(
graph.targetsOf(next).where((target) => !visited.contains(target)));
}
return visited;
}
Set<Info> findReachable(Graph<Info> graph, Info start) =>
new Set.from(graph.preOrder(start));

void printUsage() {
print('usage: dart2js_info_verify_deps <info file>');
Expand Down
38 changes: 26 additions & 12 deletions lib/src/graph.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.

/// A library to work with graphs. It contains a couple algorithms, including
/// Tarjan's algorithm to compute strongest connected components in a graph and
/// Tarjan's algorithm to compute strongly connected components in a graph and
/// Cooper et al's dominator algorithm.
///
/// Portions of the code in this library was adapted from
Expand Down Expand Up @@ -41,21 +41,35 @@ abstract class Graph<N> {
}

/// Returns all nodes reachable from [root] in post order.
List<N> postOrder(N root) {
Iterable<N> postOrder(N root) sync* {
var seen = new Set<N>();
var result = <N>[];
helper(n) {
Iterable<N> helper(n) sync* {
if (!seen.add(n)) return;
targetsOf(n).forEach(helper);
result.add(n);
for (var x in targetsOf(n)) {
yield* helper(x);
}
yield n;
}
yield* helper(root);
}

/// Returns an iterable of all nodes reachable from [root] in preorder.
Iterable<N> preOrder(N root) sync* {
var seen = new Set<N>();
var stack = <N>[root];
while (stack.isNotEmpty) {
var next = stack.removeLast();
if (!seen.contains(next)) {
seen.add(next);
yield next;
stack.addAll(targetsOf(next));
}
}
helper(root);
return result;
}

/// Return a list of nodes that form a cycle containing the given node. If the
/// node is not part of a cycle in this graph, then a list containing only the
/// node itself will be returned.
/// Returns a list of nodes that form a cycle containing the given node. If
/// the node is not part of a cycle in this graph, then a list containing only
/// the node itself will be returned.
List<N> findCycleContaining(N node) {
assert(node != null);
_SccFinder<N> finder = new _SccFinder<N>(this);
Expand Down Expand Up @@ -273,7 +287,7 @@ class _DominatorFinder<N> {
immediateDominators[root] = root;
bool changed = true;
int i = 0;
var nodesInPostOrder = _graph.postOrder(root);
var nodesInPostOrder = _graph.postOrder(root).toList();
for (var n in nodesInPostOrder) {
postOrderId[n] = i++;
}
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: dart2js_info
version: 0.2.0
version: 0.2.0+1
description: >
Libraries and tools to process data produced when running dart2js with
--dump-info.
Expand Down
73 changes: 73 additions & 0 deletions test/graph_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:dart2js_info/src/graph.dart';
import 'package:test/test.dart';

main() {
var graph = makeTestGraph();

test('preorder traversal', () {
expect(graph.preOrder('A').toList(), equals(['A', 'E', 'D', 'C', 'B']));
});

test('postorder traversal', () {
expect(graph.postOrder('A').toList(), equals(['C', 'E', 'D', 'B', 'A']));
});

test('topological sort', () {
expect(
graph.computeTopologicalSort(),
equals([
['C'],
['E'],
['D', 'B', 'A']
]));
});

test('contains path', () {
expect(graph.containsPath('A', 'C'), isTrue);
expect(graph.containsPath('B', 'E'), isTrue);
expect(graph.containsPath('C', 'A'), isFalse);
expect(graph.containsPath('E', 'B'), isFalse);
});

test('dominator tree', () {
// A dominates all other nodes in the graph, the resulting tree looks like
// A
// / / | |
// B C D E
var dom = graph.dominatorTree('A');
expect(dom.targetsOf('A').length, equals(4));
});

test('cycle finding', () {
expect(graph.findCycleContaining('B'), equals(['A', 'D', 'B']));
expect(graph.findCycleContaining('C'), equals(['C']));
});
}

/// Creates a simple test graph with the following structure:
/// ```
/// A -> E
/// / ^ ^
/// / \ /
/// v v /
/// B -> D
/// \ /
/// v v
/// C
/// ```
Graph<String> makeTestGraph() {
var graph = new EdgeListGraph<String>();
graph.addEdge('A', 'B');
graph.addEdge('A', 'D');
graph.addEdge('A', 'E');
graph.addEdge('B', 'C');
graph.addEdge('B', 'D');
graph.addEdge('D', 'A');
graph.addEdge('D', 'C');
graph.addEdge('D', 'E');
return graph;
}
1 change: 0 additions & 1 deletion test/all_test.dart → test/parse_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import 'package:dart2js_info/info.dart';
import 'package:test/test.dart';

main() {
// TODO(sigmund): add more tests
group('parse', () {
test('empty', () {
var json = {
Expand Down

0 comments on commit 0eb54e7

Please sign in to comment.