Moved CodeSplitter to before js optimizations.

- also eliminated indexed fields and functions in JsProgram.
- fixed an error due to the crossfragment reference computation
  being performed too early.

Change-Id: Id88f17697ec47326b5e5d9e9d3be8c25942a3881
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 b23739c..d3144d0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -381,7 +381,7 @@
 
       // TODO(stalcup): hide metrics gathering in a callback or subclass
       if (CoverageInstrumentor.isCoverageEnabled()) {
-        CoverageInstrumentor.exec(jsProgram, instrumentableLines);
+        CoverageInstrumentor.exec(jprogram, jsProgram, jjsmap, instrumentableLines);
       }
 
       // (6) Normalize the Js AST
@@ -389,17 +389,22 @@
 
       // TODO(stalcup): move to AST construction
       JsSymbolResolver.exec(jsProgram);
+
       if (options.getNamespace() == JsNamespaceOption.PACKAGE) {
         if (!jprogram.getRunAsyncs().isEmpty()) {
           options.setNamespace(JsNamespaceOption.NONE);
           logger.log(TreeLogger.Type.WARN,
               "Namespace option is not compatible with CodeSplitter, turning it off.");
         } else {
-          JsNamespaceChooser.exec(jsProgram, jjsmap);
+          JsNamespaceChooser.exec(jprogram, jsProgram, jjsmap);
         }
       }
 
       // TODO(stalcup): move to normalization
+      Pair<SyntheticArtifact, MultipleDependencyGraphRecorder> dependenciesAndRecorder =
+          splitJsIntoFragments(properties, permutationId, jjsmap);
+
+      // TODO(stalcup): move to normalization
       EvalFunctionsAtTopScope.exec(jsProgram, jjsmap);
 
       // (7) Optimize the JS AST.
@@ -413,13 +418,13 @@
       // Must run before code splitter and namer.
       JsStackEmulator.exec(jprogram, jsProgram, properties, jjsmap);
 
-      // TODO(stalcup): move to normalization
-      Pair<SyntheticArtifact, MultipleDependencyGraphRecorder> dependenciesAndRecorder =
-          splitJsIntoFragments(properties, permutationId, jjsmap);
-
       // TODO(stalcup): move to optimize.
       Map<JsName, JsLiteral> internedLiteralByVariableName = renameJsSymbols(properties, jjsmap);
 
+      // No new JsNames or references to JSNames can be introduced after this
+      // point.
+      HandleCrossFragmentReferences.exec(jsProgram, properties);
+
       // TODO(stalcup): move to normalization
       JsBreakUpLargeVarStatements.exec(jsProgram, properties.getConfigurationProperties());
 
@@ -599,12 +604,7 @@
     } else if (options.isSoycEnabled() || options.isJsonSoycEnabled()) {
       dependencyRecorder = recordNonSplitDependencies(new ByteArrayOutputStream());
     }
-    dependenciesAndRecorder = Pair.create(
-        dependencies, dependencyRecorder);
-
-    // No new JsNames or references to JSNames can be introduced after this
-    // point.
-    HandleCrossFragmentReferences.exec(jsProgram, properties);
+    dependenciesAndRecorder = Pair.create(dependencies, dependencyRecorder);
 
     return dependenciesAndRecorder;
   }
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 d710edc..3b33bdc 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
@@ -38,6 +38,7 @@
 import com.google.gwt.thirdparty.guava.common.collect.HashBiMap;
 import com.google.gwt.thirdparty.guava.common.collect.ImmutableList;
 import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap;
+import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet;
 import com.google.gwt.thirdparty.guava.common.collect.Iterables;
 import com.google.gwt.thirdparty.guava.common.collect.Lists;
 import com.google.gwt.thirdparty.guava.common.collect.Maps;
@@ -796,7 +797,8 @@
         + "either ImplementClassLiteralsAsField has not run yet or or there is an error computing"
         + "live class literals.";
 
-    return new JMethodCall(sourceInfo, null, getIndexedMethod("Array.getClassLiteralForArray"),
+    return new JMethodCall(sourceInfo, null, getIndexedMethod(
+        RuntimeConstants.ARRAY_GET_CLASS_LITERAL_FOR_ARRAY),
         new JFieldRef(sourceInfo, null,  leafTypeClassLiteralField,
             leafTypeClassLiteralField.getEnclosingType()), getLiteralInt(dimensions));
   }
@@ -852,8 +854,8 @@
     return field;
   }
 
