Introduces native JsType.

This CL introduces native JsType based on prototype attribute
which will later be replaced by isNative attribute.

The patch doesn't handle static JsMethods/JsProperties, a follow
up patch will fix that.

Change-Id: Ibe5bf89978bb063ad86b003fe296acd02a362ff4
Review-Link: https://gwt-review.googlesource.com/#/c/13520/
diff --git a/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java b/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
index 9236164..58fe3c4 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JSORestrictionsChecker.java
@@ -18,7 +18,6 @@
 import com.google.gwt.dev.jdt.SafeASTVisitor;
 import com.google.gwt.dev.util.InstalledHelpInfo;
 import com.google.gwt.dev.util.collect.Stack;
-import com.google.gwt.thirdparty.guava.common.base.Strings;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
@@ -29,7 +28,6 @@
 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
-import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
 import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
@@ -67,18 +65,17 @@
       "@JsExport and @JsNoExport is not allowed at the same time.";
   public static final String ERR_JSEXPORT_ON_ENUMERATION =
       "@JsExport is not allowed on individual enumerations";
-  public static final String ERR_MUST_EXTEND_MAGIC_PROTOTYPE_CLASS =
-      "Classes implementing @JsType with a prototype must extend that interface's Prototype class";
-  public static final String ERR_CLASS_EXTENDS_MAGIC_PROTOTYPE_BUT_NO_PROTOTYPE_ATTRIBUTE =
-      "Classes implementing a @JsType without a prototype should not extend the Prototype class";
   public static final String ERR_CONSTRUCTOR_WITH_PARAMETERS =
       "Constructors must not have parameters in subclasses of JavaScriptObject";
-  public static final String ERR_INSTANCE_FIELD = "Instance fields cannot be used in subclasses of JavaScriptObject";
+  public static final String ERR_INSTANCE_FIELD =
+      "Instance fields cannot be used in subclasses of JavaScriptObject";
   public static final String ERR_INSTANCE_METHOD_NONFINAL =
       "Instance methods must be 'final' in non-final subclasses of JavaScriptObject";
-  public static final String ERR_IS_NONSTATIC_NESTED = "Nested classes must be 'static' if they extend JavaScriptObject";
+  public static final String ERR_IS_NONSTATIC_NESTED =
+      "Nested classes must be 'static' if they extend JavaScriptObject";
   public static final String ERR_NEW_JSO =
-      "'new' cannot be used to create instances of JavaScriptObject subclasses; instances must originate in JavaScript";
+      "'new' cannot be used to create instances of JavaScriptObject subclasses; "
+      + "instances must originate in JavaScript";
   public static final String ERR_NONEMPTY_CONSTRUCTOR =
       "Constructors must be totally empty in subclasses of JavaScriptObject";
   public static final String ERR_NONPROTECTED_CONSTRUCTOR =
@@ -86,13 +83,10 @@
   public static final String ERR_OVERRIDDEN_METHOD =
       "Methods cannot be overridden in JavaScriptObject subclasses";
   public static final String JSO_CLASS = "com/google/gwt/core/client/JavaScriptObject";
-  public static final String ERR_FORGOT_TO_MAKE_PROTOTYPE_IMPL_JSTYPE = "@JsType subtype extends magic _Prototype class, but _Prototype class doesn't implement JsType";
-  public static final String ERR_JS_TYPE_WITH_PROTOTYPE_SET_NOT_ALLOWED_ON_CLASS_TYPES = "@JsType with prototype set not allowed on class types";
   public static final String ERR_JS_FUNCTION_ONLY_ALLOWED_ON_FUNCTIONAL_INTERFACE =
       "@JsFunction is only allowed on functional interface";
   public static final String ERR_JS_FUNCTION_CANNOT_HAVE_DEFAULT_METHODS =
       "JsFunction cannot have default methods";
-  static boolean LINT_MODE = false;
 
   private enum ClassState {
     NORMAL, JSO
@@ -247,18 +241,6 @@
       }
     }
 
