List of usage examples for org.objectweb.asm Opcodes IFEQ
int IFEQ
To view the source code for org.objectweb.asm Opcodes IFEQ.
Click Source Link
From source file:org.jboss.byteman.rule.expression.LogicalExpression.java
License:Open Source License
public void compile(MethodVisitor mv, CompileContext compileContext) throws CompileException { // make sure we are at the right source line compileContext.notifySourceLine(line); Expression oper0 = getOperand(0); Expression oper1 = getOperand(1); int currentStack = compileContext.getStackCount(); // compile the first expression and make sure it is a boolean -- adds 1 to stack height oper0.compile(mv, compileContext);/*from w w w. ja v a2s.c o m*/ if (oper0.getType() == Type.BOOLEAN) { compileBooleanConversion(Type.BOOLEAN, type.Z, mv, compileContext); } // plant a test and branch Label nextLabel = new Label(); Label endLabel = new Label(); if (oper == AND) { // only try next if we got true here mv.visitJumpInsn(Opcodes.IFNE, nextLabel); // ok, the first branch was false so stack a false for the result and skip to the end mv.visitLdcInsn(false); mv.visitJumpInsn(Opcodes.GOTO, endLabel); } else { // only try next if we got false here mv.visitJumpInsn(Opcodes.IFEQ, nextLabel); // ok, the first branch was true so stack a true for the result and skip to the end mv.visitLdcInsn(true); mv.visitJumpInsn(Opcodes.GOTO, endLabel); } // in either case if we get here the if test removed 1 from the stack compileContext.addStackCount(-1); // the else branch -- adds 1 to stack height mv.visitLabel(nextLabel); oper1.compile(mv, compileContext); if (oper0.getType() == Type.BOOLEAN) { compileBooleanConversion(Type.BOOLEAN, type.Z, mv, compileContext); } // the final result is the result of the second oper which is on the stack already // This is the end, my beau-tiful friend mv.visitLabel(endLabel); // in either case if we get here we should have one extra value on the stack // check stack height if (compileContext.getStackCount() != currentStack + 1) { throw new CompileException("LogicalExpression.compile : invalid stack height " + compileContext.getStackCount() + " expecting " + (currentStack + 1)); } }
From source file:org.jtsan.InstrumentCalls.java
License:Apache License
private void genTryCatchBlock(MethodMapping.HandlerInfo target, Label startExceptionRegion, Label endExceptionRegion) { Label startCatchRegion = new Label(); Label labelSkip = new Label(); Label labelAfter = new Label(); boolean isStatic = (opcode == Opcodes.INVOKESTATIC); gen.visitJumpInsn(Opcodes.GOTO, labelAfter); gen.visitLabel(startCatchRegion);//from w w w. j a v a2 s .c o m // TODO(vors): Handle static method exceptions incorrectly: we don't check class if (!isStatic) { // Skip the event if 'this' is not a child of the base class. saverThis.loadStack(); gen.instanceOf(Type.getObjectType(target.getWatchedClass())); gen.visitJumpInsn(Opcodes.IFEQ, labelSkip); } // Restore stack to invoke exception handler. // dup() exception object. gen.dup(); if (!isStatic) { saverThis.loadStack(); gen.swap(); } gen.push(cb.codePosition()); cb.listenerCall(target.getHandler(), (isStatic ? "(" : ("(L" + target.getWatchedClass()) + ";") + "Ljava/lang/Throwable;J)V"); gen.visitLabel(labelSkip); // throw exception object to next handler in exception table. gen.throwException(); gen.visitLabel(labelAfter); // Mark try catch region with highest priority to all Exceptions. cb.topVisitTryCatchBlock(startExceptionRegion, endExceptionRegion, startCatchRegion, "java/lang/Throwable"); }
From source file:org.jtsan.InstrumentCalls.java
License:Apache License
private void genListenerCalls(List<MethodMapping.HandlerInfo> targets, boolean saveRet) { boolean returns = false; if (saveRet && saver.hasReturnValue()) { returns = true;/* w w w. j a v a2 s .c om*/ } if (returns) { saver.saveReturnValue(); } for (MethodMapping.HandlerInfo target : targets) { Label labelSkip = new Label(); Label labelAfter = new Label(); boolean exact = target.isExact(); boolean callGenerated = false; boolean listenStatic = (opcode == Opcodes.INVOKESTATIC); if (!listenStatic) { saverThis.loadStack(); } // Shape the listener method's descriptor. String tailReplacement = "J)V"; int idx = desc.indexOf(")"); if (returns) { String retType = desc.substring(idx + 1, desc.length()); tailReplacement = retType + tailReplacement; } String actualDesc = desc.substring(0, idx) + tailReplacement; if (!listenStatic) { actualDesc = addClassAsFirstArgument(target.getWatchedClass(), actualDesc); } // Insert type match checking and the listener call. if (!exact && !listenStatic) { // Skip the event if 'this' is not a child of the base class. gen.dup(); gen.instanceOf(Type.getObjectType(target.getWatchedClass())); gen.visitJumpInsn(Opcodes.IFEQ, labelSkip); gen.checkCast(Type.getObjectType(target.getWatchedClass())); } if (!exact || target.getWatchedClass().equals(owner)) { saver.loadStack(); if (returns) { saver.loadReturnValue(); } gen.push(cb.codePosition()); cb.listenerCall(target.getHandler(), actualDesc); callGenerated = true; } if (callGenerated && !listenStatic) { gen.visitJumpInsn(Opcodes.GOTO, labelAfter); gen.visitLabel(labelSkip); gen.pop(); gen.visitLabel(labelAfter); } } if (returns) { saver.loadReturnValue(); } }
From source file:org.kantega.dogmaticmvc.mutation.MutationMethodVisitor.java
License:Apache License
private int getMutatedJumpInsn(int i) { switch (i) {//from ww w . j ava2 s. c o m case Opcodes.IFEQ: return Opcodes.IFNE; case Opcodes.IFNE: return Opcodes.IFEQ; case Opcodes.IFLT: return Opcodes.IFGE; case Opcodes.IFGE: return Opcodes.IFLT; case Opcodes.IFGT: return Opcodes.IFLE; case Opcodes.IFLE: return Opcodes.IFGT; case Opcodes.IF_ICMPEQ: return Opcodes.IF_ICMPNE; case Opcodes.IF_ICMPNE: return Opcodes.IF_ICMPEQ; case Opcodes.IF_ICMPLT: return Opcodes.IF_ICMPGE; case Opcodes.IF_ICMPGE: return Opcodes.IF_ICMPLT; case Opcodes.IF_ICMPGT: return Opcodes.IF_ICMPLE; case Opcodes.IF_ICMPLE: return Opcodes.IF_ICMPGT; case Opcodes.IF_ACMPEQ: return Opcodes.IF_ACMPNE; case Opcodes.IF_ACMPNE: return Opcodes.IF_ACMPEQ; case Opcodes.IFNULL: return Opcodes.IFNONNULL; case Opcodes.IFNONNULL: return Opcodes.IFNULL; default: return i; } }
From source file:org.lambdamatic.analyzer.ast.LambdaExpressionReader.java
License:Open Source License
/** * Extracts the comparison {@link CompoundExpressionOperator} from the given {@link JumpInsnNode}. * /* ww w . j a v a2s.com*/ * @param currentInstruction the comparison instruction * @return the corresponding {@link CompoundExpressionOperator} */ private static CompoundExpressionOperator extractComparisonOperator(final AbstractInsnNode currentInstruction) { switch (currentInstruction.getOpcode()) { case Opcodes.IF_ACMPNE: case Opcodes.IF_ICMPNE: case Opcodes.IFNE: return CompoundExpressionOperator.NOT_EQUALS; case Opcodes.IF_ACMPEQ: case Opcodes.IF_ICMPEQ: case Opcodes.IFEQ: return CompoundExpressionOperator.EQUALS; case Opcodes.IF_ICMPLE: case Opcodes.IFLE: return CompoundExpressionOperator.LESS_EQUALS; case Opcodes.IF_ICMPLT: case Opcodes.IFLT: return CompoundExpressionOperator.LESS; case Opcodes.IF_ICMPGE: case Opcodes.IFGE: return CompoundExpressionOperator.GREATER_EQUALS; case Opcodes.IF_ICMPGT: case Opcodes.IFGT: return CompoundExpressionOperator.GREATER; default: throw new AnalyzeException( "Failed to retrieve the operator for the current comparison instruction (opcode: " + currentInstruction.getOpcode() + ")"); } }
From source file:org.lambdamatic.analyzer.ast.LambdaExpressionReader.java
License:Open Source License
/** * The {@link AbstractInsnNode#getOpcode()} value should be one of {@code IFEQ}, {@code IFNE}, * {@code IFLT}, {@code IFGE}, {@code IFGT}, {@code IFLE}, {@code IFLT}, {@code IFGE}, * {@code IFGT},{@code IF_ICMPEQ}, {@code IF_ICMPNE}, {@code IF_ICMPLT}, {@code IF_ICMPGE}, * {@code IF_ICMPGT}, {@code IF_ICMPLE}, {@code IF_ACMPEQ}, {@code IF_ACMPNE}, {@code GOTO}, * {@code JSR}, {@code IFNULL} or {@code IFNONNULL}. * /*from w w w.jav a2s .co m*/ * * @param instructionCursor the cursor for the current instruction to read * @param expressionStack the stack of Expressions * @param capturedArguments the captured arguments * @param localVariables the local variables * @return the list of statements read from the jump instruction */ private List<Statement> readJumpInstruction(final InsnCursor instructionCursor, final Stack<Expression> expressionStack, final List<CapturedArgument> capturedArguments, final LocalVariables localVariables) { final JumpInsnNode jumpInsnNode = (JumpInsnNode) instructionCursor.getCurrent(); final LabelNode jumpLabel = jumpInsnNode.label; // FIXME: add support for LCMP: // Takes two two-word long integers off the stack and compares them. If // the two integers are the same, the int 0 is pushed onto the stack. If // value2 is greater than value1, the int 1 is pushed onto the stack. If // value1 is greater than value2, the int -1 is pushed onto the stack. switch (jumpInsnNode.getOpcode()) { case Opcodes.IFEQ: case Opcodes.IFNE: case Opcodes.IFLE: case Opcodes.IFLT: case Opcodes.IFGE: case Opcodes.IFGT: case Opcodes.IF_ICMPEQ: case Opcodes.IF_ICMPNE: case Opcodes.IF_ICMPLE: case Opcodes.IF_ICMPLT: case Opcodes.IF_ICMPGE: case Opcodes.IF_ICMPGT: case Opcodes.IF_ACMPEQ: case Opcodes.IF_ACMPNE: return Arrays.asList(buildControlFlowStatement(instructionCursor, expressionStack, capturedArguments, localVariables)); case Opcodes.GOTO: final InsnCursor jumpInstructionCursor = instructionCursor.duplicate(); jumpInstructionCursor.move(jumpLabel.getLabel()); return readStatements(jumpInstructionCursor, expressionStack, capturedArguments, localVariables); default: throw new AnalyzeException("Unexpected JumpInsnNode OpCode: " + jumpInsnNode.getOpcode()); } }
From source file:org.lanternpowered.server.event.filter.delegate.ExcludeSubtypeFilterDelegate.java
License:MIT License
@Override public int write(String name, ClassWriter cw, MethodVisitor mv, Method method, int locals) { // TODO could do an optimization here to inline a single instanceof if // the set would contain only a single member mv.visitVarInsn(ALOAD, 0);/*from w ww .j a v a 2s.c om*/ mv.visitFieldInsn(GETFIELD, name, "classes", "Ljava/util/Set;"); // Loop through the classes set's members mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "iterator", "()Ljava/util/Iterator;", true); mv.visitVarInsn(ASTORE, locals); Label continueLabel = new Label(); mv.visitJumpInsn(GOTO, continueLabel); Label loopStart = new Label(); mv.visitLabel(loopStart); mv.visitVarInsn(ALOAD, locals); mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;", true); mv.visitTypeInsn(CHECKCAST, "java/lang/Class"); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "isInstance", "(Ljava/lang/Object;)Z", false); mv.visitJumpInsn(Opcodes.IFEQ, continueLabel); mv.visitInsn(ACONST_NULL); mv.visitInsn(ARETURN); mv.visitLabel(continueLabel); mv.visitVarInsn(ALOAD, locals); mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z", true); mv.visitJumpInsn(IFNE, loopStart); return locals + 1; }
From source file:org.mbte.groovypp.compiler.bytecode.BytecodeExpr.java
License:Apache License
/** * convert boolean to Boolean//w w w. java 2 s. c om * @param mv */ public void boxBoolean(MethodVisitor mv) { Label l0 = new Label(); mv.visitJumpInsn(Opcodes.IFEQ, l0); mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;"); Label l1 = new Label(); mv.visitJumpInsn(Opcodes.GOTO, l1); mv.visitLabel(l0); mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;"); mv.visitLabel(l1); }
From source file:org.openquark.cal.internal.javamodel.AsmJavaBytecodeGenerator.java
License:Open Source License
private static boolean encodeIfThenElseStatement(JavaStatement.IfThenElseStatement iteStatement, GenerationContext context) throws JavaGenerationException { MethodVisitor mv = context.getMethodVisitor(); JavaExpression conditionExpr = iteStatement.getCondition(); JavaStatement thenStatement = iteStatement.getThenStatement(); JavaStatement elseStatement = iteStatement.getElseStatement(); if (conditionExpr instanceof JavaExpression.OperatorExpression) { //generate more efficient code in the case of if (boolean-valued-operator)... //This case exists to handle the special case where an operator occurs as the child of an if-then-else (or ternary operator) //conditional. For example, in the situation: ////from w ww . j av a 2 s. c om //if (x != null) {...} else {...} // // we do not want to evaluate x != null to a boolean value, push that value on the stack, // and then test it prior to selecting the correct branch. Rather, we can combine the evaluation // and jump operations into a single step. JavaExpression.OperatorExpression operatorExpr = (JavaExpression.OperatorExpression) conditionExpr; JavaOperator operator = operatorExpr.getJavaOperator(); if (operator.isLogicalOp() || operator.isRelationalOp()) { Label trueContinuation = new Label(); context.addStatementJumpLabel(trueContinuation); Label falseContinuation = new Label(); context.addStatementJumpLabel(falseContinuation); encodeBooleanValuedOperatorHelper(operatorExpr, context, trueContinuation, falseContinuation); return encodeThenStatementElseStatement(trueContinuation, falseContinuation, thenStatement, elseStatement, context); } throw new JavaGenerationException( "Unrecognized boolean-valued conditional operator " + operator.getSymbol() + "."); } //encode the condition. It will be boolean valued. encodeExpr(iteStatement.getCondition(), context); //if false, jump to falseContinuation Label falseContinuation = new Label(); mv.visitJumpInsn(Opcodes.IFEQ, falseContinuation); return encodeThenStatementElseStatement(null, falseContinuation, thenStatement, elseStatement, context); }
From source file:org.openquark.cal.internal.javamodel.AsmJavaBytecodeGenerator.java
License:Open Source License
/** * Boolean valued operators (!, &&, ||, ==, !=, <, <=, > and >=) are highly optimized during compilation to bytecode. * Here is a quick outline of the optimizations used: * -not (e1 && e2) is compiled as a single notAnd operator * -not (e1 || e2) is compiled as a single notOr operator * -not (not e) is optimized out.//from ww w . ja v a2s.c om * -not (x < y) is compiled as x >= y for integral comparisons. A similar thing is done for not (double <), but it is not quite double >= because * of NaN. However, there is special java bytecode support for treatment of this. * -Comparisons where the right-hand-side is an int 0 are treated more efficiently i.e. x > 0. * -Comparisons to null are treated specially i.e. x != null, x == null. * -if the result of a boolean valued operator is used by the condition part of an if-then-else statement (or ternary operator) then * the resulting true or false value is not pushed onto the stack and then tested. Rather we directly branch to the appropriate * continuation. * -the most complicated optimization is that "trees" of boolean valued operators are effectively compiled as a single operator. * What this means is that the resulting "true" and "false" values are not popped onto the stack and consumed by subsequent operators * but rather a "continuation style" is employed where we just jump to the correct next comparison. * This saves an extra comparison per operator, as well as unecessary pushes of trues and falses compared to the naive compilation scheme. * The precise bytecode instructions used in the compilation schemes varies depending on context (see the endsWithTrueForm argument). * * @param operatorExpr * @param context * @param trueContinuation label to jump to if the expression has a true value * @param falseContinuation label to jump to if the expression has a false value * @param endsWithTrueForm operators are encoded as a series of tests with jumps where if none of the jumps are taken the operator slips * through to the default case. This is usually "true" but if the "endsWithTrueForm" flag is set to false, then the default case will * be false. For example, this is useful when encoding a boolean-valued operator that is the left argument of the || operator. * In that case we want the default case to proceed to evaluation of the second argument of ||. * @throws JavaGenerationException */ private static void encodeBooleanValuedOperatorHelper(JavaExpression.OperatorExpression operatorExpr, GenerationContext context, Label trueContinuation, Label falseContinuation, boolean endsWithTrueForm) throws JavaGenerationException { MethodVisitor mv = context.getMethodVisitor(); JavaOperator operator = operatorExpr.getJavaOperator(); String symbol = operator.getSymbol(); JavaTypeName valueType = operator.getValueType(); if (operator.isLogicalOp()) { // Logical op: {"!", "&&", "||"} // Note: conditional statements should not be handled here.. // eg. "if" conditional evaluation happens during "if" source generation. // We can get here if, eg. printing the result of a conditional. // boolean negation if (symbol.equals("!")) { JavaExpression arg0Expr = operatorExpr.getArgument(0); //attempt to optimize a variety of cases where not is composed with another boolean valued operator. if (arg0Expr instanceof JavaExpression.OperatorExpression) { if (arg0Expr instanceof JavaExpression.OperatorExpression.Binary) { JavaExpression.OperatorExpression.Binary arg0BinaryOperatorExpr = (JavaExpression.OperatorExpression.Binary) arg0Expr; JavaOperator arg0BinaryOperator = arg0BinaryOperatorExpr.getJavaOperator(); //not (expr1 && expr2) is encoded in a special way. Effectively there is a notAnd operator. if (arg0BinaryOperator == JavaOperator.CONDITIONAL_AND) { //x notAnd y //is encoded as //if x == false then goto trueContinuation //if y == true then goto falseContinuation ////what follows is a sample continuation in the case when a literal value is pushed onto the stack //label trueContinuation: //push true //goto next //label falseContinuation: //push false //next: JavaExpression andOpArg0Expr = arg0BinaryOperatorExpr.getArgument(0); if (isBooleanValuedOperatorExpr(andOpArg0Expr)) { Label innerTrueContinuation = new Label(); encodeBooleanValuedOperatorHelper((JavaExpression.OperatorExpression) andOpArg0Expr, context, innerTrueContinuation, trueContinuation); mv.visitLabel(innerTrueContinuation); } else { encodeExpr(andOpArg0Expr, context); mv.visitJumpInsn(Opcodes.IFEQ, trueContinuation); } JavaExpression andOpArg1Expr = arg0BinaryOperatorExpr.getArgument(1); if (isBooleanValuedOperatorExpr(andOpArg1Expr)) { encodeBooleanValuedOperatorHelper((JavaExpression.OperatorExpression) andOpArg1Expr, context, falseContinuation, trueContinuation, !endsWithTrueForm); } else { encodeExpr(andOpArg1Expr, context); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFNE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFEQ, trueContinuation); } } return; } //not (expr1 || expr2) is encoded in a special way. Effectively there is a notOr operator. if (arg0BinaryOperator == JavaOperator.CONDITIONAL_OR) { //x notOr y //is encoded as //if x == true then goto falseContinuation //if y == true then goto falseContinuation ////what follows is a sample continuation in the case when a literal value is pushed onto the stack //label trueContinuation: //push true //goto next //label falseContinuation: //push false //next: JavaExpression orOpArg0Expr = arg0BinaryOperatorExpr.getArgument(0); if (isBooleanValuedOperatorExpr(orOpArg0Expr)) { Label innerFalseContinuation = new Label(); //if x evaluates to false, we want to continue with evaluating y, this is why the "endsWithTrueForm" argument is false here. //if x evaluates to false, then x notOr y returns true without needing to evaluate y. That is why the trueContinuation for x, is //the falseContinuation for the call that encodes x. encodeBooleanValuedOperatorHelper((JavaExpression.OperatorExpression) orOpArg0Expr, context, falseContinuation, innerFalseContinuation, false); mv.visitLabel(innerFalseContinuation); } else { encodeExpr(orOpArg0Expr, context); mv.visitJumpInsn(Opcodes.IFNE, falseContinuation); } JavaExpression orOpArg1Expr = arg0BinaryOperatorExpr.getArgument(1); if (isBooleanValuedOperatorExpr(orOpArg1Expr)) { encodeBooleanValuedOperatorHelper((JavaExpression.OperatorExpression) orOpArg1Expr, context, falseContinuation, trueContinuation, !endsWithTrueForm); } else { encodeExpr(orOpArg1Expr, context); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFNE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFEQ, trueContinuation); } } return; } //try to optimize not composed with a boolean valued operator as a single operation //for example, for int operators, not (x < y) is actually encoded as x >= y. JavaExpression.OperatorExpression.Binary notComposedOperatorExpr = arg0BinaryOperatorExpr .getNotComposedOperatorExpr(); if (notComposedOperatorExpr != null) { encodeBooleanValuedOperatorHelper(notComposedOperatorExpr, context, trueContinuation, falseContinuation, endsWithTrueForm); return; } //not (x Double.< y) is encoded like x Double.>= y except that the opposite DCMP instruction is used. //this is to handle NAN. Similar for the others. if (arg0BinaryOperator == JavaOperator.LESS_THAN_DOUBLE || arg0BinaryOperator == JavaOperator.LESS_THAN_EQUALS_DOUBLE || arg0BinaryOperator == JavaOperator.GREATER_THAN_DOUBLE || arg0BinaryOperator == JavaOperator.GREATER_THAN_EQUALS_DOUBLE) { //encode the first argument JavaTypeName firstArgType = encodeExpr(arg0BinaryOperatorExpr.getArgument(0), context); // Add instructions to widen the first argument if necessary. int wideningOpCode = getWideningOpCode(firstArgType, JavaTypeName.DOUBLE); if (wideningOpCode != Opcodes.NOP) { mv.visitInsn(wideningOpCode); } //endcode the second argument JavaExpression secondArgExpr = arg0BinaryOperatorExpr.getArgument(1); JavaTypeName secondArgType = encodeExpr(secondArgExpr, context); wideningOpCode = getWideningOpCode(secondArgType, JavaTypeName.DOUBLE); if (wideningOpCode != Opcodes.NOP) { mv.visitInsn(wideningOpCode); } if (arg0BinaryOperator == JavaOperator.LESS_THAN_DOUBLE) { mv.visitInsn(Opcodes.DCMPG); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFLT, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFGE, trueContinuation); } } else if (arg0BinaryOperator == JavaOperator.LESS_THAN_EQUALS_DOUBLE) { mv.visitInsn(Opcodes.DCMPG); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFLE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFGT, trueContinuation); } } else if (arg0BinaryOperator == JavaOperator.GREATER_THAN_DOUBLE) { mv.visitInsn(Opcodes.DCMPL); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFGT, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFLE, trueContinuation); } } else if (arg0BinaryOperator == JavaOperator.GREATER_THAN_EQUALS_DOUBLE) { mv.visitInsn(Opcodes.DCMPL); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFGE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFLT, trueContinuation); } } else { throw new JavaGenerationException( "Expecting one of the double operators <, >, <= or >=."); } return; } //fall through to the unoptimized case... } else if (arg0Expr instanceof JavaExpression.OperatorExpression.Unary) { //"not (not expr)" is encoded as "id expr" JavaExpression.OperatorExpression.Unary arg0UnaryOperatorExpr = (JavaExpression.OperatorExpression.Unary) arg0Expr; if (arg0UnaryOperatorExpr.getJavaOperator() != JavaOperator.LOGICAL_NEGATE) { throw new JavaGenerationException("Unary logical negation expected."); } JavaExpression expr = arg0UnaryOperatorExpr.getArgument(0); if (isBooleanValuedOperatorExpr(expr)) { encodeBooleanValuedOperatorHelper((JavaExpression.OperatorExpression) expr, context, trueContinuation, falseContinuation, endsWithTrueForm); } else { encodeExpr(expr, context); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFEQ, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFNE, trueContinuation); } } return; } } //!x //is encoded as //if x == true then goto falseContinuation; ////what follows is a sample continuation in the case when a literal value is pushed onto the stack //push true; //goto next; //falseContinuation: //push false; //label next: encodeExpr(arg0Expr, context); if (endsWithTrueForm) { //Note that IFNE consumes a value on the stack. mv.visitJumpInsn(Opcodes.IFNE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFEQ, trueContinuation); } return; } if (symbol.equals("&&")) { //x && y //is encoded as //if x == false then goto falseContinuation //if y == false then goto falseContinuation ////what follows is a sample continuation in the case when a literal value is pushed onto the stack //push true //goto next //label falseContinuation: //push false //label next: JavaExpression arg0Expr = operatorExpr.getArgument(0); if (isBooleanValuedOperatorExpr(arg0Expr)) { Label innerTrueContinuation = new Label(); encodeBooleanValuedOperatorHelper((JavaExpression.OperatorExpression) arg0Expr, context, innerTrueContinuation, falseContinuation); mv.visitLabel(innerTrueContinuation); } else { encodeExpr(arg0Expr, context); mv.visitJumpInsn(Opcodes.IFEQ, falseContinuation); } JavaExpression arg1Expr = operatorExpr.getArgument(1); if (isBooleanValuedOperatorExpr(arg1Expr)) { encodeBooleanValuedOperatorHelper((JavaExpression.OperatorExpression) arg1Expr, context, trueContinuation, falseContinuation, endsWithTrueForm); } else { encodeExpr(arg1Expr, context); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFEQ, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFNE, trueContinuation); } } return; } if (symbol.equals("||")) { //x || y //is encoded as //if x == true then goto trueContinuation //if y == false then goto falseContinuation ////what follows is a sample continuation in the case when a literal value is pushed onto the stack //push true //goto next //label falseContinuation: //push false //label next: JavaExpression arg0Expr = operatorExpr.getArgument(0); if (isBooleanValuedOperatorExpr(arg0Expr)) { Label innerFalseContinuation = new Label(); //if x evaluates to false, we want to continue with evaluating y, this is why the "endsWithTrueForm" argument is false here. encodeBooleanValuedOperatorHelper((JavaExpression.OperatorExpression) arg0Expr, context, trueContinuation, innerFalseContinuation, false); mv.visitLabel(innerFalseContinuation); } else { encodeExpr(arg0Expr, context); mv.visitJumpInsn(Opcodes.IFNE, trueContinuation); } JavaExpression arg1Expr = operatorExpr.getArgument(1); if (isBooleanValuedOperatorExpr(arg1Expr)) { encodeBooleanValuedOperatorHelper((JavaExpression.OperatorExpression) arg1Expr, context, trueContinuation, falseContinuation, endsWithTrueForm); } else { encodeExpr(arg1Expr, context); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFEQ, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFNE, trueContinuation); } } return; } throw new JavaGenerationException("Unknown logical operator " + symbol + "."); } // if(operator.isLogicalOp()) // A relational operator //one comment on the bytecode sequences: there is some subtle points here because of the treatment of special values e.g. such //as not a number, plus infinity, minus 0 etc in the double and float types. The code below is based on copying what the Java //compiler generates for simple functions such as: //double foo(double x, double y) {double z = x < y; return z;} //encode the first argument JavaTypeName firstArgType = encodeExpr(operatorExpr.getArgument(0), context); // Add instructions to widen the first argument if necessary. int wideningOpCode = getWideningOpCode(firstArgType, valueType); if (wideningOpCode != Opcodes.NOP) { mv.visitInsn(wideningOpCode); } //Deal with comparisons to null as a special case. Don't push the second argument, since the null is //implicit in the bytecode instruction. JavaExpression secondArgExpr = operatorExpr.getArgument(1); final boolean compareToNull = secondArgExpr == LiteralWrapper.NULL; //Deal with comparisons to int zero as a special case. There are special 1 argument operators for this case. //javac makes use of this optimization. Interestingly, javac does not optimize the case when the first argument //is a literal int zero i.e. 0 < x, is not converted to x > 0 which then can make use of the 1 argument comparison. final boolean compareToIntZero = isInternalIntType(valueType) && isLiteralIntZeroExpr(secondArgExpr); if (!compareToNull && !compareToIntZero) { //endcode the second argument JavaTypeName secondArgType = encodeExpr(secondArgExpr, context); wideningOpCode = getWideningOpCode(secondArgType, valueType); if (wideningOpCode != Opcodes.NOP) { mv.visitInsn(wideningOpCode); } } // relational symbols: {">", ">=", "<", "<=", "==", "!="} if (symbol.equals(">")) { switch (valueType.getTag()) { case JavaTypeName.BYTE_TAG: case JavaTypeName.SHORT_TAG: case JavaTypeName.CHAR_TAG: case JavaTypeName.INT_TAG: { if (endsWithTrueForm) { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFLE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPLE, falseContinuation); } } else { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFGT, trueContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPGT, trueContinuation); } } break; } case JavaTypeName.LONG_TAG: { mv.visitInsn(Opcodes.LCMP); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFLE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFGT, trueContinuation); } break; } case JavaTypeName.DOUBLE_TAG: { mv.visitInsn(Opcodes.DCMPL); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFLE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFGT, trueContinuation); } break; } case JavaTypeName.FLOAT_TAG: { mv.visitInsn(Opcodes.FCMPL); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFLE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFGT, trueContinuation); } break; } default: throw new IllegalArgumentException("Unsupported operand type for JVM > operator."); } } else if (symbol.equals(">=")) { switch (valueType.getTag()) { case JavaTypeName.BYTE_TAG: case JavaTypeName.SHORT_TAG: case JavaTypeName.CHAR_TAG: case JavaTypeName.INT_TAG: { if (endsWithTrueForm) { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFLT, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPLT, falseContinuation); } } else { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFGE, trueContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPGE, trueContinuation); } } break; } case JavaTypeName.LONG_TAG: { mv.visitInsn(Opcodes.LCMP); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFLT, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFGE, trueContinuation); } break; } case JavaTypeName.DOUBLE_TAG: { mv.visitInsn(Opcodes.DCMPL); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFLT, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFGE, trueContinuation); } break; } case JavaTypeName.FLOAT_TAG: { mv.visitInsn(Opcodes.FCMPL); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFLT, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFGE, trueContinuation); } break; } default: throw new IllegalArgumentException("Unsupported operand type for JVM >= operator."); } } else if (symbol.equals("<")) { switch (valueType.getTag()) { case JavaTypeName.BYTE_TAG: case JavaTypeName.SHORT_TAG: case JavaTypeName.CHAR_TAG: case JavaTypeName.INT_TAG: { if (endsWithTrueForm) { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFGE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPGE, falseContinuation); } } else { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFLT, trueContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPLT, trueContinuation); } } break; } case JavaTypeName.LONG_TAG: { mv.visitInsn(Opcodes.LCMP); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFGE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFLT, trueContinuation); } break; } case JavaTypeName.DOUBLE_TAG: { mv.visitInsn(Opcodes.DCMPG); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFGE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFLT, trueContinuation); } break; } case JavaTypeName.FLOAT_TAG: { mv.visitInsn(Opcodes.FCMPG); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFGE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFLT, trueContinuation); } break; } default: throw new IllegalArgumentException("Unsupported operand type for JVM < operator."); } } else if (symbol.equals("<=")) { switch (valueType.getTag()) { case JavaTypeName.BYTE_TAG: case JavaTypeName.SHORT_TAG: case JavaTypeName.CHAR_TAG: case JavaTypeName.INT_TAG: { if (endsWithTrueForm) { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFGT, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPGT, falseContinuation); } } else { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFLE, trueContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPLE, trueContinuation); } } break; } case JavaTypeName.LONG_TAG: { mv.visitInsn(Opcodes.LCMP); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFGT, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFLE, trueContinuation); } break; } case JavaTypeName.DOUBLE_TAG: { mv.visitInsn(Opcodes.DCMPG); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFGT, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFLE, trueContinuation); } break; } case JavaTypeName.FLOAT_TAG: { mv.visitInsn(Opcodes.FCMPG); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFGT, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFLE, trueContinuation); } break; } default: throw new IllegalArgumentException("Unsupported operand type for JVM <= operator."); } } else if (symbol.equals("==")) { switch (valueType.getTag()) { case JavaTypeName.BOOLEAN_TAG: case JavaTypeName.BYTE_TAG: case JavaTypeName.SHORT_TAG: case JavaTypeName.CHAR_TAG: case JavaTypeName.INT_TAG: { if (endsWithTrueForm) { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFNE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPNE, falseContinuation); } } else { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFEQ, trueContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPEQ, trueContinuation); } } break; } case JavaTypeName.LONG_TAG: { mv.visitInsn(Opcodes.LCMP); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFNE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFEQ, trueContinuation); } break; } case JavaTypeName.DOUBLE_TAG: { mv.visitInsn(Opcodes.DCMPL); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFNE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFEQ, trueContinuation); } break; } case JavaTypeName.FLOAT_TAG: { mv.visitInsn(Opcodes.FCMPL); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFNE, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFEQ, trueContinuation); } break; } case JavaTypeName.ARRAY_TAG: case JavaTypeName.OBJECT_TAG: { if (endsWithTrueForm) { if (compareToNull) { mv.visitJumpInsn(Opcodes.IFNONNULL, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ACMPNE, falseContinuation); } } else { if (compareToNull) { mv.visitJumpInsn(Opcodes.IFNULL, trueContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ACMPEQ, trueContinuation); } } break; } default: throw new IllegalArgumentException("Unsupported operand type for JVM == operator."); } } else if (symbol.equals("!=")) { switch (valueType.getTag()) { case JavaTypeName.BOOLEAN_TAG: case JavaTypeName.BYTE_TAG: case JavaTypeName.SHORT_TAG: case JavaTypeName.CHAR_TAG: case JavaTypeName.INT_TAG: { if (endsWithTrueForm) { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFEQ, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPEQ, falseContinuation); } } else { if (compareToIntZero) { mv.visitJumpInsn(Opcodes.IFNE, trueContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ICMPNE, trueContinuation); } } break; } case JavaTypeName.LONG_TAG: { mv.visitInsn(Opcodes.LCMP); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFEQ, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFNE, trueContinuation); } break; } case JavaTypeName.DOUBLE_TAG: { mv.visitInsn(Opcodes.DCMPL); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFEQ, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFNE, trueContinuation); } break; } case JavaTypeName.FLOAT_TAG: { mv.visitInsn(Opcodes.FCMPL); if (endsWithTrueForm) { mv.visitJumpInsn(Opcodes.IFEQ, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IFNE, trueContinuation); } break; } case JavaTypeName.ARRAY_TAG: case JavaTypeName.OBJECT_TAG: { if (endsWithTrueForm) { if (compareToNull) { mv.visitJumpInsn(Opcodes.IFNULL, falseContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ACMPEQ, falseContinuation); } } else { if (compareToNull) { mv.visitJumpInsn(Opcodes.IFNONNULL, trueContinuation); } else { mv.visitJumpInsn(Opcodes.IF_ACMPNE, trueContinuation); } } break; } default: throw new IllegalArgumentException("Unsupported operand type for JVM != operator."); } } else { throw new JavaGenerationException("Unknown relational operator " + symbol + "."); } }