Fix EnumOrdinalizer.

EnumOrdinalizer incorrectly selects enums for ordinalization
(replacement of the enum values by integer ordinals) under a
few circumstances.

Also:
 - fixed quite a few of the units tests.
 - allow ordinalization even with access to values().

Bug: issue 8846.
Change-Id: I9c22c1576a238d5f6b3a5f52b25b2ca697b83fad
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 2d988f5..4232ab8 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
@@ -37,6 +37,7 @@
 import com.google.gwt.dev.jjs.ast.JModVisitor;
 import com.google.gwt.dev.jjs.ast.JNewArray;
 import com.google.gwt.dev.jjs.ast.JNonNullType;
+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.ast.JStatement;
@@ -387,22 +388,6 @@
       if (x.getInstance() != null) {
         // check any instance field reference other than ordinal
         blackListIfEnumExpression(x.getInstance());
-      } else if (x.getField().isStatic()) {
-        /*
-         * Black list if the $VALUES static field is referenced, unless it's
-         * within the auto-generated clinit or values method, within the enum
-         * class itself.
-         *
-         * TODO (jbrosenberg): Investigate further whether referencing the
-         * $VALUES array (as well as the values() method) should not block
-         * ordinalization. Instead, convert $VALUES to an array of int.
-         */
-        if (x.getField().getName().equals(JEnumType.VALUES_ARRAY_NAME)
-            && ((this.currentMethod.getEnclosingType() != x.getField().getEnclosingType()) ||
-                (!this.currentMethod.getName().equals("values") &&
-                 !this.currentMethod.getName().equals("$clinit")))) {
-          blackListIfEnum(x.getField().getEnclosingType(), x.getSourceInfo());
-        }
       }
     }
 
@@ -429,9 +414,14 @@
       } else if (x.getTarget().isStatic()) {
         // black-list static method calls on an enum class only for valueOf()
         // and values()
-        String methodName = x.getTarget().getName();
-        if (methodName.equals("valueOf") || methodName.equals("values")) {
-          blackListIfEnum(x.getTarget().getEnclosingType(), x.getSourceInfo());
+        JMethod target = x.getTarget();
+        maybeBlackListDueToStaticCall(x.getSourceInfo(), target);
+      }
+
+      if (x.getTarget().isNative()) {
+        // Black list enum types declared in parameters of native functions.
+        for (JParameter parameter :x.getTarget().getParams()) {
+          blackListIfEnum(parameter.getType(), x.getSourceInfo());
         }
       }
 
@@ -478,15 +468,12 @@
       if (x.getInstance() != null) {
         blackListIfEnumExpression(x.getInstance());
       } else if (x.getTarget().isStatic()) {
-        /*
-         * need to exempt static methodCalls for an enum class if it occurs
-         * within the enum class itself (such as in $clinit() or values())
-         */
-        if (this.currentMethod.getEnclosingType() != x.getTarget().getEnclosingType()) {
-          blackListIfEnum(x.getTarget().getEnclosingType(), x.getSourceInfo());
-        }
+        maybeBlackListDueToStaticCall(x.getSourceInfo(), x.getTarget());
       }
 
+      // Black list enums returned to JSNI.
+      blackListIfEnum(x.getTarget().getType(), x.getSourceInfo());
+
       // defer to ImplicitUpcastAnalyzer to check method call args & params
       super.endVisit(x, ctx);
     }
@@ -608,7 +595,18 @@
         blackListIfEnum(instance.getType(), instance.getSourceInfo());
       }
     }
+
+    /**
+     * Blacklist the enum if there is a call to either MyEnum.valueOf() or MyEnum.values().
+     */
+    private void maybeBlackListDueToStaticCall(SourceInfo info, JMethod target) {
+      if (target.getEnclosingType().isEnumOrSubclass() != null &&
+          (target.getName().equals("valueOf") || target.getName().equals("values"))) {
+        blackListIfEnum(target.getEnclosingType(), info);
+      }
+    }
   }
+
   /**
    * A visitor which replaces enum types with an integer.
    *
@@ -730,20 +728,20 @@
       int removeIndex = 0;
       // Make a copy to avoid concurrent modification.
       for (JStatement stmt : new ArrayList<JStatement>(block.getStatements())) {
-        if (stmt instanceof JDeclarationStatement) {
-          JVariableRef ref = ((JDeclarationStatement) stmt).getVariableRef();
-          if (ref instanceof JFieldRef) {
-            JFieldRef enumRef = (JFieldRef) ref;
-            // See if LHS is a field ref to the class being initialized.
-            JField field = enumRef.getField();
-            if (field.isStatic() && field.getEnclosingType() == enclosingType) {
-              if (field instanceof JEnumField ||
-                  field.getName().equals(JEnumType.VALUES_ARRAY_NAME)) {
-                block.removeStmt(removeIndex--);
-                field.setInitializer(null);
-              }
-            }
-          }
+        if (!(stmt instanceof JDeclarationStatement)) {
+          continue;
+        }
+        JVariableRef ref = ((JDeclarationStatement) stmt).getVariableRef();
+        if (!(ref instanceof JFieldRef)) {
+          continue;
+        }
+
+        // See if LHS is a field ref to the class being initialized.
+        JField field = ((JFieldRef) ref).getField();
+        if (field.isStatic() && field.getEnclosingType() == enclosingType &&
+            field instanceof JEnumField) {
+          block.removeStmt(removeIndex--);
+          field.setInitializer(null);
         }
         ++removeIndex;
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index 1bc9168..d6957e3 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -2189,7 +2189,7 @@
     }
 
     private JField createEnumValuesField(JEnumType type) {
-      // $VALUES = new E[]{A,B,B};
+      // $VALUES = new E[]{A,B,C};
       JArrayType enumArrayType = new JArrayType(type);
       JField valuesField = new JField(type.getSourceInfo(), JEnumType.VALUES_ARRAY_NAME, type,
           enumArrayType, true, Disposition.FINAL);
diff --git a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
index b2f1795..fa09708 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -167,14 +167,17 @@
           "import com.google.gwt.core.client.JavaScriptObject;",
           "public abstract class Enum<E extends Enum<E>> implements Serializable {",
           "  public static native <T extends Enum<T>> T valueOf(Class<T> enumType,",
-          "      String name) /*-{ }-*/;",
+          "      String name) /*-{ return enumType + name; }-*/;",
+          "  public static native <T extends Enum<T>> T valueOf(JavaScriptObject enumType,",
+          "      String name) /*-{ return enumType + name; }-*/;",
           "  protected static native <T extends Enum<T>> JavaScriptObject createValueOfMap(",
           "      T[] enumConstants) /*-{ }-*/;",
