Refactor SOYC to reduce memory footprint.

Before: correlations from parents get copied to every single child SourceInfoCorrelation, using lots of extra memory.

After: SourceInfoCorrelations have parent pointers, and the list of correlations is computed on demand, saving a lot of memory.

Other changes:
- Got rid of the idea of merging and having more than one correlation of a given type per node.  These features were only used in practice a couple of minor cases (static evaluation of string concats, for example).
- Generally, not routing through JProgram to create child nodes.
- Cleaned up a couple of wrongful/wonky attributes.
- Output is nearly identical after this change.

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

Review by: cromwellian@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9747 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java
index 7ad6d56..51bab4b 100644
--- a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java
@@ -187,7 +187,7 @@
       // Possibly create and record Members
       if (!sourceInfoSeen.contains(info)) {
         sourceInfoSeen.add(info);
-        for (Correlation c : info.getPrimaryCorrelationsArray()) {
+        for (Correlation c : info.getCorrelations()) {
           if (c == null) {
             continue;
           }
@@ -345,7 +345,7 @@
     if (!storyCache.containsKey(info)) {
       SortedSet<Member> members = new TreeSet<Member>(
           Member.TYPE_AND_SOURCE_NAME_COMPARATOR);
-      for (Correlation c : info.getAllCorrelations()) {
+      for (Correlation c : info.getCorrelations()) {
         Member m = membersByCorrelation.get(c);
         if (m != null) {
           members.add(m);
@@ -353,7 +353,7 @@
       }
 
       String literalType = null;
-      Correlation literalCorrelation = info.getPrimaryCorrelation(Axis.LITERAL);
+      Correlation literalCorrelation = info.getCorrelation(Axis.LITERAL);
       if (literalCorrelation != null) {
         literalType = literalCorrelation.getLiteral().getDescription();
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/SourceInfo.java b/dev/core/src/com/google/gwt/dev/jjs/SourceInfo.java
index 72aeb07..7e914e9 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/SourceInfo.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/SourceInfo.java
@@ -18,8 +18,6 @@
 import com.google.gwt.dev.jjs.Correlation.Axis;
 
 import java.io.Serializable;
-import java.util.List;
-import java.util.Set;
 
 /**
  * Tracks file and line information for AST nodes.
@@ -32,53 +30,28 @@
   void addCorrelation(Correlation c);
 
   /**
-   * Copy any Correlations from another SourceInfo node if there are no
-   * Correlations on this SourceInfo with the same Axis.
+   * Return the Correlation that has been set for a given Axis, or
+   * <code>null</code> if no Correlation has been set on the given axis.
    */
-  void copyMissingCorrelationsFrom(SourceInfo other);
+  Correlation getCorrelation(Axis axis);
 
   /**
-   * Returns all Correlations applied to this SourceInfo, its parent, additional
-   * ancestor SourceInfo, and any supertype SourceInfos.
+   * Returns the Correlations added along each Axis on which a Correlation has
+   * been set. Some entries may be null and should be ignored.
    */
-  List<Correlation> getAllCorrelations();
-
-  /**
-   * Returns all Correlations along a given axis applied to this SourceInfo, its
-   * parent, additional ancestor SourceInfo, and any supertype SourceInfos.
-   */
-  List<Correlation> getAllCorrelations(Axis axis);
+  Correlation[] getCorrelations();
 
   /**
    * Returns the correlation factory that created this node.
    */
-  CorrelationFactory getCorrelationFactory();
-  
+  CorrelationFactory getCorrelator();
+
   int getEndPos();
 
   String getFileName();
 
   SourceOrigin getOrigin();
 
-  /**
-   * Returns the first Correlation that had been set with a given Axis, or
-   * <code>null</code> if no Correlation has been set on the given axis.
-   */
-  Correlation getPrimaryCorrelation(Axis axis);
-
-  /**
-   * Returns the first Correlations added along each Axis on which a Correlation
-   * has been set.
-   */
-  Set<Correlation> getPrimaryCorrelations();
-
-  /**
-   * Returns the first Correlations added along each Axis on which a Correlation
-   * has been set. Some entries may be null and should be ignored. The returned
-   * array must not be modified.
-   */
-  Correlation[] getPrimaryCorrelationsArray();
-
   int getStartLine();
 
   int getStartPos();
@@ -96,11 +69,4 @@
    * Correlations from this node.
    */
   SourceInfo makeChild(SourceOrigin origin);
-
-  /**
-   * Add additional ancestor SourceInfos. These SourceInfo objects indicate that
-   * a merge-type operation took place or that the additional ancestors have a
-   * containment relationship with the SourceInfo.
-   */
-  void merge(SourceInfo... sourceInfos);
 }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/SourceInfoCorrelation.java b/dev/core/src/com/google/gwt/dev/jjs/SourceInfoCorrelation.java
index 19d8d90..320376e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/SourceInfoCorrelation.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/SourceInfoCorrelation.java
@@ -19,12 +19,6 @@
 import com.google.gwt.dev.jjs.CorrelationFactory.RealCorrelationFactory;
 
 import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
 
 /**
  * Tracks file and line information for AST nodes.
@@ -33,16 +27,7 @@
  */
 public class SourceInfoCorrelation implements SourceInfo, Serializable {
 
-  private static final int numCorrelationAxes = Axis.values().length;
-
-  private static int numCorrelationAxes() {
-    return numCorrelationAxes;
-  }
-
-  /**
-   * Any Correlation associated with the SourceInfo.
-   */
-  private final List<Correlation> allCorrelations;
+  private static final int NUM_AXES = Axis.values().length;
 
   /**
    * Holds the origin data for the SourceInfo.
@@ -50,79 +35,74 @@
   private final SourceOrigin origin;
 
   /**
+   * My parent node, or <code>null</code> if I have no parent.
+   */
+  private final SourceInfoCorrelation parent;
+
+  /**
    * Records the first Correlation on any given Axis applied to the SourceInfo.
    * Each index of this array corresponds to the Correlation.Axis with the same
    * ordinal().
    */
-  private final Correlation[] primaryCorrelations;
+  private Correlation[] primaryCorrelations = null;
 
   public SourceInfoCorrelation(SourceOrigin origin) {
     this.origin = origin;
-    allCorrelations = new ArrayList<Correlation>();
-    primaryCorrelations = new Correlation[numCorrelationAxes()];
+    this.parent = null;
   }
 
   private SourceInfoCorrelation(SourceInfoCorrelation parent,
       SourceOrigin origin) {
     this.origin = origin;
-    this.allCorrelations = new ArrayList<Correlation>(parent.allCorrelations);
-    primaryCorrelations = parent.primaryCorrelations.clone();
+    this.parent = parent;
   }
 
   /**
    * Add a Correlation to the SourceInfo.
    */
   public void addCorrelation(Correlation c) {
-    if (!isAlreadyInAllCorrelations(c)) {
-      allCorrelations.add(c);
+    if (primaryCorrelations == null) {
+      primaryCorrelations = new Correlation[NUM_AXES];
     }
-
     int index = c.getAxis().ordinal();
-    if (primaryCorrelations[index] == null) {
-      primaryCorrelations[index] = c;
-    }
+    primaryCorrelations[index] = c;
   }
 
-  /**
-   * Copy any Correlations from another SourceInfo node if there are no
-   * Correlations on this SourceInfo with the same Axis.
-   */
-  public void copyMissingCorrelationsFrom(SourceInfo other) {
-    EnumSet<Axis> toAdd = EnumSet.allOf(Axis.class);
-    for (Correlation c : allCorrelations) {
-      toAdd.remove(c.getAxis());
-    }
-
-    for (Correlation c : other.getAllCorrelations()) {
-      if (toAdd.contains(c.getAxis())) {
-        addCorrelation(c);
+  public Correlation getCorrelation(Axis axis) {
+    if (primaryCorrelations != null) {
+      Correlation c = primaryCorrelations[axis.ordinal()];
+      if (c != null) {
+        return c;
       }
     }
-  }
-
-  /**
-   * Returns all Correlations applied to this SourceInfo, its parent, additional
-   * ancestor SourceInfo, and any supertype SourceInfos.
-   */
-  public List<Correlation> getAllCorrelations() {
-    return allCorrelations;
-  }
-
-  /**
-   * Returns all Correlations along a given axis applied to this SourceInfo, its
-   * parent, additional ancestor SourceInfo, and any supertype SourceInfos.
-   */
-  public List<Correlation> getAllCorrelations(Axis axis) {
-    List<Correlation> toReturn = new ArrayList<Correlation>();
-    for (Correlation c : getAllCorrelations()) {
-      if (c.getAxis() == axis) {
-        toReturn.add(c);
-      }
+    if (parent != null) {
+      return parent.getCorrelation(axis);
     }
-    return toReturn;
+    return null;
   }
 
-  public CorrelationFactory getCorrelationFactory() {
+  public Correlation[] getCorrelations() {
+    if (parent == null) {
+      if (primaryCorrelations == null) {
+        return new Correlation[NUM_AXES];
+      } else {
+        return primaryCorrelations.clone();
+      }
+    } else {
+      Correlation[] result = parent.getCorrelations();
+      if (primaryCorrelations != null) {
+        for (int i = 0; i < NUM_AXES; ++i) {
+          Correlation c = primaryCorrelations[i];
+          if (c != null) {
+            result[i] = c;
+          }
+        }
+      }
+      return result;
+    }
+  }
+
+  public CorrelationFactory getCorrelator() {
     return RealCorrelationFactory.INSTANCE;
   }
 
@@ -138,32 +118,6 @@
     return origin;
   }
 
-  /**
-   * Returns the first Correlation that had been set with a given Axis, or
-   * <code>null</code> if no Correlation has been set on the given axis.
-   */
-  public Correlation getPrimaryCorrelation(Axis axis) {
-    return primaryCorrelations[axis.ordinal()];
-  }
-
-  /**
-   * Returns the first Correlations added along each Axis on which a Correlation
-   * has been set.
-   */
-  public Set<Correlation> getPrimaryCorrelations() {
-    HashSet<Correlation> toReturn = new HashSet<Correlation>();
-    for (Correlation c : primaryCorrelations) {
-      if (c != null) {
-        toReturn.add(c);
-      }
-    }
-    return toReturn;
-  }
-
-  public Correlation[] getPrimaryCorrelationsArray() {
-    return primaryCorrelations;
-  }
-
   public int getStartLine() {
     return getOrigin().getStartLine();
   }
@@ -172,12 +126,6 @@
     return getOrigin().getStartPos();
   }
 
-  /**
-   * If data accumulation is enabled, create a derived SourceInfo object that
-   * indicates that one or more AST nodes were merged to create a new node. The
-   * derived node will inherit its Origin and Correlations from the SourceInfo
-   * object on which the method is invoked.
-   */
   public SourceInfo makeChild() {
     return new SourceInfoCorrelation(this, this.origin);
   }
@@ -186,46 +134,8 @@
     return new SourceInfoCorrelation(this, origin);
   }
 
-  /**
-   * Add additional ancestor SourceInfos. These SourceInfo objects indicate that
-   * a merge-type operation took place or that the additional ancestors have a
-   * containment relationship with the SourceInfo.
-   */
-  public void merge(SourceInfo... sourceInfos) {
-    for (SourceInfo info : sourceInfos) {
-      if (this == info) {
-        continue;
-      }
-
-      for (Correlation c : info.getAllCorrelations()) {
-        if (!isAlreadyInAllCorrelations(c)) {
-          allCorrelations.add(c);
-        }
-      }
-
-      for (Correlation c : info.getPrimaryCorrelations()) {
-        int i = c.getAxis().ordinal();
-        if (primaryCorrelations[i] == null) {
-          primaryCorrelations[i] = c;
-        }
-      }
-    }
-  }
-
   @Override
   public String toString() {
     return origin.toString();
   }
-
-  private boolean isAlreadyInAllCorrelations(Correlation c) {
-    // make sure this correlations is not yet in the allCorrelations list
-    boolean alreadyThere = false;
-    Iterator<Correlation> it = allCorrelations.iterator();
-    while ((alreadyThere == false) && (it.hasNext())) {
-      if (it.next().equals(c)) {
-        alreadyThere = true;
-      }
-    }
-    return alreadyThere;
-  }
 }
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 eaf3f8e..1a3b7d7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/SourceOrigin.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/SourceOrigin.java
@@ -21,10 +21,8 @@
 
 import java.util.Collections;
 import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 
 /**
  * Describes where a SourceInfo's node came from. This class currently includes
@@ -83,6 +81,8 @@
     }
   });
 
+  private static final Correlation[] NO_CORRELATIONS = new Correlation[0];
+
   /**
    * Creates SourceOrigin nodes.
    */
@@ -127,9 +127,6 @@
   public void addCorrelation(Correlation c) {
   }
 
-  public void copyMissingCorrelationsFrom(SourceInfo other) {
-  }
-
   @Override
   public boolean equals(Object o) {
     if (!(o instanceof SourceOrigin)) {
@@ -141,15 +138,15 @@
         && fileName.equals(other.fileName);
   }
 
-  public List<Correlation> getAllCorrelations() {
-    return Collections.emptyList();
+  public Correlation getCorrelation(Axis axis) {
+    return null;
   }
 
-  public List<Correlation> getAllCorrelations(Axis axis) {
-    return Collections.emptyList();
+  public Correlation[] getCorrelations() {
+    return NO_CORRELATIONS;
   }
 
-  public CorrelationFactory getCorrelationFactory() {
+  public CorrelationFactory getCorrelator() {
     return DummyCorrelationFactory.INSTANCE;
   }
 
@@ -165,18 +162,6 @@
     return this;
   }
 
-  public Correlation getPrimaryCorrelation(Axis axis) {
-    return null;
-  }
-
-  public Set<Correlation> getPrimaryCorrelations() {
-    return Collections.emptySet();
-  }
-
-  public Correlation[] getPrimaryCorrelationsArray() {
-    return new Correlation[0];
-  }
-
   public int getStartLine() {
     return startLine;
   }
@@ -199,9 +184,6 @@
     return origin;
   }
 
-  public void merge(SourceInfo... sourceInfos) {
-  }
-
   @Override
   public String toString() {
     return getFileName() + '(' + getStartLine() + ')';
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index 658fbd4..aa3977f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -337,11 +337,6 @@
 
   private final Map<JMethod, JMethod> instanceToStaticMap = new IdentityHashMap<JMethod, JMethod>();
 
-  /**
-   * The root intrinsic source info.
-   */
-  private final SourceInfo intrinsic;
-
   private IdentityHashMap<JReferenceType, JsonObject> castableTypeMaps;
 
   private JField nullField;
@@ -399,7 +394,6 @@
         JProgram.class.getName())));
 
     this.correlator = correlator;
-    intrinsic = createSourceInfo(0, getClass().getName());
   }
 
   public void addEntryMethod(JMethod entryPoint) {
@@ -801,10 +795,6 @@
     return type.getJavahSignatureName() + "_classLit";
   }
 
-  public CorrelationFactory getCorrelator() {
-    return correlator;
-  }
-
   public List<JDeclaredType> getDeclaredTypes() {
     return allTypes;
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
index 26c1558..d0c0a46 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
@@ -21,6 +21,7 @@
 import com.google.gwt.dev.jjs.HasSourceInfo;
 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.SourceOrigin;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JConstructor;
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
@@ -227,7 +228,7 @@
         JMethod newMethod = processMethodBinding(b, enclosingType, info);
         SourceInfo methodInfo = makeSourceInfo(methodDeclaration, newMethod);
         mapParameters(newMethod, methodDeclaration, methodInfo);
-        info.addCorrelation(program.getCorrelator().by(newMethod));
+        info.addCorrelation(info.getCorrelator().by(newMethod));
 
         if (newMethod.isNative()) {
           processNativeMethod(methodDeclaration, info, enclosingType, newMethod);
@@ -262,7 +263,7 @@
       JField field = program.createEnumField(info,
           String.valueOf(binding.name), (JEnumType) enclosingType,
           (JClassType) type, binding.original().id);
-      info.addCorrelation(program.getCorrelator().by(field));
+      info.addCorrelation(info.getCorrelator().by(field));
       typeMap.put(binding, field);
       return field;
     }
@@ -294,28 +295,22 @@
         HasSourceInfo enclosing) {
       int startLine = Util.getLineNumber(methodDecl.sourceStart,
           currentSeparatorPositions, 0, currentSeparatorPositions.length - 1);
-      SourceInfo toReturn = program.createSourceInfo(methodDecl.sourceStart,
+      SourceOrigin toReturn = SourceOrigin.create(methodDecl.sourceStart,
           methodDecl.bodyEnd, startLine, currentFileName);
-
-      // The SourceInfo will inherit Correlations from its enclosing object
       if (enclosing != null) {
-        toReturn.copyMissingCorrelationsFrom(enclosing.getSourceInfo());
+        return enclosing.getSourceInfo().makeChild(toReturn);
       }
-
       return toReturn;
     }
 
     private SourceInfo makeSourceInfo(Statement stmt, HasSourceInfo enclosing) {
       int startLine = Util.getLineNumber(stmt.sourceStart,
           currentSeparatorPositions, 0, currentSeparatorPositions.length - 1);
-      SourceInfo toReturn = program.createSourceInfo(stmt.sourceStart,
+      SourceOrigin toReturn = SourceOrigin.create(stmt.sourceStart,
           stmt.sourceEnd, startLine, currentFileName);
-
-      // The SourceInfo will inherit Correlations from its enclosing object
       if (enclosing != null) {
-        toReturn.copyMissingCorrelationsFrom(enclosing.getSourceInfo());
+        return enclosing.getSourceInfo().makeChild(toReturn);
       }
-
       return toReturn;
     }
 
@@ -581,9 +576,10 @@
     }
   }
 
-  private JDeclaredType createExternalType(String name,
-      ReferenceBinding binding) {
-    SourceInfo sourceInfo = makeBinarySourceInfo(binding, program);
+  private JDeclaredType createExternalType(String name, ReferenceBinding binding) {
+    char[] chars = binding.getFileName();
+    String fileName = chars == null ? "" : String.valueOf(chars);
+    SourceInfo sourceInfo = SourceOrigin.create(0, fileName);
     JDeclaredType type = createType(name, sourceInfo, binding);
     typeMap.put(binding, type);
     return type;
@@ -613,7 +609,7 @@
     JField field = program.createField(info, String.valueOf(binding.name),
         enclosingType, type, binding.isStatic(), disposition);
     typeMap.put(binding, field);
-    info.addCorrelation(program.getCorrelator().by(field));
+    info.addCorrelation(info.getCorrelator().by(field));
     return field;
   }
 
@@ -623,7 +619,7 @@
     SourceInfo info = enclosingType.getSourceInfo().makeChild();
     JField field = program.createField(info, String.valueOf(binding.name),
         enclosingType, type, false, disposition);
-    info.addCorrelation(program.getCorrelator().by(field));
+    info.addCorrelation(info.getCorrelator().by(field));
     if (binding.matchingField != null) {
       typeMap.put(binding.matchingField, field);
     }
@@ -709,7 +705,7 @@
           "ReferenceBinding is not a class, interface, or enum.");
     }
 
-    info.addCorrelation(program.getCorrelator().by(newType));
+    info.addCorrelation(info.getCorrelator().by(newType));
 
     /**
      * We emulate static initializers and instance initializers as methods.
@@ -722,7 +718,7 @@
         program.getTypeVoid(), false, true, true, true, false);
     clinit.freezeParamTypes();
     clinit.setSynthetic();
-    child.addCorrelation(program.getCorrelator().by(clinit));
+    child.addCorrelation(info.getCorrelator().by(clinit));
 
     if (newType instanceof JClassType) {
       child = info.makeChild();
@@ -730,7 +726,7 @@
           program.getTypeVoid(), false, false, true, true, false);
       init.freezeParamTypes();
       init.setSynthetic();
-      child.addCorrelation(program.getCorrelator().by(init));
+      child.addCorrelation(info.getCorrelator().by(init));
     }
 
     newType.setExternal(linker.isExternalType(newType.getName()));
@@ -778,13 +774,6 @@
     return type;
   }
 
-  private SourceInfo makeBinarySourceInfo(ReferenceBinding typeBinding,
-      JProgram program) {
-    char[] chars = typeBinding.getFileName();
-    String fileName = chars == null ? "" : String.valueOf(chars);
-    return program.createSourceInfo(-1, fileName);
-  }
-
   private void mapParameters(JMethod method, AbstractMethodDeclaration x,
       SourceInfo info) {
     MethodBinding b = x.binding;
@@ -824,7 +813,7 @@
         assert (type.getMethods().get(2) == getClassMethod);
         getClassMethod.freezeParamTypes();
         getClassMethod.setSynthetic();
-        info.addCorrelation(program.getCorrelator().by(getClassMethod));
+        info.addCorrelation(info.getCorrelator().by(getClassMethod));
       }
 
       if (binding.isNestedType() && !binding.isStatic()
@@ -943,7 +932,7 @@
 
     addThrownExceptions(b, newCtor);
 
-    info.addCorrelation(program.getCorrelator().by(newCtor));
+    info.addCorrelation(info.getCorrelator().by(newCtor));
 
     if (declaringClass.isNestedType() && !declaringClass.isStatic()) {
       // add synthetic args for locals
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index a346f4c..f727a48 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -2126,7 +2126,7 @@
       }
       addThrownExceptions(jdtBridgeMethod, bridgeMethod);
       bridgeMethod.freezeParamTypes();
-      info.addCorrelation(program.getCorrelator().by(bridgeMethod));
+      info.addCorrelation(info.getCorrelator().by(bridgeMethod));
 
       // create a call
       JMethodCall call = new JMethodCall(info, new JThisRef(info, clazz),
@@ -2472,13 +2472,10 @@
     private SourceInfo makeSourceInfo(Statement x) {
       int startLine = Util.getLineNumber(x.sourceStart,
           currentSeparatorPositions, 0, currentSeparatorPositions.length - 1);
-      SourceInfo toReturn = program.createSourceInfo(x.sourceStart,
-          x.sourceEnd, startLine, currentFileName);
-      if (currentClass != null) {
-        toReturn.copyMissingCorrelationsFrom(currentClass.getSourceInfo());
-      }
+      SourceOrigin toReturn = SourceOrigin.create(x.sourceStart, x.sourceEnd,
+          startLine, currentFileName);
       if (currentMethod != null) {
-        toReturn.copyMissingCorrelationsFrom(currentMethod.getSourceInfo());
+        return currentMethod.getSourceInfo().makeChild(toReturn);
       }
       return toReturn;
     }
@@ -2859,12 +2856,12 @@
         SourceInfo typeInfo = type.getSourceInfo().makeChild();
         JClassType mapClass = program.createClass(typeInfo, type.getName()
             + "$Map", false, true);
-        typeInfo.addCorrelation(program.getCorrelator().by(mapClass));
+        typeInfo.addCorrelation(typeInfo.getCorrelator().by(mapClass));
         mapClass.setSuperClass(program.getTypeJavaLangObject());
         SourceInfo fieldInfo = typeInfo.makeChild();
         mapField = program.createField(fieldInfo, "$MAP", mapClass,
             program.getJavaScriptObject(), true, Disposition.FINAL);
-        fieldInfo.addCorrelation(program.getCorrelator().by(mapField));
+        fieldInfo.addCorrelation(fieldInfo.getCorrelator().by(mapField));
 
         SourceInfo methodInfo = typeInfo.makeChild();
         JMethodCall call = new JMethodCall(methodInfo, null,
@@ -2876,7 +2873,7 @@
         JMethod clinit = program.createMethod(methodInfo, "$clinit", mapClass,
             program.getTypeVoid(), false, true, true, true, false);
         clinit.freezeParamTypes();
-        methodInfo.addCorrelation(program.getCorrelator().by(clinit));
+        methodInfo.addCorrelation(methodInfo.getCorrelator().by(clinit));
         JBlock clinitBlock = ((JMethodBody) clinit.getBody()).getBlock();
         clinitBlock.addStmt(declStmt);
         mapField.setInitializer(declStmt);
@@ -2907,7 +2904,7 @@
         JArrayType enumArrayType = program.getTypeArray(type);
         valuesField = program.createField(fieldInfo, "$VALUES", type,
             enumArrayType, true, Disposition.FINAL);
-        fieldInfo.addCorrelation(program.getCorrelator().by(valuesField));
+        fieldInfo.addCorrelation(fieldInfo.getCorrelator().by(valuesField));
         List<JExpression> initializers = new ArrayList<JExpression>();
         for (JEnumField field : type.getEnumList()) {
           JFieldRef fieldRef = new JFieldRef(fieldInfo, null, field, type);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
index 062c1b1..84cc483 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
@@ -144,7 +144,7 @@
     }
     newMethod.freezeParamTypes();
     newMethod.addThrownExceptions(objectMethod.getThrownExceptions());
-    sourceInfo.addCorrelation(program.getCorrelator().by(newMethod));
+    sourceInfo.addCorrelation(sourceInfo.getCorrelator().by(newMethod));
 
     // Build from bottom up.
     JMethodCall condition = new JMethodCall(sourceInfo, null,
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
index b9ce5aa..0e9345a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
@@ -173,7 +173,6 @@
       originalParamTypes.add(enclosingType.getNonNull());
       originalParamTypes.addAll(x.getOriginalParamTypes());
       newMethod.setOriginalTypes(x.getOriginalReturnType(), originalParamTypes);
-      sourceInfo.addCorrelation(program.getCorrelator().by(newMethod));
 
       // Move the body of the instance method to the static method
       JAbstractMethodBody movedBody = x.getBody();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
index 6b82869..8054c63 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
@@ -223,7 +223,7 @@
         program.getTypeJavaLangObject().getNonNull(), false, true, true, false,
         false);
     toReturn.freezeParamTypes();
-    info.addCorrelation(program.getCorrelator().by(toReturn));
+    info.addCorrelation(info.getCorrelator().by(toReturn));
     rebindMethods.put(requestType, toReturn);
 
     // Used in the return statement at the end
diff --git a/dev/core/src/com/google/gwt/dev/js/JsParser.java b/dev/core/src/com/google/gwt/dev/js/JsParser.java
index 3e9c96c..2a7b218 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsParser.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsParser.java
@@ -252,7 +252,7 @@
 
       case TokenStream.STRING: {
         SourceInfo info = makeSourceInfoDistinct(node);
-        info.addCorrelation(info.getCorrelationFactory().by(Literal.STRING));
+        info.addCorrelation(info.getCorrelator().by(Literal.STRING));
         return new JsStringLiteral(info, node.getString());
       }
 
diff --git a/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java b/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java
index 4d6434c..d867d7b 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java
@@ -646,7 +646,6 @@
           StringBuilder result = new StringBuilder();
           if (appendLiteral(result, (JsValueLiteral) arg1)
               && appendLiteral(result, (JsValueLiteral) arg2)) {
-            info.merge(arg1.getSourceInfo(), arg2.getSourceInfo());
             ctx.replaceMe(new JsStringLiteral(info, result.toString()));
           }
         }