-  public Collection<JField> getIndexedFields() {
-    return Collections.unmodifiableCollection(indexedFields.values());
+  public Set<JField> getIndexedFields() {
+    return ImmutableSet.copyOf(indexedFields.values());
   }
 
   public JMethod getIndexedMethod(String string) {
@@ -864,8 +866,8 @@
     return method;
   }
 
-  public Collection<JMethod> getIndexedMethods() {
-    return Collections.unmodifiableCollection(indexedMethods.values());
+  public Set<JMethod> getIndexedMethods() {
+    return ImmutableSet.copyOf(indexedMethods.values());
   }
 
   public JMethod getIndexedMethodOrNull(String string) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/RuntimeConstants.java b/dev/core/src/com/google/gwt/dev/jjs/ast/RuntimeConstants.java
index 8fe30e7..6698033 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/RuntimeConstants.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/RuntimeConstants.java
@@ -44,6 +44,8 @@
   public static final String COLLAPSED_PROPERTY_HOLDER_GET_PERMUTATION_ID
       = "CollapsedPropertyHolder.getPermutationId";
 
+  public static final String COVERAGE_UTIL_ON_BEFORE_UNLOAD = "CoverageUtil.onBeforeUnload";
+  public static final String COVERAGE_UTIL_COVER = "CoverageUtil.cover";
   public static final String COVERAGE_UTIL_COVERAGE = "CoverageUtil.coverage";
 
   public static final String ENUM_CREATE_VALUE_OF_MAP = "Enum.createValueOfMap";
@@ -65,6 +67,8 @@
   public static final String LONG_LIB_TO_INT = "LongLib.toInt";
   public static final String LONG_LIB_TO_STRING = "LongLib.toString";
 
+  public static final String MODULE_UTILS_GWT_ON_LOAD = "ModuleUtils.gwtOnLoad";
+
   public static final String OBJECT_CASTABLE_TYPE_MAP = "Object.castableTypeMap";
   public static final String OBJECT_CLAZZ = "Object.___clazz";
   public static final String OBJECT_GET_CLASS = "Object.getClass";
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/DefaultJsInteropExportsGenerator.java b/dev/core/src/com/google/gwt/dev/jjs/impl/DefaultJsInteropExportsGenerator.java
index b9ba337..f4fb795 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/DefaultJsInteropExportsGenerator.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/DefaultJsInteropExportsGenerator.java
@@ -19,9 +19,7 @@
 import com.google.gwt.dev.jjs.ast.JConstructor;
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JMember;
-import com.google.gwt.dev.jjs.ast.RuntimeConstants;
 import com.google.gwt.dev.js.ast.JsExpression;
-import com.google.gwt.dev.js.ast.JsFunction;
 import com.google.gwt.dev.js.ast.JsInvocation;
 import com.google.gwt.dev.js.ast.JsName;
 import com.google.gwt.dev.js.ast.JsNameRef;
@@ -29,7 +27,6 @@
 import com.google.gwt.dev.js.ast.JsStringLiteral;
 
 import java.util.List;
-import java.util.Map;
 
 /**
  * Responsible for handling @JsExport code generation for non-Closure formatted code.
@@ -45,14 +42,14 @@
 
   private final List<JsStatement> exportStmts;
   private final JsName globalTemp;
-  private final JsName provideFunc;
+  private final JsName provideFuncionName;
   private String lastExportedNamespace;
 
   public DefaultJsInteropExportsGenerator(List<JsStatement> exportStmts, JsName globalTemp,
-      Map<String, JsFunction> indexedFunctions) {
+      JsName provideFunctionName) {
     this.exportStmts = exportStmts;
     this.globalTemp = globalTemp;
-    this.provideFunc = indexedFunctions.get(RuntimeConstants.RUNTIME_PROVIDE).getName();
+    this.provideFuncionName = provideFunctionName;
   }
 
   @Override
@@ -96,7 +93,7 @@
     // _ = JCHSU.provide('foo.bar')
     SourceInfo sourceInfo = member.getSourceInfo();
     JsInvocation provideCall = new JsInvocation(sourceInfo);
-    provideCall.setQualifier(provideFunc.makeRef(sourceInfo));
+    provideCall.setQualifier(provideFuncionName.makeRef(sourceInfo));
     provideCall.getArguments().add(new JsStringLiteral(sourceInfo, namespace));
     if (ctor != null) {
       provideCall.getArguments().add(ctor);
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 4cd3402..1ce0f44 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
@@ -246,9 +246,6 @@
                 : scopeStack.peek().declareName(mangleName(x), x.getName());
       }
       names.put(x, jsName);
-      if (program.getIndexedFields().contains(x)) {
-        indexedFields.put(JjsUtils.getIndexedName(x), jsName);
-      }
       recordSymbol(x, jsName);
     }
 
@@ -424,10 +421,6 @@
       jsFunctionsByJavaMethodBody.put(x.getBody(), function);
       scopeStack.push(function.getScope());
 
-      if (program.getIndexedMethods().contains(x)) {
-        indexedFunctions.put(JjsUtils.getIndexedName(x), function);
-      }
-
       // Don't traverse the method body of methods in referenceOnly types since those method bodies
       // only exist in JS output of other modules it is their responsibility to handle their naming.
       return !program.isReferenceOnly(x.getEnclosingType());
@@ -1239,7 +1232,8 @@
       //  Perform necessary polyfills.
       addTypeDefinitionStatement(
           program.getIndexedType(RuntimeConstants.RUNTIME),
-          constructInvocation(program.getSourceInfo(), RuntimeConstants.RUNTIME_BOOTSTRAP).makeStmt());
+          constructInvocation(program.getSourceInfo(), RuntimeConstants.RUNTIME_BOOTSTRAP)
+              .makeStmt());
 
       Set<JDeclaredType> alreadyProcessed =
           Sets.<JDeclaredType>newLinkedHashSet(program.immortalCodeGenTypes);
@@ -1287,8 +1281,10 @@
           continue;
         }
 
-        JsExpression protoRef = getPrototypeQualifierOf(type, type.getSourceInfo());
-        JsNameRef clazzField = indexedFields.get("Object.___clazz").makeRef(type.getSourceInfo());
+        SourceInfo sourceInfo = type.getSourceInfo();
+        JsExpression protoRef = getPrototypeQualifierOf(type, sourceInfo);
+        JsNameRef clazzField =
+            getIndexedFieldJsName(RuntimeConstants.OBJECT_CLAZZ).makeRef(sourceInfo);
         clazzField.setQualifier(protoRef);
         JsExprStmt stmt = createAssignment(clazzField, classLiteralRef).makeStmt();
         addTypeDefinitionStatement(type, stmt);
@@ -1451,8 +1447,8 @@
       JsInteropExportsGenerator exportGenerator =
           closureCompilerFormatEnabled
               ? new ClosureJsInteropExportsGenerator(getGlobalStatements(), names)
-              : new DefaultJsInteropExportsGenerator(
-                  getGlobalStatements(), globalTemp, indexedFunctions);
+              : new DefaultJsInteropExportsGenerator(getGlobalStatements(), globalTemp,
+                  getIndexedMethodJsName(RuntimeConstants.RUNTIME_PROVIDE));
 
       // Gather exported things in JsNamespace order.
       for (JDeclaredType type : program.getDeclaredTypes()) {
@@ -1624,7 +1620,7 @@
               if (jsName == null) {
                 // this can occur when JSNI references an instance method on a
                 // type that was never actually instantiated.
-                jsName = indexedFunctions.get(RuntimeConstants.RUNTIME_EMPTY_METHOD).getName();
+                jsName = getIndexedMethodJsName(RuntimeConstants.RUNTIME_EMPTY_METHOD);
               }
               x.resolve(jsName);
             }
@@ -1782,9 +1778,7 @@
 
     private JsExpression generateCastableTypeMap(JDeclaredType type) {
       JCastMap castMap = program.getCastMap(type);
-      JField castableTypeMapField = program.getIndexedField(
-          RuntimeConstants.OBJECT_CASTABLE_TYPE_MAP);
-      JsName castableTypeMapName = names.get(castableTypeMapField);
+      JsName castableTypeMapName = getIndexedFieldJsName(RuntimeConstants.OBJECT_CASTABLE_TYPE_MAP);
 
       if (castMap != null && castableTypeMapName != null) {
         return transform(castMap);
@@ -1883,7 +1877,7 @@
       JsName gwtOnLoad = topScope.findExistingUnobfuscatableName("gwtOnLoad");
       JsVar varGwtOnLoad = new JsVar(sourceInfo, gwtOnLoad);
       varGwtOnLoad.setInitExpr(createAssignment(gwtOnLoad.makeRef(sourceInfo),
-          indexedFunctions.get("ModuleUtils.gwtOnLoad").getName().makeRef(sourceInfo)));
+          getIndexedMethodJsName(RuntimeConstants.MODULE_UTILS_GWT_ON_LOAD).makeRef(sourceInfo)));
       getGlobalStatements().add(new JsVars(sourceInfo, varGwtOnLoad));
 
       // ModuleUtils.addInitFunctions(init1, init2,...)
@@ -1945,8 +1939,8 @@
      */
     private JsInvocation constructInvocation(SourceInfo sourceInfo,
         String indexedFunctionName, List<JsExpression> args) {
-      JsFunction functionToInvoke = indexedFunctions.get(indexedFunctionName);
-      return new JsInvocation(sourceInfo, functionToInvoke, args);
+      JsName functionToInvoke = getIndexedMethodJsName(indexedFunctionName);
+      return new JsInvocation(sourceInfo, functionToInvoke.makeRef(sourceInfo), args);
     }
 
     private void generateImmortalTypes(JsVars globals) {
@@ -2159,16 +2153,16 @@
     }
 
     private void setupTypeMarkerOnJavaLangObjectPrototype(JDeclaredType type) {
-      JsFunction typeMarkerMethod = indexedFunctions.get(RuntimeConstants.RUNTIME_TYPE_MARKER_FN);
+      JsName typeMarkerMethod = getIndexedMethodJsName(RuntimeConstants.RUNTIME_TYPE_MARKER_FN);
       generatePrototypeAssignmentForJavaField(type, RuntimeConstants.OBJECT_TYPEMARKER,
-          typeMarkerMethod.getName().makeRef(type.getSourceInfo()));
+          typeMarkerMethod.makeRef(type.getSourceInfo()));
     }
 
     private void generatePrototypeAssignmentForJavaField(JDeclaredType type, String javaField,
         JsExpression rhs) {
       SourceInfo sourceInfo = type.getSourceInfo();
       JsNameRef protoRef = getPrototypeQualifierOf(type, sourceInfo);
-      JsNameRef fieldRef = indexedFields.get(javaField).makeQualifiedRef(sourceInfo, protoRef);
+      JsNameRef fieldRef = getIndexedFieldJsName(javaField).makeQualifiedRef(sourceInfo, protoRef);
       addTypeDefinitionStatement(type, createAssignment(fieldRef, rhs).makeStmt());
     }
 
@@ -2213,8 +2207,7 @@
      */
     private void setupCastMapForUnboxedType(JDeclaredType type, String castMapField) {
       //  Cast.[castMapName] = /* cast map */ { ..:1, ..:1}
-      JField castableTypeMapField = program.getIndexedField(castMapField);
-      JsName castableTypeMapName = names.get(castableTypeMapField);
+      JsName castableTypeMapName = getIndexedFieldJsName(castMapField);
       JsNameRef castMapVarRef = castableTypeMapName.makeRef(type.getSourceInfo());
 
       JsExpression castMapLiteral = generateCastableTypeMap(type);
@@ -2265,7 +2258,7 @@
       // Some JS optimizers, e.g. the closure compiler, relies on this subtle difference for
       // obfuscating property names.
       JsNameRef definePropertyMethod =
-          indexedFunctions.get(RuntimeConstants.RUNTIME_DEFINE_PROPERTIES).getName().makeRef(sourceInfo);
+          getIndexedMethodJsName(RuntimeConstants.RUNTIME_DEFINE_PROPERTIES).makeRef(sourceInfo);
 
       JsObjectLiteral definePropertyLiteral =
           JsObjectLiteral.builder(sourceInfo)
@@ -2422,10 +2415,10 @@
       // mode the more costly Object constructor function is used as the noop method since doing so
       // provides a better debug experience that does not step into already used clinits.
 
-      JsFunction emptyFunctionFn = incremental ? objectConstructorFunction
-          : indexedFunctions.get(RuntimeConstants.RUNTIME_EMPTY_METHOD);
+      JsName emptyFunctionFnName = incremental ? objectConstructorFunction.getName()
+          : getIndexedMethodJsName(RuntimeConstants.RUNTIME_EMPTY_METHOD);
       JsExpression assignment = createAssignment(clinitFunction.getName().makeRef(sourceInfo),
-          emptyFunctionFn.getName().makeRef(sourceInfo));
+          emptyFunctionFnName.makeRef(sourceInfo));
       statements.add(0, assignment.makeStmt());
     }
 
