Small nits and new tests for devirtualization of Boolean, Double and String.
Change-Id: I1923cd4aecc057ce2fe7e213b146b8d0171fe1a5
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java b/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
index 8c46eac..e1513b2 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
@@ -51,7 +51,7 @@
* Utility functions to interact with JDT classes.
*/
public final class JdtUtil {
- public static final String JSO_CLASS = "com/google/gwt/core/client/JavaScriptObject";
+ private static final String JSO_CLASS = "com/google/gwt/core/client/JavaScriptObject";
/**
* Returns a source name from an array of names.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java
index 9413c65..d28d70c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java
@@ -33,7 +33,6 @@
import com.google.gwt.dev.jjs.ast.JProgram.DispatchType;
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JReturnStatement;
-import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.JTypeOracle;
import com.google.gwt.dev.jjs.ast.JVariableRef;
import com.google.gwt.dev.jjs.ast.RuntimeConstants;
@@ -215,15 +214,6 @@
}
/**
- * Returns true if getClass() is devirtualized for {@code type}; used in
- * {@link ReplaceGetClassOverrides} to avoid replacing getClass() methods that need
- * trampolines.
- */
- public static boolean isGetClassDevirtualized(JProgram program, JType type) {
- return type == program.getJavaScriptObject() || type == program.getTypeJavaLangString();
- }
-
- /**
* Maps each Object instance methods (ie, {@link Object#equals(Object)}) onto
* its corresponding devirtualizing method.
*/
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index 66fb82f..54cf529 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -3990,8 +3990,7 @@
private boolean isSyntheticGetClassNeeded(TypeDeclaration typeDeclaration, JDeclaredType type) {
// TODO(rluble): We should check whether getClass is implemented by type and only
// instead of blacklisting.
- return type != javaLangObject && type != javaLangString && type.getSuperClass() != null &&
- !JdtUtil.isJsoSubclass(typeDeclaration.binding);
+ return type.getSuperClass() != null && !JdtUtil.isJsoSubclass(typeDeclaration.binding);
}
private void createMethod(AbstractMethodDeclaration x) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceGetClassOverrides.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceGetClassOverrides.java
index 1d04fdc..a789967 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceGetClassOverrides.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceGetClassOverrides.java
@@ -22,12 +22,14 @@
import com.google.gwt.dev.jjs.ast.JMethodCall;
import com.google.gwt.dev.jjs.ast.JModVisitor;
import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.RuntimeConstants;
/**
- * Prune all overrides of Object.getClass() except when the enclosing class is JavaScriptObject
- * (to permit getClass() devirtualization in Devirtualizer to continue to work).
- * Also Inline all method calls to Object.getClass() as Object.clazz.
+ * Prune all overrides of Object.getClass() and inline all method calls to Object.getClass()
+ * as Object.___clazz.
+ * <p>
+ * The Devirtualizer pass needs to run before this pass.
*/
public class ReplaceGetClassOverrides {
public static void exec(JProgram program) {
@@ -48,27 +50,29 @@
@Override
public void endVisit(JMethod x, Context ctx) {
- // Don't prune getClass() for objects where it is devirtualized (String, JSOs for now)
- if (Devirtualizer.isGetClassDevirtualized(program, x.getEnclosingType())) {
- return;
- }
- if (x.getOverriddenMethods().contains(getClassMethod)) {
+ if (isGetClassMethod(x)) {
ctx.removeMe();
}
}
@Override
public void endVisit(JMethodCall x, Context ctx) {
- // Don't inline getClass() for objects where it is devirtualized (String, JSOs for now)
- if (Devirtualizer.isGetClassDevirtualized(program, x.getTarget().getEnclosingType())) {
- return;
- }
- // replace overridden getClass() with reference to Object.clazz field
- if (x.getTarget() == getClassMethod ||
- x.getTarget().getOverriddenMethods().contains(getClassMethod)) {
+
+ // All calls to getClass with reference to Object.clazz field
+ if (isGetClassMethod(x.getTarget())) {
+ assert !isGetClassDevirtualized(x.getTarget().getEnclosingType());
ctx.replaceMe(new JFieldRef(x.getSourceInfo(), x.getInstance(),
clazzField, clazzField.getEnclosingType()));
}
}
+
+ private boolean isGetClassMethod(JMethod method) {
+ return method == getClassMethod || method.getOverriddenMethods().contains(getClassMethod);
+ }
+
+ private boolean isGetClassDevirtualized(JType type) {
+ return type == program.getJavaScriptObject()
+ || program.getRepresentedAsNativeTypes().contains(type);
+ }
}
}
diff --git a/user/super/com/google/gwt/emul/java/lang/Object.java b/user/super/com/google/gwt/emul/java/lang/Object.java
index 717f250..523beba 100644
--- a/user/super/com/google/gwt/emul/java/lang/Object.java
+++ b/user/super/com/google/gwt/emul/java/lang/Object.java
@@ -29,7 +29,6 @@
/**
* Holds class literal for subtypes of Object.
*/
- // BUG: If this field name conflicts with a method param name, JDT will complain
// CHECKSTYLE_OFF
private transient Class<?> ___clazz;
// CHECKSTYLE_ON
@@ -68,10 +67,7 @@
return this == other;
}
- /*
- * magic; Actual assignment to this field is done by Class.createFor() methods by injecting it
- * into the prototype.
- */
+ // TODO(rluble): declare as final
public Class<? extends Object> getClass() {
return ___clazz;
}
@@ -92,3 +88,5 @@
protected void finalize() throws Throwable {
}
}
+// DO NOT REMOVE OR MODIFY THIS magic COMMENT. It is checked by the build system to ensure we
+// are compiling GWT JRE.
\ No newline at end of file
diff --git a/user/super/com/google/gwt/emul/java/lang/String.java b/user/super/com/google/gwt/emul/java/lang/String.java
index e3fad9e..e03cfbf 100644
--- a/user/super/com/google/gwt/emul/java/lang/String.java
+++ b/user/super/com/google/gwt/emul/java/lang/String.java
@@ -433,25 +433,6 @@
}
}
- /**
- * Magic; JSODevirtualizer will use this implementation.<p>
- *
- * Each class gets a synthetic stubs for getClass at AST construction time with the exception of
- * Object, JavaScriptObject and subclasses and String; see {@link GwtAstBuilder.createMembers()}.
- * <p>
- *
- * These stubs are replaced in {@link ReplaceGetClassOverrides} by an access to field __clazz
- * which is initialized in each class prototype to point to the class literal. String is
- * implemented as a plain JavaScript string hence lacking said field.<p>
- *
- * The devirtualizer {@code JsoDevirtualizer} will insert a trampoline that uses this
- * implementation.
- */
- @Override
- public Class<? extends Object> getClass() {
- return String.class;
- }
-
@Override
public int hashCode() {
return HashCodes.hashCodeForString(this);
diff --git a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
index 1a2e150..efebaf6 100644
--- a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
+++ b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
@@ -48,6 +48,7 @@
import com.google.gwt.dev.jjs.test.MethodCallTest;
import com.google.gwt.dev.jjs.test.MethodInterfaceTest;
import com.google.gwt.dev.jjs.test.MiscellaneousTest;
+import com.google.gwt.dev.jjs.test.NativeDevirtualizationTest;
import com.google.gwt.dev.jjs.test.NativeLongTest;
import com.google.gwt.dev.jjs.test.ObjectIdentityTest;
import com.google.gwt.dev.jjs.test.SingleJsoImplTest;
@@ -101,6 +102,7 @@
suite.addTestSuite(MethodCallTest.class);
suite.addTestSuite(MethodInterfaceTest.class);
suite.addTestSuite(MiscellaneousTest.class);
+ suite.addTestSuite(NativeDevirtualizationTest.class);
suite.addTestSuite(NativeLongTest.class);
suite.addTestSuite(ObjectIdentityTest.class);
suite.addTestSuite(ScriptOnlyTest.class);
diff --git a/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java b/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java
index bb81019..5835a14 100644
--- a/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/MiscellaneousTest.java
@@ -16,7 +16,6 @@
package com.google.gwt.dev.jjs.test;
import com.google.gwt.core.client.JavaScriptException;
-import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.junit.client.GWTTestCase;
/**
@@ -295,72 +294,6 @@
}
}
- public void testString() {
- String x = "hi";
- assertEquals("hi", x);
- assertEquals("hi", x.toString());
- x = new String();
- assertEquals("", x);
- x = new String(x);
- assertEquals("", x);
- x = new String("hi");
- assertEquals("hi", x);
- assertEquals('i', x.charAt(1));
- assertEquals("hiyay", x.concat("yay"));
- assertEquals("hihi", x + x);
-
- assertEquals(
- "blahcom.google.gwt.dev.jjs.test.MiscellaneousTestabctruefalsenullc27",
- ("blah" + this + String.valueOf(new char[] {'a', 'b', 'c'}) + true
- + false + null + 'c' + 27));
- }
-
- /**
- * Ensures that polymorphic dispatch to String works correctly.
- */
- @SuppressWarnings("unchecked")
- public void testStringDynamicMethods() {
- Object s = FALSE ? new Object() : "Hello, World!";
- assertEquals(String.class, s.getClass());
- assertEquals("Hello, World!".hashCode(), s.hashCode());
- assertTrue(s.equals("Hello, World!"));
- assertTrue("Hello, World!".equals(s));
- assertFalse(s.equals(""));
- assertFalse("".equals(s));
- assertEquals("Hello, World!", s.toString());
- assertTrue(s instanceof String);
-
- Comparable b = FALSE ? new Integer(1) : "Hello, World!";
- assertTrue(((Comparable) "Hello, World!").compareTo(b) == 0);
- assertTrue(b.compareTo("Hello, World!") == 0);
- assertTrue(((Comparable) "A").compareTo(b) < 0);
- assertTrue(b.compareTo("A") > 0);
- assertTrue(((Comparable) "Z").compareTo(b) > 0);
- assertTrue(b.compareTo("Z") < 0);
- assertTrue(b instanceof String);
-
- CharSequence c = FALSE ? new StringBuilder() : "Hello, World!";
- assertEquals('e', c.charAt(1));
- assertEquals(13, c.length());
- assertEquals("ello", c.subSequence(1, 5));
- assertTrue(c instanceof String);
- }
-
- /**
- * Ensures that dispatch to JavaScript native arrays that are NOT Java arrays works properly.
- */
- public void testNativeJavaScriptArray() {
- Object jsoArray = FALSE ? new Object() : JavaScriptObject.createArray();
- assertEquals(JavaScriptObject.class, jsoArray.getClass());
- assertFalse(jsoArray instanceof Object[]);
-
- Object objectArray = FALSE ? new Object() : new Object[10];
- assertEquals(Object[].class, objectArray.getClass());
- assertTrue(objectArray instanceof Object[]);
-
- assertFalse(jsoArray.toString().equals(objectArray.toString()));
- }
-
@Override
public String toString() {
return "com.google.gwt.dev.jjs.test.MiscellaneousTest";
diff --git a/user/test/com/google/gwt/dev/jjs/test/NativeDevirtualizationTest.java b/user/test/com/google/gwt/dev/jjs/test/NativeDevirtualizationTest.java
new file mode 100644
index 0000000..967cf62
--- /dev/null
+++ b/user/test/com/google/gwt/dev/jjs/test/NativeDevirtualizationTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2015 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.test;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.junit.DoNotRunWith;
+import com.google.gwt.junit.Platform;
+import com.google.gwt.junit.client.GWTTestCase;
+
+import javaemul.internal.HashCodes;
+
+/**
+ * This should probably be refactored at some point.
+ */
+public class NativeDevirtualizationTest extends GWTTestCase {
+
+ public static final String HELLO_WORLD = "Hello, World!";
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.dev.jjs.CompilerSuite";
+ }
+
+ public void testStringDevirtualization() {
+ String x = "hi";
+ assertEquals("hi", x);
+ assertEquals("hi", x.toString());
+ x = new String();
+ assertEquals("", x);
+ x = new String(x);
+ assertEquals("", x);
+ x = new String("hi");
+ assertEquals("hi", x);
+ assertEquals('i', x.charAt(1));
+ assertEquals("hiyay", x.concat("yay"));
+ assertEquals("hihi", x + x);
+
+ assertEquals(
+ "blahabctruefalsenullc27",
+ ("blah" + String.valueOf(new char[] {'a', 'b', 'c'}) + true
+ + false + null + 'c' + 27));
+ Object s = HELLO_WORLD;
+ assertEquals(String.class, s.getClass());
+ assertEquals(HELLO_WORLD, s.toString());
+ assertEquals(HashCodes.hashCodeForString(HELLO_WORLD), s.hashCode());
+
+ assertTrue(s.equals(HELLO_WORLD));
+ assertTrue(HELLO_WORLD.equals(s));
+ assertFalse(s.equals(""));
+ assertFalse("".equals(s));
+ assertEquals(HELLO_WORLD, s.toString());
+ assertTrue(s instanceof String);
+
+ Comparable b = HELLO_WORLD;
+ assertEquals(String.class, b.getClass());
+ assertEquals(HELLO_WORLD, b.toString());
+ assertEquals(HashCodes.hashCodeForString(HELLO_WORLD), b.hashCode());
+
+ assertTrue(((Comparable) HELLO_WORLD).compareTo(b) == 0);
+ assertTrue(b.compareTo(HELLO_WORLD) == 0);
+ assertTrue(((Comparable) "A").compareTo(b) < 0);
+ assertTrue(b.compareTo("A") > 0);
+ assertTrue(((Comparable) "Z").compareTo(b) > 0);
+ assertTrue(b.compareTo("Z") < 0);
+ assertTrue(b instanceof String);
+
+ CharSequence c = HELLO_WORLD;
+ assertEquals(String.class, c.getClass());
+ assertEquals(HELLO_WORLD, c.toString());
+ assertEquals(HashCodes.hashCodeForString(HELLO_WORLD), c.hashCode());
+
+ assertEquals('e', c.charAt(1));
+ assertEquals(13, c.length());
+ assertEquals("ello", c.subSequence(1, 5));
+ assertTrue(c instanceof String);
+ }
+
+ public void testBooleanDevirtualization() {
+ final Boolean FALSE = false;
+ Object o = FALSE;
+ assertEquals(Boolean.class, o.getClass());
+ assertEquals("false", o.toString());
+
+ assertFalse((Boolean) o);
+ assertTrue(o instanceof Boolean);
+ assertFalse(o instanceof Number);
+ assertTrue(o instanceof Comparable);
+
+ Comparable b = FALSE;
+ assertEquals(Boolean.class, b.getClass());
+ assertEquals("false", b.toString());
+ assertEquals(FALSE.hashCode(), b.hashCode());
+ }
+
+ public void testDoubleDevirtualization() {
+ final Double ONE_POINT_ONE = 1.1d;
+ Object o = ONE_POINT_ONE;
+ assertEquals(Double.class, o.getClass());
+ assertEquals("1.1", o.toString());
+
+ assertEquals(1.1d, o);
+ assertTrue(o instanceof Double);
+ assertTrue(o instanceof Number);
+ assertTrue(o instanceof Comparable);
+
+ Comparable b = ONE_POINT_ONE;
+ assertEquals(Double.class, b.getClass());
+ assertEquals("1.1", b.toString());
+ assertEquals(ONE_POINT_ONE.hashCode(), b.hashCode());
+ assertTrue(b.compareTo((Double) 1.2d) < 0);
+
+ Number c = ONE_POINT_ONE;
+ assertEquals(Double.class, c.getClass());
+ assertEquals("1.1", c.toString());
+ assertEquals(ONE_POINT_ONE.hashCode(), c.hashCode());
+ assertEquals(1, c.intValue());
+ }
+
+ /**
+ * Ensures that dispatch to JavaScript native arrays that are NOT Java arrays works properly.
+ */
+ @DoNotRunWith(Platform.Devel)
+ public void testNativeJavaScriptArray() {
+ Object jsoArray = JavaScriptObject.createArray(10);
+ assertEquals(JavaScriptObject.class, jsoArray.getClass());
+ assertTrue(jsoArray instanceof JavaScriptObject);
+
+ Object objectArray = new Object[10];
+ assertEquals(Object[].class, objectArray.getClass());
+ assertTrue(objectArray instanceof Object[]);
+
+ assertFalse(jsoArray.toString().equals(objectArray.toString()));
+ }
+}