Allow casting native arrays to Object[].
Change-Id: I51888274d10d3f51bce8644d44a32a524cb63631
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 13b6402..72254c7 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
@@ -331,16 +331,14 @@
private final Map<JMethod, JMethod> staticToInstanceMap = Maps.newIdentityHashMap();
- private JClassType typeClass;
-
- private JClassType typeJavaLangObject;
-
private final Map<String, JDeclaredType> typeNameMap = Maps.newHashMap();
private Map<JField, JType> typesByClassLiteralField;
+ private JClassType typeClass;
+ private JClassType typeJavaLangObject;
+ private JArrayType typeJavaLangObjectArray;
private JClassType typeSpecialClassLiteralHolder;
-
private JClassType typeSpecialJavaScriptObject;
private JClassType typeString;
@@ -414,6 +412,7 @@
switch (name) {
case "java.lang.Object":
typeJavaLangObject = (JClassType) type;
+ typeJavaLangObjectArray = getOrCreateArrayType(type, 1);
break;
case "java.lang.String":
typeString = (JClassType) type;
@@ -1076,6 +1075,10 @@
return typeJavaLangObject;
}
+ public JArrayType getTypeJavaLangObjectArray() {
+ return typeJavaLangObjectArray;
+ }
+
public JClassType getTypeJavaLangString() {
return typeString;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementCastsAndTypeChecks.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementCastsAndTypeChecks.java
index 674cde1..3dfe1e0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementCastsAndTypeChecks.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementCastsAndTypeChecks.java
@@ -37,7 +37,6 @@
import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
import com.google.gwt.thirdparty.guava.common.collect.Maps;
-import java.util.EnumSet;
import java.util.Map;
/**
@@ -228,17 +227,7 @@
private TypeCategory determineTypeCategoryForType(JReferenceType type) {
TypeCategory typeCategory = TypeCategory.typeCategoryForType(type, program);
- assert EnumSet.of(TypeCategory.TYPE_JSO,
- TypeCategory.TYPE_JAVA_OBJECT_OR_JSO,
- TypeCategory.TYPE_NATIVE_ARRAY,
- TypeCategory.TYPE_JAVA_LANG_OBJECT,
- TypeCategory.TYPE_JAVA_LANG_STRING,
- TypeCategory.TYPE_JAVA_LANG_DOUBLE,
- TypeCategory.TYPE_JAVA_LANG_BOOLEAN,
- TypeCategory.TYPE_JAVA_OBJECT,
- TypeCategory.TYPE_JS_UNKNOWN_NATIVE,
- TypeCategory.TYPE_JS_NATIVE,
- TypeCategory.TYPE_JS_FUNCTION).contains(typeCategory);
+ assert typeCategory.castInstanceOfQualifier() != null;
return typeCategory;
}
@@ -298,9 +287,13 @@
this.pruneTrivialCasts = pruneTrivialCasts;
for (TypeCategory t : TypeCategory.values()) {
- String instanceOfMethod = "Cast.instanceOf" + t.castInstanceOfQualifier();
+ String castInstanceOfQualifier = t.castInstanceOfQualifier();
+ if (castInstanceOfQualifier == null) {
+ continue;
+ }
+ String instanceOfMethod = "Cast.instanceOf" + castInstanceOfQualifier;
instanceOfMethodsByTargetTypeCategory.put(t, program.getIndexedMethod(instanceOfMethod));
- String castMethod = "Cast.castTo" + t.castInstanceOfQualifier();
+ String castMethod = "Cast.castTo" + castInstanceOfQualifier;
dynamicCastMethodsByTargetTypeCategory.put(t, program.getIndexedMethod(castMethod));
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
index b0a9f1e..c90ea42 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
@@ -40,10 +40,11 @@
* initialize to zero vs. null).
*/
- TYPE_JAVA_OBJECT,
+ TYPE_JAVA_OBJECT(""),
TYPE_JAVA_OBJECT_OR_JSO("AllowJso"),
TYPE_JSO("Jso"),
TYPE_NATIVE_ARRAY("NativeArray"),
+ TYPE_ARRAY("Array"),
TYPE_JAVA_LANG_OBJECT("AllowJso"),
TYPE_JAVA_LANG_STRING("String"),
TYPE_JAVA_LANG_DOUBLE("Double"),
@@ -58,7 +59,7 @@
private final String castInstanceOfQualifier;
TypeCategory() {
- this("");
+ this(null);
}
TypeCategory(String castInstanceOfQualifier) {
@@ -85,7 +86,9 @@
assert type instanceof JReferenceType;
type = type.getUnderlyingType();
- if (getJsSpecialType(type) != null) {
+ if (type == program.getTypeJavaLangObjectArray()) {
+ return TypeCategory.TYPE_ARRAY;
+ } else if (getJsSpecialType(type) != null) {
return getJsSpecialType(type);
} else if (program.isUntypedArrayType(type)) {
return TypeCategory.TYPE_NATIVE_ARRAY;
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
index cc4ceea..9e843fa 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
@@ -32,17 +32,18 @@
private static final int TYPE_JAVA_OBJECT = 0;
private static final int TYPE_JAVA_OBJECT_OR_JSO = 1;
private static final int TYPE_JSO = 2;
- private static final int TYPE_NATIVE_ARRAYs = 3;
- private static final int TYPE_JAVA_LANG_OBJECT = 4;
- private static final int TYPE_JAVA_LANG_STRING = 5;
- private static final int TYPE_JAVA_LANG_DOUBLE = 6;
- private static final int TYPE_JAVA_LANG_BOOLEAN = 7;
- private static final int TYPE_JS_NATIVE = 8;
- private static final int TYPE_JS_UNKNOWN_NATIVE = 9;
- private static final int TYPE_JS_FUNCTION = 10;
- private static final int TYPE_PRIMITIVE_LONG = 11;
- private static final int TYPE_PRIMITIVE_NUMBER = 12;
- private static final int TYPE_PRIMITIVE_BOOLEAN = 13;
+ private static final int TYPE_NATIVE_ARRAY = 3;
+ private static final int TYPE_ARRAY = 4;
+ private static final int TYPE_JAVA_LANG_OBJECT = 5;
+ private static final int TYPE_JAVA_LANG_STRING = 6;
+ private static final int TYPE_JAVA_LANG_DOUBLE = 7;
+ private static final int TYPE_JAVA_LANG_BOOLEAN = 8;
+ private static final int TYPE_JS_NATIVE = 9;
+ private static final int TYPE_JS_UNKNOWN_NATIVE = 10;
+ private static final int TYPE_JS_FUNCTION = 11;
+ private static final int TYPE_PRIMITIVE_LONG = 12;
+ private static final int TYPE_PRIMITIVE_NUMBER = 13;
+ private static final int TYPE_PRIMITIVE_BOOLEAN = 14;
public static <T> T[] stampJavaTypeInfo(Object array, T[] referenceType) {
if (Array.getElementTypeCategory(referenceType) != TYPE_JS_UNKNOWN_NATIVE) {
@@ -180,6 +181,10 @@
return Cast.instanceOfDouble(value);
case TYPE_JAVA_LANG_BOOLEAN:
return Cast.instanceOfBoolean(value);
+ case TYPE_ARRAY:
+ return Cast.instanceOfArray(value);
+ case TYPE_JS_FUNCTION:
+ return Cast.instanceOfFunction(value);
case TYPE_JAVA_OBJECT:
return Cast.canCast(value, Array.getElementTypeId(array));
case TYPE_JSO:
@@ -307,6 +312,15 @@
return Cast.isArray(src) && Util.hasTypeMarker(src);
}
+ /**
+ * Returns true if {@code src} is a Java array.
+ */
+ static boolean isPrimitiveArray(Object array) {
+ int elementTypeCategory = getElementTypeCategory(array);
+ return elementTypeCategory >= TYPE_PRIMITIVE_LONG
+ && elementTypeCategory <= TYPE_PRIMITIVE_BOOLEAN;
+ };
+
private Array() {
}
}
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
index b230808..6add2d7 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
@@ -93,6 +93,14 @@
}
/**
+ * Allow a cast to an java.lang.Object array, accepting also untyped arrays.
+ */
+ static Object castToArray(Object src) {
+ checkType(src == null || instanceOfArray(src));
+ return src;
+ }
+
+ /**
* Allow a cast to (untyped) array. This case covers single and multidimensional JsType arrays.
*/
static Object castToNativeArray(Object src) {
@@ -157,6 +165,13 @@
}-*/;
/**
+ * Returns true if {@code src} is Java object array or an untyped array.
+ */
+ static boolean instanceOfArray(Object src) {
+ return isArray(src) && !Array.isPrimitiveArray(src);
+ }
+
+ /**
* Returns true if {@code src} is an array (native or not).
*/
static boolean instanceOfNativeArray(Object src) {
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 322f5f0..e9b0b3e 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -91,6 +91,7 @@
" public static native String charToString(char x) /*-{ }-*/;",
" public static Object castTo(Object src, int dstId) { return src;}",
" public static Object castToAllowJso(Object src, int dstId) { return src;}",
+ " public static Object castToArray(Object src) { return src;}",
" public static Object castToNativeArray(Object src) { return src;}",
" public static Object castToJso(Object src) { return src;}",
" public static Object castToString(Object src) { return src;}",
@@ -105,6 +106,7 @@
" public static boolean instanceOfString(Object o) { return true; }",
" public static boolean instanceOfDouble(Object o) { return true; }",
" public static boolean instanceOfBoolean(Object o) { return true; }",
+ " public static boolean instanceOfArray(Object src) { return false;}",
" public static boolean instanceOfNativeArray(Object src) { return false;}",
" public static boolean instanceOfAllowJso(Object src, int dst) { return false;}",
" public static boolean instanceOfJso(Object src) { return false;}",
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/ArrayNormalizerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/ArrayNormalizerTest.java
index 5e3b74a..9e159f1 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/ArrayNormalizerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/ArrayNormalizerTest.java
@@ -51,16 +51,16 @@
public void testObjectArray() throws Exception {
optimize("void", "Object[] o = new Object[10];")
.intoString("Object[] o = Array.initUnidimensionalArray(Object.class, [], " +
- "/* JRuntimeTypeReference */\"java.lang.Object\", 10, 4, 1);");
+ "/* JRuntimeTypeReference */\"java.lang.Object\", 10, 5, 1);");
optimize("void", "Object[] o = {null, null, Object.class};")
.intoString("Object[] o = " +
"Array.stampJavaTypeInfo(" +
"Array.getClassLiteralForArray(ClassLiteralHolder.Ljava_lang_Object_2_classLit, 1), " +
- "[], /* JRuntimeTypeReference */\"java.lang.Object\", 4, [null, null, Object.class]);");
+ "[], /* JRuntimeTypeReference */\"java.lang.Object\", 5, [null, null, Object.class]);");
optimize("void", "Object[] o = new Object[] {};")
.intoString("Object[] o = Array.stampJavaTypeInfo(Array.getClassLiteralForArray(" +
"ClassLiteralHolder.Ljava_lang_Object_2_classLit, 1), [], " +
- "/* JRuntimeTypeReference */\"java.lang.Object\", 4, []);");
+ "/* JRuntimeTypeReference */\"java.lang.Object\", 5, []);");
}
public void testNativeJsTypeArray() throws Exception {
diff --git a/user/test/com/google/gwt/core/interop/JsTypeArrayTest.java b/user/test/com/google/gwt/core/interop/JsTypeArrayTest.java
index 3091eda..9ace5d3 100644
--- a/user/test/com/google/gwt/core/interop/JsTypeArrayTest.java
+++ b/user/test/com/google/gwt/core/interop/JsTypeArrayTest.java
@@ -18,6 +18,7 @@
import com.google.gwt.core.client.ScriptInjector;
import com.google.gwt.junit.client.GWTTestCase;
+import jsinterop.annotations.JsFunction;
import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsProperty;
import jsinterop.annotations.JsType;
@@ -138,11 +139,7 @@
public void testObjectArray_castFromNative() {
SimpleJsTypeReturnForMultiDimArray[] array =
(SimpleJsTypeReturnForMultiDimArray[]) returnObjectArrayFromNative();
- try {
- assertNotNull((Object[]) array);
-
- } catch (ClassCastException expected) {
- }
+ assertNotNull((Object[]) array);
assertEquals(3, array.length);
assertEquals("1", array[0]);
}
@@ -175,7 +172,7 @@
public void testJsTypeArray_instanceOf() {
Object array = returnJsType3DimFromNative();
- assertFalse(array instanceof Object[]);
+ assertTrue(array instanceof Object[]);
assertFalse(array instanceof Double[]);
assertFalse(array instanceof int[]);
assertFalse(array instanceof SimpleJsTypeReturnForMultiDimArray);
@@ -184,7 +181,43 @@
assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[][][]);
}
+ @JsFunction
+ interface SomeFunction {
+ int m(int i);
+ }
+
+ @JsFunction
+ interface SomeOtherFunction {
+ int m(int i);
+ }
+
+ public void testJsFunctionArray() {
+ Object[] array = new SomeFunction[10];
+
+ array[0] = returnSomeFunction();
+
+ assertTrue(array instanceof SomeFunction[]);
+ assertFalse(array instanceof SomeOtherFunction[]);
+
+ try {
+ SomeOtherFunction[] other = (SomeOtherFunction[]) array;
+ fail("Should have thrown");
+ } catch (ClassCastException expected) {
+ }
+
+ try {
+ array[1] = new Object();
+ fail("Should have thrown");
+ } catch (ArrayStoreException expected) {
+ }
+ }
+
private native Object returnObjectArrayFromNative() /*-{
return ["1", "2", "3"];
}-*/;
+
+ private native Object returnSomeFunction() /*-{
+ return function(a) { return a + 2; };
+ }-*/;
+
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/ArrayTest.java b/user/test/com/google/gwt/dev/jjs/test/ArrayTest.java
index 2a6c0ad..908f417 100644
--- a/user/test/com/google/gwt/dev/jjs/test/ArrayTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/ArrayTest.java
@@ -36,7 +36,7 @@
public void testObjectArray_empty() {
Object nativeArray = createJsArray(0);
- assertFalse(nativeArray instanceof Object[]);
+ assertTrue(nativeArray instanceof Object[]);
assertFalse(nativeArray instanceof Object[][]);
assertFalse(nativeArray instanceof int[]);
assertFalse(nativeArray instanceof List[]);
@@ -55,7 +55,7 @@
public void testObjectArray_nonEmpty() {
// Native array is an object array
Object nativeArray = createJsArray(10);
- assertFalse(nativeArray instanceof Object[]);
+ assertTrue(nativeArray instanceof Object[]);
assertFalse(nativeArray instanceof Object[][]);
assertFalse(nativeArray instanceof int[]);
assertFalse(nativeArray instanceof List[]);