List of usage examples for org.objectweb.asm Opcodes NOP
int NOP
To view the source code for org.objectweb.asm Opcodes NOP.
Click Source Link
From source file:org.jacoco.core.internal.flow.InstructionTest.java
License:Open Source License
@Test public void setCovered_should_mark_branch_in_predecessor() { final Instruction i = new Instruction(new InsnNode(Opcodes.NOP), 122); i.setCovered(2);//from w w w.ja v a 2 s . co m assertEquals(1, i.getCoveredBranches()); assertEquals("{2}", i.toString()); final Instruction s1 = new Instruction(new InsnNode(Opcodes.NOP), 123); s1.setPredecessor(i, 1); s1.setCovered(0); assertEquals("{0}", s1.toString()); assertEquals(1, s1.getCoveredBranches()); assertEquals("{1, 2}", i.toString()); assertEquals(2, i.getCoveredBranches()); final Instruction s2 = new Instruction(new InsnNode(Opcodes.NOP), 124); s2.setPredecessor(i, 0); s2.setCovered(1); assertEquals("{0}", s1.toString()); assertEquals(1, s2.getCoveredBranches()); assertEquals("{0, 1, 2}", i.toString()); assertEquals(3, i.getCoveredBranches()); }
From source file:org.jacoco.core.internal.flow.InstructionTest.java
License:Open Source License
@Test public void merge_should_add_covered_branches_from_another_instruction() { final Instruction i1 = new Instruction(new InsnNode(Opcodes.NOP), 123); i1.setCovered(0);/*from www . j a va 2 s .c om*/ final Instruction i2 = new Instruction(new InsnNode(Opcodes.NOP), 123); i2.setCovered(1); i1.merge(i2); assertEquals("{0, 1}", i1.toString()); assertEquals(2, i1.getCoveredBranches()); assertEquals("{1}", i2.toString()); }
From source file:org.jacoco.core.internal.flow.InstructionTest.java
License:Open Source License
@Test public void testSetCoveredOnLongSequence() { final Instruction first = new Instruction(new InsnNode(Opcodes.NOP), 0); Instruction next = first;//from ww w .ja v a2 s. co m for (int i = 0; i < 0x10000; i++) { final Instruction insn = new Instruction(new InsnNode(Opcodes.NOP), i); insn.setPredecessor(next, 0); next = insn; } // The implementation must not cause an StackOverflowError even on very // long sequences: next.setCovered(0); assertEquals(1, first.getCoveredBranches()); }
From source file:org.jacoco.core.internal.flow.LabelFlowAnalyzerTest.java
License:Open Source License
@Test public void testFlowScenario09() { analyzer.visitInsn(Opcodes.NOP); analyzer.visitLabel(label);//w w w . j a v a2 s . c om analyzer.visitLabel(label); assertFalse(LabelInfo.isMultiTarget(label)); assertTrue(LabelInfo.isSuccessor(label)); }
From source file:org.jacoco.core.internal.instr.DuplicateFrameEliminatorTest.java
License:Open Source License
@Test public void testInsn() { testInstructionBetweenFrames(new InsnNode(Opcodes.NOP)); }
From source file:org.jacoco.core.internal.instr.FrameTracker.java
License:Open Source License
@Override public void visitInsn(final int opcode) { final Object t1, t2, t3, t4; switch (opcode) { case Opcodes.NOP: case Opcodes.RETURN: break;/* w w w .j a va 2 s .c o m*/ case Opcodes.ARETURN: case Opcodes.ATHROW: case Opcodes.FRETURN: case Opcodes.IRETURN: case Opcodes.MONITORENTER: case Opcodes.MONITOREXIT: case Opcodes.POP: pop(1); break; case Opcodes.DRETURN: case Opcodes.LRETURN: case Opcodes.POP2: pop(2); break; case Opcodes.AASTORE: case Opcodes.BASTORE: case Opcodes.CASTORE: case Opcodes.FASTORE: case Opcodes.IASTORE: case Opcodes.SASTORE: pop(3); break; case Opcodes.LASTORE: case Opcodes.DASTORE: pop(4); break; case Opcodes.ICONST_M1: case Opcodes.ICONST_0: case Opcodes.ICONST_1: case Opcodes.ICONST_2: case Opcodes.ICONST_3: case Opcodes.ICONST_4: case Opcodes.ICONST_5: push(Opcodes.INTEGER); break; case Opcodes.ARRAYLENGTH: case Opcodes.F2I: case Opcodes.I2B: case Opcodes.I2C: case Opcodes.I2S: case Opcodes.INEG: pop(1); push(Opcodes.INTEGER); break; case Opcodes.BALOAD: case Opcodes.CALOAD: case Opcodes.D2I: case Opcodes.FCMPG: case Opcodes.FCMPL: case Opcodes.IADD: case Opcodes.IALOAD: case Opcodes.IAND: case Opcodes.IDIV: case Opcodes.IMUL: case Opcodes.IOR: case Opcodes.IREM: case Opcodes.ISHL: case Opcodes.ISHR: case Opcodes.ISUB: case Opcodes.IUSHR: case Opcodes.IXOR: case Opcodes.L2I: case Opcodes.SALOAD: pop(2); push(Opcodes.INTEGER); break; case Opcodes.DCMPG: case Opcodes.DCMPL: case Opcodes.LCMP: pop(4); push(Opcodes.INTEGER); break; case Opcodes.FCONST_0: case Opcodes.FCONST_1: case Opcodes.FCONST_2: push(Opcodes.FLOAT); break; case Opcodes.FNEG: case Opcodes.I2F: pop(1); push(Opcodes.FLOAT); break; case Opcodes.D2F: case Opcodes.FADD: case Opcodes.FALOAD: case Opcodes.FDIV: case Opcodes.FMUL: case Opcodes.FREM: case Opcodes.FSUB: case Opcodes.L2F: pop(2); push(Opcodes.FLOAT); break; case Opcodes.LCONST_0: case Opcodes.LCONST_1: push(Opcodes.LONG); push(Opcodes.TOP); break; case Opcodes.F2L: case Opcodes.I2L: pop(1); push(Opcodes.LONG); push(Opcodes.TOP); break; case Opcodes.D2L: case Opcodes.LALOAD: case Opcodes.LNEG: pop(2); push(Opcodes.LONG); push(Opcodes.TOP); break; case Opcodes.LSHL: case Opcodes.LSHR: case Opcodes.LUSHR: pop(3); push(Opcodes.LONG); push(Opcodes.TOP); break; case Opcodes.LADD: case Opcodes.LAND: case Opcodes.LDIV: case Opcodes.LMUL: case Opcodes.LOR: case Opcodes.LREM: case Opcodes.LSUB: case Opcodes.LXOR: pop(4); push(Opcodes.LONG); push(Opcodes.TOP); break; case Opcodes.DCONST_0: case Opcodes.DCONST_1: push(Opcodes.DOUBLE); push(Opcodes.TOP); break; case Opcodes.F2D: case Opcodes.I2D: pop(1); push(Opcodes.DOUBLE); push(Opcodes.TOP); break; case Opcodes.DALOAD: case Opcodes.DNEG: case Opcodes.L2D: pop(2); push(Opcodes.DOUBLE); push(Opcodes.TOP); break; case Opcodes.DADD: case Opcodes.DDIV: case Opcodes.DMUL: case Opcodes.DREM: case Opcodes.DSUB: pop(4); push(Opcodes.DOUBLE); push(Opcodes.TOP); break; case Opcodes.ACONST_NULL: push(Opcodes.NULL); break; case Opcodes.AALOAD: pop(1); t1 = pop(); push(Type.getType(((String) t1).substring(1))); break; case Opcodes.DUP: t1 = pop(); push(t1); push(t1); break; case Opcodes.DUP_X1: t1 = pop(); t2 = pop(); push(t1); push(t2); push(t1); break; case Opcodes.DUP_X2: t1 = pop(); t2 = pop(); t3 = pop(); push(t1); push(t3); push(t2); push(t1); break; case Opcodes.DUP2: t1 = pop(); t2 = pop(); push(t2); push(t1); push(t2); push(t1); break; case Opcodes.DUP2_X1: t1 = pop(); t2 = pop(); t3 = pop(); push(t2); push(t1); push(t3); push(t2); push(t1); break; case Opcodes.DUP2_X2: t1 = pop(); t2 = pop(); t3 = pop(); t4 = pop(); push(t2); push(t1); push(t4); push(t3); push(t2); push(t1); break; case Opcodes.SWAP: t1 = pop(); t2 = pop(); push(t1); push(t2); break; default: throw new IllegalArgumentException(); } mv.visitInsn(opcode); }
From source file:org.jacoco.core.internal.instr.MethodInstrumenterTest.java
License:Open Source License
@Test(expected = IllegalArgumentException.class) public void testVisitJumpInsnWithProbe_InvalidOpcode() { testVisitJumpInsnWithProbe(Opcodes.NOP, Opcodes.NOP); }
From source file:org.jacoco.core.test.validation.ResizeInstructionsTest.java
License:Open Source License
/** * Test of ASM bug/*w w w .j ava2s . com*/ * <a href="https://gitlab.ow2.org/asm/asm/issues/317792">#317792</a>. */ @Test public void should_not_loose_InnerClasses_attribute() throws Exception { // FIXME fails without COMPUTE_FRAMES because of // https://gitlab.ow2.org/asm/asm/issues/317800 final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); final ClassReader cr = new ClassReader(TargetLoader.getClassDataAsBytes(Inner.class)); cr.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) { @Override public void visitEnd() { final MethodVisitor mv = cv.visitMethod(0, "m", "()V", null, null); mv.visitCode(); addCauseOfResizeInstructions(mv); mv.visitInsn(Opcodes.NOP); mv.visitMaxs(2, 1); mv.visitEnd(); super.visitEnd(); } }, 0); final byte[] bytes = instrumenter.instrument(cw.toByteArray(), ""); final TargetLoader targetLoader = new TargetLoader(); final Class<?> outer = targetLoader.add(ResizeInstructionsTest.class, TargetLoader.getClassDataAsBytes(ResizeInstructionsTest.class)); final Class<?> inner = targetLoader.add(Inner.class, bytes); assertSame(outer, inner.getEnclosingClass()); assertNotNull(inner.getEnclosingClass()); assertSame(outer, inner.getDeclaringClass()); assertNotNull(inner.getDeclaringClass()); }
From source file:org.openquark.cal.internal.javamodel.AsmJavaBytecodeGenerator.java
License:Open Source License
/** * Encodes the Java code for a given Java operator expression. * /* w w w .j a va 2 s . c o m*/ * @param operatorExpr the java operator expression * @param context * @return JavaTypeName * @throws JavaGenerationException */ private static JavaTypeName encodeOperatorExpr(JavaExpression.OperatorExpression operatorExpr, GenerationContext context) throws JavaGenerationException { MethodVisitor mv = context.getMethodVisitor(); JavaOperator operator = operatorExpr.getJavaOperator(); String symbol = operator.getSymbol(); JavaTypeName valueType = operator.getValueType(); // Now carry out the operation according to its type. if (operator.isArithmeticOp()) { // Add the instructions to evaluate the first argument. JavaTypeName arg1Type = encodeExpr(operatorExpr.getArgument(0), context); if (operatorExpr instanceof OperatorExpression.Unary) { if (symbol.equals("-")) { // number negation mv.visitInsn(getNegateOpCode(arg1Type)); return arg1Type; } throw new JavaGenerationException("Unknown unary arithmetic operator " + symbol + "."); } // Add an instruction to widen the argument if necessary. int wideningOpCode = getWideningOpCode(arg1Type, valueType); if (wideningOpCode != Opcodes.NOP) { mv.visitInsn(wideningOpCode); } // Add the instructions to evaluate the second argument. JavaTypeName arg2Type = encodeExpr(operatorExpr.getArgument(1), context); // Add an instruction to widen the argument if necessary. wideningOpCode = getWideningOpCode(arg2Type, valueType); if (wideningOpCode != Opcodes.NOP) { mv.visitInsn(wideningOpCode); } // Evaluate. mv.visitInsn(getArithmeticBinaryOpCode(symbol, valueType)); return valueType; } if (operator.isBitOp()) { // Add the instructions to evaluate the first argument. JavaTypeName arg1Type = encodeExpr(operatorExpr.getArgument(0), context); // Add an instruction to widen the argument if necessary. int wideningOpCode = getWideningOpCode(arg1Type, valueType); if (wideningOpCode != Opcodes.NOP) { mv.visitInsn(wideningOpCode); } if (operatorExpr instanceof OperatorExpression.Unary) { if (symbol.equals("~")) { // number negation if (valueType == JavaTypeName.INT) { mv.visitInsn(Opcodes.ICONST_M1); mv.visitInsn(Opcodes.IXOR); return valueType; } else if (valueType == JavaTypeName.LONG) { encodePushLongValue(new Long(-1), context); mv.visitInsn(Opcodes.LXOR); return valueType; } } throw new JavaGenerationException("Unknown unary arithmetic operator " + symbol + "."); } // Add the instructions to evaluate the second argument. JavaTypeName arg2Type = encodeExpr(operatorExpr.getArgument(1), context); // If this is >>, >>>, or << we may need to narrow the second argument to an int if (symbol.equals(">>") || symbol.equals(">>>") || symbol.equals("<<")) { if (arg2Type == JavaTypeName.LONG) { mv.visitInsn(Opcodes.L2I); } } else { // Add an instruction to widen the argument if necessary. wideningOpCode = getWideningOpCode(arg2Type, valueType); if (wideningOpCode != Opcodes.NOP) { mv.visitInsn(wideningOpCode); } } // Evaluate. mv.visitInsn(getArithmeticBinaryOpCode(symbol, valueType)); return valueType; } if (operator.isLogicalOp() || operator.isRelationalOp()) { // Logical op: {"!", "&&", "||"} // Relational op: {">", ">=", "<", "<=", "==", "!="} Label trueContinuation = new Label(); Label falseContinuation = new Label(); encodeBooleanValuedOperatorHelper(operatorExpr, context, trueContinuation, falseContinuation); return encodeThenTrueElseFalse(trueContinuation, falseContinuation, context); } if (operator == JavaOperator.STRING_CONCATENATION) { // Create an uninitialized StringBuilder, duplicate the reference (so we can invoke the initializer). mv.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder"); mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V"); // append the first arg. JavaTypeName firstArgType = encodeExpr(operatorExpr.getArgument(0), context); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", getAppendJVMDescriptor(firstArgType)); // Append the results of evaluation of the second arg. // Note that, conveniently, StringBuilder has an append() method for all the different types. JavaTypeName secondArgType = encodeExpr(operatorExpr.getArgument(1), context); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", getAppendJVMDescriptor(secondArgType)); // Call toString() on the result. mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;"); return JavaTypeName.STRING; } return encodeTernaryOperatorExpr((OperatorExpression.Ternary) operatorExpr, 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 w w w. j av a 2 s. 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 + "."); } }