Fix nondeterminism in JsDuplicateFunctionRemover.
JsDuplicateFunctionRemover is only used under some circumstances,
in particular requires compiler.stackMode=strip.
Bug: issue 8871.
Change-Id: I9ab1a85ea604a65e477c076b5e3028032ef61d8d
diff --git a/dev/core/src/com/google/gwt/dev/js/JsDuplicateFunctionRemover.java b/dev/core/src/com/google/gwt/dev/js/JsDuplicateFunctionRemover.java
index 7caf39b..d571ffd 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsDuplicateFunctionRemover.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsDuplicateFunctionRemover.java
@@ -25,11 +25,10 @@
import com.google.gwt.dev.js.ast.JsNameRef;
import com.google.gwt.dev.js.ast.JsProgram;
import com.google.gwt.dev.js.ast.JsVisitor;
-import com.google.gwt.dev.util.collect.IdentityHashSet;
import com.google.gwt.dev.util.collect.Stack;
+import com.google.gwt.thirdparty.guava.common.collect.Maps;
+import com.google.gwt.thirdparty.guava.common.collect.Sets;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
@@ -42,20 +41,19 @@
private class DuplicateFunctionBodyRecorder extends JsVisitor {
- private final Set<JsName> dontReplace = new IdentityHashSet<JsName>();
+ private final Set<JsName> dontReplace = Sets.newIdentityHashSet();
- private final Map<JsName, JsName> duplicateOriginalMap = new IdentityHashMap<JsName, JsName>();
+ private final Map<JsName, JsName> duplicateOriginalMap = Maps.newIdentityHashMap();
- private final Map<JsFunction, JsFunction> duplicateMethodOriginalMap = new IdentityHashMap<JsFunction, JsFunction>();
-
+ private final Map<JsFunction, JsFunction> duplicateMethodOriginalMap = Maps.newLinkedHashMap();
private final Stack<JsNameRef> invocationQualifiers = new Stack<JsNameRef>();
// static / global methods
- private final Map<String, JsName> uniqueBodies = new HashMap<String, JsName>();
+ private final Map<String, JsName> uniqueBodies = Maps.newHashMap();
// vtable methods
- private final Map<String, JsFunction> uniqueMethodBodies = new HashMap<String, JsFunction>();
+ private final Map<String, JsFunction> uniqueMethodBodies = Maps.newHashMap();
public DuplicateFunctionBodyRecorder() {
// Add sentinel to stop Stack.peek() from throwing exception.
@@ -245,7 +243,7 @@
DuplicateFunctionBodyRecorder dfbr = new DuplicateFunctionBodyRecorder();
dfbr.accept(fragment);
- Map<JsFunction, JsName> newNamesByHoistedFunction = new HashMap<JsFunction, JsName>();
+ Map<JsFunction, JsName> newNamesByHoistedFunction = Maps.newHashMap();
// Hoist all anonymous duplicate functions.
Map<JsFunction, JsFunction> dupMethodMap = dfbr.getDuplicateMethodMap();
for (JsFunction dupMethod : dupMethodMap.values()) {
diff --git a/dev/core/test/com/google/gwt/dev/CompilerTest.java b/dev/core/test/com/google/gwt/dev/CompilerTest.java
index 6696850..daa726f 100644
--- a/dev/core/test/com/google/gwt/dev/CompilerTest.java
+++ b/dev/core/test/com/google/gwt/dev/CompilerTest.java
@@ -45,6 +45,9 @@
public class CompilerTest extends ArgProcessorTestBase {
public static final String GWT_PERSISTENTUNITCACHE = "gwt.persistentunitcache";
+ public static final String HELLO_MODULE = "com.google.gwt.sample.hello.Hello";
+ public static final String HELLO_MODULE_STACKMODE_STRIP =
+ "com.google.gwt.sample.hello.Hello_stackMode_strip";
private final Compiler.ArgProcessor argProcessor;
private final CompilerOptionsImpl options = new CompilerOptionsImpl();
@@ -391,16 +394,22 @@
assertEquals(SourceLevel.JAVA7, SourceLevel.getBestMatchingVersion("1.7b3"));
}
+ public void testDeterministicBuild_Draft_StackModeStrip() throws
+ UnableToCompleteException, IOException {
+ assertDeterministicBuild(HELLO_MODULE_STACKMODE_STRIP, 0);
+ }
+
+ public void testDeterministicBuild_Optimized_StackModeStrip() throws
+ UnableToCompleteException, IOException {
+ assertDeterministicBuild(HELLO_MODULE_STACKMODE_STRIP, 9);
+ }
+
public void testDeterministicBuild_Draft() throws UnableToCompleteException, IOException {
- final CompilerOptionsImpl options = new CompilerOptionsImpl();
- options.setOptimizationLevel(0);
- assertDeterministicBuild(options);
+ assertDeterministicBuild(HELLO_MODULE, 0);
}
public void testDeterministicBuild_Optimized() throws UnableToCompleteException, IOException {
- final CompilerOptionsImpl options = new CompilerOptionsImpl();
- options.setOptimizationLevel(9);
- assertDeterministicBuild(options);
+ assertDeterministicBuild(HELLO_MODULE, 9);
}
// TODO(stalcup): add recompile tests for file deletion.
@@ -631,13 +640,17 @@
outputOption);
}
- private void assertDeterministicBuild(CompilerOptions options)
+ private void assertDeterministicBuild(String topLevelModule, int optimizationLevel)
throws UnableToCompleteException, IOException {
+
+ final CompilerOptionsImpl options = new CompilerOptionsImpl();
+ options.setOptimizationLevel(optimizationLevel);
+
File firstCompileWorkDir = Utility.makeTemporaryDirectory(null, "hellowork");
File secondCompileWorkDir = Utility.makeTemporaryDirectory(null, "hellowork");
String oldPersistentUnitCacheValue = System.setProperty(GWT_PERSISTENTUNITCACHE, "false");
try {
- options.addModuleName("com.google.gwt.sample.hello.Hello");
+ options.addModuleName(topLevelModule);
options.setWarDir(new File(firstCompileWorkDir, "war"));
options.setExtraDir(new File(firstCompileWorkDir, "extra"));
PrintWriterTreeLogger logger = new PrintWriterTreeLogger();
diff --git a/samples/hello/src/com/google/gwt/sample/hello/Hello_stackMode_strip.gwt.xml b/samples/hello/src/com/google/gwt/sample/hello/Hello_stackMode_strip.gwt.xml
new file mode 100644
index 0000000..95d6bc1
--- /dev/null
+++ b/samples/hello/src/com/google/gwt/sample/hello/Hello_stackMode_strip.gwt.xml
@@ -0,0 +1,19 @@
+<!-- -->
+<!-- Copyright 2014 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. -->
+
+<module rename-to="hello">
+ <inherits name="com.google.gwt.user.User"/>
+ <entry-point class="com.google.gwt.sample.hello.client.Hello"/>
+ <set-property name="compiler.stackMode" value="strip" />
+</module>