Add support to for native JsType arrays.
Java arrays stash some properties to be have to perform casts and array
store checks. Storing properties can be avoided for native JsType arrays,
which in this patch are represented as plan JavaScript arrays.
Change-Id: I63e7dcfa606dd639819f3bc17fd31d16f759cf12
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 a20648a..ac458c1 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
@@ -485,7 +485,10 @@
}
if (type.isArrayType()) {
- return EnumSet.of(DispatchType.JAVA_ARRAY);
+ // A variable of type Object[] could contain an instance of native JsType[], the latter
+ // is treated as a JSO for devirtualization purposes.
+ // TODO(rluble): maybe it should not be treated as a JSO, think .toString().
+ return EnumSet.of(DispatchType.JSO, DispatchType.JAVA_ARRAY);
}
EnumSet<DispatchType> dispatchSet = EnumSet.noneOf(DispatchType.class);
DispatchType dispatchType = getRepresentedAsNativeTypesDispatchMap().get(type);
@@ -1134,6 +1137,15 @@
}
}
+ public boolean isUntypedArrayType(JType type) {
+ if (!type.isArrayType()) {
+ return false;
+ }
+
+ JArrayType arrayType = (JArrayType) type;
+ return arrayType.getLeafType().isJsNative();
+ }
+
public boolean isJavaLangString(JType type) {
assert type != null;
return type.getUnderlyingType() == typeString;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/RuntimeConstants.java b/dev/core/src/com/google/gwt/dev/jjs/ast/RuntimeConstants.java
index af1d122..c1f2e80 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/RuntimeConstants.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/RuntimeConstants.java
@@ -27,13 +27,14 @@
public static final String ARRAY_GET_CLASS_LITERAL_FOR_ARRAY = "Array.getClassLiteralForArray";
public static final String ARRAY_INITIALIZE_UNIDIMENSIONAL_ARRAY = "Array.initUnidimensionalArray";
public static final String ARRAY_INITIALIZE_MULTIDIMENSIONAL_ARRAY = "Array.initMultidimensionalArray";
- public static final String ARRAY_STAMP_JAVA_TYPE_INFO = "Array.stampJavaTypeInfo";
+ public static final String ARRAY_NEW_ARRAY = "Array.newArray";
public static final String ARRAY_SET_CHECK = "Array.setCheck";
+ public static final String ARRAY_STAMP_JAVA_TYPE_INFO = "Array.stampJavaTypeInfo";
+ public static final String ARRAY_IS_JAVA_ARRAY = "Array.isJavaArray";
public static final String CAST_CHAR_TO_STRING = "Cast.charToString";
public static final String CAST_HAS_JAVA_OBJECT_VIRTUAL_DISPATCH =
"Cast.hasJavaObjectVirtualDispatch";
- public static final String CAST_IS_JAVA_ARRAY = "Cast.isJavaArray";
public static final String CAST_THROW_CLASS_CAST_EXCEPTION_UNLESS_NULL
= "Cast.throwClassCastExceptionUnlessNull";
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java
index 21546a2..321ba29 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java
@@ -17,8 +17,8 @@
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.Context;
-import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
@@ -30,17 +30,19 @@
*/
public class JsonArray extends JExpression {
- private final List<JExpression> expressions;
+ private final List<JExpression> expressions = Lists.newArrayList();
- private JClassType arrayType;
+ // JsonArray objects are typed as either JavaScriptObject, Object[], or native JsType[] depending
+ // on the use.
+ private JType arrayType;
- public JsonArray(SourceInfo sourceInfo, JClassType arrayType, Iterable<JExpression> expressions) {
+ public JsonArray(SourceInfo sourceInfo, JType arrayType, List<JExpression> expressions) {
super(sourceInfo);
this.arrayType = arrayType;
- this.expressions = Lists.newArrayList(expressions);
+ this.expressions.addAll(expressions);
}
- public JsonArray(SourceInfo sourceInfo, JClassType arrayType, JExpression... expressions) {
+ public JsonArray(SourceInfo sourceInfo, JType arrayType, JExpression... expressions) {
this(sourceInfo, arrayType, Arrays.asList(expressions));
}
@@ -49,7 +51,7 @@
}
@Override
- public JClassType getType() {
+ public JType getType() {
return arrayType;
}
@@ -66,9 +68,9 @@
/**
* Resolve an external references during AST stitching.
*/
- public void resolve(JClassType jsoType) {
- assert jsoType.replaces(this.arrayType);
- this.arrayType = jsoType;
+ public void resolve(JType arrayType) {
+ assert arrayType.replaces(this.arrayType);
+ this.arrayType = arrayType;
}
@Override
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
index 24c4ba8..2f98cca 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
@@ -37,6 +37,7 @@
import com.google.gwt.dev.jjs.ast.js.JsonArray;
import java.util.Collections;
+import java.util.List;
/**
* Replace array accesses and instantiations with calls to the Array class.
@@ -78,11 +79,25 @@
public void endVisit(JNewArray x, Context ctx) {
JArrayType type = x.getArrayType();
- if (x.getInitializers() != null) {
+ List<JExpression> initializers = x.getInitializers();
+ if (initializers != null) {
+ JsonArray initializerArray = new JsonArray(x.getSourceInfo(), type, initializers);
+ if (program.isUntypedArrayType(type)) {
+ ctx.replaceMe(initializerArray);
+ return;
+ }
ctx.replaceMe(createArrayFromInitializers(x, type));
return;
}
+ if (program.isUntypedArrayType(type) && type.getDims() == 1) {
+ // Create a plain array.
+ ctx.replaceMe(new JMethodCall(x.getSourceInfo(), null,
+ program.getIndexedMethod(RuntimeConstants.ARRAY_NEW_ARRAY),
+ x.getDimensionExpressions().get(0)));
+ return;
+ }
+
int suppliedDimensions = x.getDimensionExpressions().size();
assert (suppliedDimensions >= 1);
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 d28d70c..a1f3fb0 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
@@ -225,7 +225,7 @@
private final JMethod hasJavaObjectVirtualDispatch;
/**
- * Contains the Cast.instanceofArray method.
+ * Contains the Cast.isJavaArray method.
*/
private final JMethod isJavaArray;
@@ -284,7 +284,7 @@
this.hasJavaObjectVirtualDispatch =
program.getIndexedMethod(RuntimeConstants.CAST_HAS_JAVA_OBJECT_VIRTUAL_DISPATCH);
- this.isJavaArray = program.getIndexedMethod(RuntimeConstants.CAST_IS_JAVA_ARRAY);
+ this.isJavaArray = program.getIndexedMethod(RuntimeConstants.ARRAY_IS_JAVA_ARRAY);
// TODO: consider turning on null checks for "this"?
// However, for JSO's there is existing code that relies on nulls being okay.
this.converter = new StaticCallConverter(program, false);
@@ -479,7 +479,7 @@
// Synthesize the dispatch at a single conditional doing the checks in this order.
// isString(obj) ? dispatchToString : (
// isRegularJavaObject(obj) ? obj.method : (
- // isArray(obj) ?
+ // isJavaArray(obj) ?
// dispatchToArray :
// dispatchToJSO
// )
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 9d2e174..054578f 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
@@ -2912,14 +2912,20 @@
return new JStringLiteral(info, intern(string), javaLangString);
}
- /**
- * TODO(scottb): move to UnifyAst and only for non-abstract classes.
- */
private void implementGetClass(JDeclaredType type) {
+ // TODO(rluble): Object.getClass() should be final our JRE, when that is done, GwtAstBuilder
+ // creates overrides for convenience and should unmark Object.getClass as final for
+ // consistency.
JMethod method = type.getMethods().get(GET_CLASS_METHOD_INDEX);
- assert (GwtAstBuilder.GET_CLASS_METHOD_NAME.equals(method.getName()));
+ assert (GET_CLASS_METHOD_NAME.equals(method.getName()));
SourceInfo info = method.getSourceInfo();
- JjsUtils.replaceMethodBody(method, new JClassLiteral(info, type));
+ if (type.isJsoType()) {
+ // return Cast.getClass(this)
+ JjsUtils.replaceMethodBody(method,
+ new JMethodCall(info, null, CAST_GET_CLASS_METHOD, new JThisRef(info, type)));
+ } else {
+ JjsUtils.replaceMethodBody(method, new JClassLiteral(info, type));
+ }
}
private JDeclarationStatement makeDeclaration(SourceInfo info, JLocal local,
@@ -3795,6 +3801,10 @@
JMethod.getExternalizedMethod("com.google.gwt.lang.Exceptions",
"safeClose(Ljava/lang/AutoCloseable;Ljava/lang/Throwable;)Ljava/lang/Throwable;", true);
+ private static JMethod CAST_GET_CLASS_METHOD =
+ JMethod.getExternalizedMethod("com.google.gwt.lang.Cast",
+ "getClass(Ljava/lang/Object;)Ljava/lang/Class;", true);
+
private List<JDeclaredType> processImpl() {
CompilationUnitDeclaration cud = curCud.cud;
if (cud.types == null) {
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 9882345..dd26a50 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
@@ -224,6 +224,7 @@
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,
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 697e74c..80687d6 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
@@ -80,7 +80,8 @@
private boolean isGetClassDevirtualized(JType type) {
return type == program.getJavaScriptObject()
- || program.getRepresentedAsNativeTypes().contains(type);
+ || program.getRepresentedAsNativeTypes().contains(type)
+ || type.isJsNative();
}
}
}
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 af229e6..66c8695 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
@@ -41,6 +41,7 @@
TYPE_JAVA_OBJECT,
TYPE_JAVA_OBJECT_OR_JSO("AllowJso"),
TYPE_JSO("Jso"),
+ TYPE_NATIVE_ARRAY("NativeArray"),
TYPE_JAVA_LANG_OBJECT("AllowJso"),
TYPE_JAVA_LANG_STRING("String"),
TYPE_JAVA_LANG_DOUBLE("Double"),
@@ -54,11 +55,11 @@
private final String castInstanceOfQualifier;
- private TypeCategory() {
+ TypeCategory() {
this("");
}
- private TypeCategory(String castInstanceOfQualifier) {
+ TypeCategory(String castInstanceOfQualifier) {
this.castInstanceOfQualifier = castInstanceOfQualifier;
}
@@ -82,7 +83,9 @@
assert type instanceof JReferenceType;
type = type.getUnderlyingType();
- if (type == program.getTypeJavaLangObject()) {
+ if (program.isUntypedArrayType(type)) {
+ return TypeCategory.TYPE_NATIVE_ARRAY;
+ } else if (type == program.getTypeJavaLangObject()) {
return TypeCategory.TYPE_JAVA_LANG_OBJECT;
} else if (program.getRepresentedAsNativeTypesDispatchMap().containsKey(type)) {
return program.getRepresentedAsNativeTypesDispatchMap().get(type).getTypeCategory();
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 b60bda5..cc4ceea 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,24 +32,35 @@
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_JAVA_LANG_OBJECT = 3;
- private static final int TYPE_JAVA_LANG_STRING = 4;
- private static final int TYPE_JAVA_LANG_DOUBLE = 5;
- private static final int TYPE_JAVA_LANG_BOOLEAN = 6;
- private static final int TYPE_JS_NATIVE = 7;
- private static final int TYPE_JS_NATIVE_PROTOTYPE = 8;
- private static final int TYPE_JS_FUNCTION = 9;
- private static final int TYPE_PRIMITIVE_LONG = 10;
- private static final int TYPE_PRIMITIVE_NUMBER = 11;
- private static final int TYPE_PRIMITIVE_BOOLEAN = 12;
+ 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;
public static <T> T[] stampJavaTypeInfo(Object array, T[] referenceType) {
- stampJavaTypeInfo(referenceType.getClass(), Util.getCastableTypeMap(referenceType),
- Array.getElementTypeId(referenceType), Array.getElementTypeCategory(referenceType), array);
+ if (Array.getElementTypeCategory(referenceType) != TYPE_JS_UNKNOWN_NATIVE) {
+ stampJavaTypeInfo(referenceType.getClass(), Util.getCastableTypeMap(referenceType),
+ Array.getElementTypeId(referenceType),
+ Array.getElementTypeCategory(referenceType), array);
+ }
return Array.asArray(array);
}
/**
+ * Returns an untyped uninitialized array.
+ */
+ static native Object[] newArray(int size) /*-{
+ return new Array(size);
+ }-*/;
+
+ /**
* Creates an array like "new T[a][b][c][][]" by passing in a native JSON
* array, [a, b, c].
*
@@ -71,8 +82,10 @@
JavaScriptObject castableTypeMap, JavaScriptObject elementTypeId, int length,
int elementTypeCategory, int dimensions) {
Object result = initializeArrayElementsWithDefaults(elementTypeCategory, length);
- stampJavaTypeInfo(getClassLiteralForArray(leafClassLiteral, dimensions), castableTypeMap,
- elementTypeId, elementTypeCategory, result);
+ if (elementTypeCategory != TYPE_JS_UNKNOWN_NATIVE) {
+ stampJavaTypeInfo(getClassLiteralForArray(leafClassLiteral, dimensions), castableTypeMap,
+ elementTypeId, elementTypeCategory, result);
+ }
return result;
}
@@ -222,8 +235,10 @@
int elementTypeCategory = isLastDimension ? leafElementTypeCategory : TYPE_JAVA_OBJECT;
Object result = initializeArrayElementsWithDefaults(elementTypeCategory, length);
- stampJavaTypeInfo(getClassLiteralForArray(leafClassLiteral, count - index),
- castableTypeMapExprs[index], elementTypeIds[index], elementTypeCategory, result);
+ if (leafElementTypeCategory != TYPE_JS_UNKNOWN_NATIVE) {
+ stampJavaTypeInfo(getClassLiteralForArray(leafClassLiteral, count - index),
+ castableTypeMapExprs[index], elementTypeIds[index], elementTypeCategory, result);
+ }
if (!isLastDimension) {
// Recurse to next dimension.
@@ -247,9 +262,12 @@
}
private static native int getElementTypeCategory(Object array) /*-{
- return array.__elementTypeCategory$;
+ return array.__elementTypeCategory$ == null
+ ? @Array::TYPE_JS_UNKNOWN_NATIVE
+ : array.__elementTypeCategory$;
}-*/;
+ @HasNoSideEffects
private static native JavaScriptObject getElementTypeId(Object array) /*-{
return array.__elementTypeId$;
}-*/;
@@ -281,6 +299,14 @@
array.__elementTypeCategory$ = elementTypeCategory;
}-*/;
+ /**
+ * Returns true if {@code src} is a Java array.
+ */
+ @HasNoSideEffects
+ static boolean isJavaArray(Object src) {
+ return Cast.isArray(src) && Util.hasTypeMarker(src);
+ }
+
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 98956b8..afb3553 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
@@ -48,9 +48,9 @@
@HasNoSideEffects
static native boolean canCast(Object src, JavaScriptObject dstId) /*-{
if (@com.google.gwt.lang.Cast::instanceOfString(*)(src)) {
- return !!@com.google.gwt.lang.Cast::stringCastMap[dstId]
+ return !!@com.google.gwt.lang.Cast::stringCastMap[dstId];
} else if (src.@java.lang.Object::castableTypeMap) {
- return !!src.@java.lang.Object::castableTypeMap[dstId]
+ return !!src.@java.lang.Object::castableTypeMap[dstId];
} else if (@com.google.gwt.lang.Cast::instanceOfDouble(*)(src)) {
return !!@com.google.gwt.lang.Cast::doubleCastMap[dstId];
} else if (@com.google.gwt.lang.Cast::instanceOfBoolean(*)(src)) {
@@ -93,6 +93,14 @@
}
/**
+ * Allow a cast to (untyped) array. This case covers single and multidimensional JsType arrays.
+ */
+ static Object castToNativeArray(Object src) {
+ checkType(src == null || instanceOfNativeArray(src));
+ return src;
+ }
+
+ /**
* Allow a dynamic cast to an object, always succeeding if it's a JSO.
*/
static Object castToAllowJso(Object src, JavaScriptObject dstId) {
@@ -148,6 +156,13 @@
return typeof(src) === "boolean";
}-*/;
+ /**
+ * Returns true if {@code src} is an array (native or not).
+ */
+ static boolean instanceOfNativeArray(Object src) {
+ return isArray(src);
+ }
+
static boolean instanceOfNative(Object src, JavaScriptObject dstId, String jsType) {
// TODO(goktug): Remove instanceof after new JsInterop semantics.
return instanceOf(src, dstId) || jsinstanceOf(src, jsType);
@@ -319,23 +334,22 @@
* generated trampolines to implement instance dispatch.
*/
static boolean hasJavaObjectVirtualDispatch(Object src) {
- return !instanceofArray(src) && Util.hasTypeMarker(src);
+ return !isArray(src) && Util.hasTypeMarker(src);
}
+ @HasNoSideEffects
/**
* Returns true if {@code src} is a Java array.
*/
- static boolean isJavaArray(Object src) {
- return instanceofArray(src) && Util.hasTypeMarker(src);
- }
-
- /**
- * Returns true if {@code src} is an array (native or not).
- */
- private static native boolean instanceofArray(Object src) /*-{
+ static native boolean isArray(Object src) /*-{
return Array.isArray(src);
}-*/;
+ @HasNoSideEffects
+ static native Class<?> getClass(Object array) /*-{
+ return array.@java.lang.Object::___clazz
+ || @JavaScriptObject::class;
+ }-*/;
}
// CHECKSTYLE_NAMING_ON
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 4438ee9..0bf25ef 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -61,6 +61,7 @@
"package com.google.gwt.lang;",
"import com.google.gwt.core.client.JavaScriptObject;",
"public final class Array {",
+ " static <T> T newArray(int size) { return null; }",
" static void setCheck(Object array, int index, Object value) { }",
" static void initUnidimensionalArray(",
" Class arrayClass, JavaScriptObject castableTypeMap,",
@@ -71,6 +72,7 @@
" static void stampJavaTypeInfo(Class arrayClass, JavaScriptObject castableTypeMap,",
" int elementTypeId, int elementTypeCategory, Object array) { }",
" static <T> Class<T> getClassLiteralForArray() { return null; }",
+ " public static boolean isJavaArray(Object o) { return false; }",
"}"
);
}
@@ -89,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 castToNativeArray(Object src) { return src;}",
" public static Object castToJso(Object src) { return src;}",
" public static Object castToString(Object src) { return src;}",
" public static Object castToDouble(Object src) { return src;}",
@@ -96,18 +99,20 @@
" public static Object castToNative(Object src, int dstId, String type) { return src;}",
" public static Object castToUnknownNative(Object src) { return src;}",
" public static Object castToFunction(Object src) { return src; }",
+ " public static Class<?> getClass(Object src) { return null; }",
" public static boolean hasJavaObjectVirtualDispatch(Object o) { return true; }",
" public static boolean instanceOf(Object src, int dstId) { return false;}",
" 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 instanceOfNativeArray(Object src) { return false;}",
" public static boolean instanceOfAllowJso(Object src, int dst) { return false;}",
" public static boolean instanceOfJso(Object src) { return false;}",
" public static boolean instanceOfUnknownNative(Object src) { return false;}",
" public static boolean instanceOfNative(Object src, ",
" JavaScriptObject dstId, String type) { return false;}",
" public static boolean instanceOfFunction(Object src) { return false; }",
- " public static boolean isJavaArray(Object o) { return false; }",
+ " public static boolean isArray(Object o) { return false; }",
" public static boolean isJavaScriptObject(Object o) { return true; }",
" public static native boolean isNull(Object a) /*-{ }-*/;",
" public static native boolean isNotNull(Object a) /*-{ }-*/;",
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 af1eae9..5e3b74a 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
@@ -48,6 +48,28 @@
"Array.setCheck(a, 1, new EntryPoint$A());");
}
+ 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);");
+ 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]);");
+ 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, []);");
+ }
+
+ public void testNativeJsTypeArray() throws Exception {
+ addSnippetImport("jsinterop.annotations.JsType");
+ addSnippetClassDecl("@JsType(isNative = true) static class A {public String name; }");
+ optimize("void", "A[] a = new A[10];")
+ .intoString("EntryPoint$A[] a = Array.newArray(10);");
+ }
+
@Override
protected boolean doOptimizeMethod(TreeLogger logger, JProgram program, JMethod method) {
program.addEntryMethod(findMainMethod(program));
diff --git a/user/test/com/google/gwt/core/client/interop/JsTypeArrayTest.java b/user/test/com/google/gwt/core/client/interop/JsTypeArrayTest.java
index b938e95..2f9d35d 100644
--- a/user/test/com/google/gwt/core/client/interop/JsTypeArrayTest.java
+++ b/user/test/com/google/gwt/core/client/interop/JsTypeArrayTest.java
@@ -105,31 +105,76 @@
}-*/;
@JsType(isNative = true)
- interface SimpleJsTypeReturnForMultiDimArray {
- @JsProperty int getId();
+ static class SimpleJsTypeReturnForMultiDimArray {
+ @JsProperty public native int getId();
}
- // TODO(rluble): Needs fixes in ImlementCastsAndTypeChecks, ArrayNormalizer and maybe type oracle.
- public void __disabled__testJsType3DimArray_castedFromNativeWithACall() {
+ public void testJsType3DimArray_castFromNativeWithACall() {
SimpleJsTypeReturnForMultiDimArray[][][] array =
(SimpleJsTypeReturnForMultiDimArray[][][]) returnJsType3DimFromNative();
assertEquals(1, array.length);
assertEquals(2, array[0].length);
assertEquals(3, array[0][0].length);
- assertEquals(1, array[0][0][0].getId());
+ assertEquals(2, array[0][0][1].getId());
}
private native Object returnJsType3DimFromNative() /*-{
return [ [ [{id:1}, {id:2}, {}], [] ] ];
}-*/;
- // TODO(rluble): Needs fixes in ImlementCastsAndTypeChecks, ArrayNormalizer and maybe type oracle.
- public void __disabled__testObjectArray_castedFromNative() {
- Object[] array = (Object[]) returnObjectArrayFromNative();
+ private native SimpleJsTypeReturnForMultiDimArray getSimpleJsType(int i) /*-{
+ return {id:i};
+ }-*/;
+
+ public void testObjectArray_castFromNative() {
+ SimpleJsTypeReturnForMultiDimArray[] array =
+ (SimpleJsTypeReturnForMultiDimArray[]) returnObjectArrayFromNative();
+ try {
+ assertNotNull((Object[]) array);
+
+ } catch (ClassCastException expected) {
+ }
assertEquals(3, array.length);
assertEquals("1", array[0]);
}
+ public void testJsTypeArray_objectArrayInterchangeability() {
+ Object[] objArray = new Object[1];
+
+ SimpleJsTypeReturnForMultiDimArray[][][] array =
+ (SimpleJsTypeReturnForMultiDimArray[][][]) objArray;
+
+ objArray[0] = new Object[2];
+ ((Object[]) objArray[0])[0] = new Object[3];
+ array[0][0][1] = getSimpleJsType(2);
+ assertEquals(1, array.length);
+ assertEquals(2, array[0].length);
+ assertEquals(3, array[0][0].length);
+ assertEquals(2, array[0][0][1].getId());
+ }
+
+ public void testObjectArray_instanceOf() {
+ Object array = new Object[0];
+ assertTrue(array instanceof Object[]);
+ assertFalse(array instanceof Double[]);
+ assertFalse(array instanceof int[]);
+ assertFalse(array instanceof SimpleJsTypeReturnForMultiDimArray);
+ assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[]);
+ assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[][]);
+ assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[][][]);
+ }
+
+ public void testJsTypeArray_instanceOf() {
+ Object array = returnJsType3DimFromNative();
+ assertFalse(array instanceof Object[]);
+ assertFalse(array instanceof Double[]);
+ assertFalse(array instanceof int[]);
+ assertFalse(array instanceof SimpleJsTypeReturnForMultiDimArray);
+ assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[]);
+ assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[][]);
+ assertTrue(array instanceof SimpleJsTypeReturnForMultiDimArray[][][]);
+ }
+
private native Object returnObjectArrayFromNative() /*-{
return ["1", "2", "3"];
}-*/;
diff --git a/user/test/com/google/gwt/core/client/interop/JsTypeTest.java b/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
index 6eadfaa..6275c23 100644
--- a/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
+++ b/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
@@ -218,6 +218,8 @@
assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
assertTrue(object instanceof AliasToMyNativeJsTypeWithOnlyInstanceofReference);
assertFalse(object instanceof ConcreteJsType);
+ assertFalse(object instanceof MyNativeJsTypeInterface[]);
+ assertFalse(object instanceof MyNativeJsTypeInterfaceImpl[][]);
}
public void testInstanceOf_jsoWithoutProto() {
@@ -233,6 +235,8 @@
assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
assertFalse(object instanceof AliasToMyNativeJsTypeWithOnlyInstanceofReference);
assertFalse(object instanceof ConcreteJsType);
+ assertFalse(object instanceof MyNativeJsTypeInterface[]);
+ assertFalse(object instanceof MyNativeJsTypeInterfaceImpl[][]);
}
public void testInstanceOf_jsoWithNativeButtonProto() {
@@ -248,6 +252,8 @@
assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
assertFalse(object instanceof AliasToMyNativeJsTypeWithOnlyInstanceofReference);
assertFalse(object instanceof ConcreteJsType);
+ assertFalse(object instanceof MyNativeJsTypeInterface[]);
+ assertFalse(object instanceof MyNativeJsTypeInterfaceImpl[][]);
}
public void testInstanceOf_implementsJsType() {
@@ -264,6 +270,8 @@
assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
assertFalse(object instanceof AliasToMyNativeJsTypeWithOnlyInstanceofReference);
assertFalse(object instanceof ConcreteJsType);
+ assertFalse(object instanceof MyNativeJsTypeInterface[]);
+ assertFalse(object instanceof MyNativeJsTypeInterfaceImpl[][]);
}
public void testInstanceOf_implementsJsTypeWithPrototype() {
@@ -280,6 +288,8 @@
assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
assertFalse(object instanceof AliasToMyNativeJsTypeWithOnlyInstanceofReference);
assertFalse(object instanceof ConcreteJsType);
+ assertFalse(object instanceof MyNativeJsTypeInterface[]);
+ assertFalse(object instanceof MyNativeJsTypeInterfaceImpl[][]);
}
public void testInstanceOf_concreteJsType() {
@@ -296,6 +306,8 @@
assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
assertFalse(object instanceof AliasToMyNativeJsTypeWithOnlyInstanceofReference);
assertTrue(object instanceof ConcreteJsType);
+ assertFalse(object instanceof MyNativeJsTypeInterface[]);
+ assertFalse(object instanceof MyNativeJsTypeInterfaceImpl[][]);
}
public void testInstanceOf_extendsJsTypeWithProto() {
@@ -312,6 +324,8 @@
assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
assertFalse(object instanceof AliasToMyNativeJsTypeWithOnlyInstanceofReference);
assertFalse(object instanceof ConcreteJsType);
+ assertFalse(object instanceof MyNativeJsTypeInterface[]);
+ assertFalse(object instanceof MyNativeJsTypeInterfaceImpl[][]);
}
@JsType(isNative = true, namespace = GLOBAL, name = "JsTypeTest_MyNativeJsType")
diff --git a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
index efebaf6..a17e052 100644
--- a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
+++ b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
@@ -18,6 +18,7 @@
import com.google.gwt.core.client.impl.StackTraceLineNumbersTest;
import com.google.gwt.dev.jjs.scriptonly.ScriptOnlyTest;
import com.google.gwt.dev.jjs.test.AnnotationsTest;
+import com.google.gwt.dev.jjs.test.ArrayTest;
import com.google.gwt.dev.jjs.test.AutoboxTest;
import com.google.gwt.dev.jjs.test.BlankInterfaceTest;
import com.google.gwt.dev.jjs.test.ClassCastTest;
@@ -70,6 +71,7 @@
// $JUnit-BEGIN$
suite.addTestSuite(AnnotationsTest.class);
+ suite.addTestSuite(ArrayTest.class);
suite.addTestSuite(AutoboxTest.class);
suite.addTestSuite(BlankInterfaceTest.class);
suite.addTestSuite(ClassCastTest.class);
diff --git a/user/test/com/google/gwt/dev/jjs/test/ArrayTest.java b/user/test/com/google/gwt/dev/jjs/test/ArrayTest.java
new file mode 100644
index 0000000..2a6c0ad
--- /dev/null
+++ b/user/test/com/google/gwt/dev/jjs/test/ArrayTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.client.GWTTestCase;
+
+import java.util.List;
+
+/**
+ * Tests the Java arrays.
+ */
+public class ArrayTest extends GWTTestCase {
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.dev.jjs.CompilerSuite";
+ }
+
+ private native Object createJsArray(int length) /*-{
+ return new Array(length);
+ }-*/;
+
+ public void testObjectArray_empty() {
+ Object nativeArray = createJsArray(0);
+ assertFalse(nativeArray instanceof Object[]);
+ assertFalse(nativeArray instanceof Object[][]);
+ assertFalse(nativeArray instanceof int[]);
+ assertFalse(nativeArray instanceof List[]);
+ assertTrue(nativeArray.getClass() == JavaScriptObject.class);
+
+ Object objectArray = new Object[0];
+ assertTrue(objectArray instanceof Object[]);
+ assertFalse(objectArray instanceof Object[][]);
+ assertFalse(objectArray instanceof int[]);
+ assertFalse(objectArray instanceof List[]);
+ assertTrue(objectArray.getClass() == Object[].class);
+
+ assertFalse(objectArray.equals(nativeArray));
+ }
+
+ public void testObjectArray_nonEmpty() {
+ // Native array is an object array
+ Object nativeArray = createJsArray(10);
+ assertFalse(nativeArray instanceof Object[]);
+ assertFalse(nativeArray instanceof Object[][]);
+ assertFalse(nativeArray instanceof int[]);
+ assertFalse(nativeArray instanceof List[]);
+ assertTrue(nativeArray.getClass() != Object[].class);
+
+ Object objectArray = new Object[10];
+ assertTrue(objectArray instanceof Object[]);
+ assertFalse(objectArray instanceof Object[][]);
+ assertFalse(objectArray instanceof int[]);
+ assertFalse(objectArray instanceof List[]);
+ assertTrue(objectArray.getClass() == Object[].class);
+
+ assertFalse(objectArray.equals(nativeArray));
+ }
+
+ public void testObjectObjectArray() {
+ Object array = new Object[10][];
+ assertTrue(array instanceof Object[]);
+ assertTrue(array instanceof Object[][]);
+ assertFalse(array instanceof int[]);
+ assertFalse(array instanceof List[]);
+ assertTrue(array.getClass() == Object[][].class);
+
+ Object[] objectArray = (Object[]) array;
+ objectArray[0] = new Object[0];
+ objectArray[1] = new List[1];
+ objectArray[2] = new Double[1];
+
+ try {
+ objectArray[3] = new int[0];
+ fail("Should have thrown ArrayStoreException");
+ } catch (ArrayStoreException expected) {
+ }
+ try {
+ objectArray[4] = new Object();
+ fail("Should have thrown ArrayStoreException");
+ } catch (ArrayStoreException expected) {
+ }
+ }
+
+ public void testArraysToString() {
+ Object[] array = new Object[] { 1, 2 ,3 };
+ assertEquals(Object[].class.getName(), ((Object) array).toString().split("@")[0]);
+ }
+
+}