Let's say you're writing a Java (or subset-of-Java) compiler and you want to generate bytecode for a unary not expression, !E
. You're past type checking so you know E
has type boolean
, i.e. it will push a 1
or a 0
on to the operand stack.
One way to do it is something like (in Jasmin syntax):
E
ifeq truelabel
iconst_0
goto stoplabel
truelabel:
iconst_1
stoplabel:
i.e. if there's a 0 on the stack push 1, else push 0. Another way to do it, taking advantage of the fact that a boolean
is just an int
with value 1
or 0
, is to say !E = (E + 1) % 2
and generate
E
iconst_1
iadd
iconst_2
irem
Is there an advantage to using one over the other? Or something else entirely?
I once tried to write a Java decompiler, so I used to know what code javac generated. As I recall, javac 1.0.x used !E = E ? false : true
while javac 1.1 used !E = E ^ 1
(bitwise XOR).
I wouldn't count on the following definition to hold true on the bytecode level.
true == 1
On the binary level (and its almost language independent), a boolean is usually defined as
false == 0
true != 0
The javac compiler apparently also follows this definition (all checks in javac bytecode I have seen just always checks agains ZERO, never against ONE).
And it makes sense to use this definition for boolean instead only treating 1 as true, C also defines it this way (true is just != 0, not simply 1) and in assembly code this convention is also commonly used. So java also using this definition makes it possible to take/pass java booleans to other code without any special conversions.
I suspect your first code example (with the ifeq) is the only way to correctly implement the not-operator for booleans. The ^1-method (xor with 1) will fail if the boolean value is not strcitly represented as 0/1. Any other int value would cause the expression to work incorrectly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With