aboutsummaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/javassist/CtField.java13
-rw-r--r--src/main/javassist/compiler/CodeGen.java4
-rw-r--r--src/main/javassist/compiler/MemberCodeGen.java8
-rw-r--r--src/main/javassist/compiler/MemberResolver.java2
-rw-r--r--src/main/javassist/compiler/TypeChecker.java200
-rw-r--r--src/main/javassist/compiler/ast/Expr.java2
-rw-r--r--src/main/javassist/compiler/ast/Member.java10
7 files changed, 208 insertions, 31 deletions
diff --git a/src/main/javassist/CtField.java b/src/main/javassist/CtField.java
index bbf76338..c537ed58 100644
--- a/src/main/javassist/CtField.java
+++ b/src/main/javassist/CtField.java
@@ -251,13 +251,17 @@ public class CtField extends CtMember {
* A constant field is <code>static</code> and <code>final</code>.
*
* @return a <code>Integer</code>, <code>Long</code>, <code>Float</code>,
- * <code>Double</code>, or <code>String</code> object
+ * <code>Double</code>, <code>Boolean</code>,
+ * or <code>String</code> object
* representing the constant value.
* <code>null</code> if it is not a constant field
* or if the field type is not a primitive type
* or <code>String</code>.
*/
public Object getConstantValue() {
+ // When this method is modified,
+ // see also getConstantFieldValue() in TypeChecker.
+
int index = fieldInfo.getConstantValue();
if (index == 0)
return null;
@@ -271,7 +275,12 @@ public class CtField extends CtMember {
case ConstPool.CONST_Double :
return new Double(cp.getDoubleInfo(index));
case ConstPool.CONST_Integer :
- return new Integer(cp.getIntegerInfo(index));
+ int value = cp.getIntegerInfo(index);
+ // "Z" means boolean type.
+ if ("Z".equals(fieldInfo.getDescriptor()))
+ return new Boolean(value != 0);
+ else
+ return new Integer(value);
case ConstPool.CONST_String :
return cp.getStringInfo(index);
default :
diff --git a/src/main/javassist/compiler/CodeGen.java b/src/main/javassist/compiler/CodeGen.java
index 35d06817..bf6c97ef 100644
--- a/src/main/javassist/compiler/CodeGen.java
+++ b/src/main/javassist/compiler/CodeGen.java
@@ -843,7 +843,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
if (p >= 0) {
int op = binOp[index + p + 1];
if (op != NOP) {
- if (p == P_INT)
+ if (p == P_INT && exprType != BOOLEAN)
exprType = INT; // type1 may be BYTE, ...
bytecode.addOpcode(op);
@@ -1281,7 +1281,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
else if (token == MEMBER) { // field read
/* MEMBER ('#') is an extension by Javassist.
* The compiler internally uses # for compiling .class
- * expressions such as "int.class".
+ * expressions such as "int.class".
*/
atFieldRead(expr);
}
diff --git a/src/main/javassist/compiler/MemberCodeGen.java b/src/main/javassist/compiler/MemberCodeGen.java
index a4e69f59..14e14438 100644
--- a/src/main/javassist/compiler/MemberCodeGen.java
+++ b/src/main/javassist/compiler/MemberCodeGen.java
@@ -627,7 +627,13 @@ public class MemberCodeGen extends CodeGen {
{
CtField f = fieldAccess(expr);
boolean is_static = resultStatic;
- atFieldRead(f, is_static);
+ ASTree cexpr = TypeChecker.getConstantFieldValue(f);
+ if (cexpr == null)
+ atFieldRead(f, is_static);
+ else {
+ cexpr.accept(this);
+ setFieldType(f.getFieldInfo2());
+ }
}
/**
diff --git a/src/main/javassist/compiler/MemberResolver.java b/src/main/javassist/compiler/MemberResolver.java
index 3c06f62c..08d9dd37 100644
--- a/src/main/javassist/compiler/MemberResolver.java
+++ b/src/main/javassist/compiler/MemberResolver.java
@@ -228,7 +228,7 @@ public class MemberResolver implements TokenId {
}
/**
- * Only used by fieldAccess() in MemberCodeGen.
+ * Only used by fieldAccess() in MemberCodeGen and TypeChecker.
*
* @param jvmClassName a JVM class name. e.g. java/lang/String
*/
diff --git a/src/main/javassist/compiler/TypeChecker.java b/src/main/javassist/compiler/TypeChecker.java
index 196c7642..9b505afb 100644
--- a/src/main/javassist/compiler/TypeChecker.java
+++ b/src/main/javassist/compiler/TypeChecker.java
@@ -18,6 +18,7 @@ package javassist.compiler;
import javassist.CtClass;
import javassist.CtField;
import javassist.ClassPool;
+import javassist.Modifier;
import javassist.NotFoundException;
import javassist.compiler.ast.*;
import javassist.bytecode.*;
@@ -227,6 +228,12 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
}
}
+ /*
+ * If atBinExpr() substitutes a new expression for the original
+ * binary-operator expression, it changes the operator name to '+'
+ * (if the original is not '+') and sets the new expression to the
+ * left-hand-side expression and null to the right-hand-side expression.
+ */
public void atBinExpr(BinExpr expr) throws CompileError {
int token = expr.getOperator();
int k = CodeGen.lookupBinOp(token);
@@ -241,16 +248,19 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
*/
e = CallExpr.makeCall(Expr.make('.', e,
new Member("toString")), null);
- expr.setLeft(e);
+ expr.setOprand1(e);
expr.setOprand2(null); // <---- look at this!
className = jvmJavaLangString;
}
}
else {
- expr.oprand1().accept(this);
+ ASTree left = expr.oprand1();
+ ASTree right = expr.oprand2();
+ left.accept(this);
int type1 = exprType;
- expr.oprand2().accept(this);
- computeBinExprType(expr, token, type1);
+ right.accept(this);
+ if (!isConstant(expr, token, left, right))
+ computeBinExprType(expr, token, type1);
}
}
else {
@@ -260,18 +270,17 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
}
}
- // expr must be a + expression.
+ /* EXPR must be a + expression.
+ * atPlusExpr() returns non-null if the given expression is string
+ * concatenation. The returned value is "new StringBuffer().append..".
+ */
private Expr atPlusExpr(BinExpr expr) throws CompileError {
ASTree left = expr.oprand1();
ASTree right = expr.oprand2();
if (right == null) {
- /* this expression has been already type-checked since it is
- string concatenation.
- see atBinExpr() above.
- */
- exprType = CLASS;
- arrayDim = 0;
- className = jvmJavaLangString;
+ // this expression has been already type-checked.
+ // see atBinExpr() above.
+ left.accept(this);
return null;
}
@@ -292,6 +301,10 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
int dim1 = arrayDim;
String cname = className;
right.accept(this);
+
+ if (isConstant(expr, '+', left, right))
+ return null;
+
if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname))
|| (exprType == CLASS && arrayDim == 0
&& jvmJavaLangString.equals(className))) {
@@ -309,6 +322,91 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
}
}
+ private boolean isConstant(BinExpr expr, int op, ASTree left,
+ ASTree right) throws CompileError
+ {
+ left = stripPlusExpr(left);
+ right = stripPlusExpr(right);
+ ASTree newExpr = null;
+ if (left instanceof StringL && right instanceof StringL && op == '+')
+ newExpr = new StringL(((StringL)left).get()
+ + ((StringL)right).get());
+ else if (left instanceof IntConst)
+ newExpr = ((IntConst)left).compute(op, right);
+ else if (left instanceof DoubleConst)
+ newExpr = ((DoubleConst)left).compute(op, right);
+
+ if (newExpr == null)
+ return false; // not a constant expression
+ else {
+ expr.setOperator('+');
+ expr.setOprand1(newExpr);
+ expr.setOprand2(null);
+ newExpr.accept(this); // for setting exprType, arrayDim, ...
+ return true;
+ }
+ }
+
+ private static ASTree stripPlusExpr(ASTree expr) {
+ if (expr instanceof BinExpr) {
+ BinExpr e = (BinExpr)expr;
+ if (e.getOperator() == '+' && e.oprand2() == null)
+ return e.getLeft();
+ }
+ else if (expr instanceof Expr) { // note: BinExpr extends Expr.
+ Expr e = (Expr)expr;
+ int op = e.getOperator();
+ if (op == MEMBER) {
+ ASTree cexpr = getConstantFieldValue((Member)e.oprand2());
+ if (cexpr != null)
+ return cexpr;
+ }
+ else if (op == '+' && e.getRight() == null)
+ return e.getLeft();
+ }
+ else if (expr instanceof Member) {
+ ASTree cexpr = getConstantFieldValue((Member)expr);
+ if (cexpr != null)
+ return cexpr;
+ }
+
+ return expr;
+ }
+
+ /**
+ * If MEM is a static final field, this method returns a constant
+ * expression representing the value of that field.
+ */
+ private static ASTree getConstantFieldValue(Member mem) {
+ return getConstantFieldValue(mem.getField());
+ }
+
+ public static ASTree getConstantFieldValue(CtField f) {
+ if (f == null)
+ return null;
+
+ Object value = f.getConstantValue();
+ if (value == null)
+ return null;
+
+ if (value instanceof String)
+ return new StringL((String)value);
+ else if (value instanceof Double || value instanceof Float) {
+ int token = (value instanceof Double)
+ ? DoubleConstant : FloatConstant;
+ return new DoubleConst(((Number)value).doubleValue(), token);
+ }
+ else if (value instanceof Number) {
+ int token = (value instanceof Long) ? LongConstant : IntConstant;
+ return new IntConst(((Number)value).longValue(), token);
+ }
+ else if (value instanceof Boolean)
+ return new Keyword(((Boolean)value).booleanValue()
+ ? TokenId.TRUE : TokenId.FALSE);
+ else
+ return null;
+ }
+
private static boolean isPlusExpr(ASTree expr) {
if (expr instanceof BinExpr) {
BinExpr bexpr = (BinExpr)expr;
@@ -419,13 +517,42 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
else if (token == CALL) // method call
fatal();
else {
- expr.oprand1().accept(this);
- if (token == '-' || token == '~')
- if (CodeGen.isP_INT(exprType))
- exprType = INT; // type may be BYTE, ...
+ oprand.accept(this);
+ if (!isConstant(expr, token, oprand))
+ if (token == '-' || token == '~')
+ if (CodeGen.isP_INT(exprType))
+ exprType = INT; // type may be BYTE, ...
}
}
+ private boolean isConstant(Expr expr, int op, ASTree oprand) {
+ oprand = stripPlusExpr(oprand);
+ if (oprand instanceof IntConst) {
+ IntConst c = (IntConst)oprand;
+ long v = c.get();
+ if (op == '-')
+ v = -v;
+ else if (op == '~')
+ v = ~v;
+ else
+ return false;
+
+ c.set(v);
+ }
+ else if (oprand instanceof DoubleConst) {
+ DoubleConst c = (DoubleConst)oprand;
+ if (op == '-')
+ c.set(-c.get());
+ else
+ return false;
+ }
+ else
+ return false;
+
+ expr.setOperator('+');
+ return true;
+ }
+
public void atCallExpr(CallExpr expr) throws CompileError {
String mname = null;
CtClass targetClass = null;
@@ -464,6 +591,9 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
exprType = CLASS;
arrayDim = 0;
className = nfe.getField(); // JVM-internal
+ e.setOperator(MEMBER);
+ e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(
+ className)));
}
if (arrayDim > 0)
@@ -480,7 +610,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
fatal();
MemberResolver.Method minfo
- = atMethodCallCore(targetClass, mname, args);
+ = atMethodCallCore(targetClass, mname, args);
expr.setMethod(minfo);
}
@@ -591,11 +721,21 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
className = null;
}
+ /* if EXPR is to access a static field, fieldAccess() translates EXPR
+ * into an expression using '#' (MEMBER). For example, it translates
+ * java.lang.Integer.TYPE into java.lang.Integer#TYPE. This translation
+ * speeds up type resolution by MemberCodeGen.
+ */
protected CtField fieldAccess(ASTree expr) throws CompileError {
if (expr instanceof Member) {
- String name = ((Member)expr).get();
+ Member mem = (Member)expr;
+ String name = mem.get();
try {
- return thisClass.getField(name);
+ CtField f = thisClass.getField(name);
+ if (Modifier.isStatic(f.getModifiers()))
+ mem.setField(f);
+
+ return f;
}
catch (NotFoundException e) {
// EXPR might be part of a static member access?
@@ -605,9 +745,13 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
else if (expr instanceof Expr) {
Expr e = (Expr)expr;
int op = e.getOperator();
- if (op == MEMBER)
- return resolver.lookupField(((Symbol)e.oprand1()).get(),
- (Symbol)e.oprand2());
+ if (op == MEMBER) {
+ Member mem = (Member)e.oprand2();
+ CtField f
+ = resolver.lookupField(((Symbol)e.oprand1()).get(), mem);
+ mem.setField(f);
+ return f;
+ }
else if (op == '.')
try {
e.oprand1().accept(this);
@@ -623,9 +767,15 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
* If EXPR might be part of a qualified class name,
* lookupFieldByJvmName2() throws NoFieldException.
*/
- Symbol fname = (Symbol)e.oprand2();
- return resolver.lookupFieldByJvmName2(nfe.getField(),
- fname, expr);
+ Member fname = (Member)e.oprand2();
+ String jvmClassName = nfe.getField();
+ CtField f = resolver.lookupFieldByJvmName2(jvmClassName,
+ fname, expr);
+ e.setOperator(MEMBER);
+ e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(
+ jvmClassName)));
+ fname.setField(f);
+ return f;
}
}
diff --git a/src/main/javassist/compiler/ast/Expr.java b/src/main/javassist/compiler/ast/Expr.java
index aafe8a75..81ae5821 100644
--- a/src/main/javassist/compiler/ast/Expr.java
+++ b/src/main/javassist/compiler/ast/Expr.java
@@ -50,6 +50,8 @@ public class Expr extends ASTList implements TokenId {
public int getOperator() { return operatorId; }
+ public void setOperator(int op) { operatorId = op; }
+
public ASTree oprand1() { return getLeft(); }
public void setOprand1(ASTree expr) {
diff --git a/src/main/javassist/compiler/ast/Member.java b/src/main/javassist/compiler/ast/Member.java
index ee54ecc4..f0303cd3 100644
--- a/src/main/javassist/compiler/ast/Member.java
+++ b/src/main/javassist/compiler/ast/Member.java
@@ -16,14 +16,24 @@
package javassist.compiler.ast;
import javassist.compiler.CompileError;
+import javassist.CtField;
/**
* Member name.
*/
public class Member extends Symbol {
+ // cache maintained by fieldAccess() in TypeChecker.
+ // this is used to obtain the value of a static final field.
+ private CtField field;
+
public Member(String name) {
super(name);
+ field = null;
}
+ public void setField(CtField f) { field = f; }
+
+ public CtField getField() { return field; }
+
public void accept(Visitor v) throws CompileError { v.atMember(this); }
}