From be3a1d153f56e20dde215368b2f7cb5f98ea9370 Mon Sep 17 00:00:00 2001 From: chiba Date: Mon, 30 Aug 2004 17:09:15 +0000 Subject: [PATCH] temporary version. You cannot compile them. I'll discard the changes but want to check in for record. git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@127 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- src/main/javassist/compiler/CodeGen.java | 25 +- src/main/javassist/compiler/TypeChecker.java | 289 +++++++++++++++---- 2 files changed, 252 insertions(+), 62 deletions(-) diff --git a/src/main/javassist/compiler/CodeGen.java b/src/main/javassist/compiler/CodeGen.java index 35d06817..2c186eed 100644 --- a/src/main/javassist/compiler/CodeGen.java +++ b/src/main/javassist/compiler/CodeGen.java @@ -199,20 +199,28 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { } public void compileExpr(ASTree expr) throws CompileError { - doTypeCheck(expr); + expr = doTypeCheck(expr); expr.accept(this); } public boolean compileBooleanExpr(boolean branchIf, ASTree expr) throws CompileError { - doTypeCheck(expr); + expr = doTypeCheck(expr); return booleanExpr(branchIf, expr); } - public void doTypeCheck(ASTree expr) throws CompileError { - if (typeChecker != null) + /* This returns a different expression from the given one + * if the given expression has been modified. + */ + private ASTree doTypeCheck(ASTree expr) throws CompileError { + if (typeChecker != null) { expr.accept(typeChecker); + ASTree expr2 = typeChecker.modifiedExpr; + return expr2 == null ? expr : expr2; + } + else + return expr; } public void atASTList(ASTList n) throws CompileError { fatal(); } @@ -300,7 +308,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { int op = st.getOperator(); if (op == EXPR) { ASTree expr = st.getLeft(); - doTypeCheck(expr); + expr = doTypeCheck(expr); if (expr instanceof AssignExpr) atAssignExpr((AssignExpr)expr, false); else if (isPlusPlusExpr(expr)) { @@ -560,7 +568,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { */ ASTree init = d.getInitializer(); if (init != null) { - doTypeCheck(init); + init = doTypeCheck(init); atVariableAssign(null, '=', null, d, init, false); } } @@ -790,13 +798,10 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { int k = lookupBinOp(token); if (k >= 0) { expr.oprand1().accept(this); - ASTree right = expr.oprand2(); - if (right == null) - return; // see TypeChecker.atBinExpr(). - int type1 = exprType; int dim1 = arrayDim; String cname1 = className; + ASTree right = expr.oprand2(); right.accept(this); if (dim1 != arrayDim) throw new CompileError("incompatible array types"); diff --git a/src/main/javassist/compiler/TypeChecker.java b/src/main/javassist/compiler/TypeChecker.java index 196c7642..d57b95a5 100644 --- a/src/main/javassist/compiler/TypeChecker.java +++ b/src/main/javassist/compiler/TypeChecker.java @@ -17,11 +17,17 @@ package javassist.compiler; import javassist.CtClass; import javassist.CtField; +import javassist.Modifier; import javassist.ClassPool; import javassist.NotFoundException; import javassist.compiler.ast.*; import javassist.bytecode.*; +/** + * This class does type checking and, if needed, transformes the original + * abstract syntax tree. The resulting tree is available from + * this.modifiedExpr. + */ public class TypeChecker extends Visitor implements Opcode, TokenId { static final String javaLangObject = "java.lang.Object"; static final String jvmJavaLangObject = "java/lang/Object"; @@ -34,6 +40,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ... protected int arrayDim; protected String className; // JVM-internal representation + protected ASTree modifiedExpr; // null if the given expr was not changed protected MemberResolver resolver; protected CtClass thisClass; @@ -98,6 +105,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { exprType = CLASS; arrayDim = 0; className = MemberResolver.javaToJvmName(cname); + modifiedExpr = null; } } @@ -109,8 +117,12 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { atMultiNewArray(type, classname, size); else { size.head().accept(this); + if (modifiedExpr != null) + size.setHead(modifiedExpr); + exprType = type; arrayDim = 1; + modifiedExpr = null; if (type == CLASS) className = resolveClassName(classname); else @@ -130,8 +142,11 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { ++count; s.accept(this); + if (modifiedExpr != null) + size.setHead(modifiedExpr); } + modifiedExpr = null; exprType = type; arrayDim = dim; if (type == CLASS) @@ -174,49 +189,80 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { int varArray = d.getArrayDim(); String varClass = d.getClassName(); - if (op != '=') + if (op != '=') { atVariable(var); + if (modifiedExpr != null) + expr.setOprand1(modifiedExpr); + } right.accept(this); + if (modifiedExpr != null) + expr.setOprand2(modifiedExpr); + exprType = varType; arrayDim = varArray; className = varClass; + modifiedExpr = null; } private void atArrayAssign(Expr expr, int op, Expr array, ASTree right) throws CompileError { - atArrayRead(array.oprand1(), array.oprand2()); + atArrayRead(array); + if (modifiedExpr != null) + expr.setOprand1(modifiedExpr); + int aType = exprType; int aDim = arrayDim; String cname = className; right.accept(this); + if (modifiedExpr != null) + expr.setOprand2(modifiedExpr); + exprType = aType; arrayDim = aDim; className = cname; + modifiedExpr = null; } protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right) throws CompileError { - CtField f = fieldAccess(left); - atFieldRead(f); + CtField f = atFieldRead(left); int fType = exprType; int fDim = arrayDim; String cname = className; + if (modifiedExpr != null) + expr.setOprand1(modifiedExpr); + + if (Modifier.isFinal(f.getModifiers())) + throw new CompileError("assignment to a final field"); + right.accept(this); + if (modifiedExpr != null) + expr.setOprand2(modifiedExpr); + exprType = fType; arrayDim = fDim; className = cname; + modifiedExpr = null; } public void atCondExpr(CondExpr expr) throws CompileError { booleanExpr(expr.condExpr()); + if (modifiedExpr != null) + expr.setCond(modifiedExpr); + expr.thenExpr().accept(this); + if (modifiedExpr != null) + expr.setThen(modifiedExpr); + int type1 = exprType; int dim1 = arrayDim; String cname1 = className; expr.elseExpr().accept(this); + if (modifiedExpr != null) + expr.setElse(modifiedExpr); if (dim1 == 0 && dim1 == arrayDim) if (CodeGen.rightIsStrong(type1, exprType)) @@ -225,63 +271,89 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { expr.setElse(new CastExpr(type1, 0, expr.elseExpr())); exprType = type1; } + + modifiedExpr = null; } public void atBinExpr(BinExpr expr) throws CompileError { int token = expr.getOperator(); int k = CodeGen.lookupBinOp(token); - if (k >= 0) { + if (k < 0) { + /* equation: &&, ||, ==, !=, <=, >=, <, > + */ + booleanExpr(expr); + } + else { /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>> */ - if (token == '+') { + if (token != '+') + atNonPlusExpr(expr, token); + else { Expr e = atPlusExpr(expr); if (e != null) { /* String concatenation has been translated into * an expression using StringBuffer. */ e = CallExpr.makeCall(Expr.make('.', e, - new Member("toString")), null); - expr.setLeft(e); - expr.setOprand2(null); // <---- look at this! + new Member("toString")), null); className = jvmJavaLangString; + modifiedExpr = e; // expr will be replaced with e. } } - else { - expr.oprand1().accept(this); - int type1 = exprType; - expr.oprand2().accept(this); - computeBinExprType(expr, token, type1); - } } - else { - /* equation: &&, ||, ==, !=, <=, >=, <, > - */ - booleanExpr(expr); + } + + private void atNonPlusExpr(BinExpr expr, int token) throws CompileError { + ASTree left = expr.oprand1(); + ASTree right = expr.oprand2(); + + left.accept(this); + if (modifiedExpr != null) { + left = modifiedExpr; + expr.setOprand1(left); + } + + int type1 = exprType; + right.accept(this); + if (modifiedExpr != null) { + right = modifiedExpr; + expr.setOprand2(right); } + + modifiedExpr = computeConstExpr(token, left, right); + computeBinExprType(expr, token, type1); } - // expr must be a + expression. + /* This method deals with string concatenation. It converts a + + * expression on String such as: + * "value:" + i + "." + * into: + * new StringBuffer().append("value:").append(i).append(".") + * .toString() + * + * This method also inserts a cast operator for the right operand + * if needed. + * + * EXPR must be a + expression. + * + * atPlusExpr() returns null if the expression is not a string + * concatenation. + */ 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; - return null; - } if (isPlusExpr(left)) { Expr newExpr = atPlusExpr((BinExpr)left); if (newExpr != null) { right.accept(this); + if (modifiedExpr != null) + right = modifiedExpr; + exprType = CLASS; arrayDim = 0; className = "java/lang/StringBuffer"; + modifiedExpr = null; return makeAppendCall(newExpr, right); } } @@ -291,17 +363,37 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { int type1 = exprType; int dim1 = arrayDim; String cname = className; + if (modifiedExpr != null) { + left = modifiedExpr; + expr.setOprand1(left); + } + right.accept(this); + if (modifiedExpr != null) { + right = modifiedExpr; + expr.setOprand2(right); + } + + modifiedExpr = computeConstExpr('+', left, right); if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname)) || (exprType == CLASS && arrayDim == 0 - && jvmJavaLangString.equals(className))) { - ASTList sbufClass = ASTList.make(new Symbol("java"), - new Symbol("lang"), new Symbol("StringBuffer")); - ASTree e = new NewExpr(sbufClass, null); + && jvmJavaLangString.equals(className))) + { exprType = CLASS; arrayDim = 0; - className = "java/lang/StringBuffer"; - return makeAppendCall(makeAppendCall(e, left), right); + if (modifiedExpr != null) { + // this expression is constant. + className = jvmJavaLangString; + return null; + } + else { + className = "java/lang/StringBuffer"; + ASTList sbufClass = ASTList.make(new Symbol("java"), + new Symbol("lang"), + new Symbol("StringBuffer")); + ASTree e = new NewExpr(sbufClass, null); + return makeAppendCall(makeAppendCall(e, left), right); + } } else { computeBinExprType(expr, '+', type1); @@ -336,33 +428,54 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { if (CodeGen.isP_INT(exprType)) exprType = INT; // type1 may be BYTE, ... + + arrayDim = 0; + // don't change the value of modifiedExpr. } private void booleanExpr(ASTree expr) throws CompileError { + ASTree modExpr = null; int op = CodeGen.getCompOperator(expr); if (op == EQ) { // ==, !=, ... BinExpr bexpr = (BinExpr)expr; bexpr.oprand1().accept(this); + if (modifiedExpr != null) + bexpr.setOprand1(modifiedExpr); + int type1 = exprType; int dim1 = arrayDim; bexpr.oprand2().accept(this); + if (modifiedExpr != null) + bexpr.setOprand2(modifiedExpr); + if (dim1 == 0 && arrayDim == 0) insertCast(bexpr, type1, exprType); } - else if (op == '!') + else if (op == '!') { ((Expr)expr).oprand1().accept(this); + if (modifiedExpr != null) + ((Expr)expr).setOprand1(modifiedExpr); + } else if (op == ANDAND || op == OROR) { BinExpr bexpr = (BinExpr)expr; bexpr.oprand1().accept(this); + if (modifiedExpr != null) + bexpr.setOprand1(modifiedExpr); + bexpr.oprand2().accept(this); + if (modifiedExpr != null) + bexpr.setOprand2(modifiedExpr); } - else // others + else { // others expr.accept(this); + modExpr = modifiedExpr; + } exprType = BOOLEAN; arrayDim = 0; + modifiedExpr = modExpr; } private void insertCast(BinExpr expr, int type1, int type2) @@ -374,18 +487,37 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { exprType = type1; } + private ASTree computeConstExpr(int op, ASTree left, ASTree right) { + if (left instanceof StringL && right instanceof StringL && op == '+') + return new StringL(((StringL)left).get() + ((StringL)right).get()); + else if (left instanceof IntConst) + return ((IntConst)left).compute(op, right); + else if (left instanceof DoubleConst) + return ((DoubleConst)left).compute(op, right); + else + return null; // not constant expression + } + public void atCastExpr(CastExpr expr) throws CompileError { String cname = resolveClassName(expr.getClassName()); expr.getOprand().accept(this); + if (modifiedExpr != null) + expr.setOprand(modifiedExpr); + exprType = expr.getType(); arrayDim = expr.getArrayDim(); className = cname; + modifiedExpr = null; } public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError { expr.getOprand().accept(this); + if (modifiedExpr != null) + expr.setOprand(modifiedExpr); + exprType = BOOLEAN; arrayDim = 0; + modifiedExpr = null; } public void atExpr(Expr expr) throws CompileError { @@ -411,7 +543,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { atFieldRead(expr); } else if (token == ARRAY) - atArrayRead(oprand, expr.oprand2()); + atArrayRead(expr); else if (token == PLUSPLUS || token == MINUSMINUS) atPlusPlus(token, oprand, expr); else if (token == '!') @@ -419,13 +551,40 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { else if (token == CALL) // method call fatal(); else { - expr.oprand1().accept(this); - if (token == '-' || token == '~') + oprand.accept(this); + if (modifiedExpr != null) { + oprand = modifiedExpr; + expr.setOprand1(oprand); + } + + modifiedExpr = computeConstExpr(token, oprand); + if (token == '-' || token == '~') { if (CodeGen.isP_INT(exprType)) exprType = INT; // type may be BYTE, ... + } } } + private ASTree computeConstExpr(int op, ASTree oprand) { + if (oprand instanceof IntConst) { + IntConst c = (IntConst)oprand; + long v = c.get(); + if (op == '-') + v = -v; + else if (op == '~') + v = ~v; + + c.set(v); + } + else if (oprand instanceof DoubleConst) { + DoubleConst c = (DoubleConst)oprand; + if (op == '-') + c.set(-c.get()); + } + + return null; + } + public void atCallExpr(CallExpr expr) throws CompileError { String mname = null; CtClass targetClass = null; @@ -455,6 +614,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { ASTree target = e.oprand1(); try { target.accept(this); + if (modifiedExpr != null) + e.setOprand1(modifiedExpr); } catch (NoFieldException nfe) { if (nfe.getExpr() != target) @@ -482,6 +643,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { MemberResolver.Method minfo = atMethodCallCore(targetClass, mname, args); expr.setMethod(minfo); + modifiedExpr = null; } private static void badMethod() throws CompileError { @@ -489,6 +651,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } /** + * modifiedExpr is not set. + * * @return a pair of the class declaring the invoked method * and the MethodInfo of that method. Never null. */ @@ -531,6 +695,9 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { while (args != null) { ASTree a = args.head(); a.accept(this); + if (modifiedExpr != null) + args.setHead(modifiedExpr); + types[i] = exprType; dims[i] = arrayDim; cnames[i] = className; @@ -539,6 +706,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } } + /* modifiedExpr is not set. + */ void setReturnType(String desc) throws CompileError { int i = desc.indexOf(')'); if (i < 0) @@ -566,11 +735,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } } - private void atFieldRead(ASTree expr) throws CompileError { - atFieldRead(fieldAccess(expr)); - } - - private void atFieldRead(CtField f) throws CompileError { + private CtField atFieldRead(ASTree expr) throws CompileError { + CtField f = fieldAccess(expr); FieldInfo finfo = f.getFieldInfo2(); String type = finfo.getDescriptor(); @@ -589,6 +755,9 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { className = type.substring(i + 1, type.indexOf(';', i + 1)); else className = null; + + modifiedExpr = null; ?? + return f; } protected CtField fieldAccess(ASTree expr) throws CompileError { @@ -611,6 +780,9 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { else if (op == '.') try { e.oprand1().accept(this); + if (modifiedExpr != null) + e.setOprand1(modifiedExpr); + if (exprType == CLASS && arrayDim == 0) return resolver.lookupFieldByJvmName(className, (Symbol)e.oprand2()); @@ -636,25 +808,38 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { exprType = CLASS; arrayDim = 0; className =jvmJavaLangClass; + modifiedExpr = null; } public void atArrayLength(Expr expr) throws CompileError { expr.oprand1().accept(this); + if (modifiedExpr != null) + expr.setOprand1(modifiedExpr); + exprType = INT; arrayDim = 0; + modifiedExpr = null; } - public void atArrayRead(ASTree array, ASTree index) - throws CompileError - { + public void atArrayRead(Expr expr) throws CompileError { + ASTree array = expr.oprand1(); array.accept(this); + if (modifiedExpr != null) + expr.setOprand1(modifiedExpr); + int type = exprType; int dim = arrayDim; String cname = className; + + ASTree index = expr.oprand2(); index.accept(this); + if (modifiedExpr != null) + expr.setOprand2(modifiedExpr); + exprType = type; arrayDim = dim - 1; className = cname; + modifiedExpr = null; } private void atPlusPlus(int token, ASTree oprand, Expr expr) @@ -668,12 +853,13 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { Declarator d = ((Variable)oprand).getDeclarator(); exprType = d.getType(); arrayDim = d.getArrayDim(); + modifiedExpr = null; } else { if (oprand instanceof Expr) { Expr e = (Expr)oprand; if (e.getOperator() == ARRAY) { - atArrayRead(e.oprand1(), e.oprand2()); + atArrayRead(e); // arrayDim should be 0. int t = exprType; if (t == INT || t == BYTE || t == CHAR || t == SHORT) @@ -689,8 +875,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { protected void atFieldPlusPlus(ASTree oprand) throws CompileError { - CtField f = fieldAccess(oprand); - atFieldRead(f); + atFieldRead(oprand); int t = exprType; if (t == INT || t == BYTE || t == CHAR || t == SHORT) exprType = INT; -- 2.39.5