Setup classes using closure idioms

Eliminate defineClass() and inline it's function

Before:
function Stub(){}
defineClass(typeId, superTypeId, cTM, Stub);
Stub.prototype._.method = blah
ctor1.prototype = ctor2.prototype = Stub.prototype;
// class literal patched in later via lookup

After:
function Stub() {}
Stub.prototype.method = blah
Stub.prototype.castableTypeMap = {...}
Stub.prototype.___clazz = classLiteral;

goog.inherits(ctor1, Stub);
goog.inherits(ctor2, Stub);

Why do this?

1) defineClass() holds global reference to class proto
via global table, making it hard to prune unused protos

2) defineClass() hides how the ctors are chained and what
happens to Stub. Closure compiler does not like to see
ctor1.prototype = ctor2.prototype = Stub.prototype. It
does not know how to model this.

3) Closure has specific knowledge that goog.inherits()
sets up a subtyping relationship.

4) Adds goog.abstractMethod declarations to JInterfaceType
output (previously only an empty function literal was supplied)
to aid a later CL that references these with @implements JsDoc.

3% code size reduction on some apps. When JsDoc annotations
are added, this rises to 16% on Inbox. Without this CL, but
with the JsDoc annotations, there is not much gain at all.

5) Class literals are now all setup directly during
vtable initialization for regular GWT mode too,
regular than being deferred by a placeholder and
setup in defineClass(). This will lead to a slight
code size increase when not post-compiled by Closure,
but a subsequent Js pass can recover most of the regression.

Change-Id: I8560fe08601487fbe8ab80d1555e01fc0f1c308f
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ClosureJsInteropExportsGenerator.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ClosureJsInteropExportsGenerator.java
index a88df95..d55f67e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ClosureJsInteropExportsGenerator.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ClosureJsInteropExportsGenerator.java
@@ -68,9 +68,11 @@
    */
   @Override
   public void exportType(JDeclaredType x) {
-    // Note that synthesized constructors use the name of the declared types.
-    generateExport(x.getQualifiedJsName(), x.getQualifiedJsName(),
-        names.get(x).makeRef(x.getSourceInfo()), x.getSourceInfo());
+    if (!x.isJsNative() && !x.isJsFunction()) {
+      // Note that synthesized constructors use the name of the declared types.
+      generateExport(x.getQualifiedJsName(), x.getQualifiedJsName(),
+          names.get(x).makeRef(x.getSourceInfo()), x.getSourceInfo());
+    }
   }
 
   /*
@@ -100,7 +102,7 @@
       return;
     }
 
-    JsNameRef provideFuncRef = JsUtils.createQualifier("goog.provide", info);
+    JsNameRef provideFuncRef = JsUtils.createQualifiedNameRef("goog.provide", info);
     JsInvocation provideCall = new JsInvocation(info);
     provideCall.setQualifier(provideFuncRef);
     provideCall.getArguments().add(new JsStringLiteral(info, namespace));
@@ -113,6 +115,6 @@
   }
 
   private static JsExpression createExportQualifier(String namespace, SourceInfo sourceInfo) {
-    return JsUtils.createQualifier(namespace.isEmpty() ? "window" : namespace, sourceInfo);
+    return JsUtils.createQualifiedNameRef(namespace.isEmpty() ? "window" : namespace, sourceInfo);
   }
 }
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 f5b640a..5401a4d 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
@@ -82,7 +82,6 @@
 import com.google.gwt.dev.jjs.ast.JPrefixOperation;
 import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
-import com.google.gwt.dev.jjs.ast.JProgram.DispatchType;
 import com.google.gwt.dev.jjs.ast.JReferenceType;
 import com.google.gwt.dev.jjs.ast.JReturnStatement;
 import com.google.gwt.dev.jjs.ast.JStatement;
@@ -713,6 +712,8 @@
 
   private class GenerateJavaScriptVisitor extends JVisitor {
 
+    public static final String GOOG_INHERITS = "goog.inherits";
+    public static final String GOOG_ABSTRACT_METHOD = "goog.abstractMethod";
     private final Set<JDeclaredType> alreadyRan = Sets.newLinkedHashSet();
 
     private final Map<String, Object> exportedMembersByExportName = new TreeMap<String, Object>();
@@ -886,10 +887,7 @@
         }
       }
 
-      if (typeOracle.isInstantiatedType(x) && !x.isJsoType() &&
-          x !=  program.getTypeJavaLangString()) {
-        generateClassSetup(x, globalStmts);
-      }
+      generateClassSetup(x, globalStmts);
 
       // setup fields
       JsVars vars = new JsVars(x.getSourceInfo());
@@ -1151,19 +1149,48 @@
         globalStmts.add(vars);
       }
 
-      /*
-       * If a @JsType is exported, but no constructors are, @JsDoc type declarations added by the
-       * linker will fail in uncompiled mode, as they will try to access the 'Foo.prototype' which
-       * is undefined even though the goog.provide('Foo') statement exists. Here we synthesize a
-       * simple constructor to aid the linker.
-       */
-      if (closureCompilerFormatEnabled && x.isJsType()) {
-        declareSynthesizedClosureConstructor(x, globalStmts);
+      if (closureCompilerFormatEnabled && !x.isJsNative()) {
+        declareClosureInterface(x, globalStmts);
       }
 
       collectExports(x);
     }
 
