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

Side by Side Diff: compiler/java/com/google/dart/compiler/backend/js/analysis/TreeShaker.java

Issue 9479013: Remove backends. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 10 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
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.
4
5 package com.google.dart.compiler.backend.js.analysis;
6
7 import com.google.common.io.CharStreams;
8 import com.google.common.io.Closeables;
9 import com.google.dart.compiler.DartCompilerContext;
10 import com.google.dart.compiler.LibrarySource;
11
12 import org.mozilla.javascript.EvaluatorException;
13 import org.mozilla.javascript.Parser;
14 import org.mozilla.javascript.ast.AstNode;
15 import org.mozilla.javascript.ast.AstRoot;
16 import org.mozilla.javascript.ast.NodeVisitor;
17
18 import java.io.IOException;
19 import java.io.Reader;
20 import java.io.Writer;
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.LinkedHashSet;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27
28 /**
29 * A JavaScript tree shaker that is specialized for the output produced by
30 * dartc.
31 */
32 public class TreeShaker {
33 private static class VisitorIOException extends RuntimeException {
34 public VisitorIOException(IOException e) {
35 super(e);
36 }
37
38 @Override
39 public IOException getCause() {
40 return (IOException) super.getCause();
41 }
42 }
43
44 private static final class OutputFileWriter implements NodeVisitor {
45 private final Set<AstNode> nodesToEmit;
46 private final Writer outputFile;
47 private final Reader inputFile;
48 private long lastReadPosition = 0;
49 private long outputSize = 0;
50
51 private OutputFileWriter(Set<AstNode> nodesToEmit, Writer outputFile, Reader inputFile) {
52 this.nodesToEmit = nodesToEmit;
53 this.outputFile = outputFile;
54 this.inputFile = inputFile;
55 }
56
57 @Override
58 public boolean visit(AstNode node) {
59 if (node.getAstRoot() == node) {
60 return true;
61 }
62
63 try {
64 if (nodesToEmit.contains(node)) {
65 int nodePosition = node.getAbsolutePosition();
66 inputFile.skip(nodePosition - lastReadPosition);
67
68 char[] buffer = new char[node.getLength()];
69 int charsRead = inputFile.read(buffer);
70 assert (charsRead == buffer.length);
71 outputFile.write(buffer);
72 outputFile.write("\n");
73 outputSize += charsRead + 1;
74 lastReadPosition = nodePosition + node.getLength();
75 }
76 } catch (IOException e) {
77 throw new VisitorIOException(e);
78 }
79
80 return false;
81 }
82
83 public long getOutputSize() {
84 return outputSize;
85 }
86 }
87
88 private static final boolean DEBUG = false;
89
90 /**
91 * Returns the set of {@link AstNode}s that should be emitted into the final
92 * JS code.
93 */
94 private static Set<AstNode> computeNodesToEmit(AstRoot root) {
95 List<AstNode> globals = new ArrayList<AstNode>();
96 Map<String, List<JavascriptElement>> namesToElements =
97 new HashMap<String, List<JavascriptElement>>();
98 TopLevelElementIndexer declVisitor = new TopLevelElementIndexer(namesToEleme nts, globals);
99 root.visit(declVisitor);
100
101 if (DEBUG) {
102 TopLevelElementIndexer.printNamesToElements(namesToElements);
103 TopLevelElementIndexer.printGlobals(globals);
104 }
105
106 List<AstNode> worklist = new ArrayList<AstNode>();
107 for (AstNode global : globals) {
108 worklist.add(global);
109 }
110
111 worklist.addAll(declVisitor.getEntryPoints());
112 DependencyComputer dependencyComputer = new DependencyComputer(namesToElemen ts);
113 final Set<AstNode> nodesProcessed = new LinkedHashSet<AstNode>();
114 while (!worklist.isEmpty()) {
115 AstNode node = worklist.remove(worklist.size() - 1);
116 if (!nodesProcessed.add(node)) {
117 continue;
118 }
119
120 if (DEBUG) {
121 try {
122 System.out.println(node.toSource());
123 System.out.println("Dependencies:");
124 } catch (Exception e) {
125 // Ignore exceptions thrown by rhino's toSource method...
126 }
127 }
128
129 List<JavascriptElement> dependencies = dependencyComputer.computeDependenc ies(node);
130 for (JavascriptElement dependency : dependencies) {
131 if (dependency.isNative() || nodesProcessed.contains(dependency.getNode( ))) {
132 // Skip natives since they don't have a node in the AST
133 continue;
134 }
135
136 if (DEBUG) {
137 System.out.println("\t" + dependency.getQualifiedName());
138 }
139
140 worklist.add(dependency.getNode());
141 }
142 }
143 return nodesProcessed;
144 }
145
146 /**
147 * Reduce the input JS file by following the conservative "call graph" and
148 * pruning dead code.
149 */
150 public static long reduce(LibrarySource app, DartCompilerContext context,
151 String completeArtifactName, Writer outputFile) throws IOException {
152 Reader inputFile = context.getArtifactReader(app, "", completeArtifactName);
153 // Mark beyond the expected length so we can reset back to zero
154 AstRoot root = null;
155 boolean failed = true;
156 try {
157 Parser parser = new Parser();
158 root = parser.parse(inputFile, "", 1);
159 failed = false;
160 } catch (EvaluatorException e) {
161 /*
162 * This can happen if we generate bad JS code. For example, the negative
163 * tests may cause invalid control flow constructs to be generated. In
164 * this case we will swallow the exception and simply copy the input file
165 * to the output file.
166 */
167 Closeables.close(inputFile, failed);
168 inputFile = context.getArtifactReader(app, "", completeArtifactName);
169 return CharStreams.copy(inputFile, outputFile);
170 } finally {
171 Closeables.close(inputFile, failed);
172 }
173
174 final Set<AstNode> nodesProcessed = computeNodesToEmit(root);
175
176 // Need to get a new reader since we don't cache the stream
177 failed = true;
178 inputFile = context.getArtifactReader(app, "", completeArtifactName);
179 OutputFileWriter outputFileWriter =
180 new OutputFileWriter(nodesProcessed, outputFile, inputFile);
181 try {
182 root.visit(outputFileWriter);
183 failed = false;
184 return outputFileWriter.getOutputSize();
185 } catch (VisitorIOException e) {
186 throw e.getCause();
187 } finally {
188 Closeables.close(inputFile, failed);
189 }
190 }
191 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698