-          "  protected static native <T extends Enum<T>> T valueOf(JavaScriptObject map,",
-          "      String name) /*-{ }-*/;",
-          "  protected Enum(String name, int ordinal) { ", "    this.name = name;",
-          "    this.ordinal = ordinal;}", "  private final String name;",
-          "  private final int ordinal;", "  public final String name() { return name; }",
+          "  protected Enum(String name, int ordinal) { ",
+          "    this.name = name;",
+          "    this.ordinal = ordinal;}",
+          "  private final String name;",
+          "  private final int ordinal;",
+          "  public final String name() { return name; }",
           "  public final int ordinal() { return ordinal; }",
           "}"
       );
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/EnumOrdinalizerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/EnumOrdinalizerTest.java
index 2d4710d..a653128 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/EnumOrdinalizerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/EnumOrdinalizerTest.java
@@ -21,20 +21,34 @@
 import com.google.gwt.dev.jjs.ast.JProgram;
 
 /**
- * A set of tests for the conditions under which ordinalization is and is not
- * allowed.  The ordinalization is performed when allowed.
+ * A set of tests for the conditions under which ordinalization is and is not allowed.  The
+ * ordinalization is performed when allowed.
  *
- * A complete test of the resulting ordinalization is not performed.  However,
- * the ImplementCastsAndTypeChecks and the EqualityNormalizer are run after the EnumOrdinalizer,
- * to help ensure the integrity of the AST, such that there are no partially
- * mismatched type assignments or comparisons, and that no binary operations
- * between a primitive type and null have been added.  Typically, such errors
- * introduced by the EnumOrdinalizer are caught by these normalizers, so it
- * makes sense to test the output in this way.  Thus, we provide confidence
- * that the AST is left in a coherent state, but it is not a complete test that
- * ordinalization has completed correctly in every respec.
+ * A complete test of the resulting ordinalization is not performed.  However, the
+ * ImplementCastsAndTypeChecks and the EqualityNormalizer are run after the EnumOrdinalizer, to help
+ * ensure the integrity of the AST, such that there are no partially mismatched type assignments or
+ * comparisons, and that no binary operations between a primitive type and null have been added.
+ * Typically, such errors introduced by the EnumOrdinalizer are caught by these normalizers, so it
+ * makes sense to test the output in this way.  Thus, we provide confidence that the AST is left in
+ * a coherent state, but it is not a complete test that ordinalization has completed correctly in
+ * every respec.
  */
 public class EnumOrdinalizerTest extends OptimizerTestBase {
+  /*
+   * Always run ImplementCastsAndTypeChecks and EqualityNormalizer, even in cases where we
+   * are testing that ordinalization cannot occur, since there may be other
+   * enums (such as DummyEnum) which do get ordinalized, and we want to test
+   * that all is well regardless.
+   */
+  private final boolean performCastReplacement = true;
+  private final boolean runEqualityNormalizer = true;
+  // These are enabled as needed for a given test
+  private boolean runMakeCallsStatic;
+  private boolean runMethodInliner;
+  private boolean runMethodCallTightener;
+  private boolean runPruner;
+  private boolean runTypeTightener;
+
   @Override
   protected void setUp() throws Exception {
     super.setUp();
@@ -46,6 +60,11 @@
     runMethodCallTightener = false;
     runMethodInliner = true;
     runMakeCallsStatic = true;
+    // Opportunities for ordinalization are only present after unused references to $VALUES are
+    // pruned.
+    // NOTE: because we are pruning, each test case needs to make sure that enums that are
+    // considered for ordinalization are still live.
+    runPruner = true;
   }
 
   @Override
@@ -54,45 +73,45 @@
   }
 
   public void testOrdinalizeBasicAssignment()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit apple = Fruit.APPLE;",
-                    "Fruit orange = Fruit.ORANGE;");
+        "Fruit orange = Fruit.ORANGE;");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
   public void testOrdinalizeNewArrayAndAssignmentLocalRef()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit[] fruits = new Fruit[] {Fruit.APPLE, Fruit.ORANGE, Fruit.APPLE};",
-                     "if (fruits[0] == Fruit.APPLE) {",
-                     "  fruits[0] = Fruit.ORANGE;",
-                     "}");
+        "if (fruits[0] == Fruit.APPLE) {",
+        "  fruits[0] = Fruit.ORANGE;",
+        "}");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
   public void testOrdinalizeNewArrayOfArrayAndAssignmentLocalRef()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit[][] fruits = new Fruit[][] ",
