After an enum is ordinalized, any static methods generated as staticImpl's should no longer be considered as such, since there is no longer an instantated instance being passed as the first arg to the method (this instance has been transformed into an ordinal int).
This was causing some clinit's not to be generated, since method calls to staticImpl's don't force a clinit, since it is assumed that the passed in instance argument will cause the clinit to be generated.
Review at http://gwt-code-reviews.appspot.com/1467815
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10440 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 1363eb8..dfb9119 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
@@ -1017,6 +1017,13 @@
this.typesByQueryId = typesByQueryId;
}
+ public void removeStaticImplMapping(JMethod staticImpl) {
+ JMethod instanceMethod = staticToInstanceMap.remove(staticImpl);
+ if (instanceMethod != null) {
+ instanceToStaticMap.remove(instanceMethod);
+ }
+ }
+
public void setRunAsyncs(List<JRunAsync> runAsyncs) {
this.runAsyncs = Lists.normalizeUnmodifiable(runAsyncs);
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java
index c0e5a90..76ee2be 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java
@@ -663,10 +663,24 @@
return false;
}
- // cleanup clinit method for ordinalizable enums
if (canBeOrdinal(x)) {
- // method 0 is always the clinit
+ /*
+ * Cleanup clinit method for ordinalizable enums. Note, method 0 is
+ * always the clinit.
+ */
updateClinit(x.getMethods().get(0));
+
+ /*
+ * Remove any static impl mappings for any methods in an ordinal enum
+ * class. An ordinalized enum will no longer have an instance passed as
+ * the first argument for a static impl (it will just be an int). This
+ * is needed to preserve proper assumptions about static impls by other
+ * optimizers (e.g. we might need to insert a clinit, when it wouldn't
+ * be needed if a method call still had a static impl target).
+ */
+ for (JMethod method : x.getMethods()) {
+ program.removeStaticImplMapping(method);
+ }
}
return true;
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/EnumsTest.java b/user/test/com/google/gwt/dev/jjs/test/EnumsTest.java
index f27ddf7..f93f983 100644
--- a/user/test/com/google/gwt/dev/jjs/test/EnumsTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/EnumsTest.java
@@ -83,6 +83,40 @@
}
}
+ /*
+ * An enum that will have a static impl generated, which will allow it to
+ * become ordinalizable. Once ordinalized, need to make sure it's clinit
+ * is handled properly.
+ */
+ enum EnumWithStaticImpl {
+ VALUE1;
+
+ // a mock formatter, to simulate the case that inspired this test
+ private static class MockFormat {
+ private String pattern;
+
+ public MockFormat(String pattern) {
+ this.pattern = pattern;
+ }
+
+ public String format(Long date) {
+ return pattern + date.toString();
+ }
+ }
+
+ private static final MockFormat FORMATTER = new MockFormat("asdf");
+
+ public String formatDate(long date) {
+ switch (this) {
+ case VALUE1:
+ return FORMATTER.format(new Long(date));
+ default:
+ return null;
+ }
+ }
+ }
+
+ @Override
public String getModuleName() {
return "com.google.gwt.dev.jjs.EnumsSuite";
}
@@ -231,6 +265,7 @@
}
try {
+ @SuppressWarnings("all")
Class fakeEnumClass = String.class;
Enum.valueOf(fakeEnumClass, "foo");
fail("Passed a non enum class to Enum.valueOf; expected "
@@ -283,7 +318,22 @@
assertEquals(Subclassing.B, subs[1]);
assertEquals(Subclassing.C, subs[2]);
}
-
+
+ /*
+ * Test that a call to an enum instance method, which gets transformed to a
+ * static impl, produces valid executable javascript, once the enum gets
+ * ordinalized. This test is in response to a case where invalid javascript
+ * was being generated, by not generating a clinit for the enum prior to
+ * referencing a static impl method.
+ */
+ public void testEnumWithStaticImpl() {
+ EnumWithStaticImpl ewsi = EnumWithStaticImpl.VALUE1;
+ Long submitTime = new Long(1234567890);
+ String fmtDate = ewsi.formatDate(submitTime);
+ // we just need to make sure we get to this point without timing out
+ assertTrue(fmtDate != null);
+ }
+
private <T extends Enum<T>> void enumValuesTest(Class<T> enumClass) {
T[] constants = enumClass.getEnumConstants();
for (T constant : constants) {