📄 codegen.java
字号:
int pc3 = bytecode.currentPc(); if (update != null) update.accept(this); bytecode.addOpcode(Opcode.GOTO); bytecode.addIndex(pc - bytecode.currentPc() + 1); int pc4 = bytecode.currentPc(); if (expr != null) bytecode.write16bit(pc2, pc4 - pc2 + 1); patchGoto(breakList, pc4); patchGoto(continueList, pc3); continueList = prevContList; breakList = prevBreakList; hasReturned = false; } private void atSwitchStmnt(Stmnt st) throws CompileError { compileExpr(st.head()); ArrayList prevBreakList = breakList; breakList = new ArrayList(); int opcodePc = bytecode.currentPc(); bytecode.addOpcode(LOOKUPSWITCH); int npads = 3 - (opcodePc & 3); while (npads-- > 0) bytecode.add(0); Stmnt body = (Stmnt)st.tail(); int npairs = 0; for (ASTList list = body; list != null; list = list.tail()) if (((Stmnt)list.head()).getOperator() == CASE) ++npairs; // opcodePc2 is the position at which the default jump offset is. int opcodePc2 = bytecode.currentPc(); bytecode.addGap(4); bytecode.add32bit(npairs); bytecode.addGap(npairs * 8); long[] pairs = new long[npairs]; int ipairs = 0; int defaultPc = -1; for (ASTList list = body; list != null; list = list.tail()) { Stmnt label = (Stmnt)list.head(); int op = label.getOperator(); if (op == DEFAULT) defaultPc = bytecode.currentPc(); else if (op != CASE) fatal(); else { pairs[ipairs++] = ((long)computeLabel(label.head()) << 32) + ((long)(bytecode.currentPc() - opcodePc) & 0xffffffff); } hasReturned = false; ((Stmnt)label.tail()).accept(this); } Arrays.sort(pairs); int pc = opcodePc2 + 8; for (int i = 0; i < npairs; ++i) { bytecode.write32bit(pc, (int)(pairs[i] >>> 32)); bytecode.write32bit(pc + 4, (int)pairs[i]); pc += 8; } if (defaultPc < 0 || breakList.size() > 0) hasReturned = false; int endPc = bytecode.currentPc(); if (defaultPc < 0) defaultPc = endPc; bytecode.write32bit(opcodePc2, defaultPc - opcodePc); patchGoto(breakList, endPc); breakList = prevBreakList; } private int computeLabel(ASTree expr) throws CompileError { doTypeCheck(expr); expr = TypeChecker.stripPlusExpr(expr); if (expr instanceof IntConst) return (int)((IntConst)expr).get(); else throw new CompileError("bad case label"); } private void atBreakStmnt(Stmnt st, boolean notCont) throws CompileError { if (st.head() != null) throw new CompileError( "sorry, not support labeled break or continue"); bytecode.addOpcode(Opcode.GOTO); Integer pc = new Integer(bytecode.currentPc()); bytecode.addIndex(0); if (notCont) breakList.add(pc); else continueList.add(pc); } protected void atReturnStmnt(Stmnt st) throws CompileError { atReturnStmnt2(st.getLeft()); } protected final void atReturnStmnt2(ASTree result) throws CompileError { int op; if (result == null) op = Opcode.RETURN; else { compileExpr(result); if (arrayDim > 0) op = ARETURN; else { int type = exprType; if (type == DOUBLE) op = DRETURN; else if (type == FLOAT) op = FRETURN; else if (type == LONG) op = LRETURN; else if (isRefType(type)) op = ARETURN; else op = IRETURN; } } for (ReturnHook har = returnHooks; har != null; har = har.next) har.doit(bytecode, op); bytecode.addOpcode(op); hasReturned = true; } private void atThrowStmnt(Stmnt st) throws CompileError { ASTree e = st.getLeft(); compileExpr(e); if (exprType != CLASS || arrayDim > 0) throw new CompileError("bad throw statement"); bytecode.addOpcode(ATHROW); hasReturned = true; } /* overridden in MemberCodeGen */ protected void atTryStmnt(Stmnt st) throws CompileError { hasReturned = false; } private void atSyncStmnt(Stmnt st) throws CompileError { int nbreaks = getListSize(breakList); int ncontinues = getListSize(continueList); compileExpr(st.head()); if (exprType != CLASS && arrayDim == 0) throw new CompileError("bad type expr for synchronized block"); Bytecode bc = bytecode; final int var = bc.getMaxLocals(); bc.incMaxLocals(1); bc.addOpcode(DUP); bc.addAstore(var); bc.addOpcode(MONITORENTER); ReturnHook rh = new ReturnHook(this) { protected void doit(Bytecode b, int opcode) { b.addAload(var); b.addOpcode(MONITOREXIT); } }; int pc = bc.currentPc(); Stmnt body = (Stmnt)st.tail(); if (body != null) body.accept(this); int pc2 = bc.currentPc(); int pc3 = 0; if (!hasReturned) { rh.doit(bc, 0); // the 2nd arg is ignored. bc.addOpcode(Opcode.GOTO); pc3 = bc.currentPc(); bc.addIndex(0); } int pc4 = bc.currentPc(); rh.doit(bc, 0); // the 2nd arg is ignored. bc.addOpcode(ATHROW); bc.addExceptionHandler(pc, pc2, pc4, 0); if (!hasReturned) bc.write16bit(pc3, bc.currentPc() - pc3 + 1); rh.remove(this); if (getListSize(breakList) != nbreaks || getListSize(continueList) != ncontinues) throw new CompileError( "sorry, cannot break/continue in synchronized block"); } private static int getListSize(ArrayList list) { return list == null ? 0 : list.size(); } private static boolean isPlusPlusExpr(ASTree expr) { if (expr instanceof Expr) { int op = ((Expr)expr).getOperator(); return op == PLUSPLUS || op == MINUSMINUS; } return false; } public void atDeclarator(Declarator d) throws CompileError { d.setLocalVar(getMaxLocals()); d.setClassName(resolveClassName(d.getClassName())); int size; if (is2word(d.getType(), d.getArrayDim())) size = 2; else size = 1; incMaxLocals(size); /* NOTE: Array initializers has not been supported. */ ASTree init = d.getInitializer(); if (init != null) { doTypeCheck(init); atVariableAssign(null, '=', null, d, init, false); } } public abstract void atNewExpr(NewExpr n) throws CompileError; public abstract void atArrayInit(ArrayInit init) throws CompileError; public void atAssignExpr(AssignExpr expr) throws CompileError { atAssignExpr(expr, true); } protected void atAssignExpr(AssignExpr expr, boolean doDup) throws CompileError { // =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>= int op = expr.getOperator(); ASTree left = expr.oprand1(); ASTree right = expr.oprand2(); if (left instanceof Variable) atVariableAssign(expr, op, (Variable)left, ((Variable)left).getDeclarator(), right, doDup); else { if (left instanceof Expr) { Expr e = (Expr)left; if (e.getOperator() == ARRAY) { atArrayAssign(expr, op, (Expr)left, right, doDup); return; } } atFieldAssign(expr, op, left, right, doDup); } } protected static void badAssign(Expr expr) throws CompileError { String msg; if (expr == null) msg = "incompatible type for assignment"; else msg = "incompatible type for " + expr.getName(); throw new CompileError(msg); } /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=. * * expr and var can be null. */ private void atVariableAssign(Expr expr, int op, Variable var, Declarator d, ASTree right, boolean doDup) throws CompileError { int varType = d.getType(); int varArray = d.getArrayDim(); String varClass = d.getClassName(); int varNo = getLocalVar(d); if (op != '=') atVariable(var); // expr is null if the caller is atDeclarator(). if (expr == null && right instanceof ArrayInit) atArrayVariableAssign((ArrayInit)right, varType, varArray, varClass); else atAssignCore(expr, op, right, varType, varArray, varClass); if (doDup) if (is2word(varType, varArray)) bytecode.addOpcode(DUP2); else bytecode.addOpcode(DUP); if (varArray > 0) bytecode.addAstore(varNo); else if (varType == DOUBLE) bytecode.addDstore(varNo); else if (varType == FLOAT) bytecode.addFstore(varNo); else if (varType == LONG) bytecode.addLstore(varNo); else if (isRefType(varType)) bytecode.addAstore(varNo); else bytecode.addIstore(varNo); exprType = varType; arrayDim = varArray; className = varClass; } protected abstract void atArrayVariableAssign(ArrayInit init, int varType, int varArray, String varClass) throws CompileError; private void atArrayAssign(Expr expr, int op, Expr array, ASTree right, boolean doDup) throws CompileError { arrayAccess(array.oprand1(), array.oprand2()); if (op != '=') { bytecode.addOpcode(DUP2); bytecode.addOpcode(getArrayReadOp(exprType, arrayDim)); } int aType = exprType; int aDim = arrayDim; String cname = className; atAssignCore(expr, op, right, aType, aDim, cname); if (doDup) if (is2word(aType, aDim)) bytecode.addOpcode(DUP2_X2); else bytecode.addOpcode(DUP_X2); bytecode.addOpcode(getArrayWriteOp(aType, aDim)); exprType = aType; arrayDim = aDim; className = cname; } protected abstract void atFieldAssign(Expr expr, int op, ASTree left, ASTree right, boolean doDup) throws CompileError; protected void atAssignCore(Expr expr, int op, ASTree right, int type, int dim, String cname) throws CompileError { if (op == PLUS_E && dim == 0 && type == CLASS) 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); } } if (op != '=' || (dim == 0 && !isRefType(type))) atNumCastExpr(exprType, type); // 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) { if (srcDim != destDim) if (srcType == NULL) return false; else if (destDim == 0 && destType == CLASS && jvmJavaLangObject.equals(destClass)) return false; else if (isCast && srcDim == 0 && srcType == CLASS && jvmJavaLangObject.equals(srcClass)) return false; else return true; return false; } public void atCondExpr(CondExpr expr) throws CompileError { booleanExpr(false, expr.condExpr()); 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); } static final int[] binOp = { '+', DADD, FADD, LADD, IADD, '-', DSUB, FSUB, LSUB, ISUB, '*', DMUL, FMUL, LMUL, IMUL, '/', DDIV, FDIV, LDIV, IDIV, '%', DREM, FREM, LREM, IREM, '|', NOP, NOP, LOR, IOR, '^', NOP, NOP, LXOR, IXOR, '&', NOP, NOP, LAND, IAND, LSHIFT, NOP, NOP, LSHL, ISHL, RSHIFT, NOP, NOP, LSHR, ISHR, ARSHIFT, NOP, NOP, LUSHR, IUSHR }; static int lookupBinOp(int token) { int[] code = binOp; int s = code.length; for (int k = 0; k < s; k = k + 5) if (code[k] == token) return k; return -1; } public void atBinExpr(BinExpr expr) throws CompileError { int token = expr.getOperator(); /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>> */ int k = lookupBinOp(token);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -