示例#1
0
  private void atStringConcatExpr(Expr expr, int type1, int dim1, String cname1)
      throws CompileError {
    int type2 = exprType;
    int dim2 = arrayDim;
    boolean type2Is2 = is2word(type2, dim2);
    boolean type2IsString = (type2 == CLASS && jvmJavaLangString.equals(className));

    if (type2Is2) convToString(type2, dim2);

    if (is2word(type1, dim1)) {
      bytecode.addOpcode(DUP_X2);
      bytecode.addOpcode(POP);
    } else bytecode.addOpcode(SWAP);

    // even if type1 is String, the left operand might be null.
    convToString(type1, dim1);
    bytecode.addOpcode(SWAP);

    if (!type2Is2 && !type2IsString) convToString(type2, dim2);

    bytecode.addInvokevirtual(javaLangString, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
    exprType = CLASS;
    arrayDim = 0;
    className = jvmJavaLangString;
  }
示例#2
0
  /* 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;
  }
示例#3
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;
  }
示例#4
0
  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));
  }
示例#5
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");
  }
示例#6
0
  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();
    }
  }
示例#7
0
  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)
      if (har.doit(bytecode, op)) {
        hasReturned = true;
        return;
      }

    bytecode.addOpcode(op);
    hasReturned = true;
  }
示例#8
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
    }
  }
示例#9
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;
    }
  }
示例#10
0
  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;
  }
示例#11
0
  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;
  }
示例#12
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);
  }
示例#13
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();
    }
  }
示例#14
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;
  }
    public static void rewriteFakeMethod(CodeIterator methodBody, String methodDescriptor) {
      String ret = DescriptorUtils.getReturnType(methodDescriptor);
      // if the return type is larger than one then it is not a primitive
      // so it does not need to be boxed
      if (ret.length() != 1) {
        return;
      }
      byte ar = (byte) Opcode.ARETURN;
      byte[] areturn = {ar};
      // void methods are special
      if (ret.equals("V")) {

        while (methodBody.hasNext()) {
          try {
            int index = methodBody.next();
            int opcode = methodBody.byteAt(index);
            // replace a RETURN opcode with
            // ACONST_NULL
            // ARETURN
            // to return a null value
            if (opcode == Opcode.RETURN) {
              Bytecode code = new Bytecode(methodBody.get().getConstPool());
              code.add(Opcode.ACONST_NULL);
              code.add(Opcode.ARETURN);
              methodBody.insertAt(index, code.get());
            }
          } catch (BadBytecode e) {
            throw new RuntimeException(e);
          }
        }
      } else {
        while (methodBody.hasNext()) {
          try {
            int index = methodBody.next();
            int opcode = methodBody.byteAt(index);

            switch (opcode) {
              case Opcode.IRETURN:
              case Opcode.LRETURN:
              case Opcode.DRETURN:
              case Opcode.FRETURN:
                // write a NOP over the old return instruction
                // insert the boxing code to get an object on the stack
                Bytecode b = new Bytecode(methodBody.get().getConstPool());
                Boxing.box(b, ret.charAt(0));
                b.addOpcode(Opcode.ARETURN);
                methodBody.insertAt(index, b.get());
            }
          } catch (BadBytecode e) {
            throw new RuntimeException(e);
          }
        }
      }
    }
示例#16
0
  void atNumCastExpr(int srcType, int destType) throws CompileError {
    if (srcType == destType) return;

    int op, op2;
    int stype = typePrecedence(srcType);
    int dtype = typePrecedence(destType);
    if (0 <= stype && stype < 3) op = castOp[stype * 4 + dtype];
    else op = NOP;

    if (destType == DOUBLE) op2 = I2D;
    else if (destType == FLOAT) op2 = I2F;
    else if (destType == LONG) op2 = I2L;
    else if (destType == SHORT) op2 = I2S;
    else if (destType == CHAR) op2 = I2C;
    else if (destType == BYTE) op2 = I2B;
    else op2 = NOP;

    if (op != NOP) bytecode.addOpcode(op);

    if (op == NOP || op == L2I || op == F2I || op == D2I) if (op2 != NOP) bytecode.addOpcode(op2);
  }
示例#17
0
  /** @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");
  }
示例#18
0
  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);
    }
  }
示例#19
0
  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;
  }
示例#20
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);
  }
示例#21
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);
  }
示例#22
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;
  }
示例#23
0
  /* Produces the opcode to branch if the condition is true.
   * The oprands are not produced.
   *
   * Parameter expr - compare expression ==, !=, <=, >=, <, >
   */
  private void compareExpr(boolean branchIf, int token, int type1, BinExpr expr)
      throws CompileError {
    if (arrayDim == 0) convertOprandTypes(type1, exprType, expr);

    int p = typePrecedence(exprType);
    if (p == P_OTHER || arrayDim > 0)
      if (token == EQ) bytecode.addOpcode(branchIf ? IF_ACMPEQ : IF_ACMPNE);
      else if (token == NEQ) bytecode.addOpcode(branchIf ? IF_ACMPNE : IF_ACMPEQ);
      else badTypes(expr);
    else if (p == P_INT) {
      int op[] = ifOp;
      for (int i = 0; i < op.length; i += 3)
        if (op[i] == token) {
          bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]);
          return;
        }

      badTypes(expr);
    } else {
      if (p == P_DOUBLE)
        if (token == '<' || token == LE) bytecode.addOpcode(DCMPG);
        else bytecode.addOpcode(DCMPL);
      else if (p == P_FLOAT)
        if (token == '<' || token == LE) bytecode.addOpcode(FCMPG);
        else bytecode.addOpcode(FCMPL);
      else if (p == P_LONG) bytecode.addOpcode(LCMP); // 1: >, 0: =, -1: <
      else fatal();

      int[] op = ifOp2;
      for (int i = 0; i < op.length; i += 3)
        if (op[i] == token) {
          bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]);
          return;
        }

      badTypes(expr);
    }
  }
