Make SOYC produce consistent output.

http://gwt-code-reviews.appspot.com/1338805/show

Review by: robertvawter@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9682 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/SizeMapRecorder.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/SizeMapRecorder.java
index 912f040..605e72f 100644
--- a/dev/core/src/com/google/gwt/core/ext/soyc/impl/SizeMapRecorder.java
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/SizeMapRecorder.java
@@ -29,8 +29,10 @@
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
+import java.util.Comparator;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.TreeMap;
 import java.util.zip.GZIPOutputStream;
 
 /**
@@ -38,6 +40,16 @@
  * then read to produce a Story of Your Compile.
  */
 public class SizeMapRecorder {
+
+  /**
+   * Sorts by JsName.getIdent().
+   */
+  private static final Comparator<JsName> JSNAME_SORT = new Comparator<JsName>() {
+    public int compare(JsName o1, JsName o2) {
+      return o1.getIdent().compareTo(o2.getIdent());
+    }
+  };
+
   /**
    * A human-accessible type and description of a program reference. These are
    * produced by
@@ -72,7 +84,7 @@
     return toReturn;
   }
 
-  /**
+/**
    * Escapes '&', '<', '>', '"', and '\'' to their XML entity equivalents.
    */
   public static String escapeXml(String unescaped) {
@@ -81,7 +93,7 @@
     return builder.toString();
   }
 
-  /**
+/**
    * Escapes '&', '<', '>', '"', and optionally ''' to their XML entity
    * equivalents. The portion of the input string between start (inclusive) and
    * end (exclusive) is scanned.  The output is appended to the given
@@ -95,7 +107,7 @@
    * @param builder a StringBuilder to be appended with the output.
    */
   public static void escapeXml(String code, int start, int end,
-    boolean quoteApostrophe, StringBuilder builder) {
+      boolean quoteApostrophe, StringBuilder builder) {
     // See http://www.w3.org/TR/2006/REC-xml11-20060816/#charsets.
     int lastIndex = 0;
     int len = end - start;
@@ -156,7 +168,7 @@
     }
     builder.append(c, lastIndex, len - lastIndex);
   }
-  
+
   /**
    * @param logger a TreeLogger
    */
@@ -172,7 +184,9 @@
     for (int i = 0; i < sizeBreakdowns.length; i++) {
       writer.append("<sizemap fragment=\"" + i + "\" " + "size=\""
           + sizeBreakdowns[i].getSize() + "\">\n");
-      for (Entry<JsName, Integer> sizeMapEntry : sizeBreakdowns[i].getSizeMap().entrySet()) {
+      Map<JsName, Integer> sizeMap = new TreeMap<JsName, Integer>(JSNAME_SORT);
+      sizeMap.putAll(sizeBreakdowns[i].getSizeMap());
+      for (Entry<JsName, Integer> sizeMapEntry : sizeMap.entrySet()) {
         JsName name = sizeMapEntry.getKey();
         int size = sizeMapEntry.getValue();
         TypedProgramReference typedRef = typedProgramReference(name, jjsmap,
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
index dcc2821..8e4aeb3 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
@@ -16,9 +16,11 @@
 package com.google.gwt.dev.jjs.ast;
 
 import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
+import com.google.gwt.dev.jjs.impl.HasNameSort;
 import com.google.gwt.dev.util.collect.IdentityHashMap;
 import com.google.gwt.dev.util.collect.IdentityHashSet;
 import com.google.gwt.dev.util.collect.IdentitySets;
+import com.google.gwt.dev.util.collect.Lists;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -462,10 +464,11 @@
      * building the full maps.
      */
     JClassType jsoType = program.getJavaScriptObject();
-    Set<JClassType> jsoSubTypes = Collections.emptySet();
+    List<JClassType> jsoSubTypes = Lists.create();
     if (jsoType != null) {
       assert jsoType.getImplements().size() == 0;
-      jsoSubTypes = get(subClassMap, jsoType);
+      jsoSubTypes = new ArrayList<JClassType>(get(subClassMap, jsoType));
+      Collections.sort(jsoSubTypes, new HasNameSort());
       for (JClassType jsoSubType : jsoSubTypes) {
         for (JInterfaceType intf : jsoSubType.getImplements()) {
           jsoType.addImplements(intf);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
index 5dab288..b67bb11 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
@@ -205,7 +205,9 @@
       rescue(type.getSuperClass(), true, isInstantiated);
 
       // Rescue my clinit (it won't ever be explicitly referenced)
-      rescue(type.getMethods().get(0));
+      if (type.hasClinit()) {
+        rescue(type.getMethods().get(0));
+      }
 
       // JLS 12.4.1: don't rescue my super interfaces just because I'm rescued.
       // However, if I'm instantiated, let's mark them as instantiated.
@@ -273,7 +275,9 @@
       assert (isReferenced || isInstantiated);
 
       // Rescue my clinit (it won't ever be explicitly referenced
-      rescue(type.getMethods().get(0));
+      if (type.hasClinit()) {
+        rescue(type.getMethods().get(0));
+      }
 
       // JLS 12.4.1: don't rescue my super interfaces just because I'm rescued.
       // However, if I'm instantiated, let's mark them as instantiated.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
index 28c6317..4cf1372 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
@@ -361,9 +361,12 @@
         JMethod method = type.getMethods().get(i);
         if (!methodIsReferenced(method)
             || pruneViaNoninstantiability(isInstantiated, method)) {
-          type.removeMethod(i);
-          madeChanges();
-          --i;
+          // Never prune clinit directly out of the class.
+          if (i > 0) {
+            type.removeMethod(i);
+            madeChanges();
+            --i;
+          }
         } else {
           accept(method);
         }