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();
   }