Per issue 3455, split up very long var lines to avoid a bug in
the beta version of Safari 4.

This also adds a CompilerParameters module.  It looks useful for testing to be
able to tune way down compiler settings such as this one.

Review by: jgw



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5459 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/CompilePerms.java b/dev/core/src/com/google/gwt/dev/CompilePerms.java
index abf1646..e3bd98d 100644
--- a/dev/core/src/com/google/gwt/dev/CompilePerms.java
+++ b/dev/core/src/com/google/gwt/dev/CompilePerms.java
@@ -184,7 +184,8 @@
       Permutation permutation, UnifiedAst unifiedAst)
       throws UnableToCompleteException {
     return JavaToJavaScriptCompiler.compilePermutation(logger, unifiedAst,
-        permutation.getRebindAnswers(), permutation.getId());
+        permutation.getRebindAnswers(), permutation.getPropertyOracles(),
+        permutation.getId());
   }
 
   /**
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 4f60974..7b0de33 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.dev.jjs;
 
+import com.google.gwt.core.ext.PropertyOracle;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.linker.ArtifactSet;
@@ -81,6 +82,7 @@
 import com.google.gwt.dev.jjs.impl.TypeMap;
 import com.google.gwt.dev.jjs.impl.TypeTightener;
 import com.google.gwt.dev.js.EvalFunctionsAtTopScope;
+import com.google.gwt.dev.js.JsBreakUpLargeVarStatements;
 import com.google.gwt.dev.js.JsIEBlockSizeVisitor;
 import com.google.gwt.dev.js.JsInliner;
 import com.google.gwt.dev.js.JsNormalizer;
@@ -173,13 +175,14 @@
    *          {@link #precompile(TreeLogger, WebModeCompilerFrontEnd, String[], JJSOptions, boolean)}
    * @param rebindAnswers the set of rebind answers to resolve all outstanding
    *          rebind decisions
+   * @param propertyOracles All property oracles corresponding to this permutation.
    * @return the output JavaScript
    * @throws UnableToCompleteException if an error other than
    *           {@link OutOfMemoryError} occurs
    */
   public static PermutationResult compilePermutation(TreeLogger logger,
       UnifiedAst unifiedAst, Map<String, String> rebindAnswers,
-      int permutationId) throws UnableToCompleteException {
+      PropertyOracle[] propertyOracles, int permutationId) throws UnableToCompleteException {
     try {
       if (JProgram.isTracingEnabled()) {
         System.out.println("------------------------------------------------------------");
@@ -292,6 +295,8 @@
       // http://code.google.com/p/google-web-toolkit/issues/detail?id=1440
       JsIEBlockSizeVisitor.exec(jsProgram);
 
+      JsBreakUpLargeVarStatements.exec(jsProgram, propertyOracles);
+
       // (12) Generate the final output text.
       String[] js = new String[jsProgram.getFragmentCount()];
       List<Map<Range, SourceInfo>> sourceInfoMaps = options.isSoycEnabled()
diff --git a/dev/core/src/com/google/gwt/dev/js/JsBreakUpLargeVarStatements.java b/dev/core/src/com/google/gwt/dev/js/JsBreakUpLargeVarStatements.java
new file mode 100644
index 0000000..39b4132
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/js/JsBreakUpLargeVarStatements.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.js;
+
+import com.google.gwt.core.ext.BadPropertyValueException;
+import com.google.gwt.core.ext.ConfigurationProperty;
+import com.google.gwt.core.ext.PropertyOracle;
+import com.google.gwt.dev.jjs.InternalCompilerException;
+import com.google.gwt.dev.js.ast.JsContext;
+import com.google.gwt.dev.js.ast.JsModVisitor;
+import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsStatement;
+import com.google.gwt.dev.js.ast.JsVars;
+import com.google.gwt.dev.js.ast.JsVars.JsVar;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Divides large var statements into smaller ones. Very long var statements have
+ * trouble on some browsers, including the initial Safari 4 beta.  See Issue
+ * 3455.
+ */
+public class JsBreakUpLargeVarStatements extends JsModVisitor {
+  private static final String CONFIG_PROP_MAX_VARS = "compiler.max.vars.per.var";
+
+  public static void exec(JsProgram program, PropertyOracle[] propertyOracles) {
+    (new JsBreakUpLargeVarStatements(propertyOracles)).accept(program);
+  }
+
+  private static JsVars last(List<JsVars> list) {
+    return list.get(list.size() - 1);
+  }
+
+  private final int maxVarsPerStatement;
+
+  private JsBreakUpLargeVarStatements(PropertyOracle[] propertyOracles) {
+    maxVarsPerStatement = getMaxVarsPerStatement(propertyOracles[0]);
+  }
+
+  @Override
+  public void endVisit(JsVars x, JsContext<JsStatement> context) {
+    if (maxVarsPerStatement < 0) {
+      return;
+    }
+
+    if (x.getNumVars() > maxVarsPerStatement) {
+      // compute a list of smaller JsVars statements
+      List<JsVars> smallerVars = new ArrayList<JsVars>();
+      smallerVars.add(makeNewChildVars(x));
+
+      for (JsVar var : x) {
+        if (last(smallerVars).getNumVars() >= maxVarsPerStatement) {
+          // Previous statement is full; start a new one
+          smallerVars.add(makeNewChildVars(x));
+        }
+        last(smallerVars).add(var);
+      }
+
+      // replace x by the sequence smallerVars
+      for (JsVars sv : smallerVars) {
+        context.insertBefore(sv);
+      }
+      context.removeMe();
+    }
+  }
+
+  /**
+   * Look up in the specified property oracle the maximum number of variables to
+   * allow per var statement.
+   */
+  private int getMaxVarsPerStatement(PropertyOracle propertyOracle)
+      throws InternalCompilerException, NumberFormatException {
+    ConfigurationProperty prop;
+    try {
+      prop = propertyOracle.getConfigurationProperty(CONFIG_PROP_MAX_VARS);
+    } catch (BadPropertyValueException e) {
+      throw new InternalCompilerException("Could not find property "
+          + CONFIG_PROP_MAX_VARS, e);
+    }
+    int t = Integer.parseInt(prop.getValues().get(0));
+    return t;
+  }
+
+  /**
+   * Make a new, empty {@link JsVars} that is a child of x.
+   */
+  private JsVars makeNewChildVars(JsVars x) {
+    return new JsVars(x.getSourceInfo().makeChild(
+        JsBreakUpLargeVarStatements.class,
+        "breaking up a large vars statement into smaller ones"));
+  }
+}
diff --git a/user/src/com/google/gwt/core/CompilerParameters.gwt.xml b/user/src/com/google/gwt/core/CompilerParameters.gwt.xml
new file mode 100644
index 0000000..44cde7e
--- /dev/null
+++ b/user/src/com/google/gwt/core/CompilerParameters.gwt.xml
@@ -0,0 +1,26 @@
+<!--                                                                        -->
+<!-- Copyright 2009 Google Inc.                                             -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you    -->
+<!-- may not use this file except in compliance with the License. You may   -->
+<!-- may obtain a copy of the License at                                    -->
+<!--                                                                        -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0                             -->
+<!--                                                                        -->
+<!-- Unless required by applicable law or agreed to in writing, software    -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS,      -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        -->
+<!-- implied. License for the specific language governing permissions and   -->
+<!-- limitations under the License.                                         -->
+
+<!-- Compiler parameters that can be overridden for test cases .    -->
+<!--                                                                        -->
+<module>
+  <!--
+    This is the maximum number of variables in any var statement GWT
+    will emit. This avoids a bug in some browsers including
+    the initial beta of Safari 4. See Issue 3455. If it is set to -1,
+    then there is no limit.
+  -->
+  <define-configuration-property name='compiler.max.vars.per.var' is-multi-valued='false' />
+  <set-configuration-property name='compiler.max.vars.per.var' value='2400' />
+</module>
diff --git a/user/src/com/google/gwt/core/Core.gwt.xml b/user/src/com/google/gwt/core/Core.gwt.xml
index ad0a148..9f35631 100644
--- a/user/src/com/google/gwt/core/Core.gwt.xml
+++ b/user/src/com/google/gwt/core/Core.gwt.xml
@@ -21,16 +21,17 @@
   <inherits name="com.google.gwt.dev.jjs.intrinsic.Intrinsic" />
   <inherits name="com.google.gwt.emul.Emulation" />
   <inherits name="com.google.gwt.xhr.XMLHttpRequest" />
+  <inherits name="com.google.gwt.core.CompilerParameters" />
 
   <define-linker name="sso" class="com.google.gwt.core.linker.SingleScriptLinker" />
   <define-linker name="std" class="com.google.gwt.core.linker.IFrameLinker" />
-  <define-linker name="xs" class="com.google.gwt.core.linker.XSLinker" />

-

-  <define-linker name="soycReport" class="com.google.gwt.core.linker.SoycReportLinker" />

-  <define-linker name="symbolMaps" class="com.google.gwt.core.linker.SymbolMapsLinker" />

+  <define-linker name="xs" class="com.google.gwt.core.linker.XSLinker" />
+
+  <define-linker name="soycReport" class="com.google.gwt.core.linker.SoycReportLinker" />
+  <define-linker name="symbolMaps" class="com.google.gwt.core.linker.SymbolMapsLinker" />
 
   <add-linker name="std" />
-

-  <add-linker name="soycReport" />

-  <add-linker name="symbolMaps" />

+
+  <add-linker name="soycReport" />
+  <add-linker name="symbolMaps" />
 </module>
diff --git a/user/test/com/google/gwt/emultest/EmulSuite.gwt.xml b/user/test/com/google/gwt/emultest/EmulSuite.gwt.xml
index 2de2c30..e1de729 100644
--- a/user/test/com/google/gwt/emultest/EmulSuite.gwt.xml
+++ b/user/test/com/google/gwt/emultest/EmulSuite.gwt.xml
@@ -13,7 +13,13 @@
 <!-- limitations under the License.                                         -->
 
 <module>
-	<inherits name='com.google.gwt.junit.JUnit'/>
-	<inherits name='org.apache.commons.Collections'/>
-	<source path='java'/>
+  <inherits name='com.google.gwt.junit.JUnit' />
+  <inherits name='org.apache.commons.Collections' />
+  <source path='java' />
+
+  <!--
+    Specify some tighter compiler settings so that those compiler paths
+    are tested by the normal GWT regression suite
+  -->
+  <set-configuration-property name='compiler.max.vars.per.var' value='10' />
 </module>