-                     " {{Fruit.APPLE, Fruit.ORANGE},{Fruit.APPLE, Fruit.ORANGE}};",
-                     "if (fruits[0][1] == Fruit.APPLE) {",
-                     "  fruits[0][1] = Fruit.ORANGE;",
-                     "}");
+        " {{Fruit.APPLE, Fruit.ORANGE},{Fruit.APPLE, Fruit.ORANGE}};",
+        "if (fruits[0][1] == Fruit.APPLE) {",
+        "  fruits[0][1] = Fruit.ORANGE;",
+        "}");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
   public void testOrdinalizeNewArrayAndAssignmentFieldRef()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("private final Fruit[] fruits = new Fruit[] ",
-                        "  {Fruit.APPLE, Fruit.ORANGE, Fruit.APPLE};");
+        "  {Fruit.APPLE, Fruit.ORANGE, Fruit.APPLE};");
     optimize("void", "EntryPoint ep = new EntryPoint();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
@@ -100,12 +119,12 @@
   }
 
   public void testOrdinalizableFinalFieldUninitializedByDefault()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("private final Fruit uninitializedFinalFruit;",
-                        "public EntryPoint() {",
-                        "  uninitializedFinalFruit = Fruit.ORANGE;",
-                        "}");
+        "public EntryPoint() {",
+        "  uninitializedFinalFruit = Fruit.ORANGE;",
+        "}");
     optimize("void", "EntryPoint ep = new EntryPoint();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
@@ -114,18 +133,18 @@
   }
 
   public void testOrdinalizeSwitchStatement()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     setupFruitSwitchMethod();
     optimize("void", "String apple = fruitSwitch(Fruit.APPLE);",
-                    "String orange = fruitSwitch(Fruit.ORANGE);");
+        "String orange = fruitSwitch(Fruit.ORANGE);");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
   public void testOrdinalizeIfStatement()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl(
         "public static String fruitIf(Fruit fruit) {",
@@ -138,14 +157,14 @@
         " }",
         "}");
     optimize("void", "String apple = fruitIf(Fruit.APPLE);",
-                    "String orange = fruitIf(Fruit.ORANGE);");
+        "String orange = fruitIf(Fruit.ORANGE);");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
   public void testOrdinalizeConditional()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit fruit = (true) ? Fruit.APPLE : Fruit.ORANGE;");
 
@@ -154,7 +173,7 @@
   }
 
   public void testOrdinalizeFieldRefOrdinalMethodCall()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "int i = Fruit.APPLE.ordinal();");
 
@@ -163,10 +182,10 @@
   }
 
   public void testOrdinalizeVariableRefOrdinalMethodCall()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit fruit = Fruit.APPLE;",
-                    "int i = fruit.ordinal();");
+        "int i = fruit.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
@@ -178,7 +197,8 @@
     optimize("void", "EmptyEnum myEnum;");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
-    assertTrue(tracker.isOrdinalized("test.EntryPoint$EmptyEnum"));
+    assertTrue(tracker.isOrdinalized("test.EntryPoint$EmptyEnum") ||
+        !tracker.isVisited("test.EntryPoint$EmptyEnum"));
   }
 
   public void testOrdinalizeUnusedEnum() throws UnableToCompleteException {
@@ -187,84 +207,98 @@
     optimize("void", "Fruit myEnum;");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
-    assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
+    assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit") ||
+        !tracker.isVisited("test.EntryPoint$Fruit"));
   }
 
   public void testOrdinalizeMethodCallExpressionOrdinalFieldRef()
       throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("public static Fruit getResolvedFruit(Fruit fruit) {",
-                        "  if (fruit == Fruit.APPLE) {",
-                        "    return Fruit.ORANGE;",
-                        "  } else { ",
-                        "    return Fruit.APPLE;",
-                        "  }",
-                        "}");
+        "  if (fruit == Fruit.APPLE) {",
+        "    return Fruit.ORANGE;",
+        "  } else { ",
+        "    return Fruit.APPLE;",
+        "  }",
+        "}");
     addSnippetClassDecl("public static int switchMethodCall(Fruit fruit) {",
-                        "  int retVal = 0;",
-                        "  switch (getResolvedFruit(fruit)) {",
-                        "    case APPLE: retVal = 12; break;",
-                        "    case ORANGE:retVal = 73; break;",
-                        "  }",
-                        "  return retVal;",
-                        "}");
+        "  int retVal = 0;",
+        "  switch (getResolvedFruit(fruit)) {",
+        "    case APPLE: retVal = 12; break;",
+        "    case ORANGE:retVal = 73; break;",
+        "  }",
+        "  return retVal;",
+        "}");
     optimize("void", "int i = switchMethodCall(Fruit.APPLE);",
-                    "Fruit fruit = Fruit.ORANGE;",
-                    "int j = switchMethodCall(fruit);");
+        "Fruit fruit = Fruit.ORANGE;",
+        "int j = switchMethodCall(fruit);");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
   public void testOrdinalizableStaticFieldRef()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     // this will cause a static field ref in the enum clinit
     setupFruitEnumWithStaticField();
