Adds lvalue-tracking to JSNI field refs. This improves error detection (user tries to reassign a method or compile-time constant) as well as optimization ability.
Review by: spoon
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2227 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniFieldRef.java b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniFieldRef.java
index 7245843..c08c139 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniFieldRef.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniFieldRef.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -29,18 +29,24 @@
public class JsniFieldRef extends JFieldRef {
private final String ident;
+ private boolean isLvalue;
public JsniFieldRef(JProgram program, SourceInfo info, String ident,
- JField field, JReferenceType enclosingType) {
+ JField field, JReferenceType enclosingType, boolean isLvalue) {
super(program, info, field.isStatic() ? null : program.getLiteralNull(),
field, enclosingType);
this.ident = ident;
+ this.isLvalue = isLvalue;
}
public String getIdent() {
return ident;
}
+ public boolean isLvalue() {
+ return isLvalue;
+ }
+
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Finalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Finalizer.java
index 322f3b5..a6912bb 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Finalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Finalizer.java
@@ -159,7 +159,9 @@
@Override
public void endVisit(JsniFieldRef x, Context ctx) {
- recordAssignment(x);
+ if (x.isLvalue()) {
+ recordAssignment(x);
+ }
}
private void recordAssignment(JExpression lhs) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index 917a79b..6e1215c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -2589,6 +2589,12 @@
* the field.
*/
if (field.isCompileTimeConstant()) {
+ if (ctx.isLvalue()) {
+ reportJsniError(info, methodDecl,
+ "Cannot change the value of compile-time constant "
+ + field.getName());
+ }
+
JLiteral initializer = field.getConstInitializer();
JType type = initializer.getType();
if (type instanceof JPrimitiveType
@@ -2605,12 +2611,12 @@
// Normal: create a jsniRef.
JsniFieldRef fieldRef = new JsniFieldRef(program, info,
- nameRef.getIdent(), field, currentClass);
+ nameRef.getIdent(), field, currentClass, ctx.isLvalue());
nativeMethodBody.jsniFieldRefs.add(fieldRef);
}
private void processMethod(JsNameRef nameRef, SourceInfo info,
- JMethod method) {
+ JMethod method, JsContext<JsExpression> ctx) {
if (method.getEnclosingType() != null) {
if (method.isStatic() && nameRef.getQualifier() != null) {
reportJsniError(info, methodDecl,
@@ -2622,6 +2628,10 @@
+ method.getName());
}
}
+ if (ctx.isLvalue()) {
+ reportJsniError(info, methodDecl, "Cannot reassign the Java method "
+ + method.getName());
+ }
JsniMethodRef methodRef = new JsniMethodRef(program, info,
nameRef.getIdent(), method);
@@ -2645,7 +2655,7 @@
if (node instanceof JField) {
processField(nameRef, info, (JField) node, ctx);
} else if (node instanceof JMethod) {
- processMethod(nameRef, info, (JMethod) node);
+ processMethod(nameRef, info, (JMethod) node, ctx);
} else {
throw new InternalCompilerException((HasSourceInfo) node,
"JSNI reference to something other than a field or method?", null);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
index 7185243..54be4a0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
@@ -207,7 +207,8 @@
JField nullField = program.getNullField();
program.jsniMap.put(ident, nullField);
JsniFieldRef nullFieldRef = new JsniFieldRef(program,
- x.getSourceInfo(), ident, nullField, x.getEnclosingType());
+ x.getSourceInfo(), ident, nullField, x.getEnclosingType(),
+ x.isLvalue());
ctx.replaceMe(nullFieldRef);
}
}
@@ -703,11 +704,10 @@
/*
* SPECIAL: this could be an assignment that passes a value from
* JavaScript into Java.
- *
- * TODO(later): technically we only need to do this if the field is being
- * assigned to.
*/
- maybeRescueJavaScriptObjectPassingIntoJava(x.getField().getType());
+ if (x.isLvalue()) {
+ maybeRescueJavaScriptObjectPassingIntoJava(x.getField().getType());
+ }
// JsniFieldRef rescues as JFieldRef
return visit((JFieldRef) x, ctx);
}
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 51c7dd6..ef6f251 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
@@ -258,9 +258,11 @@
@Override
public void endVisit(JsniFieldRef x, Context ctx) {
- // If this happens in JSNI, we can't make any type-tightening assumptions
- // Fake an assignment-to-self to prevent tightening
- addAssignment(x.getTarget(), x);
+ if (x.isLvalue()) {
+ // If this happens in JSNI, we can't make any type-tightening
+ // assumptions. Fake an assignment-to-self to prevent tightening.
+ addAssignment(x.getTarget(), x);
+ }
}
@Override