-    private void checkJsType(TypeDeclaration type, TypeBinding typeBinding) {
-      ReferenceBinding binding = (ReferenceBinding) typeBinding;
-      if (binding.isClass()) {
-        AnnotationBinding jsinterfaceAnn = JdtUtil.getAnnotation(typeBinding,
-          JsInteropUtil.JSTYPE_CLASS);
-        String jsPrototype = JdtUtil.getAnnotationParameterString(jsinterfaceAnn, "prototype");
-        if (jsPrototype != null && !"".equals(jsPrototype)) {
-          errorOn(type, ERR_JS_TYPE_WITH_PROTOTYPE_SET_NOT_ALLOWED_ON_CLASS_TYPES);
-        }
-      }
-    }
-
     private void checkJsExport(MethodBinding mb) {
       if (JdtUtil.getAnnotation(mb, JsInteropUtil.JSEXPORT_CLASS) != null) {
         boolean isStatic = mb.isConstructor() || mb.isStatic();
@@ -294,14 +276,6 @@
     private ClassState checkType(TypeDeclaration type) {
       SourceTypeBinding binding = type.binding;
       checkJsFunction(type, binding);
-      if (isJsType(type.binding)) {
-        checkJsType(type, type.binding);
-        return ClassState.NORMAL;
-      }
-
-      if (checkClassImplementingJsType(type)) {
-        return ClassState.NORMAL;
-      }
 
       if (!isJsoSubclass(binding)) {
         return ClassState.NORMAL;
@@ -332,91 +306,6 @@
       return ClassState.JSO;
     }
 
-    private boolean checkClassImplementingJsType(TypeDeclaration type) {
-      ReferenceBinding jsInterface = findNearestJsTypeRecursive(type.binding);
-      if (jsInterface == null) {
-        return false;
-      }
-
-      AnnotationBinding jsinterfaceAnn = JdtUtil.getAnnotation(jsInterface,
-          JsInteropUtil.JSTYPE_CLASS);
-      String jsPrototype = JdtUtil.getAnnotationParameterString(jsinterfaceAnn, "prototype");
-      boolean shouldExtend = !Strings.isNullOrEmpty(jsPrototype);
-      checkClassExtendsMagicPrototype(type, jsInterface, shouldExtend);
-
-      // TODO(cromwellian) add multiple-inheritance checks when ambiguity in spec is resolved
-      return true;
-    }
-
-    private void checkClassExtendsMagicPrototype(TypeDeclaration type, ReferenceBinding jsInterface,
-        boolean shouldExtend) {
-      ReferenceBinding superClass = type.binding.superclass();
-      // if type is the _Prototype stub (implements JsType) exit
-      if (isMagicPrototype(type.binding, jsInterface)) {
-        return;
-      } else if (isMagicPrototypeStub(type)) {
-        errorOn(type, ERR_FORGOT_TO_MAKE_PROTOTYPE_IMPL_JSTYPE);
-      }
-
-      if (shouldExtend) {
-        // super class should be SomeInterface.Prototype, so enclosing type should match the jsInterface
-        if (LINT_MODE && (superClass == null || !isMagicPrototype(superClass, jsInterface))) {
-          errorOn(type, ERR_MUST_EXTEND_MAGIC_PROTOTYPE_CLASS);
-        }
-      } else {
-        if (superClass != null && isMagicPrototype(superClass, jsInterface)) {
-          errorOn(type, ERR_CLASS_EXTENDS_MAGIC_PROTOTYPE_BUT_NO_PROTOTYPE_ATTRIBUTE);
-        }
-      }
-    }
-
-    // Roughly parallels JProgram.isJsTypePrototype()
-    private boolean isMagicPrototype(ReferenceBinding type, ReferenceBinding jsInterface) {
-      if (isMagicPrototypeStub(type)) {
-        for (ReferenceBinding intf : type.superInterfaces()) {
-          if (intf == jsInterface) {
-            return true;
-          }
-        }
-      }
-      return false;
-    }
-
-    private boolean isMagicPrototypeStub(TypeDeclaration type) {
-      return isMagicPrototypeStub(type.binding);
-    }
-
-    private boolean isMagicPrototypeStub(ReferenceBinding binding) {
-      return JdtUtil.getAnnotation(binding, JsInteropUtil.JSTYPEPROTOTYPE_CLASS) != null;
-    }
-
-    /**
-     * Walks up chain of interfaces and superinterfaces to find the first one marked with @JsType.
-     */
-    private ReferenceBinding findNearestJsType(ReferenceBinding binding) {
-      if (isJsType(binding)) {
-        return binding;
-      }
-
-      for (ReferenceBinding intb : binding.superInterfaces()) {
-        ReferenceBinding checkSuperInt = findNearestJsType(intb);
-        if (checkSuperInt != null) {
-          return checkSuperInt;
-        }
-      }
-      return null;
-    }
-
-    private ReferenceBinding findNearestJsTypeRecursive(ReferenceBinding binding) {
-      ReferenceBinding nearest = findNearestJsType(binding);
-      if (nearest != null) {
-        return nearest;
-      } else if (binding.superclass() != null) {
-        return findNearestJsTypeRecursive(binding.superclass());
-      }
-      return null;
-    }
-
     private boolean areAllEnclosingClassesPublic() {
       for (SourceTypeBinding typeBinding : typeBindingStack) {
         if (!typeBinding.isPublic()) {
@@ -470,19 +359,6 @@
   }
 
   /**
-   * Returns the first JsType annotation encountered traversing the type hierarchy upwards from the type.
-   */
-  private boolean isJsType(TypeBinding typeBinding) {
-
-    if (!(typeBinding instanceof ReferenceBinding) || !(typeBinding instanceof SourceTypeBinding)) {
-      return false;
-    }
-
-    AnnotationBinding jsInterface = JdtUtil.getAnnotation(typeBinding, JsInteropUtil.JSTYPE_CLASS);
-    return jsInterface != null;
-  }
-
-  /**
    * Returns {@code true} if {@code typeBinding} is a subtype of
    * {@code JavaScriptObject}, but not {@code JavaScriptObject} itself.
    */
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java b/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java
index 8eb6492..455eed5 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java
@@ -24,7 +24,6 @@
 import com.google.gwt.thirdparty.guava.common.base.Strings;
 
 import org.eclipse.jdt.internal.compiler.ast.Annotation;
-import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
 
 import java.beans.Introspector;
@@ -40,8 +39,6 @@
   public static final String JSNOEXPORT_CLASS = "com.google.gwt.core.client.js.JsNoExport";
   public static final String JSPROPERTY_CLASS = "com.google.gwt.core.client.js.JsProperty";
   public static final String JSTYPE_CLASS = "com.google.gwt.core.client.js.JsType";
-  public static final String JSTYPEPROTOTYPE_CLASS =
-      "com.google.gwt.core.client.js.impl.PrototypeOfJsType";
 
   public static void maybeSetJsInteropProperties(JDeclaredType type, Annotation... annotations) {
     AnnotationBinding jsType = JdtUtil.getAnnotation(annotations, JSTYPE_CLASS);
@@ -106,10 +103,6 @@
     return member instanceof JConstructor ? "" : member.getName();
   }
 
-  public static boolean isJsPrototypeFlag(TypeDeclaration x) {
-    return JdtUtil.getAnnotation(x.annotations, JSTYPEPROTOTYPE_CLASS) != null;
-  }
-
   private static String maybeGetJsNamespace(Annotation[] annotations) {
     AnnotationBinding jsNamespace = JdtUtil.getAnnotation(annotations, JSNAMESPACE_CLASS);
     return JdtUtil.getAnnotationParameterString(jsNamespace, "value");
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniMethodCollector.java b/dev/core/src/com/google/gwt/dev/javac/JsniMethodCollector.java
index 741ba92..a38936c 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniMethodCollector.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniMethodCollector.java
@@ -187,10 +187,6 @@
     int startPos = jsniCode.indexOf("/*-{");
     int endPos = jsniCode.lastIndexOf("}-*/");
     if (startPos < 0 && endPos < 0) {
-      reportJsniError(
-          info,
-          method,
-          "Native methods require a JavaScript implementation enclosed with /*-{ and }-*/");
       return null;
     }
     if (startPos < 0) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java
index 4b94ea6..d2a7f6a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java
@@ -42,7 +42,6 @@
   private final boolean isFinal;
   private boolean isJso;
   private JClassType superClass;
-  private boolean isJsPrototypeStub;
 
   public JClassType(SourceInfo info, String name, boolean isAbstract, boolean isFinal) {
     super(info, name);
@@ -113,6 +112,11 @@
     return false;
   }
 
+  @Override
+  public boolean canBeImplementedExternally() {
+    return isJsNative();
+  }
+
   /**
    * Sets this type's super class.
    */
@@ -125,14 +129,6 @@
     }
   }
 
-  public boolean isJsPrototypeStub() {
-    return isJsPrototypeStub;
-  }
-
-  public void setJsPrototypeStub(boolean isJsPrototype) {
-    this.isJsPrototypeStub = isJsPrototype;
-  }
-
   @Override
   public void traverse(JVisitor visitor, Context ctx) {
     if (visitor.visit(this, ctx)) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
index 01c201a..400b3c4 100755
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
@@ -50,12 +50,12 @@
  */
 public abstract class JDeclaredType extends JReferenceType {
 
-  private String jsPrototype;
   private boolean isJsFunction;
   private boolean isJsType;
   private boolean isClassWideExport;
   private String jsNamespace = null;
   private String jsName = null;
+  private String jsPrototype;
 
   /**
    * The types of nested classes, https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
@@ -380,6 +380,11 @@
     return jsPrototype;
   }
 
+  @Override
+  public boolean isJsNative() {
+    return jsPrototype != null;
+  }
+
   /**
    * Returns this type's super class, or <code>null</code> if this type is
    * {@link Object} or an interface.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
index c260486..d345b66 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -91,7 +91,7 @@
   }
 
   public boolean canBeImplementedExternally() {
-    return isJsFunctionMethod() || isJsInterfaceMethod();
+    return isJsNative() || isJsFunctionMethod() || isJsInterfaceMethod();
   }
 
   private boolean isJsInterfaceMethod() {
@@ -226,6 +226,10 @@
     return false;
   }
 
+  public boolean isJsNative() {
+    return enclosingType != null && enclosingType.isJsNative();
+  }
+
   public void setSpecialization(List<JType> paramTypes, JType returnsType, String targetMethod) {
     this.specialization = new Specialization(paramTypes,
         returnsType == null ? this.getOriginalReturnType() : returnsType, targetMethod);
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 a437cda..3f7607e 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
@@ -130,13 +130,6 @@
     }
   }
 
-  /**
-   * Returns whether a class is a synthetic Prototype class generated by APT or user.
-   */
-  public boolean isJsTypePrototype(JDeclaredType classType) {
-    return classType instanceof JClassType && ((JClassType) classType).isJsPrototypeStub();
-  }
-
   private static final class TreeStatistics extends JVisitor {
     private int nodeCount = 0;
 
@@ -1177,20 +1170,6 @@
     return staticToInstanceMap.containsKey(method);
   }
 
-  public static JInterfaceType maybeGetJsTypeFromPrototype(JDeclaredType classType) {
-    if (classType == null) {
-      return null;
-    }
-    if (classType instanceof JClassType && ((JClassType) classType).isJsPrototypeStub()) {
-      for (JInterfaceType intf : classType.getImplements()) {
-        if (intf.isJsType() && intf.getJsPrototype() != null) {
-          return intf;
-        }
-      }
-    }
-    return null;
-  }
-
   /**
    * If the type is a JSO or an array of JSOs it returns cggcc.JavaScriptObject or an array of
    * cggcc.JavaScriptObject respectively; otherwise returns {@code type}.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java
index d7b7904..6394224 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java
@@ -77,6 +77,10 @@
     return false;
   }
 
+  public boolean isJsNative() {
+    return false;
+  }
+
   public boolean canBeImplementedExternally() {
     return false;
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
index e295c47..0156519 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
@@ -21,7 +21,6 @@
 import com.google.gwt.thirdparty.guava.common.base.Function;
 import com.google.gwt.thirdparty.guava.common.base.Objects;
 import com.google.gwt.thirdparty.guava.common.base.Predicate;
-import com.google.gwt.thirdparty.guava.common.base.Strings;
 import com.google.gwt.thirdparty.guava.common.collect.HashMultimap;
 import com.google.gwt.thirdparty.guava.common.collect.ImmutableList;
 import com.google.gwt.thirdparty.guava.common.collect.ImmutableSetMultimap;
@@ -657,31 +656,6 @@
     }
   }
 
-  /**
-   * Get the nearest JS type.
-   */
-  public JDeclaredType getNearestJsType(JType type, boolean mustHavePrototype) {
-    type = type.getUnderlyingType();
-
-    if (!(type instanceof JDeclaredType)) {
-      return null;
-    }
-
-    JDeclaredType dtype = (JDeclaredType) type;
-    if (dtype.isJsType() && (!mustHavePrototype || !Strings.isNullOrEmpty(dtype.getJsPrototype()))) {
-      return dtype;
-    }
-
-    for (JInterfaceType superIntf : dtype.getImplements()) {
-      JDeclaredType jsIntf = getNearestJsType(superIntf, mustHavePrototype);
-      if (jsIntf != null) {
-        return jsIntf;
-      }
-    }
-
-    return null;
-  }
-
   public JMethod getInstanceMethodBySignature(JClassType type, String signature) {
     return getOrCreateInstanceMethodsBySignatureForType(type).get(signature);
   }
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 b263b4c..d185fdb 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
@@ -618,7 +618,7 @@
           // Returning from this method passes a value from JavaScript into Java.
           maybeRescueJavaScriptObjectPassingIntoJava(method.getType());
         }
-        if (method.canBeCalledExternally()) {
+        if (method.canBeCalledExternally() || method.canBeImplementedExternally()) {
           for (JParameter param : method.getParams()) {
             // Parameters in JsExport, JsType, JsFunction methods should not be pruned in order to
             // keep the API intact.
@@ -630,13 +630,6 @@
           rescueClassLiteralsIfGetClassIsLive();
         }
 
-        if (program.isJsTypePrototype(method.getEnclosingType())) {
-          // for JsInterface Prototype methods, rescue all parameters
-          // because these are stub methods and the parameters would get pruned ordinarily
-          for (JParameter param : method.getParams()) {
-            rescue(param);
-          }
-        }
         if (method.getSpecialization() != null) {
           rescue(method.getSpecialization().getTargetMethod());
         }
@@ -774,9 +767,7 @@
       for (int c = params.size(); i < c; ++i) {
         JExpression arg = args.get(i);
         JParameter param = params.get(i);
-        if (arg.hasSideEffects() || liveFieldsAndMethods.contains(param)
-            // rescue any args of JsInterface Prototype methods
-            || program.isJsTypePrototype(method.getEnclosingType())) {
+        if (arg.hasSideEffects() || liveFieldsAndMethods.contains(param)) {
           this.accept(arg);
           continue;
         }
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 c609e35..2c98b69 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
@@ -518,7 +518,7 @@
       recordSymbol(x, jsName);
 
       // My class scope
-      if (x.getSuperClass() == null || x.getSuperClass().isJsPrototypeStub()) {
+      if (x.getSuperClass() == null) {
         myScope = objectScope;
       } else {
         JsScope parentScope = classScopes.get(x.getSuperClass());
@@ -610,7 +610,7 @@
          * 1:1 mapping to obfuscated symbols. Leaving them in global scope
          * causes no harm.
          */
-        jsFunction = new JsFunction(x.getSourceInfo(), topScope, globalName, true);
+        jsFunction = new JsFunction(x.getSourceInfo(), topScope, globalName, !x.isJsNative());
       }
       if (polymorphicNames.containsKey(x)) {
         polymorphicJsFunctions.add(jsFunction);
@@ -848,8 +848,8 @@
 
       alreadyRan.add(x);
 
-      if (program.isJsTypePrototype(x)) {
-        // Don't generate JS for magic @PrototypeOfJsType stubs classes, strip them from output
+      if (x.isJsNative()) {
+        // Don't generate JS for native JsType.
         return;
       }
 
@@ -857,7 +857,6 @@
       assert !program.immortalCodeGenTypes.contains(x);
       // Super classes should be emitted before the actual class.
       assert x.getSuperClass() == null || program.isReferenceOnly(x.getSuperClass()) ||
-          program.isJsTypePrototype(x.getSuperClass()) ||
           alreadyRan.contains(x.getSuperClass());
 
       List<JsFunction> jsFuncs = popList(x.getMethods().size()); // methods
@@ -1142,7 +1141,7 @@
         globalStmts.add(clinitFunc.makeStmt());
       }
 
-      assert jsFuncs.get(0).getName().getShortIdent().startsWith(GwtAstBuilder.CLINIT_NAME + "_");
+      assert jsFuncs.get(0) == methodBodyMap.get(x.getClinitMethod().getBody());
       jsFuncs.remove(0);
 
       // declare all static methods (Java8) into the global scope
@@ -1301,7 +1300,7 @@
          */
         JDeclaredType type = method.getEnclosingType();
         JDeclaredType clinitTarget = type.getClinitTarget();
-        if (clinitTarget == null || program.isJsTypePrototype(clinitTarget)) {
+        if (clinitTarget == null) {
           if (x.getInstance() != null) {
             pop(); // instance
           }
@@ -1387,7 +1386,7 @@
       jsInvocation.getArguments().addAll(args);
 
       // Is this method targeting a Foo_Prototype class?
-      if (program.isJsTypePrototype(method.getEnclosingType())) {
+      if (method.getEnclosingType().isJsNative()) {
         // TODO(goktug): inline following for further simplifications.
         return dispatchToSuperPrototype(x, method, qualifiedMethodName, jsInvocation);
       } else {
@@ -1417,17 +1416,19 @@
 
     /**
      * Setup qualifier and methodRef to dispatch to super-ctor or super-method.
+     * TODO: review this code
      */
     private JsExpression dispatchToSuperPrototype(JMethodCall x, JMethod method,
         JsNameRef qualifier, JsInvocation jsInvocation) {
 
       // in JsType case, super.foo() call requires SuperCtor.prototype.foo.call(this, args)
       // the method target should be on a class that ends with $Prototype and implements a JsType
+      // TODO: if should be an assert instead
       if (!(method instanceof JConstructor) && method.isOrOverridesJsMethod()) {
         JsNameRef protoRef = prototype.makeRef(x.getSourceInfo());
         JsNameRef methodName = new JsNameRef(x.getSourceInfo(), method.getName());
         // add qualifier so we have jsPrototype.prototype.methodName.call(this, args)
-        String jsPrototype = getJsPrototype(method.getEnclosingType());
+        String jsPrototype = method.getEnclosingType().getJsPrototype();
         protoRef.setQualifier(createJsQualifier(jsPrototype, x.getSourceInfo()));
         methodName.setQualifier(protoRef);
         qualifier.setQualifier(methodName);
@@ -1437,22 +1438,6 @@
       return JsNullLiteral.INSTANCE;
     }
 
-    private String getJsPrototype(JDeclaredType type) {
-      String jsPrototype = null;
-      // find JsType of Prototype method being invoked.
-      for (JInterfaceType intf : type.getImplements()) {
-        JDeclaredType jsIntf = typeOracle.getNearestJsType(intf, true);
-        assert jsIntf instanceof JInterfaceType;
-
-        if (jsIntf != null) {
-          jsPrototype = jsIntf.getJsPrototype();
-          break;
-        }
-      }
-      assert jsPrototype != null : "Unable to find JsType with prototype";
-      return jsPrototype;
-    }
-
     @Override
     public void endVisit(JMultiExpression x, Context ctx) {
       List<JsExpression> exprs = popList(x.getNumberOfExpressions());
@@ -1485,20 +1470,27 @@
 
     @Override
     public void endVisit(JNewInstance x, Context ctx) {
-      JsName ctorName = names.get(x.getTarget());
-      JsNew newOp = new JsNew(x.getSourceInfo(), ctorName.makeRef(x.getSourceInfo()));
+      SourceInfo sourceInfo = x.getSourceInfo();
+      JConstructor ctor = x.getTarget();
+      JsName ctorName = names.get(ctor);
+      JsNew newOp = new JsNew(sourceInfo, ctorName.makeRef(sourceInfo));
       popList(newOp.getArguments(), x.getArgs().size()); // args
       JsExpression newExpr = newOp;
-      if (x.getClassType().isJsFunctionImplementation()) {
+      if (ctor.isJsNative()) {
+        String nativeName = ctor.getEnclosingType().getJsPrototype();
+        newExpr = new JsNew(sourceInfo, createJsQualifier(nativeName, sourceInfo));
+      } else if (x.getClassType().isJsFunctionImplementation()) {
+        // Foo.prototype.samMethod
+        JMethod jsFunctionMethod = getJsFunctionMethod(x.getClassType());
+        JsNameRef funcNameRef = polymorphicNames.get(jsFunctionMethod).makeRef(sourceInfo);
+        JsNameRef protoRef = prototype.makeRef(sourceInfo);
+        funcNameRef.setQualifier(protoRef);
+        protoRef.setQualifier(ctorName.makeRef(sourceInfo));
+
+        // makeLambdaFunction(Foo.prototype.samMethod, new Foo(...))
         JsFunction makeLambdaFunc =
             indexedFunctions.get("JavaClassHierarchySetupUtil.makeLambdaFunction");
-        JMethod jsFunctionMethod = getJsFunctionMethod(x.getClassType());
-        JsNameRef funcNameRef = polymorphicNames.get(jsFunctionMethod).makeRef(x.getSourceInfo());
-        JsNameRef protoRef = prototype.makeRef(x.getSourceInfo());
-        funcNameRef.setQualifier(protoRef);
-        protoRef.setQualifier(ctorName.makeRef(x.getSourceInfo()));
-        // makeLambdaFunction(Foo.prototype.samMethod, new Foo(...))
-        newExpr = new JsInvocation(x.getSourceInfo(), makeLambdaFunc, funcNameRef, newOp);
+        newExpr = new JsInvocation(sourceInfo, makeLambdaFunc, funcNameRef, newOp);
       }
       push(newExpr);
     }
@@ -1663,8 +1655,7 @@
         return false;
       }
 
-      // Don't generate JS for magic @PrototypeOfJsType classes
-      if (program.isJsTypePrototype(x)) {
+      if (x.isJsNative()) {
         return false;
       }
 
@@ -2473,36 +2464,42 @@
       JExpression typeId = getRuntimeTypeReference(x);
       JClassType superClass = x.getSuperClass();
       JExpression superTypeId = (superClass == null) ? JNullLiteral.INSTANCE :
-          getRuntimeTypeReference(x.getSuperClass());
-      // check if there's an overriding prototype
-      JInterfaceType jsPrototypeIntf = JProgram.maybeGetJsTypeFromPrototype(superClass);
-      String jsPrototype = jsPrototypeIntf != null ? jsPrototypeIntf.getJsPrototype() : null;
-      if (x.isJsFunctionImplementation()) {
-        jsPrototype = "Function";
-      }
+          getRuntimeTypeReference(superClass);
+      String jsPrototype = getSuperPrototype(x);
 
       List<JsExpression> defineClassArguments = Lists.newArrayList();
 
       defineClassArguments.add(convertJavaLiteral(typeId));
-      // setup superclass normally
-      if (jsPrototype == null) {
-        defineClassArguments.add(convertJavaLiteral(superTypeId));
-      } else {
-        // setup extension of native JS object
-        // TODO(goktug): need to stash Object methods to the prototype as they are not inhertied.
-        defineClassArguments.add(createJsQualifier(jsPrototype, x.getSourceInfo()));
-      }
-      JsExpression castMap = generateCastableTypeMap(x);
-      defineClassArguments.add(castMap);
-
+      defineClassArguments.add(jsPrototype == null ? convertJavaLiteral(superTypeId) :
+          createJsQualifier(jsPrototype, x.getSourceInfo()));
+      defineClassArguments.add(generateCastableTypeMap(x));
       defineClassArguments.addAll(constructorArgs);
 
-      // choose appropriate setup function
       // JavaClassHierarchySetupUtil.defineClass(typeId, superTypeId, castableMap, constructors)
       JsStatement defineClassStatement = constructInvocation(x.getSourceInfo(),
           "JavaClassHierarchySetupUtil.defineClass", defineClassArguments).makeStmt();
       globalStmts.add(defineClassStatement);
       typeForStatMap.put(defineClassStatement, x);
+
+      if (jsPrototype != null) {
+        JExpression objectTypeId = getRuntimeTypeReference(program.getTypeJavaLangObject());
+        JsStatement statement =
+            constructInvocation(x.getSourceInfo(), "JavaClassHierarchySetupUtil.copyObjectMethods",
+                convertJavaLiteral(objectTypeId)).makeStmt();
+        globalStmts.add(statement);
+        typeForStatMap.put(statement, x);
+      }
+    }
+
+    private String getSuperPrototype(JClassType x) {
+      if (x.isJsFunctionImplementation()) {
+        return "Function";
+      }
+      JClassType superClass = x.getSuperClass();
+      if (superClass != null && superClass.isJsNative()) {
+        return superClass.getJsPrototype();
+      }
+      return null;
     }
 
     private void generateClassDefinition(JClassType x, List<JsStatement> globalStmts) {
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 1768df2..771d3c6 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
@@ -3089,7 +3089,9 @@
     private void processNativeMethod(MethodDeclaration x) {
       JMethod method = curMethod.method;
       JsniMethod jsniMethod = jsniMethods.get(x);
-      assert jsniMethod != null;
+      if (jsniMethod == null) {
+        return;
+      }
       SourceInfo info = method.getSourceInfo();
       JsFunction jsFunction = jsniMethod.function();
       JsniMethodBody body = new JsniMethodBody(info);
@@ -4191,9 +4193,6 @@
       JDeclaredType type;
       if (binding.isClass()) {
         type = new JClassType(info, name, binding.isAbstract(), binding.isFinal());
-        if (isJsInteropEnabled) {
-          ((JClassType) type).setJsPrototypeStub(JsInteropUtil.isJsPrototypeFlag(x));
-        }
       } else if (binding.isInterface() || binding.isAnnotationType()) {
         type = new JInterfaceType(info, name);
       } else if (binding.isEnum()) {
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 71cb6c9..553a1a4 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
@@ -21,9 +21,9 @@
 import com.google.gwt.dev.jjs.ast.JBinaryOperation;
 import com.google.gwt.dev.jjs.ast.JBinaryOperator;
 import com.google.gwt.dev.jjs.ast.JCastOperation;
+import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JExpression;
 import com.google.gwt.dev.jjs.ast.JInstanceOf;
-import com.google.gwt.dev.jjs.ast.JInterfaceType;
 import com.google.gwt.dev.jjs.ast.JMethod;
 import com.google.gwt.dev.jjs.ast.JMethodCall;
 import com.google.gwt.dev.jjs.ast.JModVisitor;
@@ -263,7 +263,7 @@
 
      assert targetTypeCategory == TypeCategory.TYPE_JS_PROTOTYPE;
      call.addArg(program.getStringLiteral(sourceInfo,
-         ((JInterfaceType) targetType).getJsPrototype()));
+         ((JDeclaredType) targetType).getJsPrototype()));
     }
     return call;
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
index 9e6c555..1f07892 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
@@ -22,7 +22,6 @@
 import com.google.gwt.dev.jjs.ast.JClassLiteral;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
-import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JEnumType;
 import com.google.gwt.dev.jjs.ast.JExpression;
 import com.google.gwt.dev.jjs.ast.JField;
@@ -350,18 +349,7 @@
     if (!(type instanceof JClassType) ||  ((JClassType) type).getSuperClass() == null) {
       return JNullLiteral.INSTANCE;
     }
-    JClassType classType = (JClassType) type;
-    if (program.isJsTypePrototype(classType)) {
-        /*
-         * When a Java type extends a JS prototype stub, we make the superclass literal
-         * equal to the Js interface.
-         */
-      JDeclaredType jsInterface = program.typeOracle.getNearestJsType(type, true);
-      assert jsInterface != null;
-      return createDependentClassLiteral(info, jsInterface);
-    }
-
-    return createDependentClassLiteral(info, classType.getSuperClass());
+    return createDependentClassLiteral(info, ((JClassType) type).getSuperClass());
   }
 
   private JClassLiteral createDependentClassLiteral(SourceInfo info, JType type) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
index 3c018ee..5806da0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
@@ -151,7 +151,7 @@
     @Override
     public boolean visit(JMethod x, Context ctx) {
       // Let's do it!
-      JDeclaredType enclosingType = (JDeclaredType) x.getEnclosingType();
+      JDeclaredType enclosingType = x.getEnclosingType();
       JType returnType = x.getType();
       SourceInfo sourceInfo = x.getSourceInfo().makeChild();
       int myIndexInClass = enclosingType.getMethods().indexOf(x);
@@ -299,6 +299,9 @@
       if (method.isAbstract()) {
         return false;
       }
+      if (method.isJsNative()) {
+        return false;
+      }
       if (method == program.getNullMethod()) {
         // Special case: we don't make calls to this method static.
         return false;
@@ -309,10 +312,6 @@
         return false;
       }
 
-      if (program.isJsTypePrototype(method.getEnclosingType())) {
-        return false;
-      }
-
       return true;
     }
   }
@@ -378,11 +377,9 @@
    * Optionally adds a null check on the former "this" parameter.
    */
   static class StaticCallConverter {
-    private final JProgram program;
     private final JMethod checkNotNull;
 
     StaticCallConverter(JProgram program, boolean addNullChecksForThis) {
-      this.program = program;
       if (addNullChecksForThis) {
         checkNotNull = program.getIndexedMethod("Exceptions.checkNotNull");
       } else {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
index a688750..b232bb6 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
@@ -123,15 +123,8 @@
 
     private InlineResult tryInlineMethodCall(JMethodCall x, Context ctx) {
       JMethod method = x.getTarget();
-      if (program.isJsTypePrototype(method.getEnclosingType())) {
-         /*
-          * Don't inline calls to JsType Prototype methods, since these are merely stubs to
-          * preserve super calls to JS prototype methods.
-          */
-        return InlineResult.BLACKLIST;
-      }
 
-      if (!method.isStatic() || method.isNative()) {
+      if (!method.isStatic() || method.isNative() || method.canBeImplementedExternally()) {
         // Only inline static methods that are not native.
         return InlineResult.BLACKLIST;
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/RemoveEmptySuperCalls.java b/dev/core/src/com/google/gwt/dev/jjs/impl/RemoveEmptySuperCalls.java
index eac0a0b..35cced8 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/RemoveEmptySuperCalls.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/RemoveEmptySuperCalls.java
@@ -33,23 +33,13 @@
    * Removes calls to no-op super constructors.
    */
   public static class EmptySuperCallVisitor extends JModVisitor {
-    private JProgram program;
-
-    public EmptySuperCallVisitor(JProgram program) {
-      this.program = program;
-    }
-
     @Override
     public void endVisit(JExpressionStatement x, Context ctx) {
       if (x.getExpr() instanceof JMethodCall && !(x.getExpr() instanceof JNewInstance)) {
         JMethodCall call = (JMethodCall) x.getExpr();
         if (call.getTarget() instanceof JConstructor) {
           JConstructor ctor = (JConstructor) call.getTarget();
-          if (program.isJsTypePrototype(ctor.getEnclosingType())) {
-            // don't remove calls to JsType super-constructors;
-            return;
-          }
-          if (ctor.isEmpty()) {
+          if (ctor.isEmpty() && !ctor.isJsNative()) {
             // TODO: move this 3-way into Simplifier.
             if (call.getArgs().isEmpty()) {
               ctx.removeMe();
@@ -67,7 +57,7 @@
   }
 
   public static boolean exec(JProgram program) {
-    EmptySuperCallVisitor v = new EmptySuperCallVisitor(program);
+    EmptySuperCallVisitor v = new EmptySuperCallVisitor();
     v.accept(program);
     return v.didChange();
   }
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 b7f73f0..e81da83 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
@@ -67,7 +67,7 @@
     } else if (program.typeOracle.isDualJsoInterface(type)
         || program.typeOracle.isJsTypeInterfaceWithoutPrototype(type)) {
       return TypeCategory.TYPE_JAVA_OBJECT_OR_JSO;
-    } else if (program.typeOracle.isJsTypeInterfaceWithPrototype(type)) {
+    } else if (type.isJsNative()) {
       return TypeCategory.TYPE_JS_PROTOTYPE;
     } else if (type.isJsFunction()) {
       return TypeCategory.TYPE_JS_FUNCTION;
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java
index ce2ac4b..b7b2000 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java
@@ -97,6 +97,15 @@
     return @JavaClassHierarchySetupUtil::portableObjCreate(*)(superPrototype);
   }-*/;
 
+  public static native void copyObjectMethods(JavaScriptObject objectPrototypeId) /*-{
+    var prototype = @JavaClassHierarchySetupUtil::prototypesByTypeId[objectPrototypeId];
+    for (var property in prototype) {
+      if (_[property] === undefined) {
+        _[property] = prototype[property];
+      }
+    }
+  }-*/;
+
   /**
    * Retrieves the class literal if stored in a place holder, {@code null} otherwise.
    */
diff --git a/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
index d3575f2..d452ba9 100644
--- a/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
@@ -562,98 +562,6 @@
         + JSORestrictionsChecker.ERR_EITHER_JSEXPORT_JSNOEXPORT);
   }
 
-  public void testJsPrototypeNotOnClass() {
-    StringBuilder buggyCode = new StringBuilder();
-    buggyCode.append("import com.google.gwt.core.client.js.JsType;\n");
-    buggyCode.append("@JsType(prototype = \"foo\")\n");
-    buggyCode.append("public class Buggy {\n");
-    buggyCode.append("void foo() {}\n");
-    buggyCode.append("}\n");
-
-    shouldGenerateError(buggyCode, "Line 3: "
-      + JSORestrictionsChecker.ERR_JS_TYPE_WITH_PROTOTYPE_SET_NOT_ALLOWED_ON_CLASS_TYPES);
-  }
-
-  public void testJsTypePrototypeExtensionNotAllowed() {
-    StringBuilder buggyCode = new StringBuilder();
-    buggyCode.append("import com.google.gwt.core.client.js.JsType;\n");
-    buggyCode.append("import com.google.gwt.core.client.js.impl.PrototypeOfJsType;\n");
-    buggyCode.append("public class Buggy {\n");
-    buggyCode.append("@JsType interface Foo { " +
-        "@PrototypeOfJsType static class Foo_Prototype implements Foo {} }\n");
-    buggyCode.append("static class BuggyFoo extends Foo.Foo_Prototype {\n");
-    buggyCode.append("}\n");
-    buggyCode.append("}\n");
-
-    shouldGenerateError(buggyCode, "Line 5: "
-        + JSORestrictionsChecker.ERR_CLASS_EXTENDS_MAGIC_PROTOTYPE_BUT_NO_PROTOTYPE_ATTRIBUTE);
-  }
-
-  public void testJsTypePrototypeExtensionNoError() {
-    StringBuilder buggyCode = new StringBuilder();
-    buggyCode.append("import com.google.gwt.core.client.js.JsType;\n");
-    buggyCode.append("import com.google.gwt.core.client.js.impl.PrototypeOfJsType;\n");
-    buggyCode.append("public class Buggy {\n");
-    buggyCode.append("@JsType (prototype =\"foo\") interface Foo { " +
-        "@PrototypeOfJsType static class Foo_Prototype implements Foo {} }\n");
-    buggyCode.append("static class BuggyFoo extends Foo.Foo_Prototype {\n");
-    buggyCode.append("}\n");
-    buggyCode.append("}\n");
-
-    shouldGenerateNoError(buggyCode);
-  }
-
-  public void testJsTypePrototypeExtensionNoError2() {
-    StringBuilder buggyCode = new StringBuilder();
-    buggyCode.append("import com.google.gwt.core.client.js.JsType;\n");
-    buggyCode.append("import com.google.gwt.core.client.js.impl.PrototypeOfJsType;\n");
-    buggyCode.append("public class Buggy {\n");
-    buggyCode.append("@JsType (prototype =\"foo\") interface Foo { }\n ");
-    buggyCode.append("@PrototypeOfJsType static class Foo_Prototype implements Foo {}\n");
-    buggyCode.append("static class BuggyFoo extends Foo_Prototype {\n");
-    buggyCode.append("}\n");
-    buggyCode.append("}\n");
-
-    shouldGenerateNoError(buggyCode);
-  }
-
-  public void testJsTypePrototypeExtensionNotAllowed2() {
-    // TODO (cromwellian): add a command-line flag for this later
-    JSORestrictionsChecker.LINT_MODE = true;
-    StringBuilder buggyCode = new StringBuilder();
-    buggyCode.append("import com.google.gwt.core.client.js.JsType;\n");
-    buggyCode.append("public class Buggy {\n");
-    buggyCode.append("@JsType (prototype =\"foo\") interface Foo { }\n");
-    buggyCode.append("static class BuggyBar {}\n");
-    buggyCode.append("static class BuggyFoo extends BuggyBar implements Foo {\n");
-    buggyCode.append("}\n");
-    buggyCode.append("}\n");
-
-    shouldGenerateError(buggyCode, "Line 5: "
-        + JSORestrictionsChecker.ERR_MUST_EXTEND_MAGIC_PROTOTYPE_CLASS);
-  }
-
-  public void testJsPropertyNoErrors() {
-    StringBuilder buggyCode = new StringBuilder();
-    buggyCode.append("import com.google.gwt.core.client.js.JsType;\n");
-    buggyCode.append("import com.google.gwt.core.client.js.JsProperty;\n");
-    buggyCode.append("@JsType public interface Buggy {\n");
-
-    buggyCode.append("@JsProperty int foo();\n");
-    buggyCode.append("@JsProperty void foo(int x);\n");
-
-    buggyCode.append("@JsProperty int getFoo();\n");
-    buggyCode.append("@JsProperty void setFoo(int x);\n");
-
-    buggyCode.append("@JsProperty boolean hasFoo();\n");
-    buggyCode.append("@JsProperty boolean isFoo();\n");
-    buggyCode.append("@JsProperty Buggy setFoo(String x);\n");
-
-    buggyCode.append("}\n");
-
-    shouldGenerateNoError(buggyCode);
-  }
-
   public void testJsFunctionOnFunctionalInterface() {
     StringBuilder goodCode = new StringBuilder();
     goodCode.append("import com.google.gwt.core.client.js.JsFunction;\n");
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/PrunerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/PrunerTest.java
index 42a43dc..babeca0 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/PrunerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/PrunerTest.java
@@ -76,29 +76,24 @@
     addSnippetClassDecl("interface UnusedInterface { void foo(); }");
     addSnippetImport("com.google.gwt.core.client.js.JsType");
     addSnippetImport("com.google.gwt.core.client.js.JsExport");
-    addSnippetImport("com.google.gwt.core.client.js.impl"
-        + ".PrototypeOfJsType");
     addSnippetClassDecl("interface Callback { void go(); }");
     addSnippetImport("com.google.gwt.core.client.js.JsType");
     addSnippetImport("com.google.gwt.core.client.js.JsExport");
 
     addSnippetClassDecl("@JsType interface Js { void doIt(Callback cb); }");
-    addSnippetClassDecl("@JsType(prototype=\"Foo\") interface JsProto { " +
-        "@PrototypeOfJsType static class Prototype implements JsProto {" +
-        "public Prototype(int arg) {}" +
-        "}" +
+    addSnippetClassDecl("@JsType(prototype=\"Foo\") static class JsProto { ",
+        "public JsProto(int arg) {}",
         "}");
-    addSnippetClassDecl("static class JsProtoImpl "
-        + "extends JsProto.Prototype {" +
-        "public JsProtoImpl() { super(10); }" +
+    addSnippetClassDecl("static class JsProtoImpl extends JsProto {",
+        "public JsProtoImpl() { super(10); }",
         "}");
 
-    addSnippetClassDecl("static class JsProtoImpl2 extends JsProto.Prototype {" +
-        "@JsExport(\"foo\") public JsProtoImpl2() { super(10); }" +
+    addSnippetClassDecl("static class JsProtoImpl2 extends JsProto {",
+        "@JsExport(\"foo\") public JsProtoImpl2() { super(10); }",
         "}");
 
-    addSnippetClassDecl("static class JsProtoImpl3 extends JsProto.Prototype {" +
-        "public JsProtoImpl3() { super(10); }" +
+    addSnippetClassDecl("static class JsProtoImpl3 extends JsProto {",
+        "public JsProtoImpl3() { super(10); }",
         "}");
 
     Result result;
diff --git a/tools/api-checker/config/gwt27_28userApi.conf b/tools/api-checker/config/gwt27_28userApi.conf
index bdf843e..1f1704b 100644
--- a/tools/api-checker/config/gwt27_28userApi.conf
+++ b/tools/api-checker/config/gwt27_28userApi.conf
@@ -131,6 +131,7 @@
 #excluded packages colon separated list
 excludedPackages com.google.gwt.core.client.impl\
 :com.google.gwt.core.shared.impl\
+:com.google.gwt.core.client.js.impl\
 :com.google.gwt.editor.client.impl\
 :com.google.gwt.i18n.client.impl\
 :com.google.gwt.junit.client.impl\
diff --git a/user/src/com/google/gwt/core/client/js/impl/PrototypeOfJsType.java b/user/src/com/google/gwt/core/client/js/impl/PrototypeOfJsType.java
deleted file mode 100644
index 9cf795f..0000000
--- a/user/src/com/google/gwt/core/client/js/impl/PrototypeOfJsType.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2013 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.core.client.js.impl;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Marker annotation used to indicate which JsType stub classes trigger prototype overriding
- * behavior in subtypes. This class is meant to be used by implementers of annotation processors.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-@Documented
-public @interface PrototypeOfJsType {
-}
diff --git a/user/test/com/google/gwt/core/client/interop/HTMLAnotherElement.java b/user/test/com/google/gwt/core/client/interop/HTMLAnotherElement.java
index e7d4925..2c2ca7e 100644
--- a/user/test/com/google/gwt/core/client/interop/HTMLAnotherElement.java
+++ b/user/test/com/google/gwt/core/client/interop/HTMLAnotherElement.java
@@ -16,11 +16,7 @@
 package com.google.gwt.core.client.interop;
 
 import com.google.gwt.core.client.js.JsType;
-import com.google.gwt.core.client.js.impl.PrototypeOfJsType;
 
 @JsType(prototype = "HTMLElement")
-interface HTMLAnotherElement {
-  @PrototypeOfJsType
-  static class Prototype implements HTMLAnotherElement {
-  }
+class HTMLAnotherElement {
 }
diff --git a/user/test/com/google/gwt/core/client/interop/HTMLButtonElement.java b/user/test/com/google/gwt/core/client/interop/HTMLButtonElement.java
index 6e2242d..7c1c532 100644
--- a/user/test/com/google/gwt/core/client/interop/HTMLButtonElement.java
+++ b/user/test/com/google/gwt/core/client/interop/HTMLButtonElement.java
@@ -16,11 +16,7 @@
 package com.google.gwt.core.client.interop;
 
 import com.google.gwt.core.client.js.JsType;
-import com.google.gwt.core.client.js.impl.PrototypeOfJsType;
 
 @JsType(prototype = "HTMLButtonElement")
-interface HTMLButtonElement extends HTMLElement {
-  @PrototypeOfJsType
-  static class Prototype implements HTMLButtonElement {
-  }
+class HTMLButtonElement extends HTMLElement {
 }
diff --git a/user/test/com/google/gwt/core/client/interop/HTMLElement.java b/user/test/com/google/gwt/core/client/interop/HTMLElement.java
index 385954e..41e9c3a 100644
--- a/user/test/com/google/gwt/core/client/interop/HTMLElement.java
+++ b/user/test/com/google/gwt/core/client/interop/HTMLElement.java
@@ -16,11 +16,7 @@
 package com.google.gwt.core.client.interop;
 
 import com.google.gwt.core.client.js.JsType;
-import com.google.gwt.core.client.js.impl.PrototypeOfJsType;
 
 @JsType(prototype = "HTMLElement")
-interface HTMLElement {
-  @PrototypeOfJsType
-  static class Prototype implements HTMLElement {
-  }
+class HTMLElement {
 }
diff --git a/user/test/com/google/gwt/core/client/interop/JsFunctionTest.java b/user/test/com/google/gwt/core/client/interop/JsFunctionTest.java
index 659f584..8bb7025 100644
--- a/user/test/com/google/gwt/core/client/interop/JsFunctionTest.java
+++ b/user/test/com/google/gwt/core/client/interop/JsFunctionTest.java
@@ -185,8 +185,13 @@
     assertNotNull(c3);
     MyJsFunctionIdentityInterface c4 = (MyJsFunctionIdentityInterface) object;
     assertNotNull(c4);
-    ElementLikeJsInterface c5 = (ElementLikeJsInterface) object;
-    assertNotNull(c5);
+    try {
+      ElementLikeJsInterface c5 = (ElementLikeJsInterface) object;
+      assertNotNull(c5);
+      fail("ClassCastException should be caught.");
+    } catch (ClassCastException cce) {
+      // Expected.
+    }
   }
 
   public void testCast_crossCastJavaInstance() {
@@ -219,7 +224,7 @@
     assertTrue(object instanceof MyJsFunctionInterfaceImpl);
     assertTrue(object instanceof MyJsFunctionIdentityInterface);
     assertTrue(object instanceof MyJsFunctionWithOnlyInstanceofReference);
-    assertTrue(object instanceof ElementLikeJsInterface);
+    assertFalse(object instanceof ElementLikeJsInterface);
   }
 
   // uncomment when Java8 is supported.
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 4914698..836c428 100644
--- a/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
+++ b/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
@@ -137,7 +137,15 @@
     assertTrue(hasField(revealedOverrideSubType, "run"));
   }
 
-  public void testSubClassWithSuperCalls() {
+  public void testConcreteNativeType() {
+    MyJsClassWithPrototype obj = new MyJsClassWithPrototype();
+    assertTrue(isUndefined(obj.getX()));
+    obj.setX(72);
+    assertEquals(72, obj.getX());
+    assertEquals(74, obj.sum(2));
+  }
+
+  public void testConcreteNativeType_sublasss() {
     MyClassExtendsJsPrototype mc = new MyClassExtendsJsPrototype();
     assertEquals(143, mc.sum(1));
 
@@ -219,7 +227,8 @@
     assertTrue(object instanceof ElementLikeJsInterface);
     assertFalse(object instanceof ElementLikeJsInterfaceImpl);
     assertTrue(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
-    assertFalse(object instanceof MyJsPrototypeWithOnlyInstanceofReference);
+    assertFalse(object instanceof MyJsInterfaceWithPrototypeAndOnlyInstanceofReference);
+    assertFalse(object instanceof MyJsClassWithPrototypeAndOnlyInstanceofReference);
     assertFalse(object instanceof ConcreteJsType);
   }
 
@@ -236,7 +245,8 @@
     assertTrue(object instanceof ElementLikeJsInterface);
     assertFalse(object instanceof ElementLikeJsInterfaceImpl);
     assertTrue(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
-    assertFalse(object instanceof MyJsPrototypeWithOnlyInstanceofReference);
+    assertFalse(object instanceof MyJsInterfaceWithPrototypeAndOnlyInstanceofReference);
+    assertFalse(object instanceof MyJsClassWithPrototypeAndOnlyInstanceofReference);
     assertFalse(object instanceof ConcreteJsType);
   }
 
@@ -253,7 +263,8 @@
     assertTrue(object instanceof ElementLikeJsInterface);
     assertFalse(object instanceof ElementLikeJsInterfaceImpl);
     assertTrue(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
-    assertTrue(object instanceof MyJsPrototypeWithOnlyInstanceofReference);
+    assertTrue(object instanceof MyJsInterfaceWithPrototypeAndOnlyInstanceofReference);
+    assertTrue(object instanceof MyJsClassWithPrototypeAndOnlyInstanceofReference);
     assertFalse(object instanceof ConcreteJsType);
   }
 
@@ -271,7 +282,8 @@
     assertTrue(object instanceof ElementLikeJsInterface);
     assertTrue(object instanceof ElementLikeJsInterfaceImpl);
     assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
-    assertFalse(object instanceof MyJsPrototypeWithOnlyInstanceofReference);
+    assertFalse(object instanceof MyJsInterfaceWithPrototypeAndOnlyInstanceofReference);
+    assertFalse(object instanceof MyJsClassWithPrototypeAndOnlyInstanceofReference);
     assertFalse(object instanceof ConcreteJsType);
   }
 
@@ -289,7 +301,8 @@
     assertFalse(object instanceof ElementLikeJsInterface);
     assertFalse(object instanceof ElementLikeJsInterfaceImpl);
     assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
-    assertFalse(object instanceof MyJsPrototypeWithOnlyInstanceofReference);
+    assertFalse(object instanceof MyJsInterfaceWithPrototypeAndOnlyInstanceofReference);
+    assertFalse(object instanceof MyJsClassWithPrototypeAndOnlyInstanceofReference);
     assertFalse(object instanceof ConcreteJsType);
   }
 
@@ -307,7 +320,8 @@
     assertFalse(object instanceof ElementLikeJsInterface);
     assertFalse(object instanceof ElementLikeJsInterfaceImpl);
     assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
-    assertFalse(object instanceof MyJsPrototypeWithOnlyInstanceofReference);
+    assertFalse(object instanceof MyJsInterfaceWithPrototypeAndOnlyInstanceofReference);
+    assertFalse(object instanceof MyJsClassWithPrototypeAndOnlyInstanceofReference);
     assertTrue(object instanceof ConcreteJsType);
   }
 
@@ -320,16 +334,14 @@
     assertTrue(object instanceof HTMLButtonElement);
     assertTrue(object instanceof HTMLElement);
     assertTrue(object instanceof Iterable);
-    /*
-     * TODO: this works, but only because Object can't be type-tightened to HTMLElement. But it will
-     * evaluate statically to false for HTMLElement instanceof HTMLAnotherElement. Depending on what
-     * the spec decides, fix JTypeOracle so that canTheoreticallyCast returns the appropriate
-     * result, as well as add a test here that can be type-tightened.
-     */
     assertFalse(object instanceof MyJsInterfaceWithPrototype);
-    assertTrue(object instanceof ElementLikeJsInterface);
-    assertTrue(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
-    assertTrue(object instanceof MyJsPrototypeWithOnlyInstanceofReference);
+    assertFalse(object instanceof MyJsInterfaceWithPrototypeImpl);
+    assertFalse(object instanceof ElementLikeJsInterface);
+    assertFalse(object instanceof ElementLikeJsInterfaceImpl);
+    assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference);
+    assertTrue(object instanceof MyJsInterfaceWithPrototypeAndOnlyInstanceofReference);
+    assertTrue(object instanceof MyJsClassWithPrototypeAndOnlyInstanceofReference);
+    assertFalse(object instanceof ConcreteJsType);
   }
 
   public void testInstanceOfWithNameSpace() {
diff --git a/user/test/com/google/gwt/core/client/interop/MyClassExtendsJsPrototype.java b/user/test/com/google/gwt/core/client/interop/MyClassExtendsJsPrototype.java
index 22c6543..faf7049 100644
--- a/user/test/com/google/gwt/core/client/interop/MyClassExtendsJsPrototype.java
+++ b/user/test/com/google/gwt/core/client/interop/MyClassExtendsJsPrototype.java
@@ -15,7 +15,7 @@
  */
 package com.google.gwt.core.client.interop;
 
-class MyClassExtendsJsPrototype extends MyJsInterfaceWithPrototype.Prototype {
+class MyClassExtendsJsPrototype extends MyJsClassWithPrototype {
 
   MyClassExtendsJsPrototype() {
     setX(42);
diff --git a/user/test/com/google/gwt/core/client/interop/MyCustomHtmlButtonWithIterator.java b/user/test/com/google/gwt/core/client/interop/MyCustomHtmlButtonWithIterator.java
index d04ede1..89e2ed4 100644
--- a/user/test/com/google/gwt/core/client/interop/MyCustomHtmlButtonWithIterator.java
+++ b/user/test/com/google/gwt/core/client/interop/MyCustomHtmlButtonWithIterator.java
@@ -17,7 +17,7 @@
 
 import java.util.Iterator;
 
-class MyCustomHtmlButtonWithIterator extends HTMLButtonElement.Prototype implements Iterable {
+class MyCustomHtmlButtonWithIterator extends HTMLButtonElement implements Iterable {
   @Override
   public Iterator iterator() {
     return null;
diff --git a/user/test/com/google/gwt/core/client/interop/MyJsPrototypeWithOnlyInstanceofReference.java b/user/test/com/google/gwt/core/client/interop/MyJsClassWithPrototype.java
similarity index 69%
copy from user/test/com/google/gwt/core/client/interop/MyJsPrototypeWithOnlyInstanceofReference.java
copy to user/test/com/google/gwt/core/client/interop/MyJsClassWithPrototype.java
index bf195de..03e6e80 100644
--- a/user/test/com/google/gwt/core/client/interop/MyJsPrototypeWithOnlyInstanceofReference.java
+++ b/user/test/com/google/gwt/core/client/interop/MyJsClassWithPrototype.java
@@ -15,11 +15,19 @@
  */
 package com.google.gwt.core.client.interop;
 
+import com.google.gwt.core.client.js.JsProperty;
 import com.google.gwt.core.client.js.JsType;
 
 /**
- * A test class marked with JsType but isn't referenced from any Java code except instanceof.
+ * A class that represents an existing native type.
  */
-@JsType(prototype = "HTMLButtonElement")
-public interface MyJsPrototypeWithOnlyInstanceofReference {
-}
\ No newline at end of file
+@JsType(prototype = "MyJsInterface")
+public class MyJsClassWithPrototype {
+  @JsProperty
+  public native int getX();
+
+  @JsProperty
+  public native void setX(int x);
+
+  public native int sum(int bias);
+}
diff --git a/user/test/com/google/gwt/core/client/interop/MyJsPrototypeWithOnlyInstanceofReference.java b/user/test/com/google/gwt/core/client/interop/MyJsClassWithPrototypeAndOnlyInstanceofReference.java
similarity index 92%
rename from user/test/com/google/gwt/core/client/interop/MyJsPrototypeWithOnlyInstanceofReference.java
rename to user/test/com/google/gwt/core/client/interop/MyJsClassWithPrototypeAndOnlyInstanceofReference.java
index bf195de..d4a013d 100644
--- a/user/test/com/google/gwt/core/client/interop/MyJsPrototypeWithOnlyInstanceofReference.java
+++ b/user/test/com/google/gwt/core/client/interop/MyJsClassWithPrototypeAndOnlyInstanceofReference.java
@@ -21,5 +21,5 @@
  * A test class marked with JsType but isn't referenced from any Java code except instanceof.
  */
 @JsType(prototype = "HTMLButtonElement")
-public interface MyJsPrototypeWithOnlyInstanceofReference {
-}
\ No newline at end of file
+public class MyJsClassWithPrototypeAndOnlyInstanceofReference {
+}
diff --git a/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototype.java b/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototype.java
index e710eea..a80f7d1 100644
--- a/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototype.java
+++ b/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototype.java
@@ -17,7 +17,6 @@
 
 import com.google.gwt.core.client.js.JsProperty;
 import com.google.gwt.core.client.js.JsType;
-import com.google.gwt.core.client.js.impl.PrototypeOfJsType;
 
 @JsType(prototype = "MyJsInterface")
 interface MyJsInterfaceWithPrototype {
@@ -29,22 +28,4 @@
   void setX(int a);
 
   int sum(int bias);
-
-  @PrototypeOfJsType
-  static class Prototype implements MyJsInterfaceWithPrototype {
-
-    @Override
-    public int getX() {
-      return 0;
-    }
-
-    @Override
-    public void setX(int a) {
-    }
-
-    @Override
-    public int sum(int bias) {
-      return 0;
-    }
-  }
 }
diff --git a/user/test/com/google/gwt/core/client/interop/MyJsPrototypeWithOnlyInstanceofReference.java b/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototypeAndOnlyInstanceofReference.java
similarity index 91%
copy from user/test/com/google/gwt/core/client/interop/MyJsPrototypeWithOnlyInstanceofReference.java
copy to user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototypeAndOnlyInstanceofReference.java
index bf195de..d8e7b69 100644
--- a/user/test/com/google/gwt/core/client/interop/MyJsPrototypeWithOnlyInstanceofReference.java
+++ b/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototypeAndOnlyInstanceofReference.java
@@ -21,5 +21,5 @@
  * A test class marked with JsType but isn't referenced from any Java code except instanceof.
  */
 @JsType(prototype = "HTMLButtonElement")
-public interface MyJsPrototypeWithOnlyInstanceofReference {
-}
\ No newline at end of file
+public interface MyJsInterfaceWithPrototypeAndOnlyInstanceofReference {
+}