-    optimize("void", "String y = Fruit.staticField;");
+    optimize("void", "String y = Fruit.staticField + Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
   public void testOrdinalizableStaticMethod()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     // this will cause a static method enum class
     setupFruitEnumWithStaticMethod();
-    optimize("void", "int y = Fruit.staticMethod();");
+    optimize("void", "int y = Fruit.staticMethod() + Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
-  public void testNotOrdinalizableStaticMethodThatRefsValuesArray()
-      throws UnableToCompleteException  {
-    // this will cause a static method that references an element
-    // of the values() array
-    setupFruitEnumWithStaticMethodThatRefsValuesArray();
-    optimize("void", "Fruit y = Fruit.forInteger(0);");
+  public void testOrdinalizableCallingValues()
+      throws UnableToCompleteException {
+    setupFruitEnum();
+    optimize("void", "int l = Fruit.values().length;",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
-    assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
+    assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
-  public void testNotOrdinalizableStaticMethodThatRefsValuesLength()
-      throws UnableToCompleteException  {
-    // this will cause a static method that references values().length
-    setupFruitEnumWithStaticMethodThatRefsValuesLength();
-    optimize("void", "Fruit y = Fruit.forInteger(0);");
+  public void testOrdinalizableStaticFieldRefToVALUES()
+      throws UnableToCompleteException {
+    // this ends up inlining the values() method call, and thus $VALUES is referenced external
+    // to the Fruit enum class.
+    setupFruitEnum();
+    optimize("void", "Fruit[] fruits = Fruit.values();",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
-    assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
+    assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
+  }
+
+  public void testOrdinalizableStaticMethodThatRefsValuesLength()
+      throws UnableToCompleteException {
+    // this will cause a static method that references values().length
+    setupFruitEnumWithStaticMethodThatRefsValuesLength();
+    optimize("void", "Fruit y = Fruit.forInteger(0);",
+        "int ord = Fruit.APPLE.ordinal();");
+
+    EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
+    assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
+    assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
   public void testNotOrdinalizableInstanceStaticFieldRef()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     // this will cause a static field ref in the enum clinit
     setupFruitEnumWithStaticField();
     optimize("void", "Fruit fruit = Fruit.APPLE;",
-                     "String y = fruit.staticField;");
+        "String y = fruit.staticField;");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -272,11 +306,11 @@
   }
 
   public void testNotOrdinalizableInstanceStaticMethod()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     // this will cause a static method enum class
     setupFruitEnumWithStaticMethod();
     optimize("void", "Fruit fruit = Fruit.APPLE;",
-                     "int y = fruit.staticMethod();");
+        "int y = fruit.staticMethod();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -284,10 +318,10 @@
   }
 
   public void testNotOrdinalizableClassLiteralReference()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Class clazz = Fruit.class;",
-                    "String clazzStr = clazz.toString();");
+        "String clazzStr = clazz.toString() + Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -295,10 +329,10 @@
   }
 
   public void testNotOrdinalizableEnumValueOfWithClassLiteralArg()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Object Carrot = Enum.valueOf(Fruit.class, \"APPLE\");",
-                    "String carrot = Carrot.toString();");
+        "String carrot = Carrot.toString() + Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -306,10 +340,10 @@
   }
 
   public void testNotOrdinalizableGetClassMethodCall()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Class clazz = Fruit.APPLE.getClass();",
-                    "String clazzStr = clazz.toString();");
+        "String clazzStr = clazz.toString() + Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -317,10 +351,11 @@
   }
 
   public void testNotOrdinalizableExplicitCastToEnumClass()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Object obj = new Object();",
-                    "Fruit fruit = (Fruit) obj;");
+        "Fruit fruit = (Fruit) obj;",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -328,10 +363,11 @@
   }
 
   public void testNotOrdinalizableExplicitCastToArrayOfEnumClass()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Enum[] enumArray = new Enum[10];",
-                    "Fruit[] fruitArray = (Fruit[]) enumArray;");
+        "Fruit[] fruitArray = (Fruit[]) enumArray;",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -339,10 +375,11 @@
   }
 
   public void testNotOrdinalizableExplicitCastFromArrayOfEnumClass()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit[] fruitArray = new Fruit[10];",
-                    "Enum[] enumArray = (Enum[]) fruitArray;");
+        "Enum[] enumArray = (Enum[]) fruitArray;",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -350,10 +387,11 @@
   }
 
   public void testNotOrdinalizableExplicitCastToArrayOfArrayOfEnumClass()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Enum[][] enumArray = new Enum[10][10];",
-                    "Fruit[][] fruitArray = (Fruit[][]) enumArray;");
+        "Fruit[][] fruitArray = (Fruit[][]) enumArray;",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -361,10 +399,11 @@
   }
 
   public void testNotOrdinalizableExplicitCastFromArrayOfArrayOfEnumClass()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit[][] fruitArray = new Fruit[10][10];",
-                    "Enum[][] enumArray = (Enum[][]) fruitArray;");
+        "Enum[][] enumArray = (Enum[][]) fruitArray;",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -372,10 +411,10 @@
   }
 
   public void testNotOrdinalizableExplicitCastFromEnumClass()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Enum Carrot = (Enum) Fruit.APPLE;",
-                    "String carrot = Carrot.toString();");
+        "String carrot = Carrot.toString();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -383,10 +422,11 @@
   }
 
   public void testNotOrdinalizableOrdinalMethodRefFromExplicitCastWithBlackListableSubExpression()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "int ord = " +
-        "((Fruit) Enum.valueOf(Fruit.class,\"APPLE\")).ordinal();");
+        "((Fruit) Enum.valueOf(Fruit.class,\"APPLE\")).ordinal();",
+        "int ord2 = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -394,10 +434,10 @@
   }
 
   public void testNotOrdinalizableInstanceFieldRef()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     // this will cause an instance field ref in the enum constructor
     setupFruitEnumWithInstanceField();
-    optimize("void");
+    optimize("void", "String instanceField = Fruit.APPLE.instanceField;");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -405,12 +445,12 @@
   }
 
   public void testNotOrdinalizableInstanceOfEnumExpression()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit fruit = Fruit.APPLE;",
-                     "if (fruit instanceof Enum) {",
-                     "  fruit = Fruit.ORANGE;",
-                     "}");
+        "if (fruit instanceof Enum) {",
+        "  fruit = Fruit.ORANGE;",
+        "}");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -418,24 +458,13 @@
   }
 
   public void testNotOrdinalizableInstanceOfEnumTestType()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Object fruitObj = new Object();",
-                     "if (fruitObj instanceof Fruit) {",
-                     "  fruitObj = null;",
-                     "}");
-
-    EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
-    assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
-    assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
-  }
-
-  public void testNotOrdinalizableStaticFieldRefToVALUES()
-      throws UnableToCompleteException  {
-    // this ends up inlining the values() method call, and thus $VALUES is referenced external
-    // to the Fruit enum class.
-    setupFruitEnum();
-    optimize("void", "Fruit[] fruits = Fruit.values();");
+        "if (fruitObj instanceof Fruit) {",
+        "  fruitObj = null;",
+        "}",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -443,12 +472,13 @@
   }
 
   public void testNotOrdinalizableStaticMethodCallValues()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     // make sure values() method call doesn't doesn't get inlined
     runMethodInliner = false;
 
     setupFruitEnum();