@@ -2820,10 +2813,6 @@
    */
   private Set<JMethod> crossClassTargets = null;
 
-  private Map<String, JsFunction> indexedFunctions = Maps.newHashMap();
-
-  private Map<String, JsName> indexedFields = Maps.newHashMap();
-
   /**
    * Contains JsNames for all interface methods. A special scope is needed so
    * that independent classes will obfuscate their interface implementation
@@ -3023,9 +3012,6 @@
     new CreateNamesAndScopesVisitor().accept(program);
     new GenerateJavaScriptTransformer().transform(program);
 
-    jsProgram.setIndexedFields(indexedFields);
-    jsProgram.setIndexedFunctions(indexedFunctions);
-
     // TODO(spoon): Instead of gathering the information here, get it via
     // SourceInfo
     JavaToJavaScriptMap jjsMap = new JavaToJavaScriptMapImpl(program.getDeclaredTypes(),
@@ -3040,4 +3026,12 @@
   private JsFunction getJsFunctionFor(JMethod jMethod) {
     return jsFunctionsByJavaMethodBody.get(jMethod.getBody());
   }
+
+  private JsName getIndexedMethodJsName(String indexedName) {
+    return names.get(program.getIndexedMethod(indexedName));
+  }
+
+  private JsName getIndexedFieldJsName(String indexedName) {
+    return names.get(program.getIndexedField(indexedName));
+  }
 }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractor.java
index fa7eaa1..cd4efb1 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractor.java
@@ -25,13 +25,13 @@
 import com.google.gwt.dev.jjs.ast.RuntimeConstants;
 import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap;
 import com.google.gwt.dev.js.JsHoister.Cloner;
+import com.google.gwt.dev.js.JsUtils;
 import com.google.gwt.dev.js.ast.JsBinaryOperation;
 import com.google.gwt.dev.js.ast.JsBinaryOperator;
 import com.google.gwt.dev.js.ast.JsContext;
 import com.google.gwt.dev.js.ast.JsEmpty;
 import com.google.gwt.dev.js.ast.JsExprStmt;
 import com.google.gwt.dev.js.ast.JsExpression;
-import com.google.gwt.dev.js.ast.JsFunction;
 import com.google.gwt.dev.js.ast.JsInvocation;
 import com.google.gwt.dev.js.ast.JsModVisitor;
 import com.google.gwt.dev.js.ast.JsName;
@@ -148,12 +148,13 @@
     return minimalDefineClassStatement;
   }
 
-  private final JProgram jprogram;
-
   private final JsProgram jsprogram;
 
   private final JavaToJavaScriptMap map;
 
+  private final JsName asyncFragmentLoaderOnLoadFnName;
+  private final JsName defineClassFnName;
+
   private StatementLogger statementLogger = new StatementLogger() {
     @Override
     public void log(JsStatement statement, boolean include) {
@@ -161,20 +162,26 @@
   };
 
   public FragmentExtractor(JProgram jprogram, JsProgram jsprogram, JavaToJavaScriptMap map) {
-    this.jprogram = jprogram;
+    this(jsprogram, map,
+        JsUtils.getJsNameForMethod(map, jprogram, RuntimeConstants.ASYNC_FRAGMENT_LOADER_ON_LOAD),
+        JsUtils.getJsNameForMethod(map, jprogram, (RuntimeConstants.RUNTIME_DEFINE_CLASS)));
+  }
+
+  public FragmentExtractor(JsProgram jsprogram, JavaToJavaScriptMap map,
+      JsName asyncFragmentLoaderOnLoadFnName, JsName defineClassFnName) {
     this.jsprogram = jsprogram;
     this.map = map;
+    this.asyncFragmentLoaderOnLoadFnName = asyncFragmentLoaderOnLoadFnName;
+    this.defineClassFnName = defineClassFnName;
   }
 
   /**
    * Create a call to {@link AsyncFragmentLoader#onLoad}.
    */
   public List<JsStatement> createOnLoadedCall(int fragmentId) {
-    JMethod loadMethod = jprogram.getIndexedMethod(RuntimeConstants.ASYNC_FRAGMENT_LOADER_ON_LOAD);
-    JsName loadMethodName = map.nameForMethod(loadMethod);
     SourceInfo sourceInfo = jsprogram.getSourceInfo();
     JsInvocation call = new JsInvocation(sourceInfo);
-    call.setQualifier(wrapWithEntry(loadMethodName.makeRef(sourceInfo)));
+    call.setQualifier(wrapWithEntry(asyncFragmentLoaderOnLoadFnName.makeRef(sourceInfo)));
     call.getArguments().add(new JsNumberLiteral(sourceInfo, fragmentId));
     List<JsStatement> newStats = Collections.<JsStatement> singletonList(call.makeStmt());
     return newStats;
@@ -409,9 +416,7 @@
         return null;
       }
       JsNameRef func = (JsNameRef) call.getQualifier();
