1

Iam trying to execute an if statement with logical and symbol '&&'. Here is what iam trying to do: Μy stack in asm byteocode has the values 0 and 1 and i want to get a result with the 'logical and' which in our case it doesn't get into the if statement.

I've tried Opcodes.IFEQ and Opcodes.IFNE instructions but the don't work.Same goes with '||' and '!' logical symbols

Any ideas?

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
Tony
  • 489
  • 2
  • 5
  • 22
  • "_don't seem to work_" is very unspecific. To get good answers you should post your code, the expected output, the actual output, and (if applicable) your input. With that information, we'll be able to understand your problem and help you. You can use the [**edit**](http://stackoverflow.com/posts/17052001/edit) button below your question to add that information. – jlordo Jun 11 '13 at 19:30

2 Answers2

3

Bytecode patterns for && and ||

Think about what a short-circuiting operator like && or || actually does. You've got some conditional branching. Let's consider &&. What you're effectively evaluating is:

if (left)
    if (right) <do something>
endIf

There is no single bytecode instruction that can describe this behavior. You need need some labels and conditional branching instructions:

.start
    <left expression>
    IFEQ .endIf // if left evaluates to zero (false), skip to end
    <right expression>
    IFEQ .endIf // if right evaluates to zero (false), skip to end
.ifTrue
    <body of 'if' block>
.endIf

The behavior of the || operator is a bit different; in this case, the logic looks something like this:

    if (left)
        goto .ifTrue
    if (!right)
        goto .endIf
.ifTrue
    <do something>
.endIf

Note how the check on the right operand is inverted to avoid an additional branch when the right operand evaluates to true. This behavior could be implemented in bytecode like so:

    <left operand>
    IFNE .ifTrue  // if left evaluates true, skip right, enter 'if' body
    <right operand>
    IFEQ .endIf   // if right evaluates false, skip 'if' body
.ifTrue
    <do something>
.endIf

When to push your operands

Note that your original question suggested you already have the left and right operands on the stack; that would be bad. You should only evaluate the right operand after the left operand has evaluated to true (nonzero) for && or false (zero) for ||. If the right operand causes side effects, evaluating it prematurely would violate the defined behavior of these operators.

Mike Strobel
  • 25,075
  • 57
  • 69
1

There are Opcodes.IAND and Opcodes.LAND. You don't mention whether the values on the stack are ints or longs, but I am assuming the former so I think Opcodes.IAND is the one you want.

Similarly, there is Opcodes.IOR for OR. For NOT, javac seems to emit a IFNE and ICONST_1 or ICONST_0 instructions, but if you know the values are either 1 or 0, it seems like you could emit an Opcodes.ICONST_1 followed by Opcodes.IXOR.

See Appendix A of the ASM User Guide, "Bytecode instructions", page 136:

http://download.forge.objectweb.org/asm/asm4-guide.pdf

David Conrad
  • 15,432
  • 2
  • 42
  • 54
  • Opcodes.IAND and Opcodes.LAND don't work with branch.I want with branch. E.x if(x<100 || x>200 && x!=y) how whould that in bytecode? – Tony Jun 11 '13 at 19:52
  • You would follow the IAND with IFEQ or IFNE. I would suggest you disassemble some code with `javap -c` and see what kind of code javac generates for these constructs. – David Conrad Jun 11 '13 at 19:55
  • Below is an execution of this code: boolean a=true; booleanb=true; if(!a){} 0: iconst_1 1: istore_1 2: iconst_1 3: istore_2 4: iload_1 5: ifne 8 8:return its says that if a is not 0 then pass which it isn't correct because we want the opposite in case of '!' – Tony Jun 11 '13 at 21:00
  • The problem is, your if statement is empty, so it does the same thing in both cases. `ifne` branch to 8, else fall through to 8. Try a method like `int f(boolean b) { if (!b) return 17; return 42; }` – David Conrad Jun 12 '13 at 19:51
  • `IAND` and `IOR` are bitwise operations and not appropriate for the logical `&&` and `||` operations because those operations are short-circuiting. For `&&`, the right operand should only be evaluated if the left operand evaluates to `true`. For `||`, the right operand should only be evaluated if the left operand evaluates to `false`. See my answer above. – Mike Strobel Jun 12 '13 at 20:17
  • The question says "i want to get a result with the 'logical and' which in our case it doesn't get into the if statement." IAND and IOR are the correct ways to AND and OR two booleans on the stack as 1 and 0, and in fact are the only instructions provided to do so. Short circuiting occurs at a higher level of compilation of the entire expression, and would involve the use of IFEQ and IFNE after the IAND or IOR. – David Conrad Jun 13 '13 at 19:05
  • I take back my last comment. A quick test with javac and javap -c shows that javac always emits combinations of IFEQ, IFNE, and branches to perform logical AND and OR operations. I had thought it would do an IAND followed by a test and branch, but this is not correct. – David Conrad Jun 13 '13 at 19:10
  • The reason being that it would violate the short-circuiting nature of the logical `&&` and `||` operators by requiring both operands to always be evaluated :). – Mike Strobel Jun 13 '13 at 19:56
  • Yes. I was confused by the fact that he said both values were already on the stack, which would mean that both were already evaluated. – David Conrad Jun 13 '13 at 21:56