+    /*
+     * Declare an interface that is referenced by an @implements clause in JsDoc
+     * generation. This is only done for interfaces that are not defined externally
+     * (native types) in external JS libraries or externs.
+     *
+     * This appears to be needed when two disjoint GWT concrete types related only by an
+     * interface (e.g. Runnable), are accessed via an exported Runnable method (run()).
+     * The disambiguate properties pass in Closure does not know how to map which run()
+     * methods could possibly be invoked (there could be classes that don't implement Runnable
+     * but which have a method called 'run'). This generated interface will be referenced
+     * in @param/@return statements and @implements clauses added by later passes or linkers.
+     *
+     * Closure compiler dead-strips it.
+     */
+    private void declareClosureInterface(JInterfaceType x, List<JsStatement> globalStmts) {
+      declareSynthesizedClosureConstructor(x, globalStmts);
+      SourceInfo sourceInfo = x.getSourceInfo();
+      // TODO(cromwellian): in a later cl, generate goog.mixin() for interface type inheritance
+      for (JMethod method : x.getMethods()) {
+        if (method.isAbstract()) {
+          JsName polyName = polymorphicNames.get(method);
+          generateVTableAssignment(globalStmts, method, polyName,
+            JsUtils.createQualifiedNameRef(GOOG_ABSTRACT_METHOD, sourceInfo));
+
+          // aliased methods are part of the interface too since they can be called
+          // from JS into the impl.
+          if (method.isOrOverridesJsMethod()) {
+            String jsName = method.getJsName();
+            JsName exportedName = polyName.getEnclosing().declareUnobfuscatableName(jsName);
+            generateVTableAlias(globalStmts, method, exportedName);
+          }
+        }
+      }
+    }
+
     @Override
     public void endVisit(JLabel x, Context ctx) {
       push(new JsLabel(x.getSourceInfo(), names.get(x)));
@@ -1354,14 +1381,7 @@
           // Construct jsPrototype.prototype.jsname
           methodNameRef = createJsQualifier(method.getQualifiedJsName(), sourceInfo);
         } else {
-          // Construct JCHSU.getPrototypeFor(type).polyname
-
-          // TODO(rluble): Ideally we would want to construct the inheritance chain the JS way and
-          // then we could do Type.prototype.polyname.call(this, ...). Currently prototypes do not
-          // have global names instead they are stuck into the prototypesByTypeId array.
-          JsInvocation protoRef =
-              constructInvocation(sourceInfo, "JavaClassHierarchySetupUtil.getClassPrototype",
-                  convertJavaLiteral(typeMapper.get(superClass)));
+          JsExpression protoRef = getPrototypeQualifierViaLookup(superClass, sourceInfo);
           methodNameRef = polymorphicNames.get(method).makeRef(sourceInfo);
           methodNameRef.setQualifier(protoRef);
         }