-      JsFunction defineClassJsFunc =
-          jsprogram.getIndexedFunction(RuntimeConstants.RUNTIME_DEFINE_CLASS);
-      if (func.getName() != defineClassJsFunc.getName()) {
+      if (func.getName() != defineClassFnName) {
         return null;
       }
       return map.typeForStatement(statement);
diff --git a/dev/core/src/com/google/gwt/dev/js/CoverageInstrumentor.java b/dev/core/src/com/google/gwt/dev/js/CoverageInstrumentor.java
index d7f7d84..9c7db5d 100644
--- a/dev/core/src/com/google/gwt/dev/js/CoverageInstrumentor.java
+++ b/dev/core/src/com/google/gwt/dev/js/CoverageInstrumentor.java
@@ -16,7 +16,9 @@
 package com.google.gwt.dev.js;
 
 import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.RuntimeConstants;
+import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap;
 import com.google.gwt.dev.js.ast.JsBinaryOperation;
 import com.google.gwt.dev.js.ast.JsBinaryOperator;
 import com.google.gwt.dev.js.ast.JsContext;
@@ -24,6 +26,7 @@
 import com.google.gwt.dev.js.ast.JsFunction;
 import com.google.gwt.dev.js.ast.JsInvocation;
 import com.google.gwt.dev.js.ast.JsModVisitor;
+import com.google.gwt.dev.js.ast.JsName;
 import com.google.gwt.dev.js.ast.JsNameRef;
 import com.google.gwt.dev.js.ast.JsNumberLiteral;
 import com.google.gwt.dev.js.ast.JsObjectLiteral;
@@ -64,15 +67,30 @@
         return;
       }
       JsInvocation update = new JsInvocation(info,
-          jsProgram.getIndexedFunction("CoverageUtil.cover"),
+          coverFnName.makeRef(info),
           new JsStringLiteral(info, info.getFileName()),
           new JsNumberLiteral(info, info.getStartLine()));
       ctx.replaceMe(new JsBinaryOperation(info, JsBinaryOperator.COMMA, update, x));
     }
   }
 
