private void atWhileStmnt(Stmnt st, boolean notDo) throws CompileError { ArrayList prevBreakList = breakList; ArrayList prevContList = continueList; breakList = new ArrayList(); continueList = new ArrayList(); ASTree expr = st.head(); Stmnt body = (Stmnt) st.tail(); int pc = 0; if (notDo) { bytecode.addOpcode(Opcode.GOTO); pc = bytecode.currentPc(); bytecode.addIndex(0); } int pc2 = bytecode.currentPc(); if (body != null) body.accept(this); int pc3 = bytecode.currentPc(); if (notDo) bytecode.write16bit(pc, pc3 - pc + 1); boolean alwaysBranch = compileBooleanExpr(true, expr); if (alwaysBranch) { bytecode.addOpcode(Opcode.GOTO); alwaysBranch = breakList.size() == 0; } bytecode.addIndex(pc2 - bytecode.currentPc() + 1); patchGoto(breakList, bytecode.currentPc()); patchGoto(continueList, pc3); continueList = prevContList; breakList = prevBreakList; hasReturned = alwaysBranch; }
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 boolean doit(Bytecode b, int opcode) { b.addAload(var); b.addOpcode(MONITOREXIT); return false; } }; 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); } if (pc < pc2) { // if the body is not empty 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 boolean needsSuperCall(Stmnt body) throws CompileError { if (body.getOperator() == BLOCK) body = (Stmnt) body.head(); if (body != null && body.getOperator() == EXPR) { ASTree expr = body.head(); if (expr != null && expr instanceof Expr && ((Expr) expr).getOperator() == CALL) { ASTree target = ((Expr) expr).head(); if (target instanceof Keyword) { int token = ((Keyword) target).get(); return token != THIS && token != SUPER; } } } return 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; }
private void atIfStmnt(Stmnt st) throws CompileError { ASTree expr = st.head(); Stmnt thenp = (Stmnt) st.tail().head(); Stmnt elsep = (Stmnt) st.tail().tail().head(); if (compileBooleanExpr(false, expr)) { hasReturned = false; if (elsep != null) elsep.accept(this); return; } int pc = bytecode.currentPc(); int pc2 = 0; bytecode.addIndex(0); // correct later hasReturned = false; if (thenp != null) thenp.accept(this); boolean thenHasReturned = hasReturned; hasReturned = false; if (elsep != null && !thenHasReturned) { bytecode.addOpcode(Opcode.GOTO); pc2 = bytecode.currentPc(); bytecode.addIndex(0); } bytecode.write16bit(pc, bytecode.currentPc() - pc + 1); if (elsep != null) { elsep.accept(this); if (!thenHasReturned) bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1); hasReturned = thenHasReturned && hasReturned; } }
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); }
/** @param isCons true if super() must be called. false if the method is a class initializer. */ public void atMethodBody(Stmnt s, boolean isCons, boolean isVoid) throws CompileError { if (s == null) return; if (isCons && needsSuperCall(s)) insertDefaultSuperCall(); hasReturned = false; s.accept(this); if (!hasReturned) if (isVoid) { bytecode.addOpcode(Opcode.RETURN); hasReturned = true; } else throw new CompileError("no return statement"); }
public void atStmnt(Stmnt st) throws CompileError { if (st == null) return; // empty 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)) { Expr e = (Expr) expr; atPlusPlus(e.getOperator(), e.oprand1(), e, false); } else { expr.accept(this); if (is2word(exprType, arrayDim)) bytecode.addOpcode(POP2); else if (exprType != VOID) bytecode.addOpcode(POP); } } else if (op == DECL || op == BLOCK) { ASTList list = st; while (list != null) { ASTree h = list.head(); list = list.tail(); if (h != null) h.accept(this); } } else if (op == IF) atIfStmnt(st); else if (op == WHILE || op == DO) atWhileStmnt(st, op == WHILE); else if (op == FOR) atForStmnt(st); else if (op == BREAK || op == CONTINUE) atBreakStmnt(st, op == BREAK); else if (op == TokenId.RETURN) atReturnStmnt(st); else if (op == THROW) atThrowStmnt(st); else if (op == TRY) atTryStmnt(st); else if (op == SWITCH) atSwitchStmnt(st); else if (op == SYNCHRONIZED) atSyncStmnt(st); else { // LABEL, SWITCH label stament might be null?. hasReturned = false; throw new CompileError("sorry, not supported statement: TokenId " + op); } }
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 void atForStmnt(Stmnt st) throws CompileError { ArrayList prevBreakList = breakList; ArrayList prevContList = continueList; breakList = new ArrayList(); continueList = new ArrayList(); Stmnt init = (Stmnt) st.head(); ASTList p = st.tail(); ASTree expr = p.head(); p = p.tail(); Stmnt update = (Stmnt) p.head(); Stmnt body = (Stmnt) p.tail(); if (init != null) init.accept(this); int pc = bytecode.currentPc(); int pc2 = 0; if (expr != null) { if (compileBooleanExpr(false, expr)) { // in case of "for (...; false; ...)" continueList = prevContList; breakList = prevBreakList; hasReturned = false; return; } pc2 = bytecode.currentPc(); bytecode.addIndex(0); } if (body != null) body.accept(this); 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; }
protected void atReturnStmnt(Stmnt st) throws CompileError { atReturnStmnt2(st.getLeft()); }