Rolling back Enum Ordinalization Optimization (latent issues have been identified)
Review at http://gwt-code-reviews.appspot.com/1128801
Review by: zundel@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9260 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 e795adb..7917969 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -65,7 +65,6 @@
import com.google.gwt.dev.jjs.impl.ArrayNormalizer;
import com.google.gwt.dev.jjs.impl.AssertionNormalizer;
import com.google.gwt.dev.jjs.impl.AssertionRemover;
-import com.google.gwt.dev.jjs.impl.AstDumper;
import com.google.gwt.dev.jjs.impl.BuildTypeMap;
import com.google.gwt.dev.jjs.impl.CastNormalizer;
import com.google.gwt.dev.jjs.impl.CatchBlockNormalizer;
@@ -73,7 +72,6 @@
import com.google.gwt.dev.jjs.impl.CodeSplitter.MultipleDependencyGraphRecorder;
import com.google.gwt.dev.jjs.impl.ControlFlowAnalyzer;
import com.google.gwt.dev.jjs.impl.DeadCodeElimination;
-import com.google.gwt.dev.jjs.impl.EnumOrdinalizer;
import com.google.gwt.dev.jjs.impl.EqualityNormalizer;
import com.google.gwt.dev.jjs.impl.Finalizer;
import com.google.gwt.dev.jjs.impl.FixAssignmentToUnbox;
@@ -100,6 +98,7 @@
import com.google.gwt.dev.jjs.impl.ReplaceRunAsyncs;
import com.google.gwt.dev.jjs.impl.ResolveRebinds;
import com.google.gwt.dev.jjs.impl.SameParameterValueOptimizer;
+import com.google.gwt.dev.jjs.impl.SourceGenerationVisitor;
import com.google.gwt.dev.jjs.impl.TypeLinker;
import com.google.gwt.dev.jjs.impl.TypeMap;
import com.google.gwt.dev.jjs.impl.TypeTightener;
@@ -125,9 +124,11 @@
import com.google.gwt.dev.js.ast.JsBlock;
import com.google.gwt.dev.js.ast.JsName;
import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.util.AbstractTextOutput;
import com.google.gwt.dev.util.DefaultTextOutput;
import com.google.gwt.dev.util.Empty;
import com.google.gwt.dev.util.Memory;
+import com.google.gwt.dev.util.TextOutput;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.OptionOptimize;
import com.google.gwt.dev.util.collect.Lists;
@@ -145,8 +146,10 @@
import org.xml.sax.SAXException;
import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.io.PrintWriter;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Collection;
@@ -571,8 +574,8 @@
allTypeDeclarations = null;
Memory.maybeDumpMemory("AstOnly");
- AstDumper.maybeDumpAST(jprogram);
-
+ maybeDumpAST(jprogram);
+
// See if we should run the EnumNameObfuscator
if (module != null) {
ConfigurationProperty enumNameObfuscationProp = (ConfigurationProperty) module.getProperties().find(
@@ -618,7 +621,7 @@
/*
* 4) Possibly optimize some.
*
- * Don't optimize early if this is a draft compile, or if there's only
+ * Don't optimizing early if this is a draft compile, or if there's only
* one permutation.
*/
if (options.getOptimizationLevel() > OptionOptimize.OPTIMIZE_LEVEL_DRAFT
@@ -705,7 +708,7 @@
optimizeEvent.end();
throw new InterruptedException();
}
- AstDumper.maybeDumpAST(jprogram);
+ maybeDumpAST(jprogram);
OptimizerStats stats = optimizeLoop("Pass " + counter, jprogram,
options.isAggressivelyOptimize());
allOptimizerStats.add(stats);
@@ -822,13 +825,6 @@
// remove same parameters value
stats.add(SameParameterValueOptimizer.exec(jprogram).recordVisits(
numNodes));
-
- /*
- * enum ordinalization
- * TODO(jbrosenberg): graduate this out of the 'isAggressivelyOptimize'
- * block, over time.
- */
- stats.add(EnumOrdinalizer.exec(jprogram).recordVisits(numNodes));
}
// prove that any types that have been culled from the main tree are
@@ -1282,6 +1278,28 @@
return result;
}
+ private static void maybeDumpAST(JProgram jprogram) {
+ String dumpFile = System.getProperty("gwt.jjs.dumpAst");
+ if (dumpFile != null) {
+ try {
+ FileOutputStream os = new FileOutputStream(dumpFile, true);
+ final PrintWriter pw = new PrintWriter(os);
+ TextOutput out = new AbstractTextOutput(false) {
+ {
+ setPrintWriter(pw);
+ }
+ };
+ SourceGenerationVisitor v = new SourceGenerationVisitor(out);
+ v.accept(jprogram);
+ pw.flush();
+ pw.close();
+ } catch (IOException e) {
+ System.out.println("Could not dump AST");
+ e.printStackTrace();
+ }
+ }
+ }
+
/**
* Open an emitted artifact and gunzip its contents.
*/
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 9c0f5b5..a5eac08 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
@@ -77,7 +77,6 @@
"java.util.Iterator", "java.lang.AssertionError", "java.lang.Boolean",
"java.lang.Byte", "java.lang.Character", "java.lang.Short",
"java.lang.Integer", "java.lang.Float", "java.lang.Double",
- "java.lang.Throwable",
"com.google.gwt.core.client.GWT",
"com.google.gwt.core.client.JavaScriptObject",
"com.google.gwt.lang.ClassLiteralHolder",
@@ -781,10 +780,6 @@
return returnMap;
}
- public String getClassLiteralName(JType type) {
- return type.getJavahSignatureName() + "_classLit";
- }
-
public CorrelationFactory getCorrelator() {
return correlator;
}
@@ -880,8 +875,8 @@
JClassLiteral.computeClassObjectAllocation(this,info, type);
// Create a field in the class literal holder to hold the object.
- JField field = new JField(info, getClassLiteralName(type),
- typeSpecialClassLiteralHolder, getTypeJavaLangClass(),
+ JField field = new JField(info, type.getJavahSignatureName()
+ + "_classLit", typeSpecialClassLiteralHolder, getTypeJavaLangClass(),
true, Disposition.FINAL);
typeSpecialClassLiteralHolder.addField(field);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/AstDumper.java b/dev/core/src/com/google/gwt/dev/jjs/impl/AstDumper.java
deleted file mode 100644
index 9897530..0000000
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/AstDumper.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2010 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.jjs.impl;
-
-import com.google.gwt.dev.jjs.ast.JProgram;
-import com.google.gwt.dev.util.AbstractTextOutput;
-import com.google.gwt.dev.util.TextOutput;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-
-/**
- * A simple utility to dump a JProgram to a temp file, which can be called
- * sequentially during a compilation/optimization run, so intermediate steps
- * can be compared.
- *
- * It uses the system property "gwt.jjs.dumpAst" to determine the name
- * (or prefix) of the file to dump the AST to.
- *
- * TODO(jbrosenberg): Add proper logging and/or exception handling for the
- * potential IOException that might occur when writing the file.
- */
-public class AstDumper {
-
- private static int autoVersionNumber = 0;
-
- /**
- * Appends a new version of the AST at the end of the file, each time it's called.
- */
- public static void maybeDumpAST(JProgram jprogram) {
- maybeDumpAST(jprogram, null, true);
- }
-
- /**
- * Writes the AST to the file with a versioned extension, using an
- * auto-incrementing version number (starting from 1), each time it's called.
- * Any previous contents of the file written to will be overwritten.
- */
- public static void maybeDumpAST(JProgram jprogram, boolean autoIncrementVersion) {
- if (!autoIncrementVersion) {
- maybeDumpAST(jprogram);
- } else {
- maybeDumpAST(jprogram, autoVersionNumber++);
- }
- }
-
- /**
- * Writes the AST to the file with the provided version number extension.
- * Any previous contents of the file written to will be overwritten.
- */
- public static void maybeDumpAST(JProgram jprogram, int versionNumber) {
- String fileExtension = "." + versionNumber;
- maybeDumpAST(jprogram, fileExtension, false);
- }
-
- /**
- * Writes the AST to the file with the provided version string extension.
- * Any previous contents of the file written to will be overwritten.
- */
- public static void maybeDumpAST(JProgram jprogram, String versionString) {
- String fileExtension = "." + versionString;
- maybeDumpAST(jprogram, fileExtension, false);
- }
-
- private static void maybeDumpAST(JProgram jprogram,
- String fileExtension, boolean append) {
- String dumpFile = System.getProperty("gwt.jjs.dumpAst");
- if (dumpFile != null) {
- if (fileExtension != null) {
- dumpFile += fileExtension;
- }
- try {
- FileOutputStream os = new FileOutputStream(dumpFile, append);
- final PrintWriter pw = new PrintWriter(os);
- TextOutput out = new AbstractTextOutput(false) {
- {
- setPrintWriter(pw);
- }
- };
- SourceGenerationVisitor v = new SourceGenerationVisitor(out);
- v.accept(jprogram);
- pw.close();
- } catch (IOException e) {
- System.out.println("Could not dump AST");
- e.printStackTrace();
- }
- }
- }
-}
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
deleted file mode 100644
index d51d2fa..0000000
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java
+++ /dev/null
@@ -1,982 +0,0 @@
-/*
- * Copyright 2010 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.jjs.impl;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.dev.jjs.ast.Context;
-import com.google.gwt.dev.jjs.ast.JArrayType;
-import com.google.gwt.dev.jjs.ast.JCastOperation;
-import com.google.gwt.dev.jjs.ast.JClassLiteral;
-import com.google.gwt.dev.jjs.ast.JClassType;
-import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
-import com.google.gwt.dev.jjs.ast.JEnumField;
-import com.google.gwt.dev.jjs.ast.JEnumType;
-import com.google.gwt.dev.jjs.ast.JExpression;
-import com.google.gwt.dev.jjs.ast.JField;
-import com.google.gwt.dev.jjs.ast.JFieldRef;
-import com.google.gwt.dev.jjs.ast.JMethod;
-import com.google.gwt.dev.jjs.ast.JMethodBody;
-import com.google.gwt.dev.jjs.ast.JMethodCall;
-import com.google.gwt.dev.jjs.ast.JModVisitor;
-import com.google.gwt.dev.jjs.ast.JNode;
-import com.google.gwt.dev.jjs.ast.JPrimitiveType;
-import com.google.gwt.dev.jjs.ast.JProgram;
-import com.google.gwt.dev.jjs.ast.JReferenceType;
-import com.google.gwt.dev.jjs.ast.JStatement;
-import com.google.gwt.dev.jjs.ast.JType;
-import com.google.gwt.dev.jjs.ast.JVariableRef;
-import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
-import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
-import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
-import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
-import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Stack;
-import java.util.TreeSet;
-
-/**
- * This optimizer replaces enum constants with their ordinal value (a simple
- * int) when possible. We call this process "ordinalization".
- *
- * Generally, this can be done for enums that are only ever referred to by
- * reference, or by their ordinal value. For the specific set of conditions
- * under which ordinalization can proceed, see the notes for the nested class
- * {@link EnumOrdinalizer.CannotBeOrdinalAnalyzer} below.
- *
- * This optimizer modifies enum classes to change their field constants to ints,
- * and to remove initialization of those constants in the clinit method. An
- * ordinalized enum class will not be removed from the AST by this optimizer,
- * but as long as all references to it are replaced (which is one of the
- * requirements for ordinalization), then the enum class itself will be pruned
- * by subsequent optimizer passes.
- *
- * Regardless of whether an ordinalized enum class ends up being completely
- * pruned away, the AST is expected to be in a coherent and usable state after
- * any pass of this optimizer. Thus, this optimizer should be considered to be
- * stateless.
- *
- * The process is broken up into 3 separate passes over the AST, each
- * implemented as a separate visitor class. The first visitor,
- * {@link EnumOrdinalizer.CannotBeOrdinalAnalyzer} compiles information
- * about each enum class in the AST, and looks for reasons not to ordinalize
- * each enum. Thus, it prepares a "black-list" of enum classes that cannot be
- * ordinalized (and it follows that all enums that don't get entered in the
- * black-list, will be allowed to be ordinalized. The set of conditions which
- * cause an enum to be black-listed are outlined below.
- *
- * If there are enum classes that didn't get black-listed remaining, the
- * subsequent passes of the optimizer will be invoked. The first,
- * {@link EnumOrdinalizer.ReplaceEnumTypesWithInteger}, replaces the type info
- * for each field or expression involved with a target enum constant with an
- * integer. The final visitor, descriptively named
- * {@link EnumOrdinalizer.ReplaceOrdinalFieldAndMethodRefsWithOrdinal}, will do
- * the job of replacing the value for references to the Enum ordinal field or
- * method of an enum constant that has been ordinalized.
- */
-public class EnumOrdinalizer {
- public static String NAME = EnumOrdinalizer.class.getSimpleName();
- public static Tracker tracker = null;
-
- public static OptimizerStats exec(JProgram program) {
- Event optimizeEvent = SpeedTracerLogger.start(
- CompilerEventType.OPTIMIZE, "optimizer", NAME);
- OptimizerStats stats = new EnumOrdinalizer(program).execImpl();
- optimizeEvent.end("didChange", "" + stats.didChange());
- return stats;
- }
-
- public static Tracker getTracker() {
- return tracker;
- }
-
- public static void startTracker() {
- tracker = new Tracker();
- }
-
- public static void stopTracker() {
- tracker = null;
- }
-
- private final JProgram program;
- private final JType classLiteralHolderType;
- private final JType nullType;
- private final JType javaScriptObjectType;
- private final JType enumType;
- private final JField enumOrdinalField;
- private final JMethod classCreateForEnumMethod;
- private final JMethod enumCreateValueOfMapMethod;
- private final JMethod enumSuperConstructor;
- private final JMethod enumOrdinalMethod;
- private final Set<JEnumType> ordinalizationBlackList = new HashSet<JEnumType>();
- private final Map<String, JEnumType> enumsVisited = new HashMap<String, JEnumType>();
-
- public EnumOrdinalizer(JProgram program) {
- this.program = program;
- this.classLiteralHolderType = program.getIndexedType("ClassLiteralHolder");
- this.nullType = program.getTypeNull();
- this.javaScriptObjectType = program.getJavaScriptObject();
- this.enumType = program.getIndexedType("Enum");
- this.enumOrdinalField = program.getIndexedField("Enum.ordinal");
- this.classCreateForEnumMethod = program.getIndexedMethod("Class.createForEnum");
- this.enumCreateValueOfMapMethod = program.getIndexedMethod("Enum.createValueOfMap");
- this.enumOrdinalMethod = program.getIndexedMethod("Enum.ordinal");
- this.enumSuperConstructor = program.getIndexedMethod("Enum.Enum");
- }
-
- /**
- * A visitor which keeps track of the enums which cannot be ordinalized. It
- * does this by keeping track of a "black-list" for ordinals which violate the
- * conditions for ordinalization, below.
- *
- * An enum cannot be ordinalized, if it:
- * is implicitly upcast.
- * is implicitly cast to from a nullType.
- * is implicitly cast to or from a javaScriptObject type.
- * is explicitly cast to another type (or vice-versa).
- * it's class literal is used explicitly.
- * it has an artificial rescue recorded for it.
- * has any field referenced, except for:
- * one of it's enum constants
- * Enum.ordinal
- * has any method called, except for:
- * ordinal()
- * Enum.ordinal()
- * Enum() super constructor
- * Enum.createValueOfMap()
- *
- * This visitor extends the ImplicitUpcastAnalyzer, which encapsulates all
- * the conditions where implicit upcasting can occur in an AST. The rest of
- * the logic for checking ordinalizability is encapsulated in this sub-class.
- *
- * It also keeps track of all enums encountered, so we can know if we need to
- * continue with the other visitors of the optimizer after this visitor runs.
- *
- * We make special allowances not to check any code statements that appear
- * within the ClassLiteralHolder class, which can contain a reference to all
- * enum class literals in the program, even after ordinalization occurs.
- *
- * Also, we ignore visiting the getClass() method for any enum subclass, since
- * it will also cause a visit to the enum's class literal, and we don't
- * necessarily want to prevent ordinalization in that case.
- *
- * Special checking is needed to detect a class literal reference that occurs
- * within a JSNI method body. We don't get a visit to JClassLiteral in that
- * case, so we need to inspect visits to JsniFieldRef for the possibility it
- * might be a reference to a class literal.
- *
- * We also skip any checking in a method call to Enum.createValueOfMap(),
- * since this is generated for any enum class initially within the extra
- * enumClass$Map class, and this call contains an implicit upcast in the
- * method call args (as well as a reference to the static enumClass$VALUES
- * field), which we want to ignore. The enumClass$Map class will not get
- * pruned as long as the enumClass is not ordinalized, and so we need to
- * ignore it's presence in the consideration for whether an enum class is
- * ordinalizable.
- */
- private class CannotBeOrdinalAnalyzer extends ImplicitUpcastAnalyzer {
-
- private final Set<String> jsniClassLiteralsVisited = new HashSet<String>();
- private final Stack<JCastOperation> castOpsToIgnore =
- new Stack<JCastOperation>();
-
- public CannotBeOrdinalAnalyzer(JProgram program) {
- super(program);
- }
-
- /*
- * After program is visited, post-process remaining tasks from accumulated data.
- */
- public void afterVisitor() {
- // black-list any Jsni enum ClassLiteralsVisited
- for (String classLiteralName : jsniClassLiteralsVisited) {
- JEnumType enumFromLiteral = enumsVisited.get(classLiteralName);
- if (enumFromLiteral != null) {
- addToBlackList(enumFromLiteral);
- }
- }
- }
-
- @Override
- public void endVisit(JCastOperation x, Context ctx) {
- // see if we've previously marked this castOp to be exempted
- if (!castOpsToIgnore.empty() &&
- castOpsToIgnore.peek() == x) {
- castOpsToIgnore.pop();
- return;
- }
-
- // check for explicit cast (check both directions)
- blackListIfEnumCast(x.getExpr().getType(), x.getCastType());
- blackListIfEnumCast(x.getCastType(), x.getExpr().getType());
- }
-
- @Override
- public void endVisit(JClassLiteral x, Context ctx) {
- /*
- * Check for references to an enum's class literal. We need to
- * black-list classes in this case, since there could be a call
- * to Enum.valueOf(someEnum.class,"name"), etc.
- *
- * Note: we won't get here for class literals that occur in the
- * ClassLiteralHolder class, or within the getClass method of an
- * enum class (see comments above).
- */
- JEnumType type = getEnumType(x.getRefType());
- if (type != null) {
- blackListIfEnum(type);
- }
- }
-
- @Override
- public void endVisit(JClassType x, Context ctx) {
- // black-list any artificially rescued classes recorded for this class
- List<JNode> rescues = x.getArtificialRescues();
- if (rescues != null && rescues.size() > 0) {
- for (JNode rescueNode : rescues) {
- if (rescueNode instanceof JType) {
- blackListIfEnum((JType) rescueNode);
- }
- }
- }
-
- // keep track of all enum classes visited
- JEnumType maybeEnum = x.isEnumOrSubclass();
- if (maybeEnum != null) {
- enumsVisited.put(program.getClassLiteralName(maybeEnum), maybeEnum);
- }
- }
-
- @Override
- public void endVisit(JFieldRef x, Context ctx) {
- // don't need to check Enum.ordinal
- if (x.getField() == enumOrdinalField) {
- return;
- }
-
- if (x.getInstance() != null) {
- // check any instance field reference other than ordinal
- blackListIfEnumExpression(x.getInstance());
- } else if (x.getField().isStatic()) {
- // check static field references
-
- /*
- * Need to exempt static fieldRefs to the special $VALUES array that
- * gets generated for all enum classes, if the reference occurs
- * within the enum class itself (such as happens in the clinit() or
- * values() method for all enums).
- */
- if (x.getField().getName().equals("$VALUES") &&
- this.currentMethod.getEnclosingType() ==
- x.getField().getEnclosingType()) {
- if (getEnumType(x.getField().getEnclosingType()) != null) {
- return;
- }
- }
-
- /*
- * Need to exempt static fieldRefs for enum constants themselves.
- * Detect these as final fields, that have the same enum type as
- * their enclosing type.
- */
- if (x.getField().isFinal() &&
- (x.getField().getEnclosingType() ==
- getEnumType(x.getField().getType()))) {
- return;
- }
-
- /*
- * Check any other refs to static fields of an enum class. This
- * includes references to $VALUES that might occur outside of the enum
- * class itself. This can occur when a call to the values() method gets
- * inlined, etc. Also check here for any user defined static fields.
- */
- blackListIfEnum(x.getField().getEnclosingType());
- }
- }
-
- @Override
- public void endVisit(JsniFieldRef x, Context ctx) {
- /*
- * Can't do the same thing as for JFieldRef,
- * all JsniFieldRefs are cast to JavaScriptObjects.
- * Need to check both the field type and the type of the instance
- * or enclosing class referencing the field.
- */
-
- // check the field type
- blackListIfEnum(x.getField().getType());
-
- // check the referrer
- if (x.getInstance() != null) {
- blackListIfEnumExpression(x.getInstance());
- } else {
- blackListIfEnum(x.getField().getEnclosingType());
- }
-
- /*
- * need to also check JsniFieldRef's for a possible reference to a
- * class literal, since we don't get a visit to JClassLiteral when
- * it occurs within Jsni (shouldn't it?).
- */
- if (x.getField().getEnclosingType() == classLiteralHolderType) {
- // see if it has an initializer with a method call to "createForEnum"
- JExpression initializer = x.getField().getInitializer();
- if (initializer instanceof JMethodCall) {
- if (((JMethodCall) initializer).getTarget() == classCreateForEnumMethod) {
- jsniClassLiteralsVisited.add(x.getField().getName());
- }
- }
- }
- }
-
- @Override
- public void endVisit(JMethodCall x, Context ctx) {
- // exempt calls to certain methods on the Enum super class
- if (x.getTarget() == enumCreateValueOfMapMethod ||
- x.getTarget() == enumSuperConstructor ||
- x.getTarget() == enumOrdinalMethod) {
- return;
- }
-
- // any other method on an enum class should cause it to be black-listed
- 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());
- }
- }
-
- // defer to ImplicitUpcastAnalyzer to check method call args & params
- super.endVisit(x, ctx);
- }
-
- @Override
- public void endVisit(JsniMethodRef x, Context ctx) {
- // no enum methods are exempted if occur within a JsniMethodRef
- 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());
- }
- }
-
- // defer to ImplicitUpcastAnalyzer to check method call args & params
- super.endVisit(x, ctx);
- }
-
- @Override
- public boolean visit(JClassType x, Context ctx) {
- /*
- * Don't want to visit the large ClassLiteralHolder class, it doesn't
- * contain references to actual usage of enum class literals. It's also
- * a time savings to not traverse this class.
- */
- if (x == classLiteralHolderType) {
- return false;
- }
- return true;
- }
-
- @Override
- public boolean visit(JFieldRef x, Context ctx) {
- /*
- * If we have a field ref of Enum.ordinal, then we want to allow a
- * cast operation from enum subclass to Enum on the instance. Other
- * optimizers have a tendency to convert things like:
- *
- * 'switch(enumObj)' to
- * 'switch((Enum)enumObj).ordinal'
- *
- * We don't want to blacklist enumObj in that case, so we push this castOp
- * on a stack and check it in the subsequent call to endVisit for
- * JCastOperation. We can't simply return false and prevent
- * the visit of the JCastOperation altogether, since we do need to visit
- * the JCastOperation's sub-expression. Since the sub-expression could
- * potentially also contain similar cast operations, we use a stack to
- * keep track of 'castOpsToIgnore'.
- */
- if (x.getField() == enumOrdinalField) {
- if (x.getInstance() != null &&
- x.getInstance() instanceof JCastOperation) {
- JCastOperation castOp = (JCastOperation) x.getInstance();
- if (getPossiblyUnderlyingType(castOp.getCastType()) == enumType) {
- JEnumType fromType = getEnumType(castOp.getExpr().getType());
- if (fromType != null) {
- castOpsToIgnore.push(castOp);
- }
- }
- }
- }
- return true;
- }
-
- @Override
- public boolean visit(JMethod x, Context ctx) {
- /*
- * Don't want to visit the generated getClass() method on an enum, since
- * it contains a reference to an enum's class literal that we don't want
- * to consider. Make sure this is not a user overloaded version
- * (i.e. check that it has no params).
- */
- if (getEnumType(x.getEnclosingType()) != null &&
- x.getName().equals("getClass") &&
- (x.getOriginalParamTypes() == null || x.getOriginalParamTypes().size() == 0)) {
- return false;
- }
-
- // defer to parent method on ImplicitCastAnalyzer
- return super.visit(x, ctx);
- }
-
- @Override
- public boolean visit(JMethodCall x, Context ctx) {
- /*
- * skip all calls to Enum.createValueOfMap, since they'd get falsely
- * flagged for referencing $VALUES and for implicitly upcasting an
- * array of an enum class, in the arg passing. This method is only
- * used by the enumClass$Map class that gets generated for every enum
- * class. Once ordinalization proceeds, this $Map class should be pruned.
- */
- if (x.getTarget() == enumCreateValueOfMapMethod) {
- return false;
- }
-
- /*
- * If we have a method call of Enum.ordinal(), then we want to allow a
- * cast operation from enum subclass to Enum on the instance. Other
- * optimizers have a tendency to convert things like:
- *
- * 'switch(enumObj.ordinal())' to
- * 'switch((Enum)enumObj).ordinal'
- *
- * We don't want to blacklist enumObj in that case, so we push this castOp
- * on a stack and and check it in the subsequent call to endVisit for
- * JCastOperation (above). We can't simply return false and prevent
- * the visit of the JCastOperation altogether, since we do need to visit
- * the castOperation's sub-expression.
- */
- if (x.getTarget() == enumOrdinalMethod) {
- if (x.getInstance() != null &&
- x.getInstance() instanceof JCastOperation) {
- JCastOperation castOp = (JCastOperation) x.getInstance();
- if (getPossiblyUnderlyingType(castOp.getCastType()) == enumType) {
- JEnumType fromType = getEnumType(castOp.getExpr().getType());
- if (fromType != null) {
- castOpsToIgnore.push(castOp);
- }
- }
- }
- }
-
- // ok to visit
- return true;
- }
-
- /*
- * Override for the method called from ImplicitUpcastAnalyzer,
- * which will be called for any implicit upcast.
- */
- @Override
- protected void processImplicitUpcast(JType fromType, JType destType) {
- if (fromType == nullType) {
- // handle case where a nullType is cast to an enum
- blackListIfEnum(destType);
- } else if (fromType == javaScriptObjectType) {
- // handle case where a javaScriptObject is cast to an enum
- blackListIfEnum(destType);
- } else {
- blackListIfEnumCast(fromType, destType);
- }
- }
-
- private void addToBlackList(JEnumType enumType) {
- ordinalizationBlackList.add(enumType);
- }
-
- private void blackListIfEnum(JType maybeEnum) {
- JEnumType actualEnum = getEnumType(maybeEnum);
- if (actualEnum != null) {
- addToBlackList(actualEnum);
- }
- }
-
- private void blackListIfEnumCast(JType maybeEnum, JType destType) {
- JEnumType actualEnum = getEnumType(maybeEnum);
- JEnumType actualDestType = getEnumType(destType);
- if (actualEnum != null) {
- if (actualDestType != actualEnum) {
- addToBlackList(actualEnum);
- }
- return;
- }
-
- // check JArrayTypes of enums
- actualEnum = getEnumTypeFromArrayElementType(maybeEnum);
- actualDestType = getEnumTypeFromArrayElementType(destType);
- if (actualEnum != null) {
- if (actualDestType != actualEnum) {
- addToBlackList(actualEnum);
- }
- }
- }
-
- private void blackListIfEnumExpression(JExpression instance) {
- if (instance != null) {
- blackListIfEnum(instance.getType());
- }
- }
- }
-
- /**
- * A visitor which replaces enum types with an integer.
- *
- * It sub-classes TypeRemapper, which encapsulates all the locations for a
- * settable type. The overridden remap() method will be called in each
- * instance, and it will test whether the type is a candidate for replacement,
- * and if so, return the new type to set (JPrimitiveType.INT).
- *
- * Any reference to an enum field constant in an expression is replaced
- * with integer.
- *
- * This will also explicitly replace an enum's field constants with its
- * ordinal int values, and remove initialization of enum constants and the
- * $VALUES array in the clinit method for the enum.
- */
- private class ReplaceEnumTypesWithInteger extends TypeRemapper {
-
- @Override
- public boolean visit(JClassType x, Context ctx) {
- // don't waste time visiting the large ClassLiteralHolder class
- if (x == classLiteralHolderType) {
- return false;
- }
-
- // cleanup clinit method for ordinalizable enums
- if (canBeOrdinal(x)) {
- // method 0 is always the clinit
- cleanupClinit(x.getMethods().get(0));
- }
- return true;
- }
-
- @Override
- public boolean visit(JField x, Context ctx) {
- /*
- * Replace an enum field constant, with it's integer valued ordinal.
- */
- if (x instanceof JEnumField && canBeOrdinal(x.getEnclosingType())) {
- int ordinal = ((JEnumField) x).ordinal();
- x.setInitializer(new JDeclarationStatement(x.getSourceInfo(),
- new JFieldRef(x.getSourceInfo(), null, x,
- x.getEnclosingType()), program.getLiteralInt(ordinal)));
- }
- return true;
- }
-
- @Override
- public boolean visit(JFieldRef x, Context ctx) {
- /*
- * Replace an enum field ref with it's integer valued ordinal.
- */
- JField field = x.getField();
- if (field instanceof JEnumField && canBeOrdinal(field.getEnclosingType())) {
- int ordinal = ((JEnumField) field).ordinal();
- ctx.replaceMe(program.getLiteralInt(ordinal));
- }
- return true;
- }
-
- /*
- * Remap enum types with JPrimitiveType.INT
- * This is an override implementation called from TypeRemapper.
- */
- @Override
- protected JType remap(JType type) {
- if (canBeOrdinal(type)) {
- return JPrimitiveType.INT;
- } else {
- return type;
- }
- }
-
- private boolean canBeOrdinal(JType type) {
- JType uType = getPossiblyUnderlyingType(type);
- return uType instanceof JEnumType &&
- !ordinalizationBlackList.contains(uType);
- }
-
- /*
- * Remove initialization of enum constants, and the $VALUES array, in the
- * clinit for an ordinalizable enum.
- */
- private void cleanupClinit(JMethod method) {
- List<JStatement> stmts = ((JMethodBody) method.getBody()).getStatements();
- Iterator<JStatement> it = stmts.iterator();
- // look for statements of the form EnumValueField = ...
- while (it.hasNext()) {
- JStatement stmt = it.next();
- if (stmt instanceof JDeclarationStatement) {
- JVariableRef ref = ((JDeclarationStatement) stmt).getVariableRef();
- if (ref instanceof JFieldRef) {
- JFieldRef enumRef = (JFieldRef) ref;
- if (enumRef.getField().getEnclosingType() == method.getEnclosingType()) {
- // see if LHS is a field ref that corresponds to the class of this method
- if (enumRef.getField() instanceof JEnumField) {
- it.remove();
- } else if (enumRef.getField().getName().equals("$VALUES")) {
- it.remove();
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * A visitor which will replace references to the ordinal field and
- * ordinal method refs with the appropropriate ordinal integer value.
- *
- * Note, this visitor must run after the ReplaceEnumTypesWithInteger visitor,
- * since it depends on detecting the locations where the enumOrdinalField or
- * enumOrdinalMethod have had their types changed to integer.
- */
- private class ReplaceOrdinalFieldAndMethodRefsWithOrdinal extends JModVisitor {
- @Override
- public boolean visit(JClassType x, Context ctx) {
- // don't waste time visiting the large ClassLiteralHolder class
- if (x == classLiteralHolderType) {
- return false;
- }
- return true;
- }
-
- @Override
- public boolean visit(JFieldRef x, Context ctx) {
- /*
- * Check field refs that refer to Enum.ordinal, but which have already
- * been ordinalized by the previous pass. This is implemented with visit
- * instead of endVisit since, in the case of an underlying cast operation,
- * we don't want to traverse the instance expression before we replace it.
- */
- if (x.getField() == enumOrdinalField) {
- if (x.getInstance() != null) {
- JType type = x.getInstance().getType();
- if (type == JPrimitiveType.INT) {
- /*
- * See if this fieldRef was converted to JPrimitiveType.INT, but
- * still points to the Enum.ordinal field. If so, replace the field
- * ref with the ordinalized int itself.
- */
- ctx.replaceMe(x.getInstance());
- } else if (x.getInstance() instanceof JCastOperation) {
- /*
- * See if this reference to Enum.ordinal is via a cast from an enum
- * sub-class, that we've already ordinalized to JPrimitiveType.INT.
- * If so, replace the whole cast operation.
- * (see JFieldRef visit method in CannotBeOrdinalAnalyzer above).
- */
- JCastOperation castOp = (JCastOperation) x.getInstance();
- if (getPossiblyUnderlyingType(castOp.getType()) == enumType) {
- if (castOp.getExpr().getType() == JPrimitiveType.INT) {
- ctx.replaceMe(castOp.getExpr());
- }
- }
- }
- }
- }
- return true;
- }
-
- @Override
- public boolean visit(JMethodCall x, Context ctx) {
- /*
- * See if this methodCall was converted to JPrimitiveType.INT, but still
- * points to the Enum.ordinal() method. If so, replace the method call with
- * the ordinal expression itself. Implement with visit (and not endVisit),
- * so we don't traverse the method call itself unnecessarily.
- */
- if (x.getTarget() == enumOrdinalMethod) {
- if (x.getInstance() != null) {
- JType type = x.getInstance().getType();
- if (type == JPrimitiveType.INT) {
- /*
- * See if this instance was converted to JPrimitiveType.INT, but still
- * points to the Enum.ordinal() method. If so, replace the method call
- * with the ordinalized int itself.
- */
- ctx.replaceMe(x.getInstance());
- } else if (x.getInstance() instanceof JCastOperation) {
- /*
- * See if this reference to Enum.ordinal() is via a cast from an enum
- * sub-class, that we've already ordinalized to JPrimitiveType.INT.
- * If so, replace the whole cast operation.
- * (see JMethodCall visit method in CannotBeOrdinalAnalyzer above).
- */
- JCastOperation castOp = (JCastOperation) x.getInstance();
- if (getPossiblyUnderlyingType(castOp.getType()) == enumType) {
- if (castOp.getExpr().getType() == JPrimitiveType.INT) {
- ctx.replaceMe(castOp.getExpr());
- }
- }
- }
- }
- }
- return true;
- }
- }
-
- private OptimizerStats execImpl() {
- OptimizerStats stats = new OptimizerStats(NAME);
-
- if (tracker != null) {
- tracker.incrementRunCount();
- tracker.maybeDumpAST(program, 0);
- }
-
- // Create black list of enum refs which can't be converted to an ordinal ref
- CannotBeOrdinalAnalyzer ordinalAnalyzer = new CannotBeOrdinalAnalyzer(program);
- ordinalAnalyzer.accept(program);
- ordinalAnalyzer.afterVisitor();
-
- if (tracker != null) {
- for (JEnumType type : enumsVisited.values()) {
- tracker.addVisited(type.getName());
- if (!ordinalizationBlackList.contains(type)) {
- tracker.addOrdinalized(type.getName());
- }
- }
- }
-
- // Bail if we don't need to do any ordinalization
- if (enumsVisited.size() == ordinalizationBlackList.size()) {
- return stats;
- }
-
- // Replace enum type refs
- ReplaceEnumTypesWithInteger replaceEnums = new ReplaceEnumTypesWithInteger();
- replaceEnums.accept(program);
- stats.recordModified(replaceEnums.getNumMods());
-
- if (tracker != null) {
- tracker.maybeDumpAST(program, 1);
- }
-
- // Replace enum field and method refs
- ReplaceOrdinalFieldAndMethodRefsWithOrdinal replaceOrdinalRefs
- = new ReplaceOrdinalFieldAndMethodRefsWithOrdinal();
- replaceOrdinalRefs.accept(program);
- stats.recordModified(replaceOrdinalRefs.getNumMods());
-
- if (tracker != null) {
- tracker.maybeDumpAST(program, 2);
- }
-
- return stats;
- }
-
- private JEnumType getEnumType(JType type) {
- type = getPossiblyUnderlyingType(type);
- if (type instanceof JClassType) {
- return ((JClassType) type).isEnumOrSubclass();
- }
- return null;
- }
-
- private JEnumType getEnumTypeFromArrayElementType(JType type) {
- type = getPossiblyUnderlyingType(type);
- if (type instanceof JArrayType) {
- type = ((JArrayType) type).getElementType();
- if (type instanceof JArrayType) {
- // recurse if multi-dimensional array
- return getEnumTypeFromArrayElementType(type);
- }
- return getEnumType(type);
- }
- return null;
- }
-
- private JType getPossiblyUnderlyingType(JType type) {
- if (type instanceof JReferenceType) {
- return ((JReferenceType) type).getUnderlyingType();
- }
- return type;
- }
-
- /**
- * A simple Tracker class for compiling lists of enum classes processed by
- * this optimizer. If enabled, the results can be logged as debug output, and
- * the results can be tested after running with a given input.
- */
- public static class Tracker {
- private final Set<String> allEnumsVisited;
- private final Set<String> allEnumsOrdinalized;
- private final List<Set<String>> enumsVisitedPerPass;
- private final List<Set<String>> enumsOrdinalizedPerPass;
- private int runCount = -1;
-
- // use TreeSets, for nice sorted iteration for output
- public Tracker() {
- allEnumsVisited = new TreeSet<String>();
- allEnumsOrdinalized = new TreeSet<String>();
- enumsVisitedPerPass = new ArrayList<Set<String>>();
- enumsOrdinalizedPerPass = new ArrayList<Set<String>>();
-
- // add entry for initial pass
- enumsVisitedPerPass.add(new TreeSet<String>());
- enumsOrdinalizedPerPass.add(new TreeSet<String>());
- }
-
- public void addOrdinalized(String ordinalized) {
- enumsOrdinalizedPerPass.get(runCount).add(ordinalized);
- allEnumsOrdinalized.add(ordinalized);
- }
-
- public void addVisited(String visited) {
- enumsVisitedPerPass.get(runCount).add(visited);
- allEnumsVisited.add(visited);
- }
-
- public int getNumOrdinalized() {
- return allEnumsOrdinalized.size();
- }
-
- public int getNumVisited() {
- return allEnumsVisited.size();
- }
-
- public void incrementRunCount() {
- runCount++;
- enumsVisitedPerPass.add(new TreeSet<String>());
- enumsOrdinalizedPerPass.add(new TreeSet<String>());
- }
-
- public boolean isOrdinalized(String className) {
- return allEnumsOrdinalized.contains(className);
- }
-
- public boolean isVisited(String className) {
- return allEnumsVisited.contains(className);
- }
-
- public void logEnumsNotOrdinalized(TreeLogger logger, TreeLogger.Type logType) {
- if (logger != null) {
- logger = logger.branch(logType, "Enums Not Ordinalized:");
- for (String enumVisited : allEnumsVisited) {
- if (!isOrdinalized(enumVisited)) {
- logger.branch(logType, enumVisited);
- }
- }
- }
- }
-
- public void logEnumsOrdinalized(TreeLogger logger, TreeLogger.Type logType) {
- if (logger != null) {
- logger = logger.branch(logType, "Enums Ordinalized:");
- for (String enumOrdinalized : allEnumsOrdinalized) {
- logger.branch(logType, enumOrdinalized);
- }
- }
- }
-
- public void logEnumsOrdinalizedPerPass(TreeLogger logger, TreeLogger.Type logType) {
- if (logger != null) {
- if (allEnumsOrdinalized.size() == 0) {
- return;
- }
- logger = logger.branch(logType, "Enums Ordinalized per Optimization Pass:");
- int pass = 0;
- for (Set<String> enumsOrdinalized : enumsOrdinalizedPerPass) {
- pass++;
- if (enumsOrdinalized.size() > 0) {
- TreeLogger subLogger = logger.branch(logType, "Pass " + pass + ": " +
- enumsOrdinalized.size() + " ordinalized");
- for (String enumOrdinalized : enumsOrdinalized) {
- subLogger.branch(logType, enumOrdinalized);
- }
- }
- }
- }
- }
-
- public void logEnumsVisitedPerPass(TreeLogger logger, TreeLogger.Type logType) {
- if (logger != null) {
- if (allEnumsVisited.size() == 0) {
- return;
- }
- logger = logger.branch(logType, "Enums Visited per Optimization Pass:");
- int pass = 0;
- for (Set<String> enumsVisited : enumsVisitedPerPass) {
- pass++;
- if (enumsVisited.size() > 0) {
- TreeLogger subLogger = logger.branch(logType, "Pass " + pass + ": " +
- enumsVisited.size() + " visited");
- for (String enumVisited : enumsVisited) {
- subLogger.branch(logType, enumVisited);
- }
- }
- }
- }
- }
-
- public void logResults(TreeLogger logger, TreeLogger.Type logType) {
- logger = logResultsSummary(logger, logType);
- logEnumsOrdinalized(logger, logType);
- logEnumsNotOrdinalized(logger, logType);
- }
-
- public void logResultsDetailed(TreeLogger logger, TreeLogger.Type logType) {
- logger = logResultsSummary(logger, logType);
- logEnumsOrdinalizedPerPass(logger, logType);
- // logEnumsVisitedPerPass(logger, logType);
- logEnumsNotOrdinalized(logger, logType);
- }
-
- public TreeLogger logResultsSummary(TreeLogger logger, TreeLogger.Type logType) {
- if (logger != null) {
- logger = logger.branch(logType, "EnumOrdinalizer Results:");
- logger.branch(logType, "After pass " + (runCount + 1));
- logger.branch(logType, allEnumsOrdinalized.size() + " of " +
- allEnumsVisited.size() + " ordinalized");
- return logger;
- }
- return null;
- }
-
- public void maybeDumpAST(JProgram program, int stage) {
- AstDumper.maybeDumpAST(program, NAME + "_" + (runCount + 1) + "_" + stage);
- }
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplicitUpcastAnalyzer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplicitUpcastAnalyzer.java
deleted file mode 100644
index 3239f59..0000000
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplicitUpcastAnalyzer.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2010 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.jjs.impl;
-
-import com.google.gwt.dev.jjs.ast.Context;
-import com.google.gwt.dev.jjs.ast.JBinaryOperation;
-import com.google.gwt.dev.jjs.ast.JBinaryOperator;
-import com.google.gwt.dev.jjs.ast.JConditional;
-import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
-import com.google.gwt.dev.jjs.ast.JField;
-import com.google.gwt.dev.jjs.ast.JExpression;
-import com.google.gwt.dev.jjs.ast.JMethod;
-import com.google.gwt.dev.jjs.ast.JMethodCall;
-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.JReferenceType;
-import com.google.gwt.dev.jjs.ast.JReturnStatement;
-import com.google.gwt.dev.jjs.ast.JThrowStatement;
-import com.google.gwt.dev.jjs.ast.JType;
-import com.google.gwt.dev.jjs.ast.JVisitor;
-import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
-
-import java.util.List;
-
-/**
- * This class will identify instances of an implicit upcast between non-primitive
- * types, and call the overridable processImplicitUpcast method.
- *
- * TODO(jbrosenberg): Consider extending to handle implicit upcasts between primitive types.
- * This is not as straightforward as for reference types, because primitives
- * can be boxed and unboxed implicitly as well.
- */
-public class ImplicitUpcastAnalyzer extends JVisitor {
-
- protected JMethod currentMethod;
- private final JType throwableType;
- private final JType javaScriptObjectType;
- private final JType nullType;
-
- public ImplicitUpcastAnalyzer(JProgram program) {
- this.throwableType = program.getIndexedType("Throwable");
- this.javaScriptObjectType = program.getJavaScriptObject();
- this.nullType = program.getTypeNull();
- }
-
- @Override
- public void endVisit(JBinaryOperation x, Context ctx) {
- if (x.isAssignment()) {
- processIfTypesNotEqual(x.getRhs().getType(), x.getLhs().getType());
- } else if (x.getRhs().getType() == nullType) {
- processIfTypesNotEqual(nullType, x.getLhs().getType());
- } else if (x.getLhs().getType() == nullType) {
- processIfTypesNotEqual(nullType, x.getRhs().getType());
- } else if (x.getOp() == JBinaryOperator.CONCAT ||
- x.getOp() == JBinaryOperator.EQ ||
- x.getOp() == JBinaryOperator.NEQ) {
- /*
- * Since we are not attempting to handle detection of upcasts between
- * primitive types, we limit handling here to CONCAT, EQ and NEQ.
- * Need to do both directions.
- */
- processIfTypesNotEqual(x.getLhs().getType(), x.getRhs().getType());
- processIfTypesNotEqual(x.getRhs().getType(), x.getLhs().getType());
- }
- }
-
- @Override
- public void endVisit(JConditional x, Context ctx) {
- processIfTypesNotEqual(x.getThenExpr().getType(), x.getType());
- processIfTypesNotEqual(x.getElseExpr().getType(), x.getType());
- }
-
- @Override
- public void endVisit(JDeclarationStatement x, Context ctx) {
- if (x.getInitializer() != null) {
- processIfTypesNotEqual(x.getInitializer().getType(),
- x.getVariableRef().getType());
- }
- }
-
- @Override
- public void endVisit(JField x, Context ctx) {
- if (x.getInitializer() == null && !x.isFinal()) {
- if (!(x.getType() instanceof JPrimitiveType)) {
- // if it is declared without an initial value, it defaults to null
- processIfTypesNotEqual(nullType,x.getType());
- }
- }
- }
-
- @Override
- public void endVisit(JMethod x, Context ctx) {
- // check for upcast in return type as compared to an overridden method
- List<JMethod> overrides = x.getOverrides();
- if (overrides != null && overrides.size() > 0) {
- // only check the first one, since other ones will be checked when those
- // overridden methods are visited, don't want to do redundant work
- processIfTypesNotEqual(x.getType(), overrides.get(0).getType());
- }
-
- if (x.getBody() != null && x.getBody().isNative()) {
- /*
- * Check if this method has a native (jsni) method body, in which case
- * all arguments passed in are implicitly cast to JavaScriptObject
- */
- List<JParameter> params = x.getParams();
- for (int i = 0; i < params.size(); i++) {
- processIfTypesNotEqual(params.get(i).getType(), javaScriptObjectType);
- }
-
- /*
- * Check if this method has a non-void return type, in which case
- * it will be implicitly cast from JavaScriptObject
- */
- if (x.getType() != JPrimitiveType.VOID) {
- processIfTypesNotEqual(javaScriptObjectType, x.getType());
- }
- }
- }
-
- @Override
- public void endVisit(JMethodCall x, Context ctx) {
- // check for upcast in argument passing
- List<JExpression> args = x.getArgs();
- List<JParameter> params = x.getTarget().getParams();
-
- for (int i = 0; i < args.size(); i++) {
- // make sure the param wasn't pruned
- if (i < params.size()) {
- processIfTypesNotEqual(args.get(i).getType(), params.get(i).getType());
- }
- }
- }
-
- @Override
- public void endVisit(JsniMethodRef x, Context ctx) {
- // the return type of this method ref will be cast to JavaScriptObject
- if (x.getTarget().getType() != JPrimitiveType.VOID) {
- processIfTypesNotEqual(x.getTarget().getType(), javaScriptObjectType);
- }
-
- // check referenced method's params, which are passed as JavaScriptObjects
- List<JParameter> params = x.getTarget().getParams();
- for (int i = 0; i < params.size(); i++) {
- processIfTypesNotEqual(javaScriptObjectType, params.get(i).getType());
- }
- }
-
- @Override
- public void endVisit(JReturnStatement x, Context ctx) {
- if (x.getExpr() != null) {
- // check against the current method return type
- processIfTypesNotEqual(x.getExpr().getType(), currentMethod.getType());
- }
- }
-
- @Override
- public void endVisit(JThrowStatement x, Context ctx) {
- // all things thrown are upcast to a Throwable
- JType type = x.getExpr().getType();
- if (type instanceof JReferenceType) {
- type = ((JReferenceType) type).getUnderlyingType();
- }
- processIfTypesNotEqual(type, throwableType);
- }
-
- @Override
- public boolean visit(JMethod x, Context ctx) {
- // save this, so can use it later for checking JReturnStatement
- currentMethod = x;
- return true;
- }
-
- /**
- * An overriding method will be called for each detected implicit upcast.
- * @param fromType
- * @param destType
- */
- protected void processImplicitUpcast(JType fromType, JType destType) {
- // override
- }
-
- private void processIfTypesNotEqual(JType fromType, JType destType) {
- if (fromType != destType) {
- processImplicitUpcast(fromType, destType);
- }
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeRemapper.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeRemapper.java
deleted file mode 100644
index d8298d6..0000000
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeRemapper.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2010 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.jjs.impl;
-
-import com.google.gwt.dev.jjs.ast.Context;
-import com.google.gwt.dev.jjs.ast.JBinaryOperation;
-import com.google.gwt.dev.jjs.ast.JCastOperation;
-import com.google.gwt.dev.jjs.ast.JConditional;
-import com.google.gwt.dev.jjs.ast.JConstructor;
-import com.google.gwt.dev.jjs.ast.JGwtCreate;
-import com.google.gwt.dev.jjs.ast.JMethod;
-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.JType;
-import com.google.gwt.dev.jjs.ast.JVariable;
-
-/**
- * This class is a visitor which can find all sites where a JType can be updated
- * from one type to another, and calls an overridable remap method for each
- * instance. An extending class can override the remap and return a new type
- * where it deems it necessary, such as to replace the type of all references
- * of a class.
- */
-public class TypeRemapper extends JModVisitor {
-
- @Override
- public void endVisit(JBinaryOperation x, Context ctx) {
- x.setType(remap(x.getType()));
- }
-
- @Override
- public void endVisit(JCastOperation x, Context ctx) {
- // JCastOperation doesn't have a settable castType method, so need to
- // create a new one and do a replacement.
- JType remapCastType = remap(x.getCastType());
- if (remapCastType != x.getCastType()) {
- JCastOperation newX = new JCastOperation(x.getSourceInfo(),
- remapCastType, x.getExpr());
- ctx.replaceMe(newX);
- }
- }
-
- @Override
- public void endVisit(JConditional x, Context ctx) {
- x.setType(remap(x.getType()));
- }
-
- @Override
- public void endVisit(JConstructor x, Context ctx) {
- x.setType(remap(x.getType()));
- }
-
- @Override
- public void endVisit(JGwtCreate x, Context ctx) {
- x.setType(remap(x.getType()));
- }
-
- @Override
- public void endVisit(JMethod x, Context ctx) {
- x.setType(remap(x.getType()));
- }
-
- @Override
- public void endVisit(JNewArray x, Context ctx) {
- x.setType((JNonNullType) remap(x.getType()));
- }
-
- @Override
- public void endVisit(JVariable x, Context ctx) {
- x.setType(remap(x.getType()));
- }
-
- /**
- * An overriding method will be called for each detected JType element.
- * @param type
- */
- protected JType remap(JType type) {
- // override to possibly return an different type
- return type;
- }
-}
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 133e356..51e913f 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -64,57 +64,22 @@
return code;
}
};
- public static final MockJavaResource CAST = new MockJavaResource(
- "com.google.gwt.lang.Cast") {
- @Override
- protected CharSequence getContent() {
- StringBuffer code = new StringBuffer();
- code.append("package com.google.gwt.lang;\n");
- code.append("public final class Cast {\n");
- code.append(" public static Object dynamicCast(Object src, int dstId) { return src;}\n");
- code.append(" public static boolean isNull(Object a) { return false;}\n");
- code.append(" public static boolean isNotNull(Object a) { return false;}\n");
- code.append(" public static boolean jsEquals(Object a, Object b) { return false;}\n");
- code.append(" public static boolean jsNotEquals(Object a, Object b) { return false;}\n");
- code.append("}\n");
- return code;
- }
- };
public static final MockJavaResource CLASS = new MockJavaResource(
"java.lang.Class") {
@Override
protected CharSequence getContent() {
- // This has extra code in the createForEnum method, to keep it from being inlined
StringBuffer code = new StringBuffer();
code.append("package java.lang;\n");
code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
code.append("public final class Class<T> {\n");
- code.append(" static <T> Class<T> createForArray(String packageName,\n");
- code.append(" String className, String seedName, Class<?> componentType) {\n");
- code.append(" return new Class<T>(); }\n");
- code.append(" static <T> Class<T> createForClass(String packageName,\n");
- code.append(" String className, String seedName, Class<? super T> superclass) {\n");
- code.append(" return new Class<T>(); }\n");
- code.append(" static <T> Class<T> createForEnum(String packageName,\n");
- code.append(" String className, String seedName, Class<? super T> superclass,\n");
- code.append(" JavaScriptObject enumConstantsFunc, JavaScriptObject enumValueOfFunc) {\n");
- code.append(" Class<T> newClass = new Class<T>();\n");
- code.append(" newClass.className = className;\n");
- code.append(" newClass.packageName = packageName;\n");
- code.append(" newClass.seedName = seedName;\n");
- code.append(" return newClass;}\n");
- code.append(" static <T> Class<T> createForInterface(String packageName, String className) {\n");
- code.append(" return new Class<T>(); }\n");
- code.append(" static <T> Class<T> createForPrimitive(String packageName,\n");
- code.append(" String className, String jni) {\n");
- code.append(" return new Class<T>(); }\n");
+ code.append(" static <T> Class<T> createForArray(String packageName, String className, String seedName, Class<?> componentType) { return new Class<T>(); }\n");
+ code.append(" static <T> Class<T> createForClass(String packageName, String className, String seedName, Class<? super T> superclass) { return new Class<T>(); }\n");
+ code.append(" static <T> Class<T> createForEnum(String packageName, String className, String seedName, Class<? super T> superclass, JavaScriptObject enumConstantsFunc, JavaScriptObject enumValueOfFunc) { return new Class<T>(); }\n");
+ code.append(" static <T> Class<T> createForInterface(String packageName, String className) { return new Class<T>(); }\n");
+ code.append(" static <T> Class<T> createForPrimitive(String packageName, String className, String jni) { return new Class<T>(); }\n");
code.append(" static boolean isClassMetadataEnabled() { return true; }\n");
code.append(" public boolean desiredAssertionStatus() { return true; }\n");
- code.append(" public String getName() { return className; }\n");
- code.append(" public T[] getEnumConstants() { return null; }\n");
- code.append(" private String packageName = null;");
- code.append(" private String className = null;");
- code.append(" private String seedName = null;");
+ code.append(" public String getName() { return null; }\n");
code.append("}\n");
return code;
}
@@ -139,20 +104,9 @@
code.append("import java.io.Serializable;\n");
code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
code.append("public abstract class Enum<E extends Enum<E>> implements Serializable {\n");
- code.append(" public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) { \n");
- code.append(" for (T enumConstant : enumType.getEnumConstants()) {\n");
- code.append(" if (enumConstant.name() != null) {\n");
- code.append(" return enumConstant;}}\n");
- code.append(" return null;}\n");
- code.append(" protected Enum(String name, int ordinal) { \n");
- code.append(" this.name = name;\n");
- code.append(" this.ordinal = ordinal;}\n");
- code.append(" protected static <T extends Enum<T>> JavaScriptObject createValueOfMap(T[] enumConstants) { return null;}\n");
+ code.append(" protected Enum(String name, int ordinal) {}\n");
+ code.append(" protected static <T extends Enum<T>> JavaScriptObject createValueOfMap(T[] enumConstants) { return null; }\n");
code.append(" protected static <T extends Enum<T>> T valueOf(JavaScriptObject map, String name) { return null; }\n");
- code.append(" private final String name;\n");
- code.append(" private final int ordinal;\n");
- code.append(" public final String name() { return name; }\n");
- code.append(" public final int ordinal() { return ordinal; }\n");
code.append("}\n");
return code;
}
@@ -286,7 +240,7 @@
// Replace the basic Class and Enum with a compiler-specific one.
result.remove(JavaResourceBase.CLASS);
result.remove(JavaResourceBase.ENUM);
- Collections.addAll(result, ARRAY, CAST, CLASS, CLASSLITERALHOLDER, ENUM, GWT,
+ Collections.addAll(result, ARRAY, CLASS, CLASSLITERALHOLDER, ENUM, GWT,
RUNASYNCCALLBACK);
return result.toArray(new MockJavaResource[result.size()]);
}
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
deleted file mode 100644
index bfe512a..0000000
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/EnumOrdinalizerTest.java
+++ /dev/null
@@ -1,969 +0,0 @@
-/*
- * Copyright 2010 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.jjs.impl;
-
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.jjs.ast.JMethod;
-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 complete test of the resulting ordinalization is not performed. However,
- * the CastNormalizer 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.
- *
- * TODO(jbrosenberg): Provide a test to assert that ordinalization has completed
- * correctly, by inspecting the AST in detail, specifically for ordinal
- * replacements, after the EnumOrdinalizer completes.
- */
-public class EnumOrdinalizerTest extends OptimizerTestBase {
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- // don't need to runDeadCodeElimination, it's after we're done anyway
- runDeadCodeElimination = false;
-
- // defaults, can be overridden by individual test cases
- runTypeTightener = false;
- runMethodCallTightener = false;
- }
-
- public void testOrdinalizeBasicAssignment()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Fruit apple = Fruit.APPLE;",
- "Fruit orange = Fruit.ORANGE;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testOrdinalizableFinalFieldUninitializedByDefault()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl("private final Fruit uninitializedFinalFruit;",
- "public EntryPoint() {",
- " uninitializedFinalFruit = Fruit.ORANGE;",
- "}");
- optimize("void", "EntryPoint ep = new EntryPoint();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testOrdinalizeSwitchStatement()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- setupFruitSwitchMethod();
- optimize("void", "String apple = fruitSwitch(Fruit.APPLE);",
- "String orange = fruitSwitch(Fruit.ORANGE);");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testOrdinalizeIfStatement()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl(
- "public static String fruitIf(Fruit fruit) {",
- " if (fruit == Fruit.APPLE) {",
- " return \"Apple\";",
- " } else if (fruit == Fruit.ORANGE) {",
- " return \"Orange\";",
- " } else {",
- " return \"Unknown\";",
- " }",
- "}");
- optimize("void", "String apple = fruitIf(Fruit.APPLE);",
- "String orange = fruitIf(Fruit.ORANGE);");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testOrdinalizeConditional()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Fruit fruit = (true) ? Fruit.APPLE : Fruit.ORANGE;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testOrdinalizeFieldRefOrdinalMethodCall()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "int i = Fruit.APPLE.ordinal();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testOrdinalizeVariableRefOrdinalMethodCall()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Fruit fruit = Fruit.APPLE;",
- "int i = fruit.ordinal();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testOrdinalizeMethodCallExpressionOrdinalFieldRef()
- throws UnableToCompleteException {
- /*
- * the switch expression gets transformed to
- * 'switch ((Enum) getResolvedFruit(fruit)).ordinal)'
- * by the time the EnumOrdinalizer sees it. So this test is testing the
- * logic to replace an ordinal field ref expression with the expression
- * itself.
- */
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl("public static Fruit getResolvedFruit(Fruit fruit) {",
- " 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;",
- "}");
- optimize("void", "int i = switchMethodCall(Fruit.APPLE);",
- "Fruit fruit = Fruit.ORANGE;",
- "int j = switchMethodCall(fruit);");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableClassLiteralReference()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Class clazz = Fruit.class;",
- "String clazzStr = clazz.toString();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableEnumValueOfWithClassLiteralArg()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Object Carrot = Enum.valueOf(Fruit.class, \"APPLE\");",
- "String carrot = Carrot.toString();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableGetClassMethodCall()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Class clazz = Fruit.APPLE.getClass();",
- "String clazzStr = clazz.toString();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableExplicitCastToEnumClass()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Object obj = new Object();",
- "Fruit fruit = (Fruit) obj;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableExplicitCastToArrayOfEnumClass()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Enum[] enumArray = new Enum[10];",
- "Fruit[] fruitArray = (Fruit[]) enumArray;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableExplicitCastFromArrayOfEnumClass()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Fruit[] fruitArray = new Fruit[10];",
- "Enum[] enumArray = (Enum[]) fruitArray;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableExplicitCastToArrayOfArrayOfEnumClass()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Enum[][] enumArray = new Enum[10][10];",
- "Fruit[][] fruitArray = (Fruit[][]) enumArray;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableExplicitCastFromArrayOfArrayOfEnumClass()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Fruit[][] fruitArray = new Fruit[10][10];",
- "Enum[][] enumArray = (Enum[][]) fruitArray;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableExplicitCastFromEnumClass()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Enum Carrot = (Enum) Fruit.APPLE;",
- "String carrot = Carrot.toString();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableOrdinalMethodRefFromExplicitCastWithBlackListableSubExpression()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "int ord = " +
- "((Fruit) Enum.valueOf(Fruit.class,\"APPLE\")).ordinal();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableInstanceFieldRef()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- // this will cause an instance field ref in the enum constructor
- setupFruitEnumWithInstanceField();
- optimize("void");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableStaticFieldRef()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- // this will cause a static field ref in the enum clinit
- setupFruitEnumWithStaticField();
- optimize("void");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableStaticMethodCallValues()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- // this ends up calling Fruit.clinit() first (which is a static method call)
- setupFruitEnum();
- optimize("void", "Fruit[] fruits = Fruit.values();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableJsniFieldRef()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl("public static Fruit instanceFruit;");
- addSnippetClassDecl("public static native void jsniMethod() /*-{",
- " var x = @test.EntryPoint::instanceFruit",
- "}-*/");
- optimize("void", "instanceFruit = Fruit.APPLE;",
- "jsniMethod();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableJsniFieldRefStatic()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl("public static native void jsniMethod() /*-{",
- " var x = @test.EntryPoint.Fruit::APPLE",
- "}-*/");
- optimize("void", "jsniMethod();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableJsniFieldRefClassLiteral()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl("public static native void jsniMethod() /*-{",
- " var x = @test.EntryPoint.Fruit::class",
- "}-*/");
- optimize("void", "jsniMethod();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastBinaryOpAssignment()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Enum tomato;",
- "tomato = Fruit.APPLE;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastFieldInitializedWithNullByDefault()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl("static private Fruit uninitializedFruitAsNull;");
- optimize("void", "if (uninitializedFruitAsNull != Fruit.APPLE) {",
- " uninitializedFruitAsNull = Fruit.ORANGE;",
- "}");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastBinaryOpEquals()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- setupVegetableEnum();
- optimize("void", "Fruit fruit = Fruit.APPLE;",
- "Enum carrot = (Enum) Vegetable.CARROT;",
- "boolean test = (fruit == carrot);");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- assertTrue(tracker.isVisited("test.EntryPoint$Vegetable"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Vegetable"));
- }
-
- public void testNotOrdinalizableImplicitUpcastBinaryOpNotEquals()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- setupVegetableEnum();
- optimize("void", "Fruit fruit = Fruit.APPLE;",
- "Enum carrot = (Enum) Vegetable.CARROT;",
- // do in opposite order from OpEquals test
- "boolean test = (carrot != fruit);");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- assertTrue(tracker.isVisited("test.EntryPoint$Vegetable"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Vegetable"));
- }
-
- public void testNotOrdinalizableImplicitUpcastBinaryOpEqualsNull()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl("public static boolean testIsNull(Fruit fruit) {",
- " if (fruit == null) {",
- " return true;",
- " } else {",
- " return false;",
- " }",
- "}");
- optimize("void", "Fruit fruit = Fruit.APPLE;",
- "boolean isNull = testIsNull(fruit) || testIsNull(Fruit.ORANGE);");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastBinaryOpNotEqualsNull()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl("public static boolean testIsNull(Fruit fruit) {",
- " if (fruit != null) {",
- " return true;",
- " } else {",
- " return false;",
- " }",
- "}");
- optimize("void", "Fruit fruit = Fruit.APPLE;",
- "boolean isNull = testIsNull(fruit) || testIsNull(Fruit.ORANGE);");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastBinaryOpStringConcat()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Fruit fruit = Fruit.APPLE;",
- "String str = \"A string followed by \" + fruit;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastBinaryOpStringConcat2()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Fruit fruit = Fruit.APPLE;",
- "String str = fruit + \" followed by a string\";");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastBinaryOpStringConcatAssignment()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Fruit fruit = Fruit.APPLE;",
- "String str = \"A string concatenated with: \";",
- "str += fruit;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastDeclarationToNull()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Fruit fruit = null;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastAssignmentToNull()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Fruit fruit;",
- "fruit = null;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastDeclaration()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- optimize("void", "Enum tomato = Fruit.APPLE;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastConditional()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- setupVegetableEnum();
- optimize("void", "Enum tomato = null;",
- "tomato = (true) ? Fruit.APPLE : Vegetable.CARROT;");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- assertTrue(tracker.isVisited("test.EntryPoint$Vegetable"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Vegetable"));
- }
-
- public void testNotOrdinalizableImplicitUpcastOverriddenMethodReturnType()
- throws UnableToCompleteException {
-
- // this test depends on the tighteners running
- runTypeTightener = true;
- runMethodCallTightener = true;
-
- EnumOrdinalizer.startTracker();
-
- /*
- * Create methods with covariant return type, which the MethodTypeTightener
- * will optimize to no longer be covariant, so make sure we check original
- * overridden method type.
- */
- addSnippetClassDecl("public interface EnumInterface {",
- " String name();",
- "}");
- addSnippetClassDecl("public abstract class AbstractClass<T extends EnumInterface> {",
- " public abstract T getEnumClass();",
- "}");
- addSnippetClassDecl("public class CustomClass1 extends AbstractClass<EnumClass1> {",
- " public EnumClass1 getEnumClass() { return EnumClass1.CONST1; }",
- "}");
- addSnippetClassDecl("public class CustomClass2 extends AbstractClass<EnumClass2> {",
- " public EnumClass2 getEnumClass() { return EnumClass2.CONST2; }",
- "}");
- addSnippetClassDecl("public enum EnumClass1 implements EnumInterface {",
- " CONST1;",
- "}");
- addSnippetClassDecl("public enum EnumClass2 implements EnumInterface {",
- " CONST2;",
- "}");
- addSnippetClassDecl("public static void testEnumClass(AbstractClass abstractClass) {",
- " EnumInterface enumClass = abstractClass.getEnumClass();",
- "}");
- optimize("void", "EntryPoint ep = new EntryPoint();",
- "AbstractClass abstractClass1 = ep.new CustomClass1();",
- "AbstractClass abstractClass2 = ep.new CustomClass2();",
- "testEnumClass(abstractClass1);",
- "testEnumClass(abstractClass2);");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$EnumClass1"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$EnumClass1"));
- assertTrue(tracker.isVisited("test.EntryPoint$EnumClass2"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$EnumClass2"));
- }
-
- public void testNotOrdinalizableImplicitUpcastMethodCallArgs()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- 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;",
- "}");
- optimize("void", "String stringApple = getEnumString(Fruit.APPLE);");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastJsniMethodBodyParams()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl("public static native void passEnumToJsniMethod(Fruit myEnum) /*-{",
- "}-*/");
- optimize("void", "passEnumToJsniMethod(Fruit.APPLE);");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastJsniMethodBodyReturnType()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl("public static native Fruit returnFruitViaJsni() /*-{",
- " var myJso;",
- " return myJso;",
- "}-*/");
- optimize("void", "Fruit fruit = returnFruitViaJsni();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastJsniMethodRefParams()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- setupFruitSwitchMethod();
- addSnippetClassDecl("public static native void fruitSwitchViaJsni() /*-{",
- " var myJso;",
- " var result = @test.EntryPoint::fruitSwitch(Ltest/EntryPoint$Fruit;)(myJso);",
- "}-*/");
- optimize("void", "fruitSwitchViaJsni();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastJsniMethodRefReturnType()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- addSnippetClassDecl("public static Fruit returnSomeFruit() {",
- " return Fruit.APPLE;",
- "}");
- addSnippetClassDecl("public static native void jsniMethodRefWithEnumReturn() /*-{",
- " var result = @test.EntryPoint::returnSomeFruit()();",
- "}-*/");
- optimize("void", "jsniMethodRefWithEnumReturn();");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- }
-
- public void testNotOrdinalizableImplicitUpcastReturnStatement()
- throws UnableToCompleteException {
- EnumOrdinalizer.startTracker();
-
- setupFruitEnum();
- setupVegetableEnum();
- addSnippetClassDecl("public static Enum returnAsEnum(int mode) {",
- " 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);");
-
- EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
- EnumOrdinalizer.stopTracker();
-
- assertTrue(tracker.isVisited("test.EntryPoint$Fruit"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit"));
- assertTrue(tracker.isVisited("test.EntryPoint$Vegetable"));
- assertFalse(tracker.isOrdinalized("test.EntryPoint$Vegetable"));
- }
-
- private void setupFruitEnum() {
- addSnippetClassDecl("public enum Fruit {APPLE, ORANGE}");
- setupExtraDummyEnum();
- }
-
- private void setupFruitEnumWithInstanceField() {
- addSnippetClassDecl("public enum Fruit {APPLE(\"a\"), ORANGE(\"b\");",
- " public final String instanceField;",
- " private Fruit(String str) {",
- " instanceField = str;",
- " }",
- "}");
- setupExtraDummyEnum();
- }
-
- private void setupFruitEnumWithStaticField() {
- addSnippetClassDecl("public enum Fruit {APPLE, ORANGE;",
- " public static final String staticField = \"STATIC\";",
- "}");
- setupExtraDummyEnum();
- }
-
- private void setupVegetableEnum() {
- addSnippetClassDecl("public enum Vegetable {CARROT, SPINACH}");
- }
-
- private void setupExtraDummyEnum() {
- /*
- * Assure there are at least more 2 enums in the program, so inlining or
- * tightening doesn't push a single enum sub-class into the methods of the
- * Enum super-class itself (which prevents ordinalization in most cases).
- * TODO(jbrosenberg): Make ordinalization work if there's only 1 enum in
- * a program.
- */
- addSnippetClassDecl("public enum DummyEnum {DUMMY}");
- }
-
- private void setupFruitSwitchMethod() {
- addSnippetClassDecl("public static String fruitSwitch(Fruit fruit) {",
- " switch(fruit) {",
- " case APPLE: return \"Apple\";",
- " case ORANGE: return \"Orange\";",
- " default: return \"Unknown\";",
- " }",
- "}");
- }
-
- /*
- * Always run CastNormalizer 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 runCastNormalizer = true;
- private final boolean runEqualityNormalizer = true;
-
- /*
- * EnumOrdinalizer depends MakeCallsStatic and MethodInliner running before
- * it runs, since they cleanup the internal structure of an enum class to
- * inline instance methods like $init.
- * TODO(jbrosenberg): Update EnumOrdinalizer to be able to succeed
- * irrespective of the ordering and interaction with other optimizers.
- */
- private final boolean runMakeCallsStatic = true;
- private final boolean runMethodInliner = true;
-
- // these can be enabled where needed
- private boolean runMethodCallTightener = false;
- private boolean runTypeTightener = false;
-
- @Override
- protected boolean optimizeMethod(JProgram program, JMethod method) {
- /*
- * EnumOrdinalizer depends MakeCallsStatic and MethodInliner running before
- * it runs, since they cleanup the internal structure of an enum class to
- * inline instance methods like $init.
- *
- * TypeTightener and methodCallTightener are necessary to test some cases
- * involving implicit casts on overridden method call return types.
- *
- * These are a subset of the actual optimizers run in JJS.optimizeLoop().
- */
- boolean didChange = false;
- AstDumper.maybeDumpAST(program, "EnumOrdinalizerTest_start");
-
- if (runMakeCallsStatic) {
- didChange = MakeCallsStatic.exec(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");
- }
-
- didChange = EnumOrdinalizer.exec(program).didChange() || didChange;
- AstDumper.maybeDumpAST(program,
- "EnumOrdinalizerTest_after_EnumOrdinalizer");
-
- /*
- * Run these normalizers to sanity check the AST. If there are any
- * dangling type substitutions, the CastNormalizer will generally find it.
- * If there are any introduced binary ops between an int and a null, the
- * EqualityNormalizer will find it.
- */
- if (runCastNormalizer) {
- CastNormalizer.exec(program, false);
- }
- if (runEqualityNormalizer) {
- EqualityNormalizer.exec(program);
- }
-
- return didChange;
- }
-}
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
index 98a4d13..1dd26ca 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
@@ -34,17 +34,17 @@
protected final class Result {
private final String returnType;
private final String originalCode;
- private final boolean madeChanges;
+ private final boolean madeChages;
private final JProgram optimizedProgram;
private final String methodName;
public Result(JProgram optimizedProgram, String returnType,
- String methodName, String originalCode, boolean madeChanges) {
+ String methodName, String originalCode, boolean madeChages) {
this.optimizedProgram = optimizedProgram;
this.returnType = returnType;
this.methodName = methodName;
this.originalCode = originalCode;
- this.madeChanges = madeChanges;
+ this.madeChages = madeChages;
}
public void into(String... expected) throws UnableToCompleteException {
@@ -77,7 +77,7 @@
}
public void noChange() {
- assertFalse(madeChanges);
+ assertFalse(madeChages);
}
public JMethod findMethod(String methodName) {
diff --git a/user/test/com/google/gwt/user/client/rpc/EnumsTest.java b/user/test/com/google/gwt/user/client/rpc/EnumsTest.java
index ddf59f5..704b656 100644
--- a/user/test/com/google/gwt/user/client/rpc/EnumsTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/EnumsTest.java
@@ -19,8 +19,6 @@
import com.google.gwt.user.client.rpc.EnumsTestService.Basic;
import com.google.gwt.user.client.rpc.EnumsTestService.Complex;
import com.google.gwt.user.client.rpc.EnumsTestService.Subclassing;
-import com.google.gwt.user.client.rpc.EnumsTestService.FieldEnum;
-import com.google.gwt.user.client.rpc.EnumsTestService.FieldEnumWrapper;
/**
* Tests enums over RPC.
@@ -122,32 +120,4 @@
}
});
}
-
- /**
- * Test that enums as fields in a wrapper class can be passed over RPC.
- */
- public void testFieldEnumWrapperClass() {
- delayTestFinishForRpc();
-
- FieldEnumWrapper wrapper = new FieldEnumWrapper();
- wrapper.setFieldEnum(FieldEnum.X);
- getService().echo(wrapper, new AsyncCallback<FieldEnumWrapper>() {
- public void onFailure(Throwable caught) {
- rethrowException(caught);
- }
-
- public void onSuccess(FieldEnumWrapper result) {
- assertNotNull("Was null", result);
- FieldEnum fieldEnum = result.getFieldEnum();
- /*
- * Don't want to do assertEquals(FieldEnum.X, fieldEnum) here,
- * since it will force an implicit upcast on FieldEnum -> Object,
- * which will bias the test. We want to assert that the
- * EnumOrdinalizer properly prevents ordinalization of FieldEnum.
- */
- assertTrue(FieldEnum.X == fieldEnum);
- finishTest();
- }
- });
- }
}
diff --git a/user/test/com/google/gwt/user/client/rpc/EnumsTestService.java b/user/test/com/google/gwt/user/client/rpc/EnumsTestService.java
index 54bb24c..6bd7f1d 100644
--- a/user/test/com/google/gwt/user/client/rpc/EnumsTestService.java
+++ b/user/test/com/google/gwt/user/client/rpc/EnumsTestService.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.user.client.rpc;
-import java.io.Serializable;
-
/**
* RemoteService used to test the use of enums over RPC.
*/
@@ -84,30 +82,7 @@
public abstract String value();
}
- /**
- * Enum to be used as a field in a wrapper class
- */
- public enum FieldEnum {
- X, Y, Z
- }
-
- /**
- * Wrapper class containing an enum field
- */
- public class FieldEnumWrapper implements Serializable {
- private FieldEnum fieldEnum = FieldEnum.Z;
-
- public FieldEnum getFieldEnum() {
- return this.fieldEnum;
- }
-
- public void setFieldEnum(FieldEnum fieldEnum) {
- this.fieldEnum = fieldEnum;
- }
- }
-
Basic echo(Basic value);
Complex echo(Complex value) throws EnumStateModificationException;
Subclassing echo(Subclassing value);
- FieldEnumWrapper echo(FieldEnumWrapper value);
}
diff --git a/user/test/com/google/gwt/user/client/rpc/EnumsTestServiceAsync.java b/user/test/com/google/gwt/user/client/rpc/EnumsTestServiceAsync.java
index af32739..d011d4d 100644
--- a/user/test/com/google/gwt/user/client/rpc/EnumsTestServiceAsync.java
+++ b/user/test/com/google/gwt/user/client/rpc/EnumsTestServiceAsync.java
@@ -18,7 +18,6 @@
import com.google.gwt.user.client.rpc.EnumsTestService.Basic;
import com.google.gwt.user.client.rpc.EnumsTestService.Complex;
import com.google.gwt.user.client.rpc.EnumsTestService.Subclassing;
-import com.google.gwt.user.client.rpc.EnumsTestService.FieldEnumWrapper;
/**
*
@@ -27,5 +26,4 @@
void echo(Basic value, AsyncCallback<Basic> callback);
void echo(Complex value, AsyncCallback<Complex> callback);
void echo(Subclassing value, AsyncCallback<Subclassing> callback);
- void echo(FieldEnumWrapper value, AsyncCallback<FieldEnumWrapper> callback);
}
diff --git a/user/test/com/google/gwt/user/server/rpc/EnumsTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/EnumsTestServiceImpl.java
index 711d9fc..dda7444 100644
--- a/user/test/com/google/gwt/user/server/rpc/EnumsTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/EnumsTestServiceImpl.java
@@ -39,8 +39,4 @@
public Subclassing echo(Subclassing value) {
return value;
}
-
- public FieldEnumWrapper echo(FieldEnumWrapper value) {
- return value;
- }
}