Fix compiler and hosted-mode crash caused by virtual overrides in SingleJsoImpl types.
Patch by: bobv
Review by: scottb
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6216 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 81f5e9f..1310630 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
@@ -448,7 +448,6 @@
}
}
}
- jsoSubType.clearImplements();
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
index 3535af3..1f683ab 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
@@ -177,13 +177,21 @@
private JMethod findConcreteImplementation(JMethod method,
JClassType concreteType) {
- for (JMethod m : concreteType.getMethods()) {
- if (program.typeOracle.getAllOverrides(m).contains(method)) {
- if (!m.isAbstract()) {
- return m;
+ /*
+ * Search supertypes for virtual overrides via subclass. See the javadoc
+ * on JTypeOracle.getAllVirtualOverrides for an example.
+ */
+ while (concreteType != null) {
+ for (JMethod m : concreteType.getMethods()) {
+ if (program.typeOracle.getAllOverrides(m).contains(method)) {
+ if (!m.isAbstract()) {
+ return m;
+ }
}
}
+ concreteType = concreteType.getSuperClass();
}
+
return null;
}
diff --git a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
index 0815fad..14f1a4c 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -36,9 +36,9 @@
import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter;
import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter.InstanceMethodOracle;
import com.google.gwt.dev.util.JsniRef;
-import com.google.gwt.dev.util.Name.SourceOrBinaryName;
-import com.google.gwt.dev.util.Name.InternalName;
import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.Name.InternalName;
+import com.google.gwt.dev.util.Name.SourceOrBinaryName;
import com.google.gwt.util.tools.Utility;
import org.apache.commons.collections.map.AbstractReferenceMap;
@@ -911,6 +911,21 @@
String mangledName = getBinaryName(type).replace('.', '_') + "_"
+ m.getName();
+ JType[] parameterTypes = new JType[m.getParameters().length];
+ for (int i = 0; i < parameterTypes.length; i++) {
+ parameterTypes[i] = m.getParameters()[i].getType();
+ }
+
+ /*
+ * Handle virtual overrides by finding the method that we would normally
+ * invoke and using its declaring class as the dispatch target.
+ */
+ while (implementingType.findMethod(m.getName(), parameterTypes) == null) {
+ implementingType = implementingType.getSuperclass();
+ }
+ assert implementingType != null : "Unable to find virtual override for "
+ + m.toString();
+
/*
* Cook up the a pseudo-method declaration for the concrete type. This
* should look something like
@@ -921,9 +936,9 @@
*/
String decl = getBinaryOrPrimitiveName(m.getReturnType()) + " "
+ m.getName() + "$ (" + getBinaryOrPrimitiveName(implementingType);
- for (JParameter p : m.getParameters()) {
+ for (JType paramType : parameterTypes) {
decl += ",";
- decl += getBinaryOrPrimitiveName(p.getType());
+ decl += getBinaryOrPrimitiveName(paramType);
}
decl += ")";
diff --git a/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java b/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java
index b954f3e..80966f5 100644
--- a/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java
@@ -24,6 +24,16 @@
public class TypeHierarchyTest extends GWTTestCase {
/**
+ * Used with PlainJso and PlainJsoWithInterface to mix interfaces into
+ * existing base classes.
+ */
+ interface Arrayish {
+ int getLength();
+
+ JavaScriptObject getObject(int i);
+ }
+
+ /**
* The bottom type for a non-trivial diamond-shaped inheritance pattern.
*/
static class DiamondImpl extends JavaScriptObject implements IDiamond2A,
@@ -59,6 +69,35 @@
interface IDiamond2B extends IDiamond1 {
}
+ /**
+ * This is a base class that is used to test adding interfaces to a JSO via a
+ * subclass.
+ */
+ static class PlainJso extends JavaScriptObject {
+ protected PlainJso() {
+ }
+
+ public final native int getLength()/*-{
+ return this.length;
+ }-*/;
+
+ public final native JavaScriptObject getObject(int i) /*-{
+ return this[i];
+ }-*/;
+ }
+
+ /**
+ * We'll mix in an interface into PlainJso.
+ */
+ static class PlainJsoWithInterface extends PlainJso implements Arrayish {
+ public static PlainJsoWithInterface create() {
+ return JavaScriptObject.createArray().cast();
+ }
+
+ protected PlainJsoWithInterface() {
+ }
+ }
+
@Override
public String getModuleName() {
return "com.google.gwt.dev.jjs.CompilerSuite";
@@ -107,4 +146,10 @@
IDiamond2B d2b = DiamondImpl.create();
assertEquals(42, d2b.size());
}
+
+ public void testVirtualOverrides() {
+ Arrayish array = PlainJsoWithInterface.create();
+ assertEquals(0, array.getLength());
+ assertNull(array.getObject(0));
+ }
}