Author: [email protected]
Date: Mon Jul 6 15:03:31 2009
New Revision: 5676
Modified:
trunk/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java
trunk/dev/core/src/com/google/gwt/core/ext/soyc/impl/SplitPointRecorder.java
trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
trunk/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java
trunk/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
trunk/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java
Log:
Has SOYC show dependency information for all of the dependency
graphs built and used by the code splitter. Thus, it is possible
to debug why code ends up in any of the code fragments the
compiler emits.
Review by: kprobst
Modified:
trunk/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java
==============================================================================
---
trunk/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java
(original)
+++
trunk/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java
Mon Jul 6 15:03:31 2009
@@ -16,51 +16,91 @@
package com.google.gwt.core.ext.soyc.impl;
import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.impl.CodeSplitter;
import com.google.gwt.dev.jjs.impl.ControlFlowAnalyzer;
+import
com.google.gwt.dev.jjs.impl.CodeSplitter.MultipleDependencyGraphRecorder;
import com.google.gwt.util.tools.Utility;
+import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.zip.GZIPOutputStream;
/**
* The control-flow dependency recorder for SOYC.
*/
-public class DependencyRecorder implements
- ControlFlowAnalyzer.DependencyRecorder {
-
+public class DependencyRecorder implements MultipleDependencyGraphRecorder
{
/**
- * Used to record dependencies of a program.
- */
- public static void recordDependencies(TreeLogger logger, OutputStream
out,
- JProgram jprogram) {
- new DependencyRecorder().recordDependenciesImpl(logger, out, jprogram);
+ * DependencyRecorder is not allowed to throw checked exceptions,
because if
+ * it did then {...@link CodeSplitter} and {...@link ControlFlowAnalyzer}
would
+ * throw exceptions all over the place. Instead, this class throws
+ * NestedIOExceptions that wrap them.
+ */
+ public static class NestedIOException extends RuntimeException {
+ public NestedIOException(IOException e) {
+ super(e);
+ }
+ }
+
+ private final StringBuilder builder = new StringBuilder();
+ private OutputStreamWriter writer;
+
+ public DependencyRecorder(OutputStream out) throws IOException {
+ try {
+ this.writer = new OutputStreamWriter(new
GZIPOutputStream(out), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new InternalCompilerException("UTF-8 is an unsupported
encoding", e);
+ }
}
- private StringBuilder builder;
+ public void close() {
+ printPost();
+ flushOutput();
+ try {
+ writer.close();
+ } catch (IOException e) {
+ throw new NestedIOException(e);
+ }
+ }
- private DependencyRecorder() {
+ public void endDependencyGraph() {
+ builder.append("</table>");
+ flushOutput();
}
/**
* Used to record the dependencies of a specific method.
- *
- * @param liveMethod
- * @param dependencyChain
*/
public void methodIsLiveBecause(JMethod liveMethod,
ArrayList<JMethod> dependencyChain) {
printMethodDependency(dependencyChain);
}
+ public void open() {
+ printPre();
+ }
+
+ public void startDependencyGraph(String identifier, String extnds) {
+ builder.append("<table name=\"");
+ builder.append(identifier);
+ builder.append("\"");
+ if (extnds != null) {
+ builder.append(" extends=\"");
+ builder.append(extnds);
+ builder.append("\"");
+ }
+ builder.append(">\n");
+ }
+
/**
* Used to record dependencies of a program.
*/
- protected void recordDependenciesImpl(TreeLogger logger, OutputStream
out,
- JProgram jprogram) {
+ protected void recordDependenciesImpl(TreeLogger logger, JProgram
jprogram) {
logger = logger.branch(TreeLogger.INFO,
"Creating Dependencies file for SOYC");
@@ -69,23 +109,14 @@
dependencyAnalyzer.setDependencyRecorder(this);
try {
- OutputStreamWriter writer
- = new OutputStreamWriter(new GZIPOutputStream(out), "UTF-8");
-
- StringBuilder localBuilder = new StringBuilder();
- this.builder = localBuilder;
-
printPre();
for (JMethod method : jprogram.getAllEntryMethods()) {
dependencyAnalyzer.traverseFrom(method);
- if (localBuilder.length() > 8 * 1024) {
- writer.write(localBuilder.toString());
- localBuilder.setLength(0);
- }
+ maybeFlushOutput();
}
printPost();
- writer.write(localBuilder.toString());
+ writer.write(builder.toString());
Utility.close(writer);
logger.log(TreeLogger.INFO, "Done");
@@ -94,18 +125,33 @@
}
}
+ private void flushOutput() {
+ try {
+ writer.write(builder.toString());
+ } catch (IOException e) {
+ throw new NestedIOException(e);
+ }
+ builder.setLength(0);
+ }
+
+ private void maybeFlushOutput() throws IOException {
+ if (builder.length() > 8 * 1024) {
+ flushOutput();
+ }
+ }
+
/**
- * Prints the control-flow dependencies to a file in a specific format.
- *
- * @param liveMethod
- * @param dependencyChain
+ * Records one dependency chain to a file. More specifically, it records
the
+ * last link of the dependency chain. The full dependency chain can be
+ * recovered by code that reads the entire dependencies file, because it
can
+ * do repeated lookups into the dependencies table to follow the chain.
*/
private void printMethodDependency(ArrayList<JMethod> dependencyChain) {
int size = dependencyChain.size();
- if (size == 0) {
+ if (size < 2) {
return;
}
-
+
JMethod curMethod = dependencyChain.get(size - 1);
builder.append("<method name=\"");
if (curMethod.getEnclosingType() != null) {
@@ -115,16 +161,14 @@
builder.append(curMethod.getName());
builder.append("\">\n");
- for (int i = size - 2; i >= 0; i--) {
- curMethod = dependencyChain.get(i);
- builder.append("<called by=\"");
- if (curMethod.getEnclosingType() != null) {
- builder.append(curMethod.getEnclosingType().getName());
- builder.append("::");
- }
- builder.append(curMethod.getName());
- builder.append("\"/>\n");
+ JMethod depMethod = dependencyChain.get(size - 2);
+ builder.append("<called by=\"");
+ if (depMethod.getEnclosingType() != null) {
+ builder.append(depMethod.getEnclosingType().getName());
+ builder.append("::");
}
+ builder.append(depMethod.getName());
+ builder.append("\"/>\n");
builder.append("</method>\n");
}
@@ -139,7 +183,6 @@
* Prints the preamble necessary for the dependencies file.
*/
private void printPre() {
- builder.append(
- "<?xml version=\"1.0\"
encoding=\"UTF-8\"?>\n<soyc-dependencies>\n");
+ builder.append("<?xml version=\"1.0\"
encoding=\"UTF-8\"?>\n<soyc-dependencies>\n");
}
}
Modified:
trunk/dev/core/src/com/google/gwt/core/ext/soyc/impl/SplitPointRecorder.java
==============================================================================
---
trunk/dev/core/src/com/google/gwt/core/ext/soyc/impl/SplitPointRecorder.java
(original)
+++
trunk/dev/core/src/com/google/gwt/core/ext/soyc/impl/SplitPointRecorder.java
Mon Jul 6 15:03:31 2009
@@ -80,6 +80,24 @@
htmlOut.printRaw(curLine);
htmlOut.newline();
}
+
+ if (!jprogram.getSplitPointInitialSequence().isEmpty()) {
+ curLine = "<initialseq>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ htmlOut.indentIn();
+
+ for (int sp : jprogram.getSplitPointInitialSequence()) {
+ curLine = "<splitpointref id=\"" + sp + "\"/>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
+
+ htmlOut.indentOut();
+ curLine = "</initialseq>";
+ htmlOut.printRaw(curLine);
+ htmlOut.newline();
+ }
htmlOut.indentOut();
htmlOut.indentOut();
Modified:
trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
==============================================================================
--- trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
(original)
+++ trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
Mon Jul 6 15:03:31 2009
@@ -82,6 +82,7 @@
import com.google.gwt.dev.jjs.impl.SourceGenerationVisitor;
import com.google.gwt.dev.jjs.impl.TypeMap;
import com.google.gwt.dev.jjs.impl.TypeTightener;
+import
com.google.gwt.dev.jjs.impl.CodeSplitter.MultipleDependencyGraphRecorder;
import com.google.gwt.dev.js.EvalFunctionsAtTopScope;
import com.google.gwt.dev.js.JsBreakUpLargeVarStatements;
import com.google.gwt.dev.js.JsIEBlockSizeVisitor;
@@ -115,6 +116,7 @@
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -292,8 +294,15 @@
stringLiteralMap);
// (10.5) Split up the program into fragments
+ SoycArtifact dependencies = null;
if (options.isAggressivelyOptimize() && options.isRunAsyncEnabled())
{
- CodeSplitter.exec(logger, jprogram, jsProgram,
postStringInterningMap);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CodeSplitter.exec(logger, jprogram, jsProgram,
postStringInterningMap,
+ chooseDependencyRecorder(options.isSoycEnabled(), baos));
+ if (baos.size() > 0) {
+ dependencies = new SoycArtifact("dependencies" + permutationId
+ + ".xml.gz", baos.toByteArray());
+ }
}
// (11) Perform any post-obfuscation normalizations.
@@ -331,7 +340,7 @@
makeSymbolMap(symbolTable), ranges, permutationId);
toReturn.getArtifacts().add(
- makeSoycArtifact(logger, permutationId, jprogram, js,
sourceInfoMaps));
+ makeSoycArtifact(logger, permutationId, jprogram, js,
sourceInfoMaps, dependencies));
System.out.println("Permutation took "
+ (System.currentTimeMillis() - permStart) + " ms");
@@ -697,6 +706,15 @@
}
}
+ private static MultipleDependencyGraphRecorder chooseDependencyRecorder(
+ boolean soycEnabled, OutputStream out) throws IOException {
+ MultipleDependencyGraphRecorder dependencyRecorder =
CodeSplitter.NULL_RECORDER;
+ if (soycEnabled) {
+ dependencyRecorder = new DependencyRecorder(out);
+ }
+ return dependencyRecorder;
+ }
+
private static JMethodCall createReboundModuleLoad(TreeLogger logger,
JDeclaredType reboundEntryType, String originalMainClassName)
throws UnableToCompleteException {
@@ -874,7 +892,7 @@
private static StandardCompilationAnalysis makeSoycArtifact(
TreeLogger logger, int permutationId, JProgram jprogram, String[] js,
- List<Map<Range, SourceInfo>> sourceInfoMaps) {
+ List<Map<Range, SourceInfo>> sourceInfoMaps, SoycArtifact
dependencies) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PerfLogger.start("Computing SOYC output");
@@ -886,7 +904,6 @@
PerfLogger.end();
SoycArtifact stories = null;
- SoycArtifact dependencies = null;
if (sourceInfoMaps != null) {
PerfLogger.start("Record stories");
@@ -894,13 +911,6 @@
StoryRecorder.recordStories(logger, baos, sourceInfoMaps, js);
stories = new SoycArtifact("stories" + permutationId + ".xml.gz",
baos.toByteArray());
- PerfLogger.end();
-
- PerfLogger.start("Record dependencies");
- baos.reset();
- DependencyRecorder.recordDependencies(logger, baos, jprogram);
- dependencies = new SoycArtifact("dependencies" + permutationId
- + ".xml.gz", baos.toByteArray());
PerfLogger.end();
}
Modified: trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
==============================================================================
--- trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
(original)
+++ trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java Mon
Jul 6 15:03:31 2009
@@ -36,6 +36,7 @@
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JStringLiteral;
import com.google.gwt.dev.jjs.ast.JVisitor;
+import com.google.gwt.dev.jjs.impl.ControlFlowAnalyzer.DependencyRecorder;
import com.google.gwt.dev.jjs.impl.FragmentExtractor.CfaLivenessPredicate;
import com.google.gwt.dev.jjs.impl.FragmentExtractor.LivenessPredicate;
import com.google.gwt.dev.jjs.impl.FragmentExtractor.NothingAlivePredicate;
@@ -96,6 +97,31 @@
*/
public class CodeSplitter {
/**
+ * A dependency recorder that can record multiple dependency graphs. It
has
+ * methods for starting and finishing new dependency graphs.
+ */
+ public interface MultipleDependencyGraphRecorder extends
DependencyRecorder {
+ /**
+ * Stop recording dependencies.
+ */
+ void close();
+
+ /**
+ * Stop recording the current dependency graph.
+ */
+ void endDependencyGraph();
+
+ void open();
+
+ /**
+ * Start a new dependency graph. It can be an extension of a previously
+ * recorded dependency graph, in which case the dependencies in the
previous
+ * graph will not be repeated.
+ */
+ void startDependencyGraph(String name, String extnds);
+ }
+
+ /**
* A statement logger that immediately prints out everything live that it
* sees.
*/
@@ -191,6 +217,27 @@
}
}
+ /**
+ * A {...@link MultipleDependencyGraphRecorder} that does nothing.
+ */
+ public static final MultipleDependencyGraphRecorder NULL_RECORDER = new
MultipleDependencyGraphRecorder() {
+ public void close() {
+ }
+
+ public void endDependencyGraph() {
+ }
+
+ public void methodIsLiveBecause(JMethod liveMethod,
+ ArrayList<JMethod> dependencyChain) {
+ }
+
+ public void open() {
+ }
+
+ public void startDependencyGraph(String name, String extnds) {
+ }
+ };
+
private static final String PROP_INITIAL_SEQUENCE
= "compiler.splitpoint.initial.sequence";
/**
@@ -198,24 +245,21 @@
*/
private static String PROP_LOG_FRAGMENT_MAP = "gwt.jjs.logFragmentMap";
- /**
- * Compute the set of initially live code for this program. Such code
must be
- * included in the initial download of the program.
- */
public static ControlFlowAnalyzer computeInitiallyLive(JProgram
jprogram) {
- ControlFlowAnalyzer cfa = new ControlFlowAnalyzer(jprogram);
- traverseEntry(jprogram, cfa, 0);
- return cfa;
+ return computeInitiallyLive(jprogram, NULL_RECORDER);
}
public static void exec(TreeLogger logger, JProgram jprogram,
- JsProgram jsprogram, JavaToJavaScriptMap map) {
+ JsProgram jsprogram, JavaToJavaScriptMap map,
+ MultipleDependencyGraphRecorder dependencyRecorder) {
if (jprogram.entryMethods.size() == 1) {
// Don't do anything if there is no call to runAsync
return;
}
- new CodeSplitter(logger, jprogram, jsprogram, map).execImpl();
+ dependencyRecorder.open();
+ new CodeSplitter(logger, jprogram, jsprogram, map,
dependencyRecorder).execImpl();
+ dependencyRecorder.close();
}
public static int getExclusiveFragmentNumber(int splitPoint,
@@ -338,6 +382,22 @@
}
/**
+ * Compute the set of initially live code for this program. Such code
must be
+ * included in the initial download of the program.
+ */
+ private static ControlFlowAnalyzer computeInitiallyLive(JProgram
jprogram,
+ MultipleDependencyGraphRecorder dependencyRecorder) {
+ dependencyRecorder.startDependencyGraph("initial", null);
+
+ ControlFlowAnalyzer cfa = new ControlFlowAnalyzer(jprogram);
+ cfa.setDependencyRecorder(dependencyRecorder);
+ traverseEntry(jprogram, cfa, 0);
+
+ dependencyRecorder.endDependencyGraph();
+ return cfa;
+ }
+
+ /**
* Find a split point as designated in the {...@link #PROP_INITIAL_SEQUENCE}
* configuration property.
*
@@ -425,6 +485,10 @@
program, info, program.getTypeArray(JPrimitiveType.INT, 1),
intExprs);
}
+ private static <T> T last(T[] array) {
+ return array[array.length - 1];
+ }
+
private static void logInitialLoadSequence(TreeLogger logger,
LinkedHashSet<Integer> initialLoadSequence) {
StringBuffer message = new StringBuffer();
@@ -507,6 +571,8 @@
}
}
+ private final MultipleDependencyGraphRecorder dependencyRecorder;
+
private final Map<JField, JClassLiteral> fieldToLiteralOfClass;
private final FragmentExtractor fragmentExtractor;
private final LinkedHashSet<Integer> initialLoadSequence;
@@ -530,12 +596,14 @@
private final int numEntries;
private CodeSplitter(TreeLogger logger, JProgram jprogram,
- JsProgram jsprogram, JavaToJavaScriptMap map) {
+ JsProgram jsprogram, JavaToJavaScriptMap map,
+ MultipleDependencyGraphRecorder dependencyRecorder) {
this.logger = logger.branch(TreeLogger.TRACE,
"Splitting JavaScript for incremental download");
this.jprogram = jprogram;
this.jsprogram = jsprogram;
this.map = map;
+ this.dependencyRecorder = dependencyRecorder;
this.initialLoadSequence = new LinkedHashSet<Integer>(
jprogram.getSplitPointInitialSequence());
@@ -544,7 +612,7 @@
fieldToLiteralOfClass = buildFieldToClassLiteralMap(jprogram);
fragmentExtractor = new FragmentExtractor(jprogram, jsprogram, map);
- initiallyLive = computeInitiallyLive(jprogram);
+ initiallyLive = computeInitiallyLive(jprogram, dependencyRecorder);
methodsInJavaScript = fragmentExtractor.findAllMethodsInJavaScript();
}
@@ -582,6 +650,8 @@
* initial load sequence, add a <code>null</code> to the list.
*/
private List<ControlFlowAnalyzer> computeAllButOneCfas() {
+ String dependencyGraphNameAfterInitialSequence =
dependencyGraphNameAfterInitialSequence();
+
List<ControlFlowAnalyzer> allButOnes = new
ArrayList<ControlFlowAnalyzer>(
numEntries - 1);
@@ -590,12 +660,16 @@
allButOnes.add(null);
continue;
}
+ dependencyRecorder.startDependencyGraph("sp" + entry,
+ dependencyGraphNameAfterInitialSequence);
ControlFlowAnalyzer cfa = new ControlFlowAnalyzer(
liveAfterInitialSequence);
+ cfa.setDependencyRecorder(dependencyRecorder);
traverseAllButEntry(cfa, entry);
// Traverse leftoversFragmentHasLoaded, because it should not
// go into any of the exclusive fragments.
cfa.traverseFromLeftoversFragmentHasLoaded();
+ dependencyRecorder.endDependencyGraph();
allButOnes.add(cfa);
}
@@ -606,15 +680,30 @@
* Compute a CFA that covers the entire live code of the program.
*/
private ControlFlowAnalyzer computeCompleteCfa() {
+ dependencyRecorder.startDependencyGraph("total", null);
ControlFlowAnalyzer everything = new ControlFlowAnalyzer(jprogram);
+ everything.setDependencyRecorder(dependencyRecorder);
for (int entry = 0; entry < numEntries; entry++) {
traverseEntry(everything, entry);
}
everything.traverseFromLeftoversFragmentHasLoaded();
+ dependencyRecorder.endDependencyGraph();
return everything;
}
/**
+ * The name of the dependency graph that corresponds to
+ * {...@link #liveAfterInitialSequence}.
+ */
+ private String dependencyGraphNameAfterInitialSequence() {
+ if (initialLoadSequence.isEmpty()) {
+ return "initial";
+ } else {
+ return "sp" + last(initialLoadSequence.toArray());
+ }
+ }
+
+ /**
* Map each program atom as exclusive to some split point, whenever
possible.
* Also fixes up load order problems that could result from splitting
code
* based on this assumption.
@@ -648,13 +737,19 @@
* sequence.
*/
liveAfterInitialSequence = new ControlFlowAnalyzer(initiallyLive);
+ String extendsCfa = "initial";
for (int sp : initialLoadSequence) {
LivenessPredicate alreadyLoaded = new CfaLivenessPredicate(
liveAfterInitialSequence);
+ String depGraphName = "sp" + sp;
+ dependencyRecorder.startDependencyGraph(depGraphName, extendsCfa);
+ extendsCfa = depGraphName;
ControlFlowAnalyzer liveAfterSp = new ControlFlowAnalyzer(
liveAfterInitialSequence);
traverseEntry(liveAfterSp, sp);
+ dependencyRecorder.endDependencyGraph();
+
LivenessPredicate liveNow = new CfaLivenessPredicate(liveAfterSp);
List<JsStatement> statsToAppend =
fragmentExtractor.createCallsToEntryMethods(sp);
Modified:
trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
==============================================================================
--- trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
(original)
+++ trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
Mon Jul 6 15:03:31 2009
@@ -74,7 +74,6 @@
* See {...@link
ControlFlowAnalyzer#setDependencyRecorder(DependencyRecorder)}.
*/
public interface DependencyRecorder {
-
/**
* Used to record the dependencies of a specific method.
*/
Modified:
trunk/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java
==============================================================================
--- trunk/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java
(original)
+++ trunk/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java Mon
Jul 6 15:03:31 2009
@@ -46,6 +46,8 @@
public static Map<String, TreeSet<String>> packageToClasses = new
TreeMap<String, TreeSet<String>>();
public static HashMap<Integer, String> splitPointToLocation = new
HashMap<Integer, String>();
+ public static ArrayList<Integer> splitPointInitialLoadSequence = new
ArrayList<Integer>();
+
public static HashMap<String, HashSet<String>> storiesToCorrClasses =
new HashMap<String, HashSet<String>>();
public static HashMap<String, HashSet<String>>
storiesToCorrClassesAndMethods = new HashMap<String, HashSet<String>>();
@@ -56,8 +58,7 @@
public static SizeBreakdown initialCodeBreakdown = new SizeBreakdown(
"Initially downloaded code", "initial");
public static SizeBreakdown leftoversBreakdown = new SizeBreakdown(
- "Leftovers code, neither initial nor exclusive to any split point",
- "leftovers");
+ "Leftovers code, code not in any other category", "leftovers");
public static SizeBreakdown totalCodeBreakdown = new SizeBreakdown(
"Total program", "total");
private static Map<Integer, SizeBreakdown> exclusiveCodeBreakdowns = new
HashMap<Integer, SizeBreakdown>();
@@ -69,7 +70,7 @@
if (numSplitPoints > 0) {
breakdowns.add(leftoversBreakdown);
for (int sp = 1; sp <= numSplitPoints; sp++) {
- breakdowns.add(exclusiveCodeBreakdown(sp));
+ breakdowns.add(splitPointCodeBreakdown(sp));
}
}
return breakdowns.toArray(EMPTY_SIZE_BREAKDOWN);
@@ -88,7 +89,7 @@
}
}
- public static SizeBreakdown exclusiveCodeBreakdown(int sp) {
+ public static SizeBreakdown splitPointCodeBreakdown(int sp) {
assert sp >= 1 && sp <= numSplitPoints;
if (!exclusiveCodeBreakdowns.containsKey(sp)) {
exclusiveCodeBreakdowns.put(sp, new SizeBreakdown("split point " + sp
Modified:
trunk/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
==============================================================================
---
trunk/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
(original)
+++
trunk/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
Mon Jul 6 15:03:31 2009
@@ -30,16 +30,49 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* A utility to make the top level HTTML file for one permutation.
*/
public class MakeTopLevelHtmlForPerm {
+ public class DependencyLinkerForExclusiveFragment implements
DependencyLinker {
+ public String dependencyLinkForClass(String className) {
+ return null;
+ }
+ }
+
+ public class DependencyLinkerForInitialCode implements DependencyLinker {
+ public String dependencyLinkForClass(String className) {
+ String packageName = GlobalInformation.classToPackage.get(className);
+ assert packageName != null;
+ return dependenciesFileName("initial", packageName) + "#" +
className;
+ }
+ }
+
+ public class DependencyLinkerForLeftoversFragment implements
DependencyLinker {
+ public String dependencyLinkForClass(String className) {
+ return leftoversStatusFileName(className);
+ }
+ }
+
+ public class DependencyLinkerForTotalBreakdown implements
DependencyLinker {
+ public String dependencyLinkForClass(String className) {
+ return splitStatusFileName(className);
+ }
+ }
+
+ interface DependencyLinker {
+ String dependencyLinkForClass(String className);
+ }
+
/**
* By a convention shared with the compiler, the initial download is
fragment
* number 0.
@@ -52,6 +85,14 @@
*/
private static final int FRAGMENT_NUMBER_TOTAL_PROGRAM = -1;
+ /**
+ * A pattern describing the name of dependency graphs for code fragments
+ * corresponding to a specific split point. These can be either exclusive
+ * fragments or fragments of code for split points in the initial load
+ * sequence.
+ */
+ private static final Pattern PATTERN_SP_INT =
Pattern.compile("sp([0-9]+)");
+
public static void copyFileOrDirectory(File srcPath, File dstPath,
String classPath, String inputFileName, boolean isDirectory)
throws IOException {
@@ -130,15 +171,18 @@
return escaped;
}
+ private static void addCenteredHeader(final PrintWriter outFile, String
header) {
+ outFile.println("<hr>");
+ outFile.println("<b>" + header + "</b>");
+ outFile.println("<hr>");
+ }
+
/**
* Adds a header line indicating which breakdown is being analyzed.
*/
private static void addHeaderWithBreakdownContext(SizeBreakdown
breakdown,
final PrintWriter outFile) {
- outFile.println("<hr>");
- outFile.println("<b>(Analyzing code subset: " +
breakdown.getDescription()
- + ")</b>");
- outFile.println("<hr>");
+ addCenteredHeader(outFile, headerLineForBreakdown(breakdown));
}
private static String classesInPackageFileName(SizeBreakdown breakdown,
@@ -167,6 +211,40 @@
return new File(outDir, localFileName);
}
+ private static String headerLineForBreakdown(SizeBreakdown breakdown) {
+ return "(Analyzing code subset: " + breakdown.getDescription() + ")";
+ }
+
+ /**
+ * Describe the code covered by the dependency graph with the supplied
name.
+ */
+ private static String inferDepGraphDescription(String depGraphName) {
+ if (depGraphName.equals("initial")) {
+ return "Initially Live Code";
+ }
+
+ if (depGraphName.equals("total")) {
+ return "All Code";
+ }
+
+ Matcher matcher = PATTERN_SP_INT.matcher(depGraphName);
+ if (matcher.matches()) {
+ int splitPoint = Integer.valueOf(matcher.group(1));
+ if (isInitialSplitPoint(splitPoint)) {
+ return "Code Becoming Live at Split Point " + splitPoint;
+ } else {
+ return "Code not Exclusive to Split Point " + splitPoint;
+ }
+ }
+
+ throw new RuntimeException("Unexpected dependency graph name: "
+ + depGraphName);
+ }
+
+ private static boolean isInitialSplitPoint(int splitPoint) {
+ return
GlobalInformation.splitPointInitialLoadSequence.contains(splitPoint);
+ }
+
private static String makeCodeTypeHtml(SizeBreakdown breakdown,
Map<String, CodeCollection> nameToCodeColl) throws IOException {
String outFileName = breakdown.getId() + "_codeTypeBreakdown.html";
@@ -455,99 +533,21 @@
yOffset = yOffset + 25;
}
- outFile.println("</div>");
- outFile.println("</body>");
- outFile.println("</html>");
+ addStandardHtmlEnding(outFile);
outFile.close();
}
}
- public void makeDependenciesHtml(Map<String, ArrayList<String>>
dependencies)
- throws IOException {
-
- String origOutFileName = "methodDependencies-";
- PrintWriter outFile = null;
- String curPackageName = "";
- String curClassName = "";
-
- for (String method : dependencies.keySet()) {
- // this key set is already in alphabetical order
- // get the package of this method, i.e., everything up to .[A-Z]
-
- String packageName = method;
- packageName = packageName.replaceAll("\\.\\p{Upper}.*", "");
-
- String className = method;
- className = className.replaceAll("::.*", "");
-
- if ((curPackageName.compareTo("") == 0)
- || (curPackageName.compareTo(packageName) != 0)) {
-
- curPackageName = packageName;
- if (outFile != null) {
- // finish up the current file
- outFile.println("</table>");
- outFile.println("<center>");
-
- outFile.println("</div>");
- outFile.println("</body>");
- outFile.println("</html>");
- outFile.close();
- }
-
- String outFileName = origOutFileName + filename(curPackageName)
- + ".html";
- outFile = new PrintWriter(getOutFile(outFileName));
-
- outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML
4.01//EN\"");
- outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
- outFile.println("<html>");
- outFile.println("<head>");
- outFile.println("<meta http-equiv=\"content-type\"
content=\"text/html;charset=ISO-8859-1\">");
- outFile.println("<title>Method Dependencies</title>");
- outFile.println("</head>");
-
- outFile.println("<style type=\"text/css\">");
- outFile.println("body {background-color: #728FCE}");
- outFile.println("h2 {background-color: transparent}");
- outFile.println("p {background-color: fuchsia}");
- outFile.println("</style>");
-
- outFile.println("<body>");
- outFile.println("<center>");
- outFile.println("<h2>Method Dependencies for package " +
curPackageName
- + "</h2>");
- outFile.println("</center>");
- outFile.println("<hr>");
-
- outFile.println("<center>");
- outFile.println("<table border=\"1\" width=\"80%\"
style=\"font-size: 11pt;\" bgcolor=\"white\">");
- }
- outFile.println("<tr>");
- if (curClassName.compareTo(className) != 0) {
- outFile.println("<td width=\"80%\"><a name=\"" + className + "\">"
- + "<a name=\"" + method + "\">" + method
- + "</a></a><font color=\"green\"> called by</font></td>");
- curClassName = className;
- } else {
- outFile.println("<td width=\"80%\"><a name=\"" + method + "\">"
- + method + "</a><font color=\"green\"> called by</font></td>");
- }
- outFile.println("</tr>");
-
- for (int i = 0; i < dependencies.get(method).size(); i++) {
- String depMethod = dependencies.get(method).get(i);
+ public void makeDependenciesHtml(
+ Map<String, Map<String, String>> allDependencies) throws IOException
{
+ for (String depGraphName : allDependencies.keySet()) {
+ makeDependenciesHtml(depGraphName,
allDependencies.get(depGraphName));
+ }
+ }
- outFile.println("<tr>");
- outFile.println("<td width=\"20%\"></td>");
- if (i != dependencies.get(method).size() - 1) {
- outFile.println("<td width=\"60%\">" + depMethod
- + "<font color=\"green\"> called by</font></td>");
- } else {
- outFile.println("<td width=\"60%\">" + depMethod + "</td>");
- }
- outFile.println("</tr>");
- }
+ public void makeLeftoverStatusPages() throws IOException {
+ for (String className : GlobalInformation.classToPackage.keySet()) {
+ makeLeftoversStatusPage(className);
}
}
@@ -656,9 +656,7 @@
outFile.println("</table>");
outFile.println("<center>");
- outFile.println("</div>");
- outFile.println("</body>");
- outFile.println("</html>");
+ addStandardHtmlEnding(outFile);
outFile.close();
}
}
@@ -666,8 +664,8 @@
/**
* Make size breakdowns for each package for one code collection.
*/
- public void makePackageClassesHtmls(SizeBreakdown breakdown)
- throws IOException {
+ public void makePackageClassesHtmls(SizeBreakdown breakdown,
+ DependencyLinker depLinker) throws IOException {
for (String packageName : GlobalInformation.packageToClasses.keySet())
{
TreeMap<Float, String> sortedClasses = new TreeMap<Float, String>(
@@ -778,10 +776,17 @@
outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText
+ "px; left:5px;\">%.1f</div>\n", size);
if (GlobalInformation.displayDependencies == true) {
- outFile.println("<div class=\"barlabel\" style=\"top:" +
yOffsetText
- + "px; left:70px;\"><a href=\"methodDependencies-"
- + filename(packageName) + ".html#" + className + "\">"
- + className + "</a></div>");
+ String dependencyLink =
depLinker.dependencyLinkForClass(className);
+ outFile.print("<div class=\"barlabel\" style=\"top:" +
yOffsetText
+ + "px; left:70px;\">");
+ if (dependencyLink != null) {
+ outFile.print("<a href=\"" + dependencyLink + "\">");
+ }
+ outFile.print(className);
+ if (dependencyLink != null) {
+ outFile.print("</a>");
+ }
+ outFile.println("</div>");
} else {
outFile.println("<div class=\"barlabel\" style=\"top:" +
yOffsetText
+ "px; left:70px;\">" + className + "</div>");
@@ -795,13 +800,17 @@
yOffset = yOffset + 25;
}
- outFile.println("</div>");
- outFile.println("</body>");
- outFile.println("</html>");
+ addStandardHtmlEnding(outFile);
outFile.close();
}
}
+ public void makeSplitStatusPages() throws IOException {
+ for (String className : GlobalInformation.classToPackage.keySet()) {
+ makeSplitStatusPage(className);
+ }
+ }
+
public void makeStringLiteralsClassesTableHtmls(SizeBreakdown breakdown)
throws IOException {
Map<String, LiteralsCollection> nameToLitColl =
breakdown.nameToLitColl;
@@ -811,25 +820,10 @@
final PrintWriter outFile = new
PrintWriter(getOutFile(breakdown.getId()
+ "_" + outFileName));
- outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML
4.01//EN\"");
- outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
- outFile.println("<html>");
- outFile.println("<head>");
- outFile.println("<meta http-equiv=\"content-type\"
content=\"text/html;charset=ISO-8859-1\">");
- outFile.println("<title>Literals of type \"" + literalType
+ "\"</title>");
- outFile.println("</head>");
-
- outFile.println("<style type=\"text/css\">");
- outFile.println("body {background-color: #728FCE}");
- outFile.println("h2 {background-color: transparent}");
- outFile.println("p {background-color: fuchsia}");
- outFile.println("</style>");
+ String title = "Literals of type \"" + literalType + "\"";
+ String header = headerLineForBreakdown(breakdown);
- outFile.println("<body>");
- outFile.println("<center>");
- outFile.println("<h2>Literals of type \"" + literalType + "\"</h2>");
- addHeaderWithBreakdownContext(breakdown, outFile);
- outFile.println("</center>");
+ addStandardHtmlProlog(outFile, title, header);
if (literalType.compareTo("otherStrings") == 0) {
outFile.println("<center>");
@@ -877,12 +871,12 @@
if ((location.indexOf("Line 0") == -1)
&&
(location.compareTo(GlobalInformation.backupLocation) != 0)) { // i.e.,
-
//
if
-
//
we
-
//
actually
-
//
know
-
//
the
-
//
location
+ // if
+ // we
+ // actually
+ // know
+ // the
+ // location
if (ct > 0) {
outFile.println("<tr>");
outFile.println("<td width=\"40%\"> </td>");
@@ -927,9 +921,7 @@
outFile.println("<center>");
}
- outFile.println("</div>");
- outFile.println("</body>");
- outFile.println("</html>");
+ addStandardHtmlEnding(outFile);
outFile.close();
}
}
@@ -996,7 +988,7 @@
} else if (i == FRAGMENT_NUMBER_INITIAL_DOWNLOAD) {
breakdown = GlobalInformation.initialCodeBreakdown;
} else {
- breakdown = GlobalInformation.exclusiveCodeBreakdown(i);
+ breakdown = GlobalInformation.splitPointCodeBreakdown(i);
}
String drillDownFileName = shellFileName(breakdown);
@@ -1039,6 +1031,147 @@
outFile.close();
}
+ private void addLefttoversStatus(String className, String packageName,
+ PrintWriter out) {
+ out.println("<tr><td> <a href=\""
+ + dependenciesFileName("total", packageName) + "#" + className
+ + "\">See why it's live</a></td></tr>");
+ for (int sp = 1; sp <= GlobalInformation.numSplitPoints; sp++) {
+ out.println("<tr><td> <a href=\""
+ + dependenciesFileName("sp" + sp, packageName) + "#" + className
+ + "\">See why it's not exclusive to s.p. #" + sp + " ("
+ + GlobalInformation.splitPointToLocation.get(sp)
+ ")</a></td></tr>");
+ }
+ }
+
+ private void addStandardHtmlEnding(final PrintWriter out) {
+ out.println("</div>");
+ out.println("</body>");
+ out.println("</html>");
+ }
+
+ private void addStandardHtmlProlog(final PrintWriter out, String title,
+ String header) {
+ out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"");
+ out.println("\"http://www.w3.org/TR/html4/strict.dtd\">");
+ out.println("<html>");
+ out.println("<head>");
+ out.println("<meta http-equiv=\"content-type\"
content=\"text/html;charset=ISO-8859-1\">");
+ out.println("<title>" + title + "</title>");
+ out.println("</head>");
+
+ out.println("<style type=\"text/css\">");
+ out.println("body {background-color: #728FCE}");
+ out.println("h2 {background-color: transparent}");
+ out.println("p {background-color: fuchsia}");
+ out.println("</style>");
+
+ out.println("<body>");
+ out.println("<center>");
+ out.println("<h2>" + title + "</h2>");
+ if (header != null) {
+ addCenteredHeader(out, header);
+ }
+ out.println("</center>");
+ }
+
+ private String dependenciesFileName(String depGraphName, String
packageName) {
+ return "methodDependencies-" + depGraphName + "-" +
filename(packageName)
+ + ".html";
+ }
+
+ private String leftoversStatusFileName(String className) {
+ return "leftoverStatus-" + filename(className);
+ }
+
+ private void makeDependenciesHtml(String depGraphName,
+ Map<String, String> dependencies) throws FileNotFoundException {
+ String depGraphDescription = inferDepGraphDescription(depGraphName);
+ PrintWriter outFile = null;
+ String curPackageName = "";
+ String curClassName = "";
+
+ for (String method : dependencies.keySet()) {
+ // this key set is already in alphabetical order
+ // get the package of this method, i.e., everything up to .[A-Z]
+
+ String packageName = method;
+ packageName = packageName.replaceAll("\\.\\p{Upper}.*", "");
+
+ String className = method;
+ className = className.replaceAll("::.*", "");
+
+ if ((curPackageName.compareTo("") == 0)
+ || (curPackageName.compareTo(packageName) != 0)) {
+
+ curPackageName = packageName;
+ if (outFile != null) {
+ // finish up the current file
+ outFile.println("</table>");
+ outFile.println("<center>");
+
+ addStandardHtmlEnding(outFile);
+ outFile.close();
+ }
+
+ String outFileName = dependenciesFileName(depGraphName,
curPackageName);
+ outFile = new PrintWriter(getOutFile(outFileName));
+
+ String packageDescription = packageName.length() == 0
+ ? "the default package" : packageName;
+ addStandardHtmlProlog(outFile, "Method Dependencies for "
+ + depGraphDescription, "Showing Package: " +
packageDescription);
+ outFile.println("<center>");
+ outFile.println("<table border=\"1\" width=\"80%\"
style=\"font-size: 11pt;\" bgcolor=\"white\">");
+ }
+ outFile.println("<tr>");
+ if (curClassName.compareTo(className) != 0) {
+ outFile.println("<td width=\"80%\"><a name=\"" + className + "\">"
+ + "<a name=\"" + method + "\">" + method
+ + "</a></a><font color=\"green\"> called by</font></td>");
+ curClassName = className;
+ } else {
+ outFile.println("<td width=\"80%\"><a name=\"" + method + "\">"
+ + method + "</a><font color=\"green\"> called by</font></td>");
+ }
+ outFile.println("</tr>");
+
+ String depMethod = dependencies.get(method);
+ while (depMethod != null) {
+ String nextDep = dependencies.get(depMethod);
+ outFile.println("<tr>");
+ outFile.println("<td width=\"20%\"></td>");
+ if (nextDep != null) {
+ outFile.println("<td width=\"60%\">" + depMethod
+ + "<font color=\"green\"> called by</font></td>");
+ } else {
+ outFile.println("<td width=\"60%\">" + depMethod + "</td>");
+ }
+ outFile.println("</tr>");
+ depMethod = nextDep;
+ }
+ }
+ }
+
+ private void makeLeftoversStatusPage(String className) throws
IOException {
+ String packageName = GlobalInformation.classToPackage.get(className);
+ PrintWriter out = new PrintWriter(
+ getOutFile(leftoversStatusFileName(className)));
+
+ addStandardHtmlProlog(out, "Leftovers page for " + className, null);
+
+ out.println("<center>");
+ out.println("<table border=\"1\" width=\"80%\" style=\"font-size:
11pt;\" bgcolor=\"white\">");
+
+ out.println("<tr><td>This class has some leftover code, neither
initial nor exclusive to any split point:</td></tr>");
+ addLefttoversStatus(className, packageName, out);
+ out.println("</table>");
+
+ addStandardHtmlEnding(out);
+
+ out.close();
+ }
+
private String makeLiteralsHtml(SizeBreakdown breakdown,
Map<String, LiteralsCollection> nameToLitColl) throws IOException {
String outFileName = breakdown.getId() + "_literalsBreakdown.html";
@@ -1189,6 +1322,36 @@
return outFileName;
}
+ private void makeSplitStatusPage(String className) throws IOException {
+ String packageName = GlobalInformation.classToPackage.get(className);
+ PrintWriter out = new PrintWriter(
+ getOutFile(splitStatusFileName(className)));
+
+ addStandardHtmlProlog(out, "Split point status for " + className,
null);
+
+ out.println("<center>");
+ out.println("<table border=\"1\" width=\"80%\" style=\"font-size:
11pt;\" bgcolor=\"white\">");
+
+ if
(GlobalInformation.initialCodeBreakdown.classToSize.containsKey(className))
{
+ out.println("<tr><td>Some code is initial (<a href=\""
+ + dependenciesFileName("initial", packageName) + "#" + className
+ + "\">see why</a>)</td></tr>");
+ }
+ for (int sp : splitPointsWithClass(className)) {
+ out.println("<tr><td>Some code downloads with s.p. #" + sp + " ("
+ + GlobalInformation.splitPointToLocation.get(sp)
+ ")</td></tr>");
+ }
+ if
(GlobalInformation.leftoversBreakdown.classToSize.containsKey(className)) {
+ out.println("<tr><td>Some code is left over:</td></tr>");
+ addLefttoversStatus(className, packageName, out);
+ }
+ out.println("</table>");
+
+ addStandardHtmlEnding(out);
+
+ out.close();
+ }
+
private String makeStringLiteralsHtml(SizeBreakdown breakdown,
Map<String, LiteralsCollection> nameToLitColl) throws IOException {
String outFileName = breakdown.getId()
+ "_stringLiteralsBreakdown.html";
@@ -1270,5 +1433,23 @@
outFile.close();
return outFileName;
+ }
+
+ /**
+ * Find which split points include code belonging to
<code>className</code>.
+ */
+ private Iterable<Integer> splitPointsWithClass(String className) {
+ List<Integer> sps = new ArrayList<Integer>();
+ for (int sp = 1; sp <= GlobalInformation.numSplitPoints; sp++) {
+ Map<String, Integer> classToSize =
GlobalInformation.splitPointCodeBreakdown(sp).classToSize;
+ if (classToSize.containsKey(className)) {
+ sps.add(sp);
+ }
+ }
+ return sps;
+ }
+
+ private String splitStatusFileName(String className) {
+ return "splitStatus-" + filename(className);
}
}
Modified: trunk/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java
==============================================================================
--- trunk/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java
(original)
+++ trunk/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java Mon
Jul 6 15:03:31 2009
@@ -16,6 +16,8 @@
package com.google.gwt.soyc;
+import com.google.gwt.soyc.MakeTopLevelHtmlForPerm.DependencyLinker;
+
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
@@ -34,6 +36,7 @@
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;
import javax.xml.parsers.ParserConfigurationException;
@@ -44,6 +47,11 @@
* The command-line entry point for creating a SOYC report.
*/
public class SoycDashboard {
+ private static class FormatException extends RuntimeException {
+ public FormatException(String message) {
+ super(message);
+ }
+ }
public static void main(String[] args) {
try {
@@ -62,7 +70,7 @@
/**
* handle dependencies
*/
- Map<String, ArrayList<String>> dependencies = new TreeMap<String,
ArrayList<String>>();
+ Map<String, Map<String, String>> dependencies = new
TreeMap<String, Map<String, String>>();
DefaultHandler depHandler =
parseXMLDocumentDependencies(dependencies);
// start parsing
@@ -133,8 +141,12 @@
}
// generate all the html files
+ makeTopLevelHtmlForPerm.makeSplitStatusPages();
+ makeTopLevelHtmlForPerm.makeLeftoverStatusPages();
for (SizeBreakdown breakdown :
GlobalInformation.allSizeBreakdowns()) {
- makeHTMLFiles(makeTopLevelHtmlForPerm, breakdown);
+ DependencyLinker linker = chooseDependencyLinker(
+ makeTopLevelHtmlForPerm, breakdown);
+ makeHTMLFiles(makeTopLevelHtmlForPerm, breakdown, linker);
}
System.out.println("Finished creating reports. To see the dashboard,
open SoycDashboard-index.html in your browser.");
@@ -160,6 +172,19 @@
}
}
+ private static DependencyLinker chooseDependencyLinker(
+ MakeTopLevelHtmlForPerm makeTopLevelHtmlForPerm, SizeBreakdown
breakdown) {
+ if (breakdown == GlobalInformation.totalCodeBreakdown) {
+ return makeTopLevelHtmlForPerm.new
DependencyLinkerForTotalBreakdown();
+ } else if (breakdown == GlobalInformation.initialCodeBreakdown) {
+ return makeTopLevelHtmlForPerm.new DependencyLinkerForInitialCode();
+ } else if (breakdown == GlobalInformation.leftoversBreakdown) {
+ return makeTopLevelHtmlForPerm.new
DependencyLinkerForLeftoversFragment();
+ } else {
+ return makeTopLevelHtmlForPerm.new
DependencyLinkerForExclusiveFragment();
+ }
+ }
+
/*
* cleans up the RPC code categories
*/
@@ -195,12 +220,12 @@
}
/**
- * generates all the HTML files
+ * generates all the HTML files for one size breakdown
*/
private static void makeHTMLFiles(
- MakeTopLevelHtmlForPerm makeTopLevelHtmlForPerm, SizeBreakdown
breakdown)
- throws IOException {
- makeTopLevelHtmlForPerm.makePackageClassesHtmls(breakdown);
+ MakeTopLevelHtmlForPerm makeTopLevelHtmlForPerm, SizeBreakdown
breakdown,
+ DependencyLinker depLinker) throws IOException {
+ makeTopLevelHtmlForPerm.makePackageClassesHtmls(breakdown, depLinker);
makeTopLevelHtmlForPerm.makeCodeTypeClassesHtmls(breakdown);
makeTopLevelHtmlForPerm.makeLiteralsClassesTableHtmls(breakdown);
makeTopLevelHtmlForPerm.makeStringLiteralsClassesTableHtmls(breakdown);
@@ -384,7 +409,7 @@
breakdowns.add(GlobalInformation.leftoversBreakdown);
}
if (curFragment >= 1 && curFragment <=
GlobalInformation.numSplitPoints) {
-
breakdowns.add(GlobalInformation.exclusiveCodeBreakdown(curFragment));
+
breakdowns.add(GlobalInformation.splitPointCodeBreakdown(curFragment));
}
return breakdowns;
}
@@ -718,44 +743,58 @@
}
private static DefaultHandler parseXMLDocumentDependencies(
- final Map<String, ArrayList<String>> dependencies) {
-
+ final Map<String, Map<String, String>> allDependencies) {
DefaultHandler handler = new DefaultHandler() {
// may want to create a class for this later
String curMethod;
+ Map<String, String> dependencies = new TreeMap<String, String>();
+ String graphExtends = null;
StringBuilder valueBuilder = new StringBuilder();
- /**
- * This method deals with the beginning of the XML element. It
analyzes
- * the XML node and adds its information to the relevant literal or
code
- * collection for later analysis.
- *
- * @see
org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
- * java.lang.String, java.lang.String, org.xml.sax.Attributes)
- */
+ @Override
+ public void endElement(String uri, String localName, String qName) {
+ if (localName.compareTo("table") == 0) {
+ if (graphExtends != null) {
+ // Add in elements from the extended graph
+ for (Entry<String, String> entry :
allDependencies.get(graphExtends).entrySet()) {
+ dependencies.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ }
+
@Override
public void startElement(String nsUri, String strippedName,
String tagName, Attributes attributes) {
valueBuilder.delete(0, valueBuilder.length());
- if ((strippedName.compareTo("method") == 0)
+ if (strippedName.compareTo("table") == 0
+ && (attributes.getValue("name") != null)) {
+ String name = attributes.getValue("name");
+ dependencies = new TreeMap<String, String>();
+ allDependencies.put(name, dependencies);
+ if (attributes.getValue("extends") != null) {
+ graphExtends = attributes.getValue("extends");
+ if (!allDependencies.containsKey(graphExtends)) {
+ throw new FormatException("Graph " + name
+ + " extends an unknown graph " + graphExtends);
+ }
+ } else {
+ graphExtends = null;
+ }
+ } else if ((strippedName.compareTo("method") == 0)
&& (attributes.getValue("name") != null)) {
curMethod = attributes.getValue("name");
} else if ((strippedName.compareTo("called") == 0)
&& (attributes.getValue("by") != null)) {
String curDepMethod = attributes.getValue("by");
if (!dependencies.containsKey(curMethod)) {
- ArrayList<String> insertArray = new ArrayList<String>();
- insertArray.add(curDepMethod);
- dependencies.put(curMethod, insertArray);
- } else {
- dependencies.get(curMethod).add(curDepMethod);
+ dependencies.put(curMethod, curDepMethod);
}
}
}
-
};
return handler;
}
@@ -764,19 +803,25 @@
DefaultHandler handler = new DefaultHandler() {
- /**
- * This method deals with the beginning of the XML element. It
analyzes
- * the XML node and adds its information to the relevant literal or
code
- * collection for later analysis.
- *
- * @see
org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
- * java.lang.String, java.lang.String, org.xml.sax.Attributes)
- */
+ private boolean inInitialLoadSequence = false;
+
+ @Override
+ public void endElement(String uri, String localName, String qName) {
+ if (localName.compareTo("initialesq") == 0) {
+ inInitialLoadSequence = false;
+ }
+ }
+
@Override
public void startElement(String nsUri, String strippedName,
String tagName, Attributes attributes) {
if (strippedName.compareTo("splitpoint") == 0) {
parseSplitPoint(attributes);
+ } else if (strippedName.compareTo("initialseq") == 0) {
+ inInitialLoadSequence = true;
+ } else if (inInitialLoadSequence
+ && strippedName.compareTo("splitpointref") == 0) {
+
GlobalInformation.splitPointInitialLoadSequence.add(parseSplitPointReference(attributes));
}
}
@@ -797,6 +842,14 @@
GlobalInformation.numSplitPoints++;
}
}
+ }
+
+ private Integer parseSplitPointReference(Attributes attributes) {
+ String spString = attributes.getValue("id");
+ if (spString == null) {
+ throw new FormatException("Could not parse split point
reference");
+ }
+ return Integer.valueOf(spString);
}
};
--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---