-    optimize("void", "Fruit[] fruits = Fruit.values();");
+    optimize("void", "Fruit[] fruits = Fruit.values();",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -456,14 +486,15 @@
   }
 
   public void testNotOrdinalizableJsniFieldRef()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("public static Fruit instanceFruit;");
     addSnippetClassDecl("public static native void jsniMethod() /*-{",
-                        "  var x = @test.EntryPoint::instanceFruit",
-                        "}-*/");
+        "  var x = @test.EntryPoint::instanceFruit",
+        "}-*/");
     optimize("void", "instanceFruit = Fruit.APPLE;",
-                    "jsniMethod();");
+        "jsniMethod();",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -471,12 +502,13 @@
   }
 
   public void testNotOrdinalizableJsniFieldRefStatic()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("public static native void jsniMethod() /*-{",
-                        "  var x = @test.EntryPoint.Fruit::APPLE",
-                        "}-*/");
-    optimize("void", "jsniMethod();");
+        "  var x = @test.EntryPoint.Fruit::APPLE",
+        "}-*/");
+    optimize("void", "jsniMethod();",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -484,12 +516,13 @@
   }
 
   public void testNotOrdinalizableJsniFieldRefClassLiteral()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("public static native void jsniMethod() /*-{",
-                        "  var x = @test.EntryPoint.Fruit::class",
-                        "}-*/");
-    optimize("void", "jsniMethod();");
+        "  var x = @test.EntryPoint.Fruit::class",
+        "}-*/");
+    optimize("void", "jsniMethod();",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -497,10 +530,12 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastBinaryOpAssignment()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
-    optimize("void", "Enum tomato;",
-                    "tomato = Fruit.APPLE;");
+    optimize("void",
+        "Enum tomato;",
+        "tomato = Fruit.APPLE;",
+        "int ord = tomato.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -508,12 +543,13 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastFieldInitializedWithNullByDefault()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("static private Fruit uninitializedFruitAsNull;");
     optimize("void", "if (uninitializedFruitAsNull != Fruit.APPLE) {",
-                     "  uninitializedFruitAsNull = Fruit.ORANGE;",
-                     "}");
+        "  uninitializedFruitAsNull = Fruit.ORANGE;",
+        "}",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -521,12 +557,12 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastBinaryOpEquals()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     setupVegetableEnum();
     optimize("void", "Fruit fruit = Fruit.APPLE;",
-                    "Enum carrot = (Enum) Vegetable.CARROT;",
-                    "boolean test = (fruit == carrot);");
+        "Enum carrot = (Enum) Vegetable.CARROT;",
+        "boolean test = (fruit == carrot);");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -536,13 +572,13 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastBinaryOpNotEquals()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     setupVegetableEnum();
     optimize("void", "Fruit fruit = Fruit.APPLE;",
-                    "Enum carrot = (Enum) Vegetable.CARROT;",
-                    // do in opposite order from OpEquals test
-                    "boolean test = (carrot != fruit);");
+        "Enum carrot = (Enum) Vegetable.CARROT;",
+        // do in opposite order from OpEquals test
+        "boolean test = (carrot != fruit);");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -552,17 +588,17 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastBinaryOpEqualsNull()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("public static boolean testIsNull(Fruit fruit) {",
-                        "  if (fruit == null) {",
-                        "    return true;",
-                        "  } else {",
-                        "    return false;",
-                        "  }",
-                        "}");
+        "  if (fruit == null) {",
+        "    return true;",
+        "  } else {",
+        "    return false;",
+        "  }",
+        "}");
     optimize("void", "Fruit fruit = Fruit.APPLE;",
-                    "boolean isNull = testIsNull(fruit) || testIsNull(Fruit.ORANGE);");
+        "boolean isNull = testIsNull(fruit) || testIsNull(Fruit.ORANGE);");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -570,17 +606,17 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastBinaryOpNotEqualsNull()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("public static boolean testIsNull(Fruit fruit) {",
-                        "  if (fruit != null) {",
-                        "    return true;",
-                        "  } else {",
-                        "    return false;",
-                        "  }",
-                        "}");
+        "  if (fruit != null) {",
+        "    return true;",
+        "  } else {",
+        "    return false;",
+        "  }",
+        "}");
     optimize("void", "Fruit fruit = Fruit.APPLE;",
-                    "boolean isNull = testIsNull(fruit) || testIsNull(Fruit.ORANGE);");
+        "boolean isNull = testIsNull(fruit) || testIsNull(Fruit.ORANGE);");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -588,10 +624,10 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastBinaryOpStringConcat()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit fruit = Fruit.APPLE;",
-                    "String str = \"A string followed by \" + fruit;");
+        "String str = \"A string followed by \" + fruit;");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -599,10 +635,10 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastBinaryOpStringConcat2()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit fruit = Fruit.APPLE;",
-                    "String str = fruit + \" followed by a string\";");
+        "String str = fruit + \" followed by a string\";");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -610,11 +646,11 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastBinaryOpStringConcatAssignment()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit fruit = Fruit.APPLE;",
-                    "String str = \"A string concatenated with: \";",
-                    "str += fruit;");
+        "String str = \"A string concatenated with: \";",
+        "str += fruit;");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -622,9 +658,10 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastDeclarationToNull()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
-    optimize("void", "Fruit fruit = null;");
+    optimize("void", "Fruit fruit = null;",
+        "int ord = fruit == null ? Fruit.APPLE.ordinal() : fruit.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -632,10 +669,11 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastAssignmentToNull()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Fruit fruit;",
-                    "fruit = null;");
+        "fruit = null;",
+        "int ord = fruit == null ? Fruit.APPLE.ordinal() : fruit.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -643,9 +681,10 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastDeclaration()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
-    optimize("void", "Enum tomato = Fruit.APPLE;");
+    optimize("void", "Enum tomato = Fruit.APPLE;",
+        "int ord = Fruit.APPLE.ordinal() + tomato.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -653,21 +692,22 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastConditional()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     setupVegetableEnum();
     optimize("void", "Enum tomato = null;",
-                    "tomato = (true) ? Fruit.APPLE : Vegetable.CARROT;");
+        "tomato = (true) ? Fruit.APPLE : Vegetable.CARROT;",
+        "int ord = Fruit.APPLE.ordinal() + Vegetable.CARROT.ordinal() + tomato.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
     assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
     assertTrue(tracker.isVisited("test.EntryPoint$Vegetable"));
-    assertFalse(tracker.isOrdinalized("test.EntryPoint$Vegetable"));
+    assertTrue(tracker.isOrdinalized("test.EntryPoint$Vegetable"));
   }
 
   public void testNotOrdinalizableImplicitUpcastOverriddenMethodReturnType()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
 
     // this test depends on the tighteners running
     runTypeTightener = true;
