Beispiel #1
0
  public void atBinExpr(BinExpr expr) throws CompileError {
    int token = expr.getOperator();

    /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
     */
    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;
      right.accept(this);
      if (dim1 != arrayDim) throw new CompileError("incompatible array types");

      if (token == '+' && dim1 == 0 && (type1 == CLASS || exprType == CLASS))
        atStringConcatExpr(expr, type1, dim1, cname1);
      else atArithBinExpr(expr, token, k, type1);
    } else {
      /* equation: &&, ||, ==, !=, <=, >=, <, >
       */
      if (!booleanExpr(true, expr)) {
        bytecode.addIndex(7);
        bytecode.addIconst(0); // false
        bytecode.addOpcode(Opcode.GOTO);
        bytecode.addIndex(4);
      }

      bytecode.addIconst(1); // true
    }
  }
Beispiel #2
0
  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;
  }
Beispiel #3
0
  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;
    }
  }
Beispiel #4
0
  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 == '!') {
      if (!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();
    }
  }
Beispiel #5
0
  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);
  }
Beispiel #6
0
  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;
  }
Beispiel #7
0
  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);
  }
Beispiel #8
0
  /* Produces the opcode to branch if the condition is true.
   * The oprand (branch offset) is not produced.
   *
   * @return	true if the compiled code is GOTO (always branch).
   * 			GOTO is not produced.
   */
  private boolean booleanExpr(boolean branchIf, ASTree expr) throws CompileError {
    boolean isAndAnd;
    int op = getCompOperator(expr);
    if (op == EQ) { // ==, !=, ...
      BinExpr bexpr = (BinExpr) expr;
      int type1 = compileOprands(bexpr);
      // here, arrayDim might represent the array dim. of the left oprand
      // if the right oprand is NULL.
      compareExpr(branchIf, bexpr.getOperator(), type1, bexpr);
    } else if (op == '!') return booleanExpr(!branchIf, ((Expr) expr).oprand1());
    else if ((isAndAnd = (op == ANDAND)) || op == OROR) {
      BinExpr bexpr = (BinExpr) expr;
      if (booleanExpr(!isAndAnd, bexpr.oprand1())) {
        exprType = BOOLEAN;
        arrayDim = 0;
        return true;
      } else {
        int pc = bytecode.currentPc();
        bytecode.addIndex(0); // correct later
        if (booleanExpr(isAndAnd, bexpr.oprand2())) bytecode.addOpcode(Opcode.GOTO);

        bytecode.write16bit(pc, bytecode.currentPc() - pc + 3);
        if (branchIf != isAndAnd) {
          bytecode.addIndex(6); // skip GOTO instruction
          bytecode.addOpcode(Opcode.GOTO);
        }
      }
    } else if (isAlwaysBranch(expr, branchIf)) {
      // Opcode.GOTO is not added here.  The caller must add it.
      exprType = BOOLEAN;
      arrayDim = 0;
      return true; // always branch
    } else { // others
      expr.accept(this);
      if (exprType != BOOLEAN || arrayDim != 0) throw new CompileError("boolean expr is required");

      bytecode.addOpcode(branchIf ? IFNE : IFEQ);
    }

    exprType = BOOLEAN;
    arrayDim = 0;
    return false;
  }
Beispiel #9
0
  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");
  }
Beispiel #10
0
  /* MemberCodeGen overrides this method.
   */
  protected void atClassObject2(String cname) throws CompileError {
    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);
  }
Beispiel #11
0
  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);

        int delta = token == PLUSPLUS ? 1 : -1;
        if (var > 0xff) {
          bytecode.addOpcode(WIDE);
          bytecode.addOpcode(IINC);
          bytecode.addIndex(var);
          bytecode.addIndex(delta);
        } else {
          bytecode.addOpcode(IINC);
          bytecode.add(var);
          bytecode.add(delta);
        }

        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);
    }
  }