@@ -1376,6 +1396,19 @@
       return jsInvocation;
     }
 
+    private JsExpression getPrototypeQualifierViaLookup(JDeclaredType type, SourceInfo sourceInfo) {
+      if (closureCompilerFormatEnabled) {
+        return getPrototypeQualifierOf(type, type.getSourceInfo());
+      } else {
+        // Construct JCHSU.getPrototypeFor(type).polyname
+        // TODO(rluble): Ideally we would want to construct the inheritance chain the JS way and
+        // then we could do Type.prototype.polyname.call(this, ...). Currently prototypes do not
+        // have global names instead they are stuck into the prototypesByTypeId array.
+        return constructInvocation(sourceInfo, "JavaClassHierarchySetupUtil.getClassPrototype",
+            convertJavaLiteral(typeMapper.get(type)));
+      }
+    }
+
     private JsExpression dispatchToJsFunction(
         JsExpression instance, List<JsExpression> args, SourceInfo sourceInfo) {
       return new JsInvocation(sourceInfo, instance, args);
@@ -1689,11 +1722,8 @@
       for (JDeclaredType type : topologicallySortedBodyTypes) {
         markPosition(globalStmts, type.getName(), Type.CLASS_START);
         accept(type);
-        JsVars classLiteralVars = new JsVars(jsProgram.getSourceInfo());
-        maybeGenerateClassLiteral(type, classLiteralVars);
-        if (!classLiteralVars.isEmpty()) {
-          globalStmts.add(classLiteralVars);
-        }
+        maybeGenerateClassLiteral(type, globalStmts);
+        installClassLiterals(globalStmts, Arrays.asList(type));
         markPosition(globalStmts, type.getName(), Type.CLASS_END);
       }
       markPosition(globalStmts, "Program", Type.PROGRAM_END);
@@ -1727,12 +1757,48 @@
         accept(type);
       }
       generateClassLiterals(globalStmts, classLiteralSupportClasses);
+      installClassLiterals(globalStmts, classLiteralSupportClasses);
 
       Set<JDeclaredType> preambleTypes = Sets.newLinkedHashSet(alreadyProcessed);
       preambleTypes.addAll(classLiteralSupportClasses);
       return preambleTypes;
     }
 