示例#24
0
  /* arrayDim values of the two oprands must be equal.
   * If an oprand type is not a numeric type, this method
   * throws an exception.
   */
  private void atArithBinExpr(Expr expr, int token, int index, int type1) throws CompileError {
    if (arrayDim != 0) badTypes(expr);

    int type2 = exprType;
    if (token == LSHIFT || token == RSHIFT || token == ARSHIFT)
      if (type2 == INT || type2 == SHORT || type2 == CHAR || type2 == BYTE) exprType = type1;
      else badTypes(expr);
    else convertOprandTypes(type1, type2, expr);

    int p = typePrecedence(exprType);
    if (p >= 0) {
      int op = binOp[index + p + 1];
      if (op != NOP) {
        if (p == P_INT && exprType != BOOLEAN) exprType = INT; // type1 may be BYTE, ...

        bytecode.addOpcode(op);
        return;
      }
    }

    badTypes(expr);
  }
示例#25
0
  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);
  }
  /**
   * Calls methodHandler.invoke with a null method parameter in order to get the underlying
   * instance. The invocation is then forwarded to this instance with generated bytecode.
   */
  protected Bytecode createForwardingMethodBody(ClassFile file, MethodInformation methodInfo)
      throws NotFoundException {
    Method method = methodInfo.getMethod();
    // we can only use bytecode based invocation for some methods
    // at the moment we restrict it solely to public methods with public
    // return and parameter types
    boolean bytecodeInvocationAllowed =
        Modifier.isPublic(method.getModifiers())
            && Modifier.isPublic(method.getReturnType().getModifiers());
    for (Class<?> paramType : method.getParameterTypes()) {
      if (!Modifier.isPublic(paramType.getModifiers())) {
        bytecodeInvocationAllowed = false;
        break;
      }
    }
    if (!bytecodeInvocationAllowed) {
      return createInterceptorBody(file, methodInfo);
    }
    Bytecode b = new Bytecode(file.getConstPool());
    int localCount = MethodUtils.calculateMaxLocals(method) + 1;

    // create a new interceptor invocation context whenever we invoke a method on a client proxy
    // we use a try-catch block in order to make sure that endInterceptorContext() is invoked
    // regardless whether
    // the method has succeeded or not
    int start = b.currentPc();
    b.addInvokestatic(
        "org.jboss.weld.bean.proxy.InterceptionDecorationContext",
        "startInterceptorContext",
        "()V");

    b.add(Opcode.ALOAD_0);
    b.addGetfield(
        file.getName(),
        "methodHandler",
        DescriptorUtils.classToStringRepresentation(MethodHandler.class));
    // pass null arguments to methodHandler.invoke
    b.add(Opcode.ALOAD_0);
    b.add(Opcode.ACONST_NULL);
    b.add(Opcode.ACONST_NULL);
    b.add(Opcode.ACONST_NULL);

    // now we have all our arguments on the stack
    // lets invoke the method
    b.addInvokeinterface(
        MethodHandler.class.getName(),
        "invoke",
        "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;",
        5);

    b.addCheckcast(methodInfo.getDeclaringClass());

    // now we should have the target bean instance on top of the stack
    // we need to dup it so we still have it to compare to the return value
    b.add(Opcode.DUP);

    // lets create the method invocation
    String methodDescriptor = methodInfo.getDescriptor();
    BytecodeUtils.loadParameters(b, methodDescriptor);
    if (method.getDeclaringClass().isInterface()) {
      b.addInvokeinterface(
          methodInfo.getDeclaringClass(),
          methodInfo.getName(),
          methodDescriptor,
          method.getParameterTypes().length + 1);
    } else {
      b.addInvokevirtual(methodInfo.getDeclaringClass(), methodInfo.getName(), methodDescriptor);
    }

    // end the interceptor context, everything was fine
    b.addInvokestatic(
        "org.jboss.weld.bean.proxy.InterceptionDecorationContext", "endInterceptorContext", "()V");

    // jump over the catch block
    b.addOpcode(Opcode.GOTO);
    JumpMarker gotoEnd = JumpUtils.addJumpInstruction(b);

    // create catch block
    b.addExceptionHandler(start, b.currentPc(), b.currentPc(), 0);
    b.addInvokestatic(
        "org.jboss.weld.bean.proxy.InterceptionDecorationContext", "endInterceptorContext", "()V");
    b.add(Opcode.ATHROW);

    // update the correct address to jump over the catch block
    gotoEnd.mark();

    // if this method returns a primitive we just return
    if (method.getReturnType().isPrimitive()) {
      BytecodeUtils.addReturnInstruction(b, methodInfo.getReturnType());
    } else {
      // otherwise we have to check that the proxy is not returning 'this;
      // now we need to check if the proxy has return 'this' and if so return
      // an
      // instance of the proxy.
      // currently we have result, beanInstance on the stack.
      b.add(Opcode.DUP_X1);
      // now we have result, beanInstance, result
      // we need to compare result and beanInstance

      // first we need to build up the inner conditional that just returns
      // the
      // result
      b.add(Opcode.IF_ACMPEQ);
      JumpMarker returnInstruction = JumpUtils.addJumpInstruction(b);
      BytecodeUtils.addReturnInstruction(b, methodInfo.getReturnType());
      returnInstruction.mark();

      // now add the case where the proxy returns 'this';
      b.add(Opcode.ALOAD_0);
      b.addCheckcast(methodInfo.getMethod().getReturnType().getName());
      BytecodeUtils.addReturnInstruction(b, methodInfo.getReturnType());
    }
    if (b.getMaxLocals() < localCount) {
      b.setMaxLocals(localCount);
    }
    return b;
  }
