Provide API to access JsConstructor from Class

This is an undocumented API and might change in any
GWT version. jsinterop.base will provide a supported
utility to access JsConstructor from Class instance.

Change-Id: Ib8bbb6bf7754bc59fa91f7d025d91721f2dfab40
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Runtime.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Runtime.java
index c7c7606..5118b40 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Runtime.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Runtime.java
@@ -61,7 +61,6 @@
     } else {
       _ = @Runtime::createSubclassPrototype(*)(superTypeIdOrPrototype);
       _.@Object::castableTypeMap = castableTypeMap;
-      _.constructor = _;
       if (!superTypeIdOrPrototype) {
         // Set the typeMarker on java.lang.Object's prototype, implicitly setting it for all
         // Java subclasses (String and Arrays have special handling in Cast and Array respectively).
@@ -138,6 +137,11 @@
         cur.execScript('var ' + parts[0]);
     }
 
+    if(optCtor) {
+      var clazz = optCtor.prototype.@Object::___clazz;
+      clazz.@Class::jsConstructor = optCtor;
+    }
+
     // Certain browsers cannot parse code in the form for((a in b); c;);
     // This pattern is produced by the JSCompiler when it collapses the
     // statement above into the conditional loop below. To prevent this from
diff --git a/user/super/com/google/gwt/emul/java/lang/Class.java b/user/super/com/google/gwt/emul/java/lang/Class.java
index fca599a..fbca4e7 100644
--- a/user/super/com/google/gwt/emul/java/lang/Class.java
+++ b/user/super/com/google/gwt/emul/java/lang/Class.java
@@ -124,15 +124,14 @@
   /**
     * Used by {@link WebModePayloadSink} to create uninitialized instances.
     */
-   @DoNotInline
-   static native JavaScriptObject getPrototypeForClass(Class<?> clazz) /*-{
-     if (clazz.@Class::isPrimitive()()) {
-       return null;
-     }
-     var typeId = clazz.@Class::typeId;
-     var prototype = @com.google.gwt.lang.Runtime::prototypesByTypeId[typeId];
-     return prototype;
-   }-*/;
+  @DoNotInline
+  static native JavaScriptObject getPrototypeForClass(Class<?> clazz) /*-{
+    if (clazz.@Class::isPrimitive()()) {
+      return null;
+    }
+    var typeId = clazz.@Class::typeId;
+    return @com.google.gwt.lang.Runtime::prototypesByTypeId[typeId];
+  }-*/;
 
   public static boolean isClassMetadataEnabled() {
     // This body may be replaced by the compiler
@@ -302,6 +301,8 @@
 
   private JavaScriptObject arrayLiterals;
 
+  private JavaScriptObject jsConstructor;
+
   // Assign a sequential id to each class literal to avoid calling hashCode which bring Impl as
   // a dependency.
   private int sequentialId = nextSequentialId++;
diff --git a/user/test/com/google/gwt/core/interop/JsExportTest.java b/user/test/com/google/gwt/core/interop/JsExportTest.java
index df58627..3c3c2b3 100644
--- a/user/test/com/google/gwt/core/interop/JsExportTest.java
+++ b/user/test/com/google/gwt/core/interop/JsExportTest.java
@@ -45,6 +45,10 @@
     $wnd.$global = $global;
   }-*/;
 
+  private native boolean isClosureFormattedOutputEnabled() /*-{
+    return !!(window.goog && window.goog.global);
+  }-*/;
+
   public void testMethodExport() {
     myClassExportsMethodCallMe1();
     assertTrue(MyClassExportsMethod.calledFromCallMe1);
@@ -207,6 +211,29 @@
     public NativeMyClassExportsConstructor(@SuppressWarnings("unused") int a) { }
   }
 
+  public void testGetJsConstructor() {
+    if (isClosureFormattedOutputEnabled()) {
+      return; // Closure formatted output doesn't support jsConstructor.
+    }
+    Object constructorFn = getJsConstructor(MyClassExportsConstructor.class);
+    assertSame(getMyClassExportsConstructor(), constructorFn);
+    assertSame(MyClassExportsConstructor.class, getClass(constructorFn));
+
+    assertNull(getJsConstructor(Object.class));
+    assertNull(getJsConstructor(String.class));
+  }
+
+  @JsProperty(namespace = "$global.woo", name = "MyClassExportsConstructor")
+  private static native Object getMyClassExportsConstructor();
+
+  private static native Object getJsConstructor(Class<?> clazz) /*-{
+    return clazz.@Class::jsConstructor;
+  }-*/;
+
+  private static native Class<?> getClass(Object ctor) /*-{
+    return ctor.prototype.@Object::___clazz;
+  }-*/;
+
   public void testExportedField() {
     assertEquals(100, MyExportedClass.EXPORTED_1);
     assertEquals(100, getExportedField());