Do not assume that "this" is always non null.
That assumption does not necessarily hold for @JsOverlay methods
not when methods are devirtualized.
Change-Id: I8fe1f6e8f4bc2d330d407faee3327c1e899baeb2
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JThisRef.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JThisRef.java
index da9105f..f182b40 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JThisRef.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JThisRef.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dev.jjs.ast;
+import static com.google.gwt.thirdparty.guava.common.base.Preconditions.checkArgument;
+
import com.google.gwt.dev.jjs.SourceInfo;
/**
@@ -22,20 +24,27 @@
*/
public class JThisRef extends JExpression {
- private final JDeclaredType type;
+ private final JDeclaredType classType;
+ private final JType type;
- public JThisRef(SourceInfo info, JDeclaredType type) {
+ public JThisRef(SourceInfo info, JDeclaredType classType) {
+ this(info, classType, classType);
+ }
+
+ public JThisRef(SourceInfo info, JDeclaredType classType, JType type) {
super(info);
+ this.classType = classType;
this.type = type;
+ checkArgument(type.getUnderlyingType().equals(classType));
}
public JDeclaredType getClassType() {
- return type;
+ return classType;
}
@Override
public JType getType() {
- return type.strengthenToNonNull();
+ return type;
}
@Override
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 90aa0a7..4bfa138 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
@@ -174,7 +174,8 @@
newMethod.setJsOverlay();
}
- JType thisParameterType = enclosingType.strengthenToNonNull();
+ // Do not strengthen to non null since the implicit NPE in instance dispatch is gone.
+ JType thisParameterType = enclosingType;
// Setup parameters; map from the old params to the new params
JParameter thisParam = newMethod.createThisParameter(sourceInfo, thisParameterType);
Map<JParameter, JParameter> varMap = Maps.newIdentityHashMap();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
index 4b2b068..bbb2912 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
@@ -42,6 +42,7 @@
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JReturnStatement;
import com.google.gwt.dev.jjs.ast.JRunAsync;
+import com.google.gwt.dev.jjs.ast.JThisRef;
import com.google.gwt.dev.jjs.ast.JTryStatement;
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.JVariable;
@@ -560,6 +561,17 @@
}
@Override
+ public void endVisit(JThisRef x, Context ctx) {
+ if (getCurrentMethod().isJsOverlay()) {
+ return;
+ }
+ if (x.getType().canBeNull()) {
+ ctx.replaceMe(
+ new JThisRef(x.getSourceInfo(), x.getClassType(), x.getType().strengthenToNonNull()));
+ }
+ }
+
+ @Override
public void endVisit(JParameter x, Context ctx) {
JMethod currentMethod = getCurrentMethod();
if (program.codeGenTypes.contains(currentMethod.getEnclosingType())
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 ca55f21..d6a66d7 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -126,6 +126,7 @@
" public static native boolean isNotNull(Object a) /*-{ }-*/;",
" public static native boolean jsEquals(Object a, Object b) /*-{ }-*/;",
" public static native boolean jsNotEquals(Object a, Object b) /*-{ }-*/;",
+ " public static native Object maskUndefined(Object src) /*-{ }-*/;",
" public static int narrow_int(double x) { return 0; }",
" public static byte narrow_long(double x) { return 0; }",
"}"
diff --git a/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java b/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java
index 7f9d57e..2811bd2 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CompilerMiscRegressionTest.java
@@ -37,6 +37,7 @@
import javaemul.internal.annotations.DoNotInline;
import jsinterop.annotations.JsMethod;
+import jsinterop.annotations.JsOverlay;
import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsProperty;
import jsinterop.annotations.JsType;
@@ -455,4 +456,21 @@
assertTrue(Double.isNaN(getNan()));
assertTrue(isNan(Double.NaN));
}
+
+ @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
+ private static class NativeObjectWithOverlay {
+ public NativeObjectWithOverlay() { }
+ @JsOverlay
+ final NativeObjectWithOverlay getThis() {
+ return this;
+ }
+ }
+
+ public void testOveralyDispatchOnNull() {
+ // Define a variable where the compiler can not statically determine that it is actually null.
+ NativeObjectWithOverlay objectWithOverlay =
+ Math.random() > 1000 ? new NativeObjectWithOverlay() : null;
+
+ assertTrue(objectWithOverlay.getThis() == null);
+ }
}