+    private void installClassLiterals(List<JsStatement> globalStmts,
+        List<JDeclaredType> classLiteralTypesToInstall) {
+      if (!closureCompilerFormatEnabled) {
+        // let createForClass() install them until a follow on CL
+        // TODO(cromwellian) remove after approval from rluble in follow up CL
+        return;
+      }
+
+      for (JDeclaredType type : classLiteralTypesToInstall) {
+        if (hasNoVTable(type)) {
+          continue;
+        }
+
+        JsNameRef classLiteralRef = createClassLiteralReference(type);
+        if (classLiteralRef == null) {
+          continue;
+        }
+
+        JsExpression protoRef = getPrototypeQualifierOf(type, type.getSourceInfo());
+        JsNameRef clazzField = indexedFields.get("Object.___clazz").makeRef(type.getSourceInfo());
+        clazzField.setQualifier(protoRef);
+        JsExprStmt stmt = createAssignment(clazzField, classLiteralRef).makeStmt();
+        globalStmts.add(stmt);
+        typeForStatMap.put(stmt, (JClassType) type);
+      }
+    }
+
+    private boolean hasNoVTable(JDeclaredType type) {
+      // Interfaces, Unboxed Types, JSOs, Native Types, JsFunction, and uninstantiated types
+      // Do not have vtables/prototype setup
+      return type instanceof JInterfaceType || program.isRepresentedAsNativeJsPrimitive(type) ||
+          type.isJsoType() || !program.typeOracle.isInstantiatedType(type) || type.isJsNative()
+          || type.isJsFunction();
+    }
+
     private List<JDeclaredType> computeClassLiteralsSupportClasses(JProgram program,
         Set<JDeclaredType> alreadyProcessedTypes) {
       if (program.isReferenceOnly(program.getIndexedType("Class"))) {
@@ -1873,12 +1939,8 @@
 
     private void generateClassLiterals(List<JsStatement> globalStmts,
         Iterable<? extends JType> orderedTypes) {
-      JsVars vars = new JsVars(jsProgram.getSourceInfo());
       for (JType type : orderedTypes) {
-        maybeGenerateClassLiteral(type, vars);
-      }
-      if (!vars.isEmpty()) {
-        globalStmts.add(vars);
+        maybeGenerateClassLiteral(type, globalStmts);
       }
     }
 
@@ -2126,12 +2188,7 @@
        * goog.object.createSet('foo', 'bar', 'baz') is optimized by closure compiler into
        * {'foo': !0, 'bar': !0, baz: !0}
        */
-      JsNameRef createSet = new JsNameRef(sourceInfo, "createSet");
-      JsNameRef googObject = new JsNameRef(sourceInfo, "object");
-      JsNameRef goog = new JsNameRef(sourceInfo, "goog");
-      createSet.setQualifier(googObject);
-      googObject.setQualifier(goog);
-
+      JsNameRef createSet = new JsNameRef(sourceInfo, "goog.object.createSet");
       JsInvocation jsInvocation = new JsInvocation(sourceInfo, createSet);
 
       for (JsExpression expr : runtimeTypeIdLiterals) {
@@ -2187,13 +2244,21 @@
       return new JsObjectLiteral(SourceOrigin.UNKNOWN);
     }
 
-    private void maybeGenerateClassLiteral(JType type, JsVars vars) {
+    private JField getClassLiteralField(JType type) {
       JDeclarationStatement decl = classLiteralDeclarationsByType.get(type);
       if (decl == null) {
-        return;
+        return null;
       }
 
-      JField field = (JField) decl.getVariableRef().getTarget();
+      return (JField) decl.getVariableRef().getTarget();
+    }
+
+    private void maybeGenerateClassLiteral(JType type, List<JsStatement> globalStmts) {
+
+      JField field = getClassLiteralField(type);
+      if (field == null) {
+        return;
+      }
 
       // TODO(rluble): refactor so that all output related to a class is decided together.
       if (type != null && type instanceof JDeclaredType
@@ -2206,15 +2271,37 @@
         return;
       }
 
+      JsVars vars = new JsVars(jsProgram.getSourceInfo());
       JsName jsName = names.get(field);
-      this.accept(decl.getInitializer());
+      this.accept(field.getInitializer());
       JsExpression classObjectAlloc = pop();
-      JsVar var = new JsVar(decl.getSourceInfo(), jsName);
+      SourceInfo info = field.getSourceInfo();
+      JsVar var = new JsVar(info, jsName);
       var.setInitExpr(classObjectAlloc);
       vars.add(var);
+      globalStmts.add(vars);
+    }
+
+    private JsNameRef createClassLiteralReference(JType type) {
+      JField field = getClassLiteralField(type);
+      if (field == null) {
+        return null;
+      }
+      JsName jsName = names.get(field);
+      return jsName.makeRef(type.getSourceInfo());
     }
 
     private void generateClassSetup(JClassType x, List<JsStatement> globalStmts) {
+      if (program.isRepresentedAsNativeJsPrimitive(x) && program.typeOracle.isInstantiatedType(x)) {
+        setupCastMapForUnboxedType(x, globalStmts,
+            program.getRepresentedAsNativeTypesDispatchMap().get(x).getCastMapField());
+        return;
+      }
+
+      if (hasNoVTable(x)) {
+        return;
+      }
+
       generateClassDefinition(x, globalStmts);
       generateVTables(x, globalStmts);
 
@@ -2222,14 +2309,7 @@
         // special: setup a "toString" alias for java.lang.Object.toString()
         generateToStringAlias(x, globalStmts);
 
-        // Set up the artificial castmap for string, double, and boolean
-        for (Map.Entry<JClassType, DispatchType> nativeRepresentedType :
-            program.getRepresentedAsNativeTypesDispatchMap().entrySet()) {
-          setupCastMapForUnboxedType(nativeRepresentedType.getKey(), globalStmts,
-              nativeRepresentedType.getValue().getCastMapField());
-        }
-
-        //  Perform necessary polyfills.
+        // Perform necessary polyfills.
         globalStmts.add(constructInvocation(x.getSourceInfo(),
             "JavaClassHierarchySetupUtil.modernizeBrowser").makeStmt());
       }
@@ -2437,10 +2517,12 @@
       typeForStatMap.put(defineClassStatement, x);
 
       if (jsPrototype != null) {
-        JExpression objectTypeId = getRuntimeTypeReference(program.getTypeJavaLangObject());
         JsStatement statement =
-            constructInvocation(x.getSourceInfo(), "JavaClassHierarchySetupUtil.copyObjectMethods",
-                convertJavaLiteral(objectTypeId)).makeStmt();
+            constructInvocation(x.getSourceInfo(),
+                "JavaClassHierarchySetupUtil.copyObjectProperties",
+                getPrototypeQualifierViaLookup(program.getTypeJavaLangObject(), x.getSourceInfo()),
+                globalTemp.makeRef(x.getSourceInfo()))
+                .makeStmt();
         globalStmts.add(statement);
         typeForStatMap.put(statement, x);
       }
@@ -2458,7 +2540,7 @@
     }
 
     private void generateClassDefinition(JClassType x, List<JsStatement> globalStmts) {
-      assert x != program.getTypeJavaLangString();
+      assert !program.isRepresentedAsNativeJsPrimitive(x);
 
       if (closureCompilerFormatEnabled) {
         generateClosureClassDefinition(x, globalStmts);
@@ -2488,38 +2570,118 @@
     /*
      * Class definition for closure output looks like:
      *
-     * defineClass(jsinterop.getUniqueId('FQTypeName'),
-     *     jsinterop.getUniqueId('FQSuperTypeName'), ctm);
-     * var ClassName = defineHiddenClosureConstructor();
+     * function ClassName() {}
      * ClassName.prototype.method1 = function() { ... };
      * ClassName.prototype.method2 = function() { ... };
-     * ctor1.prototype = ClassName.prototype;
-     * ctor2.prototype = ClassName.prototype;
-     * ctor3.prototype = ClassName.prototype;
+     * ClassName.prototype.castableTypeMap = {...}
+     * ClassName.prototype.___clazz = classLit;
+     * function Ctor1() {}
+     * function Ctor2() {}
+     *
+     * goog$inherits(Ctor1, ClassName);
+     * goog$inherits(Ctor2, ClassName);
      *
      * The primary change is to make the prototype assignment look like regular closure code to help
-     * the compiler disambiguate which methods belong to which type.
+     * the compiler disambiguate which methods belong to which type. Elimination of defineClass()
+     * makes the setup more transparent and eliminates a global table holding a reference to
+     * every prototype.
      */
     private void generateClosureClassDefinition(JClassType x, List<JsStatement> globalStmts) {
       // function ClassName(){}
       JsName classVar = declareSynthesizedClosureConstructor(x, globalStmts);
+      generateInlinedDefineClass(x, globalStmts, classVar);
 
-      // defineClass(..., ClassName)
-      generateCallToDefineClass(x, globalStmts, Arrays.asList(classVar.makeRef(x.getSourceInfo())));
-
-      // Ctor1.prototype = ClassName.prototype
-      // Ctor2.prototype = ClassName.prototype
-      // etc.
+       /*
+       * Closure style prefers 1 single ctor per type. To model this without radical changes,
+       * we simply model each concrete ctor as a subtype. This works because GWT doesn't use the
+       * native instanceof operator. So for example, class A() { A(int x){}, A(String s){} }
+       * becomes (pseudo code):
+       *
+       * function A() {}
+       * A.prototype.method = ...
+       *
+       * function A_int(x) {}
+       * function A_String(s) {}
+       * goog$inherits(A_int, A);
+       * goog$inherits(A_string, A);
+       *
+       */
       for (JMethod method : getPotentiallyAliveConstructors(x)) {
-        JsNameRef lhs = prototype.makeRef(method.getSourceInfo());
-        lhs.setQualifier(names.get(method).makeRef(method.getSourceInfo()));
-        JsNameRef rhsProtoRef = getPrototypeQualifierOf(method);
-        JsExprStmt stmt = createAssignment(lhs, rhsProtoRef).makeStmt();
-        globalStmts.add(stmt);
-        vtableInitForMethodMap.put(stmt, method);
+        JsNameRef googInherits = JsUtils.createQualifiedNameRef(GOOG_INHERITS, x.getSourceInfo());
+
+        JsExprStmt callGoogInherits = new JsInvocation(x.getSourceInfo(), googInherits,
+            names.get(method).makeRef(method.getSourceInfo()),
+            names.get(method.getEnclosingType()).makeRef(method.getSourceInfo())).makeStmt();
+        globalStmts.add(callGoogInherits);
+        vtableInitForMethodMap.put(callGoogInherits, method);
       }
     }
 
+    /**
+     * Does everything JCHSU.defineClass does, but inlined into global statements. Roughly
+     * parallels argument order of generateCallToDefineClass.
+     */
+    private void generateInlinedDefineClass(JClassType x, List<JsStatement> globalStmts,
+        JsName classVar) {
+      JClassType superClass = x.getSuperClass();
+      // check if there's an overriding prototype
+      String jsPrototype = getSuperPrototype(x);
+      JsNameRef parentCtor = jsPrototype != null ?
+          createJsQualifier(jsPrototype, x.getSourceInfo()) :
+            superClass != null ?
+              names.get(superClass).makeRef(x.getSourceInfo()) :
+              null;
+
+      if (parentCtor != null) {
+        JsNameRef googInherits = JsUtils.createQualifiedNameRef(GOOG_INHERITS, x.getSourceInfo());
+        // Use goog$inherits(ChildCtor, ParentCtor) to setup inheritance
+        JsExprStmt callGoogInherits = new JsInvocation(x.getSourceInfo(), googInherits,
+            classVar.makeRef(x.getSourceInfo()), parentCtor).makeStmt();
+        globalStmts.add(callGoogInherits);
+        typeForStatMap.put(callGoogInherits, x);
+      }
+
+      if (x == program.getTypeJavaLangObject()) {
+        setupTypeMarkerOnJavaLangObjectPrototype(x, globalStmts);
+      }
+
+      // inline assignment of castableTypeMap field instead of using defineClass()
+      setupCastMapOnPrototype(x, globalStmts);
+      if (jsPrototype != null) {
+        JsStatement statement =
+            constructInvocation(x.getSourceInfo(),
+                "JavaClassHierarchySetupUtil.copyObjectProperties",
+                getPrototypeQualifierOf(program.getTypeJavaLangObject(), x.getSourceInfo()),
+                getPrototypeQualifierOf(x, x.getSourceInfo()))
+                .makeStmt();
+        globalStmts.add(statement);
+        typeForStatMap.put(statement, x);
+      }
+    }
+
+    private void setupCastMapOnPrototype(JClassType x, List<JsStatement> globalStmts) {
+      JsExpression castMap = generateCastableTypeMap(x);
+      generateVTableAssignmentToJavaField(globalStmts, x, "Object.castableTypeMap", castMap);
+    }
+
+    private void setupTypeMarkerOnJavaLangObjectPrototype(JClassType x,
+        List<JsStatement> globalStmts) {
+      JsFunction typeMarkerMethod = indexedFunctions.get(
+          "JavaClassHierarchySetupUtil.typeMarkerFn");
+      generateVTableAssignmentToJavaField(globalStmts, x, "Object.typeMarker",
+          typeMarkerMethod.getName().makeRef(x.getSourceInfo()));
+    }
+
+    private void generateVTableAssignmentToJavaField(List<JsStatement> globalStmts,
+        JClassType x, String javaField, JsExpression rhs) {
+      JsNameRef protoRef = getPrototypeQualifierOf(x, x.getSourceInfo());
+      JsNameRef jsFieldRef = indexedFields.get(javaField).makeRef(x.getSourceInfo());
+      jsFieldRef.setQualifier(protoRef);
+      JsStatement stmt = createAssignment(jsFieldRef, rhs).makeStmt();
+      globalStmts.add(stmt);
+      typeForStatMap.put(stmt, x);
+    }
+
     /*
      * Declare an empty synthesized constructor that looks like:
      * function ClassName(){}
@@ -2626,7 +2788,8 @@
      * variable _ points the JavaScript prototype for {@code x}.
      */
     private void generateVTables(JClassType x, List<JsStatement> globalStmts) {
-      assert x != program.getTypeJavaLangString();
+      assert !program.isRepresentedAsNativeJsPrimitive(x);
+
       for (JMethod method : x.getMethods()) {
         if (!method.needsVtable()) {
           continue;
@@ -2635,6 +2798,10 @@
         if (!method.isAbstract()) {
           JsExpression rhs = getJsFunctionFor(method);
           generateVTableAssignment(globalStmts, method, polymorphicNames.get(method), rhs);
+        } else if (closureCompilerFormatEnabled) {
+          // in closure mode, we add add a goog.abstractMethod for subtypes to @override
+          generateVTableAssignment(globalStmts, method, polymorphicNames.get(method),
+              JsUtils.createQualifiedNameRef(GOOG_ABSTRACT_METHOD, x.getSourceInfo()));
         }
 
         if (method.exposesNonJsMethod()) {
@@ -2669,7 +2836,7 @@
 
     public JsNameRef createJsQualifier(String qualifier, SourceInfo sourceInfo) {
       assert !qualifier.isEmpty();
-      return JsUtils.createQualifier("$wnd." + qualifier, sourceInfo);
+      return JsUtils.createQualifiedNameRef("$wnd." + qualifier, sourceInfo);
     }
 
     /**
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractor.java
index ff2108f..b9ba2c9 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/codesplitter/FragmentExtractor.java
@@ -257,8 +257,11 @@
         }
         JClassType vtableType = vtableTypeNeeded(statement);
         if (vtableType != null && vtableType != currentVtableType) {
-          assert pendingVtableType == vtableType;
-          extractedStats.add(pendingDefineClass);
+          // there is no defineClass() call in -XclosureFormattedOutput
+          assert pendingVtableType == vtableType || pendingDefineClass == null;
+          if (pendingDefineClass != null) {
+            extractedStats.add(pendingDefineClass);
+          }
           currentVtableType = pendingVtableType;
           pendingDefineClass = null;
           pendingVtableType = null;
@@ -486,7 +489,7 @@
   private JClassType vtableTypeNeeded(JsStatement stat) {
     JMethod meth = map.vtableInitToMethod(stat);
     if (meth != null) {
-      if (meth.needsVtable()) {
+      if (meth.needsVtable() && !meth.isAbstract()) {
         return (JClassType) meth.getEnclosingType();
       }
     }
diff --git a/dev/core/src/com/google/gwt/dev/js/JsUtils.java b/dev/core/src/com/google/gwt/dev/js/JsUtils.java
index 73e9873..fbc8e75 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsUtils.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsUtils.java
@@ -128,7 +128,7 @@
    * Given a string qualifier such as 'foo.bar.Baz', returns a chain of JsNameRef's representing
    * this qualifier.
    */
-  public static JsNameRef createQualifier(String namespace, SourceInfo sourceInfo) {
+  public static JsNameRef createQualifiedNameRef(String namespace, SourceInfo sourceInfo) {
     assert !namespace.isEmpty();
     JsNameRef ref = null;
     for (String part : namespace.split("\\.")) {
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 b7b2000..185ac08 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,11 +97,11 @@
     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];
+  public static native void copyObjectProperties(JavaScriptObject from,
+      JavaScriptObject to) /*-{
+    for (var property in from) {
+      if (to[property] === undefined) {
+        to[property] = from[property];
       }
     }
   }-*/;
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 9e5713a..465d2d9 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -271,6 +271,7 @@
               "  public static void modernizeBrowser() {}",
               "  public static void emptyMethod() {}",
               "  public static void getClassPrototype() {}",
+              "  static native void typeMarkerFn() /*-{}-*/;",
               "}"
           );
         }
diff --git a/user/src/com/google/gwt/junit/linker/closurehelpers.js b/user/src/com/google/gwt/junit/linker/closurehelpers.js
index af1d220..8dbf977 100644
--- a/user/src/com/google/gwt/junit/linker/closurehelpers.js
+++ b/user/src/com/google/gwt/junit/linker/closurehelpers.js
@@ -6,8 +6,7 @@
 goog.global = this;
 goog.implicitNamespaces_ = {};
 
-goog.object = {};
-goog.object.createSet = function () {
+goog.object.createSet = function goog$object$createSet() {
   var result = {};
   for (var i = 0; i < arguments.length; i++) {
     result[arguments[i]] = true;
@@ -36,6 +35,9 @@
 goog.require = function () {
 };
 
+goog.abstractMethod = function() {
+}
+
 goog.provide = function (name) {
   // Ensure that the same namespace isn't provided twice. This is intended
   // to teach new developers that 'goog.provide' is effectively a variable
@@ -87,6 +89,68 @@
   }
 };
 
+/**
+ * Inherit the prototype methods from one constructor into another.
+ *
+ * Usage:
+ * <pre>
+ * function ParentClass(a, b) { }
+ * ParentClass.prototype.foo = function(a) { };
+ *
+ * function ChildClass(a, b, c) {
+ *   ChildClass.base(this, 'constructor', a, b);
+ * }
+ * goog.inherits(ChildClass, ParentClass);
+ *
+ * var child = new ChildClass('a', 'b', 'see');
+ * child.foo(); // This works.
+ * </pre>
+ *
+ * @param {Function} childCtor Child class.
+ * @param {Function} parentCtor Parent class.
+ */
+goog.inherits = function(childCtor, parentCtor) {
+  // Workaround MyJsInterfaceWithPrototype test since the parentCtor doesn't exist
+  // until after ScriptInjector, but this test back-patches the ctor
+  if (!parentCtor) {
+    return;
+  }
+  /** @constructor */
+  function tempCtor() {};
+  tempCtor.prototype = parentCtor.prototype;
+  childCtor.superClass_ = parentCtor.prototype;
+  childCtor.prototype = new tempCtor();
+  /** @override */
+  childCtor.prototype.constructor = childCtor;
+
+  /**
+   * Calls superclass constructor/method.
+   *
+   * This function is only available if you use goog.inherits to
+   * express inheritance relationships between classes.
+   *
+   * NOTE: This is a replacement for goog.base and for superClass_
+   * property defined in childCtor.
+   *
+   * @param {!Object} me Should always be "this".
+   * @param {string} methodName The method name to call. Calling
+   *     superclass constructor can be done with the special string
+   *     'constructor'.
+   * @param {...*} var_args The arguments to pass to superclass
+   *     method/constructor.
+   * @return {*} The return value of the superclass method/constructor.
+   */
+  childCtor.base = function(me, methodName, var_args) {
+    // Copying using loop to avoid deop due to passing arguments object to
+    // function. This is faster in many JS engines as of late 2014.
+    var args = new Array(arguments.length - 2);
+    for (var i = 2; i < arguments.length; i++) {
+      args[i - 2] = arguments[i];
+    }
+    return parentCtor.prototype[methodName].apply(me, args);
+  };
+};
+
 jsinterop.closure = {};
 jsinterop.closure.uniqueIds_ = {};
 jsinterop.closure.uniqueIdCounter_ = 0;
@@ -98,3 +162,8 @@
   }
   return jsinterop.closure.uniqueIds_[identifier];
 };
+
+$wnd.MyJsInterface = function() {};
+$wnd.MyJsInterface.staticX = 33;
+$wnd.MyJsInterface.answerToLife = function() { return 42;};
+$wnd.MyJsInterface.prototype.sum = function sum(bias) { return this.x + bias; };