Adds some StringInterner references to reduce overall memory usage
under compile report (soyc).  On A large code base, I witnessed a
reduction from 369M to 301M of heap when running the compileReport.

Review at http://gwt-code-reviews.appspot.com/1108801

Review by: conroy@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9236 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCastableTypeMap.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCastableTypeMap.java
index 0313d5d..0ded30e 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCastableTypeMap.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCastableTypeMap.java
@@ -22,10 +22,12 @@
  * The standard implementation of {@link CastableTypeMap}.
  */
 public class StandardCastableTypeMap implements CastableTypeMap {
+  // Save some memory by defining this constant string.
+  private static final String EMPTY_JSON_REF = "{}";
   
   final String jsonData;
   public StandardCastableTypeMap(String jsonData) {
-    this.jsonData = jsonData;
+    this.jsonData = jsonData.equals(EMPTY_JSON_REF) ? EMPTY_JSON_REF : jsonData;
   }
 
   public String toJs() {
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java
index 17040a7..fcd2393 100644
--- a/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/DependencyRecorder.java
@@ -19,8 +19,8 @@
 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.ControlFlowAnalyzer;
 import com.google.gwt.dev.jjs.impl.CodeSplitter.MultipleDependencyGraphRecorder;
+import com.google.gwt.dev.jjs.impl.ControlFlowAnalyzer;
 import com.google.gwt.util.tools.Utility;
 
 import java.io.IOException;
@@ -121,7 +121,7 @@
       }
       printPost();
 
-      writer.write(builder.toString());
+      flushOutput();
       Utility.close(writer);
 
     } catch (Throwable e) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index 245561c..e795adb 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -24,9 +24,9 @@
 import com.google.gwt.core.ext.linker.ArtifactSet;
 import com.google.gwt.core.ext.linker.CompilationMetricsArtifact;
 import com.google.gwt.core.ext.linker.EmittedArtifact;
+import com.google.gwt.core.ext.linker.EmittedArtifact.Visibility;
 import com.google.gwt.core.ext.linker.ModuleMetricsArtifact;
 import com.google.gwt.core.ext.linker.PrecompilationMetricsArtifact;
-import com.google.gwt.core.ext.linker.EmittedArtifact.Visibility;
 import com.google.gwt.core.ext.linker.StatementRanges;
 import com.google.gwt.core.ext.linker.SymbolData;
 import com.google.gwt.core.ext.linker.SyntheticArtifact;
@@ -308,7 +308,7 @@
 
       // (7) Generate a JavaScript code DOM from the Java type declarations
       jprogram.typeOracle.recomputeAfterOptimizations();