-  public static void exec(JsProgram jsProgram, Multimap<String, Integer> instrumentableLines) {
-    new CoverageInstrumentor(jsProgram, instrumentableLines).execImpl();
+  public static void exec(JProgram jprogram, JsProgram jsProgram, JavaToJavaScriptMap jjsmap,
+      Multimap<String, Integer> instrumentableLines) {
+
+    exec(jsProgram, instrumentableLines,
+        JsUtils
+            .getJsNameForMethod(jjsmap, jprogram, RuntimeConstants.COVERAGE_UTIL_ON_BEFORE_UNLOAD),
+        JsUtils.getJsNameForMethod(jjsmap, jprogram, RuntimeConstants.COVERAGE_UTIL_COVER),
+        JsUtils.getJsNameForField(jjsmap, jprogram, RuntimeConstants.COVERAGE_UTIL_COVERAGE));
+  }
+
+  @VisibleForTesting
+  static void exec(JsProgram jsProgram,
+      Multimap<String, Integer> instrumentableLines, JsName onBeforeUnloadFnName,
+      JsName coverFnName, JsName coverageFieldName) {
+
+    new CoverageInstrumentor(jsProgram, instrumentableLines, onBeforeUnloadFnName, coverFnName,
+        coverageFieldName).execImpl();
   }
 
   /**
@@ -95,17 +113,23 @@
 
   private Multimap<String, Integer> instrumentableLines;
   private JsProgram jsProgram;
+  private JsName onBeforeUnloadFnName;
+  private JsName coverFnName;
+  private JsName coverageFieldName;
 
-  private CoverageInstrumentor(JsProgram jsProgram, Multimap<String, Integer> instrumentableLines) {
+  private CoverageInstrumentor(JsProgram jsProgram, Multimap<String, Integer> instrumentableLines,
+      JsName onBeforeUnloadFnName, JsName coverFnName, JsName coverageFieldName) {
     this.instrumentableLines = instrumentableLines;
     this.jsProgram = jsProgram;
+    this.onBeforeUnloadFnName = onBeforeUnloadFnName;
+    this.coverFnName = coverFnName;
+    this.coverageFieldName = coverageFieldName;
   }
 
   private void addBeforeUnloadListener(SourceInfo info) {
     JsNameRef onbeforeunload = new JsNameRef(info, "onbeforeunload");
     onbeforeunload.setQualifier(new JsNameRef(info, "window"));
-    JsNameRef handler =
-        jsProgram.getIndexedFunction("CoverageUtil.onBeforeUnload").getName().makeRef(info);
+    JsNameRef handler = onBeforeUnloadFnName.makeRef(info);
     JsBinaryOperation assignment = new JsBinaryOperation(info, JsBinaryOperator.ASG,
         onbeforeunload, handler);
     jsProgram.getGlobalBlock().getStatements().add(assignment.makeStmt());
@@ -124,8 +148,7 @@
   }
 
   private void initializeBaselineCoverage(SourceInfo info) {
-    JsNameRef coverageObject =
-        jsProgram.getIndexedField(RuntimeConstants.COVERAGE_UTIL_COVERAGE).makeRef(info);
+    JsNameRef coverageObject = coverageFieldName.makeRef(info);
     JsBinaryOperation init = new JsBinaryOperation(info, JsBinaryOperator.ASG, coverageObject,
         baselineCoverage(info, instrumentableLines));
     jsProgram.getGlobalBlock().getStatements().add(init.makeStmt());
diff --git a/dev/core/src/com/google/gwt/dev/js/JsNamespaceChooser.java b/dev/core/src/com/google/gwt/dev/js/JsNamespaceChooser.java
index 86fd0af..0c47a8e 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsNamespaceChooser.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsNamespaceChooser.java
@@ -19,6 +19,7 @@
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JField;
 import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap;
 import com.google.gwt.dev.js.ast.JsBinaryOperation;
 import com.google.gwt.dev.js.ast.JsBinaryOperator;
@@ -50,11 +51,12 @@
  */
 public class JsNamespaceChooser {
 
-  public static void exec(JsProgram program, JavaToJavaScriptMap jjsmap) {
-    new JsNamespaceChooser(program, jjsmap).execImpl();
+  public static void exec(JProgram jprogram, JsProgram jsprogram, JavaToJavaScriptMap jjsmap) {
+    new JsNamespaceChooser(jprogram, jsprogram, jjsmap).execImpl();
   }
 
-  private final JsProgram program;
+  private final JProgram jprogram;
+  private final JsProgram jsprogram;
   private final JavaToJavaScriptMap jjsmap;
 
   /**
@@ -62,8 +64,9 @@
    */
   private final Map<String, JsName> packageToNamespace = Maps.newLinkedHashMap();
 
-  private JsNamespaceChooser(JsProgram program, JavaToJavaScriptMap jjsmap) {
-    this.program = program;
+  private JsNamespaceChooser(JProgram jprogram, JsProgram jsprogram, JavaToJavaScriptMap jjsmap) {
+    this.jsprogram = jsprogram;
+    this.jprogram = jprogram;
     this.jjsmap = jjsmap;
   }
 
@@ -72,7 +75,7 @@
     // First pass: visit each top-level statement in the program and move it if possible.
     // (This isn't a standard visitor because we don't want to recurse.)
 
-    List<JsStatement> globalStatements = program.getGlobalBlock().getStatements();
+    List<JsStatement> globalStatements = jsprogram.getGlobalBlock().getStatements();
     List<JsStatement> after = Lists.newArrayList();
     for (JsStatement before : globalStatements) {
       if (before instanceof JsVars) {
@@ -102,7 +105,7 @@
     globalStatements.addAll(after);
 
     // Second pass: fix all references for moved names.
-    new NameFixer().accept(program);
+    new NameFixer().accept(jsprogram);
   }
 
   /**
@@ -192,16 +195,13 @@
       return false; // not compiled from Java
     }
 
-    if (name.getStaticRef() instanceof JsFunction) {
-      JsFunction func = (JsFunction) name.getStaticRef();
-      if (program.isIndexedFunction(func)) {
-        return false; // may be called directly in another pass (for example JsStackEmulator).
-      }
+    if (isIndexedName(name)) {
+      return false; // may be called directly in another pass (for example JsStackEmulator).
     }
 
     JsName namespace = packageToNamespace.get(packageName);
     if (namespace == null) {
-      namespace = program.getScope().declareName(chooseUnusedName(packageName));
+      namespace = jsprogram.getScope().declareName(chooseUnusedName(packageName));
       packageToNamespace.put(packageName, namespace);
     }
 
@@ -209,11 +209,17 @@
     return true;
   }
 
+  private boolean isIndexedName(JsName name) {
+    return jprogram != null
+        && (jprogram.getIndexedMethods().contains(jjsmap.nameToMethod(name))
+            || jprogram.getIndexedFields().contains(jjsmap.nameToField(name)));
+  }
+
   private String chooseUnusedName(String packageName) {
     String initials = initialsForPackage(packageName);
     String candidate = initials;
     int counter = 1;
-    while (program.getScope().findExistingName(candidate) != null) {
+    while (jsprogram.getScope().findExistingName(candidate) != null) {
       counter++;
       candidate = initials + counter;
     }
diff --git a/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java b/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java
index 71c37d6..bb7f1ff 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java
@@ -22,6 +22,7 @@
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JMethod;
 import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.RuntimeConstants;
 import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap;
 import com.google.gwt.dev.js.ast.HasArguments;
 import com.google.gwt.dev.js.ast.HasName;
@@ -136,7 +137,7 @@
     }
 
     // caughtFunction is the JsFunction translated from Exceptions.wrap
-    if (name.getStaticRef() != wrapFunction) {
+    if (name != wrapFunctionName) {
       return false;
     }
     return true;
@@ -465,7 +466,7 @@
       JsName paramName = c.getParameter().getName();
 
       // wrap(e)
-      JsInvocation wrapCall = new JsInvocation(info, wrapFunction.getName().makeRef(info),
+      JsInvocation wrapCall = new JsInvocation(info, wrapFunctionName.makeRef(info),
           paramName.makeRef(info));
 
       // e = wrap(e)
@@ -966,7 +967,7 @@
     return StackMode.valueOf(value.toUpperCase(Locale.ROOT));
   }
 
-  private JsFunction wrapFunction;
+  private JsName wrapFunctionName;
   private JsName lineNumbers;
   private JProgram jprogram;
   private final JsProgram jsProgram;
@@ -1005,8 +1006,9 @@
   }
 
   private void execImpl() {
-    wrapFunction = jsProgram.getIndexedFunction("Exceptions.wrap");
-    if (wrapFunction == null) {
+    wrapFunctionName =
+        JsUtils.getJsNameForMethod(jjsmap, jprogram, RuntimeConstants.EXCEPTIONS_WRAP);
+    if (wrapFunctionName == null) {
       // No exceptions caught? Weird, but possible.
       return;
     }
diff --git a/dev/core/src/com/google/gwt/dev/js/JsUnusedFunctionRemover.java b/dev/core/src/com/google/gwt/dev/js/JsUnusedFunctionRemover.java
index 975d34a..007cf2a 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsUnusedFunctionRemover.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsUnusedFunctionRemover.java
@@ -48,8 +48,7 @@
       JsName name = f.getName();
 
       // Anonymous function, ignore it
-      if (name == null || seen.contains(name)
-          || program.getIndexedFunction("AsyncFragmentLoader.onLoad") == f) {
+      if (name == null || seen.contains(name)) {
         return;
       }
 
diff --git a/dev/core/src/com/google/gwt/dev/js/JsUtils.java b/dev/core/src/com/google/gwt/dev/js/JsUtils.java
index 9bceaae..97d9186 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsUtils.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsUtils.java
@@ -20,6 +20,8 @@
 import com.google.gwt.dev.jjs.ast.JMethod.JsPropertyAccessorType;
 import com.google.gwt.dev.jjs.ast.JParameter;
 import com.google.gwt.dev.jjs.ast.JPrimitiveType;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap;
 import com.google.gwt.dev.js.ast.JsBinaryOperation;
 import com.google.gwt.dev.js.ast.JsBinaryOperator;
 import com.google.gwt.dev.js.ast.JsBlock;
@@ -208,6 +210,16 @@
     return null;
   }
 
+  public static JsName getJsNameForMethod(JavaToJavaScriptMap jjsmap, JProgram jprogram,
+      String indexedMethodName) {
+    return jjsmap.nameForMethod(jprogram.getIndexedMethod(indexedMethodName));
+  }
+
+  public static JsName getJsNameForField(JavaToJavaScriptMap jjsmap, JProgram jprogram,
+      String indexedMethodName) {
+    return jjsmap.nameForField(jprogram.getIndexedField(indexedMethodName));
+  }
+
   public static boolean isEmpty(JsStatement stmt) {
     if (stmt == null) {
       return true;
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.java b/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.java
index b6518e4..477bde4 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.java
@@ -20,10 +20,6 @@
 
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
 
 /**
  * A JavaScript program.
@@ -34,12 +30,6 @@
 
   private JsProgramFragment[] fragments;
 
-  private final Map<String, JsName> indexedFields = new HashMap<String, JsName>();
-
-  private final Map<String, JsFunction> indexedFunctions = new HashMap<String, JsFunction>();
-
-  private final Set<JsFunction> indexedFunctionSet = new HashSet<JsFunction>();
-
   private final JsScope objectScope;
 
   private final JsScope topScope;
@@ -98,18 +88,6 @@
     return getFragmentBlock(0);
   }
 
-  public JsName getIndexedField(String name) {
-    return indexedFields.get(name);
-  }
-
-  public JsFunction getIndexedFunction(String name) {
-    return indexedFunctions.get(name);
-  }
-
-  public boolean isIndexedFunction(JsFunction func) {
-    return indexedFunctionSet.contains(func);
-  }
-
   @Override
   public NodeKind getKind() {
     return NodeKind.PROGRAM;
@@ -133,18 +111,6 @@
     }
   }
 
-  public void setIndexedFields(Map<String, JsName> indexedFields) {
-    this.indexedFields.clear();
-    this.indexedFields.putAll(indexedFields);
-  }
-
-  public void setIndexedFunctions(Map<String, JsFunction> indexedFunctions) {
-    this.indexedFunctions.clear();
-    this.indexedFunctions.putAll(indexedFunctions);
-    this.indexedFunctionSet.clear();
-    this.indexedFunctionSet.addAll(indexedFunctions.values());
-  }
-
   @Override
   public void traverse(JsVisitor v, JsContext ctx) {
     if (v.visit(this, ctx)) {
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractorTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractorTest.java
index 1e3a8ad..556a294 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractorTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractorTest.java
@@ -24,21 +24,16 @@
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JField;
 import com.google.gwt.dev.jjs.ast.JMethod;
-import com.google.gwt.dev.jjs.ast.RuntimeConstants;
 import com.google.gwt.dev.jjs.impl.JJSTestBase;
 import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap;
 import com.google.gwt.dev.js.ast.JsExprStmt;
-import com.google.gwt.dev.js.ast.JsFunction;
 import com.google.gwt.dev.js.ast.JsInvocation;
 import com.google.gwt.dev.js.ast.JsName;
 import com.google.gwt.dev.js.ast.JsNameRef;
 import com.google.gwt.dev.js.ast.JsProgram;
-import com.google.gwt.dev.js.ast.JsRootScope;
 import com.google.gwt.dev.js.ast.JsStatement;
 
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 /**
  * Unit tests for {@link com.google.gwt.dev.jjs.impl.codesplitter.FragmentExtractor}.
@@ -185,19 +180,15 @@
       final JsName barConstructorName = new JsName(null, "Bar", "Bar");
       final JConstructor barConstructor =
           new JConstructor(nullSourceInfo, barType, AccessModifier.PUBLIC);
-      Map<String, JsFunction> functionsByName = new HashMap<String, JsFunction>();
-      functionsByName.put(RuntimeConstants.RUNTIME_DEFINE_CLASS,
-          new JsFunction(nullSourceInfo, new JsRootScope(), DEFINE_CLASS_FUNCTION_NAME));
 
       final JsExprStmt defineClassStatement = createDefineClassStatement(barConstructorName);
 
       JsProgram jsProgram = new JsProgram();
-      jsProgram.setIndexedFunctions(functionsByName);
       // Defines the entirety of the JS program being split, to be the one defineClass statement.
       jsProgram.getGlobalBlock().getStatements().add(defineClassStatement);
 
       JavaToJavaScriptMap map = new MockJavaToJavaScriptMap() {
-          @Override
+        @Override
         public JMethod nameToMethod(JsName name) {
           if (name == barConstructorName) {
             // Finds the Bar constructor by name.
@@ -206,7 +197,7 @@
           return null;
         }
 
-          @Override
+        @Override
         public JClassType typeForStatement(JsStatement statement) {
           if (statement == defineClassStatement) {
             // Indicates that Bar is the type associated with the defineClass statement.
@@ -215,7 +206,7 @@
           return null;
         }
       };
-      fragmentExtractor = new FragmentExtractor(null, jsProgram, map);
+      fragmentExtractor = new FragmentExtractor(jsProgram, map, null, DEFINE_CLASS_FUNCTION_NAME);
       constructorLivePredicate = new MockLivenessPredicate() {
           @Override
         public boolean isLive(JDeclaredType type) {
diff --git a/dev/core/test/com/google/gwt/dev/js/CoverageInstrumentorTest.java b/dev/core/test/com/google/gwt/dev/js/CoverageInstrumentorTest.java
index 1186b95..b4525fd 100644
--- a/dev/core/test/com/google/gwt/dev/js/CoverageInstrumentorTest.java
+++ b/dev/core/test/com/google/gwt/dev/js/CoverageInstrumentorTest.java
@@ -17,25 +17,23 @@
 package com.google.gwt.dev.js;
 
 import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.ast.RuntimeConstants;
 import com.google.gwt.dev.js.ast.JsBlock;
 import com.google.gwt.dev.js.ast.JsContext;
 import com.google.gwt.dev.js.ast.JsExprStmt;
 import com.google.gwt.dev.js.ast.JsExpression;
 import com.google.gwt.dev.js.ast.JsFunction;
-import com.google.gwt.dev.js.ast.JsName;
 import com.google.gwt.dev.js.ast.JsObjectLiteral;
 import com.google.gwt.dev.js.ast.JsProgram;
 import com.google.gwt.dev.js.ast.JsStatement;
 import com.google.gwt.thirdparty.guava.common.base.Splitter;
 import com.google.gwt.thirdparty.guava.common.collect.HashMultimap;
 import com.google.gwt.thirdparty.guava.common.collect.LinkedHashMultimap;
-import com.google.gwt.thirdparty.guava.common.collect.Maps;
 import com.google.gwt.thirdparty.guava.common.collect.Multimap;
 
 import junit.framework.TestCase;
 
 import java.io.StringReader;
-import java.util.Map;
 
 /**
  * Tests for CoverageInstrumentor.
@@ -48,8 +46,6 @@
   public void setUp() {
     program = new JsProgram();
     SourceInfo info = program.createSourceInfo(1, "Test.java");
-    program.setIndexedFields(fields("CoverageUtil.coverage"));
-    program.setIndexedFunctions(functions("CoverageUtil.cover", "CoverageUtil.onBeforeUnload"));
     JsBlock globalBlock = program.getGlobalBlock();
     JsFunction function = new JsFunction(info, program.getScope());
     functionBody = new JsBlock(info);
@@ -57,28 +53,12 @@
     globalBlock.getStatements().add(new JsExprStmt(info, function));
   }
 
-  private Map<String, JsName> fields(String... names) {
-    Map<String, JsName> fields = Maps.newHashMap();
-    for (String name : names) {
-      JsName n = program.getScope().declareName(name, name);
-      fields.put(name, n);
-    }
-    return fields;
-  }
-
-  private Map<String, JsFunction> functions(String... names) {
-    Map<String, JsFunction> funcs = Maps.newHashMap();
-    for (String name : names) {
-      JsFunction f = new JsFunction(program.getSourceInfo(), program.getScope());
-      f.setName(program.getScope().declareName(name));
-      funcs.put(name, f);
-    }
-    return funcs;
-  }
-
   private String instrument(String code) throws Exception {
     functionBody.getStatements().clear();
-    CoverageInstrumentor.exec(program, parse(code));
+    CoverageInstrumentor.exec(program, parse(code),
+        program.getScope().declareName(RuntimeConstants.COVERAGE_UTIL_ON_BEFORE_UNLOAD),
+        program.getScope().declareName(RuntimeConstants.COVERAGE_UTIL_COVER),
+        program.getScope().declareName(RuntimeConstants.COVERAGE_UTIL_COVERAGE));
     return functionBody.toSource().trim().replaceAll("\\s+", " ");
   }
 
diff --git a/dev/core/test/com/google/gwt/dev/js/JsNamespaceChooserTest.java b/dev/core/test/com/google/gwt/dev/js/JsNamespaceChooserTest.java
index 7c80806..dae9969 100644
--- a/dev/core/test/com/google/gwt/dev/js/JsNamespaceChooserTest.java
+++ b/dev/core/test/com/google/gwt/dev/js/JsNamespaceChooserTest.java
@@ -162,7 +162,7 @@
         typeForStatement, vtableInitForMethod);
 
     // Run it.
-    JsNamespaceChooser.exec(program, jjsmap);
+    JsNamespaceChooser.exec(null, program, jjsmap);
   }
 
   private static JsProgram parseJs(String js) throws IOException, JsParserException {
diff --git a/user/test/com/google/gwt/dev/jjs/test/RunAsyncTest.java b/user/test/com/google/gwt/dev/jjs/test/RunAsyncTest.java
index 04cb0b3..9f667cf 100644
--- a/user/test/com/google/gwt/dev/jjs/test/RunAsyncTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/RunAsyncTest.java
@@ -22,12 +22,16 @@
 import com.google.gwt.core.client.Scheduler.RepeatingCommand;
 import com.google.gwt.junit.client.GWTTestCase;
 
+import javaemul.internal.annotations.DoNotInline;
+
 /**
  * Tests runAsync in various ways.
  */
 public class RunAsyncTest extends GWTTestCase {
   private static final String HELLO = "hello";
 
+  private static final String LONG_INTERNED_STRING = "abcdefghijklmnopqrstuvwxyz";
+
   private static final int RUNASYNC_TIMEOUT = 10000;
 
   private static String staticWrittenInBaseButReadLater;
@@ -39,6 +43,11 @@
     return "com.google.gwt.dev.jjs.CompilerSuite";
   }
 
+  @DoNotInline
+  public String getTestString() {
+    return LONG_INTERNED_STRING;
+  }
+
   public void testBasic() {
     delayTestFinish(RUNASYNC_TIMEOUT);
 
@@ -56,6 +65,39 @@
   }
 
   /**
+   * Only tests the XSLinker/CrossSiteRunAsyncSuite.
+   * A string which is only referenced in > 0 fragment which gets interned needs to be
+   * processed by HandleCrossFragmentReferences, but JsLiteralInterner was running after
+   * HandleCrossFragmentReferences.
+   */
+  public void testHandleCrossFragmentReference() {
+    delayTestFinish(RUNASYNC_TIMEOUT);
+
+    GWT.runAsync(new RunAsyncCallback() {
+      @Override
+      public void onFailure(Throwable caught) {
+        throw new RuntimeException(caught);
+      }
+
+      @Override
+      public void onSuccess() {
+        assertEquals(LONG_INTERNED_STRING, getTestString());
+        GWT.runAsync(new RunAsyncCallback() {
+          @Override
+          public void onFailure(Throwable caught) {
+            throw new RuntimeException(caught);
+          }
+
+          @Override
+          public void onSuccess() {
+            assertEquals(LONG_INTERNED_STRING, getTestString());
+            finishTest();
+          }
+        });
+      }
+    });
+  }
+  /**
    * Unlike with pruning, writing to a field should rescue it for code-splitting
    * purposes.
    */