示例#27
0
  /* do implicit type conversion.
   * arrayDim values of the two oprands must be zero.
   */
  private void convertOprandTypes(int type1, int type2, Expr expr) throws CompileError {
    boolean rightStrong;
    int type1_p = typePrecedence(type1);
    int type2_p = typePrecedence(type2);

    if (type2_p < 0 && type1_p < 0) // not primitive types
    return;

    if (type2_p < 0 || type1_p < 0) // either is not a primitive type
    badTypes(expr);

    int op, result_type;
    if (type1_p <= type2_p) {
      rightStrong = false;
      exprType = type1;
      op = castOp[type2_p * 4 + type1_p];
      result_type = type1_p;
    } else {
      rightStrong = true;
      op = castOp[type1_p * 4 + type2_p];
      result_type = type2_p;
    }

    if (rightStrong) {
      if (result_type == P_DOUBLE || result_type == P_LONG) {
        if (type1_p == P_DOUBLE || type1_p == P_LONG) bytecode.addOpcode(DUP2_X2);
        else bytecode.addOpcode(DUP2_X1);

        bytecode.addOpcode(POP2);
        bytecode.addOpcode(op);
        bytecode.addOpcode(DUP2_X2);
        bytecode.addOpcode(POP2);
      } else if (result_type == P_FLOAT) {
        if (type1_p == P_LONG) {
          bytecode.addOpcode(DUP_X2);
          bytecode.addOpcode(POP);
        } else bytecode.addOpcode(SWAP);

        bytecode.addOpcode(op);
        bytecode.addOpcode(SWAP);
      } else fatal();
    } else if (op != NOP) bytecode.addOpcode(op);
  }
示例#28
0
 public void atArrayRead(ASTree array, ASTree index) throws CompileError {
   arrayAccess(array, index);
   bytecode.addOpcode(getArrayReadOp(exprType, arrayDim));
 }
示例#29
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);
    }
  }