@@ -679,31 +719,31 @@
      * overridden method type.
      */
     addSnippetClassDecl("public interface EnumInterface {",
-                        "  String name();",
-                        "}");
+        "  String name();",
+        "}");
     addSnippetClassDecl("public abstract class AbstractClass<T extends EnumInterface> {",
-                        "  public abstract T getEnumClass();",
-                        "}");
+        "  public abstract T getEnumClass();",
+        "}");
     addSnippetClassDecl("public class CustomClass1 extends AbstractClass<EnumClass1> {",
-                        "  public EnumClass1 getEnumClass() { return EnumClass1.CONST1; }",
-                        "}");
+        "  public EnumClass1 getEnumClass() { return EnumClass1.CONST1; }",
+        "}");
     addSnippetClassDecl("public class CustomClass2 extends AbstractClass<EnumClass2> {",
-                        "  public EnumClass2 getEnumClass() { return EnumClass2.CONST2; }",
-                        "}");
+        "  public EnumClass2 getEnumClass() { return EnumClass2.CONST2; }",
+        "}");
     addSnippetClassDecl("public enum EnumClass1 implements EnumInterface {",
-                        "  CONST1;",
-                        "}");
+        "  CONST1;",
+        "}");
     addSnippetClassDecl("public enum EnumClass2 implements EnumInterface {",
-                        "  CONST2;",
-                        "}");
+        "  CONST2;",
+        "}");
     addSnippetClassDecl("public static void testEnumClass(AbstractClass abstractClass) {",
-                        "  EnumInterface enumClass = abstractClass.getEnumClass();",
-                        "}");
+        "  EnumInterface enumClass = abstractClass.getEnumClass();",
+        "}");
     optimize("void", "EntryPoint ep = new EntryPoint();",
-                    "AbstractClass abstractClass1 = ep.new CustomClass1();",
-                    "AbstractClass abstractClass2 = ep.new CustomClass2();",
-                    "testEnumClass(abstractClass1);",
-                    "testEnumClass(abstractClass2);");
+        "AbstractClass abstractClass1 = ep.new CustomClass1();",
+        "AbstractClass abstractClass2 = ep.new CustomClass2();",
+        "testEnumClass(abstractClass1);",
+        "testEnumClass(abstractClass2);");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$EnumClass1"));
@@ -713,18 +753,18 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastMethodCallArgs()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("public static String getEnumString(Enum myEnum) {",
-                        // make sure this method does something so not inlined
-                        "  int ord = myEnum.ordinal();",
-                        "  String retString = \"\";",
-                        "  for (int i = 0;i<ord;i++) {",
-                        "    retString += \"-\";",
-                        "  }",
-                        "  retString += myEnum.name();",
-                        "  return retString;",
-                        "}");
+        // make sure this method does something so not inlined
+        "  int ord = myEnum.ordinal();",
+        "  String retString = \"\";",
+        "  for (int i = 0;i<ord;i++) {",
+        "    retString += \"-\";",
+        "  }",
+        "  retString += myEnum.name();",
+        "  return retString;",
+        "}");
     optimize("void", "String stringApple = getEnumString(Fruit.APPLE);");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
@@ -733,16 +773,17 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastMethodCallArgsNewArray()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("public static String getEnumString(Enum[] myEnumArray) {",
-                        "  String retString = \"\";",
-                        "  for (Enum myEnum : myEnumArray) {",
-                        "    retString += myEnum.name();",
-                        "  }",
-                        "  return retString;",
-                        "}");
-    optimize("void", "String stringFruits = getEnumString(new Enum[] {Fruit.APPLE, Fruit.ORANGE});");
+        "  String retString = \"\";",
+        "  for (Enum myEnum : myEnumArray) {",
+        "    retString += myEnum.name();",
+        "  }",
+        "  return retString;",
+        "}");
+    optimize("void",
+        "String stringFruits = getEnumString(new Enum[] {Fruit.APPLE, Fruit.ORANGE});");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -750,15 +791,15 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastMethodCallVarArgs()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("public static String getEnumString(Enum...myEnumArray) {",
-                        "  String retString = \"\";",
-                        "  for (Enum myEnum : myEnumArray) {",
-                        "    retString += myEnum.name();",
-                        "  }",
-                        "  return retString;",
-                        "}");
+        "  String retString = \"\";",
+        "  for (Enum myEnum : myEnumArray) {",
+        "    retString += myEnum.name();",
+        "  }",
+        "  return retString;",
+        "}");
     optimize("void", "String stringFruits = getEnumString(Fruit.APPLE, Fruit.ORANGE);");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
