aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist/compiler/CodeGen.java
diff options
context:
space:
mode:
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2003-11-27 05:33:16 +0000
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2003-11-27 05:33:16 +0000
commitcdca9771599b4c3337aaf42cf7460a27dc1719d5 (patch)
tree9617dfa2aa53d78c6bd2d3cf4428137d355faa76 /src/main/javassist/compiler/CodeGen.java
parentced4ae1f0e2130b36cb51faf6345d5b8e036585e (diff)
downloadjavassist-cdca9771599b4c3337aaf42cf7460a27dc1719d5.tar.gz
javassist-cdca9771599b4c3337aaf42cf7460a27dc1719d5.zip
I implemented a type checker for better code generation.
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@55 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'src/main/javassist/compiler/CodeGen.java')
-rw-r--r--src/main/javassist/compiler/CodeGen.java191
1 files changed, 117 insertions, 74 deletions
diff --git a/src/main/javassist/compiler/CodeGen.java b/src/main/javassist/compiler/CodeGen.java
index 6a0bd3dc..194c3fdb 100644
--- a/src/main/javassist/compiler/CodeGen.java
+++ b/src/main/javassist/compiler/CodeGen.java
@@ -33,6 +33,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
protected Bytecode bytecode;
private int tempVar;
+ TypeChecker typeChecker;
/**
* true if the last visited node is a return statement.
@@ -56,12 +57,17 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
public CodeGen(Bytecode b) {
bytecode = b;
tempVar = -1;
+ typeChecker = null;
hasReturned = false;
inStaticMethod = false;
breakList = null;
continueList = null;
}
+ public void setTypeChecker(TypeChecker checker) {
+ typeChecker = checker;
+ }
+
protected static void fatal() throws CompileError {
throw new CompileError("fatal");
}
@@ -192,29 +198,21 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
return sbuf.toString();
}
- protected static int jvmTypeNameToExprType(char type) {
- switch(type) {
- case 'Z' :
- return BOOLEAN;
- case 'B' :
- return BYTE;
- case 'C' :
- return CHAR;
- case 'S' :
- return SHORT;
- case 'I' :
- return INT;
- case 'J' :
- return LONG;
- case 'F' :
- return FLOAT;
- case 'D' :
- return DOUBLE;
- case 'V' :
- return VOID;
- default :
- return CLASS;
- }
+ public void compileExpr(ASTree expr) throws CompileError {
+ doTypeCheck(expr);
+ expr.accept(this);
+ }
+
+ public boolean compileBooleanExpr(boolean branchIf, ASTree expr)
+ throws CompileError
+ {
+ doTypeCheck(expr);
+ return booleanExpr(branchIf, expr);
+ }
+
+ public void doTypeCheck(ASTree expr) throws CompileError {
+ if (typeChecker != null)
+ expr.accept(typeChecker);
}
public void atASTList(ASTList n) throws CompileError { fatal(); }
@@ -302,6 +300,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
int op = st.getOperator();
if (op == EXPR) {
ASTree expr = st.getLeft();
+ doTypeCheck(expr);
if (expr instanceof AssignExpr)
atAssignExpr((AssignExpr)expr, false);
else if (isPlusPlusExpr(expr)) {
@@ -359,7 +358,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
ASTree expr = st.head();
Stmnt thenp = (Stmnt)st.tail().head();
Stmnt elsep = (Stmnt)st.tail().tail().head();
- booleanExpr(false, expr);
+ compileBooleanExpr(false, expr);
int pc = bytecode.currentPc();
int pc2 = 0;
bytecode.addIndex(0); // correct later
@@ -412,7 +411,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
if (notDo)
bytecode.write16bit(pc, pc3 - pc + 1);
- boolean alwaysBranch = booleanExpr(true, expr);
+ boolean alwaysBranch = compileBooleanExpr(true, expr);
bytecode.addIndex(pc2 - bytecode.currentPc() + 1);
patchGoto(breakList, bytecode.currentPc());
@@ -449,7 +448,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
int pc = bytecode.currentPc();
int pc2 = 0;
if (expr != null) {
- booleanExpr(false, expr);
+ compileBooleanExpr(false, expr);
pc2 = bytecode.currentPc();
bytecode.addIndex(0);
}
@@ -500,7 +499,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
if (result == null)
op = Opcode.RETURN;
else {
- result.accept(this);
+ compileExpr(result);
if (arrayDim > 0)
op = ARETURN;
else {
@@ -524,7 +523,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
private void atThrowStmnt(Stmnt st) throws CompileError {
ASTree e = st.getLeft();
- e.accept(this);
+ compileExpr(e);
if (exprType != CLASS || arrayDim > 0)
throw new CompileError("bad throw statement");
@@ -560,8 +559,10 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
/* NOTE: Array initializers has not been supported.
*/
ASTree init = d.getInitializer();
- if (init != null)
+ if (init != null) {
+ doTypeCheck(init);
atVariableAssign(null, '=', null, d, init, false);
+ }
}
public abstract void atNewExpr(NewExpr n) throws CompileError;
@@ -681,20 +682,22 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
int type, int dim, String cname)
throws CompileError
{
- right.accept(this);
- if (invalidDim(exprType, arrayDim, className, type, dim, cname, false)
- || (op != '=' && dim > 0))
- badAssign(expr);
-
if (op == PLUS_E && dim == 0 && type == CLASS)
- atStringConcatExpr(expr, type, dim, cname);
- else if (op != '=') {
- int token = assignOps[op - MOD_E];
- int k = lookupBinOp(token);
- if (k < 0)
- fatal();
+ atStringPlusEq(expr, type, dim, cname, right);
+ else {
+ right.accept(this);
+ if (invalidDim(exprType, arrayDim, className, type, dim, cname,
+ false) || (op != '=' && dim > 0))
+ badAssign(expr);
+
+ if (op != '=') {
+ int token = assignOps[op - MOD_E];
+ int k = lookupBinOp(token);
+ if (k < 0)
+ fatal();
- atArithBinExpr(expr, token, k, type);
+ atArithBinExpr(expr, token, k, type);
+ }
}
if (op != '=' || (dim == 0 && !isRefType(type)))
@@ -703,6 +706,23 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
// type check should be done here.
}
+ private void atStringPlusEq(Expr expr, int type, int dim, String cname,
+ ASTree right)
+ throws CompileError
+ {
+ if (!jvmJavaLangString.equals(cname))
+ badAssign(expr);
+
+ convToString(type, dim); // the value might be null.
+ right.accept(this);
+ convToString(exprType, arrayDim);
+ bytecode.addInvokevirtual(javaLangString, "concat",
+ "(Ljava/lang/String;)Ljava/lang/String;");
+ exprType = CLASS;
+ arrayDim = 0;
+ className = jvmJavaLangString;
+ }
+
private boolean invalidDim(int srcType, int srcDim, String srcClass,
int destType, int destDim, String destClass,
boolean isCast)
@@ -727,15 +747,19 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
int pc = bytecode.currentPc();
bytecode.addIndex(0); // correct later
expr.thenExpr().accept(this);
+ int dim1 = arrayDim;
bytecode.addOpcode(Opcode.GOTO);
int pc2 = bytecode.currentPc();
bytecode.addIndex(0);
bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
expr.elseExpr().accept(this);
+ if (dim1 != arrayDim)
+ throw new CompileError("type mismatch in ?:");
+
bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1);
}
- private final int[] binOp = {
+ static final int[] binOp = {
'+', DADD, FADD, LADD, IADD,
'-', DSUB, FSUB, LSUB, ISUB,
'*', DMUL, FMUL, LMUL, IMUL,
@@ -748,7 +772,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
RSHIFT, NOP, NOP, LSHR, ISHR,
ARSHIFT, NOP, NOP, LUSHR, IUSHR };
- private int lookupBinOp(int token) {
+ static int lookupBinOp(int token) {
int[] code = binOp;
int s = code.length;
for (int k = 0; k < s; k = k + 5)
@@ -766,10 +790,14 @@ 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;
- expr.oprand2().accept(this);
+ right.accept(this);
if (dim1 != arrayDim)
throw new CompileError("incompatible array types");
@@ -778,18 +806,17 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
atStringConcatExpr(expr, type1, dim1, cname1);
else
atArithBinExpr(expr, token, k, type1);
-
- return;
}
-
- /* equation: &&, ||, ==, !=, <=, >=, <, >
- */
- booleanExpr(true, expr);
- bytecode.addIndex(7);
- bytecode.addIconst(0); // false
- bytecode.addOpcode(Opcode.GOTO);
- bytecode.addIndex(4);
- bytecode.addIconst(1); // true
+ else {
+ /* equation: &&, ||, ==, !=, <=, >=, <, >
+ */
+ booleanExpr(true, expr);
+ bytecode.addIndex(7);
+ bytecode.addIconst(0); // false
+ bytecode.addOpcode(Opcode.GOTO);
+ bytecode.addIndex(4);
+ bytecode.addIconst(1); // true
+ }
}
/* arrayDim values of the two oprands must be equal.
@@ -846,6 +873,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
else
bytecode.addOpcode(SWAP);
+ // even if type1 is String, the left operand might be null.
convToString(type1, dim1);
bytecode.addOpcode(SWAP);
@@ -923,6 +951,9 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
}
else { // others
expr.accept(this);
+ if (exprType != BOOLEAN || arrayDim != 0)
+ throw new CompileError("boolean expr is required");
+
bytecode.addOpcode(branchIf ? IFNE : IFEQ);
}
@@ -941,7 +972,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
return false;
}
- private static int getCompOperator(ASTree expr) throws CompileError {
+ static int getCompOperator(ASTree expr) throws CompileError {
if (expr instanceof Expr) {
Expr bexpr = (Expr)expr;
int token = bexpr.getOperator();
@@ -969,19 +1000,19 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
return type1;
}
- private final int ifOp[] = { EQ, IF_ICMPEQ, IF_ICMPNE,
- NEQ, IF_ICMPNE, IF_ICMPEQ,
- LE, IF_ICMPLE, IF_ICMPGT,
- GE, IF_ICMPGE, IF_ICMPLT,
- '<', IF_ICMPLT, IF_ICMPGE,
- '>', IF_ICMPGT, IF_ICMPLE };
+ private static final int ifOp[] = { EQ, IF_ICMPEQ, IF_ICMPNE,
+ NEQ, IF_ICMPNE, IF_ICMPEQ,
+ LE, IF_ICMPLE, IF_ICMPGT,
+ GE, IF_ICMPGE, IF_ICMPLT,
+ '<', IF_ICMPLT, IF_ICMPGE,
+ '>', IF_ICMPGT, IF_ICMPLE };
- private final int ifOp2[] = { EQ, IFEQ, IFNE,
- NEQ, IFNE, IFEQ,
- LE, IFLE, IFGT,
- GE, IFGE, IFLT,
- '<', IFLT, IFGE,
- '>', IFGT, IFLE };
+ private static final int ifOp2[] = { EQ, IFEQ, IFNE,
+ NEQ, IFNE, IFEQ,
+ LE, IFLE, IFGT,
+ GE, IFGE, IFLT,
+ '<', IFLT, IFGE,
+ '>', IFGT, IFLE };
/* Produces the opcode to branch if the condition is true.
* The oprands are not produced.
@@ -1070,6 +1101,18 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
return P_INT; // BOOLEAN, BYTE, CHAR, SHORT, INT
}
+ // used in TypeChecker.
+ static boolean isP_INT(int type) {
+ return typePrecedence(type) == P_INT;
+ }
+
+ // used in TypeChecker.
+ static boolean rightIsStrong(int type1, int type2) {
+ int type1_p = typePrecedence(type1);
+ int type2_p = typePrecedence(type2);
+ return type1_p >= 0 && type2_p >= 0 && type1_p > type2_p;
+ }
+
private static final int[] castOp = {
/* D F L I */
/* double */ NOP, D2F, D2L, D2I,
@@ -1221,14 +1264,12 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
}
public void atExpr(Expr expr) throws CompileError {
- // method call, array access, member access,
+ // array access, member access,
// (unary) +, (unary) -, ++, --, !, ~
int token = expr.getOperator();
ASTree oprand = expr.oprand1();
- if (token == CALL) // method call
- atMethodCall(expr);
- else if (token == '.')
+ if (token == '.')
if (((Symbol)expr.oprand2()).get().equals("length"))
atArrayLength(expr);
else
@@ -1249,6 +1290,8 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
bytecode.addIndex(4);
bytecode.addIconst(0);
}
+ else if (token == CALL) // method call
+ fatal();
else {
expr.oprand1().accept(this);
int type = typePrecedence(exprType);
@@ -1298,7 +1341,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
throw new CompileError("invalid type for " + expr.getName());
}
- protected abstract void atMethodCall(Expr expr) throws CompileError;
+ public abstract void atCallExpr(CallExpr expr) throws CompileError;
protected abstract void atFieldRead(ASTree expr) throws CompileError;
@@ -1598,7 +1641,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
public void atStringL(StringL s) throws CompileError {
exprType = CLASS;
arrayDim = 0;
- className = "java/lang/String";
+ className = jvmJavaLangString;
bytecode.addLdc(s.get());
}