-      JavaToJavaScriptMap map = GenerateJavaScriptAST.exec(jprogram, jsProgram,
+      JavaToJavaScriptMap jjsmap = GenerateJavaScriptAST.exec(jprogram, jsProgram,
           options.getOutput(), symbolTable, propertyOracles);
 
       // (8) Normalize the JS AST.
@@ -317,7 +317,7 @@
       // Resolve all unresolved JsNameRefs.
       JsSymbolResolver.exec(jsProgram);
       // Move all function definitions to a top-level scope, to reduce weirdness
-      EvalFunctionsAtTopScope.exec(jsProgram, map);
+      EvalFunctionsAtTopScope.exec(jsProgram, jjsmap);
 
       // (9) Optimize the JS AST.
       if (optimizationLevel > OptionOptimize.OPTIMIZE_LEVEL_DRAFT) {
@@ -340,7 +340,7 @@
       SyntheticArtifact dependencies = null;
       if (options.isRunAsyncEnabled()) {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        CodeSplitter.exec(logger, jprogram, jsProgram, map,
+        CodeSplitter.exec(logger, jprogram, jsProgram, jjsmap,
             chooseDependencyRecorder(options.isSoycEnabled(), baos));
         if (baos.size() == 0 && options.isSoycEnabled()) {
           recordNonSplitDependencies(jprogram, baos);
@@ -423,7 +423,7 @@
           new SizeBreakdown[js.length] : null;
       List<Map<Range, SourceInfo>> sourceInfoMaps = options.isSoycExtra() ?
           new ArrayList<Map<Range, SourceInfo>>() : null;
-      generateJavaScriptCode(options, jsProgram, map, js, ranges,
+      generateJavaScriptCode(options, jsProgram, jjsmap, js, ranges,
           sizeBreakdowns, sourceInfoMaps, splitBlocks);
 
       PermutationResult toReturn = new PermutationResultImpl(js, permutation,
@@ -441,7 +441,7 @@
             unifiedAst.getPrecompilationMetrics(), compilationMetrics));
       }
       toReturn.addArtifacts(makeSoycArtifacts(logger, permutationId, jprogram,
-          js, sizeBreakdowns, sourceInfoMaps, dependencies, map, obfuscateMap,
+          js, sizeBreakdowns, sourceInfoMaps, dependencies, jjsmap, obfuscateMap,
           unifiedAst.getModuleMetrics(), unifiedAst.getPrecompilationMetrics(),
           compilationMetrics));
 
@@ -1153,6 +1153,7 @@
       PrecompilationMetricsArtifact precompilationMetricsArtifact,
       CompilationMetricsArtifact compilationMetrics) throws IOException,
       UnableToCompleteException {
+    Memory.maybeDumpMemory("makeSoycArtifactsStart");
     List<SyntheticArtifact> soycArtifacts = new ArrayList<SyntheticArtifact>();
 
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -1215,6 +1216,7 @@
         if (dependencies != null) {
           dashboard.readDependencies(openWithGunzip(dependencies));
         }
+        Memory.maybeDumpMemory("soycReadDependenciesEnd");
       } catch (ParserConfigurationException e) {
         throw new InternalCompilerException(
             "Error reading compile report information that was just generated",
diff --git a/dev/core/src/com/google/gwt/dev/jjs/SourceOrigin.java b/dev/core/src/com/google/gwt/dev/jjs/SourceOrigin.java
index f06dba8..5e666d7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/SourceOrigin.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/SourceOrigin.java
@@ -16,13 +16,14 @@
 package com.google.gwt.dev.jjs;
 
 import com.google.gwt.dev.jjs.Correlation.Axis;
+import com.google.gwt.dev.util.StringInterner;
 
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.Map.Entry;
+import java.util.Set;
 
 /**
  * Describes where a SourceInfo's node came from. This class currently includes
@@ -118,7 +119,7 @@
   private final int startLine;
 
   private SourceOrigin(String location, int startLine) {
-    this.fileName = location;
+    this.fileName = StringInterner.get().intern(location);
     this.startLine = startLine;
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index 2ad8a9a..bc2288c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -135,8 +135,9 @@
 import com.google.gwt.dev.js.ast.JsUnaryOperation;
 import com.google.gwt.dev.js.ast.JsUnaryOperator;
 import com.google.gwt.dev.js.ast.JsVars;
-import com.google.gwt.dev.js.ast.JsWhile;
 import com.google.gwt.dev.js.ast.JsVars.JsVar;
+import com.google.gwt.dev.js.ast.JsWhile;
+import com.google.gwt.dev.util.StringInterner;
 import com.google.gwt.dev.util.collect.IdentityHashSet;
 import com.google.gwt.dev.util.collect.Maps;
 
@@ -150,10 +151,10 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.Stack;
 import java.util.TreeMap;
-import java.util.Map.Entry;
 
 /**
  * Creates a JavaScript AST from a <code>JProgram</code> node.
@@ -482,7 +483,7 @@
         }
         sb.append(')');
         sb.append(method.getOriginalReturnType().getJsniSignatureName());
-        methodSig = sb.toString();
+        methodSig = StringInterner.get().intern(sb.toString());
       } else {
         methodSig = null;
       }
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsName.java b/dev/core/src/com/google/gwt/dev/js/ast/JsName.java
index a087d15..0cb1461 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsName.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsName.java
@@ -24,7 +24,6 @@
  * An abstract base class for named JavaScript objects.
  */
 public class JsName implements Serializable {
-
   private final JsScope enclosing;
   private final String ident;
   private boolean isObfuscatable;
@@ -76,7 +75,7 @@
   }
 
   public void setShortIdent(String shortIdent) {
-    this.shortIdent = shortIdent;
+    this.shortIdent = StringInterner.get().intern(shortIdent);
   }
 
   /**
@@ -91,5 +90,4 @@
   public String toString() {
     return ident;
   }
-
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/Memory.java b/dev/core/src/com/google/gwt/dev/util/Memory.java
index 912e0d6..420130f 100644
--- a/dev/core/src/com/google/gwt/dev/util/Memory.java
+++ b/dev/core/src/com/google/gwt/dev/util/Memory.java
@@ -81,7 +81,8 @@
     }
     String dumpFile = System.getProperty(PROPERTY_DUMP_HEAP);
     if (dumpFile != null) {
-      dumpFile = info + "-" + dumpFile;
+      String procName = ManagementFactory.getRuntimeMXBean().getName();
+      dumpFile = info + "-" + procName + dumpFile;
       new File(dumpFile).delete();
       try {
         Class<?> beanClass = Class.forName("com.sun.management.HotSpotDiagnosticMXBean");
diff --git a/dev/core/src/com/google/gwt/soyc/SoycDashboard.java b/dev/core/src/com/google/gwt/soyc/SoycDashboard.java
index 22c992a..492204e 100644
--- a/dev/core/src/com/google/gwt/soyc/SoycDashboard.java
+++ b/dev/core/src/com/google/gwt/soyc/SoycDashboard.java
@@ -19,6 +19,7 @@
 import com.google.gwt.core.ext.linker.CompilationMetricsArtifact;
 import com.google.gwt.core.ext.linker.ModuleMetricsArtifact;
 import com.google.gwt.core.ext.linker.PrecompilationMetricsArtifact;
+import com.google.gwt.dev.util.StringInterner;
 import com.google.gwt.soyc.MakeTopLevelHtmlForPerm.DependencyLinker;
 import com.google.gwt.soyc.MakeTopLevelHtmlForPerm.NullDependencyLinker;
 import com.google.gwt.soyc.io.FileSystemOutputDirectory;
@@ -40,10 +41,10 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Scanner;
 import java.util.TreeMap;
 import java.util.TreeSet;
-import java.util.Map.Entry;
 import java.util.zip.GZIPInputStream;
 
 import javax.xml.parsers.ParserConfigurationException;
@@ -212,9 +213,9 @@
             && (attributes.getValue("name") != null)) {
           String name = attributes.getValue("name");
           dependencies = new TreeMap<String, String>();
-          allDependencies.put(name, dependencies);
+          allDependencies.put(StringInterner.get().intern(name), dependencies);
           if (attributes.getValue("extends") != null) {
-            graphExtends = attributes.getValue("extends");
+            graphExtends = StringInterner.get().intern(attributes.getValue("extends"));
             if (!allDependencies.containsKey(graphExtends)) {
               throw new FormatException("Graph " + name
                   + " extends an unknown graph " + graphExtends);
@@ -224,12 +225,13 @@
           }
         } else if ((strippedName.compareTo("method") == 0)
             && (attributes.getValue("name") != null)) {
-          curMethod = attributes.getValue("name");
+          curMethod = StringInterner.get().intern(attributes.getValue("name"));
         } else if ((strippedName.compareTo("called") == 0)
             && (attributes.getValue("by") != null)) {
           String curDepMethod = attributes.getValue("by");
           if (!dependencies.containsKey(curMethod)) {
-            dependencies.put(curMethod, curDepMethod);
+            dependencies.put(StringInterner.get().intern(curMethod),
+                StringInterner.get().intern(curDepMethod));
           }
         }
       }
@@ -519,7 +521,7 @@
             int idx = className.indexOf(':');
             className = className.substring(0, idx);
           }
-
+          className = StringInterner.get().intern(className);
           // derive the package name from the class
           String packageName;
           if (!globalInformation.getClassToPackage().containsKey(className)) {
@@ -529,6 +531,7 @@
           } else {
             packageName = globalInformation.getClassToPackage().get(className);
           }
+
           if (!globalInformation.getPackageToClasses().containsKey(packageName)) {
             TreeSet<String> insertSet = new TreeSet<String>();
             insertSet.add(className);
@@ -569,6 +572,8 @@
 
       private void recordSize(String refType, String ref, int size,
           GlobalInformation globalInformation) {
+        refType = StringInterner.get().intern(refType);
+        ref = StringInterner.get().intern(ref);
         for (SizeBreakdown breakdown : breakdownsForFragment(fragment)) {
           accountForSize(breakdown, refType, ref, size, globalInformation);
         }