@@ -767,7 +808,7 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastNewArrayElements()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     optimize("void", "Enum[] enums = new Enum[] {Fruit.APPLE, Fruit.ORANGE};");
 
@@ -777,20 +818,21 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastNewArrayArrayElements()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
-    optimize("void", "Enum[][] enums = new Enum[][] {{Fruit.APPLE, Fruit.ORANGE},{Fruit.ORANGE, Fruit.APPLE}};");
+    optimize("void",
+        "Enum[][] enums = new Enum[][] {{Fruit.APPLE, Fruit.ORANGE},{Fruit.ORANGE, Fruit.APPLE}};");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
     assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
-  public void testNotOrdinalizableImplicitUpcastJsniMethodBodyParams()
-      throws UnableToCompleteException  {
+  public void testNotOrdinalizableJsniMethodBodyParams()
+      throws UnableToCompleteException {
     setupFruitEnum();
-    addSnippetClassDecl("public static native void passEnumToJsniMethod(Fruit myEnum) /*-{",
-                        "}-*/");
+    addSnippetClassDecl("public static native void passEnumToJsniMethod(Enum myEnum) /*-{",
+        "  myEnum == null; }-*/");
     optimize("void", "passEnumToJsniMethod(Fruit.APPLE);");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
@@ -798,14 +840,29 @@
     assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
   }
 
-  public void testNotOrdinalizableImplicitUpcastJsniMethodBodyReturnType()
-      throws UnableToCompleteException  {
+  public void testNotOrdinalizableImplicitUpcastJsniMethodBodyParams()
+      throws UnableToCompleteException {
     setupFruitEnum();
-    addSnippetClassDecl("public static native Fruit returnFruitViaJsni() /*-{",
-                        "  var myJso;",
-                        "  return myJso;",
-                        "}-*/");
-    optimize("void", "Fruit fruit = returnFruitViaJsni();");
+    addSnippetClassDecl("public static native void passEnumToJsniMethod(Fruit myEnum) /*-{",
+        "   myEnum == null; }-*/;");
+    optimize("void", "passEnumToJsniMethod(Fruit.APPLE);");
+
+    EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
+    assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
+    assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
+  }
+
+  public void testNotOrdinalizableJsniMethodBodyCall()
+      throws UnableToCompleteException {
+    setupFruitEnum();
+    addSnippetClassDecl("public static native void consumeFruitViaJsni() /*-{",
+        "  var myJso = @test.EntryPoint::calledFromJsni(*)();",
+        "}-*/;",
+        "public static Fruit calledFromJsni() {",
+        "  return Fruit.APPLE;",
+        "}");
+    optimize("void", "consumeFruitViaJsni();",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -813,14 +870,15 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastJsniMethodRefParams()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     setupFruitSwitchMethod();
     addSnippetClassDecl("public static native void fruitSwitchViaJsni() /*-{",
-                        "  var myJso;",
-                        "  var result = @test.EntryPoint::fruitSwitch(Ltest/EntryPoint$Fruit;)(myJso);",
-                        "}-*/");
-    optimize("void", "fruitSwitchViaJsni();");
+        "  var myJso;",
+        "  var result = @test.EntryPoint::fruitSwitch(Ltest/EntryPoint$Fruit;)(myJso);",
+        "}-*/");
+    optimize("void", "fruitSwitchViaJsni();",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -828,15 +886,16 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastJsniMethodRefReturnType()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     addSnippetClassDecl("public static Fruit returnSomeFruit() {",
-                        "  return Fruit.APPLE;",
-                        "}");
+        "  return Fruit.APPLE;",
+        "}");
     addSnippetClassDecl("public static native void jsniMethodRefWithEnumReturn() /*-{",
-                        "  var result = @test.EntryPoint::returnSomeFruit()();",
-                        "}-*/");
-    optimize("void", "jsniMethodRefWithEnumReturn();");
+        "  var result = @test.EntryPoint::returnSomeFruit()();",
+        "}-*/");
+    optimize("void", "jsniMethodRefWithEnumReturn();",
+        "int ord = Fruit.APPLE.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -844,19 +903,20 @@
   }
 
   public void testNotOrdinalizableImplicitUpcastReturnStatement()
-      throws UnableToCompleteException  {
+      throws UnableToCompleteException {
     setupFruitEnum();
     setupVegetableEnum();
     addSnippetClassDecl("public static Enum returnAsEnum(int mode) {",
-                        "  if (mode == 0) {",
-                        "    return Fruit.APPLE;",
-                        "  } else {",
-                        "    return Vegetable.CARROT;",
-                        "  }",
-                        "}");
+        "  if (mode == 0) {",
+        "    return Fruit.APPLE;",
+        "  } else {",
+        "    return Vegetable.CARROT;",
+        "  }",
+        "}");
     optimize("void", "Enum myEnum = returnAsEnum(0);",
-                    // do a second one, to prevent inlining
-                    "Enum myOtherEnum = returnAsEnum(1);");
+        // do a second one, to prevent inlining
+        "Enum myOtherEnum = returnAsEnum(1);",
+        "int ord = Fruit.APPLE.ordinal() + Vegetable.CARROT.ordinal();");
 
     EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
     assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
@@ -875,49 +935,49 @@
 
   private void setupFruitEnumWithInstanceField() {
     addSnippetClassDecl("public enum Fruit {APPLE(\"a\"), ORANGE(\"b\");",
-                        "  public final String instanceField;",
-                        "  private Fruit(String str) {",
-                        "    instanceField = str;",
-                        "  }",
-                        "}");
+        "  public final String instanceField;",
+        "  private Fruit(String str) {",
+        "    instanceField = str;",
+        "  }",
+        "}");
   }
 
   private void setupFruitEnumWithStaticField() {
     addSnippetClassDecl("public enum Fruit {APPLE, ORANGE;",
-                        "  public static final String staticField = \"STATIC\";",
-                        "}");
+        "  public static final String staticField = \"STATIC\";",
+        "}");
   }
 
   private void setupFruitEnumWithStaticMethod() {
     addSnippetClassDecl("public enum Fruit {APPLE, ORANGE;",
-                        "  public static final int staticMethod() {",
-                        "    int x = 0;",
-                        "    return x;",
-                        "  }",
-                        "}");
+        "  public static final int staticMethod() {",
+        "    int x = 0;",
+        "    return x;",
+        "  }",
+        "}");
   }
 
   private void setupFruitEnumWithStaticMethodThatRefsValuesArray() {
     // add a little extra logic here, to prevent inlining
     addSnippetClassDecl("public enum Fruit {APPLE, ORANGE;",
-                        "  public static Fruit forInteger(int value) {",
-                        "    if (value < 0 || value >= 2) {",
-                        "      return ORANGE;",
-                        "    }",
-                        "    return Fruit.values()[value];",
-                        "  }",
-                        "}");
+        "  public static Fruit forInteger(int value) {",
+        "    if (value < 0 || value >= 2) {",
+        "      return ORANGE;",
+        "    }",
+        "    return Fruit.values()[value];",
+        "  }",
+        "}");
   }
 
   private void setupFruitEnumWithStaticMethodThatRefsValuesLength() {
     addSnippetClassDecl("public enum Fruit {APPLE, ORANGE;",
-                        "  public static Fruit forInteger(int value) {",
-                        "    if (value < 0 || value >= Fruit.values().length) {",
-                        "      return ORANGE;",
-                        "    }",
-                        "    return APPLE;",
-                        "  }",
-                        "}");
+        "  public static Fruit forInteger(int value) {",
+        "    if (value < 0 || value >= Fruit.values().length) {",
+        "      return ORANGE;",
+        "    }",
+        "    return APPLE;",
+        "  }",
+        "}");
   }
 
   private void setupVegetableEnum() {
@@ -926,29 +986,14 @@
 
   private void setupFruitSwitchMethod() {
     addSnippetClassDecl("public static String fruitSwitch(Fruit fruit) {",
-                        " switch(fruit) {",
-                        "   case APPLE: return \"Apple\";",
-                        "   case ORANGE: return \"Orange\";",
-                        "   default: return \"Unknown\";",
-                        " }",
-                        "}");
+        " switch(fruit) {",
+        "   case APPLE: return \"Apple\";",
+        "   case ORANGE: return \"Orange\";",
+        "   default: return \"Unknown\";",
+        " }",
+        "}");
   }
 
