Consider native fields that are only written to live.
Change-Id: I31b90f5d562867e40bfdc53439f7e3273e7cd543
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 9d9faa4..1c404a3 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
@@ -161,37 +161,37 @@
if ((x.getOp() == JBinaryOperator.CONCAT || x.getOp() == JBinaryOperator.ASG_CONCAT)) {
rescueByConcat(x.getLhs().getType());
rescueByConcat(x.getRhs().getType());
- } else if (x.getOp() == JBinaryOperator.ASG) {
- // Don't rescue variables that are merely assigned to and never read
- boolean doSkip = false;
- JExpression lhs = x.getLhs();
- if (lhs.hasSideEffects() || isVolatileField(lhs)) {
- /*
- * If the lhs has side effects, skipping it would lose the side
- * effect. If the lhs is volatile, also keep it. This behavior
- * provides a useful idiom for test cases to prevent code from being
- * pruned.
- */
- } else if (lhs instanceof JLocalRef) {
- // locals are ok to skip
- doSkip = true;
- } else if (lhs instanceof JParameterRef) {
- // parameters are ok to skip
- doSkip = true;
- } else if (lhs instanceof JFieldRef) {
- // fields must rescue the qualifier
- doSkip = true;
- JFieldRef fieldRef = (JFieldRef) lhs;
- JExpression instance = fieldRef.getInstance();
- if (instance != null) {
- accept(instance);
- }
+ }
+
+ JExpression lhs = x.getLhs();
+ if (x.getOp() != JBinaryOperator.ASG || lhs.hasSideEffects() || isVolatileField(lhs)) {
+ // Continue the normal visitor process for lhs and rhs.
+ return true;
+ }
+
+ // Assignments where the lhs does not have side effects (save for volatile fields) are special
+ // treated here. The idea is to not consider live a field/local/parameter that is only
+ // written to.
+ if (lhs instanceof JLocalRef || lhs instanceof JParameterRef) {
+ // if the lhs is a local or parameter, do not consider it live just because it is being
+ // written to.
+ accept(x.getRhs());
+ return false;
+ } else if (lhs instanceof JFieldRef) {
+ JFieldRef fieldRef = (JFieldRef) lhs;
+ JField field = fieldRef.getField();
+ if (field.canBeImplementedExternally()) {
+ // Proceed normally to consider native fields live even if they are only written to.
+ return true;
}
- if (doSkip) {
- accept(x.getRhs());
- return false;
+ // Fields that are only written to still need to process their qualifier.
+ JExpression instance = fieldRef.getInstance();
+ if (instance != null) {
+ accept(instance);
}
+ accept(x.getRhs());
+ return false;
}
return true;
}
diff --git a/user/test/com/google/gwt/core/interop/JsExportTest.java b/user/test/com/google/gwt/core/interop/JsExportTest.java
index bfdee8a..e250b97 100644
--- a/user/test/com/google/gwt/core/interop/JsExportTest.java
+++ b/user/test/com/google/gwt/core/interop/JsExportTest.java
@@ -496,5 +496,4 @@
assertEquals("L", X.m("L"));
assertEquals("M", callM("M"));
}
-
}
diff --git a/user/test/com/google/gwt/core/interop/JsPropertyTest.java b/user/test/com/google/gwt/core/interop/JsPropertyTest.java
index 95c3432..875c11b 100644
--- a/user/test/com/google/gwt/core/interop/JsPropertyTest.java
+++ b/user/test/com/google/gwt/core/interop/JsPropertyTest.java
@@ -498,4 +498,18 @@
assertFalse("Field '" + field + "' should not be exported", hasField(obj, field));
}
}
+
+ static class B {
+ @JsProperty
+ public String field;
+ }
+ private native String getB(B b)/*-{
+ return b.field;
+ }-*/;
+
+ public void testNotReadExpoprtedFieldNotPruned() {
+ B b = new B();
+ b.field = "secret";
+ assertEquals("secret", getB(b));
+ }
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/BasicJsInteropTest.java b/user/test/com/google/gwt/dev/jjs/test/BasicJsInteropTest.java
index a375bd9..d840cb9 100644
--- a/user/test/com/google/gwt/dev/jjs/test/BasicJsInteropTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/BasicJsInteropTest.java
@@ -19,11 +19,13 @@
import com.google.gwt.junit.Platform;
import com.google.gwt.junit.client.GWTTestCase;
+import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsType;
/**
* Tests for JsInterop that should work with -nogenerateJsInteropExports.
*/
+@DoNotRunWith(Platform.Devel)
public class BasicJsInteropTest extends GWTTestCase {
@Override
@@ -44,9 +46,27 @@
return { field: "AA" };
}-*/;
- @DoNotRunWith(Platform.Devel)
- public void testANotPruned() {
+ public void testNotSetNativeFieldNotNulled() {
A a = createA();
assertEquals("aa", a.field.toLowerCase());
}
+
+ /**
+ * Tests that a native field that is not written to in Java code (but has some initial value in
+ * the native implementation) is not assumed to be null.
+ */
+ @JsType(isNative = true, name = "Object", namespace = JsPackage.GLOBAL)
+ static class B {
+ public String field;
+ }
+
+ private native String getB(B b)/*-{
+ return b.field;
+ }-*/;
+
+ public void testNotAccessedNativeFieldNotPruned() {
+ B b = new B();
+ b.field = "secret";
+ assertEquals("secret", getB(b));
+ }
}