Reversed if condition in java bytecode

大兔子大兔子 提交于 2019-12-23 07:25:44

问题


Consider simple example

private static String isPositive(int val) {
    if (val > 0) {
        return "yes";
    } else {
        return "no";
    }
}

Here it's pretty straightforward: if val > 0 return yes else return no. But after compilation, in bytecode, this if condition is reversed:

  private static isPositive(I)Ljava/lang/String;
   L0
    LINENUMBER 12 L0
    ILOAD 0
    IFLE L1
   L2
    LINENUMBER 13 L2
    LDC "yes"
    ARETURN
   L1
    LINENUMBER 15 L1
   FRAME SAME
    LDC "no"
    ARETURN

It checks: if val <= 0 then return no, else return yes.

First, I thought that <= check is cheaper, and it's some kind of optimization. But if I change my initial code to

if (val <= 0) {
    return "no";
} else {
    return "yes";
}

it still will be reversed in bytecode:

   L0
    LINENUMBER 12 L0
    ILOAD 0
    IFGT L1
   L2
    LINENUMBER 13 L2
    LDC "no"
    ARETURN
   L1
    LINENUMBER 15 L1
   FRAME SAME
    LDC "yes"
    ARETURN

So, is there a reason for such behavior? Can it be changed to straightforward?


回答1:


It is probably done like this so that the two blocks of code in the if show up in the same order in the translated bytecode.

For example, this Java code:

if (val > 0) {
    return "yes";
} else {
    return "no";
}

Translates to something like this (pseudocode):

If val <= 0, then branch to L1
return "yes"
L1:
return "no"  

Note that in the original Java code, the if condition is checked to see if the first block of code should run, while in the translated bytecode the check is done to see if the branch should be taken (skipping over the first block of code). So it needs to check a complementary condition.

Can it be changed to straightforward?

Of course it would also be possible to preserve the condition, but then you would need to reverse the order of the two code blocks:

If val > 0, then branch to L1
return "no"
L1:
return "yes"  

I would not say that this version is "more straighforward" than the previous one, though.

Anyway, why would you want to change it? Both versions should be just fine.




回答2:


Actually, reversing the condition is the most straight-forward compilation strategy possible. You write Java code matching the pattern

if(condition_fullfilled) {
    somecode
}

which will get compiled to bytecode matching the pattern

  goto_if_condition_not_fullfilled A_LABEL
  compiled_somecode
A_LABEL:

Since the conditional branch says when to skip the conditional code, its condition must be the opposite of your source code saying when to execute the conditional code.

The example above, not having an else part, demonstrates why there is no simple way of compiling if with a conditional branch instruction having the same condition than your source code. It’s possible, but would require more than one branch instruction.

This straight-forward compilation strategy for if statements without else can easily expanded to handle else as well. There is no reason to change the strategy, e.g. switching the order of the statements, when an else clause is present.

Note that in your case, where both branches end in a return statement, there is no difference between

if (val > 0) {
    return "yes";
} else {
    return "no";
}

and

if (val > 0) {
    return "yes";
}
return "no";

anyway.




回答3:


The reason there probably being the operand stack that the bytecode uses to execute its statements.

First the comparison is performed and 1, 0 or -1 is pushed onto the operand stack. Next a branch is performed based on whether the value on the operand stack is greater, less-than or equal to zero.

There is a good graphical detail to this given in JavaCodeToByteCode#conditionals and a detailed Instruction For Branching as well.



来源:https://stackoverflow.com/questions/42562666/reversed-if-condition-in-java-bytecode

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!