-  /*
-   * Always run ImplementCastsAndTypeChecks and EqualityNormalizer, even in cases where we
-   * are testing that ordinalization cannot occur, since there may be other
-   * enums (such as DummyEnum) which do get ordinalized, and we want to test
-   * that all is well regardless.
-   */
-  private final boolean performCastReplacement = true;
-  private final boolean runEqualityNormalizer = true;
-
-  // These are enabled as needed for a given test
-  private boolean runMakeCallsStatic;
-  private boolean runMethodInliner;
-  private boolean runMethodCallTightener;
-  private boolean runTypeTightener;
-
   @Override
   protected boolean optimizeMethod(JProgram program, JMethod method) {
     /*
@@ -962,32 +1007,25 @@
      * These are a subset of the actual optimizers run in JJS.optimizeLoop().
      */
     boolean didChange = false;
-    AstDumper.maybeDumpAST(program, "EnumOrdinalizerTest_start");
+    program.addEntryMethod(findMainMethod(program));
 
     if (runMakeCallsStatic) {
       didChange = MakeCallsStatic.exec(new JJSOptionsImpl(), program).didChange() || didChange;
-      AstDumper.maybeDumpAST(program,
-          "EnumOrdinalizerTest_after_makeCallsStatic");
     }
     if (runTypeTightener) {
       didChange = TypeTightener.exec(program).didChange() || didChange;
-      AstDumper.maybeDumpAST(program,
-          "EnumOrdinalizerTest_after_typeTightener");
     }
     if (runMethodCallTightener) {
       didChange = MethodCallTightener.exec(program).didChange() || didChange;
-      AstDumper.maybeDumpAST(program,
-          "EnumOrdinalizerTest_after_methodCallTightener");
     }
     if (runMethodInliner) {
       didChange = MethodInliner.exec(program).didChange() || didChange;
-      AstDumper.maybeDumpAST(program,
-          "EnumOrdinalizerTest_after_methodInliner");
+    }
+    if (runPruner) {
+      didChange = Pruner.exec(program, true).didChange() || didChange;
     }
 
     didChange = EnumOrdinalizer.exec(program).didChange() || didChange;
-    AstDumper.maybeDumpAST(program,
-        "EnumOrdinalizerTest_after_EnumOrdinalizer");
 
     /*
      * Run these normalizers to sanity check the AST.  If there are any
diff --git a/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java b/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java
index 3af876d..35a4c42 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java
@@ -218,6 +218,27 @@
         SomeParentParentParent.callSomeParentParentParentM(new SomeSubSubClassInAnotherPackage()));
   }
 
+  enum MyEnum {
+    A,
+    B,
+    C;
+
+    public final static MyEnum[] VALUES = values();
+
+    public int getPriority() {
+      return VALUES.length - ordinal();
+    }
+  }
+
+  /**
+   * Tests that enum ordinalizer does not incorrectly optimize {@code MyEnum}.
+   * <p>
+   * Test for issue 8846:.
+   */
+  public void testMyEnum() {
+    assertEquals(2, MyEnum.B.getPriority());
+  }
+
   private static void assertEqualContents(float[] expected, float[] actual) {
 
     assertEquals("Array length mismatch", expected.length, actual.length);