📄 codegen.java
字号:
if (op != NOP) bytecode.addOpcode(op); if (op == NOP || op == L2I || op == F2I || op == D2I) if (op2 != NOP) bytecode.addOpcode(op2); } public void atExpr(Expr expr) throws CompileError { // array access, member access, // (unary) +, (unary) -, ++, --, !, ~ int token = expr.getOperator(); ASTree oprand = expr.oprand1(); if (token == '.') { String member = ((Symbol)expr.oprand2()).get(); if (member.equals("class")) atClassObject(expr); // .class else atFieldRead(expr); } else if (token == MEMBER) { // field read /* MEMBER ('#') is an extension by Javassist. * The compiler internally uses # for compiling .class * expressions such as "int.class". */ atFieldRead(expr); } else if (token == ARRAY) atArrayRead(oprand, expr.oprand2()); else if (token == PLUSPLUS || token == MINUSMINUS) atPlusPlus(token, oprand, expr, true); else if (token == '!') { booleanExpr(false, expr); bytecode.addIndex(7); bytecode.addIconst(1); bytecode.addOpcode(Opcode.GOTO); bytecode.addIndex(4); bytecode.addIconst(0); } else if (token == CALL) // method call fatal(); else { expr.oprand1().accept(this); int type = typePrecedence(exprType); if (arrayDim > 0) badType(expr); if (token == '-') { if (type == P_DOUBLE) bytecode.addOpcode(DNEG); else if (type == P_FLOAT) bytecode.addOpcode(FNEG); else if (type == P_LONG) bytecode.addOpcode(LNEG); else if (type == P_INT) { bytecode.addOpcode(INEG); exprType = INT; // type may be BYTE, ... } else badType(expr); } else if (token == '~') { if (type == P_INT) { bytecode.addIconst(-1); bytecode.addOpcode(IXOR); exprType = INT; // type may be BYTE. ... } else if (type == P_LONG) { bytecode.addLconst(-1); bytecode.addOpcode(LXOR); } else badType(expr); } else if (token == '+') { if (type == P_OTHER) badType(expr); // do nothing. ignore. } else fatal(); } } protected static void badType(Expr expr) throws CompileError { throw new CompileError("invalid type for " + expr.getName()); } public abstract void atCallExpr(CallExpr expr) throws CompileError; protected abstract void atFieldRead(ASTree expr) throws CompileError; public void atClassObject(Expr expr) throws CompileError { ASTree op1 = expr.oprand1(); if (!(op1 instanceof Symbol)) throw new CompileError("fatal error: badly parsed .class expr"); String cname = ((Symbol)op1).get(); if (cname.startsWith("[")) { int i = cname.indexOf("[L"); if (i >= 0) { String name = cname.substring(i + 2, cname.length() - 1); String name2 = resolveClassName(name); if (!name.equals(name2)) { /* For example, to obtain String[].class, * "[Ljava.lang.String;" (not "[Ljava/lang/String"!) * must be passed to Class.forName(). */ name2 = MemberResolver.jvmToJavaName(name2); StringBuffer sbuf = new StringBuffer(); while (i-- >= 0) sbuf.append('['); sbuf.append('L').append(name2).append(';'); cname = sbuf.toString(); } } } else { cname = resolveClassName(MemberResolver.javaToJvmName(cname)); cname = MemberResolver.jvmToJavaName(cname); } int start = bytecode.currentPc(); bytecode.addLdc(cname); bytecode.addInvokestatic("java.lang.Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;"); int end = bytecode.currentPc(); bytecode.addOpcode(Opcode.GOTO); int pc = bytecode.currentPc(); bytecode.addIndex(0); // correct later bytecode.addExceptionHandler(start, end, bytecode.currentPc(), "java.lang.ClassNotFoundException"); /* -- the following code is for inlining a call to DotClass.fail(). int var = getMaxLocals(); incMaxLocals(1); bytecode.growStack(1); bytecode.addAstore(var); bytecode.addNew("java.lang.NoClassDefFoundError"); bytecode.addOpcode(DUP); bytecode.addAload(var); bytecode.addInvokevirtual("java.lang.ClassNotFoundException", "getMessage", "()Ljava/lang/String;"); bytecode.addInvokespecial("java.lang.NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V"); */ bytecode.growStack(1); bytecode.addInvokestatic("javassist.runtime.DotClass", "fail", "(Ljava/lang/ClassNotFoundException;)" + "Ljava/lang/NoClassDefFoundError;"); bytecode.addOpcode(ATHROW); bytecode.write16bit(pc, bytecode.currentPc() - pc + 1); exprType = CLASS; arrayDim = 0; className = "java/lang/Class"; } public void atArrayRead(ASTree array, ASTree index) throws CompileError { arrayAccess(array, index); bytecode.addOpcode(getArrayReadOp(exprType, arrayDim)); } protected void arrayAccess(ASTree array, ASTree index) throws CompileError { array.accept(this); int type = exprType; int dim = arrayDim; if (dim == 0) throw new CompileError("bad array access"); String cname = className; index.accept(this); if (typePrecedence(exprType) != P_INT || arrayDim > 0) throw new CompileError("bad array index"); exprType = type; arrayDim = dim - 1; className = cname; } protected static int getArrayReadOp(int type, int dim) { if (dim > 0) return AALOAD; switch (type) { case DOUBLE : return DALOAD; case FLOAT : return FALOAD; case LONG : return LALOAD; case INT : return IALOAD; case SHORT : return SALOAD; case CHAR : return CALOAD; case BYTE : case BOOLEAN : return BALOAD; default : return AALOAD; } } protected static int getArrayWriteOp(int type, int dim) { if (dim > 0) return AASTORE; switch (type) { case DOUBLE : return DASTORE; case FLOAT : return FASTORE; case LONG : return LASTORE; case INT : return IASTORE; case SHORT : return SASTORE; case CHAR : return CASTORE; case BYTE : case BOOLEAN : return BASTORE; default : return AASTORE; } } private void atPlusPlus(int token, ASTree oprand, Expr expr, boolean doDup) throws CompileError { boolean isPost = oprand == null; // ++i or i++? if (isPost) oprand = expr.oprand2(); if (oprand instanceof Variable) { Declarator d = ((Variable)oprand).getDeclarator(); int t = exprType = d.getType(); arrayDim = d.getArrayDim(); int var = getLocalVar(d); if (arrayDim > 0) badType(expr); if (t == DOUBLE) { bytecode.addDload(var); if (doDup && isPost) bytecode.addOpcode(DUP2); bytecode.addDconst(1.0); bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB); if (doDup && !isPost) bytecode.addOpcode(DUP2); bytecode.addDstore(var); } else if (t == LONG) { bytecode.addLload(var); if (doDup && isPost) bytecode.addOpcode(DUP2); bytecode.addLconst((long)1); bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB); if (doDup && !isPost) bytecode.addOpcode(DUP2); bytecode.addLstore(var); } else if (t == FLOAT) { bytecode.addFload(var); if (doDup && isPost) bytecode.addOpcode(DUP); bytecode.addFconst(1.0f); bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB); if (doDup && !isPost) bytecode.addOpcode(DUP); bytecode.addFstore(var); } else if (t == BYTE || t == CHAR || t == SHORT || t == INT) { if (doDup && isPost) bytecode.addIload(var); bytecode.addOpcode(IINC); bytecode.add(var); bytecode.add(token == PLUSPLUS ? 1 : -1); if (doDup && !isPost) bytecode.addIload(var); } else badType(expr); } else { if (oprand instanceof Expr) { Expr e = (Expr)oprand; if (e.getOperator() == ARRAY) { atArrayPlusPlus(token, isPost, e, doDup); return; } } atFieldPlusPlus(token, isPost, oprand, expr, doDup); } } public void atArrayPlusPlus(int token, boolean isPost, Expr expr, boolean doDup) throws CompileError { arrayAccess(expr.oprand1(), expr.oprand2()); int t = exprType; int dim = arrayDim; if (dim > 0) badType(expr); bytecode.addOpcode(DUP2); bytecode.addOpcode(getArrayReadOp(t, arrayDim)); int dup_code = is2word(t, dim) ? DUP2_X2 : DUP_X2; atPlusPlusCore(dup_code, doDup, token, isPost, expr); bytecode.addOpcode(getArrayWriteOp(t, dim)); } protected void atPlusPlusCore(int dup_code, boolean doDup, int token, boolean isPost, Expr expr) throws CompileError { int t = exprType; if (doDup && isPost) bytecode.addOpcode(dup_code); if (t == INT || t == BYTE || t == CHAR || t == SHORT) { bytecode.addIconst(1); bytecode.addOpcode(token == PLUSPLUS ? IADD : ISUB); exprType = INT; } else if (t == LONG) { bytecode.addLconst((long)1); bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB); } else if (t == FLOAT) { bytecode.addFconst(1.0f); bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB); } else if (t == DOUBLE) { bytecode.addDconst(1.0); bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB); } else badType(expr); if (doDup && !isPost) bytecode.addOpcode(dup_code); } protected abstract void atFieldPlusPlus(int token, boolean isPost, ASTree oprand, Expr expr, boolean doDup) throws CompileError; public abstract void atMember(Member n) throws CompileError; public void atVariable(Variable v) throws CompileError { Declarator d = v.getDeclarator(); exprType = d.getType(); arrayDim = d.getArrayDim(); className = d.getClassName(); int var = getLocalVar(d); if (arrayDim > 0) bytecode.addAload(var); else switch (exprType) { case CLASS : bytecode.addAload(var); break; case LONG : bytecode.addLload(var); break; case FLOAT : bytecode.addFload(var); break; case DOUBLE : bytecode.addDload(var); break; default : // BOOLEAN, BYTE, CHAR, SHORT, INT bytecode.addIload(var); break; } } public void atKeyword(Keyword k) throws CompileError { arrayDim = 0; int token = k.get(); switch (token) { case TRUE : bytecode.addIconst(1); exprType = BOOLEAN; break; case FALSE : bytecode.addIconst(0); exprType = BOOLEAN; break; case NULL : bytecode.addOpcode(ACONST_NULL); exprType = NULL; break; case THIS : case SUPER : if (inStaticMethod) throw new CompileError("not-available: " + (token == THIS ? "this" : "super")); bytecode.addAload(0); exprType = CLASS; if (token == THIS) className = getThisName(); else className = getSuperName(); break; default : fatal(); } } public void atStringL(StringL s) throws CompileError { exprType = CLASS; arrayDim = 0; className = jvmJavaLangString; bytecode.addLdc(s.get()); } public void atIntConst(IntConst i) throws CompileError { arrayDim = 0; long value = i.get(); int type = i.getType(); if (type == IntConstant || type == CharConstant) { exprType = (type == IntConstant ? INT : CHAR); bytecode.addIconst((int)value); } else { exprType = LONG; bytecode.addLconst(value); } } public void atDoubleConst(DoubleConst d) throws CompileError { arrayDim = 0; if (d.getType() == DoubleConstant) { exprType = DOUBLE; bytecode.addDconst(d.get()); } else { exprType = FLOAT; bytecode.addFconst((float)d.get()); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -