Remove string based JavaScript instanceof.
Change-Id: I1cbf5feb30cefc812d03ea7bac0877cef44eceae
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
index 4c77d58..1b97a34 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
@@ -30,6 +30,7 @@
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.JInstanceOf;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JLocal;
import com.google.gwt.dev.jjs.ast.JLocalRef;
@@ -200,6 +201,10 @@
public boolean visit(JCastOperation x, Context ctx) {
// Rescue any JavaScriptObject type that is the target of a cast.
JType targetType = x.getCastType();
+
+ // Casts to native classes use the native constructor qualified name.
+ maybeRescueNativeConstructor(targetType);
+
if (!canBeInstantiatedInJavaScript(targetType)) {
return true;
}
@@ -309,6 +314,13 @@
}
@Override
+ public boolean visit(JInstanceOf expression, Context ctx) {
+ // Instanceof checks for native classes use the native constructor qualified name.
+ maybeRescueNativeConstructor(expression.getTestType());
+ return true;
+ }
+
+ @Override
public boolean visit(JInterfaceType type, Context ctx) {
boolean isReferenced = referencedTypes.contains(type);
boolean isInstantiated = instantiatedTypes.contains(type);
@@ -752,6 +764,13 @@
}
}
+ private void maybeRescueNativeConstructor(JType type) {
+ JConstructor jsConstructor = JjsUtils.getJsNativeConstructorOrNull(type);
+ if (jsConstructor != null) {
+ rescue(jsConstructor);
+ }
+ }
+
/**
* The code is very tightly tied to the behavior of
* Pruner.CleanupRefsVisitor. CleanUpRefsVisitor will prune unread
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index 779e8af..d1e265a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -1097,6 +1097,10 @@
@Override
public JsNameRef transformJsniMethodRef(JsniMethodRef jsniMethodRef) {
JMethod method = jsniMethodRef.getTarget();
+ if (method.isJsNative()) {
+ // Construct Constructor.prototype.jsname or Constructor.
+ return createJsQualifier(method.getQualifiedJsName(), jsniMethodRef.getSourceInfo());
+ }
return names.get(method).makeRef(jsniMethodRef.getSourceInfo());
}
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 955834d..674cde1 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
@@ -34,6 +34,7 @@
import com.google.gwt.dev.jjs.ast.JRuntimeTypeReference;
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.RuntimeConstants;
+import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
import com.google.gwt.thirdparty.guava.common.collect.Maps;
import java.util.EnumSet;
@@ -265,8 +266,12 @@
targetType)));
}
if (method.getParams().size() == 3) {
- call.addArg(program.getStringLiteral(sourceInfo,
- ((JDeclaredType) targetType).getQualifiedJsName()));
+ JDeclaredType declaredType = (JDeclaredType) targetType;
+
+ JMethod jsConstructor = JjsUtils.getJsNativeConstructorOrNull(declaredType);
+ assert jsConstructor != null && declaredType.isJsNative();
+ call.addArg(new JsniMethodRef(sourceInfo, declaredType.getQualifiedJsName(), jsConstructor,
+ program.getJavaScriptObject()));
}
return call;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JjsPredicates.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsPredicates.java
index e0ff7dc..ece07c1 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JjsPredicates.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsPredicates.java
@@ -15,13 +15,22 @@
*/
package com.google.gwt.dev.jjs.impl;
+import com.google.gwt.dev.jjs.ast.HasJsInfo.JsMemberType;
import com.google.gwt.dev.jjs.ast.JMember;
+import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.thirdparty.guava.common.base.Predicate;
/**
* General predicates for Java AST nodes.
*/
public class JjsPredicates {
+ public static final Predicate<JMethod> IS_JS_CONSTRUCTOR =
+ new Predicate<JMethod>() {
+ @Override
+ public boolean apply(JMethod method) {
+ return method.isConstructor() && method.getJsMemberType() == JsMemberType.CONSTRUCTOR;
+ }
+ };
public static Predicate<JMember> IS_SYNTHETIC =
new Predicate<JMember>() {
@Override
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
index 138e336..9098c1c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
@@ -304,6 +304,19 @@
}
/**
+ * Returns a native constructor of a native JsType class.
+ */
+ public static JConstructor getJsNativeConstructorOrNull(JType type) {
+ if (!type.isJsNative() || !(type.getUnderlyingType() instanceof JClassType)) {
+ return null;
+ }
+ JMethod jsConstructor = Iterables.getFirst(Iterables.filter(
+ ((JClassType) type).getMethods(), JjsPredicates.IS_JS_CONSTRUCTOR), null);
+ assert jsConstructor != null;
+ return (JConstructor) jsConstructor;
+ }
+
+ /**
* Returns a description for a type suitable for reporting errors to the users.
*/
public static String getReadableDescription(JType type) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
index 19f5151..9116dc3 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
@@ -179,9 +179,17 @@
x.setType(translate(x.getType().getUnderlyingType()));
}
+ private void maybeFlowIntoNativeConstructor(JType type) {
+ JConstructor jsConstructor = JjsUtils.getJsNativeConstructorOrNull(type);
+ if (jsConstructor != null) {
+ flowInto(jsConstructor);
+ }
+ }
+
@Override
public void endVisit(JCastOperation x, Context ctx) {
x.resolve(translate(x.getCastType()));
+ maybeFlowIntoNativeConstructor(x.getCastType());
}
@Override
@@ -266,6 +274,7 @@
@Override
public void endVisit(JInstanceOf x, Context ctx) {
x.resolve(translate(x.getTestType()));
+ maybeFlowIntoNativeConstructor(x.getTestType());
}
@Override
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 b265669..b230808 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
@@ -127,7 +127,7 @@
/**
* A dynamic cast that optionally checks for JsType prototypes.
*/
- static Object castToNative(Object src, JavaScriptObject dstId, String jsType) {
+ static Object castToNative(Object src, JavaScriptObject dstId, JavaScriptObject jsType) {
// TODO(goktug): Remove canCast after new JsInterop semantics.
checkType(src == null || canCast(src, dstId) || jsinstanceOf(src, jsType));
return src;
@@ -163,7 +163,7 @@
return isArray(src);
}
- static boolean instanceOfNative(Object src, JavaScriptObject dstId, String jsType) {
+ static boolean instanceOfNative(Object src, JavaScriptObject dstId, JavaScriptObject jsType) {
// TODO(goktug): Remove instanceof after new JsInterop semantics.
return instanceOf(src, dstId) || jsinstanceOf(src, jsType);
}
@@ -234,16 +234,8 @@
* Determine if object is an instanceof jsType regardless of window or frame.
*/
@HasNoSideEffects
- private static native boolean jsinstanceOf(Object obj, String jsTypeStr) /*-{
- if (!obj) {
- return false;
- }
-
- var jsType = $wnd;
- for (var i = 0, parts = jsTypeStr.split("."), l = parts.length; i < l ; i++) {
- jsType = jsType && jsType[parts[i]];
- }
- return jsType && obj instanceof jsType;
+ private static native boolean jsinstanceOf(Object obj, JavaScriptObject jsType) /*-{
+ return obj && jsType && obj instanceof jsType;
}-*/;
static native boolean jsNotEquals(Object a, Object b) /*-{
diff --git a/user/test/com/google/gwt/core/interop/JsTypeArrayTest.java b/user/test/com/google/gwt/core/interop/JsTypeArrayTest.java
index dfd7581..3091eda 100644
--- a/user/test/com/google/gwt/core/interop/JsTypeArrayTest.java
+++ b/user/test/com/google/gwt/core/interop/JsTypeArrayTest.java
@@ -15,8 +15,10 @@
*/
package com.google.gwt.core.interop;
+import com.google.gwt.core.client.ScriptInjector;
import com.google.gwt.junit.client.GWTTestCase;
+import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsProperty;
import jsinterop.annotations.JsType;
@@ -24,6 +26,12 @@
* Tests JsType with array functionality.
*/
public class JsTypeArrayTest extends GWTTestCase {
+ @Override
+ protected void gwtSetUp() throws Exception {
+ ScriptInjector.fromString("function JsTypeArrayTest_SimpleJsTypeReturnForMultiDimArray() {}")
+ .setWindow(ScriptInjector.TOP_WINDOW)
+ .inject();
+ }
@Override
public String getModuleName() {
@@ -104,7 +112,8 @@
holder.setArrayParam([{}, {}]);
}-*/;
- @JsType(isNative = true)
+ @JsType(isNative = true, namespace = JsPackage.GLOBAL,
+ name = "JsTypeArrayTest_SimpleJsTypeReturnForMultiDimArray")
static class SimpleJsTypeReturnForMultiDimArray {
@JsProperty public native int getId();
}