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 static CtMethod delegator0(CtMethod delegate, CtClass declaring) throws CannotCompileException, NotFoundException { MethodInfo deleInfo = delegate.getMethodInfo2(); String methodName = deleInfo.getName(); String desc = deleInfo.getDescriptor(); ConstPool cp = declaring.getClassFile2().getConstPool(); MethodInfo minfo = new MethodInfo(cp, methodName, desc); minfo.setAccessFlags(deleInfo.getAccessFlags()); ExceptionsAttribute eattr = deleInfo.getExceptionsAttribute(); if (eattr != null) minfo.setExceptionsAttribute((ExceptionsAttribute) eattr.copy(cp, null)); Bytecode code = new Bytecode(cp, 0, 0); boolean isStatic = Modifier.isStatic(delegate.getModifiers()); CtClass deleClass = delegate.getDeclaringClass(); CtClass[] params = delegate.getParameterTypes(); int s; if (isStatic) { s = code.addLoadParameters(params, 0); code.addInvokestatic(deleClass, methodName, desc); } else { code.addLoad(0, deleClass); s = code.addLoadParameters(params, 1); code.addInvokespecial(deleClass, methodName, desc); } code.addReturn(delegate.getReturnType()); code.setMaxLocals(++s); code.setMaxStack(s < 2 ? 2 : s); // for a 2-word return value minfo.setCodeAttribute(code.toCodeAttribute()); return new CtMethod(minfo, declaring); }
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 } }
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(); } }
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; }
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); }
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()); } }
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; } }
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 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)); }
/* 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; }
/** * Creates a public setter method. The setter method assigns the value of the first parameter to * the specified field in the class to which this method is added. The created method is not * static even if the field is static. You may not change it to be static by <code>setModifiers() * </code> in <code>CtBehavior</code>. * * @param methodName the name of the setter * @param field the field accessed. */ public static CtMethod setter(String methodName, CtField field) throws CannotCompileException { FieldInfo finfo = field.getFieldInfo2(); String fieldType = finfo.getDescriptor(); String desc = "(" + fieldType + ")V"; ConstPool cp = finfo.getConstPool(); MethodInfo minfo = new MethodInfo(cp, methodName, desc); minfo.setAccessFlags(AccessFlag.PUBLIC); Bytecode code = new Bytecode(cp, 3, 3); try { String fieldName = finfo.getName(); if ((finfo.getAccessFlags() & AccessFlag.STATIC) == 0) { code.addAload(0); code.addLoad(1, field.getType()); code.addPutfield(Bytecode.THIS, fieldName, fieldType); } else { code.addLoad(1, field.getType()); code.addPutstatic(Bytecode.THIS, fieldName, fieldType); } code.addReturn(null); } catch (NotFoundException e) { throw new CannotCompileException(e); } minfo.setCodeAttribute(code.toCodeAttribute()); return new CtMethod(minfo, field.getDeclaringClass()); }
protected void patchGoto(ArrayList list, int targetPc) { int n = list.size(); for (int i = 0; i < n; ++i) { int pc = ((Integer) list.get(i)).intValue(); bytecode.write16bit(pc, targetPc - pc + 1); } }
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; }
public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError { String cname = resolveClassName(expr.getClassName()); String toClass = checkCastExpr(expr, cname); bytecode.addInstanceof(toClass); exprType = BOOLEAN; arrayDim = 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; }
@Override public void visitEnd() { for (Map.Entry<Handle, Handle> entry : lambdaAccessToImplMethods.entrySet()) { Handle accessMethod = entry.getKey(); Handle implMethod = entry.getValue(); Bytecode.generateDelegateMethod(cv, ACC_STATIC | ACC_SYNTHETIC, accessMethod, implMethod); } super.visitEnd(); }
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); }
public void atCastExpr(CastExpr expr) throws CompileError { String cname = resolveClassName(expr.getClassName()); String toClass = checkCastExpr(expr, cname); int srcType = exprType; exprType = expr.getType(); arrayDim = expr.getArrayDim(); className = cname; if (toClass == null) atNumCastExpr(srcType, exprType); // built-in type else bytecode.addCheckcast(toClass); }
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; }
/** * Gets the method bridged to by a {@linkplain ResolvedJavaMethod#isBridge() bridge} method. The * value returned is the method called by {@code method} that has the same name as {@code bridge}. * * @param bridge a bridge method * @return the method called by {@code bridge} whose name is the same as {@code bridge.getName()} */ public static ResolvedJavaMethod getBridgedMethod(ResolvedJavaMethod bridge) { assert bridge.isBridge(); Bytecode code = new ResolvedJavaMethodBytecode(bridge); BytecodeStream stream = new BytecodeStream(code.getCode()); int opcode = stream.currentBC(); ResolvedJavaMethod bridged = null; while (opcode != Bytecodes.END) { switch (opcode) { case INVOKEVIRTUAL: case INVOKESPECIAL: case INVOKESTATIC: case INVOKEINTERFACE: { int cpi = stream.readCPI(); ConstantPool cp = code.getConstantPool(); cp.loadReferencedType(cpi, opcode); ResolvedJavaMethod method = (ResolvedJavaMethod) cp.lookupMethod(cpi, opcode); if (method.getName().equals(bridge.getName())) { if (!assertionsEnabled()) { return method; } assert bridged == null || bridged.equals(method) : String.format( "Found calls to different methods named %s in bridge method %s%n callee 1: %s%n callee 2: %s", bridge.getName(), bridge.format("%R %H.%n(%P)"), bridged.format("%R %H.%n(%P)"), method.format("%R %H.%n(%P)")); bridged = method; } break; } } stream.next(); opcode = stream.currentBC(); } if (bridged == null) { throw new InternalError("Couldn't find method bridged by " + bridge.format("%R %H.%n(%P)")); } return bridged; }
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); }
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; }
@Override public String toString() { String s = head.toString(); if (s.length() > 100) s = s.substring(0, 100) + "..."; if (tail != null) // se il bytecode contiene la stringa vuota, non stampiamo un newline. // Utile per il bytecode che scompare dal print-out. if (s.length() > 0) return s + "\n" + tail.toString(); else return tail.toString(); else return s; }
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; } }
/** * Replace a method body with a new method body wrapping the given method. * * @param mbody the wrapped method * @param constParam the constant parameter given to the wrapped method (maybe <code>null</code>). * @see * CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass) */ public void setWrappedBody(CtMethod mbody, ConstParameter constParam) throws CannotCompileException { declaringClass.checkModify(); CtClass clazz = getDeclaringClass(); CtClass[] params; CtClass retType; try { params = getParameterTypes(); retType = getReturnType(); } catch (NotFoundException e) { throw new CannotCompileException(e); } Bytecode code = CtNewWrappedMethod.makeBody( clazz, clazz.getClassFile2(), mbody, params, retType, constParam); CodeAttribute cattr = code.toCodeAttribute(); methodInfo.setCodeAttribute(cattr); methodInfo.setAccessFlags(methodInfo.getAccessFlags() & ~AccessFlag.ABSTRACT); // rebuilding a stack map table is not needed. }
/** @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); } }
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); }
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; }